]> git.saurik.com Git - apple/xnu.git/blame - libkern/kxld/kxld_symtab.c
xnu-1504.9.17.tar.gz
[apple/xnu.git] / libkern / kxld / kxld_symtab.c
CommitLineData
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#include <mach-o/loader.h>
30#include <mach-o/nlist.h>
31#include <sys/queue.h>
32#include <sys/types.h>
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_sect.h"
40#include "kxld_sym.h"
41#include "kxld_symtab.h"
42#include "kxld_util.h"
43
44struct kxld_symtab {
45 KXLDArray syms;
46 KXLDDict cxx_index;
47 KXLDDict name_index;
48 char *strings;
49 u_int strsize;
50};
51
52/*******************************************************************************
53* Prototypes
54*******************************************************************************/
55
56static kern_return_t init_macho(KXLDSymtab *symtab, u_char *macho,
57 struct symtab_command *src, kxld_addr_t linkedit_offset, boolean_t is_32_bit)
58 __attribute__((nonnull));
59
60#if KXLD_USER_OR_ILP32
61static kern_return_t init_syms_32(KXLDSymtab *symtab, u_char *macho, u_long offset,
62 u_int nsyms);
63#endif
64#if KXLD_USER_OR_LP64
65static kern_return_t init_syms_64(KXLDSymtab *symtab, u_char *macho, u_long offset,
66 u_int nsyms);
67#endif
68
69static kern_return_t make_cxx_index(KXLDSymtab *symtab)
70 __attribute__((nonnull));
71static boolean_t sym_is_defined_cxx(const KXLDSym *sym);
72static kern_return_t make_name_index(KXLDSymtab *symtab)
73 __attribute__((nonnull));
74static boolean_t sym_is_name_indexed(const KXLDSym *sym);
75
76
77/*******************************************************************************
78*******************************************************************************/
79size_t
80kxld_symtab_sizeof()
81{
82 return sizeof(KXLDSymtab);
83}
84
85#if KXLD_USER_OR_ILP32
86/*******************************************************************************
87*******************************************************************************/
88kern_return_t
89kxld_symtab_init_from_macho_32(KXLDSymtab *symtab, u_char *macho,
90 struct symtab_command *src, kxld_addr_t linkedit_offset)
91{
92 return init_macho(symtab, macho, src, linkedit_offset, TRUE);
93}
94#endif /* KXLD_USER_ILP32 */
95
96#if KXLD_USER_OR_LP64
97/*******************************************************************************
98*******************************************************************************/
99kern_return_t
100kxld_symtab_init_from_macho_64(KXLDSymtab *symtab, u_char *macho,
101 struct symtab_command *src, kxld_addr_t linkedit_offset)
102{
103 return init_macho(symtab, macho, src, linkedit_offset, FALSE);
104}
105#endif /* KXLD_USER_OR_LP64 */
106
107/*******************************************************************************
108*******************************************************************************/
109static kern_return_t
110init_macho(KXLDSymtab *symtab, u_char *macho, struct symtab_command *src,
111 kxld_addr_t linkedit_offset, boolean_t is_32_bit __unused)
112{
113 kern_return_t rval = KERN_FAILURE;
114
115 check(symtab);
116 check(macho);
117 check(src);
118
119 /* Initialize the symbol array */
120
121 rval = kxld_array_init(&symtab->syms, sizeof(KXLDSym), src->nsyms);
122 require_noerr(rval, finish);
123
124 /* Initialize the string table */
125
126 symtab->strings = (char *) (macho + src->stroff + linkedit_offset);
127 symtab->strsize = src->strsize;
128
129 /* Initialize the symbols */
130
131 KXLD_3264_FUNC(is_32_bit, rval,
132 init_syms_32, init_syms_64,
133 symtab, macho, (u_long) (src->symoff + linkedit_offset), src->nsyms);
134 require_noerr(rval, finish);
135
136 /* Create the C++ index */
137
138 rval = make_cxx_index(symtab);
139 require_noerr(rval, finish);
140
141 /* Create the name index */
142
143 rval = make_name_index(symtab);
144 require_noerr(rval, finish);
145
146 /* Save the output */
147
148 rval = KERN_SUCCESS;
149
150finish:
151 return rval;
152}
153
154#if KXLD_USER_OR_ILP32
155/*******************************************************************************
156*******************************************************************************/
157static kern_return_t
158init_syms_32(KXLDSymtab *symtab, u_char *macho, u_long offset, u_int nsyms)
159{
160 kern_return_t rval = KERN_FAILURE;
161 KXLDSym *sym = NULL;
162 u_int i = 0;
163 struct nlist *src_syms = (struct nlist *) (macho + offset);
164
165 for (i = 0; i < nsyms; ++i) {
166 sym = kxld_array_get_item(&symtab->syms, i);
167 require_action(sym, finish, rval=KERN_FAILURE);
168
169 rval = kxld_sym_init_from_macho32(sym, symtab->strings, &src_syms[i]);
170 require_noerr(rval, finish);
171 }
172
173 rval = KERN_SUCCESS;
174
175finish:
176 return rval;
177}
178#endif /* KXLD_USER_OR_ILP32 */
179
180#if KXLD_USER_OR_LP64
181/*******************************************************************************
182*******************************************************************************/
183static kern_return_t
184init_syms_64(KXLDSymtab *symtab, u_char *macho, u_long offset, u_int nsyms)
185{
186 kern_return_t rval = KERN_FAILURE;
187 KXLDSym *sym = NULL;
188 u_int i = 0;
189 struct nlist_64 *src_syms = (struct nlist_64 *) (macho + offset);
190
191 for (i = 0; i < nsyms; ++i) {
192 sym = kxld_array_get_item(&symtab->syms, i);
193 require_action(sym, finish, rval=KERN_FAILURE);
194
195 rval = kxld_sym_init_from_macho64(sym, symtab->strings, &src_syms[i]);
196 require_noerr(rval, finish);
197 }
198
199 rval = KERN_SUCCESS;
200
201finish:
202 return rval;
203}
204#endif /* KXLD_USER_OR_LP64 */
205
206/*******************************************************************************
207*******************************************************************************/
208void
209kxld_symtab_iterator_init(KXLDSymtabIterator *iter, const KXLDSymtab *symtab,
210 KXLDSymPredicateTest test, boolean_t negate)
211{
212 check(iter);
213 check(symtab);
214 check(test);
215
216 iter->symtab = symtab;
217 iter->idx = 0;
218 iter->test = test;
219 iter->negate = negate;
220}
221
222/*******************************************************************************
223*******************************************************************************/
224void
225kxld_symtab_clear(KXLDSymtab *symtab)
226{
227 check(symtab);
228
229 kxld_array_clear(&symtab->syms);
230 kxld_dict_clear(&symtab->cxx_index);
231 kxld_dict_clear(&symtab->name_index);
232}
233
234/*******************************************************************************
235*******************************************************************************/
236void
237kxld_symtab_deinit(KXLDSymtab *symtab)
238{
239 check(symtab);
240
241 kxld_array_deinit(&symtab->syms);
242 kxld_dict_deinit(&symtab->cxx_index);
243 kxld_dict_deinit(&symtab->name_index);
244}
245
246/*******************************************************************************
247*******************************************************************************/
248u_int
249kxld_symtab_get_num_symbols(const KXLDSymtab *symtab)
250{
251 check(symtab);
252
253 return symtab->syms.nitems;
254}
255
256/*******************************************************************************
257*******************************************************************************/
258KXLDSym *
259kxld_symtab_get_symbol_by_index(const KXLDSymtab *symtab, u_int idx)
260{
261 check(symtab);
262
263 return kxld_array_get_item(&symtab->syms, idx);
264}
265
266/*******************************************************************************
267*******************************************************************************/
268KXLDSym *
269kxld_symtab_get_symbol_by_name(const KXLDSymtab *symtab, const char *name)
270{
271 check(symtab);
272 check(name);
273
274 return kxld_dict_find(&symtab->name_index, name);
275}
276
277/*******************************************************************************
278*******************************************************************************/
279KXLDSym *
280kxld_symtab_get_cxx_symbol_by_value(const KXLDSymtab *symtab, kxld_addr_t value)
281{
282 check(symtab);
283
284 /*
285 * value may hold a THUMB address (with bit 0 set to 1) but the index will
286 * have the real address (bit 0 set to 0). So if bit 0 is set here,
287 * we clear it (should impact no architectures but ARM).
288 */
289 kxld_addr_t v = value & ~1;
290
291 return kxld_dict_find(&symtab->cxx_index, &v);
292}
293
294/*******************************************************************************
295*******************************************************************************/
296kern_return_t
297kxld_symtab_get_sym_index(const KXLDSymtab *symtab, const KXLDSym *sym,
298 u_int *symindex)
299{
300 kern_return_t rval = KERN_FAILURE;
301
302 rval = kxld_array_get_index(&symtab->syms, sym, symindex);
303 require_noerr(rval, finish);
304
305 rval = KERN_SUCCESS;
306
307finish:
308 return rval;
309}
310
311/*******************************************************************************
312*******************************************************************************/
313u_long
314kxld_symtab_get_macho_header_size(void)
315{
316 return sizeof(struct symtab_command);
317}
318
319/*******************************************************************************
320*******************************************************************************/
321u_long
322kxld_symtab_get_macho_data_size(const KXLDSymtab *symtab,
323 boolean_t is_link_state, boolean_t is_32_bit)
324{
325 KXLDSymtabIterator iter;
326 KXLDSym *sym = NULL;
327 u_long size = 1; /* strtab start padding */
328 u_int nsyms = 0;
329
330 check(symtab);
331
332 if (is_link_state) {
333 kxld_symtab_iterator_init(&iter, symtab, kxld_sym_is_exported, FALSE);
334 } else {
335 kxld_symtab_iterator_init(&iter, symtab,
336 kxld_sym_is_defined_locally, FALSE);
337 }
338
339 while ((sym = kxld_symtab_iterator_get_next(&iter))) {
340 size += strlen(sym->name) + 1;
341 ++nsyms;
342 }
343
344 if (is_32_bit) {
345 size += nsyms * sizeof(struct nlist);
346 } else {
347 size += nsyms * sizeof(struct nlist_64);
348 }
349
350 return size;
351}
352
353/*******************************************************************************
354*******************************************************************************/
355kern_return_t
356kxld_symtab_export_macho(const KXLDSymtab *symtab, u_char *buf,
357 u_long *header_offset, u_long header_size,
358 u_long *data_offset, u_long data_size,
359 boolean_t is_link_state, boolean_t is_32_bit)
360{
361 kern_return_t rval = KERN_FAILURE;
362 KXLDSymtabIterator iter;
363 KXLDSym *sym = NULL;
364 struct symtab_command *symtabhdr = NULL;
365 u_char *nl = NULL;
366 u_long nlistsize = 0;
367 char *strtab = NULL;
368 u_long stroff = 1; /* strtab start padding */
369
370 check(symtab);
371 check(buf);
372 check(header_offset);
373 check(data_offset);
374
375 require_action(sizeof(*symtabhdr) <= header_size - *header_offset,
376 finish, rval=KERN_FAILURE);
377 symtabhdr = (struct symtab_command *) (buf + *header_offset);
378 *header_offset += sizeof(*symtabhdr);
379
380 /* Initialize the symbol table header */
381
382 symtabhdr->cmd = LC_SYMTAB;
383 symtabhdr->cmdsize = (uint32_t) sizeof(*symtabhdr);
384 symtabhdr->symoff = (uint32_t) *data_offset;
385 symtabhdr->strsize = 1; /* strtab start padding */
386
387 /* Find the size of the symbol and string tables */
388
389 if (is_link_state) {
390 kxld_symtab_iterator_init(&iter, symtab, kxld_sym_is_exported, FALSE);
391 } else {
392 kxld_symtab_iterator_init(&iter, symtab,
393 kxld_sym_is_defined_locally, FALSE);
394 }
395
396 while ((sym = kxld_symtab_iterator_get_next(&iter))) {
397 symtabhdr->nsyms++;
398 symtabhdr->strsize += (uint32_t) (strlen(sym->name) + 1);
399 }
400
401 if (is_32_bit) {
402 nlistsize = sizeof(struct nlist);
403 } else {
404 nlistsize = sizeof(struct nlist_64);
405 }
406
407 symtabhdr->stroff = (uint32_t) (symtabhdr->symoff +
408 (symtabhdr->nsyms * nlistsize));
409 require_action(symtabhdr->stroff + symtabhdr->strsize <= data_size, finish,
410 rval=KERN_FAILURE);
411
412 /* Get pointers to the symbol and string tables */
413
414 nl = buf + symtabhdr->symoff;
415 strtab = (char *) (buf + symtabhdr->stroff);
416
417 /* Copy over the symbols */
418
419 kxld_symtab_iterator_reset(&iter);
420 while ((sym = kxld_symtab_iterator_get_next(&iter))) {
421
422 KXLD_3264_FUNC(is_32_bit, rval,
423 kxld_sym_export_macho_32, kxld_sym_export_macho_64,
424 sym, nl, strtab, &stroff, symtabhdr->strsize, is_link_state);
425 require_noerr(rval, finish);
426
427 nl += nlistsize;
428 stroff += rval;
429 }
430
431 /* Update the data offset */
432 *data_offset += (symtabhdr->nsyms * nlistsize) + stroff;
433
434 rval = KERN_SUCCESS;
435
436finish:
437 return rval;
438}
439
440/*******************************************************************************
441*******************************************************************************/
442u_int
443kxld_symtab_iterator_get_num_remaining(const KXLDSymtabIterator *iter)
444{
445 u_int idx = 0;
446 u_int count = 0;
447
448 check(iter);
449
450 idx = iter->idx;
451
452 for (idx = iter->idx; idx < iter->symtab->syms.nitems; ++idx) {
453 count += iter->test(kxld_array_get_item(&iter->symtab->syms, idx));
454 }
455
456 return count;
457}
458
459/*******************************************************************************
460*******************************************************************************/
461static kern_return_t
462make_cxx_index(KXLDSymtab *symtab)
463{
464 kern_return_t rval = KERN_FAILURE;
465 KXLDSymtabIterator iter;
466 KXLDSym *sym = NULL;
467 u_int nsyms = 0;
468
469 check(symtab);
470
471 /* Count the number of C++ symbols */
472 kxld_symtab_iterator_init(&iter, symtab, sym_is_defined_cxx, FALSE);
473 nsyms = kxld_symtab_iterator_get_num_remaining(&iter);
474
475 /* Create the dictionary */
476 rval = kxld_dict_init(&symtab->cxx_index, kxld_dict_kxldaddr_hash,
477 kxld_dict_kxldaddr_cmp, nsyms);
478 require_noerr(rval, finish);
479
480 /* Insert the non-stab symbols */
481 while ((sym = kxld_symtab_iterator_get_next(&iter))) {
482 rval = kxld_dict_insert(&symtab->cxx_index, &sym->base_addr, sym);
483 require_noerr(rval, finish);
484 }
485
486 rval = KERN_SUCCESS;
487
488finish:
489
490 return rval;
491}
492
493/*******************************************************************************
494*******************************************************************************/
495static boolean_t
496sym_is_defined_cxx(const KXLDSym *sym)
497{
498 return (kxld_sym_is_defined_locally(sym) && kxld_sym_is_cxx(sym));
499}
500
501/*******************************************************************************
502*******************************************************************************/
503static kern_return_t
504make_name_index(KXLDSymtab *symtab)
505{
506 kern_return_t rval = KERN_FAILURE;
507 KXLDSymtabIterator iter;
508 KXLDSym *sym = NULL;
509 u_int nsyms = 0;
510
511 check(symtab);
512
513 /* Count the number of symbols we need to index by name */
514 kxld_symtab_iterator_init(&iter, symtab, sym_is_name_indexed, FALSE);
515 nsyms = kxld_symtab_iterator_get_num_remaining(&iter);
516
517 /* Create the dictionary */
518 rval = kxld_dict_init(&symtab->name_index, kxld_dict_string_hash,
519 kxld_dict_string_cmp, nsyms);
520 require_noerr(rval, finish);
521
522 /* Insert the non-stab symbols */
523 while ((sym = kxld_symtab_iterator_get_next(&iter))) {
524 rval = kxld_dict_insert(&symtab->name_index, sym->name, sym);
525 require_noerr(rval, finish);
526 }
527
528 rval = KERN_SUCCESS;
529
530finish:
531
532 return rval;
533}
534
535/*******************************************************************************
536*******************************************************************************/
537static boolean_t
538sym_is_name_indexed(const KXLDSym *sym)
539{
540 return (kxld_sym_is_vtable(sym) ||
541 streq_safe(sym->name, KXLD_KMOD_INFO_SYMBOL,
542 const_strlen(KXLD_KMOD_INFO_SYMBOL)) ||
543 streq_safe(sym->name, KXLD_WEAK_TEST_SYMBOL,
544 const_strlen(KXLD_WEAK_TEST_SYMBOL)));
545}
546
547/*******************************************************************************
548*******************************************************************************/
549kern_return_t
550kxld_symtab_relocate(KXLDSymtab *symtab, const KXLDArray *sectarray)
551{
552 kern_return_t rval = KERN_FAILURE;
553 KXLDSymtabIterator iter;
554 KXLDSym *sym = NULL;
555 const KXLDSect *sect = NULL;
556
557 check(symtab);
558 check(sectarray);
559
560 kxld_symtab_iterator_init(&iter, symtab, kxld_sym_is_section, FALSE);
561
562 while ((sym = kxld_symtab_iterator_get_next(&iter))) {
563 sect = kxld_array_get_item(sectarray, sym->sectnum);
564 require_action(sect, finish, rval=KERN_FAILURE);
565 kxld_sym_relocate(sym, sect);
566 }
567
568 rval = KERN_SUCCESS;
569
570finish:
571
572 return rval;
573}
574
575/*******************************************************************************
576* This extends the symbol table and initializes the new symbol. We insert the
577* symbol into the name index, but we don't bother with the c++ value index
578* because it is based on the base_addr of the symbol, and the base_addr of
579* all synthesized symbols will be 0.
580*******************************************************************************/
581kern_return_t
582kxld_symtab_add_symbol(KXLDSymtab *symtab, char *name, kxld_addr_t link_addr,
583 KXLDSym **symout)
584{
585 kern_return_t rval = KERN_FAILURE;
586 KXLDSym *sym = NULL;
587 u_int symindex = symtab->syms.nitems;
588
589 rval = kxld_array_resize(&symtab->syms, symindex + 1);
590 require_noerr(rval, finish);
591
592 sym = kxld_array_get_item(&symtab->syms, symindex);
593 kxld_sym_init_absolute(sym, name, link_addr);
594
595 rval = kxld_dict_insert(&symtab->name_index, sym->name, sym);
596 require_noerr(rval, finish);
597
598 rval = KERN_SUCCESS;
599 *symout = sym;
600
601finish:
602 return rval;
603}
604
605/*******************************************************************************
606*******************************************************************************/
607KXLDSym *
608kxld_symtab_iterator_get_next(KXLDSymtabIterator *iter)
609{
610 KXLDSym *sym = NULL;
611 KXLDSym *tmp = NULL;
612 boolean_t cmp = FALSE;
613
614 check(iter);
615
616 for (; iter->idx < iter->symtab->syms.nitems; ++iter->idx) {
617 tmp = kxld_array_get_item(&iter->symtab->syms, iter->idx);
618 cmp = iter->test(tmp);
619 if (iter->negate) cmp = !cmp;
620
621 if (cmp) {
622 sym = tmp;
623 ++iter->idx;
624 break;
625 }
626 }
627
628 return sym;
629}
630
631
632/*******************************************************************************
633*******************************************************************************/
634void
635kxld_symtab_iterator_reset(KXLDSymtabIterator *iter)
636{
637 check(iter);
638 iter->idx = 0;
639}
640