]>
git.saurik.com Git - apple/xnu.git/blob - tools/lldbmacros/waitq.py
3 from core
.configuration
import *
7 def GetWaitqStateStr(waitq
):
14 return wq_types
[int(waitq
.waitq_type
)]
16 def GetWaitqBitsStr(waitq
):
18 if (Cast(waitq
.waitq_interlock
, 'int') != 0):
25 if waitq
.waitq_prepost
:
31 def WaitqTableElemType(e
):
32 type = (e
.wqte
.lt_bits
>> 29) & 0x3
41 def WaitqTableElemId(e
):
42 return e
.wqte
.lt_id
.id
44 def WaitqTableElemValid(e
):
47 return (e
.wqte
.lt_bits
& 0x80000000) == 0x80000000
49 def WaitqTableElemRefcnt(e
):
50 return (e
.wqte
.lt_bits
& 0x1fffffff)
52 def WaitqTableIdxFromId(id):
53 if hasattr(kern
.globals, 'g_lt_idx_max'):
54 idx
= id & unsigned(kern
.globals.g_lt_idx_max
)
57 idx
= id & 0x000000000003ffff
60 def WaitqTableGenFromId(id):
61 if hasattr(kern
.globals, 'g_lt_idx_max'):
62 msk
= ~
unsigned(kern
.globals.g_lt_idx_max
)
65 msk
= ~
0x000000000003ffff
67 while (msk
& 0x1) == 0:
70 return (unsigned(id) >> shift
) & msk
74 return 0, "NULL link id"
75 idx
= WaitqTableIdxFromId(id)
76 if idx
>= kern
.globals.g_wqlinktable
.nelem
:
77 return 0, "Invalid waitq link table id: {:d}".format(id)
78 slab_slot
= idx
/ kern
.globals.g_wqlinktable
.slab_elem
;
79 slab
= kern
.globals.g_wqlinktable
.table
[int(slab_slot
)]
81 print "Invalid waitq link table id:", str(id), " (invalid slab)"
82 first_elem
= Cast(slab
, 'lt_elem *')
83 addr
= int(slab
) + ((idx
- first_elem
.lt_id
.idx
) * int(kern
.globals.g_wqlinktable
.elem_sz
))
84 link
= kern
.GetValueFromAddress(addr
, 'waitq_link *')
85 gen
= WaitqTableGenFromId(id)
87 if gen
> 0 and link
.wqte
.lt_id
.generation
!= gen
:
88 warn_str
= "WARNING: found idx:{:d}/gen:{:d}, but requested idx:{:d}/gen:{:d}".format(link
.wqte
.lt_id
.idx
, link
.wqte
.lt_id
.generation
, idx
, gen
)
92 def GetWaitqPrepost(id):
93 idx
= WaitqTableIdxFromId(id)
94 if idx
> int(kern
.globals.g_prepost_table
.nelem
):
95 warn_str
= "Invalid waitq prepost table id {:s}".format(str(id))
97 slab_slot
= idx
/ kern
.globals.g_prepost_table
.slab_elem
;
98 slab
= kern
.globals.g_prepost_table
.table
[int(slab_slot
)]
100 warn_str
= "Invalid waitq prepost table id:", str(id), " (invalid slab)"
102 first_elem
= Cast(slab
, 'lt_elem *')
103 addr
= int(slab
) + ((idx
- first_elem
.lt_id
.idx
) * int(kern
.globals.g_prepost_table
.elem_sz
))
104 wqp
= kern
.GetValueFromAddress(addr
, 'wq_prepost *')
105 gen
= WaitqTableGenFromId(id)
107 if gen
> 0 and wqp
.wqte
.lt_id
.generation
!= gen
:
108 warn_str
= "WARNING: found idx:{:d}/gen:{:d}, but requested idx:{:d}/gen:{:d}".format(wqp
.wqte
.lt_id
.idx
, wqp
.wqte
.lt_id
.generation
, idx
, gen
)
113 def GetWaitqSetidString(setid
):
114 idx
= WaitqTableIdxFromId(setid
)
115 gen
= WaitqTableGenFromId(setid
)
116 # This must match the format used in WaitqSetsFromLink
117 str = "{:>7d}/{:<#14x}".format(unsigned(idx
), unsigned(gen
))
121 def WaitqSetsFromLink(link
, sets
, depth
):
123 sets
.append("{: <22s}".format("<link:NULL>"))
125 if WaitqTableElemType(link
) == "ELEM":
126 #sets.append("{: <#18x}".format(unsigned(link.wql_wqs.wql_set)))
127 #sets.append("{:>7d}/{:<#14x}".format(unsigned(id.idx),unsigned(id.generation)))
128 sets
.append(GetWaitqSetidString(link
.wqte
.lt_id
.id))
131 sets
.append("{: <22s}".format("!recursion limit!"))
133 left_link
= GetWaitqLink(link
.wql_link
.left_setid
)[0]
134 right_link
= GetWaitqLink(link
.wql_link
.right_setid
)[0]
135 WaitqSetsFromLink(left_link
, sets
, depth
+ 1)
136 WaitqSetsFromLink(right_link
, sets
, depth
+ 1)
139 def GetWaitqSets(waitq
):
143 if waitq
.waitq_set_id
== 0:
145 link
= GetWaitqLink(waitq
.waitq_set_id
)[0]
146 WaitqSetsFromLink(link
, sets
, 0)
149 def GetFrameString(pc
, compact
=True):
150 str = GetSourceInformationForAddress(unsigned(pc
))
152 return re
.sub(r
'.*0x[0-9a-f]+\s+<(\w+)( \+ 0x[0-9a-f]+)*>.*', r
'\1', str, re
.UNICODE
)
154 return re
.sub(r
'.*(0x[0-9a-f]+)\s+<(\w+)( \+ 0x[0-9a-f]+)*>.*', r
'\2(\1)', str, re
.UNICODE
)
156 @lldb_type_summary(['waitq_link', 'waitq_link *'])
157 @header("{:<18s} {:<18s} {:<19s} {:<10s} {:<1s} {:<4s} {:<10s} {:<20s}".format('addr','id','idx','gen','V','type','refcnt','info'))
158 def GetWaitqSetidLinkSummary(link
, verbose
=False):
162 fmt_str
= "{l: <#18x} {l.wqte.lt_id.id: <#18x} {l.wqte.lt_id.idx: <7d} (->{l.wqte.lt_next_idx: <7d}) {l.wqte.lt_id.generation: <#10x} {v: <1s} {t: <4s} {rcnt: <10d} "
163 if hasattr(link
, 'sl_alloc_task'):
165 fmt_str
+= "owner:{l.sl_alloc_task: <#x}/th:{l.sl_alloc_th: <#x}\n"
168 pid
= GetProcPIDForTask(link
.sl_alloc_task
)
170 pid
= unsigned(link
.sl_alloc_task
.audit_token
.val
[5])
173 pidnm
= "DEAD:{:s}".format(GetProcNameForTask(link
.sl_alloc_task
))
175 pidnm
+= GetProcNameForPid(pid
)
176 fmt_str
+= " ({:d}/{:s}), ".format(pid
, pidnm
)
177 type = WaitqTableElemType(link
)
181 if WaitqTableElemValid(link
):
183 refcnt
= WaitqTableElemRefcnt(link
)
184 out_str
= fmt_str
.format(l
=link
, v
=v
, t
=type, rcnt
=refcnt
)
186 out_str
+= "wqs:{0: <#18x}".format(unsigned(link
.wql_wqs
.wql_set
))
188 lID
= link
.wql_link
.left_setid
189 rID
= link
.wql_link
.right_setid
190 left
= GetWaitqLink(lID
)[0]
191 right
= GetWaitqLink(rID
)[0]
193 if WaitqTableElemValid(left
):
194 ltype
= WaitqTableElemType(left
)
198 if WaitqTableElemValid(right
):
199 rtype
= WaitqTableElemType(right
)
202 out_str
+= "left:{:<#x}({:s}), right:{:<#x}({:s})".format(lID
, ltype
, rID
, rtype
)
203 if hasattr(link
, 'sl_alloc_bt') and unsigned(link
.sl_alloc_bt
[0]) > 0:
204 fmt_str
= "\n{:s}alloc_bt({:d}):[".format(' '*87, link
.sl_alloc_ts
)
206 while f
< kern
.globals.g_nwaitq_btframes
:
207 fstr
= GetFrameString(link
.sl_alloc_bt
[f
], not verbose
)
209 if f
== kern
.globals.g_nwaitq_btframes
:
210 fmt_str
+= "{:<s}".format(fstr
)
212 fmt_str
+= "{:<s} <- ".format(fstr
)
215 if hasattr(link
, 'sl_mkvalid_bt') and unsigned(link
.sl_mkvalid_bt
[0]) > 0:
216 fmt_str
= "\n{:s}mkvalid_bt({:d}):[".format(' '*87, link
.sl_mkvalid_ts
)
218 while f
< kern
.globals.g_nwaitq_btframes
:
219 fstr
= GetFrameString(link
.sl_mkvalid_bt
[f
], not verbose
)
221 if f
== kern
.globals.g_nwaitq_btframes
:
222 fmt_str
+= "{:<s}".format(fstr
)
224 fmt_str
+= "{:<s} <- ".format(fstr
)
227 if hasattr(link
, 'sl_invalidate_bt') and unsigned(link
.sl_invalidate_bt
[0]) > 0:
228 fmt_str
= "\n{:s}invalidate_bt({:d}):[".format(' '*87, link
.sl_invalidate_ts
)
230 while f
< kern
.globals.g_nwaitq_btframes
:
231 fstr
= GetFrameString(link
.sl_invalidate_bt
[f
], not verbose
)
233 if f
== kern
.globals.g_nwaitq_btframes
:
234 fmt_str
+= "{:<s}".format(fstr
)
236 fmt_str
+= "{:<s} <- ".format(fstr
)
241 def PrintWaitqSetidLinkTree(link
, verbose
, sets
, indent
=87):
242 if not WaitqTableElemType(link
) == "LINK":
244 lID
= link
.wql_link
.left_setid
245 rID
= link
.wql_link
.right_setid
246 left
= GetWaitqLink(lID
)[0]
247 right
= GetWaitqLink(rID
)[0]
250 if WaitqTableElemValid(left
):
251 ltype
= WaitqTableElemType(left
)
254 lstr
= "L:{:<#x}({:s})".format(lID
, ltype
)
257 if WaitqTableElemValid(right
):
258 rtype
= WaitqTableElemType(right
)
261 rstr
= "R:{:<#x}({:s})".format(rID
, rtype
)
264 sets
.append(addressof(left
.wql_wqs
.wql_set
.wqset_q
))
266 sets
.append(addressof(right
.wql_wqs
.wql_set
.wqset_q
))
268 print "{:s}`->{:s}, {:s}".format(' '*indent
, lstr
, rstr
)
270 PrintWaitqSetidLinkTree(right
, verbose
, sets
, indent
+ len(lstr
) + 6);
272 print "{:s}`->{:s}, {:s}".format(' '*indent
, lstr
, rstr
)
273 PrintWaitqSetidLinkTree(left
, verbose
, sets
, indent
+ 4);
274 PrintWaitqSetidLinkTree(right
, verbose
, sets
, indent
+ len(lstr
) + 6)
277 # Macro: showsetidlink
278 @lldb_command('showsetidlink', "S:FT")
279 def ShowSetidLink(cmd_args
=None, cmd_options
={}):
280 """ Print waitq_link structure summary
282 Note: you can pass either a complete ID (generation + index), or
283 just the index to the -S argument.
285 usage: showsetidlink [-F] [-S ID] [0xaddr]
286 -S {ID} : show the setid link whose ID is {ID}
287 -F : follow the chain of setid structures
288 and print a summary of each one
289 -T : print the tree of setidlinks in table format
295 if config
['verbosity'] > vHUMAN
:
297 if "-T" in cmd_options
:
299 if "-S" in cmd_options
:
300 id = unsigned(kern
.GetValueFromAddress(cmd_options
["-S"], 'uint64_t *'))
301 link
, warn_str
= GetWaitqLink(id)
304 raise LookupError(warn_str
)
306 raise ArgumentError("Invalid link ID {:d}({:<#x}".format(id, id))
307 if "-F" in cmd_options
:
311 raise ArgumentError("Please pass the address of a waitq_link object")
312 link
= kern
.GetValueFromAddress(cmd_args
[0], 'waitq_link *')
314 raise ArgumentError("Invalid waitq_link {:s}".format(cmd_args
[0]))
316 print GetWaitqSetidLinkSummary
.header
317 print GetWaitqSetidLinkSummary(link
, verbose
)
319 next_id
= link
.wqte
.lt_next_idx
320 max_elem
= int(kern
.globals.g_wqlinktable
.nelem
)
321 if hasattr(kern
.globals, 'g_lt_idx_max'):
322 max_elem
= unsigned(kern
.globals.g_lt_idx_max
)
323 while link
!= 0 and next_id
< max_elem
:
324 link
, warn_str
= GetWaitqLink(unsigned(next_id
))
326 print GetWaitqSetidLinkSummary(link
, verbose
)
327 next_id
= link
.wqte
.lt_next_idx
330 print "\nLinkTree:{:<#x}({:s})".format(link
.wqte
.lt_id
.id, WaitqTableElemType(link
))
331 PrintWaitqSetidLinkTree(link
, verbose
, sets
, 9)
333 print "{:d} Sets:".format(len(sets
))
335 pp_str
= GetWaitqPreposts(wq
)
336 npreposts
= len(pp_str
)
343 nps
+= ';'.join(pp_str
)
346 print "\tWQS:{:<#x} ({:d} prepost{:s})".format(unsigned(wq
),npreposts
,nps
)
347 # EndMacro: showsetidlink
348 @lldb_command('showwaitqlink', "S:FT")
349 def ShowWaitqLink(cmd_args
=None, cmd_options
={}):
350 """ Print waitq_link structure summary
352 ShowSetidLink(cmd_args
, cmd_options
)
355 # Macro: showallsetidlinks
356 @lldb_command('showallsetidlinks', 'V:T:S:F:XQ')
357 def ShowAllSetidLinks(cmd_args
=None, cmd_options
={}):
358 """ Dump / summarize all waitq set linktable elements
360 usage: showallsetidlinks [options]
361 -V {0,1} : only show [1 == valid/live links, 0 == invalid links]
362 -T {type} : only display objects of type {type}
363 -S {desc} : only display objects of type {type} which fit {desc}
364 -T LINK -S {desc} can be:
365 iL : Invalid left-link pointer (only)
366 iR : Invalid right-link pointer (only)
367 iLR : Invalid left+right link pointers
368 iLRI : Invalid left+right link pointers AND dead allocating process
369 w/o "-T" -S {desc} can be:
370 iP : Invalid / Dead allocating process
371 -F n : summarize the backtraces at frame level 'n'
372 -X : cross-check waitq pointers in link table
373 -Q : be quiet, only summarize
381 opt_validate_links
= 0
382 opt_subtype_filter
= 0
384 if config
['verbosity'] > vHUMAN
:
386 if "-Q" in cmd_options
:
388 if "-V" in cmd_options
:
389 if int(cmd_options
["-V"]) == 1:
391 elif int(cmd_options
["-V"]) == 0:
394 raise ArgumentError("Invalid parameter to -V '{:s}': expecting 0 or 1".format(cmd_options
["-V"]))
395 if "-X" in cmd_options
:
400 if "-F" in cmd_options
:
401 opt_bt_idx
= unsigned(cmd_options
["-F"])
402 if hasattr(kern
.globals, "g_nwaitq_btframes"):
403 if opt_bt_idx
>= unsigned(kern
.globals.g_nwaitq_btframes
):
404 raise ArgumentError("Invalid BT index '{:s}' max:{:d}".format(cmd_options
["-F"], unsigned(kern
.globals.g_nwaitq_btframes
) - 1))
405 if "-T" in cmd_options
:
406 opt_type_filt
= cmd_options
["-T"]
407 if opt_type_filt
== "FREE" or opt_type_filt
== "RSVD" or opt_type_filt
== "LINK":
409 elif opt_type_filt
== "WQS":
410 opt_type_filt
= "ELEM"
412 raise ArgumentError("Invalid type filter'{:s}'".format(cmd_options
["-T"]))
413 if "-S" in cmd_options
:
414 opt_subtype_filter
= cmd_options
["-S"]
415 if opt_type_filt
== "LINK":
416 if not (opt_subtype_filter
== "iL" or \
417 opt_subtype_filter
== "iR" or \
418 opt_subtype_filter
== "iLR" or \
419 opt_subtype_filter
== "iLRI"):
420 raise ArgumentError("Invalid LINK sub-type filter \{desc\}: {:s}".format(opt_subtype_filter
))
421 elif opt_type_filt
== "":
422 if not opt_subtype_filter
== "iP":
423 raise ArgumentError("Invalid sub-type filter \{desc\}: {:s}".format(opt_subtype_filter
))
424 table
= kern
.globals.g_wqlinktable
425 nelem
= int(table
.nelem
)
433 hdr_str
= "Looking through {:d} waitq_link objects from g_wqlinktable@{:<#x}".format(nelem
, addressof(kern
.globals.g_wqlinktable
))
434 if opt_type_filt
!= "" or opt_valid_only
!= 0:
435 hdr_str
+= "\n\t`-> for "
440 if opt_type_filt
== "":
443 hdr_str
+= "{:s} objects".format(opt_type_filt
)
446 hdr_str
+= "\n\t`-> showing only VALID links"
447 elif opt_invalid_only
:
448 hdr_str
+= "\n\t`-> showing only INVALID links"
449 if opt_subtype_filter
!= 0:
450 if opt_type_filt
!= "LINK" and opt_type_filt
!= "":
451 raise ArgumentError("Subtype (-S {desc}) can only be used with (-T LINK) or no type filter at all")
452 hdr_str
+= "\n\t`-> filtering {:s} objects through '{:s}'".format(opt_type_filt
, opt_subtype_filter
)
454 hdr_str
+= "\n\t`-> cross-checking WQS elements for duplicates"
458 print GetWaitqSetidLinkSummary
.header
462 # Set a generation count to differentiate from an invalid ID
463 first_entry
= Cast(kern
.globals.g_wqlinktable
.table
[0], 'lt_elem *')
464 link
= GetWaitqLink(first_entry
.lt_id
.id)[0]
466 link
= GetWaitqLink(id)[0]
468 print "<<<invalid link:{:d}>>>".format(id)
471 lt
= WaitqTableElemType(link
)
472 isvalid
= WaitqTableElemValid(link
)
474 do_print
= not ( (isvalid
and opt_invalid_only
) or (not isvalid
and opt_valid_only
) )
475 if do_print
and opt_subtype_filter
!= 0 and lt
== "LINK":
476 lID
= link
.wql_link
.left_setid
477 rID
= link
.wql_link
.right_setid
478 left
= GetWaitqLink(lID
)[0]
479 right
= GetWaitqLink(rID
)[0]
480 lValid
= WaitqTableElemValid(left
)
481 rValid
= WaitqTableElemValid(right
)
482 if opt_subtype_filter
== "iL":
483 if lValid
or (not lValid
and not rValid
):
485 elif opt_subtype_filter
== "iR":
486 if rValid
or (not rValid
and not lValid
):
488 elif opt_subtype_filter
== "iLR":
491 elif opt_subtype_filter
== "iLRI" and hasattr(link
, 'sl_alloc_task'):
492 # only print this if both left and right are invalid
493 # and the allocating task is unknown/dead
498 pid
= GetProcPIDForTask(link
.sl_alloc_task
)
500 if link
.sl_alloc_task
:
501 pid
= unsigned(link
.sl_alloc_task
.audit_token
.val
[5])
505 pidnm
= GetProcNameForPid(pid
)
506 if pidnm
== "Unknown":
508 if (not rValid
) and (not lValid
) and is_dead
:
511 if do_print
and opt_type_filt
== "" and opt_subtype_filter
== "iP" and hasattr(link
, 'sl_alloc_task'):
512 # Only print non-free table objects that were allocated by
518 pid
= GetProcPIDForTask(link
.sl_alloc_task
)
520 if link
.sl_alloc_task
:
521 pid
= unsigned(link
.sl_alloc_task
.audit_token
.val
[5])
525 pidnm
= GetProcNameForPid(pid
)
526 if pidnm
== "Unknown":
531 if (opt_type_filt
== "" or opt_type_filt
== lt
) and do_print
:
543 if hasattr(link
, 'sl_alloc_bt'):
544 pc
= unsigned(link
.sl_alloc_bt
[opt_bt_idx
])
547 if pc_str
in bt_summary
:
548 bt_summary
[pc_str
] += 1
550 bt_summary
[pc_str
] = 1
552 print GetWaitqSetidLinkSummary(link
, verbose
)
555 # print out warnings about inconsistent state as we parse
556 # the list - even if the caller wants a summary
557 print "[WARNING] inconsistent state in idx: {:d} ({:s} element)".format(link
.wqte
.lt_id
.idx
, lt
)
558 if opt_cross_check
== 1 and lt
== "ELEM":
559 wq
= unsigned(addressof(link
.wql_wqs
.wql_set
.wqset_q
))
561 wq_ptr
[wq
].append(id)
565 if l
> max_wqs_dupes
:
571 if opt_summary
or verbose
:
572 if verbose
and opt_cross_check
:
573 sys
.stderr
.write('[{:d}|{:d}|{:d}] id: {:d}/{:d}... \r'.format(nunique_wqs
, nduplicated_wqs
, max_wqs_dupes
, id, nelem
))
575 sys
.stderr
.write('id: {:d}/{:d}... \r'.format(id, nelem
))
577 nused
= nwqs
+ nlink
+ nrsvd
578 nfound
= nused
+ nfree
+ ninv
579 print "\n\nFound {:d} objects: {:d} WQS, {:d} LINK, {:d} RSVD, {:d} FREE".format(nfound
, nwqs
, nlink
, nrsvd
, nfree
)
580 if (opt_type_filt
== "" and opt_valid_only
== 0) and (nused
!= table
.used_elem
):
581 print"\tWARNING: inconsistent state! Table reports {:d}/{:d} used elem, found {:d}/{:d}".format(table
.used_elem
, nelem
, nused
, nfound
)
582 if len(bt_summary
) > 0:
583 print "Link allocation BT (frame={:d})".format(opt_bt_idx
)
584 for k
,v
in bt_summary
.iteritems():
585 print "\t[{:d}] from: {:s}".format(v
, GetSourceInformationForAddress(unsigned(k
)))
587 print "\n{:d} Duplicated WQS objects:".format(nduplicated_wqs
)
591 print "\tWQS:{:#x} ({:d} {:s}".format(wq
, l
, str(wq_ptr
[wq
]))
592 # EndMacro: showallsetidlinks
595 # Macro: showallpreposts
596 @lldb_command('showallpreposts', 'VQT:F:Y:')
597 def ShowAllPreposts(cmd_args
=None, cmd_options
={}):
598 """ Dump / summarize all waitq prepost linkage elements
600 usage: showallpreposts [-V] [-T {type}] [-Y n] [-F n] [-Q]
601 -V : only show valid / live links
602 -T {type} : only display objects of type {type}
603 -Y {0|1} : only only show POST objects that are
604 valid (-Y 1) or invalid (-Y 0)
605 -F n : summarize the backtraces at frame level 'n'
606 -Q : be quiet, only summarize
614 if config
['verbosity'] > vHUMAN
:
616 if "-Q" in cmd_options
:
618 if "-V" in cmd_options
:
620 if "-Y" in cmd_options
:
621 opt_post_type
= unsigned(cmd_options
["-Y"])
622 if opt_post_type
!= 0 and opt_post_type
!= 1:
623 raise ArgumentError("Invalid POST obj specifier [-Y %d] (expected 0 or 1)" % cmd_options
["-Y"])
624 if "-F" in cmd_options
:
625 opt_bt_idx
= unsigned(cmd_options
["-F"])
626 if hasattr(kern
.globals, "g_nwaitq_btframes"):
627 if opt_bt_idx
>= unsigned(kern
.globals.g_nwaitq_btframes
):
628 raise ArgumentError("Invalid BT index '{:s}' max:{:d}".format(cmd_options
["-F"], unsigned(kern
.globals.g_nwaitq_btframes
) - 1))
629 if "-T" in cmd_options
:
630 opt_type_filt
= cmd_options
["-T"]
631 if opt_type_filt
== "FREE" or opt_type_filt
== "RSVD":
633 elif opt_type_filt
== "POST":
634 opt_type_filt
= "LINK"
635 elif opt_type_filt
== "WQ":
636 opt_type_filt
= "ELEM"
638 raise ArgumentError("Invalid type filter'{:s}'".format(cmd_options
["-T"]))
639 table
= kern
.globals.g_prepost_table
640 nelem
= int(table
.nelem
)
647 hdr_str
= "Looking through {:d} objects from g_prepost_table@{:<#x}".format(nelem
, addressof(kern
.globals.g_prepost_table
))
648 if opt_type_filt
!= "" or opt_valid_only
!= 0:
649 hdr_str
+= "\n\t`-> for "
654 if opt_type_filt
== "":
657 hdr_str
+= "{:s} objects".format(cmd_options
["-T"])
660 print GetWaitqPrepostSummary
.header
663 wqp
= GetWaitqPrepost(id)[0]
665 print "<<<invalid prepost:{:d}>>>".format(id)
668 lt
= WaitqTableElemType(wqp
)
669 isvalid
= WaitqTableElemValid(wqp
)
671 if isvalid
and opt_post_type
> -1 and lt
== "LINK":
672 post_wqp
= GetWaitqPrepost(wqp
.wqp_post
.wqp_wq_id
)[0]
673 post_valid
= WaitqTableElemValid(post_wqp
)
674 if opt_post_type
== 0 and post_valid
: # only count _invalid_ POST objects
676 elif opt_post_type
== 1 and not post_valid
: # only count _valid_ POST objects
678 if should_count
and (opt_type_filt
== "" or opt_type_filt
== lt
) and ((opt_valid_only
== 0 or isvalid
)):
689 if hasattr(wqp
, 'wqp_alloc_bt'):
690 pc
= unsigned(wqp
.wqp_alloc_bt
[opt_bt_idx
])
693 if pc_str
in bt_summary
:
694 bt_summary
[pc_str
] += 1
696 bt_summary
[pc_str
] = 1
698 print GetWaitqPrepostSummary(wqp
)
700 sys
.stderr
.write('id: {:d}/{:d}... \r'.format(id, nelem
))
702 nused
= nwq
+ npost
+ nrsvd
703 nfound
= nused
+ nfree
+ ninv
704 print "\nFound {:d} objects: {:d} WQ, {:d} POST, {:d} RSVD, {:d} FREE".format(nfound
, nwq
, npost
, nrsvd
, nfree
)
705 if (opt_type_filt
== "" and opt_valid_only
== 0) and (nused
!= table
.used_elem
):
706 print"\tWARNING: inconsistent state! Table reports {:d}/{:d} used elem, found {:d}/{:d}".format(table
.used_elem
, nelem
, nused
, nfound
)
707 if len(bt_summary
) > 0:
708 print "Link allocation BT (frame={:d})".format(opt_bt_idx
)
709 for k
,v
in bt_summary
.iteritems():
710 print "\t[{:d}] from: {:s}".format(v
, GetSourceInformationForAddress(unsigned(k
)))
711 # EndMacro: showallpreposts
714 @lldb_type_summary(['wq_prepost', 'wq_prepost *'])
715 @header("{:<18s} {:<18s} {:<19s} {:<10s} {:<1s} {:<4s} {:<10s} {:<20s}".format('addr','id','idx','gen','V','type','refcnt','info'))
716 def GetWaitqPrepostSummary(wqp
):
719 fmt_str
= "{w: <#18x} {w.wqte.lt_id.id: <#18x} {w.wqte.lt_id.idx: <7d} (->{w.wqte.lt_next_idx: <7d}) {w.wqte.lt_id.generation: <#10x} {v: <1s} {t: <4s} {rcnt: <10d} "
720 type = WaitqTableElemType(wqp
)
726 if WaitqTableElemValid(wqp
):
728 refcnt
= WaitqTableElemRefcnt(wqp
)
729 out_str
= fmt_str
.format(w
=wqp
, v
=v
, t
=type, rcnt
=refcnt
)
731 out_str
+= "wq:{0: <#18x}".format(unsigned(wqp
.wqp_wq
.wqp_wq_ptr
))
733 out_str
+= "next:{0: <#18x}, wqid:{1: <#18x}".format(wqp
.wqp_post
.wqp_next_id
, wqp
.wqp_post
.wqp_wq_id
)
734 post_wqp
= GetWaitqPrepost(wqp
.wqp_post
.wqp_wq_id
)[0]
735 if not WaitqTableElemValid(post_wqp
):
736 out_str
+= "(<invalid>)"
738 if WaitqTableElemType(post_wqp
) != "ELEM":
739 out_str
+= "(!WQP_WQ?)"
741 out_str
+= "({0: <#18x})".format(unsigned(post_wqp
.wqp_wq
.wqp_wq_ptr
))
746 @lldb_command('showprepost', "P:")
747 def ShowPrepost(cmd_args
=None, cmd_options
={}):
748 """ Print prepost structure summary
750 Note: you can pass either a complete ID (generation + index), or
751 just the index to the -P argument.
753 usage: showprepost [-P ID] [0xaddr]
754 -P {ID} : show prepost structure whose ID is {ID}
757 if "-P" in cmd_options
:
758 wqp
, warn_str
= GetWaitqPrepost(unsigned(kern
.GetValueFromAddress(cmd_options
["-P"], 'uint64_t *')))
761 raise LookupError(warn_str
)
763 raise ArgumentError("Invalid prepost ID {:s}".format(cmd_options
["-P"]))
766 raise ArgumentError("Please pass the address of a prepost object")
767 wqp
= kern
.GetValueFromAddress(cmd_args
[0], 'wq_prepost *')
769 raise ArgumentError("Invalid prepost {:s}".format(cmd_args
[0]))
771 print GetWaitqPrepostSummary
.header
772 print GetWaitqPrepostSummary(wqp
)
773 # EndMacro: showprepost
776 def WaitqPrepostFromObj(wqp
, head_id
, inv_ok
, prepost_str
, pp_arr
= 0, depth
= 0):
779 etype
= WaitqTableElemType(wqp
)
780 if not WaitqTableElemValid(wqp
) and not inv_ok
:
783 id = wqp
.wqte
.lt_id
.id
784 prepost_str
.append("{0: <#18x}:{1: <18s}".format(id, "<invalid>"))
786 if etype
== "ELEM": # WQP_WQ
787 prepost_str
.append("{0: <#18x}:{1: <#18x}".format(wqp
.wqte
.lt_id
.id, unsigned(wqp
.wqp_wq
.wqp_wq_ptr
)))
792 if etype
== "LINK": # WQP_POST
793 next_id
= wqp
.wqp_post
.wqp_next_id
794 post_wq
= GetWaitqPrepost(wqp
.wqp_post
.wqp_wq_id
)[0]
795 if WaitqTableElemValid(post_wq
):
796 if WaitqTableElemType(post_wq
) != "ELEM":
797 prepost_str
.append("{0: <#18x}:{1: <18s}".format(post_wq
.wqte
.lt_id
.id, "<invalid post>"))
799 prepost_str
.append("{0: <#18x}:{1: <#18x}".format(wqp
.wqte
.lt_id
.id, unsigned(post_wq
.wqp_wq
.wqp_wq_ptr
)))
800 if next_id
> 0 and next_id
!= head_id
:
802 prepost_str
.append("{: <37s}".format("!recursion limit!"))
804 WaitqPrepostFromObj(GetWaitqPrepost(next_id
)[0], head_id
, inv_ok
, prepost_str
, pp_arr
, depth
+ 1)
805 else: # "RSVD" or "FREE":
806 prepost_str
.append("{0: <#18x} -> {1: <15d}".format(wqp
.wqte
.lt_id
.id, wqp
.wqte
.lt_next_idx
))
807 next_id
= wqp
.wqte
.lt_next_idx
808 max_elem
= int(kern
.globals.g_prepost_table
.nelem
)
809 if hasattr(kern
.globals, 'g_lt_idx_max'):
810 max_elem
= unsigned(kern
.globals.g_lt_idx_max
)
811 if next_id
< max_elem
:
813 prepost_str
.append("{: <37s}".format("!recursion limit!"))
815 WaitqPrepostFromObj(GetWaitqPrepost(next_id
)[0], head_id
, inv_ok
, prepost_str
, pp_arr
, depth
+ 1)
818 def GetPrepostChain(head_id
, inv_ok
= False, pp_arr
= 0):
820 if unsigned(head_id
) == 0:
821 return [ "{0: <#18x}:{1: <18s}".format(head_id
, "<invalid>") ]
822 wqp
= GetWaitqPrepost(head_id
)[0]
824 WaitqPrepostFromObj(wqp
, head_id
, inv_ok
, pp
, pp_arr
)
826 return [ "{0: <#18x}:{1: <18s}".format(head_id
, "<invalid>") ]
829 def GetWaitqPreposts(waitq
):
830 if GetWaitqStateStr(waitq
) != "SET":
832 wqset
= Cast(waitq
, 'waitq_set *')
833 if wqset
.wqset_prepost_id
== 0:
835 if not wqset
.wqset_q
.waitq_prepost
:
836 # If the "prepost_id" is non-zero, but the 'waitq_prepost' bit is
837 # *not* set, then this waitq actually has a prepost hook!
838 return [ "{0: <#18x}:{1: <18s}".format(wqset
.wqset_prepost_id
, "<hook>") ]
839 return GetPrepostChain(wqset
.wqset_prepost_id
)
842 # Macro: showprepostchain
843 @lldb_command('showprepostchain', "P:")
844 def ShowPrepostChain(cmd_args
=None, cmd_options
={}):
845 """ Follow a chain of preposts, printing each one.
846 Note that prepost chains are circular, so this will print
847 the entire chain given a single element.
849 Note: you can pass either a complete ID (generation + index), or
850 just the index to the -P argument.
852 usage: showprepostchain [-P ID] [0xaddr]
853 -P {ID} : start printing with the prepost whose ID is {ID}
856 if "-P" in cmd_options
:
857 wqp
, warn_str
= GetWaitqPrepost(unsigned(kern
.GetValueFromAddress(cmd_options
["-P"], 'uint64_t *')))
860 raise LookupError(warn_str
)
862 raise ArgumentError("Invalid prepost ID {:s}".format(cmd_options
["-P"]))
865 raise ArgumentError("Please pass the address of a prepost object")
866 wqp
= kern
.GetValueFromAddress(cmd_args
[0], 'wq_prepost *')
868 raise ArgumentError("Invalid prepost {:s}".format(cmd_args
[0]))
871 GetPrepostChain(wqp
.wqte
.lt_id
.id, True, pp_arr
)
876 print GetWaitqPrepostSummary
.header
878 print GetWaitqPrepostSummary(pp_arr
[idx
])
880 type = WaitqTableElemType(pp_arr
[idx
])
882 post_wqp
= GetWaitqPrepost(pp_arr
[idx
].wqp_post
.wqp_wq_id
)[0]
883 if not WaitqTableElemValid(post_wqp
):
891 print "Total: {:d} ({:d} valid, {:d} invalid)".format(len(pp_arr
), nvalid
, ninvalid
)
892 # EndMacro: showprepostchain
895 @lldb_type_summary(['waitq', 'waitq *'])
896 @header("{: <16s} {: <3s} {: <4s} {: <17s} {: <18s} {: <18s} {: <37s} {: <22s} {: <10s}".format('waitq', 'typ', 'bits', 'evtmask', 'setid', 'wq_wqp', 'preposts', 'member_of', 'threads'))
897 def GetWaitqSummary(waitq
):
898 fmt_str
= "{q: <16x} {state: <3s} {bits: <4s} {q.waitq_eventmask: <#17x} {setid: <#18x} {q.waitq_prepost_id: <#18x}"
900 if waitq
.waitq_queue
.next
and waitq
.waitq_queue
.prev
:
901 for thread
in IterateLinkageChain(addressof(waitq
.waitq_queue
), 'thread *', 'wait_links'):
902 th_str
.append("{: <18s} e:{: <#18x}".format(hex(thread
), thread
.wait_event
))
904 th_str
.append("{: <39s}".format('<invalid (NULL) queue>'))
906 set_str
= GetWaitqSets(waitq
)
907 set_cnt
= len(set_str
)
908 pp_str
= GetWaitqPreposts(waitq
)
912 while idx
< pp_cnt
or idx
< set_cnt
or idx
< th_cnt
:
923 last_str
+= "{0: <37s} {1: <22s} {2: <39s}".format(p
, s
, t
)
925 last_str
+= "\n{0: <80s} {1: <37s} {2: <22s} {3: <39s}".format('', p
, s
, t
)
927 if pp_cnt
> 0 or set_cnt
> 0 or th_cnt
> 0:
928 last_str
+= "\n{:<80s} {: <37s} {: <22s} {: <39s}".format('', '-'*37, '-'*20, '-'*39)
929 last_str
+= "\n{0: <80s} {1: <37d} {2: <22d} {3: <39d}".format('', pp_cnt
, set_cnt
, th_cnt
)
931 state
= GetWaitqStateStr(waitq
)
934 setid
= Cast(waitq
, 'waitq_set *').wqset_id
935 out_str
= fmt_str
.format(q
=waitq
, state
=state
, bits
=GetWaitqBitsStr(waitq
), setid
=setid
)
940 @lldb_command('showwaitq', "P:S:")
941 def ShowWaitq(cmd_args
=None, cmd_options
={}):
942 """ Print waitq structure summary.
943 Lookup the waitq either by address, by Set ID, or indirectly
944 through a prepost object that points to the waitq.
946 Note: you can pass either a complete ID (generation + index), or
947 just the index to the -P and -S arguments.
949 usage: showwaitq [-P PrePostID] [-S SetID] [0xaddr]
950 -P {ID} : prepost ID that points to a waitq
951 -S {ID} : waitq_set ID
954 if "-P" in cmd_options
:
955 wqp
, warn_str
= GetWaitqPrepost(unsigned(kern
.GetValueFromAddress(cmd_options
["-P"], 'uint64_t *')))
958 raise LookupError(warn_str
)
960 raise ArgumentError("Invalid prepost ID {:s}".format(cmd_options
["-P"]))
961 if WaitqTableElemType(wqp
) != "ELEM":
962 raise ArgumentError("Prepost ID {:s} points to a WQP_POST object, not a WQP_WQ!".format(cmd_options
["-P"]))
963 waitq
= wqp
.wqp_wq
.wqp_wq_ptr
964 if "-S" in cmd_options
:
966 raise ArgumentError("Please pass only one of '-S' or '-P'!")
967 link
, warn_str
= GetWaitqLink(unsigned(kern
.GetValueFromAddress(cmd_options
["-S"],'uint64_t *')))
970 raise LookupError(warn_str
)
972 raise ArgumentError("Invalid link ID {:s}".format(cmd_options
["-S"]))
973 if WaitqTableElemType(link
) != "ELEM":
974 raise ArgumentError("Link ID {:s} points to a SLT_LINK object, not an SLT_WQS!".format(cmd_options
["-S"]))
975 waitq
= addressof(link
.wql_wqs
.wql_set
.wqset_q
)
977 if not waitq
and not cmd_args
:
978 raise ArgumentError("Please pass the address of a waitq!")
980 waitq
= kern
.GetValueFromAddress(cmd_args
[0], 'waitq *')
982 raise ("Unknown arguments: %r %r" % (cmd_args
, cmd_options
))
983 print GetWaitqSummary
.header
984 print GetWaitqSummary(waitq
)
985 # EndMacro: showwaitq
988 # Macro: showglobalwaitqs
989 @lldb_command('showglobalwaitqs')
990 def ShowGlobalWaitqs(cmd_args
=None):
991 """ Summarize global waitq usage
996 print "Global waitq objects"
997 print GetWaitqSummary
.header
999 while q
< kern
.globals.g_num_waitqs
:
1000 print GetWaitqSummary(addressof(kern
.globals.global_waitqs
[q
]))
1002 # EndMacro: showglobalwaitqs
1005 # Macro: showglobalqstats
1006 @lldb_command('showglobalqstats', "OF")
1007 def ShowGlobalQStats(cmd_args
=None, cmd_options
={}):
1008 """ Summarize global waitq statistics
1010 usage: showglobalqstats [-O] [-F]
1011 -O : only output waitqs with outstanding waits
1012 -F : output as much backtrace as was recorded
1017 if not hasattr(kern
.globals, 'g_waitq_stats'):
1018 print "No waitq stats support (use DEVELOPMENT kernel)!"
1021 print "Global waitq stats"
1022 print "{0: <18s} {1: <8s} {2: <8s} {3: <8s} {4: <8s} {5: <8s} {6: <32s}".format('waitq', '#waits', '#wakes', '#diff', '#fails', '#clears', 'backtraces')
1024 waiters_only
= False
1026 if "-O" in cmd_options
:
1028 if "-F" in cmd_options
:
1031 fmt_str
= "{q: <#18x} {stats.waits: <8d} {stats.wakeups: <8d} {diff: <8d} {stats.failed_wakeups: <8d} {stats.clears: <8d} {bt_str: <s}"
1032 while q
< kern
.globals.g_num_waitqs
:
1033 waitq
= kern
.globals.global_waitqs
[q
]
1034 stats
= kern
.globals.g_waitq_stats
[q
]
1035 diff
= stats
.waits
- stats
.wakeups
1036 if diff
== 0 and waiters_only
:
1042 if (stats
.last_wait
[0]):
1043 last_waitstr
= GetSourceInformationForAddress(unsigned(stats
.last_wait
[0]))
1044 if (stats
.last_wakeup
[0]):
1045 last_wakestr
= GetSourceInformationForAddress(unsigned(stats
.last_wakeup
[0]))
1046 if (stats
.last_failed_wakeup
[0]):
1047 fw_str
= GetSourceInformationForAddress(unsigned(stats
.last_failed_wakeup
[0]))
1051 while f
< kern
.globals.g_nwaitq_btframes
:
1052 if stats
.last_wait
[f
]:
1053 last_waitstr
= "{0}->{1}".format(GetSourceInformationForAddress(unsigned(stats
.last_wait
[f
])), last_waitstr
)
1054 if stats
.last_wakeup
[f
]:
1055 last_wakestr
= "{0}->{1}".format(GetSourceInformationForAddress(unsigned(stats
.last_wakeup
[f
])), last_wakestr
)
1056 if stats
.last_failed_wakeup
[f
]:
1057 fw_str
= "{0}->{1}".format(GetSourceInformationForAddress(unsigned(stats
.last_failed_wakeup
[f
])), fw_str
)
1061 bt_str
+= "wait : " + last_waitstr
1064 bt_str
+= "\n{0: <70s} ".format('')
1065 bt_str
+= "wake : " + last_wakestr
1068 bt_str
+= "\n{0: <70s} ".format('')
1069 bt_str
+= "fails: " + fw_str
1071 print fmt_str
.format(q
=addressof(waitq
), stats
=stats
, diff
=diff
, bt_str
=bt_str
)
1073 # EndMacro: showglobalqstats