diff options
-rw-r--r-- | lldb/include/lldb/Symbol/UnwindPlan.h | 42 | ||||
-rw-r--r-- | lldb/include/lldb/Target/RegisterContext.h | 19 | ||||
-rw-r--r-- | lldb/include/lldb/lldb-private-log.h | 1 | ||||
-rw-r--r-- | lldb/lldb.xcodeproj/project.pbxproj | 16 | ||||
-rw-r--r-- | lldb/source/Plugins/Process/Utility/ArchDefaultUnwindPlan-x86.cpp | 2 | ||||
-rw-r--r-- | lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp | 986 | ||||
-rw-r--r-- | lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h | 177 | ||||
-rw-r--r-- | lldb/source/Plugins/Process/Utility/UnwindAssemblyProfiler-x86.cpp | 87 | ||||
-rw-r--r-- | lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp | 141 | ||||
-rw-r--r-- | lldb/source/Plugins/Process/Utility/UnwindLLDB.h | 70 | ||||
-rw-r--r-- | lldb/source/Symbol/DWARFCallFrameInfo.cpp | 7 | ||||
-rw-r--r-- | lldb/source/Symbol/FuncUnwinders.cpp | 20 | ||||
-rw-r--r-- | lldb/source/Symbol/UnwindPlan.cpp | 41 | ||||
-rw-r--r-- | lldb/source/Target/RegisterContext.cpp | 135 | ||||
-rw-r--r-- | lldb/source/lldb-log.cpp | 2 | ||||
-rw-r--r-- | lldb/source/lldb.cpp | 2 |
16 files changed, 1714 insertions, 34 deletions
diff --git a/lldb/include/lldb/Symbol/UnwindPlan.h b/lldb/include/lldb/Symbol/UnwindPlan.h index 49356cd1e23..e6b19477934 100644 --- a/lldb/include/lldb/Symbol/UnwindPlan.h +++ b/lldb/include/lldb/Symbol/UnwindPlan.h @@ -4,6 +4,7 @@ #include "lldb/lldb-private.h" #include "lldb/Core/AddressRange.h" #include "lldb/Core/Stream.h" +#include "lldb/Core/ConstString.h" #include <map> #include <vector> @@ -69,18 +70,32 @@ public: void SetSame(); + bool IsSame () const { return m_type == isSame; } + + bool IsUnspecified () const { return m_type == unspecified; } + + bool IsCFAPlusOffset () const { return m_type == isCFAPlusOffset; } + + bool IsAtCFAPlusOffset () const { return m_type == atCFAPlusOffset; } + + bool IsInOtherRegister () const { return m_type == inOtherRegister; } + + bool IsAtDWARFExpression () const { return m_type == atDWARFExpression; } + + bool IsDWARFExpression () const { return m_type == isDWARFExpression; } + void SetAtCFAPlusOffset (int32_t offset); void SetIsCFAPlusOffset (int32_t offset); void SetInRegister (uint32_t reg_num); + uint32_t GetRegisterNumber () const { return m_location.reg_num; } + RestoreType GetLocationType () const { return m_type; } int32_t GetOffset () const { return m_location.offset; } - uint32_t GetRegNum () const { return m_location.reg_num; } - void GetDWARFExpr (const uint8_t **opcodes, uint16_t& len) const { *opcodes = m_location.expr.opcodes; len = m_location.expr.length; } void @@ -159,6 +174,13 @@ public: m_cfa_offset = offset; } + // Return the number of registers we have locations for + int + GetRegisterCount () const + { + return m_register_locations.size(); + } + void Clear (); @@ -176,13 +198,20 @@ public: public: - UnwindPlan () : m_register_kind(-1), m_row_list(), m_plan_valid_address_range() { } + UnwindPlan () : m_register_kind(-1), m_row_list(), m_plan_valid_address_range(), m_source_name() + { + m_plan_valid_address_range.SetByteSize (0); + } void Dump (Stream& s, Thread* thread) const; void AppendRow (const Row& row); + // Returns a pointer to the best row for the given offset into the function's instructions. + // If offset is -1 it indicates that the function start is unknown - the final row in the UnwindPlan is returned. + // In practice, the UnwindPlan for a function with no known start address will be the architectural default + // UnwindPlan which will only have one row. const Row* GetRowForFunctionOffset (int offset) const; @@ -207,6 +236,12 @@ public: const UnwindPlan::Row& GetRowAtIndex (uint32_t idx) const; + lldb_private::ConstString + GetSourceName () const; + + void + SetSourceName (const char *); + int GetRowCount () const; @@ -217,6 +252,7 @@ private: AddressRange m_plan_valid_address_range; uint32_t m_register_kind; // The RegisterKind these register numbers are in terms of - will need to be // translated to lldb native reg nums at unwind time + lldb_private::ConstString m_source_name; // for logging, where this UnwindPlan originated from }; // class UnwindPlan } // namespace lldb_private diff --git a/lldb/include/lldb/Target/RegisterContext.h b/lldb/include/lldb/Target/RegisterContext.h index 5c313c5fa47..c06c88d1477 100644 --- a/lldb/include/lldb/Target/RegisterContext.h +++ b/lldb/include/lldb/Target/RegisterContext.h @@ -28,6 +28,8 @@ public: //------------------------------------------------------------------ RegisterContext (Thread &thread, StackFrame *frame); + RegisterContext (Thread &thread); + virtual ~RegisterContext (); @@ -50,18 +52,12 @@ public: GetRegisterSet (uint32_t reg_set) = 0; virtual bool - ReadRegisterValue (uint32_t reg, Scalar &value) = 0; - - virtual bool ReadRegisterBytes (uint32_t reg, DataExtractor &data) = 0; virtual bool ReadAllRegisterValues (lldb::DataBufferSP &data_sp) = 0; virtual bool - WriteRegisterValue (uint32_t reg, const Scalar &value) = 0; - - virtual bool WriteRegisterBytes (uint32_t reg, DataExtractor &data, uint32_t data_offset = 0) = 0; virtual bool @@ -73,6 +69,12 @@ public: //------------------------------------------------------------------ // Subclasses can override these functions if desired //------------------------------------------------------------------ + virtual bool + ReadRegisterValue (uint32_t reg, Scalar &value); + + virtual bool + WriteRegisterValue (uint32_t reg, const Scalar &value); + virtual uint32_t NumSupportedHardwareBreakpoints (); @@ -143,7 +145,10 @@ public: WriteRegisterFromUnsigned (uint32_t reg, uint64_t uval); bool - ConvertBetweenRegisterKinds (int source_rk, uint32_t source_regnum, int target_rk, uint32_t target_regnum); + ConvertBetweenRegisterKinds (int source_rk, uint32_t source_regnum, int target_rk, uint32_t& target_regnum); + + void + SetStackFrame (StackFrame *frame); //------------------------------------------------------------------ // lldb::ExecutionContextScope pure virtual functions diff --git a/lldb/include/lldb/lldb-private-log.h b/lldb/include/lldb/lldb-private-log.h index c03da5a26b5..ebdefd4ded9 100644 --- a/lldb/include/lldb/lldb-private-log.h +++ b/lldb/include/lldb/lldb-private-log.h @@ -34,6 +34,7 @@ #define LIBLLDB_LOG_COMMUNICATION (1u << 12) #define LIBLLDB_LOG_CONNECTION (1u << 13) #define LIBLLDB_LOG_HOST (1u << 14) +#define LIBLLDB_LOG_UNWIND (1u << 15) #define LIBLLDB_LOG_ALL (UINT32_MAX) #define LIBLLDB_LOG_DEFAULT (LIBLLDB_LOG_PROCESS |\ LIBLLDB_LOG_THREAD |\ diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index 101964e3097..8d6d4f32493 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -406,6 +406,10 @@ 9AC70390117675270086C050 /* SBInstructionList.h in Headers */ = {isa = PBXBuildFile; fileRef = 9AC7038F117675270086C050 /* SBInstructionList.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9AC703AF117675410086C050 /* SBInstruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AC703AE117675410086C050 /* SBInstruction.cpp */; }; 9AC703B1117675490086C050 /* SBInstructionList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AC703B0117675490086C050 /* SBInstructionList.cpp */; }; + AF68D2561255416E002FF25B /* RegisterContextLLDB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF68D2541255416E002FF25B /* RegisterContextLLDB.cpp */; }; + AF68D2571255416E002FF25B /* RegisterContextLLDB.h in Headers */ = {isa = PBXBuildFile; fileRef = AF68D2551255416E002FF25B /* RegisterContextLLDB.h */; }; + AF68D3311255A111002FF25B /* UnwindLLDB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF68D32F1255A110002FF25B /* UnwindLLDB.cpp */; }; + AF68D3321255A111002FF25B /* UnwindLLDB.h in Headers */ = {isa = PBXBuildFile; fileRef = AF68D3301255A110002FF25B /* UnwindLLDB.h */; }; AF94005911C03F6500085DB9 /* SymbolVendor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF94005711C03F6500085DB9 /* SymbolVendor.cpp */; }; /* End PBXBuildFile section */ @@ -1130,6 +1134,10 @@ 9AF16A9E11402D69007A7B3F /* SBBreakpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBBreakpoint.h; path = include/lldb/API/SBBreakpoint.h; sourceTree = "<group>"; }; 9AF16CC611408686007A7B3F /* SBBreakpointLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBBreakpointLocation.h; path = include/lldb/API/SBBreakpointLocation.h; sourceTree = "<group>"; }; 9AF16CC7114086A1007A7B3F /* SBBreakpointLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBBreakpointLocation.cpp; path = source/API/SBBreakpointLocation.cpp; sourceTree = "<group>"; }; + AF68D2541255416E002FF25B /* RegisterContextLLDB.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RegisterContextLLDB.cpp; path = Utility/RegisterContextLLDB.cpp; sourceTree = "<group>"; }; + AF68D2551255416E002FF25B /* RegisterContextLLDB.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterContextLLDB.h; path = Utility/RegisterContextLLDB.h; sourceTree = "<group>"; }; + AF68D32F1255A110002FF25B /* UnwindLLDB.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UnwindLLDB.cpp; path = Utility/UnwindLLDB.cpp; sourceTree = "<group>"; }; + AF68D3301255A110002FF25B /* UnwindLLDB.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UnwindLLDB.h; path = Utility/UnwindLLDB.h; sourceTree = "<group>"; }; AF94005711C03F6500085DB9 /* SymbolVendor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SymbolVendor.cpp; path = source/Symbol/SymbolVendor.cpp; sourceTree = "<group>"; }; /* End PBXFileReference section */ @@ -1646,6 +1654,10 @@ 26B4666E11A2080F00CF6220 /* Utility */ = { isa = PBXGroup; children = ( + AF68D32F1255A110002FF25B /* UnwindLLDB.cpp */, + AF68D3301255A110002FF25B /* UnwindLLDB.h */, + AF68D2541255416E002FF25B /* RegisterContextLLDB.cpp */, + AF68D2551255416E002FF25B /* RegisterContextLLDB.h */, 96A6D9C71249D98800250B38 /* ArchVolatileRegs-x86.cpp */, 96A6D9C81249D98800250B38 /* ArchVolatileRegs-x86.h */, 961FAC1C12360C7D00F93A47 /* ArchDefaultUnwindPlan-x86.cpp */, @@ -2417,6 +2429,8 @@ 4C139EA6124A8B03000BFF8D /* AppleObjCRuntimeV2.h in Headers */, 4C0A91D912511CB900CA6636 /* AppleObjCTrampolineHandler.h in Headers */, 4C0A91DB12511CB900CA6636 /* AppleThreadPlanStepThroughObjCTrampoline.h in Headers */, + AF68D2571255416E002FF25B /* RegisterContextLLDB.h in Headers */, + AF68D3321255A111002FF25B /* UnwindLLDB.h in Headers */, 26424E3F125986D30016D82C /* ValueObjectConstResult.h in Headers */, 4C1AB23F1263E61100D0F04A /* ThreadPlanTestCondition.h in Headers */, ); @@ -2917,6 +2931,8 @@ 4C139EA5124A8B03000BFF8D /* AppleObjCRuntimeV2.cpp in Sources */, 4C0A91D812511CB900CA6636 /* AppleObjCTrampolineHandler.cpp in Sources */, 4C0A91DA12511CB900CA6636 /* AppleThreadPlanStepThroughObjCTrampoline.cpp in Sources */, + AF68D2561255416E002FF25B /* RegisterContextLLDB.cpp in Sources */, + AF68D3311255A111002FF25B /* UnwindLLDB.cpp in Sources */, 26424E3D125986CB0016D82C /* ValueObjectConstResult.cpp in Sources */, 4C1AB23B1263E5F400D0F04A /* ThreadPlanTestCondition.cpp in Sources */, ); diff --git a/lldb/source/Plugins/Process/Utility/ArchDefaultUnwindPlan-x86.cpp b/lldb/source/Plugins/Process/Utility/ArchDefaultUnwindPlan-x86.cpp index 1a4f18b67c7..289429d0c25 100644 --- a/lldb/source/Plugins/Process/Utility/ArchDefaultUnwindPlan-x86.cpp +++ b/lldb/source/Plugins/Process/Utility/ArchDefaultUnwindPlan-x86.cpp @@ -64,6 +64,7 @@ ArchDefaultUnwindPlan_x86::ArchDefaultUnwindPlan_x86(int cpu) : row.SetRegisterInfo (LLDB_REGNUM_GENERIC_SP, regloc); m_32bit_default.AppendRow (row); + m_32bit_default.SetSourceName ("architectural default"); row.Clear(); @@ -80,6 +81,7 @@ ArchDefaultUnwindPlan_x86::ArchDefaultUnwindPlan_x86(int cpu) : row.SetRegisterInfo (LLDB_REGNUM_GENERIC_SP, regloc); m_64bit_default.AppendRow (row); + m_64bit_default.SetSourceName ("architectural default"); } diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp new file mode 100644 index 00000000000..7a657926475 --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -0,0 +1,986 @@ +//===-- 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" + +using namespace lldb; +using namespace lldb_private; + + +RegisterContextLLDB::RegisterContextLLDB (Thread& thread, + const RegisterContextSP &next_frame, + SymbolContext& sym_ctx, + int frame_number) : + RegisterContext (thread), m_thread(thread), m_next_frame(next_frame), + m_zeroth_frame(false), m_sym_ctx(sym_ctx), m_all_registers_available(false), m_registers(), + m_cfa (LLDB_INVALID_ADDRESS), m_start_pc (), m_frame_number (frame_number) +{ + m_base_reg_ctx = m_thread.GetRegisterContext(); + if (m_next_frame.get() == NULL) + { + InitializeZerothFrame (); + } + else + { + InitializeNonZerothFrame (); + } +} + +// Initialize a RegisterContextLLDB which is the first frame of a stack -- the zeroth frame or currently +// executing frame. + +void +RegisterContextLLDB::InitializeZerothFrame() +{ + m_zeroth_frame = true; + StackFrameSP frame_sp (m_thread.GetStackFrameAtIndex (0)); + if (m_base_reg_ctx == NULL) + { + m_frame_type = eNotAValidFrame; + return; + } + m_sym_ctx = frame_sp->GetSymbolContext (eSymbolContextEverything); + const AddressRange *addr_range_ptr; + if (m_sym_ctx.function) + addr_range_ptr = &m_sym_ctx.function->GetAddressRange(); + else if (m_sym_ctx.symbol) + addr_range_ptr = m_sym_ctx.symbol->GetAddressRangePtr(); + + Address current_pc = frame_sp->GetFrameCodeAddress(); + + 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; + } + + // 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_ptr) + { + m_start_pc = addr_range_ptr->GetBaseAddress(); + m_current_offset = frame_sp->GetFrameCodeAddress().GetOffset() - m_start_pc.GetOffset(); + } + else + { + m_start_pc = current_pc; + m_current_offset = -1; + } + + // We've set m_frame_type, m_zeroth_frame, and m_sym_ctx before this call. + // This call sets the m_all_registers_available, m_fast_unwind_plan, and m_full_unwind_plan member variables. + GetUnwindPlansForFrame (current_pc); + + const UnwindPlan::Row *active_row = NULL; + int cfa_offset = 0; + int row_register_kind; + if (m_full_unwind_plan && m_full_unwind_plan->PlanValidAtAddress (current_pc)) + { + active_row = m_full_unwind_plan->GetRowForFunctionOffset (m_current_offset); + row_register_kind = m_full_unwind_plan->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; + + Log *log = GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND); + if (log) + { + log->Printf("%*sThread %u Frame %d initialized frame current pc is 0x%llx cfa is 0x%llx", + m_frame_number, "", m_thread.GetIndexID(), m_frame_number, + (uint64_t) m_cfa, (uint64_t) current_pc.GetLoadAddress (&m_thread.GetProcess().GetTarget())); + } +} + +// 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 (m_next_frame.get() == NULL) + { + m_frame_type = eNotAValidFrame; + return; + } + if (!((RegisterContextLLDB*)m_next_frame.get())->IsValid()) + { + m_frame_type = eNotAValidFrame; + return; + } + if (m_base_reg_ctx == NULL) + { + m_frame_type = eNotAValidFrame; + return; + } + + m_zeroth_frame = false; + + addr_t pc; + if (!ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc)) + { + if (log) + { + log->Printf("%*sThread %u Frame %d could not get pc value", + m_frame_number, "", m_thread.GetIndexID(), m_frame_number); + } + m_frame_type = eNotAValidFrame; + return; + } + Address current_pc; + m_thread.GetProcess().GetTarget().GetSectionLoadList().ResolveLoadAddress (pc, 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 (!current_pc.IsValid() || current_pc.GetModule() == NULL) + { + if (log) + { + log->Printf("%*sThread %u Frame %d using architectural default unwind method", + m_frame_number, "", m_thread.GetIndexID(), m_frame_number); + } + ArchSpec arch = m_thread.GetProcess().GetTarget().GetArchitecture (); + ArchDefaultUnwindPlan *arch_default = ArchDefaultUnwindPlan::FindPlugin (arch); + if (arch_default) + { + m_fast_unwind_plan = NULL; + m_full_unwind_plan = arch_default->GetArchDefaultUnwindPlan (m_thread, current_pc); + m_frame_type = eNormalFrame; + m_all_registers_available = false; + m_current_offset = -1; + addr_t cfa_regval; + int row_register_kind = m_full_unwind_plan->GetRegisterKind (); + uint32_t cfa_regnum = m_full_unwind_plan->GetRowForFunctionOffset(0)->GetCFARegister(); + int cfa_offset = m_full_unwind_plan->GetRowForFunctionOffset(0)->GetCFAOffset(); + if (!ReadGPRValue (row_register_kind, cfa_regnum, cfa_regval)) + { + if (log) + { + log->Printf("%*sThread %u Frame %d failed to get cfa value", + m_frame_number, "", m_thread.GetIndexID(), m_frame_number); + } + m_frame_type = eNormalFrame; + return; + } + m_cfa = cfa_regval + cfa_offset; + if (log) + { + log->Printf("%*sThread %u Frame %d initialized frame current pc is 0x%llx cfa is 0x%llx", + m_frame_number, "", m_thread.GetIndexID(), m_frame_number, + (uint64_t) m_cfa, (uint64_t) current_pc.GetLoadAddress (&m_thread.GetProcess().GetTarget())); + } + return; + } + m_frame_type = eNotAValidFrame; + return; + } + + // set up our m_sym_ctx SymbolContext + current_pc.GetModule()->ResolveSymbolContextForAddress (current_pc, eSymbolContextFunction | eSymbolContextSymbol, m_sym_ctx); + + const AddressRange *addr_range_ptr; + if (m_sym_ctx.function) + addr_range_ptr = &m_sym_ctx.function->GetAddressRange(); + else if (m_sym_ctx.symbol) + addr_range_ptr = m_sym_ctx.symbol->GetAddressRangePtr(); + + 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; + } + + // 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_ptr) + { + m_start_pc = addr_range_ptr->GetBaseAddress(); + m_current_offset = current_pc.GetOffset() - m_start_pc.GetOffset(); + } + else + { + m_start_pc = current_pc; + m_current_offset = -1; + } + + // We've set m_frame_type, m_zeroth_frame, and m_sym_ctx before this call. + // This call sets the m_all_registers_available, m_fast_unwind_plan, and m_full_unwind_plan member variables. + GetUnwindPlansForFrame (current_pc); + + const UnwindPlan::Row *active_row = NULL; + int cfa_offset = 0; + int row_register_kind; + if (m_fast_unwind_plan && m_fast_unwind_plan->PlanValidAtAddress (current_pc)) + { + active_row = m_fast_unwind_plan->GetRowForFunctionOffset (m_current_offset); + row_register_kind = m_fast_unwind_plan->GetRegisterKind (); + } + else if (m_full_unwind_plan && m_full_unwind_plan->PlanValidAtAddress (current_pc)) + { + active_row = m_full_unwind_plan->GetRowForFunctionOffset (m_current_offset); + row_register_kind = m_full_unwind_plan->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("%*sThread %u Frame %d failed to get cfa reg %d/%d", + m_frame_number, "", m_thread.GetIndexID(), 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; + + if (log) + { + log->Printf("%*sThread %u Frame %d initialized frame current pc is 0x%llx cfa is 0x%llx", + m_frame_number, "", m_thread.GetIndexID(), m_frame_number, + (uint64_t) m_cfa, (uint64_t) current_pc.GetLoadAddress (&m_thread.GetProcess().GetTarget())); + } +} + + + + +// On entry to this method, +// +// 1. m_frame_type should already be set to eSigtrampFrame/eDebuggerFrame +// if either of those are correct, and +// 2. m_zeroth_frame should be set to true if this is frame 0 and +// 3. m_sym_ctx should already be filled in. +// +// On exit this function will have set +// +// a. m_all_registers_available (true if we can provide any requested register, false if only a subset are provided) +// b. m_fast_unwind_plan (fast unwind plan that walks the stack while filling in only minimal registers, may be NULL) +// c. m_full_unwind_plan (full unwind plan that can provide all registers possible, will *not* be NULL) +// +// The argument current_pc should be the current pc value in the function. + +void +RegisterContextLLDB::GetUnwindPlansForFrame (Address current_pc) +{ + UnwindPlan *arch_default_up = NULL; + ArchSpec arch = m_thread.GetProcess().GetTarget().GetArchitecture (); + ArchDefaultUnwindPlan *arch_default = ArchDefaultUnwindPlan::FindPlugin (arch); + if (arch_default) + { + arch_default_up = arch_default->GetArchDefaultUnwindPlan (m_thread, current_pc); + } + + bool behaves_like_zeroth_frame = false; + + if (m_zeroth_frame) + { + behaves_like_zeroth_frame = true; + } + if (m_next_frame.get() && ((RegisterContextLLDB*) m_next_frame.get())->m_frame_type == eSigtrampFrame) + { + behaves_like_zeroth_frame = true; + } + if (m_next_frame.get() && ((RegisterContextLLDB*) m_next_frame.get())->m_frame_type == eDebuggerFrame) + { + behaves_like_zeroth_frame = true; + } + + if (behaves_like_zeroth_frame) + { + m_all_registers_available = true; + } + else + { +// If we need to implement gdb's decrement-pc-value-by-one-before-function-check macro, it would be here. +// current_pc.SetOffset (current_pc.GetOffset() - 1); + m_all_registers_available = false; + } + + // No Module for the current pc, try using the architecture default unwind. + if (current_pc.GetModule() == NULL || current_pc.GetModule()->GetObjectFile() == NULL) + { + m_fast_unwind_plan = NULL; + m_full_unwind_plan = arch_default_up; + m_frame_type = eNormalFrame; + return; + } + + FuncUnwindersSP fu; + if (current_pc.GetModule() && current_pc.GetModule()->GetObjectFile()) + { + fu = current_pc.GetModule()->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (current_pc, m_sym_ctx); + } + + // No FuncUnwinders available for this pc, try using architectural default unwind. + if (fu.get() == NULL) + { + m_fast_unwind_plan = NULL; + m_full_unwind_plan = arch_default_up; + m_frame_type = eNormalFrame; + return; + } + + // 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. + if (m_frame_type == eSigtrampFrame) + { + m_fast_unwind_plan = NULL; + UnwindPlan *up = fu->GetUnwindPlanAtCallSite (); + if (up->PlanValidAtAddress (current_pc)) + { + m_fast_unwind_plan = NULL; + m_full_unwind_plan = up; + return; + } + } + + + UnwindPlan *fast, *callsite, *noncallsite; + fast = callsite = noncallsite = NULL; + + if (fu->GetUnwindPlanFastUnwind (m_thread) + && fu->GetUnwindPlanFastUnwind (m_thread)->PlanValidAtAddress (current_pc)) + { + fast = fu->GetUnwindPlanFastUnwind (m_thread); + } + + // Typically this is the unwind created by inspecting the assembly language instructions + if (fu->GetUnwindPlanAtNonCallSite (m_thread) + && fu->GetUnwindPlanAtNonCallSite (m_thread)->PlanValidAtAddress (current_pc)) + { + noncallsite = fu->GetUnwindPlanAtNonCallSite (m_thread); + } + + + // Typically this is unwind info from an eh_frame section intended for exception handling; only valid at call sites + if (fu->GetUnwindPlanAtCallSite () + && fu->GetUnwindPlanAtCallSite ()->PlanValidAtAddress (current_pc)) + { + callsite = fu->GetUnwindPlanAtCallSite (); + } + + m_fast_unwind_plan = NULL; + m_full_unwind_plan = NULL; + + if (fast) + { + m_fast_unwind_plan = fast; + } + + if (behaves_like_zeroth_frame && noncallsite) + { + m_full_unwind_plan = noncallsite; + } + else + { + if (callsite) + { + m_full_unwind_plan = callsite; + } + else + { + m_full_unwind_plan = noncallsite; + } + } + + if (m_full_unwind_plan == NULL) + { + m_full_unwind_plan = arch_default_up; + } + + Log *log = GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND); + if (log) + { + const char *has_fast = ""; + if (m_fast_unwind_plan) + has_fast = ", and has a fast UnwindPlan"; + log->Printf("%*sThread %u Frame %d frame uses %s for full UnwindPlan%s", + m_frame_number, "", m_thread.GetIndexID(), m_frame_number, + m_full_unwind_plan->GetSourceName().GetCString(), has_fast); + } + + return; +} + +void +RegisterContextLLDB::Invalidate () +{ + m_frame_type = eNotAValidFrame; +} + +size_t +RegisterContextLLDB::GetRegisterCount () +{ + return m_base_reg_ctx->GetRegisterCount(); +} + +const RegisterInfo * +RegisterContextLLDB::GetRegisterInfoAtIndex (uint32_t reg) +{ + return m_base_reg_ctx->GetRegisterInfoAtIndex (reg); +} + +size_t +RegisterContextLLDB::GetRegisterSetCount () +{ + return m_base_reg_ctx->GetRegisterSetCount (); +} + +const RegisterSet * +RegisterContextLLDB::GetRegisterSet (uint32_t reg_set) +{ + return m_base_reg_ctx->GetRegisterSet (reg_set); +} + +uint32_t +RegisterContextLLDB::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) +{ + return m_base_reg_ctx->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 (m_next_frame.get() == NULL) + { + return m_base_reg_ctx->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_base_reg_ctx->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 (eByteOrderHost); + switch (reg_info->byte_size) + { + case 1: + { + uint8_t val = regloc.location.register_value; + memcpy (data_sp->GetBytes(), &val, sizeof (val)); + data.SetByteOrder (eByteOrderHost); + return true; + } + case 2: + { + uint16_t val = regloc.location.register_value; + memcpy (data_sp->GetBytes(), &val, sizeof (val)); + data.SetByteOrder (eByteOrderHost); + return true; + } + case 4: + { + uint32_t val = regloc.location.register_value; + memcpy (data_sp->GetBytes(), &val, sizeof (val)); + data.SetByteOrder (eByteOrderHost); + return true; + } + case 8: + { + uint64_t val = regloc.location.register_value; + memcpy (data_sp->GetBytes(), &val, sizeof (val)); + data.SetByteOrder (eByteOrderHost); + 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::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) +{ + Log *log = GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND); + + // Have we already found this register location? + std::map<uint32_t, RegisterLocation>::const_iterator iterator; + if (m_registers.size() > 0) + { + 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_base_reg_ctx->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; + if (m_fast_unwind_plan) + { + const UnwindPlan::Row *active_row = m_fast_unwind_plan->GetRowForFunctionOffset (m_current_offset); + uint32_t row_regnum; + if (!m_base_reg_ctx->ConvertBetweenRegisterKinds (eRegisterKindLLDB, lldb_regnum, m_fast_unwind_plan->GetRegisterKind(), row_regnum)) + { + if (log) + { + log->Printf("%*sThread %u Frame %d could not supply caller's reg %d location", + m_frame_number, "", m_thread.GetIndexID(), m_frame_number, + lldb_regnum); + } + return false; + } + if (active_row->GetRegisterInfo (row_regnum, unwindplan_regloc)) + { + if (log) + { + log->Printf("%*sThread %u Frame %d supplying caller's saved reg %d's location using FastUnwindPlan", + m_frame_number, "", m_thread.GetIndexID(), m_frame_number, + lldb_regnum); + } + have_unwindplan_regloc = true; + } + } + else if (m_full_unwind_plan) + { + const UnwindPlan::Row *active_row = m_full_unwind_plan->GetRowForFunctionOffset (m_current_offset); + uint32_t row_regnum; + if (!m_base_reg_ctx->ConvertBetweenRegisterKinds (eRegisterKindLLDB, lldb_regnum, m_full_unwind_plan->GetRegisterKind(), row_regnum)) + { + if (log) + { + log->Printf("%*sThread %u Frame %d could not supply caller's reg %d location", + m_frame_number, "", m_thread.GetIndexID(), m_frame_number, + lldb_regnum); + } + return false; + } + + if (active_row->GetRegisterInfo (row_regnum, unwindplan_regloc)) + { + have_unwindplan_regloc = true; + if (log) + { + log->Printf("%*sThread %u Frame %d supplying caller's saved reg %d's location using %s UnwindPlan", + m_frame_number, "", m_thread.GetIndexID(), m_frame_number, + lldb_regnum, m_full_unwind_plan->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. + 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("%*sThread %u Frame %d did not supply reg location for %d because it is volatile", + m_frame_number, "", m_thread.GetIndexID(), m_frame_number, + lldb_regnum); + } + return false; + } + + if (m_next_frame.get()) + { + return ((RegisterContextLLDB*)m_next_frame.get())->SavedLocationForRegister (lldb_regnum, regloc); + } + else + { + // 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; + if (log) + { + log->Printf("%*sThread %u Frame %d register %d is in the thread's live register context", + m_frame_number, "", m_thread.GetIndexID(), m_frame_number, + lldb_regnum); + } + return true; + } + if (log) + { + log->Printf("%*sThread %u Frame %d could not supply caller's reg %d location", + m_frame_number, "", m_thread.GetIndexID(), 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("%*sThread %u Frame %d could not supply caller's reg %d location", + m_frame_number, "", m_thread.GetIndexID(), m_frame_number, + lldb_regnum); + } + return false; + } + + if (unwindplan_regloc.IsSame()) + { + if (m_next_frame.get()) + { + return ((RegisterContextLLDB*)m_next_frame.get())->SavedLocationForRegister (lldb_regnum, regloc); + } + else + { + if (log) + { + log->Printf("%*sThread %u Frame %d could not supply caller's reg %d location", + m_frame_number, "", m_thread.GetIndexID(), m_frame_number, + lldb_regnum); + } + return false; + } + } + + 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_base_reg_ctx->ConvertBetweenRegisterKinds (m_full_unwind_plan->GetRegisterKind(), unwindplan_regnum, eRegisterKindLLDB, row_regnum_in_lldb)) + { + if (log) + { + log->Printf("%*sThread %u Frame %d could not supply caller's reg %d location", + m_frame_number, "", m_thread.GetIndexID(), 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 (log) + { + log->Printf("%*sThread %u Frame %d could not supply caller's reg %d location", + m_frame_number, "", m_thread.GetIndexID(), 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. + +// Assumes m_base_reg_ctx has been set +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_base_reg_ctx->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 (m_next_frame.get() == NULL) + { + if (m_base_reg_ctx->ReadRegisterBytes (lldb_regnum, data)) + { + data.SetAddressByteSize (m_thread.GetProcess().GetAddressByteSize()); + value = data.GetAddress (&offset); + return true; + } + else + { + return false; + } + } + + RegisterLocation regloc; + if (!((RegisterContextLLDB*)m_next_frame.get())->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) +{ + Log *log = GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND); + if (!IsValid()) + return false; + + if (log) + { + log->Printf("%*sThread %u Frame %d looking for register saved location for reg %d", + m_frame_number, "", m_thread.GetIndexID(), m_frame_number, + lldb_reg); + } + + // If this is the 0th frame, hand this over to the live register context + if (m_next_frame.get() == NULL) + { + if (log) + { + log->Printf("%*sThread %u Frame %d passing along to the live register context for reg %d", + m_frame_number, "", m_thread.GetIndexID(), m_frame_number, + lldb_reg); + } + return m_base_reg_ctx->ReadRegisterBytes (lldb_reg, data); + } + + RegisterLocation regloc; + // Find out where the NEXT frame saved THIS frame's register contents + if (!((RegisterContextLLDB*)m_next_frame.get())->SavedLocationForRegister (lldb_reg, regloc)) + return false; + + return ReadRegisterBytesFromRegisterLocation (lldb_reg, regloc, data); +} + +bool +RegisterContextLLDB::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) +{ + assert ("not yet implemented"); // FIXME + return false; +} + +bool +RegisterContextLLDB::WriteRegisterBytes (uint32_t reg, DataExtractor &data, uint32_t data_offset) +{ + assert ("not yet implemented"); // FIXME + return false; +} + +bool +RegisterContextLLDB::WriteAllRegisterValues (const lldb::DataBufferSP& data_sp) +{ + assert ("not yet implemented"); // FIXME + 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 GetPC (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::GetPC (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; + } +} diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h new file mode 100644 index 00000000000..41e43538e6d --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h @@ -0,0 +1,177 @@ +//===-- RegisterContextLLDB.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_RegisterContextLLDB_h_ +#define lldb_RegisterContextLLDB_h_ + +#include <vector> + +#include "lldb/lldb-private.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Symbol/UnwindPlan.h" +#include "lldb/Symbol/SymbolContext.h" + +class RegisterContextLLDB : public lldb_private::RegisterContext +{ +public: + RegisterContextLLDB (lldb_private::Thread &thread, + const lldb::RegisterContextSP& next_frame, + lldb_private::SymbolContext& sym_ctx, + int frame_number); + + /// + // pure virtual functions from the base class that we must implement + /// + + virtual + ~RegisterContextLLDB () { } + + virtual void + Invalidate (); + + virtual size_t + GetRegisterCount (); + + virtual const lldb::RegisterInfo * + GetRegisterInfoAtIndex (uint32_t reg); + + virtual size_t + GetRegisterSetCount (); + + virtual const lldb::RegisterSet * + GetRegisterSet (uint32_t reg_set); + + virtual bool + ReadRegisterBytes (uint32_t reg, lldb_private::DataExtractor &data); + + virtual bool + ReadAllRegisterValues (lldb::DataBufferSP &data_sp); + + virtual bool + WriteRegisterBytes (uint32_t reg, lldb_private::DataExtractor &data, uint32_t data_offset = 0); + + virtual bool + WriteAllRegisterValues (const lldb::DataBufferSP &data_sp); + + virtual uint32_t + ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); + + bool + IsValid () const; + + bool + GetCFA (lldb::addr_t& cfa); + + bool + GetStartPC (lldb::addr_t& start_pc); + + bool + GetPC (lldb::addr_t& start_pc); + +private: + + typedef enum FrameType + { + eNormalFrame, + eSigtrampFrame, + eDebuggerFrame, // a debugger inferior function call frame; we get caller's registers from debugger + eNotAValidFrame // this frame is invalid for some reason - most likely it is past the top (end) of the stack + }; + + enum RegisterLocationTypes + { + eRegisterNotSaved = 0, // register was not preserved by callee. If volatile reg, is unavailable + eRegisterSavedAtMemoryLocation, // register is saved at a specific word of target mem (target_memory_location) + eRegisterInRegister, // register is available in a (possible other) register (register_number) + eRegisterSavedAtHostMemoryLocation, // register is saved at a word in lldb's address space + eRegisterValueInferred // register val was computed (and is in register_value) + }; + + struct RegisterLocation + { + int type; + union + { + lldb::addr_t target_memory_location; + uint32_t register_number; // in eRegisterKindLLDB register numbering system + void* host_memory_location; + uint64_t register_value; // eRegisterValueInferred - e.g. stack pointer == cfa + offset + } location; + }; + + + void + InitializeZerothFrame (); + + void + InitializeNonZerothFrame(); + + // Provide a location for where THIS function saved the CALLER's register value + // Or a frame "below" this one savedit, i.e. a function called by this one, preserved a register that this + // function didn't modify/use. + // + // The RegisterLocation type may be set to eRegisterNotAvailable -- this will happen for a volatile register + // bieng queried mid-stack. Instead of floating frame 0's contents of that register up the stack (which may + // or may not be the value of that reg when the function was executing), we won't return any value. + // + // If a non-volatile register (a "preserved" register) is requested mid-stack and no frames "below" the requested + // stack have saved the register anywhere, it is safe to assume that frame 0's register values are still the same + // as the requesting frame's. + // + bool + SavedLocationForRegister (uint32_t lldb_regnum, RegisterLocation ®loc); + + bool + ReadRegisterBytesFromRegisterLocation (uint32_t regnum, RegisterLocation regloc, lldb_private::DataExtractor &data); + + bool + WriteRegisterBytesFromRegisterLocation (uint32_t regnum, RegisterLocation regloc, lldb_private::Scalar value); + + // Get the contents of a general purpose (address-size) register for this frame + // (usually retrieved from the m_next_frame) + // m_base_reg_ectx and m_next_frame should both be initialized appropriately before calling. + bool + ReadGPRValue (int register_kind, uint32_t regnum, lldb::addr_t &value); + + void + GetUnwindPlansForFrame (lldb_private::Address current_pc); + + lldb_private::Thread& m_thread; + lldb::RegisterContextSP m_next_frame; + + lldb_private::RegisterContext *m_base_reg_ctx; // RegisterContext of frame 0 (live register values only) + + /// + // The following tell us how to retrieve the CALLER's register values (ie the "previous" frame, aka the frame above) + // i.e. where THIS frame saved them + /// + + lldb_private::UnwindPlan *m_fast_unwind_plan; // may be NULL + lldb_private::UnwindPlan *m_full_unwind_plan; + bool m_zeroth_frame; // Is this the bottom-most, i.e. currently executing, frame? + bool m_all_registers_available; // Can we retrieve all regs or just nonvolatile regs? + int m_frame_type; // enum FrameType + int m_current_offset; // how far into the function we've executed; -1 if unknown + lldb_private::SymbolContext& m_sym_ctx; + + int m_frame_number; // What stack frame level this frame is - used for debug logging + + lldb::addr_t m_cfa; + lldb_private::Address m_start_pc; + + std::map<uint32_t, RegisterLocation> m_registers; // where to find reg values for this frame + + //------------------------------------------------------------------ + // For RegisterContextLLDB only + //------------------------------------------------------------------ + + DISALLOW_COPY_AND_ASSIGN (RegisterContextLLDB); +}; + +#endif // lldb_RegisterContextLLDB_h_ diff --git a/lldb/source/Plugins/Process/Utility/UnwindAssemblyProfiler-x86.cpp b/lldb/source/Plugins/Process/Utility/UnwindAssemblyProfiler-x86.cpp index 21a01f8af99..0e2a4a7f719 100644 --- a/lldb/source/Plugins/Process/Utility/UnwindAssemblyProfiler-x86.cpp +++ b/lldb/source/Plugins/Process/Utility/UnwindAssemblyProfiler-x86.cpp @@ -125,7 +125,7 @@ public: bool get_non_call_site_unwind_plan (UnwindPlan &unwind_plan); - bool get_fast_unwind_plan (UnwindPlan &unwind_plan); + bool get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_plan); bool find_first_non_prologue_insn (Address &address); @@ -166,7 +166,7 @@ private: AssemblyParse_x86::AssemblyParse_x86 (Target& target, Thread* thread, int cpu, AddressRange func) : m_target (target), m_thread (thread), m_cpu(cpu), m_func_bounds(func) -{ +{ int *initialized_flag = NULL; m_lldb_ip_regnum = m_lldb_sp_regnum = m_lldb_fp_regnum = -1; if (cpu == k_i386) @@ -489,7 +489,7 @@ AssemblyParse_x86::instruction_length (Address addr, int &length) if (EDGetDisassembler (&disasm, "i386-apple-darwin", kEDAssemblySyntaxX86ATT) != 0) { - false; + return false; } uint64_t addr_offset = addr.GetOffset(); @@ -498,7 +498,7 @@ AssemblyParse_x86::instruction_length (Address addr, int &length) arg.target = &m_target; if (EDCreateInsts (&cur_insn, 1, disasm, read_byte_for_edis, addr_offset, &arg) != 1) { - false; + return false; } length = EDInstByteSize (cur_insn); EDReleaseInst (cur_insn); @@ -566,12 +566,11 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan) goto loopnext; } + // This is the start() function (or a pthread equivalent), it starts with a pushl $0x0 which puts the + // saved pc value of 0 on the stack. In this case we want to pretend we didn't see a stack movement at all -- + // normally the saved pc value is already on the stack by the time the function starts executing. if (push_0_pattern_p ()) { - row.SetOffset (current_func_text_offset + insn_len); - current_sp_bytes_offset_from_cfa += m_wordsize; - row.SetCFAOffset (current_sp_bytes_offset_from_cfa); - unwind_plan.AppendRow (row); goto loopnext; } @@ -648,14 +647,78 @@ loopnext: current_func_text_offset += insn_len; } + unwind_plan.SetSourceName ("assembly insn profiling"); + return true; } +/* The "fast unwind plan" is valid for functions that follow the usual convention of + using the frame pointer register (ebp, rbp), i.e. the function prologue looks like + push %rbp [0x55] + mov %rsp,%rbp [0x48 0x89 0xe5] (this is a 2-byte insn seq on i386) +*/ + bool -AssemblyParse_x86::get_fast_unwind_plan (UnwindPlan &unwind_plan) +AssemblyParse_x86::get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_plan) { - UnwindPlan up; - return false; + UnwindPlan::Row row; + UnwindPlan::Row::RegisterLocation pc_reginfo; + UnwindPlan::Row::RegisterLocation sp_reginfo; + UnwindPlan::Row::RegisterLocation fp_reginfo; + unwind_plan.SetRegisterKind (eRegisterKindLLDB); + + if (!func.GetBaseAddress().IsValid()) + return false; + + uint8_t bytebuf[4]; + Error error; + if (m_target.ReadMemory (func.GetBaseAddress(), bytebuf, sizeof (bytebuf), error) == -1) + return false; + + uint8_t i386_prologue[] = {0x55, 0x89, 0xe5}; + uint8_t x86_64_prologue[] = {0x55, 0x48, 0x89, 0xe5}; + int prologue_size; + + if (memcmp (bytebuf, i386_prologue, sizeof (i386_prologue)) == 0) + { + prologue_size = sizeof (i386_prologue); + } + else if (memcmp (bytebuf, x86_64_prologue, sizeof (x86_64_prologue)) == 0) + { + prologue_size = sizeof (x86_64_prologue); + } + else + { + return false; + } + + pc_reginfo.SetAtCFAPlusOffset (-m_wordsize); + row.SetRegisterInfo (m_lldb_ip_regnum, pc_reginfo); + + sp_reginfo.SetIsCFAPlusOffset (0); + row.SetRegisterInfo (m_lldb_sp_regnum, sp_reginfo); + + // Zero instructions into the function + row.SetCFARegister (m_lldb_sp_regnum); + row.SetCFAOffset (m_wordsize); + row.SetOffset (0); + unwind_plan.AppendRow (row); + + // push %rbp has executed - stack moved, rbp now saved + row.SetCFAOffset (2 * m_wordsize); + fp_reginfo.SetAtCFAPlusOffset (2 * -m_wordsize); + row.SetRegisterInfo (m_lldb_fp_regnum, fp_reginfo); + row.SetOffset (1); + unwind_plan.AppendRow (row); + + // mov %rsp, %rbp has executed + row.SetCFARegister (m_lldb_fp_regnum); + row.SetCFAOffset (2 * m_wordsize); + row.SetOffset (prologue_size); /// 3 or 4 bytes depending on arch + unwind_plan.AppendRow (row); + + unwind_plan.SetPlanValidAddressRange (func); + return true; } bool @@ -712,7 +775,7 @@ bool UnwindAssemblyProfiler_x86::GetFastUnwindPlan (AddressRange& func, Thread& thread, UnwindPlan &unwind_plan) { AssemblyParse_x86 asm_parse(thread.GetProcess().GetTarget(), &thread, m_cpu, func); - return asm_parse.get_fast_unwind_plan (unwind_plan); + return asm_parse.get_fast_unwind_plan (func, unwind_plan); } bool diff --git a/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp b/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp new file mode 100644 index 00000000000..6d4c345e28e --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp @@ -0,0 +1,141 @@ +//===-- UnwindLLDB.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/Target/Thread.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Core/Module.h" +#include "lldb/Symbol/FuncUnwinders.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Utility/ArchDefaultUnwindPlan.h" +#include "UnwindLLDB.h" +#include "lldb/Symbol/UnwindPlan.h" +#include "lldb/Core/Log.h" + +using namespace lldb; +using namespace lldb_private; + +UnwindLLDB::UnwindLLDB (Thread &thread) : + Unwind (thread), + m_frames() +{ +} + +uint32_t +UnwindLLDB::GetFrameCount() +{ + Log *log = GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND); + if (m_frames.empty()) + { + // First, set up the 0th (initial) frame + Cursor first_cursor; + RegisterContextSP no_frame; // an empty shared pointer + RegisterContextLLDB *first_register_ctx = new RegisterContextLLDB(m_thread, no_frame, first_cursor.sctx, 0); + if (!first_register_ctx->IsValid()) + { + delete first_register_ctx; + return 0; + } + if (!first_register_ctx->GetCFA (first_cursor.cfa)) + { + delete first_register_ctx; + return 0; + } + if (!first_register_ctx->GetPC (first_cursor.start_pc)) + { + delete first_register_ctx; + return 0; + } + // Reuse the StackFrame provided by the processor native machine context for the first frame + first_register_ctx->SetStackFrame (m_thread.GetStackFrameAtIndex(0).get()); + RegisterContextSP temp_rcs(first_register_ctx); + first_cursor.reg_ctx = temp_rcs; + m_frames.push_back (first_cursor); + + // Now walk up the rest of the stack + while (1) + { + Cursor cursor; + RegisterContextLLDB *register_ctx; + int cur_idx = m_frames.size (); + register_ctx = new RegisterContextLLDB (m_thread, m_frames[cur_idx - 1].reg_ctx, cursor.sctx, cur_idx); + if (!register_ctx->IsValid()) + { + delete register_ctx; + if (log) + { + log->Printf("%*sThread %u Frame %d invalid RegisterContext for this frame, stopping stack walk", + cur_idx, "", m_thread.GetIndexID(), cur_idx); + } + break; + } + if (!register_ctx->GetCFA (cursor.cfa)) + { + delete register_ctx; + if (log) + { + log->Printf("%*sThread %u Frame %d did not get CFA for this frame, stopping stack walk", + cur_idx, "", m_thread.GetIndexID(), cur_idx); + } + break; + } + if (!register_ctx->GetPC (cursor.start_pc)) + { + delete register_ctx; + if (log) + { + log->Printf("%*sThread %u Frame %d did not get PC for this frame, stopping stack walk", + cur_idx, "", m_thread.GetIndexID(), cur_idx); + } + break; + } + RegisterContextSP temp_rcs(register_ctx); + StackFrame *frame = new StackFrame(cur_idx, cur_idx, m_thread, temp_rcs, cursor.cfa, cursor.start_pc, &cursor.sctx); + register_ctx->SetStackFrame (frame); + cursor.reg_ctx = temp_rcs; + m_frames.push_back (cursor); + } + } + return m_frames.size (); +} + +bool +UnwindLLDB::GetFrameInfoAtIndex (uint32_t idx, addr_t& cfa, addr_t& pc) +{ + // FIXME don't get the entire stack if it isn't needed. + if (m_frames.size() == 0) + GetFrameCount(); + + if (idx < m_frames.size ()) + { + cfa = m_frames[idx].cfa; + pc = m_frames[idx].start_pc; + return true; + } + return false; +} + +RegisterContext * +UnwindLLDB::CreateRegisterContextForFrame (StackFrame *frame) +{ + uint32_t idx = frame->GetFrameIndex (); + + // FIXME don't get the entire stack if it isn't needed. + if (m_frames.size() == 0) + GetFrameCount(); + + if (idx == 0) + { + return m_thread.GetRegisterContext(); + } + if (idx < m_frames.size ()) + return m_frames[idx].reg_ctx.get(); + return NULL; +} diff --git a/lldb/source/Plugins/Process/Utility/UnwindLLDB.h b/lldb/source/Plugins/Process/Utility/UnwindLLDB.h new file mode 100644 index 00000000000..5c1211719b7 --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/UnwindLLDB.h @@ -0,0 +1,70 @@ +//===-- UnwindLLDB.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_UnwindLLDB_h_ +#define lldb_UnwindLLDB_h_ + +#include "lldb/lldb-private.h" +#include "lldb/Target/Unwind.h" +#include "lldb/Symbol/FuncUnwinders.h" +#include "lldb/Symbol/UnwindPlan.h" +#include "RegisterContextLLDB.h" +#include "lldb/Target/RegisterContext.h" +#include <vector> + + +namespace lldb_private { + +class UnwindLLDB : public lldb_private::Unwind +{ +public: + UnwindLLDB (lldb_private::Thread &thread); + + virtual + ~UnwindLLDB() { } + + void + Clear() + { + m_frames.clear(); + } + + virtual uint32_t + GetFrameCount(); + + bool + GetFrameInfoAtIndex (uint32_t frame_idx, + lldb::addr_t& cfa, + lldb::addr_t& start_pc); + + lldb_private::RegisterContext * + CreateRegisterContextForFrame (lldb_private::StackFrame *frame); + +private: + struct Cursor + { + lldb::addr_t start_pc; // The start address of the function/symbol for this frame - current pc if unknown + lldb::addr_t cfa; // The canonical frame address for this stack frame + lldb_private::SymbolContext sctx; // A symbol context we'll contribute to & provide to the StackFrame creation + lldb::RegisterContextSP reg_ctx; // These are all RegisterContextLLDB's + + Cursor () : start_pc (LLDB_INVALID_ADDRESS), cfa (LLDB_INVALID_ADDRESS), sctx(), reg_ctx() { } + }; + + std::vector<Cursor> m_frames; + + //------------------------------------------------------------------ + // For UnwindLLDB only + //------------------------------------------------------------------ + DISALLOW_COPY_AND_ASSIGN (UnwindLLDB); +}; + +} + +#endif // lldb_UnwindLLDB_h_ diff --git a/lldb/source/Symbol/DWARFCallFrameInfo.cpp b/lldb/source/Symbol/DWARFCallFrameInfo.cpp index b5da066006c..9456a943ac2 100644 --- a/lldb/source/Symbol/DWARFCallFrameInfo.cpp +++ b/lldb/source/Symbol/DWARFCallFrameInfo.cpp @@ -347,7 +347,14 @@ DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t offset, Address startaddr, Unwi // is relative to the FDE offset, into a __eh_frame section // offset if (m_is_eh_frame) + { + unwind_plan.SetSourceName ("eh_frame CFI"); cie_offset = current_entry + 4 - cie_offset; + } + else + { + unwind_plan.SetSourceName ("DWARF CFI"); + } const CIE *cie = GetCIE (cie_offset); assert (cie != NULL); diff --git a/lldb/source/Symbol/FuncUnwinders.cpp b/lldb/source/Symbol/FuncUnwinders.cpp index 7998cf14eff..5ce4d25fc0a 100644 --- a/lldb/source/Symbol/FuncUnwinders.cpp +++ b/lldb/source/Symbol/FuncUnwinders.cpp @@ -71,9 +71,14 @@ UnwindPlan* FuncUnwinders::GetUnwindPlanAtNonCallSite (Thread& thread) { if (m_unwind_at_non_call_site != NULL) - m_unwind_at_non_call_site; - m_unwind_at_non_call_site = new UnwindPlan; - m_assembly_profiler->GetNonCallSiteUnwindPlanFromAssembly (m_range, thread, *m_unwind_at_non_call_site); + return m_unwind_at_non_call_site; + UnwindPlan *up = new UnwindPlan; + if (!m_assembly_profiler->GetNonCallSiteUnwindPlanFromAssembly (m_range, thread, *up)) + { + delete up; + return NULL; + } + m_unwind_at_non_call_site = up; return m_unwind_at_non_call_site; } @@ -82,8 +87,13 @@ FuncUnwinders::GetUnwindPlanFastUnwind (Thread& thread) { if (m_fast_unwind != NULL) return m_fast_unwind; - m_fast_unwind = new UnwindPlan; - m_assembly_profiler->GetFastUnwindPlan (m_range, thread, *m_fast_unwind); + UnwindPlan *up = new UnwindPlan; + if (!m_assembly_profiler->GetFastUnwindPlan (m_range, thread, *up)) + { + delete up; + return NULL; + } + m_fast_unwind = up; return m_fast_unwind; } diff --git a/lldb/source/Symbol/UnwindPlan.cpp b/lldb/source/Symbol/UnwindPlan.cpp index cc4dcf24fc6..6f370de5a37 100644 --- a/lldb/source/Symbol/UnwindPlan.cpp +++ b/lldb/source/Symbol/UnwindPlan.cpp @@ -11,6 +11,7 @@ #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Thread.h" +#include "lldb/Core/ConstString.h" using namespace lldb; using namespace lldb_private; @@ -220,6 +221,10 @@ const UnwindPlan::Row * UnwindPlan::GetRowForFunctionOffset (int offset) const { const UnwindPlan::Row *rowp = NULL; + if (offset == -1 && m_row_list.size() > 0) + { + return &m_row_list[m_row_list.size() - 1]; + } for (int i = 0; i < m_row_list.size(); ++i) { if (m_row_list[i].GetOffset() <= offset) @@ -268,7 +273,10 @@ UnwindPlan::GetRegisterKind (void) const void UnwindPlan::SetPlanValidAddressRange (const AddressRange& range) { - m_plan_valid_address_range = range; + if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0) + { + m_plan_valid_address_range = range; + } // .GetBaseAddress() = addr; // m_plan_valid_address_range.SetByteSize (range.GetByteSize()); } @@ -276,7 +284,7 @@ UnwindPlan::SetPlanValidAddressRange (const AddressRange& range) bool UnwindPlan::PlanValidAtAddress (Address addr) { - if (!m_plan_valid_address_range.GetBaseAddress().IsValid()) + if (!m_plan_valid_address_range.GetBaseAddress().IsValid() || m_plan_valid_address_range.GetByteSize() == 0) return true; if (m_plan_valid_address_range.ContainsFileAddress (addr)) @@ -288,9 +296,20 @@ UnwindPlan::PlanValidAtAddress (Address addr) void UnwindPlan::Dump (Stream& s, Thread *thread) const { - s.Printf ("Address range of this UnwindPlan: "); - m_plan_valid_address_range.Dump (&s, &thread->GetProcess().GetTarget(), Address::DumpStyleSectionNameOffset); - s.Printf ("\n"); + if (!m_source_name.IsEmpty()) + { + s.Printf ("This UnwindPlan originally sourced from %s\n", m_source_name.GetCString()); + } + if (m_plan_valid_address_range.GetBaseAddress().IsValid() && m_plan_valid_address_range.GetByteSize() > 0) + { + s.Printf ("Address range of this UnwindPlan: "); + m_plan_valid_address_range.Dump (&s, &thread->GetProcess().GetTarget(), Address::DumpStyleSectionNameOffset); + s.Printf ("\n"); + } + else + { + s.Printf ("No valid address range recorded for this UnwindPlan.\n"); + } s.Printf ("UnwindPlan register kind %d", m_register_kind); switch (m_register_kind) { @@ -308,3 +327,15 @@ UnwindPlan::Dump (Stream& s, Thread *thread) const m_row_list[i].Dump(s, m_register_kind, thread); } } + +void +UnwindPlan::SetSourceName (const char *source) +{ + m_source_name = ConstString (source); +} + +ConstString +UnwindPlan::GetSourceName () const +{ + return m_source_name; +} diff --git a/lldb/source/Target/RegisterContext.cpp b/lldb/source/Target/RegisterContext.cpp index b21890eee90..1d405325833 100644 --- a/lldb/source/Target/RegisterContext.cpp +++ b/lldb/source/Target/RegisterContext.cpp @@ -12,6 +12,7 @@ // Other libraries and framework includes // Project includes #include "lldb/Target/RegisterContext.h" +#include "lldb/Core/DataExtractor.h" #include "lldb/Core/Scalar.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/StackFrame.h" @@ -21,7 +22,7 @@ using namespace lldb; using namespace lldb_private; //---------------------------------------------------------------------- -// RegisterContext constructor +// RegisterContext constructors //---------------------------------------------------------------------- RegisterContext::RegisterContext (Thread &thread, StackFrame *frame) : m_thread (thread), @@ -29,6 +30,12 @@ RegisterContext::RegisterContext (Thread &thread, StackFrame *frame) : { } +RegisterContext::RegisterContext (Thread &thread) : + m_thread (thread), + m_frame (NULL) +{ +} + //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- @@ -200,6 +207,12 @@ RegisterContext::HardwareSingleStep (bool enable) return false; } +void +RegisterContext::SetStackFrame (StackFrame *frame) +{ + m_frame = frame; +} + Target * RegisterContext::CalculateTarget () { @@ -236,7 +249,7 @@ RegisterContext::CalculateExecutionContext (ExecutionContext &exe_ctx) bool -RegisterContext::ConvertBetweenRegisterKinds (int source_rk, uint32_t source_regnum, int target_rk, uint32_t target_regnum) +RegisterContext::ConvertBetweenRegisterKinds (int source_rk, uint32_t source_regnum, int target_rk, uint32_t& target_regnum) { const uint32_t num_registers = GetRegisterCount(); for (uint32_t reg = 0; reg < num_registers; ++reg) @@ -258,3 +271,121 @@ RegisterContext::ConvertBetweenRegisterKinds (int source_rk, uint32_t source_reg } return false; } + +bool +RegisterContext::ReadRegisterValue (uint32_t reg, Scalar &value) +{ + DataExtractor data; + if (!ReadRegisterBytes (reg, data)) + return false; + + const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg); + uint32_t offset = 0; + switch (reg_info->encoding) + { + case eEncodingUint: + switch (reg_info->byte_size) + { + case 1: + { + value = data.GetU8 (&offset); + return true; + } + case 2: + { + value = data.GetU16 (&offset); + return true; + } + case 4: + { + value = data.GetU32 (&offset); + return true; + } + case 8: + { + value = data.GetU64 (&offset); + return true; + } + } + break; + case eEncodingSint: + switch (reg_info->byte_size) + { + case 1: + { + int8_t v; + if (data.ExtractBytes (0, sizeof (int8_t), eByteOrderHost, &v) != sizeof (int8_t)) + return false; + value = v; + return true; + } + case 2: + { + int16_t v; + if (data.ExtractBytes (0, sizeof (int16_t), eByteOrderHost, &v) != sizeof (int16_t)) + return false; + value = v; + return true; + } + case 4: + { + int32_t v; + if (data.ExtractBytes (0, sizeof (int32_t), eByteOrderHost, &v) != sizeof (int32_t)) + return false; + value = v; + return true; + } + case 8: + { + int64_t v; + if (data.ExtractBytes (0, sizeof (int64_t), eByteOrderHost, &v) != sizeof (int64_t)) + return false; + value = v; + return true; + } + } + break; + case eEncodingIEEE754: + switch (reg_info->byte_size) + { + case sizeof (float): + { + float v; + if (data.ExtractBytes (0, sizeof (float), eByteOrderHost, &v) != sizeof (float)) + return false; + value = v; + return true; + } + case sizeof (double): + { + double v; + if (data.ExtractBytes (0, sizeof (double), eByteOrderHost, &v) != sizeof (double)) + return false; + value = v; + return true; + } + case sizeof (long double): + { + double v; + if (data.ExtractBytes (0, sizeof (long double), eByteOrderHost, &v) != sizeof (long double)) + return false; + value = v; + return true; + } + } + break; + } + return false; +} + +bool +RegisterContext::WriteRegisterValue (uint32_t reg, const Scalar &value) +{ + DataExtractor data; + if (!value.IsValid()) + return false; + if (!value.GetData (data)) + return false; + + return WriteRegisterBytes (reg, data); +} diff --git a/lldb/source/lldb-log.cpp b/lldb/source/lldb-log.cpp index 4e291fab4ab..ce8d2132c8b 100644 --- a/lldb/source/lldb-log.cpp +++ b/lldb/source/lldb-log.cpp @@ -152,6 +152,7 @@ lldb_private::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, Args &ar else if (strcasestr(arg, "comm") == arg) flag_bits |= LIBLLDB_LOG_COMMUNICATION; else if (strcasestr(arg, "conn") == arg) flag_bits |= LIBLLDB_LOG_CONNECTION; else if (strcasestr(arg, "host") == arg) flag_bits |= LIBLLDB_LOG_HOST; + else if (strcasestr(arg, "unwind") == arg) flag_bits |= LIBLLDB_LOG_UNWIND; else { feedback_strm->Printf("error: unrecognized log category '%s'\n", arg); @@ -186,6 +187,7 @@ lldb_private::ListLogCategories (Stream *strm) "\tshlib - log shared library related activities\n" "\tstate - log private and public process state changes\n" "\tstep - log step related activities\n" + "\tunwind - log stack unwind activities\n" "\tverbose - enable verbose loggging\n" "\twatch - log watchpoint related activities\n"); } diff --git a/lldb/source/lldb.cpp b/lldb/source/lldb.cpp index 2ae93308186..e3e8f24b526 100644 --- a/lldb/source/lldb.cpp +++ b/lldb/source/lldb.cpp @@ -69,6 +69,7 @@ lldb_private::Initialize () SymbolFileDWARFDebugMap::Initialize(); SymbolFileSymtab::Initialize(); UnwindAssemblyProfiler_x86::Initialize(); + ArchDefaultUnwindPlan_x86::Initialize(); ArchVolatileRegs_x86::Initialize(); #ifdef __APPLE__ @@ -110,6 +111,7 @@ lldb_private::Terminate () SymbolFileDWARFDebugMap::Terminate(); SymbolFileSymtab::Terminate(); UnwindAssemblyProfiler_x86::Terminate(); + ArchDefaultUnwindPlan_x86::Terminate(); ArchVolatileRegs_x86::Terminate(); #ifdef __APPLE__ |