[Lldb-commits] [lldb] r130701 - in /lldb/trunk: include/lldb/ include/lldb/Core/ include/lldb/Symbol/ include/lldb/Target/ source/API/ source/Core/ source/Expression/ source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/ source/Symbol/ source/Target/ test/objc-dynamic-value/

Jim Ingham jingham at apple.com
Mon May 2 11:13:59 PDT 2011


Author: jingham
Date: Mon May  2 13:13:59 2011
New Revision: 130701

URL: http://llvm.org/viewvc/llvm-project?rev=130701&view=rev
Log:
Adding support for fetching the Dynamic Value for ObjC Objects.

Added:
    lldb/trunk/test/objc-dynamic-value/
    lldb/trunk/test/objc-dynamic-value/Makefile
    lldb/trunk/test/objc-dynamic-value/TestObjCDynamicValue.py
    lldb/trunk/test/objc-dynamic-value/dynamic-value.m
Modified:
    lldb/trunk/include/lldb/Core/ValueObject.h
    lldb/trunk/include/lldb/Symbol/Type.h
    lldb/trunk/include/lldb/Target/LanguageRuntime.h
    lldb/trunk/include/lldb/Target/ObjCLanguageRuntime.h
    lldb/trunk/include/lldb/lldb-forward.h
    lldb/trunk/source/API/SBValue.cpp
    lldb/trunk/source/Core/ValueObject.cpp
    lldb/trunk/source/Core/ValueObjectDynamicValue.cpp
    lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp
    lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
    lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h
    lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
    lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
    lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
    lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h
    lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
    lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
    lldb/trunk/source/Symbol/Type.cpp
    lldb/trunk/source/Target/ObjCLanguageRuntime.cpp

Modified: lldb/trunk/include/lldb/Core/ValueObject.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/ValueObject.h?rev=130701&r1=130700&r2=130701&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/ValueObject.h (original)
+++ lldb/trunk/include/lldb/Core/ValueObject.h Mon May  2 13:13:59 2011
@@ -138,11 +138,7 @@
         }
         
         void
-        SetUpdated ()
-        {
-            m_first_update = false;
-            m_needs_update = false;
-        }
+        SetUpdated ();
         
         bool
         NeedsUpdating()

Modified: lldb/trunk/include/lldb/Symbol/Type.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/Type.h?rev=130701&r1=130700&r2=130701&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Symbol/Type.h (original)
+++ lldb/trunk/include/lldb/Symbol/Type.h Mon May  2 13:13:59 2011
@@ -12,6 +12,7 @@
 
 #include "lldb/lldb-private.h"
 #include "lldb/Core/ClangForward.h"
+#include "lldb/Core/ConstString.h"
 #include "lldb/Core/UserID.h"
 #include "lldb/Symbol/Declaration.h"
 #include <set>
@@ -250,6 +251,48 @@
     ResolveClangType (ResolveState clang_type_resolve_state);
 };
 
+
+///
+/// Sometimes you can find the name of the type corresponding to an object, but we don't have debug
+/// information for it.  If that is the case, you can return one of these objects, and then if it
+/// has a full type, you can use that, but if not at least you can print the name for informational
+/// purposes.
+///
+
+class TypeAndOrName
+{
+public:
+    TypeAndOrName ();
+    TypeAndOrName (lldb::TypeSP &type_sp);
+    TypeAndOrName (const char *type_str);
+    TypeAndOrName (const TypeAndOrName &rhs);
+    TypeAndOrName (ConstString &type_const_string);
+    
+    TypeAndOrName &
+    operator= (const TypeAndOrName &rhs);
+    
+    ConstString GetName () const;
+    lldb::TypeSP      GetTypeSP () const {
+        return m_type_sp;
+    };
+    
+    void
+    SetName (ConstString &type_name_const_str);
+    
+    void 
+    SetName (const char *type_name_str);
+    
+    void
+    SetTypeSP (lldb::TypeSP type_sp);
+    
+    bool
+    IsEmpty ();
+    
+private:
+    lldb::TypeSP m_type_sp;
+    ConstString m_type_name;
+};
+
 } // namespace lldb_private
 
 #endif  // liblldb_Type_h_

Modified: lldb/trunk/include/lldb/Target/LanguageRuntime.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/LanguageRuntime.h?rev=130701&r1=130700&r2=130701&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/LanguageRuntime.h (original)
+++ lldb/trunk/include/lldb/Target/LanguageRuntime.h Mon May  2 13:13:59 2011
@@ -43,7 +43,7 @@
     GetObjectDescription (Stream &str, Value &value, ExecutionContextScope *exe_scope) = 0;
     
     virtual bool
-    GetDynamicValue (ValueObject &in_value, lldb::TypeSP &type_sp, Address &address) = 0;
+    GetDynamicTypeAndAddress (ValueObject &in_value, TypeAndOrName &class_type_or_name, Address &address) = 0;
     
     // This should be a fast test to determine whether it is likely that this value would
     // have a dynamic type.

Modified: lldb/trunk/include/lldb/Target/ObjCLanguageRuntime.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/ObjCLanguageRuntime.h?rev=130701&r1=130700&r2=130701&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/ObjCLanguageRuntime.h (original)
+++ lldb/trunk/include/lldb/Target/ObjCLanguageRuntime.h Mon May  2 13:13:59 2011
@@ -55,6 +55,15 @@
     void
     AddToMethodCache (lldb::addr_t class_addr, lldb::addr_t sel, lldb::addr_t impl_addr);
     
+    TypeAndOrName
+    LookupInClassNameCache (lldb::addr_t class_addr);
+    
+    void
+    AddToClassNameCache (lldb::addr_t class_addr, const char *name, lldb::TypeSP type_sp);
+    
+    void
+    AddToClassNameCache (lldb::addr_t class_addr, const TypeAndOrName &class_or_type_name);
+    
     virtual ClangUtilityFunction *
     CreateObjectChecker (const char *) = 0;
     
@@ -117,7 +126,10 @@
     };
 
     typedef std::map<ClassAndSel,lldb::addr_t> MsgImplMap;
-    MsgImplMap m_impl_cache;        
+    MsgImplMap m_impl_cache;
+    
+    typedef std::map<lldb::addr_t,TypeAndOrName> ClassNameMap;
+    ClassNameMap m_class_name_cache;
 
     DISALLOW_COPY_AND_ASSIGN (ObjCLanguageRuntime);
 };

Modified: lldb/trunk/include/lldb/lldb-forward.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-forward.h?rev=130701&r1=130700&r2=130701&view=diff
==============================================================================
--- lldb/trunk/include/lldb/lldb-forward.h (original)
+++ lldb/trunk/include/lldb/lldb-forward.h Mon May  2 13:13:59 2011
@@ -155,6 +155,7 @@
 class   ThreadSpec;
 class   TimeValue;
 class   Type;
+class   TypeAndOrName;
 class   TypeList;
 class   UUID;
 class   Unwind;

Modified: lldb/trunk/source/API/SBValue.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBValue.cpp?rev=130701&r1=130700&r2=130701&view=diff
==============================================================================
--- lldb/trunk/source/API/SBValue.cpp (original)
+++ lldb/trunk/source/API/SBValue.cpp Mon May  2 13:13:59 2011
@@ -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;
         }

Modified: lldb/trunk/source/Core/ValueObject.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/ValueObject.cpp?rev=130701&r1=130700&r2=130701&view=diff
==============================================================================
--- lldb/trunk/source/Core/ValueObject.cpp (original)
+++ lldb/trunk/source/Core/ValueObject.cpp Mon May  2 13:13:59 2011
@@ -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)
 {

Modified: lldb/trunk/source/Core/ValueObjectDynamicValue.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/ValueObjectDynamicValue.cpp?rev=130701&r1=130700&r2=130701&view=diff
==============================================================================
--- lldb/trunk/source/Core/ValueObjectDynamicValue.cpp (original)
+++ lldb/trunk/source/Core/ValueObjectDynamicValue.cpp Mon May  2 13:13:59 2011
@@ -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)

Modified: lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp?rev=130701&r1=130700&r2=130701&view=diff
==============================================================================
--- lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp (original)
+++ lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp Mon May  2 13:13:59 2011
@@ -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();
 }

Modified: lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp?rev=130701&r1=130700&r2=130701&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp Mon May  2 13:13:59 2011
@@ -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.

Modified: lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h?rev=130701&r1=130700&r2=130701&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h Mon May  2 13:13:59 2011
@@ -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);

Modified: lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp?rev=130701&r1=130700&r2=130701&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp Mon May  2 13:13:59 2011
@@ -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;
 }

Modified: lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h?rev=130701&r1=130700&r2=130701&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h Mon May  2 13:13:59 2011
@@ -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.
     

Modified: lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp?rev=130701&r1=130700&r2=130701&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp Mon May  2 13:13:59 2011
@@ -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;
 }

Modified: lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h?rev=130701&r1=130700&r2=130701&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h Mon May  2 13:13:59 2011
@@ -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 *);

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=130701&r1=130700&r2=130701&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp Mon May  2 13:13:59 2011
@@ -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;
 }
 

Modified: lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h?rev=130701&r1=130700&r2=130701&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h Mon May  2 13:13:59 2011
@@ -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

Modified: lldb/trunk/source/Symbol/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/Type.cpp?rev=130701&r1=130700&r2=130701&view=diff
==============================================================================
--- lldb/trunk/source/Symbol/Type.cpp (original)
+++ lldb/trunk/source/Symbol/Type.cpp Mon May  2 13:13:59 2011
@@ -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;
+}

Modified: lldb/trunk/source/Target/ObjCLanguageRuntime.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/ObjCLanguageRuntime.cpp?rev=130701&r1=130700&r2=130701&view=diff
==============================================================================
--- lldb/trunk/source/Target/ObjCLanguageRuntime.cpp (original)
+++ lldb/trunk/source/Target/ObjCLanguageRuntime.cpp Mon May  2 13:13:59 2011
@@ -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 ();
+}

Added: lldb/trunk/test/objc-dynamic-value/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/objc-dynamic-value/Makefile?rev=130701&view=auto
==============================================================================
--- lldb/trunk/test/objc-dynamic-value/Makefile (added)
+++ lldb/trunk/test/objc-dynamic-value/Makefile Mon May  2 13:13:59 2011
@@ -0,0 +1,6 @@
+LEVEL = ../make
+
+OBJC_SOURCES := dynamic-value.m
+LDFLAGS = $(CFLAGS) -lobjc -framework Foundation
+
+include $(LEVEL)/Makefile.rules

Added: lldb/trunk/test/objc-dynamic-value/TestObjCDynamicValue.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/objc-dynamic-value/TestObjCDynamicValue.py?rev=130701&view=auto
==============================================================================
--- lldb/trunk/test/objc-dynamic-value/TestObjCDynamicValue.py (added)
+++ lldb/trunk/test/objc-dynamic-value/TestObjCDynamicValue.py Mon May  2 13:13:59 2011
@@ -0,0 +1,165 @@
+"""
+Use lldb Python API to test dynamic values in ObjC
+"""
+
+import os, time
+import re
+import unittest2
+import lldb, lldbutil
+from lldbtest import *
+
+class ObjCDynamicValueTestCase(TestBase):
+
+    mydir = "objc-dynamic-value"
+
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    @python_api_test
+    def test_get_dynamic_objc_vals_with_dsym(self):
+        """Test fetching ObjC dynamic values."""
+        self.buildDsym()
+        self.do_get_dynamic_vals()
+
+    @python_api_test
+    def test_get_objc_dynamic_vals_with_dwarf(self):
+        """Test fetching ObjC dynamic values."""
+        self.buildDwarf()
+        self.do_get_dynamic_vals()
+
+    def setUp(self):
+        # Call super's setUp().                                                                                                           
+        TestBase.setUp(self)
+
+        # Find the line number to break for main.c.                                                                                       
+
+        self.source_name = 'dynamic-value.m'
+        self.set_property_line = line_number(self.source_name, '// This is the line in setProperty, make sure we step to here.')
+        self.handle_SourceBase = line_number(self.source_name,
+                                                 '// Break here to check dynamic values.')
+        self.main_before_setProperty_line = line_number(self.source_name,
+                                                       '// Break here to see if we can step into real method.')
+
+    def examine_SourceDerived_ptr (self, object):
+        self.assertTrue (object.IsValid())
+        self.assertTrue (object.GetTypeName().find ('SourceDerived') != -1)
+        derivedValue = object.GetChildMemberWithName ('_derivedValue')
+        self.assertTrue (derivedValue.IsValid())
+        self.assertTrue (int (derivedValue.GetValue(), 0) == 30)
+
+    def do_get_dynamic_vals(self):
+        """Make sure we get dynamic values correctly both for compiled in classes and dynamic ones"""
+        exe = os.path.join(os.getcwd(), "a.out")
+
+        # Create a target from the debugger.
+
+        target = self.dbg.CreateTarget (exe)
+        self.assertTrue(target.IsValid(), VALID_TARGET)
+
+        # Set up our breakpoints:
+
+        handle_SourceBase_bkpt = target.BreakpointCreateByLocation(self.source_name, self.handle_SourceBase)
+        self.assertTrue(handle_SourceBase_bkpt.IsValid() and
+                        handle_SourceBase_bkpt.GetNumLocations() == 1,
+                        VALID_BREAKPOINT)
+
+        main_before_setProperty_bkpt = target.BreakpointCreateByLocation(self.source_name, self.main_before_setProperty_line)
+        self.assertTrue(main_before_setProperty_bkpt.IsValid() and
+                        main_before_setProperty_bkpt.GetNumLocations() == 1,
+                        VALID_BREAKPOINT)
+
+        # Now launch the process, and do not stop at the entry point.
+        self.process = target.LaunchSimple (None, None, os.getcwd())
+
+        self.assertTrue(self.process.GetState() == lldb.eStateStopped,
+                        PROCESS_STOPPED)
+
+        threads = lldbutil.get_threads_stopped_at_breakpoint (self.process, main_before_setProperty_bkpt)
+        self.assertTrue (len(threads) == 1)
+        thread = threads[0]
+
+        #
+        #  At this point, myObserver has a Source pointer that is actually a KVO swizzled SourceDerived
+        #  make sure we can get that properly:
+
+        frame = thread.GetFrameAtIndex(0)
+        myObserver = frame.FindVariable('myObserver')
+        self.assertTrue (myObserver.IsValid())
+        myObserver_source = myObserver.GetChildMemberWithName ('_source')
+        self.examine_SourceDerived_ptr (myObserver_source)
+
+        # The "frame var" code uses another path to get into children, so let's
+        # make sure that works as well:
+
+        result = lldb.SBCommandReturnObject()
+
+        self.expect('frame var -d 1 myObserver->_source', 'frame var finds its way into a child member',
+            patterns = ['\(SourceDerived \*\)'])
+
+        # This test is not entirely related to the main thrust of this test case, but since we're here,
+        # try stepping into setProperty, and make sure we get into the version in Source:
+
+        thread.StepInto()
+
+        threads = lldbutil.get_stopped_threads (self.process, lldb.eStopReasonPlanComplete)
+        self.assertTrue (len(threads) == 1)
+        line_entry = threads[0].GetFrameAtIndex(0).GetLineEntry()
+        self.assertTrue (line_entry.GetLine() == self.set_property_line)
+        self.assertTrue (line_entry.GetFileSpec().GetFilename() == self.source_name) 
+
+        # Okay, back to the main business.  Continue to the handle_SourceBase and make sure we get the correct dynamic value.
+
+        threads = lldbutil.continue_to_breakpoint (self.process, handle_SourceBase_bkpt)
+        self.assertTrue (len(threads) == 1)
+        thread = threads[0]
+
+        frame = thread.GetFrameAtIndex(0)
+
+        # Get "object" using FindVariable:
+
+        noDynamic = False
+        useDynamic = True
+
+        object_static = frame.FindVariable ('object', noDynamic)
+        object_dynamic = frame.FindVariable ('object', useDynamic)
+
+        # Delete this object to make sure that this doesn't cause havoc with the dynamic object that depends on it.
+        del (object_static)
+
+        self.examine_SourceDerived_ptr (object_dynamic)
+        
+        # Get "this" using FindValue, make sure that works too:
+        object_static = frame.FindValue ('object', lldb.eValueTypeVariableArgument, noDynamic)
+        object_dynamic = frame.FindValue ('object', lldb.eValueTypeVariableArgument, useDynamic)
+        del (object_static)
+        self.examine_SourceDerived_ptr (object_dynamic)
+
+        # Get "this" using the EvaluateExpression:
+        # These tests fail for now because EvaluateExpression doesn't currently support dynamic typing...
+        #object_static = frame.EvaluateExpression ('object', False)
+        #object_dynamic = frame.EvaluateExpression ('object', True)
+        #self.examine_value_object_of_object_ptr (object_static, object_dynamic, myB_loc)
+        
+        # Continue again to the handle_SourceBase and make sure we get the correct dynamic value.
+        # This one looks exactly the same, but in fact this is an "un-KVO'ed" version of SourceBase, so
+        # its isa pointer points to SourceBase not NSKVOSourceBase or whatever...
+
+        threads = lldbutil.continue_to_breakpoint (self.process, handle_SourceBase_bkpt)
+        self.assertTrue (len(threads) == 1)
+        thread = threads[0]
+
+        frame = thread.GetFrameAtIndex(0)
+
+        # Get "object" using FindVariable:
+
+        object_static = frame.FindVariable ('object', noDynamic)
+        object_dynamic = frame.FindVariable ('object', useDynamic)
+
+        # Delete this object to make sure that this doesn't cause havoc with the dynamic object that depends on it.
+        del (object_static)
+
+        self.examine_SourceDerived_ptr (object_dynamic)
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()

Added: lldb/trunk/test/objc-dynamic-value/dynamic-value.m
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/objc-dynamic-value/dynamic-value.m?rev=130701&view=auto
==============================================================================
--- lldb/trunk/test/objc-dynamic-value/dynamic-value.m (added)
+++ lldb/trunk/test/objc-dynamic-value/dynamic-value.m Mon May  2 13:13:59 2011
@@ -0,0 +1,147 @@
+#import <Foundation/Foundation.h>
+
+// SourceBase will be the base class of Source.  We'll pass a Source object into a
+// function as a SourceBase, and then see if the dynamic typing can get us through the KVO
+// goo and all the way back to Source.
+
+ at interface SourceBase: NSObject
+{
+    uint32_t _value;
+}
+- (SourceBase *) init;
+- (uint32_t) getValue;
+ at end
+
+ at implementation SourceBase
+- (SourceBase *) init
+{
+    [super init];
+    _value = 10;
+    return self;
+}
+- (uint32_t) getValue
+{
+    return _value;
+}
+ at end
+
+// Source is a class that will be observed by the Observer class below.
+// When Observer sets itself up to observe this property (in initWithASource)
+// the KVO system will overwrite the "isa" pointer of the object with the "kvo'ed" 
+// one.
+
+ at interface Source : SourceBase
+{
+    int _property;
+}
+- (Source *) init;
+- (void) setProperty: (int) newValue;
+ at end
+
+ at implementation Source
+- (Source *) init
+{
+    [super init];
+    _property = 20;
+    return self;
+}
+- (void) setProperty: (int) newValue
+{
+    _property = newValue;  // This is the line in setProperty, make sure we step to here.
+}
+ at end
+
+ at interface SourceDerived : Source
+{
+    int _derivedValue;
+}
+- (SourceDerived *) init;
+- (uint32_t) getValue;
+ at end
+
+ at implementation SourceDerived
+- (SourceDerived *) init
+{
+    [super init];
+    _derivedValue = 30;
+    return self;
+}
+- (uint32_t) getValue
+{
+    return _derivedValue;
+}
+ at end
+
+// Observer is the object that will watch Source and cause KVO to swizzle it...
+
+ at interface Observer : NSObject
+{
+    Source *_source;
+}
++ (Observer *) observerWithSource: (Source *) source;
+- (Observer *) initWithASource: (Source *) source;
+- (void) observeValueForKeyPath: (NSString *) path 
+		       ofObject: (id) object
+			 change: (NSDictionary *) change
+			context: (void *) context;
+ at end
+
+ at implementation Observer
+
++ (Observer *) observerWithSource: (Source *) inSource;
+{
+    Observer *retval;
+
+    retval = [[Observer alloc] initWithASource: inSource];
+    return retval;
+}
+
+- (Observer *) initWithASource: (Source *) source
+{
+    [super init];
+    _source = source;
+    [_source addObserver: self 
+	    forKeyPath: @"property" 
+	    options: (NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld)
+	    context: NULL];
+    return self;
+}
+
+- (void) observeValueForKeyPath: (NSString *) path 
+		       ofObject: (id) object
+			 change: (NSDictionary *) change
+			context: (void *) context
+{
+    printf ("Observer function called.\n");
+    return;
+}
+ at end
+
+uint32_t 
+handle_SourceBase (SourceBase *object)
+{
+    return [object getValue];  // Break here to check dynamic values.
+}
+
+int main ()
+{
+    SourceDerived *mySource;
+    Observer *myObserver;
+
+    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+
+    mySource = [[SourceDerived alloc] init];
+    myObserver = [Observer observerWithSource: mySource];
+
+    [mySource setProperty: 5];      // Break here to see if we can step into real method.
+    
+    uint32_t return_value = handle_SourceBase (mySource);
+
+    SourceDerived *unwatchedSource = [[SourceDerived alloc] init];
+    
+    return_value = handle_SourceBase (unwatchedSource);
+    
+    [pool release];
+    return 0;
+
+}





More information about the lldb-commits mailing list