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