blob: c3bf76eec042a20f1c95c9b124dc253087befc1d [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()
24
Greg Claytonad72e522013-02-01 00:47:49 +000025def get_iterate_memory_expr(options, process, user_init_code, user_return_code):
26 expr = '''
Greg Clayton549294a2013-01-31 06:38:09 +000027typedef unsigned natural_t;
Greg Clayton849acc82013-01-30 22:57:34 +000028typedef uintptr_t vm_size_t;
29typedef uintptr_t vm_address_t;
30typedef natural_t task_t;
31typedef int kern_return_t;
32#define KERN_SUCCESS 0
Greg Claytonad72e522013-02-01 00:47:49 +000033typedef void (*range_callback_t)(task_t task, void *baton, unsigned type, uintptr_t ptr_addr, uintptr_t ptr_size);
34''';
35 if options.search_vm_regions:
36 expr += '''
37typedef int vm_prot_t;
38typedef unsigned int vm_inherit_t;
39typedef unsigned long long memory_object_offset_t;
40typedef unsigned int boolean_t;
41typedef int vm_behavior_t;
42typedef uint32_t vm32_object_id_t;
43typedef natural_t mach_msg_type_number_t;
44typedef uint64_t mach_vm_address_t;
45typedef uint64_t mach_vm_offset_t;
46typedef uint64_t mach_vm_size_t;
47typedef uint64_t vm_map_offset_t;
48typedef uint64_t vm_map_address_t;
49typedef uint64_t vm_map_size_t;
50#define VM_PROT_NONE ((vm_prot_t) 0x00)
51#define VM_PROT_READ ((vm_prot_t) 0x01)
52#define VM_PROT_WRITE ((vm_prot_t) 0x02)
53#define VM_PROT_EXECUTE ((vm_prot_t) 0x04)
54typedef struct vm_region_submap_short_info_data_64_t {
55 vm_prot_t protection;
56 vm_prot_t max_protection;
57 vm_inherit_t inheritance;
58 memory_object_offset_t offset; // offset into object/map
59 unsigned int user_tag; // user tag on map entry
60 unsigned int ref_count; // obj/map mappers, etc
61 unsigned short shadow_depth; // only for obj
62 unsigned char external_pager; // only for obj
63 unsigned char share_mode; // see enumeration
64 boolean_t is_submap; // submap vs obj
65 vm_behavior_t behavior; // access behavior hint
66 vm32_object_id_t object_id; // obj/map name, not a handle
67 unsigned short user_wired_count;
68} vm_region_submap_short_info_data_64_t;
69#define VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 ((mach_msg_type_number_t)(sizeof(vm_region_submap_short_info_data_64_t)/sizeof(int)))''';
70 if user_init_code:
71 expr += user_init_code;
72 expr += '''
73task_t task = (task_t)mach_task_self();
74mach_vm_address_t vm_region_base_addr;
75mach_vm_size_t vm_region_size;
76natural_t vm_region_depth;
77vm_region_submap_short_info_data_64_t vm_region_info;
78kern_return_t err;
79for (vm_region_base_addr = 0, vm_region_size = 1; vm_region_size != 0; vm_region_base_addr += vm_region_size)
80{
81 mach_msg_type_number_t vm_region_info_size = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
82 err = (kern_return_t)mach_vm_region_recurse (task,
83 &vm_region_base_addr,
84 &vm_region_size,
85 &vm_region_depth,
86 &vm_region_info,
87 &vm_region_info_size);
88 if (err)
89 break;
90 // Check all read + write regions. This will cover the thread stacks
91 // and any regions of memory like __DATA segments, that might contain
92 // data we are looking for
93 if (vm_region_info.protection & VM_PROT_WRITE &&
94 vm_region_info.protection & VM_PROT_READ)
95 {
96 baton.callback (task,
97 &baton,
98 64,
99 vm_region_base_addr,
100 vm_region_size);
101 }
102}'''
103 else:
104 if options.search_stack:
105 expr += get_thread_stack_ranges_struct (process)
106 if options.search_segments:
107 expr += get_sections_ranges_struct (process)
108 if user_init_code:
109 expr += user_init_code
110 if options.search_heap:
111 expr += '''
Greg Clayton849acc82013-01-30 22:57:34 +0000112#define MALLOC_PTR_IN_USE_RANGE_TYPE 1
113typedef struct vm_range_t {
114 vm_address_t address;
115 vm_size_t size;
116} vm_range_t;
117typedef kern_return_t (*memory_reader_t)(task_t task, vm_address_t remote_address, vm_size_t size, void **local_memory);
118typedef void (*vm_range_recorder_t)(task_t task, void *baton, unsigned type, vm_range_t *range, unsigned size);
Greg Clayton849acc82013-01-30 22:57:34 +0000119typedef struct malloc_introspection_t {
120 kern_return_t (*enumerator)(task_t task, void *, unsigned type_mask, vm_address_t zone_address, memory_reader_t reader, vm_range_recorder_t recorder); /* enumerates all the malloc pointers in use */
121} malloc_introspection_t;
122typedef struct malloc_zone_t {
123 void *reserved1[12];
124 struct malloc_introspection_t *introspect;
125} malloc_zone_t;
126memory_reader_t task_peek = [](task_t task, vm_address_t remote_address, vm_size_t size, void **local_memory) -> kern_return_t {
127 *local_memory = (void*) remote_address;
128 return KERN_SUCCESS;
129};
130vm_address_t *zones = 0;
Greg Claytonad72e522013-02-01 00:47:49 +0000131unsigned int num_zones = 0;task_t task = 0;
Greg Clayton849acc82013-01-30 22:57:34 +0000132kern_return_t err = (kern_return_t)malloc_get_all_zones (task, task_peek, &zones, &num_zones);
133if (KERN_SUCCESS == err)
134{
135 for (unsigned int i=0; i<num_zones; ++i)
136 {
137 const malloc_zone_t *zone = (const malloc_zone_t *)zones[i];
138 if (zone && zone->introspect)
139 zone->introspect->enumerator (task,
140 &baton,
141 MALLOC_PTR_IN_USE_RANGE_TYPE,
142 (vm_address_t)zone,
143 task_peek,
144 [] (task_t task, void *baton, unsigned type, vm_range_t *ranges, unsigned size) -> void
145 {
146 range_callback_t callback = ((callback_baton_t *)baton)->callback;
147 for (unsigned i=0; i<size; ++i)
148 {
149 callback (task, baton, type, ranges[i].address, ranges[i].size);
150 }
151 });
152 }
Greg Claytonad72e522013-02-01 00:47:49 +0000153}'''
154
155 if options.search_stack:
156 expr += '''
Greg Clayton549294a2013-01-31 06:38:09 +0000157// Call the callback for the thread stack ranges
Greg Claytonad72e522013-02-01 00:47:49 +0000158for (uint32_t i=0; i<NUM_STACKS; ++i) {
Greg Clayton549294a2013-01-31 06:38:09 +0000159 range_callback(task, &baton, 8, stacks[i].base, stacks[i].size);
Greg Claytonad72e522013-02-01 00:47:49 +0000160 if (STACK_RED_ZONE_SIZE > 0) {
161 range_callback(task, &baton, 16, stacks[i].base - STACK_RED_ZONE_SIZE, STACK_RED_ZONE_SIZE);
162 }
163}
164 '''
165
166 if options.search_segments:
167 expr += '''
Greg Clayton549294a2013-01-31 06:38:09 +0000168// Call the callback for all segments
169for (uint32_t i=0; i<NUM_SEGMENTS; ++i)
Greg Claytonad72e522013-02-01 00:47:49 +0000170 range_callback(task, &baton, 32, segments[i].base, segments[i].size);'''
171
172 if user_return_code:
173 expr += "\n%s" % (user_return_code,)
174
175 return expr
Greg Clayton0d0f56d2012-07-07 01:22:45 +0000176
177def get_member_types_for_offset(value_type, offset, member_list):
178 member = value_type.GetFieldAtIndex(0)
179 search_bases = False
180 if member:
181 if member.GetOffsetInBytes() <= offset:
182 for field_idx in range (value_type.GetNumberOfFields()):
183 member = value_type.GetFieldAtIndex(field_idx)
184 member_byte_offset = member.GetOffsetInBytes()
185 member_end_byte_offset = member_byte_offset + member.type.size
186 if member_byte_offset <= offset and offset < member_end_byte_offset:
187 member_list.append(member)
188 get_member_types_for_offset (member.type, offset - member_byte_offset, member_list)
189 return
190 else:
191 search_bases = True
192 else:
193 search_bases = True
194 if search_bases:
195 for field_idx in range (value_type.GetNumberOfDirectBaseClasses()):
196 member = value_type.GetDirectBaseClassAtIndex(field_idx)
197 member_byte_offset = member.GetOffsetInBytes()
198 member_end_byte_offset = member_byte_offset + member.type.size
199 if member_byte_offset <= offset and offset < member_end_byte_offset:
200 member_list.append(member)
201 get_member_types_for_offset (member.type, offset - member_byte_offset, member_list)
202 return
203 for field_idx in range (value_type.GetNumberOfVirtualBaseClasses()):
204 member = value_type.GetVirtualBaseClassAtIndex(field_idx)
205 member_byte_offset = member.GetOffsetInBytes()
206 member_end_byte_offset = member_byte_offset + member.type.size
207 if member_byte_offset <= offset and offset < member_end_byte_offset:
208 member_list.append(member)
209 get_member_types_for_offset (member.type, offset - member_byte_offset, member_list)
210 return
Greg Clayton4c5c4292012-07-11 22:13:18 +0000211
212def append_regex_callback(option, opt, value, parser):
213 try:
214 ivar_regex = re.compile(value)
215 parser.values.ivar_regex_blacklist.append(ivar_regex)
216 except:
217 print 'error: an exception was thrown when compiling the ivar regular expression for "%s"' % value
Greg Clayton9098fee2012-04-21 00:11:26 +0000218
Greg Clayton93e5ba52012-04-13 16:24:09 +0000219def add_common_options(parser):
220 parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000221 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 +0000222 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 +0000223 parser.add_option('-z', '--size', action='store_true', dest='show_size', help='print the allocation size in bytes', default=False)
224 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 +0000225 parser.add_option('-m', '--memory', action='store_true', dest='memory', help='dump the memory for each matching block', default=False)
226 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 +0000227 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 +0000228 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 +0000229 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 Clayton849acc82013-01-30 22:57:34 +0000230 parser.add_option('-F', '--max-frames', type='int', dest='max_frames', help='the maximum number of stack frames to print when using the --stack or --stack-history options (default=128)', default=128)
231 parser.add_option('-H', '--max-history', type='int', dest='max_history', help='the maximum number of stack history backtraces to print for each allocation when using the --stack-history option (default=16)', default=16)
Greg Clayton549294a2013-01-31 06:38:09 +0000232 parser.add_option('-M', '--max-matches', type='int', dest='max_matches', help='the maximum number of matches to print', default=32)
Greg Claytonab20f292012-08-11 02:26:26 +0000233 parser.add_option('-O', '--offset', type='int', dest='offset', help='the matching data must be at this offset', default=-1)
Greg Claytonad72e522013-02-01 00:47:49 +0000234 parser.add_option('--ignore-stack', action='store_false', dest='search_stack', help="Don't search the stack when enumerating memory", default=True)
235 parser.add_option('--ignore-heap', action='store_false', dest='search_heap', help="Don't search the heap allocations when enumerating memory", default=True)
236 parser.add_option('--ignore-segments', action='store_false', dest='search_segments', help="Don't search readable executable segments enumerating memory", default=True)
237 parser.add_option('-V', '--vm-regions', action='store_true', dest='search_vm_regions', help='Check all VM regions instead of searching the heap, stack and segments', default=False)
Greg Clayton7a245762012-05-10 23:17:28 +0000238
Greg Clayton849acc82013-01-30 22:57:34 +0000239def type_flags_to_string(type_flags):
240 if type_flags == 0:
241 type_str = 'free'
242 elif type_flags & 2:
243 type_str = 'malloc'
244 elif type_flags & 4:
245 type_str = 'free'
246 elif type_flags & 1:
247 type_str = 'generic'
248 elif type_flags & 8:
249 type_str = 'stack'
Greg Clayton549294a2013-01-31 06:38:09 +0000250 elif type_flags & 16:
Greg Claytonad72e522013-02-01 00:47:49 +0000251 type_str = 'stack (red zone)'
252 elif type_flags & 32:
Greg Clayton549294a2013-01-31 06:38:09 +0000253 type_str = 'segment'
Greg Claytonad72e522013-02-01 00:47:49 +0000254 elif type_flags & 64:
255 type_str = 'vm_region'
Greg Clayton849acc82013-01-30 22:57:34 +0000256 else:
257 type_str = hex(type_flags)
258 return type_str
259
Greg Clayton549294a2013-01-31 06:38:09 +0000260def type_flags_to_description(type_flags, ptr_addr, ptr_size, offset):
261 show_offset = False
Greg Clayton849acc82013-01-30 22:57:34 +0000262 if type_flags == 0 or type_flags & 4:
263 type_str = 'free(%#x)' % (ptr_addr,)
264 elif type_flags & 2 or type_flags & 1:
Greg Clayton549294a2013-01-31 06:38:09 +0000265 type_str = 'malloc(%6u) -> %#x' % (ptr_size, ptr_addr)
266 show_offset = True
Greg Clayton849acc82013-01-30 22:57:34 +0000267 elif type_flags & 8:
Greg Clayton549294a2013-01-31 06:38:09 +0000268 type_str = 'stack'
269 elif type_flags & 16:
Greg Claytonad72e522013-02-01 00:47:49 +0000270 type_str = 'stack (red zone)'
271 elif type_flags & 32:
Greg Clayton549294a2013-01-31 06:38:09 +0000272 sb_addr = lldb.debugger.GetSelectedTarget().ResolveLoadAddress(ptr_addr + offset)
273 type_str = 'segment [%#x - %#x), %s + %u, %s' % (ptr_addr, ptr_addr + ptr_size, sb_addr.section.name, sb_addr.offset, sb_addr)
Greg Claytonad72e522013-02-01 00:47:49 +0000274 elif type_flags & 64:
275 sb_addr = lldb.debugger.GetSelectedTarget().ResolveLoadAddress(ptr_addr + offset)
276 type_str = 'vm_region [%#x - %#x), %s + %u, %s' % (ptr_addr, ptr_addr + ptr_size, sb_addr.section.name, sb_addr.offset, sb_addr)
Greg Clayton849acc82013-01-30 22:57:34 +0000277 else:
Greg Clayton549294a2013-01-31 06:38:09 +0000278 type_str = '%#x' % (ptr_addr,)
279 show_offset = True
280 if show_offset and offset != 0:
281 type_str += ' + %-6u' % (offset,)
Greg Clayton849acc82013-01-30 22:57:34 +0000282 return type_str
283
284def dump_stack_history_entry(options, result, stack_history_entry, idx):
Greg Clayton6f446f32012-05-10 23:37:52 +0000285 address = int(stack_history_entry.address)
286 if address:
287 type_flags = int(stack_history_entry.type_flags)
Greg Clayton7a245762012-05-10 23:17:28 +0000288 symbolicator = lldb.utils.symbolication.Symbolicator()
Greg Clayton849acc82013-01-30 22:57:34 +0000289 symbolicator.target = lldb.debugger.GetSelectedTarget()
290 type_str = type_flags_to_string(type_flags)
Greg Clayton85df60c2012-09-01 00:34:35 +0000291 result.AppendMessage('stack[%u]: addr = 0x%x, type=%s, frames:' % (idx, address, type_str))
Greg Clayton7a245762012-05-10 23:17:28 +0000292 frame_idx = 0
Greg Clayton6f446f32012-05-10 23:37:52 +0000293 idx = 0
294 pc = int(stack_history_entry.frames[idx])
Greg Clayton7a245762012-05-10 23:17:28 +0000295 while pc != 0:
296 if pc >= 0x1000:
297 frames = symbolicator.symbolicate(pc)
298 if frames:
299 for frame in frames:
Greg Clayton85df60c2012-09-01 00:34:35 +0000300 result.AppendMessage(' [%u] %s' % (frame_idx, frame))
Greg Clayton7a245762012-05-10 23:17:28 +0000301 frame_idx += 1
302 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000303 result.AppendMessage(' [%u] 0x%x' % (frame_idx, pc))
Greg Clayton7a245762012-05-10 23:17:28 +0000304 frame_idx += 1
Greg Clayton6f446f32012-05-10 23:37:52 +0000305 idx = idx + 1
306 pc = int(stack_history_entry.frames[idx])
Greg Clayton7a245762012-05-10 23:17:28 +0000307 else:
308 pc = 0
Greg Clayton849acc82013-01-30 22:57:34 +0000309 if idx >= options.max_frames:
310 result.AppendMessage('warning: the max number of stack frames (%u) was reached, use the "--max-frames=<COUNT>" option to see more frames' % (options.max_frames))
311
Greg Clayton85df60c2012-09-01 00:34:35 +0000312 result.AppendMessage('')
Greg Clayton7a245762012-05-10 23:17:28 +0000313
Greg Clayton849acc82013-01-30 22:57:34 +0000314def dump_stack_history_entries(options, result, addr, history):
Greg Clayton7a245762012-05-10 23:17:28 +0000315 # malloc_stack_entry *get_stack_history_for_address (const void * addr)
Greg Clayton549294a2013-01-31 06:38:09 +0000316 single_expr = '''
317typedef int kern_return_t;
Greg Clayton849acc82013-01-30 22:57:34 +0000318#define MAX_FRAMES %u
319typedef struct $malloc_stack_entry {
320 uint64_t address;
321 uint64_t argument;
322 uint32_t type_flags;
323 uint32_t num_frames;
324 uint64_t frames[512];
325 kern_return_t err;
326} $malloc_stack_entry;
327typedef unsigned task_t;
328$malloc_stack_entry stack;
329stack.address = 0x%x;
330stack.type_flags = 2;
331stack.num_frames = 0;
332stack.frames[0] = 0;
333uint32_t max_stack_frames = MAX_FRAMES;
334stack.err = (kern_return_t)__mach_stack_logging_get_frames (
335 (task_t)mach_task_self(),
336 stack.address,
337 &stack.frames[0],
338 max_stack_frames,
339 &stack.num_frames);
340if (stack.num_frames < MAX_FRAMES)
341 stack.frames[stack.num_frames] = 0;
342else
343 stack.frames[MAX_FRAMES-1] = 0;
344stack''' % (options.max_frames, addr);
345
Greg Clayton549294a2013-01-31 06:38:09 +0000346 history_expr = '''
347typedef int kern_return_t;
Greg Clayton849acc82013-01-30 22:57:34 +0000348typedef unsigned task_t;
349#define MAX_FRAMES %u
350#define MAX_HISTORY %u
351typedef struct mach_stack_logging_record_t {
352 uint32_t type_flags;
353 uint64_t stack_identifier;
354 uint64_t argument;
355 uint64_t address;
356} mach_stack_logging_record_t;
357typedef void (*enumerate_callback_t)(mach_stack_logging_record_t, void *);
358typedef struct malloc_stack_entry {
359 uint64_t address;
360 uint64_t argument;
361 uint32_t type_flags;
362 uint32_t num_frames;
363 uint64_t frames[MAX_FRAMES];
364 kern_return_t frames_err;
365} malloc_stack_entry;
366typedef struct $malloc_stack_history {
367 task_t task;
368 unsigned idx;
369 malloc_stack_entry entries[MAX_HISTORY];
370} $malloc_stack_history;
371$malloc_stack_history info = { (task_t)mach_task_self(), 0 };
372uint32_t max_stack_frames = MAX_FRAMES;
373enumerate_callback_t callback = [] (mach_stack_logging_record_t stack_record, void *baton) -> void {
374 $malloc_stack_history *info = ($malloc_stack_history *)baton;
375 if (info->idx < MAX_HISTORY) {
376 malloc_stack_entry *stack_entry = &(info->entries[info->idx]);
377 stack_entry->address = stack_record.address;
378 stack_entry->type_flags = stack_record.type_flags;
379 stack_entry->argument = stack_record.argument;
380 stack_entry->num_frames = 0;
381 stack_entry->frames[0] = 0;
382 stack_entry->frames_err = (kern_return_t)__mach_stack_logging_frames_for_uniqued_stack (
383 info->task,
384 stack_record.stack_identifier,
385 stack_entry->frames,
386 (uint32_t)MAX_FRAMES,
387 &stack_entry->num_frames);
388 // Terminate the frames with zero if there is room
389 if (stack_entry->num_frames < MAX_FRAMES)
390 stack_entry->frames[stack_entry->num_frames] = 0;
391 }
392 ++info->idx;
393};
394(kern_return_t)__mach_stack_logging_enumerate_records (info.task, (uint64_t)0x%x, callback, &info);
395info''' % (options.max_frames, options.max_history, addr);
396
397 frame = lldb.debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
398 if history:
399 expr = history_expr
400 else:
401 expr = single_expr
402 expr_sbvalue = frame.EvaluateExpression (expr)
403 if options.verbose:
404 print "expression:"
405 print expr
406 print "expression result:"
407 print expr_sbvalue
408 if expr_sbvalue.error.Success():
409 if history:
410 malloc_stack_history = lldb.value(expr_sbvalue)
411 num_stacks = int(malloc_stack_history.idx)
412 if num_stacks <= options.max_history:
413 i_max = num_stacks
414 else:
415 i_max = options.max_history
416 for i in range(i_max):
417 stack_history_entry = malloc_stack_history.entries[i]
418 dump_stack_history_entry(options, result, stack_history_entry, i)
419 if num_stacks > options.max_history:
420 result.AppendMessage('warning: the max number of stacks (%u) was reached, use the "--max-history=%u" option to see all of the stacks' % (options.max_history, num_stacks))
421 else:
422 stack_history_entry = lldb.value(expr_sbvalue)
423 dump_stack_history_entry(options, result, stack_history_entry, 0)
424
425 else:
426 result.AppendMessage('error: expression failed "%s" => %s' % (expr, expr_sbvalue.error))
427
428
429def display_match_results (result, options, arg_str_description, expr, print_no_matches = True):
430 frame = lldb.debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
431 if not frame:
432 result.AppendMessage('error: invalid frame')
433 return 0
434 expr_sbvalue = frame.EvaluateExpression (expr)
435 if options.verbose:
436 print "expression:"
437 print expr
438 print "expression result:"
439 print expr_sbvalue
Greg Clayton96666442012-04-11 18:30:53 +0000440 if expr_sbvalue.error.Success():
441 if expr_sbvalue.unsigned:
442 match_value = lldb.value(expr_sbvalue)
443 i = 0
Greg Claytonab20f292012-08-11 02:26:26 +0000444 match_idx = 0
Greg Clayton96666442012-04-11 18:30:53 +0000445 while 1:
Greg Clayton4c5c4292012-07-11 22:13:18 +0000446 print_entry = True
Greg Clayton96666442012-04-11 18:30:53 +0000447 match_entry = match_value[i]; i += 1
Greg Clayton849acc82013-01-30 22:57:34 +0000448 if i > options.max_matches:
449 result.AppendMessage('warning: 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 +0000450 break
Greg Clayton96666442012-04-11 18:30:53 +0000451 malloc_addr = match_entry.addr.sbvalue.unsigned
452 if malloc_addr == 0:
453 break
454 malloc_size = int(match_entry.size)
455 offset = int(match_entry.offset)
Greg Claytonab20f292012-08-11 02:26:26 +0000456
457 if options.offset >= 0 and options.offset != offset:
458 print_entry = False
459 else:
460 match_addr = malloc_addr + offset
Greg Clayton849acc82013-01-30 22:57:34 +0000461 type_flags = int(match_entry.type)
Greg Claytonad72e522013-02-01 00:47:49 +0000462 #result.AppendMessage (hex(malloc_addr + offset))
463 if type_flags == 64:
464 search_stack_old = options.search_stack
465 search_segments_old = options.search_segments
466 search_heap_old = options.search_heap
467 search_vm_regions = options.search_vm_regions
468 options.search_stack = True
469 options.search_segments = True
470 options.search_heap = True
471 options.search_vm_regions = False
472 if malloc_info_impl (lldb.debugger, result, options, [hex(malloc_addr + offset)]):
473 print_entry = False
474 options.search_stack = search_stack_old
475 options.search_segments = search_segments_old
476 options.search_heap = search_heap_old
477 options.search_vm_regions = search_vm_regions
478 if print_entry:
479 description = '%#16.16x: %s' % (match_addr, type_flags_to_description(type_flags, malloc_addr, malloc_size, offset))
480 if options.show_size:
481 description += ' <%5u>' % (malloc_size)
482 if options.show_range:
483 description += ' [%#x - %#x)' % (malloc_addr, malloc_addr + malloc_size)
484 derefed_dynamic_value = None
485 dynamic_value = match_entry.addr.sbvalue.GetDynamicValue(lldb.eDynamicCanRunTarget)
486 if dynamic_value.type.name == 'void *':
487 if options.type == 'pointer' and malloc_size == 4096:
488 error = lldb.SBError()
489 process = expr_sbvalue.GetProcess()
490 target = expr_sbvalue.GetTarget()
491 data = bytearray(process.ReadMemory(malloc_addr, 16, error))
492 if data == '\xa1\xa1\xa1\xa1AUTORELEASE!':
493 ptr_size = target.addr_size
494 thread = process.ReadUnsignedFromMemory (malloc_addr + 16 + ptr_size, ptr_size, error)
495 # 4 bytes 0xa1a1a1a1
496 # 12 bytes 'AUTORELEASE!'
497 # ptr bytes autorelease insertion point
498 # ptr bytes pthread_t
499 # ptr bytes next colder page
500 # ptr bytes next hotter page
501 # 4 bytes this page's depth in the list
502 # 4 bytes high-water mark
503 description += ' AUTORELEASE! for pthread_t %#x' % (thread)
504 # else:
505 # description += 'malloc(%u)' % (malloc_size)
506 # else:
507 # description += 'malloc(%u)' % (malloc_size)
Greg Claytona936c6e2012-09-12 02:02:32 +0000508 else:
Greg Claytonad72e522013-02-01 00:47:49 +0000509 derefed_dynamic_value = dynamic_value.deref
510 if derefed_dynamic_value:
511 derefed_dynamic_type = derefed_dynamic_value.type
512 derefed_dynamic_type_size = derefed_dynamic_type.size
513 derefed_dynamic_type_name = derefed_dynamic_type.name
514 description += ' '
515 description += derefed_dynamic_type_name
516 if offset < derefed_dynamic_type_size:
517 member_list = list();
518 get_member_types_for_offset (derefed_dynamic_type, offset, member_list)
519 if member_list:
520 member_path = ''
521 for member in member_list:
522 member_name = member.name
523 if member_name:
524 if member_path:
525 member_path += '.'
526 member_path += member_name
527 if member_path:
528 if options.ivar_regex_blacklist:
529 for ivar_regex in options.ivar_regex_blacklist:
530 if ivar_regex.match(member_path):
531 print_entry = False
532 description += '.%s' % (member_path)
533 else:
534 description += '%u bytes after %s' % (offset - derefed_dynamic_type_size, derefed_dynamic_type_name)
535 else:
536 # strip the "*" from the end of the name since we were unable to dereference this
537 description += dynamic_value.type.name[0:-1]
Greg Clayton4c5c4292012-07-11 22:13:18 +0000538 if print_entry:
Greg Claytonab20f292012-08-11 02:26:26 +0000539 match_idx += 1
Greg Claytonaaf7fad2012-09-04 14:09:21 +0000540 result_output = ''
Greg Clayton4c5c4292012-07-11 22:13:18 +0000541 if description:
Greg Claytonaaf7fad2012-09-04 14:09:21 +0000542 result_output += description
Greg Clayton4c5c4292012-07-11 22:13:18 +0000543 if options.print_type and derefed_dynamic_value:
Greg Clayton549294a2013-01-31 06:38:09 +0000544 result_output += ' %s' % (derefed_dynamic_value)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000545 if options.print_object_description and dynamic_value:
546 desc = dynamic_value.GetObjectDescription()
547 if desc:
Greg Claytona936c6e2012-09-12 02:02:32 +0000548 result_output += '\n%s' % (desc)
Greg Claytonaaf7fad2012-09-04 14:09:21 +0000549 if result_output:
550 result.AppendMessage(result_output)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000551 if options.memory:
552 cmd_result = lldb.SBCommandReturnObject()
Greg Clayton849acc82013-01-30 22:57:34 +0000553 if options.format == None:
554 memory_command = "memory read --force 0x%x 0x%x" % (malloc_addr, malloc_addr + malloc_size)
555 else:
556 memory_command = "memory read --force -f %s 0x%x 0x%x" % (options.format, malloc_addr, malloc_addr + malloc_size)
557 if options.verbose:
558 result.AppendMessage(memory_command)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000559 lldb.debugger.GetCommandInterpreter().HandleCommand(memory_command, cmd_result)
Greg Clayton85df60c2012-09-01 00:34:35 +0000560 result.AppendMessage(cmd_result.GetOutput())
Greg Clayton4c5c4292012-07-11 22:13:18 +0000561 if options.stack_history:
Greg Clayton549294a2013-01-31 06:38:09 +0000562 dump_stack_history_entries(options, result, malloc_addr, 1)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000563 elif options.stack:
Greg Clayton549294a2013-01-31 06:38:09 +0000564 dump_stack_history_entries(options, result, malloc_addr, 0)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000565 return i
566 elif print_no_matches:
Greg Clayton85df60c2012-09-01 00:34:35 +0000567 result.AppendMessage('no matches found for %s' % (arg_str_description))
Greg Clayton96666442012-04-11 18:30:53 +0000568 else:
Greg Claytonaaf7fad2012-09-04 14:09:21 +0000569 result.AppendMessage(str(expr_sbvalue.error))
Greg Clayton4c5c4292012-07-11 22:13:18 +0000570 return 0
571
Greg Clayton849acc82013-01-30 22:57:34 +0000572def get_ptr_refs_options ():
573 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
574 description='''Searches all allocations on the heap for pointer values on
575darwin user space programs. Any matches that were found will dump the malloc
576blocks that contain the pointers and might be able to print what kind of
577objects the pointers are contained in using dynamic type information in the
578program.'''
579 parser = optparse.OptionParser(description=description, prog='ptr_refs',usage=usage)
580 add_common_options(parser)
581 return parser
Greg Clayton96666442012-04-11 18:30:53 +0000582
Greg Claytonbff78412012-04-12 18:57:36 +0000583def ptr_refs(debugger, command, result, dict):
Greg Claytone93e24f2012-04-11 16:27:06 +0000584 command_args = shlex.split(command)
Greg Clayton849acc82013-01-30 22:57:34 +0000585 parser = get_ptr_refs_options()
Greg Claytone93e24f2012-04-11 16:27:06 +0000586 try:
587 (options, args) = parser.parse_args(command_args)
588 except:
589 return
Greg Clayton96666442012-04-11 18:30:53 +0000590
Greg Clayton849acc82013-01-30 22:57:34 +0000591 process = lldb.debugger.GetSelectedTarget().GetProcess()
592 if not process:
593 result.AppendMessage('error: invalid process')
594 return
595 frame = process.GetSelectedThread().GetSelectedFrame()
596 if not frame:
597 result.AppendMessage('error: invalid frame')
598 return
599
Greg Clayton96666442012-04-11 18:30:53 +0000600 options.type = 'pointer'
Greg Clayton849acc82013-01-30 22:57:34 +0000601 if options.format == None:
602 options.format = "A" # 'A' is "address" format
603
Greg Claytone93e24f2012-04-11 16:27:06 +0000604 if args:
Greg Clayton849acc82013-01-30 22:57:34 +0000605 # When we initialize the expression, we must define any types that
606 # we will need when looking at every allocation. We must also define
607 # a type named callback_baton_t and make an instance named "baton"
608 # and initialize it how ever we want to. The address of "baton" will
609 # be passed into our range callback. callback_baton_t must contain
610 # a member named "callback" whose type is "range_callback_t". This
611 # will be used by our zone callbacks to call the range callback for
612 # each malloc range.
Greg Clayton549294a2013-01-31 06:38:09 +0000613 user_init_code_format = '''
614#define MAX_MATCHES %u
Greg Clayton849acc82013-01-30 22:57:34 +0000615struct $malloc_match {
616 void *addr;
617 uintptr_t size;
618 uintptr_t offset;
619 uintptr_t type;
620};
621typedef struct callback_baton_t {
622 range_callback_t callback;
623 unsigned num_matches;
Greg Clayton549294a2013-01-31 06:38:09 +0000624 $malloc_match matches[MAX_MATCHES];
Greg Clayton849acc82013-01-30 22:57:34 +0000625 void *ptr;
626} callback_baton_t;
627range_callback_t range_callback = [](task_t task, void *baton, unsigned type, uintptr_t ptr_addr, uintptr_t ptr_size) -> void {
628 callback_baton_t *info = (callback_baton_t *)baton;
629 typedef void* T;
630 const unsigned size = sizeof(T);
631 T *array = (T*)ptr_addr;
632 for (unsigned idx = 0; ((idx + 1) * sizeof(T)) <= ptr_size; ++idx) {
633 if (array[idx] == info->ptr) {
Greg Clayton549294a2013-01-31 06:38:09 +0000634 if (info->num_matches < MAX_MATCHES) {
Greg Clayton849acc82013-01-30 22:57:34 +0000635 info->matches[info->num_matches].addr = (void*)ptr_addr;
636 info->matches[info->num_matches].size = ptr_size;
637 info->matches[info->num_matches].offset = idx*sizeof(T);
638 info->matches[info->num_matches].type = type;
639 ++info->num_matches;
640 }
641 }
642 }
643};
644callback_baton_t baton = { range_callback, 0, {0}, (void *)%s };
645'''
646 # We must also define a snippet of code to be run that returns
647 # the result of the expression we run.
648 # Here we return NULL if our pointer was not found in any malloc blocks,
649 # and we return the address of the matches array so we can then access
650 # the matching results
Greg Clayton549294a2013-01-31 06:38:09 +0000651 user_return_code = '''if (baton.num_matches < MAX_MATCHES)
652 baton.matches[baton.num_matches].addr = 0; // Terminate the matches array
Greg Clayton849acc82013-01-30 22:57:34 +0000653baton.matches'''
654 # Iterate through all of our pointer expressions and display the results
655 for ptr_expr in args:
Greg Clayton549294a2013-01-31 06:38:09 +0000656 user_init_code = user_init_code_format % (options.max_matches, ptr_expr)
Greg Claytonad72e522013-02-01 00:47:49 +0000657 expr = get_iterate_memory_expr(options, process, user_init_code, user_return_code)
Greg Clayton849acc82013-01-30 22:57:34 +0000658 arg_str_description = 'malloc block containing pointer %s' % ptr_expr
659 display_match_results (result, options, arg_str_description, expr)
Greg Claytone93e24f2012-04-11 16:27:06 +0000660 else:
Greg Clayton849acc82013-01-30 22:57:34 +0000661 result.AppendMessage('error: no pointer arguments were given')
662
663def get_cstr_refs_options():
664 usage = "usage: %prog [options] <CSTR> [CSTR ...]"
665 description='''Searches all allocations on the heap for C string values on
666darwin user space programs. Any matches that were found will dump the malloc
667blocks that contain the C strings and might be able to print what kind of
668objects the pointers are contained in using dynamic type information in the
669program.'''
670 parser = optparse.OptionParser(description=description, prog='cstr_refs',usage=usage)
671 add_common_options(parser)
672 return parser
Greg Claytone93e24f2012-04-11 16:27:06 +0000673
Greg Claytonbff78412012-04-12 18:57:36 +0000674def cstr_refs(debugger, command, result, dict):
Greg Clayton96666442012-04-11 18:30:53 +0000675 command_args = shlex.split(command)
Greg Clayton849acc82013-01-30 22:57:34 +0000676 parser = get_cstr_refs_options();
Greg Clayton96666442012-04-11 18:30:53 +0000677 try:
678 (options, args) = parser.parse_args(command_args)
679 except:
680 return
681
Greg Clayton549294a2013-01-31 06:38:09 +0000682 process = lldb.debugger.GetSelectedTarget().GetProcess()
683 if not process:
684 result.AppendMessage('error: invalid process')
685 return
686 frame = process.GetSelectedThread().GetSelectedFrame()
Greg Clayton849acc82013-01-30 22:57:34 +0000687 if not frame:
688 result.AppendMessage('error: invalid frame')
689 return
690
Greg Clayton549294a2013-01-31 06:38:09 +0000691
Greg Clayton96666442012-04-11 18:30:53 +0000692 options.type = 'cstr'
Greg Clayton849acc82013-01-30 22:57:34 +0000693 if options.format == None:
694 options.format = "Y" # 'Y' is "bytes with ASCII" format
Greg Clayton96666442012-04-11 18:30:53 +0000695
696 if args:
Greg Clayton849acc82013-01-30 22:57:34 +0000697 # When we initialize the expression, we must define any types that
698 # we will need when looking at every allocation. We must also define
699 # a type named callback_baton_t and make an instance named "baton"
700 # and initialize it how ever we want to. The address of "baton" will
701 # be passed into our range callback. callback_baton_t must contain
702 # a member named "callback" whose type is "range_callback_t". This
703 # will be used by our zone callbacks to call the range callback for
704 # each malloc range.
Greg Clayton549294a2013-01-31 06:38:09 +0000705 user_init_code_format = '''
706#define MAX_MATCHES %u
707struct $malloc_match {
Greg Clayton849acc82013-01-30 22:57:34 +0000708 void *addr;
709 uintptr_t size;
710 uintptr_t offset;
711 uintptr_t type;
712};
713typedef struct callback_baton_t {
714 range_callback_t callback;
715 unsigned num_matches;
Greg Clayton549294a2013-01-31 06:38:09 +0000716 $malloc_match matches[MAX_MATCHES];
Greg Clayton849acc82013-01-30 22:57:34 +0000717 const char *cstr;
718 unsigned cstr_len;
719} callback_baton_t;
720range_callback_t range_callback = [](task_t task, void *baton, unsigned type, uintptr_t ptr_addr, uintptr_t ptr_size) -> void {
721 callback_baton_t *info = (callback_baton_t *)baton;
722 if (info->cstr_len < ptr_size) {
723 const char *begin = (const char *)ptr_addr;
724 const char *end = begin + ptr_size - info->cstr_len;
725 for (const char *s = begin; s < end; ++s) {
726 if ((int)memcmp(s, info->cstr, info->cstr_len) == 0) {
Greg Clayton549294a2013-01-31 06:38:09 +0000727 if (info->num_matches < MAX_MATCHES) {
Greg Clayton849acc82013-01-30 22:57:34 +0000728 info->matches[info->num_matches].addr = (void*)ptr_addr;
729 info->matches[info->num_matches].size = ptr_size;
730 info->matches[info->num_matches].offset = s - begin;
731 info->matches[info->num_matches].type = type;
732 ++info->num_matches;
733 }
734 }
735 }
736 }
737};
738const char *cstr = "%s";
739callback_baton_t baton = { range_callback, 0, {0}, cstr, (unsigned)strlen(cstr) };'''
740 # We must also define a snippet of code to be run that returns
741 # the result of the expression we run.
742 # Here we return NULL if our pointer was not found in any malloc blocks,
743 # and we return the address of the matches array so we can then access
744 # the matching results
Greg Clayton549294a2013-01-31 06:38:09 +0000745 user_return_code = '''if (baton.num_matches < MAX_MATCHES)
746 baton.matches[baton.num_matches].addr = 0; // Terminate the matches array
747baton.matches'''
Greg Clayton849acc82013-01-30 22:57:34 +0000748 # Iterate through all of our pointer expressions and display the results
749 for cstr in args:
Greg Clayton549294a2013-01-31 06:38:09 +0000750 user_init_code = user_init_code_format % (options.max_matches, cstr)
Greg Claytonad72e522013-02-01 00:47:49 +0000751 expr = get_iterate_memory_expr(options, process, user_init_code, user_return_code)
Greg Clayton849acc82013-01-30 22:57:34 +0000752 arg_str_description = 'malloc block containing "%s"' % cstr
753 display_match_results (result, options, arg_str_description, expr)
Greg Clayton96666442012-04-11 18:30:53 +0000754 else:
Greg Clayton849acc82013-01-30 22:57:34 +0000755 result.AppendMessage('error: command takes one or more C string arguments')
756
757
758def get_malloc_info_options():
759 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
760 description='''Searches the heap a malloc block that contains the addresses
761specified as one or more address expressions. Any matches that were found will
762dump the malloc blocks that match or contain the specified address. The matching
763blocks might be able to show what kind of objects they are using dynamic type
764information in the program.'''
765 parser = optparse.OptionParser(description=description, prog='malloc_info',usage=usage)
766 add_common_options(parser)
767 return parser
Greg Claytone93e24f2012-04-11 16:27:06 +0000768
Greg Claytonbff78412012-04-12 18:57:36 +0000769def malloc_info(debugger, command, result, dict):
770 command_args = shlex.split(command)
Greg Clayton849acc82013-01-30 22:57:34 +0000771 parser = get_malloc_info_options()
Greg Claytonbff78412012-04-12 18:57:36 +0000772 try:
773 (options, args) = parser.parse_args(command_args)
774 except:
775 return
Greg Claytonad72e522013-02-01 00:47:49 +0000776 malloc_info_impl (debugger, result, options, args)
777
778def malloc_info_impl (debugger, result, options, args):
779 # We are specifically looking for something on the heap only
780 options.type = 'malloc_info'
Greg Clayton549294a2013-01-31 06:38:09 +0000781
782 process = lldb.debugger.GetSelectedTarget().GetProcess()
783 if not process:
784 result.AppendMessage('error: invalid process')
785 return
786 frame = process.GetSelectedThread().GetSelectedFrame()
787 if not frame:
788 result.AppendMessage('error: invalid frame')
789 return
Greg Clayton849acc82013-01-30 22:57:34 +0000790
Greg Clayton549294a2013-01-31 06:38:09 +0000791 user_init_code_format = '''
792struct $malloc_match {
Greg Clayton849acc82013-01-30 22:57:34 +0000793 void *addr;
794 uintptr_t size;
795 uintptr_t offset;
796 uintptr_t type;
797};
798typedef struct callback_baton_t {
799 range_callback_t callback;
800 unsigned num_matches;
801 $malloc_match matches[2]; // Two items so they can be NULL terminated
802 void *ptr;
803} callback_baton_t;
804range_callback_t range_callback = [](task_t task, void *baton, unsigned type, uintptr_t ptr_addr, uintptr_t ptr_size) -> void {
805 callback_baton_t *info = (callback_baton_t *)baton;
806 if (info->num_matches == 0) {
807 uint8_t *p = (uint8_t *)info->ptr;
808 uint8_t *lo = (uint8_t *)ptr_addr;
809 uint8_t *hi = lo + ptr_size;
810 if (lo <= p && p < hi) {
811 info->matches[info->num_matches].addr = (void*)ptr_addr;
812 info->matches[info->num_matches].size = ptr_size;
813 info->matches[info->num_matches].offset = p - lo;
814 info->matches[info->num_matches].type = type;
815 info->num_matches = 1;
816 }
817 }
818};
819callback_baton_t baton = { range_callback, 0, {0}, (void *)%s };
Greg Clayton549294a2013-01-31 06:38:09 +0000820baton.matches[0].addr = 0;
Greg Clayton849acc82013-01-30 22:57:34 +0000821baton.matches[1].addr = 0;'''
Greg Claytonbff78412012-04-12 18:57:36 +0000822 if args:
Greg Claytonad72e522013-02-01 00:47:49 +0000823 total_matches = 0
Greg Clayton549294a2013-01-31 06:38:09 +0000824 for ptr_expr in args:
825 user_init_code = user_init_code_format % (ptr_expr)
Greg Claytonad72e522013-02-01 00:47:49 +0000826 expr = get_iterate_memory_expr(options, process, user_init_code, 'baton.matches')
Greg Clayton549294a2013-01-31 06:38:09 +0000827 arg_str_description = 'malloc block that contains %s' % ptr_expr
Greg Claytonad72e522013-02-01 00:47:49 +0000828 total_matches += display_match_results (result, options, arg_str_description, expr)
829 return total_matches
Greg Claytonbff78412012-04-12 18:57:36 +0000830 else:
Greg Clayton849acc82013-01-30 22:57:34 +0000831 result.AppendMessage('error: command takes one or more pointer expressions')
Greg Claytonad72e522013-02-01 00:47:49 +0000832 return 0
Greg Claytonbff78412012-04-12 18:57:36 +0000833
Greg Clayton849acc82013-01-30 22:57:34 +0000834def get_thread_stack_ranges_struct (process):
Greg Clayton549294a2013-01-31 06:38:09 +0000835 '''Create code that defines a structure that represents threads stack bounds
836 for all threads. It returns a static sized array initialized with all of
837 the tid, base, size structs for all the threads.'''
Greg Clayton849acc82013-01-30 22:57:34 +0000838 stack_dicts = list()
839 if process:
840 i = 0;
841 for thread in process:
842 min_sp = thread.frame[0].sp
843 max_sp = min_sp
844 for frame in thread.frames:
845 sp = frame.sp
846 if sp < min_sp: min_sp = sp
847 if sp > max_sp: max_sp = sp
848 if min_sp < max_sp:
849 stack_dicts.append ({ 'tid' : thread.GetThreadID(), 'base' : min_sp , 'size' : max_sp-min_sp, 'index' : i })
850 i += 1
851 stack_dicts_len = len(stack_dicts)
852 if stack_dicts_len > 0:
Greg Clayton549294a2013-01-31 06:38:09 +0000853 result = '''
854#define NUM_STACKS %u
Greg Claytonad72e522013-02-01 00:47:49 +0000855#define STACK_RED_ZONE_SIZE %u
Greg Clayton849acc82013-01-30 22:57:34 +0000856typedef struct thread_stack_t { uint64_t tid, base, size; } thread_stack_t;
Greg Claytonad72e522013-02-01 00:47:49 +0000857thread_stack_t stacks[NUM_STACKS];''' % (stack_dicts_len, process.target.GetStackRedZoneSize())
Greg Clayton849acc82013-01-30 22:57:34 +0000858 for stack_dict in stack_dicts:
Greg Clayton549294a2013-01-31 06:38:09 +0000859 result += '''
860stacks[%(index)u].tid = 0x%(tid)x;
Greg Clayton849acc82013-01-30 22:57:34 +0000861stacks[%(index)u].base = 0x%(base)x;
Greg Clayton549294a2013-01-31 06:38:09 +0000862stacks[%(index)u].size = 0x%(size)x;''' % stack_dict
Greg Clayton849acc82013-01-30 22:57:34 +0000863 return result
864 else:
865 return None
Greg Clayton130a3122012-10-08 22:39:38 +0000866
Greg Clayton549294a2013-01-31 06:38:09 +0000867def get_sections_ranges_struct (process):
868 '''Create code that defines a structure that represents all segments that
869 can contain data for all images in "target". It returns a static sized
870 array initialized with all of base, size structs for all the threads.'''
871 target = process.target
872 segment_dicts = list()
873 for (module_idx, module) in enumerate(target.modules):
874 for sect_idx in range(module.GetNumSections()):
875 section = module.GetSectionAtIndex(sect_idx)
876 if not section:
877 break
878 name = section.name
879 if name != '__TEXT' and name != '__LINKEDIT' and name != '__PAGEZERO':
880 base = section.GetLoadAddress(target)
881 size = section.GetByteSize()
882 if base != lldb.LLDB_INVALID_ADDRESS and size > 0:
883 segment_dicts.append ({ 'base' : base, 'size' : size })
884 segment_dicts_len = len(segment_dicts)
885 if segment_dicts_len > 0:
886 result = '''
887#define NUM_SEGMENTS %u
888typedef struct segment_range_t { uint64_t base; uint32_t size; } segment_range_t;
889segment_range_t segments[NUM_SEGMENTS];''' % (segment_dicts_len,)
890 for (idx, segment_dict) in enumerate(segment_dicts):
891 segment_dict['index'] = idx
892 result += '''
893segments[%(index)u].base = 0x%(base)x;
894segments[%(index)u].size = 0x%(size)x;''' % segment_dict
895 return result
Greg Clayton130a3122012-10-08 22:39:38 +0000896 else:
Greg Clayton549294a2013-01-31 06:38:09 +0000897 return None
Greg Clayton130a3122012-10-08 22:39:38 +0000898
Greg Clayton4c5c4292012-07-11 22:13:18 +0000899def section_ptr_refs(debugger, command, result, dict):
900 command_args = shlex.split(command)
901 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
902 description='''Searches section contents for pointer values in darwin user space programs.'''
903 parser = optparse.OptionParser(description=description, prog='section_ptr_refs',usage=usage)
904 add_common_options(parser)
905 parser.add_option('--section', action='append', type='string', dest='section_names', help='section name to search', default=list())
906 try:
907 (options, args) = parser.parse_args(command_args)
908 except:
909 return
910
911 options.type = 'pointer'
Greg Clayton130a3122012-10-08 22:39:38 +0000912
Greg Clayton4c5c4292012-07-11 22:13:18 +0000913 sections = list()
914 section_modules = list()
915 if not options.section_names:
Greg Clayton85df60c2012-09-01 00:34:35 +0000916 result.AppendMessage('error: at least one section must be specified with the --section option')
Greg Clayton4c5c4292012-07-11 22:13:18 +0000917 return
918
Greg Clayton849acc82013-01-30 22:57:34 +0000919 target = lldb.debugger.GetSelectedTarget()
920 for module in target.modules:
Greg Clayton4c5c4292012-07-11 22:13:18 +0000921 for section_name in options.section_names:
922 section = module.section[section_name]
923 if section:
924 sections.append (section)
925 section_modules.append (module)
926 if sections:
927 dylid_load_err = load_dylib()
928 if dylid_load_err:
Greg Clayton85df60c2012-09-01 00:34:35 +0000929 result.AppendMessage(dylid_load_err)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000930 return
Greg Clayton849acc82013-01-30 22:57:34 +0000931 frame = target.GetProcess().GetSelectedThread().GetSelectedFrame()
Greg Clayton4c5c4292012-07-11 22:13:18 +0000932 for expr_str in args:
933 for (idx, section) in enumerate(sections):
934 expr = 'find_pointer_in_memory(0x%xllu, %ullu, (void *)%s)' % (section.addr.load_addr, section.size, expr_str)
935 arg_str_description = 'section %s.%s containing "%s"' % (section_modules[idx].file.fullpath, section.name, expr_str)
Greg Clayton849acc82013-01-30 22:57:34 +0000936 num_matches = display_match_results (result, options, arg_str_description, expr, False)
Greg Clayton4c5c4292012-07-11 22:13:18 +0000937 if num_matches:
938 if num_matches < options.max_matches:
939 options.max_matches = options.max_matches - num_matches
940 else:
941 options.max_matches = 0
942 if options.max_matches == 0:
943 return
944 else:
Greg Clayton85df60c2012-09-01 00:34:35 +0000945 result.AppendMessage('error: no sections were found that match any of %s' % (', '.join(options.section_names)))
Greg Clayton4c5c4292012-07-11 22:13:18 +0000946
Greg Clayton849acc82013-01-30 22:57:34 +0000947def get_objc_refs_options():
948 usage = "usage: %prog [options] <CLASS> [CLASS ...]"
949 description='''Searches all allocations on the heap for instances of
950objective C classes, or any classes that inherit from the specified classes
951in darwin user space programs. Any matches that were found will dump the malloc
952blocks that contain the C strings and might be able to print what kind of
953objects the pointers are contained in using dynamic type information in the
954program.'''
955 parser = optparse.OptionParser(description=description, prog='objc_refs',usage=usage)
956 add_common_options(parser)
957 return parser
958
Greg Claytonab20f292012-08-11 02:26:26 +0000959def objc_refs(debugger, command, result, dict):
960 command_args = shlex.split(command)
Greg Clayton849acc82013-01-30 22:57:34 +0000961 parser = get_objc_refs_options()
Greg Claytonab20f292012-08-11 02:26:26 +0000962 try:
963 (options, args) = parser.parse_args(command_args)
964 except:
965 return
966
Greg Clayton549294a2013-01-31 06:38:09 +0000967 process = lldb.debugger.GetSelectedTarget().GetProcess()
968 if not process:
969 result.AppendMessage('error: invalid process')
970 return
971 frame = process.GetSelectedThread().GetSelectedFrame()
Greg Clayton849acc82013-01-30 22:57:34 +0000972 if not frame:
973 result.AppendMessage('error: invalid frame')
974 return
975
976 options.type = 'isa'
977 if options.format == None:
978 options.format = "A" # 'A' is "address" format
979
980 num_objc_classes_value = frame.EvaluateExpression("(int)objc_getClassList((void *)0, (int)0)")
981 if not num_objc_classes_value.error.Success():
982 result.AppendMessage('error: %s' % num_objc_classes_value.error.GetCString())
983 return
984
985 num_objc_classes = num_objc_classes_value.GetValueAsUnsigned()
986 if num_objc_classes == 0:
987 result.AppendMessage('error: no objective C classes in program')
988 return
989
990 if args:
991 # When we initialize the expression, we must define any types that
992 # we will need when looking at every allocation. We must also define
993 # a type named callback_baton_t and make an instance named "baton"
994 # and initialize it how ever we want to. The address of "baton" will
995 # be passed into our range callback. callback_baton_t must contain
996 # a member named "callback" whose type is "range_callback_t". This
997 # will be used by our zone callbacks to call the range callback for
998 # each malloc range.
Greg Claytonad72e522013-02-01 00:47:49 +0000999 user_init_code_format = '''
1000#define MAX_MATCHES %u
Greg Clayton549294a2013-01-31 06:38:09 +00001001struct $malloc_match {
Greg Clayton849acc82013-01-30 22:57:34 +00001002 void *addr;
1003 uintptr_t size;
1004 uintptr_t offset;
1005 uintptr_t type;
1006};
1007typedef int (*compare_callback_t)(const void *a, const void *b);
1008typedef struct callback_baton_t {
1009 range_callback_t callback;
1010 compare_callback_t compare_callback;
1011 unsigned num_matches;
Greg Clayton549294a2013-01-31 06:38:09 +00001012 $malloc_match matches[MAX_MATCHES];
Greg Clayton849acc82013-01-30 22:57:34 +00001013 void *isa;
1014 Class classes[%u];
1015} callback_baton_t;
1016compare_callback_t compare_callback = [](const void *a, const void *b) -> int {
1017 Class a_ptr = *(Class *)a;
1018 Class b_ptr = *(Class *)b;
1019 if (a_ptr < b_ptr) return -1;
1020 if (a_ptr > b_ptr) return +1;
1021 return 0;
1022};
1023range_callback_t range_callback = [](task_t task, void *baton, unsigned type, uintptr_t ptr_addr, uintptr_t ptr_size) -> void {
1024 callback_baton_t *info = (callback_baton_t *)baton;
1025 if (sizeof(Class) <= ptr_size) {
1026 Class *curr_class_ptr = (Class *)ptr_addr;
1027 Class *matching_class_ptr = (Class *)bsearch (curr_class_ptr,
1028 (const void *)info->classes,
1029 sizeof(info->classes)/sizeof(Class),
1030 sizeof(Class),
1031 info->compare_callback);
1032 if (matching_class_ptr) {
1033 bool match = false;
1034 if (info->isa) {
1035 Class isa = *curr_class_ptr;
1036 if (info->isa == isa)
1037 match = true;
1038 else { // if (info->objc.match_superclasses) {
1039 Class super = (Class)class_getSuperclass(isa);
1040 while (super) {
1041 if (super == info->isa) {
1042 match = true;
1043 break;
1044 }
1045 super = (Class)class_getSuperclass(super);
1046 }
1047 }
1048 }
1049 else
1050 match = true;
1051 if (match) {
Greg Clayton549294a2013-01-31 06:38:09 +00001052 if (info->num_matches < MAX_MATCHES) {
Greg Clayton849acc82013-01-30 22:57:34 +00001053 info->matches[info->num_matches].addr = (void*)ptr_addr;
1054 info->matches[info->num_matches].size = ptr_size;
1055 info->matches[info->num_matches].offset = 0;
1056 info->matches[info->num_matches].type = type;
1057 ++info->num_matches;
1058 }
1059 }
1060 }
1061 }
1062};
1063callback_baton_t baton = { range_callback, compare_callback, 0, {0}, (void *)0x%x, {0} };
1064int nc = (int)objc_getClassList(baton.classes, sizeof(baton.classes)/sizeof(Class));
1065(void)qsort (baton.classes, sizeof(baton.classes)/sizeof(Class), sizeof(Class), compare_callback);'''
1066 # We must also define a snippet of code to be run that returns
1067 # the result of the expression we run.
1068 # Here we return NULL if our pointer was not found in any malloc blocks,
1069 # and we return the address of the matches array so we can then access
1070 # the matching results
Greg Clayton549294a2013-01-31 06:38:09 +00001071 user_return_code = '''if (baton.num_matches < MAX_MATCHES)
1072 baton.matches[baton.num_matches].addr = 0; // Terminate the matches array
1073 baton.matches'''
Greg Clayton849acc82013-01-30 22:57:34 +00001074 # Iterate through all of our ObjC class name arguments
1075 for class_name in args:
1076 addr_expr_str = "(void *)[%s class]" % class_name
1077 expr_sbvalue = frame.EvaluateExpression (addr_expr_str)
1078 if expr_sbvalue.error.Success():
1079 isa = expr_sbvalue.unsigned
1080 if isa:
1081 options.type = 'isa'
Greg Clayton549294a2013-01-31 06:38:09 +00001082 result.AppendMessage('Searching for all instances of classes or subclasses of "%s" (isa=0x%x)' % (class_name, isa))
1083 user_init_code = user_init_code_format % (options.max_matches, num_objc_classes, isa)
Greg Claytonad72e522013-02-01 00:47:49 +00001084 expr = get_iterate_memory_expr(options, process, user_init_code, user_return_code)
Greg Clayton849acc82013-01-30 22:57:34 +00001085 arg_str_description = 'objective C classes with isa 0x%x' % isa
1086 display_match_results (result, options, arg_str_description, expr)
Greg Claytonab20f292012-08-11 02:26:26 +00001087 else:
Greg Clayton849acc82013-01-30 22:57:34 +00001088 result.AppendMessage('error: Can\'t find isa for an ObjC class named "%s"' % (class_name))
1089 else:
1090 result.AppendMessage('error: expression error for "%s": %s' % (addr_expr_str, expr_sbvalue.error))
1091 else:
1092 result.AppendMessage('error: command takes one or more C string arguments');
Greg Claytonab20f292012-08-11 02:26:26 +00001093
Greg Clayton1dae6f32012-04-25 18:40:20 +00001094if __name__ == '__main__':
1095 lldb.debugger = lldb.SBDebugger.Create()
1096
1097# This initializer is being run from LLDB in the embedded command interpreter
1098# Add any commands contained in this module to LLDB
Greg Clayton849acc82013-01-30 22:57:34 +00001099if __package__:
1100 package_name = __package__ + '.' + __name__
1101else:
1102 package_name = __name__
1103
1104# Make the options so we can generate the help text for the new LLDB
1105# command line command prior to registering it with LLDB below. This way
1106# if clients in LLDB type "help malloc_info", they will see the exact same
1107# output as typing "malloc_info --help".
1108ptr_refs.__doc__ = get_ptr_refs_options().format_help()
1109cstr_refs.__doc__ = get_cstr_refs_options().format_help()
1110malloc_info.__doc__ = get_malloc_info_options().format_help()
1111objc_refs.__doc__ = get_objc_refs_options().format_help()
1112lldb.debugger.HandleCommand('command script add -f %s.ptr_refs ptr_refs' % package_name)
1113lldb.debugger.HandleCommand('command script add -f %s.cstr_refs cstr_refs' % package_name)
1114lldb.debugger.HandleCommand('command script add -f %s.malloc_info malloc_info' % package_name)
1115# lldb.debugger.HandleCommand('command script add -f %s.heap heap' % package_name)
1116# lldb.debugger.HandleCommand('command script add -f %s.section_ptr_refs section_ptr_refs' % package_name)
1117# lldb.debugger.HandleCommand('command script add -f %s.stack_ptr_refs stack_ptr_refs' % package_name)
1118lldb.debugger.HandleCommand('command script add -f %s.objc_refs objc_refs' % package_name)
1119print '"malloc_info", "ptr_refs", "cstr_refs", and "objc_refs" commands have been installed, use the "--help" options on these commands for detailed help.'
Greg Claytone93e24f2012-04-11 16:27:06 +00001120
1121
1122
1123