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.
14 @header("{0: <20s} {1: <6s} {2: <6s} {3: <10s} {4: <20s}".format("task", "pid", '#acts', "tablesize", "command"))
15 def GetTaskIPCSummary(task
, show_busy
= False):
16 """ Display a task's ipc summary.
18 task : core.value represeting a Task in kernel
20 str - string of ipc info for the task
23 format_string
= "{0: <#020x} {1: <6d} {2: <6d} {3: <10d} {4: <20s}"
24 busy_format
= " {0: <10d} {1: <6d}"
27 proc_name
= 'terminated: '
29 proc_name
+= 'halting: '
30 pval
= Cast(task
.bsd_info
, 'proc *')
32 proc_name
+= str(pval
.p_comm
)
33 elif int(task
.task_imp_base
) != 0 and hasattr(task
.task_imp_base
, 'iit_procname'):
34 proc_name
+= str(task
.task_imp_base
.iit_procname
)
35 table_size
= int(task
.itk_space
.is_table_size
)
36 out_string
+= format_string
.format(task
, pval
.p_pid
, task
.thread_count
, table_size
, proc_name
)
38 nbusy
, nmsgs
= GetTaskBusyPortsSummary(task
)
39 out_string
+= busy_format
.format(nbusy
, nmsgs
)
40 return (out_string
, table_size
, nbusy
, nmsgs
)
41 return (out_string
, table_size
)
43 @header("{0: <20s} {1: <6s} {2: <6s} {3: <10s} {4: <20s} {5: <10s} {6: <6s}".format("task", "pid", '#acts', "tablesize", "command", "#busyports", "#kmsgs"))
44 def GetTaskBusyIPCSummary(task
):
45 return GetTaskIPCSummary(task
, True)
47 def GetTaskBusyPortsSummary(task
):
52 while i
< isp
.is_table_size
:
53 iep
= addressof(isp
.is_table
[i
])
54 if iep
.ie_bits
& 0x00020000:
55 port
= Cast(iep
.ie_object
, 'ipc_port_t')
56 if port
.ip_messages
.data
.port
.msgcount
> 0:
58 nmsgs
+= port
.ip_messages
.data
.port
.msgcount
63 @header("{0: <20s} {1: <28s} {2: <12s} {3: <6s} {4: <4s} {5: <20s} {6: <4s}\n".format(
64 "port", "mqueue", "recvname", "flags", "refs", "recvname", "dest"))
65 def PrintPortSummary(port
, show_kmsg_summary
=True, prefix
=""):
66 """ Display a port's summary
68 port : core.value representing a port in the kernel
70 str : string of ipc info for the given port
73 portp
= Cast(port
, 'struct ipc_port *')
74 destspacep
= kern
.GetValueFromAddress(0, 'struct ipc_space *')
75 spacep
= portp
.data
.receiver
76 format_string
= "{0: #019x} {1: #019x} {2: <8s} {3: #011x} {4: <5s} {5: #05x} {6: #019x} {7: <16s}\n"
77 if portp
.ip_object
.io_bits
& 0x80000000:
78 out_string
+= prefix
+ format_string
.format(
79 unsigned(portp
), addressof(portp
.ip_messages
), ' '*8,
80 unsigned(portp
.ip_messages
.data
.port
.receiver_name
),
81 "APort", portp
.ip_object
.io_references
,
82 unsigned(portp
.ip_messages
.data
.port
.receiver_name
),
83 GetPortDestProc(portp
))
85 out_string
+= prefix
+ format_string
.format(
86 unsigned(portp
), addressof(portp
.ip_messages
), ' '*8,
87 unsigned(portp
.ip_messages
.data
.port
.receiver_name
),
88 "DPort", portp
.ip_object
.io_references
, unsigned(portp
),
92 kmsgp
= Cast(portp
.ip_messages
.data
.port
.messages
.ikmq_base
, 'ipc_kmsg_t')
94 print prefix
+ GetKMsgSummary
.header
+ prefix
+ GetKMsgSummary(kmsgp
, prefix
)
96 kmsgp
= kmsgp
.ikm_next
97 while (kmsgp
) != (kmsgheadp
):
98 print prefix
+ GetKMsgSummary(kmsgp
, prefix
)
99 kmsgp
= kmsgp
.ikm_next
102 def GetPortDestProc(portp
):
103 """ Display the name and pid of a given port's receiver
105 portp : core.value representing a pointer to a port in the kernel
106 destspacep : core.value representing a pointer to an ipc_space
108 str : string containing receiver's name and pid
110 spacep
= portp
.data
.receiver
111 out_str
= "Not found"
112 for tsk
in kern
.tasks
:
113 if tsk
.itk_space
== spacep
:
115 destprocp
= Cast(tsk
.bsd_info
, 'struct proc *')
116 out_str
= "{0:s}({1: <d})".format(destprocp
.p_comm
, destprocp
.p_pid
)
124 def GetPortDispositionString(disp
):
125 if (disp
< 0): ## use negative numbers for request ports
139 ## These dispositions should match those found in osfmk/mach/message.h
141 disp_str
= 'R' ## receive
143 disp_str
= 'dR' ## dispose receive
145 disp_str
= 'S' ## (move) send
147 disp_str
= 'cS' ## copy send
149 disp_str
= 'mS' ## make send
151 disp_str
= 'dS' ## dispose send
153 disp_str
= 'O' ## send-once
155 disp_str
= 'mO' ## make send-once
157 disp_str
= 'dO' ## dispose send-once
158 ## faux dispositions used to string-ify IPC entry types
160 disp_str
= 'PS' ## port set
162 disp_str
= 'dead' ## dead name
164 disp_str
= 'L' ## LABELH
166 disp_str
= 'V' ## Thread voucher (thread->ith_voucher->iv_port)
169 disp_str
= 'X' ## invalid
173 @header("{:<20s} {:<28s} {:<12s} {:<8s} {:<6s} {:<19s} {:<26s} {:<26s}\n".format(
174 "", "kmsg", "msgid", "disp", "size", "reply-port", "source", "destination"))
175 def GetKMsgSummary(kmsgp
, prefix_str
=""):
176 """ Display a summary for type ipc_kmsg_t
178 kmsgp : core.value representing the given ipc_kmsg_t struct
180 str : string of summary info for the given ipc_kmsg_t instance
182 kmsghp
= kmsgp
.ikm_header
183 kmsgh
= dereference(kmsghp
)
185 out_string
+= "{0: <20s} {1: <#019x} {2: <8s} {3: <#011x} ".format(
186 ' ', unsigned(kmsgp
), ' '*8, kmsgh
.msgh_id
)
187 prefix_str
= "{0: <20s} ".format(' ') + prefix_str
189 bits
= kmsgh
.msgh_bits
& 0xff
197 disposition
= "rX" # invalid
199 out_string
+= "{0: <2s}".format(disposition
)
203 bits
= (kmsgh
.msgh_bits
& 0xff00) >> 8
212 disposition
= "lX" # invalid
214 out_string
+= "{0: <2s}".format(disposition
)
218 bits
= (kmsgh
.msgh_bits
& 0xff0000) >> 16
227 out_string
+= "{0: <2s}".format(disposition
)
230 if kmsgh
.msgh_bits
& 0x80000000:
231 out_string
+= "{0: <1s}".format("c")
233 out_string
+= "{0: <1s}".format("s")
236 if kmsgh
.msgh_bits
& 0x20000000:
237 out_string
+= "{0: <1s}".format("I")
239 out_string
+= "{0: <1s}".format("-")
242 if kmsgp
.ikm_header
.msgh_remote_port
:
243 dest_proc_name
= GetDestinationProcessFromPort(kmsgp
.ikm_header
.msgh_remote_port
)
245 out_string
+= "{0: ^6d} {1: <#019x} {2: <26s} {3: <26s}\n".format(
246 unsigned(kmsgh
.msgh_size
), unsigned(kmsgh
.msgh_local_port
),
247 GetKMsgSrc(kmsgp
), dest_proc_name
)
249 if kmsgh
.msgh_bits
& 0x80000000:
250 out_string
+= prefix_str
+ "\t" + GetKMsgComplexBodyDesc
.header
+ "\n"
251 out_string
+= prefix_str
+ "\t" + GetKMsgComplexBodyDesc(kmsgp
, prefix_str
+ "\t") + "\n"
255 @header("{: <20s} {: <20s} {: <10s}".format("descriptor", "address", "size"))
256 def GetMachMsgOOLDescriptorSummary(desc
):
257 """ Returns description for mach_msg_ool_descriptor_t * object
259 format_string
= "{: <#020x} {: <#020x} {: <#010x}"
260 out_string
= format_string
.format(desc
, desc
.address
, desc
.size
)
264 def GetKmsgDescriptors(kmsgp
):
265 """ Get a list of descriptors in a complex message
267 kmsghp
= kmsgp
.ikm_header
268 kmsgh
= dereference(kmsghp
)
269 if not (kmsgh
.msgh_bits
& 0x80000000):
271 ## Something in the python/lldb types is not getting alignment correct here.
272 ## I'm grabbing a pointer to the body manually, and using tribal knowledge
273 ## of the location of the descriptor count to get this correct
274 body
= Cast(addressof(Cast(addressof(kmsgh
), 'char *')[sizeof(kmsgh
)]), 'mach_msg_body_t *')
275 #dsc_count = body.msgh_descriptor_count
276 dsc_count
= dereference(Cast(body
, 'uint32_t *'))
277 #dschead = Cast(addressof(body[1]), 'mach_msg_descriptor_t *')
278 dschead
= Cast(addressof(Cast(addressof(body
[0]), 'char *')[sizeof('uint32_t')]), 'mach_msg_descriptor_t *')
280 for i
in range(dsc_count
):
281 dsc_list
.append(dschead
[i
])
282 return (body
, dschead
, dsc_list
)
285 @header("{: <20s} {: <8s} {: <20s} {: <10s} {: <20s}".format("kmsgheader", "size", "body", "ds_count", "dsc_head"))
286 def GetKMsgComplexBodyDesc(kmsgp
, prefix_str
=""):
287 """ Routine that prints a complex kmsg's body
289 kmsghp
= kmsgp
.ikm_header
290 kmsgh
= dereference(kmsghp
)
291 if not (kmsgh
.msgh_bits
& 0x80000000):
293 format_string
= "{: <#020x} {: <#08x} {: <#020x} {: <#010x} {: <#020x}"
296 (body
, dschead
, dsc_list
) = GetKmsgDescriptors(kmsgp
)
297 out_string
+= format_string
.format(kmsghp
, sizeof(dereference(kmsghp
)), body
, len(dsc_list
), dschead
)
300 dsc_type
= unsigned(dsc
.type.type)
301 out_string
+= "\n" + prefix_str
+ "Descriptor: " + xnudefines
.mach_msg_type_descriptor_strings
[dsc_type
]
305 dstr
= GetPortDispositionString(dsc
.port
.disposition
)
306 out_string
+= " disp:{:s}, name:{: <#20x}".format(dstr
, p
)
307 elif unsigned(dsc
.type.type) in (1,3):
308 # its OOL DESCRIPTOR or OOL VOLATILE DESCRIPTOR
309 ool
= dsc
.out_of_line
310 out_string
+= " " + GetMachMsgOOLDescriptorSummary(addressof(ool
))
312 out_string
+= "\n" + prefix_str
+ "Invalid Descriptor: {}".format(dsc
)
315 def GetKMsgSrc(kmsgp
):
316 """ Routine that prints a kmsg's source process and pid details
318 kmsgp : core.value representing the given ipc_kmsg_t struct
320 str : string containing the name and pid of the kmsg's source proc
322 kmsgsrchp
= Cast(kmsgp
, 'ipc_kmsg_t').ikm_header
323 kmsgpid
= int(Cast(kern
.GetValueFromAddress(unsigned(kmsgsrchp
) + kmsgsrchp
.msgh_size
, 'uint *')[10], 'pid_t'))
325 return "{0:s} ({1:d})".format(GetProcNameForPid(kmsgpid
), kmsgpid
)
328 def PrintPortSetMembers(space
, setid
, show_kmsg_summary
):
329 """ Print out the members of a given IPC PSet
331 num_entries
= int(space
.is_table_size
)
332 is_tableval
= space
.is_table
333 setid_str
= GetWaitqSetidString(setid
)
335 prefix_str
= "{0:<21s}".format(' '*21)
338 if config
['verbosity'] > vHUMAN
:
342 while idx
< num_entries
:
343 entryval
= GetObjectAtIndexFromArray(is_tableval
, idx
)
344 ie_bits
= unsigned(entryval
.ie_bits
)
345 if not (ie_bits
& 0x00180000):
346 # It's a port entry that's _not_ dead
347 portval
= Cast(entryval
.ie_object
, 'ipc_port_t')
348 waitq
= addressof(portval
.ip_messages
.data
.port
.waitq
)
349 psets
= GetWaitqSets(addressof(portval
.ip_messages
.data
.port
.waitq
))
354 print "{:s}\n{:s}{:s}".format(GetPortDestProc(portval
), prefix_str
, PrintPortSummary
.header
)
355 PrintPortSummary(portval
, show_kmsg_summary
, prefix_str
)
357 sys
.stderr
.write('{:d}/{:d}... \r'.format(idx
, num_entries
))
361 def FindEntryName(obj
, space
):
362 """ Routine to locate a port/ipc_object in an ipc_space
363 and return the name within that space.
368 num_entries
= int(space
.is_table_size
)
369 is_tableval
= space
.is_table
371 while idx
< num_entries
:
372 entry_val
= GetObjectAtIndexFromArray(is_tableval
, idx
)
373 entry_bits
= unsigned(entry_val
.ie_bits
)
375 if (int(entry_bits
) & 0x001f0000) != 0: ## it's a valid entry
376 entry_obj
= unsigned(entry_val
.ie_object
)
377 if entry_obj
== unsigned(obj
):
378 nm
= (idx
<< 8) |
(entry_bits
>> 24)
384 @header("{0: <20s} {1: <28s} {2: <12s} {3: <6s} {4: <6s} {5: <20s} {6: <7s}\n".format(
385 "portset", "waitqueue", "recvname", "flags", "refs", "recvname", "process"))
386 def PrintPortSetSummary(pset
, space
= 0):
387 """ Display summary for a given struct ipc_pset *
389 pset : core.value representing a pset in the kernel
391 str : string of summary information for the given pset
394 show_kmsg_summary
= False
395 if config
['verbosity'] > vHUMAN
:
396 show_kmsg_summary
= True
398 local_name
= FindEntryName(pset
, space
)
400 if pset
.ips_object
.io_bits
& 0x80000000:
401 setid
= pset
.ips_messages
.data
.pset
.setq
.wqset_id
402 out_str
+= "{0: #019x} {1: #019x} {2: <7s} {3: #011x} {4: <4s} {5: >6d} {6: #019x} ".format(
403 unsigned(pset
), addressof(pset
.ips_messages
), ' '*7,
405 pset
.ips_object
.io_references
,
409 out_str
+= "{0: #019x} {1: #019x} {2: <7s} {3: #011x} {4: <4s} {5: >6d} {6: #019x} ".format(
410 unsigned(pset
), addressof(pset
.ips_messages
), ' '*7,
412 pset
.ips_object
.io_references
,
416 if setid
!= 0 and space
!= 0:
417 PrintPortSetMembers(space
, setid
, show_kmsg_summary
)
423 @lldb_command('showipc')
424 def ShowIPC(cmd_args
=None):
425 """ Routine to print data for the given IPC space
426 Usage: showipc <address of ipc space>
429 print "No arguments passed"
430 print ShowIPC
.__doc
__
432 ipc
= kern
.GetValueFromAddress(cmd_args
[0], 'ipc_space *')
434 print "unknown arguments:", str(cmd_args
)
436 print PrintIPCInformation
.header
437 PrintIPCInformation(ipc
, False, False)
443 @lldb_command('showtaskipc')
444 def ShowTaskIPC(cmd_args
=None):
445 """ Routine to print IPC summary of given task
446 Usage: showtaskipc <address of task>
449 print "No arguments passed"
450 print ShowTaskIPC
.__doc
__
452 tval
= kern
.GetValueFromAddress(cmd_args
[0], 'task *')
454 print "unknown arguments:", str(cmd_args
)
456 print GetTaskSummary
.header
+ " " + GetProcSummary
.header
457 pval
= Cast(tval
.bsd_info
, 'proc *')
458 print GetTaskSummary(tval
) + " " + GetProcSummary(pval
)
459 print GetTaskBusyIPCSummary
.header
460 (summary
, table_size
, nbusy
, nmsgs
) = GetTaskBusyIPCSummary(tval
)
463 # EndMacro: showtaskipc
467 @lldb_command('showallipc')
468 def ShowAllIPC(cmd_args
=None):
469 """ Routine to print IPC summary of all tasks
473 print GetTaskSummary
.header
+ " " + GetProcSummary
.header
474 pval
= Cast(t
.bsd_info
, 'proc *')
475 print GetTaskSummary(t
) + " " + GetProcSummary(pval
)
476 print PrintIPCInformation
.header
477 PrintIPCInformation(t
.itk_space
, False, False) + "\n\n"
479 # EndMacro: showallipc
481 @lldb_command('showipcsummary', fancy
=True)
482 def ShowIPCSummary(cmd_args
=None, cmd_options
={}, O
=None):
483 """ Summarizes the IPC state of all tasks.
484 This is a convenient way to dump some basic clues about IPC messaging. You can use the output to determine
485 tasks that are candidates for further investigation.
487 with O
.table(GetTaskIPCSummary
.header
):
490 (summary
, table_size
) = GetTaskIPCSummary(t
)
491 ipc_table_size
+= table_size
493 for t
in kern
.terminated_tasks
:
494 (summary
, table_size
) = GetTaskIPCSummary(t
)
495 ipc_table_size
+= table_size
496 print "Total Table size: {:d}".format(ipc_table_size
)
498 def GetKObjectFromPort(portval
):
499 """ Get Kobject description from the port.
500 params: portval - core.value representation of 'ipc_port *' object
501 returns: str - string of kobject information
503 io_bits
= unsigned(portval
.ip_object
.io_bits
)
505 kobject_val
= portval
.kdata
.kolabel
.ikol_kobject
507 kobject_val
= portval
.kdata
.kobject
508 kobject_str
= "{0: <#020x}".format(kobject_val
)
509 objtype_index
= io_bits
& 0x3ff
510 if objtype_index
< len(xnudefines
.kobject_types
) :
511 objtype_str
= xnudefines
.kobject_types
[objtype_index
]
512 if objtype_str
== 'IOKIT_OBJ':
513 iokit_classnm
= GetObjectTypeStr(kobject_val
)
514 if not iokit_classnm
:
515 iokit_classnm
= "<unknown class>"
517 iokit_classnm
= re
.sub(r
'vtable for ', r
'', iokit_classnm
)
518 desc_str
= "kobject({:s}:{:s})".format(objtype_str
, iokit_classnm
)
520 desc_str
= "kobject({0:s})".format(objtype_str
)
521 if xnudefines
.kobject_types
[objtype_index
] in ('TASK_RESUME', 'TASK'):
522 desc_str
+= " " + GetProcNameForTask(Cast(kobject_val
, 'task *'))
524 desc_str
= "kobject(UNKNOWN) {:d}".format(objtype_index
)
525 return kobject_str
+ " " + desc_str
527 @static_var('destcache', {})
528 def GetDestinationProcessFromPort(port
):
530 params: port - core.value representation of 'ipc_port *' object
531 returns: str - name of process
534 dest_space
= port
.data
.receiver
536 #update destcache if data is not found
537 if hex(dest_space
) not in GetDestinationProcessFromPort
.destcache
:
539 if hex(t
.itk_space
) == hex(dest_space
):
540 pval
= Cast(t
.bsd_info
, 'proc *')
541 GetDestinationProcessFromPort
.destcache
[hex(dest_space
)] = (t
, pval
)
545 else: found_dest
= True
548 (ftask
, fproc
) = GetDestinationProcessFromPort
.destcache
[hex(dest_space
)]
550 out_str
= "{0:s}({1:d})".format(fproc
.p_comm
, fproc
.p_pid
)
552 out_str
= "task {0: <#020x}".format(ftask
)
557 @header("{0: <20s} {1: <20s}".format("destname", "destination") )
558 def GetPortDestinationSummary(port
):
559 """ Get destination information for a port.
560 params: port - core.value representation of 'ipc_port *' object
561 returns: str - string of info about ports destination
564 format_string
= "{0: <20s} {1: <20s}"
567 target_spaceval
= port
.data
.receiver
568 if int(port
.ip_object
.io_bits
) & 0x800 :
569 destname_str
= GetKObjectFromPort(port
)
571 if int(port
.ip_object
.io_bits
) & 0x80000000 :
572 destname_str
= "{0: <#020x}".format(port
.ip_messages
.data
.port
.receiver_name
)
573 destination_str
= GetDestinationProcessFromPort(port
)
575 destname_str
= "{0: <#020x}".format(port
)
576 destination_str
= "inactive-port"
578 out_str
+= format_string
.format(destname_str
, destination_str
)
581 @lldb_type_summary(['ipc_entry_t'])
582 @header("{: <20s} {: <12s} {: <8s} {: <8s} {: <8s} {: <8s} {: <20s} {: <20s}".format("object", "name", "rite", "urefs", "nsets", "nmsgs", "destname", "destination"))
583 def GetIPCEntrySummary(entry
, ipc_name
='', rights_filter
=0):
584 """ Get summary of a ipc entry.
586 entry - core.value representing ipc_entry_t in the kernel
587 ipc_name - str of format '0x0123' for display in summary.
589 str - string of ipc entry related information
596 'O' : Send-once right
597 'm' : Immovable send port
598 'i' : Immovable receive port
600 types of notifications:
601 'd' : Dead-Name notification requested
602 's' : Send-Possible notification armed
603 'r' : Send-Possible notification requested
604 'n' : No-Senders notification requested
605 'x' : Port-destroy notification requested
608 entry_ptr
= int(hex(entry
), 16)
609 format_string
= "{: <#020x} {: <12s} {: <8s} {: <8d} {: <8d} {: <8d} {: <20s} {: <20s}"
614 ie_object
= entry
.ie_object
615 ie_bits
= int(entry
.ie_bits
)
616 urefs
= int(ie_bits
& 0xffff)
619 if ie_bits
& 0x00100000 :
621 elif ie_bits
& 0x00080000:
623 psetval
= Cast(ie_object
, 'ipc_pset *')
624 set_str
= GetWaitqSets(addressof(psetval
.ips_messages
.data
.pset
.setq
.wqset_q
))
628 if ie_bits
& 0x00010000 :
629 if ie_bits
& 0x00020000 :
635 elif ie_bits
& 0x00020000:
638 elif ie_bits
& 0x00040000 :
641 portval
= Cast(ie_object
, 'ipc_port_t')
642 if int(entry
.index
.request
) != 0:
643 requestsval
= portval
.ip_requests
644 sorightval
= requestsval
[int(entry
.index
.request
)].notify
.port
645 soright_ptr
= unsigned(sorightval
)
647 # dead-name notification requested
649 # send-possible armed
650 if soright_ptr
& 0x1 : right_str
+='s'
651 # send-possible requested
652 if soright_ptr
& 0x2 : right_str
+='r'
653 # No-senders notification requested
654 if portval
.ip_nsrequest
!= 0: right_str
+= 'n'
655 # port-destroy notification requested
656 if portval
.ip_pdrequest
!= 0: right_str
+= 'x'
657 # Immovable receive rights
658 if portval
.ip_immovable_receive
!= 0: right_str
+= 'i'
659 # Immovable send rights
660 if portval
.ip_immovable_send
!= 0: right_str
+= 'm'
662 if portval
.ip_no_grant
!= 0: right_str
+= 'g'
664 # early-out if the rights-filter doesn't match
665 if rights_filter
!= 0 and rights_filter
!= right_str
:
668 # append the generation to the name value
669 # (from osfmk/ipc/ipc_entry.h)
670 # bits rollover period
675 ie_gen_roll
= { 0:'.64', 1:'.48', 2:'.32', 3:'.16' }
676 ipc_name
= '{:s}{:s}'.format(ipc_name
.strip(), ie_gen_roll
[(ie_bits
& 0x00c00000) >> 22])
678 # now show the port destination part
679 destname_str
= GetPortDestinationSummary(Cast(ie_object
, 'ipc_port_t'))
680 # Get the number of sets to which this port belongs
681 set_str
= GetWaitqSets(addressof(portval
.ip_messages
.data
.port
.waitq
))
683 nmsgs
= portval
.ip_messages
.data
.port
.msgcount
684 if rights_filter
== 0 or rights_filter
== right_str
:
685 out_str
= format_string
.format(ie_object
, ipc_name
, right_str
, urefs
, nsets
, nmsgs
, destname_str
, destination_str
)
688 @header("{0: >20s}".format("user bt") )
689 def GetPortUserStack(port
, task
):
690 """ Get UserStack information for the given port & task.
691 params: port - core.value representation of 'ipc_port *' object
692 task - value representing 'task *' object
693 returns: str - string information on port's userstack
696 ie_port_callstack
= port
.ip_callstack
697 ie_port_spares
= port
.ip_spares
[0]
698 proc_val
= Cast(task
.bsd_info
, 'proc *')
699 if ie_port_callstack
[0]:
700 out_str
+= "{: <10x}".format(ie_port_callstack
[0])
702 while count
< 16 and ie_port_callstack
[count
]:
703 out_str
+= ": <10x".format(ie_port_callstack
[count
])
705 if ie_port_spares
!= proc_val
.p_pid
:
706 out_str
+= " ({:<10d})".format(ie_port_spares
)
710 @lldb_type_summary(['ipc_space *'])
711 @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'))
712 def PrintIPCInformation(space
, show_entries
=False, show_userstack
=False, rights_filter
=0):
713 """ Provide a summary of the ipc space
716 format_string
= "{0: <#020x} {1: <#020x} {2: <#020x} {3: <8s} {4: <10d} {5: <#18x} {6: >8d} {7: <8d}"
717 is_tableval
= space
.is_table
718 ports
= int(space
.is_table_size
)
720 is_bits
= int(space
.is_bits
)
721 if (is_bits
& 0x40000000) == 0: flags
+='A'
723 if (is_bits
& 0x20000000) != 0: flags
+='G'
724 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
)
726 #should show the each individual entries if asked.
727 if show_entries
== True:
728 print "\t" + GetIPCEntrySummary
.header
731 while index
< num_entries
:
732 entryval
= GetObjectAtIndexFromArray(is_tableval
, index
)
733 entry_ie_bits
= unsigned(entryval
.ie_bits
)
734 if (int(entry_ie_bits
) & 0x001f0000 ) != 0:
735 entry_name
= "{0: <#020x}".format( (index
<<8 | entry_ie_bits
>> 24) )
736 entry_str
= GetIPCEntrySummary(entryval
, entry_name
, rights_filter
)
737 if len(entry_str
) > 0:
738 print " \r\t" + entry_str
739 if show_userstack
== True:
740 entryport
= Cast(entryval
.ie_object
, 'ipc_port *')
741 if entryval
.ie_object
and (int(entry_ie_bits
) & 0x00070000) and entryport
.ip_callstack
[0]:
742 print GetPortUserStack
.header
+ GetPortUserStack(entryport
, space
.is_task
)
744 # give some progress indication (this is especially
745 # helpful for tasks with large sets of rights)
746 sys
.stderr
.write(' {:d}/{:d}...\r'.format(index
, num_entries
))
748 #done with showing entries
753 @lldb_command('showrights', 'R:')
754 def ShowRights(cmd_args
=None, cmd_options
={}):
755 """ Routine to print rights information for the given IPC space
756 Usage: showrights [-R rights_type] <address of ipc space>
757 -R rights_type : only display rights matching the string 'rights_type'
764 'O' : Send-once right
765 types of notifications:
766 'd' : Dead-Name notification requested
767 's' : Send-Possible notification armed
768 'r' : Send-Possible notification requested
769 'n' : No-Senders notification requested
770 'x' : Port-destroy notification requested
773 print "No arguments passed"
774 print ShowRights
.__doc
__
776 ipc
= kern
.GetValueFromAddress(cmd_args
[0], 'ipc_space *')
778 print "unknown arguments:", str(cmd_args
)
781 if "-R" in cmd_options
:
782 rights_type
= cmd_options
["-R"]
783 print PrintIPCInformation
.header
784 PrintIPCInformation(ipc
, True, False, rights_type
)
786 # EndMacro: showrights
788 @lldb_command('showtaskrights','R:')
789 def ShowTaskRights(cmd_args
=None, cmd_options
={}):
790 """ Routine to ipc rights information for a task
791 Usage: showtaskrights [-R rights_type] <task address>
792 -R rights_type : only display rights matching the string 'rights_type'
799 'O' : Send-once right
800 'm' : Immovable send port
801 'i' : Immovable receive port
803 types of notifications:
804 'd' : Dead-Name notification requested
805 's' : Send-Possible notification armed
806 'r' : Send-Possible notification requested
807 'n' : No-Senders notification requested
808 'x' : Port-destroy notification requested
811 print "No arguments passed"
812 print ShowTaskStacksCmdHelper
.__doc
__
814 tval
= kern
.GetValueFromAddress(cmd_args
[0], 'task *')
816 print "unknown arguments:", str(cmd_args
)
819 if "-R" in cmd_options
:
820 rights_type
= cmd_options
["-R"]
821 print GetTaskSummary
.header
+ " " + GetProcSummary
.header
822 pval
= Cast(tval
.bsd_info
, 'proc *')
823 print GetTaskSummary(tval
) + " " + GetProcSummary(pval
)
824 print PrintIPCInformation
.header
825 PrintIPCInformation(tval
.itk_space
, True, False, rights_type
)
827 # Macro: showataskrightsbt
829 @lldb_command('showtaskrightsbt', 'R:')
830 def ShowTaskRightsBt(cmd_args
=None, cmd_options
={}):
831 """ Routine to ipc rights information with userstacks for a task
832 Usage: showtaskrightsbt [-R rights_type] <task address>
833 -R rights_type : only display rights matching the string 'rights_type'
840 'O' : Send-once right
841 'm' : Immovable send port
842 'i' : Immovable receive port
844 types of notifications:
845 'd' : Dead-Name notification requested
846 's' : Send-Possible notification armed
847 'r' : Send-Possible notification requested
848 'n' : No-Senders notification requested
849 'x' : Port-destroy notification requested
852 print "No arguments passed"
853 print ShowTaskRightsBt
.__doc
__
855 tval
= kern
.GetValueFromAddress(cmd_args
[0], 'task *')
857 print "unknown arguments:", str(cmd_args
)
860 if "-R" in cmd_options
:
861 rights_type
= cmd_options
["-R"]
862 print GetTaskSummary
.header
+ " " + GetProcSummary
.header
863 pval
= Cast(tval
.bsd_info
, 'proc *')
864 print GetTaskSummary(tval
) + " " + GetProcSummary(pval
)
865 print PrintIPCInformation
.header
866 PrintIPCInformation(tval
.itk_space
, True, True, rights_type
)
868 # EndMacro: showtaskrightsbt
870 # Macro: showallrights
872 @lldb_command('showallrights', 'R:')
873 def ShowAllRights(cmd_args
=None, cmd_options
={}):
874 """ Routine to print rights information for IPC space of all tasks
875 Usage: showallrights [-R rights_type]
876 -R rights_type : only display rights matching the string 'rights_type'
883 'O' : Send-once right
884 'm' : Immovable send port
885 'i' : Immovable receive port
887 types of notifications:
888 'd' : Dead-Name notification requested
889 's' : Send-Possible notification armed
890 'r' : Send-Possible notification requested
891 'n' : No-Senders notification requested
892 'x' : Port-destroy notification requested
895 if "-R" in cmd_options
:
896 rights_type
= cmd_options
["-R"]
898 print GetTaskSummary
.header
+ " " + GetProcSummary
.header
899 pval
= Cast(t
.bsd_info
, 'proc *')
900 print GetTaskSummary(t
) + " " + GetProcSummary(pval
)
902 print PrintIPCInformation
.header
903 PrintIPCInformation(t
.itk_space
, True, False, rights_type
) + "\n\n"
904 except (KeyboardInterrupt, SystemExit):
907 print "Failed to get IPC information. Do individual showtaskrights <task> to find the error. \n\n"
909 # EndMacro: showallrights
912 def GetInTransitPortSummary(port
, disp
, holding_port
, holding_kmsg
):
913 """ String-ify the in-transit dispostion of a port.
915 ## This should match the summary generated by GetIPCEntrySummary
916 ## "object" "name" "rite" "urefs" "nsets" "nmsgs" "destname" "destination"
917 format_str
= "\t{: <#20x} {: <12} {: <8s} {: <8d} {: <8d} {: <8d} p:{: <#19x} k:{: <#19x}"
918 portname
= 'intransit'
920 disp_str
= GetPortDispositionString(disp
)
922 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
))
926 def GetDispositionFromEntryType(entry_bits
):
927 """ Translate an IPC entry type into an in-transit disposition. This allows
928 the GetInTransitPortSummary function to be re-used to string-ify IPC
931 ebits
= int(entry_bits
)
932 if (ebits
& 0x003f0000) == 0:
935 if (ebits
& 0x00010000) != 0:
936 return 17 ## MACH_PORT_RIGHT_SEND
937 elif (ebits
& 0x00020000) != 0:
938 return 16 ## MACH_PORT_RIGHT_RECEIVE
939 elif (ebits
& 0x00040000) != 0:
940 return 18 ## MACH_PORT_RIGHT_SEND_ONCE
941 elif (ebits
& 0x00080000) != 0:
942 return 100 ## MACH_PORT_RIGHT_PORT_SET
943 elif (ebits
& 0x00100000) != 0:
944 return 101 ## MACH_PORT_RIGHT_DEAD_NAME
945 elif (ebits
& 0x00200000) != 0:
946 return 102 ## MACH_PORT_RIGHT_LABELH
950 def GetDispositionFromVoucherPort(th_vport
):
951 """ Translate a thread's voucher port into a 'disposition'
953 if unsigned(th_vport
) > 0:
954 return 103 ## Voucher type
971 def PrintProgressForKmsg():
974 sys
.stderr
.write(" {:<1s}\r".format(g_progmeter
[g_kmsg_prog
% 9]))
978 def CollectPortsForAnalysis(port
, disposition
):
981 p
= Cast(port
, 'struct ipc_port *')
982 yield (p
, disposition
)
984 # no-senders notification port
985 if unsigned(p
.ip_nsrequest
) != 0:
986 PrintProgressForKmsg()
987 yield (Cast(p
.ip_nsrequest
, 'struct ipc_port *'), -1)
989 # port-death notification port
990 if unsigned(p
.ip_pdrequest
) != 0:
991 PrintProgressForKmsg()
992 yield (Cast(p
.ip_pdrequest
, 'struct ipc_port *'), -2)
994 ## ports can have many send-possible notifications armed: go through the table!
995 if unsigned(p
.ip_requests
) != 0:
996 table
= Cast(p
.ip_requests
, 'struct ipc_port_request *')
997 table_sz
= int(table
.name
.size
.its_size
)
998 for i
in range(table_sz
):
1002 if unsigned(ipr
.name
.name
) != 0:
1003 ipr_bits
= unsigned(ipr
.notify
.port
) & 3
1004 ipr_port
= kern
.GetValueFromAddress(int(ipr
.notify
.port
) & ~
3, 'struct ipc_port *')
1006 if ipr_bits
& 3: ## send-possible armed and requested
1008 elif ipr_bits
& 2: ## send-possible requested
1010 elif ipr_bits
& 1: ## send-possible armed
1012 PrintProgressForKmsg()
1013 yield (ipr_port
, ipr_disp
)
1016 def CollectKmsgPorts(task
, task_port
, kmsgp
):
1017 """ Look through a message, 'kmsgp' destined for 'task'
1018 (enqueued on task_port). Collect any port descriptors,
1019 remote, local, voucher, or other port references
1020 into a (ipc_port_t, disposition) list.
1022 kmsgh
= dereference(kmsgp
.ikm_header
)
1026 PrintProgressForKmsg()
1027 if kmsgh
.msgh_remote_port
and unsigned(kmsgh
.msgh_remote_port
) != unsigned(task_port
):
1028 disp
= kmsgh
.msgh_bits
& 0x1f
1029 p_list
+= list(CollectPortsForAnalysis(kmsgh
.msgh_remote_port
, disp
))
1031 if kmsgh
.msgh_local_port
and unsigned(kmsgh
.msgh_local_port
) != unsigned(task_port
) \
1032 and unsigned(kmsgh
.msgh_local_port
) != unsigned(kmsgh
.msgh_remote_port
):
1033 disp
= (kmsgh
.msgh_bits
& 0x1f00) >> 8
1034 p_list
+= list(CollectPortsForAnalysis(kmsgh
.msgh_local_port
, disp
))
1036 if kmsgp
.ikm_voucher
:
1037 p_list
+= list(CollectPortsForAnalysis(kmsgp
.ikm_voucher
, 0))
1039 if kmsgh
.msgh_bits
& 0x80000000:
1040 ## Complex message - look for descriptors
1041 PrintProgressForKmsg()
1042 (body
, dschead
, dsc_list
) = GetKmsgDescriptors(kmsgp
)
1043 for dsc
in dsc_list
:
1044 PrintProgressForKmsg()
1045 dsc_type
= unsigned(dsc
.type.type)
1046 if dsc_type
== 0 or dsc_type
== 2: ## 0 == port, 2 == ool port
1048 ## its a port descriptor
1049 dsc_disp
= dsc
.port
.disposition
1050 p_list
+= list(CollectPortsForAnalysis(dsc
.port
.name
, dsc_disp
))
1052 ## it's an ool_ports descriptor which is an array of ports
1053 dsc_disp
= dsc
.ool_ports
.disposition
1054 dispdata
= Cast(dsc
.ool_ports
.address
, 'struct ipc_port *')
1055 for pidx
in range(dsc
.ool_ports
.count
):
1056 PrintProgressForKmsg()
1057 p_list
+= list(CollectPortsForAnalysis(dispdata
[pidx
], dsc_disp
))
1060 def CollectKmsgPortRefs(task
, task_port
, kmsgp
, p_refs
):
1061 """ Recursively collect all references to ports inside the kmsg 'kmsgp'
1062 into the set 'p_refs'
1064 p_list
= CollectKmsgPorts(task
, task_port
, kmsgp
)
1066 ## Iterate over each ports we've collected, to see if they
1067 ## have messages on them, and then recurse!
1068 for p
, pdisp
in p_list
:
1069 ptype
= (p
.ip_object
.io_bits
& 0x7fff0000) >> 16
1070 p_refs
.add((p
, pdisp
, ptype
))
1071 if ptype
!= 0: ## don't bother with port sets
1073 ## If the port that's in-transit has messages already enqueued,
1074 ## go through each of those messages and look for more ports!
1075 if p
.ip_messages
.data
.port
.msgcount
> 0:
1076 p_kmsgp
= Cast(p
.ip_messages
.data
.port
.messages
.ikmq_base
, 'ipc_kmsg_t')
1078 while unsigned(p_kmsgp
) > 0:
1079 CollectKmsgPortRefs(task
, p
, p_kmsgp
, p_refs
)
1080 p_kmsgp
= p_kmsgp
.ikm_next
1081 if p_kmsgp
== kmsgheadp
:
1085 def FindKmsgPortRefs(instr
, task
, task_port
, kmsgp
, qport
):
1086 """ Look through a message, 'kmsgp' destined for 'task'. If we find
1087 any port descriptors, remote, local, voucher, or other port that
1088 matches 'qport', return a short description
1089 which should match the format of GetIPCEntrySummary.
1093 p_list
= CollectKmsgPorts(task
, task_port
, kmsgp
)
1095 ## Run through all ports we've collected looking for 'qport'
1096 for p
, pdisp
in p_list
:
1097 PrintProgressForKmsg()
1098 if unsigned(p
) == unsigned(qport
):
1099 ## the port we're looking for was found in this message!
1100 if len(out_str
) > 0:
1102 out_str
+= GetInTransitPortSummary(p
, pdisp
, task_port
, kmsgp
)
1104 ptype
= (p
.ip_object
.io_bits
& 0x7fff0000) >> 16
1105 if ptype
!= 0: ## don't bother with port sets
1108 ## If the port that's in-transit has messages already enqueued,
1109 ## go through each of those messages and look for more ports!
1110 if p
.ip_messages
.data
.port
.msgcount
> 0:
1111 p_kmsgp
= Cast(p
.ip_messages
.data
.port
.messages
.ikmq_base
, 'ipc_kmsg_t')
1113 while unsigned(p_kmsgp
) > 0:
1114 out_str
= FindKmsgPortRefs(out_str
, task
, p
, p_kmsgp
, qport
)
1115 p_kmsgp
= p_kmsgp
.ikm_next
1116 if p_kmsgp
== kmsgheadp
:
1121 port_iteration_do_print_taskname
= False
1122 registeredport_idx
= -10
1124 intransit_idx
= -1000
1125 taskports_idx
= -2000
1128 def IterateAllPorts(tasklist
, func
, ctx
, include_psets
, follow_busyports
, should_log
):
1129 """ Iterate over all ports in the system, calling 'func'
1132 global port_iteration_do_print_taskname
1133 global intransit_idx
, taskports_idx
, thports_idx
, registeredport_idx
, excports_idx
1135 ## XXX: also host special ports
1137 entry_port_type_mask
= 0x00070000
1139 entry_port_type_mask
= 0x000f0000
1141 if tasklist
is None:
1142 tasklist
= kern
.tasks
1143 tasklist
+= kern
.terminated_tasks
1148 # Write a progress line. Using stderr avoids automatic newline when
1149 # writing to stdout from lldb. Blank spaces at the end clear out long
1154 procname
= 'terminated: '
1156 procname
+= 'halting: '
1157 t_p
= Cast(t
.bsd_info
, 'proc *')
1158 if unsigned(t_p
) != 0:
1159 procname
+= str(t_p
.p_name
)
1160 elif unsigned(t
.task_imp_base
) != 0 and hasattr(t
.task_imp_base
, 'iit_procname'):
1161 procname
+= str(t
.task_imp_base
.iit_procname
)
1162 sys
.stderr
.write(" checking {:s} ({}/{})...{:50s}\r".format(procname
, tidx
, len(tasklist
), ''))
1165 port_iteration_do_print_taskname
= True
1167 num_entries
= int(space
.is_table_size
)
1168 is_tableval
= space
.is_table
1170 while idx
< num_entries
:
1171 entry_val
= GetObjectAtIndexFromArray(is_tableval
, idx
)
1172 entry_bits
= unsigned(entry_val
.ie_bits
)
1175 entry_name
= "{:x}".format( (idx
<< 8 | entry_bits
>> 24) )
1177 entry_disp
= GetDispositionFromEntryType(entry_bits
)
1179 ## If the entry in the table represents a port of some sort,
1180 ## then make the callback provided
1181 if int(entry_bits
) & entry_port_type_mask
:
1182 eport
= Cast(entry_val
.ie_object
, 'ipc_port_t')
1183 ## Make the callback
1184 func(t
, space
, ctx
, idx
, entry_val
, eport
, entry_disp
)
1186 ## if the port has pending messages, look through
1187 ## each message for ports (and recurse)
1188 if follow_busyports
and unsigned(eport
) > 0 and eport
.ip_messages
.data
.port
.msgcount
> 0:
1189 ## collect all port references from all messages
1190 kmsgp
= Cast(eport
.ip_messages
.data
.port
.messages
.ikmq_base
, 'ipc_kmsg_t')
1192 while unsigned(kmsgp
) > 0:
1194 CollectKmsgPortRefs(t
, eport
, kmsgp
, p_refs
)
1195 for (port
, pdisp
, ptype
) in p_refs
:
1196 func(t
, space
, ctx
, intransit_idx
, None, port
, pdisp
)
1197 kmsgp
= kmsgp
.ikm_next
1198 if kmsgp
== kmsgheadp
:
1202 ## while (idx < num_entries)
1204 ## Task ports (send rights)
1205 if unsigned(t
.itk_sself
) > 0:
1206 func(t
, space
, ctx
, taskports_idx
, 0, t
.itk_sself
, 17)
1207 if unsigned(t
.itk_host
) > 0:
1208 func(t
, space
, ctx
, taskports_idx
, 0, t
.itk_host
, 17)
1209 if unsigned(t
.itk_bootstrap
) > 0:
1210 func(t
, space
, ctx
, taskports_idx
, 0, t
.itk_bootstrap
, 17)
1211 if unsigned(t
.itk_seatbelt
) > 0:
1212 func(t
, space
, ctx
, taskports_idx
, 0, t
.itk_seatbelt
, 17)
1213 if unsigned(t
.itk_gssd
) > 0:
1214 func(t
, space
, ctx
, taskports_idx
, 0, t
.itk_gssd
, 17)
1215 if unsigned(t
.itk_debug_control
) > 0:
1216 func(t
, space
, ctx
, taskports_idx
, 0, t
.itk_debug_control
, 17)
1217 if unsigned(t
.itk_task_access
) > 0:
1218 func(t
, space
, ctx
, taskports_idx
, 0, t
.itk_task_access
, 17)
1220 ## Task name port (not a send right, just a naked ref)
1221 if unsigned(t
.itk_nself
) > 0:
1222 func(t
, space
, ctx
, taskports_idx
, 0,t
.itk_nself
, 0)
1224 ## task resume port is a receive right to resume the task
1225 if unsigned(t
.itk_resume
) > 0:
1226 func(t
, space
, ctx
, taskports_idx
, 0, t
.itk_resume
, 16)
1228 ## registered task ports (all send rights)
1230 tr_max
= sizeof(t
.itk_registered
) / sizeof(t
.itk_registered
[0])
1231 while tr_idx
< tr_max
:
1232 tport
= t
.itk_registered
[tr_idx
]
1233 if unsigned(tport
) > 0:
1235 func(t
, space
, ctx
, registeredport_idx
, 0, tport
, 17)
1236 except Exception, e
:
1237 print("\texception looking through registered port {:d}/{:d} in {:s}".format(tr_idx
,tr_max
,t
))
1241 ## Task exception ports
1243 exmax
= sizeof(t
.exc_actions
) / sizeof(t
.exc_actions
[0])
1244 while exidx
< exmax
: ## see: osfmk/mach/[arm|i386]/exception.h
1245 export
= t
.exc_actions
[exidx
].port
## send right
1246 if unsigned(export
) > 0:
1248 func(t
, space
, ctx
, excports_idx
, 0, export
, 17)
1249 except Exception, e
:
1250 print("\texception looking through exception port {:d}/{:d} in {:s}".format(exidx
,exmax
,t
))
1254 ## XXX: any ports still valid after clearing IPC space?!
1256 for thval
in IterateQueue(t
.threads
, 'thread *', 'task_threads'):
1257 ## XXX: look at block reason to see if it's in mach_msg_receive - then look at saved state / message
1259 ## Thread port (send right)
1260 if unsigned(thval
.ith_sself
) > 0:
1261 thport
= thval
.ith_sself
1262 func(t
, space
, ctx
, thports_idx
, 0, thport
, 17) ## see: osfmk/mach/message.h
1263 ## Thread special reply port (send-once right)
1264 if unsigned(thval
.ith_special_reply_port
) > 0:
1265 thport
= thval
.ith_special_reply_port
1266 func(t
, space
, ctx
, thports_idx
, 0, thport
, 18) ## see: osfmk/mach/message.h
1267 ## Thread voucher port
1268 if unsigned(thval
.ith_voucher
) > 0:
1269 vport
= thval
.ith_voucher
.iv_port
1270 if unsigned(vport
) > 0:
1271 vdisp
= GetDispositionFromVoucherPort(vport
)
1272 func(t
, space
, ctx
, thports_idx
, 0, vport
, vdisp
)
1273 ## Thread exception ports
1274 if unsigned(thval
.exc_actions
) > 0:
1276 while exidx
< exmax
: ## see: osfmk/mach/[arm|i386]/exception.h
1277 export
= thval
.exc_actions
[exidx
].port
## send right
1278 if unsigned(export
) > 0:
1280 func(t
, space
, ctx
, excports_idx
, 0, export
, 17)
1281 except Exception, e
:
1282 print("\texception looking through exception port {:d}/{:d} in {:s}".format(exidx
,exmax
,t
))
1285 ## XXX: the message on a thread (that's currently being received)
1286 ## for (thval in t.threads)
1287 ## for (t in tasklist)
1290 # Macro: findportrights
1291 def FindPortRightsCallback(task
, space
, ctx
, entry_idx
, ipc_entry
, ipc_port
, port_disp
):
1292 """ Callback which uses 'ctx' as the (port,rights_types) tuple for which
1293 a caller is seeking references. This should *not* be used from a
1294 recursive call to IterateAllPorts.
1296 global port_iteration_do_print_taskname
1298 (qport
, rights_type
) = ctx
1301 if unsigned(ipc_entry
) != 0:
1302 entry_bits
= unsigned(ipc_entry
.ie_bits
)
1303 entry_name
= "{:x}".format( (entry_idx
<< 8 | entry_bits
>> 24) )
1304 if (int(entry_bits
) & 0x001f0000) != 0 and unsigned(ipc_entry
.ie_object
) == unsigned(qport
):
1305 ## it's a valid entry, and it points to the port
1306 entry_str
= '\t' + GetIPCEntrySummary(ipc_entry
, entry_name
, rights_type
)
1308 procname
= GetProcNameForTask(task
)
1309 if unsigned(ipc_port
) != 0 and ipc_port
.ip_messages
.data
.port
.msgcount
> 0:
1310 sys
.stderr
.write(" checking {:s} busy-port {}:{:#x}...{:30s}\r".format(procname
, entry_name
, unsigned(ipc_port
), ''))
1311 ## Search through busy ports to find descriptors which could
1312 ## contain the only reference to this port!
1313 kmsgp
= Cast(ipc_port
.ip_messages
.data
.port
.messages
.ikmq_base
, 'ipc_kmsg_t')
1315 while unsigned(kmsgp
):
1316 entry_str
= FindKmsgPortRefs(entry_str
, task
, ipc_port
, kmsgp
, qport
)
1317 kmsgp
= kmsgp
.ikm_next
1318 if kmsgp
== kmsgheadp
:
1320 if len(entry_str
) > 0:
1321 sys
.stderr
.write("{:80s}\r".format(''))
1322 if port_iteration_do_print_taskname
:
1323 print "Task: {0: <#x} {1: <s}".format(task
, procname
)
1324 print '\t' + GetIPCEntrySummary
.header
1325 port_iteration_do_print_taskname
= False
1328 @lldb_command('findportrights', 'R:S:')
1329 def FindPortRights(cmd_args
=None, cmd_options
={}):
1330 """ Routine to locate and print all extant rights to a given port
1331 Usage: findportrights [-R rights_type] [-S <ipc_space_t>] <ipc_port_t>
1332 -S ipc_space : only search the specified ipc space
1333 -R rights_type : only display rights matching the string 'rights_type'
1340 'O' : Send-once right
1341 types of notifications:
1342 'd' : Dead-Name notification requested
1343 's' : Send-Possible notification armed
1344 'r' : Send-Possible notification requested
1345 'n' : No-Senders notification requested
1346 'x' : Port-destroy notification requested
1349 raise ArgumentError("no port address provided")
1350 port
= kern
.GetValueFromAddress(cmd_args
[0], 'struct ipc_port *')
1353 if "-R" in cmd_options
:
1354 rights_type
= cmd_options
["-R"]
1357 if "-S" in cmd_options
:
1358 space
= kern
.GetValueFromAddress(cmd_options
["-S"], 'struct ipc_space *')
1359 tasklist
= [ space
.is_task
]
1361 ## Don't include port sets
1362 ## Don't recurse on busy ports (we do that manually)
1364 IterateAllPorts(tasklist
, FindPortRightsCallback
, (port
, rights_type
), False, False, True)
1365 sys
.stderr
.write("{:120s}\r".format(' '))
1369 # EndMacro: findportrights
1371 # Macro: countallports
1373 def CountPortsCallback(task
, space
, ctx
, entry_idx
, ipc_entry
, ipc_port
, port_disp
):
1374 """ Callback which uses 'ctx' as the set of all ports found in the
1375 iteration. This should *not* be used from a recursive
1376 call to IterateAllPorts.
1378 global intransit_idx
1380 (p_set
, p_intransit
, p_bytask
) = ctx
1382 ## Add the port address to the set of all port addresses
1383 p_set
.add(unsigned(ipc_port
))
1385 if entry_idx
== intransit_idx
:
1386 p_intransit
.add(unsigned(ipc_port
))
1388 if task
.active
or (task
.halting
and not task
.active
):
1389 pname
= str(Cast(task
.bsd_info
, 'proc *').p_name
)
1390 if not pname
in p_bytask
.keys():
1391 p_bytask
[pname
] = { 'transit':0, 'table':0, 'other':0 }
1392 if entry_idx
== intransit_idx
:
1393 p_bytask
[pname
]['transit'] += 1
1394 elif entry_idx
>= 0:
1395 p_bytask
[pname
]['table'] += 1
1397 p_bytask
[pname
]['other'] += 1
1400 @lldb_command('countallports', 'P')
1401 def CountAllPorts(cmd_args
=None, cmd_options
={}):
1402 """ Routine to search for all as many references to ipc_port structures in the kernel
1404 Usage: countallports [-P]
1405 -P : include port sets in the count (default: NO)
1412 if "-P" in cmd_options
:
1415 ## optionally include port sets
1416 ## DO recurse on busy ports
1418 IterateAllPorts(None, CountPortsCallback
, (p_set
, p_intransit
, p_bytask
), find_psets
, True, True)
1419 sys
.stderr
.write("{:120s}\r".format(' '))
1421 print "Total ports found: {:d}".format(len(p_set
))
1422 print "In Transit: {:d}".format(len(p_intransit
))
1424 for pname
in sorted(p_bytask
.keys()):
1425 count
= p_bytask
[pname
]
1426 print "\t{: <20s}: table={: <5d}, transit={: <5d}, other={: <5d}".format(pname
, count
['table'], count
['transit'], count
['other'])
1428 # EndMacro: countallports
1430 # Macro: showpipestats
1431 @lldb_command('showpipestats')
1432 def ShowPipeStats(cmd_args
=None):
1433 """ Display pipes usage information in the kernel
1435 print "Number of pipes: {: d}".format(kern
.globals.amountpipes
)
1436 print "Memory used by pipes: {:s}".format(sizeof_fmt(int(kern
.globals.amountpipekva
)))
1437 print "Max memory allowed for pipes: {:s}".format(sizeof_fmt(int(kern
.globals.maxpipekva
)))
1438 # EndMacro: showpipestats
1440 # Macro: showtaskbusyports
1441 @lldb_command('showtaskbusyports')
1442 def ShowTaskBusyPorts(cmd_args
=None):
1443 """ Routine to print information about receive rights belonging to this task that
1444 have enqueued messages. This is oten a sign of a blocked or hung process
1445 Usage: showtaskbusyports <task address>
1448 print "No arguments passed. Please pass in the address of a task"
1449 print ShowTaskBusyPorts
.__doc
__
1451 task
= kern
.GetValueFromAddress(cmd_args
[0], 'task_t')
1452 PrintTaskBusyPorts(task
)
1455 def PrintTaskBusyPorts(task
):
1456 """ Prints all busy ports for a given task. ie. all receive rights belonging
1457 to this task that have enqueued messages.
1459 task : core.value representing a task in kernel
1461 str : String containing information about the given task's busy ports
1463 isp
= task
.itk_space
1465 while i
< isp
.is_table_size
:
1466 iep
= addressof(isp
.is_table
[i
])
1467 if iep
.ie_bits
& 0x00020000:
1468 port
= Cast(iep
.ie_object
, 'ipc_port_t')
1469 if port
.ip_messages
.data
.port
.msgcount
> 0:
1470 print PrintPortSummary
.header
1471 PrintPortSummary(port
)
1474 # EndMacro: showtaskbusyports
1476 # Macro: showallbusyports
1477 @lldb_command('showallbusyports')
1478 def ShowAllBusyPorts(cmd_args
=None):
1479 """ Routine to print information about all receive rights on the system that
1480 have enqueued messages.
1482 task_queue_head
= kern
.globals.tasks
1484 for tsk
in kern
.tasks
:
1485 PrintTaskBusyPorts(tsk
)
1487 # EndMacro: showallbusyports
1489 # Macro: showbusyportsummary
1490 @lldb_command('showbusyportsummary')
1491 def ShowBusyPortSummary(cmd_args
=None):
1492 """ Routine to print a summary of information about all receive rights
1493 on the system that have enqueued messages.
1495 task_queue_head
= kern
.globals.tasks
1501 print GetTaskBusyIPCSummary
.header
1502 for tsk
in kern
.tasks
:
1503 (summary
, table_size
, nbusy
, nmsgs
) = GetTaskBusyIPCSummary(tsk
)
1504 ipc_table_size
+= table_size
1505 ipc_busy_ports
+= nbusy
1508 for t
in kern
.terminated_tasks
:
1509 (summary
, table_size
, nbusy
, nmsgs
) = GetTaskBusyIPCSummary(tsk
)
1510 ipc_table_size
+= table_size
1511 ipc_busy_ports
+= nbusy
1514 print "Total Table Size: {:d}, Busy Ports: {:d}, Messages in-flight: {:d}".format(ipc_table_size
, ipc_busy_ports
, ipc_msgs
)
1516 # EndMacro: showbusyportsummary
1519 @lldb_command('showport','K')
1520 def ShowPort(cmd_args
=None, cmd_options
={}):
1521 """ Routine that lists details about a given IPC port
1522 Syntax: (lldb) showport 0xaddr
1525 if "-K" in cmd_options
:
1528 print "Please specify the address of the port whose details you want to print"
1529 print ShowPort
.__doc
__
1531 port
= kern
.GetValueFromAddress(cmd_args
[0], 'struct ipc_port *')
1532 print PrintPortSummary
.header
1533 PrintPortSummary(port
, show_kmsgs
)
1534 # EndMacro: showport
1536 # Macro: showmqueue:
1537 @lldb_command('showmqueue', "S:")
1538 def ShowMQueue(cmd_args
=None, cmd_options
={}):
1539 """ Routine that lists details about a given mqueue
1540 Syntax: (lldb) showmqueue 0xaddr [-S ipc_space]
1543 print "Please specify the address of the ipc_mqueue whose details you want to print"
1544 print ShowMQueue
.__doc
__
1547 if "-S" in cmd_options
:
1548 space
= kern
.GetValueFromAddress(cmd_options
["-S"], 'struct ipc_space *')
1549 mqueue
= kern
.GetValueFromAddress(cmd_args
[0], 'struct ipc_mqueue *')
1550 wq_type
= mqueue
.data
.pset
.setq
.wqset_q
.waitq_type
1551 if int(wq_type
) == 3:
1552 psetoff
= getfieldoffset('struct ipc_pset', 'ips_messages')
1553 pset
= unsigned(ArgumentStringToInt(cmd_args
[0])) - unsigned(psetoff
)
1554 print PrintPortSetSummary
.header
1555 PrintPortSetSummary(kern
.GetValueFromAddress(pset
, 'struct ipc_pset *'), space
)
1556 elif int(wq_type
) in [2, 1]:
1557 portoff
= getfieldoffset('struct ipc_port', 'ip_messages')
1558 port
= unsigned(ArgumentStringToInt(cmd_args
[0])) - unsigned(portoff
)
1559 print PrintPortSummary
.header
1560 PrintPortSummary(kern
.GetValueFromAddress(port
, 'struct ipc_port *'))
1562 print "Invalid mqueue? (waitq type {:d} is invalid)".format(int(wq_type
))
1563 # EndMacro: showmqueue
1566 @lldb_command('showkmsg')
1567 def ShowKMSG(cmd_args
=[]):
1568 """ Show detail information about a <ipc_kmsg_t> structure
1569 Usage: (lldb) showkmsg <ipc_kmsg_t>
1572 raise ArgumentError('Invalid arguments')
1573 kmsg
= kern
.GetValueFromAddress(cmd_args
[0], 'ipc_kmsg_t')
1574 print GetKMsgSummary
.header
1575 print GetKMsgSummary(kmsg
)
1577 # EndMacro: showkmsg
1580 @lldb_command('showpset', "S:")
1581 def ShowPSet(cmd_args
=None, cmd_options
={}):
1582 """ Routine that prints details for a given ipc_pset *
1583 Syntax: (lldb) showpset 0xaddr [-S ipc_space]
1586 print "Please specify the address of the pset whose details you want to print"
1587 print ShowPSet
.__doc
__
1590 if "-S" in cmd_options
:
1591 space
= kern
.GetValueFromAddress(cmd_options
["-S"], 'struct ipc_space *')
1593 print PrintPortSetSummary
.header
1594 PrintPortSetSummary(kern
.GetValueFromAddress(cmd_args
[0], 'ipc_pset *'), space
)
1595 # EndMacro: showpset
1597 # IPC importance inheritance related macros.
1599 @lldb_command('showalliits')
1600 def ShowAllIITs(cmd_args
=[], cmd_options
={}):
1601 """ Development only macro. Show list of all iits allocated in the system. """
1603 iit_queue
= kern
.globals.global_iit_alloc_queue
1605 print "This debug macro is only available in development or debug kernels"
1608 print GetIPCImportantTaskSummary
.header
1609 for iit
in IterateQueue(iit_queue
, 'struct ipc_importance_task *', 'iit_allocation'):
1610 print GetIPCImportantTaskSummary(iit
)
1613 @header("{: <18s} {: <3s} {: <18s} {: <20s} {: <18s} {: <8s}".format("ipc_imp_inherit", "don", "to_task", "proc_name", "from_elem", "depth"))
1614 @lldb_type_summary(['ipc_importance_inherit *', 'ipc_importance_inherit_t'])
1615 def GetIPCImportanceInheritSummary(iii
):
1616 """ describes iii object of type ipc_importance_inherit_t * """
1618 fmt
= "{o: <#018x} {don: <3s} {o.iii_to_task.iit_task: <#018x} {task_name: <20s} {o.iii_from_elem: <#018x} {o.iii_depth: <#08x}"
1620 if unsigned(iii
.iii_donating
):
1621 donating_str
= "DON"
1622 taskname
= GetProcNameForTask(iii
.iii_to_task
.iit_task
)
1623 if hasattr(iii
.iii_to_task
, 'iit_bsd_pid'):
1624 taskname
= "({:d}) {:s}".format(iii
.iii_to_task
.iit_bsd_pid
, iii
.iii_to_task
.iit_procname
)
1625 out_str
+= fmt
.format(o
=iii
, task_name
= taskname
, don
=donating_str
)
1628 @static_var('recursion_count', 0)
1629 @header("{: <18s} {: <4s} {: <8s} {: <8s} {: <18s} {: <18s}".format("iie", "type", "refs", "made", "#kmsgs", "#inherits"))
1630 @lldb_type_summary(['ipc_importance_elem *'])
1631 def GetIPCImportanceElemSummary(iie
):
1632 """ describes an ipc_importance_elem * object """
1634 if GetIPCImportanceElemSummary
.recursion_count
> 500:
1635 GetIPCImportanceElemSummary
.recursion_count
= 0
1636 return "Recursion of 500 reached"
1639 fmt
= "{: <#018x} {: <4s} {: <8d} {: <8d} {: <#018x} {: <#018x}"
1640 if unsigned(iie
.iie_bits
) & 0x80000000:
1645 iit
= Cast(iie
, 'struct ipc_importance_task *')
1646 inherit_count
= sum(1 for i
in IterateQueue(iit
.iit_inherits
, 'struct ipc_importance_inherit *', 'iii_inheritance'))
1648 refs
= unsigned(iie
.iie_bits
) & 0x7fffffff
1649 made_refs
= unsigned(iie
.iie_made
)
1650 kmsg_count
= sum(1 for i
in IterateQueue(iie
.iie_kmsgs
, 'struct ipc_kmsg *', 'ikm_inheritance'))
1651 out_str
+= fmt
.format(iie
, type_str
, refs
, made_refs
, kmsg_count
, inherit_count
)
1652 if config
['verbosity'] > vHUMAN
:
1654 out_str
+= "\n\t"+ GetKMsgSummary
.header
1655 for k
in IterateQueue(iie
.iie_kmsgs
, 'struct ipc_kmsg *', 'ikm_inheritance'):
1656 out_str
+= "\t" + "{: <#018x}".format(k
.ikm_header
.msgh_remote_port
) + ' ' + GetKMsgSummary(k
, "\t").lstrip()
1658 if inherit_count
> 0:
1659 out_str
+= "\n\t" + GetIPCImportanceInheritSummary
.header
+ "\n"
1660 for i
in IterateQueue(iit
.iit_inherits
, 'struct ipc_importance_inherit *', 'iii_inheritance'):
1661 out_str
+= "\t" + GetIPCImportanceInheritSummary(i
) + "\n"
1663 if type_str
== "INH":
1664 iii
= Cast(iie
, 'struct ipc_importance_inherit *')
1665 out_str
+= "Inherit from: " + GetIPCImportanceElemSummary(iii
.iii_from_elem
)
1669 @header("{: <18s} {: <18s} {: <20s}".format("iit", "task", "name"))
1670 @lldb_type_summary(['ipc_importance_task *'])
1671 def GetIPCImportantTaskSummary(iit
):
1672 """ iit is a ipc_importance_task value object.
1674 fmt
= "{: <#018x} {: <#018x} {: <20s}"
1676 pname
= GetProcNameForTask(iit
.iit_task
)
1677 if hasattr(iit
, 'iit_bsd_pid'):
1678 pname
= "({:d}) {:s}".format(iit
.iit_bsd_pid
, iit
.iit_procname
)
1679 out_str
+= fmt
.format(iit
, iit
.iit_task
, pname
)
1682 @lldb_command('showallimportancetasks')
1683 def ShowIPCImportanceTasks(cmd_args
=[], cmd_options
={}):
1684 """ display a list of all tasks with ipc importance information.
1685 Usage: (lldb) showallimportancetasks
1686 Tip: add "-v" to see detailed information on each kmsg or inherit elems
1688 print ' ' + GetIPCImportantTaskSummary
.header
+ ' ' + GetIPCImportanceElemSummary
.header
1689 for t
in kern
.tasks
:
1691 if unsigned(t
.task_imp_base
):
1692 s
+= ' ' + GetIPCImportantTaskSummary(t
.task_imp_base
)
1693 s
+= ' ' + GetIPCImportanceElemSummary(addressof(t
.task_imp_base
.iit_elem
))
1696 @lldb_command('showipcimportance', '')
1697 def ShowIPCImportance(cmd_args
=[], cmd_options
={}):
1698 """ Describe an importance from <ipc_importance_elem_t> argument.
1699 Usage: (lldb) showimportance <ipc_importance_elem_t>
1702 raise ArgumentError("Please provide valid argument")
1704 elem
= kern
.GetValueFromAddress(cmd_args
[0], 'ipc_importance_elem_t')
1705 print GetIPCImportanceElemSummary
.header
1706 print GetIPCImportanceElemSummary(elem
)
1708 @header("{: <18s} {: <10s} {: <18s} {: <18s} {: <8s} {: <5s} {: <5s} {: <5s}".format("ivac", "refs", "port", "tbl", "tblsize", "index", "Grow", "freelist"))
1709 @lldb_type_summary(['ipc_voucher_attr_control *', 'ipc_voucher_attr_control_t'])
1710 def GetIPCVoucherAttrControlSummary(ivac
):
1711 """ describes a voucher attribute control settings """
1713 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}"
1716 if unsigned(ivac
) == 0:
1717 return "{: <#018x}".format(ivac
)
1719 if unsigned(ivac
.ivac_is_growing
):
1721 out_str
+= fmt
.format(c
=ivac
, growing
= growing_str
)
1724 @lldb_command('showivac','')
1725 def ShowIPCVoucherAttributeControl(cmd_args
=[], cmd_options
={}):
1726 """ Show summary of voucher attribute contols.
1727 Usage: (lldb) showivac <ipc_voucher_attr_control_t>
1730 raise ArgumentError("Please provide correct arguments.")
1731 ivac
= kern
.GetValueFromAddress(cmd_args
[0], 'ipc_voucher_attr_control_t')
1732 print GetIPCVoucherAttrControlSummary
.header
1733 print GetIPCVoucherAttrControlSummary(ivac
)
1734 if config
['verbosity'] > vHUMAN
:
1736 last_entry_index
= unsigned(ivac
.ivac_table_size
)
1737 print "index " + GetIPCVoucherAttributeEntrySummary
.header
1738 while cur_entry_index
< last_entry_index
:
1739 print "{: <5d} ".format(cur_entry_index
) + GetIPCVoucherAttributeEntrySummary(addressof(ivac
.ivac_table
[cur_entry_index
]))
1740 cur_entry_index
+= 1
1745 @header("{: <18s} {: <30s} {: <30s} {: <30s} {: <30s} {: <30s}".format("ivam", "get_value_fn", "extract_fn", "release_value_fn", "command_fn", "release_fn"))
1746 @lldb_type_summary(['ipc_voucher_attr_manager *', 'ipc_voucher_attr_manager_t'])
1747 def GetIPCVoucherAttrManagerSummary(ivam
):
1748 """ describes a voucher attribute manager settings """
1750 fmt
= "{: <#018x} {: <30s} {: <30s} {: <30s} {: <30s} {: <30s}"
1752 if unsigned(ivam
) == 0 :
1753 return "{: <#018x}".format(ivam
)
1755 get_value_fn
= kern
.Symbolicate(unsigned(ivam
.ivam_get_value
))
1756 extract_fn
= kern
.Symbolicate(unsigned(ivam
.ivam_extract_content
))
1757 release_value_fn
= kern
.Symbolicate(unsigned(ivam
.ivam_release_value
))
1758 command_fn
= kern
.Symbolicate(unsigned(ivam
.ivam_command
))
1759 release_fn
= kern
.Symbolicate(unsigned(ivam
.ivam_release
))
1760 out_str
+= fmt
.format(ivam
, get_value_fn
, extract_fn
, release_value_fn
, command_fn
, release_fn
)
1765 @header("{: <18s} {: <10s} {:s} {:s}".format("ivgte", "key", GetIPCVoucherAttrControlSummary
.header
.strip(), GetIPCVoucherAttrManagerSummary
.header
.strip()))
1766 @lldb_type_summary(['ipc_voucher_global_table_element *', 'ipc_voucher_global_table_element_t'])
1767 def GetIPCVoucherGlobalTableElementSummary(ivgte
):
1768 """ describes a ipc_voucher_global_table_element object """
1770 fmt
= "{g: <#018x} {g.ivgte_key: <10d} {ctrl_s:s} {mgr_s:s}"
1771 out_str
+= fmt
.format(g
=ivgte
, ctrl_s
=GetIPCVoucherAttrControlSummary(ivgte
.ivgte_control
), mgr_s
=GetIPCVoucherAttrManagerSummary(ivgte
.ivgte_manager
))
1774 @lldb_command('showglobalvouchertable', '')
1775 def ShowGlobalVoucherTable(cmd_args
=[], cmd_options
={}):
1776 """ show detailed information of all voucher attribute managers registered with vouchers system
1777 Usage: (lldb) showglobalvouchertable
1779 entry_size
= sizeof(kern
.globals.iv_global_table
[0])
1780 elems
= sizeof(kern
.globals.iv_global_table
) / entry_size
1781 print GetIPCVoucherGlobalTableElementSummary
.header
1782 for i
in range(elems
):
1783 elt
= addressof(kern
.globals.iv_global_table
[i
])
1784 print GetIPCVoucherGlobalTableElementSummary(elt
)
1786 # Type summaries for Bag of Bits.
1788 @lldb_type_summary(['user_data_value_element', 'user_data_element_t'])
1789 @header("{0: <20s} {1: <16s} {2: <20s} {3: <20s} {4: <16s} {5: <20s}".format("user_data_ve", "maderefs", "checksum", "hash value", "size", "data"))
1790 def GetBagofBitsElementSummary(data_element
):
1791 """ Summarizes the Bag of Bits element
1792 params: data_element = value of the object of type user_data_value_element_t
1793 returns: String with summary of the type.
1795 format_str
= "{0: <#020x} {1: <16d} {2: <#020x} {3: <#020x} {4: <16d}"
1796 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
))
1799 for i
in range(0, (unsigned(data_element
.e_size
) - 1)):
1800 out_string
+= "{:02x}".format(int(data_element
.e_data
[i
]))
1803 def GetIPCHandleSummary(handle_ptr
):
1804 """ converts a handle value inside a voucher attribute table to ipc element and returns appropriate summary.
1805 params: handle_ptr - uint64 number stored in handle of voucher.
1806 returns: str - string summary of the element held in internal structure
1808 elem
= kern
.GetValueFromAddress(handle_ptr
, 'ipc_importance_elem_t')
1809 if elem
.iie_bits
& 0x80000000 :
1810 iie
= Cast(elem
, 'struct ipc_importance_inherit *')
1811 return GetIPCImportanceInheritSummary(iie
)
1813 iit
= Cast(elem
, 'struct ipc_importance_task *')
1814 return GetIPCImportantTaskSummary(iit
)
1816 def GetATMHandleSummary(handle_ptr
):
1817 """ Convert a handle value to atm value and returns corresponding summary of its fields.
1818 params: handle_ptr - uint64 number stored in handle of voucher
1819 returns: str - summary of atm value
1821 elem
= kern
.GetValueFromAddress(handle_ptr
, 'atm_value *')
1822 return GetATMValueSummary(elem
)
1824 def GetBankHandleSummary(handle_ptr
):
1825 """ converts a handle value inside a voucher attribute table to bank element and returns appropriate summary.
1826 params: handle_ptr - uint64 number stored in handle of voucher.
1827 returns: str - summary of bank element
1829 if handle_ptr
== 1 :
1830 return "Bank task of Current task"
1831 elem
= kern
.GetValueFromAddress(handle_ptr
, 'bank_element_t')
1832 if elem
.be_type
& 1 :
1833 ba
= Cast(elem
, 'struct bank_account *')
1834 return GetBankAccountSummary(ba
)
1836 bt
= Cast(elem
, 'struct bank_task *')
1837 return GetBankTaskSummary(bt
)
1839 def GetBagofBitsHandleSummary(handle_ptr
):
1840 """ Convert a handle value to bag of bits value and returns corresponding summary of its fields.
1841 params: handle_ptr - uint64 number stored in handle of voucher
1842 returns: str - summary of bag of bits element
1844 elem
= kern
.GetValueFromAddress(handle_ptr
, 'user_data_element_t')
1845 return GetBagofBitsElementSummary(elem
)
1847 @static_var('attr_managers',{1: GetATMHandleSummary, 2: GetIPCHandleSummary, 3: GetBankHandleSummary, 7: GetBagofBitsHandleSummary}
)
1848 def GetHandleSummaryForKey(handle_ptr
, key_num
):
1849 """ Get a summary of handle pointer from the voucher attribute manager.
1850 For example key 1 -> ATM and it puts atm_value_t in the handle. So summary of it would be atm value and refs etc.
1851 key 2 -> ipc and it puts either ipc_importance_inherit_t or ipc_important_task_t.
1852 key 3 -> Bank and it puts either bank_task_t or bank_account_t.
1853 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.
1855 key_num
= int(key_num
)
1856 if key_num
not in GetHandleSummaryForKey
.attr_managers
:
1857 return "Unknown key %d" % key_num
1858 return GetHandleSummaryForKey
.attr_managers
[key_num
](handle_ptr
)
1861 @header("{: <18s} {: <18s} {: <10s} {: <4s} {: <18s} {: <18s}".format("ivace", "value_handle", "#refs", "rel?", "maderefs", "next_layer"))
1862 @lldb_type_summary(['ivac_entry *', 'ivac_entry_t'])
1863 def GetIPCVoucherAttributeEntrySummary(ivace
, manager_key_num
= 0):
1864 """ Get summary for voucher attribute entry.
1867 fmt
= "{e: <#018x} {e.ivace_value: <#018x} {e.ivace_refs: <10d} {release: <4s} {made_refs: <18s} {next_layer: <18s}"
1873 if unsigned(ivace
.ivace_releasing
):
1875 if unsigned(ivace
.ivace_free
):
1877 if unsigned(ivace
.ivace_layered
):
1878 next_layer
= "{: <#018x}".format(ivace
.ivace_u
.ivaceu_layer
)
1880 made_refs
= "{: <18d}".format(ivace
.ivace_u
.ivaceu_made
)
1882 out_str
+= fmt
.format(e
=ivace
, release
=release_str
, made_refs
=made_refs
, next_layer
=next_layer
)
1883 if config
['verbosity'] > vHUMAN
and manager_key_num
> 0:
1884 out_str
+= " " + GetHandleSummaryForKey(unsigned(ivace
.ivace_value
), manager_key_num
)
1885 if config
['verbosity'] > vHUMAN
:
1886 out_str
+= ' {: <2s} {: <4d} {: <4d}'.format(free_str
, ivace
.ivace_next
, ivace
.ivace_index
)
1889 @lldb_command('showivacfreelist','')
1890 def ShowIVACFreeList(cmd_args
=[], cmd_options
={}):
1891 """ Walk the free list and print every entry in the list.
1892 usage: (lldb) showivacfreelist <ipc_voucher_attr_control_t>
1895 raise ArgumentError('Please provide <ipc_voucher_attr_control_t>')
1896 ivac
= kern
.GetValueFromAddress(cmd_args
[0], 'ipc_voucher_attr_control_t')
1897 print GetIPCVoucherAttrControlSummary
.header
1898 print GetIPCVoucherAttrControlSummary(ivac
)
1899 if unsigned(ivac
.ivac_freelist
) == 0:
1900 print "ivac table is full"
1902 print "index " + GetIPCVoucherAttributeEntrySummary
.header
1903 next_free
= unsigned(ivac
.ivac_freelist
)
1904 while next_free
!= 0:
1905 print "{: <5d} ".format(next_free
) + GetIPCVoucherAttributeEntrySummary(addressof(ivac
.ivac_table
[next_free
]))
1906 next_free
= unsigned(ivac
.ivac_table
[next_free
].ivace_next
)
1910 @header('{: <18s} {: <8s} {: <18s} {: <18s} {: <18s} {: <18s} {: <18s}'.format("ipc_voucher", "refs", "checksum", "hash", "tbl_size", "table", "voucher_port"))
1911 @lldb_type_summary(['ipc_voucher *', 'ipc_voucher_t'])
1912 def GetIPCVoucherSummary(voucher
, show_entries
=False):
1913 """ describe a voucher from its ipc_voucher * object """
1915 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}"
1916 out_str
+= fmt
.format(v
= voucher
)
1918 if show_entries
or config
['verbosity'] > vHUMAN
:
1919 elems
= unsigned(voucher
.iv_table_size
)
1920 entries_header_str
= "\n\t" + "{: <5s} {: <3s} {: <16s} {: <30s}".format("index", "key", "value_index", "manager") + " " + GetIPCVoucherAttributeEntrySummary
.header
1921 fmt
= "{: <5d} {: <3d} {: <16d} {: <30s}"
1922 for i
in range(elems
):
1923 voucher_entry_index
= unsigned(voucher
.iv_inline_table
[i
])
1924 if voucher_entry_index
:
1925 s
= fmt
.format(i
, GetVoucherManagerKeyForIndex(i
), voucher_entry_index
, GetVoucherAttributeManagerNameForIndex(i
))
1926 e
= GetVoucherValueHandleFromVoucherForIndex(voucher
, i
)
1928 s
+= " " + GetIPCVoucherAttributeEntrySummary(addressof(e
), GetVoucherManagerKeyForIndex(i
) )
1929 if entries_header_str
:
1930 entries_str
= entries_header_str
1931 entries_header_str
= ''
1932 entries_str
+= "\n\t" + s
1933 if not entries_header_str
:
1934 entries_str
+= "\n\t"
1935 out_str
+= entries_str
1938 def GetVoucherManagerKeyForIndex(idx
):
1939 """ Returns key number for index based on global table. Will raise index error if value is incorrect
1941 return unsigned(kern
.globals.iv_global_table
[idx
].ivgte_key
)
1943 def GetVoucherAttributeManagerForKey(k
):
1944 """ Walks through the iv_global_table and finds the attribute manager name
1945 params: k - int key number of the manager
1946 return: cvalue - the attribute manager object.
1950 entry_size
= sizeof(kern
.globals.iv_global_table
[0])
1951 elems
= sizeof(kern
.globals.iv_global_table
) / entry_size
1952 for i
in range(elems
):
1953 elt
= addressof(kern
.globals.iv_global_table
[i
])
1954 if k
== unsigned(elt
.ivgte_key
):
1955 retval
= elt
.ivgte_manager
1959 def GetVoucherAttributeControllerForKey(k
):
1960 """ Walks through the iv_global_table and finds the attribute controller
1961 params: k - int key number of the manager
1962 return: cvalue - the attribute controller object.
1966 entry_size
= sizeof(kern
.globals.iv_global_table
[0])
1967 elems
= sizeof(kern
.globals.iv_global_table
) / entry_size
1968 for i
in range(elems
):
1969 elt
= addressof(kern
.globals.iv_global_table
[i
])
1970 if k
== unsigned(elt
.ivgte_key
):
1971 retval
= elt
.ivgte_control
1976 def GetVoucherAttributeManagerName(ivam
):
1977 """ find the name of the ivam object
1978 param: ivam - cvalue object of type ipc_voucher_attr_manager_t
1979 returns: str - name of the manager
1981 return kern
.Symbolicate(unsigned(ivam
))
1983 def GetVoucherAttributeManagerNameForIndex(idx
):
1984 """ get voucher attribute manager name for index
1985 return: str - name of the attribute manager object
1987 return GetVoucherAttributeManagerName(GetVoucherAttributeManagerForKey(GetVoucherManagerKeyForIndex(idx
)))
1989 def GetVoucherValueHandleFromVoucherForIndex(voucher
, idx
):
1990 """ traverse the voucher attrs and get value_handle in the voucher attr controls table
1992 voucher - cvalue object of type ipc_voucher_t
1993 idx - int index in the entries for which you wish to get actual handle for
1994 returns: cvalue object of type ivac_entry_t
1995 None if no handle found.
1997 manager_key
= GetVoucherManagerKeyForIndex(idx
)
1998 voucher_num_elems
= unsigned(voucher
.iv_table_size
)
1999 if idx
>= voucher_num_elems
:
2000 debuglog("idx %d is out of range max: %d" % (idx
, voucher_num_elems
))
2002 voucher_entry_value
= unsigned(voucher
.iv_inline_table
[idx
])
2003 debuglog("manager_key %d" % manager_key
)
2004 ivac
= GetVoucherAttributeControllerForKey(manager_key
)
2005 if ivac
is None or unsigned(ivac
) == 0:
2006 debuglog("No voucher attribute controller for idx %d" % idx
)
2009 ivac
= kern
.GetValueFromAddress(unsigned(ivac
), 'ipc_voucher_attr_control_t') # ??? No idea why lldb does not addressof directly
2010 ivace_table
= ivac
.ivac_table
2011 if voucher_entry_value
>= unsigned(ivac
.ivac_table_size
):
2012 print "Failed to get ivace for value %d in table of size %d" % (voucher_entry_value
, unsigned(ivac
.ivac_table_size
))
2014 return ivace_table
[voucher_entry_value
]
2018 @lldb_command('showallvouchers')
2019 def ShowAllVouchers(cmd_args
=[], cmd_options
={}):
2020 """ Display a list of all vouchers in the global voucher hash table
2021 Usage: (lldb) showallvouchers
2023 iv_hash_table
= kern
.globals.ivht_bucket
2024 num_buckets
= sizeof(kern
.globals.ivht_bucket
) / sizeof(kern
.globals.ivht_bucket
[0])
2025 print GetIPCVoucherSummary
.header
2026 for i
in range(num_buckets
):
2027 for v
in IterateQueue(iv_hash_table
[i
], 'ipc_voucher_t', 'iv_hash_link'):
2028 print GetIPCVoucherSummary(v
)
2030 @lldb_command('showvoucher', '')
2031 def ShowVoucher(cmd_args
=[], cmd_options
={}):
2032 """ Describe a voucher from <ipc_voucher_t> argument.
2033 Usage: (lldb) showvoucher <ipc_voucher_t>
2036 raise ArgumentError("Please provide valid argument")
2038 voucher
= kern
.GetValueFromAddress(cmd_args
[0], 'ipc_voucher_t')
2039 print GetIPCVoucherSummary
.header
2040 print GetIPCVoucherSummary(voucher
, show_entries
=True)
2042 def GetSpaceSendRightEntries(space
, port
):
2043 """ Get entry summaries for all send rights to port address in an IPC space.
2045 space - the IPC space to search for send rights
2046 port_addr - the port address to match, or 0 to get all send rights
2047 returns: an array of IPC entries
2049 entry_table
= space
.is_table
2050 ports
= int(space
.is_table_size
)
2055 entry
= GetObjectAtIndexFromArray(entry_table
, i
)
2057 entry_ie_bits
= unsigned(entry
.ie_bits
)
2058 if (entry_ie_bits
& 0x00010000) != 0 and (not port
or entry
.ie_object
== port
):
2059 entries
.append(entry
)
2064 @lldb_command('showportsendrights')
2065 def ShowPortSendRights(cmd_args
=[], cmd_options
={}):
2066 """ Display a list of send rights across all tasks for a given port.
2067 Usage: (lldb) showportsendrights <ipc_port_t>
2070 raise ArgumentError("no port address provided")
2071 port
= kern
.GetValueFromAddress(cmd_args
[0], 'struct ipc_port *')
2074 return FindPortRights(cmd_args
=[unsigned(port
)], cmd_options
={'-R':'S'}
)
2077 @lldb_command('showtasksuspenders')
2078 def ShowTaskSuspenders(cmd_args
=[], cmd_options
={}):
2079 """ Display the tasks and send rights that are holding a target task suspended.
2080 Usage: (lldb) showtasksuspenders <task_t>
2083 raise ArgumentError("no task address provided")
2084 task
= kern
.GetValueFromAddress(cmd_args
[0], 'task_t')
2086 if task
.suspend_count
== 0:
2087 print "task {:#x} ({:s}) is not suspended".format(unsigned(task
), Cast(task
.bsd_info
, 'proc_t').p_name
)
2090 # If the task has been suspended by the kernel (potentially by
2091 # kperf, using task_suspend_internal) or a client of task_suspend2
2092 # that does not convert its task suspension token to a port using
2093 # convert_task_suspension_token_to_port, then it's impossible to determine
2094 # which task did the suspension.
2095 port
= task
.itk_resume
2097 print "task {:#x} ({:s}) is suspended but no resume port exists".format(unsigned(task
), Cast(task
.bsd_info
, 'proc_t').p_name
)
2100 return FindPortRights(cmd_args
=[unsigned(port
)], cmd_options
={'-R':'S'}
)