blob: f13a3bbf33dd39f827a52c2b6cc353fda88fa821 [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
Greg Clayton4e1042e2015-05-27 22:32:39 +0000437def display_match_results (result, options, arg_str_description, expr, print_no_matches, expr_prefix = None):
Greg Clayton85e62ec2013-01-30 22:57:34 +0000438 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 Clayton4e1042e2015-05-27 22:32:39 +0000448 if expr_prefix:
449 expr_options.SetPrefix (expr_prefix)
Greg Clayton927fa012013-04-03 07:25:30 +0000450 expr_sbvalue = frame.EvaluateExpression (expr, expr_options)
Greg Clayton85e62ec2013-01-30 22:57:34 +0000451 if options.verbose:
452 print "expression:"
453 print expr
454 print "expression result:"
455 print expr_sbvalue
Greg Clayton7fb671b2012-04-11 18:30:53 +0000456 if expr_sbvalue.error.Success():
Greg Clayton966c6f62014-01-07 21:55:00 +0000457 match_value = lldb.value(expr_sbvalue)
458 i = 0
459 match_idx = 0
460 while 1:
461 print_entry = True
462 match_entry = match_value[i]; i += 1
463 if i > options.max_matches:
464 result.AppendMessage('warning: the max number of matches (%u) was reached, use the --max-matches option to get more results' % (options.max_matches))
465 break
466 malloc_addr = match_entry.addr.sbvalue.unsigned
467 if malloc_addr == 0:
468 break
469 malloc_size = int(match_entry.size)
470 offset = int(match_entry.offset)
471
472 if options.offset >= 0 and options.offset != offset:
473 print_entry = False
474 else:
475 match_addr = malloc_addr + offset
476 type_flags = int(match_entry.type)
477 #result.AppendMessage (hex(malloc_addr + offset))
478 if type_flags == 64:
479 search_stack_old = options.search_stack
480 search_segments_old = options.search_segments
481 search_heap_old = options.search_heap
482 search_vm_regions = options.search_vm_regions
483 options.search_stack = True
484 options.search_segments = True
485 options.search_heap = True
486 options.search_vm_regions = False
487 if malloc_info_impl (lldb.debugger, result, options, [hex(malloc_addr + offset)]):
488 print_entry = False
489 options.search_stack = search_stack_old
490 options.search_segments = search_segments_old
491 options.search_heap = search_heap_old
492 options.search_vm_regions = search_vm_regions
Greg Claytone04cfd22012-07-11 22:13:18 +0000493 if print_entry:
Greg Clayton966c6f62014-01-07 21:55:00 +0000494 description = '%#16.16x: %s' % (match_addr, type_flags_to_description(type_flags, malloc_addr, malloc_size, offset))
495 if options.show_size:
496 description += ' <%5u>' % (malloc_size)
497 if options.show_range:
498 description += ' [%#x - %#x)' % (malloc_addr, malloc_addr + malloc_size)
499 derefed_dynamic_value = None
500 dynamic_value = match_entry.addr.sbvalue.GetDynamicValue(lldb.eDynamicCanRunTarget)
501 if dynamic_value.type.name == 'void *':
502 if options.type == 'pointer' and malloc_size == 4096:
503 error = lldb.SBError()
504 process = expr_sbvalue.GetProcess()
505 target = expr_sbvalue.GetTarget()
506 data = bytearray(process.ReadMemory(malloc_addr, 16, error))
507 if data == '\xa1\xa1\xa1\xa1AUTORELEASE!':
508 ptr_size = target.addr_size
509 thread = process.ReadUnsignedFromMemory (malloc_addr + 16 + ptr_size, ptr_size, error)
510 # 4 bytes 0xa1a1a1a1
511 # 12 bytes 'AUTORELEASE!'
512 # ptr bytes autorelease insertion point
513 # ptr bytes pthread_t
514 # ptr bytes next colder page
515 # ptr bytes next hotter page
516 # 4 bytes this page's depth in the list
517 # 4 bytes high-water mark
518 description += ' AUTORELEASE! for pthread_t %#x' % (thread)
519 # else:
520 # description += 'malloc(%u)' % (malloc_size)
521 # else:
522 # description += 'malloc(%u)' % (malloc_size)
523 else:
524 derefed_dynamic_value = dynamic_value.deref
525 if derefed_dynamic_value:
526 derefed_dynamic_type = derefed_dynamic_value.type
527 derefed_dynamic_type_size = derefed_dynamic_type.size
528 derefed_dynamic_type_name = derefed_dynamic_type.name
529 description += ' '
530 description += derefed_dynamic_type_name
531 if offset < derefed_dynamic_type_size:
532 member_list = list();
533 get_member_types_for_offset (derefed_dynamic_type, offset, member_list)
534 if member_list:
535 member_path = ''
536 for member in member_list:
537 member_name = member.name
538 if member_name:
539 if member_path:
540 member_path += '.'
541 member_path += member_name
542 if member_path:
543 if options.ivar_regex_blacklist:
544 for ivar_regex in options.ivar_regex_blacklist:
545 if ivar_regex.match(member_path):
546 print_entry = False
547 description += '.%s' % (member_path)
548 else:
549 description += '%u bytes after %s' % (offset - derefed_dynamic_type_size, derefed_dynamic_type_name)
Greg Clayton85e62ec2013-01-30 22:57:34 +0000550 else:
Greg Clayton966c6f62014-01-07 21:55:00 +0000551 # strip the "*" from the end of the name since we were unable to dereference this
552 description += dynamic_value.type.name[0:-1]
553 if print_entry:
554 match_idx += 1
555 result_output = ''
556 if description:
557 result_output += description
558 if options.print_type and derefed_dynamic_value:
559 result_output += ' %s' % (derefed_dynamic_value)
560 if options.print_object_description and dynamic_value:
561 desc = dynamic_value.GetObjectDescription()
562 if desc:
563 result_output += '\n%s' % (desc)
564 if result_output:
565 result.AppendMessage(result_output)
566 if options.memory:
567 cmd_result = lldb.SBCommandReturnObject()
568 if options.format == None:
569 memory_command = "memory read --force 0x%x 0x%x" % (malloc_addr, malloc_addr + malloc_size)
570 else:
571 memory_command = "memory read --force -f %s 0x%x 0x%x" % (options.format, malloc_addr, malloc_addr + malloc_size)
572 if options.verbose:
573 result.AppendMessage(memory_command)
574 lldb.debugger.GetCommandInterpreter().HandleCommand(memory_command, cmd_result)
575 result.AppendMessage(cmd_result.GetOutput())
576 if options.stack_history:
577 dump_stack_history_entries(options, result, malloc_addr, 1)
578 elif options.stack:
579 dump_stack_history_entries(options, result, malloc_addr, 0)
580 return i
Greg Clayton7fb671b2012-04-11 18:30:53 +0000581 else:
Greg Clayton7143f002012-09-04 14:09:21 +0000582 result.AppendMessage(str(expr_sbvalue.error))
Greg Claytone04cfd22012-07-11 22:13:18 +0000583 return 0
584
Greg Clayton85e62ec2013-01-30 22:57:34 +0000585def get_ptr_refs_options ():
586 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
587 description='''Searches all allocations on the heap for pointer values on
588darwin user space programs. Any matches that were found will dump the malloc
589blocks that contain the pointers and might be able to print what kind of
590objects the pointers are contained in using dynamic type information in the
591program.'''
592 parser = optparse.OptionParser(description=description, prog='ptr_refs',usage=usage)
593 add_common_options(parser)
594 return parser
Greg Clayton7fb671b2012-04-11 18:30:53 +0000595
Greg Clayton77677162012-04-12 18:57:36 +0000596def ptr_refs(debugger, command, result, dict):
Greg Clayton804de012012-04-11 16:27:06 +0000597 command_args = shlex.split(command)
Greg Clayton85e62ec2013-01-30 22:57:34 +0000598 parser = get_ptr_refs_options()
Greg Clayton804de012012-04-11 16:27:06 +0000599 try:
600 (options, args) = parser.parse_args(command_args)
601 except:
602 return
Greg Clayton7fb671b2012-04-11 18:30:53 +0000603
Greg Clayton85e62ec2013-01-30 22:57:34 +0000604 process = lldb.debugger.GetSelectedTarget().GetProcess()
605 if not process:
606 result.AppendMessage('error: invalid process')
607 return
608 frame = process.GetSelectedThread().GetSelectedFrame()
609 if not frame:
610 result.AppendMessage('error: invalid frame')
611 return
612
Greg Clayton7fb671b2012-04-11 18:30:53 +0000613 options.type = 'pointer'
Greg Clayton85e62ec2013-01-30 22:57:34 +0000614 if options.format == None:
615 options.format = "A" # 'A' is "address" format
616
Greg Clayton804de012012-04-11 16:27:06 +0000617 if args:
Greg Clayton85e62ec2013-01-30 22:57:34 +0000618 # When we initialize the expression, we must define any types that
619 # we will need when looking at every allocation. We must also define
620 # a type named callback_baton_t and make an instance named "baton"
621 # and initialize it how ever we want to. The address of "baton" will
622 # be passed into our range callback. callback_baton_t must contain
623 # a member named "callback" whose type is "range_callback_t". This
624 # will be used by our zone callbacks to call the range callback for
625 # each malloc range.
Greg Clayton4e1042e2015-05-27 22:32:39 +0000626 expr_prefix = '''
Greg Clayton85e62ec2013-01-30 22:57:34 +0000627struct $malloc_match {
628 void *addr;
629 uintptr_t size;
630 uintptr_t offset;
631 uintptr_t type;
632};
Greg Clayton4e1042e2015-05-27 22:32:39 +0000633'''
634 user_init_code_format = '''
635#define MAX_MATCHES %u
Greg Clayton85e62ec2013-01-30 22:57:34 +0000636typedef struct callback_baton_t {
637 range_callback_t callback;
638 unsigned num_matches;
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000639 $malloc_match matches[MAX_MATCHES];
Greg Clayton85e62ec2013-01-30 22:57:34 +0000640 void *ptr;
641} callback_baton_t;
642range_callback_t range_callback = [](task_t task, void *baton, unsigned type, uintptr_t ptr_addr, uintptr_t ptr_size) -> void {
643 callback_baton_t *info = (callback_baton_t *)baton;
644 typedef void* T;
645 const unsigned size = sizeof(T);
646 T *array = (T*)ptr_addr;
647 for (unsigned idx = 0; ((idx + 1) * sizeof(T)) <= ptr_size; ++idx) {
648 if (array[idx] == info->ptr) {
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000649 if (info->num_matches < MAX_MATCHES) {
Greg Clayton85e62ec2013-01-30 22:57:34 +0000650 info->matches[info->num_matches].addr = (void*)ptr_addr;
651 info->matches[info->num_matches].size = ptr_size;
652 info->matches[info->num_matches].offset = idx*sizeof(T);
653 info->matches[info->num_matches].type = type;
654 ++info->num_matches;
655 }
656 }
657 }
658};
659callback_baton_t baton = { range_callback, 0, {0}, (void *)%s };
660'''
661 # We must also define a snippet of code to be run that returns
662 # the result of the expression we run.
663 # Here we return NULL if our pointer was not found in any malloc blocks,
664 # and we return the address of the matches array so we can then access
665 # the matching results
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000666 user_return_code = '''if (baton.num_matches < MAX_MATCHES)
667 baton.matches[baton.num_matches].addr = 0; // Terminate the matches array
Greg Clayton85e62ec2013-01-30 22:57:34 +0000668baton.matches'''
669 # Iterate through all of our pointer expressions and display the results
670 for ptr_expr in args:
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000671 user_init_code = user_init_code_format % (options.max_matches, ptr_expr)
Greg Clayton13fbb992013-02-01 00:47:49 +0000672 expr = get_iterate_memory_expr(options, process, user_init_code, user_return_code)
Greg Clayton85e62ec2013-01-30 22:57:34 +0000673 arg_str_description = 'malloc block containing pointer %s' % ptr_expr
Greg Clayton4e1042e2015-05-27 22:32:39 +0000674 display_match_results (result, options, arg_str_description, expr, True, expr_prefix)
Greg Clayton804de012012-04-11 16:27:06 +0000675 else:
Greg Clayton85e62ec2013-01-30 22:57:34 +0000676 result.AppendMessage('error: no pointer arguments were given')
677
678def get_cstr_refs_options():
679 usage = "usage: %prog [options] <CSTR> [CSTR ...]"
680 description='''Searches all allocations on the heap for C string values on
681darwin user space programs. Any matches that were found will dump the malloc
682blocks that contain the C strings and might be able to print what kind of
683objects the pointers are contained in using dynamic type information in the
684program.'''
685 parser = optparse.OptionParser(description=description, prog='cstr_refs',usage=usage)
686 add_common_options(parser)
687 return parser
Greg Clayton804de012012-04-11 16:27:06 +0000688
Greg Clayton77677162012-04-12 18:57:36 +0000689def cstr_refs(debugger, command, result, dict):
Greg Clayton7fb671b2012-04-11 18:30:53 +0000690 command_args = shlex.split(command)
Greg Clayton85e62ec2013-01-30 22:57:34 +0000691 parser = get_cstr_refs_options();
Greg Clayton7fb671b2012-04-11 18:30:53 +0000692 try:
693 (options, args) = parser.parse_args(command_args)
694 except:
695 return
696
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000697 process = lldb.debugger.GetSelectedTarget().GetProcess()
698 if not process:
699 result.AppendMessage('error: invalid process')
700 return
701 frame = process.GetSelectedThread().GetSelectedFrame()
Greg Clayton85e62ec2013-01-30 22:57:34 +0000702 if not frame:
703 result.AppendMessage('error: invalid frame')
704 return
705
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000706
Greg Clayton7fb671b2012-04-11 18:30:53 +0000707 options.type = 'cstr'
Greg Clayton85e62ec2013-01-30 22:57:34 +0000708 if options.format == None:
709 options.format = "Y" # 'Y' is "bytes with ASCII" format
Greg Clayton7fb671b2012-04-11 18:30:53 +0000710
711 if args:
Greg Clayton85e62ec2013-01-30 22:57:34 +0000712 # When we initialize the expression, we must define any types that
713 # we will need when looking at every allocation. We must also define
714 # a type named callback_baton_t and make an instance named "baton"
715 # and initialize it how ever we want to. The address of "baton" will
716 # be passed into our range callback. callback_baton_t must contain
717 # a member named "callback" whose type is "range_callback_t". This
718 # will be used by our zone callbacks to call the range callback for
719 # each malloc range.
Greg Clayton4e1042e2015-05-27 22:32:39 +0000720 expr_prefix = '''
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000721struct $malloc_match {
Greg Clayton85e62ec2013-01-30 22:57:34 +0000722 void *addr;
723 uintptr_t size;
724 uintptr_t offset;
725 uintptr_t type;
726};
Greg Clayton4e1042e2015-05-27 22:32:39 +0000727'''
728 user_init_code_format = '''
729#define MAX_MATCHES %u
Greg Clayton85e62ec2013-01-30 22:57:34 +0000730typedef struct callback_baton_t {
731 range_callback_t callback;
732 unsigned num_matches;
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000733 $malloc_match matches[MAX_MATCHES];
Greg Clayton85e62ec2013-01-30 22:57:34 +0000734 const char *cstr;
735 unsigned cstr_len;
736} callback_baton_t;
737range_callback_t range_callback = [](task_t task, void *baton, unsigned type, uintptr_t ptr_addr, uintptr_t ptr_size) -> void {
738 callback_baton_t *info = (callback_baton_t *)baton;
739 if (info->cstr_len < ptr_size) {
740 const char *begin = (const char *)ptr_addr;
741 const char *end = begin + ptr_size - info->cstr_len;
742 for (const char *s = begin; s < end; ++s) {
743 if ((int)memcmp(s, info->cstr, info->cstr_len) == 0) {
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000744 if (info->num_matches < MAX_MATCHES) {
Greg Clayton85e62ec2013-01-30 22:57:34 +0000745 info->matches[info->num_matches].addr = (void*)ptr_addr;
746 info->matches[info->num_matches].size = ptr_size;
747 info->matches[info->num_matches].offset = s - begin;
748 info->matches[info->num_matches].type = type;
749 ++info->num_matches;
750 }
751 }
752 }
753 }
754};
755const char *cstr = "%s";
756callback_baton_t baton = { range_callback, 0, {0}, cstr, (unsigned)strlen(cstr) };'''
757 # We must also define a snippet of code to be run that returns
758 # the result of the expression we run.
759 # Here we return NULL if our pointer was not found in any malloc blocks,
760 # and we return the address of the matches array so we can then access
761 # the matching results
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000762 user_return_code = '''if (baton.num_matches < MAX_MATCHES)
763 baton.matches[baton.num_matches].addr = 0; // Terminate the matches array
764baton.matches'''
Greg Clayton85e62ec2013-01-30 22:57:34 +0000765 # Iterate through all of our pointer expressions and display the results
766 for cstr in args:
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000767 user_init_code = user_init_code_format % (options.max_matches, cstr)
Greg Clayton13fbb992013-02-01 00:47:49 +0000768 expr = get_iterate_memory_expr(options, process, user_init_code, user_return_code)
Greg Clayton85e62ec2013-01-30 22:57:34 +0000769 arg_str_description = 'malloc block containing "%s"' % cstr
Greg Clayton4e1042e2015-05-27 22:32:39 +0000770 display_match_results (result, options, arg_str_description, expr, True, expr_prefix)
Greg Clayton7fb671b2012-04-11 18:30:53 +0000771 else:
Greg Clayton85e62ec2013-01-30 22:57:34 +0000772 result.AppendMessage('error: command takes one or more C string arguments')
773
774
775def get_malloc_info_options():
776 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
777 description='''Searches the heap a malloc block that contains the addresses
778specified as one or more address expressions. Any matches that were found will
779dump the malloc blocks that match or contain the specified address. The matching
780blocks might be able to show what kind of objects they are using dynamic type
781information in the program.'''
782 parser = optparse.OptionParser(description=description, prog='malloc_info',usage=usage)
783 add_common_options(parser)
784 return parser
Greg Clayton804de012012-04-11 16:27:06 +0000785
Greg Clayton77677162012-04-12 18:57:36 +0000786def malloc_info(debugger, command, result, dict):
787 command_args = shlex.split(command)
Greg Clayton85e62ec2013-01-30 22:57:34 +0000788 parser = get_malloc_info_options()
Greg Clayton77677162012-04-12 18:57:36 +0000789 try:
790 (options, args) = parser.parse_args(command_args)
791 except:
792 return
Greg Clayton13fbb992013-02-01 00:47:49 +0000793 malloc_info_impl (debugger, result, options, args)
794
795def malloc_info_impl (debugger, result, options, args):
796 # We are specifically looking for something on the heap only
797 options.type = 'malloc_info'
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000798
799 process = lldb.debugger.GetSelectedTarget().GetProcess()
800 if not process:
801 result.AppendMessage('error: invalid process')
802 return
803 frame = process.GetSelectedThread().GetSelectedFrame()
804 if not frame:
805 result.AppendMessage('error: invalid frame')
806 return
Greg Clayton4e1042e2015-05-27 22:32:39 +0000807 expr_prefix = '''
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000808struct $malloc_match {
Greg Clayton85e62ec2013-01-30 22:57:34 +0000809 void *addr;
810 uintptr_t size;
811 uintptr_t offset;
812 uintptr_t type;
813};
Greg Clayton4e1042e2015-05-27 22:32:39 +0000814'''
815
816 user_init_code_format = '''
Greg Clayton85e62ec2013-01-30 22:57:34 +0000817typedef struct callback_baton_t {
818 range_callback_t callback;
819 unsigned num_matches;
820 $malloc_match matches[2]; // Two items so they can be NULL terminated
821 void *ptr;
822} callback_baton_t;
823range_callback_t range_callback = [](task_t task, void *baton, unsigned type, uintptr_t ptr_addr, uintptr_t ptr_size) -> void {
824 callback_baton_t *info = (callback_baton_t *)baton;
825 if (info->num_matches == 0) {
826 uint8_t *p = (uint8_t *)info->ptr;
827 uint8_t *lo = (uint8_t *)ptr_addr;
828 uint8_t *hi = lo + ptr_size;
829 if (lo <= p && p < hi) {
830 info->matches[info->num_matches].addr = (void*)ptr_addr;
831 info->matches[info->num_matches].size = ptr_size;
832 info->matches[info->num_matches].offset = p - lo;
833 info->matches[info->num_matches].type = type;
834 info->num_matches = 1;
835 }
836 }
837};
838callback_baton_t baton = { range_callback, 0, {0}, (void *)%s };
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000839baton.matches[0].addr = 0;
Greg Clayton85e62ec2013-01-30 22:57:34 +0000840baton.matches[1].addr = 0;'''
Greg Clayton77677162012-04-12 18:57:36 +0000841 if args:
Greg Clayton13fbb992013-02-01 00:47:49 +0000842 total_matches = 0
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000843 for ptr_expr in args:
844 user_init_code = user_init_code_format % (ptr_expr)
Greg Clayton13fbb992013-02-01 00:47:49 +0000845 expr = get_iterate_memory_expr(options, process, user_init_code, 'baton.matches')
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000846 arg_str_description = 'malloc block that contains %s' % ptr_expr
Greg Clayton4e1042e2015-05-27 22:32:39 +0000847 total_matches += display_match_results (result, options, arg_str_description, expr, True, expr_prefix)
Greg Clayton13fbb992013-02-01 00:47:49 +0000848 return total_matches
Greg Clayton77677162012-04-12 18:57:36 +0000849 else:
Greg Clayton85e62ec2013-01-30 22:57:34 +0000850 result.AppendMessage('error: command takes one or more pointer expressions')
Greg Clayton13fbb992013-02-01 00:47:49 +0000851 return 0
Greg Clayton77677162012-04-12 18:57:36 +0000852
Greg Clayton85e62ec2013-01-30 22:57:34 +0000853def get_thread_stack_ranges_struct (process):
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000854 '''Create code that defines a structure that represents threads stack bounds
855 for all threads. It returns a static sized array initialized with all of
856 the tid, base, size structs for all the threads.'''
Greg Clayton85e62ec2013-01-30 22:57:34 +0000857 stack_dicts = list()
858 if process:
859 i = 0;
860 for thread in process:
861 min_sp = thread.frame[0].sp
862 max_sp = min_sp
863 for frame in thread.frames:
864 sp = frame.sp
865 if sp < min_sp: min_sp = sp
866 if sp > max_sp: max_sp = sp
867 if min_sp < max_sp:
868 stack_dicts.append ({ 'tid' : thread.GetThreadID(), 'base' : min_sp , 'size' : max_sp-min_sp, 'index' : i })
869 i += 1
870 stack_dicts_len = len(stack_dicts)
871 if stack_dicts_len > 0:
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000872 result = '''
873#define NUM_STACKS %u
Greg Clayton13fbb992013-02-01 00:47:49 +0000874#define STACK_RED_ZONE_SIZE %u
Greg Clayton85e62ec2013-01-30 22:57:34 +0000875typedef struct thread_stack_t { uint64_t tid, base, size; } thread_stack_t;
Greg Clayton13fbb992013-02-01 00:47:49 +0000876thread_stack_t stacks[NUM_STACKS];''' % (stack_dicts_len, process.target.GetStackRedZoneSize())
Greg Clayton85e62ec2013-01-30 22:57:34 +0000877 for stack_dict in stack_dicts:
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000878 result += '''
879stacks[%(index)u].tid = 0x%(tid)x;
Greg Clayton85e62ec2013-01-30 22:57:34 +0000880stacks[%(index)u].base = 0x%(base)x;
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000881stacks[%(index)u].size = 0x%(size)x;''' % stack_dict
Greg Clayton85e62ec2013-01-30 22:57:34 +0000882 return result
883 else:
Greg Clayton966c6f62014-01-07 21:55:00 +0000884 return ''
Greg Claytonae23ed32012-10-08 22:39:38 +0000885
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000886def get_sections_ranges_struct (process):
887 '''Create code that defines a structure that represents all segments that
888 can contain data for all images in "target". It returns a static sized
889 array initialized with all of base, size structs for all the threads.'''
890 target = process.target
891 segment_dicts = list()
892 for (module_idx, module) in enumerate(target.modules):
893 for sect_idx in range(module.GetNumSections()):
894 section = module.GetSectionAtIndex(sect_idx)
895 if not section:
896 break
897 name = section.name
898 if name != '__TEXT' and name != '__LINKEDIT' and name != '__PAGEZERO':
899 base = section.GetLoadAddress(target)
900 size = section.GetByteSize()
901 if base != lldb.LLDB_INVALID_ADDRESS and size > 0:
902 segment_dicts.append ({ 'base' : base, 'size' : size })
903 segment_dicts_len = len(segment_dicts)
904 if segment_dicts_len > 0:
905 result = '''
906#define NUM_SEGMENTS %u
907typedef struct segment_range_t { uint64_t base; uint32_t size; } segment_range_t;
908segment_range_t segments[NUM_SEGMENTS];''' % (segment_dicts_len,)
909 for (idx, segment_dict) in enumerate(segment_dicts):
910 segment_dict['index'] = idx
911 result += '''
912segments[%(index)u].base = 0x%(base)x;
913segments[%(index)u].size = 0x%(size)x;''' % segment_dict
914 return result
Greg Claytonae23ed32012-10-08 22:39:38 +0000915 else:
Greg Clayton966c6f62014-01-07 21:55:00 +0000916 return ''
Greg Claytonae23ed32012-10-08 22:39:38 +0000917
Greg Claytone04cfd22012-07-11 22:13:18 +0000918def section_ptr_refs(debugger, command, result, dict):
919 command_args = shlex.split(command)
920 usage = "usage: %prog [options] <EXPR> [EXPR ...]"
921 description='''Searches section contents for pointer values in darwin user space programs.'''
922 parser = optparse.OptionParser(description=description, prog='section_ptr_refs',usage=usage)
923 add_common_options(parser)
924 parser.add_option('--section', action='append', type='string', dest='section_names', help='section name to search', default=list())
925 try:
926 (options, args) = parser.parse_args(command_args)
927 except:
928 return
929
930 options.type = 'pointer'
Greg Claytonae23ed32012-10-08 22:39:38 +0000931
Greg Claytone04cfd22012-07-11 22:13:18 +0000932 sections = list()
933 section_modules = list()
934 if not options.section_names:
Greg Claytonc373ca52012-09-01 00:34:35 +0000935 result.AppendMessage('error: at least one section must be specified with the --section option')
Greg Claytone04cfd22012-07-11 22:13:18 +0000936 return
937
Greg Clayton85e62ec2013-01-30 22:57:34 +0000938 target = lldb.debugger.GetSelectedTarget()
939 for module in target.modules:
Greg Claytone04cfd22012-07-11 22:13:18 +0000940 for section_name in options.section_names:
941 section = module.section[section_name]
942 if section:
943 sections.append (section)
944 section_modules.append (module)
945 if sections:
946 dylid_load_err = load_dylib()
947 if dylid_load_err:
Greg Claytonc373ca52012-09-01 00:34:35 +0000948 result.AppendMessage(dylid_load_err)
Greg Claytone04cfd22012-07-11 22:13:18 +0000949 return
Greg Clayton85e62ec2013-01-30 22:57:34 +0000950 frame = target.GetProcess().GetSelectedThread().GetSelectedFrame()
Greg Claytone04cfd22012-07-11 22:13:18 +0000951 for expr_str in args:
952 for (idx, section) in enumerate(sections):
953 expr = 'find_pointer_in_memory(0x%xllu, %ullu, (void *)%s)' % (section.addr.load_addr, section.size, expr_str)
954 arg_str_description = 'section %s.%s containing "%s"' % (section_modules[idx].file.fullpath, section.name, expr_str)
Greg Clayton85e62ec2013-01-30 22:57:34 +0000955 num_matches = display_match_results (result, options, arg_str_description, expr, False)
Greg Claytone04cfd22012-07-11 22:13:18 +0000956 if num_matches:
957 if num_matches < options.max_matches:
958 options.max_matches = options.max_matches - num_matches
959 else:
960 options.max_matches = 0
961 if options.max_matches == 0:
962 return
963 else:
Greg Claytonc373ca52012-09-01 00:34:35 +0000964 result.AppendMessage('error: no sections were found that match any of %s' % (', '.join(options.section_names)))
Greg Claytone04cfd22012-07-11 22:13:18 +0000965
Greg Clayton85e62ec2013-01-30 22:57:34 +0000966def get_objc_refs_options():
967 usage = "usage: %prog [options] <CLASS> [CLASS ...]"
968 description='''Searches all allocations on the heap for instances of
969objective C classes, or any classes that inherit from the specified classes
970in darwin user space programs. Any matches that were found will dump the malloc
971blocks that contain the C strings and might be able to print what kind of
972objects the pointers are contained in using dynamic type information in the
973program.'''
974 parser = optparse.OptionParser(description=description, prog='objc_refs',usage=usage)
975 add_common_options(parser)
976 return parser
977
Greg Clayton774ebdf2012-08-11 02:26:26 +0000978def objc_refs(debugger, command, result, dict):
979 command_args = shlex.split(command)
Greg Clayton85e62ec2013-01-30 22:57:34 +0000980 parser = get_objc_refs_options()
Greg Clayton774ebdf2012-08-11 02:26:26 +0000981 try:
982 (options, args) = parser.parse_args(command_args)
983 except:
984 return
985
Greg Claytone7fc9cc2013-01-31 06:38:09 +0000986 process = lldb.debugger.GetSelectedTarget().GetProcess()
987 if not process:
988 result.AppendMessage('error: invalid process')
989 return
990 frame = process.GetSelectedThread().GetSelectedFrame()
Greg Clayton85e62ec2013-01-30 22:57:34 +0000991 if not frame:
992 result.AppendMessage('error: invalid frame')
993 return
994
995 options.type = 'isa'
996 if options.format == None:
997 options.format = "A" # 'A' is "address" format
998
Greg Clayton927fa012013-04-03 07:25:30 +0000999 expr_options = lldb.SBExpressionOptions()
1000 expr_options.SetIgnoreBreakpoints(True);
1001 expr_options.SetTimeoutInMicroSeconds (3*1000*1000) # 3 second infinite timeout
1002 expr_options.SetTryAllThreads (True)
Greg Clayton6e7ab022015-01-14 21:37:19 +00001003 expr_options.SetLanguage(lldb.eLanguageTypeObjC_plus_plus)
Greg Clayton927fa012013-04-03 07:25:30 +00001004 num_objc_classes_value = frame.EvaluateExpression("(int)objc_getClassList((void *)0, (int)0)", expr_options)
Greg Clayton85e62ec2013-01-30 22:57:34 +00001005 if not num_objc_classes_value.error.Success():
1006 result.AppendMessage('error: %s' % num_objc_classes_value.error.GetCString())
1007 return
1008
1009 num_objc_classes = num_objc_classes_value.GetValueAsUnsigned()
1010 if num_objc_classes == 0:
1011 result.AppendMessage('error: no objective C classes in program')
1012 return
1013
1014 if args:
1015 # When we initialize the expression, we must define any types that
1016 # we will need when looking at every allocation. We must also define
1017 # a type named callback_baton_t and make an instance named "baton"
1018 # and initialize it how ever we want to. The address of "baton" will
1019 # be passed into our range callback. callback_baton_t must contain
1020 # a member named "callback" whose type is "range_callback_t". This
1021 # will be used by our zone callbacks to call the range callback for
1022 # each malloc range.
Greg Clayton4e1042e2015-05-27 22:32:39 +00001023 expr_prefix = '''
Greg Claytone7fc9cc2013-01-31 06:38:09 +00001024struct $malloc_match {
Greg Clayton85e62ec2013-01-30 22:57:34 +00001025 void *addr;
1026 uintptr_t size;
1027 uintptr_t offset;
1028 uintptr_t type;
1029};
Greg Clayton4e1042e2015-05-27 22:32:39 +00001030'''
1031
1032 user_init_code_format = '''
1033#define MAX_MATCHES %u
Greg Clayton85e62ec2013-01-30 22:57:34 +00001034typedef int (*compare_callback_t)(const void *a, const void *b);
1035typedef struct callback_baton_t {
1036 range_callback_t callback;
1037 compare_callback_t compare_callback;
1038 unsigned num_matches;
Greg Claytone7fc9cc2013-01-31 06:38:09 +00001039 $malloc_match matches[MAX_MATCHES];
Greg Clayton85e62ec2013-01-30 22:57:34 +00001040 void *isa;
1041 Class classes[%u];
1042} callback_baton_t;
1043compare_callback_t compare_callback = [](const void *a, const void *b) -> int {
1044 Class a_ptr = *(Class *)a;
1045 Class b_ptr = *(Class *)b;
1046 if (a_ptr < b_ptr) return -1;
1047 if (a_ptr > b_ptr) return +1;
1048 return 0;
1049};
Sean Callananf09a3db2013-08-13 00:53:33 +00001050typedef Class (*class_getSuperclass_type)(void *isa);
Greg Clayton85e62ec2013-01-30 22:57:34 +00001051range_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 +00001052 class_getSuperclass_type class_getSuperclass_impl = (class_getSuperclass_type)class_getSuperclass;
Greg Clayton85e62ec2013-01-30 22:57:34 +00001053 callback_baton_t *info = (callback_baton_t *)baton;
1054 if (sizeof(Class) <= ptr_size) {
1055 Class *curr_class_ptr = (Class *)ptr_addr;
1056 Class *matching_class_ptr = (Class *)bsearch (curr_class_ptr,
1057 (const void *)info->classes,
1058 sizeof(info->classes)/sizeof(Class),
1059 sizeof(Class),
1060 info->compare_callback);
1061 if (matching_class_ptr) {
1062 bool match = false;
1063 if (info->isa) {
1064 Class isa = *curr_class_ptr;
1065 if (info->isa == isa)
1066 match = true;
1067 else { // if (info->objc.match_superclasses) {
Sean Callananf09a3db2013-08-13 00:53:33 +00001068 Class super = class_getSuperclass_impl(isa);
Greg Clayton85e62ec2013-01-30 22:57:34 +00001069 while (super) {
1070 if (super == info->isa) {
1071 match = true;
1072 break;
1073 }
Sean Callananf09a3db2013-08-13 00:53:33 +00001074 super = class_getSuperclass_impl(super);
Greg Clayton85e62ec2013-01-30 22:57:34 +00001075 }
1076 }
1077 }
1078 else
1079 match = true;
1080 if (match) {
Greg Claytone7fc9cc2013-01-31 06:38:09 +00001081 if (info->num_matches < MAX_MATCHES) {
Greg Clayton85e62ec2013-01-30 22:57:34 +00001082 info->matches[info->num_matches].addr = (void*)ptr_addr;
1083 info->matches[info->num_matches].size = ptr_size;
1084 info->matches[info->num_matches].offset = 0;
1085 info->matches[info->num_matches].type = type;
1086 ++info->num_matches;
1087 }
1088 }
1089 }
1090 }
1091};
1092callback_baton_t baton = { range_callback, compare_callback, 0, {0}, (void *)0x%x, {0} };
1093int nc = (int)objc_getClassList(baton.classes, sizeof(baton.classes)/sizeof(Class));
1094(void)qsort (baton.classes, sizeof(baton.classes)/sizeof(Class), sizeof(Class), compare_callback);'''
1095 # We must also define a snippet of code to be run that returns
1096 # the result of the expression we run.
1097 # Here we return NULL if our pointer was not found in any malloc blocks,
1098 # and we return the address of the matches array so we can then access
1099 # the matching results
Greg Claytone7fc9cc2013-01-31 06:38:09 +00001100 user_return_code = '''if (baton.num_matches < MAX_MATCHES)
1101 baton.matches[baton.num_matches].addr = 0; // Terminate the matches array
1102 baton.matches'''
Greg Clayton85e62ec2013-01-30 22:57:34 +00001103 # Iterate through all of our ObjC class name arguments
1104 for class_name in args:
1105 addr_expr_str = "(void *)[%s class]" % class_name
Greg Clayton927fa012013-04-03 07:25:30 +00001106 expr_options = lldb.SBExpressionOptions()
1107 expr_options.SetIgnoreBreakpoints(True);
1108 expr_options.SetTimeoutInMicroSeconds (1*1000*1000) # 1 second timeout
1109 expr_options.SetTryAllThreads (True)
Greg Clayton6e7ab022015-01-14 21:37:19 +00001110 expr_options.SetLanguage(lldb.eLanguageTypeObjC_plus_plus)
Greg Clayton927fa012013-04-03 07:25:30 +00001111 expr_sbvalue = frame.EvaluateExpression (addr_expr_str, expr_options)
Greg Clayton85e62ec2013-01-30 22:57:34 +00001112 if expr_sbvalue.error.Success():
1113 isa = expr_sbvalue.unsigned
1114 if isa:
1115 options.type = 'isa'
Greg Claytone7fc9cc2013-01-31 06:38:09 +00001116 result.AppendMessage('Searching for all instances of classes or subclasses of "%s" (isa=0x%x)' % (class_name, isa))
1117 user_init_code = user_init_code_format % (options.max_matches, num_objc_classes, isa)
Greg Clayton13fbb992013-02-01 00:47:49 +00001118 expr = get_iterate_memory_expr(options, process, user_init_code, user_return_code)
Greg Clayton85e62ec2013-01-30 22:57:34 +00001119 arg_str_description = 'objective C classes with isa 0x%x' % isa
Greg Clayton4e1042e2015-05-27 22:32:39 +00001120 display_match_results (result, options, arg_str_description, expr, True, expr_prefix)
Greg Clayton774ebdf2012-08-11 02:26:26 +00001121 else:
Greg Clayton85e62ec2013-01-30 22:57:34 +00001122 result.AppendMessage('error: Can\'t find isa for an ObjC class named "%s"' % (class_name))
1123 else:
1124 result.AppendMessage('error: expression error for "%s": %s' % (addr_expr_str, expr_sbvalue.error))
1125 else:
1126 result.AppendMessage('error: command takes one or more C string arguments');
Greg Clayton774ebdf2012-08-11 02:26:26 +00001127
Greg Claytond712ef02012-04-25 18:40:20 +00001128if __name__ == '__main__':
1129 lldb.debugger = lldb.SBDebugger.Create()
1130
Greg Clayton85e62ec2013-01-30 22:57:34 +00001131# Make the options so we can generate the help text for the new LLDB
1132# command line command prior to registering it with LLDB below. This way
1133# if clients in LLDB type "help malloc_info", they will see the exact same
1134# output as typing "malloc_info --help".
1135ptr_refs.__doc__ = get_ptr_refs_options().format_help()
1136cstr_refs.__doc__ = get_cstr_refs_options().format_help()
1137malloc_info.__doc__ = get_malloc_info_options().format_help()
1138objc_refs.__doc__ = get_objc_refs_options().format_help()
Enrico Granatacd4218f2013-02-22 02:21:10 +00001139lldb.debugger.HandleCommand('command script add -f %s.ptr_refs ptr_refs' % __name__)
1140lldb.debugger.HandleCommand('command script add -f %s.cstr_refs cstr_refs' % __name__)
1141lldb.debugger.HandleCommand('command script add -f %s.malloc_info malloc_info' % __name__)
Greg Clayton85e62ec2013-01-30 22:57:34 +00001142# lldb.debugger.HandleCommand('command script add -f %s.heap heap' % package_name)
1143# lldb.debugger.HandleCommand('command script add -f %s.section_ptr_refs section_ptr_refs' % package_name)
1144# lldb.debugger.HandleCommand('command script add -f %s.stack_ptr_refs stack_ptr_refs' % package_name)
Enrico Granatacd4218f2013-02-22 02:21:10 +00001145lldb.debugger.HandleCommand('command script add -f %s.objc_refs objc_refs' % __name__)
Greg Clayton85e62ec2013-01-30 22:57:34 +00001146print '"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 +00001147
1148
1149
1150