[Lldb-commits] [lldb] r146551 - in /lldb/trunk: include/lldb/Target/DynamicLoader.h source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h source/Plugins/Process/Utility/RegisterContextLLDB.cpp

Jason Molenda jmolenda at apple.com
Tue Dec 13 20:22:18 PST 2011


Author: jmolenda
Date: Tue Dec 13 22:22:18 2011
New Revision: 146551

URL: http://llvm.org/viewvc/llvm-project?rev=146551&view=rev
Log:
On Mac OS X the Objective-C runtime (libobjc) has many critical
dispatch functions that are implemented in hand-written assembly.
There is also hand-written eh_frame instructions for unwinding
from these functions.

Normally we don't use eh_frame instructions for the currently
executing function, prefering the assembly instruction profiling
method.  But in these hand-written dispatch functions, the
profiling is doomed and we should use the eh_frame instructions.

Unfortunately there's no easy way to flag/extend the eh_frame/debug_frame
sections to annotate if the unwind instructions are accurate at
all addresses ("asynchronous") or if they are only accurate at locations
that can throw an exception ("synchronous" and the normal case for 
gcc/clang generated eh_frame/debug_frame CFI).

<rdar://problem/10508134>


Modified:
    lldb/trunk/include/lldb/Target/DynamicLoader.h
    lldb/trunk/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp
    lldb/trunk/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h
    lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp

Modified: lldb/trunk/include/lldb/Target/DynamicLoader.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/DynamicLoader.h?rev=146551&r1=146550&r2=146551&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/DynamicLoader.h (original)
+++ lldb/trunk/include/lldb/Target/DynamicLoader.h Tue Dec 13 22:22:18 2011
@@ -166,7 +166,7 @@
     {
         return 0;
     }
-    
+
     //------------------------------------------------------------------
     /// Ask if it is ok to try and load or unload an shared library 
     /// (image).
@@ -177,12 +177,40 @@
     /// sure it is an ok time to load a shared library.
     ///
     /// @return
-    ///     \b True if it is currently ok to try and load a shared 
+    ///     \b true if it is currently ok to try and load a shared 
     ///     library into the process, \b false otherwise.
     //------------------------------------------------------------------
     virtual Error
     CanLoadImage () = 0;
 
+    //------------------------------------------------------------------
+    /// Ask if the eh_frame information for the given SymbolContext should
+    /// be relied on even when it's the first frame in a stack unwind.
+    /// 
+    /// The CFI instructions from the eh_frame section are normally only
+    /// valid at call sites -- places where a program could throw an 
+    /// exception and need to unwind out.  But some Modules may be known 
+    /// to the system as having reliable eh_frame information at all call 
+    /// sites.  This would be the case if the Module's contents are largely
+    /// hand-written assembly with hand-written eh_frame information.
+    /// Normally when unwinding from a function at the beginning of a stack
+    /// unwind lldb will examine the assembly instructions to understand
+    /// how the stack frame is set up and where saved registers are stored.
+    /// But with hand-written assembly this is not reliable enough -- we need
+    /// to consult those function's hand-written eh_frame information.
+    ///
+    /// @return
+    ///     \b True if the symbol context should use eh_frame instructions
+    ///     unconditionally when unwinding from this frame.  Else \b false,
+    ///     the normal lldb unwind behavior of only using eh_frame when the
+    ///     function appears in the middle of the stack.
+    //------------------------------------------------------------------
+    virtual bool
+    AlwaysRelyOnEHUnwindInfo (SymbolContext &sym_ctx)
+    {
+       return false;
+    }
+
 protected:
     //------------------------------------------------------------------
     // Member variables.

Modified: lldb/trunk/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp?rev=146551&r1=146550&r2=146551&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp (original)
+++ lldb/trunk/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp Tue Dec 13 22:22:18 2011
@@ -1230,6 +1230,50 @@
 }
 
 //----------------------------------------------------------------------
+// On Mac OS X libobjc (the Objective-C runtime) has several critical dispatch
+// functions written in hand-written assembly, and also have hand-written unwind
+// information in the eh_frame section.  Normally we prefer analyzing the 
+// assembly instructions of a curently executing frame to unwind from that frame --
+// but on hand-written functions this profiling can fail.  We should use the
+// eh_frame instructions for these functions all the time.
+//
+// As an aside, it would be better if the eh_frame entries had a flag (or were
+// extensible so they could have an Apple-specific flag) which indicates that
+// the instructions are asynchronous -- accurate at every instruction, instead
+// of our normal default assumption that they are not.
+//----------------------------------------------------------------------
+
+bool
+DynamicLoaderMacOSXDYLD::AlwaysRelyOnEHUnwindInfo (SymbolContext &sym_ctx)
+{
+    ModuleSP module_sp;
+    if (sym_ctx.symbol)
+    {
+        AddressRange *ar = sym_ctx.symbol->GetAddressRangePtr();
+        if (ar)
+        {
+            module_sp = ar->GetBaseAddress().GetModule();
+        }
+    }
+    if (module_sp.get() == NULL && sym_ctx.function)
+    {
+        module_sp = sym_ctx.function->GetAddressRange().GetBaseAddress().GetModule();
+    }
+    if (module_sp.get() == NULL)
+        return false;
+
+    ObjCLanguageRuntime *objc_runtime = m_process->GetObjCLanguageRuntime();
+    if (objc_runtime != NULL && objc_runtime->IsModuleObjCLibrary (module_sp))
+    {
+        return true;
+    }
+
+    return false;
+}
+
+
+
+//----------------------------------------------------------------------
 // Dump a Segment to the file handle provided.
 //----------------------------------------------------------------------
 void

Modified: lldb/trunk/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h?rev=146551&r1=146550&r2=146551&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h (original)
+++ lldb/trunk/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h Tue Dec 13 22:22:18 2011
@@ -86,6 +86,9 @@
     virtual uint32_t
     GetPluginVersion();
 
+    virtual bool
+    AlwaysRelyOnEHUnwindInfo (lldb_private::SymbolContext &sym_ctx);
+
 protected:
     void
     PrivateInitialize (lldb_private::Process *process);

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=146551&r1=146550&r2=146551&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp Tue Dec 13 22:22:18 2011
@@ -26,6 +26,7 @@
 #include "lldb/Target/StackFrame.h"
 #include "lldb/Target/Target.h"
 #include "lldb/Target/Thread.h"
+#include "lldb/Target/DynamicLoader.h"
 
 #include "RegisterContextLLDB.h"
 
@@ -621,7 +622,7 @@
         }
     }
 
-    // No Module fm_current_pc.GetLoadAddress (&m_thread.GetProcess().GetTarget()or the current pc, try using the architecture default unwind.
+    // No Module for the current pc, try using the architecture default unwind.
     if (!m_current_pc.IsValid() || m_current_pc.GetModule() == NULL || m_current_pc.GetModule()->GetObjectFile() == NULL)
     {
         m_frame_type = eNormalFrame;
@@ -653,7 +654,28 @@
             return unwind_plan_sp;
     }
 
-    
+    // Ask the DynamicLoader if the eh_frame CFI should be trusted in this frame even when it's frame zero
+    // This comes up if we have hand-written functions in a Module and hand-written eh_frame.  The assembly
+    // instruction inspection may fail and the eh_frame CFI were probably written with some care to do the
+    // right thing.  It'd be nice if there was a way to ask the eh_frame directly if it is asynchronous
+    // (can be trusted at every instruction point) or synchronous (the normal case - only at call sites).
+    // But there is not.
+    if (m_thread.GetProcess().GetDynamicLoader() 
+        && m_thread.GetProcess().GetDynamicLoader()->AlwaysRelyOnEHUnwindInfo (m_sym_ctx))
+    {
+        unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one);
+        if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+        {
+            if (log && log->GetVerbose())
+            {
+                log->Printf("%*sFrame %u frame uses %s for full UnwindPlan because the DynamicLoader suggested we prefer it",
+                            m_frame_number < 100 ? m_frame_number : 100, "", m_frame_number,
+                            unwind_plan_sp->GetSourceName().GetCString());
+            }
+            return unwind_plan_sp;
+        }
+    }
+
     // Typically the NonCallSite UnwindPlan is the unwind created by inspecting the assembly language instructions
     if (behaves_like_zeroth_frame)
     {





More information about the lldb-commits mailing list