xref: /xnu-8792.41.9/tools/lldbmacros/ktrace.py (revision 5c2921b07a2480ab43ec66f5b9e41cb872bc554f)
1*5c2921b0SApple OSS Distributionsfrom __future__ import absolute_import, division, print_function
2*5c2921b0SApple OSS Distributions
3*5c2921b0SApple OSS Distributionsfrom builtins import map
4*5c2921b0SApple OSS Distributionsfrom builtins import range
5*5c2921b0SApple OSS Distributionsfrom builtins import object
6*5c2921b0SApple OSS Distributions
7*5c2921b0SApple OSS Distributionsfrom xnu import *
8*5c2921b0SApple OSS Distributionsfrom utils import *
9*5c2921b0SApple OSS Distributionsfrom core.lazytarget import *
10*5c2921b0SApple OSS Distributionsfrom misc import *
11*5c2921b0SApple OSS Distributionsfrom scheduler import *
12*5c2921b0SApple OSS Distributionsfrom kcdata import kcdata_item_iterator, KCObject, GetTypeForName, KCCompressedBufferObject
13*5c2921b0SApple OSS Distributionsfrom collections import namedtuple
14*5c2921b0SApple OSS Distributionsfrom future.utils import PY2
15*5c2921b0SApple OSS Distributionsimport heapq
16*5c2921b0SApple OSS Distributionsimport os
17*5c2921b0SApple OSS Distributionsimport plistlib
18*5c2921b0SApple OSS Distributionsimport struct
19*5c2921b0SApple OSS Distributionsimport subprocess
20*5c2921b0SApple OSS Distributionsimport sys
21*5c2921b0SApple OSS Distributionsimport tempfile
22*5c2921b0SApple OSS Distributionsimport time
23*5c2921b0SApple OSS Distributions
24*5c2921b0SApple OSS Distributions# From the defines in bsd/sys/kdebug.h:
25*5c2921b0SApple OSS Distributions
26*5c2921b0SApple OSS DistributionsKdebugClassNames = {
27*5c2921b0SApple OSS Distributions    1: "MACH",
28*5c2921b0SApple OSS Distributions    2: "NETWORK",
29*5c2921b0SApple OSS Distributions    3: "FSYSTEM",
30*5c2921b0SApple OSS Distributions    4: "BSD",
31*5c2921b0SApple OSS Distributions    5: "IOKIT",
32*5c2921b0SApple OSS Distributions    6: "DRIVERS",
33*5c2921b0SApple OSS Distributions    7: "TRACE",
34*5c2921b0SApple OSS Distributions    8: "DLIL",
35*5c2921b0SApple OSS Distributions    9: "WORKQUEUE",
36*5c2921b0SApple OSS Distributions    10: "CORESTORAGE",
37*5c2921b0SApple OSS Distributions    11: "CG",
38*5c2921b0SApple OSS Distributions    20: "MISC",
39*5c2921b0SApple OSS Distributions    30: "SECURITY",
40*5c2921b0SApple OSS Distributions    31: "DYLD",
41*5c2921b0SApple OSS Distributions    32: "QT",
42*5c2921b0SApple OSS Distributions    33: "APPS",
43*5c2921b0SApple OSS Distributions    34: "LAUNCHD",
44*5c2921b0SApple OSS Distributions    36: "PPT",
45*5c2921b0SApple OSS Distributions    37: "PERF",
46*5c2921b0SApple OSS Distributions    38: "IMPORTANCE",
47*5c2921b0SApple OSS Distributions    39: "PERFCTRL",
48*5c2921b0SApple OSS Distributions    40: "BANK",
49*5c2921b0SApple OSS Distributions    41: "XPC",
50*5c2921b0SApple OSS Distributions    42: "ATM",
51*5c2921b0SApple OSS Distributions    43: "ARIADNE",
52*5c2921b0SApple OSS Distributions    44: "DAEMON",
53*5c2921b0SApple OSS Distributions    45: "ENERGYTRACE",
54*5c2921b0SApple OSS Distributions    49: "IMG",
55*5c2921b0SApple OSS Distributions    50: "CLPC",
56*5c2921b0SApple OSS Distributions    128: "ANS",
57*5c2921b0SApple OSS Distributions    129: "SIO",
58*5c2921b0SApple OSS Distributions    130: "SEP",
59*5c2921b0SApple OSS Distributions    131: "ISP",
60*5c2921b0SApple OSS Distributions    132: "OSCAR",
61*5c2921b0SApple OSS Distributions    133: "EMBEDDEDGFX"
62*5c2921b0SApple OSS Distributions}
63*5c2921b0SApple OSS Distributions
64*5c2921b0SApple OSS Distributionsdef GetKdebugClassName(class_num):
65*5c2921b0SApple OSS Distributions    return (KdebugClassNames[class_num] + ' ({})'.format(class_num) if class_num in KdebugClassNames else 'unknown ({})'.format(class_num))
66*5c2921b0SApple OSS Distributions
67*5c2921b0SApple OSS Distributions@lldb_type_summary(['typefilter_t'])
68*5c2921b0SApple OSS Distributions@header('{0: <20s}'.format("class") + ' '.join(map('{:02x}'.format, list(range(0, 255, 8)))))
69*5c2921b0SApple OSS Distributionsdef GetKdebugTypefilter(typefilter):
70*5c2921b0SApple OSS Distributions    """ Summarizes the provided typefilter.
71*5c2921b0SApple OSS Distributions    """
72*5c2921b0SApple OSS Distributions    classes = 256
73*5c2921b0SApple OSS Distributions    subclasses_per_class = 256
74*5c2921b0SApple OSS Distributions
75*5c2921b0SApple OSS Distributions    # 8 bits at a time
76*5c2921b0SApple OSS Distributions    subclasses_per_element = 64
77*5c2921b0SApple OSS Distributions    cur_typefilter = cast(typefilter, 'uint64_t *')
78*5c2921b0SApple OSS Distributions    subclasses_fmts = ' '.join(['{:02x}'] * 8)
79*5c2921b0SApple OSS Distributions
80*5c2921b0SApple OSS Distributions    elements_per_class = subclasses_per_class // subclasses_per_element
81*5c2921b0SApple OSS Distributions
82*5c2921b0SApple OSS Distributions    out_str = ''
83*5c2921b0SApple OSS Distributions    for i in range(0, classes):
84*5c2921b0SApple OSS Distributions        print_class = False
85*5c2921b0SApple OSS Distributions        subclasses = [0] * elements_per_class
86*5c2921b0SApple OSS Distributions
87*5c2921b0SApple OSS Distributions        # check subclass ranges for set bits, remember those subclasses
88*5c2921b0SApple OSS Distributions        for j in range(0, elements_per_class):
89*5c2921b0SApple OSS Distributions            element = unsigned(cur_typefilter[i * elements_per_class + j])
90*5c2921b0SApple OSS Distributions            if element != 0:
91*5c2921b0SApple OSS Distributions                print_class = True
92*5c2921b0SApple OSS Distributions            if print_class:
93*5c2921b0SApple OSS Distributions                subclasses[j] = element
94*5c2921b0SApple OSS Distributions
95*5c2921b0SApple OSS Distributions        ## if any of the bits were set in a class, print the entire class
96*5c2921b0SApple OSS Distributions        if print_class:
97*5c2921b0SApple OSS Distributions            out_str += '{:<20s}'.format(GetKdebugClassName(i))
98*5c2921b0SApple OSS Distributions            for element in subclasses:
99*5c2921b0SApple OSS Distributions                # split up the 64-bit values into byte-sized pieces
100*5c2921b0SApple OSS Distributions                bytes = [unsigned((element >> i) & 0xff) for i in (0, 8, 16, 24, 32, 40, 48, 56)]
101*5c2921b0SApple OSS Distributions                out_str += subclasses_fmts.format(*bytes)
102*5c2921b0SApple OSS Distributions                out_str += ' '
103*5c2921b0SApple OSS Distributions
104*5c2921b0SApple OSS Distributions            out_str += '\n'
105*5c2921b0SApple OSS Distributions
106*5c2921b0SApple OSS Distributions    return out_str
107*5c2921b0SApple OSS Distributions
108*5c2921b0SApple OSS Distributions@lldb_command('showkdebugtypefilter')
109*5c2921b0SApple OSS Distributionsdef ShowKdebugTypefilter(cmd_args=None):
110*5c2921b0SApple OSS Distributions    """ Show the current kdebug typefilter (or the typefilter at an address)
111*5c2921b0SApple OSS Distributions
112*5c2921b0SApple OSS Distributions        usage: showkdebugtypefilter [<address>]
113*5c2921b0SApple OSS Distributions    """
114*5c2921b0SApple OSS Distributions
115*5c2921b0SApple OSS Distributions    if cmd_args:
116*5c2921b0SApple OSS Distributions        typefilter = kern.GetValueFromAddress(cmd_args[0], 'typefilter_t')
117*5c2921b0SApple OSS Distributions        if unsigned(typefilter) == 0:
118*5c2921b0SApple OSS Distributions            raise ArgumentError('argument provided is NULL')
119*5c2921b0SApple OSS Distributions
120*5c2921b0SApple OSS Distributions        print(GetKdebugTypefilter.header)
121*5c2921b0SApple OSS Distributions        print('-' * len(GetKdebugTypefilter.header))
122*5c2921b0SApple OSS Distributions
123*5c2921b0SApple OSS Distributions        print(GetKdebugTypefilter(typefilter))
124*5c2921b0SApple OSS Distributions        return
125*5c2921b0SApple OSS Distributions
126*5c2921b0SApple OSS Distributions    typefilter = kern.globals.kdbg_typefilter
127*5c2921b0SApple OSS Distributions    if unsigned(typefilter) == 0:
128*5c2921b0SApple OSS Distributions        raise ArgumentError('no argument provided and active typefilter is not set')
129*5c2921b0SApple OSS Distributions
130*5c2921b0SApple OSS Distributions    print(GetKdebugTypefilter.header)
131*5c2921b0SApple OSS Distributions    print('-' * len(GetKdebugTypefilter.header))
132*5c2921b0SApple OSS Distributions    print(GetKdebugTypefilter(typefilter))
133*5c2921b0SApple OSS Distributions
134*5c2921b0SApple OSS Distributionsdef GetKdebugStatus():
135*5c2921b0SApple OSS Distributions    """ Get a string summary of the kdebug subsystem.
136*5c2921b0SApple OSS Distributions    """
137*5c2921b0SApple OSS Distributions    out = ''
138*5c2921b0SApple OSS Distributions
139*5c2921b0SApple OSS Distributions    kdc_flags = kern.globals.kd_control_trace.kdc_flags
140*5c2921b0SApple OSS Distributions    out += 'kdebug flags: {}\n'.format(xnudefines.GetStateString(xnudefines.kdebug_flags_strings, kdc_flags))
141*5c2921b0SApple OSS Distributions    events = kern.globals.kd_buffer_trace.kdb_event_count
142*5c2921b0SApple OSS Distributions    buf_mb = events * (64 if kern.arch == 'x86_64' or kern.arch.startswith('arm64') else 32) // 1000000
143*5c2921b0SApple OSS Distributions    out += 'events allocated: {:<d} ({:<d} MB)\n'.format(events, buf_mb)
144*5c2921b0SApple OSS Distributions    out += 'enabled: {}\n'.format('yes' if kern.globals.kdebug_enable != 0 else 'no')
145*5c2921b0SApple OSS Distributions    if kdc_flags & xnudefines.KDBG_TYPEFILTER_CHECK:
146*5c2921b0SApple OSS Distributions        out += 'typefilter:\n'
147*5c2921b0SApple OSS Distributions        out += GetKdebugTypefilter.header + '\n'
148*5c2921b0SApple OSS Distributions        out += '-' * len(GetKdebugTypefilter.header) + '\n'
149*5c2921b0SApple OSS Distributions        typefilter = kern.globals.kdbg_typefilter
150*5c2921b0SApple OSS Distributions        if unsigned(typefilter) != 0:
151*5c2921b0SApple OSS Distributions            out += GetKdebugTypefilter(typefilter)
152*5c2921b0SApple OSS Distributions
153*5c2921b0SApple OSS Distributions    return out
154*5c2921b0SApple OSS Distributions
155*5c2921b0SApple OSS Distributions@lldb_command('showkdebug')
156*5c2921b0SApple OSS Distributionsdef ShowKdebug(cmd_args=None):
157*5c2921b0SApple OSS Distributions    """ Show the current kdebug state.
158*5c2921b0SApple OSS Distributions
159*5c2921b0SApple OSS Distributions        usage: showkdebug
160*5c2921b0SApple OSS Distributions    """
161*5c2921b0SApple OSS Distributions
162*5c2921b0SApple OSS Distributions    print(GetKdebugStatus())
163*5c2921b0SApple OSS Distributions
164*5c2921b0SApple OSS Distributions@lldb_type_summary(['kperf_timer'])
165*5c2921b0SApple OSS Distributions@header('{:<10s} {:<7s} {:<20s} {:<20s}'.format('period-ns', 'action', 'deadline', 'fire-time'))
166*5c2921b0SApple OSS Distributionsdef GetKperfTimerSummary(timer):
167*5c2921b0SApple OSS Distributions    """ Get a string summary of a kperf timer.
168*5c2921b0SApple OSS Distributions
169*5c2921b0SApple OSS Distributions        params:
170*5c2921b0SApple OSS Distributions            timer: the kptimer object to get a summary of
171*5c2921b0SApple OSS Distributions    """
172*5c2921b0SApple OSS Distributions    try:
173*5c2921b0SApple OSS Distributions        fire_time = timer.kt_fire_time
174*5c2921b0SApple OSS Distributions    except:
175*5c2921b0SApple OSS Distributions        fire_time = 0
176*5c2921b0SApple OSS Distributions    return '{:<10d} {:<7d} {:<20d} {:<20d}\n'.format(
177*5c2921b0SApple OSS Distributions        kern.GetNanotimeFromAbstime(timer.kt_period_abs), timer.kt_actionid,
178*5c2921b0SApple OSS Distributions        timer.kt_cur_deadline, fire_time)
179*5c2921b0SApple OSS Distributions
180*5c2921b0SApple OSS Distributions@lldb_type_summary(['action'])
181*5c2921b0SApple OSS Distributions@header('{:<10s} {:<20s} {:<20s}'.format('pid-filter', 'user-data', 'samplers'))
182*5c2921b0SApple OSS Distributionsdef GetKperfActionSummary(action):
183*5c2921b0SApple OSS Distributions    """ Get a string summary of a kperf action.
184*5c2921b0SApple OSS Distributions
185*5c2921b0SApple OSS Distributions        params:
186*5c2921b0SApple OSS Distributions            action: the action object to get a summary of
187*5c2921b0SApple OSS Distributions    """
188*5c2921b0SApple OSS Distributions    samplers = xnudefines.GetStateString(xnudefines.kperf_samplers_strings, action.sample)
189*5c2921b0SApple OSS Distributions    return '{:<10s} {:<20x} {:<20s}\n'.format(
190*5c2921b0SApple OSS Distributions        '-' if action.pid_filter < 0 else str(action.pid_filter), action.userdata, samplers)
191*5c2921b0SApple OSS Distributions
192*5c2921b0SApple OSS Distributionsdef GetKperfKdebugFilterDescription():
193*5c2921b0SApple OSS Distributions    kdebug_filter = kern.globals.kperf_kdebug_filter
194*5c2921b0SApple OSS Distributions    desc = ''
195*5c2921b0SApple OSS Distributions    for i in range(kdebug_filter.n_debugids):
196*5c2921b0SApple OSS Distributions        filt_index = 1 if i >= 16 else 0
197*5c2921b0SApple OSS Distributions        filt_type = (kdebug_filter.types[filt_index] >> ((i % 16) * 4)) & 0xf
198*5c2921b0SApple OSS Distributions        debugid = kdebug_filter.debugids[i]
199*5c2921b0SApple OSS Distributions        if filt_type < 2:
200*5c2921b0SApple OSS Distributions            prefix = 'C'
201*5c2921b0SApple OSS Distributions            width = 2
202*5c2921b0SApple OSS Distributions            id = debugid >> 24
203*5c2921b0SApple OSS Distributions        elif filt_type < 4:
204*5c2921b0SApple OSS Distributions            prefix = 'S'
205*5c2921b0SApple OSS Distributions            width = 4
206*5c2921b0SApple OSS Distributions            id = debugid >> 16
207*5c2921b0SApple OSS Distributions        else:
208*5c2921b0SApple OSS Distributions            prefix = 'D'
209*5c2921b0SApple OSS Distributions            width = 8
210*5c2921b0SApple OSS Distributions            id = debugid
211*5c2921b0SApple OSS Distributions
212*5c2921b0SApple OSS Distributions        suffix = ''
213*5c2921b0SApple OSS Distributions        if (filt_type % 2) == 1:
214*5c2921b0SApple OSS Distributions            if debugid & xnudefines.DBG_FUNC_START:
215*5c2921b0SApple OSS Distributions                suffix = 's'
216*5c2921b0SApple OSS Distributions            elif debugid & xnudefines.DBG_FUNC_END:
217*5c2921b0SApple OSS Distributions                suffix = 'r'
218*5c2921b0SApple OSS Distributions            else:
219*5c2921b0SApple OSS Distributions                suffix = 'n'
220*5c2921b0SApple OSS Distributions
221*5c2921b0SApple OSS Distributions        if i > 0:
222*5c2921b0SApple OSS Distributions            desc += ','
223*5c2921b0SApple OSS Distributions        desc += '{prefix}{id:0{width}x}{suffix}'.format(
224*5c2921b0SApple OSS Distributions                prefix=prefix, id=id, width=width, suffix=suffix)
225*5c2921b0SApple OSS Distributions
226*5c2921b0SApple OSS Distributions    return desc
227*5c2921b0SApple OSS Distributions
228*5c2921b0SApple OSS Distributionsdef GetKperfStatus():
229*5c2921b0SApple OSS Distributions    """ Get a string summary of the kperf subsystem.
230*5c2921b0SApple OSS Distributions    """
231*5c2921b0SApple OSS Distributions    out = ''
232*5c2921b0SApple OSS Distributions
233*5c2921b0SApple OSS Distributions    kperf_status = int(kern.globals.kperf_status)
234*5c2921b0SApple OSS Distributions    out += 'sampling: '
235*5c2921b0SApple OSS Distributions    if kperf_status == GetEnumValue('kperf_sampling::KPERF_SAMPLING_OFF'):
236*5c2921b0SApple OSS Distributions        out += 'off\n'
237*5c2921b0SApple OSS Distributions    elif kperf_status == GetEnumValue('kperf_sampling::KPERF_SAMPLING_SHUTDOWN'):
238*5c2921b0SApple OSS Distributions        out += 'shutting down\n'
239*5c2921b0SApple OSS Distributions    elif kperf_status == GetEnumValue('kperf_sampling::KPERF_SAMPLING_ON'):
240*5c2921b0SApple OSS Distributions        out += 'on\n'
241*5c2921b0SApple OSS Distributions    else:
242*5c2921b0SApple OSS Distributions        out += 'unknown\n'
243*5c2921b0SApple OSS Distributions
244*5c2921b0SApple OSS Distributions    pet = kern.globals.kptimer.g_pet_active
245*5c2921b0SApple OSS Distributions    pet_timer_id = kern.globals.kptimer.g_pet_active
246*5c2921b0SApple OSS Distributions    if pet != 0:
247*5c2921b0SApple OSS Distributions        pet_idle_rate = kern.globals.pet_idle_rate
248*5c2921b0SApple OSS Distributions        out += 'legacy PET is active (timer = {:<d}, idle rate = {:<d})\n'.format(pet_timer_id, pet_idle_rate)
249*5c2921b0SApple OSS Distributions    else:
250*5c2921b0SApple OSS Distributions        out += 'legacy PET is off\n'
251*5c2921b0SApple OSS Distributions
252*5c2921b0SApple OSS Distributions    lw_pet = kern.globals.kppet.g_lightweight
253*5c2921b0SApple OSS Distributions    if lw_pet != 0:
254*5c2921b0SApple OSS Distributions        lw_pet_gen = kern.globals.kppet_gencount
255*5c2921b0SApple OSS Distributions        out += 'lightweight PET is active (timer = {:<d}, generation count = {:<d})\n'.format(pet_timer_id, lw_pet_gen)
256*5c2921b0SApple OSS Distributions    else:
257*5c2921b0SApple OSS Distributions        out += 'lightweight PET is off\n'
258*5c2921b0SApple OSS Distributions
259*5c2921b0SApple OSS Distributions    actions = kern.globals.actionc
260*5c2921b0SApple OSS Distributions    actions_arr = kern.globals.actionv
261*5c2921b0SApple OSS Distributions
262*5c2921b0SApple OSS Distributions    out += 'actions:\n'
263*5c2921b0SApple OSS Distributions    out += '{:<5s} '.format('id') + GetKperfActionSummary.header + '\n'
264*5c2921b0SApple OSS Distributions    for i in range(0, actions):
265*5c2921b0SApple OSS Distributions        out += '{:<5d} '.format(i) + GetKperfActionSummary(actions_arr[i])
266*5c2921b0SApple OSS Distributions
267*5c2921b0SApple OSS Distributions    timers = kern.globals.kptimer.g_ntimers
268*5c2921b0SApple OSS Distributions    timers_arr = kern.globals.kptimer.g_timers
269*5c2921b0SApple OSS Distributions
270*5c2921b0SApple OSS Distributions    out += 'timers:\n'
271*5c2921b0SApple OSS Distributions    out += '{:<5s} '.format('id') + GetKperfTimerSummary.header + '\n'
272*5c2921b0SApple OSS Distributions    for i in range(0, timers):
273*5c2921b0SApple OSS Distributions        out += '{:<5d} '.format(i) + GetKperfTimerSummary(timers_arr[i])
274*5c2921b0SApple OSS Distributions
275*5c2921b0SApple OSS Distributions    return out
276*5c2921b0SApple OSS Distributions
277*5c2921b0SApple OSS Distributions
278*5c2921b0SApple OSS Distributionsdef GetKtraceStatus():
279*5c2921b0SApple OSS Distributions    """ Get a string summary of the ktrace subsystem.
280*5c2921b0SApple OSS Distributions    """
281*5c2921b0SApple OSS Distributions    out = ''
282*5c2921b0SApple OSS Distributions
283*5c2921b0SApple OSS Distributions    state = kern.globals.ktrace_state
284*5c2921b0SApple OSS Distributions    if state == GetEnumValue('ktrace_state_t::KTRACE_STATE_OFF'):
285*5c2921b0SApple OSS Distributions        out += 'ktrace is off\n'
286*5c2921b0SApple OSS Distributions    else:
287*5c2921b0SApple OSS Distributions        out += 'ktrace is active ('
288*5c2921b0SApple OSS Distributions        if state == GetEnumValue('ktrace_state_t::KTRACE_STATE_FG'):
289*5c2921b0SApple OSS Distributions            out += 'foreground)'
290*5c2921b0SApple OSS Distributions        else:
291*5c2921b0SApple OSS Distributions            out += 'background)'
292*5c2921b0SApple OSS Distributions        out += '\n'
293*5c2921b0SApple OSS Distributions        owner = kern.globals.ktrace_last_owner_execname
294*5c2921b0SApple OSS Distributions        owner_pid = kern.globals.ktrace_owning_pid
295*5c2921b0SApple OSS Distributions        out += 'owned by: {:<s} [{}]\n'.format(owner, unsigned(owner_pid))
296*5c2921b0SApple OSS Distributions        active_mask = kern.globals.ktrace_active_mask
297*5c2921b0SApple OSS Distributions        out += 'active systems: {:<#x}\n'.format(active_mask)
298*5c2921b0SApple OSS Distributions
299*5c2921b0SApple OSS Distributions    return out
300*5c2921b0SApple OSS Distributions
301*5c2921b0SApple OSS Distributions
302*5c2921b0SApple OSS Distributionsdef GetKtraceConfig():
303*5c2921b0SApple OSS Distributions    kdebug_state = 0
304*5c2921b0SApple OSS Distributions    if (kern.globals.kd_control_trace.kdc_flags & xnudefines.KDBG_BUFINIT) != 0:
305*5c2921b0SApple OSS Distributions        kdebug_state = 1
306*5c2921b0SApple OSS Distributions    if kern.globals.kdebug_enable:
307*5c2921b0SApple OSS Distributions        kdebug_state = 3
308*5c2921b0SApple OSS Distributions    kdebug_wrapping = True
309*5c2921b0SApple OSS Distributions    if (kern.globals.kd_control_trace.kdc_live_flags & xnudefines.KDBG_NOWRAP):
310*5c2921b0SApple OSS Distributions        kdebug_wrapping = False
311*5c2921b0SApple OSS Distributions
312*5c2921b0SApple OSS Distributions    kperf_state = 3 if (
313*5c2921b0SApple OSS Distributions            unsigned(kern.globals.kperf_status) ==
314*5c2921b0SApple OSS Distributions            GetEnumValue('kperf_sampling::KPERF_SAMPLING_ON')) else 0
315*5c2921b0SApple OSS Distributions
316*5c2921b0SApple OSS Distributions    action_count = kern.globals.actionc
317*5c2921b0SApple OSS Distributions    actions = kern.globals.actionv
318*5c2921b0SApple OSS Distributions    action_samplers = []
319*5c2921b0SApple OSS Distributions    action_user_datas = []
320*5c2921b0SApple OSS Distributions    action_pid_filters = []
321*5c2921b0SApple OSS Distributions    for i in range(action_count):
322*5c2921b0SApple OSS Distributions        action = actions[i]
323*5c2921b0SApple OSS Distributions        action_samplers.append(unsigned(action.sample))
324*5c2921b0SApple OSS Distributions        action_user_datas.append(unsigned(action.userdata))
325*5c2921b0SApple OSS Distributions        action_pid_filters.append(unsigned(action.pid_filter))
326*5c2921b0SApple OSS Distributions
327*5c2921b0SApple OSS Distributions    timer_count = kern.globals.kptimer.g_ntimers
328*5c2921b0SApple OSS Distributions    timers = kern.globals.kptimer.g_timers
329*5c2921b0SApple OSS Distributions    timer_actions = []
330*5c2921b0SApple OSS Distributions    timer_periods_ns = []
331*5c2921b0SApple OSS Distributions
332*5c2921b0SApple OSS Distributions    for i in range(timer_count):
333*5c2921b0SApple OSS Distributions        timer = timers[i]
334*5c2921b0SApple OSS Distributions        timer_actions.append(unsigned(timer.kt_actionid))
335*5c2921b0SApple OSS Distributions        timer_periods_ns.append(
336*5c2921b0SApple OSS Distributions            kern.GetNanotimeFromAbstime(unsigned(timer.kt_period_abs)))
337*5c2921b0SApple OSS Distributions
338*5c2921b0SApple OSS Distributions    pet_mode = 0
339*5c2921b0SApple OSS Distributions    if kern.globals.kppet.g_lightweight:
340*5c2921b0SApple OSS Distributions        pet_mode = 2
341*5c2921b0SApple OSS Distributions    elif kern.globals.kptimer.g_pet_active:
342*5c2921b0SApple OSS Distributions        pet_mode = 1
343*5c2921b0SApple OSS Distributions
344*5c2921b0SApple OSS Distributions    return {
345*5c2921b0SApple OSS Distributions        'owner_name': str(kern.globals.ktrace_last_owner_execname),
346*5c2921b0SApple OSS Distributions        'owner_kind': unsigned(kern.globals.ktrace_state),
347*5c2921b0SApple OSS Distributions        'owner_pid': int(kern.globals.ktrace_owning_pid),
348*5c2921b0SApple OSS Distributions
349*5c2921b0SApple OSS Distributions        'kdebug_state': kdebug_state,
350*5c2921b0SApple OSS Distributions        'kdebug_buffer_size': unsigned(kern.globals.kd_buffer_trace.kdb_event_count),
351*5c2921b0SApple OSS Distributions        'kdebug_typefilter': plist_data(struct.pack('B', 0xff) * 4096 * 2), # XXX
352*5c2921b0SApple OSS Distributions        'kdebug_procfilt_mode': 0, # XXX
353*5c2921b0SApple OSS Distributions        'kdebug_procfilt': [], # XXX
354*5c2921b0SApple OSS Distributions        'kdebug_wrapping': kdebug_wrapping,
355*5c2921b0SApple OSS Distributions
356*5c2921b0SApple OSS Distributions        'kperf_state': kperf_state,
357*5c2921b0SApple OSS Distributions        'kperf_actions_sampler': action_samplers,
358*5c2921b0SApple OSS Distributions        'kperf_actions_user_data': action_user_datas,
359*5c2921b0SApple OSS Distributions        'kperf_actions_pid_filter': action_pid_filters,
360*5c2921b0SApple OSS Distributions        'kperf_timers_action_id': timer_actions,
361*5c2921b0SApple OSS Distributions        'kperf_timers_period_ns': timer_periods_ns,
362*5c2921b0SApple OSS Distributions        'kperf_pet_mode': pet_mode,
363*5c2921b0SApple OSS Distributions        'kperf_pet_timer_id': unsigned(kern.globals.kptimer.g_pet_timerid),
364*5c2921b0SApple OSS Distributions        'kperf_pet_idle_rate': unsigned(kern.globals.kppet.g_idle_rate),
365*5c2921b0SApple OSS Distributions
366*5c2921b0SApple OSS Distributions        'kperf_kdebug_action_id': unsigned(kern.globals.kperf_kdebug_action),
367*5c2921b0SApple OSS Distributions        'kperf_kdebug_filter': GetKperfKdebugFilterDescription(),
368*5c2921b0SApple OSS Distributions
369*5c2921b0SApple OSS Distributions        # XXX
370*5c2921b0SApple OSS Distributions        'kpc_state': 0,
371*5c2921b0SApple OSS Distributions        'kpc_classes': 0,
372*5c2921b0SApple OSS Distributions        'kpc_thread_classes': 0,
373*5c2921b0SApple OSS Distributions        'kpc_periods': [],
374*5c2921b0SApple OSS Distributions        'kpc_action_ids': [],
375*5c2921b0SApple OSS Distributions        'kpc_config': [],
376*5c2921b0SApple OSS Distributions
377*5c2921b0SApple OSS Distributions        'context_kind': 2, # backwards-facing
378*5c2921b0SApple OSS Distributions        'reason': 'core file debugging',
379*5c2921b0SApple OSS Distributions        'command': '(lldb) savekdebugtrace',
380*5c2921b0SApple OSS Distributions        'trigger_kind': 2, # diagnostics trigger
381*5c2921b0SApple OSS Distributions    }
382*5c2921b0SApple OSS Distributions
383*5c2921b0SApple OSS Distributions
384*5c2921b0SApple OSS Distributions@lldb_command('showktrace')
385*5c2921b0SApple OSS Distributionsdef ShowKtrace(cmd_args=None):
386*5c2921b0SApple OSS Distributions    """ Show the current ktrace state, including subsystems.
387*5c2921b0SApple OSS Distributions
388*5c2921b0SApple OSS Distributions        usage: showktrace
389*5c2921b0SApple OSS Distributions    """
390*5c2921b0SApple OSS Distributions
391*5c2921b0SApple OSS Distributions    print(GetKtraceStatus())
392*5c2921b0SApple OSS Distributions    print(' ')
393*5c2921b0SApple OSS Distributions    print('kdebug:')
394*5c2921b0SApple OSS Distributions    print(GetKdebugStatus())
395*5c2921b0SApple OSS Distributions    print(' ')
396*5c2921b0SApple OSS Distributions    print('kperf:')
397*5c2921b0SApple OSS Distributions    print(GetKperfStatus())
398*5c2921b0SApple OSS Distributions
399*5c2921b0SApple OSS Distributions
400*5c2921b0SApple OSS Distributionsclass KDEvent(object):
401*5c2921b0SApple OSS Distributions    """
402*5c2921b0SApple OSS Distributions    Wrapper around kevent pointer that handles sorting logic.
403*5c2921b0SApple OSS Distributions    """
404*5c2921b0SApple OSS Distributions    def __init__(self, timestamp, kevent, k64):
405*5c2921b0SApple OSS Distributions        self.kevent = kevent
406*5c2921b0SApple OSS Distributions        self.timestamp = timestamp
407*5c2921b0SApple OSS Distributions        self.k64 = k64
408*5c2921b0SApple OSS Distributions
409*5c2921b0SApple OSS Distributions    def get_kevent(self):
410*5c2921b0SApple OSS Distributions        return self.kevent
411*5c2921b0SApple OSS Distributions
412*5c2921b0SApple OSS Distributions    def __eq__(self, other):
413*5c2921b0SApple OSS Distributions        return self.timestamp == other.timestamp
414*5c2921b0SApple OSS Distributions
415*5c2921b0SApple OSS Distributions    def __lt__(self, other):
416*5c2921b0SApple OSS Distributions        return self.timestamp < other.timestamp
417*5c2921b0SApple OSS Distributions
418*5c2921b0SApple OSS Distributions    def __gt__(self, other):
419*5c2921b0SApple OSS Distributions        return self.timestamp > other.timestamp
420*5c2921b0SApple OSS Distributions
421*5c2921b0SApple OSS Distributions    def __hash__(self):
422*5c2921b0SApple OSS Distributions        return hash(self.timestamp)
423*5c2921b0SApple OSS Distributions
424*5c2921b0SApple OSS Distributions
425*5c2921b0SApple OSS Distributionsclass KDCPU(object):
426*5c2921b0SApple OSS Distributions    """
427*5c2921b0SApple OSS Distributions    Represents all events from a single CPU.
428*5c2921b0SApple OSS Distributions    """
429*5c2921b0SApple OSS Distributions    def __init__(self, cpuid, k64, verbose, starting_timestamp=None):
430*5c2921b0SApple OSS Distributions        self.cpuid = cpuid
431*5c2921b0SApple OSS Distributions        self.iter_store = None
432*5c2921b0SApple OSS Distributions        self.k64 = k64
433*5c2921b0SApple OSS Distributions        self.verbose = verbose
434*5c2921b0SApple OSS Distributions        self.timestamp_mask = ((1 << 48) - 1) if not self.k64 else ~0
435*5c2921b0SApple OSS Distributions        self.last_timestamp = 0
436*5c2921b0SApple OSS Distributions
437*5c2921b0SApple OSS Distributions        kdstoreinfo = kern.globals.kd_buffer_trace.kdb_info[cpuid]
438*5c2921b0SApple OSS Distributions        self.kdstorep = kdstoreinfo.kd_list_head
439*5c2921b0SApple OSS Distributions
440*5c2921b0SApple OSS Distributions        if self.kdstorep.raw == xnudefines.KDS_PTR_NULL:
441*5c2921b0SApple OSS Distributions            # Return no events and stop at first call to __next__.
442*5c2921b0SApple OSS Distributions            return
443*5c2921b0SApple OSS Distributions
444*5c2921b0SApple OSS Distributions        self.iter_store = self.get_kdstore(self.kdstorep)
445*5c2921b0SApple OSS Distributions        skipped_storage_count = 0
446*5c2921b0SApple OSS Distributions        if starting_timestamp:
447*5c2921b0SApple OSS Distributions            while True:
448*5c2921b0SApple OSS Distributions                newest_event = addressof(self.iter_store.kds_records[xnudefines.EVENTS_PER_STORAGE_UNIT - 1])
449*5c2921b0SApple OSS Distributions                timestamp = unsigned(newest_event.timestamp) & self.timestamp_mask
450*5c2921b0SApple OSS Distributions                if timestamp >= starting_timestamp:
451*5c2921b0SApple OSS Distributions                    if verbose:
452*5c2921b0SApple OSS Distributions                        print('done skipping events at time {}'.format(timestamp))
453*5c2921b0SApple OSS Distributions                    break
454*5c2921b0SApple OSS Distributions                next_store = self.iter_store.kds_next
455*5c2921b0SApple OSS Distributions                if next_store.raw == xnudefines.KDS_PTR_NULL:
456*5c2921b0SApple OSS Distributions                    if verbose:
457*5c2921b0SApple OSS Distributions                        print('found no valid events from CPU {}'.format(cpuid))
458*5c2921b0SApple OSS Distributions                    self.iter_store = None
459*5c2921b0SApple OSS Distributions                    return
460*5c2921b0SApple OSS Distributions                self.iter_store = self.get_kdstore(next_store)
461*5c2921b0SApple OSS Distributions                skipped_storage_count += 1
462*5c2921b0SApple OSS Distributions        if verbose and skipped_storage_count > 0:
463*5c2921b0SApple OSS Distributions            print('CPU {} skipped {} storage units'.format(
464*5c2921b0SApple OSS Distributions                    cpuid, skipped_storage_count))
465*5c2921b0SApple OSS Distributions
466*5c2921b0SApple OSS Distributions        # XXX Doesn't have the same logic to avoid un-mergeable events
467*5c2921b0SApple OSS Distributions        #     (respecting barrier_min and bufindx) as the C code.
468*5c2921b0SApple OSS Distributions
469*5c2921b0SApple OSS Distributions        self.iter_idx = self.iter_store.kds_readlast
470*5c2921b0SApple OSS Distributions
471*5c2921b0SApple OSS Distributions    def get_kdstore(self, kdstorep):
472*5c2921b0SApple OSS Distributions        """
473*5c2921b0SApple OSS Distributions        See POINTER_FROM_KDSPTR.
474*5c2921b0SApple OSS Distributions        """
475*5c2921b0SApple OSS Distributions        buf = kern.globals.kd_buffer_trace.kd_bufs[kdstorep.buffer_index]
476*5c2921b0SApple OSS Distributions        return addressof(buf.kdr_addr[kdstorep.offset])
477*5c2921b0SApple OSS Distributions
478*5c2921b0SApple OSS Distributions    # Event iterator implementation returns KDEvent instance
479*5c2921b0SApple OSS Distributions
480*5c2921b0SApple OSS Distributions    def __iter__(self):
481*5c2921b0SApple OSS Distributions        return self
482*5c2921b0SApple OSS Distributions
483*5c2921b0SApple OSS Distributions    def __next__(self):
484*5c2921b0SApple OSS Distributions        # This CPU is out of events.
485*5c2921b0SApple OSS Distributions        if self.iter_store is None:
486*5c2921b0SApple OSS Distributions            raise StopIteration
487*5c2921b0SApple OSS Distributions
488*5c2921b0SApple OSS Distributions        if self.iter_idx == self.iter_store.kds_bufindx:
489*5c2921b0SApple OSS Distributions            self.iter_store = None
490*5c2921b0SApple OSS Distributions            raise StopIteration
491*5c2921b0SApple OSS Distributions
492*5c2921b0SApple OSS Distributions        keventp = addressof(self.iter_store.kds_records[self.iter_idx])
493*5c2921b0SApple OSS Distributions        timestamp = unsigned(keventp.timestamp) & self.timestamp_mask
494*5c2921b0SApple OSS Distributions        if self.last_timestamp == 0 and self.verbose:
495*5c2921b0SApple OSS Distributions            print('first event from CPU {} is at time {}'.format(
496*5c2921b0SApple OSS Distributions                    self.cpuid, timestamp))
497*5c2921b0SApple OSS Distributions        self.last_timestamp = timestamp
498*5c2921b0SApple OSS Distributions
499*5c2921b0SApple OSS Distributions        # Check for writer overrun.
500*5c2921b0SApple OSS Distributions        if timestamp < self.iter_store.kds_timestamp:
501*5c2921b0SApple OSS Distributions            raise StopIteration
502*5c2921b0SApple OSS Distributions
503*5c2921b0SApple OSS Distributions        self.iter_idx += 1
504*5c2921b0SApple OSS Distributions
505*5c2921b0SApple OSS Distributions        if self.iter_idx == xnudefines.EVENTS_PER_STORAGE_UNIT:
506*5c2921b0SApple OSS Distributions            snext = self.iter_store.kds_next
507*5c2921b0SApple OSS Distributions            if snext.raw == xnudefines.KDS_PTR_NULL:
508*5c2921b0SApple OSS Distributions                # Terminate iteration in next loop. Current element is the
509*5c2921b0SApple OSS Distributions                # last one in this CPU buffer.
510*5c2921b0SApple OSS Distributions                self.iter_store = None
511*5c2921b0SApple OSS Distributions            else:
512*5c2921b0SApple OSS Distributions                self.iter_store = self.get_kdstore(snext)
513*5c2921b0SApple OSS Distributions                self.iter_idx = self.iter_store.kds_readlast
514*5c2921b0SApple OSS Distributions
515*5c2921b0SApple OSS Distributions        return KDEvent(timestamp, keventp, self.k64)
516*5c2921b0SApple OSS Distributions
517*5c2921b0SApple OSS Distributions    # Python 2 compatibility
518*5c2921b0SApple OSS Distributions    # pragma pylint: disable=next-method-defined
519*5c2921b0SApple OSS Distributions    def next(self):
520*5c2921b0SApple OSS Distributions        return self.__next__()
521*5c2921b0SApple OSS Distributions
522*5c2921b0SApple OSS Distributions
523*5c2921b0SApple OSS Distributionsdef IterateKdebugEvents(verbose=False, humanize=False, last=None,
524*5c2921b0SApple OSS Distributions        include_coprocessors=True):
525*5c2921b0SApple OSS Distributions    """
526*5c2921b0SApple OSS Distributions    Yield events from the in-memory kdebug trace buffers.
527*5c2921b0SApple OSS Distributions    """
528*5c2921b0SApple OSS Distributions    ctrl = kern.globals.kd_control_trace
529*5c2921b0SApple OSS Distributions
530*5c2921b0SApple OSS Distributions    if (ctrl.kdc_flags & xnudefines.KDBG_BUFINIT) == 0:
531*5c2921b0SApple OSS Distributions        return
532*5c2921b0SApple OSS Distributions
533*5c2921b0SApple OSS Distributions    barrier_min = ctrl.kdc_oldest_time
534*5c2921b0SApple OSS Distributions
535*5c2921b0SApple OSS Distributions    if (ctrl.kdc_live_flags & xnudefines.KDBG_WRAPPED) != 0:
536*5c2921b0SApple OSS Distributions        # TODO Yield a wrap event with the barrier_min timestamp.
537*5c2921b0SApple OSS Distributions        pass
538*5c2921b0SApple OSS Distributions
539*5c2921b0SApple OSS Distributions    k64 = kern.ptrsize == 8
540*5c2921b0SApple OSS Distributions
541*5c2921b0SApple OSS Distributions    cpu_count = kern.globals.machine_info.logical_cpu_max
542*5c2921b0SApple OSS Distributions    if include_coprocessors:
543*5c2921b0SApple OSS Distributions        cpu_count = ctrl.kdebug_cpus
544*5c2921b0SApple OSS Distributions
545*5c2921b0SApple OSS Distributions    start_timestamp = None
546*5c2921b0SApple OSS Distributions    if last is not None:
547*5c2921b0SApple OSS Distributions        (numer, denom) = GetTimebaseInfo()
548*5c2921b0SApple OSS Distributions        duration = (last * 1e9) * denom / numer
549*5c2921b0SApple OSS Distributions        now = GetRecentTimestamp()
550*5c2921b0SApple OSS Distributions        start_timestamp = unsigned(now - duration)
551*5c2921b0SApple OSS Distributions        if verbose:
552*5c2921b0SApple OSS Distributions            print('starting at time {} ({} - {})'.format(
553*5c2921b0SApple OSS Distributions                    start_timestamp, now, duration))
554*5c2921b0SApple OSS Distributions
555*5c2921b0SApple OSS Distributions    # Merge sort all events from all CPUs.
556*5c2921b0SApple OSS Distributions    cpus = [KDCPU(cpuid, k64, verbose, starting_timestamp=start_timestamp)
557*5c2921b0SApple OSS Distributions            for cpuid in range(cpu_count)]
558*5c2921b0SApple OSS Distributions    last_timestamp = 0
559*5c2921b0SApple OSS Distributions    warned = False
560*5c2921b0SApple OSS Distributions    for event in heapq.merge(*cpus):
561*5c2921b0SApple OSS Distributions        if event.timestamp < last_timestamp and not warned:
562*5c2921b0SApple OSS Distributions            # Human-readable output might have garbage on the rest of the line.
563*5c2921b0SApple OSS Distributions            # Use a CSI escape sequence to clear it out.
564*5c2921b0SApple OSS Distributions            clear_line_csi = '\033[K'
565*5c2921b0SApple OSS Distributions            print(
566*5c2921b0SApple OSS Distributions                    'warning: events seem to be out-of-order',
567*5c2921b0SApple OSS Distributions                    end=((clear_line_csi + '\n') if humanize else '\n'))
568*5c2921b0SApple OSS Distributions            warned = True
569*5c2921b0SApple OSS Distributions        last_timestamp = event.timestamp
570*5c2921b0SApple OSS Distributions        yield event.get_kevent()
571*5c2921b0SApple OSS Distributions
572*5c2921b0SApple OSS Distributions
573*5c2921b0SApple OSS Distributions@header('{:>12s} {:>10s} {:>18s} {:>18s} {:>18s} {:>18s} {:>5s} {:>8s}'.format(
574*5c2921b0SApple OSS Distributions        'timestamp', 'debugid', 'arg1', 'arg2', 'arg3', 'arg4', 'cpuid',
575*5c2921b0SApple OSS Distributions        'tid'))
576*5c2921b0SApple OSS Distributionsdef GetKdebugEvent(event, k64, symbolicate=False, O=None):
577*5c2921b0SApple OSS Distributions    """
578*5c2921b0SApple OSS Distributions    Return a string representing a kdebug trace event.
579*5c2921b0SApple OSS Distributions    """
580*5c2921b0SApple OSS Distributions    if k64:
581*5c2921b0SApple OSS Distributions        timestamp = event.timestamp & ((1 << 48) - 1)
582*5c2921b0SApple OSS Distributions        cpuid = event.timestamp >> 48
583*5c2921b0SApple OSS Distributions    else:
584*5c2921b0SApple OSS Distributions        timestamp = event.timestamp
585*5c2921b0SApple OSS Distributions        cpuid = event.cpuid
586*5c2921b0SApple OSS Distributions    def fmt_arg(a):
587*5c2921b0SApple OSS Distributions        return '0x{:016x}'.format(unsigned(a))
588*5c2921b0SApple OSS Distributions    def sym_arg(a):
589*5c2921b0SApple OSS Distributions        slid_addr = kern.globals.vm_kernel_slide + unsigned(a)
590*5c2921b0SApple OSS Distributions        syms = kern.SymbolicateFromAddress(slid_addr)
591*5c2921b0SApple OSS Distributions        return syms[0].GetName() if syms else fmt_arg(a)
592*5c2921b0SApple OSS Distributions    args = list(map(
593*5c2921b0SApple OSS Distributions            sym_arg if symbolicate else fmt_arg,
594*5c2921b0SApple OSS Distributions            [event.arg1, event.arg2, event.arg3, event.arg4]))
595*5c2921b0SApple OSS Distributions    return O.format(
596*5c2921b0SApple OSS Distributions            '{:12d} 0x{:08x} {:18s} {:18s} {:18s} {:18s} {:5d} {:8d}',
597*5c2921b0SApple OSS Distributions            unsigned(timestamp), unsigned(event.debugid),
598*5c2921b0SApple OSS Distributions            args[0], args[1], args[2], args[3], unsigned(cpuid),
599*5c2921b0SApple OSS Distributions            unsigned(event.arg5))
600*5c2921b0SApple OSS Distributions
601*5c2921b0SApple OSS Distributions
602*5c2921b0SApple OSS Distributions@lldb_command('showkdebugtrace', 'L:S', fancy=True)
603*5c2921b0SApple OSS Distributionsdef ShowKdebugTrace(cmd_args=None, cmd_options={}, O=None):
604*5c2921b0SApple OSS Distributions    """
605*5c2921b0SApple OSS Distributions    List the events present in the kdebug trace buffers.
606*5c2921b0SApple OSS Distributions
607*5c2921b0SApple OSS Distributions    (lldb) showkdebugtrace [-S] [-L <last-seconds>]
608*5c2921b0SApple OSS Distributions
609*5c2921b0SApple OSS Distributions        -L <last-seconds>: only show events from the last <last-seconds> seconds
610*5c2921b0SApple OSS Distributions        -S: attempt to symbolicate arguments as kernel addresses
611*5c2921b0SApple OSS Distributions
612*5c2921b0SApple OSS Distributions    Caveats:
613*5c2921b0SApple OSS Distributions        * Events from IOPs may be missing or cut-off -- they weren't informed
614*5c2921b0SApple OSS Distributions          of this kind of buffer collection.
615*5c2921b0SApple OSS Distributions    """
616*5c2921b0SApple OSS Distributions    k64 = kern.ptrsize == 8
617*5c2921b0SApple OSS Distributions    last = cmd_options.get('-L', None)
618*5c2921b0SApple OSS Distributions    if last:
619*5c2921b0SApple OSS Distributions        try:
620*5c2921b0SApple OSS Distributions            last = float(last)
621*5c2921b0SApple OSS Distributions        except ValueError:
622*5c2921b0SApple OSS Distributions            raise ArgumentError(
623*5c2921b0SApple OSS Distributions                    'error: -L argument must be a number, not {}'.format(last))
624*5c2921b0SApple OSS Distributions    with O.table(GetKdebugEvent.header):
625*5c2921b0SApple OSS Distributions        for event in IterateKdebugEvents(
626*5c2921b0SApple OSS Distributions                config['verbosity'] > vHUMAN, humanize=True, last=last):
627*5c2921b0SApple OSS Distributions            print(GetKdebugEvent(
628*5c2921b0SApple OSS Distributions                    event, k64, symbolicate='-S' in cmd_options, O=O))
629*5c2921b0SApple OSS Distributions
630*5c2921b0SApple OSS Distributions
631*5c2921b0SApple OSS Distributionsdef binary_plist(o):
632*5c2921b0SApple OSS Distributions    if PY2:
633*5c2921b0SApple OSS Distributions        # Python 2 lacks a convenient binary plist writer.
634*5c2921b0SApple OSS Distributions        with tempfile.NamedTemporaryFile(delete=False) as f:
635*5c2921b0SApple OSS Distributions            plistlib.writePlist(o, f)
636*5c2921b0SApple OSS Distributions            name = f.name
637*5c2921b0SApple OSS Distributions
638*5c2921b0SApple OSS Distributions        subprocess.check_output(['plutil', '-convert', 'binary1', name])
639*5c2921b0SApple OSS Distributions        with open(name, mode='rb') as f:
640*5c2921b0SApple OSS Distributions            plist = f.read()
641*5c2921b0SApple OSS Distributions
642*5c2921b0SApple OSS Distributions        os.unlink(name)
643*5c2921b0SApple OSS Distributions        return plist
644*5c2921b0SApple OSS Distributions    else:
645*5c2921b0SApple OSS Distributions        return plistlib.dumps(o, fmt=plistlib.FMT_BINARY)
646*5c2921b0SApple OSS Distributions
647*5c2921b0SApple OSS Distributions
648*5c2921b0SApple OSS Distributionsdef plist_data(d):
649*5c2921b0SApple OSS Distributions    if PY2:
650*5c2921b0SApple OSS Distributions        return plistlib.Data(d)
651*5c2921b0SApple OSS Distributions    else:
652*5c2921b0SApple OSS Distributions        return d
653*5c2921b0SApple OSS Distributions
654*5c2921b0SApple OSS Distributions
655*5c2921b0SApple OSS Distributionsdef align_next_chunk(f, offset, verbose):
656*5c2921b0SApple OSS Distributions    trailing = offset % 8
657*5c2921b0SApple OSS Distributions    padding = 0
658*5c2921b0SApple OSS Distributions    if trailing != 0:
659*5c2921b0SApple OSS Distributions        padding = 8 - trailing
660*5c2921b0SApple OSS Distributions        f.write(b'\x00' * padding)
661*5c2921b0SApple OSS Distributions        if verbose:
662*5c2921b0SApple OSS Distributions            print('aligned next chunk with {} padding bytes'.format(padding))
663*5c2921b0SApple OSS Distributions    return padding
664*5c2921b0SApple OSS Distributions
665*5c2921b0SApple OSS Distributions
666*5c2921b0SApple OSS Distributionsdef GetKtraceMachine():
667*5c2921b0SApple OSS Distributions    """
668*5c2921b0SApple OSS Distributions    This is best effort -- several fields are only available to user space or
669*5c2921b0SApple OSS Distributions    are difficult to determine from a core file.
670*5c2921b0SApple OSS Distributions    """
671*5c2921b0SApple OSS Distributions    master_cpu_data = GetCpuDataForCpuID(0)
672*5c2921b0SApple OSS Distributions    if kern.arch == 'x86_64':
673*5c2921b0SApple OSS Distributions        cpu_family = unsigned(kern.globals.cpuid_cpu_info.cpuid_cpufamily)
674*5c2921b0SApple OSS Distributions    else:
675*5c2921b0SApple OSS Distributions        cpu_family = 0 # XXX
676*5c2921b0SApple OSS Distributions
677*5c2921b0SApple OSS Distributions    k64 = kern.ptrsize == 8
678*5c2921b0SApple OSS Distributions    page_size = 4 * 4096 if k64 else 4096
679*5c2921b0SApple OSS Distributions
680*5c2921b0SApple OSS Distributions    return {
681*5c2921b0SApple OSS Distributions        'kern_version': str(kern.globals.version),
682*5c2921b0SApple OSS Distributions        'boot_args': '', # XXX
683*5c2921b0SApple OSS Distributions        'hw_memsize': unsigned(kern.globals.max_mem),
684*5c2921b0SApple OSS Distributions        'hw_pagesize': page_size, # XXX
685*5c2921b0SApple OSS Distributions        'vm_pagesize': page_size, # XXX
686*5c2921b0SApple OSS Distributions        'os_name': 'Unknown', # XXX
687*5c2921b0SApple OSS Distributions        'os_version': 'Unknown', # XXX
688*5c2921b0SApple OSS Distributions        'os_build': str(kern.globals.osversion),
689*5c2921b0SApple OSS Distributions        'arch': 'Unknown', # XXX
690*5c2921b0SApple OSS Distributions        'hw_model': 'Unknown', # XXX
691*5c2921b0SApple OSS Distributions        'cpu_type': unsigned(master_cpu_data.cpu_type),
692*5c2921b0SApple OSS Distributions        'cpu_subtype': unsigned(master_cpu_data.cpu_subtype),
693*5c2921b0SApple OSS Distributions        'cpu_family': cpu_family,
694*5c2921b0SApple OSS Distributions        'active_cpus': unsigned(kern.globals.processor_avail_count),
695*5c2921b0SApple OSS Distributions        'max_cpus': unsigned(kern.globals.machine_info.logical_cpu_max),
696*5c2921b0SApple OSS Distributions        'apple_internal': True, # XXX
697*5c2921b0SApple OSS Distributions    }
698*5c2921b0SApple OSS Distributions
699*5c2921b0SApple OSS Distributions
700*5c2921b0SApple OSS DistributionsCHUNKHDR_PACK = 'IHHQ'
701*5c2921b0SApple OSS Distributions
702*5c2921b0SApple OSS Distributions
703*5c2921b0SApple OSS Distributionsdef append_chunk(f, file_offset, tag, major, minor, data, verbose):
704*5c2921b0SApple OSS Distributions    f.write(struct.pack(CHUNKHDR_PACK, tag, major, minor, len(data)))
705*5c2921b0SApple OSS Distributions    f.write(data)
706*5c2921b0SApple OSS Distributions    offset = 16 + len(data)
707*5c2921b0SApple OSS Distributions    return offset + align_next_chunk(f, file_offset + offset, verbose)
708*5c2921b0SApple OSS Distributions
709*5c2921b0SApple OSS Distributions
710*5c2921b0SApple OSS Distributions@lldb_command('savekdebugtrace', 'IL:MN:')
711*5c2921b0SApple OSS Distributionsdef SaveKdebugTrace(cmd_args=None, cmd_options={}):
712*5c2921b0SApple OSS Distributions    """
713*5c2921b0SApple OSS Distributions    Save any valid ktrace events to a file.
714*5c2921b0SApple OSS Distributions
715*5c2921b0SApple OSS Distributions    (lldb) savekdebugtrace [-IM] [-N <n-events> | -L <last-secs>] <output-path>
716*5c2921b0SApple OSS Distributions
717*5c2921b0SApple OSS Distributions        -I: ignore coprocessor (IOP) events entirely
718*5c2921b0SApple OSS Distributions        -L <last-seconds>: only save events from the <last-seconds> seconds
719*5c2921b0SApple OSS Distributions        -N <n-events>: only save the last <n-events> events
720*5c2921b0SApple OSS Distributions        -M: ensure output is machine-friendly
721*5c2921b0SApple OSS Distributions
722*5c2921b0SApple OSS Distributions    Tips:
723*5c2921b0SApple OSS Distributions        * To speed up the process, use the -I and -L options to avoid
724*5c2921b0SApple OSS Distributions          processing events based on source or time.
725*5c2921b0SApple OSS Distributions
726*5c2921b0SApple OSS Distributions    Caveats:
727*5c2921b0SApple OSS Distributions        * Fewer than the requested number of events may end up in the file.
728*5c2921b0SApple OSS Distributions        * The machine and config chunks may be missing crucial information
729*5c2921b0SApple OSS Distributions          required for tools to analyze them.
730*5c2921b0SApple OSS Distributions        * Events from coprocessors may be missing or cut-off -- they weren't
731*5c2921b0SApple OSS Distributions          informed of this kind of buffer collection.
732*5c2921b0SApple OSS Distributions        * Chunks related to post-processing, like symbolication data or a
733*5c2921b0SApple OSS Distributions          catalog will need to be added manually.
734*5c2921b0SApple OSS Distributions    """
735*5c2921b0SApple OSS Distributions
736*5c2921b0SApple OSS Distributions    k64 = kern.ptrsize == 8
737*5c2921b0SApple OSS Distributions
738*5c2921b0SApple OSS Distributions    if len(cmd_args) != 1:
739*5c2921b0SApple OSS Distributions        raise ArgumentError('error: path to trace file is required')
740*5c2921b0SApple OSS Distributions
741*5c2921b0SApple OSS Distributions    last = cmd_options.get('-L', None)
742*5c2921b0SApple OSS Distributions    if last and '-N' in cmd_options:
743*5c2921b0SApple OSS Distributions        raise ArgumentError('error: -L and -N are mutually exclusive')
744*5c2921b0SApple OSS Distributions    if last:
745*5c2921b0SApple OSS Distributions        try:
746*5c2921b0SApple OSS Distributions            last = float(last)
747*5c2921b0SApple OSS Distributions        except ValueError:
748*5c2921b0SApple OSS Distributions            raise ArgumentError(
749*5c2921b0SApple OSS Distributions                    'error: -L argument must be a number, not {}'.format(last))
750*5c2921b0SApple OSS Distributions
751*5c2921b0SApple OSS Distributions    nevents = unsigned(kern.globals.kd_buffer_trace.kdb_event_count)
752*5c2921b0SApple OSS Distributions    if nevents == 0:
753*5c2921b0SApple OSS Distributions        print('error: kdebug buffers are not set up')
754*5c2921b0SApple OSS Distributions        return
755*5c2921b0SApple OSS Distributions
756*5c2921b0SApple OSS Distributions    limit_nevents = nevents
757*5c2921b0SApple OSS Distributions    if '-N' in cmd_options:
758*5c2921b0SApple OSS Distributions        limit_nevents = unsigned(cmd_options['-N'])
759*5c2921b0SApple OSS Distributions        if limit_nevents > nevents:
760*5c2921b0SApple OSS Distributions            limit_nevents = nevents
761*5c2921b0SApple OSS Distributions    verbose = config['verbosity'] > vHUMAN
762*5c2921b0SApple OSS Distributions    humanize = '-M' not in cmd_options
763*5c2921b0SApple OSS Distributions
764*5c2921b0SApple OSS Distributions    file_offset = 0
765*5c2921b0SApple OSS Distributions    with open(cmd_args[0], 'w+b') as f:
766*5c2921b0SApple OSS Distributions        FILE_MAGIC = 0x55aa0300
767*5c2921b0SApple OSS Distributions        EVENTS_TAG = 0x00001e00
768*5c2921b0SApple OSS Distributions        SSHOT_TAG = 0x8002
769*5c2921b0SApple OSS Distributions        CONFIG_TAG = 0x8006
770*5c2921b0SApple OSS Distributions        MACHINE_TAG = 0x8c00
771*5c2921b0SApple OSS Distributions        CHUNKHDR_PACK = 'IHHQ'
772*5c2921b0SApple OSS Distributions        FILEHDR_PACK = CHUNKHDR_PACK + 'IIQQIIII'
773*5c2921b0SApple OSS Distributions        FILEHDR_SIZE = 40
774*5c2921b0SApple OSS Distributions        FUTURE_SIZE = 8
775*5c2921b0SApple OSS Distributions
776*5c2921b0SApple OSS Distributions        numer, denom = GetTimebaseInfo()
777*5c2921b0SApple OSS Distributions
778*5c2921b0SApple OSS Distributions        # XXX The kernel doesn't have a solid concept of the wall time.
779*5c2921b0SApple OSS Distributions        wall_abstime = 0
780*5c2921b0SApple OSS Distributions        wall_secs = 0
781*5c2921b0SApple OSS Distributions        wall_usecs = 0
782*5c2921b0SApple OSS Distributions
783*5c2921b0SApple OSS Distributions        event_size = 64 if k64 else 32
784*5c2921b0SApple OSS Distributions
785*5c2921b0SApple OSS Distributions        file_hdr = struct.pack(
786*5c2921b0SApple OSS Distributions                FILEHDR_PACK, FILE_MAGIC, 0, 0, FILEHDR_SIZE,
787*5c2921b0SApple OSS Distributions                numer, denom, wall_abstime, wall_secs, wall_usecs, 0, 0,
788*5c2921b0SApple OSS Distributions                0x1 if k64 else 0)
789*5c2921b0SApple OSS Distributions        f.write(file_hdr)
790*5c2921b0SApple OSS Distributions        header_size_offset = file_offset + 8
791*5c2921b0SApple OSS Distributions        file_offset += 16 + FILEHDR_SIZE # chunk header plus file header
792*5c2921b0SApple OSS Distributions
793*5c2921b0SApple OSS Distributions        if verbose:
794*5c2921b0SApple OSS Distributions            print('writing machine chunk at offset 0x{:x}'.format(file_offset))
795*5c2921b0SApple OSS Distributions        machine_data = GetKtraceMachine()
796*5c2921b0SApple OSS Distributions        machine_bytes = binary_plist(machine_data)
797*5c2921b0SApple OSS Distributions        file_offset += append_chunk(
798*5c2921b0SApple OSS Distributions                f, file_offset, MACHINE_TAG, 0, 0, machine_bytes, verbose)
799*5c2921b0SApple OSS Distributions
800*5c2921b0SApple OSS Distributions        if verbose:
801*5c2921b0SApple OSS Distributions            print('writing config chunk at offset 0x{:x}'.format(file_offset))
802*5c2921b0SApple OSS Distributions        config_data = GetKtraceConfig()
803*5c2921b0SApple OSS Distributions        config_bytes = binary_plist(config_data)
804*5c2921b0SApple OSS Distributions        file_offset += append_chunk(
805*5c2921b0SApple OSS Distributions                f, file_offset, CONFIG_TAG, 0, 0, config_bytes, verbose)
806*5c2921b0SApple OSS Distributions
807*5c2921b0SApple OSS Distributions        events_hdr = struct.pack(
808*5c2921b0SApple OSS Distributions                CHUNKHDR_PACK, EVENTS_TAG, 0, 0, 0) # size will be filled in later
809*5c2921b0SApple OSS Distributions        f.write(events_hdr)
810*5c2921b0SApple OSS Distributions        file_offset += 16 # header size
811*5c2921b0SApple OSS Distributions        event_size_offset = file_offset - FUTURE_SIZE
812*5c2921b0SApple OSS Distributions        # Future events timestamp -- doesn't need to be set for merged events.
813*5c2921b0SApple OSS Distributions        f.write(struct.pack('Q', 0))
814*5c2921b0SApple OSS Distributions        file_offset += FUTURE_SIZE
815*5c2921b0SApple OSS Distributions
816*5c2921b0SApple OSS Distributions        if verbose:
817*5c2921b0SApple OSS Distributions            print('events start at offset 0x{:x}'.format(file_offset))
818*5c2921b0SApple OSS Distributions
819*5c2921b0SApple OSS Distributions        process = LazyTarget().GetProcess()
820*5c2921b0SApple OSS Distributions        error = lldb.SBError()
821*5c2921b0SApple OSS Distributions
822*5c2921b0SApple OSS Distributions        skip_nevents = nevents - limit_nevents if limit_nevents else 0
823*5c2921b0SApple OSS Distributions        if skip_nevents > 0:
824*5c2921b0SApple OSS Distributions            print('omitting {} events from the beginning'.format(skip_nevents))
825*5c2921b0SApple OSS Distributions
826*5c2921b0SApple OSS Distributions        written_nevents = 0
827*5c2921b0SApple OSS Distributions        seen_nevents = 0
828*5c2921b0SApple OSS Distributions        start_time = time.time()
829*5c2921b0SApple OSS Distributions        update_every = 1000 if humanize else 25000
830*5c2921b0SApple OSS Distributions        for event in IterateKdebugEvents(
831*5c2921b0SApple OSS Distributions                verbose, include_coprocessors='-I' not in cmd_options,
832*5c2921b0SApple OSS Distributions                humanize=humanize, last=last):
833*5c2921b0SApple OSS Distributions            seen_nevents += 1
834*5c2921b0SApple OSS Distributions            if skip_nevents >= seen_nevents:
835*5c2921b0SApple OSS Distributions                if seen_nevents % update_every == 0:
836*5c2921b0SApple OSS Distributions                    sys.stderr.write('skipped {}/{} ({:4.2f}%) events'.format(
837*5c2921b0SApple OSS Distributions                            seen_nevents, skip_nevents,
838*5c2921b0SApple OSS Distributions                            float(seen_nevents) / skip_nevents * 100.0))
839*5c2921b0SApple OSS Distributions                    sys.stderr.write('\r')
840*5c2921b0SApple OSS Distributions
841*5c2921b0SApple OSS Distributions                continue
842*5c2921b0SApple OSS Distributions
843*5c2921b0SApple OSS Distributions            event = process.ReadMemory(
844*5c2921b0SApple OSS Distributions                    unsigned(event), event_size, error)
845*5c2921b0SApple OSS Distributions            file_offset += event_size
846*5c2921b0SApple OSS Distributions            f.write(event)
847*5c2921b0SApple OSS Distributions            written_nevents += 1
848*5c2921b0SApple OSS Distributions            # Periodically update the CLI with progress.
849*5c2921b0SApple OSS Distributions            if written_nevents % update_every == 0:
850*5c2921b0SApple OSS Distributions                sys.stderr.write('{}: wrote {}/{} ({:4.2f}%) events'.format(
851*5c2921b0SApple OSS Distributions                        time.strftime('%H:%M:%S'), written_nevents,
852*5c2921b0SApple OSS Distributions                        limit_nevents,
853*5c2921b0SApple OSS Distributions                        float(written_nevents) / nevents * 100.0))
854*5c2921b0SApple OSS Distributions                if humanize:
855*5c2921b0SApple OSS Distributions                    sys.stderr.write('\r')
856*5c2921b0SApple OSS Distributions                else:
857*5c2921b0SApple OSS Distributions                    sys.stderr.write('\n')
858*5c2921b0SApple OSS Distributions        sys.stderr.write('\n')
859*5c2921b0SApple OSS Distributions        elapsed = time.time() - start_time
860*5c2921b0SApple OSS Distributions        print('wrote {} ({}MB) events in {:.3f}s'.format(
861*5c2921b0SApple OSS Distributions                written_nevents, written_nevents * event_size >> 20, elapsed))
862*5c2921b0SApple OSS Distributions        if verbose:
863*5c2921b0SApple OSS Distributions            print('events end at offset 0x{:x}'.format(file_offset))
864*5c2921b0SApple OSS Distributions
865*5c2921b0SApple OSS Distributions        # Normally, the chunk would need to be padded to 8, but events are
866*5c2921b0SApple OSS Distributions        # already aligned.
867*5c2921b0SApple OSS Distributions
868*5c2921b0SApple OSS Distributions        kcdata = kern.globals.kc_panic_data
869*5c2921b0SApple OSS Distributions        kcdata_addr = unsigned(kcdata.kcd_addr_begin)
870*5c2921b0SApple OSS Distributions        kcdata_length = unsigned(kcdata.kcd_length)
871*5c2921b0SApple OSS Distributions        if kcdata_addr != 0 and kcdata_length != 0:
872*5c2921b0SApple OSS Distributions            print('writing stackshot')
873*5c2921b0SApple OSS Distributions            if verbose:
874*5c2921b0SApple OSS Distributions                print('stackshot is 0x{:x} bytes at offset 0x{:x}'.format(
875*5c2921b0SApple OSS Distributions                        kcdata_length, file_offset))
876*5c2921b0SApple OSS Distributions            ssdata = process.ReadMemory(kcdata_addr, kcdata_length, error)
877*5c2921b0SApple OSS Distributions            magic = struct.unpack('I', ssdata[:4])
878*5c2921b0SApple OSS Distributions            if magic[0] == GetTypeForName('KCDATA_BUFFER_BEGIN_COMPRESSED'):
879*5c2921b0SApple OSS Distributions                if verbose:
880*5c2921b0SApple OSS Distributions                    print('found compressed stackshot')
881*5c2921b0SApple OSS Distributions                iterator = kcdata_item_iterator(ssdata)
882*5c2921b0SApple OSS Distributions                for item in iterator:
883*5c2921b0SApple OSS Distributions                    kcdata_buffer = KCObject.FromKCItem(item)
884*5c2921b0SApple OSS Distributions                    if isinstance(kcdata_buffer, KCCompressedBufferObject):
885*5c2921b0SApple OSS Distributions                        kcdata_buffer.ReadItems(iterator)
886*5c2921b0SApple OSS Distributions                        decompressed = kcdata_buffer.Decompress(ssdata)
887*5c2921b0SApple OSS Distributions                        ssdata = decompressed
888*5c2921b0SApple OSS Distributions                        kcdata_length = len(ssdata)
889*5c2921b0SApple OSS Distributions                        if verbose:
890*5c2921b0SApple OSS Distributions                            print(
891*5c2921b0SApple OSS Distributions                                    'compressed stackshot is 0x{:x} bytes long'.
892*5c2921b0SApple OSS Distributions                                    format(kcdata_length))
893*5c2921b0SApple OSS Distributions
894*5c2921b0SApple OSS Distributions            file_offset += append_chunk(
895*5c2921b0SApple OSS Distributions                    f, file_offset, SSHOT_TAG, 1, 0, ssdata, verbose)
896*5c2921b0SApple OSS Distributions            if verbose:
897*5c2921b0SApple OSS Distributions                print('stackshot ends at offset 0x{:x}'.format(file_offset))
898*5c2921b0SApple OSS Distributions        else:
899*5c2921b0SApple OSS Distributions            print('warning: no stackshot; trace file may not be usable')
900*5c2921b0SApple OSS Distributions
901*5c2921b0SApple OSS Distributions        # After the number of events is known, fix up the events chunk size.
902*5c2921b0SApple OSS Distributions        events_data_size = unsigned(written_nevents * event_size) + FUTURE_SIZE
903*5c2921b0SApple OSS Distributions        f.seek(event_size_offset)
904*5c2921b0SApple OSS Distributions        f.write(struct.pack('Q', events_data_size))
905*5c2921b0SApple OSS Distributions        if verbose:
906*5c2921b0SApple OSS Distributions            print('wrote {:x} bytes at offset 0x{:x} for event size'.format(
907*5c2921b0SApple OSS Distributions                    events_data_size, event_size_offset))
908*5c2921b0SApple OSS Distributions
909*5c2921b0SApple OSS Distributions        # Fix up the size of the header chunks, too.
910*5c2921b0SApple OSS Distributions        f.seek(header_size_offset)
911*5c2921b0SApple OSS Distributions        f.write(struct.pack('Q', FILEHDR_SIZE + 16 + len(machine_bytes)))
912*5c2921b0SApple OSS Distributions        if verbose:
913*5c2921b0SApple OSS Distributions            print((
914*5c2921b0SApple OSS Distributions                    'wrote 0x{:x} bytes at offset 0x{:x} for ' +
915*5c2921b0SApple OSS Distributions                    'file header size').format(
916*5c2921b0SApple OSS Distributions                    len(machine_bytes), header_size_offset))
917*5c2921b0SApple OSS Distributions
918*5c2921b0SApple OSS Distributions    return
919*5c2921b0SApple OSS Distributions
920*5c2921b0SApple OSS Distributions# Obsolete commands.
921*5c2921b0SApple OSS Distributions
922*5c2921b0SApple OSS Distributions@lldb_command('showkerneldebugbuffercpu')
923*5c2921b0SApple OSS Distributionsdef ShowKernelDebugBufferCPU(cmd_args=None):
924*5c2921b0SApple OSS Distributions    """ REMOVED: Use showkdebugtrace instead. """
925*5c2921b0SApple OSS Distributions    raise NotImplementedError("Use showkdebugtrace instead")
926*5c2921b0SApple OSS Distributions
927*5c2921b0SApple OSS Distributions
928*5c2921b0SApple OSS Distributions@lldb_command('showkerneldebugbuffer')
929*5c2921b0SApple OSS Distributionsdef ShowKernelDebugBuffer(cmd_args=None):
930*5c2921b0SApple OSS Distributions    """ REMOVED: Use showkdebugtrace instead. """
931*5c2921b0SApple OSS Distributions    raise NotImplementedError("Use showkdebugtrace instead")
932*5c2921b0SApple OSS Distributions
933*5c2921b0SApple OSS Distributions
934*5c2921b0SApple OSS Distributions@lldb_command('dumprawtracefile')
935*5c2921b0SApple OSS Distributionsdef DumpRawTraceFile(cmd_args=[], cmd_options={}):
936*5c2921b0SApple OSS Distributions    """ REMOVED: Use savekdebugtrace instead. """
937*5c2921b0SApple OSS Distributions    raise NotImplementedError("Use savekdebugtrace instead")
938*5c2921b0SApple OSS Distributions
939*5c2921b0SApple OSS Distributions
940