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"""
5
6from xnu import *
7import sys, shlex
8from utils import *
9from core.lazytarget import *
10import xnudefines
11
12def GetProcNameForTask(task):
13    """ returns a string name of the process. if proc is not valid "unknown" is returned
14        params:
15            task: value object represeting a task in the kernel.
16        returns:
17            str : A string name of the process linked to the task
18    """
19    if not task or not unsigned(task.bsd_info):
20        return "unknown"
21    p = Cast(task.bsd_info, 'proc *')
22    return str(p.p_comm)
23
24def GetProcPIDForTask(task):
25    """ returns a int pid of the process. if the proc is not valid, val[5] from audit_token is returned.
26        params:
27            task: value object representing a task in the kernel
28        returns:
29            int : pid of the process or -1 if not found
30    """
31    if task and unsigned(task.bsd_info):
32        p = Cast(task.bsd_info, 'proc *')
33        return unsigned(p.p_pid)
34
35    if task :
36        return unsigned(task.audit_token.val[5])
37
38    return -1
39
40def GetProcInfo(proc):
41    """ returns a string name, pid, parent and task for a proc_t. Decodes cred, flag and p_stat fields.
42        params:
43            proc : value object representing a proc in the kernel
44        returns:
45            str : A string describing various information for process.
46    """
47    out_string = ""
48    out_string += ("Process {p: <#020x}\n\tname {p.p_comm: <20s}\n\tpid:{p.p_pid: <6d} " +
49                   "task:{p.task: <#020x} p_stat:{p.p_stat: <6d} parent pid: {p.p_ppid: <6d}\n"
50                   ).format(p=proc)
51    #print the Creds
52    ucred = proc.p_ucred
53    if ucred:
54        out_string += "Cred: euid {:d} ruid {:d} svuid {:d}\n".format(ucred.cr_posix.cr_uid,
55                                                                      ucred.cr_posix.cr_ruid,
56                                                                      ucred.cr_posix.cr_svuid )
57    #print the flags
58    flags = int(proc.p_flag)
59    out_string += "Flags: {0: <#020x}\n".format(flags)
60    i = 1
61    num = 1
62    while num <= flags:
63        if flags & num:
64            out_string += "\t" + xnudefines.proc_flag_explain_strings[i] + "\n"
65        elif num == 0x4: #special case for 32bit flag
66            out_string += "\t" + xnudefines.proc_flag_explain_strings[0] + "\n"
67        i += 1
68        num = num << 1
69    out_string += "State: "
70    state_val = proc.p_stat
71    if state_val < 1 or state_val > len(xnudefines.proc_state_strings) :
72        out_string += "(Unknown)"
73    else:
74        out_string += xnudefines.proc_state_strings[int(state_val)]
75
76    return out_string
77
78def GetProcNameForPid(pid):
79    """ Finds the name of the process corresponding to a given pid
80        params:
81            pid     : int, pid you want to find the procname for
82        returns
83            str     : Name of the process corresponding to the pid, "Unknown" if not found
84    """
85    for p in kern.procs:
86        if int(p.p_pid) == int(pid):
87            return str(p.p_comm)
88    return "Unknown"
89
90def GetProcForPid(search_pid):
91    """ Finds the value object representing a proc in the kernel based on its pid
92        params:
93            search_pid  : int, pid whose proc structure you want to find
94        returns:
95            value       : The value object representing the proc, if a proc corresponding
96                          to the given pid is found. Returns None otherwise
97    """
98    if search_pid == 0:
99        return kern.globals.initproc
100    else:
101        headp = kern.globals.allproc
102        for proc in IterateListEntry(headp, 'struct proc *', 'p_list'):
103            if proc.p_pid == search_pid:
104                return proc
105        return None
106
107@lldb_command('allproc')
108def AllProc(cmd_args=None):
109    """ Walk through the allproc structure and print procinfo for each process structure.
110        params:
111            cmd_args - [] : array of strings passed from lldb command prompt
112    """
113    for proc in kern.procs :
114        print GetProcInfo(proc)
115
116
117@lldb_command('zombproc')
118def ZombProc(cmd_args=None):
119    """ Routine to print out all procs in the zombie list
120        params:
121            cmd_args - [] : array of strings passed from lldb command prompt
122    """
123    if len(kern.zombprocs) != 0:
124        print "\nZombie Processes:"
125        for proc in kern.zombprocs:
126            print GetProcInfo(proc) + "\n\n"
127
128@lldb_command('zombtasks')
129def ZombTasks(cmd_args=None):
130    """ Routine to print out all tasks in the zombie list
131        params: None
132    """
133    out_str = ""
134    if len(kern.zombprocs) != 0:
135        header = "\nZombie Tasks:\n"
136        header += GetTaskSummary.header + " " + GetProcSummary.header
137        for proc in kern.zombprocs:
138            if proc.p_stat != 5:
139                t = Cast(proc.task, 'task *')
140                out_str += GetTaskSummary(t) +" "+ GetProcSummary(proc) + "\n"
141        if out_str != "":
142            print header
143            print out_str
144
145@lldb_command('zombstacks')
146def ZombStacks(cmd_args=None):
147    """ Routine to print out all stacks of tasks that are exiting
148    """
149    header_flag = 0
150    for proc in kern.zombprocs:
151        if proc.p_stat != 5:
152            if header_flag == 0:
153                print "\nZombie Stacks:"
154                header_flag = 1
155            t = Cast(proc.task, 'task *')
156            ShowTaskStacks(t)
157#End of Zombstacks
158
159def GetASTSummary(ast):
160    """ Summarizes an AST field
161        Flags:
162        P - AST_PREEMPT
163        Q - AST_QUANTUM
164        U - AST_URGENT
165        H - AST_HANDOFF
166        Y - AST_YIELD
167        A - AST_APC
168        L - AST_LEDGER
169        B - AST_BSD
170        K - AST_KPERF
171        M - AST_MACF
172        C - AST_CHUD
173        C - AST_CHUD_URGENT
174        G - AST_GUARD
175        T - AST_TELEMETRY_USER
176        T - AST_TELEMETRY_KERNEL
177        T - AST_TELEMETRY_WINDOWED
178        S - AST_SFI
179    """
180    out_string = ""
181    state = int(ast)
182    thread_state_chars = {0x0:'', 0x1:'P', 0x2:'Q', 0x4:'U', 0x8:'H', 0x10:'Y', 0x20:'A',
183                          0x40:'L', 0x80:'B', 0x100:'K', 0x200:'M', 0x400:'C', 0x800:'C',
184                          0x1000:'G', 0x2000:'T', 0x4000:'T', 0x8000:'T', 0x10000:'S'}
185    state_str = ''
186    mask = 0x1
187    while mask <= 0x10000 :
188        state_str += thread_state_chars[int(state & mask)]
189        mask = mask << 1
190
191    return state_str
192
193
194@lldb_type_summary(['task', 'task_t'])
195@header("{0: <20s} {1: <20s} {2: <20s} {3: >5s} {4: <5s}".format("task","vm_map", "ipc_space", "#acts", "flags"))
196def GetTaskSummary(task):
197    """ Summarizes the important fields in task structure.
198        params: task: value - value object representing a task in kernel
199        returns: str - summary of the task
200    """
201    out_string = ""
202    format_string = '{0: <#020x} {1: <#020x} {2: <#020x} {3: >5d} {4: <5s}'
203    thread_count = int(task.thread_count)
204    task_flags = ''
205    if hasattr(task, "suppression_generation") and (int(task.suppression_generation) & 0x1) == 0x1:
206        task_flags += 'P'
207    if hasattr(task, "suspend_count") and int(task.suspend_count) > 0:
208        task_flags += 'S'
209    if hasattr(task, 'task_imp_base') and unsigned(task.task_imp_base):
210        tib = task.task_imp_base
211        if int(tib.iit_receiver) == 1:
212            task_flags += 'R'
213        if int(tib.iit_donor) == 1:
214            task_flags += 'D'
215        if int(tib.iit_assertcnt) > 0:
216            task_flags += 'B'
217    out_string += format_string.format(task, task.map, task.itk_space, thread_count, task_flags)
218    return out_string
219
220@lldb_type_summary(['thread *', 'thread_t'])
221@header("{0: <24s} {1: <10s} {2: <20s} {3: <6s} {4: <6s} {5: <15s} {6: <15s} {7: <8s} {8: <12s} {9: <32s} {10: <20s} {11: <20s} {12: <20s}".format('thread', 'thread_id', 'processor', 'base', 'pri', 'sched_mode', 'io_policy', 'state', 'ast', 'wait_queue', 'wait_event', 'wmesg', 'thread_name'))
222def GetThreadSummary(thread):
223    """ Summarize the thread structure. It decodes the wait state and waitevents from the data in the struct.
224        params: thread: value - value objecte representing a thread in kernel
225        returns: str - summary of a thread
226
227        State flags:
228        W - WAIT
229        S - SUSP
230        R - RUN
231        U - Uninterruptible
232        H - Terminated
233        A - Terminated and on termination queue
234        I - Idle thread
235
236        policy flags:
237        B - darwinbg
238        L - lowpri cpu
239        T - IO throttle
240        P - IO passive
241        D - Terminated
242    """
243    out_string = ""
244    format_string = "{0: <24s} {1: <10s} {2: <20s} {3: <6s} {4: <6s} {5: <15s} {6: <15s} {7: <8s} {8: <12s} {9: <32s} {10: <20s} {11: <20s} {12: <20s}"
245    thread_ptr_str = str("{0: <#020x}".format(thread))
246    if int(thread.static_param) :
247        thread_ptr_str+="[WQ]"
248    thread_id = hex(thread.thread_id)
249    thread_name = ''
250    processor = hex(thread.last_processor)
251    base_priority = str(int(thread.priority))
252    sched_priority = str(int(thread.sched_pri))
253    sched_mode = ''
254    mode = str(thread.sched_mode)
255    if "TIMESHARE" in mode:
256        sched_mode+="timeshare"
257    elif "FIXED" in mode:
258        sched_mode+="fixed"
259    elif "REALTIME" in mode:
260        sched_mode+="realtime"
261
262    if (unsigned(thread.bound_processor) != 0):
263        sched_mode+=" bound"
264
265    # TH_SFLAG_THROTTLED
266    if (unsigned(thread.sched_flags) & 0x0004):
267        sched_mode+=" BG"
268
269    io_policy_str = ""
270    if int(thread.uthread) != 0:
271        uthread = Cast(thread.uthread, 'uthread *')
272        #check for thread name
273        if int(uthread.pth_name) != 0 :
274            th_name_strval = Cast(uthread.pth_name, 'char *')
275            if len(str(th_name_strval)) > 0 :
276                thread_name = str(th_name_strval)
277
278        #check for io_policy flags
279        if int(uthread.uu_flag) & 0x400:
280            io_policy_str+='RAGE '
281
282        #now flags for task_policy
283
284        io_policy_str = ""
285
286        if int(thread.effective_policy.darwinbg) != 0:
287            io_policy_str += "B"
288        if int(thread.effective_policy.lowpri_cpu) != 0:
289            io_policy_str += "L"
290
291        if int(thread.effective_policy.io_tier) != 0:
292            io_policy_str += "T"
293        if int(thread.effective_policy.io_passive) != 0:
294            io_policy_str += "P"
295        if int(thread.effective_policy.terminated) != 0:
296            io_policy_str += "D"
297
298    state = int(thread.state)
299    thread_state_chars = {0x0:'', 0x1:'W', 0x2:'S', 0x4:'R', 0x8:'U', 0x10:'H', 0x20:'A', 0x40:'P', 0x80:'I'}
300    state_str = ''
301    mask = 0x1
302    while mask <= 0x80 :
303        state_str += thread_state_chars[int(state & mask)]
304        mask = mask << 1
305
306    ast = int(thread.ast) | int(thread.reason)
307    ast_str = GetASTSummary(ast)
308
309    #wait queue information
310    wait_queue_str = ''
311    wait_event_str = ''
312    wait_message = ''
313    if ( state & 0x1 ) != 0:
314        #we need to look at the waitqueue as well
315        wait_queue_str = str("{0: <#020x}".format(int(hex(thread.wait_queue), 16)))
316        wait_event_str = str("{0: <#020x}".format(int(hex(thread.wait_event), 16)))
317        wait_event_str_sym = kern.Symbolicate(int(hex(thread.wait_event), 16))
318        if len(wait_event_str_sym) > 0:
319            wait_event_str = wait_event_str.strip() + " <" + wait_event_str_sym + ">"
320        if int(thread.uthread) != 0 :
321            uthread = Cast(thread.uthread, 'uthread *')
322            if int(uthread.uu_wmesg) != 0:
323                wait_message = str(Cast(uthread.uu_wmesg, 'char *'))
324
325    out_string += format_string.format(thread_ptr_str, thread_id, processor, base_priority, sched_priority, sched_mode, io_policy_str, state_str, ast_str, wait_queue_str, wait_event_str, wait_message, thread_name)
326    return out_string
327
328
329@lldb_type_summary(['coalition_t', 'coalition'])
330@header("type coalition summary (header tbw)")
331def GetCoalitionSummary(coal):
332    out_string = ""
333    format_string = '{0: <#020x} {1: <d} {2: <d} {3: <d}'
334    flags_string = ''
335    if (coal.terminated):
336        flags_string += ' terminated'
337    if (coal.reaped):
338        flags_string += ' reaped'
339    out_string += format_string.format(coal, coal.id, coal.ref_count, coal.active_count, )
340    return out_string
341
342@lldb_type_summary(['proc', 'proc *'])
343@header("{0: >6s} {1: ^20s} {2: >14s} {3: ^10s} {4: <20s}".format("pid", "process", "io_policy", "wq_state", "command"))
344def GetProcSummary(proc):
345    """ Summarize the process data.
346        params:
347          proc : value - value representaitng a proc * in kernel
348        returns:
349          str - string summary of the process.
350    """
351    out_string = ""
352    format_string= "{0: >6d} {1: >#020x} {2: >14s} {3: >2d} {4: >2d} {5: >2d}    {6: <20s}"
353    pval = proc.GetSBValue()
354    #code.interact(local=locals())
355    if str(pval.GetType()) != str(gettype('proc *')) :
356        return "Unknown type " + str(pval.GetType()) + " " + str(hex(proc))
357    if not proc:
358        out_string += "Process " + hex(proc) + " is not valid."
359        return out_string
360    pid = int(proc.p_pid)
361    proc_addr = int(hex(proc), 16)
362    proc_rage_str = ""
363    if int(proc.p_lflag) & 0x400000 :
364        proc_rage_str = "RAGE"
365
366    task = Cast(proc.task, 'task *')
367
368    io_policy_str = ""
369
370    if int(task.effective_policy.darwinbg) != 0:
371        io_policy_str += "B"
372    if int(task.effective_policy.lowpri_cpu) != 0:
373        io_policy_str += "L"
374
375    if int(task.effective_policy.io_tier) != 0:
376        io_policy_str += "T"
377    if int(task.effective_policy.io_passive) != 0:
378        io_policy_str += "P"
379    if int(task.effective_policy.terminated) != 0:
380        io_policy_str += "D"
381
382    if int(task.effective_policy.t_suspended) != 0:
383        io_policy_str += "S"
384    if int(task.effective_policy.t_latency_qos) != 0:
385        io_policy_str += "Q"
386    if int(task.effective_policy.t_sup_active) != 0:
387        io_policy_str += "A"
388
389
390    try:
391        work_queue = Cast(proc.p_wqptr, 'workqueue *')
392        if proc.p_wqptr != 0 :
393            wq_num_threads = int(work_queue.wq_nthreads)
394            wq_idle_threads = int(work_queue.wq_thidlecount)
395            wq_req_threads = int(work_queue.wq_reqcount)
396        else:
397            wq_num_threads = 0
398            wq_idle_threads = 0
399            wq_req_threads = 0
400    except:
401        wq_num_threads = -1
402        wq_idle_threads = -1
403        wq_req_threads = -1
404    process_name = str(proc.p_comm)
405    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)
406    return out_string
407
408@lldb_type_summary(['tty_dev_t', 'tty_dev_t *'])
409@header("{0: <20s} {1: <10s} {2: <10s} {3: <15s} {4: <15s} {5: <15s} {6: <15s}".format("tty_dev","master", "slave", "open", "free", "name", "revoke"))
410def GetTTYDevSummary(tty_dev):
411    """ Summarizes the important fields in tty_dev_t structure.
412        params: tty_dev: value - value object representing a tty_dev_t in kernel
413        returns: str - summary of the tty_dev
414    """
415    out_string = ""
416    format_string = "{0: <#020x} {1: <#010x} {2: <#010x} {3: <15s} {4: <15s} {5: <15s} {6: <15s}"
417    open_fn = kern.Symbolicate(int(hex(tty_dev.open), 16))
418    free_fn = kern.Symbolicate(int(hex(tty_dev.free), 16))
419    name_fn = kern.Symbolicate(int(hex(tty_dev.name), 16))
420    revoke_fn = kern.Symbolicate(int(hex(tty_dev.revoke), 16))
421    out_string += format_string.format(tty_dev, tty_dev.master, tty_dev.slave, open_fn, free_fn, name_fn, revoke_fn)
422    return out_string
423
424@lldb_type_summary(['kqueue *'])
425@header("{: <20s} {: <20s} {: <6s} {: <20s} {: <10s}".format('kqueue', 'process', '#events', 'wqs', 'state'))
426def GetKQueueSummary(kq):
427    """ summarizes kqueue information
428        returns: str - summary of kqueue
429    """
430    out_string = ""
431    format_string = "{o: <#020x} {o.kq_p: <#020x} {o.kq_count: <6d} {o.kq_wqs: <#020x} {st_str: <10s}"
432    state = int(kq.kq_state)
433    state_str = ''
434    mask = 0x1
435    while mask <= 0x80 :
436        if int(state & mask):
437            state_str += ' ' + xnudefines.kq_state_strings[int(state & mask)]
438        mask = mask << 1
439    out_string += format_string.format(o=kq, st_str=state_str)
440    return out_string
441
442@lldb_type_summary(['knote *'])
443@header("{0: <20s}".format('knote'))
444def GetKnoteSummary(kn):
445    """ Summarizes a knote and related information
446        returns: str - summary of knote
447    """
448    out_string = ""
449    format_string = "{o: <#020x}"
450    out_string += format_string.format(o=kn)
451    return out_string
452
453# Macro: showtask
454
455@lldb_command('showtask', 'F:')
456def ShowTask(cmd_args=None, cmd_options={}):
457    """  Routine to print a summary listing of given task
458         Usage: showtask <address of task>
459         or   : showtask -F <name of task>
460    """
461    task_list = []
462    if "-F" in cmd_options:
463        task_list = FindTasksByName(cmd_options['-F'])
464    else:
465        if not cmd_args:
466            raise ArgumentError("Invalid arguments passed.")
467
468        tval = kern.GetValueFromAddress(cmd_args[0], 'task *')
469        if not tval:
470            raise ("Unknown arguments: %r" % cmd_args)
471        task_list.append(tval)
472
473    for tval in task_list:
474        print GetTaskSummary.header + " " + GetProcSummary.header
475        pval = Cast(tval.bsd_info, 'proc *')
476        print GetTaskSummary(tval) +" "+ GetProcSummary(pval)
477
478# EndMacro: showtask
479
480# Macro: showpid
481
482@lldb_command('showpid')
483def ShowPid(cmd_args=None):
484    """  Routine to print a summary listing of task corresponding to given pid
485         Usage: showpid <pid value>
486    """
487    if not cmd_args:
488        print "No arguments passed"
489        print ShowPid.__doc__
490        return False
491    pidval = ArgumentStringToInt(cmd_args[0])
492    for t in kern.tasks:
493        pval = Cast(t.bsd_info, 'proc *')
494        if pval and pval.p_pid == pidval:
495            print GetTaskSummary.header + " " + GetProcSummary.header
496            print GetTaskSummary(t) + " " + GetProcSummary(pval)
497            break
498
499# EndMacro: showpid
500
501# Macro: showproc
502
503@lldb_command('showproc')
504def ShowProc(cmd_args=None):
505    """  Routine to print a summary listing of task corresponding to given proc
506         Usage: showproc <address of proc>
507    """
508    if not cmd_args:
509        print "No arguments passed"
510        print ShowProc.__doc__
511        return False
512    pval = kern.GetValueFromAddress(cmd_args[0], 'proc *')
513    if not pval:
514        print "unknown arguments:", str(cmd_args)
515        return False
516    print GetTaskSummary.header + " " + GetProcSummary.header
517    tval = Cast(pval.task, 'task *')
518    print GetTaskSummary(tval) +" "+ GetProcSummary(pval)
519
520# EndMacro: showproc
521
522# Macro: showprocinfo
523
524@lldb_command('showprocinfo')
525def ShowProcInfo(cmd_args=None):
526    """  Routine to display name, pid, parent & task for the given proc address
527         It also shows the Cred, Flags and state of the process
528         Usage: showprocinfo <address of proc>
529    """
530    if not cmd_args:
531        print "No arguments passed"
532        print ShowProcInfo.__doc__
533        return False
534    pval = kern.GetValueFromAddress(cmd_args[0], 'proc *')
535    if not pval:
536        print "unknown arguments:", str(cmd_args)
537        return False
538    print GetProcInfo(pval)
539
540# EndMacro: showprocinfo
541
542#Macro: showprocfiles
543
544@lldb_command('showprocfiles')
545def ShowProcFiles(cmd_args=None):
546    """ Given a proc_t pointer, display the list of open file descriptors for the referenced process.
547        Usage: showprocfiles <proc_t>
548    """
549    if not cmd_args:
550        print ShowProcFiles.__doc__
551        return
552    proc = kern.GetValueFromAddress(cmd_args[0], 'proc_t')
553    proc_filedesc = proc.p_fd
554    proc_lastfile = unsigned(proc_filedesc.fd_lastfile)
555    proc_ofiles = proc_filedesc.fd_ofiles
556    if unsigned(proc_ofiles) == 0:
557        print 'No open files for proc {0: <s}'.format(cmd_args[0])
558        return
559    print "{0: <5s} {1: <18s} {2: <10s} {3: <8s} {4: <18s} {5: <64s}".format('FD', 'FILEGLOB', 'FG_FLAGS', 'FG_TYPE', 'FG_DATA','INFO')
560    print "{0:-<5s} {0:-<18s} {0:-<10s} {0:-<8s} {0:-<18s} {0:-<64s}".format("")
561    count = 0
562
563    # Filetype map
564    filetype_dict = {
565                1: 'VNODE',
566                2: 'SOCKET',
567                3: 'PSXSHM',
568                4: 'PSXSEM',
569                5: 'KQUEUE',
570                6: 'PIPE',
571                7: 'FSEVENTS'
572              }
573
574    while count <= proc_lastfile:
575        if unsigned(proc_ofiles[count]) != 0:
576            out_str = ''
577            proc_fd_flags = proc_ofiles[count].f_flags
578            proc_fd_fglob = proc_ofiles[count].f_fglob
579            out_str += "{0: <5d} ".format(count)
580            out_str += "{0: <#18x} ".format(unsigned(proc_fd_fglob))
581            out_str += "0x{0:0>8x} ".format(unsigned(proc_fd_flags))
582            proc_fd_ftype = unsigned(proc_fd_fglob.fg_ops.fo_type)
583            if proc_fd_ftype in filetype_dict:
584                out_str += "{0: <8s} ".format(filetype_dict[proc_fd_ftype])
585            else:
586                out_str += "?: {0: <5d} ".format(proc_fd_ftype)
587            out_str += "{0: <#18x} ".format(unsigned(proc_fd_fglob.fg_data))
588            if proc_fd_ftype == 1:
589                fd_name = Cast(proc_fd_fglob.fg_data, 'struct vnode *').v_name
590                out_str += "{0: <64s}".format(fd_name)
591            out_str += "\n"
592            print out_str
593        count += 1
594
595#EndMacro: showprocfiles
596
597#Macro: showkqueue
598@lldb_command('showkqueue' ,'')
599def ShowKQueue(cmd_args=[], cmd_options={}):
600    """ Given a struct kqueue pointer, display the summary of the kqueue
601        Usage: (lldb) showkqueue <struct kqueue *>
602    """
603    if not cmd_args:
604        raise ArgumentError('Invalid arguments')
605
606    kq = kern.GetValueFromAddress(cmd_args[0], 'struct kqueue *')
607    print GetKQueueSummary.header
608    print GetKQueueSummary(kq)
609
610#EndMacro: showkqueue
611
612#Macro: showtty
613
614@lldb_command('showtty')
615def ShowTTY(cmd_args=None):
616    """ Display information about a struct tty
617        Usage: showtty <tty struct>
618    """
619    if not cmd_args:
620        print ShowTTY.__doc__
621        return
622
623    tty = kern.GetValueFromAddress(cmd_args[0], 'struct tty *')
624    print "TTY structure at:              {0: <s}".format(cmd_args[0])
625    print "Last input to raw queue:       {0: <#18x} \"{1: <s}\"".format(unsigned(tty.t_rawq.c_cs), tty.t_rawq.c_cs)
626    print "Last input to canonical queue: {0: <#18x} \"{1: <s}\"".format(unsigned(tty.t_canq.c_cs), tty.t_canq.c_cs)
627    print "Last output data:              {0: <#18x} \"{1: <s}\"".format(unsigned(tty.t_outq.c_cs), tty.t_outq.c_cs)
628    tty_state_info = [
629                  ['', 'TS_SO_OLOWAT (Wake up when output <= low water)'],
630                  ['- (synchronous I/O mode)', 'TS_ASYNC (async I/O mode)'],
631                  ['', 'TS_BUSY (Draining output)'],
632                  ['- (Carrier is NOT present)', 'TS_CARR_ON (Carrier is present)'],
633                  ['', 'TS_FLUSH (Outq has been flushed during DMA)'],
634                  ['- (Open has NOT completed)', 'TS_ISOPEN (Open has completed)'],
635                  ['', 'TS_TBLOCK (Further input blocked)'],
636                  ['', 'TS_TIMEOUT (Wait for output char processing)'],
637                  ['', 'TS_TTSTOP (Output paused)'],
638                  ['', 'TS_WOPEN (Open in progress)'],
639                  ['', 'TS_XCLUDE (Tty requires exclusivity)'],
640                  ['', 'TS_BKSL (State for lowercase \\ work)'],
641                  ['', 'TS_CNTTB (Counting tab width, ignore FLUSHO)'],
642                  ['', 'TS_ERASE (Within a \\.../ for PRTRUB)'],
643                  ['', 'TS_LNCH (Next character is literal)'],
644                  ['', 'TS_TYPEN (Retyping suspended input (PENDIN))'],
645                  ['', 'TS_CAN_BYPASS_L_RINT (Device in "raw" mode)'],
646                  ['- (Connection NOT open)', 'TS_CONNECTED (Connection open)'],
647                  ['', 'TS_SNOOP (Device is being snooped on)'],
648                  ['', 'TS_SO_OCOMPLETE (Wake up when output completes)'],
649                  ['', 'TS_ZOMBIE (Connection lost)'],
650                  ['', 'TS_CAR_OFLOW (For MDMBUF - handle in driver)'],
651                  ['', 'TS_CTS_OFLOW (For CCTS_OFLOW - handle in driver)'],
652                  ['', 'TS_DSR_OFLOW (For CDSR_OFLOW - handle in driver)']
653                ]
654    index = 0
655    mask = 0x1
656    tty_state = unsigned(tty.t_state)
657    print "State:"
658    while index < 24:
659        if tty_state & mask != 0:
660            if len(tty_state_info[index][1]) > 0:
661                print '\t' + tty_state_info[index][1]
662        else:
663            if len(tty_state_info[index][0]) > 0:
664                print '\t' + tty_state_info[index][0]
665        index += 1
666        mask = mask << 1
667    print "Flags:                    0x{0:0>8x}".format(unsigned(tty.t_flags))
668    print "Foreground Process Group: 0x{0:0>16x}".format(unsigned(tty.t_pgrp))
669    print "Enclosing session:        0x{0:0>16x}".format(unsigned(tty.t_session))
670    print "Termios:"
671    print "\tInput Flags:   0x{0:0>8x}".format(unsigned(tty.t_termios.c_iflag))
672    print "\tOutput Flags:  0x{0:0>8x}".format(unsigned(tty.t_termios.c_oflag))
673    print "\tControl Flags: 0x{0:0>8x}".format(unsigned(tty.t_termios.c_cflag))
674    print "\tLocal Flags:   0x{0:0>8x}".format(unsigned(tty.t_termios.c_lflag))
675    print "\tInput Speed:   {0: <8d}".format(tty.t_termios.c_ispeed)
676    print "\tOutput Speed:  {0: <8d}".format(tty.t_termios.c_ospeed)
677    print "High Watermark: {0: <d} bytes".format(tty.t_hiwat)
678    print "Low Watermark : {0: <d} bytes".format(tty.t_lowat)
679
680#EndMacro: showtty
681
682#Macro showallttydevs
683
684@lldb_command('showallttydevs')
685def ShowAllTTYDevs(cmd_args=[], cmd_options={}):
686    """ Show a list of ttydevs registered in the system.
687        Usage:
688        (lldb)showallttydevs
689    """
690    tty_dev_head = kern.globals.tty_dev_head
691    tty_dev = tty_dev_head
692    print GetTTYDevSummary.header
693    while unsigned(tty_dev) != 0:
694        print GetTTYDevSummary(tty_dev)
695        tty_dev = tty_dev.next
696    return ""
697
698#EndMacro: showallttydevs
699
700#Macro: dumpcallqueue
701
702@lldb_command('dumpcallqueue')
703def DumpCallQueue(cmd_args=None):
704    """ Displays the contents of the specified call_entry queue.
705        Usage: dumpcallqueue <queue_head_t *>
706    """
707    if not cmd_args:
708        print DumpCallQueue.__doc__
709        return
710    print "{0: <18s} {1: <18s} {2: <18s} {3: <64s} {4: <18s}".format('CALL_ENTRY', 'PARAM0', 'PARAM1', 'DEADLINE', 'FUNC')
711    callhead = kern.GetValueFromAddress(cmd_args[0], 'queue_head_t *')
712    count = 0
713    for callentry in IterateQueue(callhead, 'struct call_entry *',  'q_link'):
714        print "{0: <#18x} {1: <#18x} {2: <#18x} {3: <64d} {4: <#18x}".format(
715              unsigned(callentry), unsigned(callentry.param0), unsigned(callentry.param1),
716              unsigned(callentry.deadline), unsigned(callentry.func))
717        count += 1
718    print "{0: <d} entries!".format(count)
719
720#EndMacro: dumpcallqueue
721
722@lldb_command('showallcoalitions')
723def ShowAllCoalitions(cmd_args=None):
724    """  Routine to print a summary listing of all the coalitions
725    """
726    global kern
727    print GetCoalitionSummary.header
728    for c in kern.coalitions:
729        print GetCoalitionSummary(c)
730
731@lldb_command('showalltasks')
732def ShowAllTasks(cmd_args=None):
733    """  Routine to print a summary listing of all the tasks
734         wq_state -> reports "number of workq threads", "number of scheduled workq threads", "number of pending work items"
735         if "number of pending work items" seems stuck at non-zero, it may indicate that the workqueue mechanism is hung
736         io_policy -> RAGE  - rapid aging of vnodes requested
737                     NORM  - normal I/O explicitly requested (this is the default)
738                     PASS  - passive I/O requested (i.e. I/Os do not affect throttling decisions)
739                     THROT - throttled I/O requested (i.e. thread/task may be throttled after each I/O completes)
740    """
741    global kern
742    print GetTaskSummary.header + " " + GetProcSummary.header
743    for t in kern.tasks:
744        pval = Cast(t.bsd_info, 'proc *')
745        print GetTaskSummary(t) +" "+ GetProcSummary(pval)
746    ZombTasks()
747
748@lldb_command('showterminatedtasks')
749def ShowTerminatedTasks(cmd_args=None):
750    """  Routine to print a summary listing of all the terminated tasks
751         wq_state -> reports "number of workq threads", "number of scheduled workq threads", "number of pending work items"
752         if "number of pending work items" seems stuck at non-zero, it may indicate that the workqueue mechanism is hung
753         io_policy -> RAGE  - rapid aging of vnodes requested
754                     NORM  - normal I/O explicitly requested (this is the default)
755                     PASS  - passive I/O requested (i.e. I/Os do not affect throttling decisions)
756                     THROT - throttled I/O requested (i.e. thread/task may be throttled after each I/O completes)
757        syntax: (lldb)showallterminatedtasks
758    """
759    global kern
760    print GetTaskSummary.header + " " + GetProcSummary.header
761    for t in kern.terminated_tasks:
762        pval = Cast(t.bsd_info, 'proc *')
763        print GetTaskSummary(t) +" "+ GetProcSummary(pval)
764    return True
765
766# Macro: showtaskstacks
767
768def ShowTaskStacks(task):
769    """ Print a task with summary and stack information for each of its threads
770    """
771    global kern
772    print GetTaskSummary.header + " " + GetProcSummary.header
773    pval = Cast(task.bsd_info, 'proc *')
774    print GetTaskSummary(task) + " " + GetProcSummary(pval)
775    for th in IterateQueue(task.threads, 'thread *', 'task_threads'):
776        print "  " + GetThreadSummary.header
777        print "  " + GetThreadSummary(th)
778        print GetThreadBackTrace(th, prefix="    ") + "\n"
779
780def FindTasksByName(searchstr, ignore_case=True):
781    """ Search the list of tasks by name.
782        params:
783            searchstr: str - a regex like string to search for task
784            ignore_case: bool - If False then exact matching will be enforced
785        returns:
786            [] - array of task object. Empty if not found any
787    """
788    re_options = 0
789    if ignore_case:
790        re_options = re.IGNORECASE
791    search_regex = re.compile(searchstr, re_options)
792    retval = []
793    for t in kern.tasks:
794        pval = Cast(t.bsd_info, "proc *")
795        process_name = "{:s}".format(pval.p_comm)
796        if search_regex.search(process_name):
797            retval.append(t)
798    return retval
799
800@lldb_command('showtaskstacks', 'F:')
801def ShowTaskStacksCmdHelper(cmd_args=None, cmd_options={}):
802    """ Routine to print out the stack for each thread in a task
803        Usage: showtaskstacks <0xaddress of task>
804           or: showtaskstacks -F launchd
805    """
806
807    if "-F" in cmd_options:
808        find_task_str = cmd_options["-F"]
809        task_list = FindTasksByName(find_task_str)
810        for tval in task_list:
811            ShowTaskStacks(tval)
812        return
813
814    if not cmd_args:
815        raise ArgumentError("No arguments passed")
816
817    tval = kern.GetValueFromAddress(cmd_args[0], 'task *')
818    if not tval:
819        raise ArgumentError("unknown arguments: {:s}".format(str(cmd_args)))
820    else:
821        ShowTaskStacks(tval)
822        return
823
824# EndMacro: showtaskstacks
825
826@lldb_command('showallthreads')
827def ShowAllThreads(cmd_args = None):
828    """ Display info about all threads in the system
829    """
830    for t in kern.tasks:
831        ShowTaskThreads([str(int(t))])
832        print " \n"
833
834    for t in kern.terminated_tasks:
835        print "Terminated: \n"
836        ShowTaskThreads([str(int(t))])
837        print " \n"
838
839    return
840
841@lldb_command('showtaskthreads', "F:")
842def ShowTaskThreads(cmd_args = None, cmd_options={}):
843    """ Display thread information for a given task
844        Usage: showtaskthreads <0xaddress of task>
845           or: showtaskthreads -F <name>
846    """
847    task_list = []
848    if "-F" in cmd_options:
849        task_list = FindTasksByName(cmd_options["-F"])
850    elif cmd_args:
851        t = kern.GetValueFromAddress(cmd_args[0], 'task *')
852        task_list.append(t)
853    else:
854        raise ArgumentError("No arguments passed")
855
856    for task in task_list:
857        print GetTaskSummary.header + " " + GetProcSummary.header
858        pval = Cast(task.bsd_info, 'proc *')
859        print GetTaskSummary(task) + " " + GetProcSummary(pval)
860        print "\t" + GetThreadSummary.header
861        for thval in IterateQueue(task.threads, 'thread *', 'task_threads'):
862            print "\t" + GetThreadSummary(thval)
863    return
864
865@lldb_command('showact')
866def ShowAct(cmd_args=None):
867    """ Routine to print out the state of a specific thread.
868        usage: showact <activation>
869    """
870    if cmd_args == None or len(cmd_args) < 1:
871        print "No arguments passed"
872        print ShowAct.__doc__
873        return False
874    threadval = kern.GetValueFromAddress(cmd_args[0], 'thread *')
875    print GetThreadSummary.header
876    print GetThreadSummary(threadval)
877
878@lldb_command('showactstack')
879def ShowActStack(cmd_args=None):
880    """ Routine to print out the stack of a specific thread.
881        usage:  showactstack <activation>
882    """
883    if cmd_args == None or len(cmd_args) < 1:
884        print "No arguments passed"
885        print ShowAct.__doc__.strip()
886        return False
887    threadval = kern.GetValueFromAddress(cmd_args[0], 'thread *')
888    print GetThreadSummary.header
889    print GetThreadSummary(threadval)
890    print GetThreadBackTrace(threadval, prefix="\t")
891    return
892
893@lldb_command('switchtoact')
894def SwitchToAct(cmd_args=None):
895    """ Switch to different context specified by activation
896    This command allows gdb to examine the execution context and call
897    stack for the specified activation. For example, to view the backtrace
898    for an activation issue "switchtoact <address>", followed by "bt".
899    Before resuming execution, issue a "resetctx" command, to
900    return to the original execution context.
901    """
902    if cmd_args == None or len(cmd_args) < 1:
903        print "No arguments passed"
904        print SwitchToAct.__doc__.strip()
905        return False
906    thval = kern.GetValueFromAddress(cmd_args[0], 'thread *')
907    lldbthread = GetLLDBThreadForKernelThread(thval)
908    print GetThreadSummary.header
909    print GetThreadSummary(thval)
910    LazyTarget.GetProcess().selected_thread = lldbthread
911    if not LazyTarget.GetProcess().SetSelectedThread(lldbthread):
912        print "Failed to switch thread."
913    return
914# Macro: showallstacks
915@lldb_command('showallstacks')
916def ShowAllStacks(cmd_args=None):
917    """Routine to print out the stack for each thread in the system.
918    """
919    for t in kern.tasks:
920        ShowTaskStacks(t)
921        print " \n"
922    ZombStacks()
923    return
924
925# EndMacro: showallstacks
926
927# Macro: showcurrentstacks
928@lldb_command('showcurrentstacks')
929def ShowCurrentStacks(cmd_args=None):
930    """ Routine to print out the thread running on each cpu (incl. its stack)
931    """
932    processor_list = kern.GetGlobalVariable('processor_list')
933    current_processor = processor_list
934    while unsigned(current_processor) > 0:
935        print "\n" + GetProcessorSummary(current_processor)
936        active_thread = current_processor.active_thread
937        if unsigned(active_thread) != 0 :
938            task_val = active_thread.task
939            proc_val = Cast(task_val.bsd_info, 'proc *')
940            print GetTaskSummary.header + " " + GetProcSummary.header
941            print GetTaskSummary(task_val) + " " + GetProcSummary(proc_val)
942            print "\t" + GetThreadSummary.header
943            print "\t" + GetThreadSummary(active_thread)
944            print "\tBacktrace:"
945            print GetThreadBackTrace(active_thread, prefix="\t")
946        current_processor = current_processor.processor_list
947    return
948# EndMacro: showcurrentstacks
949
950@lldb_command('showcurrentthreads')
951def ShowCurrentThreads(cmd_args=None):
952    """ Display info about threads running on each cpu """
953    processor_list = kern.GetGlobalVariable('processor_list')
954    current_processor = processor_list
955    while unsigned(current_processor) > 0:
956        print GetProcessorSummary(current_processor)
957        active_thread = current_processor.active_thread
958        if unsigned(active_thread) != 0 :
959            task_val = active_thread.task
960            proc_val = Cast(task_val.bsd_info, 'proc *')
961            print GetTaskSummary.header + " " + GetProcSummary.header
962            print GetTaskSummary(task_val) + " " + GetProcSummary(proc_val)
963            print "\t" + GetThreadSummary.header
964            print "\t" + GetThreadSummary(active_thread)
965        current_processor = current_processor.processor_list
966    return
967
968def GetFullBackTrace(frame_addr, verbosity = vHUMAN, prefix = ""):
969    """ Get backtrace across interrupt context.
970        params: frame_addr - int - address in memory which is a frame pointer (ie. rbp, r7)
971                prefix - str - prefix for each line of output.
972
973    """
974    out_string = ""
975    bt_count = 0
976    frame_ptr = frame_addr
977    previous_frame_ptr = 0
978    # <rdar://problem/12677290> lldb unable to find symbol for _mh_execute_header
979    mh_execute_addr = int(lldb_run_command('p/x (uintptr_t *)&_mh_execute_header').split('=')[-1].strip(), 16)
980    while frame_ptr and frame_ptr != previous_frame_ptr and bt_count < 128:
981        if (kern.arch != 'arm' and frame_ptr < mh_execute_addr) or (kern.arch == 'arm' and frame_ptr > mh_execute_addr):
982            break
983        pc_val = kern.GetValueFromAddress(frame_ptr + kern.ptrsize,'uintptr_t *')
984        pc_val = unsigned(dereference(pc_val))
985        out_string += prefix + GetSourceInformationForAddress(pc_val) + "\n"
986        bt_count +=1
987        previous_frame_ptr = frame_ptr
988        frame_val = kern.GetValueFromAddress((frame_ptr), 'uintptr_t *')
989        if unsigned(frame_val) == 0:
990            break
991        frame_ptr = unsigned(dereference(frame_val))
992
993    return out_string
994
995@lldb_command('fullbt')
996def FullBackTrace(cmd_args=[]):
997    """ Show full backtrace across the interrupt boundary.
998        Syntax: fullbt <frame ptr>
999        Example: fullbt  `$rbp`
1000    """
1001    if len(cmd_args) < 1:
1002        print FullBackTrace.__doc__
1003        return False
1004    print GetFullBackTrace(ArgumentStringToInt(cmd_args[0]), prefix="\t")
1005
1006@lldb_command('fullbtall')
1007def FullBackTraceAll(cmd_args=[]):
1008    """ Show full backtrace across the interrupt boundary for threads running on all processors.
1009        Syntax: fullbtall
1010        Example: fullbtall
1011    """
1012    for processor in IterateLinkedList(kern.globals.processor_list, 'processor_list') :
1013        print "\n" + GetProcessorSummary(processor)
1014        active_thread = processor.active_thread
1015        if unsigned(active_thread) != 0 :
1016            task_val = active_thread.task
1017            proc_val = Cast(task_val.bsd_info, 'proc *')
1018            print GetTaskSummary.header + " " + GetProcSummary.header
1019            print GetTaskSummary(task_val) + " " + GetProcSummary(proc_val)
1020            print "\t" + GetThreadSummary.header
1021            print "\t" + GetThreadSummary(active_thread)
1022            print "\tBacktrace:"
1023
1024            ThreadVal = GetLLDBThreadForKernelThread(active_thread)
1025
1026            FramePtr = ThreadVal.frames[0].GetFP()
1027
1028            print GetFullBackTrace(unsigned(FramePtr), prefix="\t")
1029
1030
1031@lldb_command('symbolicate')
1032def SymbolicateAddress(cmd_args=[]):
1033    """ Symbolicate an address for symbol information from loaded symbols
1034        Example: "symbolicate 0xaddr" is equivalent to "output/a 0xaddr"
1035    """
1036    if len(cmd_args) < 1:
1037        print "Invalid address.\nSyntax: symbolicate <address>"
1038        return False
1039    print GetSourceInformationForAddress(ArgumentStringToInt(cmd_args[0]))
1040    return True
1041
1042@lldb_command('showinitchild')
1043def ShowInitChild(cmd_args=None):
1044    """ Routine to print out all processes in the system
1045        which are children of init process
1046    """
1047    headp = kern.globals.initproc.p_children
1048    for pp in IterateListEntry(headp, 'struct proc *', 'p_sibling'):
1049        print GetProcInfo(pp)
1050    return
1051
1052@lldb_command('showproctree')
1053def ShowProcTree(cmd_args=None):
1054    """ Routine to print the processes in the system in a hierarchical tree form. This routine does not print zombie processes.
1055        If no argument is given, showproctree will print all the processes in the system.
1056        If pid is specified, showproctree prints all the descendants of the indicated process
1057    """
1058    search_pid = 0
1059    if cmd_args:
1060        search_pid = ArgumentStringToInt(cmd_args[0])
1061
1062    if search_pid < 0:
1063        print "pid specified must be a positive number"
1064        print ShowProcTree.__doc__
1065        return
1066
1067    hdr_format = "{0: <6s} {1: <14s} {2: <9s}\n"
1068    out_string = hdr_format.format("PID", "PROCESS", "POINTER")
1069    out_string += hdr_format.format('='*3, '='*7, '='*7)
1070    proc = GetProcForPid(search_pid)
1071    out_string += "{0: <6d} {1: <14s} [ {2: #019x} ]\n".format(proc.p_ppid, proc.p_pptr.p_comm, unsigned(proc.p_pptr))
1072    out_string += "|--{0: <6d} {1: <16s} [ {2: #019x} ]\n".format(proc.p_pid, proc.p_comm, unsigned(proc))
1073    print out_string
1074    ShowProcTreeRecurse(proc, "|  ")
1075
1076    return
1077
1078def ShowProcTreeRecurse(proc, prefix=""):
1079    """ Prints descendants of a given proc in hierarchial tree form
1080        params:
1081            proc  : core.value representing a struct proc * in the kernel
1082        returns:
1083            str   : String containing info about a given proc and its descendants in tree form
1084    """
1085    if proc.p_childrencnt > 0:
1086        head_ptr = proc.p_children.lh_first
1087
1088        for p in IterateListEntry(proc.p_children, 'struct proc *', 'p_sibling'):
1089            print prefix + "|--{0: <6d} {1: <16s} [ {2: #019x} ]\n".format(p.p_pid, p.p_comm, unsigned(p))
1090            ShowProcTreeRecurse(p, prefix + "|  ")
1091
1092@lldb_command('showthreadfortid')
1093def ShowThreadForTid(cmd_args=None):
1094    """ The thread structure contains a unique thread_id value for each thread.
1095        This command is used to retrieve the address of the thread structure(thread_t)
1096        corresponding to a given thread_id.
1097    """
1098    if not cmd_args:
1099        print "Please provide thread_t whose tid you'd like to look up"
1100        print ShowThreadForTid.__doc__
1101        return
1102    search_tid = ArgumentStringToInt(cmd_args[0])
1103    for taskp in kern.tasks:
1104        for actp in IterateQueue(taskp.threads, 'struct thread *', 'task_threads'):
1105            if search_tid == int(actp.thread_id):
1106                print "Found {0: #019x}".format(actp)
1107                print GetThreadSummary.header
1108                print GetThreadSummary(actp)
1109                return
1110    print "Not a valid thread_id"
1111
1112# Macro: showallprocessors
1113
1114def GetProcessorSummary(processor):
1115    """ Internal function to print summary of processor
1116        params: processor - value representing struct processor *
1117        return: str - representing the details of given processor
1118    """
1119
1120    processor_state_str = "INVALID"
1121    processor_state = int(processor.state)
1122
1123    processor_states = {
1124                0: 'OFF_LINE',
1125                1: 'SHUTDOWN',
1126                2: 'START',
1127                # 3 (formerly INACTIVE)
1128                4: 'IDLE',
1129                5: 'DISPATCHING',
1130                6: 'RUNNING'
1131                }
1132
1133    if processor_state in processor_states:
1134        processor_state_str = "{0: <11s} ".format(processor_states[processor_state])
1135
1136    out_str = "Processor {: <#018x} cpu_id {:>#4x} State {:<s}\n".format(processor, int(processor.cpu_id), processor_state_str)
1137    return out_str
1138
1139def GetGroupSetSummary(runq, task_map):
1140    """ Internal function to print summary of group run queue
1141        params: runq - value representing struct run_queue *
1142        return: str - representing the details of given run_queue
1143    """
1144    out_str = "    runq: count {: <10d} highq: {: <10d} urgency {: <10d}\n".format(runq.count, runq.highq, runq.urgency)
1145
1146    runq_queue_i = 0
1147    runq_queue_count = sizeof(runq.queues)/sizeof(runq.queues[0])
1148
1149    for runq_queue_i in range(runq_queue_count) :
1150        runq_queue_head = addressof(runq.queues[runq_queue_i])
1151        runq_queue_p = runq_queue_head.next
1152
1153        if unsigned(runq_queue_p) != unsigned(runq_queue_head):
1154            runq_queue_this_count = 0
1155
1156            for entry in IterateQueue(runq_queue_head, "sched_entry_t", "links"):
1157                runq_queue_this_count += 1
1158
1159            out_str += "      Queue [{: <#012x}] Priority {: <3d} count {:d}\n".format(runq_queue_head, runq_queue_i, runq_queue_this_count)
1160            for entry in IterateQueue(runq_queue_head, "sched_entry_t", "links"):
1161                group = entry.group
1162                task = task_map.get(unsigned(group), "Unknown task!")
1163                out_str += "\tEntry [{: <#012x}] Priority {: <3d} Group {: <#012x} Task {: <#012x}\n".format(unsigned(entry), entry.sched_pri, unsigned(entry.group), unsigned(task))
1164
1165    return out_str
1166
1167@lldb_command('showrunq')
1168def ShowRunq(cmd_args=None):
1169    """  Routine to print information of a runq
1170         Usage: showrunq <runq>
1171    """
1172    out_str = ''
1173    runq = kern.GetValueFromAddress(cmd_args[0], 'struct run_queue *')
1174    out_str += GetRunQSummary(runq)
1175    print out_str
1176
1177def GetRunQSummary(runq):
1178    """ Internal function to print summary of run_queue
1179        params: runq - value representing struct run_queue *
1180        return: str - representing the details of given run_queue
1181    """
1182    out_str = "    runq: count {: <10d} highq: {: <10d} urgency {: <10d}\n".format(runq.count, runq.highq, runq.urgency)
1183
1184    runq_queue_i = 0
1185    runq_queue_count = sizeof(runq.queues)/sizeof(runq.queues[0])
1186
1187    for runq_queue_i in range(runq_queue_count) :
1188        runq_queue_head = addressof(runq.queues[runq_queue_i])
1189        runq_queue_p = runq_queue_head.next
1190
1191        if unsigned(runq_queue_p) != unsigned(runq_queue_head):
1192            runq_queue_this_count = 0
1193
1194            for thread in IterateQueue(runq_queue_head, "thread_t", "links"):
1195                runq_queue_this_count += 1
1196
1197            out_str += "      Queue [{: <#012x}] Priority {: <3d} count {:d}\n".format(runq_queue_head, runq_queue_i, runq_queue_this_count)
1198            out_str += "\t" + GetThreadSummary.header + "\n"
1199            for thread in IterateQueue(runq_queue_head, "thread_t", "links"):
1200                out_str += "\t" + GetThreadSummary(thread) + "\n"
1201                if config['verbosity'] > vHUMAN :
1202                    out_str += "\t" + GetThreadBackTrace(thread, prefix="\t\t") + "\n"
1203    return out_str
1204
1205
1206def GetGrrrSummary(grrr_runq):
1207    """ Internal function to print summary of grrr_run_queue
1208        params: grrr_runq - value representing struct grrr_run_queue *
1209        return: str - representing the details of given grrr_run_queue
1210    """
1211    out_str = "    GRRR Info: Count {: <10d} Weight {: <10d} Current Group {: <#012x}\n".format(grrr_runq.count,
1212        grrr_runq.weight, grrr_runq.current_group)
1213    grrr_group_i = 0
1214    grrr_group_count = sizeof(grrr_runq.groups)/sizeof(grrr_runq.groups[0])
1215    for grrr_group_i in range(grrr_group_count) :
1216        grrr_group = addressof(grrr_runq.groups[grrr_group_i])
1217        if grrr_group.count > 0:
1218            out_str += "      Group {: <3d} [{: <#012x}] ".format(grrr_group.index, grrr_group)
1219            out_str += "Count {:d} Weight {:d}\n".format(grrr_group.count, grrr_group.weight)
1220            grrr_group_client_head = addressof(grrr_group.clients)
1221            out_str += GetThreadSummary.header
1222            for thread in IterateQueue(grrr_group_client_head, "thread_t", "links"):
1223                out_str += "\t" + GetThreadSummary(thread) + "\n"
1224                if config['verbosity'] > vHUMAN :
1225                    out_str += "\t" + GetThreadBackTrace(thread, prefix="\t\t") + "\n"
1226    return out_str
1227
1228@lldb_command('showallprocessors')
1229def ShowAllProcessors(cmd_args=None):
1230    """  Routine to print information of all psets and processors
1231         Usage: showallprocessors
1232    """
1233    pset = addressof(kern.globals.pset0)
1234    show_grrr = 0
1235    show_priority_runq = 0
1236    show_priority_pset_runq = 0
1237    show_group_pset_runq = 0
1238    show_fairshare_grrr = 0
1239    show_fairshare_list = 0
1240    sched_enum_val = kern.globals._sched_enum
1241
1242    if sched_enum_val == 1:
1243        show_priority_runq = 1
1244        show_fairshare_list = 1
1245    elif sched_enum_val == 2:
1246        show_priority_pset_runq = 1
1247        show_fairshare_list = 1
1248    elif sched_enum_val == 4:
1249        show_grrr = 1
1250        show_fairshare_grrr = 1
1251    elif sched_enum_val == 5:
1252        show_priority_runq = 1
1253        show_group_pset_runq = 1
1254        show_fairshare_list = 1
1255    elif sched_enum_val == 6:
1256        show_priority_pset_runq = 1
1257        show_priority_runq = 1
1258        show_fairshare_list = 1
1259
1260    out_str = ''
1261
1262    out_str += "Scheduler: {:s} ({:s}, {:d})\n".format(kern.globals.sched_string,
1263            kern.Symbolicate(unsigned(kern.globals.sched_current_dispatch)),
1264            sched_enum_val)
1265
1266    out_str += "Runnable threads: {:d} Timeshare threads: {:d} Background threads {:d}\n".format(
1267            kern.globals.sched_run_count, kern.globals.sched_share_count, kern.globals.sched_background_count)
1268
1269    if show_group_pset_runq:
1270        # Create a group->task mapping
1271        task_map = {}
1272        for task in kern.tasks:
1273            task_map[unsigned(task.sched_group)] = task
1274        for task in kern.terminated_tasks:
1275            task_map[unsigned(task.sched_group)] = task
1276
1277    while unsigned(pset) != 0:
1278        out_str += "Processor Set  {: <#012x} Count {:d} (cpu_id {:<#x}-{:<#x})\n".format(pset,
1279            pset.cpu_set_count, pset.cpu_set_low, pset.cpu_set_hi)
1280
1281        if show_priority_pset_runq:
1282            runq = pset.pset_runq
1283            out_str += GetRunQSummary(runq)
1284
1285        if show_group_pset_runq:
1286            out_str += "Main Runq:\n"
1287            runq = pset.pset_runq
1288            out_str += GetGroupSetSummary(runq, task_map)
1289            out_str += "All Groups:\n"
1290            # TODO: Possibly output task header for each group
1291            for group in IterateQueue(kern.globals.sched_groups, "sched_group_t", "sched_groups"):
1292                if (group.runq.count != 0) :
1293                    task = task_map.get(unsigned(group), "Unknown task!")
1294                    out_str += "Group {: <#012x} Task {: <#012x}\n".format(unsigned(group), unsigned(task))
1295                    out_str += GetRunQSummary(group.runq)
1296
1297        out_str += "  Active Processors:\n"
1298        for processor in IterateQueue(pset.active_queue, "processor_t", "processor_queue"):
1299            out_str += "    "
1300            out_str += GetProcessorSummary(processor)
1301            if show_priority_runq:
1302                runq = processor.runq
1303                out_str += GetRunQSummary(runq)
1304            if show_grrr:
1305                grrr_runq = processor.grrr_runq
1306                out_str += GetGrrrSummary(grrr_runq)
1307
1308        out_str += "  Idle Processors:\n"
1309        for processor in IterateQueue(pset.idle_queue, "processor_t", "processor_queue"):
1310            out_str += "    " + GetProcessorSummary(processor)
1311            if show_priority_runq:
1312                out_str += GetRunQSummary(processor.runq)
1313
1314        out_str += "  Idle Secondary Processors:\n"
1315        for processor in IterateQueue(pset.idle_secondary_queue, "processor_t", "processor_queue"):
1316            out_str += "    " + GetProcessorSummary(processor)
1317            if show_priority_runq:
1318                out_str += GetRunQSummary(processor.runq)
1319
1320        pset = pset.pset_list
1321
1322    out_str += "\nRealtime Queue Count {:d}\n".format(kern.globals.rt_runq.count)
1323    for rt_runq_thread in IterateQueue(kern.globals.rt_runq.queue, "thread_t", "links"):
1324        out_str += ShowTask([unsigned(rt_runq_thread.task)])
1325        out_str += ShowAct([unsigned(rt_runq_thread)])
1326
1327    out_str += "\n"
1328    if show_fairshare_list:
1329        out_str += "Fair Share Queue Count {:d}\n".format(kern.globals.fs_runq.count)
1330        for fs_runq_thread in IterateQueue(kern.globals.fs_runq.queue, "thread_t", "links"):
1331            out_str += ShowTask([unsigned(fs_runq_thread.task)])
1332            out_str += ShowAct([unsigned(rt_runq_thread)])
1333    if show_fairshare_grrr:
1334        out_str += "Fair Share Queue Count {:d}\n".format(kern.globals.fs_grrr_runq.count)
1335        fs_grrr = addressof(kern.globals.fs_grrr_runq)
1336        out_str += GetGrrrSummary(fs_grrr)
1337
1338    print out_str
1339# EndMacro: showallprocessors
1340
1341def GetLedgerEntrySummary(ledger_template, ledger, i):
1342    """ Internal function to get internals of a ledger entry (*not* a ledger itself)
1343        params: ledger_template - value representing struct ledger_template_t for the task or thread
1344                ledger - value representing struct ledger_entry *
1345        return: str - formatted output information of ledger entries
1346    """
1347    ledger_limit_infinity = (uint64_t(0x1).value << 63) - 1
1348    lf_refill_scheduled = 0x0400
1349    lf_tracking_max = 0x4000
1350
1351    out_str = ''
1352    now = unsigned(kern.globals.sched_tick) / 20
1353    lim_pct = 0
1354
1355    out_str += "{: >32s} {:<2d}:".format(ledger_template.lt_entries[i].et_key, i)
1356    out_str += "{: >15d} ".format(unsigned(ledger.le_credit) - unsigned(ledger.le_debit))
1357    if (ledger.le_flags & lf_tracking_max):
1358        out_str += "{:9d} {:5d} ".format(ledger._le.le_peaks[0].le_max, now - unsigned(ledger._le.le_peaks[0].le_time))
1359        out_str += "{:9d} {:4d} ".format(ledger._le.le_peaks[1].le_max, now - unsigned(ledger._le.le_peaks[1].le_time))
1360    else:
1361        out_str += "        -     -         -    - "
1362
1363    out_str += "{:12d} {:12d} ".format(unsigned(ledger.le_credit), unsigned(ledger.le_debit))
1364    if (unsigned(ledger.le_limit) != ledger_limit_infinity):
1365        out_str += "{:12d} ".format(unsigned(ledger.le_limit))
1366    else:
1367        out_str += "           - "
1368
1369    if (ledger.le_flags & lf_refill_scheduled):
1370        out_str += "{:15d} ".format(ledger._le.le_refill.le_refill_period)
1371    else:
1372        out_str += "              - "
1373
1374    if (ledger.le_flags & lf_refill_scheduled):
1375        out_str += "{:9d} ".format((unsigned(ledger.le_limit) * 100) / ledger._le.le_refill.le_refill_period)
1376    else:
1377        out_str += "        - "
1378
1379    if (unsigned(ledger.le_warn_level) != ledger_limit_infinity):
1380        out_str += "{:9d} ".format((unsigned(ledger.le_warn_level) * 100) / unsigned(ledger.le_limit))
1381    else:
1382        out_str += "        - "
1383
1384    if ((unsigned(ledger.le_credit) - unsigned(ledger.le_debit)) > unsigned(ledger.le_limit)):
1385        out_str += "    X "
1386    else:
1387        out_str += "      "
1388
1389    out_str += "{:#8x}\n".format(ledger.le_flags)
1390    return out_str
1391
1392def GetThreadLedgerSummary(thread_val):
1393    """ Internal function to get a summary of ledger entries for the given thread
1394        params: thread - value representing struct thread *
1395        return: str - formatted output information for ledger entries of the input thread
1396    """
1397    out_str = "   [{:#08x}]\n".format(thread_val)
1398    ledgerp = thread_val.t_threadledger
1399    if ledgerp:
1400        i = 0
1401        while i != ledgerp.l_template.lt_cnt:
1402            out_str += GetLedgerEntrySummary(kern.globals.thread_ledger_template,
1403                ledgerp.l_entries[i], i)
1404            i = i + 1
1405    return out_str
1406
1407@header("{0: <15s} {1: >16s} {2: <2s} {3: >15s} {4: >9s} {5: >6s} {6: >8s} {7: <10s} {8: <9s} \
1408    {9: <12s} {10: <7s} {11: <15s} {12: <8s} {13: <9s} {14: <6s} {15: >6s}".format(
1409    "task [thread]", "entry", "#", "balance", "peakA", "(age)", "peakB", "(age)", "credit",
1410     "debit", "limit", "refill period", "lim pct", "warn pct", "over?", "flags"))
1411def GetTaskLedgers(task_val):
1412    """ Internal function to get summary of ledger entries from the task and its threads
1413        params: task_val - value representing struct task *
1414        return: str - formatted output information for ledger entries of the input task
1415    """
1416    out_str = ''
1417    task_ledgerp = task_val.ledger
1418    i = 0
1419    out_str += "{: #08x} ".format(task_val)
1420    pval = Cast(task_val.bsd_info, 'proc *')
1421    if pval:
1422        out_str += "{: <5s}:\n".format(pval.p_comm)
1423    else:
1424        out_str += "Invalid process:\n"
1425    while i != task_ledgerp.l_template.lt_cnt:
1426        out_str += GetLedgerEntrySummary(kern.globals.task_ledger_template, task_ledgerp.l_entries[i], i)
1427        i = i + 1
1428
1429    # Now walk threads
1430    for thval in IterateQueue(task_val.threads, 'thread *', 'task_threads'):
1431        out_str += GetThreadLedgerSummary(thval)
1432
1433    return out_str
1434
1435# Macro: showtaskledgers
1436
1437@lldb_command('showtaskledgers', 'F:')
1438def ShowTaskLedgers(cmd_args=None, cmd_options={}):
1439    """  Routine to print a summary  of ledger entries for the task and all of its threads
1440         Usage: showtaskledgers <address of task>
1441         or   : showtaskledgers -F <name of task>
1442    """
1443    if "-F" in cmd_options:
1444        task_list = FindTasksByName(cmd_options["-F"])
1445        for tval in task_list:
1446            print GetTaskLedgers.header
1447            print GetTaskLedgers(tval)
1448        return
1449
1450    if not cmd_args:
1451        raise ArgumentError("No arguments passed.")
1452    tval = kern.GetValueFromAddress(cmd_args[0], 'task *')
1453    if not tval:
1454        raise ArgumentError("unknown arguments: %r" %cmd_args)
1455    print GetTaskLedgers.header
1456    print GetTaskLedgers(tval)
1457
1458# EndMacro: showtaskledgers
1459
1460# Macro: showalltaskledgers
1461
1462@lldb_command('showalltaskledgers')
1463def ShowAllTaskLedgers(cmd_args=None):
1464    """  Routine to print a summary  of ledger entries for all tasks and respective threads
1465         Usage: showalltaskledgers
1466    """
1467    for t in kern.tasks:
1468        task_val = unsigned(t)
1469        ShowTaskLedgers([task_val])
1470
1471# EndMacro: showalltaskledgers
1472
1473# Macro: showprocuuidpolicytable
1474
1475@lldb_type_summary(['proc_uuid_policy_entry'])
1476@header("{0: <36s} {1: <10s}".format("uuid", "flags"))
1477def GetProcUUIDPolicyEntrySummary(entry):
1478    """ Summarizes the important fields in proc_uuid_policy_entry structure.
1479        params: entry: value - value object representing an entry
1480        returns: str - summary of the entry
1481    """
1482    data = []
1483    for i in range(16):
1484        data.append(int(entry.uuid[i]))
1485    flags = unsigned(entry.flags)
1486    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)
1487    return out_string
1488
1489@lldb_command('showprocuuidpolicytable')
1490def ShowProcUUIDPolicyTable(cmd_args=None):
1491    """ Routine to print the proc UUID policy table
1492        Usage: showprocuuidpolicytable
1493    """
1494    hashslots = unsigned(kern.globals.proc_uuid_policy_hash_mask)
1495    print "{0: <8s} ".format("slot") + GetProcUUIDPolicyEntrySummary.header
1496    for i in range(0, hashslots+1):
1497        headp = addressof(kern.globals.proc_uuid_policy_hashtbl[i])
1498        entrynum = 0
1499        for entry in IterateListEntry(headp, 'struct proc_uuid_policy_entry *', 'entries'):
1500            print "{0: >2d}.{1: <5d} ".format(i, entrynum) + GetProcUUIDPolicyEntrySummary(entry)
1501            entrynum += 1
1502
1503
1504# EndMacro: showprocuuidpolicytable
1505
1506@lldb_command('showalltaskpolicy')
1507def ShowAllTaskPolicy(cmd_args=None):
1508    """
1509         Routine to print a summary listing of all the tasks
1510         wq_state -> reports "number of workq threads", "number of scheduled workq threads", "number of pending work items"
1511         if "number of pending work items" seems stuck at non-zero, it may indicate that the workqueue mechanism is hung
1512         io_policy -> RAGE  - rapid aging of vnodes requested
1513                     NORM  - normal I/O explicitly requested (this is the default)
1514                     PASS  - passive I/O requested (i.e. I/Os do not affect throttling decisions)
1515                     THROT - throttled I/O requested (i.e. thread/task may be throttled after each I/O completes)
1516    """
1517    global kern
1518    print GetTaskSummary.header + " " + GetProcSummary.header
1519    for t in kern.tasks:
1520        pval = Cast(t.bsd_info, 'proc *')
1521        print GetTaskSummary(t) +" "+ GetProcSummary(pval)
1522        requested_strings = [
1523                ["int_darwinbg",        "DBG-int"],
1524                ["ext_darwinbg",        "DBG-ext"],
1525                ["int_iotier",          "iotier-int"],
1526                ["ext_iotier",          "iotier-ext"],
1527                ["int_iopassive",       "passive-int"],
1528                ["ext_iopassive",       "passive-ext"],
1529                ["bg_iotier",           "bg-iotier"],
1530                ["terminated",          "terminated"],
1531                ["th_pidbind_bg",       "bg-pidbind"],
1532                ["th_workq_bg",         "bg-workq"],
1533                ["t_apptype",           "apptype"],
1534                ["t_boosted",           "boosted"],
1535                ["t_int_gpu_deny",      "gpudeny-int"],
1536                ["t_ext_gpu_deny",      "gpudeny-ext"],
1537                ["t_role",              "role"],
1538                ["t_tal_enabled",       "tal-enabled"],
1539                ["t_base_latency_qos",  "latency-base"],
1540                ["t_over_latency_qos",  "latency-override"],
1541                ["t_base_through_qos",  "throughput-base"],
1542                ["t_over_through_qos",  "throughput-override"]
1543                ]
1544
1545        requested=""
1546        for value in requested_strings:
1547            if t.requested_policy.__getattr__(value[0]) :
1548                requested+=value[1] + ": " + str(t.requested_policy.__getattr__(value[0])) + " "
1549            else:
1550                requested+=""
1551
1552        suppression_strings = [
1553                ["t_sup_active",        "active"],
1554                ["t_sup_lowpri_cpu",    "lowpri-cpu"],
1555                ["t_sup_timer",         "timer-throttling"],
1556                ["t_sup_disk",          "disk-throttling"],
1557                ["t_sup_cpu_limit",     "cpu-limits"],
1558                ["t_sup_suspend",       "suspend"],
1559                ["t_sup_bg_sockets",    "bg-sockets"]
1560                ]
1561
1562        suppression=""
1563        for value in suppression_strings:
1564            if t.requested_policy.__getattr__(value[0]) :
1565                suppression+=value[1] + ": " + str(t.requested_policy.__getattr__(value[0])) + " "
1566            else:
1567                suppression+=""
1568
1569        effective_strings = [
1570                ["darwinbg",        "background"],
1571                ["lowpri_cpu",      "lowpri-cpu"],
1572                ["io_tier",         "iotier"],
1573                ["io_passive",      "passive"],
1574                ["all_sockets_bg",  "bg-allsockets"],
1575                ["new_sockets_bg",  "bg-newsockets"],
1576                ["bg_iotier",       "bg-iotier"],
1577                ["terminated",      "terminated"],
1578                ["t_gpu_deny",      "gpu-deny"],
1579                ["t_tal_engaged",   "tal-engaged"],
1580                ["t_suspended",     "suspended"],
1581                ["t_watchers_bg",   "bg-watchers"],
1582                ["t_latency_qos",   "latency-qos"],
1583                ["t_through_qos",   "throughput-qos"],
1584                ["t_sup_active",    "suppression-active"],
1585                ["t_role",          "role"]
1586                ]
1587
1588        effective=""
1589        for value in effective_strings:
1590            if t.effective_policy.__getattr__(value[0]) :
1591                effective+=value[1] + ": " + str(t.effective_policy.__getattr__(value[0])) + " "
1592            else:
1593                effective+=""
1594
1595
1596        pended_strings = [
1597                ["t_updating_policy",     "updating"],
1598                ["update_sockets",        "update_sockets"],
1599                ["t_update_timers",       "update_timers"],
1600                ["t_update_watchers",     "update_watchers"]
1601                ]
1602
1603        pended=""
1604        for value in pended_strings:
1605            if t.pended_policy.__getattr__(value[0]) :
1606                pended+=value[1] + ": " + str(t.pended_policy.__getattr__(value[0])) + " "
1607            else:
1608                pended+=""
1609
1610        print "requested: " + requested
1611        print "suppression: " + suppression
1612        print "effective: " + effective
1613        print "pended: " + pended
1614
1615
1616@lldb_type_summary(['wait_queue', 'wait_queue_t'])
1617@header("{: <20s} {: <20s} {: <15s} {:<5s} {:<5s} {: <20s}".format("waitq", "interlock", "policy", "members", "threads", "eventmask"))
1618def GetWaitQSummary(waitq):
1619    """ Summarizes the important fields in task structure.
1620        params: task: value - value object representing a task in kernel
1621        returns: str - summary of the task
1622    """
1623    out_string = ""
1624    format_string = '{: <#020x} {: <#020x} {: <15s} {: <5d} {: <5d} {: <#020x}'
1625
1626    wqtype = ""
1627
1628    if (waitq.wq_fifo == 1) :
1629        wqtype += "FIFO"
1630    else :
1631        wqtype += "PRIO"
1632
1633    if (waitq.wq_prepost == 1) :
1634        wqtype += "Prepost"
1635
1636    if (waitq.wq_type == 0x3) :
1637        wqtype += "Set"
1638    elif (waitq.wq_type == 0x2) :
1639        wqtype += "Queue"
1640    else :
1641        wqtype += "INVALID"
1642
1643    out_string += format_string.format(waitq, unsigned(waitq.wq_interlock.lock_data), policy, 0, 0, unsigned(waitq.wq_eventmask))
1644
1645    out_string += "\n" + GetThreadSummary.header
1646
1647    for thread in IterateQueue(waitq.wq_queue, "thread_t", "links"):
1648        out_string += "\n" + GetThreadSummary(thread)
1649
1650    return out_string
1651
1652
1653@lldb_command('showallsuspendedtasks', '')
1654def ShowSuspendedTasks(cmd_args=[], options={}):
1655    """ Show a list of suspended tasks with their process name summary.
1656    """
1657    print GetTaskSummary.header + ' ' + GetProcSummary.header
1658    for t in kern.tasks:
1659        if t.suspend_count > 0:
1660            print GetTaskSummary(t) + ' ' + GetProcSummary(Cast(t.bsd_info, 'proc *'))
1661    return True
1662
1663
1664