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