X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/813fb2f63a553c957e917ede5f119b021d6ce391..f427ee49d309d8fc33ebf3042c3a775f2f530ded:/tools/lldbmacros/process.py diff --git a/tools/lldbmacros/process.py b/tools/lldbmacros/process.py old mode 100644 new mode 100755 index 906d47a7f..c7d5f493c --- a/tools/lldbmacros/process.py +++ b/tools/lldbmacros/process.py @@ -9,6 +9,21 @@ from utils import * from core.lazytarget import * import time import xnudefines +import memory +import json + +def GetProcName(proc): + """ returns a string name of the process. Longer variant is preffered if provided. + params: + proc: value object representing a proc in the kernel. + returns: + str: a string name of the process linked to the task. + """ + name = str(proc.p_name) + if name != '': + return name + else: + return str(proc.p_comm) def GetProcNameForTask(task): """ returns a string name of the process. if proc is not valid "unknown" is returned @@ -20,7 +35,8 @@ def GetProcNameForTask(task): if not task or not unsigned(task.bsd_info): return "unknown" p = Cast(task.bsd_info, 'proc *') - return str(p.p_comm) + + return GetProcName(p) def GetProcPIDForTask(task): """ returns a int pid of the process. if the proc is not valid, val[5] from audit_token is returned. @@ -32,7 +48,7 @@ def GetProcPIDForTask(task): if task and unsigned(task.bsd_info): p = Cast(task.bsd_info, 'proc *') return unsigned(p.p_pid) - + if task : return unsigned(task.audit_token.val[5]) @@ -46,9 +62,9 @@ def GetProcInfo(proc): str : A string describing various information for process. """ out_string = "" - out_string += ("Process {p: <#020x}\n\tname {p.p_comm: <20s}\n\tpid:{p.p_pid: <6d} " + + out_string += ("Process {p: <#020x}\n\tname {0: <32s}\n\tpid:{p.p_pid: <6d} " + "task:{p.task: <#020x} p_stat:{p.p_stat: <6d} parent pid: {p.p_ppid: <6d}\n" - ).format(p=proc) + ).format(GetProcName(proc), p=proc) #print the Creds ucred = proc.p_ucred if ucred: @@ -85,7 +101,7 @@ def GetProcNameForPid(pid): """ for p in kern.procs: if int(p.p_pid) == int(pid): - return str(p.p_comm) + return GetProcName(p) return "Unknown" def GetProcForPid(search_pid): @@ -170,22 +186,27 @@ def GetASTSummary(ast): B - AST_BSD K - AST_KPERF M - AST_MACF - C - AST_CHUD - C - AST_CHUD_URGENT + r - AST_RESET_PCS 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', 0x400: 'r', + 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 +237,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 +403,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 +466,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 +569,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:') @@ -560,7 +621,7 @@ def ShowTaskCoalitions(cmd_args=None, cmd_options={}): # EndMacro: showtaskcoalitions @lldb_type_summary(['proc', 'proc *']) -@header("{0: >6s} {1: ^20s} {2: >14s} {3: ^10s} {4: <20s}".format("pid", "process", "io_policy", "wq_state", "command")) +@header("{0: >6s} {1: <18s} {2: >11s} {3: ^10s} {4: <32s}".format("pid", "process", "io_policy", "wq_state", "command")) def GetProcSummary(proc): """ Summarize the process data. params: @@ -569,7 +630,7 @@ def GetProcSummary(proc): str - string summary of the process. """ out_string = "" - format_string= "{0: >6d} {1: >#020x} {2: >14s} {3: >2d} {4: >2d} {5: >2d} {6: <20s}" + format_string= "{0: >6d} {1: <#018x} {2: >11s} {3: >2d} {4: >2d} {5: >2d} {6: <32s}" pval = proc.GetSBValue() #code.interact(local=locals()) if str(pval.GetType()) != str(gettype('proc *')) : @@ -619,7 +680,7 @@ def GetProcSummary(proc): wq_num_threads = -1 wq_idle_threads = -1 wq_req_threads = -1 - process_name = str(proc.p_comm) + process_name = GetProcName(proc) if process_name == 'xpcproxy': for thread in IterateQueue(task.threads, 'thread *', 'task_threads'): thread_name = GetThreadName(thread) @@ -645,47 +706,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 +741,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 +760,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 +780,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,28 +810,17 @@ 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 = '' - proc_fd_flags = proc_ofiles[count].f_flags - proc_fd_fglob = proc_ofiles[count].f_fglob + proc_fd_flags = proc_ofiles[count].fp_flags + proc_fd_fglob = proc_ofiles[count].fp_glob out_str += "{0: <5d} ".format(count) 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 +833,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') @@ -988,7 +931,7 @@ def DumpThreadTerminateQueue(cmd_args=None): count = 0 print GetThreadSummary.header - for th in IterateQueue(addressof(kern.globals.thread_terminate_queue), 'struct thread *', 'q_link'): + for th in IterateMPSCQueue(addressof(kern.globals.thread_terminate_queue.mpd_queue), 'struct thread', 'mpsc_links'): print GetThreadSummary(th) count += 1 print "{0: 20d} {2: >20d} {3: >20d} {4: >20d} {5: <20s}".format(t, - t.task_immediate_writes, - t.task_deferred_writes, - t.task_invalidated_writes, - t.task_metadata_writes, - str(pval.p_comm)) - - -@lldb_command('showalltasks','C') -def ShowAllTasks(cmd_args=None, cmd_options={}): + print "{0: <#18x} {1: >20d} {2: >20d} {3: >20d} {4: >20d} {5: <20s} {6: <20s} {7: <20s} {8: <20s} {9: <20s}".format(t, + t.task_writes_counters_internal.task_immediate_writes, + t.task_writes_counters_internal.task_deferred_writes, + t.task_writes_counters_internal.task_invalidated_writes, + t.task_writes_counters_internal.task_metadata_writes, + t.task_writes_counters_external.task_immediate_writes, + t.task_writes_counters_external.task_deferred_writes, + t.task_writes_counters_external.task_invalidated_writes, + t.task_writes_counters_external.task_metadata_writes, + GetProcName(pval)) + + +@lldb_command('showalltasks','C', fancy=True) +def ShowAllTasks(cmd_args=None, cmd_options={}, O=None): """ Routine to print a summary listing of all the tasks wq_state -> reports "number of workq threads", "number of scheduled workq threads", "number of pending work items" if "number of pending work items" seems stuck at non-zero, it may indicate that the workqueue mechanism is hung @@ -1067,11 +1014,11 @@ def ShowAllTasks(cmd_args=None, cmd_options={}): showcorpse = True extra_hdr += " " + GetKCDataSummary.header - print GetTaskSummary.header + extra_hdr + " " + GetProcSummary.header - for t in kern.tasks: - pval = Cast(t.bsd_info, 'proc *') - out_str = GetTaskSummary(t, showcorpse) + " " + GetProcSummary(pval) - print out_str + with O.table(GetTaskSummary.header + extra_hdr + " " + GetProcSummary.header): + for t in kern.tasks: + pval = Cast(t.bsd_info, 'proc *') + print GetTaskSummary(t, showcorpse) + " " + GetProcSummary(pval) + ZombTasks() @lldb_command('taskforpmap') @@ -1086,7 +1033,7 @@ def TaskForPmap(cmd_args=None): print GetTaskSummary.header + " " + GetProcSummary.header for tasklist in [kern.tasks, kern.terminated_tasks]: for t in tasklist: - if t.map.pmap == pmap: + if kern.GetValueFromAddress(unsigned(t.map.pmap), 'pmap_t') == pmap: pval = Cast(t.bsd_info, 'proc *') out_str = GetTaskSummary(t) + " " + GetProcSummary(pval) print out_str @@ -1138,7 +1085,7 @@ def FindTasksByName(searchstr, ignore_case=True): retval = [] for t in kern.tasks: pval = Cast(t.bsd_info, "proc *") - process_name = "{:s}".format(pval.p_comm) + process_name = "{:s}".format(GetProcName(pval)) if search_regex.search(process_name): retval.append(t) return retval @@ -1259,10 +1206,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 +1217,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 +1234,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 +1343,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)) @@ -1492,8 +1433,8 @@ def ShowProcTree(cmd_args=None): out_string = hdr_format.format("PID", "PROCESS", "POINTER") out_string += hdr_format.format('='*3, '='*7, '='*7) proc = GetProcForPid(search_pid) - out_string += "{0: <6d} {1: <14s} [ {2: #019x} ]\n".format(proc.p_ppid, proc.p_pptr.p_comm, unsigned(proc.p_pptr)) - out_string += "|--{0: <6d} {1: <16s} [ {2: #019x} ]\n".format(proc.p_pid, proc.p_comm, unsigned(proc)) + out_string += "{0: <6d} {1: <32s} [ {2: #019x} ]\n".format(proc.p_ppid, GetProcName(proc.p_pptr), unsigned(proc.p_pptr)) + out_string += "|--{0: <6d} {1: <32s} [ {2: #019x} ]\n".format(proc.p_pid, GetProcName(proc), unsigned(proc)) print out_string ShowProcTreeRecurse(proc, "| ") @@ -1510,7 +1451,7 @@ def ShowProcTreeRecurse(proc, prefix=""): head_ptr = proc.p_children.lh_first for p in IterateListEntry(proc.p_children, 'struct proc *', 'p_sibling'): - print prefix + "|--{0: <6d} {1: <16s} [ {2: #019x} ]\n".format(p.p_pid, p.p_comm, unsigned(p)) + print prefix + "|--{0: <6d} {1: <32s} [ {2: #019x} ]\n".format(p.p_pid, GetProcName(p), unsigned(p)) ShowProcTreeRecurse(p, prefix + "| ") @lldb_command('showthreadfortid') @@ -1581,135 +1522,246 @@ def GetProcessorSummary(processor): preemption_disable_str) return out_str -def GetLedgerEntrySummary(ledger_template, ledger, i): +def GetLedgerEntry(ledger_template, ledger, i): """ 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 * - return: str - formatted output information of ledger entries + return: entry - entry dictionary """ ledger_limit_infinity = (uint64_t(0x1).value << 63) - 1 lf_refill_scheduled = 0x0400 lf_tracking_max = 0x4000 - out_str = '' now = unsigned(kern.globals.sched_tick) / 20 lim_pct = 0 - 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)) + entry = {} + + entry["key"] = str(ledger_template.lt_entries[i].et_key) + entry["credit"] = unsigned(ledger.le_credit) + entry["debit"] = unsigned(ledger.le_debit) + entry["balance"] = entry["credit"] - entry["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)) - else: - out_str += " - - - - " - - out_str += "{:12d} {:12d} ".format(unsigned(ledger.le_credit), unsigned(ledger.le_debit)) + entry["interval_max"] = unsigned(ledger._le._le_max.le_interval_max) + entry["lifetime_max"] = unsigned(ledger._le._le_max.le_lifetime_max) + if (unsigned(ledger.le_limit) != ledger_limit_infinity): - out_str += "{:12d} ".format(unsigned(ledger.le_limit)) - else: - out_str += " - " + entry["limit"] = unsigned(ledger.le_limit) if (ledger.le_flags & lf_refill_scheduled): - out_str += "{:15d} ".format(ledger._le.le_refill.le_refill_period) + entry["refill_period"] = unsigned (ledger._le.le_refill.le_refill_period) + + if (unsigned(ledger.le_warn_percent) < 65535): + entry["warn_percent"] = unsigned (ledger.le_warn_percent * 100 / 65536) + entry["flags"] = int(ledger.le_flags) + + return entry + +def FormatLedgerEntrySummary(entry, i, show_footprint_interval_max=False): + """ internal function to format a ledger entry into a string + params: entry - A python dictionary containing the ledger entry + return: str - formatted output information of ledger entries + """ + out_str = '' + out_str += "{: >32s} {:<2d}:".format(entry["key"], i) + out_str += "{: >15d} ".format(entry["balance"]) + + if (show_footprint_interval_max): + if entry.has_key("interval_max"): + out_str += "{:12d} ".format(entry["interval_max"]) + else: + out_str += " - " + + if entry.has_key("lifetime_max"): + out_str += "{:14d} ".format(entry["lifetime_max"]) else: - out_str += " - " + out_str += " - " - if (ledger.le_flags & lf_refill_scheduled): - out_str += "{:9d} ".format((unsigned(ledger.le_limit) * 100) / ledger._le.le_refill.le_refill_period) + out_str += "{:12d} {:12d} ".format(entry["credit"], entry["debit"]) + if entry.has_key("limit"): + out_str += "{:12d} ".format(unsigned(entry["limit"])) else: + out_str += " - " + + if entry.has_key("refill_period"): + out_str += "{:15d} ".format(entry["refill_period"]) + out_str += "{:9d} ".format((entry["limit"] * 100) / entry["refill_period"]) + else: + out_str += " - " out_str += " - " - if (unsigned(ledger.le_warn_level) != ledger_limit_infinity): - out_str += "{:9d} ".format((unsigned(ledger.le_warn_level) * 100) / unsigned(ledger.le_limit)) + if entry.has_key("warn_percent"): + out_str += "{:9d} ".format(entry["warn_percent"]) else: out_str += " - " - if ((unsigned(ledger.le_credit) - unsigned(ledger.le_debit)) > unsigned(ledger.le_limit)): - out_str += " X " + if entry.has_key("limit"): + if entry["balance"] > entry["limit"]: + out_str += " X " + else: + out_str += " " else: out_str += " " - out_str += "{:#8x}\n".format(ledger.le_flags) + out_str += "{:#8x}\n".format(entry["flags"]) return out_str -def GetThreadLedgerSummary(thread_val): +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 * + return: str - formatted output information of ledger entries + """ + entry = GetLedgerEntry(ledger_template, ledger, i) + return FormatLedgerEntrySummary(entry, i) + + +def GetThreadLedgers(thread_val): """ Internal function to get a summary of ledger entries for the given thread - params: thread - value representing struct thread * - return: str - formatted output information for ledger entries of the input thread + params: thread_val - value representing struct thread * + return: thread - python dictionary containing threads's ledger entries. This can + be printed directly with FormatThreadLedgerSummmary or outputted as json. """ - out_str = " [{:#08x}]\n".format(thread_val) + thread = {} + thread["address"] = unsigned(thread_val) ledgerp = thread_val.t_threadledger + thread["entries"] = [] if ledgerp: i = 0 while i != ledgerp.l_template.lt_cnt: - out_str += GetLedgerEntrySummary(kern.globals.thread_ledger_template, - ledgerp.l_entries[i], i) + thread["entries"].append(GetLedgerEntry(kern.globals.thread_ledger_template, + ledgerp.l_entries[i], i)) i = i + 1 + return thread + +def FormatThreadLedgerSummary(thread): + """ Internal function to print a thread's ledger entries + params: thread - python dictionary containing thread's ledger entries + return: str - formatted output information for ledger entries of the input thread + """ + out_str = " [{:#08x}]\n".format(thread["address"]) + entries = thread["entries"] + for i, entry in enumerate(entries): + out_str += FormatLedgerEntrySummary(entry, i) 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): """ 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 + return: task - python dictionary containing tasks's ledger entries. This can + be printed directly with FormatTaskLedgerSummary or outputted as json. """ - out_str = '' task_ledgerp = task_val.ledger i = 0 - out_str += "{: #08x} ".format(task_val) + tasks = [] + task = {} + task["address"] = unsigned(task_val) + pval = Cast(task_val.bsd_info, 'proc *') if pval: - out_str += "{: <5s}:\n".format(pval.p_comm) - else: - out_str += "Invalid process:\n" + task["name"] = GetProcName(pval) + task["pid"] = int(pval.p_pid) + + task["entries"] = [] while i != task_ledgerp.l_template.lt_cnt: - out_str += GetLedgerEntrySummary(kern.globals.task_ledger_template, task_ledgerp.l_entries[i], i) + task["entries"].append(GetLedgerEntry(kern.globals.task_ledger_template, task_ledgerp.l_entries[i], i)) i = i + 1 # Now walk threads + task["threads"] = [] for thval in IterateQueue(task_val.threads, 'thread *', 'task_threads'): - out_str += GetThreadLedgerSummary(thval) + task["threads"].append(GetThreadLedgers(thval)) + + return task + +@header("{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")) +def FormatTaskLedgerSummary(task, 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 + """ + out_str = '' + out_str += "{: #08x} ".format(task["address"]) + if task.has_key("name"): + out_str += "{: <5s}:\n".format(task["name"]) + else: + out_str += "Invalid process\n" + for i, entry in enumerate(task["entries"]): + out_str += FormatLedgerEntrySummary(entry, i, show_footprint_interval_max) + + for thread in task["threads"]: + out_str += FormatThreadLedgerSummary(thread) return out_str + # Macro: showtaskledgers -@lldb_command('showtaskledgers', 'F:') +@lldb_command('showtaskledgers', 'JF: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 ] [-J] [ -F ] + options: + -I: show footprint interval max (DEV/DEBUG only) + -F: specify task via name instead of address + -J: output json + - + """ + print_json = False if "-F" in cmd_options: task_list = FindTasksByName(cmd_options["-F"]) for tval in task_list: - print GetTaskLedgers.header - print GetTaskLedgers(tval) + print FormatTaskLedgerSummary.header + ledgers = GetTaskLedgers(tval) + print FormatTaskLedgerSummary(ledgers) return + if "-J" in cmd_options: + print_json = True 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) + ledgers = GetTaskLedgers(tval) + if print_json: + print json.dumps(ledgers) + else: + 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 FormatTaskLedgerSummary.header + print FormatTaskLedgerSummary(ledgers, show_footprint_interval_max) # EndMacro: showtaskledgers # Macro: showalltaskledgers -@lldb_command('showalltaskledgers') -def ShowAllTaskLedgers(cmd_args=None): +@lldb_command('showalltaskledgers', "J") +def ShowAllTaskLedgers(cmd_args=None, cmd_options={}): """ Routine to print a summary of ledger entries for all tasks and respective threads - Usage: showalltaskledgers + Usage: showalltaskledgers [-J] + -J : Output json """ + print_json = False + if "-J" in cmd_options: + print_json = True + tasks = [] for t in kern.tasks: task_val = unsigned(t) - ShowTaskLedgers([task_val]) + if not print_json: + ShowTaskLedgers([task_val], cmd_options=cmd_options) + else: + tasks.append(GetTaskLedgers(t)) + if print_json: + print json.dumps(tasks) # EndMacro: showalltaskledgers @@ -1895,7 +1947,7 @@ def ShowAllPte(cmd_args=None): procp = Cast(taskp.bsd_info, 'proc *') out_str = "task = {:#x} pte = {:#x}\t".format(taskp, taskp.map.pmap.ttep) if procp != 0: - out_str += "{:s}\n".format(procp.p_comm) + out_str += "{:s}\n".format(GetProcName(procp)) else: out_str += "\n" print out_str @@ -1983,7 +2035,7 @@ def ShowProcFilesSummary(cmd_args=None): if unsigned(proc_ofiles[count]) != 0: proc_file_count += 1 count += 1 - print "{0: <#020x} {1: <20s} {2: >10d}".format(proc, proc.p_comm, proc_file_count) + print "{0: <#020x} {1: <32s} {2: >10d}".format(proc, GetProcName(proc), proc_file_count) #EndMacro: showprocfilessummary @@ -2143,7 +2195,7 @@ def Showstackafterthread(cmd_args = None): if(thval==threadval): pval = Cast(t.bsd_info, 'proc *') - process_name = "{:s}".format(pval.p_comm) + process_name = "{:s}".format(GetProcName(pval)) print "\n\n" print " *** Continuing to dump the thread stacks from the process *** :" + " " + process_name print "\n\n" @@ -2151,61 +2203,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 -