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