| //===-- RegisterContextUnwind.cpp -----------------------------------------===// | |
| // | |
| // 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/Target/RegisterContextUnwind.h" | |
| #include "lldb/Core/Address.h" | |
| #include "lldb/Core/AddressRange.h" | |
| #include "lldb/Core/Module.h" | |
| #include "lldb/Core/Value.h" | |
| #include "lldb/Expression/DWARFExpressionList.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/LanguageRuntime.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/LLDBLog.h" | |
| #include "lldb/Utility/Log.h" | |
| #include "lldb/Utility/RegisterValue.h" | |
| #include "lldb/Utility/VASPrintf.h" | |
| #include "lldb/lldb-private.h" | |
| #include "llvm/Support/Error.h" | |
| #include "llvm/Support/FormatAdapters.h" | |
| #include <cassert> | |
| #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(); | |
| } | |
| static bool CallFrameAddressIsValid(ABISP abi_sp, lldb::addr_t cfa) { | |
| if (cfa == LLDB_INVALID_ADDRESS) | |
| return false; | |
| if (abi_sp) | |
| return abi_sp->CallFrameAddressIsValid(cfa); | |
| return cfa != 0 && cfa != 1; | |
| } | |
| /// Identify a clang outlined function by symbol name. | |
| /// | |
| /// The unwind information in outlined functions from clang can be | |
| /// incorrect, and because of when the outlining happens in the compilation, | |
| /// it may not be possible to fix. We will need to ignore any | |
| /// instruction-emulation or compiler-sourced unwind plans for these | |
| /// functions, and fall back to an ABI default unwindplan. | |
| static bool IsClangOutlinedFunction(const SymbolContext &sym_ctx) { | |
| llvm::StringRef name = GetSymbolOrFunctionName(sym_ctx).GetStringRef(); | |
| if (name.starts_with("OUTLINED_FUNCTION_")) | |
| return true; | |
| return false; | |
| } | |
| #define UNWIND_LOG_IMPL(LOG_FN, log, ...) \ | |
| LOG_FN(log, "{0}th{1}/fr{2} {3}", \ | |
| llvm::indent(std::min(m_frame_number, 100U)), m_thread.GetIndexID(), \ | |
| m_frame_number, llvm::formatv(__VA_ARGS__)) | |
| #define UNWIND_LOG(log, ...) UNWIND_LOG_IMPL(LLDB_LOG, log, __VA_ARGS__) | |
| #define UNWIND_LOG_VERBOSE(log, ...) \ | |
| UNWIND_LOG_IMPL(LLDB_LOG_VERBOSE, log, __VA_ARGS__) | |
| RegisterContextUnwind::RegisterContextUnwind(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(), m_current_offset_backed_up_one(), | |
| m_behaves_like_zeroth_frame(false), 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 RegisterContextUnwind::IsUnwindPlanValidForCurrentPC( | |
| std::shared_ptr<const UnwindPlan> unwind_plan_sp) { | |
| 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 | |
| return true; | |
| } | |
| // If don't have an offset or we're at the start of the function, we've got | |
| // nothing else to try. | |
| if (!m_current_offset || 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.Slide(-1); | |
| if (unwind_plan_sp->PlanValidAtAddress(pc_minus_one)) { | |
| return true; | |
| } | |
| return false; | |
| } | |
| // Initialize a RegisterContextUnwind which is the first frame of a stack -- the | |
| // zeroth frame or currently executing frame. | |
| void RegisterContextUnwind::InitializeZerothFrame() { | |
| Log *log = GetLog(LLDBLog::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; | |
| UNWIND_LOG(log, "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; | |
| UNWIND_LOG(log, "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.) | |
| if (ABISP abi_sp = process->GetABI()) | |
| current_pc = abi_sp->FixCodeAddress(current_pc); | |
| std::shared_ptr<const UnwindPlan> lang_runtime_plan_sp = | |
| LanguageRuntime::GetRuntimeUnwindPlan(m_thread, this, | |
| m_behaves_like_zeroth_frame); | |
| if (lang_runtime_plan_sp.get()) { | |
| UNWIND_LOG(log, "This is an async frame"); | |
| } | |
| // 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) { | |
| UNWIND_LOG(log, "using architectural default unwind method"); | |
| } | |
| m_sym_ctx_valid = m_current_pc.ResolveFunctionScope(m_sym_ctx); | |
| if (m_sym_ctx.symbol) { | |
| UNWIND_LOG(log, "with pc value of {0:x}, symbol name is '{1}'", current_pc, | |
| GetSymbolOrFunctionName(m_sym_ctx)); | |
| } else if (m_sym_ctx.function) { | |
| UNWIND_LOG(log, "with pc value of {0:x}, function name is '{1}'", | |
| current_pc, GetSymbolOrFunctionName(m_sym_ctx)); | |
| } else { | |
| UNWIND_LOG(log, "with pc value of {0:x}, 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 (m_sym_ctx_valid) { | |
| m_start_pc = m_sym_ctx.GetFunctionOrSymbolAddress(); | |
| if (m_current_pc.GetModule() == m_start_pc.GetModule()) { | |
| 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 = std::nullopt; | |
| m_current_offset_backed_up_one = std::nullopt; | |
| } | |
| // We've set m_frame_type and m_sym_ctx before these calls. | |
| m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame(); | |
| m_full_unwind_plan_sp = GetFullUnwindPlanForFrame(); | |
| const UnwindPlan::Row *active_row = nullptr; | |
| lldb::RegisterKind row_register_kind = eRegisterKindGeneric; | |
| // If we have LanguageRuntime UnwindPlan for this unwind, use those | |
| // rules to find the caller frame instead of the function's normal | |
| // UnwindPlans. The full unwind plan for this frame will be | |
| // the LanguageRuntime-provided unwind plan, and there will not be a | |
| // fast unwind plan. | |
| if (lang_runtime_plan_sp.get()) { | |
| active_row = | |
| lang_runtime_plan_sp->GetRowForFunctionOffset(m_current_offset); | |
| row_register_kind = lang_runtime_plan_sp->GetRegisterKind(); | |
| if (!ReadFrameAddress(row_register_kind, active_row->GetCFAValue(), | |
| m_cfa)) { | |
| UNWIND_LOG(log, "Cannot set cfa"); | |
| } else { | |
| m_full_unwind_plan_sp = lang_runtime_plan_sp; | |
| if (log) { | |
| StreamString active_row_strm; | |
| active_row->Dump(active_row_strm, lang_runtime_plan_sp.get(), &m_thread, | |
| m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr())); | |
| UNWIND_LOG(log, "async active row: {0}", active_row_strm.GetString()); | |
| } | |
| UNWIND_LOG(log, "m_cfa = {0:x} m_afa = {1:x}", m_cfa, m_afa); | |
| UNWIND_LOG(log, | |
| "initialized async frame current pc is {0:x} cfa is {1:x} afa " | |
| "is {2:x}", | |
| m_current_pc.GetLoadAddress(exe_ctx.GetTargetPtr()), m_cfa, | |
| m_afa); | |
| return; | |
| } | |
| } | |
| 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(); | |
| PropagateTrapHandlerFlagFromUnwindPlan(m_full_unwind_plan_sp); | |
| if (active_row && 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())); | |
| UNWIND_LOG(log, "{0}", active_row_strm.GetString()); | |
| } | |
| } | |
| if (!active_row) { | |
| UNWIND_LOG(log, "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; | |
| std::shared_ptr<const UnwindPlan> 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 != nullptr) { | |
| m_fallback_unwind_plan_sp = call_site_unwind_plan; | |
| if (TryFallbackUnwindPlan()) | |
| cfa_status = true; | |
| } | |
| if (!cfa_status) { | |
| UNWIND_LOG(log, "could not read CFA value for first frame."); | |
| m_frame_type = eNotAValidFrame; | |
| return; | |
| } | |
| } else | |
| ReadFrameAddress(row_register_kind, active_row->GetAFAValue(), m_afa); | |
| if (m_cfa == LLDB_INVALID_ADDRESS && m_afa == LLDB_INVALID_ADDRESS) { | |
| UNWIND_LOG(log, | |
| "could not read CFA or AFA values for first frame, not valid."); | |
| m_frame_type = eNotAValidFrame; | |
| return; | |
| } | |
| // Give the Architecture a chance to replace the UnwindPlan. | |
| TryAdoptArchitectureUnwindPlan(); | |
| UNWIND_LOG(log, | |
| "initialized frame current pc is {0:x} cfa is {1:x} afa is {2:x} " | |
| "using {3} UnwindPlan", | |
| m_current_pc.GetLoadAddress(exe_ctx.GetTargetPtr()), m_cfa, m_afa, | |
| m_full_unwind_plan_sp->GetSourceName()); | |
| } | |
| // Initialize a RegisterContextUnwind for the non-zeroth frame -- rely on the | |
| // RegisterContextUnwind "below" it to provide things like its current pc value. | |
| void RegisterContextUnwind::InitializeNonZerothFrame() { | |
| Log *log = GetLog(LLDBLog::Unwind); | |
| if (IsFrameZero()) { | |
| m_frame_type = eNotAValidFrame; | |
| UNWIND_LOG(log, "non-zeroth frame tests positive for IsFrameZero -- that " | |
| "shouldn't happen."); | |
| return; | |
| } | |
| if (!GetNextFrame().get() || !GetNextFrame()->IsValid()) { | |
| m_frame_type = eNotAValidFrame; | |
| UNWIND_LOG(log, "Could not get next frame, marking this frame as invalid."); | |
| return; | |
| } | |
| if (!m_thread.GetRegisterContext()) { | |
| m_frame_type = eNotAValidFrame; | |
| UNWIND_LOG(log, "Could not get register context for this thread, marking " | |
| "this frame as invalid."); | |
| return; | |
| } | |
| ExecutionContext exe_ctx(m_thread.shared_from_this()); | |
| Process *process = exe_ctx.GetProcessPtr(); | |
| // Some languages may have a logical parent stack frame which is | |
| // not a real stack frame, but the programmer would consider it to | |
| // be the caller of the frame, e.g. Swift asynchronous frames. | |
| // | |
| // A LanguageRuntime may provide an UnwindPlan that is used in this | |
| // stack trace base on the RegisterContext contents, intsead | |
| // of the normal UnwindPlans we would use for the return-pc. | |
| std::shared_ptr<const UnwindPlan> lang_runtime_plan_sp = | |
| LanguageRuntime::GetRuntimeUnwindPlan(m_thread, this, | |
| m_behaves_like_zeroth_frame); | |
| if (lang_runtime_plan_sp.get()) { | |
| UNWIND_LOG(log, "This is an async frame"); | |
| } | |
| addr_t pc; | |
| if (!ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc)) { | |
| UNWIND_LOG(log, "could not get pc value"); | |
| m_frame_type = eNotAValidFrame; | |
| return; | |
| } | |
| // 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. | |
| ABISP abi_sp = process->GetABI(); | |
| if (abi_sp) | |
| pc = abi_sp->FixCodeAddress(pc); | |
| if (log) { | |
| UNWIND_LOG(log, "pc = {0:x}", pc); | |
| addr_t reg_val; | |
| if (ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP, reg_val)) | |
| UNWIND_LOG(log, "fp = {0:x}", reg_val); | |
| if (ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, reg_val)) | |
| UNWIND_LOG(log, "sp = {0:x}", 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; | |
| UNWIND_LOG(log, "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. If we're above a trap handler, | |
| // we may be at a bogus address because we jumped through a bogus function | |
| // pointer and trapped, so don't force the arch default unwind plan in that | |
| // case. | |
| ModuleSP pc_module_sp(m_current_pc.GetModule()); | |
| if ((!m_current_pc.IsValid() || !pc_module_sp) && | |
| above_trap_handler == false) { | |
| UNWIND_LOG(log, "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()) { | |
| UNWIND_LOG(log, | |
| "had a pc of {0:x} which is not in executable memory but on " | |
| "frame 1 -- allowing it once.", | |
| 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; | |
| UNWIND_LOG(log, "pc is in a non-executable section of memory and this " | |
| "isn't the 2nd frame in the stack walk."); | |
| return; | |
| } | |
| } | |
| if (abi_sp) { | |
| m_fast_unwind_plan_sp.reset(); | |
| m_full_unwind_plan_sp = abi_sp->CreateDefaultUnwindPlan(); | |
| assert(((!m_full_unwind_plan_sp || | |
| m_full_unwind_plan_sp->GetRowCount() == 0 || | |
| m_full_unwind_plan_sp->GetRowAtIndex(0) | |
| ->GetUnspecifiedRegistersAreUndefined())) && | |
| "Default UnwindPlan must set " | |
| "UnspecifiedRegistersAreUndefined to true"); | |
| if (m_frame_type != eSkipFrame) // don't override eSkipFrame | |
| { | |
| m_frame_type = eNormalFrame; | |
| } | |
| m_all_registers_available = false; | |
| m_current_offset = std::nullopt; | |
| m_current_offset_backed_up_one = std::nullopt; | |
| RegisterKind row_register_kind = m_full_unwind_plan_sp->GetRegisterKind(); | |
| if (const UnwindPlan::Row *row = | |
| m_full_unwind_plan_sp->GetRowForFunctionOffset(0)) { | |
| if (!ReadFrameAddress(row_register_kind, row->GetCFAValue(), m_cfa)) { | |
| UNWIND_LOG(log, "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 (!CallFrameAddressIsValid(abi_sp, m_cfa)) { | |
| UNWIND_LOG(log, "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; | |
| UNWIND_LOG( | |
| log, "the CFA points to a region of memory that is not readable"); | |
| return; | |
| } | |
| } else { | |
| UNWIND_LOG(log, "could not find a row for function offset zero"); | |
| m_frame_type = eNotAValidFrame; | |
| return; | |
| } | |
| if (CheckIfLoopingStack()) { | |
| TryFallbackUnwindPlan(); | |
| if (CheckIfLoopingStack()) { | |
| UNWIND_LOG(log, "same CFA address as next frame, assuming the unwind " | |
| "is looping - stopping"); | |
| m_frame_type = eNotAValidFrame; | |
| return; | |
| } | |
| } | |
| // Give the Architecture a chance to replace the UnwindPlan. | |
| TryAdoptArchitectureUnwindPlan(); | |
| UNWIND_LOG(log, "initialized frame cfa is {0:x} afa is {1:x}", m_cfa, | |
| m_afa); | |
| return; | |
| } | |
| m_frame_type = eNotAValidFrame; | |
| UNWIND_LOG(log, "could not find any symbol for this pc, or a default " | |
| "unwind plan, to continue unwind."); | |
| return; | |
| } | |
| m_sym_ctx_valid = m_current_pc.ResolveFunctionScope(m_sym_ctx); | |
| if (m_sym_ctx.symbol) { | |
| UNWIND_LOG(log, "with pc value of {0:x}, symbol name is '{1}'", pc, | |
| GetSymbolOrFunctionName(m_sym_ctx)); | |
| } else if (m_sym_ctx.function) { | |
| UNWIND_LOG(log, "with pc value of {0:x}, function name is '{1}'", pc, | |
| GetSymbolOrFunctionName(m_sym_ctx)); | |
| } else { | |
| UNWIND_LOG(log, "with pc value of {0:x}, 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 (Address addr = m_sym_ctx.GetFunctionOrSymbolAddress(); | |
| addr != m_current_pc) { | |
| // If our "current" pc isn't the start of a function, decrement the pc | |
| // if we're up the stack. | |
| if (m_behaves_like_zeroth_frame) | |
| decr_pc_and_recompute_addr_range = false; | |
| else | |
| decr_pc_and_recompute_addr_range = true; | |
| } 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 if (m_behaves_like_zeroth_frame) { | |
| 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) { | |
| UNWIND_LOG(log, | |
| "Backing up the pc value of {0:x} by 1 and re-doing symbol " | |
| "lookup; old symbol was {1}", | |
| pc, GetSymbolOrFunctionName(m_sym_ctx)); | |
| 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); | |
| UNWIND_LOG(log, "Symbol is now {0}", GetSymbolOrFunctionName(m_sym_ctx)); | |
| } | |
| // 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 (m_sym_ctx_valid) { | |
| m_start_pc = m_sym_ctx.GetFunctionOrSymbolAddress(); | |
| 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 = std::nullopt; | |
| m_current_offset_backed_up_one = std::nullopt; | |
| } | |
| 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; | |
| } | |
| } | |
| const UnwindPlan::Row *active_row; | |
| RegisterKind row_register_kind = eRegisterKindGeneric; | |
| // If we have LanguageRuntime UnwindPlan for this unwind, use those | |
| // rules to find the caller frame instead of the function's normal | |
| // UnwindPlans. The full unwind plan for this frame will be | |
| // the LanguageRuntime-provided unwind plan, and there will not be a | |
| // fast unwind plan. | |
| if (lang_runtime_plan_sp.get()) { | |
| active_row = | |
| lang_runtime_plan_sp->GetRowForFunctionOffset(m_current_offset); | |
| row_register_kind = lang_runtime_plan_sp->GetRegisterKind(); | |
| if (!ReadFrameAddress(row_register_kind, active_row->GetCFAValue(), | |
| m_cfa)) { | |
| UNWIND_LOG(log, "Cannot set cfa"); | |
| } else { | |
| m_full_unwind_plan_sp = lang_runtime_plan_sp; | |
| if (log) { | |
| StreamString active_row_strm; | |
| active_row->Dump(active_row_strm, lang_runtime_plan_sp.get(), &m_thread, | |
| m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr())); | |
| UNWIND_LOG(log, "async active row: {0}", active_row_strm.GetString()); | |
| } | |
| UNWIND_LOG(log, "m_cfa = {0:x} m_afa = {1:x}", m_cfa, m_afa); | |
| UNWIND_LOG(log, | |
| "initialized async frame current pc is {0:x} cfa is {1:x} afa " | |
| "is {2:x}", | |
| m_current_pc.GetLoadAddress(exe_ctx.GetTargetPtr()), m_cfa, | |
| m_afa); | |
| return; | |
| } | |
| } | |
| // We've set m_frame_type and m_sym_ctx before this call. | |
| m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame(); | |
| // 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 && 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())); | |
| UNWIND_LOG(log, "Using fast unwind plan '{0}'", | |
| m_fast_unwind_plan_sp->GetSourceName()); | |
| UNWIND_LOG(log, "active row: {0}", active_row_strm.GetString()); | |
| } | |
| } else { | |
| m_full_unwind_plan_sp = GetFullUnwindPlanForFrame(); | |
| if (IsUnwindPlanValidForCurrentPC(m_full_unwind_plan_sp)) { | |
| active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset( | |
| m_current_offset_backed_up_one); | |
| row_register_kind = m_full_unwind_plan_sp->GetRegisterKind(); | |
| PropagateTrapHandlerFlagFromUnwindPlan(m_full_unwind_plan_sp); | |
| if (active_row && 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())); | |
| UNWIND_LOG(log, "Using full unwind plan '{0}'", | |
| m_full_unwind_plan_sp->GetSourceName()); | |
| UNWIND_LOG(log, "active row: {0}", active_row_strm.GetString()); | |
| } | |
| } | |
| } | |
| if (!active_row) { | |
| m_frame_type = eNotAValidFrame; | |
| UNWIND_LOG(log, "could not find unwind row for this pc"); | |
| return; | |
| } | |
| if (!ReadFrameAddress(row_register_kind, active_row->GetCFAValue(), m_cfa)) { | |
| UNWIND_LOG(log, "failed to get cfa"); | |
| m_frame_type = eNotAValidFrame; | |
| return; | |
| } | |
| ReadFrameAddress(row_register_kind, active_row->GetAFAValue(), m_afa); | |
| UNWIND_LOG(log, "m_cfa = {0:x} m_afa = {1:x}", m_cfa, m_afa); | |
| if (CheckIfLoopingStack()) { | |
| TryFallbackUnwindPlan(); | |
| if (CheckIfLoopingStack()) { | |
| UNWIND_LOG(log, "same CFA address as next frame, assuming the unwind is " | |
| "looping - stopping"); | |
| m_frame_type = eNotAValidFrame; | |
| return; | |
| } | |
| } | |
| // Give the Architecture a chance to replace the UnwindPlan. | |
| TryAdoptArchitectureUnwindPlan(); | |
| UNWIND_LOG(log, | |
| "initialized frame current pc is {0:x} cfa is {1:x} afa is {2:x}", | |
| m_current_pc.GetLoadAddress(exe_ctx.GetTargetPtr()), m_cfa, m_afa); | |
| } | |
| bool RegisterContextUnwind::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 compliance) 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 unlikely) | |
| RegisterContextUnwind::SharedPtr next_frame = GetNextFrame(); | |
| if (next_frame) { | |
| RegisterContextUnwind::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 RegisterContextUnwind::IsFrameZero() const { return m_frame_number == 0; } | |
| bool RegisterContextUnwind::BehavesLikeZerothFrame() const { | |
| if (m_frame_number == 0) | |
| return true; | |
| if (m_behaves_like_zeroth_frame) | |
| return true; | |
| return false; | |
| } | |
| // 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, std::nullopt if unknown | |
| std::shared_ptr<const UnwindPlan> | |
| RegisterContextUnwind::GetFastUnwindPlanForFrame() { | |
| ModuleSP pc_module_sp(m_current_pc.GetModule()); | |
| if (!m_current_pc.IsValid() || !pc_module_sp || | |
| pc_module_sp->GetObjectFile() == nullptr) | |
| return nullptr; | |
| if (IsFrameZero()) | |
| return nullptr; | |
| FuncUnwindersSP func_unwinders_sp( | |
| pc_module_sp->GetUnwindTable().GetFuncUnwindersContainingAddress( | |
| m_current_pc, m_sym_ctx)); | |
| if (!func_unwinders_sp) | |
| return nullptr; | |
| // If we're in _sigtramp(), unwinding past this frame requires special | |
| // knowledge. | |
| if (m_frame_type == eTrapHandlerFrame || m_frame_type == eDebuggerFrame) | |
| return nullptr; | |
| if (std::shared_ptr<const UnwindPlan> unwind_plan_sp = | |
| func_unwinders_sp->GetUnwindPlanFastUnwind( | |
| *m_thread.CalculateTarget(), m_thread)) { | |
| if (unwind_plan_sp->PlanValidAtAddress(m_current_pc)) { | |
| m_frame_type = eNormalFrame; | |
| return unwind_plan_sp; | |
| } | |
| } | |
| return nullptr; | |
| } | |
| // 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, std::nullopt if unknown | |
| std::shared_ptr<const UnwindPlan> | |
| RegisterContextUnwind::GetFullUnwindPlanForFrame() { | |
| Log *log = GetLog(LLDBLog::Unwind); | |
| std::shared_ptr<const UnwindPlan> 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 = abi->CreateDefaultUnwindPlan(); | |
| assert(((!arch_default_unwind_plan_sp || | |
| arch_default_unwind_plan_sp->GetRowCount() == 0 || | |
| arch_default_unwind_plan_sp->GetRowAtIndex(0) | |
| ->GetUnspecifiedRegistersAreUndefined())) && | |
| "Default UnwindPlan must set " | |
| "UnspecifiedRegistersAreUndefined to true"); | |
| } else { | |
| UNWIND_LOG( | |
| log, "unable to get architectural default UnwindPlan from ABI plugin"); | |
| } | |
| if (IsFrameZero() || GetNextFrame()->m_frame_type == eTrapHandlerFrame || | |
| GetNextFrame()->m_frame_type == eDebuggerFrame) { | |
| m_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)) && | |
| m_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) { | |
| m_frame_type = eNormalFrame; | |
| return abi->CreateFunctionEntryUnwindPlan(); | |
| } | |
| } | |
| } | |
| // 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; | |
| } | |
| // Function outlining is a clang feature where common blocks of instructions | |
| // from separate functions can be put in a separate utility function, and | |
| // the original functions call into the utility function to execute them, | |
| // resulting in fewer bytes used for the code section overall. | |
| // | |
| // The call to the OUTLINED_FUNCTION may not be a normal ABI call (e.g. | |
| // on RISCV it might be called `jal t0, OUTLINED_FUNCTION_<nn>` putting the | |
| // return address in a temporary register instead of $ra). The unwind | |
| // instructions in eh_frame/debug_frame are not correct today for an | |
| // OUTLINED_FUNCTION, even when a normal ABI call is made. | |
| // CFI may be absent or incorrect; instruction emulation may be incorrect | |
| // because it assumes a normal ABI call was made. | |
| if (m_sym_ctx_valid && arch_default_unwind_plan_sp) { | |
| if (IsClangOutlinedFunction(m_sym_ctx)) { | |
| UNWIND_LOG(log, | |
| "Overriding full unwind plan, using architectural default for " | |
| "function {0}", | |
| GetSymbolOrFunctionName(m_sym_ctx)); | |
| 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. | |
| if (DWARFCallFrameInfo *eh_frame = | |
| pc_module_sp->GetUnwindTable().GetEHFrameInfo()) { | |
| if (std::unique_ptr<UnwindPlan> plan_up = | |
| eh_frame->GetUnwindPlan(m_current_pc)) | |
| return plan_up; | |
| } | |
| ArmUnwindInfo *arm_exidx = | |
| pc_module_sp->GetUnwindTable().GetArmUnwindInfo(); | |
| if (arm_exidx) { | |
| auto 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; | |
| } | |
| CallFrameInfo *object_file_unwind = | |
| pc_module_sp->GetUnwindTable().GetObjectFileUnwindInfo(); | |
| if (object_file_unwind) { | |
| if (std::unique_ptr<UnwindPlan> plan_up = | |
| object_file_unwind->GetUnwindPlan(m_current_pc)) | |
| return plan_up; | |
| } | |
| return arch_default_unwind_plan_sp; | |
| } | |
| if (m_frame_type == eTrapHandlerFrame && process) { | |
| m_fast_unwind_plan_sp.reset(); | |
| // On some platforms the unwind information for signal handlers is not | |
| // present or correct. Give the platform plugins a chance to provide | |
| // substitute plan. Otherwise, use eh_frame. | |
| if (m_sym_ctx_valid) { | |
| lldb::PlatformSP platform = process->GetTarget().GetPlatform(); | |
| const ArchSpec arch = process->GetTarget().GetArchitecture(); | |
| if (auto unwind_plan_sp = platform->GetTrapHandlerUnwindPlan( | |
| arch, GetSymbolOrFunctionName(m_sym_ctx))) | |
| return unwind_plan_sp; | |
| } | |
| auto 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) | |
| auto 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_LOG_VERBOSE(log, | |
| "frame uses {0} for full UnwindPlan because the " | |
| "DynamicLoader suggested we prefer it", | |
| unwind_plan_sp->GetSourceName()); | |
| return unwind_plan_sp; | |
| } | |
| } | |
| // Typically the NonCallSite UnwindPlan is the unwind created by inspecting | |
| // the assembly language instructions | |
| if (m_behaves_like_zeroth_frame && process) { | |
| auto 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. | |
| std::shared_ptr<const UnwindPlan> 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; | |
| } | |
| } | |
| UNWIND_LOG_VERBOSE( | |
| log, | |
| "frame uses {0} for full UnwindPlan because this is the non-call " | |
| "site unwind plan and this is a zeroth frame", | |
| unwind_plan_sp->GetSourceName()); | |
| 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) { | |
| UNWIND_LOG_VERBOSE(log, | |
| "frame uses {0} for full UnwindPlan because we are " | |
| "at the first instruction of a function", | |
| unwind_plan_sp->GetSourceName()); | |
| return unwind_plan_sp; | |
| } | |
| } | |
| } | |
| std::shared_ptr<const UnwindPlan> 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); | |
| } | |
| if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp)) { | |
| UNWIND_LOG_VERBOSE(log, | |
| "frame uses {0} for full UnwindPlan because this is the " | |
| "call-site unwind plan", | |
| unwind_plan_sp->GetSourceName()); | |
| 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. | |
| std::shared_ptr<const UnwindPlan> 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)) { | |
| UNWIND_LOG_VERBOSE(log, | |
| "frame uses {0} for full UnwindPlan because we failed " | |
| "to find a call-site unwind plan that would work", | |
| unwind_plan_sp->GetSourceName()); | |
| return unwind_plan_sp; | |
| } | |
| // If nothing else, use the architectural default UnwindPlan and hope that | |
| // does the job. | |
| if (arch_default_unwind_plan_sp) | |
| UNWIND_LOG_VERBOSE(log, | |
| "frame uses {0} for full UnwindPlan because we are " | |
| "falling back to the arch default plan", | |
| arch_default_unwind_plan_sp->GetSourceName()); | |
| else | |
| UNWIND_LOG(log, | |
| "Unable to find any UnwindPlan for full unwind of this frame."); | |
| return arch_default_unwind_plan_sp; | |
| } | |
| void RegisterContextUnwind::InvalidateAllRegisters() { | |
| m_frame_type = eNotAValidFrame; | |
| } | |
| size_t RegisterContextUnwind::GetRegisterCount() { | |
| return m_thread.GetRegisterContext()->GetRegisterCount(); | |
| } | |
| const RegisterInfo *RegisterContextUnwind::GetRegisterInfoAtIndex(size_t reg) { | |
| return m_thread.GetRegisterContext()->GetRegisterInfoAtIndex(reg); | |
| } | |
| size_t RegisterContextUnwind::GetRegisterSetCount() { | |
| return m_thread.GetRegisterContext()->GetRegisterSetCount(); | |
| } | |
| const RegisterSet *RegisterContextUnwind::GetRegisterSet(size_t reg_set) { | |
| return m_thread.GetRegisterContext()->GetRegisterSet(reg_set); | |
| } | |
| uint32_t RegisterContextUnwind::ConvertRegisterKindToRegisterNumber( | |
| lldb::RegisterKind kind, uint32_t num) { | |
| return m_thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber( | |
| kind, num); | |
| } | |
| bool RegisterContextUnwind::ReadRegisterValueFromRegisterLocation( | |
| lldb_private::UnwindLLDB::ConcreteRegisterLocation regloc, | |
| const RegisterInfo *reg_info, RegisterValue &value) { | |
| if (!IsValid()) | |
| return false; | |
| bool success = false; | |
| switch (regloc.type) { | |
| case UnwindLLDB::ConcreteRegisterLocation::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::ConcreteRegisterLocation::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::ConcreteRegisterLocation::eRegisterIsRegisterPlusOffset: { | |
| auto regnum = regloc.location.reg_plus_offset.register_number; | |
| const RegisterInfo *other_reg_info = | |
| GetRegisterInfoAtIndex(regloc.location.reg_plus_offset.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); | |
| } | |
| if (success) { | |
| Log *log = GetLog(LLDBLog::Unwind); | |
| UNWIND_LOG(log, "read ({0})'s location", regnum); | |
| value = value.GetAsUInt64(~0ull, &success) + | |
| regloc.location.reg_plus_offset.offset; | |
| UNWIND_LOG(log, "success {0}", success ? "yes" : "no"); | |
| } | |
| } break; | |
| case UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred: | |
| success = | |
| value.SetUInt(regloc.location.inferred_value, reg_info->byte_size); | |
| break; | |
| case UnwindLLDB::ConcreteRegisterLocation::eRegisterNotSaved: | |
| break; | |
| case UnwindLLDB::ConcreteRegisterLocation::eRegisterSavedAtHostMemoryLocation: | |
| llvm_unreachable("FIXME debugger inferior function call unwind"); | |
| case UnwindLLDB::ConcreteRegisterLocation::eRegisterSavedAtMemoryLocation: { | |
| Status error(ReadRegisterValueFromMemory( | |
| reg_info, regloc.location.target_memory_location, reg_info->byte_size, | |
| value)); | |
| success = error.Success(); | |
| } break; | |
| default: | |
| llvm_unreachable("Unknown ConcreteRegisterLocation type."); | |
| } | |
| return success; | |
| } | |
| bool RegisterContextUnwind::WriteRegisterValueToRegisterLocation( | |
| lldb_private::UnwindLLDB::ConcreteRegisterLocation regloc, | |
| const RegisterInfo *reg_info, const RegisterValue &value) { | |
| if (!IsValid()) | |
| return false; | |
| bool success = false; | |
| switch (regloc.type) { | |
| case UnwindLLDB::ConcreteRegisterLocation::eRegisterInLiveRegisterContext: { | |
| const RegisterInfo *other_reg_info = | |
| GetRegisterInfoAtIndex(regloc.location.register_number); | |
| success = | |
| m_thread.GetRegisterContext()->WriteRegister(other_reg_info, value); | |
| } break; | |
| case UnwindLLDB::ConcreteRegisterLocation::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::ConcreteRegisterLocation::eRegisterIsRegisterPlusOffset: | |
| case UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred: | |
| case UnwindLLDB::ConcreteRegisterLocation::eRegisterNotSaved: | |
| break; | |
| case UnwindLLDB::ConcreteRegisterLocation::eRegisterSavedAtHostMemoryLocation: | |
| llvm_unreachable("FIXME debugger inferior function call unwind"); | |
| case UnwindLLDB::ConcreteRegisterLocation::eRegisterSavedAtMemoryLocation: { | |
| Status error(WriteRegisterValueToMemory( | |
| reg_info, regloc.location.target_memory_location, reg_info->byte_size, | |
| value)); | |
| success = error.Success(); | |
| } break; | |
| default: | |
| llvm_unreachable("Unknown ConcreteRegisterLocation type."); | |
| } | |
| return success; | |
| } | |
| bool RegisterContextUnwind::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 difference between "the unwind plan | |
| // below this frame failed" versus "we successfully completed the stack walk" | |
| // so this method helps to disambiguate that. | |
| bool RegisterContextUnwind::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 RegisterContextUnwind::IsSkipFrame() const { | |
| return m_frame_type == eSkipFrame; | |
| } | |
| bool RegisterContextUnwind::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<std::string> &trap_handler_names( | |
| platform_sp->GetTrapHandlerSymbolNames()); | |
| for (const std::string &name : trap_handler_names) { | |
| if ((m_sym_ctx.function && | |
| m_sym_ctx.function->GetName().GetStringRef() == name) || | |
| (m_sym_ctx.symbol && | |
| m_sym_ctx.symbol->GetName().GetStringRef() == name)) { | |
| return true; | |
| } | |
| } | |
| } | |
| const std::vector<std::string> &user_specified_trap_handler_names = | |
| m_parent_unwind.GetUserSpecifiedTrapHandlerFunctionNames(); | |
| for (const std::string &name : user_specified_trap_handler_names) { | |
| if ((m_sym_ctx.function && | |
| m_sym_ctx.function->GetName().GetStringRef() == name) || | |
| (m_sym_ctx.symbol && | |
| m_sym_ctx.symbol->GetName().GetStringRef() == name)) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| // Search this stack frame's UnwindPlans for the AbstractRegisterLocation | |
| // for this register. | |
| // | |
| // \param[in] lldb_regnum | |
| // The register number (in the eRegisterKindLLDB register numbering) | |
| // we are searching for. | |
| // | |
| // \param[out] kind | |
| // Set to the RegisterKind of the UnwindPlan which is the basis for | |
| // the returned AbstractRegisterLocation; if the location is in terms | |
| // of another register number, this Kind is needed to interpret it | |
| // correctly. | |
| // | |
| // \return | |
| // An empty optional indicaTes that there was an error in processing | |
| // the request. | |
| // | |
| // If there is no unwind rule for a volatile (caller-preserved) register, | |
| // the returned AbstractRegisterLocation will be IsUndefined, | |
| // indicating that we should stop searching. | |
| // | |
| // If there is no unwind rule for a non-volatile (callee-preserved) | |
| // register, the returned AbstractRegisterLocation will be IsSame. | |
| // In frame 0, IsSame means get the value from the live register context. | |
| // Else it means to continue descending down the stack to more-live frames | |
| // looking for a location/value. | |
| // | |
| // If an AbstractRegisterLocation is found in an UnwindPlan, that will | |
| // be returned, with no consideration of the current ABI rules for | |
| // registers. Functions using an alternate ABI calling convention | |
| // will work as long as the UnwindPlans are exhaustive about what | |
| // registers are volatile/non-volatile. | |
| std::optional<UnwindPlan::Row::AbstractRegisterLocation> | |
| RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum, | |
| lldb::RegisterKind &kind) { | |
| RegisterNumber regnum(m_thread, eRegisterKindLLDB, lldb_regnum); | |
| Log *log = GetLog(LLDBLog::Unwind); | |
| kind = eRegisterKindLLDB; | |
| UnwindPlan::Row::AbstractRegisterLocation unwindplan_regloc; | |
| // First, try to find a register location via the FastUnwindPlan | |
| if (m_fast_unwind_plan_sp) { | |
| const UnwindPlan::Row *active_row = | |
| m_fast_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset); | |
| if (regnum.GetAsKind(kind) == LLDB_INVALID_REGNUM) { | |
| UNWIND_LOG(log, | |
| "could not convert lldb regnum {0} ({1}) into {2} " | |
| "RegisterKind reg numbering scheme", | |
| regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), kind); | |
| return {}; | |
| } | |
| kind = m_fast_unwind_plan_sp->GetRegisterKind(); | |
| // The Fast UnwindPlan typically only provides fp & pc as we move up | |
| // the stack, without requiring additional parsing or memory reads. | |
| // It may mark all other registers as IsUndefined() because, indicating | |
| // that it doesn't know if they were spilled to stack or not. | |
| // If this case, for an IsUndefined register, we should continue on | |
| // to the Full UnwindPlan which may have more accurate information | |
| // about register locations of all registers. | |
| if (active_row && | |
| active_row->GetRegisterInfo(regnum.GetAsKind(kind), | |
| unwindplan_regloc) && | |
| !unwindplan_regloc.IsUndefined()) { | |
| UNWIND_LOG( | |
| log, | |
| "supplying caller's saved {0} ({1})'s location using FastUnwindPlan", | |
| regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); | |
| return unwindplan_regloc; | |
| } | |
| } | |
| // Second, try to find a register location via the FullUnwindPlan. | |
| bool got_new_full_unwindplan = false; | |
| if (!m_full_unwind_plan_sp) { | |
| m_full_unwind_plan_sp = GetFullUnwindPlanForFrame(); | |
| got_new_full_unwindplan = true; | |
| } | |
| if (m_full_unwind_plan_sp) { | |
| RegisterNumber pc_regnum(m_thread, eRegisterKindGeneric, | |
| LLDB_REGNUM_GENERIC_PC); | |
| const UnwindPlan::Row *active_row = | |
| m_full_unwind_plan_sp->GetRowForFunctionOffset( | |
| m_current_offset_backed_up_one); | |
| kind = m_full_unwind_plan_sp->GetRegisterKind(); | |
| if (got_new_full_unwindplan && active_row && log) { | |
| StreamString active_row_strm; | |
| ExecutionContext exe_ctx(m_thread.shared_from_this()); | |
| active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread, | |
| m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr())); | |
| UNWIND_LOG(log, "Using full unwind plan '{0}'", | |
| m_full_unwind_plan_sp->GetSourceName()); | |
| UNWIND_LOG(log, "active row: {0}", active_row_strm.GetString()); | |
| } | |
| if (regnum.GetAsKind(kind) == LLDB_INVALID_REGNUM) { | |
| if (kind == eRegisterKindGeneric) | |
| UNWIND_LOG(log, | |
| "could not convert lldb regnum {0} ({1}) into " | |
| "eRegisterKindGeneric reg numbering scheme", | |
| regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); | |
| else | |
| UNWIND_LOG(log, | |
| "could not convert lldb regnum {0} ({1}) into {2} " | |
| "RegisterKind reg numbering scheme", | |
| regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), kind); | |
| if (active_row && active_row->GetUnspecifiedRegistersAreUndefined()) { | |
| UNWIND_LOG( | |
| log, | |
| "marking register {0} ({1}) as Undefined (volatile) in this " | |
| "stack frame because this row is UnspecifiedRegistersAreUndefined.", | |
| regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); | |
| unwindplan_regloc.SetUndefined(); | |
| return unwindplan_regloc; | |
| } | |
| return {}; | |
| } | |
| if (regnum.IsValid() && active_row && | |
| active_row->GetRegisterInfo(regnum.GetAsKind(kind), | |
| unwindplan_regloc)) { | |
| UNWIND_LOG( | |
| log, | |
| "supplying caller's saved {0} ({1})'s location using {2} UnwindPlan", | |
| regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), | |
| m_full_unwind_plan_sp->GetSourceName()); | |
| return unwindplan_regloc; | |
| } | |
| // When asking for the caller's pc, and did not find a register | |
| // location for PC above in the UnwindPlan. Check if we have a | |
| // Return Address register on this target. | |
| // | |
| // On a Return Address Register architecture like arm/mips/riscv, | |
| // the caller's pc is in the RA register, and will be spilled to | |
| // stack before any other function is called. If no function | |
| // has been called yet, the return address may still be in the | |
| // live RA reg. | |
| // | |
| // There's a lot of variety of what we might see in an UnwindPlan. | |
| // We may have | |
| // ra=IsSame {unncessary} | |
| // ra=StackAddr {caller's return addr spilled to stack} | |
| // or no reg location for pc or ra at all, in a frameless function - | |
| // the caller's return address is in live ra reg. | |
| // | |
| // If a function has been interrupted in a non-call way -- | |
| // async signal/sigtramp, or a hardware exception / interrupt / fault -- | |
| // then the "pc" and "ra" are two distinct values, and must be | |
| // handled separately. The "pc" is the pc value at the point | |
| // the function was interrupted. The "ra" is the return address | |
| // register value at that point. | |
| // The UnwindPlan for the sigtramp/trap handler will normally have | |
| // register loations for both pc and lr, and so we'll have already | |
| // fetched them above. | |
| if (pc_regnum.IsValid() && pc_regnum == regnum) { | |
| uint32_t return_address_regnum = LLDB_INVALID_REGNUM; | |
| // Get the return address register number from the UnwindPlan | |
| // or the register set definition. | |
| if (m_full_unwind_plan_sp->GetReturnAddressRegister() != | |
| LLDB_INVALID_REGNUM) { | |
| return_address_regnum = | |
| m_full_unwind_plan_sp->GetReturnAddressRegister(); | |
| } else { | |
| RegisterNumber arch_default_ra_regnum(m_thread, eRegisterKindGeneric, | |
| LLDB_REGNUM_GENERIC_RA); | |
| return_address_regnum = arch_default_ra_regnum.GetAsKind(kind); | |
| } | |
| // This system is using a return address register. | |
| if (return_address_regnum != LLDB_INVALID_REGNUM) { | |
| RegisterNumber return_address_reg; | |
| return_address_reg.init(m_thread, | |
| m_full_unwind_plan_sp->GetRegisterKind(), | |
| return_address_regnum); | |
| UNWIND_LOG(log, | |
| "requested caller's saved PC but this UnwindPlan uses a RA " | |
| "reg; getting {0} ({1}) instead", | |
| return_address_reg.GetName(), | |
| return_address_reg.GetAsKind(eRegisterKindLLDB)); | |
| // Do we have a location for the ra register? | |
| if (active_row && | |
| active_row->GetRegisterInfo(return_address_reg.GetAsKind(kind), | |
| unwindplan_regloc)) { | |
| UNWIND_LOG(log, | |
| "supplying caller's saved {0} ({1})'s location using {2} " | |
| "UnwindPlan", | |
| return_address_reg.GetName(), | |
| return_address_reg.GetAsKind(eRegisterKindLLDB), | |
| m_full_unwind_plan_sp->GetSourceName()); | |
| // If we have "ra=IsSame", rewrite to "ra=InRegister(ra)" because the | |
| // calling function thinks it is fetching "pc" and if we return an | |
| // IsSame register location, it will try to read pc. | |
| if (unwindplan_regloc.IsSame()) | |
| unwindplan_regloc.SetInRegister(return_address_reg.GetAsKind(kind)); | |
| return unwindplan_regloc; | |
| } else { | |
| // No unwind rule for the return address reg on frame 0, or an | |
| // interrupted function, means that the caller's address is still in | |
| // RA reg (0th frame) or the trap handler below this one (sigtramp | |
| // etc) has a save location for the RA reg. | |
| if (BehavesLikeZerothFrame()) { | |
| unwindplan_regloc.SetInRegister(return_address_reg.GetAsKind(kind)); | |
| return unwindplan_regloc; | |
| } | |
| } | |
| } | |
| } | |
| if (active_row && active_row->GetUnspecifiedRegistersAreUndefined()) { | |
| UNWIND_LOG( | |
| log, | |
| "marking register {0} ({1}) as Undefined (volatile) in this " | |
| "stack frame because this row is UnspecifiedRegistersAreUndefined.", | |
| regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); | |
| unwindplan_regloc.SetUndefined(); | |
| return unwindplan_regloc; | |
| } | |
| } | |
| ExecutionContext exe_ctx(m_thread.shared_from_this()); | |
| Process *process = exe_ctx.GetProcessPtr(); | |
| // Third, try finding a register location via the ABI | |
| // FallbackRegisterLocation. | |
| // | |
| // 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 willset 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)) { | |
| if (!unwindplan_regloc.IsUndefined()) | |
| UNWIND_LOG( | |
| log, | |
| "supplying caller's saved {0} ({1})'s location using ABI default", | |
| regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); | |
| // ABI defined volatile registers with no register location | |
| // will be returned as IsUndefined, stopping the search down | |
| // the stack. | |
| return unwindplan_regloc; | |
| } | |
| } | |
| // We have no AbstractRegisterLocation, and the ABI says this is a | |
| // non-volatile / callee-preserved register. Continue down the stack | |
| // or to frame 0 & the live RegisterContext. | |
| std::string unwindplan_name; | |
| if (m_full_unwind_plan_sp) { | |
| unwindplan_name += "via '"; | |
| unwindplan_name += m_full_unwind_plan_sp->GetSourceName(); | |
| unwindplan_name += "'"; | |
| } | |
| UNWIND_LOG(log, "no save location for {0} ({1}) {2}", regnum.GetName(), | |
| regnum.GetAsKind(eRegisterKindLLDB), unwindplan_name); | |
| unwindplan_regloc.SetSame(); | |
| return unwindplan_regloc; | |
| } | |
| // Answer the question: Where did THIS frame save the CALLER frame ("previous" | |
| // frame)'s register value? | |
| enum UnwindLLDB::RegisterSearchResult | |
| RegisterContextUnwind::SavedLocationForRegister( | |
| uint32_t lldb_regnum, | |
| lldb_private::UnwindLLDB::ConcreteRegisterLocation ®loc) { | |
| RegisterNumber regnum(m_thread, eRegisterKindLLDB, lldb_regnum); | |
| Log *log = GetLog(LLDBLog::Unwind); | |
| // Have we already found this register location? | |
| if (!m_registers.empty()) { | |
| auto iterator = m_registers.find(regnum.GetAsKind(eRegisterKindLLDB)); | |
| if (iterator != m_registers.end()) { | |
| regloc = iterator->second; | |
| UNWIND_LOG(log, "supplying caller's saved {0} ({1})'s location, cached", | |
| regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); | |
| return UnwindLLDB::RegisterSearchResult::eRegisterFound; | |
| } | |
| } | |
| RegisterKind abs_regkind; | |
| std::optional<UnwindPlan::Row::AbstractRegisterLocation> abs_regloc = | |
| GetAbstractRegisterLocation(lldb_regnum, abs_regkind); | |
| if (!abs_regloc) | |
| return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; | |
| if (abs_regloc->IsUndefined()) { | |
| UNWIND_LOG( | |
| log, "did not supply reg location for {0} ({1}) because it is volatile", | |
| regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); | |
| return UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile; | |
| } | |
| ExecutionContext exe_ctx(m_thread.shared_from_this()); | |
| Process *process = exe_ctx.GetProcessPtr(); | |
| // abs_regloc has valid contents about where to retrieve the register | |
| if (abs_regloc->IsUnspecified()) { | |
| lldb_private::UnwindLLDB::ConcreteRegisterLocation new_regloc = {}; | |
| new_regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterNotSaved; | |
| m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc; | |
| UNWIND_LOG(log, | |
| "save location for {0} ({1}) is unspecified, continue searching", | |
| regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); | |
| return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; | |
| } | |
| if (abs_regloc->IsSame()) { | |
| if (IsFrameZero()) { | |
| regloc.type = | |
| UnwindLLDB::ConcreteRegisterLocation::eRegisterInLiveRegisterContext; | |
| regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); | |
| m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; | |
| UNWIND_LOG(log, | |
| "supplying caller's register {0} ({1}) from the live " | |
| "RegisterContext at frame 0", | |
| regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); | |
| return UnwindLLDB::RegisterSearchResult::eRegisterFound; | |
| } | |
| // PC/RA reg don't follow the usual "callee-saved aka non-volatile" versus | |
| // "caller saved aka volatile" system. A stack frame can provide its caller | |
| // return address, but if we don't find a rule for pc/RA mid-stack, we | |
| // never want to iterate further down the stack looking for it. | |
| // Defensively prevent iterating down the stack for these two. | |
| if (!BehavesLikeZerothFrame() && | |
| (regnum.GetAsKind(eRegisterKindGeneric) == LLDB_REGNUM_GENERIC_PC || | |
| regnum.GetAsKind(eRegisterKindGeneric) == LLDB_REGNUM_GENERIC_RA)) { | |
| UNWIND_LOG(log, | |
| "register {0} ({1}) is marked as 'IsSame' - it is a pc or " | |
| "return address reg on a frame which does not have all " | |
| "registers available -- treat as if we have no information", | |
| regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); | |
| return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; | |
| } | |
| regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterInRegister; | |
| regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB); | |
| m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; | |
| UNWIND_LOG(log, | |
| "supplying caller's register {0} ({1}) value is unmodified in " | |
| "this frame", | |
| regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); | |
| return UnwindLLDB::RegisterSearchResult::eRegisterFound; | |
| } | |
| if (abs_regloc->IsCFAPlusOffset()) { | |
| int offset = abs_regloc->GetOffset(); | |
| regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred; | |
| regloc.location.inferred_value = m_cfa + offset; | |
| m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; | |
| UNWIND_LOG(log, | |
| "supplying caller's register {0} ({1}), value is CFA plus " | |
| "offset {2} [value is {3:x}]", | |
| regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), offset, | |
| regloc.location.inferred_value); | |
| return UnwindLLDB::RegisterSearchResult::eRegisterFound; | |
| } | |
| if (abs_regloc->IsAtCFAPlusOffset()) { | |
| int offset = abs_regloc->GetOffset(); | |
| regloc.type = | |
| UnwindLLDB::ConcreteRegisterLocation::eRegisterSavedAtMemoryLocation; | |
| regloc.location.target_memory_location = m_cfa + offset; | |
| m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; | |
| UNWIND_LOG(log, | |
| "supplying caller's register {0} ({1}) from the stack, saved at " | |
| "CFA plus offset {2} [saved at {3:x}]", | |
| regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), offset, | |
| regloc.location.target_memory_location); | |
| return UnwindLLDB::RegisterSearchResult::eRegisterFound; | |
| } | |
| if (abs_regloc->IsAFAPlusOffset()) { | |
| if (m_afa == LLDB_INVALID_ADDRESS) | |
| return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; | |
| int offset = abs_regloc->GetOffset(); | |
| regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred; | |
| regloc.location.inferred_value = m_afa + offset; | |
| m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; | |
| UNWIND_LOG(log, | |
| "supplying caller's register {0} ({1}), value is AFA plus " | |
| "offset {2} [value is {3:x}]", | |
| regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), offset, | |
| regloc.location.inferred_value); | |
| return UnwindLLDB::RegisterSearchResult::eRegisterFound; | |
| } | |
| if (abs_regloc->IsAtAFAPlusOffset()) { | |
| if (m_afa == LLDB_INVALID_ADDRESS) | |
| return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; | |
| int offset = abs_regloc->GetOffset(); | |
| regloc.type = | |
| UnwindLLDB::ConcreteRegisterLocation::eRegisterSavedAtMemoryLocation; | |
| regloc.location.target_memory_location = m_afa + offset; | |
| m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; | |
| UNWIND_LOG(log, | |
| "supplying caller's register {0} ({1}) from the stack, saved at " | |
| "AFA plus offset {2} [saved at {3:x}]", | |
| regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), offset, | |
| regloc.location.target_memory_location); | |
| return UnwindLLDB::RegisterSearchResult::eRegisterFound; | |
| } | |
| if (abs_regloc->IsInOtherRegister()) { | |
| RegisterNumber row_regnum(m_thread, abs_regkind, | |
| abs_regloc->GetRegisterNumber()); | |
| if (row_regnum.GetAsKind(eRegisterKindLLDB) == LLDB_INVALID_REGNUM) { | |
| UNWIND_LOG(log, | |
| "could not supply caller's {0} ({1}) location - was saved in " | |
| "another reg but couldn't convert that regnum", | |
| regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); | |
| return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; | |
| } | |
| regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterInRegister; | |
| regloc.location.register_number = row_regnum.GetAsKind(eRegisterKindLLDB); | |
| m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; | |
| UNWIND_LOG( | |
| log, | |
| "supplying caller's register {0} ({1}), saved in register {2} ({3})", | |
| regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), | |
| row_regnum.GetName(), row_regnum.GetAsKind(eRegisterKindLLDB)); | |
| return UnwindLLDB::RegisterSearchResult::eRegisterFound; | |
| } | |
| if (abs_regloc->IsDWARFExpression() || abs_regloc->IsAtDWARFExpression()) { | |
| DataExtractor dwarfdata(abs_regloc->GetDWARFExpressionBytes(), | |
| abs_regloc->GetDWARFExpressionLength(), | |
| process->GetByteOrder(), | |
| process->GetAddressByteSize()); | |
| ModuleSP opcode_ctx; | |
| DWARFExpressionList dwarfexpr(opcode_ctx, dwarfdata, nullptr); | |
| dwarfexpr.GetMutableExpressionAtAddress()->SetRegisterKind(abs_regkind); | |
| Value cfa_val = Scalar(m_cfa); | |
| cfa_val.SetValueType(Value::ValueType::LoadAddress); | |
| llvm::Expected<Value> result = | |
| dwarfexpr.Evaluate(&exe_ctx, this, 0, &cfa_val, nullptr); | |
| if (!result) { | |
| LLDB_LOG_ERROR(log, result.takeError(), | |
| "DWARF expression failed to evaluate: {0}"); | |
| } else { | |
| addr_t val; | |
| val = result->GetScalar().ULongLong(); | |
| if (abs_regloc->IsDWARFExpression()) { | |
| regloc.type = | |
| UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred; | |
| regloc.location.inferred_value = val; | |
| m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; | |
| UNWIND_LOG(log, | |
| "supplying caller's register {0} ({1}) via DWARF expression " | |
| "(IsDWARFExpression)", | |
| regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); | |
| return UnwindLLDB::RegisterSearchResult::eRegisterFound; | |
| } else { | |
| regloc.type = UnwindLLDB::ConcreteRegisterLocation:: | |
| eRegisterSavedAtMemoryLocation; | |
| regloc.location.target_memory_location = val; | |
| m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; | |
| UNWIND_LOG(log, | |
| "supplying caller's register {0} ({1}) via DWARF expression " | |
| "(IsAtDWARFExpression)", | |
| regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); | |
| return UnwindLLDB::RegisterSearchResult::eRegisterFound; | |
| } | |
| } | |
| UNWIND_LOG(log, | |
| "tried to use IsDWARFExpression or IsAtDWARFExpression for {0} " | |
| "({1}) but failed", | |
| regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); | |
| return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; | |
| } | |
| if (abs_regloc->IsConstant()) { | |
| regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred; | |
| regloc.location.inferred_value = abs_regloc->GetConstant(); | |
| m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc; | |
| UNWIND_LOG(log, "supplying caller's register {0} ({1}) via constant value", | |
| regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); | |
| return UnwindLLDB::RegisterSearchResult::eRegisterFound; | |
| } | |
| UNWIND_LOG(log, "no save location for {0} ({1}) in this stack frame", | |
| regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); | |
| // FIXME UnwindPlan::Row types atDWARFExpression and isDWARFExpression are | |
| // unsupported. | |
| return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; | |
| } | |
| UnwindPlanSP RegisterContextUnwind::TryAdoptArchitectureUnwindPlan() { | |
| if (!m_full_unwind_plan_sp) | |
| return {}; | |
| ProcessSP process_sp = m_thread.GetProcess(); | |
| if (!process_sp) | |
| return {}; | |
| UnwindPlanSP arch_override_plan_sp; | |
| if (Architecture *arch = process_sp->GetTarget().GetArchitecturePlugin()) | |
| arch_override_plan_sp = | |
| arch->GetArchitectureUnwindPlan(m_thread, this, m_full_unwind_plan_sp); | |
| if (arch_override_plan_sp) { | |
| m_full_unwind_plan_sp = arch_override_plan_sp; | |
| PropagateTrapHandlerFlagFromUnwindPlan(m_full_unwind_plan_sp); | |
| m_registers.clear(); | |
| if (Log *log = GetLog(LLDBLog::Unwind)) { | |
| UNWIND_LOG( | |
| log, "Replacing Full Unwindplan with Architecture UnwindPlan, '{0}'", | |
| m_full_unwind_plan_sp->GetSourceName()); | |
| const UnwindPlan::Row *active_row = | |
| m_full_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset); | |
| if (active_row) { | |
| StreamString active_row_strm; | |
| active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), | |
| &m_thread, | |
| m_start_pc.GetLoadAddress(&process_sp->GetTarget())); | |
| UNWIND_LOG(log, "{0}", active_row_strm.GetString()); | |
| } | |
| } | |
| } | |
| return {}; | |
| } | |
| // 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 RegisterContextUnwind::TryFallbackUnwindPlan() { | |
| if (m_fallback_unwind_plan_sp == nullptr) | |
| return false; | |
| if (m_full_unwind_plan_sp == 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::ConcreteRegisterLocation 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(); | |
| if (ProcessSP process_sp = m_thread.GetProcess()) { | |
| if (ABISP abi_sp = process_sp->GetABI()) | |
| old_caller_pc_value = abi_sp->FixCodeAddress(old_caller_pc_value); | |
| } | |
| } | |
| } | |
| } | |
| // 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 == 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'. | |
| std::shared_ptr<const UnwindPlan> 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; | |
| const UnwindPlan::Row *active_row = | |
| m_fallback_unwind_plan_sp->GetRowForFunctionOffset( | |
| m_current_offset_backed_up_one); | |
| Log *log = GetLog(LLDBLog::Unwind); | |
| if (active_row && | |
| active_row->GetCFAValue().GetValueType() != | |
| UnwindPlan::Row::FAValue::unspecified) { | |
| addr_t new_cfa; | |
| ProcessSP process_sp = m_thread.GetProcess(); | |
| ABISP abi_sp = process_sp ? process_sp->GetABI() : nullptr; | |
| if (!ReadFrameAddress(m_fallback_unwind_plan_sp->GetRegisterKind(), | |
| active_row->GetCFAValue(), new_cfa) || | |
| !CallFrameAddressIsValid(abi_sp, new_cfa)) { | |
| UNWIND_LOG(log, "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 (process_sp) | |
| new_caller_pc_value = | |
| process_sp->FixCodeAddress(new_caller_pc_value); | |
| } | |
| } | |
| } | |
| if (new_caller_pc_value == LLDB_INVALID_ADDRESS) { | |
| UNWIND_LOG(log, "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) { | |
| UNWIND_LOG(log, "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; | |
| } | |
| UNWIND_LOG(log, | |
| "trying to unwind from this function with the UnwindPlan '{0}' " | |
| "because UnwindPlan '{1}' failed.", | |
| m_fallback_unwind_plan_sp->GetSourceName(), | |
| original_full_unwind_plan_sp->GetSourceName()); | |
| // 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 RegisterContextUnwind::ForceSwitchToFallbackUnwindPlan() { | |
| if (m_fallback_unwind_plan_sp == nullptr) | |
| return false; | |
| if (m_full_unwind_plan_sp == 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; | |
| } | |
| const UnwindPlan::Row *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; | |
| ProcessSP process_sp = m_thread.GetProcess(); | |
| ABISP abi_sp = process_sp ? process_sp->GetABI() : nullptr; | |
| if (!ReadFrameAddress(m_fallback_unwind_plan_sp->GetRegisterKind(), | |
| active_row->GetCFAValue(), new_cfa) || | |
| !CallFrameAddressIsValid(abi_sp, new_cfa)) { | |
| UNWIND_LOG(GetLog(LLDBLog::Unwind), | |
| "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); | |
| UNWIND_LOG(GetLog(LLDBLog::Unwind), | |
| "switched unconditionally to the fallback unwindplan {0}", | |
| m_full_unwind_plan_sp->GetSourceName()); | |
| return true; | |
| } | |
| return false; | |
| } | |
| void RegisterContextUnwind::PropagateTrapHandlerFlagFromUnwindPlan( | |
| std::shared_ptr<const UnwindPlan> 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; | |
| Log *log = GetLog(LLDBLog::Unwind); | |
| UNWIND_LOG(log, "This frame is marked as a trap handler via its UnwindPlan"); | |
| 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. | |
| UNWIND_LOG(log, | |
| "Resetting current offset and re-doing symbol lookup; old " | |
| "symbol was {0}", | |
| GetSymbolOrFunctionName(m_sym_ctx)); | |
| m_current_offset_backed_up_one = m_current_offset; | |
| m_sym_ctx_valid = m_current_pc.ResolveFunctionScope(m_sym_ctx); | |
| UNWIND_LOG(log, "Symbol is now {0}", GetSymbolOrFunctionName(m_sym_ctx)); | |
| ExecutionContext exe_ctx(m_thread.shared_from_this()); | |
| Process *process = exe_ctx.GetProcessPtr(); | |
| Target *target = &process->GetTarget(); | |
| if (m_sym_ctx_valid) { | |
| m_start_pc = m_sym_ctx.GetFunctionOrSymbolAddress(); | |
| m_current_offset = m_current_pc.GetLoadAddress(target) - | |
| m_start_pc.GetLoadAddress(target); | |
| } | |
| } | |
| } | |
| bool RegisterContextUnwind::ReadFrameAddress( | |
| lldb::RegisterKind row_register_kind, const UnwindPlan::Row::FAValue &fa, | |
| addr_t &address) { | |
| RegisterValue reg_value; | |
| address = LLDB_INVALID_ADDRESS; | |
| addr_t cfa_reg_contents; | |
| ABISP abi_sp = m_thread.GetProcess()->GetABI(); | |
| Log *log = GetLog(LLDBLog::Unwind); | |
| switch (fa.GetValueType()) { | |
| case UnwindPlan::Row::FAValue::isRegisterDereferenced: { | |
| UNWIND_LOG(log, "CFA value via dereferencing reg"); | |
| RegisterNumber regnum_to_deref(m_thread, row_register_kind, | |
| fa.GetRegisterNumber()); | |
| addr_t reg_to_deref_contents; | |
| if (ReadGPRValue(regnum_to_deref, reg_to_deref_contents)) { | |
| const RegisterInfo *reg_info = | |
| GetRegisterInfoAtIndex(regnum_to_deref.GetAsKind(eRegisterKindLLDB)); | |
| RegisterValue reg_value; | |
| if (reg_info) { | |
| Status error = ReadRegisterValueFromMemory( | |
| reg_info, reg_to_deref_contents, reg_info->byte_size, reg_value); | |
| if (error.Success()) { | |
| address = reg_value.GetAsUInt64(); | |
| UNWIND_LOG(log, | |
| "CFA value via dereferencing reg {0} ({1}): reg has val " | |
| "{2:x}, CFA value is {3:x}", | |
| regnum_to_deref.GetName(), | |
| regnum_to_deref.GetAsKind(eRegisterKindLLDB), | |
| reg_to_deref_contents, address); | |
| return true; | |
| } else { | |
| UNWIND_LOG( | |
| log, | |
| "Tried to deref reg {0} ({1}) [{2:x}] but memory read failed.", | |
| regnum_to_deref.GetName(), | |
| regnum_to_deref.GetAsKind(eRegisterKindLLDB), | |
| reg_to_deref_contents); | |
| } | |
| } | |
| } | |
| break; | |
| } | |
| case UnwindPlan::Row::FAValue::isRegisterPlusOffset: { | |
| UNWIND_LOG(log, "CFA value via register plus offset"); | |
| RegisterNumber cfa_reg(m_thread, row_register_kind, | |
| fa.GetRegisterNumber()); | |
| if (ReadGPRValue(cfa_reg, cfa_reg_contents)) { | |
| if (!CallFrameAddressIsValid(abi_sp, cfa_reg_contents)) { | |
| UNWIND_LOG( | |
| log, | |
| "Got an invalid CFA register value - reg {0} ({1}), value {2:x}", | |
| cfa_reg.GetName(), cfa_reg.GetAsKind(eRegisterKindLLDB), | |
| cfa_reg_contents); | |
| return false; | |
| } | |
| address = cfa_reg_contents + fa.GetOffset(); | |
| UNWIND_LOG( | |
| log, | |
| "CFA is {0:x}: Register {1} ({2}) contents are {3:x}, offset is {4}", | |
| address, cfa_reg.GetName(), cfa_reg.GetAsKind(eRegisterKindLLDB), | |
| cfa_reg_contents, fa.GetOffset()); | |
| return true; | |
| } | |
| UNWIND_LOG(log, "unable to read CFA register {0} ({1})", cfa_reg.GetName(), | |
| cfa_reg.GetAsKind(eRegisterKindLLDB)); | |
| break; | |
| } | |
| case UnwindPlan::Row::FAValue::isDWARFExpression: { | |
| UNWIND_LOG(log, "CFA value via DWARF expression"); | |
| 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; | |
| DWARFExpressionList dwarfexpr(opcode_ctx, dwarfdata, nullptr); | |
| dwarfexpr.GetMutableExpressionAtAddress()->SetRegisterKind( | |
| row_register_kind); | |
| llvm::Expected<Value> result = | |
| dwarfexpr.Evaluate(&exe_ctx, this, 0, nullptr, nullptr); | |
| if (result) { | |
| address = result->GetScalar().ULongLong(); | |
| UNWIND_LOG(log, "CFA value set by DWARF expression is {0:x}", address); | |
| return true; | |
| } | |
| LLDB_LOG_ERROR(log, result.takeError(), | |
| "Failed to set CFA value via DWARF expression: {0}"); | |
| break; | |
| } | |
| case UnwindPlan::Row::FAValue::isRaSearch: { | |
| UNWIND_LOG(log, "CFA value via heuristic search"); | |
| 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) { | |
| lldb::addr_t candidate_addr = | |
| return_address_hint + i * process.GetAddressByteSize(); | |
| llvm::Expected<lldb::addr_t> candidate = | |
| process.ReadPointerFromMemory(candidate_addr); | |
| if (!candidate) { | |
| LLDB_LOG_ERROR(log, candidate.takeError(), | |
| "Cannot read memory at {1:x}: {0}", candidate_addr); | |
| return false; | |
| } | |
| Address addr; | |
| uint32_t permissions; | |
| if (process.GetLoadAddressPermissions(*candidate, permissions) && | |
| permissions & lldb::ePermissionsExecutable) { | |
| address = candidate_addr; | |
| UNWIND_LOG(log, "Heuristically found CFA: {0:x}", address); | |
| return true; | |
| } | |
| } | |
| UNWIND_LOG(log, "No suitable CFA found"); | |
| break; | |
| } | |
| case UnwindPlan::Row::FAValue::isConstant: { | |
| address = fa.GetConstant(); | |
| UNWIND_LOG(log, "CFA value set by constant is {0:x}", address); | |
| return true; | |
| } | |
| default: | |
| return false; | |
| } | |
| return false; | |
| } | |
| lldb::addr_t RegisterContextUnwind::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; | |
| if (ABISP abi_sp = m_thread.GetProcess()->GetABI()) | |
| hint = abi_sp->FixCodeAddress(hint); | |
| 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 { | |
| LLDB_LOG_ERRORV(GetLog(LLDBLog::Unwind), expected_size.takeError(), | |
| "Could not retrieve parameter size: {0}"); | |
| 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 RegisterContextUnwind::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); | |
| assert(reg_info); | |
| if (!reg_info) { | |
| UNWIND_LOG( | |
| GetLog(LLDBLog::Unwind), | |
| "Could not find RegisterInfo definition for lldb register number {0}", | |
| lldb_regnum); | |
| return false; | |
| } | |
| uint32_t generic_regnum = LLDB_INVALID_REGNUM; | |
| if (register_kind == eRegisterKindGeneric) | |
| generic_regnum = regnum; | |
| else | |
| m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds( | |
| register_kind, regnum, eRegisterKindGeneric, generic_regnum); | |
| ABISP abi_sp = m_thread.GetProcess()->GetABI(); | |
| 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(); | |
| if (abi_sp && generic_regnum != LLDB_INVALID_REGNUM) { | |
| if (generic_regnum == LLDB_REGNUM_GENERIC_PC || | |
| generic_regnum == LLDB_REGNUM_GENERIC_RA) | |
| value = abi_sp->FixCodeAddress(value); | |
| } | |
| return true; | |
| } | |
| return false; | |
| } | |
| bool pc_register = false; | |
| if (generic_regnum != LLDB_INVALID_REGNUM && | |
| (generic_regnum == LLDB_REGNUM_GENERIC_PC || | |
| generic_regnum == LLDB_REGNUM_GENERIC_RA)) | |
| pc_register = true; | |
| lldb_private::UnwindLLDB::ConcreteRegisterLocation 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(); | |
| if (pc_register) { | |
| if (ABISP abi_sp = m_thread.GetProcess()->GetABI()) { | |
| value = abi_sp->FixCodeAddress(value); | |
| } | |
| } | |
| return true; | |
| } | |
| return false; | |
| } | |
| bool RegisterContextUnwind::ReadGPRValue(const RegisterNumber ®num, | |
| addr_t &value) { | |
| return ReadGPRValue(regnum.GetRegisterKind(), regnum.GetRegisterNumber(), | |
| value); | |
| } | |
| // Find the value of a register in THIS frame | |
| bool RegisterContextUnwind::ReadRegister(const RegisterInfo *reg_info, | |
| RegisterValue &value) { | |
| if (!IsValid()) | |
| return false; | |
| const uint32_t lldb_regnum = reg_info->kinds[eRegisterKindLLDB]; | |
| Log *log = GetLog(LLDBLog::Unwind); | |
| UNWIND_LOG_VERBOSE(log, "looking for register saved location for reg {0}", | |
| lldb_regnum); | |
| // If this is the 0th frame, hand this over to the live register context | |
| if (IsFrameZero()) { | |
| UNWIND_LOG_VERBOSE(log, | |
| "passing along to the live register context for reg {0}", | |
| 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::ConcreteRegisterLocation 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; | |
| bool result = ReadRegisterValueFromRegisterLocation(regloc, reg_info, value); | |
| if (result) { | |
| if (is_pc_regnum && value.GetType() == RegisterValue::eTypeUInt64) { | |
| addr_t reg_value = value.GetAsUInt64(LLDB_INVALID_ADDRESS); | |
| if (reg_value != LLDB_INVALID_ADDRESS) { | |
| if (ABISP abi_sp = m_thread.GetProcess()->GetABI()) | |
| value = abi_sp->FixCodeAddress(reg_value); | |
| } | |
| } | |
| } | |
| return result; | |
| } | |
| bool RegisterContextUnwind::WriteRegister(const RegisterInfo *reg_info, | |
| const RegisterValue &value) { | |
| if (!IsValid()) | |
| return false; | |
| const uint32_t lldb_regnum = reg_info->kinds[eRegisterKindLLDB]; | |
| Log *log = GetLog(LLDBLog::Unwind); | |
| UNWIND_LOG_VERBOSE(log, "looking for register saved location for reg {0}", | |
| lldb_regnum); | |
| // If this is the 0th frame, hand this over to the live register context | |
| if (IsFrameZero()) { | |
| UNWIND_LOG_VERBOSE(log, | |
| "passing along to the live register context for reg {0}", | |
| lldb_regnum); | |
| return m_thread.GetRegisterContext()->WriteRegister(reg_info, value); | |
| } | |
| lldb_private::UnwindLLDB::ConcreteRegisterLocation 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 RegisterContextUnwind::ReadAllRegisterValues( | |
| lldb::WritableDataBufferSP &data_sp) { | |
| return false; | |
| } | |
| // Don't need to implement this one | |
| bool RegisterContextUnwind::WriteAllRegisterValues( | |
| const lldb::DataBufferSP &data_sp) { | |
| return false; | |
| } | |
| // Retrieve the pc value for THIS from | |
| bool RegisterContextUnwind::GetCFA(addr_t &cfa) { | |
| if (!IsValid()) { | |
| return false; | |
| } | |
| if (m_cfa == LLDB_INVALID_ADDRESS) { | |
| return false; | |
| } | |
| cfa = m_cfa; | |
| return true; | |
| } | |
| RegisterContextUnwind::SharedPtr RegisterContextUnwind::GetNextFrame() const { | |
| RegisterContextUnwind::SharedPtr regctx; | |
| if (m_frame_number == 0) | |
| return regctx; | |
| return m_parent_unwind.GetRegisterContextForFrameNum(m_frame_number - 1); | |
| } | |
| RegisterContextUnwind::SharedPtr RegisterContextUnwind::GetPrevFrame() const { | |
| RegisterContextUnwind::SharedPtr regctx; | |
| return m_parent_unwind.GetRegisterContextForFrameNum(m_frame_number + 1); | |
| } | |
| // Retrieve the address of the start of the function of THIS frame | |
| bool RegisterContextUnwind::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) | |
| { | |
| if (ABISP abi_sp = process_sp->GetABI()) | |
| start_pc = abi_sp->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 RegisterContextUnwind::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. | |
| if (ABISP abi_sp = m_thread.GetProcess()->GetABI()) | |
| pc = abi_sp->FixCodeAddress(pc); | |
| return !(m_all_registers_available == false && | |
| above_trap_handler == false && (pc == 0 || pc == 1)); | |
| } else { | |
| return false; | |
| } | |
| } |