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