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