1""" Please make sure you read the README file COMPLETELY BEFORE reading anything below. 2 It is very critical that you read coding guidelines in Section E in README file. 3""" 4from __future__ import absolute_import, division, print_function 5 6from builtins import hex 7from builtins import range 8 9import sys 10from xnu import * 11from utils import * 12from process import * 13from bank import * 14from waitq import * 15from ioreg import * 16from memory import * 17import xnudefines 18import kmemory 19 20@lldb_type_summary(['struct ipc_entry_table *', 'ipc_entry_table_t']) 21def PrintIpcEntryTable(array): 22 t, s = kalloc_array_decode(array, 'struct ipc_entry') 23 return "ptr = {:#x}, size = {:d}, elem_type = struct ipc_entry".format(unsigned(t), s) 24 25@lldb_type_summary(['struct ipc_port_requests_table *', 'ipc_port_requests_table_t']) 26def PrintIpcPortRequestTable(array): 27 t, s = kalloc_array_decode(array, 'struct ipc_port_requests') 28 return "ptr = {:#x}, size = {:d}, elem_type = struct ipc_port_requests".format(unsigned(t), s) 29 30def GetSpaceTable(space): 31 """ Return the tuple of (entries, size) of the table for a space 32 """ 33 table = space.is_table.__smr_ptr 34 if table: 35 return kalloc_array_decode(table, 'struct ipc_entry') 36 return (None, 0) 37 38def GetSpaceEntriesWithBits(is_tableval, num_entries, mask): 39 base = is_tableval.GetSBValue().Dereference() 40 return ( 41 (index, iep) 42 for index, iep in enumerate(base.xIterSiblings(1, num_entries), 1) 43 if iep.xGetIntegerByName('ie_bits') & mask 44 ) 45 46def GetSpaceObjectsWithBits(is_tableval, num_entries, mask, ty): 47 base = is_tableval.GetSBValue().Dereference() 48 return ( 49 iep.xCreateValueFromAddress( 50 None, 51 iep.xGetIntegerByName('ie_object'), 52 ty, 53 ) 54 for iep in base.xIterSiblings(1, num_entries) 55 if iep.xGetIntegerByName('ie_bits') & mask 56 ) 57 58 59@header("{0: <20s} {1: <6s} {2: <6s} {3: <10s} {4: <32s}".format("task", "pid", '#acts', "tablesize", "command")) 60def GetTaskIPCSummary(task, show_busy = False): 61 """ Display a task's ipc summary. 62 params: 63 task : core.value represeting a Task in kernel 64 returns 65 str - string of ipc info for the task 66 """ 67 out_string = '' 68 format_string = "{0: <#20x} {1: <6d} {2: <6d} {3: <10d} {4: <32s}" 69 busy_format = " {0: <10d} {1: <6d}" 70 proc_name = '' 71 if not task.active: 72 proc_name = 'terminated: ' 73 if task.halting: 74 proc_name += 'halting: ' 75 proc_name += GetProcNameForTask(task) 76 _, table_size = GetSpaceTable(task.itk_space) 77 out_string += format_string.format(task, GetProcPIDForTask(task), task.thread_count, table_size, proc_name) 78 if show_busy: 79 nbusy, nmsgs = GetTaskBusyPortsSummary(task) 80 out_string += busy_format.format(nbusy, nmsgs) 81 return (out_string, table_size, nbusy, nmsgs) 82 return (out_string, table_size) 83 84@header("{0: <20s} {1: <6s} {2: <6s} {3: <10s} {4: <32s} {5: <10s} {6: <6s}".format("task", "pid", '#acts', "tablesize", "command", "#busyports", "#kmsgs")) 85def GetTaskBusyIPCSummary(task): 86 return GetTaskIPCSummary(task, True) 87 88def GetTaskBusyPortsSummary(task): 89 is_tableval, num_entries = GetSpaceTable(task.itk_space) 90 port_ty = gettype('struct ipc_port') 91 nbusy = 0 92 nmsgs = 0 93 94 if is_tableval: 95 ports = GetSpaceObjectsWithBits(is_tableval, num_entries, 0x00020000, 96 gettype('struct ipc_port')) 97 98 for port in ports: 99 if not port or port == xnudefines.MACH_PORT_DEAD: 100 continue 101 count = port.xGetIntegerByPath('.ip_messages.imq_msgcount') 102 if count: 103 nbusy += 1 104 nmsgs += count 105 106 return (nbusy, nmsgs) 107 108 109@header("{:<20s} {:<20s} {:<10s} {:>6s} {:<20s} {:>8s} {:<20s} {:s}".format( 110 "port", "waitqueue", "recvname", "refs", "receiver", "nmsgs", "service", "dest/kobject")) 111def PrintPortSummary(port, show_kmsg_summary=True, show_sets=False, prefix="", O=None): 112 """ Display a port's summary 113 params: 114 port : core.value representing a port in the kernel 115 returns 116 str : string of ipc info for the given port 117 """ 118 119 format_string = "{:<#20x} {:<#20x} {:#010x} {:>6d} {:<#20x} {:>8d} {:<20s} {:<s}" 120 receiver_name = port.ip_messages.imq_receiver_name 121 splabel_name = 'N/A' 122 space = 0 123 refs = 0 124 125 if port.ip_object.io_bits & 0x80000000: 126 if receiver_name: 127 space = unsigned(port.ip_receiver) 128 129 try: 130 if port.ip_service_port: 131 splabel = Cast(port.ip_splabel, 'struct ipc_service_port_label *') 132 splabel_name = str(splabel.ispl_service_name) # Not on RELEASE kernel 133 except: 134 splabel_name = 'unknown' 135 136 dest_str = GetPortDestProc(port)[1] 137 else: 138 dest_str = "inactive-port" 139 140 print(prefix + format_string.format(unsigned(port), addressof(port.ip_waitq), 141 unsigned(receiver_name), port.ip_object.io_references, space, 142 port.ip_messages.imq_msgcount, splabel_name, dest_str)) 143 144 if show_kmsg_summary: 145 with O.table(prefix + GetKMsgSummary.header): 146 for kmsgp in IterateCircleQueue(port.ip_messages.imq_messages, 'ipc_kmsg', 'ikm_link'): 147 print(prefix + GetKMsgSummary(kmsgp, prefix)) 148 149 wq = Waitq(addressof(port.ip_waitq)) 150 if show_sets and wq.hasSets(): 151 def doit(wq): 152 for wqs in Waitq(addressof(port.ip_waitq)).iterateSets(): 153 PrintPortSetSummary(wqs.asPset(), space=port.ip_receiver, verbose=False, O=O) 154 155 if O is None: 156 print(PrintPortSetSummary.header) 157 doit(wq) 158 else: 159 with O.table(PrintPortSetSummary.header, indent=True): 160 doit(wq) 161 print("") 162 163def GetPortDispositionString(disp): 164 if disp < 0: ## use negative numbers for request ports 165 portname = 'notify' 166 if disp == -1: 167 disp_str = 'reqNS' 168 elif disp == -2: 169 disp_str = 'reqPD' 170 elif disp == -3: 171 disp_str = 'reqSPa' 172 elif disp == -4: 173 disp_str = 'reqSPr' 174 elif disp == -5: 175 disp_str = 'reqSPra' 176 else: 177 disp_str = '-X' 178 ## These dispositions should match those found in osfmk/mach/message.h 179 elif disp == 16: 180 disp_str = 'R' ## receive 181 elif disp == 24: 182 disp_str = 'dR' ## dispose receive 183 elif disp == 17: 184 disp_str = 'S' ## (move) send 185 elif disp == 19: 186 disp_str = 'cS' ## copy send 187 elif disp == 20: 188 disp_str = 'mS' ## make send 189 elif disp == 25: 190 disp_str = 'dS' ## dispose send 191 elif disp == 18: 192 disp_str = 'O' ## send-once 193 elif disp == 21: 194 disp_str = 'mO' ## make send-once 195 elif disp == 26: 196 disp_str = 'dO' ## dispose send-once 197 ## faux dispositions used to string-ify IPC entry types 198 elif disp == 100: 199 disp_str = 'PS' ## port set 200 elif disp == 101: 201 disp_str = 'dead' ## dead name 202 elif disp == 102: 203 disp_str = 'L' ## LABELH 204 elif disp == 103: 205 disp_str = 'V' ## Thread voucher (thread->ith_voucher->iv_port) 206 ## Catch-all 207 else: 208 disp_str = 'X' ## invalid 209 return disp_str 210 211def GetPortPDRequest(port): 212 """ Returns the port-destroyed notification port if any 213 """ 214 if port.ip_has_watchport: 215 return port.ip_twe.twe_pdrequest 216 if not port.ip_specialreply: 217 return port.ip_pdrequest 218 return 0 219 220def GetKmsgHeader(kmsgp): 221 """ Helper to get mach message header of a kmsg. 222 Assumes the kmsg has not been put to user. 223 params: 224 kmsgp : core.value representing the given ipc_kmsg_t struct 225 returns: 226 Mach message header for kmsgp 227 """ 228 inline_buffer = kmsgp + sizeof(dereference(kmsgp)) 229 230 if kmsgp.ikm_type <= int(GetEnumValue('ipc_kmsg_type_t', 'IKM_TYPE_UDATA_OOL')): 231 return kern.GetValueFromAddress(inline_buffer, 'mach_msg_header_t *') 232 233 vec = kern.GetValueFromAddress(inline_buffer, 'ipc_kmsg_vector_t *') 234 return kern.GetValueFromAddress(unsigned(vec.kmsgv_data), 'mach_msg_header_t *') 235 236@header("{:<20s} {:<20s} {:<20s} {:<10s} {:>6s} {:<20s} {:<8s} {:<26s} {:<26s}".format( 237 "", "kmsg", "header", "msgid", "size", "reply-port", "disp", "source", "destination")) 238def GetKMsgSummary(kmsgp, prefix_str=""): 239 """ Display a summary for type ipc_kmsg_t 240 params: 241 kmsgp : core.value representing the given ipc_kmsg_t struct 242 returns: 243 str : string of summary info for the given ipc_kmsg_t instance 244 """ 245 kmsghp = GetKmsgHeader(kmsgp) 246 kmsgh = dereference(kmsghp) 247 out_string = "" 248 out_string += "{:<20s} {:<#20x} {:<#20x} {kmsgh.msgh_id:#010x} {kmsgh.msgh_size:>6d} {kmsgh.msgh_local_port:<#20x} ".format( 249 '', unsigned(kmsgp), unsigned(kmsghp), kmsgh=kmsghp) 250 prefix_str = "{:<20s} ".format(' ') + prefix_str 251 disposition = "" 252 bits = kmsgh.msgh_bits & 0xff 253 254 # remote port 255 if bits == 17: 256 disposition = "rS" 257 elif bits == 18: 258 disposition = "rO" 259 else : 260 disposition = "rX" # invalid 261 262 out_string += "{:<2s}".format(disposition) 263 264 # local port 265 disposition = "" 266 bits = (kmsgh.msgh_bits & 0xff00) >> 8 267 268 if bits == 17: 269 disposition = "lS" 270 elif bits == 18: 271 disposition = "lO" 272 elif bits == 0: 273 disposition = "l-" 274 else: 275 disposition = "lX" # invalid 276 277 out_string += "{:<2s}".format(disposition) 278 279 # voucher 280 disposition = "" 281 bits = (kmsgh.msgh_bits & 0xff0000) >> 16 282 283 if bits == 17: 284 disposition = "vS" 285 elif bits == 0: 286 disposition = "v-" 287 else: 288 disposition = "vX" 289 290 out_string += "{:<2s}".format(disposition) 291 292 # complex message 293 if kmsgh.msgh_bits & 0x80000000: 294 out_string += "{0: <1s}".format("c") 295 else: 296 out_string += "{0: <1s}".format("s") 297 298 # importance boost 299 if kmsgh.msgh_bits & 0x20000000: 300 out_string += "{0: <1s}".format("I") 301 else: 302 out_string += "{0: <1s}".format("-") 303 304 dest_proc_name = "" 305 if GetKmsgHeader(kmsgp).msgh_remote_port: 306 dest_proc_name = GetPortDestinationSummary(GetKmsgHeader(kmsgp).msgh_remote_port) 307 308 out_string += " {:<26s} {:<26s}\n".format(GetKMsgSrc(kmsgp), dest_proc_name) 309 310 if kmsgh.msgh_bits & 0x80000000: 311 out_string += prefix_str + "\t" + GetKMsgComplexBodyDesc.header + "\n" 312 out_string += prefix_str + "\t" + GetKMsgComplexBodyDesc(kmsgp, prefix_str + "\t") + "\n" 313 314 return out_string 315 316@header("{: <20s} {: <20s} {: <10s}".format("descriptor", "address", "size")) 317def GetMachMsgOOLDescriptorSummary(desc): 318 """ Returns description for mach_msg_ool_descriptor_t * object 319 """ 320 format_string = "{: <#20x} {: <#20x} {:#010x}" 321 out_string = format_string.format(desc, desc.address, desc.size) 322 return out_string 323 324 325def GetKmsgDescriptors(kmsgp): 326 """ Get a list of descriptors in a complex message 327 """ 328 kmsghp = GetKmsgHeader(kmsgp) 329 kmsgh = dereference(kmsghp) 330 if not (kmsgh.msgh_bits & 0x80000000): # pragma pylint: disable=superfluous-parens 331 return [] 332 ## Something in the python/lldb types is not getting alignment correct here. 333 ## I'm grabbing a pointer to the body manually, and using tribal knowledge 334 ## of the location of the descriptor count to get this correct 335 body = Cast(addressof(Cast(addressof(kmsgh), 'char *')[sizeof(kmsgh)]), 'mach_msg_body_t *') 336 #dsc_count = body.msgh_descriptor_count 337 dsc_count = dereference(Cast(body, 'uint32_t *')) 338 #dschead = Cast(addressof(body[1]), 'mach_msg_descriptor_t *') 339 dschead = Cast(addressof(Cast(addressof(body[0]), 'char *')[sizeof('uint32_t')]), 'mach_msg_descriptor_t *') 340 dsc_list = [] 341 for i in range(dsc_count): 342 dsc_list.append(dschead[i]) 343 return (body, dschead, dsc_list) 344 345def GetKmsgTotalDescSize(kmsgp): 346 """ Helper to get total descriptor size of a kmsg. 347 Assumes the kmsg has full kernel representation (header and descriptors) 348 params: 349 kmsgp : core.value representing the given ipc_kmsg_t struct 350 returns: 351 Total descriptor size 352 """ 353 kmsghp = GetKmsgHeader(kmsgp) 354 kmsgh = dereference(kmsghp) 355 dsc_count = 0 356 357 if kmsgh.msgh_bits & 0x80000000: # MACH_MSGH_BITS_COMPLEX 358 (body, _, _) = GetKmsgDescriptors(kmsgp) 359 dsc_count = dereference(Cast(body, 'uint32_t *')) 360 361 return dsc_count * sizeof('mach_msg_descriptor_t') 362 363@header("{: <20s} {: <8s} {: <20s} {: <10s} {: <20s}".format("kmsgheader", "size", "body", "ds_count", "dsc_head")) 364def GetKMsgComplexBodyDesc(kmsgp, prefix_str=""): 365 """ Routine that prints a complex kmsg's body 366 """ 367 kmsghp = GetKmsgHeader(kmsgp) 368 kmsgh = dereference(kmsghp) 369 if not (kmsgh.msgh_bits & 0x80000000): # pragma pylint: disable=superfluous-parens 370 return "" 371 format_string = "{: <#20x} {: <#8x} {: <#20x} {:#010x} {: <#20x}" 372 out_string = "" 373 374 (body, dschead, dsc_list) = GetKmsgDescriptors(kmsgp) 375 out_string += format_string.format(kmsghp, sizeof(dereference(kmsghp)), body, len(dsc_list), dschead) 376 for dsc in dsc_list: 377 try: 378 dsc_type = unsigned(dsc.type.type) 379 out_string += "\n" + prefix_str + "Descriptor: " + xnudefines.mach_msg_type_descriptor_strings[dsc_type] 380 if dsc_type == 0: 381 # its a port. 382 p = dsc.port.name 383 dstr = GetPortDispositionString(dsc.port.disposition) 384 out_string += " disp:{:s}, name:{: <#20x}".format(dstr, p) 385 elif unsigned(dsc.type.type) in (1,3): 386 # its OOL DESCRIPTOR or OOL VOLATILE DESCRIPTOR 387 ool = dsc.out_of_line 388 out_string += " " + GetMachMsgOOLDescriptorSummary(addressof(ool)) 389 except: 390 out_string += "\n" + prefix_str + "Invalid Descriptor: {}".format(dsc) 391 return out_string 392 393def GetKmsgTrailer(kmsgp): 394 """ Helper to get trailer address of a kmsg 395 params: 396 kmsgp : core.value representing the given ipc_kmsg_t struct 397 returns: 398 Trailer address 399 """ 400 kmsghp = GetKmsgHeader(kmsgp) 401 kmsgh = dereference(kmsghp) 402 403 if (kmsgp.ikm_type == int(GetEnumValue('ipc_kmsg_type_t', 'IKM_TYPE_ALL_INLINED')) or 404 kmsgp.ikm_type == int(GetEnumValue('ipc_kmsg_type_t', 'IKM_TYPE_KDATA_OOL'))): 405 return kern.GetValueFromAddress(unsigned(kmsghp) + kmsgh.msgh_size, 'mach_msg_max_trailer_t *') 406 else: 407 if kmsgh.msgh_bits & 0x80000000: # MACH_MSGH_BITS_COMPLEX 408 content_size = kmsgh.msgh_size - sizeof('mach_msg_base_t') - GetKmsgTotalDescSize(kmsgp) 409 else: 410 content_size = kmsgh.msgh_size - sizeof('mach_msg_header_t') 411 return kern.GetValueFromAddress(unsigned(kmsgp.ikm_udata) + content_size, 'mach_msg_max_trailer_t *') 412 413def GetKMsgSrc(kmsgp): 414 """ Routine that prints a kmsg's source process and pid details 415 params: 416 kmsgp : core.value representing the given ipc_kmsg_t struct 417 returns: 418 str : string containing the name and pid of the kmsg's source proc 419 """ 420 trailer = GetKmsgTrailer(kmsgp) 421 kmsgpid = Cast(trailer, 'uint *')[10] # audit_token.val[5] 422 return "{0:s} ({1:d})".format(GetProcNameForPid(kmsgpid), kmsgpid) 423 424@header("{:<20s} {:<20s} {:<10s} {:>6s} {:<6s}".format( 425 "portset", "waitqueue", "name", "refs", "flags")) 426def PrintPortSetSummary(pset, space=0, verbose=True, O=None): 427 """ Display summary for a given struct ipc_pset * 428 params: 429 pset : core.value representing a pset in the kernel 430 returns: 431 str : string of summary information for the given pset 432 """ 433 show_kmsg_summary = False 434 if config['verbosity'] > vHUMAN : 435 show_kmsg_summary = True 436 437 wqs = Waitq(addressof(pset.ips_wqset)) 438 439 local_name = unsigned(pset.ips_wqset.wqset_index) << 8 440 dest = "-" 441 if space: 442 is_tableval, _ = GetSpaceTable(space) 443 if is_tableval: 444 entry_val = GetObjectAtIndexFromArray(is_tableval, local_name >> 8) 445 local_name |= unsigned(entry_val.ie_bits) >> 24 446 dest = GetSpaceProcDesc(space) 447 else: 448 for wq in wqs.iterateMembers(): 449 dest = GetSpaceProcDesc(wq.asPort().ip_receiver) 450 451 if pset.ips_object.io_bits & 0x80000000: 452 state = "ASet" 453 else: 454 state = "DSet" 455 456 print("{:<#20x} {:<#20x} {:#010x} {:>6d} {:<6s} {:<20s}".format( 457 unsigned(pset), addressof(pset.ips_wqset), local_name, 458 pset.ips_object.io_references, "ASet", dest)) 459 460 if verbose and wqs.hasThreads(): 461 with O.table("{:<20s} {:<20s}".format('waiter', 'event'), indent=True): 462 for thread in wqs.iterateThreads(): 463 print("{:<#20x} {:<#20x}".format(unsigned(thread), thread.wait_event)) 464 print("") 465 466 if verbose and wqs.hasMembers(): 467 with O.table(PrintPortSummary.header, indent=True): 468 for wq in wqs.iterateMembers(): 469 portval = wq.asPort() 470 PrintPortSummary(wq.asPort(), show_kmsg_summary=show_kmsg_summary, O=O) 471 print("") 472 473 474 475# Macro: showipc 476 477@lldb_command('showipc') 478def ShowIPC(cmd_args=None): 479 """ Routine to print data for the given IPC space 480 Usage: showipc <address of ipc space> 481 """ 482 if not cmd_args: 483 print("No arguments passed") 484 print(ShowIPC.__doc__) 485 return False 486 ipc = kern.GetValueFromAddress(cmd_args[0], 'ipc_space *') 487 if not ipc: 488 print("unknown arguments:", str(cmd_args)) 489 return False 490 print(PrintIPCInformation.header) 491 PrintIPCInformation(ipc, False, False) 492 return True 493 494# EndMacro: showipc 495 496# Macro: showtaskipc 497 498@lldb_command('showtaskipc') 499def ShowTaskIPC(cmd_args=None): 500 """ Routine to print IPC summary of given task 501 Usage: showtaskipc <address of task> 502 """ 503 if not cmd_args: 504 print("No arguments passed") 505 print(ShowTaskIPC.__doc__) 506 return False 507 tval = kern.GetValueFromAddress(cmd_args[0], 'task *') 508 if not tval: 509 print("unknown arguments:", str(cmd_args)) 510 return False 511 print(GetTaskSummary.header + " " + GetProcSummary.header) 512 pval = GetProcFromTask(tval) 513 print(GetTaskSummary(tval) + " " + GetProcSummary(pval)) 514 print(GetTaskBusyIPCSummary.header) 515 summary, _, _, _ = GetTaskBusyIPCSummary(tval) 516 print(summary) 517 return True 518 519# EndMacro: showtaskipc 520 521# Macro: showallipc 522 523@lldb_command('showallipc') 524def ShowAllIPC(cmd_args=None): 525 """ Routine to print IPC summary of all tasks 526 Usage: showallipc 527 """ 528 for t in kern.tasks: 529 print(GetTaskSummary.header + " " + GetProcSummary.header) 530 pval = GetProcFromTask(t) 531 print(GetTaskSummary(t) + " " + GetProcSummary(pval)) 532 print(PrintIPCInformation.header) 533 PrintIPCInformation(t.itk_space, False, False) 534 print("\n\n") 535 536# EndMacro: showallipc 537 538@lldb_command('showipcsummary', fancy=True) 539def ShowIPCSummary(cmd_args=None, cmd_options={}, O=None): 540 """ Summarizes the IPC state of all tasks. 541 This is a convenient way to dump some basic clues about IPC messaging. You can use the output to determine 542 tasks that are candidates for further investigation. 543 """ 544 with O.table(GetTaskIPCSummary.header): 545 ipc_table_size = 0 546 547 l = [ GetTaskIPCSummary(t) for t in kern.tasks ] 548 l.sort(key = lambda e: e[1], reverse=True) 549 550 for e in l: 551 print(e[0]) 552 ipc_table_size += e[1] 553 554 for t in kern.terminated_tasks: 555 ipc_table_size += GetTaskIPCSummary(t)[1] 556 557 print("Total Table size: {:d}".format(ipc_table_size)) 558 559def GetKObjectFromPort(portval): 560 """ Get Kobject description from the port. 561 params: portval - core.value representation of 'ipc_port *' object 562 returns: str - string of kobject information 563 """ 564 if not portval or portval == xnudefines.MACH_PORT_DEAD: 565 return "MACH_PORT_DEAD" 566 io_bits = unsigned(portval.ip_object.io_bits) 567 objtype_index = io_bits & 0x3ff 568 569 if not objtype_index: 570 return "not a kobject" 571 572 kobject_addr = kern.StripKernelPAC(unsigned(portval.ip_kobject)) 573 objtype_str = GetEnumName('ipc_kotype_t', objtype_index, "IKOT_") 574 575 desc_str = "{:<#20x} {:<16s}".format(kobject_addr, objtype_str) 576 577 if not kobject_addr: 578 pass 579 580 elif objtype_str == 'IOKIT_OBJECT': 581 iokit_classnm = GetObjectTypeStr(portval.ip_kobject) 582 if not iokit_classnm: 583 desc_str += " <unknown class>" 584 else: 585 desc_str += re.sub(r'vtable for ', r' ', iokit_classnm) 586 587 elif objtype_str[:5] == 'TASK_': 588 task = value(portval.GetSBValue().xCreateValueFromAddress( 589 None, kobject_addr, gettype('struct task')).AddressOf()) 590 if GetProcFromTask(task): 591 desc_str += " {:s}({:d})".format(GetProcNameForTask(task), GetProcPIDForTask(task)) 592 593 return desc_str 594 595def GetSpaceProcDesc(space): 596 """ Display the name and pid of a space's task 597 params: 598 space: core.value representing a pointer to a space 599 returns: 600 str : string containing receiver's name and pid 601 """ 602 task = space.is_task 603 if not GetProcFromTask(task): 604 return "task {:<#20x}".format(unsigned(task)) 605 return "{:s}({:d})".format(GetProcNameForTask(task), GetProcPIDForTask(task)) 606 607def GetPortDestProc(port): 608 """ Display the name and pid of a given port's receiver 609 params: 610 port : core.value representing a pointer to a port in the kernel 611 returns: 612 str : string containing receiver's name and pid 613 """ 614 615 bits = unsigned(port.ip_object.io_bits) # osfmk/ipc/ipc_object.h 616 name = unsigned(port.ip_messages.imq_receiver_name) 617 618 port_is_kobject_port = bits & xnudefines.IO_BITS_KOTYPE 619 620 if bits & xnudefines.IO_BITS_ACTIVE == 0: 621 if port_is_kobject_port: 622 return ('', 'inactive-kobject-port') 623 624 return ('', 'inactive-port') 625 626 if port_is_kobject_port: 627 return ('', GetKObjectFromPort(port)) 628 629 if name == 0: 630 return ('{:<#20x}'.format(port.ip_destination), 'in-transit') 631 632 return ('{:<#20x}'.format(name), GetSpaceProcDesc(port.ip_receiver)) 633 634@header("{:<20s} {:<20s}".format("destname", "destination") ) 635def GetPortDestinationSummary(port): 636 """ Get destination information for a port. 637 params: port - core.value representation of 'ipc_port *' object 638 returns: str - string of info about ports destination 639 """ 640 if not port or port == xnudefines.MACH_PORT_DEAD: 641 return "MACH_PORT_DEAD" 642 a, b = GetPortDestProc(port) 643 return "{:<20s} {:<20s}".format(a, b) 644 645@lldb_type_summary(['ipc_entry_t']) 646@header("{: <20s} {: <12s} {: <8s} {: <8s} {: <8s} {: <8s} {: <20s} {: <20s}".format("object", "name", "rite", "urefs", "nsets", "nmsgs", "destname", "destination")) 647def GetIPCEntrySummary(entry, ipc_name='', rights_filter=0): 648 """ Get summary of a ipc entry. 649 params: 650 entry - core.value representing ipc_entry_t in the kernel 651 ipc_name - str of format '0x0123' for display in summary. 652 returns: 653 str - string of ipc entry related information 654 655 types of rights: 656 'Dead' : Dead name 657 'Set' : Port set 658 'S' : Send right 659 'R' : Receive right 660 'O' : Send-once right 661 'm' : Immovable send port 662 'i' : Immovable receive port 663 'g' : No grant port 664 types of notifications: 665 'd' : Dead-Name notification requested 666 's' : Send-Possible notification armed 667 'r' : Send-Possible notification requested 668 'n' : No-Senders notification requested 669 'x' : Port-destroy notification requested 670 """ 671 out_str = '' 672 entry_ptr = int(hex(entry), 16) 673 format_string = "{: <#20x} {: <12s} {: <8s} {: <8d} {: <8d} {: <8d} {: <20s} {: <20s}" 674 right_str = '' 675 destname_str = '' 676 destination_str = '' 677 678 ie_object = entry.ie_object 679 ie_bits = int(entry.ie_bits) 680 io_bits = int(ie_object.io_bits) if ie_object else 0 681 urefs = int(ie_bits & 0xffff) 682 nsets = 0 683 nmsgs = 0 684 if ie_bits & 0x00100000 : 685 right_str = 'Dead' 686 elif ie_bits & 0x00080000: 687 right_str = 'Set' 688 psetval = kern.CreateTypedPointerFromAddress(unsigned(ie_object), 'struct ipc_pset') 689 wqs = Waitq(addressof(psetval.ips_wqset)) 690 members = 0 691 for m in wqs.iterateMembers(): members += 1 692 destname_str = "{:d} Members".format(members) 693 else: 694 if ie_bits & 0x00010000: 695 if ie_bits & 0x00020000: 696 # SEND + RECV 697 right_str = 'SR' 698 else: 699 # SEND only 700 right_str = 'S' 701 elif ie_bits & 0x00020000: 702 # RECV only 703 right_str = 'R' 704 elif ie_bits & 0x00040000: 705 # SEND_ONCE 706 right_str = 'O' 707 portval = kern.CreateTypedPointerFromAddress(unsigned(ie_object), 'struct ipc_port') 708 if int(entry.ie_request) != 0: 709 requestsval, _ = kalloc_array_decode(portval.ip_requests, 'struct ipc_port_request') 710 sorightval = requestsval[int(entry.ie_request)].ipr_soright 711 soright_ptr = unsigned(sorightval) 712 if soright_ptr != 0: 713 # dead-name notification requested 714 right_str += 'd' 715 # send-possible armed 716 if soright_ptr & 0x1: 717 right_str +='s' 718 # send-possible requested 719 if soright_ptr & 0x2: 720 right_str +='r' 721 # No-senders notification requested 722 if portval.ip_nsrequest != 0: 723 right_str += 'n' 724 # port-destroy notification requested 725 if GetPortPDRequest(portval): 726 right_str += 'x' 727 # Immovable receive rights 728 if portval.ip_immovable_receive != 0: 729 right_str += 'i' 730 # Immovable send rights 731 if portval.ip_immovable_send != 0: 732 right_str += 'm' 733 # No-grant Port 734 if portval.ip_no_grant != 0: 735 right_str += 'g' 736 # Port with SB filtering on 737 if io_bits & 0x00001000 != 0: 738 right_str += 'f' 739 740 # early-out if the rights-filter doesn't match 741 if rights_filter != 0 and rights_filter != right_str: 742 return '' 743 744 # now show the port destination part 745 destname_str = GetPortDestinationSummary(portval) 746 # Get the number of sets to which this port belongs 747 nsets = len([s for s in Waitq(addressof(portval.ip_waitq)).iterateSets()]) 748 nmsgs = portval.ip_messages.imq_msgcount 749 750 # append the generation to the name value 751 # (from osfmk/ipc/ipc_entry.h) 752 # bits rollover period 753 # 0 0 64 754 # 0 1 48 755 # 1 0 32 756 # 1 1 16 757 ie_gen_roll = { 0:'.64', 1:'.48', 2:'.32', 3:'.16' } 758 ipc_name = '{:s}{:s}'.format(ipc_name.strip(), ie_gen_roll[(ie_bits & 0x00c00000) >> 22]) 759 760 if rights_filter == 0 or rights_filter == right_str: 761 out_str = format_string.format(ie_object, ipc_name, right_str, urefs, nsets, nmsgs, destname_str, destination_str) 762 return out_str 763 764@header("{0: >20s}".format("user bt") ) 765def GetPortUserStack(port, task): 766 """ Get UserStack information for the given port & task. 767 params: port - core.value representation of 'ipc_port *' object 768 task - value representing 'task *' object 769 returns: str - string information on port's userstack 770 """ 771 out_str = '' 772 if not port or port == xnudefines.MACH_PORT_DEAD: 773 return out_str 774 pid = port.ip_made_pid 775 proc_val = GetProcFromTask(task) 776 if port.ip_made_bt: 777 btlib = kmemory.BTLibrary.get_shared() 778 out_str += "\n".join(btlib.get_stack(port.ip_made_bt).symbolicated_frames()) + "\n" 779 if pid != GetProcPID(proc_val): 780 out_str += " ({:<10d})\n".format(pid) 781 return out_str 782 783@lldb_type_summary(['ipc_space *']) 784@header("{0: <20s} {1: <20s} {2: <20s} {3: <8s} {4: <10s} {5: >8s} {6: <8s}".format('ipc_space', 'is_task', 'is_table', 'flags', 'ports', 'low_mod', 'high_mod')) 785def PrintIPCInformation(space, show_entries=False, show_userstack=False, rights_filter=0): 786 """ Provide a summary of the ipc space 787 """ 788 out_str = '' 789 format_string = "{0: <#20x} {1: <#20x} {2: <#20x} {3: <8s} {4: <10d} {5: >8d} {6: <8d}" 790 is_tableval, num_entries = GetSpaceTable(space) 791 flags ='' 792 if is_tableval: 793 flags += 'A' 794 else: 795 flags += ' ' 796 if (space.is_grower) != 0: 797 flags += 'G' 798 print(format_string.format(space, space.is_task, is_tableval if is_tableval else 0, flags, 799 num_entries, space.is_low_mod, space.is_high_mod)) 800 801 #should show the each individual entries if asked. 802 if show_entries and is_tableval: 803 print("\t" + GetIPCEntrySummary.header) 804 805 entries = ( 806 (index, value(iep.AddressOf())) 807 for index, iep 808 in GetSpaceEntriesWithBits(is_tableval, num_entries, 0x001f0000) 809 ) 810 811 for index, entryval in entries: 812 entry_ie_bits = unsigned(entryval.ie_bits) 813 entry_name = "{0: <#20x}".format( (index <<8 | entry_ie_bits >> 24) ) 814 entry_str = GetIPCEntrySummary(entryval, entry_name, rights_filter) 815 if not entry_str: 816 continue 817 818 print("\t" + entry_str) 819 if show_userstack: 820 entryport = Cast(entryval.ie_object, 'ipc_port *') 821 if entryval.ie_object and (int(entry_ie_bits) & 0x00070000) and entryport.ip_made_bt: 822 print(GetPortUserStack.header + GetPortUserStack(entryport, space.is_task)) 823 824 #done with showing entries 825 return out_str 826 827# Macro: showrights 828 829@lldb_command('showrights', 'R:') 830def ShowRights(cmd_args=None, cmd_options={}): 831 """ Routine to print rights information for the given IPC space 832 Usage: showrights [-R rights_type] <address of ipc space> 833 -R rights_type : only display rights matching the string 'rights_type' 834 835 types of rights: 836 'Dead' : Dead name 837 'Set' : Port set 838 'S' : Send right 839 'R' : Receive right 840 'O' : Send-once right 841 types of notifications: 842 'd' : Dead-Name notification requested 843 's' : Send-Possible notification armed 844 'r' : Send-Possible notification requested 845 'n' : No-Senders notification requested 846 'x' : Port-destroy notification requested 847 """ 848 if not cmd_args: 849 print("No arguments passed") 850 print(ShowRights.__doc__) 851 return False 852 ipc = kern.GetValueFromAddress(cmd_args[0], 'ipc_space *') 853 if not ipc: 854 print("unknown arguments:", str(cmd_args)) 855 return False 856 rights_type = 0 857 if "-R" in cmd_options: 858 rights_type = cmd_options["-R"] 859 print(PrintIPCInformation.header) 860 PrintIPCInformation(ipc, True, False, rights_type) 861 862# EndMacro: showrights 863 864@lldb_command('showtaskrights','R:') 865def ShowTaskRights(cmd_args=None, cmd_options={}): 866 """ Routine to ipc rights information for a task 867 Usage: showtaskrights [-R rights_type] <task address> 868 -R rights_type : only display rights matching the string 'rights_type' 869 870 types of rights: 871 'Dead' : Dead name 872 'Set' : Port set 873 'S' : Send right 874 'R' : Receive right 875 'O' : Send-once right 876 'm' : Immovable send port 877 'i' : Immovable receive port 878 'g' : No grant port 879 'f' : Port with SB filtering on 880 types of notifications: 881 'd' : Dead-Name notification requested 882 's' : Send-Possible notification armed 883 'r' : Send-Possible notification requested 884 'n' : No-Senders notification requested 885 'x' : Port-destroy notification requested 886 """ 887 if cmd_args is None: 888 print("No arguments passed") 889 print(ShowTaskStacksCmdHelper.__doc__) 890 return False 891 tval = kern.GetValueFromAddress(cmd_args[0], 'task *') 892 if not tval: 893 print("unknown arguments:", str(cmd_args)) 894 return False 895 rights_type = 0 896 if "-R" in cmd_options: 897 rights_type = cmd_options["-R"] 898 print(GetTaskSummary.header + " " + GetProcSummary.header) 899 pval = GetProcFromTask(tval) 900 print(GetTaskSummary(tval) + " " + GetProcSummary(pval)) 901 print(PrintIPCInformation.header) 902 PrintIPCInformation(tval.itk_space, True, False, rights_type) 903 904# Count the vouchers in a given task's ipc space 905@header("{: <20s} {: <6s} {: <20s} {: <8s}".format("task", "pid", "name", "#vouchers")) 906def GetTaskVoucherCount(t): 907 is_tableval, num_entries = GetSpaceTable(t.itk_space) 908 count = 0 909 voucher_kotype = int(GetEnumValue('ipc_kotype_t', 'IKOT_VOUCHER')) 910 911 if is_tableval: 912 ports = GetSpaceObjectsWithBits(is_tableval, num_entries, 0x00070000, 913 gettype('struct ipc_port')) 914 915 for port in ports: 916 io_bits = port.xGetIntegerByPath('.ip_object.io_bits') 917 if io_bits & 0x3ff == voucher_kotype: 918 count += 1 919 920 format_str = "{: <#20x} {: <6d} {: <20s} {: <8d}" 921 pval = GetProcFromTask(t) 922 return format_str.format(t, GetProcPID(pval), GetProcNameForTask(t), count) 923 924# Macro: countallvouchers 925@lldb_command('countallvouchers', fancy=True) 926def CountAllVouchers(cmd_args=None, cmd_options={}, O=None): 927 """ Routine to count the number of vouchers by task. Useful for finding leaks. 928 Usage: countallvouchers 929 """ 930 931 with O.table(GetTaskVoucherCount.header): 932 for t in kern.tasks: 933 print(GetTaskVoucherCount(t)) 934 935# Macro: showataskrightsbt 936 937@lldb_command('showtaskrightsbt', 'R:') 938def ShowTaskRightsBt(cmd_args=None, cmd_options={}): 939 """ Routine to ipc rights information with userstacks for a task 940 Usage: showtaskrightsbt [-R rights_type] <task address> 941 -R rights_type : only display rights matching the string 'rights_type' 942 943 types of rights: 944 'Dead' : Dead name 945 'Set' : Port set 946 'S' : Send right 947 'R' : Receive right 948 'O' : Send-once right 949 'm' : Immovable send port 950 'i' : Immovable receive port 951 'g' : No grant port 952 types of notifications: 953 'd' : Dead-Name notification requested 954 's' : Send-Possible notification armed 955 'r' : Send-Possible notification requested 956 'n' : No-Senders notification requested 957 'x' : Port-destroy notification requested 958 """ 959 if cmd_args is None: 960 print("No arguments passed") 961 print(ShowTaskRightsBt.__doc__) 962 return False 963 tval = kern.GetValueFromAddress(cmd_args[0], 'task *') 964 if not tval: 965 print("unknown arguments:", str(cmd_args)) 966 return False 967 rights_type = 0 968 if "-R" in cmd_options: 969 rights_type = cmd_options["-R"] 970 print(GetTaskSummary.header + " " + GetProcSummary.header) 971 pval = GetProcFromTask(tval) 972 print(GetTaskSummary(tval) + " " + GetProcSummary(pval)) 973 print(PrintIPCInformation.header) 974 PrintIPCInformation(tval.itk_space, True, True, rights_type) 975 976# EndMacro: showtaskrightsbt 977 978# Macro: showallrights 979 980@lldb_command('showallrights', 'R:') 981def ShowAllRights(cmd_args=None, cmd_options={}): 982 """ Routine to print rights information for IPC space of all tasks 983 Usage: showallrights [-R rights_type] 984 -R rights_type : only display rights matching the string 'rights_type' 985 986 types of rights: 987 'Dead' : Dead name 988 'Set' : Port set 989 'S' : Send right 990 'R' : Receive right 991 'O' : Send-once right 992 'm' : Immovable send port 993 'i' : Immovable receive port 994 'g' : No grant port 995 types of notifications: 996 'd' : Dead-Name notification requested 997 's' : Send-Possible notification armed 998 'r' : Send-Possible notification requested 999 'n' : No-Senders notification requested 1000 'x' : Port-destroy notification requested 1001 """ 1002 rights_type = 0 1003 if "-R" in cmd_options: 1004 rights_type = cmd_options["-R"] 1005 for t in kern.tasks: 1006 print(GetTaskSummary.header + " " + GetProcSummary.header) 1007 pval = GetProcFromTask(t) 1008 print(GetTaskSummary(t) + " " + GetProcSummary(pval)) 1009 try: 1010 print(PrintIPCInformation.header) 1011 PrintIPCInformation(t.itk_space, True, False, rights_type) + "\n\n" 1012 except (KeyboardInterrupt, SystemExit): 1013 raise 1014 except: 1015 print("Failed to get IPC information. Do individual showtaskrights <task> to find the error. \n\n") 1016 1017# EndMacro: showallrights 1018 1019 1020def GetInTransitPortSummary(port, disp, holding_port, holding_kmsg): 1021 """ String-ify the in-transit dispostion of a port. 1022 """ 1023 ## This should match the summary generated by GetIPCEntrySummary 1024 ## "object" "name" "rite" "urefs" "nsets" "nmsgs" "destname" "destination" 1025 format_str = "\t{: <#20x} {: <12} {: <8s} {: <8d} {: <8d} {: <8d} p:{: <#19x} k:{: <#19x}" 1026 portname = 'intransit' 1027 1028 disp_str = GetPortDispositionString(disp) 1029 1030 out_str = format_str.format(unsigned(port), 'in-transit', disp_str, 0, 0, port.ip_messages.imq_msgcount, unsigned(holding_port), unsigned(holding_kmsg)) 1031 return out_str 1032 1033 1034def GetDispositionFromEntryType(entry_bits): 1035 """ Translate an IPC entry type into an in-transit disposition. This allows 1036 the GetInTransitPortSummary function to be re-used to string-ify IPC 1037 entry types. 1038 """ 1039 ebits = int(entry_bits) 1040 if (ebits & 0x003f0000) == 0: 1041 return 0 1042 1043 if (ebits & 0x00010000) != 0: 1044 return 17 ## MACH_PORT_RIGHT_SEND 1045 elif (ebits & 0x00020000) != 0: 1046 return 16 ## MACH_PORT_RIGHT_RECEIVE 1047 elif (ebits & 0x00040000) != 0: 1048 return 18 ## MACH_PORT_RIGHT_SEND_ONCE 1049 elif (ebits & 0x00080000) != 0: 1050 return 100 ## MACH_PORT_RIGHT_PORT_SET 1051 elif (ebits & 0x00100000) != 0: 1052 return 101 ## MACH_PORT_RIGHT_DEAD_NAME 1053 elif (ebits & 0x00200000) != 0: 1054 return 102 ## MACH_PORT_RIGHT_LABELH 1055 else: 1056 return 0 1057 1058def GetDispositionFromVoucherPort(th_vport): 1059 """ Translate a thread's voucher port into a 'disposition' 1060 """ 1061 if unsigned(th_vport) > 0: 1062 return 103 ## Voucher type 1063 return 0 1064 1065 1066g_kmsg_prog = 0 1067g_progmeter = { 1068 0 : '*', 1069 1 : '-', 1070 2 : '\\', 1071 3 : '|', 1072 4 : '/', 1073 5 : '-', 1074 6 : '\\', 1075 7 : '|', 1076 8 : '/', 1077} 1078 1079def PrintProgressForKmsg(): 1080 global g_kmsg_prog 1081 global g_progmeter 1082 sys.stderr.write(" {:<1s}\r".format(g_progmeter[g_kmsg_prog % 9])) 1083 g_kmsg_prog += 1 1084 1085 1086def CollectPortsForAnalysis(port, disposition): 1087 """ 1088 """ 1089 if not port or port == xnudefines.MACH_PORT_DEAD: 1090 return 1091 p = Cast(port, 'struct ipc_port *') 1092 yield (p, disposition) 1093 1094 # no-senders notification port 1095 if unsigned(p.ip_nsrequest) not in (0, 1): # 1 is IP_KOBJECT_NSREQUEST_ARMED 1096 PrintProgressForKmsg() 1097 yield (p.ip_nsrequest, -1) 1098 1099 # port-death notification port 1100 pdrequest = GetPortPDRequest(p) 1101 if pdrequest: 1102 PrintProgressForKmsg() 1103 yield (pdrequest, -2) 1104 1105 ## ports can have many send-possible notifications armed: go through the table! 1106 if unsigned(p.ip_requests) != 0: 1107 table, table_sz = kalloc_array_decode(p.ip_requests, 'struct ipc_port_request') 1108 for i in range(table_sz): 1109 if i == 0: 1110 continue 1111 ipr = table[i] 1112 if unsigned(ipr.ipr_name) in (0, 0xfffffffe): 1113 # 0xfffffffe is a host notify request 1114 continue 1115 ipr_bits = unsigned(ipr.ipr_soright) & 3 1116 ipr_port = kern.GetValueFromAddress(int(ipr.ipr_soright) & ~3, 'struct ipc_port *') 1117 ipr_disp = 0 1118 if ipr_bits & 3: ## send-possible armed and requested 1119 ipr_disp = -5 1120 elif ipr_bits & 2: ## send-possible requested 1121 ipr_disp = -4 1122 elif ipr_bits & 1: ## send-possible armed 1123 ipr_disp = -3 1124 PrintProgressForKmsg() 1125 yield (ipr_port, ipr_disp) 1126 return 1127 1128def CollectKmsgPorts(task, task_port, kmsgp): 1129 """ Look through a message, 'kmsgp' destined for 'task' 1130 (enqueued on task_port). Collect any port descriptors, 1131 remote, local, voucher, or other port references 1132 into a (ipc_port_t, disposition) list. 1133 """ 1134 kmsgh = dereference(GetKmsgHeader(kmsgp)) 1135 1136 p_list = [] 1137 1138 PrintProgressForKmsg() 1139 if kmsgh.msgh_remote_port and unsigned(kmsgh.msgh_remote_port) != unsigned(task_port): 1140 disp = kmsgh.msgh_bits & 0x1f 1141 p_list += list(CollectPortsForAnalysis(kmsgh.msgh_remote_port, disp)) 1142 1143 if kmsgh.msgh_local_port and unsigned(kmsgh.msgh_local_port) != unsigned(task_port) \ 1144 and unsigned(kmsgh.msgh_local_port) != unsigned(kmsgh.msgh_remote_port): 1145 disp = (kmsgh.msgh_bits & 0x1f00) >> 8 1146 p_list += list(CollectPortsForAnalysis(kmsgh.msgh_local_port, disp)) 1147 1148 if kmsgp.ikm_voucher_port: 1149 p_list += list(CollectPortsForAnalysis(kmsgp.ikm_voucher_port, 0)) 1150 1151 if kmsgh.msgh_bits & 0x80000000: 1152 ## Complex message - look for descriptors 1153 PrintProgressForKmsg() 1154 (body, dschead, dsc_list) = GetKmsgDescriptors(kmsgp) 1155 for dsc in dsc_list: 1156 PrintProgressForKmsg() 1157 dsc_type = unsigned(dsc.type.type) 1158 if dsc_type == 0 or dsc_type == 2: ## 0 == port, 2 == ool port 1159 if dsc_type == 0: 1160 ## its a port descriptor 1161 dsc_disp = dsc.port.disposition 1162 p_list += list(CollectPortsForAnalysis(dsc.port.name, dsc_disp)) 1163 else: 1164 ## it's an ool_ports descriptor which is an array of ports 1165 dsc_disp = dsc.ool_ports.disposition 1166 dispdata = Cast(dsc.ool_ports.address, 'struct ipc_port *') 1167 for pidx in range(dsc.ool_ports.count): 1168 PrintProgressForKmsg() 1169 p_list += list(CollectPortsForAnalysis(dispdata[pidx], dsc_disp)) 1170 return p_list 1171 1172def CollectKmsgPortRefs(task, task_port, kmsgp, p_refs): 1173 """ Recursively collect all references to ports inside the kmsg 'kmsgp' 1174 into the set 'p_refs' 1175 """ 1176 p_list = CollectKmsgPorts(task, task_port, kmsgp) 1177 1178 ## Iterate over each ports we've collected, to see if they 1179 ## have messages on them, and then recurse! 1180 for p, pdisp in p_list: 1181 ptype = (p.ip_object.io_bits & 0x7fff0000) >> 16 1182 p_refs.add((p, pdisp, ptype)) 1183 if ptype != 0: ## don't bother with port sets 1184 continue 1185 ## If the port that's in-transit has messages already enqueued, 1186 ## go through each of those messages and look for more ports! 1187 for p_kmsgp in IterateCircleQueue(p.ip_messages.imq_messages, 'ipc_kmsg', 'ikm_link'): 1188 CollectKmsgPortRefs(task, p, p_kmsgp, p_refs) 1189 1190 1191def FindKmsgPortRefs(instr, task, task_port, kmsgp, qport): 1192 """ Look through a message, 'kmsgp' destined for 'task'. If we find 1193 any port descriptors, remote, local, voucher, or other port that 1194 matches 'qport', return a short description 1195 which should match the format of GetIPCEntrySummary. 1196 """ 1197 1198 out_str = instr 1199 p_list = CollectKmsgPorts(task, task_port, kmsgp) 1200 1201 ## Run through all ports we've collected looking for 'qport' 1202 for p, pdisp in p_list: 1203 PrintProgressForKmsg() 1204 if unsigned(p) == unsigned(qport): 1205 ## the port we're looking for was found in this message! 1206 if len(out_str) > 0: 1207 out_str += '\n' 1208 out_str += GetInTransitPortSummary(p, pdisp, task_port, kmsgp) 1209 1210 ptype = (p.ip_object.io_bits & 0x7fff0000) >> 16 1211 if ptype != 0: ## don't bother with port sets 1212 continue 1213 1214 ## If the port that's in-transit has messages already enqueued, 1215 ## go through each of those messages and look for more ports! 1216 for p_kmsgp in IterateCircleQueue(p.ip_messages.imq_messages, 'ipc_kmsg', 'ikm_link'): 1217 out_str = FindKmsgPortRefs(out_str, task, p, p_kmsgp, qport) 1218 1219 return out_str 1220 1221 1222port_iteration_do_print_taskname = False 1223registeredport_idx = -10 1224excports_idx = -20 1225intransit_idx = -1000 1226taskports_idx = -2000 1227thports_idx = -3000 1228 1229def IterateAllPorts(tasklist, func, ctx, include_psets, follow_busyports, should_log): 1230 """ Iterate over all ports in the system, calling 'func' 1231 for each entry in 1232 """ 1233 global port_iteration_do_print_taskname 1234 global intransit_idx, taskports_idx, thports_idx, registeredport_idx, excports_idx 1235 1236 ## XXX: also host special ports 1237 1238 entry_port_type_mask = 0x00070000 1239 if include_psets: 1240 entry_port_type_mask = 0x000f0000 1241 1242 if tasklist is None: 1243 tasklist = list(kern.tasks) 1244 tasklist += list(kern.terminated_tasks) 1245 1246 tidx = 1 1247 1248 for t in tasklist: 1249 # Write a progress line. Using stderr avoids automatic newline when 1250 # writing to stdout from lldb. Blank spaces at the end clear out long 1251 # lines. 1252 if should_log: 1253 procname = "" 1254 if not t.active: 1255 procname = 'terminated: ' 1256 if t.halting: 1257 procname += 'halting: ' 1258 procname += GetProcNameForTask(t) 1259 sys.stderr.write(" checking {:s} ({}/{})...{:50s}\r".format(procname, tidx, len(tasklist), '')) 1260 tidx += 1 1261 1262 port_iteration_do_print_taskname = True 1263 space = t.itk_space 1264 is_tableval, num_entries = GetSpaceTable(space) 1265 1266 if not is_tableval: 1267 continue 1268 1269 base = is_tableval.GetSBValue().Dereference() 1270 entries = ( 1271 value(iep.AddressOf()) 1272 for iep in base.xIterSiblings(1, num_entries) 1273 ) 1274 1275 for idx, entry_val in enumerate(entries, 1): 1276 entry_bits= unsigned(entry_val.ie_bits) 1277 entry_obj = 0 1278 entry_str = '' 1279 entry_name = "{:x}".format( (idx << 8 | entry_bits >> 24) ) 1280 1281 entry_disp = GetDispositionFromEntryType(entry_bits) 1282 1283 ## If the entry in the table represents a port of some sort, 1284 ## then make the callback provided 1285 if int(entry_bits) & entry_port_type_mask: 1286 eport = kern.CreateTypedPointerFromAddress(unsigned(entry_val.ie_object), 'struct ipc_port') 1287 ## Make the callback 1288 func(t, space, ctx, idx, entry_val, eport, entry_disp) 1289 1290 ## if the port has pending messages, look through 1291 ## each message for ports (and recurse) 1292 if follow_busyports and unsigned(eport) > 0 and eport.ip_messages.imq_msgcount > 0: 1293 ## collect all port references from all messages 1294 for kmsgp in IterateCircleQueue(eport.ip_messages.imq_messages, 'ipc_kmsg', 'ikm_link'): 1295 p_refs = set() 1296 CollectKmsgPortRefs(t, eport, kmsgp, p_refs) 1297 for (port, pdisp, ptype) in p_refs: 1298 func(t, space, ctx, intransit_idx, None, port, pdisp) 1299 ## for idx in xrange(1, num_entries) 1300 1301 ## Task ports (send rights) 1302 if unsigned(t.itk_settable_self) > 0: 1303 func(t, space, ctx, taskports_idx, 0, t.itk_settable_self, 17) 1304 if unsigned(t.itk_host) > 0: 1305 func(t, space, ctx, taskports_idx, 0, t.itk_host, 17) 1306 if unsigned(t.itk_bootstrap) > 0: 1307 func(t, space, ctx, taskports_idx, 0, t.itk_bootstrap, 17) 1308 if unsigned(t.itk_debug_control) > 0: 1309 func(t, space, ctx, taskports_idx, 0, t.itk_debug_control, 17) 1310 if unsigned(t.itk_task_access) > 0: 1311 func(t, space, ctx, taskports_idx, 0, t.itk_task_access, 17) 1312 if unsigned(t.itk_task_ports[1]) > 0: ## task read port 1313 func(t, space, ctx, taskports_idx, 0, t.itk_task_ports[1], 17) 1314 if unsigned(t.itk_task_ports[2]) > 0: ## task inspect port 1315 func(t, space, ctx, taskports_idx, 0, t.itk_task_ports[2], 17) 1316 1317 ## Task name port (not a send right, just a naked ref); TASK_FLAVOR_NAME = 3 1318 if unsigned(t.itk_task_ports[3]) > 0: 1319 func(t, space, ctx, taskports_idx, 0, t.itk_task_ports[3], 0) 1320 1321 ## task resume port is a receive right to resume the task 1322 if unsigned(t.itk_resume) > 0: 1323 func(t, space, ctx, taskports_idx, 0, t.itk_resume, 16) 1324 1325 ## registered task ports (all send rights) 1326 tr_idx = 0 1327 tr_max = sizeof(t.itk_registered) // sizeof(t.itk_registered[0]) 1328 while tr_idx < tr_max: 1329 tport = t.itk_registered[tr_idx] 1330 if unsigned(tport) > 0: 1331 try: 1332 func(t, space, ctx, registeredport_idx, 0, tport, 17) 1333 except Exception as e: 1334 print("\texception looking through registered port {:d}/{:d} in {:s}".format(tr_idx,tr_max,t)) 1335 pass 1336 tr_idx += 1 1337 1338 ## Task exception ports 1339 exidx = 0 1340 exmax = sizeof(t.exc_actions) // sizeof(t.exc_actions[0]) 1341 while exidx < exmax: ## see: osfmk/mach/[arm|i386]/exception.h 1342 export = t.exc_actions[exidx].port ## send right 1343 if unsigned(export) > 0: 1344 try: 1345 func(t, space, ctx, excports_idx, 0, export, 17) 1346 except Exception as e: 1347 print("\texception looking through exception port {:d}/{:d} in {:s}".format(exidx,exmax,t)) 1348 pass 1349 exidx += 1 1350 1351 ## XXX: any ports still valid after clearing IPC space?! 1352 1353 for thval in IterateQueue(t.threads, 'thread *', 'task_threads'): 1354 ## XXX: look at block reason to see if it's in mach_msg_receive - then look at saved state / message 1355 1356 ## Thread port (send right) 1357 if unsigned(thval.t_tro.tro_settable_self_port) > 0: 1358 thport = thval.t_tro.tro_settable_self_port 1359 func(t, space, ctx, thports_idx, 0, thport, 17) ## see: osfmk/mach/message.h 1360 ## Thread special reply port (send-once right) 1361 if unsigned(thval.ith_special_reply_port) > 0: 1362 thport = thval.ith_special_reply_port 1363 func(t, space, ctx, thports_idx, 0, thport, 18) ## see: osfmk/mach/message.h 1364 ## Thread voucher port 1365 if unsigned(thval.ith_voucher) > 0: 1366 vport = thval.ith_voucher.iv_port 1367 if unsigned(vport) > 0: 1368 vdisp = GetDispositionFromVoucherPort(vport) 1369 func(t, space, ctx, thports_idx, 0, vport, vdisp) 1370 ## Thread exception ports 1371 if unsigned(thval.t_tro.tro_exc_actions) > 0: 1372 exidx = 0 1373 while exidx < exmax: ## see: osfmk/mach/[arm|i386]/exception.h 1374 export = thval.t_tro.tro_exc_actions[exidx].port ## send right 1375 if unsigned(export) > 0: 1376 try: 1377 func(t, space, ctx, excports_idx, 0, export, 17) 1378 except Exception as e: 1379 print("\texception looking through exception port {:d}/{:d} in {:s}".format(exidx,exmax,t)) 1380 pass 1381 exidx += 1 1382 ## XXX: the message on a thread (that's currently being received) 1383 ## for (thval in t.threads) 1384 ## for (t in tasklist) 1385 1386 1387# Macro: findportrights 1388def FindPortRightsCallback(task, space, ctx, entry_idx, ipc_entry, ipc_port, port_disp): 1389 """ Callback which uses 'ctx' as the (port,rights_types) tuple for which 1390 a caller is seeking references. This should *not* be used from a 1391 recursive call to IterateAllPorts. 1392 """ 1393 global port_iteration_do_print_taskname 1394 1395 (qport, rights_type) = ctx 1396 entry_name = '' 1397 entry_str = '' 1398 if unsigned(ipc_entry) != 0: 1399 entry_bits = unsigned(ipc_entry.ie_bits) 1400 entry_name = "{:x}".format( (entry_idx << 8 | entry_bits >> 24) ) 1401 if (int(entry_bits) & 0x001f0000) != 0 and unsigned(ipc_entry.ie_object) == unsigned(qport): 1402 ## it's a valid entry, and it points to the port 1403 entry_str = '\t' + GetIPCEntrySummary(ipc_entry, entry_name, rights_type) 1404 1405 procname = GetProcNameForTask(task) 1406 if ipc_port and ipc_port != xnudefines.MACH_PORT_DEAD and ipc_port.ip_messages.imq_msgcount > 0: 1407 sys.stderr.write(" checking {:s} busy-port {}:{:#x}...{:30s}\r".format(procname, entry_name, unsigned(ipc_port), '')) 1408 ## Search through busy ports to find descriptors which could 1409 ## contain the only reference to this port! 1410 for kmsgp in IterateCircleQueue(ipc_port.ip_messages.imq_messages, 'ipc_kmsg', 'ikm_link'): 1411 entry_str = FindKmsgPortRefs(entry_str, task, ipc_port, kmsgp, qport) 1412 1413 if len(entry_str) > 0: 1414 sys.stderr.write("{:80s}\r".format('')) 1415 if port_iteration_do_print_taskname: 1416 print("Task: {0: <#x} {1: <s}".format(task, procname)) 1417 print('\t' + GetIPCEntrySummary.header) 1418 port_iteration_do_print_taskname = False 1419 print(entry_str) 1420 1421@lldb_command('findportrights', 'R:S:') 1422def FindPortRights(cmd_args=None, cmd_options={}): 1423 """ Routine to locate and print all extant rights to a given port 1424 Usage: findportrights [-R rights_type] [-S <ipc_space_t>] <ipc_port_t> 1425 -S ipc_space : only search the specified ipc space 1426 -R rights_type : only display rights matching the string 'rights_type' 1427 1428 types of rights: 1429 'Dead' : Dead name 1430 'Set' : Port set 1431 'S' : Send right 1432 'R' : Receive right 1433 'O' : Send-once right 1434 types of notifications: 1435 'd' : Dead-Name notification requested 1436 's' : Send-Possible notification armed 1437 'r' : Send-Possible notification requested 1438 'n' : No-Senders notification requested 1439 'x' : Port-destroy notification requested 1440 """ 1441 if not cmd_args: 1442 raise ArgumentError("no port address provided") 1443 port = kern.GetValueFromAddress(cmd_args[0], 'struct ipc_port *') 1444 1445 rights_type = 0 1446 if "-R" in cmd_options: 1447 rights_type = cmd_options["-R"] 1448 1449 tasklist = None 1450 if "-S" in cmd_options: 1451 space = kern.GetValueFromAddress(cmd_options["-S"], 'struct ipc_space *') 1452 tasklist = [ space.is_task ] 1453 1454 ## Don't include port sets 1455 ## Don't recurse on busy ports (we do that manually) 1456 ## DO log progress 1457 IterateAllPorts(tasklist, FindPortRightsCallback, (port, rights_type), False, False, True) 1458 sys.stderr.write("{:120s}\r".format(' ')) 1459 1460 print("Done.") 1461# EndMacro: findportrights 1462 1463# Macro: countallports 1464 1465def CountPortsCallback(task, space, ctx, entry_idx, ipc_entry, ipc_port, port_disp): 1466 """ Callback which uses 'ctx' as the set of all ports found in the 1467 iteration. This should *not* be used from a recursive 1468 call to IterateAllPorts. 1469 """ 1470 global intransit_idx 1471 1472 (p_set, p_intransit, p_bytask) = ctx 1473 1474 ## Add the port address to the set of all port addresses 1475 p_set.add(unsigned(ipc_port)) 1476 1477 if entry_idx == intransit_idx: 1478 p_intransit.add(unsigned(ipc_port)) 1479 1480 if task.active or (task.halting and not task.active): 1481 pname = GetProcNameForTask(task) 1482 if not pname in p_bytask: 1483 p_bytask[pname] = { 'transit':0, 'table':0, 'other':0 } 1484 if entry_idx == intransit_idx: 1485 p_bytask[pname]['transit'] += 1 1486 elif entry_idx >= 0: 1487 p_bytask[pname]['table'] += 1 1488 else: 1489 p_bytask[pname]['other'] += 1 1490 1491 1492@lldb_command('countallports', 'P') 1493def CountAllPorts(cmd_args=None, cmd_options={}): 1494 """ Routine to search for all as many references to ipc_port structures in the kernel 1495 that we can find. 1496 Usage: countallports [-P] 1497 -P : include port sets in the count (default: NO) 1498 """ 1499 p_set = set() 1500 p_intransit = set() 1501 p_bytask = {} 1502 1503 find_psets = False 1504 if "-P" in cmd_options: 1505 find_psets = True 1506 1507 ## optionally include port sets 1508 ## DO recurse on busy ports 1509 ## DO log progress 1510 IterateAllPorts(None, CountPortsCallback, (p_set, p_intransit, p_bytask), find_psets, True, True) 1511 sys.stderr.write("{:120s}\r".format(' ')) 1512 1513 print("Total ports found: {:d}".format(len(p_set))) 1514 print("In Transit: {:d}".format(len(p_intransit))) 1515 print("By Task:") 1516 for pname in sorted(p_bytask.keys()): 1517 count = p_bytask[pname] 1518 print("\t{: <20s}: table={: <5d}, transit={: <5d}, other={: <5d}".format(pname, count['table'], count['transit'], count['other'])) 1519# EndMacro: countallports 1520# Macro: showpipestats 1521 1522@lldb_command('showpipestats') 1523def ShowPipeStats(cmd_args=None): 1524 """ Display pipes usage information in the kernel 1525 """ 1526 print("Number of pipes: {: d}".format(kern.globals.amountpipes)) 1527 print("Memory used by pipes: {:s}".format(sizeof_fmt(int(kern.globals.amountpipekva)))) 1528 print("Max memory allowed for pipes: {:s}".format(sizeof_fmt(int(kern.globals.maxpipekva)))) 1529 1530# EndMacro: showpipestats 1531# Macro: showtaskbusyports 1532 1533@lldb_command('showtaskbusyports', fancy=True) 1534def ShowTaskBusyPorts(cmd_args=None, cmd_options={}, O=None): 1535 """ Routine to print information about receive rights belonging to this task that 1536 have enqueued messages. This is often a sign of a blocked or hung process 1537 Usage: showtaskbusyports <task address> 1538 """ 1539 if not cmd_args: 1540 print("No arguments passed. Please pass in the address of a task") 1541 print(ShowTaskBusyPorts.__doc__) 1542 return 1543 task = kern.GetValueFromAddress(cmd_args[0], 'task_t') 1544 is_tableval, num_entries = GetSpaceTable(task.itk_space) 1545 1546 if is_tableval: 1547 ports = GetSpaceObjectsWithBits(is_tableval, num_entries, 0x00020000, 1548 gettype('struct ipc_port')) 1549 1550 with O.table(PrintPortSummary.header): 1551 for port in ports: 1552 if port.xGetIntegerByPath('.ip_messages.imq_msgcount'): 1553 PrintPortSummary(value(port.AddressOf()), O=O) 1554 1555# EndMacro: showtaskbusyports 1556# Macro: showallbusyports 1557 1558@lldb_command('showallbusyports', fancy=True) 1559def ShowAllBusyPorts(cmd_args=None, cmd_options={}, O=None): 1560 """ Routine to print information about all receive rights on the system that 1561 have enqueued messages. 1562 """ 1563 with O.table(PrintPortSummary.header): 1564 port_ty = gettype("struct ipc_port") 1565 for port in kmemory.Zone("ipc ports").iter_allocated(port_ty): 1566 if port.xGetIntegerByPath('.ip_messages.imq_msgcount') > 0: 1567 PrintPortSummary(value(port.AddressOf()), O=O) 1568 1569# EndMacro: showallbusyports 1570# Macro: showallports 1571 1572@lldb_command('showallports', fancy=True) 1573def ShowAllPorts(cmd_args=None, cmd_options={}, O=None): 1574 """ Routine to print information about all allocated ports in the system 1575 1576 usage: showallports 1577 """ 1578 with O.table(PrintPortSummary.header): 1579 port_ty = gettype("struct ipc_port") 1580 for port in kmemory.Zone("ipc ports").iter_allocated(port_ty): 1581 PrintPortSummary(value(port.AddressOf()), show_kmsg_summary=False, O=O) 1582 1583# EndMacro: showallports 1584# Macro: findkobjectport 1585 1586@lldb_command('findkobjectport', fancy=True) 1587def FindKobjectPort(cmd_args=None, cmd_options={}, O=None): 1588 """ Locate all ports pointing to a given kobject 1589 1590 usage: findkobjectport <kobject-addr> 1591 """ 1592 1593 kobj_addr = unsigned(kern.GetValueFromAddress(cmd_args[0])) 1594 kmem = kmemory.KMem.get_shared() 1595 port_ty = gettype("struct ipc_port") 1596 1597 with O.table(PrintPortSummary.header): 1598 for port in kmemory.Zone("ipc ports").iter_allocated(port_ty): 1599 if port.xGetIntegerByPath('.ip_object.io_bits') & 0x3ff == 0: 1600 continue 1601 1602 ip_kobject = kmem.make_address(port.xGetScalarByName('ip_kobject')) 1603 if ip_kobject == kobj_addr: 1604 PrintPortSummary(value(port.AddressOf()), show_kmsg_summary=False, O=O) 1605 1606# EndMacro: findkobjectport 1607# Macro: showtaskbusypsets 1608 1609@lldb_command('showtaskbusypsets', fancy=True) 1610def ShowTaskBusyPortSets(cmd_args=None, cmd_options={}, O=None): 1611 """ Routine to print information about port sets belonging to this task that 1612 have enqueued messages. This is often a sign of a blocked or hung process 1613 Usage: showtaskbusypsets <task address> 1614 """ 1615 if not cmd_args: 1616 print("No arguments passed. Please pass in the address of a task") 1617 print(ShowTaskBusyPortsSets.__doc__) 1618 return 1619 task = kern.GetValueFromAddress(cmd_args[0], 'task_t') 1620 is_tableval, num_entries = GetSpaceTable(task.itk_space) 1621 1622 if is_tableval: 1623 psets = GetSpaceObjectsWithBits(is_tableval, num_entries, 0x00080000, 1624 gettype('struct ipc_pset')) 1625 1626 with O.table(PrintPortSetSummary.header): 1627 for pset in (value(v.AddressOf()) for v in psets): 1628 for wq in Waitq(addressof(pset.ips_wqset)).iterateMembers(): 1629 if wq.asPort().ip_messages.imq_msgcount > 0: 1630 PrintPortSetSummary(pset, space=task.itk_space, O=O) 1631 1632# EndMacro: showtaskbusyports 1633# Macro: showallbusypsets 1634 1635@lldb_command('showallbusypsets', fancy=True) 1636def ShowAllBusyPortSets(cmd_args=None, cmd_options={}, O=None): 1637 """ Routine to print information about all port sets on the system that 1638 have enqueued messages. 1639 """ 1640 with O.table(PrintPortSetSummary.header): 1641 pset_ty = gettype("struct ipc_pset") 1642 for pset in kmemory.Zone("ipc port sets").iter_allocated(pset_ty): 1643 pset = value(pset.AddressOf()) 1644 for wq in Waitq(addressof(pset.ips_wqset)).iterateMembers(): 1645 port = wq.asPort() 1646 if port.ip_messages.imq_msgcount > 0: 1647 PrintPortSetSummary(pset, space=port.ip_receiver, O=O) 1648 1649# EndMacro: showallbusyports 1650# Macro: showallpsets 1651 1652@lldb_command('showallpsets', fancy=True) 1653def ShowAllPortSets(cmd_args=None, cmd_options={}, O=None): 1654 """ Routine to print information about all allocated psets in the system 1655 1656 usage: showallpsets 1657 """ 1658 with O.table(PrintPortSetSummary.header): 1659 pset_ty = gettype("struct ipc_pset") 1660 for pset in kmemory.Zone("ipc port sets").iter_allocated(pset_ty): 1661 PrintPortSetSummary(value(pset.AddressOf()), O=O) 1662 1663# EndMacro: showallports 1664# Macro: showbusyportsummary 1665 1666@lldb_command('showbusyportsummary') 1667def ShowBusyPortSummary(cmd_args=None): 1668 """ Routine to print a summary of information about all receive rights 1669 on the system that have enqueued messages. 1670 """ 1671 task_queue_head = kern.globals.tasks 1672 1673 ipc_table_size = 0 1674 ipc_busy_ports = 0 1675 ipc_msgs = 0 1676 1677 print(GetTaskBusyIPCSummary.header) 1678 for tsk in kern.tasks: 1679 (summary, table_size, nbusy, nmsgs) = GetTaskBusyIPCSummary(tsk) 1680 ipc_table_size += table_size 1681 ipc_busy_ports += nbusy 1682 ipc_msgs += nmsgs 1683 print(summary) 1684 for t in kern.terminated_tasks: 1685 (summary, table_size, nbusy, nmsgs) = GetTaskBusyIPCSummary(tsk) 1686 ipc_table_size += table_size 1687 ipc_busy_ports += nbusy 1688 ipc_msgs += nmsgs 1689 print(summary) 1690 print("Total Table Size: {:d}, Busy Ports: {:d}, Messages in-flight: {:d}".format(ipc_table_size, ipc_busy_ports, ipc_msgs)) 1691 return 1692 1693# EndMacro: showbusyportsummary 1694# Macro: showport / showpset 1695 1696def ShowPortOrPset(obj, space=0, O=None): 1697 """ Routine that lists details about a given IPC port or pset 1698 Syntax: (lldb) showport 0xaddr 1699 """ 1700 if not obj or obj == xnudefines.IPC_OBJECT_DEAD: 1701 print("IPC_OBJECT_DEAD") 1702 return 1703 1704 otype = (obj.io_bits & 0x7fff0000) >> 16 1705 if otype == 0: # IOT_PORT 1706 with O.table(PrintPortSummary.header): 1707 PrintPortSummary(cast(obj, 'ipc_port_t'), show_sets=True, O=O) 1708 elif otype == 1: # IOT_PSET 1709 with O.table(PrintPortSetSummary.header): 1710 PrintPortSetSummary(cast(obj, 'ipc_pset_t'), space, O=O) 1711 1712@lldb_command('showport', 'K', fancy=True) 1713def ShowPort(cmd_args=None, cmd_options={}, O=None): 1714 """ Routine that lists details about a given IPC port 1715 1716 usage: showport <address> 1717 """ 1718 # -K is default and kept for backward compat, it used to mean "show kmsg queue" 1719 if not cmd_args: 1720 return O.error("Missing port argument") 1721 obj = kern.GetValueFromAddress(cmd_args[0], 'struct ipc_object *') 1722 ShowPortOrPset(obj, O=O) 1723 1724@lldb_command('showpset', "S:", fancy=True) 1725def ShowPSet(cmd_args=None, cmd_options={}, O=None): 1726 """ Routine that prints details for a given ipc_pset * 1727 1728 usage: showpset [-S <space>] <address> 1729 """ 1730 if not cmd_args: 1731 return O.error("Missing port argument") 1732 space = 0 1733 if "-S" in cmd_options: 1734 space = kern.GetValueFromAddress(cmd_options["-S"], 'struct ipc_space *') 1735 obj = kern.GetValueFromAddress(cmd_args[0], 'struct ipc_object *') 1736 ShowPortOrPset(obj, space=space, O=O) 1737 1738# EndMacro: showport / showpset 1739# Macro: showkmsg: 1740 1741@lldb_command('showkmsg') 1742def ShowKMSG(cmd_args=[]): 1743 """ Show detail information about a <ipc_kmsg_t> structure 1744 Usage: (lldb) showkmsg <ipc_kmsg_t> 1745 """ 1746 if not cmd_args: 1747 raise ArgumentError('Invalid arguments') 1748 kmsg = kern.GetValueFromAddress(cmd_args[0], 'ipc_kmsg_t') 1749 print(GetKMsgSummary.header) 1750 print(GetKMsgSummary(kmsg)) 1751 1752# EndMacro: showkmsg 1753# IPC importance inheritance related macros. 1754 1755@lldb_command('showalliits') 1756def ShowAllIITs(cmd_args=[], cmd_options={}): 1757 """ Development only macro. Show list of all iits allocated in the system. """ 1758 try: 1759 iit_queue = kern.globals.global_iit_alloc_queue 1760 except ValueError: 1761 print("This debug macro is only available in development or debug kernels") 1762 return 1763 1764 print(GetIPCImportantTaskSummary.header) 1765 for iit in IterateQueue(iit_queue, 'struct ipc_importance_task *', 'iit_allocation'): 1766 print(GetIPCImportantTaskSummary(iit)) 1767 return 1768 1769@header("{: <18s} {: <3s} {: <18s} {: <32s} {: <18s} {: <8s}".format("ipc_imp_inherit", "don", "to_task", "proc_name", "from_elem", "depth")) 1770@lldb_type_summary(['ipc_importance_inherit *', 'ipc_importance_inherit_t']) 1771def GetIPCImportanceInheritSummary(iii): 1772 """ describes iii object of type ipc_importance_inherit_t * """ 1773 out_str = "" 1774 fmt = "{o: <#18x} {don: <3s} {o.iii_to_task.iit_task: <#18x} {task_name: <20s} {o.iii_from_elem: <#18x} {o.iii_depth: <#8x}" 1775 donating_str = "" 1776 if unsigned(iii.iii_donating): 1777 donating_str = "DON" 1778 taskname = GetProcNameForTask(iii.iii_to_task.iit_task) 1779 if hasattr(iii.iii_to_task, 'iit_bsd_pid'): 1780 taskname = "({:d}) {:s}".format(iii.iii_to_task.iit_bsd_pid, iii.iii_to_task.iit_procname) 1781 out_str += fmt.format(o=iii, task_name = taskname, don=donating_str) 1782 return out_str 1783 1784@static_var('recursion_count', 0) 1785@header("{: <18s} {: <4s} {: <8s} {: <8s} {: <18s} {: <18s}".format("iie", "type", "refs", "made", "#kmsgs", "#inherits")) 1786@lldb_type_summary(['ipc_importance_elem *']) 1787def GetIPCImportanceElemSummary(iie): 1788 """ describes an ipc_importance_elem * object """ 1789 1790 if GetIPCImportanceElemSummary.recursion_count > 500: 1791 GetIPCImportanceElemSummary.recursion_count = 0 1792 return "Recursion of 500 reached" 1793 1794 out_str = '' 1795 fmt = "{: <#18x} {: <4s} {: <8d} {: <8d} {: <#18x} {: <#18x}" 1796 if unsigned(iie.iie_bits) & xnudefines.IIE_TYPE_MASK: 1797 type_str = "INH" 1798 inherit_count = 0 1799 else: 1800 type_str = 'TASK' 1801 iit = Cast(iie, 'struct ipc_importance_task *') 1802 inherit_count = sum(1 for i in IterateQueue(iit.iit_inherits, 'struct ipc_importance_inherit *', 'iii_inheritance')) 1803 1804 refs = unsigned(iie.iie_bits) >> xnudefines.IIE_TYPE_BITS 1805 made_refs = unsigned(iie.iie_made) 1806 kmsg_count = sum(1 for i in IterateQueue(iie.iie_kmsgs, 'struct ipc_kmsg *', 'ikm_inheritance')) 1807 out_str += fmt.format(iie, type_str, refs, made_refs, kmsg_count, inherit_count) 1808 if config['verbosity'] > vHUMAN: 1809 if kmsg_count > 0: 1810 out_str += "\n\t"+ GetKMsgSummary.header 1811 for k in IterateQueue(iie.iie_kmsgs, 'struct ipc_kmsg *', 'ikm_inheritance'): 1812 out_str += "\t" + "{: <#18x}".format(GetKmsgHeader(k).msgh_remote_port) + ' ' + GetKMsgSummary(k, "\t").lstrip() 1813 out_str += "\n" 1814 if inherit_count > 0: 1815 out_str += "\n\t" + GetIPCImportanceInheritSummary.header + "\n" 1816 for i in IterateQueue(iit.iit_inherits, 'struct ipc_importance_inherit *', 'iii_inheritance'): 1817 out_str += "\t" + GetIPCImportanceInheritSummary(i) + "\n" 1818 out_str += "\n" 1819 if type_str == "INH": 1820 iii = Cast(iie, 'struct ipc_importance_inherit *') 1821 out_str += "Inherit from: " + GetIPCImportanceElemSummary(iii.iii_from_elem) 1822 1823 return out_str 1824 1825@header("{: <18s} {: <18s} {: <32}".format("iit", "task", "name")) 1826@lldb_type_summary(['ipc_importance_task *']) 1827def GetIPCImportantTaskSummary(iit): 1828 """ iit is a ipc_importance_task value object. 1829 """ 1830 fmt = "{: <#18x} {: <#18x} {: <32}" 1831 out_str='' 1832 pname = GetProcNameForTask(iit.iit_task) 1833 if hasattr(iit, 'iit_bsd_pid'): 1834 pname = "({:d}) {:s}".format(iit.iit_bsd_pid, iit.iit_procname) 1835 out_str += fmt.format(iit, iit.iit_task, pname) 1836 return out_str 1837 1838@lldb_command('showallimportancetasks') 1839def ShowIPCImportanceTasks(cmd_args=[], cmd_options={}): 1840 """ display a list of all tasks with ipc importance information. 1841 Usage: (lldb) showallimportancetasks 1842 Tip: add "-v" to see detailed information on each kmsg or inherit elems 1843 """ 1844 print(' ' + GetIPCImportantTaskSummary.header + ' ' + GetIPCImportanceElemSummary.header) 1845 for t in kern.tasks: 1846 s = "" 1847 if unsigned(t.task_imp_base): 1848 s += ' ' + GetIPCImportantTaskSummary(t.task_imp_base) 1849 s += ' ' + GetIPCImportanceElemSummary(addressof(t.task_imp_base.iit_elem)) 1850 print(s) 1851 1852@lldb_command('showipcimportance', '') 1853def ShowIPCImportance(cmd_args=[], cmd_options={}): 1854 """ Describe an importance from <ipc_importance_elem_t> argument. 1855 Usage: (lldb) showimportance <ipc_importance_elem_t> 1856 """ 1857 if not cmd_args: 1858 raise ArgumentError("Please provide valid argument") 1859 1860 elem = kern.GetValueFromAddress(cmd_args[0], 'ipc_importance_elem_t') 1861 print(GetIPCImportanceElemSummary.header) 1862 print(GetIPCImportanceElemSummary(elem)) 1863 1864@header("{: <18s} {: <10s} {: <18s} {: <8s} {: <5s} {: <5s} {: <5s}".format("ivac", "refs", "tbl", "tblsize", "index", "Grow", "freelist")) 1865@lldb_type_summary(['ipc_voucher_attr_control *', 'ipc_voucher_attr_control_t']) 1866def GetIPCVoucherAttrControlSummary(ivac): 1867 """ describes a voucher attribute control settings """ 1868 out_str = "" 1869 fmt = "{c: <#18x} {c.ivac_refs.ref_count: <10d} {c.ivac_table: <#18x} {c.ivac_table_size: <8d} {c.ivac_key_index: <5d} {growing: <5s} {c.ivac_freelist: <5d}" 1870 growing_str = "" 1871 1872 if unsigned(ivac) == 0: 1873 return "{: <#18x}".format(ivac) 1874 1875 if unsigned(ivac.ivac_is_growing): 1876 growing_str = "Y" 1877 out_str += fmt.format(c=ivac, growing = growing_str) 1878 return out_str 1879 1880@lldb_command('showivac','') 1881def ShowIPCVoucherAttributeControl(cmd_args=[], cmd_options={}): 1882 """ Show summary of voucher attribute contols. 1883 Usage: (lldb) showivac <ipc_voucher_attr_control_t> 1884 """ 1885 if not cmd_args: 1886 raise ArgumentError("Please provide correct arguments.") 1887 ivac = kern.GetValueFromAddress(cmd_args[0], 'ipc_voucher_attr_control_t') 1888 print(GetIPCVoucherAttrControlSummary.header) 1889 print(GetIPCVoucherAttrControlSummary(ivac)) 1890 if config['verbosity'] > vHUMAN: 1891 cur_entry_index = 0 1892 last_entry_index = unsigned(ivac.ivac_table_size) 1893 print("index " + GetIPCVoucherAttributeEntrySummary.header) 1894 while cur_entry_index < last_entry_index: 1895 print("{: <5d} ".format(cur_entry_index) + GetIPCVoucherAttributeEntrySummary(addressof(ivac.ivac_table[cur_entry_index]))) 1896 cur_entry_index += 1 1897 1898 1899 1900 1901@header("{: <18s} {: <30s} {: <30s} {: <30s} {: <30s}".format("ivam", "get_value_fn", "extract_fn", "release_value_fn", "command_fn")) 1902@lldb_type_summary(['ipc_voucher_attr_manager *', 'ipc_voucher_attr_manager_t']) 1903def GetIPCVoucherAttrManagerSummary(ivam): 1904 """ describes a voucher attribute manager settings """ 1905 out_str = "" 1906 fmt = "{: <#18x} {: <30s} {: <30s} {: <30s} {: <30s}" 1907 1908 if unsigned(ivam) == 0 : 1909 return "{: <#18x}".format(ivam) 1910 1911 get_value_fn = kern.Symbolicate(unsigned(ivam.ivam_get_value)) 1912 extract_fn = kern.Symbolicate(unsigned(ivam.ivam_extract_content)) 1913 release_value_fn = kern.Symbolicate(unsigned(ivam.ivam_release_value)) 1914 command_fn = kern.Symbolicate(unsigned(ivam.ivam_command)) 1915 out_str += fmt.format(ivam, get_value_fn, extract_fn, release_value_fn, command_fn) 1916 return out_str 1917 1918 1919 1920@header("{: <18s} {: <10s} {:s} {:s}".format("ivgte", "key", GetIPCVoucherAttrControlSummary.header.strip(), GetIPCVoucherAttrManagerSummary.header.strip())) 1921@lldb_type_summary(['ipc_voucher_global_table_element *', 'ipc_voucher_global_table_element_t']) 1922def GetIPCVoucherGlobalTableElementSummary(ivgte): 1923 """ describes a ipc_voucher_global_table_element object """ 1924 out_str = "" 1925 fmt = "{g: <#18x} {g.ivgte_key: <10d} {ctrl_s:s} {mgr_s:s}" 1926 out_str += fmt.format(g=ivgte, ctrl_s=GetIPCVoucherAttrControlSummary(ivgte.ivgte_control), mgr_s=GetIPCVoucherAttrManagerSummary(ivgte.ivgte_manager)) 1927 return out_str 1928 1929@lldb_command('showglobalvouchertable', '') 1930def ShowGlobalVoucherTable(cmd_args=[], cmd_options={}): 1931 """ show detailed information of all voucher attribute managers registered with vouchers system 1932 Usage: (lldb) showglobalvouchertable 1933 """ 1934 entry_size = sizeof(kern.globals.iv_global_table[0]) 1935 elems = sizeof(kern.globals.iv_global_table) // entry_size 1936 print(GetIPCVoucherGlobalTableElementSummary.header) 1937 for i in range(elems): 1938 elt = addressof(kern.globals.iv_global_table[i]) 1939 print(GetIPCVoucherGlobalTableElementSummary(elt)) 1940 1941# Type summaries for Bag of Bits. 1942 1943@lldb_type_summary(['user_data_value_element', 'user_data_element_t']) 1944@header("{0: <20s} {1: <16s} {2: <20s} {3: <20s} {4: <16s} {5: <20s}".format("user_data_ve", "maderefs", "checksum", "hash value", "size", "data")) 1945def GetBagofBitsElementSummary(data_element): 1946 """ Summarizes the Bag of Bits element 1947 params: data_element = value of the object of type user_data_value_element_t 1948 returns: String with summary of the type. 1949 """ 1950 format_str = "{0: <#20x} {1: <16d} {2: <#20x} {3: <#20x} {4: <16d}" 1951 out_string = format_str.format(data_element, unsigned(data_element.e_made), data_element.e_sum, data_element.e_hash, unsigned(data_element.e_size)) 1952 out_string += " 0x" 1953 1954 for i in range(0, (unsigned(data_element.e_size) - 1)): 1955 out_string += "{:02x}".format(int(data_element.e_data[i])) 1956 return out_string 1957 1958def GetIPCHandleSummary(handle_ptr): 1959 """ converts a handle value inside a voucher attribute table to ipc element and returns appropriate summary. 1960 params: handle_ptr - uint64 number stored in handle of voucher. 1961 returns: str - string summary of the element held in internal structure 1962 """ 1963 elem = kern.GetValueFromAddress(handle_ptr, 'ipc_importance_elem_t') 1964 if elem.iie_bits & xnudefines.IIE_TYPE_MASK: 1965 iie = Cast(elem, 'struct ipc_importance_inherit *') 1966 return GetIPCImportanceInheritSummary(iie) 1967 else: 1968 iit = Cast(elem, 'struct ipc_importance_task *') 1969 return GetIPCImportantTaskSummary(iit) 1970 1971def GetATMHandleSummary(handle_ptr): 1972 """ Convert a handle value to atm value and returns corresponding summary of its fields. 1973 params: handle_ptr - uint64 number stored in handle of voucher 1974 returns: str - summary of atm value 1975 """ 1976 return "???" 1977 1978def GetBankHandleSummary(handle_ptr): 1979 """ converts a handle value inside a voucher attribute table to bank element and returns appropriate summary. 1980 params: handle_ptr - uint64 number stored in handle of voucher. 1981 returns: str - summary of bank element 1982 """ 1983 if handle_ptr == 1 : 1984 return "Bank task of Current task" 1985 elem = kern.GetValueFromAddress(handle_ptr, 'bank_element_t') 1986 if elem.be_type & 1 : 1987 ba = Cast(elem, 'struct bank_account *') 1988 return GetBankAccountSummary(ba) 1989 else: 1990 bt = Cast(elem, 'struct bank_task *') 1991 return GetBankTaskSummary(bt) 1992 1993def GetBagofBitsHandleSummary(handle_ptr): 1994 """ Convert a handle value to bag of bits value and returns corresponding summary of its fields. 1995 params: handle_ptr - uint64 number stored in handle of voucher 1996 returns: str - summary of bag of bits element 1997 """ 1998 elem = kern.GetValueFromAddress(handle_ptr, 'user_data_element_t') 1999 return GetBagofBitsElementSummary(elem) 2000 2001@static_var('attr_managers',{1: GetATMHandleSummary, 2: GetIPCHandleSummary, 3: GetBankHandleSummary, 7: GetBagofBitsHandleSummary}) 2002def GetHandleSummaryForKey(handle_ptr, key_num): 2003 """ Get a summary of handle pointer from the voucher attribute manager. 2004 For example key 2 -> ipc and it puts either ipc_importance_inherit_t or ipc_important_task_t. 2005 key 3 -> Bank and it puts either bank_task_t or bank_account_t. 2006 key 7 -> Bag of Bits and it puts user_data_element_t in handle. So summary of it would be Bag of Bits content and refs etc. 2007 """ 2008 key_num = int(key_num) 2009 if key_num not in GetHandleSummaryForKey.attr_managers: 2010 return "Unknown key %d" % key_num 2011 return GetHandleSummaryForKey.attr_managers[key_num](handle_ptr) 2012 2013 2014@header("{: <18s} {: <18s} {: <10s} {: <4s} {: <18s} {: <18s}".format("ivace", "value_handle", "#refs", "rel?", "maderefs", "next_layer")) 2015@lldb_type_summary(['ivac_entry *', 'ivac_entry_t']) 2016def GetIPCVoucherAttributeEntrySummary(ivace, manager_key_num = 0): 2017 """ Get summary for voucher attribute entry. 2018 """ 2019 out_str = "" 2020 fmt = "{e: <#18x} {e.ivace_value: <#18x} {e.ivace_refs: <10d} {release: <4s} {made_refs: <18s} {next_layer: <18s}" 2021 release_str = "" 2022 free_str = "" 2023 made_refs = "" 2024 next_layer = "" 2025 2026 if unsigned(ivace.ivace_releasing): 2027 release_str = "Y" 2028 if unsigned(ivace.ivace_free): 2029 free_str = 'F' 2030 if unsigned(ivace.ivace_layered): 2031 next_layer = "{: <#18x}".format(ivace.ivace_u.ivaceu_layer) 2032 else: 2033 made_refs = "{: <18d}".format(ivace.ivace_u.ivaceu_made) 2034 2035 out_str += fmt.format(e=ivace, release=release_str, made_refs=made_refs, next_layer=next_layer) 2036 if config['verbosity'] > vHUMAN and manager_key_num > 0: 2037 out_str += " " + GetHandleSummaryForKey(unsigned(ivace.ivace_value), manager_key_num) 2038 if config['verbosity'] > vHUMAN : 2039 out_str += ' {: <2s} {: <4d} {: <4d}'.format(free_str, ivace.ivace_next, ivace.ivace_index) 2040 return out_str 2041 2042@lldb_command('showivacfreelist','') 2043def ShowIVACFreeList(cmd_args=[], cmd_options={}): 2044 """ Walk the free list and print every entry in the list. 2045 usage: (lldb) showivacfreelist <ipc_voucher_attr_control_t> 2046 """ 2047 if not cmd_args: 2048 raise ArgumentError('Please provide <ipc_voucher_attr_control_t>') 2049 ivac = kern.GetValueFromAddress(cmd_args[0], 'ipc_voucher_attr_control_t') 2050 print(GetIPCVoucherAttrControlSummary.header) 2051 print(GetIPCVoucherAttrControlSummary(ivac)) 2052 if unsigned(ivac.ivac_freelist) == 0: 2053 print("ivac table is full") 2054 return 2055 print("index " + GetIPCVoucherAttributeEntrySummary.header) 2056 next_free = unsigned(ivac.ivac_freelist) 2057 while next_free != 0: 2058 print("{: <5d} ".format(next_free) + GetIPCVoucherAttributeEntrySummary(addressof(ivac.ivac_table[next_free]))) 2059 next_free = unsigned(ivac.ivac_table[next_free].ivace_next) 2060 2061 2062 2063@header('{: <18s} {: <8s} {: <18s} {: <18s}'.format("ipc_voucher", "refs", "table", "voucher_port")) 2064@lldb_type_summary(['ipc_voucher *', 'ipc_voucher_t']) 2065def GetIPCVoucherSummary(voucher, show_entries=False): 2066 """ describe a voucher from its ipc_voucher * object """ 2067 out_str = "" 2068 fmt = "{v: <#18x} {v.iv_refs: <8d} {table_addr: <#18x} {v.iv_port: <#18x}" 2069 out_str += fmt.format(v = voucher, table_addr = addressof(voucher.iv_table)) 2070 entries_str = '' 2071 if show_entries or config['verbosity'] > vHUMAN: 2072 elems = sizeof(voucher.iv_table) // sizeof(voucher.iv_table[0]) 2073 entries_header_str = "\n\t" + "{: <5s} {: <3s} {: <16s} {: <30s}".format("index", "key", "value_index", "manager") + " " + GetIPCVoucherAttributeEntrySummary.header 2074 fmt = "{: <5d} {: <3d} {: <16d} {: <30s}" 2075 for i in range(elems): 2076 voucher_entry_index = unsigned(voucher.iv_table[i]) 2077 if voucher_entry_index: 2078 s = fmt.format(i, GetVoucherManagerKeyForIndex(i), voucher_entry_index, GetVoucherAttributeManagerNameForIndex(i)) 2079 e = GetVoucherValueHandleFromVoucherForIndex(voucher, i) 2080 if e is not None: 2081 s += " " + GetIPCVoucherAttributeEntrySummary(addressof(e), GetVoucherManagerKeyForIndex(i) ) 2082 if entries_header_str : 2083 entries_str = entries_header_str 2084 entries_header_str = '' 2085 entries_str += "\n\t" + s 2086 if not entries_header_str: 2087 entries_str += "\n\t" 2088 out_str += entries_str 2089 return out_str 2090 2091def GetVoucherManagerKeyForIndex(idx): 2092 """ Returns key number for index based on global table. Will raise index error if value is incorrect 2093 """ 2094 return unsigned(kern.globals.iv_global_table[idx].ivgte_key) 2095 2096def GetVoucherAttributeManagerForKey(k): 2097 """ Walks through the iv_global_table and finds the attribute manager name 2098 params: k - int key number of the manager 2099 return: cvalue - the attribute manager object. 2100 None - if not found 2101 """ 2102 retval = None 2103 entry_size = sizeof(kern.globals.iv_global_table[0]) 2104 elems = sizeof(kern.globals.iv_global_table) // entry_size 2105 for i in range(elems): 2106 elt = addressof(kern.globals.iv_global_table[i]) 2107 if k == unsigned(elt.ivgte_key): 2108 retval = elt.ivgte_manager 2109 break 2110 return retval 2111 2112def GetVoucherAttributeControllerForKey(k): 2113 """ Walks through the iv_global_table and finds the attribute controller 2114 params: k - int key number of the manager 2115 return: cvalue - the attribute controller object. 2116 None - if not found 2117 """ 2118 retval = None 2119 entry_size = sizeof(kern.globals.iv_global_table[0]) 2120 elems = sizeof(kern.globals.iv_global_table) // entry_size 2121 for i in range(elems): 2122 elt = addressof(kern.globals.iv_global_table[i]) 2123 if k == unsigned(elt.ivgte_key): 2124 retval = elt.ivgte_control 2125 break 2126 return retval 2127 2128 2129def GetVoucherAttributeManagerName(ivam): 2130 """ find the name of the ivam object 2131 param: ivam - cvalue object of type ipc_voucher_attr_manager_t 2132 returns: str - name of the manager 2133 """ 2134 return kern.Symbolicate(unsigned(ivam)) 2135 2136def GetVoucherAttributeManagerNameForIndex(idx): 2137 """ get voucher attribute manager name for index 2138 return: str - name of the attribute manager object 2139 """ 2140 return GetVoucherAttributeManagerName(GetVoucherAttributeManagerForKey(GetVoucherManagerKeyForIndex(idx))) 2141 2142def GetVoucherValueHandleFromVoucherForIndex(voucher, idx): 2143 """ traverse the voucher attrs and get value_handle in the voucher attr controls table 2144 params: 2145 voucher - cvalue object of type ipc_voucher_t 2146 idx - int index in the entries for which you wish to get actual handle for 2147 returns: cvalue object of type ivac_entry_t 2148 None if no handle found. 2149 """ 2150 manager_key = GetVoucherManagerKeyForIndex(idx) 2151 voucher_num_elems = sizeof(voucher.iv_table) // sizeof(voucher.iv_table[0]) 2152 if idx >= voucher_num_elems: 2153 debuglog("idx %d is out of range max: %d" % (idx, voucher_num_elems)) 2154 return None 2155 voucher_entry_value = unsigned(voucher.iv_table[idx]) 2156 debuglog("manager_key %d" % manager_key) 2157 ivac = GetVoucherAttributeControllerForKey(manager_key) 2158 if ivac is None or unsigned(ivac) == 0: 2159 debuglog("No voucher attribute controller for idx %d" % idx) 2160 return None 2161 2162 ivac = kern.GetValueFromAddress(unsigned(ivac), 'ipc_voucher_attr_control_t') # ??? No idea why lldb does not addressof directly 2163 ivace_table = ivac.ivac_table 2164 if voucher_entry_value >= unsigned(ivac.ivac_table_size): 2165 print("Failed to get ivace for value %d in table of size %d" % (voucher_entry_value, unsigned(ivac.ivac_table_size))) 2166 return None 2167 return ivace_table[voucher_entry_value] 2168 2169 2170 2171@lldb_command('showallvouchers') 2172def ShowAllVouchers(cmd_args=[], cmd_options={}): 2173 """ Display a list of all vouchers in the global voucher hash table 2174 Usage: (lldb) showallvouchers 2175 """ 2176 print(GetIPCVoucherSummary.header) 2177 voucher_ty = gettype("struct ipc_voucher") 2178 for v in kmemory.Zone("ipc vouchers").iter_allocated(voucher_ty): 2179 print(GetIPCVoucherSummary(value(v.AddressOf()))) 2180 2181@lldb_command('showvoucher', '') 2182def ShowVoucher(cmd_args=[], cmd_options={}): 2183 """ Describe a voucher from <ipc_voucher_t> argument. 2184 Usage: (lldb) showvoucher <ipc_voucher_t> 2185 """ 2186 if not cmd_args: 2187 raise ArgumentError("Please provide valid argument") 2188 2189 voucher = kern.GetValueFromAddress(cmd_args[0], 'ipc_voucher_t') 2190 print(GetIPCVoucherSummary.header) 2191 print(GetIPCVoucherSummary(voucher, show_entries=True)) 2192 2193@lldb_command('showportsendrights') 2194def ShowPortSendRights(cmd_args=[], cmd_options={}): 2195 """ Display a list of send rights across all tasks for a given port. 2196 Usage: (lldb) showportsendrights <ipc_port_t> 2197 """ 2198 if not cmd_args: 2199 raise ArgumentError("no port address provided") 2200 port = kern.GetValueFromAddress(cmd_args[0], 'struct ipc_port *') 2201 if not port or port == xnudefines.MACH_PORT_DEAD: 2202 return 2203 2204 return FindPortRights(cmd_args=[unsigned(port)], cmd_options={'-R':'S'}) 2205 2206 2207@lldb_command('showtasksuspenders') 2208def ShowTaskSuspenders(cmd_args=[], cmd_options={}): 2209 """ Display the tasks and send rights that are holding a target task suspended. 2210 Usage: (lldb) showtasksuspenders <task_t> 2211 """ 2212 if not cmd_args: 2213 raise ArgumentError("no task address provided") 2214 task = kern.GetValueFromAddress(cmd_args[0], 'task_t') 2215 2216 if task.suspend_count == 0: 2217 print("task {:#x} ({:s}) is not suspended".format(unsigned(task), GetProcNameForTask(task))) 2218 return 2219 2220 # If the task has been suspended by the kernel (potentially by 2221 # kperf, using task_suspend_internal) or a client of task_suspend2 2222 # that does not convert its task suspension token to a port using 2223 # convert_task_suspension_token_to_port, then it's impossible to determine 2224 # which task did the suspension. 2225 port = task.itk_resume 2226 if task.pidsuspended: 2227 print("task {:#x} ({:s}) has been `pid_suspend`ed. (Probably runningboardd's fault. Go look at the syslog for \"Suspending task.\")".format(unsigned(task), GetProcNameForTask(task))) 2228 return 2229 elif not port: 2230 print("task {:#x} ({:s}) is suspended but no resume port exists".format(unsigned(task), GetProcNameForTask(task))) 2231 return 2232 2233 return FindPortRights(cmd_args=[unsigned(port)], cmd_options={'-R':'S'}) 2234 2235 2236# Macro: showmqueue: 2237@lldb_command('showmqueue', fancy=True) 2238def ShowMQueue(cmd_args=None, cmd_options={}, O=None): 2239 """ Routine that lists details about a given mqueue. 2240 An mqueue is directly tied to a mach port, so it just shows the details of that port. 2241 Syntax: (lldb) showmqueue <address> 2242 """ 2243 if not cmd_args: 2244 return O.error("Missing mqueue argument") 2245 space = 0 2246 mqueue = kern.GetValueFromAddress(cmd_args[0], 'struct ipc_mqueue *') 2247 portoff = getfieldoffset('struct ipc_port', 'ip_messages') 2248 port = unsigned(ArgumentStringToInt(cmd_args[0])) - unsigned(portoff) 2249 obj = kern.GetValueFromAddress(port, 'struct ipc_object *') 2250 ShowPortOrPset(obj, O=O) 2251# EndMacro: showmqueue 2252