diff --git a/lldb/examples/darwin/heap_find/heap.py b/lldb/examples/darwin/heap_find/heap.py index 4e002cfb4ab5..8aed86aab0a0 100644 --- a/lldb/examples/darwin/heap_find/heap.py +++ b/lldb/examples/darwin/heap_find/heap.py @@ -282,6 +282,7 @@ def heap_search(result, options, arg_str): result.AppendMessage(dylid_load_err) return expr = None + print_no_matches = True arg_str_description = arg_str if options.type == 'pointer': expr = 'find_pointer_in_heap((void *)%s)' % (arg_str) @@ -301,6 +302,10 @@ def heap_search(result, options, arg_str): elif options.type == 'addr': expr = 'find_block_for_address((void *)%s)' % arg_str arg_str_description = 'malloc block for %s' % arg_str + elif options.type == 'all': + expr = 'get_heap_info(1)' + arg_str_description = None + print_no_matches = False else: result.AppendMessage('error: invalid type "%s"\nvalid values are "pointer", "cstr"' % options.type) return @@ -378,29 +383,24 @@ def malloc_info(debugger, command, result, dict): else: result.AppendMessage('error: no c string arguments were given to search for') -def malloc_history(debugger, command, result, dict): +def heap(debugger, command, result, dict): command_args = shlex.split(command) usage = "usage: %prog [options] [EXPR ...]" - description='''Gets the allocation history for an expression whose result is an address. + description='''Traverse all allocations on the heap and report statistics. - Programs should set the MallocStackLogging=1 in the environment to enable stack history. This can be done - with "process launch -v MallocStackLogging=1 -- [arg1 ...]"''' - - dylid_load_err = load_dylib() - if dylid_load_err: - result.AppendMessage(dylid_load_err) + If programs set the MallocStackLogging=1 in the environment, then stack + history is available for any allocations. ''' + parser = optparse.OptionParser(description=description, prog='cstr_refs',usage=usage) + add_common_options(parser) + try: + (options, args) = parser.parse_args(command_args) + except: + return + options.type = 'all' + if args: + result.AppendMessage('error: heap command takes no arguments, only options') else: - if command_args: - for addr_expr_str in command_args: - expr_sbvalue = lldb.frame.EvaluateExpression (addr_expr_str) - if expr_sbvalue.error.Success(): - addr = expr_sbvalue.unsigned - if addr != 0: - dump_stack_history_entries (addr, 1) - else: - result.AppendMessage('error: expression error for "%s": %s' % (addr_expr_str, expr_sbvalue.error)) - else: - result.AppendMessage('error: no address expressions were specified') + heap_search (result, options, None) def section_ptr_refs(debugger, command, result, dict): command_args = shlex.split(command) @@ -490,10 +490,10 @@ if __name__ == '__main__': lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.ptr_refs ptr_refs') lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.cstr_refs cstr_refs') lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.malloc_info malloc_info') -lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.malloc_history malloc_history') +lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.heap heap') lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.section_ptr_refs section_ptr_refs') lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.objc_refs objc_refs') -print '"ptr_refs", "cstr_refs", "malloc_info", "malloc_history" and "section_ptr_refs" commands have been installed, use the "--help" options on these commands for detailed help.' +print '"ptr_refs", "cstr_refs", "malloc_info", "heap" and "section_ptr_refs" commands have been installed, use the "--help" options on these commands for detailed help.' diff --git a/lldb/examples/darwin/heap_find/heap/heap_find.cpp b/lldb/examples/darwin/heap_find/heap/heap_find.cpp index b6663d848661..96872864ddeb 100644 --- a/lldb/examples/darwin/heap_find/heap/heap_find.cpp +++ b/lldb/examples/darwin/heap_find/heap/heap_find.cpp @@ -159,7 +159,8 @@ enum data_type_t { eDataTypeAddress, eDataTypeContainsData, - eDataTypeObjC + eDataTypeObjC, + eDataTypeHeapInfo }; struct aligned_data_t @@ -205,6 +206,14 @@ struct malloc_stack_entry mach_vm_address_t frames[MAX_FRAMES]; }; +struct malloc_block_contents +{ + union { + Class isa; + void *pointers[2]; + }; +}; + static int compare_void_ptr (const void *a, const void *b) { @@ -418,6 +427,14 @@ ObjCClasses g_objc_classes; //---------------------------------------------------------------------- // ObjCClassInfo //---------------------------------------------------------------------- + +enum HeapInfoSortType +{ + eSortTypeNone, + eSortTypeBytes, + eSortTypeCount +}; + class ObjCClassInfo { public: @@ -529,15 +546,9 @@ private: return 0; } - enum SortType - { - eSortTypeNone, - eSortTypeBytes, - eSortTypeCount - }; Entry *m_entries; uint32_t m_size; - SortType m_sort_type; + HeapInfoSortType m_sort_type; }; ObjCClassInfo g_objc_class_snapshot; @@ -667,16 +678,15 @@ range_info_callback (task_t task, void *baton, unsigned type, uint64_t ptr_addr, // 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) + malloc_block_contents *block_contents = NULL; + if (task_peek (task, ptr_addr, sizeof(void *), (void **)&block_contents) == KERN_SUCCESS) { // 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); + const uint32_t objc_class_idx = g_objc_classes.FindClassIndex (block_contents->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) { @@ -687,11 +697,11 @@ range_info_callback (task_t task, void *baton, unsigned type, uint64_t ptr_addr, { // Only match exact isa values in the current class or // optionally in the super classes - if (info->objc.match_isa == objc_object_ptr->isa) + if (info->objc.match_isa == block_contents->isa) match = true; else if (info->objc.match_superclasses) { - Class super = class_getSuperclass(objc_object_ptr->isa); + Class super = class_getSuperclass(block_contents->isa); while (super) { match = super == info->objc.match_isa; @@ -721,6 +731,32 @@ range_info_callback (task_t task, void *baton, unsigned type, uint64_t ptr_addr, } } break; + + case eDataTypeHeapInfo: + // 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) + { + malloc_block_contents *block_contents = NULL; + if (task_peek (task, ptr_addr, sizeof(void *), (void **)&block_contents) == KERN_SUCCESS) + { + // 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 (block_contents->isa); + if (objc_class_idx != UINT32_MAX) + { + // This is an objective C object + g_objc_class_snapshot.AddInstance (objc_class_idx, ptr_size); + } + else + { + // Classify other heap info + } + } + } + break; + } } @@ -851,8 +887,6 @@ find_objc_objects_in_memory (void *isa) g_matches.clear(); 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; @@ -863,13 +897,53 @@ find_objc_objects_in_memory (void *isa) 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(); } +//---------------------------------------------------------------------- +// get_heap_info +// +// Gather information for all allocations on the heap and report +// statistics. +//---------------------------------------------------------------------- + +void +get_heap_info (int sort_type) +{ + 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 = eDataTypeHeapInfo; // Check each block for data + 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 + switch (sort_type) + { + case eSortTypeNone: + default: + case eSortTypeBytes: + g_objc_class_snapshot.SortByTotalBytes(g_objc_classes, true); + break; + + case eSortTypeCount: + g_objc_class_snapshot.SortByTotalCount(g_objc_classes, true); + break; + } + } + else + { + printf ("error: no objective C classes\n"); + } +} + //---------------------------------------------------------------------- // find_cstring_in_heap //