forked from OSchip/llvm-project
1318 lines
47 KiB
C++
1318 lines
47 KiB
C++
//===-- RegisterContextLLDB.cpp --------------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
#include "lldb/lldb-private.h"
|
|
#include "lldb/Core/Address.h"
|
|
#include "lldb/Core/AddressRange.h"
|
|
#include "lldb/Core/DataBufferHeap.h"
|
|
#include "lldb/Core/Log.h"
|
|
#include "lldb/Core/RegisterValue.h"
|
|
#include "lldb/Core/Value.h"
|
|
#include "lldb/Symbol/FuncUnwinders.h"
|
|
#include "lldb/Symbol/Function.h"
|
|
#include "lldb/Symbol/SymbolContext.h"
|
|
#include "lldb/Symbol/Symbol.h"
|
|
#include "lldb/Expression/DWARFExpression.h"
|
|
#include "lldb/Target/ABI.h"
|
|
#include "lldb/Target/ExecutionContext.h"
|
|
#include "lldb/Target/Process.h"
|
|
#include "lldb/Target/StackFrame.h"
|
|
#include "lldb/Target/Target.h"
|
|
#include "lldb/Target/Thread.h"
|
|
|
|
#include "RegisterContextLLDB.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
RegisterContextLLDB::RegisterContextLLDB
|
|
(
|
|
Thread& thread,
|
|
const SharedPtr &next_frame,
|
|
SymbolContext& sym_ctx,
|
|
uint32_t frame_number,
|
|
UnwindLLDB& unwind_lldb
|
|
) :
|
|
RegisterContext (thread, frame_number),
|
|
m_thread(thread),
|
|
m_fast_unwind_plan_sp (),
|
|
m_full_unwind_plan_sp (),
|
|
m_all_registers_available(false),
|
|
m_frame_type (-1),
|
|
m_cfa (LLDB_INVALID_ADDRESS),
|
|
m_start_pc (),
|
|
m_current_pc (),
|
|
m_current_offset (0),
|
|
m_current_offset_backed_up_one (0),
|
|
m_sym_ctx(sym_ctx),
|
|
m_sym_ctx_valid (false),
|
|
m_frame_number (frame_number),
|
|
m_registers(),
|
|
m_parent_unwind (unwind_lldb)
|
|
{
|
|
m_sym_ctx.Clear();
|
|
m_sym_ctx_valid = false;
|
|
|
|
if (IsFrameZero ())
|
|
{
|
|
InitializeZerothFrame ();
|
|
}
|
|
else
|
|
{
|
|
InitializeNonZerothFrame ();
|
|
}
|
|
|
|
// This same code exists over in the GetFullUnwindPlanForFrame() but it may not have been executed yet
|
|
if (IsFrameZero()
|
|
|| next_frame->m_frame_type == eSigtrampFrame
|
|
|| next_frame->m_frame_type == eDebuggerFrame)
|
|
{
|
|
m_all_registers_available = true;
|
|
}
|
|
}
|
|
|
|
// Initialize a RegisterContextLLDB which is the first frame of a stack -- the zeroth frame or currently
|
|
// executing frame.
|
|
|
|
void
|
|
RegisterContextLLDB::InitializeZerothFrame()
|
|
{
|
|
StackFrameSP frame_sp (m_thread.GetStackFrameAtIndex (0));
|
|
|
|
if (m_thread.GetRegisterContext() == NULL)
|
|
{
|
|
m_frame_type = eNotAValidFrame;
|
|
return;
|
|
}
|
|
m_sym_ctx = frame_sp->GetSymbolContext (eSymbolContextFunction | eSymbolContextSymbol);
|
|
m_sym_ctx_valid = true;
|
|
AddressRange addr_range;
|
|
m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range);
|
|
|
|
m_current_pc = frame_sp->GetFrameCodeAddress();
|
|
|
|
static ConstString g_sigtramp_name ("_sigtramp");
|
|
if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == g_sigtramp_name) ||
|
|
(m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == g_sigtramp_name))
|
|
{
|
|
m_frame_type = eSigtrampFrame;
|
|
}
|
|
else
|
|
{
|
|
// FIXME: Detect eDebuggerFrame here.
|
|
m_frame_type = eNormalFrame;
|
|
}
|
|
|
|
// If we were able to find a symbol/function, set addr_range to the bounds of that symbol/function.
|
|
// else treat the current pc value as the start_pc and record no offset.
|
|
if (addr_range.GetBaseAddress().IsValid())
|
|
{
|
|
m_start_pc = addr_range.GetBaseAddress();
|
|
if (frame_sp->GetFrameCodeAddress().GetSection() == m_start_pc.GetSection())
|
|
{
|
|
m_current_offset = frame_sp->GetFrameCodeAddress().GetOffset() - m_start_pc.GetOffset();
|
|
}
|
|
else if (frame_sp->GetFrameCodeAddress().GetModule() == m_start_pc.GetModule())
|
|
{
|
|
// This means that whatever symbol we kicked up isn't really correct
|
|
// as no should cross section boundaries... We really should NULL out
|
|
// the function/symbol in this case unless there is a bad assumption
|
|
// here due to inlined functions?
|
|
m_current_offset = frame_sp->GetFrameCodeAddress().GetFileAddress() - m_start_pc.GetFileAddress();
|
|
}
|
|
m_current_offset_backed_up_one = m_current_offset;
|
|
}
|
|
else
|
|
{
|
|
m_start_pc = m_current_pc;
|
|
m_current_offset = -1;
|
|
m_current_offset_backed_up_one = -1;
|
|
}
|
|
|
|
// We've set m_frame_type and m_sym_ctx before these calls.
|
|
|
|
m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame ();
|
|
m_full_unwind_plan_sp = GetFullUnwindPlanForFrame ();
|
|
|
|
const UnwindPlan::Row *active_row = NULL;
|
|
int cfa_offset = 0;
|
|
int row_register_kind;
|
|
if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress (m_current_pc))
|
|
{
|
|
active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
|
|
row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
|
|
}
|
|
|
|
if (active_row == NULL)
|
|
{
|
|
m_frame_type = eNotAValidFrame;
|
|
return;
|
|
}
|
|
|
|
addr_t cfa_regval;
|
|
if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval))
|
|
{
|
|
m_frame_type = eNotAValidFrame;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
}
|
|
cfa_offset = active_row->GetCFAOffset ();
|
|
|
|
m_cfa = cfa_regval + cfa_offset;
|
|
|
|
LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
|
|
|
|
// A couple of sanity checks..
|
|
if (cfa_regval == LLDB_INVALID_ADDRESS || cfa_regval == 0 || cfa_regval == 1)
|
|
{
|
|
if (log)
|
|
{
|
|
log->Printf("%*sFrame %u could not find a valid cfa address",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number);
|
|
}
|
|
m_frame_type = eNotAValidFrame;
|
|
return;
|
|
}
|
|
|
|
if (log)
|
|
{
|
|
log->Printf("%*sThread %d Frame %u initialized frame current pc is 0x%llx cfa is 0x%llx using %s UnwindPlan",
|
|
m_frame_number < 100 ? m_frame_number : 100, "",
|
|
m_thread.GetIndexID(),
|
|
m_frame_number,
|
|
(uint64_t) m_current_pc.GetLoadAddress (&m_thread.GetProcess().GetTarget()),
|
|
(uint64_t) m_cfa,
|
|
m_full_unwind_plan_sp->GetSourceName().GetCString());
|
|
}
|
|
}
|
|
|
|
// Initialize a RegisterContextLLDB for the non-zeroth frame -- rely on the RegisterContextLLDB "below" it
|
|
// to provide things like its current pc value.
|
|
|
|
void
|
|
RegisterContextLLDB::InitializeNonZerothFrame()
|
|
{
|
|
LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
|
|
if (IsFrameZero ())
|
|
{
|
|
m_frame_type = eNotAValidFrame;
|
|
return;
|
|
}
|
|
|
|
if (!GetNextFrame().get() || !GetNextFrame()->IsValid())
|
|
{
|
|
m_frame_type = eNotAValidFrame;
|
|
return;
|
|
}
|
|
if (m_thread.GetRegisterContext() == NULL)
|
|
{
|
|
m_frame_type = eNotAValidFrame;
|
|
return;
|
|
}
|
|
|
|
addr_t pc;
|
|
if (!ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc))
|
|
{
|
|
if (log)
|
|
{
|
|
log->Printf("%*sFrame %u could not get pc value",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number);
|
|
}
|
|
m_frame_type = eNotAValidFrame;
|
|
return;
|
|
}
|
|
// A pc value of 0 up on the stack indicates we've hit the end of the stack
|
|
if (pc == 0)
|
|
{
|
|
m_frame_type = eNotAValidFrame;
|
|
return;
|
|
}
|
|
m_thread.GetProcess().GetTarget().GetSectionLoadList().ResolveLoadAddress (pc, m_current_pc);
|
|
|
|
// If we don't have a Module for some reason, we're not going to find symbol/function information - just
|
|
// stick in some reasonable defaults and hope we can unwind past this frame.
|
|
if (!m_current_pc.IsValid() || m_current_pc.GetModule() == NULL)
|
|
{
|
|
if (log)
|
|
{
|
|
log->Printf("%*sFrame %u using architectural default unwind method",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number);
|
|
}
|
|
ABI *abi = m_thread.GetProcess().GetABI().get();
|
|
if (abi)
|
|
{
|
|
m_fast_unwind_plan_sp.reset ();
|
|
m_full_unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
|
|
abi->CreateDefaultUnwindPlan(*m_full_unwind_plan_sp);
|
|
m_frame_type = eNormalFrame;
|
|
m_all_registers_available = false;
|
|
m_current_offset = -1;
|
|
m_current_offset_backed_up_one = -1;
|
|
addr_t cfa_regval;
|
|
int row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
|
|
const UnwindPlan::Row *row = m_full_unwind_plan_sp->GetRowForFunctionOffset(0);
|
|
if (row)
|
|
{
|
|
uint32_t cfa_regnum = row->GetCFARegister();
|
|
int cfa_offset = row->GetCFAOffset();
|
|
if (!ReadGPRValue (row_register_kind, cfa_regnum, cfa_regval))
|
|
{
|
|
if (log)
|
|
{
|
|
log->Printf("%*sFrame %u failed to get cfa value",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number);
|
|
}
|
|
m_frame_type = eNormalFrame;
|
|
return;
|
|
}
|
|
m_cfa = cfa_regval + cfa_offset;
|
|
|
|
// A couple of sanity checks..
|
|
if (cfa_regval == LLDB_INVALID_ADDRESS || cfa_regval == 0 || cfa_regval == 1)
|
|
{
|
|
if (log)
|
|
{
|
|
log->Printf("%*sFrame %u could not find a valid cfa address",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number);
|
|
}
|
|
m_frame_type = eNotAValidFrame;
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (log)
|
|
{
|
|
log->Printf("%*sFrame %u could not find a row for function offset zero",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number);
|
|
}
|
|
m_frame_type = eNotAValidFrame;
|
|
return;
|
|
}
|
|
|
|
if (log)
|
|
{
|
|
log->Printf("%*sFrame %u initialized frame cfa is 0x%llx",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
|
|
(uint64_t) m_cfa);
|
|
}
|
|
return;
|
|
}
|
|
m_frame_type = eNotAValidFrame;
|
|
return;
|
|
}
|
|
|
|
// We require that eSymbolContextSymbol be successfully filled in or this context is of no use to us.
|
|
if ((m_current_pc.GetModule()->ResolveSymbolContextForAddress (m_current_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol)
|
|
{
|
|
m_sym_ctx_valid = true;
|
|
}
|
|
|
|
AddressRange addr_range;
|
|
if (!m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range))
|
|
{
|
|
m_sym_ctx_valid = false;
|
|
}
|
|
|
|
bool decr_pc_and_recompute_addr_range = false;
|
|
|
|
// If the symbol lookup failed...
|
|
if (m_sym_ctx_valid == false)
|
|
decr_pc_and_recompute_addr_range = true;
|
|
|
|
// Or if we're in the middle of the stack (and not "above" an asynchronous event like sigtramp),
|
|
// and our "current" pc is the start of a function...
|
|
if (m_sym_ctx_valid
|
|
&& GetNextFrame()->m_frame_type != eSigtrampFrame
|
|
&& GetNextFrame()->m_frame_type != eDebuggerFrame
|
|
&& addr_range.GetBaseAddress().IsValid()
|
|
&& addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection()
|
|
&& addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset())
|
|
{
|
|
decr_pc_and_recompute_addr_range = true;
|
|
}
|
|
|
|
// We need to back up the pc by 1 byte and re-search for the Symbol to handle the case where the "saved pc"
|
|
// value is pointing to the next function, e.g. if a function ends with a CALL instruction.
|
|
// FIXME this may need to be an architectural-dependent behavior; if so we'll need to add a member function
|
|
// to the ABI plugin and consult that.
|
|
if (decr_pc_and_recompute_addr_range)
|
|
{
|
|
Address temporary_pc(m_current_pc);
|
|
temporary_pc.SetOffset(m_current_pc.GetOffset() - 1);
|
|
m_sym_ctx.Clear();
|
|
m_sym_ctx_valid = false;
|
|
if ((m_current_pc.GetModule()->ResolveSymbolContextForAddress (temporary_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol)
|
|
{
|
|
m_sym_ctx_valid = true;
|
|
}
|
|
if (!m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range))
|
|
{
|
|
m_sym_ctx_valid = false;
|
|
}
|
|
}
|
|
|
|
// If we were able to find a symbol/function, set addr_range_ptr to the bounds of that symbol/function.
|
|
// else treat the current pc value as the start_pc and record no offset.
|
|
if (addr_range.GetBaseAddress().IsValid())
|
|
{
|
|
m_start_pc = addr_range.GetBaseAddress();
|
|
m_current_offset = m_current_pc.GetOffset() - m_start_pc.GetOffset();
|
|
m_current_offset_backed_up_one = m_current_offset;
|
|
if (decr_pc_and_recompute_addr_range && m_current_offset_backed_up_one > 0)
|
|
m_current_offset_backed_up_one--;
|
|
}
|
|
else
|
|
{
|
|
m_start_pc = m_current_pc;
|
|
m_current_offset = -1;
|
|
m_current_offset_backed_up_one = -1;
|
|
}
|
|
|
|
static ConstString sigtramp_name ("_sigtramp");
|
|
if ((m_sym_ctx.function && m_sym_ctx.function->GetMangled().GetMangledName() == sigtramp_name)
|
|
|| (m_sym_ctx.symbol && m_sym_ctx.symbol->GetMangled().GetMangledName() == sigtramp_name))
|
|
{
|
|
m_frame_type = eSigtrampFrame;
|
|
}
|
|
else
|
|
{
|
|
// FIXME: Detect eDebuggerFrame here.
|
|
m_frame_type = eNormalFrame;
|
|
}
|
|
|
|
// We've set m_frame_type and m_sym_ctx before this call.
|
|
m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame ();
|
|
|
|
const UnwindPlan::Row *active_row = NULL;
|
|
int cfa_offset = 0;
|
|
int row_register_kind;
|
|
|
|
// Try to get by with just the fast UnwindPlan if possible - the full UnwindPlan may be expensive to get
|
|
// (e.g. if we have to parse the entire eh_frame section of an ObjectFile for the first time.)
|
|
|
|
if (m_fast_unwind_plan_sp && m_fast_unwind_plan_sp->PlanValidAtAddress (m_current_pc))
|
|
{
|
|
active_row = m_fast_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
|
|
row_register_kind = m_fast_unwind_plan_sp->GetRegisterKind ();
|
|
}
|
|
else
|
|
{
|
|
m_full_unwind_plan_sp = GetFullUnwindPlanForFrame ();
|
|
if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress (m_current_pc))
|
|
{
|
|
active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
|
|
row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
|
|
}
|
|
}
|
|
|
|
if (active_row == NULL)
|
|
{
|
|
m_frame_type = eNotAValidFrame;
|
|
return;
|
|
}
|
|
|
|
addr_t cfa_regval;
|
|
if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval))
|
|
{
|
|
if (log)
|
|
{
|
|
log->Printf("%*sFrame %u failed to get cfa reg %d/%d",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
|
|
row_register_kind, active_row->GetCFARegister());
|
|
}
|
|
m_frame_type = eNotAValidFrame;
|
|
return;
|
|
}
|
|
cfa_offset = active_row->GetCFAOffset ();
|
|
|
|
m_cfa = cfa_regval + cfa_offset;
|
|
|
|
// A couple of sanity checks..
|
|
if (cfa_regval == LLDB_INVALID_ADDRESS || cfa_regval == 0 || cfa_regval == 1)
|
|
{
|
|
if (log)
|
|
{
|
|
log->Printf("%*sFrame %u could not find a valid cfa address",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number);
|
|
}
|
|
m_frame_type = eNotAValidFrame;
|
|
return;
|
|
}
|
|
|
|
// If we have a bad stack setup, we can get the same CFA value multiple times -- or even
|
|
// more devious, we can actually oscillate between two CFA values. Detect that here and
|
|
// break out to avoid a possible infinite loop in lldb trying to unwind the stack.
|
|
addr_t next_frame_cfa;
|
|
addr_t next_next_frame_cfa = LLDB_INVALID_ADDRESS;
|
|
if (GetNextFrame().get() && GetNextFrame()->GetCFA(next_frame_cfa))
|
|
{
|
|
bool repeating_frames = false;
|
|
if (next_frame_cfa == m_cfa)
|
|
{
|
|
repeating_frames = true;
|
|
}
|
|
else
|
|
{
|
|
if (GetNextFrame()->GetNextFrame() && GetNextFrame()->GetNextFrame()->GetCFA(next_next_frame_cfa)
|
|
&& next_next_frame_cfa == m_cfa)
|
|
{
|
|
repeating_frames = true;
|
|
}
|
|
}
|
|
if (repeating_frames)
|
|
{
|
|
if (log)
|
|
{
|
|
log->Printf("%*sFrame %u same CFA address as next frame, assuming the unwind is looping - stopping",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number);
|
|
}
|
|
m_frame_type = eNotAValidFrame;
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (log)
|
|
{
|
|
log->Printf("%*sFrame %u initialized frame current pc is 0x%llx cfa is 0x%llx",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
|
|
(uint64_t) m_current_pc.GetLoadAddress (&m_thread.GetProcess().GetTarget()), (uint64_t) m_cfa);
|
|
}
|
|
}
|
|
|
|
|
|
bool
|
|
RegisterContextLLDB::IsFrameZero () const
|
|
{
|
|
return m_frame_number == 0;
|
|
}
|
|
|
|
|
|
// Find a fast unwind plan for this frame, if possible.
|
|
//
|
|
// On entry to this method,
|
|
//
|
|
// 1. m_frame_type should already be set to eSigtrampFrame/eDebuggerFrame if either of those are correct,
|
|
// 2. m_sym_ctx should already be filled in, and
|
|
// 3. m_current_pc should have the current pc value for this frame
|
|
// 4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown
|
|
|
|
UnwindPlanSP
|
|
RegisterContextLLDB::GetFastUnwindPlanForFrame ()
|
|
{
|
|
UnwindPlanSP unwind_plan_sp;
|
|
if (!m_current_pc.IsValid() || m_current_pc.GetModule() == NULL || m_current_pc.GetModule()->GetObjectFile() == NULL)
|
|
return unwind_plan_sp;
|
|
|
|
if (IsFrameZero ())
|
|
return unwind_plan_sp;
|
|
|
|
FuncUnwindersSP func_unwinders_sp (m_current_pc.GetModule()->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx));
|
|
if (!func_unwinders_sp)
|
|
return unwind_plan_sp;
|
|
|
|
// If we're in _sigtramp(), unwinding past this frame requires special knowledge.
|
|
if (m_frame_type == eSigtrampFrame || m_frame_type == eDebuggerFrame)
|
|
return unwind_plan_sp;
|
|
|
|
unwind_plan_sp = func_unwinders_sp->GetUnwindPlanFastUnwind (m_thread);
|
|
if (unwind_plan_sp)
|
|
{
|
|
if (unwind_plan_sp->PlanValidAtAddress (m_current_pc))
|
|
{
|
|
LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
|
|
if (log && log->GetVerbose())
|
|
{
|
|
const char *has_fast = "";
|
|
if (m_fast_unwind_plan_sp)
|
|
has_fast = ", and has a fast UnwindPlan";
|
|
log->Printf("%*sFrame %u frame has a fast UnwindPlan",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number);
|
|
}
|
|
m_frame_type = eNormalFrame;
|
|
return unwind_plan_sp;
|
|
}
|
|
else
|
|
{
|
|
unwind_plan_sp.reset();
|
|
}
|
|
}
|
|
return unwind_plan_sp;
|
|
}
|
|
|
|
// On entry to this method,
|
|
//
|
|
// 1. m_frame_type should already be set to eSigtrampFrame/eDebuggerFrame if either of those are correct,
|
|
// 2. m_sym_ctx should already be filled in, and
|
|
// 3. m_current_pc should have the current pc value for this frame
|
|
// 4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown
|
|
|
|
UnwindPlanSP
|
|
RegisterContextLLDB::GetFullUnwindPlanForFrame ()
|
|
{
|
|
UnwindPlanSP unwind_plan_sp;
|
|
LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
|
|
UnwindPlanSP arch_default_unwind_plan_sp;
|
|
|
|
ABI *abi = m_thread.GetProcess().GetABI().get();
|
|
if (abi)
|
|
{
|
|
arch_default_unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
|
|
abi->CreateDefaultUnwindPlan(*arch_default_unwind_plan_sp);
|
|
}
|
|
|
|
bool behaves_like_zeroth_frame = false;
|
|
if (IsFrameZero ()
|
|
|| GetNextFrame()->m_frame_type == eSigtrampFrame
|
|
|| GetNextFrame()->m_frame_type == eDebuggerFrame)
|
|
{
|
|
behaves_like_zeroth_frame = true;
|
|
// If this frame behaves like a 0th frame (currently executing or
|
|
// interrupted asynchronously), all registers can be retrieved.
|
|
m_all_registers_available = true;
|
|
}
|
|
|
|
// If we've done a jmp 0x0 / bl 0x0 (called through a null function pointer) so the pc is 0x0
|
|
// in the zeroth frame, we need to use the "unwind at first instruction" arch default UnwindPlan
|
|
// Also, if this Process can report on memory region attributes, any non-executable region means
|
|
// we jumped through a bad function pointer - handle the same way as 0x0.
|
|
|
|
if (behaves_like_zeroth_frame && m_current_pc.IsValid())
|
|
{
|
|
uint32_t permissions;
|
|
addr_t current_pc_addr = m_current_pc.GetLoadAddress (&m_thread.GetProcess().GetTarget());
|
|
if (current_pc_addr == 0
|
|
|| (m_thread.GetProcess().GetLoadAddressPermissions(current_pc_addr, permissions)
|
|
&& (permissions & ePermissionsExecutable) == 0))
|
|
{
|
|
unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
|
|
abi->CreateFunctionEntryUnwindPlan(*unwind_plan_sp);
|
|
m_frame_type = eNormalFrame;
|
|
return unwind_plan_sp;
|
|
}
|
|
}
|
|
|
|
// No Module fm_current_pc.GetLoadAddress (&m_thread.GetProcess().GetTarget()or the current pc, try using the architecture default unwind.
|
|
if (!m_current_pc.IsValid() || m_current_pc.GetModule() == NULL || m_current_pc.GetModule()->GetObjectFile() == NULL)
|
|
{
|
|
m_frame_type = eNormalFrame;
|
|
return arch_default_unwind_plan_sp;
|
|
}
|
|
|
|
FuncUnwindersSP func_unwinders_sp;
|
|
if (m_sym_ctx_valid)
|
|
{
|
|
func_unwinders_sp = m_current_pc.GetModule()->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx);
|
|
}
|
|
|
|
// No FuncUnwinders available for this pc, try using architectural default unwind.
|
|
if (!func_unwinders_sp)
|
|
{
|
|
m_frame_type = eNormalFrame;
|
|
return arch_default_unwind_plan_sp;
|
|
}
|
|
|
|
// If we're in _sigtramp(), unwinding past this frame requires special knowledge. On Mac OS X this knowledge
|
|
// is properly encoded in the eh_frame section, so prefer that if available.
|
|
// On other platforms we may need to provide a platform-specific UnwindPlan which encodes the details of
|
|
// how to unwind out of sigtramp.
|
|
if (m_frame_type == eSigtrampFrame)
|
|
{
|
|
m_fast_unwind_plan_sp.reset();
|
|
unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one);
|
|
if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
|
|
return unwind_plan_sp;
|
|
}
|
|
|
|
|
|
// Typically the NonCallSite UnwindPlan is the unwind created by inspecting the assembly language instructions
|
|
if (behaves_like_zeroth_frame)
|
|
{
|
|
unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread);
|
|
if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
|
|
{
|
|
if (log && log->GetVerbose())
|
|
{
|
|
log->Printf("%*sFrame %u frame uses %s for full UnwindPlan",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
|
|
unwind_plan_sp->GetSourceName().GetCString());
|
|
}
|
|
return unwind_plan_sp;
|
|
}
|
|
}
|
|
|
|
// Typically this is unwind info from an eh_frame section intended for exception handling; only valid at call sites
|
|
unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one);
|
|
if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
|
|
{
|
|
if (log && log->GetVerbose())
|
|
{
|
|
log->Printf("%*sFrame %u frame uses %s for full UnwindPlan",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
|
|
unwind_plan_sp->GetSourceName().GetCString());
|
|
}
|
|
return unwind_plan_sp;
|
|
}
|
|
|
|
// We'd prefer to use an UnwindPlan intended for call sites when we're at a call site but if we've
|
|
// struck out on that, fall back to using the non-call-site assembly inspection UnwindPlan if possible.
|
|
unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread);
|
|
if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
|
|
{
|
|
if (log && log->GetVerbose())
|
|
{
|
|
log->Printf("%*sFrame %u frame uses %s for full UnwindPlan",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
|
|
unwind_plan_sp->GetSourceName().GetCString());
|
|
}
|
|
return unwind_plan_sp;
|
|
}
|
|
|
|
// If nothing else, use the architectural default UnwindPlan and hope that does the job.
|
|
if (log && log->GetVerbose())
|
|
{
|
|
log->Printf("%*sFrame %u frame uses %s for full UnwindPlan",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
|
|
arch_default_unwind_plan_sp->GetSourceName().GetCString());
|
|
}
|
|
return arch_default_unwind_plan_sp;
|
|
}
|
|
|
|
|
|
void
|
|
RegisterContextLLDB::InvalidateAllRegisters ()
|
|
{
|
|
m_frame_type = eNotAValidFrame;
|
|
}
|
|
|
|
size_t
|
|
RegisterContextLLDB::GetRegisterCount ()
|
|
{
|
|
return m_thread.GetRegisterContext()->GetRegisterCount();
|
|
}
|
|
|
|
const RegisterInfo *
|
|
RegisterContextLLDB::GetRegisterInfoAtIndex (uint32_t reg)
|
|
{
|
|
return m_thread.GetRegisterContext()->GetRegisterInfoAtIndex (reg);
|
|
}
|
|
|
|
size_t
|
|
RegisterContextLLDB::GetRegisterSetCount ()
|
|
{
|
|
return m_thread.GetRegisterContext()->GetRegisterSetCount ();
|
|
}
|
|
|
|
const RegisterSet *
|
|
RegisterContextLLDB::GetRegisterSet (uint32_t reg_set)
|
|
{
|
|
return m_thread.GetRegisterContext()->GetRegisterSet (reg_set);
|
|
}
|
|
|
|
uint32_t
|
|
RegisterContextLLDB::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
|
|
{
|
|
return m_thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (kind, num);
|
|
}
|
|
|
|
bool
|
|
RegisterContextLLDB::ReadRegisterValueFromRegisterLocation (lldb_private::UnwindLLDB::RegisterLocation regloc,
|
|
const RegisterInfo *reg_info,
|
|
RegisterValue &value)
|
|
{
|
|
if (!IsValid())
|
|
return false;
|
|
bool success = false;
|
|
|
|
switch (regloc.type)
|
|
{
|
|
case UnwindLLDB::RegisterLocation::eRegisterInRegister:
|
|
{
|
|
const RegisterInfo *other_reg_info = GetRegisterInfoAtIndex(regloc.location.register_number);
|
|
if (IsFrameZero ())
|
|
{
|
|
success = m_thread.GetRegisterContext()->ReadRegister (other_reg_info, value);
|
|
}
|
|
else
|
|
{
|
|
success = GetNextFrame()->ReadRegister (other_reg_info, value);
|
|
}
|
|
}
|
|
break;
|
|
case UnwindLLDB::RegisterLocation::eRegisterValueInferred:
|
|
success = value.SetUInt (regloc.location.inferred_value, reg_info->byte_size);
|
|
break;
|
|
|
|
case UnwindLLDB::RegisterLocation::eRegisterNotSaved:
|
|
break;
|
|
case UnwindLLDB::RegisterLocation::eRegisterSavedAtHostMemoryLocation:
|
|
assert ("FIXME debugger inferior function call unwind");
|
|
break;
|
|
case UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation:
|
|
{
|
|
Error error (ReadRegisterValueFromMemory(reg_info,
|
|
regloc.location.target_memory_location,
|
|
reg_info->byte_size,
|
|
value));
|
|
success = error.Success();
|
|
}
|
|
break;
|
|
default:
|
|
assert ("Unknown RegisterLocation type.");
|
|
break;
|
|
}
|
|
return success;
|
|
}
|
|
|
|
bool
|
|
RegisterContextLLDB::WriteRegisterValueToRegisterLocation (lldb_private::UnwindLLDB::RegisterLocation regloc,
|
|
const RegisterInfo *reg_info,
|
|
const RegisterValue &value)
|
|
{
|
|
if (!IsValid())
|
|
return false;
|
|
|
|
bool success = false;
|
|
|
|
switch (regloc.type)
|
|
{
|
|
case UnwindLLDB::RegisterLocation::eRegisterInRegister:
|
|
{
|
|
const RegisterInfo *other_reg_info = GetRegisterInfoAtIndex(regloc.location.register_number);
|
|
if (IsFrameZero ())
|
|
{
|
|
success = m_thread.GetRegisterContext()->WriteRegister (other_reg_info, value);
|
|
}
|
|
else
|
|
{
|
|
success = GetNextFrame()->WriteRegister (other_reg_info, value);
|
|
}
|
|
}
|
|
break;
|
|
case UnwindLLDB::RegisterLocation::eRegisterValueInferred:
|
|
case UnwindLLDB::RegisterLocation::eRegisterNotSaved:
|
|
break;
|
|
case UnwindLLDB::RegisterLocation::eRegisterSavedAtHostMemoryLocation:
|
|
assert ("FIXME debugger inferior function call unwind");
|
|
break;
|
|
case UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation:
|
|
{
|
|
Error error (WriteRegisterValueToMemory (reg_info,
|
|
regloc.location.target_memory_location,
|
|
reg_info->byte_size,
|
|
value));
|
|
success = error.Success();
|
|
}
|
|
break;
|
|
default:
|
|
assert ("Unknown RegisterLocation type.");
|
|
break;
|
|
}
|
|
return success;
|
|
}
|
|
|
|
|
|
bool
|
|
RegisterContextLLDB::IsValid () const
|
|
{
|
|
return m_frame_type != eNotAValidFrame;
|
|
}
|
|
|
|
// Answer the question: Where did THIS frame save the CALLER frame ("previous" frame)'s register value?
|
|
|
|
bool
|
|
RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation ®loc, bool check_next_frame)
|
|
{
|
|
LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
|
|
|
|
// Have we already found this register location?
|
|
if (!m_registers.empty())
|
|
{
|
|
std::map<uint32_t, lldb_private::UnwindLLDB::RegisterLocation>::const_iterator iterator;
|
|
iterator = m_registers.find (lldb_regnum);
|
|
if (iterator != m_registers.end())
|
|
{
|
|
regloc = iterator->second;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Are we looking for the CALLER's stack pointer? The stack pointer is defined to be the same as THIS frame's
|
|
// CFA so just return the CFA value. This is true on x86-32/x86-64 at least.
|
|
uint32_t sp_regnum;
|
|
if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, eRegisterKindLLDB, sp_regnum)
|
|
&& sp_regnum == lldb_regnum)
|
|
{
|
|
// make sure we won't lose precision copying an addr_t (m_cfa) into a uint64_t (.inferred_value)
|
|
assert (sizeof (addr_t) <= sizeof (uint64_t));
|
|
regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
|
|
regloc.location.inferred_value = m_cfa;
|
|
m_registers[lldb_regnum] = regloc;
|
|
return true;
|
|
}
|
|
|
|
// Look through the available UnwindPlans for the register location.
|
|
|
|
UnwindPlan::Row::RegisterLocation unwindplan_regloc;
|
|
bool have_unwindplan_regloc = false;
|
|
RegisterKind unwindplan_registerkind = (RegisterKind)-1;
|
|
|
|
if (m_fast_unwind_plan_sp)
|
|
{
|
|
const UnwindPlan::Row *active_row = m_fast_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
|
|
unwindplan_registerkind = m_fast_unwind_plan_sp->GetRegisterKind ();
|
|
uint32_t row_regnum;
|
|
if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindLLDB, lldb_regnum, unwindplan_registerkind, row_regnum))
|
|
{
|
|
if (log)
|
|
{
|
|
log->Printf("%*sFrame %u could not convert lldb regnum %d into %d RegisterKind reg numbering scheme",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
|
|
lldb_regnum, (int) unwindplan_registerkind);
|
|
}
|
|
return false;
|
|
}
|
|
if (active_row->GetRegisterInfo (row_regnum, unwindplan_regloc))
|
|
{
|
|
if (log)
|
|
{
|
|
log->Printf("%*sFrame %u supplying caller's saved reg %d's location using FastUnwindPlan",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
|
|
lldb_regnum);
|
|
}
|
|
have_unwindplan_regloc = true;
|
|
}
|
|
}
|
|
|
|
if (!have_unwindplan_regloc)
|
|
{
|
|
// m_full_unwind_plan_sp being NULL means that we haven't tried to find a full UnwindPlan yet
|
|
if (!m_full_unwind_plan_sp)
|
|
m_full_unwind_plan_sp = GetFullUnwindPlanForFrame ();
|
|
|
|
if (m_full_unwind_plan_sp)
|
|
{
|
|
const UnwindPlan::Row *active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
|
|
unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind ();
|
|
uint32_t row_regnum;
|
|
if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindLLDB, lldb_regnum, unwindplan_registerkind, row_regnum))
|
|
{
|
|
if (log)
|
|
{
|
|
if (unwindplan_registerkind == eRegisterKindGeneric)
|
|
log->Printf("%*sFrame %u could not convert lldb regnum %d into eRegisterKindGeneric reg numbering scheme",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
|
|
lldb_regnum);
|
|
else
|
|
log->Printf("%*sFrame %u could not convert lldb regnum %d into %d RegisterKind reg numbering scheme",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
|
|
lldb_regnum, (int) unwindplan_registerkind);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if (active_row->GetRegisterInfo (row_regnum, unwindplan_regloc))
|
|
{
|
|
have_unwindplan_regloc = true;
|
|
if (log)
|
|
{
|
|
log->Printf("%*sFrame %u supplying caller's saved reg %d's location using %s UnwindPlan",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
|
|
lldb_regnum, m_full_unwind_plan_sp->GetSourceName().GetCString());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (have_unwindplan_regloc == false)
|
|
{
|
|
// If a volatile register is being requested, we don't want to forward the next frame's register contents
|
|
// up the stack -- the register is not retrievable at this frame.
|
|
ABI *abi = m_thread.GetProcess().GetABI().get();
|
|
if (abi)
|
|
{
|
|
const RegisterInfo *reg_info = GetRegisterInfoAtIndex(lldb_regnum);
|
|
if (reg_info && abi->RegisterIsVolatile (reg_info))
|
|
{
|
|
if (log && log->GetVerbose ())
|
|
{
|
|
log->Printf("%*sFrame %u did not supply reg location for %d because it is volatile",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
|
|
lldb_regnum);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (IsFrameZero ())
|
|
{
|
|
// This is frame 0 - we should return the actual live register context value
|
|
lldb_private::UnwindLLDB::RegisterLocation new_regloc;
|
|
new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister;
|
|
new_regloc.location.register_number = lldb_regnum;
|
|
m_registers[lldb_regnum] = new_regloc;
|
|
regloc = new_regloc;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if (check_next_frame)
|
|
return m_parent_unwind.SearchForSavedLocationForRegister (lldb_regnum, regloc, m_frame_number - 1);
|
|
}
|
|
if (log)
|
|
{
|
|
log->Printf("%*sFrame %u could not supply caller's reg %d location",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
|
|
lldb_regnum);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// unwindplan_regloc has valid contents about where to retrieve the register
|
|
if (unwindplan_regloc.IsUnspecified())
|
|
{
|
|
lldb_private::UnwindLLDB::RegisterLocation new_regloc;
|
|
new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterNotSaved;
|
|
m_registers[lldb_regnum] = new_regloc;
|
|
if (log)
|
|
{
|
|
log->Printf("%*sFrame %u could not supply caller's reg %d location",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
|
|
lldb_regnum);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if (unwindplan_regloc.IsSame())
|
|
{
|
|
if (IsFrameZero ())
|
|
{
|
|
if (log)
|
|
{
|
|
log->Printf("%*sFrame %u could not supply caller's reg %d location",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
|
|
lldb_regnum);
|
|
}
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if (check_next_frame)
|
|
return m_parent_unwind.SearchForSavedLocationForRegister (lldb_regnum, regloc, m_frame_number - 1);
|
|
else
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (unwindplan_regloc.IsCFAPlusOffset())
|
|
{
|
|
int offset = unwindplan_regloc.GetOffset();
|
|
regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
|
|
regloc.location.inferred_value = m_cfa + offset;
|
|
m_registers[lldb_regnum] = regloc;
|
|
return true;
|
|
}
|
|
|
|
if (unwindplan_regloc.IsAtCFAPlusOffset())
|
|
{
|
|
int offset = unwindplan_regloc.GetOffset();
|
|
regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation;
|
|
regloc.location.target_memory_location = m_cfa + offset;
|
|
m_registers[lldb_regnum] = regloc;
|
|
return true;
|
|
}
|
|
|
|
if (unwindplan_regloc.IsInOtherRegister())
|
|
{
|
|
uint32_t unwindplan_regnum = unwindplan_regloc.GetRegisterNumber();
|
|
uint32_t row_regnum_in_lldb;
|
|
if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (unwindplan_registerkind, unwindplan_regnum, eRegisterKindLLDB, row_regnum_in_lldb))
|
|
{
|
|
if (log)
|
|
{
|
|
log->Printf("%*sFrame %u could not supply caller's reg %d location",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
|
|
lldb_regnum);
|
|
}
|
|
return false;
|
|
}
|
|
regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister;
|
|
regloc.location.register_number = row_regnum_in_lldb;
|
|
m_registers[lldb_regnum] = regloc;
|
|
return true;
|
|
}
|
|
|
|
if (unwindplan_regloc.IsDWARFExpression() || unwindplan_regloc.IsAtDWARFExpression())
|
|
{
|
|
DataExtractor dwarfdata (unwindplan_regloc.GetDWARFExpressionBytes(),
|
|
unwindplan_regloc.GetDWARFExpressionLength(),
|
|
m_thread.GetProcess().GetByteOrder(), m_thread.GetProcess().GetAddressByteSize());
|
|
DWARFExpression dwarfexpr (dwarfdata, 0, unwindplan_regloc.GetDWARFExpressionLength());
|
|
dwarfexpr.SetRegisterKind (unwindplan_registerkind);
|
|
ExecutionContext exe_ctx (&m_thread.GetProcess(), &m_thread, NULL);
|
|
Value result;
|
|
Error error;
|
|
if (dwarfexpr.Evaluate (&exe_ctx, NULL, NULL, NULL, this, 0, NULL, result, &error))
|
|
{
|
|
addr_t val;
|
|
val = result.GetScalar().ULongLong();
|
|
if (unwindplan_regloc.IsDWARFExpression())
|
|
{
|
|
regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
|
|
regloc.location.inferred_value = val;
|
|
m_registers[lldb_regnum] = regloc;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation;
|
|
regloc.location.target_memory_location = val;
|
|
m_registers[lldb_regnum] = regloc;
|
|
return true;
|
|
}
|
|
}
|
|
if (log)
|
|
{
|
|
log->Printf("%*sFrame %u tried to use IsDWARFExpression or IsAtDWARFExpression for reg %d but failed",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
|
|
lldb_regnum);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if (log)
|
|
{
|
|
log->Printf("%*sFrame %u could not supply caller's reg %d location",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
|
|
lldb_regnum);
|
|
}
|
|
|
|
|
|
// assert ("UnwindPlan::Row types atDWARFExpression and isDWARFExpression are unsupported.");
|
|
return false;
|
|
}
|
|
|
|
// Retrieve a general purpose register value for THIS from, as saved by the NEXT frame, i.e. the frame that
|
|
// this frame called. e.g.
|
|
//
|
|
// foo () { }
|
|
// bar () { foo (); }
|
|
// main () { bar (); }
|
|
//
|
|
// stopped in foo() so
|
|
// frame 0 - foo
|
|
// frame 1 - bar
|
|
// frame 2 - main
|
|
// and this RegisterContext is for frame 1 (bar) - if we want to get the pc value for frame 1, we need to ask
|
|
// where frame 0 (the "next" frame) saved that and retrieve the value.
|
|
|
|
bool
|
|
RegisterContextLLDB::ReadGPRValue (int register_kind, uint32_t regnum, addr_t &value)
|
|
{
|
|
if (!IsValid())
|
|
return false;
|
|
|
|
uint32_t lldb_regnum;
|
|
if (register_kind == eRegisterKindLLDB)
|
|
{
|
|
lldb_regnum = regnum;
|
|
}
|
|
else if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (register_kind, regnum, eRegisterKindLLDB, lldb_regnum))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const RegisterInfo *reg_info = GetRegisterInfoAtIndex(lldb_regnum);
|
|
RegisterValue reg_value;
|
|
// if this is frame 0 (currently executing frame), get the requested reg contents from the actual thread registers
|
|
if (IsFrameZero ())
|
|
{
|
|
if (m_thread.GetRegisterContext()->ReadRegister (reg_info, reg_value))
|
|
{
|
|
value = reg_value.GetAsUInt64();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
lldb_private::UnwindLLDB::RegisterLocation regloc;
|
|
if (!m_parent_unwind.SearchForSavedLocationForRegister (lldb_regnum, regloc, m_frame_number - 1))
|
|
{
|
|
return false;
|
|
}
|
|
if (ReadRegisterValueFromRegisterLocation (regloc, reg_info, reg_value))
|
|
{
|
|
value = reg_value.GetAsUInt64();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Find the value of a register in THIS frame
|
|
|
|
bool
|
|
RegisterContextLLDB::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value)
|
|
{
|
|
LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
|
|
if (!IsValid())
|
|
return false;
|
|
|
|
const uint32_t lldb_regnum = reg_info->kinds[eRegisterKindLLDB];
|
|
if (log && log->GetVerbose ())
|
|
{
|
|
log->Printf("%*sFrame %u looking for register saved location for reg %d",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
|
|
lldb_regnum);
|
|
}
|
|
|
|
// If this is the 0th frame, hand this over to the live register context
|
|
if (IsFrameZero ())
|
|
{
|
|
if (log && log->GetVerbose ())
|
|
{
|
|
log->Printf("%*sFrame %u passing along to the live register context for reg %d",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
|
|
lldb_regnum);
|
|
}
|
|
return m_thread.GetRegisterContext()->ReadRegister (reg_info, value);
|
|
}
|
|
|
|
lldb_private::UnwindLLDB::RegisterLocation regloc;
|
|
// Find out where the NEXT frame saved THIS frame's register contents
|
|
if (!m_parent_unwind.SearchForSavedLocationForRegister (lldb_regnum, regloc, m_frame_number - 1))
|
|
return false;
|
|
|
|
return ReadRegisterValueFromRegisterLocation (regloc, reg_info, value);
|
|
}
|
|
|
|
bool
|
|
RegisterContextLLDB::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &value)
|
|
{
|
|
LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
|
|
if (!IsValid())
|
|
return false;
|
|
|
|
const uint32_t lldb_regnum = reg_info->kinds[eRegisterKindLLDB];
|
|
if (log && log->GetVerbose ())
|
|
{
|
|
log->Printf("%*sFrame %u looking for register saved location for reg %d",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
|
|
lldb_regnum);
|
|
}
|
|
|
|
// If this is the 0th frame, hand this over to the live register context
|
|
if (IsFrameZero ())
|
|
{
|
|
if (log && log->GetVerbose ())
|
|
{
|
|
log->Printf("%*sFrame %u passing along to the live register context for reg %d",
|
|
m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
|
|
lldb_regnum);
|
|
}
|
|
return m_thread.GetRegisterContext()->WriteRegister (reg_info, value);
|
|
}
|
|
|
|
lldb_private::UnwindLLDB::RegisterLocation regloc;
|
|
// Find out where the NEXT frame saved THIS frame's register contents
|
|
if (!m_parent_unwind.SearchForSavedLocationForRegister (lldb_regnum, regloc, m_frame_number - 1))
|
|
return false;
|
|
|
|
return WriteRegisterValueToRegisterLocation (regloc, reg_info, value);
|
|
}
|
|
|
|
// Don't need to implement this one
|
|
bool
|
|
RegisterContextLLDB::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Don't need to implement this one
|
|
bool
|
|
RegisterContextLLDB::WriteAllRegisterValues (const lldb::DataBufferSP& data_sp)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Retrieve the pc value for THIS from
|
|
|
|
bool
|
|
RegisterContextLLDB::GetCFA (addr_t& cfa)
|
|
{
|
|
if (!IsValid())
|
|
{
|
|
return false;
|
|
}
|
|
if (m_cfa == LLDB_INVALID_ADDRESS)
|
|
{
|
|
return false;
|
|
}
|
|
cfa = m_cfa;
|
|
return true;
|
|
}
|
|
|
|
|
|
RegisterContextLLDB::SharedPtr
|
|
RegisterContextLLDB::GetNextFrame () const
|
|
{
|
|
RegisterContextLLDB::SharedPtr regctx;
|
|
if (m_frame_number == 0)
|
|
return regctx;
|
|
return m_parent_unwind.GetRegisterContextForFrameNum (m_frame_number - 1);
|
|
}
|
|
|
|
// Retrieve the address of the start of the function of THIS frame
|
|
|
|
bool
|
|
RegisterContextLLDB::GetStartPC (addr_t& start_pc)
|
|
{
|
|
if (!IsValid())
|
|
return false;
|
|
if (!m_start_pc.IsValid())
|
|
{
|
|
return ReadPC (start_pc);
|
|
}
|
|
start_pc = m_start_pc.GetLoadAddress (&m_thread.GetProcess().GetTarget());
|
|
return true;
|
|
}
|
|
|
|
// Retrieve the current pc value for THIS frame, as saved by the NEXT frame.
|
|
|
|
bool
|
|
RegisterContextLLDB::ReadPC (addr_t& pc)
|
|
{
|
|
if (!IsValid())
|
|
return false;
|
|
if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc))
|
|
{
|
|
// A pc value of 0 or 1 is impossible in the middle of the stack -- it indicates the end of a stack walk.
|
|
// On the currently executing frame (or such a frame interrupted asynchronously by sigtramp et al) this may
|
|
// occur if code has jumped through a NULL pointer -- we want to be able to unwind past that frame to help
|
|
// find the bug.
|
|
|
|
if (m_all_registers_available == false
|
|
&& (pc == 0 || pc == 1))
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|