]> git.saurik.com Git - apple/xnu.git/blob - SETUP/kextsymboltool/kextsymboltool.c
xnu-3789.31.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 if (!num_export_syms)
601 {
602 fprintf(stderr, "no export names\n");
603 exit(1);
604 }
605
606 import_symbols = calloc(num_import_syms, sizeof(struct symbol));
607 export_symbols = calloc(num_export_syms, sizeof(struct symbol));
608
609 import_idx = 0;
610 export_idx = 0;
611
612 for (filenum = 0; filenum < num_files; filenum++)
613 {
614 if (files[filenum].import)
615 {
616 store_symbols((char *) files[filenum].mapped, files[filenum].mapped_size,
617 import_symbols, import_idx, num_import_syms);
618 import_idx += files[filenum].nsyms;
619 }
620 else
621 {
622 store_symbols((char *) files[filenum].mapped, files[filenum].mapped_size,
623 export_symbols, export_idx, num_export_syms);
624 export_idx += files[filenum].nsyms;
625 }
626 if (false && !files[filenum].nsyms)
627 {
628 fprintf(stderr, "warning: file %s contains no names\n", files[filenum].path);
629 }
630 }
631
632
633 qsort(import_symbols, num_import_syms, sizeof(struct symbol), &qsort_cmp);
634 qsort(export_symbols, num_export_syms, sizeof(struct symbol), &qsort_cmp);
635
636 result_count = 0;
637 num_removed_syms = 0;
638 strtabsize = 4;
639 if (num_import_syms)
640 {
641 for (export_idx = 0; export_idx < num_export_syms; export_idx++)
642 {
643 struct symbol * result;
644 char * name;
645 size_t len;
646 boolean_t wild;
647
648 name = export_symbols[export_idx].indirect;
649 len = export_symbols[export_idx].indirect_len;
650 if (!name)
651 {
652 name = export_symbols[export_idx].name;
653 len = export_symbols[export_idx].name_len;
654 }
655 wild = ((len > 2) && ('*' == name[len-=2]));
656 if (wild)
657 {
658 struct bsearch_key key;
659 key.name = name;
660 key.name_len = len;
661 result = bsearch(&key, import_symbols,
662 num_import_syms, sizeof(struct symbol), &bsearch_cmp_prefix);
663
664 if (result)
665 {
666 struct symbol * first;
667 struct symbol * last;
668
669 strtabsize += (result->name_len + result->indirect_len);
670
671 first = result;
672 while (--first >= &import_symbols[0])
673 {
674 if (bsearch_cmp_prefix(&key, first))
675 break;
676 strtabsize += (first->name_len + first->indirect_len);
677 }
678 first++;
679
680 last = result;
681 while (++last < (&import_symbols[0] + num_import_syms))
682 {
683 if (bsearch_cmp_prefix(&key, last))
684 break;
685 strtabsize += (last->name_len + last->indirect_len);
686 }
687 result_count += last - first;
688 result = first;
689 export_symbols[export_idx].list = first;
690 export_symbols[export_idx].list_count = last - first;
691 export_symbols[export_idx].flags |= kExported;
692 }
693 }
694 else
695 result = bsearch(name, import_symbols,
696 num_import_syms, sizeof(struct symbol), &bsearch_cmp);
697
698 if (!result && require_imports)
699 {
700 int status;
701 char * demangled_result =
702 __cxa_demangle(export_symbols[export_idx].name + 1, NULL, NULL, &status);
703 fprintf(stderr, "exported name not in import list: %s\n",
704 demangled_result ? demangled_result : export_symbols[export_idx].name);
705 // fprintf(stderr, " : %s\n", export_symbols[export_idx].name);
706 if (demangled_result) {
707 free(demangled_result);
708 }
709 num_removed_syms++;
710 }
711 if (diff)
712 {
713 if (!result)
714 result = &export_symbols[export_idx];
715 else
716 result = NULL;
717 }
718 if (result && !wild)
719 {
720 export_symbols[export_idx].flags |= kExported;
721 strtabsize += (export_symbols[export_idx].name_len + export_symbols[export_idx].indirect_len);
722 result_count++;
723 export_symbols[export_idx].list = &export_symbols[export_idx];
724 export_symbols[export_idx].list_count = 1;
725 }
726 }
727 }
728 strtabpad = (strtabsize + 3) & ~3;
729
730 if (require_imports && num_removed_syms)
731 {
732 err = kError;
733 goto finish;
734 }
735
736 fd = open(output_name, O_WRONLY|O_CREAT|O_TRUNC, 0755);
737 if (-1 == fd)
738 {
739 perror("couldn't write output");
740 err = kErrorFileAccess;
741 goto finish;
742 }
743
744 struct symtab_command symcmd;
745 struct uuid_command uuidcmd;
746 off_t symsoffset;
747
748 symcmd.cmd = LC_SYMTAB;
749 symcmd.cmdsize = sizeof(symcmd);
750 symcmd.nsyms = result_count;
751 symcmd.strsize = strtabpad;
752
753 uuidcmd.cmd = LC_UUID;
754 uuidcmd.cmdsize = sizeof(uuidcmd);
755 uuid_generate(uuidcmd.uuid);
756
757 if (CPU_ARCH_ABI64 & target_arch->cputype)
758 {
759 struct mach_header_64 hdr;
760 struct segment_command_64 segcmd;
761
762 hdr.magic = MH_MAGIC_64;
763 hdr.cputype = target_arch->cputype;
764 hdr.cpusubtype = target_arch->cpusubtype;
765 hdr.filetype = MH_KEXT_BUNDLE;
766 hdr.ncmds = 3;
767 hdr.sizeofcmds = sizeof(segcmd) + sizeof(symcmd) + sizeof(uuidcmd);
768 hdr.flags = MH_INCRLINK;
769 symsoffset = mach_vm_round_page(hdr.sizeofcmds);
770
771 segcmd.cmd = LC_SEGMENT_64;
772 segcmd.cmdsize = sizeof(segcmd);
773 strncpy(segcmd.segname, SEG_LINKEDIT, sizeof(segcmd.segname));
774 segcmd.vmaddr = 0;
775 segcmd.vmsize = result_count * sizeof(struct nlist_64) + strtabpad;
776 segcmd.fileoff = symsoffset;
777 segcmd.filesize = segcmd.vmsize;
778 segcmd.maxprot = PROT_READ;
779 segcmd.initprot = PROT_READ;
780 segcmd.nsects = 0;
781 segcmd.flags = SG_NORELOC;
782
783 symcmd.symoff = symsoffset;
784 symcmd.stroff = result_count * sizeof(struct nlist_64)
785 + symcmd.symoff;
786
787 if (target_arch->byteorder != host_arch->byteorder)
788 {
789 swap_mach_header_64(&hdr, target_arch->byteorder);
790 swap_segment_command_64(&segcmd, target_arch->byteorder);
791 }
792 err = writeFile(fd, &hdr, sizeof(hdr));
793 if (kErrorNone != err)
794 goto finish;
795 err = writeFile(fd, &segcmd, sizeof(segcmd));
796 }
797 else
798 {
799 struct mach_header hdr;
800 struct segment_command segcmd;
801
802 hdr.magic = MH_MAGIC;
803 hdr.cputype = target_arch->cputype;
804 hdr.cpusubtype = target_arch->cpusubtype;
805 hdr.filetype = MH_KEXT_BUNDLE;
806 hdr.ncmds = 3;
807 hdr.sizeofcmds = sizeof(segcmd) + sizeof(symcmd) + sizeof(uuidcmd);
808 hdr.flags = MH_INCRLINK;
809 symsoffset = mach_vm_round_page(hdr.sizeofcmds);
810
811 segcmd.cmd = LC_SEGMENT;
812 segcmd.cmdsize = sizeof(segcmd);
813 strncpy(segcmd.segname, SEG_LINKEDIT, sizeof(segcmd.segname));
814 segcmd.vmaddr = 0;
815 segcmd.vmsize = result_count * sizeof(struct nlist) + strtabpad;
816 segcmd.fileoff = symsoffset;
817 segcmd.filesize = segcmd.vmsize;
818 segcmd.maxprot = PROT_READ;
819 segcmd.initprot = PROT_READ;
820 segcmd.nsects = 0;
821 segcmd.flags = SG_NORELOC;
822
823 symcmd.symoff = symsoffset;
824 symcmd.stroff = result_count * sizeof(struct nlist)
825 + symcmd.symoff;
826
827 if (target_arch->byteorder != host_arch->byteorder)
828 {
829 swap_mach_header(&hdr, target_arch->byteorder);
830 swap_segment_command(&segcmd, target_arch->byteorder);
831 }
832 err = writeFile(fd, &hdr, sizeof(hdr));
833 if (kErrorNone != err)
834 goto finish;
835 err = writeFile(fd, &segcmd, sizeof(segcmd));
836 }
837
838 if (kErrorNone != err)
839 goto finish;
840
841 if (target_arch->byteorder != host_arch->byteorder) {
842 swap_symtab_command(&symcmd, target_arch->byteorder);
843 swap_uuid_command(&uuidcmd, target_arch->byteorder);
844 }
845 err = writeFile(fd, &symcmd, sizeof(symcmd));
846 if (kErrorNone != err)
847 goto finish;
848 err = writeFile(fd, &uuidcmd, sizeof(uuidcmd));
849 if (kErrorNone != err)
850 goto finish;
851
852 err = seekFile(fd, symsoffset);
853 if (kErrorNone != err)
854 goto finish;
855
856 strx = 4;
857 for (export_idx = 0; export_idx < num_export_syms; export_idx++)
858 {
859 if (!export_symbols[export_idx].name)
860 continue;
861 if (!(kExported & export_symbols[export_idx].flags))
862 continue;
863
864 if (export_idx
865 && export_symbols[export_idx - 1].name
866 && !strcmp(export_symbols[export_idx - 1].name, export_symbols[export_idx].name))
867 {
868 fprintf(stderr, "duplicate export: %s\n", export_symbols[export_idx - 1].name);
869 err = kErrorDuplicate;
870 goto finish;
871 }
872
873 for (import_idx = 0; import_idx < export_symbols[export_idx].list_count; import_idx++)
874 {
875
876 if (export_symbols[export_idx].list != &export_symbols[export_idx])
877 {
878 printf("wild: %s, %s\n", export_symbols[export_idx].name,
879 export_symbols[export_idx].list[import_idx].name);
880 }
881 if (CPU_ARCH_ABI64 & target_arch->cputype)
882 {
883 struct nlist_64 nl;
884
885 nl.n_sect = 0;
886 nl.n_desc = 0;
887 nl.n_un.n_strx = strx;
888 strx += export_symbols[export_idx].list[import_idx].name_len;
889
890 if (export_symbols[export_idx].flags & kObsolete) {
891 nl.n_desc |= N_DESC_DISCARDED;
892 }
893
894 if (export_symbols[export_idx].list[import_idx].indirect)
895 {
896 nl.n_type = N_INDR | N_EXT;
897 nl.n_value = strx;
898 strx += export_symbols[export_idx].list[import_idx].indirect_len;
899 }
900 else
901 {
902 nl.n_type = N_UNDF | N_EXT;
903 nl.n_value = 0;
904 }
905
906 if (target_arch->byteorder != host_arch->byteorder)
907 swap_nlist_64(&nl, 1, target_arch->byteorder);
908
909 err = writeFile(fd, &nl, sizeof(nl));
910 }
911 else
912 {
913 struct nlist nl;
914
915 nl.n_sect = 0;
916 nl.n_desc = 0;
917 nl.n_un.n_strx = strx;
918 strx += export_symbols[export_idx].list[import_idx].name_len;
919
920 if (export_symbols[export_idx].flags & kObsolete) {
921 nl.n_desc |= N_DESC_DISCARDED;
922 }
923
924 if (export_symbols[export_idx].list[import_idx].indirect)
925 {
926 nl.n_type = N_INDR | N_EXT;
927 nl.n_value = strx;
928 strx += export_symbols[export_idx].list[import_idx].indirect_len;
929 }
930 else
931 {
932 nl.n_type = N_UNDF | N_EXT;
933 nl.n_value = 0;
934 }
935
936 if (target_arch->byteorder != host_arch->byteorder)
937 swap_nlist(&nl, 1, target_arch->byteorder);
938
939 err = writeFile(fd, &nl, sizeof(nl));
940 }
941 }
942
943 if (kErrorNone != err)
944 goto finish;
945 }
946
947 strx = sizeof(uint32_t);
948 err = writeFile(fd, &zero, strx);
949 if (kErrorNone != err)
950 goto finish;
951
952 for (export_idx = 0; export_idx < num_export_syms; export_idx++)
953 {
954 if (!export_symbols[export_idx].name)
955 continue;
956
957 for (import_idx = 0; import_idx < export_symbols[export_idx].list_count; import_idx++)
958 {
959 err = writeFile(fd, export_symbols[export_idx].list[import_idx].name,
960 export_symbols[export_idx].list[import_idx].name_len);
961 if (kErrorNone != err)
962 goto finish;
963 if (export_symbols[export_idx].list[import_idx].indirect)
964 {
965 err = writeFile(fd, export_symbols[export_idx].list[import_idx].indirect,
966 export_symbols[export_idx].list[import_idx].indirect_len);
967 if (kErrorNone != err)
968 goto finish;
969 }
970 }
971 }
972
973 err = writeFile(fd, &zero, strtabpad - strtabsize);
974 if (kErrorNone != err)
975 goto finish;
976
977 close(fd);
978
979
980 finish:
981 for (filenum = 0; filenum < num_files; filenum++) {
982 // unmap file
983 if (files[filenum].mapped_size)
984 {
985 munmap((caddr_t)files[filenum].mapped, files[filenum].mapped_size);
986 files[filenum].mapped = 0;
987 files[filenum].mapped_size = 0;
988 }
989
990 }
991
992 if (kErrorNone != err)
993 {
994 if (output_name && strncmp(output_name, "/dev/", 5))
995 unlink(output_name);
996 exit(1);
997 }
998 else
999 exit(0);
1000 return(0);
1001 }
1002