]> git.saurik.com Git - apple/xnu.git/blame - tools/lldbmacros/ipc.py
xnu-6153.141.1.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
cb323159
A
481@lldb_command('showipcsummary', fancy=True)
482def ShowIPCSummary(cmd_args=None, cmd_options={}, O=None):
39236c6e
A
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 """
cb323159
A
487 with O.table(GetTaskIPCSummary.header):
488 ipc_table_size = 0
489 for t in kern.tasks:
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
498def GetKObjectFromPort(portval):
499 """ Get Kobject description from the port.
500 params: portval - core.value representation of 'ipc_port *' object
501 returns: str - string of kobject information
502 """
39236c6e 503 io_bits = unsigned(portval.ip_object.io_bits)
ea3f0419
A
504 if io_bits & 0x400 :
505 kobject_val = portval.kdata.kolabel.ikol_kobject
506 else:
507 kobject_val = portval.kdata.kobject
508 kobject_str = "{0: <#020x}".format(kobject_val)
509 objtype_index = io_bits & 0x3ff
39236c6e 510 if objtype_index < len(xnudefines.kobject_types) :
39037602
A
511 objtype_str = xnudefines.kobject_types[objtype_index]
512 if objtype_str == 'IOKIT_OBJ':
ea3f0419 513 iokit_classnm = GetObjectTypeStr(kobject_val)
39037602
A
514 if not iokit_classnm:
515 iokit_classnm = "<unknown class>"
516 else:
517 iokit_classnm = re.sub(r'vtable for ', r'', iokit_classnm)
518 desc_str = "kobject({:s}:{:s})".format(objtype_str, iokit_classnm)
519 else:
520 desc_str = "kobject({0:s})".format(objtype_str)
521 if xnudefines.kobject_types[objtype_index] in ('TASK_RESUME', 'TASK'):
ea3f0419 522 desc_str += " " + GetProcNameForTask(Cast(kobject_val, 'task *'))
39236c6e
A
523 else:
524 desc_str = "kobject(UNKNOWN) {:d}".format(objtype_index)
525 return kobject_str + " " + desc_str
526
527@static_var('destcache', {})
528def GetDestinationProcessFromPort(port):
529 """
530 params: port - core.value representation of 'ipc_port *' object
531 returns: str - name of process
532 """
533 out_str = ''
534 dest_space = port.data.receiver
535 found_dest = False
536 #update destcache if data is not found
537 if hex(dest_space) not in GetDestinationProcessFromPort.destcache:
538 for t in kern.tasks:
539 if hex(t.itk_space) == hex(dest_space):
540 pval = Cast(t.bsd_info, 'proc *')
541 GetDestinationProcessFromPort.destcache[hex(dest_space)] = (t, pval)
542 found_dest = True
543 break
544 #end of for loop
545 else: found_dest = True
546
547 if found_dest:
548 (ftask , fproc) = GetDestinationProcessFromPort.destcache[hex(dest_space)]
549 if fproc:
550 out_str = "{0:s}({1:d})".format(fproc.p_comm, fproc.p_pid )
551 else:
552 out_str = "task {0: <#020x}".format(ftask)
553 return out_str
554
555
556
557@header("{0: <20s} {1: <20s}".format("destname", "destination") )
558def GetPortDestinationSummary(port):
559 """ Get destination information for a port.
560 params: port - core.value representation of 'ipc_port *' object
561 returns: str - string of info about ports destination
562 """
563 out_str = ''
564 format_string = "{0: <20s} {1: <20s}"
565 destname_str = ''
566 destination_str = ''
39236c6e 567 target_spaceval = port.data.receiver
cb323159 568 if int(port.ip_object.io_bits) & 0x800 :
39236c6e
A
569 destname_str = GetKObjectFromPort(port)
570 else:
571 if int(port.ip_object.io_bits) & 0x80000000 :
572 destname_str = "{0: <#020x}".format(port.ip_messages.data.port.receiver_name)
573 destination_str = GetDestinationProcessFromPort(port)
574 else:
575 destname_str = "{0: <#020x}".format(port)
576 destination_str = "inactive-port"
577
578 out_str += format_string.format(destname_str, destination_str)
579 return out_str
580
581@lldb_type_summary(['ipc_entry_t'])
d9a64523 582@header("{: <20s} {: <12s} {: <8s} {: <8s} {: <8s} {: <8s} {: <20s} {: <20s}".format("object", "name", "rite", "urefs", "nsets", "nmsgs", "destname", "destination"))
3e170ce0 583def GetIPCEntrySummary(entry, ipc_name='', rights_filter=0):
39236c6e
A
584 """ Get summary of a ipc entry.
585 params:
586 entry - core.value representing ipc_entry_t in the kernel
587 ipc_name - str of format '0x0123' for display in summary.
588 returns:
589 str - string of ipc entry related information
3e170ce0
A
590
591 types of rights:
592 'Dead' : Dead name
593 'Set' : Port set
594 'S' : Send right
595 'R' : Receive right
596 'O' : Send-once right
cb323159
A
597 'm' : Immovable send port
598 'i' : Immovable receive port
599 'g' : No grant port
3e170ce0 600 types of notifications:
d9a64523 601 'd' : Dead-Name notification requested
3e170ce0 602 's' : Send-Possible notification armed
d9a64523
A
603 'r' : Send-Possible notification requested
604 'n' : No-Senders notification requested
605 'x' : Port-destroy notification requested
39236c6e 606 """
d9a64523 607 out_str = ''
39236c6e 608 entry_ptr = int(hex(entry), 16)
3e170ce0 609 format_string = "{: <#020x} {: <12s} {: <8s} {: <8d} {: <8d} {: <8d} {: <20s} {: <20s}"
39236c6e
A
610 right_str = ''
611 destname_str = ''
612 destination_str = ''
d9a64523 613
39236c6e
A
614 ie_object = entry.ie_object
615 ie_bits = int(entry.ie_bits)
616 urefs = int(ie_bits & 0xffff)
3e170ce0
A
617 nsets = 0
618 nmsgs = 0
39236c6e
A
619 if ie_bits & 0x00100000 :
620 right_str = 'Dead'
621 elif ie_bits & 0x00080000:
622 right_str = 'Set'
3e170ce0
A
623 psetval = Cast(ie_object, 'ipc_pset *')
624 set_str = GetWaitqSets(addressof(psetval.ips_messages.data.pset.setq.wqset_q))
625 nsets = len(set_str)
626 nmsgs = 0
39236c6e
A
627 else:
628 if ie_bits & 0x00010000 :
629 if ie_bits & 0x00020000 :
3e170ce0 630 # SEND + RECV
39236c6e
A
631 right_str = 'SR'
632 else:
3e170ce0 633 # SEND only
39236c6e
A
634 right_str = 'S'
635 elif ie_bits & 0x00020000:
3e170ce0 636 # RECV only
39236c6e
A
637 right_str = 'R'
638 elif ie_bits & 0x00040000 :
3e170ce0 639 # SEND_ONCE
39236c6e 640 right_str = 'O'
fe8ab488 641 portval = Cast(ie_object, 'ipc_port_t')
39236c6e 642 if int(entry.index.request) != 0:
39236c6e
A
643 requestsval = portval.ip_requests
644 sorightval = requestsval[int(entry.index.request)].notify.port
645 soright_ptr = unsigned(sorightval)
646 if soright_ptr != 0:
d9a64523
A
647 # dead-name notification requested
648 right_str += 'd'
649 # send-possible armed
650 if soright_ptr & 0x1 : right_str +='s'
651 # send-possible requested
652 if soright_ptr & 0x2 : right_str +='r'
3e170ce0 653 # No-senders notification requested
d9a64523
A
654 if portval.ip_nsrequest != 0: right_str += 'n'
655 # port-destroy notification requested
656 if portval.ip_pdrequest != 0: right_str += 'x'
cb323159
A
657 # Immovable receive rights
658 if portval.ip_immovable_receive != 0: right_str += 'i'
659 # Immovable send rights
660 if portval.ip_immovable_send != 0: right_str += 'm'
661 # No-grant Port
662 if portval.ip_no_grant != 0: right_str += 'g'
d9a64523
A
663
664 # early-out if the rights-filter doesn't match
665 if rights_filter != 0 and rights_filter != right_str:
666 return ''
667
668 # append the generation to the name value
669 # (from osfmk/ipc/ipc_entry.h)
670 # bits rollover period
671 # 0 0 64
672 # 0 1 48
673 # 1 0 32
674 # 1 1 16
675 ie_gen_roll = { 0:'.64', 1:'.48', 2:'.32', 3:'.16' }
cb323159 676 ipc_name = '{:s}{:s}'.format(ipc_name.strip(), ie_gen_roll[(ie_bits & 0x00c00000) >> 22])
d9a64523 677
39236c6e
A
678 # now show the port destination part
679 destname_str = GetPortDestinationSummary(Cast(ie_object, 'ipc_port_t'))
3e170ce0
A
680 # Get the number of sets to which this port belongs
681 set_str = GetWaitqSets(addressof(portval.ip_messages.data.port.waitq))
682 nsets = len(set_str)
683 nmsgs = portval.ip_messages.data.port.msgcount
684 if rights_filter == 0 or rights_filter == right_str:
685 out_str = format_string.format(ie_object, ipc_name, right_str, urefs, nsets, nmsgs, destname_str, destination_str)
39236c6e
A
686 return out_str
687
688@header("{0: >20s}".format("user bt") )
689def GetPortUserStack(port, task):
690 """ Get UserStack information for the given port & task.
691 params: port - core.value representation of 'ipc_port *' object
692 task - value representing 'task *' object
693 returns: str - string information on port's userstack
694 """
695 out_str = ''
696 ie_port_callstack = port.ip_callstack
697 ie_port_spares = port.ip_spares[0]
698 proc_val = Cast(task.bsd_info, 'proc *')
699 if ie_port_callstack[0]:
700 out_str += "{: <10x}".format(ie_port_callstack[0])
701 count = 1
702 while count < 16 and ie_port_callstack[count]:
703 out_str += ": <10x".format(ie_port_callstack[count])
704 count = count + 1
705 if ie_port_spares != proc_val.p_pid:
706 out_str += " ({:<10d})".format(ie_port_spares)
707 out_str += '\n'
708 return out_str
709
710@lldb_type_summary(['ipc_space *'])
3e170ce0
A
711@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'))
712def PrintIPCInformation(space, show_entries=False, show_userstack=False, rights_filter=0):
39236c6e
A
713 """ Provide a summary of the ipc space
714 """
715 out_str = ''
3e170ce0 716 format_string = "{0: <#020x} {1: <#020x} {2: <#020x} {3: <8s} {4: <10d} {5: <#18x} {6: >8d} {7: <8d}"
39236c6e
A
717 is_tableval = space.is_table
718 ports = int(space.is_table_size)
719 flags =''
720 is_bits = int(space.is_bits)
721 if (is_bits & 0x40000000) == 0: flags +='A'
722 else: flags += ' '
723 if (is_bits & 0x20000000) != 0: flags +='G'
3e170ce0 724 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
725
726 #should show the each individual entries if asked.
727 if show_entries == True:
3e170ce0 728 print "\t" + GetIPCEntrySummary.header
39236c6e
A
729 num_entries = ports
730 index = 0
731 while index < num_entries:
732 entryval = GetObjectAtIndexFromArray(is_tableval, index)
733 entry_ie_bits = unsigned(entryval.ie_bits)
734 if (int(entry_ie_bits) & 0x001f0000 ) != 0:
735 entry_name = "{0: <#020x}".format( (index <<8 | entry_ie_bits >> 24) )
3e170ce0
A
736 entry_str = GetIPCEntrySummary(entryval, entry_name, rights_filter)
737 if len(entry_str) > 0:
738 print " \r\t" + entry_str
739 if show_userstack == True:
740 entryport = Cast(entryval.ie_object, 'ipc_port *')
741 if entryval.ie_object and (int(entry_ie_bits) & 0x00070000) and entryport.ip_callstack[0]:
742 print GetPortUserStack.header + GetPortUserStack(entryport, space.is_task)
743 else:
744 # give some progress indication (this is especially
745 # helpful for tasks with large sets of rights)
746 sys.stderr.write(' {:d}/{:d}...\r'.format(index, num_entries))
747 index += 1
39236c6e
A
748 #done with showing entries
749 return out_str
750
751# Macro: showrights
752
3e170ce0
A
753@lldb_command('showrights', 'R:')
754def ShowRights(cmd_args=None, cmd_options={}):
39236c6e 755 """ Routine to print rights information for the given IPC space
3e170ce0
A
756 Usage: showrights [-R rights_type] <address of ipc space>
757 -R rights_type : only display rights matching the string 'rights_type'
758
759 types of rights:
760 'Dead' : Dead name
761 'Set' : Port set
762 'S' : Send right
763 'R' : Receive right
764 'O' : Send-once right
d9a64523
A
765 types of notifications:
766 'd' : Dead-Name notification requested
3e170ce0 767 's' : Send-Possible notification armed
d9a64523
A
768 'r' : Send-Possible notification requested
769 'n' : No-Senders notification requested
770 'x' : Port-destroy notification requested
39236c6e
A
771 """
772 if not cmd_args:
773 print "No arguments passed"
774 print ShowRights.__doc__
775 return False
776 ipc = kern.GetValueFromAddress(cmd_args[0], 'ipc_space *')
777 if not ipc:
778 print "unknown arguments:", str(cmd_args)
779 return False
3e170ce0
A
780 rights_type = 0
781 if "-R" in cmd_options:
782 rights_type = cmd_options["-R"]
783 print PrintIPCInformation.header
784 PrintIPCInformation(ipc, True, False, rights_type)
39236c6e
A
785
786# EndMacro: showrights
787
3e170ce0
A
788@lldb_command('showtaskrights','R:')
789def ShowTaskRights(cmd_args=None, cmd_options={}):
39236c6e 790 """ Routine to ipc rights information for a task
3e170ce0
A
791 Usage: showtaskrights [-R rights_type] <task address>
792 -R rights_type : only display rights matching the string 'rights_type'
793
794 types of rights:
795 'Dead' : Dead name
796 'Set' : Port set
797 'S' : Send right
798 'R' : Receive right
799 'O' : Send-once right
cb323159
A
800 'm' : Immovable send port
801 'i' : Immovable receive port
802 'g' : No grant port
d9a64523
A
803 types of notifications:
804 'd' : Dead-Name notification requested
3e170ce0 805 's' : Send-Possible notification armed
d9a64523
A
806 'r' : Send-Possible notification requested
807 'n' : No-Senders notification requested
808 'x' : Port-destroy notification requested
39236c6e
A
809 """
810 if cmd_args == None:
811 print "No arguments passed"
812 print ShowTaskStacksCmdHelper.__doc__
813 return False
814 tval = kern.GetValueFromAddress(cmd_args[0], 'task *')
815 if not tval:
816 print "unknown arguments:", str(cmd_args)
817 return False
3e170ce0
A
818 rights_type = 0
819 if "-R" in cmd_options:
820 rights_type = cmd_options["-R"]
39236c6e
A
821 print GetTaskSummary.header + " " + GetProcSummary.header
822 pval = Cast(tval.bsd_info, 'proc *')
823 print GetTaskSummary(tval) + " " + GetProcSummary(pval)
3e170ce0
A
824 print PrintIPCInformation.header
825 PrintIPCInformation(tval.itk_space, True, False, rights_type)
39236c6e
A
826
827# Macro: showataskrightsbt
828
3e170ce0
A
829@lldb_command('showtaskrightsbt', 'R:')
830def ShowTaskRightsBt(cmd_args=None, cmd_options={}):
39236c6e 831 """ Routine to ipc rights information with userstacks for a task
3e170ce0
A
832 Usage: showtaskrightsbt [-R rights_type] <task address>
833 -R rights_type : only display rights matching the string 'rights_type'
834
835 types of rights:
836 'Dead' : Dead name
837 'Set' : Port set
838 'S' : Send right
839 'R' : Receive right
840 'O' : Send-once right
cb323159
A
841 'm' : Immovable send port
842 'i' : Immovable receive port
843 'g' : No grant port
d9a64523
A
844 types of notifications:
845 'd' : Dead-Name notification requested
3e170ce0 846 's' : Send-Possible notification armed
d9a64523
A
847 'r' : Send-Possible notification requested
848 'n' : No-Senders notification requested
849 'x' : Port-destroy notification requested
39236c6e
A
850 """
851 if cmd_args == None:
852 print "No arguments passed"
853 print ShowTaskRightsBt.__doc__
854 return False
855 tval = kern.GetValueFromAddress(cmd_args[0], 'task *')
856 if not tval:
857 print "unknown arguments:", str(cmd_args)
858 return False
3e170ce0
A
859 rights_type = 0
860 if "-R" in cmd_options:
861 rights_type = cmd_options["-R"]
39236c6e
A
862 print GetTaskSummary.header + " " + GetProcSummary.header
863 pval = Cast(tval.bsd_info, 'proc *')
864 print GetTaskSummary(tval) + " " + GetProcSummary(pval)
3e170ce0
A
865 print PrintIPCInformation.header
866 PrintIPCInformation(tval.itk_space, True, True, rights_type)
39236c6e
A
867
868# EndMacro: showtaskrightsbt
869
870# Macro: showallrights
871
3e170ce0
A
872@lldb_command('showallrights', 'R:')
873def ShowAllRights(cmd_args=None, cmd_options={}):
39236c6e 874 """ Routine to print rights information for IPC space of all tasks
3e170ce0
A
875 Usage: showallrights [-R rights_type]
876 -R rights_type : only display rights matching the string 'rights_type'
877
878 types of rights:
879 'Dead' : Dead name
880 'Set' : Port set
881 'S' : Send right
882 'R' : Receive right
883 'O' : Send-once right
cb323159
A
884 'm' : Immovable send port
885 'i' : Immovable receive port
886 'g' : No grant port
d9a64523
A
887 types of notifications:
888 'd' : Dead-Name notification requested
3e170ce0 889 's' : Send-Possible notification armed
d9a64523
A
890 'r' : Send-Possible notification requested
891 'n' : No-Senders notification requested
892 'x' : Port-destroy notification requested
39236c6e 893 """
3e170ce0
A
894 rights_type = 0
895 if "-R" in cmd_options:
896 rights_type = cmd_options["-R"]
39236c6e
A
897 for t in kern.tasks:
898 print GetTaskSummary.header + " " + GetProcSummary.header
899 pval = Cast(t.bsd_info, 'proc *')
900 print GetTaskSummary(t) + " " + GetProcSummary(pval)
fe8ab488 901 try:
3e170ce0
A
902 print PrintIPCInformation.header
903 PrintIPCInformation(t.itk_space, True, False, rights_type) + "\n\n"
fe8ab488
A
904 except (KeyboardInterrupt, SystemExit):
905 raise
906 except:
907 print "Failed to get IPC information. Do individual showtaskrights <task> to find the error. \n\n"
39236c6e
A
908
909# EndMacro: showallrights
910
d9a64523
A
911
912def GetInTransitPortSummary(port, disp, holding_port, holding_kmsg):
913 """ String-ify the in-transit dispostion of a port.
914 """
915 ## This should match the summary generated by GetIPCEntrySummary
916 ## "object" "name" "rite" "urefs" "nsets" "nmsgs" "destname" "destination"
917 format_str = "\t{: <#20x} {: <12} {: <8s} {: <8d} {: <8d} {: <8d} p:{: <#19x} k:{: <#19x}"
918 portname = 'intransit'
919
920 disp_str = GetPortDispositionString(disp)
921
922 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))
923 return out_str
924
925
926def GetDispositionFromEntryType(entry_bits):
927 """ Translate an IPC entry type into an in-transit disposition. This allows
928 the GetInTransitPortSummary function to be re-used to string-ify IPC
929 entry types.
930 """
931 ebits = int(entry_bits)
932 if (ebits & 0x003f0000) == 0:
933 return 0
934
935 if (ebits & 0x00010000) != 0:
936 return 17 ## MACH_PORT_RIGHT_SEND
937 elif (ebits & 0x00020000) != 0:
938 return 16 ## MACH_PORT_RIGHT_RECEIVE
939 elif (ebits & 0x00040000) != 0:
940 return 18 ## MACH_PORT_RIGHT_SEND_ONCE
941 elif (ebits & 0x00080000) != 0:
942 return 100 ## MACH_PORT_RIGHT_PORT_SET
943 elif (ebits & 0x00100000) != 0:
944 return 101 ## MACH_PORT_RIGHT_DEAD_NAME
945 elif (ebits & 0x00200000) != 0:
946 return 102 ## MACH_PORT_RIGHT_LABELH
947 else:
948 return 0
949
950def GetDispositionFromVoucherPort(th_vport):
951 """ Translate a thread's voucher port into a 'disposition'
952 """
953 if unsigned(th_vport) > 0:
954 return 103 ## Voucher type
955 return 0
956
957
958g_kmsg_prog = 0
959g_progmeter = {
960 0 : '*',
961 1 : '-',
962 2 : '\\',
963 3 : '|',
964 4 : '/',
965 5 : '-',
966 6 : '\\',
967 7 : '|',
968 8 : '/',
969}
970
971def PrintProgressForKmsg():
972 global g_kmsg_prog
973 global g_progmeter
974 sys.stderr.write(" {:<1s}\r".format(g_progmeter[g_kmsg_prog % 9]))
975 g_kmsg_prog += 1
976
977
978def CollectPortsForAnalysis(port, disposition):
979 """
980 """
981 p = Cast(port, 'struct ipc_port *')
982 yield (p, disposition)
983
984 # no-senders notification port
985 if unsigned(p.ip_nsrequest) != 0:
986 PrintProgressForKmsg()
987 yield (Cast(p.ip_nsrequest, 'struct ipc_port *'), -1)
988
989 # port-death notification port
990 if unsigned(p.ip_pdrequest) != 0:
991 PrintProgressForKmsg()
992 yield (Cast(p.ip_pdrequest, 'struct ipc_port *'), -2)
993
994 ## ports can have many send-possible notifications armed: go through the table!
995 if unsigned(p.ip_requests) != 0:
996 table = Cast(p.ip_requests, 'struct ipc_port_request *')
997 table_sz = int(table.name.size.its_size)
998 for i in range(table_sz):
999 if i == 0:
1000 continue
1001 ipr = table[i]
1002 if unsigned(ipr.name.name) != 0:
1003 ipr_bits = unsigned(ipr.notify.port) & 3
1004 ipr_port = kern.GetValueFromAddress(int(ipr.notify.port) & ~3, 'struct ipc_port *')
1005 ipr_disp = 0
1006 if ipr_bits & 3: ## send-possible armed and requested
1007 ipr_disp = -5
1008 elif ipr_bits & 2: ## send-possible requested
1009 ipr_disp = -4
1010 elif ipr_bits & 1: ## send-possible armed
1011 ipr_disp = -3
1012 PrintProgressForKmsg()
1013 yield (ipr_port, ipr_disp)
1014 return
1015
1016def CollectKmsgPorts(task, task_port, kmsgp):
1017 """ Look through a message, 'kmsgp' destined for 'task'
1018 (enqueued on task_port). Collect any port descriptors,
1019 remote, local, voucher, or other port references
1020 into a (ipc_port_t, disposition) list.
1021 """
1022 kmsgh = dereference(kmsgp.ikm_header)
1023
1024 p_list = []
1025
1026 PrintProgressForKmsg()
1027 if kmsgh.msgh_remote_port and unsigned(kmsgh.msgh_remote_port) != unsigned(task_port):
1028 disp = kmsgh.msgh_bits & 0x1f
1029 p_list += list(CollectPortsForAnalysis(kmsgh.msgh_remote_port, disp))
1030
1031 if kmsgh.msgh_local_port and unsigned(kmsgh.msgh_local_port) != unsigned(task_port) \
1032 and unsigned(kmsgh.msgh_local_port) != unsigned(kmsgh.msgh_remote_port):
1033 disp = (kmsgh.msgh_bits & 0x1f00) >> 8
1034 p_list += list(CollectPortsForAnalysis(kmsgh.msgh_local_port, disp))
1035
1036 if kmsgp.ikm_voucher:
1037 p_list += list(CollectPortsForAnalysis(kmsgp.ikm_voucher, 0))
1038
1039 if kmsgh.msgh_bits & 0x80000000:
1040 ## Complex message - look for descriptors
1041 PrintProgressForKmsg()
1042 (body, dschead, dsc_list) = GetKmsgDescriptors(kmsgp)
1043 for dsc in dsc_list:
1044 PrintProgressForKmsg()
1045 dsc_type = unsigned(dsc.type.type)
1046 if dsc_type == 0 or dsc_type == 2: ## 0 == port, 2 == ool port
1047 if dsc_type == 0:
1048 ## its a port descriptor
1049 dsc_disp = dsc.port.disposition
1050 p_list += list(CollectPortsForAnalysis(dsc.port.name, dsc_disp))
1051 else:
1052 ## it's an ool_ports descriptor which is an array of ports
1053 dsc_disp = dsc.ool_ports.disposition
1054 dispdata = Cast(dsc.ool_ports.address, 'struct ipc_port *')
1055 for pidx in range(dsc.ool_ports.count):
1056 PrintProgressForKmsg()
1057 p_list += list(CollectPortsForAnalysis(dispdata[pidx], dsc_disp))
1058 return p_list
1059
1060def CollectKmsgPortRefs(task, task_port, kmsgp, p_refs):
1061 """ Recursively collect all references to ports inside the kmsg 'kmsgp'
1062 into the set 'p_refs'
1063 """
1064 p_list = CollectKmsgPorts(task, task_port, kmsgp)
1065
1066 ## Iterate over each ports we've collected, to see if they
1067 ## have messages on them, and then recurse!
1068 for p, pdisp in p_list:
1069 ptype = (p.ip_object.io_bits & 0x7fff0000) >> 16
1070 p_refs.add((p, pdisp, ptype))
1071 if ptype != 0: ## don't bother with port sets
1072 continue
1073 ## If the port that's in-transit has messages already enqueued,
1074 ## go through each of those messages and look for more ports!
1075 if p.ip_messages.data.port.msgcount > 0:
1076 p_kmsgp = Cast(p.ip_messages.data.port.messages.ikmq_base, 'ipc_kmsg_t')
1077 kmsgheadp = p_kmsgp
1078 while unsigned(p_kmsgp) > 0:
1079 CollectKmsgPortRefs(task, p, p_kmsgp, p_refs)
1080 p_kmsgp = p_kmsgp.ikm_next
1081 if p_kmsgp == kmsgheadp:
1082 break;
1083
1084
1085def FindKmsgPortRefs(instr, task, task_port, kmsgp, qport):
1086 """ Look through a message, 'kmsgp' destined for 'task'. If we find
1087 any port descriptors, remote, local, voucher, or other port that
1088 matches 'qport', return a short description
1089 which should match the format of GetIPCEntrySummary.
1090 """
1091
1092 out_str = instr
1093 p_list = CollectKmsgPorts(task, task_port, kmsgp)
1094
1095 ## Run through all ports we've collected looking for 'qport'
1096 for p, pdisp in p_list:
1097 PrintProgressForKmsg()
1098 if unsigned(p) == unsigned(qport):
1099 ## the port we're looking for was found in this message!
1100 if len(out_str) > 0:
1101 out_str += '\n'
1102 out_str += GetInTransitPortSummary(p, pdisp, task_port, kmsgp)
1103
1104 ptype = (p.ip_object.io_bits & 0x7fff0000) >> 16
1105 if ptype != 0: ## don't bother with port sets
1106 continue
1107
1108 ## If the port that's in-transit has messages already enqueued,
1109 ## go through each of those messages and look for more ports!
1110 if p.ip_messages.data.port.msgcount > 0:
1111 p_kmsgp = Cast(p.ip_messages.data.port.messages.ikmq_base, 'ipc_kmsg_t')
1112 kmsgheadp = p_kmsgp
1113 while unsigned(p_kmsgp) > 0:
1114 out_str = FindKmsgPortRefs(out_str, task, p, p_kmsgp, qport)
1115 p_kmsgp = p_kmsgp.ikm_next
1116 if p_kmsgp == kmsgheadp:
1117 break
1118 return out_str
1119
1120
1121port_iteration_do_print_taskname = False
1122registeredport_idx = -10
1123excports_idx = -20
1124intransit_idx = -1000
1125taskports_idx = -2000
1126thports_idx = -3000
1127
1128def IterateAllPorts(tasklist, func, ctx, include_psets, follow_busyports, should_log):
1129 """ Iterate over all ports in the system, calling 'func'
1130 for each entry in
1131 """
1132 global port_iteration_do_print_taskname
1133 global intransit_idx, taskports_idx, thports_idx, registeredport_idx, excports_idx
1134
1135 ## XXX: also host special ports
1136
1137 entry_port_type_mask = 0x00070000
1138 if include_psets:
1139 entry_port_type_mask = 0x000f0000
1140
1141 if tasklist is None:
1142 tasklist = kern.tasks
1143 tasklist += kern.terminated_tasks
1144
1145 tidx = 1
1146
1147 for t in tasklist:
1148 # Write a progress line. Using stderr avoids automatic newline when
1149 # writing to stdout from lldb. Blank spaces at the end clear out long
1150 # lines.
1151 if should_log:
1152 procname = ""
1153 if not t.active:
1154 procname = 'terminated: '
1155 if t.halting:
1156 procname += 'halting: '
1157 t_p = Cast(t.bsd_info, 'proc *')
1158 if unsigned(t_p) != 0:
1159 procname += str(t_p.p_name)
1160 elif unsigned(t.task_imp_base) != 0 and hasattr(t.task_imp_base, 'iit_procname'):
1161 procname += str(t.task_imp_base.iit_procname)
1162 sys.stderr.write(" checking {:s} ({}/{})...{:50s}\r".format(procname, tidx, len(tasklist), ''))
1163 tidx += 1
1164
1165 port_iteration_do_print_taskname = True
1166 space = t.itk_space
1167 num_entries = int(space.is_table_size)
1168 is_tableval = space.is_table
1169 idx = 0
1170 while idx < num_entries:
1171 entry_val = GetObjectAtIndexFromArray(is_tableval, idx)
1172 entry_bits= unsigned(entry_val.ie_bits)
1173 entry_obj = 0
1174 entry_str = ''
1175 entry_name = "{:x}".format( (idx << 8 | entry_bits >> 24) )
1176
1177 entry_disp = GetDispositionFromEntryType(entry_bits)
1178
1179 ## If the entry in the table represents a port of some sort,
1180 ## then make the callback provided
1181 if int(entry_bits) & entry_port_type_mask:
1182 eport = Cast(entry_val.ie_object, 'ipc_port_t')
1183 ## Make the callback
1184 func(t, space, ctx, idx, entry_val, eport, entry_disp)
1185
1186 ## if the port has pending messages, look through
1187 ## each message for ports (and recurse)
1188 if follow_busyports and unsigned(eport) > 0 and eport.ip_messages.data.port.msgcount > 0:
1189 ## collect all port references from all messages
1190 kmsgp = Cast(eport.ip_messages.data.port.messages.ikmq_base, 'ipc_kmsg_t')
1191 kmsgheadp = kmsgp
1192 while unsigned(kmsgp) > 0:
1193 p_refs = set()
1194 CollectKmsgPortRefs(t, eport, kmsgp, p_refs)
1195 for (port, pdisp, ptype) in p_refs:
1196 func(t, space, ctx, intransit_idx, None, port, pdisp)
1197 kmsgp = kmsgp.ikm_next
1198 if kmsgp == kmsgheadp:
1199 break
1200
1201 idx = idx + 1
1202 ## while (idx < num_entries)
1203
1204 ## Task ports (send rights)
1205 if unsigned(t.itk_sself) > 0:
1206 func(t, space, ctx, taskports_idx, 0, t.itk_sself, 17)
1207 if unsigned(t.itk_host) > 0:
1208 func(t, space, ctx, taskports_idx, 0, t.itk_host, 17)
1209 if unsigned(t.itk_bootstrap) > 0:
1210 func(t, space, ctx, taskports_idx, 0, t.itk_bootstrap, 17)
1211 if unsigned(t.itk_seatbelt) > 0:
1212 func(t, space, ctx, taskports_idx, 0, t.itk_seatbelt, 17)
1213 if unsigned(t.itk_gssd) > 0:
1214 func(t, space, ctx, taskports_idx, 0, t.itk_gssd, 17)
1215 if unsigned(t.itk_debug_control) > 0:
1216 func(t, space, ctx, taskports_idx, 0, t.itk_debug_control, 17)
1217 if unsigned(t.itk_task_access) > 0:
1218 func(t, space, ctx, taskports_idx, 0, t.itk_task_access, 17)
1219
1220 ## Task name port (not a send right, just a naked ref)
1221 if unsigned(t.itk_nself) > 0:
1222 func(t, space, ctx, taskports_idx, 0,t.itk_nself, 0)
1223
1224 ## task resume port is a receive right to resume the task
1225 if unsigned(t.itk_resume) > 0:
1226 func(t, space, ctx, taskports_idx, 0, t.itk_resume, 16)
1227
1228 ## registered task ports (all send rights)
1229 tr_idx = 0
1230 tr_max = sizeof(t.itk_registered) / sizeof(t.itk_registered[0])
1231 while tr_idx < tr_max:
1232 tport = t.itk_registered[tr_idx]
1233 if unsigned(tport) > 0:
1234 try:
1235 func(t, space, ctx, registeredport_idx, 0, tport, 17)
1236 except Exception, e:
1237 print("\texception looking through registered port {:d}/{:d} in {:s}".format(tr_idx,tr_max,t))
1238 pass
1239 tr_idx += 1
1240
1241 ## Task exception ports
1242 exidx = 0
1243 exmax = sizeof(t.exc_actions) / sizeof(t.exc_actions[0])
1244 while exidx < exmax: ## see: osfmk/mach/[arm|i386]/exception.h
1245 export = t.exc_actions[exidx].port ## send right
1246 if unsigned(export) > 0:
1247 try:
1248 func(t, space, ctx, excports_idx, 0, export, 17)
1249 except Exception, e:
1250 print("\texception looking through exception port {:d}/{:d} in {:s}".format(exidx,exmax,t))
1251 pass
1252 exidx += 1
1253
1254 ## XXX: any ports still valid after clearing IPC space?!
1255
1256 for thval in IterateQueue(t.threads, 'thread *', 'task_threads'):
1257 ## XXX: look at block reason to see if it's in mach_msg_receive - then look at saved state / message
1258
1259 ## Thread port (send right)
1260 if unsigned(thval.ith_sself) > 0:
1261 thport = thval.ith_sself
1262 func(t, space, ctx, thports_idx, 0, thport, 17) ## see: osfmk/mach/message.h
1263 ## Thread special reply port (send-once right)
1264 if unsigned(thval.ith_special_reply_port) > 0:
1265 thport = thval.ith_special_reply_port
1266 func(t, space, ctx, thports_idx, 0, thport, 18) ## see: osfmk/mach/message.h
1267 ## Thread voucher port
1268 if unsigned(thval.ith_voucher) > 0:
1269 vport = thval.ith_voucher.iv_port
1270 if unsigned(vport) > 0:
1271 vdisp = GetDispositionFromVoucherPort(vport)
1272 func(t, space, ctx, thports_idx, 0, vport, vdisp)
1273 ## Thread exception ports
1274 if unsigned(thval.exc_actions) > 0:
1275 exidx = 0
1276 while exidx < exmax: ## see: osfmk/mach/[arm|i386]/exception.h
1277 export = thval.exc_actions[exidx].port ## send right
1278 if unsigned(export) > 0:
1279 try:
1280 func(t, space, ctx, excports_idx, 0, export, 17)
1281 except Exception, e:
1282 print("\texception looking through exception port {:d}/{:d} in {:s}".format(exidx,exmax,t))
1283 pass
1284 exidx += 1
1285 ## XXX: the message on a thread (that's currently being received)
1286 ## for (thval in t.threads)
1287 ## for (t in tasklist)
1288
1289
1290# Macro: findportrights
1291def FindPortRightsCallback(task, space, ctx, entry_idx, ipc_entry, ipc_port, port_disp):
1292 """ Callback which uses 'ctx' as the (port,rights_types) tuple for which
1293 a caller is seeking references. This should *not* be used from a
1294 recursive call to IterateAllPorts.
1295 """
1296 global port_iteration_do_print_taskname
1297
1298 (qport, rights_type) = ctx
1299 entry_name = ''
1300 entry_str = ''
1301 if unsigned(ipc_entry) != 0:
1302 entry_bits = unsigned(ipc_entry.ie_bits)
1303 entry_name = "{:x}".format( (entry_idx << 8 | entry_bits >> 24) )
1304 if (int(entry_bits) & 0x001f0000) != 0 and unsigned(ipc_entry.ie_object) == unsigned(qport):
1305 ## it's a valid entry, and it points to the port
1306 entry_str = '\t' + GetIPCEntrySummary(ipc_entry, entry_name, rights_type)
1307
1308 procname = GetProcNameForTask(task)
1309 if unsigned(ipc_port) != 0 and ipc_port.ip_messages.data.port.msgcount > 0:
1310 sys.stderr.write(" checking {:s} busy-port {}:{:#x}...{:30s}\r".format(procname, entry_name, unsigned(ipc_port), ''))
1311 ## Search through busy ports to find descriptors which could
1312 ## contain the only reference to this port!
1313 kmsgp = Cast(ipc_port.ip_messages.data.port.messages.ikmq_base, 'ipc_kmsg_t')
1314 kmsgheadp = kmsgp
1315 while unsigned(kmsgp):
1316 entry_str = FindKmsgPortRefs(entry_str, task, ipc_port, kmsgp, qport)
1317 kmsgp = kmsgp.ikm_next
1318 if kmsgp == kmsgheadp:
1319 break;
1320 if len(entry_str) > 0:
1321 sys.stderr.write("{:80s}\r".format(''))
1322 if port_iteration_do_print_taskname:
1323 print "Task: {0: <#x} {1: <s}".format(task, procname)
1324 print '\t' + GetIPCEntrySummary.header
1325 port_iteration_do_print_taskname = False
1326 print entry_str
1327
1328@lldb_command('findportrights', 'R:S:')
1329def FindPortRights(cmd_args=None, cmd_options={}):
1330 """ Routine to locate and print all extant rights to a given port
1331 Usage: findportrights [-R rights_type] [-S <ipc_space_t>] <ipc_port_t>
1332 -S ipc_space : only search the specified ipc space
1333 -R rights_type : only display rights matching the string 'rights_type'
1334
1335 types of rights:
1336 'Dead' : Dead name
1337 'Set' : Port set
1338 'S' : Send right
1339 'R' : Receive right
1340 'O' : Send-once right
1341 types of notifications:
1342 'd' : Dead-Name notification requested
1343 's' : Send-Possible notification armed
1344 'r' : Send-Possible notification requested
1345 'n' : No-Senders notification requested
1346 'x' : Port-destroy notification requested
1347 """
1348 if not cmd_args:
1349 raise ArgumentError("no port address provided")
1350 port = kern.GetValueFromAddress(cmd_args[0], 'struct ipc_port *')
1351
1352 rights_type = 0
1353 if "-R" in cmd_options:
1354 rights_type = cmd_options["-R"]
1355
1356 tasklist = None
1357 if "-S" in cmd_options:
1358 space = kern.GetValueFromAddress(cmd_options["-S"], 'struct ipc_space *')
1359 tasklist = [ space.is_task ]
1360
1361 ## Don't include port sets
1362 ## Don't recurse on busy ports (we do that manually)
1363 ## DO log progress
1364 IterateAllPorts(tasklist, FindPortRightsCallback, (port, rights_type), False, False, True)
1365 sys.stderr.write("{:120s}\r".format(' '))
1366
1367 print "Done."
1368 return
1369# EndMacro: findportrights
1370
1371# Macro: countallports
1372
1373def CountPortsCallback(task, space, ctx, entry_idx, ipc_entry, ipc_port, port_disp):
1374 """ Callback which uses 'ctx' as the set of all ports found in the
1375 iteration. This should *not* be used from a recursive
1376 call to IterateAllPorts.
1377 """
1378 global intransit_idx
1379
1380 (p_set, p_intransit, p_bytask) = ctx
1381
1382 ## Add the port address to the set of all port addresses
1383 p_set.add(unsigned(ipc_port))
1384
1385 if entry_idx == intransit_idx:
1386 p_intransit.add(unsigned(ipc_port))
1387
1388 if task.active or (task.halting and not task.active):
1389 pname = str(Cast(task.bsd_info, 'proc *').p_name)
1390 if not pname in p_bytask.keys():
1391 p_bytask[pname] = { 'transit':0, 'table':0, 'other':0 }
1392 if entry_idx == intransit_idx:
1393 p_bytask[pname]['transit'] += 1
1394 elif entry_idx >= 0:
1395 p_bytask[pname]['table'] += 1
1396 else:
1397 p_bytask[pname]['other'] += 1
1398
1399
1400@lldb_command('countallports', 'P')
1401def CountAllPorts(cmd_args=None, cmd_options={}):
1402 """ Routine to search for all as many references to ipc_port structures in the kernel
1403 that we can find.
1404 Usage: countallports [-P]
1405 -P : include port sets in the count (default: NO)
1406 """
1407 p_set = set()
1408 p_intransit = set()
1409 p_bytask = {}
1410
1411 find_psets = False
1412 if "-P" in cmd_options:
1413 find_psets = True
1414
1415 ## optionally include port sets
1416 ## DO recurse on busy ports
1417 ## DO log progress
1418 IterateAllPorts(None, CountPortsCallback, (p_set, p_intransit, p_bytask), find_psets, True, True)
1419 sys.stderr.write("{:120s}\r".format(' '))
1420
1421 print "Total ports found: {:d}".format(len(p_set))
1422 print "In Transit: {:d}".format(len(p_intransit))
1423 print "By Task:"
1424 for pname in sorted(p_bytask.keys()):
1425 count = p_bytask[pname]
1426 print "\t{: <20s}: table={: <5d}, transit={: <5d}, other={: <5d}".format(pname, count['table'], count['transit'], count['other'])
1427 return
1428# EndMacro: countallports
1429
39236c6e
A
1430# Macro: showpipestats
1431@lldb_command('showpipestats')
1432def ShowPipeStats(cmd_args=None):
1433 """ Display pipes usage information in the kernel
1434 """
1435 print "Number of pipes: {: d}".format(kern.globals.amountpipes)
1436 print "Memory used by pipes: {:s}".format(sizeof_fmt(int(kern.globals.amountpipekva)))
1437 print "Max memory allowed for pipes: {:s}".format(sizeof_fmt(int(kern.globals.maxpipekva)))
1438# EndMacro: showpipestats
1439
1440# Macro: showtaskbusyports
1441@lldb_command('showtaskbusyports')
1442def ShowTaskBusyPorts(cmd_args=None):
1443 """ Routine to print information about receive rights belonging to this task that
1444 have enqueued messages. This is oten a sign of a blocked or hung process
1445 Usage: showtaskbusyports <task address>
1446 """
1447 if not cmd_args:
1448 print "No arguments passed. Please pass in the address of a task"
1449 print ShowTaskBusyPorts.__doc__
1450 return
1451 task = kern.GetValueFromAddress(cmd_args[0], 'task_t')
3e170ce0 1452 PrintTaskBusyPorts(task)
39236c6e
A
1453 return
1454
3e170ce0 1455def PrintTaskBusyPorts(task):
39236c6e
A
1456 """ Prints all busy ports for a given task. ie. all receive rights belonging
1457 to this task that have enqueued messages.
1458 params:
1459 task : core.value representing a task in kernel
1460 returns:
1461 str : String containing information about the given task's busy ports
1462 """
1463 isp = task.itk_space
1464 i = 0
39236c6e
A
1465 while i < isp.is_table_size:
1466 iep = addressof(isp.is_table[i])
1467 if iep.ie_bits & 0x00020000:
1468 port = Cast(iep.ie_object, 'ipc_port_t')
1469 if port.ip_messages.data.port.msgcount > 0:
3e170ce0
A
1470 print PrintPortSummary.header
1471 PrintPortSummary(port)
39236c6e 1472 i = i + 1
3e170ce0 1473 return
39236c6e
A
1474# EndMacro: showtaskbusyports
1475
1476# Macro: showallbusyports
1477@lldb_command('showallbusyports')
1478def ShowAllBusyPorts(cmd_args=None):
1479 """ Routine to print information about all receive rights on the system that
1480 have enqueued messages.
1481 """
1482 task_queue_head = kern.globals.tasks
3e170ce0 1483
39236c6e 1484 for tsk in kern.tasks:
3e170ce0 1485 PrintTaskBusyPorts(tsk)
39236c6e
A
1486 return
1487# EndMacro: showallbusyports
1488
d9a64523
A
1489# Macro: showbusyportsummary
1490@lldb_command('showbusyportsummary')
1491def ShowBusyPortSummary(cmd_args=None):
1492 """ Routine to print a summary of information about all receive rights
1493 on the system that have enqueued messages.
1494 """
1495 task_queue_head = kern.globals.tasks
1496
1497 ipc_table_size = 0
1498 ipc_busy_ports = 0
1499 ipc_msgs = 0
1500
1501 print GetTaskBusyIPCSummary.header
1502 for tsk in kern.tasks:
1503 (summary, table_size, nbusy, nmsgs) = GetTaskBusyIPCSummary(tsk)
1504 ipc_table_size += table_size
1505 ipc_busy_ports += nbusy
1506 ipc_msgs += nmsgs
1507 print summary
1508 for t in kern.terminated_tasks:
1509 (summary, table_size, nbusy, nmsgs) = GetTaskBusyIPCSummary(tsk)
1510 ipc_table_size += table_size
1511 ipc_busy_ports += nbusy
1512 ipc_msgs += nmsgs
1513 print summary
1514 print "Total Table Size: {:d}, Busy Ports: {:d}, Messages in-flight: {:d}".format(ipc_table_size, ipc_busy_ports, ipc_msgs)
1515 return
1516# EndMacro: showbusyportsummary
1517
3e170ce0
A
1518# Macro: showport:
1519@lldb_command('showport','K')
1520def ShowPort(cmd_args=None, cmd_options={}):
1521 """ Routine that lists details about a given IPC port
1522 Syntax: (lldb) showport 0xaddr
1523 """
1524 show_kmsgs = True
1525 if "-K" in cmd_options:
1526 show_kmsgs = False
1527 if not cmd_args:
1528 print "Please specify the address of the port whose details you want to print"
1529 print ShowPort.__doc__
1530 return
1531 port = kern.GetValueFromAddress(cmd_args[0], 'struct ipc_port *')
1532 print PrintPortSummary.header
1533 PrintPortSummary(port, show_kmsgs)
1534# EndMacro: showport
1535
39236c6e 1536# Macro: showmqueue:
3e170ce0
A
1537@lldb_command('showmqueue', "S:")
1538def ShowMQueue(cmd_args=None, cmd_options={}):
39236c6e 1539 """ Routine that lists details about a given mqueue
3e170ce0 1540 Syntax: (lldb) showmqueue 0xaddr [-S ipc_space]
39236c6e
A
1541 """
1542 if not cmd_args:
1543 print "Please specify the address of the ipc_mqueue whose details you want to print"
1544 print ShowMQueue.__doc__
1545 return
3e170ce0
A
1546 space = 0
1547 if "-S" in cmd_options:
1548 space = kern.GetValueFromAddress(cmd_options["-S"], 'struct ipc_space *')
39236c6e 1549 mqueue = kern.GetValueFromAddress(cmd_args[0], 'struct ipc_mqueue *')
3e170ce0 1550 wq_type = mqueue.data.pset.setq.wqset_q.waitq_type
39236c6e 1551 if int(wq_type) == 3:
fe8ab488 1552 psetoff = getfieldoffset('struct ipc_pset', 'ips_messages')
39236c6e 1553 pset = unsigned(ArgumentStringToInt(cmd_args[0])) - unsigned(psetoff)
3e170ce0
A
1554 print PrintPortSetSummary.header
1555 PrintPortSetSummary(kern.GetValueFromAddress(pset, 'struct ipc_pset *'), space)
94ff46dc 1556 elif int(wq_type) in [2, 1]:
39236c6e
A
1557 portoff = getfieldoffset('struct ipc_port', 'ip_messages')
1558 port = unsigned(ArgumentStringToInt(cmd_args[0])) - unsigned(portoff)
3e170ce0
A
1559 print PrintPortSummary.header
1560 PrintPortSummary(kern.GetValueFromAddress(port, 'struct ipc_port *'))
1561 else:
1562 print "Invalid mqueue? (waitq type {:d} is invalid)".format(int(wq_type))
39236c6e
A
1563# EndMacro: showmqueue
1564
fe8ab488
A
1565# Macro: showkmsg:
1566@lldb_command('showkmsg')
1567def ShowKMSG(cmd_args=[]):
1568 """ Show detail information about a <ipc_kmsg_t> structure
1569 Usage: (lldb) showkmsg <ipc_kmsg_t>
1570 """
1571 if not cmd_args:
1572 raise ArgumentError('Invalid arguments')
1573 kmsg = kern.GetValueFromAddress(cmd_args[0], 'ipc_kmsg_t')
1574 print GetKMsgSummary.header
1575 print GetKMsgSummary(kmsg)
1576
1577# EndMacro: showkmsg
1578
39236c6e 1579# Macro: showpset
3e170ce0
A
1580@lldb_command('showpset', "S:")
1581def ShowPSet(cmd_args=None, cmd_options={}):
39236c6e 1582 """ Routine that prints details for a given ipc_pset *
3e170ce0 1583 Syntax: (lldb) showpset 0xaddr [-S ipc_space]
39236c6e
A
1584 """
1585 if not cmd_args:
1586 print "Please specify the address of the pset whose details you want to print"
1587 print ShowPSet.__doc__
1588 return
3e170ce0
A
1589 space = 0
1590 if "-S" in cmd_options:
1591 space = kern.GetValueFromAddress(cmd_options["-S"], 'struct ipc_space *')
1592
1593 print PrintPortSetSummary.header
1594 PrintPortSetSummary(kern.GetValueFromAddress(cmd_args[0], 'ipc_pset *'), space)
39236c6e
A
1595# EndMacro: showpset
1596
fe8ab488
A
1597# IPC importance inheritance related macros.
1598
1599@lldb_command('showalliits')
1600def ShowAllIITs(cmd_args=[], cmd_options={}):
1601 """ Development only macro. Show list of all iits allocated in the system. """
1602 try:
1603 iit_queue = kern.globals.global_iit_alloc_queue
1604 except ValueError:
1605 print "This debug macro is only available in development or debug kernels"
1606 return
1607
1608 print GetIPCImportantTaskSummary.header
1609 for iit in IterateQueue(iit_queue, 'struct ipc_importance_task *', 'iit_allocation'):
1610 print GetIPCImportantTaskSummary(iit)
1611 return
1612
1613@header("{: <18s} {: <3s} {: <18s} {: <20s} {: <18s} {: <8s}".format("ipc_imp_inherit", "don", "to_task", "proc_name", "from_elem", "depth"))
1614@lldb_type_summary(['ipc_importance_inherit *', 'ipc_importance_inherit_t'])
1615def GetIPCImportanceInheritSummary(iii):
1616 """ describes iii object of type ipc_importance_inherit_t * """
1617 out_str = ""
1618 fmt = "{o: <#018x} {don: <3s} {o.iii_to_task.iit_task: <#018x} {task_name: <20s} {o.iii_from_elem: <#018x} {o.iii_depth: <#08x}"
1619 donating_str = ""
1620 if unsigned(iii.iii_donating):
1621 donating_str = "DON"
1622 taskname = GetProcNameForTask(iii.iii_to_task.iit_task)
1623 if hasattr(iii.iii_to_task, 'iit_bsd_pid'):
1624 taskname = "({:d}) {:s}".format(iii.iii_to_task.iit_bsd_pid, iii.iii_to_task.iit_procname)
1625 out_str += fmt.format(o=iii, task_name = taskname, don=donating_str)
1626 return out_str
1627
1628@static_var('recursion_count', 0)
1629@header("{: <18s} {: <4s} {: <8s} {: <8s} {: <18s} {: <18s}".format("iie", "type", "refs", "made", "#kmsgs", "#inherits"))
1630@lldb_type_summary(['ipc_importance_elem *'])
1631def GetIPCImportanceElemSummary(iie):
1632 """ describes an ipc_importance_elem * object """
1633
1634 if GetIPCImportanceElemSummary.recursion_count > 500:
1635 GetIPCImportanceElemSummary.recursion_count = 0
1636 return "Recursion of 500 reached"
1637
1638 out_str = ''
1639 fmt = "{: <#018x} {: <4s} {: <8d} {: <8d} {: <#018x} {: <#018x}"
fe8ab488
A
1640 if unsigned(iie.iie_bits) & 0x80000000:
1641 type_str = "INH"
39037602
A
1642 inherit_count = 0
1643 else:
1644 type_str = 'TASK'
1645 iit = Cast(iie, 'struct ipc_importance_task *')
1646 inherit_count = sum(1 for i in IterateQueue(iit.iit_inherits, 'struct ipc_importance_inherit *', 'iii_inheritance'))
1647
fe8ab488
A
1648 refs = unsigned(iie.iie_bits) & 0x7fffffff
1649 made_refs = unsigned(iie.iie_made)
1650 kmsg_count = sum(1 for i in IterateQueue(iie.iie_kmsgs, 'struct ipc_kmsg *', 'ikm_inheritance'))
fe8ab488
A
1651 out_str += fmt.format(iie, type_str, refs, made_refs, kmsg_count, inherit_count)
1652 if config['verbosity'] > vHUMAN:
1653 if kmsg_count > 0:
1654 out_str += "\n\t"+ GetKMsgSummary.header
1655 for k in IterateQueue(iie.iie_kmsgs, 'struct ipc_kmsg *', 'ikm_inheritance'):
3e170ce0 1656 out_str += "\t" + "{: <#018x}".format(k.ikm_header.msgh_remote_port) + ' ' + GetKMsgSummary(k, "\t").lstrip()
fe8ab488
A
1657 out_str += "\n"
1658 if inherit_count > 0:
1659 out_str += "\n\t" + GetIPCImportanceInheritSummary.header + "\n"
39037602 1660 for i in IterateQueue(iit.iit_inherits, 'struct ipc_importance_inherit *', 'iii_inheritance'):
fe8ab488
A
1661 out_str += "\t" + GetIPCImportanceInheritSummary(i) + "\n"
1662 out_str += "\n"
1663 if type_str == "INH":
1664 iii = Cast(iie, 'struct ipc_importance_inherit *')
1665 out_str += "Inherit from: " + GetIPCImportanceElemSummary(iii.iii_from_elem)
1666
1667 return out_str
1668
1669@header("{: <18s} {: <18s} {: <20s}".format("iit", "task", "name"))
1670@lldb_type_summary(['ipc_importance_task *'])
1671def GetIPCImportantTaskSummary(iit):
1672 """ iit is a ipc_importance_task value object.
1673 """
1674 fmt = "{: <#018x} {: <#018x} {: <20s}"
1675 out_str=''
1676 pname = GetProcNameForTask(iit.iit_task)
1677 if hasattr(iit, 'iit_bsd_pid'):
1678 pname = "({:d}) {:s}".format(iit.iit_bsd_pid, iit.iit_procname)
1679 out_str += fmt.format(iit, iit.iit_task, pname)
1680 return out_str
1681
1682@lldb_command('showallimportancetasks')
1683def ShowIPCImportanceTasks(cmd_args=[], cmd_options={}):
1684 """ display a list of all tasks with ipc importance information.
1685 Usage: (lldb) showallimportancetasks
1686 Tip: add "-v" to see detailed information on each kmsg or inherit elems
1687 """
1688 print ' ' + GetIPCImportantTaskSummary.header + ' ' + GetIPCImportanceElemSummary.header
1689 for t in kern.tasks:
1690 s = ""
1691 if unsigned(t.task_imp_base):
1692 s += ' ' + GetIPCImportantTaskSummary(t.task_imp_base)
1693 s += ' ' + GetIPCImportanceElemSummary(addressof(t.task_imp_base.iit_elem))
1694 print s
1695
1696@lldb_command('showipcimportance', '')
1697def ShowIPCImportance(cmd_args=[], cmd_options={}):
1698 """ Describe an importance from <ipc_importance_elem_t> argument.
1699 Usage: (lldb) showimportance <ipc_importance_elem_t>
1700 """
1701 if not cmd_args:
1702 raise ArgumentError("Please provide valid argument")
1703
1704 elem = kern.GetValueFromAddress(cmd_args[0], 'ipc_importance_elem_t')
1705 print GetIPCImportanceElemSummary.header
1706 print GetIPCImportanceElemSummary(elem)
1707
1708@header("{: <18s} {: <10s} {: <18s} {: <18s} {: <8s} {: <5s} {: <5s} {: <5s}".format("ivac", "refs", "port", "tbl", "tblsize", "index", "Grow", "freelist"))
1709@lldb_type_summary(['ipc_voucher_attr_control *', 'ipc_voucher_attr_control_t'])
1710def GetIPCVoucherAttrControlSummary(ivac):
1711 """ describes a voucher attribute control settings """
1712 out_str = ""
1713 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}"
1714 growing_str = ""
1715
1716 if unsigned(ivac) == 0:
1717 return "{: <#018x}".format(ivac)
1718
1719 if unsigned(ivac.ivac_is_growing):
1720 growing_str = "Y"
1721 out_str += fmt.format(c=ivac, growing = growing_str)
1722 return out_str
1723
1724@lldb_command('showivac','')
1725def ShowIPCVoucherAttributeControl(cmd_args=[], cmd_options={}):
1726 """ Show summary of voucher attribute contols.
1727 Usage: (lldb) showivac <ipc_voucher_attr_control_t>
1728 """
1729 if not cmd_args:
1730 raise ArgumentError("Please provide correct arguments.")
1731 ivac = kern.GetValueFromAddress(cmd_args[0], 'ipc_voucher_attr_control_t')
1732 print GetIPCVoucherAttrControlSummary.header
1733 print GetIPCVoucherAttrControlSummary(ivac)
1734 if config['verbosity'] > vHUMAN:
1735 cur_entry_index = 0
1736 last_entry_index = unsigned(ivac.ivac_table_size)
1737 print "index " + GetIPCVoucherAttributeEntrySummary.header
1738 while cur_entry_index < last_entry_index:
1739 print "{: <5d} ".format(cur_entry_index) + GetIPCVoucherAttributeEntrySummary(addressof(ivac.ivac_table[cur_entry_index]))
1740 cur_entry_index += 1
1741
1742
1743
1744
1745@header("{: <18s} {: <30s} {: <30s} {: <30s} {: <30s} {: <30s}".format("ivam", "get_value_fn", "extract_fn", "release_value_fn", "command_fn", "release_fn"))
1746@lldb_type_summary(['ipc_voucher_attr_manager *', 'ipc_voucher_attr_manager_t'])
1747def GetIPCVoucherAttrManagerSummary(ivam):
1748 """ describes a voucher attribute manager settings """
1749 out_str = ""
1750 fmt = "{: <#018x} {: <30s} {: <30s} {: <30s} {: <30s} {: <30s}"
1751
1752 if unsigned(ivam) == 0 :
1753 return "{: <#018x}".format(ivam)
1754
1755 get_value_fn = kern.Symbolicate(unsigned(ivam.ivam_get_value))
1756 extract_fn = kern.Symbolicate(unsigned(ivam.ivam_extract_content))
1757 release_value_fn = kern.Symbolicate(unsigned(ivam.ivam_release_value))
1758 command_fn = kern.Symbolicate(unsigned(ivam.ivam_command))
1759 release_fn = kern.Symbolicate(unsigned(ivam.ivam_release))
1760 out_str += fmt.format(ivam, get_value_fn, extract_fn, release_value_fn, command_fn, release_fn)
1761 return out_str
1762
1763
1764
1765@header("{: <18s} {: <10s} {:s} {:s}".format("ivgte", "key", GetIPCVoucherAttrControlSummary.header.strip(), GetIPCVoucherAttrManagerSummary.header.strip()))
1766@lldb_type_summary(['ipc_voucher_global_table_element *', 'ipc_voucher_global_table_element_t'])
1767def GetIPCVoucherGlobalTableElementSummary(ivgte):
1768 """ describes a ipc_voucher_global_table_element object """
1769 out_str = ""
1770 fmt = "{g: <#018x} {g.ivgte_key: <10d} {ctrl_s:s} {mgr_s:s}"
1771 out_str += fmt.format(g=ivgte, ctrl_s=GetIPCVoucherAttrControlSummary(ivgte.ivgte_control), mgr_s=GetIPCVoucherAttrManagerSummary(ivgte.ivgte_manager))
1772 return out_str
1773
1774@lldb_command('showglobalvouchertable', '')
1775def ShowGlobalVoucherTable(cmd_args=[], cmd_options={}):
1776 """ show detailed information of all voucher attribute managers registered with vouchers system
1777 Usage: (lldb) showglobalvouchertable
1778 """
1779 entry_size = sizeof(kern.globals.iv_global_table[0])
1780 elems = sizeof(kern.globals.iv_global_table) / entry_size
1781 print GetIPCVoucherGlobalTableElementSummary.header
1782 for i in range(elems):
1783 elt = addressof(kern.globals.iv_global_table[i])
1784 print GetIPCVoucherGlobalTableElementSummary(elt)
1785
1786# Type summaries for Bag of Bits.
1787
1788@lldb_type_summary(['user_data_value_element', 'user_data_element_t'])
1789@header("{0: <20s} {1: <16s} {2: <20s} {3: <20s} {4: <16s} {5: <20s}".format("user_data_ve", "maderefs", "checksum", "hash value", "size", "data"))
1790def GetBagofBitsElementSummary(data_element):
1791 """ Summarizes the Bag of Bits element
1792 params: data_element = value of the object of type user_data_value_element_t
1793 returns: String with summary of the type.
1794 """
1795 format_str = "{0: <#020x} {1: <16d} {2: <#020x} {3: <#020x} {4: <16d}"
1796 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))
1797 out_string += " 0x"
1798
1799 for i in range(0, (unsigned(data_element.e_size) - 1)):
1800 out_string += "{:02x}".format(int(data_element.e_data[i]))
1801 return out_string
1802
1803def GetIPCHandleSummary(handle_ptr):
1804 """ converts a handle value inside a voucher attribute table to ipc element and returns appropriate summary.
1805 params: handle_ptr - uint64 number stored in handle of voucher.
1806 returns: str - string summary of the element held in internal structure
1807 """
1808 elem = kern.GetValueFromAddress(handle_ptr, 'ipc_importance_elem_t')
1809 if elem.iie_bits & 0x80000000 :
1810 iie = Cast(elem, 'struct ipc_importance_inherit *')
1811 return GetIPCImportanceInheritSummary(iie)
1812 else:
1813 iit = Cast(elem, 'struct ipc_importance_task *')
1814 return GetIPCImportantTaskSummary(iit)
1815
1816def GetATMHandleSummary(handle_ptr):
1817 """ Convert a handle value to atm value and returns corresponding summary of its fields.
1818 params: handle_ptr - uint64 number stored in handle of voucher
1819 returns: str - summary of atm value
1820 """
1821 elem = kern.GetValueFromAddress(handle_ptr, 'atm_value *')
1822 return GetATMValueSummary(elem)
1823
1824def GetBankHandleSummary(handle_ptr):
1825 """ converts a handle value inside a voucher attribute table to bank element and returns appropriate summary.
1826 params: handle_ptr - uint64 number stored in handle of voucher.
1827 returns: str - summary of bank element
1828 """
490019cf
A
1829 if handle_ptr == 1 :
1830 return "Bank task of Current task"
fe8ab488
A
1831 elem = kern.GetValueFromAddress(handle_ptr, 'bank_element_t')
1832 if elem.be_type & 1 :
1833 ba = Cast(elem, 'struct bank_account *')
1834 return GetBankAccountSummary(ba)
1835 else:
1836 bt = Cast(elem, 'struct bank_task *')
1837 return GetBankTaskSummary(bt)
1838
1839def GetBagofBitsHandleSummary(handle_ptr):
1840 """ Convert a handle value to bag of bits value and returns corresponding summary of its fields.
1841 params: handle_ptr - uint64 number stored in handle of voucher
1842 returns: str - summary of bag of bits element
1843 """
1844 elem = kern.GetValueFromAddress(handle_ptr, 'user_data_element_t')
1845 return GetBagofBitsElementSummary(elem)
1846
1847@static_var('attr_managers',{1: GetATMHandleSummary, 2: GetIPCHandleSummary, 3: GetBankHandleSummary, 7: GetBagofBitsHandleSummary})
1848def GetHandleSummaryForKey(handle_ptr, key_num):
1849 """ Get a summary of handle pointer from the voucher attribute manager.
1850 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.
1851 key 2 -> ipc and it puts either ipc_importance_inherit_t or ipc_important_task_t.
1852 key 3 -> Bank and it puts either bank_task_t or bank_account_t.
1853 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.
1854 """
1855 key_num = int(key_num)
1856 if key_num not in GetHandleSummaryForKey.attr_managers:
1857 return "Unknown key %d" % key_num
1858 return GetHandleSummaryForKey.attr_managers[key_num](handle_ptr)
1859
1860
1861@header("{: <18s} {: <18s} {: <10s} {: <4s} {: <18s} {: <18s}".format("ivace", "value_handle", "#refs", "rel?", "maderefs", "next_layer"))
1862@lldb_type_summary(['ivac_entry *', 'ivac_entry_t'])
1863def GetIPCVoucherAttributeEntrySummary(ivace, manager_key_num = 0):
1864 """ Get summary for voucher attribute entry.
1865 """
1866 out_str = ""
1867 fmt = "{e: <#018x} {e.ivace_value: <#018x} {e.ivace_refs: <10d} {release: <4s} {made_refs: <18s} {next_layer: <18s}"
1868 release_str = ""
1869 free_str = ""
1870 made_refs = ""
1871 next_layer = ""
1872
1873 if unsigned(ivace.ivace_releasing):
1874 release_str = "Y"
1875 if unsigned(ivace.ivace_free):
1876 free_str = 'F'
1877 if unsigned(ivace.ivace_layered):
1878 next_layer = "{: <#018x}".format(ivace.ivace_u.ivaceu_layer)
1879 else:
1880 made_refs = "{: <18d}".format(ivace.ivace_u.ivaceu_made)
1881
1882 out_str += fmt.format(e=ivace, release=release_str, made_refs=made_refs, next_layer=next_layer)
1883 if config['verbosity'] > vHUMAN and manager_key_num > 0:
1884 out_str += " " + GetHandleSummaryForKey(unsigned(ivace.ivace_value), manager_key_num)
1885 if config['verbosity'] > vHUMAN :
1886 out_str += ' {: <2s} {: <4d} {: <4d}'.format(free_str, ivace.ivace_next, ivace.ivace_index)
1887 return out_str
1888
1889@lldb_command('showivacfreelist','')
1890def ShowIVACFreeList(cmd_args=[], cmd_options={}):
1891 """ Walk the free list and print every entry in the list.
1892 usage: (lldb) showivacfreelist <ipc_voucher_attr_control_t>
1893 """
1894 if not cmd_args:
1895 raise ArgumentError('Please provide <ipc_voucher_attr_control_t>')
1896 ivac = kern.GetValueFromAddress(cmd_args[0], 'ipc_voucher_attr_control_t')
1897 print GetIPCVoucherAttrControlSummary.header
1898 print GetIPCVoucherAttrControlSummary(ivac)
1899 if unsigned(ivac.ivac_freelist) == 0:
1900 print "ivac table is full"
1901 return
1902 print "index " + GetIPCVoucherAttributeEntrySummary.header
1903 next_free = unsigned(ivac.ivac_freelist)
1904 while next_free != 0:
1905 print "{: <5d} ".format(next_free) + GetIPCVoucherAttributeEntrySummary(addressof(ivac.ivac_table[next_free]))
1906 next_free = unsigned(ivac.ivac_table[next_free].ivace_next)
1907
1908
1909
1910@header('{: <18s} {: <8s} {: <18s} {: <18s} {: <18s} {: <18s} {: <18s}'.format("ipc_voucher", "refs", "checksum", "hash", "tbl_size", "table", "voucher_port"))
1911@lldb_type_summary(['ipc_voucher *', 'ipc_voucher_t'])
1912def GetIPCVoucherSummary(voucher, show_entries=False):
1913 """ describe a voucher from its ipc_voucher * object """
1914 out_str = ""
1915 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}"
1916 out_str += fmt.format(v = voucher)
1917 entries_str = ''
1918 if show_entries or config['verbosity'] > vHUMAN:
1919 elems = unsigned(voucher.iv_table_size)
1920 entries_header_str = "\n\t" + "{: <5s} {: <3s} {: <16s} {: <30s}".format("index", "key", "value_index", "manager") + " " + GetIPCVoucherAttributeEntrySummary.header
1921 fmt = "{: <5d} {: <3d} {: <16d} {: <30s}"
1922 for i in range(elems):
1923 voucher_entry_index = unsigned(voucher.iv_inline_table[i])
1924 if voucher_entry_index:
1925 s = fmt.format(i, GetVoucherManagerKeyForIndex(i), voucher_entry_index, GetVoucherAttributeManagerNameForIndex(i))
1926 e = GetVoucherValueHandleFromVoucherForIndex(voucher, i)
1927 if e is not None:
1928 s += " " + GetIPCVoucherAttributeEntrySummary(addressof(e), GetVoucherManagerKeyForIndex(i) )
1929 if entries_header_str :
1930 entries_str = entries_header_str
1931 entries_header_str = ''
1932 entries_str += "\n\t" + s
1933 if not entries_header_str:
1934 entries_str += "\n\t"
1935 out_str += entries_str
1936 return out_str
1937
1938def GetVoucherManagerKeyForIndex(idx):
1939 """ Returns key number for index based on global table. Will raise index error if value is incorrect
1940 """
1941 return unsigned(kern.globals.iv_global_table[idx].ivgte_key)
1942
1943def GetVoucherAttributeManagerForKey(k):
1944 """ Walks through the iv_global_table and finds the attribute manager name
1945 params: k - int key number of the manager
1946 return: cvalue - the attribute manager object.
1947 None - if not found
1948 """
1949 retval = None
1950 entry_size = sizeof(kern.globals.iv_global_table[0])
1951 elems = sizeof(kern.globals.iv_global_table) / entry_size
1952 for i in range(elems):
1953 elt = addressof(kern.globals.iv_global_table[i])
1954 if k == unsigned(elt.ivgte_key):
1955 retval = elt.ivgte_manager
1956 break
1957 return retval
1958
1959def GetVoucherAttributeControllerForKey(k):
1960 """ Walks through the iv_global_table and finds the attribute controller
1961 params: k - int key number of the manager
1962 return: cvalue - the attribute controller object.
1963 None - if not found
1964 """
1965 retval = None
1966 entry_size = sizeof(kern.globals.iv_global_table[0])
1967 elems = sizeof(kern.globals.iv_global_table) / entry_size
1968 for i in range(elems):
1969 elt = addressof(kern.globals.iv_global_table[i])
1970 if k == unsigned(elt.ivgte_key):
1971 retval = elt.ivgte_control
1972 break
1973 return retval
1974
1975
1976def GetVoucherAttributeManagerName(ivam):
1977 """ find the name of the ivam object
1978 param: ivam - cvalue object of type ipc_voucher_attr_manager_t
1979 returns: str - name of the manager
1980 """
1981 return kern.Symbolicate(unsigned(ivam))
1982
1983def GetVoucherAttributeManagerNameForIndex(idx):
1984 """ get voucher attribute manager name for index
1985 return: str - name of the attribute manager object
1986 """
1987 return GetVoucherAttributeManagerName(GetVoucherAttributeManagerForKey(GetVoucherManagerKeyForIndex(idx)))
1988
1989def GetVoucherValueHandleFromVoucherForIndex(voucher, idx):
1990 """ traverse the voucher attrs and get value_handle in the voucher attr controls table
1991 params:
1992 voucher - cvalue object of type ipc_voucher_t
1993 idx - int index in the entries for which you wish to get actual handle for
1994 returns: cvalue object of type ivac_entry_t
1995 None if no handle found.
1996 """
1997 manager_key = GetVoucherManagerKeyForIndex(idx)
1998 voucher_num_elems = unsigned(voucher.iv_table_size)
1999 if idx >= voucher_num_elems:
2000 debuglog("idx %d is out of range max: %d" % (idx, voucher_num_elems))
2001 return None
2002 voucher_entry_value = unsigned(voucher.iv_inline_table[idx])
2003 debuglog("manager_key %d" % manager_key)
2004 ivac = GetVoucherAttributeControllerForKey(manager_key)
2005 if ivac is None or unsigned(ivac) == 0:
2006 debuglog("No voucher attribute controller for idx %d" % idx)
2007 return None
2008
2009 ivac = kern.GetValueFromAddress(unsigned(ivac), 'ipc_voucher_attr_control_t') # ??? No idea why lldb does not addressof directly
2010 ivace_table = ivac.ivac_table
2011 if voucher_entry_value >= unsigned(ivac.ivac_table_size):
2012 print "Failed to get ivace for value %d in table of size %d" % (voucher_entry_value, unsigned(ivac.ivac_table_size))
2013 return None
2014 return ivace_table[voucher_entry_value]
2015
2016
2017
2018@lldb_command('showallvouchers')
2019def ShowAllVouchers(cmd_args=[], cmd_options={}):
2020 """ Display a list of all vouchers in the global voucher hash table
2021 Usage: (lldb) showallvouchers
2022 """
2023 iv_hash_table = kern.globals.ivht_bucket
2024 num_buckets = sizeof(kern.globals.ivht_bucket) / sizeof(kern.globals.ivht_bucket[0])
2025 print GetIPCVoucherSummary.header
2026 for i in range(num_buckets):
2027 for v in IterateQueue(iv_hash_table[i], 'ipc_voucher_t', 'iv_hash_link'):
2028 print GetIPCVoucherSummary(v)
2029
2030@lldb_command('showvoucher', '')
2031def ShowVoucher(cmd_args=[], cmd_options={}):
2032 """ Describe a voucher from <ipc_voucher_t> argument.
2033 Usage: (lldb) showvoucher <ipc_voucher_t>
2034 """
2035 if not cmd_args:
2036 raise ArgumentError("Please provide valid argument")
2037
2038 voucher = kern.GetValueFromAddress(cmd_args[0], 'ipc_voucher_t')
2039 print GetIPCVoucherSummary.header
2040 print GetIPCVoucherSummary(voucher, show_entries=True)
fe8ab488 2041
39037602
A
2042def GetSpaceSendRightEntries(space, port):
2043 """ Get entry summaries for all send rights to port address in an IPC space.
2044 params:
2045 space - the IPC space to search for send rights
2046 port_addr - the port address to match, or 0 to get all send rights
2047 returns: an array of IPC entries
2048 """
2049 entry_table = space.is_table
2050 ports = int(space.is_table_size)
2051 i = 0
2052 entries = []
2053
2054 while i < ports:
2055 entry = GetObjectAtIndexFromArray(entry_table, i)
2056
2057 entry_ie_bits = unsigned(entry.ie_bits)
2058 if (entry_ie_bits & 0x00010000) != 0 and (not port or entry.ie_object == port):
2059 entries.append(entry)
2060 i += 1
2061
2062 return entries
2063
2064@lldb_command('showportsendrights')
2065def ShowPortSendRights(cmd_args=[], cmd_options={}):
2066 """ Display a list of send rights across all tasks for a given port.
2067 Usage: (lldb) showportsendrights <ipc_port_t>
2068 """
2069 if not cmd_args:
2070 raise ArgumentError("no port address provided")
2071 port = kern.GetValueFromAddress(cmd_args[0], 'struct ipc_port *')
2072 i = 1
2073
d9a64523 2074 return FindPortRights(cmd_args=[unsigned(port)], cmd_options={'-R':'S'})
39037602 2075
39037602
A
2076
2077@lldb_command('showtasksuspenders')
2078def ShowTaskSuspenders(cmd_args=[], cmd_options={}):
2079 """ Display the tasks and send rights that are holding a target task suspended.
2080 Usage: (lldb) showtasksuspenders <task_t>
2081 """
2082 if not cmd_args:
2083 raise ArgumentError("no task address provided")
2084 task = kern.GetValueFromAddress(cmd_args[0], 'task_t')
2085
2086 if task.suspend_count == 0:
2087 print "task {:#x} ({:s}) is not suspended".format(unsigned(task), Cast(task.bsd_info, 'proc_t').p_name)
2088 return
2089
2090 # If the task has been suspended by the kernel (potentially by
2091 # kperf, using task_suspend_internal) or a client of task_suspend2
2092 # that does not convert its task suspension token to a port using
2093 # convert_task_suspension_token_to_port, then it's impossible to determine
2094 # which task did the suspension.
2095 port = task.itk_resume
2096 if not port:
2097 print "task {:#x} ({:s}) is suspended but no resume port exists".format(unsigned(task), Cast(task.bsd_info, 'proc_t').p_name)
2098 return
2099
d9a64523 2100 return FindPortRights(cmd_args=[unsigned(port)], cmd_options={'-R':'S'})