github.com -> github.io
[striptease.git] / libstuff / ofile.c
blob6b34051f52f5ae6514ad36699370b32bc2b6d29e
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 #undef MACHINE_THREAD_STATE /* need to undef these to avoid warnings */
64 #undef MACHINE_THREAD_STATE_COUNT
65 #undef THREAD_STATE_NONE
66 #undef VALID_THREAD_STATE_FLAVOR
67 #import <mach/arm/thread_status.h>
68 #include <mach-o/nlist.h>
69 #include <mach-o/reloc.h>
70 #include "stuff/bool.h"
71 #ifdef OFI
72 #include <mach-o/dyld.h>
73 #else
74 #include "stuff/lto.h"
75 #endif
76 #include "stuff/bytesex.h"
77 #include "stuff/arch.h"
78 #include "stuff/rnd.h"
79 #include "stuff/errors.h"
80 #include "stuff/allocate.h"
81 #include "stuff/ofile.h"
82 #include "stuff/print.h"
84 #ifdef OTOOL
85 #undef ALIGNMENT_CHECKS
86 #include "otool.h"
87 #include "ofile_print.h"
88 static enum bool otool_first_ofile_map = TRUE;
89 #else /* !define(OTOOL) */
91 #if (!defined(m68k) && !defined(__i386__) && !defined(__x86_64__) && !defined(__ppc__) && !defined(__arm__))
92 #define ALIGNMENT_CHECKS_ARCHIVE_64_BIT
93 static enum bool archive_64_bit_align_warning = FALSE;
94 #endif /* (!defined(m68k) && !defined(__i386__) && !defined(__x86_64__) && !defined(__ppc__) && !defined(__arm__)) */
96 #endif /* OTOOL */
98 /* <mach/loader.h> */
99 /* The maximum section alignment allowed to be specified, as a power of two */
100 #define MAXSECTALIGN 15 /* 2**15 or 0x8000 */
102 enum check_type {
103 CHECK_BAD,
104 CHECK_GOOD
107 #ifndef OTOOL
108 struct element {
109 uint32_t offset;
110 uint32_t size;
111 char *name;
112 struct element *next;
114 #endif /* !defined(OTOOL) */
116 static enum bool ofile_specific_arch(
117 struct ofile *ofile,
118 uint32_t narch);
119 static enum check_type check_fat(
120 struct ofile *ofile);
121 static enum check_type check_fat_object_in_archive(
122 struct ofile *ofile);
123 static enum check_type check_archive(
124 struct ofile *ofile,
125 enum bool archives_with_fat_objects);
126 static enum check_type check_extend_format_1(
127 struct ofile *ofile,
128 struct ar_hdr *ar_hdr,
129 uint32_t size_left,
130 uint32_t *member_name_size);
131 static enum check_type check_archive_toc(
132 struct ofile *ofile);
133 static enum check_type check_Mach_O(
134 struct ofile *ofile);
135 static void swap_back_Mach_O(
136 struct ofile *ofile);
137 #ifndef OTOOL
138 static enum check_type check_overlaping_element(
139 struct ofile *ofile,
140 struct element *head,
141 uint32_t offset,
142 uint32_t size,
143 char *name);
144 static void free_elements(
145 struct element *head);
146 #endif /* !defined(OTOOL) */
147 static enum check_type check_dylib_module(
148 struct ofile *ofile,
149 struct symtab_command *st,
150 struct dysymtab_command *dyst,
151 char *strings,
152 uint32_t module_index);
154 #ifndef OTOOL
155 #if defined(ALIGNMENT_CHECKS) || defined(ALIGNMENT_CHECKS_ARCHIVE_64_BIT)
156 static
157 void
158 temporary_archive_member_warning(
159 struct ofile *ofile,
160 const char *format, ...)
162 va_list ap;
164 va_start(ap, format);
165 if(ofile->file_type == OFILE_FAT){
166 print("%s: for architecture %s archive member: %s(%.*s) ",
167 progname, ofile->arch_flag.name, ofile->file_name,
168 (int)ofile->member_name_size, ofile->member_name);
170 else{
171 print("%s: archive member: %s(%.*s) ", progname, ofile->file_name,
172 (int)ofile->member_name_size, ofile->member_name);
174 vprint(format, ap);
175 print("\n");
176 va_end(ap);
178 #endif /* defined(ALIGNMENT_CHECKS) */
179 #endif /* !defined(OTOOL) */
181 #ifndef OFI
183 * ofile_process() processes the specified file name can calls the routine
184 * processor on the ofiles in it. arch_flags is an array of architectures
185 * containing narch_flags which are the only architectures to process if
186 * narch_flags is non-zero. If all_archs is TRUE then all architectures of
187 * the specified file are processed. The specified file name can be of the
188 * form "archive(member)" which is taken to mean that member in that archive
189 * (or that module of a dynamic library if dylib_flat is not FALSE).
190 * For each ofile that is to be processed the routine processor is called with
191 * the corresponding ofile struct, the arch_name pass to it is either NULL or
192 * an architecture name (when it should be printed or show by processor) and
193 * cookie is the same value as passed to ofile_process.
195 __private_extern__
196 void
197 ofile_process(
198 char *name,
199 struct arch_flag *arch_flags,
200 uint32_t narch_flags,
201 enum bool all_archs,
202 enum bool process_non_objects,
203 enum bool dylib_flat,
204 enum bool use_member_syntax,
205 void (*processor)(struct ofile *ofile, char *arch_name, void *cookie),
206 void *cookie)
208 char *member_name, *p, *arch_name;
209 uint32_t len, i;
210 struct ofile ofile;
211 enum bool flag, hostflag, arch_found, family;
212 struct arch_flag host_arch_flag;
213 const struct arch_flag *family_arch_flag;
216 * If use_member_syntax is TRUE look for a name of the form
217 * "archive(member)" which is to mean a member in that archive (the
218 * member name must be at least one character long to be recognized as
219 * this form).
221 member_name = NULL;
222 if(use_member_syntax == TRUE){
223 len = strlen(name);
224 if(len >= 4 && name[len-1] == ')'){
225 p = strrchr(name, '(');
226 if(p != NULL && p != name){
227 member_name = p+1;
228 *p = '\0';
229 name[len-1] = '\0';
234 #ifdef OTOOL
235 otool_first_ofile_map = TRUE;
236 #endif /* OTOOL */
237 if(ofile_map(name, NULL, NULL, &ofile, FALSE) == FALSE)
238 return;
239 #ifdef OTOOL
240 otool_first_ofile_map = FALSE;
241 #endif /* OTOOL */
243 if(ofile.file_type == OFILE_FAT){
245 * This is a fat file so see if a list of architecture is
246 * specified and process only those.
248 if(all_archs == FALSE && narch_flags != 0){
249 for(i = 0; i < narch_flags; i++){
250 if(ofile_first_arch(&ofile) == FALSE){
251 ofile_unmap(&ofile);
252 return;
254 arch_found = FALSE;
255 family = FALSE;
256 family_arch_flag =
257 get_arch_family_from_cputype(arch_flags[i].cputype);
258 if(family_arch_flag != NULL)
259 family = (enum bool)
260 ((family_arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) ==
261 (arch_flags[i].cpusubtype & ~CPU_SUBTYPE_MASK));
262 if(narch_flags != 1)
263 arch_name = ofile.arch_flag.name;
264 else
265 arch_name = NULL;
267 if(ofile.arch_flag.cputype ==
268 arch_flags[i].cputype &&
269 ((ofile.arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK) ==
270 (arch_flags[i].cpusubtype & ~CPU_SUBTYPE_MASK) ||
271 family == TRUE)){
272 arch_found = TRUE;
273 if(ofile.arch_type == OFILE_ARCHIVE){
274 if(member_name != NULL){
275 if(ofile_specific_member(member_name,
276 &ofile) == TRUE){
277 processor(&ofile, arch_name, cookie);
278 if(ofile.headers_swapped == TRUE)
279 swap_back_Mach_O(&ofile);
282 else{
283 /* loop through archive */
284 #ifdef OTOOL
285 printf("Archive : %s", ofile.file_name);
286 if(arch_name != NULL)
287 printf(" (architecture %s)",
288 arch_name);
289 printf("\n");
290 #endif /* OTOOL */
291 if(ofile_first_member(&ofile) == TRUE){
292 flag = FALSE;
294 if(process_non_objects == TRUE ||
295 ofile.member_type ==
296 OFILE_Mach_O){
297 processor(&ofile, arch_name,
298 cookie);
299 if(ofile.headers_swapped ==TRUE)
300 swap_back_Mach_O(&ofile);
301 flag = TRUE;
303 }while(ofile_next_member(&ofile) ==
304 TRUE);
305 if(flag == FALSE){
306 error("for architecture: %s "
307 "archive: %s contains no "
308 "members that are object "
309 "files", ofile.arch_flag.name,
310 ofile.file_name);
313 else{
314 error("for architecture: %s archive: "
315 "%s contains no members",
316 ofile.arch_flag.name,
317 ofile.file_name);
321 else if(process_non_objects == TRUE ||
322 ofile.arch_type == OFILE_Mach_O){
323 if(ofile.arch_type == OFILE_Mach_O &&
324 (ofile.mh_filetype == MH_DYLIB ||
325 ofile.mh_filetype == MH_DYLIB_STUB)){
326 if(dylib_flat == TRUE){
327 processor(&ofile, arch_name, cookie);
328 if(ofile.headers_swapped == TRUE)
329 swap_back_Mach_O(&ofile);
331 else{
332 if(member_name != NULL){
333 if(ofile_specific_module(
334 member_name, &ofile) == TRUE){
335 processor(&ofile, arch_name,
336 cookie);
337 if(ofile.headers_swapped ==TRUE)
338 swap_back_Mach_O(&ofile);
341 else{
342 /*loop through the dynamic library*/
343 if(ofile_first_module(&ofile)){
345 processor(&ofile, arch_name,
346 cookie);
347 }while(ofile_next_module(
348 &ofile));
350 else{
351 processor(&ofile, arch_name,
352 cookie);
356 if(ofile.headers_swapped == TRUE)
357 swap_back_Mach_O(&ofile);
359 else{
360 if(member_name != NULL)
361 error("for architecture: %s file: %s "
362 "is not an archive and thus does "
363 "not contain member: %s",
364 ofile.arch_flag.name,
365 ofile.file_name,
366 member_name);
367 else{
368 processor(&ofile, arch_name, cookie);
369 if(ofile.headers_swapped == TRUE)
370 swap_back_Mach_O(&ofile);
374 else if(ofile.arch_type == OFILE_UNKNOWN){
375 error("for architecture: %s file: %s is "
376 "not an object file",
377 ofile.arch_flag.name,ofile.file_name);
379 if(ofile.headers_swapped == TRUE)
380 swap_back_Mach_O(&ofile);
381 break;
383 else{
384 if(ofile.headers_swapped == TRUE)
385 swap_back_Mach_O(&ofile);
387 }while(ofile_next_arch(&ofile) == TRUE);
388 if(arch_found == FALSE)
389 error("file: %s does not contain architecture: %s",
390 ofile.file_name, arch_flags[i].name);
392 ofile_unmap(&ofile);
393 return;
397 * This is a fat file and no architectures has been specified
398 * so if it contains the host architecture process only that
399 * architecture but if not process all architectures
400 * specified.
402 if(all_archs == FALSE){
403 (void)get_arch_from_host(&host_arch_flag, NULL);
404 #if __LP64__
406 * If runing as a 64-bit binary and on an Intel x86 host
407 * default to 64-bit.
409 if(host_arch_flag.cputype == CPU_TYPE_I386)
410 host_arch_flag =
411 *get_arch_family_from_cputype(CPU_TYPE_X86_64);
412 #endif /* __LP64__ */
413 hostflag = FALSE;
415 family = FALSE;
416 family_arch_flag =
417 get_arch_family_from_cputype(host_arch_flag.cputype);
418 if(family_arch_flag != NULL)
419 family = (enum bool)
420 ((family_arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) ==
421 (host_arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK));
423 ofile_unmap(&ofile);
424 if(ofile_map(name, NULL, NULL, &ofile, FALSE) == FALSE)
425 return;
426 if(ofile_first_arch(&ofile) == FALSE){
427 ofile_unmap(&ofile);
428 return;
431 if(ofile.arch_flag.cputype ==
432 host_arch_flag.cputype &&
433 ((ofile.arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK) ==
434 (host_arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK) ||
435 family == TRUE)){
436 hostflag = TRUE;
437 if(ofile.arch_type == OFILE_ARCHIVE){
438 if(member_name != NULL){
439 if(ofile_specific_member(member_name,
440 &ofile) == TRUE){
441 processor(&ofile, NULL, cookie);
442 if(ofile.headers_swapped == TRUE)
443 swap_back_Mach_O(&ofile);
446 else{
447 /* loop through archive */
448 #ifdef OTOOL
449 printf("Archive : %s\n", ofile.file_name);
450 #endif /* OTOOL */
451 if(ofile_first_member(&ofile) == TRUE){
452 flag = FALSE;
454 if(process_non_objects == TRUE ||
455 ofile.member_type == OFILE_Mach_O){
456 processor(&ofile, NULL, cookie);
457 if(ofile.headers_swapped == TRUE)
458 swap_back_Mach_O(&ofile);
459 flag = TRUE;
461 }while(ofile_next_member(&ofile) ==
462 TRUE);
463 if(flag == FALSE){
464 error("archive: %s contains no "
465 "members that are object "
466 "files", ofile.file_name);
469 else{
470 error("archive: %s contains no "
471 "members", ofile.file_name);
475 else if(process_non_objects == TRUE ||
476 ofile.arch_type == OFILE_Mach_O){
477 if(ofile.arch_type == OFILE_Mach_O &&
478 (ofile.mh_filetype == MH_DYLIB ||
479 ofile.mh_filetype == MH_DYLIB_STUB)){
480 if(dylib_flat == TRUE){
481 processor(&ofile, NULL, cookie);
483 else{
484 if(member_name != NULL){
485 if(ofile_specific_module(member_name,
486 &ofile) == TRUE)
487 processor(&ofile, NULL, cookie);
489 else{
490 /* loop through the dynamic library */
491 if(ofile_first_module(&ofile) == TRUE){
493 processor(&ofile, NULL, cookie);
494 }while(ofile_next_module(&ofile));
496 else{
497 processor(&ofile, NULL, cookie);
501 if(ofile.headers_swapped == TRUE)
502 swap_back_Mach_O(&ofile);
504 else{
505 if(member_name != NULL)
506 error("for architecture: %s file: %s is "
507 "not an archive and thus does not "
508 "contain member: %s",
509 ofile.arch_flag.name, ofile.file_name,
510 member_name);
511 else{
512 processor(&ofile, NULL, cookie);
513 if(ofile.headers_swapped == TRUE)
514 swap_back_Mach_O(&ofile);
518 else if(ofile.arch_type == OFILE_UNKNOWN){
519 error("file: %s is not an object file",
520 ofile.file_name);
523 else{
524 if(ofile.headers_swapped == TRUE)
525 swap_back_Mach_O(&ofile);
527 }while(hostflag == FALSE && ofile_next_arch(&ofile) == TRUE);
528 if(hostflag == TRUE){
529 ofile_unmap(&ofile);
530 return;
535 * Either all architectures have been specified or none have
536 * been specified and it does not contain the host architecture
537 * so do all the architectures in the fat file
539 ofile_unmap(&ofile);
540 if(ofile_map(name, NULL, NULL, &ofile, FALSE) == FALSE)
541 return;
542 if(ofile_first_arch(&ofile) == FALSE){
543 ofile_unmap(&ofile);
544 return;
547 if(ofile.arch_type == OFILE_ARCHIVE){
548 if(member_name != NULL){
549 if(ofile_specific_member(member_name, &ofile) == TRUE)
550 processor(&ofile, ofile.arch_flag.name, cookie);
552 else{
553 /* loop through archive */
554 #ifdef OTOOL
555 printf("Archive : %s (architecture %s)\n",
556 ofile.file_name, ofile.arch_flag.name);
557 #endif /* OTOOL */
558 if(ofile_first_member(&ofile) == TRUE){
559 flag = FALSE;
561 if(process_non_objects == TRUE ||
562 ofile.member_type == OFILE_Mach_O){
563 processor(&ofile, ofile.arch_flag.name,
564 cookie);
565 flag = TRUE;
567 }while(ofile_next_member(&ofile) == TRUE);
568 if(flag == FALSE){
569 error("for architecture: %s archive: %s "
570 "contains no members that are object "
571 "files", ofile.arch_flag.name,
572 ofile.file_name);
575 else{
576 error("for architecture: %s archive: %s "
577 "contains no members",
578 ofile.arch_flag.name, ofile.file_name);
582 else if(process_non_objects == TRUE ||
583 ofile.arch_type == OFILE_Mach_O){
584 if(ofile.arch_type == OFILE_Mach_O &&
585 (ofile.mh_filetype == MH_DYLIB ||
586 ofile.mh_filetype == MH_DYLIB_STUB)){
587 if(dylib_flat == TRUE){
588 processor(&ofile, ofile.arch_flag.name, cookie);
590 else{
591 if(member_name != NULL){
592 if(ofile_specific_module(member_name, &ofile)
593 == TRUE)
594 processor(&ofile, ofile.arch_flag.name,
595 cookie);
597 else{
598 /* loop through the dynamic library */
599 if(ofile_first_module(&ofile) == TRUE){
601 processor(&ofile, ofile.arch_flag.name,
602 cookie);
603 }while(ofile_next_module(&ofile) == TRUE);
605 else{
606 processor(&ofile, ofile.arch_flag.name,
607 cookie);
612 else{
613 if(member_name != NULL)
614 error("for architecture: %s file: %s is not an "
615 "archive and thus does not contain member: "
616 "%s", ofile.arch_flag.name, ofile.file_name,
617 member_name);
618 else
619 processor(&ofile, ofile.arch_flag.name, cookie);
622 else if(ofile.arch_type == OFILE_UNKNOWN){
623 error("for architecture: %s file: %s is not an "
624 "object file", ofile.arch_flag.name,
625 ofile.file_name);
627 }while(ofile_next_arch(&ofile) == TRUE);
629 else if(ofile.file_type == OFILE_ARCHIVE){
630 if(narch_flags != 0){
631 arch_found = FALSE;
632 for(i = 0; i < narch_flags; i++){
633 family = FALSE;
634 if(narch_flags == 1){
635 family_arch_flag =
636 get_arch_family_from_cputype(arch_flags[0].cputype);
637 if(family_arch_flag != NULL)
638 family = (enum bool)
639 ((family_arch_flag->cpusubtype &
640 ~CPU_SUBTYPE_MASK) ==
641 (arch_flags[0].cpusubtype &
642 ~CPU_SUBTYPE_MASK));
644 if(ofile.archive_cputype == arch_flags[i].cputype &&
645 ((ofile.archive_cpusubtype & ~CPU_SUBTYPE_MASK) ==
646 (arch_flags[i].cpusubtype & ~CPU_SUBTYPE_MASK) ||
647 family == TRUE)){
648 arch_found = TRUE;
650 else{
651 error("file: %s does not contain architecture: %s",
652 ofile.file_name, arch_flags[i].name);
655 if(arch_found == FALSE){
656 ofile_unmap(&ofile);
657 return;
660 if(member_name != NULL){
661 if(ofile_specific_member(member_name, &ofile) == TRUE)
662 processor(&ofile, NULL, cookie);
664 else{
665 /* loop through archive */
666 #ifdef OTOOL
667 printf("Archive : %s\n", ofile.file_name);
668 #endif /* OTOOL */
669 if(ofile_first_member(&ofile) == TRUE){
670 flag = FALSE;
672 if(process_non_objects == TRUE ||
673 ofile.member_type == OFILE_Mach_O){
674 processor(&ofile, NULL, cookie);
675 flag = TRUE;
677 }while(ofile_next_member(&ofile) == TRUE);
678 if(flag == FALSE){
679 error("archive: %s contains no members that are "
680 "object files", ofile.file_name);
683 else{
684 error("archive: %s contains no members",
685 ofile.file_name);
689 else if(ofile.file_type == OFILE_Mach_O){
690 if(narch_flags != 0){
691 arch_found = FALSE;
692 for(i = 0; i < narch_flags; i++){
693 family = FALSE;
694 if(narch_flags == 1){
695 family_arch_flag =
696 get_arch_family_from_cputype(arch_flags[0].cputype);
697 if(family_arch_flag != NULL)
698 family = (enum bool)
699 ((family_arch_flag->cpusubtype &
700 ~CPU_SUBTYPE_MASK) ==
701 (arch_flags[0].cpusubtype &
702 ~CPU_SUBTYPE_MASK));
704 #ifdef OTOOL
705 if(ofile.mh != NULL){
706 if(ofile.mh->magic == MH_MAGIC &&
707 ofile.mh->cputype == arch_flags[i].cputype &&
708 ((ofile.mh->cpusubtype & ~CPU_SUBTYPE_MASK) ==
709 (arch_flags[i].cpusubtype & ~CPU_SUBTYPE_MASK) ||
710 family == TRUE)){
711 arch_found = TRUE;
713 if(ofile.mh->magic == SWAP_INT(MH_MAGIC) &&
714 (cpu_type_t)SWAP_INT(ofile.mh->cputype) ==
715 arch_flags[i].cputype &&
716 ((cpu_subtype_t)SWAP_INT(ofile.mh->cpusubtype &
717 ~CPU_SUBTYPE_MASK) ==
718 (arch_flags[i].cpusubtype &
719 ~CPU_SUBTYPE_MASK) ||
720 family == TRUE)){
721 arch_found = TRUE;
724 else if(ofile.mh64 != NULL){
725 if(ofile.mh64->magic == MH_MAGIC_64 &&
726 ofile.mh64->cputype == arch_flags[i].cputype &&
727 ((ofile.mh64->cpusubtype & ~CPU_SUBTYPE_MASK) ==
728 (arch_flags[i].cpusubtype & ~CPU_SUBTYPE_MASK) ||
729 family == TRUE)){
730 arch_found = TRUE;
732 if(ofile.mh64->magic == SWAP_INT(MH_MAGIC_64) &&
733 (cpu_type_t)SWAP_INT(ofile.mh64->cputype) ==
734 arch_flags[i].cputype &&
735 ((cpu_subtype_t)SWAP_INT((ofile.mh64->cpusubtype &
736 ~CPU_SUBTYPE_MASK)) ==
737 (arch_flags[i].cpusubtype & ~CPU_SUBTYPE_MASK) ||
738 family == TRUE)){
739 arch_found = TRUE;
742 else
743 #endif /* OTOOL */
744 if(ofile.mh_cputype == arch_flags[i].cputype &&
745 ((ofile.mh_cpusubtype & ~CPU_SUBTYPE_MASK) ==
746 (arch_flags[i].cpusubtype & ~CPU_SUBTYPE_MASK) ||
747 family == TRUE)){
748 arch_found = TRUE;
750 else{
751 error("file: %s does not contain architecture: %s",
752 ofile.file_name, arch_flags[i].name);
755 if(arch_found == FALSE){
756 ofile_unmap(&ofile);
757 return;
760 if(ofile.mh_filetype == MH_DYLIB ||
761 ofile.mh_filetype == MH_DYLIB_STUB){
762 if(dylib_flat == TRUE){
763 processor(&ofile, NULL, cookie);
765 else{
766 if(member_name != NULL){
767 if(ofile_specific_module(member_name, &ofile) == TRUE)
768 processor(&ofile, NULL, cookie);
770 else{
771 /* loop through the dynamic library */
772 if(ofile_first_module(&ofile) == TRUE){
774 processor(&ofile, NULL, cookie);
775 }while(ofile_next_module(&ofile) == TRUE);
777 else{
778 processor(&ofile, NULL, cookie);
783 else{
784 if(member_name != NULL)
785 error("file: %s is not an archive and thus does not contain"
786 " member: %s", ofile.file_name, member_name);
787 else
788 processor(&ofile, NULL, cookie);
791 else{
792 if(process_non_objects == TRUE)
793 processor(&ofile, NULL, cookie);
794 else if(member_name != NULL)
795 error("file: %s(%s) is not an object file", name,
796 member_name);
797 else
798 error("file: %s is not an object file", name);
800 ofile_unmap(&ofile);
802 #endif /* !defined(OFI) */
805 * ofile_map maps in the object file specified by file_name, arch_flag and
806 * object_name and fills in the ofile struct pointed to by ofile for it.
807 * When arch_flag and object_name are both NULL, the file is just set up into
808 * ofile (if the file can be opened and mapped in, if not this call fails
809 * are error routnes are called). If arch_flag is not NULL and object_file is
810 * NULL, then the file must be a Mach-O file or a fat file with the architecture
811 * specified in the arch_flag, if not this call fails and error routines are
812 * called. When arch_flag and object_name are both not NULL, then the file must
813 * be an archive or a fat file containing archives for the specified architec-
814 * ture and contain an archive member object file with the name object_name,
815 * otherwise this call fails and error routines are called. If arch_flag is
816 * NULL and object_file is not NULL, then the file name must be an archive (not
817 * a fat file containing archives) and contain an archive member object file
818 * with the name object_name, otherwise this call fails and calls error
819 * routines. If this call suceeds then it returns non-zero and the ofile
820 * structure pointed to by ofile is filled in. If this call fails it returns 0
821 * and calls error routines to print error messages and clears the
822 * ofile structure pointed to by ofile.
824 __private_extern__
825 #ifdef OFI
826 NSObjectFileImageReturnCode
827 #else
828 enum bool
829 #endif
830 ofile_map(
831 const char *file_name,
832 const struct arch_flag *arch_flag, /* can be NULL */
833 const char *object_name, /* can be NULL */
834 struct ofile *ofile,
835 enum bool archives_with_fat_objects)
837 int fd;
838 struct stat stat_buf;
839 uint32_t size, magic;
840 char *addr;
842 magic = 0; /* to shut up the compiler warning message */
843 memset(ofile, '\0', sizeof(struct ofile));
845 /* Open the file and map it in */
846 if((fd = open(file_name, O_RDONLY)) == -1){
847 #ifdef OFI
848 return(NSObjectFileImageAccess);
849 #else
850 system_error("can't open file: %s", file_name);
851 return(FALSE);
852 #endif
854 if(fstat(fd, &stat_buf) == -1){
855 close(fd);
856 #ifdef OFI
857 return(NSObjectFileImageAccess);
858 #else
859 system_error("can't stat file: %s", file_name);
860 return(FALSE);
861 #endif
863 size = stat_buf.st_size;
865 addr = NULL;
866 if(size != 0){
867 addr = mmap(0, size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_PRIVATE, fd,
869 if((intptr_t)addr == -1){
870 system_error("can't map file: %s", file_name);
871 close(fd);
872 return(FALSE);
875 close(fd);
876 #ifdef OTOOL
877 if(otool_first_ofile_map && Wflag)
878 printf("Modification time = %ld\n", (long int)stat_buf.st_mtime);
879 #endif /* OTOOL */
881 return(ofile_map_from_memory(addr, size, file_name, stat_buf.st_mtime,
882 arch_flag, object_name, ofile, archives_with_fat_objects));
886 * ofile_map_from_memory() is the guts of ofile_map() but with an interface
887 * to pass the address and size of the file already mapped in.
889 __private_extern__
890 #ifdef OFI
891 NSObjectFileImageReturnCode
892 #else
893 enum bool
894 #endif
895 ofile_map_from_memory(
896 char *addr,
897 uint32_t size,
898 const char *file_name,
899 uint64_t mtime,
900 const struct arch_flag *arch_flag, /* can be NULL */
901 const char *object_name, /* can be NULL */
902 struct ofile *ofile,
903 enum bool archives_with_fat_objects)
905 uint32_t i;
906 uint32_t magic;
907 enum byte_sex host_byte_sex;
908 struct arch_flag host_arch_flag;
909 enum bool family;
910 const struct arch_flag *family_arch_flag;
911 uint64_t big_size;
912 #ifdef OTOOL
913 uint32_t small_nfat_arch;
914 #endif /* OTOOL */
916 /* fill in the start of the ofile structure */
917 ofile->file_name = savestr(file_name);
918 if(ofile->file_name == NULL)
919 return(FALSE);
920 ofile->file_addr = addr;
921 ofile->file_size = size;
922 ofile->file_mtime = mtime;
924 /* Try to figure out what kind of file this is */
926 if(size >= sizeof(uint32_t)){
927 magic = *((uint32_t *)addr);
929 host_byte_sex = get_host_byte_sex();
931 /* see if this file is a fat file (always in big endian byte sex) */
932 #ifdef __BIG_ENDIAN__
933 if(size >= sizeof(struct fat_header) && magic == FAT_MAGIC)
934 #endif /* __BIG_ENDIAN__ */
935 #ifdef __LITTLE_ENDIAN__
936 if(size >= sizeof(struct fat_header) && SWAP_INT(magic) == FAT_MAGIC)
937 #endif /* __LITTLE_ENDIAN__ */
939 ofile->file_type = OFILE_FAT;
940 ofile->fat_header = (struct fat_header *)addr;
941 #ifdef __LITTLE_ENDIAN__
942 swap_fat_header(ofile->fat_header, host_byte_sex);
943 #endif /* __LITTLE_ENDIAN__ */
944 #ifdef OTOOL
945 if(otool_first_ofile_map && fflag)
946 printf("Fat headers\n");
947 #endif /* OTOOL */
948 big_size = ofile->fat_header->nfat_arch;
949 big_size *= sizeof(struct fat_arch);
950 big_size += sizeof(struct fat_header);
951 if(big_size > size){
952 #ifdef OTOOL
953 error("fat file: %s truncated or malformed (fat_arch structs "
954 "would extend past the end of the file)", file_name);
955 ofile->fat_archs = allocate(size - sizeof(struct fat_header));
956 memset(ofile->fat_archs, '\0',
957 size - sizeof(struct fat_header));
958 memcpy(ofile->fat_archs,
959 addr + sizeof(struct fat_header),
960 size - sizeof(struct fat_header));
961 small_nfat_arch = (size - sizeof(struct fat_header)) /
962 sizeof(struct fat_arch);
963 #ifdef __LITTLE_ENDIAN__
964 swap_fat_arch(ofile->fat_archs, small_nfat_arch,
965 host_byte_sex);
966 #endif /* __LITTLE_ENDIAN__ */
967 if(otool_first_ofile_map && fflag)
968 print_fat_headers(ofile->fat_header, ofile->fat_archs,
969 size, vflag);
970 free(ofile->fat_archs);
971 ofile_unmap(ofile);
972 return(FALSE);
973 #else /* !defined(OTOOL) */
974 goto unknown;
975 #endif /* OTOOL */
977 ofile->fat_archs = (struct fat_arch *)(addr +
978 sizeof(struct fat_header));
979 #ifdef __LITTLE_ENDIAN__
980 swap_fat_arch(ofile->fat_archs, ofile->fat_header->nfat_arch,
981 host_byte_sex);
982 #endif /* __LITTLE_ENDIAN__ */
983 #ifdef OTOOL
984 if(otool_first_ofile_map && fflag)
985 print_fat_headers(ofile->fat_header, ofile->fat_archs,
986 size, vflag);
987 #endif /* OTOOL */
988 if(check_fat(ofile) == CHECK_BAD){
989 ofile_unmap(ofile);
990 #ifdef OFI
991 return(NSObjectFileImageFormat);
992 #else
993 return(FALSE);
994 #endif
997 * Now that the fat file is mapped fill in the ofile to the level
998 * the caller wants based on the arch_flag and object_name passed.
999 * If the caller did not specify an arch_flag or an object_name
1000 * then everything the caller wants is done.
1002 if(arch_flag == NULL && object_name == NULL)
1003 goto success;
1004 if(arch_flag == NULL){
1005 if(get_arch_from_host(&host_arch_flag, NULL) == 0){
1006 error("can't determine the host architecture (specify an "
1007 "arch_flag or fix get_arch_from_host() )");
1008 goto cleanup;
1010 ofile->arch_flag.name = savestr(host_arch_flag.name);
1011 if(ofile->arch_flag.name == NULL)
1012 goto cleanup;
1013 ofile->arch_flag.cputype = host_arch_flag.cputype;
1014 ofile->arch_flag.cpusubtype = host_arch_flag.cpusubtype;
1016 else{
1017 ofile->arch_flag.name = savestr(arch_flag->name);
1018 if(ofile->arch_flag.name == NULL)
1019 goto cleanup;
1020 ofile->arch_flag.cputype = arch_flag->cputype;
1021 ofile->arch_flag.cpusubtype = arch_flag->cpusubtype;
1024 ofile->narch = UINT_MAX;
1025 for(i = 0; i < ofile->fat_header->nfat_arch; i++){
1026 if(ofile->fat_archs[i].cputype ==
1027 ofile->arch_flag.cputype &&
1028 (ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK) ==
1029 (ofile->arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK)){
1030 ofile->narch = i;
1031 break;
1034 if(ofile->narch == UINT_MAX){
1035 family = FALSE;
1036 family_arch_flag =
1037 get_arch_family_from_cputype(ofile->arch_flag.cputype);
1038 if(family_arch_flag != NULL)
1039 family = (enum bool)
1040 ((family_arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) ==
1041 (ofile->arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK));
1042 ofile->narch = UINT_MAX;
1043 for(i = 0; i < ofile->fat_header->nfat_arch; i++){
1044 if(ofile->fat_archs[i].cputype ==
1045 ofile->arch_flag.cputype &&
1046 (family == TRUE ||
1047 (ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK) ==
1048 (ofile->arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK))){
1049 ofile->arch_flag.cpusubtype =
1050 ofile->fat_archs[i].cpusubtype;
1051 ofile->narch = i;
1052 break;
1056 if(ofile->narch == UINT_MAX){
1057 #ifdef OFI
1058 ofile_unmap(ofile);
1059 return(NSObjectFileImageArch);
1060 #else
1061 error("fat file: %s does not contain architecture %s",
1062 ofile->file_name, arch_flag->name);
1063 ofile_unmap(ofile);
1064 return(FALSE);
1065 #endif
1067 /* Now determine the file type for this specific architecture */
1068 size = ofile->fat_archs[i].size;
1069 addr = addr + ofile->fat_archs[i].offset;
1070 if(size >= sizeof(struct mach_header))
1071 memcpy(&magic, addr, sizeof(uint32_t));
1072 /* see if this file is a 32-bit Mach-O file */
1073 if(size >= sizeof(struct mach_header) &&
1074 (magic == MH_MAGIC ||
1075 magic == SWAP_INT(MH_MAGIC))){
1076 #ifdef ALIGNMENT_CHECKS
1077 if(ofile->fat_archs[i].offset % 4 != 0){
1078 error("fat file: %s architecture %s malformed for a 32-bit "
1079 "object file (offset is not a multiple of 4)",
1080 ofile->file_name, arch_flag->name);
1081 ofile_unmap(ofile);
1082 #ifdef OFI
1083 return(NSObjectFileImageFormat);
1084 #else
1085 return(FALSE);
1086 #endif
1088 #endif /* ALIGNMENT_CHECKS */
1089 ofile->arch_type = OFILE_Mach_O;
1090 ofile->object_addr = addr;
1091 ofile->object_size = size;
1092 if(magic == MH_MAGIC)
1093 ofile->object_byte_sex = host_byte_sex;
1094 else
1095 ofile->object_byte_sex =
1096 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1097 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1098 ofile->mh = (struct mach_header *)addr;
1099 ofile->load_commands = (struct load_command *)(addr +
1100 sizeof(struct mach_header));
1101 if(check_Mach_O(ofile) == CHECK_BAD){
1102 ofile_unmap(ofile);
1103 #ifdef OFI
1104 return(NSObjectFileImageFormat);
1105 #else
1106 return(FALSE);
1107 #endif
1109 if(object_name != NULL){
1110 error("fat file: %s architecture %s is not an archive "
1111 "(object_name to ofile_map() can't be specified to "
1112 "be other than NULL)", ofile->file_name,
1113 arch_flag->name);
1114 goto cleanup;
1117 /* see if this file is a 64-bit Mach-O file */
1118 else if(size >= sizeof(struct mach_header_64) &&
1119 (magic == MH_MAGIC_64 ||
1120 magic == SWAP_INT(MH_MAGIC_64))){
1121 #ifdef ALIGNMENT_CHECKS
1122 if(ofile->fat_archs[i].offset % 8 != 0){
1123 error("fat file: %s architecture %s malformed for a 64-bit "
1124 "object file (offset is not a multiple of 8)",
1125 ofile->file_name, arch_flag->name);
1126 ofile_unmap(ofile);
1127 #ifdef OFI
1128 return(NSObjectFileImageFormat);
1129 #else
1130 return(FALSE);
1131 #endif
1133 #endif /* ALIGNMENT_CHECKS */
1134 ofile->arch_type = OFILE_Mach_O;
1135 ofile->object_addr = addr;
1136 ofile->object_size = size;
1137 if(magic == MH_MAGIC_64)
1138 ofile->object_byte_sex = host_byte_sex;
1139 else
1140 ofile->object_byte_sex =
1141 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1142 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1143 ofile->mh64 = (struct mach_header_64 *)addr;
1144 ofile->load_commands = (struct load_command *)(addr +
1145 sizeof(struct mach_header_64));
1146 if(check_Mach_O(ofile) == CHECK_BAD){
1147 ofile_unmap(ofile);
1148 #ifdef OFI
1149 return(NSObjectFileImageFormat);
1150 #else
1151 return(FALSE);
1152 #endif
1154 if(object_name != NULL){
1155 error("fat file: %s architecture %s is not an archive "
1156 "(object_name to ofile_map() can't be specified to "
1157 "be other than NULL)", ofile->file_name,
1158 arch_flag->name);
1159 goto cleanup;
1162 /* see if this file is an archive file */
1163 else if(size >= SARMAG && strncmp(addr, ARMAG, SARMAG) == 0){
1164 ofile->arch_type = OFILE_ARCHIVE;
1165 if(check_archive(ofile, FALSE) == CHECK_BAD){
1166 ofile_unmap(ofile);
1167 #ifdef OFI
1168 return(NSObjectFileImageInappropriateFile);
1169 #else
1170 return(FALSE);
1171 #endif
1173 #ifdef ALIGNMENT_CHECKS
1174 if(ofile->archive_cputype != 0 &&
1175 ofile->fat_archs[i].offset % sizeof(uint32_t) != 0){
1176 error("fat file: %s architecture %s malformed archive that "
1177 "contains object files (offset to archive is not a "
1178 "multiple of sizeof(uint32_t))",
1179 ofile->file_name, arch_flag->name);
1180 ofile_unmap(ofile);
1181 #ifdef OFI
1182 return(NSObjectFileImageInappropriateFile);
1183 #else
1184 return(FALSE);
1185 #endif
1187 #endif /* ALIGNMENT_CHECKS */
1188 if(object_name != NULL){
1189 if(ofile_specific_member(object_name, ofile) == FALSE)
1190 goto cleanup;
1193 /* this file type is now known to be unknown to this program */
1194 else{
1195 ofile->file_type = OFILE_UNKNOWN;
1196 if(object_name != NULL){
1197 error("fat file: %s architecture %s is not an archive "
1198 "(object_name to ofile_map() can't be specified to "
1199 "be other than NULL)", ofile->file_name,
1200 arch_flag->name);
1201 goto cleanup;
1205 /* see if this file is a 32-bit Mach-O file */
1206 else if(size >= sizeof(struct mach_header) &&
1207 (magic == MH_MAGIC ||
1208 magic == SWAP_INT(MH_MAGIC))){
1209 ofile->file_type = OFILE_Mach_O;
1210 ofile->object_addr = addr;
1211 ofile->object_size = size;
1212 if(magic == MH_MAGIC)
1213 ofile->object_byte_sex = host_byte_sex;
1214 else
1215 ofile->object_byte_sex = host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1216 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1217 ofile->mh = (struct mach_header *)addr;
1218 ofile->load_commands = (struct load_command *)(addr +
1219 sizeof(struct mach_header));
1220 if(check_Mach_O(ofile) == CHECK_BAD){
1221 ofile_unmap(ofile);
1222 #ifdef OFI
1223 return(NSObjectFileImageFormat);
1224 #else
1225 return(FALSE);
1226 #endif
1228 if(object_name != NULL){
1229 error("file: %s is not an archive (object_name to ofile_map() "
1230 "can't be specified to be other than NULL)",
1231 ofile->file_name);
1232 goto cleanup;
1234 if(arch_flag != NULL){
1235 if(arch_flag->cputype != ofile->mh_cputype &&
1236 (arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) !=
1237 (ofile->mh_cpusubtype & ~CPU_SUBTYPE_MASK)){
1238 #ifdef OFI
1239 ofile_unmap(ofile);
1240 return(NSObjectFileImageArch);
1241 #else
1242 error("object file: %s does not match specified arch_flag: "
1243 "%s passed to ofile_map()", ofile->file_name,
1244 arch_flag->name);
1245 ofile_unmap(ofile);
1246 return(FALSE);
1247 #endif
1248 goto cleanup;
1252 /* see if this file is a 64-bit Mach-O file */
1253 else if(size >= sizeof(struct mach_header_64) &&
1254 (magic == MH_MAGIC_64 ||
1255 magic == SWAP_INT(MH_MAGIC_64))){
1256 ofile->file_type = OFILE_Mach_O;
1257 ofile->object_addr = addr;
1258 ofile->object_size = size;
1259 if(magic == MH_MAGIC_64)
1260 ofile->object_byte_sex = host_byte_sex;
1261 else
1262 ofile->object_byte_sex = host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1263 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1264 ofile->mh64 = (struct mach_header_64 *)addr;
1265 ofile->load_commands = (struct load_command *)(addr +
1266 sizeof(struct mach_header_64));
1267 if(check_Mach_O(ofile) == CHECK_BAD){
1268 ofile_unmap(ofile);
1269 #ifdef OFI
1270 return(NSObjectFileImageFormat);
1271 #else
1272 return(FALSE);
1273 #endif
1275 if(object_name != NULL){
1276 error("file: %s is not an archive (object_name to ofile_map() "
1277 "can't be specified to be other than NULL)",
1278 ofile->file_name);
1279 goto cleanup;
1281 if(arch_flag != NULL){
1282 if(arch_flag->cputype != ofile->mh_cputype &&
1283 (arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) !=
1284 (ofile->mh_cpusubtype & ~CPU_SUBTYPE_MASK)){
1285 #ifdef OFI
1286 ofile_unmap(ofile);
1287 return(NSObjectFileImageArch);
1288 #else
1289 error("object file: %s does not match specified arch_flag: "
1290 "%s passed to ofile_map()", ofile->file_name,
1291 arch_flag->name);
1292 ofile_unmap(ofile);
1293 return(FALSE);
1294 #endif
1295 goto cleanup;
1299 /* see if this file is an archive file */
1300 else if(size >= SARMAG && strncmp(addr, ARMAG, SARMAG) == 0){
1301 ofile->file_type = OFILE_ARCHIVE;
1302 if(check_archive(ofile, archives_with_fat_objects) == CHECK_BAD)
1303 goto cleanup;
1304 if(object_name != NULL){
1305 if(ofile_specific_member(object_name, ofile) == FALSE)
1306 goto cleanup;
1307 if(arch_flag != NULL){
1308 if(arch_flag->cputype != ofile->mh_cputype &&
1309 (arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) !=
1310 (ofile->mh_cpusubtype & ~CPU_SUBTYPE_MASK)){
1311 error("object file: %s(%.*s) does not match specified "
1312 "arch_flag: %s passed to ofile_map()",
1313 ofile->file_name, (int)ofile->member_name_size,
1314 ofile->member_name, arch_flag->name);
1315 goto cleanup;
1319 else{
1320 if(arch_flag != NULL){
1321 if(arch_flag->cputype != ofile->archive_cputype &&
1322 (arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) !=
1323 (ofile->archive_cpusubtype & ~CPU_SUBTYPE_MASK)){
1324 error("archive file: %s objects do not match specified "
1325 "arch_flag: %s passed to ofile_map()",
1326 ofile->file_name, arch_flag->name);
1327 goto cleanup;
1332 /* this file type is now known to be unknown to this program */
1333 else{
1334 #ifndef OTOOL
1335 unknown:
1336 #endif
1337 #ifndef OFI
1338 #ifdef LTO_SUPPORT
1339 if(is_llvm_bitcode(ofile, ofile->file_addr, ofile->file_size) ==
1340 TRUE){
1341 ofile->file_type = OFILE_LLVM_BITCODE;
1342 if(arch_flag != NULL){
1343 if(arch_flag->cputype != ofile->lto_cputype &&
1344 (arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) !=
1345 (ofile->lto_cpusubtype & ~CPU_SUBTYPE_MASK)){
1346 error("llvm bitcode file: %s does not match specified "
1347 "arch_flag: %s passed to ofile_map()",
1348 ofile->file_name, arch_flag->name);
1349 goto cleanup;
1352 if(object_name != NULL){
1353 error("file: %s is not an archive (object_name to "
1354 "ofile_map() can't be specified to be other than "
1355 "NULL)", ofile->file_name);
1356 goto cleanup;
1358 goto success;
1360 else
1361 #endif /* LTO_SUPPORT */
1362 #endif /* OFI */
1363 ofile->file_type = OFILE_UNKNOWN;
1364 if(arch_flag != NULL){
1365 #ifdef OFI
1366 ofile_unmap(ofile);
1367 return(NSObjectFileImageInappropriateFile);
1368 #else
1369 error("file: %s is unknown type (arch_flag to ofile_map() "
1370 "can't be specified to be other than NULL)",
1371 ofile->file_name);
1372 ofile_unmap(ofile);
1373 return(FALSE);
1374 #endif
1376 if(object_name != NULL){
1377 error("file: %s is not an archive (object_name to ofile_map() "
1378 "can't be specified to be other than NULL)",
1379 ofile->file_name);
1380 goto cleanup;
1383 success:
1384 return(TRUE);
1386 cleanup:
1387 ofile_unmap(ofile);
1388 return(FALSE);
1392 * ofile_unmap() deallocates the memory associated with the specified ofile
1393 * struct.
1395 __private_extern__
1396 void
1397 ofile_unmap(
1398 struct ofile *ofile)
1400 kern_return_t r;
1402 if(ofile->file_addr != NULL){
1403 if((r = vm_deallocate(mach_task_self(),
1404 (vm_address_t)ofile->file_addr,
1405 (vm_size_t)ofile->file_size)) != KERN_SUCCESS){
1406 my_mach_error(r, "Can't vm_deallocate mapped memory for file: "
1407 "%s", ofile->file_name);
1410 if(ofile->file_name != NULL)
1411 free(ofile->file_name);
1412 if(ofile->arch_flag.name != NULL)
1413 free(ofile->arch_flag.name);
1414 memset(ofile, '\0', sizeof(struct ofile));
1418 * ofile_first_arch() sets up the ofile struct for a fat file to the first arch
1419 * in it.
1421 __private_extern__
1422 enum bool
1423 ofile_first_arch(
1424 struct ofile *ofile)
1426 if(ofile->file_type == OFILE_FAT ||
1427 (ofile->file_type == OFILE_ARCHIVE &&
1428 ofile->member_type == OFILE_FAT) )
1429 return(ofile_specific_arch(ofile, 0));
1430 else{
1431 error("ofile_first_arch() called and file type of: %s is not a fat "
1432 "file\n", ofile->file_name);
1433 return(FALSE);
1438 * ofile_next_arch() sets up the ofile struct for a fat file to the next arch
1439 * in it.
1441 __private_extern__
1442 enum bool
1443 ofile_next_arch(
1444 struct ofile *ofile)
1446 if(ofile->file_type == OFILE_FAT ||
1447 (ofile->file_type == OFILE_ARCHIVE &&
1448 ofile->member_type == OFILE_FAT) ){
1449 if(ofile->narch + 1 < ofile->fat_header->nfat_arch)
1450 return(ofile_specific_arch(ofile, ofile->narch + 1));
1451 else
1452 return(FALSE);
1454 else{
1455 error("ofile_next_arch() called and file type of: %s is not a fat "
1456 "file\n", ofile->file_name);
1457 return(FALSE);
1462 * ofile_specific_arch() sets up the ofile struct for the fat file for the
1463 * specified narch.
1465 static
1466 enum bool
1467 ofile_specific_arch(
1468 struct ofile *ofile,
1469 uint32_t narch)
1471 char *addr;
1472 uint32_t size;
1473 uint32_t magic;
1474 enum byte_sex host_byte_sex;
1476 ofile->narch = narch;
1477 ofile->arch_type = OFILE_UNKNOWN;
1478 if(ofile->arch_flag.name != NULL)
1479 free(ofile->arch_flag.name);
1480 ofile->arch_flag.name = NULL;
1481 ofile->arch_flag.cputype = 0;
1482 ofile->arch_flag.cpusubtype = 0;
1483 ofile->archive_cputype = 0;
1484 ofile->archive_cpusubtype = 0;
1485 ofile->object_addr = NULL;
1486 ofile->object_size = 0;
1487 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
1488 ofile->mh = NULL;
1489 ofile->mh64 = NULL;
1490 ofile->load_commands = NULL;
1492 ofile->arch_flag.cputype = ofile->fat_archs[ofile->narch].cputype;
1493 ofile->arch_flag.cpusubtype = ofile->fat_archs[ofile->narch].cpusubtype;
1494 set_arch_flag_name(&(ofile->arch_flag));
1497 /* Now determine the file type for this specific architecture */
1498 if(ofile->file_type == OFILE_FAT){
1499 ofile->member_offset = 0;
1500 ofile->member_addr = NULL;
1501 ofile->member_size = 0;
1502 ofile->member_ar_hdr = NULL;
1503 ofile->member_type = OFILE_UNKNOWN;
1505 size = ofile->fat_archs[ofile->narch].size;
1506 addr = ofile->file_addr + ofile->fat_archs[ofile->narch].offset;
1508 else{
1509 if(ofile->file_type != OFILE_ARCHIVE ||
1510 ofile->member_type != OFILE_FAT){
1511 error("internal error. ofile_specific_arch() called but file "
1512 "is not a fat file or an archive with a fat member ");
1514 size = ofile->fat_archs[ofile->narch].size;
1515 addr = ofile->file_addr +
1516 ofile->member_offset +
1517 ofile->fat_archs[ofile->narch].offset;
1520 #ifdef OTOOL
1521 if(addr - ofile->file_addr > (ptrdiff_t)ofile->file_size){
1522 error("fat file: %s offset to architecture %s extends past end "
1523 "of file", ofile->file_name, ofile->arch_flag.name);
1524 return(FALSE);
1526 if(addr + size > ofile->file_addr + ofile->file_size)
1527 size = (ofile->file_addr + ofile->file_size) - addr;
1528 #endif /* OTOOL */
1530 if(size >= sizeof(struct mach_header))
1531 memcpy(&magic, addr, sizeof(uint32_t));
1532 /* see if this file is a 32-bit Mach-O file */
1533 if(size >= sizeof(struct mach_header) &&
1534 (magic == MH_MAGIC || magic == SWAP_INT(MH_MAGIC))){
1535 #ifdef ALIGNMENT_CHECKS
1536 if(ofile->fat_archs[ofile->narch].offset % 4 != 0){
1537 if(ofile->file_type == OFILE_ARCHIVE){
1538 error("fat file: %s(%.*s) architecture %s malformed for a "
1539 "32-bit object file (offset is not a multiple of 4)",
1540 ofile->file_name, (int)ofile->member_name_size,
1541 ofile->member_name, ofile->arch_flag.name);
1543 else
1544 error("fat file: %s architecture %s malformed for a 32-bit "
1545 "object file (offset is not a multiple of 4)",
1546 ofile->file_name, ofile->arch_flag.name);
1547 goto cleanup;
1549 #endif /* ALIGNMENT_CHECKS */
1550 ofile->arch_type = OFILE_Mach_O;
1551 ofile->object_addr = addr;
1552 ofile->object_size = size;
1553 host_byte_sex = get_host_byte_sex();
1554 if(magic == MH_MAGIC)
1555 ofile->object_byte_sex = host_byte_sex;
1556 else
1557 ofile->object_byte_sex =
1558 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1559 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1560 ofile->mh = (struct mach_header *)addr;
1561 ofile->load_commands = (struct load_command *)(addr +
1562 sizeof(struct mach_header));
1563 if(check_Mach_O(ofile) == CHECK_BAD)
1564 goto cleanup;
1566 /* see if this file is a 64-bit Mach-O file */
1567 else if(size >= sizeof(struct mach_header_64) &&
1568 (magic == MH_MAGIC_64 || magic == SWAP_INT(MH_MAGIC_64))){
1569 #ifdef ALIGNMENT_CHECKS
1570 if(ofile->fat_archs[ofile->narch].offset % 8 != 0){
1571 if(ofile->file_type == OFILE_ARCHIVE){
1572 error("fat file: %s(%.*s) architecture %s malformed for an "
1573 "object file (offset is not a multiple of 8)",
1574 ofile->file_name, (int)ofile->member_name_size,
1575 ofile->member_name, ofile->arch_flag.name);
1577 else
1578 error("fat file: %s architecture %s malformed for a 64-bit "
1579 "object file (offset is not a multiple of 8",
1580 ofile->file_name, ofile->arch_flag.name);
1581 goto cleanup;
1583 #endif /* ALIGNMENT_CHECKS */
1584 ofile->arch_type = OFILE_Mach_O;
1585 ofile->object_addr = addr;
1586 ofile->object_size = size;
1587 host_byte_sex = get_host_byte_sex();
1588 if(magic == MH_MAGIC_64)
1589 ofile->object_byte_sex = host_byte_sex;
1590 else
1591 ofile->object_byte_sex =
1592 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1593 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1594 ofile->mh64 = (struct mach_header_64 *)addr;
1595 ofile->load_commands = (struct load_command *)(addr +
1596 sizeof(struct mach_header_64));
1597 if(check_Mach_O(ofile) == CHECK_BAD)
1598 goto cleanup;
1600 /* see if this file is an archive file */
1601 else if(size >= SARMAG && strncmp(addr, ARMAG, SARMAG) == 0){
1602 ofile->arch_type = OFILE_ARCHIVE;
1603 if(check_archive(ofile, FALSE) == CHECK_BAD)
1604 goto cleanup;
1605 #ifdef ALIGNMENT_CHECKS
1606 if(ofile->archive_cputype != 0 &&
1607 ofile->fat_archs[ofile->narch].offset %
1608 sizeof(uint32_t) != 0){
1609 error("fat file: %s architecture %s malformed archive that "
1610 "contains object files (offset to archive is not a "
1611 "multiple of sizeof(uint32_t))",
1612 ofile->file_name, ofile->arch_flag.name);
1613 goto cleanup;
1615 #endif /* ALIGNMENT_CHECKS */
1618 * This type for this architecture is now known to be unknown to this
1619 * program.
1621 else{
1622 ofile->arch_type = OFILE_UNKNOWN;
1624 return(TRUE);
1625 cleanup:
1626 ofile->narch = 0;;
1627 ofile->arch_type = OFILE_UNKNOWN;
1628 if(ofile->arch_flag.name != NULL)
1629 free(ofile->arch_flag.name);
1630 ofile->arch_flag.name = NULL;
1631 ofile->arch_flag.cputype = 0;
1632 ofile->arch_flag.cpusubtype = 0;
1633 if(ofile->file_type != OFILE_ARCHIVE){
1634 ofile->member_offset = 0;
1635 ofile->member_addr = NULL;
1636 ofile->member_size = 0;
1637 ofile->member_ar_hdr = NULL;
1638 ofile->member_type = OFILE_UNKNOWN;
1640 ofile->archive_cputype = 0;
1641 ofile->archive_cpusubtype = 0;
1642 ofile->object_addr = NULL;
1643 ofile->object_size = 0;
1644 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
1645 ofile->mh = NULL;
1646 ofile->mh64 = NULL;
1647 ofile->load_commands = NULL;
1648 return(FALSE);
1652 * ofile_first_member() set up the ofile structure (the member_* fields and
1653 * the object file fields if the first member is an object file) for the first
1654 * member.
1656 __private_extern__
1657 enum bool
1658 ofile_first_member(
1659 struct ofile *ofile)
1661 char *addr;
1662 uint32_t size, offset;
1663 uint32_t magic;
1664 enum byte_sex host_byte_sex;
1665 struct ar_hdr *ar_hdr;
1666 uint32_t ar_name_size;
1668 /* These fields are to be filled in by this routine, clear them first */
1669 ofile->member_offset = 0;
1670 ofile->member_addr = NULL;
1671 ofile->member_size = 0;
1672 ofile->member_ar_hdr = NULL;
1673 ofile->member_name = NULL;
1674 ofile->member_name_size = 0;
1675 ofile->member_type = OFILE_UNKNOWN;
1676 ofile->object_addr = NULL;
1677 ofile->object_size = 0;
1678 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
1679 ofile->mh = NULL;
1680 ofile->mh64 = NULL;
1681 ofile->load_commands = NULL;
1682 #ifdef LTO_SUPPORT
1684 * Note: it is up to the caller if they want to call free_lto() on this
1685 * when iterating through the members of an archive.
1687 ofile->lto = NULL;
1688 #endif /* LTO_SUPPORT */
1691 * Get the address and size of the archive.
1693 if(ofile->file_type == OFILE_FAT){
1694 if(ofile->arch_type != OFILE_ARCHIVE){
1695 error("ofile_first_member() called on fat file: %s with a "
1696 "non-archive architecture or no architecture selected\n",
1697 ofile->file_name);
1698 return(FALSE);
1700 addr = ofile->file_addr + ofile->fat_archs[ofile->narch].offset;
1701 size = ofile->fat_archs[ofile->narch].size;
1703 else if(ofile->file_type == OFILE_ARCHIVE){
1704 addr = ofile->file_addr;
1705 size = ofile->file_size;
1707 else{
1708 error("ofile_first_member() called and file type of %s is "
1709 "OFILE_UNKNOWN\n", ofile->file_name);
1710 return(FALSE);
1712 #ifdef OTOOL
1713 if((addr + SARMAG) - ofile->file_addr > (ptrdiff_t)ofile->file_size){
1714 archive_error(ofile, "offset to first member extends past the end "
1715 "of the file");
1716 return(FALSE);
1718 if(addr + size > ofile->file_addr + ofile->file_size)
1719 size = (ofile->file_addr + ofile->file_size) - addr;
1720 #endif /* OTOOL */
1721 if(size < SARMAG || strncmp(addr, ARMAG, SARMAG) != 0){
1722 archive_error(ofile, "internal error. ofile_first_member() "
1723 "called but file does not have an archive magic "
1724 "string");
1725 return(FALSE);
1728 offset = SARMAG;
1729 if(offset != size && offset + sizeof(struct ar_hdr) > size){
1730 archive_error(ofile, "truncated or malformed (archive header of "
1731 "first member extends past the end of the file)");
1732 return(FALSE);
1735 /* check for empty archive */
1736 if(size == offset)
1737 return(FALSE);
1739 /* now we know there is a first member so set it up */
1740 ar_hdr = (struct ar_hdr *)(addr + offset);
1741 offset += sizeof(struct ar_hdr);
1742 ofile->member_offset = offset;
1743 ofile->member_addr = addr + offset;
1744 ofile->member_size = strtoul(ar_hdr->ar_size, NULL, 10);
1745 ofile->member_ar_hdr = ar_hdr;
1746 ofile->member_type = OFILE_UNKNOWN;
1747 ofile->member_name = ar_hdr->ar_name;
1748 if(strncmp(ofile->member_name, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0){
1749 ofile->member_name = ar_hdr->ar_name + sizeof(struct ar_hdr);
1750 ar_name_size = strtoul(ar_hdr->ar_name + sizeof(AR_EFMT1) - 1,
1751 NULL, 10);
1752 ofile->member_name_size = ar_name_size;
1753 ofile->member_offset += ar_name_size;
1754 ofile->member_addr += ar_name_size;
1755 ofile->member_size -= ar_name_size;
1757 else{
1758 ofile->member_name_size = size_ar_name(ar_hdr);
1759 ar_name_size = 0;
1761 /* Clear these in case there is no table of contents */
1762 ofile->toc_addr = NULL;
1763 ofile->toc_size = 0;
1764 ofile->toc_ar_hdr = NULL;
1765 ofile->toc_name = NULL;
1766 ofile->toc_name_size = 0;
1767 ofile->toc_ranlibs = NULL;
1768 ofile->toc_nranlibs = 0;
1769 ofile->toc_strings = NULL;
1770 ofile->toc_strsize = 0;
1771 ofile->toc_bad = FALSE;
1773 host_byte_sex = get_host_byte_sex();
1775 if(ofile->member_size > sizeof(uint32_t)){
1776 memcpy(&magic, ofile->member_addr, sizeof(uint32_t));
1777 #ifdef __BIG_ENDIAN__
1778 if(magic == FAT_MAGIC)
1779 #endif /* __BIG_ENDIAN__ */
1780 #ifdef __LITTLE_ENDIAN__
1781 if(magic == SWAP_INT(FAT_MAGIC))
1782 #endif /* __LITTLE_ENDIAN__ */
1784 ofile->member_type = OFILE_FAT;
1785 ofile->fat_header =
1786 (struct fat_header *)(ofile->member_addr);
1787 #ifdef __LITTLE_ENDIAN__
1788 swap_fat_header(ofile->fat_header, host_byte_sex);
1789 #endif /* __LITTLE_ENDIAN__ */
1790 if(sizeof(struct fat_header) +
1791 ofile->fat_header->nfat_arch *
1792 sizeof(struct fat_arch) > ofile->member_size){
1793 archive_member_error(ofile, "fat file truncated or "
1794 "malformed (fat_arch structs would extend past "
1795 "the end of the archive member)");
1796 goto fatcleanup;
1798 ofile->fat_archs = (struct fat_arch *)
1799 (ofile->member_addr + sizeof(struct fat_header));
1800 #ifdef __LITTLE_ENDIAN__
1801 swap_fat_arch(ofile->fat_archs,
1802 ofile->fat_header->nfat_arch, host_byte_sex);
1803 #endif /* __LITTLE_ENDIAN__ */
1804 if(check_fat_object_in_archive(ofile) == FALSE)
1805 goto fatcleanup;
1807 else if(size - (offset + ar_name_size) >=
1808 sizeof(struct mach_header) &&
1809 (magic == MH_MAGIC || magic == SWAP_INT(MH_MAGIC))){
1810 #ifdef ALIGNMENT_CHECKS
1811 if((offset + ar_name_size) % 4 != 0){
1812 archive_member_error(ofile, "offset in archive not a "
1813 "multiple of 4 (must be since member is a 32-bit "
1814 "object file)");
1815 goto cleanup;
1817 #endif /* ALIGNMENT_CHECKS */
1818 ofile->member_type = OFILE_Mach_O;
1819 ofile->object_addr = ofile->member_addr;
1820 ofile->object_size = ofile->member_size;
1821 if(magic == MH_MAGIC)
1822 ofile->object_byte_sex = host_byte_sex;
1823 else
1824 ofile->object_byte_sex =
1825 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1826 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1827 ofile->mh = (struct mach_header *)(ofile->object_addr);
1828 ofile->load_commands = (struct load_command *)
1829 (ofile->object_addr + sizeof(struct mach_header));
1830 if(check_Mach_O(ofile) == CHECK_BAD)
1831 goto cleanup;
1833 else if(size - (offset + ar_name_size) >=
1834 sizeof(struct mach_header_64) &&
1835 (magic == MH_MAGIC_64 || magic == SWAP_INT(MH_MAGIC_64))){
1836 #ifdef ALIGNMENT_CHECKS_ARCHIVE_64_BIT
1837 if(archive_64_bit_align_warning == FALSE &&
1838 (offset + ar_name_size) % 8 != 0){
1839 temporary_archive_member_warning(ofile, "offset in archive "
1840 "not a multiple of 8 (must be since member is an "
1841 "64-bit object file)");
1842 archive_64_bit_align_warning = TRUE;
1843 /* goto cleanup; */
1845 #endif /* ALIGNMENT_CHECKS_ARCHIVE_64_BIT */
1846 ofile->member_type = OFILE_Mach_O;
1847 ofile->object_addr = ofile->member_addr;
1848 ofile->object_size = ofile->member_size;
1849 if(magic == MH_MAGIC_64)
1850 ofile->object_byte_sex = host_byte_sex;
1851 else
1852 ofile->object_byte_sex =
1853 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1854 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1855 ofile->mh64 = (struct mach_header_64 *)(ofile->object_addr);
1856 ofile->load_commands = (struct load_command *)
1857 (ofile->object_addr + sizeof(struct mach_header_64));
1858 if(check_Mach_O(ofile) == CHECK_BAD)
1859 goto cleanup;
1861 if(ofile->member_type == OFILE_UNKNOWN &&
1862 (strncmp(ofile->member_name, SYMDEF_SORTED,
1863 sizeof(SYMDEF_SORTED) - 1) == 0 ||
1864 strncmp(ofile->member_name, SYMDEF,
1865 sizeof(SYMDEF) - 1) == 0)){
1866 ofile->toc_addr = ofile->member_addr;
1867 ofile->toc_size = ofile->member_size;
1868 ofile->toc_ar_hdr = ofile->member_ar_hdr;
1869 ofile->toc_name = ofile->member_name;
1870 ofile->toc_name_size = ofile->member_name_size;
1871 if(check_archive_toc(ofile) == CHECK_BAD)
1872 goto cleanup;
1874 #ifdef LTO_SUPPORT
1875 if(ofile->member_type == OFILE_UNKNOWN &&
1876 strncmp(ofile->member_name, SYMDEF_SORTED,
1877 sizeof(SYMDEF_SORTED) - 1) != 0 &&
1878 strncmp(ofile->member_name, SYMDEF,
1879 sizeof(SYMDEF) - 1) != 0 &&
1880 is_llvm_bitcode(ofile, ofile->member_addr, ofile->member_size) ==
1881 TRUE){
1882 ofile->member_type = OFILE_LLVM_BITCODE;
1883 ofile->object_addr = ofile->member_addr;
1884 ofile->object_size = ofile->member_size;
1886 #endif /* LTO_SUPPORT */
1888 return(TRUE);
1890 fatcleanup:
1891 ofile->fat_header = NULL;
1892 ofile->fat_archs = NULL;
1893 cleanup:
1894 ofile->member_offset = 0;
1895 ofile->member_addr = 0;
1896 ofile->member_size = 0;
1897 ofile->member_ar_hdr = NULL;
1898 ofile->member_name = NULL;
1899 ofile->member_name_size = 0;
1900 ofile->member_type = OFILE_UNKNOWN;
1901 ofile->object_addr = NULL;
1902 ofile->object_size = 0;
1903 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
1904 ofile->mh = NULL;
1905 ofile->mh64 = NULL;
1906 ofile->load_commands = NULL;
1907 #ifdef LTO_SUPPORT
1908 ofile->lto = NULL;
1909 ofile->lto_cputype = 0;
1910 ofile->lto_cpusubtype = 0;
1911 #endif /* LTO_SUPPORT */
1912 return(FALSE);
1916 * ofile_next_member() set up the ofile structure (the member_* fields and
1917 * the object file fields if the next member is an object file) for the next
1918 * member.
1920 __private_extern__
1921 enum bool
1922 ofile_next_member(
1923 struct ofile *ofile)
1925 char *addr;
1926 uint32_t size, offset;
1927 uint32_t magic;
1928 enum byte_sex host_byte_sex;
1929 struct ar_hdr *ar_hdr;
1930 uint32_t ar_name_size;
1933 * Get the address and size of the archive.
1935 if(ofile->file_type == OFILE_FAT){
1936 if(ofile->arch_type != OFILE_ARCHIVE){
1937 error("ofile_next_member() called on fat file: %s with a "
1938 "non-archive architecture or no architecture selected\n",
1939 ofile->file_name);
1940 return(FALSE);
1942 addr = ofile->file_addr + ofile->fat_archs[ofile->narch].offset;
1943 size = ofile->fat_archs[ofile->narch].size;
1945 else if(ofile->file_type == OFILE_ARCHIVE){
1946 addr = ofile->file_addr;
1947 size = ofile->file_size;
1949 else{
1950 error("ofile_next_member() called and file type of %s is "
1951 "OFILE_UNKNOWN\n", ofile->file_name);
1952 return(FALSE);
1954 if(size < SARMAG || strncmp(addr, ARMAG, SARMAG) != 0){
1955 archive_error(ofile, "internal error. ofile_next_member() "
1956 "called but file does not have an archive magic "
1957 "string");
1958 return(FALSE);
1960 if(ofile->member_ar_hdr == NULL){
1961 archive_error(ofile, "internal error. ofile_next_member() called "
1962 "but the ofile struct does not have an archive "
1963 "member selected");
1964 return(FALSE);
1967 /* figure out the offset to the next member */
1968 offset = ofile->member_offset + rnd(ofile->member_size,sizeof(short));
1969 #ifdef OTOOL
1970 if((addr - ofile->file_addr) + offset > ofile->file_size){
1971 archive_error(ofile, "offset to next member extends past the end "
1972 "of the file");
1973 return(FALSE);
1975 #endif /* OTOOL */
1976 /* if now at the end of the file then no more members */
1977 if(offset == size)
1978 goto cleanup;
1979 if(offset > size){
1980 archive_error(ofile, "truncated or malformed (archive header of "
1981 "next member extends past the end of the file)");
1982 return(FALSE);
1985 /* now we know there is a next member so set it up */
1986 ar_hdr = (struct ar_hdr *)(addr + offset);
1987 offset += sizeof(struct ar_hdr);
1988 ofile->member_offset = offset;
1989 ofile->member_addr = addr + offset;
1990 ofile->member_size = strtoul(ar_hdr->ar_size, NULL, 10);
1991 ofile->member_ar_hdr = ar_hdr;
1992 ofile->member_name = ar_hdr->ar_name;
1993 if(strncmp(ofile->member_name, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0){
1994 ofile->member_name = ar_hdr->ar_name + sizeof(struct ar_hdr);
1995 ar_name_size = strtoul(ar_hdr->ar_name + sizeof(AR_EFMT1) - 1,
1996 NULL, 10);
1997 ofile->member_name_size = ar_name_size;
1998 ofile->member_offset += ar_name_size;
1999 ofile->member_addr += ar_name_size;
2000 ofile->member_size -= ar_name_size;
2002 else{
2003 ofile->member_name_size = size_ar_name(ar_hdr);
2004 ar_name_size = 0;
2006 ofile->member_type = OFILE_UNKNOWN;
2007 ofile->object_addr = NULL;
2008 ofile->object_size = 0;
2009 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
2010 ofile->mh = NULL;
2011 ofile->mh64 = NULL;
2012 ofile->load_commands = NULL;
2014 host_byte_sex = get_host_byte_sex();
2016 if(ofile->member_size > sizeof(uint32_t)){
2017 memcpy(&magic, ofile->member_addr, sizeof(uint32_t));
2018 #ifdef __BIG_ENDIAN__
2019 if(magic == FAT_MAGIC)
2020 #endif /* __BIG_ENDIAN__ */
2021 #ifdef __LITTLE_ENDIAN__
2022 if(magic == SWAP_INT(FAT_MAGIC))
2023 #endif /* __LITTLE_ENDIAN__ */
2025 ofile->member_type = OFILE_FAT;
2026 ofile->fat_header = (struct fat_header *)(ofile->member_addr);
2027 #ifdef __LITTLE_ENDIAN__
2028 swap_fat_header(ofile->fat_header, host_byte_sex);
2029 #endif /* __LITTLE_ENDIAN__ */
2030 if(sizeof(struct fat_header) +
2031 ofile->fat_header->nfat_arch *
2032 sizeof(struct fat_arch) > ofile->member_size){
2033 archive_member_error(ofile, "fat file truncated or "
2034 "malformed (fat_arch structs would extend past "
2035 "the end of the archive member)");
2036 goto cleanup;
2038 ofile->fat_archs = (struct fat_arch *)(ofile->member_addr +
2039 sizeof(struct fat_header));
2040 #ifdef __LITTLE_ENDIAN__
2041 swap_fat_arch(ofile->fat_archs,
2042 ofile->fat_header->nfat_arch, host_byte_sex);
2043 #endif /* __LITTLE_ENDIAN__ */
2044 if(check_fat_object_in_archive(ofile) == FALSE)
2045 goto cleanup;
2047 else if(size - (offset + ar_name_size) >=
2048 sizeof(struct mach_header) &&
2049 (magic == MH_MAGIC ||
2050 magic == SWAP_INT(MH_MAGIC))){
2051 #ifdef ALIGNMENT_CHECKS
2052 if((offset + ar_name_size) % 4 != 0){
2053 archive_member_error(ofile, "offset in archive not "
2054 "a multiple of 4 (must be since member is an 32-bit "
2055 "object file)");
2056 goto cleanup;
2058 #endif /* ALIGNMENT_CHECKS */
2059 ofile->member_type = OFILE_Mach_O;
2060 ofile->object_addr = ofile->member_addr;
2061 ofile->object_size = ofile->member_size;
2062 if(magic == MH_MAGIC)
2063 ofile->object_byte_sex = host_byte_sex;
2064 else
2065 ofile->object_byte_sex =
2066 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
2067 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
2068 ofile->mh = (struct mach_header *)ofile->object_addr;
2069 ofile->load_commands = (struct load_command *)
2070 (ofile->object_addr + sizeof(struct mach_header));
2071 if(check_Mach_O(ofile) == CHECK_BAD)
2072 goto cleanup;
2074 else if(size - (offset + ar_name_size) >=
2075 sizeof(struct mach_header_64) &&
2076 (magic == MH_MAGIC_64 ||
2077 magic == SWAP_INT(MH_MAGIC_64))){
2078 #ifdef ALIGNMENT_CHECKS_ARCHIVE_64_BIT
2079 if(archive_64_bit_align_warning == FALSE &&
2080 (offset + ar_name_size) % 8 != 0){
2081 temporary_archive_member_warning(ofile, "offset in archive "
2082 "not a multiple of 8 (must be since member is an "
2083 "64-bit object file)");
2084 archive_64_bit_align_warning = TRUE;
2085 /* goto cleanup; */
2087 #endif /* ALIGNMENT_CHECKS_ARCHIVE_64_BIT */
2088 ofile->member_type = OFILE_Mach_O;
2089 ofile->object_addr = ofile->member_addr;
2090 ofile->object_size = ofile->member_size;
2091 if(magic == MH_MAGIC_64)
2092 ofile->object_byte_sex = host_byte_sex;
2093 else
2094 ofile->object_byte_sex =
2095 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
2096 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
2097 ofile->mh64 = (struct mach_header_64 *)ofile->object_addr;
2098 ofile->load_commands = (struct load_command *)
2099 (ofile->object_addr + sizeof(struct mach_header_64));
2100 if(check_Mach_O(ofile) == CHECK_BAD)
2101 goto cleanup;
2103 #ifdef LTO_SUPPORT
2104 if(ofile->member_type == OFILE_UNKNOWN &&
2105 is_llvm_bitcode(ofile, ofile->member_addr, ofile->member_size) ==
2106 TRUE){
2107 ofile->member_type = OFILE_LLVM_BITCODE;
2108 ofile->object_addr = ofile->member_addr;
2109 ofile->object_size = ofile->member_size;
2111 #endif /* LTO_SUPPORT */
2113 return(TRUE);
2115 cleanup:
2116 if(ofile->member_type == OFILE_FAT){
2117 ofile->fat_header = NULL;
2118 ofile->fat_archs = NULL;
2120 ofile->member_offset = 0;
2121 ofile->member_addr = NULL;
2122 ofile->member_size = 0;
2123 ofile->member_ar_hdr = NULL;
2124 ofile->member_name = NULL;
2125 ofile->member_name_size = 0;
2126 ofile->member_type = OFILE_UNKNOWN;
2127 ofile->object_addr = NULL;
2128 ofile->object_size = 0;
2129 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
2130 ofile->mh = NULL;
2131 ofile->mh64 = NULL;
2132 ofile->load_commands = NULL;
2133 #ifdef LTO_SUPPORT
2134 ofile->lto = NULL;
2135 ofile->lto_cputype = 0;
2136 ofile->lto_cpusubtype = 0;
2137 #endif /* LTO_SUPPORT */
2138 return(FALSE);
2142 * ofile_specific_member() set up the ofile structure (the member_* fields and
2143 * the object file fields if the member is an object file) for the specified
2144 * member member_name.
2146 __private_extern__
2147 enum bool
2148 ofile_specific_member(
2149 const char *member_name,
2150 struct ofile *ofile)
2152 int32_t i;
2153 char *addr;
2154 uint32_t size, offset;
2155 uint32_t magic;
2156 enum byte_sex host_byte_sex;
2157 char *ar_name;
2158 uint32_t ar_name_size;
2159 struct ar_hdr *ar_hdr;
2161 /* These fields are to be filled in by this routine, clear them first */
2162 ofile->member_offset = 0;
2163 ofile->member_addr = NULL;
2164 ofile->member_size = 0;
2165 ofile->member_ar_hdr = NULL;
2166 ofile->member_name = NULL;
2167 ofile->member_name_size = 0;
2168 ofile->member_type = OFILE_UNKNOWN;
2169 ofile->object_addr = NULL;
2170 ofile->object_size = 0;
2171 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
2172 ofile->mh = NULL;
2173 ofile->mh64 = NULL;
2174 ofile->load_commands = NULL;
2177 * Get the address and size of the archive.
2179 if(ofile->file_type == OFILE_FAT){
2180 if(ofile->arch_type != OFILE_ARCHIVE){
2181 error("ofile_specific_member() called on fat file: %s with a "
2182 "non-archive architecture or no architecture selected\n",
2183 ofile->file_name);
2184 return(FALSE);
2186 addr = ofile->file_addr + ofile->fat_archs[ofile->narch].offset;
2187 size = ofile->fat_archs[ofile->narch].size;
2189 else if(ofile->file_type == OFILE_ARCHIVE){
2190 addr = ofile->file_addr;
2191 size = ofile->file_size;
2193 else{
2194 error("ofile_specific_member() called and file type of %s is "
2195 "OFILE_UNKNOWN\n", ofile->file_name);
2196 return(FALSE);
2198 if(size < SARMAG || strncmp(addr, ARMAG, SARMAG) != 0){
2199 archive_error(ofile, "internal error. ofile_specific_member() "
2200 "called but file does not have an archive magic "
2201 "string");
2202 return(FALSE);
2205 offset = SARMAG;
2206 if(offset != size && offset + sizeof(struct ar_hdr) > size){
2207 archive_error(ofile, "truncated or malformed (archive header of "
2208 "first member extends past the end of the file)");
2209 return(FALSE);
2211 while(size > offset){
2212 ar_hdr = (struct ar_hdr *)(addr + offset);
2213 offset += sizeof(struct ar_hdr);
2214 if(strncmp(ar_hdr->ar_name, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0){
2215 #ifdef OTOOL
2216 if(check_extend_format_1(ofile, ar_hdr, size - offset,
2217 &ar_name_size) == CHECK_BAD){
2218 i = size_ar_name(ar_hdr);
2219 ar_name = ar_hdr->ar_name;
2220 ar_name_size = 0;
2222 else
2223 #endif /* OTOOL */
2225 i = strtoul(ar_hdr->ar_name + sizeof(AR_EFMT1) - 1,NULL,10);
2226 ar_name = ar_hdr->ar_name + sizeof(struct ar_hdr);
2227 ar_name_size = i;
2230 else{
2231 i = size_ar_name(ar_hdr);
2232 ar_name = ar_hdr->ar_name;
2233 ar_name_size = 0;
2235 if(i > 0 && strncmp(ar_name, member_name, i) == 0){
2237 ofile->member_name = ar_name;
2238 ofile->member_name_size = i;
2239 ofile->member_offset = offset + ar_name_size;
2240 ofile->member_addr = addr + offset + ar_name_size;
2241 ofile->member_size = strtoul(ar_hdr->ar_size, NULL, 10) -
2242 ar_name_size;
2243 ofile->member_ar_hdr = ar_hdr;
2244 ofile->member_type = OFILE_UNKNOWN;
2246 host_byte_sex = get_host_byte_sex();
2248 if(ofile->member_size > sizeof(uint32_t)){
2249 memcpy(&magic, addr + offset + ar_name_size,
2250 sizeof(uint32_t));
2251 #ifdef __BIG_ENDIAN__
2252 if(magic == FAT_MAGIC)
2253 #endif /* __BIG_ENDIAN__ */
2254 #ifdef __LITTLE_ENDIAN__
2255 if(magic == SWAP_INT(FAT_MAGIC))
2256 #endif /* __LITTLE_ENDIAN__ */
2258 ofile->member_type = OFILE_FAT;
2259 ofile->fat_header =
2260 (struct fat_header *)(addr + offset + ar_name_size);
2261 #ifdef __LITTLE_ENDIAN__
2262 swap_fat_header(ofile->fat_header, host_byte_sex);
2263 #endif /* __LITTLE_ENDIAN__ */
2264 if(sizeof(struct fat_header) +
2265 ofile->fat_header->nfat_arch *
2266 sizeof(struct fat_arch) > ofile->member_size){
2267 archive_member_error(ofile, "fat file truncated or "
2268 "malformed (fat_arch structs would extend "
2269 "past the end of the archive member)");
2270 goto fatcleanup;
2272 ofile->fat_archs =
2273 (struct fat_arch *)(addr + offset + ar_name_size +
2274 sizeof(struct fat_header));
2275 #ifdef __LITTLE_ENDIAN__
2276 swap_fat_arch(ofile->fat_archs,
2277 ofile->fat_header->nfat_arch,
2278 host_byte_sex);
2279 #endif /* __LITTLE_ENDIAN__ */
2280 if(check_fat_object_in_archive(ofile) == FALSE)
2281 goto fatcleanup;
2283 else if(size - (offset + ar_name_size) >=
2284 sizeof(struct mach_header) &&
2285 (magic == MH_MAGIC ||
2286 magic == SWAP_INT(MH_MAGIC))){
2287 #ifdef ALIGNMENT_CHECKS
2288 if((offset + ar_name_size) % 4 != 0){
2289 archive_member_error(ofile, "offset in archive not "
2290 "a multiple of 4) (must be since member is a "
2291 "32-bit object file)");
2292 goto cleanup;
2294 #endif /* ALIGNMENT_CHECKS */
2295 ofile->member_type = OFILE_Mach_O;
2296 ofile->object_addr = ofile->member_addr;
2297 ofile->object_size = ofile->member_size;
2298 if(magic == MH_MAGIC)
2299 ofile->object_byte_sex = host_byte_sex;
2300 else
2301 ofile->object_byte_sex =
2302 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
2303 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
2304 ofile->mh = (struct mach_header *)ofile->object_addr;
2305 ofile->load_commands = (struct load_command *)
2306 (ofile->object_addr + sizeof(struct mach_header));
2307 if(check_Mach_O(ofile) == CHECK_BAD)
2308 goto cleanup;
2310 else if(size - (offset + ar_name_size) >=
2311 sizeof(struct mach_header_64) &&
2312 (magic == MH_MAGIC_64 ||
2313 magic == SWAP_INT(MH_MAGIC_64))){
2314 #ifdef ALIGNMENT_CHECKS_ARCHIVE_64_BIT
2315 if(archive_64_bit_align_warning == FALSE &&
2316 (offset + ar_name_size) % 8 != 0){
2317 temporary_archive_member_warning(ofile, "offset in "
2318 "archive not a multiple of 8) (must be since "
2319 "member is a 64-bit object file)");
2320 archive_64_bit_align_warning = TRUE;
2321 /* goto cleanup; */
2323 #endif /* ALIGNMENT_CHECKS_ARCHIVE_64_BIT */
2324 ofile->member_type = OFILE_Mach_O;
2325 ofile->object_addr = ofile->member_addr;
2326 ofile->object_size = ofile->member_size;
2327 if(magic == MH_MAGIC_64)
2328 ofile->object_byte_sex = host_byte_sex;
2329 else
2330 ofile->object_byte_sex =
2331 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
2332 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
2333 ofile->mh64 = (struct mach_header_64 *)
2334 ofile->object_addr;
2335 ofile->load_commands = (struct load_command *)
2336 (ofile->object_addr +sizeof(struct mach_header_64));
2337 if(check_Mach_O(ofile) == CHECK_BAD)
2338 goto cleanup;
2341 #ifdef LTO_SUPPORT
2342 if(ofile->member_type == OFILE_UNKNOWN &&
2343 is_llvm_bitcode(ofile, ofile->member_addr,
2344 ofile->member_size) == TRUE){
2345 ofile->member_type = OFILE_LLVM_BITCODE;
2346 ofile->object_addr = ofile->member_addr;
2347 ofile->object_size = ofile->member_size;
2349 #endif /* LTO_SUPPORT */
2350 return(TRUE);
2352 offset += rnd(strtoul(ar_hdr->ar_size, NULL, 10),
2353 sizeof(short));
2355 archive_error(ofile, "does not contain a member named: %s",
2356 member_name);
2357 fatcleanup:
2358 ofile->fat_header = NULL;
2359 ofile->fat_archs = NULL;
2360 cleanup:
2361 ofile->member_offset = 0;
2362 ofile->member_addr = NULL;
2363 ofile->member_size = 0;
2364 ofile->member_ar_hdr = NULL;
2365 ofile->member_name = NULL;
2366 ofile->member_name_size = 0;
2367 ofile->member_type = OFILE_UNKNOWN;
2368 ofile->object_addr = NULL;
2369 ofile->object_size = 0;
2370 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
2371 ofile->mh = NULL;
2372 ofile->mh64 = NULL;
2373 ofile->load_commands = NULL;
2374 #ifdef LTO_SUPPORT
2375 ofile->lto = NULL;
2376 ofile->lto_cputype = 0;
2377 ofile->lto_cpusubtype = 0;
2378 #endif /* LTO_SUPPORT */
2379 return(FALSE);
2383 * ofile_first_module() set up the ofile structure (the dylib_module field)
2384 * for the first module of an MH_DYLIB or MH_DYLIB_STUB file.
2386 __private_extern__
2387 enum bool
2388 ofile_first_module(
2389 struct ofile *ofile)
2391 uint32_t i, ncmds;
2392 struct symtab_command *st;
2393 struct dysymtab_command *dyst;
2394 struct load_command *lc;
2395 enum bool swapped;
2396 enum byte_sex host_byte_sex;
2397 struct dylib_module m;
2398 struct dylib_module_64 m64;
2399 char *strings;
2401 /* These fields are to be filled in by this routine, clear them first */
2402 ofile->modtab = NULL;
2403 ofile->modtab64 = NULL;
2404 ofile->nmodtab = 0;
2405 ofile->dylib_module = NULL;
2406 ofile->dylib_module64 = NULL;
2407 ofile->dylib_module_name = NULL;
2409 if(ofile->file_type == OFILE_FAT){
2410 if(ofile->arch_type != OFILE_Mach_O &&
2411 (ofile->mh_filetype != MH_DYLIB &&
2412 ofile->mh_filetype != MH_DYLIB_STUB)){
2413 error("ofile_first_module() called on fat file: %s with a "
2414 "non-MH_DYLIB architecture or no architecture selected\n",
2415 ofile->file_name);
2416 return(FALSE);
2419 else if(ofile->arch_type != OFILE_Mach_O &&
2420 (ofile->mh_filetype != MH_DYLIB &&
2421 ofile->mh_filetype != MH_DYLIB_STUB)){
2422 error("ofile_first_module() called and file type of %s is "
2423 "non-MH_DYLIB\n", ofile->file_name);
2424 return(FALSE);
2427 st = NULL;
2428 dyst = NULL;
2429 lc = ofile->load_commands;
2430 if(ofile->mh != NULL)
2431 ncmds = ofile->mh->ncmds;
2432 else
2433 ncmds = ofile->mh64->ncmds;
2434 for(i = 0; i < ncmds; i++){
2435 if(st == NULL && lc->cmd == LC_SYMTAB){
2436 st = (struct symtab_command *)lc;
2438 else if(lc->cmd == LC_DYSYMTAB){
2439 dyst = (struct dysymtab_command *)lc;
2441 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2443 if(st == NULL || dyst == NULL){
2444 #ifndef OTOOL
2445 Mach_O_error(ofile, "MH_DYLIB format error (does not have a symbol "
2446 "table and/or a dynamic symbol table)");
2447 #endif
2448 return(FALSE);
2450 if(dyst->nmodtab == 0)
2451 return(FALSE);
2453 ofile->nmodtab = dyst->nmodtab;
2454 host_byte_sex = get_host_byte_sex();
2455 swapped = (enum bool)(host_byte_sex != ofile->object_byte_sex);
2456 strings = (char *)(ofile->object_addr + st->stroff);
2458 if(ofile->mh != NULL){
2459 ofile->modtab = (struct dylib_module *)(ofile->object_addr +
2460 dyst->modtaboff);
2461 ofile->dylib_module = ofile->modtab;
2462 m = *ofile->dylib_module;
2463 if(swapped)
2464 swap_dylib_module(&m, 1, host_byte_sex);
2465 ofile->dylib_module_name = strings + m.module_name;
2467 else{
2468 ofile->modtab64 = (struct dylib_module_64 *)(ofile->object_addr +
2469 dyst->modtaboff);
2470 ofile->dylib_module64 = ofile->modtab64;
2471 m64 = *ofile->dylib_module64;
2472 if(swapped)
2473 swap_dylib_module_64(&m64, 1, host_byte_sex);
2474 ofile->dylib_module_name = strings + m64.module_name;
2477 if(check_dylib_module(ofile, st, dyst, strings, 0) == CHECK_BAD)
2478 return(FALSE);
2479 return(TRUE);
2483 * ofile_next_module() set up the ofile structure (the dylib_module field)
2484 * for the next module of an MH_DYLIB or MH_DYLIB_STUB file.
2486 __private_extern__
2487 enum bool
2488 ofile_next_module(
2489 struct ofile *ofile)
2491 uint32_t i, module_index, ncmds;
2492 struct symtab_command *st;
2493 struct dysymtab_command *dyst;
2494 struct load_command *lc;
2495 enum bool swapped;
2496 enum byte_sex host_byte_sex;
2497 struct dylib_module m;
2498 struct dylib_module_64 m64;
2499 char *strings;
2501 if(ofile->file_type == OFILE_FAT){
2502 if(ofile->arch_type != OFILE_Mach_O &&
2503 (ofile->mh_filetype != MH_DYLIB &&
2504 ofile->mh_filetype != MH_DYLIB_STUB)){
2505 error("ofile_next_module() called on fat file: %s with a "
2506 "non-MH_DYLIB architecture or no architecture selected\n",
2507 ofile->file_name);
2508 return(FALSE);
2511 else if(ofile->arch_type != OFILE_Mach_O &&
2512 (ofile->mh_filetype != MH_DYLIB &&
2513 ofile->mh_filetype != MH_DYLIB_STUB)){
2514 error("ofile_next_module() called and file type of %s is "
2515 "non-MH_DYLIB\n", ofile->file_name);
2516 return(FALSE);
2518 st = NULL;
2519 dyst = NULL;
2520 lc = ofile->load_commands;
2521 if(ofile->mh != NULL)
2522 ncmds = ofile->mh->ncmds;
2523 else
2524 ncmds = ofile->mh64->ncmds;
2525 for(i = 0; i < ncmds; i++){
2526 if(st == NULL && lc->cmd == LC_SYMTAB){
2527 st = (struct symtab_command *)lc;
2529 else if(lc->cmd == LC_DYSYMTAB){
2530 dyst = (struct dysymtab_command *)lc;
2532 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2534 if(st == NULL || dyst == NULL){
2535 #ifndef OTOOL
2536 Mach_O_error(ofile, "MH_DYLIB format error (does not have a symbol "
2537 "table and/or a dynamic symbol table)");
2538 #endif
2539 return(FALSE);
2542 if(ofile->mh != NULL)
2543 module_index = (ofile->dylib_module + 1) - ofile->modtab;
2544 else
2545 module_index = (ofile->dylib_module64 + 1) - ofile->modtab64;
2546 if(module_index >= ofile->nmodtab)
2547 return(FALSE);
2549 host_byte_sex = get_host_byte_sex();
2550 swapped = (enum bool)(host_byte_sex != ofile->object_byte_sex);
2551 strings = (char *)(ofile->object_addr + st->stroff);
2553 if(ofile->mh != NULL){
2554 ofile->dylib_module++;
2555 m = *ofile->dylib_module;
2556 if(swapped)
2557 swap_dylib_module(&m, 1, host_byte_sex);
2558 ofile->dylib_module_name = strings + m.module_name;
2560 else{
2561 ofile->dylib_module64++;
2562 m64 = *ofile->dylib_module64;
2563 if(swapped)
2564 swap_dylib_module_64(&m64, 1, host_byte_sex);
2565 ofile->dylib_module_name = strings + m64.module_name;
2567 if(check_dylib_module(ofile, st, dyst, strings, module_index) ==
2568 CHECK_BAD)
2569 return(FALSE);
2570 return(TRUE);
2574 * ofile_specific_module() set up the ofile structure (the dylib_module fields)
2575 * for the specified module, module_name, of an MH_DYLIB or an MH_DYLIB_STUB
2576 * file.
2578 __private_extern__
2579 enum bool
2580 ofile_specific_module(
2581 const char *module_name,
2582 struct ofile *ofile)
2584 uint32_t i, ncmds;
2585 enum bool swapped;
2586 enum byte_sex host_byte_sex;
2587 struct symtab_command *st;
2588 struct dysymtab_command *dyst;
2589 struct load_command *lc;
2590 struct dylib_module *p, m;
2591 struct dylib_module_64 *p64, m64;
2592 char *strings;
2594 /* These fields are to be filled in by this routine, clear them first */
2595 ofile->modtab = NULL;
2596 ofile->modtab64 = NULL;
2597 ofile->nmodtab = 0;
2598 ofile->dylib_module = NULL;
2599 ofile->dylib_module64 = NULL;
2600 ofile->dylib_module_name = NULL;
2602 if(ofile->file_type == OFILE_FAT){
2603 if(ofile->arch_type != OFILE_Mach_O &&
2604 (ofile->mh_filetype != MH_DYLIB &&
2605 ofile->mh_filetype != MH_DYLIB_STUB)){
2606 error("ofile_specific_module() called on fat file: %s with a "
2607 "non-MH_DYLIB architecture or no architecture selected\n",
2608 ofile->file_name);
2609 return(FALSE);
2612 else if(ofile->arch_type != OFILE_Mach_O &&
2613 (ofile->mh_filetype != MH_DYLIB &&
2614 ofile->mh_filetype != MH_DYLIB_STUB)){
2615 error("ofile_specific_module() called and file type of %s is "
2616 "non-MH_DYLIB\n", ofile->file_name);
2617 return(FALSE);
2620 st = NULL;
2621 dyst = NULL;
2622 lc = ofile->load_commands;
2623 if(ofile->mh != NULL)
2624 ncmds = ofile->mh->ncmds;
2625 else
2626 ncmds = ofile->mh64->ncmds;
2627 for(i = 0; i < ncmds; i++){
2628 if(st == NULL && lc->cmd == LC_SYMTAB){
2629 st = (struct symtab_command *)lc;
2631 else if(lc->cmd == LC_DYSYMTAB){
2632 dyst = (struct dysymtab_command *)lc;
2634 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2636 if(st == NULL || dyst == NULL){
2637 #ifndef OTOOL
2638 Mach_O_error(ofile, "MH_DYLIB format error (does not have a symbol "
2639 "table and/or a dynamic symbol table)");
2640 #endif
2641 return(FALSE);
2643 if(dyst->nmodtab == 0)
2644 return(FALSE);
2646 host_byte_sex = get_host_byte_sex();
2647 swapped = (enum bool)(host_byte_sex != ofile->object_byte_sex);
2648 strings = (char *)(ofile->object_addr + st->stroff);
2650 if(ofile->mh != NULL){
2651 ofile->nmodtab = dyst->nmodtab;
2652 ofile->modtab = (struct dylib_module *)(ofile->object_addr +
2653 dyst->modtaboff);
2654 p = ofile->modtab;
2655 for(i = 0; i < dyst->nmodtab; i++){
2656 m = *p;
2657 if(swapped)
2658 swap_dylib_module(&m, 1, host_byte_sex);
2659 ofile->dylib_module = p;
2660 if(check_dylib_module(ofile, st, dyst, strings, i) == CHECK_BAD)
2661 return(FALSE);
2662 if(strcmp(module_name, strings + m.module_name) == 0){
2663 ofile->dylib_module_name = strings + m.module_name;
2664 return(TRUE);
2666 p++;
2668 m = *ofile->dylib_module;
2669 if(swapped)
2670 swap_dylib_module(&m, 1, host_byte_sex);
2671 ofile->dylib_module_name = strings + m.module_name;
2673 else{
2674 ofile->nmodtab = dyst->nmodtab;
2675 ofile->modtab64 = (struct dylib_module_64 *)(ofile->object_addr +
2676 dyst->modtaboff);
2677 p64 = ofile->modtab64;
2678 for(i = 0; i < dyst->nmodtab; i++){
2679 m64 = *p64;
2680 if(swapped)
2681 swap_dylib_module_64(&m64, 1, host_byte_sex);
2682 ofile->dylib_module64 = p64;
2683 if(check_dylib_module(ofile, st, dyst, strings, i) == CHECK_BAD)
2684 return(FALSE);
2685 if(strcmp(module_name, strings + m64.module_name) == 0){
2686 ofile->dylib_module_name = strings + m64.module_name;
2687 return(TRUE);
2689 p64++;
2691 m64 = *ofile->dylib_module64;
2692 if(swapped)
2693 swap_dylib_module_64(&m64, 1, host_byte_sex);
2694 ofile->dylib_module_name = strings + m64.module_name;
2696 #ifndef OTOOL
2697 Mach_O_error(ofile, "does not contain a module named: %s", module_name);
2698 #endif
2699 ofile->modtab = NULL;
2700 ofile->nmodtab = 0;
2701 ofile->dylib_module = NULL;
2702 ofile->dylib_module_name = NULL;
2703 return(FALSE);
2706 #ifdef DEBUG
2707 __private_extern__
2708 void
2709 ofile_print(
2710 struct ofile *ofile)
2712 printf("file_name = %s\n", ofile->file_name);
2713 printf("file_addr = 0x%x\n", (unsigned int)ofile->file_addr);
2714 printf("file_size = 0x%x\n", (unsigned int)ofile->file_size);
2715 printf("file_type = 0x%x\n", (unsigned int)ofile->file_type);
2716 printf("fat_header = 0x%x\n", (unsigned int)ofile->fat_header);
2717 printf("fat_archs = 0x%x\n", (unsigned int)ofile->fat_archs);
2718 printf("narch = 0x%x\n", (unsigned int)ofile->narch);
2719 printf("arch_type = 0x%x\n", (unsigned int)ofile->arch_type);
2720 printf("arch_flag.name = %s\n", ofile->arch_flag.name);
2721 printf("arch_flag.cputype = 0x%x\n",
2722 (unsigned int)ofile->arch_flag.cputype);
2723 printf("arch_flag.cpusubtype = 0x%x\n",
2724 (unsigned int)ofile->arch_flag.cpusubtype);
2725 printf("member_offset = 0x%x\n", (unsigned int)ofile->member_offset);
2726 printf("member_addr = 0x%x\n", (unsigned int)ofile->member_addr);
2727 printf("member_size = 0x%x\n", (unsigned int)ofile->member_size);
2728 printf("member_ar_hdr = 0x%x\n", (unsigned int)ofile->member_ar_hdr);
2729 printf("member_type = 0x%x\n", (unsigned int)ofile->member_type);
2730 printf("archive_cputype = 0x%x\n",
2731 (unsigned int)ofile->archive_cputype);
2732 printf("archive_cpusubtype = 0x%x\n",
2733 (unsigned int)ofile->archive_cpusubtype);
2734 printf("object_addr = 0x%x\n", (unsigned int)ofile->object_addr);
2735 printf("object_size = 0x%x\n", (unsigned int)ofile->object_size);
2736 printf("object_byte_sex = 0x%x\n",
2737 (unsigned int)ofile->object_byte_sex);
2738 printf("mh = 0x%x\n", (unsigned int)ofile->mh);
2739 printf("mh64 = 0x%x\n", (unsigned int)ofile->mh64);
2740 printf("load_commands = 0x%x\n", (unsigned int)ofile->load_commands);
2742 #endif /* DEBUG */
2745 * check_fat() checks the fat ofile for correctness (the fat_header and
2746 * fat_archs are assumed to be in the host byte sex).
2748 static
2749 enum check_type
2750 check_fat(
2751 struct ofile *ofile)
2753 #ifdef OTOOL
2754 return(CHECK_GOOD);
2755 #else /* !defined OTOOL */
2757 uint32_t i, j;
2758 uint64_t big_size;
2760 if(ofile->file_type != OFILE_FAT){
2761 error("internal error. check_fat() call and file type of: %s is "
2762 "not OFILE_FAT\n", ofile->file_name);
2763 return(CHECK_BAD);
2765 if(ofile->fat_header->nfat_arch == 0){
2766 error("fat file: %s malformed (contains zero architecture types)",
2767 ofile->file_name);
2768 return(CHECK_BAD);
2770 for(i = 0; i < ofile->fat_header->nfat_arch; i++){
2771 big_size = ofile->fat_archs[i].offset;
2772 big_size += ofile->fat_archs[i].size;
2773 if(big_size > ofile->file_size){
2774 error("fat file: %s truncated or malformed (offset plus size "
2775 "of cputype (%d) cpusubtype (%d) extends past the "
2776 "end of the file)", ofile->file_name,
2777 ofile->fat_archs[i].cputype,
2778 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK);
2779 return(CHECK_BAD);
2781 if(ofile->fat_archs[i].align > MAXSECTALIGN){
2782 error("fat file: %s align (2^%u) too large for cputype (%d) "
2783 "cpusubtype (%d) (maximum 2^%d)", ofile->file_name,
2784 ofile->fat_archs[i].align, ofile->fat_archs[i].cputype,
2785 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK,
2786 MAXSECTALIGN);
2787 return(CHECK_BAD);
2789 if(ofile->fat_archs[i].offset %
2790 (1 << ofile->fat_archs[i].align) != 0){
2791 error("fat file: %s offset: %u for cputype (%d) cpusubtype "
2792 "(%d)) not aligned on it's alignment (2^%u)",
2793 ofile->file_name,
2794 ofile->fat_archs[i].offset,
2795 ofile->fat_archs[i].cputype,
2796 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK,
2797 ofile->fat_archs[i].align);
2798 return(CHECK_BAD);
2801 for(i = 0; i < ofile->fat_header->nfat_arch; i++){
2802 for(j = i + 1; j < ofile->fat_header->nfat_arch; j++){
2803 if(ofile->fat_archs[i].cputype ==
2804 ofile->fat_archs[j].cputype &&
2805 (ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK) ==
2806 (ofile->fat_archs[j].cpusubtype & ~CPU_SUBTYPE_MASK)){
2807 error("fat file: %s contains two of the same "
2808 "architecture (cputype (%d) cpusubtype (%d))",
2809 ofile->file_name, ofile->fat_archs[i].cputype,
2810 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK);
2811 return(CHECK_BAD);
2815 return(CHECK_GOOD);
2816 #endif /* OTOOL */
2820 * check_fat_object_in_archive() checks the fat object file which is a member
2821 * of a thin archive for correctness (the fat_header and fat_archs are assumed
2822 * to be in the host byte sex). This is not a legal form but allowed when
2823 * archives_with_fat_objects is TRUE when ofile_map() is called.
2825 static
2826 enum check_type
2827 check_fat_object_in_archive(
2828 struct ofile *ofile)
2830 uint32_t i, j;
2831 uint32_t magic;
2833 if(ofile->file_type != OFILE_ARCHIVE){
2834 error("internal error. check_fat_object_in_archive() called and "
2835 "file type of: %s is not OFILE_ARCHIVE\n", ofile->file_name);
2836 return(CHECK_BAD);
2838 if(ofile->fat_header->nfat_arch == 0){
2839 archive_member_error(ofile, "fat file malformed (contains zero "
2840 "architecture types)");
2841 return(CHECK_BAD);
2843 for(i = 0; i < ofile->fat_header->nfat_arch; i++){
2844 if(ofile->fat_archs[i].offset + ofile->fat_archs[i].size >
2845 ofile->member_size){
2846 archive_member_error(ofile, "fat file truncated or malformed "
2847 "(offset plus size of cputype (%d) cpusubtype (%d) "
2848 "extends past the end of the file)",
2849 ofile->fat_archs[i].cputype,
2850 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK);
2851 return(CHECK_BAD);
2853 if(ofile->fat_archs[i].align > MAXSECTALIGN){
2854 archive_member_error(ofile, "fat file's align (2^%u) too "
2855 "large for cputype (%d) cpusubtype (%d) (maximum 2^%d)",
2856 ofile->fat_archs[i].align, ofile->fat_archs[i].cputype,
2857 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK,
2858 MAXSECTALIGN);
2859 return(CHECK_BAD);
2861 if(ofile->fat_archs[i].offset %
2862 (1 << ofile->fat_archs[i].align) != 0){
2863 archive_member_error(ofile, "fat file's offset: %u for "
2864 "cputype (%d) cpusubtype (%d) not aligned on it's "
2865 "alignment (2^%u)", ofile->fat_archs[i].offset,
2866 ofile->fat_archs[i].cputype,
2867 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK,
2868 ofile->fat_archs[i].align);
2869 return(CHECK_BAD);
2873 * The only supported format where fat files are allowed to appear
2874 * in archives is when the fat file contains only object files.
2876 if(ofile->fat_archs[i].size < sizeof(struct mach_header)){
2877 archive_member_error(ofile, "fat file for cputype (%d) "
2878 "cpusubtype (%d) is not an object file (size too small "
2879 "to be an object file)", ofile->fat_archs[i].cputype,
2880 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK);
2881 return(CHECK_BAD);
2883 memcpy(&magic,
2884 ofile->file_addr + ofile->member_offset +
2885 ofile->fat_archs[i].offset,
2886 sizeof(uint32_t));
2887 if(magic == MH_MAGIC || magic == SWAP_INT(MH_MAGIC)){
2888 #ifdef ALIGNMENT_CHECKS
2889 if((ofile->member_offset + ofile->fat_archs[i].offset) %
2890 4 != 0){
2891 archive_member_error(ofile, "fat object file's offset in "
2892 "archive not a multiple of 4) (must be since "
2893 "member is a 32-bit object file)");
2894 return(CHECK_BAD);
2896 #endif /* ALIGNMENT_CHECKS */
2898 else if(magic == MH_MAGIC_64 || magic == SWAP_INT(MH_MAGIC_64)){
2899 #ifdef ALIGNMENT_CHECKS_ARCHIVE_64_BIT
2900 if(archive_64_bit_align_warning == FALSE &&
2901 (ofile->member_offset + ofile->fat_archs[i].offset) %
2902 8 != 0){
2903 temporary_archive_member_warning(ofile, "fat object file's "
2904 "offset in archive not a multiple of 8) (must be since "
2905 "member is a 64-bit object file)");
2906 archive_64_bit_align_warning = TRUE;
2907 /* return(CHECK_BAD); */
2909 #endif /* ALIGNMENT_CHECKS_ARCHIVE_64_BIT */
2911 else{
2912 archive_member_error(ofile, "fat file for cputype (%d) "
2913 "cpusubtype (%d) is not an object file (bad magic "
2914 "number)", ofile->fat_archs[i].cputype,
2915 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK);
2916 return(CHECK_BAD);
2919 for(i = 0; i < ofile->fat_header->nfat_arch; i++){
2920 for(j = i + 1; j < ofile->fat_header->nfat_arch; j++){
2921 if(ofile->fat_archs[i].cputype ==
2922 ofile->fat_archs[j].cputype &&
2923 (ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK) ==
2924 (ofile->fat_archs[j].cpusubtype & ~CPU_SUBTYPE_MASK)){
2925 archive_member_error(ofile, "fat file contains two of the "
2926 "same architecture (cputype (%d) cpusubtype (%d))",
2927 ofile->fat_archs[i].cputype,
2928 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK);
2929 return(CHECK_BAD);
2933 return(CHECK_GOOD);
2937 * check_archive() checks the archive referenced in the ofile for correctness.
2939 static
2940 enum check_type
2941 check_archive(
2942 struct ofile *ofile,
2943 enum bool archives_with_fat_objects)
2945 #ifdef OTOOL
2946 return(CHECK_GOOD);
2947 #else /* !defined OTOOL */
2948 char *addr;
2949 uint32_t size, offset;
2950 uint64_t big_size;
2951 uint32_t magic;
2952 enum byte_sex host_byte_sex;
2953 enum bool swapped;
2954 struct mach_header mh;
2955 struct mach_header_64 mh64;
2956 struct ar_hdr *ar_hdr;
2957 uint32_t ar_name_size;
2960 * Get the address and size of the archive (as well as the cputype and
2961 * cpusubtype if known) and make sure it is an archive.
2963 if(ofile->file_type == OFILE_FAT){
2964 addr = ofile->file_addr + ofile->fat_archs[ofile->narch].offset;
2965 size = ofile->fat_archs[ofile->narch].size;
2966 ofile->archive_cputype = ofile->fat_archs[ofile->narch].cputype;
2967 ofile->archive_cpusubtype =
2968 ofile->fat_archs[ofile->narch].cpusubtype;
2970 else if(ofile->file_type == OFILE_ARCHIVE){
2971 addr = ofile->file_addr;
2972 size = ofile->file_size;
2973 ofile->archive_cputype = 0;
2974 ofile->archive_cpusubtype = 0;
2976 else{
2977 error("internal error. check_archive() call and file type of %s is "
2978 "OFILE_UNKNOWN\n", ofile->file_name);
2979 return(CHECK_BAD);
2981 if(size < SARMAG || strncmp(addr, ARMAG, SARMAG) != 0){
2982 error("internal error. check_archive() call for file %s which does "
2983 "not have an archive magic string", ofile->file_name);
2984 return(CHECK_BAD);
2987 host_byte_sex = get_host_byte_sex();
2989 * Check this archive out to make sure that it does not contain
2990 * any fat files and that all object files it contains have the
2991 * same cputype and subsubtype.
2993 offset = SARMAG;
2994 if(offset == size)
2995 return(CHECK_GOOD);
2996 if(offset != size && offset + sizeof(struct ar_hdr) > size){
2997 archive_error(ofile, "truncated or malformed (archive header of "
2998 "first member extends past the end of the file)");
2999 return(CHECK_BAD);
3001 while(size > offset){
3002 ar_hdr = (struct ar_hdr *)(addr + offset);
3003 ofile->member_offset = offset;
3004 ofile->member_addr = addr + offset;
3005 ofile->member_size = strtoul(ar_hdr->ar_size, NULL, 10);
3006 ofile->member_ar_hdr = ar_hdr;
3007 ofile->member_name = ar_hdr->ar_name;
3008 ofile->member_name_size = size_ar_name(ofile->member_ar_hdr);
3009 offset += sizeof(struct ar_hdr);
3011 * See if this archive member is using extend format #1 where
3012 * the size of the name is in ar_name and the name follows the
3013 * archive header.
3015 ar_name_size = 0;
3016 if(strncmp(ofile->member_name,AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0){
3017 if(check_extend_format_1(ofile, ar_hdr, size - offset,
3018 &ar_name_size) == CHECK_BAD)
3019 return(CHECK_BAD);
3020 ofile->member_name = ar_hdr->ar_name + sizeof(struct ar_hdr);
3021 ofile->member_name_size = ar_name_size;
3022 offset += ar_name_size;
3023 ofile->member_offset += ar_name_size;
3024 ofile->member_addr += ar_name_size;
3025 ofile->member_size -= ar_name_size;
3027 big_size = rnd(ofile->member_size, sizeof(short));
3028 big_size += offset;
3029 if(big_size > size){
3030 archive_member_error(ofile, "size too large (archive "
3031 "member extends past the end of the file)");
3032 return(CHECK_BAD);
3034 if(size - offset > sizeof(uint32_t)){
3035 memcpy(&magic, addr + offset, sizeof(uint32_t));
3036 #ifdef __BIG_ENDIAN__
3037 if(magic == FAT_MAGIC)
3038 #endif /* __BIG_ENDIAN__ */
3039 #ifdef __LITTLE_ENDIAN__
3040 if(magic == SWAP_INT(FAT_MAGIC))
3041 #endif /* __LITTLE_ENDIAN__ */
3043 if(archives_with_fat_objects == FALSE ||
3044 ofile->file_type != OFILE_ARCHIVE){
3045 archive_member_error(ofile, "is a fat file (not "
3046 "allowed in an archive)");
3047 return(CHECK_BAD);
3050 else{
3051 if(size - offset >= sizeof(struct mach_header) &&
3052 (magic == MH_MAGIC || magic == SWAP_INT(MH_MAGIC))){
3053 memcpy(&mh, addr + offset, sizeof(struct mach_header));
3054 if(magic == SWAP_INT(MH_MAGIC)){
3055 magic = MH_MAGIC;
3056 swapped = TRUE;
3057 swap_mach_header(&mh, host_byte_sex);
3059 swapped = FALSE;
3061 else if(size - offset >= sizeof(struct mach_header_64) &&
3062 (magic == MH_MAGIC_64 ||
3063 magic == SWAP_INT(MH_MAGIC_64))){
3064 memcpy(&mh64, addr + offset,
3065 sizeof(struct mach_header_64));
3066 if(magic == SWAP_INT(MH_MAGIC_64)){
3067 magic = MH_MAGIC_64;
3068 swapped = TRUE;
3069 swap_mach_header_64(&mh64, host_byte_sex);
3071 swapped = FALSE;
3073 if(magic == MH_MAGIC){
3074 if(ofile->archive_cputype == 0){
3075 ofile->archive_cputype = mh.cputype;
3076 ofile->archive_cpusubtype = mh.cpusubtype;
3078 else if(ofile->archive_cputype != mh.cputype){
3079 archive_member_error(ofile, "cputype (%d) does not "
3080 "match previous archive members cputype (%d) "
3081 "(all members must match)", mh.cputype,
3082 ofile->archive_cputype);
3085 else if(magic == MH_MAGIC_64){
3086 if(ofile->archive_cputype == 0){
3087 ofile->archive_cputype = mh64.cputype;
3088 ofile->archive_cpusubtype = mh64.cpusubtype;
3090 else if(ofile->archive_cputype != mh64.cputype){
3091 archive_member_error(ofile, "cputype (%d) does not "
3092 "match previous archive members cputype (%d) "
3093 "(all members must match)", mh64.cputype,
3094 ofile->archive_cputype);
3099 offset += rnd(ofile->member_size, sizeof(short));
3101 ofile->member_offset = 0;
3102 ofile->member_addr = NULL;
3103 ofile->member_size = 0;
3104 ofile->member_ar_hdr = NULL;;
3105 ofile->member_name = NULL;
3106 ofile->member_name_size = 0;
3107 return(CHECK_GOOD);
3108 #endif /* OTOOL */
3112 * check_extend_format_1() checks the archive header for extended format #1.
3114 static
3115 enum check_type
3116 check_extend_format_1(
3117 struct ofile *ofile,
3118 struct ar_hdr *ar_hdr,
3119 uint32_t size_left,
3120 uint32_t *member_name_size)
3122 char *p, *endp, buf[sizeof(ar_hdr->ar_name)+1];
3123 uint32_t ar_name_size;
3125 *member_name_size = 0;
3127 buf[sizeof(ar_hdr->ar_name)] = '\0';
3128 memcpy(buf, ar_hdr->ar_name, sizeof(ar_hdr->ar_name));
3129 p = buf + sizeof(AR_EFMT1) - 1;
3130 if(isdigit(*p) == 0){
3131 archive_error(ofile, "malformed (ar_name: %.*s for archive "
3132 "extend format #1 starts with non-digit)",
3133 (int)sizeof(ar_hdr->ar_name), ar_hdr->ar_name);
3134 return(CHECK_BAD);
3136 ar_name_size = strtoul(p, &endp, 10);
3137 if(ar_name_size == UINT_MAX && errno == ERANGE){
3138 archive_error(ofile, "malformed (size in ar_name: %.*s for "
3139 "archive extend format #1 overflows uint32_t)",
3140 (int)sizeof(ar_hdr->ar_name), ar_hdr->ar_name);
3141 return(CHECK_BAD);
3143 while(*endp == ' ' && *endp != '\0')
3144 endp++;
3145 if(*endp != '\0'){
3146 archive_error(ofile, "malformed (size in ar_name: %.*s for "
3147 "archive extend format #1 contains non-digit and "
3148 "non-space characters)", (int)sizeof(ar_hdr->ar_name),
3149 ar_hdr->ar_name);
3150 return(CHECK_BAD);
3152 if(ar_name_size > size_left){
3153 archive_error(ofile, "truncated or malformed (archive name "
3154 "of member extends past the end of the file)");
3155 return(CHECK_BAD);
3157 *member_name_size = ar_name_size;
3158 return(CHECK_GOOD);
3162 * check_archive_toc() checks the archive table of contents referenced in the
3163 * thin archive via the ofile for correctness and if bad sets the bad_toc field
3164 * in the ofile struct to TRUE. If not it sets the other toc_* fields that
3165 * ranlib(1) uses to know it can't update the table of contents and doesn't
3166 * have to totally rebuild it. And by this always returning CHECK_GOOD it
3167 * allows otool(1) to print messed up tables of contents for debugging.
3169 static
3170 enum check_type
3171 check_archive_toc(
3172 struct ofile *ofile)
3174 uint32_t i, symdef_length, offset, nranlibs, strsize;
3175 enum byte_sex host_byte_sex, toc_byte_sex;
3176 struct ranlib *ranlibs;
3177 char *strings;
3179 ofile->toc_ranlibs = NULL;
3180 ofile->toc_nranlibs = 0;
3181 ofile->toc_strings = NULL;
3182 ofile->toc_strsize = 0;
3185 * Note this can only be called when the whole file is a thin archive.
3187 if(ofile->file_type != OFILE_ARCHIVE)
3188 return(CHECK_GOOD);
3190 symdef_length = ofile->toc_size;
3192 * The contents of a __.SYMDEF file is begins with a 32-bit word giving
3193 * the size in bytes of ranlib structures which immediately follow, and
3194 * then continues with a string table consisting of a 32-bit word giving
3195 * the number of bytes of strings which follow and then the strings
3196 * themselves. So the smallest valid size is two 32-bit words long.
3198 if(symdef_length < 2 * sizeof(uint32_t)){
3200 * Size of table of contents for archive too small to be a valid
3201 * table of contents.
3203 ofile->toc_bad = TRUE;
3204 return(CHECK_GOOD);
3206 host_byte_sex = get_host_byte_sex();
3207 toc_byte_sex = get_toc_byte_sex(ofile->file_addr, ofile->file_size);
3208 if(toc_byte_sex == UNKNOWN_BYTE_SEX){
3210 * Can't determine the byte order of table of contents as it
3211 * contains no Mach-O files.
3213 ofile->toc_bad = TRUE;
3214 return(CHECK_GOOD);
3216 offset = 0;
3217 nranlibs = *((uint32_t *)(ofile->toc_addr + offset));
3218 if(toc_byte_sex != host_byte_sex)
3219 nranlibs = SWAP_INT(nranlibs);
3220 nranlibs = nranlibs / sizeof(struct ranlib);
3221 offset += sizeof(uint32_t);
3222 ranlibs = (struct ranlib *)(ofile->toc_addr + offset);
3223 offset += sizeof(struct ranlib) * nranlibs;
3224 if(nranlibs == 0)
3225 return(CHECK_GOOD);
3226 if(offset - (2 * sizeof(uint32_t)) > symdef_length){
3228 * Truncated or malformed archive. The ranlib structures in table
3229 * of contents extends past the end of the table of contents.
3231 ofile->toc_bad = TRUE;
3232 return(CHECK_GOOD);
3234 strsize = *((uint32_t *)(ofile->toc_addr + offset));
3235 if(toc_byte_sex != host_byte_sex)
3236 strsize = SWAP_INT(strsize);
3237 offset += sizeof(uint32_t);
3238 strings = ofile->toc_addr + offset;
3239 offset += strsize;
3240 if(offset - (2 * sizeof(uint32_t)) > symdef_length){
3242 * Truncated or malformed archive. The ranlib strings in table of
3243 * contents extends past the end of the table of contents.
3245 ofile->toc_bad = TRUE;
3246 return(CHECK_GOOD);
3248 if(symdef_length == 2 * sizeof(uint32_t))
3249 return(CHECK_GOOD);
3252 * Check the string offset and the member offsets of the ranlib structs.
3254 if(toc_byte_sex != host_byte_sex)
3255 swap_ranlib(ranlibs, nranlibs, host_byte_sex);
3256 for(i = 0; i < nranlibs; i++){
3257 if(ranlibs[i].ran_un.ran_strx >= strsize){
3259 * Malformed table of contents. The ranlib struct at this index
3260 * has a bad string index field.
3262 ofile->toc_bad = TRUE;
3263 return(CHECK_GOOD);
3265 if(ranlibs[i].ran_off >= ofile->file_size){
3267 * Malformed table of contents. The ranlib struct at this index
3268 * has a bad library member offset field.
3270 ofile->toc_bad = TRUE;
3271 return(CHECK_GOOD);
3274 * These should be on 4 byte boundaries because the maximum
3275 * alignment of the header structures and relocation are 4 bytes.
3276 * But this is has to be 2 bytes because that's the way ar(1) has
3277 * worked historicly in the past. Fortunately this works on the
3278 * 68k machines but will have to change when this is on a real
3279 * machine.
3281 #if defined(mc68000) || defined(__i386__)
3282 if(ranlibs[i].ran_off % sizeof(short) != 0){
3284 * Malformed table of contents. This ranlib struct library
3285 * member offset not a multiple 2 bytes.
3287 ofile->toc_bad = TRUE;
3288 return(CHECK_GOOD);
3290 #else
3291 if(ranlibs[i].ran_off % sizeof(uint32_t) != 0){
3293 * Malformed table of contents. This ranlib struct library
3294 * member offset not a multiple of 4 bytes.
3296 ofile->toc_bad = TRUE;
3297 return(CHECK_GOOD);
3299 #endif
3301 ofile->toc_ranlibs = ranlibs;
3302 ofile->toc_nranlibs = nranlibs;
3303 ofile->toc_strings = strings;
3304 ofile->toc_strsize = strsize;
3305 return(CHECK_GOOD);
3309 * check_Mach_O() checks the object file's mach header and load commands
3310 * referenced in the ofile for correctness (this also swaps the mach header
3311 * and load commands into the host byte sex if needed).
3313 static
3314 enum check_type
3315 check_Mach_O(
3316 struct ofile *ofile)
3318 #ifdef OTOOL
3319 return(CHECK_GOOD);
3320 #else /* !defined OTOOL */
3321 uint32_t size, i, j, ncmds, sizeofcmds, load_command_multiple, sizeofhdrs;
3322 cpu_type_t cputype;
3323 char *addr, *cmd_name, *element_name;
3324 enum byte_sex host_byte_sex;
3325 enum bool swapped;
3326 struct mach_header *mh;
3327 struct mach_header_64 *mh64;
3328 struct load_command *load_commands, *lc, l;
3329 struct segment_command *sg;
3330 struct segment_command_64 *sg64;
3331 struct section *s;
3332 struct section_64 *s64;
3333 struct symtab_command *st;
3334 struct dysymtab_command *dyst;
3335 struct symseg_command *ss;
3336 struct fvmlib_command *fl;
3337 struct dylib_command *dl;
3338 struct sub_framework_command *sub;
3339 struct sub_umbrella_command *usub;
3340 struct sub_library_command *lsub;
3341 struct sub_client_command *csub;
3342 struct prebound_dylib_command *pbdylib;
3343 struct dylinker_command *dyld;
3344 struct thread_command *ut;
3345 struct ident_command *id;
3346 struct routines_command *rc;
3347 struct routines_command_64 *rc64;
3348 struct twolevel_hints_command *hints;
3349 struct linkedit_data_command *code_sig, *split_info, *func_starts,
3350 *data_in_code, *code_sign_drs, *linkedit_data;
3351 struct version_min_command *vers;
3352 struct prebind_cksum_command *cs;
3353 struct encryption_info_command *encrypt_info;
3354 struct dyld_info_command *dyld_info;
3355 struct uuid_command *uuid;
3356 struct rpath_command *rpath;
3357 struct entry_point_command *ep;
3358 struct source_version_command *sv;
3359 uint32_t flavor, count, nflavor;
3360 char *p, *state;
3361 uint32_t sizeof_nlist, sizeof_dylib_module;
3362 char *struct_dylib_module_name, *struct_nlist_name;
3363 uint64_t big_size, big_end, big_load_end;
3364 struct element elements;
3366 elements.offset = 0;
3367 elements.size = 0;
3368 elements.name = NULL;
3369 elements.next = NULL;
3371 addr = ofile->object_addr;
3372 size = ofile->object_size;
3373 mh = ofile->mh;
3374 mh64 = ofile->mh64;
3375 load_commands = ofile->load_commands;
3376 host_byte_sex = get_host_byte_sex();
3377 swapped = (enum bool)(host_byte_sex != ofile->object_byte_sex);
3379 if(ofile->mh != NULL){
3380 if(swapped)
3381 swap_mach_header(mh, host_byte_sex);
3382 big_size = mh->sizeofcmds;
3383 big_size += sizeof(struct mach_header);
3384 if(big_size > size){
3385 Mach_O_error(ofile, "truncated or malformed object (load "
3386 "commands extend past the end of the file)");
3387 return(CHECK_BAD);
3389 sizeofhdrs = big_size;
3390 ofile->mh_cputype = mh->cputype;
3391 ofile->mh_cpusubtype = mh->cpusubtype;
3392 ofile->mh_filetype = mh->filetype;
3393 ncmds = mh->ncmds;
3394 sizeofcmds = mh->sizeofcmds;
3395 cputype = mh->cputype;
3396 load_command_multiple = 4;
3397 sizeof_nlist = sizeof(struct nlist);
3398 struct_nlist_name = "struct nlist";
3399 sizeof_dylib_module = sizeof(struct dylib_module);
3400 struct_dylib_module_name = "struct dylib_module";
3402 else{
3403 if(swapped)
3404 swap_mach_header_64(mh64, host_byte_sex);
3405 big_size = mh64->sizeofcmds;
3406 big_size += sizeof(struct mach_header_64);
3407 if(big_size > size){
3408 Mach_O_error(ofile, "truncated or malformed object (load "
3409 "commands extend past the end of the file)");
3410 return(CHECK_BAD);
3412 sizeofhdrs = big_size;
3413 ofile->mh_cputype = mh64->cputype;
3414 ofile->mh_cpusubtype = mh64->cpusubtype;
3415 ofile->mh_filetype = mh64->filetype;
3416 ncmds = mh64->ncmds;
3417 sizeofcmds = mh64->sizeofcmds;
3418 cputype = mh64->cputype;
3419 load_command_multiple = 8;
3420 sizeof_nlist = sizeof(struct nlist_64);
3421 struct_nlist_name = "struct nlist_64";
3422 sizeof_dylib_module = sizeof(struct dylib_module_64);
3423 struct_dylib_module_name = "struct dylib_module_64";
3425 if(check_overlaping_element(ofile, &elements, 0, sizeofhdrs,
3426 "Mach-O headers") == CHECK_BAD)
3427 goto return_bad;
3428 if(ofile->file_type == OFILE_FAT){
3429 if(ofile->fat_archs[ofile->narch].cputype != ofile->mh_cputype){
3430 Mach_O_error(ofile, "malformed fat file (fat header "
3431 "architecture: %u's cputype does not match "
3432 "object file's mach header)", ofile->narch);
3433 goto return_bad;
3437 * Make a pass through the load commands checking them to the level
3438 * that they can be parsed and all fields with offsets and sizes do
3439 * not extend past the end of the file.
3441 st = NULL;
3442 dyst = NULL;
3443 rc = NULL;
3444 rc64 = NULL;
3445 hints = NULL;
3446 code_sig = NULL;
3447 func_starts = NULL;
3448 data_in_code = NULL;
3449 code_sign_drs = NULL;
3450 split_info = NULL;
3451 cs = NULL;
3452 uuid = NULL;
3453 encrypt_info = NULL;
3454 dyld_info = NULL;
3455 vers = NULL;
3456 big_load_end = 0;
3457 for(i = 0, lc = load_commands; i < ncmds; i++){
3458 l = *lc;
3459 if(swapped)
3460 swap_load_command(&l, host_byte_sex);
3462 * Check load command size for a multiple of load_command_multiple.
3464 if(l.cmdsize % load_command_multiple != 0){
3466 * We have a hack here to allow 64-bit Mach-O core files to
3467 * have LC_THREAD commands that are only a multiple of 4 and
3468 * not 8 to be allowed since the kernel produces them.
3470 if(ofile->mh64 == NULL ||
3471 ofile->mh64->filetype != MH_CORE ||
3472 l.cmd != LC_THREAD ||
3473 l.cmdsize % 4 != 0){
3474 Mach_O_error(ofile, "malformed object (load command %u "
3475 "cmdsize not a multiple of %u)", i,
3476 load_command_multiple);
3477 goto return_bad;
3480 /* check that load command does not extends past end of commands */
3481 big_load_end += l.cmdsize;
3482 if(big_load_end > sizeofcmds){
3483 Mach_O_error(ofile, "truncated or malformed object (load "
3484 "command %u extends past the end of the file)",i);
3485 goto return_bad;
3487 /* check that the load command size is not zero */
3488 if(l.cmdsize == 0){
3489 Mach_O_error(ofile, "malformed object (load command %u cmdsize"
3490 " is zero)", i);
3491 goto return_bad;
3493 switch(l.cmd){
3494 case LC_SEGMENT:
3495 if(l.cmdsize < sizeof(struct segment_command)){
3496 Mach_O_error(ofile, "malformed object (LC_SEGMENT cmdsize "
3497 "too small) in command %u", i);
3498 goto return_bad;
3500 sg = (struct segment_command *)lc;
3501 if(swapped)
3502 swap_segment_command(sg, host_byte_sex);
3503 big_size = sg->nsects;
3504 big_size *= sizeof(struct section);
3505 big_size += sizeof(struct segment_command);
3506 if(sg->cmdsize != big_size){
3507 Mach_O_error(ofile, "malformed object (inconsistent "
3508 "cmdsize in LC_SEGMENT command %u for the "
3509 "number of sections)", i);
3510 goto return_bad;
3512 if(sg->fileoff > size){
3513 Mach_O_error(ofile, "truncated or malformed object ("
3514 "LC_SEGMENT command %u fileoff field "
3515 "extends past the end of the file)", i);
3516 goto return_bad;
3518 big_size = sg->fileoff;
3519 big_size += sg->filesize;
3520 if(big_size > size){
3521 Mach_O_error(ofile, "truncated or malformed object ("
3522 "LC_SEGMENT command %u fileoff field "
3523 "plus filesize field extends past the end of "
3524 "the file)", i);
3525 goto return_bad;
3527 if(sg->vmsize != 0 && sg->filesize > sg->vmsize){
3528 Mach_O_error(ofile, "malformed object (LC_SEGMENT command "
3529 "%u filesize field greater than vmsize field)",
3531 goto return_bad;
3533 s = (struct section *)
3534 ((char *)sg + sizeof(struct segment_command));
3535 if(swapped)
3536 swap_section(s, sg->nsects, host_byte_sex);
3537 for(j = 0 ; j < sg->nsects ; j++){
3538 if(mh->filetype != MH_DYLIB_STUB &&
3539 s->flags != S_ZEROFILL &&
3540 s->flags != S_THREAD_LOCAL_ZEROFILL && s->offset > size){
3541 Mach_O_error(ofile, "truncated or malformed object "
3542 "(offset field of section %u in LC_SEGMENT "
3543 "command %u extends past the end of the file)",
3544 j, i);
3545 goto return_bad;
3547 if(mh->filetype != MH_DYLIB_STUB &&
3548 s->flags != S_ZEROFILL &&
3549 s->flags != S_THREAD_LOCAL_ZEROFILL &&
3550 sg->fileoff == 0 && s->offset < sizeofhdrs){
3551 Mach_O_error(ofile, "malformed object (offset field of "
3552 "section %u in LC_SEGMENT command %u not "
3553 "past the headers of the file)", j, i);
3554 goto return_bad;
3556 big_size = s->offset;
3557 big_size += s->size;
3558 if(mh->filetype != MH_DYLIB_STUB &&
3559 s->flags != S_ZEROFILL &&
3560 s->flags != S_THREAD_LOCAL_ZEROFILL && big_size > size){
3561 Mach_O_error(ofile, "truncated or malformed object "
3562 "(offset field plus size field of section %u "
3563 "in LC_SEGMENT command %u extends "
3564 "past the end of the file)", j, i);
3565 goto return_bad;
3567 if(mh->filetype != MH_DYLIB_STUB &&
3568 s->flags != S_ZEROFILL &&
3569 s->flags != S_THREAD_LOCAL_ZEROFILL &&
3570 s->size > sg->filesize){
3571 Mach_O_error(ofile, "malformed object (size field of "
3572 "section %u in LC_SEGMENT command %u greater "
3573 "than the segment)", j, i);
3574 goto return_bad;
3576 if(mh->filetype != MH_DYLIB_STUB &&
3577 s->size != 0 && s->addr < sg->vmaddr){
3578 Mach_O_error(ofile, "malformed object (addr field of "
3579 "section %u in LC_SEGMENT command %u less than "
3580 "the segment's vmaddr)", j, i);
3581 goto return_bad;
3583 big_size = s->addr;
3584 big_size += s->size;
3585 big_end = sg->vmaddr;
3586 big_end += sg->vmsize;
3587 if(sg->vmsize != 0 && s->size != 0 && big_size > big_end){
3588 Mach_O_error(ofile, "malformed object (addr field plus "
3589 "size of section %u in LC_SEGMENT command %u "
3590 "greater than than the segment's vmaddr plus "
3591 "vmsize)", j, i);
3592 goto return_bad;
3594 if(mh->filetype != MH_DYLIB_STUB &&
3595 s->flags != S_ZEROFILL &&
3596 s->flags != S_THREAD_LOCAL_ZEROFILL &&
3597 check_overlaping_element(ofile, &elements, s->offset,
3598 s->size, "section contents") == CHECK_BAD)
3599 goto return_bad;
3600 if(s->reloff > size){
3601 Mach_O_error(ofile, "truncated or malformed object "
3602 "(reloff field of section %u in LC_SEGMENT "
3603 "command %u extends past the end of the file)",
3604 j, i);
3605 goto return_bad;
3607 big_size = s->nreloc;
3608 big_size *= sizeof(struct relocation_info);
3609 big_size += s->reloff;
3610 if(big_size > size){
3611 Mach_O_error(ofile, "truncated or malformed object "
3612 "(reloff field plus nreloc field times sizeof("
3613 "struct relocation_info) of section %u in "
3614 "LC_SEGMENT command %u extends past the "
3615 "end of the file)", j, i);
3616 goto return_bad;
3618 if(check_overlaping_element(ofile, &elements, s->reloff,
3619 s->nreloc * sizeof(struct relocation_info),
3620 "section relocation entries") == CHECK_BAD)
3621 goto return_bad;
3622 s++;
3624 break;
3626 case LC_SEGMENT_64:
3627 if(l.cmdsize < sizeof(struct segment_command_64)){
3628 Mach_O_error(ofile, "malformed object (LC_SEGMENT_64 "
3629 "cmdsize too small) in command %u", i);
3630 goto return_bad;
3632 sg64 = (struct segment_command_64 *)lc;
3633 if(swapped)
3634 swap_segment_command_64(sg64, host_byte_sex);
3635 big_size = sg64->nsects;
3636 big_size *= sizeof(struct section_64);
3637 big_size += sizeof(struct segment_command_64);
3638 if(sg64->cmdsize != big_size){
3639 Mach_O_error(ofile, "malformed object (inconsistent "
3640 "cmdsize in LC_SEGMENT_64 command %u for "
3641 "the number of sections)", i);
3642 goto return_bad;
3644 if(sg64->fileoff > size){
3645 Mach_O_error(ofile, "truncated or malformed object ("
3646 "LC_SEGMENT_64 command %u fileoff field "
3647 "extends past the end of the file)", i);
3648 goto return_bad;
3650 big_size = sg64->fileoff;
3651 big_size += sg64->filesize;
3652 if(big_size > size){
3653 Mach_O_error(ofile, "truncated or malformed object ("
3654 "LC_SEGMENT_64 command %u fileoff field "
3655 "plus filesize field extends past the end of "
3656 "the file)", i);
3657 goto return_bad;
3659 s64 = (struct section_64 *)
3660 ((char *)sg64 + sizeof(struct segment_command_64));
3661 if(swapped)
3662 swap_section_64(s64, sg64->nsects, host_byte_sex);
3663 for(j = 0 ; j < sg64->nsects ; j++){
3664 if(mh64->filetype != MH_DYLIB_STUB &&
3665 s64->flags != S_ZEROFILL &&
3666 s64->flags != S_THREAD_LOCAL_ZEROFILL &&
3667 s64->offset > size){
3668 Mach_O_error(ofile, "truncated or malformed object "
3669 "(offset field of section %u in LC_SEGMENT_64 "
3670 "command %u extends past the end of the file)",
3671 j, i);
3672 goto return_bad;
3674 big_size = s64->offset;
3675 big_size += s64->size;
3676 if(mh64->filetype != MH_DYLIB_STUB &&
3677 s64->flags != S_ZEROFILL &&
3678 s64->flags != S_THREAD_LOCAL_ZEROFILL &&
3679 big_size > size){
3680 Mach_O_error(ofile, "truncated or malformed object "
3681 "(offset field plus size field of section %u "
3682 "in LC_SEGMENT_64 command %u extends "
3683 "past the end of the file)", j, i);
3684 goto return_bad;
3686 if(mh64->filetype != MH_DYLIB_STUB &&
3687 s64->flags != S_ZEROFILL &&
3688 s64->flags != S_THREAD_LOCAL_ZEROFILL &&
3689 check_overlaping_element(ofile, &elements, s64->offset,
3690 s64->size, "section contents") == CHECK_BAD)
3691 goto return_bad;
3692 if(s64->reloff > size){
3693 Mach_O_error(ofile, "truncated or malformed object "
3694 "(reloff field of section %u in LC_SEGMENT_64 "
3695 "command %u extends past the end of the file)",
3696 j, i);
3697 goto return_bad;
3699 big_size = s64->nreloc;
3700 big_size *= sizeof(struct relocation_info);
3701 big_size += s64->reloff;
3702 if(big_size > size){
3703 Mach_O_error(ofile, "truncated or malformed object "
3704 "(reloff field plus nreloc field times sizeof("
3705 "struct relocation_info) of section %u in "
3706 "LC_SEGMENT_64 command %u extends past the "
3707 "end of the file)", j, i);
3708 goto return_bad;
3710 if(check_overlaping_element(ofile, &elements, s64->reloff,
3711 s64->nreloc * sizeof(struct relocation_info),
3712 "section relocation entries") == CHECK_BAD)
3713 goto return_bad;
3714 s64++;
3716 break;
3718 case LC_SYMTAB:
3719 if(l.cmdsize < sizeof(struct symtab_command)){
3720 Mach_O_error(ofile, "malformed object (LC_SYMTAB cmdsize "
3721 "too small) in command %u", i);
3722 goto return_bad;
3724 if(st != NULL){
3725 Mach_O_error(ofile, "malformed object (more than one "
3726 "LC_SYMTAB command)");
3727 goto return_bad;
3729 st = (struct symtab_command *)lc;
3730 if(swapped)
3731 swap_symtab_command(st, host_byte_sex);
3732 if(st->cmdsize != sizeof(struct symtab_command)){
3733 Mach_O_error(ofile, "malformed object (LC_SYMTAB command "
3734 "%u has incorrect cmdsize)", i);
3735 goto return_bad;
3737 if(st->symoff > size){
3738 Mach_O_error(ofile, "truncated or malformed object (symoff "
3739 "field of LC_SYMTAB command %u extends past the end "
3740 "of the file)", i);
3741 goto return_bad;
3743 big_size = st->nsyms;
3744 big_size *= sizeof_nlist;
3745 big_size += st->symoff;
3746 if(big_size > size){
3747 Mach_O_error(ofile, "truncated or malformed object (symoff "
3748 "field plus nsyms field times sizeof(%s) of LC_SYMTAB "
3749 "command %u extends past the end of the file)",
3750 struct_nlist_name, i);
3751 goto return_bad;
3753 if(check_overlaping_element(ofile, &elements, st->symoff,
3754 st->nsyms * sizeof_nlist, "symbol table") == CHECK_BAD)
3755 goto return_bad;
3756 if(st->stroff > size){
3757 Mach_O_error(ofile, "truncated or malformed object (stroff "
3758 "field of LC_SYMTAB command %u extends past the end "
3759 "of the file)", i);
3760 goto return_bad;
3762 big_size = st->stroff;
3763 big_size += st->strsize;
3764 if(big_size > size){
3765 Mach_O_error(ofile, "truncated or malformed object (stroff "
3766 "field plus strsize field of LC_SYMTAB command %u "
3767 "extends past the end of the file)", i);
3768 goto return_bad;
3770 if(check_overlaping_element(ofile, &elements, st->stroff,
3771 st->strsize, "string table") == CHECK_BAD)
3772 goto return_bad;
3773 break;
3775 case LC_DYSYMTAB:
3776 if(l.cmdsize < sizeof(struct dysymtab_command)){
3777 Mach_O_error(ofile, "malformed object (LC_DYSYMTAB cmdsize "
3778 "too small) in command %u", i);
3779 goto return_bad;
3781 if(dyst != NULL){
3782 Mach_O_error(ofile, "malformed object (more than one "
3783 "LC_DYSYMTAB command)");
3784 goto return_bad;
3786 dyst = (struct dysymtab_command *)lc;
3787 if(swapped)
3788 swap_dysymtab_command(dyst, host_byte_sex);
3789 if(dyst->cmdsize != sizeof(struct dysymtab_command)){
3790 Mach_O_error(ofile, "malformed object (LC_DYSYMTAB command "
3791 "%u has incorrect cmdsize)", i);
3792 goto return_bad;
3794 if(dyst->tocoff > size){
3795 Mach_O_error(ofile, "truncated or malformed object (tocoff "
3796 "field of LC_DYSYMTAB command %u extends past the end "
3797 "of the file)", i);
3798 goto return_bad;
3800 big_size = dyst->ntoc;
3801 big_size *= sizeof(struct dylib_table_of_contents);
3802 big_size += dyst->tocoff;
3803 if(big_size > size){
3804 Mach_O_error(ofile, "truncated or malformed object (tocoff "
3805 "field plus ntoc field times sizeof(struct dylib_table"
3806 "_of_contents) of LC_DYSYMTAB command %u extends past "
3807 "the end of the file)", i);
3808 goto return_bad;
3810 if(check_overlaping_element(ofile, &elements, dyst->tocoff,
3811 dyst->ntoc * sizeof(struct dylib_table_of_contents),
3812 "table of contents") == CHECK_BAD)
3813 goto return_bad;
3814 if(dyst->modtaboff > size){
3815 Mach_O_error(ofile, "truncated or malformed object "
3816 "(modtaboff field of LC_DYSYMTAB command %u extends "
3817 "past the end of the file)", i);
3818 goto return_bad;
3820 big_size = dyst->nmodtab;
3821 big_size *= sizeof_dylib_module;
3822 big_size += dyst->modtaboff;
3823 if(big_size > size){
3824 Mach_O_error(ofile, "truncated or malformed object "
3825 "(modtaboff field plus nmodtab field times sizeof(%s) "
3826 "of LC_DYSYMTAB command %u extends past the end of "
3827 "the file)", struct_dylib_module_name, i);
3828 goto return_bad;
3830 if(check_overlaping_element(ofile, &elements, dyst->modtaboff,
3831 dyst->nmodtab * sizeof_dylib_module, "module table") ==
3832 CHECK_BAD)
3833 goto return_bad;
3834 if(dyst->extrefsymoff > size){
3835 Mach_O_error(ofile, "truncated or malformed object "
3836 "(extrefsymoff field of LC_DYSYMTAB command %u "
3837 "extends past the end of the file)", i);
3838 goto return_bad;
3840 big_size = dyst->nextrefsyms;
3841 big_size *= sizeof(struct dylib_reference);
3842 big_size += dyst->extrefsymoff;
3843 if(big_size > size){
3844 Mach_O_error(ofile, "truncated or malformed object "
3845 "(extrefsymoff field plus nextrefsyms field times "
3846 "sizeof(struct dylib_reference) of LC_DYSYMTAB command "
3847 "%u extends past the end of the file)", i);
3848 goto return_bad;
3850 if(check_overlaping_element(ofile, &elements,dyst->extrefsymoff,
3851 dyst->nextrefsyms * sizeof(struct dylib_reference),
3852 "reference table") == CHECK_BAD)
3853 goto return_bad;
3854 if(dyst->indirectsymoff > size){
3855 Mach_O_error(ofile, "truncated or malformed object "
3856 "(indirectsymoff field of LC_DYSYMTAB command %u "
3857 "extends past the end of the file)", i);
3858 goto return_bad;
3860 big_size = dyst->nindirectsyms;
3861 big_size *= sizeof(uint32_t);
3862 big_size += dyst->indirectsymoff;
3863 if(big_size > size){
3864 Mach_O_error(ofile, "truncated or malformed object "
3865 "(indirectsymoff field plus nindirectsyms field times "
3866 "sizeof(uint32_t) of LC_DYSYMTAB command "
3867 "%u extends past the end of the file)", i);
3868 goto return_bad;
3870 if(check_overlaping_element(ofile, &elements,
3871 dyst->indirectsymoff, dyst->nindirectsyms *
3872 sizeof(uint32_t), "indirect table") == CHECK_BAD)
3873 goto return_bad;
3874 if(dyst->extreloff > size){
3875 Mach_O_error(ofile, "truncated or malformed object "
3876 "(extreloff field of LC_DYSYMTAB command %u "
3877 "extends past the end of the file)", i);
3878 goto return_bad;
3880 big_size = dyst->nextrel;
3881 big_size *= sizeof(struct relocation_info);
3882 big_size += dyst->extreloff;
3883 if(big_size > size){
3884 Mach_O_error(ofile, "truncated or malformed object "
3885 "(extreloff field plus nextrel field times "
3886 "sizeof(struct relocation_info) of LC_DYSYMTAB command "
3887 "%u extends past the end of the file)", i);
3888 goto return_bad;
3890 if(check_overlaping_element(ofile, &elements, dyst->extreloff,
3891 dyst->nextrel * sizeof(struct relocation_info),
3892 "external relocation table") == CHECK_BAD)
3893 goto return_bad;
3894 if(dyst->locreloff > size){
3895 Mach_O_error(ofile, "truncated or malformed object "
3896 "(locreloff field of LC_DYSYMTAB command %u "
3897 "extends past the end of the file)", i);
3898 goto return_bad;
3900 big_size = dyst->nlocrel;
3901 big_size *= sizeof(struct relocation_info);
3902 big_size += dyst->locreloff;
3903 if(big_size > size){
3904 Mach_O_error(ofile, "truncated or malformed object "
3905 "(locreloff field plus nlocrel field times "
3906 "sizeof(struct relocation_info) of LC_DYSYMTAB command "
3907 "%u extends past the end of the file)", i);
3908 goto return_bad;
3910 if(check_overlaping_element(ofile, &elements, dyst->locreloff,
3911 dyst->nlocrel * sizeof(struct relocation_info),
3912 "local relocation table") == CHECK_BAD)
3913 goto return_bad;
3914 break;
3916 case LC_ROUTINES:
3917 if(l.cmdsize < sizeof(struct routines_command)){
3918 Mach_O_error(ofile, "malformed object (LC_ROUTINES cmdsize "
3919 "too small) in command %u", i);
3920 goto return_bad;
3922 if(rc != NULL){
3923 Mach_O_error(ofile, "malformed object (more than one "
3924 "LC_ROUTINES command)");
3925 goto return_bad;
3927 rc = (struct routines_command *)lc;
3928 if(swapped)
3929 swap_routines_command(rc, host_byte_sex);
3930 if(rc->cmdsize != sizeof(struct routines_command)){
3931 Mach_O_error(ofile, "malformed object (LC_ROUTINES "
3932 "command %u has incorrect cmdsize)", i);
3933 goto return_bad;
3935 break;
3937 case LC_ROUTINES_64:
3938 if(l.cmdsize < sizeof(struct routines_command_64)){
3939 Mach_O_error(ofile, "malformed object (LC_ROUTINES_64 "
3940 "cmdsize too small) in command %u", i);
3941 goto return_bad;
3943 if(rc64 != NULL){
3944 Mach_O_error(ofile, "malformed object (more than one "
3945 "LC_ROUTINES_64 command)");
3946 goto return_bad;
3948 rc64 = (struct routines_command_64 *)lc;
3949 if(swapped)
3950 swap_routines_command_64(rc64, host_byte_sex);
3951 if(rc64->cmdsize != sizeof(struct routines_command_64)){
3952 Mach_O_error(ofile, "malformed object (LC_ROUTINES_64 "
3953 "command %u has incorrect cmdsize)", i);
3954 goto return_bad;
3956 break;
3958 case LC_TWOLEVEL_HINTS:
3959 if(l.cmdsize < sizeof(struct twolevel_hints_command)){
3960 Mach_O_error(ofile, "malformed object (LC_TWOLEVEL_HINTS "
3961 "cmdsize too small) in command %u", i);
3962 goto return_bad;
3964 if(hints != NULL){
3965 Mach_O_error(ofile, "malformed object (more than one "
3966 "LC_TWOLEVEL_HINTS command)");
3967 goto return_bad;
3969 hints = (struct twolevel_hints_command *)lc;
3970 if(swapped)
3971 swap_twolevel_hints_command(hints, host_byte_sex);
3972 if(hints->cmdsize != sizeof(struct twolevel_hints_command)){
3973 Mach_O_error(ofile, "malformed object (LC_TWOLEVEL_HINTS "
3974 "command %u has incorrect cmdsize)", i);
3975 goto return_bad;
3977 if(hints->offset > size){
3978 Mach_O_error(ofile, "truncated or malformed object "
3979 "(offset field of LC_TWOLEVEL_HINTS command %u "
3980 "extends past the end of the file)", i);
3981 goto return_bad;
3983 big_size = hints->nhints;
3984 big_size *= sizeof(struct twolevel_hint);
3985 big_size += hints->offset;
3986 if(big_size > size){
3987 Mach_O_error(ofile, "truncated or malformed object "
3988 "(offset field plus nhints field times "
3989 "sizeof(struct twolevel_hint) of LC_TWOLEVEL_HINTS "
3990 " command %u extends past the end of the file)", i);
3991 goto return_bad;
3993 if(check_overlaping_element(ofile, &elements, hints->offset,
3994 hints->nhints * sizeof(struct twolevel_hint),
3995 "two level hints") == CHECK_BAD)
3996 goto return_bad;
3997 break;
3999 case LC_SEGMENT_SPLIT_INFO:
4000 cmd_name = "LC_SEGMENT_SPLIT_INFO";
4001 element_name = "split info data";
4002 if(split_info != NULL){
4003 Mach_O_error(ofile, "malformed object (more than one "
4004 "%s command)", cmd_name);
4005 goto return_bad;
4007 split_info = (struct linkedit_data_command *)lc;
4008 goto check_linkedit_data_command;
4010 case LC_CODE_SIGNATURE:
4011 cmd_name = "LC_CODE_SIGNATURE";
4012 element_name = "code signature data";
4013 if(code_sig != NULL){
4014 Mach_O_error(ofile, "malformed object (more than one "
4015 "%s command)", cmd_name);
4016 goto return_bad;
4018 code_sig = (struct linkedit_data_command *)lc;
4019 goto check_linkedit_data_command;
4021 case LC_FUNCTION_STARTS:
4022 cmd_name = "LC_FUNCTION_STARTS";
4023 element_name = "function starts data";
4024 if(func_starts != NULL){
4025 Mach_O_error(ofile, "malformed object (more than one "
4026 "%s command)", cmd_name);
4027 goto return_bad;
4029 func_starts = (struct linkedit_data_command *)lc;
4030 goto check_linkedit_data_command;
4032 case LC_DATA_IN_CODE:
4033 cmd_name = "LC_DATA_IN_CODE";
4034 element_name = "date in code info";
4035 if(data_in_code != NULL){
4036 Mach_O_error(ofile, "malformed object (more than one "
4037 "%s command)", cmd_name);
4038 goto return_bad;
4040 data_in_code = (struct linkedit_data_command *)lc;
4041 goto check_linkedit_data_command;
4043 case LC_DYLIB_CODE_SIGN_DRS:
4044 cmd_name = "LC_DYLIB_CODE_SIGN_DRS";
4045 element_name = "code signing RDs data";
4046 if(code_sign_drs != NULL){
4047 Mach_O_error(ofile, "malformed object (more than one "
4048 "%s command)", cmd_name);
4049 goto return_bad;
4051 code_sign_drs = (struct linkedit_data_command *)lc;
4052 goto check_linkedit_data_command;
4054 check_linkedit_data_command:
4055 if(l.cmdsize < sizeof(struct linkedit_data_command)){
4056 Mach_O_error(ofile, "malformed object (%s cmdsize too "
4057 "small) in command %u", cmd_name, i);
4058 goto return_bad;
4060 linkedit_data = (struct linkedit_data_command *)lc;
4061 if(swapped)
4062 swap_linkedit_data_command(linkedit_data, host_byte_sex);
4063 if(linkedit_data->cmdsize !=
4064 sizeof(struct linkedit_data_command)){
4065 Mach_O_error(ofile, "malformed object (%s command %u has "
4066 "incorrect cmdsize)", cmd_name, i);
4067 goto return_bad;
4069 if(linkedit_data->dataoff > size){
4070 Mach_O_error(ofile, "truncated or malformed object "
4071 "(dataoff field of %s command %u extends past the end "
4072 "of the file)", cmd_name, i);
4073 goto return_bad;
4075 big_size = linkedit_data->dataoff;
4076 big_size += linkedit_data->datasize;
4077 if(big_size > size){
4078 Mach_O_error(ofile, "truncated or malformed object "
4079 "(dataoff field plus datasize field of "
4080 "%s command %u extends past the end of "
4081 "the file)", cmd_name, i);
4082 goto return_bad;
4084 if(check_overlaping_element(ofile, &elements,
4085 linkedit_data->dataoff, linkedit_data->datasize,
4086 element_name) == CHECK_BAD)
4087 goto return_bad;
4088 break;
4090 case LC_VERSION_MIN_MACOSX:
4091 if(l.cmdsize < sizeof(struct version_min_command)){
4092 Mach_O_error(ofile, "malformed object (LC_VERSION_MIN_"
4093 "MACOSX cmdsize too small) in command %u", i);
4094 goto return_bad;
4096 if(vers != NULL){
4097 Mach_O_error(ofile, "malformed object (more than one "
4098 "LC_VERSION_MIN_IPHONEOS or LC_VERSION_MIN_MACOSX "
4099 "command)");
4100 goto return_bad;
4102 vers = (struct version_min_command *)lc;
4103 if(swapped)
4104 swap_version_min_command(vers, host_byte_sex);
4105 if(vers->cmdsize < sizeof(struct version_min_command)){
4106 Mach_O_error(ofile, "malformed object (LC_VERSION_MIN_"
4107 "MACOSX command %u has too small cmdsize field)", i);
4108 goto return_bad;
4110 break;
4112 case LC_VERSION_MIN_IPHONEOS:
4113 if(l.cmdsize < sizeof(struct version_min_command)){
4114 Mach_O_error(ofile, "malformed object (LC_VERSION_MIN_"
4115 "IPHONEOS cmdsize too small) in command %u",i);
4116 goto return_bad;
4118 if(vers != NULL){
4119 Mach_O_error(ofile, "malformed object (more than one "
4120 "LC_VERSION_MIN_IPHONEOS or LC_VERSION_MIN_MACOSX "
4121 "command)");
4122 goto return_bad;
4124 vers = (struct version_min_command *)lc;
4125 if(swapped)
4126 swap_version_min_command(vers, host_byte_sex);
4127 if(vers->cmdsize < sizeof(struct version_min_command)){
4128 Mach_O_error(ofile, "malformed object (LC_VERSION_MIN_"
4129 "IPHONEOS command %u has too small cmdsize field)", i);
4130 goto return_bad;
4132 break;
4134 case LC_ENCRYPTION_INFO:
4135 if(l.cmdsize < sizeof(struct encryption_info_command)){
4136 Mach_O_error(ofile, "malformed object (LC_ENCRYPTION_INFO "
4137 "cmdsize too small) in command %u", i);
4138 goto return_bad;
4140 encrypt_info = (struct encryption_info_command *)lc;
4141 if(swapped)
4142 swap_encryption_command(encrypt_info, host_byte_sex);
4143 if(encrypt_info->cmdsize !=
4144 sizeof(struct encryption_info_command)){
4145 Mach_O_error(ofile, "malformed object (LC_ENCRYPTION_INFO"
4146 "command %u has incorrect cmdsize)", i);
4147 goto return_bad;
4149 if(encrypt_info->cryptoff > size){
4150 Mach_O_error(ofile, "truncated or malformed object (cryptoff "
4151 "field of LC_ENCRYPTION_INFO command %u extends "
4152 "past the end of the file)", i);
4153 goto return_bad;
4155 big_size = encrypt_info->cryptoff;
4156 big_size += encrypt_info->cryptsize;
4157 if(big_size > size){
4158 Mach_O_error(ofile, "truncated or malformed object "
4159 "(cryptoff field plus cryptsize field of "
4160 "LC_ENCRYPTION_INFO command %u extends past "
4161 "the end of the file)", i);
4162 goto return_bad;
4164 break;
4166 case LC_DYLD_INFO:
4167 case LC_DYLD_INFO_ONLY:
4168 if(l.cmdsize < sizeof(struct dyld_info_command)){
4169 Mach_O_error(ofile, "malformed object (%s cmdsize "
4170 "too small) in command %u", l.cmd ==
4171 LC_DYLD_INFO ? "LC_DYLD_INFO" :
4172 "LC_DYLD_INFO_ONLY", i);
4173 goto return_bad;
4175 dyld_info = (struct dyld_info_command *)lc;
4176 if(swapped)
4177 swap_dyld_info_command(dyld_info, host_byte_sex);
4178 if(dyld_info->cmdsize !=
4179 sizeof(struct dyld_info_command)){
4180 Mach_O_error(ofile, "malformed object (LC_DYLD_INFO"
4181 "command %u has incorrect cmdsize)", i);
4182 goto return_bad;
4184 if(dyld_info->rebase_off != 0 && dyld_info->rebase_off > size){
4185 Mach_O_error(ofile, "truncated or malformed object "
4186 "(rebase_off field of LC_DYLD_INFO command %u "
4187 "extends past the end of the file)", i);
4188 goto return_bad;
4190 if(dyld_info->rebase_off != 0){
4191 big_size = dyld_info->rebase_off;
4192 big_size += dyld_info->rebase_size;
4193 if(big_size > size){
4194 Mach_O_error(ofile, "truncated or malformed object "
4195 "(rebase_off plus rebase_size of LC_DYLD_INFO "
4196 "command %u extends past the end of the file)", i);
4197 goto return_bad;
4200 if(check_overlaping_element(ofile, &elements,
4201 dyld_info->rebase_off, dyld_info->rebase_size,
4202 "dyld rebase info") == CHECK_BAD)
4203 goto return_bad;
4204 if(dyld_info->bind_off != 0 && dyld_info->bind_off > size){
4205 Mach_O_error(ofile, "truncated or malformed object "
4206 "(bind_off field of LC_DYLD_INFO command %u "
4207 "extends past the end of the file)", i);
4208 goto return_bad;
4210 if(dyld_info->bind_off != 0){
4211 big_size = dyld_info->bind_off;
4212 big_size += dyld_info->bind_size;
4213 if(big_size > size){
4214 Mach_O_error(ofile, "truncated or malformed object "
4215 "(bind_off plus bind_size of LC_DYLD_INFO command "
4216 "%u extends past the end of the file)", i);
4217 goto return_bad;
4220 if(check_overlaping_element(ofile, &elements,
4221 dyld_info->bind_off, dyld_info->bind_size,
4222 "dyld bind info") == CHECK_BAD)
4223 goto return_bad;
4224 if(dyld_info->weak_bind_off != 0 &&
4225 dyld_info->weak_bind_off > size){
4226 Mach_O_error(ofile, "truncated or malformed object "
4227 "(weak_bind_off field of LC_DYLD_INFO command %u "
4228 "extends past the end of the file)", i);
4229 goto return_bad;
4231 if(dyld_info->weak_bind_off != 0){
4232 big_size = dyld_info->weak_bind_off;
4233 big_size += dyld_info->weak_bind_size;
4234 if(big_size > size){
4235 Mach_O_error(ofile, "truncated or malformed object "
4236 "(weak_bind_off plus weak_bind_size of LC_DYLD_INFO"
4237 " command %u extends past the end of the file)", i);
4238 goto return_bad;
4241 if(check_overlaping_element(ofile, &elements,
4242 dyld_info->weak_bind_off, dyld_info->weak_bind_size,
4243 "dyld bind info") == CHECK_BAD)
4244 goto return_bad;
4245 if(dyld_info->lazy_bind_off != 0 &&
4246 dyld_info->lazy_bind_off > size){
4247 Mach_O_error(ofile, "truncated or malformed object "
4248 "(lazy_bind_off field of LC_DYLD_INFO command %u "
4249 "extends past the end of the file)", i);
4250 goto return_bad;
4252 if(dyld_info->lazy_bind_off != 0){
4253 big_size = dyld_info->lazy_bind_off;
4254 big_size += dyld_info->lazy_bind_size;
4255 if(big_size > size){
4256 Mach_O_error(ofile, "truncated or malformed object "
4257 "(lazy_bind_off plus lazy_bind_size of LC_DYLD_INFO"
4258 " command %u extends past the end of the file)", i);
4259 goto return_bad;
4262 if(check_overlaping_element(ofile, &elements,
4263 dyld_info->lazy_bind_off, dyld_info->lazy_bind_size,
4264 "dyld lazy bind info") == CHECK_BAD)
4265 goto return_bad;
4266 if(dyld_info->export_off != 0 && dyld_info->export_off > size){
4267 Mach_O_error(ofile, "truncated or malformed object "
4268 "(export_off field of LC_DYLD_INFO command %u "
4269 "extends past the end of the file)", i);
4270 goto return_bad;
4272 if(dyld_info->export_off != 0){
4273 big_size = dyld_info->export_off;
4274 big_size += dyld_info->export_size;
4275 if(big_size > size){
4276 Mach_O_error(ofile, "truncated or malformed object "
4277 "(export_off plus export_size of LC_DYLD_INFO "
4278 "command %u extends past the end of the file)", i);
4279 goto return_bad;
4282 if(check_overlaping_element(ofile, &elements,
4283 dyld_info->export_off, dyld_info->export_size,
4284 "dyld export info") == CHECK_BAD)
4285 goto return_bad;
4286 break;
4290 case LC_PREBIND_CKSUM:
4291 if(l.cmdsize < sizeof(struct prebind_cksum_command)){
4292 Mach_O_error(ofile, "malformed object (LC_PREBIND_CKSUM "
4293 "cmdsize too small) in command %u", i);
4294 goto return_bad;
4296 if(cs != NULL){
4297 Mach_O_error(ofile, "malformed object (more than one "
4298 "LC_PREBIND_CKSUM command)");
4299 goto return_bad;
4301 cs = (struct prebind_cksum_command *)lc;
4302 if(swapped)
4303 swap_prebind_cksum_command(cs, host_byte_sex);
4304 if(cs->cmdsize != sizeof(struct prebind_cksum_command)){
4305 Mach_O_error(ofile, "malformed object (LC_PREBIND_CKSUM "
4306 "command %u has incorrect cmdsize)", i);
4307 goto return_bad;
4309 break;
4311 case LC_UUID:
4312 if(l.cmdsize < sizeof(struct uuid_command)){
4313 Mach_O_error(ofile, "malformed object (LC_UUID cmdsize "
4314 "too small) in command %u", i);
4315 goto return_bad;
4317 if(uuid != NULL){
4318 Mach_O_error(ofile, "malformed object (more than one "
4319 "LC_UUID command)");
4320 goto return_bad;
4322 uuid = (struct uuid_command *)lc;
4323 if(swapped)
4324 swap_uuid_command(uuid, host_byte_sex);
4325 if(uuid->cmdsize != sizeof(struct uuid_command)){
4326 Mach_O_error(ofile, "malformed object (LC_UUID command %u " "has incorrect cmdsize)", i);
4327 goto return_bad;
4329 break;
4331 case LC_SYMSEG:
4332 if(l.cmdsize < sizeof(struct symseg_command)){
4333 Mach_O_error(ofile, "malformed object (LC_SYMSEG cmdsize "
4334 "too small) in command %u", i);
4335 goto return_bad;
4337 ss = (struct symseg_command *)lc;
4338 if(swapped)
4339 swap_symseg_command(ss, host_byte_sex);
4340 if(ss->cmdsize != sizeof(struct symseg_command)){
4341 Mach_O_error(ofile, "malformed object (LC_SYMSEG command "
4342 "%u has incorrect cmdsize)", i);
4343 goto return_bad;
4345 if(ss->offset > size){
4346 Mach_O_error(ofile, "truncated or malformed object (offset "
4347 "field of LC_SYMSEG command %u extends past the end "
4348 "of the file)", i);
4349 goto return_bad;
4351 big_size = ss->offset;
4352 big_size += ss->size;
4353 if(big_size > size){
4354 Mach_O_error(ofile, "truncated or malformed object (offset "
4355 "field plus size field of LC_SYMTAB command %u "
4356 "extends past the end of the file)", i);
4357 goto return_bad;
4359 if(check_overlaping_element(ofile, &elements, ss->offset,
4360 ss->size, "symseg info") == CHECK_BAD)
4361 goto return_bad;
4362 break;
4364 case LC_IDFVMLIB:
4365 case LC_LOADFVMLIB:
4366 if(l.cmdsize < sizeof(struct fvmlib_command)){
4367 Mach_O_error(ofile, "malformed object (%s cmdsize "
4368 "too small) in command %u", l.cmd ==
4369 LC_IDFVMLIB ? "LC_IDFVMLIB" :
4370 "LC_LOADFVMLIB", i);
4371 goto return_bad;
4373 fl = (struct fvmlib_command *)lc;
4374 if(swapped)
4375 swap_fvmlib_command(fl, host_byte_sex);
4376 if(fl->cmdsize < sizeof(struct fvmlib_command)){
4377 Mach_O_error(ofile, "malformed object (%s command %u has "
4378 "too small cmdsize field)", fl->cmd == LC_IDFVMLIB ?
4379 "LC_IDFVMLIB" : "LC_LOADFVMLIB", i);
4380 goto return_bad;
4382 if(fl->fvmlib.name.offset >= fl->cmdsize){
4383 Mach_O_error(ofile, "truncated or malformed object (name."
4384 "offset field of %s command %u extends past the end "
4385 "of the file)", fl->cmd == LC_IDFVMLIB ? "LC_IDFVMLIB"
4386 : "LC_LOADFVMLIB", i);
4387 goto return_bad;
4389 break;
4391 case LC_ID_DYLIB:
4392 cmd_name = "LC_ID_DYLIB";
4393 goto check_dylib_command;
4394 case LC_LOAD_DYLIB:
4395 cmd_name = "LC_LOAD_DYLIB";
4396 goto check_dylib_command;
4397 case LC_LOAD_WEAK_DYLIB:
4398 cmd_name = "LC_LOAD_WEAK_DYLIB";
4399 goto check_dylib_command;
4400 case LC_REEXPORT_DYLIB:
4401 cmd_name = "LC_REEXPORT_DYLIB";
4402 goto check_dylib_command;
4403 case LC_LOAD_UPWARD_DYLIB:
4404 cmd_name = "LC_LOAD_UPWARD_DYLIB";
4405 goto check_dylib_command;
4406 case LC_LAZY_LOAD_DYLIB:
4407 cmd_name = "LC_LAZY_LOAD_DYLIB";
4408 goto check_dylib_command;
4409 check_dylib_command:
4410 if(l.cmdsize < sizeof(struct dylib_command)){
4411 Mach_O_error(ofile, "malformed object (%s cmdsize too "
4412 "small) in command %u", cmd_name, i);
4413 goto return_bad;
4415 dl = (struct dylib_command *)lc;
4416 if(swapped)
4417 swap_dylib_command(dl, host_byte_sex);
4418 if(dl->cmdsize < sizeof(struct dylib_command)){
4419 Mach_O_error(ofile, "malformed object (%s command %u has "
4420 "too small cmdsize field)", cmd_name, i);
4421 goto return_bad;
4423 if(dl->dylib.name.offset >= dl->cmdsize){
4424 Mach_O_error(ofile, "truncated or malformed object (name."
4425 "offset field of %s command %u extends past the end "
4426 "of the file)", cmd_name, i);
4427 goto return_bad;
4429 break;
4431 case LC_SUB_FRAMEWORK:
4432 if(l.cmdsize < sizeof(struct sub_framework_command)){
4433 Mach_O_error(ofile, "malformed object (LC_SUB_FRAMEWORK "
4434 "cmdsize too small) in command %u", i);
4435 goto return_bad;
4437 sub = (struct sub_framework_command *)lc;
4438 if(swapped)
4439 swap_sub_framework_command(sub, host_byte_sex);
4440 if(sub->cmdsize < sizeof(struct sub_framework_command)){
4441 Mach_O_error(ofile, "malformed object (LC_SUB_FRAMEWORK "
4442 "command %u has too small cmdsize field)", i);
4443 goto return_bad;
4445 if(sub->umbrella.offset >= sub->cmdsize){
4446 Mach_O_error(ofile, "truncated or malformed object "
4447 "(umbrella.offset field of LC_SUB_FRAMEWORK command "
4448 "%u extends past the end of the file)", i);
4449 goto return_bad;
4451 break;
4453 case LC_SUB_UMBRELLA:
4454 if(l.cmdsize < sizeof(struct sub_umbrella_command)){
4455 Mach_O_error(ofile, "malformed object (LC_SUB_UMBRELLA "
4456 "cmdsize too small) in command %u", i);
4457 goto return_bad;
4459 usub = (struct sub_umbrella_command *)lc;
4460 if(swapped)
4461 swap_sub_umbrella_command(usub, host_byte_sex);
4462 if(usub->cmdsize < sizeof(struct sub_umbrella_command)){
4463 Mach_O_error(ofile, "malformed object (LC_SUB_UMBRELLA "
4464 "command %u has too small cmdsize field)", i);
4465 goto return_bad;
4467 if(usub->sub_umbrella.offset >= usub->cmdsize){
4468 Mach_O_error(ofile, "truncated or malformed object "
4469 "(sub_umbrella.offset field of LC_SUB_UMBRELLA command "
4470 "%u extends past the end of the file)", i);
4471 goto return_bad;
4473 break;
4475 case LC_SUB_LIBRARY:
4476 if(l.cmdsize < sizeof(struct sub_library_command)){
4477 Mach_O_error(ofile, "malformed object (LC_SUB_LIBRARY "
4478 "cmdsize too small) in command %u", i);
4479 goto return_bad;
4481 lsub = (struct sub_library_command *)lc;
4482 if(swapped)
4483 swap_sub_library_command(lsub, host_byte_sex);
4484 if(lsub->cmdsize < sizeof(struct sub_library_command)){
4485 Mach_O_error(ofile, "malformed object (LC_SUB_LIBRARY "
4486 "command %u has too small cmdsize field)", i);
4487 goto return_bad;
4489 if(lsub->sub_library.offset >= lsub->cmdsize){
4490 Mach_O_error(ofile, "truncated or malformed object "
4491 "(sub_library.offset field of LC_SUB_LIBRARY command "
4492 "%u extends past the end of the file)", i);
4493 goto return_bad;
4495 break;
4497 case LC_SUB_CLIENT:
4498 if(l.cmdsize < sizeof(struct sub_client_command)){
4499 Mach_O_error(ofile, "malformed object (LC_SUB_CLIENT "
4500 "cmdsize too small) in command %u", i);
4501 goto return_bad;
4503 csub = (struct sub_client_command *)lc;
4504 if(swapped)
4505 swap_sub_client_command(csub, host_byte_sex);
4506 if(csub->cmdsize < sizeof(struct sub_client_command)){
4507 Mach_O_error(ofile, "malformed object (LC_SUB_CLIENT "
4508 "command %u has too small cmdsize field)", i);
4509 goto return_bad;
4511 if(csub->client.offset >= csub->cmdsize){
4512 Mach_O_error(ofile, "truncated or malformed object "
4513 "(cleient.offset field of LC_SUB_CLIENT command "
4514 "%u extends past the end of the file)", i);
4515 goto return_bad;
4517 break;
4519 case LC_PREBOUND_DYLIB:
4520 if(l.cmdsize < sizeof(struct prebound_dylib_command)){
4521 Mach_O_error(ofile, "malformed object (LC_PREBOUND_DYLIB "
4522 "cmdsize too small) in command %u", i);
4523 goto return_bad;
4525 pbdylib = (struct prebound_dylib_command *)lc;
4526 if(swapped)
4527 swap_prebound_dylib_command(pbdylib, host_byte_sex);
4528 if(pbdylib->cmdsize < sizeof(struct dylib_command)){
4529 Mach_O_error(ofile, "malformed object (LC_PREBIND_DYLIB "
4530 "command %u has too small cmdsize field)", i);
4531 goto return_bad;
4533 if(pbdylib->name.offset >= pbdylib->cmdsize){
4534 Mach_O_error(ofile, "truncated or malformed object (name."
4535 "offset field of LC_PREBIND_DYLIB command %u extends "
4536 "past the end of the file)", i);
4537 goto return_bad;
4539 if(pbdylib->linked_modules.offset >= pbdylib->cmdsize){
4540 Mach_O_error(ofile, "truncated or malformed object (linked_"
4541 "modules.offset field of LC_PREBIND_DYLIB command %u "
4542 "extends past the end of the file)", i);
4543 goto return_bad;
4545 break;
4547 case LC_ID_DYLINKER:
4548 cmd_name = "LC_ID_DYLINKER";
4549 goto check_dylinker_command;
4550 case LC_LOAD_DYLINKER:
4551 cmd_name = "LC_LOAD_DYLINKER";
4552 goto check_dylinker_command;
4553 case LC_DYLD_ENVIRONMENT:
4554 cmd_name = "LC_DYLD_ENVIRONMENT";
4555 goto check_dylinker_command;
4556 check_dylinker_command:
4557 if(l.cmdsize < sizeof(struct dylinker_command)){
4558 Mach_O_error(ofile, "malformed object (%s cmdsize "
4559 "too small) in command %u", cmd_name, i);
4560 goto return_bad;
4562 dyld = (struct dylinker_command *)lc;
4563 if(swapped)
4564 swap_dylinker_command(dyld, host_byte_sex);
4565 if(dyld->cmdsize < sizeof(struct dylinker_command)){
4566 Mach_O_error(ofile, "malformed object (%s command %u has "
4567 "too small cmdsize field)", cmd_name, i);
4568 goto return_bad;
4570 if(dyld->name.offset >= dyld->cmdsize){
4571 Mach_O_error(ofile, "truncated or malformed object (name."
4572 "offset field of %s command %u extends past the end "
4573 "of the file)", cmd_name, i);
4574 goto return_bad;
4576 break;
4578 case LC_UNIXTHREAD:
4579 case LC_THREAD:
4580 if(l.cmdsize < sizeof(struct thread_command)){
4581 Mach_O_error(ofile, "malformed object (%s cmdsize "
4582 "too small) in command %u", l.cmd ==
4583 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4584 "LC_THREAD", i);
4585 goto return_bad;
4587 ut = (struct thread_command *)lc;
4588 if(swapped)
4589 swap_thread_command(ut, host_byte_sex);
4590 state = (char *)ut + sizeof(struct thread_command);
4592 if(cputype == CPU_TYPE_MC680x0){
4593 struct m68k_thread_state_regs *cpu;
4594 struct m68k_thread_state_68882 *fpu;
4595 struct m68k_thread_state_user_reg *user_reg;
4597 nflavor = 0;
4598 p = (char *)ut + ut->cmdsize;
4599 while(state < p){
4600 if(state + sizeof(uint32_t) >
4601 (char *)ut + ut->cmdsize){
4602 Mach_O_error(ofile, "malformed object (flavor in "
4603 "%s command %u extends past end of command)",
4604 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4605 "LC_THREAD", i);
4606 goto return_bad;
4608 flavor = *((uint32_t *)state);
4609 if(swapped){
4610 flavor = SWAP_INT(flavor);
4611 *((uint32_t *)state) = flavor;
4613 state += sizeof(uint32_t);
4614 if(state + sizeof(uint32_t) >
4615 (char *)ut + ut->cmdsize){
4616 Mach_O_error(ofile, "malformed object (count in "
4617 "%s command %u extends past end of command)",
4618 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4619 "LC_THREAD", i);
4620 goto return_bad;
4622 count = *((uint32_t *)state);
4623 if(swapped){
4624 count = SWAP_INT(count);
4625 *((uint32_t *)state) = count;
4627 state += sizeof(uint32_t);
4628 switch(flavor){
4629 case M68K_THREAD_STATE_REGS:
4630 if(count != M68K_THREAD_STATE_REGS_COUNT){
4631 Mach_O_error(ofile, "malformed object (count "
4632 "not M68K_THREAD_STATE_REGS_COUNT for "
4633 "flavor number %u which is a M68K_THREAD_"
4634 "STATE_REGS flavor in %s command %u)",
4635 nflavor, ut->cmd == LC_UNIXTHREAD ?
4636 "LC_UNIXTHREAD" : "LC_THREAD", i);
4637 goto return_bad;
4639 cpu = (struct m68k_thread_state_regs *)state;
4640 if(state + sizeof(struct m68k_thread_state_regs) >
4641 (char *)ut + ut->cmdsize){
4642 Mach_O_error(ofile, "malformed object ("
4643 "M68K_THREAD_STATE_REGS in %s command %u "
4644 "extends past end of command)", ut->cmd ==
4645 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4646 "LC_THREAD", i);
4647 goto return_bad;
4649 if(swapped)
4650 swap_m68k_thread_state_regs(cpu, host_byte_sex);
4651 state += sizeof(struct m68k_thread_state_regs);
4652 break;
4653 case M68K_THREAD_STATE_68882:
4654 if(count != M68K_THREAD_STATE_68882_COUNT){
4655 Mach_O_error(ofile, "malformed object (count "
4656 "not M68K_THREAD_STATE_68882_COUNT for "
4657 "flavor number %u which is a M68K_THREAD_"
4658 "STATE_68882 flavor in %s command %u)",
4659 nflavor, ut->cmd == LC_UNIXTHREAD ?
4660 "LC_UNIXTHREAD" : "LC_THREAD", i);
4661 goto return_bad;
4663 fpu = (struct m68k_thread_state_68882 *)state;
4664 if(state + sizeof(struct m68k_thread_state_68882) >
4665 (char *)ut + ut->cmdsize){
4666 Mach_O_error(ofile, "malformed object ("
4667 "M68K_THREAD_STATE_68882 in %s command %u "
4668 "extends past end of command)", ut->cmd ==
4669 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4670 "LC_THREAD", i);
4671 goto return_bad;
4673 if(swapped)
4674 swap_m68k_thread_state_68882(fpu,host_byte_sex);
4675 state += sizeof(struct m68k_thread_state_68882);
4676 break;
4677 case M68K_THREAD_STATE_USER_REG:
4678 if(count != M68K_THREAD_STATE_USER_REG_COUNT){
4679 Mach_O_error(ofile, "malformed object (count "
4680 "not M68K_THREAD_STATE_USER_REG_COUNT for "
4681 "flavor number %u which is a M68K_THREAD_"
4682 "STATE_USER_REG flavor in %s command %u)",
4683 nflavor, ut->cmd == LC_UNIXTHREAD ?
4684 "LC_UNIXTHREAD" : "LC_THREAD", i);
4685 goto return_bad;
4687 user_reg =
4688 (struct m68k_thread_state_user_reg *)state;
4689 if(state+sizeof(struct m68k_thread_state_user_reg) >
4690 (char *)ut + ut->cmdsize){
4691 Mach_O_error(ofile, "malformed object ("
4692 "M68K_THREAD_STATE_USER_REG in %s command "
4693 "%u extends past end of command)", ut->cmd==
4694 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4695 "LC_THREAD", i);
4696 goto return_bad;
4698 if(swapped)
4699 swap_m68k_thread_state_user_reg(user_reg,
4700 host_byte_sex);
4701 state += sizeof(struct m68k_thread_state_user_reg);
4702 break;
4703 default:
4704 if(swapped){
4705 Mach_O_error(ofile, "malformed object (unknown "
4706 "flavor for flavor number %u in %s command"
4707 " %u can't byte swap it)", nflavor,
4708 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4709 "LC_THREAD", i);
4710 goto return_bad;
4712 state += count * sizeof(uint32_t);
4713 break;
4715 nflavor++;
4717 break;
4719 if(cputype == CPU_TYPE_POWERPC ||
4720 cputype == CPU_TYPE_VEO){
4721 ppc_thread_state_t *nrw_cpu;
4723 nflavor = 0;
4724 p = (char *)ut + ut->cmdsize;
4725 while(state < p){
4726 if(state + sizeof(uint32_t) >
4727 (char *)ut + ut->cmdsize){
4728 Mach_O_error(ofile, "malformed object (flavor in "
4729 "%s command %u extends past end of command)",
4730 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4731 "LC_THREAD", i);
4732 goto return_bad;
4734 flavor = *((uint32_t *)state);
4735 if(swapped){
4736 flavor = SWAP_INT(flavor);
4737 *((uint32_t *)state) = flavor;
4739 state += sizeof(uint32_t);
4740 if(state + sizeof(uint32_t) >
4741 (char *)ut + ut->cmdsize){
4742 Mach_O_error(ofile, "malformed object (count in "
4743 "%s command %u extends past end of command)",
4744 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4745 "LC_THREAD", i);
4746 goto return_bad;
4748 count = *((uint32_t *)state);
4749 if(swapped){
4750 count = SWAP_INT(count);
4751 *((uint32_t *)state) = count;
4753 state += sizeof(uint32_t);
4754 switch(flavor){
4755 case PPC_THREAD_STATE:
4756 if(count != PPC_THREAD_STATE_COUNT){
4757 Mach_O_error(ofile, "malformed object (count "
4758 "not PPC_THREAD_STATE_COUNT for "
4759 "flavor number %u which is a PPC_THREAD_"
4760 "STATE flavor in %s command %u)",
4761 nflavor, ut->cmd == LC_UNIXTHREAD ?
4762 "LC_UNIXTHREAD" : "LC_THREAD", i);
4763 goto return_bad;
4765 nrw_cpu = (ppc_thread_state_t *)state;
4766 if(state + sizeof(ppc_thread_state_t) >
4767 (char *)ut + ut->cmdsize){
4768 Mach_O_error(ofile, "malformed object ("
4769 "PPC_THREAD_STATE in %s command %u extends"
4770 " past end of command)", ut->cmd ==
4771 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4772 "LC_THREAD", i);
4773 goto return_bad;
4775 if(swapped)
4776 swap_ppc_thread_state_t(nrw_cpu,
4777 host_byte_sex);
4778 state += sizeof(ppc_thread_state_t);
4779 break;
4780 default:
4781 if(swapped){
4782 Mach_O_error(ofile, "malformed object (unknown "
4783 "flavor for flavor number %u in %s command"
4784 " %u can't byte swap it)", nflavor,
4785 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4786 "LC_THREAD", i);
4787 goto return_bad;
4789 state += count * sizeof(uint32_t);
4790 break;
4792 nflavor++;
4794 break;
4796 #ifdef PPC_THREAD_STATE64_COUNT
4797 if(cputype == CPU_TYPE_POWERPC64){
4798 ppc_thread_state64_t *cpu;
4800 nflavor = 0;
4801 p = (char *)ut + ut->cmdsize;
4802 while(state < p){
4803 if(state + sizeof(uint32_t) >
4804 (char *)ut + ut->cmdsize){
4805 Mach_O_error(ofile, "malformed object (flavor in "
4806 "%s command %u extends past end of command)",
4807 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4808 "LC_THREAD", i);
4809 goto return_bad;
4811 flavor = *((uint32_t *)state);
4812 if(swapped){
4813 flavor = SWAP_INT(flavor);
4814 *((uint32_t *)state) = flavor;
4816 state += sizeof(uint32_t);
4817 if(state + sizeof(uint32_t) >
4818 (char *)ut + ut->cmdsize){
4819 Mach_O_error(ofile, "malformed object (count in "
4820 "%s command %u extends past end of command)",
4821 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4822 "LC_THREAD", i);
4823 goto return_bad;
4825 count = *((uint32_t *)state);
4826 if(swapped){
4827 count = SWAP_INT(count);
4828 *((uint32_t *)state) = count;
4830 state += sizeof(uint32_t);
4831 switch(flavor){
4832 case PPC_THREAD_STATE64:
4833 if(count != PPC_THREAD_STATE64_COUNT){
4834 Mach_O_error(ofile, "malformed object (count "
4835 "not PPC_THREAD_STATE64_COUNT for "
4836 "flavor number %u which is a PPC_THREAD_"
4837 "STATE64 flavor in %s command %u)",
4838 nflavor, ut->cmd == LC_UNIXTHREAD ?
4839 "LC_UNIXTHREAD" : "LC_THREAD", i);
4840 goto return_bad;
4842 cpu = (ppc_thread_state64_t *)state;
4843 if(state + sizeof(ppc_thread_state64_t) >
4844 (char *)ut + ut->cmdsize){
4845 Mach_O_error(ofile, "malformed object ("
4846 "PPC_THREAD_STATE64 in %s command %u "
4847 "extends past end of command)", ut->cmd ==
4848 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4849 "LC_THREAD", i);
4850 goto return_bad;
4852 if(swapped)
4853 swap_ppc_thread_state64_t(cpu, host_byte_sex);
4854 state += sizeof(ppc_thread_state64_t);
4855 break;
4856 default:
4857 if(swapped){
4858 Mach_O_error(ofile, "malformed object (unknown "
4859 "flavor for flavor number %u in %s command"
4860 " %u can't byte swap it)", nflavor,
4861 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4862 "LC_THREAD", i);
4863 goto return_bad;
4865 state += count * sizeof(uint32_t);
4866 break;
4868 nflavor++;
4870 break;
4872 #endif /* PPC_THREAD_STATE64_COUNT */
4873 if(cputype == CPU_TYPE_MC88000){
4874 m88k_thread_state_grf_t *cpu;
4875 m88k_thread_state_xrf_t *fpu;
4876 m88k_thread_state_user_t *user;
4877 m88110_thread_state_impl_t *spu;
4879 nflavor = 0;
4880 p = (char *)ut + ut->cmdsize;
4881 while(state < p){
4882 if(state + sizeof(uint32_t) >
4883 (char *)ut + ut->cmdsize){
4884 Mach_O_error(ofile, "malformed object (flavor in "
4885 "%s command %u extends past end of command)",
4886 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4887 "LC_THREAD", i);
4888 goto return_bad;
4890 flavor = *((uint32_t *)state);
4891 if(swapped){
4892 flavor = SWAP_INT(flavor);
4893 *((uint32_t *)state) = flavor;
4895 state += sizeof(uint32_t);
4896 if(state + sizeof(uint32_t) >
4897 (char *)ut + ut->cmdsize){
4898 Mach_O_error(ofile, "malformed object (count in "
4899 "%s command %u extends past end of command)",
4900 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4901 "LC_THREAD", i);
4902 goto return_bad;
4904 count = *((uint32_t *)state);
4905 if(swapped){
4906 count = SWAP_INT(count);
4907 *((uint32_t *)state) = count;
4909 state += sizeof(uint32_t);
4910 switch(flavor){
4911 case M88K_THREAD_STATE_GRF:
4912 if(count != M88K_THREAD_STATE_GRF_COUNT){
4913 Mach_O_error(ofile, "malformed object (count "
4914 "not M88K_THREAD_STATE_GRF_COUNT for "
4915 "flavor number %u which is a M88K_THREAD_"
4916 "STATE_GRF flavor in %s command %u)",
4917 nflavor, ut->cmd == LC_UNIXTHREAD ?
4918 "LC_UNIXTHREAD" : "LC_THREAD", i);
4919 goto return_bad;
4921 cpu = (m88k_thread_state_grf_t *)state;
4922 if(state + sizeof(m88k_thread_state_grf_t) >
4923 (char *)ut + ut->cmdsize){
4924 Mach_O_error(ofile, "malformed object ("
4925 "M88K_THREAD_STATE_GRF in %s command %u "
4926 "extends past end of command)", ut->cmd ==
4927 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4928 "LC_THREAD", i);
4929 goto return_bad;
4931 if(swapped)
4932 swap_m88k_thread_state_grf_t(cpu,
4933 host_byte_sex);
4934 state += sizeof(m88k_thread_state_grf_t);
4935 break;
4936 case M88K_THREAD_STATE_XRF:
4937 if(count != M88K_THREAD_STATE_XRF_COUNT){
4938 Mach_O_error(ofile, "malformed object (count "
4939 "not M88K_THREAD_STATE_XRF_COUNT for "
4940 "flavor number %u which is a M88K_THREAD_"
4941 "STATE_XRF flavor in %s command %u)",
4942 nflavor, ut->cmd == LC_UNIXTHREAD ?
4943 "LC_UNIXTHREAD" : "LC_THREAD", i);
4944 goto return_bad;
4946 fpu = (m88k_thread_state_xrf_t *)state;
4947 if(state + sizeof(m88k_thread_state_xrf_t) >
4948 (char *)ut + ut->cmdsize){
4949 Mach_O_error(ofile, "malformed object ("
4950 "M88K_THREAD_STATE_XRF in %s command %u "
4951 "extends past end of command)", ut->cmd ==
4952 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4953 "LC_THREAD", i);
4954 goto return_bad;
4956 if(swapped)
4957 swap_m88k_thread_state_xrf_t(fpu,
4958 host_byte_sex);
4959 state += sizeof(m88k_thread_state_xrf_t);
4960 break;
4961 case M88K_THREAD_STATE_USER:
4962 if(count != M88K_THREAD_STATE_USER_COUNT){
4963 Mach_O_error(ofile, "malformed object (count "
4964 "not M88K_THREAD_STATE_USER_COUNT for "
4965 "flavor number %u which is a M88K_THREAD_"
4966 "STATE_USER flavor in %s command %u)",
4967 nflavor, ut->cmd == LC_UNIXTHREAD ?
4968 "LC_UNIXTHREAD" : "LC_THREAD", i);
4969 goto return_bad;
4971 user = (m88k_thread_state_user_t *)state;
4972 if(state + sizeof(m88k_thread_state_user_t) >
4973 (char *)ut + ut->cmdsize){
4974 Mach_O_error(ofile, "malformed object ("
4975 "M88K_THREAD_STATE_USER in %s command %u "
4976 "extends past end of command)", ut->cmd ==
4977 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4978 "LC_THREAD", i);
4979 goto return_bad;
4981 if(swapped)
4982 swap_m88k_thread_state_user_t(user,
4983 host_byte_sex);
4984 state += sizeof(m88k_thread_state_user_t);
4985 break;
4986 case M88110_THREAD_STATE_IMPL:
4987 if(count != M88110_THREAD_STATE_IMPL_COUNT){
4988 Mach_O_error(ofile, "malformed object (count "
4989 "not M88110_THREAD_STATE_IMPL_COUNT for "
4990 "flavor number %u which is a M88110_THREAD"
4991 "_STATE_IMPL flavor in %s command %u)",
4992 nflavor, ut->cmd == LC_UNIXTHREAD ?
4993 "LC_UNIXTHREAD" : "LC_THREAD", i);
4994 goto return_bad;
4996 spu = (m88110_thread_state_impl_t *)state;
4997 if(state + sizeof(m88110_thread_state_impl_t) >
4998 (char *)ut + ut->cmdsize){
4999 Mach_O_error(ofile, "malformed object ("
5000 "M88110_THREAD_STATE_IMPL in %s command %u "
5001 "extends past end of command)", ut->cmd ==
5002 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5003 "LC_THREAD", i);
5004 goto return_bad;
5006 if(swapped)
5007 swap_m88110_thread_state_impl_t(spu,
5008 host_byte_sex);
5009 state += sizeof(m88110_thread_state_impl_t);
5010 break;
5011 default:
5012 if(swapped){
5013 Mach_O_error(ofile, "malformed object (unknown "
5014 "flavor for flavor number %u in %s command"
5015 " %u can't byte swap it)", nflavor,
5016 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5017 "LC_THREAD", i);
5018 goto return_bad;
5020 state += count * sizeof(uint32_t);
5021 break;
5023 nflavor++;
5025 break;
5027 if(cputype == CPU_TYPE_I860){
5028 #ifdef m68k
5029 struct i860_thread_state_regs *cpu;
5030 #endif
5032 nflavor = 0;
5033 p = (char *)ut + ut->cmdsize;
5034 while(state < p){
5035 if(state + sizeof(uint32_t) >
5036 (char *)ut + ut->cmdsize){
5037 Mach_O_error(ofile, "malformed object (flavor in "
5038 "%s command %u extends past end of command)",
5039 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5040 "LC_THREAD", i);
5041 goto return_bad;
5043 flavor = *((uint32_t *)state);
5044 if(swapped){
5045 flavor = SWAP_INT(flavor);
5046 *((uint32_t *)state) = flavor;
5048 state += sizeof(uint32_t);
5049 if(state + sizeof(uint32_t) >
5050 (char *)ut + ut->cmdsize){
5051 Mach_O_error(ofile, "malformed object (count in "
5052 "%s command %u extends past end of command)",
5053 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5054 "LC_THREAD", i);
5055 return(CHECK_BAD);
5057 count = *((uint32_t *)state);
5058 if(swapped){
5059 count = SWAP_INT(count);
5060 *((uint32_t *)state) = count;
5062 state += sizeof(uint32_t);
5063 switch(flavor){
5064 case I860_THREAD_STATE_REGS:
5065 #ifdef m68k
5066 if(count != I860_THREAD_STATE_REGS_COUNT){
5067 Mach_O_error(ofile, "malformed object (count "
5068 "not I860_THREAD_STATE_REGS_COUNT for "
5069 "flavor number %u which is a I860_THREAD_"
5070 "STATE_REGS flavor in %s command %u)",
5071 nflavor, ut->cmd == LC_UNIXTHREAD ?
5072 "LC_UNIXTHREAD" : "LC_THREAD", i);
5073 goto return_bad;
5075 cpu = (struct i860_thread_state_regs *)state;
5076 if(state + sizeof(struct i860_thread_state_regs) >
5077 (char *)ut + ut->cmdsize){
5078 Mach_O_error(ofile, "malformed object ("
5079 "I860_THREAD_STATE_REGS in %s command %u "
5080 "extends past end of command)", ut->cmd ==
5081 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5082 "LC_THREAD", i);
5083 goto return_bad;
5085 if(swapped)
5086 swap_i860_thread_state_regs(cpu, host_byte_sex);
5087 state += sizeof(struct i860_thread_state_regs);
5088 #else
5089 state += count * sizeof(int);
5090 #endif
5091 break;
5092 default:
5093 if(swapped){
5094 Mach_O_error(ofile, "malformed object (unknown "
5095 "flavor for flavor number %u in %s command"
5096 " %u can't byte swap it)", nflavor,
5097 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5098 "LC_THREAD", i);
5099 goto return_bad;
5101 state += count * sizeof(uint32_t);
5102 break;
5104 nflavor++;
5106 break;
5108 if(cputype == CPU_TYPE_I386){
5109 i386_thread_state_t *cpu;
5110 /* current i386 thread states */
5111 #if i386_THREAD_STATE == 1
5112 struct i386_float_state *fpu;
5113 i386_exception_state_t *exc;
5114 #endif /* i386_THREAD_STATE == 1 */
5116 /* i386 thread states on older releases */
5117 #if i386_THREAD_STATE == -1
5118 i386_thread_fpstate_t *fpu;
5119 i386_thread_exceptstate_t *exc;
5120 i386_thread_cthreadstate_t *user;
5121 #endif /* i386_THREAD_STATE == -1 */
5123 nflavor = 0;
5124 p = (char *)ut + ut->cmdsize;
5125 while(state < p){
5126 if(state + sizeof(uint32_t) >
5127 (char *)ut + ut->cmdsize){
5128 Mach_O_error(ofile, "malformed object (flavor in "
5129 "%s command %u extends past end of command)",
5130 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5131 "LC_THREAD", i);
5132 goto return_bad;
5134 flavor = *((uint32_t *)state);
5135 if(swapped){
5136 flavor = SWAP_INT(flavor);
5137 *((uint32_t *)state) = flavor;
5139 state += sizeof(uint32_t);
5140 if(state + sizeof(uint32_t) >
5141 (char *)ut + ut->cmdsize){
5142 Mach_O_error(ofile, "malformed object (count in "
5143 "%s command %u extends past end of command)",
5144 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5145 "LC_THREAD", i);
5146 goto return_bad;
5148 count = *((uint32_t *)state);
5149 if(swapped){
5150 count = SWAP_INT(count);
5151 *((uint32_t *)state) = count;
5153 state += sizeof(uint32_t);
5154 switch((int)flavor){
5155 case i386_THREAD_STATE:
5156 #if i386_THREAD_STATE == 1
5157 case -1:
5158 #endif /* i386_THREAD_STATE == 1 */
5159 /* i386 thread states on older releases */
5160 #if i386_THREAD_STATE == -1
5161 case 1:
5162 #endif /* i386_THREAD_STATE == -1 */
5163 if(count != i386_THREAD_STATE_COUNT){
5164 Mach_O_error(ofile, "malformed object (count "
5165 "not i386_THREAD_STATE_COUNT for flavor "
5166 "number %u which is a i386_THREAD_STATE "
5167 "flavor in %s command %u)", nflavor,
5168 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5169 "LC_THREAD", i);
5170 goto return_bad;
5172 cpu = (i386_thread_state_t *)state;
5173 if(state + sizeof(i386_thread_state_t) >
5174 (char *)ut + ut->cmdsize){
5175 Mach_O_error(ofile, "malformed object ("
5176 "i386_THREAD_STATE in %s command %u "
5177 "extends past end of command)", ut->cmd ==
5178 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5179 "LC_THREAD", i);
5180 goto return_bad;
5182 if(swapped)
5183 swap_i386_thread_state(cpu, host_byte_sex);
5184 state += sizeof(i386_thread_state_t);
5185 break;
5186 /* current i386 thread states */
5187 #if i386_THREAD_STATE == 1
5188 case i386_FLOAT_STATE:
5189 if(count != i386_FLOAT_STATE_COUNT){
5190 Mach_O_error(ofile, "malformed object (count "
5191 "not i386_FLOAT_STATE_COUNT for flavor "
5192 "number %u which is a i386_FLOAT_STATE "
5193 "flavor in %s command %u)", nflavor,
5194 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5195 "LC_THREAD", i);
5196 goto return_bad;
5198 fpu = (struct i386_float_state *)state;
5199 if(state + sizeof(struct i386_float_state) >
5200 (char *)ut + ut->cmdsize){
5201 Mach_O_error(ofile, "malformed object ("
5202 "i386_FLOAT_STATE in %s command %u "
5203 "extends past end of command)", ut->cmd ==
5204 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5205 "LC_THREAD", i);
5206 goto return_bad;
5208 if(swapped)
5209 swap_i386_float_state(fpu, host_byte_sex);
5210 state += sizeof(struct i386_float_state);
5211 break;
5212 case i386_EXCEPTION_STATE:
5213 if(count != I386_EXCEPTION_STATE_COUNT){
5214 Mach_O_error(ofile, "malformed object (count "
5215 "not I386_EXCEPTION_STATE_COUNT for "
5216 "flavor number %u which is a i386_"
5217 "EXCEPTION_STATE flavor in %s command %u)",
5218 nflavor,
5219 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5220 "LC_THREAD", i);
5221 goto return_bad;
5223 exc = (i386_exception_state_t *)state;
5224 if(state + sizeof(i386_exception_state_t) >
5225 (char *)ut + ut->cmdsize){
5226 Mach_O_error(ofile, "malformed object ("
5227 "i386_EXCEPTION_STATE in %s command %u "
5228 "extends past end of command)", ut->cmd ==
5229 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5230 "LC_THREAD", i);
5231 goto return_bad;
5233 if(swapped)
5234 swap_i386_exception_state(exc,host_byte_sex);
5235 state += sizeof(i386_exception_state_t);
5236 break;
5237 #endif /* i386_THREAD_STATE == 1 */
5239 /* i386 thread states on older releases */
5240 #if i386_THREAD_STATE == -1
5241 case i386_THREAD_FPSTATE:
5242 if(count != i386_THREAD_FPSTATE_COUNT){
5243 Mach_O_error(ofile, "malformed object (count "
5244 "not i386_THREAD_FPSTATE_COUNT for flavor "
5245 "number %u which is a i386_THREAD_FPSTATE "
5246 "flavor in %s command %u)", nflavor,
5247 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5248 "LC_THREAD", i);
5249 goto return_bad;
5251 fpu = (i386_thread_fpstate_t *)state;
5252 if(state + sizeof(i386_thread_fpstate_t) >
5253 (char *)ut + ut->cmdsize){
5254 Mach_O_error(ofile, "malformed object ("
5255 "i386_THREAD_FPSTATE in %s command %u "
5256 "extends past end of command)", ut->cmd ==
5257 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5258 "LC_THREAD", i);
5259 goto return_bad;
5261 if(swapped)
5262 swap_i386_thread_fpstate(fpu, host_byte_sex);
5263 state += sizeof(i386_thread_fpstate_t);
5264 break;
5265 case i386_THREAD_EXCEPTSTATE:
5266 if(count != i386_THREAD_EXCEPTSTATE_COUNT){
5267 Mach_O_error(ofile, "malformed object (count "
5268 "not i386_THREAD_EXCEPTSTATE_COUNT for "
5269 "flavor number %u which is a i386_THREAD_"
5270 "EXCEPTSTATE flavor in %s command %u)",
5271 nflavor,
5272 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5273 "LC_THREAD", i);
5274 goto return_bad;
5276 exc = (i386_thread_exceptstate_t *)state;
5277 if(state + sizeof(i386_thread_exceptstate_t) >
5278 (char *)ut + ut->cmdsize){
5279 Mach_O_error(ofile, "malformed object ("
5280 "i386_THREAD_EXCEPTSTATE in %s command %u "
5281 "extends past end of command)", ut->cmd ==
5282 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5283 "LC_THREAD", i);
5284 goto return_bad;
5286 if(swapped)
5287 swap_i386_thread_exceptstate(exc,host_byte_sex);
5288 state += sizeof(i386_thread_exceptstate_t);
5289 break;
5290 case i386_THREAD_CTHREADSTATE:
5291 if(count != i386_THREAD_CTHREADSTATE_COUNT){
5292 Mach_O_error(ofile, "malformed object (count "
5293 "not i386_THREAD_CTHREADSTATE_COUNT for "
5294 "flavor number %u which is a i386_THREAD_"
5295 "CTHREADSTATE flavor in %s command %u)",
5296 nflavor,
5297 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5298 "LC_THREAD", i);
5299 goto return_bad;
5301 user = (i386_thread_cthreadstate_t *)state;
5302 if(state + sizeof(i386_thread_cthreadstate_t) >
5303 (char *)ut + ut->cmdsize){
5304 Mach_O_error(ofile, "malformed object ("
5305 "i386_THREAD_CTHREADSTATE in %s command %u "
5306 "extends past end of command)", ut->cmd ==
5307 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5308 "LC_THREAD", i);
5309 goto return_bad;
5311 if(swapped)
5312 swap_i386_thread_cthreadstate(user,
5313 host_byte_sex);
5314 state += sizeof(i386_thread_cthreadstate_t);
5315 break;
5316 #endif /* i386_THREAD_STATE == -1 */
5317 default:
5318 if(swapped){
5319 Mach_O_error(ofile, "malformed object (unknown "
5320 "flavor for flavor number %u in %s command"
5321 " %u can't byte swap it)", nflavor,
5322 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5323 "LC_THREAD", i);
5324 goto return_bad;
5326 state += count * sizeof(uint32_t);
5327 break;
5329 nflavor++;
5331 break;
5333 #ifdef x86_THREAD_STATE64_COUNT
5334 if(cputype == CPU_TYPE_X86_64){
5335 x86_thread_state64_t *cpu;
5337 nflavor = 0;
5338 p = (char *)ut + ut->cmdsize;
5339 while(state < p){
5340 if(state + sizeof(uint32_t) >
5341 (char *)ut + ut->cmdsize){
5342 Mach_O_error(ofile, "malformed object (flavor in "
5343 "%s command %u extends past end of command)",
5344 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5345 "LC_THREAD", i);
5346 goto return_bad;
5348 flavor = *((uint32_t *)state);
5349 if(swapped){
5350 flavor = SWAP_INT(flavor);
5351 *((uint32_t *)state) = flavor;
5353 state += sizeof(uint32_t);
5354 if(state + sizeof(uint32_t) >
5355 (char *)ut + ut->cmdsize){
5356 Mach_O_error(ofile, "malformed object (count in "
5357 "%s command %u extends past end of command)",
5358 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5359 "LC_THREAD", i);
5360 goto return_bad;
5362 count = *((uint32_t *)state);
5363 if(swapped){
5364 count = SWAP_INT(count);
5365 *((uint32_t *)state) = count;
5367 state += sizeof(uint32_t);
5368 switch(flavor){
5369 case x86_THREAD_STATE64:
5370 if(count != x86_THREAD_STATE64_COUNT){
5371 Mach_O_error(ofile, "malformed object (count "
5372 "not x86_THREAD_STATE64_COUNT for "
5373 "flavor number %u which is a x86_THREAD_"
5374 "STATE64 flavor in %s command %u)",
5375 nflavor, ut->cmd == LC_UNIXTHREAD ?
5376 "LC_UNIXTHREAD" : "LC_THREAD", i);
5377 goto return_bad;
5379 cpu = (x86_thread_state64_t *)state;
5380 if(state + sizeof(x86_thread_state64_t) >
5381 (char *)ut + ut->cmdsize){
5382 Mach_O_error(ofile, "malformed object ("
5383 "x86_THREAD_STATE64 in %s command %u "
5384 "extends past end of command)", ut->cmd ==
5385 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5386 "LC_THREAD", i);
5387 goto return_bad;
5389 if(swapped)
5390 swap_x86_thread_state64(cpu, host_byte_sex);
5391 state += sizeof(x86_thread_state64_t);
5392 break;
5393 default:
5394 if(swapped){
5395 Mach_O_error(ofile, "malformed object (unknown "
5396 "flavor for flavor number %u in %s command"
5397 " %u can't byte swap it)", nflavor,
5398 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5399 "LC_THREAD", i);
5400 goto return_bad;
5402 state += count * sizeof(uint32_t);
5403 break;
5405 nflavor++;
5407 break;
5409 #endif /* x86_THREAD_STATE64_COUNT */
5410 if(cputype == CPU_TYPE_HPPA){
5411 struct hp_pa_integer_thread_state *cpu;
5412 struct hp_pa_frame_thread_state *frame;
5413 struct hp_pa_fp_thread_state *fpu;
5415 nflavor = 0;
5416 p = (char *)ut + ut->cmdsize;
5417 while(state < p){
5418 if(state + sizeof(uint32_t) >
5419 (char *)ut + ut->cmdsize){
5420 Mach_O_error(ofile, "malformed object (flavor in "
5421 "%s command %u extends past end of command)",
5422 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5423 "LC_THREAD", i);
5424 goto return_bad;
5426 flavor = *((uint32_t *)state);
5427 if(swapped){
5428 flavor = SWAP_INT(flavor);
5429 *((uint32_t *)state) = flavor;
5431 state += sizeof(uint32_t);
5432 if(state + sizeof(uint32_t) >
5433 (char *)ut + ut->cmdsize){
5434 Mach_O_error(ofile, "malformed object (count in "
5435 "%s command %u extends past end of command)",
5436 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5437 "LC_THREAD", i);
5438 goto return_bad;
5440 count = *((uint32_t *)state);
5441 if(swapped){
5442 count = SWAP_INT(count);
5443 *((uint32_t *)state) = count;
5445 state += sizeof(uint32_t);
5446 switch(flavor){
5447 case HPPA_INTEGER_THREAD_STATE:
5448 if(count != HPPA_INTEGER_THREAD_STATE_COUNT){
5449 Mach_O_error(ofile, "malformed object (count "
5450 "not HPPA_INTEGER_THREAD_STATE_COUNT for "
5451 "flavor number %u which is a "
5452 "HPPA_INTEGER_THREAD_STATE "
5453 "flavor in %s command %u)", nflavor,
5454 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5455 "LC_THREAD", i);
5456 goto return_bad;
5458 cpu = (struct hp_pa_integer_thread_state *)state;
5459 if(state+sizeof(struct hp_pa_integer_thread_state) >
5460 (char *)ut + ut->cmdsize){
5461 Mach_O_error(ofile, "malformed object ("
5462 "HPPA_INTEGER_THREAD_STATE in %s command "
5463 "%u extends past end of command)",
5464 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5465 "LC_THREAD", i);
5466 goto return_bad;
5468 if(swapped)
5469 swap_hppa_integer_thread_state(cpu,
5470 host_byte_sex);
5471 state += sizeof(struct hp_pa_integer_thread_state);
5472 break;
5473 case HPPA_FRAME_THREAD_STATE:
5474 if(count != HPPA_FRAME_THREAD_STATE_COUNT){
5475 Mach_O_error(ofile, "malformed object (count "
5476 "not HPPA_FRAME_THREAD_STATE_COUNT for "
5477 "flavor number %u which is a HPPA_FRAME_"
5478 "THREAD_STATE flavor in %s command %u)",
5479 nflavor,
5480 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5481 "LC_THREAD", i);
5482 goto return_bad;
5484 frame = (struct hp_pa_frame_thread_state *)state;
5485 if(state + sizeof(struct hp_pa_frame_thread_state) >
5486 (char *)ut + ut->cmdsize){
5487 Mach_O_error(ofile, "malformed object ("
5488 "HPPA_FRAME_THREAD_STATE in %s command "
5489 "%u extends past end of command)",
5490 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5491 "LC_THREAD", i);
5492 goto return_bad;
5494 if(swapped)
5495 swap_hppa_frame_thread_state(frame,host_byte_sex);
5496 state += sizeof(struct hp_pa_frame_thread_state);
5497 break;
5498 case HPPA_FP_THREAD_STATE:
5499 if(count != HPPA_FP_THREAD_STATE_COUNT){
5500 Mach_O_error(ofile, "malformed object (count "
5501 "not HPPA_FP_THREAD_STATE_COUNT for "
5502 "flavor number %u which is a HPPA_FP_"
5503 "THREAD_STATE flavor in %s command %u)",
5504 nflavor,
5505 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5506 "LC_THREAD", i);
5507 goto return_bad;
5509 fpu = (struct hp_pa_fp_thread_state *)state;
5510 if(state + sizeof(struct hp_pa_fp_thread_state) >
5511 (char *)ut + ut->cmdsize){
5512 Mach_O_error(ofile, "malformed object ("
5513 "HPPA_FP_THREAD_STATE in %s command "
5514 "%u extends past end of command)",
5515 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5516 "LC_THREAD", i);
5517 goto return_bad;
5519 if(swapped)
5520 swap_hppa_fp_thread_state(fpu,host_byte_sex);
5521 state += sizeof(struct hp_pa_fp_thread_state);
5522 break;
5523 default:
5524 if(swapped){
5525 Mach_O_error(ofile, "malformed object (unknown "
5526 "flavor for flavor number %u in %s command"
5527 " %u can't byte swap it)", nflavor,
5528 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5529 "LC_THREAD", i);
5530 goto return_bad;
5532 state += count * sizeof(uint32_t);
5533 break;
5535 nflavor++;
5537 break;
5539 if(cputype == CPU_TYPE_SPARC){
5540 struct sparc_thread_state_regs *cpu;
5541 struct sparc_thread_state_fpu *fpu;
5543 nflavor = 0;
5544 p = (char *)ut + ut->cmdsize;
5545 while(state < p){
5546 if(state + sizeof(uint32_t) >
5547 (char *)ut + ut->cmdsize){
5548 Mach_O_error(ofile, "malformed object (flavor in "
5549 "%s command %u extends past end of command)",
5550 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5551 "LC_THREAD", i);
5552 goto return_bad;
5554 flavor = *((uint32_t *)state);
5555 if(swapped){
5556 flavor = SWAP_INT(flavor);
5557 *((uint32_t *)state) = flavor;
5559 state += sizeof(uint32_t);
5560 if(state + sizeof(uint32_t) >
5561 (char *)ut + ut->cmdsize){
5562 Mach_O_error(ofile, "malformed object (count in "
5563 "%s command %u extends past end of command)",
5564 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5565 "LC_THREAD", i);
5566 goto return_bad;
5568 count = *((uint32_t *)state);
5569 if(swapped){
5570 count = SWAP_INT(count);
5571 *((uint32_t *)state) = count;
5573 state += sizeof(uint32_t);
5574 switch(flavor){
5575 case SPARC_THREAD_STATE_REGS:
5576 if(count != SPARC_THREAD_STATE_REGS_COUNT){
5577 Mach_O_error(ofile, "malformed object (count "
5578 "not SPARC_THREAD_STATE_REGS_COUNT for "
5579 "flavor number %u which is a SPARC_THREAD_"
5580 "STATE_REGS flavor in %s command %u)",
5581 nflavor, ut->cmd == LC_UNIXTHREAD ?
5582 "LC_UNIXTHREAD" : "LC_THREAD", i);
5583 goto return_bad;
5585 cpu = (struct sparc_thread_state_regs *)state;
5586 if(state + sizeof(struct sparc_thread_state_regs) >
5587 (char *)ut + ut->cmdsize){
5588 Mach_O_error(ofile, "malformed object ("
5589 "SPARC_THREAD_STATE_REGS in %s command %u "
5590 "extends past end of command)", ut->cmd ==
5591 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5592 "LC_THREAD", i);
5593 goto return_bad;
5595 if(swapped)
5596 swap_sparc_thread_state_regs(cpu, host_byte_sex);
5597 state += sizeof(struct sparc_thread_state_regs);
5598 break;
5599 case SPARC_THREAD_STATE_FPU:
5600 if(count != SPARC_THREAD_STATE_FPU_COUNT){
5601 Mach_O_error(ofile, "malformed object (count "
5602 "not SPARC_THREAD_STATE_FPU_COUNT for "
5603 "flavor number %u which is a SPARC_THREAD_"
5604 "STATE_FPU flavor in %s command %u)",
5605 nflavor, ut->cmd == LC_UNIXTHREAD ?
5606 "LC_UNIXTHREAD" : "LC_THREAD", i);
5607 goto return_bad;
5609 fpu = (struct sparc_thread_state_fpu *)state;
5610 if(state + sizeof(struct sparc_thread_state_fpu) >
5611 (char *)ut + ut->cmdsize){
5612 Mach_O_error(ofile, "malformed object ("
5613 "SPARC_THREAD_STATE_FPU in %s command %u "
5614 "extends past end of command)", ut->cmd ==
5615 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5616 "LC_THREAD", i);
5617 goto return_bad;
5619 if(swapped)
5620 swap_sparc_thread_state_fpu(fpu, host_byte_sex);
5621 state += sizeof(struct sparc_thread_state_fpu);
5622 break;
5623 default:
5624 if(swapped){
5625 Mach_O_error(ofile, "malformed object (unknown "
5626 "flavor for flavor number %u in %s command"
5627 " %u can't byte swap it)", nflavor,
5628 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5629 "LC_THREAD", i);
5630 goto return_bad;
5632 state += count * sizeof(uint32_t);
5633 break;
5635 nflavor++;
5637 break;
5639 if(cputype == CPU_TYPE_ARM){
5640 arm_thread_state_t *cpu;
5642 nflavor = 0;
5643 p = (char *)ut + ut->cmdsize;
5644 while(state < p){
5645 if(state + sizeof(uint32_t) >
5646 (char *)ut + ut->cmdsize){
5647 Mach_O_error(ofile, "malformed object (flavor in "
5648 "%s command %u extends past end of command)",
5649 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5650 "LC_THREAD", i);
5651 goto return_bad;
5653 flavor = *((uint32_t *)state);
5654 if(swapped){
5655 flavor = SWAP_INT(flavor);
5656 *((uint32_t *)state) = flavor;
5658 state += sizeof(uint32_t);
5659 if(state + sizeof(uint32_t) >
5660 (char *)ut + ut->cmdsize){
5661 Mach_O_error(ofile, "malformed object (count in "
5662 "%s command %u extends past end of command)",
5663 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5664 "LC_THREAD", i);
5665 goto return_bad;
5667 count = *((uint32_t *)state);
5668 if(swapped){
5669 count = SWAP_INT(count);
5670 *((uint32_t *)state) = count;
5672 state += sizeof(uint32_t);
5673 switch(flavor){
5674 case ARM_THREAD_STATE:
5675 if(count != ARM_THREAD_STATE_COUNT){
5676 Mach_O_error(ofile, "malformed object (count "
5677 "not ARM_THREAD_STATE_COUNT for "
5678 "flavor number %u which is a ARM_THREAD_"
5679 "STATE flavor in %s command %u)",
5680 nflavor, ut->cmd == LC_UNIXTHREAD ?
5681 "LC_UNIXTHREAD" : "LC_THREAD", i);
5682 goto return_bad;
5684 cpu = (arm_thread_state_t *)state;
5685 if(state + sizeof(arm_thread_state_t) >
5686 (char *)ut + ut->cmdsize){
5687 Mach_O_error(ofile, "malformed object ("
5688 "ARM_THREAD_STATE in %s command %u "
5689 "extends past end of command)", ut->cmd ==
5690 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5691 "LC_THREAD", i);
5692 goto return_bad;
5694 if(swapped)
5695 swap_arm_thread_state_t(cpu, host_byte_sex);
5696 state += sizeof(arm_thread_state_t);
5697 break;
5698 default:
5699 if(swapped){
5700 Mach_O_error(ofile, "malformed object (unknown "
5701 "flavor for flavor number %u in %s command"
5702 " %u can't byte swap it)", nflavor,
5703 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5704 "LC_THREAD", i);
5705 goto return_bad;
5707 state += count * sizeof(uint32_t);
5708 break;
5710 nflavor++;
5712 break;
5714 if(swapped){
5715 Mach_O_error(ofile, "malformed object (unknown cputype and "
5716 "cpusubtype of object and can't byte swap and check %s "
5717 "command %u)", ut->cmd == LC_UNIXTHREAD ?
5718 "LC_UNIXTHREAD" : "LC_THREAD", i);
5719 goto return_bad;
5721 break;
5722 case LC_MAIN:
5723 if(l.cmdsize < sizeof(struct entry_point_command)){
5724 Mach_O_error(ofile, "malformed object (LC_MAIN cmdsize "
5725 "too small) in command %u", i);
5726 goto return_bad;
5728 ep = (struct entry_point_command *)lc;
5729 if(swapped)
5730 swap_entry_point_command(ep, host_byte_sex);
5732 * If we really wanted we could check that the entryoff field
5733 * really is an offset into the __TEXT segment. But since it
5734 * is not used here, we won't needlessly check it.
5736 break;
5737 case LC_SOURCE_VERSION:
5738 if(l.cmdsize < sizeof(struct source_version_command)){
5739 Mach_O_error(ofile, "malformed object (LC_SOURCE_VERSION "
5740 "cmdsize too small) in command %u", i);
5741 goto return_bad;
5743 sv = (struct source_version_command *)lc;
5744 if(swapped)
5745 swap_source_version_command(sv, host_byte_sex);
5746 case LC_IDENT:
5747 if(l.cmdsize < sizeof(struct ident_command)){
5748 Mach_O_error(ofile, "malformed object (LC_IDENT cmdsize "
5749 "too small) in command %u", i);
5750 goto return_bad;
5752 id = (struct ident_command *)lc;
5753 if(swapped)
5754 swap_ident_command(id, host_byte_sex);
5756 * Note the cmdsize field if the LC_IDENT command was checked
5757 * as part of checking all load commands cmdsize field before
5758 * the switch statement on the cmd field of the load command.
5760 break;
5761 case LC_RPATH:
5762 if(l.cmdsize < sizeof(struct rpath_command)){
5763 Mach_O_error(ofile, "malformed object (LC_RPATH: cmdsize "
5764 "too small) in command %u", i);
5765 goto return_bad;
5767 rpath = (struct rpath_command *)lc;
5768 if(swapped)
5769 swap_rpath_command(rpath, host_byte_sex);
5770 if(rpath->cmdsize < sizeof(struct rpath_command)){
5771 Mach_O_error(ofile, "malformed object (LC_RPATH command "
5772 "%u has too small cmdsize field)", i);
5773 goto return_bad;
5775 if(rpath->path.offset >= rpath->cmdsize){
5776 Mach_O_error(ofile, "truncated or malformed object (path."
5777 "offset field of LC_RPATH command %u extends past the "
5778 "end of the file)", i);
5779 goto return_bad;
5781 break;
5783 #ifndef OFI
5784 default:
5785 Mach_O_error(ofile, "malformed object (unknown load command "
5786 "%u)", i);
5787 goto return_bad;
5788 #endif /* !defined(OFI) */
5791 lc = (struct load_command *)((char *)lc + l.cmdsize);
5792 /* check that next load command does not extends past the end */
5793 if((char *)lc > (char *)load_commands + sizeofcmds){
5794 Mach_O_error(ofile, "truncated or malformed object (load "
5795 "command %u extends past the end of the file)",
5796 i + 1);
5797 goto return_bad;
5800 if(st == NULL){
5801 if(dyst != NULL){
5802 Mach_O_error(ofile, "truncated or malformed object (contains "
5803 "LC_DYSYMTAB load command without a LC_SYMTAB load command)");
5804 goto return_bad;
5807 else{
5808 if(dyst != NULL){
5809 if(dyst->nlocalsym != 0 &&
5810 dyst->ilocalsym > st->nsyms){
5811 Mach_O_error(ofile, "truncated or malformed object "
5812 "(ilocalsym in LC_DYSYMTAB load command extends past "
5813 "the end of the symbol table)");
5814 goto return_bad;
5816 big_size = dyst->ilocalsym;
5817 big_size += dyst->nlocalsym;
5818 if(dyst->nlocalsym != 0 && big_size > st->nsyms){
5819 Mach_O_error(ofile, "truncated or malformed object "
5820 "(ilocalsym plus nlocalsym in LC_DYSYMTAB load command "
5821 "extends past the end of the symbol table)");
5822 goto return_bad;
5825 if(dyst->nextdefsym != 0 &&
5826 dyst->iextdefsym > st->nsyms){
5827 Mach_O_error(ofile, "truncated or malformed object "
5828 "(iextdefsym in LC_DYSYMTAB load command extends past "
5829 "the end of the symbol table)");
5830 goto return_bad;
5832 big_size = dyst->iextdefsym;
5833 big_size += dyst->nextdefsym;
5834 if(dyst->nextdefsym != 0 && big_size > st->nsyms){
5835 Mach_O_error(ofile, "truncated or malformed object "
5836 "(iextdefsym plus nextdefsym in LC_DYSYMTAB load "
5837 "command extends past the end of the symbol table)");
5838 goto return_bad;
5841 if(dyst->nundefsym != 0 &&
5842 dyst->iundefsym > st->nsyms){
5843 Mach_O_error(ofile, "truncated or malformed object "
5844 "(iundefsym in LC_DYSYMTAB load command extends past "
5845 "the end of the symbol table)");
5846 goto return_bad;
5848 big_size = dyst->iundefsym;
5849 big_size += dyst->nundefsym;
5850 if(dyst->nundefsym != 0 && big_size > st->nsyms){
5851 Mach_O_error(ofile, "truncated or malformed object "
5852 "(iundefsym plus nundefsym in LC_DYSYMTAB load command "
5853 "extends past the end of the symbol table)");
5854 goto return_bad;
5856 if(rc != NULL){
5857 if(rc->init_module > dyst->nmodtab){
5858 Mach_O_error(ofile, "malformed object (init_module in "
5859 "LC_ROUTINES load command extends past the "
5860 "end of the module table)");
5861 goto return_bad;
5864 if(rc64 != NULL){
5865 if(rc64->init_module > dyst->nmodtab){
5866 Mach_O_error(ofile, "malformed object (init_module in "
5867 "LC_ROUTINES_64 load command extends past the "
5868 "end of the module table)");
5869 goto return_bad;
5872 if(hints != NULL){
5873 if(hints->nhints != dyst->nundefsym){
5874 Mach_O_error(ofile, "malformed object (nhints in "
5875 "LC_TWOLEVEL_HINTS load command not the same as "
5876 "nundefsym in LC_DYSYMTAB load command)");
5877 goto return_bad;
5882 /* check for an inconsistent size of the load commands */
5883 if((char *)load_commands + sizeofcmds != (char *)lc){
5884 Mach_O_error(ofile, "malformed object (inconsistent sizeofcmds "
5885 "field in mach header)");
5886 goto return_bad;
5890 * Mark this ofile so we know its headers have been swapped. We do this
5891 * in case we don't process it the first time so we can swap them back
5892 * in case we loop back to it in a fat file to process it later.
5894 if(swapped == TRUE)
5895 ofile->headers_swapped = TRUE;
5897 /* looks good return ok */
5898 free_elements(&elements);
5899 return(CHECK_GOOD);
5901 return_bad:
5902 free_elements(&elements);
5903 return(CHECK_BAD);
5904 #endif /* OTOOL */
5908 * swap_back_Mach_O() is called after the ofile has been processed to swap back
5909 * the mach header and load commands if check_Mach_O() above swapped them.
5911 static
5912 void
5913 swap_back_Mach_O(
5914 struct ofile *ofile)
5916 if(ofile->headers_swapped == TRUE){
5917 ofile->headers_swapped = FALSE;
5918 if(ofile->mh != NULL)
5919 swap_object_headers(ofile->mh, ofile->load_commands);
5920 else if(ofile->mh64 != NULL)
5921 swap_object_headers(ofile->mh64, ofile->load_commands);
5925 #ifndef OTOOL
5927 * check_overlaping_element() checks that the element in the ofile described by
5928 * offset, size and name does not overlap in list of elements in head. If it
5929 * does CHECK_BAD is returned and an error message is generated. If it doesn't
5930 * then an element is added in the ordered list and CHECK_GOOD is returned
5932 static
5933 enum check_type
5934 check_overlaping_element(
5935 struct ofile *ofile,
5936 struct element *head,
5937 uint32_t offset,
5938 uint32_t size,
5939 char *name)
5941 struct element *e, *p, *n;
5943 if(size == 0)
5944 return(CHECK_GOOD);
5946 if(head->next == NULL){
5947 n = allocate(sizeof(struct element));
5948 n->offset = offset;
5949 n->size = size;
5950 n->name = name;
5951 n->next = NULL;
5952 head->next = n;
5953 return(CHECK_GOOD);
5956 p = NULL;
5957 e = head;
5958 while(e->next != NULL){
5959 p = e;
5960 e = e->next;
5961 if((offset >= e->offset &&
5962 offset < e->offset + e->size) ||
5963 (offset + size > e->offset &&
5964 offset + size < e->offset + e->size) ||
5965 (offset <= e->offset &&
5966 offset + size >= e->offset + e->size)){
5967 Mach_O_error(ofile, "malformed object (%s at offset %u with a "
5968 "size of %u, overlaps %s at offset %u with a size of %u)",
5969 name, offset, size, e->name, e->offset, e->size);
5970 return(CHECK_BAD);
5972 if(e->next != NULL && offset + size <= e->next->offset){
5973 n = allocate(sizeof(struct element));
5974 n->offset = offset;
5975 n->size = size;
5976 n->name = name;
5977 n->next = e;
5978 p->next = n;
5979 return(CHECK_GOOD);
5982 n = allocate(sizeof(struct element));
5983 n->offset = offset;
5984 n->size = size;
5985 n->name = name;
5986 n->next = NULL;
5987 e->next = n;
5988 return(CHECK_GOOD);
5992 * free_elements() frees the list of elements on the list head.
5994 static
5995 void
5996 free_elements(
5997 struct element *head)
5999 struct element *e, *e_next;
6001 e = head->next;
6002 while(e != NULL){
6003 e_next = e->next;
6004 free(e);
6005 e = e_next;
6008 #endif /* !defined(OTOOL) */
6011 * check_dylib_module() checks the object file's dylib_module as referenced
6012 * by the dylib_module field in the ofile for correctness.
6014 static
6015 enum check_type
6016 check_dylib_module(
6017 struct ofile *ofile,
6018 struct symtab_command *st,
6019 struct dysymtab_command *dyst,
6020 char *strings,
6021 uint32_t module_index)
6023 #ifdef OTOOL
6024 return(CHECK_GOOD);
6025 #else /* !defined OTOOL */
6026 uint32_t i;
6027 enum byte_sex host_byte_sex;
6028 enum bool swapped;
6029 struct dylib_module m;
6030 struct dylib_module_64 m64;
6031 uint32_t module_name, nextdefsym, iextdefsym, nlocalsym, ilocalsym, nrefsym;
6032 uint32_t irefsym, nextrel, iextrel;
6034 host_byte_sex = get_host_byte_sex();
6035 swapped = (enum bool)(host_byte_sex != ofile->object_byte_sex);
6036 if(ofile->mh != NULL){
6037 m = *ofile->dylib_module;
6038 if(swapped)
6039 swap_dylib_module(&m, 1, host_byte_sex);
6040 module_name = m.module_name;
6041 nextdefsym = m.nextdefsym;
6042 iextdefsym = m.iextdefsym;
6043 nlocalsym = m.nlocalsym;
6044 ilocalsym = m.ilocalsym;
6045 nrefsym = m.nrefsym;
6046 irefsym = m.irefsym;
6047 nextrel = m.nextrel;
6048 iextrel = m.iextrel;
6050 else{
6051 m64 = *ofile->dylib_module64;
6052 if(swapped)
6053 swap_dylib_module_64(&m64, 1, host_byte_sex);
6054 module_name = m64.module_name;
6055 nextdefsym = m64.nextdefsym;
6056 iextdefsym = m64.iextdefsym;
6057 nlocalsym = m64.nlocalsym;
6058 ilocalsym = m64.ilocalsym;
6059 nrefsym = m64.nrefsym;
6060 irefsym = m64.irefsym;
6061 nextrel = m64.nextrel;
6062 iextrel = m64.iextrel;
6065 if(module_name > st->strsize){
6066 Mach_O_error(ofile, "truncated or malformed object (module_name "
6067 "of module table entry %u past the end of the string table)",
6068 module_index);
6069 return(CHECK_BAD);
6071 for(i = module_name; i < st->strsize && strings[i] != '\0'; i++)
6073 if(i >= st->strsize){
6074 Mach_O_error(ofile, "truncated or malformed object (module_name "
6075 "of module table entry %u extends past the end of the string "
6076 "table)", module_index);
6077 return(CHECK_BAD);
6080 if(nextdefsym != 0){
6081 if(iextdefsym > st->nsyms){
6082 Mach_O_error(ofile, "truncated or malformed object (iextdefsym "
6083 "field of module table entry %u past the end of the "
6084 "symbol table", module_index);
6085 return(CHECK_BAD);
6087 if(iextdefsym + nextdefsym > st->nsyms){
6088 Mach_O_error(ofile, "truncated or malformed object (iextdefsym "
6089 "field of module table entry %u plus nextdefsym field "
6090 "extends past the end of the symbol table", module_index);
6091 return(CHECK_BAD);
6094 if(nlocalsym != 0){
6095 if(ilocalsym > st->nsyms){
6096 Mach_O_error(ofile, "truncated or malformed object (ilocalsym "
6097 "field of module table entry %u past the end of the "
6098 "symbol table", module_index);
6099 return(CHECK_BAD);
6101 if(ilocalsym + nlocalsym > st->nsyms){
6102 Mach_O_error(ofile, "truncated or malformed object (ilocalsym "
6103 "field of module table entry %u plus nlocalsym field "
6104 "extends past the end of the symbol table", module_index);
6105 return(CHECK_BAD);
6108 if(nrefsym != 0){
6109 if(irefsym > dyst->nextrefsyms){
6110 Mach_O_error(ofile, "truncated or malformed object (irefsym "
6111 "field of module table entry %u past the end of the "
6112 "reference table", module_index);
6113 return(CHECK_BAD);
6115 if(irefsym + nrefsym > dyst->nextrefsyms){
6116 Mach_O_error(ofile, "truncated or malformed object (irefsym "
6117 "field of module table entry %u plus nrefsym field "
6118 "extends past the end of the reference table",module_index);
6119 return(CHECK_BAD);
6122 if(nextrel != 0){
6123 if(iextrel > dyst->extreloff){
6124 Mach_O_error(ofile, "truncated or malformed object (iextrel "
6125 "field of module table entry %u past the end of the "
6126 "external relocation enrties", module_index);
6127 return(CHECK_BAD);
6129 if(iextrel + nextrel > dyst->extreloff){
6130 Mach_O_error(ofile, "truncated or malformed object (iextrel "
6131 "field of module table entry %u plus nextrel field "
6132 "extends past the end of the external relocation enrties",
6133 module_index);
6134 return(CHECK_BAD);
6137 return(CHECK_GOOD);
6138 #endif /* OTOOL */
6141 __private_extern__
6142 uint32_t
6143 size_ar_name(
6144 const struct ar_hdr *ar_hdr)
6146 int32_t i;
6148 i = sizeof(ar_hdr->ar_name) - 1;
6149 if(ar_hdr->ar_name[i] == ' '){
6151 if(ar_hdr->ar_name[i] != ' ')
6152 break;
6153 i--;
6154 }while(i > 0);
6156 return(i + 1);
6158 #endif /* !defined(RLD) */