ld64 with ppc
[darwin-xtools.git] / cctools / libstuff / ofile.c
blob8a3a0602178f1ab550b196134260b52870695bfe
1 /*
2 * Copyright © 2009 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Inc. ("Apple") nor the names of its
15 * contributors may be used to endorse or promote products derived from this
16 * software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * @APPLE_LICENSE_HEADER_END@
31 #define __darwin_i386_exception_state i386_exception_state
32 #define __darwin_i386_float_state i386_float_state
33 #define __darwin_i386_thread_state i386_thread_state
35 #ifndef RLD
36 #ifdef SHLIB
37 #include "shlib.h"
38 #endif
39 #include <libc.h>
40 #include <mach/mach.h>
41 #include "stuff/openstep_mach.h"
42 #include <stddef.h>
43 #include <stdarg.h>
44 #include <limits.h>
45 #include <errno.h>
46 #include <ctype.h>
47 #include <ar.h>
48 #include <sys/file.h>
49 #include <sys/types.h>
50 #include <sys/mman.h>
51 #include <mach-o/fat.h>
52 #include <mach-o/loader.h>
53 #import <mach/m68k/thread_status.h>
54 #import <mach/ppc/thread_status.h>
55 #undef MACHINE_THREAD_STATE /* need to undef these to avoid warnings */
56 #undef MACHINE_THREAD_STATE_COUNT
57 #undef THREAD_STATE_NONE
58 #undef VALID_THREAD_STATE_FLAVOR
59 #import <mach/m88k/thread_status.h>
60 #import <mach/i860/thread_status.h>
61 #import <mach/i386/thread_status.h>
62 #import <mach/sparc/thread_status.h>
63 #import <mach/arm/thread_status.h>
64 #include <mach-o/nlist.h>
65 #include <mach-o/reloc.h>
66 #include "stuff/bool.h"
67 #ifdef OFI
68 #include <mach-o/dyld.h>
69 #else
70 #include "stuff/lto.h"
71 #endif
72 #include "stuff/bytesex.h"
73 #include "stuff/arch.h"
74 #include "stuff/rnd.h"
75 #include "stuff/errors.h"
76 #include "stuff/allocate.h"
77 #include "stuff/ofile.h"
78 #include "stuff/print.h"
80 #ifdef OTOOL
81 #undef ALIGNMENT_CHECKS
82 #include "otool.h"
83 #include "dyld_bind_info.h"
84 #include "ofile_print.h"
85 static enum bool otool_first_ofile_map = TRUE;
86 #else /* !define(OTOOL) */
88 #if (!defined(m68k) && !defined(__i386__) && !defined(__x86_64__) && !defined(__ppc__) && !defined(__arm__))
89 #define ALIGNMENT_CHECKS_ARCHIVE_64_BIT
90 static enum bool archive_64_bit_align_warning = FALSE;
91 #endif /* (!defined(m68k) && !defined(__i386__) && !defined(__x86_64__) && !defined(__ppc__) && !defined(__arm__)) */
93 #endif /* OTOOL */
95 /* <mach/loader.h> */
96 /* The maximum section alignment allowed to be specified, as a power of two */
97 #define MAXSECTALIGN 15 /* 2**15 or 0x8000 */
99 enum check_type {
100 CHECK_BAD,
101 CHECK_GOOD
104 #ifndef OTOOL
105 struct element {
106 uint32_t offset;
107 uint32_t size;
108 char *name;
109 struct element *next;
111 #endif /* !defined(OTOOL) */
113 static enum bool ofile_specific_arch(
114 struct ofile *ofile,
115 uint32_t narch);
116 static enum check_type check_fat(
117 struct ofile *ofile);
118 static enum check_type check_fat_object_in_archive(
119 struct ofile *ofile);
120 static enum check_type check_archive(
121 struct ofile *ofile,
122 enum bool archives_with_fat_objects);
123 static enum check_type check_extend_format_1(
124 struct ofile *ofile,
125 struct ar_hdr *ar_hdr,
126 uint32_t size_left,
127 uint32_t *member_name_size);
128 static enum check_type check_archive_toc(
129 struct ofile *ofile);
130 static enum check_type check_Mach_O(
131 struct ofile *ofile);
132 static void swap_back_Mach_O(
133 struct ofile *ofile);
134 #ifndef OTOOL
135 static enum check_type check_overlaping_element(
136 struct ofile *ofile,
137 struct element *head,
138 uint32_t offset,
139 uint32_t size,
140 char *name);
141 static void free_elements(
142 struct element *head);
143 #endif /* !defined(OTOOL) */
144 static enum check_type check_dylib_module(
145 struct ofile *ofile,
146 struct symtab_command *st,
147 struct dysymtab_command *dyst,
148 char *strings,
149 uint32_t module_index);
151 #ifndef OTOOL
152 #if defined(ALIGNMENT_CHECKS) || defined(ALIGNMENT_CHECKS_ARCHIVE_64_BIT)
153 static
154 void
155 temporary_archive_member_warning(
156 struct ofile *ofile,
157 const char *format, ...)
159 va_list ap;
161 va_start(ap, format);
162 if(ofile->file_type == OFILE_FAT){
163 print("%s: for architecture %s archive member: %s(%.*s) ",
164 progname, ofile->arch_flag.name, ofile->file_name,
165 (int)ofile->member_name_size, ofile->member_name);
167 else{
168 print("%s: archive member: %s(%.*s) ", progname, ofile->file_name,
169 (int)ofile->member_name_size, ofile->member_name);
171 vprint(format, ap);
172 print("\n");
173 va_end(ap);
175 #endif /* defined(ALIGNMENT_CHECKS) */
176 #endif /* !defined(OTOOL) */
178 #ifndef OFI
180 * ofile_process() processes the specified file name can calls the routine
181 * processor on the ofiles in it. arch_flags is an array of architectures
182 * containing narch_flags which are the only architectures to process if
183 * narch_flags is non-zero. If all_archs is TRUE then all architectures of
184 * the specified file are processed. The specified file name can be of the
185 * form "archive(member)" which is taken to mean that member in that archive
186 * (or that module of a dynamic library if dylib_flat is not FALSE).
187 * For each ofile that is to be processed the routine processor is called with
188 * the corresponding ofile struct, the arch_name pass to it is either NULL or
189 * an architecture name (when it should be printed or show by processor) and
190 * cookie is the same value as passed to ofile_process.
192 __private_extern__
193 void
194 ofile_process(
195 char *name,
196 struct arch_flag *arch_flags,
197 uint32_t narch_flags,
198 enum bool all_archs,
199 enum bool process_non_objects,
200 enum bool dylib_flat,
201 enum bool use_member_syntax,
202 void (*processor)(struct ofile *ofile, char *arch_name, void *cookie),
203 void *cookie)
205 char *member_name, *p, *arch_name;
206 uint32_t len, i;
207 struct ofile ofile;
208 enum bool flag, hostflag, arch_found, family;
209 struct arch_flag host_arch_flag, specific_arch_flag;
210 const struct arch_flag *family_arch_flag;
213 * If use_member_syntax is TRUE look for a name of the form
214 * "archive(member)" which is to mean a member in that archive (the
215 * member name must be at least one character long to be recognized as
216 * this form).
218 member_name = NULL;
219 if(use_member_syntax == TRUE){
220 len = strlen(name);
221 if(len >= 4 && name[len-1] == ')'){
222 p = strrchr(name, '(');
223 if(p != NULL && p != name){
224 member_name = p+1;
225 *p = '\0';
226 name[len-1] = '\0';
231 #ifdef OTOOL
232 otool_first_ofile_map = TRUE;
233 #endif /* OTOOL */
234 if(ofile_map(name, NULL, NULL, &ofile, FALSE) == FALSE)
235 return;
236 #ifdef OTOOL
237 otool_first_ofile_map = FALSE;
238 #endif /* OTOOL */
240 if(ofile.file_type == OFILE_FAT){
242 * This is a fat file so see if a list of architecture is
243 * specified and process only those.
245 if(all_archs == FALSE && narch_flags != 0){
246 for(i = 0; i < narch_flags; i++){
247 if(ofile_first_arch(&ofile) == FALSE){
248 ofile_unmap(&ofile);
249 return;
251 arch_found = FALSE;
252 family = FALSE;
253 family_arch_flag =
254 get_arch_family_from_cputype(arch_flags[i].cputype);
255 if(family_arch_flag != NULL)
256 family = (enum bool)
257 ((family_arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) ==
258 (arch_flags[i].cpusubtype & ~CPU_SUBTYPE_MASK));
259 if(narch_flags != 1)
260 arch_name = ofile.arch_flag.name;
261 else
262 arch_name = NULL;
264 if(ofile.arch_flag.cputype ==
265 arch_flags[i].cputype &&
266 ((ofile.arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK) ==
267 (arch_flags[i].cpusubtype & ~CPU_SUBTYPE_MASK) ||
268 family == TRUE)){
269 arch_found = TRUE;
270 if(ofile.arch_type == OFILE_ARCHIVE){
271 if(member_name != NULL){
272 if(ofile_specific_member(member_name,
273 &ofile) == TRUE){
274 processor(&ofile, arch_name, cookie);
275 if(ofile.headers_swapped == TRUE)
276 swap_back_Mach_O(&ofile);
279 else{
280 /* loop through archive */
281 #ifdef OTOOL
282 printf("Archive : %s", ofile.file_name);
283 if(arch_name != NULL)
284 printf(" (architecture %s)",
285 arch_name);
286 printf("\n");
287 #endif /* OTOOL */
288 if(ofile_first_member(&ofile) == TRUE){
289 flag = FALSE;
291 if(process_non_objects == TRUE ||
292 ofile.member_type ==
293 OFILE_Mach_O){
294 processor(&ofile, arch_name,
295 cookie);
296 if(ofile.headers_swapped ==TRUE)
297 swap_back_Mach_O(&ofile);
298 flag = TRUE;
300 }while(ofile_next_member(&ofile) ==
301 TRUE);
302 if(flag == FALSE){
303 error("for architecture: %s "
304 "archive: %s contains no "
305 "members that are object "
306 "files", ofile.arch_flag.name,
307 ofile.file_name);
310 else{
311 error("for architecture: %s archive: "
312 "%s contains no members",
313 ofile.arch_flag.name,
314 ofile.file_name);
318 else if(process_non_objects == TRUE ||
319 ofile.arch_type == OFILE_Mach_O){
320 if(ofile.arch_type == OFILE_Mach_O &&
321 (ofile.mh_filetype == MH_DYLIB ||
322 ofile.mh_filetype == MH_DYLIB_STUB)){
323 if(dylib_flat == TRUE){
324 processor(&ofile, arch_name, cookie);
325 if(ofile.headers_swapped == TRUE)
326 swap_back_Mach_O(&ofile);
328 else{
329 if(member_name != NULL){
330 if(ofile_specific_module(
331 member_name, &ofile) == TRUE){
332 processor(&ofile, arch_name,
333 cookie);
334 if(ofile.headers_swapped ==TRUE)
335 swap_back_Mach_O(&ofile);
338 else{
339 /*loop through the dynamic library*/
340 if(ofile_first_module(&ofile)){
342 processor(&ofile, arch_name,
343 cookie);
344 }while(ofile_next_module(
345 &ofile));
347 else{
348 processor(&ofile, arch_name,
349 cookie);
353 if(ofile.headers_swapped == TRUE)
354 swap_back_Mach_O(&ofile);
356 else{
357 if(member_name != NULL)
358 error("for architecture: %s file: %s "
359 "is not an archive and thus does "
360 "not contain member: %s",
361 ofile.arch_flag.name,
362 ofile.file_name,
363 member_name);
364 else{
365 processor(&ofile, arch_name, cookie);
366 if(ofile.headers_swapped == TRUE)
367 swap_back_Mach_O(&ofile);
371 else if(ofile.arch_type == OFILE_UNKNOWN){
372 error("for architecture: %s file: %s is "
373 "not an object file",
374 ofile.arch_flag.name,ofile.file_name);
376 if(ofile.headers_swapped == TRUE)
377 swap_back_Mach_O(&ofile);
378 break;
380 else{
381 if(ofile.headers_swapped == TRUE)
382 swap_back_Mach_O(&ofile);
384 }while(ofile_next_arch(&ofile) == TRUE);
385 if(arch_found == FALSE)
386 error("file: %s does not contain architecture: %s",
387 ofile.file_name, arch_flags[i].name);
389 ofile_unmap(&ofile);
390 return;
394 * This is a fat file and no architectures has been specified
395 * so if it contains the host architecture process only that
396 * architecture but if not process all architectures
397 * specified.
399 if(all_archs == FALSE){
400 (void)get_arch_from_host(&host_arch_flag, &specific_arch_flag);
401 #if __LP64__
403 * If runing as a 64-bit binary and on an Intel x86 host
404 * default to 64-bit.
406 if(host_arch_flag.cputype == CPU_TYPE_I386)
407 host_arch_flag =
408 *get_arch_family_from_cputype(CPU_TYPE_X86_64);
409 #endif /* __LP64__ */
410 hostflag = FALSE;
412 family = FALSE;
413 family_arch_flag =
414 get_arch_family_from_cputype(host_arch_flag.cputype);
415 #ifndef __arm__
416 if(family_arch_flag != NULL)
417 family = (enum bool)
418 ((family_arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) ==
419 (host_arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK));
420 #endif /* __arm__ */
422 ofile_unmap(&ofile);
423 if(ofile_map(name, NULL, NULL, &ofile, FALSE) == FALSE)
424 return;
425 if(ofile_first_arch(&ofile) == FALSE){
426 ofile_unmap(&ofile);
427 return;
430 if(ofile.arch_flag.cputype ==
431 host_arch_flag.cputype &&
432 ((ofile.arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK) ==
433 #ifdef __arm__
434 (specific_arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK) ||
435 #else
436 (host_arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK) ||
437 #endif /* __arm__ */
438 family == TRUE)){
439 hostflag = TRUE;
440 if(ofile.arch_type == OFILE_ARCHIVE){
441 if(member_name != NULL){
442 if(ofile_specific_member(member_name,
443 &ofile) == TRUE){
444 processor(&ofile, NULL, cookie);
445 if(ofile.headers_swapped == TRUE)
446 swap_back_Mach_O(&ofile);
449 else{
450 /* loop through archive */
451 #ifdef OTOOL
452 printf("Archive : %s\n", ofile.file_name);
453 #endif /* OTOOL */
454 if(ofile_first_member(&ofile) == TRUE){
455 flag = FALSE;
457 if(process_non_objects == TRUE ||
458 ofile.member_type == OFILE_Mach_O){
459 processor(&ofile, NULL, cookie);
460 if(ofile.headers_swapped == TRUE)
461 swap_back_Mach_O(&ofile);
462 flag = TRUE;
464 }while(ofile_next_member(&ofile) ==
465 TRUE);
466 if(flag == FALSE){
467 error("archive: %s contains no "
468 "members that are object "
469 "files", ofile.file_name);
472 else{
473 error("archive: %s contains no "
474 "members", ofile.file_name);
478 else if(process_non_objects == TRUE ||
479 ofile.arch_type == OFILE_Mach_O){
480 if(ofile.arch_type == OFILE_Mach_O &&
481 (ofile.mh_filetype == MH_DYLIB ||
482 ofile.mh_filetype == MH_DYLIB_STUB)){
483 if(dylib_flat == TRUE){
484 processor(&ofile, NULL, cookie);
486 else{
487 if(member_name != NULL){
488 if(ofile_specific_module(member_name,
489 &ofile) == TRUE)
490 processor(&ofile, NULL, cookie);
492 else{
493 /* loop through the dynamic library */
494 if(ofile_first_module(&ofile) == TRUE){
496 processor(&ofile, NULL, cookie);
497 }while(ofile_next_module(&ofile));
499 else{
500 processor(&ofile, NULL, cookie);
504 if(ofile.headers_swapped == TRUE)
505 swap_back_Mach_O(&ofile);
507 else{
508 if(member_name != NULL)
509 error("for architecture: %s file: %s is "
510 "not an archive and thus does not "
511 "contain member: %s",
512 ofile.arch_flag.name, ofile.file_name,
513 member_name);
514 else{
515 processor(&ofile, NULL, cookie);
516 if(ofile.headers_swapped == TRUE)
517 swap_back_Mach_O(&ofile);
521 else if(ofile.arch_type == OFILE_UNKNOWN){
522 error("file: %s is not an object file",
523 ofile.file_name);
526 else{
527 if(ofile.headers_swapped == TRUE)
528 swap_back_Mach_O(&ofile);
530 }while(hostflag == FALSE && ofile_next_arch(&ofile) == TRUE);
531 if(hostflag == TRUE){
532 ofile_unmap(&ofile);
533 return;
538 * Either all architectures have been specified or none have
539 * been specified and it does not contain the host architecture
540 * so do all the architectures in the fat file
542 ofile_unmap(&ofile);
543 if(ofile_map(name, NULL, NULL, &ofile, FALSE) == FALSE)
544 return;
545 if(ofile_first_arch(&ofile) == FALSE){
546 ofile_unmap(&ofile);
547 return;
550 if(ofile.arch_type == OFILE_ARCHIVE){
551 if(member_name != NULL){
552 if(ofile_specific_member(member_name, &ofile) == TRUE)
553 processor(&ofile, ofile.arch_flag.name, cookie);
555 else{
556 /* loop through archive */
557 #ifdef OTOOL
558 printf("Archive : %s (architecture %s)\n",
559 ofile.file_name, ofile.arch_flag.name);
560 #endif /* OTOOL */
561 if(ofile_first_member(&ofile) == TRUE){
562 flag = FALSE;
564 if(process_non_objects == TRUE ||
565 ofile.member_type == OFILE_Mach_O){
566 processor(&ofile, ofile.arch_flag.name,
567 cookie);
568 flag = TRUE;
570 }while(ofile_next_member(&ofile) == TRUE);
571 if(flag == FALSE){
572 error("for architecture: %s archive: %s "
573 "contains no members that are object "
574 "files", ofile.arch_flag.name,
575 ofile.file_name);
578 else{
579 error("for architecture: %s archive: %s "
580 "contains no members",
581 ofile.arch_flag.name, ofile.file_name);
585 else if(process_non_objects == TRUE ||
586 ofile.arch_type == OFILE_Mach_O){
587 if(ofile.arch_type == OFILE_Mach_O &&
588 (ofile.mh_filetype == MH_DYLIB ||
589 ofile.mh_filetype == MH_DYLIB_STUB)){
590 if(dylib_flat == TRUE){
591 processor(&ofile, ofile.arch_flag.name, cookie);
593 else{
594 if(member_name != NULL){
595 if(ofile_specific_module(member_name, &ofile)
596 == TRUE)
597 processor(&ofile, ofile.arch_flag.name,
598 cookie);
600 else{
601 /* loop through the dynamic library */
602 if(ofile_first_module(&ofile) == TRUE){
604 processor(&ofile, ofile.arch_flag.name,
605 cookie);
606 }while(ofile_next_module(&ofile) == TRUE);
608 else{
609 processor(&ofile, ofile.arch_flag.name,
610 cookie);
615 else{
616 if(member_name != NULL)
617 error("for architecture: %s file: %s is not an "
618 "archive and thus does not contain member: "
619 "%s", ofile.arch_flag.name, ofile.file_name,
620 member_name);
621 else
622 processor(&ofile, ofile.arch_flag.name, cookie);
625 else if(ofile.arch_type == OFILE_UNKNOWN){
626 error("for architecture: %s file: %s is not an "
627 "object file", ofile.arch_flag.name,
628 ofile.file_name);
630 }while(ofile_next_arch(&ofile) == TRUE);
632 else if(ofile.file_type == OFILE_ARCHIVE){
633 if(narch_flags != 0){
634 arch_found = FALSE;
635 for(i = 0; i < narch_flags; i++){
636 family = FALSE;
637 if(narch_flags == 1){
638 family_arch_flag =
639 get_arch_family_from_cputype(arch_flags[0].cputype);
640 if(family_arch_flag != NULL)
641 family = (enum bool)
642 ((family_arch_flag->cpusubtype &
643 ~CPU_SUBTYPE_MASK) ==
644 (arch_flags[0].cpusubtype &
645 ~CPU_SUBTYPE_MASK));
647 if(ofile.archive_cputype == arch_flags[i].cputype &&
648 ((ofile.archive_cpusubtype & ~CPU_SUBTYPE_MASK) ==
649 (arch_flags[i].cpusubtype & ~CPU_SUBTYPE_MASK) ||
650 family == TRUE)){
651 arch_found = TRUE;
653 else{
654 error("file: %s does not contain architecture: %s",
655 ofile.file_name, arch_flags[i].name);
658 if(arch_found == FALSE){
659 ofile_unmap(&ofile);
660 return;
663 if(member_name != NULL){
664 if(ofile_specific_member(member_name, &ofile) == TRUE)
665 processor(&ofile, NULL, cookie);
667 else{
668 /* loop through archive */
669 #ifdef OTOOL
670 printf("Archive : %s\n", ofile.file_name);
671 #endif /* OTOOL */
672 if(ofile_first_member(&ofile) == TRUE){
673 flag = FALSE;
675 if(process_non_objects == TRUE ||
676 ofile.member_type == OFILE_Mach_O){
677 processor(&ofile, NULL, cookie);
678 flag = TRUE;
680 }while(ofile_next_member(&ofile) == TRUE);
681 if(flag == FALSE){
682 error("archive: %s contains no members that are "
683 "object files", ofile.file_name);
686 else{
687 error("archive: %s contains no members",
688 ofile.file_name);
692 else if(ofile.file_type == OFILE_Mach_O){
693 if(narch_flags != 0){
694 arch_found = FALSE;
695 for(i = 0; i < narch_flags; i++){
696 family = FALSE;
697 if(narch_flags == 1){
698 family_arch_flag =
699 get_arch_family_from_cputype(arch_flags[0].cputype);
700 if(family_arch_flag != NULL)
701 family = (enum bool)
702 ((family_arch_flag->cpusubtype &
703 ~CPU_SUBTYPE_MASK) ==
704 (arch_flags[0].cpusubtype &
705 ~CPU_SUBTYPE_MASK));
707 #ifdef OTOOL
708 if(ofile.mh != NULL){
709 if(ofile.mh->magic == MH_MAGIC &&
710 ofile.mh->cputype == arch_flags[i].cputype &&
711 ((ofile.mh->cpusubtype & ~CPU_SUBTYPE_MASK) ==
712 (arch_flags[i].cpusubtype & ~CPU_SUBTYPE_MASK) ||
713 family == TRUE)){
714 arch_found = TRUE;
716 if(ofile.mh->magic == SWAP_INT(MH_MAGIC) &&
717 (cpu_type_t)SWAP_INT(ofile.mh->cputype) ==
718 arch_flags[i].cputype &&
719 ((cpu_subtype_t)SWAP_INT(ofile.mh->cpusubtype &
720 ~CPU_SUBTYPE_MASK) ==
721 (arch_flags[i].cpusubtype &
722 ~CPU_SUBTYPE_MASK) ||
723 family == TRUE)){
724 arch_found = TRUE;
727 else if(ofile.mh64 != NULL){
728 if(ofile.mh64->magic == MH_MAGIC_64 &&
729 ofile.mh64->cputype == arch_flags[i].cputype &&
730 ((ofile.mh64->cpusubtype & ~CPU_SUBTYPE_MASK) ==
731 (arch_flags[i].cpusubtype & ~CPU_SUBTYPE_MASK) ||
732 family == TRUE)){
733 arch_found = TRUE;
735 if(ofile.mh64->magic == SWAP_INT(MH_MAGIC_64) &&
736 (cpu_type_t)SWAP_INT(ofile.mh64->cputype) ==
737 arch_flags[i].cputype &&
738 ((cpu_subtype_t)SWAP_INT((ofile.mh64->cpusubtype &
739 ~CPU_SUBTYPE_MASK)) ==
740 (arch_flags[i].cpusubtype & ~CPU_SUBTYPE_MASK) ||
741 family == TRUE)){
742 arch_found = TRUE;
745 else
746 #endif /* OTOOL */
747 if(ofile.mh_cputype == arch_flags[i].cputype &&
748 ((ofile.mh_cpusubtype & ~CPU_SUBTYPE_MASK) ==
749 (arch_flags[i].cpusubtype & ~CPU_SUBTYPE_MASK) ||
750 family == TRUE)){
751 arch_found = TRUE;
753 else{
754 error("file: %s does not contain architecture: %s",
755 ofile.file_name, arch_flags[i].name);
758 if(arch_found == FALSE){
759 ofile_unmap(&ofile);
760 return;
763 if(ofile.mh_filetype == MH_DYLIB ||
764 ofile.mh_filetype == MH_DYLIB_STUB){
765 if(dylib_flat == TRUE){
766 processor(&ofile, NULL, cookie);
768 else{
769 if(member_name != NULL){
770 if(ofile_specific_module(member_name, &ofile) == TRUE)
771 processor(&ofile, NULL, cookie);
773 else{
774 /* loop through the dynamic library */
775 if(ofile_first_module(&ofile) == TRUE){
777 processor(&ofile, NULL, cookie);
778 }while(ofile_next_module(&ofile) == TRUE);
780 else{
781 processor(&ofile, NULL, cookie);
786 else{
787 if(member_name != NULL)
788 error("file: %s is not an archive and thus does not contain"
789 " member: %s", ofile.file_name, member_name);
790 else
791 processor(&ofile, NULL, cookie);
794 else{
795 if(process_non_objects == TRUE)
796 processor(&ofile, NULL, cookie);
797 else if(member_name != NULL)
798 error("file: %s(%s) is not an object file", name,
799 member_name);
800 else
801 error("file: %s is not an object file", name);
803 ofile_unmap(&ofile);
805 #endif /* !defined(OFI) */
808 * ofile_map maps in the object file specified by file_name, arch_flag and
809 * object_name and fills in the ofile struct pointed to by ofile for it.
810 * When arch_flag and object_name are both NULL, the file is just set up into
811 * ofile (if the file can be opened and mapped in, if not this call fails
812 * are error routnes are called). If arch_flag is not NULL and object_file is
813 * NULL, then the file must be a Mach-O file or a fat file with the architecture
814 * specified in the arch_flag, if not this call fails and error routines are
815 * called. When arch_flag and object_name are both not NULL, then the file must
816 * be an archive or a fat file containing archives for the specified architec-
817 * ture and contain an archive member object file with the name object_name,
818 * otherwise this call fails and error routines are called. If arch_flag is
819 * NULL and object_file is not NULL, then the file name must be an archive (not
820 * a fat file containing archives) and contain an archive member object file
821 * with the name object_name, otherwise this call fails and calls error
822 * routines. If this call suceeds then it returns non-zero and the ofile
823 * structure pointed to by ofile is filled in. If this call fails it returns 0
824 * and calls error routines to print error messages and clears the
825 * ofile structure pointed to by ofile.
827 __private_extern__
828 #ifdef OFI
829 NSObjectFileImageReturnCode
830 #else
831 enum bool
832 #endif
833 ofile_map(
834 const char *file_name,
835 const struct arch_flag *arch_flag, /* can be NULL */
836 const char *object_name, /* can be NULL */
837 struct ofile *ofile,
838 enum bool archives_with_fat_objects)
840 int fd;
841 struct stat stat_buf;
842 uint64_t size;
843 uint32_t magic;
844 char *addr;
846 magic = 0; /* to shut up the compiler warning message */
847 memset(ofile, '\0', sizeof(struct ofile));
849 /* Open the file and map it in */
850 if((fd = open(file_name, O_RDONLY)) == -1){
851 #ifdef OFI
852 return(NSObjectFileImageAccess);
853 #else
854 system_error("can't open file: %s", file_name);
855 return(FALSE);
856 #endif
858 if(fstat(fd, &stat_buf) == -1){
859 close(fd);
860 #ifdef OFI
861 return(NSObjectFileImageAccess);
862 #else
863 system_error("can't stat file: %s", file_name);
864 return(FALSE);
865 #endif
867 size = stat_buf.st_size;
869 addr = NULL;
870 if(size != 0){
871 addr = mmap(0, size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_PRIVATE, fd,
873 if((intptr_t)addr == -1){
874 system_error("can't map file: %s", file_name);
875 close(fd);
876 return(FALSE);
879 close(fd);
880 #ifdef OTOOL
881 if(otool_first_ofile_map && Wflag)
882 printf("Modification time = %ld\n", (long int)stat_buf.st_mtime);
883 #endif /* OTOOL */
885 return(ofile_map_from_memory(addr, size, file_name, stat_buf.st_mtime,
886 arch_flag, object_name, ofile, archives_with_fat_objects));
890 * ofile_map_from_memory() is the guts of ofile_map() but with an interface
891 * to pass the address and size of the file already mapped in.
893 __private_extern__
894 #ifdef OFI
895 NSObjectFileImageReturnCode
896 #else
897 enum bool
898 #endif
899 ofile_map_from_memory(
900 char *addr,
901 uint64_t size,
902 const char *file_name,
903 uint64_t mtime,
904 const struct arch_flag *arch_flag, /* can be NULL */
905 const char *object_name, /* can be NULL */
906 struct ofile *ofile,
907 enum bool archives_with_fat_objects)
909 uint32_t i;
910 uint32_t magic;
911 enum byte_sex host_byte_sex;
912 struct arch_flag host_arch_flag;
913 enum bool family;
914 const struct arch_flag *family_arch_flag;
915 uint64_t big_size;
916 #ifdef OTOOL
917 uint32_t small_nfat_arch;
918 #endif /* OTOOL */
919 uint64_t offset;
920 uint32_t align;
922 /* fill in the start of the ofile structure */
923 ofile->file_name = savestr(file_name);
924 if(ofile->file_name == NULL)
925 return(FALSE);
926 ofile->file_addr = addr;
927 ofile->file_size = size;
928 ofile->file_mtime = mtime;
930 /* Try to figure out what kind of file this is */
932 if(size >= sizeof(uint32_t)){
933 magic = *((uint32_t *)addr);
935 host_byte_sex = get_host_byte_sex();
937 /* see if this file is a fat file (always in big endian byte sex) */
938 #ifdef __BIG_ENDIAN__
939 if(size >= sizeof(struct fat_header) &&
940 (magic == FAT_MAGIC || magic == FAT_MAGIC_64))
941 #endif /* __BIG_ENDIAN__ */
942 #ifdef __LITTLE_ENDIAN__
943 if(size >= sizeof(struct fat_header) &&
944 (SWAP_INT(magic) == FAT_MAGIC || SWAP_INT(magic) == FAT_MAGIC_64))
945 #endif /* __LITTLE_ENDIAN__ */
947 ofile->file_type = OFILE_FAT;
948 ofile->fat_header = (struct fat_header *)addr;
949 #ifdef __LITTLE_ENDIAN__
950 swap_fat_header(ofile->fat_header, host_byte_sex);
951 #endif /* __LITTLE_ENDIAN__ */
952 #ifdef OTOOL
953 if(otool_first_ofile_map && fflag)
954 printf("Fat headers\n");
955 #endif /* OTOOL */
956 big_size = ofile->fat_header->nfat_arch;
957 if(ofile->fat_header->magic == FAT_MAGIC_64)
958 big_size *= sizeof(struct fat_arch_64);
959 else
960 big_size *= sizeof(struct fat_arch);
961 big_size += sizeof(struct fat_header);
962 if(big_size > size){
963 #ifdef OTOOL
964 error("fat file: %s truncated or malformed (fat_arch%s structs "
965 "would extend past the end of the file)", file_name,
966 ofile->fat_header->magic == FAT_MAGIC_64 ? "_64" : "");
967 if(ofile->fat_header->magic == FAT_MAGIC_64){
968 ofile->fat_archs64 = allocate(size -
969 sizeof(struct fat_header));
970 memset(ofile->fat_archs64, '\0',
971 size - sizeof(struct fat_header));
972 memcpy(ofile->fat_archs64,
973 addr + sizeof(struct fat_header),
974 size - sizeof(struct fat_header));
975 small_nfat_arch = (size - sizeof(struct fat_header)) /
976 sizeof(struct fat_arch_64);
977 #ifdef __LITTLE_ENDIAN__
978 swap_fat_arch_64(ofile->fat_archs64, small_nfat_arch,
979 host_byte_sex);
980 #endif /* __LITTLE_ENDIAN__ */
982 else{
983 ofile->fat_archs = allocate(size -
984 sizeof(struct fat_header));
985 memset(ofile->fat_archs, '\0',
986 size - sizeof(struct fat_header));
987 memcpy(ofile->fat_archs,
988 addr + sizeof(struct fat_header),
989 size - sizeof(struct fat_header));
990 small_nfat_arch = (size - sizeof(struct fat_header)) /
991 sizeof(struct fat_arch);
992 #ifdef __LITTLE_ENDIAN__
993 swap_fat_arch(ofile->fat_archs, small_nfat_arch,
994 host_byte_sex);
995 #endif /* __LITTLE_ENDIAN__ */
997 if(otool_first_ofile_map && fflag)
998 print_fat_headers(ofile->fat_header, ofile->fat_archs,
999 ofile->fat_archs64, size, vflag);
1000 if(ofile->fat_header->magic == FAT_MAGIC_64)
1001 free(ofile->fat_archs64);
1002 else
1003 free(ofile->fat_archs);
1004 ofile_unmap(ofile);
1005 return(FALSE);
1006 #else /* !defined(OTOOL) */
1007 goto unknown;
1008 #endif /* OTOOL */
1010 if(ofile->fat_header->magic == FAT_MAGIC_64){
1011 ofile->fat_archs64 = (struct fat_arch_64 *)
1012 (addr + sizeof(struct fat_header));
1013 #ifdef __LITTLE_ENDIAN__
1014 swap_fat_arch_64(ofile->fat_archs64,
1015 ofile->fat_header->nfat_arch, host_byte_sex);
1016 #endif /* __LITTLE_ENDIAN__ */
1018 else{
1019 ofile->fat_archs = (struct fat_arch *)
1020 (addr + sizeof(struct fat_header));
1021 #ifdef __LITTLE_ENDIAN__
1022 swap_fat_arch(ofile->fat_archs, ofile->fat_header->nfat_arch,
1023 host_byte_sex);
1024 #endif /* __LITTLE_ENDIAN__ */
1026 #ifdef OTOOL
1027 if(otool_first_ofile_map && fflag)
1028 print_fat_headers(ofile->fat_header, ofile->fat_archs,
1029 ofile->fat_archs64, size, vflag);
1030 #endif /* OTOOL */
1031 if(check_fat(ofile) == CHECK_BAD){
1032 ofile_unmap(ofile);
1033 #ifdef OFI
1034 return(NSObjectFileImageFormat);
1035 #else
1036 return(FALSE);
1037 #endif
1040 * Now that the fat file is mapped fill in the ofile to the level
1041 * the caller wants based on the arch_flag and object_name passed.
1042 * If the caller did not specify an arch_flag or an object_name
1043 * then everything the caller wants is done.
1045 if(arch_flag == NULL && object_name == NULL)
1046 goto success;
1047 if(arch_flag == NULL){
1048 if(get_arch_from_host(&host_arch_flag, NULL) == 0){
1049 error("can't determine the host architecture (specify an "
1050 "arch_flag or fix get_arch_from_host() )");
1051 goto cleanup;
1053 ofile->arch_flag.name = savestr(host_arch_flag.name);
1054 if(ofile->arch_flag.name == NULL)
1055 goto cleanup;
1056 ofile->arch_flag.cputype = host_arch_flag.cputype;
1057 ofile->arch_flag.cpusubtype = host_arch_flag.cpusubtype;
1059 else{
1060 ofile->arch_flag.name = savestr(arch_flag->name);
1061 if(ofile->arch_flag.name == NULL)
1062 goto cleanup;
1063 ofile->arch_flag.cputype = arch_flag->cputype;
1064 ofile->arch_flag.cpusubtype = arch_flag->cpusubtype;
1067 ofile->narch = UINT_MAX;
1068 for(i = 0; i < ofile->fat_header->nfat_arch; i++){
1069 if(ofile->fat_header->magic == FAT_MAGIC_64){
1070 if(ofile->fat_archs64[i].cputype ==
1071 ofile->arch_flag.cputype &&
1072 (ofile->fat_archs64[i].cpusubtype & ~CPU_SUBTYPE_MASK) ==
1073 (ofile->arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK)){
1074 ofile->narch = i;
1075 break;
1078 else{
1079 if(ofile->fat_archs[i].cputype ==
1080 ofile->arch_flag.cputype &&
1081 (ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK) ==
1082 (ofile->arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK)){
1083 ofile->narch = i;
1084 break;
1088 if(ofile->narch == UINT_MAX){
1089 family = FALSE;
1090 family_arch_flag =
1091 get_arch_family_from_cputype(ofile->arch_flag.cputype);
1092 if(family_arch_flag != NULL)
1093 family = (enum bool)
1094 ((family_arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) ==
1095 (ofile->arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK));
1096 ofile->narch = UINT_MAX;
1097 for(i = 0; i < ofile->fat_header->nfat_arch; i++){
1098 if(ofile->fat_header->magic == FAT_MAGIC_64){
1099 if(ofile->fat_archs64[i].cputype ==
1100 ofile->arch_flag.cputype &&
1101 (family == TRUE ||
1102 (ofile->fat_archs64[i].cpusubtype &
1103 ~CPU_SUBTYPE_MASK) ==
1104 (ofile->arch_flag.cpusubtype &
1105 ~CPU_SUBTYPE_MASK))){
1106 ofile->arch_flag.cpusubtype =
1107 ofile->fat_archs64[i].cpusubtype;
1108 ofile->narch = i;
1109 break;
1112 else{
1113 if(ofile->fat_archs[i].cputype ==
1114 ofile->arch_flag.cputype &&
1115 (family == TRUE ||
1116 (ofile->fat_archs[i].cpusubtype &
1117 ~CPU_SUBTYPE_MASK) ==
1118 (ofile->arch_flag.cpusubtype &
1119 ~CPU_SUBTYPE_MASK))){
1120 ofile->arch_flag.cpusubtype =
1121 ofile->fat_archs[i].cpusubtype;
1122 ofile->narch = i;
1123 break;
1128 if(ofile->narch == UINT_MAX){
1129 #ifdef OFI
1130 ofile_unmap(ofile);
1131 return(NSObjectFileImageArch);
1132 #else
1133 error("fat file: %s does not contain architecture %s",
1134 ofile->file_name, arch_flag->name);
1135 ofile_unmap(ofile);
1136 return(FALSE);
1137 #endif
1139 /* Now determine the file type for this specific architecture */
1140 if(ofile->fat_header->magic == FAT_MAGIC_64){
1141 size = ofile->fat_archs64[i].size;
1142 addr = addr + ofile->fat_archs64[i].offset;
1143 offset = ofile->fat_archs64[i].offset;
1144 align = ofile->fat_archs64[i].align;
1146 else{
1147 size = ofile->fat_archs[i].size;
1148 addr = addr + ofile->fat_archs[i].offset;
1149 offset = ofile->fat_archs[i].offset;
1150 align = ofile->fat_archs[i].align;
1152 if(size >= sizeof(struct mach_header))
1153 memcpy(&magic, addr, sizeof(uint32_t));
1154 /* see if this file is a 32-bit Mach-O file */
1155 if(size >= sizeof(struct mach_header) &&
1156 (magic == MH_MAGIC ||
1157 magic == SWAP_INT(MH_MAGIC))){
1158 #ifdef ALIGNMENT_CHECKS
1159 if(offset % 4 != 0){
1160 error("fat file: %s architecture %s malformed for a 32-bit "
1161 "object file (offset is not a multiple of 4)",
1162 ofile->file_name, arch_flag->name);
1163 ofile_unmap(ofile);
1164 #ifdef OFI
1165 return(NSObjectFileImageFormat);
1166 #else
1167 return(FALSE);
1168 #endif
1170 #endif /* ALIGNMENT_CHECKS */
1171 ofile->arch_type = OFILE_Mach_O;
1172 ofile->object_addr = addr;
1173 ofile->object_size = size;
1174 if(magic == MH_MAGIC)
1175 ofile->object_byte_sex = host_byte_sex;
1176 else
1177 ofile->object_byte_sex =
1178 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1179 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1180 ofile->mh = (struct mach_header *)addr;
1181 ofile->load_commands = (struct load_command *)(addr +
1182 sizeof(struct mach_header));
1183 if(check_Mach_O(ofile) == CHECK_BAD){
1184 ofile_unmap(ofile);
1185 #ifdef OFI
1186 return(NSObjectFileImageFormat);
1187 #else
1188 return(FALSE);
1189 #endif
1191 if(object_name != NULL){
1192 error("fat file: %s architecture %s is not an archive "
1193 "(object_name to ofile_map() can't be specified to "
1194 "be other than NULL)", ofile->file_name,
1195 arch_flag->name);
1196 goto cleanup;
1199 /* see if this file is a 64-bit Mach-O file */
1200 else if(size >= sizeof(struct mach_header_64) &&
1201 (magic == MH_MAGIC_64 ||
1202 magic == SWAP_INT(MH_MAGIC_64))){
1203 #ifdef ALIGNMENT_CHECKS
1204 if(offset % 8 != 0){
1205 error("fat file: %s architecture %s malformed for a 64-bit "
1206 "object file (offset is not a multiple of 8)",
1207 ofile->file_name, arch_flag->name);
1208 ofile_unmap(ofile);
1209 #ifdef OFI
1210 return(NSObjectFileImageFormat);
1211 #else
1212 return(FALSE);
1213 #endif
1215 #endif /* ALIGNMENT_CHECKS */
1216 ofile->arch_type = OFILE_Mach_O;
1217 ofile->object_addr = addr;
1218 ofile->object_size = size;
1219 if(magic == MH_MAGIC_64)
1220 ofile->object_byte_sex = host_byte_sex;
1221 else
1222 ofile->object_byte_sex =
1223 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1224 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1225 ofile->mh64 = (struct mach_header_64 *)addr;
1226 ofile->load_commands = (struct load_command *)(addr +
1227 sizeof(struct mach_header_64));
1228 if(check_Mach_O(ofile) == CHECK_BAD){
1229 ofile_unmap(ofile);
1230 #ifdef OFI
1231 return(NSObjectFileImageFormat);
1232 #else
1233 return(FALSE);
1234 #endif
1236 if(object_name != NULL){
1237 error("fat file: %s architecture %s is not an archive "
1238 "(object_name to ofile_map() can't be specified to "
1239 "be other than NULL)", ofile->file_name,
1240 arch_flag->name);
1241 goto cleanup;
1244 /* see if this file is an archive file */
1245 else if(size >= SARMAG && strncmp(addr, ARMAG, SARMAG) == 0){
1246 ofile->arch_type = OFILE_ARCHIVE;
1247 if(check_archive(ofile, FALSE) == CHECK_BAD){
1248 ofile_unmap(ofile);
1249 #ifdef OFI
1250 return(NSObjectFileImageInappropriateFile);
1251 #else
1252 return(FALSE);
1253 #endif
1255 #ifdef ALIGNMENT_CHECKS
1256 if(ofile->archive_cputype != 0 &&
1257 offset % sizeof(uint32_t) != 0){
1258 error("fat file: %s architecture %s malformed archive that "
1259 "contains object files (offset to archive is not a "
1260 "multiple of sizeof(uint32_t))",
1261 ofile->file_name, arch_flag->name);
1262 ofile_unmap(ofile);
1263 #ifdef OFI
1264 return(NSObjectFileImageInappropriateFile);
1265 #else
1266 return(FALSE);
1267 #endif
1269 #endif /* ALIGNMENT_CHECKS */
1270 if(object_name != NULL){
1271 if(ofile_specific_member(object_name, ofile) == FALSE)
1272 goto cleanup;
1275 /* this file type is now known to be unknown to this program */
1276 else{
1277 ofile->file_type = OFILE_UNKNOWN;
1278 if(object_name != NULL){
1279 error("fat file: %s architecture %s is not an archive "
1280 "(object_name to ofile_map() can't be specified to "
1281 "be other than NULL)", ofile->file_name,
1282 arch_flag->name);
1283 goto cleanup;
1287 /* see if this file is a 32-bit Mach-O file */
1288 else if(size >= sizeof(struct mach_header) &&
1289 (magic == MH_MAGIC ||
1290 magic == SWAP_INT(MH_MAGIC))){
1291 ofile->file_type = OFILE_Mach_O;
1292 ofile->object_addr = addr;
1293 ofile->object_size = size;
1294 if(magic == MH_MAGIC)
1295 ofile->object_byte_sex = host_byte_sex;
1296 else
1297 ofile->object_byte_sex = host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1298 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1299 ofile->mh = (struct mach_header *)addr;
1300 ofile->load_commands = (struct load_command *)(addr +
1301 sizeof(struct mach_header));
1302 if(check_Mach_O(ofile) == CHECK_BAD){
1303 ofile_unmap(ofile);
1304 #ifdef OFI
1305 return(NSObjectFileImageFormat);
1306 #else
1307 return(FALSE);
1308 #endif
1310 if(object_name != NULL){
1311 error("file: %s is not an archive (object_name to ofile_map() "
1312 "can't be specified to be other than NULL)",
1313 ofile->file_name);
1314 goto cleanup;
1316 if(arch_flag != NULL){
1317 if(arch_flag->cputype != ofile->mh_cputype &&
1318 (arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) !=
1319 (ofile->mh_cpusubtype & ~CPU_SUBTYPE_MASK)){
1320 #ifdef OFI
1321 ofile_unmap(ofile);
1322 return(NSObjectFileImageArch);
1323 #else
1324 error("object file: %s does not match specified arch_flag: "
1325 "%s passed to ofile_map()", ofile->file_name,
1326 arch_flag->name);
1327 ofile_unmap(ofile);
1328 return(FALSE);
1329 #endif
1330 goto cleanup;
1334 /* see if this file is a 64-bit Mach-O file */
1335 else if(size >= sizeof(struct mach_header_64) &&
1336 (magic == MH_MAGIC_64 ||
1337 magic == SWAP_INT(MH_MAGIC_64))){
1338 ofile->file_type = OFILE_Mach_O;
1339 ofile->object_addr = addr;
1340 ofile->object_size = size;
1341 if(magic == MH_MAGIC_64)
1342 ofile->object_byte_sex = host_byte_sex;
1343 else
1344 ofile->object_byte_sex = host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1345 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1346 ofile->mh64 = (struct mach_header_64 *)addr;
1347 ofile->load_commands = (struct load_command *)(addr +
1348 sizeof(struct mach_header_64));
1349 if(check_Mach_O(ofile) == CHECK_BAD){
1350 ofile_unmap(ofile);
1351 #ifdef OFI
1352 return(NSObjectFileImageFormat);
1353 #else
1354 return(FALSE);
1355 #endif
1357 if(object_name != NULL){
1358 error("file: %s is not an archive (object_name to ofile_map() "
1359 "can't be specified to be other than NULL)",
1360 ofile->file_name);
1361 goto cleanup;
1363 if(arch_flag != NULL){
1364 if(arch_flag->cputype != ofile->mh_cputype &&
1365 (arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) !=
1366 (ofile->mh_cpusubtype & ~CPU_SUBTYPE_MASK)){
1367 #ifdef OFI
1368 ofile_unmap(ofile);
1369 return(NSObjectFileImageArch);
1370 #else
1371 error("object file: %s does not match specified arch_flag: "
1372 "%s passed to ofile_map()", ofile->file_name,
1373 arch_flag->name);
1374 ofile_unmap(ofile);
1375 return(FALSE);
1376 #endif
1377 goto cleanup;
1381 /* see if this file is an archive file */
1382 else if(size >= SARMAG && strncmp(addr, ARMAG, SARMAG) == 0){
1383 ofile->file_type = OFILE_ARCHIVE;
1384 if(check_archive(ofile, archives_with_fat_objects) == CHECK_BAD)
1385 goto cleanup;
1386 if(object_name != NULL){
1387 if(ofile_specific_member(object_name, ofile) == FALSE)
1388 goto cleanup;
1389 if(arch_flag != NULL){
1390 if(arch_flag->cputype != ofile->mh_cputype &&
1391 (arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) !=
1392 (ofile->mh_cpusubtype & ~CPU_SUBTYPE_MASK)){
1393 error("object file: %s(%.*s) does not match specified "
1394 "arch_flag: %s passed to ofile_map()",
1395 ofile->file_name, (int)ofile->member_name_size,
1396 ofile->member_name, arch_flag->name);
1397 goto cleanup;
1401 else{
1402 if(arch_flag != NULL){
1403 if(arch_flag->cputype != ofile->archive_cputype &&
1404 (arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) !=
1405 (ofile->archive_cpusubtype & ~CPU_SUBTYPE_MASK)){
1406 error("archive file: %s objects do not match specified "
1407 "arch_flag: %s passed to ofile_map()",
1408 ofile->file_name, arch_flag->name);
1409 goto cleanup;
1414 /* this file type is now known to be unknown to this program */
1415 else{
1416 #ifndef OTOOL
1417 unknown:
1418 #endif
1419 #ifndef OFI
1420 #ifdef LTO_SUPPORT
1421 if(is_llvm_bitcode(ofile, ofile->file_addr, ofile->file_size) ==
1422 TRUE){
1423 ofile->file_type = OFILE_LLVM_BITCODE;
1424 if(arch_flag != NULL){
1425 if(arch_flag->cputype != ofile->lto_cputype &&
1426 (arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) !=
1427 (ofile->lto_cpusubtype & ~CPU_SUBTYPE_MASK)){
1428 error("llvm bitcode file: %s does not match specified "
1429 "arch_flag: %s passed to ofile_map()",
1430 ofile->file_name, arch_flag->name);
1431 goto cleanup;
1434 if(object_name != NULL){
1435 error("file: %s is not an archive (object_name to "
1436 "ofile_map() can't be specified to be other than "
1437 "NULL)", ofile->file_name);
1438 goto cleanup;
1440 goto success;
1442 else
1443 #endif /* LTO_SUPPORT */
1444 #endif /* OFI */
1445 ofile->file_type = OFILE_UNKNOWN;
1446 if(arch_flag != NULL){
1447 #ifdef OFI
1448 ofile_unmap(ofile);
1449 return(NSObjectFileImageInappropriateFile);
1450 #else
1451 error("file: %s is unknown type (arch_flag to ofile_map() "
1452 "can't be specified to be other than NULL)",
1453 ofile->file_name);
1454 ofile_unmap(ofile);
1455 return(FALSE);
1456 #endif
1458 if(object_name != NULL){
1459 error("file: %s is not an archive (object_name to ofile_map() "
1460 "can't be specified to be other than NULL)",
1461 ofile->file_name);
1462 goto cleanup;
1465 success:
1466 return(TRUE);
1468 cleanup:
1469 ofile_unmap(ofile);
1470 return(FALSE);
1474 * ofile_unmap() deallocates the memory associated with the specified ofile
1475 * struct.
1477 __private_extern__
1478 void
1479 ofile_unmap(
1480 struct ofile *ofile)
1482 kern_return_t r;
1484 if(ofile->file_addr != NULL){
1485 if((r = vm_deallocate(mach_task_self(),
1486 (vm_address_t)ofile->file_addr,
1487 (vm_size_t)ofile->file_size)) != KERN_SUCCESS){
1488 my_mach_error(r, "Can't vm_deallocate mapped memory for file: "
1489 "%s", ofile->file_name);
1492 if(ofile->file_name != NULL)
1493 free(ofile->file_name);
1494 if(ofile->arch_flag.name != NULL)
1495 free(ofile->arch_flag.name);
1496 memset(ofile, '\0', sizeof(struct ofile));
1500 * ofile_first_arch() sets up the ofile struct for a fat file to the first arch
1501 * in it.
1503 __private_extern__
1504 enum bool
1505 ofile_first_arch(
1506 struct ofile *ofile)
1508 if(ofile->file_type == OFILE_FAT ||
1509 (ofile->file_type == OFILE_ARCHIVE &&
1510 ofile->member_type == OFILE_FAT) )
1511 return(ofile_specific_arch(ofile, 0));
1512 else{
1513 error("ofile_first_arch() called and file type of: %s is not a fat "
1514 "file\n", ofile->file_name);
1515 return(FALSE);
1520 * ofile_next_arch() sets up the ofile struct for a fat file to the next arch
1521 * in it.
1523 __private_extern__
1524 enum bool
1525 ofile_next_arch(
1526 struct ofile *ofile)
1528 if(ofile->file_type == OFILE_FAT ||
1529 (ofile->file_type == OFILE_ARCHIVE &&
1530 ofile->member_type == OFILE_FAT) ){
1531 if(ofile->narch + 1 < ofile->fat_header->nfat_arch)
1532 return(ofile_specific_arch(ofile, ofile->narch + 1));
1533 else
1534 return(FALSE);
1536 else{
1537 error("ofile_next_arch() called and file type of: %s is not a fat "
1538 "file\n", ofile->file_name);
1539 return(FALSE);
1544 * ofile_specific_arch() sets up the ofile struct for the fat file for the
1545 * specified narch.
1547 static
1548 enum bool
1549 ofile_specific_arch(
1550 struct ofile *ofile,
1551 uint32_t narch)
1553 char *addr;
1554 uint64_t size, offset;
1555 uint32_t magic;
1556 enum byte_sex host_byte_sex;
1558 ofile->narch = narch;
1559 ofile->arch_type = OFILE_UNKNOWN;
1560 if(ofile->arch_flag.name != NULL)
1561 free(ofile->arch_flag.name);
1562 ofile->arch_flag.name = NULL;
1563 ofile->arch_flag.cputype = 0;
1564 ofile->arch_flag.cpusubtype = 0;
1565 ofile->archive_cputype = 0;
1566 ofile->archive_cpusubtype = 0;
1567 ofile->object_addr = NULL;
1568 ofile->object_size = 0;
1569 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
1570 ofile->mh = NULL;
1571 ofile->mh64 = NULL;
1572 ofile->load_commands = NULL;
1574 if(ofile->fat_header->magic == FAT_MAGIC_64){
1575 ofile->arch_flag.cputype =
1576 ofile->fat_archs64[ofile->narch].cputype;
1577 ofile->arch_flag.cpusubtype =
1578 ofile->fat_archs64[ofile->narch].cpusubtype;
1580 else{
1581 ofile->arch_flag.cputype =
1582 ofile->fat_archs[ofile->narch].cputype;
1583 ofile->arch_flag.cpusubtype =
1584 ofile->fat_archs[ofile->narch].cpusubtype;
1586 set_arch_flag_name(&(ofile->arch_flag));
1589 /* Now determine the file type for this specific architecture */
1590 if(ofile->file_type == OFILE_FAT){
1591 ofile->member_offset = 0;
1592 ofile->member_addr = NULL;
1593 ofile->member_size = 0;
1594 ofile->member_ar_hdr = NULL;
1595 ofile->member_type = OFILE_UNKNOWN;
1597 if(ofile->fat_header->magic == FAT_MAGIC_64){
1598 size = ofile->fat_archs64[ofile->narch].size;
1599 addr = ofile->file_addr +
1600 ofile->fat_archs64[ofile->narch].offset;
1602 else{
1603 size = ofile->fat_archs[ofile->narch].size;
1604 addr = ofile->file_addr +
1605 ofile->fat_archs[ofile->narch].offset;
1608 else{
1609 if(ofile->file_type != OFILE_ARCHIVE ||
1610 ofile->member_type != OFILE_FAT){
1611 error("internal error. ofile_specific_arch() called but file "
1612 "is not a fat file or an archive with a fat member ");
1614 if(ofile->fat_header->magic == FAT_MAGIC_64){
1615 size = ofile->fat_archs64[ofile->narch].size;
1616 addr = ofile->file_addr +
1617 ofile->member_offset +
1618 ofile->fat_archs64[ofile->narch].offset;
1620 else{
1621 size = ofile->fat_archs[ofile->narch].size;
1622 addr = ofile->file_addr +
1623 ofile->member_offset +
1624 ofile->fat_archs[ofile->narch].offset;
1628 #ifdef OTOOL
1629 if(addr - ofile->file_addr > (ptrdiff_t)ofile->file_size){
1630 error("fat file: %s offset to architecture %s extends past end "
1631 "of file", ofile->file_name, ofile->arch_flag.name);
1632 return(FALSE);
1634 if(addr + size > ofile->file_addr + ofile->file_size)
1635 size = (ofile->file_addr + ofile->file_size) - addr;
1636 #endif /* OTOOL */
1637 if(ofile->fat_header->magic == FAT_MAGIC_64)
1638 offset = ofile->fat_archs64[ofile->narch].offset;
1639 else
1640 offset = ofile->fat_archs[ofile->narch].offset;
1642 if(size >= sizeof(struct mach_header))
1643 memcpy(&magic, addr, sizeof(uint32_t));
1644 /* see if this file is a 32-bit Mach-O file */
1645 if(size >= sizeof(struct mach_header) &&
1646 (magic == MH_MAGIC || magic == SWAP_INT(MH_MAGIC))){
1647 #ifdef ALIGNMENT_CHECKS
1648 if(offset % 4 != 0){
1649 if(ofile->file_type == OFILE_ARCHIVE){
1650 error("fat file: %s(%.*s) architecture %s malformed for a "
1651 "32-bit object file (offset is not a multiple of 4)",
1652 ofile->file_name, (int)ofile->member_name_size,
1653 ofile->member_name, ofile->arch_flag.name);
1655 else
1656 error("fat file: %s architecture %s malformed for a 32-bit "
1657 "object file (offset is not a multiple of 4)",
1658 ofile->file_name, ofile->arch_flag.name);
1659 goto cleanup;
1661 #endif /* ALIGNMENT_CHECKS */
1662 ofile->arch_type = OFILE_Mach_O;
1663 ofile->object_addr = addr;
1664 ofile->object_size = size;
1665 host_byte_sex = get_host_byte_sex();
1666 if(magic == MH_MAGIC)
1667 ofile->object_byte_sex = host_byte_sex;
1668 else
1669 ofile->object_byte_sex =
1670 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1671 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1672 ofile->mh = (struct mach_header *)addr;
1673 ofile->load_commands = (struct load_command *)(addr +
1674 sizeof(struct mach_header));
1675 if(check_Mach_O(ofile) == CHECK_BAD)
1676 goto cleanup;
1678 /* see if this file is a 64-bit Mach-O file */
1679 else if(size >= sizeof(struct mach_header_64) &&
1680 (magic == MH_MAGIC_64 || magic == SWAP_INT(MH_MAGIC_64))){
1681 #ifdef ALIGNMENT_CHECKS
1682 if(offset % 8 != 0){
1683 if(ofile->file_type == OFILE_ARCHIVE){
1684 error("fat file: %s(%.*s) architecture %s malformed for an "
1685 "object file (offset is not a multiple of 8)",
1686 ofile->file_name, (int)ofile->member_name_size,
1687 ofile->member_name, ofile->arch_flag.name);
1689 else
1690 error("fat file: %s architecture %s malformed for a 64-bit "
1691 "object file (offset is not a multiple of 8",
1692 ofile->file_name, ofile->arch_flag.name);
1693 goto cleanup;
1695 #endif /* ALIGNMENT_CHECKS */
1696 ofile->arch_type = OFILE_Mach_O;
1697 ofile->object_addr = addr;
1698 ofile->object_size = size;
1699 host_byte_sex = get_host_byte_sex();
1700 if(magic == MH_MAGIC_64)
1701 ofile->object_byte_sex = host_byte_sex;
1702 else
1703 ofile->object_byte_sex =
1704 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1705 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1706 ofile->mh64 = (struct mach_header_64 *)addr;
1707 ofile->load_commands = (struct load_command *)(addr +
1708 sizeof(struct mach_header_64));
1709 if(check_Mach_O(ofile) == CHECK_BAD)
1710 goto cleanup;
1712 /* see if this file is an archive file */
1713 else if(size >= SARMAG && strncmp(addr, ARMAG, SARMAG) == 0){
1714 ofile->arch_type = OFILE_ARCHIVE;
1715 if(check_archive(ofile, FALSE) == CHECK_BAD)
1716 goto cleanup;
1717 #ifdef ALIGNMENT_CHECKS
1718 if(ofile->archive_cputype != 0 && offset % sizeof(uint32_t) != 0){
1719 error("fat file: %s architecture %s malformed archive that "
1720 "contains object files (offset to archive is not a "
1721 "multiple of sizeof(uint32_t))",
1722 ofile->file_name, ofile->arch_flag.name);
1723 goto cleanup;
1725 #endif /* ALIGNMENT_CHECKS */
1728 * This type for this architecture is now known to be unknown to this
1729 * program.
1731 else{
1732 #ifdef LTO_SUPPORT
1733 if(is_llvm_bitcode(ofile, addr, size) == TRUE){
1734 ofile->arch_type = OFILE_LLVM_BITCODE;
1735 ofile->object_addr = addr;
1736 ofile->object_size = size;
1738 else
1739 #endif /* LTO_SUPPORT */
1740 ofile->arch_type = OFILE_UNKNOWN;
1742 return(TRUE);
1743 cleanup:
1744 ofile->narch = 0;;
1745 ofile->arch_type = OFILE_UNKNOWN;
1746 if(ofile->arch_flag.name != NULL)
1747 free(ofile->arch_flag.name);
1748 ofile->arch_flag.name = NULL;
1749 ofile->arch_flag.cputype = 0;
1750 ofile->arch_flag.cpusubtype = 0;
1751 if(ofile->file_type != OFILE_ARCHIVE){
1752 ofile->member_offset = 0;
1753 ofile->member_addr = NULL;
1754 ofile->member_size = 0;
1755 ofile->member_ar_hdr = NULL;
1756 ofile->member_type = OFILE_UNKNOWN;
1758 ofile->archive_cputype = 0;
1759 ofile->archive_cpusubtype = 0;
1760 ofile->object_addr = NULL;
1761 ofile->object_size = 0;
1762 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
1763 ofile->mh = NULL;
1764 ofile->mh64 = NULL;
1765 ofile->load_commands = NULL;
1766 return(FALSE);
1770 * ofile_first_member() set up the ofile structure (the member_* fields and
1771 * the object file fields if the first member is an object file) for the first
1772 * member.
1774 __private_extern__
1775 enum bool
1776 ofile_first_member(
1777 struct ofile *ofile)
1779 char *addr;
1780 uint64_t size, offset;
1781 uint32_t magic;
1782 enum byte_sex host_byte_sex;
1783 struct ar_hdr *ar_hdr;
1784 uint32_t ar_name_size;
1785 uint32_t sizeof_fat_archs;
1787 /* These fields are to be filled in by this routine, clear them first */
1788 ofile->member_offset = 0;
1789 ofile->member_addr = NULL;
1790 ofile->member_size = 0;
1791 ofile->member_ar_hdr = NULL;
1792 ofile->member_name = NULL;
1793 ofile->member_name_size = 0;
1794 ofile->member_type = OFILE_UNKNOWN;
1795 ofile->object_addr = NULL;
1796 ofile->object_size = 0;
1797 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
1798 ofile->mh = NULL;
1799 ofile->mh64 = NULL;
1800 ofile->load_commands = NULL;
1801 #ifdef LTO_SUPPORT
1803 * Note: it is up to the caller if they want to call free_lto() on this
1804 * when iterating through the members of an archive.
1806 ofile->lto = NULL;
1807 #endif /* LTO_SUPPORT */
1810 * Get the address and size of the archive.
1812 if(ofile->file_type == OFILE_FAT){
1813 if(ofile->arch_type != OFILE_ARCHIVE){
1814 error("ofile_first_member() called on fat file: %s with a "
1815 "non-archive architecture or no architecture selected\n",
1816 ofile->file_name);
1817 return(FALSE);
1819 if(ofile->fat_header->magic == FAT_MAGIC_64){
1820 addr = ofile->file_addr +
1821 ofile->fat_archs64[ofile->narch].offset;
1822 size = ofile->fat_archs64[ofile->narch].size;
1824 else{
1825 addr = ofile->file_addr +
1826 ofile->fat_archs[ofile->narch].offset;
1827 size = ofile->fat_archs[ofile->narch].size;
1830 else if(ofile->file_type == OFILE_ARCHIVE){
1831 addr = ofile->file_addr;
1832 size = ofile->file_size;
1834 else{
1835 error("ofile_first_member() called and file type of %s is "
1836 "OFILE_UNKNOWN\n", ofile->file_name);
1837 return(FALSE);
1839 #ifdef OTOOL
1840 if((addr + SARMAG) - ofile->file_addr > (ptrdiff_t)ofile->file_size){
1841 archive_error(ofile, "offset to first member extends past the end "
1842 "of the file");
1843 return(FALSE);
1845 if(addr + size > ofile->file_addr + ofile->file_size)
1846 size = (ofile->file_addr + ofile->file_size) - addr;
1847 #endif /* OTOOL */
1848 if(size < SARMAG || strncmp(addr, ARMAG, SARMAG) != 0){
1849 archive_error(ofile, "internal error. ofile_first_member() "
1850 "called but file does not have an archive magic "
1851 "string");
1852 return(FALSE);
1855 offset = SARMAG;
1856 if(offset != size && offset + sizeof(struct ar_hdr) > size){
1857 archive_error(ofile, "truncated or malformed (archive header of "
1858 "first member extends past the end of the file)");
1859 return(FALSE);
1862 /* check for empty archive */
1863 if(size == offset)
1864 return(FALSE);
1866 /* now we know there is a first member so set it up */
1867 ar_hdr = (struct ar_hdr *)(addr + offset);
1868 offset += sizeof(struct ar_hdr);
1869 ofile->member_offset = offset;
1870 ofile->member_addr = addr + offset;
1871 ofile->member_size = strtoul(ar_hdr->ar_size, NULL, 10);
1872 if(ofile->member_size > size - sizeof(struct ar_hdr)){
1873 archive_error(ofile, "size of first archive member extends past "
1874 "the end of the archive");
1875 ofile->member_size = size - sizeof(struct ar_hdr);
1877 ofile->member_ar_hdr = ar_hdr;
1878 ofile->member_type = OFILE_UNKNOWN;
1879 ofile->member_name = ar_hdr->ar_name;
1880 if(strncmp(ofile->member_name, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0){
1881 ofile->member_name = ar_hdr->ar_name + sizeof(struct ar_hdr);
1882 ar_name_size = strtoul(ar_hdr->ar_name + sizeof(AR_EFMT1) - 1,
1883 NULL, 10);
1884 if(ar_name_size > ofile->member_size){
1885 archive_error(ofile, "size of first archive member name "
1886 "extends past the end of the archive");
1887 ar_name_size = ofile->member_size;
1889 ofile->member_name_size = ar_name_size;
1890 ofile->member_offset += ar_name_size;
1891 ofile->member_addr += ar_name_size;
1892 ofile->member_size -= ar_name_size;
1894 else{
1895 ofile->member_name_size = size_ar_name(ar_hdr);
1896 ar_name_size = 0;
1898 /* Clear these in case there is no table of contents */
1899 ofile->toc_addr = NULL;
1900 ofile->toc_size = 0;
1901 ofile->toc_ar_hdr = NULL;
1902 ofile->toc_name = NULL;
1903 ofile->toc_name_size = 0;
1904 ofile->toc_ranlibs = NULL;
1905 ofile->toc_ranlibs64 = NULL;
1906 ofile->toc_nranlibs = 0;
1907 ofile->toc_strings = NULL;
1908 ofile->toc_strsize = 0;
1909 ofile->toc_bad = FALSE;
1911 /* Clear these until we find a System V "//" named archive member */
1912 ofile->sysv_ar_strtab = NULL;
1913 ofile->sysv_ar_strtab_size = 0;
1915 host_byte_sex = get_host_byte_sex();
1917 if(ofile->member_size > sizeof(uint32_t)){
1918 memcpy(&magic, ofile->member_addr, sizeof(uint32_t));
1919 #ifdef __BIG_ENDIAN__
1920 if(magic == FAT_MAGIC || magic == FAT_MAGIC_64)
1921 #endif /* __BIG_ENDIAN__ */
1922 #ifdef __LITTLE_ENDIAN__
1923 if(magic == SWAP_INT(FAT_MAGIC) || magic == SWAP_INT(FAT_MAGIC_64))
1924 #endif /* __LITTLE_ENDIAN__ */
1926 ofile->member_type = OFILE_FAT;
1927 ofile->fat_header =
1928 (struct fat_header *)(ofile->member_addr);
1929 #ifdef __LITTLE_ENDIAN__
1930 swap_fat_header(ofile->fat_header, host_byte_sex);
1931 #endif /* __LITTLE_ENDIAN__ */
1932 if(ofile->fat_header->magic == FAT_MAGIC_64)
1933 sizeof_fat_archs = ofile->fat_header->nfat_arch *
1934 sizeof(struct fat_arch_64);
1935 else
1936 sizeof_fat_archs = ofile->fat_header->nfat_arch *
1937 sizeof(struct fat_arch);
1938 if(sizeof(struct fat_header) + sizeof_fat_archs >
1939 ofile->member_size){
1940 archive_member_error(ofile, "fat file truncated or "
1941 "malformed (fat_arch%s structs would extend past "
1942 "the end of the archive member)",
1943 ofile->fat_header->magic == FAT_MAGIC_64 ?
1944 "_64" : "");
1945 goto fatcleanup;
1947 if(ofile->fat_header->magic == FAT_MAGIC_64){
1948 ofile->fat_archs64 = (struct fat_arch_64 *)
1949 (ofile->member_addr + sizeof(struct fat_header));
1950 #ifdef __LITTLE_ENDIAN__
1951 swap_fat_arch_64(ofile->fat_archs64,
1952 ofile->fat_header->nfat_arch,
1953 host_byte_sex);
1954 #endif /* __LITTLE_ENDIAN__ */
1956 else{
1957 ofile->fat_archs = (struct fat_arch *)
1958 (ofile->member_addr + sizeof(struct fat_header));
1959 #ifdef __LITTLE_ENDIAN__
1960 swap_fat_arch(ofile->fat_archs,
1961 ofile->fat_header->nfat_arch, host_byte_sex);
1962 #endif /* __LITTLE_ENDIAN__ */
1964 if(check_fat_object_in_archive(ofile) == FALSE)
1965 goto fatcleanup;
1967 else if(size - (offset + ar_name_size) >=
1968 sizeof(struct mach_header) &&
1969 (magic == MH_MAGIC || magic == SWAP_INT(MH_MAGIC))){
1970 #ifdef ALIGNMENT_CHECKS
1971 if((offset + ar_name_size) % 4 != 0){
1972 archive_member_error(ofile, "offset in archive not a "
1973 "multiple of 4 (must be since member is a 32-bit "
1974 "object file)");
1975 goto cleanup;
1977 #endif /* ALIGNMENT_CHECKS */
1978 ofile->member_type = OFILE_Mach_O;
1979 ofile->object_addr = ofile->member_addr;
1980 ofile->object_size = ofile->member_size;
1981 if(magic == MH_MAGIC)
1982 ofile->object_byte_sex = host_byte_sex;
1983 else
1984 ofile->object_byte_sex =
1985 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1986 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1987 ofile->mh = (struct mach_header *)(ofile->object_addr);
1988 ofile->load_commands = (struct load_command *)
1989 (ofile->object_addr + sizeof(struct mach_header));
1990 if(check_Mach_O(ofile) == CHECK_BAD)
1991 goto cleanup;
1993 else if(size - (offset + ar_name_size) >=
1994 sizeof(struct mach_header_64) &&
1995 (magic == MH_MAGIC_64 || magic == SWAP_INT(MH_MAGIC_64))){
1996 #ifdef ALIGNMENT_CHECKS_ARCHIVE_64_BIT
1997 if(archive_64_bit_align_warning == FALSE &&
1998 (offset + ar_name_size) % 8 != 0){
1999 temporary_archive_member_warning(ofile, "offset in archive "
2000 "not a multiple of 8 (must be since member is an "
2001 "64-bit object file)");
2002 archive_64_bit_align_warning = TRUE;
2003 /* goto cleanup; */
2005 #endif /* ALIGNMENT_CHECKS_ARCHIVE_64_BIT */
2006 ofile->member_type = OFILE_Mach_O;
2007 ofile->object_addr = ofile->member_addr;
2008 ofile->object_size = ofile->member_size;
2009 if(magic == MH_MAGIC_64)
2010 ofile->object_byte_sex = host_byte_sex;
2011 else
2012 ofile->object_byte_sex =
2013 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
2014 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
2015 ofile->mh64 = (struct mach_header_64 *)(ofile->object_addr);
2016 ofile->load_commands = (struct load_command *)
2017 (ofile->object_addr + sizeof(struct mach_header_64));
2018 if(check_Mach_O(ofile) == CHECK_BAD)
2019 goto cleanup;
2021 if(ofile->member_type == OFILE_UNKNOWN &&
2022 (strncmp(ofile->member_name, SYMDEF_SORTED,
2023 sizeof(SYMDEF_SORTED) - 1) == 0 ||
2024 strncmp(ofile->member_name, SYMDEF,
2025 sizeof(SYMDEF) - 1) == 0 ||
2026 strncmp(ofile->member_name, SYMDEF_64_SORTED,
2027 sizeof(SYMDEF_64_SORTED) - 1) == 0 ||
2028 strncmp(ofile->member_name, SYMDEF_64,
2029 sizeof(SYMDEF_64) - 1) == 0)){
2030 ofile->toc_addr = ofile->member_addr;
2031 ofile->toc_size = ofile->member_size;
2032 ofile->toc_ar_hdr = ofile->member_ar_hdr;
2033 ofile->toc_name = ofile->member_name;
2034 ofile->toc_name_size = ofile->member_name_size;
2035 if(check_archive_toc(ofile) == CHECK_BAD)
2036 goto cleanup;
2038 else if(ofile->member_type == OFILE_UNKNOWN &&
2039 strcmp(ofile->member_name, "// ") == 0){
2040 ofile->sysv_ar_strtab = ofile->member_addr;
2041 ofile->sysv_ar_strtab_size = ofile->member_size;
2043 #ifdef LTO_SUPPORT
2044 if(ofile->member_type == OFILE_UNKNOWN &&
2045 strncmp(ofile->member_name, SYMDEF_SORTED,
2046 sizeof(SYMDEF_SORTED) - 1) != 0 &&
2047 strncmp(ofile->member_name, SYMDEF,
2048 sizeof(SYMDEF) - 1) != 0 &&
2049 is_llvm_bitcode(ofile, ofile->member_addr, ofile->member_size) ==
2050 TRUE){
2051 ofile->member_type = OFILE_LLVM_BITCODE;
2052 ofile->object_addr = ofile->member_addr;
2053 ofile->object_size = ofile->member_size;
2055 #endif /* LTO_SUPPORT */
2057 return(TRUE);
2059 fatcleanup:
2060 ofile->fat_header = NULL;
2061 ofile->fat_archs = NULL;
2062 ofile->fat_archs64 = NULL;
2063 cleanup:
2064 ofile->member_offset = 0;
2065 ofile->member_addr = 0;
2066 ofile->member_size = 0;
2067 ofile->member_ar_hdr = NULL;
2068 ofile->member_name = NULL;
2069 ofile->member_name_size = 0;
2070 ofile->member_type = OFILE_UNKNOWN;
2071 ofile->object_addr = NULL;
2072 ofile->object_size = 0;
2073 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
2074 ofile->mh = NULL;
2075 ofile->mh64 = NULL;
2076 ofile->load_commands = NULL;
2077 #ifdef LTO_SUPPORT
2078 ofile->lto = NULL;
2079 ofile->lto_cputype = 0;
2080 ofile->lto_cpusubtype = 0;
2081 #endif /* LTO_SUPPORT */
2082 return(FALSE);
2086 * ofile_next_member() set up the ofile structure (the member_* fields and
2087 * the object file fields if the next member is an object file) for the next
2088 * member.
2090 __private_extern__
2091 enum bool
2092 ofile_next_member(
2093 struct ofile *ofile)
2095 char *addr;
2096 uint64_t size, offset;
2097 uint32_t magic;
2098 enum byte_sex host_byte_sex;
2099 struct ar_hdr *ar_hdr;
2100 uint32_t ar_name_size, member_name_offset, n;
2101 uint32_t sizeof_fat_archs;
2104 * Get the address and size of the archive.
2106 if(ofile->file_type == OFILE_FAT){
2107 if(ofile->arch_type != OFILE_ARCHIVE){
2108 error("ofile_next_member() called on fat file: %s with a "
2109 "non-archive architecture or no architecture selected\n",
2110 ofile->file_name);
2111 return(FALSE);
2113 if(ofile->fat_header->magic == FAT_MAGIC_64){
2114 addr = ofile->file_addr +
2115 ofile->fat_archs64[ofile->narch].offset;
2116 size = ofile->fat_archs64[ofile->narch].size;
2118 else{
2119 addr = ofile->file_addr +
2120 ofile->fat_archs[ofile->narch].offset;
2121 size = ofile->fat_archs[ofile->narch].size;
2124 else if(ofile->file_type == OFILE_ARCHIVE){
2125 addr = ofile->file_addr;
2126 size = ofile->file_size;
2128 else{
2129 error("ofile_next_member() called and file type of %s is "
2130 "OFILE_UNKNOWN\n", ofile->file_name);
2131 return(FALSE);
2133 if(size < SARMAG || strncmp(addr, ARMAG, SARMAG) != 0){
2134 archive_error(ofile, "internal error. ofile_next_member() "
2135 "called but file does not have an archive magic "
2136 "string");
2137 return(FALSE);
2139 if(ofile->member_ar_hdr == NULL){
2140 archive_error(ofile, "internal error. ofile_next_member() called "
2141 "but the ofile struct does not have an archive "
2142 "member selected");
2143 return(FALSE);
2146 /* figure out the offset to the next member */
2147 offset = ofile->member_offset + rnd(ofile->member_size,sizeof(short));
2148 #ifdef OTOOL
2149 if((addr - ofile->file_addr) + offset > ofile->file_size){
2150 archive_error(ofile, "offset to next member extends past the end "
2151 "of the file");
2152 return(FALSE);
2154 #endif /* OTOOL */
2155 /* if now at the end of the file then no more members */
2156 if(offset == size)
2157 goto cleanup;
2158 if(offset > size){
2159 archive_error(ofile, "truncated or malformed (archive header of "
2160 "next member extends past the end of the file)");
2161 return(FALSE);
2164 /* now we know there is a next member so set it up */
2165 ar_hdr = (struct ar_hdr *)(addr + offset);
2166 offset += sizeof(struct ar_hdr);
2167 ofile->member_offset = offset;
2168 ofile->member_addr = addr + offset;
2169 ofile->member_size = strtoul(ar_hdr->ar_size, NULL, 10);
2170 if(ofile->member_size > size - sizeof(struct ar_hdr)){
2171 archive_error(ofile, "size of archive member extends past "
2172 "the end of the archive");
2173 ofile->member_size = size - sizeof(struct ar_hdr);
2175 ofile->member_ar_hdr = ar_hdr;
2176 ofile->member_name = ar_hdr->ar_name;
2177 if(ofile->sysv_ar_strtab == NULL && ofile->sysv_ar_strtab_size == 0 &&
2178 strncmp(ofile->member_name, "// ", sizeof("// ") - 1) == 0){
2179 ofile->sysv_ar_strtab = ofile->member_addr;
2180 ofile->sysv_ar_strtab_size = ofile->member_size;
2182 if(ofile->member_name[0] == '/' &&
2183 (ofile->member_name[1] != ' ' && ofile->member_name[1] != '/')){
2184 member_name_offset = strtoul(ar_hdr->ar_name + 1, NULL, 10);
2185 if(member_name_offset < ofile->sysv_ar_strtab_size){
2186 ofile->member_name = ofile->sysv_ar_strtab + member_name_offset;
2187 ofile->member_name_size = 0;
2188 for(n = member_name_offset;
2189 n < ofile->sysv_ar_strtab_size; n++){
2190 if(ofile->sysv_ar_strtab[n] == '/')
2191 break;
2192 ofile->member_name_size++;
2195 else
2196 ofile->member_name_size = size_ar_name(ar_hdr);
2198 else if(strncmp(ofile->member_name, AR_EFMT1,
2199 sizeof(AR_EFMT1) - 1) == 0){
2200 ofile->member_name = ar_hdr->ar_name + sizeof(struct ar_hdr);
2201 ar_name_size = strtoul(ar_hdr->ar_name + sizeof(AR_EFMT1) - 1,
2202 NULL, 10);
2203 if(ar_name_size > ofile->member_size){
2204 archive_error(ofile, "size of archive member name "
2205 "extends past the end of the archive");
2206 ar_name_size = ofile->member_size;
2208 ofile->member_name_size = ar_name_size;
2209 ofile->member_offset += ar_name_size;
2210 ofile->member_addr += ar_name_size;
2211 ofile->member_size -= ar_name_size;
2213 else{
2214 ofile->member_name_size = size_ar_name(ar_hdr);
2215 ar_name_size = 0;
2217 ofile->member_type = OFILE_UNKNOWN;
2218 ofile->object_addr = NULL;
2219 ofile->object_size = 0;
2220 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
2221 ofile->mh = NULL;
2222 ofile->mh64 = NULL;
2223 ofile->load_commands = NULL;
2225 host_byte_sex = get_host_byte_sex();
2227 if(ofile->member_size > sizeof(uint32_t)){
2228 memcpy(&magic, ofile->member_addr, sizeof(uint32_t));
2229 #ifdef __BIG_ENDIAN__
2230 if(magic == FAT_MAGIC || magic == FAT_MAGIC_64)
2231 #endif /* __BIG_ENDIAN__ */
2232 #ifdef __LITTLE_ENDIAN__
2233 if(magic == SWAP_INT(FAT_MAGIC) || magic == SWAP_INT(FAT_MAGIC_64))
2234 #endif /* __LITTLE_ENDIAN__ */
2236 ofile->member_type = OFILE_FAT;
2237 ofile->fat_header = (struct fat_header *)(ofile->member_addr);
2238 #ifdef __LITTLE_ENDIAN__
2239 swap_fat_header(ofile->fat_header, host_byte_sex);
2240 #endif /* __LITTLE_ENDIAN__ */
2241 if(ofile->fat_header->magic == FAT_MAGIC_64)
2242 sizeof_fat_archs = ofile->fat_header->nfat_arch *
2243 sizeof(struct fat_arch_64);
2244 else
2245 sizeof_fat_archs = ofile->fat_header->nfat_arch *
2246 sizeof(struct fat_arch);
2247 if(sizeof(struct fat_header) + sizeof_fat_archs >
2248 ofile->member_size){
2249 archive_member_error(ofile, "fat file truncated or "
2250 "malformed (fat_arch%s structs would extend past "
2251 "the end of the archive member)",
2252 ofile->fat_header->magic == FAT_MAGIC_64 ?
2253 "_64" : "");
2254 goto cleanup;
2256 if(ofile->fat_header->magic == FAT_MAGIC_64){
2257 ofile->fat_archs64 = (struct fat_arch_64 *)
2258 (ofile->member_addr + sizeof(struct fat_header));
2259 #ifdef __LITTLE_ENDIAN__
2260 swap_fat_arch_64(ofile->fat_archs64,
2261 ofile->fat_header->nfat_arch,
2262 host_byte_sex);
2263 #endif /* __LITTLE_ENDIAN__ */
2265 else{
2266 ofile->fat_archs = (struct fat_arch *)
2267 (ofile->member_addr + sizeof(struct fat_header));
2268 #ifdef __LITTLE_ENDIAN__
2269 swap_fat_arch(ofile->fat_archs,
2270 ofile->fat_header->nfat_arch, host_byte_sex);
2271 #endif /* __LITTLE_ENDIAN__ */
2273 if(check_fat_object_in_archive(ofile) == FALSE)
2274 goto cleanup;
2276 else if(size - (offset + ar_name_size) >=
2277 sizeof(struct mach_header) &&
2278 (magic == MH_MAGIC ||
2279 magic == SWAP_INT(MH_MAGIC))){
2280 #ifdef ALIGNMENT_CHECKS
2281 if((offset + ar_name_size) % 4 != 0){
2282 archive_member_error(ofile, "offset in archive not "
2283 "a multiple of 4 (must be since member is an 32-bit "
2284 "object file)");
2285 goto cleanup;
2287 #endif /* ALIGNMENT_CHECKS */
2288 ofile->member_type = OFILE_Mach_O;
2289 ofile->object_addr = ofile->member_addr;
2290 ofile->object_size = ofile->member_size;
2291 if(magic == MH_MAGIC)
2292 ofile->object_byte_sex = host_byte_sex;
2293 else
2294 ofile->object_byte_sex =
2295 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
2296 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
2297 ofile->mh = (struct mach_header *)ofile->object_addr;
2298 ofile->load_commands = (struct load_command *)
2299 (ofile->object_addr + sizeof(struct mach_header));
2300 if(check_Mach_O(ofile) == CHECK_BAD)
2301 goto cleanup;
2303 else if(size - (offset + ar_name_size) >=
2304 sizeof(struct mach_header_64) &&
2305 (magic == MH_MAGIC_64 ||
2306 magic == SWAP_INT(MH_MAGIC_64))){
2307 #ifdef ALIGNMENT_CHECKS_ARCHIVE_64_BIT
2308 if(archive_64_bit_align_warning == FALSE &&
2309 (offset + ar_name_size) % 8 != 0){
2310 temporary_archive_member_warning(ofile, "offset in archive "
2311 "not a multiple of 8 (must be since member is an "
2312 "64-bit object file)");
2313 archive_64_bit_align_warning = TRUE;
2314 /* goto cleanup; */
2316 #endif /* ALIGNMENT_CHECKS_ARCHIVE_64_BIT */
2317 ofile->member_type = OFILE_Mach_O;
2318 ofile->object_addr = ofile->member_addr;
2319 ofile->object_size = ofile->member_size;
2320 if(magic == MH_MAGIC_64)
2321 ofile->object_byte_sex = host_byte_sex;
2322 else
2323 ofile->object_byte_sex =
2324 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
2325 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
2326 ofile->mh64 = (struct mach_header_64 *)ofile->object_addr;
2327 ofile->load_commands = (struct load_command *)
2328 (ofile->object_addr + sizeof(struct mach_header_64));
2329 if(check_Mach_O(ofile) == CHECK_BAD)
2330 goto cleanup;
2332 #ifdef LTO_SUPPORT
2333 if(ofile->member_type == OFILE_UNKNOWN &&
2334 is_llvm_bitcode(ofile, ofile->member_addr, ofile->member_size) ==
2335 TRUE){
2336 ofile->member_type = OFILE_LLVM_BITCODE;
2337 ofile->object_addr = ofile->member_addr;
2338 ofile->object_size = ofile->member_size;
2340 #endif /* LTO_SUPPORT */
2342 return(TRUE);
2344 cleanup:
2345 if(ofile->member_type == OFILE_FAT){
2346 ofile->fat_header = NULL;
2347 ofile->fat_archs = NULL;
2348 ofile->fat_archs64 = NULL;
2350 ofile->member_offset = 0;
2351 ofile->member_addr = NULL;
2352 ofile->member_size = 0;
2353 ofile->member_ar_hdr = NULL;
2354 ofile->member_name = NULL;
2355 ofile->member_name_size = 0;
2356 ofile->member_type = OFILE_UNKNOWN;
2357 ofile->object_addr = NULL;
2358 ofile->object_size = 0;
2359 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
2360 ofile->mh = NULL;
2361 ofile->mh64 = NULL;
2362 ofile->load_commands = NULL;
2363 #ifdef LTO_SUPPORT
2364 ofile->lto = NULL;
2365 ofile->lto_cputype = 0;
2366 ofile->lto_cpusubtype = 0;
2367 #endif /* LTO_SUPPORT */
2368 return(FALSE);
2372 * ofile_specific_member() set up the ofile structure (the member_* fields and
2373 * the object file fields if the member is an object file) for the specified
2374 * member member_name.
2376 __private_extern__
2377 enum bool
2378 ofile_specific_member(
2379 const char *member_name,
2380 struct ofile *ofile)
2382 int32_t i, n;
2383 char *addr;
2384 uint64_t size, offset;
2385 uint32_t magic;
2386 enum byte_sex host_byte_sex;
2387 char *ar_name;
2388 uint32_t ar_name_size, member_name_offset;
2389 struct ar_hdr *ar_hdr;
2390 uint32_t sizeof_fat_archs;
2392 /* These fields are to be filled in by this routine, clear them first */
2393 ofile->member_offset = 0;
2394 ofile->member_addr = NULL;
2395 ofile->member_size = 0;
2396 ofile->member_ar_hdr = NULL;
2397 ofile->member_name = NULL;
2398 ofile->member_name_size = 0;
2399 ofile->member_type = OFILE_UNKNOWN;
2400 ofile->object_addr = NULL;
2401 ofile->object_size = 0;
2402 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
2403 ofile->mh = NULL;
2404 ofile->mh64 = NULL;
2405 ofile->load_commands = NULL;
2408 * Get the address and size of the archive.
2410 if(ofile->file_type == OFILE_FAT){
2411 if(ofile->arch_type != OFILE_ARCHIVE){
2412 error("ofile_specific_member() called on fat file: %s with a "
2413 "non-archive architecture or no architecture selected\n",
2414 ofile->file_name);
2415 return(FALSE);
2417 if(ofile->fat_header->magic == FAT_MAGIC_64){
2418 addr = ofile->file_addr +
2419 ofile->fat_archs64[ofile->narch].offset;
2420 size = ofile->fat_archs64[ofile->narch].size;
2422 else{
2423 addr = ofile->file_addr +
2424 ofile->fat_archs[ofile->narch].offset;
2425 size = ofile->fat_archs[ofile->narch].size;
2428 else if(ofile->file_type == OFILE_ARCHIVE){
2429 addr = ofile->file_addr;
2430 size = ofile->file_size;
2432 else{
2433 error("ofile_specific_member() called and file type of %s is "
2434 "OFILE_UNKNOWN\n", ofile->file_name);
2435 return(FALSE);
2437 if(size < SARMAG || strncmp(addr, ARMAG, SARMAG) != 0){
2438 archive_error(ofile, "internal error. ofile_specific_member() "
2439 "called but file does not have an archive magic "
2440 "string");
2441 return(FALSE);
2444 /* Clear these until we find a System V "//" named archive member */
2445 ofile->sysv_ar_strtab = NULL;
2446 ofile->sysv_ar_strtab_size = 0;
2448 offset = SARMAG;
2449 if(offset != size && offset + sizeof(struct ar_hdr) > size){
2450 archive_error(ofile, "truncated or malformed (archive header of "
2451 "first member extends past the end of the file)");
2452 return(FALSE);
2454 while(size > offset){
2455 ar_hdr = (struct ar_hdr *)(addr + offset);
2456 offset += sizeof(struct ar_hdr);
2458 if(ofile->sysv_ar_strtab == NULL &&
2459 ofile->sysv_ar_strtab_size == 0 &&
2460 strncmp(ar_hdr->ar_name, "// ", sizeof("// ") - 1) == 0){
2461 ofile->sysv_ar_strtab = addr + offset;
2462 ofile->sysv_ar_strtab_size = strtoul(ar_hdr->ar_size, NULL, 10);
2465 if(ar_hdr->ar_name[0] == '/' &&
2466 (ar_hdr->ar_name[1] != ' ' && ar_hdr->ar_name[1] != '/')){
2467 member_name_offset = strtoul(ar_hdr->ar_name + 1, NULL, 10);
2468 if(member_name_offset < ofile->sysv_ar_strtab_size){
2469 ar_name = ofile->sysv_ar_strtab + member_name_offset;
2470 i = 0;
2471 for(n = member_name_offset;
2472 n < ofile->sysv_ar_strtab_size; n++){
2473 if(ofile->sysv_ar_strtab[n] == '/')
2474 break;
2475 i++;
2477 ar_name_size = 0;
2479 else{
2480 i = size_ar_name(ar_hdr);
2481 ar_name = ar_hdr->ar_name;
2482 ar_name_size = 0;
2485 else if(strncmp(ar_hdr->ar_name, AR_EFMT1,
2486 sizeof(AR_EFMT1) - 1) == 0){
2487 #ifdef OTOOL
2488 if(check_extend_format_1(ofile, ar_hdr, size - offset,
2489 &ar_name_size) == CHECK_BAD){
2490 i = size_ar_name(ar_hdr);
2491 ar_name = ar_hdr->ar_name;
2492 ar_name_size = 0;
2494 else
2495 #endif /* OTOOL */
2497 i = strtoul(ar_hdr->ar_name + sizeof(AR_EFMT1) - 1,NULL,10);
2498 ar_name = ar_hdr->ar_name + sizeof(struct ar_hdr);
2499 ar_name_size = i;
2502 else{
2503 i = size_ar_name(ar_hdr);
2504 ar_name = ar_hdr->ar_name;
2505 ar_name_size = 0;
2507 if(i > 0 && strncmp(ar_name, member_name, i) == 0){
2509 ofile->member_name = ar_name;
2510 ofile->member_name_size = i;
2511 ofile->member_offset = offset + ar_name_size;
2512 ofile->member_addr = addr + offset + ar_name_size;
2513 ofile->member_size = strtoul(ar_hdr->ar_size, NULL, 10) -
2514 ar_name_size;
2515 ofile->member_ar_hdr = ar_hdr;
2516 ofile->member_type = OFILE_UNKNOWN;
2518 host_byte_sex = get_host_byte_sex();
2520 if(ofile->member_size > sizeof(uint32_t)){
2521 memcpy(&magic, addr + offset + ar_name_size,
2522 sizeof(uint32_t));
2523 #ifdef __BIG_ENDIAN__
2524 if(magic == FAT_MAGIC || magic == FAT_MAGIC_64)
2525 #endif /* __BIG_ENDIAN__ */
2526 #ifdef __LITTLE_ENDIAN__
2527 if(magic == SWAP_INT(FAT_MAGIC) ||
2528 magic == SWAP_INT(FAT_MAGIC_64))
2529 #endif /* __LITTLE_ENDIAN__ */
2531 ofile->member_type = OFILE_FAT;
2532 ofile->fat_header =
2533 (struct fat_header *)(addr + offset + ar_name_size);
2534 #ifdef __LITTLE_ENDIAN__
2535 swap_fat_header(ofile->fat_header, host_byte_sex);
2536 #endif /* __LITTLE_ENDIAN__ */
2537 if(ofile->fat_header->magic == FAT_MAGIC_64)
2538 sizeof_fat_archs = ofile->fat_header->nfat_arch *
2539 sizeof(struct fat_arch_64);
2540 else
2541 sizeof_fat_archs = ofile->fat_header->nfat_arch *
2542 sizeof(struct fat_arch);
2543 if(sizeof(struct fat_header) + sizeof_fat_archs >
2544 ofile->member_size){
2545 archive_member_error(ofile, "fat file truncated or "
2546 "malformed (fat_arch%s structs would extend"
2547 " past the end of the archive member)",
2548 ofile->fat_header->magic == FAT_MAGIC_64 ?
2549 "_64" : "");
2550 goto fatcleanup;
2552 if(ofile->fat_header->magic == FAT_MAGIC_64){
2553 ofile->fat_archs64 =
2554 (struct fat_arch_64 *)
2555 (addr + offset + ar_name_size +
2556 sizeof(struct fat_header));
2557 #ifdef __LITTLE_ENDIAN__
2558 swap_fat_arch_64(ofile->fat_archs64,
2559 ofile->fat_header->nfat_arch,
2560 host_byte_sex);
2561 #endif /* __LITTLE_ENDIAN__ */
2563 else{
2564 ofile->fat_archs =
2565 (struct fat_arch *)
2566 (addr + offset + ar_name_size +
2567 sizeof(struct fat_header));
2568 #ifdef __LITTLE_ENDIAN__
2569 swap_fat_arch(ofile->fat_archs,
2570 ofile->fat_header->nfat_arch,
2571 host_byte_sex);
2572 #endif /* __LITTLE_ENDIAN__ */
2574 if(check_fat_object_in_archive(ofile) == FALSE)
2575 goto fatcleanup;
2577 else if(size - (offset + ar_name_size) >=
2578 sizeof(struct mach_header) &&
2579 (magic == MH_MAGIC ||
2580 magic == SWAP_INT(MH_MAGIC))){
2581 #ifdef ALIGNMENT_CHECKS
2582 if((offset + ar_name_size) % 4 != 0){
2583 archive_member_error(ofile, "offset in archive not "
2584 "a multiple of 4) (must be since member is a "
2585 "32-bit object file)");
2586 goto cleanup;
2588 #endif /* ALIGNMENT_CHECKS */
2589 ofile->member_type = OFILE_Mach_O;
2590 ofile->object_addr = ofile->member_addr;
2591 ofile->object_size = ofile->member_size;
2592 if(magic == MH_MAGIC)
2593 ofile->object_byte_sex = host_byte_sex;
2594 else
2595 ofile->object_byte_sex =
2596 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
2597 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
2598 ofile->mh = (struct mach_header *)ofile->object_addr;
2599 ofile->load_commands = (struct load_command *)
2600 (ofile->object_addr + sizeof(struct mach_header));
2601 if(check_Mach_O(ofile) == CHECK_BAD)
2602 goto cleanup;
2604 else if(size - (offset + ar_name_size) >=
2605 sizeof(struct mach_header_64) &&
2606 (magic == MH_MAGIC_64 ||
2607 magic == SWAP_INT(MH_MAGIC_64))){
2608 #ifdef ALIGNMENT_CHECKS_ARCHIVE_64_BIT
2609 if(archive_64_bit_align_warning == FALSE &&
2610 (offset + ar_name_size) % 8 != 0){
2611 temporary_archive_member_warning(ofile, "offset in "
2612 "archive not a multiple of 8) (must be since "
2613 "member is a 64-bit object file)");
2614 archive_64_bit_align_warning = TRUE;
2615 /* goto cleanup; */
2617 #endif /* ALIGNMENT_CHECKS_ARCHIVE_64_BIT */
2618 ofile->member_type = OFILE_Mach_O;
2619 ofile->object_addr = ofile->member_addr;
2620 ofile->object_size = ofile->member_size;
2621 if(magic == MH_MAGIC_64)
2622 ofile->object_byte_sex = host_byte_sex;
2623 else
2624 ofile->object_byte_sex =
2625 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
2626 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
2627 ofile->mh64 = (struct mach_header_64 *)
2628 ofile->object_addr;
2629 ofile->load_commands = (struct load_command *)
2630 (ofile->object_addr +sizeof(struct mach_header_64));
2631 if(check_Mach_O(ofile) == CHECK_BAD)
2632 goto cleanup;
2635 #ifdef LTO_SUPPORT
2636 if(ofile->member_type == OFILE_UNKNOWN &&
2637 is_llvm_bitcode(ofile, ofile->member_addr,
2638 ofile->member_size) == TRUE){
2639 ofile->member_type = OFILE_LLVM_BITCODE;
2640 ofile->object_addr = ofile->member_addr;
2641 ofile->object_size = ofile->member_size;
2643 #endif /* LTO_SUPPORT */
2644 return(TRUE);
2646 offset += rnd(strtoul(ar_hdr->ar_size, NULL, 10),
2647 sizeof(short));
2649 archive_error(ofile, "does not contain a member named: %s",
2650 member_name);
2651 fatcleanup:
2652 ofile->fat_header = NULL;
2653 ofile->fat_archs = NULL;
2654 ofile->fat_archs64 = NULL;
2655 cleanup:
2656 ofile->member_offset = 0;
2657 ofile->member_addr = NULL;
2658 ofile->member_size = 0;
2659 ofile->member_ar_hdr = NULL;
2660 ofile->member_name = NULL;
2661 ofile->member_name_size = 0;
2662 ofile->member_type = OFILE_UNKNOWN;
2663 ofile->object_addr = NULL;
2664 ofile->object_size = 0;
2665 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
2666 ofile->mh = NULL;
2667 ofile->mh64 = NULL;
2668 ofile->load_commands = NULL;
2669 #ifdef LTO_SUPPORT
2670 ofile->lto = NULL;
2671 ofile->lto_cputype = 0;
2672 ofile->lto_cpusubtype = 0;
2673 #endif /* LTO_SUPPORT */
2674 return(FALSE);
2678 * ofile_first_module() set up the ofile structure (the dylib_module field)
2679 * for the first module of an MH_DYLIB or MH_DYLIB_STUB file.
2681 __private_extern__
2682 enum bool
2683 ofile_first_module(
2684 struct ofile *ofile)
2686 uint32_t i, ncmds;
2687 struct symtab_command *st;
2688 struct dysymtab_command *dyst;
2689 struct load_command *lc;
2690 enum bool swapped;
2691 enum byte_sex host_byte_sex;
2692 struct dylib_module m;
2693 struct dylib_module_64 m64;
2694 char *strings;
2696 /* These fields are to be filled in by this routine, clear them first */
2697 ofile->modtab = NULL;
2698 ofile->modtab64 = NULL;
2699 ofile->nmodtab = 0;
2700 ofile->dylib_module = NULL;
2701 ofile->dylib_module64 = NULL;
2702 ofile->dylib_module_name = NULL;
2704 if(ofile->file_type == OFILE_FAT){
2705 if(ofile->arch_type != OFILE_Mach_O &&
2706 (ofile->mh_filetype != MH_DYLIB &&
2707 ofile->mh_filetype != MH_DYLIB_STUB)){
2708 error("ofile_first_module() called on fat file: %s with a "
2709 "non-MH_DYLIB architecture or no architecture selected\n",
2710 ofile->file_name);
2711 return(FALSE);
2714 else if(ofile->arch_type != OFILE_Mach_O &&
2715 (ofile->mh_filetype != MH_DYLIB &&
2716 ofile->mh_filetype != MH_DYLIB_STUB)){
2717 error("ofile_first_module() called and file type of %s is "
2718 "non-MH_DYLIB\n", ofile->file_name);
2719 return(FALSE);
2722 st = NULL;
2723 dyst = NULL;
2724 lc = ofile->load_commands;
2725 if(ofile->mh != NULL)
2726 ncmds = ofile->mh->ncmds;
2727 else
2728 ncmds = ofile->mh64->ncmds;
2729 for(i = 0; i < ncmds; i++){
2730 if(st == NULL && lc->cmd == LC_SYMTAB){
2731 st = (struct symtab_command *)lc;
2733 else if(lc->cmd == LC_DYSYMTAB){
2734 dyst = (struct dysymtab_command *)lc;
2736 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2738 if(st == NULL || dyst == NULL){
2739 #ifndef OTOOL
2740 Mach_O_error(ofile, "MH_DYLIB format error (does not have a symbol "
2741 "table and/or a dynamic symbol table)");
2742 #endif
2743 return(FALSE);
2745 if(dyst->nmodtab == 0)
2746 return(FALSE);
2748 ofile->nmodtab = dyst->nmodtab;
2749 host_byte_sex = get_host_byte_sex();
2750 swapped = (enum bool)(host_byte_sex != ofile->object_byte_sex);
2751 strings = (char *)(ofile->object_addr + st->stroff);
2753 if(ofile->mh != NULL){
2754 ofile->modtab = (struct dylib_module *)(ofile->object_addr +
2755 dyst->modtaboff);
2756 ofile->dylib_module = ofile->modtab;
2757 m = *ofile->dylib_module;
2758 if(swapped)
2759 swap_dylib_module(&m, 1, host_byte_sex);
2760 ofile->dylib_module_name = strings + m.module_name;
2762 else{
2763 ofile->modtab64 = (struct dylib_module_64 *)(ofile->object_addr +
2764 dyst->modtaboff);
2765 ofile->dylib_module64 = ofile->modtab64;
2766 m64 = *ofile->dylib_module64;
2767 if(swapped)
2768 swap_dylib_module_64(&m64, 1, host_byte_sex);
2769 ofile->dylib_module_name = strings + m64.module_name;
2772 if(check_dylib_module(ofile, st, dyst, strings, 0) == CHECK_BAD)
2773 return(FALSE);
2774 return(TRUE);
2778 * ofile_next_module() set up the ofile structure (the dylib_module field)
2779 * for the next module of an MH_DYLIB or MH_DYLIB_STUB file.
2781 __private_extern__
2782 enum bool
2783 ofile_next_module(
2784 struct ofile *ofile)
2786 uint32_t i, module_index, ncmds;
2787 struct symtab_command *st;
2788 struct dysymtab_command *dyst;
2789 struct load_command *lc;
2790 enum bool swapped;
2791 enum byte_sex host_byte_sex;
2792 struct dylib_module m;
2793 struct dylib_module_64 m64;
2794 char *strings;
2796 if(ofile->file_type == OFILE_FAT){
2797 if(ofile->arch_type != OFILE_Mach_O &&
2798 (ofile->mh_filetype != MH_DYLIB &&
2799 ofile->mh_filetype != MH_DYLIB_STUB)){
2800 error("ofile_next_module() called on fat file: %s with a "
2801 "non-MH_DYLIB architecture or no architecture selected\n",
2802 ofile->file_name);
2803 return(FALSE);
2806 else if(ofile->arch_type != OFILE_Mach_O &&
2807 (ofile->mh_filetype != MH_DYLIB &&
2808 ofile->mh_filetype != MH_DYLIB_STUB)){
2809 error("ofile_next_module() called and file type of %s is "
2810 "non-MH_DYLIB\n", ofile->file_name);
2811 return(FALSE);
2813 st = NULL;
2814 dyst = NULL;
2815 lc = ofile->load_commands;
2816 if(ofile->mh != NULL)
2817 ncmds = ofile->mh->ncmds;
2818 else
2819 ncmds = ofile->mh64->ncmds;
2820 for(i = 0; i < ncmds; i++){
2821 if(st == NULL && lc->cmd == LC_SYMTAB){
2822 st = (struct symtab_command *)lc;
2824 else if(lc->cmd == LC_DYSYMTAB){
2825 dyst = (struct dysymtab_command *)lc;
2827 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2829 if(st == NULL || dyst == NULL){
2830 #ifndef OTOOL
2831 Mach_O_error(ofile, "MH_DYLIB format error (does not have a symbol "
2832 "table and/or a dynamic symbol table)");
2833 #endif
2834 return(FALSE);
2837 if(ofile->mh != NULL)
2838 module_index = (ofile->dylib_module + 1) - ofile->modtab;
2839 else
2840 module_index = (ofile->dylib_module64 + 1) - ofile->modtab64;
2841 if(module_index >= ofile->nmodtab)
2842 return(FALSE);
2844 host_byte_sex = get_host_byte_sex();
2845 swapped = (enum bool)(host_byte_sex != ofile->object_byte_sex);
2846 strings = (char *)(ofile->object_addr + st->stroff);
2848 if(ofile->mh != NULL){
2849 ofile->dylib_module++;
2850 m = *ofile->dylib_module;
2851 if(swapped)
2852 swap_dylib_module(&m, 1, host_byte_sex);
2853 ofile->dylib_module_name = strings + m.module_name;
2855 else{
2856 ofile->dylib_module64++;
2857 m64 = *ofile->dylib_module64;
2858 if(swapped)
2859 swap_dylib_module_64(&m64, 1, host_byte_sex);
2860 ofile->dylib_module_name = strings + m64.module_name;
2862 if(check_dylib_module(ofile, st, dyst, strings, module_index) ==
2863 CHECK_BAD)
2864 return(FALSE);
2865 return(TRUE);
2869 * ofile_specific_module() set up the ofile structure (the dylib_module fields)
2870 * for the specified module, module_name, of an MH_DYLIB or an MH_DYLIB_STUB
2871 * file.
2873 __private_extern__
2874 enum bool
2875 ofile_specific_module(
2876 const char *module_name,
2877 struct ofile *ofile)
2879 uint32_t i, ncmds;
2880 enum bool swapped;
2881 enum byte_sex host_byte_sex;
2882 struct symtab_command *st;
2883 struct dysymtab_command *dyst;
2884 struct load_command *lc;
2885 struct dylib_module *p, m;
2886 struct dylib_module_64 *p64, m64;
2887 char *strings;
2889 /* These fields are to be filled in by this routine, clear them first */
2890 ofile->modtab = NULL;
2891 ofile->modtab64 = NULL;
2892 ofile->nmodtab = 0;
2893 ofile->dylib_module = NULL;
2894 ofile->dylib_module64 = NULL;
2895 ofile->dylib_module_name = NULL;
2897 if(ofile->file_type == OFILE_FAT){
2898 if(ofile->arch_type != OFILE_Mach_O &&
2899 (ofile->mh_filetype != MH_DYLIB &&
2900 ofile->mh_filetype != MH_DYLIB_STUB)){
2901 error("ofile_specific_module() called on fat file: %s with a "
2902 "non-MH_DYLIB architecture or no architecture selected\n",
2903 ofile->file_name);
2904 return(FALSE);
2907 else if(ofile->arch_type != OFILE_Mach_O &&
2908 (ofile->mh_filetype != MH_DYLIB &&
2909 ofile->mh_filetype != MH_DYLIB_STUB)){
2910 error("ofile_specific_module() called and file type of %s is "
2911 "non-MH_DYLIB\n", ofile->file_name);
2912 return(FALSE);
2915 st = NULL;
2916 dyst = NULL;
2917 lc = ofile->load_commands;
2918 if(ofile->mh != NULL)
2919 ncmds = ofile->mh->ncmds;
2920 else
2921 ncmds = ofile->mh64->ncmds;
2922 for(i = 0; i < ncmds; i++){
2923 if(st == NULL && lc->cmd == LC_SYMTAB){
2924 st = (struct symtab_command *)lc;
2926 else if(lc->cmd == LC_DYSYMTAB){
2927 dyst = (struct dysymtab_command *)lc;
2929 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2931 if(st == NULL || dyst == NULL){
2932 #ifndef OTOOL
2933 Mach_O_error(ofile, "MH_DYLIB format error (does not have a symbol "
2934 "table and/or a dynamic symbol table)");
2935 #endif
2936 return(FALSE);
2938 if(dyst->nmodtab == 0)
2939 return(FALSE);
2941 host_byte_sex = get_host_byte_sex();
2942 swapped = (enum bool)(host_byte_sex != ofile->object_byte_sex);
2943 strings = (char *)(ofile->object_addr + st->stroff);
2945 if(ofile->mh != NULL){
2946 ofile->nmodtab = dyst->nmodtab;
2947 ofile->modtab = (struct dylib_module *)(ofile->object_addr +
2948 dyst->modtaboff);
2949 p = ofile->modtab;
2950 for(i = 0; i < dyst->nmodtab; i++){
2951 m = *p;
2952 if(swapped)
2953 swap_dylib_module(&m, 1, host_byte_sex);
2954 ofile->dylib_module = p;
2955 if(check_dylib_module(ofile, st, dyst, strings, i) == CHECK_BAD)
2956 return(FALSE);
2957 if(strcmp(module_name, strings + m.module_name) == 0){
2958 ofile->dylib_module_name = strings + m.module_name;
2959 return(TRUE);
2961 p++;
2963 m = *ofile->dylib_module;
2964 if(swapped)
2965 swap_dylib_module(&m, 1, host_byte_sex);
2966 ofile->dylib_module_name = strings + m.module_name;
2968 else{
2969 ofile->nmodtab = dyst->nmodtab;
2970 ofile->modtab64 = (struct dylib_module_64 *)(ofile->object_addr +
2971 dyst->modtaboff);
2972 p64 = ofile->modtab64;
2973 for(i = 0; i < dyst->nmodtab; i++){
2974 m64 = *p64;
2975 if(swapped)
2976 swap_dylib_module_64(&m64, 1, host_byte_sex);
2977 ofile->dylib_module64 = p64;
2978 if(check_dylib_module(ofile, st, dyst, strings, i) == CHECK_BAD)
2979 return(FALSE);
2980 if(strcmp(module_name, strings + m64.module_name) == 0){
2981 ofile->dylib_module_name = strings + m64.module_name;
2982 return(TRUE);
2984 p64++;
2986 m64 = *ofile->dylib_module64;
2987 if(swapped)
2988 swap_dylib_module_64(&m64, 1, host_byte_sex);
2989 ofile->dylib_module_name = strings + m64.module_name;
2991 #ifndef OTOOL
2992 Mach_O_error(ofile, "does not contain a module named: %s", module_name);
2993 #endif
2994 ofile->modtab = NULL;
2995 ofile->nmodtab = 0;
2996 ofile->dylib_module = NULL;
2997 ofile->dylib_module_name = NULL;
2998 return(FALSE);
3001 #ifdef DEBUG
3002 __private_extern__
3003 void
3004 ofile_print(
3005 struct ofile *ofile)
3007 printf("file_name = %s\n", ofile->file_name);
3008 printf("file_addr = 0x%x\n", (unsigned int)ofile->file_addr);
3009 printf("file_size = 0x%x\n", (unsigned int)ofile->file_size);
3010 printf("file_type = 0x%x\n", (unsigned int)ofile->file_type);
3011 printf("fat_header = 0x%x\n", (unsigned int)ofile->fat_header);
3012 printf("fat_archs = 0x%x\n", (unsigned int)ofile->fat_archs);
3013 printf("fat_archs64 = 0x%x\n", (unsigned int)ofile->fat_archs64);
3014 printf("narch = 0x%x\n", (unsigned int)ofile->narch);
3015 printf("arch_type = 0x%x\n", (unsigned int)ofile->arch_type);
3016 printf("arch_flag.name = %s\n", ofile->arch_flag.name);
3017 printf("arch_flag.cputype = 0x%x\n",
3018 (unsigned int)ofile->arch_flag.cputype);
3019 printf("arch_flag.cpusubtype = 0x%x\n",
3020 (unsigned int)ofile->arch_flag.cpusubtype);
3021 printf("member_offset = 0x%x\n", (unsigned int)ofile->member_offset);
3022 printf("member_addr = 0x%x\n", (unsigned int)ofile->member_addr);
3023 printf("member_size = 0x%x\n", (unsigned int)ofile->member_size);
3024 printf("member_ar_hdr = 0x%x\n", (unsigned int)ofile->member_ar_hdr);
3025 printf("member_type = 0x%x\n", (unsigned int)ofile->member_type);
3026 printf("archive_cputype = 0x%x\n",
3027 (unsigned int)ofile->archive_cputype);
3028 printf("archive_cpusubtype = 0x%x\n",
3029 (unsigned int)ofile->archive_cpusubtype);
3030 printf("object_addr = 0x%x\n", (unsigned int)ofile->object_addr);
3031 printf("object_size = 0x%x\n", (unsigned int)ofile->object_size);
3032 printf("object_byte_sex = 0x%x\n",
3033 (unsigned int)ofile->object_byte_sex);
3034 printf("mh = 0x%x\n", (unsigned int)ofile->mh);
3035 printf("mh64 = 0x%x\n", (unsigned int)ofile->mh64);
3036 printf("load_commands = 0x%x\n", (unsigned int)ofile->load_commands);
3038 #endif /* DEBUG */
3041 * check_fat() checks the fat ofile for correctness (the fat_header and
3042 * fat_archs or fat_archs64 are assumed to be in the host byte sex).
3044 static
3045 enum check_type
3046 check_fat(
3047 struct ofile *ofile)
3049 #ifdef OTOOL
3050 return(CHECK_GOOD);
3051 #else /* !defined OTOOL */
3053 uint32_t i, j;
3054 uint64_t big_size;
3055 cpu_type_t cputype;
3056 cpu_subtype_t cpusubtype;
3057 uint64_t offset;
3058 uint64_t size;
3059 uint32_t align;
3061 if(ofile->file_type != OFILE_FAT){
3062 error("internal error. check_fat() call and file type of: %s is "
3063 "not OFILE_FAT\n", ofile->file_name);
3064 return(CHECK_BAD);
3066 if(ofile->fat_header->nfat_arch == 0){
3067 error("fat file: %s malformed (contains zero architecture types)",
3068 ofile->file_name);
3069 return(CHECK_BAD);
3071 for(i = 0; i < ofile->fat_header->nfat_arch; i++){
3072 if(ofile->fat_header->magic == FAT_MAGIC_64){
3073 cputype = ofile->fat_archs64[i].cputype;
3074 cpusubtype = ofile->fat_archs64[i].cpusubtype;
3075 offset = ofile->fat_archs64[i].offset;
3076 size = ofile->fat_archs64[i].size;
3077 align = ofile->fat_archs64[i].align;
3079 else{
3080 cputype = ofile->fat_archs[i].cputype;
3081 cpusubtype = ofile->fat_archs[i].cpusubtype;
3082 offset = ofile->fat_archs[i].offset;
3083 size = ofile->fat_archs[i].size;
3084 align = ofile->fat_archs[i].align;
3086 big_size = offset;
3087 big_size += size;
3088 if(big_size > ofile->file_size){
3089 error("fat file: %s truncated or malformed (offset plus size "
3090 "of cputype (%d) cpusubtype (%d) extends past the "
3091 "end of the file)", ofile->file_name,
3092 cputype, cpusubtype & ~CPU_SUBTYPE_MASK);
3093 return(CHECK_BAD);
3095 if(align > MAXSECTALIGN){
3096 error("fat file: %s align (2^%u) too large for cputype (%d) "
3097 "cpusubtype (%d) (maximum 2^%d)", ofile->file_name,
3098 align, cputype, cpusubtype & ~CPU_SUBTYPE_MASK,
3099 MAXSECTALIGN);
3100 return(CHECK_BAD);
3102 if(offset %
3103 (1 << align) != 0){
3104 error("fat file: %s offset: %llu for cputype (%d) cpusubtype "
3105 "(%d)) not aligned on it's alignment (2^%u)",
3106 ofile->file_name, offset, cputype,
3107 cpusubtype & ~CPU_SUBTYPE_MASK, align);
3108 return(CHECK_BAD);
3111 for(i = 0; i < ofile->fat_header->nfat_arch; i++){
3112 for(j = i + 1; j < ofile->fat_header->nfat_arch; j++){
3113 if(ofile->fat_header->magic == FAT_MAGIC_64){
3114 if(ofile->fat_archs64[i].cputype ==
3115 ofile->fat_archs64[j].cputype &&
3116 (ofile->fat_archs64[i].cpusubtype & ~CPU_SUBTYPE_MASK) ==
3117 (ofile->fat_archs64[j].cpusubtype &
3118 ~CPU_SUBTYPE_MASK)){
3119 error("fat file: %s contains two of the same "
3120 "architecture (cputype (%d) cpusubtype (%d))",
3121 ofile->file_name, ofile->fat_archs64[i].cputype,
3122 ofile->fat_archs64[i].cpusubtype &
3123 ~CPU_SUBTYPE_MASK);
3124 return(CHECK_BAD);
3127 else{
3128 if(ofile->fat_archs[i].cputype ==
3129 ofile->fat_archs[j].cputype &&
3130 (ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK) ==
3131 (ofile->fat_archs[j].cpusubtype & ~CPU_SUBTYPE_MASK)){
3132 error("fat file: %s contains two of the same "
3133 "architecture (cputype (%d) cpusubtype (%d))",
3134 ofile->file_name, ofile->fat_archs[i].cputype,
3135 ofile->fat_archs[i].cpusubtype &
3136 ~CPU_SUBTYPE_MASK);
3137 return(CHECK_BAD);
3142 return(CHECK_GOOD);
3143 #endif /* OTOOL */
3147 * check_fat_object_in_archive() checks the fat object file which is a member
3148 * of a thin archive for correctness (the fat_header and fat_archs or
3149 * fat_archs64 are assumed to be in the host byte sex). This is not a legal
3150 * form but allowed when archives_with_fat_objects is TRUE when ofile_map() is
3151 * called.
3153 static
3154 enum check_type
3155 check_fat_object_in_archive(
3156 struct ofile *ofile)
3158 uint32_t i, j;
3159 uint32_t magic;
3160 cpu_type_t cputype;
3161 cpu_subtype_t cpusubtype;
3162 uint64_t offset;
3163 uint64_t size;
3164 uint32_t align;
3166 if(ofile->file_type != OFILE_ARCHIVE){
3167 error("internal error. check_fat_object_in_archive() called and "
3168 "file type of: %s is not OFILE_ARCHIVE\n", ofile->file_name);
3169 return(CHECK_BAD);
3171 if(ofile->fat_header->nfat_arch == 0){
3172 archive_member_error(ofile, "fat file malformed (contains zero "
3173 "architecture types)");
3174 return(CHECK_BAD);
3176 for(i = 0; i < ofile->fat_header->nfat_arch; i++){
3177 if(ofile->fat_header->magic == FAT_MAGIC_64){
3178 cputype = ofile->fat_archs64[i].cputype;
3179 cpusubtype = ofile->fat_archs64[i].cpusubtype;
3180 offset = ofile->fat_archs64[i].offset;
3181 size = ofile->fat_archs64[i].size;
3182 align = ofile->fat_archs64[i].align;
3184 else{
3185 cputype = ofile->fat_archs[i].cputype;
3186 cpusubtype = ofile->fat_archs[i].cpusubtype;
3187 offset = ofile->fat_archs[i].offset;
3188 size = ofile->fat_archs[i].size;
3189 align = ofile->fat_archs[i].align;
3191 if(offset + size > ofile->member_size){
3192 archive_member_error(ofile, "fat file truncated or malformed "
3193 "(offset plus size of cputype (%d) cpusubtype (%d) "
3194 "extends past the end of the file)",
3195 cputype, cpusubtype & ~CPU_SUBTYPE_MASK);
3196 return(CHECK_BAD);
3198 if(align > MAXSECTALIGN){
3199 archive_member_error(ofile, "fat file's align (2^%u) too "
3200 "large for cputype (%d) cpusubtype (%d) (maximum 2^%d)",
3201 align, cputype, cpusubtype & ~CPU_SUBTYPE_MASK,
3202 MAXSECTALIGN);
3203 return(CHECK_BAD);
3205 if(offset % (1 << align) != 0){
3206 archive_member_error(ofile, "fat file's offset: %llu for "
3207 "cputype (%d) cpusubtype (%d) not aligned on it's "
3208 "alignment (2^%u)", offset, cputype,
3209 cpusubtype & ~CPU_SUBTYPE_MASK, align);
3210 return(CHECK_BAD);
3214 * The only supported format where fat files are allowed to appear
3215 * in archives is when the fat file contains only object files.
3217 if(size < sizeof(struct mach_header)){
3218 archive_member_error(ofile, "fat file for cputype (%d) "
3219 "cpusubtype (%d) is not an object file (size too small "
3220 "to be an object file)", cputype,
3221 cpusubtype & ~CPU_SUBTYPE_MASK);
3222 return(CHECK_BAD);
3224 memcpy(&magic,
3225 ofile->file_addr + ofile->member_offset +
3226 offset,
3227 sizeof(uint32_t));
3228 if(magic == MH_MAGIC || magic == SWAP_INT(MH_MAGIC)){
3229 #ifdef ALIGNMENT_CHECKS
3230 if((ofile->member_offset + offset) %
3231 4 != 0){
3232 archive_member_error(ofile, "fat object file's offset in "
3233 "archive not a multiple of 4) (must be since "
3234 "member is a 32-bit object file)");
3235 return(CHECK_BAD);
3237 #endif /* ALIGNMENT_CHECKS */
3239 else if(magic == MH_MAGIC_64 || magic == SWAP_INT(MH_MAGIC_64)){
3240 #ifdef ALIGNMENT_CHECKS_ARCHIVE_64_BIT
3241 if(archive_64_bit_align_warning == FALSE &&
3242 (ofile->member_offset + offset) %
3243 8 != 0){
3244 temporary_archive_member_warning(ofile, "fat object file's "
3245 "offset in archive not a multiple of 8) (must be since "
3246 "member is a 64-bit object file)");
3247 archive_64_bit_align_warning = TRUE;
3248 /* return(CHECK_BAD); */
3250 #endif /* ALIGNMENT_CHECKS_ARCHIVE_64_BIT */
3252 else{
3253 #ifdef LTO_SUPPORT
3254 if(is_llvm_bitcode(ofile, ofile->file_addr +
3255 ofile->member_offset + offset,
3256 size) == TRUE){
3257 #ifdef ALIGNMENT_CHECKS_ARCHIVE_64_BIT
3258 if(archive_64_bit_align_warning == FALSE &&
3259 (ofile->member_offset + offset) %
3260 8 != 0){
3261 temporary_archive_member_warning(ofile, "fat object "
3262 "file's offset in archive not a multiple of 8) "
3263 "(must be since member is a 64-bit object file)");
3264 archive_64_bit_align_warning = TRUE;
3265 /* return(CHECK_BAD); */
3267 #endif
3269 else
3270 #endif /* LTO_SUPPORT */
3272 archive_member_error(ofile, "fat file for cputype (%d) "
3273 "cpusubtype (%d) is not an object file (bad magic "
3274 "number)", cputype,
3275 cpusubtype & ~CPU_SUBTYPE_MASK);
3276 return(CHECK_BAD);
3280 for(i = 0; i < ofile->fat_header->nfat_arch; i++){
3281 for(j = i + 1; j < ofile->fat_header->nfat_arch; j++){
3282 if(ofile->fat_header->magic == FAT_MAGIC_64){
3283 if(ofile->fat_archs64[i].cputype ==
3284 ofile->fat_archs64[j].cputype &&
3285 (ofile->fat_archs64[i].cpusubtype & ~CPU_SUBTYPE_MASK) ==
3286 (ofile->fat_archs64[j].cpusubtype &
3287 ~CPU_SUBTYPE_MASK)){
3288 error("fat file: %s contains two of the same "
3289 "architecture (cputype (%d) cpusubtype (%d))",
3290 ofile->file_name, ofile->fat_archs64[i].cputype,
3291 ofile->fat_archs64[i].cpusubtype &
3292 ~CPU_SUBTYPE_MASK);
3293 return(CHECK_BAD);
3296 else{
3297 if(ofile->fat_archs[i].cputype ==
3298 ofile->fat_archs[j].cputype &&
3299 (ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK) ==
3300 (ofile->fat_archs[j].cpusubtype & ~CPU_SUBTYPE_MASK)){
3301 error("fat file: %s contains two of the same "
3302 "architecture (cputype (%d) cpusubtype (%d))",
3303 ofile->file_name, ofile->fat_archs[i].cputype,
3304 ofile->fat_archs[i].cpusubtype &
3305 ~CPU_SUBTYPE_MASK);
3306 return(CHECK_BAD);
3311 return(CHECK_GOOD);
3315 * check_archive() checks the archive referenced in the ofile for correctness.
3317 static
3318 enum check_type
3319 check_archive(
3320 struct ofile *ofile,
3321 enum bool archives_with_fat_objects)
3323 #ifdef OTOOL
3324 return(CHECK_GOOD);
3325 #else /* !defined OTOOL */
3326 char *addr;
3327 uint64_t size, offset;
3328 uint64_t big_size;
3329 uint32_t magic;
3330 enum byte_sex host_byte_sex;
3331 enum bool swapped;
3332 struct mach_header mh;
3333 struct mach_header_64 mh64;
3334 struct ar_hdr *ar_hdr;
3335 uint32_t ar_name_size;
3338 * Get the address and size of the archive (as well as the cputype and
3339 * cpusubtype if known) and make sure it is an archive.
3341 if(ofile->file_type == OFILE_FAT){
3342 if(ofile->fat_header->magic == FAT_MAGIC_64){
3343 addr = ofile->file_addr +
3344 ofile->fat_archs64[ofile->narch].offset;
3345 size = ofile->fat_archs64[ofile->narch].size;
3346 ofile->archive_cputype =
3347 ofile->fat_archs64[ofile->narch].cputype;
3348 ofile->archive_cpusubtype =
3349 ofile->fat_archs64[ofile->narch].cpusubtype;
3351 else{
3352 addr = ofile->file_addr + ofile->fat_archs[ofile->narch].offset;
3353 size = ofile->fat_archs[ofile->narch].size;
3354 ofile->archive_cputype = ofile->fat_archs[ofile->narch].cputype;
3355 ofile->archive_cpusubtype =
3356 ofile->fat_archs[ofile->narch].cpusubtype;
3359 else if(ofile->file_type == OFILE_ARCHIVE){
3360 addr = ofile->file_addr;
3361 size = ofile->file_size;
3362 ofile->archive_cputype = 0;
3363 ofile->archive_cpusubtype = 0;
3365 else{
3366 error("internal error. check_archive() call and file type of %s is "
3367 "OFILE_UNKNOWN\n", ofile->file_name);
3368 return(CHECK_BAD);
3370 if(size < SARMAG || strncmp(addr, ARMAG, SARMAG) != 0){
3371 error("internal error. check_archive() call for file %s which does "
3372 "not have an archive magic string", ofile->file_name);
3373 return(CHECK_BAD);
3376 host_byte_sex = get_host_byte_sex();
3378 * Check this archive out to make sure that it does not contain
3379 * any fat files and that all object files it contains have the
3380 * same cputype and subsubtype.
3382 offset = SARMAG;
3383 if(offset == size)
3384 return(CHECK_GOOD);
3385 if(offset != size && offset + sizeof(struct ar_hdr) > size){
3386 archive_error(ofile, "truncated or malformed (archive header of "
3387 "first member extends past the end of the file)");
3388 return(CHECK_BAD);
3390 while(size > offset){
3391 ar_hdr = (struct ar_hdr *)(addr + offset);
3392 ofile->member_offset = offset;
3393 ofile->member_addr = addr + offset;
3394 ofile->member_size = strtoul(ar_hdr->ar_size, NULL, 10);
3395 ofile->member_ar_hdr = ar_hdr;
3396 ofile->member_name = ar_hdr->ar_name;
3397 ofile->member_name_size = size_ar_name(ofile->member_ar_hdr);
3398 offset += sizeof(struct ar_hdr);
3400 * See if this archive member is using extend format #1 where
3401 * the size of the name is in ar_name and the name follows the
3402 * archive header.
3404 ar_name_size = 0;
3405 if(strncmp(ofile->member_name,AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0){
3406 if(check_extend_format_1(ofile, ar_hdr, size - offset,
3407 &ar_name_size) == CHECK_BAD)
3408 return(CHECK_BAD);
3409 ofile->member_name = ar_hdr->ar_name + sizeof(struct ar_hdr);
3410 ofile->member_name_size = ar_name_size;
3411 offset += ar_name_size;
3412 ofile->member_offset += ar_name_size;
3413 ofile->member_addr += ar_name_size;
3414 ofile->member_size -= ar_name_size;
3416 big_size = rnd(ofile->member_size, sizeof(short));
3417 big_size += offset;
3418 if(big_size > size){
3419 archive_member_error(ofile, "size too large (archive "
3420 "member extends past the end of the file)");
3421 return(CHECK_BAD);
3423 if(size - offset > sizeof(uint32_t)){
3424 memcpy(&magic, addr + offset, sizeof(uint32_t));
3425 #ifdef __BIG_ENDIAN__
3426 if(magic == FAT_MAGIC || (magic == FAT_MAGIC_64))
3427 #endif /* __BIG_ENDIAN__ */
3428 #ifdef __LITTLE_ENDIAN__
3429 if(magic == SWAP_INT(FAT_MAGIC) ||
3430 magic == SWAP_INT(FAT_MAGIC_64))
3431 #endif /* __LITTLE_ENDIAN__ */
3433 if(archives_with_fat_objects == FALSE ||
3434 ofile->file_type != OFILE_ARCHIVE){
3435 archive_member_error(ofile, "is a fat file (not "
3436 "allowed in an archive)");
3437 return(CHECK_BAD);
3440 else{
3441 if(size - offset >= sizeof(struct mach_header) &&
3442 (magic == MH_MAGIC || magic == SWAP_INT(MH_MAGIC))){
3443 memcpy(&mh, addr + offset, sizeof(struct mach_header));
3444 if(magic == SWAP_INT(MH_MAGIC)){
3445 magic = MH_MAGIC;
3446 swapped = TRUE;
3447 swap_mach_header(&mh, host_byte_sex);
3449 swapped = FALSE;
3451 else if(size - offset >= sizeof(struct mach_header_64) &&
3452 (magic == MH_MAGIC_64 ||
3453 magic == SWAP_INT(MH_MAGIC_64))){
3454 memcpy(&mh64, addr + offset,
3455 sizeof(struct mach_header_64));
3456 if(magic == SWAP_INT(MH_MAGIC_64)){
3457 magic = MH_MAGIC_64;
3458 swapped = TRUE;
3459 swap_mach_header_64(&mh64, host_byte_sex);
3461 swapped = FALSE;
3463 if(magic == MH_MAGIC){
3464 if(ofile->archive_cputype == 0){
3465 ofile->archive_cputype = mh.cputype;
3466 ofile->archive_cpusubtype = mh.cpusubtype;
3468 else if(ofile->archive_cputype != mh.cputype){
3469 archive_member_error(ofile, "cputype (%d) does not "
3470 "match previous archive members cputype (%d) "
3471 "(all members must match)", mh.cputype,
3472 ofile->archive_cputype);
3475 else if(magic == MH_MAGIC_64){
3476 if(ofile->archive_cputype == 0){
3477 ofile->archive_cputype = mh64.cputype;
3478 ofile->archive_cpusubtype = mh64.cpusubtype;
3480 else if(ofile->archive_cputype != mh64.cputype){
3481 archive_member_error(ofile, "cputype (%d) does not "
3482 "match previous archive members cputype (%d) "
3483 "(all members must match)", mh64.cputype,
3484 ofile->archive_cputype);
3489 offset += rnd(ofile->member_size, sizeof(short));
3491 ofile->member_offset = 0;
3492 ofile->member_addr = NULL;
3493 ofile->member_size = 0;
3494 ofile->member_ar_hdr = NULL;;
3495 ofile->member_name = NULL;
3496 ofile->member_name_size = 0;
3497 return(CHECK_GOOD);
3498 #endif /* OTOOL */
3502 * check_extend_format_1() checks the archive header for extended format #1.
3504 static
3505 enum check_type
3506 check_extend_format_1(
3507 struct ofile *ofile,
3508 struct ar_hdr *ar_hdr,
3509 uint32_t size_left,
3510 uint32_t *member_name_size)
3512 char *p, *endp, buf[sizeof(ar_hdr->ar_name)+1];
3513 uint32_t ar_name_size;
3515 *member_name_size = 0;
3517 buf[sizeof(ar_hdr->ar_name)] = '\0';
3518 memcpy(buf, ar_hdr->ar_name, sizeof(ar_hdr->ar_name));
3519 p = buf + sizeof(AR_EFMT1) - 1;
3520 if(isdigit(*p) == 0){
3521 archive_error(ofile, "malformed (ar_name: %.*s for archive "
3522 "extend format #1 starts with non-digit)",
3523 (int)sizeof(ar_hdr->ar_name), ar_hdr->ar_name);
3524 return(CHECK_BAD);
3526 ar_name_size = strtoul(p, &endp, 10);
3527 if(ar_name_size == UINT_MAX && errno == ERANGE){
3528 archive_error(ofile, "malformed (size in ar_name: %.*s for "
3529 "archive extend format #1 overflows uint32_t)",
3530 (int)sizeof(ar_hdr->ar_name), ar_hdr->ar_name);
3531 return(CHECK_BAD);
3533 while(*endp == ' ' && *endp != '\0')
3534 endp++;
3535 if(*endp != '\0'){
3536 archive_error(ofile, "malformed (size in ar_name: %.*s for "
3537 "archive extend format #1 contains non-digit and "
3538 "non-space characters)", (int)sizeof(ar_hdr->ar_name),
3539 ar_hdr->ar_name);
3540 return(CHECK_BAD);
3542 if(ar_name_size > size_left){
3543 archive_error(ofile, "truncated or malformed (archive name "
3544 "of member extends past the end of the file)");
3545 return(CHECK_BAD);
3547 *member_name_size = ar_name_size;
3548 return(CHECK_GOOD);
3552 * check_archive_toc() checks the archive table of contents referenced in the
3553 * thin archive via the ofile for correctness and if bad sets the bad_toc field
3554 * in the ofile struct to TRUE. If not it sets the other toc_* fields that
3555 * ranlib(1) uses to know it can't update the table of contents and doesn't
3556 * have to totally rebuild it. And by this always returning CHECK_GOOD it
3557 * allows otool(1) to print messed up tables of contents for debugging.
3559 static
3560 enum check_type
3561 check_archive_toc(
3562 struct ofile *ofile)
3564 uint32_t symdef_length, nranlibs, strsize;
3565 uint64_t i, n, offset, ran_off, nranlibs64, strsize64;
3566 enum byte_sex host_byte_sex, toc_byte_sex;
3567 struct ranlib *ranlibs;
3568 struct ranlib_64 *ranlibs64;
3569 char *strings;
3570 enum bool toc_is_32bit;
3572 ofile->toc_is_32bit = TRUE;
3573 ofile->toc_ranlibs = NULL;
3574 ofile->toc_ranlibs64 = NULL;
3575 ofile->toc_nranlibs = 0;
3576 ofile->toc_strings = NULL;
3577 ofile->toc_strsize = 0;
3580 * Note this can only be called when the whole file is a thin archive.
3582 if(ofile->file_type != OFILE_ARCHIVE)
3583 return(CHECK_GOOD);
3585 symdef_length = ofile->toc_size;
3586 if(strncmp(ofile->member_name, SYMDEF_64_SORTED,
3587 ofile->member_name_size) == 0 ||
3588 strncmp(ofile->member_name, SYMDEF_64,
3589 ofile->member_name_size) == 0)
3590 toc_is_32bit = FALSE;
3591 else
3592 toc_is_32bit = TRUE;
3593 if(toc_is_32bit == TRUE){
3595 * The contents of a __.SYMDEF file is begins with a 32-bit word
3596 * giving the size in bytes of ranlib structures which immediately
3597 * follow, and then continues with a string table consisting of a
3598 * 32-bit word giving the number of bytes of strings which follow
3599 * and then the strings themselves. So the smallest valid size is
3600 * two 32-bit words long.
3602 if(symdef_length < 2 * sizeof(uint32_t)){
3604 * Size of table of contents for archive too small to be a valid
3605 * table of contents.
3607 ofile->toc_bad = TRUE;
3608 return(CHECK_GOOD);
3610 } else {
3612 * The contents of a __.SYMDEF_64 file is begins with a 64-bit word
3613 * giving the size in bytes of ranlib structures which immediately
3614 * follow, and then continues with a string table consisting of a
3615 * 64-bit word giving the number of bytes of strings which follow
3616 * and then the strings themselves. So the smallest valid size is
3617 * two 64-bit words long.
3619 if(symdef_length < 2 * sizeof(uint64_t)){
3621 * Size of table of contents for archive too small to be a valid
3622 * table of contents.
3624 ofile->toc_bad = TRUE;
3625 return(CHECK_GOOD);
3628 host_byte_sex = get_host_byte_sex();
3629 toc_byte_sex = get_toc_byte_sex(ofile->file_addr, ofile->file_size);
3630 if(toc_byte_sex == UNKNOWN_BYTE_SEX){
3632 * Can't determine the byte order of table of contents as it
3633 * contains no Mach-O files.
3635 ofile->toc_bad = TRUE;
3636 return(CHECK_GOOD);
3638 offset = 0;
3639 if(toc_is_32bit == TRUE){
3640 nranlibs = *((uint32_t *)(ofile->toc_addr + offset));
3641 if(toc_byte_sex != host_byte_sex)
3642 nranlibs = SWAP_INT(nranlibs);
3643 nranlibs = nranlibs / sizeof(struct ranlib);
3644 n = nranlibs;
3645 offset += sizeof(uint32_t);
3647 ranlibs = (struct ranlib *)(ofile->toc_addr + offset);
3648 offset += sizeof(struct ranlib) * nranlibs;
3649 if(nranlibs == 0)
3650 return(CHECK_GOOD);
3651 if(offset - (2 * sizeof(uint32_t)) > symdef_length){
3653 * Truncated or malformed archive. The ranlib structures in
3654 * table of contents extends past the end of the table of
3655 * contents.
3657 ofile->toc_bad = TRUE;
3658 return(CHECK_GOOD);
3661 strsize = *((uint32_t *)(ofile->toc_addr + offset));
3662 if(toc_byte_sex != host_byte_sex)
3663 strsize = SWAP_INT(strsize);
3664 offset += sizeof(uint32_t);
3666 strings = ofile->toc_addr + offset;
3667 offset += strsize;
3668 if(offset - (2 * sizeof(uint32_t)) > symdef_length){
3670 * Truncated or malformed archive. The ranlib strings in table
3671 * of contents extends past the end of the table of contents.
3673 ofile->toc_bad = TRUE;
3674 return(CHECK_GOOD);
3676 if(symdef_length == 2 * sizeof(uint32_t))
3677 return(CHECK_GOOD);
3678 } else {
3679 nranlibs64 = *((uint64_t *)(ofile->toc_addr + offset));
3680 if(toc_byte_sex != host_byte_sex)
3681 nranlibs64 = SWAP_LONG_LONG(nranlibs64);
3682 nranlibs64 = nranlibs64 / sizeof(struct ranlib_64);
3683 n = nranlibs64;
3684 offset += sizeof(uint64_t);
3686 ranlibs64 = (struct ranlib_64 *)(ofile->toc_addr + offset);
3687 offset += sizeof(struct ranlib_64) * nranlibs64;
3688 if(nranlibs64 == 0)
3689 return(CHECK_GOOD);
3690 if(offset - (2 * sizeof(uint64_t)) > symdef_length){
3692 * Truncated or malformed archive. The ranlib structures in
3693 * table of contents extends past the end of the table of
3694 * contents.
3696 ofile->toc_bad = TRUE;
3697 return(CHECK_GOOD);
3700 strsize64 = *((uint64_t *)(ofile->toc_addr + offset));
3701 if(toc_byte_sex != host_byte_sex)
3702 strsize64 = SWAP_LONG_LONG(strsize64);
3703 offset += sizeof(uint64_t);
3705 strings = ofile->toc_addr + offset;
3706 offset += strsize64;
3707 if(offset - (2 * sizeof(uint64_t)) > symdef_length){
3709 * Truncated or malformed archive. The ranlib strings in table
3710 * of contents extends past the end of the table of contents.
3712 ofile->toc_bad = TRUE;
3713 return(CHECK_GOOD);
3715 if(symdef_length == 2 * sizeof(uint64_t))
3716 return(CHECK_GOOD);
3720 * Check the string offset and the member offsets of the ranlib structs.
3722 if(toc_byte_sex != host_byte_sex){
3723 if(toc_is_32bit == TRUE)
3724 swap_ranlib(ranlibs, nranlibs, host_byte_sex);
3725 else
3726 swap_ranlib_64(ranlibs64, nranlibs64, host_byte_sex);
3728 for(i = 0; i < n; i++){
3729 if(toc_is_32bit == TRUE){
3730 if(ranlibs[i].ran_un.ran_strx >= strsize){
3732 * Malformed table of contents. The ranlib struct at this
3733 * index has a bad string index field.
3735 ofile->toc_bad = TRUE;
3736 return(CHECK_GOOD);
3738 if(ranlibs[i].ran_off >= ofile->file_size){
3740 * Malformed table of contents. The ranlib struct at this
3741 * index has a bad library member offset field.
3743 ofile->toc_bad = TRUE;
3744 return(CHECK_GOOD);
3746 ran_off = ranlibs[i].ran_off;
3747 } else {
3748 if(ranlibs64[i].ran_un.ran_strx >= strsize64){
3750 * Malformed table of contents. The ranlib struct at this
3751 * index has a bad string index field.
3753 ofile->toc_bad = TRUE;
3754 return(CHECK_GOOD);
3756 if(ranlibs64[i].ran_off >= ofile->file_size){
3758 * Malformed table of contents. The ranlib struct at this
3759 * index has a bad library member offset field.
3761 ofile->toc_bad = TRUE;
3762 return(CHECK_GOOD);
3764 ran_off = ranlibs64[i].ran_off;
3768 * These should be on 4 byte boundaries because the maximum
3769 * alignment of the header structures and relocation are 4 bytes.
3770 * But this is has to be 2 bytes because that's the way ar(1) has
3771 * worked historicly in the past. Fortunately this works on the
3772 * 68k machines but will have to change when this is on a real
3773 * machine.
3775 #if defined(mc68000) || defined(__i386__)
3776 if(ran_off % sizeof(short) != 0){
3778 * Malformed table of contents. This ranlib struct library
3779 * member offset not a multiple 2 bytes.
3781 ofile->toc_bad = TRUE;
3782 return(CHECK_GOOD);
3784 #else
3785 if(toc_is_32bit == TRUE){
3786 if(ran_off % sizeof(uint32_t) != 0){
3788 * Malformed table of contents. This ranlib struct library
3789 * member offset not a multiple of 4 bytes.
3791 ofile->toc_bad = TRUE;
3792 return(CHECK_GOOD);
3794 } else {
3795 if(ran_off % sizeof(uint64_t) != 0){
3797 * Malformed table of contents. This ranlib struct library
3798 * member offset not a multiple of 8 bytes.
3800 ofile->toc_bad = TRUE;
3801 return(CHECK_GOOD);
3804 #endif
3806 ofile->toc_is_32bit = toc_is_32bit;
3807 ofile->toc_ranlibs = ranlibs;
3808 ofile->toc_ranlibs64 = ranlibs64;
3809 ofile->toc_strings = strings;
3810 if(toc_is_32bit == TRUE){
3811 ofile->toc_nranlibs = nranlibs;
3812 ofile->toc_strsize = strsize;
3813 } else {
3814 ofile->toc_nranlibs = nranlibs64;
3815 ofile->toc_strsize = strsize64;
3817 return(CHECK_GOOD);
3821 * check_Mach_O() checks the object file's mach header and load commands
3822 * referenced in the ofile for correctness (this also swaps the mach header
3823 * and load commands into the host byte sex if needed).
3825 static
3826 enum check_type
3827 check_Mach_O(
3828 struct ofile *ofile)
3830 #ifdef OTOOL
3831 return(CHECK_GOOD);
3832 #else /* !defined OTOOL */
3833 uint32_t size, i, j, ncmds, sizeofcmds, load_command_multiple, sizeofhdrs;
3834 cpu_type_t cputype;
3835 char *addr, *cmd_name, *element_name;
3836 enum byte_sex host_byte_sex;
3837 enum bool swapped;
3838 struct mach_header *mh;
3839 struct mach_header_64 *mh64;
3840 struct load_command *load_commands, *lc, l;
3841 struct segment_command *sg;
3842 struct segment_command_64 *sg64;
3843 struct section *s;
3844 struct section_64 *s64;
3845 struct symtab_command *st;
3846 struct dysymtab_command *dyst;
3847 struct symseg_command *ss;
3848 struct fvmlib_command *fl;
3849 struct dylib_command *dl;
3850 struct sub_framework_command *sub;
3851 struct sub_umbrella_command *usub;
3852 struct sub_library_command *lsub;
3853 struct sub_client_command *csub;
3854 struct prebound_dylib_command *pbdylib;
3855 struct dylinker_command *dyld;
3856 struct thread_command *ut;
3857 struct ident_command *id;
3858 struct routines_command *rc;
3859 struct routines_command_64 *rc64;
3860 struct twolevel_hints_command *hints;
3861 struct linkedit_data_command *code_sig, *split_info, *func_starts,
3862 *data_in_code, *code_sign_drs, *linkedit_data;
3863 struct linkedit_data_command *link_opt_hint;
3864 struct version_min_command *vers;
3865 struct prebind_cksum_command *cs;
3866 struct encryption_info_command *encrypt_info;
3867 struct encryption_info_command_64 *encrypt_info64;
3868 struct linker_option_command *lo;
3869 struct dyld_info_command *dyld_info;
3870 struct uuid_command *uuid;
3871 struct rpath_command *rpath;
3872 struct entry_point_command *ep;
3873 struct source_version_command *sv;
3874 uint32_t flavor, count, nflavor;
3875 char *p, *state;
3876 uint32_t sizeof_nlist, sizeof_dylib_module;
3877 char *struct_dylib_module_name, *struct_nlist_name;
3878 uint64_t big_size, big_end, big_load_end;
3879 struct element elements;
3880 cpu_type_t fat_cputype;
3882 elements.offset = 0;
3883 elements.size = 0;
3884 elements.name = NULL;
3885 elements.next = NULL;
3887 addr = ofile->object_addr;
3888 size = ofile->object_size;
3889 mh = ofile->mh;
3890 mh64 = ofile->mh64;
3891 load_commands = ofile->load_commands;
3892 host_byte_sex = get_host_byte_sex();
3893 swapped = (enum bool)(host_byte_sex != ofile->object_byte_sex);
3895 if(ofile->mh != NULL){
3896 if(swapped)
3897 swap_mach_header(mh, host_byte_sex);
3898 big_size = mh->sizeofcmds;
3899 big_size += sizeof(struct mach_header);
3900 if(big_size > size){
3901 Mach_O_error(ofile, "truncated or malformed object (load "
3902 "commands extend past the end of the file)");
3903 return(CHECK_BAD);
3905 sizeofhdrs = big_size;
3906 ofile->mh_cputype = mh->cputype;
3907 ofile->mh_cpusubtype = mh->cpusubtype;
3908 ofile->mh_filetype = mh->filetype;
3909 ncmds = mh->ncmds;
3910 sizeofcmds = mh->sizeofcmds;
3911 cputype = mh->cputype;
3912 load_command_multiple = 4;
3913 sizeof_nlist = sizeof(struct nlist);
3914 struct_nlist_name = "struct nlist";
3915 sizeof_dylib_module = sizeof(struct dylib_module);
3916 struct_dylib_module_name = "struct dylib_module";
3918 else{
3919 if(swapped)
3920 swap_mach_header_64(mh64, host_byte_sex);
3921 big_size = mh64->sizeofcmds;
3922 big_size += sizeof(struct mach_header_64);
3923 if(big_size > size){
3924 Mach_O_error(ofile, "truncated or malformed object (load "
3925 "commands extend past the end of the file)");
3926 return(CHECK_BAD);
3928 sizeofhdrs = big_size;
3929 ofile->mh_cputype = mh64->cputype;
3930 ofile->mh_cpusubtype = mh64->cpusubtype;
3931 ofile->mh_filetype = mh64->filetype;
3932 ncmds = mh64->ncmds;
3933 sizeofcmds = mh64->sizeofcmds;
3934 cputype = mh64->cputype;
3935 load_command_multiple = 8;
3936 sizeof_nlist = sizeof(struct nlist_64);
3937 struct_nlist_name = "struct nlist_64";
3938 sizeof_dylib_module = sizeof(struct dylib_module_64);
3939 struct_dylib_module_name = "struct dylib_module_64";
3941 if(check_overlaping_element(ofile, &elements, 0, sizeofhdrs,
3942 "Mach-O headers") == CHECK_BAD)
3943 goto return_bad;
3944 if(ofile->file_type == OFILE_FAT){
3945 if(ofile->fat_header->magic == FAT_MAGIC_64)
3946 fat_cputype = ofile->fat_archs64[ofile->narch].cputype;
3947 else
3948 fat_cputype = ofile->fat_archs[ofile->narch].cputype;
3949 if(fat_cputype != ofile->mh_cputype){
3950 Mach_O_error(ofile, "malformed fat file (fat header "
3951 "architecture: %u's cputype does not match "
3952 "object file's mach header)", ofile->narch);
3953 goto return_bad;
3957 * Make a pass through the load commands checking them to the level
3958 * that they can be parsed and all fields with offsets and sizes do
3959 * not extend past the end of the file.
3961 st = NULL;
3962 dyst = NULL;
3963 rc = NULL;
3964 rc64 = NULL;
3965 hints = NULL;
3966 code_sig = NULL;
3967 func_starts = NULL;
3968 data_in_code = NULL;
3969 code_sign_drs = NULL;
3970 link_opt_hint = NULL;
3971 split_info = NULL;
3972 cs = NULL;
3973 uuid = NULL;
3974 encrypt_info = NULL;
3975 dyld_info = NULL;
3976 vers = NULL;
3977 big_load_end = 0;
3978 for(i = 0, lc = load_commands; i < ncmds; i++){
3979 if(big_load_end + sizeof(struct load_command) > sizeofcmds){
3980 Mach_O_error(ofile, "truncated or malformed object (load "
3981 "command %u extends past the end all load "
3982 "commands in the file)", i);
3983 goto return_bad;
3985 l = *lc;
3986 if(swapped)
3987 swap_load_command(&l, host_byte_sex);
3989 * Check load command size for a multiple of load_command_multiple.
3991 if(l.cmdsize % load_command_multiple != 0){
3993 * We have a hack here to allow 64-bit Mach-O core files to
3994 * have LC_THREAD commands that are only a multiple of 4 and
3995 * not 8 to be allowed since the kernel produces them.
3997 if(ofile->mh64 == NULL ||
3998 ofile->mh64->filetype != MH_CORE ||
3999 l.cmd != LC_THREAD ||
4000 l.cmdsize % 4 != 0){
4001 Mach_O_error(ofile, "malformed object (load command %u "
4002 "cmdsize not a multiple of %u)", i,
4003 load_command_multiple);
4004 goto return_bad;
4007 /* check that load command does not extends past end of commands */
4008 big_load_end += l.cmdsize;
4009 if(big_load_end > sizeofcmds){
4010 Mach_O_error(ofile, "truncated or malformed object (load "
4011 "command %u extends past the end of the file)",i);
4012 goto return_bad;
4014 /* check that the load command size is not zero */
4015 if(l.cmdsize == 0){
4016 Mach_O_error(ofile, "malformed object (load command %u cmdsize"
4017 " is zero)", i);
4018 goto return_bad;
4020 switch(l.cmd){
4021 case LC_SEGMENT:
4022 if(l.cmdsize < sizeof(struct segment_command)){
4023 Mach_O_error(ofile, "malformed object (LC_SEGMENT cmdsize "
4024 "too small) in command %u", i);
4025 goto return_bad;
4027 sg = (struct segment_command *)lc;
4028 if(swapped)
4029 swap_segment_command(sg, host_byte_sex);
4030 big_size = sg->nsects;
4031 big_size *= sizeof(struct section);
4032 big_size += sizeof(struct segment_command);
4033 if(sg->cmdsize != big_size){
4034 Mach_O_error(ofile, "malformed object (inconsistent "
4035 "cmdsize in LC_SEGMENT command %u for the "
4036 "number of sections)", i);
4037 goto return_bad;
4039 if(sg->fileoff > size){
4040 Mach_O_error(ofile, "truncated or malformed object ("
4041 "LC_SEGMENT command %u fileoff field "
4042 "extends past the end of the file)", i);
4043 goto return_bad;
4045 big_size = sg->fileoff;
4046 big_size += sg->filesize;
4047 if(big_size > size){
4048 Mach_O_error(ofile, "truncated or malformed object ("
4049 "LC_SEGMENT command %u fileoff field "
4050 "plus filesize field extends past the end of "
4051 "the file)", i);
4052 goto return_bad;
4054 if(sg->vmsize != 0 && sg->filesize > sg->vmsize){
4055 Mach_O_error(ofile, "malformed object (LC_SEGMENT command "
4056 "%u filesize field greater than vmsize field)",
4058 goto return_bad;
4060 s = (struct section *)
4061 ((char *)sg + sizeof(struct segment_command));
4062 if(swapped)
4063 swap_section(s, sg->nsects, host_byte_sex);
4064 for(j = 0 ; j < sg->nsects ; j++){
4065 if(mh->filetype != MH_DYLIB_STUB &&
4066 mh->filetype != MH_DSYM &&
4067 s->flags != S_ZEROFILL &&
4068 s->flags != S_THREAD_LOCAL_ZEROFILL && s->offset > size){
4069 Mach_O_error(ofile, "truncated or malformed object "
4070 "(offset field of section %u in LC_SEGMENT "
4071 "command %u extends past the end of the file)",
4072 j, i);
4073 goto return_bad;
4075 if(mh->filetype != MH_DYLIB_STUB &&
4076 mh->filetype != MH_DSYM &&
4077 s->flags != S_ZEROFILL &&
4078 s->flags != S_THREAD_LOCAL_ZEROFILL &&
4079 sg->fileoff == 0 && s->offset < sizeofhdrs &&
4080 s->size != 0){
4081 Mach_O_error(ofile, "malformed object (offset field of "
4082 "section %u in LC_SEGMENT command %u not "
4083 "past the headers of the file)", j, i);
4084 goto return_bad;
4086 big_size = s->offset;
4087 big_size += s->size;
4088 if(mh->filetype != MH_DYLIB_STUB &&
4089 mh->filetype != MH_DSYM &&
4090 s->flags != S_ZEROFILL &&
4091 s->flags != S_THREAD_LOCAL_ZEROFILL && big_size > size){
4092 Mach_O_error(ofile, "truncated or malformed object "
4093 "(offset field plus size field of section %u "
4094 "in LC_SEGMENT command %u extends "
4095 "past the end of the file)", j, i);
4096 goto return_bad;
4098 if(mh->filetype != MH_DYLIB_STUB &&
4099 mh->filetype != MH_DSYM &&
4100 s->flags != S_ZEROFILL &&
4101 s->flags != S_THREAD_LOCAL_ZEROFILL &&
4102 s->size > sg->filesize){
4103 Mach_O_error(ofile, "malformed object (size field of "
4104 "section %u in LC_SEGMENT command %u greater "
4105 "than the segment)", j, i);
4106 goto return_bad;
4108 if(mh->filetype != MH_DYLIB_STUB &&
4109 mh->filetype != MH_DSYM &&
4110 s->size != 0 && s->addr < sg->vmaddr){
4111 Mach_O_error(ofile, "malformed object (addr field of "
4112 "section %u in LC_SEGMENT command %u less than "
4113 "the segment's vmaddr)", j, i);
4114 goto return_bad;
4116 big_size = s->addr;
4117 big_size += s->size;
4118 big_end = sg->vmaddr;
4119 big_end += sg->vmsize;
4120 if(sg->vmsize != 0 && s->size != 0 && big_size > big_end){
4121 Mach_O_error(ofile, "malformed object (addr field plus "
4122 "size of section %u in LC_SEGMENT command %u "
4123 "greater than than the segment's vmaddr plus "
4124 "vmsize)", j, i);
4125 goto return_bad;
4127 if(mh->filetype != MH_DYLIB_STUB &&
4128 mh->filetype != MH_DSYM &&
4129 s->flags != S_ZEROFILL &&
4130 s->flags != S_THREAD_LOCAL_ZEROFILL &&
4131 check_overlaping_element(ofile, &elements, s->offset,
4132 s->size, "section contents") == CHECK_BAD)
4133 goto return_bad;
4134 if(s->reloff > size){
4135 Mach_O_error(ofile, "truncated or malformed object "
4136 "(reloff field of section %u in LC_SEGMENT "
4137 "command %u extends past the end of the file)",
4138 j, i);
4139 goto return_bad;
4141 big_size = s->nreloc;
4142 big_size *= sizeof(struct relocation_info);
4143 big_size += s->reloff;
4144 if(big_size > size){
4145 Mach_O_error(ofile, "truncated or malformed object "
4146 "(reloff field plus nreloc field times sizeof("
4147 "struct relocation_info) of section %u in "
4148 "LC_SEGMENT command %u extends past the "
4149 "end of the file)", j, i);
4150 goto return_bad;
4152 if(check_overlaping_element(ofile, &elements, s->reloff,
4153 s->nreloc * sizeof(struct relocation_info),
4154 "section relocation entries") == CHECK_BAD)
4155 goto return_bad;
4156 s++;
4158 break;
4160 case LC_SEGMENT_64:
4161 if(l.cmdsize < sizeof(struct segment_command_64)){
4162 Mach_O_error(ofile, "malformed object (LC_SEGMENT_64 "
4163 "cmdsize too small) in command %u", i);
4164 goto return_bad;
4166 sg64 = (struct segment_command_64 *)lc;
4167 if(swapped)
4168 swap_segment_command_64(sg64, host_byte_sex);
4169 big_size = sg64->nsects;
4170 big_size *= sizeof(struct section_64);
4171 big_size += sizeof(struct segment_command_64);
4172 if(sg64->cmdsize != big_size){
4173 Mach_O_error(ofile, "malformed object (inconsistent "
4174 "cmdsize in LC_SEGMENT_64 command %u for "
4175 "the number of sections)", i);
4176 goto return_bad;
4178 if(sg64->fileoff > size){
4179 Mach_O_error(ofile, "truncated or malformed object ("
4180 "LC_SEGMENT_64 command %u fileoff field "
4181 "extends past the end of the file)", i);
4182 goto return_bad;
4184 big_size = sg64->fileoff;
4185 big_size += sg64->filesize;
4186 if(big_size > size){
4187 Mach_O_error(ofile, "truncated or malformed object ("
4188 "LC_SEGMENT_64 command %u fileoff field "
4189 "plus filesize field extends past the end of "
4190 "the file)", i);
4191 goto return_bad;
4193 s64 = (struct section_64 *)
4194 ((char *)sg64 + sizeof(struct segment_command_64));
4195 if(swapped)
4196 swap_section_64(s64, sg64->nsects, host_byte_sex);
4197 for(j = 0 ; j < sg64->nsects ; j++){
4198 if(mh64->filetype != MH_DYLIB_STUB &&
4199 mh64->filetype != MH_DSYM &&
4200 s64->flags != S_ZEROFILL &&
4201 s64->flags != S_THREAD_LOCAL_ZEROFILL &&
4202 s64->offset > size){
4203 Mach_O_error(ofile, "truncated or malformed object "
4204 "(offset field of section %u in LC_SEGMENT_64 "
4205 "command %u extends past the end of the file)",
4206 j, i);
4207 goto return_bad;
4209 if(mh64->filetype != MH_DYLIB_STUB &&
4210 mh64->filetype != MH_DSYM &&
4211 s64->flags != S_ZEROFILL &&
4212 s64->flags != S_THREAD_LOCAL_ZEROFILL &&
4213 sg64->fileoff == 0 && s64->offset < sizeofhdrs &&
4214 s64->size != 0){
4215 Mach_O_error(ofile, "malformed object (offset field of "
4216 "section %u in LC_SEGMENT command %u not "
4217 "past the headers of the file)", j, i);
4218 goto return_bad;
4220 big_size = s64->offset;
4221 big_size += s64->size;
4222 if(mh64->filetype != MH_DYLIB_STUB &&
4223 mh64->filetype != MH_DSYM &&
4224 s64->flags != S_ZEROFILL &&
4225 s64->flags != S_THREAD_LOCAL_ZEROFILL &&
4226 big_size > size){
4227 Mach_O_error(ofile, "truncated or malformed object "
4228 "(offset field plus size field of section %u "
4229 "in LC_SEGMENT_64 command %u extends "
4230 "past the end of the file)", j, i);
4231 goto return_bad;
4233 if(mh64->filetype != MH_DYLIB_STUB &&
4234 mh64->filetype != MH_DSYM &&
4235 s64->flags != S_ZEROFILL &&
4236 s64->flags != S_THREAD_LOCAL_ZEROFILL &&
4237 check_overlaping_element(ofile, &elements, s64->offset,
4238 s64->size, "section contents") == CHECK_BAD)
4239 goto return_bad;
4240 if(s64->reloff > size){
4241 Mach_O_error(ofile, "truncated or malformed object "
4242 "(reloff field of section %u in LC_SEGMENT_64 "
4243 "command %u extends past the end of the file)",
4244 j, i);
4245 goto return_bad;
4247 big_size = s64->nreloc;
4248 big_size *= sizeof(struct relocation_info);
4249 big_size += s64->reloff;
4250 if(big_size > size){
4251 Mach_O_error(ofile, "truncated or malformed object "
4252 "(reloff field plus nreloc field times sizeof("
4253 "struct relocation_info) of section %u in "
4254 "LC_SEGMENT_64 command %u extends past the "
4255 "end of the file)", j, i);
4256 goto return_bad;
4258 if(check_overlaping_element(ofile, &elements, s64->reloff,
4259 s64->nreloc * sizeof(struct relocation_info),
4260 "section relocation entries") == CHECK_BAD)
4261 goto return_bad;
4262 s64++;
4264 break;
4266 case LC_SYMTAB:
4267 if(l.cmdsize < sizeof(struct symtab_command)){
4268 Mach_O_error(ofile, "malformed object (LC_SYMTAB cmdsize "
4269 "too small) in command %u", i);
4270 goto return_bad;
4272 if(st != NULL){
4273 Mach_O_error(ofile, "malformed object (more than one "
4274 "LC_SYMTAB command)");
4275 goto return_bad;
4277 st = (struct symtab_command *)lc;
4278 if(swapped)
4279 swap_symtab_command(st, host_byte_sex);
4280 if(st->cmdsize != sizeof(struct symtab_command)){
4281 Mach_O_error(ofile, "malformed object (LC_SYMTAB command "
4282 "%u has incorrect cmdsize)", i);
4283 goto return_bad;
4285 if(st->symoff > size){
4286 Mach_O_error(ofile, "truncated or malformed object (symoff "
4287 "field of LC_SYMTAB command %u extends past the end "
4288 "of the file)", i);
4289 goto return_bad;
4291 big_size = st->nsyms;
4292 big_size *= sizeof_nlist;
4293 big_size += st->symoff;
4294 if(big_size > size){
4295 Mach_O_error(ofile, "truncated or malformed object (symoff "
4296 "field plus nsyms field times sizeof(%s) of LC_SYMTAB "
4297 "command %u extends past the end of the file)",
4298 struct_nlist_name, i);
4299 goto return_bad;
4301 if(check_overlaping_element(ofile, &elements, st->symoff,
4302 st->nsyms * sizeof_nlist, "symbol table") == CHECK_BAD)
4303 goto return_bad;
4304 if(st->stroff > size){
4305 Mach_O_error(ofile, "truncated or malformed object (stroff "
4306 "field of LC_SYMTAB command %u extends past the end "
4307 "of the file)", i);
4308 goto return_bad;
4310 big_size = st->stroff;
4311 big_size += st->strsize;
4312 if(big_size > size){
4313 Mach_O_error(ofile, "truncated or malformed object (stroff "
4314 "field plus strsize field of LC_SYMTAB command %u "
4315 "extends past the end of the file)", i);
4316 goto return_bad;
4318 if(check_overlaping_element(ofile, &elements, st->stroff,
4319 st->strsize, "string table") == CHECK_BAD)
4320 goto return_bad;
4321 break;
4323 case LC_DYSYMTAB:
4324 if(l.cmdsize < sizeof(struct dysymtab_command)){
4325 Mach_O_error(ofile, "malformed object (LC_DYSYMTAB cmdsize "
4326 "too small) in command %u", i);
4327 goto return_bad;
4329 if(dyst != NULL){
4330 Mach_O_error(ofile, "malformed object (more than one "
4331 "LC_DYSYMTAB command)");
4332 goto return_bad;
4334 dyst = (struct dysymtab_command *)lc;
4335 if(swapped)
4336 swap_dysymtab_command(dyst, host_byte_sex);
4337 if(dyst->cmdsize != sizeof(struct dysymtab_command)){
4338 Mach_O_error(ofile, "malformed object (LC_DYSYMTAB command "
4339 "%u has incorrect cmdsize)", i);
4340 goto return_bad;
4342 if(dyst->tocoff > size){
4343 Mach_O_error(ofile, "truncated or malformed object (tocoff "
4344 "field of LC_DYSYMTAB command %u extends past the end "
4345 "of the file)", i);
4346 goto return_bad;
4348 big_size = dyst->ntoc;
4349 big_size *= sizeof(struct dylib_table_of_contents);
4350 big_size += dyst->tocoff;
4351 if(big_size > size){
4352 Mach_O_error(ofile, "truncated or malformed object (tocoff "
4353 "field plus ntoc field times sizeof(struct dylib_table"
4354 "_of_contents) of LC_DYSYMTAB command %u extends past "
4355 "the end of the file)", i);
4356 goto return_bad;
4358 if(check_overlaping_element(ofile, &elements, dyst->tocoff,
4359 dyst->ntoc * sizeof(struct dylib_table_of_contents),
4360 "table of contents") == CHECK_BAD)
4361 goto return_bad;
4362 if(dyst->modtaboff > size){
4363 Mach_O_error(ofile, "truncated or malformed object "
4364 "(modtaboff field of LC_DYSYMTAB command %u extends "
4365 "past the end of the file)", i);
4366 goto return_bad;
4368 big_size = dyst->nmodtab;
4369 big_size *= sizeof_dylib_module;
4370 big_size += dyst->modtaboff;
4371 if(big_size > size){
4372 Mach_O_error(ofile, "truncated or malformed object "
4373 "(modtaboff field plus nmodtab field times sizeof(%s) "
4374 "of LC_DYSYMTAB command %u extends past the end of "
4375 "the file)", struct_dylib_module_name, i);
4376 goto return_bad;
4378 if(check_overlaping_element(ofile, &elements, dyst->modtaboff,
4379 dyst->nmodtab * sizeof_dylib_module, "module table") ==
4380 CHECK_BAD)
4381 goto return_bad;
4382 if(dyst->extrefsymoff > size){
4383 Mach_O_error(ofile, "truncated or malformed object "
4384 "(extrefsymoff field of LC_DYSYMTAB command %u "
4385 "extends past the end of the file)", i);
4386 goto return_bad;
4388 big_size = dyst->nextrefsyms;
4389 big_size *= sizeof(struct dylib_reference);
4390 big_size += dyst->extrefsymoff;
4391 if(big_size > size){
4392 Mach_O_error(ofile, "truncated or malformed object "
4393 "(extrefsymoff field plus nextrefsyms field times "
4394 "sizeof(struct dylib_reference) of LC_DYSYMTAB command "
4395 "%u extends past the end of the file)", i);
4396 goto return_bad;
4398 if(check_overlaping_element(ofile, &elements,dyst->extrefsymoff,
4399 dyst->nextrefsyms * sizeof(struct dylib_reference),
4400 "reference table") == CHECK_BAD)
4401 goto return_bad;
4402 if(dyst->indirectsymoff > size){
4403 Mach_O_error(ofile, "truncated or malformed object "
4404 "(indirectsymoff field of LC_DYSYMTAB command %u "
4405 "extends past the end of the file)", i);
4406 goto return_bad;
4408 big_size = dyst->nindirectsyms;
4409 big_size *= sizeof(uint32_t);
4410 big_size += dyst->indirectsymoff;
4411 if(big_size > size){
4412 Mach_O_error(ofile, "truncated or malformed object "
4413 "(indirectsymoff field plus nindirectsyms field times "
4414 "sizeof(uint32_t) of LC_DYSYMTAB command "
4415 "%u extends past the end of the file)", i);
4416 goto return_bad;
4418 if(check_overlaping_element(ofile, &elements,
4419 dyst->indirectsymoff, dyst->nindirectsyms *
4420 sizeof(uint32_t), "indirect table") == CHECK_BAD)
4421 goto return_bad;
4422 if(dyst->extreloff > size){
4423 Mach_O_error(ofile, "truncated or malformed object "
4424 "(extreloff field of LC_DYSYMTAB command %u "
4425 "extends past the end of the file)", i);
4426 goto return_bad;
4428 big_size = dyst->nextrel;
4429 big_size *= sizeof(struct relocation_info);
4430 big_size += dyst->extreloff;
4431 if(big_size > size){
4432 Mach_O_error(ofile, "truncated or malformed object "
4433 "(extreloff field plus nextrel field times "
4434 "sizeof(struct relocation_info) of LC_DYSYMTAB command "
4435 "%u extends past the end of the file)", i);
4436 goto return_bad;
4438 if(check_overlaping_element(ofile, &elements, dyst->extreloff,
4439 dyst->nextrel * sizeof(struct relocation_info),
4440 "external relocation table") == CHECK_BAD)
4441 goto return_bad;
4442 if(dyst->locreloff > size){
4443 Mach_O_error(ofile, "truncated or malformed object "
4444 "(locreloff field of LC_DYSYMTAB command %u "
4445 "extends past the end of the file)", i);
4446 goto return_bad;
4448 big_size = dyst->nlocrel;
4449 big_size *= sizeof(struct relocation_info);
4450 big_size += dyst->locreloff;
4451 if(big_size > size){
4452 Mach_O_error(ofile, "truncated or malformed object "
4453 "(locreloff field plus nlocrel field times "
4454 "sizeof(struct relocation_info) of LC_DYSYMTAB command "
4455 "%u extends past the end of the file)", i);
4456 goto return_bad;
4458 if(check_overlaping_element(ofile, &elements, dyst->locreloff,
4459 dyst->nlocrel * sizeof(struct relocation_info),
4460 "local relocation table") == CHECK_BAD)
4461 goto return_bad;
4462 break;
4464 case LC_ROUTINES:
4465 if(l.cmdsize < sizeof(struct routines_command)){
4466 Mach_O_error(ofile, "malformed object (LC_ROUTINES cmdsize "
4467 "too small) in command %u", i);
4468 goto return_bad;
4470 if(rc != NULL){
4471 Mach_O_error(ofile, "malformed object (more than one "
4472 "LC_ROUTINES command)");
4473 goto return_bad;
4475 rc = (struct routines_command *)lc;
4476 if(swapped)
4477 swap_routines_command(rc, host_byte_sex);
4478 if(rc->cmdsize != sizeof(struct routines_command)){
4479 Mach_O_error(ofile, "malformed object (LC_ROUTINES "
4480 "command %u has incorrect cmdsize)", i);
4481 goto return_bad;
4483 break;
4485 case LC_ROUTINES_64:
4486 if(l.cmdsize < sizeof(struct routines_command_64)){
4487 Mach_O_error(ofile, "malformed object (LC_ROUTINES_64 "
4488 "cmdsize too small) in command %u", i);
4489 goto return_bad;
4491 if(rc64 != NULL){
4492 Mach_O_error(ofile, "malformed object (more than one "
4493 "LC_ROUTINES_64 command)");
4494 goto return_bad;
4496 rc64 = (struct routines_command_64 *)lc;
4497 if(swapped)
4498 swap_routines_command_64(rc64, host_byte_sex);
4499 if(rc64->cmdsize != sizeof(struct routines_command_64)){
4500 Mach_O_error(ofile, "malformed object (LC_ROUTINES_64 "
4501 "command %u has incorrect cmdsize)", i);
4502 goto return_bad;
4504 break;
4506 case LC_TWOLEVEL_HINTS:
4507 if(l.cmdsize < sizeof(struct twolevel_hints_command)){
4508 Mach_O_error(ofile, "malformed object (LC_TWOLEVEL_HINTS "
4509 "cmdsize too small) in command %u", i);
4510 goto return_bad;
4512 if(hints != NULL){
4513 Mach_O_error(ofile, "malformed object (more than one "
4514 "LC_TWOLEVEL_HINTS command)");
4515 goto return_bad;
4517 hints = (struct twolevel_hints_command *)lc;
4518 if(swapped)
4519 swap_twolevel_hints_command(hints, host_byte_sex);
4520 if(hints->cmdsize != sizeof(struct twolevel_hints_command)){
4521 Mach_O_error(ofile, "malformed object (LC_TWOLEVEL_HINTS "
4522 "command %u has incorrect cmdsize)", i);
4523 goto return_bad;
4525 if(hints->offset > size){
4526 Mach_O_error(ofile, "truncated or malformed object "
4527 "(offset field of LC_TWOLEVEL_HINTS command %u "
4528 "extends past the end of the file)", i);
4529 goto return_bad;
4531 big_size = hints->nhints;
4532 big_size *= sizeof(struct twolevel_hint);
4533 big_size += hints->offset;
4534 if(big_size > size){
4535 Mach_O_error(ofile, "truncated or malformed object "
4536 "(offset field plus nhints field times "
4537 "sizeof(struct twolevel_hint) of LC_TWOLEVEL_HINTS "
4538 " command %u extends past the end of the file)", i);
4539 goto return_bad;
4541 if(check_overlaping_element(ofile, &elements, hints->offset,
4542 hints->nhints * sizeof(struct twolevel_hint),
4543 "two level hints") == CHECK_BAD)
4544 goto return_bad;
4545 break;
4547 case LC_SEGMENT_SPLIT_INFO:
4548 cmd_name = "LC_SEGMENT_SPLIT_INFO";
4549 element_name = "split info data";
4550 if(split_info != NULL){
4551 Mach_O_error(ofile, "malformed object (more than one "
4552 "%s command)", cmd_name);
4553 goto return_bad;
4555 split_info = (struct linkedit_data_command *)lc;
4556 goto check_linkedit_data_command;
4558 case LC_CODE_SIGNATURE:
4559 cmd_name = "LC_CODE_SIGNATURE";
4560 element_name = "code signature data";
4561 if(code_sig != NULL){
4562 Mach_O_error(ofile, "malformed object (more than one "
4563 "%s command)", cmd_name);
4564 goto return_bad;
4566 code_sig = (struct linkedit_data_command *)lc;
4567 goto check_linkedit_data_command;
4569 case LC_FUNCTION_STARTS:
4570 cmd_name = "LC_FUNCTION_STARTS";
4571 element_name = "function starts data";
4572 if(func_starts != NULL){
4573 Mach_O_error(ofile, "malformed object (more than one "
4574 "%s command)", cmd_name);
4575 goto return_bad;
4577 func_starts = (struct linkedit_data_command *)lc;
4578 goto check_linkedit_data_command;
4580 case LC_DATA_IN_CODE:
4581 cmd_name = "LC_DATA_IN_CODE";
4582 element_name = "date in code info";
4583 if(data_in_code != NULL){
4584 Mach_O_error(ofile, "malformed object (more than one "
4585 "%s command)", cmd_name);
4586 goto return_bad;
4588 data_in_code = (struct linkedit_data_command *)lc;
4589 goto check_linkedit_data_command;
4591 case LC_DYLIB_CODE_SIGN_DRS:
4592 cmd_name = "LC_DYLIB_CODE_SIGN_DRS";
4593 element_name = "code signing RDs data";
4594 if(code_sign_drs != NULL){
4595 Mach_O_error(ofile, "malformed object (more than one "
4596 "%s command)", cmd_name);
4597 goto return_bad;
4599 code_sign_drs = (struct linkedit_data_command *)lc;
4600 goto check_linkedit_data_command;
4602 case LC_LINKER_OPTIMIZATION_HINT:
4603 cmd_name = "LC_LINKER_OPTIMIZATION_HINT";
4604 element_name = "linker optimization hint";
4605 if(link_opt_hint != NULL){
4606 Mach_O_error(ofile, "malformed object (more than one "
4607 "%s command)", cmd_name);
4608 goto return_bad;
4610 link_opt_hint = (struct linkedit_data_command *)lc;
4611 goto check_linkedit_data_command;
4613 check_linkedit_data_command:
4614 if(l.cmdsize < sizeof(struct linkedit_data_command)){
4615 Mach_O_error(ofile, "malformed object (%s cmdsize too "
4616 "small) in command %u", cmd_name, i);
4617 goto return_bad;
4619 linkedit_data = (struct linkedit_data_command *)lc;
4620 if(swapped)
4621 swap_linkedit_data_command(linkedit_data, host_byte_sex);
4622 if(linkedit_data->cmdsize !=
4623 sizeof(struct linkedit_data_command)){
4624 Mach_O_error(ofile, "malformed object (%s command %u has "
4625 "incorrect cmdsize)", cmd_name, i);
4626 goto return_bad;
4628 if(linkedit_data->dataoff > size){
4629 Mach_O_error(ofile, "truncated or malformed object "
4630 "(dataoff field of %s command %u extends past the end "
4631 "of the file)", cmd_name, i);
4632 goto return_bad;
4634 big_size = linkedit_data->dataoff;
4635 big_size += linkedit_data->datasize;
4636 if(big_size > size){
4637 Mach_O_error(ofile, "truncated or malformed object "
4638 "(dataoff field plus datasize field of "
4639 "%s command %u extends past the end of "
4640 "the file)", cmd_name, i);
4641 goto return_bad;
4643 if(check_overlaping_element(ofile, &elements,
4644 linkedit_data->dataoff, linkedit_data->datasize,
4645 element_name) == CHECK_BAD)
4646 goto return_bad;
4647 break;
4649 case LC_VERSION_MIN_MACOSX:
4650 if(l.cmdsize < sizeof(struct version_min_command)){
4651 Mach_O_error(ofile, "malformed object (LC_VERSION_MIN_"
4652 "MACOSX cmdsize too small) in command %u", i);
4653 goto return_bad;
4655 if(vers != NULL){
4656 Mach_O_error(ofile, "malformed object (more than one "
4657 "LC_VERSION_MIN_IPHONEOS or LC_VERSION_MIN_MACOSX "
4658 "command)");
4659 goto return_bad;
4661 vers = (struct version_min_command *)lc;
4662 if(swapped)
4663 swap_version_min_command(vers, host_byte_sex);
4664 if(vers->cmdsize < sizeof(struct version_min_command)){
4665 Mach_O_error(ofile, "malformed object (LC_VERSION_MIN_"
4666 "MACOSX command %u has too small cmdsize field)", i);
4667 goto return_bad;
4669 break;
4671 case LC_VERSION_MIN_IPHONEOS:
4672 if(l.cmdsize < sizeof(struct version_min_command)){
4673 Mach_O_error(ofile, "malformed object (LC_VERSION_MIN_"
4674 "IPHONEOS cmdsize too small) in command %u",i);
4675 goto return_bad;
4677 if(vers != NULL){
4678 Mach_O_error(ofile, "malformed object (more than one "
4679 "LC_VERSION_MIN_IPHONEOS or LC_VERSION_MIN_MACOSX "
4680 "command)");
4681 goto return_bad;
4683 vers = (struct version_min_command *)lc;
4684 if(swapped)
4685 swap_version_min_command(vers, host_byte_sex);
4686 if(vers->cmdsize < sizeof(struct version_min_command)){
4687 Mach_O_error(ofile, "malformed object (LC_VERSION_MIN_"
4688 "IPHONEOS command %u has too small cmdsize field)", i);
4689 goto return_bad;
4691 break;
4693 case LC_VERSION_MIN_TVOS:
4694 if(l.cmdsize < sizeof(struct version_min_command)){
4695 Mach_O_error(ofile, "malformed object (LC_VERSION_MIN_"
4696 " cmdsize too small) in command %u",i);
4697 goto return_bad;
4699 if(vers != NULL){
4700 Mach_O_error(ofile, "malformed object (more than one "
4701 "LC_VERSION_MIN_ command)");
4702 goto return_bad;
4704 vers = (struct version_min_command *)lc;
4705 if(swapped)
4706 swap_version_min_command(vers, host_byte_sex);
4707 if(vers->cmdsize < sizeof(struct version_min_command)){
4708 Mach_O_error(ofile, "malformed object (LC_VERSION_MIN_"
4709 " command %u has too small cmdsize field)", i);
4710 goto return_bad;
4712 break;
4714 case LC_VERSION_MIN_WATCHOS:
4715 if(l.cmdsize < sizeof(struct version_min_command)){
4716 Mach_O_error(ofile, "malformed object (LC_VERSION_MIN_"
4717 "WATCHOS cmdsize too small) in command %u",i);
4718 goto return_bad;
4720 if(vers != NULL){
4721 Mach_O_error(ofile, "malformed object (more than one "
4722 "LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_MACOSX or "
4723 "LC_VERSION_MIN_WATCHOS command)");
4724 goto return_bad;
4726 vers = (struct version_min_command *)lc;
4727 if(swapped)
4728 swap_version_min_command(vers, host_byte_sex);
4729 if(vers->cmdsize < sizeof(struct version_min_command)){
4730 Mach_O_error(ofile, "malformed object (LC_VERSION_MIN_"
4731 "WATCHOS command %u has too small cmdsize field)", i);
4732 goto return_bad;
4734 break;
4736 case LC_ENCRYPTION_INFO:
4737 if(l.cmdsize < sizeof(struct encryption_info_command)){
4738 Mach_O_error(ofile, "malformed object (LC_ENCRYPTION_INFO "
4739 "cmdsize too small) in command %u", i);
4740 goto return_bad;
4742 encrypt_info = (struct encryption_info_command *)lc;
4743 if(swapped)
4744 swap_encryption_command(encrypt_info, host_byte_sex);
4745 if(encrypt_info->cmdsize !=
4746 sizeof(struct encryption_info_command)){
4747 Mach_O_error(ofile, "malformed object (LC_ENCRYPTION_INFO"
4748 "command %u has incorrect cmdsize)", i);
4749 goto return_bad;
4751 if(encrypt_info->cryptoff > size){
4752 Mach_O_error(ofile, "truncated or malformed object (cryptoff "
4753 "field of LC_ENCRYPTION_INFO command %u extends "
4754 "past the end of the file)", i);
4755 goto return_bad;
4757 big_size = encrypt_info->cryptoff;
4758 big_size += encrypt_info->cryptsize;
4759 if(big_size > size){
4760 Mach_O_error(ofile, "truncated or malformed object "
4761 "(cryptoff field plus cryptsize field of "
4762 "LC_ENCRYPTION_INFO command %u extends past "
4763 "the end of the file)", i);
4764 goto return_bad;
4766 break;
4768 case LC_ENCRYPTION_INFO_64:
4769 if(l.cmdsize < sizeof(struct encryption_info_command_64)){
4770 Mach_O_error(ofile, "malformed object (LC_ENCRYPTION_INFO"
4771 "_64 cmdsize too small) in command %u", i);
4772 goto return_bad;
4774 encrypt_info64 = (struct encryption_info_command_64 *)lc;
4775 if(swapped)
4776 swap_encryption_command_64(encrypt_info64, host_byte_sex);
4777 if(encrypt_info64->cmdsize !=
4778 sizeof(struct encryption_info_command_64)){
4779 Mach_O_error(ofile, "malformed object (LC_ENCRYPTION_INFO"
4780 "_64 command %u has incorrect cmdsize)", i);
4781 goto return_bad;
4783 if(encrypt_info64->cryptoff > size){
4784 Mach_O_error(ofile, "truncated or malformed object (cryptoff "
4785 "field of LC_ENCRYPTION_INFO_64 command %u extends"
4786 " past the end of the file)", i);
4787 goto return_bad;
4789 big_size = encrypt_info64->cryptoff;
4790 big_size += encrypt_info64->cryptsize;
4791 if(big_size > size){
4792 Mach_O_error(ofile, "truncated or malformed object "
4793 "(cryptoff field plus cryptsize field of "
4794 "LC_ENCRYPTION_INFO_64 command %u extends past"
4795 " the end of the file)", i);
4796 goto return_bad;
4798 break;
4800 case LC_LINKER_OPTION:
4801 if(l.cmdsize < sizeof(struct linker_option_command)){
4802 Mach_O_error(ofile, "malformed object (LC_LINKER_OPTION "
4803 "cmdsize too small) in command %u", i);
4804 goto return_bad;
4806 lo = (struct linker_option_command *)lc;
4807 if(swapped)
4808 swap_linker_option_command(lo, host_byte_sex);
4809 if(lo->cmdsize <
4810 sizeof(struct linker_option_command)){
4811 Mach_O_error(ofile, "malformed object (LC_LINKER_OPTION "
4812 " command %u cmdsize too small)", i);
4813 goto return_bad;
4815 break;
4817 case LC_DYLD_INFO:
4818 case LC_DYLD_INFO_ONLY:
4819 if(l.cmdsize < sizeof(struct dyld_info_command)){
4820 Mach_O_error(ofile, "malformed object (%s cmdsize "
4821 "too small) in command %u", l.cmd ==
4822 LC_DYLD_INFO ? "LC_DYLD_INFO" :
4823 "LC_DYLD_INFO_ONLY", i);
4824 goto return_bad;
4826 dyld_info = (struct dyld_info_command *)lc;
4827 if(swapped)
4828 swap_dyld_info_command(dyld_info, host_byte_sex);
4829 if(dyld_info->cmdsize !=
4830 sizeof(struct dyld_info_command)){
4831 Mach_O_error(ofile, "malformed object (LC_DYLD_INFO"
4832 "command %u has incorrect cmdsize)", i);
4833 goto return_bad;
4835 if(dyld_info->rebase_off != 0 && dyld_info->rebase_off > size){
4836 Mach_O_error(ofile, "truncated or malformed object "
4837 "(rebase_off field of LC_DYLD_INFO command %u "
4838 "extends past the end of the file)", i);
4839 goto return_bad;
4841 if(dyld_info->rebase_off != 0){
4842 big_size = dyld_info->rebase_off;
4843 big_size += dyld_info->rebase_size;
4844 if(big_size > size){
4845 Mach_O_error(ofile, "truncated or malformed object "
4846 "(rebase_off plus rebase_size of LC_DYLD_INFO "
4847 "command %u extends past the end of the file)", i);
4848 goto return_bad;
4851 if(check_overlaping_element(ofile, &elements,
4852 dyld_info->rebase_off, dyld_info->rebase_size,
4853 "dyld rebase info") == CHECK_BAD)
4854 goto return_bad;
4855 if(dyld_info->bind_off != 0 && dyld_info->bind_off > size){
4856 Mach_O_error(ofile, "truncated or malformed object "
4857 "(bind_off field of LC_DYLD_INFO command %u "
4858 "extends past the end of the file)", i);
4859 goto return_bad;
4861 if(dyld_info->bind_off != 0){
4862 big_size = dyld_info->bind_off;
4863 big_size += dyld_info->bind_size;
4864 if(big_size > size){
4865 Mach_O_error(ofile, "truncated or malformed object "
4866 "(bind_off plus bind_size of LC_DYLD_INFO command "
4867 "%u extends past the end of the file)", i);
4868 goto return_bad;
4871 if(check_overlaping_element(ofile, &elements,
4872 dyld_info->bind_off, dyld_info->bind_size,
4873 "dyld bind info") == CHECK_BAD)
4874 goto return_bad;
4875 if(dyld_info->weak_bind_off != 0 &&
4876 dyld_info->weak_bind_off > size){
4877 Mach_O_error(ofile, "truncated or malformed object "
4878 "(weak_bind_off field of LC_DYLD_INFO command %u "
4879 "extends past the end of the file)", i);
4880 goto return_bad;
4882 if(dyld_info->weak_bind_off != 0){
4883 big_size = dyld_info->weak_bind_off;
4884 big_size += dyld_info->weak_bind_size;
4885 if(big_size > size){
4886 Mach_O_error(ofile, "truncated or malformed object "
4887 "(weak_bind_off plus weak_bind_size of LC_DYLD_INFO"
4888 " command %u extends past the end of the file)", i);
4889 goto return_bad;
4892 if(check_overlaping_element(ofile, &elements,
4893 dyld_info->weak_bind_off, dyld_info->weak_bind_size,
4894 "dyld bind info") == CHECK_BAD)
4895 goto return_bad;
4896 if(dyld_info->lazy_bind_off != 0 &&
4897 dyld_info->lazy_bind_off > size){
4898 Mach_O_error(ofile, "truncated or malformed object "
4899 "(lazy_bind_off field of LC_DYLD_INFO command %u "
4900 "extends past the end of the file)", i);
4901 goto return_bad;
4903 if(dyld_info->lazy_bind_off != 0){
4904 big_size = dyld_info->lazy_bind_off;
4905 big_size += dyld_info->lazy_bind_size;
4906 if(big_size > size){
4907 Mach_O_error(ofile, "truncated or malformed object "
4908 "(lazy_bind_off plus lazy_bind_size of LC_DYLD_INFO"
4909 " command %u extends past the end of the file)", i);
4910 goto return_bad;
4913 if(check_overlaping_element(ofile, &elements,
4914 dyld_info->lazy_bind_off, dyld_info->lazy_bind_size,
4915 "dyld lazy bind info") == CHECK_BAD)
4916 goto return_bad;
4917 if(dyld_info->export_off != 0 && dyld_info->export_off > size){
4918 Mach_O_error(ofile, "truncated or malformed object "
4919 "(export_off field of LC_DYLD_INFO command %u "
4920 "extends past the end of the file)", i);
4921 goto return_bad;
4923 if(dyld_info->export_off != 0){
4924 big_size = dyld_info->export_off;
4925 big_size += dyld_info->export_size;
4926 if(big_size > size){
4927 Mach_O_error(ofile, "truncated or malformed object "
4928 "(export_off plus export_size of LC_DYLD_INFO "
4929 "command %u extends past the end of the file)", i);
4930 goto return_bad;
4933 if(check_overlaping_element(ofile, &elements,
4934 dyld_info->export_off, dyld_info->export_size,
4935 "dyld export info") == CHECK_BAD)
4936 goto return_bad;
4937 break;
4941 case LC_PREBIND_CKSUM:
4942 if(l.cmdsize < sizeof(struct prebind_cksum_command)){
4943 Mach_O_error(ofile, "malformed object (LC_PREBIND_CKSUM "
4944 "cmdsize too small) in command %u", i);
4945 goto return_bad;
4947 if(cs != NULL){
4948 Mach_O_error(ofile, "malformed object (more than one "
4949 "LC_PREBIND_CKSUM command)");
4950 goto return_bad;
4952 cs = (struct prebind_cksum_command *)lc;
4953 if(swapped)
4954 swap_prebind_cksum_command(cs, host_byte_sex);
4955 if(cs->cmdsize != sizeof(struct prebind_cksum_command)){
4956 Mach_O_error(ofile, "malformed object (LC_PREBIND_CKSUM "
4957 "command %u has incorrect cmdsize)", i);
4958 goto return_bad;
4960 break;
4962 case LC_UUID:
4963 if(l.cmdsize < sizeof(struct uuid_command)){
4964 Mach_O_error(ofile, "malformed object (LC_UUID cmdsize "
4965 "too small) in command %u", i);
4966 goto return_bad;
4968 if(uuid != NULL){
4969 Mach_O_error(ofile, "malformed object (more than one "
4970 "LC_UUID command)");
4971 goto return_bad;
4973 uuid = (struct uuid_command *)lc;
4974 if(swapped)
4975 swap_uuid_command(uuid, host_byte_sex);
4976 if(uuid->cmdsize != sizeof(struct uuid_command)){
4977 Mach_O_error(ofile, "malformed object (LC_UUID command %u " "has incorrect cmdsize)", i);
4978 goto return_bad;
4980 break;
4982 case LC_SYMSEG:
4983 if(l.cmdsize < sizeof(struct symseg_command)){
4984 Mach_O_error(ofile, "malformed object (LC_SYMSEG cmdsize "
4985 "too small) in command %u", i);
4986 goto return_bad;
4988 ss = (struct symseg_command *)lc;
4989 if(swapped)
4990 swap_symseg_command(ss, host_byte_sex);
4991 if(ss->cmdsize != sizeof(struct symseg_command)){
4992 Mach_O_error(ofile, "malformed object (LC_SYMSEG command "
4993 "%u has incorrect cmdsize)", i);
4994 goto return_bad;
4996 if(ss->offset > size){
4997 Mach_O_error(ofile, "truncated or malformed object (offset "
4998 "field of LC_SYMSEG command %u extends past the end "
4999 "of the file)", i);
5000 goto return_bad;
5002 big_size = ss->offset;
5003 big_size += ss->size;
5004 if(big_size > size){
5005 Mach_O_error(ofile, "truncated or malformed object (offset "
5006 "field plus size field of LC_SYMTAB command %u "
5007 "extends past the end of the file)", i);
5008 goto return_bad;
5010 if(check_overlaping_element(ofile, &elements, ss->offset,
5011 ss->size, "symseg info") == CHECK_BAD)
5012 goto return_bad;
5013 break;
5015 case LC_IDFVMLIB:
5016 case LC_LOADFVMLIB:
5017 if(l.cmdsize < sizeof(struct fvmlib_command)){
5018 Mach_O_error(ofile, "malformed object (%s cmdsize "
5019 "too small) in command %u", l.cmd ==
5020 LC_IDFVMLIB ? "LC_IDFVMLIB" :
5021 "LC_LOADFVMLIB", i);
5022 goto return_bad;
5024 fl = (struct fvmlib_command *)lc;
5025 if(swapped)
5026 swap_fvmlib_command(fl, host_byte_sex);
5027 if(fl->cmdsize < sizeof(struct fvmlib_command)){
5028 Mach_O_error(ofile, "malformed object (%s command %u has "
5029 "too small cmdsize field)", fl->cmd == LC_IDFVMLIB ?
5030 "LC_IDFVMLIB" : "LC_LOADFVMLIB", i);
5031 goto return_bad;
5033 if(fl->fvmlib.name.offset >= fl->cmdsize){
5034 Mach_O_error(ofile, "truncated or malformed object (name."
5035 "offset field of %s command %u extends past the end "
5036 "of the file)", fl->cmd == LC_IDFVMLIB ? "LC_IDFVMLIB"
5037 : "LC_LOADFVMLIB", i);
5038 goto return_bad;
5040 break;
5042 case LC_ID_DYLIB:
5043 cmd_name = "LC_ID_DYLIB";
5044 goto check_dylib_command;
5045 case LC_LOAD_DYLIB:
5046 cmd_name = "LC_LOAD_DYLIB";
5047 goto check_dylib_command;
5048 case LC_LOAD_WEAK_DYLIB:
5049 cmd_name = "LC_LOAD_WEAK_DYLIB";
5050 goto check_dylib_command;
5051 case LC_REEXPORT_DYLIB:
5052 cmd_name = "LC_REEXPORT_DYLIB";
5053 goto check_dylib_command;
5054 case LC_LOAD_UPWARD_DYLIB:
5055 cmd_name = "LC_LOAD_UPWARD_DYLIB";
5056 goto check_dylib_command;
5057 case LC_LAZY_LOAD_DYLIB:
5058 cmd_name = "LC_LAZY_LOAD_DYLIB";
5059 goto check_dylib_command;
5060 check_dylib_command:
5061 if(l.cmdsize < sizeof(struct dylib_command)){
5062 Mach_O_error(ofile, "malformed object (%s cmdsize too "
5063 "small) in command %u", cmd_name, i);
5064 goto return_bad;
5066 dl = (struct dylib_command *)lc;
5067 if(swapped)
5068 swap_dylib_command(dl, host_byte_sex);
5069 if(dl->cmdsize < sizeof(struct dylib_command)){
5070 Mach_O_error(ofile, "malformed object (%s command %u has "
5071 "too small cmdsize field)", cmd_name, i);
5072 goto return_bad;
5074 if(dl->dylib.name.offset >= dl->cmdsize){
5075 Mach_O_error(ofile, "truncated or malformed object (name."
5076 "offset field of %s command %u extends past the end "
5077 "of the file)", cmd_name, i);
5078 goto return_bad;
5080 break;
5082 case LC_SUB_FRAMEWORK:
5083 if(l.cmdsize < sizeof(struct sub_framework_command)){
5084 Mach_O_error(ofile, "malformed object (LC_SUB_FRAMEWORK "
5085 "cmdsize too small) in command %u", i);
5086 goto return_bad;
5088 sub = (struct sub_framework_command *)lc;
5089 if(swapped)
5090 swap_sub_framework_command(sub, host_byte_sex);
5091 if(sub->cmdsize < sizeof(struct sub_framework_command)){
5092 Mach_O_error(ofile, "malformed object (LC_SUB_FRAMEWORK "
5093 "command %u has too small cmdsize field)", i);
5094 goto return_bad;
5096 if(sub->umbrella.offset >= sub->cmdsize){
5097 Mach_O_error(ofile, "truncated or malformed object "
5098 "(umbrella.offset field of LC_SUB_FRAMEWORK command "
5099 "%u extends past the end of the file)", i);
5100 goto return_bad;
5102 break;
5104 case LC_SUB_UMBRELLA:
5105 if(l.cmdsize < sizeof(struct sub_umbrella_command)){
5106 Mach_O_error(ofile, "malformed object (LC_SUB_UMBRELLA "
5107 "cmdsize too small) in command %u", i);
5108 goto return_bad;
5110 usub = (struct sub_umbrella_command *)lc;
5111 if(swapped)
5112 swap_sub_umbrella_command(usub, host_byte_sex);
5113 if(usub->cmdsize < sizeof(struct sub_umbrella_command)){
5114 Mach_O_error(ofile, "malformed object (LC_SUB_UMBRELLA "
5115 "command %u has too small cmdsize field)", i);
5116 goto return_bad;
5118 if(usub->sub_umbrella.offset >= usub->cmdsize){
5119 Mach_O_error(ofile, "truncated or malformed object "
5120 "(sub_umbrella.offset field of LC_SUB_UMBRELLA command "
5121 "%u extends past the end of the file)", i);
5122 goto return_bad;
5124 break;
5126 case LC_SUB_LIBRARY:
5127 if(l.cmdsize < sizeof(struct sub_library_command)){
5128 Mach_O_error(ofile, "malformed object (LC_SUB_LIBRARY "
5129 "cmdsize too small) in command %u", i);
5130 goto return_bad;
5132 lsub = (struct sub_library_command *)lc;
5133 if(swapped)
5134 swap_sub_library_command(lsub, host_byte_sex);
5135 if(lsub->cmdsize < sizeof(struct sub_library_command)){
5136 Mach_O_error(ofile, "malformed object (LC_SUB_LIBRARY "
5137 "command %u has too small cmdsize field)", i);
5138 goto return_bad;
5140 if(lsub->sub_library.offset >= lsub->cmdsize){
5141 Mach_O_error(ofile, "truncated or malformed object "
5142 "(sub_library.offset field of LC_SUB_LIBRARY command "
5143 "%u extends past the end of the file)", i);
5144 goto return_bad;
5146 break;
5148 case LC_SUB_CLIENT:
5149 if(l.cmdsize < sizeof(struct sub_client_command)){
5150 Mach_O_error(ofile, "malformed object (LC_SUB_CLIENT "
5151 "cmdsize too small) in command %u", i);
5152 goto return_bad;
5154 csub = (struct sub_client_command *)lc;
5155 if(swapped)
5156 swap_sub_client_command(csub, host_byte_sex);
5157 if(csub->cmdsize < sizeof(struct sub_client_command)){
5158 Mach_O_error(ofile, "malformed object (LC_SUB_CLIENT "
5159 "command %u has too small cmdsize field)", i);
5160 goto return_bad;
5162 if(csub->client.offset >= csub->cmdsize){
5163 Mach_O_error(ofile, "truncated or malformed object "
5164 "(cleient.offset field of LC_SUB_CLIENT command "
5165 "%u extends past the end of the file)", i);
5166 goto return_bad;
5168 break;
5170 case LC_PREBOUND_DYLIB:
5171 if(l.cmdsize < sizeof(struct prebound_dylib_command)){
5172 Mach_O_error(ofile, "malformed object (LC_PREBOUND_DYLIB "
5173 "cmdsize too small) in command %u", i);
5174 goto return_bad;
5176 pbdylib = (struct prebound_dylib_command *)lc;
5177 if(swapped)
5178 swap_prebound_dylib_command(pbdylib, host_byte_sex);
5179 if(pbdylib->cmdsize < sizeof(struct dylib_command)){
5180 Mach_O_error(ofile, "malformed object (LC_PREBIND_DYLIB "
5181 "command %u has too small cmdsize field)", i);
5182 goto return_bad;
5184 if(pbdylib->name.offset >= pbdylib->cmdsize){
5185 Mach_O_error(ofile, "truncated or malformed object (name."
5186 "offset field of LC_PREBIND_DYLIB command %u extends "
5187 "past the end of the file)", i);
5188 goto return_bad;
5190 if(pbdylib->linked_modules.offset >= pbdylib->cmdsize){
5191 Mach_O_error(ofile, "truncated or malformed object (linked_"
5192 "modules.offset field of LC_PREBIND_DYLIB command %u "
5193 "extends past the end of the file)", i);
5194 goto return_bad;
5196 break;
5198 case LC_ID_DYLINKER:
5199 cmd_name = "LC_ID_DYLINKER";
5200 goto check_dylinker_command;
5201 case LC_LOAD_DYLINKER:
5202 cmd_name = "LC_LOAD_DYLINKER";
5203 goto check_dylinker_command;
5204 case LC_DYLD_ENVIRONMENT:
5205 cmd_name = "LC_DYLD_ENVIRONMENT";
5206 goto check_dylinker_command;
5207 check_dylinker_command:
5208 if(l.cmdsize < sizeof(struct dylinker_command)){
5209 Mach_O_error(ofile, "malformed object (%s cmdsize "
5210 "too small) in command %u", cmd_name, i);
5211 goto return_bad;
5213 dyld = (struct dylinker_command *)lc;
5214 if(swapped)
5215 swap_dylinker_command(dyld, host_byte_sex);
5216 if(dyld->cmdsize < sizeof(struct dylinker_command)){
5217 Mach_O_error(ofile, "malformed object (%s command %u has "
5218 "too small cmdsize field)", cmd_name, i);
5219 goto return_bad;
5221 if(dyld->name.offset >= dyld->cmdsize){
5222 Mach_O_error(ofile, "truncated or malformed object (name."
5223 "offset field of %s command %u extends past the end "
5224 "of the file)", cmd_name, i);
5225 goto return_bad;
5227 break;
5229 case LC_UNIXTHREAD:
5230 case LC_THREAD:
5231 if(l.cmdsize < sizeof(struct thread_command)){
5232 Mach_O_error(ofile, "malformed object (%s cmdsize "
5233 "too small) in command %u", l.cmd ==
5234 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5235 "LC_THREAD", i);
5236 goto return_bad;
5238 ut = (struct thread_command *)lc;
5239 if(swapped)
5240 swap_thread_command(ut, host_byte_sex);
5241 state = (char *)ut + sizeof(struct thread_command);
5243 if(cputype == CPU_TYPE_MC680x0){
5244 struct m68k_thread_state_regs *cpu;
5245 struct m68k_thread_state_68882 *fpu;
5246 struct m68k_thread_state_user_reg *user_reg;
5248 nflavor = 0;
5249 p = (char *)ut + ut->cmdsize;
5250 while(state < p){
5251 if(state + sizeof(uint32_t) >
5252 (char *)ut + ut->cmdsize){
5253 Mach_O_error(ofile, "malformed object (flavor in "
5254 "%s command %u extends past end of command)",
5255 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5256 "LC_THREAD", i);
5257 goto return_bad;
5259 flavor = *((uint32_t *)state);
5260 if(swapped){
5261 flavor = SWAP_INT(flavor);
5262 *((uint32_t *)state) = flavor;
5264 state += sizeof(uint32_t);
5265 if(state + sizeof(uint32_t) >
5266 (char *)ut + ut->cmdsize){
5267 Mach_O_error(ofile, "malformed object (count in "
5268 "%s command %u extends past end of command)",
5269 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5270 "LC_THREAD", i);
5271 goto return_bad;
5273 count = *((uint32_t *)state);
5274 if(swapped){
5275 count = SWAP_INT(count);
5276 *((uint32_t *)state) = count;
5278 state += sizeof(uint32_t);
5279 switch(flavor){
5280 case M68K_THREAD_STATE_REGS:
5281 if(count != M68K_THREAD_STATE_REGS_COUNT){
5282 Mach_O_error(ofile, "malformed object (count "
5283 "not M68K_THREAD_STATE_REGS_COUNT for "
5284 "flavor number %u which is a M68K_THREAD_"
5285 "STATE_REGS flavor in %s command %u)",
5286 nflavor, ut->cmd == LC_UNIXTHREAD ?
5287 "LC_UNIXTHREAD" : "LC_THREAD", i);
5288 goto return_bad;
5290 cpu = (struct m68k_thread_state_regs *)state;
5291 if(state + sizeof(struct m68k_thread_state_regs) >
5292 (char *)ut + ut->cmdsize){
5293 Mach_O_error(ofile, "malformed object ("
5294 "M68K_THREAD_STATE_REGS in %s command %u "
5295 "extends past end of command)", ut->cmd ==
5296 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5297 "LC_THREAD", i);
5298 goto return_bad;
5300 if(swapped)
5301 swap_m68k_thread_state_regs(cpu, host_byte_sex);
5302 state += sizeof(struct m68k_thread_state_regs);
5303 break;
5304 case M68K_THREAD_STATE_68882:
5305 if(count != M68K_THREAD_STATE_68882_COUNT){
5306 Mach_O_error(ofile, "malformed object (count "
5307 "not M68K_THREAD_STATE_68882_COUNT for "
5308 "flavor number %u which is a M68K_THREAD_"
5309 "STATE_68882 flavor in %s command %u)",
5310 nflavor, ut->cmd == LC_UNIXTHREAD ?
5311 "LC_UNIXTHREAD" : "LC_THREAD", i);
5312 goto return_bad;
5314 fpu = (struct m68k_thread_state_68882 *)state;
5315 if(state + sizeof(struct m68k_thread_state_68882) >
5316 (char *)ut + ut->cmdsize){
5317 Mach_O_error(ofile, "malformed object ("
5318 "M68K_THREAD_STATE_68882 in %s command %u "
5319 "extends past end of command)", ut->cmd ==
5320 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5321 "LC_THREAD", i);
5322 goto return_bad;
5324 if(swapped)
5325 swap_m68k_thread_state_68882(fpu,host_byte_sex);
5326 state += sizeof(struct m68k_thread_state_68882);
5327 break;
5328 case M68K_THREAD_STATE_USER_REG:
5329 if(count != M68K_THREAD_STATE_USER_REG_COUNT){
5330 Mach_O_error(ofile, "malformed object (count "
5331 "not M68K_THREAD_STATE_USER_REG_COUNT for "
5332 "flavor number %u which is a M68K_THREAD_"
5333 "STATE_USER_REG flavor in %s command %u)",
5334 nflavor, ut->cmd == LC_UNIXTHREAD ?
5335 "LC_UNIXTHREAD" : "LC_THREAD", i);
5336 goto return_bad;
5338 user_reg =
5339 (struct m68k_thread_state_user_reg *)state;
5340 if(state+sizeof(struct m68k_thread_state_user_reg) >
5341 (char *)ut + ut->cmdsize){
5342 Mach_O_error(ofile, "malformed object ("
5343 "M68K_THREAD_STATE_USER_REG in %s command "
5344 "%u extends past end of command)", ut->cmd==
5345 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5346 "LC_THREAD", i);
5347 goto return_bad;
5349 if(swapped)
5350 swap_m68k_thread_state_user_reg(user_reg,
5351 host_byte_sex);
5352 state += sizeof(struct m68k_thread_state_user_reg);
5353 break;
5354 default:
5355 if(swapped){
5356 Mach_O_error(ofile, "malformed object (unknown "
5357 "flavor for flavor number %u in %s command"
5358 " %u can't byte swap it)", nflavor,
5359 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5360 "LC_THREAD", i);
5361 goto return_bad;
5363 state += count * sizeof(uint32_t);
5364 break;
5366 nflavor++;
5368 break;
5370 if(cputype == CPU_TYPE_POWERPC ||
5371 cputype == CPU_TYPE_VEO){
5372 ppc_thread_state_t *nrw_cpu;
5374 nflavor = 0;
5375 p = (char *)ut + ut->cmdsize;
5376 while(state < p){
5377 if(state + sizeof(uint32_t) >
5378 (char *)ut + ut->cmdsize){
5379 Mach_O_error(ofile, "malformed object (flavor in "
5380 "%s command %u extends past end of command)",
5381 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5382 "LC_THREAD", i);
5383 goto return_bad;
5385 flavor = *((uint32_t *)state);
5386 if(swapped){
5387 flavor = SWAP_INT(flavor);
5388 *((uint32_t *)state) = flavor;
5390 state += sizeof(uint32_t);
5391 if(state + sizeof(uint32_t) >
5392 (char *)ut + ut->cmdsize){
5393 Mach_O_error(ofile, "malformed object (count in "
5394 "%s command %u extends past end of command)",
5395 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5396 "LC_THREAD", i);
5397 goto return_bad;
5399 count = *((uint32_t *)state);
5400 if(swapped){
5401 count = SWAP_INT(count);
5402 *((uint32_t *)state) = count;
5404 state += sizeof(uint32_t);
5405 switch(flavor){
5406 case PPC_THREAD_STATE:
5407 if(count != PPC_THREAD_STATE_COUNT){
5408 Mach_O_error(ofile, "malformed object (count "
5409 "not PPC_THREAD_STATE_COUNT for "
5410 "flavor number %u which is a PPC_THREAD_"
5411 "STATE flavor in %s command %u)",
5412 nflavor, ut->cmd == LC_UNIXTHREAD ?
5413 "LC_UNIXTHREAD" : "LC_THREAD", i);
5414 goto return_bad;
5416 nrw_cpu = (ppc_thread_state_t *)state;
5417 if(state + sizeof(ppc_thread_state_t) >
5418 (char *)ut + ut->cmdsize){
5419 Mach_O_error(ofile, "malformed object ("
5420 "PPC_THREAD_STATE in %s command %u extends"
5421 " past end of command)", ut->cmd ==
5422 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5423 "LC_THREAD", i);
5424 goto return_bad;
5426 if(swapped)
5427 swap_ppc_thread_state_t(nrw_cpu,
5428 host_byte_sex);
5429 state += sizeof(ppc_thread_state_t);
5430 break;
5431 default:
5432 if(swapped){
5433 Mach_O_error(ofile, "malformed object (unknown "
5434 "flavor for flavor number %u in %s command"
5435 " %u can't byte swap it)", nflavor,
5436 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5437 "LC_THREAD", i);
5438 goto return_bad;
5440 state += count * sizeof(uint32_t);
5441 break;
5443 nflavor++;
5445 break;
5447 #ifdef PPC_THREAD_STATE64_COUNT
5448 if(cputype == CPU_TYPE_POWERPC64){
5449 ppc_thread_state64_t *cpu;
5451 nflavor = 0;
5452 p = (char *)ut + ut->cmdsize;
5453 while(state < p){
5454 if(state + sizeof(uint32_t) >
5455 (char *)ut + ut->cmdsize){
5456 Mach_O_error(ofile, "malformed object (flavor in "
5457 "%s command %u extends past end of command)",
5458 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5459 "LC_THREAD", i);
5460 goto return_bad;
5462 flavor = *((uint32_t *)state);
5463 if(swapped){
5464 flavor = SWAP_INT(flavor);
5465 *((uint32_t *)state) = flavor;
5467 state += sizeof(uint32_t);
5468 if(state + sizeof(uint32_t) >
5469 (char *)ut + ut->cmdsize){
5470 Mach_O_error(ofile, "malformed object (count in "
5471 "%s command %u extends past end of command)",
5472 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5473 "LC_THREAD", i);
5474 goto return_bad;
5476 count = *((uint32_t *)state);
5477 if(swapped){
5478 count = SWAP_INT(count);
5479 *((uint32_t *)state) = count;
5481 state += sizeof(uint32_t);
5482 switch(flavor){
5483 case PPC_THREAD_STATE64:
5484 if(count != PPC_THREAD_STATE64_COUNT){
5485 Mach_O_error(ofile, "malformed object (count "
5486 "not PPC_THREAD_STATE64_COUNT for "
5487 "flavor number %u which is a PPC_THREAD_"
5488 "STATE64 flavor in %s command %u)",
5489 nflavor, ut->cmd == LC_UNIXTHREAD ?
5490 "LC_UNIXTHREAD" : "LC_THREAD", i);
5491 goto return_bad;
5493 cpu = (ppc_thread_state64_t *)state;
5494 if(state + sizeof(ppc_thread_state64_t) >
5495 (char *)ut + ut->cmdsize){
5496 Mach_O_error(ofile, "malformed object ("
5497 "PPC_THREAD_STATE64 in %s command %u "
5498 "extends past end of command)", ut->cmd ==
5499 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5500 "LC_THREAD", i);
5501 goto return_bad;
5503 if(swapped)
5504 swap_ppc_thread_state64_t(cpu, host_byte_sex);
5505 state += sizeof(ppc_thread_state64_t);
5506 break;
5507 default:
5508 if(swapped){
5509 Mach_O_error(ofile, "malformed object (unknown "
5510 "flavor for flavor number %u in %s command"
5511 " %u can't byte swap it)", nflavor,
5512 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5513 "LC_THREAD", i);
5514 goto return_bad;
5516 state += count * sizeof(uint32_t);
5517 break;
5519 nflavor++;
5521 break;
5523 #endif /* PPC_THREAD_STATE64_COUNT */
5524 if(cputype == CPU_TYPE_MC88000){
5525 m88k_thread_state_grf_t *cpu;
5526 m88k_thread_state_xrf_t *fpu;
5527 m88k_thread_state_user_t *user;
5528 m88110_thread_state_impl_t *spu;
5530 nflavor = 0;
5531 p = (char *)ut + ut->cmdsize;
5532 while(state < p){
5533 if(state + sizeof(uint32_t) >
5534 (char *)ut + ut->cmdsize){
5535 Mach_O_error(ofile, "malformed object (flavor in "
5536 "%s command %u extends past end of command)",
5537 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5538 "LC_THREAD", i);
5539 goto return_bad;
5541 flavor = *((uint32_t *)state);
5542 if(swapped){
5543 flavor = SWAP_INT(flavor);
5544 *((uint32_t *)state) = flavor;
5546 state += sizeof(uint32_t);
5547 if(state + sizeof(uint32_t) >
5548 (char *)ut + ut->cmdsize){
5549 Mach_O_error(ofile, "malformed object (count in "
5550 "%s command %u extends past end of command)",
5551 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5552 "LC_THREAD", i);
5553 goto return_bad;
5555 count = *((uint32_t *)state);
5556 if(swapped){
5557 count = SWAP_INT(count);
5558 *((uint32_t *)state) = count;
5560 state += sizeof(uint32_t);
5561 switch(flavor){
5562 case M88K_THREAD_STATE_GRF:
5563 if(count != M88K_THREAD_STATE_GRF_COUNT){
5564 Mach_O_error(ofile, "malformed object (count "
5565 "not M88K_THREAD_STATE_GRF_COUNT for "
5566 "flavor number %u which is a M88K_THREAD_"
5567 "STATE_GRF flavor in %s command %u)",
5568 nflavor, ut->cmd == LC_UNIXTHREAD ?
5569 "LC_UNIXTHREAD" : "LC_THREAD", i);
5570 goto return_bad;
5572 cpu = (m88k_thread_state_grf_t *)state;
5573 if(state + sizeof(m88k_thread_state_grf_t) >
5574 (char *)ut + ut->cmdsize){
5575 Mach_O_error(ofile, "malformed object ("
5576 "M88K_THREAD_STATE_GRF in %s command %u "
5577 "extends past end of command)", ut->cmd ==
5578 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5579 "LC_THREAD", i);
5580 goto return_bad;
5582 if(swapped)
5583 swap_m88k_thread_state_grf_t(cpu,
5584 host_byte_sex);
5585 state += sizeof(m88k_thread_state_grf_t);
5586 break;
5587 case M88K_THREAD_STATE_XRF:
5588 if(count != M88K_THREAD_STATE_XRF_COUNT){
5589 Mach_O_error(ofile, "malformed object (count "
5590 "not M88K_THREAD_STATE_XRF_COUNT for "
5591 "flavor number %u which is a M88K_THREAD_"
5592 "STATE_XRF flavor in %s command %u)",
5593 nflavor, ut->cmd == LC_UNIXTHREAD ?
5594 "LC_UNIXTHREAD" : "LC_THREAD", i);
5595 goto return_bad;
5597 fpu = (m88k_thread_state_xrf_t *)state;
5598 if(state + sizeof(m88k_thread_state_xrf_t) >
5599 (char *)ut + ut->cmdsize){
5600 Mach_O_error(ofile, "malformed object ("
5601 "M88K_THREAD_STATE_XRF in %s command %u "
5602 "extends past end of command)", ut->cmd ==
5603 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5604 "LC_THREAD", i);
5605 goto return_bad;
5607 if(swapped)
5608 swap_m88k_thread_state_xrf_t(fpu,
5609 host_byte_sex);
5610 state += sizeof(m88k_thread_state_xrf_t);
5611 break;
5612 case M88K_THREAD_STATE_USER:
5613 if(count != M88K_THREAD_STATE_USER_COUNT){
5614 Mach_O_error(ofile, "malformed object (count "
5615 "not M88K_THREAD_STATE_USER_COUNT for "
5616 "flavor number %u which is a M88K_THREAD_"
5617 "STATE_USER flavor in %s command %u)",
5618 nflavor, ut->cmd == LC_UNIXTHREAD ?
5619 "LC_UNIXTHREAD" : "LC_THREAD", i);
5620 goto return_bad;
5622 user = (m88k_thread_state_user_t *)state;
5623 if(state + sizeof(m88k_thread_state_user_t) >
5624 (char *)ut + ut->cmdsize){
5625 Mach_O_error(ofile, "malformed object ("
5626 "M88K_THREAD_STATE_USER in %s command %u "
5627 "extends past end of command)", ut->cmd ==
5628 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5629 "LC_THREAD", i);
5630 goto return_bad;
5632 if(swapped)
5633 swap_m88k_thread_state_user_t(user,
5634 host_byte_sex);
5635 state += sizeof(m88k_thread_state_user_t);
5636 break;
5637 case M88110_THREAD_STATE_IMPL:
5638 if(count != M88110_THREAD_STATE_IMPL_COUNT){
5639 Mach_O_error(ofile, "malformed object (count "
5640 "not M88110_THREAD_STATE_IMPL_COUNT for "
5641 "flavor number %u which is a M88110_THREAD"
5642 "_STATE_IMPL flavor in %s command %u)",
5643 nflavor, ut->cmd == LC_UNIXTHREAD ?
5644 "LC_UNIXTHREAD" : "LC_THREAD", i);
5645 goto return_bad;
5647 spu = (m88110_thread_state_impl_t *)state;
5648 if(state + sizeof(m88110_thread_state_impl_t) >
5649 (char *)ut + ut->cmdsize){
5650 Mach_O_error(ofile, "malformed object ("
5651 "M88110_THREAD_STATE_IMPL in %s command %u "
5652 "extends past end of command)", ut->cmd ==
5653 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5654 "LC_THREAD", i);
5655 goto return_bad;
5657 if(swapped)
5658 swap_m88110_thread_state_impl_t(spu,
5659 host_byte_sex);
5660 state += sizeof(m88110_thread_state_impl_t);
5661 break;
5662 default:
5663 if(swapped){
5664 Mach_O_error(ofile, "malformed object (unknown "
5665 "flavor for flavor number %u in %s command"
5666 " %u can't byte swap it)", nflavor,
5667 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5668 "LC_THREAD", i);
5669 goto return_bad;
5671 state += count * sizeof(uint32_t);
5672 break;
5674 nflavor++;
5676 break;
5678 if(cputype == CPU_TYPE_I860){
5679 #ifdef m68k
5680 struct i860_thread_state_regs *cpu;
5681 #endif
5683 nflavor = 0;
5684 p = (char *)ut + ut->cmdsize;
5685 while(state < p){
5686 if(state + sizeof(uint32_t) >
5687 (char *)ut + ut->cmdsize){
5688 Mach_O_error(ofile, "malformed object (flavor in "
5689 "%s command %u extends past end of command)",
5690 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5691 "LC_THREAD", i);
5692 goto return_bad;
5694 flavor = *((uint32_t *)state);
5695 if(swapped){
5696 flavor = SWAP_INT(flavor);
5697 *((uint32_t *)state) = flavor;
5699 state += sizeof(uint32_t);
5700 if(state + sizeof(uint32_t) >
5701 (char *)ut + ut->cmdsize){
5702 Mach_O_error(ofile, "malformed object (count in "
5703 "%s command %u extends past end of command)",
5704 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5705 "LC_THREAD", i);
5706 return(CHECK_BAD);
5708 count = *((uint32_t *)state);
5709 if(swapped){
5710 count = SWAP_INT(count);
5711 *((uint32_t *)state) = count;
5713 state += sizeof(uint32_t);
5714 switch(flavor){
5715 case I860_THREAD_STATE_REGS:
5716 #ifdef m68k
5717 if(count != I860_THREAD_STATE_REGS_COUNT){
5718 Mach_O_error(ofile, "malformed object (count "
5719 "not I860_THREAD_STATE_REGS_COUNT for "
5720 "flavor number %u which is a I860_THREAD_"
5721 "STATE_REGS flavor in %s command %u)",
5722 nflavor, ut->cmd == LC_UNIXTHREAD ?
5723 "LC_UNIXTHREAD" : "LC_THREAD", i);
5724 goto return_bad;
5726 cpu = (struct i860_thread_state_regs *)state;
5727 if(state + sizeof(struct i860_thread_state_regs) >
5728 (char *)ut + ut->cmdsize){
5729 Mach_O_error(ofile, "malformed object ("
5730 "I860_THREAD_STATE_REGS in %s command %u "
5731 "extends past end of command)", ut->cmd ==
5732 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5733 "LC_THREAD", i);
5734 goto return_bad;
5736 if(swapped)
5737 swap_i860_thread_state_regs(cpu, host_byte_sex);
5738 state += sizeof(struct i860_thread_state_regs);
5739 #else
5740 state += count * sizeof(int);
5741 #endif
5742 break;
5743 default:
5744 if(swapped){
5745 Mach_O_error(ofile, "malformed object (unknown "
5746 "flavor for flavor number %u in %s command"
5747 " %u can't byte swap it)", nflavor,
5748 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5749 "LC_THREAD", i);
5750 goto return_bad;
5752 state += count * sizeof(uint32_t);
5753 break;
5755 nflavor++;
5757 break;
5759 if(cputype == CPU_TYPE_I386){
5760 i386_thread_state_t *cpu;
5761 /* current i386 thread states */
5762 #if i386_THREAD_STATE == 1
5763 struct i386_float_state *fpu;
5764 i386_exception_state_t *exc;
5765 #endif /* i386_THREAD_STATE == 1 */
5767 /* i386 thread states on older releases */
5768 #if i386_THREAD_STATE == -1
5769 i386_thread_fpstate_t *fpu;
5770 i386_thread_exceptstate_t *exc;
5771 i386_thread_cthreadstate_t *user;
5772 #endif /* i386_THREAD_STATE == -1 */
5774 nflavor = 0;
5775 p = (char *)ut + ut->cmdsize;
5776 while(state < p){
5777 if(state + sizeof(uint32_t) >
5778 (char *)ut + ut->cmdsize){
5779 Mach_O_error(ofile, "malformed object (flavor in "
5780 "%s command %u extends past end of command)",
5781 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5782 "LC_THREAD", i);
5783 goto return_bad;
5785 flavor = *((uint32_t *)state);
5786 if(swapped){
5787 flavor = SWAP_INT(flavor);
5788 *((uint32_t *)state) = flavor;
5790 state += sizeof(uint32_t);
5791 if(state + sizeof(uint32_t) >
5792 (char *)ut + ut->cmdsize){
5793 Mach_O_error(ofile, "malformed object (count in "
5794 "%s command %u extends past end of command)",
5795 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5796 "LC_THREAD", i);
5797 goto return_bad;
5799 count = *((uint32_t *)state);
5800 if(swapped){
5801 count = SWAP_INT(count);
5802 *((uint32_t *)state) = count;
5804 state += sizeof(uint32_t);
5805 switch((int)flavor){
5806 case i386_THREAD_STATE:
5807 #if i386_THREAD_STATE == 1
5808 case -1:
5809 #endif /* i386_THREAD_STATE == 1 */
5810 /* i386 thread states on older releases */
5811 #if i386_THREAD_STATE == -1
5812 case 1:
5813 #endif /* i386_THREAD_STATE == -1 */
5814 if(count != i386_THREAD_STATE_COUNT){
5815 Mach_O_error(ofile, "malformed object (count "
5816 "not i386_THREAD_STATE_COUNT for flavor "
5817 "number %u which is a i386_THREAD_STATE "
5818 "flavor in %s command %u)", nflavor,
5819 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5820 "LC_THREAD", i);
5821 goto return_bad;
5823 cpu = (i386_thread_state_t *)state;
5824 if(state + sizeof(i386_thread_state_t) >
5825 (char *)ut + ut->cmdsize){
5826 Mach_O_error(ofile, "malformed object ("
5827 "i386_THREAD_STATE in %s command %u "
5828 "extends past end of command)", ut->cmd ==
5829 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5830 "LC_THREAD", i);
5831 goto return_bad;
5833 if(swapped)
5834 swap_i386_thread_state(cpu, host_byte_sex);
5835 state += sizeof(i386_thread_state_t);
5836 break;
5837 /* current i386 thread states */
5838 #if i386_THREAD_STATE == 1
5839 case i386_FLOAT_STATE:
5840 if(count != i386_FLOAT_STATE_COUNT){
5841 Mach_O_error(ofile, "malformed object (count "
5842 "not i386_FLOAT_STATE_COUNT for flavor "
5843 "number %u which is a i386_FLOAT_STATE "
5844 "flavor in %s command %u)", nflavor,
5845 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5846 "LC_THREAD", i);
5847 goto return_bad;
5849 fpu = (struct i386_float_state *)state;
5850 if(state + sizeof(struct i386_float_state) >
5851 (char *)ut + ut->cmdsize){
5852 Mach_O_error(ofile, "malformed object ("
5853 "i386_FLOAT_STATE in %s command %u "
5854 "extends past end of command)", ut->cmd ==
5855 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5856 "LC_THREAD", i);
5857 goto return_bad;
5859 if(swapped)
5860 swap_i386_float_state(fpu, host_byte_sex);
5861 state += sizeof(struct i386_float_state);
5862 break;
5863 case i386_EXCEPTION_STATE:
5864 if(count != I386_EXCEPTION_STATE_COUNT){
5865 Mach_O_error(ofile, "malformed object (count "
5866 "not I386_EXCEPTION_STATE_COUNT for "
5867 "flavor number %u which is a i386_"
5868 "EXCEPTION_STATE flavor in %s command %u)",
5869 nflavor,
5870 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5871 "LC_THREAD", i);
5872 goto return_bad;
5874 exc = (i386_exception_state_t *)state;
5875 if(state + sizeof(i386_exception_state_t) >
5876 (char *)ut + ut->cmdsize){
5877 Mach_O_error(ofile, "malformed object ("
5878 "i386_EXCEPTION_STATE in %s command %u "
5879 "extends past end of command)", ut->cmd ==
5880 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5881 "LC_THREAD", i);
5882 goto return_bad;
5884 if(swapped)
5885 swap_i386_exception_state(exc,host_byte_sex);
5886 state += sizeof(i386_exception_state_t);
5887 break;
5888 #endif /* i386_THREAD_STATE == 1 */
5890 /* i386 thread states on older releases */
5891 #if i386_THREAD_STATE == -1
5892 case i386_THREAD_FPSTATE:
5893 if(count != i386_THREAD_FPSTATE_COUNT){
5894 Mach_O_error(ofile, "malformed object (count "
5895 "not i386_THREAD_FPSTATE_COUNT for flavor "
5896 "number %u which is a i386_THREAD_FPSTATE "
5897 "flavor in %s command %u)", nflavor,
5898 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5899 "LC_THREAD", i);
5900 goto return_bad;
5902 fpu = (i386_thread_fpstate_t *)state;
5903 if(state + sizeof(i386_thread_fpstate_t) >
5904 (char *)ut + ut->cmdsize){
5905 Mach_O_error(ofile, "malformed object ("
5906 "i386_THREAD_FPSTATE in %s command %u "
5907 "extends past end of command)", ut->cmd ==
5908 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5909 "LC_THREAD", i);
5910 goto return_bad;
5912 if(swapped)
5913 swap_i386_thread_fpstate(fpu, host_byte_sex);
5914 state += sizeof(i386_thread_fpstate_t);
5915 break;
5916 case i386_THREAD_EXCEPTSTATE:
5917 if(count != i386_THREAD_EXCEPTSTATE_COUNT){
5918 Mach_O_error(ofile, "malformed object (count "
5919 "not i386_THREAD_EXCEPTSTATE_COUNT for "
5920 "flavor number %u which is a i386_THREAD_"
5921 "EXCEPTSTATE flavor in %s command %u)",
5922 nflavor,
5923 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5924 "LC_THREAD", i);
5925 goto return_bad;
5927 exc = (i386_thread_exceptstate_t *)state;
5928 if(state + sizeof(i386_thread_exceptstate_t) >
5929 (char *)ut + ut->cmdsize){
5930 Mach_O_error(ofile, "malformed object ("
5931 "i386_THREAD_EXCEPTSTATE in %s command %u "
5932 "extends past end of command)", ut->cmd ==
5933 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5934 "LC_THREAD", i);
5935 goto return_bad;
5937 if(swapped)
5938 swap_i386_thread_exceptstate(exc,host_byte_sex);
5939 state += sizeof(i386_thread_exceptstate_t);
5940 break;
5941 case i386_THREAD_CTHREADSTATE:
5942 if(count != i386_THREAD_CTHREADSTATE_COUNT){
5943 Mach_O_error(ofile, "malformed object (count "
5944 "not i386_THREAD_CTHREADSTATE_COUNT for "
5945 "flavor number %u which is a i386_THREAD_"
5946 "CTHREADSTATE flavor in %s command %u)",
5947 nflavor,
5948 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5949 "LC_THREAD", i);
5950 goto return_bad;
5952 user = (i386_thread_cthreadstate_t *)state;
5953 if(state + sizeof(i386_thread_cthreadstate_t) >
5954 (char *)ut + ut->cmdsize){
5955 Mach_O_error(ofile, "malformed object ("
5956 "i386_THREAD_CTHREADSTATE in %s command %u "
5957 "extends past end of command)", ut->cmd ==
5958 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5959 "LC_THREAD", i);
5960 goto return_bad;
5962 if(swapped)
5963 swap_i386_thread_cthreadstate(user,
5964 host_byte_sex);
5965 state += sizeof(i386_thread_cthreadstate_t);
5966 break;
5967 #endif /* i386_THREAD_STATE == -1 */
5968 default:
5969 if(swapped){
5970 Mach_O_error(ofile, "malformed object (unknown "
5971 "flavor for flavor number %u in %s command"
5972 " %u can't byte swap it)", nflavor,
5973 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5974 "LC_THREAD", i);
5975 goto return_bad;
5977 state += count * sizeof(uint32_t);
5978 break;
5980 nflavor++;
5982 break;
5984 #ifdef x86_THREAD_STATE64_COUNT
5985 if(cputype == CPU_TYPE_X86_64){
5986 x86_thread_state64_t *cpu;
5988 nflavor = 0;
5989 p = (char *)ut + ut->cmdsize;
5990 while(state < p){
5991 if(state + sizeof(uint32_t) >
5992 (char *)ut + ut->cmdsize){
5993 Mach_O_error(ofile, "malformed object (flavor in "
5994 "%s command %u extends past end of command)",
5995 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5996 "LC_THREAD", i);
5997 goto return_bad;
5999 flavor = *((uint32_t *)state);
6000 if(swapped){
6001 flavor = SWAP_INT(flavor);
6002 *((uint32_t *)state) = flavor;
6004 state += sizeof(uint32_t);
6005 if(state + sizeof(uint32_t) >
6006 (char *)ut + ut->cmdsize){
6007 Mach_O_error(ofile, "malformed object (count in "
6008 "%s command %u extends past end of command)",
6009 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
6010 "LC_THREAD", i);
6011 goto return_bad;
6013 count = *((uint32_t *)state);
6014 if(swapped){
6015 count = SWAP_INT(count);
6016 *((uint32_t *)state) = count;
6018 state += sizeof(uint32_t);
6019 switch(flavor){
6020 case x86_THREAD_STATE64:
6021 if(count != x86_THREAD_STATE64_COUNT){
6022 Mach_O_error(ofile, "malformed object (count "
6023 "not x86_THREAD_STATE64_COUNT for "
6024 "flavor number %u which is a x86_THREAD_"
6025 "STATE64 flavor in %s command %u)",
6026 nflavor, ut->cmd == LC_UNIXTHREAD ?
6027 "LC_UNIXTHREAD" : "LC_THREAD", i);
6028 goto return_bad;
6030 cpu = (x86_thread_state64_t *)state;
6031 if(state + sizeof(x86_thread_state64_t) >
6032 (char *)ut + ut->cmdsize){
6033 Mach_O_error(ofile, "malformed object ("
6034 "x86_THREAD_STATE64 in %s command %u "
6035 "extends past end of command)", ut->cmd ==
6036 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
6037 "LC_THREAD", i);
6038 goto return_bad;
6040 if(swapped)
6041 swap_x86_thread_state64(cpu, host_byte_sex);
6042 state += sizeof(x86_thread_state64_t);
6043 break;
6044 default:
6045 if(swapped){
6046 Mach_O_error(ofile, "malformed object (unknown "
6047 "flavor for flavor number %u in %s command"
6048 " %u can't byte swap it)", nflavor,
6049 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
6050 "LC_THREAD", i);
6051 goto return_bad;
6053 state += count * sizeof(uint32_t);
6054 break;
6056 nflavor++;
6058 break;
6060 #endif /* x86_THREAD_STATE64_COUNT */
6061 if(cputype == CPU_TYPE_HPPA){
6062 struct hp_pa_integer_thread_state *cpu;
6063 struct hp_pa_frame_thread_state *frame;
6064 struct hp_pa_fp_thread_state *fpu;
6066 nflavor = 0;
6067 p = (char *)ut + ut->cmdsize;
6068 while(state < p){
6069 if(state + sizeof(uint32_t) >
6070 (char *)ut + ut->cmdsize){
6071 Mach_O_error(ofile, "malformed object (flavor in "
6072 "%s command %u extends past end of command)",
6073 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
6074 "LC_THREAD", i);
6075 goto return_bad;
6077 flavor = *((uint32_t *)state);
6078 if(swapped){
6079 flavor = SWAP_INT(flavor);
6080 *((uint32_t *)state) = flavor;
6082 state += sizeof(uint32_t);
6083 if(state + sizeof(uint32_t) >
6084 (char *)ut + ut->cmdsize){
6085 Mach_O_error(ofile, "malformed object (count in "
6086 "%s command %u extends past end of command)",
6087 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
6088 "LC_THREAD", i);
6089 goto return_bad;
6091 count = *((uint32_t *)state);
6092 if(swapped){
6093 count = SWAP_INT(count);
6094 *((uint32_t *)state) = count;
6096 state += sizeof(uint32_t);
6097 switch(flavor){
6098 case HPPA_INTEGER_THREAD_STATE:
6099 if(count != HPPA_INTEGER_THREAD_STATE_COUNT){
6100 Mach_O_error(ofile, "malformed object (count "
6101 "not HPPA_INTEGER_THREAD_STATE_COUNT for "
6102 "flavor number %u which is a "
6103 "HPPA_INTEGER_THREAD_STATE "
6104 "flavor in %s command %u)", nflavor,
6105 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
6106 "LC_THREAD", i);
6107 goto return_bad;
6109 cpu = (struct hp_pa_integer_thread_state *)state;
6110 if(state+sizeof(struct hp_pa_integer_thread_state) >
6111 (char *)ut + ut->cmdsize){
6112 Mach_O_error(ofile, "malformed object ("
6113 "HPPA_INTEGER_THREAD_STATE in %s command "
6114 "%u extends past end of command)",
6115 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
6116 "LC_THREAD", i);
6117 goto return_bad;
6119 if(swapped)
6120 swap_hppa_integer_thread_state(cpu,
6121 host_byte_sex);
6122 state += sizeof(struct hp_pa_integer_thread_state);
6123 break;
6124 case HPPA_FRAME_THREAD_STATE:
6125 if(count != HPPA_FRAME_THREAD_STATE_COUNT){
6126 Mach_O_error(ofile, "malformed object (count "
6127 "not HPPA_FRAME_THREAD_STATE_COUNT for "
6128 "flavor number %u which is a HPPA_FRAME_"
6129 "THREAD_STATE flavor in %s command %u)",
6130 nflavor,
6131 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
6132 "LC_THREAD", i);
6133 goto return_bad;
6135 frame = (struct hp_pa_frame_thread_state *)state;
6136 if(state + sizeof(struct hp_pa_frame_thread_state) >
6137 (char *)ut + ut->cmdsize){
6138 Mach_O_error(ofile, "malformed object ("
6139 "HPPA_FRAME_THREAD_STATE in %s command "
6140 "%u extends past end of command)",
6141 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
6142 "LC_THREAD", i);
6143 goto return_bad;
6145 if(swapped)
6146 swap_hppa_frame_thread_state(frame,host_byte_sex);
6147 state += sizeof(struct hp_pa_frame_thread_state);
6148 break;
6149 case HPPA_FP_THREAD_STATE:
6150 if(count != HPPA_FP_THREAD_STATE_COUNT){
6151 Mach_O_error(ofile, "malformed object (count "
6152 "not HPPA_FP_THREAD_STATE_COUNT for "
6153 "flavor number %u which is a HPPA_FP_"
6154 "THREAD_STATE flavor in %s command %u)",
6155 nflavor,
6156 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
6157 "LC_THREAD", i);
6158 goto return_bad;
6160 fpu = (struct hp_pa_fp_thread_state *)state;
6161 if(state + sizeof(struct hp_pa_fp_thread_state) >
6162 (char *)ut + ut->cmdsize){
6163 Mach_O_error(ofile, "malformed object ("
6164 "HPPA_FP_THREAD_STATE in %s command "
6165 "%u extends past end of command)",
6166 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
6167 "LC_THREAD", i);
6168 goto return_bad;
6170 if(swapped)
6171 swap_hppa_fp_thread_state(fpu,host_byte_sex);
6172 state += sizeof(struct hp_pa_fp_thread_state);
6173 break;
6174 default:
6175 if(swapped){
6176 Mach_O_error(ofile, "malformed object (unknown "
6177 "flavor for flavor number %u in %s command"
6178 " %u can't byte swap it)", nflavor,
6179 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
6180 "LC_THREAD", i);
6181 goto return_bad;
6183 state += count * sizeof(uint32_t);
6184 break;
6186 nflavor++;
6188 break;
6190 if(cputype == CPU_TYPE_SPARC){
6191 struct sparc_thread_state_regs *cpu;
6192 struct sparc_thread_state_fpu *fpu;
6194 nflavor = 0;
6195 p = (char *)ut + ut->cmdsize;
6196 while(state < p){
6197 if(state + sizeof(uint32_t) >
6198 (char *)ut + ut->cmdsize){
6199 Mach_O_error(ofile, "malformed object (flavor in "
6200 "%s command %u extends past end of command)",
6201 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
6202 "LC_THREAD", i);
6203 goto return_bad;
6205 flavor = *((uint32_t *)state);
6206 if(swapped){
6207 flavor = SWAP_INT(flavor);
6208 *((uint32_t *)state) = flavor;
6210 state += sizeof(uint32_t);
6211 if(state + sizeof(uint32_t) >
6212 (char *)ut + ut->cmdsize){
6213 Mach_O_error(ofile, "malformed object (count in "
6214 "%s command %u extends past end of command)",
6215 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
6216 "LC_THREAD", i);
6217 goto return_bad;
6219 count = *((uint32_t *)state);
6220 if(swapped){
6221 count = SWAP_INT(count);
6222 *((uint32_t *)state) = count;
6224 state += sizeof(uint32_t);
6225 switch(flavor){
6226 case SPARC_THREAD_STATE_REGS:
6227 if(count != SPARC_THREAD_STATE_REGS_COUNT){
6228 Mach_O_error(ofile, "malformed object (count "
6229 "not SPARC_THREAD_STATE_REGS_COUNT for "
6230 "flavor number %u which is a SPARC_THREAD_"
6231 "STATE_REGS flavor in %s command %u)",
6232 nflavor, ut->cmd == LC_UNIXTHREAD ?
6233 "LC_UNIXTHREAD" : "LC_THREAD", i);
6234 goto return_bad;
6236 cpu = (struct sparc_thread_state_regs *)state;
6237 if(state + sizeof(struct sparc_thread_state_regs) >
6238 (char *)ut + ut->cmdsize){
6239 Mach_O_error(ofile, "malformed object ("
6240 "SPARC_THREAD_STATE_REGS in %s command %u "
6241 "extends past end of command)", ut->cmd ==
6242 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
6243 "LC_THREAD", i);
6244 goto return_bad;
6246 if(swapped)
6247 swap_sparc_thread_state_regs(cpu, host_byte_sex);
6248 state += sizeof(struct sparc_thread_state_regs);
6249 break;
6250 case SPARC_THREAD_STATE_FPU:
6251 if(count != SPARC_THREAD_STATE_FPU_COUNT){
6252 Mach_O_error(ofile, "malformed object (count "
6253 "not SPARC_THREAD_STATE_FPU_COUNT for "
6254 "flavor number %u which is a SPARC_THREAD_"
6255 "STATE_FPU flavor in %s command %u)",
6256 nflavor, ut->cmd == LC_UNIXTHREAD ?
6257 "LC_UNIXTHREAD" : "LC_THREAD", i);
6258 goto return_bad;
6260 fpu = (struct sparc_thread_state_fpu *)state;
6261 if(state + sizeof(struct sparc_thread_state_fpu) >
6262 (char *)ut + ut->cmdsize){
6263 Mach_O_error(ofile, "malformed object ("
6264 "SPARC_THREAD_STATE_FPU in %s command %u "
6265 "extends past end of command)", ut->cmd ==
6266 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
6267 "LC_THREAD", i);
6268 goto return_bad;
6270 if(swapped)
6271 swap_sparc_thread_state_fpu(fpu, host_byte_sex);
6272 state += sizeof(struct sparc_thread_state_fpu);
6273 break;
6274 default:
6275 if(swapped){
6276 Mach_O_error(ofile, "malformed object (unknown "
6277 "flavor for flavor number %u in %s command"
6278 " %u can't byte swap it)", nflavor,
6279 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
6280 "LC_THREAD", i);
6281 goto return_bad;
6283 state += count * sizeof(uint32_t);
6284 break;
6286 nflavor++;
6288 break;
6290 if(cputype == CPU_TYPE_ARM){
6291 arm_thread_state_t *cpu;
6293 nflavor = 0;
6294 p = (char *)ut + ut->cmdsize;
6295 while(state < p){
6296 if(state + sizeof(uint32_t) >
6297 (char *)ut + ut->cmdsize){
6298 Mach_O_error(ofile, "malformed object (flavor in "
6299 "%s command %u extends past end of command)",
6300 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
6301 "LC_THREAD", i);
6302 goto return_bad;
6304 flavor = *((uint32_t *)state);
6305 if(swapped){
6306 flavor = SWAP_INT(flavor);
6307 *((uint32_t *)state) = flavor;
6309 state += sizeof(uint32_t);
6310 if(state + sizeof(uint32_t) >
6311 (char *)ut + ut->cmdsize){
6312 Mach_O_error(ofile, "malformed object (count in "
6313 "%s command %u extends past end of command)",
6314 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
6315 "LC_THREAD", i);
6316 goto return_bad;
6318 count = *((uint32_t *)state);
6319 if(swapped){
6320 count = SWAP_INT(count);
6321 *((uint32_t *)state) = count;
6323 state += sizeof(uint32_t);
6324 switch(flavor){
6325 case ARM_THREAD_STATE:
6326 if(count != ARM_THREAD_STATE_COUNT){
6327 Mach_O_error(ofile, "malformed object (count "
6328 "not ARM_THREAD_STATE_COUNT for "
6329 "flavor number %u which is a ARM_THREAD_"
6330 "STATE flavor in %s command %u)",
6331 nflavor, ut->cmd == LC_UNIXTHREAD ?
6332 "LC_UNIXTHREAD" : "LC_THREAD", i);
6333 goto return_bad;
6335 cpu = (arm_thread_state_t *)state;
6336 if(state + sizeof(arm_thread_state_t) >
6337 (char *)ut + ut->cmdsize){
6338 Mach_O_error(ofile, "malformed object ("
6339 "ARM_THREAD_STATE in %s command %u "
6340 "extends past end of command)", ut->cmd ==
6341 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
6342 "LC_THREAD", i);
6343 goto return_bad;
6345 if(swapped)
6346 swap_arm_thread_state_t(cpu, host_byte_sex);
6347 state += sizeof(arm_thread_state_t);
6348 break;
6349 default:
6350 if(swapped){
6351 Mach_O_error(ofile, "malformed object (unknown "
6352 "flavor for flavor number %u in %s command"
6353 " %u can't byte swap it)", nflavor,
6354 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
6355 "LC_THREAD", i);
6356 goto return_bad;
6358 state += count * sizeof(uint32_t);
6359 break;
6361 nflavor++;
6363 break;
6365 if(cputype == CPU_TYPE_ARM64){
6366 arm_thread_state64_t *cpu;
6368 nflavor = 0;
6369 p = (char *)ut + ut->cmdsize;
6370 while(state < p){
6371 if(state + sizeof(uint32_t) >
6372 (char *)ut + ut->cmdsize){
6373 Mach_O_error(ofile, "malformed object (flavor in "
6374 "%s command %u extends past end of command)",
6375 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
6376 "LC_THREAD", i);
6377 goto return_bad;
6379 flavor = *((uint32_t *)state);
6380 if(swapped){
6381 flavor = SWAP_INT(flavor);
6382 *((uint32_t *)state) = flavor;
6384 state += sizeof(uint32_t);
6385 if(state + sizeof(uint32_t) >
6386 (char *)ut + ut->cmdsize){
6387 Mach_O_error(ofile, "malformed object (count in "
6388 "%s command %u extends past end of command)",
6389 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
6390 "LC_THREAD", i);
6391 goto return_bad;
6393 count = *((uint32_t *)state);
6394 if(swapped){
6395 count = SWAP_INT(count);
6396 *((uint32_t *)state) = count;
6398 state += sizeof(uint32_t);
6399 switch(flavor){
6400 case ARM_THREAD_STATE64:
6401 if(count != ARM_THREAD_STATE64_COUNT){
6402 Mach_O_error(ofile, "malformed object (count "
6403 "not ARM_THREAD_STATE64_COUNT for "
6404 "flavor number %u which is a ARM_THREAD_"
6405 "STATE64 flavor in %s command %u)",
6406 nflavor, ut->cmd == LC_UNIXTHREAD ?
6407 "LC_UNIXTHREAD" : "LC_THREAD", i);
6408 goto return_bad;
6410 cpu = (arm_thread_state64_t *)state;
6411 if(state + sizeof(arm_thread_state64_t) >
6412 (char *)ut + ut->cmdsize){
6413 Mach_O_error(ofile, "malformed object ("
6414 "ARM_THREAD_STATE64 in %s command %u "
6415 "extends past end of command)", ut->cmd ==
6416 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
6417 "LC_THREAD", i);
6418 goto return_bad;
6420 if(swapped)
6421 swap_arm_thread_state64_t(cpu, host_byte_sex);
6422 state += sizeof(arm_thread_state64_t);
6423 break;
6424 default:
6425 if(swapped){
6426 Mach_O_error(ofile, "malformed object (unknown "
6427 "flavor for flavor number %u in %s command"
6428 " %u can't byte swap it)", nflavor,
6429 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
6430 "LC_THREAD", i);
6431 goto return_bad;
6433 state += count * sizeof(uint32_t);
6434 break;
6436 nflavor++;
6438 break;
6440 if(swapped){
6441 Mach_O_error(ofile, "malformed object (unknown cputype and "
6442 "cpusubtype of object and can't byte swap and check %s "
6443 "command %u)", ut->cmd == LC_UNIXTHREAD ?
6444 "LC_UNIXTHREAD" : "LC_THREAD", i);
6445 goto return_bad;
6447 break;
6448 case LC_MAIN:
6449 if(l.cmdsize < sizeof(struct entry_point_command)){
6450 Mach_O_error(ofile, "malformed object (LC_MAIN cmdsize "
6451 "too small) in command %u", i);
6452 goto return_bad;
6454 ep = (struct entry_point_command *)lc;
6455 if(swapped)
6456 swap_entry_point_command(ep, host_byte_sex);
6458 * If we really wanted we could check that the entryoff field
6459 * really is an offset into the __TEXT segment. But since it
6460 * is not used here, we won't needlessly check it.
6462 break;
6463 case LC_SOURCE_VERSION:
6464 if(l.cmdsize < sizeof(struct source_version_command)){
6465 Mach_O_error(ofile, "malformed object (LC_SOURCE_VERSION "
6466 "cmdsize too small) in command %u", i);
6467 goto return_bad;
6469 sv = (struct source_version_command *)lc;
6470 if(swapped)
6471 swap_source_version_command(sv, host_byte_sex);
6472 case LC_IDENT:
6473 if(l.cmdsize < sizeof(struct ident_command)){
6474 Mach_O_error(ofile, "malformed object (LC_IDENT cmdsize "
6475 "too small) in command %u", i);
6476 goto return_bad;
6478 id = (struct ident_command *)lc;
6479 if(swapped)
6480 swap_ident_command(id, host_byte_sex);
6482 * Note the cmdsize field if the LC_IDENT command was checked
6483 * as part of checking all load commands cmdsize field before
6484 * the switch statement on the cmd field of the load command.
6486 break;
6487 case LC_RPATH:
6488 if(l.cmdsize < sizeof(struct rpath_command)){
6489 Mach_O_error(ofile, "malformed object (LC_RPATH: cmdsize "
6490 "too small) in command %u", i);
6491 goto return_bad;
6493 rpath = (struct rpath_command *)lc;
6494 if(swapped)
6495 swap_rpath_command(rpath, host_byte_sex);
6496 if(rpath->cmdsize < sizeof(struct rpath_command)){
6497 Mach_O_error(ofile, "malformed object (LC_RPATH command "
6498 "%u has too small cmdsize field)", i);
6499 goto return_bad;
6501 if(rpath->path.offset >= rpath->cmdsize){
6502 Mach_O_error(ofile, "truncated or malformed object (path."
6503 "offset field of LC_RPATH command %u extends past the "
6504 "end of the file)", i);
6505 goto return_bad;
6507 break;
6509 #ifndef OFI
6510 default:
6511 Mach_O_error(ofile, "malformed object (unknown load command "
6512 "%u)", i);
6513 goto return_bad;
6514 #endif /* !defined(OFI) */
6517 lc = (struct load_command *)((char *)lc + l.cmdsize);
6518 /* check that next load command does not extends past the end */
6519 if((char *)lc > (char *)load_commands + sizeofcmds){
6520 Mach_O_error(ofile, "truncated or malformed object (load "
6521 "command %u extends past the end of the file)",
6522 i + 1);
6523 goto return_bad;
6526 if(st == NULL){
6527 if(dyst != NULL){
6528 Mach_O_error(ofile, "truncated or malformed object (contains "
6529 "LC_DYSYMTAB load command without a LC_SYMTAB load command)");
6530 goto return_bad;
6533 else{
6534 if(dyst != NULL){
6535 if(dyst->nlocalsym != 0 &&
6536 dyst->ilocalsym > st->nsyms){
6537 Mach_O_error(ofile, "truncated or malformed object "
6538 "(ilocalsym in LC_DYSYMTAB load command extends past "
6539 "the end of the symbol table)");
6540 goto return_bad;
6542 big_size = dyst->ilocalsym;
6543 big_size += dyst->nlocalsym;
6544 if(dyst->nlocalsym != 0 && big_size > st->nsyms){
6545 Mach_O_error(ofile, "truncated or malformed object "
6546 "(ilocalsym plus nlocalsym in LC_DYSYMTAB load command "
6547 "extends past the end of the symbol table)");
6548 goto return_bad;
6551 if(dyst->nextdefsym != 0 &&
6552 dyst->iextdefsym > st->nsyms){
6553 Mach_O_error(ofile, "truncated or malformed object "
6554 "(iextdefsym in LC_DYSYMTAB load command extends past "
6555 "the end of the symbol table)");
6556 goto return_bad;
6558 big_size = dyst->iextdefsym;
6559 big_size += dyst->nextdefsym;
6560 if(dyst->nextdefsym != 0 && big_size > st->nsyms){
6561 Mach_O_error(ofile, "truncated or malformed object "
6562 "(iextdefsym plus nextdefsym in LC_DYSYMTAB load "
6563 "command extends past the end of the symbol table)");
6564 goto return_bad;
6567 if(dyst->nundefsym != 0 &&
6568 dyst->iundefsym > st->nsyms){
6569 Mach_O_error(ofile, "truncated or malformed object "
6570 "(iundefsym in LC_DYSYMTAB load command extends past "
6571 "the end of the symbol table)");
6572 goto return_bad;
6574 big_size = dyst->iundefsym;
6575 big_size += dyst->nundefsym;
6576 if(dyst->nundefsym != 0 && big_size > st->nsyms){
6577 Mach_O_error(ofile, "truncated or malformed object "
6578 "(iundefsym plus nundefsym in LC_DYSYMTAB load command "
6579 "extends past the end of the symbol table)");
6580 goto return_bad;
6582 if(rc != NULL){
6583 if(rc->init_module > dyst->nmodtab){
6584 Mach_O_error(ofile, "malformed object (init_module in "
6585 "LC_ROUTINES load command extends past the "
6586 "end of the module table)");
6587 goto return_bad;
6590 if(rc64 != NULL){
6591 if(rc64->init_module > dyst->nmodtab){
6592 Mach_O_error(ofile, "malformed object (init_module in "
6593 "LC_ROUTINES_64 load command extends past the "
6594 "end of the module table)");
6595 goto return_bad;
6598 if(hints != NULL){
6599 if(hints->nhints != dyst->nundefsym){
6600 Mach_O_error(ofile, "malformed object (nhints in "
6601 "LC_TWOLEVEL_HINTS load command not the same as "
6602 "nundefsym in LC_DYSYMTAB load command)");
6603 goto return_bad;
6608 /* check for an inconsistent size of the load commands */
6609 if((char *)load_commands + sizeofcmds != (char *)lc){
6610 Mach_O_error(ofile, "malformed object (inconsistent sizeofcmds "
6611 "field in mach header)");
6612 goto return_bad;
6616 * Mark this ofile so we know its headers have been swapped. We do this
6617 * in case we don't process it the first time so we can swap them back
6618 * in case we loop back to it in a fat file to process it later.
6620 if(swapped == TRUE)
6621 ofile->headers_swapped = TRUE;
6623 /* looks good return ok */
6624 free_elements(&elements);
6625 return(CHECK_GOOD);
6627 return_bad:
6628 free_elements(&elements);
6629 return(CHECK_BAD);
6630 #endif /* OTOOL */
6634 * swap_back_Mach_O() is called after the ofile has been processed to swap back
6635 * the mach header and load commands if check_Mach_O() above swapped them.
6637 static
6638 void
6639 swap_back_Mach_O(
6640 struct ofile *ofile)
6642 if(ofile->headers_swapped == TRUE){
6643 ofile->headers_swapped = FALSE;
6644 if(ofile->mh != NULL)
6645 swap_object_headers(ofile->mh, ofile->load_commands);
6646 else if(ofile->mh64 != NULL)
6647 swap_object_headers(ofile->mh64, ofile->load_commands);
6651 #ifndef OTOOL
6653 * check_overlaping_element() checks that the element in the ofile described by
6654 * offset, size and name does not overlap in list of elements in head. If it
6655 * does CHECK_BAD is returned and an error message is generated. If it doesn't
6656 * then an element is added in the ordered list and CHECK_GOOD is returned
6658 static
6659 enum check_type
6660 check_overlaping_element(
6661 struct ofile *ofile,
6662 struct element *head,
6663 uint32_t offset,
6664 uint32_t size,
6665 char *name)
6667 struct element *e, *p, *n;
6669 if(size == 0)
6670 return(CHECK_GOOD);
6672 if(head->next == NULL){
6673 n = allocate(sizeof(struct element));
6674 n->offset = offset;
6675 n->size = size;
6676 n->name = name;
6677 n->next = NULL;
6678 head->next = n;
6679 return(CHECK_GOOD);
6682 p = NULL;
6683 e = head;
6684 while(e->next != NULL){
6685 p = e;
6686 e = e->next;
6687 if((offset >= e->offset &&
6688 offset < e->offset + e->size) ||
6689 (offset + size > e->offset &&
6690 offset + size < e->offset + e->size) ||
6691 (offset <= e->offset &&
6692 offset + size >= e->offset + e->size)){
6693 Mach_O_error(ofile, "malformed object (%s at offset %u with a "
6694 "size of %u, overlaps %s at offset %u with a size of %u)",
6695 name, offset, size, e->name, e->offset, e->size);
6696 return(CHECK_BAD);
6698 if(e->next != NULL && offset + size <= e->next->offset){
6699 n = allocate(sizeof(struct element));
6700 n->offset = offset;
6701 n->size = size;
6702 n->name = name;
6703 n->next = e;
6704 p->next = n;
6705 return(CHECK_GOOD);
6708 n = allocate(sizeof(struct element));
6709 n->offset = offset;
6710 n->size = size;
6711 n->name = name;
6712 n->next = NULL;
6713 e->next = n;
6714 return(CHECK_GOOD);
6718 * free_elements() frees the list of elements on the list head.
6720 static
6721 void
6722 free_elements(
6723 struct element *head)
6725 struct element *e, *e_next;
6727 e = head->next;
6728 while(e != NULL){
6729 e_next = e->next;
6730 free(e);
6731 e = e_next;
6734 #endif /* !defined(OTOOL) */
6737 * check_dylib_module() checks the object file's dylib_module as referenced
6738 * by the dylib_module field in the ofile for correctness.
6740 static
6741 enum check_type
6742 check_dylib_module(
6743 struct ofile *ofile,
6744 struct symtab_command *st,
6745 struct dysymtab_command *dyst,
6746 char *strings,
6747 uint32_t module_index)
6749 #ifdef OTOOL
6750 return(CHECK_GOOD);
6751 #else /* !defined OTOOL */
6752 uint32_t i;
6753 enum byte_sex host_byte_sex;
6754 enum bool swapped;
6755 struct dylib_module m;
6756 struct dylib_module_64 m64;
6757 uint32_t module_name, nextdefsym, iextdefsym, nlocalsym, ilocalsym, nrefsym;
6758 uint32_t irefsym, nextrel, iextrel;
6760 host_byte_sex = get_host_byte_sex();
6761 swapped = (enum bool)(host_byte_sex != ofile->object_byte_sex);
6762 if(ofile->mh != NULL){
6763 m = *ofile->dylib_module;
6764 if(swapped)
6765 swap_dylib_module(&m, 1, host_byte_sex);
6766 module_name = m.module_name;
6767 nextdefsym = m.nextdefsym;
6768 iextdefsym = m.iextdefsym;
6769 nlocalsym = m.nlocalsym;
6770 ilocalsym = m.ilocalsym;
6771 nrefsym = m.nrefsym;
6772 irefsym = m.irefsym;
6773 nextrel = m.nextrel;
6774 iextrel = m.iextrel;
6776 else{
6777 m64 = *ofile->dylib_module64;
6778 if(swapped)
6779 swap_dylib_module_64(&m64, 1, host_byte_sex);
6780 module_name = m64.module_name;
6781 nextdefsym = m64.nextdefsym;
6782 iextdefsym = m64.iextdefsym;
6783 nlocalsym = m64.nlocalsym;
6784 ilocalsym = m64.ilocalsym;
6785 nrefsym = m64.nrefsym;
6786 irefsym = m64.irefsym;
6787 nextrel = m64.nextrel;
6788 iextrel = m64.iextrel;
6791 if(module_name > st->strsize){
6792 Mach_O_error(ofile, "truncated or malformed object (module_name "
6793 "of module table entry %u past the end of the string table)",
6794 module_index);
6795 return(CHECK_BAD);
6797 for(i = module_name; i < st->strsize && strings[i] != '\0'; i++)
6799 if(i >= st->strsize){
6800 Mach_O_error(ofile, "truncated or malformed object (module_name "
6801 "of module table entry %u extends past the end of the string "
6802 "table)", module_index);
6803 return(CHECK_BAD);
6806 if(nextdefsym != 0){
6807 if(iextdefsym > st->nsyms){
6808 Mach_O_error(ofile, "truncated or malformed object (iextdefsym "
6809 "field of module table entry %u past the end of the "
6810 "symbol table", module_index);
6811 return(CHECK_BAD);
6813 if(iextdefsym + nextdefsym > st->nsyms){
6814 Mach_O_error(ofile, "truncated or malformed object (iextdefsym "
6815 "field of module table entry %u plus nextdefsym field "
6816 "extends past the end of the symbol table", module_index);
6817 return(CHECK_BAD);
6820 if(nlocalsym != 0){
6821 if(ilocalsym > st->nsyms){
6822 Mach_O_error(ofile, "truncated or malformed object (ilocalsym "
6823 "field of module table entry %u past the end of the "
6824 "symbol table", module_index);
6825 return(CHECK_BAD);
6827 if(ilocalsym + nlocalsym > st->nsyms){
6828 Mach_O_error(ofile, "truncated or malformed object (ilocalsym "
6829 "field of module table entry %u plus nlocalsym field "
6830 "extends past the end of the symbol table", module_index);
6831 return(CHECK_BAD);
6834 if(nrefsym != 0){
6835 if(irefsym > dyst->nextrefsyms){
6836 Mach_O_error(ofile, "truncated or malformed object (irefsym "
6837 "field of module table entry %u past the end of the "
6838 "reference table", module_index);
6839 return(CHECK_BAD);
6841 if(irefsym + nrefsym > dyst->nextrefsyms){
6842 Mach_O_error(ofile, "truncated or malformed object (irefsym "
6843 "field of module table entry %u plus nrefsym field "
6844 "extends past the end of the reference table",module_index);
6845 return(CHECK_BAD);
6848 if(nextrel != 0){
6849 if(iextrel > dyst->extreloff){
6850 Mach_O_error(ofile, "truncated or malformed object (iextrel "
6851 "field of module table entry %u past the end of the "
6852 "external relocation enrties", module_index);
6853 return(CHECK_BAD);
6855 if(iextrel + nextrel > dyst->extreloff){
6856 Mach_O_error(ofile, "truncated or malformed object (iextrel "
6857 "field of module table entry %u plus nextrel field "
6858 "extends past the end of the external relocation enrties",
6859 module_index);
6860 return(CHECK_BAD);
6863 return(CHECK_GOOD);
6864 #endif /* OTOOL */
6867 __private_extern__
6868 uint32_t
6869 size_ar_name(
6870 const struct ar_hdr *ar_hdr)
6872 int32_t i;
6874 i = sizeof(ar_hdr->ar_name) - 1;
6875 if(ar_hdr->ar_name[i] == ' '){
6877 if(ar_hdr->ar_name[i] != ' ')
6878 break;
6879 i--;
6880 }while(i > 0);
6883 * For System V archives names ends in a '/' which are not part of the
6884 * name. Except for the table of contents member named "/" and archive
6885 * string table member name which has the name "//".
6887 if(i > 1 && ar_hdr->ar_name[i] == '/')
6888 i--;
6889 return(i + 1);
6891 #endif /* !defined(RLD) */