summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/include/lldb/Symbol/UnwindPlan.h42
-rw-r--r--lldb/include/lldb/Target/RegisterContext.h19
-rw-r--r--lldb/include/lldb/lldb-private-log.h1
-rw-r--r--lldb/lldb.xcodeproj/project.pbxproj16
-rw-r--r--lldb/source/Plugins/Process/Utility/ArchDefaultUnwindPlan-x86.cpp2
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp986
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h177
-rw-r--r--lldb/source/Plugins/Process/Utility/UnwindAssemblyProfiler-x86.cpp87
-rw-r--r--lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp141
-rw-r--r--lldb/source/Plugins/Process/Utility/UnwindLLDB.h70
-rw-r--r--lldb/source/Symbol/DWARFCallFrameInfo.cpp7
-rw-r--r--lldb/source/Symbol/FuncUnwinders.cpp20
-rw-r--r--lldb/source/Symbol/UnwindPlan.cpp41
-rw-r--r--lldb/source/Target/RegisterContext.cpp135
-rw-r--r--lldb/source/lldb-log.cpp2
-rw-r--r--lldb/source/lldb.cpp2
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 &regloc)
+{
+ 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 &regloc);
+
+ 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__
OpenPOWER on IntegriCloud