[Lldb-commits] [lldb] r118882 - in /lldb/trunk: include/lldb/Symbol/FuncUnwinders.h source/Plugins/Process/Utility/RegisterContextLLDB.cpp source/Plugins/Process/Utility/RegisterContextLLDB.h source/Symbol/FuncUnwinders.cpp

Jason Molenda jmolenda at apple.com
Thu Nov 11 21:23:10 PST 2010


Author: jmolenda
Date: Thu Nov 11 23:23:10 2010
New Revision: 118882

URL: http://llvm.org/viewvc/llvm-project?rev=118882&view=rev
Log:
I'm not thrilled with how I structured this but RegisterContextLLDB
needs to use the current pc and current offset in two ways:  To 
determine which function we are currently executing, and the decide
how much of that function has executed so far.  For the former use,
we need to back up the saved pc value by one byte if we're going to
use the correct function's unwind information -- we may be executing
a CALL instruction at the end of a function and the following instruction
belongs to a new function, or we may be looking at unwind information
which only covers the call instruction and not the subsequent instruction.

But when we're talking about deciding which row of an UnwindPlan to
execute, we want to use the actual byte offset in the function, not the
byte offset - 1.

Right now RegisterContextLLDB is tracking both the "real" offset and
an "offset minus one" and different parts of the class have to know 
which one to use and they need to be updated/set in tandem.  I want
to revisit this at some point.

The second change made in looking up eh_frame information; it was
formerly done by looking for the start address of the function we
are currently executing.  But it is possible to have unwind information
for a function which only covers a small section of the function's
address range.  In which case looking up by the start pc value may not
find the eh_frame FDE.

The hand-written _sigtramp() unwind info on Mac OS X, which covers
exactly one instruction in the middle of the function, happens to
trigger both of these issues.

I still need to get the UnwindPlan runner to handle arbitrary dwarf
expressions in the FDE but there's a good chance it will be easy to
reuse the DWARFExpression class to do this.


Modified:
    lldb/trunk/include/lldb/Symbol/FuncUnwinders.h
    lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
    lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h
    lldb/trunk/source/Symbol/FuncUnwinders.cpp

Modified: lldb/trunk/include/lldb/Symbol/FuncUnwinders.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/FuncUnwinders.h?rev=118882&r1=118881&r2=118882&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Symbol/FuncUnwinders.h (original)
+++ lldb/trunk/include/lldb/Symbol/FuncUnwinders.h Thu Nov 11 23:23:10 2010
@@ -37,8 +37,13 @@
 
     ~FuncUnwinders ();
 
+    // current_offset is the byte offset into the function.
+    // 0 means no instructions have executed yet.  -1 means the offset is unknown.
+    // On architectures where the pc points to the next instruction that will execute, this
+    // offset value will have already been decremented by 1 to stay within the bounds of the 
+    // correct function body.
     UnwindPlan*
-    GetUnwindPlanAtCallSite ();
+    GetUnwindPlanAtCallSite (int current_offset);
 
     UnwindPlan*
     GetUnwindPlanAtNonCallSite (lldb_private::Thread& thread);

Modified: lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp?rev=118882&r1=118881&r2=118882&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp Thu Nov 11 23:23:10 2010
@@ -35,7 +35,7 @@
     m_sym_ctx(sym_ctx), m_all_registers_available(false), m_registers(),
     m_cfa (LLDB_INVALID_ADDRESS), m_start_pc (), m_current_pc (), m_frame_number (frame_number),
     m_full_unwind_plan(NULL), m_fast_unwind_plan(NULL), m_base_reg_ctx (), m_frame_type (-1), 
-    m_current_offset (0), m_sym_ctx_valid (false)
+    m_current_offset (0), m_current_offset_backed_up_one (0), m_sym_ctx_valid (false)
 {
     m_sym_ctx.Clear();
     m_sym_ctx_valid = false;
@@ -107,11 +107,13 @@
     {
         m_start_pc = addr_range.GetBaseAddress();
         m_current_offset = frame_sp->GetFrameCodeAddress().GetOffset() - m_start_pc.GetOffset();
+        m_current_offset_backed_up_one = m_current_offset;
     }
     else
     {
         m_start_pc = m_current_pc;
         m_current_offset = -1;
+        m_current_offset_backed_up_one = -1;
     }
 
     // We've set m_frame_type and m_sym_ctx before these calls.
@@ -224,6 +226,7 @@
             m_frame_type = eNormalFrame;
             m_all_registers_available = false;
             m_current_offset = -1;
+            m_current_offset_backed_up_one = -1;
             addr_t cfa_regval;
             int row_register_kind = m_full_unwind_plan->GetRegisterKind ();
             uint32_t cfa_regnum = m_full_unwind_plan->GetRowForFunctionOffset(0)->GetCFARegister();
@@ -276,16 +279,42 @@
         m_sym_ctx_valid = false;
     }
 
-    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;
+    bool decr_pc_and_recompute_addr_range = false;
+
+    // If the symbol lookup failed...
+    if (m_sym_ctx_valid == false)
+       decr_pc_and_recompute_addr_range = true;
+
+    // Or if we're in the middle of the stack (and not "above" an asynchornous event like sigtramp),
+    // and our "current" pc is the start of a function...
+    if (m_sym_ctx_valid
+        && ((RegisterContextLLDB*) m_next_frame.get())->m_frame_type != eSigtrampFrame
+        && ((RegisterContextLLDB*) m_next_frame.get())->m_frame_type != eDebuggerFrame
+        && addr_range.GetBaseAddress().IsValid()
+        && addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection()
+        && addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset())
+    {
+        decr_pc_and_recompute_addr_range = true;
+    }
+
+    // We need to back up the pc by 1 byte and re-search for the Symbol to handle the case where the "saved pc"
+    // value is pointing to the next function, e.g. if a function ends with a CALL instruction.
+    // FIXME this may need to be an architectural-dependent behavior; if so we'll need to add a member function
+    // to the ABI plugin and consult that.
+    if (decr_pc_and_recompute_addr_range) 
+    {
+        Address temporary_pc(m_current_pc);
+        temporary_pc.SetOffset(m_current_pc.GetOffset() - 1);
+        m_sym_ctx.Clear();
+        m_sym_ctx_valid = false;
+        if ((m_current_pc.GetModule()->ResolveSymbolContextForAddress (temporary_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol)
+        {
+            m_sym_ctx_valid = true;
+        }
+        if (!m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, addr_range))
+        {
+            m_sym_ctx_valid = false;
+        }
     }
 
     // If we were able to find a symbol/function, set addr_range_ptr to the bounds of that symbol/function.
@@ -294,11 +323,27 @@
     {
         m_start_pc = addr_range.GetBaseAddress();
         m_current_offset = m_current_pc.GetOffset() - m_start_pc.GetOffset();
+        m_current_offset_backed_up_one = m_current_offset;
+        if (decr_pc_and_recompute_addr_range && m_current_offset_backed_up_one > 0)
+            m_current_offset_backed_up_one--;
     }
     else
     {
         m_start_pc = m_current_pc;
         m_current_offset = -1;
+        m_current_offset_backed_up_one = -1;
+    }
+
+    static ConstString sigtramp_name ("_sigtramp");
+    if ((m_sym_ctx.function && m_sym_ctx.function->GetMangled().GetMangledName() == sigtramp_name)
+        || (m_sym_ctx.symbol && m_sym_ctx.symbol->GetMangled().GetMangledName() == sigtramp_name))
+    {
+        m_frame_type = eSigtrampFrame;
+    }
+    else
+    {
+        // FIXME:  Detect eDebuggerFrame here.
+        m_frame_type = eNormalFrame;
     }
 
     // We've set m_frame_type and m_sym_ctx before this call.
@@ -386,6 +431,7 @@
 //   1. m_frame_type should already be set to eSigtrampFrame/eDebuggerFrame if either of those are correct, 
 //   2. m_sym_ctx should already be filled in, and
 //   3. m_current_pc should have the current pc value for this frame
+//   4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown
 
 UnwindPlan *
 RegisterContextLLDB::GetFastUnwindPlanForFrame ()
@@ -437,6 +483,7 @@
 //   1. m_frame_type should already be set to eSigtrampFrame/eDebuggerFrame if either of those are correct, 
 //   2. m_sym_ctx should already be filled in, and
 //   3. m_current_pc should have the current pc value for this frame
+//   4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown
 
 UnwindPlan *
 RegisterContextLLDB::GetFullUnwindPlanForFrame ()
@@ -499,8 +546,8 @@
     if (m_frame_type == eSigtrampFrame)
     {
         m_fast_unwind_plan = NULL;
-        up = fu->GetUnwindPlanAtCallSite ();
-        if (up->PlanValidAtAddress (m_current_pc))
+        up = fu->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one);
+        if (up && up->PlanValidAtAddress (m_current_pc))
         {
             return up;
         }
@@ -521,7 +568,7 @@
     }
 
     // Typically this is unwind info from an eh_frame section intended for exception handling; only valid at call sites
-    up = fu->GetUnwindPlanAtCallSite ();
+    up = fu->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one);
     if (up && up->PlanValidAtAddress (m_current_pc))
     {
         if (log && IsLogVerbose())

Modified: lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h?rev=118882&r1=118881&r2=118882&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h Thu Nov 11 23:23:10 2010
@@ -167,16 +167,27 @@
     lldb_private::UnwindPlan *m_full_unwind_plan;
     bool m_all_registers_available;               // Can we retrieve all regs or just nonvolatile regs?
     int m_frame_type;                             // enum FrameType
+
+    lldb::addr_t m_cfa;
+    lldb_private::Address m_start_pc;
+    lldb_private::Address m_current_pc;
+
     int m_current_offset;                         // how far into the function we've executed; -1 if unknown
+                                                  // 0 if no instructions have been executed yet.
+
+    int m_current_offset_backed_up_one;           // how far into the function we've executed; -1 if unknown
+                                                  // 0 if no instructions have been executed yet.
+                                                  // On architectures where the return address on the stack points
+                                                  // to the instruction after the CALL, this value will have 1 
+                                                  // subtracted from it.  Else a function that ends in a CALL will
+                                                  // have an offset pointing into the next function's address range.
+                                                  // m_current_pc has the actual address of the "current" pc.
+
     lldb_private::SymbolContext& m_sym_ctx;
     bool m_sym_ctx_valid;                         // if ResolveSymbolContextForAddress fails, don't try to use 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;
-    lldb_private::Address m_current_pc;
-
     std::map<uint32_t, RegisterLocation> m_registers; // where to find reg values for this frame
 
     //------------------------------------------------------------------

Modified: lldb/trunk/source/Symbol/FuncUnwinders.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/FuncUnwinders.cpp?rev=118882&r1=118881&r2=118882&view=diff
==============================================================================
--- lldb/trunk/source/Symbol/FuncUnwinders.cpp (original)
+++ lldb/trunk/source/Symbol/FuncUnwinders.cpp Thu Nov 11 23:23:10 2010
@@ -47,24 +47,39 @@
 }
 
 UnwindPlan*
-FuncUnwinders::GetUnwindPlanAtCallSite ()
+FuncUnwinders::GetUnwindPlanAtCallSite (int current_offset)
 {
     if (m_unwind_at_call_site != NULL)
         return m_unwind_at_call_site;
     if (!m_range.GetBaseAddress().IsValid())
         return NULL;
 
+    // We have cases (e.g. with _sigtramp on Mac OS X) where the hand-written eh_frame unwind info for a
+    // function does not cover the entire range of the function and so the FDE only lists a subset of the
+    // address range.  If we try to look up the unwind info by the starting address of the function 
+    // (i.e. m_range.GetBaseAddress()) we may not find the eh_frame FDE.  We need to use the actual byte offset
+    // into the function when looking it up.
+
+    Address current_pc (m_range.GetBaseAddress ());
+    if (current_offset != -1)
+        current_pc.SetOffset (current_pc.GetOffset() + current_offset);
+
     DWARFCallFrameInfo *eh_frame = m_unwind_table.GetEHFrameInfo();
+    UnwindPlan *up = NULL;
     if (eh_frame)
     {
-        UnwindPlan *up = new UnwindPlan;
-        if (eh_frame->GetUnwindPlan (m_range.GetBaseAddress (), *up) == true)
+        up = new UnwindPlan;
+        if (!eh_frame->GetUnwindPlan (current_pc, *up))
         {
-            m_unwind_at_call_site = up;
-            return m_unwind_at_call_site;
+            delete up;
+            return NULL;
         }
     }
-    return NULL;
+    if (!up)
+        return NULL;
+
+    m_unwind_at_call_site = up;
+    return m_unwind_at_call_site;
 }
 
 UnwindPlan*





More information about the lldb-commits mailing list