diff options
Diffstat (limited to 'source/Plugins/Process/Utility/RegisterContextLLDB.cpp')
| -rw-r--r-- | source/Plugins/Process/Utility/RegisterContextLLDB.cpp | 164 |
1 files changed, 132 insertions, 32 deletions
diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp index c19aec3a02c7..f87db5810740 100644 --- a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -21,15 +21,17 @@ #include "lldb/Symbol/FuncUnwinders.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" -#include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/Symbol.h" +#include "lldb/Symbol/SymbolContext.h" #include "lldb/Target/ABI.h" +#include "lldb/Target/DynamicLoader.h" #include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" -#include "lldb/Target/DynamicLoader.h" #include "RegisterContextLLDB.h" @@ -75,13 +77,44 @@ RegisterContextLLDB::RegisterContextLLDB // This same code exists over in the GetFullUnwindPlanForFrame() but it may not have been executed yet if (IsFrameZero() - || next_frame->m_frame_type == eSigtrampFrame + || next_frame->m_frame_type == eTrapHandlerFrame || next_frame->m_frame_type == eDebuggerFrame) { m_all_registers_available = true; } } +bool +RegisterContextLLDB::IsUnwindPlanValidForCurrentPC(lldb::UnwindPlanSP unwind_plan_sp, int &valid_pc_offset) +{ + if (!unwind_plan_sp) + return false; + + // check if m_current_pc is valid + if (unwind_plan_sp->PlanValidAtAddress(m_current_pc)) + { + // yes - current offset can be used as is + valid_pc_offset = m_current_offset; + return true; + } + + // if m_current_offset <= 0, we've got nothing else to try + if (m_current_offset <= 0) + return false; + + // check pc - 1 to see if it's valid + Address pc_minus_one (m_current_pc); + pc_minus_one.SetOffset(m_current_pc.GetOffset() - 1); + if (unwind_plan_sp->PlanValidAtAddress(pc_minus_one)) + { + // *valid_pc_offset = m_current_offset - 1; + valid_pc_offset = m_current_pc.GetOffset() - 1; + return true; + } + + return false; +} + // Initialize a RegisterContextLLDB which is the first frame of a stack -- the zeroth frame or currently // executing frame. @@ -95,6 +128,7 @@ RegisterContextLLDB::InitializeZerothFrame() if (reg_ctx_sp.get() == NULL) { m_frame_type = eNotAValidFrame; + UnwindLogMsg ("frame does not have a register context"); return; } @@ -103,6 +137,7 @@ RegisterContextLLDB::InitializeZerothFrame() if (current_pc == LLDB_INVALID_ADDRESS) { m_frame_type = eNotAValidFrame; + UnwindLogMsg ("frame does not have a pc"); return; } @@ -117,7 +152,7 @@ RegisterContextLLDB::InitializeZerothFrame() current_pc = abi->FixCodeAddress(current_pc); // Initialize m_current_pc, an Address object, based on current_pc, an addr_t. - process->GetTarget().GetSectionLoadList().ResolveLoadAddress (current_pc, m_current_pc); + m_current_pc.SetLoadAddress (current_pc, &process->GetTarget()); // If we don't have a Module for some reason, we're not going to find symbol/function information - just // stick in some reasonable defaults and hope we can unwind past this frame. @@ -137,11 +172,9 @@ RegisterContextLLDB::InitializeZerothFrame() AddressRange addr_range; m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range); - static ConstString g_sigtramp_name ("_sigtramp"); - if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == g_sigtramp_name) || - (m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == g_sigtramp_name)) + if (IsTrapHandlerSymbol (process, m_sym_ctx)) { - m_frame_type = eSigtrampFrame; + m_frame_type = eTrapHandlerFrame; } else { @@ -197,6 +230,7 @@ RegisterContextLLDB::InitializeZerothFrame() if (!active_row.get()) { + UnwindLogMsg ("could not find an unwindplan row for this frame's pc"); m_frame_type = eNotAValidFrame; return; } @@ -205,6 +239,7 @@ RegisterContextLLDB::InitializeZerothFrame() addr_t cfa_regval = LLDB_INVALID_ADDRESS; if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval)) { + UnwindLogMsg ("could not read CFA register for this frame."); m_frame_type = eNotAValidFrame; return; } @@ -229,17 +264,20 @@ RegisterContextLLDB::InitializeNonZerothFrame() if (IsFrameZero ()) { m_frame_type = eNotAValidFrame; + UnwindLogMsg ("non-zeroth frame tests positive for IsFrameZero -- that shouldn't happen."); return; } if (!GetNextFrame().get() || !GetNextFrame()->IsValid()) { m_frame_type = eNotAValidFrame; + UnwindLogMsg ("Could not get next frame, marking this frame as invalid."); return; } if (!m_thread.GetRegisterContext()) { m_frame_type = eNotAValidFrame; + UnwindLogMsg ("Could not get register context for this thread, marking this frame as invalid."); return; } @@ -265,6 +303,7 @@ RegisterContextLLDB::InitializeNonZerothFrame() if (pc == 0) { m_frame_type = eNotAValidFrame; + UnwindLogMsg ("this frame has a pc of 0x0"); return; } @@ -276,7 +315,7 @@ RegisterContextLLDB::InitializeNonZerothFrame() if (abi) pc = abi->FixCodeAddress(pc); - process->GetTarget().GetSectionLoadList().ResolveLoadAddress (pc, m_current_pc); + m_current_pc.SetLoadAddress (pc, &process->GetTarget()); // If we don't have a Module for some reason, we're not going to find symbol/function information - just // stick in some reasonable defaults and hope we can unwind past this frame. @@ -304,6 +343,7 @@ RegisterContextLLDB::InitializeNonZerothFrame() { // anywhere other than the second frame, a non-executable pc means we're off in the weeds -- stop now. m_frame_type = eNotAValidFrame; + UnwindLogMsg ("pc is in a non-executable section of memory and this isn't the 2nd frame in the stack walk."); return; } } @@ -352,6 +392,7 @@ RegisterContextLLDB::InitializeNonZerothFrame() && (permissions & ePermissionsReadable) == 0) { m_frame_type = eNotAValidFrame; + UnwindLogMsg ("the CFA points to a region of memory that is not readable"); return; } } @@ -366,10 +407,15 @@ RegisterContextLLDB::InitializeNonZerothFrame() return; } m_frame_type = eNotAValidFrame; + UnwindLogMsg ("could not find any symbol for this pc, or a default unwind plan, to continue unwind."); return; } bool resolve_tail_call_address = true; // m_current_pc can be one past the address range of the function... + // This will handle the case where the saved pc does not point to + // a function/symbol because it is beyond the bounds of the correct + // function and there's no symbol there. ResolveSymbolContextForAddress + // will fail to find a symbol, back up the pc by 1 and re-search. uint32_t resolved_scope = pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, eSymbolContextFunction | eSymbolContextSymbol, m_sym_ctx, resolve_tail_call_address); @@ -392,18 +438,35 @@ RegisterContextLLDB::InitializeNonZerothFrame() if (m_sym_ctx_valid == false) decr_pc_and_recompute_addr_range = true; - // Or if we're in the middle of the stack (and not "above" an asynchronous event like sigtramp), and - // our "current" pc is the start of a function or our "current" pc is one past the end of a function... + // Or if we're in the middle of the stack (and not "above" an asynchronous event like sigtramp), + // and our "current" pc is the start of a function... if (m_sym_ctx_valid - && GetNextFrame()->m_frame_type != eSigtrampFrame + && GetNextFrame()->m_frame_type != eTrapHandlerFrame && GetNextFrame()->m_frame_type != eDebuggerFrame && addr_range.GetBaseAddress().IsValid() - && addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection()) + && addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection() + && addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset()) { - if (addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset() || - addr_range.GetBaseAddress().GetOffset() + addr_range.GetByteSize() == m_current_pc.GetOffset()) + decr_pc_and_recompute_addr_range = true; + } + + // We need to back up the pc by 1 byte and re-search for the Symbol to handle the case where the "saved pc" + // value is pointing to the next function, e.g. if a function ends with a CALL instruction. + // FIXME this may need to be an architectural-dependent behavior; if so we'll need to add a member function + // to the ABI plugin and consult that. + if (decr_pc_and_recompute_addr_range) + { + Address temporary_pc(m_current_pc); + temporary_pc.SetOffset(m_current_pc.GetOffset() - 1); + m_sym_ctx.Clear(false); + m_sym_ctx_valid = false; + if ((pc_module_sp->ResolveSymbolContextForAddress (temporary_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol) + { + m_sym_ctx_valid = true; + } + if (!m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range)) { - decr_pc_and_recompute_addr_range = true; + m_sym_ctx_valid = false; } } @@ -428,11 +491,9 @@ RegisterContextLLDB::InitializeNonZerothFrame() m_current_offset_backed_up_one = -1; } - static ConstString sigtramp_name ("_sigtramp"); - if ((m_sym_ctx.function && m_sym_ctx.function->GetMangled().GetMangledName() == sigtramp_name) - || (m_sym_ctx.symbol && m_sym_ctx.symbol->GetMangled().GetMangledName() == sigtramp_name)) + if (IsTrapHandlerSymbol (process, m_sym_ctx)) { - m_frame_type = eSigtrampFrame; + m_frame_type = eTrapHandlerFrame; } else { @@ -467,9 +528,10 @@ RegisterContextLLDB::InitializeNonZerothFrame() else { m_full_unwind_plan_sp = GetFullUnwindPlanForFrame (); - if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress (m_current_pc)) + int valid_offset = -1; + if (IsUnwindPlanValidForCurrentPC(m_full_unwind_plan_sp, valid_offset)) { - active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); + active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (valid_offset); row_register_kind = m_full_unwind_plan_sp->GetRegisterKind (); if (active_row.get() && log) { @@ -483,6 +545,7 @@ RegisterContextLLDB::InitializeNonZerothFrame() if (!active_row.get()) { m_frame_type = eNotAValidFrame; + UnwindLogMsg ("could not find unwind row for this pc"); return; } @@ -551,7 +614,7 @@ RegisterContextLLDB::IsFrameZero () const // // On entry to this method, // -// 1. m_frame_type should already be set to eSigtrampFrame/eDebuggerFrame if either of those are correct, +// 1. m_frame_type should already be set to eTrapHandlerFrame/eDebuggerFrame if either of those are correct, // 2. m_sym_ctx should already be filled in, and // 3. m_current_pc should have the current pc value for this frame // 4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown @@ -573,7 +636,7 @@ RegisterContextLLDB::GetFastUnwindPlanForFrame () return unwind_plan_sp; // If we're in _sigtramp(), unwinding past this frame requires special knowledge. - if (m_frame_type == eSigtrampFrame || m_frame_type == eDebuggerFrame) + if (m_frame_type == eTrapHandlerFrame || m_frame_type == eDebuggerFrame) return unwind_plan_sp; unwind_plan_sp = func_unwinders_sp->GetUnwindPlanFastUnwind (m_thread); @@ -602,7 +665,7 @@ RegisterContextLLDB::GetFastUnwindPlanForFrame () // On entry to this method, // -// 1. m_frame_type should already be set to eSigtrampFrame/eDebuggerFrame if either of those are correct, +// 1. m_frame_type should already be set to eTrapHandlerFrame/eDebuggerFrame if either of those are correct, // 2. m_sym_ctx should already be filled in, and // 3. m_current_pc should have the current pc value for this frame // 4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown @@ -627,7 +690,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () bool behaves_like_zeroth_frame = false; if (IsFrameZero () - || GetNextFrame()->m_frame_type == eSigtrampFrame + || GetNextFrame()->m_frame_type == eTrapHandlerFrame || GetNextFrame()->m_frame_type == eDebuggerFrame) { behaves_like_zeroth_frame = true; @@ -648,7 +711,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () uint32_t permissions; addr_t current_pc_addr = m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()); if (current_pc_addr == 0 - || (process->GetLoadAddressPermissions(current_pc_addr, permissions) + || (process->GetLoadAddressPermissions (current_pc_addr, permissions) && (permissions & ePermissionsExecutable) == 0)) { unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); @@ -697,7 +760,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () // is properly encoded in the eh_frame section, so prefer that if available. // On other platforms we may need to provide a platform-specific UnwindPlan which encodes the details of // how to unwind out of sigtramp. - if (m_frame_type == eSigtrampFrame) + if (m_frame_type == eTrapHandlerFrame) { m_fast_unwind_plan_sp.reset(); unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one); @@ -735,7 +798,8 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () // Typically this is unwind info from an eh_frame section intended for exception handling; only valid at call sites unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one); - if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc)) + int valid_offset = -1; + if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset)) { UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString()); return unwind_plan_sp; @@ -744,7 +808,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () // We'd prefer to use an UnwindPlan intended for call sites when we're at a call site but if we've // struck out on that, fall back to using the non-call-site assembly inspection UnwindPlan if possible. unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread); - if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc)) + if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset)) { UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString()); return unwind_plan_sp; @@ -915,6 +979,12 @@ RegisterContextLLDB::IsValid () const return m_frame_type != eNotAValidFrame; } +bool +RegisterContextLLDB::IsTrapHandlerFrame () const +{ + return m_frame_type == eTrapHandlerFrame; +} + // A skip frame is a bogus frame on the stack -- but one where we're likely to find a real frame farther // up the stack if we keep looking. It's always the second frame in an unwind (i.e. the first frame after // frame zero) where unwinding can be the trickiest. Ideally we'll mark up this frame in some way so the @@ -927,6 +997,35 @@ RegisterContextLLDB::IsSkipFrame () const return m_frame_type == eSkipFrame; } +bool +RegisterContextLLDB::IsTrapHandlerSymbol (lldb_private::Process *process, const lldb_private::SymbolContext &m_sym_ctx) const +{ + PlatformSP platform_sp (process->GetTarget().GetPlatform()); + if (platform_sp) + { + const std::vector<ConstString> trap_handler_names (platform_sp->GetTrapHandlerSymbolNames()); + for (ConstString name : trap_handler_names) + { + if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == name) || + (m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == name)) + { + return true; + } + } + } + const std::vector<ConstString> user_specified_trap_handler_names (m_parent_unwind.GetUserSpecifiedTrapHandlerFunctionNames()); + for (ConstString name : user_specified_trap_handler_names) + { + if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == name) || + (m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == name)) + { + return true; + } + } + + return false; +} + // Answer the question: Where did THIS frame save the CALLER frame ("previous" frame)'s register value? enum UnwindLLDB::RegisterSearchResult @@ -1161,7 +1260,7 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred; regloc.location.inferred_value = m_cfa + offset; m_registers[lldb_regnum] = regloc; - UnwindLogMsg ("supplying caller's register %d, value is CFA plus offset", lldb_regnum); + UnwindLogMsg ("supplying caller's register %d, value is CFA plus offset %d", lldb_regnum, offset); return UnwindLLDB::RegisterSearchResult::eRegisterFound; } @@ -1171,7 +1270,7 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation; regloc.location.target_memory_location = m_cfa + offset; m_registers[lldb_regnum] = regloc; - UnwindLogMsg ("supplying caller's register %d from the stack, saved at CFA plus offset", lldb_regnum); + UnwindLogMsg ("supplying caller's register %d from the stack, saved at CFA plus offset %d", lldb_regnum, offset); return UnwindLLDB::RegisterSearchResult::eRegisterFound; } @@ -1550,3 +1649,4 @@ RegisterContextLLDB::UnwindLogMsgVerbose (const char *fmt, ...) } } + |
