]> git.saurik.com Git - apple/xnu.git/blob - tools/lldbmacros/ipc.py
xnu-3789.1.32.tar.gz
[apple/xnu.git] / tools / lldbmacros / ipc.py
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 """
4 from xnu import *
5 import sys, shlex
6 from utils import *
7 from process import *
8 from atm import *
9 from bank import *
10 from waitq import *
11 from ioreg import *
12 import xnudefines
13
14 @header("{0: <20s} {1: <6s} {2: <6s} {3: <10s} {4: <15s}".format("task", "pid", '#acts', "tablesize", "command"))
15 def GetTaskIPCSummary(task):
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 = ''
23 format_string = "{0: <#020x} {1: <6d} {2: <6d} {3: <10d} {4: <15s}"
24 pval = Cast(task.bsd_info, 'proc *')
25 table_size = int(task.itk_space.is_table_size)
26 proc_name = str(pval.p_comm)
27 out_string += format_string.format(task, pval.p_pid, task.thread_count, table_size, proc_name)
28 return out_string
29
30 @header("{0: <20s} {1: <28s} {2: <12s} {3: <6s} {4: <4s} {5: <20s} {6: <4s}\n".format(
31 "port", "mqueue", "recvname", "flags", "refs", "recvname", "dest"))
32 def PrintPortSummary(port, show_kmsg_summary=True, prefix=""):
33 """ Display a port's summary
34 params:
35 port : core.value representing a port in the kernel
36 returns
37 str : string of ipc info for the given port
38 """
39 out_string = ""
40 portp = Cast(port, 'struct ipc_port *')
41 destspacep = kern.GetValueFromAddress(0, 'struct ipc_space *')
42 spacep = portp.data.receiver
43 format_string = "{0: #019x} {1: #019x} {2: <8s} {3: #011x} {4: <5s} {5: #05x} {6: #019x} {7: <16s}\n"
44 if portp.ip_object.io_bits & 0x80000000:
45 out_string += prefix + format_string.format(
46 unsigned(portp), addressof(portp.ip_messages), ' '*8,
47 unsigned(portp.ip_messages.data.port.receiver_name),
48 "APort", portp.ip_object.io_references,
49 unsigned(portp.ip_messages.data.port.receiver_name),
50 GetPortDestProc(portp))
51 else:
52 out_string += prefix + format_string.format(
53 unsigned(portp), addressof(portp.ip_messages), ' '*8,
54 unsigned(portp.ip_messages.data.port.receiver_name),
55 "DPort", portp.ip_object.io_references, unsigned(portp),
56 "inactive-port")
57 print out_string
58 if show_kmsg_summary:
59 kmsgp = Cast(portp.ip_messages.data.port.messages.ikmq_base, 'ipc_kmsg_t')
60 if unsigned(kmsgp):
61 print prefix + GetKMsgSummary.header + prefix + GetKMsgSummary(kmsgp, prefix)
62 kmsgheadp = kmsgp
63 kmsgp = kmsgp.ikm_next
64 while (kmsgp) != (kmsgheadp):
65 print prefix + GetKMsgSummary(kmsgp, prefix)
66 kmsgp = kmsgp.ikm_next
67 return
68
69 def GetPortDestProc(portp):
70 """ Display the name and pid of a given port's receiver
71 params:
72 portp : core.value representing a pointer to a port in the kernel
73 destspacep : core.value representing a pointer to an ipc_space
74 returns:
75 str : string containing receiver's name and pid
76 """
77 spacep = portp.data.receiver
78 out_str = "Not found"
79 for tsk in kern.tasks:
80 if tsk.itk_space == spacep:
81 if tsk.bsd_info:
82 destprocp = Cast(tsk.bsd_info, 'struct proc *')
83 out_str = "{0:s}({1: <d})".format(destprocp.p_comm, destprocp.p_pid)
84 else:
85 out_str = "unknown"
86 break
87
88 return out_str
89
90 @header("{:<20s} {:<28s} {:<12s} {:<8s} {:<6s} {:<19s} {:<26s} {:<26s}\n".format(
91 "", "kmsg", "msgid", "disp", "size", "reply-port", "source", "destination"))
92 def GetKMsgSummary(kmsgp, prefix_str=""):
93 """ Display a summary for type ipc_kmsg_t
94 params:
95 kmsgp : core.value representing the given ipc_kmsg_t struct
96 returns:
97 str : string of summary info for the given ipc_kmsg_t instance
98 """
99 kmsghp = kmsgp.ikm_header
100 kmsgh = dereference(kmsghp)
101 out_string = ""
102 out_string += "{0: <20s} {1: <#019x} {2: <8s} {3: <#011x} ".format(
103 ' ', unsigned(kmsgp), ' '*8, kmsgh.msgh_id)
104 prefix_str = "{0: <20s} ".format(' ') + prefix_str
105 disposition = ""
106 bits = kmsgh.msgh_bits & 0xff
107
108 # remote port
109 if bits == 17:
110 disposition = "rS"
111 elif bits == 18:
112 disposition = "rO"
113 else :
114 disposition = "rX" # invalid
115
116 out_string += "{0: <2s}".format(disposition)
117
118 # local port
119 disposition = ""
120 bits = (kmsgh.msgh_bits & 0xff00) >> 8
121
122 if bits == 17:
123 disposition = "lS"
124 elif bits == 18:
125 disposition = "lO"
126 elif bits == 0:
127 disposition = "l-"
128 else:
129 disposition = "lX" # invalid
130
131 out_string += "{0: <2s}".format(disposition)
132
133 # voucher
134 disposition = ""
135 bits = (kmsgh.msgh_bits & 0xff0000) >> 16
136
137 if bits == 17:
138 disposition = "vS"
139 elif bits == 0:
140 disposition = "v-"
141 else:
142 disposition = "vX"
143
144 out_string += "{0: <2s}".format(disposition)
145
146 # complex message
147 if kmsgh.msgh_bits & 0x80000000:
148 out_string += "{0: <1s}".format("c")
149 else:
150 out_string += "{0: <1s}".format("s")
151
152 # importance boost
153 if kmsgh.msgh_bits & 0x20000000:
154 out_string += "{0: <1s}".format("I")
155 else:
156 out_string += "{0: <1s}".format("-")
157
158 dest_proc_name = ""
159 if kmsgp.ikm_header.msgh_remote_port:
160 dest_proc_name = GetDestinationProcessFromPort(kmsgp.ikm_header.msgh_remote_port)
161
162 out_string += "{0: ^6d} {1: <#019x} {2: <26s} {3: <26s}\n".format(
163 unsigned(kmsgh.msgh_size), unsigned(kmsgh.msgh_local_port),
164 GetKMsgSrc(kmsgp), dest_proc_name)
165
166 if kmsgh.msgh_bits & 0x80000000:
167 out_string += prefix_str + "\t" + GetKMsgBody.header + "\n"
168 out_string += prefix_str + "\t" + GetKMsgBody(kmsgp, prefix_str + "\t") + "\n"
169
170 return out_string
171
172 @header("{: <20s} {: <20s} {: <10s}".format("descriptor", "address", "size"))
173 def GetMachMsgOOLDescriptorSummary(desc):
174 """ Returns description for mach_msg_ool_descriptor_t * object
175 """
176 format_string = "{: <#020x} {: <#020x} {: <#010x}"
177 out_string = format_string.format(desc, desc.address, desc.size)
178 return out_string
179
180 @header("{: <20s} {: <8s} {: <20s} {: <10s} {: <20s}".format("kmsgheader", "size", "body", "ds_count", "dsc_head"))
181 def GetKMsgBody(kmsgp, prefix_str=""):
182 """ Routine that prints a complex kmsg's body
183 """
184 kmsghp = kmsgp.ikm_header
185 kmsgh = dereference(kmsghp)
186 format_string = "{: <#020x} {: <#08x} {: <#020x} {: <#010x} {: <#020x}"
187 out_string = ""
188 body = Cast(addressof(kmsghp[1]), 'mach_msg_body_t *')
189 dsc_count = body.msgh_descriptor_count
190
191 dschead = Cast(addressof(body[1]), 'mach_msg_descriptor_t *')
192 out_string += format_string.format(kmsghp, sizeof(dereference(kmsghp)), body, unsigned(dsc_count), dschead)
193
194 for i in range(dsc_count):
195 dsc = dschead[i]
196 out_string += "\n" + prefix_str + "Descriptor: " + xnudefines.mach_msg_type_descriptor_strings[unsigned(dsc.type.type)]
197 if unsigned(dsc.type.type) == 0:
198 # its a port.
199 p = dsc.port.name
200 out_string += " name: {: <#20x}".format(p)
201 elif unsigned(dsc.type.type) in (1,3):
202 # its OOL DESCRIPTOR or OOL VOLATILE DESCRIPTOR
203 ool = dsc.out_of_line
204 out_string += " " + GetMachMsgOOLDescriptorSummary(addressof(ool))
205 return out_string
206
207 def GetKMsgSrc(kmsgp):
208 """ Routine that prints a kmsg's source process and pid details
209 params:
210 kmsgp : core.value representing the given ipc_kmsg_t struct
211 returns:
212 str : string containing the name and pid of the kmsg's source proc
213 """
214 kmsgsrchp = Cast(kmsgp, 'ipc_kmsg_t').ikm_header
215 kmsgpid = int(Cast(kern.GetValueFromAddress(unsigned(kmsgsrchp) + kmsgsrchp.msgh_size, 'uint *')[10], 'pid_t'))
216
217 return "{0:s} ({1:d})".format(GetProcNameForPid(kmsgpid), kmsgpid)
218
219
220 def PrintPortSetMembers(space, setid, show_kmsg_summary):
221 """ Print out the members of a given IPC PSet
222 """
223 num_entries = int(space.is_table_size)
224 is_tableval = space.is_table
225 setid_str = GetWaitqSetidString(setid)
226
227 prefix_str = "{0:<21s}".format(' '*21)
228 once = True
229 verbose = False
230 if config['verbosity'] > vHUMAN:
231 verbose = True
232
233 idx = 0
234 while idx < num_entries:
235 entryval = GetObjectAtIndexFromArray(is_tableval, idx)
236 ie_bits = unsigned(entryval.ie_bits)
237 if not (ie_bits & 0x00180000):
238 # It's a port entry that's _not_ dead
239 portval = Cast(entryval.ie_object, 'ipc_port_t')
240 waitq = addressof(portval.ip_messages.data.port.waitq)
241 psets = GetWaitqSets(addressof(portval.ip_messages.data.port.waitq))
242 for ps in psets:
243 if ps == setid_str:
244 if once:
245 once = False
246 print "{:s}\n{:s}{:s}".format(GetPortDestProc(portval), prefix_str, PrintPortSummary.header)
247 PrintPortSummary(portval, show_kmsg_summary, prefix_str)
248 if verbose:
249 sys.stderr.write('{:d}/{:d}... \r'.format(idx, num_entries))
250 idx += 1
251 return
252
253
254 @header("{0: <20s} {1: <28s} {2: <12s} {3: <6s} {4: <6s} {5: <20s} {6: <7s}\n".format(
255 "portset", "waitqueue", "recvname", "flags", "refs", "recvname", "process"))
256 def PrintPortSetSummary(pset, space = 0):
257 """ Display summary for a given struct ipc_pset *
258 params:
259 pset : core.value representing a pset in the kernel
260 returns:
261 str : string of summary information for the given pset
262 """
263 out_str = ""
264 show_kmsg_summary = False
265 if config['verbosity'] > vHUMAN :
266 show_kmsg_summary = True
267
268 setid = 0
269 if pset.ips_object.io_bits & 0x80000000:
270 setid = pset.ips_messages.data.pset.setq.wqset_id
271 out_str += "{0: #019x} {1: #019x} {2: <7s} {3: #011x} {4: <4s} {5: >6d} {6: #019x} ".format(
272 unsigned(pset), addressof(pset.ips_messages), ' '*7,
273 pset.ips_messages.data.pset.local_name, "ASet",
274 pset.ips_object.io_references,
275 pset.ips_messages.data.pset.local_name)
276
277 else:
278 out_str += "{0: #019x} {1: #019x} {2: <7s} {3: #011x} {4: <4s} {5: >6d} {6: #019x} ".format(
279 unsigned(pset), addressof(pset.ips_messages), ' '*7,
280 pset.ips_messages.data.pset.local_name, "DSet",
281 pset.ips_object.io_references,
282 pset.ips_messages.data.pset.local_name)
283 print out_str
284
285 if setid != 0 and space != 0:
286 PrintPortSetMembers(space, setid, show_kmsg_summary)
287
288 return
289
290 # Macro: showipc
291
292 @lldb_command('showipc')
293 def ShowIPC(cmd_args=None):
294 """ Routine to print data for the given IPC space
295 Usage: showipc <address of ipc space>
296 """
297 if not cmd_args:
298 print "No arguments passed"
299 print ShowIPC.__doc__
300 return False
301 ipc = kern.GetValueFromAddress(cmd_args[0], 'ipc_space *')
302 if not ipc:
303 print "unknown arguments:", str(cmd_args)
304 return False
305 print PrintIPCInformation.header
306 PrintIPCInformation(ipc, False, False)
307
308 # EndMacro: showipc
309
310 # Macro: showtaskipc
311
312 @lldb_command('showtaskipc')
313 def ShowTaskIPC(cmd_args=None):
314 """ Routine to print IPC summary of given task
315 Usage: showtaskipc <address of task>
316 """
317 if not cmd_args:
318 print "No arguments passed"
319 print ShowTaskIPC.__doc__
320 return False
321 tval = kern.GetValueFromAddress(cmd_args[0], 'task *')
322 if not tval:
323 print "unknown arguments:", str(cmd_args)
324 return False
325 print GetTaskSummary.header + " " + GetProcSummary.header
326 pval = Cast(tval.bsd_info, 'proc *')
327 print GetTaskSummary(tval) + " " + GetProcSummary(pval)
328 print GetTaskIPCSummary.header
329 print GetTaskIPCSummary(tval)
330
331 # EndMacro: showtaskipc
332
333 # Macro: showallipc
334
335 @lldb_command('showallipc')
336 def ShowAllIPC(cmd_args=None):
337 """ Routine to print IPC summary of all tasks
338 Usage: showallipc
339 """
340 for t in kern.tasks:
341 print GetTaskSummary.header + " " + GetProcSummary.header
342 pval = Cast(t.bsd_info, 'proc *')
343 print GetTaskSummary(t) + " " + GetProcSummary(pval)
344 print PrintIPCInformation.header
345 PrintIPCInformation(t.itk_space, False, False) + "\n\n"
346
347 # EndMacro: showallipc
348
349 @lldb_command('showipcsummary')
350 def ShowIPCSummary(cmd_args=None):
351 """ Summarizes the IPC state of all tasks.
352 This is a convenient way to dump some basic clues about IPC messaging. You can use the output to determine
353 tasks that are candidates for further investigation.
354 """
355 print GetTaskIPCSummary.header
356 for t in kern.tasks:
357 print GetTaskIPCSummary(t)
358 return
359
360 def GetKObjectFromPort(portval):
361 """ Get Kobject description from the port.
362 params: portval - core.value representation of 'ipc_port *' object
363 returns: str - string of kobject information
364 """
365 kobject_str = "{0: <#020x}".format(portval.kdata.kobject)
366 io_bits = unsigned(portval.ip_object.io_bits)
367 objtype_index = io_bits & 0xfff
368 if objtype_index < len(xnudefines.kobject_types) :
369 objtype_str = xnudefines.kobject_types[objtype_index]
370 if objtype_str == 'IOKIT_OBJ':
371 iokit_classnm = GetObjectTypeStr(portval.kdata.kobject)
372 if not iokit_classnm:
373 iokit_classnm = "<unknown class>"
374 else:
375 iokit_classnm = re.sub(r'vtable for ', r'', iokit_classnm)
376 desc_str = "kobject({:s}:{:s})".format(objtype_str, iokit_classnm)
377 else:
378 desc_str = "kobject({0:s})".format(objtype_str)
379 if xnudefines.kobject_types[objtype_index] in ('TASK_RESUME', 'TASK'):
380 desc_str += " " + GetProcNameForTask(Cast(portval.kdata.kobject, 'task *'))
381 else:
382 desc_str = "kobject(UNKNOWN) {:d}".format(objtype_index)
383 return kobject_str + " " + desc_str
384
385 @static_var('destcache', {})
386 def GetDestinationProcessFromPort(port):
387 """
388 params: port - core.value representation of 'ipc_port *' object
389 returns: str - name of process
390 """
391 out_str = ''
392 dest_space = port.data.receiver
393 found_dest = False
394 #update destcache if data is not found
395 if hex(dest_space) not in GetDestinationProcessFromPort.destcache:
396 for t in kern.tasks:
397 if hex(t.itk_space) == hex(dest_space):
398 pval = Cast(t.bsd_info, 'proc *')
399 GetDestinationProcessFromPort.destcache[hex(dest_space)] = (t, pval)
400 found_dest = True
401 break
402 #end of for loop
403 else: found_dest = True
404
405 if found_dest:
406 (ftask , fproc) = GetDestinationProcessFromPort.destcache[hex(dest_space)]
407 if fproc:
408 out_str = "{0:s}({1:d})".format(fproc.p_comm, fproc.p_pid )
409 else:
410 out_str = "task {0: <#020x}".format(ftask)
411 return out_str
412
413
414
415 @header("{0: <20s} {1: <20s}".format("destname", "destination") )
416 def GetPortDestinationSummary(port):
417 """ Get destination information for a port.
418 params: port - core.value representation of 'ipc_port *' object
419 returns: str - string of info about ports destination
420 """
421 out_str = ''
422 format_string = "{0: <20s} {1: <20s}"
423 destname_str = ''
424 destination_str = ''
425 ipc_space_kernel = unsigned(kern.globals.ipc_space_kernel)
426 target_spaceval = port.data.receiver
427 if unsigned(target_spaceval) == ipc_space_kernel :
428 destname_str = GetKObjectFromPort(port)
429 else:
430 if int(port.ip_object.io_bits) & 0x80000000 :
431 destname_str = "{0: <#020x}".format(port.ip_messages.data.port.receiver_name)
432 destination_str = GetDestinationProcessFromPort(port)
433 else:
434 destname_str = "{0: <#020x}".format(port)
435 destination_str = "inactive-port"
436
437 out_str += format_string.format(destname_str, destination_str)
438 return out_str
439
440 @lldb_type_summary(['ipc_entry_t'])
441 @header("{: <20s} {: <20s} {: <8s} {: <8s} {: <8s} {: <8s} {: <20s} {: <20s}".format("object", "name","rite", "urefs", "nsets", "nmsgs", "destname", "destination"))
442 def GetIPCEntrySummary(entry, ipc_name='', rights_filter=0):
443 """ Get summary of a ipc entry.
444 params:
445 entry - core.value representing ipc_entry_t in the kernel
446 ipc_name - str of format '0x0123' for display in summary.
447 returns:
448 str - string of ipc entry related information
449
450 types of rights:
451 'Dead' : Dead name
452 'Set' : Port set
453 'S' : Send right
454 'R' : Receive right
455 'O' : Send-once right
456 types of notifications:
457 's' : Send-Possible notification armed
458 'd' : Send-Possible notification requested
459 'n' : Dead-Name notification requested
460 'c' : ???
461 'x' : No-Senders notification requested
462 """
463 out_str = ''
464 entry_ptr = int(hex(entry), 16)
465 format_string = "{: <#020x} {: <12s} {: <8s} {: <8d} {: <8d} {: <8d} {: <20s} {: <20s}"
466 right_str = ''
467 destname_str = ''
468 destination_str = ''
469
470 ie_object = entry.ie_object
471 ie_bits = int(entry.ie_bits)
472 urefs = int(ie_bits & 0xffff)
473 nsets = 0
474 nmsgs = 0
475 if ie_bits & 0x00100000 :
476 right_str = 'Dead'
477 elif ie_bits & 0x00080000:
478 right_str = 'Set'
479 psetval = Cast(ie_object, 'ipc_pset *')
480 set_str = GetWaitqSets(addressof(psetval.ips_messages.data.pset.setq.wqset_q))
481 nsets = len(set_str)
482 nmsgs = 0
483 else:
484 if ie_bits & 0x00010000 :
485 if ie_bits & 0x00020000 :
486 # SEND + RECV
487 right_str = 'SR'
488 else:
489 # SEND only
490 right_str = 'S'
491 elif ie_bits & 0x00020000:
492 # RECV only
493 right_str = 'R'
494 elif ie_bits & 0x00040000 :
495 # SEND_ONCE
496 right_str = 'O'
497 portval = Cast(ie_object, 'ipc_port_t')
498 if int(entry.index.request) != 0:
499 requestsval = portval.ip_requests
500 sorightval = requestsval[int(entry.index.request)].notify.port
501 soright_ptr = unsigned(sorightval)
502 if soright_ptr != 0:
503 # send-possible armed
504 if soright_ptr & 0x1 : right_str +='s'
505 # send-possible requested
506 elif soright_ptr & 0x2 : right_str +='d'
507 # dead-name notification requested
508 else : right_str +='n'
509 # XXX: What does this bit mean?
510 if ie_bits & 0x00800000 : right_str +='c'
511 # No-senders notification requested
512 if portval.ip_nsrequest != 0: right_str +='x'
513 # now show the port destination part
514 destname_str = GetPortDestinationSummary(Cast(ie_object, 'ipc_port_t'))
515 # Get the number of sets to which this port belongs
516 set_str = GetWaitqSets(addressof(portval.ip_messages.data.port.waitq))
517 nsets = len(set_str)
518 nmsgs = portval.ip_messages.data.port.msgcount
519 if rights_filter == 0 or rights_filter == right_str:
520 out_str = format_string.format(ie_object, ipc_name, right_str, urefs, nsets, nmsgs, destname_str, destination_str)
521 return out_str
522
523 @header("{0: >20s}".format("user bt") )
524 def GetPortUserStack(port, task):
525 """ Get UserStack information for the given port & task.
526 params: port - core.value representation of 'ipc_port *' object
527 task - value representing 'task *' object
528 returns: str - string information on port's userstack
529 """
530 out_str = ''
531 ie_port_callstack = port.ip_callstack
532 ie_port_spares = port.ip_spares[0]
533 proc_val = Cast(task.bsd_info, 'proc *')
534 if ie_port_callstack[0]:
535 out_str += "{: <10x}".format(ie_port_callstack[0])
536 count = 1
537 while count < 16 and ie_port_callstack[count]:
538 out_str += ": <10x".format(ie_port_callstack[count])
539 count = count + 1
540 if ie_port_spares != proc_val.p_pid:
541 out_str += " ({:<10d})".format(ie_port_spares)
542 out_str += '\n'
543 return out_str
544
545 @lldb_type_summary(['ipc_space *'])
546 @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'))
547 def PrintIPCInformation(space, show_entries=False, show_userstack=False, rights_filter=0):
548 """ Provide a summary of the ipc space
549 """
550 out_str = ''
551 format_string = "{0: <#020x} {1: <#020x} {2: <#020x} {3: <8s} {4: <10d} {5: <#18x} {6: >8d} {7: <8d}"
552 is_tableval = space.is_table
553 ports = int(space.is_table_size)
554 flags =''
555 is_bits = int(space.is_bits)
556 if (is_bits & 0x40000000) == 0: flags +='A'
557 else: flags += ' '
558 if (is_bits & 0x20000000) != 0: flags +='G'
559 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)
560
561 #should show the each individual entries if asked.
562 if show_entries == True:
563 print "\t" + GetIPCEntrySummary.header
564 num_entries = ports
565 index = 0
566 while index < num_entries:
567 entryval = GetObjectAtIndexFromArray(is_tableval, index)
568 entry_ie_bits = unsigned(entryval.ie_bits)
569 if (int(entry_ie_bits) & 0x001f0000 ) != 0:
570 entry_name = "{0: <#020x}".format( (index <<8 | entry_ie_bits >> 24) )
571 entry_str = GetIPCEntrySummary(entryval, entry_name, rights_filter)
572 if len(entry_str) > 0:
573 print " \r\t" + entry_str
574 if show_userstack == True:
575 entryport = Cast(entryval.ie_object, 'ipc_port *')
576 if entryval.ie_object and (int(entry_ie_bits) & 0x00070000) and entryport.ip_callstack[0]:
577 print GetPortUserStack.header + GetPortUserStack(entryport, space.is_task)
578 else:
579 # give some progress indication (this is especially
580 # helpful for tasks with large sets of rights)
581 sys.stderr.write(' {:d}/{:d}...\r'.format(index, num_entries))
582 index += 1
583 #done with showing entries
584 return out_str
585
586 # Macro: showrights
587
588 @lldb_command('showrights', 'R:')
589 def ShowRights(cmd_args=None, cmd_options={}):
590 """ Routine to print rights information for the given IPC space
591 Usage: showrights [-R rights_type] <address of ipc space>
592 -R rights_type : only display rights matching the string 'rights_type'
593
594 types of rights:
595 'Dead' : Dead name
596 'Set' : Port set
597 'S' : Send right
598 'R' : Receive right
599 'O' : Send-once right
600 types of notifications (append to rights type string):
601 's' : Send-Possible notification armed
602 'd' : Send-Possible notification requested
603 'n' : Dead-Name notification requested
604 'c' : ???
605 'x' : No-Senders notification requested
606 """
607 if not cmd_args:
608 print "No arguments passed"
609 print ShowRights.__doc__
610 return False
611 ipc = kern.GetValueFromAddress(cmd_args[0], 'ipc_space *')
612 if not ipc:
613 print "unknown arguments:", str(cmd_args)
614 return False
615 rights_type = 0
616 if "-R" in cmd_options:
617 rights_type = cmd_options["-R"]
618 print PrintIPCInformation.header
619 PrintIPCInformation(ipc, True, False, rights_type)
620
621 # EndMacro: showrights
622
623 @lldb_command('showtaskrights','R:')
624 def ShowTaskRights(cmd_args=None, cmd_options={}):
625 """ Routine to ipc rights information for a task
626 Usage: showtaskrights [-R rights_type] <task address>
627 -R rights_type : only display rights matching the string 'rights_type'
628
629 types of rights:
630 'Dead' : Dead name
631 'Set' : Port set
632 'S' : Send right
633 'R' : Receive right
634 'O' : Send-once right
635 types of notifications (append to rights type string):
636 's' : Send-Possible notification armed
637 'd' : Send-Possible notification requested
638 'n' : Dead-Name notification requested
639 'c' : ???
640 'x' : No-Senders notification requested
641 """
642 if cmd_args == None:
643 print "No arguments passed"
644 print ShowTaskStacksCmdHelper.__doc__
645 return False
646 tval = kern.GetValueFromAddress(cmd_args[0], 'task *')
647 if not tval:
648 print "unknown arguments:", str(cmd_args)
649 return False
650 rights_type = 0
651 if "-R" in cmd_options:
652 rights_type = cmd_options["-R"]
653 print GetTaskSummary.header + " " + GetProcSummary.header
654 pval = Cast(tval.bsd_info, 'proc *')
655 print GetTaskSummary(tval) + " " + GetProcSummary(pval)
656 print PrintIPCInformation.header
657 PrintIPCInformation(tval.itk_space, True, False, rights_type)
658
659 # Macro: showataskrightsbt
660
661 @lldb_command('showtaskrightsbt', 'R:')
662 def ShowTaskRightsBt(cmd_args=None, cmd_options={}):
663 """ Routine to ipc rights information with userstacks for a task
664 Usage: showtaskrightsbt [-R rights_type] <task address>
665 -R rights_type : only display rights matching the string 'rights_type'
666
667 types of rights:
668 'Dead' : Dead name
669 'Set' : Port set
670 'S' : Send right
671 'R' : Receive right
672 'O' : Send-once right
673 types of notifications (append to rights type string):
674 's' : Send-Possible notification armed
675 'd' : Send-Possible notification requested
676 'n' : Dead-Name notification requested
677 'c' : ???
678 'x' : No-Senders notification requested
679 """
680 if cmd_args == None:
681 print "No arguments passed"
682 print ShowTaskRightsBt.__doc__
683 return False
684 tval = kern.GetValueFromAddress(cmd_args[0], 'task *')
685 if not tval:
686 print "unknown arguments:", str(cmd_args)
687 return False
688 rights_type = 0
689 if "-R" in cmd_options:
690 rights_type = cmd_options["-R"]
691 print GetTaskSummary.header + " " + GetProcSummary.header
692 pval = Cast(tval.bsd_info, 'proc *')
693 print GetTaskSummary(tval) + " " + GetProcSummary(pval)
694 print PrintIPCInformation.header
695 PrintIPCInformation(tval.itk_space, True, True, rights_type)
696
697 # EndMacro: showtaskrightsbt
698
699 # Macro: showallrights
700
701 @lldb_command('showallrights', 'R:')
702 def ShowAllRights(cmd_args=None, cmd_options={}):
703 """ Routine to print rights information for IPC space of all tasks
704 Usage: showallrights [-R rights_type]
705 -R rights_type : only display rights matching the string 'rights_type'
706
707 types of rights:
708 'Dead' : Dead name
709 'Set' : Port set
710 'S' : Send right
711 'R' : Receive right
712 'O' : Send-once right
713 types of notifications (append to rights type string):
714 's' : Send-Possible notification armed
715 'd' : Send-Possible notification requested
716 'n' : Dead-Name notification requested
717 'c' : ???
718 'x' : No-Senders notification requested
719 """
720 rights_type = 0
721 if "-R" in cmd_options:
722 rights_type = cmd_options["-R"]
723 for t in kern.tasks:
724 print GetTaskSummary.header + " " + GetProcSummary.header
725 pval = Cast(t.bsd_info, 'proc *')
726 print GetTaskSummary(t) + " " + GetProcSummary(pval)
727 try:
728 print PrintIPCInformation.header
729 PrintIPCInformation(t.itk_space, True, False, rights_type) + "\n\n"
730 except (KeyboardInterrupt, SystemExit):
731 raise
732 except:
733 print "Failed to get IPC information. Do individual showtaskrights <task> to find the error. \n\n"
734
735 # EndMacro: showallrights
736
737 # Macro: showpipestats
738 @lldb_command('showpipestats')
739 def ShowPipeStats(cmd_args=None):
740 """ Display pipes usage information in the kernel
741 """
742 print "Number of pipes: {: d}".format(kern.globals.amountpipes)
743 print "Memory used by pipes: {:s}".format(sizeof_fmt(int(kern.globals.amountpipekva)))
744 print "Max memory allowed for pipes: {:s}".format(sizeof_fmt(int(kern.globals.maxpipekva)))
745 # EndMacro: showpipestats
746
747 # Macro: showtaskbusyports
748 @lldb_command('showtaskbusyports')
749 def ShowTaskBusyPorts(cmd_args=None):
750 """ Routine to print information about receive rights belonging to this task that
751 have enqueued messages. This is oten a sign of a blocked or hung process
752 Usage: showtaskbusyports <task address>
753 """
754 if not cmd_args:
755 print "No arguments passed. Please pass in the address of a task"
756 print ShowTaskBusyPorts.__doc__
757 return
758 task = kern.GetValueFromAddress(cmd_args[0], 'task_t')
759 PrintTaskBusyPorts(task)
760 return
761
762 def PrintTaskBusyPorts(task):
763 """ Prints all busy ports for a given task. ie. all receive rights belonging
764 to this task that have enqueued messages.
765 params:
766 task : core.value representing a task in kernel
767 returns:
768 str : String containing information about the given task's busy ports
769 """
770 isp = task.itk_space
771 i = 0
772 while i < isp.is_table_size:
773 iep = addressof(isp.is_table[i])
774 if iep.ie_bits & 0x00020000:
775 port = Cast(iep.ie_object, 'ipc_port_t')
776 if port.ip_messages.data.port.msgcount > 0:
777 print PrintPortSummary.header
778 PrintPortSummary(port)
779 i = i + 1
780 return
781 # EndMacro: showtaskbusyports
782
783 # Macro: showallbusyports
784 @lldb_command('showallbusyports')
785 def ShowAllBusyPorts(cmd_args=None):
786 """ Routine to print information about all receive rights on the system that
787 have enqueued messages.
788 """
789 task_queue_head = kern.globals.tasks
790
791 for tsk in kern.tasks:
792 PrintTaskBusyPorts(tsk)
793 return
794 # EndMacro: showallbusyports
795
796 # Macro: showport:
797 @lldb_command('showport','K')
798 def ShowPort(cmd_args=None, cmd_options={}):
799 """ Routine that lists details about a given IPC port
800 Syntax: (lldb) showport 0xaddr
801 """
802 show_kmsgs = True
803 if "-K" in cmd_options:
804 show_kmsgs = False
805 if not cmd_args:
806 print "Please specify the address of the port whose details you want to print"
807 print ShowPort.__doc__
808 return
809 port = kern.GetValueFromAddress(cmd_args[0], 'struct ipc_port *')
810 print PrintPortSummary.header
811 PrintPortSummary(port, show_kmsgs)
812 # EndMacro: showport
813
814 # Macro: showmqueue:
815 @lldb_command('showmqueue', "S:")
816 def ShowMQueue(cmd_args=None, cmd_options={}):
817 """ Routine that lists details about a given mqueue
818 Syntax: (lldb) showmqueue 0xaddr [-S ipc_space]
819 """
820 if not cmd_args:
821 print "Please specify the address of the ipc_mqueue whose details you want to print"
822 print ShowMQueue.__doc__
823 return
824 space = 0
825 if "-S" in cmd_options:
826 space = kern.GetValueFromAddress(cmd_options["-S"], 'struct ipc_space *')
827 mqueue = kern.GetValueFromAddress(cmd_args[0], 'struct ipc_mqueue *')
828 wq_type = mqueue.data.pset.setq.wqset_q.waitq_type
829 if int(wq_type) == 3:
830 psetoff = getfieldoffset('struct ipc_pset', 'ips_messages')
831 pset = unsigned(ArgumentStringToInt(cmd_args[0])) - unsigned(psetoff)
832 print PrintPortSetSummary.header
833 PrintPortSetSummary(kern.GetValueFromAddress(pset, 'struct ipc_pset *'), space)
834 elif int(wq_type) == 2:
835 portoff = getfieldoffset('struct ipc_port', 'ip_messages')
836 port = unsigned(ArgumentStringToInt(cmd_args[0])) - unsigned(portoff)
837 print PrintPortSummary.header
838 PrintPortSummary(kern.GetValueFromAddress(port, 'struct ipc_port *'))
839 else:
840 print "Invalid mqueue? (waitq type {:d} is invalid)".format(int(wq_type))
841 # EndMacro: showmqueue
842
843 # Macro: showkmsg:
844 @lldb_command('showkmsg')
845 def ShowKMSG(cmd_args=[]):
846 """ Show detail information about a <ipc_kmsg_t> structure
847 Usage: (lldb) showkmsg <ipc_kmsg_t>
848 """
849 if not cmd_args:
850 raise ArgumentError('Invalid arguments')
851 kmsg = kern.GetValueFromAddress(cmd_args[0], 'ipc_kmsg_t')
852 print GetKMsgSummary.header
853 print GetKMsgSummary(kmsg)
854
855 # EndMacro: showkmsg
856
857 # Macro: showpset
858 @lldb_command('showpset', "S:")
859 def ShowPSet(cmd_args=None, cmd_options={}):
860 """ Routine that prints details for a given ipc_pset *
861 Syntax: (lldb) showpset 0xaddr [-S ipc_space]
862 """
863 if not cmd_args:
864 print "Please specify the address of the pset whose details you want to print"
865 print ShowPSet.__doc__
866 return
867 space = 0
868 if "-S" in cmd_options:
869 space = kern.GetValueFromAddress(cmd_options["-S"], 'struct ipc_space *')
870
871 print PrintPortSetSummary.header
872 PrintPortSetSummary(kern.GetValueFromAddress(cmd_args[0], 'ipc_pset *'), space)
873 # EndMacro: showpset
874
875 # IPC importance inheritance related macros.
876
877 @lldb_command('showalliits')
878 def ShowAllIITs(cmd_args=[], cmd_options={}):
879 """ Development only macro. Show list of all iits allocated in the system. """
880 try:
881 iit_queue = kern.globals.global_iit_alloc_queue
882 except ValueError:
883 print "This debug macro is only available in development or debug kernels"
884 return
885
886 print GetIPCImportantTaskSummary.header
887 for iit in IterateQueue(iit_queue, 'struct ipc_importance_task *', 'iit_allocation'):
888 print GetIPCImportantTaskSummary(iit)
889 return
890
891 @header("{: <18s} {: <3s} {: <18s} {: <20s} {: <18s} {: <8s}".format("ipc_imp_inherit", "don", "to_task", "proc_name", "from_elem", "depth"))
892 @lldb_type_summary(['ipc_importance_inherit *', 'ipc_importance_inherit_t'])
893 def GetIPCImportanceInheritSummary(iii):
894 """ describes iii object of type ipc_importance_inherit_t * """
895 out_str = ""
896 fmt = "{o: <#018x} {don: <3s} {o.iii_to_task.iit_task: <#018x} {task_name: <20s} {o.iii_from_elem: <#018x} {o.iii_depth: <#08x}"
897 donating_str = ""
898 if unsigned(iii.iii_donating):
899 donating_str = "DON"
900 taskname = GetProcNameForTask(iii.iii_to_task.iit_task)
901 if hasattr(iii.iii_to_task, 'iit_bsd_pid'):
902 taskname = "({:d}) {:s}".format(iii.iii_to_task.iit_bsd_pid, iii.iii_to_task.iit_procname)
903 out_str += fmt.format(o=iii, task_name = taskname, don=donating_str)
904 return out_str
905
906 @static_var('recursion_count', 0)
907 @header("{: <18s} {: <4s} {: <8s} {: <8s} {: <18s} {: <18s}".format("iie", "type", "refs", "made", "#kmsgs", "#inherits"))
908 @lldb_type_summary(['ipc_importance_elem *'])
909 def GetIPCImportanceElemSummary(iie):
910 """ describes an ipc_importance_elem * object """
911
912 if GetIPCImportanceElemSummary.recursion_count > 500:
913 GetIPCImportanceElemSummary.recursion_count = 0
914 return "Recursion of 500 reached"
915
916 out_str = ''
917 fmt = "{: <#018x} {: <4s} {: <8d} {: <8d} {: <#018x} {: <#018x}"
918 if unsigned(iie.iie_bits) & 0x80000000:
919 type_str = "INH"
920 inherit_count = 0
921 else:
922 type_str = 'TASK'
923 iit = Cast(iie, 'struct ipc_importance_task *')
924 inherit_count = sum(1 for i in IterateQueue(iit.iit_inherits, 'struct ipc_importance_inherit *', 'iii_inheritance'))
925
926 refs = unsigned(iie.iie_bits) & 0x7fffffff
927 made_refs = unsigned(iie.iie_made)
928 kmsg_count = sum(1 for i in IterateQueue(iie.iie_kmsgs, 'struct ipc_kmsg *', 'ikm_inheritance'))
929 out_str += fmt.format(iie, type_str, refs, made_refs, kmsg_count, inherit_count)
930 if config['verbosity'] > vHUMAN:
931 if kmsg_count > 0:
932 out_str += "\n\t"+ GetKMsgSummary.header
933 for k in IterateQueue(iie.iie_kmsgs, 'struct ipc_kmsg *', 'ikm_inheritance'):
934 out_str += "\t" + "{: <#018x}".format(k.ikm_header.msgh_remote_port) + ' ' + GetKMsgSummary(k, "\t").lstrip()
935 out_str += "\n"
936 if inherit_count > 0:
937 out_str += "\n\t" + GetIPCImportanceInheritSummary.header + "\n"
938 for i in IterateQueue(iit.iit_inherits, 'struct ipc_importance_inherit *', 'iii_inheritance'):
939 out_str += "\t" + GetIPCImportanceInheritSummary(i) + "\n"
940 out_str += "\n"
941 if type_str == "INH":
942 iii = Cast(iie, 'struct ipc_importance_inherit *')
943 out_str += "Inherit from: " + GetIPCImportanceElemSummary(iii.iii_from_elem)
944
945 return out_str
946
947 @header("{: <18s} {: <18s} {: <20s}".format("iit", "task", "name"))
948 @lldb_type_summary(['ipc_importance_task *'])
949 def GetIPCImportantTaskSummary(iit):
950 """ iit is a ipc_importance_task value object.
951 """
952 fmt = "{: <#018x} {: <#018x} {: <20s}"
953 out_str=''
954 pname = GetProcNameForTask(iit.iit_task)
955 if hasattr(iit, 'iit_bsd_pid'):
956 pname = "({:d}) {:s}".format(iit.iit_bsd_pid, iit.iit_procname)
957 out_str += fmt.format(iit, iit.iit_task, pname)
958 return out_str
959
960 @lldb_command('showallimportancetasks')
961 def ShowIPCImportanceTasks(cmd_args=[], cmd_options={}):
962 """ display a list of all tasks with ipc importance information.
963 Usage: (lldb) showallimportancetasks
964 Tip: add "-v" to see detailed information on each kmsg or inherit elems
965 """
966 print ' ' + GetIPCImportantTaskSummary.header + ' ' + GetIPCImportanceElemSummary.header
967 for t in kern.tasks:
968 s = ""
969 if unsigned(t.task_imp_base):
970 s += ' ' + GetIPCImportantTaskSummary(t.task_imp_base)
971 s += ' ' + GetIPCImportanceElemSummary(addressof(t.task_imp_base.iit_elem))
972 print s
973
974 @lldb_command('showipcimportance', '')
975 def ShowIPCImportance(cmd_args=[], cmd_options={}):
976 """ Describe an importance from <ipc_importance_elem_t> argument.
977 Usage: (lldb) showimportance <ipc_importance_elem_t>
978 """
979 if not cmd_args:
980 raise ArgumentError("Please provide valid argument")
981
982 elem = kern.GetValueFromAddress(cmd_args[0], 'ipc_importance_elem_t')
983 print GetIPCImportanceElemSummary.header
984 print GetIPCImportanceElemSummary(elem)
985
986 @header("{: <18s} {: <10s} {: <18s} {: <18s} {: <8s} {: <5s} {: <5s} {: <5s}".format("ivac", "refs", "port", "tbl", "tblsize", "index", "Grow", "freelist"))
987 @lldb_type_summary(['ipc_voucher_attr_control *', 'ipc_voucher_attr_control_t'])
988 def GetIPCVoucherAttrControlSummary(ivac):
989 """ describes a voucher attribute control settings """
990 out_str = ""
991 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}"
992 growing_str = ""
993
994 if unsigned(ivac) == 0:
995 return "{: <#018x}".format(ivac)
996
997 if unsigned(ivac.ivac_is_growing):
998 growing_str = "Y"
999 out_str += fmt.format(c=ivac, growing = growing_str)
1000 return out_str
1001
1002 @lldb_command('showivac','')
1003 def ShowIPCVoucherAttributeControl(cmd_args=[], cmd_options={}):
1004 """ Show summary of voucher attribute contols.
1005 Usage: (lldb) showivac <ipc_voucher_attr_control_t>
1006 """
1007 if not cmd_args:
1008 raise ArgumentError("Please provide correct arguments.")
1009 ivac = kern.GetValueFromAddress(cmd_args[0], 'ipc_voucher_attr_control_t')
1010 print GetIPCVoucherAttrControlSummary.header
1011 print GetIPCVoucherAttrControlSummary(ivac)
1012 if config['verbosity'] > vHUMAN:
1013 cur_entry_index = 0
1014 last_entry_index = unsigned(ivac.ivac_table_size)
1015 print "index " + GetIPCVoucherAttributeEntrySummary.header
1016 while cur_entry_index < last_entry_index:
1017 print "{: <5d} ".format(cur_entry_index) + GetIPCVoucherAttributeEntrySummary(addressof(ivac.ivac_table[cur_entry_index]))
1018 cur_entry_index += 1
1019
1020
1021
1022
1023 @header("{: <18s} {: <30s} {: <30s} {: <30s} {: <30s} {: <30s}".format("ivam", "get_value_fn", "extract_fn", "release_value_fn", "command_fn", "release_fn"))
1024 @lldb_type_summary(['ipc_voucher_attr_manager *', 'ipc_voucher_attr_manager_t'])
1025 def GetIPCVoucherAttrManagerSummary(ivam):
1026 """ describes a voucher attribute manager settings """
1027 out_str = ""
1028 fmt = "{: <#018x} {: <30s} {: <30s} {: <30s} {: <30s} {: <30s}"
1029
1030 if unsigned(ivam) == 0 :
1031 return "{: <#018x}".format(ivam)
1032
1033 get_value_fn = kern.Symbolicate(unsigned(ivam.ivam_get_value))
1034 extract_fn = kern.Symbolicate(unsigned(ivam.ivam_extract_content))
1035 release_value_fn = kern.Symbolicate(unsigned(ivam.ivam_release_value))
1036 command_fn = kern.Symbolicate(unsigned(ivam.ivam_command))
1037 release_fn = kern.Symbolicate(unsigned(ivam.ivam_release))
1038 out_str += fmt.format(ivam, get_value_fn, extract_fn, release_value_fn, command_fn, release_fn)
1039 return out_str
1040
1041
1042
1043 @header("{: <18s} {: <10s} {:s} {:s}".format("ivgte", "key", GetIPCVoucherAttrControlSummary.header.strip(), GetIPCVoucherAttrManagerSummary.header.strip()))
1044 @lldb_type_summary(['ipc_voucher_global_table_element *', 'ipc_voucher_global_table_element_t'])
1045 def GetIPCVoucherGlobalTableElementSummary(ivgte):
1046 """ describes a ipc_voucher_global_table_element object """
1047 out_str = ""
1048 fmt = "{g: <#018x} {g.ivgte_key: <10d} {ctrl_s:s} {mgr_s:s}"
1049 out_str += fmt.format(g=ivgte, ctrl_s=GetIPCVoucherAttrControlSummary(ivgte.ivgte_control), mgr_s=GetIPCVoucherAttrManagerSummary(ivgte.ivgte_manager))
1050 return out_str
1051
1052 @lldb_command('showglobalvouchertable', '')
1053 def ShowGlobalVoucherTable(cmd_args=[], cmd_options={}):
1054 """ show detailed information of all voucher attribute managers registered with vouchers system
1055 Usage: (lldb) showglobalvouchertable
1056 """
1057 entry_size = sizeof(kern.globals.iv_global_table[0])
1058 elems = sizeof(kern.globals.iv_global_table) / entry_size
1059 print GetIPCVoucherGlobalTableElementSummary.header
1060 for i in range(elems):
1061 elt = addressof(kern.globals.iv_global_table[i])
1062 print GetIPCVoucherGlobalTableElementSummary(elt)
1063
1064 # Type summaries for Bag of Bits.
1065
1066 @lldb_type_summary(['user_data_value_element', 'user_data_element_t'])
1067 @header("{0: <20s} {1: <16s} {2: <20s} {3: <20s} {4: <16s} {5: <20s}".format("user_data_ve", "maderefs", "checksum", "hash value", "size", "data"))
1068 def GetBagofBitsElementSummary(data_element):
1069 """ Summarizes the Bag of Bits element
1070 params: data_element = value of the object of type user_data_value_element_t
1071 returns: String with summary of the type.
1072 """
1073 format_str = "{0: <#020x} {1: <16d} {2: <#020x} {3: <#020x} {4: <16d}"
1074 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))
1075 out_string += " 0x"
1076
1077 for i in range(0, (unsigned(data_element.e_size) - 1)):
1078 out_string += "{:02x}".format(int(data_element.e_data[i]))
1079 return out_string
1080
1081 def GetIPCHandleSummary(handle_ptr):
1082 """ converts a handle value inside a voucher attribute table to ipc element and returns appropriate summary.
1083 params: handle_ptr - uint64 number stored in handle of voucher.
1084 returns: str - string summary of the element held in internal structure
1085 """
1086 elem = kern.GetValueFromAddress(handle_ptr, 'ipc_importance_elem_t')
1087 if elem.iie_bits & 0x80000000 :
1088 iie = Cast(elem, 'struct ipc_importance_inherit *')
1089 return GetIPCImportanceInheritSummary(iie)
1090 else:
1091 iit = Cast(elem, 'struct ipc_importance_task *')
1092 return GetIPCImportantTaskSummary(iit)
1093
1094 def GetATMHandleSummary(handle_ptr):
1095 """ Convert a handle value to atm value and returns corresponding summary of its fields.
1096 params: handle_ptr - uint64 number stored in handle of voucher
1097 returns: str - summary of atm value
1098 """
1099 elem = kern.GetValueFromAddress(handle_ptr, 'atm_value *')
1100 return GetATMValueSummary(elem)
1101
1102 def GetBankHandleSummary(handle_ptr):
1103 """ converts a handle value inside a voucher attribute table to bank element and returns appropriate summary.
1104 params: handle_ptr - uint64 number stored in handle of voucher.
1105 returns: str - summary of bank element
1106 """
1107 if handle_ptr == 1 :
1108 return "Bank task of Current task"
1109 elem = kern.GetValueFromAddress(handle_ptr, 'bank_element_t')
1110 if elem.be_type & 1 :
1111 ba = Cast(elem, 'struct bank_account *')
1112 return GetBankAccountSummary(ba)
1113 else:
1114 bt = Cast(elem, 'struct bank_task *')
1115 return GetBankTaskSummary(bt)
1116
1117 def GetBagofBitsHandleSummary(handle_ptr):
1118 """ Convert a handle value to bag of bits value and returns corresponding summary of its fields.
1119 params: handle_ptr - uint64 number stored in handle of voucher
1120 returns: str - summary of bag of bits element
1121 """
1122 elem = kern.GetValueFromAddress(handle_ptr, 'user_data_element_t')
1123 return GetBagofBitsElementSummary(elem)
1124
1125 @static_var('attr_managers',{1: GetATMHandleSummary, 2: GetIPCHandleSummary, 3: GetBankHandleSummary, 7: GetBagofBitsHandleSummary})
1126 def GetHandleSummaryForKey(handle_ptr, key_num):
1127 """ Get a summary of handle pointer from the voucher attribute manager.
1128 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.
1129 key 2 -> ipc and it puts either ipc_importance_inherit_t or ipc_important_task_t.
1130 key 3 -> Bank and it puts either bank_task_t or bank_account_t.
1131 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.
1132 """
1133 key_num = int(key_num)
1134 if key_num not in GetHandleSummaryForKey.attr_managers:
1135 return "Unknown key %d" % key_num
1136 return GetHandleSummaryForKey.attr_managers[key_num](handle_ptr)
1137
1138
1139 @header("{: <18s} {: <18s} {: <10s} {: <4s} {: <18s} {: <18s}".format("ivace", "value_handle", "#refs", "rel?", "maderefs", "next_layer"))
1140 @lldb_type_summary(['ivac_entry *', 'ivac_entry_t'])
1141 def GetIPCVoucherAttributeEntrySummary(ivace, manager_key_num = 0):
1142 """ Get summary for voucher attribute entry.
1143 """
1144 out_str = ""
1145 fmt = "{e: <#018x} {e.ivace_value: <#018x} {e.ivace_refs: <10d} {release: <4s} {made_refs: <18s} {next_layer: <18s}"
1146 release_str = ""
1147 free_str = ""
1148 made_refs = ""
1149 next_layer = ""
1150
1151 if unsigned(ivace.ivace_releasing):
1152 release_str = "Y"
1153 if unsigned(ivace.ivace_free):
1154 free_str = 'F'
1155 if unsigned(ivace.ivace_layered):
1156 next_layer = "{: <#018x}".format(ivace.ivace_u.ivaceu_layer)
1157 else:
1158 made_refs = "{: <18d}".format(ivace.ivace_u.ivaceu_made)
1159
1160 out_str += fmt.format(e=ivace, release=release_str, made_refs=made_refs, next_layer=next_layer)
1161 if config['verbosity'] > vHUMAN and manager_key_num > 0:
1162 out_str += " " + GetHandleSummaryForKey(unsigned(ivace.ivace_value), manager_key_num)
1163 if config['verbosity'] > vHUMAN :
1164 out_str += ' {: <2s} {: <4d} {: <4d}'.format(free_str, ivace.ivace_next, ivace.ivace_index)
1165 return out_str
1166
1167 @lldb_command('showivacfreelist','')
1168 def ShowIVACFreeList(cmd_args=[], cmd_options={}):
1169 """ Walk the free list and print every entry in the list.
1170 usage: (lldb) showivacfreelist <ipc_voucher_attr_control_t>
1171 """
1172 if not cmd_args:
1173 raise ArgumentError('Please provide <ipc_voucher_attr_control_t>')
1174 ivac = kern.GetValueFromAddress(cmd_args[0], 'ipc_voucher_attr_control_t')
1175 print GetIPCVoucherAttrControlSummary.header
1176 print GetIPCVoucherAttrControlSummary(ivac)
1177 if unsigned(ivac.ivac_freelist) == 0:
1178 print "ivac table is full"
1179 return
1180 print "index " + GetIPCVoucherAttributeEntrySummary.header
1181 next_free = unsigned(ivac.ivac_freelist)
1182 while next_free != 0:
1183 print "{: <5d} ".format(next_free) + GetIPCVoucherAttributeEntrySummary(addressof(ivac.ivac_table[next_free]))
1184 next_free = unsigned(ivac.ivac_table[next_free].ivace_next)
1185
1186
1187
1188 @header('{: <18s} {: <8s} {: <18s} {: <18s} {: <18s} {: <18s} {: <18s}'.format("ipc_voucher", "refs", "checksum", "hash", "tbl_size", "table", "voucher_port"))
1189 @lldb_type_summary(['ipc_voucher *', 'ipc_voucher_t'])
1190 def GetIPCVoucherSummary(voucher, show_entries=False):
1191 """ describe a voucher from its ipc_voucher * object """
1192 out_str = ""
1193 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}"
1194 out_str += fmt.format(v = voucher)
1195 entries_str = ''
1196 if show_entries or config['verbosity'] > vHUMAN:
1197 elems = unsigned(voucher.iv_table_size)
1198 entries_header_str = "\n\t" + "{: <5s} {: <3s} {: <16s} {: <30s}".format("index", "key", "value_index", "manager") + " " + GetIPCVoucherAttributeEntrySummary.header
1199 fmt = "{: <5d} {: <3d} {: <16d} {: <30s}"
1200 for i in range(elems):
1201 voucher_entry_index = unsigned(voucher.iv_inline_table[i])
1202 if voucher_entry_index:
1203 s = fmt.format(i, GetVoucherManagerKeyForIndex(i), voucher_entry_index, GetVoucherAttributeManagerNameForIndex(i))
1204 e = GetVoucherValueHandleFromVoucherForIndex(voucher, i)
1205 if e is not None:
1206 s += " " + GetIPCVoucherAttributeEntrySummary(addressof(e), GetVoucherManagerKeyForIndex(i) )
1207 if entries_header_str :
1208 entries_str = entries_header_str
1209 entries_header_str = ''
1210 entries_str += "\n\t" + s
1211 if not entries_header_str:
1212 entries_str += "\n\t"
1213 out_str += entries_str
1214 return out_str
1215
1216 def GetVoucherManagerKeyForIndex(idx):
1217 """ Returns key number for index based on global table. Will raise index error if value is incorrect
1218 """
1219 return unsigned(kern.globals.iv_global_table[idx].ivgte_key)
1220
1221 def GetVoucherAttributeManagerForKey(k):
1222 """ Walks through the iv_global_table and finds the attribute manager name
1223 params: k - int key number of the manager
1224 return: cvalue - the attribute manager object.
1225 None - if not found
1226 """
1227 retval = None
1228 entry_size = sizeof(kern.globals.iv_global_table[0])
1229 elems = sizeof(kern.globals.iv_global_table) / entry_size
1230 for i in range(elems):
1231 elt = addressof(kern.globals.iv_global_table[i])
1232 if k == unsigned(elt.ivgte_key):
1233 retval = elt.ivgte_manager
1234 break
1235 return retval
1236
1237 def GetVoucherAttributeControllerForKey(k):
1238 """ Walks through the iv_global_table and finds the attribute controller
1239 params: k - int key number of the manager
1240 return: cvalue - the attribute controller object.
1241 None - if not found
1242 """
1243 retval = None
1244 entry_size = sizeof(kern.globals.iv_global_table[0])
1245 elems = sizeof(kern.globals.iv_global_table) / entry_size
1246 for i in range(elems):
1247 elt = addressof(kern.globals.iv_global_table[i])
1248 if k == unsigned(elt.ivgte_key):
1249 retval = elt.ivgte_control
1250 break
1251 return retval
1252
1253
1254 def GetVoucherAttributeManagerName(ivam):
1255 """ find the name of the ivam object
1256 param: ivam - cvalue object of type ipc_voucher_attr_manager_t
1257 returns: str - name of the manager
1258 """
1259 return kern.Symbolicate(unsigned(ivam))
1260
1261 def GetVoucherAttributeManagerNameForIndex(idx):
1262 """ get voucher attribute manager name for index
1263 return: str - name of the attribute manager object
1264 """
1265 return GetVoucherAttributeManagerName(GetVoucherAttributeManagerForKey(GetVoucherManagerKeyForIndex(idx)))
1266
1267 def GetVoucherValueHandleFromVoucherForIndex(voucher, idx):
1268 """ traverse the voucher attrs and get value_handle in the voucher attr controls table
1269 params:
1270 voucher - cvalue object of type ipc_voucher_t
1271 idx - int index in the entries for which you wish to get actual handle for
1272 returns: cvalue object of type ivac_entry_t
1273 None if no handle found.
1274 """
1275 manager_key = GetVoucherManagerKeyForIndex(idx)
1276 voucher_num_elems = unsigned(voucher.iv_table_size)
1277 if idx >= voucher_num_elems:
1278 debuglog("idx %d is out of range max: %d" % (idx, voucher_num_elems))
1279 return None
1280 voucher_entry_value = unsigned(voucher.iv_inline_table[idx])
1281 debuglog("manager_key %d" % manager_key)
1282 ivac = GetVoucherAttributeControllerForKey(manager_key)
1283 if ivac is None or unsigned(ivac) == 0:
1284 debuglog("No voucher attribute controller for idx %d" % idx)
1285 return None
1286
1287 ivac = kern.GetValueFromAddress(unsigned(ivac), 'ipc_voucher_attr_control_t') # ??? No idea why lldb does not addressof directly
1288 ivace_table = ivac.ivac_table
1289 if voucher_entry_value >= unsigned(ivac.ivac_table_size):
1290 print "Failed to get ivace for value %d in table of size %d" % (voucher_entry_value, unsigned(ivac.ivac_table_size))
1291 return None
1292 return ivace_table[voucher_entry_value]
1293
1294
1295
1296 @lldb_command('showallvouchers')
1297 def ShowAllVouchers(cmd_args=[], cmd_options={}):
1298 """ Display a list of all vouchers in the global voucher hash table
1299 Usage: (lldb) showallvouchers
1300 """
1301 iv_hash_table = kern.globals.ivht_bucket
1302 num_buckets = sizeof(kern.globals.ivht_bucket) / sizeof(kern.globals.ivht_bucket[0])
1303 print GetIPCVoucherSummary.header
1304 for i in range(num_buckets):
1305 for v in IterateQueue(iv_hash_table[i], 'ipc_voucher_t', 'iv_hash_link'):
1306 print GetIPCVoucherSummary(v)
1307
1308 @lldb_command('showvoucher', '')
1309 def ShowVoucher(cmd_args=[], cmd_options={}):
1310 """ Describe a voucher from <ipc_voucher_t> argument.
1311 Usage: (lldb) showvoucher <ipc_voucher_t>
1312 """
1313 if not cmd_args:
1314 raise ArgumentError("Please provide valid argument")
1315
1316 voucher = kern.GetValueFromAddress(cmd_args[0], 'ipc_voucher_t')
1317 print GetIPCVoucherSummary.header
1318 print GetIPCVoucherSummary(voucher, show_entries=True)
1319
1320 def GetSpaceSendRightEntries(space, port):
1321 """ Get entry summaries for all send rights to port address in an IPC space.
1322 params:
1323 space - the IPC space to search for send rights
1324 port_addr - the port address to match, or 0 to get all send rights
1325 returns: an array of IPC entries
1326 """
1327 entry_table = space.is_table
1328 ports = int(space.is_table_size)
1329 i = 0
1330 entries = []
1331
1332 while i < ports:
1333 entry = GetObjectAtIndexFromArray(entry_table, i)
1334
1335 entry_ie_bits = unsigned(entry.ie_bits)
1336 if (entry_ie_bits & 0x00010000) != 0 and (not port or entry.ie_object == port):
1337 entries.append(entry)
1338 i += 1
1339
1340 return entries
1341
1342 @lldb_command('showportsendrights')
1343 def ShowPortSendRights(cmd_args=[], cmd_options={}):
1344 """ Display a list of send rights across all tasks for a given port.
1345 Usage: (lldb) showportsendrights <ipc_port_t>
1346 """
1347 if not cmd_args:
1348 raise ArgumentError("no port address provided")
1349 port = kern.GetValueFromAddress(cmd_args[0], 'struct ipc_port *')
1350 i = 1
1351
1352 for t in kern.tasks:
1353 # Write a progress line. Using stderr avoids automatic newline when
1354 # writing to stdout from lldb. Blank spaces at the end clear out long
1355 # lines.
1356 sys.stderr.write("checking {:s} ({}/{})...{:30s}\r".format(Cast(t.bsd_info, 'proc_t').p_name, i, len(kern.tasks), ''))
1357 i += 1
1358 entries = GetSpaceSendRightEntries(t.itk_space, port)
1359
1360 if entries:
1361 print GetTaskIPCSummary.header
1362 print GetTaskIPCSummary(t)
1363 print '\t' + GetIPCEntrySummary.header
1364
1365 for entry in entries:
1366 print "\t" + GetIPCEntrySummary(entry)
1367
1368 @lldb_command('showtasksuspenders')
1369 def ShowTaskSuspenders(cmd_args=[], cmd_options={}):
1370 """ Display the tasks and send rights that are holding a target task suspended.
1371 Usage: (lldb) showtasksuspenders <task_t>
1372 """
1373 if not cmd_args:
1374 raise ArgumentError("no task address provided")
1375 task = kern.GetValueFromAddress(cmd_args[0], 'task_t')
1376
1377 if task.suspend_count == 0:
1378 print "task {:#x} ({:s}) is not suspended".format(unsigned(task), Cast(task.bsd_info, 'proc_t').p_name)
1379 return
1380
1381 # If the task has been suspended by the kernel (potentially by
1382 # kperf, using task_suspend_internal) or a client of task_suspend2
1383 # that does not convert its task suspension token to a port using
1384 # convert_task_suspension_token_to_port, then it's impossible to determine
1385 # which task did the suspension.
1386 port = task.itk_resume
1387 if not port:
1388 print "task {:#x} ({:s}) is suspended but no resume port exists".format(unsigned(task), Cast(task.bsd_info, 'proc_t').p_name)
1389 return
1390
1391 return ShowPortSendRights(cmd_args=[unsigned(port)], cmd_options=cmd_options)