Improved "objc_refs" a bit to be able to find all instances of a class'

superclasses on top of finding the exact class. The current attempt is still
too slow, but it lays the groundwork.

llvm-svn: 163135
This commit is contained in:
Greg Clayton 2012-09-04 14:09:21 +00:00
parent cbe99bbb36
commit 7143f00ae9
3 changed files with 132 additions and 13 deletions

View File

@ -249,14 +249,17 @@ def display_match_results (result, options, arg_str_description, expr_sbvalue, p
description += ', ivar = %s' % (member_path)
if print_entry:
match_idx += 1
result_output = ''
if description:
result.AppendMessage(description)
result_output += description
if options.print_type and derefed_dynamic_value:
result.AppendMessage('%s' % (derefed_dynamic_value))
result_output += '%s' % (derefed_dynamic_value)
if options.print_object_description and dynamic_value:
desc = dynamic_value.GetObjectDescription()
if desc:
result.AppendMessage(', po=%s' % (desc))
result_output += ', po=%s' % (desc)
if result_output:
result.AppendMessage(result_output)
if options.memory:
cmd_result = lldb.SBCommandReturnObject()
memory_command = "memory read -f %s 0x%x 0x%x" % (options.format, malloc_addr, malloc_addr + malloc_size)
@ -270,7 +273,7 @@ def display_match_results (result, options, arg_str_description, expr_sbvalue, p
elif print_no_matches:
result.AppendMessage('no matches found for %s' % (arg_str_description))
else:
result.AppendMessage(expr_sbvalue.error )
result.AppendMessage(str(expr_sbvalue.error))
return 0
def heap_search(result, options, arg_str):
@ -286,7 +289,8 @@ def heap_search(result, options, arg_str):
if options.format == None:
options.format = "A" # 'A' is "address" format
elif options.type == 'isa':
expr = 'find_pointer_in_heap((void *)%s)' % (arg_str)
expr = 'find_objc_objects_in_memory ((void *)%s)' % (arg_str)
#result.AppendMessage ('expr -u0 -- %s' % expr) # REMOVE THIS LINE
arg_str_description = 'objective C classes with isa %s' % arg_str
options.offset = 0
if options.format == None:
@ -473,7 +477,9 @@ def objc_refs(debugger, command, result, dict):
else:
result.AppendMessage('error: expression error for "%s": %s' % (addr_expr_str, expr_sbvalue.error))
else:
result.AppendMessage('error: no address expressions were specified')
# Find all objective C objects by not specifying an isa
options.type = 'isa'
heap_search (result, options, '0x0')
if __name__ == '__main__':
lldb.debugger = lldb.SBDebugger.Create()

View File

@ -18,7 +18,7 @@ DSYM ?= $(EXE).dSYM
# dsym file.
#----------------------------------------------------------------------
$(EXE) : heap_find.cpp
$(CXX) $(CFLAGS) -install_name "@executable_path/libheap.dylib" -dynamiclib heap_find.cpp -o "$(EXE)"
$(CXX) $(CFLAGS) -install_name "@executable_path/libheap.dylib" -dynamiclib -lobjc heap_find.cpp -o "$(EXE)"
#----------------------------------------------------------------------
# Include all of the makefiles for each source file so we don't have

View File

@ -66,8 +66,10 @@
#include <assert.h>
#include <ctype.h>
#include <dlfcn.h>
#include <mach/mach.h>
#include <malloc/malloc.h>
#include <objc/objc-runtime.h>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
@ -126,6 +128,8 @@ __mach_stack_logging_frames_for_uniqued_stack (
uint32_t *count
);
extern "C" void *gdb_class_getClass (void *objc_class);
//----------------------------------------------------------------------
// Redefine private gloval variables prototypes from
// "/usr/local/include/stack_logging.h"
@ -154,7 +158,8 @@ struct range_callback_info_t
enum data_type_t
{
eDataTypeAddress,
eDataTypeContainsData
eDataTypeContainsData,
eDataTypeObjC
};
struct aligned_data_t
@ -164,6 +169,12 @@ struct aligned_data_t
uint32_t align;
};
struct objc_data_t
{
Class match_isa; // Set to NULL for all objective C objects
bool match_superclasses;
};
struct range_contains_data_callback_info_t
{
data_type_t type;
@ -172,6 +183,7 @@ struct range_contains_data_callback_info_t
{
uintptr_t addr;
aligned_data_t data;
objc_data_t objc;
};
uint32_t match_count;
bool done;
@ -196,7 +208,6 @@ struct malloc_stack_entry
// Local global variables
//----------------------------------------------------------------------
std::vector<malloc_match> g_matches;
const void *g_lookup_addr = 0;
std::vector<malloc_stack_entry> g_malloc_stack_history;
mach_vm_address_t g_stack_frames[MAX_FRAMES];
char g_error_string[PATH_MAX];
@ -280,6 +291,7 @@ range_info_callback (task_t task, void *baton, unsigned type, uint64_t ptr_addr,
switch (info->type)
{
case eDataTypeAddress:
// Check if the current malloc block contains an address specified by "info->addr"
if (ptr_addr <= info->addr && info->addr < end_addr)
{
++info->match_count;
@ -289,6 +301,7 @@ range_info_callback (task_t task, void *baton, unsigned type, uint64_t ptr_addr,
break;
case eDataTypeContainsData:
// Check if the current malloc block contains data specified in "info->data"
{
const uint32_t size = info->data.size;
if (size < ptr_size) // Make sure this block can contain this data
@ -318,6 +331,82 @@ range_info_callback (task_t task, void *baton, unsigned type, uint64_t ptr_addr,
}
}
break;
case eDataTypeObjC:
// Check if the current malloc block contains an objective C object
// of any sort where the first pointer in the object is an OBJC class
// pointer (an isa)
{
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))
{
bool match = false;
if (info->objc.match_isa == 0)
{
// Match any objective C object
match = true;
}
else
{
// Only match exact isa values in the current class or
// optionally in the super classes
if (info->objc.match_isa == objc_object_ptr->isa)
match = true;
else if (info->objc.match_superclasses)
{
Class super = class_getSuperclass(objc_object_ptr->isa);
while (super)
{
match = super == info->objc.match_isa;
if (match)
break;
super = class_getSuperclass(super);
}
}
}
if (match)
{
//printf (" success\n");
++info->match_count;
malloc_match match = { (void *)ptr_addr, ptr_size, 0 };
g_matches.push_back(match);
}
else
{
//printf (" error: wrong class: %s\n", dl_info.dli_sname);
}
}
else
{
//printf ("\terror: symbol not objc class: %s\n", dl_info.dli_sname);
return;
}
}
}
break;
}
}
@ -399,7 +488,6 @@ find_pointer_in_heap (const void * addr)
{
range_contains_data_callback_info_t data_info;
data_info.type = eDataTypeContainsData; // Check each block for data
g_lookup_addr = addr;
data_info.data.buffer = (uint8_t *)&addr; // What data? The pointer value passed in
data_info.data.size = sizeof(addr); // How many bytes? The byte size of a pointer
data_info.data.align = sizeof(addr); // Align to a pointer byte size
@ -429,7 +517,6 @@ find_pointer_in_memory (uint64_t memory_addr, uint64_t memory_size, const void *
// that is the a pointer
range_contains_data_callback_info_t data_info;
data_info.type = eDataTypeContainsData; // Check each block for data
g_lookup_addr = addr;
data_info.data.buffer = (uint8_t *)&addr; // What data? The pointer value passed in
data_info.data.size = sizeof(addr); // How many bytes? The byte size of a pointer
data_info.data.align = sizeof(addr); // Align to a pointer byte size
@ -443,6 +530,34 @@ find_pointer_in_memory (uint64_t memory_addr, uint64_t memory_size, const void *
return g_matches.data();
}
//----------------------------------------------------------------------
// find_objc_objects_in_memory
//
// Find all instances of ObjC classes 'c', or all ObjC classes if 'c' is
// NULL. If 'c' is non NULL, then also check objects to see if they
// inherit from 'c'
//----------------------------------------------------------------------
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_matches.empty())
return NULL;
malloc_match match = { NULL, 0, 0 };
g_matches.push_back(match);
return g_matches.data();
}
//----------------------------------------------------------------------
// find_cstring_in_heap
//
@ -461,7 +576,6 @@ find_cstring_in_heap (const char *s)
// that is the C string passed in aligned on a 1 byte boundary
range_contains_data_callback_info_t data_info;
data_info.type = eDataTypeContainsData; // Check each block for data
g_lookup_addr = s; // If an expression was used, then fill in the resolved address we are looking up
data_info.data.buffer = (uint8_t *)s; // What data? The C string passed in
data_info.data.size = strlen(s); // How many bytes? The length of the C string
data_info.data.align = 1; // Data doesn't need to be aligned, so set the alignment to 1
@ -488,7 +602,6 @@ find_block_for_address (const void *addr)
// Setup "info" to look for a malloc block that contains data
// that is the C string passed in aligned on a 1 byte boundary
range_contains_data_callback_info_t data_info;
g_lookup_addr = addr; // If an expression was used, then fill in the resolved address we are looking up
data_info.type = eDataTypeAddress; // Check each block to see if the block contains the address passed in
data_info.addr = (uintptr_t)addr; // What data? The C string passed in
data_info.match_count = 0; // Initialize the match count to zero