diff --git a/lldb/examples/darwin/heap_find/heap.py b/lldb/examples/darwin/heap_find/heap.py index 3a04846e6d7c..170dcc0ccd93 100644 --- a/lldb/examples/darwin/heap_find/heap.py +++ b/lldb/examples/darwin/heap_find/heap.py @@ -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() diff --git a/lldb/examples/darwin/heap_find/heap/Makefile b/lldb/examples/darwin/heap_find/heap/Makefile index bf3580c853db..0e33dc9f8936 100644 --- a/lldb/examples/darwin/heap_find/heap/Makefile +++ b/lldb/examples/darwin/heap_find/heap/Makefile @@ -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 diff --git a/lldb/examples/darwin/heap_find/heap/heap_find.cpp b/lldb/examples/darwin/heap_find/heap/heap_find.cpp index 78ad1b3096ff..f8db2b09041a 100644 --- a/lldb/examples/darwin/heap_find/heap/heap_find.cpp +++ b/lldb/examples/darwin/heap_find/heap/heap_find.cpp @@ -66,8 +66,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -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 g_matches; -const void *g_lookup_addr = 0; std::vector 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