xref: /xnu-10002.61.3/tools/lldbmacros/process.py (revision 0f4c859e951fba394238ab619495c4e1d54d0f34)
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.__smr_ptr
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        p - AST_PROC_RESOURCE
246    """
247    out_string = ""
248    state = int(ast)
249    thread_state_chars = {0x0:'', 0x1:'P', 0x2:'Q', 0x4:'U', 0x8:'H', 0x10:'Y', 0x20:'A',
250                          0x40:'L', 0x80:'B', 0x100:'K', 0x200:'M', 0x400: 'r', 0x800: 'a',
251                          0x1000:'G', 0x2000:'T', 0x4000:'T', 0x8000:'T', 0x10000:'S',
252                          0x20000: 'D', 0x40000: 'I', 0x80000: 'E', 0x100000: 'R', 0x400000: 'p'}
253    state_str = ''
254    mask = 0x1
255    while mask <= 0x200000:
256        state_str += thread_state_chars[int(state & mask)]
257        mask = mask << 1
258
259    return state_str
260
261
262@lldb_type_summary(['kcdata_descriptor *', 'kcdata_descriptor_t'])
263@header("{0: <20s} {1: <20s} {2: <20s} {3: <10s} {4: <5s}".format("kcdata_descriptor", "begin_addr", "cur_pos", "size", "flags"))
264def GetKCDataSummary(kcdata):
265    """ Summarizes kcdata_descriptor structure
266        params: kcdata: value - value object representing kcdata_descriptor
267        returns: str - summary of the kcdata object
268    """
269    format_string = "{0: <#020x} {1: <#020x} {2: <#020x} {3: <10d} {4: <#05x}"
270    return format_string.format(kcdata, kcdata.kcd_addr_begin, kcdata.kcd_addr_end, kcdata.kcd_length, kcdata.kcd_flags)
271
272
273@lldb_type_summary(['task', 'task_t'])
274@header("{0: <20s} {1: <20s} {2: <20s} {3: >5s} {4: <5s}".format("task","vm_map", "ipc_space", "#acts", "flags"))
275def GetTaskSummary(task, showcorpse=False):
276    """ Summarizes the important fields in task structure.
277        params: task: value - value object representing a task in kernel
278        returns: str - summary of the task
279    """
280    out_string = ""
281    format_string = '{0: <#020x} {1: <#020x} {2: <#020x} {3: >5d} {4: <5s}'
282    thread_count = int(task.thread_count)
283    task_flags = ''
284    if hasattr(task, "suppression_generation") and (int(task.suppression_generation) & 0x1) == 0x1:
285        task_flags += 'P'
286    if hasattr(task, "effective_policy") and int(task.effective_policy.tep_sup_active) == 1:
287        task_flags += 'N'
288    if hasattr(task, "suspend_count") and int(task.suspend_count) > 0:
289        task_flags += 'S'
290    if hasattr(task, 'task_imp_base') and unsigned(task.task_imp_base):
291        tib = task.task_imp_base
292        if int(tib.iit_receiver) == 1:
293            task_flags += 'R'
294        if int(tib.iit_donor) == 1:
295            task_flags += 'D'
296        if int(tib.iit_assertcnt) > 0:
297            task_flags += 'B'
298
299    proc_ro = Cast(task.bsd_info_ro, 'proc_ro *')
300
301    # check if corpse flag is set
302    if unsigned(proc_ro.t_flags_ro) & 0x20:
303        task_flags += 'C'
304    if unsigned(task.t_flags) & 0x40:
305        task_flags += 'P'
306
307    out_string += format_string.format(task, task.map, task.itk_space, thread_count, task_flags)
308    if showcorpse is True and unsigned(task.corpse_info) != 0:
309        out_string += " " + GetKCDataSummary(task.corpse_info)
310    return out_string
311
312def GetMachThread(uthread):
313    """ Converts the passed in value interpreted as a uthread_t into a thread_t
314    """
315    addr = unsigned(uthread) - sizeof('struct thread')
316    thread = kern.GetValueFromAddress(addr, 'struct thread *')
317    return thread
318
319def GetBSDThread(thread):
320    """ Converts the passed in value interpreted as a thread_t into a uthread_t
321    """
322    addr = unsigned(thread) + sizeof('struct thread')
323    return kern.GetValueFromAddress(addr, 'struct uthread *')
324
325def GetProcFromTask(task):
326    """ Converts the passed in value interpreted as a task_t into a proc_t
327    """
328    if unsigned(task) and unsigned(task.t_flags) & TF_HAS_PROC:
329        addr = unsigned(task) - kern.globals.proc_struct_size
330        return value(task.GetSBValue().xCreateValueFromAddress(
331            'proc', addr, gettype('struct proc')
332        ).AddressOf())
333    return kern.GetValueFromAddress(0, 'proc *')
334
335def GetTaskFromProc(proc):
336    """ Converts the passed in value interpreted as a proc_t into a task_t
337    """
338    if unsigned(proc) and unsigned(proc.p_lflag) & P_LHASTASK:
339        addr = unsigned(proc) + kern.globals.proc_struct_size
340        return value(proc.GetSBValue().xCreateValueFromAddress(
341            'task', addr, gettype('struct task')
342        ).AddressOf())
343    return kern.GetValueFromAddress(0, 'task *')
344
345def GetThreadName(thread):
346    """ Get the name of a thread, if possible.  Returns the empty string
347        otherwise.
348    """
349    uthread = GetBSDThread(thread)
350    if int(uthread.pth_name) != 0 :
351        th_name_strval = Cast(uthread.pth_name, 'char *')
352        if len(str(th_name_strval)) > 0 :
353            return str(th_name_strval)
354
355    return ''
356
357ThreadSummary = namedtuple('ThreadSummary', [
358        'thread', 'tid', 'task', 'processor', 'base', 'pri', 'sched_mode', 'io_policy',
359        'state', 'ast', 'waitq', 'wait_evt', 'wait_evt_sym', 'wait_msg',
360        'name'])
361ThreadSummaryNames = ThreadSummary(*ThreadSummary._fields)
362ThreadSummaryFormat = (
363        '{ts.thread: <20s} {ts.tid: <10s} {ts.task: <20s} {ts.processor: <20s} {ts.base: <6s} '
364        '{ts.pri: <6s} {ts.sched_mode: <10s} {ts.io_policy: <15s} '
365        '{ts.state: <8s} {ts.ast: <12s} {ts.waitq: <18s} {ts.wait_evt: <18s} '
366        '{ts.wait_evt_sym: <30s} {ts.wait_msg: <20s} {ts.name: <20s}')
367
368@lldb_type_summary(['thread *', 'thread_t'])
369@header(ThreadSummaryFormat.format(ts=ThreadSummaryNames))
370def GetThreadSummary(thread, O=None):
371    """ Summarize the thread structure.
372
373        params: thread: value - value object representing a thread in kernel
374        returns: str - summary of a thread
375
376        State flags:
377        W - Wait asserted
378        S - Suspended
379        R - Runnable
380        U - Uninterruptible
381        H - Terminated
382        A - Terminated (on queue)
383        I - Idle thread
384        C - Crashed thread
385        K - Waking
386
387        policy flags:
388        B - darwinbg
389        T - IO throttle
390        P - IO passive
391        D - Terminated
392    """
393    thread_ptr_str = '{:<#018x}'.format(thread)
394    thread_task_ptr_str = '{:<#018x}'.format(thread.t_tro.tro_task)
395
396    if int(thread.static_param):
397        thread_ptr_str += ' W'
398    thread_id = hex(thread.thread_id)
399    processor = hex(thread.last_processor)
400    base_priority = str(int(thread.base_pri))
401    sched_priority = str(int(thread.sched_pri))
402    sched_mode = ''
403    mode = str(thread.sched_mode)
404    if 'TIMESHARE' in mode:
405        sched_mode += 'TMSHR'
406    elif 'FIXED' in mode:
407        sched_mode += 'FIXED'
408    elif 'REALTIME' in mode:
409        sched_mode += 'RT'
410
411    if (unsigned(thread.bound_processor) != 0):
412        sched_mode += ' BIND'
413
414    TH_SFLAG_THROTTLED = 0x4
415    if (unsigned(thread.sched_flags) & TH_SFLAG_THROTTLED):
416        sched_mode += ' BG'
417
418    thread_name = GetThreadName(thread)
419    uthread = GetBSDThread(thread)
420
421    io_policy_str = ""
422    if int(uthread.uu_flag) & 0x400:
423        io_policy_str += 'RAGE '
424    if int(thread.effective_policy.thep_darwinbg) != 0:
425        io_policy_str += 'B'
426    if int(thread.effective_policy.thep_io_tier) != 0:
427        io_policy_str += 'T'
428    if int(thread.effective_policy.thep_io_passive) != 0:
429        io_policy_str += 'P'
430    if int(thread.effective_policy.thep_terminated) != 0:
431        io_policy_str += 'D'
432
433    state = int(thread.state)
434    thread_state_chars = {
435        0x0: '', 0x1: 'W', 0x2: 'S', 0x4: 'R', 0x8: 'U', 0x10: 'H', 0x20: 'A',
436        0x40: 'P', 0x80: 'I', 0x100: 'K'
437    }
438    state_str = ''
439    mask = 0x1
440    while mask <= 0x100:
441        state_str += thread_state_chars[int(state & mask)]
442        mask <<= 1
443
444    if int(thread.inspection):
445        state_str += 'C'
446
447    ast = int(thread.ast) | int(thread.reason)
448    ast_str = GetASTSummary(ast)
449
450    wait_queue_str = ''
451    wait_event_str = ''
452    wait_event_str_sym = ''
453    wait_message = ''
454    if (state & 0x1) != 0:
455        wait_queue_str = '{:<#018x}'.format(unsigned(thread.waitq.wq_q))
456        wait_event_str = '{:<#018x}'.format(unsigned(thread.wait_event))
457        wait_event_str_sym = kern.Symbolicate(int(hex(thread.wait_event), 16))
458        uthread = GetBSDThread(thread)
459        if int(uthread.uu_wmesg) != 0:
460            wait_message = str(Cast(uthread.uu_wmesg, 'char *'))
461
462    ts = ThreadSummary(
463            thread=thread_ptr_str, tid=thread_id,
464            task=thread_task_ptr_str, processor=processor,
465            base=base_priority, pri=sched_priority, sched_mode=sched_mode,
466            io_policy=io_policy_str, state=state_str, ast=ast_str,
467            waitq=wait_queue_str, wait_evt=wait_event_str,
468            wait_evt_sym=wait_event_str_sym, wait_msg=wait_message,
469            name=thread_name)
470    if O is not None:
471        return O.format(ThreadSummaryFormat, ts=ts)
472    else:
473        return ThreadSummaryFormat.format(ts=ts)
474
475
476def GetTaskRoleString(role):
477    role_strs = {
478                 0 : "TASK_UNSPECIFIED",
479                 1 : "TASK_FOREGROUND_APPLICATION",
480                 2 : "TASK_BACKGROUND_APPLICATION",
481                 3 : "TASK_CONTROL_APPLICATION",
482                 4 : "TASK_GRAPHICS_SERVER",
483                 5 : "TASK_THROTTLE_APPLICATION",
484                 6 : "TASK_NONUI_APPLICATION",
485                 7 : "TASK_DEFAULT_APPLICATION",
486                }
487    return role_strs[int(role)]
488
489def GetCoalitionFlagString(coal):
490    flags = []
491    if (coal.privileged):
492        flags.append('privileged')
493    if (coal.termrequested):
494        flags.append('termrequested')
495    if (coal.terminated):
496        flags.append('terminated')
497    if (coal.reaped):
498        flags.append('reaped')
499    if (coal.notified):
500        flags.append('notified')
501    if (coal.efficient):
502        flags.append('efficient')
503    return "|".join(flags)
504
505def GetCoalitionTasks(queue, coal_type, thread_details=False):
506    sfi_strs = {
507                 0x0  : "SFI_CLASS_UNSPECIFIED",
508                 0x1  : "SFI_CLASS_DARWIN_BG",
509                 0x2  : "SFI_CLASS_APP_NAP",
510                 0x3  : "SFI_CLASS_MANAGED_FOCAL",
511                 0x4  : "SFI_CLASS_MANAGED_NONFOCAL",
512                 0x5  : "SFI_CLASS_DEFAULT_FOCAL",
513                 0x6  : "SFI_CLASS_DEFAULT_NONFOCAL",
514                 0x7  : "SFI_CLASS_KERNEL",
515                 0x8  : "SFI_CLASS_OPTED_OUT",
516                 0x9  : "SFI_CLASS_UTILITY",
517                 0xA  : "SFI_CLASS_LEGACY_FOCAL",
518                 0xB  : "SFI_CLASS_LEGACY_NONFOCAL",
519                 0xC  : "SFI_CLASS_USER_INITIATED_FOCAL",
520                 0xD  : "SFI_CLASS_USER_INITIATED_NONFOCAL",
521                 0xE  : "SFI_CLASS_USER_INTERACTIVE_FOCAL",
522                 0xF  : "SFI_CLASS_USER_INTERACTIVE_NONFOCAL",
523                 0x10 : "SFI_CLASS_MAINTENANCE",
524                }
525    tasks = []
526    field_path = '.task_coalition[{}]'.format(coal_type)
527    for task in IterateLinkageChain(queue, 'task *', field_path):
528        task_str = "({0: <d},{1: #x}, {2: <s}, {3: <s})".format(GetProcPIDForTask(task),task,GetProcNameForTask(task),GetTaskRoleString(task.effective_policy.tep_role))
529        if thread_details:
530            for thread in IterateQueue(task.threads, "thread_t", "task_threads"):
531                task_str += "\n\t\t\t|-> thread:" + hex(thread) + ", " + sfi_strs[int(thread.sfi_class)]
532        tasks.append(task_str)
533    return tasks
534
535def GetCoalitionTypeString(type):
536    """ Convert a coalition type field into a string
537    Currently supported types (from <mach/coalition.h>):
538        COALITION_TYPE_RESOURCE
539        COALITION_TYPE_JETSAM
540    """
541    if type == 0: # COALITION_TYPE_RESOURCE
542        return 'RESOURCE'
543    if type == 1:
544        return 'JETSAM'
545    return '<unknown>'
546
547def GetResourceCoalitionSummary(coal, verbose=False):
548    """ Summarize a resource coalition
549    """
550    out_string = "Resource Coalition:\n\t  Ledger:\n"
551    thread_details = False
552    if config['verbosity'] > vSCRIPT:
553        thread_details = True
554    ledgerp = coal.r.ledger
555    if verbose and unsigned(ledgerp) != 0:
556        i = 0
557        while i != ledgerp.l_template.lt_cnt:
558            out_string += "\t\t"
559            out_string += GetLedgerEntrySummary(kern.globals.task_ledger_template, ledgerp, i)
560            i = i + 1
561    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)
562    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)
563    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)
564    if verbose:
565        out_string += "\n\t  cpu_time_effective[THREAD_QOS_DEFAULT] {0: <d}".format(coal.r.cpu_time_eqos[0])
566        out_string += "\n\t  cpu_time_effective[THREAD_QOS_MAINTENANCE] {0: <d}".format(coal.r.cpu_time_eqos[1])
567        out_string += "\n\t  cpu_time_effective[THREAD_QOS_BACKGROUND] {0: <d}".format(coal.r.cpu_time_eqos[2])
568        out_string += "\n\t  cpu_time_effective[THREAD_QOS_UTILITY] {0: <d}".format(coal.r.cpu_time_eqos[3])
569        out_string += "\n\t  cpu_time_effective[THREAD_QOS_LEGACY] {0: <d}".format(coal.r.cpu_time_eqos[4])
570        out_string += "\n\t  cpu_time_effective[THREAD_QOS_USER_INITIATED] {0: <d}".format(coal.r.cpu_time_eqos[5])
571        out_string += "\n\t  cpu_time_effective[THREAD_QOS_USER_INTERACTIVE] {0: <d}".format(coal.r.cpu_time_eqos[6])
572    out_string += "\n\t  Tasks:\n\t\t"
573    tasks = GetCoalitionTasks(addressof(coal.r.tasks), 0, thread_details)
574    out_string += "\n\t\t".join(tasks)
575    return out_string
576
577def GetJetsamCoalitionSummary(coal, verbose=False):
578    out_string = "Jetsam Coalition:"
579    thread_details = False
580    if config['verbosity'] > vSCRIPT:
581        thread_details = True
582    if unsigned(coal.j.leader) == 0:
583        out_string += "\n\t  NO Leader!"
584    else:
585        out_string += "\n\t  Leader:\n\t\t"
586        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))
587    out_string += "\n\t  Extensions:\n\t\t"
588    tasks = GetCoalitionTasks(addressof(coal.j.extensions), 1, thread_details)
589    out_string += "\n\t\t".join(tasks)
590    out_string += "\n\t  XPC Services:\n\t\t"
591    tasks = GetCoalitionTasks(addressof(coal.j.services), 1, thread_details)
592    out_string += "\n\t\t".join(tasks)
593    out_string += "\n\t  Other Tasks:\n\t\t"
594    tasks = GetCoalitionTasks(addressof(coal.j.other), 1, thread_details)
595    out_string += "\n\t\t".join(tasks)
596    out_string += "\n\t  Thread Group: {0: <#020x}\n".format(coal.j.thread_group)
597    return out_string
598
599@lldb_type_summary(['coalition_t', 'coalition *'])
600@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"))
601def GetCoalitionSummary(coal):
602    if unsigned(coal) == 0:
603        return '{0: <#020x} {1: <15s} {2: <10d} {3: <10d} {4: <10d} {5: <12d} {6: <12d} {7: <s}'.format(0, "", -1, -1, -1, -1, -1, "")
604    out_string = ""
605    format_string = '{0: <#020x} {1: <15s} {2: <10d} {3: <10d} {4: <10d} {5: <12d} {6: <12d} {7: <s}'
606    type_string = GetCoalitionTypeString(coal.type)
607    flag_string = GetCoalitionFlagString(coal)
608    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)
609    return out_string
610
611def GetCoalitionInfo(coal, verbose=False):
612    """ returns a string describing a coalition, including details about the particular coalition type.
613        params:
614            coal : value object representing a coalition in the kernel
615        returns:
616            str : A string describing the coalition.
617    """
618    if unsigned(coal) == 0:
619        return "<null coalition>"
620    typestr = GetCoalitionTypeString(coal.type)
621    flagstr = GetCoalitionFlagString(coal)
622    out_string = ""
623    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)
624    if coal.type == 0: # COALITION_TYPE_RESOURCE
625        out_string += GetResourceCoalitionSummary(coal, verbose)
626    elif coal.type == 1: # COALITION_TYPE_JETSAM
627        out_string += GetJetsamCoalitionSummary(coal, verbose)
628    else:
629        out_string += "Unknown Type"
630
631    return out_string
632
633# Macro: showcoalitioninfo
634
635@lldb_command('showcoalitioninfo')
636def ShowCoalitionInfo(cmd_args=None, cmd_options={}):
637    """  Display more detailed information about a coalition
638         Usage: showcoalitioninfo <address of coalition>
639    """
640    verbose = False
641    if config['verbosity'] > vHUMAN:
642        verbose = True
643    if not cmd_args:
644        raise ArgumentError("No arguments passed")
645    coal = kern.GetValueFromAddress(cmd_args[0], 'coalition *')
646    if not coal:
647        print("unknown arguments:", str(cmd_args))
648        return False
649    print(GetCoalitionInfo(coal, verbose))
650
651# EndMacro: showcoalitioninfo
652
653# Macro: showallcoalitions
654
655@lldb_command('showallcoalitions')
656def ShowAllCoalitions(cmd_args=None):
657    """  Print a summary listing of all the coalitions
658    """
659    global kern
660    print(GetCoalitionSummary.header)
661    for c in kern.coalitions:
662        print(GetCoalitionSummary(c))
663
664# EndMacro: showallcoalitions
665
666# Macro: showallthreadgroups
667
668@lldb_type_summary(['struct thread_group *', 'thread_group *'])
669@header("{0: <20s} {1: <5s} {2: <16s} {3: <5s} {4: <8s} {5: <20s}".format("thread_group", "id", "name", "refc", "flags", "recommendation"))
670def GetThreadGroupSummary(tg):
671    if unsigned(tg) == 0:
672        return '{0: <#020x} {1: <5d} {2: <16s} {3: <5d} {4: <8s} {5: <20d}'.format(0, -1, "", -1, "", -1)
673    out_string = ""
674    format_string = '{0: <#020x} {1: <5d} {2: <16s} {3: <5d} {4: <8s} {5: <20d}'
675    tg_flags = ''
676    if (tg.tg_flags & 0x1):
677        tg_flags += 'E'
678    if (tg.tg_flags & 0x2):
679        tg_flags += 'A'
680    if (tg.tg_flags & 0x4):
681        tg_flags += 'C'
682    if (tg.tg_flags & 0x100):
683        tg_flags += 'U'
684    out_string += format_string.format(tg, tg.tg_id, tg.tg_name, tg.tg_refcount.ref_count, tg_flags, tg.tg_recommendation)
685    return out_string
686
687@lldb_command('showallthreadgroups')
688def ShowAllThreadGroups(cmd_args=None):
689    """  Print a summary listing of all thread groups
690    """
691    global kern
692    print(GetThreadGroupSummary.header)
693    for tg in kern.thread_groups:
694        print(GetThreadGroupSummary(tg))
695
696# EndMacro: showallthreadgroups
697
698# Macro: showtaskcoalitions
699
700@lldb_command('showtaskcoalitions', 'F:')
701def ShowTaskCoalitions(cmd_args=None, cmd_options={}):
702    """
703    """
704    task_list = []
705    if "-F" in cmd_options:
706        task_list = FindTasksByName(cmd_options["-F"])
707    elif cmd_args:
708        t = kern.GetValueFromAddress(cmd_args[0], 'task *')
709        task_list.append(t)
710    else:
711        raise ArgumentError("No arguments passed")
712
713    if len(task_list) > 0:
714        print(GetCoalitionSummary.header)
715    for task in task_list:
716        print(GetCoalitionSummary(task.coalition[0]))
717        print(GetCoalitionSummary(task.coalition[1]))
718
719# EndMacro: showtaskcoalitions
720
721@lldb_type_summary(['proc', 'proc *'])
722@header("{0: >6s}   {1: <18s} {2: >11s} {3: ^10s} {4: <32s}".format("pid", "process", "io_policy", "wq_state", "command"))
723def GetProcSummary(proc):
724    """ Summarize the process data.
725        params:
726          proc : value - value representaitng a proc * in kernel
727        returns:
728          str - string summary of the process.
729    """
730    if not proc:
731        return "Process is not valid."
732
733    out_string = ""
734    format_string= "{0: >6d}   {1: <#018x} {2: >11s} {3: >2d} {4: >2d} {5: >2d}   {6: <32s}"
735    pval = proc.GetSBValue()
736    #code.interact(local=locals())
737    if str(pval.GetType()) != str(gettype('proc *')) :
738        return "Unknown type " + str(pval.GetType()) + " " + str(hex(proc))
739    pid = int(GetProcPID(proc))
740    proc_addr = int(hex(proc), 16)
741    proc_rage_str = ""
742    if int(proc.p_lflag) & 0x400000 :
743        proc_rage_str = "RAGE"
744
745    task = GetTaskFromProc(proc)
746
747    io_policy_str = ""
748
749    if int(task.effective_policy.tep_darwinbg) != 0:
750        io_policy_str += "B"
751    if int(task.effective_policy.tep_lowpri_cpu) != 0:
752        io_policy_str += "L"
753
754    if int(task.effective_policy.tep_io_tier) != 0:
755        io_policy_str += "T"
756    if int(task.effective_policy.tep_io_passive) != 0:
757        io_policy_str += "P"
758    if int(task.effective_policy.tep_terminated) != 0:
759        io_policy_str += "D"
760
761    if int(task.effective_policy.tep_latency_qos) != 0:
762        io_policy_str += "Q"
763    if int(task.effective_policy.tep_sup_active) != 0:
764        io_policy_str += "A"
765
766    if int(proc.p_refcount) & GetEnumValue("proc_ref_bits_t::P_REF_SHADOW") :
767        io_policy_str += "S"
768
769
770    try:
771        work_queue = proc.p_wqptr
772        if proc.p_wqptr != 0 :
773            wq_num_threads = int(work_queue.wq_nthreads)
774            wq_idle_threads = int(work_queue.wq_thidlecount)
775            wq_req_threads = int(work_queue.wq_reqcount)
776        else:
777            wq_num_threads = 0
778            wq_idle_threads = 0
779            wq_req_threads = 0
780    except:
781        wq_num_threads = -1
782        wq_idle_threads = -1
783        wq_req_threads = -1
784    process_name = GetProcName(proc)
785    if process_name == 'xpcproxy':
786        for thread in IterateQueue(task.threads, 'thread *', 'task_threads'):
787            thread_name = GetThreadName(thread)
788            if thread_name:
789                process_name += ' (' + thread_name + ')'
790                break
791    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)
792    return out_string
793
794@lldb_type_summary(['tty_dev_t', 'tty_dev_t *'])
795@header("{0: <20s} {1: <10s} {2: <10s} {3: <15s} {4: <15s} {5: <15s} {6: <15s}".format("tty_dev","primary", "replica", "open", "free", "name", "revoke"))
796def GetTTYDevSummary(tty_dev):
797    """ Summarizes the important fields in tty_dev_t structure.
798        params: tty_dev: value - value object representing a tty_dev_t in kernel
799        returns: str - summary of the tty_dev
800    """
801    out_string = ""
802    format_string = "{0: <#020x} {1: <#010x} {2: <#010x} {3: <15s} {4: <15s} {5: <15s} {6: <15s}"
803    open_fn = kern.Symbolicate(int(hex(tty_dev.open), 16))
804    free_fn = kern.Symbolicate(int(hex(tty_dev.free), 16))
805    name_fn = kern.Symbolicate(int(hex(tty_dev.name), 16))
806    revoke_fn = kern.Symbolicate(int(hex(tty_dev.revoke), 16))
807    out_string += format_string.format(tty_dev, tty_dev.primary, tty_dev.replica, open_fn, free_fn, name_fn, revoke_fn)
808    return out_string
809
810# Macro: showtask
811
812@lldb_command('showtask', 'F:')
813def ShowTask(cmd_args=None, cmd_options={}):
814    """  Routine to print a summary listing of given task
815         Usage: showtask <address of task>
816         or   : showtask -F <name of task>
817    """
818    task_list = []
819    if "-F" in cmd_options:
820        task_list = FindTasksByName(cmd_options['-F'])
821    else:
822        if not cmd_args:
823            raise ArgumentError("Invalid arguments passed.")
824
825        tval = kern.GetValueFromAddress(cmd_args[0], 'task *')
826        if not tval:
827            raise ArgumentError("Unknown arguments: {:s}".format(cmd_args[0]))
828        task_list.append(tval)
829
830    for tval in task_list:
831        print(GetTaskSummary.header + " " + GetProcSummary.header)
832        pval = GetProcFromTask(tval)
833        print(GetTaskSummary(tval) +" "+ GetProcSummary(pval))
834
835# EndMacro: showtask
836
837# Macro: showpid
838
839@lldb_command('showpid')
840def ShowPid(cmd_args=None):
841    """  Routine to print a summary listing of task corresponding to given pid
842         Usage: showpid <pid value>
843    """
844    if not cmd_args:
845        raise ArgumentError("No arguments passed")
846    pidval = ArgumentStringToInt(cmd_args[0])
847    for t in kern.tasks:
848        pval = GetProcFromTask(t)
849        if pval and GetProcPID(pval) == pidval:
850            print(GetTaskSummary.header + " " + GetProcSummary.header)
851            print(GetTaskSummary(t) + " " + GetProcSummary(pval))
852            break
853
854# EndMacro: showpid
855
856# Macro: showproc
857
858@lldb_command('showproc')
859def ShowProc(cmd_args=None):
860    """  Routine to print a summary listing of task corresponding to given proc
861         Usage: showproc <address of proc>
862    """
863    if not cmd_args:
864        raise ArgumentError("No arguments passed")
865    pval = kern.GetValueFromAddress(cmd_args[0], 'proc *')
866    if not pval:
867        print("unknown arguments:", str(cmd_args))
868        return False
869    print(GetTaskSummary.header + " " + GetProcSummary.header)
870    tval = GetTaskFromProc(pval)
871    print(GetTaskSummary(tval) + " " + GetProcSummary(pval))
872
873# EndMacro: showproc
874
875# Macro: showprocinfo
876
877@lldb_command('showprocinfo')
878def ShowProcInfo(cmd_args=None):
879    """  Routine to display name, pid, parent & task for the given proc address
880         It also shows the Cred, Flags and state of the process
881         Usage: showprocinfo <address of proc>
882    """
883    if not cmd_args:
884        raise ArgumentError("No arguments passed")
885    pval = kern.GetValueFromAddress(cmd_args[0], 'proc *')
886    if not pval:
887        print("unknown arguments:", str(cmd_args))
888        return False
889    print(GetProcInfo(pval))
890
891# EndMacro: showprocinfo
892
893#Macro: showprocfiles
894
895@lldb_command('showprocfiles')
896def ShowProcFiles(cmd_args=None):
897    """ Given a proc_t pointer, display the list of open file descriptors for the referenced process.
898        Usage: showprocfiles <proc_t>
899    """
900    if not cmd_args:
901        print(ShowProcFiles.__doc__)
902        return
903    proc = kern.GetValueFromAddress(cmd_args[0], 'proc_t')
904    proc_filedesc = addressof(proc.p_fd)
905    proc_ofiles = proc_filedesc.fd_ofiles
906    if unsigned(proc_ofiles) == 0:
907        print('No open files for proc {0: <s}'.format(cmd_args[0]))
908        return
909    print("{0: <5s} {1: <18s} {2: <10s} {3: <8s} {4: <18s} {5: <64s}".format('FD', 'FILEGLOB', 'FG_FLAGS', 'FG_TYPE', 'FG_DATA','INFO'))
910    print("{0:-<5s} {0:-<18s} {0:-<10s} {0:-<8s} {0:-<18s} {0:-<64s}".format(""))
911
912    for fd in range(0, unsigned(proc_filedesc.fd_afterlast)):
913        if unsigned(proc_ofiles[fd]) != 0:
914            out_str = ''
915            proc_fd_flags = proc_ofiles[fd].fp_flags
916            proc_fd_fglob = proc_ofiles[fd].fp_glob
917            proc_fd_fglob_fg_data = Cast(proc_fd_fglob.fg_data, 'void *')
918            out_str += "{0: <5d} ".format(fd)
919            out_str += "{0: <#18x} ".format(unsigned(proc_fd_fglob))
920            out_str += "0x{0:0>8x} ".format(unsigned(proc_fd_flags))
921            proc_fd_ftype = unsigned(proc_fd_fglob.fg_ops.fo_type)
922            if proc_fd_ftype in xnudefines.filetype_strings:
923                out_str += "{0: <8s} ".format(xnudefines.filetype_strings[proc_fd_ftype])
924            else:
925                out_str += "?: {0: <5d} ".format(proc_fd_ftype)
926            out_str += "{0: <#18x} ".format(unsigned(proc_fd_fglob_fg_data))
927            if proc_fd_ftype == 1:
928                fd_name = Cast(proc_fd_fglob_fg_data, 'struct vnode *').v_name
929                out_str += "{0: <64s}".format(fd_name)
930            out_str += "\n"
931            print(out_str)
932
933#EndMacro: showprocfiles
934
935#Macro: showtty
936
937@lldb_command('showtty')
938def ShowTTY(cmd_args=None):
939    """ Display information about a struct tty
940        Usage: showtty <tty struct>
941    """
942    if not cmd_args:
943        print(ShowTTY.__doc__)
944        return
945
946    tty = kern.GetValueFromAddress(cmd_args[0], 'struct tty *')
947    print("TTY structure at:              {0: <s}".format(cmd_args[0]))
948    print("Last input to raw queue:       {0: <#18x} \"{1: <s}\"".format(unsigned(tty.t_rawq.c_cs), tty.t_rawq.c_cs))
949    print("Last input to canonical queue: {0: <#18x} \"{1: <s}\"".format(unsigned(tty.t_canq.c_cs), tty.t_canq.c_cs))
950    print("Last output data:              {0: <#18x} \"{1: <s}\"".format(unsigned(tty.t_outq.c_cs), tty.t_outq.c_cs))
951    tty_state_info = [
952                  ['', 'TS_SO_OLOWAT (Wake up when output <= low water)'],
953                  ['- (synchronous I/O mode)', 'TS_ASYNC (async I/O mode)'],
954                  ['', 'TS_BUSY (Draining output)'],
955                  ['- (Carrier is NOT present)', 'TS_CARR_ON (Carrier is present)'],
956                  ['', 'TS_FLUSH (Outq has been flushed during DMA)'],
957                  ['- (Open has NOT completed)', 'TS_ISOPEN (Open has completed)'],
958                  ['', 'TS_TBLOCK (Further input blocked)'],
959                  ['', 'TS_TIMEOUT (Wait for output char processing)'],
960                  ['', 'TS_TTSTOP (Output paused)'],
961                  ['', 'TS_WOPEN (Open in progress)'],
962                  ['', 'TS_XCLUDE (Tty requires exclusivity)'],
963                  ['', 'TS_BKSL (State for lowercase \\ work)'],
964                  ['', 'TS_CNTTB (Counting tab width, ignore FLUSHO)'],
965                  ['', 'TS_ERASE (Within a \\.../ for PRTRUB)'],
966                  ['', 'TS_LNCH (Next character is literal)'],
967                  ['', 'TS_TYPEN (Retyping suspended input (PENDIN))'],
968                  ['', 'TS_CAN_BYPASS_L_RINT (Device in "raw" mode)'],
969                  ['- (Connection NOT open)', 'TS_CONNECTED (Connection open)'],
970                  ['', 'TS_SNOOP (Device is being snooped on)'],
971                  ['', 'TS_SO_OCOMPLETE (Wake up when output completes)'],
972                  ['', 'TS_ZOMBIE (Connection lost)'],
973                  ['', 'TS_CAR_OFLOW (For MDMBUF - handle in driver)'],
974                  ['', 'TS_CTS_OFLOW (For CCTS_OFLOW - handle in driver)'],
975                  ['', 'TS_DSR_OFLOW (For CDSR_OFLOW - handle in driver)']
976                ]
977    index = 0
978    mask = 0x1
979    tty_state = unsigned(tty.t_state)
980    print("State:")
981    while index < 24:
982        if tty_state & mask != 0:
983            if len(tty_state_info[index][1]) > 0:
984                print('\t' + tty_state_info[index][1])
985        else:
986            if len(tty_state_info[index][0]) > 0:
987                print('\t' + tty_state_info[index][0])
988        index += 1
989        mask = mask << 1
990    print("Flags:                    0x{0:0>8x}".format(unsigned(tty.t_flags)))
991    print("Foreground Process Group: 0x{0:0>16x}".format(unsigned(tty.t_pgrp)))
992    print("Enclosing session:        0x{0:0>16x}".format(unsigned(tty.t_session)))
993    print("Termios:")
994    print("\tInput Flags:   0x{0:0>8x}".format(unsigned(tty.t_termios.c_iflag)))
995    print("\tOutput Flags:  0x{0:0>8x}".format(unsigned(tty.t_termios.c_oflag)))
996    print("\tControl Flags: 0x{0:0>8x}".format(unsigned(tty.t_termios.c_cflag)))
997    print("\tLocal Flags:   0x{0:0>8x}".format(unsigned(tty.t_termios.c_lflag)))
998    print("\tInput Speed:   {0: <8d}".format(tty.t_termios.c_ispeed))
999    print("\tOutput Speed:  {0: <8d}".format(tty.t_termios.c_ospeed))
1000    print("High Watermark: {0: <d} bytes".format(tty.t_hiwat))
1001    print("Low Watermark : {0: <d} bytes".format(tty.t_lowat))
1002
1003#EndMacro: showtty
1004
1005#Macro showallttydevs
1006
1007@lldb_command('showallttydevs')
1008def ShowAllTTYDevs(cmd_args=[], cmd_options={}):
1009    """ Show a list of ttydevs registered in the system.
1010        Usage:
1011        (lldb)showallttydevs
1012    """
1013    tty_dev_head = kern.globals.tty_dev_head
1014    tty_dev = tty_dev_head
1015    print(GetTTYDevSummary.header)
1016    while unsigned(tty_dev) != 0:
1017        print(GetTTYDevSummary(tty_dev))
1018        tty_dev = tty_dev.next
1019    return ""
1020
1021#EndMacro: showallttydevs
1022
1023#Macro: dumpthread_terminate_queue
1024
1025@lldb_command('dumpthread_terminate_queue', fancy=True)
1026def DumpThreadTerminateQueue(cmd_args=None, cmd_options={}, O=None):
1027    """ Displays the contents of the specified call_entry queue.
1028        Usage: dumpthread_terminate_queue
1029    """
1030
1031    count = 0
1032    with O.table(GetThreadSummary.header):
1033        for th in IterateMPSCQueue(addressof(kern.globals.thread_terminate_queue.mpd_queue), 'struct thread', 'mpsc_links'):
1034            print(GetThreadSummary(th, O=O))
1035            count += 1
1036    print("{0: <d} entries!".format(count))
1037
1038#EndMacro: dumpthread_terminate_queue
1039
1040#Macro: dumpcrashed_thread_queue
1041
1042@lldb_command('dumpcrashed_thread_queue', fancy=True)
1043def DumpCrashedThreadsQueue(cmd_args=None, cmd_options={}, O=None):
1044    """ Displays the contents of the specified call_entry queue.
1045        Usage: dumpcrashed_thread_queue
1046    """
1047
1048    count = 0
1049    with O.table(GetThreadSummary.header):
1050        for th in IterateQueue(addressof(kern.globals.crashed_threads_queue), 'struct thread *',  'q_link'):
1051            print(GetThreadSummary(th), O=O)
1052            count += 1
1053    print("{0: <d} entries!".format(count))
1054
1055#EndMacro: dumpcrashed_thread_queue
1056
1057#Macro: dumpcallqueue
1058
1059@lldb_command('dumpcallqueue')
1060def DumpCallQueue(cmd_args=None):
1061    """ Displays the contents of the specified call_entry queue.
1062        Usage: dumpcallqueue <queue_head_t *>
1063    """
1064    if not cmd_args:
1065        raise ArgumentError("Invalid arguments")
1066
1067    print("{0: <18s} {1: <18s} {2: <18s} {3: <64s} {4: <18s}".format('CALL_ENTRY', 'PARAM0', 'PARAM1', 'DEADLINE', 'FUNC'))
1068    callhead = kern.GetValueFromAddress(cmd_args[0], 'queue_head_t *')
1069    count = 0
1070    for callentry in IterateQueue(callhead, 'struct call_entry *',  'q_link'):
1071        print("{0: <#18x} {1: <#18x} {2: <#18x} {3: <64d} {4: <#18x}".format(
1072              unsigned(callentry), unsigned(callentry.param0), unsigned(callentry.param1),
1073              unsigned(callentry.deadline), unsigned(callentry.func)))
1074        count += 1
1075    print("{0: <d} entries!".format(count))
1076
1077#EndMacro: dumpcallqueue
1078
1079@lldb_command('showalltasklogicalwrites')
1080def ShowAllTaskIOStats(cmd_args=None):
1081    """ Commad to print I/O stats for all tasks
1082    """
1083    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"))
1084    for t in kern.tasks:
1085        pval = GetProcFromTask(t)
1086        print("{0: <#18x} {1: >20d} {2: >20d} {3: >20d} {4: >20d}  {5: <20s} {6: <20s} {7: <20s} {8: <20s} {9: <20s}".format(t,
1087            t.task_writes_counters_internal.task_immediate_writes,
1088            t.task_writes_counters_internal.task_deferred_writes,
1089            t.task_writes_counters_internal.task_invalidated_writes,
1090            t.task_writes_counters_internal.task_metadata_writes,
1091            t.task_writes_counters_external.task_immediate_writes,
1092            t.task_writes_counters_external.task_deferred_writes,
1093            t.task_writes_counters_external.task_invalidated_writes,
1094            t.task_writes_counters_external.task_metadata_writes,
1095            GetProcName(pval)))
1096
1097
1098@lldb_command('showalltasks','C', fancy=True)
1099def ShowAllTasks(cmd_args=None, cmd_options={}, O=None):
1100    """  Routine to print a summary listing of all the tasks
1101         wq_state -> reports "number of workq threads", "number of scheduled workq threads", "number of pending work items"
1102         if "number of pending work items" seems stuck at non-zero, it may indicate that the workqueue mechanism is hung
1103         io_policy -> RAGE  - rapid aging of vnodes requested
1104                     NORM  - normal I/O explicitly requested (this is the default)
1105                     PASS  - passive I/O requested (i.e. I/Os do not affect throttling decisions)
1106                     THROT - throttled I/O requested (i.e. thread/task may be throttled after each I/O completes)
1107         Usage: (lldb) showalltasks -C  : describe the corpse structure
1108    """
1109    global kern
1110    extra_hdr = ''
1111    showcorpse = False
1112    if '-C' in cmd_options:
1113        showcorpse = True
1114        extra_hdr += " " + GetKCDataSummary.header
1115
1116    with O.table(GetTaskSummary.header + extra_hdr + " " + GetProcSummary.header):
1117        for t in kern.tasks:
1118            pval = GetProcFromTask(t)
1119            print(GetTaskSummary(t, showcorpse) + " " + GetProcSummary(pval))
1120
1121    ZombTasks()
1122
1123def TaskForPmapHelper(pmap):
1124    """ Given a pmap pointer, return the task pointer which contains that
1125        address space.
1126
1127        pmap: PMAP pointer whose task to find.
1128    """
1129    for tasklist in [kern.tasks, kern.terminated_tasks]:
1130        for task in tasklist:
1131            if kern.GetValueFromAddress(unsigned(task.map.pmap), 'pmap_t') == pmap:
1132                return task
1133
1134    return None
1135
1136@lldb_command('taskforpmap')
1137def TaskForPmap(cmd_args=None):
1138    """ Find the task whose pmap corresponds to <pmap>.
1139        Syntax: (lldb) taskforpmap <pmap>
1140            Multiple -v's can be specified for increased verbosity
1141    """
1142    if cmd_args is None or len(cmd_args) < 1:
1143        raise ArgumentError("Too few arguments to taskforpmap.")
1144    pmap = kern.GetValueFromAddress(cmd_args[0], 'pmap_t')
1145    task = TaskForPmapHelper(pmap)
1146
1147    if task is None:
1148        print("Couldn't find task for pmap {:#x}".format(pmap))
1149        return
1150
1151    print(GetTaskSummary.header + " " + GetProcSummary.header)
1152    pval = GetProcFromTask(task)
1153    print(GetTaskSummary(task) + " " + GetProcSummary(pval))
1154
1155@lldb_command('showterminatedtasks')
1156def ShowTerminatedTasks(cmd_args=None):
1157    """  Routine to print a summary listing of all the terminated tasks
1158         wq_state -> reports "number of workq threads", "number of scheduled workq threads", "number of pending work items"
1159         if "number of pending work items" seems stuck at non-zero, it may indicate that the workqueue mechanism is hung
1160         io_policy -> RAGE  - rapid aging of vnodes requested
1161                     NORM  - normal I/O explicitly requested (this is the default)
1162                     PASS  - passive I/O requested (i.e. I/Os do not affect throttling decisions)
1163                     THROT - throttled I/O requested (i.e. thread/task may be throttled after each I/O completes)
1164        syntax: (lldb)showallterminatedtasks
1165    """
1166    global kern
1167    print(GetTaskSummary.header + " " + GetProcSummary.header)
1168    for t in kern.terminated_tasks:
1169
1170        # If the task has been terminated it's likely that the process is
1171        # gone too. If there is no proc it may still be possible to find
1172        # the original proc name.
1173        pval = GetProcFromTask(t)
1174        if pval:
1175            psummary = GetProcSummary(pval)
1176        else:
1177            name = GetProcNameForTask(t);
1178            pslen = GetProcSummary.header.find("command");
1179            psummary = "{0: <{indent}} {1: <s}".format("", name, indent = pslen - 1)
1180
1181        print(GetTaskSummary(t) + " " + psummary)
1182
1183    return True
1184
1185# Macro: showtaskstacks
1186
1187def ShowTaskStacks(task, O=None):
1188    """ Print a task with summary and stack information for each of its threads
1189    """
1190    global kern
1191    print(GetTaskSummary.header + " " + GetProcSummary.header)
1192    pval = GetProcFromTask(task)
1193    print(GetTaskSummary(task) + " " + GetProcSummary(pval))
1194    for th in IterateQueue(task.threads, 'thread *', 'task_threads'):
1195        with O.table(GetThreadSummary.header, indent=True):
1196            print(GetThreadSummary(th, O=O))
1197            print(GetThreadBackTrace(th, prefix="    ") + "\n")
1198
1199def FindTasksByName(searchstr, ignore_case=True):
1200    """ Search the list of tasks by name.
1201        params:
1202            searchstr: str - a regex like string to search for task
1203            ignore_case: bool - If False then exact matching will be enforced
1204        returns:
1205            [] - array of task object. Empty if not found any
1206    """
1207    re_options = 0
1208    if ignore_case:
1209        re_options = re.IGNORECASE
1210    search_regex = re.compile(searchstr, re_options)
1211    retval = []
1212    for t in kern.tasks:
1213        pval = GetProcFromTask(t)
1214        process_name = "{:s}".format(GetProcName(pval))
1215        if search_regex.search(process_name):
1216            retval.append(t)
1217    return retval
1218
1219@lldb_command('showtaskstacks', 'F:', fancy=True)
1220def ShowTaskStacksCmdHelper(cmd_args=None, cmd_options={}, O=None):
1221    """ Routine to print out the stack for each thread in a task
1222        Usage: showtaskstacks <0xaddress of task>
1223           or: showtaskstacks -F launchd
1224    """
1225
1226    if "-F" in cmd_options:
1227        find_task_str = cmd_options["-F"]
1228        task_list = FindTasksByName(find_task_str)
1229        for tval in task_list:
1230            ShowTaskStacks(tval, O=O)
1231        return
1232
1233    if not cmd_args:
1234        raise ArgumentError("No arguments passed")
1235
1236    tval = kern.GetValueFromAddress(cmd_args[0], 'task *')
1237    if not tval:
1238        raise ArgumentError("unknown arguments: {:s}".format(str(cmd_args)))
1239    else:
1240        ShowTaskStacks(tval, O=O)
1241
1242# EndMacro: showtaskstacks
1243
1244def CheckTaskProcRefs(task, proc, O=None):
1245    btlib = kmemory.BTLibrary.get_shared()
1246
1247    for thread in IterateQueue(task.threads, 'thread *', 'task_threads'):
1248        uthread = GetBSDThread(thread)
1249        refcount = int(uthread.uu_proc_refcount)
1250        uu_ref_info = uthread.uu_proc_ref_info
1251        if int(uu_ref_info) == 0:
1252            continue
1253        uu_ref_index = int(uu_ref_info.upri_pindex)
1254        if refcount == 0:
1255            continue
1256        for ref in range(0, uu_ref_index):
1257            if unsigned(uu_ref_info.upri_proc_ps[ref]) == unsigned(proc):
1258                print(GetTaskSummary.header + " " + GetProcSummary.header)
1259                pval = GetProcFromTask(task)
1260                print(GetTaskSummary(task) + " " + GetProcSummary(pval))
1261                with O.table(GetThreadSummary.header, indent=True):
1262                    print(GetThreadSummary(thread, O=O))
1263
1264                bts = btlib.get_stack(unsigned(uu_ref_info.upri_proc_stacks[ref]))
1265                print(*bts.symbolicated_frames(), sep="\n")
1266
1267@lldb_command('showprocrefs', fancy=True)
1268def ShowProcRefs(cmd_args=None, cmd_options={}, O=None):
1269    """ Display information on threads/BTs that could be holding a reference on the specified proc
1270        NOTE: We can't say affirmatively if any of these references are still held since
1271              there's no way to pair references with drop-refs in the current infrastructure.
1272        Usage: showprocrefs <proc>
1273    """
1274    if cmd_args is None or len(cmd_args) < 1:
1275         raise ArgumentError("No arguments passed")
1276
1277    proc = kern.GetValueFromAddress(cmd_args[0], 'proc *')
1278
1279    for t in kern.tasks:
1280        CheckTaskProcRefs(t, proc, O=O)
1281    for t in kern.terminated_tasks:
1282        CheckTaskProcRefs(t, proc, O=O)
1283
1284@lldb_command('showallthreads', fancy=True)
1285def ShowAllThreads(cmd_args=None, cmd_options={}, O=None):
1286    """ Display info about all threads in the system
1287    """
1288
1289    # Terminated threads get prefixed with a 'T'
1290    def ShowTaskTerminatedThreads(task, O=O):
1291        tlist = tmap.get(unsigned(task), [])
1292        for thval in tlist:
1293            print("T\t" + GetThreadSummary(thval, O=O))
1294
1295    # Task -> [thread, ..] map of terminated threads
1296    tmap = defaultdict(list)
1297    for thr in kern.terminated_threads:
1298        tmap[unsigned(thr.t_tro.tro_task)].append(thr)
1299
1300    for t in kern.tasks:
1301        ShowTaskThreads([str(int(t))], O=O)
1302        ShowTaskTerminatedThreads(t, O=O)
1303        print(" \n")
1304
1305    for t in kern.terminated_tasks:
1306        print("Terminated: \n")
1307        ShowTaskThreads([str(int(t))], O=O)
1308        ShowTaskTerminatedThreads(t, O=O)
1309        print(" \n")
1310
1311    return
1312
1313@lldb_command('showterminatedthreads', fancy=True)
1314def ShowTerminatedThreads(cmd_args=None, cmd_options={}, O=None):
1315    """ Display info about all terminated threads in the system
1316    """
1317
1318    with O.table(GetThreadSummary.header, indent=True):
1319        for t in kern.terminated_threads:
1320            print(GetThreadSummary(t, O=O))
1321
1322
1323@lldb_command('showtaskthreads', "F:", fancy=True)
1324def ShowTaskThreads(cmd_args = None, cmd_options={}, O=None):
1325    """ List the threads of a task.
1326        Usage: showtaskthreads <task-ptr>
1327           or: showtaskthreads -F <name>
1328    """
1329    task_list = []
1330    if "-F" in cmd_options:
1331        task_list = FindTasksByName(cmd_options["-F"])
1332    elif cmd_args:
1333        t = kern.GetValueFromAddress(cmd_args[0], 'task *')
1334        task_list = [t]
1335    else:
1336        raise ArgumentError("No arguments passed")
1337
1338    for task in task_list:
1339        print(GetTaskSummary.header + " " + GetProcSummary.header)
1340        pval = GetProcFromTask(task)
1341        print(GetTaskSummary(task) + " " + GetProcSummary(pval))
1342        with O.table(GetThreadSummary.header, indent=True):
1343            for thval in IterateQueue(task.threads, 'thread *', 'task_threads'):
1344                print(GetThreadSummary(thval, O=O))
1345    return
1346
1347@lldb_command('showact', fancy=True)
1348def ShowAct(cmd_args=None, cmd_options={}, O=None):
1349    """ Routine to print out the state of a specific thread.
1350        usage: showact <activation>
1351    """
1352    if not cmd_args:
1353        raise ArgumentError("No arguments passed")
1354    threadval = kern.GetValueFromAddress(cmd_args[0], 'thread *')
1355    with O.table(GetThreadSummary.header):
1356        print(GetThreadSummary(threadval, O=O))
1357
1358@lldb_command('showactstack', fancy=True)
1359def ShowActStack(cmd_args=None, cmd_options={}, O=None):
1360    """ Routine to print out the stack of a specific thread.
1361        usage:  showactstack <activation>
1362    """
1363    if not cmd_args:
1364        raise ArgumentError("No arguments passed")
1365    threadval = kern.GetValueFromAddress(cmd_args[0], 'thread *')
1366    with O.table(GetThreadSummary.header):
1367        print(GetThreadSummary(threadval, O=O))
1368    print(GetThreadBackTrace(threadval, prefix="\t"))
1369    return
1370
1371@lldb_command('switchtoact', fancy=True)
1372def SwitchToAct(cmd_args=None, cmd_options={}, O=None):
1373    """ Switch to different context specified by activation
1374    This command allows gdb to examine the execution context and call
1375    stack for the specified activation. For example, to view the backtrace
1376    for an activation issue "switchtoact <address>", followed by "bt".
1377    Before resuming execution, issue a "resetctx" command, to
1378    return to the original execution context.
1379    """
1380    if cmd_args is None or len(cmd_args) < 1:
1381        raise ArgumentError("No arguments passed")
1382    thval = kern.GetValueFromAddress(cmd_args[0], 'thread *')
1383    lldbthread = GetLLDBThreadForKernelThread(thval)
1384    with O.table(GetThreadSummary.header):
1385        print(GetThreadSummary(thval, O=O))
1386    LazyTarget.GetProcess().selected_thread = lldbthread
1387    if not LazyTarget.GetProcess().SetSelectedThread(lldbthread):
1388        print("Failed to switch thread.")
1389    return
1390
1391@lldb_command('switchtoregs')
1392def SwitchToRegs(cmd_args=None):
1393    """ Routine to switch to a register state.
1394        Usage: (lldb) switchtoregs <struct arm_saved_state[64] *>
1395        This command creates a fake thread in lldb with the saved register state.
1396        Note: This command ONLY works for ARM based kernel setup.
1397    """
1398
1399    if cmd_args is None or len(cmd_args) < 1:
1400        raise ArgumentError("No arguments passed")
1401
1402    lldb_process = LazyTarget.GetProcess()
1403
1404    saved_state = ArgumentStringToInt(cmd_args[0])
1405    # any change to this logic requires change in operating_system.py as well
1406    fake_thread_id = 0xdead0000 | (saved_state & ~0xffff0000)
1407    fake_thread_id = fake_thread_id & 0xdeadffff
1408    lldb_process.CreateOSPluginThread(0xdeadbeef, saved_state)
1409    lldbthread = lldb_process.GetThreadByID(int(fake_thread_id))
1410
1411    if not lldbthread.IsValid():
1412        print("Failed to create thread")
1413        return
1414
1415    lldb_process.selected_thread = lldbthread
1416    if not lldb_process.SetSelectedThread(lldbthread):
1417        print("Failed to switch thread")
1418    print("Switched to Fake thread created from register state at {:#x}".format(
1419            saved_state))
1420
1421
1422# Macro: showallstacks
1423@lldb_command('showallstacks', fancy=True)
1424def ShowAllStacks(cmd_args=None, cmd_options={}, O=None):
1425    """Routine to print out the stack for each thread in the system.
1426    """
1427    for t in kern.tasks:
1428        ShowTaskStacks(t, O=O)
1429        print(" \n")
1430    ZombStacks(O=O)
1431
1432# EndMacro: showallstacks
1433
1434# Macro: showcurrentstacks
1435@lldb_command('showcurrentstacks', fancy=True)
1436def ShowCurrentStacks(cmd_args=None, cmd_options={}, O=None):
1437    """ Routine to print out the thread running on each cpu (incl. its stack)
1438    """
1439    processor_list = kern.GetGlobalVariable('processor_list')
1440    current_processor = processor_list
1441    while unsigned(current_processor) > 0:
1442        print("\n" + GetProcessorSummary(current_processor))
1443        active_thread = current_processor.active_thread
1444        if unsigned(active_thread) != 0:
1445            task_val = active_thread.t_tro.tro_task
1446            proc_val = GetProcFromTask(task_val)
1447            print(GetTaskSummary.header + " " + GetProcSummary.header)
1448            print(GetTaskSummary(task_val) + " " + GetProcSummary(proc_val))
1449            with O.table(GetThreadSummary.header, indent=True):
1450                print(GetThreadSummary(active_thread, O=O))
1451            print("\tBacktrace:")
1452            print(GetThreadBackTrace(active_thread, prefix="\t"))
1453        current_processor = current_processor.processor_list
1454    return
1455# EndMacro: showcurrentstacks
1456
1457@lldb_command('showcurrentthreads', fancy=True)
1458def ShowCurrentThreads(cmd_args=None, cmd_options={}, O=None):
1459    """ Display info about threads running on each cpu """
1460    processor_list = kern.GetGlobalVariable('processor_list')
1461    current_processor = processor_list
1462    while unsigned(current_processor) > 0:
1463        print(GetProcessorSummary(current_processor))
1464        active_thread = current_processor.active_thread
1465        if unsigned(active_thread) != 0 :
1466            task_val = active_thread.t_tro.tro_task
1467            proc_val = GetProcFromTask(task_val)
1468            print(GetTaskSummary.header + " " + GetProcSummary.header)
1469            print(GetTaskSummary(task_val) + " " + GetProcSummary(proc_val))
1470            with O.table(GetThreadSummary.header, indent=True):
1471                print(GetThreadSummary(active_thread, O=O))
1472        current_processor = current_processor.processor_list
1473    return
1474
1475def GetFullBackTrace(frame_addr, verbosity = vHUMAN, prefix = ""):
1476    """ Get backtrace across interrupt context.
1477        params: frame_addr - int - address in memory which is a frame pointer (ie. rbp, r7)
1478                prefix - str - prefix for each line of output.
1479
1480    """
1481    out_string = ""
1482    bt_count = 0
1483    frame_ptr = frame_addr
1484    previous_frame_ptr = 0
1485    # <rdar://problem/12677290> lldb unable to find symbol for _mh_execute_header
1486    mh_execute_addr = int(lldb_run_command('p/x (uintptr_t *)&_mh_execute_header').split('=')[-1].strip(), 16)
1487    while frame_ptr and frame_ptr != previous_frame_ptr and bt_count < 128:
1488        if (not kern.arch.startswith('arm') and frame_ptr < mh_execute_addr) or (kern.arch.startswith('arm') and frame_ptr > mh_execute_addr):
1489            break
1490        pc_val = kern.GetValueFromAddress(frame_ptr + kern.ptrsize,'uintptr_t *')
1491        pc_val = kern.StripKernelPAC(unsigned(dereference(pc_val)))
1492        out_string += prefix + GetSourceInformationForAddress(pc_val) + "\n"
1493        bt_count +=1
1494        previous_frame_ptr = frame_ptr
1495        frame_val = kern.GetValueFromAddress((frame_ptr), 'uintptr_t *')
1496        if unsigned(frame_val) == 0:
1497            break
1498        frame_ptr = unsigned(dereference(frame_val))
1499
1500    return out_string
1501
1502@lldb_command('fullbt')
1503def FullBackTrace(cmd_args=[]):
1504    """ Show full backtrace across the interrupt boundary.
1505        Syntax: fullbt <frame ptr>
1506        Example: fullbt  `$rbp`
1507    """
1508    if len(cmd_args) < 1:
1509        print(FullBackTrace.__doc__)
1510        return False
1511    print(GetFullBackTrace(ArgumentStringToInt(cmd_args[0]), prefix="\t"))
1512
1513@lldb_command('fullbtall', fancy=True)
1514def FullBackTraceAll(cmd_args=[], cmd_options={}, O=None):
1515    """ Show full backtrace across the interrupt boundary for threads running on all processors.
1516        Syntax: fullbtall
1517        Example: fullbtall
1518    """
1519    for processor in IterateLinkedList(kern.globals.processor_list, 'processor_list') :
1520        print("\n" + GetProcessorSummary(processor))
1521        active_thread = processor.active_thread
1522        if unsigned(active_thread) != 0 :
1523            task_val = active_thread.t_tro.tro_task
1524            proc_val = GetProcFromTask(task_val)
1525            print(GetTaskSummary.header + " " + GetProcSummary.header)
1526            print(GetTaskSummary(task_val) + " " + GetProcSummary(proc_val))
1527            with O.table(GetThreadSummary.header, indent=True):
1528                print(GetThreadSummary(active_thread, O=O))
1529            print("\tBacktrace:")
1530
1531            ThreadVal = GetLLDBThreadForKernelThread(active_thread)
1532
1533            FramePtr = ThreadVal.frames[0].GetFP()
1534
1535            print(GetFullBackTrace(unsigned(FramePtr), prefix="\t"))
1536
1537
1538@lldb_command('symbolicate')
1539def SymbolicateAddress(cmd_args=[]):
1540    """ Symbolicate an address for symbol information from loaded symbols
1541        Example: "symbolicate 0xaddr" is equivalent to "output/a 0xaddr"
1542    """
1543    if len(cmd_args) < 1:
1544        print("Invalid address.\nSyntax: symbolicate <address>")
1545        return False
1546    print(GetSourceInformationForAddress(ArgumentStringToInt(cmd_args[0])))
1547    return True
1548
1549@lldb_command('showinitchild')
1550def ShowInitChild(cmd_args=None):
1551    """ Routine to print out all processes in the system
1552        which are children of init process
1553    """
1554    headp = kern.globals.initproc.p_children
1555    for pp in IterateListEntry(headp, 'p_sibling'):
1556        print(GetProcInfo(pp))
1557    return
1558
1559@lldb_command('showproctree')
1560def ShowProcTree(cmd_args=None):
1561    """ Routine to print the processes in the system in a hierarchical tree form. This routine does not print zombie processes.
1562        If no argument is given, showproctree will print all the processes in the system.
1563        If pid is specified, showproctree prints all the descendants of the indicated process
1564    """
1565    search_pid = 0
1566    if cmd_args:
1567        search_pid = ArgumentStringToInt(cmd_args[0])
1568
1569    if search_pid < 0:
1570        print("pid specified must be a positive number")
1571        print(ShowProcTree.__doc__)
1572        return
1573
1574    hdr_format = "{0: <6s} {1: <14s} {2: <9s}\n"
1575    out_string = hdr_format.format("PID", "PROCESS", "POINTER")
1576    out_string += hdr_format.format('='*3, '='*7, '='*7)
1577    proc = GetProcForPid(search_pid)
1578    out_string += "{0: <6d} {1: <32s} [ {2: #019x} ]\n".format(
1579            proc.p_ppid, GetProcName(proc.p_pptr), unsigned(proc.p_pptr))
1580    out_string += "|--{0: <6d} {1: <32s} [ {2: #019x} ]\n".format(
1581            GetProcPID(proc), GetProcName(proc), unsigned(proc))
1582    print(out_string)
1583    ShowProcTreeRecurse(proc, "|  ")
1584
1585def ShowProcTreeRecurse(proc, prefix=""):
1586    """ Prints descendants of a given proc in hierarchial tree form
1587        params:
1588            proc  : core.value representing a struct proc * in the kernel
1589        returns:
1590            str   : String containing info about a given proc and its descendants in tree form
1591    """
1592    if proc.p_childrencnt > 0:
1593        head_ptr = proc.p_children.lh_first
1594
1595        for p in IterateListEntry(proc.p_children, 'p_sibling'):
1596            print(prefix + "|--{0: <6d} {1: <32s} [ {2: #019x} ]\n".format(
1597                    GetProcPID(p), GetProcName(p), unsigned(p)))
1598            ShowProcTreeRecurse(p, prefix + "|  ")
1599
1600@lldb_command('showthreadfortid', fancy=True)
1601def ShowThreadForTid(cmd_args=None, O=None):
1602    """ The thread structure contains a unique thread_id value for each thread.
1603        This command is used to retrieve the address of the thread structure(thread_t)
1604        corresponding to a given thread_id.
1605    """
1606    if not cmd_args:
1607        print("Please provide thread_t whose tid you'd like to look up")
1608        print(ShowThreadForTid.__doc__)
1609        return
1610    search_tid = ArgumentStringToInt(cmd_args[0])
1611    for taskp in kern.tasks:
1612        for actp in IterateQueue(taskp.threads, 'struct thread *', 'task_threads'):
1613            if search_tid == int(actp.thread_id):
1614                print("Found {0: #019x}".format(actp))
1615                with O.table(GetThreadSummary.header):
1616                    print(GetThreadSummary(actp, O=O))
1617                return
1618    print("Not a valid thread_id")
1619
1620def GetProcessorSummary(processor):
1621    """ Internal function to print summary of processor
1622        params: processor - value representing struct processor *
1623        return: str - representing the details of given processor
1624    """
1625
1626    processor_state_str = "INVALID"
1627    processor_state = int(processor.state)
1628
1629    processor_states = {
1630                0: 'OFF_LINE',
1631                1: 'SHUTDOWN',
1632                2: 'START',
1633                3: 'PENDING_OFFLINE',
1634                4: 'IDLE',
1635                5: 'DISPATCHING',
1636                6: 'RUNNING'
1637                }
1638
1639    if processor_state in processor_states:
1640        processor_state_str = "{0: <11s} ".format(processor_states[processor_state])
1641
1642    processor_recommended_str = ""
1643    if int(processor.is_recommended) == 0:
1644        processor_recommended_str = " (not recommended)"
1645
1646    ast = 0
1647    preemption_disable = 0
1648    preemption_disable_str = ""
1649
1650    if kern.arch == 'x86_64':
1651        cpu_data = kern.globals.cpu_data_ptr[processor.cpu_id]
1652        if (cpu_data != 0) :
1653            ast = cpu_data.cpu_pending_ast
1654            preemption_disable = cpu_data.cpu_preemption_level
1655    # On arm64, it's kern.globals.CpuDataEntries[processor.cpu_id].cpu_data_vaddr
1656    # but LLDB can't find CpuDataEntries...
1657
1658    ast_str = GetASTSummary(ast)
1659
1660    if (preemption_disable != 0) :
1661        preemption_disable_str = "Preemption Disabled"
1662
1663    processor_reasons = {
1664        0: '(REASON_NONE)',
1665        1: '(REASON_SYSTEM)',
1666        2: '(REASON_USER)',
1667        3: '(REASON_CLPC_SYSTEM)',
1668        4: '(REASON_CLPC_USER)'
1669    }
1670
1671    processor_shutdown_reason_str = "";
1672    processor_shutdown_reason = int(processor.last_shutdown_reason)
1673
1674    if processor_state in {0, 1, 3}:
1675        processor_shutdown_reason_str = processor_reasons[processor_shutdown_reason]
1676
1677    out_str = "Processor {: <#018x} cpu_id {:>#4x} AST: {:<6s} State {:<s}{:<s}{:<s} {:<s}\n".format(
1678            processor, int(processor.cpu_id), ast_str, processor_state_str, processor_shutdown_reason_str,
1679            processor_recommended_str, preemption_disable_str)
1680    return out_str
1681
1682ledger_limit_infinity = (uint64_t(0x1).value << 63) - 1
1683
1684def GetLedgerEntryIndex(template, name):
1685    i = 0
1686    while i != template.lt_cnt:
1687        if str(template.lt_entries[i].et_key) == name:
1688            return i
1689        i = i + 1
1690    return -1
1691
1692def GetLedgerEntryWithTemplate(ledger_template, ledgerp, i):
1693    """ Internal function to get internals of a ledger entry (*not* a ledger itself)
1694        params: ledger_template - value representing struct ledger_template_t for the task or thread
1695                ledgerp - value representing ledger pointer
1696                i - index in ledger
1697        return: entry - entry dictionary
1698    """
1699    lf_refill_scheduled = 0x0400
1700    lf_tracking_max = 0x4000
1701
1702    now = unsigned(kern.globals.sched_tick) // 20
1703    lim_pct = 0
1704
1705    entry = {}
1706
1707    et = ledger_template.lt_entries[i]
1708    entry["key"] = str(et.et_key)
1709    if et.et_size == sizeof("struct ledger_entry_small"):
1710        les = ledgerp.l_entries[et.et_offset]
1711        entry["credit"] = unsigned(les.les_credit)
1712        entry["debit"] = 0
1713        entry["flags"] = int(les.les_flags)
1714        entry["limit"] = ledger_limit_infinity
1715    elif et.et_size == sizeof("struct ledger_entry"):
1716        le = Cast(addressof(ledgerp.l_entries[et.et_offset]), "struct ledger_entry *")
1717        entry["credit"] = unsigned(le.le_credit)
1718        entry["debit"] = unsigned(le.le_debit)
1719        if (le.le_flags & lf_tracking_max):
1720            if hasattr(le._le._le_max, "le_interval_max"):
1721                entry["interval_max"] = unsigned(le._le._le_max.le_interval_max)
1722            entry["lifetime_max"] = unsigned(le._le._le_max.le_lifetime_max)
1723
1724        entry["limit"] = unsigned(le.le_limit)
1725
1726        if (le.le_flags & lf_refill_scheduled):
1727            entry["refill_period"] = unsigned (le._le.le_refill.le_refill_period)
1728
1729        if (unsigned(le.le_warn_percent) < 65535):
1730            entry["warn_percent"] = unsigned (le.le_warn_percent * 100 / 65536)
1731        entry["flags"] = int(le.le_flags)
1732        entry["diag_threshold_scaled"] = int(le.le_diag_threshold_scaled)
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