blob: 8bd8cd9653b20bbaa7754c3c8683ee82c0a5035a [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 Clayton130a3122012-10-08 22:39:38 +0000136 parser.add_option('-V', '--vm-regions', action='store_true', dest='check_vm_regions', help='Also check the VM regions', default=False)
Greg Clayton7a245762012-05-10 23:17:28 +0000137
Greg Clayton85df60c2012-09-01 00:34:35 +0000138def dump_stack_history_entry(result, stack_history_entry, idx):
Greg Clayton6f446f32012-05-10 23:37:52 +0000139 address = int(stack_history_entry.address)
140 if address:
141 type_flags = int(stack_history_entry.type_flags)
Greg Clayton7a245762012-05-10 23:17:28 +0000142 symbolicator = lldb.utils.symbolication.Symbolicator()
143 symbolicator.target = lldb.target
Greg Claytonbf479652012-05-11 02:42:36 +0000144 type_str = ''
145 if type_flags == 0:
146 type_str = 'free'
147 else:
148 if type_flags & 2:
149 type_str = 'alloc'
150 elif type_flags & 4:
151 type_str = 'free'
152 elif type_flags & 1:
153 type_str = 'generic'
154 else:
155 type_str = hex(type_flags)
Greg Clayton85df60c2012-09-01 00:34:35 +0000156 result.AppendMessage('stack[%u]: addr = 0x%x, type=%s, frames:' % (idx, address, type_str))
Greg Clayton7a245762012-05-10 23:17:28 +0000157 frame_idx = 0
Greg Clayton6f446f32012-05-10 23:37:52 +0000158 idx = 0
159 pc = int(stack_history_entry.frames[idx])
Greg Clayton7a245762012-05-10 23:17:28 +0000160 while pc != 0:
161 if pc >= 0x1000:
162 frames = symbolicator.symbolicate(pc)
163 if frames:
164 for frame in frames:
Greg Clayton85df60c2012-09-01 00:34:35 +0000165 result.AppendMessage(' [%u] %s' % (frame_idx, frame))
Greg Clayton7a245762012-05-10 23:17:28 +0000166 frame_idx += 1
167 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000168 result.AppendMessage(' [%u] 0x%x' % (frame_idx, pc))
Greg Clayton7a245762012-05-10 23:17:28 +0000169 frame_idx += 1
Greg Clayton6f446f32012-05-10 23:37:52 +0000170 idx = idx + 1
171 pc = int(stack_history_entry.frames[idx])
Greg Clayton7a245762012-05-10 23:17:28 +0000172 else:
173 pc = 0
Greg Clayton85df60c2012-09-01 00:34:35 +0000174 result.AppendMessage('')
Greg Clayton7a245762012-05-10 23:17:28 +0000175
Greg Clayton85df60c2012-09-01 00:34:35 +0000176def dump_stack_history_entries(result, addr, history):
Greg Clayton7a245762012-05-10 23:17:28 +0000177 # malloc_stack_entry *get_stack_history_for_address (const void * addr)
Greg Claytonbf479652012-05-11 02:42:36 +0000178 expr = 'get_stack_history_for_address((void *)0x%x, %u)' % (addr, history)
Greg Clayton7a245762012-05-10 23:17:28 +0000179 expr_sbvalue = lldb.frame.EvaluateExpression (expr)
180 if expr_sbvalue.error.Success():
181 if expr_sbvalue.unsigned:
182 expr_value = lldb.value(expr_sbvalue)
183 idx = 0;
184 stack_history_entry = expr_value[idx]
Greg Clayton6f446f32012-05-10 23:37:52 +0000185 while int(stack_history_entry.address) != 0:
Greg Clayton85df60c2012-09-01 00:34:35 +0000186 dump_stack_history_entry(result, stack_history_entry, idx)
Greg Clayton7a245762012-05-10 23:17:28 +0000187 idx = idx + 1
188 stack_history_entry = expr_value[idx]
Greg Clayton85df60c2012-09-01 00:34:35 +0000189 else:
190 result.AppendMessage('"%s" returned zero' % (expr))
Greg Claytonbf479652012-05-11 02:42:36 +0000191 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000192 result.AppendMessage('error: expression failed "%s" => %s' % (expr, expr_sbvalue.error))
Greg Clayton7a245762012-05-10 23:17:28 +0000193
Greg Clayton4c5c4292012-07-11 22:13:18 +0000194
Greg Clayton85df60c2012-09-01 00:34:35 +0000195def display_match_results (result, options, arg_str_description, expr_sbvalue, print_no_matches = True):
Greg Clayton96666442012-04-11 18:30:53 +0000196 if expr_sbvalue.error.Success():
197 if expr_sbvalue.unsigned:
198 match_value = lldb.value(expr_sbvalue)
199 i = 0
Greg Claytonab20f292012-08-11 02:26:26 +0000200 match_idx = 0
Greg Clayton96666442012-04-11 18:30:53 +0000201 while 1:
Greg Clayton4c5c4292012-07-11 22:13:18 +0000202 print_entry = True
Greg Clayton96666442012-04-11 18:30:53 +0000203 match_entry = match_value[i]; i += 1
Greg Clayton4c5c4292012-07-11 22:13:18 +0000204 if i >= options.max_matches:
Greg Clayton85df60c2012-09-01 00:34:35 +0000205 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 +0000206 break
Greg Clayton96666442012-04-11 18:30:53 +0000207 malloc_addr = match_entry.addr.sbvalue.unsigned
208 if malloc_addr == 0:
209 break
210 malloc_size = int(match_entry.size)
211 offset = int(match_entry.offset)
Greg Claytonab20f292012-08-11 02:26:26 +0000212
213 if options.offset >= 0 and options.offset != offset:
214 print_entry = False
215 else:
216 match_addr = malloc_addr + offset
217 dynamic_value = match_entry.addr.sbvalue.GetDynamicValue(lldb.eDynamicCanRunTarget)
Greg Claytona936c6e2012-09-12 02:02:32 +0000218 description = '%#x: ' % (match_addr)
219 if options.show_size:
220 description += '<%5u> ' % (malloc_size)
221 if options.show_range:
222 if offset > 0:
223 description += '[%#x - %#x) + %-6u ' % (malloc_addr, malloc_addr + malloc_size, offset)
224 else:
225 description += '[%#x - %#x)' % (malloc_addr, malloc_addr + malloc_size)
226 else:
227 if options.type != 'isa':
228 description += '%#x + %-6u ' % (malloc_addr, offset)
Greg Claytonab20f292012-08-11 02:26:26 +0000229 derefed_dynamic_value = None
230 if dynamic_value.type.name == 'void *':
231 if options.type == 'pointer' and malloc_size == 4096:
232 error = lldb.SBError()
233 data = bytearray(lldb.process.ReadMemory(malloc_addr, 16, error))
234 if data == '\xa1\xa1\xa1\xa1AUTORELEASE!':
Greg Claytona936c6e2012-09-12 02:02:32 +0000235 ptr_size = lldb.target.addr_size
236 thread = lldb.process.ReadUnsignedFromMemory (malloc_addr + 16 + ptr_size, ptr_size, error)
237 # 4 bytes 0xa1a1a1a1
238 # 12 bytes 'AUTORELEASE!'
239 # ptr bytes autorelease insertion point
240 # ptr bytes pthread_t
241 # ptr bytes next colder page
242 # ptr bytes next hotter page
243 # 4 bytes this page's depth in the list
244 # 4 bytes high-water mark
245 description += 'AUTORELEASE! for pthread_t %#x' % (thread)
246 else:
247 description += 'malloc(%u)' % (malloc_size)
248 else:
249 description += 'malloc(%u)' % (malloc_size)
Greg Claytonab20f292012-08-11 02:26:26 +0000250 else:
251 derefed_dynamic_value = dynamic_value.deref
252 if derefed_dynamic_value:
253 derefed_dynamic_type = derefed_dynamic_value.type
254 derefed_dynamic_type_size = derefed_dynamic_type.size
255 derefed_dynamic_type_name = derefed_dynamic_type.name
Greg Claytona936c6e2012-09-12 02:02:32 +0000256 description += derefed_dynamic_type_name
Greg Claytonab20f292012-08-11 02:26:26 +0000257 if offset < derefed_dynamic_type_size:
258 member_list = list();
259 get_member_types_for_offset (derefed_dynamic_type, offset, member_list)
260 if member_list:
261 member_path = ''
262 for member in member_list:
263 member_name = member.name
264 if member_name:
265 if member_path:
266 member_path += '.'
267 member_path += member_name
268 if member_path:
269 if options.ivar_regex_blacklist:
270 for ivar_regex in options.ivar_regex_blacklist:
271 if ivar_regex.match(member_path):
272 print_entry = False
Greg Claytona936c6e2012-09-12 02:02:32 +0000273 description += '.%s' % (member_path)
274 else:
275 description += '%u bytes after %s' % (offset - derefed_dynamic_type_size, derefed_dynamic_type_name)
276 else:
277 # strip the "*" from the end of the name since we were unable to dereference this
278 description += dynamic_value.type.name[0:-1]
Greg Clayton4c5c4292012-07-11 22:13:18 +0000279 if print_entry:
Greg Claytonab20f292012-08-11 02:26:26 +0000280 match_idx += 1
Greg Claytonaaf7fad2012-09-04 14:09:21 +0000281 result_output = ''
Greg Clayton4c5c4292012-07-11 22:13:18 +0000282 if description:
Greg Claytonaaf7fad2012-09-04 14:09:21 +0000283 result_output += description
Greg Clayton4c5c4292012-07-11 22:13:18 +0000284 if options.print_type and derefed_dynamic_value:
Greg Claytonaaf7fad2012-09-04 14:09:21 +0000285 result_output += '%s' % (derefed_dynamic_value)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000286 if options.print_object_description and dynamic_value:
287 desc = dynamic_value.GetObjectDescription()
288 if desc:
Greg Claytona936c6e2012-09-12 02:02:32 +0000289 result_output += '\n%s' % (desc)
Greg Claytonaaf7fad2012-09-04 14:09:21 +0000290 if result_output:
291 result.AppendMessage(result_output)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000292 if options.memory:
293 cmd_result = lldb.SBCommandReturnObject()
294 memory_command = "memory read -f %s 0x%x 0x%x" % (options.format, malloc_addr, malloc_addr + malloc_size)
295 lldb.debugger.GetCommandInterpreter().HandleCommand(memory_command, cmd_result)
Greg Clayton85df60c2012-09-01 00:34:35 +0000296 result.AppendMessage(cmd_result.GetOutput())
Greg Clayton4c5c4292012-07-11 22:13:18 +0000297 if options.stack_history:
Greg Clayton85df60c2012-09-01 00:34:35 +0000298 dump_stack_history_entries(result, malloc_addr, 1)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000299 elif options.stack:
Greg Clayton85df60c2012-09-01 00:34:35 +0000300 dump_stack_history_entries(result, malloc_addr, 0)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000301 return i
302 elif print_no_matches:
Greg Clayton85df60c2012-09-01 00:34:35 +0000303 result.AppendMessage('no matches found for %s' % (arg_str_description))
Greg Clayton96666442012-04-11 18:30:53 +0000304 else:
Greg Claytonaaf7fad2012-09-04 14:09:21 +0000305 result.AppendMessage(str(expr_sbvalue.error))
Greg Clayton4c5c4292012-07-11 22:13:18 +0000306 return 0
307
Greg Clayton85df60c2012-09-01 00:34:35 +0000308def heap_search(result, options, arg_str):
Greg Clayton4c5c4292012-07-11 22:13:18 +0000309 dylid_load_err = load_dylib()
310 if dylid_load_err:
Greg Clayton85df60c2012-09-01 00:34:35 +0000311 result.AppendMessage(dylid_load_err)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000312 return
313 expr = None
Greg Clayton393fc5f2012-09-11 18:10:27 +0000314 print_no_matches = True
Greg Clayton4c5c4292012-07-11 22:13:18 +0000315 arg_str_description = arg_str
Greg Clayton4c5c4292012-07-11 22:13:18 +0000316 if options.type == 'pointer':
Greg Clayton130a3122012-10-08 22:39:38 +0000317 expr = 'find_pointer_in_heap((void *)%s, (int)%u)' % (arg_str, options.check_vm_regions)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000318 arg_str_description = 'malloc block containing pointer %s' % arg_str
319 if options.format == None:
320 options.format = "A" # 'A' is "address" format
Greg Claytonab20f292012-08-11 02:26:26 +0000321 elif options.type == 'isa':
Greg Clayton130a3122012-10-08 22:39:38 +0000322 expr = 'find_objc_objects_in_memory ((void *)%s, (int)%u)' % (arg_str, options.check_vm_regions)
Greg Claytonaaf7fad2012-09-04 14:09:21 +0000323 #result.AppendMessage ('expr -u0 -- %s' % expr) # REMOVE THIS LINE
Greg Claytonab20f292012-08-11 02:26:26 +0000324 arg_str_description = 'objective C classes with isa %s' % arg_str
325 options.offset = 0
326 if options.format == None:
327 options.format = "A" # 'A' is "address" format
Greg Clayton4c5c4292012-07-11 22:13:18 +0000328 elif options.type == 'cstr':
Greg Clayton130a3122012-10-08 22:39:38 +0000329 expr = 'find_cstring_in_heap("%s", (int)%u)' % (arg_str, options.check_vm_regions)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000330 arg_str_description = 'malloc block containing "%s"' % arg_str
331 elif options.type == 'addr':
Greg Clayton130a3122012-10-08 22:39:38 +0000332 expr = 'find_block_for_address((void *)%s, (int)%u)' % (arg_str, options.check_vm_regions)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000333 arg_str_description = 'malloc block for %s' % arg_str
Greg Clayton393fc5f2012-09-11 18:10:27 +0000334 elif options.type == 'all':
335 expr = 'get_heap_info(1)'
336 arg_str_description = None
337 print_no_matches = False
Greg Clayton4c5c4292012-07-11 22:13:18 +0000338 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000339 result.AppendMessage('error: invalid type "%s"\nvalid values are "pointer", "cstr"' % options.type)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000340 return
Greg Clayton85df60c2012-09-01 00:34:35 +0000341 if options.format == None:
342 options.format = "Y" # 'Y' is "bytes with ASCII" format
Greg Clayton4c5c4292012-07-11 22:13:18 +0000343
Greg Clayton85df60c2012-09-01 00:34:35 +0000344 display_match_results (result, options, arg_str_description, lldb.frame.EvaluateExpression (expr))
Greg Clayton96666442012-04-11 18:30:53 +0000345
Greg Claytonbff78412012-04-12 18:57:36 +0000346def ptr_refs(debugger, command, result, dict):
Greg Claytone93e24f2012-04-11 16:27:06 +0000347 command_args = shlex.split(command)
Greg Claytonbf479652012-05-11 02:42:36 +0000348 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
Greg Clayton96666442012-04-11 18:30:53 +0000349 description='''Searches the heap for pointer references on darwin user space programs.
350
351 Any matches that were found will dump the malloc blocks that contain the pointers
352 and might be able to print what kind of objects the pointers are contained in using
Greg Claytonbff78412012-04-12 18:57:36 +0000353 dynamic type information in the program.'''
354 parser = optparse.OptionParser(description=description, prog='ptr_refs',usage=usage)
Greg Clayton93e5ba52012-04-13 16:24:09 +0000355 add_common_options(parser)
Greg Claytone93e24f2012-04-11 16:27:06 +0000356 try:
357 (options, args) = parser.parse_args(command_args)
358 except:
359 return
Greg Clayton96666442012-04-11 18:30:53 +0000360
361 options.type = 'pointer'
Greg Claytone93e24f2012-04-11 16:27:06 +0000362
363 if args:
364
365 for data in args:
Greg Clayton85df60c2012-09-01 00:34:35 +0000366 heap_search (result, options, data)
Greg Claytone93e24f2012-04-11 16:27:06 +0000367 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000368 resultresult.AppendMessage('error: no pointer arguments were given')
Greg Claytone93e24f2012-04-11 16:27:06 +0000369
Greg Claytonbff78412012-04-12 18:57:36 +0000370def cstr_refs(debugger, command, result, dict):
Greg Clayton96666442012-04-11 18:30:53 +0000371 command_args = shlex.split(command)
Greg Claytonbff78412012-04-12 18:57:36 +0000372 usage = "usage: %prog [options] <CSTR> [CSTR ...]"
Greg Clayton96666442012-04-11 18:30:53 +0000373 description='''Searches the heap for C string references on darwin user space programs.
374
375 Any matches that were found will dump the malloc blocks that contain the C strings
376 and might be able to print what kind of objects the pointers are contained in using
Greg Claytonbff78412012-04-12 18:57:36 +0000377 dynamic type information in the program.'''
378 parser = optparse.OptionParser(description=description, prog='cstr_refs',usage=usage)
Greg Clayton93e5ba52012-04-13 16:24:09 +0000379 add_common_options(parser)
Greg Clayton96666442012-04-11 18:30:53 +0000380 try:
381 (options, args) = parser.parse_args(command_args)
382 except:
383 return
384
385 options.type = 'cstr'
386
387 if args:
388
389 for data in args:
Greg Clayton85df60c2012-09-01 00:34:35 +0000390 heap_search (result, options, data)
Greg Clayton96666442012-04-11 18:30:53 +0000391 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000392 result.AppendMessage('error: no c string arguments were given to search for');
Greg Claytone93e24f2012-04-11 16:27:06 +0000393
Greg Claytonbff78412012-04-12 18:57:36 +0000394def malloc_info(debugger, command, result, dict):
395 command_args = shlex.split(command)
Greg Claytonbf479652012-05-11 02:42:36 +0000396 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
Greg Claytonbff78412012-04-12 18:57:36 +0000397 description='''Searches the heap a malloc block that contains the addresses specified as arguments.
398
399 Any matches that were found will dump the malloc blocks that match or contain
400 the specified address. The matching blocks might be able to show what kind
401 of objects they are using dynamic type information in the program.'''
402 parser = optparse.OptionParser(description=description, prog='cstr_refs',usage=usage)
Greg Clayton93e5ba52012-04-13 16:24:09 +0000403 add_common_options(parser)
Greg Claytonbff78412012-04-12 18:57:36 +0000404 try:
405 (options, args) = parser.parse_args(command_args)
406 except:
407 return
Greg Claytonbff78412012-04-12 18:57:36 +0000408 options.type = 'addr'
Greg Claytonbff78412012-04-12 18:57:36 +0000409 if args:
Greg Claytonbff78412012-04-12 18:57:36 +0000410 for data in args:
Greg Clayton85df60c2012-09-01 00:34:35 +0000411 heap_search (result, options, data)
Greg Claytonbff78412012-04-12 18:57:36 +0000412 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000413 result.AppendMessage('error: no c string arguments were given to search for')
Greg Claytonbff78412012-04-12 18:57:36 +0000414
Greg Clayton393fc5f2012-09-11 18:10:27 +0000415def heap(debugger, command, result, dict):
Greg Claytonbf479652012-05-11 02:42:36 +0000416 command_args = shlex.split(command)
417 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
Greg Clayton393fc5f2012-09-11 18:10:27 +0000418 description='''Traverse all allocations on the heap and report statistics.
Greg Claytonbf479652012-05-11 02:42:36 +0000419
Greg Clayton393fc5f2012-09-11 18:10:27 +0000420 If programs set the MallocStackLogging=1 in the environment, then stack
421 history is available for any allocations. '''
422 parser = optparse.OptionParser(description=description, prog='cstr_refs',usage=usage)
423 add_common_options(parser)
424 try:
425 (options, args) = parser.parse_args(command_args)
426 except:
427 return
428 options.type = 'all'
429 if args:
430 result.AppendMessage('error: heap command takes no arguments, only options')
Greg Claytonbf479652012-05-11 02:42:36 +0000431 else:
Greg Clayton393fc5f2012-09-11 18:10:27 +0000432 heap_search (result, options, None)
Greg Claytonbf479652012-05-11 02:42:36 +0000433
Greg Clayton130a3122012-10-08 22:39:38 +0000434def stack_ptr_refs(debugger, command, result, dict):
435 command_args = shlex.split(command)
436 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
437 description='''Searches thread stack contents for pointer values in darwin user space programs.'''
438 parser = optparse.OptionParser(description=description, prog='section_ptr_refs',usage=usage)
439 add_common_options(parser)
440 try:
441 (options, args) = parser.parse_args(command_args)
442 except:
443 return
444
445 options.type = 'pointer'
446
447 stack_threads = list()
448 stack_bases = list()
449 stack_sizes = list()
450 for thread in lldb.process:
451 min_sp = thread.frame[0].sp
452 max_sp = min_sp
453 for frame in thread.frames:
454 sp = frame.sp
455 if sp < min_sp: min_sp = sp
456 if sp > max_sp: max_sp = sp
457 result.AppendMessage ('%s stack [%#x - %#x)' % (thread, min_sp, max_sp))
458 if min_sp < max_sp:
459 stack_threads.append (thread)
460 stack_bases.append (min_sp)
461 stack_sizes.append (max_sp-min_sp)
462
463 if stack_bases:
464 dylid_load_err = load_dylib()
465 if dylid_load_err:
466 result.AppendMessage(dylid_load_err)
467 return
468 for expr_str in args:
469 for (idx, stack_base) in enumerate(stack_bases):
470 stack_size = stack_sizes[idx]
471 expr = 'find_pointer_in_memory(0x%xllu, %ullu, (void *)%s)' % (stack_base, stack_size, expr_str)
472 arg_str_description = 'thead %s stack containing "%s"' % (stack_threads[idx], expr_str)
473 num_matches = display_match_results (result, options, arg_str_description, lldb.frame.EvaluateExpression (expr), False)
474 if num_matches:
475 if num_matches < options.max_matches:
476 options.max_matches = options.max_matches - num_matches
477 else:
478 options.max_matches = 0
479 if options.max_matches == 0:
480 return
481 else:
482 result.AppendMessage('error: no thread stacks were found that match any of %s' % (', '.join(options.section_names)))
483
Greg Clayton4c5c4292012-07-11 22:13:18 +0000484def section_ptr_refs(debugger, command, result, dict):
485 command_args = shlex.split(command)
486 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
487 description='''Searches section contents for pointer values in darwin user space programs.'''
488 parser = optparse.OptionParser(description=description, prog='section_ptr_refs',usage=usage)
489 add_common_options(parser)
490 parser.add_option('--section', action='append', type='string', dest='section_names', help='section name to search', default=list())
491 try:
492 (options, args) = parser.parse_args(command_args)
493 except:
494 return
495
496 options.type = 'pointer'
Greg Clayton130a3122012-10-08 22:39:38 +0000497
Greg Clayton4c5c4292012-07-11 22:13:18 +0000498 sections = list()
499 section_modules = list()
500 if not options.section_names:
Greg Clayton85df60c2012-09-01 00:34:35 +0000501 result.AppendMessage('error: at least one section must be specified with the --section option')
Greg Clayton4c5c4292012-07-11 22:13:18 +0000502 return
503
504 for module in lldb.target.modules:
505 for section_name in options.section_names:
506 section = module.section[section_name]
507 if section:
508 sections.append (section)
509 section_modules.append (module)
510 if sections:
511 dylid_load_err = load_dylib()
512 if dylid_load_err:
Greg Clayton85df60c2012-09-01 00:34:35 +0000513 result.AppendMessage(dylid_load_err)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000514 return
515 for expr_str in args:
516 for (idx, section) in enumerate(sections):
517 expr = 'find_pointer_in_memory(0x%xllu, %ullu, (void *)%s)' % (section.addr.load_addr, section.size, expr_str)
518 arg_str_description = 'section %s.%s containing "%s"' % (section_modules[idx].file.fullpath, section.name, expr_str)
Greg Clayton85df60c2012-09-01 00:34:35 +0000519 num_matches = display_match_results (result, options, arg_str_description, lldb.frame.EvaluateExpression (expr), False)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000520 if num_matches:
521 if num_matches < options.max_matches:
522 options.max_matches = options.max_matches - num_matches
523 else:
524 options.max_matches = 0
525 if options.max_matches == 0:
526 return
527 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000528 result.AppendMessage('error: no sections were found that match any of %s' % (', '.join(options.section_names)))
Greg Clayton4c5c4292012-07-11 22:13:18 +0000529
Greg Claytonab20f292012-08-11 02:26:26 +0000530def objc_refs(debugger, command, result, dict):
531 command_args = shlex.split(command)
532 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
533 description='''Find all heap allocations given one or more objective C class names.'''
534 parser = optparse.OptionParser(description=description, prog='object_refs',usage=usage)
535 add_common_options(parser)
536 try:
537 (options, args) = parser.parse_args(command_args)
538 except:
539 return
540
541 dylid_load_err = load_dylib()
542 if dylid_load_err:
Greg Clayton85df60c2012-09-01 00:34:35 +0000543 result.AppendMessage(dylid_load_err)
Greg Claytonab20f292012-08-11 02:26:26 +0000544 else:
545 if args:
546 for class_name in args:
547 addr_expr_str = "(void *)[%s class]" % class_name
548 expr_sbvalue = lldb.frame.EvaluateExpression (addr_expr_str)
549 if expr_sbvalue.error.Success():
550 isa = expr_sbvalue.unsigned
551 if isa:
552 options.type = 'isa'
Greg Claytona936c6e2012-09-12 02:02:32 +0000553 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 +0000554 heap_search (result, options, '0x%x' % isa)
Greg Claytonab20f292012-08-11 02:26:26 +0000555 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000556 result.AppendMessage('error: Can\'t find isa for an ObjC class named "%s"' % (class_name))
Greg Claytonab20f292012-08-11 02:26:26 +0000557 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000558 result.AppendMessage('error: expression error for "%s": %s' % (addr_expr_str, expr_sbvalue.error))
Greg Claytonab20f292012-08-11 02:26:26 +0000559 else:
Greg Claytonaaf7fad2012-09-04 14:09:21 +0000560 # Find all objective C objects by not specifying an isa
561 options.type = 'isa'
562 heap_search (result, options, '0x0')
Greg Claytonab20f292012-08-11 02:26:26 +0000563
Greg Clayton1dae6f32012-04-25 18:40:20 +0000564if __name__ == '__main__':
565 lldb.debugger = lldb.SBDebugger.Create()
566
567# This initializer is being run from LLDB in the embedded command interpreter
568# Add any commands contained in this module to LLDB
569lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.ptr_refs ptr_refs')
570lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.cstr_refs cstr_refs')
571lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.malloc_info malloc_info')
Greg Clayton393fc5f2012-09-11 18:10:27 +0000572lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.heap heap')
Greg Clayton4c5c4292012-07-11 22:13:18 +0000573lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.section_ptr_refs section_ptr_refs')
Greg Clayton130a3122012-10-08 22:39:38 +0000574lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.stack_ptr_refs stack_ptr_refs')
Greg Claytonab20f292012-08-11 02:26:26 +0000575lldb.debugger.HandleCommand('command script add -f lldb.macosx.heap.objc_refs objc_refs')
Greg Clayton130a3122012-10-08 22:39:38 +0000576print '"ptr_refs", "cstr_refs", "malloc_info", "heap", "section_ptr_refs" and "stack_ptr_refs" commands have been installed, use the "--help" options on these commands for detailed help.'
Greg Claytone93e24f2012-04-11 16:27:06 +0000577
578
579
580