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