forked from OSchip/llvm-project
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:
parent
cbe99bbb36
commit
7143f00ae9
|
@ -249,14 +249,17 @@ def display_match_results (result, options, arg_str_description, expr_sbvalue, p
|
||||||
description += ', ivar = %s' % (member_path)
|
description += ', ivar = %s' % (member_path)
|
||||||
if print_entry:
|
if print_entry:
|
||||||
match_idx += 1
|
match_idx += 1
|
||||||
|
result_output = ''
|
||||||
if description:
|
if description:
|
||||||
result.AppendMessage(description)
|
result_output += description
|
||||||
if options.print_type and derefed_dynamic_value:
|
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:
|
if options.print_object_description and dynamic_value:
|
||||||
desc = dynamic_value.GetObjectDescription()
|
desc = dynamic_value.GetObjectDescription()
|
||||||
if desc:
|
if desc:
|
||||||
result.AppendMessage(', po=%s' % (desc))
|
result_output += ', po=%s' % (desc)
|
||||||
|
if result_output:
|
||||||
|
result.AppendMessage(result_output)
|
||||||
if options.memory:
|
if options.memory:
|
||||||
cmd_result = lldb.SBCommandReturnObject()
|
cmd_result = lldb.SBCommandReturnObject()
|
||||||
memory_command = "memory read -f %s 0x%x 0x%x" % (options.format, malloc_addr, malloc_addr + malloc_size)
|
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:
|
elif print_no_matches:
|
||||||
result.AppendMessage('no matches found for %s' % (arg_str_description))
|
result.AppendMessage('no matches found for %s' % (arg_str_description))
|
||||||
else:
|
else:
|
||||||
result.AppendMessage(expr_sbvalue.error )
|
result.AppendMessage(str(expr_sbvalue.error))
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def heap_search(result, options, arg_str):
|
def heap_search(result, options, arg_str):
|
||||||
|
@ -286,7 +289,8 @@ def heap_search(result, options, arg_str):
|
||||||
if options.format == None:
|
if options.format == None:
|
||||||
options.format = "A" # 'A' is "address" format
|
options.format = "A" # 'A' is "address" format
|
||||||
elif options.type == 'isa':
|
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
|
arg_str_description = 'objective C classes with isa %s' % arg_str
|
||||||
options.offset = 0
|
options.offset = 0
|
||||||
if options.format == None:
|
if options.format == None:
|
||||||
|
@ -473,7 +477,9 @@ def objc_refs(debugger, command, result, dict):
|
||||||
else:
|
else:
|
||||||
result.AppendMessage('error: expression error for "%s": %s' % (addr_expr_str, expr_sbvalue.error))
|
result.AppendMessage('error: expression error for "%s": %s' % (addr_expr_str, expr_sbvalue.error))
|
||||||
else:
|
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__':
|
if __name__ == '__main__':
|
||||||
lldb.debugger = lldb.SBDebugger.Create()
|
lldb.debugger = lldb.SBDebugger.Create()
|
||||||
|
|
|
@ -18,7 +18,7 @@ DSYM ?= $(EXE).dSYM
|
||||||
# dsym file.
|
# dsym file.
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
$(EXE) : heap_find.cpp
|
$(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
|
# Include all of the makefiles for each source file so we don't have
|
||||||
|
|
|
@ -66,8 +66,10 @@
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
#include <mach/mach.h>
|
#include <mach/mach.h>
|
||||||
#include <malloc/malloc.h>
|
#include <malloc/malloc.h>
|
||||||
|
#include <objc/objc-runtime.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -126,6 +128,8 @@ __mach_stack_logging_frames_for_uniqued_stack (
|
||||||
uint32_t *count
|
uint32_t *count
|
||||||
);
|
);
|
||||||
|
|
||||||
|
extern "C" void *gdb_class_getClass (void *objc_class);
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// Redefine private gloval variables prototypes from
|
// Redefine private gloval variables prototypes from
|
||||||
// "/usr/local/include/stack_logging.h"
|
// "/usr/local/include/stack_logging.h"
|
||||||
|
@ -154,7 +158,8 @@ struct range_callback_info_t
|
||||||
enum data_type_t
|
enum data_type_t
|
||||||
{
|
{
|
||||||
eDataTypeAddress,
|
eDataTypeAddress,
|
||||||
eDataTypeContainsData
|
eDataTypeContainsData,
|
||||||
|
eDataTypeObjC
|
||||||
};
|
};
|
||||||
|
|
||||||
struct aligned_data_t
|
struct aligned_data_t
|
||||||
|
@ -164,6 +169,12 @@ struct aligned_data_t
|
||||||
uint32_t align;
|
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
|
struct range_contains_data_callback_info_t
|
||||||
{
|
{
|
||||||
data_type_t type;
|
data_type_t type;
|
||||||
|
@ -172,6 +183,7 @@ struct range_contains_data_callback_info_t
|
||||||
{
|
{
|
||||||
uintptr_t addr;
|
uintptr_t addr;
|
||||||
aligned_data_t data;
|
aligned_data_t data;
|
||||||
|
objc_data_t objc;
|
||||||
};
|
};
|
||||||
uint32_t match_count;
|
uint32_t match_count;
|
||||||
bool done;
|
bool done;
|
||||||
|
@ -196,7 +208,6 @@ struct malloc_stack_entry
|
||||||
// Local global variables
|
// Local global variables
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
std::vector<malloc_match> g_matches;
|
std::vector<malloc_match> g_matches;
|
||||||
const void *g_lookup_addr = 0;
|
|
||||||
std::vector<malloc_stack_entry> g_malloc_stack_history;
|
std::vector<malloc_stack_entry> g_malloc_stack_history;
|
||||||
mach_vm_address_t g_stack_frames[MAX_FRAMES];
|
mach_vm_address_t g_stack_frames[MAX_FRAMES];
|
||||||
char g_error_string[PATH_MAX];
|
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)
|
switch (info->type)
|
||||||
{
|
{
|
||||||
case eDataTypeAddress:
|
case eDataTypeAddress:
|
||||||
|
// Check if the current malloc block contains an address specified by "info->addr"
|
||||||
if (ptr_addr <= info->addr && info->addr < end_addr)
|
if (ptr_addr <= info->addr && info->addr < end_addr)
|
||||||
{
|
{
|
||||||
++info->match_count;
|
++info->match_count;
|
||||||
|
@ -289,6 +301,7 @@ range_info_callback (task_t task, void *baton, unsigned type, uint64_t ptr_addr,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eDataTypeContainsData:
|
case eDataTypeContainsData:
|
||||||
|
// Check if the current malloc block contains data specified in "info->data"
|
||||||
{
|
{
|
||||||
const uint32_t size = info->data.size;
|
const uint32_t size = info->data.size;
|
||||||
if (size < ptr_size) // Make sure this block can contain this data
|
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;
|
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;
|
range_contains_data_callback_info_t data_info;
|
||||||
data_info.type = eDataTypeContainsData; // Check each block for data
|
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.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.size = sizeof(addr); // How many bytes? The byte size of a pointer
|
||||||
data_info.data.align = sizeof(addr); // Align to a pointer byte size
|
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
|
// that is the a pointer
|
||||||
range_contains_data_callback_info_t data_info;
|
range_contains_data_callback_info_t data_info;
|
||||||
data_info.type = eDataTypeContainsData; // Check each block for data
|
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.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.size = sizeof(addr); // How many bytes? The byte size of a pointer
|
||||||
data_info.data.align = sizeof(addr); // Align to a pointer byte size
|
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();
|
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
|
// 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
|
// that is the C string passed in aligned on a 1 byte boundary
|
||||||
range_contains_data_callback_info_t data_info;
|
range_contains_data_callback_info_t data_info;
|
||||||
data_info.type = eDataTypeContainsData; // Check each block for data
|
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.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.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
|
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
|
// Setup "info" to look for a malloc block that contains data
|
||||||
// that is the C string passed in aligned on a 1 byte boundary
|
// that is the C string passed in aligned on a 1 byte boundary
|
||||||
range_contains_data_callback_info_t data_info;
|
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.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.addr = (uintptr_t)addr; // What data? The C string passed in
|
||||||
data_info.match_count = 0; // Initialize the match count to zero
|
data_info.match_count = 0; // Initialize the match count to zero
|
||||||
|
|
Loading…
Reference in New Issue