summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/examples/darwin/heap_find/heap.py1
-rw-r--r--lldb/examples/darwin/heap_find/heap/heap_find.cpp286
2 files changed, 253 insertions, 34 deletions
diff --git a/lldb/examples/darwin/heap_find/heap.py b/lldb/examples/darwin/heap_find/heap.py
index 170dcc0ccd9..4e002cfb4ab 100644
--- a/lldb/examples/darwin/heap_find/heap.py
+++ b/lldb/examples/darwin/heap_find/heap.py
@@ -471,6 +471,7 @@ def objc_refs(debugger, command, result, dict):
isa = expr_sbvalue.unsigned
if isa:
options.type = 'isa'
+ result.AppendMessage('Searching for all instances of %s (isa=0x%x)' % (class_name, isa))
heap_search (result, options, '0x%x' % isa)
else:
result.AppendMessage('error: Can\'t find isa for an ObjC class named "%s"' % (class_name))
diff --git a/lldb/examples/darwin/heap_find/heap/heap_find.cpp b/lldb/examples/darwin/heap_find/heap/heap_find.cpp
index 0982394d000..b6663d84866 100644
--- a/lldb/examples/darwin/heap_find/heap/heap_find.cpp
+++ b/lldb/examples/darwin/heap_find/heap/heap_find.cpp
@@ -147,7 +147,7 @@ extern "C" int stack_logging_enable_logging;
//----------------------------------------------------------------------
typedef void range_callback_t (task_t task, void *baton, unsigned type, uint64_t ptr_addr, uint64_t ptr_size);
typedef void zone_callback_t (void *info, const malloc_zone_t *zone);
-
+typedef int (*comare_function_t)(const void *, const void *);
struct range_callback_info_t
{
zone_callback_t *zone_callback;
@@ -171,7 +171,7 @@ struct aligned_data_t
struct objc_data_t
{
- Class match_isa; // Set to NULL for all objective C objects
+ void *match_isa; // Set to NULL for all objective C objects
bool match_superclasses;
};
@@ -205,6 +205,16 @@ struct malloc_stack_entry
mach_vm_address_t frames[MAX_FRAMES];
};
+static int
+compare_void_ptr (const void *a, const void *b)
+{
+ Class a_ptr = *(Class *)a;
+ Class b_ptr = *(Class *)b;
+ if (a_ptr < b_ptr) return -1;
+ if (a_ptr > b_ptr) return +1;
+ return 0;
+}
+
class MatchResults
{
enum {
@@ -310,11 +320,227 @@ protected:
};
//----------------------------------------------------------------------
+// A safe way to allocate memory and keep it from interfering with the
+// malloc enumerators.
+//----------------------------------------------------------------------
+void *
+safe_malloc(size_t n_bytes)
+{
+ if (n_bytes > 0)
+ {
+ const int k_page_size = getpagesize();
+ const mach_vm_size_t vm_size = ((n_bytes + k_page_size - 1)/k_page_size) * k_page_size;
+ vm_address_t address = NULL;
+ kern_return_t kerr = vm_allocate (mach_task_self(), &address, vm_size, true);
+ if (kerr == KERN_SUCCESS)
+ return (void *)address;
+ }
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// ObjCClasses
+//----------------------------------------------------------------------
+class ObjCClasses
+{
+public:
+ ObjCClasses() :
+ m_objc_class_ptrs (NULL),
+ m_size (0)
+ {
+ }
+
+ bool
+ Update()
+ {
+ // TODO: find out if class list has changed and update if needed
+ if (m_objc_class_ptrs == NULL)
+ {
+ m_size = objc_getClassList(NULL, 0);
+ if (m_size > 0)
+ {
+ // Allocate the class pointers
+ m_objc_class_ptrs = (Class *)safe_malloc (m_size * sizeof(Class));
+ m_size = objc_getClassList(m_objc_class_ptrs, m_size);
+ // Sort Class pointers for quick lookup
+ ::qsort (m_objc_class_ptrs, m_size, sizeof(Class), compare_void_ptr);
+ }
+ else
+ return false;
+ }
+ return true;
+ }
+
+ uint32_t
+ FindClassIndex (Class isa)
+ {
+ Class *matching_class = (Class *)bsearch (&isa,
+ m_objc_class_ptrs,
+ m_size,
+ sizeof(Class),
+ compare_void_ptr);
+ if (matching_class)
+ {
+ uint32_t idx = matching_class - m_objc_class_ptrs;
+ return idx;
+ }
+ return UINT32_MAX;
+ }
+
+ Class
+ GetClassAtIndex (uint32_t idx) const
+ {
+ if (idx < m_size)
+ return m_objc_class_ptrs[idx];
+ return NULL;
+ }
+ uint32_t
+ GetSize() const
+ {
+ return m_size;
+ }
+private:
+ Class *m_objc_class_ptrs;
+ uint32_t m_size;
+};
+
+
+
+//----------------------------------------------------------------------
// Local global variables
//----------------------------------------------------------------------
//std::vector<malloc_match> g_matches;
MatchResults g_matches;
MallocStackLoggingEntries g_malloc_stack_history;
+ObjCClasses g_objc_classes;
+
+//----------------------------------------------------------------------
+// ObjCClassInfo
+//----------------------------------------------------------------------
+class ObjCClassInfo
+{
+public:
+ ObjCClassInfo() :
+ m_entries (NULL),
+ m_size (0),
+ m_sort_type (eSortTypeNone)
+ {
+ }
+
+ void
+ Update (const ObjCClasses &objc_classes)
+ {
+ m_size = objc_classes.GetSize();
+ m_entries = (Entry *)safe_malloc (m_size * sizeof(Entry));
+ m_sort_type = eSortTypeNone;
+ Reset ();
+ }
+
+ bool
+ AddInstance (uint32_t idx, uint64_t ptr_size)
+ {
+ if (m_size == 0)
+ Update (g_objc_classes);
+ // Update the totals for the classes
+ if (idx < m_size)
+ {
+ m_entries[idx].bytes += ptr_size;
+ ++m_entries[idx].count;
+ return true;
+ }
+ return false;
+ }
+
+ void
+ Reset ()
+ {
+ m_sort_type = eSortTypeNone;
+ for (uint32_t i=0; i<m_size; ++i)
+ {
+ // In case we sort the entries after gathering the data, we will
+ // want to know the index into the m_objc_class_ptrs[] array.
+ m_entries[i].idx = i;
+ m_entries[i].bytes = 0;
+ m_entries[i].count = 0;
+ }
+ }
+ void
+ SortByTotalBytes (const ObjCClasses &objc_classes, bool print)
+ {
+ if (m_sort_type != eSortTypeBytes && m_size > 0)
+ {
+ ::qsort (m_entries, m_size, sizeof(Entry), (comare_function_t)compare_bytes);
+ m_sort_type = eSortTypeBytes;
+ }
+ if (print && m_size > 0)
+ {
+ puts("Objective C objects by total bytes:");
+ puts("Total Bytes Class Name");
+ puts("----------- -----------------------------------------------------------------");
+ for (uint32_t i=0; i<m_size && m_entries[i].bytes > 0; ++i)
+ {
+ printf ("%11llu %s\n", m_entries[i].bytes, class_getName (objc_classes.GetClassAtIndex(m_entries[i].idx)));
+ }
+ }
+ }
+ void
+ SortByTotalCount (const ObjCClasses &objc_classes, bool print)
+ {
+ if (m_sort_type != eSortTypeCount && m_size > 0)
+ {
+ ::qsort (m_entries, m_size, sizeof(Entry), (comare_function_t)compare_count);
+ m_sort_type = eSortTypeCount;
+ }
+ if (print && m_size > 0)
+ {
+ puts("Objective C objects by total count:");
+ puts("Count Class Name");
+ puts("-------- -----------------------------------------------------------------");
+ for (uint32_t i=0; i<m_size && m_entries[i].count > 0; ++i)
+ {
+ printf ("%8u %s\n", m_entries[i].count, class_getName (objc_classes.GetClassAtIndex(m_entries[i].idx)));
+ }
+ }
+ }
+private:
+ struct Entry
+ {
+ uint32_t idx; // Index into the m_objc_class_ptrs[] array
+ uint32_t count; // Number of object instances that were found
+ uint64_t bytes; // Total number of bytes for each objc class
+ };
+
+ static int
+ compare_bytes (const Entry *a, const Entry *b)
+ {
+ // Reverse the comparisong to most bytes entries end up at top of list
+ if (a->bytes > b->bytes) return -1;
+ if (a->bytes < b->bytes) return +1;
+ return 0;
+ }
+
+ static int
+ compare_count (const Entry *a, const Entry *b)
+ {
+ // Reverse the comparisong to most count entries end up at top of list
+ if (a->count > b->count) return -1;
+ if (a->count < b->count) return +1;
+ return 0;
+ }
+
+ enum SortType
+ {
+ eSortTypeNone,
+ eSortTypeBytes,
+ eSortTypeCount
+ };
+ Entry *m_entries;
+ uint32_t m_size;
+ SortType m_sort_type;
+};
+
+ObjCClassInfo g_objc_class_snapshot;
//----------------------------------------------------------------------
// task_peek
@@ -444,29 +670,13 @@ range_info_callback (task_t task, void *baton, unsigned type, uint64_t ptr_addr,
struct objc_class *objc_object_ptr = NULL;
if (task_peek (task, ptr_addr, sizeof(void *), (void **)&objc_object_ptr) == KERN_SUCCESS)
{
- const uint64_t isa_bits = (uintptr_t)objc_object_ptr->isa;
- //printf ("objc: addr = 0x%16.16llx, size = %6llu, isa = 0x%16.16llx", ptr_addr, ptr_size, isa_bits);
- Dl_info dl_info;
-
- if (isa_bits == 0 || isa_bits % sizeof(void*))
- {
- //printf (" error: invalid pointer\n");
- return;
- }
- if (dladdr(objc_object_ptr->isa, &dl_info) == 0)
- {
- //printf (" error: symbol lookup failed\n");
- return;
- }
- if (dl_info.dli_sname == NULL)
- {
- //printf (" error: no symbol name\n");
- return;
- }
-
- if ((dl_info.dli_sname[0] == 'O' && strncmp("OBJC_CLASS_$_" , dl_info.dli_sname, 13) == 0) ||
- (dl_info.dli_sname[0] == '.' && strncmp(".objc_class_name_", dl_info.dli_sname, 17) == 0))
+ // We assume that g_objc_classes is up to date
+ // that the class list was verified to have some classes in it
+ // before calling this function
+ const uint32_t objc_class_idx = g_objc_classes.FindClassIndex (objc_object_ptr->isa);
+ if (objc_class_idx != UINT32_MAX)
{
+ g_objc_class_snapshot.AddInstance (objc_class_idx, ptr_size);
bool match = false;
if (info->objc.match_isa == 0)
{
@@ -639,16 +849,24 @@ malloc_match *
find_objc_objects_in_memory (void *isa)
{
g_matches.clear();
- // Setup "info" to look for a malloc block that contains data
- // that is the a pointer
- range_contains_data_callback_info_t data_info;
- data_info.type = eDataTypeObjC; // Check each block for data
- data_info.objc.match_isa = (Class)isa;
- data_info.objc.match_superclasses = true;
- data_info.match_count = 0; // Initialize the match count to zero
- data_info.done = false; // Set done to false so searching doesn't stop
- range_callback_info_t info = { enumerate_range_in_zone, range_info_callback, &data_info };
- foreach_zone_in_this_process (&info);
+ if (g_objc_classes.Update())
+ {
+ // Reset all stats
+ g_objc_class_snapshot.Reset ();
+ // Setup "info" to look for a malloc block that contains data
+ // that is the a pointer
+ range_contains_data_callback_info_t data_info;
+ data_info.type = eDataTypeObjC; // Check each block for data
+ data_info.objc.match_isa = isa;
+ data_info.objc.match_superclasses = true;
+ data_info.match_count = 0; // Initialize the match count to zero
+ data_info.done = false; // Set done to false so searching doesn't stop
+ range_callback_info_t info = { enumerate_range_in_zone, range_info_callback, &data_info };
+ foreach_zone_in_this_process (&info);
+
+ // Sort and print byte total bytes
+ g_objc_class_snapshot.SortByTotalBytes(g_objc_classes, true);
+ }
return g_matches.data();
}
OpenPOWER on IntegriCloud