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.
13 @header("{0: <20s} {1: <6s} {2: <6s} {3: <10s} {4: <32s}".format("task", "pid", '#acts', "tablesize", "command"))
14 def GetTaskIPCSummary(task
, show_busy
= False):
15 """ Display a task's ipc summary.
17 task : core.value represeting a Task in kernel
19 str - string of ipc info for the task
22 format_string
= "{0: <#020x} {1: <6d} {2: <6d} {3: <10d} {4: <32s}"
23 busy_format
= " {0: <10d} {1: <6d}"
26 proc_name
= 'terminated: '
28 proc_name
+= 'halting: '
29 pval
= Cast(task
.bsd_info
, 'proc *')
31 proc_name
+= GetProcName(pval
)
32 elif int(task
.task_imp_base
) != 0 and hasattr(task
.task_imp_base
, 'iit_procname'):
33 proc_name
+= str(task
.task_imp_base
.iit_procname
)
34 table_size
= int(task
.itk_space
.is_table_size
)
35 out_string
+= format_string
.format(task
, pval
.p_pid
, task
.thread_count
, table_size
, proc_name
)
37 nbusy
, nmsgs
= GetTaskBusyPortsSummary(task
)
38 out_string
+= busy_format
.format(nbusy
, nmsgs
)
39 return (out_string
, table_size
, nbusy
, nmsgs
)
40 return (out_string
, table_size
)
42 @header("{0: <20s} {1: <6s} {2: <6s} {3: <10s} {4: <32s} {5: <10s} {6: <6s}".format("task", "pid", '#acts', "tablesize", "command", "#busyports", "#kmsgs"))
43 def GetTaskBusyIPCSummary(task
):
44 return GetTaskIPCSummary(task
, True)
46 def GetTaskBusyPortsSummary(task
):
51 while i
< isp
.is_table_size
:
52 iep
= addressof(isp
.is_table
[i
])
53 if iep
.ie_bits
& 0x00020000:
54 port
= Cast(iep
.ie_object
, 'ipc_port_t')
55 if port
.ip_messages
.data
.port
.msgcount
> 0:
57 nmsgs
+= port
.ip_messages
.data
.port
.msgcount
62 @header("{0: <20s} {1: <28s} {2: <12s} {3: <6s} {4: <4s} {5: <20s} {6: <4s}\n".format(
63 "port", "mqueue", "recvname", "flags", "refs", "recvname", "dest"))
64 def PrintPortSummary(port
, show_kmsg_summary
=True, prefix
=""):
65 """ Display a port's summary
67 port : core.value representing a port in the kernel
69 str : string of ipc info for the given port
72 portp
= Cast(port
, 'struct ipc_port *')
73 destspacep
= kern
.GetValueFromAddress(0, 'struct ipc_space *')
74 spacep
= portp
.data
.receiver
75 format_string
= "{0: #019x} {1: #019x} {2: <8s} {3: #011x} {4: <5s} {5: #05x} {6: #019x} {7: <16s}\n"
76 if portp
.ip_object
.io_bits
& 0x80000000:
77 out_string
+= prefix
+ format_string
.format(
78 unsigned(portp
), addressof(portp
.ip_messages
), ' '*8,
79 unsigned(portp
.ip_messages
.data
.port
.receiver_name
),
80 "APort", portp
.ip_object
.io_references
,
81 unsigned(portp
.ip_messages
.data
.port
.receiver_name
),
82 GetPortDestProc(portp
))
84 out_string
+= prefix
+ format_string
.format(
85 unsigned(portp
), addressof(portp
.ip_messages
), ' '*8,
86 unsigned(portp
.ip_messages
.data
.port
.receiver_name
),
87 "DPort", portp
.ip_object
.io_references
, unsigned(portp
),
91 kmsgp
= Cast(portp
.ip_messages
.data
.port
.messages
.ikmq_base
, 'ipc_kmsg_t')
93 print prefix
+ GetKMsgSummary
.header
+ prefix
+ GetKMsgSummary(kmsgp
, prefix
)
95 kmsgp
= kmsgp
.ikm_next
96 while (kmsgp
) != (kmsgheadp
):
97 print prefix
+ GetKMsgSummary(kmsgp
, prefix
)
98 kmsgp
= kmsgp
.ikm_next
101 def GetPortDestProc(portp
):
102 """ Display the name and pid of a given port's receiver
104 portp : core.value representing a pointer to a port in the kernel
105 destspacep : core.value representing a pointer to an ipc_space
107 str : string containing receiver's name and pid
109 spacep
= portp
.data
.receiver
110 out_str
= "Not found"
111 for tsk
in kern
.tasks
:
112 if tsk
.itk_space
== spacep
:
114 destprocp
= Cast(tsk
.bsd_info
, 'struct proc *')
115 out_str
= "{0:s}({1: <d})".format(GetProcName(destprocp
), destprocp
.p_pid
)
123 def GetPortDispositionString(disp
):
124 if (disp
< 0): ## use negative numbers for request ports
138 ## These dispositions should match those found in osfmk/mach/message.h
140 disp_str
= 'R' ## receive
142 disp_str
= 'dR' ## dispose receive
144 disp_str
= 'S' ## (move) send
146 disp_str
= 'cS' ## copy send
148 disp_str
= 'mS' ## make send
150 disp_str
= 'dS' ## dispose send
152 disp_str
= 'O' ## send-once
154 disp_str
= 'mO' ## make send-once
156 disp_str
= 'dO' ## dispose send-once
157 ## faux dispositions used to string-ify IPC entry types
159 disp_str
= 'PS' ## port set
161 disp_str
= 'dead' ## dead name
163 disp_str
= 'L' ## LABELH
165 disp_str
= 'V' ## Thread voucher (thread->ith_voucher->iv_port)
168 disp_str
= 'X' ## invalid
172 @header("{:<20s} {:<28s} {:<12s} {:<8s} {:<6s} {:<19s} {:<26s} {:<26s}\n".format(
173 "", "kmsg", "msgid", "disp", "size", "reply-port", "source", "destination"))
174 def GetKMsgSummary(kmsgp
, prefix_str
=""):
175 """ Display a summary for type ipc_kmsg_t
177 kmsgp : core.value representing the given ipc_kmsg_t struct
179 str : string of summary info for the given ipc_kmsg_t instance
181 kmsghp
= kmsgp
.ikm_header
182 kmsgh
= dereference(kmsghp
)
184 out_string
+= "{0: <20s} {1: <#019x} {2: <8s} {3: <#011x} ".format(
185 ' ', unsigned(kmsgp
), ' '*8, kmsgh
.msgh_id
)
186 prefix_str
= "{0: <20s} ".format(' ') + prefix_str
188 bits
= kmsgh
.msgh_bits
& 0xff
196 disposition
= "rX" # invalid
198 out_string
+= "{0: <2s}".format(disposition
)
202 bits
= (kmsgh
.msgh_bits
& 0xff00) >> 8
211 disposition
= "lX" # invalid
213 out_string
+= "{0: <2s}".format(disposition
)
217 bits
= (kmsgh
.msgh_bits
& 0xff0000) >> 16
226 out_string
+= "{0: <2s}".format(disposition
)
229 if kmsgh
.msgh_bits
& 0x80000000:
230 out_string
+= "{0: <1s}".format("c")
232 out_string
+= "{0: <1s}".format("s")
235 if kmsgh
.msgh_bits
& 0x20000000:
236 out_string
+= "{0: <1s}".format("I")
238 out_string
+= "{0: <1s}".format("-")
241 if kmsgp
.ikm_header
.msgh_remote_port
:
242 dest_proc_name
= GetDestinationProcessFromPort(kmsgp
.ikm_header
.msgh_remote_port
)
244 out_string
+= "{0: ^6d} {1: <#019x} {2: <26s} {3: <26s}\n".format(
245 unsigned(kmsgh
.msgh_size
), unsigned(kmsgh
.msgh_local_port
),
246 GetKMsgSrc(kmsgp
), dest_proc_name
)
248 if kmsgh
.msgh_bits
& 0x80000000:
249 out_string
+= prefix_str
+ "\t" + GetKMsgComplexBodyDesc
.header
+ "\n"
250 out_string
+= prefix_str
+ "\t" + GetKMsgComplexBodyDesc(kmsgp
, prefix_str
+ "\t") + "\n"
254 @header("{: <20s} {: <20s} {: <10s}".format("descriptor", "address", "size"))
255 def GetMachMsgOOLDescriptorSummary(desc
):
256 """ Returns description for mach_msg_ool_descriptor_t * object
258 format_string
= "{: <#020x} {: <#020x} {: <#010x}"
259 out_string
= format_string
.format(desc
, desc
.address
, desc
.size
)
263 def GetKmsgDescriptors(kmsgp
):
264 """ Get a list of descriptors in a complex message
266 kmsghp
= kmsgp
.ikm_header
267 kmsgh
= dereference(kmsghp
)
268 if not (kmsgh
.msgh_bits
& 0x80000000):
270 ## Something in the python/lldb types is not getting alignment correct here.
271 ## I'm grabbing a pointer to the body manually, and using tribal knowledge
272 ## of the location of the descriptor count to get this correct
273 body
= Cast(addressof(Cast(addressof(kmsgh
), 'char *')[sizeof(kmsgh
)]), 'mach_msg_body_t *')
274 #dsc_count = body.msgh_descriptor_count
275 dsc_count
= dereference(Cast(body
, 'uint32_t *'))
276 #dschead = Cast(addressof(body[1]), 'mach_msg_descriptor_t *')
277 dschead
= Cast(addressof(Cast(addressof(body
[0]), 'char *')[sizeof('uint32_t')]), 'mach_msg_descriptor_t *')
279 for i
in range(dsc_count
):
280 dsc_list
.append(dschead
[i
])
281 return (body
, dschead
, dsc_list
)
284 @header("{: <20s} {: <8s} {: <20s} {: <10s} {: <20s}".format("kmsgheader", "size", "body", "ds_count", "dsc_head"))
285 def GetKMsgComplexBodyDesc(kmsgp
, prefix_str
=""):
286 """ Routine that prints a complex kmsg's body
288 kmsghp
= kmsgp
.ikm_header
289 kmsgh
= dereference(kmsghp
)
290 if not (kmsgh
.msgh_bits
& 0x80000000):
292 format_string
= "{: <#020x} {: <#08x} {: <#020x} {: <#010x} {: <#020x}"
295 (body
, dschead
, dsc_list
) = GetKmsgDescriptors(kmsgp
)
296 out_string
+= format_string
.format(kmsghp
, sizeof(dereference(kmsghp
)), body
, len(dsc_list
), dschead
)
299 dsc_type
= unsigned(dsc
.type.type)
300 out_string
+= "\n" + prefix_str
+ "Descriptor: " + xnudefines
.mach_msg_type_descriptor_strings
[dsc_type
]
304 dstr
= GetPortDispositionString(dsc
.port
.disposition
)
305 out_string
+= " disp:{:s}, name:{: <#20x}".format(dstr
, p
)
306 elif unsigned(dsc
.type.type) in (1,3):
307 # its OOL DESCRIPTOR or OOL VOLATILE DESCRIPTOR
308 ool
= dsc
.out_of_line
309 out_string
+= " " + GetMachMsgOOLDescriptorSummary(addressof(ool
))
311 out_string
+= "\n" + prefix_str
+ "Invalid Descriptor: {}".format(dsc
)
314 def GetKMsgSrc(kmsgp
):
315 """ Routine that prints a kmsg's source process and pid details
317 kmsgp : core.value representing the given ipc_kmsg_t struct
319 str : string containing the name and pid of the kmsg's source proc
321 kmsgsrchp
= Cast(kmsgp
, 'ipc_kmsg_t').ikm_header
322 kmsgpid
= int(Cast(kern
.GetValueFromAddress(unsigned(kmsgsrchp
) + kmsgsrchp
.msgh_size
, 'uint *')[10], 'pid_t'))
324 return "{0:s} ({1:d})".format(GetProcNameForPid(kmsgpid
), kmsgpid
)
327 def PrintPortSetMembers(space
, setid
, show_kmsg_summary
):
328 """ Print out the members of a given IPC PSet
330 num_entries
= int(space
.is_table_size
)
331 is_tableval
= space
.is_table
332 setid_str
= GetWaitqSetidString(setid
)
334 prefix_str
= "{0:<21s}".format(' '*21)
337 if config
['verbosity'] > vHUMAN
:
341 while idx
< num_entries
:
342 entryval
= GetObjectAtIndexFromArray(is_tableval
, idx
)
343 ie_bits
= unsigned(entryval
.ie_bits
)
344 if not (ie_bits
& 0x00180000):
345 # It's a port entry that's _not_ dead
346 portval
= Cast(entryval
.ie_object
, 'ipc_port_t')
347 waitq
= addressof(portval
.ip_messages
.data
.port
.waitq
)
348 psets
= GetWaitqSets(addressof(portval
.ip_messages
.data
.port
.waitq
))
353 print "{:s}\n{:s}{:s}".format(GetPortDestProc(portval
), prefix_str
, PrintPortSummary
.header
)
354 PrintPortSummary(portval
, show_kmsg_summary
, prefix_str
)
356 sys
.stderr
.write('{:d}/{:d}... \r'.format(idx
, num_entries
))
360 def FindEntryName(obj
, space
):
361 """ Routine to locate a port/ipc_object in an ipc_space
362 and return the name within that space.
367 num_entries
= int(space
.is_table_size
)
368 is_tableval
= space
.is_table
370 while idx
< num_entries
:
371 entry_val
= GetObjectAtIndexFromArray(is_tableval
, idx
)
372 entry_bits
= unsigned(entry_val
.ie_bits
)
374 if (int(entry_bits
) & 0x001f0000) != 0: ## it's a valid entry
375 entry_obj
= unsigned(entry_val
.ie_object
)
376 if entry_obj
== unsigned(obj
):
377 nm
= (idx
<< 8) |
(entry_bits
>> 24)
383 @header("{0: <20s} {1: <28s} {2: <12s} {3: <6s} {4: <6s} {5: <20s} {6: <7s}\n".format(
384 "portset", "waitqueue", "recvname", "flags", "refs", "recvname", "process"))
385 def PrintPortSetSummary(pset
, space
= 0):
386 """ Display summary for a given struct ipc_pset *
388 pset : core.value representing a pset in the kernel
390 str : string of summary information for the given pset
393 show_kmsg_summary
= False
394 if config
['verbosity'] > vHUMAN
:
395 show_kmsg_summary
= True
397 local_name
= FindEntryName(pset
, space
)
399 if pset
.ips_object
.io_bits
& 0x80000000:
400 setid
= pset
.ips_messages
.data
.pset
.setq
.wqset_id
401 out_str
+= "{0: #019x} {1: #019x} {2: <7s} {3: #011x} {4: <4s} {5: >6d} {6: #019x} ".format(
402 unsigned(pset
), addressof(pset
.ips_messages
), ' '*7,
404 pset
.ips_object
.io_references
,
408 out_str
+= "{0: #019x} {1: #019x} {2: <7s} {3: #011x} {4: <4s} {5: >6d} {6: #019x} ".format(
409 unsigned(pset
), addressof(pset
.ips_messages
), ' '*7,
411 pset
.ips_object
.io_references
,
415 if setid
!= 0 and space
!= 0:
416 PrintPortSetMembers(space
, setid
, show_kmsg_summary
)
422 @lldb_command('showipc')
423 def ShowIPC(cmd_args
=None):
424 """ Routine to print data for the given IPC space
425 Usage: showipc <address of ipc space>
428 print "No arguments passed"
429 print ShowIPC
.__doc
__
431 ipc
= kern
.GetValueFromAddress(cmd_args
[0], 'ipc_space *')
433 print "unknown arguments:", str(cmd_args
)
435 print PrintIPCInformation
.header
436 PrintIPCInformation(ipc
, False, False)
442 @lldb_command('showtaskipc')
443 def ShowTaskIPC(cmd_args
=None):
444 """ Routine to print IPC summary of given task
445 Usage: showtaskipc <address of task>
448 print "No arguments passed"
449 print ShowTaskIPC
.__doc
__
451 tval
= kern
.GetValueFromAddress(cmd_args
[0], 'task *')
453 print "unknown arguments:", str(cmd_args
)
455 print GetTaskSummary
.header
+ " " + GetProcSummary
.header
456 pval
= Cast(tval
.bsd_info
, 'proc *')
457 print GetTaskSummary(tval
) + " " + GetProcSummary(pval
)
458 print GetTaskBusyIPCSummary
.header
459 (summary
, table_size
, nbusy
, nmsgs
) = GetTaskBusyIPCSummary(tval
)
462 # EndMacro: showtaskipc
466 @lldb_command('showallipc')
467 def ShowAllIPC(cmd_args
=None):
468 """ Routine to print IPC summary of all tasks
472 print GetTaskSummary
.header
+ " " + GetProcSummary
.header
473 pval
= Cast(t
.bsd_info
, 'proc *')
474 print GetTaskSummary(t
) + " " + GetProcSummary(pval
)
475 print PrintIPCInformation
.header
476 PrintIPCInformation(t
.itk_space
, False, False) + "\n\n"
478 # EndMacro: showallipc
480 @lldb_command('showipcsummary', fancy
=True)
481 def ShowIPCSummary(cmd_args
=None, cmd_options
={}, O
=None):
482 """ Summarizes the IPC state of all tasks.
483 This is a convenient way to dump some basic clues about IPC messaging. You can use the output to determine
484 tasks that are candidates for further investigation.
486 with O
.table(GetTaskIPCSummary
.header
):
489 (summary
, table_size
) = GetTaskIPCSummary(t
)
490 ipc_table_size
+= table_size
492 for t
in kern
.terminated_tasks
:
493 (summary
, table_size
) = GetTaskIPCSummary(t
)
494 ipc_table_size
+= table_size
495 print "Total Table size: {:d}".format(ipc_table_size
)
497 def GetKObjectFromPort(portval
):
498 """ Get Kobject description from the port.
499 params: portval - core.value representation of 'ipc_port *' object
500 returns: str - string of kobject information
502 io_bits
= unsigned(portval
.ip_object
.io_bits
)
503 if not io_bits
& 0x800:
504 return "not a kobject"
507 kobject_val
= portval
.kdata
.kolabel
.ikol_kobject
509 kobject_val
= portval
.kdata
.kobject
510 kobject_str
= "{0: <#020x}".format(kobject_val
)
511 objtype_index
= io_bits
& 0x3ff
512 if objtype_index
< len(xnudefines
.kobject_types
) :
513 objtype_str
= xnudefines
.kobject_types
[objtype_index
]
514 if objtype_str
== 'IOKIT_OBJ':
515 iokit_classnm
= GetObjectTypeStr(kobject_val
)
516 if not iokit_classnm
:
517 iokit_classnm
= "<unknown class>"
519 iokit_classnm
= re
.sub(r
'vtable for ', r
'', iokit_classnm
)
520 desc_str
= "kobject({:s}:{:s})".format(objtype_str
, iokit_classnm
)
522 desc_str
= "kobject({0:s})".format(objtype_str
)
523 if xnudefines
.kobject_types
[objtype_index
] in ('TASK_RESUME', 'TASK'):
524 desc_str
+= " " + GetProcNameForTask(Cast(kobject_val
, 'task *'))
526 desc_str
= "kobject(UNKNOWN) {:d}".format(objtype_index
)
527 return kobject_str
+ " " + desc_str
529 @static_var('destcache', {})
530 def GetDestinationProcessFromPort(port
):
532 params: port - core.value representation of 'ipc_port *' object
533 returns: str - name of process
536 dest_space
= port
.data
.receiver
537 task
= dest_space
.is_task
538 if task
.bsd_info
!= 0:
539 out_str
= "{0:s}({1:d})".format(GetProcNameForTask(task
), GetProcPIDForTask(task
) )
541 out_str
= "task {0: <#020x}".format(task
)
544 @header("{0: <20s} {1: <20s}".format("destname", "destination") )
545 def GetPortDestinationSummary(port
):
546 """ Get destination information for a port.
547 params: port - core.value representation of 'ipc_port *' object
548 returns: str - string of info about ports destination
551 format_string
= "{0: <20s} {1: <20s}"
554 target_spaceval
= port
.data
.receiver
556 destname_str
= GetKObjectFromPort(port
)
557 if "not a kobject" in destname_str
or "kobject(TIMER)" in destname_str
:
558 if int(port
.ip_object
.io_bits
) & 0x80000000 :
559 destname_str
= "{0: <#020x}".format(port
.ip_messages
.data
.port
.receiver_name
)
560 destination_str
= GetDestinationProcessFromPort(port
)
562 destname_str
= "{0: <#020x}".format(port
)
563 destination_str
= "inactive-port"
565 out_str
+= format_string
.format(destname_str
, destination_str
)
568 @lldb_type_summary(['ipc_entry_t'])
569 @header("{: <20s} {: <12s} {: <8s} {: <8s} {: <8s} {: <8s} {: <20s} {: <20s}".format("object", "name", "rite", "urefs", "nsets", "nmsgs", "destname", "destination"))
570 def GetIPCEntrySummary(entry
, ipc_name
='', rights_filter
=0):
571 """ Get summary of a ipc entry.
573 entry - core.value representing ipc_entry_t in the kernel
574 ipc_name - str of format '0x0123' for display in summary.
576 str - string of ipc entry related information
583 'O' : Send-once right
584 'm' : Immovable send port
585 'i' : Immovable receive port
587 types of notifications:
588 'd' : Dead-Name notification requested
589 's' : Send-Possible notification armed
590 'r' : Send-Possible notification requested
591 'n' : No-Senders notification requested
592 'x' : Port-destroy notification requested
595 entry_ptr
= int(hex(entry
), 16)
596 format_string
= "{: <#020x} {: <12s} {: <8s} {: <8d} {: <8d} {: <8d} {: <20s} {: <20s}"
601 ie_object
= entry
.ie_object
602 ie_bits
= int(entry
.ie_bits
)
603 io_bits
= int(ie_object
.io_bits
)
604 urefs
= int(ie_bits
& 0xffff)
607 if ie_bits
& 0x00100000 :
609 elif ie_bits
& 0x00080000:
611 psetval
= Cast(ie_object
, 'ipc_pset *')
612 set_str
= GetWaitqSets(addressof(psetval
.ips_messages
.data
.pset
.setq
.wqset_q
))
616 if ie_bits
& 0x00010000 :
617 if ie_bits
& 0x00020000 :
623 elif ie_bits
& 0x00020000:
626 elif ie_bits
& 0x00040000 :
629 portval
= Cast(ie_object
, 'ipc_port_t')
630 if int(entry
.index
.request
) != 0:
631 requestsval
= portval
.ip_requests
632 sorightval
= requestsval
[int(entry
.index
.request
)].notify
.port
633 soright_ptr
= unsigned(sorightval
)
635 # dead-name notification requested
637 # send-possible armed
638 if soright_ptr
& 0x1 : right_str
+='s'
639 # send-possible requested
640 if soright_ptr
& 0x2 : right_str
+='r'
641 # No-senders notification requested
642 if portval
.ip_nsrequest
!= 0: right_str
+= 'n'
643 # port-destroy notification requested
644 if portval
.ip_pdrequest
!= 0: right_str
+= 'x'
645 # Immovable receive rights
646 if portval
.ip_immovable_receive
!= 0: right_str
+= 'i'
647 # Immovable send rights
648 if portval
.ip_immovable_send
!= 0: right_str
+= 'm'
650 if portval
.ip_no_grant
!= 0: right_str
+= 'g'
651 # Port with SB filtering on
652 if io_bits
& 0x00001000 != 0: right_str
+= 'f'
654 # early-out if the rights-filter doesn't match
655 if rights_filter
!= 0 and rights_filter
!= right_str
:
658 # append the generation to the name value
659 # (from osfmk/ipc/ipc_entry.h)
660 # bits rollover period
665 ie_gen_roll
= { 0:'.64', 1:'.48', 2:'.32', 3:'.16' }
666 ipc_name
= '{:s}{:s}'.format(ipc_name
.strip(), ie_gen_roll
[(ie_bits
& 0x00c00000) >> 22])
668 # now show the port destination part
669 destname_str
= GetPortDestinationSummary(Cast(ie_object
, 'ipc_port_t'))
670 # Get the number of sets to which this port belongs
671 set_str
= GetWaitqSets(addressof(portval
.ip_messages
.data
.port
.waitq
))
673 nmsgs
= portval
.ip_messages
.data
.port
.msgcount
674 if rights_filter
== 0 or rights_filter
== right_str
:
675 out_str
= format_string
.format(ie_object
, ipc_name
, right_str
, urefs
, nsets
, nmsgs
, destname_str
, destination_str
)
678 @header("{0: >20s}".format("user bt") )
679 def GetPortUserStack(port
, task
):
680 """ Get UserStack information for the given port & task.
681 params: port - core.value representation of 'ipc_port *' object
682 task - value representing 'task *' object
683 returns: str - string information on port's userstack
686 ie_port_callstack
= port
.ip_callstack
687 ie_port_spares
= port
.ip_spares
[0]
688 proc_val
= Cast(task
.bsd_info
, 'proc *')
689 if ie_port_callstack
[0]:
690 out_str
+= "{: <10x}".format(ie_port_callstack
[0])
692 while count
< 16 and ie_port_callstack
[count
]:
693 out_str
+= ": <10x".format(ie_port_callstack
[count
])
695 if ie_port_spares
!= proc_val
.p_pid
:
696 out_str
+= " ({:<10d})".format(ie_port_spares
)
700 @lldb_type_summary(['ipc_space *'])
701 @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'))
702 def PrintIPCInformation(space
, show_entries
=False, show_userstack
=False, rights_filter
=0):
703 """ Provide a summary of the ipc space
706 format_string
= "{0: <#020x} {1: <#020x} {2: <#020x} {3: <8s} {4: <10d} {5: <#18x} {6: >8d} {7: <8d}"
707 is_tableval
= space
.is_table
708 ports
= int(space
.is_table_size
)
710 is_bits
= int(space
.is_bits
)
711 if (is_bits
& 0x40000000) == 0: flags
+='A'
713 if (is_bits
& 0x20000000) != 0: flags
+='G'
714 print format_string
.format(space
, space
.is_task
, space
.is_table
, flags
, space
.is_table_size
, space
.is_table_next
, space
.is_low_mod
, space
.is_high_mod
)
716 #should show the each individual entries if asked.
717 if show_entries
== True:
718 print "\t" + GetIPCEntrySummary
.header
721 while index
< num_entries
:
722 entryval
= GetObjectAtIndexFromArray(is_tableval
, index
)
723 entry_ie_bits
= unsigned(entryval
.ie_bits
)
724 if (int(entry_ie_bits
) & 0x001f0000 ) != 0:
725 entry_name
= "{0: <#020x}".format( (index
<<8 | entry_ie_bits
>> 24) )
726 entry_str
= GetIPCEntrySummary(entryval
, entry_name
, rights_filter
)
727 if len(entry_str
) > 0:
728 print " \r\t" + entry_str
729 if show_userstack
== True:
730 entryport
= Cast(entryval
.ie_object
, 'ipc_port *')
731 if entryval
.ie_object
and (int(entry_ie_bits
) & 0x00070000) and entryport
.ip_callstack
[0]:
732 print GetPortUserStack
.header
+ GetPortUserStack(entryport
, space
.is_task
)
734 # give some progress indication (this is especially
735 # helpful for tasks with large sets of rights)
736 sys
.stderr
.write(' {:d}/{:d}...\r'.format(index
, num_entries
))
738 #done with showing entries
743 @lldb_command('showrights', 'R:')
744 def ShowRights(cmd_args
=None, cmd_options
={}):
745 """ Routine to print rights information for the given IPC space
746 Usage: showrights [-R rights_type] <address of ipc space>
747 -R rights_type : only display rights matching the string 'rights_type'
754 'O' : Send-once right
755 types of notifications:
756 'd' : Dead-Name notification requested
757 's' : Send-Possible notification armed
758 'r' : Send-Possible notification requested
759 'n' : No-Senders notification requested
760 'x' : Port-destroy notification requested
763 print "No arguments passed"
764 print ShowRights
.__doc
__
766 ipc
= kern
.GetValueFromAddress(cmd_args
[0], 'ipc_space *')
768 print "unknown arguments:", str(cmd_args
)
771 if "-R" in cmd_options
:
772 rights_type
= cmd_options
["-R"]
773 print PrintIPCInformation
.header
774 PrintIPCInformation(ipc
, True, False, rights_type
)
776 # EndMacro: showrights
778 @lldb_command('showtaskrights','R:')
779 def ShowTaskRights(cmd_args
=None, cmd_options
={}):
780 """ Routine to ipc rights information for a task
781 Usage: showtaskrights [-R rights_type] <task address>
782 -R rights_type : only display rights matching the string 'rights_type'
789 'O' : Send-once right
790 'm' : Immovable send port
791 'i' : Immovable receive port
793 'f' : Port with SB filtering on
794 types of notifications:
795 'd' : Dead-Name notification requested
796 's' : Send-Possible notification armed
797 'r' : Send-Possible notification requested
798 'n' : No-Senders notification requested
799 'x' : Port-destroy notification requested
802 print "No arguments passed"
803 print ShowTaskStacksCmdHelper
.__doc
__
805 tval
= kern
.GetValueFromAddress(cmd_args
[0], 'task *')
807 print "unknown arguments:", str(cmd_args
)
810 if "-R" in cmd_options
:
811 rights_type
= cmd_options
["-R"]
812 print GetTaskSummary
.header
+ " " + GetProcSummary
.header
813 pval
= Cast(tval
.bsd_info
, 'proc *')
814 print GetTaskSummary(tval
) + " " + GetProcSummary(pval
)
815 print PrintIPCInformation
.header
816 PrintIPCInformation(tval
.itk_space
, True, False, rights_type
)
818 # Count the vouchers in a given task's ipc space
819 @header("{: <20s} {: <6s} {: <12s} {: <8s}".format("task", "pid", "name", "#vouchers"))
820 def GetTaskVoucherCount(t
):
822 is_tableval
= space
.is_table
823 num_entries
= int(space
.is_table_size
)
825 for index
in range (0, num_entries
):
826 entryval
= GetObjectAtIndexFromArray(is_tableval
, index
)
827 entry_ie_bits
= unsigned(entryval
.ie_bits
)
828 if (int(entry_ie_bits
) & 0x00070000 ) != 0:
829 port
= Cast(entryval
.ie_object
, 'ipc_port_t')
830 if int(port
.ip_object
.io_bits
) & 0x800 :
832 io_bits
= unsigned(port
.ip_object
.io_bits
)
833 objtype_index
= io_bits
& 0x3ff
834 if objtype_index
< len(xnudefines
.kobject_types
) :
835 objtype_str
= xnudefines
.kobject_types
[objtype_index
]
836 if objtype_str
== "VOUCHER":
838 format_str
= "{: <#020x} {: <6d} {: <12s} {: <8d}"
839 pval
= Cast(t
.bsd_info
, 'proc *')
840 return format_str
.format(t
, pval
.p_pid
, GetProcNameForTask(t
), count
)
842 # Macro: countallvouchers
843 @lldb_command('countallvouchers', fancy
=True)
844 def CountAllVouchers(cmd_args
=None, cmd_options
={}, O
=None):
845 """ Routine to count the number of vouchers by task. Useful for finding leaks.
846 Usage: countallvouchers
849 with O
.table(GetTaskVoucherCount
.header
):
851 print(GetTaskVoucherCount(t
))
853 # Macro: showataskrightsbt
855 @lldb_command('showtaskrightsbt', 'R:')
856 def ShowTaskRightsBt(cmd_args
=None, cmd_options
={}):
857 """ Routine to ipc rights information with userstacks for a task
858 Usage: showtaskrightsbt [-R rights_type] <task address>
859 -R rights_type : only display rights matching the string 'rights_type'
866 'O' : Send-once right
867 'm' : Immovable send port
868 'i' : Immovable receive port
870 types of notifications:
871 'd' : Dead-Name notification requested
872 's' : Send-Possible notification armed
873 'r' : Send-Possible notification requested
874 'n' : No-Senders notification requested
875 'x' : Port-destroy notification requested
878 print "No arguments passed"
879 print ShowTaskRightsBt
.__doc
__
881 tval
= kern
.GetValueFromAddress(cmd_args
[0], 'task *')
883 print "unknown arguments:", str(cmd_args
)
886 if "-R" in cmd_options
:
887 rights_type
= cmd_options
["-R"]
888 print GetTaskSummary
.header
+ " " + GetProcSummary
.header
889 pval
= Cast(tval
.bsd_info
, 'proc *')
890 print GetTaskSummary(tval
) + " " + GetProcSummary(pval
)
891 print PrintIPCInformation
.header
892 PrintIPCInformation(tval
.itk_space
, True, True, rights_type
)
894 # EndMacro: showtaskrightsbt
896 # Macro: showallrights
898 @lldb_command('showallrights', 'R:')
899 def ShowAllRights(cmd_args
=None, cmd_options
={}):
900 """ Routine to print rights information for IPC space of all tasks
901 Usage: showallrights [-R rights_type]
902 -R rights_type : only display rights matching the string 'rights_type'
909 'O' : Send-once right
910 'm' : Immovable send port
911 'i' : Immovable receive port
913 types of notifications:
914 'd' : Dead-Name notification requested
915 's' : Send-Possible notification armed
916 'r' : Send-Possible notification requested
917 'n' : No-Senders notification requested
918 'x' : Port-destroy notification requested
921 if "-R" in cmd_options
:
922 rights_type
= cmd_options
["-R"]
924 print GetTaskSummary
.header
+ " " + GetProcSummary
.header
925 pval
= Cast(t
.bsd_info
, 'proc *')
926 print GetTaskSummary(t
) + " " + GetProcSummary(pval
)
928 print PrintIPCInformation
.header
929 PrintIPCInformation(t
.itk_space
, True, False, rights_type
) + "\n\n"
930 except (KeyboardInterrupt, SystemExit):
933 print "Failed to get IPC information. Do individual showtaskrights <task> to find the error. \n\n"
935 # EndMacro: showallrights
938 def GetInTransitPortSummary(port
, disp
, holding_port
, holding_kmsg
):
939 """ String-ify the in-transit dispostion of a port.
941 ## This should match the summary generated by GetIPCEntrySummary
942 ## "object" "name" "rite" "urefs" "nsets" "nmsgs" "destname" "destination"
943 format_str
= "\t{: <#20x} {: <12} {: <8s} {: <8d} {: <8d} {: <8d} p:{: <#19x} k:{: <#19x}"
944 portname
= 'intransit'
946 disp_str
= GetPortDispositionString(disp
)
948 out_str
= format_str
.format(unsigned(port
), 'in-transit', disp_str
, 0, 0, port
.ip_messages
.data
.port
.msgcount
, unsigned(holding_port
), unsigned(holding_kmsg
))
952 def GetDispositionFromEntryType(entry_bits
):
953 """ Translate an IPC entry type into an in-transit disposition. This allows
954 the GetInTransitPortSummary function to be re-used to string-ify IPC
957 ebits
= int(entry_bits
)
958 if (ebits
& 0x003f0000) == 0:
961 if (ebits
& 0x00010000) != 0:
962 return 17 ## MACH_PORT_RIGHT_SEND
963 elif (ebits
& 0x00020000) != 0:
964 return 16 ## MACH_PORT_RIGHT_RECEIVE
965 elif (ebits
& 0x00040000) != 0:
966 return 18 ## MACH_PORT_RIGHT_SEND_ONCE
967 elif (ebits
& 0x00080000) != 0:
968 return 100 ## MACH_PORT_RIGHT_PORT_SET
969 elif (ebits
& 0x00100000) != 0:
970 return 101 ## MACH_PORT_RIGHT_DEAD_NAME
971 elif (ebits
& 0x00200000) != 0:
972 return 102 ## MACH_PORT_RIGHT_LABELH
976 def GetDispositionFromVoucherPort(th_vport
):
977 """ Translate a thread's voucher port into a 'disposition'
979 if unsigned(th_vport
) > 0:
980 return 103 ## Voucher type
997 def PrintProgressForKmsg():
1000 sys
.stderr
.write(" {:<1s}\r".format(g_progmeter
[g_kmsg_prog
% 9]))
1004 def CollectPortsForAnalysis(port
, disposition
):
1007 p
= Cast(port
, 'struct ipc_port *')
1008 yield (p
, disposition
)
1010 # no-senders notification port
1011 if unsigned(p
.ip_nsrequest
) != 0:
1012 PrintProgressForKmsg()
1013 yield (Cast(p
.ip_nsrequest
, 'struct ipc_port *'), -1)
1015 # port-death notification port
1016 if unsigned(p
.ip_pdrequest
) != 0:
1017 PrintProgressForKmsg()
1018 yield (Cast(p
.ip_pdrequest
, 'struct ipc_port *'), -2)
1020 ## ports can have many send-possible notifications armed: go through the table!
1021 if unsigned(p
.ip_requests
) != 0:
1022 table
= Cast(p
.ip_requests
, 'struct ipc_port_request *')
1023 table_sz
= int(table
.name
.size
.its_size
)
1024 for i
in range(table_sz
):
1028 if unsigned(ipr
.name
.name
) != 0:
1029 ipr_bits
= unsigned(ipr
.notify
.port
) & 3
1030 ipr_port
= kern
.GetValueFromAddress(int(ipr
.notify
.port
) & ~
3, 'struct ipc_port *')
1032 if ipr_bits
& 3: ## send-possible armed and requested
1034 elif ipr_bits
& 2: ## send-possible requested
1036 elif ipr_bits
& 1: ## send-possible armed
1038 PrintProgressForKmsg()
1039 yield (ipr_port
, ipr_disp
)
1042 def CollectKmsgPorts(task
, task_port
, kmsgp
):
1043 """ Look through a message, 'kmsgp' destined for 'task'
1044 (enqueued on task_port). Collect any port descriptors,
1045 remote, local, voucher, or other port references
1046 into a (ipc_port_t, disposition) list.
1048 kmsgh
= dereference(kmsgp
.ikm_header
)
1052 PrintProgressForKmsg()
1053 if kmsgh
.msgh_remote_port
and unsigned(kmsgh
.msgh_remote_port
) != unsigned(task_port
):
1054 disp
= kmsgh
.msgh_bits
& 0x1f
1055 p_list
+= list(CollectPortsForAnalysis(kmsgh
.msgh_remote_port
, disp
))
1057 if kmsgh
.msgh_local_port
and unsigned(kmsgh
.msgh_local_port
) != unsigned(task_port
) \
1058 and unsigned(kmsgh
.msgh_local_port
) != unsigned(kmsgh
.msgh_remote_port
):
1059 disp
= (kmsgh
.msgh_bits
& 0x1f00) >> 8
1060 p_list
+= list(CollectPortsForAnalysis(kmsgh
.msgh_local_port
, disp
))
1062 if kmsgp
.ikm_voucher
:
1063 p_list
+= list(CollectPortsForAnalysis(kmsgp
.ikm_voucher
, 0))
1065 if kmsgh
.msgh_bits
& 0x80000000:
1066 ## Complex message - look for descriptors
1067 PrintProgressForKmsg()
1068 (body
, dschead
, dsc_list
) = GetKmsgDescriptors(kmsgp
)
1069 for dsc
in dsc_list
:
1070 PrintProgressForKmsg()
1071 dsc_type
= unsigned(dsc
.type.type)
1072 if dsc_type
== 0 or dsc_type
== 2: ## 0 == port, 2 == ool port
1074 ## its a port descriptor
1075 dsc_disp
= dsc
.port
.disposition
1076 p_list
+= list(CollectPortsForAnalysis(dsc
.port
.name
, dsc_disp
))
1078 ## it's an ool_ports descriptor which is an array of ports
1079 dsc_disp
= dsc
.ool_ports
.disposition
1080 dispdata
= Cast(dsc
.ool_ports
.address
, 'struct ipc_port *')
1081 for pidx
in range(dsc
.ool_ports
.count
):
1082 PrintProgressForKmsg()
1083 p_list
+= list(CollectPortsForAnalysis(dispdata
[pidx
], dsc_disp
))
1086 def CollectKmsgPortRefs(task
, task_port
, kmsgp
, p_refs
):
1087 """ Recursively collect all references to ports inside the kmsg 'kmsgp'
1088 into the set 'p_refs'
1090 p_list
= CollectKmsgPorts(task
, task_port
, kmsgp
)
1092 ## Iterate over each ports we've collected, to see if they
1093 ## have messages on them, and then recurse!
1094 for p
, pdisp
in p_list
:
1095 ptype
= (p
.ip_object
.io_bits
& 0x7fff0000) >> 16
1096 p_refs
.add((p
, pdisp
, ptype
))
1097 if ptype
!= 0: ## don't bother with port sets
1099 ## If the port that's in-transit has messages already enqueued,
1100 ## go through each of those messages and look for more ports!
1101 if p
.ip_messages
.data
.port
.msgcount
> 0:
1102 p_kmsgp
= Cast(p
.ip_messages
.data
.port
.messages
.ikmq_base
, 'ipc_kmsg_t')
1104 while unsigned(p_kmsgp
) > 0:
1105 CollectKmsgPortRefs(task
, p
, p_kmsgp
, p_refs
)
1106 p_kmsgp
= p_kmsgp
.ikm_next
1107 if p_kmsgp
== kmsgheadp
:
1111 def FindKmsgPortRefs(instr
, task
, task_port
, kmsgp
, qport
):
1112 """ Look through a message, 'kmsgp' destined for 'task'. If we find
1113 any port descriptors, remote, local, voucher, or other port that
1114 matches 'qport', return a short description
1115 which should match the format of GetIPCEntrySummary.
1119 p_list
= CollectKmsgPorts(task
, task_port
, kmsgp
)
1121 ## Run through all ports we've collected looking for 'qport'
1122 for p
, pdisp
in p_list
:
1123 PrintProgressForKmsg()
1124 if unsigned(p
) == unsigned(qport
):
1125 ## the port we're looking for was found in this message!
1126 if len(out_str
) > 0:
1128 out_str
+= GetInTransitPortSummary(p
, pdisp
, task_port
, kmsgp
)
1130 ptype
= (p
.ip_object
.io_bits
& 0x7fff0000) >> 16
1131 if ptype
!= 0: ## don't bother with port sets
1134 ## If the port that's in-transit has messages already enqueued,
1135 ## go through each of those messages and look for more ports!
1136 if p
.ip_messages
.data
.port
.msgcount
> 0:
1137 p_kmsgp
= Cast(p
.ip_messages
.data
.port
.messages
.ikmq_base
, 'ipc_kmsg_t')
1139 while unsigned(p_kmsgp
) > 0:
1140 out_str
= FindKmsgPortRefs(out_str
, task
, p
, p_kmsgp
, qport
)
1141 p_kmsgp
= p_kmsgp
.ikm_next
1142 if p_kmsgp
== kmsgheadp
:
1147 port_iteration_do_print_taskname
= False
1148 registeredport_idx
= -10
1150 intransit_idx
= -1000
1151 taskports_idx
= -2000
1154 def IterateAllPorts(tasklist
, func
, ctx
, include_psets
, follow_busyports
, should_log
):
1155 """ Iterate over all ports in the system, calling 'func'
1158 global port_iteration_do_print_taskname
1159 global intransit_idx
, taskports_idx
, thports_idx
, registeredport_idx
, excports_idx
1161 ## XXX: also host special ports
1163 entry_port_type_mask
= 0x00070000
1165 entry_port_type_mask
= 0x000f0000
1167 if tasklist
is None:
1168 tasklist
= kern
.tasks
1169 tasklist
+= kern
.terminated_tasks
1174 # Write a progress line. Using stderr avoids automatic newline when
1175 # writing to stdout from lldb. Blank spaces at the end clear out long
1180 procname
= 'terminated: '
1182 procname
+= 'halting: '
1183 t_p
= Cast(t
.bsd_info
, 'proc *')
1184 if unsigned(t_p
) != 0:
1185 procname
+= GetProcName(t_p
)
1186 elif unsigned(t
.task_imp_base
) != 0 and hasattr(t
.task_imp_base
, 'iit_procname'):
1187 procname
+= str(t
.task_imp_base
.iit_procname
)
1188 sys
.stderr
.write(" checking {:s} ({}/{})...{:50s}\r".format(procname
, tidx
, len(tasklist
), ''))
1191 port_iteration_do_print_taskname
= True
1193 num_entries
= int(space
.is_table_size
)
1194 is_tableval
= space
.is_table
1196 while idx
< num_entries
:
1197 entry_val
= GetObjectAtIndexFromArray(is_tableval
, idx
)
1198 entry_bits
= unsigned(entry_val
.ie_bits
)
1201 entry_name
= "{:x}".format( (idx
<< 8 | entry_bits
>> 24) )
1203 entry_disp
= GetDispositionFromEntryType(entry_bits
)
1205 ## If the entry in the table represents a port of some sort,
1206 ## then make the callback provided
1207 if int(entry_bits
) & entry_port_type_mask
:
1208 eport
= Cast(entry_val
.ie_object
, 'ipc_port_t')
1209 ## Make the callback
1210 func(t
, space
, ctx
, idx
, entry_val
, eport
, entry_disp
)
1212 ## if the port has pending messages, look through
1213 ## each message for ports (and recurse)
1214 if follow_busyports
and unsigned(eport
) > 0 and eport
.ip_messages
.data
.port
.msgcount
> 0:
1215 ## collect all port references from all messages
1216 kmsgp
= Cast(eport
.ip_messages
.data
.port
.messages
.ikmq_base
, 'ipc_kmsg_t')
1218 while unsigned(kmsgp
) > 0:
1220 CollectKmsgPortRefs(t
, eport
, kmsgp
, p_refs
)
1221 for (port
, pdisp
, ptype
) in p_refs
:
1222 func(t
, space
, ctx
, intransit_idx
, None, port
, pdisp
)
1223 kmsgp
= kmsgp
.ikm_next
1224 if kmsgp
== kmsgheadp
:
1228 ## while (idx < num_entries)
1230 ## Task ports (send rights)
1231 if unsigned(t
.itk_settable_self
) > 0:
1232 func(t
, space
, ctx
, taskports_idx
, 0, t
.itk_settable_self
, 17)
1233 if unsigned(t
.itk_host
) > 0:
1234 func(t
, space
, ctx
, taskports_idx
, 0, t
.itk_host
, 17)
1235 if unsigned(t
.itk_bootstrap
) > 0:
1236 func(t
, space
, ctx
, taskports_idx
, 0, t
.itk_bootstrap
, 17)
1237 if unsigned(t
.itk_seatbelt
) > 0:
1238 func(t
, space
, ctx
, taskports_idx
, 0, t
.itk_seatbelt
, 17)
1239 if unsigned(t
.itk_gssd
) > 0:
1240 func(t
, space
, ctx
, taskports_idx
, 0, t
.itk_gssd
, 17)
1241 if unsigned(t
.itk_debug_control
) > 0:
1242 func(t
, space
, ctx
, taskports_idx
, 0, t
.itk_debug_control
, 17)
1243 if unsigned(t
.itk_task_access
) > 0:
1244 func(t
, space
, ctx
, taskports_idx
, 0, t
.itk_task_access
, 17)
1245 if unsigned(t
.itk_self
[1]) > 0: ## task read port
1246 func(t
, space
, ctx
, taskports_idx
, 0, t
.itk_self
[1], 17)
1247 if unsigned(t
.itk_self
[2]) > 0: ## task inspect port
1248 func(t
, space
, ctx
, taskports_idx
, 0, t
.itk_self
[2], 17)
1250 ## Task name port (not a send right, just a naked ref); TASK_FLAVOR_NAME = 3
1251 if unsigned(t
.itk_self
[3]) > 0:
1252 func(t
, space
, ctx
, taskports_idx
, 0, t
.itk_self
[3], 0)
1254 ## task resume port is a receive right to resume the task
1255 if unsigned(t
.itk_resume
) > 0:
1256 func(t
, space
, ctx
, taskports_idx
, 0, t
.itk_resume
, 16)
1258 ## registered task ports (all send rights)
1260 tr_max
= sizeof(t
.itk_registered
) / sizeof(t
.itk_registered
[0])
1261 while tr_idx
< tr_max
:
1262 tport
= t
.itk_registered
[tr_idx
]
1263 if unsigned(tport
) > 0:
1265 func(t
, space
, ctx
, registeredport_idx
, 0, tport
, 17)
1266 except Exception, e
:
1267 print("\texception looking through registered port {:d}/{:d} in {:s}".format(tr_idx
,tr_max
,t
))
1271 ## Task exception ports
1273 exmax
= sizeof(t
.exc_actions
) / sizeof(t
.exc_actions
[0])
1274 while exidx
< exmax
: ## see: osfmk/mach/[arm|i386]/exception.h
1275 export
= t
.exc_actions
[exidx
].port
## send right
1276 if unsigned(export
) > 0:
1278 func(t
, space
, ctx
, excports_idx
, 0, export
, 17)
1279 except Exception, e
:
1280 print("\texception looking through exception port {:d}/{:d} in {:s}".format(exidx
,exmax
,t
))
1284 ## XXX: any ports still valid after clearing IPC space?!
1286 for thval
in IterateQueue(t
.threads
, 'thread *', 'task_threads'):
1287 ## XXX: look at block reason to see if it's in mach_msg_receive - then look at saved state / message
1289 ## Thread port (send right)
1290 if unsigned(thval
.ith_settable_self
) > 0:
1291 thport
= thval
.ith_settable_self
1292 func(t
, space
, ctx
, thports_idx
, 0, thport
, 17) ## see: osfmk/mach/message.h
1293 ## Thread special reply port (send-once right)
1294 if unsigned(thval
.ith_special_reply_port
) > 0:
1295 thport
= thval
.ith_special_reply_port
1296 func(t
, space
, ctx
, thports_idx
, 0, thport
, 18) ## see: osfmk/mach/message.h
1297 ## Thread voucher port
1298 if unsigned(thval
.ith_voucher
) > 0:
1299 vport
= thval
.ith_voucher
.iv_port
1300 if unsigned(vport
) > 0:
1301 vdisp
= GetDispositionFromVoucherPort(vport
)
1302 func(t
, space
, ctx
, thports_idx
, 0, vport
, vdisp
)
1303 ## Thread exception ports
1304 if unsigned(thval
.exc_actions
) > 0:
1306 while exidx
< exmax
: ## see: osfmk/mach/[arm|i386]/exception.h
1307 export
= thval
.exc_actions
[exidx
].port
## send right
1308 if unsigned(export
) > 0:
1310 func(t
, space
, ctx
, excports_idx
, 0, export
, 17)
1311 except Exception, e
:
1312 print("\texception looking through exception port {:d}/{:d} in {:s}".format(exidx
,exmax
,t
))
1315 ## XXX: the message on a thread (that's currently being received)
1316 ## for (thval in t.threads)
1317 ## for (t in tasklist)
1320 # Macro: findportrights
1321 def FindPortRightsCallback(task
, space
, ctx
, entry_idx
, ipc_entry
, ipc_port
, port_disp
):
1322 """ Callback which uses 'ctx' as the (port,rights_types) tuple for which
1323 a caller is seeking references. This should *not* be used from a
1324 recursive call to IterateAllPorts.
1326 global port_iteration_do_print_taskname
1328 (qport
, rights_type
) = ctx
1331 if unsigned(ipc_entry
) != 0:
1332 entry_bits
= unsigned(ipc_entry
.ie_bits
)
1333 entry_name
= "{:x}".format( (entry_idx
<< 8 | entry_bits
>> 24) )
1334 if (int(entry_bits
) & 0x001f0000) != 0 and unsigned(ipc_entry
.ie_object
) == unsigned(qport
):
1335 ## it's a valid entry, and it points to the port
1336 entry_str
= '\t' + GetIPCEntrySummary(ipc_entry
, entry_name
, rights_type
)
1338 procname
= GetProcNameForTask(task
)
1339 if unsigned(ipc_port
) != 0 and ipc_port
.ip_messages
.data
.port
.msgcount
> 0:
1340 sys
.stderr
.write(" checking {:s} busy-port {}:{:#x}...{:30s}\r".format(procname
, entry_name
, unsigned(ipc_port
), ''))
1341 ## Search through busy ports to find descriptors which could
1342 ## contain the only reference to this port!
1343 kmsgp
= Cast(ipc_port
.ip_messages
.data
.port
.messages
.ikmq_base
, 'ipc_kmsg_t')
1345 while unsigned(kmsgp
):
1346 entry_str
= FindKmsgPortRefs(entry_str
, task
, ipc_port
, kmsgp
, qport
)
1347 kmsgp
= kmsgp
.ikm_next
1348 if kmsgp
== kmsgheadp
:
1350 if len(entry_str
) > 0:
1351 sys
.stderr
.write("{:80s}\r".format(''))
1352 if port_iteration_do_print_taskname
:
1353 print "Task: {0: <#x} {1: <s}".format(task
, procname
)
1354 print '\t' + GetIPCEntrySummary
.header
1355 port_iteration_do_print_taskname
= False
1358 @lldb_command('findportrights', 'R:S:')
1359 def FindPortRights(cmd_args
=None, cmd_options
={}):
1360 """ Routine to locate and print all extant rights to a given port
1361 Usage: findportrights [-R rights_type] [-S <ipc_space_t>] <ipc_port_t>
1362 -S ipc_space : only search the specified ipc space
1363 -R rights_type : only display rights matching the string 'rights_type'
1370 'O' : Send-once right
1371 types of notifications:
1372 'd' : Dead-Name notification requested
1373 's' : Send-Possible notification armed
1374 'r' : Send-Possible notification requested
1375 'n' : No-Senders notification requested
1376 'x' : Port-destroy notification requested
1379 raise ArgumentError("no port address provided")
1380 port
= kern
.GetValueFromAddress(cmd_args
[0], 'struct ipc_port *')
1383 if "-R" in cmd_options
:
1384 rights_type
= cmd_options
["-R"]
1387 if "-S" in cmd_options
:
1388 space
= kern
.GetValueFromAddress(cmd_options
["-S"], 'struct ipc_space *')
1389 tasklist
= [ space
.is_task
]
1391 ## Don't include port sets
1392 ## Don't recurse on busy ports (we do that manually)
1394 IterateAllPorts(tasklist
, FindPortRightsCallback
, (port
, rights_type
), False, False, True)
1395 sys
.stderr
.write("{:120s}\r".format(' '))
1399 # EndMacro: findportrights
1401 # Macro: countallports
1403 def CountPortsCallback(task
, space
, ctx
, entry_idx
, ipc_entry
, ipc_port
, port_disp
):
1404 """ Callback which uses 'ctx' as the set of all ports found in the
1405 iteration. This should *not* be used from a recursive
1406 call to IterateAllPorts.
1408 global intransit_idx
1410 (p_set
, p_intransit
, p_bytask
) = ctx
1412 ## Add the port address to the set of all port addresses
1413 p_set
.add(unsigned(ipc_port
))
1415 if entry_idx
== intransit_idx
:
1416 p_intransit
.add(unsigned(ipc_port
))
1418 if task
.active
or (task
.halting
and not task
.active
):
1419 pname
= GetProcName(Cast(task
.bsd_info
, 'proc *'))
1420 if not pname
in p_bytask
.keys():
1421 p_bytask
[pname
] = { 'transit':0, 'table':0, 'other':0 }
1422 if entry_idx
== intransit_idx
:
1423 p_bytask
[pname
]['transit'] += 1
1424 elif entry_idx
>= 0:
1425 p_bytask
[pname
]['table'] += 1
1427 p_bytask
[pname
]['other'] += 1
1430 @lldb_command('countallports', 'P')
1431 def CountAllPorts(cmd_args
=None, cmd_options
={}):
1432 """ Routine to search for all as many references to ipc_port structures in the kernel
1434 Usage: countallports [-P]
1435 -P : include port sets in the count (default: NO)
1442 if "-P" in cmd_options
:
1445 ## optionally include port sets
1446 ## DO recurse on busy ports
1448 IterateAllPorts(None, CountPortsCallback
, (p_set
, p_intransit
, p_bytask
), find_psets
, True, True)
1449 sys
.stderr
.write("{:120s}\r".format(' '))
1451 print "Total ports found: {:d}".format(len(p_set
))
1452 print "In Transit: {:d}".format(len(p_intransit
))
1454 for pname
in sorted(p_bytask
.keys()):
1455 count
= p_bytask
[pname
]
1456 print "\t{: <20s}: table={: <5d}, transit={: <5d}, other={: <5d}".format(pname
, count
['table'], count
['transit'], count
['other'])
1458 # EndMacro: countallports
1460 # Macro: showpipestats
1461 @lldb_command('showpipestats')
1462 def ShowPipeStats(cmd_args
=None):
1463 """ Display pipes usage information in the kernel
1465 print "Number of pipes: {: d}".format(kern
.globals.amountpipes
)
1466 print "Memory used by pipes: {:s}".format(sizeof_fmt(int(kern
.globals.amountpipekva
)))
1467 print "Max memory allowed for pipes: {:s}".format(sizeof_fmt(int(kern
.globals.maxpipekva
)))
1468 # EndMacro: showpipestats
1470 # Macro: showtaskbusyports
1471 @lldb_command('showtaskbusyports')
1472 def ShowTaskBusyPorts(cmd_args
=None):
1473 """ Routine to print information about receive rights belonging to this task that
1474 have enqueued messages. This is oten a sign of a blocked or hung process
1475 Usage: showtaskbusyports <task address>
1478 print "No arguments passed. Please pass in the address of a task"
1479 print ShowTaskBusyPorts
.__doc
__
1481 task
= kern
.GetValueFromAddress(cmd_args
[0], 'task_t')
1482 PrintTaskBusyPorts(task
)
1485 def PrintTaskBusyPorts(task
):
1486 """ Prints all busy ports for a given task. ie. all receive rights belonging
1487 to this task that have enqueued messages.
1489 task : core.value representing a task in kernel
1491 str : String containing information about the given task's busy ports
1493 isp
= task
.itk_space
1495 while i
< isp
.is_table_size
:
1496 iep
= addressof(isp
.is_table
[i
])
1497 if iep
.ie_bits
& 0x00020000:
1498 port
= Cast(iep
.ie_object
, 'ipc_port_t')
1499 if port
.ip_messages
.data
.port
.msgcount
> 0:
1500 print PrintPortSummary
.header
1501 PrintPortSummary(port
)
1504 # EndMacro: showtaskbusyports
1506 # Macro: showallbusyports
1507 @lldb_command('showallbusyports')
1508 def ShowAllBusyPorts(cmd_args
=None):
1509 """ Routine to print information about all receive rights on the system that
1510 have enqueued messages.
1512 task_queue_head
= kern
.globals.tasks
1514 for tsk
in kern
.tasks
:
1515 PrintTaskBusyPorts(tsk
)
1517 # EndMacro: showallbusyports
1519 # Macro: showbusyportsummary
1520 @lldb_command('showbusyportsummary')
1521 def ShowBusyPortSummary(cmd_args
=None):
1522 """ Routine to print a summary of information about all receive rights
1523 on the system that have enqueued messages.
1525 task_queue_head
= kern
.globals.tasks
1531 print GetTaskBusyIPCSummary
.header
1532 for tsk
in kern
.tasks
:
1533 (summary
, table_size
, nbusy
, nmsgs
) = GetTaskBusyIPCSummary(tsk
)
1534 ipc_table_size
+= table_size
1535 ipc_busy_ports
+= nbusy
1538 for t
in kern
.terminated_tasks
:
1539 (summary
, table_size
, nbusy
, nmsgs
) = GetTaskBusyIPCSummary(tsk
)
1540 ipc_table_size
+= table_size
1541 ipc_busy_ports
+= nbusy
1544 print "Total Table Size: {:d}, Busy Ports: {:d}, Messages in-flight: {:d}".format(ipc_table_size
, ipc_busy_ports
, ipc_msgs
)
1546 # EndMacro: showbusyportsummary
1549 @lldb_command('showport','K')
1550 def ShowPort(cmd_args
=None, cmd_options
={}):
1551 """ Routine that lists details about a given IPC port
1552 Syntax: (lldb) showport 0xaddr
1555 if "-K" in cmd_options
:
1558 print "Please specify the address of the port whose details you want to print"
1559 print ShowPort
.__doc
__
1561 port
= kern
.GetValueFromAddress(cmd_args
[0], 'struct ipc_port *')
1562 print PrintPortSummary
.header
1563 PrintPortSummary(port
, show_kmsgs
)
1564 # EndMacro: showport
1566 # Macro: showmqueue:
1567 @lldb_command('showmqueue', "S:")
1568 def ShowMQueue(cmd_args
=None, cmd_options
={}):
1569 """ Routine that lists details about a given mqueue
1570 Syntax: (lldb) showmqueue 0xaddr [-S ipc_space]
1573 print "Please specify the address of the ipc_mqueue whose details you want to print"
1574 print ShowMQueue
.__doc
__
1577 if "-S" in cmd_options
:
1578 space
= kern
.GetValueFromAddress(cmd_options
["-S"], 'struct ipc_space *')
1579 mqueue
= kern
.GetValueFromAddress(cmd_args
[0], 'struct ipc_mqueue *')
1580 wq_type
= mqueue
.data
.pset
.setq
.wqset_q
.waitq_type
1581 if int(wq_type
) == 3:
1582 psetoff
= getfieldoffset('struct ipc_pset', 'ips_messages')
1583 pset
= unsigned(ArgumentStringToInt(cmd_args
[0])) - unsigned(psetoff
)
1584 print PrintPortSetSummary
.header
1585 PrintPortSetSummary(kern
.GetValueFromAddress(pset
, 'struct ipc_pset *'), space
)
1586 elif int(wq_type
) in [2, 1]:
1587 portoff
= getfieldoffset('struct ipc_port', 'ip_messages')
1588 port
= unsigned(ArgumentStringToInt(cmd_args
[0])) - unsigned(portoff
)
1589 print PrintPortSummary
.header
1590 PrintPortSummary(kern
.GetValueFromAddress(port
, 'struct ipc_port *'))
1592 print "Invalid mqueue? (waitq type {:d} is invalid)".format(int(wq_type
))
1593 # EndMacro: showmqueue
1596 @lldb_command('showkmsg')
1597 def ShowKMSG(cmd_args
=[]):
1598 """ Show detail information about a <ipc_kmsg_t> structure
1599 Usage: (lldb) showkmsg <ipc_kmsg_t>
1602 raise ArgumentError('Invalid arguments')
1603 kmsg
= kern
.GetValueFromAddress(cmd_args
[0], 'ipc_kmsg_t')
1604 print GetKMsgSummary
.header
1605 print GetKMsgSummary(kmsg
)
1607 # EndMacro: showkmsg
1610 @lldb_command('showpset', "S:")
1611 def ShowPSet(cmd_args
=None, cmd_options
={}):
1612 """ Routine that prints details for a given ipc_pset *
1613 Syntax: (lldb) showpset 0xaddr [-S ipc_space]
1616 print "Please specify the address of the pset whose details you want to print"
1617 print ShowPSet
.__doc
__
1620 if "-S" in cmd_options
:
1621 space
= kern
.GetValueFromAddress(cmd_options
["-S"], 'struct ipc_space *')
1623 print PrintPortSetSummary
.header
1624 PrintPortSetSummary(kern
.GetValueFromAddress(cmd_args
[0], 'ipc_pset *'), space
)
1625 # EndMacro: showpset
1627 # IPC importance inheritance related macros.
1629 @lldb_command('showalliits')
1630 def ShowAllIITs(cmd_args
=[], cmd_options
={}):
1631 """ Development only macro. Show list of all iits allocated in the system. """
1633 iit_queue
= kern
.globals.global_iit_alloc_queue
1635 print "This debug macro is only available in development or debug kernels"
1638 print GetIPCImportantTaskSummary
.header
1639 for iit
in IterateQueue(iit_queue
, 'struct ipc_importance_task *', 'iit_allocation'):
1640 print GetIPCImportantTaskSummary(iit
)
1643 @header("{: <18s} {: <3s} {: <18s} {: <32s} {: <18s} {: <8s}".format("ipc_imp_inherit", "don", "to_task", "proc_name", "from_elem", "depth"))
1644 @lldb_type_summary(['ipc_importance_inherit *', 'ipc_importance_inherit_t'])
1645 def GetIPCImportanceInheritSummary(iii
):
1646 """ describes iii object of type ipc_importance_inherit_t * """
1648 fmt
= "{o: <#018x} {don: <3s} {o.iii_to_task.iit_task: <#018x} {task_name: <20s} {o.iii_from_elem: <#018x} {o.iii_depth: <#08x}"
1650 if unsigned(iii
.iii_donating
):
1651 donating_str
= "DON"
1652 taskname
= GetProcNameForTask(iii
.iii_to_task
.iit_task
)
1653 if hasattr(iii
.iii_to_task
, 'iit_bsd_pid'):
1654 taskname
= "({:d}) {:s}".format(iii
.iii_to_task
.iit_bsd_pid
, iii
.iii_to_task
.iit_procname
)
1655 out_str
+= fmt
.format(o
=iii
, task_name
= taskname
, don
=donating_str
)
1658 @static_var('recursion_count', 0)
1659 @header("{: <18s} {: <4s} {: <8s} {: <8s} {: <18s} {: <18s}".format("iie", "type", "refs", "made", "#kmsgs", "#inherits"))
1660 @lldb_type_summary(['ipc_importance_elem *'])
1661 def GetIPCImportanceElemSummary(iie
):
1662 """ describes an ipc_importance_elem * object """
1664 if GetIPCImportanceElemSummary
.recursion_count
> 500:
1665 GetIPCImportanceElemSummary
.recursion_count
= 0
1666 return "Recursion of 500 reached"
1669 fmt
= "{: <#018x} {: <4s} {: <8d} {: <8d} {: <#018x} {: <#018x}"
1670 if unsigned(iie
.iie_bits
) & 0x80000000:
1675 iit
= Cast(iie
, 'struct ipc_importance_task *')
1676 inherit_count
= sum(1 for i
in IterateQueue(iit
.iit_inherits
, 'struct ipc_importance_inherit *', 'iii_inheritance'))
1678 refs
= unsigned(iie
.iie_bits
) & 0x7fffffff
1679 made_refs
= unsigned(iie
.iie_made
)
1680 kmsg_count
= sum(1 for i
in IterateQueue(iie
.iie_kmsgs
, 'struct ipc_kmsg *', 'ikm_inheritance'))
1681 out_str
+= fmt
.format(iie
, type_str
, refs
, made_refs
, kmsg_count
, inherit_count
)
1682 if config
['verbosity'] > vHUMAN
:
1684 out_str
+= "\n\t"+ GetKMsgSummary
.header
1685 for k
in IterateQueue(iie
.iie_kmsgs
, 'struct ipc_kmsg *', 'ikm_inheritance'):
1686 out_str
+= "\t" + "{: <#018x}".format(k
.ikm_header
.msgh_remote_port
) + ' ' + GetKMsgSummary(k
, "\t").lstrip()
1688 if inherit_count
> 0:
1689 out_str
+= "\n\t" + GetIPCImportanceInheritSummary
.header
+ "\n"
1690 for i
in IterateQueue(iit
.iit_inherits
, 'struct ipc_importance_inherit *', 'iii_inheritance'):
1691 out_str
+= "\t" + GetIPCImportanceInheritSummary(i
) + "\n"
1693 if type_str
== "INH":
1694 iii
= Cast(iie
, 'struct ipc_importance_inherit *')
1695 out_str
+= "Inherit from: " + GetIPCImportanceElemSummary(iii
.iii_from_elem
)
1699 @header("{: <18s} {: <18s} {: <32}".format("iit", "task", "name"))
1700 @lldb_type_summary(['ipc_importance_task *'])
1701 def GetIPCImportantTaskSummary(iit
):
1702 """ iit is a ipc_importance_task value object.
1704 fmt
= "{: <#018x} {: <#018x} {: <32}"
1706 pname
= GetProcNameForTask(iit
.iit_task
)
1707 if hasattr(iit
, 'iit_bsd_pid'):
1708 pname
= "({:d}) {:s}".format(iit
.iit_bsd_pid
, iit
.iit_procname
)
1709 out_str
+= fmt
.format(iit
, iit
.iit_task
, pname
)
1712 @lldb_command('showallimportancetasks')
1713 def ShowIPCImportanceTasks(cmd_args
=[], cmd_options
={}):
1714 """ display a list of all tasks with ipc importance information.
1715 Usage: (lldb) showallimportancetasks
1716 Tip: add "-v" to see detailed information on each kmsg or inherit elems
1718 print ' ' + GetIPCImportantTaskSummary
.header
+ ' ' + GetIPCImportanceElemSummary
.header
1719 for t
in kern
.tasks
:
1721 if unsigned(t
.task_imp_base
):
1722 s
+= ' ' + GetIPCImportantTaskSummary(t
.task_imp_base
)
1723 s
+= ' ' + GetIPCImportanceElemSummary(addressof(t
.task_imp_base
.iit_elem
))
1726 @lldb_command('showipcimportance', '')
1727 def ShowIPCImportance(cmd_args
=[], cmd_options
={}):
1728 """ Describe an importance from <ipc_importance_elem_t> argument.
1729 Usage: (lldb) showimportance <ipc_importance_elem_t>
1732 raise ArgumentError("Please provide valid argument")
1734 elem
= kern
.GetValueFromAddress(cmd_args
[0], 'ipc_importance_elem_t')
1735 print GetIPCImportanceElemSummary
.header
1736 print GetIPCImportanceElemSummary(elem
)
1738 @header("{: <18s} {: <10s} {: <18s} {: <18s} {: <8s} {: <5s} {: <5s} {: <5s}".format("ivac", "refs", "port", "tbl", "tblsize", "index", "Grow", "freelist"))
1739 @lldb_type_summary(['ipc_voucher_attr_control *', 'ipc_voucher_attr_control_t'])
1740 def GetIPCVoucherAttrControlSummary(ivac
):
1741 """ describes a voucher attribute control settings """
1743 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}"
1746 if unsigned(ivac
) == 0:
1747 return "{: <#018x}".format(ivac
)
1749 if unsigned(ivac
.ivac_is_growing
):
1751 out_str
+= fmt
.format(c
=ivac
, growing
= growing_str
)
1754 @lldb_command('showivac','')
1755 def ShowIPCVoucherAttributeControl(cmd_args
=[], cmd_options
={}):
1756 """ Show summary of voucher attribute contols.
1757 Usage: (lldb) showivac <ipc_voucher_attr_control_t>
1760 raise ArgumentError("Please provide correct arguments.")
1761 ivac
= kern
.GetValueFromAddress(cmd_args
[0], 'ipc_voucher_attr_control_t')
1762 print GetIPCVoucherAttrControlSummary
.header
1763 print GetIPCVoucherAttrControlSummary(ivac
)
1764 if config
['verbosity'] > vHUMAN
:
1766 last_entry_index
= unsigned(ivac
.ivac_table_size
)
1767 print "index " + GetIPCVoucherAttributeEntrySummary
.header
1768 while cur_entry_index
< last_entry_index
:
1769 print "{: <5d} ".format(cur_entry_index
) + GetIPCVoucherAttributeEntrySummary(addressof(ivac
.ivac_table
[cur_entry_index
]))
1770 cur_entry_index
+= 1
1775 @header("{: <18s} {: <30s} {: <30s} {: <30s} {: <30s} {: <30s}".format("ivam", "get_value_fn", "extract_fn", "release_value_fn", "command_fn", "release_fn"))
1776 @lldb_type_summary(['ipc_voucher_attr_manager *', 'ipc_voucher_attr_manager_t'])
1777 def GetIPCVoucherAttrManagerSummary(ivam
):
1778 """ describes a voucher attribute manager settings """
1780 fmt
= "{: <#018x} {: <30s} {: <30s} {: <30s} {: <30s} {: <30s}"
1782 if unsigned(ivam
) == 0 :
1783 return "{: <#018x}".format(ivam
)
1785 get_value_fn
= kern
.Symbolicate(unsigned(ivam
.ivam_get_value
))
1786 extract_fn
= kern
.Symbolicate(unsigned(ivam
.ivam_extract_content
))
1787 release_value_fn
= kern
.Symbolicate(unsigned(ivam
.ivam_release_value
))
1788 command_fn
= kern
.Symbolicate(unsigned(ivam
.ivam_command
))
1789 release_fn
= kern
.Symbolicate(unsigned(ivam
.ivam_release
))
1790 out_str
+= fmt
.format(ivam
, get_value_fn
, extract_fn
, release_value_fn
, command_fn
, release_fn
)
1795 @header("{: <18s} {: <10s} {:s} {:s}".format("ivgte", "key", GetIPCVoucherAttrControlSummary
.header
.strip(), GetIPCVoucherAttrManagerSummary
.header
.strip()))
1796 @lldb_type_summary(['ipc_voucher_global_table_element *', 'ipc_voucher_global_table_element_t'])
1797 def GetIPCVoucherGlobalTableElementSummary(ivgte
):
1798 """ describes a ipc_voucher_global_table_element object """
1800 fmt
= "{g: <#018x} {g.ivgte_key: <10d} {ctrl_s:s} {mgr_s:s}"
1801 out_str
+= fmt
.format(g
=ivgte
, ctrl_s
=GetIPCVoucherAttrControlSummary(ivgte
.ivgte_control
), mgr_s
=GetIPCVoucherAttrManagerSummary(ivgte
.ivgte_manager
))
1804 @lldb_command('showglobalvouchertable', '')
1805 def ShowGlobalVoucherTable(cmd_args
=[], cmd_options
={}):
1806 """ show detailed information of all voucher attribute managers registered with vouchers system
1807 Usage: (lldb) showglobalvouchertable
1809 entry_size
= sizeof(kern
.globals.iv_global_table
[0])
1810 elems
= sizeof(kern
.globals.iv_global_table
) / entry_size
1811 print GetIPCVoucherGlobalTableElementSummary
.header
1812 for i
in range(elems
):
1813 elt
= addressof(kern
.globals.iv_global_table
[i
])
1814 print GetIPCVoucherGlobalTableElementSummary(elt
)
1816 # Type summaries for Bag of Bits.
1818 @lldb_type_summary(['user_data_value_element', 'user_data_element_t'])
1819 @header("{0: <20s} {1: <16s} {2: <20s} {3: <20s} {4: <16s} {5: <20s}".format("user_data_ve", "maderefs", "checksum", "hash value", "size", "data"))
1820 def GetBagofBitsElementSummary(data_element
):
1821 """ Summarizes the Bag of Bits element
1822 params: data_element = value of the object of type user_data_value_element_t
1823 returns: String with summary of the type.
1825 format_str
= "{0: <#020x} {1: <16d} {2: <#020x} {3: <#020x} {4: <16d}"
1826 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
))
1829 for i
in range(0, (unsigned(data_element
.e_size
) - 1)):
1830 out_string
+= "{:02x}".format(int(data_element
.e_data
[i
]))
1833 def GetIPCHandleSummary(handle_ptr
):
1834 """ converts a handle value inside a voucher attribute table to ipc element and returns appropriate summary.
1835 params: handle_ptr - uint64 number stored in handle of voucher.
1836 returns: str - string summary of the element held in internal structure
1838 elem
= kern
.GetValueFromAddress(handle_ptr
, 'ipc_importance_elem_t')
1839 if elem
.iie_bits
& 0x80000000 :
1840 iie
= Cast(elem
, 'struct ipc_importance_inherit *')
1841 return GetIPCImportanceInheritSummary(iie
)
1843 iit
= Cast(elem
, 'struct ipc_importance_task *')
1844 return GetIPCImportantTaskSummary(iit
)
1846 def GetATMHandleSummary(handle_ptr
):
1847 """ Convert a handle value to atm value and returns corresponding summary of its fields.
1848 params: handle_ptr - uint64 number stored in handle of voucher
1849 returns: str - summary of atm value
1853 def GetBankHandleSummary(handle_ptr
):
1854 """ converts a handle value inside a voucher attribute table to bank element and returns appropriate summary.
1855 params: handle_ptr - uint64 number stored in handle of voucher.
1856 returns: str - summary of bank element
1858 if handle_ptr
== 1 :
1859 return "Bank task of Current task"
1860 elem
= kern
.GetValueFromAddress(handle_ptr
, 'bank_element_t')
1861 if elem
.be_type
& 1 :
1862 ba
= Cast(elem
, 'struct bank_account *')
1863 return GetBankAccountSummary(ba
)
1865 bt
= Cast(elem
, 'struct bank_task *')
1866 return GetBankTaskSummary(bt
)
1868 def GetBagofBitsHandleSummary(handle_ptr
):
1869 """ Convert a handle value to bag of bits value and returns corresponding summary of its fields.
1870 params: handle_ptr - uint64 number stored in handle of voucher
1871 returns: str - summary of bag of bits element
1873 elem
= kern
.GetValueFromAddress(handle_ptr
, 'user_data_element_t')
1874 return GetBagofBitsElementSummary(elem
)
1876 @static_var('attr_managers',{1: GetATMHandleSummary, 2: GetIPCHandleSummary, 3: GetBankHandleSummary, 7: GetBagofBitsHandleSummary}
)
1877 def GetHandleSummaryForKey(handle_ptr
, key_num
):
1878 """ Get a summary of handle pointer from the voucher attribute manager.
1879 For example key 2 -> ipc and it puts either ipc_importance_inherit_t or ipc_important_task_t.
1880 key 3 -> Bank and it puts either bank_task_t or bank_account_t.
1881 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.
1883 key_num
= int(key_num
)
1884 if key_num
not in GetHandleSummaryForKey
.attr_managers
:
1885 return "Unknown key %d" % key_num
1886 return GetHandleSummaryForKey
.attr_managers
[key_num
](handle_ptr
)
1889 @header("{: <18s} {: <18s} {: <10s} {: <4s} {: <18s} {: <18s}".format("ivace", "value_handle", "#refs", "rel?", "maderefs", "next_layer"))
1890 @lldb_type_summary(['ivac_entry *', 'ivac_entry_t'])
1891 def GetIPCVoucherAttributeEntrySummary(ivace
, manager_key_num
= 0):
1892 """ Get summary for voucher attribute entry.
1895 fmt
= "{e: <#018x} {e.ivace_value: <#018x} {e.ivace_refs: <10d} {release: <4s} {made_refs: <18s} {next_layer: <18s}"
1901 if unsigned(ivace
.ivace_releasing
):
1903 if unsigned(ivace
.ivace_free
):
1905 if unsigned(ivace
.ivace_layered
):
1906 next_layer
= "{: <#018x}".format(ivace
.ivace_u
.ivaceu_layer
)
1908 made_refs
= "{: <18d}".format(ivace
.ivace_u
.ivaceu_made
)
1910 out_str
+= fmt
.format(e
=ivace
, release
=release_str
, made_refs
=made_refs
, next_layer
=next_layer
)
1911 if config
['verbosity'] > vHUMAN
and manager_key_num
> 0:
1912 out_str
+= " " + GetHandleSummaryForKey(unsigned(ivace
.ivace_value
), manager_key_num
)
1913 if config
['verbosity'] > vHUMAN
:
1914 out_str
+= ' {: <2s} {: <4d} {: <4d}'.format(free_str
, ivace
.ivace_next
, ivace
.ivace_index
)
1917 @lldb_command('showivacfreelist','')
1918 def ShowIVACFreeList(cmd_args
=[], cmd_options
={}):
1919 """ Walk the free list and print every entry in the list.
1920 usage: (lldb) showivacfreelist <ipc_voucher_attr_control_t>
1923 raise ArgumentError('Please provide <ipc_voucher_attr_control_t>')
1924 ivac
= kern
.GetValueFromAddress(cmd_args
[0], 'ipc_voucher_attr_control_t')
1925 print GetIPCVoucherAttrControlSummary
.header
1926 print GetIPCVoucherAttrControlSummary(ivac
)
1927 if unsigned(ivac
.ivac_freelist
) == 0:
1928 print "ivac table is full"
1930 print "index " + GetIPCVoucherAttributeEntrySummary
.header
1931 next_free
= unsigned(ivac
.ivac_freelist
)
1932 while next_free
!= 0:
1933 print "{: <5d} ".format(next_free
) + GetIPCVoucherAttributeEntrySummary(addressof(ivac
.ivac_table
[next_free
]))
1934 next_free
= unsigned(ivac
.ivac_table
[next_free
].ivace_next
)
1938 @header('{: <18s} {: <8s} {: <18s} {: <18s} {: <18s} {: <18s} {: <18s}'.format("ipc_voucher", "refs", "checksum", "hash", "tbl_size", "table", "voucher_port"))
1939 @lldb_type_summary(['ipc_voucher *', 'ipc_voucher_t'])
1940 def GetIPCVoucherSummary(voucher
, show_entries
=False):
1941 """ describe a voucher from its ipc_voucher * object """
1943 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}"
1944 out_str
+= fmt
.format(v
= voucher
)
1946 if show_entries
or config
['verbosity'] > vHUMAN
:
1947 elems
= unsigned(voucher
.iv_table_size
)
1948 entries_header_str
= "\n\t" + "{: <5s} {: <3s} {: <16s} {: <30s}".format("index", "key", "value_index", "manager") + " " + GetIPCVoucherAttributeEntrySummary
.header
1949 fmt
= "{: <5d} {: <3d} {: <16d} {: <30s}"
1950 for i
in range(elems
):
1951 voucher_entry_index
= unsigned(voucher
.iv_inline_table
[i
])
1952 if voucher_entry_index
:
1953 s
= fmt
.format(i
, GetVoucherManagerKeyForIndex(i
), voucher_entry_index
, GetVoucherAttributeManagerNameForIndex(i
))
1954 e
= GetVoucherValueHandleFromVoucherForIndex(voucher
, i
)
1956 s
+= " " + GetIPCVoucherAttributeEntrySummary(addressof(e
), GetVoucherManagerKeyForIndex(i
) )
1957 if entries_header_str
:
1958 entries_str
= entries_header_str
1959 entries_header_str
= ''
1960 entries_str
+= "\n\t" + s
1961 if not entries_header_str
:
1962 entries_str
+= "\n\t"
1963 out_str
+= entries_str
1966 def GetVoucherManagerKeyForIndex(idx
):
1967 """ Returns key number for index based on global table. Will raise index error if value is incorrect
1969 return unsigned(kern
.globals.iv_global_table
[idx
].ivgte_key
)
1971 def GetVoucherAttributeManagerForKey(k
):
1972 """ Walks through the iv_global_table and finds the attribute manager name
1973 params: k - int key number of the manager
1974 return: cvalue - the attribute manager object.
1978 entry_size
= sizeof(kern
.globals.iv_global_table
[0])
1979 elems
= sizeof(kern
.globals.iv_global_table
) / entry_size
1980 for i
in range(elems
):
1981 elt
= addressof(kern
.globals.iv_global_table
[i
])
1982 if k
== unsigned(elt
.ivgte_key
):
1983 retval
= elt
.ivgte_manager
1987 def GetVoucherAttributeControllerForKey(k
):
1988 """ Walks through the iv_global_table and finds the attribute controller
1989 params: k - int key number of the manager
1990 return: cvalue - the attribute controller object.
1994 entry_size
= sizeof(kern
.globals.iv_global_table
[0])
1995 elems
= sizeof(kern
.globals.iv_global_table
) / entry_size
1996 for i
in range(elems
):
1997 elt
= addressof(kern
.globals.iv_global_table
[i
])
1998 if k
== unsigned(elt
.ivgte_key
):
1999 retval
= elt
.ivgte_control
2004 def GetVoucherAttributeManagerName(ivam
):
2005 """ find the name of the ivam object
2006 param: ivam - cvalue object of type ipc_voucher_attr_manager_t
2007 returns: str - name of the manager
2009 return kern
.Symbolicate(unsigned(ivam
))
2011 def GetVoucherAttributeManagerNameForIndex(idx
):
2012 """ get voucher attribute manager name for index
2013 return: str - name of the attribute manager object
2015 return GetVoucherAttributeManagerName(GetVoucherAttributeManagerForKey(GetVoucherManagerKeyForIndex(idx
)))
2017 def GetVoucherValueHandleFromVoucherForIndex(voucher
, idx
):
2018 """ traverse the voucher attrs and get value_handle in the voucher attr controls table
2020 voucher - cvalue object of type ipc_voucher_t
2021 idx - int index in the entries for which you wish to get actual handle for
2022 returns: cvalue object of type ivac_entry_t
2023 None if no handle found.
2025 manager_key
= GetVoucherManagerKeyForIndex(idx
)
2026 voucher_num_elems
= unsigned(voucher
.iv_table_size
)
2027 if idx
>= voucher_num_elems
:
2028 debuglog("idx %d is out of range max: %d" % (idx
, voucher_num_elems
))
2030 voucher_entry_value
= unsigned(voucher
.iv_inline_table
[idx
])
2031 debuglog("manager_key %d" % manager_key
)
2032 ivac
= GetVoucherAttributeControllerForKey(manager_key
)
2033 if ivac
is None or unsigned(ivac
) == 0:
2034 debuglog("No voucher attribute controller for idx %d" % idx
)
2037 ivac
= kern
.GetValueFromAddress(unsigned(ivac
), 'ipc_voucher_attr_control_t') # ??? No idea why lldb does not addressof directly
2038 ivace_table
= ivac
.ivac_table
2039 if voucher_entry_value
>= unsigned(ivac
.ivac_table_size
):
2040 print "Failed to get ivace for value %d in table of size %d" % (voucher_entry_value
, unsigned(ivac
.ivac_table_size
))
2042 return ivace_table
[voucher_entry_value
]
2046 @lldb_command('showallvouchers')
2047 def ShowAllVouchers(cmd_args
=[], cmd_options
={}):
2048 """ Display a list of all vouchers in the global voucher hash table
2049 Usage: (lldb) showallvouchers
2051 iv_hash_table
= kern
.globals.ivht_bucket
2052 num_buckets
= sizeof(kern
.globals.ivht_bucket
) / sizeof(kern
.globals.ivht_bucket
[0])
2053 print GetIPCVoucherSummary
.header
2054 for i
in range(num_buckets
):
2055 for v
in IterateQueue(iv_hash_table
[i
], 'ipc_voucher_t', 'iv_hash_link'):
2056 print GetIPCVoucherSummary(v
)
2058 @lldb_command('showvoucher', '')
2059 def ShowVoucher(cmd_args
=[], cmd_options
={}):
2060 """ Describe a voucher from <ipc_voucher_t> argument.
2061 Usage: (lldb) showvoucher <ipc_voucher_t>
2064 raise ArgumentError("Please provide valid argument")
2066 voucher
= kern
.GetValueFromAddress(cmd_args
[0], 'ipc_voucher_t')
2067 print GetIPCVoucherSummary
.header
2068 print GetIPCVoucherSummary(voucher
, show_entries
=True)
2070 def GetSpaceSendRightEntries(space
, port
):
2071 """ Get entry summaries for all send rights to port address in an IPC space.
2073 space - the IPC space to search for send rights
2074 port_addr - the port address to match, or 0 to get all send rights
2075 returns: an array of IPC entries
2077 entry_table
= space
.is_table
2078 ports
= int(space
.is_table_size
)
2083 entry
= GetObjectAtIndexFromArray(entry_table
, i
)
2085 entry_ie_bits
= unsigned(entry
.ie_bits
)
2086 if (entry_ie_bits
& 0x00010000) != 0 and (not port
or entry
.ie_object
== port
):
2087 entries
.append(entry
)
2092 @lldb_command('showportsendrights')
2093 def ShowPortSendRights(cmd_args
=[], cmd_options
={}):
2094 """ Display a list of send rights across all tasks for a given port.
2095 Usage: (lldb) showportsendrights <ipc_port_t>
2098 raise ArgumentError("no port address provided")
2099 port
= kern
.GetValueFromAddress(cmd_args
[0], 'struct ipc_port *')
2102 return FindPortRights(cmd_args
=[unsigned(port
)], cmd_options
={'-R':'S'}
)
2105 @lldb_command('showtasksuspenders')
2106 def ShowTaskSuspenders(cmd_args
=[], cmd_options
={}):
2107 """ Display the tasks and send rights that are holding a target task suspended.
2108 Usage: (lldb) showtasksuspenders <task_t>
2111 raise ArgumentError("no task address provided")
2112 task
= kern
.GetValueFromAddress(cmd_args
[0], 'task_t')
2114 if task
.suspend_count
== 0:
2115 print "task {:#x} ({:s}) is not suspended".format(unsigned(task
), GetProcName(Cast(task
.bsd_info
, 'proc_t')))
2118 # If the task has been suspended by the kernel (potentially by
2119 # kperf, using task_suspend_internal) or a client of task_suspend2
2120 # that does not convert its task suspension token to a port using
2121 # convert_task_suspension_token_to_port, then it's impossible to determine
2122 # which task did the suspension.
2123 port
= task
.itk_resume
2125 print "task {:#x} ({:s}) is suspended but no resume port exists".format(unsigned(task
), GetProcName(Cast(task
.bsd_info
, 'proc_t')))
2128 return FindPortRights(cmd_args
=[unsigned(port
)], cmd_options
={'-R':'S'}
)