]> git.saurik.com Git - apple/xnu.git/blob - SETUP/kextsymboltool/kextsymboltool.c
46f644b552d3f85206b1a9cb31ca19957ffc21b5
[apple/xnu.git] / SETUP / kextsymboltool / kextsymboltool.c
1 /*
2 * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 #include <libc.h>
24 #include <errno.h>
25 #include <ctype.h>
26
27 #include <mach/mach_init.h>
28
29 #include <sys/stat.h>
30 #include <sys/file.h>
31 #include <sys/mman.h>
32
33 #include <mach-o/arch.h>
34 #include <mach-o/fat.h>
35 #include <mach-o/loader.h>
36 #include <mach-o/nlist.h>
37 #include <mach-o/swap.h>
38
39 #include <uuid/uuid.h>
40 #include <stdbool.h>
41
42 #pragma mark Typedefs, Enums, Constants
43 /*********************************************************************
44 * Typedefs, Enums, Constants
45 *********************************************************************/
46 typedef enum {
47 kErrorNone = 0,
48 kError,
49 kErrorFileAccess,
50 kErrorDiskFull,
51 kErrorDuplicate
52 } ToolError;
53
54 #pragma mark Function Protos
55 /*********************************************************************
56 * Function Protos
57 *********************************************************************/
58 __private_extern__ ToolError
59 readFile(const char *path, vm_offset_t * objAddr, vm_size_t * objSize);
60
61 __private_extern__ ToolError
62 writeFile(int fd, const void * data, size_t length);
63
64 __private_extern__ ToolError
65 seekFile(int fd, off_t offset);
66
67 extern char* __cxa_demangle(const char* mangled_name,
68 char* buf,
69 size_t* n,
70 int* status);
71
72 #pragma mark Functions
73 /*********************************************************************
74 *********************************************************************/
75 __private_extern__ ToolError
76 writeFile(int fd, const void * data, size_t length)
77 {
78 ToolError err;
79
80 if (length != (size_t)write(fd, data, length)) {
81 err = kErrorDiskFull;
82 } else {
83 err = kErrorNone;
84 }
85
86 if (kErrorNone != err) {
87 perror("couldn't write output");
88 }
89
90 return err;
91 }
92
93 /*********************************************************************
94 *********************************************************************/
95 __private_extern__ ToolError
96 seekFile(int fd, off_t offset)
97 {
98 ToolError err;
99
100 if (offset != lseek(fd, offset, SEEK_SET)) {
101 err = kErrorDiskFull;
102 } else {
103 err = kErrorNone;
104 }
105
106 if (kErrorNone != err) {
107 perror("couldn't write output");
108 }
109
110 return err;
111 }
112
113 /*********************************************************************
114 *********************************************************************/
115 __private_extern__ ToolError
116 readFile(const char *path, vm_offset_t * objAddr, vm_size_t * objSize)
117 {
118 ToolError err = kErrorFileAccess;
119 int fd;
120 struct stat stat_buf;
121
122 *objAddr = 0;
123 *objSize = 0;
124
125 do{
126 if ((fd = open(path, O_RDONLY)) == -1) {
127 continue;
128 }
129
130 if (fstat(fd, &stat_buf) == -1) {
131 continue;
132 }
133
134 if (0 == (stat_buf.st_mode & S_IFREG)) {
135 continue;
136 }
137
138 /* Don't try to map an empty file, it fails now due to conformance
139 * stuff (PR 4611502).
140 */
141 if (0 == stat_buf.st_size) {
142 err = kErrorNone;
143 continue;
144 }
145
146 *objSize = stat_buf.st_size;
147
148 *objAddr = (vm_offset_t)mmap(NULL /* address */, *objSize,
149 PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE /* flags */,
150 fd, 0 /* offset */);
151
152 if ((void *)*objAddr == MAP_FAILED) {
153 *objAddr = 0;
154 *objSize = 0;
155 continue;
156 }
157
158 err = kErrorNone;
159 } while (false);
160
161 if (-1 != fd) {
162 close(fd);
163 }
164 if (kErrorNone != err) {
165 fprintf(stderr, "couldn't read %s: %s\n", path, strerror(errno));
166 }
167
168 return err;
169 }
170
171
172 enum { kExported = 0x00000001, kObsolete = 0x00000002 };
173
174 struct symbol {
175 char * name;
176 unsigned int name_len;
177 char * indirect;
178 unsigned int indirect_len;
179 unsigned int flags;
180 struct symbol * list;
181 unsigned int list_count;
182 };
183
184 static bool
185 issymchar( char c )
186 {
187 return (c > ' ') && (c <= '~') && (c != ':') && (c != '#');
188 }
189
190 static bool
191 iswhitespace( char c )
192 {
193 return (c == ' ') || (c == '\t');
194 }
195
196 /*
197 * Function for qsort for comparing symbol list names.
198 */
199 static int
200 qsort_cmp(const void * _left, const void * _right)
201 {
202 struct symbol * left = (struct symbol *) _left;
203 struct symbol * right = (struct symbol *) _right;
204
205 return strcmp(left->name, right->name);
206 }
207
208 /*
209 * Function for bsearch for finding a symbol name.
210 */
211
212 static int
213 bsearch_cmp( const void * _key, const void * _cmp)
214 {
215 char * key = (char *)_key;
216 struct symbol * cmp = (struct symbol *) _cmp;
217
218 return strcmp(key, cmp->name);
219 }
220
221 struct bsearch_key {
222 char * name;
223 unsigned int name_len;
224 };
225
226 static int
227 bsearch_cmp_prefix( const void * _key, const void * _cmp)
228 {
229 struct bsearch_key * key = (struct bsearch_key *)_key;
230 struct symbol * cmp = (struct symbol *) _cmp;
231
232 return strncmp(key->name, cmp->name, key->name_len);
233 }
234
235 static uint32_t
236 count_symbols(char * file, vm_size_t file_size)
237 {
238 uint32_t nsyms = 0;
239 char * scan;
240 char * eol;
241 char * next;
242
243 for (scan = file; true; scan = next) {
244 eol = memchr(scan, '\n', file_size - (scan - file));
245 if (eol == NULL) {
246 break;
247 }
248 next = eol + 1;
249
250 /* Skip empty lines.
251 */
252 if (eol == scan) {
253 continue;
254 }
255
256 /* Skip comment lines.
257 */
258 if (scan[0] == '#') {
259 continue;
260 }
261
262 /* Scan past any non-symbol characters at the beginning of the line. */
263 while ((scan < eol) && !issymchar(*scan)) {
264 scan++;
265 }
266
267 /* No symbol on line? Move along.
268 */
269 if (scan == eol) {
270 continue;
271 }
272
273 /* Skip symbols starting with '.'.
274 */
275 if (scan[0] == '.') {
276 continue;
277 }
278 nsyms++;
279 }
280
281 return nsyms;
282 }
283
284 static uint32_t
285 store_symbols(char * file, vm_size_t file_size, struct symbol * symbols, uint32_t idx, uint32_t max_symbols)
286 {
287 char * scan;
288 char * line;
289 char * eol;
290 char * next;
291
292 uint32_t strtabsize;
293
294 strtabsize = 0;
295
296 for (scan = file, line = file; true; scan = next, line = next) {
297 char * name = NULL;
298 char * name_term = NULL;
299 unsigned int name_len = 0;
300 char * indirect = NULL;
301 char * indirect_term = NULL;
302 unsigned int indirect_len = 0;
303 char * option = NULL;
304 char * option_term = NULL;
305 unsigned int option_len = 0;
306 char optionstr[256];
307 boolean_t obsolete = 0;
308
309 eol = memchr(scan, '\n', file_size - (scan - file));
310 if (eol == NULL) {
311 break;
312 }
313 next = eol + 1;
314
315 /* Skip empty lines.
316 */
317 if (eol == scan) {
318 continue;
319 }
320
321 *eol = '\0';
322
323 /* Skip comment lines.
324 */
325 if (scan[0] == '#') {
326 continue;
327 }
328
329 /* Scan past any non-symbol characters at the beginning of the line. */
330 while ((scan < eol) && !issymchar(*scan)) {
331 scan++;
332 }
333
334 /* No symbol on line? Move along.
335 */
336 if (scan == eol) {
337 continue;
338 }
339
340 /* Skip symbols starting with '.'.
341 */
342 if (scan[0] == '.') {
343 continue;
344 }
345
346 name = scan;
347
348 /* Find the end of the symbol.
349 */
350 while ((*scan != '\0') && issymchar(*scan)) {
351 scan++;
352 }
353
354 /* Note char past end of symbol.
355 */
356 name_term = scan;
357
358 /* Stored length must include the terminating nul char.
359 */
360 name_len = name_term - name + 1;
361
362 /* Now look for an indirect.
363 */
364 if (*scan != '\0') {
365 while ((*scan != '\0') && iswhitespace(*scan)) {
366 scan++;
367 }
368 if (*scan == ':') {
369 scan++;
370 while ((*scan != '\0') && iswhitespace(*scan)) {
371 scan++;
372 }
373 if (issymchar(*scan)) {
374 indirect = scan;
375
376 /* Find the end of the symbol.
377 */
378 while ((*scan != '\0') && issymchar(*scan)) {
379 scan++;
380 }
381
382 /* Note char past end of symbol.
383 */
384 indirect_term = scan;
385
386 /* Stored length must include the terminating nul char.
387 */
388 indirect_len = indirect_term - indirect + 1;
389 } else if (*scan == '\0') {
390 fprintf(stderr, "bad format in symbol line: %s\n", line);
391 exit(1);
392 }
393 } else if (*scan != '\0' && *scan != '-') {
394 fprintf(stderr, "bad format in symbol line: %s\n", line);
395 exit(1);
396 }
397 }
398
399 /* Look for options.
400 */
401 if (*scan != '\0') {
402 while ((*scan != '\0') && iswhitespace(*scan)) {
403 scan++;
404 }
405
406 if (*scan == '-') {
407 scan++;
408
409 if (isalpha(*scan)) {
410 option = scan;
411
412 /* Find the end of the option.
413 */
414 while ((*scan != '\0') && isalpha(*scan)) {
415 scan++;
416 }
417
418 /* Note char past end of option.
419 */
420 option_term = scan;
421 option_len = option_term - option;
422
423 if (option_len >= sizeof(optionstr)) {
424 fprintf(stderr, "option too long in symbol line: %s\n", line);
425 exit(1);
426 }
427 memcpy(optionstr, option, option_len);
428 optionstr[option_len] = '\0';
429
430 /* Find the option.
431 */
432 if (!strncmp(optionstr, "obsolete", option_len)) {
433 obsolete = TRUE;
434 }
435 } else if (*scan == '\0') {
436 fprintf(stderr, "bad format in symbol line: %s\n", line);
437 exit(1);
438 }
439 }
440 }
441
442 if (idx >= max_symbols) {
443 fprintf(stderr, "symbol[%d/%d] overflow: %s\n", idx, max_symbols, line);
444 exit(1);
445 }
446
447 *name_term = '\0';
448 if (indirect_term) {
449 *indirect_term = '\0';
450 }
451
452 symbols[idx].name = name;
453 symbols[idx].name_len = name_len;
454 symbols[idx].indirect = indirect;
455 symbols[idx].indirect_len = indirect_len;
456 symbols[idx].flags = (obsolete) ? kObsolete : 0;
457
458 strtabsize += symbols[idx].name_len + symbols[idx].indirect_len;
459 idx++;
460 }
461
462 return strtabsize;
463 }
464
465 static const NXArchInfo *
466 lookup_arch(const char *archstring)
467 {
468 /*
469 * As new architectures are supported by xnu, add a mapping function
470 * without relying on host libraries.
471 */
472 static const NXArchInfo archlist[] = {
473 { "x86_64", 0x01000007 /* CPU_TYPE_X86_64 */, 3 /* CPU_SUBTYPE_X86_64_ALL */, NX_LittleEndian, NULL },
474 { "x86_64h", 0x01000007 /* CPU_TYPE_X86_64 */, 8 /* CPU_SUBTYPE_X86_64_H */, NX_LittleEndian, NULL },
475 { "armv7", 12 /* CPU_TYPE_ARM */, 9 /* CPU_SUBTYPE_ARM_V7 */, NX_LittleEndian, NULL },
476 { "armv7s", 12 /* CPU_TYPE_ARM */, 11 /* CPU_SUBTYPE_ARM_V7S */, NX_LittleEndian, NULL },
477 { "armv7k", 12 /* CPU_TYPE_ARM */, 12 /* CPU_SUBTYPE_ARM_V7K */, NX_LittleEndian, NULL },
478 { "arm64", 0x0100000c /* CPU_TYPE_ARM64 */, 0 /* CPU_SUBTYPE_ARM64_ALL */, NX_LittleEndian, NULL },
479 };
480 unsigned long i;
481
482 for (i = 0; i < sizeof(archlist) / sizeof(archlist[0]); i++) {
483 if (0 == strcmp(archstring, archlist[i].name)) {
484 return &archlist[i];
485 }
486 }
487
488 return NULL;
489 }
490
491 /*********************************************************************
492 *********************************************************************/
493 int
494 main(int argc, char * argv[])
495 {
496 ToolError err;
497 int i, fd;
498 const char * output_name = NULL;
499 uint32_t zero = 0, num_files = 0;
500 uint32_t filenum;
501 uint32_t strx, strtabsize, strtabpad;
502 struct symbol * import_symbols;
503 struct symbol * export_symbols;
504 uint32_t num_import_syms, num_export_syms;
505 uint32_t result_count, num_removed_syms;
506 uint32_t import_idx, export_idx;
507 const NXArchInfo * host_arch;
508 const NXArchInfo * target_arch;
509 boolean_t require_imports = true;
510 boolean_t diff = false;
511
512
513 struct file {
514 vm_offset_t mapped;
515 vm_size_t mapped_size;
516 uint32_t nsyms;
517 boolean_t import;
518 const char * path;
519 };
520 struct file files[64];
521
522 host_arch = NXGetLocalArchInfo();
523 target_arch = host_arch;
524
525 for (i = 1; i < argc; i += 2) {
526 boolean_t import;
527
528 if (!strcmp("-sect", argv[i])) {
529 require_imports = false;
530 i--;
531 continue;
532 }
533 if (!strcmp("-diff", argv[i])) {
534 require_imports = false;
535 diff = true;
536 i--;
537 continue;
538 }
539
540 if (i == (argc - 1)) {
541 fprintf(stderr, "bad arguments: %s\n", argv[i]);
542 exit(1);
543 }
544
545 if (!strcmp("-arch", argv[i])) {
546 target_arch = lookup_arch(argv[i + 1]);
547 if (!target_arch) {
548 fprintf(stderr, "unknown architecture name: %s\n", argv[i + 1]);
549 exit(1);
550 }
551 continue;
552 }
553 if (!strcmp("-output", argv[i])) {
554 output_name = argv[i + 1];
555 continue;
556 }
557
558 if (!strcmp("-import", argv[i])) {
559 import = true;
560 } else if (!strcmp("-export", argv[i])) {
561 import = false;
562 } else {
563 fprintf(stderr, "unknown option: %s\n", argv[i]);
564 exit(1);
565 }
566
567 err = readFile(argv[i + 1], &files[num_files].mapped, &files[num_files].mapped_size);
568 if (kErrorNone != err) {
569 exit(1);
570 }
571
572 if (files[num_files].mapped && files[num_files].mapped_size) {
573 files[num_files].import = import;
574 files[num_files].path = argv[i + 1];
575 num_files++;
576 }
577 }
578
579 if (!output_name) {
580 fprintf(stderr, "no output file\n");
581 exit(1);
582 }
583
584 num_import_syms = 0;
585 num_export_syms = 0;
586 for (filenum = 0; filenum < num_files; filenum++) {
587 files[filenum].nsyms = count_symbols((char *) files[filenum].mapped, files[filenum].mapped_size);
588 if (files[filenum].import) {
589 num_import_syms += files[filenum].nsyms;
590 } else {
591 num_export_syms += files[filenum].nsyms;
592 }
593 }
594
595 import_symbols = calloc(num_import_syms, sizeof(struct symbol));
596 export_symbols = calloc(num_export_syms, sizeof(struct symbol));
597
598 import_idx = 0;
599 export_idx = 0;
600
601 for (filenum = 0; filenum < num_files; filenum++) {
602 if (files[filenum].import) {
603 store_symbols((char *) files[filenum].mapped, files[filenum].mapped_size,
604 import_symbols, import_idx, num_import_syms);
605 import_idx += files[filenum].nsyms;
606 } else {
607 store_symbols((char *) files[filenum].mapped, files[filenum].mapped_size,
608 export_symbols, export_idx, num_export_syms);
609 export_idx += files[filenum].nsyms;
610 }
611 if (false && !files[filenum].nsyms) {
612 fprintf(stderr, "warning: file %s contains no names\n", files[filenum].path);
613 }
614 }
615
616
617 qsort(import_symbols, num_import_syms, sizeof(struct symbol), &qsort_cmp);
618 qsort(export_symbols, num_export_syms, sizeof(struct symbol), &qsort_cmp);
619
620 result_count = 0;
621 num_removed_syms = 0;
622 strtabsize = 4;
623 if (num_import_syms) {
624 for (export_idx = 0; export_idx < num_export_syms; export_idx++) {
625 struct symbol * result;
626 char * name;
627 size_t len;
628 boolean_t wild;
629
630 name = export_symbols[export_idx].indirect;
631 len = export_symbols[export_idx].indirect_len;
632 if (!name) {
633 name = export_symbols[export_idx].name;
634 len = export_symbols[export_idx].name_len;
635 }
636 wild = ((len > 2) && ('*' == name[len -= 2]));
637 if (wild) {
638 struct bsearch_key key;
639 key.name = name;
640 key.name_len = len;
641 result = bsearch(&key, import_symbols,
642 num_import_syms, sizeof(struct symbol), &bsearch_cmp_prefix);
643
644 if (result) {
645 struct symbol * first;
646 struct symbol * last;
647
648 strtabsize += (result->name_len + result->indirect_len);
649
650 first = result;
651 while (--first >= &import_symbols[0]) {
652 if (bsearch_cmp_prefix(&key, first)) {
653 break;
654 }
655 strtabsize += (first->name_len + first->indirect_len);
656 }
657 first++;
658
659 last = result;
660 while (++last < (&import_symbols[0] + num_import_syms)) {
661 if (bsearch_cmp_prefix(&key, last)) {
662 break;
663 }
664 strtabsize += (last->name_len + last->indirect_len);
665 }
666 result_count += last - first;
667 result = first;
668 export_symbols[export_idx].list = first;
669 export_symbols[export_idx].list_count = last - first;
670 export_symbols[export_idx].flags |= kExported;
671 }
672 } else {
673 result = bsearch(name, import_symbols,
674 num_import_syms, sizeof(struct symbol), &bsearch_cmp);
675 }
676
677 if (!result && require_imports) {
678 int status;
679 char * demangled_result =
680 __cxa_demangle(export_symbols[export_idx].name + 1, NULL, NULL, &status);
681 fprintf(stderr, "exported name not in import list: %s\n",
682 demangled_result ? demangled_result : export_symbols[export_idx].name);
683 // fprintf(stderr, " : %s\n", export_symbols[export_idx].name);
684 if (demangled_result) {
685 free(demangled_result);
686 }
687 num_removed_syms++;
688 }
689 if (diff) {
690 if (!result) {
691 result = &export_symbols[export_idx];
692 } else {
693 result = NULL;
694 }
695 }
696 if (result && !wild) {
697 export_symbols[export_idx].flags |= kExported;
698 strtabsize += (export_symbols[export_idx].name_len + export_symbols[export_idx].indirect_len);
699 result_count++;
700 export_symbols[export_idx].list = &export_symbols[export_idx];
701 export_symbols[export_idx].list_count = 1;
702 }
703 }
704 }
705 strtabpad = (strtabsize + 3) & ~3;
706
707 if (require_imports && num_removed_syms) {
708 err = kError;
709 goto finish;
710 }
711
712 fd = open(output_name, O_WRONLY | O_CREAT | O_TRUNC, 0755);
713 if (-1 == fd) {
714 perror("couldn't write output");
715 err = kErrorFileAccess;
716 goto finish;
717 }
718
719 struct symtab_command symcmd;
720 struct uuid_command uuidcmd;
721 off_t symsoffset;
722
723 symcmd.cmd = LC_SYMTAB;
724 symcmd.cmdsize = sizeof(symcmd);
725 symcmd.nsyms = result_count;
726 symcmd.strsize = strtabpad;
727
728 uuidcmd.cmd = LC_UUID;
729 uuidcmd.cmdsize = sizeof(uuidcmd);
730 uuid_generate(uuidcmd.uuid);
731
732 if (CPU_ARCH_ABI64 & target_arch->cputype) {
733 struct mach_header_64 hdr;
734 struct segment_command_64 segcmd;
735
736 hdr.magic = MH_MAGIC_64;
737 hdr.cputype = target_arch->cputype;
738 hdr.cpusubtype = target_arch->cpusubtype;
739 hdr.filetype = MH_KEXT_BUNDLE;
740 hdr.ncmds = 3;
741 hdr.sizeofcmds = sizeof(segcmd) + sizeof(symcmd) + sizeof(uuidcmd);
742 hdr.flags = MH_INCRLINK;
743 symsoffset = mach_vm_round_page(hdr.sizeofcmds);
744
745 segcmd.cmd = LC_SEGMENT_64;
746 segcmd.cmdsize = sizeof(segcmd);
747 strncpy(segcmd.segname, SEG_LINKEDIT, sizeof(segcmd.segname));
748 segcmd.vmaddr = 0;
749 segcmd.vmsize = result_count * sizeof(struct nlist_64) + strtabpad;
750 segcmd.fileoff = symsoffset;
751 segcmd.filesize = segcmd.vmsize;
752 segcmd.maxprot = PROT_READ;
753 segcmd.initprot = PROT_READ;
754 segcmd.nsects = 0;
755 segcmd.flags = SG_NORELOC;
756
757 symcmd.symoff = symsoffset;
758 symcmd.stroff = result_count * sizeof(struct nlist_64)
759 + symcmd.symoff;
760
761 if (target_arch->byteorder != host_arch->byteorder) {
762 swap_mach_header_64(&hdr, target_arch->byteorder);
763 swap_segment_command_64(&segcmd, target_arch->byteorder);
764 }
765 err = writeFile(fd, &hdr, sizeof(hdr));
766 if (kErrorNone != err) {
767 goto finish;
768 }
769 err = writeFile(fd, &segcmd, sizeof(segcmd));
770 } else {
771 struct mach_header hdr;
772 struct segment_command segcmd;
773
774 hdr.magic = MH_MAGIC;
775 hdr.cputype = target_arch->cputype;
776 hdr.cpusubtype = target_arch->cpusubtype;
777 hdr.filetype = MH_KEXT_BUNDLE;
778 hdr.ncmds = 3;
779 hdr.sizeofcmds = sizeof(segcmd) + sizeof(symcmd) + sizeof(uuidcmd);
780 hdr.flags = MH_INCRLINK;
781 symsoffset = mach_vm_round_page(hdr.sizeofcmds);
782
783 segcmd.cmd = LC_SEGMENT;
784 segcmd.cmdsize = sizeof(segcmd);
785 strncpy(segcmd.segname, SEG_LINKEDIT, sizeof(segcmd.segname));
786 segcmd.vmaddr = 0;
787 segcmd.vmsize = result_count * sizeof(struct nlist) + strtabpad;
788 segcmd.fileoff = symsoffset;
789 segcmd.filesize = segcmd.vmsize;
790 segcmd.maxprot = PROT_READ;
791 segcmd.initprot = PROT_READ;
792 segcmd.nsects = 0;
793 segcmd.flags = SG_NORELOC;
794
795 symcmd.symoff = symsoffset;
796 symcmd.stroff = result_count * sizeof(struct nlist)
797 + symcmd.symoff;
798
799 if (target_arch->byteorder != host_arch->byteorder) {
800 swap_mach_header(&hdr, target_arch->byteorder);
801 swap_segment_command(&segcmd, target_arch->byteorder);
802 }
803 err = writeFile(fd, &hdr, sizeof(hdr));
804 if (kErrorNone != err) {
805 goto finish;
806 }
807 err = writeFile(fd, &segcmd, sizeof(segcmd));
808 }
809
810 if (kErrorNone != err) {
811 goto finish;
812 }
813
814 if (target_arch->byteorder != host_arch->byteorder) {
815 swap_symtab_command(&symcmd, target_arch->byteorder);
816 swap_uuid_command(&uuidcmd, target_arch->byteorder);
817 }
818 err = writeFile(fd, &symcmd, sizeof(symcmd));
819 if (kErrorNone != err) {
820 goto finish;
821 }
822 err = writeFile(fd, &uuidcmd, sizeof(uuidcmd));
823 if (kErrorNone != err) {
824 goto finish;
825 }
826
827 err = seekFile(fd, symsoffset);
828 if (kErrorNone != err) {
829 goto finish;
830 }
831
832 strx = 4;
833 for (export_idx = 0; export_idx < num_export_syms; export_idx++) {
834 if (!export_symbols[export_idx].name) {
835 continue;
836 }
837 if (!(kExported & export_symbols[export_idx].flags)) {
838 continue;
839 }
840
841 if (export_idx
842 && export_symbols[export_idx - 1].name
843 && !strcmp(export_symbols[export_idx - 1].name, export_symbols[export_idx].name)) {
844 fprintf(stderr, "duplicate export: %s\n", export_symbols[export_idx - 1].name);
845 err = kErrorDuplicate;
846 goto finish;
847 }
848
849 for (import_idx = 0; import_idx < export_symbols[export_idx].list_count; import_idx++) {
850 if (export_symbols[export_idx].list != &export_symbols[export_idx]) {
851 printf("wild: %s, %s\n", export_symbols[export_idx].name,
852 export_symbols[export_idx].list[import_idx].name);
853 }
854 if (CPU_ARCH_ABI64 & target_arch->cputype) {
855 struct nlist_64 nl;
856
857 nl.n_sect = 0;
858 nl.n_desc = 0;
859 nl.n_un.n_strx = strx;
860 strx += export_symbols[export_idx].list[import_idx].name_len;
861
862 if (export_symbols[export_idx].flags & kObsolete) {
863 nl.n_desc |= N_DESC_DISCARDED;
864 }
865
866 if (export_symbols[export_idx].list[import_idx].indirect) {
867 nl.n_type = N_INDR | N_EXT;
868 nl.n_value = strx;
869 strx += export_symbols[export_idx].list[import_idx].indirect_len;
870 } else {
871 nl.n_type = N_UNDF | N_EXT;
872 nl.n_value = 0;
873 }
874
875 if (target_arch->byteorder != host_arch->byteorder) {
876 swap_nlist_64(&nl, 1, target_arch->byteorder);
877 }
878
879 err = writeFile(fd, &nl, sizeof(nl));
880 } else {
881 struct nlist nl;
882
883 nl.n_sect = 0;
884 nl.n_desc = 0;
885 nl.n_un.n_strx = strx;
886 strx += export_symbols[export_idx].list[import_idx].name_len;
887
888 if (export_symbols[export_idx].flags & kObsolete) {
889 nl.n_desc |= N_DESC_DISCARDED;
890 }
891
892 if (export_symbols[export_idx].list[import_idx].indirect) {
893 nl.n_type = N_INDR | N_EXT;
894 nl.n_value = strx;
895 strx += export_symbols[export_idx].list[import_idx].indirect_len;
896 } else {
897 nl.n_type = N_UNDF | N_EXT;
898 nl.n_value = 0;
899 }
900
901 if (target_arch->byteorder != host_arch->byteorder) {
902 swap_nlist(&nl, 1, target_arch->byteorder);
903 }
904
905 err = writeFile(fd, &nl, sizeof(nl));
906 }
907 }
908
909 if (kErrorNone != err) {
910 goto finish;
911 }
912 }
913
914 strx = sizeof(uint32_t);
915 err = writeFile(fd, &zero, strx);
916 if (kErrorNone != err) {
917 goto finish;
918 }
919
920 for (export_idx = 0; export_idx < num_export_syms; export_idx++) {
921 if (!export_symbols[export_idx].name) {
922 continue;
923 }
924
925 for (import_idx = 0; import_idx < export_symbols[export_idx].list_count; import_idx++) {
926 err = writeFile(fd, export_symbols[export_idx].list[import_idx].name,
927 export_symbols[export_idx].list[import_idx].name_len);
928 if (kErrorNone != err) {
929 goto finish;
930 }
931 if (export_symbols[export_idx].list[import_idx].indirect) {
932 err = writeFile(fd, export_symbols[export_idx].list[import_idx].indirect,
933 export_symbols[export_idx].list[import_idx].indirect_len);
934 if (kErrorNone != err) {
935 goto finish;
936 }
937 }
938 }
939 }
940
941 err = writeFile(fd, &zero, strtabpad - strtabsize);
942 if (kErrorNone != err) {
943 goto finish;
944 }
945
946 close(fd);
947
948
949 finish:
950 for (filenum = 0; filenum < num_files; filenum++) {
951 // unmap file
952 if (files[filenum].mapped_size) {
953 munmap((caddr_t)files[filenum].mapped, files[filenum].mapped_size);
954 files[filenum].mapped = 0;
955 files[filenum].mapped_size = 0;
956 }
957 }
958
959 if (kErrorNone != err) {
960 if (output_name && strncmp(output_name, "/dev/", 5)) {
961 unlink(output_name);
962 }
963 exit(1);
964 } else {
965 exit(0);
966 }
967 return 0;
968 }