]> git.saurik.com Git - apple/xnu.git/blame - SETUP/kextsymboltool/kextsymboltool.c
xnu-2422.1.72.tar.gz
[apple/xnu.git] / SETUP / kextsymboltool / kextsymboltool.c
CommitLineData
6d2010ae
A
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
39236c6e
A
27#include <mach/mach_init.h>
28
6d2010ae
A
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>
39236c6e 40#include <stdbool.h>
6d2010ae
A
41
42#pragma mark Typedefs, Enums, Constants
43/*********************************************************************
44* Typedefs, Enums, Constants
45*********************************************************************/
46typedef 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
59readFile(const char *path, vm_offset_t * objAddr, vm_size_t * objSize);
60
61__private_extern__ ToolError
62writeFile(int fd, const void * data, size_t length);
63
39236c6e
A
64__private_extern__ ToolError
65seekFile(int fd, off_t offset);
66
6d2010ae
A
67extern 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
76writeFile(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
39236c6e
A
91 /*********************************************************************
92 *********************************************************************/
93__private_extern__ ToolError
94seekFile(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
6d2010ae
A
109/*********************************************************************
110*********************************************************************/
111__private_extern__ ToolError
112readFile(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
169enum { kExported = 0x00000001, kObsolete = 0x00000002 };
170
171struct 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
181static bool issymchar( char c )
182{
183 return ((c > ' ') && (c <= '~') && (c != ':') && (c != '#'));
184}
185
186static bool iswhitespace( char c )
187{
188 return ((c == ' ') || (c == '\t'));
189}
190
191/*
192 * Function for qsort for comparing symbol list names.
193 */
194static int
195qsort_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
207static int
208bsearch_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
216struct bsearch_key
217{
218 char * name;
219 unsigned int name_len;
220};
221
222static int
223bsearch_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
231static uint32_t
232count_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
281static uint32_t
282store_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/*********************************************************************
468*********************************************************************/
469int main(int argc, char * argv[])
470{
471 ToolError err;
472 int i, fd;
473 const char * output_name = NULL;
474 uint32_t zero = 0, num_files = 0;
475 uint32_t filenum;
476 uint32_t strx, strtabsize, strtabpad;
477 struct symbol * import_symbols;
478 struct symbol * export_symbols;
479 uint32_t num_import_syms, num_export_syms;
480 uint32_t result_count, num_removed_syms;
481 uint32_t import_idx, export_idx;
482 const NXArchInfo * host_arch;
483 const NXArchInfo * target_arch;
484 boolean_t require_imports = true;
485 boolean_t diff = false;
486
487
488 struct file {
489 vm_offset_t mapped;
490 vm_size_t mapped_size;
491 uint32_t nsyms;
492 boolean_t import;
493 const char * path;
494 };
495 struct file files[64];
496
497 host_arch = NXGetLocalArchInfo();
498 target_arch = host_arch;
499
500 for( i = 1; i < argc; i += 2)
501 {
502 boolean_t import;
503
504 if (!strcmp("-sect", argv[i]))
505 {
506 require_imports = false;
507 i--;
508 continue;
509 }
510 if (!strcmp("-diff", argv[i]))
511 {
512 require_imports = false;
513 diff = true;
514 i--;
515 continue;
516 }
517
518 if (i == (argc - 1))
519 {
520 fprintf(stderr, "bad arguments: %s\n", argv[i]);
521 exit(1);
522 }
523
524 if (!strcmp("-arch", argv[i]))
525 {
526 target_arch = NXGetArchInfoFromName(argv[i + 1]);
527 if (!target_arch)
528 {
529 fprintf(stderr, "unknown architecture name: %s\n", argv[i+1]);
530 exit(1);
531 }
532 continue;
533 }
534 if (!strcmp("-output", argv[i]))
535 {
536 output_name = argv[i+1];
537 continue;
538 }
539
540 if (!strcmp("-import", argv[i]))
541 import = true;
542 else if (!strcmp("-export", argv[i]))
543 import = false;
544 else
545 {
546 fprintf(stderr, "unknown option: %s\n", argv[i]);
547 exit(1);
548 }
549
550 err = readFile(argv[i+1], &files[num_files].mapped, &files[num_files].mapped_size);
551 if (kErrorNone != err)
552 exit(1);
553
554 if (files[num_files].mapped && files[num_files].mapped_size)
555 {
556 files[num_files].import = import;
557 files[num_files].path = argv[i+1];
558 num_files++;
559 }
560 }
561
562 if (!output_name)
563 {
564 fprintf(stderr, "no output file\n");
565 exit(1);
566 }
567
568 num_import_syms = 0;
569 num_export_syms = 0;
570 for (filenum = 0; filenum < num_files; filenum++)
571 {
572 files[filenum].nsyms = count_symbols((char *) files[filenum].mapped, files[filenum].mapped_size);
573 if (files[filenum].import)
574 num_import_syms += files[filenum].nsyms;
575 else
576 num_export_syms += files[filenum].nsyms;
577 }
578 if (!num_export_syms)
579 {
580 fprintf(stderr, "no export names\n");
581 exit(1);
582 }
583
584 import_symbols = calloc(num_import_syms, sizeof(struct symbol));
585 export_symbols = calloc(num_export_syms, sizeof(struct symbol));
586
587 import_idx = 0;
588 export_idx = 0;
589
590 for (filenum = 0; filenum < num_files; filenum++)
591 {
592 if (files[filenum].import)
593 {
594 store_symbols((char *) files[filenum].mapped, files[filenum].mapped_size,
595 import_symbols, import_idx, num_import_syms);
596 import_idx += files[filenum].nsyms;
597 }
598 else
599 {
600 store_symbols((char *) files[filenum].mapped, files[filenum].mapped_size,
601 export_symbols, export_idx, num_export_syms);
602 export_idx += files[filenum].nsyms;
603 }
604 if (false && !files[filenum].nsyms)
605 {
606 fprintf(stderr, "warning: file %s contains no names\n", files[filenum].path);
607 }
608 }
609
610
611 qsort(import_symbols, num_import_syms, sizeof(struct symbol), &qsort_cmp);
612 qsort(export_symbols, num_export_syms, sizeof(struct symbol), &qsort_cmp);
613
614 result_count = 0;
615 num_removed_syms = 0;
616 strtabsize = 4;
617 if (num_import_syms)
618 {
619 for (export_idx = 0; export_idx < num_export_syms; export_idx++)
620 {
621 struct symbol * result;
622 char * name;
623 size_t len;
624 boolean_t wild;
625
626 name = export_symbols[export_idx].indirect;
627 len = export_symbols[export_idx].indirect_len;
628 if (!name)
629 {
630 name = export_symbols[export_idx].name;
631 len = export_symbols[export_idx].name_len;
632 }
633 wild = ((len > 2) && ('*' == name[len-=2]));
634 if (wild)
635 {
636 struct bsearch_key key;
637 key.name = name;
638 key.name_len = len;
639 result = bsearch(&key, import_symbols,
640 num_import_syms, sizeof(struct symbol), &bsearch_cmp_prefix);
641
642 if (result)
643 {
644 struct symbol * first;
645 struct symbol * last;
646
647 strtabsize += (result->name_len + result->indirect_len);
648
649 first = result;
650 while (--first >= &import_symbols[0])
651 {
652 if (bsearch_cmp_prefix(&key, first))
653 break;
654 strtabsize += (first->name_len + first->indirect_len);
655 }
656 first++;
657
658 last = result;
659 while (++last < (&import_symbols[0] + num_import_syms))
660 {
661 if (bsearch_cmp_prefix(&key, last))
662 break;
663 strtabsize += (last->name_len + last->indirect_len);
664 }
665 result_count += last - first;
666 result = first;
667 export_symbols[export_idx].list = first;
668 export_symbols[export_idx].list_count = last - first;
669 export_symbols[export_idx].flags |= kExported;
670 }
671 }
672 else
673 result = bsearch(name, import_symbols,
674 num_import_syms, sizeof(struct symbol), &bsearch_cmp);
675
676 if (!result && require_imports)
677 {
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 {
691 if (!result)
692 result = &export_symbols[export_idx];
693 else
694 result = NULL;
695 }
696 if (result && !wild)
697 {
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 {
710 err = kError;
711 goto finish;
712 }
713
714 fd = open(output_name, O_WRONLY|O_CREAT|O_TRUNC, 0755);
715 if (-1 == fd)
716 {
717 perror("couldn't write output");
718 err = kErrorFileAccess;
719 goto finish;
720 }
721
722 struct symtab_command symcmd;
723 struct uuid_command uuidcmd;
39236c6e 724 off_t symsoffset;
6d2010ae
A
725
726 symcmd.cmd = LC_SYMTAB;
727 symcmd.cmdsize = sizeof(symcmd);
6d2010ae
A
728 symcmd.nsyms = result_count;
729 symcmd.strsize = strtabpad;
730
731 uuidcmd.cmd = LC_UUID;
732 uuidcmd.cmdsize = sizeof(uuidcmd);
733 uuid_generate(uuidcmd.uuid);
734
735 if (CPU_ARCH_ABI64 & target_arch->cputype)
736 {
39236c6e
A
737 struct mach_header_64 hdr;
738 struct segment_command_64 segcmd;
739
6d2010ae
A
740 hdr.magic = MH_MAGIC_64;
741 hdr.cputype = target_arch->cputype;
742 hdr.cpusubtype = target_arch->cpusubtype;
743 hdr.filetype = MH_KEXT_BUNDLE;
39236c6e
A
744 hdr.ncmds = 3;
745 hdr.sizeofcmds = sizeof(segcmd) + sizeof(symcmd) + sizeof(uuidcmd);
6d2010ae 746 hdr.flags = MH_INCRLINK;
39236c6e
A
747 symsoffset = mach_vm_round_page(hdr.sizeofcmds);
748
749 segcmd.cmd = LC_SEGMENT_64;
750 segcmd.cmdsize = sizeof(segcmd);
751 strncpy(segcmd.segname, SEG_LINKEDIT, sizeof(segcmd.segname));
752 segcmd.vmaddr = 0;
753 segcmd.vmsize = result_count * sizeof(struct nlist_64) + strtabpad;
754 segcmd.fileoff = symsoffset;
755 segcmd.filesize = segcmd.vmsize;
756 segcmd.maxprot = PROT_READ;
757 segcmd.initprot = PROT_READ;
758 segcmd.nsects = 0;
759 segcmd.flags = SG_NORELOC;
760
761 symcmd.symoff = symsoffset;
6d2010ae
A
762 symcmd.stroff = result_count * sizeof(struct nlist_64)
763 + symcmd.symoff;
764
765 if (target_arch->byteorder != host_arch->byteorder)
39236c6e 766 {
6d2010ae 767 swap_mach_header_64(&hdr, target_arch->byteorder);
39236c6e
A
768 swap_segment_command_64(&segcmd, target_arch->byteorder);
769 }
6d2010ae 770 err = writeFile(fd, &hdr, sizeof(hdr));
39236c6e
A
771 if (kErrorNone != err)
772 goto finish;
773 err = writeFile(fd, &segcmd, sizeof(segcmd));
6d2010ae
A
774 }
775 else
776 {
39236c6e
A
777 struct mach_header hdr;
778 struct segment_command segcmd;
779
6d2010ae
A
780 hdr.magic = MH_MAGIC;
781 hdr.cputype = target_arch->cputype;
782 hdr.cpusubtype = target_arch->cpusubtype;
783 hdr.filetype = (target_arch->cputype == CPU_TYPE_I386) ? MH_OBJECT : MH_KEXT_BUNDLE;
39236c6e
A
784 hdr.ncmds = 3;
785 hdr.sizeofcmds = sizeof(segcmd) + sizeof(symcmd) + sizeof(uuidcmd);
6d2010ae 786 hdr.flags = MH_INCRLINK;
39236c6e
A
787 symsoffset = mach_vm_round_page(hdr.sizeofcmds);
788
789 segcmd.cmd = LC_SEGMENT;
790 segcmd.cmdsize = sizeof(segcmd);
791 strncpy(segcmd.segname, SEG_LINKEDIT, sizeof(segcmd.segname));
792 segcmd.vmaddr = 0;
793 segcmd.vmsize = result_count * sizeof(struct nlist) + strtabpad;
794 segcmd.fileoff = symsoffset;
795 segcmd.filesize = segcmd.vmsize;
796 segcmd.maxprot = PROT_READ;
797 segcmd.initprot = PROT_READ;
798 segcmd.nsects = 0;
799 segcmd.flags = SG_NORELOC;
800
801 symcmd.symoff = symsoffset;
6d2010ae
A
802 symcmd.stroff = result_count * sizeof(struct nlist)
803 + symcmd.symoff;
804
805 if (target_arch->byteorder != host_arch->byteorder)
39236c6e 806 {
6d2010ae 807 swap_mach_header(&hdr, target_arch->byteorder);
39236c6e
A
808 swap_segment_command(&segcmd, target_arch->byteorder);
809 }
6d2010ae 810 err = writeFile(fd, &hdr, sizeof(hdr));
39236c6e
A
811 if (kErrorNone != err)
812 goto finish;
813 err = writeFile(fd, &segcmd, sizeof(segcmd));
6d2010ae
A
814 }
815
816 if (kErrorNone != err)
817 goto finish;
818
819 if (target_arch->byteorder != host_arch->byteorder) {
820 swap_symtab_command(&symcmd, target_arch->byteorder);
821 swap_uuid_command(&uuidcmd, target_arch->byteorder);
822 }
823 err = writeFile(fd, &symcmd, sizeof(symcmd));
824 if (kErrorNone != err)
825 goto finish;
826 err = writeFile(fd, &uuidcmd, sizeof(uuidcmd));
827 if (kErrorNone != err)
828 goto finish;
829
39236c6e
A
830 err = seekFile(fd, symsoffset);
831 if (kErrorNone != err)
832 goto finish;
833
6d2010ae
A
834 strx = 4;
835 for (export_idx = 0; export_idx < num_export_syms; export_idx++)
836 {
837 if (!export_symbols[export_idx].name)
838 continue;
839 if (!(kExported & export_symbols[export_idx].flags))
840 continue;
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 {
846 fprintf(stderr, "duplicate export: %s\n", export_symbols[export_idx - 1].name);
847 err = kErrorDuplicate;
848 goto finish;
849 }
850
851 for (import_idx = 0; import_idx < export_symbols[export_idx].list_count; import_idx++)
852 {
853
854 if (export_symbols[export_idx].list != &export_symbols[export_idx])
855 {
856 printf("wild: %s, %s\n", export_symbols[export_idx].name,
857 export_symbols[export_idx].list[import_idx].name);
858 }
859 if (CPU_ARCH_ABI64 & target_arch->cputype)
860 {
861 struct nlist_64 nl;
862
863 nl.n_sect = 0;
864 nl.n_desc = 0;
865 nl.n_un.n_strx = strx;
866 strx += export_symbols[export_idx].list[import_idx].name_len;
867
868 if (export_symbols[export_idx].flags & kObsolete) {
869 nl.n_desc |= N_DESC_DISCARDED;
870 }
871
872 if (export_symbols[export_idx].list[import_idx].indirect)
873 {
874 nl.n_type = N_INDR | N_EXT;
875 nl.n_value = strx;
876 strx += export_symbols[export_idx].list[import_idx].indirect_len;
877 }
878 else
879 {
880 nl.n_type = N_UNDF | N_EXT;
881 nl.n_value = 0;
882 }
883
884 if (target_arch->byteorder != host_arch->byteorder)
885 swap_nlist_64(&nl, 1, target_arch->byteorder);
886
887 err = writeFile(fd, &nl, sizeof(nl));
888 }
889 else
890 {
891 struct nlist nl;
892
893 nl.n_sect = 0;
894 nl.n_desc = 0;
895 nl.n_un.n_strx = strx;
896 strx += export_symbols[export_idx].list[import_idx].name_len;
897
898 if (export_symbols[export_idx].flags & kObsolete) {
899 nl.n_desc |= N_DESC_DISCARDED;
900 }
901
902 if (export_symbols[export_idx].list[import_idx].indirect)
903 {
904 nl.n_type = N_INDR | N_EXT;
905 nl.n_value = strx;
906 strx += export_symbols[export_idx].list[import_idx].indirect_len;
907 }
908 else
909 {
910 nl.n_type = N_UNDF | N_EXT;
911 nl.n_value = 0;
912 }
913
914 if (target_arch->byteorder != host_arch->byteorder)
915 swap_nlist(&nl, 1, target_arch->byteorder);
916
917 err = writeFile(fd, &nl, sizeof(nl));
918 }
919 }
920
921 if (kErrorNone != err)
922 goto finish;
923 }
924
925 strx = sizeof(uint32_t);
926 err = writeFile(fd, &zero, strx);
927 if (kErrorNone != err)
928 goto finish;
929
930 for (export_idx = 0; export_idx < num_export_syms; export_idx++)
931 {
932 if (!export_symbols[export_idx].name)
933 continue;
934
935 for (import_idx = 0; import_idx < export_symbols[export_idx].list_count; import_idx++)
936 {
937 err = writeFile(fd, export_symbols[export_idx].list[import_idx].name,
938 export_symbols[export_idx].list[import_idx].name_len);
939 if (kErrorNone != err)
940 goto finish;
941 if (export_symbols[export_idx].list[import_idx].indirect)
942 {
943 err = writeFile(fd, export_symbols[export_idx].list[import_idx].indirect,
944 export_symbols[export_idx].list[import_idx].indirect_len);
945 if (kErrorNone != err)
946 goto finish;
947 }
948 }
949 }
950
951 err = writeFile(fd, &zero, strtabpad - strtabsize);
952 if (kErrorNone != err)
953 goto finish;
954
955 close(fd);
956
957
958finish:
959 for (filenum = 0; filenum < num_files; filenum++) {
960 // unmap file
961 if (files[filenum].mapped_size)
962 {
963 munmap((caddr_t)files[filenum].mapped, files[filenum].mapped_size);
964 files[filenum].mapped = 0;
965 files[filenum].mapped_size = 0;
966 }
967
968 }
969
970 if (kErrorNone != err)
971 {
972 if (output_name)
973 unlink(output_name);
974 exit(1);
975 }
976 else
977 exit(0);
978 return(0);
979}
980