]>
Commit | Line | Data |
---|---|---|
b0d623f7 A |
1 | /* |
2 | * Copyright (c) 2008 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 | #include <string.h> | |
29 | ||
30 | #if !KERNEL | |
31 | #include <libkern/OSByteOrder.h> | |
32 | #endif | |
33 | ||
34 | #define DEBUG_ASSERT_COMPONENT_NAME_STRING "kxld" | |
35 | #include <AssertMacros.h> | |
36 | ||
37 | #include "kxld_array.h" | |
38 | #include "kxld_dict.h" | |
39 | #include "kxld_kext.h" | |
40 | #include "kxld_state.h" | |
41 | #include "kxld_sym.h" | |
42 | #include "kxld_symtab.h" | |
43 | #include "kxld_util.h" | |
44 | #include "kxld_vtable.h" | |
45 | ||
46 | #define LINK_STATE_MAGIC 0xF00DD00D | |
47 | #define CIGAM_ETATS_KNIL 0x0DD00DF0 | |
48 | ||
49 | #define LINK_STATE_MAGIC_64 0xCAFEF00D | |
50 | #define CIGAM_ETATS_KNIL_64 0x0DF0FECA | |
51 | ||
52 | #define LINK_STATE_VERSION 1 | |
53 | ||
54 | static kern_return_t init_string_index(KXLDDict *strings, KXLDArray *tmps, | |
55 | KXLDSymtabIterator *iter, const KXLDArray *vtables, u_int nsymentries, | |
56 | u_long *strsize); | |
57 | static kern_return_t add_string_to_index(KXLDDict *strings, const char *str, | |
58 | KXLDArray *tmps, u_int *tmpi, u_long *stroff); | |
59 | static kern_return_t create_link_state(u_char **_file, u_long *_filesize, | |
60 | const KXLDKext *kext, KXLDSymtabIterator *iter, const KXLDArray *vtables, | |
61 | KXLDDict *strings, u_int nsyms, u_int nsymentries, u_long strsize); | |
62 | static boolean_t state_is_32_bit(KXLDLinkStateHdr *state); | |
63 | ||
64 | #if KXLD_USER_OR_ILP32 | |
65 | static kern_return_t get_symbols_32(KXLDState *state, KXLDDict *defined_symbols, | |
66 | KXLDDict *obsolete_symbols); | |
67 | static kern_return_t copy_symbols_32(u_char *file, u_long *data_offset, | |
68 | KXLDSymtabIterator *iter, const KXLDDict *strings); | |
69 | static kern_return_t copy_vtables_32(u_char *file, u_long *header_offset, | |
70 | u_long *data_offset, const KXLDArray *vtables, const KXLDDict *strings); | |
71 | #endif /* KXLD_USER_OR_ILP32*/ | |
72 | #if KXLD_USER_OR_LP64 | |
73 | static kern_return_t get_symbols_64(KXLDState *state, KXLDDict *defined_symbols, | |
74 | KXLDDict *obsolete_symbols); | |
75 | static kern_return_t copy_symbols_64(u_char *file, u_long *data_offset, | |
76 | KXLDSymtabIterator *iter, const KXLDDict *strings); | |
77 | static kern_return_t copy_vtables_64(u_char *file, u_long *header_offset, | |
78 | u_long *data_offset, const KXLDArray *vtables, const KXLDDict *strings); | |
79 | #endif /* KXLD_USER_OR_ILP64 */ | |
80 | ||
81 | #if !KERNEL | |
82 | static boolean_t swap_link_state(u_char *state); | |
83 | static void swap_link_state_32(u_char *state); | |
84 | static void swap_link_state_64(u_char *state); | |
85 | static boolean_t unswap_link_state(u_char *state); | |
86 | static void unswap_link_state_32(u_char *state); | |
87 | static void unswap_link_state_64(u_char *state); | |
88 | static void swap_state_hdr(KXLDLinkStateHdr *state_hdr); | |
89 | static void swap_vtable_hdr(KXLDVTableHdr *vtable_hdr); | |
90 | static void swap_sym_entry_32(KXLDSymEntry32 *entry); | |
91 | static void swap_sym_entry_64(KXLDSymEntry64 *entry); | |
92 | #endif | |
93 | ||
94 | /******************************************************************************* | |
95 | *******************************************************************************/ | |
96 | kern_return_t | |
97 | kxld_state_init_from_file(KXLDState *state, u_char *file, | |
98 | KXLDArray *section_order __unused) | |
99 | { | |
100 | kern_return_t rval = KERN_FAILURE; | |
101 | KXLDLinkStateHdr *hdr = (KXLDLinkStateHdr *) file; | |
102 | #if KXLD_USER_OR_OBJECT | |
103 | KXLDSectionName *dstname = NULL; | |
104 | KXLDSectionName *srcname = NULL; | |
105 | #endif | |
106 | KXLDVTableHdr *vhdr = NULL; | |
107 | KXLDVTable *vtable = NULL; | |
108 | u_int i = 0; | |
109 | ||
110 | check(state); | |
111 | check(file); | |
112 | ||
113 | #if !KERNEL | |
114 | /* Swap the link state file to host byte order for as long this kxld_state | |
115 | * object owns the file. | |
116 | */ | |
117 | state->swap = swap_link_state(file); | |
118 | #endif | |
119 | require_action(hdr->magic == LINK_STATE_MAGIC || | |
120 | hdr->magic == LINK_STATE_MAGIC_64, | |
121 | finish, rval=KERN_FAILURE); | |
122 | ||
123 | state->file = file; | |
124 | ||
125 | #if KXLD_USER_OR_OBJECT | |
126 | if (section_order && !section_order->nitems && hdr->nsects) { | |
127 | rval = kxld_array_init(section_order, sizeof(*dstname), hdr->nsects); | |
128 | require_noerr(rval, finish); | |
129 | ||
130 | srcname = (KXLDSectionName *) (file + hdr->sectoff); | |
131 | for (i = 0; i < hdr->nsects; ++i, ++srcname) { | |
132 | dstname = kxld_array_get_item(section_order, i); | |
133 | memcpy(dstname, srcname, sizeof(*srcname)); | |
134 | } | |
135 | } | |
136 | #endif | |
137 | ||
138 | rval = kxld_array_init(&state->vtables, sizeof(*vtable), hdr->nvtables); | |
139 | require_noerr(rval, finish); | |
140 | ||
141 | vhdr = (KXLDVTableHdr *) (file + hdr->voff); | |
142 | for (i = 0; i < hdr->nvtables; ++i, ++vhdr) { | |
143 | vtable = kxld_array_get_item(&state->vtables, i); | |
144 | KXLD_3264_FUNC(kxld_is_32_bit(hdr->cputype), rval, | |
145 | kxld_vtable_init_from_link_state_32, | |
146 | kxld_vtable_init_from_link_state_64, | |
147 | vtable, file, vhdr); | |
148 | require_noerr(rval, finish); | |
149 | } | |
150 | ||
151 | rval = KERN_SUCCESS; | |
152 | ||
153 | finish: | |
154 | return rval; | |
155 | } | |
156 | ||
157 | /******************************************************************************* | |
158 | *******************************************************************************/ | |
159 | void | |
160 | kxld_state_clear(KXLDState *state) | |
161 | { | |
162 | KXLDVTable *vtable = NULL; | |
163 | u_int i = 0; | |
164 | ||
165 | check(state); | |
166 | ||
167 | #if !KERNEL | |
168 | /* We use kxld_state objects to wrap the link state files. Whenever the | |
169 | * file is wrapped by a kxld_state object, the file is kept in host byte | |
170 | * order. Once we are done, we must return it to target byte order. | |
171 | */ | |
172 | if (state->swap) (void)unswap_link_state(state->file); | |
173 | #endif | |
174 | ||
175 | state->file = NULL; | |
176 | state->swap = FALSE; | |
177 | for (i = 0; i < state->vtables.nitems; ++i) { | |
178 | vtable = kxld_array_get_item(&state->vtables, i); | |
179 | kxld_vtable_clear(vtable); | |
180 | } | |
181 | kxld_array_reset(&state->vtables); | |
182 | } | |
183 | ||
184 | /******************************************************************************* | |
185 | *******************************************************************************/ | |
186 | void | |
187 | kxld_state_deinit(KXLDState *state) | |
188 | { | |
189 | KXLDVTable *vtable = NULL; | |
190 | u_int i = 0; | |
191 | ||
192 | check(state); | |
193 | ||
194 | #if !KERNEL | |
195 | if (state->file && state->swap) (void)unswap_link_state(state->file); | |
196 | #endif | |
197 | ||
198 | for (i = 0; i < state->vtables.maxitems; ++i) { | |
199 | vtable = kxld_array_get_slot(&state->vtables, i); | |
200 | kxld_vtable_deinit(vtable); | |
201 | } | |
202 | kxld_array_deinit(&state->vtables); | |
203 | bzero(state, sizeof(*state)); | |
204 | } | |
205 | ||
206 | /******************************************************************************* | |
207 | *******************************************************************************/ | |
208 | u_int | |
209 | kxld_state_get_num_symbols(KXLDState *state) | |
210 | { | |
211 | KXLDLinkStateHdr *hdr = (KXLDLinkStateHdr *) state->file; | |
212 | ||
213 | return hdr->nsyms; | |
214 | } | |
215 | ||
216 | /******************************************************************************* | |
217 | *******************************************************************************/ | |
218 | kern_return_t | |
219 | kxld_state_get_symbols(KXLDState *state, KXLDDict *defined_symbols, | |
220 | KXLDDict *obsolete_symbols) | |
221 | { | |
222 | KXLDLinkStateHdr * hdr = (KXLDLinkStateHdr *) state->file; | |
223 | kern_return_t rval = KERN_FAILURE; | |
224 | ||
225 | check(state); | |
226 | check(defined_symbols); | |
227 | check(obsolete_symbols); | |
228 | ||
229 | require_action(hdr->magic == LINK_STATE_MAGIC || | |
230 | hdr->magic == LINK_STATE_MAGIC_64, | |
231 | finish, rval=KERN_FAILURE); | |
232 | ||
233 | KXLD_3264_FUNC(state_is_32_bit(hdr), rval, | |
234 | get_symbols_32, get_symbols_64, | |
235 | state, defined_symbols, obsolete_symbols); | |
236 | require_noerr(rval, finish); | |
237 | ||
238 | rval = KERN_SUCCESS; | |
239 | ||
240 | finish: | |
241 | return rval; | |
242 | } | |
243 | ||
244 | #if KXLD_USER_OR_ILP32 | |
245 | /******************************************************************************* | |
246 | *******************************************************************************/ | |
247 | static kern_return_t | |
248 | get_symbols_32(KXLDState *state, KXLDDict *defined_symbols, | |
249 | KXLDDict *obsolete_symbols) | |
250 | { | |
251 | kern_return_t rval = KERN_FAILURE; | |
252 | KXLDLinkStateHdr *hdr = (KXLDLinkStateHdr *) state->file; | |
253 | KXLDSymEntry32 *entry = NULL; | |
254 | const char *name = NULL; | |
255 | u_int i = 0; | |
256 | ||
257 | entry = (KXLDSymEntry32 *) (state->file + hdr->symoff); | |
258 | for (i = 0; i < hdr->nsyms; ++i, ++entry) { | |
259 | name = (const char *) (state->file + entry->nameoff); | |
260 | rval = kxld_dict_insert(defined_symbols, name, &entry->addr); | |
261 | require_noerr(rval, finish); | |
262 | ||
263 | if (entry->flags & KXLD_SYM_OBSOLETE) { | |
264 | rval = kxld_dict_insert(obsolete_symbols, name, &entry->addr); | |
265 | require_noerr(rval, finish); | |
266 | } | |
267 | } | |
268 | ||
269 | rval = KERN_SUCCESS; | |
270 | ||
271 | finish: | |
272 | return rval; | |
273 | } | |
274 | #endif /* KXLD_USER_OR_ILP32 */ | |
275 | ||
276 | #if KXLD_USER_OR_LP64 | |
277 | /******************************************************************************* | |
278 | *******************************************************************************/ | |
279 | static kern_return_t | |
280 | get_symbols_64(KXLDState *state, KXLDDict *defined_symbols, | |
281 | KXLDDict *obsolete_symbols) | |
282 | { | |
283 | kern_return_t rval = KERN_FAILURE; | |
284 | KXLDLinkStateHdr *hdr = (KXLDLinkStateHdr *) state->file; | |
285 | KXLDSymEntry64 *entry = NULL; | |
286 | const char *name = NULL; | |
287 | u_int i = 0; | |
288 | ||
289 | entry = (KXLDSymEntry64 *) (state->file + hdr->symoff); | |
290 | for (i = 0; i < hdr->nsyms; ++i, ++entry) { | |
291 | name = (const char *) (state->file + entry->nameoff); | |
292 | rval = kxld_dict_insert(defined_symbols, name, &entry->addr); | |
293 | require_noerr(rval, finish); | |
294 | ||
295 | if (entry->flags & KXLD_SYM_OBSOLETE) { | |
296 | rval = kxld_dict_insert(obsolete_symbols, name, &entry->addr); | |
297 | require_noerr(rval, finish); | |
298 | } | |
299 | } | |
300 | ||
301 | rval = KERN_SUCCESS; | |
302 | ||
303 | finish: | |
304 | return rval; | |
305 | } | |
306 | #endif /* KXLD_USER_OR_LP64 */ | |
307 | ||
308 | /******************************************************************************* | |
309 | *******************************************************************************/ | |
310 | u_int | |
311 | kxld_state_get_num_vtables(KXLDState *state) | |
312 | { | |
313 | return state->vtables.nitems; | |
314 | } | |
315 | ||
316 | /******************************************************************************* | |
317 | *******************************************************************************/ | |
318 | kern_return_t | |
319 | kxld_state_get_vtables(KXLDState *state, KXLDDict *patched_vtables) | |
320 | { | |
321 | kern_return_t rval = KERN_FAILURE; | |
322 | KXLDVTable *vtable = NULL; | |
323 | u_int i = 0; | |
324 | ||
325 | check(state); | |
326 | check(patched_vtables); | |
327 | ||
328 | for (i = 0; i < state->vtables.nitems; ++i) { | |
329 | vtable = kxld_array_get_item(&state->vtables, i); | |
330 | rval = kxld_dict_insert(patched_vtables, vtable->name, vtable); | |
331 | require_noerr(rval, finish); | |
332 | } | |
333 | ||
334 | rval = KERN_SUCCESS; | |
335 | ||
336 | finish: | |
337 | return rval; | |
338 | } | |
339 | ||
340 | /******************************************************************************* | |
341 | *******************************************************************************/ | |
342 | void | |
343 | kxld_state_get_cputype(const KXLDState *state, cpu_type_t *cputype, | |
344 | cpu_subtype_t *cpusubtype) | |
345 | { | |
346 | KXLDLinkStateHdr *hdr = (KXLDLinkStateHdr *) state->file; | |
347 | ||
348 | check(state); | |
349 | check(cputype); | |
350 | check(cpusubtype); | |
351 | ||
352 | *cputype = hdr->cputype; | |
353 | *cpusubtype = hdr->cpusubtype; | |
354 | } | |
355 | ||
356 | /******************************************************************************* | |
357 | *******************************************************************************/ | |
358 | kern_return_t | |
359 | kxld_state_export_kext_to_file(KXLDKext *kext, u_char **file, u_long *filesize, | |
360 | KXLDDict *strings, KXLDArray *tmps) | |
361 | { | |
362 | kern_return_t rval = KERN_FAILURE; | |
363 | KXLDSymtabIterator iter; | |
364 | const KXLDSymtab *symtab = NULL; | |
365 | const KXLDArray *vtables = NULL; | |
366 | const KXLDVTable *vtable = NULL; | |
367 | u_int nsyms = 0; | |
368 | u_int nsymentries = 0; | |
369 | u_int i = 0; | |
370 | u_long strsize = 0; | |
371 | ||
372 | check(kext); | |
373 | check(file); | |
374 | check(tmps); | |
375 | ||
376 | bzero(&iter, sizeof(iter)); | |
377 | ||
378 | /* Get the vtables and symbol tables from the kext */ | |
379 | ||
380 | kxld_kext_get_vtables(kext, &vtables); | |
381 | symtab = kxld_kext_get_symtab(kext); | |
382 | require_action(symtab, finish, rval=KERN_FAILURE); | |
383 | ||
384 | /* Count the number of symentries we'll need in the linkstate */ | |
385 | ||
386 | kxld_symtab_iterator_init(&iter, symtab, kxld_sym_is_exported, FALSE); | |
387 | ||
388 | nsyms = kxld_symtab_iterator_get_num_remaining(&iter); | |
389 | nsymentries = nsyms; | |
390 | for (i = 0; i < vtables->nitems; ++i) { | |
391 | vtable = kxld_array_get_item(vtables, i); | |
392 | nsymentries += vtable->entries.nitems; | |
393 | } | |
394 | ||
395 | /* Initialize the string index */ | |
396 | ||
397 | rval = init_string_index(strings, tmps, &iter, vtables, nsymentries, | |
398 | &strsize); | |
399 | require_noerr(rval, finish); | |
400 | ||
401 | /* Create the linkstate file */ | |
402 | ||
403 | rval = create_link_state(file, filesize, kext, &iter, vtables, | |
404 | strings, nsyms, nsymentries, strsize); | |
405 | require_noerr(rval, finish); | |
406 | ||
407 | /* Swap if necessary */ | |
408 | ||
409 | #if !KERNEL | |
410 | if (kxld_kext_target_needs_swap(kext)) unswap_link_state(*file); | |
411 | #endif /* !KERNEL */ | |
412 | ||
413 | rval = KERN_SUCCESS; | |
414 | ||
415 | finish: | |
416 | return rval; | |
417 | } | |
418 | ||
419 | /******************************************************************************* | |
420 | *******************************************************************************/ | |
421 | static kern_return_t | |
422 | init_string_index(KXLDDict *strings, KXLDArray *tmps, KXLDSymtabIterator *iter, | |
423 | const KXLDArray *vtables, u_int nsymentries, u_long *_strsize) | |
424 | { | |
425 | kern_return_t rval = KERN_SUCCESS; | |
426 | const KXLDSym *sym = NULL; | |
427 | const KXLDVTable *vtable = NULL; | |
428 | const KXLDVTableEntry *ventry = NULL; | |
429 | u_long strsize = 0; | |
430 | u_int tmpi = 0; | |
431 | u_int i = 0; | |
432 | u_int j = 0; | |
433 | ||
434 | check(strings); | |
435 | check(tmps); | |
436 | check(iter); | |
437 | check(vtables); | |
438 | check(_strsize); | |
439 | ||
440 | *_strsize = 0; | |
441 | ||
442 | /* Initialize the string dictionary and string offset array */ | |
443 | ||
444 | rval = kxld_dict_init(strings, kxld_dict_string_hash, kxld_dict_string_cmp, | |
445 | nsymentries); | |
446 | require_noerr(rval, finish); | |
447 | ||
448 | rval = kxld_array_init(tmps, sizeof(u_long), nsymentries); | |
449 | require_noerr(rval, finish); | |
450 | ||
451 | /* Add all of the strings from the symbol table to the dictionary */ | |
452 | ||
453 | kxld_symtab_iterator_reset(iter); | |
454 | while ((sym = kxld_symtab_iterator_get_next(iter))) { | |
455 | rval = add_string_to_index(strings, sym->name, tmps, &tmpi, &strsize); | |
456 | require_noerr(rval, finish); | |
457 | } | |
458 | ||
459 | /* Add all of the strings from the vtables entries to the dictionary */ | |
460 | ||
461 | for (i = 0; i < vtables->nitems; ++i) { | |
462 | vtable = kxld_array_get_item(vtables, i); | |
463 | rval = add_string_to_index(strings, vtable->name, tmps, &tmpi, &strsize); | |
464 | require_noerr(rval, finish); | |
465 | ||
466 | for (j = 0; j < vtable->entries.nitems; ++j) { | |
467 | ventry = kxld_array_get_item(&vtable->entries, j); | |
468 | if (ventry->patched.name) { | |
469 | rval = add_string_to_index(strings, ventry->patched.name, tmps, | |
470 | &tmpi, &strsize); | |
471 | require_noerr(rval, finish); | |
472 | } | |
473 | } | |
474 | } | |
475 | ||
476 | *_strsize = strsize; | |
477 | rval = KERN_SUCCESS; | |
478 | ||
479 | finish: | |
480 | return rval; | |
481 | } | |
482 | ||
483 | /******************************************************************************* | |
484 | *******************************************************************************/ | |
485 | static kern_return_t | |
486 | add_string_to_index(KXLDDict *strings, const char *str, KXLDArray *tmps, | |
487 | u_int *tmpi, u_long *stroff) | |
488 | { | |
489 | kern_return_t rval = KERN_FAILURE; | |
490 | u_long *tmpp = NULL; | |
491 | ||
492 | if (!kxld_dict_find(strings, str)) { | |
493 | tmpp = kxld_array_get_item(tmps, (*tmpi)++); | |
494 | *tmpp = *stroff; | |
495 | ||
496 | rval = kxld_dict_insert(strings, str, tmpp); | |
497 | require_noerr(rval, finish); | |
498 | ||
499 | *stroff += strlen(str) + 1; | |
500 | } | |
501 | ||
502 | rval = KERN_SUCCESS; | |
503 | ||
504 | finish: | |
505 | return rval; | |
506 | } | |
507 | ||
508 | /******************************************************************************* | |
509 | *******************************************************************************/ | |
510 | static boolean_t | |
511 | state_is_32_bit(KXLDLinkStateHdr *state) | |
512 | { | |
513 | return kxld_is_32_bit(state->cputype); | |
514 | } | |
515 | ||
516 | /******************************************************************************* | |
517 | *******************************************************************************/ | |
518 | static kern_return_t | |
519 | create_link_state(u_char **_file, u_long *_filesize, const KXLDKext *kext, | |
520 | KXLDSymtabIterator *iter, const KXLDArray *vtables, KXLDDict *strings, | |
521 | u_int nsyms, u_int nsymentries, u_long strsize) | |
522 | { | |
523 | kern_return_t rval = KERN_SUCCESS; | |
524 | u_char *file = NULL; | |
525 | KXLDLinkStateHdr *hdr = NULL; | |
526 | KXLDDictIterator striter; | |
527 | #if KXLD_USER_OR_OBJECT | |
528 | KXLDSectionName *dstsectname = NULL; | |
529 | KXLDSectionName *srcsectname = NULL; | |
530 | const KXLDArray *section_order = NULL; | |
531 | u_int i = 0; | |
532 | #endif | |
533 | const char *name = NULL; | |
534 | char *dstname = NULL; | |
535 | u_long *stridx = 0; | |
536 | u_long hsize = 0; | |
537 | u_long dsize = 0; | |
538 | u_long filesize = 0; | |
539 | u_long hoff = 0; | |
540 | u_long doff = 0; | |
541 | u_long stroff = 0; | |
542 | ||
543 | check(_file); | |
544 | check(iter); | |
545 | check(vtables); | |
546 | check(strings); | |
547 | ||
548 | *_file = NULL; | |
549 | *_filesize = 0; | |
550 | ||
551 | #if KXLD_USER_OR_OBJECT | |
552 | section_order = kxld_kext_get_section_order(kext); | |
553 | #endif | |
554 | ||
555 | /* Calculate header and data size */ | |
556 | ||
557 | hsize = sizeof(KXLDLinkStateHdr); | |
558 | hsize += vtables->nitems * sizeof(KXLDVTableHdr); | |
559 | #if KXLD_USER_OR_OBJECT | |
560 | if (section_order) { | |
561 | hsize += section_order->nitems * sizeof(KXLDSectionName); | |
562 | } | |
563 | #endif | |
564 | ||
565 | if (kxld_kext_is_32_bit(kext)) { | |
566 | dsize = nsymentries * sizeof(KXLDSymEntry32); | |
567 | } else { | |
568 | dsize = nsymentries * sizeof(KXLDSymEntry64); | |
569 | } | |
570 | ||
571 | filesize = hsize + dsize + strsize; | |
572 | ||
573 | hoff = 0; | |
574 | doff = hsize; | |
575 | stroff = hsize + dsize; | |
576 | ||
577 | /* Allocate the link state */ | |
578 | ||
579 | file = kxld_alloc_pageable(filesize); | |
580 | require_action(file, finish, rval=KERN_RESOURCE_SHORTAGE); | |
581 | ||
582 | /* Initialize link state header */ | |
583 | ||
584 | hdr = (KXLDLinkStateHdr *) file; | |
585 | hoff += sizeof(*hdr); | |
586 | ||
587 | if (state_is_32_bit(hdr)) { | |
588 | hdr->magic = LINK_STATE_MAGIC; | |
589 | } else { | |
590 | hdr->magic = LINK_STATE_MAGIC_64; | |
591 | } | |
592 | hdr->version = LINK_STATE_VERSION; | |
593 | kxld_kext_get_cputype(kext, &hdr->cputype, &hdr->cpusubtype); | |
594 | hdr->nsects = 0; | |
595 | hdr->nvtables = vtables->nitems; | |
596 | hdr->nsyms = nsyms; | |
597 | ||
598 | #if KXLD_USER_OR_OBJECT | |
599 | if (section_order) { | |
600 | hdr->nsects = section_order->nitems; | |
601 | hdr->sectoff = (uint32_t) hoff; | |
602 | ||
603 | dstsectname = (KXLDSectionName *) (file + hoff); | |
604 | hoff += section_order->nitems * sizeof(*dstsectname); | |
605 | ||
606 | for (i = 0; i < section_order->nitems; ++i, ++dstsectname) { | |
607 | srcsectname = kxld_array_get_item(section_order, i); | |
608 | memcpy(dstsectname, srcsectname, sizeof(*srcsectname)); | |
609 | } | |
610 | } | |
611 | #endif | |
612 | ||
613 | hdr->voff = (uint32_t) hoff; | |
614 | hdr->symoff = (uint32_t) doff; | |
615 | ||
616 | /* Copy strings */ | |
617 | ||
618 | kxld_dict_iterator_init(&striter, strings); | |
619 | kxld_dict_iterator_get_next(&striter, (const void **) &name, (void **) &stridx); | |
620 | while (name) { | |
621 | *stridx += stroff; | |
622 | dstname = (char *) (file + *stridx); | |
623 | strlcpy(dstname, name, filesize - *stridx); | |
624 | kxld_dict_iterator_get_next(&striter, (const void **) &name, (void **) &stridx); | |
625 | } | |
626 | ||
627 | /* Copy symbols */ | |
628 | ||
629 | KXLD_3264_FUNC(state_is_32_bit(hdr), rval, | |
630 | copy_symbols_32, copy_symbols_64, | |
631 | file, &doff, iter, strings); | |
632 | require_noerr(rval, finish); | |
633 | ||
634 | /* Copy vtables */ | |
635 | ||
636 | KXLD_3264_FUNC(state_is_32_bit(hdr), rval, | |
637 | copy_vtables_32, copy_vtables_64, | |
638 | file, &hoff, &doff, vtables, strings); | |
639 | require_noerr(rval, finish); | |
640 | ||
641 | *_file = file; | |
642 | *_filesize = filesize; | |
643 | file = NULL; | |
644 | rval = KERN_SUCCESS; | |
645 | ||
646 | finish: | |
647 | ||
648 | if (file) { | |
649 | kxld_page_free(file, filesize); | |
650 | file = NULL; | |
651 | } | |
652 | ||
653 | return rval; | |
654 | } | |
655 | ||
656 | #if KXLD_USER_OR_ILP32 | |
657 | /******************************************************************************* | |
658 | *******************************************************************************/ | |
659 | static kern_return_t | |
660 | copy_symbols_32(u_char *file, u_long *data_offset, KXLDSymtabIterator *iter, | |
661 | const KXLDDict *strings) | |
662 | { | |
663 | kern_return_t rval = KERN_FAILURE; | |
664 | KXLDSymEntry32 *symentry = NULL; | |
665 | const KXLDSym *sym = NULL; | |
666 | u_long *stridx = 0; | |
667 | ||
668 | kxld_symtab_iterator_reset(iter); | |
669 | while ((sym = kxld_symtab_iterator_get_next(iter))) { | |
670 | symentry = (KXLDSymEntry32 *) (file + *data_offset); | |
671 | stridx = kxld_dict_find(strings, sym->name); | |
672 | require_action(stridx, finish, rval=KERN_FAILURE); | |
673 | ||
674 | /* Initialize the symentry */ | |
675 | ||
676 | symentry->nameoff = (uint32_t) *stridx; | |
677 | if (sym->predicates.is_thumb) { | |
678 | symentry->addr = (uint32_t) sym->link_addr | 1; | |
679 | } else { | |
680 | symentry->addr = (uint32_t) sym->link_addr; | |
681 | } | |
682 | symentry->flags = 0; | |
683 | ||
684 | /* Set any flags */ | |
685 | ||
686 | symentry->flags |= (kxld_sym_is_obsolete(sym)) ? KXLD_SYM_OBSOLETE : 0; | |
687 | ||
688 | *data_offset += sizeof(*symentry); | |
689 | } | |
690 | ||
691 | rval = KERN_SUCCESS; | |
692 | ||
693 | finish: | |
694 | return rval; | |
695 | } | |
696 | #endif /* KXLD_USER_OR_ILP32 */ | |
697 | ||
698 | #if KXLD_USER_OR_LP64 | |
699 | /******************************************************************************* | |
700 | *******************************************************************************/ | |
701 | static kern_return_t | |
702 | copy_symbols_64(u_char *file, u_long *data_offset, KXLDSymtabIterator *iter, | |
703 | const KXLDDict *strings) | |
704 | { | |
705 | kern_return_t rval = KERN_FAILURE; | |
706 | KXLDSymEntry64 *symentry = NULL; | |
707 | const KXLDSym *sym = NULL; | |
708 | u_long *stridx = 0; | |
709 | ||
710 | kxld_symtab_iterator_reset(iter); | |
711 | while ((sym = kxld_symtab_iterator_get_next(iter))) { | |
712 | symentry = (KXLDSymEntry64 *) (file + *data_offset); | |
713 | stridx = kxld_dict_find(strings, sym->name); | |
714 | require_action(stridx, finish, rval=KERN_FAILURE); | |
715 | ||
716 | /* Initialize the symentry */ | |
717 | ||
718 | symentry->nameoff = (uint32_t) *stridx; | |
719 | symentry->addr = (uint64_t) sym->link_addr; | |
720 | symentry->flags = 0; | |
721 | ||
722 | /* Set any flags */ | |
723 | ||
724 | symentry->flags |= (kxld_sym_is_obsolete(sym)) ? KXLD_SYM_OBSOLETE : 0; | |
725 | ||
726 | *data_offset += sizeof(*symentry); | |
727 | } | |
728 | ||
729 | rval = KERN_SUCCESS; | |
730 | ||
731 | finish: | |
732 | return rval; | |
733 | } | |
734 | #endif /* KXLD_USER_OR_LP64 */ | |
735 | ||
736 | #if KXLD_USER_OR_ILP32 | |
737 | /******************************************************************************* | |
738 | *******************************************************************************/ | |
739 | static kern_return_t | |
740 | copy_vtables_32(u_char *file, u_long *header_offset, u_long *data_offset, | |
741 | const KXLDArray *vtables, const KXLDDict *strings) | |
742 | { | |
743 | kern_return_t rval = KERN_FAILURE; | |
744 | KXLDVTable *vtable = NULL; | |
745 | KXLDVTableHdr *vhdr = NULL; | |
746 | KXLDVTableEntry *ventry = NULL; | |
747 | KXLDSymEntry32 *symentry = NULL; | |
748 | u_long *stridx = 0; | |
749 | u_int i = 0; | |
750 | u_int j = 0; | |
751 | ||
752 | for (i = 0; i < vtables->nitems; ++i) { | |
753 | vtable = kxld_array_get_item(vtables, i); | |
754 | stridx = kxld_dict_find(strings, vtable->name); | |
755 | require_action(stridx, finish, rval=KERN_FAILURE); | |
756 | ||
757 | vhdr = (KXLDVTableHdr *) (file + *header_offset); | |
758 | vhdr->nameoff = (uint32_t) *stridx; | |
759 | vhdr->nentries = vtable->entries.nitems; | |
760 | vhdr->vtableoff = (uint32_t) (*data_offset); | |
761 | ||
762 | *header_offset += sizeof(*vhdr); | |
763 | ||
764 | for(j = 0; j < vtable->entries.nitems; ++j) { | |
765 | ||
766 | ventry = kxld_array_get_item(&vtable->entries, j); | |
767 | symentry = (KXLDSymEntry32 *) (file + *data_offset); | |
768 | ||
769 | if (ventry->patched.name) { | |
770 | stridx = kxld_dict_find(strings, ventry->patched.name); | |
771 | require_action(stridx, finish, rval=KERN_FAILURE); | |
772 | ||
773 | symentry->nameoff = (uint32_t) *stridx; | |
774 | symentry->addr = (uint32_t) ventry->patched.addr; | |
775 | } else { | |
776 | symentry->nameoff = 0; | |
777 | symentry->addr = 0; | |
778 | } | |
779 | ||
780 | *data_offset += sizeof(*symentry); | |
781 | } | |
782 | } | |
783 | ||
784 | rval = KERN_SUCCESS; | |
785 | ||
786 | finish: | |
787 | return rval; | |
788 | } | |
789 | #endif /* KXLD_USER_OR_ILP32 */ | |
790 | ||
791 | #if KXLD_USER_OR_LP64 | |
792 | /******************************************************************************* | |
793 | *******************************************************************************/ | |
794 | static kern_return_t | |
795 | copy_vtables_64(u_char *file, u_long *header_offset, u_long *data_offset, | |
796 | const KXLDArray *vtables, const KXLDDict *strings) | |
797 | { | |
798 | kern_return_t rval = KERN_FAILURE; | |
799 | KXLDVTable *vtable = NULL; | |
800 | KXLDVTableHdr *vhdr = NULL; | |
801 | KXLDVTableEntry *ventry = NULL; | |
802 | KXLDSymEntry64 *symentry = NULL; | |
803 | u_long *stridx = 0; | |
804 | u_int i = 0; | |
805 | u_int j = 0; | |
806 | ||
807 | for (i = 0; i < vtables->nitems; ++i) { | |
808 | vtable = kxld_array_get_item(vtables, i); | |
809 | stridx = kxld_dict_find(strings, vtable->name); | |
810 | require_action(stridx, finish, rval=KERN_FAILURE); | |
811 | ||
812 | vhdr = (KXLDVTableHdr *) (file + *header_offset); | |
813 | vhdr->nameoff = (uint32_t) *stridx; | |
814 | vhdr->nentries = vtable->entries.nitems; | |
815 | vhdr->vtableoff = (uint32_t) (*data_offset); | |
816 | ||
817 | *header_offset += sizeof(*vhdr); | |
818 | ||
819 | for(j = 0; j < vtable->entries.nitems; ++j) { | |
820 | ||
821 | ventry = kxld_array_get_item(&vtable->entries, j); | |
822 | symentry = (KXLDSymEntry64 *) (file + *data_offset); | |
823 | ||
824 | if (ventry->patched.name) { | |
825 | stridx = kxld_dict_find(strings, ventry->patched.name); | |
826 | require_action(stridx, finish, rval=KERN_FAILURE); | |
827 | ||
828 | symentry->nameoff = (uint32_t) *stridx; | |
829 | symentry->addr = (uint64_t) ventry->patched.addr; | |
830 | } else { | |
831 | symentry->nameoff = 0; | |
832 | symentry->addr = 0; | |
833 | } | |
834 | ||
835 | *data_offset += sizeof(*symentry); | |
836 | } | |
837 | } | |
838 | ||
839 | rval = KERN_SUCCESS; | |
840 | ||
841 | finish: | |
842 | return rval; | |
843 | } | |
844 | #endif /* KXLD_USER_OR_LP64 */ | |
845 | ||
846 | #if !KERNEL | |
847 | /******************************************************************************* | |
848 | *******************************************************************************/ | |
849 | static boolean_t | |
850 | swap_link_state(u_char *state) | |
851 | { | |
852 | KXLDLinkStateHdr *state_hdr = (KXLDLinkStateHdr *) state; | |
853 | ||
854 | if (state_hdr->magic == CIGAM_ETATS_KNIL) { | |
855 | swap_link_state_32(state); | |
856 | return TRUE; | |
857 | } else if (state_hdr->magic == CIGAM_ETATS_KNIL_64) { | |
858 | swap_link_state_64(state); | |
859 | return TRUE; | |
860 | } | |
861 | ||
862 | return FALSE; | |
863 | } | |
864 | ||
865 | /******************************************************************************* | |
866 | *******************************************************************************/ | |
867 | static void | |
868 | swap_link_state_32(u_char *state) | |
869 | { | |
870 | KXLDLinkStateHdr *state_hdr = NULL; | |
871 | KXLDVTableHdr *vtable_hdr = NULL; | |
872 | KXLDSymEntry32 *entry = NULL; | |
873 | u_int i = 0; | |
874 | u_int j = 0; | |
875 | ||
876 | state_hdr = (KXLDLinkStateHdr *) state; | |
877 | ||
878 | if (state_hdr->magic != CIGAM_ETATS_KNIL) return; | |
879 | ||
880 | /* Swap the header */ | |
881 | swap_state_hdr(state_hdr); | |
882 | ||
883 | /* Swap the symbols */ | |
884 | entry = (KXLDSymEntry32 *) (state + state_hdr->symoff); | |
885 | for (i = 0; i < state_hdr->nsyms; ++i, ++entry) { | |
886 | swap_sym_entry_32(entry); | |
887 | } | |
888 | ||
889 | /* Swap the vtable headers and entries */ | |
890 | vtable_hdr = (KXLDVTableHdr *) (state + state_hdr->voff); | |
891 | for (i = 0; i < state_hdr->nvtables; ++i, ++vtable_hdr) { | |
892 | swap_vtable_hdr(vtable_hdr); | |
893 | ||
894 | entry = (KXLDSymEntry32 *) (state + vtable_hdr->vtableoff); | |
895 | for (j = 0; j < vtable_hdr->nentries; ++j, ++entry) { | |
896 | swap_sym_entry_32(entry); | |
897 | } | |
898 | } | |
899 | } | |
900 | ||
901 | /******************************************************************************* | |
902 | *******************************************************************************/ | |
903 | static void | |
904 | swap_link_state_64(u_char *state) | |
905 | { | |
906 | KXLDLinkStateHdr *state_hdr = NULL; | |
907 | KXLDVTableHdr *vtable_hdr = NULL; | |
908 | KXLDSymEntry64 *entry = NULL; | |
909 | u_int i = 0; | |
910 | u_int j = 0; | |
911 | ||
912 | state_hdr = (KXLDLinkStateHdr *) state; | |
913 | ||
914 | if (state_hdr->magic != CIGAM_ETATS_KNIL_64) return; | |
915 | ||
916 | /* Swap the header */ | |
917 | swap_state_hdr(state_hdr); | |
918 | ||
919 | /* Swap the symbols */ | |
920 | entry = (KXLDSymEntry64 *) (state + state_hdr->symoff); | |
921 | for (i = 0; i < state_hdr->nsyms; ++i, ++entry) { | |
922 | swap_sym_entry_64(entry); | |
923 | } | |
924 | ||
925 | /* Swap the vtable headers and entries */ | |
926 | vtable_hdr = (KXLDVTableHdr *) (state + state_hdr->voff); | |
927 | for (i = 0; i < state_hdr->nvtables; ++i, ++vtable_hdr) { | |
928 | swap_vtable_hdr(vtable_hdr); | |
929 | ||
930 | entry = (KXLDSymEntry64 *) (state + vtable_hdr->vtableoff); | |
931 | for (j = 0; j < vtable_hdr->nentries; ++j, ++entry) { | |
932 | swap_sym_entry_64(entry); | |
933 | } | |
934 | } | |
935 | } | |
936 | ||
937 | /******************************************************************************* | |
938 | *******************************************************************************/ | |
939 | static boolean_t | |
940 | unswap_link_state(u_char *state) | |
941 | { | |
942 | KXLDLinkStateHdr *state_hdr = (KXLDLinkStateHdr *) state; | |
943 | ||
944 | if (state_hdr->magic == LINK_STATE_MAGIC) { | |
945 | unswap_link_state_32(state); | |
946 | return TRUE; | |
947 | } else if (state_hdr->magic == LINK_STATE_MAGIC_64) { | |
948 | unswap_link_state_64(state); | |
949 | return TRUE; | |
950 | } | |
951 | ||
952 | return FALSE; | |
953 | } | |
954 | ||
955 | /******************************************************************************* | |
956 | *******************************************************************************/ | |
957 | static void | |
958 | unswap_link_state_32(u_char *state) | |
959 | { | |
960 | KXLDLinkStateHdr *state_hdr = NULL; | |
961 | KXLDVTableHdr *vtable_hdr = NULL; | |
962 | KXLDSymEntry32 *entry = NULL; | |
963 | u_int i = 0; | |
964 | u_int j = 0; | |
965 | ||
966 | state_hdr = (KXLDLinkStateHdr *) state; | |
967 | ||
968 | if (state_hdr->magic != LINK_STATE_MAGIC) return; | |
969 | ||
970 | /* Unswap the vtables and their headers */ | |
971 | vtable_hdr = (KXLDVTableHdr *) (state + state_hdr->voff); | |
972 | for (i = 0; i < state_hdr->nvtables; ++i, ++vtable_hdr) { | |
973 | entry = (KXLDSymEntry32 *) (state + vtable_hdr->vtableoff); | |
974 | for (j = 0; j < vtable_hdr->nentries; ++j, ++entry) { | |
975 | swap_sym_entry_32(entry); | |
976 | } | |
977 | ||
978 | swap_vtable_hdr(vtable_hdr); | |
979 | } | |
980 | ||
981 | /* Unswap the symbols themselves */ | |
982 | entry = (KXLDSymEntry32 *) (state + state_hdr->symoff); | |
983 | for (i = 0; i < state_hdr->nsyms; ++i, ++entry) { | |
984 | swap_sym_entry_32(entry); | |
985 | } | |
986 | ||
987 | /* Unswap the header */ | |
988 | swap_state_hdr(state_hdr); | |
989 | } | |
990 | ||
991 | /******************************************************************************* | |
992 | *******************************************************************************/ | |
993 | static void | |
994 | unswap_link_state_64(u_char *state) | |
995 | { | |
996 | KXLDLinkStateHdr *state_hdr = NULL; | |
997 | KXLDVTableHdr *vtable_hdr = NULL; | |
998 | KXLDSymEntry64 *entry = NULL; | |
999 | u_int i = 0; | |
1000 | u_int j = 0; | |
1001 | ||
1002 | state_hdr = (KXLDLinkStateHdr *) state; | |
1003 | ||
1004 | if (state_hdr->magic != LINK_STATE_MAGIC_64) return; | |
1005 | ||
1006 | /* Unswap the vtables and their headers */ | |
1007 | vtable_hdr = (KXLDVTableHdr *) (state + state_hdr->voff); | |
1008 | for (i = 0; i < state_hdr->nvtables; ++i, ++vtable_hdr) { | |
1009 | entry = (KXLDSymEntry64 *) (state + vtable_hdr->vtableoff); | |
1010 | for (j = 0; j < vtable_hdr->nentries; ++j, ++entry) { | |
1011 | swap_sym_entry_64(entry); | |
1012 | } | |
1013 | ||
1014 | swap_vtable_hdr(vtable_hdr); | |
1015 | } | |
1016 | ||
1017 | /* Unswap the symbols themselves */ | |
1018 | entry = (KXLDSymEntry64 *) (state + state_hdr->symoff); | |
1019 | for (i = 0; i < state_hdr->nsyms; ++i, ++entry) { | |
1020 | swap_sym_entry_64(entry); | |
1021 | } | |
1022 | ||
1023 | /* Unswap the header */ | |
1024 | swap_state_hdr(state_hdr); | |
1025 | } | |
1026 | ||
1027 | /******************************************************************************* | |
1028 | *******************************************************************************/ | |
1029 | static void | |
1030 | swap_state_hdr(KXLDLinkStateHdr *state_hdr) | |
1031 | { | |
1032 | state_hdr->magic = OSSwapInt32(state_hdr->magic); | |
1033 | state_hdr->version = OSSwapInt32(state_hdr->version); | |
1034 | state_hdr->cputype = OSSwapInt32(state_hdr->cputype); | |
1035 | state_hdr->cpusubtype = OSSwapInt32(state_hdr->cpusubtype); | |
1036 | state_hdr->nsects = OSSwapInt32(state_hdr->nsects); | |
1037 | state_hdr->sectoff = OSSwapInt32(state_hdr->sectoff); | |
1038 | state_hdr->nvtables = OSSwapInt32(state_hdr->nvtables); | |
1039 | state_hdr->voff = OSSwapInt32(state_hdr->voff); | |
1040 | state_hdr->nsyms = OSSwapInt32(state_hdr->nsyms); | |
1041 | state_hdr->symoff = OSSwapInt32(state_hdr->symoff); | |
1042 | } | |
1043 | ||
1044 | /******************************************************************************* | |
1045 | *******************************************************************************/ | |
1046 | static void | |
1047 | swap_vtable_hdr(KXLDVTableHdr *vtable_hdr) | |
1048 | { | |
1049 | vtable_hdr->nameoff = OSSwapInt32(vtable_hdr->nameoff); | |
1050 | vtable_hdr->vtableoff = OSSwapInt32(vtable_hdr->vtableoff); | |
1051 | vtable_hdr->nentries = OSSwapInt32(vtable_hdr->nentries); | |
1052 | } | |
1053 | ||
1054 | /******************************************************************************* | |
1055 | *******************************************************************************/ | |
1056 | static void | |
1057 | swap_sym_entry_32(KXLDSymEntry32 *entry) | |
1058 | { | |
1059 | entry->nameoff = OSSwapInt32(entry->nameoff); | |
1060 | entry->addr = OSSwapInt32(entry->addr); | |
1061 | } | |
1062 | ||
1063 | /******************************************************************************* | |
1064 | *******************************************************************************/ | |
1065 | static void | |
1066 | swap_sym_entry_64(KXLDSymEntry64 *entry) | |
1067 | { | |
1068 | entry->nameoff = OSSwapInt32(entry->nameoff); | |
1069 | entry->addr = OSSwapInt64(entry->addr); | |
1070 | } | |
1071 | #endif /* !KERNEL */ | |
1072 |