xref: /xnu-8796.141.3/tools/lldbmacros/process.py (revision 1b191cb58250d0705d8a51287127505aa4bc0789)
1
2""" Please make sure you read the README file COMPLETELY BEFORE reading anything below.
3    It is very critical that you read coding guidelines in Section E in README file.
4"""
5from __future__ import absolute_import, division, print_function
6
7from builtins import hex
8from builtins import range
9
10from xnu import *
11import sys, shlex
12from utils import *
13from core.lazytarget import *
14import time
15import xnudefines
16import kmemory
17import memory
18import json
19from collections import defaultdict, namedtuple
20
21NO_PROC_NAME = "unknown"
22P_LHASTASK = 0x00000002
23TF_HAS_PROC = 0x00800000
24
25def GetProcPID(proc):
26    """ returns the PID of a process.
27        params:
28            proc: value object representing a proc in the kernel.
29        returns:
30            int: the pid of the process.
31    """
32    return unsigned(proc.p_pid) if proc else -1
33
34def GetProcPlatform(proc):
35    """ returns the platform identifier of a process.
36        params:
37            proc: value object representing a proc in the kernel.
38        returns:
39            int: the platform identifier of the process.
40    """
41    if not proc:
42        return None
43    return int(proc.p_proc_ro.p_platform_data.p_platform)
44
45def GetProcName(proc):
46    """ returns a string name of the process. Longer variant is preffered if provided.
47        params:
48            proc: value object representing a proc in the kernel.
49        returns:
50            str: a string name of the process linked to the task.
51    """
52    if not proc:
53        return NO_PROC_NAME
54    name = str(proc.p_name)
55    return name if name != '' else str(proc.p_comm)
56
57def GetProcNameForTask(task):
58    """ returns a string name of the process. If proc is not valid the proc
59        name is looked up in the associated importance structure (if
60        available). If no name can be found, "unknown"  is returned.
61        params:
62            task: value object represeting a task in the kernel.
63        returns:
64            str : A string name of the process linked to the task
65    """
66    if task:
67        p = GetProcFromTask(task)
68        if p:
69            return GetProcName(p)
70
71        if (hasattr(task, 'task_imp_base') and
72           hasattr(task.task_imp_base, 'iit_procname') and
73           unsigned(task.task_imp_base) != 0):
74            return str(task.task_imp_base.iit_procname)
75
76    return NO_PROC_NAME
77
78def GetProcPIDForTask(task):
79    """ returns a int pid of the process. if the proc is not valid, val[5] from audit_token is returned.
80        params:
81            task: value object representing a task in the kernel
82        returns:
83            int : pid of the process or -1 if not found
84    """
85    if not task:
86        return -1
87
88    p = GetProcFromTask(task)
89    if p:
90        return GetProcPID(p)
91
92    proc_ro = Cast(task.bsd_info_ro, 'proc_ro *')
93    pid = unsigned(proc_ro.task_tokens.audit_token.val[5])
94    return pid
95
96def GetProcStartAbsTimeForTask(task):
97    if task:
98        p = GetProcFromTask(task)
99        if unsigned(p):
100            return p.p_stats.ps_start
101    return None
102
103def GetProcInfo(proc):
104    """ returns a string name, pid, parent and task for a proc_t. Decodes cred, flag and p_stat fields.
105        params:
106            proc : value object representing a proc in the kernel
107        returns:
108            str : A string describing various information for process.
109    """
110    out_string = ""
111    out_string += ("Process {p: <#020x}\n\tname {0: <32s}\n\tpid:{1: <6d} " +
112                   "task:{task: <#020x} p_stat:{p.p_stat: <6d} parent pid: {p.p_ppid: <6d}\n"
113                   ).format(GetProcName(proc), GetProcPID(proc), task=GetTaskFromProc(proc), p=proc)
114    #print the Creds
115    ucred = proc.p_proc_ro.p_ucred
116    if ucred:
117        out_string += "Cred: euid {:d} ruid {:d} svuid {:d}\n".format(ucred.cr_posix.cr_uid,
118                                                                      ucred.cr_posix.cr_ruid,
119                                                                      ucred.cr_posix.cr_svuid )
120    #print the flags
121    flags = int(proc.p_flag)
122    out_string += "Flags: {0: <#020x}\n".format(flags)
123    num = 1
124    while num <= flags:
125        if flags & num:
126            explain_str = xnudefines.proc_flag_explain_strings.get(num, 'unknown')
127            out_string += "\t0x{:08x} - ".format(num) + explain_str + "\n"
128        elif num == 0x4: #special case for 32bit flag
129            out_string += "\t!0x00000004 - process is 32 bit\n"
130        num = num << 1
131    out_string += "State: "
132    state_val = proc.p_stat
133    if state_val < 1 or state_val > len(xnudefines.proc_state_strings) :
134        out_string += "(Unknown)"
135    else:
136        out_string += xnudefines.proc_state_strings[int(state_val)]
137
138    return out_string
139
140def GetProcNameForPid(pid):
141    """ Finds the name of the process corresponding to a given pid
142        params:
143            pid     : int, pid you want to find the procname for
144        returns
145            str     : Name of the process corresponding to the pid, "Unknown" if not found
146    """
147    for p in kern.procs:
148        if int(GetProcPID(p)) == int(pid):
149            return GetProcName(p)
150    return NO_PROC_NAME
151
152def GetProcForPid(search_pid):
153    """ Finds the value object representing a proc in the kernel based on its pid
154        params:
155            search_pid  : int, pid whose proc structure you want to find
156        returns:
157            value       : The value object representing the proc, if a proc corresponding
158                          to the given pid is found. Returns None otherwise
159    """
160    if search_pid == 0:
161        return kern.globals.initproc
162    else:
163        headp = kern.globals.allproc
164        for proc in IterateListEntry(headp, 'p_list'):
165            if GetProcPID(proc) == search_pid:
166                return proc
167        return None
168
169@lldb_command('allproc')
170def AllProc(cmd_args=None):
171    """ Walk through the allproc structure and print procinfo for each process structure.
172        params:
173            cmd_args - [] : array of strings passed from lldb command prompt
174    """
175    for proc in kern.procs :
176        print(GetProcInfo(proc))
177
178
179@lldb_command('zombproc')
180def ZombProc(cmd_args=None):
181    """ Routine to print out all procs in the zombie list
182        params:
183            cmd_args - [] : array of strings passed from lldb command prompt
184    """
185    if any(kern.zombprocs):
186        print("\nZombie Processes:")
187        for proc in kern.zombprocs:
188            print(GetProcInfo(proc) + "\n\n")
189
190@lldb_command('zombtasks')
191def ZombTasks(cmd_args=None):
192    """ Routine to print out all tasks in the zombie list
193        params: None
194    """
195    out_str = ""
196    if any(kern.zombprocs):
197        header = "\nZombie Tasks:\n"
198        header += GetTaskSummary.header + " " + GetProcSummary.header
199        for proc in kern.zombprocs:
200            if proc.p_stat != 5:
201                t = GetTaskFromProc(proc)
202                out_str += GetTaskSummary(t) +" "+ GetProcSummary(proc) + "\n"
203        if out_str != "":
204            print(header)
205            print(out_str)
206
207@lldb_command('zombstacks', fancy=True)
208def ZombStacks(cmd_args=None, cmd_options={}, O=None):
209    """ Routine to print out all stacks of tasks that are exiting
210    """
211    header_flag = 0
212    for proc in kern.zombprocs:
213        if proc.p_stat != 5:
214            if header_flag == 0:
215                print("\nZombie Stacks:")
216                header_flag = 1
217            t = GetTaskFromProc(proc)
218            ShowTaskStacks(t, O=O)
219#End of Zombstacks
220
221def GetASTSummary(ast):
222    """ Summarizes an AST field
223        Flags:
224        P - AST_PREEMPT
225        Q - AST_QUANTUM
226        U - AST_URGENT
227        H - AST_HANDOFF
228        Y - AST_YIELD
229        A - AST_APC
230        L - AST_LEDGER
231        B - AST_BSD
232        K - AST_KPERF
233        M - AST_MACF
234        r - AST_RESET_PCS
235        a - AST_ARCADE
236        G - AST_GUARD
237        T - AST_TELEMETRY_USER
238        T - AST_TELEMETRY_KERNEL
239        T - AST_TELEMETRY_WINDOWED
240        S - AST_SFI
241        D - AST_DTRACE
242        I - AST_TELEMETRY_IO
243        E - AST_KEVENT
244        R - AST_REBALANCE
245        N - AST_UNQUIESCE
246        p  - AST_PROC_RESOURCE
247    """
248    out_string = ""
249    state = int(ast)
250    thread_state_chars = {0x0:'', 0x1:'P', 0x2:'Q', 0x4:'U', 0x8:'H', 0x10:'Y', 0x20:'A',
251                          0x40:'L', 0x80:'B', 0x100:'K', 0x200:'M', 0x400: 'r', 0x800: 'a',
252                          0x1000:'G', 0x2000:'T', 0x4000:'T', 0x8000:'T', 0x10000:'S',
253                          0x20000: 'D', 0x40000: 'I', 0x80000: 'E', 0x100000: 'R', 0x200000: 'N', 0x400000: 'p'}
254    state_str = ''
255    mask = 0x1
256    while mask <= 0x200000:
257        state_str += thread_state_chars[int(state & mask)]
258        mask = mask << 1
259
260    return state_str
261
262
263@lldb_type_summary(['kcdata_descriptor *', 'kcdata_descriptor_t'])
264@header("{0: <20s} {1: <20s} {2: <20s} {3: <10s} {4: <5s}".format("kcdata_descriptor", "begin_addr", "cur_pos", "size", "flags"))
265def GetKCDataSummary(kcdata):
266    """ Summarizes kcdata_descriptor structure
267        params: kcdata: value - value object representing kcdata_descriptor
268        returns: str - summary of the kcdata object
269    """
270    format_string = "{0: <#020x} {1: <#020x} {2: <#020x} {3: <10d} {4: <#05x}"
271    return format_string.format(kcdata, kcdata.kcd_addr_begin, kcdata.kcd_addr_end, kcdata.kcd_length, kcdata.kcd_flags)
272
273
274@lldb_type_summary(['task', 'task_t'])
275@header("{0: <20s} {1: <20s} {2: <20s} {3: >5s} {4: <5s}".format("task","vm_map", "ipc_space", "#acts", "flags"))
276def GetTaskSummary(task, showcorpse=False):
277    """ Summarizes the important fields in task structure.
278        params: task: value - value object representing a task in kernel
279        returns: str - summary of the task
280    """
281    out_string = ""
282    format_string = '{0: <#020x} {1: <#020x} {2: <#020x} {3: >5d} {4: <5s}'
283    thread_count = int(task.thread_count)
284    task_flags = ''
285    if hasattr(task, "suppression_generation") and (int(task.suppression_generation) & 0x1) == 0x1:
286        task_flags += 'P'
287    if hasattr(task, "effective_policy") and int(task.effective_policy.tep_sup_active) == 1:
288        task_flags += 'N'
289    if hasattr(task, "suspend_count") and int(task.suspend_count) > 0:
290        task_flags += 'S'
291    if hasattr(task, 'task_imp_base') and unsigned(task.task_imp_base):
292        tib = task.task_imp_base
293        if int(tib.iit_receiver) == 1:
294            task_flags += 'R'
295        if int(tib.iit_donor) == 1:
296            task_flags += 'D'
297        if int(tib.iit_assertcnt) > 0:
298            task_flags += 'B'
299
300    proc_ro = Cast(task.bsd_info_ro, 'proc_ro *')
301
302    # check if corpse flag is set
303    if unsigned(proc_ro.t_flags_ro) & 0x20:
304        task_flags += 'C'
305    if unsigned(task.t_flags) & 0x40:
306        task_flags += 'P'
307
308    out_string += format_string.format(task, task.map, task.itk_space, thread_count, task_flags)
309    if showcorpse is True and unsigned(task.corpse_info) != 0:
310        out_string += " " + GetKCDataSummary(task.corpse_info)
311    return out_string
312
313def GetMachThread(uthread):
314    """ Converts the passed in value interpreted as a uthread_t into a thread_t
315    """
316    addr = unsigned(uthread) - sizeof('struct thread')
317    thread = kern.GetValueFromAddress(addr, 'struct thread *')
318    return thread
319
320def GetBSDThread(thread):
321    """ Converts the passed in value interpreted as a thread_t into a uthread_t
322    """
323    addr = unsigned(thread) + sizeof('struct thread')
324    return kern.GetValueFromAddress(addr, 'struct uthread *')
325
326def GetProcFromTask(task):
327    """ Converts the passed in value interpreted as a task_t into a proc_t
328    """
329    if unsigned(task) and unsigned(task.t_flags) & TF_HAS_PROC:
330        addr = unsigned(task) - kern.globals.proc_struct_size
331        return value(task.GetSBValue().xCreateValueFromAddress(
332            'proc', addr, gettype('struct proc')
333        ).AddressOf())
334    return kern.GetValueFromAddress(0, 'proc *')
335
336def GetTaskFromProc(proc):
337    """ Converts the passed in value interpreted as a proc_t into a task_t
338    """
339    if unsigned(proc) and unsigned(proc.p_lflag) & P_LHASTASK:
340        addr = unsigned(proc) + kern.globals.proc_struct_size
341        return value(proc.GetSBValue().xCreateValueFromAddress(
342            'task', addr, gettype('struct task')
343        ).AddressOf())
344    return kern.GetValueFromAddress(0, 'task *')
345
346def GetThreadName(thread):
347    """ Get the name of a thread, if possible.  Returns the empty string
348        otherwise.
349    """
350    uthread = GetBSDThread(thread)
351    if int(uthread.pth_name) != 0 :
352        th_name_strval = Cast(uthread.pth_name, 'char *')
353        if len(str(th_name_strval)) > 0 :
354            return str(th_name_strval)
355
356    return ''
357
358ThreadSummary = namedtuple('ThreadSummary', [
359        'thread', 'tid', 'task', 'processor', 'base', 'pri', 'sched_mode', 'io_policy',
360        'state', 'ast', 'waitq', 'wait_evt', 'wait_evt_sym', 'wait_msg',
361        'name'])
362ThreadSummaryNames = ThreadSummary(*ThreadSummary._fields)
363ThreadSummaryFormat = (
364        '{ts.thread: <20s} {ts.tid: <10s} {ts.task: <20s} {ts.processor: <20s} {ts.base: <6s} '
365        '{ts.pri: <6s} {ts.sched_mode: <10s} {ts.io_policy: <15s} '
366        '{ts.state: <8s} {ts.ast: <12s} {ts.waitq: <18s} {ts.wait_evt: <18s} '
367        '{ts.wait_evt_sym: <30s} {ts.wait_msg: <20s} {ts.name: <20s}')
368
369@lldb_type_summary(['thread *', 'thread_t'])
370@header(ThreadSummaryFormat.format(ts=ThreadSummaryNames))
371def GetThreadSummary(thread, O=None):
372    """ Summarize the thread structure.
373
374        params: thread: value - value object representing a thread in kernel
375        returns: str - summary of a thread
376
377        State flags:
378        W - Wait asserted
379        S - Suspended
380        R - Runnable
381        U - Uninterruptible
382        H - Terminated
383        A - Terminated (on queue)
384        I - Idle thread
385        C - Crashed thread
386        K - Waking
387
388        policy flags:
389        B - darwinbg
390        T - IO throttle
391        P - IO passive
392        D - Terminated
393    """
394    thread_ptr_str = '{:<#018x}'.format(thread)
395    thread_task_ptr_str = '{:<#018x}'.format(thread.t_tro.tro_task)
396
397    if int(thread.static_param):
398        thread_ptr_str += ' W'
399    thread_id = hex(thread.thread_id)
400    processor = hex(thread.last_processor)
401    base_priority = str(int(thread.base_pri))
402    sched_priority = str(int(thread.sched_pri))
403    sched_mode = ''
404    mode = str(thread.sched_mode)
405    if 'TIMESHARE' in mode:
406        sched_mode += 'TMSHR'
407    elif 'FIXED' in mode:
408        sched_mode += 'FIXED'
409    elif 'REALTIME' in mode:
410        sched_mode += 'RT'
411
412    if (unsigned(thread.bound_processor) != 0):
413        sched_mode += ' BIND'
414
415    TH_SFLAG_THROTTLED = 0x4
416    if (unsigned(thread.sched_flags) & TH_SFLAG_THROTTLED):
417        sched_mode += ' BG'
418
419    thread_name = GetThreadName(thread)
420    uthread = GetBSDThread(thread)
421
422    io_policy_str = ""
423    if int(uthread.uu_flag) & 0x400:
424        io_policy_str += 'RAGE '
425    if int(thread.effective_policy.thep_darwinbg) != 0:
426        io_policy_str += 'B'
427    if int(thread.effective_policy.thep_io_tier) != 0:
428        io_policy_str += 'T'
429    if int(thread.effective_policy.thep_io_passive) != 0:
430        io_policy_str += 'P'
431    if int(thread.effective_policy.thep_terminated) != 0:
432        io_policy_str += 'D'
433
434    state = int(thread.state)
435    thread_state_chars = {
436        0x0: '', 0x1: 'W', 0x2: 'S', 0x4: 'R', 0x8: 'U', 0x10: 'H', 0x20: 'A',
437        0x40: 'P', 0x80: 'I', 0x100: 'K'
438    }
439    state_str = ''
440    mask = 0x1
441    while mask <= 0x100:
442        state_str += thread_state_chars[int(state & mask)]
443        mask <<= 1
444
445    if int(thread.inspection):
446        state_str += 'C'
447
448    ast = int(thread.ast) | int(thread.reason)
449    ast_str = GetASTSummary(ast)
450
451    wait_queue_str = ''
452    wait_event_str = ''
453    wait_event_str_sym = ''
454    wait_message = ''
455    if (state & 0x1) != 0:
456        wait_queue_str = '{:<#018x}'.format(unsigned(thread.waitq.wq_q))
457        wait_event_str = '{:<#018x}'.format(unsigned(thread.wait_event))
458        wait_event_str_sym = kern.Symbolicate(int(hex(thread.wait_event), 16))
459        uthread = GetBSDThread(thread)
460        if int(uthread.uu_wmesg) != 0:
461            wait_message = str(Cast(uthread.uu_wmesg, 'char *'))
462
463    ts = ThreadSummary(
464            thread=thread_ptr_str, tid=thread_id,
465            task=thread_task_ptr_str, processor=processor,
466            base=base_priority, pri=sched_priority, sched_mode=sched_mode,
467            io_policy=io_policy_str, state=state_str, ast=ast_str,
468            waitq=wait_queue_str, wait_evt=wait_event_str,
469            wait_evt_sym=wait_event_str_sym, wait_msg=wait_message,
470            name=thread_name)
471    if O is not None:
472        return O.format(ThreadSummaryFormat, ts=ts)
473    else:
474        return ThreadSummaryFormat.format(ts=ts)
475
476
477def GetTaskRoleString(role):
478    role_strs = {
479                 0 : "TASK_UNSPECIFIED",
480                 1 : "TASK_FOREGROUND_APPLICATION",
481                 2 : "TASK_BACKGROUND_APPLICATION",
482                 3 : "TASK_CONTROL_APPLICATION",
483                 4 : "TASK_GRAPHICS_SERVER",
484                 5 : "TASK_THROTTLE_APPLICATION",
485                 6 : "TASK_NONUI_APPLICATION",
486                 7 : "TASK_DEFAULT_APPLICATION",
487                }
488    return role_strs[int(role)]
489
490def GetCoalitionFlagString(coal):
491    flags = []
492    if (coal.privileged):
493        flags.append('privileged')
494    if (coal.termrequested):
495        flags.append('termrequested')
496    if (coal.terminated):
497        flags.append('terminated')
498    if (coal.reaped):
499        flags.append('reaped')
500    if (coal.notified):
501        flags.append('notified')
502    if (coal.efficient):
503        flags.append('efficient')
504    return "|".join(flags)
505
506def GetCoalitionTasks(queue, coal_type, thread_details=False):
507    sfi_strs = {
508                 0x0  : "SFI_CLASS_UNSPECIFIED",
509                 0x1  : "SFI_CLASS_DARWIN_BG",
510                 0x2  : "SFI_CLASS_APP_NAP",
511                 0x3  : "SFI_CLASS_MANAGED_FOCAL",
512                 0x4  : "SFI_CLASS_MANAGED_NONFOCAL",
513                 0x5  : "SFI_CLASS_DEFAULT_FOCAL",
514                 0x6  : "SFI_CLASS_DEFAULT_NONFOCAL",
515                 0x7  : "SFI_CLASS_KERNEL",
516                 0x8  : "SFI_CLASS_OPTED_OUT",
517                 0x9  : "SFI_CLASS_UTILITY",
518                 0xA  : "SFI_CLASS_LEGACY_FOCAL",
519                 0xB  : "SFI_CLASS_LEGACY_NONFOCAL",
520                 0xC  : "SFI_CLASS_USER_INITIATED_FOCAL",
521                 0xD  : "SFI_CLASS_USER_INITIATED_NONFOCAL",
522                 0xE  : "SFI_CLASS_USER_INTERACTIVE_FOCAL",
523                 0xF  : "SFI_CLASS_USER_INTERACTIVE_NONFOCAL",
524                 0x10 : "SFI_CLASS_MAINTENANCE",
525                }
526    tasks = []
527    field_path = '.task_coalition[{}]'.format(coal_type)
528    for task in IterateLinkageChain(queue, 'task *', field_path):
529        task_str = "({0: <d},{1: #x}, {2: <s}, {3: <s})".format(GetProcPIDForTask(task),task,GetProcNameForTask(task),GetTaskRoleString(task.effective_policy.tep_role))
530        if thread_details:
531            for thread in IterateQueue(task.threads, "thread_t", "task_threads"):
532                task_str += "\n\t\t\t|-> thread:" + hex(thread) + ", " + sfi_strs[int(thread.sfi_class)]
533        tasks.append(task_str)
534    return tasks
535
536def GetCoalitionTypeString(type):
537    """ Convert a coalition type field into a string
538    Currently supported types (from <mach/coalition.h>):
539        COALITION_TYPE_RESOURCE
540        COALITION_TYPE_JETSAM
541    """
542    if type == 0: # COALITION_TYPE_RESOURCE
543        return 'RESOURCE'
544    if type == 1:
545        return 'JETSAM'
546    return '<unknown>'
547
548def GetResourceCoalitionSummary(coal, verbose=False):
549    """ Summarize a resource coalition
550    """
551    out_string = "Resource Coalition:\n\t  Ledger:\n"
552    thread_details = False
553    if config['verbosity'] > vSCRIPT:
554        thread_details = True
555    ledgerp = coal.r.ledger
556    if verbose and unsigned(ledgerp) != 0:
557        i = 0
558        while i != ledgerp.l_template.lt_cnt:
559            out_string += "\t\t"
560            out_string += GetLedgerEntrySummary(kern.globals.task_ledger_template, ledgerp, i)
561            i = i + 1
562    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)
563    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)
564    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)
565    if verbose:
566        out_string += "\n\t  cpu_time_effective[THREAD_QOS_DEFAULT] {0: <d}".format(coal.r.cpu_time_eqos[0])
567        out_string += "\n\t  cpu_time_effective[THREAD_QOS_MAINTENANCE] {0: <d}".format(coal.r.cpu_time_eqos[1])
568        out_string += "\n\t  cpu_time_effective[THREAD_QOS_BACKGROUND] {0: <d}".format(coal.r.cpu_time_eqos[2])
569        out_string += "\n\t  cpu_time_effective[THREAD_QOS_UTILITY] {0: <d}".format(coal.r.cpu_time_eqos[3])
570        out_string += "\n\t  cpu_time_effective[THREAD_QOS_LEGACY] {0: <d}".format(coal.r.cpu_time_eqos[4])
571        out_string += "\n\t  cpu_time_effective[THREAD_QOS_USER_INITIATED] {0: <d}".format(coal.r.cpu_time_eqos[5])
572        out_string += "\n\t  cpu_time_effective[THREAD_QOS_USER_INTERACTIVE] {0: <d}".format(coal.r.cpu_time_eqos[6])
573    out_string += "\n\t  Tasks:\n\t\t"
574    tasks = GetCoalitionTasks(addressof(coal.r.tasks), 0, thread_details)
575    out_string += "\n\t\t".join(tasks)
576    return out_string
577
578def GetJetsamCoalitionSummary(coal, verbose=False):
579    out_string = "Jetsam Coalition:"
580    thread_details = False
581    if config['verbosity'] > vSCRIPT:
582        thread_details = True
583    if unsigned(coal.j.leader) == 0:
584        out_string += "\n\t  NO Leader!"
585    else:
586        out_string += "\n\t  Leader:\n\t\t"
587        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))
588    out_string += "\n\t  Extensions:\n\t\t"
589    tasks = GetCoalitionTasks(addressof(coal.j.extensions), 1, thread_details)
590    out_string += "\n\t\t".join(tasks)
591    out_string += "\n\t  XPC Services:\n\t\t"
592    tasks = GetCoalitionTasks(addressof(coal.j.services), 1, thread_details)
593    out_string += "\n\t\t".join(tasks)
594    out_string += "\n\t  Other Tasks:\n\t\t"
595    tasks = GetCoalitionTasks(addressof(coal.j.other), 1, thread_details)
596    out_string += "\n\t\t".join(tasks)
597    out_string += "\n\t  Thread Group: {0: <#020x}\n".format(coal.j.thread_group)
598    return out_string
599
600@lldb_type_summary(['coalition_t', 'coalition *'])
601@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"))
602def GetCoalitionSummary(coal):
603    if unsigned(coal) == 0:
604        return '{0: <#020x} {1: <15s} {2: <10d} {3: <10d} {4: <10d} {5: <12d} {6: <12d} {7: <s}'.format(0, "", -1, -1, -1, -1, -1, "")
605    out_string = ""
606    format_string = '{0: <#020x} {1: <15s} {2: <10d} {3: <10d} {4: <10d} {5: <12d} {6: <12d} {7: <s}'
607    type_string = GetCoalitionTypeString(coal.type)
608    flag_string = GetCoalitionFlagString(coal)
609    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)
610    return out_string
611
612def GetCoalitionInfo(coal, verbose=False):
613    """ returns a string describing a coalition, including details about the particular coalition type.
614        params:
615            coal : value object representing a coalition in the kernel
616        returns:
617            str : A string describing the coalition.
618    """
619    if unsigned(coal) == 0:
620        return "<null coalition>"
621    typestr = GetCoalitionTypeString(coal.type)
622    flagstr = GetCoalitionFlagString(coal)
623    out_string = ""
624    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)
625    if coal.type == 0: # COALITION_TYPE_RESOURCE
626        out_string += GetResourceCoalitionSummary(coal, verbose)
627    elif coal.type == 1: # COALITION_TYPE_JETSAM
628        out_string += GetJetsamCoalitionSummary(coal, verbose)
629    else:
630        out_string += "Unknown Type"
631
632    return out_string
633
634# Macro: showcoalitioninfo
635
636@lldb_command('showcoalitioninfo')
637def ShowCoalitionInfo(cmd_args=None, cmd_options={}):
638    """  Display more detailed information about a coalition
639         Usage: showcoalitioninfo <address of coalition>
640    """
641    verbose = False
642    if config['verbosity'] > vHUMAN:
643        verbose = True
644    if not cmd_args:
645        raise ArgumentError("No arguments passed")
646    coal = kern.GetValueFromAddress(cmd_args[0], 'coalition *')
647    if not coal:
648        print("unknown arguments:", str(cmd_args))
649        return False
650    print(GetCoalitionInfo(coal, verbose))
651
652# EndMacro: showcoalitioninfo
653
654# Macro: showallcoalitions
655
656@lldb_command('showallcoalitions')
657def ShowAllCoalitions(cmd_args=None):
658    """  Print a summary listing of all the coalitions
659    """
660    global kern
661    print(GetCoalitionSummary.header)
662    for c in kern.coalitions:
663        print(GetCoalitionSummary(c))
664
665# EndMacro: showallcoalitions
666
667# Macro: showallthreadgroups
668
669@lldb_type_summary(['struct thread_group *', 'thread_group *'])
670@header("{0: <20s} {1: <5s} {2: <16s} {3: <5s} {4: <8s} {5: <20s}".format("thread_group", "id", "name", "refc", "flags", "recommendation"))
671def GetThreadGroupSummary(tg):
672    if unsigned(tg) == 0:
673        return '{0: <#020x} {1: <5d} {2: <16s} {3: <5d} {4: <8s} {5: <20d}'.format(0, -1, "", -1, "", -1)
674    out_string = ""
675    format_string = '{0: <#020x} {1: <5d} {2: <16s} {3: <5d} {4: <8s} {5: <20d}'
676    tg_flags = ''
677    if (tg.tg_flags & 0x1):
678        tg_flags += 'E'
679    if (tg.tg_flags & 0x2):
680        tg_flags += 'A'
681    if (tg.tg_flags & 0x4):
682        tg_flags += 'C'
683    if (tg.tg_flags & 0x100):
684        tg_flags += 'U'
685    out_string += format_string.format(tg, tg.tg_id, tg.tg_name, tg.tg_refcount.ref_count, tg_flags, tg.tg_recommendation)
686    return out_string
687
688@lldb_command('showallthreadgroups')
689def ShowAllThreadGroups(cmd_args=None):
690    """  Print a summary listing of all thread groups
691    """
692    global kern
693    print(GetThreadGroupSummary.header)
694    for tg in kern.thread_groups:
695        print(GetThreadGroupSummary(tg))
696
697# EndMacro: showallthreadgroups
698
699# Macro: showtaskcoalitions
700
701@lldb_command('showtaskcoalitions', 'F:')
702def ShowTaskCoalitions(cmd_args=None, cmd_options={}):
703    """
704    """
705    task_list = []
706    if "-F" in cmd_options:
707        task_list = FindTasksByName(cmd_options["-F"])
708    elif cmd_args:
709        t = kern.GetValueFromAddress(cmd_args[0], 'task *')
710        task_list.append(t)
711    else:
712        raise ArgumentError("No arguments passed")
713
714    if len(task_list) > 0:
715        print(GetCoalitionSummary.header)
716    for task in task_list:
717        print(GetCoalitionSummary(task.coalition[0]))
718        print(GetCoalitionSummary(task.coalition[1]))
719
720# EndMacro: showtaskcoalitions
721
722@lldb_type_summary(['proc', 'proc *'])
723@header("{0: >6s}   {1: <18s} {2: >11s} {3: ^10s} {4: <32s}".format("pid", "process", "io_policy", "wq_state", "command"))
724def GetProcSummary(proc):
725    """ Summarize the process data.
726        params:
727          proc : value - value representaitng a proc * in kernel
728        returns:
729          str - string summary of the process.
730    """
731    if not proc:
732        return "Process is not valid."
733
734    out_string = ""
735    format_string= "{0: >6d}   {1: <#018x} {2: >11s} {3: >2d} {4: >2d} {5: >2d}   {6: <32s}"
736    pval = proc.GetSBValue()
737    #code.interact(local=locals())
738    if str(pval.GetType()) != str(gettype('proc *')) :
739        return "Unknown type " + str(pval.GetType()) + " " + str(hex(proc))
740    pid = int(GetProcPID(proc))
741    proc_addr = int(hex(proc), 16)
742    proc_rage_str = ""
743    if int(proc.p_lflag) & 0x400000 :
744        proc_rage_str = "RAGE"
745
746    task = GetTaskFromProc(proc)
747
748    io_policy_str = ""
749
750    if int(task.effective_policy.tep_darwinbg) != 0:
751        io_policy_str += "B"
752    if int(task.effective_policy.tep_lowpri_cpu) != 0:
753        io_policy_str += "L"
754
755    if int(task.effective_policy.tep_io_tier) != 0:
756        io_policy_str += "T"
757    if int(task.effective_policy.tep_io_passive) != 0:
758        io_policy_str += "P"
759    if int(task.effective_policy.tep_terminated) != 0:
760        io_policy_str += "D"
761
762    if int(task.effective_policy.tep_latency_qos) != 0:
763        io_policy_str += "Q"
764    if int(task.effective_policy.tep_sup_active) != 0:
765        io_policy_str += "A"
766
767    if int(proc.p_refcount) & GetEnumValue("proc_ref_bits_t::P_REF_SHADOW") :
768        io_policy_str += "S"
769
770
771    try:
772        work_queue = proc.p_wqptr
773        if proc.p_wqptr != 0 :
774            wq_num_threads = int(work_queue.wq_nthreads)
775            wq_idle_threads = int(work_queue.wq_thidlecount)
776            wq_req_threads = int(work_queue.wq_reqcount)
777        else:
778            wq_num_threads = 0
779            wq_idle_threads = 0
780            wq_req_threads = 0
781    except:
782        wq_num_threads = -1
783        wq_idle_threads = -1
784        wq_req_threads = -1
785    process_name = GetProcName(proc)
786    if process_name == 'xpcproxy':
787        for thread in IterateQueue(task.threads, 'thread *', 'task_threads'):
788            thread_name = GetThreadName(thread)
789            if thread_name:
790                process_name += ' (' + thread_name + ')'
791                break
792    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)
793    return out_string
794
795@lldb_type_summary(['tty_dev_t', 'tty_dev_t *'])
796@header("{0: <20s} {1: <10s} {2: <10s} {3: <15s} {4: <15s} {5: <15s} {6: <15s}".format("tty_dev","primary", "replica", "open", "free", "name", "revoke"))
797def GetTTYDevSummary(tty_dev):
798    """ Summarizes the important fields in tty_dev_t structure.
799        params: tty_dev: value - value object representing a tty_dev_t in kernel
800        returns: str - summary of the tty_dev
801    """
802    out_string = ""
803    format_string = "{0: <#020x} {1: <#010x} {2: <#010x} {3: <15s} {4: <15s} {5: <15s} {6: <15s}"
804    open_fn = kern.Symbolicate(int(hex(tty_dev.open), 16))
805    free_fn = kern.Symbolicate(int(hex(tty_dev.free), 16))
806    name_fn = kern.Symbolicate(int(hex(tty_dev.name), 16))
807    revoke_fn = kern.Symbolicate(int(hex(tty_dev.revoke), 16))
808    out_string += format_string.format(tty_dev, tty_dev.primary, tty_dev.replica, open_fn, free_fn, name_fn, revoke_fn)
809    return out_string
810
811# Macro: showtask
812
813@lldb_command('showtask', 'F:')
814def ShowTask(cmd_args=None, cmd_options={}):
815    """  Routine to print a summary listing of given task
816         Usage: showtask <address of task>
817         or   : showtask -F <name of task>
818    """
819    task_list = []
820    if "-F" in cmd_options:
821        task_list = FindTasksByName(cmd_options['-F'])
822    else:
823        if not cmd_args:
824            raise ArgumentError("Invalid arguments passed.")
825
826        tval = kern.GetValueFromAddress(cmd_args[0], 'task *')
827        if not tval:
828            raise ArgumentError("Unknown arguments: {:s}".format(cmd_args[0]))
829        task_list.append(tval)
830
831    for tval in task_list:
832        print(GetTaskSummary.header + " " + GetProcSummary.header)
833        pval = GetProcFromTask(tval)
834        print(GetTaskSummary(tval) +" "+ GetProcSummary(pval))
835
836# EndMacro: showtask
837
838# Macro: showpid
839
840@lldb_command('showpid')
841def ShowPid(cmd_args=None):
842    """  Routine to print a summary listing of task corresponding to given pid
843         Usage: showpid <pid value>
844    """
845    if not cmd_args:
846        raise ArgumentError("No arguments passed")
847    pidval = ArgumentStringToInt(cmd_args[0])
848    for t in kern.tasks:
849        pval = GetProcFromTask(t)
850        if pval and GetProcPID(pval) == pidval:
851            print(GetTaskSummary.header + " " + GetProcSummary.header)
852            print(GetTaskSummary(t) + " " + GetProcSummary(pval))
853            break
854
855# EndMacro: showpid
856
857# Macro: showproc
858
859@lldb_command('showproc')
860def ShowProc(cmd_args=None):
861    """  Routine to print a summary listing of task corresponding to given proc
862         Usage: showproc <address of proc>
863    """
864    if not cmd_args:
865        raise ArgumentError("No arguments passed")
866    pval = kern.GetValueFromAddress(cmd_args[0], 'proc *')
867    if not pval:
868        print("unknown arguments:", str(cmd_args))
869        return False
870    print(GetTaskSummary.header + " " + GetProcSummary.header)
871    tval = GetTaskFromProc(pval)
872    print(GetTaskSummary(tval) + " " + GetProcSummary(pval))
873
874# EndMacro: showproc
875
876# Macro: showprocinfo
877
878@lldb_command('showprocinfo')
879def ShowProcInfo(cmd_args=None):
880    """  Routine to display name, pid, parent & task for the given proc address
881         It also shows the Cred, Flags and state of the process
882         Usage: showprocinfo <address of proc>
883    """
884    if not cmd_args:
885        raise ArgumentError("No arguments passed")
886    pval = kern.GetValueFromAddress(cmd_args[0], 'proc *')
887    if not pval:
888        print("unknown arguments:", str(cmd_args))
889        return False
890    print(GetProcInfo(pval))
891
892# EndMacro: showprocinfo
893
894#Macro: showprocfiles
895
896@lldb_command('showprocfiles')
897def ShowProcFiles(cmd_args=None):
898    """ Given a proc_t pointer, display the list of open file descriptors for the referenced process.
899        Usage: showprocfiles <proc_t>
900    """
901    if not cmd_args:
902        print(ShowProcFiles.__doc__)
903        return
904    proc = kern.GetValueFromAddress(cmd_args[0], 'proc_t')
905    proc_filedesc = addressof(proc.p_fd)
906    proc_ofiles = proc_filedesc.fd_ofiles
907    if unsigned(proc_ofiles) == 0:
908        print('No open files for proc {0: <s}'.format(cmd_args[0]))
909        return
910    print("{0: <5s} {1: <18s} {2: <10s} {3: <8s} {4: <18s} {5: <64s}".format('FD', 'FILEGLOB', 'FG_FLAGS', 'FG_TYPE', 'FG_DATA','INFO'))
911    print("{0:-<5s} {0:-<18s} {0:-<10s} {0:-<8s} {0:-<18s} {0:-<64s}".format(""))
912
913    for fd in range(0, unsigned(proc_filedesc.fd_afterlast)):
914        if unsigned(proc_ofiles[fd]) != 0:
915            out_str = ''
916            proc_fd_flags = proc_ofiles[fd].fp_flags
917            proc_fd_fglob = proc_ofiles[fd].fp_glob
918            proc_fd_fglob_fg_data = Cast(proc_fd_fglob.fg_data, 'void *')
919            out_str += "{0: <5d} ".format(fd)
920            out_str += "{0: <#18x} ".format(unsigned(proc_fd_fglob))
921            out_str += "0x{0:0>8x} ".format(unsigned(proc_fd_flags))
922            proc_fd_ftype = unsigned(proc_fd_fglob.fg_ops.fo_type)
923            if proc_fd_ftype in xnudefines.filetype_strings:
924                out_str += "{0: <8s} ".format(xnudefines.filetype_strings[proc_fd_ftype])
925            else:
926                out_str += "?: {0: <5d} ".format(proc_fd_ftype)
927            out_str += "{0: <#18x} ".format(unsigned(proc_fd_fglob_fg_data))
928            if proc_fd_ftype == 1:
929                fd_name = Cast(proc_fd_fglob_fg_data, 'struct vnode *').v_name
930                out_str += "{0: <64s}".format(fd_name)
931            out_str += "\n"
932            print(out_str)
933
934#EndMacro: showprocfiles
935
936#Macro: showtty
937
938@lldb_command('showtty')
939def ShowTTY(cmd_args=None):
940    """ Display information about a struct tty
941        Usage: showtty <tty struct>
942    """
943    if not cmd_args:
944        print(ShowTTY.__doc__)
945        return
946
947    tty = kern.GetValueFromAddress(cmd_args[0], 'struct tty *')
948    print("TTY structure at:              {0: <s}".format(cmd_args[0]))
949    print("Last input to raw queue:       {0: <#18x} \"{1: <s}\"".format(unsigned(tty.t_rawq.c_cs), tty.t_rawq.c_cs))
950    print("Last input to canonical queue: {0: <#18x} \"{1: <s}\"".format(unsigned(tty.t_canq.c_cs), tty.t_canq.c_cs))
951    print("Last output data:              {0: <#18x} \"{1: <s}\"".format(unsigned(tty.t_outq.c_cs), tty.t_outq.c_cs))
952    tty_state_info = [
953                  ['', 'TS_SO_OLOWAT (Wake up when output <= low water)'],
954                  ['- (synchronous I/O mode)', 'TS_ASYNC (async I/O mode)'],
955                  ['', 'TS_BUSY (Draining output)'],
956                  ['- (Carrier is NOT present)', 'TS_CARR_ON (Carrier is present)'],
957                  ['', 'TS_FLUSH (Outq has been flushed during DMA)'],
958                  ['- (Open has NOT completed)', 'TS_ISOPEN (Open has completed)'],
959                  ['', 'TS_TBLOCK (Further input blocked)'],
960                  ['', 'TS_TIMEOUT (Wait for output char processing)'],
961                  ['', 'TS_TTSTOP (Output paused)'],
962                  ['', 'TS_WOPEN (Open in progress)'],
963                  ['', 'TS_XCLUDE (Tty requires exclusivity)'],
964                  ['', 'TS_BKSL (State for lowercase \\ work)'],
965                  ['', 'TS_CNTTB (Counting tab width, ignore FLUSHO)'],
966                  ['', 'TS_ERASE (Within a \\.../ for PRTRUB)'],
967                  ['', 'TS_LNCH (Next character is literal)'],
968                  ['', 'TS_TYPEN (Retyping suspended input (PENDIN))'],
969                  ['', 'TS_CAN_BYPASS_L_RINT (Device in "raw" mode)'],
970                  ['- (Connection NOT open)', 'TS_CONNECTED (Connection open)'],
971                  ['', 'TS_SNOOP (Device is being snooped on)'],
972                  ['', 'TS_SO_OCOMPLETE (Wake up when output completes)'],
973                  ['', 'TS_ZOMBIE (Connection lost)'],
974                  ['', 'TS_CAR_OFLOW (For MDMBUF - handle in driver)'],
975                  ['', 'TS_CTS_OFLOW (For CCTS_OFLOW - handle in driver)'],
976                  ['', 'TS_DSR_OFLOW (For CDSR_OFLOW - handle in driver)']
977                ]
978    index = 0
979    mask = 0x1
980    tty_state = unsigned(tty.t_state)
981    print("State:")
982    while index < 24:
983        if tty_state & mask != 0:
984            if len(tty_state_info[index][1]) > 0:
985                print('\t' + tty_state_info[index][1])
986        else:
987            if len(tty_state_info[index][0]) > 0:
988                print('\t' + tty_state_info[index][0])
989        index += 1
990        mask = mask << 1
991    print("Flags:                    0x{0:0>8x}".format(unsigned(tty.t_flags)))
992    print("Foreground Process Group: 0x{0:0>16x}".format(unsigned(tty.t_pgrp)))
993    print("Enclosing session:        0x{0:0>16x}".format(unsigned(tty.t_session)))
994    print("Termios:")
995    print("\tInput Flags:   0x{0:0>8x}".format(unsigned(tty.t_termios.c_iflag)))
996    print("\tOutput Flags:  0x{0:0>8x}".format(unsigned(tty.t_termios.c_oflag)))
997    print("\tControl Flags: 0x{0:0>8x}".format(unsigned(tty.t_termios.c_cflag)))
998    print("\tLocal Flags:   0x{0:0>8x}".format(unsigned(tty.t_termios.c_lflag)))
999    print("\tInput Speed:   {0: <8d}".format(tty.t_termios.c_ispeed))
1000    print("\tOutput Speed:  {0: <8d}".format(tty.t_termios.c_ospeed))
1001    print("High Watermark: {0: <d} bytes".format(tty.t_hiwat))
1002    print("Low Watermark : {0: <d} bytes".format(tty.t_lowat))
1003
1004#EndMacro: showtty
1005
1006#Macro showallttydevs
1007
1008@lldb_command('showallttydevs')
1009def ShowAllTTYDevs(cmd_args=[], cmd_options={}):
1010    """ Show a list of ttydevs registered in the system.
1011        Usage:
1012        (lldb)showallttydevs
1013    """
1014    tty_dev_head = kern.globals.tty_dev_head
1015    tty_dev = tty_dev_head
1016    print(GetTTYDevSummary.header)
1017    while unsigned(tty_dev) != 0:
1018        print(GetTTYDevSummary(tty_dev))
1019        tty_dev = tty_dev.next
1020    return ""
1021
1022#EndMacro: showallttydevs
1023
1024#Macro: dumpthread_terminate_queue
1025
1026@lldb_command('dumpthread_terminate_queue', fancy=True)
1027def DumpThreadTerminateQueue(cmd_args=None, cmd_options={}, O=None):
1028    """ Displays the contents of the specified call_entry queue.
1029        Usage: dumpthread_terminate_queue
1030    """
1031
1032    count = 0
1033    with O.table(GetThreadSummary.header):
1034        for th in IterateMPSCQueue(addressof(kern.globals.thread_terminate_queue.mpd_queue), 'struct thread', 'mpsc_links'):
1035            print(GetThreadSummary(th, O=O))
1036            count += 1
1037    print("{0: <d} entries!".format(count))
1038
1039#EndMacro: dumpthread_terminate_queue
1040
1041#Macro: dumpcrashed_thread_queue
1042
1043@lldb_command('dumpcrashed_thread_queue', fancy=True)
1044def DumpCrashedThreadsQueue(cmd_args=None, cmd_options={}, O=None):
1045    """ Displays the contents of the specified call_entry queue.
1046        Usage: dumpcrashed_thread_queue
1047    """
1048
1049    count = 0
1050    with O.table(GetThreadSummary.header):
1051        for th in IterateQueue(addressof(kern.globals.crashed_threads_queue), 'struct thread *',  'q_link'):
1052            print(GetThreadSummary(th), O=O)
1053            count += 1
1054    print("{0: <d} entries!".format(count))
1055
1056#EndMacro: dumpcrashed_thread_queue
1057
1058#Macro: dumpcallqueue
1059
1060@lldb_command('dumpcallqueue')
1061def DumpCallQueue(cmd_args=None):
1062    """ Displays the contents of the specified call_entry queue.
1063        Usage: dumpcallqueue <queue_head_t *>
1064    """
1065    if not cmd_args:
1066        raise ArgumentError("Invalid arguments")
1067
1068    print("{0: <18s} {1: <18s} {2: <18s} {3: <64s} {4: <18s}".format('CALL_ENTRY', 'PARAM0', 'PARAM1', 'DEADLINE', 'FUNC'))
1069    callhead = kern.GetValueFromAddress(cmd_args[0], 'queue_head_t *')
1070    count = 0
1071    for callentry in IterateQueue(callhead, 'struct call_entry *',  'q_link'):
1072        print("{0: <#18x} {1: <#18x} {2: <#18x} {3: <64d} {4: <#18x}".format(
1073              unsigned(callentry), unsigned(callentry.param0), unsigned(callentry.param1),
1074              unsigned(callentry.deadline), unsigned(callentry.func)))
1075        count += 1
1076    print("{0: <d} entries!".format(count))
1077
1078#EndMacro: dumpcallqueue
1079
1080@lldb_command('showalltasklogicalwrites')
1081def ShowAllTaskIOStats(cmd_args=None):
1082    """ Commad to print I/O stats for all tasks
1083    """
1084    print("{0: <20s} {1: <20s} {2: <20s} {3: <20s} {4: <20s} {5: <20s} {6: <20s} {7: <20s} {8: <20s} {9: <32}".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"))
1085    for t in kern.tasks:
1086        pval = GetProcFromTask(t)
1087        print("{0: <#18x} {1: >20d} {2: >20d} {3: >20d} {4: >20d}  {5: <20s} {6: <20s} {7: <20s} {8: <20s} {9: <20s}".format(t,
1088            t.task_writes_counters_internal.task_immediate_writes,
1089            t.task_writes_counters_internal.task_deferred_writes,
1090            t.task_writes_counters_internal.task_invalidated_writes,
1091            t.task_writes_counters_internal.task_metadata_writes,
1092            t.task_writes_counters_external.task_immediate_writes,
1093            t.task_writes_counters_external.task_deferred_writes,
1094            t.task_writes_counters_external.task_invalidated_writes,
1095            t.task_writes_counters_external.task_metadata_writes,
1096            GetProcName(pval)))
1097
1098
1099@lldb_command('showalltasks','C', fancy=True)
1100def ShowAllTasks(cmd_args=None, cmd_options={}, O=None):
1101    """  Routine to print a summary listing of all the tasks
1102         wq_state -> reports "number of workq threads", "number of scheduled workq threads", "number of pending work items"
1103         if "number of pending work items" seems stuck at non-zero, it may indicate that the workqueue mechanism is hung
1104         io_policy -> RAGE  - rapid aging of vnodes requested
1105                     NORM  - normal I/O explicitly requested (this is the default)
1106                     PASS  - passive I/O requested (i.e. I/Os do not affect throttling decisions)
1107                     THROT - throttled I/O requested (i.e. thread/task may be throttled after each I/O completes)
1108         Usage: (lldb) showalltasks -C  : describe the corpse structure
1109    """
1110    global kern
1111    extra_hdr = ''
1112    showcorpse = False
1113    if '-C' in cmd_options:
1114        showcorpse = True
1115        extra_hdr += " " + GetKCDataSummary.header
1116
1117    with O.table(GetTaskSummary.header + extra_hdr + " " + GetProcSummary.header):
1118        for t in kern.tasks:
1119            pval = GetProcFromTask(t)
1120            print(GetTaskSummary(t, showcorpse) + " " + GetProcSummary(pval))
1121
1122    ZombTasks()
1123
1124def TaskForPmapHelper(pmap):
1125    """ Given a pmap pointer, return the task pointer which contains that
1126        address space.
1127
1128        pmap: PMAP pointer whose task to find.
1129    """
1130    for tasklist in [kern.tasks, kern.terminated_tasks]:
1131        for task in tasklist:
1132            if kern.GetValueFromAddress(unsigned(task.map.pmap), 'pmap_t') == pmap:
1133                return task
1134
1135    return None
1136
1137@lldb_command('taskforpmap')
1138def TaskForPmap(cmd_args=None):
1139    """ Find the task whose pmap corresponds to <pmap>.
1140        Syntax: (lldb) taskforpmap <pmap>
1141            Multiple -v's can be specified for increased verbosity
1142    """
1143    if cmd_args == None or len(cmd_args) < 1:
1144        raise ArgumentError("Too few arguments to taskforpmap.")
1145    pmap = kern.GetValueFromAddress(cmd_args[0], 'pmap_t')
1146    task = TaskForPmapHelper(pmap)
1147
1148    if task is None:
1149        print("Couldn't find task for pmap {:#x}".format(pmap))
1150        return
1151
1152    print(GetTaskSummary.header + " " + GetProcSummary.header)
1153    pval = GetProcFromTask(task)
1154    print(GetTaskSummary(task) + " " + GetProcSummary(pval))
1155
1156@lldb_command('showterminatedtasks')
1157def ShowTerminatedTasks(cmd_args=None):
1158    """  Routine to print a summary listing of all the terminated tasks
1159         wq_state -> reports "number of workq threads", "number of scheduled workq threads", "number of pending work items"
1160         if "number of pending work items" seems stuck at non-zero, it may indicate that the workqueue mechanism is hung
1161         io_policy -> RAGE  - rapid aging of vnodes requested
1162                     NORM  - normal I/O explicitly requested (this is the default)
1163                     PASS  - passive I/O requested (i.e. I/Os do not affect throttling decisions)
1164                     THROT - throttled I/O requested (i.e. thread/task may be throttled after each I/O completes)
1165        syntax: (lldb)showallterminatedtasks
1166    """
1167    global kern
1168    print(GetTaskSummary.header + " " + GetProcSummary.header)
1169    for t in kern.terminated_tasks:
1170
1171        # If the task has been terminated it's likely that the process is
1172        # gone too. If there is no proc it may still be possible to find
1173        # the original proc name.
1174        pval = GetProcFromTask(t)
1175        if pval:
1176            psummary = GetProcSummary(pval)
1177        else:
1178            name = GetProcNameForTask(t);
1179            pslen = GetProcSummary.header.find("command");
1180            psummary = "{0: <{indent}} {1: <s}".format("", name, indent = pslen - 1)
1181
1182        print(GetTaskSummary(t) + " " + psummary)
1183
1184    return True
1185
1186# Macro: showtaskstacks
1187
1188def ShowTaskStacks(task, O=None):
1189    """ Print a task with summary and stack information for each of its threads
1190    """
1191    global kern
1192    print(GetTaskSummary.header + " " + GetProcSummary.header)
1193    pval = GetProcFromTask(task)
1194    print(GetTaskSummary(task) + " " + GetProcSummary(pval))
1195    for th in IterateQueue(task.threads, 'thread *', 'task_threads'):
1196        with O.table(GetThreadSummary.header, indent=True):
1197            print(GetThreadSummary(th, O=O))
1198            print(GetThreadBackTrace(th, prefix="    ") + "\n")
1199
1200def FindTasksByName(searchstr, ignore_case=True):
1201    """ Search the list of tasks by name.
1202        params:
1203            searchstr: str - a regex like string to search for task
1204            ignore_case: bool - If False then exact matching will be enforced
1205        returns:
1206            [] - array of task object. Empty if not found any
1207    """
1208    re_options = 0
1209    if ignore_case:
1210        re_options = re.IGNORECASE
1211    search_regex = re.compile(searchstr, re_options)
1212    retval = []
1213    for t in kern.tasks:
1214        pval = GetProcFromTask(t)
1215        process_name = "{:s}".format(GetProcName(pval))
1216        if search_regex.search(process_name):
1217            retval.append(t)
1218    return retval
1219
1220@lldb_command('showtaskstacks', 'F:', fancy=True)
1221def ShowTaskStacksCmdHelper(cmd_args=None, cmd_options={}, O=None):
1222    """ Routine to print out the stack for each thread in a task
1223        Usage: showtaskstacks <0xaddress of task>
1224           or: showtaskstacks -F launchd
1225    """
1226
1227    if "-F" in cmd_options:
1228        find_task_str = cmd_options["-F"]
1229        task_list = FindTasksByName(find_task_str)
1230        for tval in task_list:
1231            ShowTaskStacks(tval, O=O)
1232        return
1233
1234    if not cmd_args:
1235        raise ArgumentError("No arguments passed")
1236
1237    tval = kern.GetValueFromAddress(cmd_args[0], 'task *')
1238    if not tval:
1239        raise ArgumentError("unknown arguments: {:s}".format(str(cmd_args)))
1240    else:
1241        ShowTaskStacks(tval, O=O)
1242
1243# EndMacro: showtaskstacks
1244
1245def CheckTaskProcRefs(task, proc, O=None):
1246    btlib = kmemory.BTLibrary.get_shared()
1247
1248    for thread in IterateQueue(task.threads, 'thread *', 'task_threads'):
1249        uthread = GetBSDThread(thread)
1250        refcount = int(uthread.uu_proc_refcount)
1251        uu_ref_info = uthread.uu_proc_ref_info
1252        if int(uu_ref_info) == 0:
1253            continue
1254        uu_ref_index = int(uu_ref_info.upri_pindex)
1255        if refcount == 0:
1256            continue
1257        for ref in range(0, uu_ref_index):
1258            if unsigned(uu_ref_info.upri_proc_ps[ref]) == unsigned(proc):
1259                print(GetTaskSummary.header + " " + GetProcSummary.header)
1260                pval = GetProcFromTask(task)
1261                print(GetTaskSummary(task) + " " + GetProcSummary(pval))
1262                with O.table(GetThreadSummary.header, indent=True):
1263                    print(GetThreadSummary(thread, O=O))
1264
1265                bts = btlib.get_stack(unsigned(uu_ref_info.upri_proc_stacks[ref]))
1266                print(*bts.symbolicated_frames(), sep="\n")
1267
1268@lldb_command('showprocrefs', fancy=True)
1269def ShowProcRefs(cmd_args=None, cmd_options={}, O=None):
1270    """ Display information on threads/BTs that could be holding a reference on the specified proc
1271        NOTE: We can't say affirmatively if any of these references are still held since
1272              there's no way to pair references with drop-refs in the current infrastructure.
1273        Usage: showprocrefs <proc>
1274    """
1275    if cmd_args == None or len(cmd_args) < 1:
1276         raise ArgumentError("No arguments passed")
1277
1278    proc = kern.GetValueFromAddress(cmd_args[0], 'proc *')
1279
1280    for t in kern.tasks:
1281        CheckTaskProcRefs(t, proc, O=O)
1282    for t in kern.terminated_tasks:
1283        CheckTaskProcRefs(t, proc, O=O)
1284
1285@lldb_command('showallthreads', fancy=True)
1286def ShowAllThreads(cmd_args=None, cmd_options={}, O=None):
1287    """ Display info about all threads in the system
1288    """
1289
1290    # Terminated threads get prefixed with a 'T'
1291    def ShowTaskTerminatedThreads(task, O=O):
1292        tlist = tmap.get(unsigned(task), [])
1293        for thval in tlist:
1294            print("T\t" + GetThreadSummary(thval, O=O))
1295
1296    # Task -> [thread, ..] map of terminated threads
1297    tmap = defaultdict(list)
1298    for thr in kern.terminated_threads:
1299        tmap[unsigned(thr.t_tro.tro_task)].append(thr)
1300
1301    for t in kern.tasks:
1302        ShowTaskThreads([str(int(t))], O=O)
1303        ShowTaskTerminatedThreads(t, O=O)
1304        print(" \n")
1305
1306    for t in kern.terminated_tasks:
1307        print("Terminated: \n")
1308        ShowTaskThreads([str(int(t))], O=O)
1309        ShowTaskTerminatedThreads(t, O=O)
1310        print(" \n")
1311
1312    return
1313
1314@lldb_command('showterminatedthreads', fancy=True)
1315def ShowTerminatedThreads(cmd_args=None, cmd_options={}, O=None):
1316    """ Display info about all terminated threads in the system
1317    """
1318
1319    with O.table(GetThreadSummary.header, indent=True):
1320        for t in kern.terminated_threads:
1321            print(GetThreadSummary(t, O=O))
1322
1323
1324@lldb_command('showtaskthreads', "F:", fancy=True)
1325def ShowTaskThreads(cmd_args = None, cmd_options={}, O=None):
1326    """ List the threads of a task.
1327        Usage: showtaskthreads <task-ptr>
1328           or: showtaskthreads -F <name>
1329    """
1330    task_list = []
1331    if "-F" in cmd_options:
1332        task_list = FindTasksByName(cmd_options["-F"])
1333    elif cmd_args:
1334        t = kern.GetValueFromAddress(cmd_args[0], 'task *')
1335        task_list = [t]
1336    else:
1337        raise ArgumentError("No arguments passed")
1338
1339    for task in task_list:
1340        print(GetTaskSummary.header + " " + GetProcSummary.header)
1341        pval = GetProcFromTask(task)
1342        print(GetTaskSummary(task) + " " + GetProcSummary(pval))
1343        with O.table(GetThreadSummary.header, indent=True):
1344            for thval in IterateQueue(task.threads, 'thread *', 'task_threads'):
1345                print(GetThreadSummary(thval, O=O))
1346    return
1347
1348@lldb_command('showact', fancy=True)
1349def ShowAct(cmd_args=None, cmd_options={}, O=None):
1350    """ Routine to print out the state of a specific thread.
1351        usage: showact <activation>
1352    """
1353    if not cmd_args:
1354        raise ArgumentError("No arguments passed")
1355    threadval = kern.GetValueFromAddress(cmd_args[0], 'thread *')
1356    with O.table(GetThreadSummary.header):
1357        print(GetThreadSummary(threadval, O=O))
1358
1359@lldb_command('showactstack', fancy=True)
1360def ShowActStack(cmd_args=None, cmd_options={}, O=None):
1361    """ Routine to print out the stack of a specific thread.
1362        usage:  showactstack <activation>
1363    """
1364    if not cmd_args:
1365        raise ArgumentError("No arguments passed")
1366    threadval = kern.GetValueFromAddress(cmd_args[0], 'thread *')
1367    with O.table(GetThreadSummary.header):
1368        print(GetThreadSummary(threadval, O=O))
1369    print(GetThreadBackTrace(threadval, prefix="\t"))
1370    return
1371
1372@lldb_command('switchtoact', fancy=True)
1373def SwitchToAct(cmd_args=None, cmd_options={}, O=None):
1374    """ Switch to different context specified by activation
1375    This command allows gdb to examine the execution context and call
1376    stack for the specified activation. For example, to view the backtrace
1377    for an activation issue "switchtoact <address>", followed by "bt".
1378    Before resuming execution, issue a "resetctx" command, to
1379    return to the original execution context.
1380    """
1381    if cmd_args is None or len(cmd_args) < 1:
1382        raise ArgumentError("No arguments passed")
1383    thval = kern.GetValueFromAddress(cmd_args[0], 'thread *')
1384    lldbthread = GetLLDBThreadForKernelThread(thval)
1385    with O.table(GetThreadSummary.header):
1386        print(GetThreadSummary(thval, O=O))
1387    LazyTarget.GetProcess().selected_thread = lldbthread
1388    if not LazyTarget.GetProcess().SetSelectedThread(lldbthread):
1389        print("Failed to switch thread.")
1390    return
1391
1392@lldb_command('switchtoregs')
1393def SwitchToRegs(cmd_args=None):
1394    """ Routine to switch to a register state.
1395        Usage: (lldb) switchtoregs <struct arm_saved_state[64] *>
1396        This command creates a fake thread in lldb with the saved register state.
1397        Note: This command ONLY works for ARM based kernel setup.
1398    """
1399
1400    if cmd_args == None or len(cmd_args) < 1:
1401        raise ArgumentError("No arguments passed")
1402
1403    lldb_process = LazyTarget.GetProcess()
1404
1405    saved_state = ArgumentStringToInt(cmd_args[0])
1406    # any change to this logic requires change in operating_system.py as well
1407    fake_thread_id = 0xdead0000 | (saved_state & ~0xffff0000)
1408    fake_thread_id = fake_thread_id & 0xdeadffff
1409    lldb_process.CreateOSPluginThread(0xdeadbeef, saved_state)
1410    lldbthread = lldb_process.GetThreadByID(int(fake_thread_id))
1411
1412    if not lldbthread.IsValid():
1413        print("Failed to create thread")
1414        return
1415
1416    lldb_process.selected_thread = lldbthread
1417    if not lldb_process.SetSelectedThread(lldbthread):
1418        print("Failed to switch thread")
1419    print("Switched to Fake thread created from register state at {:#x}".format(
1420            saved_state))
1421
1422
1423# Macro: showallstacks
1424@lldb_command('showallstacks', fancy=True)
1425def ShowAllStacks(cmd_args=None, cmd_options={}, O=None):
1426    """Routine to print out the stack for each thread in the system.
1427    """
1428    for t in kern.tasks:
1429        ShowTaskStacks(t, O=O)
1430        print(" \n")
1431    ZombStacks(O=O)
1432
1433# EndMacro: showallstacks
1434
1435# Macro: showcurrentstacks
1436@lldb_command('showcurrentstacks', fancy=True)
1437def ShowCurrentStacks(cmd_args=None, cmd_options={}, O=None):
1438    """ Routine to print out the thread running on each cpu (incl. its stack)
1439    """
1440    processor_list = kern.GetGlobalVariable('processor_list')
1441    current_processor = processor_list
1442    while unsigned(current_processor) > 0:
1443        print("\n" + GetProcessorSummary(current_processor))
1444        active_thread = current_processor.active_thread
1445        if unsigned(active_thread) != 0:
1446            task_val = active_thread.t_tro.tro_task
1447            proc_val = GetProcFromTask(task_val)
1448            print(GetTaskSummary.header + " " + GetProcSummary.header)
1449            print(GetTaskSummary(task_val) + " " + GetProcSummary(proc_val))
1450            with O.table(GetThreadSummary.header, indent=True):
1451                print(GetThreadSummary(active_thread, O=O))
1452            print("\tBacktrace:")
1453            print(GetThreadBackTrace(active_thread, prefix="\t"))
1454        current_processor = current_processor.processor_list
1455    return
1456# EndMacro: showcurrentstacks
1457
1458@lldb_command('showcurrentthreads', fancy=True)
1459def ShowCurrentThreads(cmd_args=None, cmd_options={}, O=None):
1460    """ Display info about threads running on each cpu """
1461    processor_list = kern.GetGlobalVariable('processor_list')
1462    current_processor = processor_list
1463    while unsigned(current_processor) > 0:
1464        print(GetProcessorSummary(current_processor))
1465        active_thread = current_processor.active_thread
1466        if unsigned(active_thread) != 0 :
1467            task_val = active_thread.t_tro.tro_task
1468            proc_val = GetProcFromTask(task_val)
1469            print(GetTaskSummary.header + " " + GetProcSummary.header)
1470            print(GetTaskSummary(task_val) + " " + GetProcSummary(proc_val))
1471            with O.table(GetThreadSummary.header, indent=True):
1472                print(GetThreadSummary(active_thread, O=O))
1473        current_processor = current_processor.processor_list
1474    return
1475
1476def GetFullBackTrace(frame_addr, verbosity = vHUMAN, prefix = ""):
1477    """ Get backtrace across interrupt context.
1478        params: frame_addr - int - address in memory which is a frame pointer (ie. rbp, r7)
1479                prefix - str - prefix for each line of output.
1480
1481    """
1482    out_string = ""
1483    bt_count = 0
1484    frame_ptr = frame_addr
1485    previous_frame_ptr = 0
1486    # <rdar://problem/12677290> lldb unable to find symbol for _mh_execute_header
1487    mh_execute_addr = int(lldb_run_command('p/x (uintptr_t *)&_mh_execute_header').split('=')[-1].strip(), 16)
1488    while frame_ptr and frame_ptr != previous_frame_ptr and bt_count < 128:
1489        if (not kern.arch.startswith('arm') and frame_ptr < mh_execute_addr) or (kern.arch.startswith('arm') and frame_ptr > mh_execute_addr):
1490            break
1491        pc_val = kern.GetValueFromAddress(frame_ptr + kern.ptrsize,'uintptr_t *')
1492        pc_val = kern.StripKernelPAC(unsigned(dereference(pc_val)))
1493        out_string += prefix + GetSourceInformationForAddress(pc_val) + "\n"
1494        bt_count +=1
1495        previous_frame_ptr = frame_ptr
1496        frame_val = kern.GetValueFromAddress((frame_ptr), 'uintptr_t *')
1497        if unsigned(frame_val) == 0:
1498            break
1499        frame_ptr = unsigned(dereference(frame_val))
1500
1501    return out_string
1502
1503@lldb_command('fullbt')
1504def FullBackTrace(cmd_args=[]):
1505    """ Show full backtrace across the interrupt boundary.
1506        Syntax: fullbt <frame ptr>
1507        Example: fullbt  `$rbp`
1508    """
1509    if len(cmd_args) < 1:
1510        print(FullBackTrace.__doc__)
1511        return False
1512    print(GetFullBackTrace(ArgumentStringToInt(cmd_args[0]), prefix="\t"))
1513
1514@lldb_command('fullbtall', fancy=True)
1515def FullBackTraceAll(cmd_args=[], cmd_options={}, O=None):
1516    """ Show full backtrace across the interrupt boundary for threads running on all processors.
1517        Syntax: fullbtall
1518        Example: fullbtall
1519    """
1520    for processor in IterateLinkedList(kern.globals.processor_list, 'processor_list') :
1521        print("\n" + GetProcessorSummary(processor))
1522        active_thread = processor.active_thread
1523        if unsigned(active_thread) != 0 :
1524            task_val = active_thread.t_tro.tro_task
1525            proc_val = GetProcFromTask(task_val)
1526            print(GetTaskSummary.header + " " + GetProcSummary.header)
1527            print(GetTaskSummary(task_val) + " " + GetProcSummary(proc_val))
1528            with O.table(GetThreadSummary.header, indent=True):
1529                print(GetThreadSummary(active_thread, O=O))
1530            print("\tBacktrace:")
1531
1532            ThreadVal = GetLLDBThreadForKernelThread(active_thread)
1533
1534            FramePtr = ThreadVal.frames[0].GetFP()
1535
1536            print(GetFullBackTrace(unsigned(FramePtr), prefix="\t"))
1537
1538
1539@lldb_command('symbolicate')
1540def SymbolicateAddress(cmd_args=[]):
1541    """ Symbolicate an address for symbol information from loaded symbols
1542        Example: "symbolicate 0xaddr" is equivalent to "output/a 0xaddr"
1543    """
1544    if len(cmd_args) < 1:
1545        print("Invalid address.\nSyntax: symbolicate <address>")
1546        return False
1547    print(GetSourceInformationForAddress(ArgumentStringToInt(cmd_args[0])))
1548    return True
1549
1550@lldb_command('showinitchild')
1551def ShowInitChild(cmd_args=None):
1552    """ Routine to print out all processes in the system
1553        which are children of init process
1554    """
1555    headp = kern.globals.initproc.p_children
1556    for pp in IterateListEntry(headp, 'p_sibling'):
1557        print(GetProcInfo(pp))
1558    return
1559
1560@lldb_command('showproctree')
1561def ShowProcTree(cmd_args=None):
1562    """ Routine to print the processes in the system in a hierarchical tree form. This routine does not print zombie processes.
1563        If no argument is given, showproctree will print all the processes in the system.
1564        If pid is specified, showproctree prints all the descendants of the indicated process
1565    """
1566    search_pid = 0
1567    if cmd_args:
1568        search_pid = ArgumentStringToInt(cmd_args[0])
1569
1570    if search_pid < 0:
1571        print("pid specified must be a positive number")
1572        print(ShowProcTree.__doc__)
1573        return
1574
1575    hdr_format = "{0: <6s} {1: <14s} {2: <9s}\n"
1576    out_string = hdr_format.format("PID", "PROCESS", "POINTER")
1577    out_string += hdr_format.format('='*3, '='*7, '='*7)
1578    proc = GetProcForPid(search_pid)
1579    out_string += "{0: <6d} {1: <32s} [ {2: #019x} ]\n".format(
1580            proc.p_ppid, GetProcName(proc.p_pptr), unsigned(proc.p_pptr))
1581    out_string += "|--{0: <6d} {1: <32s} [ {2: #019x} ]\n".format(
1582            GetProcPID(proc), GetProcName(proc), unsigned(proc))
1583    print(out_string)
1584    ShowProcTreeRecurse(proc, "|  ")
1585
1586def ShowProcTreeRecurse(proc, prefix=""):
1587    """ Prints descendants of a given proc in hierarchial tree form
1588        params:
1589            proc  : core.value representing a struct proc * in the kernel
1590        returns:
1591            str   : String containing info about a given proc and its descendants in tree form
1592    """
1593    if proc.p_childrencnt > 0:
1594        head_ptr = proc.p_children.lh_first
1595
1596        for p in IterateListEntry(proc.p_children, 'p_sibling'):
1597            print(prefix + "|--{0: <6d} {1: <32s} [ {2: #019x} ]\n".format(
1598                    GetProcPID(p), GetProcName(p), unsigned(p)))
1599            ShowProcTreeRecurse(p, prefix + "|  ")
1600
1601@lldb_command('showthreadfortid', fancy=True)
1602def ShowThreadForTid(cmd_args=None, O=None):
1603    """ The thread structure contains a unique thread_id value for each thread.
1604        This command is used to retrieve the address of the thread structure(thread_t)
1605        corresponding to a given thread_id.
1606    """
1607    if not cmd_args:
1608        print("Please provide thread_t whose tid you'd like to look up")
1609        print(ShowThreadForTid.__doc__)
1610        return
1611    search_tid = ArgumentStringToInt(cmd_args[0])
1612    for taskp in kern.tasks:
1613        for actp in IterateQueue(taskp.threads, 'struct thread *', 'task_threads'):
1614            if search_tid == int(actp.thread_id):
1615                print("Found {0: #019x}".format(actp))
1616                with O.table(GetThreadSummary.header):
1617                    print(GetThreadSummary(actp, O=O))
1618                return
1619    print("Not a valid thread_id")
1620
1621def GetProcessorSummary(processor):
1622    """ Internal function to print summary of processor
1623        params: processor - value representing struct processor *
1624        return: str - representing the details of given processor
1625    """
1626
1627    processor_state_str = "INVALID"
1628    processor_state = int(processor.state)
1629
1630    processor_states = {
1631                0: 'OFF_LINE',
1632                1: 'SHUTDOWN',
1633                2: 'START',
1634                3: 'PENDING_OFFLINE',
1635                4: 'IDLE',
1636                5: 'DISPATCHING',
1637                6: 'RUNNING'
1638                }
1639
1640    if processor_state in processor_states:
1641        processor_state_str = "{0: <11s} ".format(processor_states[processor_state])
1642
1643    processor_recommended_str = ""
1644    if int(processor.is_recommended) == 0:
1645        processor_recommended_str = " (not recommended)"
1646
1647    ast = 0
1648    preemption_disable = 0
1649    preemption_disable_str = ""
1650
1651    if kern.arch == 'x86_64':
1652        cpu_data = kern.globals.cpu_data_ptr[processor.cpu_id]
1653        if (cpu_data != 0) :
1654            ast = cpu_data.cpu_pending_ast
1655            preemption_disable = cpu_data.cpu_preemption_level
1656    # On arm64, it's kern.globals.CpuDataEntries[processor.cpu_id].cpu_data_vaddr
1657    # but LLDB can't find CpuDataEntries...
1658
1659    ast_str = GetASTSummary(ast)
1660
1661    if (preemption_disable != 0) :
1662        preemption_disable_str = "Preemption Disabled"
1663
1664    processor_reasons = {
1665        0: '(REASON_NONE)',
1666        1: '(REASON_SYSTEM)',
1667        2: '(REASON_USER)',
1668        3: '(REASON_CLPC_SYSTEM)',
1669        4: '(REASON_CLPC_USER)'
1670    }
1671
1672    processor_shutdown_reason_str = "";
1673    processor_shutdown_reason = int(processor.last_shutdown_reason)
1674
1675    if processor_state in {0, 1, 3}:
1676        processor_shutdown_reason_str = processor_reasons[processor_shutdown_reason]
1677
1678    out_str = "Processor {: <#018x} cpu_id {:>#4x} AST: {:<6s} State {:<s}{:<s}{:<s} {:<s}\n".format(
1679            processor, int(processor.cpu_id), ast_str, processor_state_str, processor_shutdown_reason_str,
1680            processor_recommended_str, preemption_disable_str)
1681    return out_str
1682
1683ledger_limit_infinity = (uint64_t(0x1).value << 63) - 1
1684
1685def GetLedgerEntryIndex(template, name):
1686    i = 0
1687    while i != template.lt_cnt:
1688        if str(template.lt_entries[i].et_key) == name:
1689            return i
1690        i = i + 1
1691    return -1
1692
1693def GetLedgerEntryWithTemplate(ledger_template, ledgerp, i):
1694    """ Internal function to get internals of a ledger entry (*not* a ledger itself)
1695        params: ledger_template - value representing struct ledger_template_t for the task or thread
1696                ledgerp - value representing ledger pointer
1697                i - index in ledger
1698        return: entry - entry dictionary
1699    """
1700    lf_refill_scheduled = 0x0400
1701    lf_tracking_max = 0x4000
1702
1703    now = unsigned(kern.globals.sched_tick) // 20
1704    lim_pct = 0
1705
1706    entry = {}
1707
1708    et = ledger_template.lt_entries[i]
1709    entry["key"] = str(et.et_key)
1710    if et.et_size == sizeof("struct ledger_entry_small"):
1711        les = ledgerp.l_entries[et.et_offset]
1712        entry["credit"] = unsigned(les.les_credit)
1713        entry["debit"] = 0
1714        entry["flags"] = int(les.les_flags)
1715        entry["limit"] = ledger_limit_infinity
1716    elif et.et_size == sizeof("struct ledger_entry"):
1717        le = Cast(addressof(ledgerp.l_entries[et.et_offset]), "struct ledger_entry *")
1718        entry["credit"] = unsigned(le.le_credit)
1719        entry["debit"] = unsigned(le.le_debit)
1720        if (le.le_flags & lf_tracking_max):
1721            if hasattr(le._le._le_max, "le_interval_max"):
1722                entry["interval_max"] = unsigned(le._le._le_max.le_interval_max)
1723            entry["lifetime_max"] = unsigned(le._le._le_max.le_lifetime_max)
1724
1725        entry["limit"] = unsigned(le.le_limit)
1726
1727        if (le.le_flags & lf_refill_scheduled):
1728            entry["refill_period"] = unsigned (le._le.le_refill.le_refill_period)
1729
1730        if (unsigned(le.le_warn_percent) < 65535):
1731            entry["warn_percent"] = unsigned (le.le_warn_percent * 100 / 65536)
1732        entry["flags"] = int(le.le_flags)
1733    else:
1734        return None
1735
1736    entry["balance"] = entry["credit"] - entry["debit"]
1737    return entry
1738
1739def GetLedgerEntryWithName(ledger_template, ledger, name):
1740    idx = GetLedgerEntryIndex(ledger_template, name)
1741    assert(idx != -1)
1742    return GetLedgerEntryWithTemplate(ledger_template, ledger, idx)
1743
1744def FormatLedgerEntrySummary(entry, i, show_footprint_interval_max=False):
1745    """ internal function to format a ledger entry into a string
1746        params: entry - A python dictionary containing the ledger entry
1747        return: str - formatted output information of ledger entries
1748    """
1749    out_str = ''
1750    out_str += "{: >32s} {:<2d}:".format(entry["key"], i)
1751    out_str += "{: >15d} ".format(entry["balance"])
1752
1753    if (show_footprint_interval_max):
1754        if "interval_max" in entry:
1755            out_str += "{:12d} ".format(entry["interval_max"])
1756        else:
1757            out_str += "           - "
1758
1759    if "lifetime_max" in entry:
1760        out_str += "{:14d} ".format(entry["lifetime_max"])
1761    else:
1762        out_str += "             - "
1763
1764    out_str += "{:12d} {:12d} ".format(entry["credit"], entry["debit"])
1765    if entry.get('limit', unsigned(ledger_limit_infinity)) != unsigned(ledger_limit_infinity):
1766        out_str += "{:12d} ".format(unsigned(entry["limit"]))
1767    else:
1768        out_str += "           - "
1769
1770    if "refill_period" in entry:
1771        out_str += "{:15d} ".format(entry["refill_period"])
1772        if entry["refill_period"] != 0:
1773            out_str += "{:9d} ".format((entry["limit"] * 100) // entry["refill_period"])
1774        else:
1775            out_str += "XXXXX     - "
1776    else:
1777        out_str += "              - "
1778        out_str += "        - "
1779
1780    if "warn_percent" in entry:
1781        out_str += "{:9d} ".format(entry["warn_percent"])
1782    else:
1783        out_str += "        - "
1784
1785    if "limit" in entry:
1786        if entry["balance"] > entry["limit"]:
1787            out_str += "    X "
1788        else:
1789            out_str += "      "
1790    else:
1791        out_str += "      "
1792
1793    out_str += "{:#8x}\n".format(entry["flags"])
1794    return out_str
1795
1796def GetLedgerEntrySummary(ledger_template, ledger, i, show_footprint_interval_max=False):
1797    """ internal function to get internals of a ledger entry (*not* a ledger itself)
1798        params: ledger_template - value representing struct ledger_template_t for the task or thread
1799                ledger - value representing ledger pointer
1800        return: str - formatted output information of ledger entries
1801    """
1802    entry = GetLedgerEntryWithTemplate(ledger_template, ledger, i)
1803    return FormatLedgerEntrySummary(entry, i)
1804
1805
1806def GetThreadLedgers(thread_val):
1807    """ Internal function to get a summary of ledger entries for the given thread
1808        params: thread_val - value representing struct thread *
1809        return: thread - python dictionary containing threads's ledger entries. This can
1810        be printed directly with FormatThreadLedgerSummmary or outputted as json.
1811    """
1812    thread = {}
1813    thread["address"] = unsigned(thread_val)
1814    ledgerp = thread_val.t_threadledger
1815    thread["entries"] = []
1816    if ledgerp:
1817        i = 0
1818        while i != ledgerp.l_template.lt_cnt:
1819            thread["entries"].append(GetLedgerEntryWithTemplate(kern.globals.thread_ledger_template,
1820                ledgerp, i))
1821            i = i + 1
1822    return thread
1823
1824def FormatThreadLedgerSummary(thread):
1825    """ Internal function to print a thread's ledger entries
1826        params: thread - python dictionary containing thread's ledger entries
1827        return: str - formatted output information for ledger entries of the input thread
1828    """
1829    out_str = "   [{:#08x}]\n".format(thread["address"])
1830    entries = thread["entries"]
1831    for i, entry in enumerate(entries):
1832        out_str += FormatLedgerEntrySummary(entry, i)
1833    return out_str
1834
1835def GetTaskLedgers(task_val):
1836    """ Internal function to get summary of ledger entries from the task and its threads
1837        params: task_val - value representing struct task *
1838        return: task - python dictionary containing tasks's ledger entries. This can
1839        be printed directly with FormatTaskLedgerSummary or outputted as json.
1840    """
1841    task_ledgerp = task_val.ledger
1842    i = 0
1843    tasks = []
1844    task = {}
1845    task["address"] = unsigned(task_val)
1846
1847    pval = GetProcFromTask(task_val)
1848    if pval:
1849        task["name"] = GetProcName(pval)
1850        task["pid"] = int(GetProcPID(pval))
1851
1852    task["entries"] = []
1853    while i != task_ledgerp.l_template.lt_cnt:
1854        task["entries"].append(GetLedgerEntryWithTemplate(kern.globals.task_ledger_template, task_ledgerp, i))
1855        i = i + 1
1856
1857    # Now walk threads
1858    task["threads"] = []
1859    for thval in IterateQueue(task_val.threads, 'thread *', 'task_threads'):
1860        task["threads"].append(GetThreadLedgers(thval))
1861
1862    return task
1863
1864@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(
1865            "task [thread]", "entry", "#", "balance", "lifetime_max", "credit",
1866            "debit", "limit", "refill period", "lim pct", "warn pct", "over?", "flags"))
1867def FormatTaskLedgerSummary(task, show_footprint_interval_max=False):
1868    """ Internal function to get summary of ledger entries from the task and its threads
1869        params: task_val - value representing struct task *
1870        return: str - formatted output information for ledger entries of the input task
1871    """
1872    out_str = ''
1873    out_str += "{: #08x} ".format(task["address"])
1874    if "name" in task:
1875        out_str += "{: <5s}:\n".format(task["name"])
1876    else:
1877        out_str += "Invalid process\n"
1878
1879    for i, entry in enumerate(task["entries"]):
1880        out_str += FormatLedgerEntrySummary(entry, i, show_footprint_interval_max)
1881
1882    for thread in task["threads"]:
1883        out_str += FormatThreadLedgerSummary(thread)
1884    return out_str
1885
1886
1887# Macro: showtaskledgers
1888
1889@lldb_command('showtaskledgers', 'JF:I')
1890def ShowTaskLedgers(cmd_args=None, cmd_options={}):
1891    """  Routine to print a summary  of ledger entries for the task and all of its threads
1892         or   : showtaskledgers [ -I ] [-J] [ -F ] <task>
1893         options:
1894            -I: show footprint interval max (DEV/DEBUG only)
1895            -F: specify task via name instead of address
1896            -J: output json
1897        -
1898    """
1899    print_json = False
1900    if "-F" in cmd_options:
1901        task_list = FindTasksByName(cmd_options["-F"])
1902        for tval in task_list:
1903            print(FormatTaskLedgerSummary.header)
1904            ledgers = GetTaskLedgers(tval)
1905            print(FormatTaskLedgerSummary(ledgers))
1906        return
1907    if "-J" in cmd_options:
1908        print_json = True
1909
1910    if not cmd_args:
1911        raise ArgumentError("No arguments passed.")
1912    show_footprint_interval_max = False
1913    if "-I" in cmd_options:
1914        show_footprint_interval_max = True
1915    tval = kern.GetValueFromAddress(cmd_args[0], 'task *')
1916    if not tval:
1917        raise ArgumentError("unknown arguments: %r" %cmd_args)
1918    ledgers = GetTaskLedgers(tval)
1919    if print_json:
1920        print(json.dumps(ledgers))
1921    else:
1922        if (show_footprint_interval_max):
1923            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(
1924            "task [thread]", "entry", "#", "balance", "intrvl_max", "lifetime_max", "credit",
1925            "debit", "limit", "refill period", "lim pct", "warn pct", "over?", "flags"))
1926        else:
1927            print(FormatTaskLedgerSummary.header)
1928        print(FormatTaskLedgerSummary(ledgers, show_footprint_interval_max))
1929
1930# EndMacro: showtaskledgers
1931
1932# Macro: showalltaskledgers
1933
1934@lldb_command('showalltaskledgers', "J")
1935def ShowAllTaskLedgers(cmd_args=None, cmd_options={}):
1936    """  Routine to print a summary  of ledger entries for all tasks and respective threads
1937         Usage: showalltaskledgers [-J]
1938            -J      : Output json
1939    """
1940    print_json = False
1941    if "-J" in cmd_options:
1942        print_json = True
1943    tasks = []
1944    for t in kern.tasks:
1945        task_val = unsigned(t)
1946        if not print_json:
1947            ShowTaskLedgers([task_val], cmd_options=cmd_options)
1948        else:
1949            tasks.append(GetTaskLedgers(t))
1950    if print_json:
1951        print(json.dumps(tasks))
1952
1953# EndMacro: showalltaskledgers
1954
1955# Macro: showprocuuidpolicytable
1956
1957@lldb_type_summary(['proc_uuid_policy_entry'])
1958@header("{0: <36s} {1: <10s}".format("uuid", "flags"))
1959def GetProcUUIDPolicyEntrySummary(entry):
1960    """ Summarizes the important fields in proc_uuid_policy_entry structure.
1961        params: entry: value - value object representing an entry
1962        returns: str - summary of the entry
1963    """
1964    data = []
1965    for i in range(16):
1966        data.append(int(entry.uuid[i]))
1967    flags = unsigned(entry.flags)
1968    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} 0x{b:0>8x}".format(a=data, b=flags)
1969    return out_string
1970
1971@lldb_command('showprocuuidpolicytable')
1972def ShowProcUUIDPolicyTable(cmd_args=None):
1973    """ Routine to print the proc UUID policy table
1974        Usage: showprocuuidpolicytable
1975    """
1976    hashslots = unsigned(kern.globals.proc_uuid_policy_hash_mask)
1977    print("{0: <8s} ".format("slot") + GetProcUUIDPolicyEntrySummary.header)
1978    for i in range(0, hashslots+1):
1979        headp = addressof(kern.globals.proc_uuid_policy_hashtbl[i])
1980        entrynum = 0
1981        for entry in IterateListEntry(headp, 'entries'):
1982            print("{0: >2d}.{1: <5d} ".format(i, entrynum) + GetProcUUIDPolicyEntrySummary(entry))
1983            entrynum += 1
1984
1985
1986# EndMacro: showprocuuidpolicytable
1987
1988@lldb_command('showalltaskpolicy')
1989def ShowAllTaskPolicy(cmd_args=None):
1990    """
1991         Routine to print a summary listing of all the tasks
1992         wq_state -> reports "number of workq threads", "number of scheduled workq threads", "number of pending work items"
1993         if "number of pending work items" seems stuck at non-zero, it may indicate that the workqueue mechanism is hung
1994         io_policy -> RAGE  - rapid aging of vnodes requested
1995                     NORM  - normal I/O explicitly requested (this is the default)
1996                     PASS  - passive I/O requested (i.e. I/Os do not affect throttling decisions)
1997                     THROT - throttled I/O requested (i.e. thread/task may be throttled after each I/O completes)
1998    """
1999    global kern
2000    print(GetTaskSummary.header + " " + GetProcSummary.header)
2001    for t in kern.tasks:
2002        pval = GetProcFromTask(t)
2003        print(GetTaskSummary(t) +" "+ GetProcSummary(pval))
2004        requested_strings = [
2005                ["int_darwinbg",        "DBG-int"],
2006                ["ext_darwinbg",        "DBG-ext"],
2007                ["int_iotier",          "iotier-int"],
2008                ["ext_iotier",          "iotier-ext"],
2009                ["int_iopassive",       "passive-int"],
2010                ["ext_iopassive",       "passive-ext"],
2011                ["bg_iotier",           "bg-iotier"],
2012                ["terminated",          "terminated"],
2013                ["th_pidbind_bg",       "bg-pidbind"],
2014                ["t_apptype",           "apptype"],
2015                ["t_boosted",           "boosted"],
2016                ["t_role",              "role"],
2017                ["t_tal_enabled",       "tal-enabled"],
2018                ["t_base_latency_qos",  "latency-base"],
2019                ["t_over_latency_qos",  "latency-override"],
2020                ["t_base_through_qos",  "throughput-base"],
2021                ["t_over_through_qos",  "throughput-override"]
2022                ]
2023
2024        requested=""
2025        for value in requested_strings:
2026            if t.requested_policy.__getattr__(value[0]) :
2027                requested+=value[1] + ": " + str(t.requested_policy.__getattr__(value[0])) + " "
2028            else:
2029                requested+=""
2030
2031        suppression_strings = [
2032                ["t_sup_active",        "active"],
2033                ["t_sup_lowpri_cpu",    "lowpri-cpu"],
2034                ["t_sup_timer",         "timer-throttling"],
2035                ["t_sup_disk",          "disk-throttling"],
2036                ["t_sup_cpu_limit",     "cpu-limits"],
2037                ["t_sup_suspend",       "suspend"],
2038                ["t_sup_bg_sockets",    "bg-sockets"]
2039                ]
2040
2041        suppression=""
2042        for value in suppression_strings:
2043            if t.requested_policy.__getattr__(value[0]) :
2044                suppression+=value[1] + ": " + str(t.requested_policy.__getattr__(value[0])) + " "
2045            else:
2046                suppression+=""
2047
2048        effective_strings = [
2049                ["darwinbg",        "background"],
2050                ["lowpri_cpu",      "lowpri-cpu"],
2051                ["io_tier",         "iotier"],
2052                ["io_passive",      "passive"],
2053                ["all_sockets_bg",  "bg-allsockets"],
2054                ["new_sockets_bg",  "bg-newsockets"],
2055                ["bg_iotier",       "bg-iotier"],
2056                ["terminated",      "terminated"],
2057                ["t_gpu_deny",      "gpu-deny"],
2058                ["t_tal_engaged",   "tal-engaged"],
2059                ["t_suspended",     "suspended"],
2060                ["t_watchers_bg",   "bg-watchers"],
2061                ["t_latency_qos",   "latency-qos"],
2062                ["t_through_qos",   "throughput-qos"],
2063                ["t_sup_active",    "suppression-active"],
2064                ["t_role",          "role"]
2065                ]
2066
2067        effective=""
2068        for value in effective_strings:
2069            if t.effective_policy.__getattr__(value[0]) :
2070                effective+=value[1] + ": " + str(t.effective_policy.__getattr__(value[0])) + " "
2071            else:
2072                effective+=""
2073
2074        print("requested: " + requested)
2075        print("suppression: " + suppression)
2076        print("effective: " + effective)
2077
2078
2079@lldb_command('showallsuspendedtasks', '')
2080def ShowSuspendedTasks(cmd_args=[], options={}):
2081    """ Show a list of suspended tasks with their process name summary.
2082    """
2083    print(GetTaskSummary.header + ' ' + GetProcSummary.header)
2084    for t in kern.tasks:
2085        if t.suspend_count > 0:
2086            print(GetTaskSummary(t) + ' ' + GetProcSummary(GetProcFromTask(t)))
2087    return True
2088
2089# Macro: showallpte
2090@lldb_command('showallpte')
2091def ShowAllPte(cmd_args=None):
2092    """ Prints out the physical address of the pte for all tasks
2093    """
2094    head_taskp = addressof(kern.globals.tasks)
2095    taskp = Cast(head_taskp.next, 'task *')
2096    while taskp != head_taskp:
2097        procp = GetProcFromTask(taskp)
2098        out_str = "task = {:#x} pte = {:#x}\t".format(taskp, taskp.map.pmap.ttep)
2099        if procp != 0:
2100            out_str += "{:s}\n".format(GetProcName(procp))
2101        else:
2102            out_str += "\n"
2103        print(out_str)
2104        taskp = Cast(taskp.tasks.next, 'struct task *')
2105
2106# EndMacro: showallpte
2107
2108# Macro: showallrefcounts
2109@lldb_command('showallrefcounts')
2110@header("{0: <20s} {1: ^10s}".format("task", "ref_count"))
2111def ShowAllRefCounts(cmd_args=None):
2112    """ Prints the ref_count of all tasks
2113    """
2114    out_str = ''
2115    head_taskp = addressof(kern.globals.tasks)
2116    taskp = Cast(head_taskp.next, 'task *')
2117    print(ShowAllRefCounts.header)
2118    while taskp != head_taskp:
2119        out_str += "{: <#20x}".format(taskp)
2120        out_str += "{: ^10d}\n".format(taskp.ref_count.ref_count)
2121        taskp = Cast(taskp.tasks.next, 'task *')
2122    print(out_str)
2123# EndMacro: showallrefcounts
2124
2125# Macro: showallrunnablethreads
2126@lldb_command('showallrunnablethreads', fancy=True)
2127def ShowAllRunnableThreads(cmd_args=None, cmd_options={}, O=None):
2128    """ Prints the sched usage information for all threads of each task
2129    """
2130    out_str = ''
2131    for taskp in kern.tasks:
2132        for actp in IterateQueue(taskp.threads, 'thread *', 'task_threads'):
2133            if int(actp.state & 0x4):
2134                ShowActStack([unsigned(actp)], O=O)
2135
2136# EndMacro: showallrunnablethreads
2137
2138# Macro: showallschedusage
2139@lldb_command('showallschedusage')
2140@header("{0:<20s} {1:^10s} {2:^10s} {3:^15s}".format("Thread", "Priority", "State", "sched_usage"))
2141def ShowAllSchedUsage(cmd_args=None):
2142    """ Prints the sched usage information for all threads of each task
2143    """
2144    out_str = ''
2145    for taskp in kern.tasks:
2146        ShowTask([unsigned(taskp)])
2147        print(ShowAllSchedUsage.header)
2148        for actp in IterateQueue(taskp.threads, 'thread *', 'task_threads'):
2149            out_str = "{: <#20x}".format(actp)
2150            out_str += "{: ^10s}".format(str(int(actp.sched_pri)))
2151            state = int(actp.state)
2152            thread_state_chars = {0:'', 1:'W', 2:'S', 4:'R', 8:'U', 16:'H', 32:'A', 64:'P', 128:'I'}
2153            state_str = ''
2154            state_str += thread_state_chars[int(state & 0x1)]
2155            state_str += thread_state_chars[int(state & 0x2)]
2156            state_str += thread_state_chars[int(state & 0x4)]
2157            state_str += thread_state_chars[int(state & 0x8)]
2158            state_str += thread_state_chars[int(state & 0x10)]
2159            state_str += thread_state_chars[int(state & 0x20)]
2160            state_str += thread_state_chars[int(state & 0x40)]
2161            state_str += thread_state_chars[int(state & 0x80)]
2162            out_str += "{: ^10s}".format(state_str)
2163            out_str += "{: >15d}".format(actp.sched_usage)
2164            print(out_str + "\n")
2165        print("\n\n")
2166
2167# EndMacro: showallschedusage
2168
2169#Macro: showprocfilessummary
2170@lldb_command('showprocfilessummary')
2171@header("{0: <20s} {1: <20s} {2: >10s}".format("Process", "Name", "Number of Open Files"))
2172def ShowProcFilesSummary(cmd_args=None):
2173    """ Display the summary of open file descriptors for all processes in task list
2174        Usage: showprocfilessummary
2175    """
2176    print(ShowProcFilesSummary.header)
2177    for proc in kern.procs:
2178        proc_filedesc = addressof(proc.p_fd)
2179        proc_ofiles = proc_filedesc.fd_ofiles
2180        proc_file_count = 0
2181        for fd in range(0, proc_filedesc.fd_afterlast):
2182            if unsigned(proc_ofiles[fd]) != 0:
2183                proc_file_count += 1
2184        print("{0: <#020x} {1: <32s} {2: >10d}".format(proc, GetProcName(proc), proc_file_count))
2185
2186#EndMacro: showprocfilessummary
2187
2188@lldb_command('workinguserstacks')
2189def WorkingUserStacks(cmd_args=None):
2190    """ Print out the user stack for each thread in a task, followed by the user libraries.
2191        Syntax: (lldb) workinguserstacks <task_t>
2192    """
2193    if not cmd_args:
2194        print("Insufficient arguments" + ShowTaskUserStacks.__doc__)
2195        return False
2196    task = kern.GetValueFromAddress(cmd_args[0], 'task *')
2197    print(GetTaskSummary.header + " " + GetProcSummary.header)
2198    pval = GetProcFromTask(task)
2199    print(GetTaskSummary(task) + " " + GetProcSummary(pval) + "\n \n")
2200    for thval in IterateQueue(task.threads, 'thread *', 'task_threads'):
2201        print("For thread 0x{0:x}".format(thval))
2202        try:
2203            ShowThreadUserStack([hex(thval)])
2204        except Exception as exc_err:
2205            print("Failed to show user stack for thread 0x{0:x}".format(thval))
2206            if config['debug']:
2207                raise exc_err
2208            else:
2209                print("Enable debugging ('(lldb) xnudebug debug') to see detailed trace.")
2210    WorkingUserLibraries([hex(task)])
2211
2212@static_var("exec_load_path", 0)
2213@lldb_command("workingkuserlibraries")
2214def WorkingUserLibraries(cmd_args=None):
2215    """ Show binary images known by dyld in target task
2216        For a given user task, inspect the dyld shared library state and print information about all Mach-O images.
2217        Syntax: (lldb)workinguserlibraries <task_t>
2218    """
2219    if not cmd_args:
2220        print("Insufficient arguments")
2221        print(ShowTaskUserLibraries.__doc__)
2222        return False
2223
2224    print("{0: <18s} {1: <12s} {2: <36s} {3: <50s}".format('address','type','uuid','path'))
2225    out_format = "0x{0:0>16x} {1: <12s} {2: <36s} {3: <50s}"
2226    task = kern.GetValueFromAddress(cmd_args[0], 'task_t')
2227    is_task_64 = int(task.t_flags) & 0x1
2228    dyld_all_image_infos_address = unsigned(task.all_image_info_addr)
2229    cur_data_offset = 0
2230    if dyld_all_image_infos_address == 0:
2231        print("No dyld shared library information available for task")
2232        return False
2233    vers_info_data = GetUserDataAsString(task, dyld_all_image_infos_address, 112)
2234    version = _ExtractDataFromString(vers_info_data, cur_data_offset, "uint32_t")
2235    cur_data_offset += 4
2236    if version > 12:
2237        print("Unknown dyld all_image_infos version number %d" % version)
2238    image_info_count = _ExtractDataFromString(vers_info_data, cur_data_offset, "uint32_t")
2239    WorkingUserLibraries.exec_load_path = 0
2240    if is_task_64:
2241        image_info_size = 24
2242        image_info_array_address = _ExtractDataFromString(vers_info_data, 8, "uint64_t")
2243        dyld_load_address = _ExtractDataFromString(vers_info_data, 8*4, "uint64_t")
2244        dyld_all_image_infos_address_from_struct = _ExtractDataFromString(vers_info_data, 8*13, "uint64_t")
2245    else:
2246        image_info_size = 12
2247        image_info_array_address = _ExtractDataFromString(vers_info_data, 4*2, "uint32_t")
2248        dyld_load_address = _ExtractDataFromString(vers_info_data, 4*5, "uint32_t")
2249        dyld_all_image_infos_address_from_struct = _ExtractDataFromString(vers_info_data, 4*14, "uint32_t")
2250    # Account for ASLR slide before dyld can fix the structure
2251    dyld_load_address = dyld_load_address + (dyld_all_image_infos_address - dyld_all_image_infos_address_from_struct)
2252
2253    i = 0
2254    while i < image_info_count:
2255        image_info_address = image_info_array_address + i * image_info_size
2256        img_data = GetUserDataAsString(task, image_info_address, image_info_size)
2257        if is_task_64:
2258            image_info_addr = _ExtractDataFromString(img_data, 0, "uint64_t")
2259            image_info_path = _ExtractDataFromString(img_data, 8, "uint64_t")
2260        else:
2261            image_info_addr = _ExtractDataFromString(img_data, 0, "uint32_t")
2262            image_info_path = _ExtractDataFromString(img_data, 4, "uint32_t")
2263        PrintImageInfo(task, image_info_addr, image_info_path)
2264        i += 1
2265
2266    # load_path might get set when the main executable is processed.
2267    if WorkingUserLibraries.exec_load_path != 0:
2268        PrintImageInfo(task, dyld_load_address, WorkingUserLibraries.exec_load_path)
2269    return
2270
2271# Macro: showstackaftertask
2272
2273@lldb_command('showstackaftertask', 'F:', fancy=True)
2274def Showstackaftertask(cmd_args=None, cmd_options={}, O=None):
2275    """ Routine to print the thread stacks for all tasks succeeding a given task
2276        Usage: showstackaftertask <0xaddress of task>
2277           or: showstackaftertask  -F <taskname>
2278    """
2279    if "-F" in cmd_options:
2280        # Find the task pointer corresponding to its task name
2281        find_task_str = cmd_options["-F"]
2282        task_list = FindTasksByName(find_task_str)
2283
2284        # Iterate through the list of tasks and print all task stacks thereafter
2285        for tval in task_list:
2286            ListTaskStacks(tval, O=O)
2287        return
2288
2289    if not cmd_args:
2290        raise ArgumentError("Insufficient arguments")
2291    tval = kern.GetValueFromAddress(cmd_args[0], 'task *')
2292    if not tval:
2293        raise ArgumentError("unknown arguments: {:s}".format(str(cmd_args)))
2294    else:
2295        ListTaskStacks(tval, O=O)
2296
2297    ZombStacks(O=O)
2298
2299# EndMacro: showstackaftertask
2300
2301def ListTaskStacks(task, O=None):
2302    """ Search for a given task and print the list of all task stacks thereafter.
2303    """
2304    # Initialize local variable task_flag to mark when a given task is found.
2305    task_flag=0
2306
2307    for t in kern.tasks:
2308        if (task_flag == 1):
2309            ShowTaskStacks(t, O=O)
2310            print("\n")
2311        if (t == task):
2312            task_flag = 1
2313
2314# Macro: showstackafterthread
2315@lldb_command('showstackafterthread', fancy=True)
2316def Showstackafterthread(cmd_args=None, cmd_options={}, O=None):
2317    """ Routine to print the stacks of all threads succeeding a given thread.
2318        Usage: Showstackafterthread <0xaddress of thread>
2319    """
2320    # local variable thread_flag is used to mark when a given thread is found.
2321    thread_flag=0
2322    if cmd_args:
2323       threadval = kern.GetValueFromAddress(cmd_args[0], 'thread *')
2324    else:
2325        raise ArgumentError("No arguments passed")
2326    # Iterate through list of all tasks to look up a given thread
2327    for t in kern.tasks:
2328        if(thread_flag==1):
2329            pval = GetProcFromTask(t)
2330            print(GetTaskSummary.header + " "+ GetProcSummary.header)
2331            print(GetTaskSummary(t) +     " "+ GetProcSummary(pval))
2332            print("\n")
2333         # Look up for a given thread from the the list of threads of a given task
2334        for thval in IterateQueue(t.threads, 'thread *', 'task_threads'):
2335            if thread_flag == 1:
2336                print("\n")
2337                with O.table(GetThreadSummary.header, indent=True):
2338                    print(GetThreadSummary(active_thread, O=O))
2339                print(GetThreadBackTrace(thval, prefix="\t")+"\n")
2340                print("\n")
2341
2342            if thval == threadval:
2343                pval = GetProcFromTask(t)
2344                process_name = "{:s}".format(GetProcName(pval))
2345                print("\n\n")
2346                print(" *** Continuing to dump the thread stacks from the process *** :" + " " + process_name)
2347                print("\n\n")
2348                thread_flag = 1
2349        print('\n')
2350    return
2351