]>
Commit | Line | Data |
---|---|---|
3e170ce0 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 | #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> | |
40 | ||
39037602 A |
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); |
42 | ||
3e170ce0 | 43 | /* |
39037602 A |
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. | |
3e170ce0 | 46 | * |
39037602 | 47 | * NOTE: This function will not give an accurate estimate for buffers that will |
0a7de745 | 48 | * contain unknown types (those with string descriptions). |
3e170ce0 | 49 | */ |
0a7de745 A |
50 | uint32_t |
51 | kcdata_estimate_required_buffer_size(uint32_t num_items, uint32_t payload_size) | |
39037602 A |
52 | { |
53 | /* | |
54 | * In the worst case each item will need (KCDATA_ALIGNMENT_SIZE - 1) padding | |
55 | */ | |
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); | |
3e170ce0 | 59 | |
39037602 A |
60 | return max_padding_bytes + item_description_bytes + begin_and_end_marker_bytes + payload_size; |
61 | } | |
3e170ce0 | 62 | |
0a7de745 A |
63 | kcdata_descriptor_t |
64 | kcdata_memory_alloc_init(mach_vm_address_t buffer_addr_p, unsigned data_type, unsigned size, unsigned flags) | |
3e170ce0 A |
65 | { |
66 | kcdata_descriptor_t data = NULL; | |
67 | mach_vm_address_t user_addr = 0; | |
68 | ||
69 | data = kalloc(sizeof(struct kcdata_descriptor)); | |
70 | if (data == NULL) { | |
71 | return NULL; | |
72 | } | |
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; | |
78 | ||
79 | /* Initialize the BEGIN header */ | |
0a7de745 | 80 | if (KERN_SUCCESS != kcdata_get_memory_addr(data, data_type, 0, &user_addr)) { |
3e170ce0 A |
81 | kcdata_memory_destroy(data); |
82 | return NULL; | |
83 | } | |
84 | ||
85 | return data; | |
86 | } | |
87 | ||
0a7de745 A |
88 | kern_return_t |
89 | kcdata_memory_static_init(kcdata_descriptor_t data, mach_vm_address_t buffer_addr_p, unsigned data_type, unsigned size, unsigned flags) | |
3e170ce0 A |
90 | { |
91 | mach_vm_address_t user_addr = 0; | |
92 | ||
93 | if (data == NULL) { | |
94 | return KERN_INVALID_ARGUMENT; | |
95 | } | |
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; | |
101 | ||
102 | /* Initialize the BEGIN header */ | |
103 | return kcdata_get_memory_addr(data, data_type, 0, &user_addr); | |
104 | } | |
105 | ||
0a7de745 A |
106 | void * |
107 | kcdata_memory_get_begin_addr(kcdata_descriptor_t data) | |
5ba3f43e A |
108 | { |
109 | if (data == NULL) { | |
110 | return NULL; | |
111 | } | |
112 | ||
113 | return (void *)data->kcd_addr_begin; | |
114 | } | |
115 | ||
0a7de745 A |
116 | uint64_t |
117 | kcdata_memory_get_used_bytes(kcdata_descriptor_t kcd) | |
3e170ce0 A |
118 | { |
119 | assert(kcd != NULL); | |
120 | return ((uint64_t)kcd->kcd_addr_end - (uint64_t)kcd->kcd_addr_begin) + sizeof(struct kcdata_item); | |
121 | } | |
122 | ||
123 | /* | |
124 | * Free up the memory associated with kcdata | |
125 | */ | |
0a7de745 A |
126 | kern_return_t |
127 | kcdata_memory_destroy(kcdata_descriptor_t data) | |
3e170ce0 A |
128 | { |
129 | if (!data) { | |
130 | return KERN_INVALID_ARGUMENT; | |
131 | } | |
132 | ||
133 | /* | |
134 | * data->kcd_addr_begin points to memory in not tracked by | |
135 | * kcdata lib. So not clearing that here. | |
136 | */ | |
137 | kfree(data, sizeof(struct kcdata_descriptor)); | |
138 | return KERN_SUCCESS; | |
139 | } | |
140 | ||
141 | ||
142 | ||
143 | /* | |
144 | * Routine: kcdata_get_memory_addr | |
145 | * Desc: get memory address in the userspace memory for corpse info | |
39037602 A |
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 | |
3e170ce0 A |
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(). | |
153 | */ | |
39037602 A |
154 | kern_return_t |
155 | kcdata_get_memory_addr(kcdata_descriptor_t data, uint32_t type, uint32_t size, mach_vm_address_t * user_addr) | |
3e170ce0 | 156 | { |
39037602 A |
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); | |
160 | } | |
161 | ||
162 | /* | |
163 | * Routine: kcdata_add_buffer_end | |
164 | * | |
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. | |
168 | * | |
169 | * params: data - pointer describing the crash info allocation | |
170 | */ | |
171 | ||
172 | kern_return_t | |
173 | kcdata_write_buffer_end(kcdata_descriptor_t data) | |
174 | { | |
175 | struct kcdata_item info; | |
176 | bzero(&info, sizeof(info)); | |
177 | info.type = KCDATA_TYPE_BUFFER_END; | |
178 | info.size = 0; | |
179 | return kcdata_memcpy(data, data->kcd_addr_end, &info, sizeof(info)); | |
3e170ce0 A |
180 | } |
181 | ||
182 | /* | |
183 | * Routine: kcdata_get_memory_addr_with_flavor | |
184 | * Desc: internal function with flags field. See documentation for kcdata_get_memory_addr for details | |
185 | */ | |
186 | ||
0a7de745 A |
187 | static kern_return_t |
188 | kcdata_get_memory_addr_with_flavor( | |
189 | kcdata_descriptor_t data, | |
190 | uint32_t type, | |
191 | uint32_t size, | |
192 | uint64_t flags, | |
193 | mach_vm_address_t *user_addr) | |
3e170ce0 | 194 | { |
d9a64523 | 195 | kern_return_t kr; |
3e170ce0 | 196 | struct kcdata_item info; |
3e170ce0 | 197 | |
a39ff7e2 | 198 | uint32_t orig_size = size; |
3e170ce0 | 199 | /* make sure 16 byte aligned */ |
d9a64523 A |
200 | uint32_t padding = kcdata_calc_padding(size); |
201 | size += padding; | |
a39ff7e2 A |
202 | uint32_t total_size = size + sizeof(info); |
203 | ||
204 | if (user_addr == NULL || data == NULL || total_size + sizeof(info) < orig_size) { | |
205 | return KERN_INVALID_ARGUMENT; | |
206 | } | |
3e170ce0 A |
207 | |
208 | bzero(&info, sizeof(info)); | |
39037602 A |
209 | info.type = type; |
210 | info.size = size; | |
211 | info.flags = flags; | |
3e170ce0 A |
212 | |
213 | /* check available memory, including trailer size for KCDATA_TYPE_BUFFER_END */ | |
a39ff7e2 | 214 | if (total_size + sizeof(info) > data->kcd_length || |
0a7de745 | 215 | data->kcd_length - (total_size + sizeof(info)) < data->kcd_addr_end - data->kcd_addr_begin) { |
3e170ce0 A |
216 | return KERN_RESOURCE_SHORTAGE; |
217 | } | |
218 | ||
d9a64523 | 219 | kr = kcdata_memcpy(data, data->kcd_addr_end, &info, sizeof(info)); |
0a7de745 | 220 | if (kr) { |
d9a64523 | 221 | return kr; |
0a7de745 | 222 | } |
3e170ce0 A |
223 | |
224 | data->kcd_addr_end += sizeof(info); | |
d9a64523 A |
225 | |
226 | if (padding) { | |
227 | kr = kcdata_bzero(data, data->kcd_addr_end + size - padding, padding); | |
0a7de745 | 228 | if (kr) { |
d9a64523 | 229 | return kr; |
0a7de745 | 230 | } |
d9a64523 A |
231 | } |
232 | ||
3e170ce0 A |
233 | *user_addr = data->kcd_addr_end; |
234 | data->kcd_addr_end += size; | |
235 | ||
39037602 A |
236 | if (!(data->kcd_flags & KCFLAG_NO_AUTO_ENDBUFFER)) { |
237 | /* setup the end header as well */ | |
238 | return kcdata_write_buffer_end(data); | |
3e170ce0 | 239 | } else { |
39037602 | 240 | return KERN_SUCCESS; |
3e170ce0 | 241 | } |
3e170ce0 A |
242 | } |
243 | ||
244 | /* | |
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(). | |
255 | */ | |
256 | ||
0a7de745 A |
257 | kern_return_t |
258 | kcdata_get_memory_addr_for_array( | |
259 | kcdata_descriptor_t data, | |
260 | uint32_t type_of_element, | |
261 | uint32_t size_of_element, | |
262 | uint32_t count, | |
263 | mach_vm_address_t *user_addr) | |
3e170ce0 | 264 | { |
39037602 A |
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; | |
3e170ce0 | 269 | uint32_t total_size = count * size_of_element; |
39037602 A |
270 | uint32_t pad = kcdata_calc_padding(total_size); |
271 | ||
272 | return kcdata_get_memory_addr_with_flavor(data, KCDATA_TYPE_ARRAY_PAD0 | pad, total_size, flags, user_addr); | |
3e170ce0 A |
273 | } |
274 | ||
275 | /* | |
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() | |
283 | */ | |
284 | ||
0a7de745 A |
285 | kern_return_t |
286 | kcdata_add_container_marker( | |
287 | kcdata_descriptor_t data, | |
288 | uint32_t header_type, | |
289 | uint32_t container_type, | |
290 | uint64_t identifier) | |
3e170ce0 A |
291 | { |
292 | mach_vm_address_t user_addr; | |
293 | kern_return_t kr; | |
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); | |
0a7de745 | 297 | if (kr != KERN_SUCCESS) { |
3e170ce0 | 298 | return kr; |
0a7de745 | 299 | } |
3e170ce0 | 300 | |
0a7de745 | 301 | if (data_size) { |
3e170ce0 | 302 | kr = kcdata_memcpy(data, user_addr, &container_type, data_size); |
0a7de745 | 303 | } |
3e170ce0 A |
304 | return kr; |
305 | } | |
306 | ||
39037602 A |
307 | /* |
308 | * Routine: kcdata_undo_addcontainer_begin | |
309 | * Desc: call this after adding a container begin but before adding anything else to revert. | |
310 | */ | |
311 | kern_return_t | |
312 | kcdata_undo_add_container_begin(kcdata_descriptor_t data) | |
313 | { | |
314 | /* | |
315 | * the payload of a container begin is a single uint64_t. It is padded out | |
316 | * to 16 bytes. | |
317 | */ | |
318 | const mach_vm_address_t padded_payload_size = 16; | |
319 | data->kcd_addr_end -= sizeof(struct kcdata_item) + padded_payload_size; | |
320 | ||
321 | if (!(data->kcd_flags & KCFLAG_NO_AUTO_ENDBUFFER)) { | |
322 | /* setup the end header as well */ | |
323 | return kcdata_write_buffer_end(data); | |
324 | } else { | |
325 | return KERN_SUCCESS; | |
326 | } | |
327 | } | |
328 | ||
3e170ce0 A |
329 | /* |
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. | |
337 | */ | |
338 | ||
0a7de745 A |
339 | kern_return_t |
340 | kcdata_memcpy(kcdata_descriptor_t data, mach_vm_address_t dst_addr, const void *src_addr, uint32_t size) | |
3e170ce0 A |
341 | { |
342 | if (data->kcd_flags & KCFLAG_USE_COPYOUT) { | |
0a7de745 | 343 | if (copyout(src_addr, dst_addr, size)) { |
3e170ce0 | 344 | return KERN_NO_ACCESS; |
0a7de745 | 345 | } |
3e170ce0 A |
346 | } else { |
347 | memcpy((void *)dst_addr, src_addr, size); | |
348 | } | |
349 | return KERN_SUCCESS; | |
350 | } | |
351 | ||
d9a64523 A |
352 | /* |
353 | * Routine: kcdata_bzero | |
354 | * Desc: zero out a portion of a kcdata buffer. | |
355 | */ | |
356 | kern_return_t | |
357 | kcdata_bzero(kcdata_descriptor_t data, mach_vm_address_t dst_addr, uint32_t size) | |
358 | { | |
359 | kern_return_t kr = KERN_SUCCESS; | |
360 | if (data->kcd_flags & KCFLAG_USE_COPYOUT) { | |
361 | uint8_t zeros[16] = {}; | |
362 | while (size) { | |
363 | uint32_t block_size = MIN(size, 16); | |
364 | kr = copyout(&zeros, dst_addr, block_size); | |
0a7de745 | 365 | if (kr) { |
d9a64523 | 366 | return KERN_NO_ACCESS; |
0a7de745 | 367 | } |
d9a64523 A |
368 | size -= block_size; |
369 | } | |
370 | return KERN_SUCCESS; | |
371 | } else { | |
372 | bzero((void*)dst_addr, size); | |
373 | return KERN_SUCCESS; | |
374 | } | |
375 | } | |
376 | ||
3e170ce0 A |
377 | /* |
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. | |
387 | */ | |
388 | ||
0a7de745 A |
389 | kern_return_t |
390 | kcdata_add_type_definition( | |
391 | kcdata_descriptor_t data, | |
392 | uint32_t type_id, | |
393 | char *type_name, | |
394 | struct kcdata_subtype_descriptor *elements_array_addr, | |
395 | uint32_t elements_count) | |
3e170ce0 A |
396 | { |
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); | |
39037602 | 401 | bzero(&kc_type_definition, sizeof(kc_type_definition)); |
3e170ce0 | 402 | |
0a7de745 | 403 | if (strlen(type_name) >= KCDATA_DESC_MAXLEN) { |
3e170ce0 | 404 | return KERN_INVALID_ARGUMENT; |
0a7de745 | 405 | } |
3e170ce0 A |
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; | |
409 | ||
410 | total_size += elements_count * sizeof(struct kcdata_subtype_descriptor); | |
39037602 A |
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, | |
0a7de745 | 413 | kcdata_calc_padding(total_size), &user_addr))) { |
3e170ce0 | 414 | return kr; |
0a7de745 A |
415 | } |
416 | if (KERN_SUCCESS != (kr = kcdata_memcpy(data, user_addr, (void *)&kc_type_definition, sizeof(struct kcdata_type_definition)))) { | |
3e170ce0 | 417 | return kr; |
0a7de745 | 418 | } |
3e170ce0 | 419 | user_addr += sizeof(struct kcdata_type_definition); |
0a7de745 | 420 | if (KERN_SUCCESS != (kr = kcdata_memcpy(data, user_addr, (void *)elements_array_addr, elements_count * sizeof(struct kcdata_subtype_descriptor)))) { |
3e170ce0 | 421 | return kr; |
0a7de745 | 422 | } |
3e170ce0 A |
423 | return kr; |
424 | } | |
425 | ||
426 | #pragma pack(4) | |
427 | ||
428 | /* Internal structs for convenience */ | |
429 | struct _uint64_with_description_data { | |
430 | char desc[KCDATA_DESC_MAXLEN]; | |
431 | uint64_t data; | |
432 | }; | |
433 | ||
434 | struct _uint32_with_description_data { | |
435 | char desc[KCDATA_DESC_MAXLEN]; | |
436 | uint32_t data; | |
437 | }; | |
438 | ||
439 | #pragma pack() | |
440 | ||
39037602 A |
441 | kern_return_t |
442 | kcdata_add_uint64_with_description(kcdata_descriptor_t data_desc, uint64_t data, const char * description) | |
3e170ce0 | 443 | { |
0a7de745 | 444 | if (strlen(description) >= KCDATA_DESC_MAXLEN) { |
3e170ce0 | 445 | return KERN_INVALID_ARGUMENT; |
0a7de745 | 446 | } |
3e170ce0 A |
447 | |
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); | |
453 | ||
454 | strlcpy(&(save_data.desc[0]), description, sizeof(save_data.desc)); | |
455 | save_data.data = data; | |
456 | ||
457 | kr = kcdata_get_memory_addr(data_desc, KCDATA_TYPE_UINT64_DESC, size_req, &user_addr); | |
0a7de745 | 458 | if (kr != KERN_SUCCESS) { |
3e170ce0 | 459 | return kr; |
0a7de745 | 460 | } |
3e170ce0 A |
461 | |
462 | if (data_desc->kcd_flags & KCFLAG_USE_COPYOUT) { | |
0a7de745 | 463 | if (copyout(&save_data, user_addr, size_req)) { |
3e170ce0 | 464 | return KERN_NO_ACCESS; |
0a7de745 | 465 | } |
3e170ce0 A |
466 | } else { |
467 | memcpy((void *)user_addr, &save_data, size_req); | |
468 | } | |
469 | return KERN_SUCCESS; | |
470 | } | |
471 | ||
0a7de745 A |
472 | kern_return_t |
473 | kcdata_add_uint32_with_description( | |
474 | kcdata_descriptor_t data_desc, | |
475 | uint32_t data, | |
476 | const char *description) | |
3e170ce0 A |
477 | { |
478 | assert(strlen(description) < KCDATA_DESC_MAXLEN); | |
0a7de745 | 479 | if (strlen(description) >= KCDATA_DESC_MAXLEN) { |
3e170ce0 | 480 | return KERN_INVALID_ARGUMENT; |
0a7de745 | 481 | } |
3e170ce0 A |
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); | |
486 | ||
487 | bzero(&save_data, size_req); | |
488 | strlcpy(&(save_data.desc[0]), description, sizeof(save_data.desc)); | |
489 | save_data.data = data; | |
490 | ||
491 | kr = kcdata_get_memory_addr(data_desc, KCDATA_TYPE_UINT32_DESC, size_req, &user_addr); | |
0a7de745 | 492 | if (kr != KERN_SUCCESS) { |
3e170ce0 | 493 | return kr; |
0a7de745 | 494 | } |
3e170ce0 | 495 | if (data_desc->kcd_flags & KCFLAG_USE_COPYOUT) { |
0a7de745 | 496 | if (copyout(&save_data, user_addr, size_req)) { |
3e170ce0 | 497 | return KERN_NO_ACCESS; |
0a7de745 | 498 | } |
3e170ce0 A |
499 | } else { |
500 | memcpy((void *)user_addr, &save_data, size_req); | |
501 | } | |
502 | return KERN_SUCCESS; | |
503 | } | |
504 | ||
505 | ||
506 | /* end buffer management api */ |