xref: /xnu-12377.61.12/doc/debugging/extensible_paniclog.md (revision 4d495c6e23c53686cf65f45067f79024cf5dcee8)
1*4d495c6eSApple OSS Distributions# Extensible Paniclog
2*4d495c6eSApple OSS Distributions
3*4d495c6eSApple OSS DistributionsThis documentation discusses the API and features of the extensible paniclog in XNU's panic flow.
4*4d495c6eSApple OSS Distributions
5*4d495c6eSApple OSS Distributions## Overview
6*4d495c6eSApple OSS Distributions
7*4d495c6eSApple OSS DistributionsWith this feature we want to provide an infrastructure for kexts / dexts to insert their system state into the paniclog. Currently there is no way of knowing the kext or dext state unless we take a full coredump. With this feature, they can drop relevant state information that will end up in the paniclog and can be used to triage panics.
8*4d495c6eSApple OSS Distributions
9*4d495c6eSApple OSS Distributions## UUID ↔ buffer data mapping
10*4d495c6eSApple OSS Distributions
11*4d495c6eSApple OSS DistributionsAll clients who adopt this infrastructure will have to use a UUID that maps to a format of the buffer data. Clients will have to provide a mapping that specifies how to decode the data. This mapping will be used to decode the data in DumpPanic or a tool integrated into MPT.
12*4d495c6eSApple OSS Distributions
13*4d495c6eSApple OSS Distributions## IOKit APIs
14*4d495c6eSApple OSS Distributions
15*4d495c6eSApple OSS DistributionsSource Code: `iokit/IOKit/IOExtensiblePaniclog.h`
16*4d495c6eSApple OSS Distributions
17*4d495c6eSApple OSS Distributions```c
18*4d495c6eSApple OSS Distributionsstatic bool createWithUUID(uuid_t uuid, const char *data_id, uint32_t max_len, ext_paniclog_create_options_t options, IOExtensiblePaniclog **out);
19*4d495c6eSApple OSS Distributions```
20*4d495c6eSApple OSS Distributions
21*4d495c6eSApple OSS DistributionsThis is the first API that is called by a kext to initialize an IOExtensiblePaniclog instance. It takes a UUID, data_id, max len, and options as input and emits an instance in the out pointer. The data id takes a short description of the buffer and the maximum length is 32 bytes.
22*4d495c6eSApple OSS Distributions
23*4d495c6eSApple OSS Distributions```c
24*4d495c6eSApple OSS Distributionsint setActive();
25*4d495c6eSApple OSS Distributionsint setInactive();
26*4d495c6eSApple OSS Distributions```
27*4d495c6eSApple OSS Distributions
28*4d495c6eSApple OSS DistributionsThese functions are called to make an IOExtensiblePaniclog instance active or inactive. An instance is collected and put into the panic file only if it's active. It's ignored in the panic path if it's inactive.
29*4d495c6eSApple OSS Distributions
30*4d495c6eSApple OSS Distributions```c
31*4d495c6eSApple OSS Distributionsint insertData(void *addr, uint32_t len);
32*4d495c6eSApple OSS Distributions```
33*4d495c6eSApple OSS Distributions
34*4d495c6eSApple OSS DistributionsThis function inserts the data pointed to by addr into the IOExtensiblePaniclog instance. It will copy the data into the buffer from offset 0.
35*4d495c6eSApple OSS Distributions
36*4d495c6eSApple OSS Distributions```c
37*4d495c6eSApple OSS Distributionsint appendData(void *addr, uint32_t len);
38*4d495c6eSApple OSS Distributions```
39*4d495c6eSApple OSS Distributions
40*4d495c6eSApple OSS DistributionsThis function appends the data pointed to by addr into the IOExtensiblePaniclog instance. It will position the data after the previous insert or append.
41*4d495c6eSApple OSS Distributions
42*4d495c6eSApple OSS Distributions```c
43*4d495c6eSApple OSS Distributionsvoid *claimBuffer();
44*4d495c6eSApple OSS Distributions```
45*4d495c6eSApple OSS Distributions
46*4d495c6eSApple OSS DistributionsThis function returns the buffer of the IOExtensiblePaniclog instance. This function also sets the used length of the handle to the max length. The entire buffer is copied out when the system panic after this function call. yieldBuffer() has to be called before using insertData() or appendData(). 
47*4d495c6eSApple OSS Distributions
48*4d495c6eSApple OSS Distributions```c
49*4d495c6eSApple OSS Distributionsint yieldBuffer(uint32_t used_len);
50*4d495c6eSApple OSS Distributions```
51*4d495c6eSApple OSS Distributions
52*4d495c6eSApple OSS DistributionsThis function is called to yield the buffer and set the used_len for the buffer.
53*4d495c6eSApple OSS Distributions
54*4d495c6eSApple OSS Distributions```c
55*4d495c6eSApple OSS Distributionsint setUsedLen(uint32_t used_len)
56*4d495c6eSApple OSS Distributions```
57*4d495c6eSApple OSS Distributions
58*4d495c6eSApple OSS DistributionsThis function is called to set the used len of the buffer.
59*4d495c6eSApple OSS Distributions
60*4d495c6eSApple OSS Distributions## DriverKit APIs
61*4d495c6eSApple OSS Distributions
62*4d495c6eSApple OSS DistributionsSource Code: `iokit/DriverKit/IOExtensiblePaniclog.iig`
63*4d495c6eSApple OSS Distributions
64*4d495c6eSApple OSS Distributions```cpp
65*4d495c6eSApple OSS Distributionsstatic kern_return_t Create(OSData *uuid, OSString *data_id, uint32_t max_len, IOExtensiblePaniclog **out);
66*4d495c6eSApple OSS Distributions```
67*4d495c6eSApple OSS Distributions
68*4d495c6eSApple OSS DistributionsThis is first API that is called by a dext to initialize an IOExtensiblePaniclog instance. It takes a UUID, data_id and the max len as input and emits an instance in the out pointer. The data id takes a short description of the buffer and the maximum length is 32 bytes.
69*4d495c6eSApple OSS Distributions
70*4d495c6eSApple OSS Distributions```cpp
71*4d495c6eSApple OSS Distributionskern_return_t SetActive();
72*4d495c6eSApple OSS Distributionskern_return_t SetInactive();
73*4d495c6eSApple OSS Distributions```
74*4d495c6eSApple OSS Distributions
75*4d495c6eSApple OSS DistributionsThese functions are called to make an IOExtensiblePaniclog instance active or inactive. An instance is collected and put into the panic file only if it's active. It's ignored in the panic path if it's inactive.
76*4d495c6eSApple OSS Distributions
77*4d495c6eSApple OSS Distributions```cpp
78*4d495c6eSApple OSS Distributionskern_return_t InsertData(OSData *data);
79*4d495c6eSApple OSS Distributions```
80*4d495c6eSApple OSS Distributions
81*4d495c6eSApple OSS DistributionsThis function inserts the data pointed to by addr into the IOExtensiblePaniclog instance. It will copy the data into the buffer from offset 0.
82*4d495c6eSApple OSS Distributions
83*4d495c6eSApple OSS Distributions```cpp
84*4d495c6eSApple OSS Distributionskern_return_t AppendData(OSData *data);
85*4d495c6eSApple OSS Distributions```
86*4d495c6eSApple OSS Distributions
87*4d495c6eSApple OSS DistributionsThis function appends the data pointed to by addr into the IOExtensiblePaniclog instance. It will position the data after the previous insert or append.
88*4d495c6eSApple OSS Distributions
89*4d495c6eSApple OSS Distributions```cpp
90*4d495c6eSApple OSS Distributionskern_return_t ClaimBuffer(uint64_t *addr, uint64_t *len);
91*4d495c6eSApple OSS Distributions```
92*4d495c6eSApple OSS Distributions
93*4d495c6eSApple OSS DistributionsThis function is called to get a pointer to the ext paniclog buffer. After this function is called, the user is responsible for copying data into the buffer. The entire buffer is copied when a system panics. After claiming the buffer, YieldBuffer() has to be called to set the used_len of the buffer before calling InsertData() or AppendData().
94*4d495c6eSApple OSS Distributions
95*4d495c6eSApple OSS Distributions```cpp
96*4d495c6eSApple OSS Distributionskern_return_t YieldBuffer(uint32_t used_len);
97*4d495c6eSApple OSS Distributions```
98*4d495c6eSApple OSS Distributions
99*4d495c6eSApple OSS DistributionsThis function is called to yield the buffer and set the used_len for the buffer.
100*4d495c6eSApple OSS Distributions
101*4d495c6eSApple OSS Distributions```cpp
102*4d495c6eSApple OSS Distributionskern_return_t SetUsedLen(uint32_t used_len);
103*4d495c6eSApple OSS Distributions```
104*4d495c6eSApple OSS Distributions
105*4d495c6eSApple OSS DistributionsThis function is called to set the used len of the buffer.
106*4d495c6eSApple OSS Distributions
107*4d495c6eSApple OSS Distributions## Low-Level Kernel APIs
108*4d495c6eSApple OSS Distributions
109*4d495c6eSApple OSS DistributionsSource Code: `osfmk/kern/ext_paniclog.h`
110*4d495c6eSApple OSS Distributions
111*4d495c6eSApple OSS Distributions### ExtensiblePaniclog Handle Struct
112*4d495c6eSApple OSS Distributions
113*4d495c6eSApple OSS Distributions```c
114*4d495c6eSApple OSS Distributionstypedef struct ext_paniclog_handle {
115*4d495c6eSApple OSS Distributions	LIST_ENTRY(ext_paniclog_handle) handles;
116*4d495c6eSApple OSS Distributions	uuid_t uuid;
117*4d495c6eSApple OSS Distributions	char data_id[MAX_DATA_ID_SIZE];
118*4d495c6eSApple OSS Distributions	void *buf_addr;
119*4d495c6eSApple OSS Distributions	uint32_t max_len;
120*4d495c6eSApple OSS Distributions	uint32_t used_len;
121*4d495c6eSApple OSS Distributions    ext_paniclog_create_options_t options;
122*4d495c6eSApple OSS Distributions    ext_paniclog_flags_t flags;
123*4d495c6eSApple OSS Distributions	uint8_t active;
124*4d495c6eSApple OSS Distributions} ext_paniclog_handle_t;
125*4d495c6eSApple OSS Distributions```
126*4d495c6eSApple OSS Distributions
127*4d495c6eSApple OSS DistributionsWe employ handles in XNU to guarantee the effective management of buffer lifecycles, prevent nested panics from occurring during access from the panic path, and build a durable and expandable API. The primary reason for using handles is to allow XNU to oversee the entire buffer lifecycle. By keeping track of the buffer's state and managing its deallocation, we can avoid potential issues that may arise during panic scenarios.
128*4d495c6eSApple OSS Distributions
129*4d495c6eSApple OSS Distributions```c
130*4d495c6eSApple OSS Distributionsext_paniclog_handle_t *ext_paniclog_handle_alloc_with_uuid(uuid_t uuid, const char *data_id, uint32_t max_len, ext_paniclog_create_options_t);
131*4d495c6eSApple OSS Distributions```
132*4d495c6eSApple OSS Distributions
133*4d495c6eSApple OSS DistributionsThis function will be called to initialize a buffer of the specified length. For all subsequent operations we use this handle as input. It takes a UUID, data_id, max len, and options as input and emits an instance in the out pointer. The data id takes a short description of the buffer and the maximum length is 32 bytes. This function will return a handle on success and NULL on failure.
134*4d495c6eSApple OSS Distributions
135*4d495c6eSApple OSS Distributions```c
136*4d495c6eSApple OSS Distributionsint ext_paniclog_handle_set_active(ext_paniclog_handle_t *handle);
137*4d495c6eSApple OSS Distributions```
138*4d495c6eSApple OSS Distributions
139*4d495c6eSApple OSS DistributionsThis function sets the handle as active. In active state, this buffer will get picked up by the panic path and put into the panic file.
140*4d495c6eSApple OSS Distributions
141*4d495c6eSApple OSS Distributions```c
142*4d495c6eSApple OSS Distributionsint ext_paniclog_handle_set_inactive(ext_paniclog_handle_t *handle);
143*4d495c6eSApple OSS Distributions```
144*4d495c6eSApple OSS Distributions
145*4d495c6eSApple OSS DistributionsThis function sets the handle as inactive.
146*4d495c6eSApple OSS Distributions
147*4d495c6eSApple OSS Distributions```c
148*4d495c6eSApple OSS Distributionsvoid ext_paniclog_handle_free(ext_paniclog_handle_t *handle)
149*4d495c6eSApple OSS Distributions```
150*4d495c6eSApple OSS Distributions
151*4d495c6eSApple OSS DistributionsThis functions deallocates all the memory that is allocated in the alloc function. The handle has to a be a valid and this function should only be called after handle_alloc is called.
152*4d495c6eSApple OSS Distributions
153*4d495c6eSApple OSS Distributions```c
154*4d495c6eSApple OSS Distributionsint ext_paniclog_insert_data(ext_paniclog_handle_t *handle, void *addr, size_t len)
155*4d495c6eSApple OSS Distributions```
156*4d495c6eSApple OSS Distributions
157*4d495c6eSApple OSS DistributionsThis function is called to insert the data from a buffer to the handle buffer. This function will take a handle that has been previously allocated, an address to the buffer and length of the buffer. This function will return 0 on success and a negative value on failure.
158*4d495c6eSApple OSS Distributions
159*4d495c6eSApple OSS Distributions```c
160*4d495c6eSApple OSS Distributionsint ext_paniclog_append_data(ext_paniclog_handle_t *handle, void *addr, uint32_t len);
161*4d495c6eSApple OSS Distributions```
162*4d495c6eSApple OSS Distributions
163*4d495c6eSApple OSS DistributionsThis function is called to append to the data that is already present in the buffer.
164*4d495c6eSApple OSS Distributions
165*4d495c6eSApple OSS Distributions```c
166*4d495c6eSApple OSS Distributionsvoid *ext_paniclog_get_buffer(ext_paniclog_handle_t *handle)
167*4d495c6eSApple OSS Distributions```
168*4d495c6eSApple OSS Distributions
169*4d495c6eSApple OSS DistributionsThis function is called to get a pointer to the ext paniclog buffer. To modify the buffer after getting the pointer use the `ext_paniclog_claim_buffer()`.
170*4d495c6eSApple OSS Distributions
171*4d495c6eSApple OSS Distributions```c
172*4d495c6eSApple OSS Distributionsvoid *ext_paniclog_claim_buffer(ext_paniclog_handle_t *handle);
173*4d495c6eSApple OSS Distributions```
174*4d495c6eSApple OSS Distributions
175*4d495c6eSApple OSS DistributionsThis function is called to get a pointer to the ext paniclog buffer. After this function is called, the user is responsible for copying data into the buffer. The entire buffer is copied when a system panics. After claiming the buffer, `ext_paniclog_yield_buffer()` has to be called to set the `used_len` of the buffer before calling `ext_paniclog_insert_data()` or `ext_paniclog_append_data()`.
176*4d495c6eSApple OSS Distributions
177*4d495c6eSApple OSS Distributions```c
178*4d495c6eSApple OSS Distributionsint ext_paniclog_yield_buffer(ext_paniclog_handle_t *handle, uint32_t used_len);
179*4d495c6eSApple OSS Distributions```
180*4d495c6eSApple OSS Distributions
181*4d495c6eSApple OSS DistributionsThis function is called to yield the buffer and set the used_len for the buffer.
182*4d495c6eSApple OSS Distributions
183*4d495c6eSApple OSS Distributions```c
184*4d495c6eSApple OSS Distributionsint ext_paniclog_set_used_len(ext_paniclog_handle_t *handle, uint32_t used_len);
185*4d495c6eSApple OSS Distributions```
186*4d495c6eSApple OSS Distributions
187*4d495c6eSApple OSS DistributionsThis function is called to set the used len of the buffer.
188*4d495c6eSApple OSS Distributions
189*4d495c6eSApple OSS Distributions## panic_with_data APIs
190*4d495c6eSApple OSS Distributions
191*4d495c6eSApple OSS Distributions```c
192*4d495c6eSApple OSS Distributionsvoid panic_with_data(uuid_t uuid, void *addr, uint32_t len, uint64_t debugger_options_mask, const char *format, ...);
193*4d495c6eSApple OSS Distributions```
194*4d495c6eSApple OSS Distributions
195*4d495c6eSApple OSS DistributionsThis function is called when a kernel client is panicking and wants to insert the data into the extensible panic log. We treat this as a special case and put this data at the start of the extensible panic log region. The client has to supply the UUID to decode the buffer that is pushed to the paniclog.
196*4d495c6eSApple OSS Distributions
197*4d495c6eSApple OSS Distributions```c
198*4d495c6eSApple OSS Distributionsint panic_with_data(char *uuid, void *addr, uint32_t len, uint32_t flags, const char *msg);
199*4d495c6eSApple OSS Distributions```
200*4d495c6eSApple OSS Distributions
201*4d495c6eSApple OSS DistributionsThis provides the same functionality as panic_with_data() for userspace clients.
202*4d495c6eSApple OSS Distributions
203*4d495c6eSApple OSS Distributions## Special Options
204*4d495c6eSApple OSS Distributions
205*4d495c6eSApple OSS Distributions### `EXT_PANICLOG_OPTIONS_ADD_SEPARATE_KEY`
206*4d495c6eSApple OSS Distributions
207*4d495c6eSApple OSS DistributionsIf the `EXT_PANICLOG_OPTIONS_ADD_SEPARATE_KEY` option is set when creating an ExtensiblePaniclog handle, the Data ID / buffer data (key / value) pair will be added directly to the paniclog instead of under the "ExtensiblePaniclog" key.
208*4d495c6eSApple OSS Distributions
209*4d495c6eSApple OSS Distributions## Implementation
210*4d495c6eSApple OSS Distributions
211*4d495c6eSApple OSS Distributions### Estimating the panic log size
212*4d495c6eSApple OSS Distributions
213*4d495c6eSApple OSS DistributionsWe want to add the utilization metrics of the panic log to the panic.ips file. This will give us an idea of the percentage of the panic log we currently use and how big each section in the panic log is. We will use this data to estimate how big the other log section usually is and ensure that we leave enough space for this section when inserting the extensible panic log. We will cut off the extensible panic log if we cannot fit all the buffers into the free region.
214*4d495c6eSApple OSS Distributions
215*4d495c6eSApple OSS Distributions### Registering a buffer + Writing data to the buffer
216*4d495c6eSApple OSS Distributions
217*4d495c6eSApple OSS DistributionsWe have APIs exposed at different layers so that a client can use whatever suits it best. In DriverKit and IOKit cases, they call the `createWithUUID` or `Create` methods to create an IOExtensiblePaniclog instance and use that instance to insert or append data to a buffer.
218*4d495c6eSApple OSS Distributions
219*4d495c6eSApple OSS DistributionsLower level clients use `ext_paniclog_handle_alloc_with_uuid` to allocate a handle and use that handle to insert data using `ext_paniclog_insert_data` and `ext_paniclog_append_data` functions.
220*4d495c6eSApple OSS Distributions
221*4d495c6eSApple OSS DistributionsWhen a kernel client is panicking, it has the option to call `panic_with_data()`, which just takes a UUID, buffer address and length. This API makes sure that we copy this data in to the extensible panic log.
222*4d495c6eSApple OSS Distributions
223*4d495c6eSApple OSS Distributions### Insert data into the extended panic log
224*4d495c6eSApple OSS Distributions
225*4d495c6eSApple OSS DistributionsCurrent structure of the panic log is as follows:
226*4d495c6eSApple OSS Distributions
227*4d495c6eSApple OSS Distributions```
228*4d495c6eSApple OSS Distributions-------------------------
229*4d495c6eSApple OSS Distributions-      Panic Header     -
230*4d495c6eSApple OSS Distributions-------------------------
231*4d495c6eSApple OSS Distributions-                       -
232*4d495c6eSApple OSS Distributions-       Panic Log       -
233*4d495c6eSApple OSS Distributions-                       -
234*4d495c6eSApple OSS Distributions-------------------------
235*4d495c6eSApple OSS Distributions-                       -
236*4d495c6eSApple OSS Distributions-      Stack shots      -
237*4d495c6eSApple OSS Distributions-                       -
238*4d495c6eSApple OSS Distributions-------------------------
239*4d495c6eSApple OSS Distributions-                       -
240*4d495c6eSApple OSS Distributions-       Other Log       -
241*4d495c6eSApple OSS Distributions-                       -
242*4d495c6eSApple OSS Distributions-------------------------
243*4d495c6eSApple OSS Distributions-       Misc Data       -
244*4d495c6eSApple OSS Distributions-------------------------
245*4d495c6eSApple OSS Distributions-                       -
246*4d495c6eSApple OSS Distributions-                       -
247*4d495c6eSApple OSS Distributions-         Free          -
248*4d495c6eSApple OSS Distributions-                       -
249*4d495c6eSApple OSS Distributions-                       -
250*4d495c6eSApple OSS Distributions-------------------------
251*4d495c6eSApple OSS Distributions```
252*4d495c6eSApple OSS Distributions
253*4d495c6eSApple OSS DistributionsWe want to use the free part of the panic log to insert the extensible panic log. After we insert the stackshots, we calculate and see how much space we have in the panic log to insert the extensible panic log. These calculations will use the data that we collect from our utilization metrics and leave out space for the other log section. We then go through the ext_paniclog linked list and start inserting the buffers into the panic log region until we fill out size we calculated. After this, we move onto inserting data into the other log section.
254*4d495c6eSApple OSS Distributions
255*4d495c6eSApple OSS Distributions## Format / structure of the extensible panic log:
256*4d495c6eSApple OSS Distributions
257*4d495c6eSApple OSS Distributions```
258*4d495c6eSApple OSS Distributions+---------+------------+---------+---------+------------+------------+---------+---------+---------+-----------+------------+----------+
259*4d495c6eSApple OSS Distributions|         |            |         |         |            |            |         |         |         |           |            |          |
260*4d495c6eSApple OSS Distributions|Version  | No of logs | UUID 1  | Flags 1 | Data ID 1  | Data len 1 | Data 1  | UUID 2  | Flags 2 | Data ID 2 | Data len 2 | Data 2   |
261*4d495c6eSApple OSS Distributions|         |            |         |         |            |            |         |         |         |           |            |          |
262*4d495c6eSApple OSS Distributions+---------+------------+---------+---------+------------+------------+---------+---------+---------+-----------+------------+----------+
263*4d495c6eSApple OSS Distributions```
264*4d495c6eSApple OSS Distributions
265*4d495c6eSApple OSS Distributions## Extract and format the extensible panic log into the panic.ips file
266*4d495c6eSApple OSS Distributions
267*4d495c6eSApple OSS DistributionsIn DumpPanic, we will extract this data from the panic log region and format it to be readable. We can group the data according to uuid and sort it with the data_id of the data. An example of the extensible panic log data in the panic.ips file shown below.
268*4d495c6eSApple OSS Distributions
269*4d495c6eSApple OSS Distributions```
270*4d495c6eSApple OSS Distributions{
271*4d495c6eSApple OSS Distributions    "ExtensiblePanicLog": {
272*4d495c6eSApple OSS Distributions        "<UUID_1>": [
273*4d495c6eSApple OSS Distributions            {
274*4d495c6eSApple OSS Distributions                "DataID": "0x1"
275*4d495c6eSApple OSS Distributions                "data" : <buffer1>
276*4d495c6eSApple OSS Distributions            },
277*4d495c6eSApple OSS Distributions            {
278*4d495c6eSApple OSS Distributions                "DataID": "0x2"
279*4d495c6eSApple OSS Distributions                "data" : <buffer2>
280*4d495c6eSApple OSS Distributions            }
281*4d495c6eSApple OSS Distributions        ],
282*4d495c6eSApple OSS Distributions        "<UUID_2>": [
283*4d495c6eSApple OSS Distributions            {
284*4d495c6eSApple OSS Distributions                "DataID": "0x1"
285*4d495c6eSApple OSS Distributions                "data" : <buffer1>
286*4d495c6eSApple OSS Distributions            },
287*4d495c6eSApple OSS Distributions            {
288*4d495c6eSApple OSS Distributions                "DataID": "0x2"
289*4d495c6eSApple OSS Distributions                "data" : <buffer2>
290*4d495c6eSApple OSS Distributions            }
291*4d495c6eSApple OSS Distributions        ],
292*4d495c6eSApple OSS Distributions    },
293*4d495c6eSApple OSS Distributions    "SeparateFieldDataID1": "Separate buffer value here 1",
294*4d495c6eSApple OSS Distributions    "SeparateFieldDataID2": "Separate buffer value here 2",
295*4d495c6eSApple OSS Distributions}
296*4d495c6eSApple OSS Distributions```
297*4d495c6eSApple OSS Distributions
298*4d495c6eSApple OSS DistributionsNotice that there are two fields below ExtensiblePanicLog in the panic.ips example above. If you were to pass the option `EXT_PANICLOG_CREATE_OPTIONS_ADD_SEPARATE_KEY` to the handle create function, DumpPanic would process that handle as seen above, by adding it as a field directly to the panic file instead of including it in the ExtensiblePanicLog field.
299*4d495c6eSApple OSS Distributions
300*4d495c6eSApple OSS Distributions## Example code
301*4d495c6eSApple OSS Distributions
302*4d495c6eSApple OSS Distributions### IOKit Example
303*4d495c6eSApple OSS Distributions
304*4d495c6eSApple OSS Distributions#### Creating the handle
305*4d495c6eSApple OSS Distributions
306*4d495c6eSApple OSS Distributions```c
307*4d495c6eSApple OSS Distributionschar uuid_string_1[] = "E2070C7E-A1C3-41DF-ABA4-B9921DACCD87";
308*4d495c6eSApple OSS Distributionsbool res;
309*4d495c6eSApple OSS Distributionskern_return_t ret;
310*4d495c6eSApple OSS Distributions
311*4d495c6eSApple OSS Distributionsuuid_t uuid_1;
312*4d495c6eSApple OSS Distributionsuuid_parse(uuid_string_1, uuid_1);
313*4d495c6eSApple OSS Distributions
314*4d495c6eSApple OSS Distributionsres = IOExtensiblePaniclog::createWithUUID(uuid_1, "Lha ops 1", 1024, EXT_PANICLOG_OPTIONS_NONE, &paniclog_handle_1);
315*4d495c6eSApple OSS Distributionsif (res == false) {
316*4d495c6eSApple OSS Distributions    DEBUG_LOG ("Failed to create ext paniclog handle: %d\n", res);
317*4d495c6eSApple OSS Distributions}
318*4d495c6eSApple OSS Distributions
319*4d495c6eSApple OSS DistributionsDEBUG_LOG("Created panic log handle 1 with UUID: %s\n", uuid_string_1);
320*4d495c6eSApple OSS Distributions
321*4d495c6eSApple OSS Distributionschar uuid_string_2[] = "28245A8F-04CA-4932-8A38-E6C159FD9C92";
322*4d495c6eSApple OSS Distributionsuuid_t uuid_2;
323*4d495c6eSApple OSS Distributionsuuid_parse(uuid_string_2, uuid_2);
324*4d495c6eSApple OSS Distributionsres = IOExtensiblePaniclog::createWithUUID(uuid_2, "Lha ops 2", 1024, EXT_PANICLOG_OPTIONS_NONE, &paniclog_handle_2);
325*4d495c6eSApple OSS Distributionsif (res == false) {
326*4d495c6eSApple OSS Distributions    DEBUG_LOG ("Failed to create ext paniclog handle: %d\n", res);
327*4d495c6eSApple OSS Distributions}
328*4d495c6eSApple OSS Distributions
329*4d495c6eSApple OSS DistributionsDEBUG_LOG("Created panic log handle 2 with UUID: %s\n", uuid_string_2);
330*4d495c6eSApple OSS Distributions```
331*4d495c6eSApple OSS Distributions
332*4d495c6eSApple OSS Distributions#### Inserting the data
333*4d495c6eSApple OSS Distributions
334*4d495c6eSApple OSS Distributions```c
335*4d495c6eSApple OSS DistributionsDEBUG_LOG ("%s\n", __FUNCTION__);
336*4d495c6eSApple OSS Distributionschar buff[1024] = {0};
337*4d495c6eSApple OSS Distributionssnprintf(buff, 1024, "HW access Dir: %u Type: %u Address: %llu\n", input->direction, input->type, input->address);
338*4d495c6eSApple OSS Distributions
339*4d495c6eSApple OSS Distributionschar buff1[1024] = {0};
340*4d495c6eSApple OSS Distributions
341*4d495c6eSApple OSS Distributionspaniclog_handle_1->insertData(buff, (uint32_t)strlen(buff));
342*4d495c6eSApple OSS Distributionspaniclog_handle_1->setActive();
343*4d495c6eSApple OSS Distributions
344*4d495c6eSApple OSS Distributionspaniclog_handle_2->insertData(input, sizeof(HardwareAccessParameters));
345*4d495c6eSApple OSS Distributionspaniclog_handle_2->setActive();
346*4d495c6eSApple OSS Distributions```
347*4d495c6eSApple OSS Distributions
348*4d495c6eSApple OSS Distributions### DriverKit Example
349*4d495c6eSApple OSS Distributions
350*4d495c6eSApple OSS Distributions#### Creating the handle
351*4d495c6eSApple OSS Distributions
352*4d495c6eSApple OSS Distributions```cpp
353*4d495c6eSApple OSS DistributionsOSData *uuid_data = OSData::withBytes(&uuid_3[0], sizeof(uuid_t));
354*4d495c6eSApple OSS Distributionsif (!uuid_data) {
355*4d495c6eSApple OSS Distributions    IOLog("Data was not created\n");
356*4d495c6eSApple OSS Distributions    return NULL;
357*4d495c6eSApple OSS Distributions}
358*4d495c6eSApple OSS Distributions
359*4d495c6eSApple OSS DistributionsOSString *data_id = OSString::withCString("DriverKit OP 1");
360*4d495c6eSApple OSS Distributions
361*4d495c6eSApple OSS Distributionsret = IOExtensiblePaniclog::Create(uuid_data, data_id, 64, kIOExtensiblePaniclogOptionsNone, &paniclog_handle_3);
362*4d495c6eSApple OSS Distributionsif (ret != kIOReturnSuccess) {
363*4d495c6eSApple OSS Distributions    IOLog("Failed to create paniclog handle 3\n");
364*4d495c6eSApple OSS Distributions    return NULL;
365*4d495c6eSApple OSS Distributions}
366*4d495c6eSApple OSS DistributionsIOLog("EXT_PANICLOG: Created panic log handle 3 with UUID: %s\n", uuid_string_3);
367*4d495c6eSApple OSS Distributions```
368*4d495c6eSApple OSS Distributions
369*4d495c6eSApple OSS Distributions#### Inserting the data
370*4d495c6eSApple OSS Distributions
371*4d495c6eSApple OSS Distributions```cpp
372*4d495c6eSApple OSS Distributionsret = paniclog_handle_3->ClaimBuffer(&addr, &len);
373*4d495c6eSApple OSS Distributionsif (ret != kIOReturnSuccess) {
374*4d495c6eSApple OSS Distributions    IOLog("EXT_PANICLOG: Failed to claim buffer. Ret: %x\n", ret);
375*4d495c6eSApple OSS Distributions    return NULL;
376*4d495c6eSApple OSS Distributions}
377*4d495c6eSApple OSS Distributions
378*4d495c6eSApple OSS DistributionsIOLog("EXT_PANICLOG: Got buffer address %llu, %llu", addr, len);
379*4d495c6eSApple OSS Distributions
380*4d495c6eSApple OSS Distributionsbuff1 = (char *)addr;
381*4d495c6eSApple OSS Distributions
382*4d495c6eSApple OSS DistributionsIOLog("EXT_PANICLOG: Ignoring write for now");
383*4d495c6eSApple OSS Distributionsmemcpy(buff1, buff, strlen(buff));
384*4d495c6eSApple OSS Distributions
385*4d495c6eSApple OSS Distributionspaniclog_handle_3->YieldBuffer((uint32_t)strlen(buff));
386*4d495c6eSApple OSS Distributions
387*4d495c6eSApple OSS Distributionspaniclog_handle_3->SetActive();
388*4d495c6eSApple OSS Distributions```
389*4d495c6eSApple OSS Distributions
390