In cases where the Objective-C ivar symbols are stripped out,
expressions that refer to ivars will not work because Clang
emits IR that refers to them to get the ivar offsets. 
However, it is possible to search the runtime for these values.

I have added support for reading the relevant tables to the
Objective-C runtime, and extended ClangExpressionDeclMap to
query that information if and only if it doesn't find the symbols
in the binary.

Also added a testcase.

<rdar://problem/12628122>


git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@168018 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Expression/ClangExpressionDeclMap.cpp b/source/Expression/ClangExpressionDeclMap.cpp
index f54d53e..4cd74a8 100644
--- a/source/Expression/ClangExpressionDeclMap.cpp
+++ b/source/Expression/ClangExpressionDeclMap.cpp
@@ -40,6 +40,7 @@
 #include "lldb/Symbol/Variable.h"
 #include "lldb/Symbol/VariableList.h"
 #include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/RegisterContext.h"
 #include "lldb/Target/StackFrame.h"
@@ -749,7 +750,7 @@
 }
 
 addr_t
-ClangExpressionDeclMap::GetSymbolAddress (Target &target, const ConstString &name, lldb::SymbolType symbol_type)
+ClangExpressionDeclMap::GetSymbolAddress (Target &target, Process *process, const ConstString &name, lldb::SymbolType symbol_type)
 {
     SymbolContextList sc_list;
     
@@ -808,6 +809,16 @@
         }
     }
     
+    if (symbol_load_addr == LLDB_INVALID_ADDRESS && process)
+    {
+        ObjCLanguageRuntime *runtime = process->GetObjCLanguageRuntime();
+        
+        if (runtime)
+        {
+            symbol_load_addr = runtime->LookupRuntimeSymbol(name);
+        }
+    }
+    
     return symbol_load_addr;
 }
 
@@ -819,7 +830,7 @@
     if (!m_parser_vars->m_exe_ctx.GetTargetPtr())
         return false;
     
-    return GetSymbolAddress(m_parser_vars->m_exe_ctx.GetTargetRef(), name, symbol_type);
+    return GetSymbolAddress(m_parser_vars->m_exe_ctx.GetTargetRef(), m_parser_vars->m_exe_ctx.GetProcessPtr(), name, symbol_type);
 }
 
 // Interface for IRInterpreter
@@ -1840,7 +1851,7 @@
     }
     else if (sym)
     {
-        addr_t location_load_addr = GetSymbolAddress(*target, name, lldb::eSymbolTypeAny);
+        addr_t location_load_addr = GetSymbolAddress(*target, process, name, lldb::eSymbolTypeAny);
         
         if (location_load_addr == LLDB_INVALID_ADDRESS)
         {
diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
index 5b758c8..9fb6f4e 100644
--- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
+++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
@@ -1047,8 +1047,9 @@
     
     virtual bool
     Describe (std::function <void (ObjCLanguageRuntime::ObjCISA)> const &superclass_func,
-              std::function <void (const char *, const char *)> const &instance_method_func,
-              std::function <void (const char *, const char *)> const &class_method_func)
+              std::function <bool (const char *, const char *)> const &instance_method_func,
+              std::function <bool (const char *, const char *)> const &class_method_func,
+              std::function <bool (const char *, const char *, lldb::addr_t, uint64_t)> const &ivar_func)
     {
         lldb_private::Process *process = m_runtime.GetProcess();
 
@@ -1084,7 +1085,8 @@
             {
                 method->Read(process, base_method_list->m_first_ptr + (i * base_method_list->m_entsize));
                 
-                instance_method_func(method->m_name.c_str(), method->m_types.c_str());
+                if (instance_method_func(method->m_name.c_str(), method->m_types.c_str()))
+                    break;
             }
         }
         
@@ -1097,9 +1099,32 @@
             
             metaclass.Describe(std::function <void (ObjCLanguageRuntime::ObjCISA)> (nullptr),
                                class_method_func,
-                               std::function <void (const char *, const char *)> (nullptr));
+                               std::function <bool (const char *, const char *)> (nullptr),
+                               std::function <bool (const char *, const char *, lldb::addr_t, uint64_t)> (nullptr));
         }
-        while (0);
+        
+        if (ivar_func)
+        {
+            std::auto_ptr <ivar_list_t> ivar_list;
+            
+            ivar_list.reset(new ivar_list_t);
+            if (!ivar_list->Read(process, class_ro->m_ivars_ptr))
+                return false;
+            
+            if (ivar_list->m_entsize != ivar_t::GetSize(process))
+                return false;
+            
+            std::auto_ptr <ivar_t> ivar;
+            ivar.reset(new ivar_t);
+            
+            for (uint32_t i = 0, e = ivar_list->m_count; i < e; ++i)
+            {
+                ivar->Read(process, ivar_list->m_first_ptr + (i * ivar_list->m_entsize));
+                
+                if (ivar_func(ivar->m_name.c_str(), ivar->m_type.c_str(), ivar->m_offset_ptr, ivar->m_size))
+                    break;
+            }
+        }
             
         return true;
     }
@@ -1392,6 +1417,98 @@
         }
     };
     
+    struct ivar_list_t
+    {
+        uint32_t        m_entsize;
+        uint32_t        m_count;
+        lldb::addr_t    m_first_ptr;
+        
+        bool Read(Process *process, lldb::addr_t addr)
+        {
+            size_t size = sizeof(uint32_t)  // uint32_t entsize;
+                        + sizeof(uint32_t); // uint32_t count;
+            
+            DataBufferHeap buffer (size, '\0');
+            Error error;
+            
+            process->ReadMemory(addr, buffer.GetBytes(), size, error);
+            if (error.Fail())
+            {
+                return false;
+            }
+            
+            DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize());
+            
+            uint32_t cursor = 0;
+            
+            m_entsize   = extractor.GetU32_unchecked(&cursor);
+            m_count     = extractor.GetU32_unchecked(&cursor);
+            m_first_ptr = addr + cursor;
+            
+            return true;
+        }
+    };
+    
+    struct ivar_t
+    {
+        lldb::addr_t    m_offset_ptr;
+        lldb::addr_t    m_name_ptr;
+        lldb::addr_t    m_type_ptr;
+        uint32_t        m_alignment;
+        uint32_t        m_size;
+        
+        std::string     m_name;
+        std::string     m_type;
+        
+        static size_t GetSize(Process *process)
+        {
+            size_t ptr_size = process->GetAddressByteSize();
+            
+            return ptr_size             // uintptr_t *offset;
+                 + ptr_size             // const char *name;
+                 + ptr_size             // const char *type;
+                 + sizeof(uint32_t)     // uint32_t alignment;
+                 + sizeof(uint32_t);    // uint32_t size;
+        }
+        
+        bool Read(Process *process, lldb::addr_t addr)
+        {
+            size_t size = GetSize(process);
+            
+            DataBufferHeap buffer (size, '\0');
+            Error error;
+            
+            process->ReadMemory(addr, buffer.GetBytes(), size, error);
+            if (error.Fail())
+            {
+                return false;
+            }
+            
+            DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize());
+            
+            uint32_t cursor = 0;
+            
+            m_offset_ptr = extractor.GetAddress_unchecked(&cursor);
+            m_name_ptr   = extractor.GetAddress_unchecked(&cursor);
+            m_type_ptr   = extractor.GetAddress_unchecked(&cursor);
+            m_alignment  = extractor.GetU32_unchecked(&cursor);
+            m_size       = extractor.GetU32_unchecked(&cursor);
+            
+            const size_t buffer_size = 1024;
+            size_t count;
+            
+            DataBufferHeap string_buf(buffer_size, 0);
+            
+            count = process->ReadCStringFromMemory(m_name_ptr, (char*)string_buf.GetBytes(), buffer_size, error);
+            m_name.assign((char*)string_buf.GetBytes(), count);
+            
+            count = process->ReadCStringFromMemory(m_type_ptr, (char*)string_buf.GetBytes(), buffer_size, error);
+            m_type.assign((char*)string_buf.GetBytes(), count);
+            
+            return true;
+        }
+    };
+    
     bool Read_objc_class (Process* process, std::auto_ptr<objc_class_t> &objc_class)
     {
         objc_class.reset(new objc_class_t);
@@ -1864,3 +1981,53 @@
     
     return m_type_vendor_ap.get();
 }
+
+lldb::addr_t
+AppleObjCRuntimeV2::LookupRuntimeSymbol (const ConstString &name)
+{
+    lldb::addr_t ret = LLDB_INVALID_ADDRESS;
+
+    const char *name_cstr = name.AsCString();    
+    
+    if (name_cstr)
+    {
+        llvm::StringRef name_strref(name_cstr);
+        
+        static const llvm::StringRef ivar_prefix("OBJC_IVAR_$_");
+        
+        if (name_strref.startswith(ivar_prefix))
+        {
+            llvm::StringRef ivar_skipped_prefix = name_strref.substr(ivar_prefix.size());
+            std::pair<llvm::StringRef, llvm::StringRef> class_and_ivar = ivar_skipped_prefix.split('.');
+            
+            if (class_and_ivar.first.size() && class_and_ivar.second.size())
+            {
+                const ConstString class_name_cs(class_and_ivar.first);
+                ClassDescriptorSP descriptor = ObjCLanguageRuntime::GetClassDescriptor(class_name_cs);
+                                
+                if (descriptor)
+                {
+                    const ConstString ivar_name_cs(class_and_ivar.second);
+                    const char *ivar_name_cstr = ivar_name_cs.AsCString();
+                    
+                    auto ivar_func = [&ret, ivar_name_cstr](const char *name, const char *type, lldb::addr_t offset_addr, uint64_t size)
+                    {
+                        if (!strcmp(name, ivar_name_cstr))
+                        {
+                            ret = offset_addr;
+                            return true;
+                        }
+                        return false;
+                    };
+
+                    descriptor->Describe(std::function<void (ObjCISA)>(nullptr),
+                                         std::function<bool (const char *, const char *)>(nullptr),
+                                         std::function<bool (const char *, const char *)>(nullptr),
+                                         ivar_func);
+                }
+            }
+        }
+    } 
+    
+    return ret;
+}
diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
index 8dafd0f..5940182 100644
--- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
+++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
@@ -99,6 +99,9 @@
     virtual TypeVendor *
     GetTypeVendor();
     
+    virtual lldb::addr_t
+    LookupRuntimeSymbol (const ConstString &name);
+    
 protected:
     virtual lldb::BreakpointResolverSP
     CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp);
diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeVendor.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeVendor.cpp
index 1ab1063..69f4209 100644
--- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeVendor.cpp
+++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeVendor.cpp
@@ -529,6 +529,8 @@
         
         if (method_decl)
             interface_decl->addDecl(method_decl);
+        
+        return false;
     };
     
     auto class_method_func = [log, interface_decl, this](const char *name, const char *types)
@@ -542,6 +544,8 @@
         
         if (method_decl)
             interface_decl->addDecl(method_decl);
+        
+        return false;
     };
     
     if (log)
@@ -552,7 +556,10 @@
     }
     
     
-    if (!descriptor->Describe(superclass_func, instance_method_func, class_method_func))
+    if (!descriptor->Describe(superclass_func,
+                              instance_method_func,
+                              class_method_func,
+                              std::function <bool (const char *, const char *, lldb::addr_t, uint64_t)> (nullptr)))
         return false;
     
     if (log)