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