2 * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
27 #include <mach/mach_init.h>
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>
39 #include <uuid/uuid.h>
42 #pragma mark Typedefs, Enums, Constants
43 /*********************************************************************
44 * Typedefs, Enums, Constants
45 *********************************************************************/
54 #pragma mark Function Protos
55 /*********************************************************************
57 *********************************************************************/
58 __private_extern__ ToolError
59 readFile(const char *path
, vm_offset_t
* objAddr
, vm_size_t
* objSize
);
61 __private_extern__ ToolError
62 writeFile(int fd
, const void * data
, size_t length
);
64 __private_extern__ ToolError
65 seekFile(int fd
, off_t offset
);
67 extern char* __cxa_demangle(const char* mangled_name
,
72 #pragma mark Functions
73 /*********************************************************************
74 *********************************************************************/
75 __private_extern__ ToolError
76 writeFile(int fd
, const void * data
, size_t length
)
80 if (length
!= (size_t)write(fd
, data
, length
)) {
86 if (kErrorNone
!= err
) {
87 perror("couldn't write output");
93 /*********************************************************************
94 *********************************************************************/
95 __private_extern__ ToolError
96 seekFile(int fd
, off_t offset
)
100 if (offset
!= lseek(fd
, offset
, SEEK_SET
)) {
101 err
= kErrorDiskFull
;
106 if (kErrorNone
!= err
) {
107 perror("couldn't write output");
113 /*********************************************************************
114 *********************************************************************/
115 __private_extern__ ToolError
116 readFile(const char *path
, vm_offset_t
* objAddr
, vm_size_t
* objSize
)
118 ToolError err
= kErrorFileAccess
;
120 struct stat stat_buf
;
126 if ((fd
= open(path
, O_RDONLY
)) == -1) {
130 if (fstat(fd
, &stat_buf
) == -1) {
134 if (0 == (stat_buf
.st_mode
& S_IFREG
)) {
138 /* Don't try to map an empty file, it fails now due to conformance
139 * stuff (PR 4611502).
141 if (0 == stat_buf
.st_size
) {
146 *objSize
= stat_buf
.st_size
;
148 *objAddr
= (vm_offset_t
)mmap(NULL
/* address */, *objSize
,
149 PROT_READ
| PROT_WRITE
, MAP_FILE
| MAP_PRIVATE
/* flags */,
152 if ((void *)*objAddr
== MAP_FAILED
) {
164 if (kErrorNone
!= err
) {
165 fprintf(stderr
, "couldn't read %s: %s\n", path
, strerror(errno
));
172 enum { kExported
= 0x00000001, kObsolete
= 0x00000002 };
176 unsigned int name_len
;
178 unsigned int indirect_len
;
180 struct symbol
* list
;
181 unsigned int list_count
;
187 return (c
> ' ') && (c
<= '~') && (c
!= ':') && (c
!= '#');
191 iswhitespace( char c
)
193 return (c
== ' ') || (c
== '\t');
197 * Function for qsort for comparing symbol list names.
200 qsort_cmp(const void * _left
, const void * _right
)
202 struct symbol
* left
= (struct symbol
*) _left
;
203 struct symbol
* right
= (struct symbol
*) _right
;
205 return strcmp(left
->name
, right
->name
);
209 * Function for bsearch for finding a symbol name.
213 bsearch_cmp( const void * _key
, const void * _cmp
)
215 char * key
= (char *)_key
;
216 struct symbol
* cmp
= (struct symbol
*) _cmp
;
218 return strcmp(key
, cmp
->name
);
223 unsigned int name_len
;
227 bsearch_cmp_prefix( const void * _key
, const void * _cmp
)
229 struct bsearch_key
* key
= (struct bsearch_key
*)_key
;
230 struct symbol
* cmp
= (struct symbol
*) _cmp
;
232 return strncmp(key
->name
, cmp
->name
, key
->name_len
);
236 count_symbols(char * file
, vm_size_t file_size
)
243 for (scan
= file
; true; scan
= next
) {
244 eol
= memchr(scan
, '\n', file_size
- (scan
- file
));
256 /* Skip comment lines.
258 if (scan
[0] == '#') {
262 /* Scan past any non-symbol characters at the beginning of the line. */
263 while ((scan
< eol
) && !issymchar(*scan
)) {
267 /* No symbol on line? Move along.
273 /* Skip symbols starting with '.'.
275 if (scan
[0] == '.') {
285 store_symbols(char * file
, vm_size_t file_size
, struct symbol
* symbols
, uint32_t idx
, uint32_t max_symbols
)
296 for (scan
= file
, line
= file
; true; scan
= next
, line
= next
) {
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;
307 boolean_t obsolete
= 0;
309 eol
= memchr(scan
, '\n', file_size
- (scan
- file
));
323 /* Skip comment lines.
325 if (scan
[0] == '#') {
329 /* Scan past any non-symbol characters at the beginning of the line. */
330 while ((scan
< eol
) && !issymchar(*scan
)) {
334 /* No symbol on line? Move along.
340 /* Skip symbols starting with '.'.
342 if (scan
[0] == '.') {
348 /* Find the end of the symbol.
350 while ((*scan
!= '\0') && issymchar(*scan
)) {
354 /* Note char past end of symbol.
358 /* Stored length must include the terminating nul char.
360 name_len
= name_term
- name
+ 1;
362 /* Now look for an indirect.
365 while ((*scan
!= '\0') && iswhitespace(*scan
)) {
370 while ((*scan
!= '\0') && iswhitespace(*scan
)) {
373 if (issymchar(*scan
)) {
376 /* Find the end of the symbol.
378 while ((*scan
!= '\0') && issymchar(*scan
)) {
382 /* Note char past end of symbol.
384 indirect_term
= scan
;
386 /* Stored length must include the terminating nul char.
388 indirect_len
= indirect_term
- indirect
+ 1;
389 } else if (*scan
== '\0') {
390 fprintf(stderr
, "bad format in symbol line: %s\n", line
);
393 } else if (*scan
!= '\0' && *scan
!= '-') {
394 fprintf(stderr
, "bad format in symbol line: %s\n", line
);
402 while ((*scan
!= '\0') && iswhitespace(*scan
)) {
409 if (isalpha(*scan
)) {
412 /* Find the end of the option.
414 while ((*scan
!= '\0') && isalpha(*scan
)) {
418 /* Note char past end of option.
421 option_len
= option_term
- option
;
423 if (option_len
>= sizeof(optionstr
)) {
424 fprintf(stderr
, "option too long in symbol line: %s\n", line
);
427 memcpy(optionstr
, option
, option_len
);
428 optionstr
[option_len
] = '\0';
432 if (!strncmp(optionstr
, "obsolete", option_len
)) {
435 } else if (*scan
== '\0') {
436 fprintf(stderr
, "bad format in symbol line: %s\n", line
);
442 if (idx
>= max_symbols
) {
443 fprintf(stderr
, "symbol[%d/%d] overflow: %s\n", idx
, max_symbols
, line
);
449 *indirect_term
= '\0';
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;
458 strtabsize
+= symbols
[idx
].name_len
+ symbols
[idx
].indirect_len
;
465 static const NXArchInfo
*
466 lookup_arch(const char *archstring
)
469 * As new architectures are supported by xnu, add a mapping function
470 * without relying on host libraries.
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
},
482 for (i
= 0; i
< sizeof(archlist
) / sizeof(archlist
[0]); i
++) {
483 if (0 == strcmp(archstring
, archlist
[i
].name
)) {
491 /*********************************************************************
492 *********************************************************************/
494 main(int argc
, char * argv
[])
498 const char * output_name
= NULL
;
499 uint32_t zero
= 0, num_files
= 0;
501 uint32_t strx
, strtabsize
, strtabpad
;
502 struct symbol
* import_symbols
;
503 struct symbol
* export_symbols
;
504 uint32_t num_import_syms
, num_export_syms
;
505 uint32_t result_count
, num_removed_syms
;
506 uint32_t import_idx
, export_idx
;
507 const NXArchInfo
* host_arch
;
508 const NXArchInfo
* target_arch
;
509 boolean_t require_imports
= true;
510 boolean_t diff
= false;
515 vm_size_t mapped_size
;
520 struct file files
[64];
522 host_arch
= NXGetLocalArchInfo();
523 target_arch
= host_arch
;
525 for (i
= 1; i
< argc
; i
+= 2) {
528 if (!strcmp("-sect", argv
[i
])) {
529 require_imports
= false;
533 if (!strcmp("-diff", argv
[i
])) {
534 require_imports
= false;
540 if (i
== (argc
- 1)) {
541 fprintf(stderr
, "bad arguments: %s\n", argv
[i
]);
545 if (!strcmp("-arch", argv
[i
])) {
546 target_arch
= lookup_arch(argv
[i
+ 1]);
548 fprintf(stderr
, "unknown architecture name: %s\n", argv
[i
+ 1]);
553 if (!strcmp("-output", argv
[i
])) {
554 output_name
= argv
[i
+ 1];
558 if (!strcmp("-import", argv
[i
])) {
560 } else if (!strcmp("-export", argv
[i
])) {
563 fprintf(stderr
, "unknown option: %s\n", argv
[i
]);
567 err
= readFile(argv
[i
+ 1], &files
[num_files
].mapped
, &files
[num_files
].mapped_size
);
568 if (kErrorNone
!= err
) {
572 if (files
[num_files
].mapped
&& files
[num_files
].mapped_size
) {
573 files
[num_files
].import = import;
574 files
[num_files
].path
= argv
[i
+ 1];
580 fprintf(stderr
, "no output file\n");
586 for (filenum
= 0; filenum
< num_files
; filenum
++) {
587 files
[filenum
].nsyms
= count_symbols((char *) files
[filenum
].mapped
, files
[filenum
].mapped_size
);
588 if (files
[filenum
].import) {
589 num_import_syms
+= files
[filenum
].nsyms
;
591 num_export_syms
+= files
[filenum
].nsyms
;
595 import_symbols
= calloc(num_import_syms
, sizeof(struct symbol
));
596 export_symbols
= calloc(num_export_syms
, sizeof(struct symbol
));
601 for (filenum
= 0; filenum
< num_files
; filenum
++) {
602 if (files
[filenum
].import) {
603 store_symbols((char *) files
[filenum
].mapped
, files
[filenum
].mapped_size
,
604 import_symbols
, import_idx
, num_import_syms
);
605 import_idx
+= files
[filenum
].nsyms
;
607 store_symbols((char *) files
[filenum
].mapped
, files
[filenum
].mapped_size
,
608 export_symbols
, export_idx
, num_export_syms
);
609 export_idx
+= files
[filenum
].nsyms
;
611 if (false && !files
[filenum
].nsyms
) {
612 fprintf(stderr
, "warning: file %s contains no names\n", files
[filenum
].path
);
617 qsort(import_symbols
, num_import_syms
, sizeof(struct symbol
), &qsort_cmp
);
618 qsort(export_symbols
, num_export_syms
, sizeof(struct symbol
), &qsort_cmp
);
621 num_removed_syms
= 0;
623 if (num_import_syms
) {
624 for (export_idx
= 0; export_idx
< num_export_syms
; export_idx
++) {
625 struct symbol
* result
;
630 name
= export_symbols
[export_idx
].indirect
;
631 len
= export_symbols
[export_idx
].indirect_len
;
633 name
= export_symbols
[export_idx
].name
;
634 len
= export_symbols
[export_idx
].name_len
;
636 wild
= ((len
> 2) && ('*' == name
[len
-= 2]));
638 struct bsearch_key key
;
641 result
= bsearch(&key
, import_symbols
,
642 num_import_syms
, sizeof(struct symbol
), &bsearch_cmp_prefix
);
645 struct symbol
* first
;
646 struct symbol
* last
;
648 strtabsize
+= (result
->name_len
+ result
->indirect_len
);
651 while (--first
>= &import_symbols
[0]) {
652 if (bsearch_cmp_prefix(&key
, first
)) {
655 strtabsize
+= (first
->name_len
+ first
->indirect_len
);
660 while (++last
< (&import_symbols
[0] + num_import_syms
)) {
661 if (bsearch_cmp_prefix(&key
, last
)) {
664 strtabsize
+= (last
->name_len
+ last
->indirect_len
);
666 result_count
+= last
- first
;
668 export_symbols
[export_idx
].list
= first
;
669 export_symbols
[export_idx
].list_count
= last
- first
;
670 export_symbols
[export_idx
].flags
|= kExported
;
673 result
= bsearch(name
, import_symbols
,
674 num_import_syms
, sizeof(struct symbol
), &bsearch_cmp
);
677 if (!result
&& require_imports
) {
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
);
691 result
= &export_symbols
[export_idx
];
696 if (result
&& !wild
) {
697 export_symbols
[export_idx
].flags
|= kExported
;
698 strtabsize
+= (export_symbols
[export_idx
].name_len
+ export_symbols
[export_idx
].indirect_len
);
700 export_symbols
[export_idx
].list
= &export_symbols
[export_idx
];
701 export_symbols
[export_idx
].list_count
= 1;
705 strtabpad
= (strtabsize
+ 3) & ~3;
707 if (require_imports
&& num_removed_syms
) {
712 fd
= open(output_name
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0755);
714 perror("couldn't write output");
715 err
= kErrorFileAccess
;
719 struct symtab_command symcmd
;
720 struct uuid_command uuidcmd
;
723 symcmd
.cmd
= LC_SYMTAB
;
724 symcmd
.cmdsize
= sizeof(symcmd
);
725 symcmd
.nsyms
= result_count
;
726 symcmd
.strsize
= strtabpad
;
728 uuidcmd
.cmd
= LC_UUID
;
729 uuidcmd
.cmdsize
= sizeof(uuidcmd
);
730 uuid_generate(uuidcmd
.uuid
);
732 if (CPU_ARCH_ABI64
& target_arch
->cputype
) {
733 struct mach_header_64 hdr
;
734 struct segment_command_64 segcmd
;
736 hdr
.magic
= MH_MAGIC_64
;
737 hdr
.cputype
= target_arch
->cputype
;
738 hdr
.cpusubtype
= target_arch
->cpusubtype
;
739 hdr
.filetype
= MH_KEXT_BUNDLE
;
741 hdr
.sizeofcmds
= sizeof(segcmd
) + sizeof(symcmd
) + sizeof(uuidcmd
);
742 hdr
.flags
= MH_INCRLINK
;
743 symsoffset
= mach_vm_round_page(hdr
.sizeofcmds
);
745 segcmd
.cmd
= LC_SEGMENT_64
;
746 segcmd
.cmdsize
= sizeof(segcmd
);
747 strncpy(segcmd
.segname
, SEG_LINKEDIT
, sizeof(segcmd
.segname
));
749 segcmd
.vmsize
= result_count
* sizeof(struct nlist_64
) + strtabpad
;
750 segcmd
.fileoff
= symsoffset
;
751 segcmd
.filesize
= segcmd
.vmsize
;
752 segcmd
.maxprot
= PROT_READ
;
753 segcmd
.initprot
= PROT_READ
;
755 segcmd
.flags
= SG_NORELOC
;
757 symcmd
.symoff
= symsoffset
;
758 symcmd
.stroff
= result_count
* sizeof(struct nlist_64
)
761 if (target_arch
->byteorder
!= host_arch
->byteorder
) {
762 swap_mach_header_64(&hdr
, target_arch
->byteorder
);
763 swap_segment_command_64(&segcmd
, target_arch
->byteorder
);
765 err
= writeFile(fd
, &hdr
, sizeof(hdr
));
766 if (kErrorNone
!= err
) {
769 err
= writeFile(fd
, &segcmd
, sizeof(segcmd
));
771 struct mach_header hdr
;
772 struct segment_command segcmd
;
774 hdr
.magic
= MH_MAGIC
;
775 hdr
.cputype
= target_arch
->cputype
;
776 hdr
.cpusubtype
= target_arch
->cpusubtype
;
777 hdr
.filetype
= MH_KEXT_BUNDLE
;
779 hdr
.sizeofcmds
= sizeof(segcmd
) + sizeof(symcmd
) + sizeof(uuidcmd
);
780 hdr
.flags
= MH_INCRLINK
;
781 symsoffset
= mach_vm_round_page(hdr
.sizeofcmds
);
783 segcmd
.cmd
= LC_SEGMENT
;
784 segcmd
.cmdsize
= sizeof(segcmd
);
785 strncpy(segcmd
.segname
, SEG_LINKEDIT
, sizeof(segcmd
.segname
));
787 segcmd
.vmsize
= result_count
* sizeof(struct nlist
) + strtabpad
;
788 segcmd
.fileoff
= symsoffset
;
789 segcmd
.filesize
= segcmd
.vmsize
;
790 segcmd
.maxprot
= PROT_READ
;
791 segcmd
.initprot
= PROT_READ
;
793 segcmd
.flags
= SG_NORELOC
;
795 symcmd
.symoff
= symsoffset
;
796 symcmd
.stroff
= result_count
* sizeof(struct nlist
)
799 if (target_arch
->byteorder
!= host_arch
->byteorder
) {
800 swap_mach_header(&hdr
, target_arch
->byteorder
);
801 swap_segment_command(&segcmd
, target_arch
->byteorder
);
803 err
= writeFile(fd
, &hdr
, sizeof(hdr
));
804 if (kErrorNone
!= err
) {
807 err
= writeFile(fd
, &segcmd
, sizeof(segcmd
));
810 if (kErrorNone
!= err
) {
814 if (target_arch
->byteorder
!= host_arch
->byteorder
) {
815 swap_symtab_command(&symcmd
, target_arch
->byteorder
);
816 swap_uuid_command(&uuidcmd
, target_arch
->byteorder
);
818 err
= writeFile(fd
, &symcmd
, sizeof(symcmd
));
819 if (kErrorNone
!= err
) {
822 err
= writeFile(fd
, &uuidcmd
, sizeof(uuidcmd
));
823 if (kErrorNone
!= err
) {
827 err
= seekFile(fd
, symsoffset
);
828 if (kErrorNone
!= err
) {
833 for (export_idx
= 0; export_idx
< num_export_syms
; export_idx
++) {
834 if (!export_symbols
[export_idx
].name
) {
837 if (!(kExported
& export_symbols
[export_idx
].flags
)) {
842 && export_symbols
[export_idx
- 1].name
843 && !strcmp(export_symbols
[export_idx
- 1].name
, export_symbols
[export_idx
].name
)) {
844 fprintf(stderr
, "duplicate export: %s\n", export_symbols
[export_idx
- 1].name
);
845 err
= kErrorDuplicate
;
849 for (import_idx
= 0; import_idx
< export_symbols
[export_idx
].list_count
; import_idx
++) {
850 if (export_symbols
[export_idx
].list
!= &export_symbols
[export_idx
]) {
851 printf("wild: %s, %s\n", export_symbols
[export_idx
].name
,
852 export_symbols
[export_idx
].list
[import_idx
].name
);
854 if (CPU_ARCH_ABI64
& target_arch
->cputype
) {
859 nl
.n_un
.n_strx
= strx
;
860 strx
+= export_symbols
[export_idx
].list
[import_idx
].name_len
;
862 if (export_symbols
[export_idx
].flags
& kObsolete
) {
863 nl
.n_desc
|= N_DESC_DISCARDED
;
866 if (export_symbols
[export_idx
].list
[import_idx
].indirect
) {
867 nl
.n_type
= N_INDR
| N_EXT
;
869 strx
+= export_symbols
[export_idx
].list
[import_idx
].indirect_len
;
871 nl
.n_type
= N_UNDF
| N_EXT
;
875 if (target_arch
->byteorder
!= host_arch
->byteorder
) {
876 swap_nlist_64(&nl
, 1, target_arch
->byteorder
);
879 err
= writeFile(fd
, &nl
, sizeof(nl
));
885 nl
.n_un
.n_strx
= strx
;
886 strx
+= export_symbols
[export_idx
].list
[import_idx
].name_len
;
888 if (export_symbols
[export_idx
].flags
& kObsolete
) {
889 nl
.n_desc
|= N_DESC_DISCARDED
;
892 if (export_symbols
[export_idx
].list
[import_idx
].indirect
) {
893 nl
.n_type
= N_INDR
| N_EXT
;
895 strx
+= export_symbols
[export_idx
].list
[import_idx
].indirect_len
;
897 nl
.n_type
= N_UNDF
| N_EXT
;
901 if (target_arch
->byteorder
!= host_arch
->byteorder
) {
902 swap_nlist(&nl
, 1, target_arch
->byteorder
);
905 err
= writeFile(fd
, &nl
, sizeof(nl
));
909 if (kErrorNone
!= err
) {
914 strx
= sizeof(uint32_t);
915 err
= writeFile(fd
, &zero
, strx
);
916 if (kErrorNone
!= err
) {
920 for (export_idx
= 0; export_idx
< num_export_syms
; export_idx
++) {
921 if (!export_symbols
[export_idx
].name
) {
925 for (import_idx
= 0; import_idx
< export_symbols
[export_idx
].list_count
; import_idx
++) {
926 err
= writeFile(fd
, export_symbols
[export_idx
].list
[import_idx
].name
,
927 export_symbols
[export_idx
].list
[import_idx
].name_len
);
928 if (kErrorNone
!= err
) {
931 if (export_symbols
[export_idx
].list
[import_idx
].indirect
) {
932 err
= writeFile(fd
, export_symbols
[export_idx
].list
[import_idx
].indirect
,
933 export_symbols
[export_idx
].list
[import_idx
].indirect_len
);
934 if (kErrorNone
!= err
) {
941 err
= writeFile(fd
, &zero
, strtabpad
- strtabsize
);
942 if (kErrorNone
!= err
) {
950 for (filenum
= 0; filenum
< num_files
; filenum
++) {
952 if (files
[filenum
].mapped_size
) {
953 munmap((caddr_t
)files
[filenum
].mapped
, files
[filenum
].mapped_size
);
954 files
[filenum
].mapped
= 0;
955 files
[filenum
].mapped_size
= 0;
959 if (kErrorNone
!= err
) {
960 if (output_name
&& strncmp(output_name
, "/dev/", 5)) {