summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/lldb/source/Plugins/Process/Utility
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Plugins/Process/Utility')
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.h10
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp31
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp279
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h42
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp90
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.h20
7 files changed, 376 insertions, 98 deletions
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.cpp
index 5211362..d045bc7 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.cpp
@@ -25,7 +25,7 @@ HistoryThread::HistoryThread (lldb_private::Process &process,
std::vector<lldb::addr_t> pcs,
uint32_t stop_id,
bool stop_id_is_valid) :
- Thread (process, LLDB_INVALID_THREAD_ID),
+ Thread (process, tid),
m_framelist_mutex(),
m_framelist(),
m_pcs (pcs),
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.h
index 01fdd16..f9a431d 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.h
@@ -22,6 +22,16 @@
namespace lldb_private {
+//----------------------------------------------------------------------
+/// @class HistoryThread HistoryThread.h "HistoryThread.h"
+/// @brief A thread object representing a backtrace from a previous point in the process execution
+///
+/// This subclass of Thread is used to provide a backtrace from earlier in
+/// process execution. It is given a backtrace list of pc addresses and
+/// optionally a stop_id of when those pc addresses were collected, and it will
+/// create stack frames for them.
+//----------------------------------------------------------------------
+
class HistoryThread : public lldb_private::Thread
{
public:
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
index 6d1b04f..1d5d19f 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
@@ -34,9 +34,16 @@
using namespace lldb;
using namespace lldb_private;
-bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr,
- addr_t addr, addr_t length, unsigned prot,
- unsigned flags, addr_t fd, addr_t offset) {
+bool
+lldb_private::InferiorCallMmap (Process *process,
+ addr_t &allocated_addr,
+ addr_t addr,
+ addr_t length,
+ unsigned prot,
+ unsigned flags,
+ addr_t fd,
+ addr_t offset)
+{
Thread *thread = process->GetThreadList().GetSelectedThread().get();
if (thread == NULL)
return false;
@@ -139,8 +146,11 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr,
return false;
}
-bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr,
- addr_t length) {
+bool
+lldb_private::InferiorCallMunmap (Process *process,
+ addr_t addr,
+ addr_t length)
+{
Thread *thread = process->GetThreadList().GetSelectedThread().get();
if (thread == NULL)
return false;
@@ -209,7 +219,14 @@ bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr,
return false;
}
-bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t &returned_func) {
+// FIXME: This has nothing to do with Posix, it is just a convenience function that calls a
+// function of the form "void * (*)(void)". We should find a better place to put this.
+
+bool
+lldb_private::InferiorCall (Process *process,
+ const Address *address,
+ addr_t &returned_func)
+{
Thread *thread = process->GetThreadList().GetSelectedThread().get();
if (thread == NULL || address == NULL)
return false;
@@ -233,7 +250,7 @@ bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t
lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan);
if (call_plan_sp)
{
- StreamFile error_strm;
+ StreamString error_strm;
// This plan is a utility plan, so set it to discard itself when done.
call_plan_sp->SetIsMasterPlan (true);
call_plan_sp->SetOkayToDiscard(true);
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
index c19aec3..f209d53 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
+++ b/contrib/llvm/tools/lldb/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"
@@ -48,6 +50,7 @@ RegisterContextLLDB::RegisterContextLLDB
m_thread(thread),
m_fast_unwind_plan_sp (),
m_full_unwind_plan_sp (),
+ m_fallback_unwind_plan_sp (),
m_all_registers_available(false),
m_frame_type (-1),
m_cfa (LLDB_INVALID_ADDRESS),
@@ -75,13 +78,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 +129,7 @@ RegisterContextLLDB::InitializeZerothFrame()
if (reg_ctx_sp.get() == NULL)
{
m_frame_type = eNotAValidFrame;
+ UnwindLogMsg ("frame does not have a register context");
return;
}
@@ -103,6 +138,7 @@ RegisterContextLLDB::InitializeZerothFrame()
if (current_pc == LLDB_INVALID_ADDRESS)
{
m_frame_type = eNotAValidFrame;
+ UnwindLogMsg ("frame does not have a pc");
return;
}
@@ -117,7 +153,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 +173,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 +231,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 +240,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 +265,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 +304,7 @@ RegisterContextLLDB::InitializeNonZerothFrame()
if (pc == 0)
{
m_frame_type = eNotAValidFrame;
+ UnwindLogMsg ("this frame has a pc of 0x0");
return;
}
@@ -276,7 +316,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 +344,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 +393,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 +408,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 +439,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 +492,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 +529,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 +546,7 @@ RegisterContextLLDB::InitializeNonZerothFrame()
if (!active_row.get())
{
m_frame_type = eNotAValidFrame;
+ UnwindLogMsg ("could not find unwind row for this pc");
return;
}
@@ -551,7 +615,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 +637,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 +666,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 +691,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 +712,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,12 +761,14 @@ 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);
- if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc) && unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolYes)
+ {
return unwind_plan_sp;
+ }
}
// Ask the DynamicLoader if the eh_frame CFI should be trusted in this frame even when it's frame zero
@@ -728,6 +794,15 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame ()
unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread);
if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
{
+ if (unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo)
+ {
+ // We probably have an UnwindPlan created by inspecting assembly instructions, and we probably
+ // don't have any eh_frame instructions available.
+ // The assembly profilers work really well with compiler-generated functions but hand-written
+ // assembly can be problematic. We'll set the architecture default UnwindPlan as our fallback
+ // UnwindPlan in case this doesn't work out when we try to unwind.
+ m_fallback_unwind_plan_sp = arch_default_unwind_plan_sp;
+ }
UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());
return unwind_plan_sp;
}
@@ -735,7 +810,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 +820,17 @@ 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 (unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo)
+ {
+ // We probably have an UnwindPlan created by inspecting assembly instructions, and we probably
+ // don't have any eh_frame instructions available.
+ // The assembly profilers work really well with compiler-generated functions but hand-written
+ // assembly can be problematic. We'll set the architecture default UnwindPlan as our fallback
+ // UnwindPlan in case this doesn't work out when we try to unwind.
+ m_fallback_unwind_plan_sp = arch_default_unwind_plan_sp;
+ }
+
+ 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 +1001,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 +1019,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
@@ -1077,21 +1198,22 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat
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))
+ if (TryFallbackUnwindPlan())
{
- have_unwindplan_regloc = true;
- }
- else
- {
- have_unwindplan_regloc = false;
+ // 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;
+ }
}
}
}
@@ -1161,7 +1283,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 +1293,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;
}
@@ -1234,54 +1356,48 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat
}
// 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.
+// replace it with the architecture's default unwindplan, 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 ()
+bool
+RegisterContextLLDB::TryFallbackUnwindPlan ()
{
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)
+ if (m_fallback_unwind_plan_sp.get() == NULL)
+ return false;
+
+ UnwindPlanSP original_full_unwind_plan_sp = m_full_unwind_plan_sp;
+ UnwindPlan::RowSP active_row = m_fallback_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+
+ if (active_row && active_row->GetCFARegister() != LLDB_INVALID_REGNUM)
{
- 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)
+ FuncUnwindersSP func_unwinders_sp;
+ if (m_sym_ctx_valid && m_current_pc.IsValid() && m_current_pc.GetModule())
{
- UnwindPlan::RowSP active_row = arch_default_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
-
- if (active_row && active_row->GetCFARegister() != LLDB_INVALID_REGNUM)
+ func_unwinders_sp = m_current_pc.GetModule()->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx);
+ if (func_unwinders_sp)
{
- 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 = LLDB_INVALID_ADDRESS;
- 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());
+ func_unwinders_sp->InvalidateNonCallSiteUnwindPlan (m_thread);
}
}
+ m_registers.clear();
+ m_full_unwind_plan_sp = m_fallback_unwind_plan_sp;
+ addr_t cfa_regval = LLDB_INVALID_ADDRESS;
+ if (ReadGPRValue (m_fallback_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(), m_fallback_unwind_plan_sp->GetSourceName().GetCString());
+ m_fallback_unwind_plan_sp.reset();
}
+
+ return true;
}
// Retrieve a general purpose register value for THIS frame, as saved by the NEXT frame, i.e. the frame that
@@ -1550,3 +1666,4 @@ RegisterContextLLDB::UnwindLogMsgVerbose (const char *fmt, ...)
}
}
+
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h
index dc6d8c6..0a60bfe 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h
@@ -73,6 +73,9 @@ public:
IsValid () const;
bool
+ IsTrapHandlerFrame () const;
+
+ bool
GetCFA (lldb::addr_t& cfa);
bool
@@ -86,7 +89,7 @@ private:
enum FrameType
{
eNormalFrame,
- eSigtrampFrame,
+ eTrapHandlerFrame,
eDebuggerFrame, // a debugger inferior function call frame; we get caller's registers from debugger
eSkipFrame, // The unwind resulted in a bogus frame but may get back on track so we don't want to give up yet
eNotAValidFrame // this frame is invalid for some reason - most likely it is past the top (end) of the stack
@@ -120,6 +123,19 @@ private:
bool
IsSkipFrame () const;
+
+ //------------------------------------------------------------------
+ /// Determines if a SymbolContext is a trap handler or not
+ ///
+ /// Given a SymbolContext, determines if this is a trap handler function
+ /// aka asynchronous signal handler.
+ ///
+ /// @return
+ /// Returns true if the SymbolContext is a trap handler.
+ //------------------------------------------------------------------
+ bool
+ IsTrapHandlerSymbol (lldb_private::Process *process, const lldb_private::SymbolContext &m_sym_ctx) const;
+
// Provide a location for where THIS function saved the CALLER's register value
// Or a frame "below" this one saved it, i.e. a function called by this one, preserved a register that this
// function didn't modify/use.
@@ -144,8 +160,20 @@ private:
const lldb_private::RegisterInfo *reg_info,
const lldb_private::RegisterValue &value);
- void
- InvalidateFullUnwindPlan ();
+ //------------------------------------------------------------------
+ /// If the unwind has to the caller frame has failed, try something else
+ ///
+ /// If lldb is using an assembly language based UnwindPlan for a frame and
+ /// the unwind to the caller frame fails, try falling back to a generic
+ /// UnwindPlan (architecture default unwindplan) to see if that might work
+ /// better. This is mostly helping to work around problems where the
+ /// assembly language inspection fails on hand-written assembly code.
+ ///
+ /// @return
+ /// Returns true if a fallback unwindplan was found & was installed.
+ //------------------------------------------------------------------
+ bool
+ TryFallbackUnwindPlan ();
// Get the contents of a general purpose (address-size) register for this frame
// (usually retrieved from the next frame)
@@ -164,6 +192,10 @@ private:
void
UnwindLogMsgVerbose (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+ bool
+ IsUnwindPlanValidForCurrentPC(lldb::UnwindPlanSP unwind_plan_sp, int &valid_pc_offset);
+
+
lldb_private::Thread& m_thread;
///
@@ -171,8 +203,10 @@ private:
// i.e. where THIS frame saved them
///
- lldb::UnwindPlanSP m_fast_unwind_plan_sp; // may be NULL
+ lldb::UnwindPlanSP m_fast_unwind_plan_sp; // may be NULL
lldb::UnwindPlanSP m_full_unwind_plan_sp;
+ lldb::UnwindPlanSP m_fallback_unwind_plan_sp; // may be NULL
+
bool m_all_registers_available; // Can we retrieve all regs or just nonvolatile regs?
int m_frame_type; // enum FrameType
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp
index 552ae50..5db08e5 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp
@@ -26,8 +26,21 @@ using namespace lldb_private;
UnwindLLDB::UnwindLLDB (Thread &thread) :
Unwind (thread),
m_frames(),
- m_unwind_complete(false)
+ m_unwind_complete(false),
+ m_user_supplied_trap_handler_functions()
{
+ ProcessSP process_sp(thread.GetProcess());
+ if (process_sp)
+ {
+ Args args;
+ process_sp->GetTarget().GetUserSpecifiedTrapHandlerNames (args);
+ size_t count = args.GetArgumentCount();
+ for (size_t i = 0; i < count; i++)
+ {
+ const char *func_name = args.GetArgumentAtIndex(i);
+ m_user_supplied_trap_handler_functions.push_back (ConstString (func_name));
+ }
+ }
}
uint32_t
@@ -95,7 +108,13 @@ UnwindLLDB::AddFirstFrame ()
first_cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp;
m_frames.push_back (first_cursor_sp);
return true;
+
unwind_done:
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ if (log)
+ {
+ log->Printf ("th%d Unwind of this thread is complete.", m_thread.GetIndexID());
+ }
m_unwind_complete = true;
return false;
}
@@ -138,10 +157,27 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi)
}
if (reg_ctx_sp.get() == NULL)
+ {
+ // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return
+ // true. Subsequent calls to TryFallbackUnwindPlan() will return false.
+ if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan())
+ {
+ return AddOneMoreFrame (abi);
+ }
+ if (log)
+ log->Printf ("%*sFrame %d did not get a RegisterContext, stopping.",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
goto unwind_done;
+ }
if (!reg_ctx_sp->IsValid())
{
+ // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return
+ // true. Subsequent calls to TryFallbackUnwindPlan() will return false.
+ if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan())
+ {
+ return AddOneMoreFrame (abi);
+ }
if (log)
{
log->Printf("%*sFrame %d invalid RegisterContext for this frame, stopping stack walk",
@@ -151,6 +187,12 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi)
}
if (!reg_ctx_sp->GetCFA (cursor_sp->cfa))
{
+ // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return
+ // true. Subsequent calls to TryFallbackUnwindPlan() will return false.
+ if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan())
+ {
+ return AddOneMoreFrame (abi);
+ }
if (log)
{
log->Printf("%*sFrame %d did not get CFA for this frame, stopping stack walk",
@@ -160,15 +202,33 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi)
}
if (abi && !abi->CallFrameAddressIsValid(cursor_sp->cfa))
{
- if (log)
+ // On Mac OS X, the _sigtramp asynchronous signal trampoline frame may not have
+ // its (constructed) CFA aligned correctly -- don't do the abi alignment check for
+ // these.
+ if (reg_ctx_sp->IsTrapHandlerFrame() == false)
{
- log->Printf("%*sFrame %d did not get a valid CFA for this frame, stopping stack walk",
- cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return
+ // true. Subsequent calls to TryFallbackUnwindPlan() will return false.
+ if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan())
+ {
+ return AddOneMoreFrame (abi);
+ }
+ if (log)
+ {
+ log->Printf("%*sFrame %d did not get a valid CFA for this frame, stopping stack walk",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ }
+ goto unwind_done;
}
- goto unwind_done;
}
if (!reg_ctx_sp->ReadPC (cursor_sp->start_pc))
{
+ // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return
+ // true. Subsequent calls to TryFallbackUnwindPlan() will return false.
+ if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan())
+ {
+ return AddOneMoreFrame (abi);
+ }
if (log)
{
log->Printf("%*sFrame %d did not get PC for this frame, stopping stack walk",
@@ -178,6 +238,12 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi)
}
if (abi && !abi->CodeAddressIsValid (cursor_sp->start_pc))
{
+ // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return
+ // true. Subsequent calls to TryFallbackUnwindPlan() will return false.
+ if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan())
+ {
+ return AddOneMoreFrame (abi);
+ }
if (log)
{
log->Printf("%*sFrame %d did not get a valid PC, stopping stack walk",
@@ -185,12 +251,26 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi)
}
goto unwind_done;
}
+ if (!m_frames.empty())
+ {
+ // Infinite loop where the current cursor is the same as the previous one...
+ if (m_frames.back()->start_pc == cursor_sp->start_pc && m_frames.back()->cfa == cursor_sp->cfa)
+ {
+ if (log)
+ log->Printf ("th%d pc of this frame is the same as the previous frame and CFAs for both frames are identical -- stopping unwind", m_thread.GetIndexID());
+ goto unwind_done;
+ }
+ }
cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp;
m_frames.push_back (cursor_sp);
return true;
unwind_done:
+ if (log)
+ {
+ log->Printf ("th%d Unwind of this thread is complete.", m_thread.GetIndexID());
+ }
m_unwind_complete = true;
return false;
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.h
index 5725654..eb54003 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.h
@@ -13,6 +13,7 @@
#include <vector>
#include "lldb/lldb-public.h"
+#include "lldb/Core/ConstString.h"
#include "lldb/Symbol/FuncUnwinders.h"
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/Target/RegisterContext.h"
@@ -90,6 +91,24 @@ protected:
SearchForSavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation &regloc, uint32_t starting_frame_num, bool pc_register);
+ //------------------------------------------------------------------
+ /// Provide the list of user-specified trap handler functions
+ ///
+ /// The Platform is one source of trap handler function names; that
+ /// may be augmented via a setting. The setting needs to be converted
+ /// into an array of ConstStrings before it can be used - we only want
+ /// to do that once per thread so it's here in the UnwindLLDB object.
+ ///
+ /// @return
+ /// Vector of ConstStrings of trap handler function names. May be
+ /// empty.
+ //------------------------------------------------------------------
+ const std::vector<ConstString> &
+ GetUserSpecifiedTrapHandlerFunctionNames ()
+ {
+ return m_user_supplied_trap_handler_functions;
+ }
+
private:
struct Cursor
@@ -110,6 +129,7 @@ private:
// number of frames, etc. Otherwise we've only gone as far as directly asked, and m_frames.size()
// is how far we've currently gone.
+ std::vector<ConstString> m_user_supplied_trap_handler_functions;
bool AddOneMoreFrame (ABI *abi);
bool AddFirstFrame ();
OpenPOWER on IntegriCloud