<rdar://problem/10645694>
authorGreg Clayton <gclayton@apple.com>
Sun, 8 Jan 2012 05:54:35 +0000 (05:54 +0000)
committerGreg Clayton <gclayton@apple.com>
Sun, 8 Jan 2012 05:54:35 +0000 (05:54 +0000)
Fixed an ARM backtracing issue where if the previous frame was a thumb
function and it was a tail call so that the current frame returned to
an address that would fall into the next function, we would use the
next function as the basis for how we unwound the previous frame's
registers and of course get things wrong. We now fix the PC code
address using the current ABI plug-in, and the ARM ABI plug-in has
been modified to correctly fix the code address. So when we do the
symbol context lookup, instead of taking an address like 0x1001 and
decrementing 1, and looking up the symbol context for a frame, we
now correctly fix 0x1001 to 0x1000, then decrement that by 1 to
get the correct symbol context.

I added a bunch more logging to "log enable lldb uwnind" to help
us in the future. We now log the PC, FP and SP (if they are available),
and we also dump the "active_row" that we find for unwinding a frame.

llvm-svn: 147747

lldb/include/lldb/Target/ABI.h
lldb/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h
lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp

index 722e38d..4709d79 100644 (file)
@@ -76,6 +76,15 @@ public:
     virtual bool
     CodeAddressIsValid (lldb::addr_t pc) = 0;    
 
+    virtual bool
+    FixCodeAddress (lldb::addr_t pc)
+    {
+        // Some targets might use bits in a code address to indicate
+        // a mode switch. ARM uses bit zero to signify a code address is
+        // thumb, so any ARM ABI plug-ins would strip those bits.
+        return pc;
+    }
+
     virtual const RegisterInfo *
     GetRegisterInfoArray (uint32_t &count) = 0;
 
index 70809e0..5516b59 100644 (file)
@@ -82,6 +82,14 @@ public:
         return pc <= UINT32_MAX;
     }
     
+    virtual bool
+    FixCodeAddress (lldb::addr_t pc)
+    {
+        // ARM uses bit zero to signify a code address is thumb, so we must
+        // strip bit zero in any code addresses.
+        return pc & ~(lldb::addr_t)1;
+    }
+
     virtual const lldb_private::RegisterInfo *
     GetRegisterInfoArray (uint32_t &count);
 
index 4f927fe..0faa8cc 100644 (file)
@@ -87,6 +87,8 @@ RegisterContextLLDB::InitializeZerothFrame()
 {
     StackFrameSP frame_sp (m_thread.GetStackFrameAtIndex (0));
 
+    LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+
     if (m_thread.GetRegisterContext() == NULL)
     {
         m_frame_type = eNotAValidFrame;
@@ -149,6 +151,13 @@ RegisterContextLLDB::InitializeZerothFrame()
     {
         active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
         row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
+        if (active_row && log)
+        {
+            StreamString active_row_strm;
+            active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(&m_thread.GetProcess().GetTarget()));
+            log->Printf("%*sFrame %u active row: %s",
+                        m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, active_row_strm.GetString().c_str());
+        }
     }
 
     if (active_row == NULL)
@@ -157,6 +166,7 @@ RegisterContextLLDB::InitializeZerothFrame()
         return;
     }
 
+    
     addr_t cfa_regval;
     if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval))
     {
@@ -170,7 +180,13 @@ RegisterContextLLDB::InitializeZerothFrame()
 
     m_cfa = cfa_regval + cfa_offset;
 
-    LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+    if (log)
+    {
+        log->Printf("%*sFrame %u cfa_regval = 0x%16.16llx (cfa_regval = 0x%16.16llx, cfa_offset = %i)",
+                    m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
+                    m_cfa, cfa_regval, cfa_offset);
+    }
+    
 
     // A couple of sanity checks..
     if (cfa_regval == LLDB_INVALID_ADDRESS || cfa_regval == 0 || cfa_regval == 1)
@@ -232,6 +248,20 @@ RegisterContextLLDB::InitializeNonZerothFrame()
         m_frame_type = eNotAValidFrame;
         return;
     }
+    
+    if (log)
+    {
+        log->Printf("%*sFrame %u pc = 0x%16.16llx",
+                    m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, pc);
+        addr_t reg_val;
+        if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP, reg_val))
+            log->Printf("%*sFrame %u fp = 0x%16.16llx",
+                        m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, reg_val);
+
+        if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, reg_val))
+            log->Printf("%*sFrame %u sp = 0x%16.16llx",
+                        m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, reg_val);
+    }
 
     // A pc of 0x0 means it's the end of the stack crawl
     if (pc == 0)
@@ -239,6 +269,12 @@ RegisterContextLLDB::InitializeNonZerothFrame()
         m_frame_type = eNotAValidFrame;
         return;
     }
+    
+    // Let ABIs fixup code addresses to make sure they are valid. In ARM ABIs
+    // this will strip bit zero in case we read a PC from memory or from the LR.   
+    ABI *abi = m_thread.GetProcess().GetABI().get();
+    if (abi)
+        pc = abi->FixCodeAddress(pc);
 
     // Test the pc value to see if we know it's in an unmapped/non-executable region of memory.
     uint32_t permissions;
@@ -277,7 +313,6 @@ RegisterContextLLDB::InitializeNonZerothFrame()
             log->Printf("%*sFrame %u using architectural default unwind method",
                         m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number);
         }
-        ABI *abi = m_thread.GetProcess().GetABI().get();
         if (abi)
         {
             m_fast_unwind_plan_sp.reset ();
@@ -452,6 +487,13 @@ RegisterContextLLDB::InitializeNonZerothFrame()
     {
         active_row = m_fast_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
         row_register_kind = m_fast_unwind_plan_sp->GetRegisterKind ();
+        if (active_row && log)
+        {
+            StreamString active_row_strm;
+            active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(&m_thread.GetProcess().GetTarget()));
+            log->Printf("%*sFrame %u active row: %s",
+                        m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, active_row_strm.GetString().c_str());
+        }
     }
     else 
     {
@@ -460,6 +502,13 @@ RegisterContextLLDB::InitializeNonZerothFrame()
         {
             active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
             row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
+            if (active_row && log)
+            {
+                StreamString active_row_strm;
+                active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(&m_thread.GetProcess().GetTarget()));
+                log->Printf("%*sFrame %u active row: %s",
+                            m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number, active_row_strm.GetString().c_str());
+            }
         }
     }
 
@@ -485,6 +534,13 @@ RegisterContextLLDB::InitializeNonZerothFrame()
 
     m_cfa = cfa_regval + cfa_offset;
 
+    if (log)
+    {
+        log->Printf("%*sFrame %u cfa_regval = 0x%16.16llx (cfa_regval = 0x%16.16llx, cfa_offset = %i)",
+                    m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
+                    m_cfa, cfa_regval, cfa_offset);
+    }
+
     // A couple of sanity checks..
     if (cfa_regval == LLDB_INVALID_ADDRESS || cfa_regval == 0 || cfa_regval == 1)
     {