Adding support for fetching the Dynamic Value for ObjC Objects.
git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@130701 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/API/SBValue.cpp b/source/API/SBValue.cpp
index 6ad6bb9..f499fae 100644
--- a/source/API/SBValue.cpp
+++ b/source/API/SBValue.cpp
@@ -357,7 +357,7 @@
{
if (child_sp)
{
- lldb::ValueObjectSP dynamic_sp = child_sp->GetDynamicValue(true);
+ lldb::ValueObjectSP dynamic_sp = child_sp->GetDynamicValue (true);
if (dynamic_sp)
child_sp = dynamic_sp;
}
@@ -410,7 +410,7 @@
{
if (child_sp)
{
- lldb::ValueObjectSP dynamic_sp = child_sp->GetDynamicValue(true);
+ lldb::ValueObjectSP dynamic_sp = child_sp->GetDynamicValue (true);
if (dynamic_sp)
child_sp = dynamic_sp;
}
diff --git a/source/Core/ValueObject.cpp b/source/Core/ValueObject.cpp
index 1f443e8..521d3eb 100644
--- a/source/Core/ValueObject.cpp
+++ b/source/Core/ValueObject.cpp
@@ -1644,6 +1644,16 @@
return true;
}
+void
+ValueObject::EvaluationPoint::SetUpdated ()
+{
+ m_first_update = false;
+ m_needs_update = false;
+ if (m_process_sp)
+ m_stop_id = m_process_sp->GetStopID();
+}
+
+
bool
ValueObject::EvaluationPoint::SetContext (ExecutionContextScope *exe_scope)
{
diff --git a/source/Core/ValueObjectDynamicValue.cpp b/source/Core/ValueObjectDynamicValue.cpp
index 17eb90a..b43c651 100644
--- a/source/Core/ValueObjectDynamicValue.cpp
+++ b/source/Core/ValueObjectDynamicValue.cpp
@@ -135,7 +135,7 @@
if (!process)
return false;
- lldb::TypeSP dynamic_type_sp;
+ TypeAndOrName class_type_or_name;
Address dynamic_address;
bool found_dynamic_type = false;
@@ -144,22 +144,29 @@
{
LanguageRuntime *runtime = process->GetLanguageRuntime (known_type);
if (runtime)
- found_dynamic_type = runtime->GetDynamicValue(*m_parent, dynamic_type_sp, dynamic_address);
+ found_dynamic_type = runtime->GetDynamicTypeAndAddress (*m_parent, class_type_or_name, dynamic_address);
}
else
{
LanguageRuntime *cpp_runtime = process->GetLanguageRuntime (lldb::eLanguageTypeC_plus_plus);
if (cpp_runtime)
- found_dynamic_type = cpp_runtime->GetDynamicValue(*m_parent, dynamic_type_sp, dynamic_address);
+ found_dynamic_type = cpp_runtime->GetDynamicTypeAndAddress (*m_parent, class_type_or_name, dynamic_address);
if (!found_dynamic_type)
{
LanguageRuntime *objc_runtime = process->GetLanguageRuntime (lldb::eLanguageTypeObjC);
if (objc_runtime)
- found_dynamic_type = cpp_runtime->GetDynamicValue(*m_parent, dynamic_type_sp, dynamic_address);
+ found_dynamic_type = cpp_runtime->GetDynamicTypeAndAddress (*m_parent, class_type_or_name, dynamic_address);
}
}
+ lldb::TypeSP dynamic_type_sp = class_type_or_name.GetTypeSP();
+
+ // Getting the dynamic value may have run the program a bit, and so marked us as needing updating, but we really
+ // don't...
+
+ m_update_point.SetUpdated();
+
// If we don't have a dynamic type, then make ourselves just a echo of our parent.
// Or we could return false, and make ourselves an echo of our parent?
if (!found_dynamic_type)
diff --git a/source/Expression/ClangExpressionDeclMap.cpp b/source/Expression/ClangExpressionDeclMap.cpp
index 60a37bc..678c175 100644
--- a/source/Expression/ClangExpressionDeclMap.cpp
+++ b/source/Expression/ClangExpressionDeclMap.cpp
@@ -73,7 +73,8 @@
m_parser_vars->m_sym_ctx = exe_ctx.frame->GetSymbolContext(lldb::eSymbolContextEverything);
else if (exe_ctx.thread)
m_parser_vars->m_sym_ctx = exe_ctx.thread->GetStackFrameAtIndex(0)->GetSymbolContext(lldb::eSymbolContextEverything);
-
+ else if (exe_ctx.process)
+ m_parser_vars->m_sym_ctx = SymbolContext(exe_ctx.target->GetSP(), ModuleSP());
if (exe_ctx.target)
m_parser_vars->m_persistent_vars = &exe_ctx.target->GetPersistentVariables();
}
diff --git a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
index fb4c98d..20b608e 100644
--- a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
+++ b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
@@ -41,7 +41,7 @@
}
bool
-ItaniumABILanguageRuntime::GetDynamicValue (ValueObject &in_value, lldb::TypeSP &dynamic_type_sp, Address &dynamic_address)
+ItaniumABILanguageRuntime::GetDynamicTypeAndAddress (ValueObject &in_value, TypeAndOrName &class_type_or_name, Address &dynamic_address)
{
// For Itanium, if the type has a vtable pointer in the object, it will be at offset 0
// in the object. That will point to the "address point" within the vtable (not the beginning of the
@@ -104,6 +104,7 @@
{
// We are a C++ class, that's good. Get the class name and look it up:
const char *class_name = name + strlen(vtable_demangled_prefix);
+ class_type_or_name.SetName (class_name);
TypeList class_types;
uint32_t num_matches = target->GetImages().FindTypes (sc,
ConstString(class_name),
@@ -112,14 +113,40 @@
class_types);
if (num_matches == 1)
{
- dynamic_type_sp = class_types.GetTypeAtIndex(0);
+ class_type_or_name.SetTypeSP(class_types.GetTypeAtIndex(0));
}
else if (num_matches > 1)
{
- // How to sort out which of the type matches to pick?
+ for (size_t i = 0; i < num_matches; i++)
+ {
+ lldb::TypeSP this_type(class_types.GetTypeAtIndex(i));
+ if (this_type)
+ {
+ if (ClangASTContext::IsCXXClassType(this_type->GetClangFullType()))
+ {
+ // There can only be one type with a given name,
+ // so we've just found duplicate definitions, and this
+ // one will do as well as any other.
+ // We don't consider something to have a dynamic type if
+ // it is the same as the static type. So compare against
+ // the value we were handed:
+
+ clang::ASTContext *in_ast_ctx = in_value.GetClangAST ();
+ clang::ASTContext *this_ast_ctx = this_type->GetClangAST ();
+ if (in_ast_ctx != this_ast_ctx
+ || !ClangASTContext::AreTypesSame (in_ast_ctx,
+ in_value.GetClangType(),
+ this_type->GetClangFullType()))
+ {
+ class_type_or_name.SetTypeSP (this_type);
+ return true;
+ }
+ return false;
+ }
+ }
+ }
}
-
- if (!dynamic_type_sp)
+ else
return false;
// The offset_to_top is two pointers above the address.
diff --git a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h
index 421ac12..966090d 100644
--- a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h
+++ b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h
@@ -31,7 +31,7 @@
IsVTableName (const char *name);
virtual bool
- GetDynamicValue (ValueObject &in_value, lldb::TypeSP &type_sp, Address &address);
+ GetDynamicTypeAndAddress (ValueObject &in_value, TypeAndOrName &class_type_or_name, Address &address);
virtual bool
CouldHaveDynamicValue (ValueObject &in_value);
diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
index 08af0b6..62eac38 100644
--- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
+++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
@@ -198,7 +198,7 @@
}
bool
-AppleObjCRuntime::GetDynamicValue (ValueObject &in_value, lldb::TypeSP &type_sp, Address &address)
+AppleObjCRuntime::GetDynamicTypeAndAddress (ValueObject &in_value, TypeAndOrName &class_type_or_name, Address &address)
{
return false;
}
diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
index e7e0f71..f3eb074 100644
--- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
+++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
@@ -41,7 +41,7 @@
CouldHaveDynamicValue (ValueObject &in_value);
virtual bool
- GetDynamicValue (ValueObject &in_value, lldb::TypeSP &type_sp, Address &address);
+ GetDynamicTypeAndAddress (ValueObject &in_value, TypeAndOrName &class_type_or_name, Address &address);
// These are the ObjC specific functions.
diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
index 000f14e..fe29b62 100644
--- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
+++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
@@ -41,7 +41,7 @@
static const char *pluginShort = "language.apple.objc.v1";
bool
-AppleObjCRuntimeV1::GetDynamicValue (ValueObject &in_value, lldb::TypeSP &type_sp, Address &address)
+AppleObjCRuntimeV1::GetDynamicTypeAndAddress (ValueObject &in_value, TypeAndOrName &class_type_or_name, Address &address)
{
return false;
}
diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h
index 975c018..7a43ca3 100644
--- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h
+++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h
@@ -32,7 +32,7 @@
// These are generic runtime functions:
virtual bool
- GetDynamicValue (ValueObject &in_value, lldb::TypeSP &type_sp, Address &address);
+ GetDynamicTypeAndAddress (ValueObject &in_value, TypeAndOrName &class_type_or_name, Address &address);
virtual ClangUtilityFunction *
CreateObjectChecker (const char *);
diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
index c6e3533..42e7aee 100644
--- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
+++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
@@ -40,15 +40,359 @@
static const char *pluginDesc = "Apple Objective C Language Runtime - Version 2";
static const char *pluginShort = "language.apple.objc.v2";
+
+const char *AppleObjCRuntimeV2::g_find_class_name_function_name = "__lldb_apple_objc_v2_find_class_name";
+const char *AppleObjCRuntimeV2::g_find_class_name_function_body = " \n\
+extern \"C\" \n\
+{ \n\
+ extern void *gdb_class_getClass (void *objc_class); \n\
+ extern void *class_getName(void *objc_class); \n\
+ extern int printf(const char *format, ...); \n\
+} \n\
+ \n\
+struct __lldb_objc_object { \n\
+ void *isa; \n\
+}; \n\
+ \n\
+extern \"C\" void *__lldb_apple_objc_v2_find_class_name ( \n\
+ __lldb_objc_object *object_ptr, \n\
+ int debug) \n\
+{ \n\
+ void *name = 0; \n\
+ if (debug) \n\
+ printf (\"\\n*** Called in v2_find_class_name with object: 0x%p\\n\", object_ptr); \n\
+ // Call gdb_class_getClass so we can tell if the class is good. \n\
+ void *objc_class = gdb_class_getClass (object_ptr->isa); \n\
+ if (objc_class) \n\
+ { \n\
+ void *actual_class = (void *) [(id) object_ptr class]; \n\
+ if (actual_class != 0) \n\
+ name = class_getName((void *) actual_class); \n\
+ if (debug) \n\
+ printf (\"\\n*** Found name: %s\\n\", name ? name : \"<NOT FOUND>\"); \n\
+ } \n\
+ else if (debug) \n\
+ printf (\"\\n*** gdb_class_getClass returned NULL\\n\"); \n\
+ return name; \n\
+} \n\
+";
+
+const char *AppleObjCRuntimeV2::g_objc_class_symbol_prefix = "OBJC_CLASS_$_";
+const char *AppleObjCRuntimeV2::g_objc_class_data_section_name = "__objc_data";
+
AppleObjCRuntimeV2::AppleObjCRuntimeV2 (Process *process, ModuleSP &objc_module_sp) :
- lldb_private::AppleObjCRuntime (process)
+ lldb_private::AppleObjCRuntime (process),
+ m_get_class_name_args(LLDB_INVALID_ADDRESS),
+ m_get_class_name_args_mutex(Mutex::eMutexTypeNormal)
{
m_has_object_getClass = (objc_module_sp->FindFirstSymbolWithNameAndType(ConstString("gdb_object_getClass")) != NULL);
}
bool
-AppleObjCRuntimeV2::GetDynamicValue (ValueObject &in_value, lldb::TypeSP &type_sp, Address &address)
+AppleObjCRuntimeV2::RunFunctionToFindClassName(lldb::addr_t object_addr, Thread *thread, char *name_dst, size_t max_name_len)
{
+ // Since we are going to run code we have to make sure only one thread at a time gets to try this.
+ Mutex::Locker (m_get_class_name_args_mutex);
+
+ StreamString errors;
+
+ LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); // FIXME - a more appropriate log channel?
+
+ int32_t debug;
+ if (log)
+ debug = 1;
+ else
+ debug = 0;
+
+ ValueList dispatch_values;
+
+ Value void_ptr_value;
+ ClangASTContext *clang_ast_context = m_process->GetTarget().GetScratchClangASTContext();
+
+ 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);
+ void_ptr_value.GetScalar() = object_addr;
+
+ dispatch_values.PushValue (void_ptr_value);
+
+ Value int_value;
+ lldb::clang_type_t clang_int_type = clang_ast_context->GetBuiltinTypeForEncodingAndBitSize(lldb::eEncodingSint, 32);
+ int_value.SetValueType (Value::eValueTypeScalar);
+ int_value.SetContext (Value::eContextTypeClangType, clang_int_type);
+ int_value.GetScalar() = debug;
+
+ dispatch_values.PushValue (int_value);
+
+ ExecutionContext exe_ctx;
+ thread->CalculateExecutionContext(exe_ctx);
+
+ Address find_class_name_address;
+
+ if (!m_get_class_name_code.get())
+ {
+ m_get_class_name_code.reset (new ClangUtilityFunction (g_find_class_name_function_body,
+ g_find_class_name_function_name));
+
+ if (!m_get_class_name_code->Install(errors, exe_ctx))
+ {
+ if (log)
+ log->Printf ("Failed to install implementation lookup: %s.", errors.GetData());
+ m_get_class_name_code.reset();
+ return false;
+ }
+ find_class_name_address.Clear();
+ find_class_name_address.SetOffset(m_get_class_name_code->StartAddress());
+ }
+ else
+ {
+ find_class_name_address.Clear();
+ find_class_name_address.SetOffset(m_get_class_name_code->StartAddress());
+ }
+
+ // Next make the runner function for our implementation utility function.
+ if (!m_get_class_name_function.get())
+ {
+ m_get_class_name_function.reset(new ClangFunction (*m_process,
+ clang_ast_context,
+ clang_void_ptr_type,
+ find_class_name_address,
+ dispatch_values));
+
+ errors.Clear();
+ unsigned num_errors = m_get_class_name_function->CompileFunction(errors);
+ if (num_errors)
+ {
+ if (log)
+ log->Printf ("Error compiling function: \"%s\".", errors.GetData());
+ return false;
+ }
+
+ errors.Clear();
+ if (!m_get_class_name_function->WriteFunctionWrapper(exe_ctx, errors))
+ {
+ if (log)
+ log->Printf ("Error Inserting function: \"%s\".", errors.GetData());
+ return false;
+ }
+ }
+
+ if (m_get_class_name_code.get() == NULL || m_get_class_name_function.get() == NULL)
+ return false;
+
+ // Finally, write down the arguments, and call the function. Note that we will re-use the same space in the target
+ // for the args. We're locking this to ensure that only one thread at a time gets to call this function, so we don't
+ // have to worry about overwriting the arguments.
+
+ if (!m_get_class_name_function->WriteFunctionArguments (exe_ctx, m_get_class_name_args, find_class_name_address, dispatch_values, errors))
+ return false;
+
+ bool stop_others = true;
+ bool try_all_threads = true;
+ bool unwind_on_error = true;
+
+ ExecutionResults results = m_get_class_name_function->ExecuteFunction (exe_ctx,
+ &m_get_class_name_args,
+ errors,
+ stop_others,
+ 1000000,
+ try_all_threads,
+ unwind_on_error,
+ void_ptr_value);
+
+ if (results != eExecutionCompleted)
+ {
+ if (log)
+ log->Printf("Error evaluating our find class name function: %d.\n", results);
+ return false;
+ }
+
+ lldb::addr_t result_ptr = void_ptr_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ size_t chars_read = m_process->ReadCStringFromMemory (result_ptr, name_dst, max_name_len);
+
+ // If we exhausted our buffer before finding a NULL we're probably off in the weeds somewhere...
+ if (chars_read == max_name_len)
+ return false;
+ else
+ return true;
+
+}
+
+bool
+AppleObjCRuntimeV2::GetDynamicTypeAndAddress (ValueObject &in_value, TypeAndOrName &class_type_or_name, Address &address)
+{
+ // The Runtime is attached to a particular process, you shouldn't pass in a value from another process.
+ assert (in_value.GetUpdatePoint().GetProcess() == m_process);
+
+ // Make sure we can have a dynamic value before starting...
+ if (CouldHaveDynamicValue (in_value))
+ {
+ // First job, pull out the address at 0 offset from the object That will be the ISA pointer.
+ AddressType address_type;
+ lldb::addr_t original_ptr = in_value.GetPointerValue(address_type, true);
+
+ // ObjC only has single inheritance, so the objects all start at the same pointer value.
+ address.SetSection (NULL);
+ address.SetOffset (original_ptr);
+
+ if (original_ptr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ Target *target = m_process->CalculateTarget();
+
+ char memory_buffer[16];
+ DataExtractor data(memory_buffer, sizeof(memory_buffer),
+ m_process->GetByteOrder(),
+ m_process->GetAddressByteSize());
+ size_t address_byte_size = m_process->GetAddressByteSize();
+ Error error;
+ size_t bytes_read = m_process->ReadMemory (original_ptr,
+ memory_buffer,
+ address_byte_size,
+ error);
+ if (!error.Success() || (bytes_read != address_byte_size))
+ {
+ return false;
+ }
+
+ uint32_t offset_ptr = 0;
+ lldb::addr_t isa_addr = data.GetAddress (&offset_ptr);
+
+ if (offset_ptr == 0)
+ return false;
+
+ // Make sure the class address is readable, otherwise this is not a good object:
+ bytes_read = m_process->ReadMemory (isa_addr,
+ memory_buffer,
+ address_byte_size,
+ error);
+ if (bytes_read != address_byte_size)
+ return false;
+
+ // First check the cache...
+
+ SymbolContext sc;
+
+ class_type_or_name = LookupInClassNameCache (isa_addr);
+
+ if (!class_type_or_name.IsEmpty())
+ {
+ if (class_type_or_name.GetTypeSP() != NULL)
+ return true;
+ else
+ return false;
+ }
+
+ const char *class_name = NULL;
+ Address isa_address;
+ target->GetSectionLoadList().ResolveLoadAddress (isa_addr, isa_address);
+
+ if (isa_address.IsValid())
+ {
+ // If the ISA pointer points to one of the sections in the binary, then see if we can
+ // get the class name from the symbols.
+
+ const Section *section = isa_address.GetSection();
+
+ if (section)
+ {
+ // If this points to a section that we know about, then this is
+ // some static class or nothing. See if it is in the right section
+ // and if its name is the right form.
+ ConstString section_name = section->GetName();
+ if (section_name == ConstString(g_objc_class_data_section_name))
+ {
+ isa_address.CalculateSymbolContext(&sc);
+ if (sc.symbol)
+ {
+ class_name = sc.symbol->GetName().AsCString();
+ if (strstr (class_name, g_objc_class_symbol_prefix) == class_name)
+ class_name += strlen (g_objc_class_symbol_prefix);
+ else
+ return false;
+ }
+ }
+ }
+ }
+
+ char class_buffer[1024];
+ if (class_name == NULL)
+ {
+ // If the class address didn't point into the binary, or
+ // it points into the right section but there wasn't a symbol
+ // there, try to look it up by calling the class method in the target.
+ ExecutionContextScope *exe_scope = in_value.GetUpdatePoint().GetExecutionContextScope();
+ Thread *thread_to_use;
+ if (exe_scope)
+ thread_to_use = exe_scope->CalculateThread();
+
+ if (thread_to_use == NULL)
+ thread_to_use = m_process->GetThreadList().GetSelectedThread().get();
+
+ if (thread_to_use == NULL)
+ return false;
+
+ if (!RunFunctionToFindClassName (original_ptr, thread_to_use, class_buffer, 1024))
+ return false;
+
+ class_name = class_buffer;
+
+ }
+
+ if (class_name != NULL && *class_name != '\0')
+ {
+ class_type_or_name.SetName (class_name);
+
+ TypeList class_types;
+ uint32_t num_matches = target->GetImages().FindTypes (sc,
+ class_type_or_name.GetName(),
+ true,
+ UINT32_MAX,
+ class_types);
+ if (num_matches == 1)
+ {
+ class_type_or_name.SetTypeSP (class_types.GetTypeAtIndex(0));
+ return true;
+ }
+ else
+ {
+ for (size_t i = 0; i < num_matches; i++)
+ {
+ lldb::TypeSP this_type(class_types.GetTypeAtIndex(i));
+ if (this_type)
+ {
+ if (ClangASTContext::IsObjCClassType(this_type->GetClangFullType()))
+ {
+ // There can only be one type with a given name,
+ // so we've just found duplicate definitions, and this
+ // one will do as well as any other.
+ // We don't consider something to have a dynamic type if
+ // it is the same as the static type. So compare against
+ // the value we were handed:
+
+ clang::ASTContext *in_ast_ctx = in_value.GetClangAST ();
+ clang::ASTContext *this_ast_ctx = this_type->GetClangAST ();
+ if (in_ast_ctx != this_ast_ctx
+ || !ClangASTContext::AreTypesSame (in_ast_ctx,
+ in_value.GetClangType(),
+ this_type->GetClangFullType()))
+ {
+ class_type_or_name.SetTypeSP (this_type);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ AddToClassNameCache (isa_addr, class_type_or_name);
+ if (class_type_or_name.GetTypeSP())
+ return true;
+ else
+ return false;
+ }
+ }
+
return false;
}
diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
index 0015dd2..93395ff 100644
--- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
+++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
@@ -23,7 +23,7 @@
#include "AppleThreadPlanStepThroughObjCTrampoline.h"
namespace lldb_private {
-
+
class AppleObjCRuntimeV2 :
public AppleObjCRuntime
{
@@ -32,7 +32,7 @@
// These are generic runtime functions:
virtual bool
- GetDynamicValue (ValueObject &in_value, lldb::TypeSP &type_sp, Address &address);
+ GetDynamicTypeAndAddress (ValueObject &in_value, TypeAndOrName &class_type_or_name, Address &address);
virtual ClangUtilityFunction *
CreateObjectChecker (const char *);
@@ -76,7 +76,18 @@
private:
AppleObjCRuntimeV2(Process *process, ModuleSP &objc_module_sp);
- bool m_has_object_getClass;
+ bool RunFunctionToFindClassName (lldb::addr_t class_addr, Thread *thread, char *name_dst, size_t max_name_len);
+
+ bool m_has_object_getClass;
+ std::auto_ptr<ClangFunction> m_get_class_name_function;
+ std::auto_ptr<ClangUtilityFunction> m_get_class_name_code;
+ lldb::addr_t m_get_class_name_args;
+ Mutex m_get_class_name_args_mutex;
+
+ static const char *g_find_class_name_function_name;
+ static const char *g_find_class_name_function_body;
+ static const char *g_objc_class_symbol_prefix;
+ static const char *g_objc_class_data_section_name;
};
} // namespace lldb_private
diff --git a/source/Symbol/Type.cpp b/source/Symbol/Type.cpp
index 31fad29..71cbcdd 100644
--- a/source/Symbol/Type.cpp
+++ b/source/Symbol/Type.cpp
@@ -662,3 +662,75 @@
}
+TypeAndOrName::TypeAndOrName () : m_type_sp(), m_type_name()
+{
+
+}
+
+TypeAndOrName::TypeAndOrName (TypeSP &in_type_sp) : m_type_sp(in_type_sp)
+{
+ if (in_type_sp)
+ m_type_name = in_type_sp->GetName();
+}
+
+TypeAndOrName::TypeAndOrName (const char *in_type_str) : m_type_name(in_type_str)
+{
+}
+
+TypeAndOrName::TypeAndOrName (const TypeAndOrName &rhs) : m_type_sp (rhs.m_type_sp), m_type_name (rhs.m_type_name)
+{
+
+}
+
+TypeAndOrName::TypeAndOrName (ConstString &in_type_const_string) : m_type_name (in_type_const_string)
+{
+}
+
+TypeAndOrName &
+TypeAndOrName::operator= (const TypeAndOrName &rhs)
+{
+ if (this != &rhs)
+ {
+ m_type_name = rhs.m_type_name;
+ m_type_sp = rhs.m_type_sp;
+ }
+ return *this;
+}
+
+ConstString
+TypeAndOrName::GetName () const
+{
+ if (m_type_sp)
+ return m_type_sp->GetName();
+ else
+ return m_type_name;
+}
+
+void
+TypeAndOrName::SetName (ConstString &type_name_const_str)
+{
+ m_type_name = type_name_const_str;
+}
+
+void
+TypeAndOrName::SetName (const char *type_name_str)
+{
+ m_type_name.SetCString (type_name_str);
+}
+
+void
+TypeAndOrName::SetTypeSP (lldb::TypeSP type_sp)
+{
+ m_type_sp = type_sp;
+ if (type_sp)
+ m_type_name = type_sp->GetName();
+}
+
+bool
+TypeAndOrName::IsEmpty()
+{
+ if (m_type_name || m_type_sp)
+ return false;
+ else
+ return true;
+}
diff --git a/source/Target/ObjCLanguageRuntime.cpp b/source/Target/ObjCLanguageRuntime.cpp
index bc6e8a0..1d57556 100644
--- a/source/Target/ObjCLanguageRuntime.cpp
+++ b/source/Target/ObjCLanguageRuntime.cpp
@@ -12,6 +12,7 @@
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Type.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
using namespace lldb;
@@ -50,3 +51,45 @@
return (*pos).second;
return LLDB_INVALID_ADDRESS;
}
+
+void
+ObjCLanguageRuntime::AddToClassNameCache (lldb::addr_t class_addr, const char *name, lldb::TypeSP type_sp)
+{
+ LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ {
+ log->Printf ("Caching: class 0x%llx name: %s.", class_addr, name);
+ }
+
+ TypeAndOrName class_type_or_name;
+
+ if (type_sp != NULL)
+ class_type_or_name.SetTypeSP (type_sp);
+ else if (name && *name != '\0')
+ class_type_or_name.SetName (name);
+ else
+ return;
+ m_class_name_cache.insert (std::pair<lldb::addr_t,TypeAndOrName> (class_addr, class_type_or_name));
+}
+
+void
+ObjCLanguageRuntime::AddToClassNameCache (lldb::addr_t class_addr, const TypeAndOrName &class_type_or_name)
+{
+ LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ {
+ log->Printf ("Caching: class 0x%llx name: %s.", class_addr, class_type_or_name.GetName().AsCString());
+ }
+
+ m_class_name_cache.insert (std::pair<lldb::addr_t,TypeAndOrName> (class_addr, class_type_or_name));
+}
+
+TypeAndOrName
+ObjCLanguageRuntime::LookupInClassNameCache (lldb::addr_t class_addr)
+{
+ ClassNameMap::iterator pos, end = m_class_name_cache.end();
+ pos = m_class_name_cache.find (class_addr);
+ if (pos != end)
+ return (*pos).second;
+ return TypeAndOrName ();
+}