]>
git.saurik.com Git - apple/xnu.git/blob - tools/lldbmacros/waitq.py
e5914d4302bf10f036111ca4392d225842cbb492
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
.wqt_bits
>> 29) & 0x3
41 def WaitqTableElemId(e
):
42 return e
.wqte
.wqt_id
.id
44 def WaitqTableElemValid(e
):
47 return (e
.wqte
.wqt_bits
& 0x80000000) == 0x80000000
49 def WaitqTableElemRefcnt(e
):
50 return (e
.wqte
.wqt_bits
& 0x1fffffff)
52 def WaitqTableIdxFromId(id):
53 if hasattr(kern
.globals, 'g_wqt_idx_max'):
54 idx
= id & unsigned(kern
.globals.g_wqt_idx_max
)
57 idx
= id & 0x000000000003ffff
60 def WaitqTableGenFromId(id):
61 if hasattr(kern
.globals, 'g_wqt_idx_max'):
62 msk
= ~
unsigned(kern
.globals.g_wqt_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_linktable
.nelem
:
77 return 0, "Invalid waitq link table id: {:d}".format(id)
78 slab_slot
= idx
/ kern
.globals.g_linktable
.slab_elem
;
79 slab
= kern
.globals.g_linktable
.table
[int(slab_slot
)]
81 print "Invalid waitq link table id:", str(id), " (invalid slab)"
82 first_elem
= Cast(slab
, 'wqt_elem *')
83 addr
= int(slab
) + ((idx
- first_elem
.wqt_id
.idx
) * int(kern
.globals.g_linktable
.elem_sz
))
84 link
= kern
.GetValueFromAddress(addr
, 'setid_link *')
85 gen
= WaitqTableGenFromId(id)
87 if gen
> 0 and link
.wqte
.wqt_id
.generation
!= gen
:
88 warn_str
= "WARNING: found idx:{:d}/gen:{:d}, but requested idx:{:d}/gen:{:d}".format(link
.wqte
.wqt_id
.idx
, link
.wqte
.wqt_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
, 'wqt_elem *')
103 addr
= int(slab
) + ((idx
- first_elem
.wqt_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
.wqt_id
.generation
!= gen
:
108 warn_str
= "WARNING: found idx:{:d}/gen:{:d}, but requested idx:{:d}/gen:{:d}".format(wqp
.wqte
.wqt_id
.idx
, wqp
.wqte
.wqt_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.sl_wqs.sl_set)))
127 #sets.append("{:>7d}/{:<#14x}".format(unsigned(id.idx),unsigned(id.generation)))
128 sets
.append(GetWaitqSetidString(link
.wqte
.wqt_id
.id))
131 sets
.append("{: <22s}".format("!recursion limit!"))
133 left_link
= GetWaitqLink(link
.sl_link
.sl_left_setid
)[0]
134 right_link
= GetWaitqLink(link
.sl_link
.sl_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(['setid_link', 'setid_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.wqt_id.id: <#18x} {l.wqte.wqt_id.idx: <7d} (->{l.wqte.wqt_next_idx: <7d}) {l.wqte.wqt_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
.sl_wqs
.sl_set
))
188 lID
= link
.sl_link
.sl_left_setid
189 rID
= link
.sl_link
.sl_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
.sl_link
.sl_left_setid
245 rID
= link
.sl_link
.sl_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
.sl_wqs
.sl_set
.wqset_q
))
266 sets
.append(addressof(right
.sl_wqs
.sl_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 setid_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 setid_link object")
312 link
= kern
.GetValueFromAddress(cmd_args
[0], 'setid_link *')
314 raise ArgumentError("Invalid setid_link {:s}".format(cmd_args
[0]))
316 print GetWaitqSetidLinkSummary
.header
317 print GetWaitqSetidLinkSummary(link
, verbose
)
319 next_id
= link
.wqte
.wqt_next_idx
320 max_elem
= int(kern
.globals.g_linktable
.nelem
)
321 if hasattr(kern
.globals, 'g_wqt_idx_max'):
322 max_elem
= unsigned(kern
.globals.g_wqt_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
.wqt_next_idx
330 print "\nLinkTree:{:<#x}({:s})".format(link
.wqte
.wqt_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
350 # Macro: showallsetidlinks
351 @lldb_command('showallsetidlinks', 'V:T:S:F:XQ')
352 def ShowAllSetidLinks(cmd_args
=None, cmd_options
={}):
353 """ Dump / summarize all waitq set linktable elements
355 usage: showallsetidlinks [options]
356 -V {0,1} : only show [1 == valid/live links, 0 == invalid links]
357 -T {type} : only display objects of type {type}
358 -S {desc} : only display objects of type {type} which fit {desc}
359 -T LINK -S {desc} can be:
360 iL : Invalid left-link pointer (only)
361 iR : Invalid right-link pointer (only)
362 iLR : Invalid left+right link pointers
363 iLRI : Invalid left+right link pointers AND dead allocating process
364 w/o "-T" -S {desc} can be:
365 iP : Invalid / Dead allocating process
366 -F n : summarize the backtraces at frame level 'n'
367 -X : cross-check waitq pointers in link table
368 -Q : be quiet, only summarize
376 opt_validate_links
= 0
377 opt_subtype_filter
= 0
379 if config
['verbosity'] > vHUMAN
:
381 if "-Q" in cmd_options
:
383 if "-V" in cmd_options
:
384 if int(cmd_options
["-V"]) == 1:
386 elif int(cmd_options
["-V"]) == 0:
389 raise ArgumentError("Invalid parameter to -V '{:s}': expecting 0 or 1".format(cmd_options
["-V"]))
390 if "-X" in cmd_options
:
395 if "-F" in cmd_options
:
396 opt_bt_idx
= unsigned(cmd_options
["-F"])
397 if hasattr(kern
.globals, "g_nwaitq_btframes"):
398 if opt_bt_idx
>= unsigned(kern
.globals.g_nwaitq_btframes
):
399 raise ArgumentError("Invalid BT index '{:s}' max:{:d}".format(cmd_options
["-F"], unsigned(kern
.globals.g_nwaitq_btframes
) - 1))
400 if "-T" in cmd_options
:
401 opt_type_filt
= cmd_options
["-T"]
402 if opt_type_filt
== "FREE" or opt_type_filt
== "RSVD" or opt_type_filt
== "LINK":
404 elif opt_type_filt
== "WQS":
405 opt_type_filt
= "ELEM"
407 raise ArgumentError("Invalid type filter'{:s}'".format(cmd_options
["-T"]))
408 if "-S" in cmd_options
:
409 opt_subtype_filter
= cmd_options
["-S"]
410 if opt_type_filt
== "LINK":
411 if not (opt_subtype_filter
== "iL" or \
412 opt_subtype_filter
== "iR" or \
413 opt_subtype_filter
== "iLR" or \
414 opt_subtype_filter
== "iLRI"):
415 raise ArgumentError("Invalid LINK sub-type filter \{desc\}: {:s}".format(opt_subtype_filter
))
416 elif opt_type_filt
== "":
417 if not opt_subtype_filter
== "iP":
418 raise ArgumentError("Invalid sub-type filter \{desc\}: {:s}".format(opt_subtype_filter
))
419 table
= kern
.globals.g_linktable
420 nelem
= int(table
.nelem
)
428 hdr_str
= "Looking through {:d} setid_link objects from g_linktable@{:<#x}".format(nelem
, addressof(kern
.globals.g_linktable
))
429 if opt_type_filt
!= "" or opt_valid_only
!= 0:
430 hdr_str
+= "\n\t`-> for "
435 if opt_type_filt
== "":
438 hdr_str
+= "{:s} objects".format(opt_type_filt
)
441 hdr_str
+= "\n\t`-> showing only VALID links"
442 elif opt_invalid_only
:
443 hdr_str
+= "\n\t`-> showing only INVALID links"
444 if opt_subtype_filter
!= 0:
445 if opt_type_filt
!= "LINK" and opt_type_filt
!= "":
446 raise ArgumentError("Subtype (-S {desc}) can only be used with (-T LINK) or no type filter at all")
447 hdr_str
+= "\n\t`-> filtering {:s} objects through '{:s}'".format(opt_type_filt
, opt_subtype_filter
)
449 hdr_str
+= "\n\t`-> cross-checking WQS elements for duplicates"
453 print GetWaitqSetidLinkSummary
.header
457 # Set a generation count to differentiate from an invalid ID
458 first_entry
= Cast(kern
.globals.g_linktable
.table
[0], 'wqt_elem *')
459 link
= GetWaitqLink(first_entry
.wqt_id
.id)[0]
461 link
= GetWaitqLink(id)[0]
463 print "<<<invalid link:{:d}>>>".format(id)
466 lt
= WaitqTableElemType(link
)
467 isvalid
= WaitqTableElemValid(link
)
469 do_print
= not ( (isvalid
and opt_invalid_only
) or (not isvalid
and opt_valid_only
) )
470 if do_print
and opt_subtype_filter
!= 0 and lt
== "LINK":
471 lID
= link
.sl_link
.sl_left_setid
472 rID
= link
.sl_link
.sl_right_setid
473 left
= GetWaitqLink(lID
)[0]
474 right
= GetWaitqLink(rID
)[0]
475 lValid
= WaitqTableElemValid(left
)
476 rValid
= WaitqTableElemValid(right
)
477 if opt_subtype_filter
== "iL":
478 if lValid
or (not lValid
and not rValid
):
480 elif opt_subtype_filter
== "iR":
481 if rValid
or (not rValid
and not lValid
):
483 elif opt_subtype_filter
== "iLR":
486 elif opt_subtype_filter
== "iLRI" and hasattr(link
, 'sl_alloc_task'):
487 # only print this if both left and right are invalid
488 # and the allocating task is unknown/dead
493 pid
= GetProcPIDForTask(link
.sl_alloc_task
)
495 if link
.sl_alloc_task
:
496 pid
= unsigned(link
.sl_alloc_task
.audit_token
.val
[5])
500 pidnm
= GetProcNameForPid(pid
)
501 if pidnm
== "Unknown":
503 if (not rValid
) and (not lValid
) and is_dead
:
506 if do_print
and opt_type_filt
== "" and opt_subtype_filter
== "iP" and hasattr(link
, 'sl_alloc_task'):
507 # Only print non-free table objects that were allocated by
513 pid
= GetProcPIDForTask(link
.sl_alloc_task
)
515 if link
.sl_alloc_task
:
516 pid
= unsigned(link
.sl_alloc_task
.audit_token
.val
[5])
520 pidnm
= GetProcNameForPid(pid
)
521 if pidnm
== "Unknown":
526 if (opt_type_filt
== "" or opt_type_filt
== lt
) and do_print
:
538 if hasattr(link
, 'sl_alloc_bt'):
539 pc
= unsigned(link
.sl_alloc_bt
[opt_bt_idx
])
542 if pc_str
in bt_summary
:
543 bt_summary
[pc_str
] += 1
545 bt_summary
[pc_str
] = 1
547 print GetWaitqSetidLinkSummary(link
, verbose
)
550 # print out warnings about inconsistent state as we parse
551 # the list - even if the caller wants a summary
552 print "[WARNING] inconsistent state in idx: {:d} ({:s} element)".format(link
.wqte
.wqt_id
.idx
, lt
)
553 if opt_cross_check
== 1 and lt
== "ELEM":
554 wq
= unsigned(addressof(link
.sl_wqs
.sl_set
.wqset_q
))
556 wq_ptr
[wq
].append(id)
560 if l
> max_wqs_dupes
:
566 if opt_summary
or verbose
:
567 if verbose
and opt_cross_check
:
568 sys
.stderr
.write('[{:d}|{:d}|{:d}] id: {:d}/{:d}... \r'.format(nunique_wqs
, nduplicated_wqs
, max_wqs_dupes
, id, nelem
))
570 sys
.stderr
.write('id: {:d}/{:d}... \r'.format(id, nelem
))
572 nused
= nwqs
+ nlink
+ nrsvd
573 nfound
= nused
+ nfree
+ ninv
574 print "\n\nFound {:d} objects: {:d} WQS, {:d} LINK, {:d} RSVD, {:d} FREE".format(nfound
, nwqs
, nlink
, nrsvd
, nfree
)
575 if (opt_type_filt
== "" and opt_valid_only
== 0) and (nused
!= table
.used_elem
):
576 print"\tWARNING: inconsistent state! Table reports {:d}/{:d} used elem, found {:d}/{:d}".format(table
.used_elem
, nelem
, nused
, nfound
)
577 if len(bt_summary
) > 0:
578 print "Link allocation BT (frame={:d})".format(opt_bt_idx
)
579 for k
,v
in bt_summary
.iteritems():
580 print "\t[{:d}] from: {:s}".format(v
, GetSourceInformationForAddress(unsigned(k
)))
582 print "\n{:d} Duplicated WQS objects:".format(nduplicated_wqs
)
586 print "\tWQS:{:#x} ({:d} {:s}".format(wq
, l
, str(wq_ptr
[wq
]))
587 # EndMacro: showallsetidlinks
590 # Macro: showallpreposts
591 @lldb_command('showallpreposts', 'VQT:F:Y:')
592 def ShowAllPreposts(cmd_args
=None, cmd_options
={}):
593 """ Dump / summarize all waitq prepost linkage elements
595 usage: showallpreposts [-V] [-T {type}] [-Y n] [-F n] [-Q]
596 -V : only show valid / live links
597 -T {type} : only display objects of type {type}
598 -Y {0|1} : only only show POST objects that are
599 valid (-Y 1) or invalid (-Y 0)
600 -F n : summarize the backtraces at frame level 'n'
601 -Q : be quiet, only summarize
609 if config
['verbosity'] > vHUMAN
:
611 if "-Q" in cmd_options
:
613 if "-V" in cmd_options
:
615 if "-Y" in cmd_options
:
616 opt_post_type
= unsigned(cmd_options
["-Y"])
617 if opt_post_type
!= 0 and opt_post_type
!= 1:
618 raise ArgumentError("Invalid POST obj specifier [-Y %d] (expected 0 or 1)" % cmd_options
["-Y"])
619 if "-F" in cmd_options
:
620 opt_bt_idx
= unsigned(cmd_options
["-F"])
621 if hasattr(kern
.globals, "g_nwaitq_btframes"):
622 if opt_bt_idx
>= unsigned(kern
.globals.g_nwaitq_btframes
):
623 raise ArgumentError("Invalid BT index '{:s}' max:{:d}".format(cmd_options
["-F"], unsigned(kern
.globals.g_nwaitq_btframes
) - 1))
624 if "-T" in cmd_options
:
625 opt_type_filt
= cmd_options
["-T"]
626 if opt_type_filt
== "FREE" or opt_type_filt
== "RSVD":
628 elif opt_type_filt
== "POST":
629 opt_type_filt
= "LINK"
630 elif opt_type_filt
== "WQ":
631 opt_type_filt
= "ELEM"
633 raise ArgumentError("Invalid type filter'{:s}'".format(cmd_options
["-T"]))
634 table
= kern
.globals.g_prepost_table
635 nelem
= int(table
.nelem
)
642 hdr_str
= "Looking through {:d} objects from g_prepost_table@{:<#x}".format(nelem
, addressof(kern
.globals.g_prepost_table
))
643 if opt_type_filt
!= "" or opt_valid_only
!= 0:
644 hdr_str
+= "\n\t`-> for "
649 if opt_type_filt
== "":
652 hdr_str
+= "{:s} objects".format(cmd_options
["-T"])
655 print GetWaitqPrepostSummary
.header
658 wqp
= GetWaitqPrepost(id)[0]
660 print "<<<invalid prepost:{:d}>>>".format(id)
663 lt
= WaitqTableElemType(wqp
)
664 isvalid
= WaitqTableElemValid(wqp
)
666 if isvalid
and opt_post_type
> -1 and lt
== "LINK":
667 post_wqp
= GetWaitqPrepost(wqp
.wqp_post
.wqp_wq_id
)[0]
668 post_valid
= WaitqTableElemValid(post_wqp
)
669 if opt_post_type
== 0 and post_valid
: # only count _invalid_ POST objects
671 elif opt_post_type
== 1 and not post_valid
: # only count _valid_ POST objects
673 if should_count
and (opt_type_filt
== "" or opt_type_filt
== lt
) and ((opt_valid_only
== 0 or isvalid
)):
684 if hasattr(wqp
, 'wqp_alloc_bt'):
685 pc
= unsigned(wqp
.wqp_alloc_bt
[opt_bt_idx
])
688 if pc_str
in bt_summary
:
689 bt_summary
[pc_str
] += 1
691 bt_summary
[pc_str
] = 1
693 print GetWaitqPrepostSummary(wqp
)
695 sys
.stderr
.write('id: {:d}/{:d}... \r'.format(id, nelem
))
697 nused
= nwq
+ npost
+ nrsvd
698 nfound
= nused
+ nfree
+ ninv
699 print "\nFound {:d} objects: {:d} WQ, {:d} POST, {:d} RSVD, {:d} FREE".format(nfound
, nwq
, npost
, nrsvd
, nfree
)
700 if (opt_type_filt
== "" and opt_valid_only
== 0) and (nused
!= table
.used_elem
):
701 print"\tWARNING: inconsistent state! Table reports {:d}/{:d} used elem, found {:d}/{:d}".format(table
.used_elem
, nelem
, nused
, nfound
)
702 if len(bt_summary
) > 0:
703 print "Link allocation BT (frame={:d})".format(opt_bt_idx
)
704 for k
,v
in bt_summary
.iteritems():
705 print "\t[{:d}] from: {:s}".format(v
, GetSourceInformationForAddress(unsigned(k
)))
706 # EndMacro: showallpreposts
709 @lldb_type_summary(['wq_prepost', 'wq_prepost *'])
710 @header("{:<18s} {:<18s} {:<19s} {:<10s} {:<1s} {:<4s} {:<10s} {:<20s}".format('addr','id','idx','gen','V','type','refcnt','info'))
711 def GetWaitqPrepostSummary(wqp
):
714 fmt_str
= "{w: <#18x} {w.wqte.wqt_id.id: <#18x} {w.wqte.wqt_id.idx: <7d} (->{w.wqte.wqt_next_idx: <7d}) {w.wqte.wqt_id.generation: <#10x} {v: <1s} {t: <4s} {rcnt: <10d} "
715 type = WaitqTableElemType(wqp
)
721 if WaitqTableElemValid(wqp
):
723 refcnt
= WaitqTableElemRefcnt(wqp
)
724 out_str
= fmt_str
.format(w
=wqp
, v
=v
, t
=type, rcnt
=refcnt
)
726 out_str
+= "wq:{0: <#18x}".format(unsigned(wqp
.wqp_wq
.wqp_wq_ptr
))
728 out_str
+= "next:{0: <#18x}, wqid:{1: <#18x}".format(wqp
.wqp_post
.wqp_next_id
, wqp
.wqp_post
.wqp_wq_id
)
729 post_wqp
= GetWaitqPrepost(wqp
.wqp_post
.wqp_wq_id
)[0]
730 if not WaitqTableElemValid(post_wqp
):
731 out_str
+= "(<invalid>)"
733 if WaitqTableElemType(post_wqp
) != "ELEM":
734 out_str
+= "(!WQP_WQ?)"
736 out_str
+= "({0: <#18x})".format(unsigned(post_wqp
.wqp_wq
.wqp_wq_ptr
))
741 @lldb_command('showprepost', "P:")
742 def ShowPrepost(cmd_args
=None, cmd_options
={}):
743 """ Print prepost structure summary
745 Note: you can pass either a complete ID (generation + index), or
746 just the index to the -P argument.
748 usage: showprepost [-P ID] [0xaddr]
749 -P {ID} : show prepost structure whose ID is {ID}
752 if "-P" in cmd_options
:
753 wqp
, warn_str
= GetWaitqPrepost(unsigned(kern
.GetValueFromAddress(cmd_options
["-P"], 'uint64_t *')))
756 raise LookupError(warn_str
)
758 raise ArgumentError("Invalid prepost ID {:s}".format(cmd_options
["-P"]))
761 raise ArgumentError("Please pass the address of a prepost object")
762 wqp
= kern
.GetValueFromAddress(cmd_args
[0], 'wq_prepost *')
764 raise ArgumentError("Invalid prepost {:s}".format(cmd_args
[0]))
766 print GetWaitqPrepostSummary
.header
767 print GetWaitqPrepostSummary(wqp
)
768 # EndMacro: showprepost
771 def WaitqPrepostFromObj(wqp
, head_id
, inv_ok
, prepost_str
, pp_arr
= 0, depth
= 0):
774 etype
= WaitqTableElemType(wqp
)
775 if not WaitqTableElemValid(wqp
) and not inv_ok
:
778 id = wqp
.wqte
.wqt_id
.id
779 prepost_str
.append("{0: <#18x}:{1: <18s}".format(id, "<invalid>"))
781 if etype
== "ELEM": # WQP_WQ
782 prepost_str
.append("{0: <#18x}:{1: <#18x}".format(wqp
.wqte
.wqt_id
.id, unsigned(wqp
.wqp_wq
.wqp_wq_ptr
)))
787 if etype
== "LINK": # WQP_POST
788 next_id
= wqp
.wqp_post
.wqp_next_id
789 post_wq
= GetWaitqPrepost(wqp
.wqp_post
.wqp_wq_id
)[0]
790 if WaitqTableElemValid(post_wq
):
791 if WaitqTableElemType(post_wq
) != "ELEM":
792 prepost_str
.append("{0: <#18x}:{1: <18s}".format(post_wq
.wqte
.wqt_id
.id, "<invalid post>"))
794 prepost_str
.append("{0: <#18x}:{1: <#18x}".format(wqp
.wqte
.wqt_id
.id, unsigned(post_wq
.wqp_wq
.wqp_wq_ptr
)))
795 if next_id
> 0 and next_id
!= head_id
:
797 prepost_str
.append("{: <37s}".format("!recursion limit!"))
799 WaitqPrepostFromObj(GetWaitqPrepost(next_id
)[0], head_id
, inv_ok
, prepost_str
, pp_arr
, depth
+ 1)
800 else: # "RSVD" or "FREE":
801 prepost_str
.append("{0: <#18x} -> {1: <15d}".format(wqp
.wqte
.wqt_id
.id, wqp
.wqte
.wqt_next_idx
))
802 next_id
= wqp
.wqte
.wqt_next_idx
803 max_elem
= int(kern
.globals.g_prepost_table
.nelem
)
804 if hasattr(kern
.globals, 'g_wqt_idx_max'):
805 max_elem
= unsigned(kern
.globals.g_wqt_idx_max
)
806 if next_id
< max_elem
:
808 prepost_str
.append("{: <37s}".format("!recursion limit!"))
810 WaitqPrepostFromObj(GetWaitqPrepost(next_id
)[0], head_id
, inv_ok
, prepost_str
, pp_arr
, depth
+ 1)
813 def GetPrepostChain(head_id
, inv_ok
= False, pp_arr
= 0):
815 if unsigned(head_id
) == 0:
816 return [ "{0: <#18x}:{1: <18s}".format(head_id
, "<invalid>") ]
817 wqp
= GetWaitqPrepost(head_id
)[0]
819 WaitqPrepostFromObj(wqp
, head_id
, inv_ok
, pp
, pp_arr
)
821 return [ "{0: <#18x}:{1: <18s}".format(head_id
, "<invalid>") ]
824 def GetWaitqPreposts(waitq
):
825 if GetWaitqStateStr(waitq
) != "SET":
827 wqset
= Cast(waitq
, 'waitq_set *')
828 if wqset
.wqset_prepost_id
== 0:
830 return GetPrepostChain(wqset
.wqset_prepost_id
)
833 # Macro: showprepostchain
834 @lldb_command('showprepostchain', "P:")
835 def ShowPrepostChain(cmd_args
=None, cmd_options
={}):
836 """ Follow a chain of preposts, printing each one.
837 Note that prepost chains are circular, so this will print
838 the entire chain given a single element.
840 Note: you can pass either a complete ID (generation + index), or
841 just the index to the -P argument.
843 usage: showprepostchain [-P ID] [0xaddr]
844 -P {ID} : start printing with the prepost whose ID is {ID}
847 if "-P" in cmd_options
:
848 wqp
, warn_str
= GetWaitqPrepost(unsigned(kern
.GetValueFromAddress(cmd_options
["-P"], 'uint64_t *')))
851 raise LookupError(warn_str
)
853 raise ArgumentError("Invalid prepost ID {:s}".format(cmd_options
["-P"]))
856 raise ArgumentError("Please pass the address of a prepost object")
857 wqp
= kern
.GetValueFromAddress(cmd_args
[0], 'wq_prepost *')
859 raise ArgumentError("Invalid prepost {:s}".format(cmd_args
[0]))
862 GetPrepostChain(wqp
.wqte
.wqt_id
.id, True, pp_arr
)
867 print GetWaitqPrepostSummary
.header
869 print GetWaitqPrepostSummary(pp_arr
[idx
])
871 type = WaitqTableElemType(pp_arr
[idx
])
873 post_wqp
= GetWaitqPrepost(pp_arr
[idx
].wqp_post
.wqp_wq_id
)[0]
874 if not WaitqTableElemValid(post_wqp
):
882 print "Total: {:d} ({:d} valid, {:d} invalid)".format(len(pp_arr
), nvalid
, ninvalid
)
883 # EndMacro: showprepostchain
886 @lldb_type_summary(['waitq', 'waitq *'])
887 @header("{: <16s} {: <3s} {: <4s} {: <17s} {: <18s} {: <18s} {: <37s} {: <22s} {: <10s}".format('waitq', 'typ', 'bits', 'evtmask', 'setid', 'wq_wqp', 'preposts', 'member_of', 'threads'))
888 def GetWaitqSummary(waitq
):
889 fmt_str
= "{q: <16x} {state: <3s} {bits: <4s} {q.waitq_eventmask: <#17x} {setid: <#18x} {q.waitq_prepost_id: <#18x}"
891 if waitq
.waitq_queue
.next
and waitq
.waitq_queue
.prev
:
892 for thread
in IterateLinkageChain(addressof(waitq
.waitq_queue
), 'thread *', 'links'):
893 th_str
.append("{: <18s} e:{: <#18x}".format(hex(thread
), thread
.wait_event
))
895 th_str
.append("{: <39s}".format('<invalid (NULL) queue>'))
897 set_str
= GetWaitqSets(waitq
)
898 set_cnt
= len(set_str
)
899 pp_str
= GetWaitqPreposts(waitq
)
903 while idx
< pp_cnt
or idx
< set_cnt
or idx
< th_cnt
:
914 last_str
+= "{0: <37s} {1: <22s} {2: <39s}".format(p
, s
, t
)
916 last_str
+= "\n{0: <80s} {1: <37s} {2: <22s} {3: <39s}".format('', p
, s
, t
)
918 if pp_cnt
> 0 or set_cnt
> 0 or th_cnt
> 0:
919 last_str
+= "\n{:<80s} {: <37s} {: <22s} {: <39s}".format('', '-'*37, '-'*20, '-'*39)
920 last_str
+= "\n{0: <80s} {1: <37d} {2: <22d} {3: <39d}".format('', pp_cnt
, set_cnt
, th_cnt
)
922 state
= GetWaitqStateStr(waitq
)
925 setid
= Cast(waitq
, 'waitq_set *').wqset_id
926 out_str
= fmt_str
.format(q
=waitq
, state
=state
, bits
=GetWaitqBitsStr(waitq
), setid
=setid
)
931 @lldb_command('showwaitq', "P:S:")
932 def ShowWaitq(cmd_args
=None, cmd_options
={}):
933 """ Print waitq structure summary.
934 Lookup the waitq either by address, by Set ID, or indirectly
935 through a prepost object that points to the waitq.
937 Note: you can pass either a complete ID (generation + index), or
938 just the index to the -P and -S arguments.
940 usage: showwaitq [-P PrePostID] [-S SetID] [0xaddr]
941 -P {ID} : prepost ID that points to a waitq
942 -S {ID} : waitq_set ID
945 if "-P" in cmd_options
:
946 wqp
, warn_str
= GetWaitqPrepost(unsigned(kern
.GetValueFromAddress(cmd_options
["-P"], 'uint64_t *')))
949 raise LookupError(warn_str
)
951 raise ArgumentError("Invalid prepost ID {:s}".format(cmd_options
["-P"]))
952 if WaitqTableElemType(wqp
) != "ELEM":
953 raise ArgumentError("Prepost ID {:s} points to a WQP_POST object, not a WQP_WQ!".format(cmd_options
["-P"]))
954 waitq
= wqp
.wqp_wq
.wqp_wq_ptr
955 if "-S" in cmd_options
:
957 raise ArgumentError("Please pass only one of '-S' or '-P'!")
958 link
, warn_str
= GetWaitqLink(unsigned(kern
.GetValueFromAddress(cmd_options
["-S"],'uint64_t *')))
961 raise LookupError(warn_str
)
963 raise ArgumentError("Invalid link ID {:s}".format(cmd_options
["-S"]))
964 if WaitqTableElemType(link
) != "ELEM":
965 raise ArgumentError("Link ID {:s} points to a SLT_LINK object, not an SLT_WQS!".format(cmd_options
["-S"]))
966 waitq
= addressof(link
.sl_wqs
.sl_set
.wqset_q
)
968 if not waitq
and not cmd_args
:
969 raise ArgumentError("Please pass the address of a waitq!")
971 waitq
= kern
.GetValueFromAddress(cmd_args
[0], 'waitq *')
973 raise ("Unknown arguments: %r %r" % (cmd_args
, cmd_options
))
974 print GetWaitqSummary
.header
975 print GetWaitqSummary(waitq
)
976 # EndMacro: showwaitq
979 # Macro: showglobalwaitqs
980 @lldb_command('showglobalwaitqs')
981 def ShowGlobalWaitqs(cmd_args
=None):
982 """ Summarize global waitq usage
987 print "Global waitq objects"
988 print GetWaitqSummary
.header
990 while q
< kern
.globals.g_num_waitqs
:
991 print GetWaitqSummary(addressof(kern
.globals.global_waitqs
[q
]))
993 # EndMacro: showglobalwaitqs
996 # Macro: showglobalqstats
997 @lldb_command('showglobalqstats', "OF")
998 def ShowGlobalQStats(cmd_args
=None, cmd_options
={}):
999 """ Summarize global waitq statistics
1001 usage: showglobalqstats [-O] [-F]
1002 -O : only output waitqs with outstanding waits
1003 -F : output as much backtrace as was recorded
1008 if not hasattr(kern
.globals, 'g_waitq_stats'):
1009 print "No waitq stats support (use DEVELOPMENT kernel)!"
1012 print "Global waitq stats"
1013 print "{0: <18s} {1: <8s} {2: <8s} {3: <8s} {4: <8s} {5: <8s} {6: <32s}".format('waitq', '#waits', '#wakes', '#diff', '#fails', '#clears', 'backtraces')
1015 waiters_only
= False
1017 if "-O" in cmd_options
:
1019 if "-F" in cmd_options
:
1022 fmt_str
= "{q: <#18x} {stats.waits: <8d} {stats.wakeups: <8d} {diff: <8d} {stats.failed_wakeups: <8d} {stats.clears: <8d} {bt_str: <s}"
1023 while q
< kern
.globals.g_num_waitqs
:
1024 waitq
= kern
.globals.global_waitqs
[q
]
1025 stats
= kern
.globals.g_waitq_stats
[q
]
1026 diff
= stats
.waits
- stats
.wakeups
1027 if diff
== 0 and waiters_only
:
1033 if (stats
.last_wait
[0]):
1034 last_waitstr
= GetSourceInformationForAddress(unsigned(stats
.last_wait
[0]))
1035 if (stats
.last_wakeup
[0]):
1036 last_wakestr
= GetSourceInformationForAddress(unsigned(stats
.last_wakeup
[0]))
1037 if (stats
.last_failed_wakeup
[0]):
1038 fw_str
= GetSourceInformationForAddress(unsigned(stats
.last_failed_wakeup
[0]))
1042 while f
< kern
.globals.g_nwaitq_btframes
:
1043 if stats
.last_wait
[f
]:
1044 last_waitstr
= "{0}->{1}".format(GetSourceInformationForAddress(unsigned(stats
.last_wait
[f
])), last_waitstr
)
1045 if stats
.last_wakeup
[f
]:
1046 last_wakestr
= "{0}->{1}".format(GetSourceInformationForAddress(unsigned(stats
.last_wakeup
[f
])), last_wakestr
)
1047 if stats
.last_failed_wakeup
[f
]:
1048 fw_str
= "{0}->{1}".format(GetSourceInformationForAddress(unsigned(stats
.last_failed_wakeup
[f
])), fw_str
)
1052 bt_str
+= "wait : " + last_waitstr
1055 bt_str
+= "\n{0: <70s} ".format('')
1056 bt_str
+= "wake : " + last_wakestr
1059 bt_str
+= "\n{0: <70s} ".format('')
1060 bt_str
+= "fails: " + fw_str
1062 print fmt_str
.format(q
=addressof(waitq
), stats
=stats
, diff
=diff
, bt_str
=bt_str
)
1064 # EndMacro: showglobalqstats