xref: /xnu-11417.140.69/tools/lldbmacros/kcdata.py (revision 43a90889846e00bfb5cf1d255cdc0a701a1e05a4)
1#!/usr/bin/env python3
2import sys
3import struct
4import mmap
5import json
6import copy
7import re
8import base64
9import argparse
10import logging
11import contextlib
12import zlib
13from operator import itemgetter
14
15long = int
16
17class Globals(object):
18    pass
19G = Globals()
20G.accept_incomplete_data = False
21G.data_was_incomplete = False
22
23kcdata_type_def = {
24    'KCDATA_TYPE_INVALID':              0x0,
25    'KCDATA_TYPE_STRING_DESC':          0x1,
26    'KCDATA_TYPE_UINT32_DESC':          0x2,
27    'KCDATA_TYPE_UINT64_DESC':          0x3,
28    'KCDATA_TYPE_INT32_DESC':           0x4,
29    'KCDATA_TYPE_INT64_DESC':           0x5,
30    'KCDATA_TYPE_BINDATA_DESC':         0x6,
31    'KCDATA_TYPE_ARRAY':                0x11,
32    'KCDATA_TYPE_TYPEDEFINITION':       0x12,
33    'KCDATA_TYPE_CONTAINER_BEGIN':      0x13,
34    'KCDATA_TYPE_CONTAINER_END':        0x14,
35
36    'KCDATA_TYPE_ARRAY_PAD0':           0x20,
37    'KCDATA_TYPE_ARRAY_PAD1':           0x21,
38    'KCDATA_TYPE_ARRAY_PAD2':           0x22,
39    'KCDATA_TYPE_ARRAY_PAD3':           0x23,
40    'KCDATA_TYPE_ARRAY_PAD4':           0x24,
41    'KCDATA_TYPE_ARRAY_PAD5':           0x25,
42    'KCDATA_TYPE_ARRAY_PAD6':           0x26,
43    'KCDATA_TYPE_ARRAY_PAD7':           0x27,
44    'KCDATA_TYPE_ARRAY_PAD8':           0x28,
45    'KCDATA_TYPE_ARRAY_PAD9':           0x29,
46    'KCDATA_TYPE_ARRAY_PADa':           0x2a,
47    'KCDATA_TYPE_ARRAY_PADb':           0x2b,
48    'KCDATA_TYPE_ARRAY_PADc':           0x2c,
49    'KCDATA_TYPE_ARRAY_PADd':           0x2d,
50    'KCDATA_TYPE_ARRAY_PADe':           0x2e,
51    'KCDATA_TYPE_ARRAY_PADf':           0x2f,
52
53    'KCDATA_TYPE_LIBRARY_LOADINFO':     0x30,
54    'KCDATA_TYPE_LIBRARY_LOADINFO64':   0x31,
55    'KCDATA_TYPE_TIMEBASE':             0x32,
56    'KCDATA_TYPE_MACH_ABSOLUTE_TIME':   0x33,
57    'KCDATA_TYPE_TIMEVAL':              0x34,
58    'KCDATA_TYPE_USECS_SINCE_EPOCH':    0x35,
59    'KCDATA_TYPE_PID':                  0x36,
60    'KCDATA_TYPE_PROCNAME':             0x37,
61    'KCDATA_TYPE_NESTED_KCDATA':        0x38,
62    'KCDATA_TYPE_LIBRARY_AOTINFO':      0x39,
63
64    'STACKSHOT_KCCONTAINER_TASK':       0x903,
65    'STACKSHOT_KCCONTAINER_THREAD':     0x904,
66    'STACKSHOT_KCTYPE_DONATING_PIDS':   0x907,
67    'STACKSHOT_KCTYPE_SHAREDCACHE_LOADINFO': 0x908,
68    'STACKSHOT_KCTYPE_THREAD_NAME':     0x909,
69    'STACKSHOT_KCTYPE_KERN_STACKFRAME': 0x90A,
70    'STACKSHOT_KCTYPE_KERN_STACKFRAME64': 0x90B,
71    'STACKSHOT_KCTYPE_USER_STACKFRAME': 0x90C,
72    'STACKSHOT_KCTYPE_USER_STACKFRAME64': 0x90D,
73    'STACKSHOT_KCTYPE_BOOTARGS':        0x90E,
74    'STACKSHOT_KCTYPE_OSVERSION':       0x90F,
75    'STACKSHOT_KCTYPE_KERN_PAGE_SIZE':  0x910,
76    'STACKSHOT_KCTYPE_JETSAM_LEVEL':    0x911,
77    'STACKSHOT_KCTYPE_DELTA_SINCE_TIMESTAMP': 0x912,
78    'STACKSHOT_KCTYPE_KERN_STACKLR':  0x913,
79    'STACKSHOT_KCTYPE_KERN_STACKLR64':  0x914,
80    'STACKSHOT_KCTYPE_USER_STACKLR':  0x915,
81    'STACKSHOT_KCTYPE_USER_STACKLR64':  0x916,
82    'STACKSHOT_KCTYPE_NONRUNNABLE_TIDS':  0x917,
83    'STACKSHOT_KCTYPE_NONRUNNABLE_TASKS':  0x918,
84    'STACKSHOT_KCTYPE_CPU_TIMES': 0x919,
85    'STACKSHOT_KCTYPE_STACKSHOT_DURATION': 0x91a,
86    'STACKSHOT_KCTYPE_STACKSHOT_FAULT_STATS': 0x91b,
87    'STACKSHOT_KCTYPE_KERNELCACHE_LOADINFO': 0x91c,
88    'STACKSHOT_KCTYPE_THREAD_WAITINFO' : 0x91d,
89    'STACKSHOT_KCTYPE_THREAD_GROUP_SNAPSHOT' : 0x91e,
90    'STACKSHOT_KCTYPE_THREAD_GROUP' : 0x91f,
91    'STACKSHOT_KCTYPE_JETSAM_COALITION_SNAPSHOT' : 0x920,
92    'STACKSHOT_KCTYPE_JETSAM_COALITION' : 0x921,
93    'STACKSHOT_KCTYPE_THREAD_POLICY_VERSION': 0x922,
94    'STACKSHOT_KCTYPE_INSTRS_CYCLES' : 0x923,
95    'STACKSHOT_KCTYPE_USER_STACKTOP' : 0x924,
96    'STACKSHOT_KCTYPE_ASID' : 0x925,
97    'STACKSHOT_KCTYPE_PAGE_TABLES' : 0x926,
98    'STACKSHOT_KCTYPE_SYS_SHAREDCACHE_LAYOUT' : 0x927,
99    'STACKSHOT_KCTYPE_THREAD_DISPATCH_QUEUE_LABEL' : 0x928,
100    'STACKSHOT_KCTYPE_THREAD_TURNSTILEINFO' : 0x929,
101    'STACKSHOT_KCTYPE_TASK_CPU_ARCHITECTURE' : 0x92a,
102    'STACKSHOT_KCTYPE_LATENCY_INFO' : 0x92b,
103    'STACKSHOT_KCTYPE_LATENCY_INFO_TASK' : 0x92c,
104    'STACKSHOT_KCTYPE_LATENCY_INFO_THREAD' : 0x92d,
105    'STACKSHOT_KCTYPE_LOADINFO64_TEXT_EXEC' : 0x92e,
106    'STACKSHOT_KCTYPE_AOTCACHE_LOADINFO' : 0x92f,
107    'STACKSHOT_KCTYPE_TRANSITIONING_TASK_SNAPSHOT' : 0x930,
108    'STACKSHOT_KCCONTAINER_TRANSITIONING_TASK' : 0x931,
109    'STACKSHOT_KCTYPE_USER_ASYNC_START_INDEX' : 0x932,
110    'STACKSHOT_KCTYPE_USER_ASYNC_STACKLR64' : 0x933,
111    'STACKSHOT_KCCONTAINER_PORTLABEL' : 0x934,
112    'STACKSHOT_KCTYPE_PORTLABEL' : 0x935,
113    'STACKSHOT_KCTYPE_PORTLABEL_NAME' : 0x936,
114    'STACKSHOT_KCTYPE_DYLD_COMPACTINFO' : 0x937,
115    'STACKSHOT_KCTYPE_SUSPENSION_INFO' : 0x938,
116    'STACKSHOT_KCTYPE_SUSPENSION_SOURCE' : 0x939,
117    'STACKSHOT_KCTYPE_TASK_DELTA_SNAPSHOT': 0x940,
118    'STACKSHOT_KCTYPE_THREAD_DELTA_SNAPSHOT': 0x941,
119    'STACKSHOT_KCCONTAINER_SHAREDCACHE' : 0x942,
120    'STACKSHOT_KCTYPE_SHAREDCACHE_INFO' : 0x943,
121    'STACKSHOT_KCTYPE_SHAREDCACHE_AOTINFO' : 0x944,
122    'STACKSHOT_KCTYPE_SHAREDCACHE_ID' : 0x945,
123    'STACKSHOT_KCTYPE_CODESIGNING_INFO' : 0x946,
124    'STACKSHOT_KCTYPE_OS_BUILD_VERSION' : 0x947,
125    'STACKSHOT_KCTYPE_KERN_EXCLAVES_THREADINFO' : 0x948,
126    'STACKSHOT_KCCONTAINER_EXCLAVES' : 0x949,
127    'STACKSHOT_KCCONTAINER_EXCLAVE_SCRESULT' : 0x94a,
128    'STACKSHOT_KCTYPE_EXCLAVE_SCRESULT_INFO' : 0x94b,
129    'STACKSHOT_KCCONTAINER_EXCLAVE_IPCSTACKENTRY' : 0x94c,
130    'STACKSHOT_KCTYPE_EXCLAVE_IPCSTACKENTRY_INFO' : 0x94d,
131    'STACKSHOT_KCTYPE_EXCLAVE_IPCSTACKENTRY_ECSTACK' : 0x94e,
132    'STACKSHOT_KCCONTAINER_EXCLAVE_ADDRESSSPACE' : 0x94f,
133    'STACKSHOT_KCTYPE_EXCLAVE_ADDRESSSPACE_INFO' : 0x950,
134    'STACKSHOT_KCTYPE_EXCLAVE_ADDRESSSPACE_NAME' : 0x951,
135    'STACKSHOT_KCCONTAINER_EXCLAVE_TEXTLAYOUT' : 0x952,
136    'STACKSHOT_KCTYPE_EXCLAVE_TEXTLAYOUT_INFO' : 0x953,
137    'STACKSHOT_KCTYPE_EXCLAVE_TEXTLAYOUT_SEGMENTS' : 0x954,
138    'STACKSHOT_KCTYPE_KERN_EXCLAVES_CRASH_THREADINFO' : 0x955,
139    'STACKSHOT_KCTYPE_LATENCY_INFO_CPU': 0x956,
140    'STACKSHOT_KCTYPE_TASK_EXEC_META': 0x957,
141    'KCDATA_TYPE_BUFFER_END':      0xF19158ED,
142
143    'TASK_CRASHINFO_EXTMODINFO':           0x801,
144    'TASK_CRASHINFO_BSDINFOWITHUNIQID':    0x802,
145    'TASK_CRASHINFO_TASKDYLD_INFO':        0x803,
146    'TASK_CRASHINFO_UUID':                 0x804,
147    'TASK_CRASHINFO_PID':                  0x805,
148    'TASK_CRASHINFO_PPID':                 0x806,
149
150    # Don't want anyone using this.  It's struct rusage from whatever machine generated the data
151    #'TASK_CRASHINFO_RUSAGE':               0x807,
152    'Type_0x807':               0x807,
153
154    'TASK_CRASHINFO_RUSAGE_INFO':          0x808,
155    'TASK_CRASHINFO_PROC_NAME':            0x809,
156    'TASK_CRASHINFO_PROC_STARTTIME':       0x80B,
157    'TASK_CRASHINFO_USERSTACK':            0x80C,
158    'TASK_CRASHINFO_ARGSLEN':              0x80D,
159    'TASK_CRASHINFO_EXCEPTION_CODES':      0x80E,
160    'TASK_CRASHINFO_PROC_PATH':            0x80F,
161    'TASK_CRASHINFO_PROC_CSFLAGS':         0x810,
162    'TASK_CRASHINFO_PROC_STATUS':          0x811,
163    'TASK_CRASHINFO_UID':                  0x812,
164    'TASK_CRASHINFO_GID':                  0x813,
165    'TASK_CRASHINFO_PROC_ARGC':            0x814,
166    'TASK_CRASHINFO_PROC_FLAGS':           0x815,
167    'TASK_CRASHINFO_CPUTYPE':              0x816,
168    'TASK_CRASHINFO_WORKQUEUEINFO':        0x817,
169    'TASK_CRASHINFO_RESPONSIBLE_PID':      0x818,
170    'TASK_CRASHINFO_DIRTY_FLAGS':          0x819,
171    'TASK_CRASHINFO_CRASHED_THREADID':     0x81A,
172    'TASK_CRASHINFO_COALITION_ID':         0x81B,
173    'TASK_CRASHINFO_JIT_ADDRESS_RANGE':    0x840,
174    'TASK_CRASHINFO_MB':                   0x841,
175    'TASK_CRASHINFO_CS_AUXILIARY_INFO':    0x842,
176    'EXIT_REASON_SNAPSHOT':                0x1001,
177    'EXIT_REASON_USER_DESC':               0x1002,
178    'EXIT_REASON_USER_PAYLOAD':            0x1003,
179    'EXIT_REASON_CODESIGNING_INFO':        0x1004,
180    'EXIT_REASON_WORKLOOP_ID':             0x1005,
181    'EXIT_REASON_DISPATCH_QUEUE_NO':       0x1006,
182    'KCDATA_BUFFER_BEGIN_CRASHINFO':       0xDEADF157,
183    'KCDATA_BUFFER_BEGIN_DELTA_STACKSHOT': 0xDE17A59A,
184    'KCDATA_BUFFER_BEGIN_STACKSHOT':       0x59a25807,
185    'KCDATA_BUFFER_BEGIN_COMPRESSED':      0x434f4d50,
186    'KCDATA_BUFFER_BEGIN_OS_REASON':       0x53A20900,
187    'KCDATA_BUFFER_BEGIN_XNUPOST_CONFIG':  0x1E21C09F
188}
189kcdata_type_def_rev = dict((v, k) for k, v in iter(kcdata_type_def.items()))
190
191KNOWN_TYPES_COLLECTION = {}
192
193KNOWN_TOPLEVEL_CONTAINER_TYPES = ()
194
195def enum(**args):
196    return type('enum', (), args)
197
198#
199# Decode bytes as UTF-8, using surrogateescape if there are invalid UTF-8
200# sequences; see PEP-383
201#
202def BytesToString(b):
203    if isinstance(b, str):
204        return b
205    return b.decode('utf-8', errors="surrogateescape")
206
207# important keys
208SC_SLID_FIRSTMAPPING_KEY = 'sharedCacheSlidFirstMapping'
209
210# important builtin types
211KCSUBTYPE_TYPE = enum(KC_ST_CHAR=1, KC_ST_INT8=2, KC_ST_UINT8=3, KC_ST_INT16=4, KC_ST_UINT16=5, KC_ST_INT32=6, KC_ST_UINT32=7, KC_ST_INT64=8, KC_ST_UINT64=9)
212
213
214LEGAL_OLD_STYLE_ARRAY_TYPE_NAMES = ['KCDATA_TYPE_LIBRARY_LOADINFO',
215                                    'KCDATA_TYPE_LIBRARY_LOADINFO64',
216                                    'STACKSHOT_KCTYPE_KERN_STACKFRAME',
217                                    'STACKSHOT_KCTYPE_USER_STACKFRAME',
218                                    'STACKSHOT_KCTYPE_KERN_STACKFRAME64',
219                                    'STACKSHOT_KCTYPE_USER_STACKFRAME64',
220                                    'STACKSHOT_KCTYPE_DONATING_PIDS',
221                                    'STACKSHOT_KCTYPE_THREAD_DELTA_SNAPSHOT']
222
223KCDATA_FLAGS_STRUCT_PADDING_MASK = 0xf
224KCDATA_FLAGS_STRUCT_HAS_PADDING = 0x80
225
226class KCSubTypeElement(object):
227    """convert kcdata_subtype_descriptor to """
228    _unpack_formats = (None, 'c', 'b', 'B', 'h', 'H', 'i', 'I', 'q', 'Q')
229    _ctypes = ('Unknown', 'char', 'int8_t', 'uint8_t', 'int16_t', 'uint16_t', 'int32_t', 'uint32_t', 'int64_t', 'uint64_t')
230
231    def __init__(self, st_name, st_type, st_size, st_offset=0, st_flag=0, custom_repr=None):
232        self.name = st_name
233        self.offset = st_offset
234        self.type_id = st_type
235        if st_type <= 0 or st_type > KCSUBTYPE_TYPE.KC_ST_UINT64:
236            raise ValueError("Invalid type passed %d" % st_type)
237        self.unpack_fmt = KCSubTypeElement._unpack_formats[self.type_id]
238        self.size = st_size
239        self.totalsize = st_size
240        self.count = 1
241        self.is_array_type = False
242        self.custom_JsonRepr = custom_repr
243        if (st_flag & 0x1) == 0x1:
244            self.is_array_type = True
245            self.size = st_size & 0xffff
246            self.count = (st_size >> 16) & 0xffff
247            self.totalsize = self.size * self.count
248
249    @staticmethod
250    def GetSizeForArray(el_count, el_size):
251        return ((el_count & 0xffff) << 16) | (el_size & 0xffff)
252
253    @staticmethod
254    def FromBinaryTypeData(byte_data):
255        (st_flag, st_type, st_offset, st_size, st_name) = struct.unpack_from('=BBHI32s', byte_data)
256        st_name = BytesToString(st_name).rstrip('\0')
257        return KCSubTypeElement(st_name, st_type, st_size, st_offset, st_flag)
258
259    @staticmethod
260    def FromBasicCtype(st_name, st_type, st_offset=0, legacy_size=None):
261        if st_type <= 0 or st_type > KCSUBTYPE_TYPE.KC_ST_UINT64:
262            raise ValueError("Invalid type passed %d" % st_type)
263        st_size = struct.calcsize(KCSubTypeElement._unpack_formats[st_type])
264        st_flag = 0
265        retval = KCSubTypeElement(st_name, st_type, st_size, st_offset, st_flag, KCSubTypeElement._get_naked_element_value)
266        if legacy_size:
267            retval.legacy_size = legacy_size
268        return retval
269
270    @staticmethod
271    def FromKCSubTypeElement(other, name_override=''):
272        _copy = copy.copy(other)
273        if name_override:
274            _copy.name = name_override
275        return copy
276
277    def GetName(self):
278        return self.name
279
280    def GetTotalSize(self):
281        return self.totalsize
282
283    def GetValueAsString(self, base_data, array_pos=0):
284        v = self.GetValue(base_data, array_pos)
285        if isinstance(v, bytes):
286            return BytesToString(v)
287        return str(v)
288
289    def GetValue(self, base_data, array_pos=0):
290        return struct.unpack_from(self.unpack_fmt, base_data[self.offset + (array_pos * self.size):])[0]
291
292    @staticmethod
293    def _get_naked_element_value(elementValue, elementName):
294        return json.dumps(elementValue)
295
296    def __str__(self):
297        if self.is_array_type:
298            return '[%d,%d] %s  %s[%d];' % (self.offset, self.totalsize, self.GetCTypeDesc(), self.name, self.count)
299        return '[%d,%d] %s  %s;' % (self.offset, self.totalsize, self.GetCTypeDesc(), self.name)
300
301    def __repr__(self):
302        return str(self)
303
304    def GetCTypeDesc(self):
305        return KCSubTypeElement._ctypes[self.type_id]
306
307    def GetStringRepr(self, base_data):
308        if not self.is_array_type:
309            return self.GetValueAsString(base_data)
310        if self.type_id == KCSUBTYPE_TYPE.KC_ST_CHAR:
311            str_len = self.count
312            if len(base_data) < str_len:
313                str_len = len(base_data)
314            str_arr = []
315            for i in range(str_len):
316                _v = self.GetValue(base_data, i)
317                if ord(_v) == 0:
318                    break
319                str_arr.append(self.GetValueAsString(base_data, i))
320            return json.dumps(''.join(str_arr))
321
322        count = self.count
323        if count > len(base_data)//self.size:
324            count = len(base_data)//self.size
325
326        o = '[' + ','.join([self.GetValueAsString(base_data, i) for i in range(count)]) + ']'
327
328        return o
329
330    def GetJsonRepr(self, base_data, flags=0):
331        if (flags & (KCDATA_FLAGS_STRUCT_HAS_PADDING | KCDATA_FLAGS_STRUCT_PADDING_MASK)) != 0:
332            padding = (flags & KCDATA_FLAGS_STRUCT_PADDING_MASK)
333            if padding:
334                base_data = base_data[:-padding]
335        if self.custom_JsonRepr:
336            if self.is_array_type:
337                e_data = [self.GetValue(base_data, i) for i in range(self.count)]
338            else:
339                e_data = self.GetValue(base_data)
340            return self.custom_JsonRepr(e_data, self.name)
341        return self.GetStringRepr(base_data)
342
343    def sizeof(self):
344        return self.totalsize
345
346    def ShouldSkip(self, data):
347        return len(data) < self.offset + self.totalsize
348
349    def ShouldMerge(self):
350        return False
351
352
353class KCTypeDescription(object):
354    def __init__(self, t_type_id, t_elements=[], t_name='anon', custom_repr=None, legacy_size=None, merge=False, naked=False):
355        self.type_id = t_type_id
356        self.elements = t_elements
357        self.name = t_name
358        self.totalsize = 0
359        self.custom_JsonRepr = custom_repr
360        if legacy_size:
361            self.legacy_size = legacy_size
362        self.merge = merge
363        self.naked = naked
364        for e in self.elements:
365            self.totalsize += e.GetTotalSize()
366
367    def ValidateData(self, base_data):
368        if len(base_data) >= self.totalsize:
369            return True
370        return False
371
372    def GetTypeID(self):
373        return self.type_id
374
375    def GetName(self):
376        return self.name
377
378    def __str__(self):
379        o = '%s {\n\t' % self.name + "\n\t".join([str(e) for e in self.elements]) + '\n};'
380        return o
381
382    @staticmethod
383    def FromKCTypeDescription(other, t_type_id, t_name):
384        retval = KCTypeDescription(t_type_id, other.elements, t_name, other.custom_JsonRepr,
385                                   legacy_size=getattr(other, 'legacy_size', None))
386        return retval
387
388    def ShouldMerge(self):
389        return self.merge
390
391    def GetJsonRepr(self, base_data, flags):
392        if (flags & (KCDATA_FLAGS_STRUCT_HAS_PADDING | KCDATA_FLAGS_STRUCT_PADDING_MASK)) != 0:
393            padding = (flags & KCDATA_FLAGS_STRUCT_PADDING_MASK)
394            if padding:
395                base_data = base_data[:-padding]
396        elif hasattr(self, 'legacy_size') and len(base_data) == self.legacy_size + ((-self.legacy_size) & 0xf):
397            base_data = base_data[:self.legacy_size]
398        if self.custom_JsonRepr:
399            return self.custom_JsonRepr([e.GetValue(base_data) for e in self.elements])
400        if self.naked:
401            o = ", ".join([e.GetJsonRepr(base_data) for e in self.elements if not e.ShouldSkip(base_data)])
402        else:
403            o = ", ".join(['"%s": %s' % (e.GetName(), e.GetJsonRepr(base_data)) for e in self.elements if not e.ShouldSkip(base_data)])
404        if not self.merge:
405            o = '{' + o + '}'
406        return o
407
408    def sizeof(self):
409        return max(st.totalsize + st.offset for st in self.elements)
410
411
412def GetTypeNameForKey(k):
413    retval = "0x%x" % k
414    if k in KNOWN_TYPES_COLLECTION:
415        retval = KNOWN_TYPES_COLLECTION[k].GetName()
416    elif k in kcdata_type_def_rev:
417        retval = kcdata_type_def_rev[k]
418    return retval
419
420
421def GetTypeForName(n):
422    ret = 0
423    if n in kcdata_type_def:
424        ret = kcdata_type_def[n]
425    return ret
426
427
428LEGAL_OLD_STYLE_ARRAY_TYPES = list(map(GetTypeForName, LEGAL_OLD_STYLE_ARRAY_TYPE_NAMES))
429
430kcdata_type_def_rev[GetTypeForName('KCDATA_BUFFER_BEGIN_STACKSHOT')] = 'kcdata_stackshot'
431kcdata_type_def_rev[GetTypeForName('KCDATA_BUFFER_BEGIN_DELTA_STACKSHOT')] = 'kcdata_delta_stackshot'
432kcdata_type_def_rev[GetTypeForName('KCDATA_BUFFER_BEGIN_CRASHINFO')] = 'kcdata_crashinfo'
433kcdata_type_def_rev[GetTypeForName('KCDATA_BUFFER_BEGIN_OS_REASON')] = 'kcdata_reason'
434kcdata_type_def_rev[GetTypeForName('STACKSHOT_KCCONTAINER_TASK')] = 'task_snapshots'
435kcdata_type_def_rev[GetTypeForName('STACKSHOT_KCCONTAINER_TRANSITIONING_TASK')] = 'transitioning_task_snapshots'
436kcdata_type_def_rev[GetTypeForName('STACKSHOT_KCCONTAINER_THREAD')] = 'thread_snapshots'
437kcdata_type_def_rev[GetTypeForName('STACKSHOT_KCCONTAINER_PORTLABEL')] = 'portlabels'
438kcdata_type_def_rev[GetTypeForName('STACKSHOT_KCCONTAINER_SHAREDCACHE')] = 'shared_caches'
439kcdata_type_def_rev[GetTypeForName('KCDATA_BUFFER_BEGIN_XNUPOST_CONFIG')] = 'xnupost_testconfig'
440kcdata_type_def_rev[GetTypeForName('STACKSHOT_KCCONTAINER_EXCLAVES')] = 'threads_exclave'
441kcdata_type_def_rev[GetTypeForName('STACKSHOT_KCCONTAINER_EXCLAVE_SCRESULT')] = 'thread_exclave'
442kcdata_type_def_rev[GetTypeForName('STACKSHOT_KCCONTAINER_EXCLAVE_IPCSTACKENTRY')] = 'exclave_ipcstackentry'
443kcdata_type_def_rev[GetTypeForName('STACKSHOT_KCCONTAINER_EXCLAVE_ADDRESSSPACE')] = 'exclave_addressspace'
444kcdata_type_def_rev[GetTypeForName('STACKSHOT_KCCONTAINER_EXCLAVE_TEXTLAYOUT')] = 'exclave_textlayout'
445
446class Indent(object):
447    def __init__(self):
448        self.n = 0
449    def __call__(self, end=False):
450        if end:
451            return " " * (self.n-4)
452        else:
453            return " " * self.n
454    @contextlib.contextmanager
455    def indent(self):
456        self.n += 4
457        try:
458            yield
459        finally:
460            self.n -= 4
461
462INDENT = Indent()
463
464class KCObject(object):
465
466    def __init__(self, type_code, data, offset, flags=0):
467
468        self.i_type = type_code
469        self.i_data = data
470        self.offset = offset
471        self.i_size = len(data)
472        self.i_flags = flags
473        self.obj_collection = []
474        self.obj = {}
475        self.is_container_type = False
476        self.is_array_type = False
477        self.is_naked_type = False
478        self.nested_kcdata = None
479        self.i_name = GetTypeNameForKey(type_code)
480
481        self.ParseData()
482
483        if self.i_type == GetTypeForName('KCDATA_TYPE_CONTAINER_BEGIN'):
484            self.__class__ = KCContainerObject
485        elif self.i_type == GetTypeForName('KCDATA_BUFFER_BEGIN_COMPRESSED'):
486            self.__class__ = KCCompressedBufferObject
487        elif self.i_type in KNOWN_TOPLEVEL_CONTAINER_TYPES:
488            self.__class__ = KCBufferObject
489
490        self.InitAfterParse()
491
492    def __str__(self):
493        return "<KCObject at 0x%x>" % self.offset
494
495    def InitAfterParse(self):
496        pass
497
498    @staticmethod
499    def FromKCItem(kcitem):
500        return KCObject(kcitem.i_type, kcitem.i_data, kcitem.i_offset, kcitem.i_flags)
501
502    def IsContainerEnd(self):
503        return self.i_type == GetTypeForName('KCDATA_TYPE_CONTAINER_END')
504
505    def IsBufferEnd(self):
506        return self.i_type == GetTypeForName('KCDATA_TYPE_BUFFER_END')
507
508    def IsArray(self):
509        return self.is_array_type
510
511    def ShouldMerge(self):
512        if self.nested_kcdata:
513            return True
514        elif not self.is_array_type and self.i_type in KNOWN_TYPES_COLLECTION:
515            return KNOWN_TYPES_COLLECTION[self.i_type].ShouldMerge()
516        else:
517            return False
518
519    def GetJsonRepr(self):
520        if self.is_array_type:
521            return '[' + ', '.join([i.GetJsonRepr() for i in self.obj_collection]) + ']'
522        if self.i_type in KNOWN_TYPES_COLLECTION:
523            return KNOWN_TYPES_COLLECTION[self.i_type].GetJsonRepr(self.i_data, self.i_flags)
524        if self.is_naked_type:
525            return json.dumps(self.obj)
526        if self.nested_kcdata:
527            return self.nested_kcdata.GetJsonRepr()
528
529        raise NotImplementedError("Broken GetJsonRepr implementation")
530
531    def ParseData(self):
532
533        logging.info(self.i_type)
534        if self.i_type == GetTypeForName('KCDATA_TYPE_CONTAINER_BEGIN'):
535            self.obj['uniqID'] = self.i_flags
536            self.i_name = str(self.obj['uniqID'])
537            self.obj['typeID'] = struct.unpack_from('I', self.i_data)[0]
538            logging.info("0x%08x: %sCONTAINER: %s(%x)" % (self.offset, INDENT(), GetTypeNameForKey(self.obj['typeID']), self.i_flags))
539
540        elif self.i_type in (KNOWN_TOPLEVEL_CONTAINER_TYPES):
541            self.obj['uniqID'] = self.i_name
542            self.obj['typeID'] = self.i_type
543            logging.info("0x%08x: %s%s" % (self.offset, INDENT(), self.i_name))
544
545        elif self.i_type == GetTypeForName('KCDATA_TYPE_CONTAINER_END'):
546            self.obj['uniqID'] = self.i_flags
547            logging.info("0x%08x: %sEND" % (self.offset, INDENT(end=True)))
548
549        elif self.i_type == GetTypeForName('KCDATA_TYPE_BUFFER_END'):
550            self.obj = ''
551            logging.info("0x%08x: %sEND_BUFFER" % (self.offset, INDENT(end=True)))
552
553        elif self.i_type == GetTypeForName('KCDATA_TYPE_UINT32_DESC'):
554            self.is_naked_type = True
555            u_d = struct.unpack_from('32sI', self.i_data)
556            self.i_name = BytesToString(u_d[0]).rstrip('\0')
557            self.obj = u_d[1]
558            logging.info("0x%08x: %s%s" % (self.offset, INDENT(), self.i_name))
559
560        elif self.i_type == GetTypeForName('KCDATA_TYPE_UINT64_DESC'):
561            self.is_naked_type = True
562            u_d = struct.unpack_from('32sQ', self.i_data)
563            self.i_name = BytesToString(u_d[0]).rstrip('\0')
564            self.obj = u_d[1]
565            logging.info("0x%08x: %s%s" % (self.offset, INDENT(), self.i_name))
566
567        elif self.i_type == GetTypeForName('KCDATA_TYPE_TYPEDEFINITION'):
568            self.is_naked_type = True
569            u_d = struct.unpack_from('II32s', self.i_data)
570            self.obj['name'] = BytesToString(u_d[2]).split(chr(0))[0]
571            self.i_name = "typedef[%s]" % self.obj['name']
572            self.obj['typeID'] = u_d[0]
573            self.obj['numOfFields'] = u_d[1]
574            element_arr = []
575            for i in range(u_d[1]):
576                e = KCSubTypeElement.FromBinaryTypeData(self.i_data[40+(i*40):])
577                element_arr.append(e)
578            type_desc = KCTypeDescription(u_d[0], element_arr, self.obj['name'])
579            self.obj['fields'] = [str(e) for e in element_arr]
580            KNOWN_TYPES_COLLECTION[type_desc.GetTypeID()] = type_desc
581            logging.info("0x%08x: %s%s" % (self.offset, INDENT(), self.i_name))
582
583        elif self.i_type == GetTypeForName('KCDATA_TYPE_ARRAY'):
584            self.is_array_type = True
585            e_t = (self.i_flags >> 32) & 0xffffffff
586            if e_t not in LEGAL_OLD_STYLE_ARRAY_TYPES:
587                raise Exception("illegal old-style array type: %s (0x%x)" % (GetTypeNameForKey(e_t), e_t))
588            e_c = self.i_flags & 0xffffffff
589            e_s = KNOWN_TYPES_COLLECTION[e_t].legacy_size
590            if e_s * e_c > self.i_size:
591                raise Exception("array too small for its count")
592            self.obj['typeID'] = e_t
593            self.i_name = GetTypeNameForKey(e_t)
594            self.i_type = e_t
595            self.obj['numOfElements'] = e_c
596            self.obj['sizeOfElement'] = e_s
597            logging.info("0x%08x: %sARRAY: %s" % (self.offset, INDENT(), self.i_name))
598            #populate the array here by recursive creation of KCObject
599            with INDENT.indent():
600                for _i in range(e_c):
601                    _o = KCObject(e_t, self.i_data[(_i * e_s):(_i * e_s) + e_s], self.offset + _i*e_s)
602                    self.obj_collection.append(_o)
603
604        elif self.i_type >= GetTypeForName('KCDATA_TYPE_ARRAY_PAD0') and self.i_type <= GetTypeForName('KCDATA_TYPE_ARRAY_PADf'):
605            self.is_array_type = True
606            e_t = (self.i_flags >> 32) & 0xffffffff
607            e_c = self.i_flags & 0xffffffff
608            e_s = (self.i_size - (self.i_type & 0xf)) // e_c if e_c != 0 else None
609            self.obj['typeID'] = e_t
610            self.i_name = GetTypeNameForKey(e_t)
611            self.i_type = e_t
612            self.obj['numOfElements'] = e_c
613            self.obj['sizeOfElement'] = e_s
614            logging.info("0x%08x: %sARRAY: %s" % (self.offset, INDENT(), self.i_name))
615            #populate the array here by recursive creation of KCObject
616            with INDENT.indent():
617                for _i in range(e_c):
618                    _o = KCObject(e_t, self.i_data[(_i * e_s):(_i * e_s) + e_s], self.offset + _i*e_s)
619                    self.obj_collection.append(_o)
620
621        elif self.i_type == GetTypeForName('KCDATA_TYPE_NESTED_KCDATA'):
622            logging.info("0x%08x: %sNESTED_KCDATA" % (self.offset, INDENT()))
623            with INDENT.indent():
624                nested_iterator = kcdata_item_iterator(self.i_data[:self.i_size])
625                nested_buffer = KCObject.FromKCItem(next(nested_iterator))
626                if not isinstance(nested_buffer, KCBufferObject):
627                    raise Exception("nested buffer isn't a KCBufferObject")
628                nested_buffer.ReadItems(nested_iterator)
629            self.nested_kcdata = nested_buffer
630
631        elif self.i_type in KNOWN_TYPES_COLLECTION:
632            self.i_name = KNOWN_TYPES_COLLECTION[self.i_type].GetName()
633            self.is_naked_type = True
634            logging.info("0x%08x: %s%s" % (self.offset, INDENT(), self.i_name))
635        else:
636            self.is_naked_type = True
637            #self.obj = "data of len %d" % len(self.i_data)
638            #self.obj = ''.join(["%x" % ki for ki in struct.unpack('%dB' % len(self.i_data), self.i_data)])
639            if isinstance(self.i_data, str):
640                self.obj = list(map(ord, BytesToString(self.i_data)))
641            else:
642                self.obj = [i for i in self.i_data]
643            logging.info("0x%08x: %s%s" % (self.offset, INDENT(), self.i_name))
644
645
646class KCContainerObject(KCObject):
647    def __init__(self, *args, **kwargs):
648        assert False
649
650    def InitAfterParse(self):
651        self.obj_container_dict = {}
652        self.obj_nested_objs = {}
653
654    def ShouldMerge(self):
655        return True
656
657    def GetJsonRepr(self):
658        # o = '"%s"' % self.obj['uniqID'] + ' : { "typeID" : %d ,' % self.obj['typeID']
659        o = '"%s"' % self.obj['uniqID'] + ' : { '
660        for (k, v) in self.obj_container_dict.items():
661            if v.ShouldMerge():
662                o += v.GetJsonRepr() + ","
663            else:
664                o += ' "%s" : ' % k + v.GetJsonRepr() + ","
665
666        for (k, v) in self.obj_nested_objs.items():
667            o += '"%s" : {' % k + ",".join([vi.GetJsonRepr() for vi in v.values()]) + "} ,"
668
669        o = o.rstrip(',') + "}"
670
671        return o
672
673    def AddObject(self, kco):
674        assert not kco.IsContainerEnd()
675        if isinstance(kco, KCContainerObject):
676            type_name = GetTypeNameForKey(kco.obj['typeID'])
677            if type_name not in self.obj_nested_objs:
678                self.obj_nested_objs[type_name] = {}
679            self.obj_nested_objs[type_name][kco.i_name] = kco
680            return
681        if kco.i_name in self.obj_container_dict:
682            if kco.IsArray() and self.obj_container_dict[kco.i_name].IsArray():
683                self.obj_container_dict[kco.i_name].obj_collection.extend( kco.obj_collection )
684        else:
685            self.obj_container_dict[kco.i_name] = kco
686
687    def IsEndMarker(self, o):
688        if not o.IsContainerEnd():
689            return False
690        if o.i_flags != self.i_flags:
691            raise Exception("container end marker doesn't match")
692        return True
693
694    no_end_message = "could not find container end marker"
695
696    def ReadItems(self, iterator):
697        found_end = False
698        with INDENT.indent():
699            for i in iterator:
700                o = KCObject.FromKCItem(i)
701                if self.IsEndMarker(o):
702                    found_end = True
703                    break
704                if o.IsBufferEnd():
705                    break
706                if isinstance(o, KCContainerObject):
707                    o.ReadItems(iterator)
708                self.AddObject(o)
709        if not found_end:
710            if G.accept_incomplete_data:
711                if not G.data_was_incomplete:
712                    print("kcdata.py WARNING: data is incomplete!", file=sys.stderr)
713                    G.data_was_incomplete = True
714            else:
715                raise Exception(self.no_end_message)
716
717
718
719class KCBufferObject(KCContainerObject):
720
721    def IsEndMarker(self,o):
722        if o.IsContainerEnd():
723            raise Exception("container end marker at the toplevel")
724        return o.IsBufferEnd()
725
726    no_end_message = "could not find buffer end marker"
727
728class KCCompressedBufferObject(KCContainerObject):
729
730    def ReadItems(self, iterator):
731        self.header = dict()
732        with INDENT.indent():
733            for i in iterator:
734                o = KCObject.FromKCItem(i)
735                if self.IsEndMarker(o):
736                    self.compressed_type = o.i_type
737                    self.blob_start = o.offset + 16
738                    break
739                o.ParseData()
740                self.header[o.i_name] = o.obj
741
742    def IsEndMarker(self, o):
743        return o.i_type in KNOWN_TOPLEVEL_CONTAINER_TYPES
744
745    def GetCompressedBlob(self, data):
746        if self.header['kcd_c_type'] != 1:
747            raise NotImplementedError
748        blob = data[self.blob_start:self.blob_start+self.header['kcd_c_totalout']]
749        if len(blob) != self.header['kcd_c_totalout']:
750            raise ValueError
751        return blob
752
753    def Decompress(self, data):
754        start_marker = struct.pack('<IIII', self.compressed_type, 0, 0, 0)
755        end_marker = struct.pack('<IIII', GetTypeForName('KCDATA_TYPE_BUFFER_END'), 0, 0, 0)
756        decompressed = zlib.decompress(self.GetCompressedBlob(data))
757        if len(decompressed) != self.header['kcd_c_totalin']:
758            raise ValueError("length of decompressed: %d vs expected %d" % (len(decompressed), self.header['kcd_c_totalin']))
759        alignbytes = b'\x00' * (-len(decompressed) % 16)
760        return start_marker + decompressed + alignbytes + end_marker
761
762
763class KCData_item:
764    """ a basic kcdata_item type object.
765    """
766    header_size = 16  # (uint32_t + uint32_t + uint64_t)
767
768    def __init__(self, barray, pos=0):
769        """ create an object by parsing data from bytes array
770            returns : obj - if data is readable
771                      raises ValueError if something is not ok.
772        """
773        self.i_type = struct.unpack('I', barray[pos:pos+4])[0]     # int.from_bytes(barray[pos:pos+4])
774        self.i_size = struct.unpack('I', barray[pos+4:pos+8])[0]   # int.from_bytes(barray[pos+4:pos+8])
775        self.i_flags = struct.unpack('Q', barray[pos+8:pos+16])[0]  # int.from_bytes(barray[pos+8:pos+16])
776        self.i_data = barray[pos+16: (pos + 16 + self.i_size)]
777        self.i_offset = pos
778
779    def __len__(self):
780        return self.i_size + KCData_item.header_size
781
782    def GetHeaderDescription(self):
783        outs = "type: 0x%x size: 0x%x flags: 0x%x  (%s)" % (self.i_type, self.i_size, self.i_flags, GetTypeNameForKey(self.i_type))
784        if self.i_offset is not None:
785            outs = "pos: 0x%x" % self.i_offset + outs
786        return outs
787
788    def __str__(self):
789        return self.GetHeaderDescription()
790
791def kcdata_item_iterator(data):
792    file_len = len(data)
793    curpos = 0
794    while curpos < file_len:
795        item = KCData_item(data, curpos)
796        yield item
797        curpos += len(item)
798
799def _get_data_element(elementValues):
800    return json.dumps(elementValues[-1])
801
802KNOWN_TOPLEVEL_CONTAINER_TYPES = list(map(GetTypeForName, ('KCDATA_BUFFER_BEGIN_COMPRESSED', 'KCDATA_BUFFER_BEGIN_CRASHINFO', 'KCDATA_BUFFER_BEGIN_STACKSHOT', 'KCDATA_BUFFER_BEGIN_DELTA_STACKSHOT', 'KCDATA_BUFFER_BEGIN_OS_REASON','KCDATA_BUFFER_BEGIN_XNUPOST_CONFIG')))
803
804KNOWN_TYPES_COLLECTION[GetTypeForName('KCDATA_TYPE_UINT32_DESC')] = KCTypeDescription(GetTypeForName('KCDATA_TYPE_UINT32_DESC'), (
805    KCSubTypeElement('desc', KCSUBTYPE_TYPE.KC_ST_CHAR, KCSubTypeElement.GetSizeForArray(32, 1), 0, 1),
806    KCSubTypeElement('data', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 32, 0)
807),
808    'KCDATA_TYPE_UINT32_DESC',
809    _get_data_element
810)
811
812KNOWN_TYPES_COLLECTION[GetTypeForName('KCDATA_TYPE_UINT64_DESC')] = KCTypeDescription(GetTypeForName('KCDATA_TYPE_UINT64_DESC'), (
813    KCSubTypeElement('desc', KCSUBTYPE_TYPE.KC_ST_CHAR, KCSubTypeElement.GetSizeForArray(32, 1), 0, 1),
814    KCSubTypeElement('data', KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 32, 0)
815),
816    'KCDATA_TYPE_UINT64_DESC',
817    _get_data_element
818)
819
820KNOWN_TYPES_COLLECTION[GetTypeForName('KCDATA_TYPE_TIMEBASE')] = KCTypeDescription(GetTypeForName('KCDATA_TYPE_TIMEBASE'), (
821    KCSubTypeElement('numer', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 0, 0),
822    KCSubTypeElement('denom', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 4, 0)
823),
824    'mach_timebase_info'
825)
826
827
828STACKSHOT_IO_NUM_PRIORITIES = 4
829KNOWN_TYPES_COLLECTION[0x901] = KCTypeDescription(0x901, (
830    KCSubTypeElement.FromBasicCtype('ss_disk_reads_count', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
831    KCSubTypeElement.FromBasicCtype('ss_disk_reads_size', KCSUBTYPE_TYPE.KC_ST_UINT64, 8),
832    KCSubTypeElement.FromBasicCtype('ss_disk_writes_count', KCSUBTYPE_TYPE.KC_ST_UINT64, 16),
833    KCSubTypeElement.FromBasicCtype('ss_disk_writes_size', KCSUBTYPE_TYPE.KC_ST_UINT64, 24),
834    KCSubTypeElement('ss_io_priority_count', KCSUBTYPE_TYPE.KC_ST_UINT64, KCSubTypeElement.GetSizeForArray(STACKSHOT_IO_NUM_PRIORITIES, 8), 32, 1),
835    KCSubTypeElement('ss_io_priority_size', KCSUBTYPE_TYPE.KC_ST_UINT64, KCSubTypeElement.GetSizeForArray(STACKSHOT_IO_NUM_PRIORITIES, 8), 32 + (STACKSHOT_IO_NUM_PRIORITIES * 8), 1),
836    KCSubTypeElement.FromBasicCtype('ss_paging_count', KCSUBTYPE_TYPE.KC_ST_UINT64, 32 + 2 * (STACKSHOT_IO_NUM_PRIORITIES * 8)),
837    KCSubTypeElement.FromBasicCtype('ss_paging_size', KCSUBTYPE_TYPE.KC_ST_UINT64, 40 + 2 * (STACKSHOT_IO_NUM_PRIORITIES * 8)),
838    KCSubTypeElement.FromBasicCtype('ss_non_paging_count', KCSUBTYPE_TYPE.KC_ST_UINT64, 48 + 2 * (STACKSHOT_IO_NUM_PRIORITIES * 8)),
839    KCSubTypeElement.FromBasicCtype('ss_non_paging_size', KCSUBTYPE_TYPE.KC_ST_UINT64, 56 + 2 * (STACKSHOT_IO_NUM_PRIORITIES * 8)),
840    KCSubTypeElement.FromBasicCtype('ss_data_count', KCSUBTYPE_TYPE.KC_ST_UINT64, 64 + 2 * (STACKSHOT_IO_NUM_PRIORITIES * 8)),
841    KCSubTypeElement.FromBasicCtype('ss_data_size', KCSUBTYPE_TYPE.KC_ST_UINT64, 72 + 2 * (STACKSHOT_IO_NUM_PRIORITIES * 8)),
842    KCSubTypeElement.FromBasicCtype('ss_metadata_count', KCSUBTYPE_TYPE.KC_ST_UINT64, 80 + 2 * (STACKSHOT_IO_NUM_PRIORITIES * 8)),
843    KCSubTypeElement.FromBasicCtype('ss_metadata_size', KCSUBTYPE_TYPE.KC_ST_UINT64, 88 + 2 * (STACKSHOT_IO_NUM_PRIORITIES * 8))
844),
845    'io_statistics'
846)
847
848KNOWN_TYPES_COLLECTION[0x902] = KCTypeDescription(0x902, (
849    KCSubTypeElement('snapshot_magic', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 4 * 0, 0),
850    KCSubTypeElement('free_pages', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 4 * 1, 0),
851    KCSubTypeElement('active_pages', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 4 * 2, 0),
852    KCSubTypeElement('inactive_pages', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 4 * 3, 0),
853    KCSubTypeElement('purgeable_pages', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 4 * 4, 0),
854    KCSubTypeElement('wired_pages', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 4 * 5, 0),
855    KCSubTypeElement('speculative_pages', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 4 * 6, 0),
856    KCSubTypeElement('throttled_pages', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 4 * 7, 0),
857    KCSubTypeElement('filebacked_pages', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 4 * 8, 0),
858    KCSubTypeElement('compressions', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 4 * 9, 0),
859    KCSubTypeElement('decompressions', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 4 * 10, 0),
860    KCSubTypeElement('compressor_size', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 4 * 11, 0),
861    KCSubTypeElement('busy_buffer_count', KCSUBTYPE_TYPE.KC_ST_INT32, 4, 4 * 12, 0),
862    KCSubTypeElement('pages_wanted', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 4 * 13, 0),
863    KCSubTypeElement('pages_reclaimed', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 4 * 14, 0),
864    KCSubTypeElement('pages_wanted_reclaimed_valid', KCSUBTYPE_TYPE.KC_ST_UINT8, 1, 4 * 15, 0)
865),
866    'mem_and_io_snapshot'
867)
868
869
870KNOWN_TYPES_COLLECTION[0x930] = KCTypeDescription(0x930, (
871    KCSubTypeElement.FromBasicCtype('tts_unique_pid', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
872    KCSubTypeElement.FromBasicCtype('tts_ss_flags', KCSUBTYPE_TYPE.KC_ST_UINT64, 8),
873    KCSubTypeElement.FromBasicCtype('tts_transition_type', KCSUBTYPE_TYPE.KC_ST_UINT64, 16),
874    KCSubTypeElement.FromBasicCtype('tts_pid', KCSUBTYPE_TYPE.KC_ST_INT32, 24),
875    KCSubTypeElement('tts_p_comm', KCSUBTYPE_TYPE.KC_ST_CHAR, KCSubTypeElement.GetSizeForArray(32, 1), 28, 1)
876),
877    'transitioning_task_snapshot'
878)
879
880KNOWN_TYPES_COLLECTION[0x905] = KCTypeDescription(0x905, (
881    KCSubTypeElement.FromBasicCtype('ts_unique_pid', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
882    KCSubTypeElement.FromBasicCtype('ts_ss_flags', KCSUBTYPE_TYPE.KC_ST_UINT64, 8),
883    KCSubTypeElement.FromBasicCtype('ts_user_time_in_terminated_thre', KCSUBTYPE_TYPE.KC_ST_UINT64, 16),
884    KCSubTypeElement.FromBasicCtype('ts_system_time_in_terminated_th', KCSUBTYPE_TYPE.KC_ST_UINT64, 24),
885    KCSubTypeElement.FromBasicCtype('ts_p_start_sec', KCSUBTYPE_TYPE.KC_ST_UINT64, 32),
886    KCSubTypeElement.FromBasicCtype('ts_task_size', KCSUBTYPE_TYPE.KC_ST_UINT64, 40),
887    KCSubTypeElement.FromBasicCtype('ts_max_resident_size', KCSUBTYPE_TYPE.KC_ST_UINT64, 48),
888    KCSubTypeElement.FromBasicCtype('ts_suspend_count', KCSUBTYPE_TYPE.KC_ST_UINT32, 56),
889    KCSubTypeElement.FromBasicCtype('ts_faults', KCSUBTYPE_TYPE.KC_ST_UINT32, 60),
890    KCSubTypeElement.FromBasicCtype('ts_pageins', KCSUBTYPE_TYPE.KC_ST_UINT32, 64),
891    KCSubTypeElement.FromBasicCtype('ts_cow_faults', KCSUBTYPE_TYPE.KC_ST_UINT32, 68),
892    KCSubTypeElement.FromBasicCtype('ts_was_throttled', KCSUBTYPE_TYPE.KC_ST_UINT32, 72),
893    KCSubTypeElement.FromBasicCtype('ts_did_throttle', KCSUBTYPE_TYPE.KC_ST_UINT32, 76),
894    KCSubTypeElement.FromBasicCtype('ts_latency_qos', KCSUBTYPE_TYPE.KC_ST_UINT32, 80),
895    KCSubTypeElement.FromBasicCtype('ts_pid', KCSUBTYPE_TYPE.KC_ST_INT32, 84),
896    KCSubTypeElement('ts_p_comm', KCSUBTYPE_TYPE.KC_ST_CHAR, KCSubTypeElement.GetSizeForArray(32, 1), 88, 1)
897),
898    'task_snapshot'
899)
900
901
902KNOWN_TYPES_COLLECTION[0x946] = KCTypeDescription(0x946, (
903     KCSubTypeElement.FromBasicCtype('csflags', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
904     KCSubTypeElement.FromBasicCtype('cs_trust_level', KCSUBTYPE_TYPE.KC_ST_UINT32, 8),
905     ),
906     'stackshot_task_codesigning_info'
907)
908KNOWN_TYPES_COLLECTION[0x906] = KCTypeDescription(0x906, (
909    KCSubTypeElement.FromBasicCtype('ths_thread_id', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
910    KCSubTypeElement.FromBasicCtype('ths_wait_event', KCSUBTYPE_TYPE.KC_ST_UINT64, 8),
911    KCSubTypeElement.FromBasicCtype('ths_continuation', KCSUBTYPE_TYPE.KC_ST_UINT64, 16),
912    KCSubTypeElement.FromBasicCtype('ths_total_syscalls', KCSUBTYPE_TYPE.KC_ST_UINT64, 24),
913    KCSubTypeElement.FromBasicCtype('ths_voucher_identifier', KCSUBTYPE_TYPE.KC_ST_UINT64, 32),
914    KCSubTypeElement.FromBasicCtype('ths_dqserialnum', KCSUBTYPE_TYPE.KC_ST_UINT64, 40),
915    KCSubTypeElement.FromBasicCtype('ths_user_time', KCSUBTYPE_TYPE.KC_ST_UINT64, 48),
916    KCSubTypeElement.FromBasicCtype('ths_sys_time', KCSUBTYPE_TYPE.KC_ST_UINT64, 56),
917    KCSubTypeElement.FromBasicCtype('ths_ss_flags', KCSUBTYPE_TYPE.KC_ST_UINT64, 64),
918    KCSubTypeElement.FromBasicCtype('ths_last_run_time', KCSUBTYPE_TYPE.KC_ST_UINT64, 72),
919    KCSubTypeElement.FromBasicCtype('ths_last_made_runnable_time', KCSUBTYPE_TYPE.KC_ST_UINT64, 80),
920    KCSubTypeElement.FromBasicCtype('ths_state', KCSUBTYPE_TYPE.KC_ST_UINT32, 88),
921    KCSubTypeElement.FromBasicCtype('ths_sched_flags', KCSUBTYPE_TYPE.KC_ST_UINT32, 92),
922    KCSubTypeElement.FromBasicCtype('ths_base_priority', KCSUBTYPE_TYPE.KC_ST_INT16, 96),
923    KCSubTypeElement.FromBasicCtype('ths_sched_priority', KCSUBTYPE_TYPE.KC_ST_INT16, 98),
924    KCSubTypeElement.FromBasicCtype('ths_eqos', KCSUBTYPE_TYPE.KC_ST_UINT8, 100),
925    KCSubTypeElement.FromBasicCtype('ths_rqos', KCSUBTYPE_TYPE.KC_ST_UINT8, 101),
926    KCSubTypeElement.FromBasicCtype('ths_rqos_override', KCSUBTYPE_TYPE.KC_ST_UINT8, 102),
927    KCSubTypeElement.FromBasicCtype('ths_io_tier', KCSUBTYPE_TYPE.KC_ST_UINT8, 103),
928    KCSubTypeElement.FromBasicCtype('ths_thread_t', KCSUBTYPE_TYPE.KC_ST_UINT64, 104),
929    KCSubTypeElement.FromBasicCtype('ths_requested_policy', KCSUBTYPE_TYPE.KC_ST_UINT64, 112),
930    KCSubTypeElement.FromBasicCtype('ths_effective_policy', KCSUBTYPE_TYPE.KC_ST_UINT64, 120),
931),
932    'thread_snapshot',
933    legacy_size = 0x68
934)
935
936KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_THREAD_DISPATCH_QUEUE_LABEL')] = KCSubTypeElement('dispatch_queue_label', KCSUBTYPE_TYPE.KC_ST_CHAR,
937                          KCSubTypeElement.GetSizeForArray(64, 1), 0, 1)
938
939KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_THREAD_DELTA_SNAPSHOT')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_THREAD_DELTA_SNAPSHOT'), (
940    KCSubTypeElement.FromBasicCtype('tds_thread_id', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
941    KCSubTypeElement.FromBasicCtype('tds_voucher_identifier', KCSUBTYPE_TYPE.KC_ST_UINT64, 8),
942    KCSubTypeElement.FromBasicCtype('tds_ss_flags', KCSUBTYPE_TYPE.KC_ST_UINT64, 16),
943    KCSubTypeElement.FromBasicCtype('tds_last_made_runnable_time', KCSUBTYPE_TYPE.KC_ST_UINT64, 24),
944    KCSubTypeElement.FromBasicCtype('tds_state', KCSUBTYPE_TYPE.KC_ST_UINT32, 32),
945    KCSubTypeElement.FromBasicCtype('tds_sched_flags', KCSUBTYPE_TYPE.KC_ST_UINT32, 36),
946    KCSubTypeElement.FromBasicCtype('tds_base_priority', KCSUBTYPE_TYPE.KC_ST_INT16, 40),
947    KCSubTypeElement.FromBasicCtype('tds_sched_priority', KCSUBTYPE_TYPE.KC_ST_INT16, 42),
948    KCSubTypeElement.FromBasicCtype('tds_eqos', KCSUBTYPE_TYPE.KC_ST_UINT8, 44),
949    KCSubTypeElement.FromBasicCtype('tds_rqos', KCSUBTYPE_TYPE.KC_ST_UINT8, 45),
950    KCSubTypeElement.FromBasicCtype('tds_rqos_override', KCSUBTYPE_TYPE.KC_ST_UINT8, 46),
951    KCSubTypeElement.FromBasicCtype('tds_io_tier', KCSUBTYPE_TYPE.KC_ST_UINT8, 47),
952    KCSubTypeElement.FromBasicCtype('tds_requested_policy', KCSUBTYPE_TYPE.KC_ST_UINT64, 48),
953    KCSubTypeElement.FromBasicCtype('tds_effective_policy', KCSUBTYPE_TYPE.KC_ST_UINT64, 56),
954),
955    'thread_delta_snapshot',
956    legacy_size = 48
957)
958
959KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_TASK_DELTA_SNAPSHOT')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_TASK_DELTA_SNAPSHOT'), (
960    KCSubTypeElement.FromBasicCtype('tds_unique_pid', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
961    KCSubTypeElement.FromBasicCtype('tds_ss_flags', KCSUBTYPE_TYPE.KC_ST_UINT64, 8),
962    KCSubTypeElement.FromBasicCtype('tds_user_time_in_terminated_thr', KCSUBTYPE_TYPE.KC_ST_UINT64, 16),
963    KCSubTypeElement.FromBasicCtype('tds_system_time_in_terminated_t', KCSUBTYPE_TYPE.KC_ST_UINT64, 24),
964    KCSubTypeElement.FromBasicCtype('tds_task_size', KCSUBTYPE_TYPE.KC_ST_UINT64, 32),
965    KCSubTypeElement.FromBasicCtype('tds_max_resident_size', KCSUBTYPE_TYPE.KC_ST_UINT64, 40),
966    KCSubTypeElement.FromBasicCtype('tds_suspend_count', KCSUBTYPE_TYPE.KC_ST_UINT32, 48),
967    KCSubTypeElement.FromBasicCtype('tds_faults', KCSUBTYPE_TYPE.KC_ST_UINT32, 52),
968    KCSubTypeElement.FromBasicCtype('tds_pageins', KCSUBTYPE_TYPE.KC_ST_UINT32, 56),
969    KCSubTypeElement.FromBasicCtype('tds_cow_faults', KCSUBTYPE_TYPE.KC_ST_UINT32, 60),
970    KCSubTypeElement.FromBasicCtype('tds_was_throttled', KCSUBTYPE_TYPE.KC_ST_UINT32, 64),
971    KCSubTypeElement.FromBasicCtype('tds_did_throttle', KCSUBTYPE_TYPE.KC_ST_UINT32, 68),
972    KCSubTypeElement.FromBasicCtype('tds_latency_qos', KCSUBTYPE_TYPE.KC_ST_UINT32, 72),
973),
974    'task_delta_snapshot'
975)
976
977KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_TASK_EXEC_META')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_TASK_EXEC_META'), (
978    KCSubTypeElement.FromBasicCtype('tem_flags', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
979),
980    'task_exec_meta'
981)
982
983KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_THREAD_NAME')] = KCSubTypeElement('pth_name', KCSUBTYPE_TYPE.KC_ST_CHAR, KCSubTypeElement.GetSizeForArray(64, 1), 0, 1)
984
985KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_SYS_SHAREDCACHE_LAYOUT')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_SYS_SHAREDCACHE_LAYOUT'), (
986    KCSubTypeElement('imageLoadAddress', KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 0, 0),
987    KCSubTypeElement('imageUUID', KCSUBTYPE_TYPE.KC_ST_UINT8, KCSubTypeElement.GetSizeForArray(16, 1), 8, 1)
988),
989    'system_shared_cache_layout'
990)
991
992KNOWN_TYPES_COLLECTION[GetTypeForName('KCDATA_TYPE_LIBRARY_LOADINFO64')] = KCTypeDescription(GetTypeForName('KCDATA_TYPE_LIBRARY_LOADINFO64'), (
993    KCSubTypeElement('imageLoadAddress', KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 0, 0),
994    KCSubTypeElement('imageUUID', KCSUBTYPE_TYPE.KC_ST_UINT8, KCSubTypeElement.GetSizeForArray(16, 1), 8, 1)
995),
996    'dyld_load_info',
997    legacy_size = 24
998)
999
1000KNOWN_TYPES_COLLECTION[GetTypeForName('KCDATA_TYPE_LIBRARY_LOADINFO')] = KCTypeDescription(GetTypeForName('KCDATA_TYPE_LIBRARY_LOADINFO'), (
1001    KCSubTypeElement('imageLoadAddress', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 0, 0),
1002    KCSubTypeElement('imageUUID', KCSUBTYPE_TYPE.KC_ST_UINT8, KCSubTypeElement.GetSizeForArray(16, 1), 4, 1)
1003),
1004    'dyld_load_info',
1005    legacy_size = 20
1006)
1007
1008KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_LOADINFO64_TEXT_EXEC')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_LOADINFO64_TEXT_EXEC'), (
1009    KCSubTypeElement('imageLoadAddress', KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 0, 0),
1010    KCSubTypeElement('imageUUID', KCSUBTYPE_TYPE.KC_ST_UINT8, KCSubTypeElement.GetSizeForArray(16, 1), 8, 1),
1011),
1012    'dyld_load_info_text_exec'
1013)
1014
1015KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_AOTCACHE_LOADINFO')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_AOTCACHE_LOADINFO'), (
1016    KCSubTypeElement('x86SlidBaseAddress', KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 0, 0),
1017    KCSubTypeElement('x86UUID', KCSUBTYPE_TYPE.KC_ST_UINT8, KCSubTypeElement.GetSizeForArray(16, 1), 8, 1),
1018    KCSubTypeElement('aotSlidBaseAddress', KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 24, 0),
1019    KCSubTypeElement('aotUUID', KCSUBTYPE_TYPE.KC_ST_UINT8, KCSubTypeElement.GetSizeForArray(16, 1), 32, 1),
1020),
1021    'dyld_aot_cache_uuid_info'
1022)
1023KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_SHAREDCACHE_AOTINFO')] = KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_AOTCACHE_LOADINFO')]
1024
1025KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_SHAREDCACHE_LOADINFO')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_SHAREDCACHE_LOADINFO'), (
1026    KCSubTypeElement('imageLoadAddress', KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 0, 0),
1027    KCSubTypeElement('imageUUID', KCSUBTYPE_TYPE.KC_ST_UINT8, KCSubTypeElement.GetSizeForArray(16, 1), 8, 1),
1028    KCSubTypeElement('imageSlidBaseAddress', KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 24, 0),
1029    KCSubTypeElement('sharedCacheSlidFirstMapping', KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 32, 0),
1030),
1031    'shared_cache_dyld_load_info',
1032    legacy_size = 0x18
1033)
1034
1035KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_SHAREDCACHE_INFO')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_SHAREDCACHE_INFO'), (
1036    KCSubTypeElement('sharedCacheSlide', KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 0, 0),
1037    KCSubTypeElement('sharedCacheUUID', KCSUBTYPE_TYPE.KC_ST_UINT8, KCSubTypeElement.GetSizeForArray(16, 1), 8, 1),
1038    KCSubTypeElement('sharedCacheUnreliableSlidBaseAd', KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 24, 0),
1039    KCSubTypeElement('sharedCacheSlidFirstMapping', KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 32, 0),
1040    KCSubTypeElement('sharedCacheID', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 40, 0),
1041    KCSubTypeElement('sharedCacheFlags', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 44, 0),
1042),
1043    'shared_cache_dyld_load_info',
1044)
1045
1046KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_KERNELCACHE_LOADINFO')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_KERNELCACHE_LOADINFO'), (
1047    KCSubTypeElement('imageLoadAddress', KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 0, 0),
1048    KCSubTypeElement('imageUUID', KCSUBTYPE_TYPE.KC_ST_UINT8, KCSubTypeElement.GetSizeForArray(16, 1), 8, 1),
1049),
1050    'kernelcache_load_info'
1051)
1052
1053KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_SHAREDCACHE_ID')] = KCSubTypeElement('sharedCacheID', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 0, 0, KCSubTypeElement._get_naked_element_value)
1054
1055KNOWN_TYPES_COLLECTION[0x33] = KCSubTypeElement('mach_absolute_time', KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 0, 0, KCSubTypeElement._get_naked_element_value)
1056KNOWN_TYPES_COLLECTION[0x907] = KCSubTypeElement.FromBasicCtype('donating_pids', KCSUBTYPE_TYPE.KC_ST_INT32, legacy_size=4)
1057
1058KNOWN_TYPES_COLLECTION[GetTypeForName('KCDATA_TYPE_USECS_SINCE_EPOCH')] = KCSubTypeElement('usecs_since_epoch', KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 0, 0, KCSubTypeElement._get_naked_element_value)
1059
1060KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_KERN_STACKFRAME')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_KERN_STACKFRAME'), (
1061    KCSubTypeElement.FromBasicCtype('lr', KCSUBTYPE_TYPE.KC_ST_UINT32),
1062    KCSubTypeElement.FromBasicCtype('sp', KCSUBTYPE_TYPE.KC_ST_UINT32, 4)
1063),
1064    'kernel_stack_frames',
1065    legacy_size = 8
1066)
1067
1068KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_KERN_STACKLR')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_KERN_STACKLR'), (
1069    KCSubTypeElement.FromBasicCtype('lr', KCSUBTYPE_TYPE.KC_ST_UINT32),
1070),
1071    'kernel_stack_frames'
1072)
1073
1074
1075KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_USER_STACKFRAME')] = KCTypeDescription.FromKCTypeDescription(
1076    KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_KERN_STACKFRAME')],
1077    GetTypeForName('STACKSHOT_KCTYPE_USER_STACKFRAME'),
1078    'user_stack_frames'
1079)
1080
1081KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_USER_STACKLR')] = KCTypeDescription.FromKCTypeDescription(
1082    KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_KERN_STACKLR')],
1083    GetTypeForName('STACKSHOT_KCTYPE_USER_STACKLR'),
1084    'user_stack_frames'
1085)
1086
1087KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_KERN_STACKFRAME64')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_KERN_STACKFRAME64'), (
1088    KCSubTypeElement.FromBasicCtype('lr', KCSUBTYPE_TYPE.KC_ST_UINT64),
1089    KCSubTypeElement.FromBasicCtype('sp', KCSUBTYPE_TYPE.KC_ST_UINT64, 8)
1090),
1091    'kernel_stack_frames',
1092    legacy_size = 16
1093)
1094
1095KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_USER_STACKFRAME64')] = KCTypeDescription.FromKCTypeDescription(
1096    KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_KERN_STACKFRAME64')],
1097    GetTypeForName('STACKSHOT_KCTYPE_USER_STACKFRAME64'),
1098    'user_stack_frames'
1099)
1100
1101
1102KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_KERN_STACKLR64')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_KERN_STACKLR64'), (
1103    KCSubTypeElement.FromBasicCtype('lr', KCSUBTYPE_TYPE.KC_ST_UINT64),
1104),
1105    'kernel_stack_frames'
1106)
1107
1108KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_USER_STACKLR64')] = KCTypeDescription.FromKCTypeDescription(
1109    KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_KERN_STACKLR64')],
1110    GetTypeForName('STACKSHOT_KCTYPE_USER_STACKLR64'),
1111    'user_stack_frames'
1112)
1113
1114KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_USER_ASYNC_START_INDEX')] = KCSubTypeElement.FromBasicCtype('user_async_start_index', KCSUBTYPE_TYPE.KC_ST_UINT32)
1115
1116KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_USER_ASYNC_STACKLR64')] = KCTypeDescription.FromKCTypeDescription(
1117    KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_KERN_STACKLR64')],
1118    GetTypeForName('STACKSHOT_KCTYPE_USER_ASYNC_STACKLR64'),
1119    'user_async_stack_frames'
1120)
1121
1122KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_NONRUNNABLE_TIDS')] = KCSubTypeElement.FromBasicCtype('nonrunnable_threads', KCSUBTYPE_TYPE.KC_ST_INT64)
1123
1124KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_NONRUNNABLE_TASKS')] = KCSubTypeElement.FromBasicCtype('nonrunnable_tasks', KCSUBTYPE_TYPE.KC_ST_INT64)
1125
1126KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_OSVERSION')] = KCSubTypeElement('osversion', KCSUBTYPE_TYPE.KC_ST_CHAR,
1127                          KCSubTypeElement.GetSizeForArray(256, 1), 0, 1)
1128
1129KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_BOOTARGS')] = KCSubTypeElement('boot_args', KCSUBTYPE_TYPE.KC_ST_CHAR,
1130                           KCSubTypeElement.GetSizeForArray(256, 1), 0, 1)
1131
1132KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_KERN_PAGE_SIZE')] = KCSubTypeElement('kernel_page_size', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 0, 0, KCSubTypeElement._get_naked_element_value)
1133
1134KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_THREAD_POLICY_VERSION')] = KCSubTypeElement('thread_policy_version', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 0, 0, KCSubTypeElement._get_naked_element_value)
1135
1136KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_JETSAM_LEVEL')] = KCSubTypeElement('jetsam_level', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 0, 0, KCSubTypeElement._get_naked_element_value)
1137
1138KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_DELTA_SINCE_TIMESTAMP')] = KCSubTypeElement("stackshot_delta_since_timestamp", KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 0, 0, KCSubTypeElement._get_naked_element_value)
1139
1140KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_STACKSHOT_FAULT_STATS')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_STACKSHOT_FAULT_STATS'),
1141            (
1142                        KCSubTypeElement.FromBasicCtype('sfs_pages_faulted_in', KCSUBTYPE_TYPE.KC_ST_UINT32, 0),
1143                        KCSubTypeElement.FromBasicCtype('sfs_time_spent_faulting', KCSUBTYPE_TYPE.KC_ST_UINT64, 4),
1144                        KCSubTypeElement.FromBasicCtype('sfs_system_max_fault_time', KCSUBTYPE_TYPE.KC_ST_UINT64, 12),
1145                        KCSubTypeElement.FromBasicCtype('sfs_stopped_faulting', KCSUBTYPE_TYPE.KC_ST_UINT8, 20)
1146            ),
1147            'stackshot_fault_stats')
1148
1149KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_THREAD_WAITINFO')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_THREAD_WAITINFO'),
1150            (
1151                        KCSubTypeElement.FromBasicCtype('owner', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
1152                        KCSubTypeElement.FromBasicCtype('waiter', KCSUBTYPE_TYPE.KC_ST_UINT64, 8),
1153                        KCSubTypeElement.FromBasicCtype('context', KCSUBTYPE_TYPE.KC_ST_UINT64, 16),
1154                        KCSubTypeElement.FromBasicCtype('wait_type', KCSUBTYPE_TYPE.KC_ST_UINT8, 24),
1155                        KCSubTypeElement.FromBasicCtype('portlabel_id', KCSUBTYPE_TYPE.KC_ST_INT16, 25),
1156                        KCSubTypeElement.FromBasicCtype('wait_flags', KCSUBTYPE_TYPE.KC_ST_INT32, 27)
1157            ),
1158            'thread_waitinfo')
1159
1160KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_THREAD_TURNSTILEINFO')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_THREAD_TURNSTILEINFO'),
1161            (
1162                        KCSubTypeElement.FromBasicCtype('waiter', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
1163                        KCSubTypeElement.FromBasicCtype('turnstile_context', KCSUBTYPE_TYPE.KC_ST_UINT64, 8),
1164                        KCSubTypeElement.FromBasicCtype('turnstile_priority', KCSUBTYPE_TYPE.KC_ST_UINT8, 16),
1165                        KCSubTypeElement.FromBasicCtype('number_of_hops', KCSUBTYPE_TYPE.KC_ST_UINT8, 17),
1166                        KCSubTypeElement.FromBasicCtype('turnstile_flags', KCSUBTYPE_TYPE.KC_ST_UINT64, 18),
1167                        KCSubTypeElement.FromBasicCtype('portlabel_id', KCSUBTYPE_TYPE.KC_ST_INT16, 26),
1168            ),
1169            'thread_turnstileinfo')
1170
1171KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_PORTLABEL')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_PORTLABEL'),
1172            (
1173                        KCSubTypeElement.FromBasicCtype('portlabel_id', KCSUBTYPE_TYPE.KC_ST_INT16, 0),
1174                        KCSubTypeElement.FromBasicCtype('portlabel_flags', KCSUBTYPE_TYPE.KC_ST_UINT16, 2),
1175                        KCSubTypeElement.FromBasicCtype('portlabel_domain', KCSUBTYPE_TYPE.KC_ST_UINT8, 4),
1176            ),
1177            'portlabel_info', merge=True)
1178
1179KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_PORTLABEL_NAME')] = (
1180    KCSubTypeElement("portlabel_name", KCSUBTYPE_TYPE.KC_ST_CHAR, KCSubTypeElement.GetSizeForArray(-1, 1), 0, 1))
1181
1182KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_THREAD_GROUP_SNAPSHOT')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_THREAD_GROUP'),
1183            (
1184                        KCSubTypeElement.FromBasicCtype('tgs_id', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
1185                        KCSubTypeElement('tgs_name', KCSUBTYPE_TYPE.KC_ST_CHAR, KCSubTypeElement.GetSizeForArray(16, 1),
1186                            8, 1),
1187                        KCSubTypeElement.FromBasicCtype('tgs_flags', KCSUBTYPE_TYPE.KC_ST_UINT64, 24),
1188            ),
1189            'thread_group_snapshot')
1190
1191
1192KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_THREAD_GROUP')] = KCSubTypeElement('thread_group', KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 0, 0, KCSubTypeElement._get_naked_element_value)
1193
1194KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_JETSAM_COALITION_SNAPSHOT')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_JETSAM_COALITION_SNAPSHOT'),
1195            (
1196                        KCSubTypeElement.FromBasicCtype('jcs_id', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
1197                        KCSubTypeElement.FromBasicCtype('jcs_flags', KCSUBTYPE_TYPE.KC_ST_UINT64, 8),
1198                        KCSubTypeElement.FromBasicCtype('jcs_thread_group', KCSUBTYPE_TYPE.KC_ST_UINT64, 16),
1199                        KCSubTypeElement.FromBasicCtype('jcs_leader_task_uniqueid', KCSUBTYPE_TYPE.KC_ST_UINT64, 24)
1200            ),
1201            'jetsam_coalition_snapshot')
1202
1203KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_JETSAM_COALITION')] = KCSubTypeElement('jetsam_coalition', KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 0, 0, KCSubTypeElement._get_naked_element_value)
1204
1205KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_INSTRS_CYCLES')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_INSTRS_CYCLES'),
1206            (
1207                        KCSubTypeElement.FromBasicCtype('ics_instructions', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
1208                        KCSubTypeElement.FromBasicCtype('ics_cycles', KCSUBTYPE_TYPE.KC_ST_UINT64, 8),
1209                        KCSubTypeElement.FromBasicCtype('ics_p_instructions', KCSUBTYPE_TYPE.KC_ST_UINT64, 16),
1210                        KCSubTypeElement.FromBasicCtype('ics_p_cycles', KCSUBTYPE_TYPE.KC_ST_UINT64, 24),
1211            ),
1212            'instrs_cycles_snapshot')
1213
1214KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_TASK_CPU_ARCHITECTURE')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_TASK_CPU_ARCHITECTURE'),
1215            (
1216                        KCSubTypeElement.FromBasicCtype('cputype', KCSUBTYPE_TYPE.KC_ST_INT32, 0),
1217                        KCSubTypeElement.FromBasicCtype('cpusubtype', KCSUBTYPE_TYPE.KC_ST_INT32, 4)
1218            ),
1219            'task_cpu_architecture')
1220
1221KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_LATENCY_INFO')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_LATENCY_INFO'),
1222            (
1223                        KCSubTypeElement.FromBasicCtype('latency_version', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
1224                        KCSubTypeElement.FromBasicCtype('setup_latency', KCSUBTYPE_TYPE.KC_ST_UINT64, 8),
1225                        KCSubTypeElement.FromBasicCtype('total_task_iteration_latency', KCSUBTYPE_TYPE.KC_ST_UINT64, 16),
1226                        KCSubTypeElement.FromBasicCtype('total_terminated_task_iteration', KCSUBTYPE_TYPE.KC_ST_UINT64, 24),
1227                        KCSubTypeElement.FromBasicCtype('task_queue_building_latency_mt', KCSUBTYPE_TYPE.KC_ST_UINT64, 32),
1228                        KCSubTypeElement.FromBasicCtype('terminated_task_queue_building_latency_mt', KCSUBTYPE_TYPE.KC_ST_UINT64, 40),
1229                        KCSubTypeElement.FromBasicCtype('cpu_wait_latency_mt', KCSUBTYPE_TYPE.KC_ST_INT32, 48),
1230                        KCSubTypeElement.FromBasicCtype('calling_cpu_number', KCSUBTYPE_TYPE.KC_ST_INT32, 56),
1231            ),
1232            'stackshot_latency_collection')
1233
1234KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_LATENCY_INFO_CPU')] = KCTypeDescription(GetTypeForName('STACKSHOT_LATENCY_INFO_CPU'),
1235            (
1236                        KCSubTypeElement.FromBasicCtype('cpu_number', KCSUBTYPE_TYPE.KC_ST_INT32, 0),
1237                        KCSubTypeElement.FromBasicCtype('cluster_type', KCSUBTYPE_TYPE.KC_ST_INT32, 4),
1238                        KCSubTypeElement.FromBasicCtype('init_latency_mt', KCSUBTYPE_TYPE.KC_ST_UINT64, 8),
1239                        KCSubTypeElement.FromBasicCtype('workqueue_latency_mt', KCSUBTYPE_TYPE.KC_ST_UINT64, 16),
1240                        KCSubTypeElement.FromBasicCtype('total_latency_mt', KCSUBTYPE_TYPE.KC_ST_UINT64, 24),
1241                        KCSubTypeElement.FromBasicCtype('total_cycles', KCSUBTYPE_TYPE.KC_ST_UINT64, 32),
1242                        KCSubTypeElement.FromBasicCtype('total_instrs', KCSUBTYPE_TYPE.KC_ST_UINT64, 40),
1243                        KCSubTypeElement.FromBasicCtype('tasks_processed', KCSUBTYPE_TYPE.KC_ST_UINT64, 48),
1244                        KCSubTypeElement.FromBasicCtype('threads_processed', KCSUBTYPE_TYPE.KC_ST_UINT64, 56),
1245                        KCSubTypeElement.FromBasicCtype('faulting_time_mt', KCSUBTYPE_TYPE.KC_ST_UINT64, 64),
1246                        KCSubTypeElement.FromBasicCtype('total_buf', KCSUBTYPE_TYPE.KC_ST_UINT64, 72),
1247                        KCSubTypeElement.FromBasicCtype('intercluster_buf_used', KCSUBTYPE_TYPE.KC_ST_UINT64, 80),
1248            ),
1249            'stackshot_latency_cpu')
1250
1251KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_LATENCY_INFO_TASK')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_LATENCY_INFO_TASK'),
1252            (
1253                        KCSubTypeElement.FromBasicCtype('task_uniqueid', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
1254                        KCSubTypeElement.FromBasicCtype('setup_latency', KCSUBTYPE_TYPE.KC_ST_UINT64, 8),
1255                        KCSubTypeElement.FromBasicCtype('task_thread_count_loop_latency', KCSUBTYPE_TYPE.KC_ST_UINT64, 16),
1256                        KCSubTypeElement.FromBasicCtype('task_thread_data_loop_latency', KCSUBTYPE_TYPE.KC_ST_UINT64, 24),
1257                        KCSubTypeElement.FromBasicCtype('cur_tsnap_latency', KCSUBTYPE_TYPE.KC_ST_UINT64, 32),
1258                        KCSubTypeElement.FromBasicCtype('pmap_latency', KCSUBTYPE_TYPE.KC_ST_UINT64, 40),
1259                        KCSubTypeElement.FromBasicCtype('bsd_proc_ids_latency', KCSUBTYPE_TYPE.KC_ST_UINT64, 48),
1260                        KCSubTypeElement.FromBasicCtype('misc_latency', KCSUBTYPE_TYPE.KC_ST_UINT64, 56),
1261                        KCSubTypeElement.FromBasicCtype('misc2_latency', KCSUBTYPE_TYPE.KC_ST_UINT64, 64),
1262                        KCSubTypeElement.FromBasicCtype('end_latency', KCSUBTYPE_TYPE.KC_ST_UINT64, 72)
1263            ),
1264            'stackshot_latency_task')
1265
1266KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_LATENCY_INFO_THREAD')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_LATENCY_INFO_THREAD'),
1267            (
1268                        KCSubTypeElement.FromBasicCtype('thread_id', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
1269                        KCSubTypeElement.FromBasicCtype('cur_thsnap1_latency', KCSUBTYPE_TYPE.KC_ST_UINT64, 8),
1270                        KCSubTypeElement.FromBasicCtype('dispatch_serial_latency', KCSUBTYPE_TYPE.KC_ST_UINT64, 16),
1271                        KCSubTypeElement.FromBasicCtype('dispatch_label_latency', KCSUBTYPE_TYPE.KC_ST_UINT64, 24),
1272                        KCSubTypeElement.FromBasicCtype('cur_thsnap2_latency', KCSUBTYPE_TYPE.KC_ST_UINT64, 32),
1273                        KCSubTypeElement.FromBasicCtype('thread_name_latency', KCSUBTYPE_TYPE.KC_ST_UINT64, 40),
1274                        KCSubTypeElement.FromBasicCtype('sur_times_latency', KCSUBTYPE_TYPE.KC_ST_UINT64, 48),
1275                        KCSubTypeElement.FromBasicCtype('user_stack_latency', KCSUBTYPE_TYPE.KC_ST_UINT64, 56),
1276                        KCSubTypeElement.FromBasicCtype('kernel_stack_latency', KCSUBTYPE_TYPE.KC_ST_UINT64, 64),
1277                        KCSubTypeElement.FromBasicCtype('misc_latency', KCSUBTYPE_TYPE.KC_ST_UINT64, 72),
1278            ),
1279            'stackshot_latency_thread')
1280
1281KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_THREAD_NAME')] = KCSubTypeElement('pth_name', KCSUBTYPE_TYPE.KC_ST_CHAR, KCSubTypeElement.GetSizeForArray(64, 1), 0, 1)
1282
1283def set_type(name, *args):
1284    typ = GetTypeForName(name)
1285    KNOWN_TYPES_COLLECTION[typ] = KCTypeDescription(GetTypeForName(typ), *args)
1286
1287
1288set_type('STACKSHOT_KCTYPE_USER_STACKTOP',
1289         (
1290             KCSubTypeElement.FromBasicCtype('sp', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
1291             KCSubTypeElement('stack_contents', KCSUBTYPE_TYPE.KC_ST_UINT8, KCSubTypeElement.GetSizeForArray(8, 1), 8, 1),
1292         ),
1293         'user_stacktop')
1294
1295#KNOWN_TYPES_COLLECTION[0x907] = KCSubTypeElement('donating_pids', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 0, 0, KCSubTypeElement._get_naked_element_value)
1296KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_PID')] = KCSubTypeElement('pid', KCSUBTYPE_TYPE.KC_ST_INT32, 4, 0, 0)
1297KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_PPID')] = KCSubTypeElement('ppid', KCSUBTYPE_TYPE.KC_ST_INT32, 4, 0, 0)
1298KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_PROC_NAME')] = KCSubTypeElement('p_comm', KCSUBTYPE_TYPE.KC_ST_CHAR,
1299                           KCSubTypeElement.GetSizeForArray(32, 1), 0, 1)
1300KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_USERSTACK')] = KCSubTypeElement('userstack_ptr', KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 0, 0)
1301KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_ARGSLEN')] = KCSubTypeElement('p_argslen', KCSUBTYPE_TYPE.KC_ST_INT32, 4, 0, 0)
1302
1303KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_PROC_PATH')] = KCSubTypeElement('p_path', KCSUBTYPE_TYPE.KC_ST_CHAR,
1304                           KCSubTypeElement.GetSizeForArray(1024, 1), 0, 1)
1305KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_PROC_CSFLAGS')] = KCSubTypeElement('p_csflags', KCSUBTYPE_TYPE.KC_ST_INT32, 4, 0, 0)
1306KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_UID')] = KCSubTypeElement('uid', KCSUBTYPE_TYPE.KC_ST_INT32, 4, 0, 0)
1307KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_GID')] = KCSubTypeElement('gid', KCSUBTYPE_TYPE.KC_ST_INT32, 4, 0, 0)
1308KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_PROC_ARGC')] = KCSubTypeElement('argc', KCSUBTYPE_TYPE.KC_ST_INT32, 4, 0, 0)
1309KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_PROC_FLAGS')] = KCSubTypeElement('p_flags', KCSUBTYPE_TYPE.KC_ST_INT32, 4, 0, 0)
1310KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_CPUTYPE')] = KCSubTypeElement('cputype', KCSUBTYPE_TYPE.KC_ST_INT32, 4, 0, 0)
1311KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_RESPONSIBLE_PID')] = KCSubTypeElement('responsible_pid', KCSUBTYPE_TYPE.KC_ST_INT32, 4, 0, 0)
1312KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_DIRTY_FLAGS')] = KCSubTypeElement('dirty_flags', KCSUBTYPE_TYPE.KC_ST_INT32, 4, 0, 0)
1313KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_CRASHED_THREADID')] = KCSubTypeElement('crashed_threadid', KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 0, 0)
1314KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_COALITION_ID')] = KCSubTypeElement('coalition_id', KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 0, 0)
1315
1316KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_PROC_STATUS')] = KCSubTypeElement('p_status', KCSUBTYPE_TYPE.KC_ST_UINT8, 1, 0, 0)
1317
1318KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_BSDINFOWITHUNIQID')] = KCTypeDescription(GetTypeForName('TASK_CRASHINFO_BSDINFOWITHUNIQID'),
1319    (   KCSubTypeElement('p_uuid', KCSUBTYPE_TYPE.KC_ST_UINT8, KCSubTypeElement.GetSizeForArray(16, 1), 0, 1),
1320        KCSubTypeElement.FromBasicCtype('p_uniqueid', KCSUBTYPE_TYPE.KC_ST_UINT64, 16),
1321        KCSubTypeElement.FromBasicCtype('p_puniqueid', KCSUBTYPE_TYPE.KC_ST_UINT64, 24)
1322    ),
1323    'proc_uniqidentifierinfo')
1324
1325KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_EXCEPTION_CODES')] = (
1326    KCTypeDescription(GetTypeForName('TASK_CRASHINFO_EXCEPTION_CODES'),
1327                      (KCSubTypeElement.FromBasicCtype('code_0', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
1328                       KCSubTypeElement.FromBasicCtype('code_1', KCSUBTYPE_TYPE.KC_ST_UINT64, 8)),
1329                      'mach_exception_data_t'))
1330
1331
1332KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_PROC_STARTTIME')] = (
1333    KCTypeDescription(GetTypeForName('TASK_CRASHINFO_PROC_STARTTIME'),
1334                      (KCSubTypeElement.FromBasicCtype('tv_sec', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
1335                       KCSubTypeElement.FromBasicCtype('tv_usec', KCSUBTYPE_TYPE.KC_ST_UINT64, 8)),
1336                      'proc_starttime'))
1337
1338
1339KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_RUSAGE_INFO')] = KCTypeDescription(GetTypeForName('TASK_CRASHINFO_RUSAGE_INFO'),
1340    (
1341        KCSubTypeElement('ri_uuid', KCSUBTYPE_TYPE.KC_ST_UINT8, KCSubTypeElement.GetSizeForArray(16, 1), 0, 1),
1342            KCSubTypeElement.FromBasicCtype('ri_user_time', KCSUBTYPE_TYPE.KC_ST_UINT64, 16),
1343            KCSubTypeElement.FromBasicCtype('ri_system_time', KCSUBTYPE_TYPE.KC_ST_UINT64, 24),
1344            KCSubTypeElement.FromBasicCtype('ri_pkg_idle_wkups', KCSUBTYPE_TYPE.KC_ST_UINT64, 32),
1345            KCSubTypeElement.FromBasicCtype('ri_interrupt_wkups', KCSUBTYPE_TYPE.KC_ST_UINT64, 40),
1346            KCSubTypeElement.FromBasicCtype('ri_pageins', KCSUBTYPE_TYPE.KC_ST_UINT64, 48),
1347            KCSubTypeElement.FromBasicCtype('ri_wired_size', KCSUBTYPE_TYPE.KC_ST_UINT64, 56),
1348            KCSubTypeElement.FromBasicCtype('ri_resident_size', KCSUBTYPE_TYPE.KC_ST_UINT64, 64),
1349            KCSubTypeElement.FromBasicCtype('ri_phys_footprint', KCSUBTYPE_TYPE.KC_ST_UINT64, 72),
1350            KCSubTypeElement.FromBasicCtype('ri_proc_start_abstime', KCSUBTYPE_TYPE.KC_ST_UINT64, 80),
1351            KCSubTypeElement.FromBasicCtype('ri_proc_exit_abstime', KCSUBTYPE_TYPE.KC_ST_UINT64, 88),
1352            KCSubTypeElement.FromBasicCtype('ri_child_user_time', KCSUBTYPE_TYPE.KC_ST_UINT64, 96),
1353            KCSubTypeElement.FromBasicCtype('ri_child_system_time', KCSUBTYPE_TYPE.KC_ST_UINT64, 104),
1354            KCSubTypeElement.FromBasicCtype('ri_child_pkg_idle_wkups', KCSUBTYPE_TYPE.KC_ST_UINT64, 112),
1355            KCSubTypeElement.FromBasicCtype('ri_child_interrupt_wkups', KCSUBTYPE_TYPE.KC_ST_UINT64, 120),
1356            KCSubTypeElement.FromBasicCtype('ri_child_pageins', KCSUBTYPE_TYPE.KC_ST_UINT64, 128),
1357            KCSubTypeElement.FromBasicCtype('ri_child_elapsed_abstime', KCSUBTYPE_TYPE.KC_ST_UINT64, 136),
1358            KCSubTypeElement.FromBasicCtype('ri_diskio_bytesread', KCSUBTYPE_TYPE.KC_ST_UINT64, 144),
1359            KCSubTypeElement.FromBasicCtype('ri_diskio_byteswritten', KCSUBTYPE_TYPE.KC_ST_UINT64, 152),
1360            KCSubTypeElement.FromBasicCtype('ri_cpu_time_qos_default', KCSUBTYPE_TYPE.KC_ST_UINT64, 160),
1361            KCSubTypeElement.FromBasicCtype('ri_cpu_time_qos_maintenance', KCSUBTYPE_TYPE.KC_ST_UINT64, 168),
1362            KCSubTypeElement.FromBasicCtype('ri_cpu_time_qos_background', KCSUBTYPE_TYPE.KC_ST_UINT64, 176),
1363            KCSubTypeElement.FromBasicCtype('ri_cpu_time_qos_utility', KCSUBTYPE_TYPE.KC_ST_UINT64, 184),
1364            KCSubTypeElement.FromBasicCtype('ri_cpu_time_qos_legacy', KCSUBTYPE_TYPE.KC_ST_UINT64, 192),
1365            KCSubTypeElement.FromBasicCtype('ri_cpu_time_qos_user_initiated', KCSUBTYPE_TYPE.KC_ST_UINT64, 200),
1366            KCSubTypeElement.FromBasicCtype('ri_cpu_time_qos_user_interactiv', KCSUBTYPE_TYPE.KC_ST_UINT64, 208),
1367            KCSubTypeElement.FromBasicCtype('ri_billed_system_time', KCSUBTYPE_TYPE.KC_ST_UINT64, 216),
1368            KCSubTypeElement.FromBasicCtype('ri_serviced_system_time', KCSUBTYPE_TYPE.KC_ST_UINT64, 224)
1369    ),
1370    'rusage_info')
1371
1372#The sizes for these need to be kept in sync with
1373#MAX_CRASHINFO_SIGNING_ID_LEN, MAX_CRASHINFO_TEAM_ID_LEN
1374KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_CS_SIGNING_ID')] = KCSubTypeElement('cs_signing_id', KCSUBTYPE_TYPE.KC_ST_CHAR,
1375                           KCSubTypeElement.GetSizeForArray(64, 1), 0, 1)
1376KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_CS_TEAM_ID')] = KCSubTypeElement('cs_team_id', KCSUBTYPE_TYPE.KC_ST_CHAR,
1377                           KCSubTypeElement.GetSizeForArray(32, 1), 0, 1)
1378
1379KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_CS_VALIDATION_CATEGORY')] = KCSubTypeElement('cs_validation_category', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 0, 0)
1380
1381KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_CS_TRUST_LEVEL')] = KCSubTypeElement('cs_trust_level', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 0, 0)
1382
1383KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_JIT_ADDRESS_RANGE')] = KCTypeDescription(GetTypeForName('TASK_CRASHINFO_JIT_ADDRESS_RANGE'),
1384    (
1385        KCSubTypeElement.FromBasicCtype('start_address', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
1386        KCSubTypeElement.FromBasicCtype('end_address', KCSUBTYPE_TYPE.KC_ST_UINT64, 8),
1387    ), 'jit_address_range')
1388
1389KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_MB')] = KCTypeDescription(GetTypeForName('TASK_CRASHINFO_MB'),
1390    (
1391        KCSubTypeElement.FromBasicCtype('start_address', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
1392        KCSubTypeElement('data', KCSUBTYPE_TYPE.KC_ST_UINT64, KCSubTypeElement.GetSizeForArray(64, 64), 8, 0),
1393    )
1394)
1395
1396KNOWN_TYPES_COLLECTION[GetTypeForName('TASK_CRASHINFO_CS_AUXILIARY_INFO')] = KCSubTypeElement('cs_auxiliary_info', KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 0, 0)
1397
1398KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_CPU_TIMES')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_CPU_TIMES'),
1399    (
1400        KCSubTypeElement.FromBasicCtype('user_usec', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
1401        KCSubTypeElement.FromBasicCtype('system_usec', KCSUBTYPE_TYPE.KC_ST_UINT64, 8),
1402        KCSubTypeElement.FromBasicCtype('runnable_usec', KCSUBTYPE_TYPE.KC_ST_UINT64, 16),
1403    ), 'cpu_times')
1404
1405KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_STACKSHOT_DURATION')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_STACKSHOT_DURATION'),
1406    (
1407        KCSubTypeElement.FromBasicCtype('stackshot_duration', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
1408        KCSubTypeElement.FromBasicCtype('stackshot_duration_outer', KCSUBTYPE_TYPE.KC_ST_UINT64, 8),
1409        KCSubTypeElement.FromBasicCtype('stackshot_duration_prior', KCSUBTYPE_TYPE.KC_ST_UINT64, 16),
1410    ), 'stackshot_duration', merge=True
1411)
1412
1413KNOWN_TYPES_COLLECTION[GetTypeForName('KCDATA_TYPE_PROCNAME')] = (
1414    KCSubTypeElement("proc_name", KCSUBTYPE_TYPE.KC_ST_CHAR, KCSubTypeElement.GetSizeForArray(-1, 1), 0, 1))
1415
1416KNOWN_TYPES_COLLECTION[GetTypeForName('KCDATA_TYPE_PID')] = (
1417    KCSubTypeElement('pid', KCSUBTYPE_TYPE.KC_ST_INT32, 4, 0, 0))
1418
1419KNOWN_TYPES_COLLECTION[GetTypeForName('KCDATA_TYPE_LIBRARY_AOTINFO')] = KCTypeDescription(GetTypeForName('KCDATA_TYPE_LIBRARY_AOTINFO'),
1420    (
1421        KCSubTypeElement('x86LoadAddress', KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 0, 0),
1422        KCSubTypeElement('aotLoadAddress', KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 8, 0),
1423        KCSubTypeElement('aotImageSize', KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 16, 0),
1424        KCSubTypeElement('aotImageKey', KCSUBTYPE_TYPE.KC_ST_UINT8, KCSubTypeElement.GetSizeForArray(32, 1), 24, 1),
1425    ), 'dyld_aot_info')
1426
1427KNOWN_TYPES_COLLECTION[GetTypeForName('EXIT_REASON_SNAPSHOT')] = KCTypeDescription(GetTypeForName('EXIT_REASON_SNAPSHOT'),
1428    (
1429        KCSubTypeElement.FromBasicCtype('ers_namespace', KCSUBTYPE_TYPE.KC_ST_UINT32, 0),
1430        KCSubTypeElement.FromBasicCtype('ers_code', KCSUBTYPE_TYPE.KC_ST_UINT64, 4),
1431        KCSubTypeElement.FromBasicCtype('ers_flags', KCSUBTYPE_TYPE.KC_ST_UINT64, 12),
1432    ), 'exit_reason_basic_info')
1433
1434KNOWN_TYPES_COLLECTION[GetTypeForName('EXIT_REASON_USER_DESC')] = (
1435    KCSubTypeElement("exit_reason_user_description", KCSUBTYPE_TYPE.KC_ST_CHAR, KCSubTypeElement.GetSizeForArray(-1, 1), 0, 1))
1436
1437KNOWN_TYPES_COLLECTION[GetTypeForName('EXIT_REASON_USER_PAYLOAD')] = KCSubTypeElement('exit_reason_user_payload',
1438        KCSUBTYPE_TYPE.KC_ST_UINT8, KCSubTypeElement.GetSizeForArray(-1, 1), 0, 1)
1439
1440KNOWN_TYPES_COLLECTION[GetTypeForName('EXIT_REASON_CODESIGNING_INFO')] = KCTypeDescription(GetTypeForName('EXIT_REASON_CODESIGNING_INFO'),
1441    (
1442        KCSubTypeElement.FromBasicCtype('ceri_virt_addr', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
1443        KCSubTypeElement.FromBasicCtype('ceri_file_offset', KCSUBTYPE_TYPE.KC_ST_UINT64, 8),
1444        KCSubTypeElement("ceri_pathname", KCSUBTYPE_TYPE.KC_ST_CHAR, KCSubTypeElement.GetSizeForArray(1024, 1), 16, 1),
1445        KCSubTypeElement("ceri_filename", KCSUBTYPE_TYPE.KC_ST_CHAR, KCSubTypeElement.GetSizeForArray(1024, 1), 1040, 1),
1446        KCSubTypeElement.FromBasicCtype('ceri_codesig_modtime_secs', KCSUBTYPE_TYPE.KC_ST_UINT64, 2064),
1447        KCSubTypeElement.FromBasicCtype('ceri_codesig_modtime_nsecs', KCSUBTYPE_TYPE.KC_ST_UINT64, 2072),
1448        KCSubTypeElement.FromBasicCtype('ceri_page_modtime_secs', KCSUBTYPE_TYPE.KC_ST_UINT64, 2080),
1449        KCSubTypeElement.FromBasicCtype('ceri_page_modtime_nsecs', KCSUBTYPE_TYPE.KC_ST_UINT64, 2088),
1450        KCSubTypeElement.FromBasicCtype('ceri_path_truncated', KCSUBTYPE_TYPE.KC_ST_UINT8, 2096),
1451        KCSubTypeElement.FromBasicCtype('ceri_object_codesigned', KCSUBTYPE_TYPE.KC_ST_UINT8, 2097),
1452        KCSubTypeElement.FromBasicCtype('ceri_page_codesig_validated', KCSUBTYPE_TYPE.KC_ST_UINT8, 2098),
1453        KCSubTypeElement.FromBasicCtype('ceri_page_codesig_tainted', KCSUBTYPE_TYPE.KC_ST_UINT8, 2099),
1454        KCSubTypeElement.FromBasicCtype('ceri_page_codesig_nx', KCSUBTYPE_TYPE.KC_ST_UINT8, 2100),
1455        KCSubTypeElement.FromBasicCtype('ceri_page_wpmapped', KCSUBTYPE_TYPE.KC_ST_UINT8, 2101),
1456        KCSubTypeElement.FromBasicCtype('ceri_page_slid', KCSUBTYPE_TYPE.KC_ST_UINT8, 2102),
1457        KCSubTypeElement.FromBasicCtype('ceri_page_dirty', KCSUBTYPE_TYPE.KC_ST_UINT8, 2103),
1458        KCSubTypeElement.FromBasicCtype('ceri_page_shadow_depth', KCSUBTYPE_TYPE.KC_ST_UINT32, 2104),
1459    ), 'exit_reason_codesigning_info')
1460
1461KNOWN_TYPES_COLLECTION[GetTypeForName('EXIT_REASON_WORKLOOP_ID')] = (
1462        KCSubTypeElement('exit_reason_workloop_id', KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 0, 0, KCSubTypeElement._get_naked_element_value))
1463
1464KNOWN_TYPES_COLLECTION[GetTypeForName('EXIT_REASON_DISPATCH_QUEUE_NO')] = (
1465        KCSubTypeElement('exit_reason_dispatch_queue_no', KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 0, 0, KCSubTypeElement._get_naked_element_value))
1466
1467KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_ASID')] = (
1468    KCSubTypeElement('ts_asid', KCSUBTYPE_TYPE.KC_ST_UINT32, 4, 0, 0))
1469
1470KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_PAGE_TABLES')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_PAGE_TABLES'), (
1471    KCSubTypeElement(None, KCSUBTYPE_TYPE.KC_ST_UINT64, 8, 0, 0, KCSubTypeElement._get_naked_element_value), ),
1472    'ts_pagetable',
1473    merge=True,
1474    naked=True
1475)
1476
1477KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_SUSPENSION_INFO')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_SUSPENSION_INFO'), (
1478    KCSubTypeElement.FromBasicCtype('tss_last_start', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
1479    KCSubTypeElement.FromBasicCtype('tss_last_end', KCSUBTYPE_TYPE.KC_ST_UINT64, 8),
1480    KCSubTypeElement.FromBasicCtype('tss_count', KCSUBTYPE_TYPE.KC_ST_UINT64, 16),
1481    KCSubTypeElement.FromBasicCtype('tss_duration', KCSUBTYPE_TYPE.KC_ST_UINT64, 24),
1482), 'suspension_info')
1483
1484KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_SUSPENSION_SOURCE')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_SUSPENSION_SOURCE'), (
1485    KCSubTypeElement.FromBasicCtype('tss_time', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
1486    KCSubTypeElement.FromBasicCtype('tss_tid', KCSUBTYPE_TYPE.KC_ST_UINT64, 8),
1487    KCSubTypeElement.FromBasicCtype('tss_pid', KCSUBTYPE_TYPE.KC_ST_INT32, 16),
1488    KCSubTypeElement('tss_procname', KCSUBTYPE_TYPE.KC_ST_CHAR, KCSubTypeElement.GetSizeForArray(65, 1), 20, 1)
1489), 'suspension_source')
1490
1491KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_OS_BUILD_VERSION')] = KCSubTypeElement('os_build_version', KCSUBTYPE_TYPE.KC_ST_CHAR,
1492                          KCSubTypeElement.GetSizeForArray(256, 1), 0, 1)
1493
1494KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_KERN_EXCLAVES_THREADINFO')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_KERN_EXCLAVES_THREADINFO'),
1495    (
1496        KCSubTypeElement.FromBasicCtype('tei_scid', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
1497        KCSubTypeElement.FromBasicCtype('tei_thread_offset', KCSUBTYPE_TYPE.KC_ST_UINT32, 8),
1498        KCSubTypeElement.FromBasicCtype('tei_flags', KCSUBTYPE_TYPE.KC_ST_UINT32, 12),
1499    ), 'exclaves_thread_info')
1500
1501KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_EXCLAVE_SCRESULT_INFO')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_EXCLAVE_SCRESULT_INFO'),
1502    (
1503        KCSubTypeElement.FromBasicCtype('esc_id', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
1504        KCSubTypeElement.FromBasicCtype('esc_flags', KCSUBTYPE_TYPE.KC_ST_UINT64, 8),
1505    ), 'exclave_scresult_info')
1506
1507KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_EXCLAVE_IPCSTACKENTRY_INFO')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_EXCLAVE_IPCSTACKENTRY_INFO'),
1508    (
1509        KCSubTypeElement.FromBasicCtype('eise_asid', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
1510        KCSubTypeElement.FromBasicCtype('eise_tnid', KCSUBTYPE_TYPE.KC_ST_UINT64, 8),
1511        KCSubTypeElement.FromBasicCtype('eise_invocationid', KCSUBTYPE_TYPE.KC_ST_UINT64, 16),
1512        KCSubTypeElement.FromBasicCtype('eise_flags', KCSUBTYPE_TYPE.KC_ST_UINT64, 24),
1513    ), 'exclave_ipcstackentry_info')
1514
1515KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_EXCLAVE_IPCSTACKENTRY_ECSTACK')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_EXCLAVE_IPCSTACKENTRY_ECSTACK'),
1516    (
1517        KCSubTypeElement.FromBasicCtype('lr', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
1518    ), 'secure_ecstack_entry')
1519
1520KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_EXCLAVE_ADDRESSSPACE_INFO')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_EXCLAVE_ADDRESSSPACE_INFO'),
1521    (
1522        KCSubTypeElement.FromBasicCtype('eas_id', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
1523        KCSubTypeElement.FromBasicCtype('eas_flags', KCSUBTYPE_TYPE.KC_ST_UINT64, 8),
1524        KCSubTypeElement.FromBasicCtype('eas_layoutid', KCSUBTYPE_TYPE.KC_ST_UINT64, 16),
1525        KCSubTypeElement.FromBasicCtype('eas_slide', KCSUBTYPE_TYPE.KC_ST_UINT64, 24),
1526        KCSubTypeElement.FromBasicCtype('eas_asroot', KCSUBTYPE_TYPE.KC_ST_UINT64, 32),
1527    ), 'exclave_addressspace_info')
1528
1529KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_EXCLAVE_ADDRESSSPACE_NAME')] = KCSubTypeElement('exclave_addressspace_name', KCSUBTYPE_TYPE.KC_ST_CHAR, KCSubTypeElement.GetSizeForArray(64, 1), 0, 1)
1530
1531KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_EXCLAVE_TEXTLAYOUT_INFO')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_EXCLAVE_TEXTLAYOUT_INFO'),
1532    (
1533        KCSubTypeElement.FromBasicCtype('layout_id', KCSUBTYPE_TYPE.KC_ST_UINT64, 0),
1534        KCSubTypeElement.FromBasicCtype('etl_flags', KCSUBTYPE_TYPE.KC_ST_UINT64, 8),
1535        KCSubTypeElement.FromBasicCtype('sharedcache_index', KCSUBTYPE_TYPE.KC_ST_UINT32, 16),
1536    ), 'exclave_textlayout_info')
1537
1538KNOWN_TYPES_COLLECTION[GetTypeForName('STACKSHOT_KCTYPE_EXCLAVE_TEXTLAYOUT_SEGMENTS')] = KCTypeDescription(GetTypeForName('STACKSHOT_KCTYPE_EXCLAVE_TEXTLAYOUT_SEGMENTS'),
1539    (
1540        KCSubTypeElement('layoutSegment_uuid', KCSUBTYPE_TYPE.KC_ST_UINT8, KCSubTypeElement.GetSizeForArray(16, 1), 0, 1),
1541        KCSubTypeElement.FromBasicCtype('layoutSegment_loadAddress', KCSUBTYPE_TYPE.KC_ST_UINT64, 16),
1542        KCSubTypeElement.FromBasicCtype('layoutSegment_rawLoadAddress', KCSUBTYPE_TYPE.KC_ST_UINT64, 24),
1543    ), 'exclave_textlayout_segments')
1544
1545
1546
1547def GetSecondsFromMATime(mat, tb):
1548    return (float(long(mat) * tb['numer']) / tb['denom']) / 1e9
1549
1550def GetLongForAddress(address):
1551    if isinstance(address, str):
1552        if '0x' in address.lower():
1553            address = long(address, 16)
1554        else:
1555            address = long(address)
1556    return address
1557
1558def FindLibraryForAddress(liblist, address):
1559    current_lib = None
1560    for l in liblist:
1561        l_addr = GetLongForAddress(l[1])
1562        if address >= l_addr:
1563            current_lib = l
1564    return current_lib
1565
1566def FindIndexOfLibInCatalog(catalog, lib):
1567    index = None
1568    i = 0
1569    for l in catalog:
1570        if l[0] == lib[0] and l[1] == lib[1]:
1571            index = i
1572            break
1573        i += 1
1574
1575    if index is None:
1576        catalog.append(lib)
1577        index = len(catalog) - 1
1578
1579    return index
1580
1581def GetOffsetOfAddressForLib(lib, address):
1582    return (address - GetLongForAddress(lib[1]))
1583
1584def GetSymbolInfoForFrame(catalog, liblist, address):
1585    address = GetLongForAddress(address)
1586    lib = FindLibraryForAddress(liblist, address)
1587    if not lib:
1588        lib = ["00000000000000000000000000000000",0,"A"]
1589    offset = GetOffsetOfAddressForLib(lib, address)
1590    index = FindIndexOfLibInCatalog(catalog, lib)
1591    return [index, offset]
1592
1593def GetStateDescription(s):
1594    retval = []
1595    TH_WAIT = 0x01
1596    TH_SUSP = 0x02
1597    TH_RUN = 0x04
1598    TH_UNINT = 0x08
1599    TH_TERMINATE = 0x10
1600    TH_TERMINATE2 = 0x20
1601    TH_WAIT_REPORT = 0x40
1602    TH_IDLE = 0x80
1603    if (s & TH_WAIT):
1604        retval.append("TH_WAIT")
1605    if (s & TH_SUSP):
1606        retval.append("TH_SUSP")
1607    if (s & TH_RUN):
1608        retval.append("TH_RUN")
1609    if (s & TH_UNINT):
1610        retval.append("TH_UNINT")
1611    if (s & TH_TERMINATE):
1612        retval.append("TH_TERMINATE")
1613    if (s & TH_TERMINATE2):
1614        retval.append("TH_TERMINATE2")
1615    if (s & TH_WAIT_REPORT):
1616        retval.append("TH_WAIT_REPORT")
1617    if (s & TH_IDLE):
1618        retval.append("TH_IDLE")
1619    return retval
1620
1621
1622def format_uuid(elementValues):
1623    # sometimes we get string like "25A926D8-F742-3E5E..."
1624    if isinstance(elementValues, str):
1625        return elementValues
1626    return ''.join("%02x" % i for i in elementValues)
1627
1628kThreadWaitNone                 = 0x00
1629kThreadWaitKernelMutex          = 0x01
1630kThreadWaitPortReceive          = 0x02
1631kThreadWaitPortSetReceive       = 0x03
1632kThreadWaitPortSend             = 0x04
1633kThreadWaitPortSendInTransit    = 0x05
1634kThreadWaitSemaphore            = 0x06
1635kThreadWaitKernelRWLockRead     = 0x07
1636kThreadWaitKernelRWLockWrite    = 0x08
1637kThreadWaitKernelRWLockUpgrade  = 0x09
1638kThreadWaitUserLock             = 0x0a
1639kThreadWaitPThreadMutex         = 0x0b
1640kThreadWaitPThreadRWLockRead    = 0x0c
1641kThreadWaitPThreadRWLockWrite   = 0x0d
1642kThreadWaitPThreadCondVar       = 0x0e
1643kThreadWaitParkedWorkQueue      = 0x0f
1644kThreadWaitWorkloopSyncWait     = 0x10
1645kThreadWaitOnProcess            = 0x11
1646kThreadWaitSleepWithInheritor   = 0x12
1647kThreadWaitEventlink            = 0x13
1648kThreadWaitCompressor           = 0x14
1649kThreadWaitParkedBoundWorkQueue = 0x15
1650kThreadWaitPageBusy             = 0x16
1651kThreadWaitPagerInit            = 0x17
1652kThreadWaitPagerReady           = 0x18
1653kThreadWaitPagingActivity       = 0x19
1654kThreadWaitMappingInProgress    = 0x1a
1655kThreadWaitMemoryBlocked        = 0x1b
1656kThreadWaitPagingInProgress     = 0x1c
1657kThreadWaitPageInThrottle       = 0x1d
1658kThreadWaitExclaveCore          = 0x1e
1659kThreadWaitExclaveKit           = 0x1f
1660
1661
1662UINT64_MAX = 0xffffffffffffffff
1663STACKSHOT_WAITOWNER_KERNEL      = (UINT64_MAX - 1)
1664STACKSHOT_WAITOWNER_PORT_LOCKED = (UINT64_MAX - 2)
1665STACKSHOT_WAITOWNER_PSET_LOCKED = (UINT64_MAX - 3)
1666STACKSHOT_WAITOWNER_INTRANSIT   = (UINT64_MAX - 4)
1667STACKSHOT_WAITOWNER_MTXSPIN     = (UINT64_MAX - 5)
1668STACKSHOT_WAITOWNER_THREQUESTED = (UINT64_MAX - 6)
1669STACKSHOT_WAITOWNER_SUSPENDED   = (UINT64_MAX - 7)
1670
1671STACKSHOT_TURNSTILE_STATUS_UNKNOWN         = 0x01
1672STACKSHOT_TURNSTILE_STATUS_LOCKED_WAITQ    = 0x02
1673STACKSHOT_TURNSTILE_STATUS_WORKQUEUE       = 0x04
1674STACKSHOT_TURNSTILE_STATUS_THREAD          = 0x08
1675STACKSHOT_TURNSTILE_STATUS_BLOCKED_ON_TASK = 0x10
1676STACKSHOT_TURNSTILE_STATUS_HELD_IPLOCK     = 0x20
1677STACKSHOT_TURNSTILE_STATUS_SENDPORT        = 0x40
1678STACKSHOT_TURNSTILE_STATUS_RECEIVEPORT     = 0x80
1679
1680#
1681# These come from xpc_domain_type_t in <xpc/launch_private.h>
1682PORTLABEL_DOMAINS = {
1683    1: 'system',        # XPC_DOMAIN_SYSTEM
1684    2: 'user',          # XPC_DOMAIN_USER
1685    5: 'pid',           # XPC_DOMAIN_PID
1686    7: 'port',          # XPC_DOMAIN_PORT
1687}
1688def portlabel_domain(x):
1689    if x is None:
1690        return "unknown"
1691    return PORTLABEL_DOMAINS.get(x, "unknown.{}".format(x))
1692
1693STACKSHOT_WAITINFO_FLAGS_SPECIALREPLY = 0x1
1694STACKSHOT_PORTLABEL_THROTTLED = 0x2
1695
1696def portThrottledSuffix(portlabel_flags):
1697    if (portlabel_flags & STACKSHOT_PORTLABEL_THROTTLED):
1698        return " (service port throttled by launchd)"
1699    else:
1700        return ""
1701
1702def formatPortLabelID(portlabel_id, portlabels):
1703    portlabel = {}
1704    if portlabel_id > 0:
1705        if portlabels is not None:
1706            portlabel = portlabels.get(str(portlabel_id), {})
1707        portlabel_name = portlabel_domain(portlabel.get('portlabel_domain')) + " "
1708        portlabel_name += portlabel.get("portlabel_name", "!!!unknown, ID {} !!!".format(portlabel_id))
1709        return " {" + portlabel_name + portThrottledSuffix(portlabel.get('portlabel_flags', 0)) + "}"
1710    if portlabel_id < 0:
1711        return " {labeled, info truncated" + portThrottledSuffix(portlabel.get('portlabel_flags', 0)) + "}"
1712    return ""
1713
1714def formatWaitInfo(info, wantHex, portlabels):
1715    base='#x' if wantHex else 'd'
1716    s = 'thread {0:{base}}: '.format(info['waiter'], base=base)
1717    type = info['wait_type']
1718    context = info['context']
1719    owner = info['owner']
1720    ownerThread = "{0:{base}}".format(owner, base=base)
1721    portlabel_id = info.get('portlabel_id', 0)
1722    flags = info.get('wait_flags', 0)
1723
1724    if type == kThreadWaitKernelMutex:
1725        s += 'kernel mutex %x' % context
1726        if owner == STACKSHOT_WAITOWNER_MTXSPIN:
1727            s += " in spin mode"
1728        elif owner:
1729            s += " owned by thread %s" % ownerThread
1730        else:
1731            s += "with unknown owner"
1732    elif type == kThreadWaitPortReceive:
1733        s += "mach_msg receive on "
1734        if flags & STACKSHOT_WAITINFO_FLAGS_SPECIALREPLY:
1735            s += "REPLY "
1736            flags = flags - STACKSHOT_WAITINFO_FLAGS_SPECIALREPLY
1737        if owner == STACKSHOT_WAITOWNER_PORT_LOCKED:
1738            s += "locked port %x" % context
1739        elif owner == STACKSHOT_WAITOWNER_INTRANSIT:
1740            s += "intransit port %x" % context
1741        elif owner:
1742            s += "port %x name %x" % (context, owner)
1743        else:
1744            s += "port %x" % context
1745    elif type == kThreadWaitPortSetReceive:
1746        if owner == STACKSHOT_WAITOWNER_PSET_LOCKED:
1747            s += "mach_msg receive on locked port set %x" % context
1748        else:
1749            s += "mach_msg receive on port set %x" % context
1750    elif type == kThreadWaitPortSend:
1751        s += "mach_msg send on "
1752        if owner == STACKSHOT_WAITOWNER_PORT_LOCKED:
1753            s += "locked port %x" % context
1754        elif owner == STACKSHOT_WAITOWNER_INTRANSIT:
1755            s += "intransit port %x" % context
1756        elif owner == STACKSHOT_WAITOWNER_KERNEL:
1757            s += "port %x owned by kernel" % context
1758        elif owner:
1759            s += "port %x owned by pid %d" % (context, owner)
1760        else:
1761            s += "port %x with unknown owner" % context
1762    elif type == kThreadWaitPortSendInTransit:
1763        s += "mach_msg send on port %x in transit to " % context
1764        if owner:
1765            s += "port %x" % owner
1766        else:
1767            s += "unknown port"
1768    elif type == kThreadWaitSemaphore:
1769        s += "semaphore port %x " % context
1770        if owner:
1771            s += "owned by pid %d" % owner
1772        else:
1773            s += "with unknown owner"
1774    elif type == kThreadWaitKernelRWLockRead:
1775        s += "krwlock %x for reading" % context
1776        if owner:
1777            s += " owned by thread %s" % ownerThread
1778    elif type == kThreadWaitKernelRWLockWrite:
1779        s += "krwlock %x for writing" % context
1780        if owner:
1781            s += " owned by thread %s" % ownerThread
1782    elif type == kThreadWaitKernelRWLockUpgrade:
1783        s += "krwlock %x for upgrading" % context
1784        if owner:
1785            s += " owned by thread %s" % ownerThread
1786    elif type == kThreadWaitUserLock:
1787        if owner:
1788            s += "unfair lock %x owned by thread %s" % (context, ownerThread)
1789        else:
1790            s += "spin lock %x" % context
1791    elif type == kThreadWaitPThreadMutex:
1792        s += "pthread mutex %x" % context
1793        if owner:
1794            s += " owned by thread %s" % ownerThread
1795        else:
1796            s += " with unknown owner"
1797    elif type == kThreadWaitPThreadRWLockRead:
1798        s += "pthread rwlock %x for reading" % context
1799    elif type == kThreadWaitPThreadRWLockWrite:
1800        s += "pthread rwlock %x for writing" % context
1801    elif type == kThreadWaitPThreadCondVar:
1802        s += "pthread condvar %x" % context
1803    elif type == kThreadWaitWorkloopSyncWait:
1804        s += "workloop sync wait"
1805        if owner == STACKSHOT_WAITOWNER_SUSPENDED:
1806            s += ", suspended"
1807        elif owner == STACKSHOT_WAITOWNER_THREQUESTED:
1808            s += ", thread requested"
1809        elif owner != 0:
1810            s += ", owned by thread %s" % ownerThread
1811        else:
1812            s += ", unknown owner"
1813        s += ", workloop id %x" % context
1814    elif type == kThreadWaitOnProcess:
1815        if owner == 2**64-1:
1816            s += "waitpid, for any children"
1817        elif 2**32 <= owner and owner < 2**64-1:
1818            s += "waitpid, for process group %d" % abs(owner - 2**64)
1819        else:
1820            s += "waitpid, for pid %d" % owner
1821    elif type == kThreadWaitSleepWithInheritor:
1822        if owner == 0:
1823            s += "turnstile, held waitq"
1824        else:
1825            s += "turnstile, pushing thread %s" % ownerThread
1826    elif type == kThreadWaitEventlink:
1827        if owner == 0:
1828            s += "eventlink, held waitq"
1829        else:
1830            s += "eventlink, signaled by thread %s" % ownerThread
1831    elif type == kThreadWaitCompressor:
1832        s += "in compressor segment %x, busy for thread %s" % (context, ownerThread)
1833    elif type == kThreadWaitExclaveCore:
1834        if owner == 0:
1835            s += "exclavecore wait, id 0x%x" % context
1836        else:
1837            s += "exclavecore wait, id 0x%x, owner thread %s" % (context, ownerThread)
1838    elif type == kThreadWaitExclaveKit:
1839        if owner == 0:
1840            s += "exclavekit wait, id 0x%x" % context
1841        else:
1842            s += "exclavekit wait, id 0x%x, owner thread %s" % (context, ownerThread)
1843    elif type == kThreadWaitPageBusy:
1844        s += f"busy page 0x{context:x}"
1845    elif type == kThreadWaitPagerInit:
1846        s += f"pager initialization for vm object 0x{context:x}"
1847    elif type == kThreadWaitPagerReady:
1848        s += f"pager ready for vm object 0x{context:x}"
1849    elif type == kThreadWaitPagingActivity:
1850        s += f"paging/activity in progress for vm object 0x{context:x}"
1851    elif type == kThreadWaitMappingInProgress:
1852        s += f"mapping in progress for vm object 0x{context:x}"
1853    elif type == kThreadWaitMemoryBlocked:
1854        s += f"blocked vm object 0x{context:x}"
1855    elif type == kThreadWaitPagingInProgress:
1856        s += f"paging in progress for vm object 0x{context:x}"
1857    elif type == kThreadWaitPageInThrottle:
1858        s += f"throttled vm object 0x{context:x}"
1859    else:
1860        s += "unknown type %d (owner %s, context %x)" % (type, ownerThread, context)
1861
1862    s += formatPortLabelID(portlabel_id, portlabels)
1863
1864    if flags != 0:
1865        s += "flags {}".format(hex(flags))
1866    return s
1867
1868def formatTurnstileInfo(ti, wi_portlabel_id, portlabels):
1869    if ti is None:
1870        return " [no turnstile]"
1871
1872    ts_flags = int(ti['turnstile_flags'])
1873    ctx = int(ti['turnstile_context'])
1874    hop = int(ti['number_of_hops'])
1875    prio = int(ti['turnstile_priority'])
1876    portlabel_id = ti.get("portlabel_id", 0)
1877
1878    portlabel_summary = ""
1879    if portlabel_id != 0 and portlabel_id != wi_portlabel_id:
1880        portlabel_summary += formatPortLabelID(portlabel_id, portlabels)
1881
1882    if ts_flags & STACKSHOT_TURNSTILE_STATUS_HELD_IPLOCK:
1883        return " [turnstile blocked on task, but ip_lock was held]" + portlabel_summary
1884    if ts_flags & STACKSHOT_TURNSTILE_STATUS_BLOCKED_ON_TASK:
1885        return " [turnstile blocked on task pid %d, hops: %d, priority: %d]%s" % (ctx, hop, prio, portlabel_summary)
1886    if ts_flags & STACKSHOT_TURNSTILE_STATUS_LOCKED_WAITQ:
1887        return " [turnstile was in process of being updated]" + portlabel_summary
1888    if ts_flags & STACKSHOT_TURNSTILE_STATUS_WORKQUEUE:
1889        return " [blocked on workqueue: 0x%x, hops: %x, priority: %d]%s" % (ctx, hop, prio, portlabel_summary)
1890    if ts_flags & STACKSHOT_TURNSTILE_STATUS_THREAD:
1891        return " [blocked on: %d, hops: %x, priority: %d]%s" % (ctx, hop, prio, portlabel_summary)
1892    if ts_flags & STACKSHOT_TURNSTILE_STATUS_UNKNOWN:
1893        return " [turnstile with unknown inheritor]" + portlabel_summary
1894
1895    return " [unknown turnstile status!]" + portlabel_summary
1896
1897def formatWaitInfoWithTurnstiles(waitinfos, tsinfos, portlabels):
1898    wis_tis = []
1899    for w in waitinfos:
1900        found_pair = False
1901        for t in tsinfos:
1902            if int(w['waiter']) == int(t['waiter']):
1903                wis_tis.append((w, t))
1904                found_pair = True
1905                break
1906        if not found_pair:
1907            wis_tis.append((w, None))
1908
1909    return [formatWaitInfo(wi, False, portlabels) + formatTurnstileInfo(ti, wi.get('portlabel_id', 0), portlabels) for (wi, ti) in wis_tis]
1910
1911
1912def FindTextLayout(text_layouts, text_layout_id):
1913    for layout in text_layouts.values():
1914        if layout['exclave_textlayout_info']['layout_id'] == text_layout_id:
1915            return layout
1916    return None
1917
1918def BinaryImagesFromExclavesLayout(textlayout):
1919    flags = textlayout['exclave_textlayout_info']['etl_flags']
1920    sharedCacheIndex = textlayout['exclave_textlayout_info'].get('sharedcache_index', 0xffffffff)
1921    layouts = [ [format_uuid(layout['layoutSegment_uuid']), layout['layoutSegment_loadAddress'], 'P'] for layout in textlayout['exclave_textlayout_segments'] ]
1922    # 0x4 == kExclaveTextLayoutHasSharedCache
1923    if ((flags & 0x4) != 0 and sharedCacheIndex < len(layouts)):
1924        layouts[sharedCacheIndex][2] = "S"
1925    layouts.sort(key=itemgetter(1))
1926    return layouts
1927
1928def GetExclaveLibs(text_layouts, text_layout_id):
1929    textlayout = text_layouts.get(str(text_layout_id))
1930
1931    # This fallback is needed to preserve compatibility with kcdata generated before rdar://123838752
1932    # FindTextLayout function should be removed in future
1933    if not textlayout or textlayout['exclave_textlayout_info']['layout_id'] != text_layout_id:
1934        textlayout = FindTextLayout(text_layouts, text_layout_id)
1935
1936    return BinaryImagesFromExclavesLayout(textlayout)
1937
1938# kcdata is json at path 'kcdata_stackshot/threads_exclave/0'
1939def GetEASFrames(AllImageCatalog, kcdata, ipc_entry, notes, scid):
1940    info = ipc_entry['exclave_ipcstackentry_info']
1941    asid = info['eise_asid']
1942
1943    address_spaces = kcdata.get('exclave_addressspace')
1944    if not address_spaces:
1945        notes.warn("PID ${PID} TID ${TID} SCID %d Missing address spaces info" % scid)
1946        return []
1947    as_info = address_spaces.get(str(asid))
1948    if not as_info:
1949        notes.warn("PID ${PID} TID ${TID} SCID %d Missing address space info for ASID 0x%x" % (scid, asid))
1950        return []
1951    text_layout_id = as_info['exclave_addressspace_info']['eas_layoutid']
1952    addr_space_name = as_info['exclave_addressspace_name']
1953
1954    exclave_libs = GetExclaveLibs(kcdata['exclave_textlayout'], text_layout_id)
1955
1956    frames = []
1957    stack = ipc_entry.get('secure_ecstack_entry', [])
1958    for stack_item in stack:
1959        lr = GetLongForAddress(stack_item['lr'])
1960        # this is a buggy value of unknown origin
1961        # rdar://123508690 (Some Exclave Stackshot frames ends with invalid value 0xFFFF000000000000)
1962        if lr == 0xFFFF000000000000:
1963            continue
1964        frames.append(GetSymbolInfoForFrame(AllImageCatalog, exclave_libs, lr))
1965
1966    if frames:
1967        frame_info = "frames %d to %d" % (notes.offset, notes.offset + len(frames) - 1)
1968    else:
1969        frame_info = "no frames"
1970    notes.info("PID ${PID} TID ${TID} SCID %d ASID 0x%x has address space name '%s' (%s)" % (scid, asid, addr_space_name, frame_info))
1971    notes.addToOffset(len(frames))
1972    return frames
1973
1974
1975def GetExclavesFrames(AllImageCatalog, json, scid, notes):
1976    kcdata = json['kcdata_stackshot']
1977    threads_exclave = kcdata.get('threads_exclave')
1978    if not threads_exclave:
1979        notes.warn("PID ${PID} TID ${TID} no threads_exclave info found, skipping exclaves frames")
1980        return []
1981
1982    exclaves_content = threads_exclave.get('0')
1983    if not exclaves_content:
1984        notes.warn("PID ${PID} TID ${TID} threads_exclave data not found, skipping exclaves frames")
1985        return []
1986
1987    threads_info = exclaves_content.get('thread_exclave')
1988    if not threads_info:
1989        notes.warn("PID ${PID} TID ${TID} no thread_exclave info found, skipping exclaves frames")
1990        return []
1991
1992    scid_info = threads_info.get(str(scid))
1993    if not scid_info:
1994        notes.warn("PID ${PID} TID ${TID} no exclaves info available for SCID %d, skipping exclaves frames" % scid)
1995        return []
1996
1997    frames = []
1998
1999    ipc_stack = scid_info.get("exclave_ipcstackentry")
2000    if not ipc_stack:
2001        notes.info("\nPID ${PID} TID ${TID} SCID %d IPC chain is missing" % scid)
2002        return []
2003    notes.info("\nPID ${PID} TID ${TID} SCID %d has IPC chain with %d items:" % (scid, len(ipc_stack)))
2004    for i in reversed(range(len(ipc_stack))):
2005        ipc_entry = ipc_stack[str(i)]
2006        entry_frames = GetEASFrames(AllImageCatalog, exclaves_content, ipc_entry, notes, scid)
2007        frames.extend(entry_frames)
2008
2009    return frames
2010
2011
2012def InsertExclavesFrames(AllImageCatalog, json, thdata, notes, kernel_frames):
2013    thread_info = thdata.get('exclaves_thread_info')
2014    if not thread_info:
2015        # this is not exclave thread
2016        return
2017
2018    scid = thread_info["tei_scid"]
2019    offset = thread_info["tei_thread_offset"]
2020    notes.offset = offset
2021
2022    exclaves_frames = GetExclavesFrames(AllImageCatalog, json, scid, notes)
2023
2024    # insert exclaves frames to offset
2025    for i in range(len(exclaves_frames)):
2026        kernel_frames.insert(offset + i, exclaves_frames[i])
2027
2028class NotesBuilder:
2029
2030    notes = []
2031    pid = None
2032    tis = None
2033    offset = 0
2034
2035    def __init__(self, pid, tid):
2036        self.pid = pid
2037        self.tid = tid
2038        self.notes = []
2039        self.offset = 0 # offset of next IPC stack in kernel stack
2040
2041    # Replace ${PID} with a PID and ${TID} with TID and add newline
2042    def format(self, note):
2043        note = note.replace('${PID}', str(self.pid))
2044        note = note.replace('${TID}', str(self.tid))
2045        return note + '\n'
2046
2047    def warn(self, note):
2048        note = self.format(note)
2049        sys.stdout.write(note)
2050        self.notes.append(note)
2051
2052    def info(self, note):
2053        note = self.format(note)
2054        self.notes.append(note)
2055
2056    def isEmpty(self):
2057        return len(self.notes) == 0
2058
2059    def text(self):
2060        return ''.join(self.notes)
2061
2062    def addToOffset(self, frame_count):
2063        self.offset += frame_count
2064
2065def SaveStackshotReport(j, outfile_name, incomplete):
2066    import time
2067    ss = j.get('kcdata_stackshot')
2068    if not ss:
2069        print("No KCDATA_BUFFER_BEGIN_STACKSHOT object found. Skipping writing report.")
2070        return
2071
2072    timestamp = ss.get('usecs_since_epoch')
2073    try:
2074        timestamp = time.strftime("%Y-%m-%d %H:%M:%S +0000",time.gmtime(timestamp // 1000000 if timestamp else None))
2075    except ValueError as e:
2076        print("couldn't convert timestamp:", str(e))
2077        timestamp = None
2078
2079    os_version = ss.get('osversion', 'Unknown')
2080    timebase = ss.get('mach_timebase_info', {"denom": 1, "numer": 1})
2081
2082    sc_note = None
2083    extra_note = None
2084    dsc_common = None
2085    shared_cache_info = ss.get('shared_cache_dyld_load_info')
2086    if shared_cache_info:
2087        shared_cache_base_addr = shared_cache_info['imageSlidBaseAddress']
2088        # If we have a slidFirstMapping and it's >= base_address, use that.
2089        #
2090        # Otherwise we're processing a stackshot from before the slidFirstMapping
2091        # field was introduced and corrected.  On ARM the SlidBaseAddress is the
2092        # same, but on x86 it's off by 0x20000000.  We use 'X86_64' in the
2093        # kernel version string plus checking kern_page_size == 4k' as
2094        # proxy for x86_64, and only adjust SlidBaseAddress if the unslid
2095        # address is precisely the expected incorrect value.
2096        #
2097        is_intel = ('X86_64' in ss.get('osversion', "") and
2098           ss.get('kernel_page_size', 0) == 4096)
2099        slidFirstMapping = shared_cache_info.get(SC_SLID_FIRSTMAPPING_KEY, -1)
2100        if slidFirstMapping >= shared_cache_base_addr:
2101            shared_cache_base_addr = slidFirstMapping
2102            sc_note = "base-accurate"
2103
2104        elif is_intel:
2105            sc_slide = shared_cache_info['imageLoadAddress']
2106            if (shared_cache_base_addr - sc_slide) == 0x7fff00000000:
2107                shared_cache_base_addr += 0x20000000
2108                sc_note = "base-x86-adjusted"
2109                extra_note = "Shared cache base adjusted for x86. "
2110            else:
2111                sc_note = "base-x86-unknown"
2112
2113        dsc_common = [format_uuid(shared_cache_info['imageUUID']),
2114                shared_cache_base_addr, "S" ]
2115        print("Shared cache UUID found from the binary data is <%s> " % str(dsc_common[0]))
2116
2117    dsc_layout = ss.get('system_shared_cache_layout')
2118
2119    dsc_libs = []
2120    if dsc_layout:
2121        print("Found in memory system shared cache layout with {} images".format(len(dsc_layout)))
2122        slide = ss.get('shared_cache_dyld_load_info')['imageLoadAddress']
2123
2124        for image in dsc_layout:
2125            dsc_libs.append([format_uuid(image['imageUUID']), image['imageLoadAddress'] + slide, "C"])
2126
2127    AllImageCatalog = []
2128    obj = {}
2129    obj["kernel"] = os_version
2130    if timestamp is not None:
2131        obj["date"] = timestamp
2132    obj["reason"] = "kernel panic stackshot"
2133    obj["incident"] = "ABCDEFGH-1234-56IJ-789K-0LMNOPQRSTUV"
2134    obj["crashReporterKey"] = "12ab34cd45aabbccdd6712ab34cd45aabbccdd67"
2135    obj["bootArgs"] = ss.get('boot_args','')
2136    obj["frontmostPids"] = [0]
2137    obj["exception"] = "0xDEADF157"
2138    obj["processByPid"] = {}
2139    if sc_note is not None:
2140        obj["sharedCacheNote"] = sc_note
2141
2142    if incomplete:
2143        obj["reason"] = "!!!INCOMPLETE!!! kernel panic stackshot"
2144        obj["notes"] = "Generated by xnu kcdata.py from incomplete data!   Some information is missing! "
2145    else:
2146        obj["notes"] = "Generated by xnu kcdata.py. "
2147
2148    if extra_note is not None:
2149        obj["notes"] = obj["notes"] + extra_note
2150
2151    processByPid = obj["processByPid"]
2152    ssplist = ss.get('task_snapshots', {})
2153    ssplist.update(ss.get('transitioning_task_snapshots', {}))
2154    kern_load_info = []
2155    if "0" in ssplist:
2156        kc_uuid = ssplist["0"].get('kernelcache_load_info', None)
2157        if kc_uuid:
2158            kernelcache_uuid = [format_uuid(kc_uuid['imageUUID']), kc_uuid['imageLoadAddress'], "U" ]
2159            kern_load_info.append(kernelcache_uuid)
2160
2161        kl_infos = ssplist["0"].get("dyld_load_info", [])
2162        for dlinfo in kl_infos:
2163            kern_load_info.append([format_uuid(dlinfo['imageUUID']), dlinfo['imageLoadAddress'], "K"])
2164
2165        kl_infos_text_exec = ssplist["0"].get("dyld_load_info_text_exec", [])
2166        for dlinfo in kl_infos_text_exec:
2167            kern_load_info.append([format_uuid(dlinfo['imageUUID']), dlinfo['imageLoadAddress'], "T"])
2168
2169    for pid,piddata in sorted(ssplist.items()):
2170        processByPid[str(pid)] = {}
2171        tsnap = processByPid[str(pid)]
2172        pr_lib_dsc = dsc_common
2173
2174        # see if there's an alternate shared cache
2175        scd = piddata.get('shared_cache_dyld_load_info')
2176        if scd is not None:
2177            if 'imageSlidBaseAddress' not in scd:
2178                print("Specific task shared cache format does not include slid shared cache base address. Skipping writing report.")
2179                return
2180
2181            scd_uuid = format_uuid(scd['imageUUID'])
2182            scd_base_addr = scd['imageSlidBaseAddress']
2183            pr_lib_dsc = [scd_uuid, scd_base_addr, "S"]
2184
2185        pr_libs = []
2186        if len(dsc_libs) == 0 and pr_lib_dsc:
2187            pr_libs.append(pr_lib_dsc)
2188        _lib_type = "P"
2189        if int(pid) == 0:
2190            _lib_type = "K"
2191            pr_libs = []
2192        else:
2193            for dlinfo in piddata.get('dyld_load_info',[]):
2194                pr_libs.append([format_uuid(dlinfo['imageUUID']), dlinfo['imageLoadAddress'], _lib_type])
2195
2196        pr_libs.extend(kern_load_info)
2197        pr_libs.extend(dsc_libs)
2198
2199        if 'jit_address_range' in piddata:
2200            address_range = piddata.get('jit_address_range', {})
2201            tsnap['jitStartAddress'] = address_range['start_address']
2202            tsnap['jitEndAddress'] = address_range['end_address']
2203            pr_libs.append([format_uuid("00000000000000000000000000000000"), tsnap['jitStartAddress'] , "J"])
2204        pr_libs.sort(key=itemgetter(1))
2205        ttsnap = piddata.get('transitioning_task_snapshot', None)
2206        if ttsnap is not None:
2207            # Transitioning task snapshots have "tts_" prefixes; change them to
2208            # "ts_".
2209            ttsnap = { key[1:] : value for key,value in ttsnap.items() }
2210            # Add a note to let people know
2211            obj["notes"] = obj["notes"] + "PID {} is a transitioning (exiting) task. ".format(pid)
2212        tasksnap = piddata.get('task_snapshot', ttsnap)
2213        if tasksnap is None:
2214            continue
2215        tsnap["pid"] = tasksnap["ts_pid"]
2216        if 'ts_asid' in piddata:
2217            tsnap["asid"] = piddata["ts_asid"]
2218
2219        if 'ts_pagetable' in piddata:
2220            pagetables = []
2221            for tte in piddata["ts_pagetable"]:
2222                pagetables.append(tte)
2223            tsnap["pageTables"] = pagetables
2224
2225        # Some fields are missing from transitioning_task snapshots.
2226        if ttsnap is None:
2227            tsnap["residentMemoryBytes"] = tasksnap["ts_task_size"]
2228            tsnap["timesDidThrottle"] = tasksnap["ts_did_throttle"]
2229            tsnap["systemTimeTask"] = GetSecondsFromMATime(tasksnap["ts_system_time_in_terminated_th"], timebase)
2230            tsnap["pageIns"] = tasksnap["ts_pageins"]
2231            tsnap["pageFaults"] = tasksnap["ts_faults"]
2232            tsnap["userTimeTask"] = GetSecondsFromMATime(tasksnap["ts_user_time_in_terminated_thre"], timebase)
2233        tsnap["procname"] = tasksnap["ts_p_comm"]
2234        if ttsnap is None:
2235            tsnap["copyOnWriteFaults"] = tasksnap["ts_cow_faults"]
2236            tsnap["timesThrottled"] = tasksnap["ts_was_throttled"]
2237        tsnap["threadById"] = {}
2238        threadByID = tsnap["threadById"]
2239        thlist = piddata.get('thread_snapshots', {})
2240        for tid,thdata in sorted(thlist.items()):
2241            threadByID[str(tid)] = {}
2242            thsnap = threadByID[str(tid)]
2243            if "thread_snapshot" not in thdata:
2244                print("Found broken thread state for thread ID: %s." % tid)
2245                break
2246            threadsnap = thdata["thread_snapshot"]
2247            thsnap["userTime"] = GetSecondsFromMATime(threadsnap["ths_user_time"], timebase)
2248            thsnap["id"] = threadsnap["ths_thread_id"]
2249            thsnap["basePriority"] = threadsnap["ths_base_priority"]
2250            thsnap["systemTime"] = GetSecondsFromMATime(threadsnap["ths_sys_time"], timebase)
2251            thsnap["schedPriority"] = threadsnap["ths_sched_priority"]
2252            thsnap["state"] = GetStateDescription(threadsnap['ths_state'])
2253            thsnap["qosEffective"] = threadsnap["ths_eqos"]
2254            thsnap["qosRequested"] = threadsnap["ths_rqos"]
2255
2256            if "pth_name" in thdata:
2257                thsnap["name"] = thdata["pth_name"]
2258
2259            if threadsnap['ths_continuation']:
2260                thsnap["continuation"] = GetSymbolInfoForFrame(AllImageCatalog, pr_libs, threadsnap['ths_continuation'])
2261            if "kernel_stack_frames" in thdata:
2262                kuserframes = []
2263                for f in thdata["kernel_stack_frames"]:
2264                    kuserframes.append(GetSymbolInfoForFrame(AllImageCatalog, pr_libs, f['lr']))
2265                notesBuilder = NotesBuilder(tsnap['pid'], tid)
2266                InsertExclavesFrames(AllImageCatalog, j, thdata, notesBuilder, kuserframes)
2267                if not notesBuilder.isEmpty():
2268                    obj['notes'] += notesBuilder.text()
2269                thsnap["kernelFrames"] = kuserframes
2270
2271            if "user_stack_frames" in thdata:
2272                uframes = []
2273                for f in thdata["user_stack_frames"]:
2274                    uframes.append(GetSymbolInfoForFrame(AllImageCatalog, pr_libs, f['lr']))
2275                thsnap["userFrames"] = uframes
2276
2277            if "user_stacktop" in thdata:
2278                (address,) = struct.unpack("<Q", struct.pack("B"*8, *thdata["user_stacktop"]["stack_contents"]))
2279                thsnap["userStacktop"] = GetSymbolInfoForFrame(AllImageCatalog, pr_libs, address)
2280
2281            if threadsnap['ths_wait_event']:
2282                thsnap["waitEvent"] = GetSymbolInfoForFrame(AllImageCatalog, pr_libs, threadsnap['ths_wait_event'])
2283
2284        if 'thread_waitinfo' in piddata and 'thread_turnstileinfo' in piddata:
2285            tsnap['waitInfo'] = formatWaitInfoWithTurnstiles(piddata['thread_waitinfo'], piddata['thread_turnstileinfo'], piddata.get('portlabels', None))
2286        elif 'thread_waitinfo' in piddata:
2287            portlabels = ss.get('portlabels', None)
2288            tsnap['waitInfo'] = [formatWaitInfo(x, False, portlabels) for x in piddata['thread_waitinfo']]
2289        if 'stackshot_task_codesigning_info' in piddata:
2290            csinfo = piddata.get('stackshot_task_codesigning_info', {})
2291            tsnap['csFlags'] = csinfo['csflags']
2292            tsnap['csTrustLevel'] = csinfo['cs_trust_level']
2293        if 'suspension_info' in piddata:
2294            suspinfo = piddata.get('suspension_info', {})
2295            tsnap['suspension_count'] = suspinfo['tss_count']
2296            tsnap['suspension_duration_secs'] = GetSecondsFromMATime(suspinfo['tss_duration'], timebase)
2297            tsnap['suspension_last_start'] = GetSecondsFromMATime(suspinfo['tss_last_start'], timebase)
2298            tsnap['suspension_last_end'] = GetSecondsFromMATime(suspinfo['tss_last_end'], timebase)
2299
2300            suspsources = piddata.get('suspension_source', [])
2301            suspension_sources = []
2302            for source in filter(lambda x: x['tss_time'] != 0, suspsources):
2303                suspension_sources.append({
2304                    'suspension_time': GetSecondsFromMATime(source['tss_time'], timebase),
2305                    'suspension_tid': source['tss_tid'],
2306                    'suspension_pid': source['tss_pid'],
2307                    'suspension_procname': source['tss_procname'],
2308                })
2309
2310            tsnap['suspension_sources'] = suspension_sources
2311            # check if process is currently suspended
2312            if tsnap['suspension_last_start'] > tsnap['suspension_last_end']:
2313                obj['notes'] += "\nPID {} ({}) is currently suspended (count: {}, total duration: {:.4f}s, last_start: {:.4f}, last_end: {:.4f}) - recent suspensions are:\n".format(pid, tsnap['procname'], tsnap['suspension_count'], tsnap['suspension_duration_secs'], tsnap['suspension_last_start'], tsnap['suspension_last_end'])
2314                for source in suspension_sources:
2315                    obj['notes'] += "From PID {} TID {} ({}) - at {}\n".format(source['suspension_pid'], source['suspension_tid'], source['suspension_procname'], source['suspension_time'])
2316
2317    obj['binaryImages'] = AllImageCatalog
2318    if outfile_name == '-':
2319        fh = sys.stdout
2320    else:
2321        fh = open(outfile_name, "w")
2322
2323    header = {}
2324    header['bug_type'] = 288
2325    if timestamp is not None:
2326        header['timestamp'] = timestamp
2327    header['os_version'] = os_version
2328    fh.write(json.dumps(header, sort_keys=True))
2329    fh.write("\n")
2330
2331    fh.write(json.dumps(obj, sort_keys=True, indent=2, separators=(',', ': ')))
2332    fh.close()
2333
2334
2335@contextlib.contextmanager
2336def data_from_stream(stream):
2337    try:
2338        fmap = mmap.mmap(stream.fileno(), 0, mmap.MAP_SHARED, mmap.PROT_READ)
2339    except Exception:
2340        yield stream.buffer.read()
2341    else:
2342        try:
2343            yield fmap
2344        finally:
2345            fmap.close()
2346
2347def iterate_kcdatas(kcdata_file):
2348    with data_from_stream(kcdata_file) as data:
2349        iterator = kcdata_item_iterator(data)
2350        kcdata_buffer = KCObject.FromKCItem(next(iterator))
2351
2352        if isinstance(kcdata_buffer, KCCompressedBufferObject):
2353            kcdata_buffer.ReadItems(iterator)
2354            decompressed = kcdata_buffer.Decompress(data)
2355            iterator = kcdata_item_iterator(decompressed)
2356            kcdata_buffer = KCObject.FromKCItem(next(iterator))
2357
2358        if not isinstance(kcdata_buffer, KCBufferObject):
2359            # ktrace stackshot chunk
2360            iterator = kcdata_item_iterator(data[16:])
2361            kcdata_buffer = KCObject.FromKCItem(next(iterator))
2362
2363        if not isinstance(kcdata_buffer, KCBufferObject):
2364            try:
2365                decoded = base64.b64decode(data)
2366            except Exception:
2367                pass
2368            else:
2369                iterator = kcdata_item_iterator(decoded)
2370                kcdata_buffer = KCObject.FromKCItem(next(iterator))
2371        if not isinstance(kcdata_buffer, KCBufferObject):
2372            import gzip
2373            from io import BytesIO
2374            try:
2375                decompressed = gzip.GzipFile(fileobj=BytesIO(data[:])).read()
2376            except Exception:
2377                pass
2378            else:
2379                iterator = kcdata_item_iterator(decompressed)
2380                kcdata_buffer = KCObject.FromKCItem(next(iterator))
2381
2382        if not isinstance(kcdata_buffer, KCBufferObject):
2383            raise Exception("unknown file type")
2384
2385
2386        kcdata_buffer.ReadItems(iterator)
2387        yield kcdata_buffer
2388
2389        for magic in iterator:
2390            kcdata_buffer = KCObject.FromKCItem(magic)
2391            if kcdata_buffer.i_type == 0:
2392                continue
2393            if not isinstance(kcdata_buffer, KCBufferObject):
2394                raise Exception("unknown file type")
2395            kcdata_buffer.ReadItems(iterator)
2396            yield kcdata_buffer
2397
2398#
2399# Values for various flag fields.  Each entry's key is the key seen in the
2400# processed kcdata, the value is an array of bits, from low (0x1) to high, with
2401# either a string flag name or None for unused holes.
2402#
2403# Only put flags in here which are stable - this is run against stackshots
2404# of all different versions.  For anything unstable, we'll need a decoder ring
2405# added to the stackshot.
2406#
2407PRETTIFY_FLAGS = {
2408    'jcs_flags': [
2409       'kCoalitionTermRequested',
2410       'kCoalitionTerminated',
2411       'kCoalitionReaped',
2412       'kCoalitionPrivileged',
2413    ],
2414    'sharedCacheFlags': [
2415       'kSharedCacheSystemPrimary',
2416       'kSharedCacheDriverkit'
2417       'kSharedCacheAOT',
2418    ],
2419    'stackshot_in_flags': [ # STACKSHOT_*, also stackshot_out_flags
2420        'get_dq',
2421        'save_loadinfo',
2422        'get_global_mem_stats',
2423        'save_kext_loadinfo',
2424        None,
2425        None,
2426        None,
2427        None,
2428        'active_kernel_threads_only',
2429        'get_boot_profile',
2430        'do_compress',
2431        None,
2432        None,
2433        'save_imp_donation_pids',
2434        'save_in_kernel_buffer',
2435        'retrieve_existing_buffer',
2436        'kcdata_format',
2437        'enable_bt_faulting',
2438        'collect_delta_snapshot',
2439        'collect_sharedcache_layout',
2440        'trylock',
2441        'enable_uuid_faulting',
2442        'from_panic',
2443        'no_io_stats',
2444        'thread_waitinfo',
2445        'thread_group',
2446        'save_jetsam_coalitions',
2447        'instrs_cycles',
2448        'asid',
2449        'page_tables',
2450        'disable_latency_info',
2451        'save_dyld_compactinfo',
2452        'include_driver_threads_in_kernel',
2453        'exclaves',
2454    ],
2455    'system_state_flags': [
2456        'kUser64_p',
2457        'kKern64_p',
2458    ],
2459    'tgs_flags': [
2460        'kThreadGroupEfficient',
2461        'kThreadGroupApplication',
2462        'kThreadGroupCritical',
2463        'kThreadGroupBestEffort',
2464        None,
2465        None,
2466        None,
2467        None,
2468        'kThreadGroupUIApplication',
2469        'kThreadGroupManaged',
2470        'kThreadGroupStrictTimers',
2471    ],
2472    'ths_ss_flags': [
2473        'kUser64_p',
2474        'kKern64_p',
2475        'kHasDispatchSerial',
2476        'kStacksPCOnly',
2477        'kThreadDarwinBG',
2478        'kThreadIOPassive',
2479        'kThreadSuspended',
2480        'kThreadTruncatedBT',
2481        'kGlobalForcedIdle',
2482        'kThreadFaultedBT',
2483        'kThreadTriedFaultBT',
2484        'kThreadOnCore',
2485        'kThreadIdleWorker',
2486        'kThreadMain',
2487        'kThreadTruncKernBT',
2488        'kThreadTruncUserBT',
2489        'kThreadTruncUserAsyncBT',
2490        'kThreadExclaveRPCActive',
2491        'kThreadExclaveUpcallActive',
2492        'kThreadExclaveSchedulerRequest',
2493    ],
2494    'ths_state': [
2495        'TH_WAIT',
2496        'TH_SUSP',
2497        'TH_RUN',
2498        'TH_UNINT',
2499        'TH_TERMINATE',
2500        'TH_TERMINATE2',
2501        'TH_WAIT_REPORT',
2502        'TH_IDLE',
2503    ],
2504    'ts_ss_flags': [
2505        'kUser64_p',
2506        'kKern64_p',
2507        'kTaskRsrcFlagged',
2508        'kTerminatedSnapshot',
2509        'kPidSuspended',
2510        'kFrozen',
2511        'kTaskDarwinBG',
2512        'kTaskExtDarwinBG',
2513        'kTaskVisVisible',
2514        'kTaskVisNonvisible',
2515        'kTaskIsForeground',
2516        'kTaskIsBoosted',
2517        'kTaskIsSuppressed',
2518        'kTaskIsTimerThrottled',
2519        'kTaskIsImpDonor',
2520        'kTaskIsLiveImpDonor',
2521        'kTaskIsDirty',
2522        'kTaskWqExceededConstrainedThreadLimit',
2523        'kTaskWqExceededTotalThreadLimit',
2524        'kTaskWqFlagsAvailable',
2525        'kTaskUUIDInfoFaultedIn',
2526        'kTaskUUIDInfoMissing',
2527        'kTaskUUIDInfoTriedFault',
2528        'kTaskSharedRegionInfoUnavailable',
2529        'kTaskTALEngaged',
2530        None,
2531        'kTaskIsDirtyTracked',
2532        'kTaskAllowIdleExit',
2533        'kTaskIsTranslated',
2534        'kTaskSharedRegionNone',
2535        'kTaskSharedRegionSystem',
2536        'kTaskSharedRegionOther',
2537        'kTaskDyldCompactInfoNone',
2538        'kTaskDyldCompactInfoTooBig',
2539        'kTaskDyldCompactInfoFaultedIn',
2540        'kTaskDyldCompactInfoMissing',
2541        'kTaskDyldCompactInfoTriedFault',
2542        'kTaskWqExceededCooperativeThreadLimit',
2543        'kTaskWqExceededActiveConstrainedThreadLimit',
2544    ],
2545    'turnstile_flags': [
2546        'turnstile_status_unknown',
2547        'turnstile_status_locked_waitq',
2548        'turnstile_status_workqueue',
2549        'turnstile_status_thread',
2550        'turnstile_status_blocked_on_task',
2551        'turnstile_status_held_iplock',
2552    ],
2553    'portlabel_flags': [
2554        'label_read_failed',
2555        'service_throttled',
2556    ],
2557    'esc_flags': [
2558        'kExclaveScresultHaveIPCStack',
2559    ],
2560    'eise_flags': [
2561        'kExclaveIpcStackEntryHaveInvocationID',
2562        'kExclaveIpcStackEntryHaveStack',
2563    ],
2564    'eas_flags': [
2565        'kExclaveAddressSpaceHaveSlide',
2566    ],
2567    'etl_flags': [
2568        'kExclaveTextLayoutLoadAddressesSynthetic',
2569        'kExclaveTextLayoutLoadAddressesUnslid',
2570        'kExclaveTextLayoutHasSharedCache',
2571    ],
2572}
2573PRETTIFY_FLAGS['stackshot_out_flags'] = PRETTIFY_FLAGS['stackshot_in_flags']
2574PRETTIFY_FLAGS['tts_ss_flags'] = PRETTIFY_FLAGS['ts_ss_flags']
2575
2576# Fields which should never be hexified
2577PRETTIFY_DONTHEX = {
2578    'stackshot_in_pid': True,
2579    'tts_pid': True,
2580    'ts_pid': True,
2581    'donating_pids': True,
2582    'ppid': True,
2583}
2584
2585# Only hex() the value if it is multiple digits
2586def prettify_hex(v):
2587    if v < -9 or v > 9:
2588        return hex(v)
2589    return str(v)
2590
2591def prettify_flags(v, flags):
2592    output=""
2593    seen = 0
2594    if v == 0:
2595        return "0"
2596    for (s, n) in zip(range(len(flags)),flags):
2597        if n is None:
2598            continue
2599        if (v & (2 ** s)):
2600            output += "|" + n
2601            seen |= 2 ** s
2602    if output == "":
2603        return prettify_hex(v)
2604    rest = (v & ~seen)
2605    if (rest != 0):
2606        output += "|" + prettify_hex(rest)
2607    return prettify_hex(v) + " (" + output[1:] + ")"
2608
2609def prettify_core(data, mosthex, key, portlabels):
2610    if key == 'stack_contents':
2611        (address,) = struct.unpack("<Q", struct.pack("B"*8, *data))
2612        return '0x%X' % address
2613
2614    elif isinstance(data, list):
2615        if 'uuid' in key.lower() and len(data) == 16:
2616            return '%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X' % tuple(data)
2617
2618        return [prettify_core(x, mosthex, key, portlabels) for x in data]
2619
2620    elif key == 'thread_waitinfo':
2621        return formatWaitInfo(data, mosthex, portlabels)
2622
2623    elif isinstance(data, dict):
2624        if 'portlabels' in data:
2625            portlabels = data['portlabels']
2626        newdata = dict()
2627        for key, value in data.items():
2628            if mosthex and key != 'task_snapshots' and len(key) > 0 and key.isnumeric():
2629                key = prettify_hex(int(key))
2630            newdata[key] = prettify_core(value, mosthex, key, portlabels)
2631        return newdata
2632
2633    elif 'address' in key.lower() and isinstance(data, (int, long)):
2634        return '0x%X' % data
2635    elif key == 'lr' or key == SC_SLID_FIRSTMAPPING_KEY:
2636        return '0x%X' % data
2637    elif key in PRETTIFY_FLAGS and isinstance(data, (int, long)):
2638        return prettify_flags(data, PRETTIFY_FLAGS[key])
2639    elif key.endswith('_flags') and isinstance(data, (int, long)):
2640        return prettify_hex(data)
2641
2642    elif mosthex and not PRETTIFY_DONTHEX.get(key, False):
2643        if isinstance(data, (int, long)):
2644            return prettify_hex(data)
2645        elif isinstance(data, str) and len(data) > 0 and data.isnumeric():
2646            return prettify_hex(int(data))
2647        return data
2648
2649    else:
2650        return data
2651
2652def prettify(data, mosthex):
2653    return prettify_core(data, mosthex, "", None)
2654
2655# N.B.: This is called directly from `xnu.py` for `panicdata -S XXX.ips`'s implementation.
2656def decode_kcdata_file(kcdata_file, stackshot_file, multiple=False, prettyhex=False, pretty=False, output_as_plist=False):
2657    for i,kcdata_buffer in enumerate(iterate_kcdatas(kcdata_file)):
2658        if i > 0 and not multiple:
2659            break
2660
2661        str_data = "{" + kcdata_buffer.GetJsonRepr() + "}"
2662        str_data = str_data.replace("\t", "    ")
2663
2664        try:
2665            json_obj = json.loads(str_data)
2666        except Exception:
2667            print("JSON reparsing failed!  Printing string data!\n", file=sys.stderr)
2668            import textwrap
2669            print(textwrap.fill(str_data, 100))
2670            raise
2671
2672        if prettyhex:
2673            json_obj = prettify(json_obj, True)
2674        elif pretty:
2675            json_obj = prettify(json_obj, False)
2676
2677        if stackshot_file:
2678            SaveStackshotReport(json_obj, stackshot_file, G.data_was_incomplete)
2679        elif output_as_plist:
2680            import Foundation
2681            plist = Foundation.NSPropertyListSerialization.dataWithPropertyList_format_options_error_(
2682                json_obj, Foundation.NSPropertyListXMLFormat_v1_0, 0, None)[0].bytes().tobytes()
2683            #sigh.  on some pythons long integers are getting output with L's in the plist.
2684            plist = re.sub(r'^(\s*<integer>\d+)L(</integer>\s*)$', r"\1\2", BytesToString(plist), flags=re.MULTILINE)
2685            print(plist,)
2686        else:
2687            print(json.dumps(json_obj, sort_keys=True, indent=4, separators=(',', ': ')))
2688
2689if __name__ == '__main__':
2690    parser = argparse.ArgumentParser(description="Decode a kcdata binary file.")
2691    parser.add_argument("-l", "--listtypes", action="store_true", required=False, default=False,
2692                        help="List all known types",
2693                        dest="list_known_types")
2694
2695    parser.add_argument("-s", "--stackshot", required=False, default=False,
2696                        help="Generate a stackshot report file",
2697                        dest="stackshot_file")
2698
2699    parser.add_argument("--multiple", help="look for multiple stackshots in a single file", action='store_true')
2700
2701    parser.add_argument("-p", "--plist", required=False, default=False,
2702                        help="output as plist", action="store_true")
2703
2704    parser.add_argument("-S", "--sdk", required=False, default="", help="sdk property passed to xcrun command to find the required tools. Default is empty string.", dest="sdk")
2705    parser.add_argument("-P", "--pretty", default=False, action='store_true', help="make the output a little more human readable")
2706    parser.add_argument("-X", "--prettyhex", default=False, action='store_true', help="make the output a little more human readable, and print most things as hex")
2707    parser.add_argument("--incomplete", action='store_true', help="accept incomplete data")
2708    parser.add_argument("kcdata_file", type=argparse.FileType('r'), help="Path to a kcdata binary file.")
2709
2710    class VerboseAction(argparse.Action):
2711        def __call__(self, parser, namespace, values, option_string=None):
2712            logging.basicConfig(level=logging.INFO, stream=sys.stderr, format='%(message)s')
2713    parser.add_argument('-v', "--verbose", action=VerboseAction, nargs=0)
2714
2715    args = parser.parse_args()
2716
2717    if args.multiple and args.stackshot_file:
2718        raise NotImplementedError
2719
2720    if args.pretty and args.stackshot_file:
2721        raise NotImplementedError
2722
2723    if args.list_known_types:
2724        for (n, t) in KNOWN_TYPES_COLLECTION.items():
2725            print("%d : %s " % (n, str(t)))
2726        sys.exit(1)
2727
2728    if args.incomplete or args.stackshot_file:
2729        G.accept_incomplete_data = True
2730
2731    decode_kcdata_file(args.kcdata_file, args.stackshot_file, args.multiple, args.prettyhex, args.pretty, args.plist)
2732