1""" Please make sure you read the README file COMPLETELY BEFORE reading anything below.
2    It is very critical that you read coding guidelines in Section E in README file.
3"""
4from xnu import *
5import sys, shlex
6from utils import *
7from process import *
8import xnudefines
9
10@header("{0: <20s} {1: <6s} {2: <6s} {3: <10s} {4: <15s}".format("task", "pid", '#acts', "tablesize", "command"))
11def GetTaskIPCSummary(task):
12    """ Display a task's ipc summary.
13        params:
14            task : core.value represeting a Task in kernel
15        returns
16            str - string of ipc info for the task
17    """
18    out_string = ''
19    format_string = "{0: <#020x} {1: <6d} {2: <6d} {3: <10d} {4: <15s}"
20    pval = Cast(task.bsd_info, 'proc *')
21    table_size = int(task.itk_space.is_table_size)
22    proc_name = str(pval.p_comm)
23    out_string += format_string.format(task, pval.p_pid, task.thread_count, table_size, proc_name)
24    return out_string
25
26@header("{0: <20s} {1: <28s} {2: <12s} {3: <6s} {4: <4s}  {5: <20s} {6: <4s}\n".format(
27            "port", "mqueue", "recvname", "flags", "refs", "recvname", "dest"))
28def GetPortSummary(port, show_kmsg_summary=True, prefix=""):
29    """ Display a port's summary
30        params:
31            port : core.value representing a port in the kernel
32        returns
33            str  : string of ipc info for the given port
34    """
35    out_string = ""
36    portp = Cast(port, 'struct ipc_port *')
37    destspacep = kern.GetValueFromAddress(0, 'struct ipc_space *')
38    spacep = portp.data.receiver
39    format_string = "{0: #019x} {1: #019x} {2: <8s} {3: #011x}   {4: <5s} {5: #05x}  {6: #019x}  {7: <16s}\n"
40    if portp.ip_object.io_bits & 0x80000000:
41        out_string += prefix + format_string.format(
42                                unsigned(portp), addressof(portp.ip_messages), ' '*8,
43                                unsigned(portp.ip_messages.data.port.receiver_name),
44                                "APort", portp.ip_object.io_references,
45                                unsigned(portp.ip_messages.data.port.receiver_name),
46                                GetPortDestProc(portp))
47    else:
48        out_string += prefix + format_string.format(
49                                unsigned(portp), addressof(portp.ip_messages), ' '*8,
50                                unsigned(portp.ip_messages.data.port.receiver_name),
51                                "DPort", portp.ip_object.io_references, unsigned(portp),
52                                "inactive-port")
53
54    if show_kmsg_summary:
55        kmsgp = Cast(portp.ip_messages.data.port.messages.ikmq_base, 'ipc_kmsg_t')
56        out_string += prefix + GetKMsgSummary.header + prefix + GetKMsgSummary(kmsgp)
57
58        kmsgheadp = kmsgp
59        kmsgp = kmsgp.ikm_next
60        while (kmsgp) != (kmsgheadp):
61            out_string += prefix + GetKMsgSummary(kmsgp)
62            kmsgp = kmsgp.ikm_next
63    return out_string
64
65def GetPortDestProc(portp):
66    """ Display the name and pid of a given port's receiver
67        params:
68            portp : core.value representing a pointer to a port in the kernel
69            destspacep : core.value representing a pointer to an ipc_space
70        returns:
71            str   : string containing receiver's name and pid
72    """
73    spacep = portp.data.receiver
74    out_str = "Not found"
75    for tsk in kern.tasks:
76        if tsk.itk_space == spacep:
77            if tsk.bsd_info:
78                destprocp = Cast(tsk.bsd_info, 'struct proc *')
79                out_str = "{0:s}({1: <d})".format(destprocp.p_comm, destprocp.p_pid)
80            else:
81                out_str = "task {0: #019x}".format(desttaskp)
82            break
83
84    return out_str
85
86@header("{0: <20s} {1: <28s} {2: <12s} {3: <6s} {4: <6s} {5: <19s} {6: <6s}\n".format(
87            "dest-port", "kmsg", "msgid", "disp", "size", "reply-port", "source"))
88def GetKMsgSummary(kmsgp):
89    """ Display a summary for type ipc_kmsg_t
90        params:
91            kmsgp : core.value representing the given ipc_kmsg_t struct
92        returns:
93            str   : string of summary info for the given ipc_kmsg_t instance
94    """
95    kmsghp = kmsgp.ikm_header
96    kmsgh = dereference(kmsghp)
97    out_string = ""
98    out_string += "{0: <19s} {1: #019x} {2: <8s} {3: #011x}   ".format(
99                    ' '*19, unsigned(kmsgp), ' '*8, kmsgh.msgh_id)
100
101    if (kmsgh.msgh_bits & 0xff) == 19:
102        out_string += "{0: <2s}".format("rC")
103    else:
104        out_string += "{0: <2s}".format("rM")
105
106    if (kmsgh.msgh_bits & 0xff00) == (19 << 8):
107        out_string += "{0: <2s}".format("lC")
108    else:
109        out_string += "{0: <2s}".format("lM")
110    if kmsgh.msgh_bits & 0xf0000000:
111        out_string += "{0: <2s}".format("c")
112    else:
113        out_string += "{0: <2s}".format("s")
114
115    out_string += "{0: >5d}  {1: #019x}  {2: <16s}\n".format(
116                    unsigned(kmsgh.msgh_size), kmsgh.msgh_local_port,
117                    GetKMsgSrc(kmsgp))
118    return out_string
119
120def GetKMsgSrc(kmsgp):
121    """ Routine that prints a kmsg's source process and pid details
122        params:
123            kmsgp : core.value representing the given ipc_kmsg_t struct
124        returns:
125            str  : string containing the name and pid of the kmsg's source proc
126    """
127    kmsgsrchp = Cast(kmsgp, 'ipc_kmsg_t').ikm_header
128    kmsgpid = int(Cast(kern.GetValueFromAddress(unsigned(kmsgsrchp) + kmsgsrchp.msgh_size, 'uint *')[10], 'pid_t'))
129
130    return "{0:s} ({1:d})".format(GetProcNameForPid(kmsgpid), kmsgpid)
131
132@header("{0: <20s} {1: <28s} {2: <12s} {3: <6s} {4: <6s} {5: <20s} {6: <7s}\n".format(
133            "portset", "waitqueue", "recvname", "flags", "refs", "recvname", "process"))
134def GetPortSetSummary(pset):
135    """ Display summary for a given struct ipc_pset *
136        params:
137            pset : core.value representing a pset in the kernel
138        returns:
139            str  : string of summary information for the given pset
140    """
141    out_str = ""
142    if pset.ips_object.io_bits & 0x80000000:
143        out_str += "{0: #019x}  {1: #019x} {2: <7s} {3: #011x}   {4: <4s} {5: >6d}  {6: #019x}   ".format(
144                    unsigned(pset), addressof(pset.ips_messages), ' '*7,
145                    pset.ips_messages.data.pset.local_name, "ASet",
146                    pset.ips_object.io_references,
147                    pset.ips_messages.data.pset.local_name)
148
149    else:
150        out_str += "{0: #019x}  {1: #019x} {2: <7s} {3: #011x}   {4: <4s} {5: >6d}  {6: #019x}   ".format(
151                    unsigned(pset), addressof(pset.ips_messages), ' '*7,
152                    pset.ips_messages.data.pset.local_name, "DSet",
153                    pset.ips_object.io_references,
154                    pset.ips_messages.data.pset.local_name)
155
156    once = True
157    setlinksp = addressof(pset.ips_messages.data.pset.set_queue.wqs_setlinks)
158    wql = Cast(pset.ips_messages.data.pset.set_queue.wqs_setlinks.next, 'WaitQueueLink *')
159    portoff = getfieldoffset('struct ipc_port', 'ip_messages')
160    prefix_str = "{0:<21s}".format(' '*21)
161    while unsigned(wql) != unsigned(Cast(setlinksp, 'void *')):
162        portp = kern.GetValueFromAddress(unsigned(wql.wql_element.wqe_queue) - portoff, 'ipc_port *')
163        if once:
164            once = False
165            out_str += "{0:s}\n{1:s}{2:s}".format(GetPortDestProc(portp), prefix_str, GetPortSummary.header)
166        out_str += GetPortSummary(portp, False, prefix_str)
167        wql = Cast(wql.wql_setlinks.next, 'WaitQueueLink *')
168    return out_str
169
170# Macro: showipc
171
172@lldb_command('showipc')
173def ShowIPC(cmd_args=None):
174    """  Routine to print data for the given IPC space
175         Usage: showipc <address of ipc space>
176    """
177    if not cmd_args:
178        print "No arguments passed"
179        print ShowIPC.__doc__
180        return False
181    ipc = kern.GetValueFromAddress(cmd_args[0], 'ipc_space *')
182    if not ipc:
183        print "unknown arguments:", str(cmd_args)
184        return False
185    print GetIPCInformation.header
186    print GetIPCInformation(ipc, False, False)
187
188# EndMacro: showipc
189
190# Macro: showtaskipc
191
192@lldb_command('showtaskipc')
193def ShowTaskIPC(cmd_args=None):
194    """  Routine to print IPC summary of given task
195         Usage: showtaskipc <address of task>
196    """
197    if not cmd_args:
198        print "No arguments passed"
199        print ShowTaskIPC.__doc__
200        return False
201    tval = kern.GetValueFromAddress(cmd_args[0], 'task *')
202    if not tval:
203        print "unknown arguments:", str(cmd_args)
204        return False
205    print GetTaskSummary.header + " " + GetProcSummary.header
206    pval = Cast(tval.bsd_info, 'proc *')
207    print GetTaskSummary(tval) + " " + GetProcSummary(pval)
208    print GetTaskIPCSummary.header
209    print GetTaskIPCSummary(tval)
210
211# EndMacro: showtaskipc
212
213# Macro: showallipc
214
215@lldb_command('showallipc')
216def ShowAllIPC(cmd_args=None):
217    """  Routine to print IPC summary of all tasks
218         Usage: showallipc
219    """
220    for t in kern.tasks:
221        print GetTaskSummary.header + " " + GetProcSummary.header
222        pval = Cast(t.bsd_info, 'proc *')
223        print GetTaskSummary(t) + " " + GetProcSummary(pval)
224        print GetIPCInformation.header
225        print GetIPCInformation(t.itk_space, False, False) + "\n\n"
226
227# EndMacro: showallipc
228
229@lldb_command('showipcsummary')
230def ShowIPCSummary(cmd_args=None):
231    """ Summarizes the IPC state of all tasks.
232        This is a convenient way to dump some basic clues about IPC messaging. You can use the output to determine
233        tasks that are candidates for further investigation.
234    """
235    print GetTaskIPCSummary.header
236    for t in kern.tasks:
237        print GetTaskIPCSummary(t)
238    return
239
240def GetKObjectFromPort(portval):
241    """ Get Kobject description from the port.
242        params: portval - core.value representation of 'ipc_port *' object
243        returns: str - string of kobject information
244    """
245    kobject_str = "{0: <#020x}".format(portval.kdata.kobject)
246    io_bits = unsigned(portval.ip_object.io_bits)
247    objtype_index = io_bits & 0xfff
248    if objtype_index < len(xnudefines.kobject_types) :
249        desc_str = "kobject({0:s})".format(xnudefines.kobject_types[objtype_index])
250    else:
251        desc_str = "kobject(UNKNOWN) {:d}".format(objtype_index)
252    return kobject_str + " " + desc_str
253
254@static_var('destcache', {})
255def GetDestinationProcessFromPort(port):
256    """
257        params: port - core.value representation of 'ipc_port *' object
258        returns: str - name of process
259    """
260    out_str = ''
261    dest_space = port.data.receiver
262    found_dest = False
263    #update destcache if data is not found
264    if hex(dest_space) not in GetDestinationProcessFromPort.destcache:
265        for t in kern.tasks:
266            if hex(t.itk_space) == hex(dest_space):
267                pval = Cast(t.bsd_info, 'proc *')
268                GetDestinationProcessFromPort.destcache[hex(dest_space)] = (t, pval)
269                found_dest = True
270                break
271        #end of for loop
272    else: found_dest = True
273
274    if found_dest:
275        (ftask , fproc) = GetDestinationProcessFromPort.destcache[hex(dest_space)]
276        if fproc:
277            out_str = "{0:s}({1:d})".format(fproc.p_comm, fproc.p_pid )
278        else:
279            out_str = "task {0: <#020x}".format(ftask)
280    return out_str
281
282
283
284@header("{0: <20s} {1: <20s}".format("destname", "destination") )
285def GetPortDestinationSummary(port):
286    """ Get destination information for a port.
287        params: port - core.value representation of 'ipc_port *' object
288        returns: str - string of info about ports destination
289    """
290    out_str = ''
291    format_string = "{0: <20s} {1: <20s}"
292    destname_str = ''
293    destination_str = ''
294    ipc_space_kernel = unsigned(kern.globals.ipc_space_kernel)
295    target_spaceval = port.data.receiver
296    if unsigned(target_spaceval) == ipc_space_kernel :
297        destname_str = GetKObjectFromPort(port)
298    else:
299        if int(port.ip_object.io_bits) & 0x80000000 :
300            destname_str = "{0: <#020x}".format(port.ip_messages.data.port.receiver_name)
301            destination_str = GetDestinationProcessFromPort(port)
302        else:
303            destname_str = "{0: <#020x}".format(port)
304            destination_str = "inactive-port"
305
306    out_str += format_string.format(destname_str, destination_str)
307    return out_str
308
309@lldb_type_summary(['ipc_entry_t'])
310@header("{0: <20s} {1: <20s} {2: <8s} {3: <8s} {4: <20s} {5: <20s}".format("object", "name","rite", "urefs", "destname", "destination"))
311def GetIPCEntrySummary(entry, ipc_name=''):
312    """ Get summary of a ipc entry.
313        params:
314            entry - core.value representing ipc_entry_t in the kernel
315            ipc_name - str of format '0x0123' for display in summary.
316        returns:
317            str - string of ipc entry related information
318    """
319    out_str = ''
320    entry_ptr = int(hex(entry), 16)
321    format_string = "{0: <#020x} {1: <12s} {2: <8s} {3: <8d} {4: <20s} {5: <20s}"
322    right_str = ''
323    destname_str = ''
324    destination_str = ''
325
326    ie_object = entry.ie_object
327    ie_bits = int(entry.ie_bits)
328    urefs = int(ie_bits & 0xffff)
329    if ie_bits & 0x00100000 :
330        right_str = 'Dead'
331    elif ie_bits & 0x00080000:
332        right_str = 'Set'
333    else:
334        if ie_bits & 0x00010000 :
335            if ie_bits & 0x00020000 :
336                right_str = 'SR'
337            else:
338                right_str = 'S'
339        elif ie_bits & 0x00020000:
340            right_str = 'R'
341        elif ie_bits & 0x00040000 :
342            right_str = 'O'
343        if int(entry.index.request) != 0:
344            portval = Cast(ie_object, 'ipc_port_t')
345            requestsval = portval.ip_requests
346            sorightval = requestsval[int(entry.index.request)].notify.port
347            soright_ptr = unsigned(sorightval)
348            if soright_ptr != 0:
349                 if soright_ptr & 0x1 : right_str +='s'
350                 elif soright_ptr & 0x2 : right_str +='d'
351                 else : right_str +='n'
352        if ie_bits & 0x00800000 : right_str +='c'
353        # now show the port destination part
354        destname_str = GetPortDestinationSummary(Cast(ie_object, 'ipc_port_t'))
355
356    out_str = format_string.format(ie_object, ipc_name, right_str, urefs, destname_str, destination_str)
357    return out_str
358
359@header("{0: >20s}".format("user bt") )
360def GetPortUserStack(port, task):
361    """ Get UserStack information for the given port & task.
362        params: port - core.value representation of 'ipc_port *' object
363                task - value representing 'task *' object
364        returns: str - string information on port's userstack
365    """
366    out_str = ''
367    ie_port_callstack = port.ip_callstack
368    ie_port_spares = port.ip_spares[0]
369    proc_val = Cast(task.bsd_info, 'proc *')
370    if ie_port_callstack[0]:
371        out_str += "{: <10x}".format(ie_port_callstack[0])
372        count = 1
373        while count < 16 and ie_port_callstack[count]:
374            out_str += ": <10x".format(ie_port_callstack[count])
375            count = count + 1
376        if ie_port_spares != proc_val.p_pid:
377            out_str += " ({:<10d})".format(ie_port_spares)
378        out_str += '\n'
379    return out_str
380
381@lldb_type_summary(['ipc_space *'])
382@header("{0: <20s} {1: <20s} {2: <20s} {3: <8s} {4: <10s} {5: <16s} {6: <10s} {7: <7s}".format('ipc_space', 'is_task', 'is_table', 'flags', 'ports', 'table_next', 'low_mod', 'high_mod'))
383def GetIPCInformation(space, show_entries=False, show_userstack=False):
384    """ Provide a summary of the ipc space
385    """
386    out_str = ''
387    format_string = "{0: <#020x} {1: <#020x} {2: <#020x} {3: <8s} {4: <10d} {5: <#01x} {6: >10d} {7: >10d}"
388    is_tableval = space.is_table
389    ports = int(space.is_table_size)
390    flags =''
391    is_bits = int(space.is_bits)
392    if (is_bits & 0x40000000) == 0: flags +='A'
393    else: flags += ' '
394    if (is_bits & 0x20000000) != 0: flags +='G'
395    out_str += format_string.format(space, space.is_task, space.is_table, flags, space.is_table_size, space.is_table_next, space.is_low_mod, space.is_high_mod)
396
397    #should show the each individual entries if asked.
398    if show_entries == True:
399        out_str += "\n\t" + GetIPCEntrySummary.header + "\n"
400        num_entries = ports
401        index = 0
402        while index < num_entries:
403            entryval = GetObjectAtIndexFromArray(is_tableval, index)
404            entry_ie_bits = unsigned(entryval.ie_bits)
405            if (int(entry_ie_bits) & 0x001f0000 ) != 0:
406                entry_name = "{0: <#020x}".format( (index <<8 | entry_ie_bits >> 24) )
407                out_str += "\t" + GetIPCEntrySummary(entryval, entry_name) + "\n"
408                if show_userstack == True:
409                    entryport = Cast(entryval.ie_object, 'ipc_port *')
410                    if entryval.ie_object and (int(entry_ie_bits) & 0x00070000) and entryport.ip_callstack[0]:
411                        out_str += GetPortUserStack.header
412                        out_str += GetPortUserStack(entryport, space.is_task)
413            index +=1
414    #done with showing entries
415    return out_str
416
417# Macro: showrights
418
419@lldb_command('showrights')
420def ShowRights(cmd_args=None):
421    """  Routine to print rights information for the given IPC space
422         Usage: showrights <address of ipc space>
423    """
424    if not cmd_args:
425        print "No arguments passed"
426        print ShowRights.__doc__
427        return False
428    ipc = kern.GetValueFromAddress(cmd_args[0], 'ipc_space *')
429    if not ipc:
430        print "unknown arguments:", str(cmd_args)
431        return False
432    print GetIPCInformation.header
433    print GetIPCInformation(ipc, True, False)
434
435# EndMacro: showrights
436
437@lldb_command('showtaskrights')
438def ShowTaskRights(cmd_args=None):
439    """ Routine to ipc rights information for a task
440        Usage: showtaskrights <task address>
441    """
442    if cmd_args == None:
443        print "No arguments passed"
444        print ShowTaskStacksCmdHelper.__doc__
445        return False
446    tval = kern.GetValueFromAddress(cmd_args[0], 'task *')
447    if not tval:
448        print "unknown arguments:", str(cmd_args)
449        return False
450    print GetTaskSummary.header + " " + GetProcSummary.header
451    pval = Cast(tval.bsd_info, 'proc *')
452    print GetTaskSummary(tval) + " " + GetProcSummary(pval)
453    print GetIPCInformation.header
454    print GetIPCInformation(tval.itk_space, True, False)
455
456# Macro: showataskrightsbt
457
458@lldb_command('showtaskrightsbt')
459def ShowTaskRightsBt(cmd_args=None):
460    """ Routine to ipc rights information with userstacks for a task
461        Usage: showtaskrightsbt <task address>
462    """
463    if cmd_args == None:
464        print "No arguments passed"
465        print ShowTaskRightsBt.__doc__
466        return False
467    tval = kern.GetValueFromAddress(cmd_args[0], 'task *')
468    if not tval:
469        print "unknown arguments:", str(cmd_args)
470        return False
471    print GetTaskSummary.header + " " + GetProcSummary.header
472    pval = Cast(tval.bsd_info, 'proc *')
473    print GetTaskSummary(tval) + " " + GetProcSummary(pval)
474    print GetIPCInformation.header
475    print GetIPCInformation(tval.itk_space, True, True)
476
477# EndMacro: showtaskrightsbt
478
479# Macro: showallrights
480
481@lldb_command('showallrights')
482def ShowAllRights(cmd_args=None):
483    """  Routine to print rights information for IPC space of all tasks
484         Usage: showallrights
485    """
486    for t in kern.tasks:
487        print GetTaskSummary.header + " " + GetProcSummary.header
488        pval = Cast(t.bsd_info, 'proc *')
489        print GetTaskSummary(t) + " " + GetProcSummary(pval)
490        print GetIPCInformation.header
491        print GetIPCInformation(t.itk_space, True, False) + "\n\n"
492
493# EndMacro: showallrights
494
495# Macro: showpipestats
496@lldb_command('showpipestats')
497def ShowPipeStats(cmd_args=None):
498    """ Display pipes usage information in the kernel
499    """
500    print "Number of pipes: {: d}".format(kern.globals.amountpipes)
501    print "Memory used by pipes: {:s}".format(sizeof_fmt(int(kern.globals.amountpipekva)))
502    print "Max memory allowed for pipes: {:s}".format(sizeof_fmt(int(kern.globals.maxpipekva)))
503# EndMacro: showpipestats
504
505# Macro: showtaskbusyports
506@lldb_command('showtaskbusyports')
507def ShowTaskBusyPorts(cmd_args=None):
508    """ Routine to print information about receive rights belonging to this task that
509        have enqueued messages. This is oten a sign of a blocked or hung process
510        Usage: showtaskbusyports <task address>
511    """
512    if not cmd_args:
513        print "No arguments passed. Please pass in the address of a task"
514        print ShowTaskBusyPorts.__doc__
515        return
516    task = kern.GetValueFromAddress(cmd_args[0], 'task_t')
517    print GetTaskBusyPorts(task)
518    return
519
520def GetTaskBusyPorts(task):
521    """ Prints all busy ports for a given task. ie. all receive rights belonging
522        to this task that have enqueued messages.
523        params:
524            task : core.value representing a task in kernel
525        returns:
526            str  : String containing information about the given task's busy ports
527    """
528    isp = task.itk_space
529    i = 0
530    out_string = ""
531    while i < isp.is_table_size:
532        iep = addressof(isp.is_table[i])
533        if iep.ie_bits & 0x00020000:
534            port = Cast(iep.ie_object, 'ipc_port_t')
535            if port.ip_messages.data.port.msgcount > 0:
536                out_string += GetPortSummary.header + GetPortSummary(port)
537        i = i + 1
538    return out_string
539# EndMacro: showtaskbusyports
540
541# Macro: showallbusyports
542@lldb_command('showallbusyports')
543def ShowAllBusyPorts(cmd_args=None):
544    """ Routine to print information about all receive rights on the system that
545        have enqueued messages.
546    """
547    task_queue_head = kern.globals.tasks
548
549    for tsk in kern.tasks:
550        print GetTaskBusyPorts(tsk)
551    return
552# EndMacro: showallbusyports
553
554# Macro: showmqueue:
555@lldb_command('showmqueue')
556def ShowMQueue(cmd_args=None):
557    """ Routine that lists details about a given mqueue
558        Syntax: (lldb) showmqueue 0xaddr
559    """
560    if not cmd_args:
561        print "Please specify the address of the ipc_mqueue whose details you want to print"
562        print ShowMQueue.__doc__
563        return
564    mqueue = kern.GetValueFromAddress(cmd_args[0], 'struct ipc_mqueue *')
565    wq_type = mqueue.data.pset.set_queue.wqs_wait_queue.wq_type
566    if int(wq_type) == 3:
567        psetoff = getfieldoffset('struct ipc_pset *', 'ips_messages')
568        pset = unsigned(ArgumentStringToInt(cmd_args[0])) - unsigned(psetoff)
569        print GetPortSetSummary.header + GetPortSetSummary(kern.GetValueFromAddress(pset, 'struct ipc_pset *'))
570    if int(wq_type) == 2:
571        portoff = getfieldoffset('struct ipc_port', 'ip_messages')
572        port = unsigned(ArgumentStringToInt(cmd_args[0])) - unsigned(portoff)
573        print GetPortSummary.header + GetPortSummary(kern.GetValueFromAddress(port, 'struct ipc_port *'))
574# EndMacro: showmqueue
575
576# Macro: showpset
577@lldb_command('showpset')
578def ShowPSet(cmd_args=None):
579    """ Routine that prints details for a given ipc_pset *
580        Syntax: (lldb) showpset 0xaddr
581    """
582    if not cmd_args:
583        print "Please specify the address of the pset whose details you want to print"
584        print ShowPSet.__doc__
585        return
586
587    print GetPortSetSummary.header + GetPortSetSummary(kern.GetValueFromAddress(cmd_args[0], 'ipc_pset *'))
588# EndMacro: showpset
589
590