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