//===-- 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_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_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, 0, false, 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, 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 && 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, 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--; } 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::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; } }