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