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