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