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