blob: 8aed86aab0a0394b77f3384d7a87256cd041ef48 [file] [log] [blame]
Greg Claytone93e24f2012-04-11 16:27:06 +00001#!/usr/bin/python
2
3#----------------------------------------------------------------------
Greg Clayton1dae6f32012-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 Claytone93e24f2012-04-11 16:27:06 +00007#
Greg Clayton1dae6f32012-04-25 18:40:20 +00008# (lldb) script import lldb.macosx.heap
Greg Claytone93e24f2012-04-11 16:27:06 +00009#----------------------------------------------------------------------
10
11import lldb
12import commands
13import optparse
Greg Clayton96666442012-04-11 18:30:53 +000014import os
Greg Clayton1dae6f32012-04-25 18:40:20 +000015import os.path
Greg Clayton4c5c4292012-07-11 22:13:18 +000016import re
Greg Claytone93e24f2012-04-11 16:27:06 +000017import shlex
Greg Clayton1dae6f32012-04-25 18:40:20 +000018import string
19import tempfile
Greg Clayton6f2f0ab2012-04-25 01:49:50 +000020import lldb.utils.symbolication
Greg Claytone93e24f2012-04-11 16:27:06 +000021
Greg Clayton1dae6f32012-04-25 18:40:20 +000022g_libheap_dylib_dir = None
23g_libheap_dylib_dict = dict()
Greg Claytonbf479652012-05-11 02:42:36 +000024g_verbose = False
Greg Clayton1dae6f32012-04-25 18:40:20 +000025
Greg Clayton9098fee2012-04-21 00:11:26 +000026def load_dylib():
27 if lldb.target:
Greg Clayton1dae6f32012-04-25 18:40:20 +000028 global g_libheap_dylib_dir
29 global g_libheap_dylib_dict
30 triple = lldb.target.triple
Greg Clayton3e339792012-04-25 21:23:07 +000031 if triple in g_libheap_dylib_dict:
32 libheap_dylib_path = g_libheap_dylib_dict[triple]
33 else:
Greg Clayton1dae6f32012-04-25 18:40:20 +000034 if not g_libheap_dylib_dir:
Greg Clayton3e339792012-04-25 21:23:07 +000035 g_libheap_dylib_dir = tempfile.gettempdir() + '/lldb-dylibs'
36 triple_dir = g_libheap_dylib_dir + '/' + triple + '/' + __name__
Greg Clayton1dae6f32012-04-25 18:40:20 +000037 if not os.path.exists(triple_dir):
Greg Clayton3e339792012-04-25 21:23:07 +000038 os.makedirs(triple_dir)
Greg Clayton1dae6f32012-04-25 18:40:20 +000039 libheap_dylib_path = triple_dir + '/libheap.dylib'
40 g_libheap_dylib_dict[triple] = libheap_dylib_path
Greg Clayton3e339792012-04-25 21:23:07 +000041 heap_code_directory = os.path.dirname(__file__) + '/heap'
42 heap_source_file = heap_code_directory + '/heap_find.cpp'
43 # Check if the dylib doesn't exist, or if "heap_find.cpp" is newer than the dylib
44 if not os.path.exists(libheap_dylib_path) or os.stat(heap_source_file).st_mtime > os.stat(libheap_dylib_path).st_mtime:
45 # Remake the dylib
Greg Clayton1dae6f32012-04-25 18:40:20 +000046 make_command = '(cd "%s" ; make EXE="%s" ARCH=%s)' % (heap_code_directory, libheap_dylib_path, string.split(triple, '-')[0])
Greg Clayton0cae0632012-06-27 19:57:59 +000047 (make_exit_status, make_output) = commands.getstatusoutput(make_command)
48 if make_exit_status != 0:
Greg Clayton85df60c2012-09-01 00:34:35 +000049 return 'error: make failed: %s' % (make_output)
Greg Clayton9098fee2012-04-21 00:11:26 +000050 if os.path.exists(libheap_dylib_path):
51 libheap_dylib_spec = lldb.SBFileSpec(libheap_dylib_path)
52 if lldb.target.FindModule(libheap_dylib_spec):
53 return None # success, 'libheap.dylib' already loaded
54 if lldb.process:
55 state = lldb.process.state
56 if state == lldb.eStateStopped:
57 (libheap_dylib_path)
58 error = lldb.SBError()
59 image_idx = lldb.process.LoadImage(libheap_dylib_spec, error)
60 if error.Success():
61 return None
62 else:
63 if error:
64 return 'error: %s' % error
65 else:
66 return 'error: "process load \'%s\'" failed' % libheap_dylib_spec
67 else:
68 return 'error: process is not stopped'
69 else:
70 return 'error: invalid process'
71 else:
72 return 'error: file does not exist "%s"' % libheap_dylib_path
73 else:
74 return 'error: invalid target'
75
76 debugger.HandleCommand('process load "%s"' % libheap_dylib_path)
Greg Claytonbf479652012-05-11 02:42:36 +000077 if lldb.target.FindModule(libheap_dylib_spec):
78 return None # success, 'libheap.dylib' already loaded
79 return 'error: failed to load "%s"' % libheap_dylib_path
Greg Clayton0d0f56d2012-07-07 01:22:45 +000080
81def get_member_types_for_offset(value_type, offset, member_list):
82 member = value_type.GetFieldAtIndex(0)
83 search_bases = False
84 if member:
85 if member.GetOffsetInBytes() <= offset:
86 for field_idx in range (value_type.GetNumberOfFields()):
87 member = value_type.GetFieldAtIndex(field_idx)
88 member_byte_offset = member.GetOffsetInBytes()
89 member_end_byte_offset = member_byte_offset + member.type.size
90 if member_byte_offset <= offset and offset < member_end_byte_offset:
91 member_list.append(member)
92 get_member_types_for_offset (member.type, offset - member_byte_offset, member_list)
93 return
94 else:
95 search_bases = True
96 else:
97 search_bases = True
98 if search_bases:
99 for field_idx in range (value_type.GetNumberOfDirectBaseClasses()):
100 member = value_type.GetDirectBaseClassAtIndex(field_idx)
101 member_byte_offset = member.GetOffsetInBytes()
102 member_end_byte_offset = member_byte_offset + member.type.size
103 if member_byte_offset <= offset and offset < member_end_byte_offset:
104 member_list.append(member)
105 get_member_types_for_offset (member.type, offset - member_byte_offset, member_list)
106 return
107 for field_idx in range (value_type.GetNumberOfVirtualBaseClasses()):
108 member = value_type.GetVirtualBaseClassAtIndex(field_idx)
109 member_byte_offset = member.GetOffsetInBytes()
110 member_end_byte_offset = member_byte_offset + member.type.size
111 if member_byte_offset <= offset and offset < member_end_byte_offset:
112 member_list.append(member)
113 get_member_types_for_offset (member.type, offset - member_byte_offset, member_list)
114 return
Greg Clayton4c5c4292012-07-11 22:13:18 +0000115
116def append_regex_callback(option, opt, value, parser):
117 try:
118 ivar_regex = re.compile(value)
119 parser.values.ivar_regex_blacklist.append(ivar_regex)
120 except:
121 print 'error: an exception was thrown when compiling the ivar regular expression for "%s"' % value
Greg Clayton9098fee2012-04-21 00:11:26 +0000122
Greg Clayton93e5ba52012-04-13 16:24:09 +0000123def add_common_options(parser):
124 parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000125 parser.add_option('-t', '--type', action='store_true', dest='print_type', help='print the full value of the type for each matching malloc block', default=False)
Greg Clayton93e5ba52012-04-13 16:24:09 +0000126 parser.add_option('-o', '--po', action='store_true', dest='print_object_description', help='print the object descriptions for any matches', default=False)
127 parser.add_option('-m', '--memory', action='store_true', dest='memory', help='dump the memory for each matching block', default=False)
128 parser.add_option('-f', '--format', type='string', dest='format', help='the format to use when dumping memory if --memory is specified', default=None)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000129 parser.add_option('-I', '--omit-ivar-regex', type='string', action='callback', callback=append_regex_callback, dest='ivar_regex_blacklist', default=[], help='specify one or more regular expressions used to backlist any matches that are in ivars')
Greg Clayton9098fee2012-04-21 00:11:26 +0000130 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 Clayton7a245762012-05-10 23:17:28 +0000131 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 Clayton4c5c4292012-07-11 22:13:18 +0000132 parser.add_option('-M', '--max-matches', type='int', dest='max_matches', help='the maximum number of matches to print', default=256)
Greg Claytonab20f292012-08-11 02:26:26 +0000133 parser.add_option('-O', '--offset', type='int', dest='offset', help='the matching data must be at this offset', default=-1)
Greg Clayton7a245762012-05-10 23:17:28 +0000134
Greg Clayton85df60c2012-09-01 00:34:35 +0000135def dump_stack_history_entry(result, stack_history_entry, idx):
Greg Clayton6f446f32012-05-10 23:37:52 +0000136 address = int(stack_history_entry.address)
137 if address:
138 type_flags = int(stack_history_entry.type_flags)
Greg Clayton7a245762012-05-10 23:17:28 +0000139 symbolicator = lldb.utils.symbolication.Symbolicator()
140 symbolicator.target = lldb.target
Greg Claytonbf479652012-05-11 02:42:36 +0000141 type_str = ''
142 if type_flags == 0:
143 type_str = 'free'
144 else:
145 if type_flags & 2:
146 type_str = 'alloc'
147 elif type_flags & 4:
148 type_str = 'free'
149 elif type_flags & 1:
150 type_str = 'generic'
151 else:
152 type_str = hex(type_flags)
Greg Clayton85df60c2012-09-01 00:34:35 +0000153 result.AppendMessage('stack[%u]: addr = 0x%x, type=%s, frames:' % (idx, address, type_str))
Greg Clayton7a245762012-05-10 23:17:28 +0000154 frame_idx = 0
Greg Clayton6f446f32012-05-10 23:37:52 +0000155 idx = 0
156 pc = int(stack_history_entry.frames[idx])
Greg Clayton7a245762012-05-10 23:17:28 +0000157 while pc != 0:
158 if pc >= 0x1000:
159 frames = symbolicator.symbolicate(pc)
160 if frames:
161 for frame in frames:
Greg Clayton85df60c2012-09-01 00:34:35 +0000162 result.AppendMessage(' [%u] %s' % (frame_idx, frame))
Greg Clayton7a245762012-05-10 23:17:28 +0000163 frame_idx += 1
164 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000165 result.AppendMessage(' [%u] 0x%x' % (frame_idx, pc))
Greg Clayton7a245762012-05-10 23:17:28 +0000166 frame_idx += 1
Greg Clayton6f446f32012-05-10 23:37:52 +0000167 idx = idx + 1
168 pc = int(stack_history_entry.frames[idx])
Greg Clayton7a245762012-05-10 23:17:28 +0000169 else:
170 pc = 0
Greg Clayton85df60c2012-09-01 00:34:35 +0000171 result.AppendMessage('')
Greg Clayton7a245762012-05-10 23:17:28 +0000172
Greg Clayton85df60c2012-09-01 00:34:35 +0000173def dump_stack_history_entries(result, addr, history):
Greg Clayton7a245762012-05-10 23:17:28 +0000174 # malloc_stack_entry *get_stack_history_for_address (const void * addr)
Greg Claytonbf479652012-05-11 02:42:36 +0000175 expr = 'get_stack_history_for_address((void *)0x%x, %u)' % (addr, history)
Greg Clayton7a245762012-05-10 23:17:28 +0000176 expr_sbvalue = lldb.frame.EvaluateExpression (expr)
177 if expr_sbvalue.error.Success():
178 if expr_sbvalue.unsigned:
179 expr_value = lldb.value(expr_sbvalue)
180 idx = 0;
181 stack_history_entry = expr_value[idx]
Greg Clayton6f446f32012-05-10 23:37:52 +0000182 while int(stack_history_entry.address) != 0:
Greg Clayton85df60c2012-09-01 00:34:35 +0000183 dump_stack_history_entry(result, stack_history_entry, idx)
Greg Clayton7a245762012-05-10 23:17:28 +0000184 idx = idx + 1
185 stack_history_entry = expr_value[idx]
Greg Clayton85df60c2012-09-01 00:34:35 +0000186 else:
187 result.AppendMessage('"%s" returned zero' % (expr))
Greg Claytonbf479652012-05-11 02:42:36 +0000188 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000189 result.AppendMessage('error: expression failed "%s" => %s' % (expr, expr_sbvalue.error))
Greg Clayton7a245762012-05-10 23:17:28 +0000190
Greg Clayton4c5c4292012-07-11 22:13:18 +0000191
Greg Clayton85df60c2012-09-01 00:34:35 +0000192def display_match_results (result, options, arg_str_description, expr_sbvalue, print_no_matches = True):
Greg Clayton96666442012-04-11 18:30:53 +0000193 if expr_sbvalue.error.Success():
194 if expr_sbvalue.unsigned:
195 match_value = lldb.value(expr_sbvalue)
196 i = 0
Greg Claytonab20f292012-08-11 02:26:26 +0000197 match_idx = 0
Greg Clayton96666442012-04-11 18:30:53 +0000198 while 1:
Greg Clayton4c5c4292012-07-11 22:13:18 +0000199 print_entry = True
Greg Clayton96666442012-04-11 18:30:53 +0000200 match_entry = match_value[i]; i += 1
Greg Clayton4c5c4292012-07-11 22:13:18 +0000201 if i >= options.max_matches:
Greg Clayton85df60c2012-09-01 00:34:35 +0000202 result.AppendMessage('error: the max number of matches (%u) was reached, use the --max-matches option to get more results' % (options.max_matches))
Greg Clayton4c5c4292012-07-11 22:13:18 +0000203 break
Greg Clayton96666442012-04-11 18:30:53 +0000204 malloc_addr = match_entry.addr.sbvalue.unsigned
205 if malloc_addr == 0:
206 break
207 malloc_size = int(match_entry.size)
208 offset = int(match_entry.offset)
Greg Claytonab20f292012-08-11 02:26:26 +0000209
210 if options.offset >= 0 and options.offset != offset:
211 print_entry = False
212 else:
213 match_addr = malloc_addr + offset
214 dynamic_value = match_entry.addr.sbvalue.GetDynamicValue(lldb.eDynamicCanRunTarget)
215 description = '[%u] %s: addr = 0x%x' % (match_idx, arg_str_description, malloc_addr)
216 if offset != 0:
217 description += ' + %u' % (offset)
218 description += ', size = %u' % (malloc_size)
219 derefed_dynamic_value = None
220 if dynamic_value.type.name == 'void *':
221 if options.type == 'pointer' and malloc_size == 4096:
222 error = lldb.SBError()
223 data = bytearray(lldb.process.ReadMemory(malloc_addr, 16, error))
224 if data == '\xa1\xa1\xa1\xa1AUTORELEASE!':
225 description += ', type = (AUTORELEASE!)'
226 else:
227 derefed_dynamic_value = dynamic_value.deref
228 if derefed_dynamic_value:
229 derefed_dynamic_type = derefed_dynamic_value.type
230 derefed_dynamic_type_size = derefed_dynamic_type.size
231 derefed_dynamic_type_name = derefed_dynamic_type.name
232 description += ', type = %s <%u>' % (derefed_dynamic_type_name, derefed_dynamic_type_size)
233 if offset < derefed_dynamic_type_size:
234 member_list = list();
235 get_member_types_for_offset (derefed_dynamic_type, offset, member_list)
236 if member_list:
237 member_path = ''
238 for member in member_list:
239 member_name = member.name
240 if member_name:
241 if member_path:
242 member_path += '.'
243 member_path += member_name
244 if member_path:
245 if options.ivar_regex_blacklist:
246 for ivar_regex in options.ivar_regex_blacklist:
247 if ivar_regex.match(member_path):
248 print_entry = False
249 description += ', ivar = %s' % (member_path)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000250 if print_entry:
Greg Claytonab20f292012-08-11 02:26:26 +0000251 match_idx += 1
Greg Claytonaaf7fad2012-09-04 14:09:21 +0000252 result_output = ''
Greg Clayton4c5c4292012-07-11 22:13:18 +0000253 if description:
Greg Claytonaaf7fad2012-09-04 14:09:21 +0000254 result_output += description
Greg Clayton4c5c4292012-07-11 22:13:18 +0000255 if options.print_type and derefed_dynamic_value:
Greg Claytonaaf7fad2012-09-04 14:09:21 +0000256 result_output += '%s' % (derefed_dynamic_value)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000257 if options.print_object_description and dynamic_value:
258 desc = dynamic_value.GetObjectDescription()
259 if desc:
Greg Claytonaaf7fad2012-09-04 14:09:21 +0000260 result_output += ', po=%s' % (desc)
261 if result_output:
262 result.AppendMessage(result_output)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000263 if options.memory:
264 cmd_result = lldb.SBCommandReturnObject()
265 memory_command = "memory read -f %s 0x%x 0x%x" % (options.format, malloc_addr, malloc_addr + malloc_size)
266 lldb.debugger.GetCommandInterpreter().HandleCommand(memory_command, cmd_result)
Greg Clayton85df60c2012-09-01 00:34:35 +0000267 result.AppendMessage(cmd_result.GetOutput())
Greg Clayton4c5c4292012-07-11 22:13:18 +0000268 if options.stack_history:
Greg Clayton85df60c2012-09-01 00:34:35 +0000269 dump_stack_history_entries(result, malloc_addr, 1)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000270 elif options.stack:
Greg Clayton85df60c2012-09-01 00:34:35 +0000271 dump_stack_history_entries(result, malloc_addr, 0)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000272 return i
273 elif print_no_matches:
Greg Clayton85df60c2012-09-01 00:34:35 +0000274 result.AppendMessage('no matches found for %s' % (arg_str_description))
Greg Clayton96666442012-04-11 18:30:53 +0000275 else:
Greg Claytonaaf7fad2012-09-04 14:09:21 +0000276 result.AppendMessage(str(expr_sbvalue.error))
Greg Clayton4c5c4292012-07-11 22:13:18 +0000277 return 0
278
Greg Clayton85df60c2012-09-01 00:34:35 +0000279def heap_search(result, options, arg_str):
Greg Clayton4c5c4292012-07-11 22:13:18 +0000280 dylid_load_err = load_dylib()
281 if dylid_load_err:
Greg Clayton85df60c2012-09-01 00:34:35 +0000282 result.AppendMessage(dylid_load_err)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000283 return
284 expr = None
Greg Clayton393fc5f2012-09-11 18:10:27 +0000285 print_no_matches = True
Greg Clayton4c5c4292012-07-11 22:13:18 +0000286 arg_str_description = arg_str
Greg Clayton4c5c4292012-07-11 22:13:18 +0000287 if options.type == 'pointer':
288 expr = 'find_pointer_in_heap((void *)%s)' % (arg_str)
289 arg_str_description = 'malloc block containing pointer %s' % arg_str
290 if options.format == None:
291 options.format = "A" # 'A' is "address" format
Greg Claytonab20f292012-08-11 02:26:26 +0000292 elif options.type == 'isa':
Greg Claytonaaf7fad2012-09-04 14:09:21 +0000293 expr = 'find_objc_objects_in_memory ((void *)%s)' % (arg_str)
294 #result.AppendMessage ('expr -u0 -- %s' % expr) # REMOVE THIS LINE
Greg Claytonab20f292012-08-11 02:26:26 +0000295 arg_str_description = 'objective C classes with isa %s' % arg_str
296 options.offset = 0
297 if options.format == None:
298 options.format = "A" # 'A' is "address" format
Greg Clayton4c5c4292012-07-11 22:13:18 +0000299 elif options.type == 'cstr':
300 expr = 'find_cstring_in_heap("%s")' % arg_str
301 arg_str_description = 'malloc block containing "%s"' % arg_str
302 elif options.type == 'addr':
303 expr = 'find_block_for_address((void *)%s)' % arg_str
304 arg_str_description = 'malloc block for %s' % arg_str
Greg Clayton393fc5f2012-09-11 18:10:27 +0000305 elif options.type == 'all':
306 expr = 'get_heap_info(1)'
307 arg_str_description = None
308 print_no_matches = False
Greg Clayton4c5c4292012-07-11 22:13:18 +0000309 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000310 result.AppendMessage('error: invalid type "%s"\nvalid values are "pointer", "cstr"' % options.type)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000311 return
Greg Clayton85df60c2012-09-01 00:34:35 +0000312 if options.format == None:
313 options.format = "Y" # 'Y' is "bytes with ASCII" format
Greg Clayton4c5c4292012-07-11 22:13:18 +0000314
Greg Clayton85df60c2012-09-01 00:34:35 +0000315 display_match_results (result, options, arg_str_description, lldb.frame.EvaluateExpression (expr))
Greg Clayton96666442012-04-11 18:30:53 +0000316
Greg Claytonbff78412012-04-12 18:57:36 +0000317def ptr_refs(debugger, command, result, dict):
Greg Claytone93e24f2012-04-11 16:27:06 +0000318 command_args = shlex.split(command)
Greg Claytonbf479652012-05-11 02:42:36 +0000319 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
Greg Clayton96666442012-04-11 18:30:53 +0000320 description='''Searches the heap for pointer references on darwin user space programs.
321
322 Any matches that were found will dump the malloc blocks that contain the pointers
323 and might be able to print what kind of objects the pointers are contained in using
Greg Claytonbff78412012-04-12 18:57:36 +0000324 dynamic type information in the program.'''
325 parser = optparse.OptionParser(description=description, prog='ptr_refs',usage=usage)
Greg Clayton93e5ba52012-04-13 16:24:09 +0000326 add_common_options(parser)
Greg Claytone93e24f2012-04-11 16:27:06 +0000327 try:
328 (options, args) = parser.parse_args(command_args)
329 except:
330 return
Greg Clayton96666442012-04-11 18:30:53 +0000331
332 options.type = 'pointer'
Greg Claytone93e24f2012-04-11 16:27:06 +0000333
334 if args:
335
336 for data in args:
Greg Clayton85df60c2012-09-01 00:34:35 +0000337 heap_search (result, options, data)
Greg Claytone93e24f2012-04-11 16:27:06 +0000338 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000339 resultresult.AppendMessage('error: no pointer arguments were given')
Greg Claytone93e24f2012-04-11 16:27:06 +0000340
Greg Claytonbff78412012-04-12 18:57:36 +0000341def cstr_refs(debugger, command, result, dict):
Greg Clayton96666442012-04-11 18:30:53 +0000342 command_args = shlex.split(command)
Greg Claytonbff78412012-04-12 18:57:36 +0000343 usage = "usage: %prog [options] <CSTR> [CSTR ...]"
Greg Clayton96666442012-04-11 18:30:53 +0000344 description='''Searches the heap for C string references on darwin user space programs.
345
346 Any matches that were found will dump the malloc blocks that contain the C strings
347 and might be able to print what kind of objects the pointers are contained in using
Greg Claytonbff78412012-04-12 18:57:36 +0000348 dynamic type information in the program.'''
349 parser = optparse.OptionParser(description=description, prog='cstr_refs',usage=usage)
Greg Clayton93e5ba52012-04-13 16:24:09 +0000350 add_common_options(parser)
Greg Clayton96666442012-04-11 18:30:53 +0000351 try:
352 (options, args) = parser.parse_args(command_args)
353 except:
354 return
355
356 options.type = 'cstr'
357
358 if args:
359
360 for data in args:
Greg Clayton85df60c2012-09-01 00:34:35 +0000361 heap_search (result, options, data)
Greg Clayton96666442012-04-11 18:30:53 +0000362 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000363 result.AppendMessage('error: no c string arguments were given to search for');
Greg Claytone93e24f2012-04-11 16:27:06 +0000364
Greg Claytonbff78412012-04-12 18:57:36 +0000365def malloc_info(debugger, command, result, dict):
366 command_args = shlex.split(command)
Greg Claytonbf479652012-05-11 02:42:36 +0000367 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
Greg Claytonbff78412012-04-12 18:57:36 +0000368 description='''Searches the heap a malloc block that contains the addresses specified as arguments.
369
370 Any matches that were found will dump the malloc blocks that match or contain
371 the specified address. The matching blocks might be able to show what kind
372 of objects they are using dynamic type information in the program.'''
373 parser = optparse.OptionParser(description=description, prog='cstr_refs',usage=usage)
Greg Clayton93e5ba52012-04-13 16:24:09 +0000374 add_common_options(parser)
Greg Claytonbff78412012-04-12 18:57:36 +0000375 try:
376 (options, args) = parser.parse_args(command_args)
377 except:
378 return
Greg Claytonbff78412012-04-12 18:57:36 +0000379 options.type = 'addr'
Greg Claytonbff78412012-04-12 18:57:36 +0000380 if args:
Greg Claytonbff78412012-04-12 18:57:36 +0000381 for data in args:
Greg Clayton85df60c2012-09-01 00:34:35 +0000382 heap_search (result, options, data)
Greg Claytonbff78412012-04-12 18:57:36 +0000383 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000384 result.AppendMessage('error: no c string arguments were given to search for')
Greg Claytonbff78412012-04-12 18:57:36 +0000385
Greg Clayton393fc5f2012-09-11 18:10:27 +0000386def heap(debugger, command, result, dict):
Greg Claytonbf479652012-05-11 02:42:36 +0000387 command_args = shlex.split(command)
388 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
Greg Clayton393fc5f2012-09-11 18:10:27 +0000389 description='''Traverse all allocations on the heap and report statistics.
Greg Claytonbf479652012-05-11 02:42:36 +0000390
Greg Clayton393fc5f2012-09-11 18:10:27 +0000391 If programs set the MallocStackLogging=1 in the environment, then stack
392 history is available for any allocations. '''
393 parser = optparse.OptionParser(description=description, prog='cstr_refs',usage=usage)
394 add_common_options(parser)
395 try:
396 (options, args) = parser.parse_args(command_args)
397 except:
398 return
399 options.type = 'all'
400 if args:
401 result.AppendMessage('error: heap command takes no arguments, only options')
Greg Claytonbf479652012-05-11 02:42:36 +0000402 else:
Greg Clayton393fc5f2012-09-11 18:10:27 +0000403 heap_search (result, options, None)
Greg Claytonbf479652012-05-11 02:42:36 +0000404
Greg Clayton4c5c4292012-07-11 22:13:18 +0000405def section_ptr_refs(debugger, command, result, dict):
406 command_args = shlex.split(command)
407 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
408 description='''Searches section contents for pointer values in darwin user space programs.'''
409 parser = optparse.OptionParser(description=description, prog='section_ptr_refs',usage=usage)
410 add_common_options(parser)
411 parser.add_option('--section', action='append', type='string', dest='section_names', help='section name to search', default=list())
412 try:
413 (options, args) = parser.parse_args(command_args)
414 except:
415 return
416
417 options.type = 'pointer'
418
419 sections = list()
420 section_modules = list()
421 if not options.section_names:
Greg Clayton85df60c2012-09-01 00:34:35 +0000422 result.AppendMessage('error: at least one section must be specified with the --section option')
Greg Clayton4c5c4292012-07-11 22:13:18 +0000423 return
424
425 for module in lldb.target.modules:
426 for section_name in options.section_names:
427 section = module.section[section_name]
428 if section:
429 sections.append (section)
430 section_modules.append (module)
431 if sections:
432 dylid_load_err = load_dylib()
433 if dylid_load_err:
Greg Clayton85df60c2012-09-01 00:34:35 +0000434 result.AppendMessage(dylid_load_err)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000435 return
436 for expr_str in args:
437 for (idx, section) in enumerate(sections):
438 expr = 'find_pointer_in_memory(0x%xllu, %ullu, (void *)%s)' % (section.addr.load_addr, section.size, expr_str)
439 arg_str_description = 'section %s.%s containing "%s"' % (section_modules[idx].file.fullpath, section.name, expr_str)
Greg Clayton85df60c2012-09-01 00:34:35 +0000440 num_matches = display_match_results (result, options, arg_str_description, lldb.frame.EvaluateExpression (expr), False)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000441 if num_matches:
442 if num_matches < options.max_matches:
443 options.max_matches = options.max_matches - num_matches
444 else:
445 options.max_matches = 0
446 if options.max_matches == 0:
447 return
448 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000449 result.AppendMessage('error: no sections were found that match any of %s' % (', '.join(options.section_names)))
Greg Clayton4c5c4292012-07-11 22:13:18 +0000450
Greg Claytonab20f292012-08-11 02:26:26 +0000451def objc_refs(debugger, command, result, dict):
452 command_args = shlex.split(command)
453 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
454 description='''Find all heap allocations given one or more objective C class names.'''
455 parser = optparse.OptionParser(description=description, prog='object_refs',usage=usage)
456 add_common_options(parser)
457 try:
458 (options, args) = parser.parse_args(command_args)
459 except:
460 return
461
462 dylid_load_err = load_dylib()
463 if dylid_load_err:
Greg Clayton85df60c2012-09-01 00:34:35 +0000464 result.AppendMessage(dylid_load_err)
Greg Claytonab20f292012-08-11 02:26:26 +0000465 else:
466 if args:
467 for class_name in args:
468 addr_expr_str = "(void *)[%s class]" % class_name
469 expr_sbvalue = lldb.frame.EvaluateExpression (addr_expr_str)
470 if expr_sbvalue.error.Success():
471 isa = expr_sbvalue.unsigned
472 if isa:
473 options.type = 'isa'
Greg Claytona48bf372012-09-10 17:22:45 +0000474 result.AppendMessage('Searching for all instances of %s (isa=0x%x)' % (class_name, isa))
Greg Clayton85df60c2012-09-01 00:34:35 +0000475 heap_search (result, options, '0x%x' % isa)
Greg Claytonab20f292012-08-11 02:26:26 +0000476 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000477 result.AppendMessage('error: Can\'t find isa for an ObjC class named "%s"' % (class_name))
Greg Claytonab20f292012-08-11 02:26:26 +0000478 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000479 result.AppendMessage('error: expression error for "%s": %s' % (addr_expr_str, expr_sbvalue.error))
Greg Claytonab20f292012-08-11 02:26:26 +0000480 else:
Greg Claytonaaf7fad2012-09-04 14:09:21 +0000481 # Find all objective C objects by not specifying an isa
482 options.type = 'isa'
483 heap_search (result, options, '0x0')
Greg Claytonab20f292012-08-11 02:26:26 +0000484
Greg Clayton1dae6f32012-04-25 18:40:20 +0000485if __name__ == '__main__':
486 lldb.debugger = lldb.SBDebugger.Create()
487
488# This initializer is being run from LLDB in the embedded command interpreter
489# Add any commands contained in this module to LLDB
490lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.ptr_refs ptr_refs')
491lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.cstr_refs cstr_refs')
492lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.malloc_info malloc_info')
Greg Clayton393fc5f2012-09-11 18:10:27 +0000493lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.heap heap')
Greg Clayton4c5c4292012-07-11 22:13:18 +0000494lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.section_ptr_refs section_ptr_refs')
Greg Claytonab20f292012-08-11 02:26:26 +0000495lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.objc_refs objc_refs')
Greg Clayton393fc5f2012-09-11 18:10:27 +0000496print '"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.'
Greg Claytone93e24f2012-04-11 16:27:06 +0000497
498
499
500