]>
Commit | Line | Data |
---|---|---|
39037602 A |
1 | /* |
2 | * Copyright (c) 2015 Apple Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
14 | * | |
15 | * Please obtain a copy of the License at | |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
25 | * | |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
27 | */ | |
28 | ||
29 | ||
30 | /* | |
31 | * | |
32 | * THE KCDATA MANIFESTO | |
33 | * | |
34 | * Kcdata is a self-describing data serialization format. It is meant to get | |
35 | * nested data structures out of xnu with minimum fuss, but also for that data | |
36 | * to be easy to parse. It is also meant to allow us to add new fields and | |
37 | * evolve the data format without breaking old parsers. | |
38 | * | |
39 | * Kcdata is a permanent data format suitable for long-term storage including | |
40 | * in files. It is very important that we continue to be able to parse old | |
41 | * versions of kcdata-based formats. To this end, there are several | |
42 | * invariants you MUST MAINTAIN if you alter this file. | |
43 | * | |
44 | * * None of the magic numbers should ever be a byteswap of themselves or | |
45 | * of any of the other magic numbers. | |
46 | * | |
47 | * * Never remove any type. | |
48 | * | |
49 | * * All kcdata structs must be packed, and must exclusively use fixed-size | |
50 | * types. | |
51 | * | |
52 | * * Never change the definition of any type, except to add new fields to | |
53 | * the end. | |
54 | * | |
55 | * * If you do add new fields to the end of a type, do not actually change | |
56 | * the definition of the old structure. Instead, define a new structure | |
57 | * with the new fields. See thread_snapshot_v3 as an example. This | |
58 | * provides source compatibility for old readers, and also documents where | |
59 | * the potential size cutoffs are. | |
60 | * | |
61 | * * If you change libkdd, or kcdata.py run the unit tests under libkdd. | |
62 | * | |
63 | * * If you add a type or extend an existing one, add a sample test to | |
64 | * libkdd/tests so future changes to libkdd will always parse your struct | |
65 | * correctly. | |
66 | * | |
67 | * For example to add a field to this: | |
68 | * | |
69 | * struct foobar { | |
70 | * uint32_t baz; | |
71 | * uint32_t quux; | |
72 | * } __attribute__ ((packed)); | |
73 | * | |
74 | * Make it look like this: | |
75 | * | |
76 | * struct foobar { | |
77 | * uint32_t baz; | |
78 | * uint32_t quux; | |
79 | * ///////// end version 1 of foobar. sizeof(struct foobar) was 8 //////// | |
80 | * uint32_t frozzle; | |
81 | * } __attribute__ ((packed)); | |
82 | * | |
83 | * If you are parsing kcdata formats, you MUST | |
84 | * | |
85 | * * Check the length field of each struct, including array elements. If the | |
86 | * struct is longer than you expect, you must ignore the extra data. | |
87 | * | |
88 | * * Ignore any data types you do not understand. | |
89 | * | |
90 | * Additionally, we want to be as forward compatible as we can. Meaning old | |
91 | * tools should still be able to use new data whenever possible. To this end, | |
92 | * you should: | |
93 | * | |
94 | * * Try not to add new versions of types that supplant old ones. Instead | |
95 | * extend the length of existing types or add supplemental types. | |
96 | * | |
97 | * * Try not to remove information from existing kcdata formats, unless | |
98 | * removal was explicitly asked for. For example it is fine to add a | |
99 | * stackshot flag to remove unwanted information, but you should not | |
100 | * remove it from the default stackshot if the new flag is absent. | |
101 | * | |
102 | * * (TBD) If you do break old readers by removing information or | |
103 | * supplanting old structs, then increase the major version number. | |
104 | * | |
105 | * | |
106 | * | |
107 | * The following is a description of the kcdata format. | |
108 | * | |
109 | * | |
110 | * The format for data is setup in a generic format as follows | |
111 | * | |
112 | * Layout of data structure: | |
113 | * | |
114 | * | 8 - bytes | | |
115 | * | type = MAGIC | LENGTH | | |
116 | * | 0 | | |
117 | * | type | size | | |
118 | * | flags | | |
119 | * | data | | |
120 | * |___________data____________| | |
121 | * | type | size | | |
122 | * | flags | | |
123 | * |___________data____________| | |
124 | * | type = END | size=0 | | |
125 | * | 0 | | |
126 | * | |
127 | * | |
128 | * The type field describes what kind of data is passed. For example type = TASK_CRASHINFO_UUID means the following data is a uuid. | |
129 | * These types need to be defined in task_corpses.h for easy consumption by userspace inspection tools. | |
130 | * | |
131 | * Some range of types is reserved for special types like ints, longs etc. A cool new functionality made possible with this | |
132 | * extensible data format is that kernel can decide to put more information as required without requiring user space tools to | |
133 | * re-compile to be compatible. The case of rusage struct versions could be introduced without breaking existing tools. | |
134 | * | |
135 | * Feature description: Generic data with description | |
136 | * ------------------- | |
137 | * Further more generic data with description is very much possible now. For example | |
138 | * | |
139 | * - kcdata_add_uint64_with_description(cdatainfo, 0x700, "NUM MACH PORTS"); | |
140 | * - and more functions that allow adding description. | |
141 | * The userspace tools can then look at the description and print the data even if they are not compiled with knowledge of the field apriori. | |
142 | * | |
143 | * Example data: | |
144 | * 0000 57 f1 ad de 00 00 00 00 00 00 00 00 00 00 00 00 W............... | |
145 | * 0010 01 00 00 00 00 00 00 00 30 00 00 00 00 00 00 00 ........0....... | |
146 | * 0020 50 49 44 00 00 00 00 00 00 00 00 00 00 00 00 00 PID............. | |
147 | * 0030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |
148 | * 0040 9c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |
149 | * 0050 01 00 00 00 00 00 00 00 30 00 00 00 00 00 00 00 ........0....... | |
150 | * 0060 50 41 52 45 4e 54 20 50 49 44 00 00 00 00 00 00 PARENT PID...... | |
151 | * 0070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |
152 | * 0080 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |
153 | * 0090 ed 58 91 f1 | |
154 | * | |
155 | * Feature description: Container markers for compound data | |
156 | * ------------------ | |
157 | * If a given kernel data type is complex and requires adding multiple optional fields inside a container | |
158 | * object for a consumer to understand arbitrary data, we package it using container markers. | |
159 | * | |
160 | * For example, the stackshot code gathers information and describes the state of a given task with respect | |
161 | * to many subsystems. It includes data such as io stats, vm counters, process names/flags and syscall counts. | |
162 | * | |
163 | * kcdata_add_container_marker(kcdata_p, KCDATA_TYPE_CONTAINER_BEGIN, STACKSHOT_KCCONTAINER_TASK, task_uniqueid); | |
164 | * // add multiple data, or add_<type>_with_description()s here | |
165 | * | |
166 | * kcdata_add_container_marker(kcdata_p, KCDATA_TYPE_CONTAINER_END, STACKSHOT_KCCONTAINER_TASK, task_uniqueid); | |
167 | * | |
168 | * Feature description: Custom Data formats on demand | |
169 | * -------------------- | |
170 | * With the self describing nature of format, the kernel provider can describe a data type (uniquely identified by a number) and use | |
171 | * it in the buffer for sending data. The consumer can parse the type information and have knowledge of describing incoming data. | |
172 | * Following is an example of how we can describe a kernel specific struct sample_disk_io_stats in buffer. | |
173 | * | |
174 | * struct sample_disk_io_stats { | |
175 | * uint64_t disk_reads_count; | |
176 | * uint64_t disk_reads_size; | |
177 | * uint64_t io_priority_count[4]; | |
178 | * uint64_t io_priority_size; | |
179 | * } __attribute__ ((packed)); | |
180 | * | |
181 | * | |
182 | * struct kcdata_subtype_descriptor disk_io_stats_def[] = { | |
183 | * {KCS_SUBTYPE_FLAGS_NONE, KC_ST_UINT64, 0 * sizeof(uint64_t), sizeof(uint64_t), "disk_reads_count"}, | |
184 | * {KCS_SUBTYPE_FLAGS_NONE, KC_ST_UINT64, 1 * sizeof(uint64_t), sizeof(uint64_t), "disk_reads_size"}, | |
185 | * {KCS_SUBTYPE_FLAGS_ARRAY, KC_ST_UINT64, 2 * sizeof(uint64_t), KCS_SUBTYPE_PACK_SIZE(4, sizeof(uint64_t)), "io_priority_count"}, | |
186 | * {KCS_SUBTYPE_FLAGS_ARRAY, KC_ST_UINT64, (2 + 4) * sizeof(uint64_t), sizeof(uint64_t), "io_priority_size"}, | |
187 | * }; | |
188 | * | |
189 | * Now you can add this custom type definition into the buffer as | |
190 | * kcdata_add_type_definition(kcdata_p, KCTYPE_SAMPLE_DISK_IO_STATS, "sample_disk_io_stats", | |
191 | * &disk_io_stats_def[0], sizeof(disk_io_stats_def)/sizeof(struct kcdata_subtype_descriptor)); | |
192 | * | |
193 | */ | |
194 | ||
195 | ||
196 | #ifndef _KCDATA_H_ | |
197 | #define _KCDATA_H_ | |
198 | ||
199 | #include <stdint.h> | |
200 | #include <string.h> | |
201 | #include <uuid/uuid.h> | |
202 | ||
203 | #define KCDATA_DESC_MAXLEN 32 /* including NULL byte at end */ | |
204 | ||
205 | #define KCDATA_FLAGS_STRUCT_PADDING_MASK 0xf | |
206 | #define KCDATA_FLAGS_STRUCT_HAS_PADDING 0x80 | |
207 | ||
208 | /* | |
209 | * kcdata aligns elements to 16 byte boundaries. | |
210 | */ | |
211 | #define KCDATA_ALIGNMENT_SIZE 0x10 | |
212 | ||
213 | struct kcdata_item { | |
214 | uint32_t type; | |
215 | uint32_t size; /* len(data) */ | |
216 | /* flags. | |
217 | * | |
218 | * For structures: | |
219 | * padding = flags & 0xf | |
220 | * has_padding = (flags & 0x80) >> 7 | |
221 | * | |
222 | * has_padding is needed to disambiguate cases such as | |
223 | * thread_snapshot_v2 and thread_snapshot_v3. Their | |
224 | * respective sizes are 0x68 and 0x70, and thread_snapshot_v2 | |
225 | * was emmitted by old kernels *before* we started recording | |
226 | * padding. Since legacy thread_snapsht_v2 and modern | |
227 | * thread_snapshot_v3 will both record 0 for the padding | |
228 | * flags, we need some other bit which will be nonzero in the | |
229 | * flags to disambiguate. | |
230 | * | |
231 | * This is why we hardcode a special case for | |
232 | * STACKSHOT_KCTYPE_THREAD_SNAPSHOT into the iterator | |
233 | * functions below. There is only a finite number of such | |
234 | * hardcodings which will ever be needed. They can occur | |
235 | * when: | |
236 | * | |
237 | * * We have a legacy structure that predates padding flags | |
238 | * | |
239 | * * which we want to extend without changing the kcdata type | |
240 | * | |
241 | * * by only so many bytes as would fit in the space that | |
242 | * was previously unused padding. | |
243 | * | |
244 | * For containers: | |
245 | * container_id = flags | |
246 | * | |
247 | * For arrays: | |
248 | * element_count = flags & UINT32_MAX | |
249 | * element_type = (flags >> 32) & UINT32_MAX | |
250 | */ | |
251 | uint64_t flags; | |
252 | char data[]; /* must be at the end */ | |
253 | }; | |
254 | ||
255 | typedef struct kcdata_item * kcdata_item_t; | |
256 | ||
257 | enum KCDATA_SUBTYPE_TYPES { KC_ST_CHAR = 1, KC_ST_INT8, KC_ST_UINT8, KC_ST_INT16, KC_ST_UINT16, KC_ST_INT32, KC_ST_UINT32, KC_ST_INT64, KC_ST_UINT64 }; | |
258 | typedef enum KCDATA_SUBTYPE_TYPES kctype_subtype_t; | |
259 | ||
260 | /* | |
261 | * A subtype description structure that defines | |
262 | * how a compound data is laid out in memory. This | |
263 | * provides on the fly definition of types and consumption | |
264 | * by the parser. | |
265 | */ | |
266 | struct kcdata_subtype_descriptor { | |
267 | uint8_t kcs_flags; | |
268 | #define KCS_SUBTYPE_FLAGS_NONE 0x0 | |
269 | #define KCS_SUBTYPE_FLAGS_ARRAY 0x1 | |
270 | /* Force struct type even if only one element. | |
271 | * | |
272 | * Normally a kcdata_type_definition is treated as a structure if it has | |
273 | * more than one subtype descriptor. Otherwise it is treated as a simple | |
274 | * type. For example libkdd will represent a simple integer 42 as simply | |
275 | * 42, but it will represent a structure containing an integer 42 as | |
276 | * {"field_name": 42}.. | |
277 | * | |
278 | * If a kcdata_type_definition has only single subtype, then it will be | |
279 | * treated as a structure iff KCS_SUBTYPE_FLAGS_STRUCT is set. If it has | |
280 | * multiple subtypes, it will always be treated as a structure. | |
281 | * | |
282 | * KCS_SUBTYPE_FLAGS_MERGE has the opposite effect. If this flag is used then | |
283 | * even if there are multiple elements, they will all be treated as individual | |
284 | * properties of the parent dictionary. | |
285 | */ | |
286 | #define KCS_SUBTYPE_FLAGS_STRUCT 0x2 /* force struct type even if only one element */ | |
287 | #define KCS_SUBTYPE_FLAGS_MERGE 0x4 /* treat as multiple elements of parents instead of struct */ | |
288 | uint8_t kcs_elem_type; /* restricted to kctype_subtype_t */ | |
289 | uint16_t kcs_elem_offset; /* offset in struct where data is found */ | |
290 | uint32_t kcs_elem_size; /* size of element (or) packed state for array type */ | |
291 | char kcs_name[KCDATA_DESC_MAXLEN]; /* max 31 bytes for name of field */ | |
292 | }; | |
293 | ||
294 | typedef struct kcdata_subtype_descriptor * kcdata_subtype_descriptor_t; | |
295 | ||
296 | /* | |
297 | * In case of array of basic c types in kctype_subtype_t, | |
298 | * size is packed in lower 16 bits and | |
299 | * count is packed in upper 16 bits of kcs_elem_size field. | |
300 | */ | |
301 | #define KCS_SUBTYPE_PACK_SIZE(e_count, e_size) (((e_count)&0xffffu) << 16 | ((e_size)&0xffffu)) | |
302 | ||
303 | static inline uint32_t | |
304 | kcs_get_elem_size(kcdata_subtype_descriptor_t d) | |
305 | { | |
306 | if (d->kcs_flags & KCS_SUBTYPE_FLAGS_ARRAY) { | |
307 | /* size is composed as ((count &0xffff)<<16 | (elem_size & 0xffff)) */ | |
0a7de745 | 308 | return (uint32_t)((d->kcs_elem_size & 0xffff) * ((d->kcs_elem_size & 0xffff0000) >> 16)); |
39037602 A |
309 | } |
310 | return d->kcs_elem_size; | |
311 | } | |
312 | ||
313 | static inline uint32_t | |
314 | kcs_get_elem_count(kcdata_subtype_descriptor_t d) | |
315 | { | |
0a7de745 | 316 | if (d->kcs_flags & KCS_SUBTYPE_FLAGS_ARRAY) { |
39037602 | 317 | return (d->kcs_elem_size >> 16) & 0xffff; |
0a7de745 | 318 | } |
39037602 A |
319 | return 1; |
320 | } | |
321 | ||
322 | static inline int | |
323 | kcs_set_elem_size(kcdata_subtype_descriptor_t d, uint32_t size, uint32_t count) | |
324 | { | |
325 | if (count > 1) { | |
326 | /* means we are setting up an array */ | |
0a7de745 | 327 | if (size > 0xffff || count > 0xffff) { |
39037602 | 328 | return -1; //invalid argument |
0a7de745 | 329 | } |
39037602 | 330 | d->kcs_elem_size = ((count & 0xffff) << 16 | (size & 0xffff)); |
0a7de745 | 331 | } else { |
39037602 A |
332 | d->kcs_elem_size = size; |
333 | } | |
334 | return 0; | |
335 | } | |
336 | ||
337 | struct kcdata_type_definition { | |
338 | uint32_t kct_type_identifier; | |
339 | uint32_t kct_num_elements; | |
340 | char kct_name[KCDATA_DESC_MAXLEN]; | |
341 | struct kcdata_subtype_descriptor kct_elements[]; | |
342 | }; | |
343 | ||
344 | ||
345 | /* chunk type definitions. 0 - 0x7ff are reserved and defined here | |
346 | * NOTE: Please update kcdata/libkdd/kcdtypes.c if you make any changes | |
347 | * in STACKSHOT_KCTYPE_* types. | |
348 | */ | |
349 | ||
350 | /* | |
351 | * Types with description value. | |
352 | * these will have KCDATA_DESC_MAXLEN-1 length string description | |
353 | * and rest of kcdata_iter_size() - KCDATA_DESC_MAXLEN bytes as data | |
354 | */ | |
355 | #define KCDATA_TYPE_INVALID 0x0u | |
356 | #define KCDATA_TYPE_STRING_DESC 0x1u | |
357 | #define KCDATA_TYPE_UINT32_DESC 0x2u | |
358 | #define KCDATA_TYPE_UINT64_DESC 0x3u | |
359 | #define KCDATA_TYPE_INT32_DESC 0x4u | |
360 | #define KCDATA_TYPE_INT64_DESC 0x5u | |
361 | #define KCDATA_TYPE_BINDATA_DESC 0x6u | |
362 | ||
363 | /* | |
364 | * Compound type definitions | |
365 | */ | |
366 | #define KCDATA_TYPE_ARRAY 0x11u /* Array of data OBSOLETE DONT USE THIS*/ | |
367 | #define KCDATA_TYPE_TYPEDEFINTION 0x12u /* Meta type that describes a type on the fly. */ | |
368 | #define KCDATA_TYPE_CONTAINER_BEGIN \ | |
369 | 0x13u /* Container type which has corresponding CONTAINER_END header. \ | |
0a7de745 A |
370 | * KCDATA_TYPE_CONTAINER_BEGIN has type in the data segment. \ |
371 | * Both headers have (uint64_t) ID for matching up nested data. \ | |
372 | */ | |
39037602 A |
373 | #define KCDATA_TYPE_CONTAINER_END 0x14u |
374 | ||
375 | #define KCDATA_TYPE_ARRAY_PAD0 0x20u /* Array of data with 0 byte of padding*/ | |
376 | #define KCDATA_TYPE_ARRAY_PAD1 0x21u /* Array of data with 1 byte of padding*/ | |
377 | #define KCDATA_TYPE_ARRAY_PAD2 0x22u /* Array of data with 2 byte of padding*/ | |
378 | #define KCDATA_TYPE_ARRAY_PAD3 0x23u /* Array of data with 3 byte of padding*/ | |
379 | #define KCDATA_TYPE_ARRAY_PAD4 0x24u /* Array of data with 4 byte of padding*/ | |
380 | #define KCDATA_TYPE_ARRAY_PAD5 0x25u /* Array of data with 5 byte of padding*/ | |
381 | #define KCDATA_TYPE_ARRAY_PAD6 0x26u /* Array of data with 6 byte of padding*/ | |
382 | #define KCDATA_TYPE_ARRAY_PAD7 0x27u /* Array of data with 7 byte of padding*/ | |
383 | #define KCDATA_TYPE_ARRAY_PAD8 0x28u /* Array of data with 8 byte of padding*/ | |
384 | #define KCDATA_TYPE_ARRAY_PAD9 0x29u /* Array of data with 9 byte of padding*/ | |
385 | #define KCDATA_TYPE_ARRAY_PADa 0x2au /* Array of data with a byte of padding*/ | |
386 | #define KCDATA_TYPE_ARRAY_PADb 0x2bu /* Array of data with b byte of padding*/ | |
387 | #define KCDATA_TYPE_ARRAY_PADc 0x2cu /* Array of data with c byte of padding*/ | |
388 | #define KCDATA_TYPE_ARRAY_PADd 0x2du /* Array of data with d byte of padding*/ | |
389 | #define KCDATA_TYPE_ARRAY_PADe 0x2eu /* Array of data with e byte of padding*/ | |
390 | #define KCDATA_TYPE_ARRAY_PADf 0x2fu /* Array of data with f byte of padding*/ | |
391 | ||
392 | /* | |
393 | * Generic data types that are most commonly used | |
394 | */ | |
395 | #define KCDATA_TYPE_LIBRARY_LOADINFO 0x30u /* struct dyld_uuid_info_32 */ | |
396 | #define KCDATA_TYPE_LIBRARY_LOADINFO64 0x31u /* struct dyld_uuid_info_64 */ | |
397 | #define KCDATA_TYPE_TIMEBASE 0x32u /* struct mach_timebase_info */ | |
398 | #define KCDATA_TYPE_MACH_ABSOLUTE_TIME 0x33u /* uint64_t */ | |
399 | #define KCDATA_TYPE_TIMEVAL 0x34u /* struct timeval64 */ | |
400 | #define KCDATA_TYPE_USECS_SINCE_EPOCH 0x35u /* time in usecs uint64_t */ | |
401 | #define KCDATA_TYPE_PID 0x36u /* int32_t */ | |
402 | #define KCDATA_TYPE_PROCNAME 0x37u /* char * */ | |
403 | #define KCDATA_TYPE_NESTED_KCDATA 0x38u /* nested kcdata buffer */ | |
404 | ||
405 | #define KCDATA_TYPE_BUFFER_END 0xF19158EDu | |
406 | ||
407 | /* MAGIC numbers defined for each class of chunked data | |
408 | * | |
409 | * To future-proof against big-endian arches, make sure none of these magic | |
410 | * numbers are byteswaps of each other | |
411 | */ | |
412 | ||
413 | #define KCDATA_BUFFER_BEGIN_CRASHINFO 0xDEADF157u /* owner: corpses/task_corpse.h */ | |
414 | /* type-range: 0x800 - 0x8ff */ | |
415 | #define KCDATA_BUFFER_BEGIN_STACKSHOT 0x59a25807u /* owner: sys/stackshot.h */ | |
416 | /* type-range: 0x900 - 0x93f */ | |
417 | #define KCDATA_BUFFER_BEGIN_DELTA_STACKSHOT 0xDE17A59Au /* owner: sys/stackshot.h */ | |
418 | /* type-range: 0x940 - 0x9ff */ | |
419 | #define KCDATA_BUFFER_BEGIN_OS_REASON 0x53A20900u /* owner: sys/reason.h */ | |
420 | /* type-range: 0x1000-0x103f */ | |
421 | #define KCDATA_BUFFER_BEGIN_XNUPOST_CONFIG 0x1e21c09fu /* owner: osfmk/tests/kernel_tests.c */ | |
422 | /* type-range: 0x1040-0x105f */ | |
423 | ||
424 | /* next type range number available 0x1060 */ | |
425 | /**************** definitions for XNUPOST *********************/ | |
0a7de745 | 426 | #define XNUPOST_KCTYPE_TESTCONFIG 0x1040 |
39037602 A |
427 | |
428 | /**************** definitions for stackshot *********************/ | |
429 | ||
430 | /* This value must always match IO_NUM_PRIORITIES defined in thread_info.h */ | |
0a7de745 | 431 | #define STACKSHOT_IO_NUM_PRIORITIES 4 |
39037602 | 432 | /* This value must always match MAXTHREADNAMESIZE used in bsd */ |
0a7de745 | 433 | #define STACKSHOT_MAX_THREAD_NAME_SIZE 64 |
39037602 A |
434 | |
435 | /* | |
436 | * NOTE: Please update kcdata/libkdd/kcdtypes.c if you make any changes | |
437 | * in STACKSHOT_KCTYPE_* types. | |
438 | */ | |
cb323159 A |
439 | #define STACKSHOT_KCTYPE_IOSTATS 0x901u /* io_stats_snapshot */ |
440 | #define STACKSHOT_KCTYPE_GLOBAL_MEM_STATS 0x902u /* struct mem_and_io_snapshot */ | |
441 | #define STACKSHOT_KCCONTAINER_TASK 0x903u | |
442 | #define STACKSHOT_KCCONTAINER_THREAD 0x904u | |
443 | #define STACKSHOT_KCTYPE_TASK_SNAPSHOT 0x905u /* task_snapshot_v2 */ | |
444 | #define STACKSHOT_KCTYPE_THREAD_SNAPSHOT 0x906u /* thread_snapshot_v2, thread_snapshot_v3 */ | |
445 | #define STACKSHOT_KCTYPE_DONATING_PIDS 0x907u /* int[] */ | |
446 | #define STACKSHOT_KCTYPE_SHAREDCACHE_LOADINFO 0x908u /* same as KCDATA_TYPE_LIBRARY_LOADINFO64 */ | |
447 | #define STACKSHOT_KCTYPE_THREAD_NAME 0x909u /* char[] */ | |
448 | #define STACKSHOT_KCTYPE_KERN_STACKFRAME 0x90Au /* struct stack_snapshot_frame32 */ | |
449 | #define STACKSHOT_KCTYPE_KERN_STACKFRAME64 0x90Bu /* struct stack_snapshot_frame64 */ | |
450 | #define STACKSHOT_KCTYPE_USER_STACKFRAME 0x90Cu /* struct stack_snapshot_frame32 */ | |
451 | #define STACKSHOT_KCTYPE_USER_STACKFRAME64 0x90Du /* struct stack_snapshot_frame64 */ | |
452 | #define STACKSHOT_KCTYPE_BOOTARGS 0x90Eu /* boot args string */ | |
453 | #define STACKSHOT_KCTYPE_OSVERSION 0x90Fu /* os version string */ | |
454 | #define STACKSHOT_KCTYPE_KERN_PAGE_SIZE 0x910u /* kernel page size in uint32_t */ | |
455 | #define STACKSHOT_KCTYPE_JETSAM_LEVEL 0x911u /* jetsam level in uint32_t */ | |
456 | #define STACKSHOT_KCTYPE_DELTA_SINCE_TIMESTAMP 0x912u /* timestamp used for the delta stackshot */ | |
457 | #define STACKSHOT_KCTYPE_KERN_STACKLR 0x913u /* uint32_t */ | |
458 | #define STACKSHOT_KCTYPE_KERN_STACKLR64 0x914u /* uint64_t */ | |
459 | #define STACKSHOT_KCTYPE_USER_STACKLR 0x915u /* uint32_t */ | |
460 | #define STACKSHOT_KCTYPE_USER_STACKLR64 0x916u /* uint64_t */ | |
461 | #define STACKSHOT_KCTYPE_NONRUNNABLE_TIDS 0x917u /* uint64_t */ | |
462 | #define STACKSHOT_KCTYPE_NONRUNNABLE_TASKS 0x918u /* uint64_t */ | |
463 | #define STACKSHOT_KCTYPE_CPU_TIMES 0x919u /* struct stackshot_cpu_times or stackshot_cpu_times_v2 */ | |
464 | #define STACKSHOT_KCTYPE_STACKSHOT_DURATION 0x91au /* struct stackshot_duration */ | |
465 | #define STACKSHOT_KCTYPE_STACKSHOT_FAULT_STATS 0x91bu /* struct stackshot_fault_stats */ | |
466 | #define STACKSHOT_KCTYPE_KERNELCACHE_LOADINFO 0x91cu /* kernelcache UUID -- same as KCDATA_TYPE_LIBRARY_LOADINFO64 */ | |
467 | #define STACKSHOT_KCTYPE_THREAD_WAITINFO 0x91du /* struct stackshot_thread_waitinfo */ | |
468 | #define STACKSHOT_KCTYPE_THREAD_GROUP_SNAPSHOT 0x91eu /* struct thread_group_snapshot or thread_group_snapshot_v2 */ | |
469 | #define STACKSHOT_KCTYPE_THREAD_GROUP 0x91fu /* uint64_t */ | |
470 | #define STACKSHOT_KCTYPE_JETSAM_COALITION_SNAPSHOT 0x920u /* struct jetsam_coalition_snapshot */ | |
471 | #define STACKSHOT_KCTYPE_JETSAM_COALITION 0x921u /* uint64_t */ | |
472 | #define STACKSHOT_KCTYPE_THREAD_POLICY_VERSION 0x922u /* THREAD_POLICY_INTERNAL_STRUCT_VERSION in uint32 */ | |
473 | #define STACKSHOT_KCTYPE_INSTRS_CYCLES 0x923u /* struct instrs_cycles_snapshot */ | |
474 | #define STACKSHOT_KCTYPE_USER_STACKTOP 0x924u /* struct stack_snapshot_stacktop */ | |
475 | #define STACKSHOT_KCTYPE_ASID 0x925u /* uint32_t */ | |
476 | #define STACKSHOT_KCTYPE_PAGE_TABLES 0x926u /* uint64_t */ | |
477 | #define STACKSHOT_KCTYPE_SYS_SHAREDCACHE_LAYOUT 0x927u /* same as KCDATA_TYPE_LIBRARY_LOADINFO64 */ | |
478 | #define STACKSHOT_KCTYPE_THREAD_DISPATCH_QUEUE_LABEL 0x928u /* dispatch queue label */ | |
479 | #define STACKSHOT_KCTYPE_THREAD_TURNSTILEINFO 0x929u /* struct stackshot_thread_turnstileinfo */ | |
39037602 A |
480 | |
481 | #define STACKSHOT_KCTYPE_TASK_DELTA_SNAPSHOT 0x940u /* task_delta_snapshot_v2 */ | |
a39ff7e2 | 482 | #define STACKSHOT_KCTYPE_THREAD_DELTA_SNAPSHOT 0x941u /* thread_delta_snapshot_v* */ |
39037602 | 483 | |
39037602 A |
484 | struct stack_snapshot_frame32 { |
485 | uint32_t lr; | |
486 | uint32_t sp; | |
487 | }; | |
488 | ||
489 | struct stack_snapshot_frame64 { | |
0a7de745 A |
490 | uint64_t lr; |
491 | uint64_t sp; | |
39037602 A |
492 | }; |
493 | ||
494 | struct dyld_uuid_info_32 { | |
0a7de745 A |
495 | uint32_t imageLoadAddress; /* base address image is mapped at */ |
496 | uuid_t imageUUID; | |
39037602 A |
497 | }; |
498 | ||
499 | struct dyld_uuid_info_64 { | |
0a7de745 A |
500 | uint64_t imageLoadAddress; /* XXX image slide */ |
501 | uuid_t imageUUID; | |
39037602 A |
502 | }; |
503 | ||
504 | struct dyld_uuid_info_64_v2 { | |
0a7de745 A |
505 | uint64_t imageLoadAddress; /* XXX image slide */ |
506 | uuid_t imageUUID; | |
507 | /* end of version 1 of dyld_uuid_info_64. sizeof v1 was 24 */ | |
508 | uint64_t imageSlidBaseAddress; /* slid base address of image */ | |
39037602 A |
509 | }; |
510 | ||
511 | struct user32_dyld_uuid_info { | |
0a7de745 A |
512 | uint32_t imageLoadAddress; /* base address image is mapped into */ |
513 | uuid_t imageUUID; /* UUID of image */ | |
39037602 A |
514 | }; |
515 | ||
516 | struct user64_dyld_uuid_info { | |
0a7de745 A |
517 | uint64_t imageLoadAddress; /* base address image is mapped into */ |
518 | uuid_t imageUUID; /* UUID of image */ | |
39037602 A |
519 | }; |
520 | ||
521 | enum task_snapshot_flags { | |
cb323159 | 522 | /* k{User,Kernel}64_p (values 0x1 and 0x2) are defined in generic_snapshot_flags */ |
39037602 A |
523 | kTaskRsrcFlagged = 0x4, // In the EXC_RESOURCE danger zone? |
524 | kTerminatedSnapshot = 0x8, | |
525 | kPidSuspended = 0x10, // true for suspended task | |
526 | kFrozen = 0x20, // true for hibernated task (along with pidsuspended) | |
527 | kTaskDarwinBG = 0x40, | |
528 | kTaskExtDarwinBG = 0x80, | |
529 | kTaskVisVisible = 0x100, | |
530 | kTaskVisNonvisible = 0x200, | |
531 | kTaskIsForeground = 0x400, | |
532 | kTaskIsBoosted = 0x800, | |
533 | kTaskIsSuppressed = 0x1000, | |
534 | kTaskIsTimerThrottled = 0x2000, /* deprecated */ | |
535 | kTaskIsImpDonor = 0x4000, | |
536 | kTaskIsLiveImpDonor = 0x8000, | |
537 | kTaskIsDirty = 0x10000, | |
538 | kTaskWqExceededConstrainedThreadLimit = 0x20000, | |
539 | kTaskWqExceededTotalThreadLimit = 0x40000, | |
540 | kTaskWqFlagsAvailable = 0x80000, | |
541 | kTaskUUIDInfoFaultedIn = 0x100000, /* successfully faulted in some UUID info */ | |
542 | kTaskUUIDInfoMissing = 0x200000, /* some UUID info was paged out */ | |
543 | kTaskUUIDInfoTriedFault = 0x400000, /* tried to fault in UUID info */ | |
544 | kTaskSharedRegionInfoUnavailable = 0x800000, /* shared region info unavailable */ | |
d9a64523 A |
545 | kTaskTALEngaged = 0x1000000, |
546 | /* 0x2000000 unused */ | |
547 | kTaskIsDirtyTracked = 0x4000000, | |
548 | kTaskAllowIdleExit = 0x8000000, | |
39037602 A |
549 | }; |
550 | ||
551 | enum thread_snapshot_flags { | |
cb323159 | 552 | /* k{User,Kernel}64_p (values 0x1 and 0x2) are defined in generic_snapshot_flags */ |
39037602 A |
553 | kHasDispatchSerial = 0x4, |
554 | kStacksPCOnly = 0x8, /* Stack traces have no frame pointers. */ | |
555 | kThreadDarwinBG = 0x10, /* Thread is darwinbg */ | |
556 | kThreadIOPassive = 0x20, /* Thread uses passive IO */ | |
557 | kThreadSuspended = 0x40, /* Thread is suspended */ | |
558 | kThreadTruncatedBT = 0x80, /* Unmapped pages caused truncated backtrace */ | |
559 | kGlobalForcedIdle = 0x100, /* Thread performs global forced idle */ | |
560 | kThreadFaultedBT = 0x200, /* Some thread stack pages were faulted in as part of BT */ | |
561 | kThreadTriedFaultBT = 0x400, /* We tried to fault in thread stack pages as part of BT */ | |
562 | kThreadOnCore = 0x800, /* Thread was on-core when we entered debugger context */ | |
563 | kThreadIdleWorker = 0x1000, /* Thread is an idle libpthread worker thread */ | |
5ba3f43e | 564 | kThreadMain = 0x2000, /* Thread is the main thread */ |
39037602 A |
565 | }; |
566 | ||
567 | struct mem_and_io_snapshot { | |
0a7de745 A |
568 | uint32_t snapshot_magic; |
569 | uint32_t free_pages; | |
570 | uint32_t active_pages; | |
571 | uint32_t inactive_pages; | |
572 | uint32_t purgeable_pages; | |
573 | uint32_t wired_pages; | |
574 | uint32_t speculative_pages; | |
575 | uint32_t throttled_pages; | |
576 | uint32_t filebacked_pages; | |
577 | uint32_t compressions; | |
578 | uint32_t decompressions; | |
579 | uint32_t compressor_size; | |
580 | int32_t busy_buffer_count; | |
581 | uint32_t pages_wanted; | |
582 | uint32_t pages_reclaimed; | |
583 | uint8_t pages_wanted_reclaimed_valid; // did mach_vm_pressure_monitor succeed? | |
39037602 A |
584 | } __attribute__((packed)); |
585 | ||
586 | /* SS_TH_* macros are for ths_state */ | |
587 | #define SS_TH_WAIT 0x01 /* queued for waiting */ | |
588 | #define SS_TH_SUSP 0x02 /* stopped or requested to stop */ | |
589 | #define SS_TH_RUN 0x04 /* running or on runq */ | |
590 | #define SS_TH_UNINT 0x08 /* waiting uninteruptibly */ | |
591 | #define SS_TH_TERMINATE 0x10 /* halted at termination */ | |
592 | #define SS_TH_TERMINATE2 0x20 /* added to termination queue */ | |
593 | #define SS_TH_IDLE 0x80 /* idling processor */ | |
594 | ||
595 | struct thread_snapshot_v2 { | |
596 | uint64_t ths_thread_id; | |
597 | uint64_t ths_wait_event; | |
598 | uint64_t ths_continuation; | |
599 | uint64_t ths_total_syscalls; | |
600 | uint64_t ths_voucher_identifier; | |
601 | uint64_t ths_dqserialnum; | |
602 | uint64_t ths_user_time; | |
603 | uint64_t ths_sys_time; | |
604 | uint64_t ths_ss_flags; | |
605 | uint64_t ths_last_run_time; | |
606 | uint64_t ths_last_made_runnable_time; | |
607 | uint32_t ths_state; | |
608 | uint32_t ths_sched_flags; | |
609 | int16_t ths_base_priority; | |
610 | int16_t ths_sched_priority; | |
611 | uint8_t ths_eqos; | |
612 | uint8_t ths_rqos; | |
613 | uint8_t ths_rqos_override; | |
614 | uint8_t ths_io_tier; | |
615 | } __attribute__((packed)); | |
616 | ||
617 | struct thread_snapshot_v3 { | |
618 | uint64_t ths_thread_id; | |
619 | uint64_t ths_wait_event; | |
620 | uint64_t ths_continuation; | |
621 | uint64_t ths_total_syscalls; | |
622 | uint64_t ths_voucher_identifier; | |
623 | uint64_t ths_dqserialnum; | |
624 | uint64_t ths_user_time; | |
625 | uint64_t ths_sys_time; | |
626 | uint64_t ths_ss_flags; | |
627 | uint64_t ths_last_run_time; | |
628 | uint64_t ths_last_made_runnable_time; | |
629 | uint32_t ths_state; | |
630 | uint32_t ths_sched_flags; | |
631 | int16_t ths_base_priority; | |
632 | int16_t ths_sched_priority; | |
633 | uint8_t ths_eqos; | |
634 | uint8_t ths_rqos; | |
635 | uint8_t ths_rqos_override; | |
636 | uint8_t ths_io_tier; | |
637 | uint64_t ths_thread_t; | |
638 | } __attribute__((packed)); | |
639 | ||
5ba3f43e A |
640 | |
641 | struct thread_snapshot_v4 { | |
642 | uint64_t ths_thread_id; | |
643 | uint64_t ths_wait_event; | |
644 | uint64_t ths_continuation; | |
645 | uint64_t ths_total_syscalls; | |
646 | uint64_t ths_voucher_identifier; | |
647 | uint64_t ths_dqserialnum; | |
648 | uint64_t ths_user_time; | |
649 | uint64_t ths_sys_time; | |
650 | uint64_t ths_ss_flags; | |
651 | uint64_t ths_last_run_time; | |
652 | uint64_t ths_last_made_runnable_time; | |
653 | uint32_t ths_state; | |
654 | uint32_t ths_sched_flags; | |
655 | int16_t ths_base_priority; | |
656 | int16_t ths_sched_priority; | |
657 | uint8_t ths_eqos; | |
658 | uint8_t ths_rqos; | |
659 | uint8_t ths_rqos_override; | |
660 | uint8_t ths_io_tier; | |
661 | uint64_t ths_thread_t; | |
662 | uint64_t ths_requested_policy; | |
663 | uint64_t ths_effective_policy; | |
664 | } __attribute__((packed)); | |
665 | ||
666 | ||
667 | struct thread_group_snapshot { | |
668 | uint64_t tgs_id; | |
669 | char tgs_name[16]; | |
670 | } __attribute__((packed)); | |
671 | ||
5c9f4661 A |
672 | enum thread_group_flags { |
673 | kThreadGroupEfficient = 0x1, | |
674 | kThreadGroupUIApp = 0x2 | |
675 | }; | |
676 | ||
677 | struct thread_group_snapshot_v2 { | |
678 | uint64_t tgs_id; | |
679 | char tgs_name[16]; | |
680 | uint64_t tgs_flags; | |
681 | } __attribute__((packed)); | |
682 | ||
5ba3f43e A |
683 | enum coalition_flags { |
684 | kCoalitionTermRequested = 0x1, | |
685 | kCoalitionTerminated = 0x2, | |
686 | kCoalitionReaped = 0x4, | |
687 | kCoalitionPrivileged = 0x8, | |
688 | }; | |
689 | ||
690 | struct jetsam_coalition_snapshot { | |
691 | uint64_t jcs_id; | |
692 | uint64_t jcs_flags; | |
693 | uint64_t jcs_thread_group; | |
694 | uint64_t jcs_leader_task_uniqueid; | |
695 | } __attribute__((packed)); | |
696 | ||
697 | struct instrs_cycles_snapshot { | |
698 | uint64_t ics_instructions; | |
699 | uint64_t ics_cycles; | |
700 | } __attribute__((packed)); | |
701 | ||
39037602 A |
702 | struct thread_delta_snapshot_v2 { |
703 | uint64_t tds_thread_id; | |
704 | uint64_t tds_voucher_identifier; | |
705 | uint64_t tds_ss_flags; | |
706 | uint64_t tds_last_made_runnable_time; | |
707 | uint32_t tds_state; | |
708 | uint32_t tds_sched_flags; | |
709 | int16_t tds_base_priority; | |
710 | int16_t tds_sched_priority; | |
711 | uint8_t tds_eqos; | |
712 | uint8_t tds_rqos; | |
713 | uint8_t tds_rqos_override; | |
714 | uint8_t tds_io_tier; | |
715 | } __attribute__ ((packed)); | |
716 | ||
a39ff7e2 A |
717 | struct thread_delta_snapshot_v3 { |
718 | uint64_t tds_thread_id; | |
719 | uint64_t tds_voucher_identifier; | |
720 | uint64_t tds_ss_flags; | |
721 | uint64_t tds_last_made_runnable_time; | |
722 | uint32_t tds_state; | |
723 | uint32_t tds_sched_flags; | |
724 | int16_t tds_base_priority; | |
725 | int16_t tds_sched_priority; | |
726 | uint8_t tds_eqos; | |
727 | uint8_t tds_rqos; | |
728 | uint8_t tds_rqos_override; | |
729 | uint8_t tds_io_tier; | |
730 | uint64_t tds_requested_policy; | |
731 | uint64_t tds_effective_policy; | |
732 | } __attribute__ ((packed)); | |
733 | ||
0a7de745 | 734 | struct io_stats_snapshot { |
39037602 A |
735 | /* |
736 | * I/O Statistics | |
737 | * XXX: These fields must be together. | |
738 | */ | |
739 | uint64_t ss_disk_reads_count; | |
740 | uint64_t ss_disk_reads_size; | |
741 | uint64_t ss_disk_writes_count; | |
742 | uint64_t ss_disk_writes_size; | |
743 | uint64_t ss_io_priority_count[STACKSHOT_IO_NUM_PRIORITIES]; | |
744 | uint64_t ss_io_priority_size[STACKSHOT_IO_NUM_PRIORITIES]; | |
745 | uint64_t ss_paging_count; | |
746 | uint64_t ss_paging_size; | |
747 | uint64_t ss_non_paging_count; | |
748 | uint64_t ss_non_paging_size; | |
749 | uint64_t ss_data_count; | |
750 | uint64_t ss_data_size; | |
751 | uint64_t ss_metadata_count; | |
752 | uint64_t ss_metadata_size; | |
753 | /* XXX: I/O Statistics end */ | |
39037602 A |
754 | } __attribute__ ((packed)); |
755 | ||
756 | struct task_snapshot_v2 { | |
757 | uint64_t ts_unique_pid; | |
758 | uint64_t ts_ss_flags; | |
759 | uint64_t ts_user_time_in_terminated_threads; | |
760 | uint64_t ts_system_time_in_terminated_threads; | |
761 | uint64_t ts_p_start_sec; | |
762 | uint64_t ts_task_size; | |
763 | uint64_t ts_max_resident_size; | |
764 | uint32_t ts_suspend_count; | |
765 | uint32_t ts_faults; | |
766 | uint32_t ts_pageins; | |
767 | uint32_t ts_cow_faults; | |
768 | uint32_t ts_was_throttled; | |
769 | uint32_t ts_did_throttle; | |
770 | uint32_t ts_latency_qos; | |
771 | int32_t ts_pid; | |
772 | char ts_p_comm[32]; | |
773 | } __attribute__ ((packed)); | |
774 | ||
775 | struct task_delta_snapshot_v2 { | |
776 | uint64_t tds_unique_pid; | |
777 | uint64_t tds_ss_flags; | |
778 | uint64_t tds_user_time_in_terminated_threads; | |
779 | uint64_t tds_system_time_in_terminated_threads; | |
780 | uint64_t tds_task_size; | |
781 | uint64_t tds_max_resident_size; | |
782 | uint32_t tds_suspend_count; | |
783 | uint32_t tds_faults; | |
784 | uint32_t tds_pageins; | |
785 | uint32_t tds_cow_faults; | |
786 | uint32_t tds_was_throttled; | |
787 | uint32_t tds_did_throttle; | |
788 | uint32_t tds_latency_qos; | |
789 | } __attribute__ ((packed)); | |
790 | ||
791 | struct stackshot_cpu_times { | |
792 | uint64_t user_usec; | |
793 | uint64_t system_usec; | |
794 | } __attribute__((packed)); | |
795 | ||
d9a64523 A |
796 | struct stackshot_cpu_times_v2 { |
797 | uint64_t user_usec; | |
798 | uint64_t system_usec; | |
799 | uint64_t runnable_usec; | |
800 | } __attribute__((packed)); | |
801 | ||
39037602 A |
802 | struct stackshot_duration { |
803 | uint64_t stackshot_duration; | |
804 | uint64_t stackshot_duration_outer; | |
805 | } __attribute__((packed)); | |
806 | ||
807 | struct stackshot_fault_stats { | |
808 | uint32_t sfs_pages_faulted_in; /* number of pages faulted in using KDP fault path */ | |
809 | uint64_t sfs_time_spent_faulting; /* MATUs spent faulting */ | |
810 | uint64_t sfs_system_max_fault_time; /* MATUs fault time limit per stackshot */ | |
811 | uint8_t sfs_stopped_faulting; /* we stopped decompressing because we hit the limit */ | |
812 | } __attribute__((packed)); | |
813 | ||
813fb2f6 | 814 | typedef struct stackshot_thread_waitinfo { |
0a7de745 A |
815 | uint64_t owner; /* The thread that owns the object */ |
816 | uint64_t waiter; /* The thread that's waiting on the object */ | |
817 | uint64_t context; /* A context uniquely identifying the object */ | |
818 | uint8_t wait_type; /* The type of object that the thread is waiting on */ | |
813fb2f6 A |
819 | } __attribute__((packed)) thread_waitinfo_t; |
820 | ||
cb323159 A |
821 | typedef struct stackshot_thread_turnstileinfo { |
822 | uint64_t waiter; /* The thread that's waiting on the object */ | |
823 | uint64_t turnstile_context; /* Associated data (either thread id, or workq addr) */ | |
824 | uint8_t turnstile_priority; | |
825 | uint8_t number_of_hops; | |
826 | #define STACKSHOT_TURNSTILE_STATUS_UNKNOWN (1 << 0) /* The final inheritor is unknown (bug?) */ | |
827 | #define STACKSHOT_TURNSTILE_STATUS_LOCKED_WAITQ (1 << 1) /* A waitq was found to be locked */ | |
828 | #define STACKSHOT_TURNSTILE_STATUS_WORKQUEUE (1 << 2) /* The final inheritor is a workqueue */ | |
829 | #define STACKSHOT_TURNSTILE_STATUS_THREAD (1 << 3) /* The final inheritor is a thread */ | |
830 | uint64_t turnstile_flags; | |
831 | } __attribute__((packed)) thread_turnstileinfo_t; | |
832 | ||
813fb2f6 A |
833 | #define STACKSHOT_WAITOWNER_KERNEL (UINT64_MAX - 1) |
834 | #define STACKSHOT_WAITOWNER_PORT_LOCKED (UINT64_MAX - 2) | |
835 | #define STACKSHOT_WAITOWNER_PSET_LOCKED (UINT64_MAX - 3) | |
836 | #define STACKSHOT_WAITOWNER_INTRANSIT (UINT64_MAX - 4) | |
837 | #define STACKSHOT_WAITOWNER_MTXSPIN (UINT64_MAX - 5) | |
5ba3f43e A |
838 | #define STACKSHOT_WAITOWNER_THREQUESTED (UINT64_MAX - 6) /* workloop waiting for a new worker thread */ |
839 | #define STACKSHOT_WAITOWNER_SUSPENDED (UINT64_MAX - 7) /* workloop is suspended */ | |
813fb2f6 A |
840 | |
841 | ||
d9a64523 A |
842 | struct stack_snapshot_stacktop { |
843 | uint64_t sp; | |
844 | uint8_t stack_contents[8]; | |
845 | }; | |
846 | ||
847 | ||
39037602 A |
848 | /**************** definitions for crashinfo *********************/ |
849 | ||
850 | /* | |
851 | * NOTE: Please update kcdata/libkdd/kcdtypes.c if you make any changes | |
852 | * in TASK_CRASHINFO_* types. | |
853 | */ | |
854 | ||
855 | /* FIXME some of these types aren't clean (fixed width, packed, and defined *here*) */ | |
856 | ||
a39ff7e2 | 857 | struct crashinfo_proc_uniqidentifierinfo { |
0a7de745 A |
858 | uint8_t p_uuid[16]; /* UUID of the main executable */ |
859 | uint64_t p_uniqueid; /* 64 bit unique identifier for process */ | |
860 | uint64_t p_puniqueid; /* unique identifier for process's parent */ | |
861 | uint64_t p_reserve2; /* reserved for future use */ | |
862 | uint64_t p_reserve3; /* reserved for future use */ | |
863 | uint64_t p_reserve4; /* reserved for future use */ | |
a39ff7e2 A |
864 | } __attribute__((packed)); |
865 | ||
39037602 A |
866 | #define TASK_CRASHINFO_BEGIN KCDATA_BUFFER_BEGIN_CRASHINFO |
867 | #define TASK_CRASHINFO_STRING_DESC KCDATA_TYPE_STRING_DESC | |
868 | #define TASK_CRASHINFO_UINT32_DESC KCDATA_TYPE_UINT32_DESC | |
869 | #define TASK_CRASHINFO_UINT64_DESC KCDATA_TYPE_UINT64_DESC | |
870 | ||
871 | #define TASK_CRASHINFO_EXTMODINFO 0x801 | |
a39ff7e2 | 872 | #define TASK_CRASHINFO_BSDINFOWITHUNIQID 0x802 /* struct crashinfo_proc_uniqidentifierinfo */ |
39037602 A |
873 | #define TASK_CRASHINFO_TASKDYLD_INFO 0x803 |
874 | #define TASK_CRASHINFO_UUID 0x804 | |
875 | #define TASK_CRASHINFO_PID 0x805 | |
876 | #define TASK_CRASHINFO_PPID 0x806 | |
877 | #define TASK_CRASHINFO_RUSAGE 0x807 /* struct rusage DEPRECATED do not use. | |
0a7de745 | 878 | * This struct has longs in it */ |
39037602 A |
879 | #define TASK_CRASHINFO_RUSAGE_INFO 0x808 /* struct rusage_info_v3 from resource.h */ |
880 | #define TASK_CRASHINFO_PROC_NAME 0x809 /* char * */ | |
881 | #define TASK_CRASHINFO_PROC_STARTTIME 0x80B /* struct timeval64 */ | |
882 | #define TASK_CRASHINFO_USERSTACK 0x80C /* uint64_t */ | |
883 | #define TASK_CRASHINFO_ARGSLEN 0x80D | |
884 | #define TASK_CRASHINFO_EXCEPTION_CODES 0x80E /* mach_exception_data_t */ | |
885 | #define TASK_CRASHINFO_PROC_PATH 0x80F /* string of len MAXPATHLEN */ | |
886 | #define TASK_CRASHINFO_PROC_CSFLAGS 0x810 /* uint32_t */ | |
887 | #define TASK_CRASHINFO_PROC_STATUS 0x811 /* char */ | |
888 | #define TASK_CRASHINFO_UID 0x812 /* uid_t */ | |
889 | #define TASK_CRASHINFO_GID 0x813 /* gid_t */ | |
890 | #define TASK_CRASHINFO_PROC_ARGC 0x814 /* int */ | |
891 | #define TASK_CRASHINFO_PROC_FLAGS 0x815 /* unsigned int */ | |
892 | #define TASK_CRASHINFO_CPUTYPE 0x816 /* cpu_type_t */ | |
893 | #define TASK_CRASHINFO_WORKQUEUEINFO 0x817 /* struct proc_workqueueinfo */ | |
894 | #define TASK_CRASHINFO_RESPONSIBLE_PID 0x818 /* pid_t */ | |
895 | #define TASK_CRASHINFO_DIRTY_FLAGS 0x819 /* int */ | |
896 | #define TASK_CRASHINFO_CRASHED_THREADID 0x81A /* uint64_t */ | |
897 | #define TASK_CRASHINFO_COALITION_ID 0x81B /* uint64_t */ | |
898 | #define TASK_CRASHINFO_UDATA_PTRS 0x81C /* uint64_t */ | |
899 | #define TASK_CRASHINFO_MEMORY_LIMIT 0x81D /* uint64_t */ | |
900 | ||
d9a64523 A |
901 | #define TASK_CRASHINFO_LEDGER_INTERNAL 0x81E /* uint64_t */ |
902 | #define TASK_CRASHINFO_LEDGER_INTERNAL_COMPRESSED 0x81F /* uint64_t */ | |
903 | #define TASK_CRASHINFO_LEDGER_IOKIT_MAPPED 0x820 /* uint64_t */ | |
904 | #define TASK_CRASHINFO_LEDGER_ALTERNATE_ACCOUNTING 0x821 /* uint64_t */ | |
905 | #define TASK_CRASHINFO_LEDGER_ALTERNATE_ACCOUNTING_COMPRESSED 0x822 /* uint64_t */ | |
906 | #define TASK_CRASHINFO_LEDGER_PURGEABLE_NONVOLATILE 0x823 /* uint64_t */ | |
907 | #define TASK_CRASHINFO_LEDGER_PURGEABLE_NONVOLATILE_COMPRESSED 0x824 /* uint64_t */ | |
908 | #define TASK_CRASHINFO_LEDGER_PAGE_TABLE 0x825 /* uint64_t */ | |
909 | #define TASK_CRASHINFO_LEDGER_PHYS_FOOTPRINT 0x826 /* uint64_t */ | |
910 | #define TASK_CRASHINFO_LEDGER_PHYS_FOOTPRINT_LIFETIME_MAX 0x827 /* uint64_t */ | |
911 | #define TASK_CRASHINFO_LEDGER_NETWORK_NONVOLATILE 0x828 /* uint64_t */ | |
912 | #define TASK_CRASHINFO_LEDGER_NETWORK_NONVOLATILE_COMPRESSED 0x829 /* uint64_t */ | |
913 | #define TASK_CRASHINFO_LEDGER_WIRED_MEM 0x82A /* uint64_t */ | |
cb323159 A |
914 | #define TASK_CRASHINFO_PROC_PERSONA_ID 0x82B /* uid_t */ |
915 | #define TASK_CRASHINFO_MEMORY_LIMIT_INCREASE 0x82C /* uint32_t */ | |
d9a64523 A |
916 | |
917 | ||
918 | ||
39037602 A |
919 | #define TASK_CRASHINFO_END KCDATA_TYPE_BUFFER_END |
920 | ||
921 | /**************** definitions for os reasons *********************/ | |
922 | ||
923 | #define EXIT_REASON_SNAPSHOT 0x1001 | |
924 | #define EXIT_REASON_USER_DESC 0x1002 /* string description of reason */ | |
925 | #define EXIT_REASON_USER_PAYLOAD 0x1003 /* user payload data */ | |
926 | #define EXIT_REASON_CODESIGNING_INFO 0x1004 | |
5ba3f43e A |
927 | #define EXIT_REASON_WORKLOOP_ID 0x1005 |
928 | #define EXIT_REASON_DISPATCH_QUEUE_NO 0x1006 | |
39037602 A |
929 | |
930 | struct exit_reason_snapshot { | |
0a7de745 A |
931 | uint32_t ers_namespace; |
932 | uint64_t ers_code; | |
933 | /* end of version 1 of exit_reason_snapshot. sizeof v1 was 12 */ | |
934 | uint64_t ers_flags; | |
39037602 A |
935 | } __attribute__((packed)); |
936 | ||
937 | #define EXIT_REASON_CODESIG_PATH_MAX 1024 | |
938 | ||
939 | struct codesigning_exit_reason_info { | |
940 | uint64_t ceri_virt_addr; | |
941 | uint64_t ceri_file_offset; | |
942 | char ceri_pathname[EXIT_REASON_CODESIG_PATH_MAX]; | |
943 | char ceri_filename[EXIT_REASON_CODESIG_PATH_MAX]; | |
944 | uint64_t ceri_codesig_modtime_secs; | |
945 | uint64_t ceri_codesig_modtime_nsecs; | |
946 | uint64_t ceri_page_modtime_secs; | |
947 | uint64_t ceri_page_modtime_nsecs; | |
948 | uint8_t ceri_path_truncated; | |
949 | uint8_t ceri_object_codesigned; | |
950 | uint8_t ceri_page_codesig_validated; | |
951 | uint8_t ceri_page_codesig_tainted; | |
952 | uint8_t ceri_page_codesig_nx; | |
953 | uint8_t ceri_page_wpmapped; | |
954 | uint8_t ceri_page_slid; | |
955 | uint8_t ceri_page_dirty; | |
956 | uint32_t ceri_page_shadow_depth; | |
957 | } __attribute__((packed)); | |
958 | ||
959 | #define EXIT_REASON_USER_DESC_MAX_LEN 1024 | |
960 | #define EXIT_REASON_PAYLOAD_MAX_LEN 2048 | |
961 | /**************** safe iterators *********************/ | |
962 | ||
963 | typedef struct kcdata_iter { | |
964 | kcdata_item_t item; | |
965 | void *end; | |
966 | } kcdata_iter_t; | |
967 | ||
968 | ||
969 | static inline | |
0a7de745 A |
970 | kcdata_iter_t |
971 | kcdata_iter(void *buffer, unsigned long size) | |
972 | { | |
39037602 A |
973 | kcdata_iter_t iter; |
974 | iter.item = (kcdata_item_t) buffer; | |
975 | iter.end = (void*) (((uintptr_t)buffer) + size); | |
976 | return iter; | |
977 | } | |
978 | ||
979 | static inline | |
980 | kcdata_iter_t kcdata_iter_unsafe(void *buffer) __attribute__((deprecated)); | |
981 | ||
982 | static inline | |
0a7de745 A |
983 | kcdata_iter_t |
984 | kcdata_iter_unsafe(void *buffer) | |
985 | { | |
39037602 A |
986 | kcdata_iter_t iter; |
987 | iter.item = (kcdata_item_t) buffer; | |
988 | iter.end = (void*) (uintptr_t) ~0; | |
989 | return iter; | |
990 | } | |
991 | ||
cb323159 | 992 | static const kcdata_iter_t kcdata_invalid_iter = { .item = NULL, .end = NULL }; |
39037602 A |
993 | |
994 | static inline | |
0a7de745 A |
995 | int |
996 | kcdata_iter_valid(kcdata_iter_t iter) | |
997 | { | |
39037602 | 998 | return |
0a7de745 A |
999 | ((uintptr_t)iter.item + sizeof(struct kcdata_item) <= (uintptr_t)iter.end) && |
1000 | ((uintptr_t)iter.item + sizeof(struct kcdata_item) + iter.item->size <= (uintptr_t)iter.end); | |
39037602 A |
1001 | } |
1002 | ||
1003 | ||
1004 | static inline | |
0a7de745 A |
1005 | kcdata_iter_t |
1006 | kcdata_iter_next(kcdata_iter_t iter) | |
1007 | { | |
39037602 A |
1008 | iter.item = (kcdata_item_t) (((uintptr_t)iter.item) + sizeof(struct kcdata_item) + (iter.item->size)); |
1009 | return iter; | |
1010 | } | |
1011 | ||
1012 | static inline uint32_t | |
1013 | kcdata_iter_type(kcdata_iter_t iter) | |
1014 | { | |
0a7de745 | 1015 | if ((iter.item->type & ~0xfu) == KCDATA_TYPE_ARRAY_PAD0) { |
39037602 | 1016 | return KCDATA_TYPE_ARRAY; |
0a7de745 | 1017 | } else { |
39037602 | 1018 | return iter.item->type; |
0a7de745 | 1019 | } |
39037602 A |
1020 | } |
1021 | ||
1022 | static inline uint32_t | |
1023 | kcdata_calc_padding(uint32_t size) | |
1024 | { | |
d9a64523 | 1025 | /* calculate number of bytes to add to size to get something divisible by 16 */ |
39037602 A |
1026 | return (-size) & 0xf; |
1027 | } | |
1028 | ||
1029 | static inline uint32_t | |
1030 | kcdata_flags_get_padding(uint64_t flags) | |
1031 | { | |
1032 | return flags & KCDATA_FLAGS_STRUCT_PADDING_MASK; | |
1033 | } | |
1034 | ||
1035 | /* see comment above about has_padding */ | |
1036 | static inline int | |
1037 | kcdata_iter_is_legacy_item(kcdata_iter_t iter, uint32_t legacy_size) | |
1038 | { | |
1039 | uint32_t legacy_size_padded = legacy_size + kcdata_calc_padding(legacy_size); | |
0a7de745 A |
1040 | return iter.item->size == legacy_size_padded && |
1041 | (iter.item->flags & (KCDATA_FLAGS_STRUCT_PADDING_MASK | KCDATA_FLAGS_STRUCT_HAS_PADDING)) == 0; | |
39037602 A |
1042 | } |
1043 | ||
1044 | static inline uint32_t | |
1045 | kcdata_iter_size(kcdata_iter_t iter) | |
1046 | { | |
1047 | uint32_t legacy_size = 0; | |
1048 | ||
1049 | switch (kcdata_iter_type(iter)) { | |
1050 | case KCDATA_TYPE_ARRAY: | |
1051 | case KCDATA_TYPE_CONTAINER_BEGIN: | |
1052 | return iter.item->size; | |
1053 | case STACKSHOT_KCTYPE_THREAD_SNAPSHOT: { | |
1054 | legacy_size = sizeof(struct thread_snapshot_v2); | |
1055 | if (kcdata_iter_is_legacy_item(iter, legacy_size)) { | |
1056 | return legacy_size; | |
1057 | } | |
1058 | ||
1059 | goto not_legacy; | |
1060 | } | |
1061 | case STACKSHOT_KCTYPE_SHAREDCACHE_LOADINFO: { | |
1062 | legacy_size = sizeof(struct dyld_uuid_info_64); | |
1063 | if (kcdata_iter_is_legacy_item(iter, legacy_size)) { | |
1064 | return legacy_size; | |
1065 | } | |
1066 | ||
1067 | goto not_legacy; | |
1068 | } | |
1069 | not_legacy: | |
1070 | default: | |
0a7de745 | 1071 | if (iter.item->size < kcdata_flags_get_padding(iter.item->flags)) { |
39037602 | 1072 | return 0; |
0a7de745 | 1073 | } else { |
39037602 | 1074 | return iter.item->size - kcdata_flags_get_padding(iter.item->flags); |
0a7de745 | 1075 | } |
39037602 A |
1076 | } |
1077 | } | |
1078 | ||
1079 | static inline uint64_t | |
1080 | kcdata_iter_flags(kcdata_iter_t iter) | |
1081 | { | |
1082 | return iter.item->flags; | |
1083 | } | |
1084 | ||
1085 | static inline | |
0a7de745 A |
1086 | void * |
1087 | kcdata_iter_payload(kcdata_iter_t iter) | |
1088 | { | |
39037602 A |
1089 | return &iter.item->data; |
1090 | } | |
1091 | ||
1092 | ||
1093 | static inline | |
0a7de745 A |
1094 | uint32_t |
1095 | kcdata_iter_array_elem_type(kcdata_iter_t iter) | |
1096 | { | |
39037602 A |
1097 | return (iter.item->flags >> 32) & UINT32_MAX; |
1098 | } | |
1099 | ||
1100 | static inline | |
0a7de745 A |
1101 | uint32_t |
1102 | kcdata_iter_array_elem_count(kcdata_iter_t iter) | |
1103 | { | |
39037602 A |
1104 | return (iter.item->flags) & UINT32_MAX; |
1105 | } | |
1106 | ||
1107 | /* KCDATA_TYPE_ARRAY is ambiguous about the size of the array elements. Size is | |
1108 | * calculated as total_size / elements_count, but total size got padded out to a | |
1109 | * 16 byte alignment. New kernels will generate KCDATA_TYPE_ARRAY_PAD* instead | |
1110 | * to explicitly tell us how much padding was used. Here we have a fixed, never | |
1111 | * to be altered list of the sizes of array elements that were used before I | |
1112 | * discovered this issue. If you find a KCDATA_TYPE_ARRAY that is not one of | |
1113 | * these types, treat it as invalid data. */ | |
1114 | ||
1115 | static inline | |
1116 | uint32_t | |
0a7de745 A |
1117 | kcdata_iter_array_size_switch(kcdata_iter_t iter) |
1118 | { | |
1119 | switch (kcdata_iter_array_elem_type(iter)) { | |
39037602 A |
1120 | case KCDATA_TYPE_LIBRARY_LOADINFO: |
1121 | return sizeof(struct dyld_uuid_info_32); | |
1122 | case KCDATA_TYPE_LIBRARY_LOADINFO64: | |
1123 | return sizeof(struct dyld_uuid_info_64); | |
1124 | case STACKSHOT_KCTYPE_KERN_STACKFRAME: | |
1125 | case STACKSHOT_KCTYPE_USER_STACKFRAME: | |
1126 | return sizeof(struct stack_snapshot_frame32); | |
1127 | case STACKSHOT_KCTYPE_KERN_STACKFRAME64: | |
1128 | case STACKSHOT_KCTYPE_USER_STACKFRAME64: | |
1129 | return sizeof(struct stack_snapshot_frame64); | |
1130 | case STACKSHOT_KCTYPE_DONATING_PIDS: | |
1131 | return sizeof(int32_t); | |
1132 | case STACKSHOT_KCTYPE_THREAD_DELTA_SNAPSHOT: | |
1133 | return sizeof(struct thread_delta_snapshot_v2); | |
0a7de745 A |
1134 | // This one is only here to make some unit tests work. It should be OK to |
1135 | // remove. | |
39037602 A |
1136 | case TASK_CRASHINFO_CRASHED_THREADID: |
1137 | return sizeof(uint64_t); | |
1138 | default: | |
1139 | return 0; | |
1140 | } | |
1141 | } | |
1142 | ||
1143 | static inline | |
0a7de745 A |
1144 | int |
1145 | kcdata_iter_array_valid(kcdata_iter_t iter) | |
1146 | { | |
1147 | if (!kcdata_iter_valid(iter)) { | |
39037602 | 1148 | return 0; |
0a7de745 A |
1149 | } |
1150 | if (kcdata_iter_type(iter) != KCDATA_TYPE_ARRAY) { | |
39037602 | 1151 | return 0; |
0a7de745 A |
1152 | } |
1153 | if (kcdata_iter_array_elem_count(iter) == 0) { | |
39037602 | 1154 | return iter.item->size == 0; |
0a7de745 | 1155 | } |
39037602 A |
1156 | if (iter.item->type == KCDATA_TYPE_ARRAY) { |
1157 | uint32_t elem_size = kcdata_iter_array_size_switch(iter); | |
0a7de745 | 1158 | if (elem_size == 0) { |
39037602 | 1159 | return 0; |
0a7de745 | 1160 | } |
39037602 A |
1161 | /* sizes get aligned to the nearest 16. */ |
1162 | return | |
0a7de745 A |
1163 | kcdata_iter_array_elem_count(iter) <= iter.item->size / elem_size && |
1164 | iter.item->size % kcdata_iter_array_elem_count(iter) < 16; | |
39037602 A |
1165 | } else { |
1166 | return | |
0a7de745 A |
1167 | (iter.item->type & 0xf) <= iter.item->size && |
1168 | kcdata_iter_array_elem_count(iter) <= iter.item->size - (iter.item->type & 0xf) && | |
1169 | (iter.item->size - (iter.item->type & 0xf)) % kcdata_iter_array_elem_count(iter) == 0; | |
39037602 A |
1170 | } |
1171 | } | |
1172 | ||
1173 | ||
1174 | static inline | |
0a7de745 A |
1175 | uint32_t |
1176 | kcdata_iter_array_elem_size(kcdata_iter_t iter) | |
1177 | { | |
1178 | if (iter.item->type == KCDATA_TYPE_ARRAY) { | |
39037602 | 1179 | return kcdata_iter_array_size_switch(iter); |
0a7de745 A |
1180 | } |
1181 | if (kcdata_iter_array_elem_count(iter) == 0) { | |
39037602 | 1182 | return 0; |
0a7de745 | 1183 | } |
39037602 A |
1184 | return (iter.item->size - (iter.item->type & 0xf)) / kcdata_iter_array_elem_count(iter); |
1185 | } | |
1186 | ||
1187 | static inline | |
0a7de745 A |
1188 | int |
1189 | kcdata_iter_container_valid(kcdata_iter_t iter) | |
1190 | { | |
39037602 | 1191 | return |
0a7de745 A |
1192 | kcdata_iter_valid(iter) && |
1193 | kcdata_iter_type(iter) == KCDATA_TYPE_CONTAINER_BEGIN && | |
1194 | iter.item->size >= sizeof(uint32_t); | |
39037602 A |
1195 | } |
1196 | ||
1197 | static inline | |
0a7de745 A |
1198 | uint32_t |
1199 | kcdata_iter_container_type(kcdata_iter_t iter) | |
1200 | { | |
1201 | return *(uint32_t *) kcdata_iter_payload(iter); | |
39037602 A |
1202 | } |
1203 | ||
1204 | static inline | |
0a7de745 A |
1205 | uint64_t |
1206 | kcdata_iter_container_id(kcdata_iter_t iter) | |
1207 | { | |
39037602 A |
1208 | return iter.item->flags; |
1209 | } | |
1210 | ||
1211 | ||
1212 | #define KCDATA_ITER_FOREACH(iter) for(; kcdata_iter_valid(iter) && iter.item->type != KCDATA_TYPE_BUFFER_END; iter = kcdata_iter_next(iter)) | |
1213 | #define KCDATA_ITER_FOREACH_FAILED(iter) (!kcdata_iter_valid(iter) || (iter).item->type != KCDATA_TYPE_BUFFER_END) | |
1214 | ||
1215 | static inline | |
1216 | kcdata_iter_t | |
1217 | kcdata_iter_find_type(kcdata_iter_t iter, uint32_t type) | |
1218 | { | |
1219 | KCDATA_ITER_FOREACH(iter) | |
1220 | { | |
0a7de745 | 1221 | if (kcdata_iter_type(iter) == type) { |
39037602 | 1222 | return iter; |
0a7de745 | 1223 | } |
39037602 A |
1224 | } |
1225 | return kcdata_invalid_iter; | |
1226 | } | |
1227 | ||
1228 | static inline | |
0a7de745 A |
1229 | int |
1230 | kcdata_iter_data_with_desc_valid(kcdata_iter_t iter, uint32_t minsize) | |
1231 | { | |
39037602 | 1232 | return |
0a7de745 A |
1233 | kcdata_iter_valid(iter) && |
1234 | kcdata_iter_size(iter) >= KCDATA_DESC_MAXLEN + minsize && | |
1235 | ((char*)kcdata_iter_payload(iter))[KCDATA_DESC_MAXLEN - 1] == 0; | |
39037602 A |
1236 | } |
1237 | ||
1238 | static inline | |
0a7de745 A |
1239 | char * |
1240 | kcdata_iter_string(kcdata_iter_t iter, uint32_t offset) | |
1241 | { | |
39037602 A |
1242 | if (offset > kcdata_iter_size(iter)) { |
1243 | return NULL; | |
1244 | } | |
1245 | uint32_t maxlen = kcdata_iter_size(iter) - offset; | |
1246 | char *s = ((char*)kcdata_iter_payload(iter)) + offset; | |
1247 | if (strnlen(s, maxlen) < maxlen) { | |
1248 | return s; | |
1249 | } else { | |
1250 | return NULL; | |
1251 | } | |
1252 | } | |
1253 | ||
0a7de745 A |
1254 | static inline void |
1255 | kcdata_iter_get_data_with_desc(kcdata_iter_t iter, char **desc_ptr, void **data_ptr, uint32_t *size_ptr) | |
1256 | { | |
1257 | if (desc_ptr) { | |
39037602 | 1258 | *desc_ptr = (char *)kcdata_iter_payload(iter); |
0a7de745 A |
1259 | } |
1260 | if (data_ptr) { | |
39037602 | 1261 | *data_ptr = (void *)((uintptr_t)kcdata_iter_payload(iter) + KCDATA_DESC_MAXLEN); |
0a7de745 A |
1262 | } |
1263 | if (size_ptr) { | |
39037602 | 1264 | *size_ptr = kcdata_iter_size(iter) - KCDATA_DESC_MAXLEN; |
0a7de745 | 1265 | } |
39037602 A |
1266 | } |
1267 | ||
1268 | #endif |