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