More fixes to "malloc_history".

llvm-svn: 156605
This commit is contained in:
Greg Clayton 2012-05-11 02:42:36 +00:00
parent 74d7f15aed
commit 341039faca
2 changed files with 90 additions and 64 deletions

View File

@ -20,6 +20,7 @@ import lldb.utils.symbolication
g_libheap_dylib_dir = None
g_libheap_dylib_dict = dict()
g_verbose = False
def load_dylib():
if lldb.target:
@ -72,6 +73,9 @@ def load_dylib():
return 'error: invalid target'
debugger.HandleCommand('process load "%s"' % libheap_dylib_path)
if lldb.target.FindModule(libheap_dylib_spec):
return None # success, 'libheap.dylib' already loaded
return 'error: failed to load "%s"' % libheap_dylib_path
def add_common_options(parser):
parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False)
@ -81,17 +85,25 @@ def add_common_options(parser):
parser.add_option('-s', '--stack', action='store_true', dest='stack', help='gets the stack that allocated each malloc block if MallocStackLogging is enabled', default=False)
parser.add_option('-S', '--stack-history', action='store_true', dest='stack_history', help='gets the stack history for all allocations whose start address matches each malloc block if MallocStackLogging is enabled', default=False)
type_flag_strings = [ 'free', 'generic', 'alloc', 'dealloc' ];
def dump_stack_history_entry(stack_history_entry, idx):
address = int(stack_history_entry.address)
if address:
type_flags = int(stack_history_entry.type_flags)
argument = int(stack_history_entry.argument)
symbolicator = lldb.utils.symbolication.Symbolicator()
symbolicator.target = lldb.target
global type_flag_strings
print 'stack_history_entry[%u]: addr = 0x%x, type=%s, arg=%u, frames=' % (idx, address, type_flag_strings[type_flags], argument)
type_str = ''
if type_flags == 0:
type_str = 'free'
else:
if type_flags & 2:
type_str = 'alloc'
elif type_flags & 4:
type_str = 'free'
elif type_flags & 1:
type_str = 'generic'
else:
type_str = hex(type_flags)
print 'stack[%u]: addr = 0x%x, type=%s, frames:' % (idx, address, type_str)
frame_idx = 0
idx = 0
pc = int(stack_history_entry.frames[idx])
@ -100,20 +112,20 @@ def dump_stack_history_entry(stack_history_entry, idx):
frames = symbolicator.symbolicate(pc)
if frames:
for frame in frames:
print '[%3u] %s' % (frame_idx, frame)
print ' [%u] %s' % (frame_idx, frame)
frame_idx += 1
else:
print '[%3u] 0x%x' % (frame_idx, pc)
print ' [%u] 0x%x' % (frame_idx, pc)
frame_idx += 1
idx = idx + 1
pc = int(stack_history_entry.frames[idx])
else:
pc = 0
print
def dump_stack_history_entries(addr):
def dump_stack_history_entries(addr, history):
# malloc_stack_entry *get_stack_history_for_address (const void * addr)
expr = 'get_stack_history_for_address((void *)0x%x)' % (addr)
expr = 'get_stack_history_for_address((void *)0x%x, %u)' % (addr, history)
print 'expr = "%s"' % (expr)
expr_sbvalue = lldb.frame.EvaluateExpression (expr)
if expr_sbvalue.error.Success():
@ -126,6 +138,10 @@ def dump_stack_history_entries(addr):
dump_stack_history_entry(stack_history_entry, idx)
idx = idx + 1
stack_history_entry = expr_value[idx]
else:
print 'error: expression returned => %s' % (expr_sbvalue)
else:
print 'error: expression failed "%s" => %s' % (expr, expr_sbvalue.error)
def heap_search(options, arg_str):
@ -234,42 +250,9 @@ def heap_search(options, arg_str):
lldb.debugger.GetCommandInterpreter().HandleCommand(memory_command, cmd_result)
print cmd_result.GetOutput()
if options.stack_history:
dump_stack_history_entries(malloc_addr)
dump_stack_history_entries(malloc_addr, 1)
elif options.stack:
symbolicator = lldb.utils.symbolication.Symbolicator()
symbolicator.target = lldb.target
expr_str = "g_stack_frames_count = sizeof(g_stack_frames)/sizeof(uint64_t); (int)__mach_stack_logging_get_frames((unsigned)mach_task_self(), 0x%xull, g_stack_frames, g_stack_frames_count, &g_stack_frames_count)" % (malloc_addr)
#print expr_str
expr = lldb.frame.EvaluateExpression (expr_str);
expr_error = expr.GetError()
if expr_error.Success():
err = expr.unsigned
if err:
print 'error: __mach_stack_logging_get_frames() returned error %i' % (err)
else:
count_expr = lldb.frame.EvaluateExpression ("g_stack_frames_count")
count = count_expr.unsigned
#print 'g_stack_frames_count is %u' % (count)
if count > 0:
frame_idx = 0
frames_expr = lldb.value(lldb.frame.EvaluateExpression ("g_stack_frames"))
done = False
for stack_frame_idx in range(count):
if not done:
frame_load_addr = int(frames_expr[stack_frame_idx])
if frame_load_addr >= 0x1000:
frames = symbolicator.symbolicate(frame_load_addr)
if frames:
for frame in frames:
print '[%3u] %s' % (frame_idx, frame)
frame_idx += 1
else:
print '[%3u] 0x%x' % (frame_idx, frame_load_addr)
frame_idx += 1
else:
done = True
else:
print 'error: %s' % (expr_error)
dump_stack_history_entries(malloc_addr, 0)
else:
print '%s %s was not found in any malloc blocks' % (options.type, arg_str)
else:
@ -278,7 +261,7 @@ def heap_search(options, arg_str):
def ptr_refs(debugger, command, result, dict):
command_args = shlex.split(command)
usage = "usage: %prog [options] <PTR> [PTR ...]"
usage = "usage: %prog [options] <EXPR> [EXPR ...]"
description='''Searches the heap for pointer references on darwin user space programs.
Any matches that were found will dump the malloc blocks that contain the pointers
@ -326,7 +309,7 @@ def cstr_refs(debugger, command, result, dict):
def malloc_info(debugger, command, result, dict):
command_args = shlex.split(command)
usage = "usage: %prog [options] <ADDR> [ADDR ...]"
usage = "usage: %prog [options] <EXPR> [EXPR ...]"
description='''Searches the heap a malloc block that contains the addresses specified as arguments.
Any matches that were found will dump the malloc blocks that match or contain
@ -338,16 +321,37 @@ def malloc_info(debugger, command, result, dict):
(options, args) = parser.parse_args(command_args)
except:
return
options.type = 'addr'
if args:
for data in args:
heap_search (options, data)
else:
print 'error: no c string arguments were given to search for'
def malloc_history(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.
Programs should set the MallocStackLoggingNoCompact=1 in the environment to enable stack history. This can be done
with "process launch -v MallocStackLoggingNoCompact=1 -- [arg1 ...]"'''
dylid_load_err = load_dylib()
if dylid_load_err:
print dylid_load_err
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:
print 'error: expression error for "%s": %s' % (addr_expr_str, expr_sbvalue.error)
else:
print 'error: no address expressions were specified'
if __name__ == '__main__':
lldb.debugger = lldb.SBDebugger.Create()
@ -356,7 +360,8 @@ 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')
print '"ptr_refs", "cstr_refs", and "malloc_info" commands have been installed, use the "--help" options on these commands for detailed help.'
lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.malloc_history malloc_history')
print '"ptr_refs", "cstr_refs", "malloc_info", and "malloc_history" commands have been installed, use the "--help" options on these commands for detailed help.'

View File

@ -121,7 +121,7 @@ struct malloc_match
struct malloc_stack_entry
{
void *address;
const void *address;
uint64_t argument;
uint32_t type_flags;
std::vector<uintptr_t> frames;
@ -132,7 +132,7 @@ 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];
uint32_t g_stack_frames_count = 0;
char g_error_string[PATH_MAX];
//----------------------------------------------------------------------
// task_peek
@ -273,21 +273,42 @@ get_stack_for_address_enumerator(mach_stack_logging_record_t stack_record, void
}
malloc_stack_entry *
get_stack_history_for_address (const void * addr)
get_stack_history_for_address (const void * addr, int history)
{
// typedef struct {
// uint32_t type_flags;
// uint64_t stack_identifier;
// uint64_t argument;
// mach_vm_address_t address;
// } mach_stack_logging_record_t;
std::vector<malloc_stack_entry> empty;
g_malloc_stack_history.swap(empty);
if (!stack_logging_enable_logging || (history && !stack_logging_dontcompact))
{
if (history)
strncpy(g_error_string, "error: stack history logging is not enabled, set MallocStackLoggingNoCompact=1 in the environment when launching to enable stack history logging.", sizeof(g_error_string));
else
strncpy(g_error_string, "error: stack logging is not enabled, set MallocStackLogging=1 in the environment when launching to enable stack logging.", sizeof(g_error_string));
return NULL;
}
kern_return_t err;
task_t task = mach_task_self();
kern_return_t err = __mach_stack_logging_enumerate_records (task,
(mach_vm_address_t)addr,
get_stack_for_address_enumerator,
&task);
if (history)
{
err = __mach_stack_logging_enumerate_records (task,
(mach_vm_address_t)addr,
get_stack_for_address_enumerator,
&task);
}
else
{
uint32_t num_frames = 0;
err = __mach_stack_logging_get_frames(task, (mach_vm_address_t)addr, g_stack_frames, MAX_FRAMES, &num_frames);
if (err == 0 && num_frames > 0)
{
g_malloc_stack_history.resize(1);
g_malloc_stack_history.back().address = addr;
g_malloc_stack_history.back().type_flags = stack_logging_type_alloc;
g_malloc_stack_history.back().argument = 0;
if (num_frames > 0)
g_malloc_stack_history.back().frames.assign(g_stack_frames, g_stack_frames + num_frames);
g_malloc_stack_history.back().frames.push_back(0); // Terminate the frames with zero
}
}
// Append an empty entry
if (g_malloc_stack_history.empty())
return NULL;