]> git.saurik.com Git - apple/xnu.git/blob - SETUP/kextsymboltool/kextsymboltool.c
2954a391f074b74055ad9b2e37b75f57e14e2e0a
[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 { "arm64e", 0x0100000c /* CPU_TYPE_ARM64 */, 2 /* CPU_SUBTYPE_ARM64_E */, NX_LittleEndian, NULL },
480 };
481 unsigned long i;
482
483 for (i = 0; i < sizeof(archlist) / sizeof(archlist[0]); i++) {
484 if (0 == strcmp(archstring, archlist[i].name)) {
485 return &archlist[i];
486 }
487 }
488
489 return NULL;
490 }
491
492 /*********************************************************************
493 *********************************************************************/
494 int
495 main(int argc, char * argv[])
496 {
497 ToolError err;
498 int i, fd;
499 const char * output_name = NULL;
500 uint32_t zero = 0, num_files = 0;
501 uint32_t filenum;
502 uint32_t strx, strtabsize, strtabpad;
503 struct symbol * import_symbols;
504 struct symbol * export_symbols;
505 uint32_t num_import_syms, num_export_syms;
506 uint32_t result_count, num_removed_syms;
507 uint32_t import_idx, export_idx;
508 const NXArchInfo * host_arch;
509 const NXArchInfo * target_arch;
510 boolean_t require_imports = true;
511 boolean_t diff = false;
512
513
514 struct file {
515 vm_offset_t mapped;
516 vm_size_t mapped_size;
517 uint32_t nsyms;
518 boolean_t import;
519 const char * path;
520 };
521 struct file files[64];
522
523 host_arch = NXGetLocalArchInfo();
524 target_arch = host_arch;
525
526 for (i = 1; i < argc; i += 2) {
527 boolean_t import;
528
529 if (!strcmp("-sect", argv[i])) {
530 require_imports = false;
531 i--;
532 continue;
533 }
534 if (!strcmp("-diff", argv[i])) {
535 require_imports = false;
536 diff = true;
537 i--;
538 continue;
539 }
540
541 if (i == (argc - 1)) {
542 fprintf(stderr, "bad arguments: %s\n", argv[i]);
543 exit(1);
544 }
545
546 if (!strcmp("-arch", argv[i])) {
547 target_arch = lookup_arch(argv[i + 1]);
548 if (!target_arch) {
549 fprintf(stderr, "unknown architecture name: %s\n", argv[i + 1]);
550 exit(1);
551 }
552 continue;
553 }
554 if (!strcmp("-output", argv[i])) {
555 output_name = argv[i + 1];
556 continue;
557 }
558
559 if (!strcmp("-import", argv[i])) {
560 import = true;
561 } else if (!strcmp("-export", argv[i])) {
562 import = false;
563 } else {
564 fprintf(stderr, "unknown option: %s\n", argv[i]);
565 exit(1);
566 }
567
568 err = readFile(argv[i + 1], &files[num_files].mapped, &files[num_files].mapped_size);
569 if (kErrorNone != err) {
570 exit(1);
571 }
572
573 if (files[num_files].mapped && files[num_files].mapped_size) {
574 files[num_files].import = import;
575 files[num_files].path = argv[i + 1];
576 num_files++;
577 }
578 }
579
580 if (!output_name) {
581 fprintf(stderr, "no output file\n");
582 exit(1);
583 }
584
585 num_import_syms = 0;
586 num_export_syms = 0;
587 for (filenum = 0; filenum < num_files; filenum++) {
588 files[filenum].nsyms = count_symbols((char *) files[filenum].mapped, files[filenum].mapped_size);
589 if (files[filenum].import) {
590 num_import_syms += files[filenum].nsyms;
591 } else {
592 num_export_syms += files[filenum].nsyms;
593 }
594 }
595
596 import_symbols = calloc(num_import_syms, sizeof(struct symbol));
597 export_symbols = calloc(num_export_syms, sizeof(struct symbol));
598
599 import_idx = 0;
600 export_idx = 0;
601
602 for (filenum = 0; filenum < num_files; filenum++) {
603 if (files[filenum].import) {
604 store_symbols((char *) files[filenum].mapped, files[filenum].mapped_size,
605 import_symbols, import_idx, num_import_syms);
606 import_idx += files[filenum].nsyms;
607 } else {
608 store_symbols((char *) files[filenum].mapped, files[filenum].mapped_size,
609 export_symbols, export_idx, num_export_syms);
610 export_idx += files[filenum].nsyms;
611 }
612 if (false && !files[filenum].nsyms) {
613 fprintf(stderr, "warning: file %s contains no names\n", files[filenum].path);
614 }
615 }
616
617
618 qsort(import_symbols, num_import_syms, sizeof(struct symbol), &qsort_cmp);
619 qsort(export_symbols, num_export_syms, sizeof(struct symbol), &qsort_cmp);
620
621 result_count = 0;
622 num_removed_syms = 0;
623 strtabsize = 4;
624 if (num_import_syms) {
625 for (export_idx = 0; export_idx < num_export_syms; export_idx++) {
626 struct symbol * result;
627 char * name;
628 size_t len;
629 boolean_t wild;
630
631 name = export_symbols[export_idx].indirect;
632 len = export_symbols[export_idx].indirect_len;
633 if (!name) {
634 name = export_symbols[export_idx].name;
635 len = export_symbols[export_idx].name_len;
636 }
637 wild = ((len > 2) && ('*' == name[len -= 2]));
638 if (wild) {
639 struct bsearch_key key;
640 key.name = name;
641 key.name_len = len;
642 result = bsearch(&key, import_symbols,
643 num_import_syms, sizeof(struct symbol), &bsearch_cmp_prefix);
644
645 if (result) {
646 struct symbol * first;
647 struct symbol * last;
648
649 strtabsize += (result->name_len + result->indirect_len);
650
651 first = result;
652 while (--first >= &import_symbols[0]) {
653 if (bsearch_cmp_prefix(&key, first)) {
654 break;
655 }
656 strtabsize += (first->name_len + first->indirect_len);
657 }
658 first++;
659
660 last = result;
661 while (++last < (&import_symbols[0] + num_import_syms)) {
662 if (bsearch_cmp_prefix(&key, last)) {
663 break;
664 }
665 strtabsize += (last->name_len + last->indirect_len);
666 }
667 result_count += last - first;
668 result = first;
669 export_symbols[export_idx].list = first;
670 export_symbols[export_idx].list_count = last - first;
671 export_symbols[export_idx].flags |= kExported;
672 }
673 } else {
674 result = bsearch(name, import_symbols,
675 num_import_syms, sizeof(struct symbol), &bsearch_cmp);
676 }
677
678 if (!result && require_imports) {
679 int status;
680 char * demangled_result =
681 __cxa_demangle(export_symbols[export_idx].name + 1, NULL, NULL, &status);
682 fprintf(stderr, "exported name not in import list: %s\n",
683 demangled_result ? demangled_result : export_symbols[export_idx].name);
684 // fprintf(stderr, " : %s\n", export_symbols[export_idx].name);
685 if (demangled_result) {
686 free(demangled_result);
687 }
688 num_removed_syms++;
689 }
690 if (diff) {
691 if (!result) {
692 result = &export_symbols[export_idx];
693 } else {
694 result = NULL;
695 }
696 }
697 if (result && !wild) {
698 export_symbols[export_idx].flags |= kExported;
699 strtabsize += (export_symbols[export_idx].name_len + export_symbols[export_idx].indirect_len);
700 result_count++;
701 export_symbols[export_idx].list = &export_symbols[export_idx];
702 export_symbols[export_idx].list_count = 1;
703 }
704 }
705 }
706 strtabpad = (strtabsize + 3) & ~3;
707
708 if (require_imports && num_removed_syms) {
709 err = kError;
710 goto finish;
711 }
712
713 fd = open(output_name, O_WRONLY | O_CREAT | O_TRUNC, 0755);
714 if (-1 == fd) {
715 perror("couldn't write output");
716 err = kErrorFileAccess;
717 goto finish;
718 }
719
720 struct symtab_command symcmd;
721 struct uuid_command uuidcmd;
722 off_t symsoffset;
723
724 symcmd.cmd = LC_SYMTAB;
725 symcmd.cmdsize = sizeof(symcmd);
726 symcmd.nsyms = result_count;
727 symcmd.strsize = strtabpad;
728
729 uuidcmd.cmd = LC_UUID;
730 uuidcmd.cmdsize = sizeof(uuidcmd);
731 uuid_generate(uuidcmd.uuid);
732
733 if (CPU_ARCH_ABI64 & target_arch->cputype) {
734 struct mach_header_64 hdr;
735 struct segment_command_64 segcmd;
736
737 hdr.magic = MH_MAGIC_64;
738 hdr.cputype = target_arch->cputype;
739 hdr.cpusubtype = target_arch->cpusubtype;
740 hdr.filetype = MH_KEXT_BUNDLE;
741 hdr.ncmds = 3;
742 hdr.sizeofcmds = sizeof(segcmd) + sizeof(symcmd) + sizeof(uuidcmd);
743 hdr.flags = MH_INCRLINK;
744 symsoffset = mach_vm_round_page(hdr.sizeofcmds);
745
746 segcmd.cmd = LC_SEGMENT_64;
747 segcmd.cmdsize = sizeof(segcmd);
748 strncpy(segcmd.segname, SEG_LINKEDIT, sizeof(segcmd.segname));
749 segcmd.vmaddr = 0;
750 segcmd.vmsize = result_count * sizeof(struct nlist_64) + strtabpad;
751 segcmd.fileoff = symsoffset;
752 segcmd.filesize = segcmd.vmsize;
753 segcmd.maxprot = PROT_READ;
754 segcmd.initprot = PROT_READ;
755 segcmd.nsects = 0;
756 segcmd.flags = SG_NORELOC;
757
758 symcmd.symoff = symsoffset;
759 symcmd.stroff = result_count * sizeof(struct nlist_64)
760 + symcmd.symoff;
761
762 if (target_arch->byteorder != host_arch->byteorder) {
763 swap_mach_header_64(&hdr, target_arch->byteorder);
764 swap_segment_command_64(&segcmd, target_arch->byteorder);
765 }
766 err = writeFile(fd, &hdr, sizeof(hdr));
767 if (kErrorNone != err) {
768 goto finish;
769 }
770 err = writeFile(fd, &segcmd, sizeof(segcmd));
771 } else {
772 struct mach_header hdr;
773 struct segment_command segcmd;
774
775 hdr.magic = MH_MAGIC;
776 hdr.cputype = target_arch->cputype;
777 hdr.cpusubtype = target_arch->cpusubtype;
778 hdr.filetype = MH_KEXT_BUNDLE;
779 hdr.ncmds = 3;
780 hdr.sizeofcmds = sizeof(segcmd) + sizeof(symcmd) + sizeof(uuidcmd);
781 hdr.flags = MH_INCRLINK;
782 symsoffset = mach_vm_round_page(hdr.sizeofcmds);
783
784 segcmd.cmd = LC_SEGMENT;
785 segcmd.cmdsize = sizeof(segcmd);
786 strncpy(segcmd.segname, SEG_LINKEDIT, sizeof(segcmd.segname));
787 segcmd.vmaddr = 0;
788 segcmd.vmsize = result_count * sizeof(struct nlist) + strtabpad;
789 segcmd.fileoff = symsoffset;
790 segcmd.filesize = segcmd.vmsize;
791 segcmd.maxprot = PROT_READ;
792 segcmd.initprot = PROT_READ;
793 segcmd.nsects = 0;
794 segcmd.flags = SG_NORELOC;
795
796 symcmd.symoff = symsoffset;
797 symcmd.stroff = result_count * sizeof(struct nlist)
798 + symcmd.symoff;
799
800 if (target_arch->byteorder != host_arch->byteorder) {
801 swap_mach_header(&hdr, target_arch->byteorder);
802 swap_segment_command(&segcmd, target_arch->byteorder);
803 }
804 err = writeFile(fd, &hdr, sizeof(hdr));
805 if (kErrorNone != err) {
806 goto finish;
807 }
808 err = writeFile(fd, &segcmd, sizeof(segcmd));
809 }
810
811 if (kErrorNone != err) {
812 goto finish;
813 }
814
815 if (target_arch->byteorder != host_arch->byteorder) {
816 swap_symtab_command(&symcmd, target_arch->byteorder);
817 swap_uuid_command(&uuidcmd, target_arch->byteorder);
818 }
819 err = writeFile(fd, &symcmd, sizeof(symcmd));
820 if (kErrorNone != err) {
821 goto finish;
822 }
823 err = writeFile(fd, &uuidcmd, sizeof(uuidcmd));
824 if (kErrorNone != err) {
825 goto finish;
826 }
827
828 err = seekFile(fd, symsoffset);
829 if (kErrorNone != err) {
830 goto finish;
831 }
832
833 strx = 4;
834 for (export_idx = 0; export_idx < num_export_syms; export_idx++) {
835 if (!export_symbols[export_idx].name) {
836 continue;
837 }
838 if (!(kExported & export_symbols[export_idx].flags)) {
839 continue;
840 }
841
842 if (export_idx
843 && export_symbols[export_idx - 1].name
844 && !strcmp(export_symbols[export_idx - 1].name, export_symbols[export_idx].name)) {
845 fprintf(stderr, "duplicate export: %s\n", export_symbols[export_idx - 1].name);
846 err = kErrorDuplicate;
847 goto finish;
848 }
849
850 for (import_idx = 0; import_idx < export_symbols[export_idx].list_count; import_idx++) {
851 if (export_symbols[export_idx].list != &export_symbols[export_idx]) {
852 printf("wild: %s, %s\n", export_symbols[export_idx].name,
853 export_symbols[export_idx].list[import_idx].name);
854 }
855 if (CPU_ARCH_ABI64 & target_arch->cputype) {
856 struct nlist_64 nl;
857
858 nl.n_sect = 0;
859 nl.n_desc = 0;
860 nl.n_un.n_strx = strx;
861 strx += export_symbols[export_idx].list[import_idx].name_len;
862
863 if (export_symbols[export_idx].flags & kObsolete) {
864 nl.n_desc |= N_DESC_DISCARDED;
865 }
866
867 if (export_symbols[export_idx].list[import_idx].indirect) {
868 nl.n_type = N_INDR | N_EXT;
869 nl.n_value = strx;
870 strx += export_symbols[export_idx].list[import_idx].indirect_len;
871 } else {
872 nl.n_type = N_UNDF | N_EXT;
873 nl.n_value = 0;
874 }
875
876 if (target_arch->byteorder != host_arch->byteorder) {
877 swap_nlist_64(&nl, 1, target_arch->byteorder);
878 }
879
880 err = writeFile(fd, &nl, sizeof(nl));
881 } else {
882 struct nlist nl;
883
884 nl.n_sect = 0;
885 nl.n_desc = 0;
886 nl.n_un.n_strx = strx;
887 strx += export_symbols[export_idx].list[import_idx].name_len;
888
889 if (export_symbols[export_idx].flags & kObsolete) {
890 nl.n_desc |= N_DESC_DISCARDED;
891 }
892
893 if (export_symbols[export_idx].list[import_idx].indirect) {
894 nl.n_type = N_INDR | N_EXT;
895 nl.n_value = strx;
896 strx += export_symbols[export_idx].list[import_idx].indirect_len;
897 } else {
898 nl.n_type = N_UNDF | N_EXT;
899 nl.n_value = 0;
900 }
901
902 if (target_arch->byteorder != host_arch->byteorder) {
903 swap_nlist(&nl, 1, target_arch->byteorder);
904 }
905
906 err = writeFile(fd, &nl, sizeof(nl));
907 }
908 }
909
910 if (kErrorNone != err) {
911 goto finish;
912 }
913 }
914
915 strx = sizeof(uint32_t);
916 err = writeFile(fd, &zero, strx);
917 if (kErrorNone != err) {
918 goto finish;
919 }
920
921 for (export_idx = 0; export_idx < num_export_syms; export_idx++) {
922 if (!export_symbols[export_idx].name) {
923 continue;
924 }
925
926 for (import_idx = 0; import_idx < export_symbols[export_idx].list_count; import_idx++) {
927 err = writeFile(fd, export_symbols[export_idx].list[import_idx].name,
928 export_symbols[export_idx].list[import_idx].name_len);
929 if (kErrorNone != err) {
930 goto finish;
931 }
932 if (export_symbols[export_idx].list[import_idx].indirect) {
933 err = writeFile(fd, export_symbols[export_idx].list[import_idx].indirect,
934 export_symbols[export_idx].list[import_idx].indirect_len);
935 if (kErrorNone != err) {
936 goto finish;
937 }
938 }
939 }
940 }
941
942 err = writeFile(fd, &zero, strtabpad - strtabsize);
943 if (kErrorNone != err) {
944 goto finish;
945 }
946
947 close(fd);
948
949
950 finish:
951 for (filenum = 0; filenum < num_files; filenum++) {
952 // unmap file
953 if (files[filenum].mapped_size) {
954 munmap((caddr_t)files[filenum].mapped, files[filenum].mapped_size);
955 files[filenum].mapped = 0;
956 files[filenum].mapped_size = 0;
957 }
958 }
959
960 if (kErrorNone != err) {
961 if (output_name && strncmp(output_name, "/dev/", 5)) {
962 unlink(output_name);
963 }
964 exit(1);
965 } else {
966 exit(0);
967 }
968 return 0;
969 }