[Lldb-commits] [lldb] r175101 - <rdar://problem/13210494>
Greg Clayton
gclayton at apple.com
Wed Feb 13 14:56:15 PST 2013
Author: gclayton
Date: Wed Feb 13 16:56:14 2013
New Revision: 175101
URL: http://llvm.org/viewvc/llvm-project?rev=175101&view=rev
Log:
<rdar://problem/13210494>
Parse objective C information as efficiently as possible and without taking dangerous runtime locks.
Reworked the way objective C information is parsed by:
1 - don't read all class names up front, this is about 500K of data with names
2 - add a 32 bit hash map that maps a hash of a name to the Class pointer (isa)
3 - Improved name lookups by using the new hash map
4 - split up reading the objc runtime info into dynamic and shared cache since the shared cache only needs to be read once.
5 - When reading all isa values, also get the 32 bit hash instead of the name
6 - Read names lazily now that we don't need all names up front
7 - Allow the hash maps to not be there and still have this function correctly
There is dead code in here with all of the various methods I tried. I want to check this in first to not lose any of it in case we need to revert to any of the extra code. I will promptly cleanup and commit again.
Modified:
lldb/trunk/include/lldb/Core/MappedHash.h
lldb/trunk/include/lldb/Core/Timer.h
lldb/trunk/include/lldb/Expression/ClangFunction.h
lldb/trunk/include/lldb/Target/ObjCLanguageRuntime.h
lldb/trunk/source/Expression/ClangUtilityFunction.cpp
lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
lldb/trunk/source/Target/ObjCLanguageRuntime.cpp
Modified: lldb/trunk/include/lldb/Core/MappedHash.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/MappedHash.h?rev=175101&r1=175100&r2=175101&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/MappedHash.h (original)
+++ lldb/trunk/include/lldb/Core/MappedHash.h Wed Feb 13 16:56:14 2013
@@ -271,7 +271,7 @@ public:
const uint32_t hash = m_entries[i].hash;
const uint32_t bucket_idx = hash % header.bucket_count;
const uint32_t strp_offset = m_entries[i].str_offset;
- const dw_offset_t die_offset = m_entries[i].die_offset;
+ const uint32_t die_offset = m_entries[i].die_offset;
hash_buckets[bucket_idx][hash][strp_offset].push_back(die_offset);
}
Modified: lldb/trunk/include/lldb/Core/Timer.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/Timer.h?rev=175101&r1=175100&r2=175101&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/Timer.h (original)
+++ lldb/trunk/include/lldb/Core/Timer.h Wed Feb 13 16:56:14 2013
@@ -92,6 +92,68 @@ private:
DISALLOW_COPY_AND_ASSIGN (Timer);
};
+class IntervalTimer
+{
+public:
+ IntervalTimer() :
+ m_start (TimeValue::Now())
+ {
+ }
+
+ ~IntervalTimer()
+ {
+ }
+
+ uint64_t
+ GetElapsedNanoSeconds() const
+ {
+ return TimeValue::Now() - m_start;
+ }
+
+ void
+ Reset ()
+ {
+ m_start = TimeValue::Now();
+ }
+
+ int
+ PrintfElapsed (const char *format, ...) __attribute__ ((format (printf, 2, 3)))
+ {
+ TimeValue now (TimeValue::Now());
+ const uint64_t elapsed_nsec = now - m_start;
+ const char *unit = NULL;
+ float elapsed_value;
+ if (elapsed_nsec < 1000)
+ {
+ unit = "ns";
+ elapsed_value = (float)elapsed_nsec;
+ }
+ else if (elapsed_nsec < 1000000)
+ {
+ unit = "us";
+ elapsed_value = (float)elapsed_nsec/1000.0f;
+ }
+ else if (elapsed_nsec < 1000000000)
+ {
+ unit = "ms";
+ elapsed_value = (float)elapsed_nsec/1000000.0f;
+ }
+ else
+ {
+ unit = "sec";
+ elapsed_value = (float)elapsed_nsec/1000000000.0f;
+ }
+ int result = printf ("%3.2f %s: ", elapsed_value, unit);
+ va_list args;
+ va_start (args, format);
+ result += vprintf (format, args);
+ va_end (args);
+ return result;
+ }
+protected:
+ TimeValue m_start;
+};
+
} // namespace lldb_private
#endif // #if defined(__cplusplus)
Modified: lldb/trunk/include/lldb/Expression/ClangFunction.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Expression/ClangFunction.h?rev=175101&r1=175100&r2=175101&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Expression/ClangFunction.h (original)
+++ lldb/trunk/include/lldb/Expression/ClangFunction.h Wed Feb 13 16:56:14 2013
@@ -609,6 +609,11 @@ public:
return false;
}
+ ValueList
+ GetArgumentValues () const
+ {
+ return m_arg_values;
+ }
private:
//------------------------------------------------------------------
// For ClangFunction only
Modified: lldb/trunk/include/lldb/Target/ObjCLanguageRuntime.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/ObjCLanguageRuntime.h?rev=175101&r1=175100&r2=175101&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/ObjCLanguageRuntime.h (original)
+++ lldb/trunk/include/lldb/Target/ObjCLanguageRuntime.h Wed Feb 13 16:56:14 2013
@@ -351,7 +351,7 @@ public:
IsValidISA(ObjCISA isa)
{
UpdateISAToDescriptorMap();
- return m_isa_to_descriptor_cache.count(isa) > 0;
+ return m_isa_to_descriptor.count(isa) > 0;
}
virtual void
@@ -360,7 +360,7 @@ public:
void
UpdateISAToDescriptorMap()
{
- if (m_process && m_process->GetStopID() != m_isa_to_descriptor_cache_stop_id)
+ if (m_process && m_process->GetStopID() != m_isa_to_descriptor_stop_id)
{
UpdateISAToDescriptorMapIfNeeded ();
}
@@ -508,6 +508,40 @@ protected:
{
return false;
}
+
+
+ bool
+ ISAIsCached (ObjCISA isa) const
+ {
+ return m_isa_to_descriptor.find(isa) != m_isa_to_descriptor.end();
+ }
+
+ bool
+ AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp)
+ {
+ if (isa != 0)
+ {
+ m_isa_to_descriptor[isa] = descriptor_sp;
+ return true;
+ }
+ return false;
+ }
+
+ bool
+ AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp, const char *class_name);
+
+ bool
+ AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp, uint32_t class_name_hash)
+ {
+ if (isa != 0)
+ {
+ m_isa_to_descriptor[isa] = descriptor_sp;
+ m_hash_to_isa_map.insert(std::make_pair(class_name_hash, isa));
+ return true;
+ }
+ return false;
+ }
+
private:
// We keep a map of <Class,Selector>->Implementation so we don't have to call the resolver
// function over and over.
@@ -556,17 +590,25 @@ private:
};
typedef std::map<ClassAndSel,lldb::addr_t> MsgImplMap;
+ typedef std::map<ObjCISA, ClassDescriptorSP> ISAToDescriptorMap;
+ typedef std::multimap<uint32_t, ObjCISA> HashToISAMap;
+ typedef ISAToDescriptorMap::iterator ISAToDescriptorIterator;
+ typedef HashToISAMap::iterator HashToISAIterator;
+
MsgImplMap m_impl_cache;
-
LazyBool m_has_new_literals_and_indexing;
+ ISAToDescriptorMap m_isa_to_descriptor;
+ HashToISAMap m_hash_to_isa_map;
+
protected:
- typedef std::map<ObjCISA, ClassDescriptorSP> ISAToDescriptorMap;
- typedef ISAToDescriptorMap::iterator ISAToDescriptorIterator;
- ISAToDescriptorMap m_isa_to_descriptor_cache;
- uint32_t m_isa_to_descriptor_cache_stop_id;
+ uint32_t m_isa_to_descriptor_stop_id;
typedef std::map<ConstString, lldb::TypeWP> CompleteClassMap;
CompleteClassMap m_complete_class_cache;
+
+ ISAToDescriptorIterator
+ GetDescriptorIterator (const ConstString &name);
+
DISALLOW_COPY_AND_ASSIGN (ObjCLanguageRuntime);
};
Modified: lldb/trunk/source/Expression/ClangUtilityFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/ClangUtilityFunction.cpp?rev=175101&r1=175100&r2=175101&view=diff
==============================================================================
--- lldb/trunk/source/Expression/ClangUtilityFunction.cpp (original)
+++ lldb/trunk/source/Expression/ClangUtilityFunction.cpp Wed Feb 13 16:56:14 2013
@@ -28,6 +28,33 @@
using namespace lldb_private;
+static const char *g_global_defines =
+"#undef NULL \n"
+"#undef Nil \n"
+"#undef nil \n"
+"#undef YES \n"
+"#undef NO \n"
+"#define NULL ((int)0) \n"
+"#define Nil ((Class)0) \n"
+"#define nil ((id)0) \n"
+"#define YES ((BOOL)1) \n"
+"#define NO ((BOOL)0) \n"
+"typedef signed char BOOL; \n"
+"typedef signed __INT8_TYPE__ int8_t;\n"
+"typedef unsigned __INT8_TYPE__ uint8_t;\n"
+"typedef signed __INT16_TYPE__ int16_t;\n"
+"typedef unsigned __INT16_TYPE__ uint16_t;\n"
+"typedef signed __INT32_TYPE__ int32_t;\n"
+"typedef unsigned __INT32_TYPE__ uint32_t;\n"
+"typedef signed __INT64_TYPE__ int64_t;\n"
+"typedef unsigned __INT64_TYPE__ uint64_t;\n"
+"typedef signed __INTPTR_TYPE__ intptr_t;\n"
+"typedef unsigned __INTPTR_TYPE__ uintptr_t;\n"
+"typedef __SIZE_TYPE__ size_t; \n"
+"typedef __PTRDIFF_TYPE__ ptrdiff_t;\n"
+"typedef unsigned short unichar;\n";
+
+
//------------------------------------------------------------------
/// Constructor
///
@@ -40,9 +67,11 @@ using namespace lldb_private;
ClangUtilityFunction::ClangUtilityFunction (const char *text,
const char *name) :
ClangExpression (),
- m_function_text (text),
+ m_function_text (g_global_defines),
m_function_name (name)
{
+ if (text && text[0])
+ m_function_text.append (text);
}
ClangUtilityFunction::~ClangUtilityFunction ()
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=175101&r1=175100&r2=175101&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp Wed Feb 13 16:56:14 2013
@@ -364,9 +364,8 @@ AppleObjCRuntimeV1::UpdateISAToDescripto
{
// Update the process stop ID that indicates the last time we updated the
// map, wether it was successful or not.
- m_isa_to_descriptor_cache_stop_id = process->GetStopID();
+ m_isa_to_descriptor_stop_id = process->GetStopID();
-
lldb::LogSP log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
ProcessSP process_sp = process->shared_from_this();
@@ -431,14 +430,14 @@ AppleObjCRuntimeV1::UpdateISAToDescripto
isa = bucket_data;
if (isa)
{
- if (m_isa_to_descriptor_cache.count(isa) == 0)
+ if (!ISAIsCached(isa))
{
ClassDescriptorSP descriptor_sp (new ClassDescriptorV1(isa, process_sp));
if (log && log->GetVerbose())
log->Printf("AppleObjCRuntimeV1 added (ObjCISA)0x%" PRIx64 " from _objc_debug_class_hash to isa->descriptor cache", isa);
- m_isa_to_descriptor_cache[isa] = descriptor_sp;
+ AddClass (isa, descriptor_sp);
}
}
}
@@ -453,14 +452,14 @@ AppleObjCRuntimeV1::UpdateISAToDescripto
if (isa && isa != LLDB_INVALID_ADDRESS)
{
- if (m_isa_to_descriptor_cache.count(isa) == 0)
+ if (!ISAIsCached(isa))
{
ClassDescriptorSP descriptor_sp (new ClassDescriptorV1(isa, process_sp));
if (log && log->GetVerbose())
log->Printf("AppleObjCRuntimeV1 added (ObjCISA)0x%" PRIx64 " from _objc_debug_class_hash to isa->descriptor cache", isa);
- m_isa_to_descriptor_cache[isa] = descriptor_sp;
+ AddClass (isa, descriptor_sp);
}
}
}
@@ -473,7 +472,7 @@ AppleObjCRuntimeV1::UpdateISAToDescripto
}
else
{
- m_isa_to_descriptor_cache_stop_id = UINT32_MAX;
+ m_isa_to_descriptor_stop_id = UINT32_MAX;
}
}
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=175101&r1=175100&r2=175101&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp Wed Feb 13 16:56:14 2013
@@ -24,6 +24,7 @@
#include "lldb/Core/DataBufferMemoryMap.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/Log.h"
+#include "lldb/Core/MappedHash.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Scalar.h"
@@ -51,15 +52,16 @@
using namespace lldb;
using namespace lldb_private;
-
static const char *pluginName = "AppleObjCRuntimeV2";
static const char *pluginDesc = "Apple Objective C Language Runtime - Version 2";
static const char *pluginShort = "language.apple.objc.v2";
+// 2 second timeout when running utility functions
+#define UTILITY_FUNCTION_TIMEOUT_USEC 2*1000*1000
-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\
+static const char *g_find_class_name_function_name = "__lldb_apple_objc_v2_find_class_name";
+static const char *g_find_class_name_function_body = " \n\
extern \"C\" \n\
{ \n\
extern void *gdb_class_getClass (void *objc_class); \n\
@@ -72,9 +74,8 @@ struct __lldb_objc_object {
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\
+extern \"C\" void *__lldb_apple_objc_v2_find_class_name (__lldb_objc_object *object_ptr, \n\
+ int debug) \n\
{ \n\
void *name = 0; \n\
if (debug) \n\
@@ -105,14 +106,11 @@ extern \"C\" void *__lldb_apple_objc_v2_
} \n\
";
-const char *AppleObjCRuntimeV2::g_summarize_classes_function_name = "__lldb_apple_objc_v2_summarize_classes";
-const char *AppleObjCRuntimeV2::g_summarize_classes_function_body = " \n\
+static const char *g_summarize_classes_function_name = "__lldb_apple_objc_v2_summarize_classes";
+static const char *g_summarize_classes_function_body = " \n\
\n\
#define NULL (0) \n\
\n\
-typedef unsigned int uint32_t; \n\
-typedef unsigned long size_t; \n\
- \n\
extern \"C\" \n\
{ \n\
extern void *memset (void *b, int c, size_t len); \n\
@@ -166,6 +164,489 @@ extern \"C\" uint32_t __lldb_apple_objc_
} \n\
";
+static const char *g_get_dynamic_class_info_name = "__lldb_apple_objc_v2_get_dynamic_class_info";
+// Testing using the new C++11 raw string literals. If this breaks GCC then we will
+// need to revert to the code above...
+static const char *g_get_dynamic_class_info_body = R"(
+
+extern "C"
+{
+ size_t strlen(const char *);
+ char *strncpy (char * s1, const char * s2, size_t n);
+ int printf(const char * format, ...);
+}
+//#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN
+#ifdef ENABLE_DEBUG_PRINTF
+#define DEBUG_PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define DEBUG_PRINTF(fmt, ...)
+#endif
+
+typedef struct _NXMapTable {
+ void *prototype;
+ unsigned num_classes;
+ unsigned num_buckets_minus_one;
+ void *buckets;
+} NXMapTable;
+
+#define NX_MAPNOTAKEY ((void *)(-1))
+
+typedef struct BucketInfo
+{
+ const char *name_ptr;
+ Class isa;
+} BucketInfo;
+
+typedef struct ClassInfo
+{
+ Class isa;
+ const char *name_ptr;
+ char name[32];
+} ClassInfo;
+
+uint32_t
+__lldb_apple_objc_v2_get_dynamic_class_info (void *gdb_objc_realized_classes_ptr,
+ void *class_infos_ptr,
+ uint32_t class_infos_byte_size)
+{
+ DEBUG_PRINTF ("gdb_objc_realized_classes_ptr = %p\n", gdb_objc_realized_classes_ptr);
+ DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);
+ DEBUG_PRINTF ("class_infos_byte_size = %u\n", class_infos_byte_size);
+ const NXMapTable *grc = (const NXMapTable *)gdb_objc_realized_classes_ptr;
+ if (grc)
+ {
+ const unsigned num_classes = grc->num_classes;
+ if (class_infos_ptr)
+ {
+ const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);
+ ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;
+ BucketInfo *buckets = (BucketInfo *)grc->buckets;
+
+ uint32_t class_info_idx = 0;
+ for (unsigned i=0; i<=grc->num_buckets_minus_one; ++i)
+ {
+ if (buckets[i].name_ptr != NX_MAPNOTAKEY)
+ {
+ if (class_info_idx < max_class_infos)
+ {
+ if (strlen(buckets[i].name_ptr) < sizeof(class_infos[class_info_idx].name))
+ {
+ strncpy(class_infos[class_info_idx].name, buckets[i].name_ptr, sizeof(class_infos[class_info_idx].name));
+ class_infos[class_info_idx].name_ptr = 0;
+ }
+ else
+ {
+ class_infos[class_info_idx].name[0] = '\0';
+ class_infos[class_info_idx].name_ptr = buckets[i].name_ptr;
+ }
+ class_infos[class_info_idx].isa = buckets[i].isa;
+ }
+ ++class_info_idx;
+ }
+ }
+ if (class_info_idx < max_class_infos)
+ {
+ class_infos[class_info_idx].isa = NULL;
+ class_infos[class_info_idx].name_ptr = NULL;
+ class_infos[class_info_idx].name[0] = '\0';
+ }
+ }
+ return num_classes;
+ }
+ return 0;
+}
+
+)";
+
+
+static const char *g_get_dynamic_class_info2_name = "__lldb_apple_objc_v2_get_dynamic_class_info2";
+// Testing using the new C++11 raw string literals. If this breaks GCC then we will
+// need to revert to the code above...
+static const char *g_get_dynamic_class_info2_body = R"(
+
+extern "C"
+{
+ size_t strlen(const char *);
+ char *strncpy (char * s1, const char * s2, size_t n);
+ int printf(const char * format, ...);
+}
+//#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN
+#ifdef ENABLE_DEBUG_PRINTF
+#define DEBUG_PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define DEBUG_PRINTF(fmt, ...)
+#endif
+
+typedef struct _NXMapTable {
+ void *prototype;
+ unsigned num_classes;
+ unsigned num_buckets_minus_one;
+ void *buckets;
+} NXMapTable;
+
+#define NX_MAPNOTAKEY ((void *)(-1))
+
+typedef struct BucketInfo
+{
+ const char *name_ptr;
+ Class isa;
+} BucketInfo;
+
+struct ClassInfo
+{
+ Class isa;
+ uint32_t hash;
+} __attribute__((__packed__));
+
+uint32_t
+__lldb_apple_objc_v2_get_dynamic_class_info2 (void *gdb_objc_realized_classes_ptr,
+ void *class_infos_ptr,
+ uint32_t class_infos_byte_size)
+{
+ DEBUG_PRINTF ("gdb_objc_realized_classes_ptr = %p\n", gdb_objc_realized_classes_ptr);
+ DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);
+ DEBUG_PRINTF ("class_infos_byte_size = %u\n", class_infos_byte_size);
+ const NXMapTable *grc = (const NXMapTable *)gdb_objc_realized_classes_ptr;
+ if (grc)
+ {
+ const unsigned num_classes = grc->num_classes;
+ if (class_infos_ptr)
+ {
+ const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);
+ ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;
+ BucketInfo *buckets = (BucketInfo *)grc->buckets;
+
+ uint32_t idx = 0;
+ for (unsigned i=0; i<=grc->num_buckets_minus_one; ++i)
+ {
+ if (buckets[i].name_ptr != NX_MAPNOTAKEY)
+ {
+ if (idx < max_class_infos)
+ {
+ const char *s = buckets[i].name_ptr;
+ uint32_t h = 5381;
+ for (unsigned char c = *s; c; c = *++s)
+ h = ((h << 5) + h) + c;
+ class_infos[idx].hash = h;
+ class_infos[idx].isa = buckets[i].isa;
+ }
+ ++idx;
+ }
+ }
+ if (idx < max_class_infos)
+ {
+ class_infos[idx].isa = NULL;
+ class_infos[idx].hash = 0;
+ }
+ }
+ return num_classes;
+ }
+ return 0;
+}
+
+)";
+
+
+static const char *g_get_shared_cache_class_info_name = "__lldb_apple_objc_v2_get_shared_cache_class_info";
+// Testing using the new C++11 raw string literals. If this breaks GCC then we will
+// need to revert to the code above...
+static const char *g_get_shared_cache_class_info_body = R"(
+
+extern "C"
+{
+ const char *class_getName(void *objc_class);
+ size_t strlen(const char *);
+ char *strncpy (char * s1, const char * s2, size_t n);
+ int printf(const char * format, ...);
+}
+
+//#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN
+#ifdef ENABLE_DEBUG_PRINTF
+#define DEBUG_PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define DEBUG_PRINTF(fmt, ...)
+#endif
+
+
+struct objc_classheader_t {
+ int32_t clsOffset;
+ int32_t hiOffset;
+};
+
+struct objc_clsopt_t {
+ uint32_t capacity;
+ uint32_t occupied;
+ uint32_t shift;
+ uint32_t mask;
+ uint32_t zero;
+ uint32_t unused;
+ uint64_t salt;
+ uint32_t scramble[256];
+ uint8_t tab[0]; // tab[mask+1]
+// uint8_t checkbytes[capacity];
+// int32_t offset[capacity];
+// objc_classheader_t clsOffsets[capacity];
+// uint32_t duplicateCount;
+// objc_classheader_t duplicateOffsets[duplicateCount];
+};
+
+struct objc_opt_t {
+ uint32_t version;
+ int32_t selopt_offset;
+ int32_t headeropt_offset;
+ int32_t clsopt_offset;
+};
+
+struct ClassInfo
+{
+ Class isa;
+ const char *name_ptr;
+ char name[32];
+};
+
+uint32_t
+__lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
+ void *class_infos_ptr,
+ uint32_t class_infos_byte_size)
+{
+ uint32_t idx = 0;
+ DEBUG_PRINTF ("objc_opt_ro_ptr = %p\n", objc_opt_ro_ptr);
+ DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);
+ DEBUG_PRINTF ("class_infos_byte_size = %u (%zu class infos)\n", class_infos_byte_size, (size_t)(class_infos_byte_size/sizeof(ClassInfo)));
+ if (objc_opt_ro_ptr)
+ {
+ const objc_opt_t *objc_opt = (objc_opt_t *)objc_opt_ro_ptr;
+ DEBUG_PRINTF ("objc_opt->version = %u\n", objc_opt->version);
+ DEBUG_PRINTF ("objc_opt->selopt_offset = %d\n", objc_opt->selopt_offset);
+ DEBUG_PRINTF ("objc_opt->headeropt_offset = %d\n", objc_opt->headeropt_offset);
+ DEBUG_PRINTF ("objc_opt->clsopt_offset = %d\n", objc_opt->clsopt_offset);
+ if (objc_opt->version == 12)
+ {
+ const objc_clsopt_t* clsopt = (const objc_clsopt_t*)((uint8_t *)objc_opt + objc_opt->clsopt_offset);
+ const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);
+ ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;
+ int32_t zeroOffset = 16;
+ const uint8_t *checkbytes = &clsopt->tab[clsopt->mask+1];
+ const int32_t *offsets = (const int32_t *)(checkbytes + clsopt->capacity);
+ const objc_classheader_t *classOffsets = (const objc_classheader_t *)(offsets + clsopt->capacity);
+ DEBUG_PRINTF ("clsopt->capacity = %u\n", clsopt->capacity);
+ DEBUG_PRINTF ("clsopt->mask = 0x%8.8x\n", clsopt->mask);
+ DEBUG_PRINTF ("classOffsets = %p\n", classOffsets);
+ for (uint32_t i=0; i<clsopt->capacity; ++i)
+ {
+ const int32_t clsOffset = classOffsets[i].clsOffset;
+ if (clsOffset & 1)
+ continue; // duplicate
+ else if (clsOffset == zeroOffset)
+ continue; // zero offset
+
+ if (class_infos && idx < max_class_infos)
+ {
+ class_infos[idx].isa = (Class)((uint8_t *)clsopt + clsOffset);
+ const char *name = class_getName (class_infos[idx].isa);
+ DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
+ if (strlen(name) < sizeof(class_infos[idx].name))
+ {
+ strncpy(class_infos[idx].name, name, sizeof(class_infos[idx].name));
+ class_infos[idx].name_ptr = 0;
+ }
+ else
+ {
+ class_infos[idx].name[0] = '\0';
+ class_infos[idx].name_ptr = name;
+ }
+ }
+ ++idx;
+ }
+
+ const uint32_t *duplicate_count_ptr = (uint32_t *)&classOffsets[clsopt->capacity];
+ const uint32_t duplicate_count = *duplicate_count_ptr;
+ const objc_classheader_t *duplicateClassOffsets = (const objc_classheader_t *)(&duplicate_count_ptr[1]);
+ DEBUG_PRINTF ("duplicate_count = %u\n", duplicate_count);
+ DEBUG_PRINTF ("duplicateClassOffsets = %p\n", duplicateClassOffsets);
+ for (uint32_t i=0; i<duplicate_count; ++i)
+ {
+ const int32_t clsOffset = duplicateClassOffsets[i].clsOffset;
+ if (clsOffset & 1)
+ continue; // duplicate
+ else if (clsOffset == zeroOffset)
+ continue; // zero offset
+
+ if (class_infos && idx < max_class_infos)
+ {
+ class_infos[idx].isa = (Class)((uint8_t *)clsopt + clsOffset);
+ const char *name = class_getName (class_infos[idx].isa);
+ DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
+ if (strlen(name) < sizeof(class_infos[idx].name))
+ {
+ strncpy(class_infos[idx].name, name, sizeof(class_infos[idx].name));
+ class_infos[idx].name_ptr = 0;
+ }
+ else
+ {
+ class_infos[idx].name[0] = '\0';
+ class_infos[idx].name_ptr = name;
+ }
+ }
+ ++idx;
+ }
+ }
+ DEBUG_PRINTF ("%u class_infos\n", idx);
+ DEBUG_PRINTF ("done\n");
+ }
+ return idx;
+}
+
+
+)";
+
+
+
+static const char *g_get_shared_cache_class_info2_name = "__lldb_apple_objc_v2_get_shared_cache_class_info2";
+// Testing using the new C++11 raw string literals. If this breaks GCC then we will
+// need to revert to the code above...
+static const char *g_get_shared_cache_class_info2_body = R"(
+
+extern "C"
+{
+ const char *class_getName(void *objc_class);
+ size_t strlen(const char *);
+ char *strncpy (char * s1, const char * s2, size_t n);
+ int printf(const char * format, ...);
+}
+
+//#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN
+#ifdef ENABLE_DEBUG_PRINTF
+#define DEBUG_PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define DEBUG_PRINTF(fmt, ...)
+#endif
+
+
+struct objc_classheader_t {
+ int32_t clsOffset;
+ int32_t hiOffset;
+};
+
+struct objc_clsopt_t {
+ uint32_t capacity;
+ uint32_t occupied;
+ uint32_t shift;
+ uint32_t mask;
+ uint32_t zero;
+ uint32_t unused;
+ uint64_t salt;
+ uint32_t scramble[256];
+ uint8_t tab[0]; // tab[mask+1]
+ // uint8_t checkbytes[capacity];
+ // int32_t offset[capacity];
+ // objc_classheader_t clsOffsets[capacity];
+ // uint32_t duplicateCount;
+ // objc_classheader_t duplicateOffsets[duplicateCount];
+};
+
+struct objc_opt_t {
+ uint32_t version;
+ int32_t selopt_offset;
+ int32_t headeropt_offset;
+ int32_t clsopt_offset;
+};
+
+struct ClassInfo
+{
+ Class isa;
+ uint32_t hash;
+} __attribute__((__packed__));
+
+uint32_t
+__lldb_apple_objc_v2_get_shared_cache_class_info2 (void *objc_opt_ro_ptr,
+ void *class_infos_ptr,
+ uint32_t class_infos_byte_size)
+{
+ uint32_t idx = 0;
+ DEBUG_PRINTF ("objc_opt_ro_ptr = %p\n", objc_opt_ro_ptr);
+ DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);
+ DEBUG_PRINTF ("class_infos_byte_size = %u (%zu class infos)\n", class_infos_byte_size, (size_t)(class_infos_byte_size/sizeof(ClassInfo)));
+ if (objc_opt_ro_ptr)
+ {
+ const objc_opt_t *objc_opt = (objc_opt_t *)objc_opt_ro_ptr;
+ DEBUG_PRINTF ("objc_opt->version = %u\n", objc_opt->version);
+ DEBUG_PRINTF ("objc_opt->selopt_offset = %d\n", objc_opt->selopt_offset);
+ DEBUG_PRINTF ("objc_opt->headeropt_offset = %d\n", objc_opt->headeropt_offset);
+ DEBUG_PRINTF ("objc_opt->clsopt_offset = %d\n", objc_opt->clsopt_offset);
+ if (objc_opt->version == 12)
+ {
+ const objc_clsopt_t* clsopt = (const objc_clsopt_t*)((uint8_t *)objc_opt + objc_opt->clsopt_offset);
+ const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);
+ ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;
+ int32_t zeroOffset = 16;
+ const uint8_t *checkbytes = &clsopt->tab[clsopt->mask+1];
+ const int32_t *offsets = (const int32_t *)(checkbytes + clsopt->capacity);
+ const objc_classheader_t *classOffsets = (const objc_classheader_t *)(offsets + clsopt->capacity);
+ DEBUG_PRINTF ("clsopt->capacity = %u\n", clsopt->capacity);
+ DEBUG_PRINTF ("clsopt->mask = 0x%8.8x\n", clsopt->mask);
+ DEBUG_PRINTF ("classOffsets = %p\n", classOffsets);
+ for (uint32_t i=0; i<clsopt->capacity; ++i)
+ {
+ const int32_t clsOffset = classOffsets[i].clsOffset;
+ if (clsOffset & 1)
+ continue; // duplicate
+ else if (clsOffset == zeroOffset)
+ continue; // zero offset
+
+ if (class_infos && idx < max_class_infos)
+ {
+ class_infos[idx].isa = (Class)((uint8_t *)clsopt + clsOffset);
+ const char *name = class_getName (class_infos[idx].isa);
+ DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
+ // Hash the class name so we don't have to read it
+ const char *s = name;
+ uint32_t h = 5381;
+ for (unsigned char c = *s; c; c = *++s)
+ h = ((h << 5) + h) + c;
+ class_infos[idx].hash = h;
+ }
+ ++idx;
+ }
+
+ const uint32_t *duplicate_count_ptr = (uint32_t *)&classOffsets[clsopt->capacity];
+ const uint32_t duplicate_count = *duplicate_count_ptr;
+ const objc_classheader_t *duplicateClassOffsets = (const objc_classheader_t *)(&duplicate_count_ptr[1]);
+ DEBUG_PRINTF ("duplicate_count = %u\n", duplicate_count);
+ DEBUG_PRINTF ("duplicateClassOffsets = %p\n", duplicateClassOffsets);
+ for (uint32_t i=0; i<duplicate_count; ++i)
+ {
+ const int32_t clsOffset = duplicateClassOffsets[i].clsOffset;
+ if (clsOffset & 1)
+ continue; // duplicate
+ else if (clsOffset == zeroOffset)
+ continue; // zero offset
+
+ if (class_infos && idx < max_class_infos)
+ {
+ class_infos[idx].isa = (Class)((uint8_t *)clsopt + clsOffset);
+ const char *name = class_getName (class_infos[idx].isa);
+ DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
+ // Hash the class name so we don't have to read it
+ const char *s = name;
+ uint32_t h = 5381;
+ for (unsigned char c = *s; c; c = *++s)
+ h = ((h << 5) + h) + c;
+ class_infos[idx].hash = h;
+ }
+ ++idx;
+ }
+ }
+ DEBUG_PRINTF ("%u class_infos\n", idx);
+ DEBUG_PRINTF ("done\n");
+ }
+ return idx;
+}
+
+
+)";
+
+
AppleObjCRuntimeV2::AppleObjCRuntimeV2 (Process *process,
const ModuleSP &objc_module_sp) :
AppleObjCRuntime (process),
@@ -177,6 +658,14 @@ AppleObjCRuntimeV2::AppleObjCRuntimeV2 (
m_names_allocation (LLDB_INVALID_ADDRESS),
m_summarize_classes_args (LLDB_INVALID_ADDRESS),
m_summarize_classes_args_mutex (Mutex::eMutexTypeNormal),
+ m_get_class_info_function(),
+ m_get_class_info_code(),
+ m_get_class_info_args (LLDB_INVALID_ADDRESS),
+ m_get_class_info_args_mutex (Mutex::eMutexTypeNormal),
+ m_get_shared_cache_class_info_function(),
+ m_get_shared_cache_class_info_code(),
+ m_get_shared_cache_class_info_args (LLDB_INVALID_ADDRESS),
+ m_get_shared_cache_class_info_args_mutex (Mutex::eMutexTypeNormal),
m_type_vendor_ap (),
m_isa_hash_table_ptr (LLDB_INVALID_ADDRESS),
m_hash_signature (),
@@ -557,6 +1046,15 @@ public:
{
}
+ void
+ Dump ()
+ {
+ printf ("RemoteNXMapTable.m_load_addr = 0x%llx\n", m_load_addr);
+ printf ("RemoteNXMapTable.m_count = %u\n", m_count);
+ printf ("RemoteNXMapTable.m_num_buckets_minus_one = %u\n", m_num_buckets_minus_one);
+ printf ("RemoteNXMapTable.m_buckets_ptr = 0x%llx\n", m_buckets_ptr);
+ }
+
bool
ParseHeader (Process* process, lldb::addr_t load_addr)
{
@@ -737,6 +1235,12 @@ public:
{
return m_buckets_ptr;
}
+
+ lldb::addr_t
+ GetTableLoadAddress() const
+ {
+ return m_load_addr;
+ }
private:
// contents of _NXMapTable struct
@@ -1032,7 +1536,7 @@ private:
m_name (name)
{
}
-
+
public:
virtual ConstString
GetClassName ()
@@ -1906,380 +2410,1383 @@ AppleObjCRuntimeV2::GetISAHashTablePoint
return m_isa_hash_table_ptr;
}
-void
-AppleObjCRuntimeV2::UpdateISAToDescriptorMapIfNeeded()
+
+bool
+AppleObjCRuntimeV2::UpdateISAToDescriptorMapUsingUtilityFunction_objc_getClassList()
{
- Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
-
- // Else we need to check with our process to see when the map was updated.
Process *process = GetProcess();
-
- if (process)
- {
- RemoteNXMapTable hash_table;
+
+ if (process == NULL)
+ return false;
+
+ lldb::LogSP log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ ExecutionContext exe_ctx;
+
+ ThreadSP thread_sp = process->GetThreadList().GetSelectedThread();
+
+ if (!thread_sp)
+ return false;
+
+ thread_sp->CalculateExecutionContext(exe_ctx);
+ ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext();
+
+ if (!clang_ast_context)
+ return false;
+
+ Address summarize_classes_address;
+
+ StreamString errors;
+
+ if (!m_summarize_classes_code.get())
+ {
+ m_summarize_classes_code.reset (new ClangUtilityFunction (g_summarize_classes_function_body,
+ g_summarize_classes_function_name));
- // Update the process stop ID that indicates the last time we updated the
- // map, wether it was successful or not.
- m_isa_to_descriptor_cache_stop_id = process->GetStopID();
+ errors.Clear();
- if (!m_hash_signature.NeedsUpdate(process, this, hash_table))
- return;
+ if (!m_summarize_classes_code->Install(errors, exe_ctx))
+ {
+ if (log)
+ log->Printf ("Failed to install implementation lookup: %s.", errors.GetData());
+ m_summarize_classes_code.reset();
+ return false;
+ }
+ summarize_classes_address.Clear();
+ summarize_classes_address.SetOffset(m_summarize_classes_code->StartAddress());
+ }
+ else
+ {
+ summarize_classes_address.Clear();
+ summarize_classes_address.SetOffset(m_summarize_classes_code->StartAddress());
+ }
+
+ const uint32_t name_size = 32;
+
+ Error err;
+
+ if (m_isas_allocation != LLDB_INVALID_ADDRESS)
+ process->DeallocateMemory(m_isas_allocation);
+
+ if (m_names_allocation != LLDB_INVALID_ADDRESS)
+ process->DeallocateMemory(m_names_allocation);
+
+ // This must be kept in sync with the definition in g_summarize_classes_function_body!
+
+ clang_type_t clang_uint32_t_type = clang_ast_context->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
+ clang_type_t clang_void_pointer_type = clang_ast_context->CreatePointerType(clang_ast_context->GetBuiltInType_void());
+
+ Value isas_value;
+ isas_value.SetValueType (Value::eValueTypeScalar);
+ isas_value.SetContext (Value::eContextTypeClangType, clang_void_pointer_type);
+ isas_value.GetScalar() = 0;
+
+ Value names_value;
+ names_value.SetValueType (Value::eValueTypeScalar);
+ names_value.SetContext (Value::eContextTypeClangType, clang_void_pointer_type);
+ names_value.GetScalar() = 0;
+
+ Value num_isas_assumed_value;
+ num_isas_assumed_value.SetValueType (Value::eValueTypeScalar);
+ num_isas_assumed_value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type);
+ num_isas_assumed_value.GetScalar() = 0;
+
+ Value name_size_value;
+ name_size_value.SetValueType (Value::eValueTypeScalar);
+ name_size_value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type);
+ name_size_value.GetScalar() = 0;
+
+ ValueList dispatch_values;
+ dispatch_values.PushValue (isas_value);
+ dispatch_values.PushValue (names_value);
+ dispatch_values.PushValue (num_isas_assumed_value);
+ dispatch_values.PushValue (name_size_value);
+
+ // Next make the runner function for our implementation utility function.
+ if (!m_summarize_classes_function.get())
+ {
+ m_summarize_classes_function.reset(new ClangFunction (*m_process,
+ clang_ast_context,
+ clang_uint32_t_type,
+ summarize_classes_address,
+ dispatch_values));
- m_hash_signature.UpdateSignature (hash_table);
-
- do
+ errors.Clear();
+
+ unsigned num_errors = m_summarize_classes_function->CompileFunction(errors);
+ if (num_errors)
{
- Mutex::Locker locker(m_summarize_classes_args_mutex);
-
- lldb::LogSP log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
-
- ExecutionContext exe_ctx;
-
- ThreadSP thread_sp = process->GetThreadList().GetSelectedThread();
-
- if (!thread_sp)
- break;
-
- thread_sp->CalculateExecutionContext(exe_ctx);
- ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext();
-
- if (!clang_ast_context)
- break;
-
- Address summarize_classes_address;
-
- StreamString errors;
-
- if (!m_summarize_classes_code.get())
- {
- m_summarize_classes_code.reset (new ClangUtilityFunction (g_summarize_classes_function_body,
- g_summarize_classes_function_name));
-
- errors.Clear();
-
- if (!m_summarize_classes_code->Install(errors, exe_ctx))
- {
- if (log)
- log->Printf ("Failed to install implementation lookup: %s.", errors.GetData());
- m_summarize_classes_code.reset();
- break;
- }
- summarize_classes_address.Clear();
- summarize_classes_address.SetOffset(m_summarize_classes_code->StartAddress());
- }
- else
- {
- summarize_classes_address.Clear();
- summarize_classes_address.SetOffset(m_summarize_classes_code->StartAddress());
- }
-
- const uint32_t name_size = 32;
-
- Error err;
-
- if (m_isas_allocation != LLDB_INVALID_ADDRESS)
- process->DeallocateMemory(m_isas_allocation);
-
- if (m_names_allocation != LLDB_INVALID_ADDRESS)
- process->DeallocateMemory(m_names_allocation);
-
- // This must be kept in sync with the definition in g_summarize_classes_function_body!
-
- clang_type_t clang_uint32_t_type = clang_ast_context->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
- clang_type_t clang_void_pointer_type = clang_ast_context->CreatePointerType(clang_ast_context->GetBuiltInType_void());
-
- Value isas_value;
- isas_value.SetValueType (Value::eValueTypeScalar);
- isas_value.SetContext (Value::eContextTypeClangType, clang_void_pointer_type);
- isas_value.GetScalar() = 0;
-
- Value names_value;
- names_value.SetValueType (Value::eValueTypeScalar);
- names_value.SetContext (Value::eContextTypeClangType, clang_void_pointer_type);
- names_value.GetScalar() = 0;
-
- Value num_isas_assumed_value;
- num_isas_assumed_value.SetValueType (Value::eValueTypeScalar);
- num_isas_assumed_value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type);
- num_isas_assumed_value.GetScalar() = 0;
-
- Value name_size_value;
- name_size_value.SetValueType (Value::eValueTypeScalar);
- name_size_value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type);
- name_size_value.GetScalar() = 0;
-
- ValueList dispatch_values;
- dispatch_values.PushValue (isas_value);
- dispatch_values.PushValue (names_value);
- dispatch_values.PushValue (num_isas_assumed_value);
- dispatch_values.PushValue (name_size_value);
-
- // Next make the runner function for our implementation utility function.
- if (!m_summarize_classes_function.get())
- {
- m_summarize_classes_function.reset(new ClangFunction (*m_process,
- clang_ast_context,
- clang_uint32_t_type,
- summarize_classes_address,
- dispatch_values));
-
- errors.Clear();
-
- unsigned num_errors = m_summarize_classes_function->CompileFunction(errors);
- if (num_errors)
- {
- if (log)
- log->Printf ("Error compiling function: \"%s\".", errors.GetData());
- break;
- }
-
- errors.Clear();
-
- if (!m_summarize_classes_function->WriteFunctionWrapper(exe_ctx, errors))
- {
- if (log)
- log->Printf ("Error Inserting function: \"%s\".", errors.GetData());
- break;
- }
- }
-
- if (m_summarize_classes_code.get() == NULL || m_summarize_classes_function.get() == NULL)
- break;
-
- // Write the initial arguments: (NULL, NULL, 0, 0). The return value will be the
- // new value of num_isas.
-
- {
- errors.Clear();
-
- if (!m_summarize_classes_function->WriteFunctionArguments (exe_ctx, m_summarize_classes_args, summarize_classes_address, dispatch_values, errors))
- {
- if (log)
- log->Printf ("Error writing function arguments: \"%s\".", errors.GetData());
- break;
-
- }
- }
-
- bool stop_others = true;
- bool try_all_threads = false;
- bool unwind_on_error = true;
- bool ignore_breakpoints = true;
-
- Value num_isas_value;
- num_isas_value.SetValueType (Value::eValueTypeScalar);
- num_isas_value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type);
- num_isas_value.GetScalar() = 0;
-
- errors.Clear();
-
- ExecutionResults results = m_summarize_classes_function->ExecuteFunction (exe_ctx,
- &m_summarize_classes_args,
- errors,
- stop_others,
- 100000,
- try_all_threads,
- unwind_on_error,
- ignore_breakpoints,
- num_isas_value);
-
- if (results != eExecutionCompleted)
- {
- if (log)
- log->Printf("Error evaluating our find class name function: %s.\n", errors.GetData());
- break;
- }
-
- // With the result from that, allocate real buffers.
-
- uint32_t num_isas = num_isas_value.GetScalar().ULong();
-
if (log)
- log->Printf("Fast class summary mode reports %u isas\n", num_isas);
-
- uint32_t isas_allocation_size = num_isas * process->GetAddressByteSize();
- uint32_t names_allocation_size = num_isas * name_size;
-
- if (m_isas_allocation == LLDB_INVALID_ADDRESS)
- {
- m_isas_allocation = process->AllocateMemory(isas_allocation_size,
- ePermissionsReadable | ePermissionsWritable,
- err);
-
- if (m_isas_allocation == LLDB_INVALID_ADDRESS)
- break;
- }
-
- if (m_names_allocation == LLDB_INVALID_ADDRESS)
- {
- m_names_allocation = process->AllocateMemory(names_allocation_size,
- ePermissionsReadable | ePermissionsWritable,
- err);
-
- if (m_names_allocation == LLDB_INVALID_ADDRESS)
- break;
+ log->Printf ("Error compiling function: \"%s\".", errors.GetData());
+ return false;
+ }
+
+ errors.Clear();
+
+ if (!m_summarize_classes_function->WriteFunctionWrapper(exe_ctx, errors))
+ {
+ if (log)
+ log->Printf ("Error Inserting function: \"%s\".", errors.GetData());
+ return false;
+ }
+ }
+
+ if (m_summarize_classes_code.get() == NULL || m_summarize_classes_function.get() == NULL)
+ return false;
+
+ // Write the initial arguments: (NULL, NULL, 0, 0). The return value will be the
+ // new value of num_isas.
+
+ Mutex::Locker locker(m_summarize_classes_args_mutex);
+
+ errors.Clear();
+
+ if (!m_summarize_classes_function->WriteFunctionArguments (exe_ctx,
+ m_summarize_classes_args,
+ summarize_classes_address,
+ dispatch_values,
+ errors))
+ {
+ if (log)
+ log->Printf ("Error writing function arguments: \"%s\".", errors.GetData());
+ return false;
+ }
+
+ bool stop_others = true;
+ bool try_all_threads = false;
+ bool unwind_on_error = true;
+ bool ignore_breakpoints = true;
+
+ Value num_isas_value;
+ num_isas_value.SetValueType (Value::eValueTypeScalar);
+ num_isas_value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type);
+ num_isas_value.GetScalar() = 0;
+
+ errors.Clear();
+
+ ExecutionResults results = m_summarize_classes_function->ExecuteFunction (exe_ctx,
+ &m_summarize_classes_args,
+ errors,
+ stop_others,
+ UTILITY_FUNCTION_TIMEOUT_USEC,
+ try_all_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ num_isas_value);
+
+ if (results != eExecutionCompleted)
+ {
+ if (log)
+ log->Printf("Error evaluating our find class name function: %s.\n", errors.GetData());
+ return false;
+ }
+
+ // With the result from that, allocate real buffers.
+
+ uint32_t num_isas = num_isas_value.GetScalar().ULong();
+
+ if (log)
+ log->Printf("Fast class summary mode reports %u isas\n", num_isas);
+
+ const uint32_t addr_size = process->GetAddressByteSize();
+ uint32_t isas_allocation_size = num_isas * addr_size;
+ uint32_t names_allocation_size = num_isas * name_size;
+
+ if (m_isas_allocation == LLDB_INVALID_ADDRESS)
+ {
+ m_isas_allocation = process->AllocateMemory(isas_allocation_size,
+ ePermissionsReadable | ePermissionsWritable,
+ err);
+
+ if (m_isas_allocation == LLDB_INVALID_ADDRESS)
+ return false;
+ }
+
+ if (m_names_allocation == LLDB_INVALID_ADDRESS)
+ {
+ m_names_allocation = process->AllocateMemory(names_allocation_size,
+ ePermissionsReadable | ePermissionsWritable,
+ err);
+
+ if (m_names_allocation == LLDB_INVALID_ADDRESS)
+ return false;
+ }
+
+ // Write the final arguments.
+
+ dispatch_values.Clear();
+
+ isas_value.GetScalar() = m_isas_allocation;
+ names_value.GetScalar() = m_names_allocation;
+ num_isas_assumed_value.GetScalar() = num_isas;
+ name_size_value.GetScalar() = name_size;
+
+ dispatch_values.PushValue (isas_value);
+ dispatch_values.PushValue (names_value);
+ dispatch_values.PushValue (num_isas_assumed_value);
+ dispatch_values.PushValue (name_size_value);
+
+ errors.Clear();
+
+ if (!m_summarize_classes_function->WriteFunctionArguments (exe_ctx, m_summarize_classes_args, summarize_classes_address, dispatch_values, errors))
+ {
+ if (log)
+ log->Printf ("Error writing function arguments: \"%s\".", errors.GetData());
+ return false;
+
+ }
+
+ errors.Clear();
+
+ results = m_summarize_classes_function->ExecuteFunction (exe_ctx,
+ &m_summarize_classes_args,
+ errors,
+ stop_others,
+ UTILITY_FUNCTION_TIMEOUT_USEC,
+ try_all_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ num_isas_value);
+
+ if (results != eExecutionCompleted)
+ {
+ if (log)
+ log->Printf("Error evaluating our find class name function: %s.\n", errors.GetData());
+ return false;
+ }
+
+ DataBufferHeap isas_buffer(isas_allocation_size, 0);
+ DataBufferHeap names_buffer(names_allocation_size, 0);
+
+ if (process->ReadMemory(m_isas_allocation, isas_buffer.GetBytes(), isas_allocation_size, err) != isas_allocation_size)
+ return false;
+
+ if (process->ReadMemory(m_names_allocation, names_buffer.GetBytes(), names_allocation_size, err) != names_allocation_size)
+ return false;
+
+ DataExtractor isa_extractor(isas_buffer.GetBytes(), isas_allocation_size, process->GetByteOrder(), addr_size);
+
+ lldb::offset_t offset = 0;
+
+ for (size_t index = 0; index < num_isas; ++index)
+ {
+ uint64_t isa = isa_extractor.GetPointer(&offset);
+
+ const char *name = (const char*)(names_buffer.GetBytes() + (name_size * index));
+
+ if (log && log->GetVerbose())
+ log->Printf("Fast class summary mode found isa 0x%llx (%s)", isa, name);
+
+ // The name can only be relied upon if it is NULL-terminated.
+ // Otherwise it ran off its allocation and has been partially overwritten by the next name.
+
+ ClassDescriptorSP descriptor_sp;
+
+ if (name[name_size - 1] == '\0')
+ AddClass (isa, ClassDescriptorSP(new ClassDescriptorV2(*this, isa, name)), name);
+ else
+ AddClass (isa, ClassDescriptorSP(new ClassDescriptorV2(*this, isa, NULL)));
+ }
+
+ return true;
+}
+
+
+bool
+AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic(RemoteNXMapTable &hash_table)
+{
+ Process *process = GetProcess();
+
+ if (process == NULL)
+ return false;
+
+ lldb::LogSP log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ ExecutionContext exe_ctx;
+
+ ThreadSP thread_sp = process->GetThreadList().GetSelectedThread();
+
+ if (!thread_sp)
+ return false;
+
+ thread_sp->CalculateExecutionContext(exe_ctx);
+ ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext();
+
+ if (!ast)
+ return false;
+
+ Address function_address;
+
+ StreamString errors;
+
+ const uint32_t addr_size = process->GetAddressByteSize();
+
+ Error err;
+
+ // Read the total number of classes from the hash table
+ const uint32_t num_classes = hash_table.GetCount();
+ if (num_classes == 0)
+ {
+ if (log)
+ log->Printf ("No dynamic classes found in gdb_objc_realized_classes.");
+ return false;
+ }
+
+ // Make some types for our arguments
+ clang_type_t clang_uint32_t_type = ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
+ clang_type_t clang_void_pointer_type = ast->CreatePointerType(ast->GetBuiltInType_void());
+
+ if (!m_get_class_info_code.get())
+ {
+ m_get_class_info_code.reset (new ClangUtilityFunction (g_get_dynamic_class_info_body,
+ g_get_dynamic_class_info_name));
+
+ errors.Clear();
+
+ if (!m_get_class_info_code->Install(errors, exe_ctx))
+ {
+ if (log)
+ log->Printf ("Failed to install implementation lookup: %s.", errors.GetData());
+ m_get_class_info_code.reset();
+ }
+ }
+
+ if (m_get_class_info_code.get())
+ function_address.SetOffset(m_get_class_info_code->StartAddress());
+ else
+ return false;
+
+ ValueList arguments;
+
+ // Next make the runner function for our implementation utility function.
+ if (!m_get_class_info_function.get())
+ {
+ Value value;
+ value.SetValueType (Value::eValueTypeScalar);
+ value.SetContext (Value::eContextTypeClangType, clang_void_pointer_type);
+ arguments.PushValue (value);
+
+ value.SetValueType (Value::eValueTypeScalar);
+ value.SetContext (Value::eContextTypeClangType, clang_void_pointer_type);
+ arguments.PushValue (value);
+
+ value.SetValueType (Value::eValueTypeScalar);
+ value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type);
+ arguments.PushValue (value);
+
+ m_get_class_info_function.reset(new ClangFunction (*m_process,
+ ast,
+ clang_uint32_t_type,
+ function_address,
+ arguments));
+
+ if (m_get_class_info_function.get() == NULL)
+ return false;
+
+ errors.Clear();
+
+ unsigned num_errors = m_get_class_info_function->CompileFunction(errors);
+ if (num_errors)
+ {
+ if (log)
+ log->Printf ("Error compiling function: \"%s\".", errors.GetData());
+ return false;
+ }
+
+ errors.Clear();
+
+ if (!m_get_class_info_function->WriteFunctionWrapper(exe_ctx, errors))
+ {
+ if (log)
+ log->Printf ("Error Inserting function: \"%s\".", errors.GetData());
+ return false;
+ }
+ }
+ else
+ {
+ arguments = m_get_class_info_function->GetArgumentValues ();
+ }
+
+ const uint32_t class_info_byte_size = 32 + 2 * addr_size;
+ const uint32_t class_infos_byte_size = num_classes * class_info_byte_size;
+ lldb::addr_t class_infos_addr = process->AllocateMemory(class_infos_byte_size,
+ ePermissionsReadable | ePermissionsWritable,
+ err);
+
+ if (class_infos_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ Mutex::Locker locker(m_get_class_info_args_mutex);
+
+ // Fill in our function argument values
+ arguments.GetValueAtIndex(0)->GetScalar() = hash_table.GetTableLoadAddress();
+ arguments.GetValueAtIndex(1)->GetScalar() = class_infos_addr;
+ arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size;
+
+ bool success = false;
+
+ errors.Clear();
+
+ // Write our function arguments into the process so we can run our function
+ if (m_get_class_info_function->WriteFunctionArguments (exe_ctx,
+ m_get_class_info_args,
+ function_address,
+ arguments,
+ errors))
+ {
+ bool stop_others = true;
+ bool try_all_threads = false;
+ bool unwind_on_error = true;
+ bool ignore_breakpoints = true;
+
+ Value return_value;
+ return_value.SetValueType (Value::eValueTypeScalar);
+ return_value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type);
+ return_value.GetScalar() = 0;
+
+ errors.Clear();
+
+ // Run the function
+ ExecutionResults results = m_get_class_info_function->ExecuteFunction (exe_ctx,
+ &m_get_class_info_args,
+ errors,
+ stop_others,
+ UTILITY_FUNCTION_TIMEOUT_USEC,
+ try_all_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ return_value);
+
+ if (results == eExecutionCompleted)
+ {
+ // The result is the number of ClassInfo structures that were filled in
+ uint32_t num_class_infos = return_value.GetScalar().ULong();
+ if (num_class_infos > 0)
+ {
+ // Read the ClassInfo structures
+ DataBufferHeap buffer (num_class_infos * class_info_byte_size, 0);
+ if (process->ReadMemory(class_infos_addr, buffer.GetBytes(), buffer.GetByteSize(), err) == buffer.GetByteSize())
+ {
+ std::string class_name_str;
+ lldb::offset_t offset = 0;
+ DataExtractor class_infos_data (buffer.GetBytes(), buffer.GetByteSize(), process->GetByteOrder(), addr_size);
+
+ // Iterate through all ClassInfo structures
+ for (uint32_t i=0; i<num_class_infos; ++i)
+ {
+ ObjCISA isa = class_infos_data.GetPointer(&offset);
+
+ if (isa == 0)
+ {
+ if (log)
+ log->Printf("AppleObjCRuntimeV2 found NULL isa, ignoring this class info");
+ continue;
+ }
+ // Check if we already know about this ISA, if we do, the info will
+ // never change, so we can just skip it.
+ if (ISAIsCached(isa))
+ {
+ // This ISA is already in our map, skip the name_ptr and name string
+ // and continue
+ offset += addr_size + 32;
+ }
+ else
+ {
+ // Read the name_ptr. "name_ptr" will be NULL if the C string was able to
+ // fit in the 32 character buffer in the ClassInfo structure that is read below
+ addr_t name_ptr = class_infos_data.GetPointer(&offset);
+ // Read the class name from the 32 character array.
+ const char *class_name = class_infos_data.PeekCStr(offset);
+ offset += 32;
+ if (name_ptr)
+ {
+ // The name was longer that 32 characers, we need to read the class name
+ // from memory ourselves.
+ if (process->ReadCStringFromMemory(name_ptr, class_name_str, err) == 0)
+ class_name_str.clear();
+ class_name = class_name_str.c_str();
+ }
+
+ if (class_name && class_name[0])
+ {
+ //ClassDescriptorSP descriptor_sp (new ClassDescriptorV2(*this, isa, class_name));
+ ClassDescriptorSP descriptor_sp (new ClassDescriptorV2(*this, isa, class_name));
+ AddClass (isa, descriptor_sp, class_name);
+
+ if (log && log->GetVerbose())
+ log->Printf("AppleObjCRuntimeV2 added (ObjCISA)0x%" PRIx64 " (%s) from dynamic table to isa->descriptor cache", isa, class_name);
+ }
+ else
+ {
+ if (log)
+ log->Printf("AppleObjCRuntimeV2 failed to read class name for (ObjCISA)0x%" PRIx64, isa);
+ }
+ }
+ }
+ }
}
-
- // Write the final arguments.
-
- dispatch_values.Clear();
-
- isas_value.GetScalar() = m_isas_allocation;
- names_value.GetScalar() = m_names_allocation;
- num_isas_assumed_value.GetScalar() = num_isas;
- name_size_value.GetScalar() = name_size;
-
- dispatch_values.PushValue (isas_value);
- dispatch_values.PushValue (names_value);
- dispatch_values.PushValue (num_isas_assumed_value);
- dispatch_values.PushValue (name_size_value);
-
- {
- errors.Clear();
-
- if (!m_summarize_classes_function->WriteFunctionArguments (exe_ctx, m_summarize_classes_args, summarize_classes_address, dispatch_values, errors))
+ success = true;
+ }
+ else
+ {
+ if (log)
+ log->Printf("Error evaluating our find class name function: %s.\n", errors.GetData());
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("Error writing function arguments: \"%s\".", errors.GetData());
+ }
+
+ // Deallocate the memory we allocated for the ClassInfo array
+ process->DeallocateMemory(class_infos_addr);
+
+ return success;
+}
+
+
+bool
+AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic2(RemoteNXMapTable &hash_table)
+{
+ Process *process = GetProcess();
+
+ if (process == NULL)
+ return false;
+
+ lldb::LogSP log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ ExecutionContext exe_ctx;
+
+ ThreadSP thread_sp = process->GetThreadList().GetSelectedThread();
+
+ if (!thread_sp)
+ return false;
+
+ thread_sp->CalculateExecutionContext(exe_ctx);
+ ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext();
+
+ if (!ast)
+ return false;
+
+ Address function_address;
+
+ StreamString errors;
+
+ const uint32_t addr_size = process->GetAddressByteSize();
+
+ Error err;
+
+ // Read the total number of classes from the hash table
+ const uint32_t num_classes = hash_table.GetCount();
+ if (num_classes == 0)
+ {
+ if (log)
+ log->Printf ("No dynamic classes found in gdb_objc_realized_classes.");
+ return false;
+ }
+
+ // Make some types for our arguments
+ clang_type_t clang_uint32_t_type = ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
+ clang_type_t clang_void_pointer_type = ast->CreatePointerType(ast->GetBuiltInType_void());
+
+ if (!m_get_class_info_code.get())
+ {
+ m_get_class_info_code.reset (new ClangUtilityFunction (g_get_dynamic_class_info2_body,
+ g_get_dynamic_class_info2_name));
+
+ errors.Clear();
+
+ if (!m_get_class_info_code->Install(errors, exe_ctx))
+ {
+ if (log)
+ log->Printf ("Failed to install implementation lookup: %s.", errors.GetData());
+ m_get_class_info_code.reset();
+ }
+ }
+
+ if (m_get_class_info_code.get())
+ function_address.SetOffset(m_get_class_info_code->StartAddress());
+ else
+ return false;
+
+ ValueList arguments;
+
+ // Next make the runner function for our implementation utility function.
+ if (!m_get_class_info_function.get())
+ {
+ Value value;
+ value.SetValueType (Value::eValueTypeScalar);
+ value.SetContext (Value::eContextTypeClangType, clang_void_pointer_type);
+ arguments.PushValue (value);
+
+ value.SetValueType (Value::eValueTypeScalar);
+ value.SetContext (Value::eContextTypeClangType, clang_void_pointer_type);
+ arguments.PushValue (value);
+
+ value.SetValueType (Value::eValueTypeScalar);
+ value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type);
+ arguments.PushValue (value);
+
+ m_get_class_info_function.reset(new ClangFunction (*m_process,
+ ast,
+ clang_uint32_t_type,
+ function_address,
+ arguments));
+
+ if (m_get_class_info_function.get() == NULL)
+ return false;
+
+ errors.Clear();
+
+ unsigned num_errors = m_get_class_info_function->CompileFunction(errors);
+ if (num_errors)
+ {
+ if (log)
+ log->Printf ("Error compiling function: \"%s\".", errors.GetData());
+ return false;
+ }
+
+ errors.Clear();
+
+ if (!m_get_class_info_function->WriteFunctionWrapper(exe_ctx, errors))
+ {
+ if (log)
+ log->Printf ("Error Inserting function: \"%s\".", errors.GetData());
+ return false;
+ }
+ }
+ else
+ {
+ arguments = m_get_class_info_function->GetArgumentValues ();
+ }
+
+ const uint32_t class_info_byte_size = addr_size + 4;
+ const uint32_t class_infos_byte_size = num_classes * class_info_byte_size;
+ lldb::addr_t class_infos_addr = process->AllocateMemory(class_infos_byte_size,
+ ePermissionsReadable | ePermissionsWritable,
+ err);
+
+ if (class_infos_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ Mutex::Locker locker(m_get_class_info_args_mutex);
+
+ // Fill in our function argument values
+ arguments.GetValueAtIndex(0)->GetScalar() = hash_table.GetTableLoadAddress();
+ arguments.GetValueAtIndex(1)->GetScalar() = class_infos_addr;
+ arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size;
+
+ bool success = false;
+
+ errors.Clear();
+
+ // Write our function arguments into the process so we can run our function
+ if (m_get_class_info_function->WriteFunctionArguments (exe_ctx,
+ m_get_class_info_args,
+ function_address,
+ arguments,
+ errors))
+ {
+ bool stop_others = true;
+ bool try_all_threads = false;
+ bool unwind_on_error = true;
+ bool ignore_breakpoints = true;
+
+ Value return_value;
+ return_value.SetValueType (Value::eValueTypeScalar);
+ return_value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type);
+ return_value.GetScalar() = 0;
+
+ errors.Clear();
+
+ // Run the function
+ ExecutionResults results = m_get_class_info_function->ExecuteFunction (exe_ctx,
+ &m_get_class_info_args,
+ errors,
+ stop_others,
+ UTILITY_FUNCTION_TIMEOUT_USEC,
+ try_all_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ return_value);
+
+ if (results == eExecutionCompleted)
+ {
+ // The result is the number of ClassInfo structures that were filled in
+ uint32_t num_class_infos = return_value.GetScalar().ULong();
+ if (num_class_infos > 0)
+ {
+ // Read the ClassInfo structures
+ DataBufferHeap buffer (num_class_infos * class_info_byte_size, 0);
+ if (process->ReadMemory(class_infos_addr, buffer.GetBytes(), buffer.GetByteSize(), err) == buffer.GetByteSize())
+ {
+ DataExtractor class_infos_data (buffer.GetBytes(),
+ buffer.GetByteSize(),
+ process->GetByteOrder(),
+ addr_size);
+ ParseISAHashArray (class_infos_data, num_class_infos);
+ }
+ }
+ success = true;
+ }
+ else
+ {
+ if (log)
+ log->Printf("Error evaluating our find class name function: %s.\n", errors.GetData());
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("Error writing function arguments: \"%s\".", errors.GetData());
+ }
+
+ // Deallocate the memory we allocated for the ClassInfo array
+ process->DeallocateMemory(class_infos_addr);
+
+ return success;
+}
+
+
+bool
+AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache()
+{
+ Process *process = GetProcess();
+
+ if (process == NULL)
+ return false;
+
+ lldb::LogSP log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ ExecutionContext exe_ctx;
+
+ ThreadSP thread_sp = process->GetThreadList().GetSelectedThread();
+
+ if (!thread_sp)
+ return false;
+
+ thread_sp->CalculateExecutionContext(exe_ctx);
+ ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext();
+
+ if (!ast)
+ return false;
+
+ Address function_address;
+
+ StreamString errors;
+
+ const uint32_t addr_size = process->GetAddressByteSize();
+
+ Error err;
+
+ const lldb::addr_t objc_opt_ptr = GetSharedCacheReadOnlyAddress();
+
+ if (objc_opt_ptr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ // Read the total number of classes from the hash table
+ const uint32_t num_classes = 16*1024;
+ if (num_classes == 0)
+ {
+ if (log)
+ log->Printf ("No dynamic classes found in gdb_objc_realized_classes_addr.");
+ return false;
+ }
+
+ // Make some types for our arguments
+ clang_type_t clang_uint32_t_type = ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
+ clang_type_t clang_void_pointer_type = ast->CreatePointerType(ast->GetBuiltInType_void());
+
+ if (!m_get_shared_cache_class_info_code.get())
+ {
+ m_get_shared_cache_class_info_code.reset (new ClangUtilityFunction (g_get_shared_cache_class_info_body,
+ g_get_shared_cache_class_info_name));
+
+ errors.Clear();
+
+ if (!m_get_shared_cache_class_info_code->Install(errors, exe_ctx))
+ {
+ if (log)
+ log->Printf ("Failed to install implementation lookup: %s.", errors.GetData());
+ m_get_shared_cache_class_info_code.reset();
+ }
+ }
+
+ if (m_get_shared_cache_class_info_code.get())
+ function_address.SetOffset(m_get_shared_cache_class_info_code->StartAddress());
+ else
+ return false;
+
+ ValueList arguments;
+
+ // Next make the runner function for our implementation utility function.
+ if (!m_get_shared_cache_class_info_function.get())
+ {
+ Value value;
+ value.SetValueType (Value::eValueTypeScalar);
+ value.SetContext (Value::eContextTypeClangType, clang_void_pointer_type);
+ arguments.PushValue (value);
+
+ value.SetValueType (Value::eValueTypeScalar);
+ value.SetContext (Value::eContextTypeClangType, clang_void_pointer_type);
+ arguments.PushValue (value);
+
+ value.SetValueType (Value::eValueTypeScalar);
+ value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type);
+ arguments.PushValue (value);
+
+ m_get_shared_cache_class_info_function.reset(new ClangFunction (*m_process,
+ ast,
+ clang_uint32_t_type,
+ function_address,
+ arguments));
+
+ if (m_get_shared_cache_class_info_function.get() == NULL)
+ return false;
+
+ errors.Clear();
+
+ unsigned num_errors = m_get_shared_cache_class_info_function->CompileFunction(errors);
+ if (num_errors)
+ {
+ if (log)
+ log->Printf ("Error compiling function: \"%s\".", errors.GetData());
+ return false;
+ }
+
+ errors.Clear();
+
+ if (!m_get_shared_cache_class_info_function->WriteFunctionWrapper(exe_ctx, errors))
+ {
+ if (log)
+ log->Printf ("Error Inserting function: \"%s\".", errors.GetData());
+ return false;
+ }
+ }
+ else
+ {
+ arguments = m_get_shared_cache_class_info_function->GetArgumentValues ();
+ }
+
+ const uint32_t class_info_byte_size = 32 + 2 * addr_size;
+ const uint32_t class_infos_byte_size = num_classes * class_info_byte_size;
+ lldb::addr_t class_infos_addr = process->AllocateMemory (class_infos_byte_size,
+ ePermissionsReadable | ePermissionsWritable,
+ err);
+
+ if (class_infos_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ Mutex::Locker locker(m_get_shared_cache_class_info_args_mutex);
+
+ // Fill in our function argument values
+ arguments.GetValueAtIndex(0)->GetScalar() = objc_opt_ptr;
+ arguments.GetValueAtIndex(1)->GetScalar() = class_infos_addr;
+ arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size;
+
+ bool success = false;
+
+ errors.Clear();
+
+ // Write our function arguments into the process so we can run our function
+ if (m_get_shared_cache_class_info_function->WriteFunctionArguments (exe_ctx,
+ m_get_shared_cache_class_info_args,
+ function_address,
+ arguments,
+ errors))
+ {
+ bool stop_others = true;
+ bool try_all_threads = false;
+ bool unwind_on_error = true;
+ bool ignore_breakpoints = true;
+
+ Value return_value;
+ return_value.SetValueType (Value::eValueTypeScalar);
+ return_value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type);
+ return_value.GetScalar() = 0;
+
+ errors.Clear();
+
+ // Run the function
+ ExecutionResults results = m_get_shared_cache_class_info_function->ExecuteFunction (exe_ctx,
+ &m_get_shared_cache_class_info_args,
+ errors,
+ stop_others,
+ UTILITY_FUNCTION_TIMEOUT_USEC,
+ try_all_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ return_value);
+
+ if (results == eExecutionCompleted)
+ {
+ // The result is the number of ClassInfo structures that were filled in
+ uint32_t num_class_infos = return_value.GetScalar().ULong();
+ if (num_class_infos > 0)
+ {
+ // Read the ClassInfo structures
+ DataBufferHeap buffer (num_class_infos * class_info_byte_size, 0);
+ if (process->ReadMemory(class_infos_addr, buffer.GetBytes(), buffer.GetByteSize(), err) == buffer.GetByteSize())
{
- if (log)
- log->Printf ("Error writing function arguments: \"%s\".", errors.GetData());
- break;
+ std::string class_name_str;
+ lldb::offset_t offset = 0;
+ DataExtractor class_infos_data (buffer.GetBytes(), buffer.GetByteSize(), process->GetByteOrder(), addr_size);
+ // Iterate through all ClassInfo structures
+ for (uint32_t i=0; i<num_class_infos; ++i)
+ {
+ ObjCISA isa = class_infos_data.GetPointer(&offset);
+
+ if (isa == 0)
+ {
+ if (log)
+ log->Printf("AppleObjCRuntimeV2 found NULL isa, ignoring this class info");
+ continue;
+ }
+ // Check if we already know about this ISA, if we do, the info will
+ // never change, so we can just skip it.
+ if (ISAIsCached(isa))
+ {
+ // This ISA is already in our map, skip the name_ptr and name string
+ // and continue
+ offset += addr_size + 32;
+ }
+ else
+ {
+ // Read the name_ptr. "name_ptr" will be NULL if the C string was able to
+ // fit in the 32 character buffer in the ClassInfo structure that is read below
+ addr_t name_ptr = class_infos_data.GetPointer(&offset);
+ // Read the class name from the 32 character array.
+ const char *class_name = class_infos_data.PeekCStr(offset);
+ offset += 32;
+ if (name_ptr)
+ {
+ // The name was longer that 32 characers, we need to read the class name
+ // from memory ourselves.
+ if (process->ReadCStringFromMemory(name_ptr, class_name_str, err) == 0)
+ class_name_str.clear();
+ class_name = class_name_str.c_str();
+ }
+
+ if (class_name && class_name[0])
+ {
+ ClassDescriptorSP descriptor_sp (new ClassDescriptorV2(*this, isa, class_name));
+ AddClass (isa, descriptor_sp, class_name);
+
+ if (log && log->GetVerbose())
+ log->Printf("AppleObjCRuntimeV2 added (ObjCISA)0x%" PRIx64 " (%s) from shared cache table to isa->descriptor cache", isa, class_name);
+ }
+ else
+ {
+ if (log)
+ log->Printf("AppleObjCRuntimeV2 failed to read class name for (ObjCISA)0x%" PRIx64, isa);
+ }
+ }
+ }
}
}
-
- errors.Clear();
-
- results = m_summarize_classes_function->ExecuteFunction (exe_ctx,
- &m_summarize_classes_args,
- errors,
- stop_others,
- 100000,
- try_all_threads,
- unwind_on_error,
- ignore_breakpoints,
- num_isas_value);
-
- if (results != eExecutionCompleted)
- {
- if (log)
- log->Printf("Error evaluating our find class name function: %s.\n", errors.GetData());
- break;
+ success = true;
+ }
+ else
+ {
+ if (log)
+ log->Printf("Error evaluating our find class name function: %s.\n", errors.GetData());
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("Error writing function arguments: \"%s\".", errors.GetData());
+ }
+
+ // Deallocate the memory we allocated for the ClassInfo array
+ process->DeallocateMemory(class_infos_addr);
+
+ return success;
+}
+
+void
+AppleObjCRuntimeV2::ParseISAHashArray (const DataExtractor &data, uint32_t num_class_infos)
+{
+ lldb::LogSP log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // Iterate through all ClassInfo structures
+ lldb::offset_t offset = 0;
+ for (uint32_t i=0; i<num_class_infos; ++i)
+ {
+ ObjCISA isa = data.GetPointer(&offset);
+
+ if (isa == 0)
+ {
+ if (log)
+ log->Printf("AppleObjCRuntimeV2 found NULL isa, ignoring this class info");
+ continue;
+ }
+ // Check if we already know about this ISA, if we do, the info will
+ // never change, so we can just skip it.
+ if (ISAIsCached(isa))
+ {
+ offset += 4;
+ }
+ else
+ {
+ // Read the 32 bit hash for the class name
+ const uint32_t name_hash = data.GetU32(&offset);
+ ClassDescriptorSP descriptor_sp (new ClassDescriptorV2(*this, isa, NULL));
+ AddClass (isa, descriptor_sp, name_hash);
+ if (log && log->GetVerbose())
+ log->Printf("AppleObjCRuntimeV2 added isa=0x%" PRIx64 ", hash=0x%8.8x", isa, name_hash);
+ }
+ }
+}
+
+bool
+AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache2()
+{
+ Process *process = GetProcess();
+
+ if (process == NULL)
+ return false;
+
+ lldb::LogSP log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ ExecutionContext exe_ctx;
+
+ ThreadSP thread_sp = process->GetThreadList().GetSelectedThread();
+
+ if (!thread_sp)
+ return false;
+
+ thread_sp->CalculateExecutionContext(exe_ctx);
+ ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext();
+
+ if (!ast)
+ return false;
+
+ Address function_address;
+
+ StreamString errors;
+
+ const uint32_t addr_size = process->GetAddressByteSize();
+
+ Error err;
+
+ const lldb::addr_t objc_opt_ptr = GetSharedCacheReadOnlyAddress();
+
+ if (objc_opt_ptr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ // Read the total number of classes from the hash table
+ const uint32_t num_classes = 16*1024;
+ if (num_classes == 0)
+ {
+ if (log)
+ log->Printf ("No dynamic classes found in gdb_objc_realized_classes_addr.");
+ return false;
+ }
+
+ // Make some types for our arguments
+ clang_type_t clang_uint32_t_type = ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
+ clang_type_t clang_void_pointer_type = ast->CreatePointerType(ast->GetBuiltInType_void());
+
+ if (!m_get_shared_cache_class_info_code.get())
+ {
+ m_get_shared_cache_class_info_code.reset (new ClangUtilityFunction (g_get_shared_cache_class_info2_body,
+ g_get_shared_cache_class_info2_name));
+
+ errors.Clear();
+
+ if (!m_get_shared_cache_class_info_code->Install(errors, exe_ctx))
+ {
+ if (log)
+ log->Printf ("Failed to install implementation lookup: %s.", errors.GetData());
+ m_get_shared_cache_class_info_code.reset();
+ }
+ }
+
+ if (m_get_shared_cache_class_info_code.get())
+ function_address.SetOffset(m_get_shared_cache_class_info_code->StartAddress());
+ else
+ return false;
+
+ ValueList arguments;
+
+ // Next make the runner function for our implementation utility function.
+ if (!m_get_shared_cache_class_info_function.get())
+ {
+ Value value;
+ value.SetValueType (Value::eValueTypeScalar);
+ value.SetContext (Value::eContextTypeClangType, clang_void_pointer_type);
+ arguments.PushValue (value);
+
+ value.SetValueType (Value::eValueTypeScalar);
+ value.SetContext (Value::eContextTypeClangType, clang_void_pointer_type);
+ arguments.PushValue (value);
+
+ value.SetValueType (Value::eValueTypeScalar);
+ value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type);
+ arguments.PushValue (value);
+
+ m_get_shared_cache_class_info_function.reset(new ClangFunction (*m_process,
+ ast,
+ clang_uint32_t_type,
+ function_address,
+ arguments));
+
+ if (m_get_shared_cache_class_info_function.get() == NULL)
+ return false;
+
+ errors.Clear();
+
+ unsigned num_errors = m_get_shared_cache_class_info_function->CompileFunction(errors);
+ if (num_errors)
+ {
+ if (log)
+ log->Printf ("Error compiling function: \"%s\".", errors.GetData());
+ return false;
+ }
+
+ errors.Clear();
+
+ if (!m_get_shared_cache_class_info_function->WriteFunctionWrapper(exe_ctx, errors))
+ {
+ if (log)
+ log->Printf ("Error Inserting function: \"%s\".", errors.GetData());
+ return false;
+ }
+ }
+ else
+ {
+ arguments = m_get_shared_cache_class_info_function->GetArgumentValues ();
+ }
+
+ const uint32_t class_info_byte_size = addr_size + 4;
+ const uint32_t class_infos_byte_size = num_classes * class_info_byte_size;
+ lldb::addr_t class_infos_addr = process->AllocateMemory (class_infos_byte_size,
+ ePermissionsReadable | ePermissionsWritable,
+ err);
+
+ if (class_infos_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ Mutex::Locker locker(m_get_shared_cache_class_info_args_mutex);
+
+ // Fill in our function argument values
+ arguments.GetValueAtIndex(0)->GetScalar() = objc_opt_ptr;
+ arguments.GetValueAtIndex(1)->GetScalar() = class_infos_addr;
+ arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size;
+
+ bool success = false;
+
+ errors.Clear();
+
+ // Write our function arguments into the process so we can run our function
+ if (m_get_shared_cache_class_info_function->WriteFunctionArguments (exe_ctx,
+ m_get_shared_cache_class_info_args,
+ function_address,
+ arguments,
+ errors))
+ {
+ bool stop_others = true;
+ bool try_all_threads = false;
+ bool unwind_on_error = true;
+ bool ignore_breakpoints = true;
+
+ Value return_value;
+ return_value.SetValueType (Value::eValueTypeScalar);
+ return_value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type);
+ return_value.GetScalar() = 0;
+
+ errors.Clear();
+
+ // Run the function
+ ExecutionResults results = m_get_shared_cache_class_info_function->ExecuteFunction (exe_ctx,
+ &m_get_shared_cache_class_info_args,
+ errors,
+ stop_others,
+ UTILITY_FUNCTION_TIMEOUT_USEC,
+ try_all_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ return_value);
+
+ if (results == eExecutionCompleted)
+ {
+ // The result is the number of ClassInfo structures that were filled in
+ uint32_t num_class_infos = return_value.GetScalar().ULong();
+ if (num_class_infos > 0)
+ {
+ // Read the ClassInfo structures
+ DataBufferHeap buffer (num_class_infos * class_info_byte_size, 0);
+ if (process->ReadMemory(class_infos_addr,
+ buffer.GetBytes(),
+ buffer.GetByteSize(),
+ err) == buffer.GetByteSize())
+ {
+ DataExtractor class_infos_data (buffer.GetBytes(),
+ buffer.GetByteSize(),
+ process->GetByteOrder(),
+ addr_size);
+
+ ParseISAHashArray (class_infos_data, num_class_infos);
+ }
}
+ success = true;
+ }
+ else
+ {
+ if (log)
+ log->Printf("Error evaluating our find class name function: %s.\n", errors.GetData());
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("Error writing function arguments: \"%s\".", errors.GetData());
+ }
+
+ // Deallocate the memory we allocated for the ClassInfo array
+ process->DeallocateMemory(class_infos_addr);
+
+ return success;
+}
+
+
+bool
+AppleObjCRuntimeV2::UpdateISAToDescriptorMapFromMemory (RemoteNXMapTable &hash_table)
+{
+ lldb::LogSP log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ Process *process = GetProcess();
+
+ if (process == NULL)
+ return false;
+
+ uint32_t num_map_table_isas = 0;
+
+ ModuleSP objc_module_sp(GetObjCModule());
+
+ if (objc_module_sp)
+ {
+ for (RemoteNXMapTable::element elt : hash_table)
+ {
+ ++num_map_table_isas;
- DataBufferHeap isas_buffer(isas_allocation_size, 0);
- DataBufferHeap names_buffer(names_allocation_size, 0);
-
- if (process->ReadMemory(m_isas_allocation, isas_buffer.GetBytes(), isas_allocation_size, err) != isas_allocation_size)
- break;
-
- if (process->ReadMemory(m_names_allocation, names_buffer.GetBytes(), names_allocation_size, err) != names_allocation_size)
- break;
-
- DataExtractor isa_extractor(isas_buffer.GetBytes(), isas_allocation_size, process->GetByteOrder(), process->GetAddressByteSize());
+ if (ISAIsCached(elt.second))
+ continue;
- lldb::offset_t offset = 0;
+ ClassDescriptorSP descriptor_sp = ClassDescriptorSP(new ClassDescriptorV2(*this, elt.second, elt.first.AsCString()));
- for (size_t index = 0; index < num_isas; ++index)
- {
- uint64_t isa = isa_extractor.GetPointer(&offset);
-
- const char *name = (const char*)(names_buffer.GetBytes() + (name_size * index));
-
- if (log && log->GetVerbose())
- log->Printf("Fast class summary mode found isa 0x%llx (%s)", isa, name);
-
- // The name can only be relied upon if it is NULL-terminated.
- // Otherwise it ran off its allocation and has been partially overwritten by the next name.
-
- ClassDescriptorSP descriptor_sp;
-
- if (name[name_size - 1] == '\0')
- descriptor_sp.reset(new ClassDescriptorV2(*this, isa, name));
- else
- descriptor_sp.reset(new ClassDescriptorV2(*this, isa, NULL));
-
- m_isa_to_descriptor_cache[isa] = descriptor_sp;
- }
+ if (log && log->GetVerbose())
+ log->Printf("AppleObjCRuntimeV2 added (ObjCISA)0x%" PRIx64 " (%s) from dynamic table to isa->descriptor cache", elt.second, elt.first.AsCString());
- return;
- } while(0);
+ AddClass (elt.second, descriptor_sp, elt.first.AsCString());
+ }
+ }
+
+ return num_map_table_isas > 0;
+}
+
+lldb::addr_t
+AppleObjCRuntimeV2::GetSharedCacheReadOnlyAddress()
+{
+ Process *process = GetProcess();
+
+ if (process)
+ {
+ ModuleSP objc_module_sp(GetObjCModule());
- do
+ if (objc_module_sp)
{
- lldb::LogSP log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
-
- uint32_t num_map_table_isas = 0;
- uint32_t num_objc_opt_ro_isas = 0;
-
- ModuleSP objc_module_sp(GetObjCModule());
+ ObjectFile *objc_object = objc_module_sp->GetObjectFile();
- if (objc_module_sp)
+ if (objc_object)
{
- for (RemoteNXMapTable::element elt : hash_table)
- {
- ++num_map_table_isas;
-
- if (m_isa_to_descriptor_cache.count(elt.second))
- continue;
-
- ClassDescriptorSP descriptor_sp = ClassDescriptorSP(new ClassDescriptorV2(*this, elt.second, elt.first.AsCString()));
-
- if (log && log->GetVerbose())
- log->Printf("AppleObjCRuntimeV2 added (ObjCISA)0x%" PRIx64 " (%s) from dynamic table to isa->descriptor cache", elt.second, elt.first.AsCString());
-
- m_isa_to_descriptor_cache[elt.second] = descriptor_sp;
- }
+ SectionList *section_list = objc_object->GetSectionList();
- if (!m_loaded_objc_opt)
+ if (section_list)
{
- m_loaded_objc_opt = true;
-
- ObjectFile *objc_object = objc_module_sp->GetObjectFile();
+ SectionSP text_segment_sp (section_list->FindSectionByName(ConstString("__TEXT")));
- if (objc_object)
+ if (text_segment_sp)
{
- SectionList *section_list = objc_object->GetSectionList();
+ SectionSP objc_opt_section_sp (text_segment_sp->GetChildren().FindSectionByName(ConstString("__objc_opt_ro")));
- if (section_list)
+ if (objc_opt_section_sp)
{
- SectionSP text_segment_sp (section_list->FindSectionByName(ConstString("__TEXT")));
-
- if (text_segment_sp)
- {
- SectionSP objc_opt_section_sp (text_segment_sp->GetChildren().FindSectionByName(ConstString("__objc_opt_ro")));
-
- if (objc_opt_section_sp)
- {
- lldb::addr_t objc_opt_ptr = objc_opt_section_sp->GetLoadBaseAddress(&process->GetTarget());
-
- if (objc_opt_ptr != LLDB_INVALID_ADDRESS)
- {
- RemoteObjCOpt objc_opt(process, objc_opt_ptr);
-
- for (ObjCLanguageRuntime::ObjCISA objc_isa : objc_opt)
- {
- ++num_objc_opt_ro_isas;
- if (m_isa_to_descriptor_cache.count(objc_isa))
- continue;
-
- ClassDescriptorSP descriptor_sp = ClassDescriptorSP(new ClassDescriptorV2(*this, objc_isa, NULL));
-
- if (log && log->GetVerbose())
- log->Printf("AppleObjCRuntimeV2 added (ObjCISA)0x%" PRIx64 " (%s) from static table to isa->descriptor cache", objc_isa, descriptor_sp->GetClassName().AsCString());
-
- m_isa_to_descriptor_cache[objc_isa] = descriptor_sp;
- }
- }
- }
- }
+ return objc_opt_section_sp->GetLoadBaseAddress(&process->GetTarget());
}
}
}
}
- } while (0);
+ }
+ }
+ return LLDB_INVALID_ADDRESS;
+}
+bool
+AppleObjCRuntimeV2::UpdateISAToDescriptorMapFromDYLDSharedCache ()
+{
+ if (m_loaded_objc_opt)
+ return true;
+
+ lldb::LogSP log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ uint32_t num_objc_opt_ro_isas = 0;
+ const lldb::addr_t objc_opt_ptr = GetSharedCacheReadOnlyAddress();
+
+ if (objc_opt_ptr != LLDB_INVALID_ADDRESS)
+ {
+ RemoteObjCOpt objc_opt(GetProcess(), objc_opt_ptr);
+
+ for (ObjCLanguageRuntime::ObjCISA isa : objc_opt)
+ {
+ ++num_objc_opt_ro_isas;
+ if (ISAIsCached(isa))
+ continue;
+
+ ClassDescriptorSP descriptor_sp(new ClassDescriptorV2(*this, isa, NULL));
+ if (log && log->GetVerbose())
+ log->Printf("AppleObjCRuntimeV2 added (ObjCISA)0x%" PRIx64 " (%s) from static table to isa->descriptor cache", isa, descriptor_sp->GetClassName().AsCString());
+
+ AddClass (isa, descriptor_sp);
+ }
+ }
+ return num_objc_opt_ro_isas > 0;
+}
+
+void
+AppleObjCRuntimeV2::UpdateISAToDescriptorMapIfNeeded()
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+
+ // Else we need to check with our process to see when the map was updated.
+ Process *process = GetProcess();
+
+ if (process)
+ {
+ RemoteNXMapTable hash_table;
+
+ // Update the process stop ID that indicates the last time we updated the
+ // map, wether it was successful or not.
+ m_isa_to_descriptor_stop_id = process->GetStopID();
+
+ if (!m_hash_signature.NeedsUpdate(process, this, hash_table))
+ return;
+
+ m_hash_signature.UpdateSignature (hash_table);
+
+ // Grab the dynamicly loaded objc classes from the hash table in memory
+ UpdateISAToDescriptorMapDynamic2(hash_table);
+
+ // Now get the objc classes that are baked into the Objective C runtime
+ // in the shared cache.
+ if (!m_loaded_objc_opt)
+ UpdateISAToDescriptorMapSharedCache2();
}
else
{
- m_isa_to_descriptor_cache_stop_id = UINT32_MAX;
+ m_isa_to_descriptor_stop_id = UINT32_MAX;
}
}
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=175101&r1=175100&r2=175101&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h Wed Feb 13 16:56:14 2013
@@ -135,7 +135,36 @@ private:
lldb::addr_t
GetISAHashTablePointer ();
- bool RunFunctionToFindClassName (lldb::addr_t class_addr, Thread *thread, char *name_dst, size_t max_name_len);
+ bool
+ UpdateISAToDescriptorMapFromMemory (RemoteNXMapTable &hash_table);
+
+ bool
+ UpdateISAToDescriptorMapFromDYLDSharedCache ();
+
+ bool
+ UpdateISAToDescriptorMapUsingUtilityFunction_objc_getClassList();
+
+ bool
+ UpdateISAToDescriptorMapDynamic(RemoteNXMapTable &hash_table);
+
+ bool
+ UpdateISAToDescriptorMapDynamic2(RemoteNXMapTable &hash_table);
+
+ void
+ ParseISAHashArray (const lldb_private::DataExtractor &data,
+ uint32_t num_class_infos);
+
+ bool
+ UpdateISAToDescriptorMapSharedCache ();
+
+ bool
+ UpdateISAToDescriptorMapSharedCache2 ();
+
+ lldb::addr_t
+ GetSharedCacheReadOnlyAddress();
+
+ bool
+ RunFunctionToFindClassName (lldb::addr_t class_addr, Thread *thread, char *name_dst, size_t max_name_len);
std::auto_ptr<ClangFunction> m_get_class_name_function;
std::auto_ptr<ClangUtilityFunction> m_get_class_name_code;
@@ -146,22 +175,28 @@ private:
std::auto_ptr<ClangFunction> m_summarize_classes_function;
std::auto_ptr<ClangUtilityFunction> m_summarize_classes_code;
+
lldb::addr_t m_isas_allocation;
lldb::addr_t m_names_allocation;
lldb::addr_t m_summarize_classes_args;
Mutex m_summarize_classes_args_mutex;
+ std::auto_ptr<ClangFunction> m_get_class_info_function;
+ std::auto_ptr<ClangUtilityFunction> m_get_class_info_code;
+ lldb::addr_t m_get_class_info_args;
+ Mutex m_get_class_info_args_mutex;
+
+ std::auto_ptr<ClangFunction> m_get_shared_cache_class_info_function;
+ std::auto_ptr<ClangUtilityFunction> m_get_shared_cache_class_info_code;
+ lldb::addr_t m_get_shared_cache_class_info_args;
+ Mutex m_get_shared_cache_class_info_args_mutex;
+
std::auto_ptr<TypeVendor> m_type_vendor_ap;
lldb::addr_t m_isa_hash_table_ptr;
HashTableSignature m_hash_signature;
bool m_has_object_getClass;
bool m_loaded_objc_opt;
- static const char *g_find_class_name_function_name;
- static const char *g_find_class_name_function_body;
-
- static const char *g_summarize_classes_function_name;
- static const char *g_summarize_classes_function_body;
};
} // namespace lldb_private
Modified: lldb/trunk/source/Target/ObjCLanguageRuntime.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/ObjCLanguageRuntime.cpp?rev=175101&r1=175100&r2=175101&view=diff
==============================================================================
--- lldb/trunk/source/Target/ObjCLanguageRuntime.cpp (original)
+++ lldb/trunk/source/Target/ObjCLanguageRuntime.cpp Wed Feb 13 16:56:14 2013
@@ -9,6 +9,7 @@
#include "clang/AST/Type.h"
#include "lldb/Core/Log.h"
+#include "lldb/Core/MappedHash.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Timer.h"
@@ -34,12 +35,25 @@ ObjCLanguageRuntime::~ObjCLanguageRuntim
ObjCLanguageRuntime::ObjCLanguageRuntime (Process *process) :
LanguageRuntime (process),
m_has_new_literals_and_indexing (eLazyBoolCalculate),
- m_isa_to_descriptor_cache(),
- m_isa_to_descriptor_cache_stop_id (UINT32_MAX)
+ m_isa_to_descriptor(),
+ m_isa_to_descriptor_stop_id (UINT32_MAX)
{
}
+bool
+ObjCLanguageRuntime::AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp, const char *class_name)
+{
+ if (isa != 0)
+ {
+ m_isa_to_descriptor[isa] = descriptor_sp;
+ // class_name is assumed to be valid
+ m_hash_to_isa_map.insert(std::make_pair(MappedHash::HashStringUsingDJB(class_name), isa));
+ return true;
+ }
+ return false;
+}
+
void
ObjCLanguageRuntime::AddToMethodCache (lldb::addr_t class_addr, lldb::addr_t selector, lldb::addr_t impl_addr)
{
@@ -431,13 +445,50 @@ ObjCLanguageRuntime::ClassDescriptor::Is
ObjCLanguageRuntime::ObjCISA
ObjCLanguageRuntime::GetISA(const ConstString &name)
{
- UpdateISAToDescriptorMap();
- for (const ISAToDescriptorMap::value_type &val : m_isa_to_descriptor_cache)
- if (val.second && val.second->GetClassName() == name)
- return val.first;
+ ISAToDescriptorIterator pos = GetDescriptorIterator (name);
+ if (pos != m_isa_to_descriptor.end())
+ return pos->first;
return 0;
}
+ObjCLanguageRuntime::ISAToDescriptorIterator
+ObjCLanguageRuntime::GetDescriptorIterator (const ConstString &name)
+{
+ ISAToDescriptorIterator end = m_isa_to_descriptor.end();
+
+ if (name)
+ {
+ UpdateISAToDescriptorMap();
+ if (m_hash_to_isa_map.empty())
+ {
+ // No name hashes were provided, we need to just linearly power through the
+ // names and find a match
+ for (ISAToDescriptorIterator pos = m_isa_to_descriptor.begin(); pos != end; ++pos)
+ {
+ if (pos->second->GetClassName() == name)
+ return pos;
+ }
+ }
+ else
+ {
+ // Name hashes were provided, so use them to efficiently lookup name to isa/descriptor
+ const uint32_t name_hash = MappedHash::HashStringUsingDJB (name.GetCString());
+ std::pair <HashToISAIterator, HashToISAIterator> range = m_hash_to_isa_map.equal_range(name_hash);
+ for (HashToISAIterator range_pos = range.first; range_pos != range.second; ++range_pos)
+ {
+ ISAToDescriptorIterator pos = m_isa_to_descriptor.find (range_pos->second);
+ if (pos != m_isa_to_descriptor.end())
+ {
+ if (pos->second->GetClassName() == name)
+ return pos;
+ }
+ }
+ }
+ }
+ return end;
+}
+
+
ObjCLanguageRuntime::ObjCISA
ObjCLanguageRuntime::GetParentClass(ObjCLanguageRuntime::ObjCISA isa)
{
@@ -463,10 +514,9 @@ ObjCLanguageRuntime::GetActualTypeName(O
ObjCLanguageRuntime::ClassDescriptorSP
ObjCLanguageRuntime::GetClassDescriptor (const ConstString &class_name)
{
- UpdateISAToDescriptorMap();
- for (const ISAToDescriptorMap::value_type &val : m_isa_to_descriptor_cache)
- if (val.second && val.second->GetClassName() == class_name)
- return val.second;
+ ISAToDescriptorIterator pos = GetDescriptorIterator (class_name);
+ if (pos != m_isa_to_descriptor.end())
+ return pos->second;
return ClassDescriptorSP();
}
@@ -521,8 +571,8 @@ ObjCLanguageRuntime::GetClassDescriptor
if (isa)
{
UpdateISAToDescriptorMap();
- ObjCLanguageRuntime::ISAToDescriptorIterator pos = m_isa_to_descriptor_cache.find(isa);
- if (pos != m_isa_to_descriptor_cache.end())
+ ObjCLanguageRuntime::ISAToDescriptorIterator pos = m_isa_to_descriptor.find(isa);
+ if (pos != m_isa_to_descriptor.end())
return pos->second;
}
return ClassDescriptorSP();
More information about the lldb-commits
mailing list