blob: 84343b924259c4f69c8ff832ea5e2b58cd1b4a68 [file] [log] [blame]
//===-- 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/Module.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Value.h"
#include "lldb/Expression/DWARFExpression.h"
#include "lldb/Symbol/FuncUnwinders.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/Symbol.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 "lldb/Target/DynamicLoader.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(false);
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()
{
Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
ExecutionContext exe_ctx(m_thread.shared_from_this());
RegisterContextSP reg_ctx_sp = m_thread.GetRegisterContext();
if (reg_ctx_sp.get() == NULL)
{
m_frame_type = eNotAValidFrame;
return;
}
addr_t current_pc = reg_ctx_sp->GetPC();
if (current_pc == LLDB_INVALID_ADDRESS)
{
m_frame_type = eNotAValidFrame;
return;
}
Process *process = exe_ctx.GetProcessPtr();
// Let ABIs fixup code addresses to make sure they are valid. In ARM ABIs
// this will strip bit zero in case we read a PC from memory or from the LR.
// (which would be a no-op in frame 0 where we get it from the register set,
// but still a good idea to make the call here for other ABIs that may exist.)
ABI *abi = process->GetABI().get();
if (abi)
current_pc = abi->FixCodeAddress(current_pc);
// Initialize m_current_pc, an Address object, based on current_pc, an addr_t.
process->GetTarget().GetSectionLoadList().ResolveLoadAddress (current_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.
ModuleSP pc_module_sp (m_current_pc.GetModule());
if (!m_current_pc.IsValid() || !pc_module_sp)
{
UnwindLogMsg ("using architectural default unwind method");
}
// We require that eSymbolContextSymbol be successfully filled in or this context is of no use to us.
if (pc_module_sp.get()
&& (pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol)
{
m_sym_ctx_valid = true;
}
AddressRange addr_range;
m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range);
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 (m_current_pc.GetSection() == m_start_pc.GetSection())
{
m_current_offset = m_current_pc.GetOffset() - m_start_pc.GetOffset();
}
else if (m_current_pc.GetModule() == m_start_pc.GetModule())
{
// This means that whatever symbol we kicked up isn't really correct
// --- we should not 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 = m_current_pc.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 ();
UnwindPlan::RowSP active_row;
int cfa_offset = 0;
int row_register_kind = -1;
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.get() && log)
{
StreamString active_row_strm;
active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr()));
UnwindLogMsg ("%s", active_row_strm.GetString().c_str());
}
}
if (!active_row.get())
{
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;
UnwindLogMsg ("cfa_regval = 0x%16.16" PRIx64 " (cfa_regval = 0x%16.16" PRIx64 ", cfa_offset = %i)", m_cfa, cfa_regval, cfa_offset);
UnwindLogMsg ("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64 " using %s UnwindPlan",
(uint64_t) m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()),
(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()
{
Log *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())
{
m_frame_type = eNotAValidFrame;
return;
}
addr_t pc;
if (!ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc))
{
UnwindLogMsg ("could not get pc value");
m_frame_type = eNotAValidFrame;
return;
}
if (log)
{
UnwindLogMsg ("pc = 0x%16.16" PRIx64, pc);
addr_t reg_val;
if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP, reg_val))
UnwindLogMsg ("fp = 0x%16.16" PRIx64, reg_val);
if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, reg_val))
UnwindLogMsg ("sp = 0x%16.16" PRIx64, reg_val);
}
// A pc of 0x0 means it's the end of the stack crawl
if (pc == 0)
{
m_frame_type = eNotAValidFrame;
return;
}
ExecutionContext exe_ctx(m_thread.shared_from_this());
Process *process = exe_ctx.GetProcessPtr();
// Let ABIs fixup code addresses to make sure they are valid. In ARM ABIs
// this will strip bit zero in case we read a PC from memory or from the LR.
ABI *abi = process->GetABI().get();
if (abi)
pc = abi->FixCodeAddress(pc);
process->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.
ModuleSP pc_module_sp (m_current_pc.GetModule());
if (!m_current_pc.IsValid() || !pc_module_sp)
{
UnwindLogMsg ("using architectural default unwind method");
// Test the pc value to see if we know it's in an unmapped/non-executable region of memory.
uint32_t permissions;
if (process->GetLoadAddressPermissions(pc, permissions)
&& (permissions & ePermissionsExecutable) == 0)
{
// If this is the second frame off the stack, we may have unwound the first frame
// incorrectly. But using the architecture default unwind plan may get us back on
// track -- albeit possibly skipping a real frame. Give this frame a clearly-invalid
// pc and see if we can get any further.
if (GetNextFrame().get() && GetNextFrame()->IsValid() && GetNextFrame()->IsFrameZero())
{
UnwindLogMsg ("had a pc of 0x%" PRIx64 " which is not in executable memory but on frame 1 -- allowing it once.",
(uint64_t) pc);
m_frame_type = eSkipFrame;
}
else
{
// anywhere other than the second frame, a non-executable pc means we're off in the weeds -- stop now.
m_frame_type = eNotAValidFrame;
return;
}
}
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);
if (m_frame_type != eSkipFrame) // don't override eSkipFrame
{
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 ();
UnwindPlan::RowSP row = m_full_unwind_plan_sp->GetRowForFunctionOffset(0);
if (row.get())
{
uint32_t cfa_regnum = row->GetCFARegister();
int cfa_offset = row->GetCFAOffset();
if (!ReadGPRValue (row_register_kind, cfa_regnum, cfa_regval))
{
UnwindLogMsg ("failed to get cfa value");
if (m_frame_type != eSkipFrame) // don't override eSkipFrame
{
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)
{
UnwindLogMsg ("could not find a valid cfa address");
m_frame_type = eNotAValidFrame;
return;
}
// cfa_regval should point into the stack memory; if we can query memory region permissions,
// see if the memory is allocated & readable.
if (process->GetLoadAddressPermissions(cfa_regval, permissions)
&& (permissions & ePermissionsReadable) == 0)
{
m_frame_type = eNotAValidFrame;
return;
}
}
else
{
UnwindLogMsg ("could not find a row for function offset zero");
m_frame_type = eNotAValidFrame;
return;
}
UnwindLogMsg ("initialized frame cfa is 0x%" PRIx64, (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 ((pc_module_sp->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(false);
m_sym_ctx_valid = false;
if ((pc_module_sp->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.
if (m_frame_type != eSkipFrame) // don't override eSkipFrame
{
m_frame_type = eNormalFrame;
}
}
// We've set m_frame_type and m_sym_ctx before this call.
m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame ();
UnwindPlan::RowSP active_row;
int cfa_offset = 0;
int row_register_kind = -1;
// 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 ();
if (active_row.get() && log)
{
StreamString active_row_strm;
active_row->Dump(active_row_strm, m_fast_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr()));
UnwindLogMsg ("active row: %s", active_row_strm.GetString().c_str());
}
}
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.get() && log)
{
StreamString active_row_strm;
active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr()));
UnwindLogMsg ("active row: %s", active_row_strm.GetString().c_str());
}
}
}
if (!active_row.get())
{
m_frame_type = eNotAValidFrame;
return;
}
addr_t cfa_regval;
if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval))
{
UnwindLogMsg ("failed to get cfa reg %d/%d", row_register_kind, active_row->GetCFARegister());
m_frame_type = eNotAValidFrame;
return;
}
cfa_offset = active_row->GetCFAOffset ();
m_cfa = cfa_regval + cfa_offset;
UnwindLogMsg ("cfa_regval = 0x%16.16" PRIx64 " (cfa_regval = 0x%16.16" PRIx64 ", cfa_offset = %i)", m_cfa, cfa_regval, cfa_offset);
// A couple of sanity checks..
if (cfa_regval == LLDB_INVALID_ADDRESS || cfa_regval == 0 || cfa_regval == 1)
{
UnwindLogMsg ("could not find a valid cfa address");
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 && abi->FunctionCallsChangeCFA())
{
UnwindLogMsg ("same CFA address as next frame, assuming the unwind is looping - stopping");
m_frame_type = eNotAValidFrame;
return;
}
}
UnwindLogMsg ("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64,
(uint64_t) m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()), (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;
ModuleSP pc_module_sp (m_current_pc.GetModule());
if (!m_current_pc.IsValid() || !pc_module_sp || pc_module_sp->GetObjectFile() == NULL)
return unwind_plan_sp;
if (IsFrameZero ())
return unwind_plan_sp;
FuncUnwindersSP func_unwinders_sp (pc_module_sp->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))
{
Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
if (log && log->GetVerbose())
{
if (m_fast_unwind_plan_sp)
UnwindLogMsgVerbose ("frame, and has a fast UnwindPlan");
else
UnwindLogMsgVerbose ("frame");
}
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;
UnwindPlanSP arch_default_unwind_plan_sp;
ExecutionContext exe_ctx(m_thread.shared_from_this());
Process *process = exe_ctx.GetProcessPtr();
ABI *abi = process ? process->GetABI().get() : NULL;
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.
// Note, if the symbol context has a function for the symbol, then we don't need to do this check.
if ((!m_sym_ctx_valid || m_sym_ctx.function == NULL) && behaves_like_zeroth_frame && m_current_pc.IsValid())
{
uint32_t permissions;
addr_t current_pc_addr = m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr());
if (current_pc_addr == 0
|| (process->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 for the current pc, try using the architecture default unwind.
ModuleSP pc_module_sp (m_current_pc.GetModule());
if (!m_current_pc.IsValid() || !pc_module_sp || pc_module_sp->GetObjectFile() == NULL)
{
m_frame_type = eNormalFrame;
return arch_default_unwind_plan_sp;
}
FuncUnwindersSP func_unwinders_sp;
if (m_sym_ctx_valid)
{
func_unwinders_sp = pc_module_sp->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;
}
// Ask the DynamicLoader if the eh_frame CFI should be trusted in this frame even when it's frame zero
// This comes up if we have hand-written functions in a Module and hand-written eh_frame. The assembly
// instruction inspection may fail and the eh_frame CFI were probably written with some care to do the
// right thing. It'd be nice if there was a way to ask the eh_frame directly if it is asynchronous
// (can be trusted at every instruction point) or synchronous (the normal case - only at call sites).
// But there is not.
if (process && process->GetDynamicLoader() && process->GetDynamicLoader()->AlwaysRelyOnEHUnwindInfo (m_sym_ctx))
{
unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one);
if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
{
UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan because the DynamicLoader suggested we prefer it",
unwind_plan_sp->GetSourceName().GetCString());
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))
{
UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", 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))
{
UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", 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))
{
UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());
return unwind_plan_sp;
}
// If nothing else, use the architectural default UnwindPlan and hope that does the job.
UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", 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 (size_t reg)
{
return m_thread.GetRegisterContext()->GetRegisterInfoAtIndex (reg);
}
size_t
RegisterContextLLDB::GetRegisterSetCount ()
{
return m_thread.GetRegisterContext()->GetRegisterSetCount ();
}
const RegisterSet *
RegisterContextLLDB::GetRegisterSet (size_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 (!other_reg_info)
return false;
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;
}
// A skip frame is a bogus frame on the stack -- but one where we're likely to find a real frame farther
// up the stack if we keep looking. It's always the second frame in an unwind (i.e. the first frame after
// frame zero) where unwinding can be the trickiest. Ideally we'll mark up this frame in some way so the
// user knows we're displaying bad data and we may have skipped one frame of their real program in the
// process of getting back on track.
bool
RegisterContextLLDB::IsSkipFrame () const
{
return m_frame_type == eSkipFrame;
}
// Answer the question: Where did THIS frame save the CALLER frame ("previous" frame)'s register value?
enum UnwindLLDB::RegisterSearchResult
RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation &regloc)
{
// 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;
UnwindLogMsg ("supplying caller's saved reg %d's location, cached", lldb_regnum);
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
}
}
static uint32_t sp_regnum = LLDB_INVALID_REGNUM;
static uint32_t pc_regnum = LLDB_INVALID_REGNUM;
static bool generic_registers_initialized = false;
if (!generic_registers_initialized)
{
m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, eRegisterKindLLDB, sp_regnum);
m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, eRegisterKindLLDB, pc_regnum);
generic_registers_initialized = 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.
if (sp_regnum != LLDB_INVALID_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;
UnwindLogMsg ("supplying caller's stack pointer (%d) value, computed from CFA", lldb_regnum);
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
}
// 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)
{
UnwindPlan::RowSP 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))
{
UnwindLogMsg ("could not convert lldb regnum %d into %d RegisterKind reg numbering scheme",
lldb_regnum, (int) unwindplan_registerkind);
return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
}
if (active_row->GetRegisterInfo (row_regnum, unwindplan_regloc))
{
UnwindLogMsg ("supplying caller's saved reg %d's location using FastUnwindPlan", 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)
{
UnwindPlan::RowSP active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind ();
uint32_t row_regnum;
bool row_register_rewritten_to_return_address_reg = false;
// If we're fetching the saved pc and this UnwindPlan defines a ReturnAddress register (e.g. lr on arm),
// look for the return address register number in the UnwindPlan's row.
if (lldb_regnum == pc_regnum && m_full_unwind_plan_sp->GetReturnAddressRegister() != LLDB_INVALID_REGNUM)
{
row_regnum = m_full_unwind_plan_sp->GetReturnAddressRegister();
row_register_rewritten_to_return_address_reg = true;
UnwindLogMsg ("requested caller's saved PC but this UnwindPlan uses a RA reg; getting reg %d instead",
row_regnum);
}
else
{
if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindLLDB, lldb_regnum, unwindplan_registerkind, row_regnum))
{
if (unwindplan_registerkind == eRegisterKindGeneric)
UnwindLogMsg ("could not convert lldb regnum %d into eRegisterKindGeneric reg numbering scheme", lldb_regnum);
else
UnwindLogMsg ("could not convert lldb regnum %d into %d RegisterKind reg numbering scheme",
lldb_regnum, (int) unwindplan_registerkind);
return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
}
}
if (active_row->GetRegisterInfo (row_regnum, unwindplan_regloc))
{
have_unwindplan_regloc = true;
UnwindLogMsg ("supplying caller's saved reg %d's location using %s UnwindPlan", lldb_regnum,
m_full_unwind_plan_sp->GetSourceName().GetCString());
}
// This is frame 0 and we're retrieving the PC and it's saved in a Return Address register and
// it hasn't been saved anywhere yet -- that is, it's still live in the actual register.
// Handle this specially.
if (have_unwindplan_regloc == false
&& row_register_rewritten_to_return_address_reg == true
&& IsFrameZero()
&& row_regnum != LLDB_INVALID_REGNUM)
{
uint32_t ra_regnum_in_lldb_reg_numbering;
if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (unwindplan_registerkind, row_regnum, eRegisterKindLLDB, ra_regnum_in_lldb_reg_numbering))
{
lldb_private::UnwindLLDB::RegisterLocation new_regloc;
new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister;
new_regloc.location.register_number = ra_regnum_in_lldb_reg_numbering;
m_registers[lldb_regnum] = new_regloc;
regloc = new_regloc;
UnwindLogMsg ("supplying caller's register %d from the live RegisterContext at frame 0, saved in %d", lldb_regnum, ra_regnum_in_lldb_reg_numbering);
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
}
}
// If this architecture stores the return address in a register (it defines a Return Address register)
// and we're on a non-zero stack frame and the Full UnwindPlan says that the pc is stored in the
// RA registers (e.g. lr on arm), then we know that the full unwindplan is not trustworthy -- this
// is an impossible situation and the instruction emulation code has likely been misled.
// If this stack frame meets those criteria, we need to throw away the Full UnwindPlan that the
// instruction emulation came up with and fall back to the architecture's Default UnwindPlan so
// the stack walk can get past this point.
// Special note: If the Full UnwindPlan was generated from the compiler, don't second-guess it
// when we're at a call site location.
// arch_default_ra_regnum is the return address register # in the Full UnwindPlan register numbering
uint32_t arch_default_ra_regnum = LLDB_INVALID_REGNUM;
if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, unwindplan_registerkind, arch_default_ra_regnum)
&& arch_default_ra_regnum != LLDB_INVALID_REGNUM
&& pc_regnum != LLDB_INVALID_REGNUM
&& pc_regnum == lldb_regnum
&& unwindplan_regloc.IsInOtherRegister()
&& unwindplan_regloc.GetRegisterNumber() == arch_default_ra_regnum
&& m_full_unwind_plan_sp->GetSourcedFromCompiler() != eLazyBoolYes
&& !m_all_registers_available)
{
UnwindLogMsg ("%s UnwindPlan tried to restore the pc from the link register but this is a non-zero frame",
m_full_unwind_plan_sp->GetSourceName().GetCString());
// Throw away the full unwindplan; install the arch default unwindplan
InvalidateFullUnwindPlan();
// Now re-fetch the pc value we're searching for
uint32_t arch_default_pc_reg = LLDB_INVALID_REGNUM;
UnwindPlan::RowSP active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, m_full_unwind_plan_sp->GetRegisterKind(), arch_default_pc_reg)
&& arch_default_pc_reg != LLDB_INVALID_REGNUM
&& active_row
&& active_row->GetRegisterInfo (arch_default_pc_reg, unwindplan_regloc))
{
have_unwindplan_regloc = true;
}
else
{
have_unwindplan_regloc = false;
}
}
}
}
ExecutionContext exe_ctx(m_thread.shared_from_this());
Process *process = exe_ctx.GetProcessPtr();
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 = process ? process->GetABI().get() : NULL;
if (abi)
{
const RegisterInfo *reg_info = GetRegisterInfoAtIndex(lldb_regnum);
if (reg_info && abi->RegisterIsVolatile (reg_info))
{
UnwindLogMsg ("did not supply reg location for %d because it is volatile", lldb_regnum);
return UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile;
}
}
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;
UnwindLogMsg ("supplying caller's register %d from the live RegisterContext at frame 0", lldb_regnum);
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
}
else
UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
}
// 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;
UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
}
if (unwindplan_regloc.IsSame())
{
if (IsFrameZero ())
{
UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
}
else
{
return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
}
}
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;
UnwindLogMsg ("supplying caller's register %d, value is CFA plus offset", lldb_regnum);
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
}
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;
UnwindLogMsg ("supplying caller's register %d from the stack, saved at CFA plus offset", lldb_regnum);
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
}
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))
{
UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
}
regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister;
regloc.location.register_number = row_regnum_in_lldb;
m_registers[lldb_regnum] = regloc;
UnwindLogMsg ("supplying caller's register %d, saved in register %d", lldb_regnum, row_regnum_in_lldb);
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
}
if (unwindplan_regloc.IsDWARFExpression() || unwindplan_regloc.IsAtDWARFExpression())
{
DataExtractor dwarfdata (unwindplan_regloc.GetDWARFExpressionBytes(),
unwindplan_regloc.GetDWARFExpressionLength(),
process->GetByteOrder(), process->GetAddressByteSize());
DWARFExpression dwarfexpr (dwarfdata, 0, unwindplan_regloc.GetDWARFExpressionLength());
dwarfexpr.SetRegisterKind (unwindplan_registerkind);
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;
UnwindLogMsg ("supplying caller's register %d via DWARF expression (IsDWARFExpression)", lldb_regnum);
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
}
else
{
regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation;
regloc.location.target_memory_location = val;
m_registers[lldb_regnum] = regloc;
UnwindLogMsg ("supplying caller's register %d via DWARF expression (IsAtDWARFExpression)", lldb_regnum);
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
}
}
UnwindLogMsg ("tried to use IsDWARFExpression or IsAtDWARFExpression for reg %d but failed", lldb_regnum);
return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
}
UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
// FIXME UnwindPlan::Row types atDWARFExpression and isDWARFExpression are unsupported.
return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
}
// If the Full unwindplan has been determined to be incorrect, this method will
// replace it with the architecture's default unwindplna, if one is defined.
// It will also find the FuncUnwinders object for this function and replace the
// Full unwind method for the function there so we don't use the errant Full unwindplan
// again in the future of this debug session.
// We're most likely doing this because the Full unwindplan was generated by assembly
// instruction profiling and the profiler got something wrong.
void
RegisterContextLLDB::InvalidateFullUnwindPlan ()
{
UnwindPlan::Row::RegisterLocation unwindplan_regloc;
ExecutionContext exe_ctx (m_thread.shared_from_this());
Process *process = exe_ctx.GetProcessPtr();
ABI *abi = process ? process->GetABI().get() : NULL;
if (abi)
{
UnwindPlanSP original_full_unwind_plan_sp = m_full_unwind_plan_sp;
UnwindPlanSP arch_default_unwind_plan_sp;
arch_default_unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
abi->CreateDefaultUnwindPlan(*arch_default_unwind_plan_sp);
if (arch_default_unwind_plan_sp)
{
UnwindPlan::RowSP active_row = arch_default_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
if (active_row && active_row->GetCFARegister() != LLDB_INVALID_REGNUM)
{
FuncUnwindersSP func_unwinders_sp;
if (m_sym_ctx_valid && m_current_pc.IsValid() && m_current_pc.GetModule())
{
func_unwinders_sp = m_current_pc.GetModule()->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx);
if (func_unwinders_sp)
{
func_unwinders_sp->InvalidateNonCallSiteUnwindPlan (m_thread);
}
}
m_registers.clear();
m_full_unwind_plan_sp = arch_default_unwind_plan_sp;
addr_t cfa_regval;
if (ReadGPRValue (arch_default_unwind_plan_sp->GetRegisterKind(), active_row->GetCFARegister(), cfa_regval))
{
m_cfa = cfa_regval + active_row->GetCFAOffset ();
}
UnwindLogMsg ("full unwind plan '%s' has been replaced by architecture default unwind plan '%s' for this function from now on.",
original_full_unwind_plan_sp->GetSourceName().GetCString(), arch_default_unwind_plan_sp->GetSourceName().GetCString());
}
}
}
}
// Retrieve a general purpose register value for THIS frame, 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;
}
bool pc_register = false;
uint32_t generic_regnum;
if (register_kind == eRegisterKindGeneric && regnum == LLDB_REGNUM_GENERIC_PC)
{
pc_register = true;
}
else if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (register_kind, regnum, eRegisterKindGeneric, generic_regnum)
&& generic_regnum == LLDB_REGNUM_GENERIC_PC)
{
pc_register = true;
}
lldb_private::UnwindLLDB::RegisterLocation regloc;
if (!m_parent_unwind.SearchForSavedLocationForRegister (lldb_regnum, regloc, m_frame_number - 1, pc_register))
{
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)
{
if (!IsValid())
return false;
const uint32_t lldb_regnum = reg_info->kinds[eRegisterKindLLDB];
UnwindLogMsgVerbose ("looking for register saved location for reg %d", lldb_regnum);
// If this is the 0th frame, hand this over to the live register context
if (IsFrameZero ())
{
UnwindLogMsgVerbose ("passing along to the live register context for reg %d", 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, false))
return false;
return ReadRegisterValueFromRegisterLocation (regloc, reg_info, value);
}
bool
RegisterContextLLDB::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &value)
{
if (!IsValid())
return false;
const uint32_t lldb_regnum = reg_info->kinds[eRegisterKindLLDB];
UnwindLogMsgVerbose ("looking for register saved location for reg %d", lldb_regnum);
// If this is the 0th frame, hand this over to the live register context
if (IsFrameZero ())
{
UnwindLogMsgVerbose ("passing along to the live register context for reg %d", 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, false))
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);
}
RegisterContextLLDB::SharedPtr
RegisterContextLLDB::GetPrevFrame () const
{
RegisterContextLLDB::SharedPtr 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 (CalculateTarget().get());
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;
}
}
void
RegisterContextLLDB::UnwindLogMsg (const char *fmt, ...)
{
Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
if (log)
{
va_list args;
va_start (args, fmt);
char *logmsg;
if (vasprintf (&logmsg, fmt, args) == -1 || logmsg == NULL)
{
if (logmsg)
free (logmsg);
va_end (args);
return;
}
va_end (args);
log->Printf ("%*sth%d/fr%u %s",
m_frame_number < 100 ? m_frame_number : 100, "", m_thread.GetIndexID(), m_frame_number,
logmsg);
free (logmsg);
}
}
void
RegisterContextLLDB::UnwindLogMsgVerbose (const char *fmt, ...)
{
Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
if (log && log->GetVerbose())
{
va_list args;
va_start (args, fmt);
char *logmsg;
if (vasprintf (&logmsg, fmt, args) == -1 || logmsg == NULL)
{
if (logmsg)
free (logmsg);
va_end (args);
return;
}
va_end (args);
log->Printf ("%*sth%d/fr%u %s",
m_frame_number < 100 ? m_frame_number : 100, "", m_thread.GetIndexID(), m_frame_number,
logmsg);
free (logmsg);
}
}