summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
diff options
context:
space:
mode:
authorpatrick <patrick@openbsd.org>2020-08-03 14:33:06 +0000
committerpatrick <patrick@openbsd.org>2020-08-03 14:33:06 +0000
commit061da546b983eb767bad15e67af1174fb0bcf31c (patch)
tree83c78b820819d70aa40c36d90447978b300078c5 /gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
parentImport LLVM 10.0.0 release including clang, lld and lldb. (diff)
downloadwireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.tar.xz
wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.zip
Import LLVM 10.0.0 release including clang, lld and lldb.
ok hackroom tested by plenty
Diffstat (limited to 'gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp')
-rw-r--r--gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp2198
1 files changed, 2198 insertions, 0 deletions
diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
new file mode 100644
index 00000000000..49a589f1498
--- /dev/null
+++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
@@ -0,0 +1,2198 @@
+//===-- RegisterContextLLDB.cpp --------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/ArmUnwindInfo.h"
+#include "lldb/Symbol/CallFrameInfo.h"
+#include "lldb/Symbol/DWARFCallFrameInfo.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/SymbolFile.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/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/lldb-private.h"
+
+#include "RegisterContextLLDB.h"
+
+#include <memory>
+
+using namespace lldb;
+using namespace lldb_private;
+
+static ConstString GetSymbolOrFunctionName(const SymbolContext &sym_ctx) {
+ if (sym_ctx.symbol)
+ return sym_ctx.symbol->GetName();
+ else if (sym_ctx.function)
+ return sym_ctx.function->GetName();
+ return ConstString();
+}
+
+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_fallback_unwind_plan_sp(), m_all_registers_available(false),
+ m_frame_type(-1), m_cfa(LLDB_INVALID_ADDRESS),
+ m_afa(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 == 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.
+
+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() == nullptr) {
+ m_frame_type = eNotAValidFrame;
+ UnwindLogMsg("frame does not have a register context");
+ return;
+ }
+
+ addr_t current_pc = reg_ctx_sp->GetPC();
+
+ if (current_pc == LLDB_INVALID_ADDRESS) {
+ m_frame_type = eNotAValidFrame;
+ UnwindLogMsg("frame does not have a pc");
+ 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.
+ 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.
+ ModuleSP pc_module_sp(m_current_pc.GetModule());
+ if (!m_current_pc.IsValid() || !pc_module_sp) {
+ UnwindLogMsg("using architectural default unwind method");
+ }
+
+ AddressRange addr_range;
+ m_sym_ctx_valid = m_current_pc.ResolveFunctionScope(m_sym_ctx, &addr_range);
+
+ if (m_sym_ctx.symbol) {
+ UnwindLogMsg("with pc value of 0x%" PRIx64 ", symbol name is '%s'",
+ current_pc, GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
+ } else if (m_sym_ctx.function) {
+ UnwindLogMsg("with pc value of 0x%" PRIx64 ", function name is '%s'",
+ current_pc, GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
+ } else {
+ UnwindLogMsg("with pc value of 0x%" PRIx64
+ ", no symbol/function name is known.",
+ current_pc);
+ }
+
+ if (IsTrapHandlerSymbol(process, m_sym_ctx)) {
+ m_frame_type = eTrapHandlerFrame;
+ } 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;
+ lldb::RegisterKind row_register_kind = eRegisterKindGeneric;
+ 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.GetData());
+ }
+ }
+
+ if (!active_row.get()) {
+ UnwindLogMsg("could not find an unwindplan row for this frame's pc");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ if (!ReadFrameAddress(row_register_kind, active_row->GetCFAValue(), m_cfa)) {
+ // Try the fall back unwind plan since the
+ // full unwind plan failed.
+ FuncUnwindersSP func_unwinders_sp;
+ UnwindPlanSP call_site_unwind_plan;
+ bool cfa_status = false;
+
+ if (m_sym_ctx_valid) {
+ func_unwinders_sp =
+ pc_module_sp->GetUnwindTable().GetFuncUnwindersContainingAddress(
+ m_current_pc, m_sym_ctx);
+ }
+
+ if (func_unwinders_sp.get() != nullptr)
+ call_site_unwind_plan = func_unwinders_sp->GetUnwindPlanAtCallSite(
+ process->GetTarget(), m_thread);
+
+ if (call_site_unwind_plan.get() != nullptr) {
+ m_fallback_unwind_plan_sp = call_site_unwind_plan;
+ if (TryFallbackUnwindPlan())
+ cfa_status = true;
+ }
+ if (!cfa_status) {
+ UnwindLogMsg("could not read CFA value for first frame.");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+ } else
+ ReadFrameAddress(row_register_kind, active_row->GetAFAValue(), m_afa);
+
+ UnwindLogMsg("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64
+ " afa is 0x%" PRIx64 " using %s UnwindPlan",
+ (uint64_t)m_current_pc.GetLoadAddress(exe_ctx.GetTargetPtr()),
+ (uint64_t)m_cfa,
+ (uint64_t)m_afa,
+ 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;
+ 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;
+ }
+
+ addr_t pc;
+ if (!ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc)) {
+ UnwindLogMsg("could not get pc value");
+ 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);
+
+ if (log) {
+ UnwindLogMsg("pc = 0x%" PRIx64, pc);
+ addr_t reg_val;
+ if (ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP, reg_val))
+ UnwindLogMsg("fp = 0x%" PRIx64, reg_val);
+ if (ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, reg_val))
+ UnwindLogMsg("sp = 0x%" PRIx64, reg_val);
+ }
+
+ // A pc of 0x0 means it's the end of the stack crawl unless we're above a trap
+ // handler function
+ bool above_trap_handler = false;
+ if (GetNextFrame().get() && GetNextFrame()->IsValid() &&
+ GetNextFrame()->IsTrapHandlerFrame())
+ above_trap_handler = true;
+
+ if (pc == 0 || pc == 0x1) {
+ if (!above_trap_handler) {
+ m_frame_type = eNotAValidFrame;
+ UnwindLogMsg("this frame has a pc of 0x0");
+ return;
+ }
+ }
+
+ const bool allow_section_end = true;
+ m_current_pc.SetLoadAddress(pc, &process->GetTarget(), allow_section_end);
+
+ // 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;
+ UnwindLogMsg("pc is in a non-executable section of memory and this "
+ "isn't the 2nd frame in the stack walk.");
+ return;
+ }
+ }
+
+ if (abi) {
+ m_fast_unwind_plan_sp.reset();
+ m_full_unwind_plan_sp =
+ std::make_shared<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;
+ RegisterKind row_register_kind = m_full_unwind_plan_sp->GetRegisterKind();
+ UnwindPlan::RowSP row = m_full_unwind_plan_sp->GetRowForFunctionOffset(0);
+ if (row.get()) {
+ if (!ReadFrameAddress(row_register_kind, row->GetCFAValue(), m_cfa)) {
+ UnwindLogMsg("failed to get cfa value");
+ if (m_frame_type != eSkipFrame) // don't override eSkipFrame
+ {
+ m_frame_type = eNotAValidFrame;
+ }
+ return;
+ }
+
+ ReadFrameAddress(row_register_kind, row->GetAFAValue(), m_afa);
+
+ // A couple of sanity checks..
+ if (m_cfa == LLDB_INVALID_ADDRESS || m_cfa == 0 || m_cfa == 1) {
+ UnwindLogMsg("could not find a valid cfa address");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ // m_cfa should point into the stack memory; if we can query memory
+ // region permissions, see if the memory is allocated & readable.
+ if (process->GetLoadAddressPermissions(m_cfa, permissions) &&
+ (permissions & ePermissionsReadable) == 0) {
+ m_frame_type = eNotAValidFrame;
+ UnwindLogMsg(
+ "the CFA points to a region of memory that is not readable");
+ return;
+ }
+ } else {
+ UnwindLogMsg("could not find a row for function offset zero");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ if (CheckIfLoopingStack()) {
+ TryFallbackUnwindPlan();
+ if (CheckIfLoopingStack()) {
+ UnwindLogMsg("same CFA address as next frame, assuming the unwind is "
+ "looping - stopping");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+ }
+
+ UnwindLogMsg("initialized frame cfa is 0x%" PRIx64 " afa is 0x%" PRIx64,
+ (uint64_t)m_cfa, (uint64_t)m_afa);
+ return;
+ }
+ m_frame_type = eNotAValidFrame;
+ UnwindLogMsg("could not find any symbol for this pc, or a default unwind "
+ "plan, to continue unwind.");
+ return;
+ }
+
+ AddressRange addr_range;
+ m_sym_ctx_valid = m_current_pc.ResolveFunctionScope(m_sym_ctx, &addr_range);
+
+ if (m_sym_ctx.symbol) {
+ UnwindLogMsg("with pc value of 0x%" PRIx64 ", symbol name is '%s'", pc,
+ GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
+ } else if (m_sym_ctx.function) {
+ UnwindLogMsg("with pc value of 0x%" PRIx64 ", function name is '%s'", pc,
+ GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
+ } else {
+ UnwindLogMsg("with pc value of 0x%" PRIx64
+ ", no symbol/function name is known.",
+ pc);
+ }
+
+ bool decr_pc_and_recompute_addr_range;
+
+ if (!m_sym_ctx_valid) {
+ // Always decrement and recompute if the symbol lookup failed
+ decr_pc_and_recompute_addr_range = true;
+ } else if (GetNextFrame()->m_frame_type == eTrapHandlerFrame ||
+ GetNextFrame()->m_frame_type == eDebuggerFrame) {
+ // Don't decrement if we're "above" an asynchronous event like
+ // sigtramp.
+ decr_pc_and_recompute_addr_range = false;
+ } else if (!addr_range.GetBaseAddress().IsValid() ||
+ addr_range.GetBaseAddress().GetSection() != m_current_pc.GetSection() ||
+ addr_range.GetBaseAddress().GetOffset() != m_current_pc.GetOffset()) {
+ // If our "current" pc isn't the start of a function, no need
+ // to decrement and recompute.
+ decr_pc_and_recompute_addr_range = false;
+ } else if (IsTrapHandlerSymbol(process, m_sym_ctx)) {
+ // Signal dispatch may set the return address of the handler it calls to
+ // point to the first byte of a return trampoline (like __kernel_rt_sigreturn),
+ // so do not decrement and recompute if the symbol we already found is a trap
+ // handler.
+ decr_pc_and_recompute_addr_range = false;
+ } else {
+ // Decrement to find the function containing the call.
+ 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) {
+ UnwindLogMsg("Backing up the pc value of 0x%" PRIx64
+ " by 1 and re-doing symbol lookup; old symbol was %s",
+ pc, GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
+ Address temporary_pc;
+ temporary_pc.SetLoadAddress(pc - 1, &process->GetTarget());
+ m_sym_ctx.Clear(false);
+ m_sym_ctx_valid = temporary_pc.ResolveFunctionScope(m_sym_ctx, &addr_range);
+
+ UnwindLogMsg("Symbol is now %s",
+ GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
+ }
+
+ // 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 = pc - m_start_pc.GetLoadAddress(&process->GetTarget());
+ 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--;
+ if (m_sym_ctx_valid) {
+ m_current_pc.SetLoadAddress(pc - 1, &process->GetTarget());
+ }
+ }
+ } else {
+ m_start_pc = m_current_pc;
+ m_current_offset = -1;
+ m_current_offset_backed_up_one = -1;
+ }
+
+ if (IsTrapHandlerSymbol(process, m_sym_ctx)) {
+ m_frame_type = eTrapHandlerFrame;
+ } 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;
+ RegisterKind row_register_kind = eRegisterKindGeneric;
+
+ // 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();
+ PropagateTrapHandlerFlagFromUnwindPlan(m_fast_unwind_plan_sp);
+ 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.GetData());
+ }
+ } else {
+ m_full_unwind_plan_sp = GetFullUnwindPlanForFrame();
+ int valid_offset = -1;
+ if (IsUnwindPlanValidForCurrentPC(m_full_unwind_plan_sp, valid_offset)) {
+ active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset(valid_offset);
+ row_register_kind = m_full_unwind_plan_sp->GetRegisterKind();
+ PropagateTrapHandlerFlagFromUnwindPlan(m_full_unwind_plan_sp);
+ 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.GetData());
+ }
+ }
+ }
+
+ if (!active_row.get()) {
+ m_frame_type = eNotAValidFrame;
+ UnwindLogMsg("could not find unwind row for this pc");
+ return;
+ }
+
+ if (!ReadFrameAddress(row_register_kind, active_row->GetCFAValue(), m_cfa)) {
+ UnwindLogMsg("failed to get cfa");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ ReadFrameAddress(row_register_kind, active_row->GetAFAValue(), m_afa);
+
+ UnwindLogMsg("m_cfa = 0x%" PRIx64 " m_afa = 0x%" PRIx64, m_cfa, m_afa);
+
+ if (CheckIfLoopingStack()) {
+ TryFallbackUnwindPlan();
+ if (CheckIfLoopingStack()) {
+ 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 " afa is 0x%" PRIx64,
+ (uint64_t)m_current_pc.GetLoadAddress(exe_ctx.GetTargetPtr()),
+ (uint64_t)m_cfa,
+ (uint64_t)m_afa);
+}
+
+bool RegisterContextLLDB::CheckIfLoopingStack() {
+ // 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. To detect when we have the same CFA value
+ // multiple times, we compare the
+ // CFA of the current
+ // frame with the 2nd next frame because in some specail case (e.g. signal
+ // hanlders, hand written assembly without ABI compiance) we can have 2
+ // frames with the same
+ // CFA (in theory we
+ // can have arbitrary number of frames with the same CFA, but more then 2 is
+ // very very unlikely)
+
+ RegisterContextLLDB::SharedPtr next_frame = GetNextFrame();
+ if (next_frame) {
+ RegisterContextLLDB::SharedPtr next_next_frame = next_frame->GetNextFrame();
+ addr_t next_next_frame_cfa = LLDB_INVALID_ADDRESS;
+ if (next_next_frame && next_next_frame->GetCFA(next_next_frame_cfa)) {
+ if (next_next_frame_cfa == m_cfa) {
+ // We have a loop in the stack unwind
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+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 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
+
+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() == nullptr)
+ return unwind_plan_sp;
+
+ if (IsFrameZero())
+ return unwind_plan_sp;
+
+ FuncUnwindersSP func_unwinders_sp(
+ pc_module_sp->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 == eTrapHandlerFrame || m_frame_type == eDebuggerFrame)
+ return unwind_plan_sp;
+
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanFastUnwind(
+ *m_thread.CalculateTarget(), 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 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
+
+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() : nullptr;
+ if (abi) {
+ arch_default_unwind_plan_sp =
+ std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
+ abi->CreateDefaultUnwindPlan(*arch_default_unwind_plan_sp);
+ } else {
+ UnwindLogMsg(
+ "unable to get architectural default UnwindPlan from ABI plugin");
+ }
+
+ bool behaves_like_zeroth_frame = false;
+ if (IsFrameZero() || GetNextFrame()->m_frame_type == eTrapHandlerFrame ||
+ 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 we
+ // have a symbol context & a symbol, we don't want to follow this code path.
+ // This is for jumping to memory regions without any information available.
+
+ if ((!m_sym_ctx_valid ||
+ (m_sym_ctx.function == nullptr && m_sym_ctx.symbol == nullptr)) &&
+ 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 &&
+ process->GetLoadAddressPermissions(current_pc_addr, permissions) &&
+ (permissions & ePermissionsExecutable) == 0)) {
+ if (abi) {
+ unwind_plan_sp =
+ std::make_shared<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() == nullptr) {
+ 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->GetUnwindTable().GetFuncUnwindersContainingAddress(
+ m_current_pc, m_sym_ctx);
+ }
+
+ // No FuncUnwinders available for this pc (stripped function symbols, lldb
+ // could not augment its function table with another source, like
+ // LC_FUNCTION_STARTS or eh_frame in ObjectFileMachO). See if eh_frame or the
+ // .ARM.exidx tables have unwind information for this address, else fall back
+ // to the architectural default unwind.
+ if (!func_unwinders_sp) {
+ m_frame_type = eNormalFrame;
+
+ if (!pc_module_sp || !pc_module_sp->GetObjectFile() ||
+ !m_current_pc.IsValid())
+ return arch_default_unwind_plan_sp;
+
+ // Even with -fomit-frame-pointer, we can try eh_frame to get back on
+ // track.
+ DWARFCallFrameInfo *eh_frame =
+ pc_module_sp->GetUnwindTable().GetEHFrameInfo();
+ if (eh_frame) {
+ unwind_plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
+ if (eh_frame->GetUnwindPlan(m_current_pc, *unwind_plan_sp))
+ return unwind_plan_sp;
+ else
+ unwind_plan_sp.reset();
+ }
+
+ ArmUnwindInfo *arm_exidx =
+ pc_module_sp->GetUnwindTable().GetArmUnwindInfo();
+ if (arm_exidx) {
+ unwind_plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
+ if (arm_exidx->GetUnwindPlan(exe_ctx.GetTargetRef(), m_current_pc,
+ *unwind_plan_sp))
+ return unwind_plan_sp;
+ else
+ unwind_plan_sp.reset();
+ }
+
+ CallFrameInfo *object_file_unwind =
+ pc_module_sp->GetUnwindTable().GetObjectFileUnwindInfo();
+ if (object_file_unwind) {
+ unwind_plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
+ if (object_file_unwind->GetUnwindPlan(m_current_pc, *unwind_plan_sp))
+ return unwind_plan_sp;
+ else
+ unwind_plan_sp.reset();
+ }
+
+ 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 == eTrapHandlerFrame && process) {
+ m_fast_unwind_plan_sp.reset();
+ unwind_plan_sp =
+ func_unwinders_sp->GetEHFrameUnwindPlan(process->GetTarget());
+ if (!unwind_plan_sp)
+ unwind_plan_sp =
+ func_unwinders_sp->GetObjectFileUnwindPlan(process->GetTarget());
+ 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 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)) {
+ // We must specifically call the GetEHFrameUnwindPlan() method here --
+ // normally we would call GetUnwindPlanAtCallSite() -- because CallSite may
+ // return an unwind plan sourced from either eh_frame (that's what we
+ // intend) or compact unwind (this won't work)
+ unwind_plan_sp =
+ func_unwinders_sp->GetEHFrameUnwindPlan(process->GetTarget());
+ if (!unwind_plan_sp)
+ unwind_plan_sp =
+ func_unwinders_sp->GetObjectFileUnwindPlan(process->GetTarget());
+ 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 && process) {
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite(
+ process->GetTarget(), 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. The assembly profilers work really well with compiler-
+ // generated functions but hand- written assembly can be problematic.
+ // We set the eh_frame based unwind plan as our fallback unwind plan if
+ // instruction emulation doesn't work out even for non call sites if it
+ // is available and use the architecture default unwind plan if it is
+ // not available. The eh_frame unwind plan is more reliable even on non
+ // call sites then the architecture default plan and for hand written
+ // assembly code it is often written in a way that it valid at all
+ // location what helps in the most common cases when the instruction
+ // emulation fails.
+ UnwindPlanSP call_site_unwind_plan =
+ func_unwinders_sp->GetUnwindPlanAtCallSite(process->GetTarget(),
+ m_thread);
+ if (call_site_unwind_plan &&
+ call_site_unwind_plan.get() != unwind_plan_sp.get() &&
+ call_site_unwind_plan->GetSourceName() !=
+ unwind_plan_sp->GetSourceName()) {
+ m_fallback_unwind_plan_sp = call_site_unwind_plan;
+ } else {
+ m_fallback_unwind_plan_sp = arch_default_unwind_plan_sp;
+ }
+ }
+ UnwindLogMsgVerbose("frame uses %s for full UnwindPlan because this "
+ "is the non-call site unwind plan and this is a "
+ "zeroth frame",
+ unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+
+ // If we're on the first instruction of a function, and we have an
+ // architectural default UnwindPlan for the initial instruction of a
+ // function, use that.
+ if (m_current_offset == 0) {
+ unwind_plan_sp =
+ func_unwinders_sp->GetUnwindPlanArchitectureDefaultAtFunctionEntry(
+ m_thread);
+ if (unwind_plan_sp) {
+ UnwindLogMsgVerbose("frame uses %s for full UnwindPlan because we are at "
+ "the first instruction of a function",
+ 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
+ if (process) {
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite(
+ process->GetTarget(), m_thread);
+ }
+ int valid_offset = -1;
+ if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset)) {
+ UnwindLogMsgVerbose("frame uses %s for full UnwindPlan because this "
+ "is the call-site unwind plan",
+ 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.
+ if (process) {
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite(
+ process->GetTarget(), m_thread);
+ }
+ if (unwind_plan_sp &&
+ unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo) {
+ // We probably have an UnwindPlan created by inspecting assembly
+ // instructions. The assembly profilers work really well with compiler-
+ // generated functions but hand- written assembly can be problematic. We
+ // set the eh_frame based unwind plan as our fallback unwind plan if
+ // instruction emulation doesn't work out even for non call sites if it is
+ // available and use the architecture default unwind plan if it is not
+ // available. The eh_frame unwind plan is more reliable even on non call
+ // sites then the architecture default plan and for hand written assembly
+ // code it is often written in a way that it valid at all location what
+ // helps in the most common cases when the instruction emulation fails.
+ UnwindPlanSP call_site_unwind_plan =
+ func_unwinders_sp->GetUnwindPlanAtCallSite(process->GetTarget(),
+ m_thread);
+ if (call_site_unwind_plan &&
+ call_site_unwind_plan.get() != unwind_plan_sp.get() &&
+ call_site_unwind_plan->GetSourceName() !=
+ unwind_plan_sp->GetSourceName()) {
+ m_fallback_unwind_plan_sp = call_site_unwind_plan;
+ } else {
+ m_fallback_unwind_plan_sp = arch_default_unwind_plan_sp;
+ }
+ }
+
+ if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset)) {
+ UnwindLogMsgVerbose("frame uses %s for full UnwindPlan because we "
+ "failed to find a call-site unwind plan that would work",
+ unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+
+ // If nothing else, use the architectural default UnwindPlan and hope that
+ // does the job.
+ if (arch_default_unwind_plan_sp)
+ UnwindLogMsgVerbose(
+ "frame uses %s for full UnwindPlan because we are falling back "
+ "to the arch default plan",
+ arch_default_unwind_plan_sp->GetSourceName().GetCString());
+ else
+ UnwindLogMsg(
+ "Unable to find any UnwindPlan for full unwind of this frame.");
+
+ 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(
+ lldb::RegisterKind 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::eRegisterInLiveRegisterContext: {
+ const RegisterInfo *other_reg_info =
+ GetRegisterInfoAtIndex(regloc.location.register_number);
+
+ if (!other_reg_info)
+ return false;
+
+ success =
+ m_thread.GetRegisterContext()->ReadRegister(other_reg_info, value);
+ } break;
+ 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:
+ llvm_unreachable("FIXME debugger inferior function call unwind");
+ case UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation: {
+ Status error(ReadRegisterValueFromMemory(
+ reg_info, regloc.location.target_memory_location, reg_info->byte_size,
+ value));
+ success = error.Success();
+ } break;
+ default:
+ llvm_unreachable("Unknown RegisterLocation type.");
+ }
+ 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::eRegisterInLiveRegisterContext: {
+ const RegisterInfo *other_reg_info =
+ GetRegisterInfoAtIndex(regloc.location.register_number);
+ success =
+ m_thread.GetRegisterContext()->WriteRegister(other_reg_info, value);
+ } break;
+ 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:
+ llvm_unreachable("FIXME debugger inferior function call unwind");
+ case UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation: {
+ Status error(WriteRegisterValueToMemory(
+ reg_info, regloc.location.target_memory_location, reg_info->byte_size,
+ value));
+ success = error.Success();
+ } break;
+ default:
+ llvm_unreachable("Unknown RegisterLocation type.");
+ }
+ return success;
+}
+
+bool RegisterContextLLDB::IsValid() const {
+ return m_frame_type != eNotAValidFrame;
+}
+
+// After the final stack frame in a stack walk we'll get one invalid
+// (eNotAValidFrame) stack frame -- one past the end of the stack walk. But
+// higher-level code will need to tell the differnece between "the unwind plan
+// below this frame failed" versus "we successfully completed the stack walk"
+// so this method helps to disambiguate that.
+
+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 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;
+}
+
+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
+RegisterContextLLDB::SavedLocationForRegister(
+ uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation &regloc) {
+ RegisterNumber regnum(m_thread, eRegisterKindLLDB, lldb_regnum);
+
+ // 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(regnum.GetAsKind(eRegisterKindLLDB));
+ if (iterator != m_registers.end()) {
+ regloc = iterator->second;
+ UnwindLogMsg("supplying caller's saved %s (%d)'s location, cached",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ 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 = kNumRegisterKinds;
+
+ 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();
+ if (regnum.GetAsKind(unwindplan_registerkind) == LLDB_INVALID_REGNUM) {
+ UnwindLogMsg("could not convert lldb regnum %s (%d) into %d RegisterKind "
+ "reg numbering scheme",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB),
+ (int)unwindplan_registerkind);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ if (active_row->GetRegisterInfo(regnum.GetAsKind(unwindplan_registerkind),
+ unwindplan_regloc)) {
+ UnwindLogMsg(
+ "supplying caller's saved %s (%d)'s location using FastUnwindPlan",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ 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) {
+ RegisterNumber pc_regnum(m_thread, eRegisterKindGeneric,
+ LLDB_REGNUM_GENERIC_PC);
+
+ UnwindPlan::RowSP active_row =
+ m_full_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset);
+ unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind();
+
+ RegisterNumber return_address_reg;
+
+ // 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 (pc_regnum.IsValid() && pc_regnum == regnum &&
+ m_full_unwind_plan_sp->GetReturnAddressRegister() !=
+ LLDB_INVALID_REGNUM) {
+
+ return_address_reg.init(
+ m_thread, m_full_unwind_plan_sp->GetRegisterKind(),
+ m_full_unwind_plan_sp->GetReturnAddressRegister());
+ regnum = return_address_reg;
+ UnwindLogMsg("requested caller's saved PC but this UnwindPlan uses a "
+ "RA reg; getting %s (%d) instead",
+ return_address_reg.GetName(),
+ return_address_reg.GetAsKind(eRegisterKindLLDB));
+ } else {
+ if (regnum.GetAsKind(unwindplan_registerkind) == LLDB_INVALID_REGNUM) {
+ if (unwindplan_registerkind == eRegisterKindGeneric) {
+ UnwindLogMsg("could not convert lldb regnum %s (%d) into "
+ "eRegisterKindGeneric reg numbering scheme",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ } else {
+ UnwindLogMsg("could not convert lldb regnum %s (%d) into %d "
+ "RegisterKind reg numbering scheme",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB),
+ (int)unwindplan_registerkind);
+ }
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ }
+
+ if (regnum.IsValid() &&
+ active_row->GetRegisterInfo(regnum.GetAsKind(unwindplan_registerkind),
+ unwindplan_regloc)) {
+ have_unwindplan_regloc = true;
+ UnwindLogMsg(
+ "supplying caller's saved %s (%d)'s location using %s UnwindPlan",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB),
+ 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 && return_address_reg.IsValid() &&
+ IsFrameZero()) {
+ if (return_address_reg.GetAsKind(eRegisterKindLLDB) !=
+ LLDB_INVALID_REGNUM) {
+ lldb_private::UnwindLLDB::RegisterLocation new_regloc;
+ new_regloc.type =
+ UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext;
+ new_regloc.location.register_number =
+ return_address_reg.GetAsKind(eRegisterKindLLDB);
+ m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc;
+ regloc = new_regloc;
+ UnwindLogMsg("supplying caller's register %s (%d) from the live "
+ "RegisterContext at frame 0, saved in %d",
+ return_address_reg.GetName(),
+ return_address_reg.GetAsKind(eRegisterKindLLDB),
+ return_address_reg.GetAsKind(eRegisterKindLLDB));
+ 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
+ RegisterNumber arch_default_ra_regnum(m_thread, eRegisterKindGeneric,
+ LLDB_REGNUM_GENERIC_RA);
+
+ if (arch_default_ra_regnum.GetAsKind(unwindplan_registerkind) !=
+ LLDB_INVALID_REGNUM &&
+ pc_regnum == regnum && unwindplan_regloc.IsInOtherRegister() &&
+ unwindplan_regloc.GetRegisterNumber() ==
+ arch_default_ra_regnum.GetAsKind(unwindplan_registerkind) &&
+ 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
+ if (ForceSwitchToFallbackUnwindPlan()) {
+ // Update for the possibly new unwind plan
+ unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind();
+ UnwindPlan::RowSP active_row =
+ m_full_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset);
+
+ // Sanity check: Verify that we can fetch a pc value and CFA value
+ // with this unwind plan
+
+ RegisterNumber arch_default_pc_reg(m_thread, eRegisterKindGeneric,
+ LLDB_REGNUM_GENERIC_PC);
+ bool can_fetch_pc_value = false;
+ bool can_fetch_cfa = false;
+ addr_t cfa_value;
+ if (active_row) {
+ if (arch_default_pc_reg.GetAsKind(unwindplan_registerkind) !=
+ LLDB_INVALID_REGNUM &&
+ active_row->GetRegisterInfo(
+ arch_default_pc_reg.GetAsKind(unwindplan_registerkind),
+ unwindplan_regloc)) {
+ can_fetch_pc_value = true;
+ }
+ if (ReadFrameAddress(unwindplan_registerkind,
+ active_row->GetCFAValue(), cfa_value)) {
+ can_fetch_cfa = true;
+ }
+ }
+
+ have_unwindplan_regloc = can_fetch_pc_value && can_fetch_cfa;
+ } else {
+ // We were unable to fall back to another unwind plan
+ have_unwindplan_regloc = false;
+ }
+ }
+ }
+ }
+
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ if (!have_unwindplan_regloc) {
+ // If the UnwindPlan failed to give us an unwind location for this
+ // register, we may be able to fall back to some ABI-defined default. For
+ // example, some ABIs allow to determine the caller's SP via the CFA. Also,
+ // the ABI may set volatile registers to the undefined state.
+ ABI *abi = process ? process->GetABI().get() : nullptr;
+ if (abi) {
+ const RegisterInfo *reg_info =
+ GetRegisterInfoAtIndex(regnum.GetAsKind(eRegisterKindLLDB));
+ if (reg_info &&
+ abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc)) {
+ UnwindLogMsg(
+ "supplying caller's saved %s (%d)'s location using ABI default",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ have_unwindplan_regloc = true;
+ }
+ }
+ }
+
+ if (!have_unwindplan_regloc) {
+ 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::eRegisterInLiveRegisterContext;
+ new_regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB);
+ m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc;
+ regloc = new_regloc;
+ UnwindLogMsg("supplying caller's register %s (%d) from the live "
+ "RegisterContext at frame 0",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ } else {
+ std::string unwindplan_name("");
+ if (m_full_unwind_plan_sp) {
+ unwindplan_name += "via '";
+ unwindplan_name += m_full_unwind_plan_sp->GetSourceName().AsCString();
+ unwindplan_name += "'";
+ }
+ UnwindLogMsg("no save location for %s (%d) %s", regnum.GetName(),
+ regnum.GetAsKind(eRegisterKindLLDB),
+ unwindplan_name.c_str());
+ }
+ 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[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc;
+ UnwindLogMsg("save location for %s (%d) is unspecified, continue searching",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+
+ if (unwindplan_regloc.IsUndefined()) {
+ UnwindLogMsg(
+ "did not supply reg location for %s (%d) because it is volatile",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile;
+ }
+
+ if (unwindplan_regloc.IsSame()) {
+ if (!IsFrameZero() &&
+ (regnum.GetAsKind(eRegisterKindGeneric) == LLDB_REGNUM_GENERIC_PC ||
+ regnum.GetAsKind(eRegisterKindGeneric) == LLDB_REGNUM_GENERIC_RA)) {
+ UnwindLogMsg("register %s (%d) is marked as 'IsSame' - it is a pc or "
+ "return address reg on a non-zero frame -- treat as if we "
+ "have no information",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ } else {
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister;
+ regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB);
+ m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg(
+ "supplying caller's register %s (%d), saved in register %s (%d)",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB),
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ }
+
+ if (unwindplan_regloc.IsCFAPlusOffset()) {
+ int offset = unwindplan_regloc.GetOffset();
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
+ regloc.location.inferred_value = m_cfa + offset;
+ m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg("supplying caller's register %s (%d), value is CFA plus "
+ "offset %d [value is 0x%" PRIx64 "]",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), offset,
+ regloc.location.inferred_value);
+ 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[regnum.GetAsKind(eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg("supplying caller's register %s (%d) from the stack, saved at "
+ "CFA plus offset %d [saved at 0x%" PRIx64 "]",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), offset,
+ regloc.location.target_memory_location);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
+ if (unwindplan_regloc.IsAFAPlusOffset()) {
+ if (m_afa == LLDB_INVALID_ADDRESS)
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+
+ int offset = unwindplan_regloc.GetOffset();
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
+ regloc.location.inferred_value = m_afa + offset;
+ m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg("supplying caller's register %s (%d), value is AFA plus "
+ "offset %d [value is 0x%" PRIx64 "]",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), offset,
+ regloc.location.inferred_value);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
+ if (unwindplan_regloc.IsAtAFAPlusOffset()) {
+ if (m_afa == LLDB_INVALID_ADDRESS)
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+
+ int offset = unwindplan_regloc.GetOffset();
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation;
+ regloc.location.target_memory_location = m_afa + offset;
+ m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg("supplying caller's register %s (%d) from the stack, saved at "
+ "AFA plus offset %d [saved at 0x%" PRIx64 "]",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), offset,
+ regloc.location.target_memory_location);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
+ if (unwindplan_regloc.IsInOtherRegister()) {
+ uint32_t unwindplan_regnum = unwindplan_regloc.GetRegisterNumber();
+ RegisterNumber row_regnum(m_thread, unwindplan_registerkind,
+ unwindplan_regnum);
+ if (row_regnum.GetAsKind(eRegisterKindLLDB) == LLDB_INVALID_REGNUM) {
+ UnwindLogMsg("could not supply caller's %s (%d) location - was saved in "
+ "another reg but couldn't convert that regnum",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister;
+ regloc.location.register_number = row_regnum.GetAsKind(eRegisterKindLLDB);
+ m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg(
+ "supplying caller's register %s (%d), saved in register %s (%d)",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB),
+ row_regnum.GetName(), row_regnum.GetAsKind(eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
+ if (unwindplan_regloc.IsDWARFExpression() ||
+ unwindplan_regloc.IsAtDWARFExpression()) {
+ DataExtractor dwarfdata(unwindplan_regloc.GetDWARFExpressionBytes(),
+ unwindplan_regloc.GetDWARFExpressionLength(),
+ process->GetByteOrder(),
+ process->GetAddressByteSize());
+ ModuleSP opcode_ctx;
+ DWARFExpression dwarfexpr(opcode_ctx, dwarfdata, nullptr);
+ dwarfexpr.SetRegisterKind(unwindplan_registerkind);
+ Value cfa_val = Scalar(m_cfa);
+ cfa_val.SetValueType(Value::eValueTypeLoadAddress);
+ Value result;
+ Status error;
+ if (dwarfexpr.Evaluate(&exe_ctx, this, 0, &cfa_val, nullptr, 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[regnum.GetAsKind(eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg("supplying caller's register %s (%d) via DWARF expression "
+ "(IsDWARFExpression)",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ } else {
+ regloc.type =
+ UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation;
+ regloc.location.target_memory_location = val;
+ m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg("supplying caller's register %s (%d) via DWARF expression "
+ "(IsAtDWARFExpression)",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ }
+ UnwindLogMsg("tried to use IsDWARFExpression or IsAtDWARFExpression for %s "
+ "(%d) but failed",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+
+ UnwindLogMsg("no save location for %s (%d) in this stack frame",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+
+ // FIXME UnwindPlan::Row types atDWARFExpression and isDWARFExpression are
+ // unsupported.
+
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+}
+
+// TryFallbackUnwindPlan() -- this method is a little tricky.
+//
+// When this is called, the frame above -- the caller frame, the "previous"
+// frame -- is invalid or bad.
+//
+// Instead of stopping the stack walk here, we'll try a different UnwindPlan
+// and see if we can get a valid frame above us.
+//
+// This most often happens when an unwind plan based on assembly instruction
+// inspection is not correct -- mostly with hand-written assembly functions or
+// functions where the stack frame is set up "out of band", e.g. the kernel
+// saved the register context and then called an asynchronous trap handler like
+// _sigtramp.
+//
+// Often in these cases, if we just do a dumb stack walk we'll get past this
+// tricky frame and our usual techniques can continue to be used.
+
+bool RegisterContextLLDB::TryFallbackUnwindPlan() {
+ if (m_fallback_unwind_plan_sp.get() == nullptr)
+ return false;
+
+ if (m_full_unwind_plan_sp.get() == nullptr)
+ return false;
+
+ if (m_full_unwind_plan_sp.get() == m_fallback_unwind_plan_sp.get() ||
+ m_full_unwind_plan_sp->GetSourceName() ==
+ m_fallback_unwind_plan_sp->GetSourceName()) {
+ return false;
+ }
+
+ // If a compiler generated unwind plan failed, trying the arch default
+ // unwindplan isn't going to do any better.
+ if (m_full_unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolYes)
+ return false;
+
+ // Get the caller's pc value and our own CFA value. Swap in the fallback
+ // unwind plan, re-fetch the caller's pc value and CFA value. If they're the
+ // same, then the fallback unwind plan provides no benefit.
+
+ RegisterNumber pc_regnum(m_thread, eRegisterKindGeneric,
+ LLDB_REGNUM_GENERIC_PC);
+
+ addr_t old_caller_pc_value = LLDB_INVALID_ADDRESS;
+ addr_t new_caller_pc_value = LLDB_INVALID_ADDRESS;
+ UnwindLLDB::RegisterLocation regloc;
+ if (SavedLocationForRegister(pc_regnum.GetAsKind(eRegisterKindLLDB),
+ regloc) ==
+ UnwindLLDB::RegisterSearchResult::eRegisterFound) {
+ const RegisterInfo *reg_info =
+ GetRegisterInfoAtIndex(pc_regnum.GetAsKind(eRegisterKindLLDB));
+ if (reg_info) {
+ RegisterValue reg_value;
+ if (ReadRegisterValueFromRegisterLocation(regloc, reg_info, reg_value)) {
+ old_caller_pc_value = reg_value.GetAsUInt64();
+ }
+ }
+ }
+
+ // This is a tricky wrinkle! If SavedLocationForRegister() detects a really
+ // impossible register location for the full unwind plan, it may call
+ // ForceSwitchToFallbackUnwindPlan() which in turn replaces the full
+ // unwindplan with the fallback... in short, we're done, we're using the
+ // fallback UnwindPlan. We checked if m_fallback_unwind_plan_sp was nullptr
+ // at the top -- the only way it became nullptr since then is via
+ // SavedLocationForRegister().
+ if (m_fallback_unwind_plan_sp.get() == nullptr)
+ return true;
+
+ // Switch the full UnwindPlan to be the fallback UnwindPlan. If we decide
+ // this isn't working, we need to restore. We'll also need to save & restore
+ // the value of the m_cfa ivar. Save is down below a bit in 'old_cfa'.
+ UnwindPlanSP original_full_unwind_plan_sp = m_full_unwind_plan_sp;
+ addr_t old_cfa = m_cfa;
+ addr_t old_afa = m_afa;
+
+ m_registers.clear();
+
+ m_full_unwind_plan_sp = m_fallback_unwind_plan_sp;
+
+ UnwindPlan::RowSP active_row =
+ m_fallback_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset);
+
+ if (active_row &&
+ active_row->GetCFAValue().GetValueType() !=
+ UnwindPlan::Row::FAValue::unspecified) {
+ addr_t new_cfa;
+ if (!ReadFrameAddress(m_fallback_unwind_plan_sp->GetRegisterKind(),
+ active_row->GetCFAValue(), new_cfa) ||
+ new_cfa == 0 || new_cfa == 1 || new_cfa == LLDB_INVALID_ADDRESS) {
+ UnwindLogMsg("failed to get cfa with fallback unwindplan");
+ m_fallback_unwind_plan_sp.reset();
+ m_full_unwind_plan_sp = original_full_unwind_plan_sp;
+ return false;
+ }
+ m_cfa = new_cfa;
+
+ ReadFrameAddress(m_fallback_unwind_plan_sp->GetRegisterKind(),
+ active_row->GetAFAValue(), m_afa);
+
+ if (SavedLocationForRegister(pc_regnum.GetAsKind(eRegisterKindLLDB),
+ regloc) ==
+ UnwindLLDB::RegisterSearchResult::eRegisterFound) {
+ const RegisterInfo *reg_info =
+ GetRegisterInfoAtIndex(pc_regnum.GetAsKind(eRegisterKindLLDB));
+ if (reg_info) {
+ RegisterValue reg_value;
+ if (ReadRegisterValueFromRegisterLocation(regloc, reg_info,
+ reg_value)) {
+ new_caller_pc_value = reg_value.GetAsUInt64();
+ }
+ }
+ }
+
+ if (new_caller_pc_value == LLDB_INVALID_ADDRESS) {
+ UnwindLogMsg("failed to get a pc value for the caller frame with the "
+ "fallback unwind plan");
+ m_fallback_unwind_plan_sp.reset();
+ m_full_unwind_plan_sp = original_full_unwind_plan_sp;
+ m_cfa = old_cfa;
+ m_afa = old_afa;
+ return false;
+ }
+
+ if (old_caller_pc_value == new_caller_pc_value &&
+ m_cfa == old_cfa &&
+ m_afa == old_afa) {
+ UnwindLogMsg("fallback unwind plan got the same values for this frame "
+ "CFA and caller frame pc, not using");
+ m_fallback_unwind_plan_sp.reset();
+ m_full_unwind_plan_sp = original_full_unwind_plan_sp;
+ return false;
+ }
+
+ UnwindLogMsg("trying to unwind from this function with the UnwindPlan '%s' "
+ "because UnwindPlan '%s' failed.",
+ m_fallback_unwind_plan_sp->GetSourceName().GetCString(),
+ original_full_unwind_plan_sp->GetSourceName().GetCString());
+
+ // We've copied the fallback unwind plan into the full - now clear the
+ // fallback.
+ m_fallback_unwind_plan_sp.reset();
+ PropagateTrapHandlerFlagFromUnwindPlan(m_full_unwind_plan_sp);
+ }
+
+ return true;
+}
+
+bool RegisterContextLLDB::ForceSwitchToFallbackUnwindPlan() {
+ if (m_fallback_unwind_plan_sp.get() == nullptr)
+ return false;
+
+ if (m_full_unwind_plan_sp.get() == nullptr)
+ return false;
+
+ if (m_full_unwind_plan_sp.get() == m_fallback_unwind_plan_sp.get() ||
+ m_full_unwind_plan_sp->GetSourceName() ==
+ m_fallback_unwind_plan_sp->GetSourceName()) {
+ return false;
+ }
+
+ UnwindPlan::RowSP active_row =
+ m_fallback_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset);
+
+ if (active_row &&
+ active_row->GetCFAValue().GetValueType() !=
+ UnwindPlan::Row::FAValue::unspecified) {
+ addr_t new_cfa;
+ if (!ReadFrameAddress(m_fallback_unwind_plan_sp->GetRegisterKind(),
+ active_row->GetCFAValue(), new_cfa) ||
+ new_cfa == 0 || new_cfa == 1 || new_cfa == LLDB_INVALID_ADDRESS) {
+ UnwindLogMsg("failed to get cfa with fallback unwindplan");
+ m_fallback_unwind_plan_sp.reset();
+ return false;
+ }
+
+ ReadFrameAddress(m_fallback_unwind_plan_sp->GetRegisterKind(),
+ active_row->GetAFAValue(), m_afa);
+
+ m_full_unwind_plan_sp = m_fallback_unwind_plan_sp;
+ m_fallback_unwind_plan_sp.reset();
+
+ m_registers.clear();
+
+ m_cfa = new_cfa;
+
+ PropagateTrapHandlerFlagFromUnwindPlan(m_full_unwind_plan_sp);
+
+ UnwindLogMsg("switched unconditionally to the fallback unwindplan %s",
+ m_full_unwind_plan_sp->GetSourceName().GetCString());
+ return true;
+ }
+ return false;
+}
+
+void RegisterContextLLDB::PropagateTrapHandlerFlagFromUnwindPlan(
+ lldb::UnwindPlanSP unwind_plan) {
+ if (unwind_plan->GetUnwindPlanForSignalTrap() != eLazyBoolYes) {
+ // Unwind plan does not indicate trap handler. Do nothing. We may
+ // already be flagged as trap handler flag due to the symbol being
+ // in the trap handler symbol list, and that should take precedence.
+ return;
+ } else if (m_frame_type != eNormalFrame) {
+ // If this is already a trap handler frame, nothing to do.
+ // If this is a skip or debug or invalid frame, don't override that.
+ return;
+ }
+
+ m_frame_type = eTrapHandlerFrame;
+
+ if (m_current_offset_backed_up_one != m_current_offset) {
+ // We backed up the pc by 1 to compute the symbol context, but
+ // now need to undo that because the pc of the trap handler
+ // frame may in fact be the first instruction of a signal return
+ // trampoline, rather than the instruction after a call. This
+ // happens on systems where the signal handler dispatch code, rather
+ // than calling the handler and being returned to, jumps to the
+ // handler after pushing the address of a return trampoline on the
+ // stack -- on these systems, when the handler returns, control will
+ // be transferred to the return trampoline, so that's the best
+ // symbol we can present in the callstack.
+ UnwindLogMsg("Resetting current offset and re-doing symbol lookup; "
+ "old symbol was %s",
+ GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
+ m_current_offset_backed_up_one = m_current_offset;
+
+ AddressRange addr_range;
+ m_sym_ctx_valid = m_current_pc.ResolveFunctionScope(m_sym_ctx, &addr_range);
+
+ UnwindLogMsg("Symbol is now %s",
+ GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
+
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ Target *target = &process->GetTarget();
+
+ m_start_pc = addr_range.GetBaseAddress();
+ m_current_offset =
+ m_current_pc.GetLoadAddress(target) - m_start_pc.GetLoadAddress(target);
+ }
+}
+
+bool RegisterContextLLDB::ReadFrameAddress(
+ lldb::RegisterKind row_register_kind, UnwindPlan::Row::FAValue &fa,
+ addr_t &address) {
+ RegisterValue reg_value;
+
+ address = LLDB_INVALID_ADDRESS;
+ addr_t cfa_reg_contents;
+
+ switch (fa.GetValueType()) {
+ case UnwindPlan::Row::FAValue::isRegisterDereferenced: {
+ RegisterNumber cfa_reg(m_thread, row_register_kind,
+ fa.GetRegisterNumber());
+ if (ReadGPRValue(cfa_reg, cfa_reg_contents)) {
+ const RegisterInfo *reg_info =
+ GetRegisterInfoAtIndex(cfa_reg.GetAsKind(eRegisterKindLLDB));
+ RegisterValue reg_value;
+ if (reg_info) {
+ Status error = ReadRegisterValueFromMemory(
+ reg_info, cfa_reg_contents, reg_info->byte_size, reg_value);
+ if (error.Success()) {
+ address = reg_value.GetAsUInt64();
+ UnwindLogMsg(
+ "CFA value via dereferencing reg %s (%d): reg has val 0x%" PRIx64
+ ", CFA value is 0x%" PRIx64,
+ cfa_reg.GetName(), cfa_reg.GetAsKind(eRegisterKindLLDB),
+ cfa_reg_contents, address);
+ return true;
+ } else {
+ UnwindLogMsg("Tried to deref reg %s (%d) [0x%" PRIx64
+ "] but memory read failed.",
+ cfa_reg.GetName(), cfa_reg.GetAsKind(eRegisterKindLLDB),
+ cfa_reg_contents);
+ }
+ }
+ }
+ break;
+ }
+ case UnwindPlan::Row::FAValue::isRegisterPlusOffset: {
+ RegisterNumber cfa_reg(m_thread, row_register_kind,
+ fa.GetRegisterNumber());
+ if (ReadGPRValue(cfa_reg, cfa_reg_contents)) {
+ if (cfa_reg_contents == LLDB_INVALID_ADDRESS || cfa_reg_contents == 0 ||
+ cfa_reg_contents == 1) {
+ UnwindLogMsg(
+ "Got an invalid CFA register value - reg %s (%d), value 0x%" PRIx64,
+ cfa_reg.GetName(), cfa_reg.GetAsKind(eRegisterKindLLDB),
+ cfa_reg_contents);
+ cfa_reg_contents = LLDB_INVALID_ADDRESS;
+ return false;
+ }
+ address = cfa_reg_contents + fa.GetOffset();
+ UnwindLogMsg(
+ "CFA is 0x%" PRIx64 ": Register %s (%d) contents are 0x%" PRIx64
+ ", offset is %d",
+ address, cfa_reg.GetName(), cfa_reg.GetAsKind(eRegisterKindLLDB),
+ cfa_reg_contents, fa.GetOffset());
+ return true;
+ }
+ break;
+ }
+ case UnwindPlan::Row::FAValue::isDWARFExpression: {
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ DataExtractor dwarfdata(fa.GetDWARFExpressionBytes(),
+ fa.GetDWARFExpressionLength(),
+ process->GetByteOrder(),
+ process->GetAddressByteSize());
+ ModuleSP opcode_ctx;
+ DWARFExpression dwarfexpr(opcode_ctx, dwarfdata, nullptr);
+ dwarfexpr.SetRegisterKind(row_register_kind);
+ Value result;
+ Status error;
+ if (dwarfexpr.Evaluate(&exe_ctx, this, 0, nullptr, nullptr, result,
+ &error)) {
+ address = result.GetScalar().ULongLong();
+
+ UnwindLogMsg("CFA value set by DWARF expression is 0x%" PRIx64,
+ address);
+ return true;
+ }
+ UnwindLogMsg("Failed to set CFA value via DWARF expression: %s",
+ error.AsCString());
+ break;
+ }
+ case UnwindPlan::Row::FAValue::isRaSearch: {
+ Process &process = *m_thread.GetProcess();
+ lldb::addr_t return_address_hint = GetReturnAddressHint(fa.GetOffset());
+ if (return_address_hint == LLDB_INVALID_ADDRESS)
+ return false;
+ const unsigned max_iterations = 256;
+ for (unsigned i = 0; i < max_iterations; ++i) {
+ Status st;
+ lldb::addr_t candidate_addr =
+ return_address_hint + i * process.GetAddressByteSize();
+ lldb::addr_t candidate =
+ process.ReadPointerFromMemory(candidate_addr, st);
+ if (st.Fail()) {
+ UnwindLogMsg("Cannot read memory at 0x%" PRIx64 ": %s", candidate_addr,
+ st.AsCString());
+ return false;
+ }
+ Address addr;
+ uint32_t permissions;
+ if (process.GetLoadAddressPermissions(candidate, permissions) &&
+ permissions & lldb::ePermissionsExecutable) {
+ address = candidate_addr;
+ UnwindLogMsg("Heuristically found CFA: 0x%" PRIx64, address);
+ return true;
+ }
+ }
+ UnwindLogMsg("No suitable CFA found");
+ break;
+ }
+ default:
+ return false;
+ }
+ return false;
+}
+
+lldb::addr_t RegisterContextLLDB::GetReturnAddressHint(int32_t plan_offset) {
+ addr_t hint;
+ if (!ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, hint))
+ return LLDB_INVALID_ADDRESS;
+ if (!m_sym_ctx.module_sp || !m_sym_ctx.symbol)
+ return LLDB_INVALID_ADDRESS;
+
+ hint += plan_offset;
+
+ if (auto next = GetNextFrame()) {
+ if (!next->m_sym_ctx.module_sp || !next->m_sym_ctx.symbol)
+ return LLDB_INVALID_ADDRESS;
+ if (auto expected_size =
+ next->m_sym_ctx.module_sp->GetSymbolFile()->GetParameterStackSize(
+ *next->m_sym_ctx.symbol))
+ hint += *expected_size;
+ else {
+ UnwindLogMsgVerbose("Could not retrieve parameter size: %s",
+ llvm::toString(expected_size.takeError()).c_str());
+ return LLDB_INVALID_ADDRESS;
+ }
+ }
+ return hint;
+}
+
+// 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(lldb::RegisterKind 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 || regnum == LLDB_REGNUM_GENERIC_RA)) {
+ pc_register = true;
+ } else if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds(
+ register_kind, regnum, eRegisterKindGeneric, generic_regnum) &&
+ (generic_regnum == LLDB_REGNUM_GENERIC_PC ||
+ generic_regnum == LLDB_REGNUM_GENERIC_RA)) {
+ 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;
+}
+
+bool RegisterContextLLDB::ReadGPRValue(const RegisterNumber &regnum,
+ addr_t &value) {
+ return ReadGPRValue(regnum.GetRegisterKind(), regnum.GetRegisterNumber(),
+ value);
+}
+
+// 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);
+ }
+
+ bool is_pc_regnum = false;
+ if (reg_info->kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_PC ||
+ reg_info->kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_RA) {
+ is_pc_regnum = true;
+ }
+
+ 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, is_pc_regnum))
+ 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()) {
+ bool read_successfully = ReadPC (start_pc);
+ if (read_successfully)
+ {
+ ProcessSP process_sp (m_thread.GetProcess());
+ if (process_sp)
+ {
+ ABI *abi = process_sp->GetABI().get();
+ if (abi)
+ start_pc = abi->FixCodeAddress(start_pc);
+ }
+ }
+ return read_successfully;
+ }
+ 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;
+
+ bool above_trap_handler = false;
+ if (GetNextFrame().get() && GetNextFrame()->IsValid() &&
+ GetNextFrame()->IsTrapHandlerFrame())
+ above_trap_handler = true;
+
+ 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.
+
+ ProcessSP process_sp (m_thread.GetProcess());
+ if (process_sp)
+ {
+ ABI *abi = process_sp->GetABI().get();
+ if (abi)
+ pc = abi->FixCodeAddress(pc);
+ }
+
+ return !(m_all_registers_available == false &&
+ above_trap_handler == false && (pc == 0 || pc == 1));
+ } 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 == nullptr) {
+ if (logmsg)
+ free(logmsg);
+ va_end(args);
+ return;
+ }
+ va_end(args);
+
+ LLDB_LOGF(log, "%*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 == nullptr) {
+ if (logmsg)
+ free(logmsg);
+ va_end(args);
+ return;
+ }
+ va_end(args);
+
+ LLDB_LOGF(log, "%*sth%d/fr%u %s",
+ m_frame_number < 100 ? m_frame_number : 100, "",
+ m_thread.GetIndexID(), m_frame_number, logmsg);
+ free(logmsg);
+ }
+}