diff options
author | emaste <emaste@FreeBSD.org> | 2013-08-23 18:06:42 +0000 |
---|---|---|
committer | emaste <emaste@FreeBSD.org> | 2013-08-23 18:06:42 +0000 |
commit | 424d4dadd208e2a1e9a43c3d55f47f03ba0c4509 (patch) | |
tree | 05d762b98a499804ce690e6ce04033f1ddf4dee6 /contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp | |
parent | cde487f27a84e02a560384f75178fddca68740f6 (diff) | |
parent | dcd15f81789e389c1cb27d264fcdddfd0a6002bd (diff) | |
download | FreeBSD-src-424d4dadd208e2a1e9a43c3d55f47f03ba0c4509.zip FreeBSD-src-424d4dadd208e2a1e9a43c3d55f47f03ba0c4509.tar.gz |
Merge lldb r188801 to contrib/llvm/tools/lldb/
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp')
-rw-r--r-- | contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp | 1541 |
1 files changed, 1541 insertions, 0 deletions
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp new file mode 100644 index 0000000..1ffc30d --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -0,0 +1,1541 @@ +//===-- RegisterContextLLDB.cpp --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +#include "lldb/lldb-private.h" +#include "lldb/Core/Address.h" +#include "lldb/Core/AddressRange.h" +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Core/Value.h" +#include "lldb/Expression/DWARFExpression.h" +#include "lldb/Symbol/DWARFCallFrameInfo.h" +#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/Target/ABI.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/DynamicLoader.h" + +#include "RegisterContextLLDB.h" + +using namespace lldb; +using namespace lldb_private; + +RegisterContextLLDB::RegisterContextLLDB +( + Thread& thread, + const SharedPtr &next_frame, + SymbolContext& sym_ctx, + uint32_t frame_number, + UnwindLLDB& unwind_lldb +) : + RegisterContext (thread, frame_number), + m_thread(thread), + m_fast_unwind_plan_sp (), + m_full_unwind_plan_sp (), + m_all_registers_available(false), + m_frame_type (-1), + m_cfa (LLDB_INVALID_ADDRESS), + m_start_pc (), + m_current_pc (), + m_current_offset (0), + m_current_offset_backed_up_one (0), + m_sym_ctx(sym_ctx), + m_sym_ctx_valid (false), + m_frame_number (frame_number), + m_registers(), + m_parent_unwind (unwind_lldb) +{ + m_sym_ctx.Clear(false); + m_sym_ctx_valid = false; + + if (IsFrameZero ()) + { + InitializeZerothFrame (); + } + else + { + InitializeNonZerothFrame (); + } + + // This same code exists over in the GetFullUnwindPlanForFrame() but it may not have been executed yet + if (IsFrameZero() + || next_frame->m_frame_type == eSigtrampFrame + || next_frame->m_frame_type == eDebuggerFrame) + { + m_all_registers_available = true; + } +} + +// Initialize a RegisterContextLLDB which is the first frame of a stack -- the zeroth frame or currently +// executing frame. + +void +RegisterContextLLDB::InitializeZerothFrame() +{ + Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); + ExecutionContext exe_ctx(m_thread.shared_from_this()); + RegisterContextSP reg_ctx_sp = m_thread.GetRegisterContext(); + + if (reg_ctx_sp.get() == NULL) + { + m_frame_type = eNotAValidFrame; + return; + } + + addr_t current_pc = reg_ctx_sp->GetPC(); + + if (current_pc == LLDB_INVALID_ADDRESS) + { + m_frame_type = eNotAValidFrame; + return; + } + + Process *process = exe_ctx.GetProcessPtr(); + + // Let ABIs fixup code addresses to make sure they are valid. In ARM ABIs + // this will strip bit zero in case we read a PC from memory or from the LR. + // (which would be a no-op in frame 0 where we get it from the register set, + // but still a good idea to make the call here for other ABIs that may exist.) + ABI *abi = process->GetABI().get(); + if (abi) + current_pc = abi->FixCodeAddress(current_pc); + + // Initialize m_current_pc, an Address object, based on current_pc, an addr_t. + process->GetTarget().GetSectionLoadList().ResolveLoadAddress (current_pc, m_current_pc); + + // If we don't have a Module for some reason, we're not going to find symbol/function information - just + // stick in some reasonable defaults and hope we can unwind past this frame. + ModuleSP pc_module_sp (m_current_pc.GetModule()); + if (!m_current_pc.IsValid() || !pc_module_sp) + { + UnwindLogMsg ("using architectural default unwind method"); + } + + // We require that eSymbolContextSymbol be successfully filled in or this context is of no use to us. + if (pc_module_sp.get() + && (pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol) + { + m_sym_ctx_valid = true; + } + + 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)) + { + m_frame_type = eSigtrampFrame; + } + else + { + // FIXME: Detect eDebuggerFrame here. + m_frame_type = eNormalFrame; + } + + // If we were able to find a symbol/function, set addr_range to the bounds of that symbol/function. + // else treat the current pc value as the start_pc and record no offset. + if (addr_range.GetBaseAddress().IsValid()) + { + m_start_pc = addr_range.GetBaseAddress(); + if (m_current_pc.GetSection() == m_start_pc.GetSection()) + { + m_current_offset = m_current_pc.GetOffset() - m_start_pc.GetOffset(); + } + else if (m_current_pc.GetModule() == m_start_pc.GetModule()) + { + // This means that whatever symbol we kicked up isn't really correct + // --- we should not cross section boundaries ... We really should NULL out + // the function/symbol in this case unless there is a bad assumption + // here due to inlined functions? + m_current_offset = m_current_pc.GetFileAddress() - m_start_pc.GetFileAddress(); + } + m_current_offset_backed_up_one = m_current_offset; + } + else + { + m_start_pc = m_current_pc; + m_current_offset = -1; + m_current_offset_backed_up_one = -1; + } + + // We've set m_frame_type and m_sym_ctx before these calls. + + m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame (); + m_full_unwind_plan_sp = GetFullUnwindPlanForFrame (); + + UnwindPlan::RowSP active_row; + int cfa_offset = 0; + int row_register_kind = -1; + if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress (m_current_pc)) + { + active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); + row_register_kind = m_full_unwind_plan_sp->GetRegisterKind (); + if (active_row.get() && log) + { + StreamString active_row_strm; + active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr())); + UnwindLogMsg ("%s", active_row_strm.GetString().c_str()); + } + } + + if (!active_row.get()) + { + m_frame_type = eNotAValidFrame; + return; + } + + + addr_t cfa_regval = LLDB_INVALID_ADDRESS; + if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval)) + { + m_frame_type = eNotAValidFrame; + return; + } + + cfa_offset = active_row->GetCFAOffset (); + m_cfa = cfa_regval + cfa_offset; + + UnwindLogMsg ("cfa_regval = 0x%16.16" PRIx64 " (cfa_regval = 0x%16.16" PRIx64 ", cfa_offset = %i)", m_cfa, cfa_regval, cfa_offset); + UnwindLogMsg ("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64 " using %s UnwindPlan", + (uint64_t) m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()), + (uint64_t) m_cfa, + m_full_unwind_plan_sp->GetSourceName().GetCString()); +} + +// Initialize a RegisterContextLLDB for the non-zeroth frame -- rely on the RegisterContextLLDB "below" it +// to provide things like its current pc value. + +void +RegisterContextLLDB::InitializeNonZerothFrame() +{ + Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); + if (IsFrameZero ()) + { + m_frame_type = eNotAValidFrame; + return; + } + + if (!GetNextFrame().get() || !GetNextFrame()->IsValid()) + { + m_frame_type = eNotAValidFrame; + return; + } + if (!m_thread.GetRegisterContext()) + { + m_frame_type = eNotAValidFrame; + return; + } + + addr_t pc; + if (!ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc)) + { + UnwindLogMsg ("could not get pc value"); + m_frame_type = eNotAValidFrame; + return; + } + + if (log) + { + UnwindLogMsg ("pc = 0x%16.16" PRIx64, pc); + addr_t reg_val; + if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP, reg_val)) + UnwindLogMsg ("fp = 0x%16.16" PRIx64, reg_val); + if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, reg_val)) + UnwindLogMsg ("sp = 0x%16.16" PRIx64, reg_val); + } + + // A pc of 0x0 means it's the end of the stack crawl + if (pc == 0) + { + m_frame_type = eNotAValidFrame; + return; + } + + ExecutionContext exe_ctx(m_thread.shared_from_this()); + Process *process = exe_ctx.GetProcessPtr(); + // Let ABIs fixup code addresses to make sure they are valid. In ARM ABIs + // this will strip bit zero in case we read a PC from memory or from the LR. + ABI *abi = process->GetABI().get(); + if (abi) + pc = abi->FixCodeAddress(pc); + + process->GetTarget().GetSectionLoadList().ResolveLoadAddress (pc, m_current_pc); + + // If we don't have a Module for some reason, we're not going to find symbol/function information - just + // stick in some reasonable defaults and hope we can unwind past this frame. + ModuleSP pc_module_sp (m_current_pc.GetModule()); + if (!m_current_pc.IsValid() || !pc_module_sp) + { + UnwindLogMsg ("using architectural default unwind method"); + + // Test the pc value to see if we know it's in an unmapped/non-executable region of memory. + uint32_t permissions; + if (process->GetLoadAddressPermissions(pc, permissions) + && (permissions & ePermissionsExecutable) == 0) + { + // If this is the second frame off the stack, we may have unwound the first frame + // incorrectly. But using the architecture default unwind plan may get us back on + // track -- albeit possibly skipping a real frame. Give this frame a clearly-invalid + // pc and see if we can get any further. + if (GetNextFrame().get() && GetNextFrame()->IsValid() && GetNextFrame()->IsFrameZero()) + { + UnwindLogMsg ("had a pc of 0x%" PRIx64 " which is not in executable memory but on frame 1 -- allowing it once.", + (uint64_t) pc); + m_frame_type = eSkipFrame; + } + else + { + // anywhere other than the second frame, a non-executable pc means we're off in the weeds -- stop now. + m_frame_type = eNotAValidFrame; + return; + } + } + + if (abi) + { + m_fast_unwind_plan_sp.reset (); + m_full_unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); + abi->CreateDefaultUnwindPlan(*m_full_unwind_plan_sp); + if (m_frame_type != eSkipFrame) // don't override eSkipFrame + { + m_frame_type = eNormalFrame; + } + m_all_registers_available = false; + m_current_offset = -1; + m_current_offset_backed_up_one = -1; + addr_t cfa_regval = LLDB_INVALID_ADDRESS; + int row_register_kind = m_full_unwind_plan_sp->GetRegisterKind (); + UnwindPlan::RowSP row = m_full_unwind_plan_sp->GetRowForFunctionOffset(0); + if (row.get()) + { + uint32_t cfa_regnum = row->GetCFARegister(); + int cfa_offset = row->GetCFAOffset(); + if (!ReadGPRValue (row_register_kind, cfa_regnum, cfa_regval)) + { + UnwindLogMsg ("failed to get cfa value"); + if (m_frame_type != eSkipFrame) // don't override eSkipFrame + { + m_frame_type = eNormalFrame; + } + return; + } + m_cfa = cfa_regval + cfa_offset; + + // A couple of sanity checks.. + if (cfa_regval == LLDB_INVALID_ADDRESS || cfa_regval == 0 || cfa_regval == 1) + { + UnwindLogMsg ("could not find a valid cfa address"); + m_frame_type = eNotAValidFrame; + return; + } + + // cfa_regval should point into the stack memory; if we can query memory region permissions, + // see if the memory is allocated & readable. + if (process->GetLoadAddressPermissions(cfa_regval, permissions) + && (permissions & ePermissionsReadable) == 0) + { + m_frame_type = eNotAValidFrame; + return; + } + } + else + { + UnwindLogMsg ("could not find a row for function offset zero"); + m_frame_type = eNotAValidFrame; + return; + } + + UnwindLogMsg ("initialized frame cfa is 0x%" PRIx64, (uint64_t) m_cfa); + return; + } + m_frame_type = eNotAValidFrame; + return; + } + + // We require that eSymbolContextSymbol be successfully filled in or this context is of no use to us. + if ((pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol) + { + m_sym_ctx_valid = true; + } + + AddressRange addr_range; + if (!m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range)) + { + m_sym_ctx_valid = false; + } + + bool decr_pc_and_recompute_addr_range = false; + + // If the symbol lookup failed... + 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... + if (m_sym_ctx_valid + && GetNextFrame()->m_frame_type != eSigtrampFrame + && GetNextFrame()->m_frame_type != eDebuggerFrame + && addr_range.GetBaseAddress().IsValid() + && addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection() + && addr_range.GetBaseAddress().GetOffset() == 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)) + { + m_sym_ctx_valid = false; + } + } + + // If we were able to find a symbol/function, set addr_range_ptr to the bounds of that symbol/function. + // else treat the current pc value as the start_pc and record no offset. + if (addr_range.GetBaseAddress().IsValid()) + { + m_start_pc = addr_range.GetBaseAddress(); + m_current_offset = m_current_pc.GetOffset() - m_start_pc.GetOffset(); + 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.SetOffset(m_current_pc.GetOffset() - 1); + } + } + else + { + m_start_pc = m_current_pc; + m_current_offset = -1; + 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)) + { + m_frame_type = eSigtrampFrame; + } + else + { + // FIXME: Detect eDebuggerFrame here. + if (m_frame_type != eSkipFrame) // don't override eSkipFrame + { + m_frame_type = eNormalFrame; + } + } + + // We've set m_frame_type and m_sym_ctx before this call. + m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame (); + + UnwindPlan::RowSP active_row; + int cfa_offset = 0; + int row_register_kind = -1; + + // 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 (); + if (active_row.get() && log) + { + StreamString active_row_strm; + active_row->Dump(active_row_strm, m_fast_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr())); + UnwindLogMsg ("active row: %s", active_row_strm.GetString().c_str()); + } + } + else + { + m_full_unwind_plan_sp = GetFullUnwindPlanForFrame (); + if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress (m_current_pc)) + { + active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); + row_register_kind = m_full_unwind_plan_sp->GetRegisterKind (); + if (active_row.get() && log) + { + StreamString active_row_strm; + active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr())); + UnwindLogMsg ("active row: %s", active_row_strm.GetString().c_str()); + } + } + } + + if (!active_row.get()) + { + m_frame_type = eNotAValidFrame; + return; + } + + addr_t cfa_regval = LLDB_INVALID_ADDRESS; + if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval)) + { + UnwindLogMsg ("failed to get cfa reg %d/%d", row_register_kind, active_row->GetCFARegister()); + m_frame_type = eNotAValidFrame; + return; + } + + cfa_offset = active_row->GetCFAOffset (); + m_cfa = cfa_regval + cfa_offset; + + UnwindLogMsg ("cfa_regval = 0x%16.16" PRIx64 " (cfa_regval = 0x%16.16" PRIx64 ", cfa_offset = %i)", m_cfa, cfa_regval, cfa_offset); + + // A couple of sanity checks.. + if (cfa_regval == LLDB_INVALID_ADDRESS || cfa_regval == 0 || cfa_regval == 1) + { + UnwindLogMsg ("could not find a valid cfa address"); + m_frame_type = eNotAValidFrame; + return; + } + + // 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. + addr_t next_frame_cfa; + addr_t next_next_frame_cfa = LLDB_INVALID_ADDRESS; + if (GetNextFrame().get() && GetNextFrame()->GetCFA(next_frame_cfa)) + { + bool repeating_frames = false; + if (next_frame_cfa == m_cfa) + { + repeating_frames = true; + } + else + { + if (GetNextFrame()->GetNextFrame() && GetNextFrame()->GetNextFrame()->GetCFA(next_next_frame_cfa) + && next_next_frame_cfa == m_cfa) + { + repeating_frames = true; + } + } + if (repeating_frames && abi->FunctionCallsChangeCFA()) + { + UnwindLogMsg ("same CFA address as next frame, assuming the unwind is looping - stopping"); + m_frame_type = eNotAValidFrame; + return; + } + } + + UnwindLogMsg ("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64, + (uint64_t) m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()), (uint64_t) m_cfa); +} + + +bool +RegisterContextLLDB::IsFrameZero () const +{ + return m_frame_number == 0; +} + + +// Find a fast unwind plan for this frame, if possible. +// +// On entry to this method, +// +// 1. m_frame_type should already be set to eSigtrampFrame/eDebuggerFrame if either of those are correct, +// 2. m_sym_ctx should already be filled in, and +// 3. m_current_pc should have the current pc value for this frame +// 4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown + +UnwindPlanSP +RegisterContextLLDB::GetFastUnwindPlanForFrame () +{ + UnwindPlanSP unwind_plan_sp; + ModuleSP pc_module_sp (m_current_pc.GetModule()); + + if (!m_current_pc.IsValid() || !pc_module_sp || pc_module_sp->GetObjectFile() == NULL) + return unwind_plan_sp; + + if (IsFrameZero ()) + return unwind_plan_sp; + + FuncUnwindersSP func_unwinders_sp (pc_module_sp->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx)); + if (!func_unwinders_sp) + return unwind_plan_sp; + + // If we're in _sigtramp(), unwinding past this frame requires special knowledge. + if (m_frame_type == eSigtrampFrame || m_frame_type == eDebuggerFrame) + return unwind_plan_sp; + + unwind_plan_sp = func_unwinders_sp->GetUnwindPlanFastUnwind (m_thread); + if (unwind_plan_sp) + { + if (unwind_plan_sp->PlanValidAtAddress (m_current_pc)) + { + Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); + if (log && log->GetVerbose()) + { + if (m_fast_unwind_plan_sp) + UnwindLogMsgVerbose ("frame, and has a fast UnwindPlan"); + else + UnwindLogMsgVerbose ("frame"); + } + m_frame_type = eNormalFrame; + return unwind_plan_sp; + } + else + { + unwind_plan_sp.reset(); + } + } + return unwind_plan_sp; +} + +// On entry to this method, +// +// 1. m_frame_type should already be set to eSigtrampFrame/eDebuggerFrame if either of those are correct, +// 2. m_sym_ctx should already be filled in, and +// 3. m_current_pc should have the current pc value for this frame +// 4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown + +UnwindPlanSP +RegisterContextLLDB::GetFullUnwindPlanForFrame () +{ + UnwindPlanSP unwind_plan_sp; + UnwindPlanSP arch_default_unwind_plan_sp; + ExecutionContext exe_ctx(m_thread.shared_from_this()); + Process *process = exe_ctx.GetProcessPtr(); + ABI *abi = process ? process->GetABI().get() : NULL; + if (abi) + { + arch_default_unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); + abi->CreateDefaultUnwindPlan(*arch_default_unwind_plan_sp); + } + + bool behaves_like_zeroth_frame = false; + if (IsFrameZero () + || GetNextFrame()->m_frame_type == eSigtrampFrame + || GetNextFrame()->m_frame_type == eDebuggerFrame) + { + behaves_like_zeroth_frame = true; + // If this frame behaves like a 0th frame (currently executing or + // interrupted asynchronously), all registers can be retrieved. + m_all_registers_available = true; + } + + // If we've done a jmp 0x0 / bl 0x0 (called through a null function pointer) so the pc is 0x0 + // in the zeroth frame, we need to use the "unwind at first instruction" arch default UnwindPlan + // Also, if this Process can report on memory region attributes, any non-executable region means + // we jumped through a bad function pointer - handle the same way as 0x0. + // Note, if the symbol context has a function for the symbol, then we don't need to do this check. + + if ((!m_sym_ctx_valid || m_sym_ctx.function == NULL) && 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->GetLoadAddressPermissions(current_pc_addr, permissions) + && (permissions & ePermissionsExecutable) == 0)) + { + unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); + abi->CreateFunctionEntryUnwindPlan(*unwind_plan_sp); + m_frame_type = eNormalFrame; + return unwind_plan_sp; + } + } + + // No Module for the current pc, try using the architecture default unwind. + ModuleSP pc_module_sp (m_current_pc.GetModule()); + if (!m_current_pc.IsValid() || !pc_module_sp || pc_module_sp->GetObjectFile() == NULL) + { + m_frame_type = eNormalFrame; + return arch_default_unwind_plan_sp; + } + + FuncUnwindersSP func_unwinders_sp; + if (m_sym_ctx_valid) + { + func_unwinders_sp = pc_module_sp->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx); + } + + // No FuncUnwinders available for this pc (i.e. a stripped function symbol and -fomit-frame-pointer). + // Try using the eh_frame information relative to the current PC, + // and finally fall back on the architectural default unwind. + if (!func_unwinders_sp) + { + DWARFCallFrameInfo *eh_frame = pc_module_sp && pc_module_sp->GetObjectFile() ? + pc_module_sp->GetObjectFile()->GetUnwindTable().GetEHFrameInfo() : nullptr; + + m_frame_type = eNormalFrame; + if (eh_frame && m_current_pc.IsValid()) + { + unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); + // Even with -fomit-frame-pointer, we can try eh_frame to get back on track. + if (eh_frame->GetUnwindPlan (m_current_pc, *unwind_plan_sp)) + return unwind_plan_sp; + else + unwind_plan_sp.reset(); + } + return arch_default_unwind_plan_sp; + } + + // If we're in _sigtramp(), unwinding past this frame requires special knowledge. On Mac OS X this knowledge + // is properly encoded in the eh_frame section, so prefer that if available. + // On other platforms we may need to provide a platform-specific UnwindPlan which encodes the details of + // how to unwind out of sigtramp. + if (m_frame_type == eSigtrampFrame) + { + m_fast_unwind_plan_sp.reset(); + unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one); + if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc)) + 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)) + { + unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one); + if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc)) + { + UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan because the DynamicLoader suggested we prefer it", + unwind_plan_sp->GetSourceName().GetCString()); + return unwind_plan_sp; + } + } + + // Typically the NonCallSite UnwindPlan is the unwind created by inspecting the assembly language instructions + if (behaves_like_zeroth_frame) + { + unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread); + if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc)) + { + UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString()); + return unwind_plan_sp; + } + } + + // Typically this is unwind info from an eh_frame section intended for exception handling; only valid at call sites + unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one); + if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc)) + { + UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString()); + return unwind_plan_sp; + } + + // We'd prefer to use an UnwindPlan intended for call sites when we're at a call site but if we've + // struck out on that, fall back to using the non-call-site assembly inspection UnwindPlan if possible. + unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread); + if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc)) + { + UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString()); + return unwind_plan_sp; + } + + // If nothing else, use the architectural default UnwindPlan and hope that does the job. + UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", arch_default_unwind_plan_sp->GetSourceName().GetCString()); + return arch_default_unwind_plan_sp; +} + + +void +RegisterContextLLDB::InvalidateAllRegisters () +{ + m_frame_type = eNotAValidFrame; +} + +size_t +RegisterContextLLDB::GetRegisterCount () +{ + return m_thread.GetRegisterContext()->GetRegisterCount(); +} + +const RegisterInfo * +RegisterContextLLDB::GetRegisterInfoAtIndex (size_t reg) +{ + return m_thread.GetRegisterContext()->GetRegisterInfoAtIndex (reg); +} + +size_t +RegisterContextLLDB::GetRegisterSetCount () +{ + return m_thread.GetRegisterContext()->GetRegisterSetCount (); +} + +const RegisterSet * +RegisterContextLLDB::GetRegisterSet (size_t reg_set) +{ + return m_thread.GetRegisterContext()->GetRegisterSet (reg_set); +} + +uint32_t +RegisterContextLLDB::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) +{ + return m_thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (kind, num); +} + +bool +RegisterContextLLDB::ReadRegisterValueFromRegisterLocation (lldb_private::UnwindLLDB::RegisterLocation regloc, + const RegisterInfo *reg_info, + RegisterValue &value) +{ + if (!IsValid()) + return false; + bool success = false; + + switch (regloc.type) + { + case UnwindLLDB::RegisterLocation::eRegisterInRegister: + { + const RegisterInfo *other_reg_info = GetRegisterInfoAtIndex(regloc.location.register_number); + + if (!other_reg_info) + return false; + + if (IsFrameZero ()) + { + success = m_thread.GetRegisterContext()->ReadRegister (other_reg_info, value); + } + else + { + success = GetNextFrame()->ReadRegister (other_reg_info, value); + } + } + break; + case UnwindLLDB::RegisterLocation::eRegisterValueInferred: + success = value.SetUInt (regloc.location.inferred_value, reg_info->byte_size); + break; + + case UnwindLLDB::RegisterLocation::eRegisterNotSaved: + break; + case UnwindLLDB::RegisterLocation::eRegisterSavedAtHostMemoryLocation: + assert ("FIXME debugger inferior function call unwind"); + break; + case UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation: + { + Error error (ReadRegisterValueFromMemory(reg_info, + regloc.location.target_memory_location, + reg_info->byte_size, + value)); + success = error.Success(); + } + break; + default: + assert ("Unknown RegisterLocation type."); + break; + } + return success; +} + +bool +RegisterContextLLDB::WriteRegisterValueToRegisterLocation (lldb_private::UnwindLLDB::RegisterLocation regloc, + const RegisterInfo *reg_info, + const RegisterValue &value) +{ + if (!IsValid()) + return false; + + bool success = false; + + switch (regloc.type) + { + case UnwindLLDB::RegisterLocation::eRegisterInRegister: + { + const RegisterInfo *other_reg_info = GetRegisterInfoAtIndex(regloc.location.register_number); + if (IsFrameZero ()) + { + success = m_thread.GetRegisterContext()->WriteRegister (other_reg_info, value); + } + else + { + success = GetNextFrame()->WriteRegister (other_reg_info, value); + } + } + break; + case UnwindLLDB::RegisterLocation::eRegisterValueInferred: + case UnwindLLDB::RegisterLocation::eRegisterNotSaved: + break; + case UnwindLLDB::RegisterLocation::eRegisterSavedAtHostMemoryLocation: + assert ("FIXME debugger inferior function call unwind"); + break; + case UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation: + { + Error error (WriteRegisterValueToMemory (reg_info, + regloc.location.target_memory_location, + reg_info->byte_size, + value)); + success = error.Success(); + } + break; + default: + assert ("Unknown RegisterLocation type."); + break; + } + return success; +} + + +bool +RegisterContextLLDB::IsValid () const +{ + return m_frame_type != eNotAValidFrame; +} + +// A skip frame is a bogus frame on the stack -- but one where we're likely to find a real frame farther +// up the stack if we keep looking. It's always the second frame in an unwind (i.e. the first frame after +// frame zero) where unwinding can be the trickiest. Ideally we'll mark up this frame in some way so the +// user knows we're displaying bad data and we may have skipped one frame of their real program in the +// process of getting back on track. + +bool +RegisterContextLLDB::IsSkipFrame () const +{ + return m_frame_type == eSkipFrame; +} + +// Answer the question: Where did THIS frame save the CALLER frame ("previous" frame)'s register value? + +enum UnwindLLDB::RegisterSearchResult +RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation ®loc) +{ + // Have we already found this register location? + if (!m_registers.empty()) + { + std::map<uint32_t, lldb_private::UnwindLLDB::RegisterLocation>::const_iterator iterator; + iterator = m_registers.find (lldb_regnum); + if (iterator != m_registers.end()) + { + regloc = iterator->second; + UnwindLogMsg ("supplying caller's saved reg %d's location, cached", lldb_regnum); + return UnwindLLDB::RegisterSearchResult::eRegisterFound; + } + } + + uint32_t sp_regnum = LLDB_INVALID_REGNUM; + uint32_t pc_regnum = LLDB_INVALID_REGNUM; + m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, eRegisterKindLLDB, sp_regnum); + m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, eRegisterKindLLDB, pc_regnum); + + // Are we looking for the CALLER's stack pointer? The stack pointer is defined to be the same as THIS frame's + // CFA so just return the CFA value. This is true on x86-32/x86-64 at least. + if (sp_regnum != LLDB_INVALID_REGNUM && sp_regnum == lldb_regnum) + { + // make sure we won't lose precision copying an addr_t (m_cfa) into a uint64_t (.inferred_value) + assert (sizeof (addr_t) <= sizeof (uint64_t)); + regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred; + regloc.location.inferred_value = m_cfa; + m_registers[lldb_regnum] = regloc; + UnwindLogMsg ("supplying caller's stack pointer (%d) value, computed from CFA", lldb_regnum); + return UnwindLLDB::RegisterSearchResult::eRegisterFound; + } + + // Look through the available UnwindPlans for the register location. + + UnwindPlan::Row::RegisterLocation unwindplan_regloc; + bool have_unwindplan_regloc = false; + RegisterKind unwindplan_registerkind = (RegisterKind)-1; + + if (m_fast_unwind_plan_sp) + { + UnwindPlan::RowSP active_row = m_fast_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); + unwindplan_registerkind = m_fast_unwind_plan_sp->GetRegisterKind (); + uint32_t row_regnum; + if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindLLDB, lldb_regnum, unwindplan_registerkind, row_regnum)) + { + UnwindLogMsg ("could not convert lldb regnum %d into %d RegisterKind reg numbering scheme", + lldb_regnum, (int) unwindplan_registerkind); + return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; + } + if (active_row->GetRegisterInfo (row_regnum, unwindplan_regloc)) + { + UnwindLogMsg ("supplying caller's saved reg %d's location using FastUnwindPlan", lldb_regnum); + have_unwindplan_regloc = true; + } + } + + if (!have_unwindplan_regloc) + { + // m_full_unwind_plan_sp being NULL means that we haven't tried to find a full UnwindPlan yet + if (!m_full_unwind_plan_sp) + m_full_unwind_plan_sp = GetFullUnwindPlanForFrame (); + + if (m_full_unwind_plan_sp) + { + UnwindPlan::RowSP active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); + unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind (); + uint32_t row_regnum; + bool row_register_rewritten_to_return_address_reg = false; + + // If we're fetching the saved pc and this UnwindPlan defines a ReturnAddress register (e.g. lr on arm), + // look for the return address register number in the UnwindPlan's row. + if (lldb_regnum == pc_regnum && m_full_unwind_plan_sp->GetReturnAddressRegister() != LLDB_INVALID_REGNUM) + { + row_regnum = m_full_unwind_plan_sp->GetReturnAddressRegister(); + row_register_rewritten_to_return_address_reg = true; + UnwindLogMsg ("requested caller's saved PC but this UnwindPlan uses a RA reg; getting reg %d instead", + row_regnum); + } + else + { + if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindLLDB, lldb_regnum, unwindplan_registerkind, row_regnum)) + { + if (unwindplan_registerkind == eRegisterKindGeneric) + UnwindLogMsg ("could not convert lldb regnum %d into eRegisterKindGeneric reg numbering scheme", lldb_regnum); + else + UnwindLogMsg ("could not convert lldb regnum %d into %d RegisterKind reg numbering scheme", + lldb_regnum, (int) unwindplan_registerkind); + return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; + } + } + + if (active_row->GetRegisterInfo (row_regnum, unwindplan_regloc)) + { + have_unwindplan_regloc = true; + UnwindLogMsg ("supplying caller's saved reg %d's location using %s UnwindPlan", lldb_regnum, + m_full_unwind_plan_sp->GetSourceName().GetCString()); + } + + // This is frame 0 and we're retrieving the PC and it's saved in a Return Address register and + // it hasn't been saved anywhere yet -- that is, it's still live in the actual register. + // Handle this specially. + + if (have_unwindplan_regloc == false + && row_register_rewritten_to_return_address_reg == true + && IsFrameZero() + && row_regnum != LLDB_INVALID_REGNUM) + { + uint32_t ra_regnum_in_lldb_reg_numbering; + if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (unwindplan_registerkind, row_regnum, eRegisterKindLLDB, ra_regnum_in_lldb_reg_numbering)) + { + lldb_private::UnwindLLDB::RegisterLocation new_regloc; + new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister; + new_regloc.location.register_number = ra_regnum_in_lldb_reg_numbering; + m_registers[lldb_regnum] = new_regloc; + regloc = new_regloc; + UnwindLogMsg ("supplying caller's register %d from the live RegisterContext at frame 0, saved in %d", lldb_regnum, ra_regnum_in_lldb_reg_numbering); + return UnwindLLDB::RegisterSearchResult::eRegisterFound; + } + } + + // If this architecture stores the return address in a register (it defines a Return Address register) + // and we're on a non-zero stack frame and the Full UnwindPlan says that the pc is stored in the + // RA registers (e.g. lr on arm), then we know that the full unwindplan is not trustworthy -- this + // is an impossible situation and the instruction emulation code has likely been misled. + // If this stack frame meets those criteria, we need to throw away the Full UnwindPlan that the + // instruction emulation came up with and fall back to the architecture's Default UnwindPlan so + // the stack walk can get past this point. + + // Special note: If the Full UnwindPlan was generated from the compiler, don't second-guess it + // when we're at a call site location. + + // arch_default_ra_regnum is the return address register # in the Full UnwindPlan register numbering + uint32_t arch_default_ra_regnum = LLDB_INVALID_REGNUM; + if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, unwindplan_registerkind, arch_default_ra_regnum) + && arch_default_ra_regnum != LLDB_INVALID_REGNUM + && pc_regnum != LLDB_INVALID_REGNUM + && pc_regnum == lldb_regnum + && unwindplan_regloc.IsInOtherRegister() + && unwindplan_regloc.GetRegisterNumber() == arch_default_ra_regnum + && m_full_unwind_plan_sp->GetSourcedFromCompiler() != eLazyBoolYes + && !m_all_registers_available) + { + UnwindLogMsg ("%s UnwindPlan tried to restore the pc from the link register but this is a non-zero frame", + m_full_unwind_plan_sp->GetSourceName().GetCString()); + + // Throw away the full unwindplan; install the arch default unwindplan + InvalidateFullUnwindPlan(); + + // Now re-fetch the pc value we're searching for + uint32_t arch_default_pc_reg = LLDB_INVALID_REGNUM; + UnwindPlan::RowSP active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); + if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, m_full_unwind_plan_sp->GetRegisterKind(), arch_default_pc_reg) + && arch_default_pc_reg != LLDB_INVALID_REGNUM + && active_row + && active_row->GetRegisterInfo (arch_default_pc_reg, unwindplan_regloc)) + { + have_unwindplan_regloc = true; + } + else + { + have_unwindplan_regloc = false; + } + } + } + } + + + ExecutionContext exe_ctx(m_thread.shared_from_this()); + Process *process = exe_ctx.GetProcessPtr(); + if (have_unwindplan_regloc == false) + { + // If a volatile register is being requested, we don't want to forward the next frame's register contents + // up the stack -- the register is not retrievable at this frame. + ABI *abi = process ? process->GetABI().get() : NULL; + if (abi) + { + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(lldb_regnum); + if (reg_info && abi->RegisterIsVolatile (reg_info)) + { + UnwindLogMsg ("did not supply reg location for %d because it is volatile", lldb_regnum); + return UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile; + } + } + + if (IsFrameZero ()) + { + // This is frame 0 - we should return the actual live register context value + lldb_private::UnwindLLDB::RegisterLocation new_regloc; + new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister; + new_regloc.location.register_number = lldb_regnum; + m_registers[lldb_regnum] = new_regloc; + regloc = new_regloc; + UnwindLogMsg ("supplying caller's register %d from the live RegisterContext at frame 0", lldb_regnum); + return UnwindLLDB::RegisterSearchResult::eRegisterFound; + } + else + UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum); + return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; + } + + // unwindplan_regloc has valid contents about where to retrieve the register + if (unwindplan_regloc.IsUnspecified()) + { + lldb_private::UnwindLLDB::RegisterLocation new_regloc; + new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterNotSaved; + m_registers[lldb_regnum] = new_regloc; + UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum); + return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; + } + + if (unwindplan_regloc.IsSame()) + { + if (IsFrameZero ()) + { + UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum); + return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; + } + else + { + return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; + } + } + + if (unwindplan_regloc.IsCFAPlusOffset()) + { + int offset = unwindplan_regloc.GetOffset(); + 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); + return UnwindLLDB::RegisterSearchResult::eRegisterFound; + } + + if (unwindplan_regloc.IsAtCFAPlusOffset()) + { + int offset = unwindplan_regloc.GetOffset(); + regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation; + regloc.location.target_memory_location = m_cfa + offset; + m_registers[lldb_regnum] = regloc; + UnwindLogMsg ("supplying caller's register %d from the stack, saved at CFA plus offset", lldb_regnum); + return UnwindLLDB::RegisterSearchResult::eRegisterFound; + } + + if (unwindplan_regloc.IsInOtherRegister()) + { + uint32_t unwindplan_regnum = unwindplan_regloc.GetRegisterNumber(); + uint32_t row_regnum_in_lldb; + if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (unwindplan_registerkind, unwindplan_regnum, eRegisterKindLLDB, row_regnum_in_lldb)) + { + UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum); + return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; + } + regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister; + regloc.location.register_number = row_regnum_in_lldb; + m_registers[lldb_regnum] = regloc; + UnwindLogMsg ("supplying caller's register %d, saved in register %d", lldb_regnum, row_regnum_in_lldb); + return UnwindLLDB::RegisterSearchResult::eRegisterFound; + } + + if (unwindplan_regloc.IsDWARFExpression() || unwindplan_regloc.IsAtDWARFExpression()) + { + DataExtractor dwarfdata (unwindplan_regloc.GetDWARFExpressionBytes(), + unwindplan_regloc.GetDWARFExpressionLength(), + process->GetByteOrder(), process->GetAddressByteSize()); + DWARFExpression dwarfexpr (dwarfdata, 0, unwindplan_regloc.GetDWARFExpressionLength()); + dwarfexpr.SetRegisterKind (unwindplan_registerkind); + Value result; + Error error; + if (dwarfexpr.Evaluate (&exe_ctx, NULL, NULL, this, 0, NULL, result, &error)) + { + addr_t val; + val = result.GetScalar().ULongLong(); + if (unwindplan_regloc.IsDWARFExpression()) + { + regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred; + regloc.location.inferred_value = val; + m_registers[lldb_regnum] = regloc; + UnwindLogMsg ("supplying caller's register %d via DWARF expression (IsDWARFExpression)", lldb_regnum); + return UnwindLLDB::RegisterSearchResult::eRegisterFound; + } + else + { + regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation; + regloc.location.target_memory_location = val; + m_registers[lldb_regnum] = regloc; + UnwindLogMsg ("supplying caller's register %d via DWARF expression (IsAtDWARFExpression)", lldb_regnum); + return UnwindLLDB::RegisterSearchResult::eRegisterFound; + } + } + UnwindLogMsg ("tried to use IsDWARFExpression or IsAtDWARFExpression for reg %d but failed", lldb_regnum); + return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; + } + + UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum); + + // FIXME UnwindPlan::Row types atDWARFExpression and isDWARFExpression are unsupported. + + return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; +} + +// If the Full unwindplan has been determined to be incorrect, this method will +// replace it with the architecture's default unwindplna, if one is defined. +// It will also find the FuncUnwinders object for this function and replace the +// Full unwind method for the function there so we don't use the errant Full unwindplan +// again in the future of this debug session. +// We're most likely doing this because the Full unwindplan was generated by assembly +// instruction profiling and the profiler got something wrong. + +void +RegisterContextLLDB::InvalidateFullUnwindPlan () +{ + UnwindPlan::Row::RegisterLocation unwindplan_regloc; + ExecutionContext exe_ctx (m_thread.shared_from_this()); + Process *process = exe_ctx.GetProcessPtr(); + ABI *abi = process ? process->GetABI().get() : NULL; + if (abi) + { + UnwindPlanSP original_full_unwind_plan_sp = m_full_unwind_plan_sp; + UnwindPlanSP arch_default_unwind_plan_sp; + arch_default_unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); + abi->CreateDefaultUnwindPlan(*arch_default_unwind_plan_sp); + if (arch_default_unwind_plan_sp) + { + UnwindPlan::RowSP active_row = arch_default_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); + + if (active_row && active_row->GetCFARegister() != LLDB_INVALID_REGNUM) + { + FuncUnwindersSP func_unwinders_sp; + if (m_sym_ctx_valid && m_current_pc.IsValid() && m_current_pc.GetModule()) + { + func_unwinders_sp = m_current_pc.GetModule()->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx); + if (func_unwinders_sp) + { + func_unwinders_sp->InvalidateNonCallSiteUnwindPlan (m_thread); + } + } + m_registers.clear(); + m_full_unwind_plan_sp = arch_default_unwind_plan_sp; + addr_t cfa_regval = LLDB_INVALID_ADDRESS; + if (ReadGPRValue (arch_default_unwind_plan_sp->GetRegisterKind(), active_row->GetCFARegister(), cfa_regval)) + { + m_cfa = cfa_regval + active_row->GetCFAOffset (); + } + + UnwindLogMsg ("full unwind plan '%s' has been replaced by architecture default unwind plan '%s' for this function from now on.", + original_full_unwind_plan_sp->GetSourceName().GetCString(), arch_default_unwind_plan_sp->GetSourceName().GetCString()); + } + } + } +} + +// Retrieve a general purpose register value for THIS frame, as saved by the NEXT frame, i.e. the frame that +// this frame called. e.g. +// +// foo () { } +// bar () { foo (); } +// main () { bar (); } +// +// stopped in foo() so +// frame 0 - foo +// frame 1 - bar +// frame 2 - main +// and this RegisterContext is for frame 1 (bar) - if we want to get the pc value for frame 1, we need to ask +// where frame 0 (the "next" frame) saved that and retrieve the value. + +bool +RegisterContextLLDB::ReadGPRValue (int register_kind, uint32_t regnum, addr_t &value) +{ + if (!IsValid()) + return false; + + uint32_t lldb_regnum; + if (register_kind == eRegisterKindLLDB) + { + lldb_regnum = regnum; + } + else if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (register_kind, regnum, eRegisterKindLLDB, lldb_regnum)) + { + return false; + } + + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(lldb_regnum); + RegisterValue reg_value; + // if this is frame 0 (currently executing frame), get the requested reg contents from the actual thread registers + if (IsFrameZero ()) + { + if (m_thread.GetRegisterContext()->ReadRegister (reg_info, reg_value)) + { + value = reg_value.GetAsUInt64(); + return true; + } + return false; + } + + bool pc_register = false; + uint32_t generic_regnum; + if (register_kind == eRegisterKindGeneric && regnum == LLDB_REGNUM_GENERIC_PC) + { + pc_register = true; + } + else if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (register_kind, regnum, eRegisterKindGeneric, generic_regnum) + && generic_regnum == LLDB_REGNUM_GENERIC_PC) + { + pc_register = true; + } + + lldb_private::UnwindLLDB::RegisterLocation regloc; + if (!m_parent_unwind.SearchForSavedLocationForRegister (lldb_regnum, regloc, m_frame_number - 1, pc_register)) + { + return false; + } + if (ReadRegisterValueFromRegisterLocation (regloc, reg_info, reg_value)) + { + value = reg_value.GetAsUInt64(); + return true; + } + return false; +} + +// Find the value of a register in THIS frame + +bool +RegisterContextLLDB::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value) +{ + if (!IsValid()) + return false; + + const uint32_t lldb_regnum = reg_info->kinds[eRegisterKindLLDB]; + UnwindLogMsgVerbose ("looking for register saved location for reg %d", lldb_regnum); + + // If this is the 0th frame, hand this over to the live register context + if (IsFrameZero ()) + { + UnwindLogMsgVerbose ("passing along to the live register context for reg %d", lldb_regnum); + return m_thread.GetRegisterContext()->ReadRegister (reg_info, value); + } + + lldb_private::UnwindLLDB::RegisterLocation regloc; + // Find out where the NEXT frame saved THIS frame's register contents + if (!m_parent_unwind.SearchForSavedLocationForRegister (lldb_regnum, regloc, m_frame_number - 1, false)) + return false; + + return ReadRegisterValueFromRegisterLocation (regloc, reg_info, value); +} + +bool +RegisterContextLLDB::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &value) +{ + if (!IsValid()) + return false; + + const uint32_t lldb_regnum = reg_info->kinds[eRegisterKindLLDB]; + UnwindLogMsgVerbose ("looking for register saved location for reg %d", lldb_regnum); + + // If this is the 0th frame, hand this over to the live register context + if (IsFrameZero ()) + { + UnwindLogMsgVerbose ("passing along to the live register context for reg %d", lldb_regnum); + return m_thread.GetRegisterContext()->WriteRegister (reg_info, value); + } + + lldb_private::UnwindLLDB::RegisterLocation regloc; + // Find out where the NEXT frame saved THIS frame's register contents + if (!m_parent_unwind.SearchForSavedLocationForRegister (lldb_regnum, regloc, m_frame_number - 1, false)) + return false; + + return WriteRegisterValueToRegisterLocation (regloc, reg_info, value); +} + +// Don't need to implement this one +bool +RegisterContextLLDB::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) +{ + return false; +} + +// Don't need to implement this one +bool +RegisterContextLLDB::WriteAllRegisterValues (const lldb::DataBufferSP& data_sp) +{ + return false; +} + +// Retrieve the pc value for THIS from + +bool +RegisterContextLLDB::GetCFA (addr_t& cfa) +{ + if (!IsValid()) + { + return false; + } + if (m_cfa == LLDB_INVALID_ADDRESS) + { + return false; + } + cfa = m_cfa; + return true; +} + + +RegisterContextLLDB::SharedPtr +RegisterContextLLDB::GetNextFrame () const +{ + RegisterContextLLDB::SharedPtr regctx; + if (m_frame_number == 0) + return regctx; + return m_parent_unwind.GetRegisterContextForFrameNum (m_frame_number - 1); +} + +RegisterContextLLDB::SharedPtr +RegisterContextLLDB::GetPrevFrame () const +{ + RegisterContextLLDB::SharedPtr regctx; + return m_parent_unwind.GetRegisterContextForFrameNum (m_frame_number + 1); +} + +// Retrieve the address of the start of the function of THIS frame + +bool +RegisterContextLLDB::GetStartPC (addr_t& start_pc) +{ + if (!IsValid()) + return false; + + if (!m_start_pc.IsValid()) + { + return ReadPC (start_pc); + } + start_pc = m_start_pc.GetLoadAddress (CalculateTarget().get()); + return true; +} + +// Retrieve the current pc value for THIS frame, as saved by the NEXT frame. + +bool +RegisterContextLLDB::ReadPC (addr_t& pc) +{ + if (!IsValid()) + return false; + + 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 (m_all_registers_available == false + && (pc == 0 || pc == 1)) + { + return false; + } + else + { + return true; + } + } + else + { + return false; + } +} + + +void +RegisterContextLLDB::UnwindLogMsg (const char *fmt, ...) +{ + Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); + if (log) + { + va_list args; + va_start (args, fmt); + + char *logmsg; + if (vasprintf (&logmsg, fmt, args) == -1 || logmsg == NULL) + { + if (logmsg) + free (logmsg); + va_end (args); + return; + } + va_end (args); + + log->Printf ("%*sth%d/fr%u %s", + m_frame_number < 100 ? m_frame_number : 100, "", m_thread.GetIndexID(), m_frame_number, + logmsg); + free (logmsg); + } +} + +void +RegisterContextLLDB::UnwindLogMsgVerbose (const char *fmt, ...) +{ + Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); + if (log && log->GetVerbose()) + { + va_list args; + va_start (args, fmt); + + char *logmsg; + if (vasprintf (&logmsg, fmt, args) == -1 || logmsg == NULL) + { + if (logmsg) + free (logmsg); + va_end (args); + return; + } + va_end (args); + + log->Printf ("%*sth%d/fr%u %s", + m_frame_number < 100 ? m_frame_number : 100, "", m_thread.GetIndexID(), m_frame_number, + logmsg); + free (logmsg); + } +} + |