blob: 27f27811cc2e410c42ca810eb5e2ce582fda5a7c [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()
23
Greg Claytonb403a152012-04-21 00:11:26 +000024def load_dylib():
25 if lldb.target:
Greg Claytond712ef02012-04-25 18:40:20 +000026 global g_libheap_dylib_dir
27 global g_libheap_dylib_dict
28 triple = lldb.target.triple
Greg Clayton4f76fef2012-04-25 21:23:07 +000029 if triple in g_libheap_dylib_dict:
30 libheap_dylib_path = g_libheap_dylib_dict[triple]
31 else:
Greg Claytond712ef02012-04-25 18:40:20 +000032 if not g_libheap_dylib_dir:
Greg Clayton4f76fef2012-04-25 21:23:07 +000033 g_libheap_dylib_dir = tempfile.gettempdir() + '/lldb-dylibs'
34 triple_dir = g_libheap_dylib_dir + '/' + triple + '/' + __name__
Greg Claytond712ef02012-04-25 18:40:20 +000035 if not os.path.exists(triple_dir):
Greg Clayton4f76fef2012-04-25 21:23:07 +000036 os.makedirs(triple_dir)
Greg Claytond712ef02012-04-25 18:40:20 +000037 libheap_dylib_path = triple_dir + '/libheap.dylib'
38 g_libheap_dylib_dict[triple] = libheap_dylib_path
Greg Clayton4f76fef2012-04-25 21:23:07 +000039 heap_code_directory = os.path.dirname(__file__) + '/heap'
40 heap_source_file = heap_code_directory + '/heap_find.cpp'
41 # Check if the dylib doesn't exist, or if "heap_find.cpp" is newer than the dylib
42 if not os.path.exists(libheap_dylib_path) or os.stat(heap_source_file).st_mtime > os.stat(libheap_dylib_path).st_mtime:
43 # Remake the dylib
Greg Claytond712ef02012-04-25 18:40:20 +000044 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 +000045 # print make_command
Greg Claytond712ef02012-04-25 18:40:20 +000046 make_output = commands.getoutput(make_command)
Greg Clayton4f76fef2012-04-25 21:23:07 +000047 # print make_output
Greg Claytonb403a152012-04-21 00:11:26 +000048 if os.path.exists(libheap_dylib_path):
49 libheap_dylib_spec = lldb.SBFileSpec(libheap_dylib_path)
50 if lldb.target.FindModule(libheap_dylib_spec):
51 return None # success, 'libheap.dylib' already loaded
52 if lldb.process:
53 state = lldb.process.state
54 if state == lldb.eStateStopped:
55 (libheap_dylib_path)
56 error = lldb.SBError()
57 image_idx = lldb.process.LoadImage(libheap_dylib_spec, error)
58 if error.Success():
59 return None
60 else:
61 if error:
62 return 'error: %s' % error
63 else:
64 return 'error: "process load \'%s\'" failed' % libheap_dylib_spec
65 else:
66 return 'error: process is not stopped'
67 else:
68 return 'error: invalid process'
69 else:
70 return 'error: file does not exist "%s"' % libheap_dylib_path
71 else:
72 return 'error: invalid target'
73
74 debugger.HandleCommand('process load "%s"' % libheap_dylib_path)
75
Greg Claytond84bb482012-04-13 16:24:09 +000076def add_common_options(parser):
77 parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False)
78 parser.add_option('-o', '--po', action='store_true', dest='print_object_description', help='print the object descriptions for any matches', default=False)
79 parser.add_option('-m', '--memory', action='store_true', dest='memory', help='dump the memory for each matching block', default=False)
80 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 +000081 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)
82 #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 Claytond84bb482012-04-13 16:24:09 +000083
Greg Clayton7fb671b2012-04-11 18:30:53 +000084def heap_search(options, arg_str):
Greg Claytonb403a152012-04-21 00:11:26 +000085 dylid_load_err = load_dylib()
86 if dylid_load_err:
87 print dylid_load_err
88 return
Greg Clayton7fb671b2012-04-11 18:30:53 +000089 expr = None
Greg Clayton77677162012-04-12 18:57:36 +000090 arg_str_description = arg_str
Greg Claytond84bb482012-04-13 16:24:09 +000091 default_memory_format = "Y" # 'Y' is "bytes with ASCII" format
92 #memory_chunk_size = 1
Greg Clayton7fb671b2012-04-11 18:30:53 +000093 if options.type == 'pointer':
Greg Claytond712ef02012-04-25 18:40:20 +000094 expr = 'find_pointer_in_heap((void *)%s)' % (arg_str)
Greg Clayton77677162012-04-12 18:57:36 +000095 arg_str_description = 'malloc block containing pointer %s' % arg_str
Greg Claytond84bb482012-04-13 16:24:09 +000096 default_memory_format = "A" # 'A' is "address" format
97 #memory_chunk_size = lldb.process.GetAddressByteSize()
Greg Clayton7fb671b2012-04-11 18:30:53 +000098 elif options.type == 'cstr':
99 expr = 'find_cstring_in_heap("%s")' % arg_str
Greg Clayton77677162012-04-12 18:57:36 +0000100 arg_str_description = 'malloc block containing "%s"' % arg_str
101 elif options.type == 'addr':
Greg Clayton1bcb26c2012-04-12 21:06:22 +0000102 expr = 'find_block_for_address((void *)%s)' % arg_str
Greg Clayton77677162012-04-12 18:57:36 +0000103 arg_str_description = 'malloc block for %s' % arg_str
Greg Clayton7fb671b2012-04-11 18:30:53 +0000104 else:
105 print 'error: invalid type "%s"\nvalid values are "pointer", "cstr"' % options.type
106 return
107
108 expr_sbvalue = lldb.frame.EvaluateExpression (expr)
109 if expr_sbvalue.error.Success():
110 if expr_sbvalue.unsigned:
111 match_value = lldb.value(expr_sbvalue)
112 i = 0
113 while 1:
114 match_entry = match_value[i]; i += 1
115 malloc_addr = match_entry.addr.sbvalue.unsigned
116 if malloc_addr == 0:
117 break
118 malloc_size = int(match_entry.size)
119 offset = int(match_entry.offset)
120 dynamic_value = match_entry.addr.sbvalue.GetDynamicValue(lldb.eDynamicCanRunTarget)
121 # If the type is still 'void *' then we weren't able to figure
122 # out a dynamic type for the malloc_addr
123 type_name = dynamic_value.type.name
Greg Clayton77677162012-04-12 18:57:36 +0000124 description = '[%u] %s: addr = 0x%x' % (i, arg_str_description, malloc_addr)
125 if offset != 0:
126 description += ' + %u' % (offset)
127 description += ', size = %u' % (malloc_size)
Greg Clayton7fb671b2012-04-11 18:30:53 +0000128 if type_name == 'void *':
129 if options.type == 'pointer' and malloc_size == 4096:
130 error = lldb.SBError()
131 data = bytearray(lldb.process.ReadMemory(malloc_addr, 16, error))
132 if data == '\xa1\xa1\xa1\xa1AUTORELEASE!':
Greg Clayton77677162012-04-12 18:57:36 +0000133 description += ', type = (AUTORELEASE!)'
Greg Claytond84bb482012-04-13 16:24:09 +0000134 print description
Greg Clayton77677162012-04-12 18:57:36 +0000135 else:
136 description += ', type = %s' % (type_name)
137 derefed_dynamic_value = dynamic_value.deref
138 ivar_member = None
139 if derefed_dynamic_value:
140 derefed_dynamic_type = derefed_dynamic_value.type
141 member = derefed_dynamic_type.GetFieldAtIndex(0)
142 search_bases = False
143 if member:
144 if member.GetOffsetInBytes() <= offset:
145 for field_idx in range (derefed_dynamic_type.GetNumberOfFields()):
146 member = derefed_dynamic_type.GetFieldAtIndex(field_idx)
147 member_byte_offset = member.GetOffsetInBytes()
148 if member_byte_offset == offset:
149 ivar_member = member
150 break
151 else:
152 search_bases = True
Greg Clayton7fb671b2012-04-11 18:30:53 +0000153 else:
154 search_bases = True
Greg Clayton7fb671b2012-04-11 18:30:53 +0000155
Greg Clayton77677162012-04-12 18:57:36 +0000156 if not ivar_member and search_bases:
157 for field_idx in range (derefed_dynamic_type.GetNumberOfDirectBaseClasses()):
158 member = derefed_dynamic_type.GetDirectBaseClassAtIndex(field_idx)
Greg Clayton7fb671b2012-04-11 18:30:53 +0000159 member_byte_offset = member.GetOffsetInBytes()
160 if member_byte_offset == offset:
161 ivar_member = member
162 break
Greg Clayton77677162012-04-12 18:57:36 +0000163 if not ivar_member:
164 for field_idx in range (derefed_dynamic_type.GetNumberOfVirtualBaseClasses()):
165 member = derefed_dynamic_type.GetVirtualBaseClassAtIndex(field_idx)
166 member_byte_offset = member.GetOffsetInBytes()
167 if member_byte_offset == offset:
168 ivar_member = member
169 break
Greg Clayton7fb671b2012-04-11 18:30:53 +0000170 if ivar_member:
Greg Clayton77677162012-04-12 18:57:36 +0000171 description +=', ivar = %s' % (ivar_member.name)
172
173 print description
174 if derefed_dynamic_value:
175 print derefed_dynamic_value
176 if options.print_object_description:
177 desc = dynamic_value.GetObjectDescription()
178 if desc:
179 print ' (%s) 0x%x %s\n' % (type_name, malloc_addr, desc)
Greg Claytond84bb482012-04-13 16:24:09 +0000180 if options.memory:
181 memory_format = options.format
182 if not memory_format:
183 memory_format = default_memory_format
184 cmd_result = lldb.SBCommandReturnObject()
185 #count = malloc_size / memory_chunk_size
186 memory_command = "memory read -f %s 0x%x 0x%x" % (memory_format, malloc_addr, malloc_addr + malloc_size)
187 lldb.debugger.GetCommandInterpreter().HandleCommand(memory_command, cmd_result)
188 print cmd_result.GetOutput()
Greg Claytonb403a152012-04-21 00:11:26 +0000189 if options.stack:
Greg Claytoned3eee62012-04-25 01:49:50 +0000190 symbolicator = lldb.utils.symbolication.Symbolicator()
Greg Claytonb403a152012-04-21 00:11:26 +0000191 symbolicator.target = lldb.target
192 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)
193 #print expr_str
194 expr = lldb.frame.EvaluateExpression (expr_str);
195 expr_error = expr.GetError()
196 if expr_error.Success():
197 err = expr.unsigned
198 if err:
199 print 'error: __mach_stack_logging_get_frames() returned error %i' % (err)
200 else:
201 count_expr = lldb.frame.EvaluateExpression ("g_stack_frames_count")
202 count = count_expr.unsigned
203 #print 'g_stack_frames_count is %u' % (count)
204 if count > 0:
205 frame_idx = 0
206 frames_expr = lldb.value(lldb.frame.EvaluateExpression ("g_stack_frames"))
207 done = False
208 for stack_frame_idx in range(count):
209 if not done:
210 frame_load_addr = int(frames_expr[stack_frame_idx])
211 if frame_load_addr >= 0x1000:
212 frames = symbolicator.symbolicate(frame_load_addr)
213 if frames:
214 for frame in frames:
215 print '[%3u] %s' % (frame_idx, frame)
216 frame_idx += 1
217 else:
218 print '[%3u] 0x%x' % (frame_idx, frame_load_addr)
219 frame_idx += 1
220 else:
221 done = True
222 else:
223 print 'error: %s' % (expr_error)
Greg Clayton7fb671b2012-04-11 18:30:53 +0000224 else:
225 print '%s %s was not found in any malloc blocks' % (options.type, arg_str)
226 else:
Greg Clayton77677162012-04-12 18:57:36 +0000227 print expr_sbvalue.error
228 print
Greg Clayton7fb671b2012-04-11 18:30:53 +0000229
Greg Clayton77677162012-04-12 18:57:36 +0000230def ptr_refs(debugger, command, result, dict):
Greg Clayton804de012012-04-11 16:27:06 +0000231 command_args = shlex.split(command)
Greg Clayton77677162012-04-12 18:57:36 +0000232 usage = "usage: %prog [options] <PTR> [PTR ...]"
Greg Clayton7fb671b2012-04-11 18:30:53 +0000233 description='''Searches the heap for pointer references on darwin user space programs.
234
235 Any matches that were found will dump the malloc blocks that contain the pointers
236 and might be able to print what kind of objects the pointers are contained in using
Greg Clayton77677162012-04-12 18:57:36 +0000237 dynamic type information in the program.'''
238 parser = optparse.OptionParser(description=description, prog='ptr_refs',usage=usage)
Greg Claytond84bb482012-04-13 16:24:09 +0000239 add_common_options(parser)
Greg Clayton804de012012-04-11 16:27:06 +0000240 try:
241 (options, args) = parser.parse_args(command_args)
242 except:
243 return
Greg Clayton7fb671b2012-04-11 18:30:53 +0000244
245 options.type = 'pointer'
Greg Clayton804de012012-04-11 16:27:06 +0000246
247 if args:
248
249 for data in args:
Greg Clayton7fb671b2012-04-11 18:30:53 +0000250 heap_search (options, data)
Greg Clayton804de012012-04-11 16:27:06 +0000251 else:
Greg Clayton7fb671b2012-04-11 18:30:53 +0000252 print 'error: no pointer arguments were given'
Greg Clayton804de012012-04-11 16:27:06 +0000253
Greg Clayton77677162012-04-12 18:57:36 +0000254def cstr_refs(debugger, command, result, dict):
Greg Clayton7fb671b2012-04-11 18:30:53 +0000255 command_args = shlex.split(command)
Greg Clayton77677162012-04-12 18:57:36 +0000256 usage = "usage: %prog [options] <CSTR> [CSTR ...]"
Greg Clayton7fb671b2012-04-11 18:30:53 +0000257 description='''Searches the heap for C string references on darwin user space programs.
258
259 Any matches that were found will dump the malloc blocks that contain the C strings
260 and might be able to print what kind of objects the pointers are contained in using
Greg Clayton77677162012-04-12 18:57:36 +0000261 dynamic type information in the program.'''
262 parser = optparse.OptionParser(description=description, prog='cstr_refs',usage=usage)
Greg Claytond84bb482012-04-13 16:24:09 +0000263 add_common_options(parser)
Greg Clayton7fb671b2012-04-11 18:30:53 +0000264 try:
265 (options, args) = parser.parse_args(command_args)
266 except:
267 return
268
269 options.type = 'cstr'
270
271 if args:
272
273 for data in args:
274 heap_search (options, data)
275 else:
276 print 'error: no c string arguments were given to search for'
Greg Clayton804de012012-04-11 16:27:06 +0000277
Greg Clayton77677162012-04-12 18:57:36 +0000278def malloc_info(debugger, command, result, dict):
279 command_args = shlex.split(command)
280 usage = "usage: %prog [options] <ADDR> [ADDR ...]"
281 description='''Searches the heap a malloc block that contains the addresses specified as arguments.
282
283 Any matches that were found will dump the malloc blocks that match or contain
284 the specified address. The matching blocks might be able to show what kind
285 of objects they are using dynamic type information in the program.'''
286 parser = optparse.OptionParser(description=description, prog='cstr_refs',usage=usage)
Greg Claytond84bb482012-04-13 16:24:09 +0000287 add_common_options(parser)
Greg Clayton77677162012-04-12 18:57:36 +0000288 try:
289 (options, args) = parser.parse_args(command_args)
290 except:
291 return
292
293 options.type = 'addr'
294
295 if args:
296
297 for data in args:
298 heap_search (options, data)
299 else:
300 print 'error: no c string arguments were given to search for'
301
Greg Claytond712ef02012-04-25 18:40:20 +0000302if __name__ == '__main__':
303 lldb.debugger = lldb.SBDebugger.Create()
304
305# This initializer is being run from LLDB in the embedded command interpreter
306# Add any commands contained in this module to LLDB
307lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.ptr_refs ptr_refs')
308lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.cstr_refs cstr_refs')
309lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.malloc_info malloc_info')
310print '"ptr_refs", "cstr_refs", and "malloc_info" commands have been installed, use the "--help" options on these commands for detailed help.'
Greg Clayton804de012012-04-11 16:27:06 +0000311
312
313
314