2 * Copyright (c) 2015 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <kern/assert.h>
30 #include <mach/mach_types.h>
31 #include <mach/boolean.h>
32 #include <mach/vm_param.h>
33 #include <kern/kern_types.h>
34 #include <kern/mach_param.h>
35 #include <kern/thread.h>
36 #include <kern/task.h>
37 #include <kern/kern_cdata.h>
38 #include <kern/kalloc.h>
39 #include <mach/mach_vm.h>
41 static kern_return_t
kcdata_get_memory_addr_with_flavor(kcdata_descriptor_t data
, uint32_t type
, uint32_t size
, uint64_t flags
, mach_vm_address_t
*user_addr
);
44 * Estimates how large of a buffer that should be allocated for a buffer that will contain
45 * num_items items of known types with overall length payload_size.
47 * NOTE: This function will not give an accurate estimate for buffers that will
48 * contain unknown types (those with string descriptions).
51 kcdata_estimate_required_buffer_size(uint32_t num_items
, uint32_t payload_size
)
54 * In the worst case each item will need (KCDATA_ALIGNMENT_SIZE - 1) padding
56 uint32_t max_padding_bytes
= num_items
* (KCDATA_ALIGNMENT_SIZE
- 1);
57 uint32_t item_description_bytes
= num_items
* sizeof(struct kcdata_item
);
58 uint32_t begin_and_end_marker_bytes
= 2 * sizeof(struct kcdata_item
);
60 return max_padding_bytes
+ item_description_bytes
+ begin_and_end_marker_bytes
+ payload_size
;
64 kcdata_memory_alloc_init(mach_vm_address_t buffer_addr_p
, unsigned data_type
, unsigned size
, unsigned flags
)
66 kcdata_descriptor_t data
= NULL
;
67 mach_vm_address_t user_addr
= 0;
69 data
= kalloc(sizeof(struct kcdata_descriptor
));
73 bzero(data
, sizeof(struct kcdata_descriptor
));
74 data
->kcd_addr_begin
= buffer_addr_p
;
75 data
->kcd_addr_end
= buffer_addr_p
;
76 data
->kcd_flags
= (flags
& KCFLAG_USE_COPYOUT
)? KCFLAG_USE_COPYOUT
: KCFLAG_USE_MEMCOPY
;
77 data
->kcd_length
= size
;
79 /* Initialize the BEGIN header */
80 if (KERN_SUCCESS
!= kcdata_get_memory_addr(data
, data_type
, 0, &user_addr
)) {
81 kcdata_memory_destroy(data
);
89 kcdata_memory_static_init(kcdata_descriptor_t data
, mach_vm_address_t buffer_addr_p
, unsigned data_type
, unsigned size
, unsigned flags
)
91 mach_vm_address_t user_addr
= 0;
94 return KERN_INVALID_ARGUMENT
;
96 bzero(data
, sizeof(struct kcdata_descriptor
));
97 data
->kcd_addr_begin
= buffer_addr_p
;
98 data
->kcd_addr_end
= buffer_addr_p
;
99 data
->kcd_flags
= (flags
& KCFLAG_USE_COPYOUT
)? KCFLAG_USE_COPYOUT
: KCFLAG_USE_MEMCOPY
;
100 data
->kcd_length
= size
;
102 /* Initialize the BEGIN header */
103 return kcdata_get_memory_addr(data
, data_type
, 0, &user_addr
);
107 kcdata_memory_get_begin_addr(kcdata_descriptor_t data
)
113 return (void *)data
->kcd_addr_begin
;
117 kcdata_memory_get_used_bytes(kcdata_descriptor_t kcd
)
120 return ((uint64_t)kcd
->kcd_addr_end
- (uint64_t)kcd
->kcd_addr_begin
) + sizeof(struct kcdata_item
);
124 * Free up the memory associated with kcdata
127 kcdata_memory_destroy(kcdata_descriptor_t data
)
130 return KERN_INVALID_ARGUMENT
;
134 * data->kcd_addr_begin points to memory in not tracked by
135 * kcdata lib. So not clearing that here.
137 kfree(data
, sizeof(struct kcdata_descriptor
));
144 * Routine: kcdata_get_memory_addr
145 * Desc: get memory address in the userspace memory for corpse info
146 * NOTE: The caller is responsible for zeroing the resulting memory or
147 * using other means to mark memory if it has failed populating the
148 * data in middle of operation.
149 * params: data - pointer describing the crash info allocation
150 * type - type of data to be put. See corpse.h for defined types
151 * size - size requested. The header describes this size
152 * returns: mach_vm_address_t address in user memory for copyout().
155 kcdata_get_memory_addr(kcdata_descriptor_t data
, uint32_t type
, uint32_t size
, mach_vm_address_t
* user_addr
)
157 /* record number of padding bytes as lower 4 bits of flags */
158 uint64_t flags
= (KCDATA_FLAGS_STRUCT_PADDING_MASK
& kcdata_calc_padding(size
)) | KCDATA_FLAGS_STRUCT_HAS_PADDING
;
159 return kcdata_get_memory_addr_with_flavor(data
, type
, size
, flags
, user_addr
);
163 * Routine: kcdata_add_buffer_end
165 * Desc: Write buffer end marker. This does not advance the end pointer in the
166 * kcdata_descriptor_t, so it may be used conservatively before additional data
167 * is added, as long as it is at least called after the last time data is added.
169 * params: data - pointer describing the crash info allocation
173 kcdata_write_buffer_end(kcdata_descriptor_t data
)
175 struct kcdata_item info
;
176 bzero(&info
, sizeof(info
));
177 info
.type
= KCDATA_TYPE_BUFFER_END
;
179 return kcdata_memcpy(data
, data
->kcd_addr_end
, &info
, sizeof(info
));
183 * Routine: kcdata_get_memory_addr_with_flavor
184 * Desc: internal function with flags field. See documentation for kcdata_get_memory_addr for details
188 kcdata_get_memory_addr_with_flavor(
189 kcdata_descriptor_t data
,
193 mach_vm_address_t
*user_addr
)
196 struct kcdata_item info
;
198 uint32_t orig_size
= size
;
199 /* make sure 16 byte aligned */
200 uint32_t padding
= kcdata_calc_padding(size
);
202 uint32_t total_size
= size
+ sizeof(info
);
204 if (user_addr
== NULL
|| data
== NULL
|| total_size
+ sizeof(info
) < orig_size
) {
205 return KERN_INVALID_ARGUMENT
;
208 bzero(&info
, sizeof(info
));
213 /* check available memory, including trailer size for KCDATA_TYPE_BUFFER_END */
214 if (total_size
+ sizeof(info
) > data
->kcd_length
||
215 data
->kcd_length
- (total_size
+ sizeof(info
)) < data
->kcd_addr_end
- data
->kcd_addr_begin
) {
216 return KERN_RESOURCE_SHORTAGE
;
219 kr
= kcdata_memcpy(data
, data
->kcd_addr_end
, &info
, sizeof(info
));
224 data
->kcd_addr_end
+= sizeof(info
);
227 kr
= kcdata_bzero(data
, data
->kcd_addr_end
+ size
- padding
, padding
);
233 *user_addr
= data
->kcd_addr_end
;
234 data
->kcd_addr_end
+= size
;
236 if (!(data
->kcd_flags
& KCFLAG_NO_AUTO_ENDBUFFER
)) {
237 /* setup the end header as well */
238 return kcdata_write_buffer_end(data
);
245 * Routine: kcdata_get_memory_addr_for_array
246 * Desc: get memory address in the userspace memory for corpse info
247 * NOTE: The caller is responsible to zero the resulting memory or
248 * user other means to mark memory if it has failed populating the
249 * data in middle of operation.
250 * params: data - pointer describing the crash info allocation
251 * type_of_element - type of data to be put. See kern_cdata.h for defined types
252 * size_of_element - size of element. The header describes this size
253 * count - num of elements in array.
254 * returns: mach_vm_address_t address in user memory for copyout().
258 kcdata_get_memory_addr_for_array(
259 kcdata_descriptor_t data
,
260 uint32_t type_of_element
,
261 uint32_t size_of_element
,
263 mach_vm_address_t
*user_addr
)
265 /* for arrays we record the number of padding bytes as the low-order 4 bits
266 * of the type field. KCDATA_TYPE_ARRAY_PAD{x} means x bytes of pad. */
267 uint64_t flags
= type_of_element
;
268 flags
= (flags
<< 32) | count
;
269 uint32_t total_size
= count
* size_of_element
;
270 uint32_t pad
= kcdata_calc_padding(total_size
);
272 return kcdata_get_memory_addr_with_flavor(data
, KCDATA_TYPE_ARRAY_PAD0
| pad
, total_size
, flags
, user_addr
);
276 * Routine: kcdata_add_container_marker
277 * Desc: Add a container marker in the buffer for type and identifier.
278 * params: data - pointer describing the crash info allocation
279 * header_type - one of (KCDATA_TYPE_CONTAINER_BEGIN ,KCDATA_TYPE_CONTAINER_END)
280 * container_type - type of data to be put. See kern_cdata.h for defined types
281 * identifier - unique identifier. This is required to match nested containers.
282 * returns: return value of kcdata_get_memory_addr()
286 kcdata_add_container_marker(
287 kcdata_descriptor_t data
,
288 uint32_t header_type
,
289 uint32_t container_type
,
292 mach_vm_address_t user_addr
;
294 assert(header_type
== KCDATA_TYPE_CONTAINER_END
|| header_type
== KCDATA_TYPE_CONTAINER_BEGIN
);
295 uint32_t data_size
= (header_type
== KCDATA_TYPE_CONTAINER_BEGIN
)? sizeof(uint32_t): 0;
296 kr
= kcdata_get_memory_addr_with_flavor(data
, header_type
, data_size
, identifier
, &user_addr
);
297 if (kr
!= KERN_SUCCESS
) {
302 kr
= kcdata_memcpy(data
, user_addr
, &container_type
, data_size
);
308 * Routine: kcdata_undo_addcontainer_begin
309 * Desc: call this after adding a container begin but before adding anything else to revert.
312 kcdata_undo_add_container_begin(kcdata_descriptor_t data
)
315 * the payload of a container begin is a single uint64_t. It is padded out
318 const mach_vm_address_t padded_payload_size
= 16;
319 data
->kcd_addr_end
-= sizeof(struct kcdata_item
) + padded_payload_size
;
321 if (!(data
->kcd_flags
& KCFLAG_NO_AUTO_ENDBUFFER
)) {
322 /* setup the end header as well */
323 return kcdata_write_buffer_end(data
);
330 * Routine: kcdata_memcpy
331 * Desc: a common function to copy data out based on either copyout or memcopy flags
332 * params: data - pointer describing the kcdata buffer
333 * dst_addr - destination address
334 * src_addr - source address
335 * size - size in bytes to copy.
336 * returns: KERN_NO_ACCESS if copyout fails.
340 kcdata_memcpy(kcdata_descriptor_t data
, mach_vm_address_t dst_addr
, const void *src_addr
, uint32_t size
)
342 if (data
->kcd_flags
& KCFLAG_USE_COPYOUT
) {
343 if (copyout(src_addr
, dst_addr
, size
)) {
344 return KERN_NO_ACCESS
;
347 memcpy((void *)dst_addr
, src_addr
, size
);
353 * Routine: kcdata_bzero
354 * Desc: zero out a portion of a kcdata buffer.
357 kcdata_bzero(kcdata_descriptor_t data
, mach_vm_address_t dst_addr
, uint32_t size
)
359 kern_return_t kr
= KERN_SUCCESS
;
360 if (data
->kcd_flags
& KCFLAG_USE_COPYOUT
) {
361 uint8_t zeros
[16] = {};
363 uint32_t block_size
= MIN(size
, 16);
364 kr
= copyout(&zeros
, dst_addr
, block_size
);
366 return KERN_NO_ACCESS
;
372 bzero((void*)dst_addr
, size
);
378 * Routine: kcdata_add_type_definition
379 * Desc: add type definition to kcdata buffer.
380 * see feature description in documentation above.
381 * params: data - pointer describing the kcdata buffer
382 * type_id - unique type identifier for this data
383 * type_name - a string of max KCDATA_DESC_MAXLEN size for name of type
384 * elements_array - address to descriptors for each field in struct
385 * elements_count - count of how many fields are there in struct.
386 * returns: return code from kcdata_get_memory_addr in case of failure.
390 kcdata_add_type_definition(
391 kcdata_descriptor_t data
,
394 struct kcdata_subtype_descriptor
*elements_array_addr
,
395 uint32_t elements_count
)
397 kern_return_t kr
= KERN_SUCCESS
;
398 struct kcdata_type_definition kc_type_definition
;
399 mach_vm_address_t user_addr
;
400 uint32_t total_size
= sizeof(struct kcdata_type_definition
);
401 bzero(&kc_type_definition
, sizeof(kc_type_definition
));
403 if (strlen(type_name
) >= KCDATA_DESC_MAXLEN
) {
404 return KERN_INVALID_ARGUMENT
;
406 strlcpy(&kc_type_definition
.kct_name
[0], type_name
, KCDATA_DESC_MAXLEN
);
407 kc_type_definition
.kct_num_elements
= elements_count
;
408 kc_type_definition
.kct_type_identifier
= type_id
;
410 total_size
+= elements_count
* sizeof(struct kcdata_subtype_descriptor
);
411 /* record number of padding bytes as lower 4 bits of flags */
412 if (KERN_SUCCESS
!= (kr
= kcdata_get_memory_addr_with_flavor(data
, KCDATA_TYPE_TYPEDEFINTION
, total_size
,
413 kcdata_calc_padding(total_size
), &user_addr
))) {
416 if (KERN_SUCCESS
!= (kr
= kcdata_memcpy(data
, user_addr
, (void *)&kc_type_definition
, sizeof(struct kcdata_type_definition
)))) {
419 user_addr
+= sizeof(struct kcdata_type_definition
);
420 if (KERN_SUCCESS
!= (kr
= kcdata_memcpy(data
, user_addr
, (void *)elements_array_addr
, elements_count
* sizeof(struct kcdata_subtype_descriptor
)))) {
428 /* Internal structs for convenience */
429 struct _uint64_with_description_data
{
430 char desc
[KCDATA_DESC_MAXLEN
];
434 struct _uint32_with_description_data
{
435 char desc
[KCDATA_DESC_MAXLEN
];
442 kcdata_add_uint64_with_description(kcdata_descriptor_t data_desc
, uint64_t data
, const char * description
)
444 if (strlen(description
) >= KCDATA_DESC_MAXLEN
) {
445 return KERN_INVALID_ARGUMENT
;
448 kern_return_t kr
= 0;
449 mach_vm_address_t user_addr
;
450 struct _uint64_with_description_data save_data
;
451 const uint64_t size_req
= sizeof(save_data
);
452 bzero(&save_data
, size_req
);
454 strlcpy(&(save_data
.desc
[0]), description
, sizeof(save_data
.desc
));
455 save_data
.data
= data
;
457 kr
= kcdata_get_memory_addr(data_desc
, KCDATA_TYPE_UINT64_DESC
, size_req
, &user_addr
);
458 if (kr
!= KERN_SUCCESS
) {
462 if (data_desc
->kcd_flags
& KCFLAG_USE_COPYOUT
) {
463 if (copyout(&save_data
, user_addr
, size_req
)) {
464 return KERN_NO_ACCESS
;
467 memcpy((void *)user_addr
, &save_data
, size_req
);
473 kcdata_add_uint32_with_description(
474 kcdata_descriptor_t data_desc
,
476 const char *description
)
478 assert(strlen(description
) < KCDATA_DESC_MAXLEN
);
479 if (strlen(description
) >= KCDATA_DESC_MAXLEN
) {
480 return KERN_INVALID_ARGUMENT
;
482 kern_return_t kr
= 0;
483 mach_vm_address_t user_addr
;
484 struct _uint32_with_description_data save_data
;
485 const uint64_t size_req
= sizeof(save_data
);
487 bzero(&save_data
, size_req
);
488 strlcpy(&(save_data
.desc
[0]), description
, sizeof(save_data
.desc
));
489 save_data
.data
= data
;
491 kr
= kcdata_get_memory_addr(data_desc
, KCDATA_TYPE_UINT32_DESC
, size_req
, &user_addr
);
492 if (kr
!= KERN_SUCCESS
) {
495 if (data_desc
->kcd_flags
& KCFLAG_USE_COPYOUT
) {
496 if (copyout(&save_data
, user_addr
, size_req
)) {
497 return KERN_NO_ACCESS
;
500 memcpy((void *)user_addr
, &save_data
, size_req
);
506 /* end buffer management api */