in tools/lldbmacros/waitq.py [0:0]
def ShowAllSetidLinks(cmd_args=None, cmd_options={}):
""" Dump / summarize all waitq set linktable elements
usage: showallsetidlinks [options]
-V {0,1} : only show [1 == valid/live links, 0 == invalid links]
-T {type} : only display objects of type {type}
-S {desc} : only display objects of type {type} which fit {desc}
-T LINK -S {desc} can be:
iL : Invalid left-link pointer (only)
iR : Invalid right-link pointer (only)
iLR : Invalid left+right link pointers
iLRI : Invalid left+right link pointers AND dead allocating process
w/o "-T" -S {desc} can be:
iP : Invalid / Dead allocating process
-F n : summarize the backtraces at frame level 'n'
-X : cross-check waitq pointers in link table
-Q : be quiet, only summarize
"""
opt_summary = 0
opt_type_filt = ""
opt_valid_only = 0
opt_invalid_only = 0
opt_bt_idx = 0
opt_cross_check = 0
opt_validate_links = 0
opt_subtype_filter = 0
verbose = False
if config['verbosity'] > vHUMAN:
verbose = True
if "-Q" in cmd_options:
opt_summary = 1
if "-V" in cmd_options:
if int(cmd_options["-V"]) == 1:
opt_valid_only = 1
elif int(cmd_options["-V"]) == 0:
opt_invalid_only = 1
else:
raise ArgumentError("Invalid parameter to -V '{:s}': expecting 0 or 1".format(cmd_options["-V"]))
if "-X" in cmd_options:
opt_cross_check = 1
nunique_wqs = 0
nduplicated_wqs = 0
max_wqs_dupes = 0
if "-F" in cmd_options:
opt_bt_idx = unsigned(cmd_options["-F"])
if hasattr(kern.globals, "g_nwaitq_btframes"):
if opt_bt_idx >= unsigned(kern.globals.g_nwaitq_btframes):
raise ArgumentError("Invalid BT index '{:s}' max:{:d}".format(cmd_options["-F"], unsigned(kern.globals.g_nwaitq_btframes) - 1))
if "-T" in cmd_options:
opt_type_filt = cmd_options["-T"]
if opt_type_filt == "FREE" or opt_type_filt == "RSVD" or opt_type_filt == "LINK":
pass
elif opt_type_filt == "WQS":
opt_type_filt = "ELEM"
else:
raise ArgumentError("Invalid type filter'{:s}'".format(cmd_options["-T"]))
if "-S" in cmd_options:
opt_subtype_filter = cmd_options["-S"]
if opt_type_filt == "LINK":
if not (opt_subtype_filter == "iL" or \
opt_subtype_filter == "iR" or \
opt_subtype_filter == "iLR" or \
opt_subtype_filter == "iLRI"):
raise ArgumentError("Invalid LINK sub-type filter \{desc\}: {:s}".format(opt_subtype_filter))
elif opt_type_filt == "":
if not opt_subtype_filter == "iP":
raise ArgumentError("Invalid sub-type filter \{desc\}: {:s}".format(opt_subtype_filter))
table = kern.globals.g_wqlinktable
nelem = int(table.nelem)
wq_ptr = {}
bt_summary = {}
nfree = 0
ninv = 0
nwqs = 0
nlink = 0
nrsvd = 0
hdr_str = "Looking through {:d} waitq_link objects from g_wqlinktable@{:<#x}".format(nelem, addressof(kern.globals.g_wqlinktable))
if opt_type_filt != "" or opt_valid_only != 0:
hdr_str += "\n\t`-> for "
if opt_valid_only:
hdr_str += "valid "
else:
hdr_str += "all "
if opt_type_filt == "":
hdr_str += "objects"
else:
hdr_str += "{:s} objects".format(opt_type_filt)
else:
if opt_valid_only:
hdr_str += "\n\t`-> showing only VALID links"
elif opt_invalid_only:
hdr_str += "\n\t`-> showing only INVALID links"
if opt_subtype_filter != 0:
if opt_type_filt != "LINK" and opt_type_filt != "":
raise ArgumentError("Subtype (-S {desc}) can only be used with (-T LINK) or no type filter at all")
hdr_str += "\n\t`-> filtering {:s} objects through '{:s}'".format(opt_type_filt, opt_subtype_filter)
if opt_cross_check:
hdr_str += "\n\t`-> cross-checking WQS elements for duplicates"
hdr_str += "\n\n"
print hdr_str
if not opt_summary:
print GetWaitqSetidLinkSummary.header
id = 0
while id < nelem:
if id == 0:
# Set a generation count to differentiate from an invalid ID
first_entry = Cast(kern.globals.g_wqlinktable.table[0], 'lt_elem *')
link = GetWaitqLink(first_entry.lt_id.id)[0]
else:
link = GetWaitqLink(id)[0]
if not link:
print "<<<invalid link:{:d}>>>".format(id)
ninv += 1
else:
lt = WaitqTableElemType(link)
isvalid = WaitqTableElemValid(link)
inconsistent = 0
do_print = not ( (isvalid and opt_invalid_only) or (not isvalid and opt_valid_only) )
if do_print and opt_subtype_filter != 0 and lt == "LINK":
lID = link.wql_link.left_setid
rID = link.wql_link.right_setid
left = GetWaitqLink(lID)[0]
right = GetWaitqLink(rID)[0]
lValid = WaitqTableElemValid(left)
rValid = WaitqTableElemValid(right)
if opt_subtype_filter == "iL":
if lValid or (not lValid and not rValid):
do_print = False
elif opt_subtype_filter == "iR":
if rValid or (not rValid and not lValid):
do_print = False
elif opt_subtype_filter == "iLR":
if rValid or lValid:
do_print = False
elif opt_subtype_filter == "iLRI" and hasattr(link, 'sl_alloc_task'):
# only print this if both left and right are invalid
# and the allocating task is unknown/dead
do_print = False
is_dead = 0
pid = -1
try:
pid = GetProcPIDForTask(link.sl_alloc_task)
except:
if link.sl_alloc_task:
pid = unsigned(link.sl_alloc_task.audit_token.val[5])
if pid < 0:
is_dead = 1
else:
pidnm = GetProcNameForPid(pid)
if pidnm == "Unknown":
is_dead = 1
if (not rValid) and (not lValid) and is_dead:
do_print = True
if do_print and opt_type_filt == "" and opt_subtype_filter == "iP" and hasattr(link, 'sl_alloc_task'):
# Only print non-free table objects that were allocated by
# dead processes
do_print = False
is_dead = 0
pid = -1
try:
pid = GetProcPIDForTask(link.sl_alloc_task)
except:
if link.sl_alloc_task:
pid = unsigned(link.sl_alloc_task.audit_token.val[5])
if pid < 0:
is_dead = 1
else:
pidnm = GetProcNameForPid(pid)
if pidnm == "Unknown":
is_dead = 1
if is_dead:
do_print = True
if (opt_type_filt == "" or opt_type_filt == lt) and do_print:
if lt == "ELEM":
nwqs += 1
elif lt == "LINK":
nlink += 1
elif lt == "RSVD":
nrsvd += 1
elif lt == "FREE":
nfree += 1
else:
ninv += 1
inconsistent = 1
if hasattr(link, 'sl_alloc_bt'):
pc = unsigned(link.sl_alloc_bt[opt_bt_idx])
pc_str = str(pc)
if pc > 0:
if pc_str in bt_summary:
bt_summary[pc_str] += 1
else:
bt_summary[pc_str] = 1
if not opt_summary:
print GetWaitqSetidLinkSummary(link, verbose)
if inconsistent:
ninconsistent += 1
# print out warnings about inconsistent state as we parse
# the list - even if the caller wants a summary
print "[WARNING] inconsistent state in idx: {:d} ({:s} element)".format(link.wqte.lt_id.idx, lt)
if opt_cross_check == 1 and lt == "ELEM":
wq = unsigned(addressof(link.wql_wqs.wql_set.wqset_q))
if wq in wq_ptr:
wq_ptr[wq].append(id)
l = len(wq_ptr[wq])
if l == 2:
nduplicated_wqs += 1
if l > max_wqs_dupes:
max_wqs_dupes = l
else:
wq_ptr[wq] = [ id ]
nunique_wqs += 1
id += 1
if opt_summary or verbose:
if verbose and opt_cross_check:
sys.stderr.write('[{:d}|{:d}|{:d}] id: {:d}/{:d}... \r'.format(nunique_wqs, nduplicated_wqs, max_wqs_dupes, id, nelem))
else:
sys.stderr.write('id: {:d}/{:d}... \r'.format(id, nelem))
nused = nwqs + nlink + nrsvd
nfound = nused + nfree + ninv
print "\n\nFound {:d} objects: {:d} WQS, {:d} LINK, {:d} RSVD, {:d} FREE".format(nfound, nwqs, nlink, nrsvd, nfree)
if (opt_type_filt == "" and opt_valid_only == 0) and (nused != table.used_elem):
print"\tWARNING: inconsistent state! Table reports {:d}/{:d} used elem, found {:d}/{:d}".format(table.used_elem, nelem, nused, nfound)
if len(bt_summary) > 0:
print "Link allocation BT (frame={:d})".format(opt_bt_idx)
for k,v in bt_summary.iteritems():
print "\t[{:d}] from: {:s}".format(v, GetSourceInformationForAddress(unsigned(k)))
if opt_cross_check:
print "\n{:d} Duplicated WQS objects:".format(nduplicated_wqs)
for wq in wq_ptr:
l = len(wq_ptr[wq])
if l > 1:
print "\tWQS:{:#x} ({:d} {:s}".format(wq, l, str(wq_ptr[wq]))