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