From dffa9773ce7788b76c945960636987508fe1be8e Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Wed, 20 Feb 2013 20:35:38 +0000 Subject: [PATCH] Handle the case where the runtime uses class_getMethodImplementation for both scalar and structure return methods. rdar://problem/13238168 llvm-svn: 175662 --- .../AppleObjCTrampolineHandler.cpp | 146 +++++++++++++++++- .../AppleObjCTrampolineHandler.h | 2 + 2 files changed, 140 insertions(+), 8 deletions(-) diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp index 8f31d8418e7b..5cc611eeae99 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp @@ -43,7 +43,8 @@ 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\ +const char *AppleObjCTrampolineHandler::g_lookup_implementation_function_code = NULL; +const char *AppleObjCTrampolineHandler::g_lookup_implementation_with_stret_function_code = " \n\ extern \"C\" \n\ { \n\ extern void *class_getMethodImplementation(void *objc_class, void *sel); \n\ @@ -152,6 +153,106 @@ extern \"C\" void * __lldb_objc_find_implementation_for_selector (void *object, return return_struct.impl_addr; \n\ } \n\ "; +const char *AppleObjCTrampolineHandler::g_lookup_implementation_no_stret_function_code = " \n\ +extern \"C\" \n\ +{ \n\ + extern void *class_getMethodImplementation(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\ + return_struct.impl_addr = class_getMethodImplementation (return_struct.class_addr, \n\ + return_struct.sel_addr); \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), @@ -556,8 +657,26 @@ AppleObjCTrampolineHandler::AppleObjCTrampolineHandler (const ProcessSP &process m_msg_forward_stret_addr = msg_forward_stret->GetAddress().GetOpcodeLoadAddress(target); // FIXME: Do some kind of logging here. - if (m_impl_fn_addr == LLDB_INVALID_ADDRESS || m_impl_stret_fn_addr == LLDB_INVALID_ADDRESS) + if (m_impl_fn_addr == LLDB_INVALID_ADDRESS) + { + // If we can't even find the ordinary get method implementation function, then we aren't going to be able to + // step through any method dispatches. Warn to that effect and get out of here. + process_sp->GetTarget().GetDebugger().GetErrorStream().Printf("Could not find implementation lookup function \"%s\"" + " step in through ObjC method dispatch will not work.\n", + get_impl_name.AsCString()); return; + } + else if (m_impl_stret_fn_addr == LLDB_INVALID_ADDRESS) + { + // It there is no stret return lookup function, assume that it is the same as the straight lookup: + m_impl_stret_fn_addr = m_impl_fn_addr; + // Also we will use the version of the lookup code that doesn't rely on the stret version of the function. + g_lookup_implementation_function_code = g_lookup_implementation_no_stret_function_code; + } + else + { + g_lookup_implementation_function_code = g_lookup_implementation_with_stret_function_code; + } // Look up the addresses for the objc dispatch functions and cache them. For now I'm inspecting the symbol // names dynamically to figure out how to dispatch to them. If it becomes more complicated than this we can @@ -629,15 +748,26 @@ AppleObjCTrampolineHandler::SetupDispatchFunction (Thread &thread, ValueList &di } 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 (g_lookup_implementation_function_code != NULL) + { + 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 args_addr; + } + } + else { if (log) - log->Printf ("Failed to install implementation lookup: %s.", errors.GetData()); - m_impl_code.reset(); - return args_addr; + log->Printf("No method lookup implementation code."); + errors.Printf ("No method lookup implementation code found."); + return LLDB_INVALID_ADDRESS; } + impl_code_address.Clear(); impl_code_address.SetOffset(m_impl_code->StartAddress()); } diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h index eec6fce48d90..a50651431e79 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h @@ -67,6 +67,8 @@ public: private: static const char *g_lookup_implementation_function_name; static const char *g_lookup_implementation_function_code; + static const char *g_lookup_implementation_with_stret_function_code; + static const char *g_lookup_implementation_no_stret_function_code; class AppleObjCVTables {