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