aboutsummaryrefslogtreecommitdiff
path: root/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Plugins/Process/Utility/RegisterContextLLDB.cpp')
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLLDB.cpp164
1 files changed, 132 insertions, 32 deletions
diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
index c19aec3a02c7..f87db5810740 100644
--- a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
+++ b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
@@ -21,15 +21,17 @@
#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/Symbol/SymbolContext.h"
#include "lldb/Target/ABI.h"
+#include "lldb/Target/DynamicLoader.h"
#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
+#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
-#include "lldb/Target/DynamicLoader.h"
#include "RegisterContextLLDB.h"
@@ -75,13 +77,44 @@ RegisterContextLLDB::RegisterContextLLDB
// 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 == eTrapHandlerFrame
|| next_frame->m_frame_type == eDebuggerFrame)
{
m_all_registers_available = true;
}
}
+bool
+RegisterContextLLDB::IsUnwindPlanValidForCurrentPC(lldb::UnwindPlanSP unwind_plan_sp, int &valid_pc_offset)
+{
+ if (!unwind_plan_sp)
+ return false;
+
+ // check if m_current_pc is valid
+ if (unwind_plan_sp->PlanValidAtAddress(m_current_pc))
+ {
+ // yes - current offset can be used as is
+ valid_pc_offset = m_current_offset;
+ return true;
+ }
+
+ // if m_current_offset <= 0, we've got nothing else to try
+ if (m_current_offset <= 0)
+ return false;
+
+ // check pc - 1 to see if it's valid
+ Address pc_minus_one (m_current_pc);
+ pc_minus_one.SetOffset(m_current_pc.GetOffset() - 1);
+ if (unwind_plan_sp->PlanValidAtAddress(pc_minus_one))
+ {
+ // *valid_pc_offset = m_current_offset - 1;
+ valid_pc_offset = m_current_pc.GetOffset() - 1;
+ return true;
+ }
+
+ return false;
+}
+
// Initialize a RegisterContextLLDB which is the first frame of a stack -- the zeroth frame or currently
// executing frame.
@@ -95,6 +128,7 @@ RegisterContextLLDB::InitializeZerothFrame()
if (reg_ctx_sp.get() == NULL)
{
m_frame_type = eNotAValidFrame;
+ UnwindLogMsg ("frame does not have a register context");
return;
}
@@ -103,6 +137,7 @@ RegisterContextLLDB::InitializeZerothFrame()
if (current_pc == LLDB_INVALID_ADDRESS)
{
m_frame_type = eNotAValidFrame;
+ UnwindLogMsg ("frame does not have a pc");
return;
}
@@ -117,7 +152,7 @@ RegisterContextLLDB::InitializeZerothFrame()
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);
+ m_current_pc.SetLoadAddress (current_pc, &process->GetTarget());
// 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.
@@ -137,11 +172,9 @@ RegisterContextLLDB::InitializeZerothFrame()
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))
+ if (IsTrapHandlerSymbol (process, m_sym_ctx))
{
- m_frame_type = eSigtrampFrame;
+ m_frame_type = eTrapHandlerFrame;
}
else
{
@@ -197,6 +230,7 @@ RegisterContextLLDB::InitializeZerothFrame()
if (!active_row.get())
{
+ UnwindLogMsg ("could not find an unwindplan row for this frame's pc");
m_frame_type = eNotAValidFrame;
return;
}
@@ -205,6 +239,7 @@ RegisterContextLLDB::InitializeZerothFrame()
addr_t cfa_regval = LLDB_INVALID_ADDRESS;
if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval))
{
+ UnwindLogMsg ("could not read CFA register for this frame.");
m_frame_type = eNotAValidFrame;
return;
}
@@ -229,17 +264,20 @@ RegisterContextLLDB::InitializeNonZerothFrame()
if (IsFrameZero ())
{
m_frame_type = eNotAValidFrame;
+ UnwindLogMsg ("non-zeroth frame tests positive for IsFrameZero -- that shouldn't happen.");
return;
}
if (!GetNextFrame().get() || !GetNextFrame()->IsValid())
{
m_frame_type = eNotAValidFrame;
+ UnwindLogMsg ("Could not get next frame, marking this frame as invalid.");
return;
}
if (!m_thread.GetRegisterContext())
{
m_frame_type = eNotAValidFrame;
+ UnwindLogMsg ("Could not get register context for this thread, marking this frame as invalid.");
return;
}
@@ -265,6 +303,7 @@ RegisterContextLLDB::InitializeNonZerothFrame()
if (pc == 0)
{
m_frame_type = eNotAValidFrame;
+ UnwindLogMsg ("this frame has a pc of 0x0");
return;
}
@@ -276,7 +315,7 @@ RegisterContextLLDB::InitializeNonZerothFrame()
if (abi)
pc = abi->FixCodeAddress(pc);
- process->GetTarget().GetSectionLoadList().ResolveLoadAddress (pc, m_current_pc);
+ m_current_pc.SetLoadAddress (pc, &process->GetTarget());
// 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.
@@ -304,6 +343,7 @@ RegisterContextLLDB::InitializeNonZerothFrame()
{
// anywhere other than the second frame, a non-executable pc means we're off in the weeds -- stop now.
m_frame_type = eNotAValidFrame;
+ UnwindLogMsg ("pc is in a non-executable section of memory and this isn't the 2nd frame in the stack walk.");
return;
}
}
@@ -352,6 +392,7 @@ RegisterContextLLDB::InitializeNonZerothFrame()
&& (permissions & ePermissionsReadable) == 0)
{
m_frame_type = eNotAValidFrame;
+ UnwindLogMsg ("the CFA points to a region of memory that is not readable");
return;
}
}
@@ -366,10 +407,15 @@ RegisterContextLLDB::InitializeNonZerothFrame()
return;
}
m_frame_type = eNotAValidFrame;
+ UnwindLogMsg ("could not find any symbol for this pc, or a default unwind plan, to continue unwind.");
return;
}
bool resolve_tail_call_address = true; // m_current_pc can be one past the address range of the function...
+ // This will handle the case where the saved pc does not point to
+ // a function/symbol because it is beyond the bounds of the correct
+ // function and there's no symbol there. ResolveSymbolContextForAddress
+ // will fail to find a symbol, back up the pc by 1 and re-search.
uint32_t resolved_scope = pc_module_sp->ResolveSymbolContextForAddress (m_current_pc,
eSymbolContextFunction | eSymbolContextSymbol,
m_sym_ctx, resolve_tail_call_address);
@@ -392,18 +438,35 @@ RegisterContextLLDB::InitializeNonZerothFrame()
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 or our "current" pc is one past the end of a function...
+ // 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 != eTrapHandlerFrame
&& GetNextFrame()->m_frame_type != eDebuggerFrame
&& addr_range.GetBaseAddress().IsValid()
- && addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection())
+ && addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection()
+ && addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset())
{
- if (addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset() ||
- addr_range.GetBaseAddress().GetOffset() + addr_range.GetByteSize() == 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))
{
- decr_pc_and_recompute_addr_range = true;
+ m_sym_ctx_valid = false;
}
}
@@ -428,11 +491,9 @@ RegisterContextLLDB::InitializeNonZerothFrame()
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))
+ if (IsTrapHandlerSymbol (process, m_sym_ctx))
{
- m_frame_type = eSigtrampFrame;
+ m_frame_type = eTrapHandlerFrame;
}
else
{
@@ -467,9 +528,10 @@ RegisterContextLLDB::InitializeNonZerothFrame()
else
{
m_full_unwind_plan_sp = GetFullUnwindPlanForFrame ();
- if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ int valid_offset = -1;
+ if (IsUnwindPlanValidForCurrentPC(m_full_unwind_plan_sp, valid_offset))
{
- active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+ active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (valid_offset);
row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
if (active_row.get() && log)
{
@@ -483,6 +545,7 @@ RegisterContextLLDB::InitializeNonZerothFrame()
if (!active_row.get())
{
m_frame_type = eNotAValidFrame;
+ UnwindLogMsg ("could not find unwind row for this pc");
return;
}
@@ -551,7 +614,7 @@ RegisterContextLLDB::IsFrameZero () const
//
// On entry to this method,
//
-// 1. m_frame_type should already be set to eSigtrampFrame/eDebuggerFrame if either of those are correct,
+// 1. m_frame_type should already be set to eTrapHandlerFrame/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
@@ -573,7 +636,7 @@ RegisterContextLLDB::GetFastUnwindPlanForFrame ()
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)
+ if (m_frame_type == eTrapHandlerFrame || m_frame_type == eDebuggerFrame)
return unwind_plan_sp;
unwind_plan_sp = func_unwinders_sp->GetUnwindPlanFastUnwind (m_thread);
@@ -602,7 +665,7 @@ RegisterContextLLDB::GetFastUnwindPlanForFrame ()
// On entry to this method,
//
-// 1. m_frame_type should already be set to eSigtrampFrame/eDebuggerFrame if either of those are correct,
+// 1. m_frame_type should already be set to eTrapHandlerFrame/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
@@ -627,7 +690,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()
bool behaves_like_zeroth_frame = false;
if (IsFrameZero ()
- || GetNextFrame()->m_frame_type == eSigtrampFrame
+ || GetNextFrame()->m_frame_type == eTrapHandlerFrame
|| GetNextFrame()->m_frame_type == eDebuggerFrame)
{
behaves_like_zeroth_frame = true;
@@ -648,7 +711,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()
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)
+ || (process->GetLoadAddressPermissions (current_pc_addr, permissions)
&& (permissions & ePermissionsExecutable) == 0))
{
unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
@@ -697,7 +760,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()
// 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)
+ if (m_frame_type == eTrapHandlerFrame)
{
m_fast_unwind_plan_sp.reset();
unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one);
@@ -735,7 +798,8 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()
// 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))
+ int valid_offset = -1;
+ if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset))
{
UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());
return unwind_plan_sp;
@@ -744,7 +808,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()
// 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 (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset))
{
UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());
return unwind_plan_sp;
@@ -915,6 +979,12 @@ RegisterContextLLDB::IsValid () const
return m_frame_type != eNotAValidFrame;
}
+bool
+RegisterContextLLDB::IsTrapHandlerFrame () const
+{
+ return m_frame_type == eTrapHandlerFrame;
+}
+
// 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
@@ -927,6 +997,35 @@ RegisterContextLLDB::IsSkipFrame () const
return m_frame_type == eSkipFrame;
}
+bool
+RegisterContextLLDB::IsTrapHandlerSymbol (lldb_private::Process *process, const lldb_private::SymbolContext &m_sym_ctx) const
+{
+ PlatformSP platform_sp (process->GetTarget().GetPlatform());
+ if (platform_sp)
+ {
+ const std::vector<ConstString> trap_handler_names (platform_sp->GetTrapHandlerSymbolNames());
+ for (ConstString name : trap_handler_names)
+ {
+ if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == name) ||
+ (m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == name))
+ {
+ return true;
+ }
+ }
+ }
+ const std::vector<ConstString> user_specified_trap_handler_names (m_parent_unwind.GetUserSpecifiedTrapHandlerFunctionNames());
+ for (ConstString name : user_specified_trap_handler_names)
+ {
+ if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == name) ||
+ (m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == name))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
// Answer the question: Where did THIS frame save the CALLER frame ("previous" frame)'s register value?
enum UnwindLLDB::RegisterSearchResult
@@ -1161,7 +1260,7 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat
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);
+ UnwindLogMsg ("supplying caller's register %d, value is CFA plus offset %d", lldb_regnum, offset);
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
}
@@ -1171,7 +1270,7 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat
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);
+ UnwindLogMsg ("supplying caller's register %d from the stack, saved at CFA plus offset %d", lldb_regnum, offset);
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
}
@@ -1550,3 +1649,4 @@ RegisterContextLLDB::UnwindLogMsgVerbose (const char *fmt, ...)
}
}
+