blob: da36495c2ac0dcc8b84caac6faf5634df2569c3c [file] [log] [blame]
Greg Claytone93e24f2012-04-11 16:27:06 +00001#!/usr/bin/python
2
3#----------------------------------------------------------------------
4# Be sure to add the python path that points to the LLDB shared library.
5#
6# # To use this in the embedded python interpreter using "lldb" just
7# import it with the full path using the "command script import"
8# command
9# (lldb) command script import /path/to/heap.py
10#
11# For the shells csh, tcsh:
12# ( setenv PYTHONPATH /path/to/LLDB.framework/Resources/Python ; ./heap.py )
13#
14# For the shells sh, bash:
15# PYTHONPATH=/path/to/LLDB.framework/Resources/Python ./heap.py
16#----------------------------------------------------------------------
17
18import lldb
19import commands
20import optparse
Greg Clayton96666442012-04-11 18:30:53 +000021import os
Greg Claytone93e24f2012-04-11 16:27:06 +000022import shlex
Greg Clayton9098fee2012-04-21 00:11:26 +000023import symbolication # from lldb/examples/python/symbolication.py
Greg Claytone93e24f2012-04-11 16:27:06 +000024
Greg Clayton9098fee2012-04-21 00:11:26 +000025def load_dylib():
26 if lldb.target:
27 python_module_directory = os.path.dirname(__file__)
28 libheap_dylib_path = python_module_directory + '/libheap.dylib'
29 if not os.path.exists(libheap_dylib_path):
30 make_command = '(cd "%s" ; make)' % python_module_directory
31 print make_command
32 print commands.getoutput(make_command)
33 if os.path.exists(libheap_dylib_path):
34 libheap_dylib_spec = lldb.SBFileSpec(libheap_dylib_path)
35 if lldb.target.FindModule(libheap_dylib_spec):
36 return None # success, 'libheap.dylib' already loaded
37 if lldb.process:
38 state = lldb.process.state
39 if state == lldb.eStateStopped:
40 (libheap_dylib_path)
41 error = lldb.SBError()
42 image_idx = lldb.process.LoadImage(libheap_dylib_spec, error)
43 if error.Success():
44 return None
45 else:
46 if error:
47 return 'error: %s' % error
48 else:
49 return 'error: "process load \'%s\'" failed' % libheap_dylib_spec
50 else:
51 return 'error: process is not stopped'
52 else:
53 return 'error: invalid process'
54 else:
55 return 'error: file does not exist "%s"' % libheap_dylib_path
56 else:
57 return 'error: invalid target'
58
59 debugger.HandleCommand('process load "%s"' % libheap_dylib_path)
60
Greg Clayton93e5ba52012-04-13 16:24:09 +000061def add_common_options(parser):
62 parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False)
63 parser.add_option('-o', '--po', action='store_true', dest='print_object_description', help='print the object descriptions for any matches', default=False)
64 parser.add_option('-m', '--memory', action='store_true', dest='memory', help='dump the memory for each matching block', default=False)
65 parser.add_option('-f', '--format', type='string', dest='format', help='the format to use when dumping memory if --memory is specified', default=None)
Greg Clayton9098fee2012-04-21 00:11:26 +000066 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)
67 #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)
Greg Clayton93e5ba52012-04-13 16:24:09 +000068
Greg Clayton96666442012-04-11 18:30:53 +000069def heap_search(options, arg_str):
Greg Clayton9098fee2012-04-21 00:11:26 +000070 dylid_load_err = load_dylib()
71 if dylid_load_err:
72 print dylid_load_err
73 return
Greg Clayton96666442012-04-11 18:30:53 +000074 expr = None
Greg Claytonbff78412012-04-12 18:57:36 +000075 arg_str_description = arg_str
Greg Clayton93e5ba52012-04-13 16:24:09 +000076 default_memory_format = "Y" # 'Y' is "bytes with ASCII" format
77 #memory_chunk_size = 1
Greg Clayton96666442012-04-11 18:30:53 +000078 if options.type == 'pointer':
Greg Claytonf5902cb2012-04-12 21:06:22 +000079 expr = 'find_pointer_in_heap((void *)%s)' % arg_str
Greg Claytonbff78412012-04-12 18:57:36 +000080 arg_str_description = 'malloc block containing pointer %s' % arg_str
Greg Clayton93e5ba52012-04-13 16:24:09 +000081 default_memory_format = "A" # 'A' is "address" format
82 #memory_chunk_size = lldb.process.GetAddressByteSize()
Greg Clayton96666442012-04-11 18:30:53 +000083 elif options.type == 'cstr':
84 expr = 'find_cstring_in_heap("%s")' % arg_str
Greg Claytonbff78412012-04-12 18:57:36 +000085 arg_str_description = 'malloc block containing "%s"' % arg_str
86 elif options.type == 'addr':
Greg Claytonf5902cb2012-04-12 21:06:22 +000087 expr = 'find_block_for_address((void *)%s)' % arg_str
Greg Claytonbff78412012-04-12 18:57:36 +000088 arg_str_description = 'malloc block for %s' % arg_str
Greg Clayton96666442012-04-11 18:30:53 +000089 else:
90 print 'error: invalid type "%s"\nvalid values are "pointer", "cstr"' % options.type
91 return
92
93 expr_sbvalue = lldb.frame.EvaluateExpression (expr)
94 if expr_sbvalue.error.Success():
95 if expr_sbvalue.unsigned:
96 match_value = lldb.value(expr_sbvalue)
97 i = 0
98 while 1:
99 match_entry = match_value[i]; i += 1
100 malloc_addr = match_entry.addr.sbvalue.unsigned
101 if malloc_addr == 0:
102 break
103 malloc_size = int(match_entry.size)
104 offset = int(match_entry.offset)
105 dynamic_value = match_entry.addr.sbvalue.GetDynamicValue(lldb.eDynamicCanRunTarget)
106 # If the type is still 'void *' then we weren't able to figure
107 # out a dynamic type for the malloc_addr
108 type_name = dynamic_value.type.name
Greg Claytonbff78412012-04-12 18:57:36 +0000109 description = '[%u] %s: addr = 0x%x' % (i, arg_str_description, malloc_addr)
110 if offset != 0:
111 description += ' + %u' % (offset)
112 description += ', size = %u' % (malloc_size)
Greg Clayton96666442012-04-11 18:30:53 +0000113 if type_name == 'void *':
114 if options.type == 'pointer' and malloc_size == 4096:
115 error = lldb.SBError()
116 data = bytearray(lldb.process.ReadMemory(malloc_addr, 16, error))
117 if data == '\xa1\xa1\xa1\xa1AUTORELEASE!':
Greg Claytonbff78412012-04-12 18:57:36 +0000118 description += ', type = (AUTORELEASE!)'
Greg Clayton93e5ba52012-04-13 16:24:09 +0000119 print description
Greg Claytonbff78412012-04-12 18:57:36 +0000120 else:
121 description += ', type = %s' % (type_name)
122 derefed_dynamic_value = dynamic_value.deref
123 ivar_member = None
124 if derefed_dynamic_value:
125 derefed_dynamic_type = derefed_dynamic_value.type
126 member = derefed_dynamic_type.GetFieldAtIndex(0)
127 search_bases = False
128 if member:
129 if member.GetOffsetInBytes() <= offset:
130 for field_idx in range (derefed_dynamic_type.GetNumberOfFields()):
131 member = derefed_dynamic_type.GetFieldAtIndex(field_idx)
132 member_byte_offset = member.GetOffsetInBytes()
133 if member_byte_offset == offset:
134 ivar_member = member
135 break
136 else:
137 search_bases = True
Greg Clayton96666442012-04-11 18:30:53 +0000138 else:
139 search_bases = True
Greg Clayton96666442012-04-11 18:30:53 +0000140
Greg Claytonbff78412012-04-12 18:57:36 +0000141 if not ivar_member and search_bases:
142 for field_idx in range (derefed_dynamic_type.GetNumberOfDirectBaseClasses()):
143 member = derefed_dynamic_type.GetDirectBaseClassAtIndex(field_idx)
Greg Clayton96666442012-04-11 18:30:53 +0000144 member_byte_offset = member.GetOffsetInBytes()
145 if member_byte_offset == offset:
146 ivar_member = member
147 break
Greg Claytonbff78412012-04-12 18:57:36 +0000148 if not ivar_member:
149 for field_idx in range (derefed_dynamic_type.GetNumberOfVirtualBaseClasses()):
150 member = derefed_dynamic_type.GetVirtualBaseClassAtIndex(field_idx)
151 member_byte_offset = member.GetOffsetInBytes()
152 if member_byte_offset == offset:
153 ivar_member = member
154 break
Greg Clayton96666442012-04-11 18:30:53 +0000155 if ivar_member:
Greg Claytonbff78412012-04-12 18:57:36 +0000156 description +=', ivar = %s' % (ivar_member.name)
157
158 print description
159 if derefed_dynamic_value:
160 print derefed_dynamic_value
161 if options.print_object_description:
162 desc = dynamic_value.GetObjectDescription()
163 if desc:
164 print ' (%s) 0x%x %s\n' % (type_name, malloc_addr, desc)
Greg Clayton93e5ba52012-04-13 16:24:09 +0000165 if options.memory:
166 memory_format = options.format
167 if not memory_format:
168 memory_format = default_memory_format
169 cmd_result = lldb.SBCommandReturnObject()
170 #count = malloc_size / memory_chunk_size
171 memory_command = "memory read -f %s 0x%x 0x%x" % (memory_format, malloc_addr, malloc_addr + malloc_size)
172 lldb.debugger.GetCommandInterpreter().HandleCommand(memory_command, cmd_result)
173 print cmd_result.GetOutput()
Greg Clayton9098fee2012-04-21 00:11:26 +0000174 if options.stack:
175 symbolicator = symbolication.Symbolicator()
176 symbolicator.target = lldb.target
177 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)
178 #print expr_str
179 expr = lldb.frame.EvaluateExpression (expr_str);
180 expr_error = expr.GetError()
181 if expr_error.Success():
182 err = expr.unsigned
183 if err:
184 print 'error: __mach_stack_logging_get_frames() returned error %i' % (err)
185 else:
186 count_expr = lldb.frame.EvaluateExpression ("g_stack_frames_count")
187 count = count_expr.unsigned
188 #print 'g_stack_frames_count is %u' % (count)
189 if count > 0:
190 frame_idx = 0
191 frames_expr = lldb.value(lldb.frame.EvaluateExpression ("g_stack_frames"))
192 done = False
193 for stack_frame_idx in range(count):
194 if not done:
195 frame_load_addr = int(frames_expr[stack_frame_idx])
196 if frame_load_addr >= 0x1000:
197 frames = symbolicator.symbolicate(frame_load_addr)
198 if frames:
199 for frame in frames:
200 print '[%3u] %s' % (frame_idx, frame)
201 frame_idx += 1
202 else:
203 print '[%3u] 0x%x' % (frame_idx, frame_load_addr)
204 frame_idx += 1
205 else:
206 done = True
207 else:
208 print 'error: %s' % (expr_error)
Greg Clayton96666442012-04-11 18:30:53 +0000209 else:
210 print '%s %s was not found in any malloc blocks' % (options.type, arg_str)
211 else:
Greg Claytonbff78412012-04-12 18:57:36 +0000212 print expr_sbvalue.error
213 print
Greg Clayton96666442012-04-11 18:30:53 +0000214
Greg Claytonbff78412012-04-12 18:57:36 +0000215def ptr_refs(debugger, command, result, dict):
Greg Claytone93e24f2012-04-11 16:27:06 +0000216 command_args = shlex.split(command)
Greg Claytonbff78412012-04-12 18:57:36 +0000217 usage = "usage: %prog [options] <PTR> [PTR ...]"
Greg Clayton96666442012-04-11 18:30:53 +0000218 description='''Searches the heap for pointer references on darwin user space programs.
219
220 Any matches that were found will dump the malloc blocks that contain the pointers
221 and might be able to print what kind of objects the pointers are contained in using
Greg Claytonbff78412012-04-12 18:57:36 +0000222 dynamic type information in the program.'''
223 parser = optparse.OptionParser(description=description, prog='ptr_refs',usage=usage)
Greg Clayton93e5ba52012-04-13 16:24:09 +0000224 add_common_options(parser)
Greg Claytone93e24f2012-04-11 16:27:06 +0000225 try:
226 (options, args) = parser.parse_args(command_args)
227 except:
228 return
Greg Clayton96666442012-04-11 18:30:53 +0000229
230 options.type = 'pointer'
Greg Claytone93e24f2012-04-11 16:27:06 +0000231
232 if args:
233
234 for data in args:
Greg Clayton96666442012-04-11 18:30:53 +0000235 heap_search (options, data)
Greg Claytone93e24f2012-04-11 16:27:06 +0000236 else:
Greg Clayton96666442012-04-11 18:30:53 +0000237 print 'error: no pointer arguments were given'
Greg Claytone93e24f2012-04-11 16:27:06 +0000238
Greg Claytonbff78412012-04-12 18:57:36 +0000239def cstr_refs(debugger, command, result, dict):
Greg Clayton96666442012-04-11 18:30:53 +0000240 command_args = shlex.split(command)
Greg Claytonbff78412012-04-12 18:57:36 +0000241 usage = "usage: %prog [options] <CSTR> [CSTR ...]"
Greg Clayton96666442012-04-11 18:30:53 +0000242 description='''Searches the heap for C string references on darwin user space programs.
243
244 Any matches that were found will dump the malloc blocks that contain the C strings
245 and might be able to print what kind of objects the pointers are contained in using
Greg Claytonbff78412012-04-12 18:57:36 +0000246 dynamic type information in the program.'''
247 parser = optparse.OptionParser(description=description, prog='cstr_refs',usage=usage)
Greg Clayton93e5ba52012-04-13 16:24:09 +0000248 add_common_options(parser)
Greg Clayton96666442012-04-11 18:30:53 +0000249 try:
250 (options, args) = parser.parse_args(command_args)
251 except:
252 return
253
254 options.type = 'cstr'
255
256 if args:
257
258 for data in args:
259 heap_search (options, data)
260 else:
261 print 'error: no c string arguments were given to search for'
Greg Claytone93e24f2012-04-11 16:27:06 +0000262
Greg Claytonbff78412012-04-12 18:57:36 +0000263def malloc_info(debugger, command, result, dict):
264 command_args = shlex.split(command)
265 usage = "usage: %prog [options] <ADDR> [ADDR ...]"
266 description='''Searches the heap a malloc block that contains the addresses specified as arguments.
267
268 Any matches that were found will dump the malloc blocks that match or contain
269 the specified address. The matching blocks might be able to show what kind
270 of objects they are using dynamic type information in the program.'''
271 parser = optparse.OptionParser(description=description, prog='cstr_refs',usage=usage)
Greg Clayton93e5ba52012-04-13 16:24:09 +0000272 add_common_options(parser)
Greg Claytonbff78412012-04-12 18:57:36 +0000273 try:
274 (options, args) = parser.parse_args(command_args)
275 except:
276 return
277
278 options.type = 'addr'
279
280 if args:
281
282 for data in args:
283 heap_search (options, data)
284 else:
285 print 'error: no c string arguments were given to search for'
286
Greg Claytone93e24f2012-04-11 16:27:06 +0000287def __lldb_init_module (debugger, dict):
288 # This initializer is being run from LLDB in the embedded command interpreter
289 # Add any commands contained in this module to LLDB
Greg Claytonbff78412012-04-12 18:57:36 +0000290 debugger.HandleCommand('command script add -f heap.ptr_refs ptr_refs')
291 debugger.HandleCommand('command script add -f heap.cstr_refs cstr_refs')
292 debugger.HandleCommand('command script add -f heap.malloc_info malloc_info')
293 print '"ptr_refs", "cstr_refs", and "malloc_info" commands have been installed, use the "--help" options on these commands for detailed help.'
Greg Claytone93e24f2012-04-11 16:27:06 +0000294
295
296
297