forked from OSchip/llvm-project
Added "heap" command to get info on all allocations on the heap. Currently only objective C objects are supported since they are easy to detect.
llvm-svn: 163637
This commit is contained in:
parent
571d9e4b80
commit
4b963415c2
|
@ -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> [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.'
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
|
Loading…
Reference in New Issue