blob: e6d2b1f073b06b5cc08da2dfd831df1d14cb8649 [file] [log] [blame]
Greg Clayton804de012012-04-11 16:27:06 +00001#!/usr/bin/python
2
3#----------------------------------------------------------------------
Greg Claytond712ef02012-04-25 18:40:20 +00004# This module is designed to live inside the "lldb" python package
5# in the "lldb.macosx" package. To use this in the embedded python
6# interpreter using "lldb" just import it:
Greg Clayton804de012012-04-11 16:27:06 +00007#
Greg Claytond712ef02012-04-25 18:40:20 +00008# (lldb) script import lldb.macosx.heap
Greg Clayton804de012012-04-11 16:27:06 +00009#----------------------------------------------------------------------
10
11import lldb
12import commands
13import optparse
Greg Clayton7fb671b2012-04-11 18:30:53 +000014import os
Greg Claytond712ef02012-04-25 18:40:20 +000015import os.path
Greg Clayton804de012012-04-11 16:27:06 +000016import shlex
Greg Claytond712ef02012-04-25 18:40:20 +000017import string
18import tempfile
Greg Claytoned3eee62012-04-25 01:49:50 +000019import lldb.utils.symbolication
Greg Clayton804de012012-04-11 16:27:06 +000020
Greg Claytond712ef02012-04-25 18:40:20 +000021g_libheap_dylib_dir = None
22g_libheap_dylib_dict = dict()
Greg Clayton341039f2012-05-11 02:42:36 +000023g_verbose = False
Greg Claytond712ef02012-04-25 18:40:20 +000024
Greg Claytonb403a152012-04-21 00:11:26 +000025def load_dylib():
26 if lldb.target:
Greg Claytond712ef02012-04-25 18:40:20 +000027 global g_libheap_dylib_dir
28 global g_libheap_dylib_dict
29 triple = lldb.target.triple
Greg Clayton4f76fef2012-04-25 21:23:07 +000030 if triple in g_libheap_dylib_dict:
31 libheap_dylib_path = g_libheap_dylib_dict[triple]
32 else:
Greg Claytond712ef02012-04-25 18:40:20 +000033 if not g_libheap_dylib_dir:
Greg Clayton4f76fef2012-04-25 21:23:07 +000034 g_libheap_dylib_dir = tempfile.gettempdir() + '/lldb-dylibs'
35 triple_dir = g_libheap_dylib_dir + '/' + triple + '/' + __name__
Greg Claytond712ef02012-04-25 18:40:20 +000036 if not os.path.exists(triple_dir):
Greg Clayton4f76fef2012-04-25 21:23:07 +000037 os.makedirs(triple_dir)
Greg Claytond712ef02012-04-25 18:40:20 +000038 libheap_dylib_path = triple_dir + '/libheap.dylib'
39 g_libheap_dylib_dict[triple] = libheap_dylib_path
Greg Clayton4f76fef2012-04-25 21:23:07 +000040 heap_code_directory = os.path.dirname(__file__) + '/heap'
41 heap_source_file = heap_code_directory + '/heap_find.cpp'
42 # Check if the dylib doesn't exist, or if "heap_find.cpp" is newer than the dylib
43 if not os.path.exists(libheap_dylib_path) or os.stat(heap_source_file).st_mtime > os.stat(libheap_dylib_path).st_mtime:
44 # Remake the dylib
Greg Claytond712ef02012-04-25 18:40:20 +000045 make_command = '(cd "%s" ; make EXE="%s" ARCH=%s)' % (heap_code_directory, libheap_dylib_path, string.split(triple, '-')[0])
Greg Clayton4f76fef2012-04-25 21:23:07 +000046 # print make_command
Greg Claytond712ef02012-04-25 18:40:20 +000047 make_output = commands.getoutput(make_command)
Greg Clayton4f76fef2012-04-25 21:23:07 +000048 # print make_output
Greg Claytonb403a152012-04-21 00:11:26 +000049 if os.path.exists(libheap_dylib_path):
50 libheap_dylib_spec = lldb.SBFileSpec(libheap_dylib_path)
51 if lldb.target.FindModule(libheap_dylib_spec):
52 return None # success, 'libheap.dylib' already loaded
53 if lldb.process:
54 state = lldb.process.state
55 if state == lldb.eStateStopped:
56 (libheap_dylib_path)
57 error = lldb.SBError()
58 image_idx = lldb.process.LoadImage(libheap_dylib_spec, error)
59 if error.Success():
60 return None
61 else:
62 if error:
63 return 'error: %s' % error
64 else:
65 return 'error: "process load \'%s\'" failed' % libheap_dylib_spec
66 else:
67 return 'error: process is not stopped'
68 else:
69 return 'error: invalid process'
70 else:
71 return 'error: file does not exist "%s"' % libheap_dylib_path
72 else:
73 return 'error: invalid target'
74
75 debugger.HandleCommand('process load "%s"' % libheap_dylib_path)
Greg Clayton341039f2012-05-11 02:42:36 +000076 if lldb.target.FindModule(libheap_dylib_spec):
77 return None # success, 'libheap.dylib' already loaded
78 return 'error: failed to load "%s"' % libheap_dylib_path
Greg Claytonb403a152012-04-21 00:11:26 +000079
Greg Claytond84bb482012-04-13 16:24:09 +000080def add_common_options(parser):
81 parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False)
82 parser.add_option('-o', '--po', action='store_true', dest='print_object_description', help='print the object descriptions for any matches', default=False)
83 parser.add_option('-m', '--memory', action='store_true', dest='memory', help='dump the memory for each matching block', default=False)
84 parser.add_option('-f', '--format', type='string', dest='format', help='the format to use when dumping memory if --memory is specified', default=None)
Greg Claytonb403a152012-04-21 00:11:26 +000085 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)
Greg Claytond9fc5352012-05-10 23:17:28 +000086 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)
87
Greg Claytond9fc5352012-05-10 23:17:28 +000088def dump_stack_history_entry(stack_history_entry, idx):
Greg Clayton7200ed12012-05-10 23:37:52 +000089 address = int(stack_history_entry.address)
90 if address:
91 type_flags = int(stack_history_entry.type_flags)
Greg Claytond9fc5352012-05-10 23:17:28 +000092 symbolicator = lldb.utils.symbolication.Symbolicator()
93 symbolicator.target = lldb.target
Greg Clayton341039f2012-05-11 02:42:36 +000094 type_str = ''
95 if type_flags == 0:
96 type_str = 'free'
97 else:
98 if type_flags & 2:
99 type_str = 'alloc'
100 elif type_flags & 4:
101 type_str = 'free'
102 elif type_flags & 1:
103 type_str = 'generic'
104 else:
105 type_str = hex(type_flags)
106 print 'stack[%u]: addr = 0x%x, type=%s, frames:' % (idx, address, type_str)
Greg Claytond9fc5352012-05-10 23:17:28 +0000107 frame_idx = 0
Greg Clayton7200ed12012-05-10 23:37:52 +0000108 idx = 0
109 pc = int(stack_history_entry.frames[idx])
Greg Claytond9fc5352012-05-10 23:17:28 +0000110 while pc != 0:
111 if pc >= 0x1000:
112 frames = symbolicator.symbolicate(pc)
113 if frames:
114 for frame in frames:
Greg Clayton341039f2012-05-11 02:42:36 +0000115 print ' [%u] %s' % (frame_idx, frame)
Greg Claytond9fc5352012-05-10 23:17:28 +0000116 frame_idx += 1
117 else:
Greg Clayton341039f2012-05-11 02:42:36 +0000118 print ' [%u] 0x%x' % (frame_idx, pc)
Greg Claytond9fc5352012-05-10 23:17:28 +0000119 frame_idx += 1
Greg Clayton7200ed12012-05-10 23:37:52 +0000120 idx = idx + 1
121 pc = int(stack_history_entry.frames[idx])
Greg Claytond9fc5352012-05-10 23:17:28 +0000122 else:
123 pc = 0
Greg Clayton341039f2012-05-11 02:42:36 +0000124 print
Greg Claytond9fc5352012-05-10 23:17:28 +0000125
Greg Clayton341039f2012-05-11 02:42:36 +0000126def dump_stack_history_entries(addr, history):
Greg Claytond9fc5352012-05-10 23:17:28 +0000127 # malloc_stack_entry *get_stack_history_for_address (const void * addr)
Greg Clayton341039f2012-05-11 02:42:36 +0000128 expr = 'get_stack_history_for_address((void *)0x%x, %u)' % (addr, history)
Greg Clayton7200ed12012-05-10 23:37:52 +0000129 print 'expr = "%s"' % (expr)
Greg Claytond9fc5352012-05-10 23:17:28 +0000130 expr_sbvalue = lldb.frame.EvaluateExpression (expr)
131 if expr_sbvalue.error.Success():
132 if expr_sbvalue.unsigned:
133 expr_value = lldb.value(expr_sbvalue)
Greg Clayton7200ed12012-05-10 23:37:52 +0000134 #print 'expr_value = ', expr_value
Greg Claytond9fc5352012-05-10 23:17:28 +0000135 idx = 0;
136 stack_history_entry = expr_value[idx]
Greg Clayton7200ed12012-05-10 23:37:52 +0000137 while int(stack_history_entry.address) != 0:
Greg Claytond9fc5352012-05-10 23:17:28 +0000138 dump_stack_history_entry(stack_history_entry, idx)
139 idx = idx + 1
140 stack_history_entry = expr_value[idx]
Greg Clayton341039f2012-05-11 02:42:36 +0000141 else:
142 print 'error: expression returned => %s' % (expr_sbvalue)
143 else:
144 print 'error: expression failed "%s" => %s' % (expr, expr_sbvalue.error)
Greg Claytond9fc5352012-05-10 23:17:28 +0000145
Greg Claytond84bb482012-04-13 16:24:09 +0000146
Greg Clayton7fb671b2012-04-11 18:30:53 +0000147def heap_search(options, arg_str):
Greg Claytonb403a152012-04-21 00:11:26 +0000148 dylid_load_err = load_dylib()
149 if dylid_load_err:
150 print dylid_load_err
151 return
Greg Clayton7fb671b2012-04-11 18:30:53 +0000152 expr = None
Greg Clayton77677162012-04-12 18:57:36 +0000153 arg_str_description = arg_str
Greg Claytond84bb482012-04-13 16:24:09 +0000154 default_memory_format = "Y" # 'Y' is "bytes with ASCII" format
155 #memory_chunk_size = 1
Greg Clayton7fb671b2012-04-11 18:30:53 +0000156 if options.type == 'pointer':
Greg Claytond712ef02012-04-25 18:40:20 +0000157 expr = 'find_pointer_in_heap((void *)%s)' % (arg_str)
Greg Clayton77677162012-04-12 18:57:36 +0000158 arg_str_description = 'malloc block containing pointer %s' % arg_str
Greg Claytond84bb482012-04-13 16:24:09 +0000159 default_memory_format = "A" # 'A' is "address" format
160 #memory_chunk_size = lldb.process.GetAddressByteSize()
Greg Clayton7fb671b2012-04-11 18:30:53 +0000161 elif options.type == 'cstr':
162 expr = 'find_cstring_in_heap("%s")' % arg_str
Greg Clayton77677162012-04-12 18:57:36 +0000163 arg_str_description = 'malloc block containing "%s"' % arg_str
164 elif options.type == 'addr':
Greg Clayton1bcb26c2012-04-12 21:06:22 +0000165 expr = 'find_block_for_address((void *)%s)' % arg_str
Greg Clayton77677162012-04-12 18:57:36 +0000166 arg_str_description = 'malloc block for %s' % arg_str
Greg Clayton7fb671b2012-04-11 18:30:53 +0000167 else:
168 print 'error: invalid type "%s"\nvalid values are "pointer", "cstr"' % options.type
169 return
170
171 expr_sbvalue = lldb.frame.EvaluateExpression (expr)
172 if expr_sbvalue.error.Success():
173 if expr_sbvalue.unsigned:
174 match_value = lldb.value(expr_sbvalue)
175 i = 0
176 while 1:
177 match_entry = match_value[i]; i += 1
178 malloc_addr = match_entry.addr.sbvalue.unsigned
179 if malloc_addr == 0:
180 break
181 malloc_size = int(match_entry.size)
182 offset = int(match_entry.offset)
183 dynamic_value = match_entry.addr.sbvalue.GetDynamicValue(lldb.eDynamicCanRunTarget)
184 # If the type is still 'void *' then we weren't able to figure
185 # out a dynamic type for the malloc_addr
186 type_name = dynamic_value.type.name
Greg Clayton77677162012-04-12 18:57:36 +0000187 description = '[%u] %s: addr = 0x%x' % (i, arg_str_description, malloc_addr)
188 if offset != 0:
189 description += ' + %u' % (offset)
190 description += ', size = %u' % (malloc_size)
Greg Clayton7fb671b2012-04-11 18:30:53 +0000191 if type_name == 'void *':
192 if options.type == 'pointer' and malloc_size == 4096:
193 error = lldb.SBError()
194 data = bytearray(lldb.process.ReadMemory(malloc_addr, 16, error))
195 if data == '\xa1\xa1\xa1\xa1AUTORELEASE!':
Greg Clayton77677162012-04-12 18:57:36 +0000196 description += ', type = (AUTORELEASE!)'
Greg Claytond84bb482012-04-13 16:24:09 +0000197 print description
Greg Clayton77677162012-04-12 18:57:36 +0000198 else:
199 description += ', type = %s' % (type_name)
200 derefed_dynamic_value = dynamic_value.deref
201 ivar_member = None
202 if derefed_dynamic_value:
203 derefed_dynamic_type = derefed_dynamic_value.type
204 member = derefed_dynamic_type.GetFieldAtIndex(0)
205 search_bases = False
206 if member:
207 if member.GetOffsetInBytes() <= offset:
208 for field_idx in range (derefed_dynamic_type.GetNumberOfFields()):
209 member = derefed_dynamic_type.GetFieldAtIndex(field_idx)
210 member_byte_offset = member.GetOffsetInBytes()
211 if member_byte_offset == offset:
212 ivar_member = member
213 break
214 else:
215 search_bases = True
Greg Clayton7fb671b2012-04-11 18:30:53 +0000216 else:
217 search_bases = True
Greg Clayton7fb671b2012-04-11 18:30:53 +0000218
Greg Clayton77677162012-04-12 18:57:36 +0000219 if not ivar_member and search_bases:
220 for field_idx in range (derefed_dynamic_type.GetNumberOfDirectBaseClasses()):
221 member = derefed_dynamic_type.GetDirectBaseClassAtIndex(field_idx)
Greg Clayton7fb671b2012-04-11 18:30:53 +0000222 member_byte_offset = member.GetOffsetInBytes()
223 if member_byte_offset == offset:
224 ivar_member = member
225 break
Greg Clayton77677162012-04-12 18:57:36 +0000226 if not ivar_member:
227 for field_idx in range (derefed_dynamic_type.GetNumberOfVirtualBaseClasses()):
228 member = derefed_dynamic_type.GetVirtualBaseClassAtIndex(field_idx)
229 member_byte_offset = member.GetOffsetInBytes()
230 if member_byte_offset == offset:
231 ivar_member = member
232 break
Greg Clayton7fb671b2012-04-11 18:30:53 +0000233 if ivar_member:
Greg Clayton77677162012-04-12 18:57:36 +0000234 description +=', ivar = %s' % (ivar_member.name)
235
236 print description
237 if derefed_dynamic_value:
238 print derefed_dynamic_value
239 if options.print_object_description:
240 desc = dynamic_value.GetObjectDescription()
241 if desc:
242 print ' (%s) 0x%x %s\n' % (type_name, malloc_addr, desc)
Greg Claytond84bb482012-04-13 16:24:09 +0000243 if options.memory:
244 memory_format = options.format
245 if not memory_format:
246 memory_format = default_memory_format
247 cmd_result = lldb.SBCommandReturnObject()
248 #count = malloc_size / memory_chunk_size
249 memory_command = "memory read -f %s 0x%x 0x%x" % (memory_format, malloc_addr, malloc_addr + malloc_size)
250 lldb.debugger.GetCommandInterpreter().HandleCommand(memory_command, cmd_result)
251 print cmd_result.GetOutput()
Greg Claytond9fc5352012-05-10 23:17:28 +0000252 if options.stack_history:
Greg Clayton341039f2012-05-11 02:42:36 +0000253 dump_stack_history_entries(malloc_addr, 1)
Greg Claytond9fc5352012-05-10 23:17:28 +0000254 elif options.stack:
Greg Clayton341039f2012-05-11 02:42:36 +0000255 dump_stack_history_entries(malloc_addr, 0)
Greg Clayton7fb671b2012-04-11 18:30:53 +0000256 else:
257 print '%s %s was not found in any malloc blocks' % (options.type, arg_str)
258 else:
Greg Clayton77677162012-04-12 18:57:36 +0000259 print expr_sbvalue.error
260 print
Greg Clayton7fb671b2012-04-11 18:30:53 +0000261
Greg Clayton77677162012-04-12 18:57:36 +0000262def ptr_refs(debugger, command, result, dict):
Greg Clayton804de012012-04-11 16:27:06 +0000263 command_args = shlex.split(command)
Greg Clayton341039f2012-05-11 02:42:36 +0000264 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
Greg Clayton7fb671b2012-04-11 18:30:53 +0000265 description='''Searches the heap for pointer references on darwin user space programs.
266
267 Any matches that were found will dump the malloc blocks that contain the pointers
268 and might be able to print what kind of objects the pointers are contained in using
Greg Clayton77677162012-04-12 18:57:36 +0000269 dynamic type information in the program.'''
270 parser = optparse.OptionParser(description=description, prog='ptr_refs',usage=usage)
Greg Claytond84bb482012-04-13 16:24:09 +0000271 add_common_options(parser)
Greg Clayton804de012012-04-11 16:27:06 +0000272 try:
273 (options, args) = parser.parse_args(command_args)
274 except:
275 return
Greg Clayton7fb671b2012-04-11 18:30:53 +0000276
277 options.type = 'pointer'
Greg Clayton804de012012-04-11 16:27:06 +0000278
279 if args:
280
281 for data in args:
Greg Clayton7fb671b2012-04-11 18:30:53 +0000282 heap_search (options, data)
Greg Clayton804de012012-04-11 16:27:06 +0000283 else:
Greg Clayton7fb671b2012-04-11 18:30:53 +0000284 print 'error: no pointer arguments were given'
Greg Clayton804de012012-04-11 16:27:06 +0000285
Greg Clayton77677162012-04-12 18:57:36 +0000286def cstr_refs(debugger, command, result, dict):
Greg Clayton7fb671b2012-04-11 18:30:53 +0000287 command_args = shlex.split(command)
Greg Clayton77677162012-04-12 18:57:36 +0000288 usage = "usage: %prog [options] <CSTR> [CSTR ...]"
Greg Clayton7fb671b2012-04-11 18:30:53 +0000289 description='''Searches the heap for C string references on darwin user space programs.
290
291 Any matches that were found will dump the malloc blocks that contain the C strings
292 and might be able to print what kind of objects the pointers are contained in using
Greg Clayton77677162012-04-12 18:57:36 +0000293 dynamic type information in the program.'''
294 parser = optparse.OptionParser(description=description, prog='cstr_refs',usage=usage)
Greg Claytond84bb482012-04-13 16:24:09 +0000295 add_common_options(parser)
Greg Clayton7fb671b2012-04-11 18:30:53 +0000296 try:
297 (options, args) = parser.parse_args(command_args)
298 except:
299 return
300
301 options.type = 'cstr'
302
303 if args:
304
305 for data in args:
306 heap_search (options, data)
307 else:
308 print 'error: no c string arguments were given to search for'
Greg Clayton804de012012-04-11 16:27:06 +0000309
Greg Clayton77677162012-04-12 18:57:36 +0000310def malloc_info(debugger, command, result, dict):
311 command_args = shlex.split(command)
Greg Clayton341039f2012-05-11 02:42:36 +0000312 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
Greg Clayton77677162012-04-12 18:57:36 +0000313 description='''Searches the heap a malloc block that contains the addresses specified as arguments.
314
315 Any matches that were found will dump the malloc blocks that match or contain
316 the specified address. The matching blocks might be able to show what kind
317 of objects they are using dynamic type information in the program.'''
318 parser = optparse.OptionParser(description=description, prog='cstr_refs',usage=usage)
Greg Claytond84bb482012-04-13 16:24:09 +0000319 add_common_options(parser)
Greg Clayton77677162012-04-12 18:57:36 +0000320 try:
321 (options, args) = parser.parse_args(command_args)
322 except:
323 return
Greg Clayton77677162012-04-12 18:57:36 +0000324 options.type = 'addr'
Greg Clayton77677162012-04-12 18:57:36 +0000325 if args:
Greg Clayton77677162012-04-12 18:57:36 +0000326 for data in args:
327 heap_search (options, data)
328 else:
329 print 'error: no c string arguments were given to search for'
330
Greg Clayton341039f2012-05-11 02:42:36 +0000331def malloc_history(debugger, command, result, dict):
332 command_args = shlex.split(command)
333 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
334 description='''Gets the allocation history for an expression whose result is an address.
335
336 Programs should set the MallocStackLoggingNoCompact=1 in the environment to enable stack history. This can be done
337 with "process launch -v MallocStackLoggingNoCompact=1 -- [arg1 ...]"'''
338
339 dylid_load_err = load_dylib()
340 if dylid_load_err:
341 print dylid_load_err
342 else:
343 if command_args:
344 for addr_expr_str in command_args:
345 expr_sbvalue = lldb.frame.EvaluateExpression (addr_expr_str)
346 if expr_sbvalue.error.Success():
347 addr = expr_sbvalue.unsigned
348 if addr != 0:
349 dump_stack_history_entries (addr, 1)
350 else:
351 print 'error: expression error for "%s": %s' % (addr_expr_str, expr_sbvalue.error)
352 else:
353 print 'error: no address expressions were specified'
354
Greg Claytond712ef02012-04-25 18:40:20 +0000355if __name__ == '__main__':
356 lldb.debugger = lldb.SBDebugger.Create()
357
358# This initializer is being run from LLDB in the embedded command interpreter
359# Add any commands contained in this module to LLDB
360lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.ptr_refs ptr_refs')
361lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.cstr_refs cstr_refs')
362lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.malloc_info malloc_info')
Greg Clayton341039f2012-05-11 02:42:36 +0000363lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.malloc_history malloc_history')
364print '"ptr_refs", "cstr_refs", "malloc_info", and "malloc_history" commands have been installed, use the "--help" options on these commands for detailed help.'
Greg Clayton804de012012-04-11 16:27:06 +0000365
366
367
368