""" Please make sure you read the README file COMPLETELY BEFORE reading anything below.
- It is very critical that you read coding guidelines in Section E in README file.
+ It is very critical that you read coding guidelines in Section E in README file.
"""
from xnu import *
import sys, shlex
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
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
-
+
return state_str
+@lldb_type_summary(['kcdata_descriptor *', 'kcdata_descriptor_t'])
+@header("{0: <20s} {1: <20s} {2: <20s} {3: <10s} {4: <5s}".format("kcdata_descriptor", "begin_addr", "cur_pos", "size", "flags"))
+def GetKCDataSummary(kcdata):
+ """ Summarizes kcdata_descriptor structure
+ params: kcdata: value - value object representing kcdata_descriptor
+ returns: str - summary of the kcdata object
+ """
+ format_string = "{0: <#020x} {1: <#020x} {2: <#020x} {3: <10d} {4: <#05x}"
+ return format_string.format(kcdata, kcdata.kcd_addr_begin, kcdata.kcd_addr_end, kcdata.kcd_length, kcdata.kcd_flags)
+
+
@lldb_type_summary(['task', 'task_t'])
@header("{0: <20s} {1: <20s} {2: <20s} {3: >5s} {4: <5s}".format("task","vm_map", "ipc_space", "#acts", "flags"))
-def GetTaskSummary(task):
+def GetTaskSummary(task, showcorpse=False):
""" Summarizes the important fields in task structure.
params: task: value - value object representing a task in kernel
returns: str - summary of the task
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):
task_flags += 'D'
if int(tib.iit_assertcnt) > 0:
task_flags += 'B'
+
+ # check if corpse flag is set
+ if unsigned(task.t_flags) & 0x20:
+ task_flags += 'C'
+ if unsigned(task.t_flags) & 0x40:
+ task_flags += 'P'
+
out_string += format_string.format(task, task.map, task.itk_space, thread_count, task_flags)
+ if showcorpse is True and unsigned(task.corpse_info) != 0:
+ out_string += " " + GetKCDataSummary(task.corpse_info)
return out_string
+def GetThreadName(thread):
+ """ Get the name of a thread, if possible. Returns the empty string
+ otherwise.
+ """
+ if int(thread.uthread) != 0:
+ uthread = Cast(thread.uthread, 'uthread *')
+ if int(uthread.pth_name) != 0 :
+ th_name_strval = Cast(uthread.pth_name, 'char *')
+ if len(str(th_name_strval)) > 0 :
+ return str(th_name_strval)
+
+ return ''
+
@lldb_type_summary(['thread *', 'thread_t'])
-@header("{0: <24s} {1: <10s} {2: <20s} {3: <6s} {4: <6s} {5: <15s} {6: <15s} {7: <8s} {8: <12s} {9: <32s} {10: <20s} {11: <20s} {12: <20s}".format('thread', 'thread_id', 'processor', 'base', 'pri', 'sched_mode', 'io_policy', 'state', 'ast', 'wait_queue', 'wait_event', 'wmesg', 'thread_name'))
+@header("{0: <24s} {1: <10s} {2: <20s} {3: <6s} {4: <6s} {5: <15s} {6: <15s} {7: <8s} {8: <12s} {9: <32s} {10: <20s} {11: <20s} {12: <20s}".format('thread', 'thread_id', 'processor', 'base', 'pri', 'sched_mode', 'io_policy', 'state', 'ast', 'waitq', 'wait_event', 'wmesg', 'thread_name'))
def GetThreadSummary(thread):
""" Summarize the thread structure. It decodes the wait state and waitevents from the data in the struct.
params: thread: value - value objecte representing a thread in kernel
H - Terminated
A - Terminated and on termination queue
I - Idle thread
+ C - Crashed thread
policy flags:
B - darwinbg
- L - lowpri cpu
T - IO throttle
P - IO passive
D - Terminated
if int(thread.static_param) :
thread_ptr_str+="[WQ]"
thread_id = hex(thread.thread_id)
- thread_name = ''
processor = hex(thread.last_processor)
- base_priority = str(int(thread.priority))
+ base_priority = str(int(thread.base_pri))
sched_priority = str(int(thread.sched_pri))
sched_mode = ''
mode = str(thread.sched_mode)
sched_mode+=" BG"
io_policy_str = ""
+ thread_name = GetThreadName(thread)
if int(thread.uthread) != 0:
uthread = Cast(thread.uthread, 'uthread *')
- #check for thread name
- if int(uthread.pth_name) != 0 :
- th_name_strval = Cast(uthread.pth_name, 'char *')
- if len(str(th_name_strval)) > 0 :
- thread_name = str(th_name_strval)
-
+
#check for io_policy flags
if int(uthread.uu_flag) & 0x400:
io_policy_str+='RAGE '
io_policy_str = ""
- if int(thread.effective_policy.darwinbg) != 0:
+ if int(thread.effective_policy.thep_darwinbg) != 0:
io_policy_str += "B"
- if int(thread.effective_policy.lowpri_cpu) != 0:
- io_policy_str += "L"
-
- if int(thread.effective_policy.io_tier) != 0:
+ if int(thread.effective_policy.thep_io_tier) != 0:
io_policy_str += "T"
- if int(thread.effective_policy.io_passive) != 0:
+ if int(thread.effective_policy.thep_io_passive) != 0:
io_policy_str += "P"
- if int(thread.effective_policy.terminated) != 0:
+ if int(thread.effective_policy.thep_terminated) != 0:
io_policy_str += "D"
state = int(thread.state)
while mask <= 0x80 :
state_str += thread_state_chars[int(state & mask)]
mask = mask << 1
-
+
+ if int(thread.inspection):
+ state_str += 'C'
+
ast = int(thread.ast) | int(thread.reason)
ast_str = GetASTSummary(ast)
wait_message = ''
if ( state & 0x1 ) != 0:
#we need to look at the waitqueue as well
- wait_queue_str = str("{0: <#020x}".format(int(hex(thread.wait_queue), 16)))
+ wait_queue_str = str("{0: <#020x}".format(int(hex(thread.waitq), 16)))
wait_event_str = str("{0: <#020x}".format(int(hex(thread.wait_event), 16)))
wait_event_str_sym = kern.Symbolicate(int(hex(thread.wait_event), 16))
if len(wait_event_str_sym) > 0:
out_string += format_string.format(thread_ptr_str, thread_id, processor, base_priority, sched_priority, sched_mode, io_policy_str, state_str, ast_str, wait_queue_str, wait_event_str, wait_message, thread_name)
return out_string
-
-@lldb_type_summary(['coalition_t', 'coalition'])
-@header("{:>18s} {:>10s} {:>8s} {:>8s} {:>8s} {:>8s}".format("coalition", "id", "refcount", "active", "focal", "nonfocal"))
-def GetCoalitionSummary(coal):
- out_string = ""
- format_string = '{:>#018x} {:>10d} {:>8d} {:>8d} {:>8d} {:>8d}'
- flags_string = ''
+def GetTaskRoleString(role):
+ role_strs = {
+ 0 : "TASK_UNSPECIFIED",
+ 1 : "TASK_FOREGROUND_APPLICATION",
+ 2 : "TASK_BACKGROUND_APPLICATION",
+ 3 : "TASK_CONTROL_APPLICATION",
+ 4 : "TASK_GRAPHICS_SERVER",
+ 5 : "TASK_THROTTLE_APPLICATION",
+ 6 : "TASK_NONUI_APPLICATION",
+ 7 : "TASK_DEFAULT_APPLICATION",
+ }
+ return role_strs[int(role)]
+
+def GetCoalitionFlagString(coal):
+ flags = []
+ if (coal.privileged):
+ flags.append('privileged')
+ if (coal.termrequested):
+ flags.append('termrequested')
if (coal.terminated):
- flags_string += ' terminated'
+ flags.append('terminated')
if (coal.reaped):
- flags_string += ' reaped'
- out_string += format_string.format(coal, coal.id, coal.ref_count, coal.active_count, coal.focal_tasks_count, coal.non_focal_tasks_count)
+ 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):
+ sfi_strs = {
+ 0x0 : "SFI_CLASS_UNSPECIFIED",
+ 0x1 : "SFI_CLASS_DARWIN_BG",
+ 0x2 : "SFI_CLASS_APP_NAP",
+ 0x3 : "SFI_CLASS_MANAGED_FOCAL",
+ 0x4 : "SFI_CLASS_MANAGED_NONFOCAL",
+ 0x5 : "SFI_CLASS_DEFAULT_FOCAL",
+ 0x6 : "SFI_CLASS_DEFAULT_NONFOCAL",
+ 0x7 : "SFI_CLASS_KERNEL",
+ 0x8 : "SFI_CLASS_OPTED_OUT",
+ 0x9 : "SFI_CLASS_UTILITY",
+ 0xA : "SFI_CLASS_LEGACY_FOCAL",
+ 0xB : "SFI_CLASS_LEGACY_NONFOCAL",
+ 0xC : "SFI_CLASS_USER_INITIATED_FOCAL",
+ 0xD : "SFI_CLASS_USER_INITIATED_NONFOCAL",
+ 0xE : "SFI_CLASS_USER_INTERACTIVE_FOCAL",
+ 0xF : "SFI_CLASS_USER_INTERACTIVE_NONFOCAL",
+ 0x10 : "SFI_CLASS_MAINTENANCE",
+ }
+ tasks = []
+ field_name = 'task_coalition'
+ for task in IterateLinkageChain(queue, 'task *', field_name, coal_type * sizeof('queue_chain_t')):
+ task_str = "({0: <d},{1: #x}, {2: <s}, {3: <s})".format(GetProcPIDForTask(task),task,GetProcNameForTask(task),GetTaskRoleString(task.effective_policy.tep_role))
+ if thread_details:
+ for thread in IterateQueue(task.threads, "thread_t", "task_threads"):
+ task_str += "\n\t\t\t|-> thread:" + hex(thread) + ", " + sfi_strs[int(thread.sfi_class)]
+ tasks.append(task_str)
+ return tasks
+
+def GetCoalitionTypeString(type):
+ """ Convert a coalition type field into a string
+ Currently supported types (from <mach/coalition.h>):
+ COALITION_TYPE_RESOURCE
+ COALITION_TYPE_JETSAM
+ """
+ if type == 0: # COALITION_TYPE_RESOURCE
+ return 'RESOURCE'
+ if type == 1:
+ return 'JETSAM'
+ return '<unknown>'
+
+def GetResourceCoalitionSummary(coal, verbose=False):
+ """ Summarize a resource coalition
+ """
+ out_string = "Resource Coalition:\n\t Ledger:\n"
+ thread_details = False
+ if config['verbosity'] > vSCRIPT:
+ thread_details = True
+ ledgerp = coal.r.ledger
+ if verbose and unsigned(ledgerp) != 0:
+ i = 0
+ while i != ledgerp.l_template.lt_cnt:
+ out_string += "\t\t"
+ out_string += GetLedgerEntrySummary(kern.globals.task_ledger_template, ledgerp.l_entries[i], i)
+ i = i + 1
+ out_string += "\t bytesread {0: <d}\n\t byteswritten {1: <d}\n\t gpu_time {2: <d}".format(coal.r.bytesread, coal.r.byteswritten, coal.r.gpu_time)
+ out_string += "\n\t total_tasks {0: <d}\n\t dead_tasks {1: <d}\n\t active_tasks {2: <d}".format(coal.r.task_count, coal.r.dead_task_count, coal.r.task_count - coal.r.dead_task_count)
+ out_string += "\n\t last_became_nonempty_time {0: <d}\n\t time_nonempty {1: <d}".format(coal.r.last_became_nonempty_time, coal.r.time_nonempty)
+ out_string += "\n\t cpu_ptime {0: <d}".format(coal.r.cpu_ptime)
+ if verbose:
+ out_string += "\n\t cpu_time_effective[THREAD_QOS_DEFAULT] {0: <d}".format(coal.r.cpu_time_eqos[0])
+ out_string += "\n\t cpu_time_effective[THREAD_QOS_MAINTENANCE] {0: <d}".format(coal.r.cpu_time_eqos[1])
+ out_string += "\n\t cpu_time_effective[THREAD_QOS_BACKGROUND] {0: <d}".format(coal.r.cpu_time_eqos[2])
+ out_string += "\n\t cpu_time_effective[THREAD_QOS_UTILITY] {0: <d}".format(coal.r.cpu_time_eqos[3])
+ out_string += "\n\t cpu_time_effective[THREAD_QOS_LEGACY] {0: <d}".format(coal.r.cpu_time_eqos[4])
+ out_string += "\n\t cpu_time_effective[THREAD_QOS_USER_INITIATED] {0: <d}".format(coal.r.cpu_time_eqos[5])
+ out_string += "\n\t cpu_time_effective[THREAD_QOS_USER_INTERACTIVE] {0: <d}".format(coal.r.cpu_time_eqos[6])
+ out_string += "\n\t Tasks:\n\t\t"
+ tasks = GetCoalitionTasks(addressof(coal.r.tasks), 0, thread_details)
+ out_string += "\n\t\t".join(tasks)
+ return out_string
+
+def GetJetsamCoalitionSummary(coal, verbose=False):
+ out_string = "Jetsam Coalition:"
+ thread_details = False
+ if config['verbosity'] > vSCRIPT:
+ thread_details = True
+ if unsigned(coal.j.leader) == 0:
+ out_string += "\n\t NO Leader!"
+ else:
+ out_string += "\n\t Leader:\n\t\t"
+ out_string += "({0: <d},{1: #x}, {2: <s}, {3: <s})".format(GetProcPIDForTask(coal.j.leader),coal.j.leader,GetProcNameForTask(coal.j.leader),GetTaskRoleString(coal.j.leader.effective_policy.tep_role))
+ out_string += "\n\t Extensions:\n\t\t"
+ tasks = GetCoalitionTasks(addressof(coal.j.extensions), 1, thread_details)
+ out_string += "\n\t\t".join(tasks)
+ out_string += "\n\t XPC Services:\n\t\t"
+ tasks = GetCoalitionTasks(addressof(coal.j.services), 1, thread_details)
+ out_string += "\n\t\t".join(tasks)
+ out_string += "\n\t Other Tasks:\n\t\t"
+ tasks = GetCoalitionTasks(addressof(coal.j.other), 1, thread_details)
+ out_string += "\n\t\t".join(tasks)
+ out_string += "\n\t Thread Group: {0: <#020x}\n".format(coal.j.thread_group)
+ return out_string
+
+@lldb_type_summary(['coalition_t', 'coalition *'])
+@header("{0: <20s} {1: <15s} {2: <10s} {3: <10s} {4: <10s} {5: <12s} {6: <12s} {7: <20s}".format("coalition", "type", "id", "ref count", "act count", "focal cnt", "nonfocal cnt","flags"))
+def GetCoalitionSummary(coal):
+ if unsigned(coal) == 0:
+ return '{0: <#020x} {1: <15s} {2: <10d} {3: <10d} {4: <10d} {5: <12d} {6: <12d} {7: <s}'.format(0, "", -1, -1, -1, -1, -1, "")
+ out_string = ""
+ format_string = '{0: <#020x} {1: <15s} {2: <10d} {3: <10d} {4: <10d} {5: <12d} {6: <12d} {7: <s}'
+ type_string = GetCoalitionTypeString(coal.type)
+ flag_string = GetCoalitionFlagString(coal)
+ out_string += format_string.format(coal, type_string, coal.id, coal.ref_count, coal.active_count, coal.focal_task_count, coal.nonfocal_task_count, flag_string)
+ return out_string
+
+def GetCoalitionInfo(coal, verbose=False):
+ """ returns a string describing a coalition, including details about the particular coalition type.
+ params:
+ coal : value object representing a coalition in the kernel
+ returns:
+ str : A string describing the coalition.
+ """
+ if unsigned(coal) == 0:
+ return "<null coalition>"
+ typestr = GetCoalitionTypeString(coal.type)
+ flagstr = GetCoalitionFlagString(coal)
+ out_string = ""
+ out_string += "Coalition {c: <#020x}\n\tID {c.id: <d}\n\tType {c.type: <d} ({t: <s})\n\tRefCount {c.ref_count: <d}\n\tActiveCount {c.active_count: <d}\n\tFocal Tasks: {c.focal_task_count: <d}\n\tNon-Focal Tasks: {c.nonfocal_task_count: <d}\n\tFlags {f: <s}\n\t".format(c=coal,t=typestr,f=flagstr)
+ if coal.type == 0: # COALITION_TYPE_RESOURCE
+ out_string += GetResourceCoalitionSummary(coal, verbose)
+ elif coal.type == 1: # COALITION_TYPE_JETSAM
+ out_string += GetJetsamCoalitionSummary(coal, verbose)
+ else:
+ out_string += "Unknown Type"
return out_string
+# Macro: showcoalitioninfo
+
+@lldb_command('showcoalitioninfo')
+def ShowCoalitionInfo(cmd_args=None, cmd_options={}):
+ """ Display more detailed information about a coalition
+ Usage: showcoalitioninfo <address of coalition>
+ """
+ verbose = False
+ if config['verbosity'] > vHUMAN:
+ verbose = True
+ if not cmd_args:
+ raise ArgumentError("No arguments passed")
+ coal = kern.GetValueFromAddress(cmd_args[0], 'coalition *')
+ if not coal:
+ print "unknown arguments:", str(cmd_args)
+ return False
+ print GetCoalitionInfo(coal, verbose)
+
+# EndMacro: showcoalitioninfo
+
+# Macro: showallcoalitions
+
+@lldb_command('showallcoalitions')
+def ShowAllCoalitions(cmd_args=None):
+ """ Print a summary listing of all the coalitions
+ """
+ global kern
+ print GetCoalitionSummary.header
+ for c in kern.coalitions:
+ print GetCoalitionSummary(c)
+
+# 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:')
+def ShowTaskCoalitions(cmd_args=None, cmd_options={}):
+ """
+ """
+ task_list = []
+ if "-F" in cmd_options:
+ task_list = FindTasksByName(cmd_options["-F"])
+ elif cmd_args:
+ t = kern.GetValueFromAddress(cmd_args[0], 'task *')
+ task_list.append(t)
+ else:
+ raise ArgumentError("No arguments passed")
+
+ if len(task_list) > 0:
+ print GetCoalitionSummary.header
+ for task in task_list:
+ print GetCoalitionSummary(task.coalition[0])
+ print GetCoalitionSummary(task.coalition[1])
+
+# 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: <20s}".format("pid", "process", "io_policy", "wq_state", "command"))
def GetProcSummary(proc):
""" Summarize the process data.
params:
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: <20s}"
pval = proc.GetSBValue()
#code.interact(local=locals())
if str(pval.GetType()) != str(gettype('proc *')) :
io_policy_str = ""
- if int(task.effective_policy.darwinbg) != 0:
+ if int(task.effective_policy.tep_darwinbg) != 0:
io_policy_str += "B"
- if int(task.effective_policy.lowpri_cpu) != 0:
+ if int(task.effective_policy.tep_lowpri_cpu) != 0:
io_policy_str += "L"
- if int(task.effective_policy.io_tier) != 0:
+ if int(task.effective_policy.tep_io_tier) != 0:
io_policy_str += "T"
- if int(task.effective_policy.io_passive) != 0:
+ if int(task.effective_policy.tep_io_passive) != 0:
io_policy_str += "P"
- if int(task.effective_policy.terminated) != 0:
+ if int(task.effective_policy.tep_terminated) != 0:
io_policy_str += "D"
- if int(task.effective_policy.t_suspended) != 0:
- io_policy_str += "S"
- if int(task.effective_policy.t_latency_qos) != 0:
+ if int(task.effective_policy.tep_latency_qos) != 0:
io_policy_str += "Q"
- if int(task.effective_policy.t_sup_active) != 0:
+ if int(task.effective_policy.tep_sup_active) != 0:
io_policy_str += "A"
wq_idle_threads = -1
wq_req_threads = -1
process_name = str(proc.p_comm)
+ if process_name == 'xpcproxy':
+ for thread in IterateQueue(task.threads, 'thread *', 'task_threads'):
+ thread_name = GetThreadName(thread)
+ if thread_name:
+ process_name += ' (' + thread_name + ')'
+ break
out_string += format_string.format(pid, proc_addr, " ".join([proc_rage_str, io_policy_str]), wq_num_threads, wq_idle_threads, wq_req_threads, process_name)
return out_string
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} {o.kq_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, st_str=state_str)
- return out_string
-
-@lldb_type_summary(['knote *'])
-@header("{0: <20s}".format('knote'))
-def GetKnoteSummary(kn):
- """ Summarizes a knote and related information
- returns: str - summary of knote
- """
- out_string = ""
- format_string = "{o: <#020x}"
- out_string += format_string.format(o=kn)
- return out_string
-
# Macro: showtask
@lldb_command('showtask', 'F:')
Usage: showpid <pid value>
"""
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 *')
Usage: showproc <address of proc>
"""
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)
Usage: showprocinfo <address of proc>
"""
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)
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 = ''
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))
#EndMacro: showprocfiles
-#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 <struct kqueue *>
- """
- 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')
#EndMacro: showallttydevs
+#Macro: dumpthread_terminate_queue
+
+@lldb_command('dumpthread_terminate_queue')
+def DumpThreadTerminateQueue(cmd_args=None):
+ """ Displays the contents of the specified call_entry queue.
+ Usage: dumpthread_terminate_queue
+ """
+
+ count = 0
+ print GetThreadSummary.header
+ for th in IterateMPSCQueue(addressof(kern.globals.thread_terminate_queue.mpd_queue), 'struct thread', 'mpsc_links'):
+ print GetThreadSummary(th)
+ count += 1
+ print "{0: <d} entries!".format(count)
+
+#EndMacro: dumpthread_terminate_queue
+
+#Macro: dumpcrashed_thread_queue
+
+@lldb_command('dumpcrashed_thread_queue')
+def DumpCrashedThreadsQueue(cmd_args=None):
+ """ Displays the contents of the specified call_entry queue.
+ Usage: dumpcrashed_thread_queue
+ """
+
+ count = 0
+ print GetThreadSummary.header
+ for th in IterateQueue(addressof(kern.globals.crashed_threads_queue), 'struct thread *', 'q_link'):
+ print GetThreadSummary(th)
+ count += 1
+ print "{0: <d} entries!".format(count)
+
+#EndMacro: dumpcrashed_thread_queue
+
#Macro: dumpcallqueue
@lldb_command('dumpcallqueue')
Usage: dumpcallqueue <queue_head_t *>
"""
if not cmd_args:
- print DumpCallQueue.__doc__
- return
+ raise ArgumentError("Invalid arguments")
+
print "{0: <18s} {1: <18s} {2: <18s} {3: <64s} {4: <18s}".format('CALL_ENTRY', 'PARAM0', 'PARAM1', 'DEADLINE', 'FUNC')
callhead = kern.GetValueFromAddress(cmd_args[0], 'queue_head_t *')
count = 0
#EndMacro: dumpcallqueue
-@lldb_command('showallcoalitions')
-def ShowAllCoalitions(cmd_args=None):
- """ Routine to print a summary listing of all the coalitions
+@lldb_command('showalltasklogicalwrites')
+def ShowAllTaskIOStats(cmd_args=None):
+ """ Commad to print I/O stats for all tasks
"""
- global kern
-
- role_strs = {
- 0 : "TASK_UNSPECIFIED",
- 1 : "TASK_FOREGROUND_APPLICATION",
- 2 : "TASK_BACKGROUND_APPLICATION",
- 3 : "TASK_CONTROL_APPLICATION",
- 4 : "TASK_GRAPHICS_SERVER",
- 5 : "TASK_THROTTLE_APPLICATION",
- 6 : "TASK_NONUI_APPLICATION",
- 7 : "TASK_DEFAULT_APPLICATION",
- }
-
- sfi_strs = {
- 0x0 : "SFI_CLASS_UNSPECIFIED",
- 0x1 : "SFI_CLASS_DARWIN_BG",
- 0x2 : "SFI_CLASS_APP_NAP",
- 0x3 : "SFI_CLASS_MANAGED_FOCAL",
- 0x4 : "SFI_CLASS_MANAGED_NONFOCAL",
- 0x5 : "SFI_CLASS_DEFAULT_FOCAL",
- 0x6 : "SFI_CLASS_DEFAULT_NONFOCAL",
- 0x7 : "SFI_CLASS_KERNEL",
- 0x8 : "SFI_CLASS_OPTED_OUT",
- 0x9 : "SFI_CLASS_UTILITY",
- 0xA : "SFI_CLASS_LEGACY_FOCAL",
- 0xB : "SFI_CLASS_LEGACY_NONFOCAL",
- 0xC : "SFI_CLASS_USER_INITIATED_FOCAL",
- 0xD : "SFI_CLASS_USER_INITIATED_NONFOCAL",
- 0xE : "SFI_CLASS_USER_INTERACTIVE_FOCAL",
- 0xF : "SFI_CLASS_USER_INTERACTIVE_NONFOCAL",
- 0x10 : "SFI_CLASS_MAINTENANCE",
- }
-
-
- print GetCoalitionSummary.header
- for c in kern.coalitions:
- print GetCoalitionSummary(c)
- for task in IterateQueue(c.tasks, "task_t", "coalition_tasks"):
- print "\t" + hex(task) + " " + GetProcNameForTask(task) + " " + role_strs[int(task.effective_policy.t_role)]
- for thread in IterateQueue(task.threads, "thread_t", "task_threads"):
- print "\t\t" + hex(thread) + " " + sfi_strs[int(thread.sfi_class)]
-
-
-@lldb_command('showalltasks')
-def ShowAllTasks(cmd_args=None):
+ print "{0: <20s} {1: <20s} {2: <20s} {3: <20s} {4: <20s} {5: <20s} {6: <20s} {7: <20s} {8: <20s} {9: <20s}".format("task", "Immediate Writes", "Deferred Writes", "Invalidated Writes", "Metadata Writes", "Immediate Writes to External", "Deferred Writes to External", "Invalidated Writes to External", "Metadata Writes to External", "name")
+ for t in kern.tasks:
+ pval = Cast(t.bsd_info, 'proc *')
+ 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,
+ str(pval.p_comm))
+
+
+@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
NORM - normal I/O explicitly requested (this is the default)
PASS - passive I/O requested (i.e. I/Os do not affect throttling decisions)
THROT - throttled I/O requested (i.e. thread/task may be throttled after each I/O completes)
+ Usage: (lldb) showalltasks -C : describe the corpse structure
"""
global kern
- print GetTaskSummary.header + " " + GetProcSummary.header
- for t in kern.tasks:
- pval = Cast(t.bsd_info, 'proc *')
- print GetTaskSummary(t) +" "+ GetProcSummary(pval)
+ extra_hdr = ''
+ showcorpse = False
+ if '-C' in cmd_options:
+ showcorpse = True
+ extra_hdr += " " + GetKCDataSummary.header
+
+ 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')
+def TaskForPmap(cmd_args=None):
+ """ Find the task whose pmap corresponds to <pmap>.
+ Syntax: (lldb) taskforpmap <pmap>
+ Multiple -v's can be specified for increased verbosity
+ """
+ if cmd_args == None or len(cmd_args) < 1:
+ raise ArgumentError("Too few arguments to taskforpmap.")
+ pmap = kern.GetValueFromAddress(cmd_args[0], 'pmap_t')
+ print GetTaskSummary.header + " " + GetProcSummary.header
+ for tasklist in [kern.tasks, kern.terminated_tasks]:
+ for t in tasklist:
+ if t.map.pmap == pmap:
+ pval = Cast(t.bsd_info, 'proc *')
+ out_str = GetTaskSummary(t) + " " + GetProcSummary(pval)
+ print out_str
+
@lldb_command('showterminatedtasks')
def ShowTerminatedTasks(cmd_args=None):
""" Routine to print a summary listing of all the terminated tasks
# EndMacro: showtaskstacks
+def CheckTaskProcRefs(task, proc):
+ for thread in IterateQueue(task.threads, 'thread *', 'task_threads'):
+ if int(thread.uthread) == 0:
+ continue
+ uthread = Cast(thread.uthread, 'uthread *')
+ refcount = int(uthread.uu_proc_refcount)
+ uu_ref_index = int(uthread.uu_pindex)
+ if refcount == 0:
+ continue
+ for ref in range(0, uu_ref_index):
+ if unsigned(uthread.uu_proc_ps[ref]) == unsigned(proc):
+ print GetTaskSummary.header + " " + GetProcSummary.header
+ pval = Cast(task.bsd_info, 'proc *')
+ print GetTaskSummary(task) + " " + GetProcSummary(pval)
+ print "\t" + GetThreadSummary.header
+ print "\t" + GetThreadSummary(thread) + "\n"
+
+ for frame in range (0, 10):
+ trace_addr = unsigned(uthread.uu_proc_pcs[ref][frame])
+ symbol_arr = kern.SymbolicateFromAddress(unsigned(trace_addr))
+ if symbol_arr:
+ symbol_str = str(symbol_arr[0].addr)
+ else:
+ symbol_str = ''
+ print '{0: <#x} {1: <s}'.format(trace_addr, symbol_str)
+ return
+
+@lldb_command('showprocrefs')
+def ShowProcRefs(cmd_args = None):
+ """ Display information on threads/BTs that could be holding a reference on the specified proc
+ NOTE: We can't say affirmatively if any of these references are still held since
+ there's no way to pair references with drop-refs in the current infrastructure.
+ Usage: showprocrefs <proc>
+ """
+ if cmd_args == None or len(cmd_args) < 1:
+ raise ArgumentError("No arguments passed")
+
+ proc = kern.GetValueFromAddress(cmd_args[0], 'proc *')
+
+ for t in kern.tasks:
+ CheckTaskProcRefs(t, proc)
+ for t in kern.terminated_tasks:
+ CheckTaskProcRefs(t, proc)
+
+ return
+
@lldb_command('showallthreads')
def ShowAllThreads(cmd_args = None):
""" Display info about all threads in the system
""" Routine to print out the state of a specific thread.
usage: showact <activation>
"""
- 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)
""" Routine to print out the stack of a specific thread.
usage: showactstack <activation>
"""
- 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)
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
if not LazyTarget.GetProcess().SetSelectedThread(lldbthread):
print "Failed to switch thread."
return
+
+@lldb_command('switchtoregs')
+def SwitchToRegs(cmd_args=None):
+ """ Routine to switch to a register state.
+ Usage: (lldb) switchtoregs <struct arm_saved_state[64] *>
+ This command creates a fake thread in lldb with the saved register state.
+ Note: This command ONLY works for ARM based kernel setup.
+ """
+
+ if cmd_args == None or len(cmd_args) < 1:
+ raise ArgumentError("No arguments passed")
+
+ lldb_process = LazyTarget.GetProcess()
+
+ saved_state = ArgumentStringToInt(cmd_args[0])
+ # any change to this logic requires change in operating_system.py as well
+ fake_thread_id = 0xdead0000 | (saved_state & ~0xffff0000)
+ fake_thread_id = fake_thread_id & 0xdeadffff
+ lldb_process.CreateOSPluginThread(0xdeadbeef, saved_state)
+ lldbthread = lldb_process.GetThreadByID(int(fake_thread_id))
+
+ if not lldbthread.IsValid():
+ print "Failed to create thread"
+ return
+
+ lldb_process.selected_thread = lldbthread
+ if not lldb_process.SetSelectedThread(lldbthread):
+ print "Failed to switch thread"
+ print "Switched to Fake thread created from register state at 0x%x" % saved_state
+
+
+
# Macro: showallstacks
@lldb_command('showallstacks')
def ShowAllStacks(cmd_args=None):
# <rdar://problem/12677290> 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 != 'arm' and frame_ptr < mh_execute_addr) or (kern.arch == 'arm' 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))
return
print "Not a valid thread_id"
-# Macro: showallprocessors
-
def GetProcessorSummary(processor):
""" Internal function to print summary of processor
params: processor - value representing struct processor *
if processor_state in processor_states:
processor_state_str = "{0: <11s} ".format(processor_states[processor_state])
- out_str = "Processor {: <#018x} cpu_id {:>#4x} State {:<s}\n".format(processor, int(processor.cpu_id), processor_state_str)
- return out_str
+ processor_recommended_str = ""
+ if int(processor.is_recommended) == 0:
+ processor_recommended_str = " (not recommended)"
-def GetGroupSetSummary(runq, task_map):
- """ Internal function to print summary of group run queue
- params: runq - value representing struct run_queue *
- return: str - representing the details of given run_queue
- """
- out_str = " runq: count {: <10d} highq: {: <10d} urgency {: <10d}\n".format(runq.count, runq.highq, runq.urgency)
-
- runq_queue_i = 0
- runq_queue_count = sizeof(runq.queues)/sizeof(runq.queues[0])
-
- for runq_queue_i in range(runq_queue_count) :
- runq_queue_head = addressof(runq.queues[runq_queue_i])
- runq_queue_p = runq_queue_head.next
-
- if unsigned(runq_queue_p) != unsigned(runq_queue_head):
- runq_queue_this_count = 0
-
- for entry in IterateQueue(runq_queue_head, "sched_entry_t", "links"):
- runq_queue_this_count += 1
-
- out_str += " Queue [{: <#012x}] Priority {: <3d} count {:d}\n".format(runq_queue_head, runq_queue_i, runq_queue_this_count)
- for entry in IterateQueue(runq_queue_head, "sched_entry_t", "links"):
- group = entry.group
- task = task_map.get(unsigned(group), "Unknown task!")
- out_str += "\tEntry [{: <#012x}] Priority {: <3d} Group {: <#012x} Task {: <#012x}\n".format(unsigned(entry), entry.sched_pri, unsigned(entry.group), unsigned(task))
-
- return out_str
+ ast = 0
+ preemption_disable = 0
+ preemption_disable_str = ""
-@lldb_command('showrunq')
-def ShowRunq(cmd_args=None):
- """ Routine to print information of a runq
- Usage: showrunq <runq>
- """
- out_str = ''
- runq = kern.GetValueFromAddress(cmd_args[0], 'struct run_queue *')
- out_str += GetRunQSummary(runq)
- print out_str
-
-def GetRunQSummary(runq):
- """ Internal function to print summary of run_queue
- params: runq - value representing struct run_queue *
- return: str - representing the details of given run_queue
- """
- out_str = " runq: count {: <10d} highq: {: <10d} urgency {: <10d}\n".format(runq.count, runq.highq, runq.urgency)
-
- runq_queue_i = 0
- runq_queue_count = sizeof(runq.queues)/sizeof(runq.queues[0])
-
- for runq_queue_i in range(runq_queue_count) :
- runq_queue_head = addressof(runq.queues[runq_queue_i])
- runq_queue_p = runq_queue_head.next
-
- if unsigned(runq_queue_p) != unsigned(runq_queue_head):
- runq_queue_this_count = 0
-
- for thread in IterateQueue(runq_queue_head, "thread_t", "links"):
- runq_queue_this_count += 1
-
- out_str += " Queue [{: <#012x}] Priority {: <3d} count {:d}\n".format(runq_queue_head, runq_queue_i, runq_queue_this_count)
- out_str += "\t" + GetThreadSummary.header + "\n"
- for thread in IterateQueue(runq_queue_head, "thread_t", "links"):
- out_str += "\t" + GetThreadSummary(thread) + "\n"
- if config['verbosity'] > vHUMAN :
- out_str += "\t" + GetThreadBackTrace(thread, prefix="\t\t") + "\n"
- return out_str
+ if kern.arch == 'x86_64':
+ cpu_data = kern.globals.cpu_data_ptr[processor.cpu_id]
+ if (cpu_data != 0) :
+ ast = cpu_data.cpu_pending_ast
+ preemption_disable = cpu_data.cpu_preemption_level
+ # On arm64, it's kern.globals.CpuDataEntries[processor.cpu_id].cpu_data_vaddr
+ # but LLDB can't find CpuDataEntries...
+ ast_str = GetASTSummary(ast)
-def GetGrrrSummary(grrr_runq):
- """ Internal function to print summary of grrr_run_queue
- params: grrr_runq - value representing struct grrr_run_queue *
- return: str - representing the details of given grrr_run_queue
- """
- out_str = " GRRR Info: Count {: <10d} Weight {: <10d} Current Group {: <#012x}\n".format(grrr_runq.count,
- grrr_runq.weight, grrr_runq.current_group)
- grrr_group_i = 0
- grrr_group_count = sizeof(grrr_runq.groups)/sizeof(grrr_runq.groups[0])
- for grrr_group_i in range(grrr_group_count) :
- grrr_group = addressof(grrr_runq.groups[grrr_group_i])
- if grrr_group.count > 0:
- out_str += " Group {: <3d} [{: <#012x}] ".format(grrr_group.index, grrr_group)
- out_str += "Count {:d} Weight {:d}\n".format(grrr_group.count, grrr_group.weight)
- grrr_group_client_head = addressof(grrr_group.clients)
- out_str += GetThreadSummary.header
- for thread in IterateQueue(grrr_group_client_head, "thread_t", "links"):
- out_str += "\t" + GetThreadSummary(thread) + "\n"
- if config['verbosity'] > vHUMAN :
- out_str += "\t" + GetThreadBackTrace(thread, prefix="\t\t") + "\n"
- return out_str
-
-@lldb_command('showallprocessors')
-def ShowAllProcessors(cmd_args=None):
- """ Routine to print information of all psets and processors
- Usage: showallprocessors
- """
- pset = addressof(kern.globals.pset0)
- show_grrr = 0
- show_priority_runq = 0
- show_priority_pset_runq = 0
- show_group_pset_runq = 0
- show_fairshare_grrr = 0
- show_fairshare_list = 0
- sched_enum_val = kern.globals._sched_enum
-
- if sched_enum_val == 1:
- show_priority_runq = 1
- show_fairshare_list = 1
- elif sched_enum_val == 2:
- show_priority_pset_runq = 1
- show_fairshare_list = 1
- elif sched_enum_val == 4:
- show_grrr = 1
- show_fairshare_grrr = 1
- elif sched_enum_val == 5:
- show_priority_runq = 1
- show_group_pset_runq = 1
- show_fairshare_list = 1
- elif sched_enum_val == 6:
- show_priority_pset_runq = 1
- show_priority_runq = 1
- show_fairshare_list = 1
-
- out_str = ''
-
- out_str += "Scheduler: {:s} ({:s}, {:d})\n".format(kern.globals.sched_string,
- kern.Symbolicate(unsigned(kern.globals.sched_current_dispatch)),
- sched_enum_val)
-
- out_str += "Runnable threads: {:d} Timeshare threads: {:d} Background threads {:d}\n".format(
- kern.globals.sched_run_count, kern.globals.sched_share_count, kern.globals.sched_background_count)
-
- if show_group_pset_runq:
- # Create a group->task mapping
- task_map = {}
- for task in kern.tasks:
- task_map[unsigned(task.sched_group)] = task
- for task in kern.terminated_tasks:
- task_map[unsigned(task.sched_group)] = task
-
- while unsigned(pset) != 0:
- out_str += "Processor Set {: <#012x} Count {:d} (cpu_id {:<#x}-{:<#x})\n".format(pset,
- pset.cpu_set_count, pset.cpu_set_low, pset.cpu_set_hi)
-
- if show_priority_pset_runq:
- runq = pset.pset_runq
- out_str += GetRunQSummary(runq)
-
- if show_group_pset_runq:
- out_str += "Main Runq:\n"
- runq = pset.pset_runq
- out_str += GetGroupSetSummary(runq, task_map)
- out_str += "All Groups:\n"
- # TODO: Possibly output task header for each group
- for group in IterateQueue(kern.globals.sched_groups, "sched_group_t", "sched_groups"):
- if (group.runq.count != 0) :
- task = task_map.get(unsigned(group), "Unknown task!")
- out_str += "Group {: <#012x} Task {: <#012x}\n".format(unsigned(group), unsigned(task))
- out_str += GetRunQSummary(group.runq)
-
- out_str += " Active Processors:\n"
- for processor in IterateQueue(pset.active_queue, "processor_t", "processor_queue"):
- out_str += " "
- out_str += GetProcessorSummary(processor)
- if show_priority_runq:
- runq = processor.runq
- out_str += GetRunQSummary(runq)
- if show_grrr:
- grrr_runq = processor.grrr_runq
- out_str += GetGrrrSummary(grrr_runq)
-
- out_str += " Idle Processors:\n"
- for processor in IterateQueue(pset.idle_queue, "processor_t", "processor_queue"):
- out_str += " " + GetProcessorSummary(processor)
- if show_priority_runq:
- out_str += GetRunQSummary(processor.runq)
-
- out_str += " Idle Secondary Processors:\n"
- for processor in IterateQueue(pset.idle_secondary_queue, "processor_t", "processor_queue"):
- out_str += " " + GetProcessorSummary(processor)
- if show_priority_runq:
- out_str += GetRunQSummary(processor.runq)
-
- pset = pset.pset_list
-
- out_str += "\nRealtime Queue Count {:d}\n".format(kern.globals.rt_runq.count)
- for rt_runq_thread in IterateQueue(kern.globals.rt_runq.queue, "thread_t", "links"):
- out_str += ShowTask([unsigned(rt_runq_thread.task)])
- out_str += ShowAct([unsigned(rt_runq_thread)])
-
- out_str += "\n"
- if show_fairshare_list:
- out_str += "Fair Share Queue Count {:d}\n".format(kern.globals.fs_runq.count)
- for fs_runq_thread in IterateQueue(kern.globals.fs_runq.queue, "thread_t", "links"):
- out_str += ShowTask([unsigned(fs_runq_thread.task)])
- out_str += ShowAct([unsigned(rt_runq_thread)])
- if show_fairshare_grrr:
- out_str += "Fair Share Queue Count {:d}\n".format(kern.globals.fs_grrr_runq.count)
- fs_grrr = addressof(kern.globals.fs_grrr_runq)
- out_str += GetGrrrSummary(fs_grrr)
+ if (preemption_disable != 0) :
+ preemption_disable_str = "Preemption Disabled"
- print out_str
-# EndMacro: showallprocessors
+ out_str = "Processor {: <#018x} cpu_id {:>#4x} AST: {:<6s} State {:<s}{:<s} {:<s}\n".format(
+ processor, int(processor.cpu_id), ast_str, processor_state_str, processor_recommended_str,
+ 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 *
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))
else:
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 (unsigned(ledger.le_warn_percent) < 65535):
+ out_str += "{:9d} ".format(unsigned(ledger.le_warn_percent * 100. / 65536))
else:
out_str += " - "
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
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
# 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 <address of task>
- or : showtaskledgers -F <name of task>
+ or : showtaskledgers [ -I ] [ -F ] <task>
+ 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"])
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
["bg_iotier", "bg-iotier"],
["terminated", "terminated"],
["th_pidbind_bg", "bg-pidbind"],
- ["th_workq_bg", "bg-workq"],
["t_apptype", "apptype"],
["t_boosted", "boosted"],
- ["t_int_gpu_deny", "gpudeny-int"],
- ["t_ext_gpu_deny", "gpudeny-ext"],
["t_role", "role"],
["t_tal_enabled", "tal-enabled"],
["t_base_latency_qos", "latency-base"],
else:
effective+=""
-
- pended_strings = [
- ["t_updating_policy", "updating"],
- ["update_sockets", "update_sockets"],
- ["t_update_timers", "update_timers"],
- ["t_update_watchers", "update_watchers"]
- ]
-
- pended=""
- for value in pended_strings:
- if t.pended_policy.__getattr__(value[0]) :
- pended+=value[1] + ": " + str(t.pended_policy.__getattr__(value[0])) + " "
- else:
- pended+=""
-
print "requested: " + requested
print "suppression: " + suppression
print "effective: " + effective
- print "pended: " + pended
@lldb_type_summary(['wait_queue', 'wait_queue_t'])
print GetTaskSummary(t) + ' ' + GetProcSummary(Cast(t.bsd_info, 'proc *'))
return True
+# Macro: showallpte
+@lldb_command('showallpte')
+def ShowAllPte(cmd_args=None):
+ """ Prints out the physical address of the pte for all tasks
+ """
+ head_taskp = addressof(kern.globals.tasks)
+ taskp = Cast(head_taskp.next, 'task *')
+ while taskp != head_taskp:
+ 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)
+ else:
+ out_str += "\n"
+ print out_str
+ taskp = Cast(taskp.tasks.next, 'struct task *')
+
+# EndMacro: showallpte
+
+# Macro: showallrefcounts
+@lldb_command('showallrefcounts')
+@header("{0: <20s} {1: ^10s}".format("task", "ref_count"))
+def ShowAllRefCounts(cmd_args=None):
+ """ Prints the ref_count of all tasks
+ """
+ out_str = ''
+ head_taskp = addressof(kern.globals.tasks)
+ taskp = Cast(head_taskp.next, 'task *')
+ print ShowAllRefCounts.header
+ while taskp != head_taskp:
+ out_str += "{: <#20x}".format(taskp)
+ out_str += "{: ^10d}\n".format(taskp.ref_count)
+ taskp = Cast(taskp.tasks.next, 'task *')
+ print out_str
+# EndMacro: showallrefcounts
+
+# Macro: showallrunnablethreads
+@lldb_command('showallrunnablethreads')
+def ShowAllRunnableThreads(cmd_args=None):
+ """ Prints the sched usage information for all threads of each task
+ """
+ out_str = ''
+ for taskp in kern.tasks:
+ for actp in IterateQueue(taskp.threads, 'thread *', 'task_threads'):
+ if int(actp.state & 0x4):
+ ShowActStack([unsigned(actp)])
+
+# EndMacro: showallrunnablethreads
+
+# Macro: showallschedusage
+@lldb_command('showallschedusage')
+@header("{0:<20s} {1:^10s} {2:^10s} {3:^15s}".format("Thread", "Priority", "State", "sched_usage"))
+def ShowAllSchedUsage(cmd_args=None):
+ """ Prints the sched usage information for all threads of each task
+ """
+ out_str = ''
+ for taskp in kern.tasks:
+ ShowTask([unsigned(taskp)])
+ print ShowAllSchedUsage.header
+ for actp in IterateQueue(taskp.threads, 'thread *', 'task_threads'):
+ out_str = "{: <#20x}".format(actp)
+ out_str += "{: ^10s}".format(str(int(actp.sched_pri)))
+ state = int(actp.state)
+ thread_state_chars = {0:'', 1:'W', 2:'S', 4:'R', 8:'U', 16:'H', 32:'A', 64:'P', 128:'I'}
+ state_str = ''
+ state_str += thread_state_chars[int(state & 0x1)]
+ state_str += thread_state_chars[int(state & 0x2)]
+ state_str += thread_state_chars[int(state & 0x4)]
+ state_str += thread_state_chars[int(state & 0x8)]
+ state_str += thread_state_chars[int(state & 0x10)]
+ state_str += thread_state_chars[int(state & 0x20)]
+ state_str += thread_state_chars[int(state & 0x40)]
+ state_str += thread_state_chars[int(state & 0x80)]
+ out_str += "{: ^10s}".format(state_str)
+ out_str += "{: >15d}".format(actp.sched_usage)
+ print out_str + "\n"
+ print "\n\n"
+
+# EndMacro: showallschedusage
+
+#Macro: showprocfilessummary
+@lldb_command('showprocfilessummary')
+@header("{0: <20s} {1: <20s} {2: >10s}".format("Process", "Name", "Number of Open Files"))
+def ShowProcFilesSummary(cmd_args=None):
+ """ Display the summary of open file descriptors for all processes in task list
+ Usage: showprocfilessummary
+ """
+ print ShowProcFilesSummary.header
+ for proc in kern.procs:
+ proc_filedesc = proc.p_fd
+ proc_ofiles = proc_filedesc.fd_ofiles
+ proc_lastfile = unsigned(proc_filedesc.fd_lastfile)
+ count = 0
+ proc_file_count = 0
+ if proc_filedesc.fd_nfiles != 0:
+ while count <= proc_lastfile:
+ 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)
+
+#EndMacro: showprocfilessummary
+
+@lldb_command('workinguserstacks')
+def WorkingUserStacks(cmd_args=None):
+ """ Print out the user stack for each thread in a task, followed by the user libraries.
+ Syntax: (lldb) workinguserstacks <task_t>
+ """
+ if not cmd_args:
+ print "Insufficient arguments" + ShowTaskUserStacks.__doc__
+ return False
+ task = kern.GetValueFromAddress(cmd_args[0], 'task *')
+ print GetTaskSummary.header + " " + GetProcSummary.header
+ pval = Cast(task.bsd_info, 'proc *')
+ print GetTaskSummary(task) + " " + GetProcSummary(pval) + "\n \n"
+ for thval in IterateQueue(task.threads, 'thread *', 'task_threads'):
+ print "For thread 0x{0:x}".format(thval)
+ try:
+ ShowThreadUserStack([hex(thval)])
+ except Exception as exc_err:
+ print "Failed to show user stack for thread 0x{0:x}".format(thval)
+ if config['debug']:
+ raise exc_err
+ else:
+ print "Enable debugging ('(lldb) xnudebug debug') to see detailed trace."
+ WorkingUserLibraries([hex(task)])
+ return
+
+@static_var("exec_load_path", 0)
+@lldb_command("workingkuserlibraries")
+def WorkingUserLibraries(cmd_args=None):
+ """ Show binary images known by dyld in target task
+ For a given user task, inspect the dyld shared library state and print information about all Mach-O images.
+ Syntax: (lldb)workinguserlibraries <task_t>
+ """
+ if not cmd_args:
+ print "Insufficient arguments"
+ print ShowTaskUserLibraries.__doc__
+ return False
+
+ print "{0: <18s} {1: <12s} {2: <36s} {3: <50s}".format('address','type','uuid','path')
+ out_format = "0x{0:0>16x} {1: <12s} {2: <36s} {3: <50s}"
+ task = kern.GetValueFromAddress(cmd_args[0], 'task_t')
+ is_task_64 = int(task.t_flags) & 0x1
+ dyld_all_image_infos_address = unsigned(task.all_image_info_addr)
+ cur_data_offset = 0
+ if dyld_all_image_infos_address == 0:
+ print "No dyld shared library information available for task"
+ return False
+ vers_info_data = GetUserDataAsString(task, dyld_all_image_infos_address, 112)
+ version = _ExtractDataFromString(vers_info_data, cur_data_offset, "uint32_t")
+ cur_data_offset += 4
+ if version > 12:
+ print "Unknown dyld all_image_infos version number %d" % version
+ image_info_count = _ExtractDataFromString(vers_info_data, cur_data_offset, "uint32_t")
+ WorkingUserLibraries.exec_load_path = 0
+ if is_task_64:
+ image_info_size = 24
+ image_info_array_address = _ExtractDataFromString(vers_info_data, 8, "uint64_t")
+ dyld_load_address = _ExtractDataFromString(vers_info_data, 8*4, "uint64_t")
+ dyld_all_image_infos_address_from_struct = _ExtractDataFromString(vers_info_data, 8*13, "uint64_t")
+ else:
+ image_info_size = 12
+ image_info_array_address = _ExtractDataFromString(vers_info_data, 4*2, "uint32_t")
+ dyld_load_address = _ExtractDataFromString(vers_info_data, 4*5, "uint32_t")
+ dyld_all_image_infos_address_from_struct = _ExtractDataFromString(vers_info_data, 4*14, "uint32_t")
+ # Account for ASLR slide before dyld can fix the structure
+ dyld_load_address = dyld_load_address + (dyld_all_image_infos_address - dyld_all_image_infos_address_from_struct)
+
+ i = 0
+ while i < image_info_count:
+ image_info_address = image_info_array_address + i * image_info_size
+ img_data = GetUserDataAsString(task, image_info_address, image_info_size)
+ if is_task_64:
+ image_info_addr = _ExtractDataFromString(img_data, 0, "uint64_t")
+ image_info_path = _ExtractDataFromString(img_data, 8, "uint64_t")
+ else:
+ image_info_addr = _ExtractDataFromString(img_data, 0, "uint32_t")
+ image_info_path = _ExtractDataFromString(img_data, 4, "uint32_t")
+ PrintImageInfo(task, image_info_addr, image_info_path)
+ i += 1
+
+ # load_path might get set when the main executable is processed.
+ if WorkingUserLibraries.exec_load_path != 0:
+ PrintImageInfo(task, dyld_load_address, WorkingUserLibraries.exec_load_path)
+ return
+
+# Macro: showstackaftertask
+@lldb_command('showstackaftertask','F:')
+def Showstackaftertask(cmd_args=None,cmd_options={}):
+ """ Routine to print the thread stacks for all tasks succeeding a given task
+ Usage: showstackaftertask <0xaddress of task>
+ or: showstackaftertask -F <taskname>
+ """
+ if "-F" in cmd_options:
+ # Find the task pointer corresponding to its task name
+ find_task_str = cmd_options["-F"]
+ task_list = FindTasksByName(find_task_str)
+
+ # Iterate through the list of tasks and print all task stacks thereafter
+ for tval in task_list:
+ ListTaskStacks(tval)
+ return
+
+ if not cmd_args:
+ raise ArgumentError("Insufficient arguments")
+ tval = kern.GetValueFromAddress(cmd_args[0], 'task *')
+ if not tval:
+ raise ArgumentError("unknown arguments: {:s}".format(str(cmd_args)))
+ else:
+ ListTaskStacks(tval)
+
+ ZombStacks()
+ return
+# EndMacro: showstackaftertask
+
+def ListTaskStacks(task):
+ """ Search for a given task and print the list of all task stacks thereafter.
+ """
+ # Initialize local variable task_flag to mark when a given task is found.
+ task_flag=0
+
+ for t in kern.tasks:
+ if (task_flag == 1):
+ ShowTaskStacks(t)
+ print "\n"
+ if (t == task):
+ task_flag = 1
+
+# Macro: showstackafterthread
+@lldb_command('showstackafterthread')
+def Showstackafterthread(cmd_args = None):
+ """ Routine to print the stacks of all threads succeeding a given thread.
+ Usage: Showstackafterthread <0xaddress of thread>
+ """
+ # local variable thread_flag is used to mark when a given thread is found.
+ thread_flag=0
+ if cmd_args:
+ threadval = kern.GetValueFromAddress(cmd_args[0], 'thread *')
+ else:
+ raise ArgumentError("No arguments passed")
+ # Iterate through list of all tasks to look up a given thread
+ for t in kern.tasks:
+ if(thread_flag==1):
+ pval = Cast(t.bsd_info, 'proc *')
+ print GetTaskSummary.header + " "+ GetProcSummary.header
+ print GetTaskSummary(t) + " "+ GetProcSummary(pval)
+ print "\n"
+ # Look up for a given thread from the the list of threads of a given task
+ for thval in IterateQueue(t.threads, 'thread *', 'task_threads'):
+ if (thread_flag==1):
+ print "\n"
+ print " " + GetThreadSummary.header
+ print " " + GetThreadSummary(thval)
+ print GetThreadBackTrace(thval, prefix="\t")+"\n"
+ print "\n"
+
+ if(thval==threadval):
+ pval = Cast(t.bsd_info, 'proc *')
+ process_name = "{:s}".format(pval.p_comm)
+ print "\n\n"
+ print " *** Continuing to dump the thread stacks from the process *** :" + " " + process_name
+ print "\n\n"
+ thread_flag = 1
+ print '\n'
+ return