blob: 0e59deb55f8d176cba5f67f64141a9bee7bb2afa [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)
Greg Claytona936c6e2012-09-12 02:02:32 +0000127 parser.add_option('-z', '--size', action='store_true', dest='show_size', help='print the allocation size in bytes', default=False)
128 parser.add_option('-r', '--range', action='store_true', dest='show_range', help='print the allocation address range instead of just the allocation base address', default=False)
Greg Clayton93e5ba52012-04-13 16:24:09 +0000129 parser.add_option('-m', '--memory', action='store_true', dest='memory', help='dump the memory for each matching block', default=False)
130 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 +0000131 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 +0000132 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 +0000133 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 +0000134 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 +0000135 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 +0000136
Greg Clayton85df60c2012-09-01 00:34:35 +0000137def dump_stack_history_entry(result, stack_history_entry, idx):
Greg Clayton6f446f32012-05-10 23:37:52 +0000138 address = int(stack_history_entry.address)
139 if address:
140 type_flags = int(stack_history_entry.type_flags)
Greg Clayton7a245762012-05-10 23:17:28 +0000141 symbolicator = lldb.utils.symbolication.Symbolicator()
142 symbolicator.target = lldb.target
Greg Claytonbf479652012-05-11 02:42:36 +0000143 type_str = ''
144 if type_flags == 0:
145 type_str = 'free'
146 else:
147 if type_flags & 2:
148 type_str = 'alloc'
149 elif type_flags & 4:
150 type_str = 'free'
151 elif type_flags & 1:
152 type_str = 'generic'
153 else:
154 type_str = hex(type_flags)
Greg Clayton85df60c2012-09-01 00:34:35 +0000155 result.AppendMessage('stack[%u]: addr = 0x%x, type=%s, frames:' % (idx, address, type_str))
Greg Clayton7a245762012-05-10 23:17:28 +0000156 frame_idx = 0
Greg Clayton6f446f32012-05-10 23:37:52 +0000157 idx = 0
158 pc = int(stack_history_entry.frames[idx])
Greg Clayton7a245762012-05-10 23:17:28 +0000159 while pc != 0:
160 if pc >= 0x1000:
161 frames = symbolicator.symbolicate(pc)
162 if frames:
163 for frame in frames:
Greg Clayton85df60c2012-09-01 00:34:35 +0000164 result.AppendMessage(' [%u] %s' % (frame_idx, frame))
Greg Clayton7a245762012-05-10 23:17:28 +0000165 frame_idx += 1
166 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000167 result.AppendMessage(' [%u] 0x%x' % (frame_idx, pc))
Greg Clayton7a245762012-05-10 23:17:28 +0000168 frame_idx += 1
Greg Clayton6f446f32012-05-10 23:37:52 +0000169 idx = idx + 1
170 pc = int(stack_history_entry.frames[idx])
Greg Clayton7a245762012-05-10 23:17:28 +0000171 else:
172 pc = 0
Greg Clayton85df60c2012-09-01 00:34:35 +0000173 result.AppendMessage('')
Greg Clayton7a245762012-05-10 23:17:28 +0000174
Greg Clayton85df60c2012-09-01 00:34:35 +0000175def dump_stack_history_entries(result, addr, history):
Greg Clayton7a245762012-05-10 23:17:28 +0000176 # malloc_stack_entry *get_stack_history_for_address (const void * addr)
Greg Claytonbf479652012-05-11 02:42:36 +0000177 expr = 'get_stack_history_for_address((void *)0x%x, %u)' % (addr, history)
Greg Clayton7a245762012-05-10 23:17:28 +0000178 expr_sbvalue = lldb.frame.EvaluateExpression (expr)
179 if expr_sbvalue.error.Success():
180 if expr_sbvalue.unsigned:
181 expr_value = lldb.value(expr_sbvalue)
182 idx = 0;
183 stack_history_entry = expr_value[idx]
Greg Clayton6f446f32012-05-10 23:37:52 +0000184 while int(stack_history_entry.address) != 0:
Greg Clayton85df60c2012-09-01 00:34:35 +0000185 dump_stack_history_entry(result, stack_history_entry, idx)
Greg Clayton7a245762012-05-10 23:17:28 +0000186 idx = idx + 1
187 stack_history_entry = expr_value[idx]
Greg Clayton85df60c2012-09-01 00:34:35 +0000188 else:
189 result.AppendMessage('"%s" returned zero' % (expr))
Greg Claytonbf479652012-05-11 02:42:36 +0000190 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000191 result.AppendMessage('error: expression failed "%s" => %s' % (expr, expr_sbvalue.error))
Greg Clayton7a245762012-05-10 23:17:28 +0000192
Greg Clayton4c5c4292012-07-11 22:13:18 +0000193
Greg Clayton85df60c2012-09-01 00:34:35 +0000194def display_match_results (result, options, arg_str_description, expr_sbvalue, print_no_matches = True):
Greg Clayton96666442012-04-11 18:30:53 +0000195 if expr_sbvalue.error.Success():
196 if expr_sbvalue.unsigned:
197 match_value = lldb.value(expr_sbvalue)
198 i = 0
Greg Claytonab20f292012-08-11 02:26:26 +0000199 match_idx = 0
Greg Clayton96666442012-04-11 18:30:53 +0000200 while 1:
Greg Clayton4c5c4292012-07-11 22:13:18 +0000201 print_entry = True
Greg Clayton96666442012-04-11 18:30:53 +0000202 match_entry = match_value[i]; i += 1
Greg Clayton4c5c4292012-07-11 22:13:18 +0000203 if i >= options.max_matches:
Greg Clayton85df60c2012-09-01 00:34:35 +0000204 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 +0000205 break
Greg Clayton96666442012-04-11 18:30:53 +0000206 malloc_addr = match_entry.addr.sbvalue.unsigned
207 if malloc_addr == 0:
208 break
209 malloc_size = int(match_entry.size)
210 offset = int(match_entry.offset)
Greg Claytonab20f292012-08-11 02:26:26 +0000211
212 if options.offset >= 0 and options.offset != offset:
213 print_entry = False
214 else:
215 match_addr = malloc_addr + offset
216 dynamic_value = match_entry.addr.sbvalue.GetDynamicValue(lldb.eDynamicCanRunTarget)
Greg Claytona936c6e2012-09-12 02:02:32 +0000217 description = '%#x: ' % (match_addr)
218 if options.show_size:
219 description += '<%5u> ' % (malloc_size)
220 if options.show_range:
221 if offset > 0:
222 description += '[%#x - %#x) + %-6u ' % (malloc_addr, malloc_addr + malloc_size, offset)
223 else:
224 description += '[%#x - %#x)' % (malloc_addr, malloc_addr + malloc_size)
225 else:
226 if options.type != 'isa':
227 description += '%#x + %-6u ' % (malloc_addr, offset)
Greg Claytonab20f292012-08-11 02:26:26 +0000228 derefed_dynamic_value = None
229 if dynamic_value.type.name == 'void *':
230 if options.type == 'pointer' and malloc_size == 4096:
231 error = lldb.SBError()
232 data = bytearray(lldb.process.ReadMemory(malloc_addr, 16, error))
233 if data == '\xa1\xa1\xa1\xa1AUTORELEASE!':
Greg Claytona936c6e2012-09-12 02:02:32 +0000234 ptr_size = lldb.target.addr_size
235 thread = lldb.process.ReadUnsignedFromMemory (malloc_addr + 16 + ptr_size, ptr_size, error)
236 # 4 bytes 0xa1a1a1a1
237 # 12 bytes 'AUTORELEASE!'
238 # ptr bytes autorelease insertion point
239 # ptr bytes pthread_t
240 # ptr bytes next colder page
241 # ptr bytes next hotter page
242 # 4 bytes this page's depth in the list
243 # 4 bytes high-water mark
244 description += 'AUTORELEASE! for pthread_t %#x' % (thread)
245 else:
246 description += 'malloc(%u)' % (malloc_size)
247 else:
248 description += 'malloc(%u)' % (malloc_size)
Greg Claytonab20f292012-08-11 02:26:26 +0000249 else:
250 derefed_dynamic_value = dynamic_value.deref
251 if derefed_dynamic_value:
252 derefed_dynamic_type = derefed_dynamic_value.type
253 derefed_dynamic_type_size = derefed_dynamic_type.size
254 derefed_dynamic_type_name = derefed_dynamic_type.name
Greg Claytona936c6e2012-09-12 02:02:32 +0000255 description += derefed_dynamic_type_name
Greg Claytonab20f292012-08-11 02:26:26 +0000256 if offset < derefed_dynamic_type_size:
257 member_list = list();
258 get_member_types_for_offset (derefed_dynamic_type, offset, member_list)
259 if member_list:
260 member_path = ''
261 for member in member_list:
262 member_name = member.name
263 if member_name:
264 if member_path:
265 member_path += '.'
266 member_path += member_name
267 if member_path:
268 if options.ivar_regex_blacklist:
269 for ivar_regex in options.ivar_regex_blacklist:
270 if ivar_regex.match(member_path):
271 print_entry = False
Greg Claytona936c6e2012-09-12 02:02:32 +0000272 description += '.%s' % (member_path)
273 else:
274 description += '%u bytes after %s' % (offset - derefed_dynamic_type_size, derefed_dynamic_type_name)
275 else:
276 # strip the "*" from the end of the name since we were unable to dereference this
277 description += dynamic_value.type.name[0:-1]
Greg Clayton4c5c4292012-07-11 22:13:18 +0000278 if print_entry:
Greg Claytonab20f292012-08-11 02:26:26 +0000279 match_idx += 1
Greg Claytonaaf7fad2012-09-04 14:09:21 +0000280 result_output = ''
Greg Clayton4c5c4292012-07-11 22:13:18 +0000281 if description:
Greg Claytonaaf7fad2012-09-04 14:09:21 +0000282 result_output += description
Greg Clayton4c5c4292012-07-11 22:13:18 +0000283 if options.print_type and derefed_dynamic_value:
Greg Claytonaaf7fad2012-09-04 14:09:21 +0000284 result_output += '%s' % (derefed_dynamic_value)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000285 if options.print_object_description and dynamic_value:
286 desc = dynamic_value.GetObjectDescription()
287 if desc:
Greg Claytona936c6e2012-09-12 02:02:32 +0000288 result_output += '\n%s' % (desc)
Greg Claytonaaf7fad2012-09-04 14:09:21 +0000289 if result_output:
290 result.AppendMessage(result_output)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000291 if options.memory:
292 cmd_result = lldb.SBCommandReturnObject()
293 memory_command = "memory read -f %s 0x%x 0x%x" % (options.format, malloc_addr, malloc_addr + malloc_size)
294 lldb.debugger.GetCommandInterpreter().HandleCommand(memory_command, cmd_result)
Greg Clayton85df60c2012-09-01 00:34:35 +0000295 result.AppendMessage(cmd_result.GetOutput())
Greg Clayton4c5c4292012-07-11 22:13:18 +0000296 if options.stack_history:
Greg Clayton85df60c2012-09-01 00:34:35 +0000297 dump_stack_history_entries(result, malloc_addr, 1)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000298 elif options.stack:
Greg Clayton85df60c2012-09-01 00:34:35 +0000299 dump_stack_history_entries(result, malloc_addr, 0)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000300 return i
301 elif print_no_matches:
Greg Clayton85df60c2012-09-01 00:34:35 +0000302 result.AppendMessage('no matches found for %s' % (arg_str_description))
Greg Clayton96666442012-04-11 18:30:53 +0000303 else:
Greg Claytonaaf7fad2012-09-04 14:09:21 +0000304 result.AppendMessage(str(expr_sbvalue.error))
Greg Clayton4c5c4292012-07-11 22:13:18 +0000305 return 0
306
Greg Clayton85df60c2012-09-01 00:34:35 +0000307def heap_search(result, options, arg_str):
Greg Clayton4c5c4292012-07-11 22:13:18 +0000308 dylid_load_err = load_dylib()
309 if dylid_load_err:
Greg Clayton85df60c2012-09-01 00:34:35 +0000310 result.AppendMessage(dylid_load_err)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000311 return
312 expr = None
Greg Clayton393fc5f2012-09-11 18:10:27 +0000313 print_no_matches = True
Greg Clayton4c5c4292012-07-11 22:13:18 +0000314 arg_str_description = arg_str
Greg Clayton4c5c4292012-07-11 22:13:18 +0000315 if options.type == 'pointer':
316 expr = 'find_pointer_in_heap((void *)%s)' % (arg_str)
317 arg_str_description = 'malloc block containing pointer %s' % arg_str
318 if options.format == None:
319 options.format = "A" # 'A' is "address" format
Greg Claytonab20f292012-08-11 02:26:26 +0000320 elif options.type == 'isa':
Greg Claytonaaf7fad2012-09-04 14:09:21 +0000321 expr = 'find_objc_objects_in_memory ((void *)%s)' % (arg_str)
322 #result.AppendMessage ('expr -u0 -- %s' % expr) # REMOVE THIS LINE
Greg Claytonab20f292012-08-11 02:26:26 +0000323 arg_str_description = 'objective C classes with isa %s' % arg_str
324 options.offset = 0
325 if options.format == None:
326 options.format = "A" # 'A' is "address" format
Greg Clayton4c5c4292012-07-11 22:13:18 +0000327 elif options.type == 'cstr':
328 expr = 'find_cstring_in_heap("%s")' % arg_str
329 arg_str_description = 'malloc block containing "%s"' % arg_str
330 elif options.type == 'addr':
331 expr = 'find_block_for_address((void *)%s)' % arg_str
332 arg_str_description = 'malloc block for %s' % arg_str
Greg Clayton393fc5f2012-09-11 18:10:27 +0000333 elif options.type == 'all':
334 expr = 'get_heap_info(1)'
335 arg_str_description = None
336 print_no_matches = False
Greg Clayton4c5c4292012-07-11 22:13:18 +0000337 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000338 result.AppendMessage('error: invalid type "%s"\nvalid values are "pointer", "cstr"' % options.type)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000339 return
Greg Clayton85df60c2012-09-01 00:34:35 +0000340 if options.format == None:
341 options.format = "Y" # 'Y' is "bytes with ASCII" format
Greg Clayton4c5c4292012-07-11 22:13:18 +0000342
Greg Clayton85df60c2012-09-01 00:34:35 +0000343 display_match_results (result, options, arg_str_description, lldb.frame.EvaluateExpression (expr))
Greg Clayton96666442012-04-11 18:30:53 +0000344
Greg Claytonbff78412012-04-12 18:57:36 +0000345def ptr_refs(debugger, command, result, dict):
Greg Claytone93e24f2012-04-11 16:27:06 +0000346 command_args = shlex.split(command)
Greg Claytonbf479652012-05-11 02:42:36 +0000347 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
Greg Clayton96666442012-04-11 18:30:53 +0000348 description='''Searches the heap for pointer references on darwin user space programs.
349
350 Any matches that were found will dump the malloc blocks that contain the pointers
351 and might be able to print what kind of objects the pointers are contained in using
Greg Claytonbff78412012-04-12 18:57:36 +0000352 dynamic type information in the program.'''
353 parser = optparse.OptionParser(description=description, prog='ptr_refs',usage=usage)
Greg Clayton93e5ba52012-04-13 16:24:09 +0000354 add_common_options(parser)
Greg Claytone93e24f2012-04-11 16:27:06 +0000355 try:
356 (options, args) = parser.parse_args(command_args)
357 except:
358 return
Greg Clayton96666442012-04-11 18:30:53 +0000359
360 options.type = 'pointer'
Greg Claytone93e24f2012-04-11 16:27:06 +0000361
362 if args:
363
364 for data in args:
Greg Clayton85df60c2012-09-01 00:34:35 +0000365 heap_search (result, options, data)
Greg Claytone93e24f2012-04-11 16:27:06 +0000366 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000367 resultresult.AppendMessage('error: no pointer arguments were given')
Greg Claytone93e24f2012-04-11 16:27:06 +0000368
Greg Claytonbff78412012-04-12 18:57:36 +0000369def cstr_refs(debugger, command, result, dict):
Greg Clayton96666442012-04-11 18:30:53 +0000370 command_args = shlex.split(command)
Greg Claytonbff78412012-04-12 18:57:36 +0000371 usage = "usage: %prog [options] <CSTR> [CSTR ...]"
Greg Clayton96666442012-04-11 18:30:53 +0000372 description='''Searches the heap for C string references on darwin user space programs.
373
374 Any matches that were found will dump the malloc blocks that contain the C strings
375 and might be able to print what kind of objects the pointers are contained in using
Greg Claytonbff78412012-04-12 18:57:36 +0000376 dynamic type information in the program.'''
377 parser = optparse.OptionParser(description=description, prog='cstr_refs',usage=usage)
Greg Clayton93e5ba52012-04-13 16:24:09 +0000378 add_common_options(parser)
Greg Clayton96666442012-04-11 18:30:53 +0000379 try:
380 (options, args) = parser.parse_args(command_args)
381 except:
382 return
383
384 options.type = 'cstr'
385
386 if args:
387
388 for data in args:
Greg Clayton85df60c2012-09-01 00:34:35 +0000389 heap_search (result, options, data)
Greg Clayton96666442012-04-11 18:30:53 +0000390 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000391 result.AppendMessage('error: no c string arguments were given to search for');
Greg Claytone93e24f2012-04-11 16:27:06 +0000392
Greg Claytonbff78412012-04-12 18:57:36 +0000393def malloc_info(debugger, command, result, dict):
394 command_args = shlex.split(command)
Greg Claytonbf479652012-05-11 02:42:36 +0000395 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
Greg Claytonbff78412012-04-12 18:57:36 +0000396 description='''Searches the heap a malloc block that contains the addresses specified as arguments.
397
398 Any matches that were found will dump the malloc blocks that match or contain
399 the specified address. The matching blocks might be able to show what kind
400 of objects they are using dynamic type information in the program.'''
401 parser = optparse.OptionParser(description=description, prog='cstr_refs',usage=usage)
Greg Clayton93e5ba52012-04-13 16:24:09 +0000402 add_common_options(parser)
Greg Claytonbff78412012-04-12 18:57:36 +0000403 try:
404 (options, args) = parser.parse_args(command_args)
405 except:
406 return
Greg Claytonbff78412012-04-12 18:57:36 +0000407 options.type = 'addr'
Greg Claytonbff78412012-04-12 18:57:36 +0000408 if args:
Greg Claytonbff78412012-04-12 18:57:36 +0000409 for data in args:
Greg Clayton85df60c2012-09-01 00:34:35 +0000410 heap_search (result, options, data)
Greg Claytonbff78412012-04-12 18:57:36 +0000411 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000412 result.AppendMessage('error: no c string arguments were given to search for')
Greg Claytonbff78412012-04-12 18:57:36 +0000413
Greg Clayton393fc5f2012-09-11 18:10:27 +0000414def heap(debugger, command, result, dict):
Greg Claytonbf479652012-05-11 02:42:36 +0000415 command_args = shlex.split(command)
416 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
Greg Clayton393fc5f2012-09-11 18:10:27 +0000417 description='''Traverse all allocations on the heap and report statistics.
Greg Claytonbf479652012-05-11 02:42:36 +0000418
Greg Clayton393fc5f2012-09-11 18:10:27 +0000419 If programs set the MallocStackLogging=1 in the environment, then stack
420 history is available for any allocations. '''
421 parser = optparse.OptionParser(description=description, prog='cstr_refs',usage=usage)
422 add_common_options(parser)
423 try:
424 (options, args) = parser.parse_args(command_args)
425 except:
426 return
427 options.type = 'all'
428 if args:
429 result.AppendMessage('error: heap command takes no arguments, only options')
Greg Claytonbf479652012-05-11 02:42:36 +0000430 else:
Greg Clayton393fc5f2012-09-11 18:10:27 +0000431 heap_search (result, options, None)
Greg Claytonbf479652012-05-11 02:42:36 +0000432
Greg Clayton4c5c4292012-07-11 22:13:18 +0000433def section_ptr_refs(debugger, command, result, dict):
434 command_args = shlex.split(command)
435 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
436 description='''Searches section contents for pointer values in darwin user space programs.'''
437 parser = optparse.OptionParser(description=description, prog='section_ptr_refs',usage=usage)
438 add_common_options(parser)
439 parser.add_option('--section', action='append', type='string', dest='section_names', help='section name to search', default=list())
440 try:
441 (options, args) = parser.parse_args(command_args)
442 except:
443 return
444
445 options.type = 'pointer'
446
447 sections = list()
448 section_modules = list()
449 if not options.section_names:
Greg Clayton85df60c2012-09-01 00:34:35 +0000450 result.AppendMessage('error: at least one section must be specified with the --section option')
Greg Clayton4c5c4292012-07-11 22:13:18 +0000451 return
452
453 for module in lldb.target.modules:
454 for section_name in options.section_names:
455 section = module.section[section_name]
456 if section:
457 sections.append (section)
458 section_modules.append (module)
459 if sections:
460 dylid_load_err = load_dylib()
461 if dylid_load_err:
Greg Clayton85df60c2012-09-01 00:34:35 +0000462 result.AppendMessage(dylid_load_err)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000463 return
464 for expr_str in args:
465 for (idx, section) in enumerate(sections):
466 expr = 'find_pointer_in_memory(0x%xllu, %ullu, (void *)%s)' % (section.addr.load_addr, section.size, expr_str)
467 arg_str_description = 'section %s.%s containing "%s"' % (section_modules[idx].file.fullpath, section.name, expr_str)
Greg Clayton85df60c2012-09-01 00:34:35 +0000468 num_matches = display_match_results (result, options, arg_str_description, lldb.frame.EvaluateExpression (expr), False)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000469 if num_matches:
470 if num_matches < options.max_matches:
471 options.max_matches = options.max_matches - num_matches
472 else:
473 options.max_matches = 0
474 if options.max_matches == 0:
475 return
476 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000477 result.AppendMessage('error: no sections were found that match any of %s' % (', '.join(options.section_names)))
Greg Clayton4c5c4292012-07-11 22:13:18 +0000478
Greg Claytonab20f292012-08-11 02:26:26 +0000479def objc_refs(debugger, command, result, dict):
480 command_args = shlex.split(command)
481 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
482 description='''Find all heap allocations given one or more objective C class names.'''
483 parser = optparse.OptionParser(description=description, prog='object_refs',usage=usage)
484 add_common_options(parser)
485 try:
486 (options, args) = parser.parse_args(command_args)
487 except:
488 return
489
490 dylid_load_err = load_dylib()
491 if dylid_load_err:
Greg Clayton85df60c2012-09-01 00:34:35 +0000492 result.AppendMessage(dylid_load_err)
Greg Claytonab20f292012-08-11 02:26:26 +0000493 else:
494 if args:
495 for class_name in args:
496 addr_expr_str = "(void *)[%s class]" % class_name
497 expr_sbvalue = lldb.frame.EvaluateExpression (addr_expr_str)
498 if expr_sbvalue.error.Success():
499 isa = expr_sbvalue.unsigned
500 if isa:
501 options.type = 'isa'
Greg Claytona936c6e2012-09-12 02:02:32 +0000502 result.AppendMessage('Searching for all instances of classes or subclasses of %s (isa=0x%x)' % (class_name, isa))
Greg Clayton85df60c2012-09-01 00:34:35 +0000503 heap_search (result, options, '0x%x' % isa)
Greg Claytonab20f292012-08-11 02:26:26 +0000504 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000505 result.AppendMessage('error: Can\'t find isa for an ObjC class named "%s"' % (class_name))
Greg Claytonab20f292012-08-11 02:26:26 +0000506 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000507 result.AppendMessage('error: expression error for "%s": %s' % (addr_expr_str, expr_sbvalue.error))
Greg Claytonab20f292012-08-11 02:26:26 +0000508 else:
Greg Claytonaaf7fad2012-09-04 14:09:21 +0000509 # Find all objective C objects by not specifying an isa
510 options.type = 'isa'
511 heap_search (result, options, '0x0')
Greg Claytonab20f292012-08-11 02:26:26 +0000512
Greg Clayton1dae6f32012-04-25 18:40:20 +0000513if __name__ == '__main__':
514 lldb.debugger = lldb.SBDebugger.Create()
515
516# This initializer is being run from LLDB in the embedded command interpreter
517# Add any commands contained in this module to LLDB
518lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.ptr_refs ptr_refs')
519lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.cstr_refs cstr_refs')
520lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.malloc_info malloc_info')
Greg Clayton393fc5f2012-09-11 18:10:27 +0000521lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.heap heap')
Greg Clayton4c5c4292012-07-11 22:13:18 +0000522lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.section_ptr_refs section_ptr_refs')
Greg Claytonab20f292012-08-11 02:26:26 +0000523lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.objc_refs objc_refs')
Greg Clayton393fc5f2012-09-11 18:10:27 +0000524print '"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 +0000525
526
527
528