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')
482 def ShowIPCSummary(cmd_args
=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 print 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
)
499 def GetKObjectFromPort(portval
):
500 """ Get Kobject description from the port.
501 params: portval - core.value representation of 'ipc_port *' object
502 returns: str - string of kobject information
504 kobject_str
= "{0: <#020x}".format(portval
.kdata
.kobject
)
505 io_bits
= unsigned(portval
.ip_object
.io_bits
)
506 objtype_index
= io_bits
& 0xfff
507 if objtype_index
< len(xnudefines
.kobject_types
) :
508 objtype_str
= xnudefines
.kobject_types
[objtype_index
]
509 if objtype_str
== 'IOKIT_OBJ':
510 iokit_classnm
= GetObjectTypeStr(portval
.kdata
.kobject
)
511 if not iokit_classnm
:
512 iokit_classnm
= "<unknown class>"
514 iokit_classnm
= re
.sub(r
'vtable for ', r
'', iokit_classnm
)
515 desc_str
= "kobject({:s}:{:s})".format(objtype_str
, iokit_classnm
)
517 desc_str
= "kobject({0:s})".format(objtype_str
)
518 if xnudefines
.kobject_types
[objtype_index
] in ('TASK_RESUME', 'TASK'):
519 desc_str
+= " " + GetProcNameForTask(Cast(portval
.kdata
.kobject
, 'task *'))
521 desc_str
= "kobject(UNKNOWN) {:d}".format(objtype_index
)
522 return kobject_str
+ " " + desc_str
524 @static_var('destcache', {})
525 def GetDestinationProcessFromPort(port
):
527 params: port - core.value representation of 'ipc_port *' object
528 returns: str - name of process
531 dest_space
= port
.data
.receiver
533 #update destcache if data is not found
534 if hex(dest_space
) not in GetDestinationProcessFromPort
.destcache
:
536 if hex(t
.itk_space
) == hex(dest_space
):
537 pval
= Cast(t
.bsd_info
, 'proc *')
538 GetDestinationProcessFromPort
.destcache
[hex(dest_space
)] = (t
, pval
)
542 else: found_dest
= True
545 (ftask
, fproc
) = GetDestinationProcessFromPort
.destcache
[hex(dest_space
)]
547 out_str
= "{0:s}({1:d})".format(fproc
.p_comm
, fproc
.p_pid
)
549 out_str
= "task {0: <#020x}".format(ftask
)
554 @header("{0: <20s} {1: <20s}".format("destname", "destination") )
555 def GetPortDestinationSummary(port
):
556 """ Get destination information for a port.
557 params: port - core.value representation of 'ipc_port *' object
558 returns: str - string of info about ports destination
561 format_string
= "{0: <20s} {1: <20s}"
564 ipc_space_kernel
= unsigned(kern
.globals.ipc_space_kernel
)
565 target_spaceval
= port
.data
.receiver
566 if unsigned(target_spaceval
) == ipc_space_kernel
:
567 destname_str
= GetKObjectFromPort(port
)
569 if int(port
.ip_object
.io_bits
) & 0x80000000 :
570 destname_str
= "{0: <#020x}".format(port
.ip_messages
.data
.port
.receiver_name
)
571 destination_str
= GetDestinationProcessFromPort(port
)
573 destname_str
= "{0: <#020x}".format(port
)
574 destination_str
= "inactive-port"
576 out_str
+= format_string
.format(destname_str
, destination_str
)
579 @lldb_type_summary(['ipc_entry_t'])
580 @header("{: <20s} {: <12s} {: <8s} {: <8s} {: <8s} {: <8s} {: <20s} {: <20s}".format("object", "name", "rite", "urefs", "nsets", "nmsgs", "destname", "destination"))
581 def GetIPCEntrySummary(entry
, ipc_name
='', rights_filter
=0):
582 """ Get summary of a ipc entry.
584 entry - core.value representing ipc_entry_t in the kernel
585 ipc_name - str of format '0x0123' for display in summary.
587 str - string of ipc entry related information
594 'O' : Send-once right
595 types of notifications:
596 'd' : Dead-Name notification requested
597 's' : Send-Possible notification armed
598 'r' : Send-Possible notification requested
599 'n' : No-Senders notification requested
600 'x' : Port-destroy notification requested
603 entry_ptr
= int(hex(entry
), 16)
604 format_string
= "{: <#020x} {: <12s} {: <8s} {: <8d} {: <8d} {: <8d} {: <20s} {: <20s}"
609 ie_object
= entry
.ie_object
610 ie_bits
= int(entry
.ie_bits
)
611 urefs
= int(ie_bits
& 0xffff)
614 if ie_bits
& 0x00100000 :
616 elif ie_bits
& 0x00080000:
618 psetval
= Cast(ie_object
, 'ipc_pset *')
619 set_str
= GetWaitqSets(addressof(psetval
.ips_messages
.data
.pset
.setq
.wqset_q
))
623 if ie_bits
& 0x00010000 :
624 if ie_bits
& 0x00020000 :
630 elif ie_bits
& 0x00020000:
633 elif ie_bits
& 0x00040000 :
636 portval
= Cast(ie_object
, 'ipc_port_t')
637 if int(entry
.index
.request
) != 0:
638 requestsval
= portval
.ip_requests
639 sorightval
= requestsval
[int(entry
.index
.request
)].notify
.port
640 soright_ptr
= unsigned(sorightval
)
642 # dead-name notification requested
644 # send-possible armed
645 if soright_ptr
& 0x1 : right_str
+='s'
646 # send-possible requested
647 if soright_ptr
& 0x2 : right_str
+='r'
648 # No-senders notification requested
649 if portval
.ip_nsrequest
!= 0: right_str
+= 'n'
650 # port-destroy notification requested
651 if portval
.ip_pdrequest
!= 0: right_str
+= 'x'
653 # early-out if the rights-filter doesn't match
654 if rights_filter
!= 0 and rights_filter
!= right_str
:
657 # append the generation to the name value
658 # (from osfmk/ipc/ipc_entry.h)
659 # bits rollover period
664 ie_gen_roll
= { 0:'.64', 1:'.48', 2:'.32', 3:'.16' }
665 ipc_name
= '{:s}{:s}'.format(strip(ipc_name
), ie_gen_roll
[(ie_bits
& 0x00c00000) >> 22])
667 # now show the port destination part
668 destname_str
= GetPortDestinationSummary(Cast(ie_object
, 'ipc_port_t'))
669 # Get the number of sets to which this port belongs
670 set_str
= GetWaitqSets(addressof(portval
.ip_messages
.data
.port
.waitq
))
672 nmsgs
= portval
.ip_messages
.data
.port
.msgcount
673 if rights_filter
== 0 or rights_filter
== right_str
:
674 out_str
= format_string
.format(ie_object
, ipc_name
, right_str
, urefs
, nsets
, nmsgs
, destname_str
, destination_str
)
677 @header("{0: >20s}".format("user bt") )
678 def GetPortUserStack(port
, task
):
679 """ Get UserStack information for the given port & task.
680 params: port - core.value representation of 'ipc_port *' object
681 task - value representing 'task *' object
682 returns: str - string information on port's userstack
685 ie_port_callstack
= port
.ip_callstack
686 ie_port_spares
= port
.ip_spares
[0]
687 proc_val
= Cast(task
.bsd_info
, 'proc *')
688 if ie_port_callstack
[0]:
689 out_str
+= "{: <10x}".format(ie_port_callstack
[0])
691 while count
< 16 and ie_port_callstack
[count
]:
692 out_str
+= ": <10x".format(ie_port_callstack
[count
])
694 if ie_port_spares
!= proc_val
.p_pid
:
695 out_str
+= " ({:<10d})".format(ie_port_spares
)
699 @lldb_type_summary(['ipc_space *'])
700 @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'))
701 def PrintIPCInformation(space
, show_entries
=False, show_userstack
=False, rights_filter
=0):
702 """ Provide a summary of the ipc space
705 format_string
= "{0: <#020x} {1: <#020x} {2: <#020x} {3: <8s} {4: <10d} {5: <#18x} {6: >8d} {7: <8d}"
706 is_tableval
= space
.is_table
707 ports
= int(space
.is_table_size
)
709 is_bits
= int(space
.is_bits
)
710 if (is_bits
& 0x40000000) == 0: flags
+='A'
712 if (is_bits
& 0x20000000) != 0: flags
+='G'
713 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
)
715 #should show the each individual entries if asked.
716 if show_entries
== True:
717 print "\t" + GetIPCEntrySummary
.header
720 while index
< num_entries
:
721 entryval
= GetObjectAtIndexFromArray(is_tableval
, index
)
722 entry_ie_bits
= unsigned(entryval
.ie_bits
)
723 if (int(entry_ie_bits
) & 0x001f0000 ) != 0:
724 entry_name
= "{0: <#020x}".format( (index
<<8 | entry_ie_bits
>> 24) )
725 entry_str
= GetIPCEntrySummary(entryval
, entry_name
, rights_filter
)
726 if len(entry_str
) > 0:
727 print " \r\t" + entry_str
728 if show_userstack
== True:
729 entryport
= Cast(entryval
.ie_object
, 'ipc_port *')
730 if entryval
.ie_object
and (int(entry_ie_bits
) & 0x00070000) and entryport
.ip_callstack
[0]:
731 print GetPortUserStack
.header
+ GetPortUserStack(entryport
, space
.is_task
)
733 # give some progress indication (this is especially
734 # helpful for tasks with large sets of rights)
735 sys
.stderr
.write(' {:d}/{:d}...\r'.format(index
, num_entries
))
737 #done with showing entries
742 @lldb_command('showrights', 'R:')
743 def ShowRights(cmd_args
=None, cmd_options
={}):
744 """ Routine to print rights information for the given IPC space
745 Usage: showrights [-R rights_type] <address of ipc space>
746 -R rights_type : only display rights matching the string 'rights_type'
753 'O' : Send-once right
754 types of notifications:
755 'd' : Dead-Name notification requested
756 's' : Send-Possible notification armed
757 'r' : Send-Possible notification requested
758 'n' : No-Senders notification requested
759 'x' : Port-destroy notification requested
762 print "No arguments passed"
763 print ShowRights
.__doc
__
765 ipc
= kern
.GetValueFromAddress(cmd_args
[0], 'ipc_space *')
767 print "unknown arguments:", str(cmd_args
)
770 if "-R" in cmd_options
:
771 rights_type
= cmd_options
["-R"]
772 print PrintIPCInformation
.header
773 PrintIPCInformation(ipc
, True, False, rights_type
)
775 # EndMacro: showrights
777 @lldb_command('showtaskrights','R:')
778 def ShowTaskRights(cmd_args
=None, cmd_options
={}):
779 """ Routine to ipc rights information for a task
780 Usage: showtaskrights [-R rights_type] <task address>
781 -R rights_type : only display rights matching the string 'rights_type'
788 'O' : Send-once right
789 types of notifications:
790 'd' : Dead-Name notification requested
791 's' : Send-Possible notification armed
792 'r' : Send-Possible notification requested
793 'n' : No-Senders notification requested
794 'x' : Port-destroy notification requested
797 print "No arguments passed"
798 print ShowTaskStacksCmdHelper
.__doc
__
800 tval
= kern
.GetValueFromAddress(cmd_args
[0], 'task *')
802 print "unknown arguments:", str(cmd_args
)
805 if "-R" in cmd_options
:
806 rights_type
= cmd_options
["-R"]
807 print GetTaskSummary
.header
+ " " + GetProcSummary
.header
808 pval
= Cast(tval
.bsd_info
, 'proc *')
809 print GetTaskSummary(tval
) + " " + GetProcSummary(pval
)
810 print PrintIPCInformation
.header
811 PrintIPCInformation(tval
.itk_space
, True, False, rights_type
)
813 # Macro: showataskrightsbt
815 @lldb_command('showtaskrightsbt', 'R:')
816 def ShowTaskRightsBt(cmd_args
=None, cmd_options
={}):
817 """ Routine to ipc rights information with userstacks for a task
818 Usage: showtaskrightsbt [-R rights_type] <task address>
819 -R rights_type : only display rights matching the string 'rights_type'
826 'O' : Send-once right
827 types of notifications:
828 'd' : Dead-Name notification requested
829 's' : Send-Possible notification armed
830 'r' : Send-Possible notification requested
831 'n' : No-Senders notification requested
832 'x' : Port-destroy notification requested
835 print "No arguments passed"
836 print ShowTaskRightsBt
.__doc
__
838 tval
= kern
.GetValueFromAddress(cmd_args
[0], 'task *')
840 print "unknown arguments:", str(cmd_args
)
843 if "-R" in cmd_options
:
844 rights_type
= cmd_options
["-R"]
845 print GetTaskSummary
.header
+ " " + GetProcSummary
.header
846 pval
= Cast(tval
.bsd_info
, 'proc *')
847 print GetTaskSummary(tval
) + " " + GetProcSummary(pval
)
848 print PrintIPCInformation
.header
849 PrintIPCInformation(tval
.itk_space
, True, True, rights_type
)
851 # EndMacro: showtaskrightsbt
853 # Macro: showallrights
855 @lldb_command('showallrights', 'R:')
856 def ShowAllRights(cmd_args
=None, cmd_options
={}):
857 """ Routine to print rights information for IPC space of all tasks
858 Usage: showallrights [-R rights_type]
859 -R rights_type : only display rights matching the string 'rights_type'
866 'O' : Send-once right
867 types of notifications:
868 'd' : Dead-Name notification requested
869 's' : Send-Possible notification armed
870 'r' : Send-Possible notification requested
871 'n' : No-Senders notification requested
872 'x' : Port-destroy notification requested
875 if "-R" in cmd_options
:
876 rights_type
= cmd_options
["-R"]
878 print GetTaskSummary
.header
+ " " + GetProcSummary
.header
879 pval
= Cast(t
.bsd_info
, 'proc *')
880 print GetTaskSummary(t
) + " " + GetProcSummary(pval
)
882 print PrintIPCInformation
.header
883 PrintIPCInformation(t
.itk_space
, True, False, rights_type
) + "\n\n"
884 except (KeyboardInterrupt, SystemExit):
887 print "Failed to get IPC information. Do individual showtaskrights <task> to find the error. \n\n"
889 # EndMacro: showallrights
892 def GetInTransitPortSummary(port
, disp
, holding_port
, holding_kmsg
):
893 """ String-ify the in-transit dispostion of a port.
895 ## This should match the summary generated by GetIPCEntrySummary
896 ## "object" "name" "rite" "urefs" "nsets" "nmsgs" "destname" "destination"
897 format_str
= "\t{: <#20x} {: <12} {: <8s} {: <8d} {: <8d} {: <8d} p:{: <#19x} k:{: <#19x}"
898 portname
= 'intransit'
900 disp_str
= GetPortDispositionString(disp
)
902 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
))
906 def GetDispositionFromEntryType(entry_bits
):
907 """ Translate an IPC entry type into an in-transit disposition. This allows
908 the GetInTransitPortSummary function to be re-used to string-ify IPC
911 ebits
= int(entry_bits
)
912 if (ebits
& 0x003f0000) == 0:
915 if (ebits
& 0x00010000) != 0:
916 return 17 ## MACH_PORT_RIGHT_SEND
917 elif (ebits
& 0x00020000) != 0:
918 return 16 ## MACH_PORT_RIGHT_RECEIVE
919 elif (ebits
& 0x00040000) != 0:
920 return 18 ## MACH_PORT_RIGHT_SEND_ONCE
921 elif (ebits
& 0x00080000) != 0:
922 return 100 ## MACH_PORT_RIGHT_PORT_SET
923 elif (ebits
& 0x00100000) != 0:
924 return 101 ## MACH_PORT_RIGHT_DEAD_NAME
925 elif (ebits
& 0x00200000) != 0:
926 return 102 ## MACH_PORT_RIGHT_LABELH
930 def GetDispositionFromVoucherPort(th_vport
):
931 """ Translate a thread's voucher port into a 'disposition'
933 if unsigned(th_vport
) > 0:
934 return 103 ## Voucher type
951 def PrintProgressForKmsg():
954 sys
.stderr
.write(" {:<1s}\r".format(g_progmeter
[g_kmsg_prog
% 9]))
958 def CollectPortsForAnalysis(port
, disposition
):
961 p
= Cast(port
, 'struct ipc_port *')
962 yield (p
, disposition
)
964 # no-senders notification port
965 if unsigned(p
.ip_nsrequest
) != 0:
966 PrintProgressForKmsg()
967 yield (Cast(p
.ip_nsrequest
, 'struct ipc_port *'), -1)
969 # port-death notification port
970 if unsigned(p
.ip_pdrequest
) != 0:
971 PrintProgressForKmsg()
972 yield (Cast(p
.ip_pdrequest
, 'struct ipc_port *'), -2)
974 ## ports can have many send-possible notifications armed: go through the table!
975 if unsigned(p
.ip_requests
) != 0:
976 table
= Cast(p
.ip_requests
, 'struct ipc_port_request *')
977 table_sz
= int(table
.name
.size
.its_size
)
978 for i
in range(table_sz
):
982 if unsigned(ipr
.name
.name
) != 0:
983 ipr_bits
= unsigned(ipr
.notify
.port
) & 3
984 ipr_port
= kern
.GetValueFromAddress(int(ipr
.notify
.port
) & ~
3, 'struct ipc_port *')
986 if ipr_bits
& 3: ## send-possible armed and requested
988 elif ipr_bits
& 2: ## send-possible requested
990 elif ipr_bits
& 1: ## send-possible armed
992 PrintProgressForKmsg()
993 yield (ipr_port
, ipr_disp
)
996 def CollectKmsgPorts(task
, task_port
, kmsgp
):
997 """ Look through a message, 'kmsgp' destined for 'task'
998 (enqueued on task_port). Collect any port descriptors,
999 remote, local, voucher, or other port references
1000 into a (ipc_port_t, disposition) list.
1002 kmsgh
= dereference(kmsgp
.ikm_header
)
1006 PrintProgressForKmsg()
1007 if kmsgh
.msgh_remote_port
and unsigned(kmsgh
.msgh_remote_port
) != unsigned(task_port
):
1008 disp
= kmsgh
.msgh_bits
& 0x1f
1009 p_list
+= list(CollectPortsForAnalysis(kmsgh
.msgh_remote_port
, disp
))
1011 if kmsgh
.msgh_local_port
and unsigned(kmsgh
.msgh_local_port
) != unsigned(task_port
) \
1012 and unsigned(kmsgh
.msgh_local_port
) != unsigned(kmsgh
.msgh_remote_port
):
1013 disp
= (kmsgh
.msgh_bits
& 0x1f00) >> 8
1014 p_list
+= list(CollectPortsForAnalysis(kmsgh
.msgh_local_port
, disp
))
1016 if kmsgp
.ikm_voucher
:
1017 p_list
+= list(CollectPortsForAnalysis(kmsgp
.ikm_voucher
, 0))
1019 if kmsgh
.msgh_bits
& 0x80000000:
1020 ## Complex message - look for descriptors
1021 PrintProgressForKmsg()
1022 (body
, dschead
, dsc_list
) = GetKmsgDescriptors(kmsgp
)
1023 for dsc
in dsc_list
:
1024 PrintProgressForKmsg()
1025 dsc_type
= unsigned(dsc
.type.type)
1026 if dsc_type
== 0 or dsc_type
== 2: ## 0 == port, 2 == ool port
1028 ## its a port descriptor
1029 dsc_disp
= dsc
.port
.disposition
1030 p_list
+= list(CollectPortsForAnalysis(dsc
.port
.name
, dsc_disp
))
1032 ## it's an ool_ports descriptor which is an array of ports
1033 dsc_disp
= dsc
.ool_ports
.disposition
1034 dispdata
= Cast(dsc
.ool_ports
.address
, 'struct ipc_port *')
1035 for pidx
in range(dsc
.ool_ports
.count
):
1036 PrintProgressForKmsg()
1037 p_list
+= list(CollectPortsForAnalysis(dispdata
[pidx
], dsc_disp
))
1040 def CollectKmsgPortRefs(task
, task_port
, kmsgp
, p_refs
):
1041 """ Recursively collect all references to ports inside the kmsg 'kmsgp'
1042 into the set 'p_refs'
1044 p_list
= CollectKmsgPorts(task
, task_port
, kmsgp
)
1046 ## Iterate over each ports we've collected, to see if they
1047 ## have messages on them, and then recurse!
1048 for p
, pdisp
in p_list
:
1049 ptype
= (p
.ip_object
.io_bits
& 0x7fff0000) >> 16
1050 p_refs
.add((p
, pdisp
, ptype
))
1051 if ptype
!= 0: ## don't bother with port sets
1053 ## If the port that's in-transit has messages already enqueued,
1054 ## go through each of those messages and look for more ports!
1055 if p
.ip_messages
.data
.port
.msgcount
> 0:
1056 p_kmsgp
= Cast(p
.ip_messages
.data
.port
.messages
.ikmq_base
, 'ipc_kmsg_t')
1058 while unsigned(p_kmsgp
) > 0:
1059 CollectKmsgPortRefs(task
, p
, p_kmsgp
, p_refs
)
1060 p_kmsgp
= p_kmsgp
.ikm_next
1061 if p_kmsgp
== kmsgheadp
:
1065 def FindKmsgPortRefs(instr
, task
, task_port
, kmsgp
, qport
):
1066 """ Look through a message, 'kmsgp' destined for 'task'. If we find
1067 any port descriptors, remote, local, voucher, or other port that
1068 matches 'qport', return a short description
1069 which should match the format of GetIPCEntrySummary.
1073 p_list
= CollectKmsgPorts(task
, task_port
, kmsgp
)
1075 ## Run through all ports we've collected looking for 'qport'
1076 for p
, pdisp
in p_list
:
1077 PrintProgressForKmsg()
1078 if unsigned(p
) == unsigned(qport
):
1079 ## the port we're looking for was found in this message!
1080 if len(out_str
) > 0:
1082 out_str
+= GetInTransitPortSummary(p
, pdisp
, task_port
, kmsgp
)
1084 ptype
= (p
.ip_object
.io_bits
& 0x7fff0000) >> 16
1085 if ptype
!= 0: ## don't bother with port sets
1088 ## If the port that's in-transit has messages already enqueued,
1089 ## go through each of those messages and look for more ports!
1090 if p
.ip_messages
.data
.port
.msgcount
> 0:
1091 p_kmsgp
= Cast(p
.ip_messages
.data
.port
.messages
.ikmq_base
, 'ipc_kmsg_t')
1093 while unsigned(p_kmsgp
) > 0:
1094 out_str
= FindKmsgPortRefs(out_str
, task
, p
, p_kmsgp
, qport
)
1095 p_kmsgp
= p_kmsgp
.ikm_next
1096 if p_kmsgp
== kmsgheadp
:
1101 port_iteration_do_print_taskname
= False
1102 registeredport_idx
= -10
1104 intransit_idx
= -1000
1105 taskports_idx
= -2000
1108 def IterateAllPorts(tasklist
, func
, ctx
, include_psets
, follow_busyports
, should_log
):
1109 """ Iterate over all ports in the system, calling 'func'
1112 global port_iteration_do_print_taskname
1113 global intransit_idx
, taskports_idx
, thports_idx
, registeredport_idx
, excports_idx
1115 ## XXX: also host special ports
1117 entry_port_type_mask
= 0x00070000
1119 entry_port_type_mask
= 0x000f0000
1121 if tasklist
is None:
1122 tasklist
= kern
.tasks
1123 tasklist
+= kern
.terminated_tasks
1128 # Write a progress line. Using stderr avoids automatic newline when
1129 # writing to stdout from lldb. Blank spaces at the end clear out long
1134 procname
= 'terminated: '
1136 procname
+= 'halting: '
1137 t_p
= Cast(t
.bsd_info
, 'proc *')
1138 if unsigned(t_p
) != 0:
1139 procname
+= str(t_p
.p_name
)
1140 elif unsigned(t
.task_imp_base
) != 0 and hasattr(t
.task_imp_base
, 'iit_procname'):
1141 procname
+= str(t
.task_imp_base
.iit_procname
)
1142 sys
.stderr
.write(" checking {:s} ({}/{})...{:50s}\r".format(procname
, tidx
, len(tasklist
), ''))
1145 port_iteration_do_print_taskname
= True
1147 num_entries
= int(space
.is_table_size
)
1148 is_tableval
= space
.is_table
1150 while idx
< num_entries
:
1151 entry_val
= GetObjectAtIndexFromArray(is_tableval
, idx
)
1152 entry_bits
= unsigned(entry_val
.ie_bits
)
1155 entry_name
= "{:x}".format( (idx
<< 8 | entry_bits
>> 24) )
1157 entry_disp
= GetDispositionFromEntryType(entry_bits
)
1159 ## If the entry in the table represents a port of some sort,
1160 ## then make the callback provided
1161 if int(entry_bits
) & entry_port_type_mask
:
1162 eport
= Cast(entry_val
.ie_object
, 'ipc_port_t')
1163 ## Make the callback
1164 func(t
, space
, ctx
, idx
, entry_val
, eport
, entry_disp
)
1166 ## if the port has pending messages, look through
1167 ## each message for ports (and recurse)
1168 if follow_busyports
and unsigned(eport
) > 0 and eport
.ip_messages
.data
.port
.msgcount
> 0:
1169 ## collect all port references from all messages
1170 kmsgp
= Cast(eport
.ip_messages
.data
.port
.messages
.ikmq_base
, 'ipc_kmsg_t')
1172 while unsigned(kmsgp
) > 0:
1174 CollectKmsgPortRefs(t
, eport
, kmsgp
, p_refs
)
1175 for (port
, pdisp
, ptype
) in p_refs
:
1176 func(t
, space
, ctx
, intransit_idx
, None, port
, pdisp
)
1177 kmsgp
= kmsgp
.ikm_next
1178 if kmsgp
== kmsgheadp
:
1182 ## while (idx < num_entries)
1184 ## Task ports (send rights)
1185 if unsigned(t
.itk_sself
) > 0:
1186 func(t
, space
, ctx
, taskports_idx
, 0, t
.itk_sself
, 17)
1187 if unsigned(t
.itk_host
) > 0:
1188 func(t
, space
, ctx
, taskports_idx
, 0, t
.itk_host
, 17)
1189 if unsigned(t
.itk_bootstrap
) > 0:
1190 func(t
, space
, ctx
, taskports_idx
, 0, t
.itk_bootstrap
, 17)
1191 if unsigned(t
.itk_seatbelt
) > 0:
1192 func(t
, space
, ctx
, taskports_idx
, 0, t
.itk_seatbelt
, 17)
1193 if unsigned(t
.itk_gssd
) > 0:
1194 func(t
, space
, ctx
, taskports_idx
, 0, t
.itk_gssd
, 17)
1195 if unsigned(t
.itk_debug_control
) > 0:
1196 func(t
, space
, ctx
, taskports_idx
, 0, t
.itk_debug_control
, 17)
1197 if unsigned(t
.itk_task_access
) > 0:
1198 func(t
, space
, ctx
, taskports_idx
, 0, t
.itk_task_access
, 17)
1200 ## Task name port (not a send right, just a naked ref)
1201 if unsigned(t
.itk_nself
) > 0:
1202 func(t
, space
, ctx
, taskports_idx
, 0,t
.itk_nself
, 0)
1204 ## task resume port is a receive right to resume the task
1205 if unsigned(t
.itk_resume
) > 0:
1206 func(t
, space
, ctx
, taskports_idx
, 0, t
.itk_resume
, 16)
1208 ## registered task ports (all send rights)
1210 tr_max
= sizeof(t
.itk_registered
) / sizeof(t
.itk_registered
[0])
1211 while tr_idx
< tr_max
:
1212 tport
= t
.itk_registered
[tr_idx
]
1213 if unsigned(tport
) > 0:
1215 func(t
, space
, ctx
, registeredport_idx
, 0, tport
, 17)
1216 except Exception, e
:
1217 print("\texception looking through registered port {:d}/{:d} in {:s}".format(tr_idx
,tr_max
,t
))
1221 ## Task exception ports
1223 exmax
= sizeof(t
.exc_actions
) / sizeof(t
.exc_actions
[0])
1224 while exidx
< exmax
: ## see: osfmk/mach/[arm|i386]/exception.h
1225 export
= t
.exc_actions
[exidx
].port
## send right
1226 if unsigned(export
) > 0:
1228 func(t
, space
, ctx
, excports_idx
, 0, export
, 17)
1229 except Exception, e
:
1230 print("\texception looking through exception port {:d}/{:d} in {:s}".format(exidx
,exmax
,t
))
1234 ## XXX: any ports still valid after clearing IPC space?!
1236 for thval
in IterateQueue(t
.threads
, 'thread *', 'task_threads'):
1237 ## XXX: look at block reason to see if it's in mach_msg_receive - then look at saved state / message
1239 ## Thread port (send right)
1240 if unsigned(thval
.ith_sself
) > 0:
1241 thport
= thval
.ith_sself
1242 func(t
, space
, ctx
, thports_idx
, 0, thport
, 17) ## see: osfmk/mach/message.h
1243 ## Thread special reply port (send-once right)
1244 if unsigned(thval
.ith_special_reply_port
) > 0:
1245 thport
= thval
.ith_special_reply_port
1246 func(t
, space
, ctx
, thports_idx
, 0, thport
, 18) ## see: osfmk/mach/message.h
1247 ## Thread voucher port
1248 if unsigned(thval
.ith_voucher
) > 0:
1249 vport
= thval
.ith_voucher
.iv_port
1250 if unsigned(vport
) > 0:
1251 vdisp
= GetDispositionFromVoucherPort(vport
)
1252 func(t
, space
, ctx
, thports_idx
, 0, vport
, vdisp
)
1253 ## Thread exception ports
1254 if unsigned(thval
.exc_actions
) > 0:
1256 while exidx
< exmax
: ## see: osfmk/mach/[arm|i386]/exception.h
1257 export
= thval
.exc_actions
[exidx
].port
## send right
1258 if unsigned(export
) > 0:
1260 func(t
, space
, ctx
, excports_idx
, 0, export
, 17)
1261 except Exception, e
:
1262 print("\texception looking through exception port {:d}/{:d} in {:s}".format(exidx
,exmax
,t
))
1265 ## XXX: the message on a thread (that's currently being received)
1266 ## for (thval in t.threads)
1267 ## for (t in tasklist)
1270 # Macro: findportrights
1271 def FindPortRightsCallback(task
, space
, ctx
, entry_idx
, ipc_entry
, ipc_port
, port_disp
):
1272 """ Callback which uses 'ctx' as the (port,rights_types) tuple for which
1273 a caller is seeking references. This should *not* be used from a
1274 recursive call to IterateAllPorts.
1276 global port_iteration_do_print_taskname
1278 (qport
, rights_type
) = ctx
1281 if unsigned(ipc_entry
) != 0:
1282 entry_bits
= unsigned(ipc_entry
.ie_bits
)
1283 entry_name
= "{:x}".format( (entry_idx
<< 8 | entry_bits
>> 24) )
1284 if (int(entry_bits
) & 0x001f0000) != 0 and unsigned(ipc_entry
.ie_object
) == unsigned(qport
):
1285 ## it's a valid entry, and it points to the port
1286 entry_str
= '\t' + GetIPCEntrySummary(ipc_entry
, entry_name
, rights_type
)
1288 procname
= GetProcNameForTask(task
)
1289 if unsigned(ipc_port
) != 0 and ipc_port
.ip_messages
.data
.port
.msgcount
> 0:
1290 sys
.stderr
.write(" checking {:s} busy-port {}:{:#x}...{:30s}\r".format(procname
, entry_name
, unsigned(ipc_port
), ''))
1291 ## Search through busy ports to find descriptors which could
1292 ## contain the only reference to this port!
1293 kmsgp
= Cast(ipc_port
.ip_messages
.data
.port
.messages
.ikmq_base
, 'ipc_kmsg_t')
1295 while unsigned(kmsgp
):
1296 entry_str
= FindKmsgPortRefs(entry_str
, task
, ipc_port
, kmsgp
, qport
)
1297 kmsgp
= kmsgp
.ikm_next
1298 if kmsgp
== kmsgheadp
:
1300 if len(entry_str
) > 0:
1301 sys
.stderr
.write("{:80s}\r".format(''))
1302 if port_iteration_do_print_taskname
:
1303 print "Task: {0: <#x} {1: <s}".format(task
, procname
)
1304 print '\t' + GetIPCEntrySummary
.header
1305 port_iteration_do_print_taskname
= False
1308 @lldb_command('findportrights', 'R:S:')
1309 def FindPortRights(cmd_args
=None, cmd_options
={}):
1310 """ Routine to locate and print all extant rights to a given port
1311 Usage: findportrights [-R rights_type] [-S <ipc_space_t>] <ipc_port_t>
1312 -S ipc_space : only search the specified ipc space
1313 -R rights_type : only display rights matching the string 'rights_type'
1320 'O' : Send-once right
1321 types of notifications:
1322 'd' : Dead-Name notification requested
1323 's' : Send-Possible notification armed
1324 'r' : Send-Possible notification requested
1325 'n' : No-Senders notification requested
1326 'x' : Port-destroy notification requested
1329 raise ArgumentError("no port address provided")
1330 port
= kern
.GetValueFromAddress(cmd_args
[0], 'struct ipc_port *')
1333 if "-R" in cmd_options
:
1334 rights_type
= cmd_options
["-R"]
1337 if "-S" in cmd_options
:
1338 space
= kern
.GetValueFromAddress(cmd_options
["-S"], 'struct ipc_space *')
1339 tasklist
= [ space
.is_task
]
1341 ## Don't include port sets
1342 ## Don't recurse on busy ports (we do that manually)
1344 IterateAllPorts(tasklist
, FindPortRightsCallback
, (port
, rights_type
), False, False, True)
1345 sys
.stderr
.write("{:120s}\r".format(' '))
1349 # EndMacro: findportrights
1351 # Macro: countallports
1353 def CountPortsCallback(task
, space
, ctx
, entry_idx
, ipc_entry
, ipc_port
, port_disp
):
1354 """ Callback which uses 'ctx' as the set of all ports found in the
1355 iteration. This should *not* be used from a recursive
1356 call to IterateAllPorts.
1358 global intransit_idx
1360 (p_set
, p_intransit
, p_bytask
) = ctx
1362 ## Add the port address to the set of all port addresses
1363 p_set
.add(unsigned(ipc_port
))
1365 if entry_idx
== intransit_idx
:
1366 p_intransit
.add(unsigned(ipc_port
))
1368 if task
.active
or (task
.halting
and not task
.active
):
1369 pname
= str(Cast(task
.bsd_info
, 'proc *').p_name
)
1370 if not pname
in p_bytask
.keys():
1371 p_bytask
[pname
] = { 'transit':0, 'table':0, 'other':0 }
1372 if entry_idx
== intransit_idx
:
1373 p_bytask
[pname
]['transit'] += 1
1374 elif entry_idx
>= 0:
1375 p_bytask
[pname
]['table'] += 1
1377 p_bytask
[pname
]['other'] += 1
1380 @lldb_command('countallports', 'P')
1381 def CountAllPorts(cmd_args
=None, cmd_options
={}):
1382 """ Routine to search for all as many references to ipc_port structures in the kernel
1384 Usage: countallports [-P]
1385 -P : include port sets in the count (default: NO)
1392 if "-P" in cmd_options
:
1395 ## optionally include port sets
1396 ## DO recurse on busy ports
1398 IterateAllPorts(None, CountPortsCallback
, (p_set
, p_intransit
, p_bytask
), find_psets
, True, True)
1399 sys
.stderr
.write("{:120s}\r".format(' '))
1401 print "Total ports found: {:d}".format(len(p_set
))
1402 print "In Transit: {:d}".format(len(p_intransit
))
1404 for pname
in sorted(p_bytask
.keys()):
1405 count
= p_bytask
[pname
]
1406 print "\t{: <20s}: table={: <5d}, transit={: <5d}, other={: <5d}".format(pname
, count
['table'], count
['transit'], count
['other'])
1408 # EndMacro: countallports
1410 # Macro: showpipestats
1411 @lldb_command('showpipestats')
1412 def ShowPipeStats(cmd_args
=None):
1413 """ Display pipes usage information in the kernel
1415 print "Number of pipes: {: d}".format(kern
.globals.amountpipes
)
1416 print "Memory used by pipes: {:s}".format(sizeof_fmt(int(kern
.globals.amountpipekva
)))
1417 print "Max memory allowed for pipes: {:s}".format(sizeof_fmt(int(kern
.globals.maxpipekva
)))
1418 # EndMacro: showpipestats
1420 # Macro: showtaskbusyports
1421 @lldb_command('showtaskbusyports')
1422 def ShowTaskBusyPorts(cmd_args
=None):
1423 """ Routine to print information about receive rights belonging to this task that
1424 have enqueued messages. This is oten a sign of a blocked or hung process
1425 Usage: showtaskbusyports <task address>
1428 print "No arguments passed. Please pass in the address of a task"
1429 print ShowTaskBusyPorts
.__doc
__
1431 task
= kern
.GetValueFromAddress(cmd_args
[0], 'task_t')
1432 PrintTaskBusyPorts(task
)
1435 def PrintTaskBusyPorts(task
):
1436 """ Prints all busy ports for a given task. ie. all receive rights belonging
1437 to this task that have enqueued messages.
1439 task : core.value representing a task in kernel
1441 str : String containing information about the given task's busy ports
1443 isp
= task
.itk_space
1445 while i
< isp
.is_table_size
:
1446 iep
= addressof(isp
.is_table
[i
])
1447 if iep
.ie_bits
& 0x00020000:
1448 port
= Cast(iep
.ie_object
, 'ipc_port_t')
1449 if port
.ip_messages
.data
.port
.msgcount
> 0:
1450 print PrintPortSummary
.header
1451 PrintPortSummary(port
)
1454 # EndMacro: showtaskbusyports
1456 # Macro: showallbusyports
1457 @lldb_command('showallbusyports')
1458 def ShowAllBusyPorts(cmd_args
=None):
1459 """ Routine to print information about all receive rights on the system that
1460 have enqueued messages.
1462 task_queue_head
= kern
.globals.tasks
1464 for tsk
in kern
.tasks
:
1465 PrintTaskBusyPorts(tsk
)
1467 # EndMacro: showallbusyports
1469 # Macro: showbusyportsummary
1470 @lldb_command('showbusyportsummary')
1471 def ShowBusyPortSummary(cmd_args
=None):
1472 """ Routine to print a summary of information about all receive rights
1473 on the system that have enqueued messages.
1475 task_queue_head
= kern
.globals.tasks
1481 print GetTaskBusyIPCSummary
.header
1482 for tsk
in kern
.tasks
:
1483 (summary
, table_size
, nbusy
, nmsgs
) = GetTaskBusyIPCSummary(tsk
)
1484 ipc_table_size
+= table_size
1485 ipc_busy_ports
+= nbusy
1488 for t
in kern
.terminated_tasks
:
1489 (summary
, table_size
, nbusy
, nmsgs
) = GetTaskBusyIPCSummary(tsk
)
1490 ipc_table_size
+= table_size
1491 ipc_busy_ports
+= nbusy
1494 print "Total Table Size: {:d}, Busy Ports: {:d}, Messages in-flight: {:d}".format(ipc_table_size
, ipc_busy_ports
, ipc_msgs
)
1496 # EndMacro: showbusyportsummary
1499 @lldb_command('showport','K')
1500 def ShowPort(cmd_args
=None, cmd_options
={}):
1501 """ Routine that lists details about a given IPC port
1502 Syntax: (lldb) showport 0xaddr
1505 if "-K" in cmd_options
:
1508 print "Please specify the address of the port whose details you want to print"
1509 print ShowPort
.__doc
__
1511 port
= kern
.GetValueFromAddress(cmd_args
[0], 'struct ipc_port *')
1512 print PrintPortSummary
.header
1513 PrintPortSummary(port
, show_kmsgs
)
1514 # EndMacro: showport
1516 # Macro: showmqueue:
1517 @lldb_command('showmqueue', "S:")
1518 def ShowMQueue(cmd_args
=None, cmd_options
={}):
1519 """ Routine that lists details about a given mqueue
1520 Syntax: (lldb) showmqueue 0xaddr [-S ipc_space]
1523 print "Please specify the address of the ipc_mqueue whose details you want to print"
1524 print ShowMQueue
.__doc
__
1527 if "-S" in cmd_options
:
1528 space
= kern
.GetValueFromAddress(cmd_options
["-S"], 'struct ipc_space *')
1529 mqueue
= kern
.GetValueFromAddress(cmd_args
[0], 'struct ipc_mqueue *')
1530 wq_type
= mqueue
.data
.pset
.setq
.wqset_q
.waitq_type
1531 if int(wq_type
) == 3:
1532 psetoff
= getfieldoffset('struct ipc_pset', 'ips_messages')
1533 pset
= unsigned(ArgumentStringToInt(cmd_args
[0])) - unsigned(psetoff
)
1534 print PrintPortSetSummary
.header
1535 PrintPortSetSummary(kern
.GetValueFromAddress(pset
, 'struct ipc_pset *'), space
)
1536 elif int(wq_type
) == 2:
1537 portoff
= getfieldoffset('struct ipc_port', 'ip_messages')
1538 port
= unsigned(ArgumentStringToInt(cmd_args
[0])) - unsigned(portoff
)
1539 print PrintPortSummary
.header
1540 PrintPortSummary(kern
.GetValueFromAddress(port
, 'struct ipc_port *'))
1542 print "Invalid mqueue? (waitq type {:d} is invalid)".format(int(wq_type
))
1543 # EndMacro: showmqueue
1546 @lldb_command('showkmsg')
1547 def ShowKMSG(cmd_args
=[]):
1548 """ Show detail information about a <ipc_kmsg_t> structure
1549 Usage: (lldb) showkmsg <ipc_kmsg_t>
1552 raise ArgumentError('Invalid arguments')
1553 kmsg
= kern
.GetValueFromAddress(cmd_args
[0], 'ipc_kmsg_t')
1554 print GetKMsgSummary
.header
1555 print GetKMsgSummary(kmsg
)
1557 # EndMacro: showkmsg
1560 @lldb_command('showpset', "S:")
1561 def ShowPSet(cmd_args
=None, cmd_options
={}):
1562 """ Routine that prints details for a given ipc_pset *
1563 Syntax: (lldb) showpset 0xaddr [-S ipc_space]
1566 print "Please specify the address of the pset whose details you want to print"
1567 print ShowPSet
.__doc
__
1570 if "-S" in cmd_options
:
1571 space
= kern
.GetValueFromAddress(cmd_options
["-S"], 'struct ipc_space *')
1573 print PrintPortSetSummary
.header
1574 PrintPortSetSummary(kern
.GetValueFromAddress(cmd_args
[0], 'ipc_pset *'), space
)
1575 # EndMacro: showpset
1577 # IPC importance inheritance related macros.
1579 @lldb_command('showalliits')
1580 def ShowAllIITs(cmd_args
=[], cmd_options
={}):
1581 """ Development only macro. Show list of all iits allocated in the system. """
1583 iit_queue
= kern
.globals.global_iit_alloc_queue
1585 print "This debug macro is only available in development or debug kernels"
1588 print GetIPCImportantTaskSummary
.header
1589 for iit
in IterateQueue(iit_queue
, 'struct ipc_importance_task *', 'iit_allocation'):
1590 print GetIPCImportantTaskSummary(iit
)
1593 @header("{: <18s} {: <3s} {: <18s} {: <20s} {: <18s} {: <8s}".format("ipc_imp_inherit", "don", "to_task", "proc_name", "from_elem", "depth"))
1594 @lldb_type_summary(['ipc_importance_inherit *', 'ipc_importance_inherit_t'])
1595 def GetIPCImportanceInheritSummary(iii
):
1596 """ describes iii object of type ipc_importance_inherit_t * """
1598 fmt
= "{o: <#018x} {don: <3s} {o.iii_to_task.iit_task: <#018x} {task_name: <20s} {o.iii_from_elem: <#018x} {o.iii_depth: <#08x}"
1600 if unsigned(iii
.iii_donating
):
1601 donating_str
= "DON"
1602 taskname
= GetProcNameForTask(iii
.iii_to_task
.iit_task
)
1603 if hasattr(iii
.iii_to_task
, 'iit_bsd_pid'):
1604 taskname
= "({:d}) {:s}".format(iii
.iii_to_task
.iit_bsd_pid
, iii
.iii_to_task
.iit_procname
)
1605 out_str
+= fmt
.format(o
=iii
, task_name
= taskname
, don
=donating_str
)
1608 @static_var('recursion_count', 0)
1609 @header("{: <18s} {: <4s} {: <8s} {: <8s} {: <18s} {: <18s}".format("iie", "type", "refs", "made", "#kmsgs", "#inherits"))
1610 @lldb_type_summary(['ipc_importance_elem *'])
1611 def GetIPCImportanceElemSummary(iie
):
1612 """ describes an ipc_importance_elem * object """
1614 if GetIPCImportanceElemSummary
.recursion_count
> 500:
1615 GetIPCImportanceElemSummary
.recursion_count
= 0
1616 return "Recursion of 500 reached"
1619 fmt
= "{: <#018x} {: <4s} {: <8d} {: <8d} {: <#018x} {: <#018x}"
1620 if unsigned(iie
.iie_bits
) & 0x80000000:
1625 iit
= Cast(iie
, 'struct ipc_importance_task *')
1626 inherit_count
= sum(1 for i
in IterateQueue(iit
.iit_inherits
, 'struct ipc_importance_inherit *', 'iii_inheritance'))
1628 refs
= unsigned(iie
.iie_bits
) & 0x7fffffff
1629 made_refs
= unsigned(iie
.iie_made
)
1630 kmsg_count
= sum(1 for i
in IterateQueue(iie
.iie_kmsgs
, 'struct ipc_kmsg *', 'ikm_inheritance'))
1631 out_str
+= fmt
.format(iie
, type_str
, refs
, made_refs
, kmsg_count
, inherit_count
)
1632 if config
['verbosity'] > vHUMAN
:
1634 out_str
+= "\n\t"+ GetKMsgSummary
.header
1635 for k
in IterateQueue(iie
.iie_kmsgs
, 'struct ipc_kmsg *', 'ikm_inheritance'):
1636 out_str
+= "\t" + "{: <#018x}".format(k
.ikm_header
.msgh_remote_port
) + ' ' + GetKMsgSummary(k
, "\t").lstrip()
1638 if inherit_count
> 0:
1639 out_str
+= "\n\t" + GetIPCImportanceInheritSummary
.header
+ "\n"
1640 for i
in IterateQueue(iit
.iit_inherits
, 'struct ipc_importance_inherit *', 'iii_inheritance'):
1641 out_str
+= "\t" + GetIPCImportanceInheritSummary(i
) + "\n"
1643 if type_str
== "INH":
1644 iii
= Cast(iie
, 'struct ipc_importance_inherit *')
1645 out_str
+= "Inherit from: " + GetIPCImportanceElemSummary(iii
.iii_from_elem
)
1649 @header("{: <18s} {: <18s} {: <20s}".format("iit", "task", "name"))
1650 @lldb_type_summary(['ipc_importance_task *'])
1651 def GetIPCImportantTaskSummary(iit
):
1652 """ iit is a ipc_importance_task value object.
1654 fmt
= "{: <#018x} {: <#018x} {: <20s}"
1656 pname
= GetProcNameForTask(iit
.iit_task
)
1657 if hasattr(iit
, 'iit_bsd_pid'):
1658 pname
= "({:d}) {:s}".format(iit
.iit_bsd_pid
, iit
.iit_procname
)
1659 out_str
+= fmt
.format(iit
, iit
.iit_task
, pname
)
1662 @lldb_command('showallimportancetasks')
1663 def ShowIPCImportanceTasks(cmd_args
=[], cmd_options
={}):
1664 """ display a list of all tasks with ipc importance information.
1665 Usage: (lldb) showallimportancetasks
1666 Tip: add "-v" to see detailed information on each kmsg or inherit elems
1668 print ' ' + GetIPCImportantTaskSummary
.header
+ ' ' + GetIPCImportanceElemSummary
.header
1669 for t
in kern
.tasks
:
1671 if unsigned(t
.task_imp_base
):
1672 s
+= ' ' + GetIPCImportantTaskSummary(t
.task_imp_base
)
1673 s
+= ' ' + GetIPCImportanceElemSummary(addressof(t
.task_imp_base
.iit_elem
))
1676 @lldb_command('showipcimportance', '')
1677 def ShowIPCImportance(cmd_args
=[], cmd_options
={}):
1678 """ Describe an importance from <ipc_importance_elem_t> argument.
1679 Usage: (lldb) showimportance <ipc_importance_elem_t>
1682 raise ArgumentError("Please provide valid argument")
1684 elem
= kern
.GetValueFromAddress(cmd_args
[0], 'ipc_importance_elem_t')
1685 print GetIPCImportanceElemSummary
.header
1686 print GetIPCImportanceElemSummary(elem
)
1688 @header("{: <18s} {: <10s} {: <18s} {: <18s} {: <8s} {: <5s} {: <5s} {: <5s}".format("ivac", "refs", "port", "tbl", "tblsize", "index", "Grow", "freelist"))
1689 @lldb_type_summary(['ipc_voucher_attr_control *', 'ipc_voucher_attr_control_t'])
1690 def GetIPCVoucherAttrControlSummary(ivac
):
1691 """ describes a voucher attribute control settings """
1693 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}"
1696 if unsigned(ivac
) == 0:
1697 return "{: <#018x}".format(ivac
)
1699 if unsigned(ivac
.ivac_is_growing
):
1701 out_str
+= fmt
.format(c
=ivac
, growing
= growing_str
)
1704 @lldb_command('showivac','')
1705 def ShowIPCVoucherAttributeControl(cmd_args
=[], cmd_options
={}):
1706 """ Show summary of voucher attribute contols.
1707 Usage: (lldb) showivac <ipc_voucher_attr_control_t>
1710 raise ArgumentError("Please provide correct arguments.")
1711 ivac
= kern
.GetValueFromAddress(cmd_args
[0], 'ipc_voucher_attr_control_t')
1712 print GetIPCVoucherAttrControlSummary
.header
1713 print GetIPCVoucherAttrControlSummary(ivac
)
1714 if config
['verbosity'] > vHUMAN
:
1716 last_entry_index
= unsigned(ivac
.ivac_table_size
)
1717 print "index " + GetIPCVoucherAttributeEntrySummary
.header
1718 while cur_entry_index
< last_entry_index
:
1719 print "{: <5d} ".format(cur_entry_index
) + GetIPCVoucherAttributeEntrySummary(addressof(ivac
.ivac_table
[cur_entry_index
]))
1720 cur_entry_index
+= 1
1725 @header("{: <18s} {: <30s} {: <30s} {: <30s} {: <30s} {: <30s}".format("ivam", "get_value_fn", "extract_fn", "release_value_fn", "command_fn", "release_fn"))
1726 @lldb_type_summary(['ipc_voucher_attr_manager *', 'ipc_voucher_attr_manager_t'])
1727 def GetIPCVoucherAttrManagerSummary(ivam
):
1728 """ describes a voucher attribute manager settings """
1730 fmt
= "{: <#018x} {: <30s} {: <30s} {: <30s} {: <30s} {: <30s}"
1732 if unsigned(ivam
) == 0 :
1733 return "{: <#018x}".format(ivam
)
1735 get_value_fn
= kern
.Symbolicate(unsigned(ivam
.ivam_get_value
))
1736 extract_fn
= kern
.Symbolicate(unsigned(ivam
.ivam_extract_content
))
1737 release_value_fn
= kern
.Symbolicate(unsigned(ivam
.ivam_release_value
))
1738 command_fn
= kern
.Symbolicate(unsigned(ivam
.ivam_command
))
1739 release_fn
= kern
.Symbolicate(unsigned(ivam
.ivam_release
))
1740 out_str
+= fmt
.format(ivam
, get_value_fn
, extract_fn
, release_value_fn
, command_fn
, release_fn
)
1745 @header("{: <18s} {: <10s} {:s} {:s}".format("ivgte", "key", GetIPCVoucherAttrControlSummary
.header
.strip(), GetIPCVoucherAttrManagerSummary
.header
.strip()))
1746 @lldb_type_summary(['ipc_voucher_global_table_element *', 'ipc_voucher_global_table_element_t'])
1747 def GetIPCVoucherGlobalTableElementSummary(ivgte
):
1748 """ describes a ipc_voucher_global_table_element object """
1750 fmt
= "{g: <#018x} {g.ivgte_key: <10d} {ctrl_s:s} {mgr_s:s}"
1751 out_str
+= fmt
.format(g
=ivgte
, ctrl_s
=GetIPCVoucherAttrControlSummary(ivgte
.ivgte_control
), mgr_s
=GetIPCVoucherAttrManagerSummary(ivgte
.ivgte_manager
))
1754 @lldb_command('showglobalvouchertable', '')
1755 def ShowGlobalVoucherTable(cmd_args
=[], cmd_options
={}):
1756 """ show detailed information of all voucher attribute managers registered with vouchers system
1757 Usage: (lldb) showglobalvouchertable
1759 entry_size
= sizeof(kern
.globals.iv_global_table
[0])
1760 elems
= sizeof(kern
.globals.iv_global_table
) / entry_size
1761 print GetIPCVoucherGlobalTableElementSummary
.header
1762 for i
in range(elems
):
1763 elt
= addressof(kern
.globals.iv_global_table
[i
])
1764 print GetIPCVoucherGlobalTableElementSummary(elt
)
1766 # Type summaries for Bag of Bits.
1768 @lldb_type_summary(['user_data_value_element', 'user_data_element_t'])
1769 @header("{0: <20s} {1: <16s} {2: <20s} {3: <20s} {4: <16s} {5: <20s}".format("user_data_ve", "maderefs", "checksum", "hash value", "size", "data"))
1770 def GetBagofBitsElementSummary(data_element
):
1771 """ Summarizes the Bag of Bits element
1772 params: data_element = value of the object of type user_data_value_element_t
1773 returns: String with summary of the type.
1775 format_str
= "{0: <#020x} {1: <16d} {2: <#020x} {3: <#020x} {4: <16d}"
1776 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
))
1779 for i
in range(0, (unsigned(data_element
.e_size
) - 1)):
1780 out_string
+= "{:02x}".format(int(data_element
.e_data
[i
]))
1783 def GetIPCHandleSummary(handle_ptr
):
1784 """ converts a handle value inside a voucher attribute table to ipc element and returns appropriate summary.
1785 params: handle_ptr - uint64 number stored in handle of voucher.
1786 returns: str - string summary of the element held in internal structure
1788 elem
= kern
.GetValueFromAddress(handle_ptr
, 'ipc_importance_elem_t')
1789 if elem
.iie_bits
& 0x80000000 :
1790 iie
= Cast(elem
, 'struct ipc_importance_inherit *')
1791 return GetIPCImportanceInheritSummary(iie
)
1793 iit
= Cast(elem
, 'struct ipc_importance_task *')
1794 return GetIPCImportantTaskSummary(iit
)
1796 def GetATMHandleSummary(handle_ptr
):
1797 """ Convert a handle value to atm value and returns corresponding summary of its fields.
1798 params: handle_ptr - uint64 number stored in handle of voucher
1799 returns: str - summary of atm value
1801 elem
= kern
.GetValueFromAddress(handle_ptr
, 'atm_value *')
1802 return GetATMValueSummary(elem
)
1804 def GetBankHandleSummary(handle_ptr
):
1805 """ converts a handle value inside a voucher attribute table to bank element and returns appropriate summary.
1806 params: handle_ptr - uint64 number stored in handle of voucher.
1807 returns: str - summary of bank element
1809 if handle_ptr
== 1 :
1810 return "Bank task of Current task"
1811 elem
= kern
.GetValueFromAddress(handle_ptr
, 'bank_element_t')
1812 if elem
.be_type
& 1 :
1813 ba
= Cast(elem
, 'struct bank_account *')
1814 return GetBankAccountSummary(ba
)
1816 bt
= Cast(elem
, 'struct bank_task *')
1817 return GetBankTaskSummary(bt
)
1819 def GetBagofBitsHandleSummary(handle_ptr
):
1820 """ Convert a handle value to bag of bits value and returns corresponding summary of its fields.
1821 params: handle_ptr - uint64 number stored in handle of voucher
1822 returns: str - summary of bag of bits element
1824 elem
= kern
.GetValueFromAddress(handle_ptr
, 'user_data_element_t')
1825 return GetBagofBitsElementSummary(elem
)
1827 @static_var('attr_managers',{1: GetATMHandleSummary, 2: GetIPCHandleSummary, 3: GetBankHandleSummary, 7: GetBagofBitsHandleSummary}
)
1828 def GetHandleSummaryForKey(handle_ptr
, key_num
):
1829 """ Get a summary of handle pointer from the voucher attribute manager.
1830 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.
1831 key 2 -> ipc and it puts either ipc_importance_inherit_t or ipc_important_task_t.
1832 key 3 -> Bank and it puts either bank_task_t or bank_account_t.
1833 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.
1835 key_num
= int(key_num
)
1836 if key_num
not in GetHandleSummaryForKey
.attr_managers
:
1837 return "Unknown key %d" % key_num
1838 return GetHandleSummaryForKey
.attr_managers
[key_num
](handle_ptr
)
1841 @header("{: <18s} {: <18s} {: <10s} {: <4s} {: <18s} {: <18s}".format("ivace", "value_handle", "#refs", "rel?", "maderefs", "next_layer"))
1842 @lldb_type_summary(['ivac_entry *', 'ivac_entry_t'])
1843 def GetIPCVoucherAttributeEntrySummary(ivace
, manager_key_num
= 0):
1844 """ Get summary for voucher attribute entry.
1847 fmt
= "{e: <#018x} {e.ivace_value: <#018x} {e.ivace_refs: <10d} {release: <4s} {made_refs: <18s} {next_layer: <18s}"
1853 if unsigned(ivace
.ivace_releasing
):
1855 if unsigned(ivace
.ivace_free
):
1857 if unsigned(ivace
.ivace_layered
):
1858 next_layer
= "{: <#018x}".format(ivace
.ivace_u
.ivaceu_layer
)
1860 made_refs
= "{: <18d}".format(ivace
.ivace_u
.ivaceu_made
)
1862 out_str
+= fmt
.format(e
=ivace
, release
=release_str
, made_refs
=made_refs
, next_layer
=next_layer
)
1863 if config
['verbosity'] > vHUMAN
and manager_key_num
> 0:
1864 out_str
+= " " + GetHandleSummaryForKey(unsigned(ivace
.ivace_value
), manager_key_num
)
1865 if config
['verbosity'] > vHUMAN
:
1866 out_str
+= ' {: <2s} {: <4d} {: <4d}'.format(free_str
, ivace
.ivace_next
, ivace
.ivace_index
)
1869 @lldb_command('showivacfreelist','')
1870 def ShowIVACFreeList(cmd_args
=[], cmd_options
={}):
1871 """ Walk the free list and print every entry in the list.
1872 usage: (lldb) showivacfreelist <ipc_voucher_attr_control_t>
1875 raise ArgumentError('Please provide <ipc_voucher_attr_control_t>')
1876 ivac
= kern
.GetValueFromAddress(cmd_args
[0], 'ipc_voucher_attr_control_t')
1877 print GetIPCVoucherAttrControlSummary
.header
1878 print GetIPCVoucherAttrControlSummary(ivac
)
1879 if unsigned(ivac
.ivac_freelist
) == 0:
1880 print "ivac table is full"
1882 print "index " + GetIPCVoucherAttributeEntrySummary
.header
1883 next_free
= unsigned(ivac
.ivac_freelist
)
1884 while next_free
!= 0:
1885 print "{: <5d} ".format(next_free
) + GetIPCVoucherAttributeEntrySummary(addressof(ivac
.ivac_table
[next_free
]))
1886 next_free
= unsigned(ivac
.ivac_table
[next_free
].ivace_next
)
1890 @header('{: <18s} {: <8s} {: <18s} {: <18s} {: <18s} {: <18s} {: <18s}'.format("ipc_voucher", "refs", "checksum", "hash", "tbl_size", "table", "voucher_port"))
1891 @lldb_type_summary(['ipc_voucher *', 'ipc_voucher_t'])
1892 def GetIPCVoucherSummary(voucher
, show_entries
=False):
1893 """ describe a voucher from its ipc_voucher * object """
1895 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}"
1896 out_str
+= fmt
.format(v
= voucher
)
1898 if show_entries
or config
['verbosity'] > vHUMAN
:
1899 elems
= unsigned(voucher
.iv_table_size
)
1900 entries_header_str
= "\n\t" + "{: <5s} {: <3s} {: <16s} {: <30s}".format("index", "key", "value_index", "manager") + " " + GetIPCVoucherAttributeEntrySummary
.header
1901 fmt
= "{: <5d} {: <3d} {: <16d} {: <30s}"
1902 for i
in range(elems
):
1903 voucher_entry_index
= unsigned(voucher
.iv_inline_table
[i
])
1904 if voucher_entry_index
:
1905 s
= fmt
.format(i
, GetVoucherManagerKeyForIndex(i
), voucher_entry_index
, GetVoucherAttributeManagerNameForIndex(i
))
1906 e
= GetVoucherValueHandleFromVoucherForIndex(voucher
, i
)
1908 s
+= " " + GetIPCVoucherAttributeEntrySummary(addressof(e
), GetVoucherManagerKeyForIndex(i
) )
1909 if entries_header_str
:
1910 entries_str
= entries_header_str
1911 entries_header_str
= ''
1912 entries_str
+= "\n\t" + s
1913 if not entries_header_str
:
1914 entries_str
+= "\n\t"
1915 out_str
+= entries_str
1918 def GetVoucherManagerKeyForIndex(idx
):
1919 """ Returns key number for index based on global table. Will raise index error if value is incorrect
1921 return unsigned(kern
.globals.iv_global_table
[idx
].ivgte_key
)
1923 def GetVoucherAttributeManagerForKey(k
):
1924 """ Walks through the iv_global_table and finds the attribute manager name
1925 params: k - int key number of the manager
1926 return: cvalue - the attribute manager object.
1930 entry_size
= sizeof(kern
.globals.iv_global_table
[0])
1931 elems
= sizeof(kern
.globals.iv_global_table
) / entry_size
1932 for i
in range(elems
):
1933 elt
= addressof(kern
.globals.iv_global_table
[i
])
1934 if k
== unsigned(elt
.ivgte_key
):
1935 retval
= elt
.ivgte_manager
1939 def GetVoucherAttributeControllerForKey(k
):
1940 """ Walks through the iv_global_table and finds the attribute controller
1941 params: k - int key number of the manager
1942 return: cvalue - the attribute controller object.
1946 entry_size
= sizeof(kern
.globals.iv_global_table
[0])
1947 elems
= sizeof(kern
.globals.iv_global_table
) / entry_size
1948 for i
in range(elems
):
1949 elt
= addressof(kern
.globals.iv_global_table
[i
])
1950 if k
== unsigned(elt
.ivgte_key
):
1951 retval
= elt
.ivgte_control
1956 def GetVoucherAttributeManagerName(ivam
):
1957 """ find the name of the ivam object
1958 param: ivam - cvalue object of type ipc_voucher_attr_manager_t
1959 returns: str - name of the manager
1961 return kern
.Symbolicate(unsigned(ivam
))
1963 def GetVoucherAttributeManagerNameForIndex(idx
):
1964 """ get voucher attribute manager name for index
1965 return: str - name of the attribute manager object
1967 return GetVoucherAttributeManagerName(GetVoucherAttributeManagerForKey(GetVoucherManagerKeyForIndex(idx
)))
1969 def GetVoucherValueHandleFromVoucherForIndex(voucher
, idx
):
1970 """ traverse the voucher attrs and get value_handle in the voucher attr controls table
1972 voucher - cvalue object of type ipc_voucher_t
1973 idx - int index in the entries for which you wish to get actual handle for
1974 returns: cvalue object of type ivac_entry_t
1975 None if no handle found.
1977 manager_key
= GetVoucherManagerKeyForIndex(idx
)
1978 voucher_num_elems
= unsigned(voucher
.iv_table_size
)
1979 if idx
>= voucher_num_elems
:
1980 debuglog("idx %d is out of range max: %d" % (idx
, voucher_num_elems
))
1982 voucher_entry_value
= unsigned(voucher
.iv_inline_table
[idx
])
1983 debuglog("manager_key %d" % manager_key
)
1984 ivac
= GetVoucherAttributeControllerForKey(manager_key
)
1985 if ivac
is None or unsigned(ivac
) == 0:
1986 debuglog("No voucher attribute controller for idx %d" % idx
)
1989 ivac
= kern
.GetValueFromAddress(unsigned(ivac
), 'ipc_voucher_attr_control_t') # ??? No idea why lldb does not addressof directly
1990 ivace_table
= ivac
.ivac_table
1991 if voucher_entry_value
>= unsigned(ivac
.ivac_table_size
):
1992 print "Failed to get ivace for value %d in table of size %d" % (voucher_entry_value
, unsigned(ivac
.ivac_table_size
))
1994 return ivace_table
[voucher_entry_value
]
1998 @lldb_command('showallvouchers')
1999 def ShowAllVouchers(cmd_args
=[], cmd_options
={}):
2000 """ Display a list of all vouchers in the global voucher hash table
2001 Usage: (lldb) showallvouchers
2003 iv_hash_table
= kern
.globals.ivht_bucket
2004 num_buckets
= sizeof(kern
.globals.ivht_bucket
) / sizeof(kern
.globals.ivht_bucket
[0])
2005 print GetIPCVoucherSummary
.header
2006 for i
in range(num_buckets
):
2007 for v
in IterateQueue(iv_hash_table
[i
], 'ipc_voucher_t', 'iv_hash_link'):
2008 print GetIPCVoucherSummary(v
)
2010 @lldb_command('showvoucher', '')
2011 def ShowVoucher(cmd_args
=[], cmd_options
={}):
2012 """ Describe a voucher from <ipc_voucher_t> argument.
2013 Usage: (lldb) showvoucher <ipc_voucher_t>
2016 raise ArgumentError("Please provide valid argument")
2018 voucher
= kern
.GetValueFromAddress(cmd_args
[0], 'ipc_voucher_t')
2019 print GetIPCVoucherSummary
.header
2020 print GetIPCVoucherSummary(voucher
, show_entries
=True)
2022 def GetSpaceSendRightEntries(space
, port
):
2023 """ Get entry summaries for all send rights to port address in an IPC space.
2025 space - the IPC space to search for send rights
2026 port_addr - the port address to match, or 0 to get all send rights
2027 returns: an array of IPC entries
2029 entry_table
= space
.is_table
2030 ports
= int(space
.is_table_size
)
2035 entry
= GetObjectAtIndexFromArray(entry_table
, i
)
2037 entry_ie_bits
= unsigned(entry
.ie_bits
)
2038 if (entry_ie_bits
& 0x00010000) != 0 and (not port
or entry
.ie_object
== port
):
2039 entries
.append(entry
)
2044 @lldb_command('showportsendrights')
2045 def ShowPortSendRights(cmd_args
=[], cmd_options
={}):
2046 """ Display a list of send rights across all tasks for a given port.
2047 Usage: (lldb) showportsendrights <ipc_port_t>
2050 raise ArgumentError("no port address provided")
2051 port
= kern
.GetValueFromAddress(cmd_args
[0], 'struct ipc_port *')
2054 return FindPortRights(cmd_args
=[unsigned(port
)], cmd_options
={'-R':'S'}
)
2057 @lldb_command('showtasksuspenders')
2058 def ShowTaskSuspenders(cmd_args
=[], cmd_options
={}):
2059 """ Display the tasks and send rights that are holding a target task suspended.
2060 Usage: (lldb) showtasksuspenders <task_t>
2063 raise ArgumentError("no task address provided")
2064 task
= kern
.GetValueFromAddress(cmd_args
[0], 'task_t')
2066 if task
.suspend_count
== 0:
2067 print "task {:#x} ({:s}) is not suspended".format(unsigned(task
), Cast(task
.bsd_info
, 'proc_t').p_name
)
2070 # If the task has been suspended by the kernel (potentially by
2071 # kperf, using task_suspend_internal) or a client of task_suspend2
2072 # that does not convert its task suspension token to a port using
2073 # convert_task_suspension_token_to_port, then it's impossible to determine
2074 # which task did the suspension.
2075 port
= task
.itk_resume
2077 print "task {:#x} ({:s}) is suspended but no resume port exists".format(unsigned(task
), Cast(task
.bsd_info
, 'proc_t').p_name
)
2080 return FindPortRights(cmd_args
=[unsigned(port
)], cmd_options
={'-R':'S'}
)