X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/813fb2f63a553c957e917ede5f119b021d6ce391..d9a64523371fa019c4575bb400cbbc3a50ac9903:/tools/lldbmacros/process.py diff --git a/tools/lldbmacros/process.py b/tools/lldbmacros/process.py old mode 100644 new mode 100755 index 906d47a7f..f37169a3b --- a/tools/lldbmacros/process.py +++ b/tools/lldbmacros/process.py @@ -9,6 +9,7 @@ from utils import * from core.lazytarget import * import time import xnudefines +import memory def GetProcNameForTask(task): """ returns a string name of the process. if proc is not valid "unknown" is returned @@ -170,22 +171,26 @@ def GetASTSummary(ast): B - AST_BSD K - AST_KPERF M - AST_MACF - C - AST_CHUD - C - AST_CHUD_URGENT G - AST_GUARD T - AST_TELEMETRY_USER T - AST_TELEMETRY_KERNEL T - AST_TELEMETRY_WINDOWED S - AST_SFI + D - AST_DTRACE + I - AST_TELEMETRY_IO + E - AST_KEVENT + R - AST_REBALANCE + N - AST_UNQUIESCE """ out_string = "" state = int(ast) thread_state_chars = {0x0:'', 0x1:'P', 0x2:'Q', 0x4:'U', 0x8:'H', 0x10:'Y', 0x20:'A', - 0x40:'L', 0x80:'B', 0x100:'K', 0x200:'M', 0x400:'C', 0x800:'C', - 0x1000:'G', 0x2000:'T', 0x4000:'T', 0x8000:'T', 0x10000:'S'} + 0x40:'L', 0x80:'B', 0x100:'K', 0x200:'M', + 0x1000:'G', 0x2000:'T', 0x4000:'T', 0x8000:'T', 0x10000:'S', + 0x20000: 'D', 0x40000: 'I', 0x80000: 'E', 0x100000: 'R', 0x200000: 'N'} state_str = '' mask = 0x1 - while mask <= 0x10000: + while mask <= 0x80000: state_str += thread_state_chars[int(state & mask)] mask = mask << 1 @@ -216,6 +221,8 @@ def GetTaskSummary(task, showcorpse=False): task_flags = '' if hasattr(task, "suppression_generation") and (int(task.suppression_generation) & 0x1) == 0x1: task_flags += 'P' + if hasattr(task, "effective_policy") and int(task.effective_policy.tep_sup_active) == 1: + task_flags += 'N' if hasattr(task, "suspend_count") and int(task.suspend_count) > 0: task_flags += 'S' if hasattr(task, 'task_imp_base') and unsigned(task.task_imp_base): @@ -380,6 +387,8 @@ def GetCoalitionFlagString(coal): flags.append('reaped') if (coal.notified): flags.append('notified') + if (coal.efficient): + flags.append('efficient') return "|".join(flags) def GetCoalitionTasks(queue, coal_type, thread_details=False): @@ -441,6 +450,15 @@ def GetResourceCoalitionSummary(coal, verbose=False): out_string += "\t bytesread {0: vHUMAN: verbose = True if not cmd_args: - print "No arguments passed" - print ShowCoalitionInfo.__doc__ - return False + raise ArgumentError("No arguments passed") coal = kern.GetValueFromAddress(cmd_args[0], 'coalition *') if not coal: print "unknown arguments:", str(cmd_args) @@ -536,6 +553,34 @@ def ShowAllCoalitions(cmd_args=None): # EndMacro: showallcoalitions +# Macro: showallthreadgroups + +@lldb_type_summary(['struct thread_group *', 'thread_group *']) +@header("{0: <20s} {1: <5s} {2: <16s} {3: <5s} {4: <8s} {5: <20s}".format("thread_group", "id", "name", "refc", "flags", "recommendation")) +def GetThreadGroupSummary(tg): + if unsigned(tg) == 0: + return '{0: <#020x} {1: <5d} {2: <16s} {3: <5d} {4: <8s} {5: <20d}'.format(0, -1, "", -1, "", -1) + out_string = "" + format_string = '{0: <#020x} {1: <5d} {2: <16s} {3: <5d} {4: <8s} {5: <20d}' + tg_flags = '' + if (tg.tg_flags & 0x1): + tg_flags += 'E' + if (tg.tg_flags & 0x2): + tg_flags += 'U' + out_string += format_string.format(tg, tg.tg_id, tg.tg_name, tg.tg_refcount, tg_flags, tg.tg_recommendation) + return out_string + +@lldb_command('showallthreadgroups') +def ShowAllThreadGroups(cmd_args=None): + """ Print a summary listing of all thread groups + """ + global kern + print GetThreadGroupSummary.header + for tg in kern.thread_groups: + print GetThreadGroupSummary(tg) + +# EndMacro: showallthreadgroups + # Macro: showtaskcoalitions @lldb_command('showtaskcoalitions', 'F:') @@ -645,47 +690,6 @@ def GetTTYDevSummary(tty_dev): out_string += format_string.format(tty_dev, tty_dev.master, tty_dev.slave, open_fn, free_fn, name_fn, revoke_fn) return out_string -@lldb_type_summary(['kqueue *']) -@header("{: <20s} {: <20s} {: <6s} {: <20s} {: <10s}".format('kqueue', 'process', '#events', 'wqs', 'state')) -def GetKQueueSummary(kq): - """ summarizes kqueue information - returns: str - summary of kqueue - """ - out_string = "" - format_string = "{o: <#020x} {o.kq_p: <#020x} {o.kq_count: <6d} {wqs: <#020x} {st_str: <10s}" - state = int(kq.kq_state) - state_str = '' - mask = 0x1 - while mask <= 0x80 : - if int(state & mask): - state_str += ' ' + xnudefines.kq_state_strings[int(state & mask)] - mask = mask << 1 - out_string += format_string.format(o=kq, wqs=addressof(kq.kq_wqs), st_str=state_str) - out_string += "\n" + GetKnoteSummary.header - for kn in IterateTAILQ_HEAD(kq.kq_head, 'kn_tqe'): - out_string += "\n" + GetKnoteSummary(kn) - return out_string - -@lldb_type_summary(['knote *']) -@header("{0: <20s} {1: <10s} {2: <10s} {3: <20s} {4: <20s} {5: <30s}".format('knote', 'ident', 'kev_flags', 'kn_kq', 'filtops', ' status')) -def GetKnoteSummary(kn): - """ Summarizes a knote and related information - returns: str - summary of knote - """ - out_string = "" - format_string = "{o: <#020x} {o.kn_kevent.ident: <#010X} {o.kn_kevent.flags: <#010X} {o.kn_kq: <#020X} {ops_str: <20s} {st_str: <30s}" - state = unsigned(kn.kn_status) - fops_str = kern.Symbolicate(unsigned(kn.kn_fop)) - mask = 0x1 - status_desc = '' - while mask <= 0x40: - if state & mask: - status_desc += ' ' + xnudefines.kn_state_strings[int(state & mask)] - mask = mask << 1 - - out_string += format_string.format(o=kn, st_str=status_desc, ops_str=fops_str) - return out_string - # Macro: showtask @lldb_command('showtask', 'F:') @@ -721,9 +725,7 @@ def ShowPid(cmd_args=None): Usage: showpid """ if not cmd_args: - print "No arguments passed" - print ShowPid.__doc__ - return False + raise ArgumentError("No arguments passed") pidval = ArgumentStringToInt(cmd_args[0]) for t in kern.tasks: pval = Cast(t.bsd_info, 'proc *') @@ -742,9 +744,7 @@ def ShowProc(cmd_args=None): Usage: showproc
""" if not cmd_args: - print "No arguments passed" - print ShowProc.__doc__ - return False + raise ArgumentError("No arguments passed") pval = kern.GetValueFromAddress(cmd_args[0], 'proc *') if not pval: print "unknown arguments:", str(cmd_args) @@ -764,9 +764,7 @@ def ShowProcInfo(cmd_args=None): Usage: showprocinfo
""" if not cmd_args: - print "No arguments passed" - print ShowProcInfo.__doc__ - return False + raise ArgumentError("No arguments passed") pval = kern.GetValueFromAddress(cmd_args[0], 'proc *') if not pval: print "unknown arguments:", str(cmd_args) @@ -796,17 +794,6 @@ def ShowProcFiles(cmd_args=None): print "{0:-<5s} {0:-<18s} {0:-<10s} {0:-<8s} {0:-<18s} {0:-<64s}".format("") count = 0 - # Filetype map - filetype_dict = { - 1: 'VNODE', - 2: 'SOCKET', - 3: 'PSXSHM', - 4: 'PSXSEM', - 5: 'KQUEUE', - 6: 'PIPE', - 7: 'FSEVENTS' - } - while count <= proc_lastfile: if unsigned(proc_ofiles[count]) != 0: out_str = '' @@ -816,8 +803,8 @@ def ShowProcFiles(cmd_args=None): out_str += "{0: <#18x} ".format(unsigned(proc_fd_fglob)) out_str += "0x{0:0>8x} ".format(unsigned(proc_fd_flags)) proc_fd_ftype = unsigned(proc_fd_fglob.fg_ops.fo_type) - if proc_fd_ftype in filetype_dict: - out_str += "{0: <8s} ".format(filetype_dict[proc_fd_ftype]) + if proc_fd_ftype in xnudefines.filetype_strings: + out_str += "{0: <8s} ".format(xnudefines.filetype_strings[proc_fd_ftype]) else: out_str += "?: {0: <5d} ".format(proc_fd_ftype) out_str += "{0: <#18x} ".format(unsigned(proc_fd_fglob.fg_data)) @@ -830,66 +817,6 @@ def ShowProcFiles(cmd_args=None): #EndMacro: showprocfiles - -def GetProcKqueues(proc): - filetype_KQUEUE = 5 - - proc_filedesc = proc.p_fd - proc_lastfile = unsigned(proc_filedesc.fd_lastfile) - proc_ofiles = proc_filedesc.fd_ofiles - - queues = list() - - if unsigned(proc_ofiles) == 0: - return queues - - count = 0 - - while count <= proc_lastfile: - if unsigned(proc_ofiles[count]) != 0: - proc_fd_flags = proc_ofiles[count].f_flags - proc_fd_fglob = proc_ofiles[count].f_fglob - proc_fd_ftype = unsigned(proc_fd_fglob.fg_ops.fo_type) - if proc_fd_ftype == filetype_KQUEUE: - q = Cast(proc_fd_fglob.fg_data, 'struct kqueue *') - queues.append(q) - count += 1 - - return queues - -def GetAllKqueues(): - for t in kern.tasks: - if unsigned(t.bsd_info) == 0: - continue - pval = Cast(t.bsd_info, 'proc *') - for kq in GetProcKqueues(pval): - yield kq - -#Macro: showallkqueues -@lldb_command('showallkqueues' ,'') -def ShowAllKqueues(cmd_args=[], cmd_options={}): - """ Display a summary of all the kqueues in the system """ - for kq in GetAllKqueues(): - print GetKQueueSummary.header - print GetKQueueSummary(kq) - print "\n\n" -#EndMacro: showallkqueues - -#Macro: showkqueue -@lldb_command('showkqueue' ,'') -def ShowKQueue(cmd_args=[], cmd_options={}): - """ Given a struct kqueue pointer, display the summary of the kqueue - Usage: (lldb) showkqueue - """ - if not cmd_args: - raise ArgumentError('Invalid arguments') - - kq = kern.GetValueFromAddress(cmd_args[0], 'struct kqueue *') - print GetKQueueSummary.header - print GetKQueueSummary(kq) - -#EndMacro: showkqueue - #Macro: showtty @lldb_command('showtty') @@ -1259,10 +1186,8 @@ def ShowAct(cmd_args=None): """ Routine to print out the state of a specific thread. usage: showact """ - if cmd_args == None or len(cmd_args) < 1: - print "No arguments passed" - print ShowAct.__doc__ - return False + if not cmd_args: + raise ArgumentError("No arguments passed") threadval = kern.GetValueFromAddress(cmd_args[0], 'thread *') print GetThreadSummary.header print GetThreadSummary(threadval) @@ -1272,10 +1197,8 @@ def ShowActStack(cmd_args=None): """ Routine to print out the stack of a specific thread. usage: showactstack """ - if cmd_args == None or len(cmd_args) < 1: - print "No arguments passed" - print ShowAct.__doc__.strip() - return False + if not cmd_args: + raise ArgumentError("No arguments passed") threadval = kern.GetValueFromAddress(cmd_args[0], 'thread *') print GetThreadSummary.header print GetThreadSummary(threadval) @@ -1291,10 +1214,8 @@ def SwitchToAct(cmd_args=None): Before resuming execution, issue a "resetctx" command, to return to the original execution context. """ - if cmd_args == None or len(cmd_args) < 1: - print "No arguments passed" - print SwitchToAct.__doc__.strip() - return False + if cmd_args is None or len(cmd_args) < 1: + raise ArgumentError("No arguments passed") thval = kern.GetValueFromAddress(cmd_args[0], 'thread *') lldbthread = GetLLDBThreadForKernelThread(thval) print GetThreadSummary.header @@ -1402,7 +1323,7 @@ def GetFullBackTrace(frame_addr, verbosity = vHUMAN, prefix = ""): # lldb unable to find symbol for _mh_execute_header mh_execute_addr = int(lldb_run_command('p/x (uintptr_t *)&_mh_execute_header').split('=')[-1].strip(), 16) while frame_ptr and frame_ptr != previous_frame_ptr and bt_count < 128: - if (kern.arch not in ('arm', 'arm64') and frame_ptr < mh_execute_addr) or (kern.arch in ('arm', 'arm64') and frame_ptr > mh_execute_addr): + if (not kern.arch.startswith('arm') and frame_ptr < mh_execute_addr) or (kern.arch.startswith('arm') and frame_ptr > mh_execute_addr): break pc_val = kern.GetValueFromAddress(frame_ptr + kern.ptrsize,'uintptr_t *') pc_val = unsigned(dereference(pc_val)) @@ -1581,7 +1502,7 @@ def GetProcessorSummary(processor): preemption_disable_str) return out_str -def GetLedgerEntrySummary(ledger_template, ledger, i): +def GetLedgerEntrySummary(ledger_template, ledger, i, show_footprint_interval_max=False): """ Internal function to get internals of a ledger entry (*not* a ledger itself) params: ledger_template - value representing struct ledger_template_t for the task or thread ledger - value representing struct ledger_entry * @@ -1598,11 +1519,13 @@ def GetLedgerEntrySummary(ledger_template, ledger, i): out_str += "{: >32s} {:<2d}:".format(ledger_template.lt_entries[i].et_key, i) out_str += "{: >15d} ".format(unsigned(ledger.le_credit) - unsigned(ledger.le_debit)) if (ledger.le_flags & lf_tracking_max): - out_str += "{:9d} {:5d} ".format(ledger._le.le_peaks[0].le_max, now - unsigned(ledger._le.le_peaks[0].le_time)) - out_str += "{:9d} {:4d} ".format(ledger._le.le_peaks[1].le_max, now - unsigned(ledger._le.le_peaks[1].le_time)) + if (show_footprint_interval_max): + out_str += "{:12d} ".format(ledger._le._le_max.le_interval_max) + out_str += "{:14d} ".format(ledger._le._le_max.le_lifetime_max) else: - out_str += " - - - - " - + if (show_footprint_interval_max): + out_str += " - " + out_str += " - " out_str += "{:12d} {:12d} ".format(unsigned(ledger.le_credit), unsigned(ledger.le_debit)) if (unsigned(ledger.le_limit) != ledger_limit_infinity): out_str += "{:12d} ".format(unsigned(ledger.le_limit)) @@ -1647,11 +1570,7 @@ def GetThreadLedgerSummary(thread_val): i = i + 1 return out_str -@header("{0: <15s} {1: >16s} {2: <2s} {3: >15s} {4: >9s} {5: >6s} {6: >8s} {7: <10s} {8: <9s} \ - {9: <12s} {10: <7s} {11: <15s} {12: <8s} {13: <9s} {14: <6s} {15: >6s}".format( - "task [thread]", "entry", "#", "balance", "peakA", "(age)", "peakB", "(age)", "credit", - "debit", "limit", "refill period", "lim pct", "warn pct", "over?", "flags")) -def GetTaskLedgers(task_val): +def GetTaskLedgers(task_val, show_footprint_interval_max=False): """ Internal function to get summary of ledger entries from the task and its threads params: task_val - value representing struct task * return: str - formatted output information for ledger entries of the input task @@ -1666,7 +1585,7 @@ def GetTaskLedgers(task_val): else: out_str += "Invalid process:\n" while i != task_ledgerp.l_template.lt_cnt: - out_str += GetLedgerEntrySummary(kern.globals.task_ledger_template, task_ledgerp.l_entries[i], i) + out_str += GetLedgerEntrySummary(kern.globals.task_ledger_template, task_ledgerp.l_entries[i], i, show_footprint_interval_max) i = i + 1 # Now walk threads @@ -1677,11 +1596,14 @@ def GetTaskLedgers(task_val): # Macro: showtaskledgers -@lldb_command('showtaskledgers', 'F:') +@lldb_command('showtaskledgers', 'F:I') def ShowTaskLedgers(cmd_args=None, cmd_options={}): """ Routine to print a summary of ledger entries for the task and all of its threads - Usage: showtaskledgers
- or : showtaskledgers -F + or : showtaskledgers [ -I ] [ -F ] + options: + -I: show footprint interval max (DEV/DEBUG only) + -F: specify task via name instead of address + - """ if "-F" in cmd_options: task_list = FindTasksByName(cmd_options["-F"]) @@ -1692,24 +1614,34 @@ def ShowTaskLedgers(cmd_args=None, cmd_options={}): if not cmd_args: raise ArgumentError("No arguments passed.") + show_footprint_interval_max = False + if "-I" in cmd_options: + show_footprint_interval_max = True tval = kern.GetValueFromAddress(cmd_args[0], 'task *') if not tval: raise ArgumentError("unknown arguments: %r" %cmd_args) - print GetTaskLedgers.header - print GetTaskLedgers(tval) + if (show_footprint_interval_max): + print "{0: <15s} {1: >16s} {2: <2s} {3: >15s} {4: >12s} {5: >14s} {6: >12s} {7: >12s} {8: >12s} {9: <15s} {10: <8s} {11: <9s} {12: <6s} {13: >6s}".format( + "task [thread]", "entry", "#", "balance", "intrvl_max", "lifetime_max", "credit", + "debit", "limit", "refill period", "lim pct", "warn pct", "over?", "flags") + else: + print "{0: <15s} {1: >16s} {2: <2s} {3: >15s} {4: >14s} {5: >12s} {6: >12s} {7: >12s} {8: <15s} {9: <8s} {10: <9s} {11: <6s} {12: >6s}".format( + "task [thread]", "entry", "#", "balance", "lifetime_max", "credit", + "debit", "limit", "refill period", "lim pct", "warn pct", "over?", "flags") + print GetTaskLedgers(tval, show_footprint_interval_max) # EndMacro: showtaskledgers # Macro: showalltaskledgers @lldb_command('showalltaskledgers') -def ShowAllTaskLedgers(cmd_args=None): +def ShowAllTaskLedgers(cmd_args=None, cmd_options={}): """ Routine to print a summary of ledger entries for all tasks and respective threads Usage: showalltaskledgers """ for t in kern.tasks: task_val = unsigned(t) - ShowTaskLedgers([task_val]) + ShowTaskLedgers([task_val], cmd_options=cmd_options) # EndMacro: showalltaskledgers @@ -2151,61 +2083,3 @@ def Showstackafterthread(cmd_args = None): print '\n' return -def FindVMEntriesForVnode(task, vn): - """ returns an array of vme that have the vnode set to defined vnode - each entry in array is of format (vme, start_addr, end_address, protection) - """ - retval = [] - vmmap = task.map - pmap = vmmap.pmap - pager_ops_addr = unsigned(addressof(kern.globals.vnode_pager_ops)) - debuglog("pager_ops_addr %s" % hex(pager_ops_addr)) - - if unsigned(pmap) == 0: - return retval - vme_list_head = vmmap.hdr.links - vme_ptr_type = gettype('vm_map_entry *') - for vme in IterateQueue(vme_list_head, vme_ptr_type, 'links'): - #print vme - if unsigned(vme.is_sub_map) == 0 and unsigned(vme.object.vm_object) != 0: - obj = vme.object.vm_object - else: - continue - - while obj != 0: - if obj.pager != 0: - if obj.internal: - pass - else: - vn_pager = Cast(obj.pager, 'vnode_pager *') - if unsigned(vn_pager.pager_ops) == pager_ops_addr and unsigned(vn_pager.vnode_handle) == unsigned(vn): - retval.append((vme, unsigned(vme.links.start), unsigned(vme.links.end), unsigned(vme.protection))) - obj = obj.shadow - return retval - -@lldb_command('showtaskloadinfo') -def ShowTaskLoadInfo(cmd_args=None, cmd_options={}): - """ Print the load address and uuid for the process - Usage: (lldb)showtaskloadinfo - """ - if not cmd_args: - raise ArgumentError("Insufficient arguments") - t = kern.GetValueFromAddress(cmd_args[0], 'struct task *') - print_format = "0x{0:x} - 0x{1:x} {2: <50s} (??? - ???) <{3: <36s}> {4: <50s}" - p = Cast(t.bsd_info, 'struct proc *') - uuid = p.p_uuid - uuid_out_string = "{a[0]:02X}{a[1]:02X}{a[2]:02X}{a[3]:02X}-{a[4]:02X}{a[5]:02X}-{a[6]:02X}{a[7]:02X}-{a[8]:02X}{a[9]:02X}-{a[10]:02X}{a[11]:02X}{a[12]:02X}{a[13]:02X}{a[14]:02X}{a[15]:02X}".format(a=uuid) - filepath = GetVnodePath(p.p_textvp) - libname = filepath.split('/')[-1] - #print "uuid: %s file: %s" % (uuid_out_string, filepath) - mappings = FindVMEntriesForVnode(t, p.p_textvp) - load_addr = 0 - end_addr = 0 - for m in mappings: - if m[3] == 5: - load_addr = m[1] - end_addr = m[2] - #print "Load address: %s" % hex(m[1]) - print print_format.format(load_addr, end_addr, libname, uuid_out_string, filepath) - return None -