1from xnu import * 2from utils import * 3from process import * 4from pmap import * 5import struct 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: 10 pc_val : int - integer form of the pc address 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 44 user_abi_type = "uint64_t" 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 50 user_abi_type = "uint32_t" 51 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)) 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) 66 67 frameno = 0 68 while True: 69 frameno = frameno + 1 70 frame = GetUserDataAsString(thread.t_tro.tro_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) 77 return 78 79def _PrintARMUserStack(task, cur_pc, cur_fp, framesize, frametype, frameformat, user_lib_info=None): 80 cur_pc = kern.StripUserPAC(cur_pc) 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) 91 cur_pc = kern.StripUserPAC(cur_pc) 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.t_tro.tro_task, cur_pc, cur_fp, framesize, frametype, frameformat, user_lib_info=user_lib_info) 105 106def ShowARM64UserStack(thread, user_lib_info = None): 107 SAVED_STATE_FLAVOR_ARM=20 108 SAVED_STATE_FLAVOR_ARM64=21 109 upcb_addr = kern.StripKernelPAC(thread.machine.upcb) 110 upcb = kern.GetValueFromAddress(upcb_addr, 'arm_saved_state_t *') 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.t_tro.tro_task, cur_pc, cur_fp, framesize, frametype, frameformat, user_lib_info=user_lib_info) 131 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) 146 elif kern.arch.startswith("arm64"): 147 ShowARM64UserStack(thread) 148 return True 149 150@lldb_command('printuserdata','XO:') 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. 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 161 options: 162 -X : print all values in hex. 163 -O <file path>: Save data to file 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 172 if format_specifier_str == "s": 173 print "0x%x: " % uspace_addr + GetUserspaceString(task, uspace_addr) 174 return True 175 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 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 191 upacked_data = struct.unpack(format_specifier_str, user_data_string) 192 element_size = user_data_len / len(upacked_data) 193 for i in range(len(upacked_data)): 194 if "-X" in cmd_options: 195 print "0x%x: " % (uspace_addr + i*element_size) + hex(upacked_data[i]) 196 else: 197 print "0x%x: " % (uspace_addr + i*element_size) + str(upacked_data[i]) 198 199 return True 200 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 *') 213 ptrsize = 8 if int(task.t_flags) & 0x1 else 4 214 215 format_string = "Q" if ptrsize == 8 else "I" 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 226 pos = string_area_addr - ptrsize 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 235 pos -= ptrsize 236 237 user_data_string = GetUserDataAsString(task, pos, ptrsize) 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 253def ShowTaskUserStacks(task): 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 = """\ 258Process: {pname:s} [{pid:d}] 259Path: {path: <50s} 260Identifier: {pname: <30s} 261Version: ??? (???) 262Code Type: {parch: <20s} 263Parent Process: {ppname:s} [{ppid:d}] 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 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 287 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) 298 if pval: 299 pid = GetProcPID(pval) 300 pname = GetProcName(pval) 301 path = GetProcName(pval) 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), 314 timest = date_string, 315 parch = parch_s, 316 osversion = osversion 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 332 elif kern.arch.startswith("arm64"): 333 printthread_user_stack_ptr = ShowARM64UserStack 334 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 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 GetProcPID(pval) == 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) 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 "" 402 elif (kern.arch == 'x86_64' or kern.arch.startswith('arm')) and (long(size) < (2 * kern.globals.page_size)): 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) 433 content += LazyTarget.GetProcess().ReadMemory(range2_in_kva, range2_size, err) 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 469def GetUserspaceString(task, string_address): 470 """ Maps 32 bytes at a time and packs as string 471 params: 472 task: obj - referencing task to read data from 473 string_address: int - address where the image path is stored 474 returns: 475 str - string path of the file. "" if failed to read. 476 """ 477 done = False 478 retval = "" 479 480 if string_address == 0: 481 done = True 482 483 while not done: 484 str_data = GetUserDataAsString(task, string_address, 32) 485 if len(str_data) == 0: 486 break 487 i = 0 488 while i < 32: 489 if ord(str_data[i]): 490 retval += str_data[i] 491 else: 492 break 493 i += 1 494 if i < 32: 495 done = True 496 else: 497 string_address += 32 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 543 lcmd_data = GetUserDataAsString(task, lc_address, 24) 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 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) 556 #also print image path 557 path_out_string = GetUserspaceString(task, mh_path_address) 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") 562 debuglog("Found load command to be 0xe for address %s" % hex(ShowTaskUserLibraries.exec_load_path)) 563 lc_address = lc_address + lc_cmd_size 564 lc_idx += 1 565 566 if not found_uuid_data: 567 path_out_string = GetUserspaceString(task, mh_path_address) 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) 593 debuglog("dyld_all_image_infos_address = %s" % hex(dyld_all_image_infos_address)) 594 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 599 600 debuglog("Extracting version information.") 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 604 if version > 14: 605 print "Unknown dyld all_image_infos version number %d" % version 606 image_info_count = _ExtractDataFromString(vers_info_data, cur_data_offset, "uint32_t") 607 debuglog("version = %d count = %d is_task_64 = %s" % (version, image_info_count, repr(is_task_64))) 608 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 627 debuglog("i = %d, image_info_address = %s, image_info_size = %d" % (i, hex(image_info_address), image_info_size)) 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 635 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") 642 643 if image_info_addr : 644 debuglog("Found image: image_info_addr = %s, image_info_path= %s" % (hex(image_info_addr), hex(image_info_path))) 645 image_info_list.append((image_info_addr, image_info_path)) 646 i += 1 647 648 image_info_list.sort() 649 num_images_found = len(image_info_list) 650 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 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.") 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)) 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]]) 683 return 684 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 744 path_out = GetUserspaceString(task, dyld_all_image_infos_dyldVersion_postslide) 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: 773 out_str += GetUserspaceString(task, dyld_all_image_infos_errorMessage) 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" 815 out_str += GetUserspaceString(task, dyld_all_image_infos_errorClientOfDylibPath) 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" 820 out_str += GetUserspaceString(task, dyld_all_image_infos_errorTargetDylibPath) 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" 825 out_str += GetUserspaceString(task, dyld_all_image_infos_errorSymbol) 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 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 902 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.') 929 return SaveDataToFile(memory_begin_address, memory_size, outputfile, task) 930 else: 931 return SaveDataToFile(memory_begin_address, memory_size, outputfile, None) 932