[Lldb-commits] [lldb] r121437 - in /lldb/trunk: include/lldb/Target/ lldb.xcodeproj/ source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/

Jim Ingham jingham at apple.com
Thu Dec 9 16:26:25 PST 2010


Author: jingham
Date: Thu Dec  9 18:26:25 2010
New Revision: 121437

URL: http://llvm.org/viewvc/llvm-project?rev=121437&view=rev
Log:
Changing the ObjC find method implementation to use a ClangUtilityFunction inserted into the target.  Consolidate all the
logic for finding the target of a method dispatch into this function, insert & call it.  Gets calls to super, and all the
fixup & fixedup variants working properly.  Also gets the class from the object so that we step through KVO wrapper methods
into the actual user code.

Modified:
    lldb/trunk/include/lldb/Target/ThreadPlanStepOut.h
    lldb/trunk/lldb.xcodeproj/project.pbxproj
    lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
    lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp
    lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h
    lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp
    lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h

Modified: lldb/trunk/include/lldb/Target/ThreadPlanStepOut.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/ThreadPlanStepOut.h?rev=121437&r1=121436&r2=121437&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/ThreadPlanStepOut.h (original)
+++ lldb/trunk/include/lldb/Target/ThreadPlanStepOut.h Thu Dec  9 18:26:25 2010
@@ -35,13 +35,13 @@
     virtual bool WillStop ();
     virtual bool MischiefManaged ();
 
-protected:
     ThreadPlanStepOut (Thread &thread,
                        SymbolContext *addr_context,
                        bool first_insn,
                        bool stop_others,
                        lldb::Vote stop_vote,
                        lldb::Vote run_vote);
+protected:
 
 private:
     SymbolContext *m_step_from_context;

Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=121437&r1=121436&r2=121437&view=diff
==============================================================================
--- lldb/trunk/lldb.xcodeproj/project.pbxproj (original)
+++ lldb/trunk/lldb.xcodeproj/project.pbxproj Thu Dec  9 18:26:25 2010
@@ -2459,7 +2459,6 @@
 			isa = PBXProject;
 			buildConfigurationList = 1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "lldb" */;
 			compatibilityVersion = "Xcode 3.1";
-			developmentRegion = English;
 			hasScannedForEncodings = 1;
 			knownRegions = (
 				en,

Modified: lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp?rev=121437&r1=121436&r2=121437&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp Thu Dec  9 18:26:25 2010
@@ -136,7 +136,7 @@
     if (m_has_object_getClass)
     {
         assert(snprintf(&buf->contents[0], sizeof(buf->contents),
-                        "extern \"C\" int gdb_object_getClass(void *);      \n"
+                        "extern \"C\" void *gdb_object_getClass(void *);      \n"
                         "extern \"C\" void                                  \n"
                         "%s(void *$__lldb_arg_obj)                          \n"
                         "{                                                  \n"
@@ -148,7 +148,7 @@
     else
     {
         assert(snprintf(&buf->contents[0], sizeof(buf->contents), 
-                        "extern \"C\" int gdb_class_getClass(void *);         \n"
+                        "extern \"C\" void *gdb_class_getClass(void *);         \n"
                         "extern \"C\" void                                    \n"
                         "%s(void *$__lldb_arg_obj)                            \n"
                         "{                                                    \n"

Modified: lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp?rev=121437&r1=121436&r2=121437&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp Thu Dec  9 18:26:25 2010
@@ -22,7 +22,6 @@
 #include "lldb/Core/Log.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/Value.h"
-#include "lldb/Expression/ClangFunction.h"
 #include "lldb/Symbol/ClangASTContext.h"
 #include "lldb/Target/ObjCLanguageRuntime.h"
 #include "lldb/Target/Process.h"
@@ -35,7 +34,117 @@
 using namespace lldb;
 using namespace lldb_private;
 
-        
+const char *AppleObjCTrampolineHandler::g_lookup_implementation_function_name = "__lldb_objc_find_implementation_for_selector";
+const char *AppleObjCTrampolineHandler::g_lookup_implementation_function_code = "                               \n\
+extern \"C\"                                                                                                    \n\
+{                                                                                                               \n\
+    extern void *class_getMethodImplementation(void *objc_class, void *sel);                                    \n\
+    extern void *class_getMethodImplementation_stret(void *objc_class, void *sel);                              \n\
+    extern void * sel_getUid(char *name);                                                                       \n\
+    extern int printf(const char *format, ...);                                                                 \n\
+}                                                                                                               \n\
+extern \"C\" void * __lldb_objc_find_implementation_for_selector (void *object,                                 \n\
+                                                    void *sel,                                                  \n\
+                                                    int is_stret,                                               \n\
+                                                    int is_super,                                               \n\
+                                                    int is_super2,                                              \n\
+                                                    int is_fixup,                                               \n\
+                                                    int is_fixed,                                               \n\
+                                                    int debug)                                                  \n\
+{                                                                                                               \n\
+    struct __lldb_imp_return_struct                                                                             \n\
+    {                                                                                                           \n\
+        void *class_addr;                                                                                       \n\
+        void *sel_addr;                                                                                         \n\
+        void *impl_addr;                                                                                        \n\
+    };                                                                                                          \n\
+                                                                                                                \n\
+    struct __lldb_objc_class {                                                                                  \n\
+        void *isa;                                                                                              \n\
+        void *super_ptr;                                                                                        \n\
+    };                                                                                                          \n\
+    struct __lldb_objc_super {                                                                                  \n\
+        void *reciever;                                                                                         \n\
+        struct __lldb_objc_class *class_ptr;                                                                    \n\
+    };                                                                                                          \n\
+    struct __lldb_msg_ref {                                                                                     \n\
+        void *dont_know;                                                                                        \n\
+        void *sel;                                                                                              \n\
+    };                                                                                                          \n\
+                                                                                                                \n\
+    struct __lldb_imp_return_struct return_struct;                                                              \n\
+                                                                                                                \n\
+    if (debug)                                                                                                  \n\
+        printf (\"\\n*** Called with obj: 0x%p sel: 0x%p is_stret: %d is_super: %d, \"                          \n\
+                \"is_super2: %d, is_fixup: %d, is_fixed: %d\\n\",                                               \n\
+                 object, sel, is_stret, is_super, is_super2, is_fixup, is_fixed);                               \n\
+    if (is_super)                                                                                               \n\
+    {                                                                                                           \n\
+        if (is_super2)                                                                                          \n\
+        {                                                                                                       \n\
+            return_struct.class_addr = ((__lldb_objc_super *) object)->class_ptr->super_ptr;                    \n\
+        }                                                                                                       \n\
+        else                                                                                                    \n\
+        {                                                                                                       \n\
+            return_struct.class_addr = ((__lldb_objc_super *) object)->class_ptr;                               \n\
+        }                                                                                                       \n\
+    }                                                                                                           \n\
+    else                                                                                                        \n\
+    {                                                                                                           \n\
+        void *class_ptr = (void *) [(id) object class];                                                         \n\
+        if (class_ptr == object)                                                                                \n\
+        {                                                                                                       \n\
+            struct __lldb_objc_class *class_as_class_struct = (struct __lldb_objc_class *) class_ptr;           \n\
+            if (debug)                                                                                          \n\
+                printf (\"Found a class object, need to return the meta class 0x%p -> 0x%p\\n\",                \n\
+                        class_ptr, class_as_class_struct->isa);                                                 \n\
+            return_struct.class_addr = class_as_class_struct->isa;                                              \n\
+        }                                                                                                       \n\
+        else                                                                                                    \n\
+        {                                                                                                       \n\
+            if (debug)                                                                                          \n\
+                printf (\"[object class] returned: 0x%p.\\n\", class_ptr);                                      \n\
+            return_struct.class_addr = class_ptr;                                                               \n\
+        }                                                                                                       \n\
+    }                                                                                                           \n\
+                                                                                                                \n\
+    if (is_fixup)                                                                                               \n\
+    {                                                                                                           \n\
+        if (is_fixed)                                                                                           \n\
+        {                                                                                                       \n\
+            return_struct.sel_addr = ((__lldb_msg_ref *) sel)->sel;                                             \n\
+        }                                                                                                       \n\
+        else                                                                                                    \n\
+        {                                                                                                       \n\
+            char *sel_name = (char *) ((__lldb_msg_ref *) sel)->sel;                                            \n\
+            return_struct.sel_addr = sel_getUid (sel_name);                                                     \n\
+            if (debug)                                                                                          \n\
+                printf (\"\\n*** Got fixed up selector: 0x%p for name %s.\\n\",                                 \n\
+                        return_struct.sel_addr, sel_name);                                                      \n\
+        }                                                                                                       \n\
+    }                                                                                                           \n\
+    else                                                                                                        \n\
+    {                                                                                                           \n\
+        return_struct.sel_addr = sel;                                                                           \n\
+    }                                                                                                           \n\
+                                                                                                                \n\
+    if (is_stret)                                                                                               \n\
+    {                                                                                                           \n\
+        return_struct.impl_addr = class_getMethodImplementation_stret (return_struct.class_addr,                \n\
+                                                                       return_struct.sel_addr);                 \n\
+    }                                                                                                           \n\
+    else                                                                                                        \n\
+    {                                                                                                           \n\
+        return_struct.impl_addr = class_getMethodImplementation (return_struct.class_addr,                      \n\
+                                                                       return_struct.sel_addr);                 \n\
+    }                                                                                                           \n\
+    if (debug)                                                                                                  \n\
+        printf (\"\\n*** Returning implementation: 0x%p.\\n\", return_struct.impl_addr);                        \n\
+                                                                                                                \n\
+    return return_struct.impl_addr;                                                                             \n\
+}                                                                                                               \n\
+";
+
 AppleObjCTrampolineHandler::AppleObjCVTables::VTableRegion::VTableRegion(AppleObjCVTables *owner, lldb::addr_t header_addr) :
     m_valid (true),
     m_owner(owner),
@@ -383,27 +492,27 @@
 const AppleObjCTrampolineHandler::DispatchFunction
 AppleObjCTrampolineHandler::g_dispatch_functions[] =
 {
-    // NAME                              STRET  SUPER  FIXUP TYPE
-    {"objc_msgSend",                     false, false, AppleObjCTrampolineHandler::DispatchFunction::eFixUpNone    },
-    {"objc_msgSend_fixup",               false, false, AppleObjCTrampolineHandler::DispatchFunction::eFixUpToFix   },
-    {"objc_msgSend_fixedup",             false, false, AppleObjCTrampolineHandler::DispatchFunction::eFixUpFixed   },
-    {"objc_msgSend_stret",               true,  false, AppleObjCTrampolineHandler::DispatchFunction::eFixUpNone    },
-    {"objc_msgSend_stret_fixup",         true,  false, AppleObjCTrampolineHandler::DispatchFunction::eFixUpToFix   },
-    {"objc_msgSend_stret_fixedup",       true,  false, AppleObjCTrampolineHandler::DispatchFunction::eFixUpFixed   },
-    {"objc_msgSend_fpret",               false, false, AppleObjCTrampolineHandler::DispatchFunction::eFixUpNone    },
-    {"objc_msgSend_fpret_fixup",         false, false, AppleObjCTrampolineHandler::DispatchFunction::eFixUpToFix   },
-    {"objc_msgSend_fpret_fixedup",       false, false, AppleObjCTrampolineHandler::DispatchFunction::eFixUpFixed   },
-    {"objc_msgSend_fp2ret",              false, false, AppleObjCTrampolineHandler::DispatchFunction::eFixUpNone    },
-    {"objc_msgSend_fp2ret_fixup",        false, false, AppleObjCTrampolineHandler::DispatchFunction::eFixUpToFix   },
-    {"objc_msgSend_fp2ret_fixedup",      false, false, AppleObjCTrampolineHandler::DispatchFunction::eFixUpFixed   },
-    {"objc_msgSendSuper",                false, true,  AppleObjCTrampolineHandler::DispatchFunction::eFixUpNone    },
-    {"objc_msgSendSuper_stret",          true,  true,  AppleObjCTrampolineHandler::DispatchFunction::eFixUpNone    },
-    {"objc_msgSendSuper2",               false, true,  AppleObjCTrampolineHandler::DispatchFunction::eFixUpNone    },
-    {"objc_msgSendSuper2_fixup",         false, true,  AppleObjCTrampolineHandler::DispatchFunction::eFixUpToFix   },
-    {"objc_msgSendSuper2_fixedup",       false, true,  AppleObjCTrampolineHandler::DispatchFunction::eFixUpFixed   },
-    {"objc_msgSendSuper2_stret",         true,  true,  AppleObjCTrampolineHandler::DispatchFunction::eFixUpNone    },
-    {"objc_msgSendSuper2_stret_fixup",   true,  true,  AppleObjCTrampolineHandler::DispatchFunction::eFixUpToFix   },
-    {"objc_msgSendSuper2_stret_fixedup", true,  true,  AppleObjCTrampolineHandler::DispatchFunction::eFixUpFixed   },
+    // NAME                              STRET  SUPER  SUPER2  FIXUP TYPE
+    {"objc_msgSend",                     false, false, false, DispatchFunction::eFixUpNone    },
+    {"objc_msgSend_fixup",               false, false, false, DispatchFunction::eFixUpToFix   },
+    {"objc_msgSend_fixedup",             false, false, false, DispatchFunction::eFixUpFixed   },
+    {"objc_msgSend_stret",               true,  false, false, DispatchFunction::eFixUpNone    },
+    {"objc_msgSend_stret_fixup",         true,  false, false, DispatchFunction::eFixUpToFix   },
+    {"objc_msgSend_stret_fixedup",       true,  false, false, DispatchFunction::eFixUpFixed   },
+    {"objc_msgSend_fpret",               false, false, false, DispatchFunction::eFixUpNone    },
+    {"objc_msgSend_fpret_fixup",         false, false, false, DispatchFunction::eFixUpToFix   },
+    {"objc_msgSend_fpret_fixedup",       false, false, false, DispatchFunction::eFixUpFixed   },
+    {"objc_msgSend_fp2ret",              false, false,  true, DispatchFunction::eFixUpNone    },
+    {"objc_msgSend_fp2ret_fixup",        false, false,  true, DispatchFunction::eFixUpToFix   },
+    {"objc_msgSend_fp2ret_fixedup",      false, false,  true, DispatchFunction::eFixUpFixed   },
+    {"objc_msgSendSuper",                false, true,  false, DispatchFunction::eFixUpNone    },
+    {"objc_msgSendSuper_stret",          true,  true,  false, DispatchFunction::eFixUpNone    },
+    {"objc_msgSendSuper2",               false, true,   true, DispatchFunction::eFixUpNone    },
+    {"objc_msgSendSuper2_fixup",         false, true,   true, DispatchFunction::eFixUpToFix   },
+    {"objc_msgSendSuper2_fixedup",       false, true,   true, DispatchFunction::eFixUpFixed   },
+    {"objc_msgSendSuper2_stret",         true,  true,   true, DispatchFunction::eFixUpNone    },
+    {"objc_msgSendSuper2_stret_fixup",   true,  true,   true, DispatchFunction::eFixUpToFix   },
+    {"objc_msgSendSuper2_stret_fixedup", true,  true,   true, DispatchFunction::eFixUpFixed   },
     {NULL}
 };
 
@@ -411,21 +520,30 @@
     m_process_sp (process_sp),
     m_objc_module_sp (objc_module_sp),
     m_impl_fn_addr (LLDB_INVALID_ADDRESS),
-    m_impl_stret_fn_addr (LLDB_INVALID_ADDRESS)
+    m_impl_stret_fn_addr (LLDB_INVALID_ADDRESS),
+    m_msg_forward_addr (LLDB_INVALID_ADDRESS)
 {
     // Look up the known resolution functions:
     
     ConstString get_impl_name("class_getMethodImplementation");
     ConstString get_impl_stret_name("class_getMethodImplementation_stret");
+    ConstString msg_forward_name("_objc_msgForward");
+    ConstString msg_forward_stret_name("_objc_msgForward_stret");
     
     Target *target = m_process_sp ? &m_process_sp->GetTarget() : NULL;
     const Symbol *class_getMethodImplementation = m_objc_module_sp->FindFirstSymbolWithNameAndType (get_impl_name, eSymbolTypeCode);
     const Symbol *class_getMethodImplementation_stret = m_objc_module_sp->FindFirstSymbolWithNameAndType (get_impl_stret_name, eSymbolTypeCode);
+    const Symbol *msg_forward = m_objc_module_sp->FindFirstSymbolWithNameAndType (msg_forward_name, eSymbolTypeCode);
+    const Symbol *msg_forward_stret = m_objc_module_sp->FindFirstSymbolWithNameAndType (msg_forward_stret_name, eSymbolTypeCode);
     
     if (class_getMethodImplementation)
         m_impl_fn_addr = class_getMethodImplementation->GetValue().GetLoadAddress(target);
     if  (class_getMethodImplementation_stret)
         m_impl_stret_fn_addr = class_getMethodImplementation_stret->GetValue().GetLoadAddress(target);
+    if (msg_forward)
+        m_msg_forward_addr = msg_forward->GetValue().GetLoadAddress(target);
+    if  (msg_forward_stret)
+        m_msg_forward_stret_addr = msg_forward_stret->GetValue().GetLoadAddress(target);
     
     // FIXME: Do some kind of logging here.
     if (m_impl_fn_addr == LLDB_INVALID_ADDRESS || m_impl_stret_fn_addr == LLDB_INVALID_ADDRESS)
@@ -467,6 +585,9 @@
     DispatchFunction this_dispatch;
     bool found_it = false;
     
+    // First step is to look and see if we are in one of the known ObjC dispatch functions.  We've already compiled
+    // a table of same, so consult it.
+    
     MsgsendMap::iterator pos;
     pos = m_msgSend_map.find (curr_pc);
     if (pos != m_msgSend_map.end())
@@ -475,6 +596,8 @@
         found_it = true;
     }
     
+    // Next check to see if we are in a vtable region:
+    
     if (!found_it)
     {
         uint32_t flags;
@@ -496,6 +619,8 @@
     {
         LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
 
+        // We are decoding a method dispatch.  
+        // First job is to pull the arguments out:
         
         lldb::StackFrameSP thread_cur_frame = thread.GetStackFrameAtIndex(0);
         
@@ -506,16 +631,12 @@
             
         Target *target = thread.CalculateTarget();
         
-        // FIXME: Since neither the value nor the Clang QualType know their ASTContext, 
-        // we have to make sure the type we put in our value list comes from the same ASTContext
-        // the ABI will use to get the argument values.  THis is the bottom-most frame's module.
-
         ClangASTContext *clang_ast_context = target->GetScratchClangASTContext();
         ValueList argument_values;
-        Value input_value;
-        void *clang_void_ptr_type = clang_ast_context->GetVoidPtrType(false);
-        input_value.SetValueType (Value::eValueTypeScalar);
-        input_value.SetContext (Value::eContextTypeClangType, clang_void_ptr_type);
+        Value void_ptr_value;
+        lldb::clang_type_t clang_void_ptr_type = clang_ast_context->GetVoidPtrType(false);
+        void_ptr_value.SetValueType (Value::eValueTypeScalar);
+        void_ptr_value.SetContext (Value::eContextTypeClangType, clang_void_ptr_type);
         
         int obj_index;
         int sel_index;
@@ -527,99 +648,185 @@
         {
             obj_index = 1;
             sel_index = 2;
-            argument_values.PushValue(input_value);
-            argument_values.PushValue(input_value);
-            argument_values.PushValue(input_value);
+            argument_values.PushValue(void_ptr_value);
+            argument_values.PushValue(void_ptr_value);
+            argument_values.PushValue(void_ptr_value);
         }
         else
         {
             obj_index = 0;
             sel_index = 1;
-            argument_values.PushValue(input_value);
-            argument_values.PushValue(input_value);
+            argument_values.PushValue(void_ptr_value);
+            argument_values.PushValue(void_ptr_value);
         }
 
         
         bool success = abi->GetArgumentValues (thread, argument_values);
         if (!success)
             return ret_plan_sp;
-        
-        // Okay, the first value here is the object, we actually want the class of that object.
-        // For now we're just going with the ISA.  
-        // FIXME: This should really be the return value of [object class] to properly handle KVO interposition.
-        
+            
+        // Pull the class out of the Object and see if we've already cached this method call,
+        // If so we can push a run-to-address plan directly.  Otherwise we have to figure out where
+        // the implementation lives.
+
         Value isa_value(*(argument_values.GetValueAtIndex(obj_index)));
-        
-        // This is a little cheesy, but since object->isa is the first field, 
+
+        // This is a little cheesy, but since object->isa is the first field,
         // making the object value a load address value and resolving it will get
         // the pointer sized data pointed to by that value...
-        ExecutionContext exec_ctx;
-        thread.CalculateExecutionContext (exec_ctx);
+        ExecutionContext exe_ctx;
+        thread.CalculateExecutionContext (exe_ctx);
 
         isa_value.SetValueType(Value::eValueTypeLoadAddress);
-        isa_value.ResolveValue(&exec_ctx, clang_ast_context->getASTContext());
-        
-        if (this_dispatch.fixedup == DispatchFunction::eFixUpFixed)
-        {
-            // For the FixedUp method the Selector is actually a pointer to a 
-            // structure, the second field of which is the selector number.
-            Value *sel_value = argument_values.GetValueAtIndex(sel_index);
-            sel_value->GetScalar() += process->GetAddressByteSize();
-            sel_value->SetValueType(Value::eValueTypeLoadAddress);
-            sel_value->ResolveValue(&exec_ctx, clang_ast_context->getASTContext());            
-        }
-        else if (this_dispatch.fixedup == DispatchFunction::eFixUpToFix)
-        {   
-            // FIXME: If the method dispatch is not "fixed up" then the selector is actually a
-            // pointer to the string name of the selector.  We need to look that up...
-            // For now I'm going to punt on that and just return no plan.
-            if (log)
-                log->Printf ("Punting on stepping into un-fixed-up method dispatch.");
-            return ret_plan_sp;
-        }
-        
-        // FIXME: If this is a dispatch to the super-class, we need to get the super-class from
-        // the class, and disaptch to that instead.
-        // But for now I just punt and return no plan.
-        if (this_dispatch.is_super)
-        {   
-            if (log)
-                log->Printf ("Punting on stepping into super method dispatch.");
-            return ret_plan_sp;
-        }
-        
-        ValueList dispatch_values;
-        dispatch_values.PushValue (isa_value);
-        dispatch_values.PushValue(*(argument_values.GetValueAtIndex(sel_index)));
-        
+        isa_value.ResolveValue(&exe_ctx, clang_ast_context->getASTContext());
+        lldb::addr_t isa_addr = isa_value.GetScalar().ULongLong();
+        lldb::addr_t sel_addr = argument_values.GetValueAtIndex(sel_index)->GetScalar().ULongLong();
+
         if (log)
         {
             log->Printf("Resolving method call for class - 0x%llx and selector - 0x%llx",
-                        dispatch_values.GetValueAtIndex(0)->GetScalar().ULongLong(),
-                        dispatch_values.GetValueAtIndex(1)->GetScalar().ULongLong());
+                        isa_addr, sel_addr);
         }
         ObjCLanguageRuntime *objc_runtime = m_process_sp->GetObjCLanguageRuntime ();
         assert(objc_runtime != NULL);
-        lldb::addr_t impl_addr = objc_runtime->LookupInMethodCache (dispatch_values.GetValueAtIndex(0)->GetScalar().ULongLong(),
-                                                dispatch_values.GetValueAtIndex(1)->GetScalar().ULongLong());
+        
+        lldb::addr_t impl_addr = objc_runtime->LookupInMethodCache (isa_addr, sel_addr);
                                                 
         if (impl_addr == LLDB_INVALID_ADDRESS)
-        {
-
-            Address resolve_address(NULL, this_dispatch.stret_return ? m_impl_stret_fn_addr : m_impl_fn_addr);
-            
+        {            
+            // We haven't seen this class/selector pair yet.  Look it up.
             StreamString errors;
+            Address impl_code_address;
+            
+            ValueList dispatch_values;
+            
+            // We've will inject a little function in the target that takes the object, selector and some flags,
+            // and figures out the implementation.  Looks like:
+            //      void *__lldb_objc_find_implementation_for_selector (void *object, 
+            //                                                          void *sel, 
+            //                                                          int is_stret, 
+            //                                                          int is_super, 
+            //                                                          int is_super2, 
+            //                                                          int is_fixup, 
+            //                                                          int is_fixed,
+            //                                                          int debug)
+            // So set up the arguments for that call.
+            
+            dispatch_values.PushValue (*(argument_values.GetValueAtIndex(obj_index)));
+            dispatch_values.PushValue (*(argument_values.GetValueAtIndex(sel_index)));
+            
+            Value flag_value;
+            lldb::clang_type_t clang_int_type = clang_ast_context->GetBuiltinTypeForEncodingAndBitSize(lldb::eEncodingSint, 32);
+            flag_value.SetValueType (Value::eValueTypeScalar);
+            flag_value.SetContext (Value::eContextTypeClangType, clang_int_type);
+            
+            if (this_dispatch.stret_return)
+                flag_value.GetScalar() = 1;
+            else
+                flag_value.GetScalar() = 0;
+            dispatch_values.PushValue (flag_value);
+                    
+            if (this_dispatch.is_super)
+                flag_value.GetScalar() = 1;
+            else
+                flag_value.GetScalar() = 0;
+            dispatch_values.PushValue (flag_value);
+                    
+            if (this_dispatch.is_super2)
+                flag_value.GetScalar() = 1;
+            else
+                flag_value.GetScalar() = 0;
+            dispatch_values.PushValue (flag_value);
+                    
+            switch (this_dispatch.fixedup)
+            {
+              case DispatchFunction::eFixUpNone:
+                 flag_value.GetScalar() = 0;
+                 dispatch_values.PushValue (flag_value);
+                 dispatch_values.PushValue (flag_value);
+                 break;
+              case DispatchFunction::eFixUpFixed:
+                 flag_value.GetScalar() = 1;
+                 dispatch_values.PushValue (flag_value);
+                 flag_value.GetScalar() = 1;
+                 dispatch_values.PushValue (flag_value);
+                 break;
+              case DispatchFunction::eFixUpToFix:
+                 flag_value.GetScalar() = 1;
+                 dispatch_values.PushValue (flag_value);
+                 flag_value.GetScalar() = 0;
+                 dispatch_values.PushValue (flag_value);
+                 break;
+            }
+            if (log) 
+                flag_value.GetScalar() = 1;
+            else
+                flag_value.GetScalar() = 0;  // FIXME - Set to 0 when debugging is done.
+                 dispatch_values.PushValue (flag_value);
+
+            // Now, if we haven't already, make and insert the function as a ClangUtilityFunction, and make and insert 
+            // it's runner ClangFunction.
             { 
                 // Scope for mutex locker:
                 Mutex::Locker locker(m_impl_function_mutex);
+                
+                // First stage is to make the ClangUtility to hold our injected function:
+
+#define USE_BUILTIN_FUNCTION 0  // Define this to 1 and we will use the get_implementation function found in the target.
+                                // This is useful for debugging additions to the get_impl function 'cause you don't have
+                                // to bother with string-ifying the code into g_lookup_implementation_function_code.
+                
+                if (USE_BUILTIN_FUNCTION)
+                {
+                    ConstString our_utility_function_name("__lldb_objc_find_implementation_for_selector");
+                    SymbolContextList sc_list;
+                    exe_ctx.target->GetImages().FindSymbolsWithNameAndType (our_utility_function_name, eSymbolTypeCode, sc_list);
+                    if (sc_list.GetSize() == 1)
+                    {
+                        SymbolContext sc;
+                        sc_list.GetContextAtIndex(0, sc);
+                        if (sc.symbol != NULL)
+                            impl_code_address = sc.symbol->GetValue();
+                            
+                        lldb::addr_t addr = impl_code_address.GetLoadAddress (exe_ctx.target);
+                        printf ("Getting address for our_utility_function: 0x%llx.\n", addr);
+                    }
+                    else
+                    {
+                        printf ("Could not find implementation function address.\n");
+                        return ret_plan_sp;
+                    }
+                }
+                else if (!m_impl_code.get())
+                {
+                    m_impl_code.reset (new ClangUtilityFunction (g_lookup_implementation_function_code,
+                                                                 g_lookup_implementation_function_name));
+                    if (!m_impl_code->Install(errors, exe_ctx))
+                    {
+                        if (log)
+                            log->Printf ("Failed to install implementation lookup: %s.", errors.GetData());
+                        m_impl_code.reset();
+                        return ret_plan_sp;
+                    }
+                    impl_code_address.Clear();
+                    impl_code_address.SetOffset(m_impl_code->StartAddress());
+                }
+                else
+                {
+                    impl_code_address.Clear();
+                    impl_code_address.SetOffset(m_impl_code->StartAddress());
+                }
+
+                // Next make the runner function for our implementation utility function.
                 if (!m_impl_function.get())
                 {
                      m_impl_function.reset(new ClangFunction(process->GetTargetTriple().GetCString(), 
                                                              clang_ast_context, 
                                                              clang_void_ptr_type, 
-                                                             resolve_address, 
+                                                             impl_code_address, 
                                                              dispatch_values));
-                            
+                    
+                    errors.Clear();        
                     unsigned num_errors = m_impl_function->CompileFunction(errors);
                     if (num_errors)
                     {
@@ -629,7 +836,7 @@
                     }
                     
                     errors.Clear();
-                    if (!m_impl_function->WriteFunctionWrapper(exec_ctx, errors))
+                    if (!m_impl_function->WriteFunctionWrapper(exe_ctx, errors))
                     {
                         if (log)
                             log->Printf ("Error Inserting function: \"%s\".", errors.GetData());
@@ -637,19 +844,21 @@
                     }
                 }
                 
-            }
+            } 
             
             errors.Clear();
             
-            // Now write down the argument values for this call.
+            // Now write down the argument values for this particular call.  This looks like it might be a race condition
+            // if other threads were calling into here, but actually it isn't because we allocate a new args structure for
+            // this call by passing args_addr = LLDB_INVALID_ADDRESS...
+
             lldb::addr_t args_addr = LLDB_INVALID_ADDRESS;
-            if (!m_impl_function->WriteFunctionArguments (exec_ctx, args_addr, resolve_address, dispatch_values, errors))
+            if (!m_impl_function->WriteFunctionArguments (exe_ctx, args_addr, impl_code_address, dispatch_values, errors))
                 return ret_plan_sp;
         
-            ret_plan_sp.reset (new AppleThreadPlanStepThroughObjCTrampoline (thread, this, args_addr, 
-                                                                        argument_values.GetValueAtIndex(0)->GetScalar().ULongLong(),
+            ret_plan_sp.reset (new AppleThreadPlanStepThroughObjCTrampoline (thread, this, args_addr,
                                                                         dispatch_values.GetValueAtIndex(0)->GetScalar().ULongLong(),
-                                                                        dispatch_values.GetValueAtIndex(1)->GetScalar().ULongLong(),
+                                                                        isa_addr, sel_addr,
                                                                         stop_others));
             if (log)
             {

Modified: lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h?rev=121437&r1=121436&r2=121437&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h Thu Dec  9 18:26:25 2010
@@ -18,6 +18,7 @@
 // Project includes
 #include "lldb/Expression/ClangExpression.h"
 #include "lldb/Expression/ClangFunction.h"
+#include "lldb/Expression/ClangUtilityFunction.h"
 #include "lldb/Host/Mutex.h"
 
 
@@ -38,6 +39,12 @@
     ClangFunction *
     GetLookupImplementationWrapperFunction ();
     
+    bool 
+    AddrIsMsgForward (lldb::addr_t addr) const
+    {
+        return (addr == m_msg_forward_addr || addr == m_msg_forward_stret_addr);
+    }
+
     
     struct DispatchFunction {
     public:
@@ -51,10 +58,13 @@
         const char *name;
         bool stret_return;
         bool is_super;
+        bool is_super2;
         FixUpState fixedup;
     };
     
 private:
+    static const char *g_lookup_implementation_function_name;
+    static const char *g_lookup_implementation_function_code;
 
     class AppleObjCVTables
     {
@@ -165,7 +175,7 @@
         {   
             return m_process_sp.get();
         }
-
+        
     private:
         ProcessSP m_process_sp;
         typedef std::vector<VTableRegion> region_collection;
@@ -182,11 +192,13 @@
     MsgsendMap m_msgSend_map;
     ProcessSP m_process_sp;
     ModuleSP m_objc_module_sp;
-    lldb::addr_t get_impl_addr;
     std::auto_ptr<ClangFunction> m_impl_function;
+    std::auto_ptr<ClangUtilityFunction> m_impl_code;
     Mutex m_impl_function_mutex;
     lldb::addr_t m_impl_fn_addr;
     lldb::addr_t m_impl_stret_fn_addr;
+    lldb::addr_t m_msg_forward_addr;
+    lldb::addr_t m_msg_forward_stret_addr;
     std::auto_ptr<AppleObjCVTables> m_vtables_ap;
     
      

Modified: lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp?rev=121437&r1=121436&r2=121437&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp Thu Dec  9 18:26:25 2010
@@ -20,6 +20,7 @@
 #include "lldb/Target/ExecutionContext.h"
 #include "lldb/Target/ObjCLanguageRuntime.h"
 #include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "lldb/Target/ThreadPlanStepOut.h"
 #include "lldb/Core/Log.h"
 
 using namespace lldb_private;
@@ -31,19 +32,19 @@
         Thread &thread, 
         AppleObjCTrampolineHandler *trampoline_handler, 
         lldb::addr_t args_addr, 
-        lldb::addr_t object_ptr, 
-        lldb::addr_t class_ptr, 
-        lldb::addr_t sel_ptr, 
+        lldb::addr_t object_addr,
+        lldb::addr_t isa_addr,
+        lldb::addr_t sel_addr,
         bool stop_others) :
     ThreadPlan (ThreadPlan::eKindGeneric, "MacOSX Step through ObjC Trampoline", thread, 
         lldb::eVoteNoOpinion, lldb::eVoteNoOpinion),
-    m_stop_others (stop_others),
-    m_object_ptr (object_ptr),
-    m_class_ptr (class_ptr),
-    m_sel_ptr (sel_ptr),
+    m_trampoline_handler (trampoline_handler),
     m_args_addr (args_addr),
-    m_objc_trampoline_handler (trampoline_handler),
-    m_impl_function (trampoline_handler->GetLookupImplementationWrapperFunction())
+    m_object_addr (object_addr),
+    m_isa_addr(isa_addr),
+    m_sel_addr(sel_addr),
+    m_impl_function (trampoline_handler->GetLookupImplementationWrapperFunction()),
+    m_stop_others (stop_others)
 {
     
 }
@@ -74,8 +75,8 @@
         s->Printf("Step through ObjC trampoline");
     else
     {
-        s->Printf ("Stepping to implementation of ObjC method - obj: 0x%llx class: 0x%llx selector: 0x%llx",
-        m_object_ptr, m_class_ptr, m_sel_ptr);
+        s->Printf ("Stepping to implementation of ObjC method - obj: 0x%llx, isa: 0x%llx, sel: 0x%llx",
+        m_object_addr, m_isa_addr, m_sel_addr);
     }
 }
                 
@@ -122,12 +123,26 @@
                 SetPlanComplete();
                 return true;
             }
+            if (m_trampoline_handler->AddrIsMsgForward(target_addr))
+            {
+                if (log)
+                    log->Printf ("Implementation lookup returned msgForward function: 0x%llx, stopping.", target_addr);
+
+                SymbolContext sc = m_thread.GetStackFrameAtIndex(0)->GetSymbolContext(eSymbolContextEverything);
+                m_run_to_sp.reset(new ThreadPlanStepOut(m_thread, &sc, true, m_stop_others, eVoteNoOpinion, eVoteNoOpinion));
+                m_thread.QueueThreadPlan(m_run_to_sp, false);
+                m_run_to_sp->SetPrivate(true);
+                return false;
+            }
+            
             if (log)
                 log->Printf("Running to ObjC method implementation: 0x%llx", target_addr);
             
             ObjCLanguageRuntime *objc_runtime = GetThread().GetProcess().GetObjCLanguageRuntime();
             assert (objc_runtime != NULL);
-            objc_runtime->AddToMethodCache (m_class_ptr, m_sel_ptr, target_addr);
+            objc_runtime->AddToMethodCache (m_isa_addr, m_sel_addr, target_addr);
+            if (log)
+                log->Printf("Adding {0x%llx, 0x%llx} = 0x%llx to cache.", m_isa_addr, m_sel_addr, target_addr);
 
             // Extract the target address from the value:
             

Modified: lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h?rev=121437&r1=121436&r2=121437&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h Thu Dec  9 18:26:25 2010
@@ -29,12 +29,12 @@
 	// Constructors and Destructors
 	//------------------------------------------------------------------
 	AppleThreadPlanStepThroughObjCTrampoline(Thread &thread, 
-                                        AppleObjCTrampolineHandler *trampoline_handler, 
-                                        lldb::addr_t args_addr, 
-                                        lldb::addr_t object_ptr, 
-                                        lldb::addr_t class_ptr, 
-                                        lldb::addr_t sel_ptr, 
-                                        bool stop_others);
+                                             AppleObjCTrampolineHandler *trampoline_handler, 
+                                             lldb::addr_t args_addr, 
+                                             lldb::addr_t object_addr,
+                                             lldb::addr_t isa_addr,
+                                             lldb::addr_t sel_addr,
+                                             bool stop_others);
     
 	virtual ~AppleThreadPlanStepThroughObjCTrampoline();
 
@@ -77,18 +77,17 @@
 	//------------------------------------------------------------------
 	// For AppleThreadPlanStepThroughObjCTrampoline only
 	//------------------------------------------------------------------
-    bool m_stop_others;
-    lldb::addr_t m_object_ptr;
-    lldb::addr_t m_class_ptr;
-    lldb::addr_t m_sel_ptr;
-
+    AppleObjCTrampolineHandler *m_trampoline_handler; // FIXME - ensure this doesn't go away on us?  SP maybe?
+    lldb::addr_t m_args_addr;     // Stores the address for our step through function result structure.
+    lldb::addr_t m_object_addr;  // This is only for Description.
+    lldb::addr_t m_isa_addr;     // isa_addr and sel_addr are the keys we will use to cache the implementation.
+    lldb::addr_t m_sel_addr;
     ThreadPlanSP m_func_sp;       // This is the function call plan.  We fill it at start, then set it
                                   // to NULL when this plan is done.  That way we know to go to:
-    lldb::addr_t m_args_addr;     // Stores the address for our step through function result structure.
     ThreadPlanSP m_run_to_sp;     // The plan that runs to the target.
-    AppleObjCTrampolineHandler *m_objc_trampoline_handler;
     ClangFunction *m_impl_function;  // This is a pointer to a impl function that 
                                      // is owned by the client that pushes this plan.
+    bool m_stop_others;
 };
 
 } // namespace lldb_private





More information about the lldb-commits mailing list