[Lldb-commits] [lldb] r117256 - in /lldb/trunk: include/lldb/ include/lldb/Symbol/ include/lldb/Target/ lldb.xcodeproj/ source/ source/Plugins/Process/Utility/ source/Symbol/ source/Target/

Jason Molenda jmolenda at apple.com
Mon Oct 25 04:12:08 PDT 2010


Author: jmolenda
Date: Mon Oct 25 06:12:07 2010
New Revision: 117256

URL: http://llvm.org/viewvc/llvm-project?rev=117256&view=rev
Log:
Check in the native lldb unwinder.  

Not yet enabled as the default unwinder but there are no known
backtrace problems with the code at this point.

Added 'log enable lldb unwind' to help diagnose backtrace problems;
this output needs a little refining but it's a good first step.

eh_frame information is currently read unconditionally - the code
is structured to allow this to be delayed until it's actually needed.
There is a performance hit when you have to parse the eh_frame
information for any largeish executable/library so it's necessary
to avoid if possible.

It's confusing having both the UnwindPlan::RegisterLocation struct
and the RegisterConextLLDB::RegisterLocation struct, I need to rename
one of them.

The writing of registers isn't done in the RegisterConextLLDB subclass
yet; neither is the running of complex DWARF expressions from eh_frame
(e.g. used for _sigtramp on Mac OS X).


Added:
    lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
    lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h
    lldb/trunk/source/Plugins/Process/Utility/UnwindLLDB.cpp
    lldb/trunk/source/Plugins/Process/Utility/UnwindLLDB.h
Modified:
    lldb/trunk/include/lldb/Symbol/UnwindPlan.h
    lldb/trunk/include/lldb/Target/RegisterContext.h
    lldb/trunk/include/lldb/lldb-private-log.h
    lldb/trunk/lldb.xcodeproj/project.pbxproj
    lldb/trunk/source/Plugins/Process/Utility/ArchDefaultUnwindPlan-x86.cpp
    lldb/trunk/source/Plugins/Process/Utility/UnwindAssemblyProfiler-x86.cpp
    lldb/trunk/source/Symbol/DWARFCallFrameInfo.cpp
    lldb/trunk/source/Symbol/FuncUnwinders.cpp
    lldb/trunk/source/Symbol/UnwindPlan.cpp
    lldb/trunk/source/Target/RegisterContext.cpp
    lldb/trunk/source/lldb-log.cpp
    lldb/trunk/source/lldb.cpp

Modified: lldb/trunk/include/lldb/Symbol/UnwindPlan.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/UnwindPlan.h?rev=117256&r1=117255&r2=117256&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Symbol/UnwindPlan.h (original)
+++ lldb/trunk/include/lldb/Symbol/UnwindPlan.h Mon Oct 25 06:12:07 2010
@@ -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 @@
     
             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 @@
             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:
 
-    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 @@
     const UnwindPlan::Row&
     GetRowAtIndex (uint32_t idx) const;
 
+    lldb_private::ConstString
+    GetSourceName () const;
+
+    void
+    SetSourceName (const char *);
+
     int
     GetRowCount () const;
 
@@ -217,6 +252,7 @@
     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

Modified: lldb/trunk/include/lldb/Target/RegisterContext.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/RegisterContext.h?rev=117256&r1=117255&r2=117256&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/RegisterContext.h (original)
+++ lldb/trunk/include/lldb/Target/RegisterContext.h Mon Oct 25 06:12:07 2010
@@ -28,6 +28,8 @@
     //------------------------------------------------------------------
     RegisterContext (Thread &thread, StackFrame *frame);
 
+    RegisterContext (Thread &thread);
+
     virtual
     ~RegisterContext ();
 
@@ -50,18 +52,12 @@
     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 @@
     //------------------------------------------------------------------
     // 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 @@
     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

Modified: lldb/trunk/include/lldb/lldb-private-log.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-private-log.h?rev=117256&r1=117255&r2=117256&view=diff
==============================================================================
--- lldb/trunk/include/lldb/lldb-private-log.h (original)
+++ lldb/trunk/include/lldb/lldb-private-log.h Mon Oct 25 06:12:07 2010
@@ -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      |\

Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=117256&r1=117255&r2=117256&view=diff
==============================================================================
--- lldb/trunk/lldb.xcodeproj/project.pbxproj (original)
+++ lldb/trunk/lldb.xcodeproj/project.pbxproj Mon Oct 25 06:12:07 2010
@@ -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 */,
 			);

Modified: lldb/trunk/source/Plugins/Process/Utility/ArchDefaultUnwindPlan-x86.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/ArchDefaultUnwindPlan-x86.cpp?rev=117256&r1=117255&r2=117256&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/ArchDefaultUnwindPlan-x86.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Utility/ArchDefaultUnwindPlan-x86.cpp Mon Oct 25 06:12:07 2010
@@ -64,6 +64,7 @@
     row.SetRegisterInfo (LLDB_REGNUM_GENERIC_SP, regloc);
 
     m_32bit_default.AppendRow (row);
+    m_32bit_default.SetSourceName ("architectural default");
 
     row.Clear();
 
@@ -80,6 +81,7 @@
     row.SetRegisterInfo (LLDB_REGNUM_GENERIC_SP, regloc);
 
     m_64bit_default.AppendRow (row);
+    m_64bit_default.SetSourceName ("architectural default");
 }
 
 

Added: lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp?rev=117256&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp (added)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp Mon Oct 25 06:12:07 2010
@@ -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;
+    }
+}

Added: lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h?rev=117256&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h (added)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h Mon Oct 25 06:12:07 2010
@@ -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_

Modified: lldb/trunk/source/Plugins/Process/Utility/UnwindAssemblyProfiler-x86.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/UnwindAssemblyProfiler-x86.cpp?rev=117256&r1=117255&r2=117256&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/UnwindAssemblyProfiler-x86.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Utility/UnwindAssemblyProfiler-x86.cpp Mon Oct 25 06:12:07 2010
@@ -125,7 +125,7 @@
 
     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 @@
 
 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 @@
 
     if (EDGetDisassembler (&disasm, "i386-apple-darwin", kEDAssemblySyntaxX86ATT) != 0)
     {
-        false;
+        return false;
     }
 
     uint64_t addr_offset = addr.GetOffset();
@@ -498,7 +498,7 @@
     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 @@
             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 @@
         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 @@
 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

Added: lldb/trunk/source/Plugins/Process/Utility/UnwindLLDB.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/UnwindLLDB.cpp?rev=117256&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/UnwindLLDB.cpp (added)
+++ lldb/trunk/source/Plugins/Process/Utility/UnwindLLDB.cpp Mon Oct 25 06:12:07 2010
@@ -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;
+}

Added: lldb/trunk/source/Plugins/Process/Utility/UnwindLLDB.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/UnwindLLDB.h?rev=117256&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/UnwindLLDB.h (added)
+++ lldb/trunk/source/Plugins/Process/Utility/UnwindLLDB.h Mon Oct 25 06:12:07 2010
@@ -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_

Modified: lldb/trunk/source/Symbol/DWARFCallFrameInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/DWARFCallFrameInfo.cpp?rev=117256&r1=117255&r2=117256&view=diff
==============================================================================
--- lldb/trunk/source/Symbol/DWARFCallFrameInfo.cpp (original)
+++ lldb/trunk/source/Symbol/DWARFCallFrameInfo.cpp Mon Oct 25 06:12:07 2010
@@ -347,7 +347,14 @@
     // 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);

Modified: lldb/trunk/source/Symbol/FuncUnwinders.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/FuncUnwinders.cpp?rev=117256&r1=117255&r2=117256&view=diff
==============================================================================
--- lldb/trunk/source/Symbol/FuncUnwinders.cpp (original)
+++ lldb/trunk/source/Symbol/FuncUnwinders.cpp Mon Oct 25 06:12:07 2010
@@ -71,9 +71,14 @@
 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 @@
 {
     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;
 }
 

Modified: lldb/trunk/source/Symbol/UnwindPlan.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/UnwindPlan.cpp?rev=117256&r1=117255&r2=117256&view=diff
==============================================================================
--- lldb/trunk/source/Symbol/UnwindPlan.cpp (original)
+++ lldb/trunk/source/Symbol/UnwindPlan.cpp Mon Oct 25 06:12:07 2010
@@ -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 @@
 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 @@
 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 @@
 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 @@
 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 @@
         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;
+}

Modified: lldb/trunk/source/Target/RegisterContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/RegisterContext.cpp?rev=117256&r1=117255&r2=117256&view=diff
==============================================================================
--- lldb/trunk/source/Target/RegisterContext.cpp (original)
+++ lldb/trunk/source/Target/RegisterContext.cpp Mon Oct 25 06:12:07 2010
@@ -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_private;
 
 //----------------------------------------------------------------------
-// RegisterContext constructor
+// RegisterContext constructors
 //----------------------------------------------------------------------
 RegisterContext::RegisterContext (Thread &thread, StackFrame *frame) :
     m_thread (thread),
@@ -29,6 +30,12 @@
 {
 }
 
+RegisterContext::RegisterContext (Thread &thread) :
+    m_thread (thread),
+    m_frame (NULL)
+{
+}
+
 //----------------------------------------------------------------------
 // Destructor
 //----------------------------------------------------------------------
@@ -200,6 +207,12 @@
     return false;
 }
 
+void
+RegisterContext::SetStackFrame (StackFrame *frame)
+{
+    m_frame = frame;
+}
+
 Target *
 RegisterContext::CalculateTarget ()
 {
@@ -236,7 +249,7 @@
 
 
 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 @@
     }
     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);
+}

Modified: lldb/trunk/source/lldb-log.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/lldb-log.cpp?rev=117256&r1=117255&r2=117256&view=diff
==============================================================================
--- lldb/trunk/source/lldb-log.cpp (original)
+++ lldb/trunk/source/lldb-log.cpp Mon Oct 25 06:12:07 2010
@@ -152,6 +152,7 @@
             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 @@
         "\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");
 }

Modified: lldb/trunk/source/lldb.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/lldb.cpp?rev=117256&r1=117255&r2=117256&view=diff
==============================================================================
--- lldb/trunk/source/lldb.cpp (original)
+++ lldb/trunk/source/lldb.cpp Mon Oct 25 06:12:07 2010
@@ -69,6 +69,7 @@
         SymbolFileDWARFDebugMap::Initialize();
         SymbolFileSymtab::Initialize();
         UnwindAssemblyProfiler_x86::Initialize();
+        ArchDefaultUnwindPlan_x86::Initialize();
         ArchVolatileRegs_x86::Initialize();
 
 #ifdef __APPLE__
@@ -110,6 +111,7 @@
     SymbolFileDWARFDebugMap::Terminate();
     SymbolFileSymtab::Terminate();
     UnwindAssemblyProfiler_x86::Terminate();
+    ArchDefaultUnwindPlan_x86::Terminate();
     ArchVolatileRegs_x86::Terminate();
 
 #ifdef __APPLE__





More information about the lldb-commits mailing list