]> git.saurik.com Git - apple/xnu.git/blame - tools/lldbmacros/userspace.py
xnu-7195.101.1.tar.gz
[apple/xnu.git] / tools / lldbmacros / userspace.py
CommitLineData
39236c6e
A
1from xnu import *
2from utils import *
3from process import *
4from pmap import *
fe8ab488 5import struct
39236c6e
A
6
7def GetBinaryNameForPC(pc_val, user_lib_info = None):
8 """ find the binary in user_lib_info that the passed pc_val falls in range of.
9 params:
fe8ab488 10 pc_val : int - integer form of the pc address
39236c6e
A
11 user_lib_info: [] of [] which hold start, end, binary name
12 returns:
13 str - Name of binary or "unknown" if not found.
14 """
15 retval = "unknown"
16 if not user_lib_info:
17 return retval
18 matches = []
19 for info in user_lib_info:
20 if pc_val >= info[0] and pc_val <= info[1]:
21 matches.append((pc_val - info[0], info[2]))
22 matches.sort()
23 if matches:
24 retval = matches[0][1]
25 return retval
26
27def ShowX86UserStack(thread, user_lib_info = None):
28 """ Display user space stack frame and pc addresses.
29 params:
30 thread: obj referencing thread value
31 returns:
32 Nothing
33 """
34 iss = Cast(thread.machine.iss, 'x86_saved_state_t *')
35 abi = int(iss.flavor)
36 user_ip = 0
37 user_frame = 0
38 user_abi_ret_offset = 0
39 if abi == 0xf:
40 debuglog("User process is 64 bit")
41 user_ip = iss.uss.ss_64.isf.rip
42 user_frame = iss.uss.ss_64.rbp
43 user_abi_ret_offset = 8
fe8ab488 44 user_abi_type = "uint64_t"
39236c6e
A
45 else:
46 debuglog("user process is 32 bit")
47 user_ip = iss.uss.ss_32.eip
48 user_frame = iss.uss.ss_32.ebp
49 user_abi_ret_offset = 4
fe8ab488
A
50 user_abi_type = "uint32_t"
51
39236c6e
A
52 if user_ip == 0:
53 print "This activation does not appear to have a valid user context."
54 return False
55
56 cur_ip = user_ip
57 cur_frame = user_frame
58 debuglog("ip= 0x%x , fr = 0x%x " % (cur_ip, cur_frame))
39236c6e
A
59
60 frameformat = "{0:d} FP: 0x{1:x} PC: 0x{2:x}"
61 if user_lib_info is not None:
62 frameformat = "{0:d} {3: <30s} 0x{2:x}"
63 print frameformat.format(0, cur_frame, cur_ip, GetBinaryNameForPC(cur_ip, user_lib_info))
64
65 print kern.Symbolicate(cur_ip)
fe8ab488
A
66
67 frameno = 0
68 while True:
69 frameno = frameno + 1
70 frame = GetUserDataAsString(thread.task, unsigned(cur_frame), user_abi_ret_offset*2)
71 cur_ip = _ExtractDataFromString(frame, user_abi_ret_offset, user_abi_type)
72 cur_frame = _ExtractDataFromString(frame, 0, user_abi_type)
73 if not cur_frame or cur_frame == 0x0000000800000008:
74 break
75 print frameformat.format(frameno, cur_frame, cur_ip, GetBinaryNameForPC(cur_ip, user_lib_info))
76 print kern.Symbolicate(cur_ip)
39236c6e
A
77 return
78
79def _PrintARMUserStack(task, cur_pc, cur_fp, framesize, frametype, frameformat, user_lib_info=None):
cb323159 80 cur_pc = kern.StripUserPAC(cur_pc)
39236c6e
A
81 if cur_pc == 0:
82 "No valid user context for this activation."
83 return
84 frameno = 0
85 print frameformat.format(frameno, cur_fp, cur_pc, GetBinaryNameForPC(cur_pc, user_lib_info))
86 while True:
87 frameno = frameno + 1
88 frame = GetUserDataAsString(task, cur_fp, framesize)
89 cur_fp = _ExtractDataFromString(frame, 0, frametype)
90 cur_pc = _ExtractDataFromString(frame, (framesize / 2), frametype)
cb323159 91 cur_pc = kern.StripUserPAC(cur_pc)
39236c6e
A
92 if not cur_fp:
93 break
94 print frameformat.format(frameno, cur_fp, cur_pc, GetBinaryNameForPC(cur_pc, user_lib_info))
95
96def ShowARMUserStack(thread, user_lib_info = None):
97 cur_pc = unsigned(thread.machine.PcbData.pc)
98 cur_fp = unsigned(thread.machine.PcbData.r[7])
99 frameformat = "{0:>2d} FP: 0x{1:x} PC: 0x{2:x}"
100 if user_lib_info is not None:
101 frameformat = "{0:>2d} {3: <30s} 0x{2:0>8x}"
102 framesize = 8
103 frametype = "uint32_t"
104 _PrintARMUserStack(thread.task, cur_pc, cur_fp, framesize, frametype, frameformat, user_lib_info=user_lib_info)
105
fe8ab488
A
106def ShowARM64UserStack(thread, user_lib_info = None):
107 SAVED_STATE_FLAVOR_ARM=20
108 SAVED_STATE_FLAVOR_ARM64=21
f427ee49
A
109 upcb_addr = kern.StripKernelPAC(thread.machine.upcb)
110 upcb = kern.GetValueFromAddress(upcb_addr, 'arm_saved_state_t *')
fe8ab488
A
111 flavor = upcb.ash.flavor
112 frameformat = "{0:>2d} FP: 0x{1:x} PC: 0x{2:x}"
113 if flavor == SAVED_STATE_FLAVOR_ARM64:
114 cur_pc = unsigned(upcb.uss.ss_64.pc)
115 cur_fp = unsigned(upcb.uss.ss_64.fp)
116 if user_lib_info is not None:
117 frameformat = "{0:>2d} {3: <30s} 0x{2:x}"
118 framesize = 16
119 frametype = "uint64_t"
120 elif flavor == SAVED_STATE_FLAVOR_ARM:
121 cur_pc = unsigned(upcb.uss.ss_32.pc)
122 cur_fp = unsigned(upcb.uss.ss_32.r[7])
123 if user_lib_info is not None:
124 frameformat = "{0:>2d}: {3: <30s} 0x{2:x}"
125 framesize = 8
126 frametype = "uint32_t"
127 else:
128 raise RuntimeError("Thread {0} has an invalid flavor {1}".format(unsigned(thread), flavor))
129
130 _PrintARMUserStack(thread.task, cur_pc, cur_fp, framesize, frametype, frameformat, user_lib_info=user_lib_info)
131
39236c6e
A
132
133@lldb_command('showthreaduserstack')
134def ShowThreadUserStack(cmd_args=None):
135 """ Show user stack for a given thread.
136 Syntax: (lldb) showthreaduserstack <thread_ptr>
137 """
138 if not cmd_args:
139 raise ArgumentError("Insufficient arguments")
140
141 thread = kern.GetValueFromAddress(ArgumentStringToInt(cmd_args[0]), 'thread *')
142 if kern.arch == "x86_64":
143 ShowX86UserStack(thread)
144 elif kern.arch == "arm":
145 ShowARMUserStack(thread)
5ba3f43e 146 elif kern.arch.startswith("arm64"):
fe8ab488
A
147 ShowARM64UserStack(thread)
148 return True
149
3e170ce0 150@lldb_command('printuserdata','XO:')
fe8ab488
A
151def PrintUserspaceData(cmd_args=None, cmd_options={}):
152 """ Read userspace data for given task and print based on format provided.
153 Syntax: (lldb) printuserdata <task_t> <uspace_address> <format_specifier>
154 params:
155 <task_t> : pointer to task
156 <uspace_address> : address to user space memory
157 <format_specifier> : String representation for processing the data and printing it.
3e170ce0
A
158 e.g Q -> unsigned long long, q -> long long, I -> unsigned int, i -> int
159 10i -> 10 ints, 20s -> 20 character string, s -> null terminated string
160 See: https://docs.python.org/2/library/struct.html#format-characters
fe8ab488
A
161 options:
162 -X : print all values in hex.
3e170ce0 163 -O <file path>: Save data to file
fe8ab488
A
164 """
165
166 if not cmd_args or len(cmd_args) < 3:
167 raise ArgumentError("Insufficient arguments")
168 task = kern.GetValueFromAddress(cmd_args[0], 'task *')
169 uspace_addr = ArgumentStringToInt(cmd_args[1])
170 format_specifier_str = cmd_args[2]
171 user_data_len = 0
3e170ce0
A
172 if format_specifier_str == "s":
173 print "0x%x: " % uspace_addr + GetUserspaceString(task, uspace_addr)
174 return True
175
fe8ab488
A
176 try:
177 user_data_len = struct.calcsize(format_specifier_str)
178 except Exception, e:
179 raise ArgumentError("Invalid format specifier provided.")
180
181 user_data_string = GetUserDataAsString(task, uspace_addr, user_data_len)
182 if not user_data_string:
183 print "Could not read any data from userspace address."
184 return False
3e170ce0
A
185 if "-O" in cmd_options:
186 fh = open(cmd_options["-O"],"w")
187 fh.write(user_data_string)
188 fh.close()
189 print "Written %d bytes to %s." % (user_data_len, cmd_options['-O'])
190 return True
fe8ab488 191 upacked_data = struct.unpack(format_specifier_str, user_data_string)
3e170ce0 192 element_size = user_data_len / len(upacked_data)
fe8ab488
A
193 for i in range(len(upacked_data)):
194 if "-X" in cmd_options:
3e170ce0 195 print "0x%x: " % (uspace_addr + i*element_size) + hex(upacked_data[i])
fe8ab488 196 else:
3e170ce0 197 print "0x%x: " % (uspace_addr + i*element_size) + str(upacked_data[i])
fe8ab488 198
39236c6e
A
199 return True
200
3e170ce0
A
201@lldb_command('showtaskuserargs')
202def ShowTaskUserArgs(cmd_args=None, cmd_options={}):
203 """ Read the process argv, env, and apple strings from the user stack
204 Syntax: (lldb) showtaskuserargs <task_t>
205 params:
206 <task_t> : pointer to task
207 """
208 if not cmd_args or len(cmd_args) != 1:
209 raise ArgumentError("Insufficient arguments")
210
211 task = kern.GetValueFromAddress(cmd_args[0], 'task *')
212 proc = Cast(task.bsd_info, 'proc *')
d9a64523 213 ptrsize = 8 if int(task.t_flags) & 0x1 else 4
3e170ce0 214
d9a64523 215 format_string = "Q" if ptrsize == 8 else "I"
3e170ce0
A
216
217 string_area_size = proc.p_argslen
218 string_area_addr = proc.user_stack - string_area_size
219
220 string_area = GetUserDataAsString(task, string_area_addr, string_area_size)
221 if not string_area:
222 print "Could not read any data from userspace address."
223 return False
224
225 i = 0
d9a64523 226 pos = string_area_addr - ptrsize
3e170ce0
A
227
228 for name in ["apple", "env", "argv"] :
229 while True:
230 if name == "argv" :
231 if i == proc.p_argc:
232 break
233 i += 1
234
d9a64523 235 pos -= ptrsize
3e170ce0 236
d9a64523 237 user_data_string = GetUserDataAsString(task, pos, ptrsize)
3e170ce0
A
238 ptr = struct.unpack(format_string, user_data_string)[0]
239
240 if ptr == 0:
241 break
242
243 if string_area_addr <= ptr and ptr < string_area_addr+string_area_size :
244 string_offset = ptr - string_area_addr
245 string = string_area[string_offset:];
246 else:
247 string = GetUserspaceString(task, ptr)
248
249 print name + "[]: " + string
250
251 return True
252
d190cdc3 253def ShowTaskUserStacks(task):
39236c6e
A
254 #print GetTaskSummary.header + " " + GetProcSummary.header
255 pval = Cast(task.bsd_info, 'proc *')
256 #print GetTaskSummary(task) + " " + GetProcSummary(pval) + "\n \n"
257 crash_report_format_string = """\
d190cdc3 258Process: {pname:s} [{pid:d}]
39236c6e 259Path: {path: <50s}
fe8ab488 260Identifier: {pname: <30s}
39236c6e
A
261Version: ??? (???)
262Code Type: {parch: <20s}
d190cdc3 263Parent Process: {ppname:s} [{ppid:d}]
39236c6e
A
264
265Date/Time: {timest:s}.000 -0800
266OS Version: {osversion: <20s}
267Report Version: 8
268
269Exception Type: n/a
270Exception Codes: n/a
271Crashed Thread: 0
272
273Application Specific Information:
274Synthetic crash log generated from Kernel userstacks
275
276"""
277 user_lib_rex = re.compile("([0-9a-fx]+)\s-\s([0-9a-fx]+)\s+(.*?)\s", re.IGNORECASE|re.MULTILINE)
278 from datetime import datetime
5ba3f43e
A
279 if pval:
280 ts = datetime.fromtimestamp(int(pval.p_start.tv_sec))
281 date_string = ts.strftime('%Y-%m-%d %H:%M:%S')
282 else:
283 date_string = "none"
284 is_64 = True
285 if pval and (pval.p_flag & 0x4) == 0 :
286 is_64 = False
fe8ab488 287
39236c6e
A
288 parch_s = ""
289 if kern.arch == "x86_64" or kern.arch == "i386":
290 osversion = "Mac OS X 10.8"
291 parch_s = "I386 (32 bit)"
292 if is_64:
293 parch_s = "X86-64 (Native)"
294 else:
295 parch_s = kern.arch
296 osversion = "iOS"
297 osversion += " ({:s})".format(kern.globals.osversion)
5ba3f43e
A
298 if pval:
299 pid = pval.p_pid
f427ee49
A
300 pname = GetProcName(pval)
301 path = GetProcName(pval)
5ba3f43e
A
302 ppid = pval.p_ppid
303 else:
304 pid = 0
305 pname = "unknown"
306 path = "unknown"
307 ppid = 0
308
309 print crash_report_format_string.format(pid = pid,
310 pname = pname,
311 path = path,
312 ppid = ppid,
313 ppname = GetProcNameForPid(ppid),
39236c6e
A
314 timest = date_string,
315 parch = parch_s,
316 osversion = osversion
39236c6e
A
317 )
318 print "Binary Images:"
319 ShowTaskUserLibraries([hex(task)])
320 usertask_lib_info = [] # will host [startaddr, endaddr, lib_name] entries
321 for entry in ShowTaskUserLibraries.found_images:
322 #print "processing line %s" % line
323 arr = user_lib_rex.findall(entry[3])
324 #print "%r" % arr
325 if len(arr) == 0 :
326 continue
327 usertask_lib_info.append([int(arr[0][0],16), int(arr[0][1],16), str(arr[0][2]).strip()])
328
329 printthread_user_stack_ptr = ShowX86UserStack
330 if kern.arch == "arm":
331 printthread_user_stack_ptr = ShowARMUserStack
5ba3f43e 332 elif kern.arch.startswith("arm64"):
fe8ab488
A
333 printthread_user_stack_ptr = ShowARM64UserStack
334
39236c6e
A
335 counter = 0
336 for thval in IterateQueue(task.threads, 'thread *', 'task_threads'):
337 print "\nThread {0:d} name:0x{1:x}\nThread {0:d}:".format(counter, thval)
338 counter += 1
339 try:
340 printthread_user_stack_ptr(thval, usertask_lib_info)
341 except Exception as exc_err:
342 print "Failed to show user stack for thread 0x{0:x}".format(thval)
343 if config['debug']:
344 raise exc_err
345 else:
346 print "Enable debugging ('(lldb) xnudebug debug') to see detailed trace."
347 return
348
d190cdc3
A
349@lldb_command('showtaskuserstacks', "P:F:")
350def ShowTaskUserStacksCmdHelper(cmd_args=None, cmd_options={}):
351 """ Print out the user stack for each thread in a task, followed by the user libraries.
352 Syntax: (lldb) showtaskuserstacks <task_t>
353 or: (lldb) showtaskuserstacks -P <pid>
354 or: (lldb) showtaskuserstacks -F <task_name>
355 The format is compatible with CrashTracer. You can also use the speedtracer plugin as follows
356 (lldb) showtaskuserstacks <task_t> -p speedtracer
357
358 Note: the address ranges are approximations. Also the list may not be completely accurate. This command expects memory read failures
359 and hence will skip a library if unable to read information. Please use your good judgement and not take the output as accurate
360 """
361 task_list = []
362 if "-F" in cmd_options:
363 task_list = FindTasksByName(cmd_options["-F"])
364 elif "-P" in cmd_options:
365 pidval = ArgumentStringToInt(cmd_options["-P"])
366 for t in kern.tasks:
367 pval = Cast(t.bsd_info, 'proc *')
368 if pval and pval.p_pid == pidval:
369 task_list.append(t)
370 break
371 elif cmd_args:
372 t = kern.GetValueFromAddress(cmd_args[0], 'task *')
373 task_list.append(t)
374 else:
375 raise ArgumentError("Insufficient arguments")
376
377 for task in task_list:
378 ShowTaskUserStacks(task)
39236c6e
A
379
380def GetUserDataAsString(task, addr, size):
381 """ Get data from task's address space as a string of bytes
382 params:
383 task: task object from which to extract information
384 addr: int - start address to get data from.
385 size: int - no of bytes to read.
386 returns:
387 str - a stream of bytes. Empty string if read fails.
388 """
389 err = lldb.SBError()
390 if GetConnectionProtocol() == "kdp":
391 kdp_pmap_addr = unsigned(addressof(kern.globals.kdp_pmap))
392 if not WriteInt64ToMemoryAddress(unsigned(task.map.pmap), kdp_pmap_addr):
393 debuglog("Failed to write in kdp_pmap from GetUserDataAsString.")
394 return ""
395 content = LazyTarget.GetProcess().ReadMemory(addr, size, err)
396 if not err.Success():
397 debuglog("Failed to read process memory. Error: " + err.description)
398 return ""
399 if not WriteInt64ToMemoryAddress(0, kdp_pmap_addr):
400 debuglog("Failed to reset in kdp_pmap from GetUserDataAsString.")
401 return ""
5ba3f43e 402 elif (kern.arch == 'x86_64' or kern.arch.startswith('arm')) and (long(size) < (2 * kern.globals.page_size)):
39236c6e
A
403 # Without the benefit of a KDP stub on the target, try to
404 # find the user task's physical mapping and memcpy the data.
405 # If it straddles a page boundary, copy in two passes
406 range1_addr = long(addr)
407 range1_size = long(size)
408 if kern.StraddlesPage(range1_addr, range1_size):
409 range2_addr = long(kern.TruncPage(range1_addr + range1_size))
410 range2_size = long(range1_addr + range1_size - range2_addr)
411 range1_size = long(range2_addr - range1_addr)
412 else:
413 range2_addr = 0
414 range2_size = 0
415 range2_in_kva = 0
416
417 paddr_range1 = PmapWalk(task.map.pmap, range1_addr, vSILENT)
418 if not paddr_range1:
419 debuglog("Not mapped task 0x{:x} address 0x{:x}".format(task, addr))
420 return ""
421
422 range1_in_kva = kern.PhysToKernelVirt(paddr_range1)
423 content = LazyTarget.GetProcess().ReadMemory(range1_in_kva, range1_size, err)
424 if not err.Success():
425 raise RuntimeError("Failed to read process memory. Error: " + err.description)
426
427 if range2_addr:
428 paddr_range2 = PmapWalk(task.map.pmap, range2_addr, vSILENT)
429 if not paddr_range2:
430 debuglog("Not mapped task 0x{:x} address 0x{:x}".format(task, addr))
431 return ""
432 range2_in_kva = kern.PhysToKernelVirt(paddr_range2)
fe8ab488 433 content += LazyTarget.GetProcess().ReadMemory(range2_in_kva, range2_size, err)
39236c6e
A
434 if not err.Success():
435 raise RuntimeError("Failed to read process memory. Error: " + err.description)
436 else:
437 raise NotImplementedError("GetUserDataAsString does not support this configuration")
438
439 return content
440
441def _ExtractDataFromString(strdata, offset, data_type, length=0):
442 """ Extract specific data from string buffer
443 params:
444 strdata: str - string data give from GetUserDataAsString
445 offset: int - 0 based offset into the data.
446 data_type: str - defines what type to be read as. Supported values are:
447 'uint64_t', 'uint32_t', 'string'
448 length: int - used when data_type=='string'
449 returns
450 None - if extraction failed.
451 obj - based on what is requested in data_type
452 """
453 unpack_str = "s"
454 if data_type == 'uint64_t':
455 length = 8
456 unpack_str = "Q"
457 elif data_type == "uint32_t":
458 length = 4
459 unpack_str = "I"
460 else:
461 unpack_str= "%ds" % length
462
463 data_len = len(strdata)
464 if offset > data_len or (offset + length) > data_len or offset < 0:
465 debuglog("Invalid arguments to _ExtractDataFromString.")
466 return 0
467 return struct.unpack(unpack_str, strdata[offset:(offset + length)])[0]
468
3e170ce0 469def GetUserspaceString(task, string_address):
fe8ab488 470 """ Maps 32 bytes at a time and packs as string
39236c6e
A
471 params:
472 task: obj - referencing task to read data from
3e170ce0 473 string_address: int - address where the image path is stored
39236c6e
A
474 returns:
475 str - string path of the file. "" if failed to read.
476 """
477 done = False
478 retval = ""
479
3e170ce0 480 if string_address == 0:
39236c6e
A
481 done = True
482
483 while not done:
3e170ce0
A
484 str_data = GetUserDataAsString(task, string_address, 32)
485 if len(str_data) == 0:
39236c6e
A
486 break
487 i = 0
488 while i < 32:
3e170ce0
A
489 if ord(str_data[i]):
490 retval += str_data[i]
39236c6e
A
491 else:
492 break
493 i += 1
494 if i < 32:
495 done = True
496 else:
3e170ce0 497 string_address += 32
39236c6e
A
498 return retval
499
500def GetImageInfo(task, mh_image_address, mh_path_address, approx_end_address=None):
501 """ Print user library informaiton.
502 params:
503 task : obj referencing the task for which Image info printed
504 mh_image_address : int - address which has image info
505 mh_path_address : int - address which holds path name string
506 approx_end_address: int - address which lldbmacros think is end address.
507 returns:
508 str - string representing image info. "" if failure to read data.
509 """
510 if approx_end_address:
511 image_end_load_address = int(approx_end_address) -1
512 else:
513 image_end_load_address = int(mh_image_address) + 0xffffffff
514
515 print_format = "0x{0:x} - 0x{1:x} {2: <50s} (??? - ???) <{3: <36s}> {4: <50s}"
516 # 32 bytes enough for mach_header/mach_header_64
517 mh_data = GetUserDataAsString(task, mh_image_address, 32)
518 if len(mh_data) == 0:
519 debuglog("unable to get userdata for task 0x{:x} img_addr 0x{:x} path_address 0x{:x}".format(
520 task, mh_image_address, mh_path_address))
521 return ""
522 mh_magic = _ExtractDataFromString(mh_data, (4 * 0), "uint32_t")
523 mh_cputype = _ExtractDataFromString(mh_data,(4 * 1), "uint32_t")
524 mh_cpusubtype = _ExtractDataFromString(mh_data,(4 * 2), "uint32_t")
525 mh_filetype = _ExtractDataFromString(mh_data,(4 * 3), "uint32_t")
526 mh_ncmds = _ExtractDataFromString(mh_data,(4 * 4), "uint32_t")
527 mh_sizeofcmds = _ExtractDataFromString(mh_data,(4 * 5), "uint32_t")
528 mh_flags = _ExtractDataFromString(mh_data,(4 * 6), "uint32_t")
529
530 if mh_magic == 0xfeedfacf:
531 mh_64 = True
532 lc_address = mh_image_address + 32
533 else:
534 mh_64 = False
535 lc_address = mh_image_address + 28
536
537 lc_idx = 0
538 uuid_data = 0
539 found_uuid_data = False
540 retval = None
541 while lc_idx < mh_ncmds:
542 # 24 bytes is the size of uuid_command
fe8ab488 543 lcmd_data = GetUserDataAsString(task, lc_address, 24)
39236c6e
A
544 lc_cmd = _ExtractDataFromString(lcmd_data, 4 * 0, "uint32_t")
545 lc_cmd_size = _ExtractDataFromString(lcmd_data, 4 * 1, "uint32_t")
546 lc_data = _ExtractDataFromString(lcmd_data, 4*2, "string", 16)
547
548 uuid_out_string = ""
549 path_out_string = ""
550
551 if lc_cmd == 0x1b:
552 # need to print the uuid now.
553 uuid_data = [ord(x) for x in lc_data]
554 found_uuid_data = True
fe8ab488 555 uuid_out_string = "{a[0]:02X}{a[1]:02X}{a[2]:02X}{a[3]:02X}-{a[4]:02X}{a[5]:02X}-{a[6]:02X}{a[7]:02X}-{a[8]:02X}{a[9]:02X}-{a[10]:02X}{a[11]:02X}{a[12]:02X}{a[13]:02X}{a[14]:02X}{a[15]:02X}".format(a=uuid_data)
39236c6e 556 #also print image path
3e170ce0 557 path_out_string = GetUserspaceString(task, mh_path_address)
39236c6e
A
558 path_base_name = path_out_string.split("/")[-1]
559 retval = print_format.format(mh_image_address, image_end_load_address, path_base_name, uuid_out_string, path_out_string)
560 elif lc_cmd == 0xe:
561 ShowTaskUserLibraries.exec_load_path = lc_address + _ExtractDataFromString(lcmd_data, 4*2, "uint32_t")
fe8ab488 562 debuglog("Found load command to be 0xe for address %s" % hex(ShowTaskUserLibraries.exec_load_path))
39236c6e
A
563 lc_address = lc_address + lc_cmd_size
564 lc_idx += 1
565
566 if not found_uuid_data:
3e170ce0 567 path_out_string = GetUserspaceString(task, mh_path_address)
39236c6e
A
568 path_base_name = path_out_string.split("/")[-1]
569 uuid_out_string = ""
570
571 retval = print_format.format(mh_image_address, image_end_load_address, path_base_name, uuid_out_string, path_out_string)
572 return retval
573
574@static_var("found_images", []) # holds entries of format (startaddr, endaddr, image_path_addr, infostring)
575@static_var("exec_load_path", 0)
576@lldb_command("showtaskuserlibraries")
577def ShowTaskUserLibraries(cmd_args=None):
578 """ Show binary images known by dyld in target task
579 For a given user task, inspect the dyld shared library state and print information about all Mach-O images.
580 Syntax: (lldb)showtaskuserlibraries <task_t>
581 Note: the address ranges are approximations. Also the list may not be completely accurate. This command expects memory read failures
582 and hence will skip a library if unable to read information. Please use your good judgement and not take the output as accurate
583 """
584 if not cmd_args:
585 raise ArgumentError("Insufficient arguments")
586
587 #reset the found_images array
588 ShowTaskUserLibraries.found_images = []
589
590 task = kern.GetValueFromAddress(cmd_args[0], 'task_t')
591 is_task_64 = int(task.t_flags) & 0x1
592 dyld_all_image_infos_address = unsigned(task.all_image_info_addr)
fe8ab488
A
593 debuglog("dyld_all_image_infos_address = %s" % hex(dyld_all_image_infos_address))
594
39236c6e
A
595 cur_data_offset = 0
596 if dyld_all_image_infos_address == 0:
597 print "No dyld shared library information available for task"
598 return False
fe8ab488
A
599
600 debuglog("Extracting version information.")
39236c6e
A
601 vers_info_data = GetUserDataAsString(task, dyld_all_image_infos_address, 112)
602 version = _ExtractDataFromString(vers_info_data, cur_data_offset, "uint32_t")
603 cur_data_offset += 4
fe8ab488 604 if version > 14:
39236c6e
A
605 print "Unknown dyld all_image_infos version number %d" % version
606 image_info_count = _ExtractDataFromString(vers_info_data, cur_data_offset, "uint32_t")
fe8ab488
A
607 debuglog("version = %d count = %d is_task_64 = %s" % (version, image_info_count, repr(is_task_64)))
608
39236c6e
A
609 ShowTaskUserLibraries.exec_load_path = 0
610 if is_task_64:
611 image_info_size = 24
612 image_info_array_address = _ExtractDataFromString(vers_info_data, 8, "uint64_t")
613 dyld_load_address = _ExtractDataFromString(vers_info_data, 8*4, "uint64_t")
614 dyld_all_image_infos_address_from_struct = _ExtractDataFromString(vers_info_data, 8*13, "uint64_t")
615 else:
616 image_info_size = 12
617 image_info_array_address = _ExtractDataFromString(vers_info_data, 4*2, "uint32_t")
618 dyld_load_address = _ExtractDataFromString(vers_info_data, 4*5, "uint32_t")
619 dyld_all_image_infos_address_from_struct = _ExtractDataFromString(vers_info_data, 4*14, "uint32_t")
620 # Account for ASLR slide before dyld can fix the structure
621 dyld_load_address = dyld_load_address + (dyld_all_image_infos_address - dyld_all_image_infos_address_from_struct)
622
623 i = 0
624 image_info_list = []
625 while i < image_info_count:
626 image_info_address = image_info_array_address + i * image_info_size
fe8ab488 627 debuglog("i = %d, image_info_address = %s, image_info_size = %d" % (i, hex(image_info_address), image_info_size))
39236c6e
A
628 n_im_info_addr = None
629 img_data = ""
630 try:
631 img_data = GetUserDataAsString(task, image_info_address, image_info_size)
632 except Exception, e:
633 debuglog("Failed to read user data for task 0x{:x} addr 0x{:x}, exception {:s}".format(task, image_info_address, str(e)))
634 pass
fe8ab488 635
39236c6e
A
636 if is_task_64:
637 image_info_addr = _ExtractDataFromString(img_data, 0, "uint64_t")
638 image_info_path = _ExtractDataFromString(img_data, 8, "uint64_t")
639 else:
640 image_info_addr = _ExtractDataFromString(img_data, 0, "uint32_t")
641 image_info_path = _ExtractDataFromString(img_data, 4, "uint32_t")
fe8ab488 642
39236c6e 643 if image_info_addr :
fe8ab488 644 debuglog("Found image: image_info_addr = %s, image_info_path= %s" % (hex(image_info_addr), hex(image_info_path)))
39236c6e
A
645 image_info_list.append((image_info_addr, image_info_path))
646 i += 1
fe8ab488 647
39236c6e 648 image_info_list.sort()
fe8ab488
A
649 num_images_found = len(image_info_list)
650
39236c6e
A
651 for ii in range(num_images_found):
652 n_im_info_addr = dyld_load_address
653 if ii + 1 < num_images_found:
654 n_im_info_addr = image_info_list[ii+1][0]
655
656 image_info_addr = image_info_list[ii][0]
657 image_info_path = image_info_list[ii][1]
658 try:
659 image_print_s = GetImageInfo(task, image_info_addr, image_info_path, approx_end_address=n_im_info_addr)
660 if len(image_print_s) > 0:
661 print image_print_s
662 ShowTaskUserLibraries.found_images.append((image_info_addr, n_im_info_addr, image_info_path, image_print_s))
663 else:
664 debuglog("Failed to print image info for task 0x{:x} image_info 0x{:x}".format(task, image_info_addr))
665 except Exception,e:
666 if config['debug']:
667 raise e
fe8ab488
A
668
669 # load_path might get set when the main executable is processed.
670 if ShowTaskUserLibraries.exec_load_path != 0:
671 debuglog("main executable load_path is set.")
39236c6e
A
672 image_print_s = GetImageInfo(task, dyld_load_address, ShowTaskUserLibraries.exec_load_path)
673 if len(image_print_s) > 0:
674 print image_print_s
675 ShowTaskUserLibraries.found_images.append((dyld_load_address, dyld_load_address + 0xffffffff,
676 ShowTaskUserLibraries.exec_load_path, image_print_s))
677 else:
678 debuglog("Failed to print image for main executable for task 0x{:x} dyld_load_addr 0x{:x}".format(task, dyld_load_address))
fe8ab488
A
679 else:
680 debuglog("Falling back to vm entry method for finding executable load address")
681 print "# NOTE: Failed to find executable using all_image_infos. Using fuzzy match to find best possible load address for executable."
682 ShowTaskLoadInfo([cmd_args[0]])
39236c6e
A
683 return
684
fe8ab488
A
685@lldb_command("showtaskuserdyldinfo")
686def ShowTaskUserDyldInfo(cmd_args=None):
687 """ Inspect the dyld global info for the given user task & print out all fields including error messages
688 Syntax: (lldb)showtaskuserdyldinfo <task_t>
689 """
690 if cmd_args == None or len(cmd_args) < 1:
691 print "No arguments passed"
692 print ShowTaskUserDyldInfo.__doc__.strip()
693 return
694
695 out_str = ""
696 task = kern.GetValueFromAddress(cmd_args[0], 'task_t')
697 is_task_64 = int(task.t_flags) & 0x1
698 dyld_all_image_infos_address = unsigned(task.all_image_info_addr)
699 if dyld_all_image_infos_address == 0:
700 print "No dyld shared library information available for task"
701 return False
702 vers_info_data = GetUserDataAsString(task, dyld_all_image_infos_address, 112)
703 dyld_all_image_infos_version = _ExtractDataFromString(vers_info_data, 0, "uint32_t")
704 if dyld_all_image_infos_version > 14:
705 out_str += "Unknown dyld all_image_infos version number %d" % dyld_all_image_infos_version
706
707 # Find fields by byte offset. We assume at least version 9 is supported
708 if is_task_64:
709 dyld_all_image_infos_infoArrayCount = _ExtractDataFromString(vers_info_data, 4, "uint32_t")
710 dyld_all_image_infos_infoArray = _ExtractDataFromString(vers_info_data, 8, "uint64_t")
711 dyld_all_image_infos_notification = _ExtractDataFromString(vers_info_data, 16, "uint64_t")
712 dyld_all_image_infos_processDetachedFromSharedRegion = _ExtractDataFromString(vers_info_data, 24, "string")
713 dyld_all_image_infos_libSystemInitialized = _ExtractDataFromString(vers_info_data, 25, "string")
714 dyld_all_image_infos_dyldImageLoadAddress = _ExtractDataFromString(vers_info_data, 32, "uint64_t")
715 dyld_all_image_infos_jitInfo = _ExtractDataFromString(vers_info_data, 40, "uint64_t")
716 dyld_all_image_infos_dyldVersion = _ExtractDataFromString(vers_info_data, 48, "uint64_t")
717 dyld_all_image_infos_errorMessage = _ExtractDataFromString(vers_info_data, 56, "uint64_t")
718 dyld_all_image_infos_terminationFlags = _ExtractDataFromString(vers_info_data, 64, "uint64_t")
719 dyld_all_image_infos_coreSymbolicationShmPage = _ExtractDataFromString(vers_info_data, 72, "uint64_t")
720 dyld_all_image_infos_systemOrderFlag = _ExtractDataFromString(vers_info_data, 80, "uint64_t")
721 dyld_all_image_infos_uuidArrayCount = _ExtractDataFromString(vers_info_data, 88, "uint64_t")
722 dyld_all_image_infos_uuidArray = _ExtractDataFromString(vers_info_data, 96, "uint64_t")
723 dyld_all_image_infos_dyldAllImageInfosAddress = _ExtractDataFromString(vers_info_data, 104, "uint64_t")
724 else:
725 dyld_all_image_infos_infoArrayCount = _ExtractDataFromString(vers_info_data, 4, "uint32_t")
726 dyld_all_image_infos_infoArray = _ExtractDataFromString(vers_info_data, 8, "uint32_t")
727 dyld_all_image_infos_notification = _ExtractDataFromString(vers_info_data, 12, "uint32_t")
728 dyld_all_image_infos_processDetachedFromSharedRegion = _ExtractDataFromString(vers_info_data, 16, "string")
729 dyld_all_image_infos_libSystemInitialized = _ExtractDataFromString(vers_info_data, 17, "string")
730 dyld_all_image_infos_dyldImageLoadAddress = _ExtractDataFromString(vers_info_data, 20, "uint32_t")
731 dyld_all_image_infos_jitInfo = _ExtractDataFromString(vers_info_data, 24, "uint32_t")
732 dyld_all_image_infos_dyldVersion = _ExtractDataFromString(vers_info_data, 28, "uint32_t")
733 dyld_all_image_infos_errorMessage = _ExtractDataFromString(vers_info_data, 32, "uint32_t")
734 dyld_all_image_infos_terminationFlags = _ExtractDataFromString(vers_info_data, 36, "uint32_t")
735 dyld_all_image_infos_coreSymbolicationShmPage = _ExtractDataFromString(vers_info_data, 40, "uint32_t")
736 dyld_all_image_infos_systemOrderFlag = _ExtractDataFromString(vers_info_data, 44, "uint32_t")
737 dyld_all_image_infos_uuidArrayCount = _ExtractDataFromString(vers_info_data, 48, "uint32_t")
738 dyld_all_image_infos_uuidArray = _ExtractDataFromString(vers_info_data, 52, "uint32_t")
739 dyld_all_image_infos_dyldAllImageInfosAddress = _ExtractDataFromString(vers_info_data, 56, "uint32_t")
740
741 dyld_all_imfo_infos_slide = (dyld_all_image_infos_address - dyld_all_image_infos_dyldAllImageInfosAddress)
742 dyld_all_image_infos_dyldVersion_postslide = (dyld_all_image_infos_dyldVersion + dyld_all_imfo_infos_slide)
743
3e170ce0 744 path_out = GetUserspaceString(task, dyld_all_image_infos_dyldVersion_postslide)
fe8ab488
A
745 out_str += "[dyld-{:s}]\n".format(path_out)
746 out_str += "version \t\t\t\t: {:d}\n".format(dyld_all_image_infos_version)
747 out_str += "infoArrayCount \t\t\t\t: {:d}\n".format(dyld_all_image_infos_infoArrayCount)
748 out_str += "infoArray \t\t\t\t: {:#x}\n".format(dyld_all_image_infos_infoArray)
749 out_str += "notification \t\t\t\t: {:#x}\n".format(dyld_all_image_infos_notification)
750
751 out_str += "processDetachedFromSharedRegion \t: "
752 if dyld_all_image_infos_processDetachedFromSharedRegion != "":
753 out_str += "TRUE\n".format(dyld_all_image_infos_processDetachedFromSharedRegion)
754 else:
755 out_str += "FALSE\n"
756
757 out_str += "libSystemInitialized \t\t\t: "
758 if dyld_all_image_infos_libSystemInitialized != "":
759 out_str += "TRUE\n".format(dyld_all_image_infos_libSystemInitialized)
760 else:
761 out_str += "FALSE\n"
762
763 out_str += "dyldImageLoadAddress \t\t\t: {:#x}\n".format(dyld_all_image_infos_dyldImageLoadAddress)
764 out_str += "jitInfo \t\t\t\t: {:#x}\n".format(dyld_all_image_infos_jitInfo)
765 out_str += "\ndyldVersion \t\t\t\t: {:#x}".format(dyld_all_image_infos_dyldVersion)
766 if (dyld_all_imfo_infos_slide != 0):
767 out_str += " (currently {:#x})\n".format(dyld_all_image_infos_dyldVersion_postslide)
768 else:
769 out_str += "\n"
770
771 out_str += "errorMessage \t\t\t\t: {:#x}\n".format(dyld_all_image_infos_errorMessage)
772 if dyld_all_image_infos_errorMessage != 0:
3e170ce0 773 out_str += GetUserspaceString(task, dyld_all_image_infos_errorMessage)
fe8ab488
A
774
775 out_str += "terminationFlags \t\t\t: {:#x}\n".format(dyld_all_image_infos_terminationFlags)
776 out_str += "coreSymbolicationShmPage \t\t: {:#x}\n".format(dyld_all_image_infos_coreSymbolicationShmPage)
777 out_str += "systemOrderFlag \t\t\t: {:#x}\n".format(dyld_all_image_infos_systemOrderFlag)
778 out_str += "uuidArrayCount \t\t\t\t: {:#x}\n".format(dyld_all_image_infos_uuidArrayCount)
779 out_str += "uuidArray \t\t\t\t: {:#x}\n".format(dyld_all_image_infos_uuidArray)
780 out_str += "dyldAllImageInfosAddress \t\t: {:#x}".format(dyld_all_image_infos_dyldAllImageInfosAddress)
781 if (dyld_all_imfo_infos_slide != 0):
782 out_str += " (currently {:#x})\n".format(dyld_all_image_infos_address)
783 else:
784 out_str += "\n"
785
786 if is_task_64:
787 dyld_all_image_infos_address = dyld_all_image_infos_address + 112
788 dyld_all_image_infos_v10 = GetUserDataAsString(task, dyld_all_image_infos_address, 64)
789 dyld_all_image_infos_initialImageCount = _ExtractDataFromString(dyld_all_image_infos_v10, 112-112, "uint64_t")
790 dyld_all_image_infos_errorKind = _ExtractDataFromString(dyld_all_image_infos_v10, 120-112, "uint64_t")
791 dyld_all_image_infos_errorClientOfDylibPath = _ExtractDataFromString(dyld_all_image_infos_v10, 128-112, "uint64_t")
792 dyld_all_image_infos_errorTargetDylibPath = _ExtractDataFromString(dyld_all_image_infos_v10, 136-112, "uint64_t")
793 dyld_all_image_infos_errorSymbol = _ExtractDataFromString(dyld_all_image_infos_v10, 144-112, "uint64_t")
794 dyld_all_image_infos_sharedCacheSlide = _ExtractDataFromString(dyld_all_image_infos_v10, 152-112, "uint64_t")
795 dyld_all_image_infos_sharedCacheUUID = _ExtractDataFromString(dyld_all_image_infos_v10, 160-112, "string")
796 else:
797 dyld_all_image_infos_address = dyld_all_image_infos_address + 60
798 dyld_all_image_infos_v10 = GetUserDataAsString(task, dyld_all_image_infos_address, 40)
799 dyld_all_image_infos_initialImageCount = _ExtractDataFromString(dyld_all_image_infos_v10, 60-60, "uint32_t")
800 dyld_all_image_infos_errorKind = _ExtractDataFromString(dyld_all_image_infos_v10, 64-60, "uint32_t")
801 dyld_all_image_infos_errorClientOfDylibPath = _ExtractDataFromString(dyld_all_image_infos_v10, 68-60, "uint32_t")
802 dyld_all_image_infos_errorTargetDylibPath = _ExtractDataFromString(dyld_all_image_infos_v10, 72-60, "uint32_t")
803 dyld_all_image_infos_errorSymbol = _ExtractDataFromString(dyld_all_image_infos_v10, 76-60, "uint32_t")
804 dyld_all_image_infos_sharedCacheSlide = _ExtractDataFromString(dyld_all_image_infos_v10, 80-60, "uint32_t")
805 dyld_all_image_infos_sharedCacheUUID = _ExtractDataFromString(dyld_all_image_infos_v10, 84-60, "string")
806
807 if dyld_all_image_infos_version >= 10:
808 out_str += "\ninitialImageCount \t\t\t: {:#x}\n".format(dyld_all_image_infos_initialImageCount)
809
810 if dyld_all_image_infos_version >= 11:
811 out_str += "errorKind \t\t\t\t: {:#x}\n".format(dyld_all_image_infos_errorKind)
812 out_str += "errorClientOfDylibPath \t\t\t: {:#x}\n".format(dyld_all_image_infos_errorClientOfDylibPath)
813 if dyld_all_image_infos_errorClientOfDylibPath != 0:
814 out_str += "\t\t\t\t"
3e170ce0 815 out_str += GetUserspaceString(task, dyld_all_image_infos_errorClientOfDylibPath)
fe8ab488
A
816 out_str += "\n"
817 out_str += "errorTargetDylibPath \t\t\t: {:#x}\n".format(dyld_all_image_infos_errorTargetDylibPath)
818 if dyld_all_image_infos_errorTargetDylibPath != 0:
819 out_str += "\t\t\t\t"
3e170ce0 820 out_str += GetUserspaceString(task, dyld_all_image_infos_errorTargetDylibPath)
fe8ab488
A
821 out_str += "\n"
822 out_str += "errorSymbol \t\t\t\t: {:#x}\n".format(dyld_all_image_infos_errorSymbol)
823 if dyld_all_image_infos_errorSymbol != 0:
824 out_str += "\t\t\t\t"
3e170ce0 825 out_str += GetUserspaceString(task, dyld_all_image_infos_errorSymbol)
fe8ab488
A
826 out_str += "\n"
827
828 if dyld_all_image_infos_version >= 12:
829 out_str += "sharedCacheSlide \t\t\t: {:#x}\n".format(dyld_all_image_infos_sharedCacheSlide)
830 if dyld_all_image_infos_version >= 13 and dyld_all_image_infos_sharedCacheUUID != "":
831 out_str += "sharedCacheUUID \t\t\t: {:s}\n".format(dyld_all_image_infos_sharedCacheUUID)
832 else:
833 out_str += "No dyld information available for task\n"
834 print out_str
835
836# Macro: showosmalloc
837@lldb_type_summary(['OSMallocTag'])
838@header("{0: <20s} {1: >5s} {2: ^16s} {3: <5s} {4: <40s}".format("TAG", "COUNT", "STATE", "ATTR", "NAME"))
839def GetOSMallocTagSummary(malloc_tag):
840 """ Summarize the given OSMalloc tag.
841 params:
842 malloc_tag : value - value representing a _OSMallocTag_ * in kernel
843 returns:
844 out_str - string summary of the OSMalloc tag.
845 """
846 if not malloc_tag:
847 return "Invalid malloc tag value: 0x0"
848
849 out_str = "{: <#20x} {: >5d} {: ^#16x} {: <5d} {: <40s}\n".format(malloc_tag,
850 malloc_tag.OSMT_refcnt, malloc_tag.OSMT_state, malloc_tag.OSMT_attr, malloc_tag.OSMT_name)
851 return out_str
852
853@lldb_command('showosmalloc')
854def ShowOSMalloc(cmd_args=None):
855 """ Print the outstanding allocation count of OSMalloc tags
856 Usage: showosmalloc
857 """
858 summary_str = ""
859 tag_headp = Cast(addressof(kern.globals.OSMalloc_tag_list), 'struct _OSMallocTag_ *')
860 tagp = Cast(tag_headp.OSMT_link.next, 'struct _OSMallocTag_ *')
861 summary_str += GetOSMallocTagSummary.header + "\n"
862 while tagp != tag_headp:
863 summary_str += GetOSMallocTagSummary(tagp)
864 tagp = Cast(tagp.OSMT_link.next, 'struct _OSMallocTag_ *')
865
866 print summary_str
867
868# EndMacro: showosmalloc
869
cb323159
A
870def SaveDataToFile(start_addr, length, outputfile, task=None,):
871 """ Save the data at the specified address (of the specified length) to the file.
872 params: start_addr : start address of the region of memory to save
873 length : length of the region of memory to save
874 outputfile : file to save the data in
875 task (optional) : task containing the memory region (if from user data)
876 returns: True if we saved the requested data, False otherwise
877 """
878 if task:
879 memory_data = GetUserDataAsString(task, start_addr, length)
880 else:
881 data_ptr = kern.GetValueFromAddress(start_addr, 'uint8_t *')
882 if data_ptr == 0:
883 print "invalid kernel start address specified"
884 return False
885 memory_data = []
886 for i in range(length):
887 memory_data.append(chr(data_ptr[i]))
888 if i % 50000 == 0:
889 print "%d of %d \r" % (i, length),
890 memory_data = ''.join(memory_data)
891
892 if len(memory_data) != length:
893 print "Failed to read {:d} bytes from address {: <#020x}".format(length, start_addr)
894 return False
895
896 fh = open(outputfile, 'w')
897 fh.write(memory_data)
898 fh.close()
899 print "Saved {:d} bytes to file {:s}".format(length, outputfile)
900 return True
901
fe8ab488 902
3e170ce0
A
903@lldb_command('savekcdata', 'T:O:')
904def SaveKCDataToFile(cmd_args=None, cmd_options={}):
905 """ Save the data referred by the kcdata_descriptor structure.
906 options:
907 -T: <task_t> pointer to task if memory referenced is in userstask.
908 -O: <output file path> path to file to save data. default: /tmp/kcdata.<timestamp>.bin
909 Usage: (lldb) savekcdata <kcdata_descriptor_t> -T <task_t> -O /path/to/outputfile.bin
910 """
911 if not cmd_args:
912 raise ArgumentError('Please provide the kcdata descriptor.')
913
914 kcdata = kern.GetValueFromAddress(cmd_args[0], 'kcdata_descriptor_t')
915
916 outputfile = '/tmp/kcdata.{:s}.bin'.format(str(time.time()))
917 task = None
918 if '-O' in cmd_options:
919 outputfile = cmd_options['-O']
920 if '-T' in cmd_options:
921 task = kern.GetValueFromAddress(cmd_options['-T'], 'task_t')
922
923 memory_begin_address = unsigned(kcdata.kcd_addr_begin)
924 memory_size = 16 + unsigned(kcdata.kcd_addr_end) - memory_begin_address
925 flags_copyout = unsigned(kcdata.kcd_flags)
926 if flags_copyout:
927 if not task:
928 raise ArgumentError('Invalid task pointer provided.')
cb323159 929 return SaveDataToFile(memory_begin_address, memory_size, outputfile, task)
3e170ce0 930 else:
cb323159 931 return SaveDataToFile(memory_begin_address, memory_size, outputfile, None)