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