blob: 2ebff60ba7a23ebaeb25bed875c53b5aa847e247 [file] [log] [blame]
Greg Clayton804de012012-04-11 16:27:06 +00001#!/usr/bin/python
2
3#----------------------------------------------------------------------
Greg Claytond712ef02012-04-25 18:40:20 +00004# This module is designed to live inside the "lldb" python package
5# in the "lldb.macosx" package. To use this in the embedded python
6# interpreter using "lldb" just import it:
Greg Clayton804de012012-04-11 16:27:06 +00007#
Greg Claytond712ef02012-04-25 18:40:20 +00008# (lldb) script import lldb.macosx.heap
Greg Clayton804de012012-04-11 16:27:06 +00009#----------------------------------------------------------------------
10
11import lldb
12import commands
13import optparse
Greg Clayton7fb671b2012-04-11 18:30:53 +000014import os
Greg Claytond712ef02012-04-25 18:40:20 +000015import os.path
Greg Claytone04cfd22012-07-11 22:13:18 +000016import re
Greg Clayton804de012012-04-11 16:27:06 +000017import shlex
Greg Claytond712ef02012-04-25 18:40:20 +000018import string
19import tempfile
Greg Claytoned3eee62012-04-25 01:49:50 +000020import lldb.utils.symbolication
Greg Clayton804de012012-04-11 16:27:06 +000021
Greg Claytond712ef02012-04-25 18:40:20 +000022g_libheap_dylib_dir = None
23g_libheap_dylib_dict = dict()
24
Greg Clayton13fbb992013-02-01 00:47:49 +000025def get_iterate_memory_expr(options, process, user_init_code, user_return_code):
26 expr = '''
Greg Claytone7fc9cc2013-01-31 06:38:09 +000027typedef unsigned natural_t;
Greg Clayton85e62ec2013-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 Clayton13fbb992013-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 Clayton85e62ec2013-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 Clayton85e62ec2013-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 Clayton13fbb992013-02-01 00:47:49 +0000131unsigned int num_zones = 0;task_t task = 0;
Greg Clayton85e62ec2013-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 Clayton13fbb992013-02-01 00:47:49 +0000153}'''
154
155 if options.search_stack:
156 expr += '''
Greg Clayton966c6f62014-01-07 21:55:00 +0000157#ifdef NUM_STACKS
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000158// Call the callback for the thread stack ranges
Greg Clayton13fbb992013-02-01 00:47:49 +0000159for (uint32_t i=0; i<NUM_STACKS; ++i) {
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000160 range_callback(task, &baton, 8, stacks[i].base, stacks[i].size);
Greg Clayton13fbb992013-02-01 00:47:49 +0000161 if (STACK_RED_ZONE_SIZE > 0) {
162 range_callback(task, &baton, 16, stacks[i].base - STACK_RED_ZONE_SIZE, STACK_RED_ZONE_SIZE);
163 }
164}
Greg Clayton966c6f62014-01-07 21:55:00 +0000165#endif'''
Greg Clayton13fbb992013-02-01 00:47:49 +0000166
167 if options.search_segments:
168 expr += '''
Greg Clayton966c6f62014-01-07 21:55:00 +0000169#ifdef NUM_SEGMENTS
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000170// Call the callback for all segments
171for (uint32_t i=0; i<NUM_SEGMENTS; ++i)
Greg Clayton966c6f62014-01-07 21:55:00 +0000172 range_callback(task, &baton, 32, segments[i].base, segments[i].size);
173#endif'''
Greg Clayton13fbb992013-02-01 00:47:49 +0000174
175 if user_return_code:
176 expr += "\n%s" % (user_return_code,)
177
178 return expr
Greg Clayton94073022012-07-07 01:22:45 +0000179
180def get_member_types_for_offset(value_type, offset, member_list):
181 member = value_type.GetFieldAtIndex(0)
182 search_bases = False
183 if member:
184 if member.GetOffsetInBytes() <= offset:
185 for field_idx in range (value_type.GetNumberOfFields()):
186 member = value_type.GetFieldAtIndex(field_idx)
187 member_byte_offset = member.GetOffsetInBytes()
188 member_end_byte_offset = member_byte_offset + member.type.size
189 if member_byte_offset <= offset and offset < member_end_byte_offset:
190 member_list.append(member)
191 get_member_types_for_offset (member.type, offset - member_byte_offset, member_list)
192 return
193 else:
194 search_bases = True
195 else:
196 search_bases = True
197 if search_bases:
198 for field_idx in range (value_type.GetNumberOfDirectBaseClasses()):
199 member = value_type.GetDirectBaseClassAtIndex(field_idx)
200 member_byte_offset = member.GetOffsetInBytes()
201 member_end_byte_offset = member_byte_offset + member.type.size
202 if member_byte_offset <= offset and offset < member_end_byte_offset:
203 member_list.append(member)
204 get_member_types_for_offset (member.type, offset - member_byte_offset, member_list)
205 return
206 for field_idx in range (value_type.GetNumberOfVirtualBaseClasses()):
207 member = value_type.GetVirtualBaseClassAtIndex(field_idx)
208 member_byte_offset = member.GetOffsetInBytes()
209 member_end_byte_offset = member_byte_offset + member.type.size
210 if member_byte_offset <= offset and offset < member_end_byte_offset:
211 member_list.append(member)
212 get_member_types_for_offset (member.type, offset - member_byte_offset, member_list)
213 return
Greg Claytone04cfd22012-07-11 22:13:18 +0000214
215def append_regex_callback(option, opt, value, parser):
216 try:
217 ivar_regex = re.compile(value)
218 parser.values.ivar_regex_blacklist.append(ivar_regex)
219 except:
220 print 'error: an exception was thrown when compiling the ivar regular expression for "%s"' % value
Greg Claytonb403a152012-04-21 00:11:26 +0000221
Greg Claytond84bb482012-04-13 16:24:09 +0000222def add_common_options(parser):
223 parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False)
Greg Claytone04cfd22012-07-11 22:13:18 +0000224 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 Claytond84bb482012-04-13 16:24:09 +0000225 parser.add_option('-o', '--po', action='store_true', dest='print_object_description', help='print the object descriptions for any matches', default=False)
Greg Claytona3606ad2012-09-12 02:02:32 +0000226 parser.add_option('-z', '--size', action='store_true', dest='show_size', help='print the allocation size in bytes', default=False)
227 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 Claytond84bb482012-04-13 16:24:09 +0000228 parser.add_option('-m', '--memory', action='store_true', dest='memory', help='dump the memory for each matching block', default=False)
229 parser.add_option('-f', '--format', type='string', dest='format', help='the format to use when dumping memory if --memory is specified', default=None)
Greg Claytone04cfd22012-07-11 22:13:18 +0000230 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 Claytonb403a152012-04-21 00:11:26 +0000231 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 Claytond9fc5352012-05-10 23:17:28 +0000232 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 Clayton85e62ec2013-01-30 22:57:34 +0000233 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)
234 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 Claytone7fc9cc2013-01-31 06:38:09 +0000235 parser.add_option('-M', '--max-matches', type='int', dest='max_matches', help='the maximum number of matches to print', default=32)
Greg Clayton774ebdf2012-08-11 02:26:26 +0000236 parser.add_option('-O', '--offset', type='int', dest='offset', help='the matching data must be at this offset', default=-1)
Greg Clayton13fbb992013-02-01 00:47:49 +0000237 parser.add_option('--ignore-stack', action='store_false', dest='search_stack', help="Don't search the stack when enumerating memory", default=True)
238 parser.add_option('--ignore-heap', action='store_false', dest='search_heap', help="Don't search the heap allocations when enumerating memory", default=True)
239 parser.add_option('--ignore-segments', action='store_false', dest='search_segments', help="Don't search readable executable segments enumerating memory", default=True)
240 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 Claytond9fc5352012-05-10 23:17:28 +0000241
Greg Clayton85e62ec2013-01-30 22:57:34 +0000242def type_flags_to_string(type_flags):
243 if type_flags == 0:
244 type_str = 'free'
245 elif type_flags & 2:
246 type_str = 'malloc'
247 elif type_flags & 4:
248 type_str = 'free'
249 elif type_flags & 1:
250 type_str = 'generic'
251 elif type_flags & 8:
252 type_str = 'stack'
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000253 elif type_flags & 16:
Greg Clayton13fbb992013-02-01 00:47:49 +0000254 type_str = 'stack (red zone)'
255 elif type_flags & 32:
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000256 type_str = 'segment'
Greg Clayton13fbb992013-02-01 00:47:49 +0000257 elif type_flags & 64:
258 type_str = 'vm_region'
Greg Clayton85e62ec2013-01-30 22:57:34 +0000259 else:
260 type_str = hex(type_flags)
261 return type_str
262
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000263def type_flags_to_description(type_flags, ptr_addr, ptr_size, offset):
264 show_offset = False
Greg Clayton85e62ec2013-01-30 22:57:34 +0000265 if type_flags == 0 or type_flags & 4:
266 type_str = 'free(%#x)' % (ptr_addr,)
267 elif type_flags & 2 or type_flags & 1:
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000268 type_str = 'malloc(%6u) -> %#x' % (ptr_size, ptr_addr)
269 show_offset = True
Greg Clayton85e62ec2013-01-30 22:57:34 +0000270 elif type_flags & 8:
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000271 type_str = 'stack'
272 elif type_flags & 16:
Greg Clayton13fbb992013-02-01 00:47:49 +0000273 type_str = 'stack (red zone)'
274 elif type_flags & 32:
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000275 sb_addr = lldb.debugger.GetSelectedTarget().ResolveLoadAddress(ptr_addr + offset)
276 type_str = 'segment [%#x - %#x), %s + %u, %s' % (ptr_addr, ptr_addr + ptr_size, sb_addr.section.name, sb_addr.offset, sb_addr)
Greg Clayton13fbb992013-02-01 00:47:49 +0000277 elif type_flags & 64:
278 sb_addr = lldb.debugger.GetSelectedTarget().ResolveLoadAddress(ptr_addr + offset)
279 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 Clayton85e62ec2013-01-30 22:57:34 +0000280 else:
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000281 type_str = '%#x' % (ptr_addr,)
282 show_offset = True
283 if show_offset and offset != 0:
284 type_str += ' + %-6u' % (offset,)
Greg Clayton85e62ec2013-01-30 22:57:34 +0000285 return type_str
286
287def dump_stack_history_entry(options, result, stack_history_entry, idx):
Greg Clayton7200ed12012-05-10 23:37:52 +0000288 address = int(stack_history_entry.address)
289 if address:
290 type_flags = int(stack_history_entry.type_flags)
Greg Claytond9fc5352012-05-10 23:17:28 +0000291 symbolicator = lldb.utils.symbolication.Symbolicator()
Greg Clayton85e62ec2013-01-30 22:57:34 +0000292 symbolicator.target = lldb.debugger.GetSelectedTarget()
293 type_str = type_flags_to_string(type_flags)
Greg Claytonc373ca52012-09-01 00:34:35 +0000294 result.AppendMessage('stack[%u]: addr = 0x%x, type=%s, frames:' % (idx, address, type_str))
Greg Claytond9fc5352012-05-10 23:17:28 +0000295 frame_idx = 0
Greg Clayton7200ed12012-05-10 23:37:52 +0000296 idx = 0
297 pc = int(stack_history_entry.frames[idx])
Greg Claytond9fc5352012-05-10 23:17:28 +0000298 while pc != 0:
299 if pc >= 0x1000:
300 frames = symbolicator.symbolicate(pc)
301 if frames:
302 for frame in frames:
Greg Claytonc373ca52012-09-01 00:34:35 +0000303 result.AppendMessage(' [%u] %s' % (frame_idx, frame))
Greg Claytond9fc5352012-05-10 23:17:28 +0000304 frame_idx += 1
305 else:
Greg Claytonc373ca52012-09-01 00:34:35 +0000306 result.AppendMessage(' [%u] 0x%x' % (frame_idx, pc))
Greg Claytond9fc5352012-05-10 23:17:28 +0000307 frame_idx += 1
Greg Clayton7200ed12012-05-10 23:37:52 +0000308 idx = idx + 1
309 pc = int(stack_history_entry.frames[idx])
Greg Claytond9fc5352012-05-10 23:17:28 +0000310 else:
311 pc = 0
Greg Clayton85e62ec2013-01-30 22:57:34 +0000312 if idx >= options.max_frames:
313 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))
314
Greg Claytonc373ca52012-09-01 00:34:35 +0000315 result.AppendMessage('')
Greg Claytond9fc5352012-05-10 23:17:28 +0000316
Greg Clayton85e62ec2013-01-30 22:57:34 +0000317def dump_stack_history_entries(options, result, addr, history):
Greg Claytond9fc5352012-05-10 23:17:28 +0000318 # malloc_stack_entry *get_stack_history_for_address (const void * addr)
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000319 single_expr = '''
320typedef int kern_return_t;
Greg Clayton85e62ec2013-01-30 22:57:34 +0000321#define MAX_FRAMES %u
322typedef struct $malloc_stack_entry {
323 uint64_t address;
324 uint64_t argument;
325 uint32_t type_flags;
326 uint32_t num_frames;
327 uint64_t frames[512];
328 kern_return_t err;
329} $malloc_stack_entry;
330typedef unsigned task_t;
331$malloc_stack_entry stack;
332stack.address = 0x%x;
333stack.type_flags = 2;
334stack.num_frames = 0;
335stack.frames[0] = 0;
336uint32_t max_stack_frames = MAX_FRAMES;
337stack.err = (kern_return_t)__mach_stack_logging_get_frames (
338 (task_t)mach_task_self(),
339 stack.address,
340 &stack.frames[0],
341 max_stack_frames,
342 &stack.num_frames);
343if (stack.num_frames < MAX_FRAMES)
344 stack.frames[stack.num_frames] = 0;
345else
346 stack.frames[MAX_FRAMES-1] = 0;
347stack''' % (options.max_frames, addr);
348
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000349 history_expr = '''
350typedef int kern_return_t;
Greg Clayton85e62ec2013-01-30 22:57:34 +0000351typedef unsigned task_t;
352#define MAX_FRAMES %u
353#define MAX_HISTORY %u
354typedef struct mach_stack_logging_record_t {
355 uint32_t type_flags;
356 uint64_t stack_identifier;
357 uint64_t argument;
358 uint64_t address;
359} mach_stack_logging_record_t;
360typedef void (*enumerate_callback_t)(mach_stack_logging_record_t, void *);
361typedef struct malloc_stack_entry {
362 uint64_t address;
363 uint64_t argument;
364 uint32_t type_flags;
365 uint32_t num_frames;
366 uint64_t frames[MAX_FRAMES];
367 kern_return_t frames_err;
368} malloc_stack_entry;
369typedef struct $malloc_stack_history {
370 task_t task;
371 unsigned idx;
372 malloc_stack_entry entries[MAX_HISTORY];
373} $malloc_stack_history;
374$malloc_stack_history info = { (task_t)mach_task_self(), 0 };
375uint32_t max_stack_frames = MAX_FRAMES;
376enumerate_callback_t callback = [] (mach_stack_logging_record_t stack_record, void *baton) -> void {
377 $malloc_stack_history *info = ($malloc_stack_history *)baton;
378 if (info->idx < MAX_HISTORY) {
379 malloc_stack_entry *stack_entry = &(info->entries[info->idx]);
380 stack_entry->address = stack_record.address;
381 stack_entry->type_flags = stack_record.type_flags;
382 stack_entry->argument = stack_record.argument;
383 stack_entry->num_frames = 0;
384 stack_entry->frames[0] = 0;
385 stack_entry->frames_err = (kern_return_t)__mach_stack_logging_frames_for_uniqued_stack (
386 info->task,
387 stack_record.stack_identifier,
388 stack_entry->frames,
389 (uint32_t)MAX_FRAMES,
390 &stack_entry->num_frames);
391 // Terminate the frames with zero if there is room
392 if (stack_entry->num_frames < MAX_FRAMES)
393 stack_entry->frames[stack_entry->num_frames] = 0;
394 }
395 ++info->idx;
396};
397(kern_return_t)__mach_stack_logging_enumerate_records (info.task, (uint64_t)0x%x, callback, &info);
398info''' % (options.max_frames, options.max_history, addr);
399
400 frame = lldb.debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
401 if history:
402 expr = history_expr
403 else:
404 expr = single_expr
Greg Clayton927fa012013-04-03 07:25:30 +0000405 expr_options = lldb.SBExpressionOptions()
406 expr_options.SetIgnoreBreakpoints(True);
407 expr_options.SetTimeoutInMicroSeconds (5*1000*1000) # 5 second timeout
408 expr_options.SetTryAllThreads (True)
Greg Clayton6e7ab022015-01-14 21:37:19 +0000409 expr_options.SetLanguage(lldb.eLanguageTypeObjC_plus_plus)
Greg Clayton927fa012013-04-03 07:25:30 +0000410 expr_sbvalue = frame.EvaluateExpression (expr, expr_options)
Greg Clayton85e62ec2013-01-30 22:57:34 +0000411 if options.verbose:
412 print "expression:"
413 print expr
414 print "expression result:"
415 print expr_sbvalue
416 if expr_sbvalue.error.Success():
417 if history:
418 malloc_stack_history = lldb.value(expr_sbvalue)
419 num_stacks = int(malloc_stack_history.idx)
420 if num_stacks <= options.max_history:
421 i_max = num_stacks
422 else:
423 i_max = options.max_history
424 for i in range(i_max):
425 stack_history_entry = malloc_stack_history.entries[i]
426 dump_stack_history_entry(options, result, stack_history_entry, i)
427 if num_stacks > options.max_history:
428 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))
429 else:
430 stack_history_entry = lldb.value(expr_sbvalue)
431 dump_stack_history_entry(options, result, stack_history_entry, 0)
432
433 else:
434 result.AppendMessage('error: expression failed "%s" => %s' % (expr, expr_sbvalue.error))
435
436
437def display_match_results (result, options, arg_str_description, expr, print_no_matches = True):
438 frame = lldb.debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
439 if not frame:
440 result.AppendMessage('error: invalid frame')
441 return 0
Greg Clayton927fa012013-04-03 07:25:30 +0000442 expr_options = lldb.SBExpressionOptions()
443 expr_options.SetIgnoreBreakpoints(True);
444 expr_options.SetFetchDynamicValue(lldb.eNoDynamicValues);
445 expr_options.SetTimeoutInMicroSeconds (30*1000*1000) # 30 second timeout
446 expr_options.SetTryAllThreads (False)
Greg Clayton6e7ab022015-01-14 21:37:19 +0000447 expr_options.SetLanguage (lldb.eLanguageTypeObjC_plus_plus)
Greg Clayton927fa012013-04-03 07:25:30 +0000448 expr_sbvalue = frame.EvaluateExpression (expr, expr_options)
Greg Clayton85e62ec2013-01-30 22:57:34 +0000449 if options.verbose:
450 print "expression:"
451 print expr
452 print "expression result:"
453 print expr_sbvalue
Greg Clayton7fb671b2012-04-11 18:30:53 +0000454 if expr_sbvalue.error.Success():
Greg Clayton966c6f62014-01-07 21:55:00 +0000455 match_value = lldb.value(expr_sbvalue)
456 i = 0
457 match_idx = 0
458 while 1:
459 print_entry = True
460 match_entry = match_value[i]; i += 1
461 if i > options.max_matches:
462 result.AppendMessage('warning: the max number of matches (%u) was reached, use the --max-matches option to get more results' % (options.max_matches))
463 break
464 malloc_addr = match_entry.addr.sbvalue.unsigned
465 if malloc_addr == 0:
466 break
467 malloc_size = int(match_entry.size)
468 offset = int(match_entry.offset)
469
470 if options.offset >= 0 and options.offset != offset:
471 print_entry = False
472 else:
473 match_addr = malloc_addr + offset
474 type_flags = int(match_entry.type)
475 #result.AppendMessage (hex(malloc_addr + offset))
476 if type_flags == 64:
477 search_stack_old = options.search_stack
478 search_segments_old = options.search_segments
479 search_heap_old = options.search_heap
480 search_vm_regions = options.search_vm_regions
481 options.search_stack = True
482 options.search_segments = True
483 options.search_heap = True
484 options.search_vm_regions = False
485 if malloc_info_impl (lldb.debugger, result, options, [hex(malloc_addr + offset)]):
486 print_entry = False
487 options.search_stack = search_stack_old
488 options.search_segments = search_segments_old
489 options.search_heap = search_heap_old
490 options.search_vm_regions = search_vm_regions
Greg Claytone04cfd22012-07-11 22:13:18 +0000491 if print_entry:
Greg Clayton966c6f62014-01-07 21:55:00 +0000492 description = '%#16.16x: %s' % (match_addr, type_flags_to_description(type_flags, malloc_addr, malloc_size, offset))
493 if options.show_size:
494 description += ' <%5u>' % (malloc_size)
495 if options.show_range:
496 description += ' [%#x - %#x)' % (malloc_addr, malloc_addr + malloc_size)
497 derefed_dynamic_value = None
498 dynamic_value = match_entry.addr.sbvalue.GetDynamicValue(lldb.eDynamicCanRunTarget)
499 if dynamic_value.type.name == 'void *':
500 if options.type == 'pointer' and malloc_size == 4096:
501 error = lldb.SBError()
502 process = expr_sbvalue.GetProcess()
503 target = expr_sbvalue.GetTarget()
504 data = bytearray(process.ReadMemory(malloc_addr, 16, error))
505 if data == '\xa1\xa1\xa1\xa1AUTORELEASE!':
506 ptr_size = target.addr_size
507 thread = process.ReadUnsignedFromMemory (malloc_addr + 16 + ptr_size, ptr_size, error)
508 # 4 bytes 0xa1a1a1a1
509 # 12 bytes 'AUTORELEASE!'
510 # ptr bytes autorelease insertion point
511 # ptr bytes pthread_t
512 # ptr bytes next colder page
513 # ptr bytes next hotter page
514 # 4 bytes this page's depth in the list
515 # 4 bytes high-water mark
516 description += ' AUTORELEASE! for pthread_t %#x' % (thread)
517 # else:
518 # description += 'malloc(%u)' % (malloc_size)
519 # else:
520 # description += 'malloc(%u)' % (malloc_size)
521 else:
522 derefed_dynamic_value = dynamic_value.deref
523 if derefed_dynamic_value:
524 derefed_dynamic_type = derefed_dynamic_value.type
525 derefed_dynamic_type_size = derefed_dynamic_type.size
526 derefed_dynamic_type_name = derefed_dynamic_type.name
527 description += ' '
528 description += derefed_dynamic_type_name
529 if offset < derefed_dynamic_type_size:
530 member_list = list();
531 get_member_types_for_offset (derefed_dynamic_type, offset, member_list)
532 if member_list:
533 member_path = ''
534 for member in member_list:
535 member_name = member.name
536 if member_name:
537 if member_path:
538 member_path += '.'
539 member_path += member_name
540 if member_path:
541 if options.ivar_regex_blacklist:
542 for ivar_regex in options.ivar_regex_blacklist:
543 if ivar_regex.match(member_path):
544 print_entry = False
545 description += '.%s' % (member_path)
546 else:
547 description += '%u bytes after %s' % (offset - derefed_dynamic_type_size, derefed_dynamic_type_name)
Greg Clayton85e62ec2013-01-30 22:57:34 +0000548 else:
Greg Clayton966c6f62014-01-07 21:55:00 +0000549 # strip the "*" from the end of the name since we were unable to dereference this
550 description += dynamic_value.type.name[0:-1]
551 if print_entry:
552 match_idx += 1
553 result_output = ''
554 if description:
555 result_output += description
556 if options.print_type and derefed_dynamic_value:
557 result_output += ' %s' % (derefed_dynamic_value)
558 if options.print_object_description and dynamic_value:
559 desc = dynamic_value.GetObjectDescription()
560 if desc:
561 result_output += '\n%s' % (desc)
562 if result_output:
563 result.AppendMessage(result_output)
564 if options.memory:
565 cmd_result = lldb.SBCommandReturnObject()
566 if options.format == None:
567 memory_command = "memory read --force 0x%x 0x%x" % (malloc_addr, malloc_addr + malloc_size)
568 else:
569 memory_command = "memory read --force -f %s 0x%x 0x%x" % (options.format, malloc_addr, malloc_addr + malloc_size)
570 if options.verbose:
571 result.AppendMessage(memory_command)
572 lldb.debugger.GetCommandInterpreter().HandleCommand(memory_command, cmd_result)
573 result.AppendMessage(cmd_result.GetOutput())
574 if options.stack_history:
575 dump_stack_history_entries(options, result, malloc_addr, 1)
576 elif options.stack:
577 dump_stack_history_entries(options, result, malloc_addr, 0)
578 return i
Greg Clayton7fb671b2012-04-11 18:30:53 +0000579 else:
Greg Clayton7143f002012-09-04 14:09:21 +0000580 result.AppendMessage(str(expr_sbvalue.error))
Greg Claytone04cfd22012-07-11 22:13:18 +0000581 return 0
582
Greg Clayton85e62ec2013-01-30 22:57:34 +0000583def get_ptr_refs_options ():
584 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
585 description='''Searches all allocations on the heap for pointer values on
586darwin user space programs. Any matches that were found will dump the malloc
587blocks that contain the pointers and might be able to print what kind of
588objects the pointers are contained in using dynamic type information in the
589program.'''
590 parser = optparse.OptionParser(description=description, prog='ptr_refs',usage=usage)
591 add_common_options(parser)
592 return parser
Greg Clayton7fb671b2012-04-11 18:30:53 +0000593
Greg Clayton77677162012-04-12 18:57:36 +0000594def ptr_refs(debugger, command, result, dict):
Greg Clayton804de012012-04-11 16:27:06 +0000595 command_args = shlex.split(command)
Greg Clayton85e62ec2013-01-30 22:57:34 +0000596 parser = get_ptr_refs_options()
Greg Clayton804de012012-04-11 16:27:06 +0000597 try:
598 (options, args) = parser.parse_args(command_args)
599 except:
600 return
Greg Clayton7fb671b2012-04-11 18:30:53 +0000601
Greg Clayton85e62ec2013-01-30 22:57:34 +0000602 process = lldb.debugger.GetSelectedTarget().GetProcess()
603 if not process:
604 result.AppendMessage('error: invalid process')
605 return
606 frame = process.GetSelectedThread().GetSelectedFrame()
607 if not frame:
608 result.AppendMessage('error: invalid frame')
609 return
610
Greg Clayton7fb671b2012-04-11 18:30:53 +0000611 options.type = 'pointer'
Greg Clayton85e62ec2013-01-30 22:57:34 +0000612 if options.format == None:
613 options.format = "A" # 'A' is "address" format
614
Greg Clayton804de012012-04-11 16:27:06 +0000615 if args:
Greg Clayton85e62ec2013-01-30 22:57:34 +0000616 # When we initialize the expression, we must define any types that
617 # we will need when looking at every allocation. We must also define
618 # a type named callback_baton_t and make an instance named "baton"
619 # and initialize it how ever we want to. The address of "baton" will
620 # be passed into our range callback. callback_baton_t must contain
621 # a member named "callback" whose type is "range_callback_t". This
622 # will be used by our zone callbacks to call the range callback for
623 # each malloc range.
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000624 user_init_code_format = '''
625#define MAX_MATCHES %u
Greg Clayton85e62ec2013-01-30 22:57:34 +0000626struct $malloc_match {
627 void *addr;
628 uintptr_t size;
629 uintptr_t offset;
630 uintptr_t type;
631};
632typedef struct callback_baton_t {
633 range_callback_t callback;
634 unsigned num_matches;
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000635 $malloc_match matches[MAX_MATCHES];
Greg Clayton85e62ec2013-01-30 22:57:34 +0000636 void *ptr;
637} callback_baton_t;
638range_callback_t range_callback = [](task_t task, void *baton, unsigned type, uintptr_t ptr_addr, uintptr_t ptr_size) -> void {
639 callback_baton_t *info = (callback_baton_t *)baton;
640 typedef void* T;
641 const unsigned size = sizeof(T);
642 T *array = (T*)ptr_addr;
643 for (unsigned idx = 0; ((idx + 1) * sizeof(T)) <= ptr_size; ++idx) {
644 if (array[idx] == info->ptr) {
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000645 if (info->num_matches < MAX_MATCHES) {
Greg Clayton85e62ec2013-01-30 22:57:34 +0000646 info->matches[info->num_matches].addr = (void*)ptr_addr;
647 info->matches[info->num_matches].size = ptr_size;
648 info->matches[info->num_matches].offset = idx*sizeof(T);
649 info->matches[info->num_matches].type = type;
650 ++info->num_matches;
651 }
652 }
653 }
654};
655callback_baton_t baton = { range_callback, 0, {0}, (void *)%s };
656'''
657 # We must also define a snippet of code to be run that returns
658 # the result of the expression we run.
659 # Here we return NULL if our pointer was not found in any malloc blocks,
660 # and we return the address of the matches array so we can then access
661 # the matching results
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000662 user_return_code = '''if (baton.num_matches < MAX_MATCHES)
663 baton.matches[baton.num_matches].addr = 0; // Terminate the matches array
Greg Clayton85e62ec2013-01-30 22:57:34 +0000664baton.matches'''
665 # Iterate through all of our pointer expressions and display the results
666 for ptr_expr in args:
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000667 user_init_code = user_init_code_format % (options.max_matches, ptr_expr)
Greg Clayton13fbb992013-02-01 00:47:49 +0000668 expr = get_iterate_memory_expr(options, process, user_init_code, user_return_code)
Greg Clayton85e62ec2013-01-30 22:57:34 +0000669 arg_str_description = 'malloc block containing pointer %s' % ptr_expr
670 display_match_results (result, options, arg_str_description, expr)
Greg Clayton804de012012-04-11 16:27:06 +0000671 else:
Greg Clayton85e62ec2013-01-30 22:57:34 +0000672 result.AppendMessage('error: no pointer arguments were given')
673
674def get_cstr_refs_options():
675 usage = "usage: %prog [options] <CSTR> [CSTR ...]"
676 description='''Searches all allocations on the heap for C string values on
677darwin user space programs. Any matches that were found will dump the malloc
678blocks that contain the C strings and might be able to print what kind of
679objects the pointers are contained in using dynamic type information in the
680program.'''
681 parser = optparse.OptionParser(description=description, prog='cstr_refs',usage=usage)
682 add_common_options(parser)
683 return parser
Greg Clayton804de012012-04-11 16:27:06 +0000684
Greg Clayton77677162012-04-12 18:57:36 +0000685def cstr_refs(debugger, command, result, dict):
Greg Clayton7fb671b2012-04-11 18:30:53 +0000686 command_args = shlex.split(command)
Greg Clayton85e62ec2013-01-30 22:57:34 +0000687 parser = get_cstr_refs_options();
Greg Clayton7fb671b2012-04-11 18:30:53 +0000688 try:
689 (options, args) = parser.parse_args(command_args)
690 except:
691 return
692
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000693 process = lldb.debugger.GetSelectedTarget().GetProcess()
694 if not process:
695 result.AppendMessage('error: invalid process')
696 return
697 frame = process.GetSelectedThread().GetSelectedFrame()
Greg Clayton85e62ec2013-01-30 22:57:34 +0000698 if not frame:
699 result.AppendMessage('error: invalid frame')
700 return
701
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000702
Greg Clayton7fb671b2012-04-11 18:30:53 +0000703 options.type = 'cstr'
Greg Clayton85e62ec2013-01-30 22:57:34 +0000704 if options.format == None:
705 options.format = "Y" # 'Y' is "bytes with ASCII" format
Greg Clayton7fb671b2012-04-11 18:30:53 +0000706
707 if args:
Greg Clayton85e62ec2013-01-30 22:57:34 +0000708 # When we initialize the expression, we must define any types that
709 # we will need when looking at every allocation. We must also define
710 # a type named callback_baton_t and make an instance named "baton"
711 # and initialize it how ever we want to. The address of "baton" will
712 # be passed into our range callback. callback_baton_t must contain
713 # a member named "callback" whose type is "range_callback_t". This
714 # will be used by our zone callbacks to call the range callback for
715 # each malloc range.
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000716 user_init_code_format = '''
717#define MAX_MATCHES %u
718struct $malloc_match {
Greg Clayton85e62ec2013-01-30 22:57:34 +0000719 void *addr;
720 uintptr_t size;
721 uintptr_t offset;
722 uintptr_t type;
723};
724typedef struct callback_baton_t {
725 range_callback_t callback;
726 unsigned num_matches;
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000727 $malloc_match matches[MAX_MATCHES];
Greg Clayton85e62ec2013-01-30 22:57:34 +0000728 const char *cstr;
729 unsigned cstr_len;
730} callback_baton_t;
731range_callback_t range_callback = [](task_t task, void *baton, unsigned type, uintptr_t ptr_addr, uintptr_t ptr_size) -> void {
732 callback_baton_t *info = (callback_baton_t *)baton;
733 if (info->cstr_len < ptr_size) {
734 const char *begin = (const char *)ptr_addr;
735 const char *end = begin + ptr_size - info->cstr_len;
736 for (const char *s = begin; s < end; ++s) {
737 if ((int)memcmp(s, info->cstr, info->cstr_len) == 0) {
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000738 if (info->num_matches < MAX_MATCHES) {
Greg Clayton85e62ec2013-01-30 22:57:34 +0000739 info->matches[info->num_matches].addr = (void*)ptr_addr;
740 info->matches[info->num_matches].size = ptr_size;
741 info->matches[info->num_matches].offset = s - begin;
742 info->matches[info->num_matches].type = type;
743 ++info->num_matches;
744 }
745 }
746 }
747 }
748};
749const char *cstr = "%s";
750callback_baton_t baton = { range_callback, 0, {0}, cstr, (unsigned)strlen(cstr) };'''
751 # We must also define a snippet of code to be run that returns
752 # the result of the expression we run.
753 # Here we return NULL if our pointer was not found in any malloc blocks,
754 # and we return the address of the matches array so we can then access
755 # the matching results
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000756 user_return_code = '''if (baton.num_matches < MAX_MATCHES)
757 baton.matches[baton.num_matches].addr = 0; // Terminate the matches array
758baton.matches'''
Greg Clayton85e62ec2013-01-30 22:57:34 +0000759 # Iterate through all of our pointer expressions and display the results
760 for cstr in args:
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000761 user_init_code = user_init_code_format % (options.max_matches, cstr)
Greg Clayton13fbb992013-02-01 00:47:49 +0000762 expr = get_iterate_memory_expr(options, process, user_init_code, user_return_code)
Greg Clayton85e62ec2013-01-30 22:57:34 +0000763 arg_str_description = 'malloc block containing "%s"' % cstr
764 display_match_results (result, options, arg_str_description, expr)
Greg Clayton7fb671b2012-04-11 18:30:53 +0000765 else:
Greg Clayton85e62ec2013-01-30 22:57:34 +0000766 result.AppendMessage('error: command takes one or more C string arguments')
767
768
769def get_malloc_info_options():
770 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
771 description='''Searches the heap a malloc block that contains the addresses
772specified as one or more address expressions. Any matches that were found will
773dump the malloc blocks that match or contain the specified address. The matching
774blocks might be able to show what kind of objects they are using dynamic type
775information in the program.'''
776 parser = optparse.OptionParser(description=description, prog='malloc_info',usage=usage)
777 add_common_options(parser)
778 return parser
Greg Clayton804de012012-04-11 16:27:06 +0000779
Greg Clayton77677162012-04-12 18:57:36 +0000780def malloc_info(debugger, command, result, dict):
781 command_args = shlex.split(command)
Greg Clayton85e62ec2013-01-30 22:57:34 +0000782 parser = get_malloc_info_options()
Greg Clayton77677162012-04-12 18:57:36 +0000783 try:
784 (options, args) = parser.parse_args(command_args)
785 except:
786 return
Greg Clayton13fbb992013-02-01 00:47:49 +0000787 malloc_info_impl (debugger, result, options, args)
788
789def malloc_info_impl (debugger, result, options, args):
790 # We are specifically looking for something on the heap only
791 options.type = 'malloc_info'
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000792
793 process = lldb.debugger.GetSelectedTarget().GetProcess()
794 if not process:
795 result.AppendMessage('error: invalid process')
796 return
797 frame = process.GetSelectedThread().GetSelectedFrame()
798 if not frame:
799 result.AppendMessage('error: invalid frame')
800 return
Greg Clayton85e62ec2013-01-30 22:57:34 +0000801
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000802 user_init_code_format = '''
803struct $malloc_match {
Greg Clayton85e62ec2013-01-30 22:57:34 +0000804 void *addr;
805 uintptr_t size;
806 uintptr_t offset;
807 uintptr_t type;
808};
809typedef struct callback_baton_t {
810 range_callback_t callback;
811 unsigned num_matches;
812 $malloc_match matches[2]; // Two items so they can be NULL terminated
813 void *ptr;
814} callback_baton_t;
815range_callback_t range_callback = [](task_t task, void *baton, unsigned type, uintptr_t ptr_addr, uintptr_t ptr_size) -> void {
816 callback_baton_t *info = (callback_baton_t *)baton;
817 if (info->num_matches == 0) {
818 uint8_t *p = (uint8_t *)info->ptr;
819 uint8_t *lo = (uint8_t *)ptr_addr;
820 uint8_t *hi = lo + ptr_size;
821 if (lo <= p && p < hi) {
822 info->matches[info->num_matches].addr = (void*)ptr_addr;
823 info->matches[info->num_matches].size = ptr_size;
824 info->matches[info->num_matches].offset = p - lo;
825 info->matches[info->num_matches].type = type;
826 info->num_matches = 1;
827 }
828 }
829};
830callback_baton_t baton = { range_callback, 0, {0}, (void *)%s };
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000831baton.matches[0].addr = 0;
Greg Clayton85e62ec2013-01-30 22:57:34 +0000832baton.matches[1].addr = 0;'''
Greg Clayton77677162012-04-12 18:57:36 +0000833 if args:
Greg Clayton13fbb992013-02-01 00:47:49 +0000834 total_matches = 0
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000835 for ptr_expr in args:
836 user_init_code = user_init_code_format % (ptr_expr)
Greg Clayton13fbb992013-02-01 00:47:49 +0000837 expr = get_iterate_memory_expr(options, process, user_init_code, 'baton.matches')
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000838 arg_str_description = 'malloc block that contains %s' % ptr_expr
Greg Clayton13fbb992013-02-01 00:47:49 +0000839 total_matches += display_match_results (result, options, arg_str_description, expr)
840 return total_matches
Greg Clayton77677162012-04-12 18:57:36 +0000841 else:
Greg Clayton85e62ec2013-01-30 22:57:34 +0000842 result.AppendMessage('error: command takes one or more pointer expressions')
Greg Clayton13fbb992013-02-01 00:47:49 +0000843 return 0
Greg Clayton77677162012-04-12 18:57:36 +0000844
Greg Clayton85e62ec2013-01-30 22:57:34 +0000845def get_thread_stack_ranges_struct (process):
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000846 '''Create code that defines a structure that represents threads stack bounds
847 for all threads. It returns a static sized array initialized with all of
848 the tid, base, size structs for all the threads.'''
Greg Clayton85e62ec2013-01-30 22:57:34 +0000849 stack_dicts = list()
850 if process:
851 i = 0;
852 for thread in process:
853 min_sp = thread.frame[0].sp
854 max_sp = min_sp
855 for frame in thread.frames:
856 sp = frame.sp
857 if sp < min_sp: min_sp = sp
858 if sp > max_sp: max_sp = sp
859 if min_sp < max_sp:
860 stack_dicts.append ({ 'tid' : thread.GetThreadID(), 'base' : min_sp , 'size' : max_sp-min_sp, 'index' : i })
861 i += 1
862 stack_dicts_len = len(stack_dicts)
863 if stack_dicts_len > 0:
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000864 result = '''
865#define NUM_STACKS %u
Greg Clayton13fbb992013-02-01 00:47:49 +0000866#define STACK_RED_ZONE_SIZE %u
Greg Clayton85e62ec2013-01-30 22:57:34 +0000867typedef struct thread_stack_t { uint64_t tid, base, size; } thread_stack_t;
Greg Clayton13fbb992013-02-01 00:47:49 +0000868thread_stack_t stacks[NUM_STACKS];''' % (stack_dicts_len, process.target.GetStackRedZoneSize())
Greg Clayton85e62ec2013-01-30 22:57:34 +0000869 for stack_dict in stack_dicts:
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000870 result += '''
871stacks[%(index)u].tid = 0x%(tid)x;
Greg Clayton85e62ec2013-01-30 22:57:34 +0000872stacks[%(index)u].base = 0x%(base)x;
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000873stacks[%(index)u].size = 0x%(size)x;''' % stack_dict
Greg Clayton85e62ec2013-01-30 22:57:34 +0000874 return result
875 else:
Greg Clayton966c6f62014-01-07 21:55:00 +0000876 return ''
Greg Claytonae23ed32012-10-08 22:39:38 +0000877
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000878def get_sections_ranges_struct (process):
879 '''Create code that defines a structure that represents all segments that
880 can contain data for all images in "target". It returns a static sized
881 array initialized with all of base, size structs for all the threads.'''
882 target = process.target
883 segment_dicts = list()
884 for (module_idx, module) in enumerate(target.modules):
885 for sect_idx in range(module.GetNumSections()):
886 section = module.GetSectionAtIndex(sect_idx)
887 if not section:
888 break
889 name = section.name
890 if name != '__TEXT' and name != '__LINKEDIT' and name != '__PAGEZERO':
891 base = section.GetLoadAddress(target)
892 size = section.GetByteSize()
893 if base != lldb.LLDB_INVALID_ADDRESS and size > 0:
894 segment_dicts.append ({ 'base' : base, 'size' : size })
895 segment_dicts_len = len(segment_dicts)
896 if segment_dicts_len > 0:
897 result = '''
898#define NUM_SEGMENTS %u
899typedef struct segment_range_t { uint64_t base; uint32_t size; } segment_range_t;
900segment_range_t segments[NUM_SEGMENTS];''' % (segment_dicts_len,)
901 for (idx, segment_dict) in enumerate(segment_dicts):
902 segment_dict['index'] = idx
903 result += '''
904segments[%(index)u].base = 0x%(base)x;
905segments[%(index)u].size = 0x%(size)x;''' % segment_dict
906 return result
Greg Claytonae23ed32012-10-08 22:39:38 +0000907 else:
Greg Clayton966c6f62014-01-07 21:55:00 +0000908 return ''
Greg Claytonae23ed32012-10-08 22:39:38 +0000909
Greg Claytone04cfd22012-07-11 22:13:18 +0000910def section_ptr_refs(debugger, command, result, dict):
911 command_args = shlex.split(command)
912 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
913 description='''Searches section contents for pointer values in darwin user space programs.'''
914 parser = optparse.OptionParser(description=description, prog='section_ptr_refs',usage=usage)
915 add_common_options(parser)
916 parser.add_option('--section', action='append', type='string', dest='section_names', help='section name to search', default=list())
917 try:
918 (options, args) = parser.parse_args(command_args)
919 except:
920 return
921
922 options.type = 'pointer'
Greg Claytonae23ed32012-10-08 22:39:38 +0000923
Greg Claytone04cfd22012-07-11 22:13:18 +0000924 sections = list()
925 section_modules = list()
926 if not options.section_names:
Greg Claytonc373ca52012-09-01 00:34:35 +0000927 result.AppendMessage('error: at least one section must be specified with the --section option')
Greg Claytone04cfd22012-07-11 22:13:18 +0000928 return
929
Greg Clayton85e62ec2013-01-30 22:57:34 +0000930 target = lldb.debugger.GetSelectedTarget()
931 for module in target.modules:
Greg Claytone04cfd22012-07-11 22:13:18 +0000932 for section_name in options.section_names:
933 section = module.section[section_name]
934 if section:
935 sections.append (section)
936 section_modules.append (module)
937 if sections:
938 dylid_load_err = load_dylib()
939 if dylid_load_err:
Greg Claytonc373ca52012-09-01 00:34:35 +0000940 result.AppendMessage(dylid_load_err)
Greg Claytone04cfd22012-07-11 22:13:18 +0000941 return
Greg Clayton85e62ec2013-01-30 22:57:34 +0000942 frame = target.GetProcess().GetSelectedThread().GetSelectedFrame()
Greg Claytone04cfd22012-07-11 22:13:18 +0000943 for expr_str in args:
944 for (idx, section) in enumerate(sections):
945 expr = 'find_pointer_in_memory(0x%xllu, %ullu, (void *)%s)' % (section.addr.load_addr, section.size, expr_str)
946 arg_str_description = 'section %s.%s containing "%s"' % (section_modules[idx].file.fullpath, section.name, expr_str)
Greg Clayton85e62ec2013-01-30 22:57:34 +0000947 num_matches = display_match_results (result, options, arg_str_description, expr, False)
Greg Claytone04cfd22012-07-11 22:13:18 +0000948 if num_matches:
949 if num_matches < options.max_matches:
950 options.max_matches = options.max_matches - num_matches
951 else:
952 options.max_matches = 0
953 if options.max_matches == 0:
954 return
955 else:
Greg Claytonc373ca52012-09-01 00:34:35 +0000956 result.AppendMessage('error: no sections were found that match any of %s' % (', '.join(options.section_names)))
Greg Claytone04cfd22012-07-11 22:13:18 +0000957
Greg Clayton85e62ec2013-01-30 22:57:34 +0000958def get_objc_refs_options():
959 usage = "usage: %prog [options] <CLASS> [CLASS ...]"
960 description='''Searches all allocations on the heap for instances of
961objective C classes, or any classes that inherit from the specified classes
962in darwin user space programs. Any matches that were found will dump the malloc
963blocks that contain the C strings and might be able to print what kind of
964objects the pointers are contained in using dynamic type information in the
965program.'''
966 parser = optparse.OptionParser(description=description, prog='objc_refs',usage=usage)
967 add_common_options(parser)
968 return parser
969
Greg Clayton774ebdf2012-08-11 02:26:26 +0000970def objc_refs(debugger, command, result, dict):
971 command_args = shlex.split(command)
Greg Clayton85e62ec2013-01-30 22:57:34 +0000972 parser = get_objc_refs_options()
Greg Clayton774ebdf2012-08-11 02:26:26 +0000973 try:
974 (options, args) = parser.parse_args(command_args)
975 except:
976 return
977
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000978 process = lldb.debugger.GetSelectedTarget().GetProcess()
979 if not process:
980 result.AppendMessage('error: invalid process')
981 return
982 frame = process.GetSelectedThread().GetSelectedFrame()
Greg Clayton85e62ec2013-01-30 22:57:34 +0000983 if not frame:
984 result.AppendMessage('error: invalid frame')
985 return
986
987 options.type = 'isa'
988 if options.format == None:
989 options.format = "A" # 'A' is "address" format
990
Greg Clayton927fa012013-04-03 07:25:30 +0000991 expr_options = lldb.SBExpressionOptions()
992 expr_options.SetIgnoreBreakpoints(True);
993 expr_options.SetTimeoutInMicroSeconds (3*1000*1000) # 3 second infinite timeout
994 expr_options.SetTryAllThreads (True)
Greg Clayton6e7ab022015-01-14 21:37:19 +0000995 expr_options.SetLanguage(lldb.eLanguageTypeObjC_plus_plus)
Greg Clayton927fa012013-04-03 07:25:30 +0000996 num_objc_classes_value = frame.EvaluateExpression("(int)objc_getClassList((void *)0, (int)0)", expr_options)
Greg Clayton85e62ec2013-01-30 22:57:34 +0000997 if not num_objc_classes_value.error.Success():
998 result.AppendMessage('error: %s' % num_objc_classes_value.error.GetCString())
999 return
1000
1001 num_objc_classes = num_objc_classes_value.GetValueAsUnsigned()
1002 if num_objc_classes == 0:
1003 result.AppendMessage('error: no objective C classes in program')
1004 return
1005
1006 if args:
1007 # When we initialize the expression, we must define any types that
1008 # we will need when looking at every allocation. We must also define
1009 # a type named callback_baton_t and make an instance named "baton"
1010 # and initialize it how ever we want to. The address of "baton" will
1011 # be passed into our range callback. callback_baton_t must contain
1012 # a member named "callback" whose type is "range_callback_t". This
1013 # will be used by our zone callbacks to call the range callback for
1014 # each malloc range.
Greg Clayton13fbb992013-02-01 00:47:49 +00001015 user_init_code_format = '''
1016#define MAX_MATCHES %u
Greg Claytone7fc9cc2013-01-31 06:38:09 +00001017struct $malloc_match {
Greg Clayton85e62ec2013-01-30 22:57:34 +00001018 void *addr;
1019 uintptr_t size;
1020 uintptr_t offset;
1021 uintptr_t type;
1022};
1023typedef int (*compare_callback_t)(const void *a, const void *b);
1024typedef struct callback_baton_t {
1025 range_callback_t callback;
1026 compare_callback_t compare_callback;
1027 unsigned num_matches;
Greg Claytone7fc9cc2013-01-31 06:38:09 +00001028 $malloc_match matches[MAX_MATCHES];
Greg Clayton85e62ec2013-01-30 22:57:34 +00001029 void *isa;
1030 Class classes[%u];
1031} callback_baton_t;
1032compare_callback_t compare_callback = [](const void *a, const void *b) -> int {
1033 Class a_ptr = *(Class *)a;
1034 Class b_ptr = *(Class *)b;
1035 if (a_ptr < b_ptr) return -1;
1036 if (a_ptr > b_ptr) return +1;
1037 return 0;
1038};
Sean Callananf09a3db2013-08-13 00:53:33 +00001039typedef Class (*class_getSuperclass_type)(void *isa);
Greg Clayton85e62ec2013-01-30 22:57:34 +00001040range_callback_t range_callback = [](task_t task, void *baton, unsigned type, uintptr_t ptr_addr, uintptr_t ptr_size) -> void {
Sean Callananf09a3db2013-08-13 00:53:33 +00001041 class_getSuperclass_type class_getSuperclass_impl = (class_getSuperclass_type)class_getSuperclass;
Greg Clayton85e62ec2013-01-30 22:57:34 +00001042 callback_baton_t *info = (callback_baton_t *)baton;
1043 if (sizeof(Class) <= ptr_size) {
1044 Class *curr_class_ptr = (Class *)ptr_addr;
1045 Class *matching_class_ptr = (Class *)bsearch (curr_class_ptr,
1046 (const void *)info->classes,
1047 sizeof(info->classes)/sizeof(Class),
1048 sizeof(Class),
1049 info->compare_callback);
1050 if (matching_class_ptr) {
1051 bool match = false;
1052 if (info->isa) {
1053 Class isa = *curr_class_ptr;
1054 if (info->isa == isa)
1055 match = true;
1056 else { // if (info->objc.match_superclasses) {
Sean Callananf09a3db2013-08-13 00:53:33 +00001057 Class super = class_getSuperclass_impl(isa);
Greg Clayton85e62ec2013-01-30 22:57:34 +00001058 while (super) {
1059 if (super == info->isa) {
1060 match = true;
1061 break;
1062 }
Sean Callananf09a3db2013-08-13 00:53:33 +00001063 super = class_getSuperclass_impl(super);
Greg Clayton85e62ec2013-01-30 22:57:34 +00001064 }
1065 }
1066 }
1067 else
1068 match = true;
1069 if (match) {
Greg Claytone7fc9cc2013-01-31 06:38:09 +00001070 if (info->num_matches < MAX_MATCHES) {
Greg Clayton85e62ec2013-01-30 22:57:34 +00001071 info->matches[info->num_matches].addr = (void*)ptr_addr;
1072 info->matches[info->num_matches].size = ptr_size;
1073 info->matches[info->num_matches].offset = 0;
1074 info->matches[info->num_matches].type = type;
1075 ++info->num_matches;
1076 }
1077 }
1078 }
1079 }
1080};
1081callback_baton_t baton = { range_callback, compare_callback, 0, {0}, (void *)0x%x, {0} };
1082int nc = (int)objc_getClassList(baton.classes, sizeof(baton.classes)/sizeof(Class));
1083(void)qsort (baton.classes, sizeof(baton.classes)/sizeof(Class), sizeof(Class), compare_callback);'''
1084 # We must also define a snippet of code to be run that returns
1085 # the result of the expression we run.
1086 # Here we return NULL if our pointer was not found in any malloc blocks,
1087 # and we return the address of the matches array so we can then access
1088 # the matching results
Greg Claytone7fc9cc2013-01-31 06:38:09 +00001089 user_return_code = '''if (baton.num_matches < MAX_MATCHES)
1090 baton.matches[baton.num_matches].addr = 0; // Terminate the matches array
1091 baton.matches'''
Greg Clayton85e62ec2013-01-30 22:57:34 +00001092 # Iterate through all of our ObjC class name arguments
1093 for class_name in args:
1094 addr_expr_str = "(void *)[%s class]" % class_name
Greg Clayton927fa012013-04-03 07:25:30 +00001095 expr_options = lldb.SBExpressionOptions()
1096 expr_options.SetIgnoreBreakpoints(True);
1097 expr_options.SetTimeoutInMicroSeconds (1*1000*1000) # 1 second timeout
1098 expr_options.SetTryAllThreads (True)
Greg Clayton6e7ab022015-01-14 21:37:19 +00001099 expr_options.SetLanguage(lldb.eLanguageTypeObjC_plus_plus)
Greg Clayton927fa012013-04-03 07:25:30 +00001100 expr_sbvalue = frame.EvaluateExpression (addr_expr_str, expr_options)
Greg Clayton85e62ec2013-01-30 22:57:34 +00001101 if expr_sbvalue.error.Success():
1102 isa = expr_sbvalue.unsigned
1103 if isa:
1104 options.type = 'isa'
Greg Claytone7fc9cc2013-01-31 06:38:09 +00001105 result.AppendMessage('Searching for all instances of classes or subclasses of "%s" (isa=0x%x)' % (class_name, isa))
1106 user_init_code = user_init_code_format % (options.max_matches, num_objc_classes, isa)
Greg Clayton13fbb992013-02-01 00:47:49 +00001107 expr = get_iterate_memory_expr(options, process, user_init_code, user_return_code)
Greg Clayton85e62ec2013-01-30 22:57:34 +00001108 arg_str_description = 'objective C classes with isa 0x%x' % isa
1109 display_match_results (result, options, arg_str_description, expr)
Greg Clayton774ebdf2012-08-11 02:26:26 +00001110 else:
Greg Clayton85e62ec2013-01-30 22:57:34 +00001111 result.AppendMessage('error: Can\'t find isa for an ObjC class named "%s"' % (class_name))
1112 else:
1113 result.AppendMessage('error: expression error for "%s": %s' % (addr_expr_str, expr_sbvalue.error))
1114 else:
1115 result.AppendMessage('error: command takes one or more C string arguments');
Greg Clayton774ebdf2012-08-11 02:26:26 +00001116
Greg Claytond712ef02012-04-25 18:40:20 +00001117if __name__ == '__main__':
1118 lldb.debugger = lldb.SBDebugger.Create()
1119
Greg Clayton85e62ec2013-01-30 22:57:34 +00001120# Make the options so we can generate the help text for the new LLDB
1121# command line command prior to registering it with LLDB below. This way
1122# if clients in LLDB type "help malloc_info", they will see the exact same
1123# output as typing "malloc_info --help".
1124ptr_refs.__doc__ = get_ptr_refs_options().format_help()
1125cstr_refs.__doc__ = get_cstr_refs_options().format_help()
1126malloc_info.__doc__ = get_malloc_info_options().format_help()
1127objc_refs.__doc__ = get_objc_refs_options().format_help()
Enrico Granatacd4218f2013-02-22 02:21:10 +00001128lldb.debugger.HandleCommand('command script add -f %s.ptr_refs ptr_refs' % __name__)
1129lldb.debugger.HandleCommand('command script add -f %s.cstr_refs cstr_refs' % __name__)
1130lldb.debugger.HandleCommand('command script add -f %s.malloc_info malloc_info' % __name__)
Greg Clayton85e62ec2013-01-30 22:57:34 +00001131# lldb.debugger.HandleCommand('command script add -f %s.heap heap' % package_name)
1132# lldb.debugger.HandleCommand('command script add -f %s.section_ptr_refs section_ptr_refs' % package_name)
1133# lldb.debugger.HandleCommand('command script add -f %s.stack_ptr_refs stack_ptr_refs' % package_name)
Enrico Granatacd4218f2013-02-22 02:21:10 +00001134lldb.debugger.HandleCommand('command script add -f %s.objc_refs objc_refs' % __name__)
Greg Clayton85e62ec2013-01-30 22:57:34 +00001135print '"malloc_info", "ptr_refs", "cstr_refs", and "objc_refs" commands have been installed, use the "--help" options on these commands for detailed help.'
Greg Clayton804de012012-04-11 16:27:06 +00001136
1137
1138
1139