| //===-- 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 "RegisterContextLLDB.h" |
| #include "lldb/Target/Thread.h" |
| #include "lldb/Symbol/Function.h" |
| #include "lldb/Symbol/SymbolContext.h" |
| #include "lldb/Symbol/Symbol.h" |
| #include "lldb/Core/Address.h" |
| #include "lldb/Core/AddressRange.h" |
| #include "lldb/Target/Target.h" |
| #include "lldb/Target/Process.h" |
| #include "lldb/Utility/ArchDefaultUnwindPlan.h" |
| #include "lldb/Symbol/FuncUnwinders.h" |
| #include "lldb/Core/DataBufferHeap.h" |
| #include "lldb/Utility/ArchVolatileRegs.h" |
| #include "lldb/Core/Log.h" |
| #include "lldb/Expression/DWARFExpression.h" |
| #include "lldb/Core/Value.h" |
| #include "lldb/Target/ExecutionContext.h" |
| #include "lldb/Target/StackFrame.h" |
| |
| using namespace lldb; |
| using namespace lldb_private; |
| |
| |
| RegisterContextLLDB::RegisterContextLLDB |
| ( |
| Thread& thread, |
| const SharedPtr &next_frame, |
| SymbolContext& sym_ctx, |
| uint32_t frame_number |
| ) : |
| RegisterContext (thread, frame_number), |
| m_thread(thread), |
| m_next_frame(next_frame), |
| m_sym_ctx(sym_ctx), |
| m_all_registers_available(false), |
| m_registers(), |
| m_cfa (LLDB_INVALID_ADDRESS), |
| m_start_pc (), |
| m_current_pc (), |
| m_frame_number (frame_number), |
| m_full_unwind_plan_sp (), |
| m_fast_unwind_plan_sp (), |
| m_frame_type (-1), |
| m_current_offset (0), |
| m_current_offset_backed_up_one (0), |
| m_sym_ctx_valid (false) |
| { |
| m_sym_ctx.Clear(); |
| 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() |
| || m_next_frame->m_frame_type == eSigtrampFrame |
| || m_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() |
| { |
| StackFrameSP frame_sp (m_thread.GetStackFrameAtIndex (0)); |
| |
| if (m_thread.GetRegisterContext() == NULL) |
| { |
| m_frame_type = eNotAValidFrame; |
| return; |
| } |
| m_sym_ctx = frame_sp->GetSymbolContext (eSymbolContextFunction | eSymbolContextSymbol); |
| m_sym_ctx_valid = true; |
| AddressRange addr_range; |
| m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, addr_range); |
| |
| m_current_pc = frame_sp->GetFrameCodeAddress(); |
| |
| 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 (frame_sp->GetFrameCodeAddress().GetSection() == m_start_pc.GetSection()) |
| { |
| m_current_offset = frame_sp->GetFrameCodeAddress().GetOffset() - m_start_pc.GetOffset(); |
| } |
| else if (frame_sp->GetFrameCodeAddress().GetModule() == m_start_pc.GetModule()) |
| { |
| // This means that whatever symbol we kicked up isn't really correct |
| // as no should 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 = frame_sp->GetFrameCodeAddress().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 (); |
| |
| const UnwindPlan::Row *active_row = NULL; |
| int cfa_offset = 0; |
| int row_register_kind; |
| 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 == NULL) |
| { |
| m_frame_type = eNotAValidFrame; |
| return; |
| } |
| |
| addr_t cfa_regval; |
| if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval)) |
| { |
| m_frame_type = eNotAValidFrame; |
| return; |
| } |
| else |
| { |
| } |
| cfa_offset = active_row->GetCFAOffset (); |
| |
| m_cfa = cfa_regval + cfa_offset; |
| |
| LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); |
| |
| // A couple of sanity checks.. |
| if (cfa_regval == LLDB_INVALID_ADDRESS || cfa_regval == 0 || cfa_regval == 1) |
| { |
| if (log) |
| { |
| log->Printf("%*sFrame %u could not find a valid cfa address", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number); |
| } |
| m_frame_type = eNotAValidFrame; |
| return; |
| } |
| |
| if (log) |
| { |
| log->Printf("%*sThread %d Frame %u initialized frame current pc is 0x%llx cfa is 0x%llx using %s UnwindPlan", |
| m_frame_number < 100 ? m_frame_number : 100, "", |
| m_thread.GetIndexID(), |
| m_frame_number, |
| (uint64_t) m_current_pc.GetLoadAddress (&m_thread.GetProcess().GetTarget()), |
| (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() |
| { |
| LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); |
| if (IsFrameZero ()) |
| { |
| m_frame_type = eNotAValidFrame; |
| return; |
| } |
| |
| if (!m_next_frame->IsValid()) |
| { |
| m_frame_type = eNotAValidFrame; |
| return; |
| } |
| if (m_thread.GetRegisterContext() == NULL) |
| { |
| m_frame_type = eNotAValidFrame; |
| return; |
| } |
| |
| addr_t pc; |
| if (!ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc)) |
| { |
| if (log) |
| { |
| log->Printf("%*sFrame %u could not get pc value", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number); |
| } |
| m_frame_type = eNotAValidFrame; |
| return; |
| } |
| // A pc value of 0 up on the stack indicates we've hit the end of the stack |
| if (pc == 0) |
| { |
| m_frame_type = eNotAValidFrame; |
| return; |
| } |
| m_thread.GetProcess().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. |
| if (!m_current_pc.IsValid() || m_current_pc.GetModule() == NULL) |
| { |
| if (log) |
| { |
| log->Printf("%*sFrame %u using architectural default unwind method", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number); |
| } |
| const ArchSpec &arch = m_thread.GetProcess().GetTarget().GetArchitecture (); |
| ArchDefaultUnwindPlanSP arch_default_sp (ArchDefaultUnwindPlan::FindPlugin (arch)); |
| if (arch_default_sp) |
| { |
| m_fast_unwind_plan_sp.reset(); |
| m_full_unwind_plan_sp = arch_default_sp->GetArchDefaultUnwindPlan (m_thread, m_current_pc); |
| m_frame_type = eNormalFrame; |
| m_all_registers_available = false; |
| m_current_offset = -1; |
| m_current_offset_backed_up_one = -1; |
| addr_t cfa_regval; |
| int row_register_kind = m_full_unwind_plan_sp->GetRegisterKind (); |
| uint32_t cfa_regnum = m_full_unwind_plan_sp->GetRowForFunctionOffset(0)->GetCFARegister(); |
| int cfa_offset = m_full_unwind_plan_sp->GetRowForFunctionOffset(0)->GetCFAOffset(); |
| if (!ReadGPRValue (row_register_kind, cfa_regnum, cfa_regval)) |
| { |
| if (log) |
| { |
| log->Printf("%*sFrame %u failed to get cfa value", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number); |
| } |
| 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) |
| { |
| if (log) |
| { |
| log->Printf("%*sFrame %u could not find a valid cfa address", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number); |
| } |
| m_frame_type = eNotAValidFrame; |
| return; |
| } |
| |
| if (log) |
| { |
| log->Printf("%*sFrame %u initialized frame cfa is 0x%llx", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, |
| (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 ((m_current_pc.GetModule()->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, 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 |
| && m_next_frame->m_frame_type != eSigtrampFrame |
| && m_next_frame->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(); |
| m_sym_ctx_valid = false; |
| if ((m_current_pc.GetModule()->ResolveSymbolContextForAddress (temporary_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol) |
| { |
| m_sym_ctx_valid = true; |
| } |
| if (!m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 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--; |
| } |
| 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. |
| m_frame_type = eNormalFrame; |
| } |
| |
| // We've set m_frame_type and m_sym_ctx before this call. |
| m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame (); |
| |
| const UnwindPlan::Row *active_row = NULL; |
| int cfa_offset = 0; |
| int row_register_kind; |
| |
| // 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 (); |
| } |
| 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 == NULL) |
| { |
| m_frame_type = eNotAValidFrame; |
| return; |
| } |
| |
| addr_t cfa_regval; |
| if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval)) |
| { |
| if (log) |
| { |
| log->Printf("%*sFrame %u failed to get cfa reg %d/%d", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, |
| row_register_kind, active_row->GetCFARegister()); |
| } |
| m_frame_type = eNotAValidFrame; |
| return; |
| } |
| cfa_offset = active_row->GetCFAOffset (); |
| |
| m_cfa = cfa_regval + cfa_offset; |
| |
| // A couple of sanity checks.. |
| if (cfa_regval == LLDB_INVALID_ADDRESS || cfa_regval == 0 || cfa_regval == 1) |
| { |
| if (log) |
| { |
| log->Printf("%*sFrame %u could not find a valid cfa address", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number); |
| } |
| m_frame_type = eNotAValidFrame; |
| return; |
| } |
| |
| if (log) |
| { |
| log->Printf("%*sFrame %u initialized frame current pc is 0x%llx cfa is 0x%llx", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, |
| (uint64_t) m_current_pc.GetLoadAddress (&m_thread.GetProcess().GetTarget()), (uint64_t) m_cfa); |
| } |
| } |
| |
| |
| bool |
| RegisterContextLLDB::IsFrameZero () const |
| { |
| if (m_next_frame.get () == NULL) |
| return true; |
| else |
| 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 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; |
| if (!m_current_pc.IsValid() || m_current_pc.GetModule() == NULL || m_current_pc.GetModule()->GetObjectFile() == NULL) |
| return unwind_plan_sp; |
| |
| if (IsFrameZero ()) |
| return unwind_plan_sp; |
| |
| FuncUnwindersSP func_unwinders_sp (m_current_pc.GetModule()->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)) |
| { |
| LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); |
| if (log && IsLogVerbose()) |
| { |
| const char *has_fast = ""; |
| if (m_fast_unwind_plan_sp) |
| has_fast = ", and has a fast UnwindPlan"; |
| log->Printf("%*sFrame %u frame has a fast UnwindPlan", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number); |
| } |
| 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; |
| LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); |
| UnwindPlanSP arch_default_unwind_plan_sp; |
| const ArchSpec &arch = m_thread.GetProcess().GetTarget().GetArchitecture (); |
| ArchDefaultUnwindPlanSP arch_default_sp (ArchDefaultUnwindPlan::FindPlugin (arch)); |
| if (arch_default_sp) |
| arch_default_unwind_plan_sp = arch_default_sp->GetArchDefaultUnwindPlan (m_thread, m_current_pc); |
| |
| bool behaves_like_zeroth_frame = false; |
| if (IsFrameZero () |
| || m_next_frame->m_frame_type == eSigtrampFrame |
| || m_next_frame->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; |
| } |
| |
| // No Module for the current pc, try using the architecture default unwind. |
| if (!m_current_pc.IsValid() || m_current_pc.GetModule() == NULL || m_current_pc.GetModule()->GetObjectFile() == NULL) |
| { |
| m_frame_type = eNormalFrame; |
| return arch_default_unwind_plan_sp; |
| } |
| |
| FuncUnwindersSP func_unwinders_sp; |
| if (m_sym_ctx_valid) |
| { |
| func_unwinders_sp = m_current_pc.GetModule()->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx); |
| } |
| |
| // No FuncUnwinders available for this pc, try using architectural default unwind. |
| if (!func_unwinders_sp) |
| { |
| m_frame_type = eNormalFrame; |
| 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; |
| } |
| |
| |
| // 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)) |
| { |
| if (log && IsLogVerbose()) |
| { |
| log->Printf("%*sFrame %u frame uses %s for full UnwindPlan", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, |
| 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)) |
| { |
| if (log && IsLogVerbose()) |
| { |
| log->Printf("%*sFrame %u frame uses %s for full UnwindPlan", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, |
| 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)) |
| { |
| if (log && IsLogVerbose()) |
| { |
| log->Printf("%*sFrame %u frame uses %s for full UnwindPlan", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, |
| unwind_plan_sp->GetSourceName().GetCString()); |
| } |
| return unwind_plan_sp; |
| } |
| |
| // If nothing else, use the architectural default UnwindPlan and hope that does the job. |
| if (log && IsLogVerbose()) |
| { |
| log->Printf("%*sFrame %u frame uses %s for full UnwindPlan", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, |
| 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 (uint32_t reg) |
| { |
| return m_thread.GetRegisterContext()->GetRegisterInfoAtIndex (reg); |
| } |
| |
| size_t |
| RegisterContextLLDB::GetRegisterSetCount () |
| { |
| return m_thread.GetRegisterContext()->GetRegisterSetCount (); |
| } |
| |
| const RegisterSet * |
| RegisterContextLLDB::GetRegisterSet (uint32_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::ReadRegisterBytesFromRegisterLocation (uint32_t regnum, RegisterLocation regloc, DataExtractor &data) |
| { |
| if (!IsValid()) |
| return false; |
| |
| if (regloc.type == eRegisterInRegister) |
| { |
| data.SetAddressByteSize (m_thread.GetProcess().GetAddressByteSize()); |
| data.SetByteOrder (m_thread.GetProcess().GetByteOrder()); |
| if (IsFrameZero ()) |
| { |
| return m_thread.GetRegisterContext()->ReadRegisterBytes (regloc.location.register_number, data); |
| } |
| else |
| { |
| return m_next_frame->ReadRegisterBytes (regloc.location.register_number, data); |
| } |
| } |
| if (regloc.type == eRegisterNotSaved) |
| { |
| return false; |
| } |
| if (regloc.type == eRegisterSavedAtHostMemoryLocation) |
| { |
| assert ("FIXME debugger inferior function call unwind"); |
| } |
| if (regloc.type != eRegisterSavedAtMemoryLocation) |
| { |
| assert ("Unknown RegisterLocation type."); |
| } |
| |
| const RegisterInfo *reg_info = m_thread.GetRegisterContext()->GetRegisterInfoAtIndex (regnum); |
| DataBufferSP data_sp (new DataBufferHeap (reg_info->byte_size, 0)); |
| data.SetData (data_sp, 0, reg_info->byte_size); |
| data.SetAddressByteSize (m_thread.GetProcess().GetAddressByteSize()); |
| |
| if (regloc.type == eRegisterValueInferred) |
| { |
| data.SetByteOrder (lldb::endian::InlHostByteOrder()); |
| switch (reg_info->byte_size) |
| { |
| case 1: |
| { |
| uint8_t val = regloc.location.register_value; |
| memcpy (data_sp->GetBytes(), &val, sizeof (val)); |
| data.SetByteOrder (lldb::endian::InlHostByteOrder()); |
| return true; |
| } |
| case 2: |
| { |
| uint16_t val = regloc.location.register_value; |
| memcpy (data_sp->GetBytes(), &val, sizeof (val)); |
| data.SetByteOrder (lldb::endian::InlHostByteOrder()); |
| return true; |
| } |
| case 4: |
| { |
| uint32_t val = regloc.location.register_value; |
| memcpy (data_sp->GetBytes(), &val, sizeof (val)); |
| data.SetByteOrder (lldb::endian::InlHostByteOrder()); |
| return true; |
| } |
| case 8: |
| { |
| uint64_t val = regloc.location.register_value; |
| memcpy (data_sp->GetBytes(), &val, sizeof (val)); |
| data.SetByteOrder (lldb::endian::InlHostByteOrder()); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| assert (regloc.type == eRegisterSavedAtMemoryLocation); |
| Error error; |
| data.SetByteOrder (m_thread.GetProcess().GetByteOrder()); |
| if (!m_thread.GetProcess().ReadMemory (regloc.location.target_memory_location, data_sp->GetBytes(), reg_info->byte_size, error)) |
| return false; |
| return true; |
| } |
| |
| bool |
| RegisterContextLLDB::WriteRegisterBytesToRegisterLocation (uint32_t regnum, RegisterLocation regloc, DataExtractor &data, uint32_t data_offset) |
| { |
| if (!IsValid()) |
| return false; |
| |
| if (regloc.type == eRegisterInRegister) |
| { |
| if (IsFrameZero ()) |
| { |
| return m_thread.GetRegisterContext()->WriteRegisterBytes (regloc.location.register_number, data, data_offset); |
| } |
| else |
| { |
| return m_next_frame->WriteRegisterBytes (regloc.location.register_number, data, data_offset); |
| } |
| } |
| if (regloc.type == eRegisterNotSaved) |
| { |
| return false; |
| } |
| if (regloc.type == eRegisterValueInferred) |
| { |
| return false; |
| } |
| if (regloc.type == eRegisterSavedAtHostMemoryLocation) |
| { |
| assert ("FIXME debugger inferior function call unwind"); |
| } |
| if (regloc.type != eRegisterSavedAtMemoryLocation) |
| { |
| assert ("Unknown RegisterLocation type."); |
| } |
| |
| Error error; |
| const RegisterInfo *reg_info = m_thread.GetRegisterContext()->GetRegisterInfoAtIndex (regnum); |
| if (reg_info->byte_size == 0) |
| return false; |
| uint8_t *buf = (uint8_t*) alloca (reg_info->byte_size); |
| if (data.ExtractBytes (data_offset, reg_info->byte_size, m_thread.GetProcess().GetByteOrder(), buf) != reg_info->byte_size) |
| return false; |
| if (m_thread.GetProcess().WriteMemory (regloc.location.target_memory_location, buf, reg_info->byte_size, error) != reg_info->byte_size) |
| return false; |
| |
| return true; |
| } |
| |
| |
| bool |
| RegisterContextLLDB::IsValid () const |
| { |
| return m_frame_type != eNotAValidFrame; |
| } |
| |
| // Answer the question: Where did THIS frame save the CALLER frame ("previous" frame)'s register value? |
| |
| bool |
| RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, RegisterLocation ®loc) |
| { |
| LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); |
| |
| // Have we already found this register location? |
| if (!m_registers.empty()) |
| { |
| std::map<uint32_t, RegisterLocation>::const_iterator iterator; |
| iterator = m_registers.find (lldb_regnum); |
| if (iterator != m_registers.end()) |
| { |
| regloc = iterator->second; |
| return true; |
| } |
| } |
| |
| // 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. |
| uint32_t sp_regnum; |
| if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, eRegisterKindLLDB, sp_regnum) |
| && sp_regnum == lldb_regnum) |
| { |
| // make sure we won't lose precision copying an addr_t (m_cfa) into a uint64_t (.register_value) |
| assert (sizeof (addr_t) <= sizeof (uint64_t)); |
| regloc.type = eRegisterValueInferred; |
| regloc.location.register_value = m_cfa; |
| m_registers[lldb_regnum] = regloc; |
| return true; |
| } |
| |
| // Look through the available UnwindPlans for the register location. |
| |
| UnwindPlan::Row::RegisterLocation unwindplan_regloc; |
| bool have_unwindplan_regloc = false; |
| int unwindplan_registerkind = -1; |
| |
| if (m_fast_unwind_plan_sp) |
| { |
| const UnwindPlan::Row *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)) |
| { |
| if (log) |
| { |
| log->Printf("%*sFrame %u could not convert lldb regnum %d into %d RegisterKind reg numbering scheme", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, |
| lldb_regnum, (int) unwindplan_registerkind); |
| } |
| return false; |
| } |
| if (active_row->GetRegisterInfo (row_regnum, unwindplan_regloc)) |
| { |
| if (log) |
| { |
| log->Printf("%*sFrame %u supplying caller's saved reg %d's location using FastUnwindPlan", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, |
| 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) |
| { |
| const UnwindPlan::Row *active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); |
| unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind (); |
| uint32_t row_regnum; |
| if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindLLDB, lldb_regnum, unwindplan_registerkind, row_regnum)) |
| { |
| if (log) |
| { |
| if (unwindplan_registerkind == eRegisterKindGeneric) |
| log->Printf("%*sFrame %u could not convert lldb regnum %d into eRegisterKindGeneric reg numbering scheme", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, |
| lldb_regnum); |
| else |
| log->Printf("%*sFrame %u could not convert lldb regnum %d into %d RegisterKind reg numbering scheme", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, |
| lldb_regnum, (int) unwindplan_registerkind); |
| } |
| return false; |
| } |
| |
| if (active_row->GetRegisterInfo (row_regnum, unwindplan_regloc)) |
| { |
| have_unwindplan_regloc = true; |
| if (log && IsLogVerbose ()) |
| { |
| log->Printf("%*sFrame %u supplying caller's saved reg %d's location using %s UnwindPlan", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, |
| lldb_regnum, m_full_unwind_plan_sp->GetSourceName().GetCString()); |
| } |
| } |
| } |
| } |
| |
| if (have_unwindplan_regloc == false) |
| { |
| // If a volatile register is being requested, we don't want to forward m_next_frame's register contents |
| // up the stack -- the register is not retrievable at this frame. |
| const ArchSpec &arch = m_thread.GetProcess().GetTarget().GetArchitecture (); |
| ArchVolatileRegs *volatile_regs = ArchVolatileRegs::FindPlugin (arch); |
| if (volatile_regs && volatile_regs->RegisterIsVolatile (m_thread, lldb_regnum)) |
| { |
| if (log) |
| { |
| log->Printf("%*sFrame %u did not supply reg location for %d because it is volatile", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, |
| lldb_regnum); |
| } |
| return false; |
| } |
| |
| if (IsFrameZero ()) |
| { |
| // This is frame 0 - we should return the actual live register context value |
| RegisterLocation new_regloc; |
| new_regloc.type = eRegisterInRegister; |
| new_regloc.location.register_number = lldb_regnum; |
| m_registers[lldb_regnum] = new_regloc; |
| regloc = new_regloc; |
| return true; |
| } |
| else |
| { |
| return m_next_frame->SavedLocationForRegister (lldb_regnum, regloc); |
| } |
| if (log) |
| { |
| log->Printf("%*sFrame %u could not supply caller's reg %d location", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, |
| lldb_regnum); |
| } |
| return false; |
| } |
| |
| // unwindplan_regloc has valid contents about where to retrieve the register |
| if (unwindplan_regloc.IsUnspecified()) |
| { |
| RegisterLocation new_regloc; |
| new_regloc.type = eRegisterNotSaved; |
| m_registers[lldb_regnum] = new_regloc; |
| if (log) |
| { |
| log->Printf("%*sFrame %u could not supply caller's reg %d location", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, |
| lldb_regnum); |
| } |
| return false; |
| } |
| |
| if (unwindplan_regloc.IsSame()) |
| { |
| if (IsFrameZero ()) |
| { |
| if (log) |
| { |
| log->Printf("%*sFrame %u could not supply caller's reg %d location", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, |
| lldb_regnum); |
| } |
| return false; |
| } |
| else |
| { |
| return m_next_frame->SavedLocationForRegister (lldb_regnum, regloc); |
| } |
| } |
| |
| if (unwindplan_regloc.IsCFAPlusOffset()) |
| { |
| int offset = unwindplan_regloc.GetOffset(); |
| regloc.type = eRegisterValueInferred; |
| regloc.location.register_value = m_cfa + offset; |
| m_registers[lldb_regnum] = regloc; |
| return true; |
| } |
| |
| if (unwindplan_regloc.IsAtCFAPlusOffset()) |
| { |
| int offset = unwindplan_regloc.GetOffset(); |
| regloc.type = eRegisterSavedAtMemoryLocation; |
| regloc.location.target_memory_location = m_cfa + offset; |
| m_registers[lldb_regnum] = regloc; |
| return true; |
| } |
| |
| 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)) |
| { |
| if (log) |
| { |
| log->Printf("%*sFrame %u could not supply caller's reg %d location", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, |
| lldb_regnum); |
| } |
| return false; |
| } |
| regloc.type = eRegisterInRegister; |
| regloc.location.register_number = row_regnum_in_lldb; |
| m_registers[lldb_regnum] = regloc; |
| return true; |
| } |
| |
| if (unwindplan_regloc.IsDWARFExpression() || unwindplan_regloc.IsAtDWARFExpression()) |
| { |
| DataExtractor dwarfdata (unwindplan_regloc.GetDWARFExpressionBytes(), |
| unwindplan_regloc.GetDWARFExpressionLength(), |
| m_thread.GetProcess().GetByteOrder(), m_thread.GetProcess().GetAddressByteSize()); |
| DWARFExpression dwarfexpr (dwarfdata, 0, unwindplan_regloc.GetDWARFExpressionLength()); |
| dwarfexpr.SetRegisterKind (unwindplan_registerkind); |
| ExecutionContext exe_ctx (&m_thread.GetProcess(), &m_thread, NULL); |
| Value result; |
| Error error; |
| if (dwarfexpr.Evaluate (&exe_ctx, NULL, NULL, NULL, this, 0, NULL, result, &error)) |
| { |
| addr_t val; |
| val = result.GetScalar().ULongLong(); |
| if (unwindplan_regloc.IsDWARFExpression()) |
| { |
| regloc.type = eRegisterValueInferred; |
| regloc.location.register_value = val; |
| m_registers[lldb_regnum] = regloc; |
| return true; |
| } |
| else |
| { |
| regloc.type = eRegisterSavedAtMemoryLocation; |
| regloc.location.target_memory_location = val; |
| m_registers[lldb_regnum] = regloc; |
| return true; |
| } |
| } |
| if (log) |
| { |
| log->Printf("%*sFrame %u tried to use IsDWARFExpression or IsAtDWARFExpression for reg %d but failed", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, |
| lldb_regnum); |
| } |
| return false; |
| } |
| |
| if (log) |
| { |
| log->Printf("%*sFrame %u could not supply caller's reg %d location", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, |
| lldb_regnum); |
| } |
| |
| |
| // assert ("UnwindPlan::Row types atDWARFExpression and isDWARFExpression are unsupported."); |
| return false; |
| } |
| |
| // Retrieve a general purpose register value for THIS from, 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; |
| } |
| |
| uint32_t offset = 0; |
| DataExtractor data; |
| data.SetAddressByteSize (m_thread.GetProcess().GetAddressByteSize()); |
| data.SetByteOrder (m_thread.GetProcess().GetByteOrder()); |
| |
| // if this is frame 0 (currently executing frame), get the requested reg contents from the actual thread registers |
| if (IsFrameZero ()) |
| { |
| if (m_thread.GetRegisterContext()->ReadRegisterBytes (lldb_regnum, data)) |
| { |
| data.SetAddressByteSize (m_thread.GetProcess().GetAddressByteSize()); |
| value = data.GetAddress (&offset); |
| return true; |
| } |
| return false; |
| } |
| |
| RegisterLocation regloc; |
| if (!m_next_frame->SavedLocationForRegister (lldb_regnum, regloc)) |
| { |
| return false; |
| } |
| if (!ReadRegisterBytesFromRegisterLocation (lldb_regnum, regloc, data)) |
| { |
| return false; |
| } |
| data.SetAddressByteSize (m_thread.GetProcess().GetAddressByteSize()); |
| value = data.GetAddress (&offset); |
| return true; |
| } |
| |
| // Find the value of a register in THIS frame |
| |
| bool |
| RegisterContextLLDB::ReadRegisterBytes (uint32_t lldb_reg, DataExtractor& data) |
| { |
| LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); |
| if (!IsValid()) |
| return false; |
| |
| if (log && IsLogVerbose ()) |
| { |
| log->Printf("%*sFrame %u looking for register saved location for reg %d", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, |
| lldb_reg); |
| } |
| |
| // If this is the 0th frame, hand this over to the live register context |
| if (IsFrameZero ()) |
| { |
| if (log) |
| { |
| log->Printf("%*sFrame %u passing along to the live register context for reg %d", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, |
| lldb_reg); |
| } |
| return m_thread.GetRegisterContext()->ReadRegisterBytes (lldb_reg, data); |
| } |
| |
| RegisterLocation regloc; |
| // Find out where the NEXT frame saved THIS frame's register contents |
| if (!m_next_frame->SavedLocationForRegister (lldb_reg, regloc)) |
| return false; |
| |
| return ReadRegisterBytesFromRegisterLocation (lldb_reg, regloc, data); |
| } |
| |
| bool |
| RegisterContextLLDB::WriteRegisterBytes (uint32_t lldb_reg, DataExtractor &data, uint32_t data_offset) |
| { |
| LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); |
| if (!IsValid()) |
| return false; |
| |
| if (log && IsLogVerbose ()) |
| { |
| log->Printf("%*sFrame %u looking for register saved location for reg %d", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, |
| lldb_reg); |
| } |
| |
| // If this is the 0th frame, hand this over to the live register context |
| if (IsFrameZero ()) |
| { |
| if (log) |
| { |
| log->Printf("%*sFrame %u passing along to the live register context for reg %d", |
| m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, |
| lldb_reg); |
| } |
| return m_thread.GetRegisterContext()->WriteRegisterBytes (lldb_reg, data, data_offset); |
| } |
| |
| RegisterLocation regloc; |
| // Find out where the NEXT frame saved THIS frame's register contents |
| if (!m_next_frame->SavedLocationForRegister (lldb_reg, regloc)) |
| return false; |
| |
| return WriteRegisterBytesToRegisterLocation (lldb_reg, regloc, data, data_offset); |
| } |
| |
| // 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; |
| } |
| |
| // 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 (&m_thread.GetProcess().GetTarget()); |
| 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; |
| } |
| } |