]>
Commit | Line | Data |
---|---|---|
b0d623f7 A |
1 | /* |
2 | * Copyright (c) 2008 Apple Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
0a7de745 | 5 | * |
b0d623f7 A |
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. | |
0a7de745 | 14 | * |
b0d623f7 A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
0a7de745 | 17 | * |
b0d623f7 A |
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. | |
0a7de745 | 25 | * |
b0d623f7 A |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
27 | */ | |
28 | #include <string.h> | |
29 | #include <mach/vm_prot.h> | |
30 | #include <mach-o/loader.h> | |
31 | #include <sys/types.h> | |
32 | ||
33 | #if KERNEL | |
34 | #include <mach/vm_param.h> | |
35 | #else | |
36 | #include <mach/mach_init.h> | |
37 | #endif /* KERNEL */ | |
38 | ||
39 | #define DEBUG_ASSERT_COMPONENT_NAME_STRING "kxld" | |
40 | #include <AssertMacros.h> | |
41 | ||
316670eb | 42 | #include "kxld_reloc.h" |
b0d623f7 A |
43 | #include "kxld_sect.h" |
44 | #include "kxld_seg.h" | |
6d2010ae | 45 | #include "kxld_symtab.h" |
b0d623f7 A |
46 | #include "kxld_util.h" |
47 | ||
48 | #define MAX_SEGS 20 | |
49 | ||
50 | #define TEXT_SEG_PROT (VM_PROT_READ | VM_PROT_EXECUTE) | |
51 | #define DATA_SEG_PROT (VM_PROT_READ | VM_PROT_WRITE) | |
52 | ||
39037602 A |
53 | extern boolean_t isSplitKext; |
54 | extern boolean_t isOldInterface; | |
55 | ||
b0d623f7 A |
56 | #if KXLD_USER_OR_OBJECT |
57 | static kern_return_t reorder_sections(KXLDSeg *seg, KXLDArray *section_order); | |
0a7de745 | 58 | static void reorder_section(KXLDArray *sects, u_int *sect_reorder_index, |
b0d623f7 A |
59 | KXLDSect **reorder_buffer, u_int reorder_buffer_index); |
60 | #endif /* KXLD_USER_OR_OBJECT */ | |
61 | ||
62 | #if 0 | |
63 | static KXLDSeg * get_segment_by_name(KXLDArray *segarray, const char *name); | |
64 | #endif | |
65 | ||
66 | #if KXLD_USER_OR_ILP32 | |
67 | static kern_return_t seg_export_macho_header_32(const KXLDSeg *seg, u_char *buf, | |
68 | u_long *header_offset, u_long header_size, u_long data_offset); | |
69 | #endif | |
70 | #if KXLD_USER_OR_LP64 | |
71 | static kern_return_t seg_export_macho_header_64(const KXLDSeg *seg, u_char *buf, | |
72 | u_long *header_offset, u_long header_size, u_long data_offset); | |
73 | #endif | |
74 | ||
75 | static KXLDSect * get_sect_by_index(const KXLDSeg *seg, u_int idx); | |
76 | ||
77 | #if KXLD_USER_OR_ILP32 | |
78 | /******************************************************************************* | |
79 | *******************************************************************************/ | |
80 | kern_return_t | |
81 | kxld_seg_init_from_macho_32(KXLDSeg *seg, struct segment_command *src) | |
82 | { | |
0a7de745 A |
83 | kern_return_t rval = KERN_FAILURE; |
84 | check(seg); | |
85 | check(src); | |
b0d623f7 | 86 | |
0a7de745 A |
87 | strlcpy(seg->segname, src->segname, sizeof(seg->segname)); |
88 | seg->base_addr = src->vmaddr; | |
89 | seg->link_addr = src->vmaddr; | |
90 | seg->vmsize = src->vmsize; | |
91 | seg->fileoff = src->fileoff; | |
92 | seg->maxprot = src->maxprot; | |
93 | seg->initprot = src->initprot; | |
94 | seg->flags = src->flags; | |
b0d623f7 | 95 | |
0a7de745 A |
96 | rval = kxld_array_init(&seg->sects, sizeof(KXLDSect *), src->nsects); |
97 | require_noerr(rval, finish); | |
b0d623f7 | 98 | |
0a7de745 | 99 | rval = KERN_SUCCESS; |
b0d623f7 A |
100 | |
101 | finish: | |
0a7de745 | 102 | return rval; |
b0d623f7 A |
103 | } |
104 | #endif /* KXLD_USER_OR_ILP32 */ | |
105 | ||
106 | #if KXLD_USER_OR_LP64 | |
107 | /******************************************************************************* | |
108 | *******************************************************************************/ | |
109 | kern_return_t | |
110 | kxld_seg_init_from_macho_64(KXLDSeg *seg, struct segment_command_64 *src) | |
111 | { | |
0a7de745 A |
112 | kern_return_t rval = KERN_FAILURE; |
113 | check(seg); | |
114 | check(src); | |
115 | ||
116 | strlcpy(seg->segname, src->segname, sizeof(seg->segname)); | |
117 | seg->base_addr = src->vmaddr; | |
118 | seg->link_addr = src->vmaddr; | |
119 | seg->vmsize = src->vmsize; | |
120 | ||
121 | seg->fileoff = src->fileoff; | |
122 | seg->maxprot = src->maxprot; | |
123 | seg->initprot = src->initprot; | |
124 | seg->flags = src->flags; | |
125 | ||
126 | rval = kxld_array_init(&seg->sects, sizeof(KXLDSect *), src->nsects); | |
127 | require_noerr(rval, finish); | |
128 | ||
129 | rval = KERN_SUCCESS; | |
b0d623f7 A |
130 | |
131 | finish: | |
0a7de745 | 132 | return rval; |
b0d623f7 A |
133 | } |
134 | #endif /* KXLD_USER_OR_LP64 */ | |
135 | ||
136 | #if KXLD_USER_OR_OBJECT | |
137 | /******************************************************************************* | |
138 | *******************************************************************************/ | |
139 | kern_return_t | |
140 | kxld_seg_create_seg_from_sections(KXLDArray *segarray, KXLDArray *sectarray) | |
141 | { | |
0a7de745 A |
142 | kern_return_t rval = KERN_FAILURE; |
143 | KXLDSeg *seg = NULL; | |
144 | KXLDSect *sect = NULL; | |
145 | KXLDSect **sectp = NULL; | |
146 | u_int i = 0; | |
b0d623f7 | 147 | |
0a7de745 | 148 | /* Initialize the segment array to one segment */ |
b0d623f7 | 149 | |
0a7de745 A |
150 | rval = kxld_array_init(segarray, sizeof(KXLDSeg), 1); |
151 | require_noerr(rval, finish); | |
b0d623f7 | 152 | |
0a7de745 | 153 | /* Initialize the segment */ |
b0d623f7 | 154 | |
0a7de745 A |
155 | seg = kxld_array_get_item(segarray, 0); |
156 | seg->initprot = VM_PROT_ALL; | |
157 | seg->maxprot = VM_PROT_ALL; | |
158 | seg->link_addr = 0; | |
b0d623f7 | 159 | |
0a7de745 | 160 | /* Add the sections to the segment */ |
b0d623f7 | 161 | |
0a7de745 A |
162 | rval = kxld_array_init(&seg->sects, sizeof(KXLDSect *), sectarray->nitems); |
163 | require_noerr(rval, finish); | |
b0d623f7 | 164 | |
0a7de745 A |
165 | for (i = 0; i < sectarray->nitems; ++i) { |
166 | sect = kxld_array_get_item(sectarray, i); | |
167 | sectp = kxld_array_get_item(&seg->sects, i); | |
b0d623f7 | 168 | |
0a7de745 A |
169 | *sectp = sect; |
170 | } | |
b0d623f7 | 171 | |
0a7de745 | 172 | rval = KERN_SUCCESS; |
b0d623f7 | 173 | finish: |
0a7de745 | 174 | return rval; |
b0d623f7 A |
175 | } |
176 | ||
177 | /******************************************************************************* | |
178 | *******************************************************************************/ | |
179 | kern_return_t | |
180 | kxld_seg_finalize_object_segment(KXLDArray *segarray, KXLDArray *section_order, | |
181 | u_long hdrsize) | |
182 | { | |
0a7de745 A |
183 | kern_return_t rval = KERN_FAILURE; |
184 | KXLDSeg *seg = NULL; | |
185 | KXLDSect *sect = NULL; | |
186 | u_long sect_offset = 0; | |
187 | u_int i = 0; | |
188 | ||
189 | check(segarray); | |
190 | check(section_order); | |
191 | require_action(segarray->nitems == 1, finish, rval = KERN_FAILURE); | |
b0d623f7 | 192 | |
0a7de745 | 193 | seg = kxld_array_get_item(segarray, 0); |
b0d623f7 | 194 | |
0a7de745 | 195 | /* Reorder the sections */ |
b0d623f7 | 196 | |
0a7de745 A |
197 | rval = reorder_sections(seg, section_order); |
198 | require_noerr(rval, finish); | |
b0d623f7 | 199 | |
0a7de745 | 200 | /* Set the initial link address at the end of the header pages */ |
b0d623f7 | 201 | |
0a7de745 | 202 | seg->link_addr = kxld_round_page_cross_safe(hdrsize); |
b0d623f7 | 203 | |
0a7de745 | 204 | /* Fix up all of the section addresses */ |
b0d623f7 | 205 | |
0a7de745 A |
206 | sect_offset = (u_long) seg->link_addr; |
207 | for (i = 0; i < seg->sects.nitems; ++i) { | |
208 | sect = *(KXLDSect **)kxld_array_get_item(&seg->sects, i); | |
b0d623f7 | 209 | |
0a7de745 A |
210 | sect->link_addr = kxld_sect_align_address(sect, sect_offset); |
211 | sect_offset = (u_long) (sect->link_addr + sect->size); | |
212 | } | |
b0d623f7 | 213 | |
0a7de745 | 214 | /* Finish initializing the segment */ |
b0d623f7 | 215 | |
0a7de745 A |
216 | seg->vmsize = kxld_round_page_cross_safe(sect_offset) - seg->link_addr; |
217 | ||
218 | rval = KERN_SUCCESS; | |
b0d623f7 | 219 | finish: |
0a7de745 | 220 | return rval; |
b0d623f7 A |
221 | } |
222 | ||
223 | /******************************************************************************* | |
224 | * The legacy section ordering used by kld was based of the order of sections | |
225 | * in the kernel file. To achieve the same layout, we save the kernel's | |
226 | * section ordering as an array of section names when the kernel file itself | |
227 | * is linked. Then, when kexts are linked with the KXLD_LEGACY_LAYOUT flag, | |
228 | * we refer to the kernel's section layout to order the kext's sections. | |
229 | * | |
230 | * The algorithm below is as follows. We iterate through all of the kernel's | |
231 | * sections grouped by segment name, so that we are processing all of the __TEXT | |
232 | * sections, then all of the __DATA sections, etc. We then iterate through the | |
233 | * kext's sections with a similar grouping, looking for sections that match | |
234 | * the current kernel's section. In this way, we order all of the matching | |
235 | * kext sections in the order in which they appear in the kernel, and then place | |
236 | * all remaining kext sections at the end of the current segment grouping in | |
237 | * the order in which they originally appeared. Sections that only appear in | |
238 | * the kernel are not created. segments that only appear in the kext are | |
239 | * left in their original ordering. | |
240 | * | |
241 | * An example: | |
242 | * | |
243 | * Kernel sections: | |
244 | * __TEXT,__text | |
b0d623f7 A |
245 | * __TEXT,__const |
246 | * __DATA,__data | |
247 | * | |
248 | * Kext sections: | |
249 | * __TEXT,__const | |
250 | * __TEXT,__literal4 | |
251 | * __TEXT,__text | |
252 | * __DATA,__const | |
253 | * __DATA,__data | |
254 | * | |
255 | * Reordered kext sections: | |
256 | * __TEXT,__text | |
257 | * __TEXT,__const | |
258 | * __TEXT,__literal4 | |
259 | * __DATA,__data | |
260 | * __DATA,__const | |
261 | * | |
262 | * In the implementation below, we use a reorder buffer to hold pointers to the | |
263 | * sections of the current working segment. We scan this buffer looking for | |
264 | * matching sections, placing them in the segment's section index as we find them. | |
265 | * If this function must exit early, the segment's section index is left in an | |
266 | * unusable state. | |
267 | *******************************************************************************/ | |
268 | static kern_return_t | |
269 | reorder_sections(KXLDSeg *seg, KXLDArray *section_order) | |
270 | { | |
0a7de745 A |
271 | kern_return_t rval = KERN_FAILURE; |
272 | KXLDSect *sect = NULL; | |
273 | KXLDSect **reorder_buffer = NULL; | |
274 | KXLDSectionName *section_name = NULL; | |
275 | const char *segname = NULL; | |
276 | u_int sect_index = 0, legacy_index = 0, sect_reorder_index = 0; | |
277 | u_int i = 0, j = 0; | |
278 | u_int sect_start = 0, sect_end = 0, legacy_start = 0, legacy_end = 0; | |
279 | u_int nsects = 0; | |
280 | ||
281 | check(seg); | |
282 | check(section_order); | |
283 | ||
284 | /* Allocate the reorder buffer with enough space to hold all of the | |
285 | * sections. | |
286 | */ | |
287 | ||
288 | reorder_buffer = kxld_alloc( | |
289 | seg->sects.nitems * sizeof(*reorder_buffer)); | |
290 | require_action(reorder_buffer, finish, rval = KERN_RESOURCE_SHORTAGE); | |
291 | ||
292 | while (legacy_index < section_order->nitems) { | |
293 | /* Find the next group of sections with a common segment in the | |
294 | * section_order array. | |
295 | */ | |
296 | ||
297 | legacy_start = legacy_index++; | |
298 | legacy_end = legacy_index; | |
299 | ||
300 | section_name = kxld_array_get_item(section_order, legacy_start); | |
301 | segname = section_name->segname; | |
302 | while (legacy_index < section_order->nitems) { | |
303 | section_name = kxld_array_get_item(section_order, legacy_index); | |
304 | if (!streq_safe(segname, section_name->segname, | |
305 | sizeof(section_name->segname))) { | |
306 | break; | |
307 | } | |
308 | ||
309 | ++legacy_index; | |
310 | ++legacy_end; | |
311 | } | |
312 | ||
313 | /* Find a group of sections in the kext that match the current | |
314 | * section_order segment. | |
315 | */ | |
316 | ||
317 | sect_start = sect_index; | |
318 | sect_end = sect_index; | |
319 | ||
320 | while (sect_index < seg->sects.nitems) { | |
321 | sect = *(KXLDSect **) kxld_array_get_item(&seg->sects, sect_index); | |
322 | if (!streq_safe(segname, sect->segname, sizeof(sect->segname))) { | |
323 | break; | |
324 | } | |
325 | ||
326 | ++sect_index; | |
327 | ++sect_end; | |
328 | } | |
329 | nsects = sect_end - sect_start; | |
330 | ||
331 | if (!nsects) { | |
332 | continue; | |
333 | } | |
334 | ||
335 | /* Populate the reorder buffer with the current group of kext sections */ | |
336 | ||
337 | for (i = sect_start; i < sect_end; ++i) { | |
338 | reorder_buffer[i - sect_start] = | |
339 | *(KXLDSect **) kxld_array_get_item(&seg->sects, i); | |
340 | } | |
341 | ||
342 | /* For each section_order section, scan the reorder buffer for a matching | |
343 | * kext section. If one is found, copy it into the next slot in the | |
344 | * segment's section index. | |
345 | */ | |
346 | ||
347 | sect_reorder_index = sect_start; | |
348 | for (i = legacy_start; i < legacy_end; ++i) { | |
349 | section_name = kxld_array_get_item(section_order, i); | |
350 | sect = NULL; | |
351 | ||
352 | for (j = 0; j < nsects; ++j) { | |
353 | sect = reorder_buffer[j]; | |
354 | if (!sect) { | |
355 | continue; | |
356 | } | |
357 | ||
358 | if (streq_safe(section_name->sectname, sect->sectname, | |
359 | sizeof(section_name->sectname))) { | |
360 | break; | |
361 | } | |
362 | ||
363 | sect = NULL; | |
364 | } | |
365 | ||
366 | if (sect) { | |
367 | (void) reorder_section(&seg->sects, §_reorder_index, | |
368 | reorder_buffer, j); | |
369 | } | |
370 | } | |
371 | ||
372 | /* If any sections remain in the reorder buffer, they are not specified | |
373 | * in the section_order array, so append them to the section index in | |
374 | * in the order they are found. | |
375 | */ | |
376 | ||
377 | for (i = 0; i < nsects; ++i) { | |
378 | if (!reorder_buffer[i]) { | |
379 | continue; | |
380 | } | |
381 | reorder_section(&seg->sects, §_reorder_index, reorder_buffer, i); | |
382 | } | |
383 | } | |
384 | ||
385 | rval = KERN_SUCCESS; | |
b0d623f7 A |
386 | |
387 | finish: | |
388 | ||
0a7de745 A |
389 | if (reorder_buffer) { |
390 | kxld_free(reorder_buffer, seg->sects.nitems * sizeof(*reorder_buffer)); | |
391 | reorder_buffer = NULL; | |
392 | } | |
b0d623f7 | 393 | |
0a7de745 | 394 | return rval; |
b0d623f7 A |
395 | } |
396 | ||
397 | /******************************************************************************* | |
398 | *******************************************************************************/ | |
399 | static void | |
0a7de745 | 400 | reorder_section(KXLDArray *sects, u_int *sect_reorder_index, |
b0d623f7 A |
401 | KXLDSect **reorder_buffer, u_int reorder_buffer_index) |
402 | { | |
0a7de745 | 403 | KXLDSect **tmp = NULL; |
b0d623f7 | 404 | |
0a7de745 | 405 | tmp = kxld_array_get_item(sects, *sect_reorder_index); |
b0d623f7 | 406 | |
0a7de745 A |
407 | *tmp = reorder_buffer[reorder_buffer_index]; |
408 | reorder_buffer[reorder_buffer_index]->sectnum = *sect_reorder_index; | |
409 | reorder_buffer[reorder_buffer_index] = NULL; | |
b0d623f7 | 410 | |
0a7de745 | 411 | ++(*sect_reorder_index); |
b0d623f7 | 412 | } |
6d2010ae A |
413 | |
414 | /******************************************************************************* | |
415 | *******************************************************************************/ | |
416 | kern_return_t | |
417 | kxld_seg_init_linkedit(KXLDArray *segs) | |
418 | { | |
0a7de745 A |
419 | kern_return_t rval = KERN_FAILURE; |
420 | KXLDSeg *seg = NULL; | |
421 | KXLDSeg *le = NULL; | |
422 | ||
423 | rval = kxld_array_resize(segs, 2); | |
424 | require_noerr(rval, finish); | |
6d2010ae | 425 | |
0a7de745 A |
426 | seg = kxld_array_get_item(segs, 0); |
427 | le = kxld_array_get_item(segs, 1); | |
6d2010ae | 428 | |
0a7de745 A |
429 | strlcpy(le->segname, SEG_LINKEDIT, sizeof(le->segname)); |
430 | le->link_addr = kxld_round_page_cross_safe(seg->link_addr + seg->vmsize); | |
431 | le->maxprot = VM_PROT_ALL; | |
432 | le->initprot = VM_PROT_DEFAULT; | |
6d2010ae | 433 | |
0a7de745 | 434 | rval = KERN_SUCCESS; |
6d2010ae A |
435 | |
436 | finish: | |
0a7de745 | 437 | return rval; |
6d2010ae | 438 | } |
b0d623f7 A |
439 | #endif /* KXLD_USER_OR_OBJECT */ |
440 | ||
441 | /******************************************************************************* | |
442 | *******************************************************************************/ | |
443 | void | |
444 | kxld_seg_clear(KXLDSeg *seg) | |
445 | { | |
0a7de745 A |
446 | check(seg); |
447 | ||
448 | bzero(seg->segname, sizeof(seg->segname)); | |
449 | seg->base_addr = 0; | |
450 | seg->link_addr = 0; | |
451 | seg->vmsize = 0; | |
452 | seg->flags = 0; | |
453 | seg->maxprot = 0; | |
454 | seg->initprot = 0; | |
455 | ||
456 | /* Don't clear the individual sections here because kxld_kext.c will take | |
457 | * care of that. | |
458 | */ | |
459 | kxld_array_clear(&seg->sects); | |
b0d623f7 A |
460 | } |
461 | ||
462 | /******************************************************************************* | |
463 | *******************************************************************************/ | |
0a7de745 | 464 | void |
b0d623f7 A |
465 | kxld_seg_deinit(KXLDSeg *seg) |
466 | { | |
0a7de745 | 467 | check(seg); |
b0d623f7 | 468 | |
0a7de745 A |
469 | kxld_array_deinit(&seg->sects); |
470 | bzero(seg, sizeof(*seg)); | |
b0d623f7 A |
471 | } |
472 | ||
473 | /******************************************************************************* | |
474 | *******************************************************************************/ | |
0a7de745 | 475 | kxld_size_t |
b0d623f7 A |
476 | kxld_seg_get_vmsize(const KXLDSeg *seg) |
477 | { | |
0a7de745 A |
478 | check(seg); |
479 | ||
480 | return seg->vmsize; | |
b0d623f7 A |
481 | } |
482 | ||
483 | /******************************************************************************* | |
484 | *******************************************************************************/ | |
485 | u_long | |
486 | kxld_seg_get_macho_header_size(const KXLDSeg *seg, boolean_t is_32_bit) | |
487 | { | |
0a7de745 A |
488 | u_long size = 0; |
489 | ||
490 | check(seg); | |
491 | ||
492 | if (is_32_bit) { | |
493 | size += sizeof(struct segment_command); | |
494 | } else { | |
495 | size += sizeof(struct segment_command_64); | |
496 | } | |
497 | size += seg->sects.nitems * kxld_sect_get_macho_header_size(is_32_bit); | |
498 | ||
499 | return size; | |
b0d623f7 A |
500 | } |
501 | ||
502 | /******************************************************************************* | |
503 | *******************************************************************************/ | |
316670eb A |
504 | /* This is no longer used, but may be useful some day... */ |
505 | #if 0 | |
b0d623f7 A |
506 | u_long |
507 | kxld_seg_get_macho_data_size(const KXLDSeg *seg) | |
508 | { | |
0a7de745 A |
509 | u_long size = 0; |
510 | u_int i = 0; | |
511 | KXLDSect *sect = NULL; | |
b0d623f7 | 512 | |
0a7de745 | 513 | check(seg); |
b0d623f7 | 514 | |
0a7de745 A |
515 | for (i = 0; i < seg->sects.nitems; ++i) { |
516 | sect = get_sect_by_index(seg, i); | |
517 | size = (u_long) kxld_sect_align_address(sect, size); | |
518 | size += kxld_sect_get_macho_data_size(sect); | |
519 | } | |
b0d623f7 | 520 | |
0a7de745 | 521 | return kxld_round_page_cross_safe(size); |
b0d623f7 | 522 | } |
316670eb | 523 | #endif |
b0d623f7 A |
524 | |
525 | /******************************************************************************* | |
526 | *******************************************************************************/ | |
0a7de745 | 527 | static KXLDSect * |
b0d623f7 A |
528 | get_sect_by_index(const KXLDSeg *seg, u_int idx) |
529 | { | |
0a7de745 | 530 | check(seg); |
b0d623f7 | 531 | |
0a7de745 | 532 | return *(KXLDSect **) kxld_array_get_item(&seg->sects, idx); |
b0d623f7 A |
533 | } |
534 | ||
535 | /******************************************************************************* | |
536 | *******************************************************************************/ | |
537 | kern_return_t | |
538 | kxld_seg_export_macho_to_file_buffer(const KXLDSeg *seg, u_char *buf, | |
0a7de745 | 539 | u_long *header_offset, u_long header_size, |
b0d623f7 A |
540 | u_long *data_offset, u_long data_size, |
541 | boolean_t is_32_bit) | |
542 | { | |
0a7de745 A |
543 | kern_return_t rval = KERN_FAILURE; |
544 | KXLDSect *sect = NULL; | |
545 | u_long base_data_offset = *data_offset; | |
546 | u_int i = 0; | |
547 | struct segment_command *hdr32 = | |
548 | (struct segment_command *) ((void *) (buf + *header_offset)); | |
549 | struct segment_command_64 *hdr64 = | |
550 | (struct segment_command_64 *) ((void *) (buf + *header_offset)); | |
b0d623f7 | 551 | |
0a7de745 A |
552 | check(seg); |
553 | check(buf); | |
554 | check(header_offset); | |
555 | check(data_offset); | |
b0d623f7 | 556 | |
0a7de745 | 557 | /* Write out the header */ |
b0d623f7 | 558 | |
0a7de745 A |
559 | KXLD_3264_FUNC(is_32_bit, rval, |
560 | seg_export_macho_header_32, seg_export_macho_header_64, | |
561 | seg, buf, header_offset, header_size, *data_offset); | |
562 | require_noerr(rval, finish); | |
b0d623f7 | 563 | |
0a7de745 | 564 | /* Write out each section */ |
b0d623f7 | 565 | |
0a7de745 A |
566 | for (i = 0; i < seg->sects.nitems; ++i) { |
567 | sect = get_sect_by_index(seg, i); | |
b0d623f7 | 568 | |
0a7de745 A |
569 | rval = kxld_sect_export_macho_to_file_buffer(sect, buf, header_offset, |
570 | header_size, data_offset, data_size, is_32_bit); | |
571 | require_noerr(rval, finish); | |
572 | } | |
b0d623f7 | 573 | |
0a7de745 | 574 | /* Update the filesize */ |
b0d623f7 | 575 | |
0a7de745 A |
576 | if (is_32_bit) { |
577 | hdr32->filesize = (uint32_t) (*data_offset - base_data_offset); | |
578 | } else { | |
579 | hdr64->filesize = (uint64_t) (*data_offset - base_data_offset); | |
580 | } | |
b0d623f7 | 581 | |
0a7de745 | 582 | *data_offset = (u_long)kxld_round_page_cross_safe(*data_offset); |
b0d623f7 | 583 | |
0a7de745 | 584 | rval = KERN_SUCCESS; |
b0d623f7 A |
585 | |
586 | finish: | |
0a7de745 | 587 | return rval; |
b0d623f7 A |
588 | } |
589 | ||
39037602 | 590 | |
b0d623f7 A |
591 | /******************************************************************************* |
592 | *******************************************************************************/ | |
593 | kern_return_t | |
39037602 | 594 | kxld_seg_export_macho_to_vm(const KXLDSeg *seg, |
0a7de745 A |
595 | u_char *buf, |
596 | u_long *header_offset, | |
597 | u_long header_size, | |
598 | u_long data_size, | |
599 | kxld_addr_t file_link_addr, | |
600 | boolean_t is_32_bit) | |
b0d623f7 | 601 | { |
0a7de745 A |
602 | kern_return_t rval = KERN_FAILURE; |
603 | KXLDSect * sect = NULL; | |
604 | ||
605 | // data_offset is used to set fileoff field in segment header | |
606 | u_long data_offset; | |
607 | u_int i = 0; | |
608 | ||
609 | check(seg); | |
610 | check(buf); | |
611 | check(header_offset); | |
b0d623f7 | 612 | |
0a7de745 | 613 | data_offset = (u_long) (seg->link_addr - file_link_addr); |
b0d623f7 | 614 | |
0a7de745 | 615 | /* Write out the header */ |
b0d623f7 | 616 | |
0a7de745 A |
617 | KXLD_3264_FUNC(is_32_bit, rval, |
618 | seg_export_macho_header_32, seg_export_macho_header_64, | |
619 | seg, | |
620 | buf, | |
621 | header_offset, header_size, data_offset); | |
622 | require_noerr(rval, finish); | |
b0d623f7 | 623 | |
0a7de745 | 624 | /* Write out each section */ |
b0d623f7 | 625 | |
0a7de745 A |
626 | for (i = 0; i < seg->sects.nitems; ++i) { |
627 | sect = get_sect_by_index(seg, i); | |
b0d623f7 | 628 | |
0a7de745 A |
629 | rval = kxld_sect_export_macho_to_vm(sect, buf, header_offset, |
630 | header_size, file_link_addr, data_size, is_32_bit); | |
631 | require_noerr(rval, finish); | |
632 | } | |
b0d623f7 | 633 | |
0a7de745 | 634 | rval = KERN_SUCCESS; |
b0d623f7 A |
635 | |
636 | finish: | |
0a7de745 | 637 | return rval; |
b0d623f7 A |
638 | } |
639 | ||
640 | #if KXLD_USER_OR_ILP32 | |
641 | /******************************************************************************* | |
642 | *******************************************************************************/ | |
643 | static kern_return_t | |
644 | seg_export_macho_header_32(const KXLDSeg *seg, u_char *buf, | |
645 | u_long *header_offset, u_long header_size, u_long data_offset) | |
646 | { | |
0a7de745 A |
647 | kern_return_t rval = KERN_FAILURE; |
648 | struct segment_command *seghdr = NULL; | |
649 | ||
650 | check(seg); | |
651 | check(buf); | |
652 | check(header_offset); | |
653 | ||
654 | require_action(sizeof(*seghdr) <= header_size - *header_offset, finish, | |
655 | rval = KERN_FAILURE); | |
656 | seghdr = (struct segment_command *) ((void *) (buf + *header_offset)); | |
657 | *header_offset += sizeof(*seghdr); | |
658 | ||
659 | seghdr->cmd = LC_SEGMENT; | |
660 | seghdr->cmdsize = (uint32_t) sizeof(*seghdr); | |
661 | seghdr->cmdsize += | |
662 | (uint32_t) (seg->sects.nitems * kxld_sect_get_macho_header_size(TRUE)); | |
663 | strlcpy(seghdr->segname, seg->segname, sizeof(seghdr->segname)); | |
664 | seghdr->vmaddr = (uint32_t) seg->link_addr; | |
665 | seghdr->vmsize = (uint32_t) seg->vmsize; | |
666 | seghdr->fileoff = (uint32_t) data_offset; | |
667 | seghdr->filesize = (uint32_t) seg->vmsize; | |
668 | seghdr->maxprot = seg->maxprot; | |
669 | seghdr->initprot = seg->initprot; | |
670 | seghdr->nsects = seg->sects.nitems; | |
671 | seghdr->flags = 0; | |
b0d623f7 | 672 | |
39037602 | 673 | #if SPLIT_KEXTS_DEBUG |
0a7de745 A |
674 | { |
675 | kxld_log(kKxldLogLinking, kKxldLogErr, | |
676 | "segname %s seghdr %p vmaddr %p vmsize 0x%02X %u fileoff 0x%02X %u <%s>", | |
677 | seg->segname[0] ? seg->segname : "none", | |
678 | (void *) seghdr, | |
679 | (void *) ((uint64_t)seghdr->vmaddr), | |
680 | seghdr->vmsize, | |
681 | seghdr->vmsize, | |
682 | seghdr->fileoff, | |
683 | seghdr->fileoff, | |
684 | __func__); | |
685 | } | |
39037602 | 686 | #endif |
0a7de745 A |
687 | |
688 | rval = KERN_SUCCESS; | |
b0d623f7 A |
689 | |
690 | finish: | |
0a7de745 | 691 | return rval; |
b0d623f7 A |
692 | } |
693 | #endif /* KXLD_USER_OR_ILP32 */ | |
694 | ||
0a7de745 | 695 | #if KXLD_USER_OR_LP64 |
b0d623f7 A |
696 | /******************************************************************************* |
697 | *******************************************************************************/ | |
698 | static kern_return_t | |
699 | seg_export_macho_header_64(const KXLDSeg *seg, u_char *buf, | |
700 | u_long *header_offset, u_long header_size, u_long data_offset) | |
701 | { | |
0a7de745 A |
702 | kern_return_t rval = KERN_FAILURE; |
703 | struct segment_command_64 *seghdr = NULL; | |
b0d623f7 | 704 | |
0a7de745 A |
705 | check(seg); |
706 | check(buf); | |
707 | check(header_offset); | |
708 | ||
709 | require_action(sizeof(*seghdr) <= header_size - *header_offset, finish, | |
710 | rval = KERN_FAILURE); | |
b0d623f7 | 711 | |
39037602 | 712 | #if SPLIT_KEXTS_DEBUG |
0a7de745 A |
713 | { |
714 | struct mach_header_64 *mach; | |
715 | ||
716 | mach = (struct mach_header_64 *) ((void *) buf); | |
717 | ||
718 | if (mach->magic != MH_MAGIC_64) { | |
719 | kxld_log(kKxldLogLinking, kKxldLogErr, | |
720 | "bad macho header at %p <%s>", | |
721 | (void *) mach, __func__); | |
722 | goto finish; | |
723 | } | |
724 | } | |
39037602 | 725 | #endif |
0a7de745 A |
726 | |
727 | seghdr = (struct segment_command_64 *) ((void *) (buf + *header_offset)); | |
728 | *header_offset += sizeof(*seghdr); | |
729 | ||
730 | seghdr->cmd = LC_SEGMENT_64; | |
731 | seghdr->cmdsize = (uint32_t) sizeof(*seghdr); | |
732 | seghdr->cmdsize += | |
733 | (uint32_t) (seg->sects.nitems * kxld_sect_get_macho_header_size(FALSE)); | |
734 | strlcpy(seghdr->segname, seg->segname, sizeof(seghdr->segname)); | |
735 | seghdr->vmaddr = (uint64_t) seg->link_addr; | |
736 | seghdr->vmsize = (uint64_t) seg->vmsize; | |
737 | seghdr->fileoff = (uint64_t) data_offset; | |
738 | seghdr->filesize = (uint64_t) seg->vmsize; | |
739 | seghdr->maxprot = seg->maxprot; | |
740 | seghdr->initprot = seg->initprot; | |
741 | seghdr->nsects = seg->sects.nitems; | |
742 | seghdr->flags = 0; | |
b0d623f7 | 743 | |
39037602 | 744 | #if SPLIT_KEXTS_DEBUG |
0a7de745 A |
745 | { |
746 | kxld_log(kKxldLogLinking, kKxldLogErr, | |
747 | "%p >>> Start of %s seghdr (size %lu) <%s>", | |
748 | (void *) seghdr, | |
749 | seg->segname[0] ? seg->segname : "none", | |
750 | sizeof(*seghdr), | |
751 | __func__); | |
752 | kxld_log(kKxldLogLinking, kKxldLogErr, | |
753 | "%p <<< End of %s seghdr <%s>", | |
754 | (void *) ((u_char *)seghdr + sizeof(*seghdr)), | |
755 | seg->segname[0] ? seg->segname : "none", | |
756 | __func__); | |
757 | ||
758 | kxld_log(kKxldLogLinking, kKxldLogErr, | |
759 | "%s seghdr, cmdsize %d vmaddr %p vmsize %p %llu fileoff %p %llu <%s>", | |
760 | seg->segname[0] ? seg->segname : "none", | |
761 | seghdr->cmdsize, | |
762 | (void *) seghdr->vmaddr, | |
763 | (void *) seghdr->vmsize, | |
764 | seghdr->vmsize, | |
765 | (void *) seghdr->fileoff, | |
766 | seghdr->fileoff, | |
767 | __func__); | |
768 | } | |
39037602 A |
769 | #endif |
770 | ||
0a7de745 | 771 | rval = KERN_SUCCESS; |
b0d623f7 A |
772 | |
773 | finish: | |
0a7de745 | 774 | return rval; |
b0d623f7 A |
775 | } |
776 | #endif /* KXLD_USER_OR_LP64 */ | |
777 | ||
778 | /******************************************************************************* | |
779 | *******************************************************************************/ | |
780 | kern_return_t | |
781 | kxld_seg_add_section(KXLDSeg *seg, KXLDSect *sect) | |
782 | { | |
0a7de745 A |
783 | kern_return_t rval = KERN_FAILURE; |
784 | KXLDSect **sectp = NULL; | |
785 | u_int i; | |
786 | ||
787 | check(seg); | |
788 | check(sect); | |
789 | require_action(streq_safe(seg->segname, sect->segname, sizeof(seg->segname)), | |
790 | finish, rval = KERN_FAILURE); | |
791 | ||
792 | /* Add the section into the section index */ | |
793 | ||
794 | for (i = 0; i < seg->sects.nitems; ++i) { | |
795 | sectp = kxld_array_get_item(&seg->sects, i); | |
796 | if (NULL == *sectp) { | |
797 | *sectp = sect; | |
798 | break; | |
799 | } | |
800 | } | |
801 | require_action(i < seg->sects.nitems, finish, rval = KERN_FAILURE); | |
802 | ||
803 | rval = KERN_SUCCESS; | |
b0d623f7 A |
804 | |
805 | finish: | |
806 | ||
0a7de745 | 807 | return rval; |
b0d623f7 A |
808 | } |
809 | ||
810 | /******************************************************************************* | |
811 | *******************************************************************************/ | |
812 | kern_return_t | |
813 | kxld_seg_finish_init(KXLDSeg *seg) | |
814 | { | |
0a7de745 A |
815 | kern_return_t rval = KERN_FAILURE; |
816 | u_int i = 0; | |
817 | KXLDSect *sect = NULL; | |
818 | kxld_addr_t maxaddr = 0; | |
819 | kxld_size_t maxsize = 0; | |
820 | ||
821 | /* If we already have a size for this segment (e.g. from the mach-o load | |
822 | * command) then don't recalculate the segment size. This is safer since | |
823 | * when we recalculate we are making assumptions about page alignment and | |
824 | * padding that the kext mach-o file was built with. Better to trust the | |
825 | * macho-o info, if we have it. If we don't (i.e. vmsize == 0) then add up | |
826 | * the section sizes and take a best guess at page padding. | |
827 | */ | |
828 | if ((seg->vmsize == 0) && (seg->sects.nitems)) { | |
829 | for (i = 0; i < seg->sects.nitems; ++i) { | |
830 | sect = get_sect_by_index(seg, i); | |
831 | require_action(sect, finish, rval = KERN_FAILURE); | |
832 | if (sect->base_addr > maxaddr) { | |
833 | maxaddr = sect->base_addr; | |
834 | maxsize = sect->size; | |
835 | } | |
836 | } | |
837 | seg->vmsize = kxld_round_page_cross_safe(maxaddr + | |
838 | maxsize - seg->base_addr); | |
839 | } | |
840 | ||
841 | rval = KERN_SUCCESS; | |
842 | ||
b0d623f7 | 843 | finish: |
0a7de745 | 844 | return rval; |
b0d623f7 A |
845 | } |
846 | ||
847 | /******************************************************************************* | |
848 | *******************************************************************************/ | |
849 | void | |
850 | kxld_seg_set_vm_protections(KXLDSeg *seg, boolean_t strict_protections) | |
851 | { | |
0a7de745 A |
852 | if (strict_protections) { |
853 | if (!strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname))) { | |
854 | seg->initprot = TEXT_SEG_PROT; | |
855 | seg->maxprot = TEXT_SEG_PROT; | |
856 | } else { | |
857 | seg->initprot = DATA_SEG_PROT; | |
858 | seg->maxprot = DATA_SEG_PROT; | |
859 | } | |
860 | } else { | |
861 | seg->initprot = VM_PROT_ALL; | |
862 | seg->maxprot = VM_PROT_ALL; | |
863 | } | |
b0d623f7 A |
864 | } |
865 | ||
866 | /******************************************************************************* | |
867 | *******************************************************************************/ | |
868 | void | |
869 | kxld_seg_relocate(KXLDSeg *seg, kxld_addr_t link_addr) | |
870 | { | |
0a7de745 A |
871 | KXLDSect *sect = NULL; |
872 | u_int i = 0; | |
873 | splitKextLinkInfo * link_info = (splitKextLinkInfo *) link_addr; | |
874 | kxld_addr_t my_link_addr; | |
875 | ||
876 | if (isOldInterface) { | |
877 | seg->link_addr += link_addr; | |
878 | } else { | |
879 | if (isSplitKext) { | |
880 | // we have a split kext | |
881 | if (kxld_seg_is_text_seg(seg)) { | |
882 | // assumes this is the beginning of the kext | |
883 | my_link_addr = link_info->vmaddr_TEXT; | |
884 | seg->link_addr = my_link_addr; | |
885 | } else if (kxld_seg_is_text_exec_seg(seg)) { | |
886 | my_link_addr = link_info->vmaddr_TEXT_EXEC; | |
887 | seg->link_addr = my_link_addr; | |
888 | // vmaddr_TEXT_EXEC is the actual vmaddr for this segment so we need | |
889 | // to adjust for kxld_sect_relocate assuming the link addr is | |
890 | // the address of the kext (macho header in __TEXT) | |
891 | my_link_addr -= seg->base_addr; | |
892 | } else if (kxld_seg_is_data_seg(seg)) { | |
893 | my_link_addr = link_info->vmaddr_DATA; | |
894 | seg->link_addr = my_link_addr; | |
895 | // vmaddr_DATA is the actual vmaddr for this segment so we need | |
896 | // to adjust for kxld_sect_relocate assuming the link addr is | |
897 | // the address of the kext (macho header in __TEXT) | |
898 | my_link_addr -= seg->base_addr; | |
899 | } else if (kxld_seg_is_data_const_seg(seg)) { | |
900 | my_link_addr = link_info->vmaddr_DATA_CONST; | |
901 | seg->link_addr = my_link_addr; | |
902 | // vmaddr_DATA_CONST is the actual vmaddr for this segment so we need | |
903 | // to adjust for kxld_sect_relocate assuming the link addr is | |
904 | // the address of the kext (macho header in __TEXT) | |
905 | my_link_addr -= seg->base_addr; | |
906 | } else if (kxld_seg_is_llvm_cov_seg(seg)) { | |
907 | my_link_addr = link_info->vmaddr_LLVM_COV; | |
908 | seg->link_addr = my_link_addr; | |
909 | // vmaddr_LLVM_COV is the actual vmaddr for this segment so we need | |
910 | // to adjust for kxld_sect_relocate assuming the link addr is | |
911 | // the address of the kext (macho header in __TEXT) | |
912 | my_link_addr -= seg->base_addr; | |
913 | } else if (kxld_seg_is_linkedit_seg(seg)) { | |
914 | my_link_addr = link_info->vmaddr_LINKEDIT; | |
915 | seg->link_addr = my_link_addr; | |
916 | // vmaddr_DATA is the actual vmaddr for this segment so we need | |
917 | // to adjust for kxld_sect_relocate assuming the link addr is | |
918 | // the address of the kext (macho header in __TEXT) | |
919 | my_link_addr -= seg->base_addr; | |
920 | } else { | |
921 | kxld_log(kKxldLogLinking, kKxldLogErr, | |
922 | " not expecting this segment %s!!! <%s>", | |
923 | seg->segname[0] ? seg->segname : "none", | |
924 | __func__); | |
925 | my_link_addr = link_info->vmaddr_TEXT; | |
926 | seg->link_addr += my_link_addr; | |
927 | } | |
928 | } else { | |
929 | my_link_addr = link_info->vmaddr_TEXT; | |
930 | seg->link_addr += my_link_addr; | |
931 | } | |
932 | } | |
933 | ||
39037602 | 934 | #if SPLIT_KEXTS_DEBUG |
0a7de745 A |
935 | { |
936 | kxld_log(kKxldLogLinking, kKxldLogErr, | |
937 | "%p >>> Start of %s segment (vmsize %llu) <%s>)", | |
938 | (void *) seg->link_addr, | |
939 | seg->segname[0] ? seg->segname : "none", | |
940 | seg->vmsize, | |
941 | __func__); | |
942 | kxld_log(kKxldLogLinking, kKxldLogErr, | |
943 | "%p <<< End of %s segment <%s>", | |
944 | (void *) (seg->link_addr + seg->vmsize), | |
945 | seg->segname[0] ? seg->segname : "none", | |
946 | __func__); | |
947 | } | |
39037602 | 948 | #endif |
0a7de745 A |
949 | |
950 | for (i = 0; i < seg->sects.nitems; ++i) { | |
951 | sect = get_sect_by_index(seg, i); | |
952 | if (isOldInterface) { | |
953 | kxld_sect_relocate(sect, link_addr); | |
954 | } else { | |
955 | kxld_sect_relocate(sect, my_link_addr); | |
956 | } | |
957 | } | |
b0d623f7 A |
958 | } |
959 | ||
6d2010ae A |
960 | /******************************************************************************* |
961 | *******************************************************************************/ | |
0a7de745 A |
962 | void |
963 | kxld_seg_populate_linkedit(KXLDSeg *seg, const KXLDSymtab *symtab, boolean_t is_32_bit | |
316670eb A |
964 | #if KXLD_PIC_KEXTS |
965 | , const KXLDArray *locrelocs | |
966 | , const KXLDArray *extrelocs | |
967 | , boolean_t target_supports_slideable_kexts | |
968 | #endif /* KXLD_PIC_KEXTS */ | |
39037602 | 969 | , uint32_t splitinfolc_size |
0a7de745 | 970 | ) |
6d2010ae | 971 | { |
0a7de745 | 972 | u_long size = 0; |
316670eb | 973 | |
0a7de745 | 974 | size += kxld_symtab_get_macho_data_size(symtab, is_32_bit); |
316670eb A |
975 | |
976 | #if KXLD_PIC_KEXTS | |
0a7de745 A |
977 | if (target_supports_slideable_kexts) { |
978 | size += kxld_reloc_get_macho_data_size(locrelocs, extrelocs); | |
979 | } | |
980 | #endif /* KXLD_PIC_KEXTS */ | |
316670eb | 981 | |
0a7de745 A |
982 | // 0 unless this is a split kext |
983 | size += splitinfolc_size; | |
39037602 | 984 | |
0a7de745 | 985 | seg->vmsize = kxld_round_page_cross_safe(size); |
6d2010ae A |
986 | } |
987 | ||
39037602 | 988 | /******************************************************************************* |
0a7de745 | 989 | *******************************************************************************/ |
39037602 A |
990 | boolean_t |
991 | kxld_seg_is_split_seg(const KXLDSeg *seg) | |
992 | { | |
0a7de745 A |
993 | boolean_t result = FALSE; |
994 | ||
995 | check(seg); | |
996 | if (isSplitKext) { | |
997 | if (kxld_seg_is_data_seg(seg) || kxld_seg_is_linkedit_seg(seg) || | |
998 | kxld_seg_is_text_exec_seg(seg) || kxld_seg_is_data_const_seg(seg) || | |
999 | kxld_seg_is_llvm_cov_seg(seg)) { | |
1000 | result = TRUE; | |
1001 | } | |
1002 | } | |
1003 | ||
1004 | return result; | |
39037602 A |
1005 | } |
1006 | ||
1007 | boolean_t | |
1008 | kxld_seg_is_text_seg(const KXLDSeg *seg) | |
1009 | { | |
0a7de745 A |
1010 | boolean_t result = FALSE; |
1011 | ||
1012 | check(seg); | |
1013 | result = !strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)); | |
1014 | ||
1015 | return result; | |
39037602 A |
1016 | } |
1017 | ||
1018 | boolean_t | |
1019 | kxld_seg_is_text_exec_seg(const KXLDSeg *seg) | |
1020 | { | |
0a7de745 A |
1021 | boolean_t result = FALSE; |
1022 | ||
1023 | check(seg); | |
1024 | result = !strncmp(seg->segname, "__TEXT_EXEC", sizeof(seg->segname)); | |
1025 | ||
1026 | return result; | |
39037602 A |
1027 | } |
1028 | ||
1029 | boolean_t | |
1030 | kxld_seg_is_data_seg(const KXLDSeg *seg) | |
1031 | { | |
0a7de745 A |
1032 | boolean_t result = FALSE; |
1033 | ||
1034 | check(seg); | |
1035 | result = !strncmp(seg->segname, SEG_DATA, sizeof(seg->segname)); | |
1036 | ||
1037 | return result; | |
39037602 A |
1038 | } |
1039 | ||
1040 | boolean_t | |
1041 | kxld_seg_is_data_const_seg(const KXLDSeg *seg) | |
1042 | { | |
0a7de745 A |
1043 | boolean_t result = FALSE; |
1044 | ||
1045 | check(seg); | |
1046 | result = !strncmp(seg->segname, "__DATA_CONST", sizeof(seg->segname)); | |
1047 | ||
1048 | return result; | |
39037602 A |
1049 | } |
1050 | ||
1051 | boolean_t | |
1052 | kxld_seg_is_linkedit_seg(const KXLDSeg *seg) | |
1053 | { | |
0a7de745 A |
1054 | boolean_t result = FALSE; |
1055 | ||
1056 | check(seg); | |
1057 | result = !strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)); | |
1058 | ||
1059 | return result; | |
39037602 A |
1060 | } |
1061 | ||
813fb2f6 A |
1062 | boolean_t |
1063 | kxld_seg_is_llvm_cov_seg(const KXLDSeg *seg) | |
1064 | { | |
0a7de745 | 1065 | boolean_t result = FALSE; |
813fb2f6 | 1066 | |
0a7de745 A |
1067 | check(seg); |
1068 | result = !strncmp(seg->segname, "__LLVM_COV", sizeof(seg->segname)); | |
813fb2f6 | 1069 | |
0a7de745 | 1070 | return result; |
813fb2f6 | 1071 | } |