Rename README -> README.txt
[striptease.git] / libstuff / ofile.c
blobd9fdd92902681a68827030786dbdc868ba3dbfda
1 /*
2 * Copyright © 2009 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Inc. ("Apple") nor the names of its
15 * contributors may be used to endorse or promote products derived from this
16 * software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * @APPLE_LICENSE_HEADER_END@
31 #define __darwin_i386_exception_state i386_exception_state
32 #define __darwin_i386_float_state i386_float_state
33 #define __darwin_i386_thread_state i386_thread_state
35 #ifndef RLD
36 #ifdef SHLIB
37 #include "shlib.h"
38 #endif
39 #include <libc.h>
40 #include <mach/mach.h>
41 #include "stuff/openstep_mach.h"
42 #include <stddef.h>
43 #include <stdarg.h>
44 #include <limits.h>
45 #include <errno.h>
46 #include <ctype.h>
47 #include <ar.h>
48 #include <sys/file.h>
49 #include <sys/types.h>
50 #include <sys/mman.h>
51 #include <mach-o/fat.h>
52 #include <mach-o/loader.h>
53 #import <mach/m68k/thread_status.h>
54 #import <mach/ppc/thread_status.h>
55 #undef MACHINE_THREAD_STATE /* need to undef these to avoid warnings */
56 #undef MACHINE_THREAD_STATE_COUNT
57 #undef THREAD_STATE_NONE
58 #undef VALID_THREAD_STATE_FLAVOR
59 #import <mach/m88k/thread_status.h>
60 #import <mach/i860/thread_status.h>
61 #import <mach/i386/thread_status.h>
62 #import <mach/sparc/thread_status.h>
63 #import <mach/arm/thread_status.h>
64 #include <mach-o/nlist.h>
65 #include <mach-o/reloc.h>
66 #include "stuff/bool.h"
67 #ifdef OFI
68 #include <mach-o/dyld.h>
69 #else
70 #include "stuff/lto.h"
71 #endif
72 #include "stuff/bytesex.h"
73 #include "stuff/arch.h"
74 #include "stuff/rnd.h"
75 #include "stuff/errors.h"
76 #include "stuff/allocate.h"
77 #include "stuff/ofile.h"
78 #include "stuff/print.h"
80 #ifdef OTOOL
81 #undef ALIGNMENT_CHECKS
82 #include "otool.h"
83 #include "ofile_print.h"
84 static enum bool otool_first_ofile_map = TRUE;
85 #else /* !define(OTOOL) */
87 #if (!defined(m68k) && !defined(__i386__) && !defined(__x86_64__) && !defined(__ppc__) && !defined(__arm__))
88 #define ALIGNMENT_CHECKS_ARCHIVE_64_BIT
89 static enum bool archive_64_bit_align_warning = FALSE;
90 #endif /* (!defined(m68k) && !defined(__i386__) && !defined(__x86_64__) && !defined(__ppc__) && !defined(__arm__)) */
92 #endif /* OTOOL */
94 /* <mach/loader.h> */
95 /* The maximum section alignment allowed to be specified, as a power of two */
96 #define MAXSECTALIGN 15 /* 2**15 or 0x8000 */
98 enum check_type {
99 CHECK_BAD,
100 CHECK_GOOD
103 #ifndef OTOOL
104 struct element {
105 uint32_t offset;
106 uint32_t size;
107 char *name;
108 struct element *next;
110 #endif /* !defined(OTOOL) */
112 static enum bool ofile_specific_arch(
113 struct ofile *ofile,
114 uint32_t narch);
115 static enum check_type check_fat(
116 struct ofile *ofile);
117 static enum check_type check_fat_object_in_archive(
118 struct ofile *ofile);
119 static enum check_type check_archive(
120 struct ofile *ofile,
121 enum bool archives_with_fat_objects);
122 static enum check_type check_extend_format_1(
123 struct ofile *ofile,
124 struct ar_hdr *ar_hdr,
125 uint32_t size_left,
126 uint32_t *member_name_size);
127 static enum check_type check_archive_toc(
128 struct ofile *ofile);
129 static enum check_type check_Mach_O(
130 struct ofile *ofile);
131 static void swap_back_Mach_O(
132 struct ofile *ofile);
133 #ifndef OTOOL
134 static enum check_type check_overlaping_element(
135 struct ofile *ofile,
136 struct element *head,
137 uint32_t offset,
138 uint32_t size,
139 char *name);
140 static void free_elements(
141 struct element *head);
142 #endif /* !defined(OTOOL) */
143 static enum check_type check_dylib_module(
144 struct ofile *ofile,
145 struct symtab_command *st,
146 struct dysymtab_command *dyst,
147 char *strings,
148 uint32_t module_index);
150 #ifndef OTOOL
151 #if defined(ALIGNMENT_CHECKS) || defined(ALIGNMENT_CHECKS_ARCHIVE_64_BIT)
152 static
153 void
154 temporary_archive_member_warning(
155 struct ofile *ofile,
156 const char *format, ...)
158 va_list ap;
160 va_start(ap, format);
161 if(ofile->file_type == OFILE_FAT){
162 print("%s: for architecture %s archive member: %s(%.*s) ",
163 progname, ofile->arch_flag.name, ofile->file_name,
164 (int)ofile->member_name_size, ofile->member_name);
166 else{
167 print("%s: archive member: %s(%.*s) ", progname, ofile->file_name,
168 (int)ofile->member_name_size, ofile->member_name);
170 vprint(format, ap);
171 print("\n");
172 va_end(ap);
174 #endif /* defined(ALIGNMENT_CHECKS) */
175 #endif /* !defined(OTOOL) */
177 #ifndef OFI
179 * ofile_process() processes the specified file name can calls the routine
180 * processor on the ofiles in it. arch_flags is an array of architectures
181 * containing narch_flags which are the only architectures to process if
182 * narch_flags is non-zero. If all_archs is TRUE then all architectures of
183 * the specified file are processed. The specified file name can be of the
184 * form "archive(member)" which is taken to mean that member in that archive
185 * (or that module of a dynamic library if dylib_flat is not FALSE).
186 * For each ofile that is to be processed the routine processor is called with
187 * the corresponding ofile struct, the arch_name pass to it is either NULL or
188 * an architecture name (when it should be printed or show by processor) and
189 * cookie is the same value as passed to ofile_process.
191 __private_extern__
192 void
193 ofile_process(
194 char *name,
195 struct arch_flag *arch_flags,
196 uint32_t narch_flags,
197 enum bool all_archs,
198 enum bool process_non_objects,
199 enum bool dylib_flat,
200 enum bool use_member_syntax,
201 void (*processor)(struct ofile *ofile, char *arch_name, void *cookie),
202 void *cookie)
204 char *member_name, *p, *arch_name;
205 uint32_t len, i;
206 struct ofile ofile;
207 enum bool flag, hostflag, arch_found, family;
208 struct arch_flag host_arch_flag;
209 const struct arch_flag *family_arch_flag;
212 * If use_member_syntax is TRUE look for a name of the form
213 * "archive(member)" which is to mean a member in that archive (the
214 * member name must be at least one character long to be recognized as
215 * this form).
217 member_name = NULL;
218 if(use_member_syntax == TRUE){
219 len = strlen(name);
220 if(len >= 4 && name[len-1] == ')'){
221 p = strrchr(name, '(');
222 if(p != NULL && p != name){
223 member_name = p+1;
224 *p = '\0';
225 name[len-1] = '\0';
230 #ifdef OTOOL
231 otool_first_ofile_map = TRUE;
232 #endif /* OTOOL */
233 if(ofile_map(name, NULL, NULL, &ofile, FALSE) == FALSE)
234 return;
235 #ifdef OTOOL
236 otool_first_ofile_map = FALSE;
237 #endif /* OTOOL */
239 if(ofile.file_type == OFILE_FAT){
241 * This is a fat file so see if a list of architecture is
242 * specified and process only those.
244 if(all_archs == FALSE && narch_flags != 0){
245 for(i = 0; i < narch_flags; i++){
246 if(ofile_first_arch(&ofile) == FALSE){
247 ofile_unmap(&ofile);
248 return;
250 arch_found = FALSE;
251 family = FALSE;
252 family_arch_flag =
253 get_arch_family_from_cputype(arch_flags[i].cputype);
254 if(family_arch_flag != NULL)
255 family = (enum bool)
256 ((family_arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) ==
257 (arch_flags[i].cpusubtype & ~CPU_SUBTYPE_MASK));
258 if(narch_flags != 1)
259 arch_name = ofile.arch_flag.name;
260 else
261 arch_name = NULL;
263 if(ofile.arch_flag.cputype ==
264 arch_flags[i].cputype &&
265 ((ofile.arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK) ==
266 (arch_flags[i].cpusubtype & ~CPU_SUBTYPE_MASK) ||
267 family == TRUE)){
268 arch_found = TRUE;
269 if(ofile.arch_type == OFILE_ARCHIVE){
270 if(member_name != NULL){
271 if(ofile_specific_member(member_name,
272 &ofile) == TRUE){
273 processor(&ofile, arch_name, cookie);
274 if(ofile.headers_swapped == TRUE)
275 swap_back_Mach_O(&ofile);
278 else{
279 /* loop through archive */
280 #ifdef OTOOL
281 printf("Archive : %s", ofile.file_name);
282 if(arch_name != NULL)
283 printf(" (architecture %s)",
284 arch_name);
285 printf("\n");
286 #endif /* OTOOL */
287 if(ofile_first_member(&ofile) == TRUE){
288 flag = FALSE;
290 if(process_non_objects == TRUE ||
291 ofile.member_type ==
292 OFILE_Mach_O){
293 processor(&ofile, arch_name,
294 cookie);
295 if(ofile.headers_swapped ==TRUE)
296 swap_back_Mach_O(&ofile);
297 flag = TRUE;
299 }while(ofile_next_member(&ofile) ==
300 TRUE);
301 if(flag == FALSE){
302 error("for architecture: %s "
303 "archive: %s contains no "
304 "members that are object "
305 "files", ofile.arch_flag.name,
306 ofile.file_name);
309 else{
310 error("for architecture: %s archive: "
311 "%s contains no members",
312 ofile.arch_flag.name,
313 ofile.file_name);
317 else if(process_non_objects == TRUE ||
318 ofile.arch_type == OFILE_Mach_O){
319 if(ofile.arch_type == OFILE_Mach_O &&
320 (ofile.mh_filetype == MH_DYLIB ||
321 ofile.mh_filetype == MH_DYLIB_STUB)){
322 if(dylib_flat == TRUE){
323 processor(&ofile, arch_name, cookie);
324 if(ofile.headers_swapped == TRUE)
325 swap_back_Mach_O(&ofile);
327 else{
328 if(member_name != NULL){
329 if(ofile_specific_module(
330 member_name, &ofile) == TRUE){
331 processor(&ofile, arch_name,
332 cookie);
333 if(ofile.headers_swapped ==TRUE)
334 swap_back_Mach_O(&ofile);
337 else{
338 /*loop through the dynamic library*/
339 if(ofile_first_module(&ofile)){
341 processor(&ofile, arch_name,
342 cookie);
343 }while(ofile_next_module(
344 &ofile));
346 else{
347 processor(&ofile, arch_name,
348 cookie);
352 if(ofile.headers_swapped == TRUE)
353 swap_back_Mach_O(&ofile);
355 else{
356 if(member_name != NULL)
357 error("for architecture: %s file: %s "
358 "is not an archive and thus does "
359 "not contain member: %s",
360 ofile.arch_flag.name,
361 ofile.file_name,
362 member_name);
363 else{
364 processor(&ofile, arch_name, cookie);
365 if(ofile.headers_swapped == TRUE)
366 swap_back_Mach_O(&ofile);
370 else if(ofile.arch_type == OFILE_UNKNOWN){
371 error("for architecture: %s file: %s is "
372 "not an object file",
373 ofile.arch_flag.name,ofile.file_name);
375 if(ofile.headers_swapped == TRUE)
376 swap_back_Mach_O(&ofile);
377 break;
379 else{
380 if(ofile.headers_swapped == TRUE)
381 swap_back_Mach_O(&ofile);
383 }while(ofile_next_arch(&ofile) == TRUE);
384 if(arch_found == FALSE)
385 error("file: %s does not contain architecture: %s",
386 ofile.file_name, arch_flags[i].name);
388 ofile_unmap(&ofile);
389 return;
393 * This is a fat file and no architectures has been specified
394 * so if it contains the host architecture process only that
395 * architecture but if not process all architectures
396 * specified.
398 if(all_archs == FALSE){
399 (void)get_arch_from_host(&host_arch_flag, NULL);
400 #if __LP64__
402 * If runing as a 64-bit binary and on an Intel x86 host
403 * default to 64-bit.
405 if(host_arch_flag.cputype == CPU_TYPE_I386)
406 host_arch_flag =
407 *get_arch_family_from_cputype(CPU_TYPE_X86_64);
408 #endif /* __LP64__ */
409 hostflag = FALSE;
411 family = FALSE;
412 family_arch_flag =
413 get_arch_family_from_cputype(host_arch_flag.cputype);
414 if(family_arch_flag != NULL)
415 family = (enum bool)
416 ((family_arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) ==
417 (host_arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK));
419 ofile_unmap(&ofile);
420 if(ofile_map(name, NULL, NULL, &ofile, FALSE) == FALSE)
421 return;
422 if(ofile_first_arch(&ofile) == FALSE){
423 ofile_unmap(&ofile);
424 return;
427 if(ofile.arch_flag.cputype ==
428 host_arch_flag.cputype &&
429 ((ofile.arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK) ==
430 (host_arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK) ||
431 family == TRUE)){
432 hostflag = TRUE;
433 if(ofile.arch_type == OFILE_ARCHIVE){
434 if(member_name != NULL){
435 if(ofile_specific_member(member_name,
436 &ofile) == TRUE){
437 processor(&ofile, NULL, cookie);
438 if(ofile.headers_swapped == TRUE)
439 swap_back_Mach_O(&ofile);
442 else{
443 /* loop through archive */
444 #ifdef OTOOL
445 printf("Archive : %s\n", ofile.file_name);
446 #endif /* OTOOL */
447 if(ofile_first_member(&ofile) == TRUE){
448 flag = FALSE;
450 if(process_non_objects == TRUE ||
451 ofile.member_type == OFILE_Mach_O){
452 processor(&ofile, NULL, cookie);
453 if(ofile.headers_swapped == TRUE)
454 swap_back_Mach_O(&ofile);
455 flag = TRUE;
457 }while(ofile_next_member(&ofile) ==
458 TRUE);
459 if(flag == FALSE){
460 error("archive: %s contains no "
461 "members that are object "
462 "files", ofile.file_name);
465 else{
466 error("archive: %s contains no "
467 "members", ofile.file_name);
471 else if(process_non_objects == TRUE ||
472 ofile.arch_type == OFILE_Mach_O){
473 if(ofile.arch_type == OFILE_Mach_O &&
474 (ofile.mh_filetype == MH_DYLIB ||
475 ofile.mh_filetype == MH_DYLIB_STUB)){
476 if(dylib_flat == TRUE){
477 processor(&ofile, NULL, cookie);
479 else{
480 if(member_name != NULL){
481 if(ofile_specific_module(member_name,
482 &ofile) == TRUE)
483 processor(&ofile, NULL, cookie);
485 else{
486 /* loop through the dynamic library */
487 if(ofile_first_module(&ofile) == TRUE){
489 processor(&ofile, NULL, cookie);
490 }while(ofile_next_module(&ofile));
492 else{
493 processor(&ofile, NULL, cookie);
497 if(ofile.headers_swapped == TRUE)
498 swap_back_Mach_O(&ofile);
500 else{
501 if(member_name != NULL)
502 error("for architecture: %s file: %s is "
503 "not an archive and thus does not "
504 "contain member: %s",
505 ofile.arch_flag.name, ofile.file_name,
506 member_name);
507 else{
508 processor(&ofile, NULL, cookie);
509 if(ofile.headers_swapped == TRUE)
510 swap_back_Mach_O(&ofile);
514 else if(ofile.arch_type == OFILE_UNKNOWN){
515 error("file: %s is not an object file",
516 ofile.file_name);
519 else{
520 if(ofile.headers_swapped == TRUE)
521 swap_back_Mach_O(&ofile);
523 }while(hostflag == FALSE && ofile_next_arch(&ofile) == TRUE);
524 if(hostflag == TRUE){
525 ofile_unmap(&ofile);
526 return;
531 * Either all architectures have been specified or none have
532 * been specified and it does not contain the host architecture
533 * so do all the architectures in the fat file
535 ofile_unmap(&ofile);
536 if(ofile_map(name, NULL, NULL, &ofile, FALSE) == FALSE)
537 return;
538 if(ofile_first_arch(&ofile) == FALSE){
539 ofile_unmap(&ofile);
540 return;
543 if(ofile.arch_type == OFILE_ARCHIVE){
544 if(member_name != NULL){
545 if(ofile_specific_member(member_name, &ofile) == TRUE)
546 processor(&ofile, ofile.arch_flag.name, cookie);
548 else{
549 /* loop through archive */
550 #ifdef OTOOL
551 printf("Archive : %s (architecture %s)\n",
552 ofile.file_name, ofile.arch_flag.name);
553 #endif /* OTOOL */
554 if(ofile_first_member(&ofile) == TRUE){
555 flag = FALSE;
557 if(process_non_objects == TRUE ||
558 ofile.member_type == OFILE_Mach_O){
559 processor(&ofile, ofile.arch_flag.name,
560 cookie);
561 flag = TRUE;
563 }while(ofile_next_member(&ofile) == TRUE);
564 if(flag == FALSE){
565 error("for architecture: %s archive: %s "
566 "contains no members that are object "
567 "files", ofile.arch_flag.name,
568 ofile.file_name);
571 else{
572 error("for architecture: %s archive: %s "
573 "contains no members",
574 ofile.arch_flag.name, ofile.file_name);
578 else if(process_non_objects == TRUE ||
579 ofile.arch_type == OFILE_Mach_O){
580 if(ofile.arch_type == OFILE_Mach_O &&
581 (ofile.mh_filetype == MH_DYLIB ||
582 ofile.mh_filetype == MH_DYLIB_STUB)){
583 if(dylib_flat == TRUE){
584 processor(&ofile, ofile.arch_flag.name, cookie);
586 else{
587 if(member_name != NULL){
588 if(ofile_specific_module(member_name, &ofile)
589 == TRUE)
590 processor(&ofile, ofile.arch_flag.name,
591 cookie);
593 else{
594 /* loop through the dynamic library */
595 if(ofile_first_module(&ofile) == TRUE){
597 processor(&ofile, ofile.arch_flag.name,
598 cookie);
599 }while(ofile_next_module(&ofile) == TRUE);
601 else{
602 processor(&ofile, ofile.arch_flag.name,
603 cookie);
608 else{
609 if(member_name != NULL)
610 error("for architecture: %s file: %s is not an "
611 "archive and thus does not contain member: "
612 "%s", ofile.arch_flag.name, ofile.file_name,
613 member_name);
614 else
615 processor(&ofile, ofile.arch_flag.name, cookie);
618 else if(ofile.arch_type == OFILE_UNKNOWN){
619 error("for architecture: %s file: %s is not an "
620 "object file", ofile.arch_flag.name,
621 ofile.file_name);
623 }while(ofile_next_arch(&ofile) == TRUE);
625 else if(ofile.file_type == OFILE_ARCHIVE){
626 if(narch_flags != 0){
627 arch_found = FALSE;
628 for(i = 0; i < narch_flags; i++){
629 family = FALSE;
630 if(narch_flags == 1){
631 family_arch_flag =
632 get_arch_family_from_cputype(arch_flags[0].cputype);
633 if(family_arch_flag != NULL)
634 family = (enum bool)
635 ((family_arch_flag->cpusubtype &
636 ~CPU_SUBTYPE_MASK) ==
637 (arch_flags[0].cpusubtype &
638 ~CPU_SUBTYPE_MASK));
640 if(ofile.archive_cputype == arch_flags[i].cputype &&
641 ((ofile.archive_cpusubtype & ~CPU_SUBTYPE_MASK) ==
642 (arch_flags[i].cpusubtype & ~CPU_SUBTYPE_MASK) ||
643 family == TRUE)){
644 arch_found = TRUE;
646 else{
647 error("file: %s does not contain architecture: %s",
648 ofile.file_name, arch_flags[i].name);
651 if(arch_found == FALSE){
652 ofile_unmap(&ofile);
653 return;
656 if(member_name != NULL){
657 if(ofile_specific_member(member_name, &ofile) == TRUE)
658 processor(&ofile, NULL, cookie);
660 else{
661 /* loop through archive */
662 #ifdef OTOOL
663 printf("Archive : %s\n", ofile.file_name);
664 #endif /* OTOOL */
665 if(ofile_first_member(&ofile) == TRUE){
666 flag = FALSE;
668 if(process_non_objects == TRUE ||
669 ofile.member_type == OFILE_Mach_O){
670 processor(&ofile, NULL, cookie);
671 flag = TRUE;
673 }while(ofile_next_member(&ofile) == TRUE);
674 if(flag == FALSE){
675 error("archive: %s contains no members that are "
676 "object files", ofile.file_name);
679 else{
680 error("archive: %s contains no members",
681 ofile.file_name);
685 else if(ofile.file_type == OFILE_Mach_O){
686 if(narch_flags != 0){
687 arch_found = FALSE;
688 for(i = 0; i < narch_flags; i++){
689 family = FALSE;
690 if(narch_flags == 1){
691 family_arch_flag =
692 get_arch_family_from_cputype(arch_flags[0].cputype);
693 if(family_arch_flag != NULL)
694 family = (enum bool)
695 ((family_arch_flag->cpusubtype &
696 ~CPU_SUBTYPE_MASK) ==
697 (arch_flags[0].cpusubtype &
698 ~CPU_SUBTYPE_MASK));
700 #ifdef OTOOL
701 if(ofile.mh != NULL){
702 if(ofile.mh->magic == MH_MAGIC &&
703 ofile.mh->cputype == arch_flags[i].cputype &&
704 ((ofile.mh->cpusubtype & ~CPU_SUBTYPE_MASK) ==
705 (arch_flags[i].cpusubtype & ~CPU_SUBTYPE_MASK) ||
706 family == TRUE)){
707 arch_found = TRUE;
709 if(ofile.mh->magic == SWAP_INT(MH_MAGIC) &&
710 (cpu_type_t)SWAP_INT(ofile.mh->cputype) ==
711 arch_flags[i].cputype &&
712 ((cpu_subtype_t)SWAP_INT(ofile.mh->cpusubtype &
713 ~CPU_SUBTYPE_MASK) ==
714 (arch_flags[i].cpusubtype &
715 ~CPU_SUBTYPE_MASK) ||
716 family == TRUE)){
717 arch_found = TRUE;
720 else if(ofile.mh64 != NULL){
721 if(ofile.mh64->magic == MH_MAGIC_64 &&
722 ofile.mh64->cputype == arch_flags[i].cputype &&
723 ((ofile.mh64->cpusubtype & ~CPU_SUBTYPE_MASK) ==
724 (arch_flags[i].cpusubtype & ~CPU_SUBTYPE_MASK) ||
725 family == TRUE)){
726 arch_found = TRUE;
728 if(ofile.mh64->magic == SWAP_INT(MH_MAGIC_64) &&
729 (cpu_type_t)SWAP_INT(ofile.mh64->cputype) ==
730 arch_flags[i].cputype &&
731 ((cpu_subtype_t)SWAP_INT((ofile.mh64->cpusubtype &
732 ~CPU_SUBTYPE_MASK)) ==
733 (arch_flags[i].cpusubtype & ~CPU_SUBTYPE_MASK) ||
734 family == TRUE)){
735 arch_found = TRUE;
738 else
739 #endif /* OTOOL */
740 if(ofile.mh_cputype == arch_flags[i].cputype &&
741 ((ofile.mh_cpusubtype & ~CPU_SUBTYPE_MASK) ==
742 (arch_flags[i].cpusubtype & ~CPU_SUBTYPE_MASK) ||
743 family == TRUE)){
744 arch_found = TRUE;
746 else{
747 error("file: %s does not contain architecture: %s",
748 ofile.file_name, arch_flags[i].name);
751 if(arch_found == FALSE){
752 ofile_unmap(&ofile);
753 return;
756 if(ofile.mh_filetype == MH_DYLIB ||
757 ofile.mh_filetype == MH_DYLIB_STUB){
758 if(dylib_flat == TRUE){
759 processor(&ofile, NULL, cookie);
761 else{
762 if(member_name != NULL){
763 if(ofile_specific_module(member_name, &ofile) == TRUE)
764 processor(&ofile, NULL, cookie);
766 else{
767 /* loop through the dynamic library */
768 if(ofile_first_module(&ofile) == TRUE){
770 processor(&ofile, NULL, cookie);
771 }while(ofile_next_module(&ofile) == TRUE);
773 else{
774 processor(&ofile, NULL, cookie);
779 else{
780 if(member_name != NULL)
781 error("file: %s is not an archive and thus does not contain"
782 " member: %s", ofile.file_name, member_name);
783 else
784 processor(&ofile, NULL, cookie);
787 else{
788 if(process_non_objects == TRUE)
789 processor(&ofile, NULL, cookie);
790 else if(member_name != NULL)
791 error("file: %s(%s) is not an object file", name,
792 member_name);
793 else
794 error("file: %s is not an object file", name);
796 ofile_unmap(&ofile);
798 #endif /* !defined(OFI) */
801 * ofile_map maps in the object file specified by file_name, arch_flag and
802 * object_name and fills in the ofile struct pointed to by ofile for it.
803 * When arch_flag and object_name are both NULL, the file is just set up into
804 * ofile (if the file can be opened and mapped in, if not this call fails
805 * are error routnes are called). If arch_flag is not NULL and object_file is
806 * NULL, then the file must be a Mach-O file or a fat file with the architecture
807 * specified in the arch_flag, if not this call fails and error routines are
808 * called. When arch_flag and object_name are both not NULL, then the file must
809 * be an archive or a fat file containing archives for the specified architec-
810 * ture and contain an archive member object file with the name object_name,
811 * otherwise this call fails and error routines are called. If arch_flag is
812 * NULL and object_file is not NULL, then the file name must be an archive (not
813 * a fat file containing archives) and contain an archive member object file
814 * with the name object_name, otherwise this call fails and calls error
815 * routines. If this call suceeds then it returns non-zero and the ofile
816 * structure pointed to by ofile is filled in. If this call fails it returns 0
817 * and calls error routines to print error messages and clears the
818 * ofile structure pointed to by ofile.
820 __private_extern__
821 #ifdef OFI
822 NSObjectFileImageReturnCode
823 #else
824 enum bool
825 #endif
826 ofile_map(
827 const char *file_name,
828 const struct arch_flag *arch_flag, /* can be NULL */
829 const char *object_name, /* can be NULL */
830 struct ofile *ofile,
831 enum bool archives_with_fat_objects)
833 int fd;
834 struct stat stat_buf;
835 uint32_t size, magic;
836 char *addr;
838 magic = 0; /* to shut up the compiler warning message */
839 memset(ofile, '\0', sizeof(struct ofile));
841 /* Open the file and map it in */
842 if((fd = open(file_name, O_RDONLY)) == -1){
843 #ifdef OFI
844 return(NSObjectFileImageAccess);
845 #else
846 system_error("can't open file: %s", file_name);
847 return(FALSE);
848 #endif
850 if(fstat(fd, &stat_buf) == -1){
851 close(fd);
852 #ifdef OFI
853 return(NSObjectFileImageAccess);
854 #else
855 system_error("can't stat file: %s", file_name);
856 return(FALSE);
857 #endif
859 size = stat_buf.st_size;
861 addr = NULL;
862 if(size != 0){
863 addr = mmap(0, size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_PRIVATE, fd,
865 if((intptr_t)addr == -1){
866 system_error("can't map file: %s", file_name);
867 close(fd);
868 return(FALSE);
871 close(fd);
872 #ifdef OTOOL
873 if(otool_first_ofile_map && Wflag)
874 printf("Modification time = %ld\n", (long int)stat_buf.st_mtime);
875 #endif /* OTOOL */
877 return(ofile_map_from_memory(addr, size, file_name, stat_buf.st_mtime,
878 arch_flag, object_name, ofile, archives_with_fat_objects));
882 * ofile_map_from_memory() is the guts of ofile_map() but with an interface
883 * to pass the address and size of the file already mapped in.
885 __private_extern__
886 #ifdef OFI
887 NSObjectFileImageReturnCode
888 #else
889 enum bool
890 #endif
891 ofile_map_from_memory(
892 char *addr,
893 uint32_t size,
894 const char *file_name,
895 uint64_t mtime,
896 const struct arch_flag *arch_flag, /* can be NULL */
897 const char *object_name, /* can be NULL */
898 struct ofile *ofile,
899 enum bool archives_with_fat_objects)
901 uint32_t i;
902 uint32_t magic;
903 enum byte_sex host_byte_sex;
904 struct arch_flag host_arch_flag;
905 enum bool family;
906 const struct arch_flag *family_arch_flag;
907 uint64_t big_size;
908 #ifdef OTOOL
909 uint32_t small_nfat_arch;
910 #endif /* OTOOL */
912 /* fill in the start of the ofile structure */
913 ofile->file_name = savestr(file_name);
914 if(ofile->file_name == NULL)
915 return(FALSE);
916 ofile->file_addr = addr;
917 ofile->file_size = size;
918 ofile->file_mtime = mtime;
920 /* Try to figure out what kind of file this is */
922 if(size >= sizeof(uint32_t)){
923 magic = *((uint32_t *)addr);
925 host_byte_sex = get_host_byte_sex();
927 /* see if this file is a fat file (always in big endian byte sex) */
928 #ifdef __BIG_ENDIAN__
929 if(size >= sizeof(struct fat_header) && magic == FAT_MAGIC)
930 #endif /* __BIG_ENDIAN__ */
931 #ifdef __LITTLE_ENDIAN__
932 if(size >= sizeof(struct fat_header) && SWAP_INT(magic) == FAT_MAGIC)
933 #endif /* __LITTLE_ENDIAN__ */
935 ofile->file_type = OFILE_FAT;
936 ofile->fat_header = (struct fat_header *)addr;
937 #ifdef __LITTLE_ENDIAN__
938 swap_fat_header(ofile->fat_header, host_byte_sex);
939 #endif /* __LITTLE_ENDIAN__ */
940 #ifdef OTOOL
941 if(otool_first_ofile_map && fflag)
942 printf("Fat headers\n");
943 #endif /* OTOOL */
944 big_size = ofile->fat_header->nfat_arch;
945 big_size *= sizeof(struct fat_arch);
946 big_size += sizeof(struct fat_header);
947 if(big_size > size){
948 #ifdef OTOOL
949 error("fat file: %s truncated or malformed (fat_arch structs "
950 "would extend past the end of the file)", file_name);
951 ofile->fat_archs = allocate(size - sizeof(struct fat_header));
952 memset(ofile->fat_archs, '\0',
953 size - sizeof(struct fat_header));
954 memcpy(ofile->fat_archs,
955 addr + sizeof(struct fat_header),
956 size - sizeof(struct fat_header));
957 small_nfat_arch = (size - sizeof(struct fat_header)) /
958 sizeof(struct fat_arch);
959 #ifdef __LITTLE_ENDIAN__
960 swap_fat_arch(ofile->fat_archs, small_nfat_arch,
961 host_byte_sex);
962 #endif /* __LITTLE_ENDIAN__ */
963 if(otool_first_ofile_map && fflag)
964 print_fat_headers(ofile->fat_header, ofile->fat_archs,
965 size, vflag);
966 free(ofile->fat_archs);
967 ofile_unmap(ofile);
968 return(FALSE);
969 #else /* !defined(OTOOL) */
970 goto unknown;
971 #endif /* OTOOL */
973 ofile->fat_archs = (struct fat_arch *)(addr +
974 sizeof(struct fat_header));
975 #ifdef __LITTLE_ENDIAN__
976 swap_fat_arch(ofile->fat_archs, ofile->fat_header->nfat_arch,
977 host_byte_sex);
978 #endif /* __LITTLE_ENDIAN__ */
979 #ifdef OTOOL
980 if(otool_first_ofile_map && fflag)
981 print_fat_headers(ofile->fat_header, ofile->fat_archs,
982 size, vflag);
983 #endif /* OTOOL */
984 if(check_fat(ofile) == CHECK_BAD){
985 ofile_unmap(ofile);
986 #ifdef OFI
987 return(NSObjectFileImageFormat);
988 #else
989 return(FALSE);
990 #endif
993 * Now that the fat file is mapped fill in the ofile to the level
994 * the caller wants based on the arch_flag and object_name passed.
995 * If the caller did not specify an arch_flag or an object_name
996 * then everything the caller wants is done.
998 if(arch_flag == NULL && object_name == NULL)
999 goto success;
1000 if(arch_flag == NULL){
1001 if(get_arch_from_host(&host_arch_flag, NULL) == 0){
1002 error("can't determine the host architecture (specify an "
1003 "arch_flag or fix get_arch_from_host() )");
1004 goto cleanup;
1006 ofile->arch_flag.name = savestr(host_arch_flag.name);
1007 if(ofile->arch_flag.name == NULL)
1008 goto cleanup;
1009 ofile->arch_flag.cputype = host_arch_flag.cputype;
1010 ofile->arch_flag.cpusubtype = host_arch_flag.cpusubtype;
1012 else{
1013 ofile->arch_flag.name = savestr(arch_flag->name);
1014 if(ofile->arch_flag.name == NULL)
1015 goto cleanup;
1016 ofile->arch_flag.cputype = arch_flag->cputype;
1017 ofile->arch_flag.cpusubtype = arch_flag->cpusubtype;
1020 ofile->narch = UINT_MAX;
1021 for(i = 0; i < ofile->fat_header->nfat_arch; i++){
1022 if(ofile->fat_archs[i].cputype ==
1023 ofile->arch_flag.cputype &&
1024 (ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK) ==
1025 (ofile->arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK)){
1026 ofile->narch = i;
1027 break;
1030 if(ofile->narch == UINT_MAX){
1031 family = FALSE;
1032 family_arch_flag =
1033 get_arch_family_from_cputype(ofile->arch_flag.cputype);
1034 if(family_arch_flag != NULL)
1035 family = (enum bool)
1036 ((family_arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) ==
1037 (ofile->arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK));
1038 ofile->narch = UINT_MAX;
1039 for(i = 0; i < ofile->fat_header->nfat_arch; i++){
1040 if(ofile->fat_archs[i].cputype ==
1041 ofile->arch_flag.cputype &&
1042 (family == TRUE ||
1043 (ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK) ==
1044 (ofile->arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK))){
1045 ofile->arch_flag.cpusubtype =
1046 ofile->fat_archs[i].cpusubtype;
1047 ofile->narch = i;
1048 break;
1052 if(ofile->narch == UINT_MAX){
1053 #ifdef OFI
1054 ofile_unmap(ofile);
1055 return(NSObjectFileImageArch);
1056 #else
1057 error("fat file: %s does not contain architecture %s",
1058 ofile->file_name, arch_flag->name);
1059 ofile_unmap(ofile);
1060 return(FALSE);
1061 #endif
1063 /* Now determine the file type for this specific architecture */
1064 size = ofile->fat_archs[i].size;
1065 addr = addr + ofile->fat_archs[i].offset;
1066 if(size >= sizeof(struct mach_header))
1067 memcpy(&magic, addr, sizeof(uint32_t));
1068 /* see if this file is a 32-bit Mach-O file */
1069 if(size >= sizeof(struct mach_header) &&
1070 (magic == MH_MAGIC ||
1071 magic == SWAP_INT(MH_MAGIC))){
1072 #ifdef ALIGNMENT_CHECKS
1073 if(ofile->fat_archs[i].offset % 4 != 0){
1074 error("fat file: %s architecture %s malformed for a 32-bit "
1075 "object file (offset is not a multiple of 4)",
1076 ofile->file_name, arch_flag->name);
1077 ofile_unmap(ofile);
1078 #ifdef OFI
1079 return(NSObjectFileImageFormat);
1080 #else
1081 return(FALSE);
1082 #endif
1084 #endif /* ALIGNMENT_CHECKS */
1085 ofile->arch_type = OFILE_Mach_O;
1086 ofile->object_addr = addr;
1087 ofile->object_size = size;
1088 if(magic == MH_MAGIC)
1089 ofile->object_byte_sex = host_byte_sex;
1090 else
1091 ofile->object_byte_sex =
1092 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1093 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1094 ofile->mh = (struct mach_header *)addr;
1095 ofile->load_commands = (struct load_command *)(addr +
1096 sizeof(struct mach_header));
1097 if(check_Mach_O(ofile) == CHECK_BAD){
1098 ofile_unmap(ofile);
1099 #ifdef OFI
1100 return(NSObjectFileImageFormat);
1101 #else
1102 return(FALSE);
1103 #endif
1105 if(object_name != NULL){
1106 error("fat file: %s architecture %s is not an archive "
1107 "(object_name to ofile_map() can't be specified to "
1108 "be other than NULL)", ofile->file_name,
1109 arch_flag->name);
1110 goto cleanup;
1113 /* see if this file is a 64-bit Mach-O file */
1114 else if(size >= sizeof(struct mach_header_64) &&
1115 (magic == MH_MAGIC_64 ||
1116 magic == SWAP_INT(MH_MAGIC_64))){
1117 #ifdef ALIGNMENT_CHECKS
1118 if(ofile->fat_archs[i].offset % 8 != 0){
1119 error("fat file: %s architecture %s malformed for a 64-bit "
1120 "object file (offset is not a multiple of 8)",
1121 ofile->file_name, arch_flag->name);
1122 ofile_unmap(ofile);
1123 #ifdef OFI
1124 return(NSObjectFileImageFormat);
1125 #else
1126 return(FALSE);
1127 #endif
1129 #endif /* ALIGNMENT_CHECKS */
1130 ofile->arch_type = OFILE_Mach_O;
1131 ofile->object_addr = addr;
1132 ofile->object_size = size;
1133 if(magic == MH_MAGIC_64)
1134 ofile->object_byte_sex = host_byte_sex;
1135 else
1136 ofile->object_byte_sex =
1137 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1138 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1139 ofile->mh64 = (struct mach_header_64 *)addr;
1140 ofile->load_commands = (struct load_command *)(addr +
1141 sizeof(struct mach_header_64));
1142 if(check_Mach_O(ofile) == CHECK_BAD){
1143 ofile_unmap(ofile);
1144 #ifdef OFI
1145 return(NSObjectFileImageFormat);
1146 #else
1147 return(FALSE);
1148 #endif
1150 if(object_name != NULL){
1151 error("fat file: %s architecture %s is not an archive "
1152 "(object_name to ofile_map() can't be specified to "
1153 "be other than NULL)", ofile->file_name,
1154 arch_flag->name);
1155 goto cleanup;
1158 /* see if this file is an archive file */
1159 else if(size >= SARMAG && strncmp(addr, ARMAG, SARMAG) == 0){
1160 ofile->arch_type = OFILE_ARCHIVE;
1161 if(check_archive(ofile, FALSE) == CHECK_BAD){
1162 ofile_unmap(ofile);
1163 #ifdef OFI
1164 return(NSObjectFileImageInappropriateFile);
1165 #else
1166 return(FALSE);
1167 #endif
1169 #ifdef ALIGNMENT_CHECKS
1170 if(ofile->archive_cputype != 0 &&
1171 ofile->fat_archs[i].offset % sizeof(uint32_t) != 0){
1172 error("fat file: %s architecture %s malformed archive that "
1173 "contains object files (offset to archive is not a "
1174 "multiple of sizeof(uint32_t))",
1175 ofile->file_name, arch_flag->name);
1176 ofile_unmap(ofile);
1177 #ifdef OFI
1178 return(NSObjectFileImageInappropriateFile);
1179 #else
1180 return(FALSE);
1181 #endif
1183 #endif /* ALIGNMENT_CHECKS */
1184 if(object_name != NULL){
1185 if(ofile_specific_member(object_name, ofile) == FALSE)
1186 goto cleanup;
1189 /* this file type is now known to be unknown to this program */
1190 else{
1191 ofile->file_type = OFILE_UNKNOWN;
1192 if(object_name != NULL){
1193 error("fat file: %s architecture %s is not an archive "
1194 "(object_name to ofile_map() can't be specified to "
1195 "be other than NULL)", ofile->file_name,
1196 arch_flag->name);
1197 goto cleanup;
1201 /* see if this file is a 32-bit Mach-O file */
1202 else if(size >= sizeof(struct mach_header) &&
1203 (magic == MH_MAGIC ||
1204 magic == SWAP_INT(MH_MAGIC))){
1205 ofile->file_type = OFILE_Mach_O;
1206 ofile->object_addr = addr;
1207 ofile->object_size = size;
1208 if(magic == MH_MAGIC)
1209 ofile->object_byte_sex = host_byte_sex;
1210 else
1211 ofile->object_byte_sex = host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1212 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1213 ofile->mh = (struct mach_header *)addr;
1214 ofile->load_commands = (struct load_command *)(addr +
1215 sizeof(struct mach_header));
1216 if(check_Mach_O(ofile) == CHECK_BAD){
1217 ofile_unmap(ofile);
1218 #ifdef OFI
1219 return(NSObjectFileImageFormat);
1220 #else
1221 return(FALSE);
1222 #endif
1224 if(object_name != NULL){
1225 error("file: %s is not an archive (object_name to ofile_map() "
1226 "can't be specified to be other than NULL)",
1227 ofile->file_name);
1228 goto cleanup;
1230 if(arch_flag != NULL){
1231 if(arch_flag->cputype != ofile->mh_cputype &&
1232 (arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) !=
1233 (ofile->mh_cpusubtype & ~CPU_SUBTYPE_MASK)){
1234 #ifdef OFI
1235 ofile_unmap(ofile);
1236 return(NSObjectFileImageArch);
1237 #else
1238 error("object file: %s does not match specified arch_flag: "
1239 "%s passed to ofile_map()", ofile->file_name,
1240 arch_flag->name);
1241 ofile_unmap(ofile);
1242 return(FALSE);
1243 #endif
1244 goto cleanup;
1248 /* see if this file is a 64-bit Mach-O file */
1249 else if(size >= sizeof(struct mach_header_64) &&
1250 (magic == MH_MAGIC_64 ||
1251 magic == SWAP_INT(MH_MAGIC_64))){
1252 ofile->file_type = OFILE_Mach_O;
1253 ofile->object_addr = addr;
1254 ofile->object_size = size;
1255 if(magic == MH_MAGIC_64)
1256 ofile->object_byte_sex = host_byte_sex;
1257 else
1258 ofile->object_byte_sex = host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1259 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1260 ofile->mh64 = (struct mach_header_64 *)addr;
1261 ofile->load_commands = (struct load_command *)(addr +
1262 sizeof(struct mach_header_64));
1263 if(check_Mach_O(ofile) == CHECK_BAD){
1264 ofile_unmap(ofile);
1265 #ifdef OFI
1266 return(NSObjectFileImageFormat);
1267 #else
1268 return(FALSE);
1269 #endif
1271 if(object_name != NULL){
1272 error("file: %s is not an archive (object_name to ofile_map() "
1273 "can't be specified to be other than NULL)",
1274 ofile->file_name);
1275 goto cleanup;
1277 if(arch_flag != NULL){
1278 if(arch_flag->cputype != ofile->mh_cputype &&
1279 (arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) !=
1280 (ofile->mh_cpusubtype & ~CPU_SUBTYPE_MASK)){
1281 #ifdef OFI
1282 ofile_unmap(ofile);
1283 return(NSObjectFileImageArch);
1284 #else
1285 error("object file: %s does not match specified arch_flag: "
1286 "%s passed to ofile_map()", ofile->file_name,
1287 arch_flag->name);
1288 ofile_unmap(ofile);
1289 return(FALSE);
1290 #endif
1291 goto cleanup;
1295 /* see if this file is an archive file */
1296 else if(size >= SARMAG && strncmp(addr, ARMAG, SARMAG) == 0){
1297 ofile->file_type = OFILE_ARCHIVE;
1298 if(check_archive(ofile, archives_with_fat_objects) == CHECK_BAD)
1299 goto cleanup;
1300 if(object_name != NULL){
1301 if(ofile_specific_member(object_name, ofile) == FALSE)
1302 goto cleanup;
1303 if(arch_flag != NULL){
1304 if(arch_flag->cputype != ofile->mh_cputype &&
1305 (arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) !=
1306 (ofile->mh_cpusubtype & ~CPU_SUBTYPE_MASK)){
1307 error("object file: %s(%.*s) does not match specified "
1308 "arch_flag: %s passed to ofile_map()",
1309 ofile->file_name, (int)ofile->member_name_size,
1310 ofile->member_name, arch_flag->name);
1311 goto cleanup;
1315 else{
1316 if(arch_flag != NULL){
1317 if(arch_flag->cputype != ofile->archive_cputype &&
1318 (arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) !=
1319 (ofile->archive_cpusubtype & ~CPU_SUBTYPE_MASK)){
1320 error("archive file: %s objects do not match specified "
1321 "arch_flag: %s passed to ofile_map()",
1322 ofile->file_name, arch_flag->name);
1323 goto cleanup;
1328 /* this file type is now known to be unknown to this program */
1329 else{
1330 #ifndef OTOOL
1331 unknown:
1332 #endif
1333 #ifndef OFI
1334 #ifdef LTO_SUPPORT
1335 if(is_llvm_bitcode(ofile, ofile->file_addr, ofile->file_size) ==
1336 TRUE){
1337 ofile->file_type = OFILE_LLVM_BITCODE;
1338 if(arch_flag != NULL){
1339 if(arch_flag->cputype != ofile->lto_cputype &&
1340 (arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) !=
1341 (ofile->lto_cpusubtype & ~CPU_SUBTYPE_MASK)){
1342 error("llvm bitcode file: %s does not match specified "
1343 "arch_flag: %s passed to ofile_map()",
1344 ofile->file_name, arch_flag->name);
1345 goto cleanup;
1348 if(object_name != NULL){
1349 error("file: %s is not an archive (object_name to "
1350 "ofile_map() can't be specified to be other than "
1351 "NULL)", ofile->file_name);
1352 goto cleanup;
1354 goto success;
1356 else
1357 #endif /* LTO_SUPPORT */
1358 #endif /* OFI */
1359 ofile->file_type = OFILE_UNKNOWN;
1360 if(arch_flag != NULL){
1361 #ifdef OFI
1362 ofile_unmap(ofile);
1363 return(NSObjectFileImageInappropriateFile);
1364 #else
1365 error("file: %s is unknown type (arch_flag to ofile_map() "
1366 "can't be specified to be other than NULL)",
1367 ofile->file_name);
1368 ofile_unmap(ofile);
1369 return(FALSE);
1370 #endif
1372 if(object_name != NULL){
1373 error("file: %s is not an archive (object_name to ofile_map() "
1374 "can't be specified to be other than NULL)",
1375 ofile->file_name);
1376 goto cleanup;
1379 success:
1380 return(TRUE);
1382 cleanup:
1383 ofile_unmap(ofile);
1384 return(FALSE);
1388 * ofile_unmap() deallocates the memory associated with the specified ofile
1389 * struct.
1391 __private_extern__
1392 void
1393 ofile_unmap(
1394 struct ofile *ofile)
1396 kern_return_t r;
1398 if(ofile->file_addr != NULL){
1399 if((r = vm_deallocate(mach_task_self(),
1400 (vm_address_t)ofile->file_addr,
1401 (vm_size_t)ofile->file_size)) != KERN_SUCCESS){
1402 my_mach_error(r, "Can't vm_deallocate mapped memory for file: "
1403 "%s", ofile->file_name);
1406 if(ofile->file_name != NULL)
1407 free(ofile->file_name);
1408 if(ofile->arch_flag.name != NULL)
1409 free(ofile->arch_flag.name);
1410 memset(ofile, '\0', sizeof(struct ofile));
1414 * ofile_first_arch() sets up the ofile struct for a fat file to the first arch
1415 * in it.
1417 __private_extern__
1418 enum bool
1419 ofile_first_arch(
1420 struct ofile *ofile)
1422 if(ofile->file_type == OFILE_FAT ||
1423 (ofile->file_type == OFILE_ARCHIVE &&
1424 ofile->member_type == OFILE_FAT) )
1425 return(ofile_specific_arch(ofile, 0));
1426 else{
1427 error("ofile_first_arch() called and file type of: %s is not a fat "
1428 "file\n", ofile->file_name);
1429 return(FALSE);
1434 * ofile_next_arch() sets up the ofile struct for a fat file to the next arch
1435 * in it.
1437 __private_extern__
1438 enum bool
1439 ofile_next_arch(
1440 struct ofile *ofile)
1442 if(ofile->file_type == OFILE_FAT ||
1443 (ofile->file_type == OFILE_ARCHIVE &&
1444 ofile->member_type == OFILE_FAT) ){
1445 if(ofile->narch + 1 < ofile->fat_header->nfat_arch)
1446 return(ofile_specific_arch(ofile, ofile->narch + 1));
1447 else
1448 return(FALSE);
1450 else{
1451 error("ofile_next_arch() called and file type of: %s is not a fat "
1452 "file\n", ofile->file_name);
1453 return(FALSE);
1458 * ofile_specific_arch() sets up the ofile struct for the fat file for the
1459 * specified narch.
1461 static
1462 enum bool
1463 ofile_specific_arch(
1464 struct ofile *ofile,
1465 uint32_t narch)
1467 char *addr;
1468 uint32_t size;
1469 uint32_t magic;
1470 enum byte_sex host_byte_sex;
1472 ofile->narch = narch;
1473 ofile->arch_type = OFILE_UNKNOWN;
1474 if(ofile->arch_flag.name != NULL)
1475 free(ofile->arch_flag.name);
1476 ofile->arch_flag.name = NULL;
1477 ofile->arch_flag.cputype = 0;
1478 ofile->arch_flag.cpusubtype = 0;
1479 ofile->archive_cputype = 0;
1480 ofile->archive_cpusubtype = 0;
1481 ofile->object_addr = NULL;
1482 ofile->object_size = 0;
1483 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
1484 ofile->mh = NULL;
1485 ofile->mh64 = NULL;
1486 ofile->load_commands = NULL;
1488 ofile->arch_flag.cputype = ofile->fat_archs[ofile->narch].cputype;
1489 ofile->arch_flag.cpusubtype = ofile->fat_archs[ofile->narch].cpusubtype;
1490 set_arch_flag_name(&(ofile->arch_flag));
1493 /* Now determine the file type for this specific architecture */
1494 if(ofile->file_type == OFILE_FAT){
1495 ofile->member_offset = 0;
1496 ofile->member_addr = NULL;
1497 ofile->member_size = 0;
1498 ofile->member_ar_hdr = NULL;
1499 ofile->member_type = OFILE_UNKNOWN;
1501 size = ofile->fat_archs[ofile->narch].size;
1502 addr = ofile->file_addr + ofile->fat_archs[ofile->narch].offset;
1504 else{
1505 if(ofile->file_type != OFILE_ARCHIVE ||
1506 ofile->member_type != OFILE_FAT){
1507 error("internal error. ofile_specific_arch() called but file "
1508 "is not a fat file or an archive with a fat member ");
1510 size = ofile->fat_archs[ofile->narch].size;
1511 addr = ofile->file_addr +
1512 ofile->member_offset +
1513 ofile->fat_archs[ofile->narch].offset;
1516 #ifdef OTOOL
1517 if(addr - ofile->file_addr > (ptrdiff_t)ofile->file_size){
1518 error("fat file: %s offset to architecture %s extends past end "
1519 "of file", ofile->file_name, ofile->arch_flag.name);
1520 return(FALSE);
1522 if(addr + size > ofile->file_addr + ofile->file_size)
1523 size = (ofile->file_addr + ofile->file_size) - addr;
1524 #endif /* OTOOL */
1526 if(size >= sizeof(struct mach_header))
1527 memcpy(&magic, addr, sizeof(uint32_t));
1528 /* see if this file is a 32-bit Mach-O file */
1529 if(size >= sizeof(struct mach_header) &&
1530 (magic == MH_MAGIC || magic == SWAP_INT(MH_MAGIC))){
1531 #ifdef ALIGNMENT_CHECKS
1532 if(ofile->fat_archs[ofile->narch].offset % 4 != 0){
1533 if(ofile->file_type == OFILE_ARCHIVE){
1534 error("fat file: %s(%.*s) architecture %s malformed for a "
1535 "32-bit object file (offset is not a multiple of 4)",
1536 ofile->file_name, (int)ofile->member_name_size,
1537 ofile->member_name, ofile->arch_flag.name);
1539 else
1540 error("fat file: %s architecture %s malformed for a 32-bit "
1541 "object file (offset is not a multiple of 4)",
1542 ofile->file_name, ofile->arch_flag.name);
1543 goto cleanup;
1545 #endif /* ALIGNMENT_CHECKS */
1546 ofile->arch_type = OFILE_Mach_O;
1547 ofile->object_addr = addr;
1548 ofile->object_size = size;
1549 host_byte_sex = get_host_byte_sex();
1550 if(magic == MH_MAGIC)
1551 ofile->object_byte_sex = host_byte_sex;
1552 else
1553 ofile->object_byte_sex =
1554 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1555 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1556 ofile->mh = (struct mach_header *)addr;
1557 ofile->load_commands = (struct load_command *)(addr +
1558 sizeof(struct mach_header));
1559 if(check_Mach_O(ofile) == CHECK_BAD)
1560 goto cleanup;
1562 /* see if this file is a 64-bit Mach-O file */
1563 else if(size >= sizeof(struct mach_header_64) &&
1564 (magic == MH_MAGIC_64 || magic == SWAP_INT(MH_MAGIC_64))){
1565 #ifdef ALIGNMENT_CHECKS
1566 if(ofile->fat_archs[ofile->narch].offset % 8 != 0){
1567 if(ofile->file_type == OFILE_ARCHIVE){
1568 error("fat file: %s(%.*s) architecture %s malformed for an "
1569 "object file (offset is not a multiple of 8)",
1570 ofile->file_name, (int)ofile->member_name_size,
1571 ofile->member_name, ofile->arch_flag.name);
1573 else
1574 error("fat file: %s architecture %s malformed for a 64-bit "
1575 "object file (offset is not a multiple of 8",
1576 ofile->file_name, ofile->arch_flag.name);
1577 goto cleanup;
1579 #endif /* ALIGNMENT_CHECKS */
1580 ofile->arch_type = OFILE_Mach_O;
1581 ofile->object_addr = addr;
1582 ofile->object_size = size;
1583 host_byte_sex = get_host_byte_sex();
1584 if(magic == MH_MAGIC_64)
1585 ofile->object_byte_sex = host_byte_sex;
1586 else
1587 ofile->object_byte_sex =
1588 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1589 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1590 ofile->mh64 = (struct mach_header_64 *)addr;
1591 ofile->load_commands = (struct load_command *)(addr +
1592 sizeof(struct mach_header_64));
1593 if(check_Mach_O(ofile) == CHECK_BAD)
1594 goto cleanup;
1596 /* see if this file is an archive file */
1597 else if(size >= SARMAG && strncmp(addr, ARMAG, SARMAG) == 0){
1598 ofile->arch_type = OFILE_ARCHIVE;
1599 if(check_archive(ofile, FALSE) == CHECK_BAD)
1600 goto cleanup;
1601 #ifdef ALIGNMENT_CHECKS
1602 if(ofile->archive_cputype != 0 &&
1603 ofile->fat_archs[ofile->narch].offset %
1604 sizeof(uint32_t) != 0){
1605 error("fat file: %s architecture %s malformed archive that "
1606 "contains object files (offset to archive is not a "
1607 "multiple of sizeof(uint32_t))",
1608 ofile->file_name, ofile->arch_flag.name);
1609 goto cleanup;
1611 #endif /* ALIGNMENT_CHECKS */
1614 * This type for this architecture is now known to be unknown to this
1615 * program.
1617 else{
1618 ofile->arch_type = OFILE_UNKNOWN;
1620 return(TRUE);
1621 cleanup:
1622 ofile->narch = 0;;
1623 ofile->arch_type = OFILE_UNKNOWN;
1624 if(ofile->arch_flag.name != NULL)
1625 free(ofile->arch_flag.name);
1626 ofile->arch_flag.name = NULL;
1627 ofile->arch_flag.cputype = 0;
1628 ofile->arch_flag.cpusubtype = 0;
1629 if(ofile->file_type != OFILE_ARCHIVE){
1630 ofile->member_offset = 0;
1631 ofile->member_addr = NULL;
1632 ofile->member_size = 0;
1633 ofile->member_ar_hdr = NULL;
1634 ofile->member_type = OFILE_UNKNOWN;
1636 ofile->archive_cputype = 0;
1637 ofile->archive_cpusubtype = 0;
1638 ofile->object_addr = NULL;
1639 ofile->object_size = 0;
1640 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
1641 ofile->mh = NULL;
1642 ofile->mh64 = NULL;
1643 ofile->load_commands = NULL;
1644 return(FALSE);
1648 * ofile_first_member() set up the ofile structure (the member_* fields and
1649 * the object file fields if the first member is an object file) for the first
1650 * member.
1652 __private_extern__
1653 enum bool
1654 ofile_first_member(
1655 struct ofile *ofile)
1657 char *addr;
1658 uint32_t size, offset;
1659 uint32_t magic;
1660 enum byte_sex host_byte_sex;
1661 struct ar_hdr *ar_hdr;
1662 uint32_t ar_name_size;
1664 /* These fields are to be filled in by this routine, clear them first */
1665 ofile->member_offset = 0;
1666 ofile->member_addr = NULL;
1667 ofile->member_size = 0;
1668 ofile->member_ar_hdr = NULL;
1669 ofile->member_name = NULL;
1670 ofile->member_name_size = 0;
1671 ofile->member_type = OFILE_UNKNOWN;
1672 ofile->object_addr = NULL;
1673 ofile->object_size = 0;
1674 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
1675 ofile->mh = NULL;
1676 ofile->mh64 = NULL;
1677 ofile->load_commands = NULL;
1678 #ifdef LTO_SUPPORT
1680 * Note: it is up to the caller if they want to call free_lto() on this
1681 * when iterating through the members of an archive.
1683 ofile->lto = NULL;
1684 #endif /* LTO_SUPPORT */
1687 * Get the address and size of the archive.
1689 if(ofile->file_type == OFILE_FAT){
1690 if(ofile->arch_type != OFILE_ARCHIVE){
1691 error("ofile_first_member() called on fat file: %s with a "
1692 "non-archive architecture or no architecture selected\n",
1693 ofile->file_name);
1694 return(FALSE);
1696 addr = ofile->file_addr + ofile->fat_archs[ofile->narch].offset;
1697 size = ofile->fat_archs[ofile->narch].size;
1699 else if(ofile->file_type == OFILE_ARCHIVE){
1700 addr = ofile->file_addr;
1701 size = ofile->file_size;
1703 else{
1704 error("ofile_first_member() called and file type of %s is "
1705 "OFILE_UNKNOWN\n", ofile->file_name);
1706 return(FALSE);
1708 #ifdef OTOOL
1709 if((addr + SARMAG) - ofile->file_addr > (ptrdiff_t)ofile->file_size){
1710 archive_error(ofile, "offset to first member extends past the end "
1711 "of the file");
1712 return(FALSE);
1714 if(addr + size > ofile->file_addr + ofile->file_size)
1715 size = (ofile->file_addr + ofile->file_size) - addr;
1716 #endif /* OTOOL */
1717 if(size < SARMAG || strncmp(addr, ARMAG, SARMAG) != 0){
1718 archive_error(ofile, "internal error. ofile_first_member() "
1719 "called but file does not have an archive magic "
1720 "string");
1721 return(FALSE);
1724 offset = SARMAG;
1725 if(offset != size && offset + sizeof(struct ar_hdr) > size){
1726 archive_error(ofile, "truncated or malformed (archive header of "
1727 "first member extends past the end of the file)");
1728 return(FALSE);
1731 /* check for empty archive */
1732 if(size == offset)
1733 return(FALSE);
1735 /* now we know there is a first member so set it up */
1736 ar_hdr = (struct ar_hdr *)(addr + offset);
1737 offset += sizeof(struct ar_hdr);
1738 ofile->member_offset = offset;
1739 ofile->member_addr = addr + offset;
1740 ofile->member_size = strtoul(ar_hdr->ar_size, NULL, 10);
1741 ofile->member_ar_hdr = ar_hdr;
1742 ofile->member_type = OFILE_UNKNOWN;
1743 ofile->member_name = ar_hdr->ar_name;
1744 if(strncmp(ofile->member_name, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0){
1745 ofile->member_name = ar_hdr->ar_name + sizeof(struct ar_hdr);
1746 ar_name_size = strtoul(ar_hdr->ar_name + sizeof(AR_EFMT1) - 1,
1747 NULL, 10);
1748 ofile->member_name_size = ar_name_size;
1749 ofile->member_offset += ar_name_size;
1750 ofile->member_addr += ar_name_size;
1751 ofile->member_size -= ar_name_size;
1753 else{
1754 ofile->member_name_size = size_ar_name(ar_hdr);
1755 ar_name_size = 0;
1757 /* Clear these in case there is no table of contents */
1758 ofile->toc_addr = NULL;
1759 ofile->toc_size = 0;
1760 ofile->toc_ar_hdr = NULL;
1761 ofile->toc_name = NULL;
1762 ofile->toc_name_size = 0;
1763 ofile->toc_ranlibs = NULL;
1764 ofile->toc_nranlibs = 0;
1765 ofile->toc_strings = NULL;
1766 ofile->toc_strsize = 0;
1767 ofile->toc_bad = FALSE;
1769 host_byte_sex = get_host_byte_sex();
1771 if(ofile->member_size > sizeof(uint32_t)){
1772 memcpy(&magic, ofile->member_addr, sizeof(uint32_t));
1773 #ifdef __BIG_ENDIAN__
1774 if(magic == FAT_MAGIC)
1775 #endif /* __BIG_ENDIAN__ */
1776 #ifdef __LITTLE_ENDIAN__
1777 if(magic == SWAP_INT(FAT_MAGIC))
1778 #endif /* __LITTLE_ENDIAN__ */
1780 ofile->member_type = OFILE_FAT;
1781 ofile->fat_header =
1782 (struct fat_header *)(ofile->member_addr);
1783 #ifdef __LITTLE_ENDIAN__
1784 swap_fat_header(ofile->fat_header, host_byte_sex);
1785 #endif /* __LITTLE_ENDIAN__ */
1786 if(sizeof(struct fat_header) +
1787 ofile->fat_header->nfat_arch *
1788 sizeof(struct fat_arch) > ofile->member_size){
1789 archive_member_error(ofile, "fat file truncated or "
1790 "malformed (fat_arch structs would extend past "
1791 "the end of the archive member)");
1792 goto fatcleanup;
1794 ofile->fat_archs = (struct fat_arch *)
1795 (ofile->member_addr + sizeof(struct fat_header));
1796 #ifdef __LITTLE_ENDIAN__
1797 swap_fat_arch(ofile->fat_archs,
1798 ofile->fat_header->nfat_arch, host_byte_sex);
1799 #endif /* __LITTLE_ENDIAN__ */
1800 if(check_fat_object_in_archive(ofile) == FALSE)
1801 goto fatcleanup;
1803 else if(size - (offset + ar_name_size) >=
1804 sizeof(struct mach_header) &&
1805 (magic == MH_MAGIC || magic == SWAP_INT(MH_MAGIC))){
1806 #ifdef ALIGNMENT_CHECKS
1807 if((offset + ar_name_size) % 4 != 0){
1808 archive_member_error(ofile, "offset in archive not a "
1809 "multiple of 4 (must be since member is a 32-bit "
1810 "object file)");
1811 goto cleanup;
1813 #endif /* ALIGNMENT_CHECKS */
1814 ofile->member_type = OFILE_Mach_O;
1815 ofile->object_addr = ofile->member_addr;
1816 ofile->object_size = ofile->member_size;
1817 if(magic == MH_MAGIC)
1818 ofile->object_byte_sex = host_byte_sex;
1819 else
1820 ofile->object_byte_sex =
1821 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1822 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1823 ofile->mh = (struct mach_header *)(ofile->object_addr);
1824 ofile->load_commands = (struct load_command *)
1825 (ofile->object_addr + sizeof(struct mach_header));
1826 if(check_Mach_O(ofile) == CHECK_BAD)
1827 goto cleanup;
1829 else if(size - (offset + ar_name_size) >=
1830 sizeof(struct mach_header_64) &&
1831 (magic == MH_MAGIC_64 || magic == SWAP_INT(MH_MAGIC_64))){
1832 #ifdef ALIGNMENT_CHECKS_ARCHIVE_64_BIT
1833 if(archive_64_bit_align_warning == FALSE &&
1834 (offset + ar_name_size) % 8 != 0){
1835 temporary_archive_member_warning(ofile, "offset in archive "
1836 "not a multiple of 8 (must be since member is an "
1837 "64-bit object file)");
1838 archive_64_bit_align_warning = TRUE;
1839 /* goto cleanup; */
1841 #endif /* ALIGNMENT_CHECKS_ARCHIVE_64_BIT */
1842 ofile->member_type = OFILE_Mach_O;
1843 ofile->object_addr = ofile->member_addr;
1844 ofile->object_size = ofile->member_size;
1845 if(magic == MH_MAGIC_64)
1846 ofile->object_byte_sex = host_byte_sex;
1847 else
1848 ofile->object_byte_sex =
1849 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1850 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1851 ofile->mh64 = (struct mach_header_64 *)(ofile->object_addr);
1852 ofile->load_commands = (struct load_command *)
1853 (ofile->object_addr + sizeof(struct mach_header_64));
1854 if(check_Mach_O(ofile) == CHECK_BAD)
1855 goto cleanup;
1857 if(ofile->member_type == OFILE_UNKNOWN &&
1858 (strncmp(ofile->member_name, SYMDEF_SORTED,
1859 sizeof(SYMDEF_SORTED) - 1) == 0 ||
1860 strncmp(ofile->member_name, SYMDEF,
1861 sizeof(SYMDEF) - 1) == 0)){
1862 ofile->toc_addr = ofile->member_addr;
1863 ofile->toc_size = ofile->member_size;
1864 ofile->toc_ar_hdr = ofile->member_ar_hdr;
1865 ofile->toc_name = ofile->member_name;
1866 ofile->toc_name_size = ofile->member_name_size;
1867 if(check_archive_toc(ofile) == CHECK_BAD)
1868 goto cleanup;
1870 #ifdef LTO_SUPPORT
1871 if(ofile->member_type == OFILE_UNKNOWN &&
1872 strncmp(ofile->member_name, SYMDEF_SORTED,
1873 sizeof(SYMDEF_SORTED) - 1) != 0 &&
1874 strncmp(ofile->member_name, SYMDEF,
1875 sizeof(SYMDEF) - 1) != 0 &&
1876 is_llvm_bitcode(ofile, ofile->member_addr, ofile->member_size) ==
1877 TRUE){
1878 ofile->member_type = OFILE_LLVM_BITCODE;
1879 ofile->object_addr = ofile->member_addr;
1880 ofile->object_size = ofile->member_size;
1882 #endif /* LTO_SUPPORT */
1884 return(TRUE);
1886 fatcleanup:
1887 ofile->fat_header = NULL;
1888 ofile->fat_archs = NULL;
1889 cleanup:
1890 ofile->member_offset = 0;
1891 ofile->member_addr = 0;
1892 ofile->member_size = 0;
1893 ofile->member_ar_hdr = NULL;
1894 ofile->member_name = NULL;
1895 ofile->member_name_size = 0;
1896 ofile->member_type = OFILE_UNKNOWN;
1897 ofile->object_addr = NULL;
1898 ofile->object_size = 0;
1899 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
1900 ofile->mh = NULL;
1901 ofile->mh64 = NULL;
1902 ofile->load_commands = NULL;
1903 #ifdef LTO_SUPPORT
1904 ofile->lto = NULL;
1905 ofile->lto_cputype = 0;
1906 ofile->lto_cpusubtype = 0;
1907 #endif /* LTO_SUPPORT */
1908 return(FALSE);
1912 * ofile_next_member() set up the ofile structure (the member_* fields and
1913 * the object file fields if the next member is an object file) for the next
1914 * member.
1916 __private_extern__
1917 enum bool
1918 ofile_next_member(
1919 struct ofile *ofile)
1921 char *addr;
1922 uint32_t size, offset;
1923 uint32_t magic;
1924 enum byte_sex host_byte_sex;
1925 struct ar_hdr *ar_hdr;
1926 uint32_t ar_name_size;
1929 * Get the address and size of the archive.
1931 if(ofile->file_type == OFILE_FAT){
1932 if(ofile->arch_type != OFILE_ARCHIVE){
1933 error("ofile_next_member() called on fat file: %s with a "
1934 "non-archive architecture or no architecture selected\n",
1935 ofile->file_name);
1936 return(FALSE);
1938 addr = ofile->file_addr + ofile->fat_archs[ofile->narch].offset;
1939 size = ofile->fat_archs[ofile->narch].size;
1941 else if(ofile->file_type == OFILE_ARCHIVE){
1942 addr = ofile->file_addr;
1943 size = ofile->file_size;
1945 else{
1946 error("ofile_next_member() called and file type of %s is "
1947 "OFILE_UNKNOWN\n", ofile->file_name);
1948 return(FALSE);
1950 if(size < SARMAG || strncmp(addr, ARMAG, SARMAG) != 0){
1951 archive_error(ofile, "internal error. ofile_next_member() "
1952 "called but file does not have an archive magic "
1953 "string");
1954 return(FALSE);
1956 if(ofile->member_ar_hdr == NULL){
1957 archive_error(ofile, "internal error. ofile_next_member() called "
1958 "but the ofile struct does not have an archive "
1959 "member selected");
1960 return(FALSE);
1963 /* figure out the offset to the next member */
1964 offset = ofile->member_offset + rnd(ofile->member_size,sizeof(short));
1965 #ifdef OTOOL
1966 if((addr - ofile->file_addr) + offset > ofile->file_size){
1967 archive_error(ofile, "offset to next member extends past the end "
1968 "of the file");
1969 return(FALSE);
1971 #endif /* OTOOL */
1972 /* if now at the end of the file then no more members */
1973 if(offset == size)
1974 goto cleanup;
1975 if(offset > size){
1976 archive_error(ofile, "truncated or malformed (archive header of "
1977 "next member extends past the end of the file)");
1978 return(FALSE);
1981 /* now we know there is a next member so set it up */
1982 ar_hdr = (struct ar_hdr *)(addr + offset);
1983 offset += sizeof(struct ar_hdr);
1984 ofile->member_offset = offset;
1985 ofile->member_addr = addr + offset;
1986 ofile->member_size = strtoul(ar_hdr->ar_size, NULL, 10);
1987 ofile->member_ar_hdr = ar_hdr;
1988 ofile->member_name = ar_hdr->ar_name;
1989 if(strncmp(ofile->member_name, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0){
1990 ofile->member_name = ar_hdr->ar_name + sizeof(struct ar_hdr);
1991 ar_name_size = strtoul(ar_hdr->ar_name + sizeof(AR_EFMT1) - 1,
1992 NULL, 10);
1993 ofile->member_name_size = ar_name_size;
1994 ofile->member_offset += ar_name_size;
1995 ofile->member_addr += ar_name_size;
1996 ofile->member_size -= ar_name_size;
1998 else{
1999 ofile->member_name_size = size_ar_name(ar_hdr);
2000 ar_name_size = 0;
2002 ofile->member_type = OFILE_UNKNOWN;
2003 ofile->object_addr = NULL;
2004 ofile->object_size = 0;
2005 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
2006 ofile->mh = NULL;
2007 ofile->mh64 = NULL;
2008 ofile->load_commands = NULL;
2010 host_byte_sex = get_host_byte_sex();
2012 if(ofile->member_size > sizeof(uint32_t)){
2013 memcpy(&magic, ofile->member_addr, sizeof(uint32_t));
2014 #ifdef __BIG_ENDIAN__
2015 if(magic == FAT_MAGIC)
2016 #endif /* __BIG_ENDIAN__ */
2017 #ifdef __LITTLE_ENDIAN__
2018 if(magic == SWAP_INT(FAT_MAGIC))
2019 #endif /* __LITTLE_ENDIAN__ */
2021 ofile->member_type = OFILE_FAT;
2022 ofile->fat_header = (struct fat_header *)(ofile->member_addr);
2023 #ifdef __LITTLE_ENDIAN__
2024 swap_fat_header(ofile->fat_header, host_byte_sex);
2025 #endif /* __LITTLE_ENDIAN__ */
2026 if(sizeof(struct fat_header) +
2027 ofile->fat_header->nfat_arch *
2028 sizeof(struct fat_arch) > ofile->member_size){
2029 archive_member_error(ofile, "fat file truncated or "
2030 "malformed (fat_arch structs would extend past "
2031 "the end of the archive member)");
2032 goto cleanup;
2034 ofile->fat_archs = (struct fat_arch *)(ofile->member_addr +
2035 sizeof(struct fat_header));
2036 #ifdef __LITTLE_ENDIAN__
2037 swap_fat_arch(ofile->fat_archs,
2038 ofile->fat_header->nfat_arch, host_byte_sex);
2039 #endif /* __LITTLE_ENDIAN__ */
2040 if(check_fat_object_in_archive(ofile) == FALSE)
2041 goto cleanup;
2043 else if(size - (offset + ar_name_size) >=
2044 sizeof(struct mach_header) &&
2045 (magic == MH_MAGIC ||
2046 magic == SWAP_INT(MH_MAGIC))){
2047 #ifdef ALIGNMENT_CHECKS
2048 if((offset + ar_name_size) % 4 != 0){
2049 archive_member_error(ofile, "offset in archive not "
2050 "a multiple of 4 (must be since member is an 32-bit "
2051 "object file)");
2052 goto cleanup;
2054 #endif /* ALIGNMENT_CHECKS */
2055 ofile->member_type = OFILE_Mach_O;
2056 ofile->object_addr = ofile->member_addr;
2057 ofile->object_size = ofile->member_size;
2058 if(magic == MH_MAGIC)
2059 ofile->object_byte_sex = host_byte_sex;
2060 else
2061 ofile->object_byte_sex =
2062 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
2063 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
2064 ofile->mh = (struct mach_header *)ofile->object_addr;
2065 ofile->load_commands = (struct load_command *)
2066 (ofile->object_addr + sizeof(struct mach_header));
2067 if(check_Mach_O(ofile) == CHECK_BAD)
2068 goto cleanup;
2070 else if(size - (offset + ar_name_size) >=
2071 sizeof(struct mach_header_64) &&
2072 (magic == MH_MAGIC_64 ||
2073 magic == SWAP_INT(MH_MAGIC_64))){
2074 #ifdef ALIGNMENT_CHECKS_ARCHIVE_64_BIT
2075 if(archive_64_bit_align_warning == FALSE &&
2076 (offset + ar_name_size) % 8 != 0){
2077 temporary_archive_member_warning(ofile, "offset in archive "
2078 "not a multiple of 8 (must be since member is an "
2079 "64-bit object file)");
2080 archive_64_bit_align_warning = TRUE;
2081 /* goto cleanup; */
2083 #endif /* ALIGNMENT_CHECKS_ARCHIVE_64_BIT */
2084 ofile->member_type = OFILE_Mach_O;
2085 ofile->object_addr = ofile->member_addr;
2086 ofile->object_size = ofile->member_size;
2087 if(magic == MH_MAGIC_64)
2088 ofile->object_byte_sex = host_byte_sex;
2089 else
2090 ofile->object_byte_sex =
2091 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
2092 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
2093 ofile->mh64 = (struct mach_header_64 *)ofile->object_addr;
2094 ofile->load_commands = (struct load_command *)
2095 (ofile->object_addr + sizeof(struct mach_header_64));
2096 if(check_Mach_O(ofile) == CHECK_BAD)
2097 goto cleanup;
2099 #ifdef LTO_SUPPORT
2100 if(ofile->member_type == OFILE_UNKNOWN &&
2101 is_llvm_bitcode(ofile, ofile->member_addr, ofile->member_size) ==
2102 TRUE){
2103 ofile->member_type = OFILE_LLVM_BITCODE;
2104 ofile->object_addr = ofile->member_addr;
2105 ofile->object_size = ofile->member_size;
2107 #endif /* LTO_SUPPORT */
2109 return(TRUE);
2111 cleanup:
2112 if(ofile->member_type == OFILE_FAT){
2113 ofile->fat_header = NULL;
2114 ofile->fat_archs = NULL;
2116 ofile->member_offset = 0;
2117 ofile->member_addr = NULL;
2118 ofile->member_size = 0;
2119 ofile->member_ar_hdr = NULL;
2120 ofile->member_name = NULL;
2121 ofile->member_name_size = 0;
2122 ofile->member_type = OFILE_UNKNOWN;
2123 ofile->object_addr = NULL;
2124 ofile->object_size = 0;
2125 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
2126 ofile->mh = NULL;
2127 ofile->mh64 = NULL;
2128 ofile->load_commands = NULL;
2129 #ifdef LTO_SUPPORT
2130 ofile->lto = NULL;
2131 ofile->lto_cputype = 0;
2132 ofile->lto_cpusubtype = 0;
2133 #endif /* LTO_SUPPORT */
2134 return(FALSE);
2138 * ofile_specific_member() set up the ofile structure (the member_* fields and
2139 * the object file fields if the member is an object file) for the specified
2140 * member member_name.
2142 __private_extern__
2143 enum bool
2144 ofile_specific_member(
2145 const char *member_name,
2146 struct ofile *ofile)
2148 int32_t i;
2149 char *addr;
2150 uint32_t size, offset;
2151 uint32_t magic;
2152 enum byte_sex host_byte_sex;
2153 char *ar_name;
2154 uint32_t ar_name_size;
2155 struct ar_hdr *ar_hdr;
2157 /* These fields are to be filled in by this routine, clear them first */
2158 ofile->member_offset = 0;
2159 ofile->member_addr = NULL;
2160 ofile->member_size = 0;
2161 ofile->member_ar_hdr = NULL;
2162 ofile->member_name = NULL;
2163 ofile->member_name_size = 0;
2164 ofile->member_type = OFILE_UNKNOWN;
2165 ofile->object_addr = NULL;
2166 ofile->object_size = 0;
2167 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
2168 ofile->mh = NULL;
2169 ofile->mh64 = NULL;
2170 ofile->load_commands = NULL;
2173 * Get the address and size of the archive.
2175 if(ofile->file_type == OFILE_FAT){
2176 if(ofile->arch_type != OFILE_ARCHIVE){
2177 error("ofile_specific_member() called on fat file: %s with a "
2178 "non-archive architecture or no architecture selected\n",
2179 ofile->file_name);
2180 return(FALSE);
2182 addr = ofile->file_addr + ofile->fat_archs[ofile->narch].offset;
2183 size = ofile->fat_archs[ofile->narch].size;
2185 else if(ofile->file_type == OFILE_ARCHIVE){
2186 addr = ofile->file_addr;
2187 size = ofile->file_size;
2189 else{
2190 error("ofile_specific_member() called and file type of %s is "
2191 "OFILE_UNKNOWN\n", ofile->file_name);
2192 return(FALSE);
2194 if(size < SARMAG || strncmp(addr, ARMAG, SARMAG) != 0){
2195 archive_error(ofile, "internal error. ofile_specific_member() "
2196 "called but file does not have an archive magic "
2197 "string");
2198 return(FALSE);
2201 offset = SARMAG;
2202 if(offset != size && offset + sizeof(struct ar_hdr) > size){
2203 archive_error(ofile, "truncated or malformed (archive header of "
2204 "first member extends past the end of the file)");
2205 return(FALSE);
2207 while(size > offset){
2208 ar_hdr = (struct ar_hdr *)(addr + offset);
2209 offset += sizeof(struct ar_hdr);
2210 if(strncmp(ar_hdr->ar_name, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0){
2211 #ifdef OTOOL
2212 if(check_extend_format_1(ofile, ar_hdr, size - offset,
2213 &ar_name_size) == CHECK_BAD){
2214 i = size_ar_name(ar_hdr);
2215 ar_name = ar_hdr->ar_name;
2216 ar_name_size = 0;
2218 else
2219 #endif /* OTOOL */
2221 i = strtoul(ar_hdr->ar_name + sizeof(AR_EFMT1) - 1,NULL,10);
2222 ar_name = ar_hdr->ar_name + sizeof(struct ar_hdr);
2223 ar_name_size = i;
2226 else{
2227 i = size_ar_name(ar_hdr);
2228 ar_name = ar_hdr->ar_name;
2229 ar_name_size = 0;
2231 if(i > 0 && strncmp(ar_name, member_name, i) == 0){
2233 ofile->member_name = ar_name;
2234 ofile->member_name_size = i;
2235 ofile->member_offset = offset + ar_name_size;
2236 ofile->member_addr = addr + offset + ar_name_size;
2237 ofile->member_size = strtoul(ar_hdr->ar_size, NULL, 10) -
2238 ar_name_size;
2239 ofile->member_ar_hdr = ar_hdr;
2240 ofile->member_type = OFILE_UNKNOWN;
2242 host_byte_sex = get_host_byte_sex();
2244 if(ofile->member_size > sizeof(uint32_t)){
2245 memcpy(&magic, addr + offset + ar_name_size,
2246 sizeof(uint32_t));
2247 #ifdef __BIG_ENDIAN__
2248 if(magic == FAT_MAGIC)
2249 #endif /* __BIG_ENDIAN__ */
2250 #ifdef __LITTLE_ENDIAN__
2251 if(magic == SWAP_INT(FAT_MAGIC))
2252 #endif /* __LITTLE_ENDIAN__ */
2254 ofile->member_type = OFILE_FAT;
2255 ofile->fat_header =
2256 (struct fat_header *)(addr + offset + ar_name_size);
2257 #ifdef __LITTLE_ENDIAN__
2258 swap_fat_header(ofile->fat_header, host_byte_sex);
2259 #endif /* __LITTLE_ENDIAN__ */
2260 if(sizeof(struct fat_header) +
2261 ofile->fat_header->nfat_arch *
2262 sizeof(struct fat_arch) > ofile->member_size){
2263 archive_member_error(ofile, "fat file truncated or "
2264 "malformed (fat_arch structs would extend "
2265 "past the end of the archive member)");
2266 goto fatcleanup;
2268 ofile->fat_archs =
2269 (struct fat_arch *)(addr + offset + ar_name_size +
2270 sizeof(struct fat_header));
2271 #ifdef __LITTLE_ENDIAN__
2272 swap_fat_arch(ofile->fat_archs,
2273 ofile->fat_header->nfat_arch,
2274 host_byte_sex);
2275 #endif /* __LITTLE_ENDIAN__ */
2276 if(check_fat_object_in_archive(ofile) == FALSE)
2277 goto fatcleanup;
2279 else if(size - (offset + ar_name_size) >=
2280 sizeof(struct mach_header) &&
2281 (magic == MH_MAGIC ||
2282 magic == SWAP_INT(MH_MAGIC))){
2283 #ifdef ALIGNMENT_CHECKS
2284 if((offset + ar_name_size) % 4 != 0){
2285 archive_member_error(ofile, "offset in archive not "
2286 "a multiple of 4) (must be since member is a "
2287 "32-bit object file)");
2288 goto cleanup;
2290 #endif /* ALIGNMENT_CHECKS */
2291 ofile->member_type = OFILE_Mach_O;
2292 ofile->object_addr = ofile->member_addr;
2293 ofile->object_size = ofile->member_size;
2294 if(magic == MH_MAGIC)
2295 ofile->object_byte_sex = host_byte_sex;
2296 else
2297 ofile->object_byte_sex =
2298 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
2299 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
2300 ofile->mh = (struct mach_header *)ofile->object_addr;
2301 ofile->load_commands = (struct load_command *)
2302 (ofile->object_addr + sizeof(struct mach_header));
2303 if(check_Mach_O(ofile) == CHECK_BAD)
2304 goto cleanup;
2306 else if(size - (offset + ar_name_size) >=
2307 sizeof(struct mach_header_64) &&
2308 (magic == MH_MAGIC_64 ||
2309 magic == SWAP_INT(MH_MAGIC_64))){
2310 #ifdef ALIGNMENT_CHECKS_ARCHIVE_64_BIT
2311 if(archive_64_bit_align_warning == FALSE &&
2312 (offset + ar_name_size) % 8 != 0){
2313 temporary_archive_member_warning(ofile, "offset in "
2314 "archive not a multiple of 8) (must be since "
2315 "member is a 64-bit object file)");
2316 archive_64_bit_align_warning = TRUE;
2317 /* goto cleanup; */
2319 #endif /* ALIGNMENT_CHECKS_ARCHIVE_64_BIT */
2320 ofile->member_type = OFILE_Mach_O;
2321 ofile->object_addr = ofile->member_addr;
2322 ofile->object_size = ofile->member_size;
2323 if(magic == MH_MAGIC_64)
2324 ofile->object_byte_sex = host_byte_sex;
2325 else
2326 ofile->object_byte_sex =
2327 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
2328 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
2329 ofile->mh64 = (struct mach_header_64 *)
2330 ofile->object_addr;
2331 ofile->load_commands = (struct load_command *)
2332 (ofile->object_addr +sizeof(struct mach_header_64));
2333 if(check_Mach_O(ofile) == CHECK_BAD)
2334 goto cleanup;
2337 #ifdef LTO_SUPPORT
2338 if(ofile->member_type == OFILE_UNKNOWN &&
2339 is_llvm_bitcode(ofile, ofile->member_addr,
2340 ofile->member_size) == TRUE){
2341 ofile->member_type = OFILE_LLVM_BITCODE;
2342 ofile->object_addr = ofile->member_addr;
2343 ofile->object_size = ofile->member_size;
2345 #endif /* LTO_SUPPORT */
2346 return(TRUE);
2348 offset += rnd(strtoul(ar_hdr->ar_size, NULL, 10),
2349 sizeof(short));
2351 archive_error(ofile, "does not contain a member named: %s",
2352 member_name);
2353 fatcleanup:
2354 ofile->fat_header = NULL;
2355 ofile->fat_archs = NULL;
2356 cleanup:
2357 ofile->member_offset = 0;
2358 ofile->member_addr = NULL;
2359 ofile->member_size = 0;
2360 ofile->member_ar_hdr = NULL;
2361 ofile->member_name = NULL;
2362 ofile->member_name_size = 0;
2363 ofile->member_type = OFILE_UNKNOWN;
2364 ofile->object_addr = NULL;
2365 ofile->object_size = 0;
2366 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
2367 ofile->mh = NULL;
2368 ofile->mh64 = NULL;
2369 ofile->load_commands = NULL;
2370 #ifdef LTO_SUPPORT
2371 ofile->lto = NULL;
2372 ofile->lto_cputype = 0;
2373 ofile->lto_cpusubtype = 0;
2374 #endif /* LTO_SUPPORT */
2375 return(FALSE);
2379 * ofile_first_module() set up the ofile structure (the dylib_module field)
2380 * for the first module of an MH_DYLIB or MH_DYLIB_STUB file.
2382 __private_extern__
2383 enum bool
2384 ofile_first_module(
2385 struct ofile *ofile)
2387 uint32_t i, ncmds;
2388 struct symtab_command *st;
2389 struct dysymtab_command *dyst;
2390 struct load_command *lc;
2391 enum bool swapped;
2392 enum byte_sex host_byte_sex;
2393 struct dylib_module m;
2394 struct dylib_module_64 m64;
2395 char *strings;
2397 /* These fields are to be filled in by this routine, clear them first */
2398 ofile->modtab = NULL;
2399 ofile->modtab64 = NULL;
2400 ofile->nmodtab = 0;
2401 ofile->dylib_module = NULL;
2402 ofile->dylib_module64 = NULL;
2403 ofile->dylib_module_name = NULL;
2405 if(ofile->file_type == OFILE_FAT){
2406 if(ofile->arch_type != OFILE_Mach_O &&
2407 (ofile->mh_filetype != MH_DYLIB &&
2408 ofile->mh_filetype != MH_DYLIB_STUB)){
2409 error("ofile_first_module() called on fat file: %s with a "
2410 "non-MH_DYLIB architecture or no architecture selected\n",
2411 ofile->file_name);
2412 return(FALSE);
2415 else if(ofile->arch_type != OFILE_Mach_O &&
2416 (ofile->mh_filetype != MH_DYLIB &&
2417 ofile->mh_filetype != MH_DYLIB_STUB)){
2418 error("ofile_first_module() called and file type of %s is "
2419 "non-MH_DYLIB\n", ofile->file_name);
2420 return(FALSE);
2423 st = NULL;
2424 dyst = NULL;
2425 lc = ofile->load_commands;
2426 if(ofile->mh != NULL)
2427 ncmds = ofile->mh->ncmds;
2428 else
2429 ncmds = ofile->mh64->ncmds;
2430 for(i = 0; i < ncmds; i++){
2431 if(st == NULL && lc->cmd == LC_SYMTAB){
2432 st = (struct symtab_command *)lc;
2434 else if(lc->cmd == LC_DYSYMTAB){
2435 dyst = (struct dysymtab_command *)lc;
2437 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2439 if(st == NULL || dyst == NULL){
2440 #ifndef OTOOL
2441 Mach_O_error(ofile, "MH_DYLIB format error (does not have a symbol "
2442 "table and/or a dynamic symbol table)");
2443 #endif
2444 return(FALSE);
2446 if(dyst->nmodtab == 0)
2447 return(FALSE);
2449 ofile->nmodtab = dyst->nmodtab;
2450 host_byte_sex = get_host_byte_sex();
2451 swapped = (enum bool)(host_byte_sex != ofile->object_byte_sex);
2452 strings = (char *)(ofile->object_addr + st->stroff);
2454 if(ofile->mh != NULL){
2455 ofile->modtab = (struct dylib_module *)(ofile->object_addr +
2456 dyst->modtaboff);
2457 ofile->dylib_module = ofile->modtab;
2458 m = *ofile->dylib_module;
2459 if(swapped)
2460 swap_dylib_module(&m, 1, host_byte_sex);
2461 ofile->dylib_module_name = strings + m.module_name;
2463 else{
2464 ofile->modtab64 = (struct dylib_module_64 *)(ofile->object_addr +
2465 dyst->modtaboff);
2466 ofile->dylib_module64 = ofile->modtab64;
2467 m64 = *ofile->dylib_module64;
2468 if(swapped)
2469 swap_dylib_module_64(&m64, 1, host_byte_sex);
2470 ofile->dylib_module_name = strings + m64.module_name;
2473 if(check_dylib_module(ofile, st, dyst, strings, 0) == CHECK_BAD)
2474 return(FALSE);
2475 return(TRUE);
2479 * ofile_next_module() set up the ofile structure (the dylib_module field)
2480 * for the next module of an MH_DYLIB or MH_DYLIB_STUB file.
2482 __private_extern__
2483 enum bool
2484 ofile_next_module(
2485 struct ofile *ofile)
2487 uint32_t i, module_index, ncmds;
2488 struct symtab_command *st;
2489 struct dysymtab_command *dyst;
2490 struct load_command *lc;
2491 enum bool swapped;
2492 enum byte_sex host_byte_sex;
2493 struct dylib_module m;
2494 struct dylib_module_64 m64;
2495 char *strings;
2497 if(ofile->file_type == OFILE_FAT){
2498 if(ofile->arch_type != OFILE_Mach_O &&
2499 (ofile->mh_filetype != MH_DYLIB &&
2500 ofile->mh_filetype != MH_DYLIB_STUB)){
2501 error("ofile_next_module() called on fat file: %s with a "
2502 "non-MH_DYLIB architecture or no architecture selected\n",
2503 ofile->file_name);
2504 return(FALSE);
2507 else if(ofile->arch_type != OFILE_Mach_O &&
2508 (ofile->mh_filetype != MH_DYLIB &&
2509 ofile->mh_filetype != MH_DYLIB_STUB)){
2510 error("ofile_next_module() called and file type of %s is "
2511 "non-MH_DYLIB\n", ofile->file_name);
2512 return(FALSE);
2514 st = NULL;
2515 dyst = NULL;
2516 lc = ofile->load_commands;
2517 if(ofile->mh != NULL)
2518 ncmds = ofile->mh->ncmds;
2519 else
2520 ncmds = ofile->mh64->ncmds;
2521 for(i = 0; i < ncmds; i++){
2522 if(st == NULL && lc->cmd == LC_SYMTAB){
2523 st = (struct symtab_command *)lc;
2525 else if(lc->cmd == LC_DYSYMTAB){
2526 dyst = (struct dysymtab_command *)lc;
2528 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2530 if(st == NULL || dyst == NULL){
2531 #ifndef OTOOL
2532 Mach_O_error(ofile, "MH_DYLIB format error (does not have a symbol "
2533 "table and/or a dynamic symbol table)");
2534 #endif
2535 return(FALSE);
2538 if(ofile->mh != NULL)
2539 module_index = (ofile->dylib_module + 1) - ofile->modtab;
2540 else
2541 module_index = (ofile->dylib_module64 + 1) - ofile->modtab64;
2542 if(module_index >= ofile->nmodtab)
2543 return(FALSE);
2545 host_byte_sex = get_host_byte_sex();
2546 swapped = (enum bool)(host_byte_sex != ofile->object_byte_sex);
2547 strings = (char *)(ofile->object_addr + st->stroff);
2549 if(ofile->mh != NULL){
2550 ofile->dylib_module++;
2551 m = *ofile->dylib_module;
2552 if(swapped)
2553 swap_dylib_module(&m, 1, host_byte_sex);
2554 ofile->dylib_module_name = strings + m.module_name;
2556 else{
2557 ofile->dylib_module64++;
2558 m64 = *ofile->dylib_module64;
2559 if(swapped)
2560 swap_dylib_module_64(&m64, 1, host_byte_sex);
2561 ofile->dylib_module_name = strings + m64.module_name;
2563 if(check_dylib_module(ofile, st, dyst, strings, module_index) ==
2564 CHECK_BAD)
2565 return(FALSE);
2566 return(TRUE);
2570 * ofile_specific_module() set up the ofile structure (the dylib_module fields)
2571 * for the specified module, module_name, of an MH_DYLIB or an MH_DYLIB_STUB
2572 * file.
2574 __private_extern__
2575 enum bool
2576 ofile_specific_module(
2577 const char *module_name,
2578 struct ofile *ofile)
2580 uint32_t i, ncmds;
2581 enum bool swapped;
2582 enum byte_sex host_byte_sex;
2583 struct symtab_command *st;
2584 struct dysymtab_command *dyst;
2585 struct load_command *lc;
2586 struct dylib_module *p, m;
2587 struct dylib_module_64 *p64, m64;
2588 char *strings;
2590 /* These fields are to be filled in by this routine, clear them first */
2591 ofile->modtab = NULL;
2592 ofile->modtab64 = NULL;
2593 ofile->nmodtab = 0;
2594 ofile->dylib_module = NULL;
2595 ofile->dylib_module64 = NULL;
2596 ofile->dylib_module_name = NULL;
2598 if(ofile->file_type == OFILE_FAT){
2599 if(ofile->arch_type != OFILE_Mach_O &&
2600 (ofile->mh_filetype != MH_DYLIB &&
2601 ofile->mh_filetype != MH_DYLIB_STUB)){
2602 error("ofile_specific_module() called on fat file: %s with a "
2603 "non-MH_DYLIB architecture or no architecture selected\n",
2604 ofile->file_name);
2605 return(FALSE);
2608 else if(ofile->arch_type != OFILE_Mach_O &&
2609 (ofile->mh_filetype != MH_DYLIB &&
2610 ofile->mh_filetype != MH_DYLIB_STUB)){
2611 error("ofile_specific_module() called and file type of %s is "
2612 "non-MH_DYLIB\n", ofile->file_name);
2613 return(FALSE);
2616 st = NULL;
2617 dyst = NULL;
2618 lc = ofile->load_commands;
2619 if(ofile->mh != NULL)
2620 ncmds = ofile->mh->ncmds;
2621 else
2622 ncmds = ofile->mh64->ncmds;
2623 for(i = 0; i < ncmds; i++){
2624 if(st == NULL && lc->cmd == LC_SYMTAB){
2625 st = (struct symtab_command *)lc;
2627 else if(lc->cmd == LC_DYSYMTAB){
2628 dyst = (struct dysymtab_command *)lc;
2630 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2632 if(st == NULL || dyst == NULL){
2633 #ifndef OTOOL
2634 Mach_O_error(ofile, "MH_DYLIB format error (does not have a symbol "
2635 "table and/or a dynamic symbol table)");
2636 #endif
2637 return(FALSE);
2639 if(dyst->nmodtab == 0)
2640 return(FALSE);
2642 host_byte_sex = get_host_byte_sex();
2643 swapped = (enum bool)(host_byte_sex != ofile->object_byte_sex);
2644 strings = (char *)(ofile->object_addr + st->stroff);
2646 if(ofile->mh != NULL){
2647 ofile->nmodtab = dyst->nmodtab;
2648 ofile->modtab = (struct dylib_module *)(ofile->object_addr +
2649 dyst->modtaboff);
2650 p = ofile->modtab;
2651 for(i = 0; i < dyst->nmodtab; i++){
2652 m = *p;
2653 if(swapped)
2654 swap_dylib_module(&m, 1, host_byte_sex);
2655 ofile->dylib_module = p;
2656 if(check_dylib_module(ofile, st, dyst, strings, i) == CHECK_BAD)
2657 return(FALSE);
2658 if(strcmp(module_name, strings + m.module_name) == 0){
2659 ofile->dylib_module_name = strings + m.module_name;
2660 return(TRUE);
2662 p++;
2664 m = *ofile->dylib_module;
2665 if(swapped)
2666 swap_dylib_module(&m, 1, host_byte_sex);
2667 ofile->dylib_module_name = strings + m.module_name;
2669 else{
2670 ofile->nmodtab = dyst->nmodtab;
2671 ofile->modtab64 = (struct dylib_module_64 *)(ofile->object_addr +
2672 dyst->modtaboff);
2673 p64 = ofile->modtab64;
2674 for(i = 0; i < dyst->nmodtab; i++){
2675 m64 = *p64;
2676 if(swapped)
2677 swap_dylib_module_64(&m64, 1, host_byte_sex);
2678 ofile->dylib_module64 = p64;
2679 if(check_dylib_module(ofile, st, dyst, strings, i) == CHECK_BAD)
2680 return(FALSE);
2681 if(strcmp(module_name, strings + m64.module_name) == 0){
2682 ofile->dylib_module_name = strings + m64.module_name;
2683 return(TRUE);
2685 p64++;
2687 m64 = *ofile->dylib_module64;
2688 if(swapped)
2689 swap_dylib_module_64(&m64, 1, host_byte_sex);
2690 ofile->dylib_module_name = strings + m64.module_name;
2692 #ifndef OTOOL
2693 Mach_O_error(ofile, "does not contain a module named: %s", module_name);
2694 #endif
2695 ofile->modtab = NULL;
2696 ofile->nmodtab = 0;
2697 ofile->dylib_module = NULL;
2698 ofile->dylib_module_name = NULL;
2699 return(FALSE);
2702 #ifdef DEBUG
2703 __private_extern__
2704 void
2705 ofile_print(
2706 struct ofile *ofile)
2708 printf("file_name = %s\n", ofile->file_name);
2709 printf("file_addr = 0x%x\n", (unsigned int)ofile->file_addr);
2710 printf("file_size = 0x%x\n", (unsigned int)ofile->file_size);
2711 printf("file_type = 0x%x\n", (unsigned int)ofile->file_type);
2712 printf("fat_header = 0x%x\n", (unsigned int)ofile->fat_header);
2713 printf("fat_archs = 0x%x\n", (unsigned int)ofile->fat_archs);
2714 printf("narch = 0x%x\n", (unsigned int)ofile->narch);
2715 printf("arch_type = 0x%x\n", (unsigned int)ofile->arch_type);
2716 printf("arch_flag.name = %s\n", ofile->arch_flag.name);
2717 printf("arch_flag.cputype = 0x%x\n",
2718 (unsigned int)ofile->arch_flag.cputype);
2719 printf("arch_flag.cpusubtype = 0x%x\n",
2720 (unsigned int)ofile->arch_flag.cpusubtype);
2721 printf("member_offset = 0x%x\n", (unsigned int)ofile->member_offset);
2722 printf("member_addr = 0x%x\n", (unsigned int)ofile->member_addr);
2723 printf("member_size = 0x%x\n", (unsigned int)ofile->member_size);
2724 printf("member_ar_hdr = 0x%x\n", (unsigned int)ofile->member_ar_hdr);
2725 printf("member_type = 0x%x\n", (unsigned int)ofile->member_type);
2726 printf("archive_cputype = 0x%x\n",
2727 (unsigned int)ofile->archive_cputype);
2728 printf("archive_cpusubtype = 0x%x\n",
2729 (unsigned int)ofile->archive_cpusubtype);
2730 printf("object_addr = 0x%x\n", (unsigned int)ofile->object_addr);
2731 printf("object_size = 0x%x\n", (unsigned int)ofile->object_size);
2732 printf("object_byte_sex = 0x%x\n",
2733 (unsigned int)ofile->object_byte_sex);
2734 printf("mh = 0x%x\n", (unsigned int)ofile->mh);
2735 printf("mh64 = 0x%x\n", (unsigned int)ofile->mh64);
2736 printf("load_commands = 0x%x\n", (unsigned int)ofile->load_commands);
2738 #endif /* DEBUG */
2741 * check_fat() checks the fat ofile for correctness (the fat_header and
2742 * fat_archs are assumed to be in the host byte sex).
2744 static
2745 enum check_type
2746 check_fat(
2747 struct ofile *ofile)
2749 #ifdef OTOOL
2750 return(CHECK_GOOD);
2751 #else /* !defined OTOOL */
2753 uint32_t i, j;
2754 uint64_t big_size;
2756 if(ofile->file_type != OFILE_FAT){
2757 error("internal error. check_fat() call and file type of: %s is "
2758 "not OFILE_FAT\n", ofile->file_name);
2759 return(CHECK_BAD);
2761 if(ofile->fat_header->nfat_arch == 0){
2762 error("fat file: %s malformed (contains zero architecture types)",
2763 ofile->file_name);
2764 return(CHECK_BAD);
2766 for(i = 0; i < ofile->fat_header->nfat_arch; i++){
2767 big_size = ofile->fat_archs[i].offset;
2768 big_size += ofile->fat_archs[i].size;
2769 if(big_size > ofile->file_size){
2770 error("fat file: %s truncated or malformed (offset plus size "
2771 "of cputype (%d) cpusubtype (%d) extends past the "
2772 "end of the file)", ofile->file_name,
2773 ofile->fat_archs[i].cputype,
2774 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK);
2775 return(CHECK_BAD);
2777 if(ofile->fat_archs[i].align > MAXSECTALIGN){
2778 error("fat file: %s align (2^%u) too large for cputype (%d) "
2779 "cpusubtype (%d) (maximum 2^%d)", ofile->file_name,
2780 ofile->fat_archs[i].align, ofile->fat_archs[i].cputype,
2781 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK,
2782 MAXSECTALIGN);
2783 return(CHECK_BAD);
2785 if(ofile->fat_archs[i].offset %
2786 (1 << ofile->fat_archs[i].align) != 0){
2787 error("fat file: %s offset: %u for cputype (%d) cpusubtype "
2788 "(%d)) not aligned on it's alignment (2^%u)",
2789 ofile->file_name,
2790 ofile->fat_archs[i].offset,
2791 ofile->fat_archs[i].cputype,
2792 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK,
2793 ofile->fat_archs[i].align);
2794 return(CHECK_BAD);
2797 for(i = 0; i < ofile->fat_header->nfat_arch; i++){
2798 for(j = i + 1; j < ofile->fat_header->nfat_arch; j++){
2799 if(ofile->fat_archs[i].cputype ==
2800 ofile->fat_archs[j].cputype &&
2801 (ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK) ==
2802 (ofile->fat_archs[j].cpusubtype & ~CPU_SUBTYPE_MASK)){
2803 error("fat file: %s contains two of the same "
2804 "architecture (cputype (%d) cpusubtype (%d))",
2805 ofile->file_name, ofile->fat_archs[i].cputype,
2806 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK);
2807 return(CHECK_BAD);
2811 return(CHECK_GOOD);
2812 #endif /* OTOOL */
2816 * check_fat_object_in_archive() checks the fat object file which is a member
2817 * of a thin archive for correctness (the fat_header and fat_archs are assumed
2818 * to be in the host byte sex). This is not a legal form but allowed when
2819 * archives_with_fat_objects is TRUE when ofile_map() is called.
2821 static
2822 enum check_type
2823 check_fat_object_in_archive(
2824 struct ofile *ofile)
2826 uint32_t i, j;
2827 uint32_t magic;
2829 if(ofile->file_type != OFILE_ARCHIVE){
2830 error("internal error. check_fat_object_in_archive() called and "
2831 "file type of: %s is not OFILE_ARCHIVE\n", ofile->file_name);
2832 return(CHECK_BAD);
2834 if(ofile->fat_header->nfat_arch == 0){
2835 archive_member_error(ofile, "fat file malformed (contains zero "
2836 "architecture types)");
2837 return(CHECK_BAD);
2839 for(i = 0; i < ofile->fat_header->nfat_arch; i++){
2840 if(ofile->fat_archs[i].offset + ofile->fat_archs[i].size >
2841 ofile->member_size){
2842 archive_member_error(ofile, "fat file truncated or malformed "
2843 "(offset plus size of cputype (%d) cpusubtype (%d) "
2844 "extends past the end of the file)",
2845 ofile->fat_archs[i].cputype,
2846 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK);
2847 return(CHECK_BAD);
2849 if(ofile->fat_archs[i].align > MAXSECTALIGN){
2850 archive_member_error(ofile, "fat file's align (2^%u) too "
2851 "large for cputype (%d) cpusubtype (%d) (maximum 2^%d)",
2852 ofile->fat_archs[i].align, ofile->fat_archs[i].cputype,
2853 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK,
2854 MAXSECTALIGN);
2855 return(CHECK_BAD);
2857 if(ofile->fat_archs[i].offset %
2858 (1 << ofile->fat_archs[i].align) != 0){
2859 archive_member_error(ofile, "fat file's offset: %u for "
2860 "cputype (%d) cpusubtype (%d) not aligned on it's "
2861 "alignment (2^%u)", ofile->fat_archs[i].offset,
2862 ofile->fat_archs[i].cputype,
2863 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK,
2864 ofile->fat_archs[i].align);
2865 return(CHECK_BAD);
2869 * The only supported format where fat files are allowed to appear
2870 * in archives is when the fat file contains only object files.
2872 if(ofile->fat_archs[i].size < sizeof(struct mach_header)){
2873 archive_member_error(ofile, "fat file for cputype (%d) "
2874 "cpusubtype (%d) is not an object file (size too small "
2875 "to be an object file)", ofile->fat_archs[i].cputype,
2876 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK);
2877 return(CHECK_BAD);
2879 memcpy(&magic,
2880 ofile->file_addr + ofile->member_offset +
2881 ofile->fat_archs[i].offset,
2882 sizeof(uint32_t));
2883 if(magic == MH_MAGIC || magic == SWAP_INT(MH_MAGIC)){
2884 #ifdef ALIGNMENT_CHECKS
2885 if((ofile->member_offset + ofile->fat_archs[i].offset) %
2886 4 != 0){
2887 archive_member_error(ofile, "fat object file's offset in "
2888 "archive not a multiple of 4) (must be since "
2889 "member is a 32-bit object file)");
2890 return(CHECK_BAD);
2892 #endif /* ALIGNMENT_CHECKS */
2894 else if(magic == MH_MAGIC_64 || magic == SWAP_INT(MH_MAGIC_64)){
2895 #ifdef ALIGNMENT_CHECKS_ARCHIVE_64_BIT
2896 if(archive_64_bit_align_warning == FALSE &&
2897 (ofile->member_offset + ofile->fat_archs[i].offset) %
2898 8 != 0){
2899 temporary_archive_member_warning(ofile, "fat object file's "
2900 "offset in archive not a multiple of 8) (must be since "
2901 "member is a 64-bit object file)");
2902 archive_64_bit_align_warning = TRUE;
2903 /* return(CHECK_BAD); */
2905 #endif /* ALIGNMENT_CHECKS_ARCHIVE_64_BIT */
2907 else{
2908 archive_member_error(ofile, "fat file for cputype (%d) "
2909 "cpusubtype (%d) is not an object file (bad magic "
2910 "number)", ofile->fat_archs[i].cputype,
2911 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK);
2912 return(CHECK_BAD);
2915 for(i = 0; i < ofile->fat_header->nfat_arch; i++){
2916 for(j = i + 1; j < ofile->fat_header->nfat_arch; j++){
2917 if(ofile->fat_archs[i].cputype ==
2918 ofile->fat_archs[j].cputype &&
2919 (ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK) ==
2920 (ofile->fat_archs[j].cpusubtype & ~CPU_SUBTYPE_MASK)){
2921 archive_member_error(ofile, "fat file contains two of the "
2922 "same architecture (cputype (%d) cpusubtype (%d))",
2923 ofile->fat_archs[i].cputype,
2924 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK);
2925 return(CHECK_BAD);
2929 return(CHECK_GOOD);
2933 * check_archive() checks the archive referenced in the ofile for correctness.
2935 static
2936 enum check_type
2937 check_archive(
2938 struct ofile *ofile,
2939 enum bool archives_with_fat_objects)
2941 #ifdef OTOOL
2942 return(CHECK_GOOD);
2943 #else /* !defined OTOOL */
2944 char *addr;
2945 uint32_t size, offset;
2946 uint64_t big_size;
2947 uint32_t magic;
2948 enum byte_sex host_byte_sex;
2949 enum bool swapped;
2950 struct mach_header mh;
2951 struct mach_header_64 mh64;
2952 struct ar_hdr *ar_hdr;
2953 uint32_t ar_name_size;
2956 * Get the address and size of the archive (as well as the cputype and
2957 * cpusubtype if known) and make sure it is an archive.
2959 if(ofile->file_type == OFILE_FAT){
2960 addr = ofile->file_addr + ofile->fat_archs[ofile->narch].offset;
2961 size = ofile->fat_archs[ofile->narch].size;
2962 ofile->archive_cputype = ofile->fat_archs[ofile->narch].cputype;
2963 ofile->archive_cpusubtype =
2964 ofile->fat_archs[ofile->narch].cpusubtype;
2966 else if(ofile->file_type == OFILE_ARCHIVE){
2967 addr = ofile->file_addr;
2968 size = ofile->file_size;
2969 ofile->archive_cputype = 0;
2970 ofile->archive_cpusubtype = 0;
2972 else{
2973 error("internal error. check_archive() call and file type of %s is "
2974 "OFILE_UNKNOWN\n", ofile->file_name);
2975 return(CHECK_BAD);
2977 if(size < SARMAG || strncmp(addr, ARMAG, SARMAG) != 0){
2978 error("internal error. check_archive() call for file %s which does "
2979 "not have an archive magic string", ofile->file_name);
2980 return(CHECK_BAD);
2983 host_byte_sex = get_host_byte_sex();
2985 * Check this archive out to make sure that it does not contain
2986 * any fat files and that all object files it contains have the
2987 * same cputype and subsubtype.
2989 offset = SARMAG;
2990 if(offset == size)
2991 return(CHECK_GOOD);
2992 if(offset != size && offset + sizeof(struct ar_hdr) > size){
2993 archive_error(ofile, "truncated or malformed (archive header of "
2994 "first member extends past the end of the file)");
2995 return(CHECK_BAD);
2997 while(size > offset){
2998 ar_hdr = (struct ar_hdr *)(addr + offset);
2999 ofile->member_offset = offset;
3000 ofile->member_addr = addr + offset;
3001 ofile->member_size = strtoul(ar_hdr->ar_size, NULL, 10);
3002 ofile->member_ar_hdr = ar_hdr;
3003 ofile->member_name = ar_hdr->ar_name;
3004 ofile->member_name_size = size_ar_name(ofile->member_ar_hdr);
3005 offset += sizeof(struct ar_hdr);
3007 * See if this archive member is using extend format #1 where
3008 * the size of the name is in ar_name and the name follows the
3009 * archive header.
3011 ar_name_size = 0;
3012 if(strncmp(ofile->member_name,AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0){
3013 if(check_extend_format_1(ofile, ar_hdr, size - offset,
3014 &ar_name_size) == CHECK_BAD)
3015 return(CHECK_BAD);
3016 ofile->member_name = ar_hdr->ar_name + sizeof(struct ar_hdr);
3017 ofile->member_name_size = ar_name_size;
3018 offset += ar_name_size;
3019 ofile->member_offset += ar_name_size;
3020 ofile->member_addr += ar_name_size;
3021 ofile->member_size -= ar_name_size;
3023 big_size = rnd(ofile->member_size, sizeof(short));
3024 big_size += offset;
3025 if(big_size > size){
3026 archive_member_error(ofile, "size too large (archive "
3027 "member extends past the end of the file)");
3028 return(CHECK_BAD);
3030 if(size - offset > sizeof(uint32_t)){
3031 memcpy(&magic, addr + offset, sizeof(uint32_t));
3032 #ifdef __BIG_ENDIAN__
3033 if(magic == FAT_MAGIC)
3034 #endif /* __BIG_ENDIAN__ */
3035 #ifdef __LITTLE_ENDIAN__
3036 if(magic == SWAP_INT(FAT_MAGIC))
3037 #endif /* __LITTLE_ENDIAN__ */
3039 if(archives_with_fat_objects == FALSE ||
3040 ofile->file_type != OFILE_ARCHIVE){
3041 archive_member_error(ofile, "is a fat file (not "
3042 "allowed in an archive)");
3043 return(CHECK_BAD);
3046 else{
3047 if(size - offset >= sizeof(struct mach_header) &&
3048 (magic == MH_MAGIC || magic == SWAP_INT(MH_MAGIC))){
3049 memcpy(&mh, addr + offset, sizeof(struct mach_header));
3050 if(magic == SWAP_INT(MH_MAGIC)){
3051 magic = MH_MAGIC;
3052 swapped = TRUE;
3053 swap_mach_header(&mh, host_byte_sex);
3055 swapped = FALSE;
3057 else if(size - offset >= sizeof(struct mach_header_64) &&
3058 (magic == MH_MAGIC_64 ||
3059 magic == SWAP_INT(MH_MAGIC_64))){
3060 memcpy(&mh64, addr + offset,
3061 sizeof(struct mach_header_64));
3062 if(magic == SWAP_INT(MH_MAGIC_64)){
3063 magic = MH_MAGIC_64;
3064 swapped = TRUE;
3065 swap_mach_header_64(&mh64, host_byte_sex);
3067 swapped = FALSE;
3069 if(magic == MH_MAGIC){
3070 if(ofile->archive_cputype == 0){
3071 ofile->archive_cputype = mh.cputype;
3072 ofile->archive_cpusubtype = mh.cpusubtype;
3074 else if(ofile->archive_cputype != mh.cputype){
3075 archive_member_error(ofile, "cputype (%d) does not "
3076 "match previous archive members cputype (%d) "
3077 "(all members must match)", mh.cputype,
3078 ofile->archive_cputype);
3081 else if(magic == MH_MAGIC_64){
3082 if(ofile->archive_cputype == 0){
3083 ofile->archive_cputype = mh64.cputype;
3084 ofile->archive_cpusubtype = mh64.cpusubtype;
3086 else if(ofile->archive_cputype != mh64.cputype){
3087 archive_member_error(ofile, "cputype (%d) does not "
3088 "match previous archive members cputype (%d) "
3089 "(all members must match)", mh64.cputype,
3090 ofile->archive_cputype);
3095 offset += rnd(ofile->member_size, sizeof(short));
3097 ofile->member_offset = 0;
3098 ofile->member_addr = NULL;
3099 ofile->member_size = 0;
3100 ofile->member_ar_hdr = NULL;;
3101 ofile->member_name = NULL;
3102 ofile->member_name_size = 0;
3103 return(CHECK_GOOD);
3104 #endif /* OTOOL */
3108 * check_extend_format_1() checks the archive header for extended format #1.
3110 static
3111 enum check_type
3112 check_extend_format_1(
3113 struct ofile *ofile,
3114 struct ar_hdr *ar_hdr,
3115 uint32_t size_left,
3116 uint32_t *member_name_size)
3118 char *p, *endp, buf[sizeof(ar_hdr->ar_name)+1];
3119 uint32_t ar_name_size;
3121 *member_name_size = 0;
3123 buf[sizeof(ar_hdr->ar_name)] = '\0';
3124 memcpy(buf, ar_hdr->ar_name, sizeof(ar_hdr->ar_name));
3125 p = buf + sizeof(AR_EFMT1) - 1;
3126 if(isdigit(*p) == 0){
3127 archive_error(ofile, "malformed (ar_name: %.*s for archive "
3128 "extend format #1 starts with non-digit)",
3129 (int)sizeof(ar_hdr->ar_name), ar_hdr->ar_name);
3130 return(CHECK_BAD);
3132 ar_name_size = strtoul(p, &endp, 10);
3133 if(ar_name_size == UINT_MAX && errno == ERANGE){
3134 archive_error(ofile, "malformed (size in ar_name: %.*s for "
3135 "archive extend format #1 overflows uint32_t)",
3136 (int)sizeof(ar_hdr->ar_name), ar_hdr->ar_name);
3137 return(CHECK_BAD);
3139 while(*endp == ' ' && *endp != '\0')
3140 endp++;
3141 if(*endp != '\0'){
3142 archive_error(ofile, "malformed (size in ar_name: %.*s for "
3143 "archive extend format #1 contains non-digit and "
3144 "non-space characters)", (int)sizeof(ar_hdr->ar_name),
3145 ar_hdr->ar_name);
3146 return(CHECK_BAD);
3148 if(ar_name_size > size_left){
3149 archive_error(ofile, "truncated or malformed (archive name "
3150 "of member extends past the end of the file)");
3151 return(CHECK_BAD);
3153 *member_name_size = ar_name_size;
3154 return(CHECK_GOOD);
3158 * check_archive_toc() checks the archive table of contents referenced in the
3159 * thin archive via the ofile for correctness and if bad sets the bad_toc field
3160 * in the ofile struct to TRUE. If not it sets the other toc_* fields that
3161 * ranlib(1) uses to know it can't update the table of contents and doesn't
3162 * have to totally rebuild it. And by this always returning CHECK_GOOD it
3163 * allows otool(1) to print messed up tables of contents for debugging.
3165 static
3166 enum check_type
3167 check_archive_toc(
3168 struct ofile *ofile)
3170 uint32_t i, symdef_length, offset, nranlibs, strsize;
3171 enum byte_sex host_byte_sex, toc_byte_sex;
3172 struct ranlib *ranlibs;
3173 char *strings;
3175 ofile->toc_ranlibs = NULL;
3176 ofile->toc_nranlibs = 0;
3177 ofile->toc_strings = NULL;
3178 ofile->toc_strsize = 0;
3181 * Note this can only be called when the whole file is a thin archive.
3183 if(ofile->file_type != OFILE_ARCHIVE)
3184 return(CHECK_GOOD);
3186 symdef_length = ofile->toc_size;
3188 * The contents of a __.SYMDEF file is begins with a 32-bit word giving
3189 * the size in bytes of ranlib structures which immediately follow, and
3190 * then continues with a string table consisting of a 32-bit word giving
3191 * the number of bytes of strings which follow and then the strings
3192 * themselves. So the smallest valid size is two 32-bit words long.
3194 if(symdef_length < 2 * sizeof(uint32_t)){
3196 * Size of table of contents for archive too small to be a valid
3197 * table of contents.
3199 ofile->toc_bad = TRUE;
3200 return(CHECK_GOOD);
3202 host_byte_sex = get_host_byte_sex();
3203 toc_byte_sex = get_toc_byte_sex(ofile->file_addr, ofile->file_size);
3204 if(toc_byte_sex == UNKNOWN_BYTE_SEX){
3206 * Can't determine the byte order of table of contents as it
3207 * contains no Mach-O files.
3209 ofile->toc_bad = TRUE;
3210 return(CHECK_GOOD);
3212 offset = 0;
3213 nranlibs = *((uint32_t *)(ofile->toc_addr + offset));
3214 if(toc_byte_sex != host_byte_sex)
3215 nranlibs = SWAP_INT(nranlibs);
3216 nranlibs = nranlibs / sizeof(struct ranlib);
3217 offset += sizeof(uint32_t);
3218 ranlibs = (struct ranlib *)(ofile->toc_addr + offset);
3219 offset += sizeof(struct ranlib) * nranlibs;
3220 if(nranlibs == 0)
3221 return(CHECK_GOOD);
3222 if(offset - (2 * sizeof(uint32_t)) > symdef_length){
3224 * Truncated or malformed archive. The ranlib structures in table
3225 * of contents extends past the end of the table of contents.
3227 ofile->toc_bad = TRUE;
3228 return(CHECK_GOOD);
3230 strsize = *((uint32_t *)(ofile->toc_addr + offset));
3231 if(toc_byte_sex != host_byte_sex)
3232 strsize = SWAP_INT(strsize);
3233 offset += sizeof(uint32_t);
3234 strings = ofile->toc_addr + offset;
3235 offset += strsize;
3236 if(offset - (2 * sizeof(uint32_t)) > symdef_length){
3238 * Truncated or malformed archive. The ranlib strings in table of
3239 * contents extends past the end of the table of contents.
3241 ofile->toc_bad = TRUE;
3242 return(CHECK_GOOD);
3244 if(symdef_length == 2 * sizeof(uint32_t))
3245 return(CHECK_GOOD);
3248 * Check the string offset and the member offsets of the ranlib structs.
3250 if(toc_byte_sex != host_byte_sex)
3251 swap_ranlib(ranlibs, nranlibs, host_byte_sex);
3252 for(i = 0; i < nranlibs; i++){
3253 if(ranlibs[i].ran_un.ran_strx >= strsize){
3255 * Malformed table of contents. The ranlib struct at this index
3256 * has a bad string index field.
3258 ofile->toc_bad = TRUE;
3259 return(CHECK_GOOD);
3261 if(ranlibs[i].ran_off >= ofile->file_size){
3263 * Malformed table of contents. The ranlib struct at this index
3264 * has a bad library member offset field.
3266 ofile->toc_bad = TRUE;
3267 return(CHECK_GOOD);
3270 * These should be on 4 byte boundaries because the maximum
3271 * alignment of the header structures and relocation are 4 bytes.
3272 * But this is has to be 2 bytes because that's the way ar(1) has
3273 * worked historicly in the past. Fortunately this works on the
3274 * 68k machines but will have to change when this is on a real
3275 * machine.
3277 #if defined(mc68000) || defined(__i386__)
3278 if(ranlibs[i].ran_off % sizeof(short) != 0){
3280 * Malformed table of contents. This ranlib struct library
3281 * member offset not a multiple 2 bytes.
3283 ofile->toc_bad = TRUE;
3284 return(CHECK_GOOD);
3286 #else
3287 if(ranlibs[i].ran_off % sizeof(uint32_t) != 0){
3289 * Malformed table of contents. This ranlib struct library
3290 * member offset not a multiple of 4 bytes.
3292 ofile->toc_bad = TRUE;
3293 return(CHECK_GOOD);
3295 #endif
3297 ofile->toc_ranlibs = ranlibs;
3298 ofile->toc_nranlibs = nranlibs;
3299 ofile->toc_strings = strings;
3300 ofile->toc_strsize = strsize;
3301 return(CHECK_GOOD);
3305 * check_Mach_O() checks the object file's mach header and load commands
3306 * referenced in the ofile for correctness (this also swaps the mach header
3307 * and load commands into the host byte sex if needed).
3309 static
3310 enum check_type
3311 check_Mach_O(
3312 struct ofile *ofile)
3314 #ifdef OTOOL
3315 return(CHECK_GOOD);
3316 #else /* !defined OTOOL */
3317 uint32_t size, i, j, ncmds, sizeofcmds, load_command_multiple, sizeofhdrs;
3318 cpu_type_t cputype;
3319 char *addr, *cmd_name;
3320 enum byte_sex host_byte_sex;
3321 enum bool swapped;
3322 struct mach_header *mh;
3323 struct mach_header_64 *mh64;
3324 struct load_command *load_commands, *lc, l;
3325 struct segment_command *sg;
3326 struct segment_command_64 *sg64;
3327 struct section *s;
3328 struct section_64 *s64;
3329 struct symtab_command *st;
3330 struct dysymtab_command *dyst;
3331 struct symseg_command *ss;
3332 struct fvmlib_command *fl;
3333 struct dylib_command *dl;
3334 struct sub_framework_command *sub;
3335 struct sub_umbrella_command *usub;
3336 struct sub_library_command *lsub;
3337 struct sub_client_command *csub;
3338 struct prebound_dylib_command *pbdylib;
3339 struct dylinker_command *dyld;
3340 struct thread_command *ut;
3341 struct ident_command *id;
3342 struct routines_command *rc;
3343 struct routines_command_64 *rc64;
3344 struct twolevel_hints_command *hints;
3345 struct linkedit_data_command *code_sig, *split_info, *func_starts;
3346 struct version_min_command *vers;
3347 struct prebind_cksum_command *cs;
3348 struct encryption_info_command *encrypt_info;
3349 struct dyld_info_command *dyld_info;
3350 struct uuid_command *uuid;
3351 struct rpath_command *rpath;
3352 uint32_t flavor, count, nflavor;
3353 char *p, *state;
3354 uint32_t sizeof_nlist, sizeof_dylib_module;
3355 char *struct_dylib_module_name, *struct_nlist_name;
3356 uint64_t big_size, big_end, big_load_end;
3357 struct element elements;
3359 elements.offset = 0;
3360 elements.size = 0;
3361 elements.name = NULL;
3362 elements.next = NULL;
3364 addr = ofile->object_addr;
3365 size = ofile->object_size;
3366 mh = ofile->mh;
3367 mh64 = ofile->mh64;
3368 load_commands = ofile->load_commands;
3369 host_byte_sex = get_host_byte_sex();
3370 swapped = (enum bool)(host_byte_sex != ofile->object_byte_sex);
3372 if(ofile->mh != NULL){
3373 if(swapped)
3374 swap_mach_header(mh, host_byte_sex);
3375 big_size = mh->sizeofcmds;
3376 big_size += sizeof(struct mach_header);
3377 if(big_size > size){
3378 Mach_O_error(ofile, "truncated or malformed object (load "
3379 "commands extend past the end of the file)");
3380 return(CHECK_BAD);
3382 sizeofhdrs = big_size;
3383 ofile->mh_cputype = mh->cputype;
3384 ofile->mh_cpusubtype = mh->cpusubtype;
3385 ofile->mh_filetype = mh->filetype;
3386 ncmds = mh->ncmds;
3387 sizeofcmds = mh->sizeofcmds;
3388 cputype = mh->cputype;
3389 load_command_multiple = 4;
3390 sizeof_nlist = sizeof(struct nlist);
3391 struct_nlist_name = "struct nlist";
3392 sizeof_dylib_module = sizeof(struct dylib_module);
3393 struct_dylib_module_name = "struct dylib_module";
3395 else{
3396 if(swapped)
3397 swap_mach_header_64(mh64, host_byte_sex);
3398 big_size = mh64->sizeofcmds;
3399 big_size += sizeof(struct mach_header_64);
3400 if(big_size > size){
3401 Mach_O_error(ofile, "truncated or malformed object (load "
3402 "commands extend past the end of the file)");
3403 return(CHECK_BAD);
3405 sizeofhdrs = big_size;
3406 ofile->mh_cputype = mh64->cputype;
3407 ofile->mh_cpusubtype = mh64->cpusubtype;
3408 ofile->mh_filetype = mh64->filetype;
3409 ncmds = mh64->ncmds;
3410 sizeofcmds = mh64->sizeofcmds;
3411 cputype = mh64->cputype;
3412 load_command_multiple = 8;
3413 sizeof_nlist = sizeof(struct nlist_64);
3414 struct_nlist_name = "struct nlist_64";
3415 sizeof_dylib_module = sizeof(struct dylib_module_64);
3416 struct_dylib_module_name = "struct dylib_module_64";
3418 if(check_overlaping_element(ofile, &elements, 0, sizeofhdrs,
3419 "Mach-O headers") == CHECK_BAD)
3420 goto return_bad;
3421 if(ofile->file_type == OFILE_FAT){
3422 if(ofile->fat_archs[ofile->narch].cputype != ofile->mh_cputype){
3423 Mach_O_error(ofile, "malformed fat file (fat header "
3424 "architecture: %u's cputype does not match "
3425 "object file's mach header)", ofile->narch);
3426 goto return_bad;
3430 * Make a pass through the load commands checking them to the level
3431 * that they can be parsed and all fields with offsets and sizes do
3432 * not extend past the end of the file.
3434 st = NULL;
3435 dyst = NULL;
3436 rc = NULL;
3437 rc64 = NULL;
3438 hints = NULL;
3439 code_sig = NULL;
3440 func_starts = NULL;
3441 split_info = NULL;
3442 cs = NULL;
3443 uuid = NULL;
3444 encrypt_info = NULL;
3445 dyld_info = NULL;
3446 vers = NULL;
3447 big_load_end = 0;
3448 for(i = 0, lc = load_commands; i < ncmds; i++){
3449 l = *lc;
3450 if(swapped)
3451 swap_load_command(&l, host_byte_sex);
3453 * Check load command size for a multiple of load_command_multiple.
3455 if(l.cmdsize % load_command_multiple != 0){
3457 * We have a hack here to allow 64-bit Mach-O core files to
3458 * have LC_THREAD commands that are only a multiple of 4 and
3459 * not 8 to be allowed since the kernel produces them.
3461 if(ofile->mh64 == NULL ||
3462 ofile->mh64->filetype != MH_CORE ||
3463 l.cmd != LC_THREAD ||
3464 l.cmdsize % 4 != 0){
3465 Mach_O_error(ofile, "malformed object (load command %u "
3466 "cmdsize not a multiple of %u)", i,
3467 load_command_multiple);
3468 goto return_bad;
3471 /* check that load command does not extends past end of commands */
3472 big_load_end += l.cmdsize;
3473 if(big_load_end > sizeofcmds){
3474 Mach_O_error(ofile, "truncated or malformed object (load "
3475 "command %u extends past the end of the file)",i);
3476 goto return_bad;
3478 /* check that the load command size is not zero */
3479 if(l.cmdsize == 0){
3480 Mach_O_error(ofile, "malformed object (load command %u cmdsize"
3481 " is zero)", i);
3482 goto return_bad;
3484 switch(l.cmd){
3485 case LC_SEGMENT:
3486 if(l.cmdsize < sizeof(struct segment_command)){
3487 Mach_O_error(ofile, "malformed object (LC_SEGMENT cmdsize "
3488 "too small) in command %u", i);
3489 goto return_bad;
3491 sg = (struct segment_command *)lc;
3492 if(swapped)
3493 swap_segment_command(sg, host_byte_sex);
3494 big_size = sg->nsects;
3495 big_size *= sizeof(struct section);
3496 big_size += sizeof(struct segment_command);
3497 if(sg->cmdsize != big_size){
3498 Mach_O_error(ofile, "malformed object (inconsistent "
3499 "cmdsize in LC_SEGMENT command %u for the "
3500 "number of sections)", i);
3501 goto return_bad;
3503 if(sg->fileoff > size){
3504 Mach_O_error(ofile, "truncated or malformed object ("
3505 "LC_SEGMENT command %u fileoff field "
3506 "extends past the end of the file)", i);
3507 goto return_bad;
3509 big_size = sg->fileoff;
3510 big_size += sg->filesize;
3511 if(big_size > size){
3512 Mach_O_error(ofile, "truncated or malformed object ("
3513 "LC_SEGMENT command %u fileoff field "
3514 "plus filesize field extends past the end of "
3515 "the file)", i);
3516 goto return_bad;
3518 if(sg->vmsize != 0 && sg->filesize > sg->vmsize){
3519 Mach_O_error(ofile, "malformed object (LC_SEGMENT command "
3520 "%u filesize field greater than vmsize field)",
3522 goto return_bad;
3524 s = (struct section *)
3525 ((char *)sg + sizeof(struct segment_command));
3526 if(swapped)
3527 swap_section(s, sg->nsects, host_byte_sex);
3528 for(j = 0 ; j < sg->nsects ; j++){
3529 if(mh->filetype != MH_DYLIB_STUB &&
3530 s->flags != S_ZEROFILL &&
3531 s->flags != S_THREAD_LOCAL_ZEROFILL && s->offset > size){
3532 Mach_O_error(ofile, "truncated or malformed object "
3533 "(offset field of section %u in LC_SEGMENT "
3534 "command %u extends past the end of the file)",
3535 j, i);
3536 goto return_bad;
3538 if(mh->filetype != MH_DYLIB_STUB &&
3539 s->flags != S_ZEROFILL &&
3540 s->flags != S_THREAD_LOCAL_ZEROFILL &&
3541 sg->fileoff == 0 && s->offset < sizeofhdrs){
3542 Mach_O_error(ofile, "malformed object (offset field of "
3543 "section %u in LC_SEGMENT command %u not "
3544 "past the headers of the file)", j, i);
3545 goto return_bad;
3547 big_size = s->offset;
3548 big_size += s->size;
3549 if(mh->filetype != MH_DYLIB_STUB &&
3550 s->flags != S_ZEROFILL &&
3551 s->flags != S_THREAD_LOCAL_ZEROFILL && big_size > size){
3552 Mach_O_error(ofile, "truncated or malformed object "
3553 "(offset field plus size field of section %u "
3554 "in LC_SEGMENT command %u extends "
3555 "past the end of the file)", j, i);
3556 goto return_bad;
3558 if(mh->filetype != MH_DYLIB_STUB &&
3559 s->flags != S_ZEROFILL &&
3560 s->flags != S_THREAD_LOCAL_ZEROFILL &&
3561 s->size > sg->filesize){
3562 Mach_O_error(ofile, "malformed object (size field of "
3563 "section %u in LC_SEGMENT command %u greater "
3564 "than the segment)", j, i);
3565 goto return_bad;
3567 if(mh->filetype != MH_DYLIB_STUB &&
3568 s->size != 0 && s->addr < sg->vmaddr){
3569 Mach_O_error(ofile, "malformed object (addr field of "
3570 "section %u in LC_SEGMENT command %u less than "
3571 "the segment's vmaddr)", j, i);
3572 goto return_bad;
3574 big_size = s->addr;
3575 big_size += s->size;
3576 big_end = sg->vmaddr;
3577 big_end += sg->vmsize;
3578 if(sg->vmsize != 0 && s->size != 0 && big_size > big_end){
3579 Mach_O_error(ofile, "malformed object (addr field plus "
3580 "size of section %u in LC_SEGMENT command %u "
3581 "greater than than the segment's vmaddr plus "
3582 "vmsize)", j, i);
3583 goto return_bad;
3585 if(mh->filetype != MH_DYLIB_STUB &&
3586 s->flags != S_ZEROFILL &&
3587 s->flags != S_THREAD_LOCAL_ZEROFILL &&
3588 check_overlaping_element(ofile, &elements, s->offset,
3589 s->size, "section contents") == CHECK_BAD)
3590 goto return_bad;
3591 if(s->reloff > size){
3592 Mach_O_error(ofile, "truncated or malformed object "
3593 "(reloff field of section %u in LC_SEGMENT "
3594 "command %u extends past the end of the file)",
3595 j, i);
3596 goto return_bad;
3598 big_size = s->nreloc;
3599 big_size *= sizeof(struct relocation_info);
3600 big_size += s->reloff;
3601 if(big_size > size){
3602 Mach_O_error(ofile, "truncated or malformed object "
3603 "(reloff field plus nreloc field times sizeof("
3604 "struct relocation_info) of section %u in "
3605 "LC_SEGMENT command %u extends past the "
3606 "end of the file)", j, i);
3607 goto return_bad;
3609 if(check_overlaping_element(ofile, &elements, s->reloff,
3610 s->nreloc * sizeof(struct relocation_info),
3611 "section relocation entries") == CHECK_BAD)
3612 goto return_bad;
3613 s++;
3615 break;
3617 case LC_SEGMENT_64:
3618 if(l.cmdsize < sizeof(struct segment_command_64)){
3619 Mach_O_error(ofile, "malformed object (LC_SEGMENT_64 "
3620 "cmdsize too small) in command %u", i);
3621 goto return_bad;
3623 sg64 = (struct segment_command_64 *)lc;
3624 if(swapped)
3625 swap_segment_command_64(sg64, host_byte_sex);
3626 big_size = sg64->nsects;
3627 big_size *= sizeof(struct section_64);
3628 big_size += sizeof(struct segment_command_64);
3629 if(sg64->cmdsize != big_size){
3630 Mach_O_error(ofile, "malformed object (inconsistent "
3631 "cmdsize in LC_SEGMENT_64 command %u for "
3632 "the number of sections)", i);
3633 goto return_bad;
3635 if(sg64->fileoff > size){
3636 Mach_O_error(ofile, "truncated or malformed object ("
3637 "LC_SEGMENT_64 command %u fileoff field "
3638 "extends past the end of the file)", i);
3639 goto return_bad;
3641 big_size = sg64->fileoff;
3642 big_size += sg64->filesize;
3643 if(big_size > size){
3644 Mach_O_error(ofile, "truncated or malformed object ("
3645 "LC_SEGMENT_64 command %u fileoff field "
3646 "plus filesize field extends past the end of "
3647 "the file)", i);
3648 goto return_bad;
3650 s64 = (struct section_64 *)
3651 ((char *)sg64 + sizeof(struct segment_command_64));
3652 if(swapped)
3653 swap_section_64(s64, sg64->nsects, host_byte_sex);
3654 for(j = 0 ; j < sg64->nsects ; j++){
3655 if(mh64->filetype != MH_DYLIB_STUB &&
3656 s64->flags != S_ZEROFILL &&
3657 s64->flags != S_THREAD_LOCAL_ZEROFILL &&
3658 s64->offset > size){
3659 Mach_O_error(ofile, "truncated or malformed object "
3660 "(offset field of section %u in LC_SEGMENT_64 "
3661 "command %u extends past the end of the file)",
3662 j, i);
3663 goto return_bad;
3665 big_size = s64->offset;
3666 big_size += s64->size;
3667 if(mh64->filetype != MH_DYLIB_STUB &&
3668 s64->flags != S_ZEROFILL &&
3669 s64->flags != S_THREAD_LOCAL_ZEROFILL &&
3670 big_size > size){
3671 Mach_O_error(ofile, "truncated or malformed object "
3672 "(offset field plus size field of section %u "
3673 "in LC_SEGMENT_64 command %u extends "
3674 "past the end of the file)", j, i);
3675 goto return_bad;
3677 if(mh64->filetype != MH_DYLIB_STUB &&
3678 s64->flags != S_ZEROFILL &&
3679 s64->flags != S_THREAD_LOCAL_ZEROFILL &&
3680 check_overlaping_element(ofile, &elements, s64->offset,
3681 s64->size, "section contents") == CHECK_BAD)
3682 goto return_bad;
3683 if(s64->reloff > size){
3684 Mach_O_error(ofile, "truncated or malformed object "
3685 "(reloff field of section %u in LC_SEGMENT_64 "
3686 "command %u extends past the end of the file)",
3687 j, i);
3688 goto return_bad;
3690 big_size = s64->nreloc;
3691 big_size *= sizeof(struct relocation_info);
3692 big_size += s64->reloff;
3693 if(big_size > size){
3694 Mach_O_error(ofile, "truncated or malformed object "
3695 "(reloff field plus nreloc field times sizeof("
3696 "struct relocation_info) of section %u in "
3697 "LC_SEGMENT_64 command %u extends past the "
3698 "end of the file)", j, i);
3699 goto return_bad;
3701 if(check_overlaping_element(ofile, &elements, s64->reloff,
3702 s64->nreloc * sizeof(struct relocation_info),
3703 "section relocation entries") == CHECK_BAD)
3704 goto return_bad;
3705 s64++;
3707 break;
3709 case LC_SYMTAB:
3710 if(l.cmdsize < sizeof(struct symtab_command)){
3711 Mach_O_error(ofile, "malformed object (LC_SYMTAB cmdsize "
3712 "too small) in command %u", i);
3713 goto return_bad;
3715 if(st != NULL){
3716 Mach_O_error(ofile, "malformed object (more than one "
3717 "LC_SYMTAB command)");
3718 goto return_bad;
3720 st = (struct symtab_command *)lc;
3721 if(swapped)
3722 swap_symtab_command(st, host_byte_sex);
3723 if(st->cmdsize != sizeof(struct symtab_command)){
3724 Mach_O_error(ofile, "malformed object (LC_SYMTAB command "
3725 "%u has incorrect cmdsize)", i);
3726 goto return_bad;
3728 if(st->symoff > size){
3729 Mach_O_error(ofile, "truncated or malformed object (symoff "
3730 "field of LC_SYMTAB command %u extends past the end "
3731 "of the file)", i);
3732 goto return_bad;
3734 big_size = st->nsyms;
3735 big_size *= sizeof_nlist;
3736 big_size += st->symoff;
3737 if(big_size > size){
3738 Mach_O_error(ofile, "truncated or malformed object (symoff "
3739 "field plus nsyms field times sizeof(%s) of LC_SYMTAB "
3740 "command %u extends past the end of the file)",
3741 struct_nlist_name, i);
3742 goto return_bad;
3744 if(check_overlaping_element(ofile, &elements, st->symoff,
3745 st->nsyms * sizeof_nlist, "symbol table") == CHECK_BAD)
3746 goto return_bad;
3747 if(st->stroff > size){
3748 Mach_O_error(ofile, "truncated or malformed object (stroff "
3749 "field of LC_SYMTAB command %u extends past the end "
3750 "of the file)", i);
3751 goto return_bad;
3753 big_size = st->stroff;
3754 big_size += st->strsize;
3755 if(big_size > size){
3756 Mach_O_error(ofile, "truncated or malformed object (stroff "
3757 "field plus strsize field of LC_SYMTAB command %u "
3758 "extends past the end of the file)", i);
3759 goto return_bad;
3761 if(check_overlaping_element(ofile, &elements, st->stroff,
3762 st->strsize, "string table") == CHECK_BAD)
3763 goto return_bad;
3764 break;
3766 case LC_DYSYMTAB:
3767 if(l.cmdsize < sizeof(struct dysymtab_command)){
3768 Mach_O_error(ofile, "malformed object (LC_DYSYMTAB cmdsize "
3769 "too small) in command %u", i);
3770 goto return_bad;
3772 if(dyst != NULL){
3773 Mach_O_error(ofile, "malformed object (more than one "
3774 "LC_DYSYMTAB command)");
3775 goto return_bad;
3777 dyst = (struct dysymtab_command *)lc;
3778 if(swapped)
3779 swap_dysymtab_command(dyst, host_byte_sex);
3780 if(dyst->cmdsize != sizeof(struct dysymtab_command)){
3781 Mach_O_error(ofile, "malformed object (LC_DYSYMTAB command "
3782 "%u has incorrect cmdsize)", i);
3783 goto return_bad;
3785 if(dyst->tocoff > size){
3786 Mach_O_error(ofile, "truncated or malformed object (tocoff "
3787 "field of LC_DYSYMTAB command %u extends past the end "
3788 "of the file)", i);
3789 goto return_bad;
3791 big_size = dyst->ntoc;
3792 big_size *= sizeof(struct dylib_table_of_contents);
3793 big_size += dyst->tocoff;
3794 if(big_size > size){
3795 Mach_O_error(ofile, "truncated or malformed object (tocoff "
3796 "field plus ntoc field times sizeof(struct dylib_table"
3797 "_of_contents) of LC_DYSYMTAB command %u extends past "
3798 "the end of the file)", i);
3799 goto return_bad;
3801 if(check_overlaping_element(ofile, &elements, dyst->tocoff,
3802 dyst->ntoc * sizeof(struct dylib_table_of_contents),
3803 "table of contents") == CHECK_BAD)
3804 goto return_bad;
3805 if(dyst->modtaboff > size){
3806 Mach_O_error(ofile, "truncated or malformed object "
3807 "(modtaboff field of LC_DYSYMTAB command %u extends "
3808 "past the end of the file)", i);
3809 goto return_bad;
3811 big_size = dyst->nmodtab;
3812 big_size *= sizeof_dylib_module;
3813 big_size += dyst->modtaboff;
3814 if(big_size > size){
3815 Mach_O_error(ofile, "truncated or malformed object "
3816 "(modtaboff field plus nmodtab field times sizeof(%s) "
3817 "of LC_DYSYMTAB command %u extends past the end of "
3818 "the file)", struct_dylib_module_name, i);
3819 goto return_bad;
3821 if(check_overlaping_element(ofile, &elements, dyst->modtaboff,
3822 dyst->nmodtab * sizeof_dylib_module, "module table") ==
3823 CHECK_BAD)
3824 goto return_bad;
3825 if(dyst->extrefsymoff > size){
3826 Mach_O_error(ofile, "truncated or malformed object "
3827 "(extrefsymoff field of LC_DYSYMTAB command %u "
3828 "extends past the end of the file)", i);
3829 goto return_bad;
3831 big_size = dyst->nextrefsyms;
3832 big_size *= sizeof(struct dylib_reference);
3833 big_size += dyst->extrefsymoff;
3834 if(big_size > size){
3835 Mach_O_error(ofile, "truncated or malformed object "
3836 "(extrefsymoff field plus nextrefsyms field times "
3837 "sizeof(struct dylib_reference) of LC_DYSYMTAB command "
3838 "%u extends past the end of the file)", i);
3839 goto return_bad;
3841 if(check_overlaping_element(ofile, &elements,dyst->extrefsymoff,
3842 dyst->nextrefsyms * sizeof(struct dylib_reference),
3843 "reference table") == CHECK_BAD)
3844 goto return_bad;
3845 if(dyst->indirectsymoff > size){
3846 Mach_O_error(ofile, "truncated or malformed object "
3847 "(indirectsymoff field of LC_DYSYMTAB command %u "
3848 "extends past the end of the file)", i);
3849 goto return_bad;
3851 big_size = dyst->nindirectsyms;
3852 big_size *= sizeof(uint32_t);
3853 big_size += dyst->indirectsymoff;
3854 if(big_size > size){
3855 Mach_O_error(ofile, "truncated or malformed object "
3856 "(indirectsymoff field plus nindirectsyms field times "
3857 "sizeof(uint32_t) of LC_DYSYMTAB command "
3858 "%u extends past the end of the file)", i);
3859 goto return_bad;
3861 if(check_overlaping_element(ofile, &elements,
3862 dyst->indirectsymoff, dyst->nindirectsyms *
3863 sizeof(uint32_t), "indirect table") == CHECK_BAD)
3864 goto return_bad;
3865 if(dyst->extreloff > size){
3866 Mach_O_error(ofile, "truncated or malformed object "
3867 "(extreloff field of LC_DYSYMTAB command %u "
3868 "extends past the end of the file)", i);
3869 goto return_bad;
3871 big_size = dyst->nextrel;
3872 big_size *= sizeof(struct relocation_info);
3873 big_size += dyst->extreloff;
3874 if(big_size > size){
3875 Mach_O_error(ofile, "truncated or malformed object "
3876 "(extreloff field plus nextrel field times "
3877 "sizeof(struct relocation_info) of LC_DYSYMTAB command "
3878 "%u extends past the end of the file)", i);
3879 goto return_bad;
3881 if(check_overlaping_element(ofile, &elements, dyst->extreloff,
3882 dyst->nextrel * sizeof(struct relocation_info),
3883 "external relocation table") == CHECK_BAD)
3884 goto return_bad;
3885 if(dyst->locreloff > size){
3886 Mach_O_error(ofile, "truncated or malformed object "
3887 "(locreloff field of LC_DYSYMTAB command %u "
3888 "extends past the end of the file)", i);
3889 goto return_bad;
3891 big_size = dyst->nlocrel;
3892 big_size *= sizeof(struct relocation_info);
3893 big_size += dyst->locreloff;
3894 if(big_size > size){
3895 Mach_O_error(ofile, "truncated or malformed object "
3896 "(locreloff field plus nlocrel field times "
3897 "sizeof(struct relocation_info) of LC_DYSYMTAB command "
3898 "%u extends past the end of the file)", i);
3899 goto return_bad;
3901 if(check_overlaping_element(ofile, &elements, dyst->locreloff,
3902 dyst->nlocrel * sizeof(struct relocation_info),
3903 "local relocation table") == CHECK_BAD)
3904 goto return_bad;
3905 break;
3907 case LC_ROUTINES:
3908 if(l.cmdsize < sizeof(struct routines_command)){
3909 Mach_O_error(ofile, "malformed object (LC_ROUTINES cmdsize "
3910 "too small) in command %u", i);
3911 goto return_bad;
3913 if(rc != NULL){
3914 Mach_O_error(ofile, "malformed object (more than one "
3915 "LC_ROUTINES command)");
3916 goto return_bad;
3918 rc = (struct routines_command *)lc;
3919 if(swapped)
3920 swap_routines_command(rc, host_byte_sex);
3921 if(rc->cmdsize != sizeof(struct routines_command)){
3922 Mach_O_error(ofile, "malformed object (LC_ROUTINES "
3923 "command %u has incorrect cmdsize)", i);
3924 goto return_bad;
3926 break;
3928 case LC_ROUTINES_64:
3929 if(l.cmdsize < sizeof(struct routines_command_64)){
3930 Mach_O_error(ofile, "malformed object (LC_ROUTINES_64 "
3931 "cmdsize too small) in command %u", i);
3932 goto return_bad;
3934 if(rc64 != NULL){
3935 Mach_O_error(ofile, "malformed object (more than one "
3936 "LC_ROUTINES_64 command)");
3937 goto return_bad;
3939 rc64 = (struct routines_command_64 *)lc;
3940 if(swapped)
3941 swap_routines_command_64(rc64, host_byte_sex);
3942 if(rc64->cmdsize != sizeof(struct routines_command_64)){
3943 Mach_O_error(ofile, "malformed object (LC_ROUTINES_64 "
3944 "command %u has incorrect cmdsize)", i);
3945 goto return_bad;
3947 break;
3949 case LC_TWOLEVEL_HINTS:
3950 if(l.cmdsize < sizeof(struct twolevel_hints_command)){
3951 Mach_O_error(ofile, "malformed object (LC_TWOLEVEL_HINTS "
3952 "cmdsize too small) in command %u", i);
3953 goto return_bad;
3955 if(hints != NULL){
3956 Mach_O_error(ofile, "malformed object (more than one "
3957 "LC_TWOLEVEL_HINTS command)");
3958 goto return_bad;
3960 hints = (struct twolevel_hints_command *)lc;
3961 if(swapped)
3962 swap_twolevel_hints_command(hints, host_byte_sex);
3963 if(hints->cmdsize != sizeof(struct twolevel_hints_command)){
3964 Mach_O_error(ofile, "malformed object (LC_TWOLEVEL_HINTS "
3965 "command %u has incorrect cmdsize)", i);
3966 goto return_bad;
3968 if(hints->offset > size){
3969 Mach_O_error(ofile, "truncated or malformed object "
3970 "(offset field of LC_TWOLEVEL_HINTS command %u "
3971 "extends past the end of the file)", i);
3972 goto return_bad;
3974 big_size = hints->nhints;
3975 big_size *= sizeof(struct twolevel_hint);
3976 big_size += hints->offset;
3977 if(big_size > size){
3978 Mach_O_error(ofile, "truncated or malformed object "
3979 "(offset field plus nhints field times "
3980 "sizeof(struct twolevel_hint) of LC_TWOLEVEL_HINTS "
3981 " command %u extends past the end of the file)", i);
3982 goto return_bad;
3984 if(check_overlaping_element(ofile, &elements, hints->offset,
3985 hints->nhints * sizeof(struct twolevel_hint),
3986 "two level hints") == CHECK_BAD)
3987 goto return_bad;
3988 break;
3990 case LC_CODE_SIGNATURE:
3991 if(l.cmdsize < sizeof(struct linkedit_data_command)){
3992 Mach_O_error(ofile, "malformed object (LC_CODE_SIGNATURE "
3993 "cmdsize too small) in command %u", i);
3994 goto return_bad;
3996 if(code_sig != NULL){
3997 Mach_O_error(ofile, "malformed object (more than one "
3998 "LC_CODE_SIGNATURE command)");
3999 goto return_bad;
4001 code_sig = (struct linkedit_data_command *)lc;
4002 if(swapped)
4003 swap_linkedit_data_command(code_sig, host_byte_sex);
4004 if(code_sig->cmdsize != sizeof(struct linkedit_data_command)){
4005 Mach_O_error(ofile, "malformed object (LC_CODE_SIGNATURE "
4006 "command %u has incorrect cmdsize)", i);
4007 goto return_bad;
4009 if(code_sig->dataoff > size){
4010 Mach_O_error(ofile, "truncated or malformed object "
4011 "(dataoff field of LC_CODE_SIGNATURE command %u "
4012 "extends past the end of the file)", i);
4013 goto return_bad;
4015 big_size = code_sig->dataoff;
4016 big_size += code_sig->datasize;
4017 if(big_size > size){
4018 Mach_O_error(ofile, "truncated or malformed object "
4019 "(dataoff field plus datasize field of "
4020 "LC_CODE_SIGNATURE command %u extends past the end of "
4021 "the file)", i);
4022 goto return_bad;
4024 if(check_overlaping_element(ofile, &elements, code_sig->dataoff,
4025 code_sig->datasize, "code signature data") == CHECK_BAD)
4026 goto return_bad;
4027 break;
4029 case LC_SEGMENT_SPLIT_INFO:
4030 if(l.cmdsize < sizeof(struct linkedit_data_command)){
4031 Mach_O_error(ofile, "malformed object (LC_SEGMENT_SPLIT_"
4032 "INFO cmdsize too small) in command %u", i);
4033 goto return_bad;
4035 if(split_info != NULL){
4036 Mach_O_error(ofile, "malformed object (more than one "
4037 "LC_SEGMENT_SPLIT_INFO command)");
4038 goto return_bad;
4040 split_info = (struct linkedit_data_command *)lc;
4041 if(swapped)
4042 swap_linkedit_data_command(split_info, host_byte_sex);
4043 if(split_info->cmdsize != sizeof(struct linkedit_data_command)){
4044 Mach_O_error(ofile, "malformed object (LC_SEGMENT_SPLIT_"
4045 "INFO command %u has incorrect cmdsize)", i);
4046 goto return_bad;
4048 if(split_info->dataoff > size){
4049 Mach_O_error(ofile, "truncated or malformed object "
4050 "(dataoff field of LC_SEGMENT_SPLIT_INFO command %u "
4051 "extends past the end of the file)", i);
4052 goto return_bad;
4054 big_size = split_info->dataoff;
4055 big_size += split_info->datasize;
4056 if(big_size > size){
4057 Mach_O_error(ofile, "truncated or malformed object "
4058 "(dataoff field plus datasize field of LC_SEGMENT_"
4059 "SPLIT_INFO command %u extends past the end of "
4060 "the file)", i);
4061 goto return_bad;
4063 if((split_info->datasize % load_command_multiple) != 0){
4064 Mach_O_error(ofile, "truncated or malformed object "
4065 "(datasize field of LC_SEGMENT_SPLIT_INFO command %u "
4066 "is not a multple of %u)", i, load_command_multiple);
4067 goto return_bad;
4069 if(check_overlaping_element(ofile, &elements,
4070 split_info->dataoff, split_info->datasize,
4071 "split info data") == CHECK_BAD)
4072 goto return_bad;
4073 break;
4075 case LC_FUNCTION_STARTS:
4076 if(l.cmdsize < sizeof(struct linkedit_data_command)){
4077 Mach_O_error(ofile, "malformed object (LC_FUNCTION_STARTS "
4078 "cmdsize too small) in command %u", i);
4079 goto return_bad;
4081 if(func_starts != NULL){
4082 Mach_O_error(ofile, "malformed object (more than one "
4083 "LC_FUNCTION_STARTS command)");
4084 goto return_bad;
4086 func_starts = (struct linkedit_data_command *)lc;
4087 if(swapped)
4088 swap_linkedit_data_command(func_starts, host_byte_sex);
4089 if(func_starts->cmdsize !=
4090 sizeof(struct linkedit_data_command)){
4091 Mach_O_error(ofile, "malformed object (LC_FUNCTION_STARTS "
4092 "command %u has incorrect cmdsize)", i);
4093 goto return_bad;
4095 if(func_starts->dataoff > size){
4096 Mach_O_error(ofile, "truncated or malformed object "
4097 "(dataoff field of LC_FUNCTION_STARTS command %u "
4098 "extends past the end of the file)", i);
4099 goto return_bad;
4101 big_size = func_starts->dataoff;
4102 big_size += func_starts->datasize;
4103 if(big_size > size){
4104 Mach_O_error(ofile, "truncated or malformed object "
4105 "(dataoff field plus datasize field of "
4106 "LC_FUNCTION_STARTS command %u extends past the end of "
4107 "the file)", i);
4108 goto return_bad;
4110 if(check_overlaping_element(ofile, &elements,
4111 func_starts->dataoff, func_starts->datasize,
4112 "function starts data") == CHECK_BAD)
4113 goto return_bad;
4114 break;
4116 case LC_VERSION_MIN_MACOSX:
4117 if(l.cmdsize < sizeof(struct version_min_command)){
4118 Mach_O_error(ofile, "malformed object (LC_VERSION_MIN_"
4119 "MACOSX cmdsize too small) in command %u", i);
4120 goto return_bad;
4122 if(vers != NULL){
4123 Mach_O_error(ofile, "malformed object (more than one "
4124 "LC_VERSION_MIN_IPHONEOS or LC_VERSION_MIN_MACOSX "
4125 "command)");
4126 goto return_bad;
4128 vers = (struct version_min_command *)lc;
4129 if(swapped)
4130 swap_version_min_command(vers, host_byte_sex);
4131 if(vers->cmdsize < sizeof(struct version_min_command)){
4132 Mach_O_error(ofile, "malformed object (LC_VERSION_MIN_"
4133 "MACOSX command %u has too small cmdsize field)", i);
4134 goto return_bad;
4136 break;
4138 case LC_VERSION_MIN_IPHONEOS:
4139 if(l.cmdsize < sizeof(struct version_min_command)){
4140 Mach_O_error(ofile, "malformed object (LC_VERSION_MIN_"
4141 "IPHONEOS cmdsize too small) in command %u",i);
4142 goto return_bad;
4144 if(vers != NULL){
4145 Mach_O_error(ofile, "malformed object (more than one "
4146 "LC_VERSION_MIN_IPHONEOS or LC_VERSION_MIN_MACOSX "
4147 "command)");
4148 goto return_bad;
4150 vers = (struct version_min_command *)lc;
4151 if(swapped)
4152 swap_version_min_command(vers, host_byte_sex);
4153 if(vers->cmdsize < sizeof(struct version_min_command)){
4154 Mach_O_error(ofile, "malformed object (LC_VERSION_MIN_"
4155 "IPHONEOS command %u has too small cmdsize field)", i);
4156 goto return_bad;
4158 break;
4160 case LC_ENCRYPTION_INFO:
4161 if(l.cmdsize < sizeof(struct encryption_info_command)){
4162 Mach_O_error(ofile, "malformed object (LC_ENCRYPTION_INFO "
4163 "cmdsize too small) in command %u", i);
4164 goto return_bad;
4166 encrypt_info = (struct encryption_info_command *)lc;
4167 if(swapped)
4168 swap_encryption_command(encrypt_info, host_byte_sex);
4169 if(encrypt_info->cmdsize !=
4170 sizeof(struct encryption_info_command)){
4171 Mach_O_error(ofile, "malformed object (LC_ENCRYPTION_INFO"
4172 "command %u has incorrect cmdsize)", i);
4173 goto return_bad;
4175 if(encrypt_info->cryptoff > size){
4176 Mach_O_error(ofile, "truncated or malformed object (cryptoff "
4177 "field of LC_ENCRYPTION_INFO command %u extends "
4178 "past the end of the file)", i);
4179 goto return_bad;
4181 big_size = encrypt_info->cryptoff;
4182 big_size += encrypt_info->cryptsize;
4183 if(big_size > size){
4184 Mach_O_error(ofile, "truncated or malformed object "
4185 "(cryptoff field plus cryptsize field of "
4186 "LC_ENCRYPTION_INFO command %u extends past "
4187 "the end of the file)", i);
4188 goto return_bad;
4190 break;
4192 case LC_DYLD_INFO:
4193 case LC_DYLD_INFO_ONLY:
4194 if(l.cmdsize < sizeof(struct dyld_info_command)){
4195 Mach_O_error(ofile, "malformed object (%s cmdsize "
4196 "too small) in command %u", l.cmd ==
4197 LC_DYLD_INFO ? "LC_DYLD_INFO" :
4198 "LC_DYLD_INFO_ONLY", i);
4199 goto return_bad;
4201 dyld_info = (struct dyld_info_command *)lc;
4202 if(swapped)
4203 swap_dyld_info_command(dyld_info, host_byte_sex);
4204 if(dyld_info->cmdsize !=
4205 sizeof(struct dyld_info_command)){
4206 Mach_O_error(ofile, "malformed object (LC_DYLD_INFO"
4207 "command %u has incorrect cmdsize)", i);
4208 goto return_bad;
4210 if(dyld_info->rebase_off != 0 && dyld_info->rebase_off > size){
4211 Mach_O_error(ofile, "truncated or malformed object "
4212 "(rebase_off field of LC_DYLD_INFO command %u "
4213 "extends past the end of the file)", i);
4214 goto return_bad;
4216 if(dyld_info->rebase_off != 0){
4217 big_size = dyld_info->rebase_off;
4218 big_size += dyld_info->rebase_size;
4219 if(big_size > size){
4220 Mach_O_error(ofile, "truncated or malformed object "
4221 "(rebase_off plus rebase_size of LC_DYLD_INFO "
4222 "command %u extends past the end of the file)", i);
4223 goto return_bad;
4226 if(check_overlaping_element(ofile, &elements,
4227 dyld_info->rebase_off, dyld_info->rebase_size,
4228 "dyld rebase info") == CHECK_BAD)
4229 goto return_bad;
4230 if(dyld_info->bind_off != 0 && dyld_info->bind_off > size){
4231 Mach_O_error(ofile, "truncated or malformed object "
4232 "(bind_off field of LC_DYLD_INFO command %u "
4233 "extends past the end of the file)", i);
4234 goto return_bad;
4236 if(dyld_info->bind_off != 0){
4237 big_size = dyld_info->bind_off;
4238 big_size += dyld_info->bind_size;
4239 if(big_size > size){
4240 Mach_O_error(ofile, "truncated or malformed object "
4241 "(bind_off plus bind_size of LC_DYLD_INFO command "
4242 "%u extends past the end of the file)", i);
4243 goto return_bad;
4246 if(check_overlaping_element(ofile, &elements,
4247 dyld_info->bind_off, dyld_info->bind_size,
4248 "dyld bind info") == CHECK_BAD)
4249 goto return_bad;
4250 if(dyld_info->weak_bind_off != 0 &&
4251 dyld_info->weak_bind_off > size){
4252 Mach_O_error(ofile, "truncated or malformed object "
4253 "(weak_bind_off field of LC_DYLD_INFO command %u "
4254 "extends past the end of the file)", i);
4255 goto return_bad;
4257 if(dyld_info->weak_bind_off != 0){
4258 big_size = dyld_info->weak_bind_off;
4259 big_size += dyld_info->weak_bind_size;
4260 if(big_size > size){
4261 Mach_O_error(ofile, "truncated or malformed object "
4262 "(weak_bind_off plus weak_bind_size of LC_DYLD_INFO"
4263 " command %u extends past the end of the file)", i);
4264 goto return_bad;
4267 if(check_overlaping_element(ofile, &elements,
4268 dyld_info->weak_bind_off, dyld_info->weak_bind_size,
4269 "dyld bind info") == CHECK_BAD)
4270 goto return_bad;
4271 if(dyld_info->lazy_bind_off != 0 &&
4272 dyld_info->lazy_bind_off > size){
4273 Mach_O_error(ofile, "truncated or malformed object "
4274 "(lazy_bind_off field of LC_DYLD_INFO command %u "
4275 "extends past the end of the file)", i);
4276 goto return_bad;
4278 if(dyld_info->lazy_bind_off != 0){
4279 big_size = dyld_info->lazy_bind_off;
4280 big_size += dyld_info->lazy_bind_size;
4281 if(big_size > size){
4282 Mach_O_error(ofile, "truncated or malformed object "
4283 "(lazy_bind_off plus lazy_bind_size of LC_DYLD_INFO"
4284 " command %u extends past the end of the file)", i);
4285 goto return_bad;
4288 if(check_overlaping_element(ofile, &elements,
4289 dyld_info->lazy_bind_off, dyld_info->lazy_bind_size,
4290 "dyld lazy bind info") == CHECK_BAD)
4291 goto return_bad;
4292 if(dyld_info->export_off != 0 && dyld_info->export_off > size){
4293 Mach_O_error(ofile, "truncated or malformed object "
4294 "(export_off field of LC_DYLD_INFO command %u "
4295 "extends past the end of the file)", i);
4296 goto return_bad;
4298 if(dyld_info->export_off != 0){
4299 big_size = dyld_info->export_off;
4300 big_size += dyld_info->export_size;
4301 if(big_size > size){
4302 Mach_O_error(ofile, "truncated or malformed object "
4303 "(export_off plus export_size of LC_DYLD_INFO "
4304 "command %u extends past the end of the file)", i);
4305 goto return_bad;
4308 if(check_overlaping_element(ofile, &elements,
4309 dyld_info->export_off, dyld_info->export_size,
4310 "dyld export info") == CHECK_BAD)
4311 goto return_bad;
4312 break;
4316 case LC_PREBIND_CKSUM:
4317 if(l.cmdsize < sizeof(struct prebind_cksum_command)){
4318 Mach_O_error(ofile, "malformed object (LC_PREBIND_CKSUM "
4319 "cmdsize too small) in command %u", i);
4320 goto return_bad;
4322 if(cs != NULL){
4323 Mach_O_error(ofile, "malformed object (more than one "
4324 "LC_PREBIND_CKSUM command)");
4325 goto return_bad;
4327 cs = (struct prebind_cksum_command *)lc;
4328 if(swapped)
4329 swap_prebind_cksum_command(cs, host_byte_sex);
4330 if(cs->cmdsize != sizeof(struct prebind_cksum_command)){
4331 Mach_O_error(ofile, "malformed object (LC_PREBIND_CKSUM "
4332 "command %u has incorrect cmdsize)", i);
4333 goto return_bad;
4335 break;
4337 case LC_UUID:
4338 if(l.cmdsize < sizeof(struct uuid_command)){
4339 Mach_O_error(ofile, "malformed object (LC_UUID cmdsize "
4340 "too small) in command %u", i);
4341 goto return_bad;
4343 if(uuid != NULL){
4344 Mach_O_error(ofile, "malformed object (more than one "
4345 "LC_UUID command)");
4346 goto return_bad;
4348 uuid = (struct uuid_command *)lc;
4349 if(swapped)
4350 swap_uuid_command(uuid, host_byte_sex);
4351 if(uuid->cmdsize != sizeof(struct uuid_command)){
4352 Mach_O_error(ofile, "malformed object (LC_UUID command %u " "has incorrect cmdsize)", i);
4353 goto return_bad;
4355 break;
4357 case LC_SYMSEG:
4358 if(l.cmdsize < sizeof(struct symseg_command)){
4359 Mach_O_error(ofile, "malformed object (LC_SYMSEG cmdsize "
4360 "too small) in command %u", i);
4361 goto return_bad;
4363 ss = (struct symseg_command *)lc;
4364 if(swapped)
4365 swap_symseg_command(ss, host_byte_sex);
4366 if(ss->cmdsize != sizeof(struct symseg_command)){
4367 Mach_O_error(ofile, "malformed object (LC_SYMSEG command "
4368 "%u has incorrect cmdsize)", i);
4369 goto return_bad;
4371 if(ss->offset > size){
4372 Mach_O_error(ofile, "truncated or malformed object (offset "
4373 "field of LC_SYMSEG command %u extends past the end "
4374 "of the file)", i);
4375 goto return_bad;
4377 big_size = ss->offset;
4378 big_size += ss->size;
4379 if(big_size > size){
4380 Mach_O_error(ofile, "truncated or malformed object (offset "
4381 "field plus size field of LC_SYMTAB command %u "
4382 "extends past the end of the file)", i);
4383 goto return_bad;
4385 if(check_overlaping_element(ofile, &elements, ss->offset,
4386 ss->size, "symseg info") == CHECK_BAD)
4387 goto return_bad;
4388 break;
4390 case LC_IDFVMLIB:
4391 case LC_LOADFVMLIB:
4392 if(l.cmdsize < sizeof(struct fvmlib_command)){
4393 Mach_O_error(ofile, "malformed object (%s cmdsize "
4394 "too small) in command %u", l.cmd ==
4395 LC_IDFVMLIB ? "LC_IDFVMLIB" :
4396 "LC_LOADFVMLIB", i);
4397 goto return_bad;
4399 fl = (struct fvmlib_command *)lc;
4400 if(swapped)
4401 swap_fvmlib_command(fl, host_byte_sex);
4402 if(fl->cmdsize < sizeof(struct fvmlib_command)){
4403 Mach_O_error(ofile, "malformed object (%s command %u has "
4404 "too small cmdsize field)", fl->cmd == LC_IDFVMLIB ?
4405 "LC_IDFVMLIB" : "LC_LOADFVMLIB", i);
4406 goto return_bad;
4408 if(fl->fvmlib.name.offset >= fl->cmdsize){
4409 Mach_O_error(ofile, "truncated or malformed object (name."
4410 "offset field of %s command %u extends past the end "
4411 "of the file)", fl->cmd == LC_IDFVMLIB ? "LC_IDFVMLIB"
4412 : "LC_LOADFVMLIB", i);
4413 goto return_bad;
4415 break;
4417 case LC_ID_DYLIB:
4418 cmd_name = "LC_ID_DYLIB";
4419 goto check_dylib_command;
4420 case LC_LOAD_DYLIB:
4421 cmd_name = "LC_LOAD_DYLIB";
4422 goto check_dylib_command;
4423 case LC_LOAD_WEAK_DYLIB:
4424 cmd_name = "LC_LOAD_WEAK_DYLIB";
4425 goto check_dylib_command;
4426 case LC_REEXPORT_DYLIB:
4427 cmd_name = "LC_REEXPORT_DYLIB";
4428 goto check_dylib_command;
4429 case LC_LOAD_UPWARD_DYLIB:
4430 cmd_name = "LC_LOAD_UPWARD_DYLIB";
4431 goto check_dylib_command;
4432 case LC_LAZY_LOAD_DYLIB:
4433 cmd_name = "LC_LAZY_LOAD_DYLIB";
4434 goto check_dylib_command;
4435 check_dylib_command:
4436 if(l.cmdsize < sizeof(struct dylib_command)){
4437 Mach_O_error(ofile, "malformed object (%s cmdsize too "
4438 "small) in command %u", cmd_name, i);
4439 goto return_bad;
4441 dl = (struct dylib_command *)lc;
4442 if(swapped)
4443 swap_dylib_command(dl, host_byte_sex);
4444 if(dl->cmdsize < sizeof(struct dylib_command)){
4445 Mach_O_error(ofile, "malformed object (%s command %u has "
4446 "too small cmdsize field)", cmd_name, i);
4447 goto return_bad;
4449 if(dl->dylib.name.offset >= dl->cmdsize){
4450 Mach_O_error(ofile, "truncated or malformed object (name."
4451 "offset field of %s command %u extends past the end "
4452 "of the file)", cmd_name, i);
4453 goto return_bad;
4455 break;
4457 case LC_SUB_FRAMEWORK:
4458 if(l.cmdsize < sizeof(struct sub_framework_command)){
4459 Mach_O_error(ofile, "malformed object (LC_SUB_FRAMEWORK "
4460 "cmdsize too small) in command %u", i);
4461 goto return_bad;
4463 sub = (struct sub_framework_command *)lc;
4464 if(swapped)
4465 swap_sub_framework_command(sub, host_byte_sex);
4466 if(sub->cmdsize < sizeof(struct sub_framework_command)){
4467 Mach_O_error(ofile, "malformed object (LC_SUB_FRAMEWORK "
4468 "command %u has too small cmdsize field)", i);
4469 goto return_bad;
4471 if(sub->umbrella.offset >= sub->cmdsize){
4472 Mach_O_error(ofile, "truncated or malformed object "
4473 "(umbrella.offset field of LC_SUB_FRAMEWORK command "
4474 "%u extends past the end of the file)", i);
4475 goto return_bad;
4477 break;
4479 case LC_SUB_UMBRELLA:
4480 if(l.cmdsize < sizeof(struct sub_umbrella_command)){
4481 Mach_O_error(ofile, "malformed object (LC_SUB_UMBRELLA "
4482 "cmdsize too small) in command %u", i);
4483 goto return_bad;
4485 usub = (struct sub_umbrella_command *)lc;
4486 if(swapped)
4487 swap_sub_umbrella_command(usub, host_byte_sex);
4488 if(usub->cmdsize < sizeof(struct sub_umbrella_command)){
4489 Mach_O_error(ofile, "malformed object (LC_SUB_UMBRELLA "
4490 "command %u has too small cmdsize field)", i);
4491 goto return_bad;
4493 if(usub->sub_umbrella.offset >= usub->cmdsize){
4494 Mach_O_error(ofile, "truncated or malformed object "
4495 "(sub_umbrella.offset field of LC_SUB_UMBRELLA command "
4496 "%u extends past the end of the file)", i);
4497 goto return_bad;
4499 break;
4501 case LC_SUB_LIBRARY:
4502 if(l.cmdsize < sizeof(struct sub_library_command)){
4503 Mach_O_error(ofile, "malformed object (LC_SUB_LIBRARY "
4504 "cmdsize too small) in command %u", i);
4505 goto return_bad;
4507 lsub = (struct sub_library_command *)lc;
4508 if(swapped)
4509 swap_sub_library_command(lsub, host_byte_sex);
4510 if(lsub->cmdsize < sizeof(struct sub_library_command)){
4511 Mach_O_error(ofile, "malformed object (LC_SUB_LIBRARY "
4512 "command %u has too small cmdsize field)", i);
4513 goto return_bad;
4515 if(lsub->sub_library.offset >= lsub->cmdsize){
4516 Mach_O_error(ofile, "truncated or malformed object "
4517 "(sub_library.offset field of LC_SUB_LIBRARY command "
4518 "%u extends past the end of the file)", i);
4519 goto return_bad;
4521 break;
4523 case LC_SUB_CLIENT:
4524 if(l.cmdsize < sizeof(struct sub_client_command)){
4525 Mach_O_error(ofile, "malformed object (LC_SUB_CLIENT "
4526 "cmdsize too small) in command %u", i);
4527 goto return_bad;
4529 csub = (struct sub_client_command *)lc;
4530 if(swapped)
4531 swap_sub_client_command(csub, host_byte_sex);
4532 if(csub->cmdsize < sizeof(struct sub_client_command)){
4533 Mach_O_error(ofile, "malformed object (LC_SUB_CLIENT "
4534 "command %u has too small cmdsize field)", i);
4535 goto return_bad;
4537 if(csub->client.offset >= csub->cmdsize){
4538 Mach_O_error(ofile, "truncated or malformed object "
4539 "(cleient.offset field of LC_SUB_CLIENT command "
4540 "%u extends past the end of the file)", i);
4541 goto return_bad;
4543 break;
4545 case LC_PREBOUND_DYLIB:
4546 if(l.cmdsize < sizeof(struct prebound_dylib_command)){
4547 Mach_O_error(ofile, "malformed object (LC_PREBOUND_DYLIB "
4548 "cmdsize too small) in command %u", i);
4549 goto return_bad;
4551 pbdylib = (struct prebound_dylib_command *)lc;
4552 if(swapped)
4553 swap_prebound_dylib_command(pbdylib, host_byte_sex);
4554 if(pbdylib->cmdsize < sizeof(struct dylib_command)){
4555 Mach_O_error(ofile, "malformed object (LC_PREBIND_DYLIB "
4556 "command %u has too small cmdsize field)", i);
4557 goto return_bad;
4559 if(pbdylib->name.offset >= pbdylib->cmdsize){
4560 Mach_O_error(ofile, "truncated or malformed object (name."
4561 "offset field of LC_PREBIND_DYLIB command %u extends "
4562 "past the end of the file)", i);
4563 goto return_bad;
4565 if(pbdylib->linked_modules.offset >= pbdylib->cmdsize){
4566 Mach_O_error(ofile, "truncated or malformed object (linked_"
4567 "modules.offset field of LC_PREBIND_DYLIB command %u "
4568 "extends past the end of the file)", i);
4569 goto return_bad;
4571 break;
4573 case LC_ID_DYLINKER:
4574 cmd_name = "LC_ID_DYLINKER";
4575 goto check_dylinker_command;
4576 case LC_LOAD_DYLINKER:
4577 cmd_name = "LC_LOAD_DYLINKER";
4578 goto check_dylinker_command;
4579 case LC_DYLD_ENVIRONMENT:
4580 cmd_name = "LC_DYLD_ENVIRONMENT";
4581 goto check_dylinker_command;
4582 check_dylinker_command:
4583 if(l.cmdsize < sizeof(struct dylinker_command)){
4584 Mach_O_error(ofile, "malformed object (%s cmdsize "
4585 "too small) in command %u", cmd_name, i);
4586 goto return_bad;
4588 dyld = (struct dylinker_command *)lc;
4589 if(swapped)
4590 swap_dylinker_command(dyld, host_byte_sex);
4591 if(dyld->cmdsize < sizeof(struct dylinker_command)){
4592 Mach_O_error(ofile, "malformed object (%s command %u has "
4593 "too small cmdsize field)", cmd_name, i);
4594 goto return_bad;
4596 if(dyld->name.offset >= dyld->cmdsize){
4597 Mach_O_error(ofile, "truncated or malformed object (name."
4598 "offset field of %s command %u extends past the end "
4599 "of the file)", cmd_name, i);
4600 goto return_bad;
4602 break;
4604 case LC_UNIXTHREAD:
4605 case LC_THREAD:
4606 if(l.cmdsize < sizeof(struct thread_command)){
4607 Mach_O_error(ofile, "malformed object (%s cmdsize "
4608 "too small) in command %u", l.cmd ==
4609 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4610 "LC_THREAD", i);
4611 goto return_bad;
4613 ut = (struct thread_command *)lc;
4614 if(swapped)
4615 swap_thread_command(ut, host_byte_sex);
4616 state = (char *)ut + sizeof(struct thread_command);
4618 if(cputype == CPU_TYPE_MC680x0){
4619 struct m68k_thread_state_regs *cpu;
4620 struct m68k_thread_state_68882 *fpu;
4621 struct m68k_thread_state_user_reg *user_reg;
4623 nflavor = 0;
4624 p = (char *)ut + ut->cmdsize;
4625 while(state < p){
4626 if(state + sizeof(uint32_t) >
4627 (char *)ut + ut->cmdsize){
4628 Mach_O_error(ofile, "malformed object (flavor in "
4629 "%s command %u extends past end of command)",
4630 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4631 "LC_THREAD", i);
4632 goto return_bad;
4634 flavor = *((uint32_t *)state);
4635 if(swapped){
4636 flavor = SWAP_INT(flavor);
4637 *((uint32_t *)state) = flavor;
4639 state += sizeof(uint32_t);
4640 if(state + sizeof(uint32_t) >
4641 (char *)ut + ut->cmdsize){
4642 Mach_O_error(ofile, "malformed object (count in "
4643 "%s command %u extends past end of command)",
4644 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4645 "LC_THREAD", i);
4646 goto return_bad;
4648 count = *((uint32_t *)state);
4649 if(swapped){
4650 count = SWAP_INT(count);
4651 *((uint32_t *)state) = count;
4653 state += sizeof(uint32_t);
4654 switch(flavor){
4655 case M68K_THREAD_STATE_REGS:
4656 if(count != M68K_THREAD_STATE_REGS_COUNT){
4657 Mach_O_error(ofile, "malformed object (count "
4658 "not M68K_THREAD_STATE_REGS_COUNT for "
4659 "flavor number %u which is a M68K_THREAD_"
4660 "STATE_REGS flavor in %s command %u)",
4661 nflavor, ut->cmd == LC_UNIXTHREAD ?
4662 "LC_UNIXTHREAD" : "LC_THREAD", i);
4663 goto return_bad;
4665 cpu = (struct m68k_thread_state_regs *)state;
4666 if(state + sizeof(struct m68k_thread_state_regs) >
4667 (char *)ut + ut->cmdsize){
4668 Mach_O_error(ofile, "malformed object ("
4669 "M68K_THREAD_STATE_REGS in %s command %u "
4670 "extends past end of command)", ut->cmd ==
4671 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4672 "LC_THREAD", i);
4673 goto return_bad;
4675 if(swapped)
4676 swap_m68k_thread_state_regs(cpu, host_byte_sex);
4677 state += sizeof(struct m68k_thread_state_regs);
4678 break;
4679 case M68K_THREAD_STATE_68882:
4680 if(count != M68K_THREAD_STATE_68882_COUNT){
4681 Mach_O_error(ofile, "malformed object (count "
4682 "not M68K_THREAD_STATE_68882_COUNT for "
4683 "flavor number %u which is a M68K_THREAD_"
4684 "STATE_68882 flavor in %s command %u)",
4685 nflavor, ut->cmd == LC_UNIXTHREAD ?
4686 "LC_UNIXTHREAD" : "LC_THREAD", i);
4687 goto return_bad;
4689 fpu = (struct m68k_thread_state_68882 *)state;
4690 if(state + sizeof(struct m68k_thread_state_68882) >
4691 (char *)ut + ut->cmdsize){
4692 Mach_O_error(ofile, "malformed object ("
4693 "M68K_THREAD_STATE_68882 in %s command %u "
4694 "extends past end of command)", ut->cmd ==
4695 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4696 "LC_THREAD", i);
4697 goto return_bad;
4699 if(swapped)
4700 swap_m68k_thread_state_68882(fpu,host_byte_sex);
4701 state += sizeof(struct m68k_thread_state_68882);
4702 break;
4703 case M68K_THREAD_STATE_USER_REG:
4704 if(count != M68K_THREAD_STATE_USER_REG_COUNT){
4705 Mach_O_error(ofile, "malformed object (count "
4706 "not M68K_THREAD_STATE_USER_REG_COUNT for "
4707 "flavor number %u which is a M68K_THREAD_"
4708 "STATE_USER_REG flavor in %s command %u)",
4709 nflavor, ut->cmd == LC_UNIXTHREAD ?
4710 "LC_UNIXTHREAD" : "LC_THREAD", i);
4711 goto return_bad;
4713 user_reg =
4714 (struct m68k_thread_state_user_reg *)state;
4715 if(state+sizeof(struct m68k_thread_state_user_reg) >
4716 (char *)ut + ut->cmdsize){
4717 Mach_O_error(ofile, "malformed object ("
4718 "M68K_THREAD_STATE_USER_REG in %s command "
4719 "%u extends past end of command)", ut->cmd==
4720 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4721 "LC_THREAD", i);
4722 goto return_bad;
4724 if(swapped)
4725 swap_m68k_thread_state_user_reg(user_reg,
4726 host_byte_sex);
4727 state += sizeof(struct m68k_thread_state_user_reg);
4728 break;
4729 default:
4730 if(swapped){
4731 Mach_O_error(ofile, "malformed object (unknown "
4732 "flavor for flavor number %u in %s command"
4733 " %u can't byte swap it)", nflavor,
4734 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4735 "LC_THREAD", i);
4736 goto return_bad;
4738 state += count * sizeof(uint32_t);
4739 break;
4741 nflavor++;
4743 break;
4745 if(cputype == CPU_TYPE_POWERPC ||
4746 cputype == CPU_TYPE_VEO){
4747 ppc_thread_state_t *nrw_cpu;
4749 nflavor = 0;
4750 p = (char *)ut + ut->cmdsize;
4751 while(state < p){
4752 if(state + sizeof(uint32_t) >
4753 (char *)ut + ut->cmdsize){
4754 Mach_O_error(ofile, "malformed object (flavor in "
4755 "%s command %u extends past end of command)",
4756 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4757 "LC_THREAD", i);
4758 goto return_bad;
4760 flavor = *((uint32_t *)state);
4761 if(swapped){
4762 flavor = SWAP_INT(flavor);
4763 *((uint32_t *)state) = flavor;
4765 state += sizeof(uint32_t);
4766 if(state + sizeof(uint32_t) >
4767 (char *)ut + ut->cmdsize){
4768 Mach_O_error(ofile, "malformed object (count in "
4769 "%s command %u extends past end of command)",
4770 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4771 "LC_THREAD", i);
4772 goto return_bad;
4774 count = *((uint32_t *)state);
4775 if(swapped){
4776 count = SWAP_INT(count);
4777 *((uint32_t *)state) = count;
4779 state += sizeof(uint32_t);
4780 switch(flavor){
4781 case PPC_THREAD_STATE:
4782 if(count != PPC_THREAD_STATE_COUNT){
4783 Mach_O_error(ofile, "malformed object (count "
4784 "not PPC_THREAD_STATE_COUNT for "
4785 "flavor number %u which is a PPC_THREAD_"
4786 "STATE flavor in %s command %u)",
4787 nflavor, ut->cmd == LC_UNIXTHREAD ?
4788 "LC_UNIXTHREAD" : "LC_THREAD", i);
4789 goto return_bad;
4791 nrw_cpu = (ppc_thread_state_t *)state;
4792 if(state + sizeof(ppc_thread_state_t) >
4793 (char *)ut + ut->cmdsize){
4794 Mach_O_error(ofile, "malformed object ("
4795 "PPC_THREAD_STATE in %s command %u extends"
4796 " past end of command)", ut->cmd ==
4797 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4798 "LC_THREAD", i);
4799 goto return_bad;
4801 if(swapped)
4802 swap_ppc_thread_state_t(nrw_cpu,
4803 host_byte_sex);
4804 state += sizeof(ppc_thread_state_t);
4805 break;
4806 default:
4807 if(swapped){
4808 Mach_O_error(ofile, "malformed object (unknown "
4809 "flavor for flavor number %u in %s command"
4810 " %u can't byte swap it)", nflavor,
4811 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4812 "LC_THREAD", i);
4813 goto return_bad;
4815 state += count * sizeof(uint32_t);
4816 break;
4818 nflavor++;
4820 break;
4822 #ifdef PPC_THREAD_STATE64_COUNT
4823 if(cputype == CPU_TYPE_POWERPC64){
4824 ppc_thread_state64_t *cpu;
4826 nflavor = 0;
4827 p = (char *)ut + ut->cmdsize;
4828 while(state < p){
4829 if(state + sizeof(uint32_t) >
4830 (char *)ut + ut->cmdsize){
4831 Mach_O_error(ofile, "malformed object (flavor in "
4832 "%s command %u extends past end of command)",
4833 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4834 "LC_THREAD", i);
4835 goto return_bad;
4837 flavor = *((uint32_t *)state);
4838 if(swapped){
4839 flavor = SWAP_INT(flavor);
4840 *((uint32_t *)state) = flavor;
4842 state += sizeof(uint32_t);
4843 if(state + sizeof(uint32_t) >
4844 (char *)ut + ut->cmdsize){
4845 Mach_O_error(ofile, "malformed object (count in "
4846 "%s command %u extends past end of command)",
4847 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4848 "LC_THREAD", i);
4849 goto return_bad;
4851 count = *((uint32_t *)state);
4852 if(swapped){
4853 count = SWAP_INT(count);
4854 *((uint32_t *)state) = count;
4856 state += sizeof(uint32_t);
4857 switch(flavor){
4858 case PPC_THREAD_STATE64:
4859 if(count != PPC_THREAD_STATE64_COUNT){
4860 Mach_O_error(ofile, "malformed object (count "
4861 "not PPC_THREAD_STATE64_COUNT for "
4862 "flavor number %u which is a PPC_THREAD_"
4863 "STATE64 flavor in %s command %u)",
4864 nflavor, ut->cmd == LC_UNIXTHREAD ?
4865 "LC_UNIXTHREAD" : "LC_THREAD", i);
4866 goto return_bad;
4868 cpu = (ppc_thread_state64_t *)state;
4869 if(state + sizeof(ppc_thread_state64_t) >
4870 (char *)ut + ut->cmdsize){
4871 Mach_O_error(ofile, "malformed object ("
4872 "PPC_THREAD_STATE64 in %s command %u "
4873 "extends past end of command)", ut->cmd ==
4874 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4875 "LC_THREAD", i);
4876 goto return_bad;
4878 if(swapped)
4879 swap_ppc_thread_state64_t(cpu, host_byte_sex);
4880 state += sizeof(ppc_thread_state64_t);
4881 break;
4882 default:
4883 if(swapped){
4884 Mach_O_error(ofile, "malformed object (unknown "
4885 "flavor for flavor number %u in %s command"
4886 " %u can't byte swap it)", nflavor,
4887 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4888 "LC_THREAD", i);
4889 goto return_bad;
4891 state += count * sizeof(uint32_t);
4892 break;
4894 nflavor++;
4896 break;
4898 #endif /* PPC_THREAD_STATE64_COUNT */
4899 if(cputype == CPU_TYPE_MC88000){
4900 m88k_thread_state_grf_t *cpu;
4901 m88k_thread_state_xrf_t *fpu;
4902 m88k_thread_state_user_t *user;
4903 m88110_thread_state_impl_t *spu;
4905 nflavor = 0;
4906 p = (char *)ut + ut->cmdsize;
4907 while(state < p){
4908 if(state + sizeof(uint32_t) >
4909 (char *)ut + ut->cmdsize){
4910 Mach_O_error(ofile, "malformed object (flavor in "
4911 "%s command %u extends past end of command)",
4912 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4913 "LC_THREAD", i);
4914 goto return_bad;
4916 flavor = *((uint32_t *)state);
4917 if(swapped){
4918 flavor = SWAP_INT(flavor);
4919 *((uint32_t *)state) = flavor;
4921 state += sizeof(uint32_t);
4922 if(state + sizeof(uint32_t) >
4923 (char *)ut + ut->cmdsize){
4924 Mach_O_error(ofile, "malformed object (count in "
4925 "%s command %u extends past end of command)",
4926 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4927 "LC_THREAD", i);
4928 goto return_bad;
4930 count = *((uint32_t *)state);
4931 if(swapped){
4932 count = SWAP_INT(count);
4933 *((uint32_t *)state) = count;
4935 state += sizeof(uint32_t);
4936 switch(flavor){
4937 case M88K_THREAD_STATE_GRF:
4938 if(count != M88K_THREAD_STATE_GRF_COUNT){
4939 Mach_O_error(ofile, "malformed object (count "
4940 "not M88K_THREAD_STATE_GRF_COUNT for "
4941 "flavor number %u which is a M88K_THREAD_"
4942 "STATE_GRF flavor in %s command %u)",
4943 nflavor, ut->cmd == LC_UNIXTHREAD ?
4944 "LC_UNIXTHREAD" : "LC_THREAD", i);
4945 goto return_bad;
4947 cpu = (m88k_thread_state_grf_t *)state;
4948 if(state + sizeof(m88k_thread_state_grf_t) >
4949 (char *)ut + ut->cmdsize){
4950 Mach_O_error(ofile, "malformed object ("
4951 "M88K_THREAD_STATE_GRF in %s command %u "
4952 "extends past end of command)", ut->cmd ==
4953 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4954 "LC_THREAD", i);
4955 goto return_bad;
4957 if(swapped)
4958 swap_m88k_thread_state_grf_t(cpu,
4959 host_byte_sex);
4960 state += sizeof(m88k_thread_state_grf_t);
4961 break;
4962 case M88K_THREAD_STATE_XRF:
4963 if(count != M88K_THREAD_STATE_XRF_COUNT){
4964 Mach_O_error(ofile, "malformed object (count "
4965 "not M88K_THREAD_STATE_XRF_COUNT for "
4966 "flavor number %u which is a M88K_THREAD_"
4967 "STATE_XRF flavor in %s command %u)",
4968 nflavor, ut->cmd == LC_UNIXTHREAD ?
4969 "LC_UNIXTHREAD" : "LC_THREAD", i);
4970 goto return_bad;
4972 fpu = (m88k_thread_state_xrf_t *)state;
4973 if(state + sizeof(m88k_thread_state_xrf_t) >
4974 (char *)ut + ut->cmdsize){
4975 Mach_O_error(ofile, "malformed object ("
4976 "M88K_THREAD_STATE_XRF in %s command %u "
4977 "extends past end of command)", ut->cmd ==
4978 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4979 "LC_THREAD", i);
4980 goto return_bad;
4982 if(swapped)
4983 swap_m88k_thread_state_xrf_t(fpu,
4984 host_byte_sex);
4985 state += sizeof(m88k_thread_state_xrf_t);
4986 break;
4987 case M88K_THREAD_STATE_USER:
4988 if(count != M88K_THREAD_STATE_USER_COUNT){
4989 Mach_O_error(ofile, "malformed object (count "
4990 "not M88K_THREAD_STATE_USER_COUNT for "
4991 "flavor number %u which is a M88K_THREAD_"
4992 "STATE_USER flavor in %s command %u)",
4993 nflavor, ut->cmd == LC_UNIXTHREAD ?
4994 "LC_UNIXTHREAD" : "LC_THREAD", i);
4995 goto return_bad;
4997 user = (m88k_thread_state_user_t *)state;
4998 if(state + sizeof(m88k_thread_state_user_t) >
4999 (char *)ut + ut->cmdsize){
5000 Mach_O_error(ofile, "malformed object ("
5001 "M88K_THREAD_STATE_USER in %s command %u "
5002 "extends past end of command)", ut->cmd ==
5003 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5004 "LC_THREAD", i);
5005 goto return_bad;
5007 if(swapped)
5008 swap_m88k_thread_state_user_t(user,
5009 host_byte_sex);
5010 state += sizeof(m88k_thread_state_user_t);
5011 break;
5012 case M88110_THREAD_STATE_IMPL:
5013 if(count != M88110_THREAD_STATE_IMPL_COUNT){
5014 Mach_O_error(ofile, "malformed object (count "
5015 "not M88110_THREAD_STATE_IMPL_COUNT for "
5016 "flavor number %u which is a M88110_THREAD"
5017 "_STATE_IMPL flavor in %s command %u)",
5018 nflavor, ut->cmd == LC_UNIXTHREAD ?
5019 "LC_UNIXTHREAD" : "LC_THREAD", i);
5020 goto return_bad;
5022 spu = (m88110_thread_state_impl_t *)state;
5023 if(state + sizeof(m88110_thread_state_impl_t) >
5024 (char *)ut + ut->cmdsize){
5025 Mach_O_error(ofile, "malformed object ("
5026 "M88110_THREAD_STATE_IMPL in %s command %u "
5027 "extends past end of command)", ut->cmd ==
5028 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5029 "LC_THREAD", i);
5030 goto return_bad;
5032 if(swapped)
5033 swap_m88110_thread_state_impl_t(spu,
5034 host_byte_sex);
5035 state += sizeof(m88110_thread_state_impl_t);
5036 break;
5037 default:
5038 if(swapped){
5039 Mach_O_error(ofile, "malformed object (unknown "
5040 "flavor for flavor number %u in %s command"
5041 " %u can't byte swap it)", nflavor,
5042 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5043 "LC_THREAD", i);
5044 goto return_bad;
5046 state += count * sizeof(uint32_t);
5047 break;
5049 nflavor++;
5051 break;
5053 if(cputype == CPU_TYPE_I860){
5054 #ifdef m68k
5055 struct i860_thread_state_regs *cpu;
5056 #endif
5058 nflavor = 0;
5059 p = (char *)ut + ut->cmdsize;
5060 while(state < p){
5061 if(state + sizeof(uint32_t) >
5062 (char *)ut + ut->cmdsize){
5063 Mach_O_error(ofile, "malformed object (flavor in "
5064 "%s command %u extends past end of command)",
5065 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5066 "LC_THREAD", i);
5067 goto return_bad;
5069 flavor = *((uint32_t *)state);
5070 if(swapped){
5071 flavor = SWAP_INT(flavor);
5072 *((uint32_t *)state) = flavor;
5074 state += sizeof(uint32_t);
5075 if(state + sizeof(uint32_t) >
5076 (char *)ut + ut->cmdsize){
5077 Mach_O_error(ofile, "malformed object (count in "
5078 "%s command %u extends past end of command)",
5079 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5080 "LC_THREAD", i);
5081 return(CHECK_BAD);
5083 count = *((uint32_t *)state);
5084 if(swapped){
5085 count = SWAP_INT(count);
5086 *((uint32_t *)state) = count;
5088 state += sizeof(uint32_t);
5089 switch(flavor){
5090 case I860_THREAD_STATE_REGS:
5091 #ifdef m68k
5092 if(count != I860_THREAD_STATE_REGS_COUNT){
5093 Mach_O_error(ofile, "malformed object (count "
5094 "not I860_THREAD_STATE_REGS_COUNT for "
5095 "flavor number %u which is a I860_THREAD_"
5096 "STATE_REGS flavor in %s command %u)",
5097 nflavor, ut->cmd == LC_UNIXTHREAD ?
5098 "LC_UNIXTHREAD" : "LC_THREAD", i);
5099 goto return_bad;
5101 cpu = (struct i860_thread_state_regs *)state;
5102 if(state + sizeof(struct i860_thread_state_regs) >
5103 (char *)ut + ut->cmdsize){
5104 Mach_O_error(ofile, "malformed object ("
5105 "I860_THREAD_STATE_REGS in %s command %u "
5106 "extends past end of command)", ut->cmd ==
5107 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5108 "LC_THREAD", i);
5109 goto return_bad;
5111 if(swapped)
5112 swap_i860_thread_state_regs(cpu, host_byte_sex);
5113 state += sizeof(struct i860_thread_state_regs);
5114 #else
5115 state += count * sizeof(int);
5116 #endif
5117 break;
5118 default:
5119 if(swapped){
5120 Mach_O_error(ofile, "malformed object (unknown "
5121 "flavor for flavor number %u in %s command"
5122 " %u can't byte swap it)", nflavor,
5123 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5124 "LC_THREAD", i);
5125 goto return_bad;
5127 state += count * sizeof(uint32_t);
5128 break;
5130 nflavor++;
5132 break;
5134 if(cputype == CPU_TYPE_I386){
5135 i386_thread_state_t *cpu;
5136 /* current i386 thread states */
5137 #if i386_THREAD_STATE == 1
5138 struct i386_float_state *fpu;
5139 i386_exception_state_t *exc;
5140 #endif /* i386_THREAD_STATE == 1 */
5142 /* i386 thread states on older releases */
5143 #if i386_THREAD_STATE == -1
5144 i386_thread_fpstate_t *fpu;
5145 i386_thread_exceptstate_t *exc;
5146 i386_thread_cthreadstate_t *user;
5147 #endif /* i386_THREAD_STATE == -1 */
5149 nflavor = 0;
5150 p = (char *)ut + ut->cmdsize;
5151 while(state < p){
5152 if(state + sizeof(uint32_t) >
5153 (char *)ut + ut->cmdsize){
5154 Mach_O_error(ofile, "malformed object (flavor in "
5155 "%s command %u extends past end of command)",
5156 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5157 "LC_THREAD", i);
5158 goto return_bad;
5160 flavor = *((uint32_t *)state);
5161 if(swapped){
5162 flavor = SWAP_INT(flavor);
5163 *((uint32_t *)state) = flavor;
5165 state += sizeof(uint32_t);
5166 if(state + sizeof(uint32_t) >
5167 (char *)ut + ut->cmdsize){
5168 Mach_O_error(ofile, "malformed object (count in "
5169 "%s command %u extends past end of command)",
5170 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5171 "LC_THREAD", i);
5172 goto return_bad;
5174 count = *((uint32_t *)state);
5175 if(swapped){
5176 count = SWAP_INT(count);
5177 *((uint32_t *)state) = count;
5179 state += sizeof(uint32_t);
5180 switch((int)flavor){
5181 case i386_THREAD_STATE:
5182 #if i386_THREAD_STATE == 1
5183 case -1:
5184 #endif /* i386_THREAD_STATE == 1 */
5185 /* i386 thread states on older releases */
5186 #if i386_THREAD_STATE == -1
5187 case 1:
5188 #endif /* i386_THREAD_STATE == -1 */
5189 if(count != i386_THREAD_STATE_COUNT){
5190 Mach_O_error(ofile, "malformed object (count "
5191 "not i386_THREAD_STATE_COUNT for flavor "
5192 "number %u which is a i386_THREAD_STATE "
5193 "flavor in %s command %u)", nflavor,
5194 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5195 "LC_THREAD", i);
5196 goto return_bad;
5198 cpu = (i386_thread_state_t *)state;
5199 if(state + sizeof(i386_thread_state_t) >
5200 (char *)ut + ut->cmdsize){
5201 Mach_O_error(ofile, "malformed object ("
5202 "i386_THREAD_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_thread_state(cpu, host_byte_sex);
5210 state += sizeof(i386_thread_state_t);
5211 break;
5212 /* current i386 thread states */
5213 #if i386_THREAD_STATE == 1
5214 case i386_FLOAT_STATE:
5215 if(count != i386_FLOAT_STATE_COUNT){
5216 Mach_O_error(ofile, "malformed object (count "
5217 "not i386_FLOAT_STATE_COUNT for flavor "
5218 "number %u which is a i386_FLOAT_STATE "
5219 "flavor in %s command %u)", nflavor,
5220 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5221 "LC_THREAD", i);
5222 goto return_bad;
5224 fpu = (struct i386_float_state *)state;
5225 if(state + sizeof(struct i386_float_state) >
5226 (char *)ut + ut->cmdsize){
5227 Mach_O_error(ofile, "malformed object ("
5228 "i386_FLOAT_STATE in %s command %u "
5229 "extends past end of command)", ut->cmd ==
5230 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5231 "LC_THREAD", i);
5232 goto return_bad;
5234 if(swapped)
5235 swap_i386_float_state(fpu, host_byte_sex);
5236 state += sizeof(struct i386_float_state);
5237 break;
5238 case i386_EXCEPTION_STATE:
5239 if(count != I386_EXCEPTION_STATE_COUNT){
5240 Mach_O_error(ofile, "malformed object (count "
5241 "not I386_EXCEPTION_STATE_COUNT for "
5242 "flavor number %u which is a i386_"
5243 "EXCEPTION_STATE flavor in %s command %u)",
5244 nflavor,
5245 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5246 "LC_THREAD", i);
5247 goto return_bad;
5249 exc = (i386_exception_state_t *)state;
5250 if(state + sizeof(i386_exception_state_t) >
5251 (char *)ut + ut->cmdsize){
5252 Mach_O_error(ofile, "malformed object ("
5253 "i386_EXCEPTION_STATE in %s command %u "
5254 "extends past end of command)", ut->cmd ==
5255 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5256 "LC_THREAD", i);
5257 goto return_bad;
5259 if(swapped)
5260 swap_i386_exception_state(exc,host_byte_sex);
5261 state += sizeof(i386_exception_state_t);
5262 break;
5263 #endif /* i386_THREAD_STATE == 1 */
5265 /* i386 thread states on older releases */
5266 #if i386_THREAD_STATE == -1
5267 case i386_THREAD_FPSTATE:
5268 if(count != i386_THREAD_FPSTATE_COUNT){
5269 Mach_O_error(ofile, "malformed object (count "
5270 "not i386_THREAD_FPSTATE_COUNT for flavor "
5271 "number %u which is a i386_THREAD_FPSTATE "
5272 "flavor in %s command %u)", nflavor,
5273 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5274 "LC_THREAD", i);
5275 goto return_bad;
5277 fpu = (i386_thread_fpstate_t *)state;
5278 if(state + sizeof(i386_thread_fpstate_t) >
5279 (char *)ut + ut->cmdsize){
5280 Mach_O_error(ofile, "malformed object ("
5281 "i386_THREAD_FPSTATE in %s command %u "
5282 "extends past end of command)", ut->cmd ==
5283 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5284 "LC_THREAD", i);
5285 goto return_bad;
5287 if(swapped)
5288 swap_i386_thread_fpstate(fpu, host_byte_sex);
5289 state += sizeof(i386_thread_fpstate_t);
5290 break;
5291 case i386_THREAD_EXCEPTSTATE:
5292 if(count != i386_THREAD_EXCEPTSTATE_COUNT){
5293 Mach_O_error(ofile, "malformed object (count "
5294 "not i386_THREAD_EXCEPTSTATE_COUNT for "
5295 "flavor number %u which is a i386_THREAD_"
5296 "EXCEPTSTATE flavor in %s command %u)",
5297 nflavor,
5298 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5299 "LC_THREAD", i);
5300 goto return_bad;
5302 exc = (i386_thread_exceptstate_t *)state;
5303 if(state + sizeof(i386_thread_exceptstate_t) >
5304 (char *)ut + ut->cmdsize){
5305 Mach_O_error(ofile, "malformed object ("
5306 "i386_THREAD_EXCEPTSTATE in %s command %u "
5307 "extends past end of command)", ut->cmd ==
5308 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5309 "LC_THREAD", i);
5310 goto return_bad;
5312 if(swapped)
5313 swap_i386_thread_exceptstate(exc,host_byte_sex);
5314 state += sizeof(i386_thread_exceptstate_t);
5315 break;
5316 case i386_THREAD_CTHREADSTATE:
5317 if(count != i386_THREAD_CTHREADSTATE_COUNT){
5318 Mach_O_error(ofile, "malformed object (count "
5319 "not i386_THREAD_CTHREADSTATE_COUNT for "
5320 "flavor number %u which is a i386_THREAD_"
5321 "CTHREADSTATE flavor in %s command %u)",
5322 nflavor,
5323 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5324 "LC_THREAD", i);
5325 goto return_bad;
5327 user = (i386_thread_cthreadstate_t *)state;
5328 if(state + sizeof(i386_thread_cthreadstate_t) >
5329 (char *)ut + ut->cmdsize){
5330 Mach_O_error(ofile, "malformed object ("
5331 "i386_THREAD_CTHREADSTATE in %s command %u "
5332 "extends past end of command)", ut->cmd ==
5333 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5334 "LC_THREAD", i);
5335 goto return_bad;
5337 if(swapped)
5338 swap_i386_thread_cthreadstate(user,
5339 host_byte_sex);
5340 state += sizeof(i386_thread_cthreadstate_t);
5341 break;
5342 #endif /* i386_THREAD_STATE == -1 */
5343 default:
5344 if(swapped){
5345 Mach_O_error(ofile, "malformed object (unknown "
5346 "flavor for flavor number %u in %s command"
5347 " %u can't byte swap it)", nflavor,
5348 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5349 "LC_THREAD", i);
5350 goto return_bad;
5352 state += count * sizeof(uint32_t);
5353 break;
5355 nflavor++;
5357 break;
5359 #ifdef x86_THREAD_STATE64_COUNT
5360 if(cputype == CPU_TYPE_X86_64){
5361 x86_thread_state64_t *cpu;
5363 nflavor = 0;
5364 p = (char *)ut + ut->cmdsize;
5365 while(state < p){
5366 if(state + sizeof(uint32_t) >
5367 (char *)ut + ut->cmdsize){
5368 Mach_O_error(ofile, "malformed object (flavor in "
5369 "%s command %u extends past end of command)",
5370 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5371 "LC_THREAD", i);
5372 goto return_bad;
5374 flavor = *((uint32_t *)state);
5375 if(swapped){
5376 flavor = SWAP_INT(flavor);
5377 *((uint32_t *)state) = flavor;
5379 state += sizeof(uint32_t);
5380 if(state + sizeof(uint32_t) >
5381 (char *)ut + ut->cmdsize){
5382 Mach_O_error(ofile, "malformed object (count in "
5383 "%s command %u extends past end of command)",
5384 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5385 "LC_THREAD", i);
5386 goto return_bad;
5388 count = *((uint32_t *)state);
5389 if(swapped){
5390 count = SWAP_INT(count);
5391 *((uint32_t *)state) = count;
5393 state += sizeof(uint32_t);
5394 switch(flavor){
5395 case x86_THREAD_STATE64:
5396 if(count != x86_THREAD_STATE64_COUNT){
5397 Mach_O_error(ofile, "malformed object (count "
5398 "not x86_THREAD_STATE64_COUNT for "
5399 "flavor number %u which is a x86_THREAD_"
5400 "STATE64 flavor in %s command %u)",
5401 nflavor, ut->cmd == LC_UNIXTHREAD ?
5402 "LC_UNIXTHREAD" : "LC_THREAD", i);
5403 goto return_bad;
5405 cpu = (x86_thread_state64_t *)state;
5406 if(state + sizeof(x86_thread_state64_t) >
5407 (char *)ut + ut->cmdsize){
5408 Mach_O_error(ofile, "malformed object ("
5409 "x86_THREAD_STATE64 in %s command %u "
5410 "extends past end of command)", ut->cmd ==
5411 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5412 "LC_THREAD", i);
5413 goto return_bad;
5415 if(swapped)
5416 swap_x86_thread_state64(cpu, host_byte_sex);
5417 state += sizeof(x86_thread_state64_t);
5418 break;
5419 default:
5420 if(swapped){
5421 Mach_O_error(ofile, "malformed object (unknown "
5422 "flavor for flavor number %u in %s command"
5423 " %u can't byte swap it)", nflavor,
5424 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5425 "LC_THREAD", i);
5426 goto return_bad;
5428 state += count * sizeof(uint32_t);
5429 break;
5431 nflavor++;
5433 break;
5435 #endif /* x86_THREAD_STATE64_COUNT */
5436 if(cputype == CPU_TYPE_HPPA){
5437 struct hp_pa_integer_thread_state *cpu;
5438 struct hp_pa_frame_thread_state *frame;
5439 struct hp_pa_fp_thread_state *fpu;
5441 nflavor = 0;
5442 p = (char *)ut + ut->cmdsize;
5443 while(state < p){
5444 if(state + sizeof(uint32_t) >
5445 (char *)ut + ut->cmdsize){
5446 Mach_O_error(ofile, "malformed object (flavor in "
5447 "%s command %u extends past end of command)",
5448 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5449 "LC_THREAD", i);
5450 goto return_bad;
5452 flavor = *((uint32_t *)state);
5453 if(swapped){
5454 flavor = SWAP_INT(flavor);
5455 *((uint32_t *)state) = flavor;
5457 state += sizeof(uint32_t);
5458 if(state + sizeof(uint32_t) >
5459 (char *)ut + ut->cmdsize){
5460 Mach_O_error(ofile, "malformed object (count in "
5461 "%s command %u extends past end of command)",
5462 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5463 "LC_THREAD", i);
5464 goto return_bad;
5466 count = *((uint32_t *)state);
5467 if(swapped){
5468 count = SWAP_INT(count);
5469 *((uint32_t *)state) = count;
5471 state += sizeof(uint32_t);
5472 switch(flavor){
5473 case HPPA_INTEGER_THREAD_STATE:
5474 if(count != HPPA_INTEGER_THREAD_STATE_COUNT){
5475 Mach_O_error(ofile, "malformed object (count "
5476 "not HPPA_INTEGER_THREAD_STATE_COUNT for "
5477 "flavor number %u which is a "
5478 "HPPA_INTEGER_THREAD_STATE "
5479 "flavor in %s command %u)", nflavor,
5480 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5481 "LC_THREAD", i);
5482 goto return_bad;
5484 cpu = (struct hp_pa_integer_thread_state *)state;
5485 if(state+sizeof(struct hp_pa_integer_thread_state) >
5486 (char *)ut + ut->cmdsize){
5487 Mach_O_error(ofile, "malformed object ("
5488 "HPPA_INTEGER_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_integer_thread_state(cpu,
5496 host_byte_sex);
5497 state += sizeof(struct hp_pa_integer_thread_state);
5498 break;
5499 case HPPA_FRAME_THREAD_STATE:
5500 if(count != HPPA_FRAME_THREAD_STATE_COUNT){
5501 Mach_O_error(ofile, "malformed object (count "
5502 "not HPPA_FRAME_THREAD_STATE_COUNT for "
5503 "flavor number %u which is a HPPA_FRAME_"
5504 "THREAD_STATE flavor in %s command %u)",
5505 nflavor,
5506 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5507 "LC_THREAD", i);
5508 goto return_bad;
5510 frame = (struct hp_pa_frame_thread_state *)state;
5511 if(state + sizeof(struct hp_pa_frame_thread_state) >
5512 (char *)ut + ut->cmdsize){
5513 Mach_O_error(ofile, "malformed object ("
5514 "HPPA_FRAME_THREAD_STATE in %s command "
5515 "%u extends past end of command)",
5516 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5517 "LC_THREAD", i);
5518 goto return_bad;
5520 if(swapped)
5521 swap_hppa_frame_thread_state(frame,host_byte_sex);
5522 state += sizeof(struct hp_pa_frame_thread_state);
5523 break;
5524 case HPPA_FP_THREAD_STATE:
5525 if(count != HPPA_FP_THREAD_STATE_COUNT){
5526 Mach_O_error(ofile, "malformed object (count "
5527 "not HPPA_FP_THREAD_STATE_COUNT for "
5528 "flavor number %u which is a HPPA_FP_"
5529 "THREAD_STATE flavor in %s command %u)",
5530 nflavor,
5531 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5532 "LC_THREAD", i);
5533 goto return_bad;
5535 fpu = (struct hp_pa_fp_thread_state *)state;
5536 if(state + sizeof(struct hp_pa_fp_thread_state) >
5537 (char *)ut + ut->cmdsize){
5538 Mach_O_error(ofile, "malformed object ("
5539 "HPPA_FP_THREAD_STATE in %s command "
5540 "%u extends past end of command)",
5541 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5542 "LC_THREAD", i);
5543 goto return_bad;
5545 if(swapped)
5546 swap_hppa_fp_thread_state(fpu,host_byte_sex);
5547 state += sizeof(struct hp_pa_fp_thread_state);
5548 break;
5549 default:
5550 if(swapped){
5551 Mach_O_error(ofile, "malformed object (unknown "
5552 "flavor for flavor number %u in %s command"
5553 " %u can't byte swap it)", nflavor,
5554 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5555 "LC_THREAD", i);
5556 goto return_bad;
5558 state += count * sizeof(uint32_t);
5559 break;
5561 nflavor++;
5563 break;
5565 if(cputype == CPU_TYPE_SPARC){
5566 struct sparc_thread_state_regs *cpu;
5567 struct sparc_thread_state_fpu *fpu;
5569 nflavor = 0;
5570 p = (char *)ut + ut->cmdsize;
5571 while(state < p){
5572 if(state + sizeof(uint32_t) >
5573 (char *)ut + ut->cmdsize){
5574 Mach_O_error(ofile, "malformed object (flavor in "
5575 "%s command %u extends past end of command)",
5576 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5577 "LC_THREAD", i);
5578 goto return_bad;
5580 flavor = *((uint32_t *)state);
5581 if(swapped){
5582 flavor = SWAP_INT(flavor);
5583 *((uint32_t *)state) = flavor;
5585 state += sizeof(uint32_t);
5586 if(state + sizeof(uint32_t) >
5587 (char *)ut + ut->cmdsize){
5588 Mach_O_error(ofile, "malformed object (count in "
5589 "%s command %u extends past end of command)",
5590 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5591 "LC_THREAD", i);
5592 goto return_bad;
5594 count = *((uint32_t *)state);
5595 if(swapped){
5596 count = SWAP_INT(count);
5597 *((uint32_t *)state) = count;
5599 state += sizeof(uint32_t);
5600 switch(flavor){
5601 case SPARC_THREAD_STATE_REGS:
5602 if(count != SPARC_THREAD_STATE_REGS_COUNT){
5603 Mach_O_error(ofile, "malformed object (count "
5604 "not SPARC_THREAD_STATE_REGS_COUNT for "
5605 "flavor number %u which is a SPARC_THREAD_"
5606 "STATE_REGS flavor in %s command %u)",
5607 nflavor, ut->cmd == LC_UNIXTHREAD ?
5608 "LC_UNIXTHREAD" : "LC_THREAD", i);
5609 goto return_bad;
5611 cpu = (struct sparc_thread_state_regs *)state;
5612 if(state + sizeof(struct sparc_thread_state_regs) >
5613 (char *)ut + ut->cmdsize){
5614 Mach_O_error(ofile, "malformed object ("
5615 "SPARC_THREAD_STATE_REGS in %s command %u "
5616 "extends past end of command)", ut->cmd ==
5617 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5618 "LC_THREAD", i);
5619 goto return_bad;
5621 if(swapped)
5622 swap_sparc_thread_state_regs(cpu, host_byte_sex);
5623 state += sizeof(struct sparc_thread_state_regs);
5624 break;
5625 case SPARC_THREAD_STATE_FPU:
5626 if(count != SPARC_THREAD_STATE_FPU_COUNT){
5627 Mach_O_error(ofile, "malformed object (count "
5628 "not SPARC_THREAD_STATE_FPU_COUNT for "
5629 "flavor number %u which is a SPARC_THREAD_"
5630 "STATE_FPU flavor in %s command %u)",
5631 nflavor, ut->cmd == LC_UNIXTHREAD ?
5632 "LC_UNIXTHREAD" : "LC_THREAD", i);
5633 goto return_bad;
5635 fpu = (struct sparc_thread_state_fpu *)state;
5636 if(state + sizeof(struct sparc_thread_state_fpu) >
5637 (char *)ut + ut->cmdsize){
5638 Mach_O_error(ofile, "malformed object ("
5639 "SPARC_THREAD_STATE_FPU in %s command %u "
5640 "extends past end of command)", ut->cmd ==
5641 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5642 "LC_THREAD", i);
5643 goto return_bad;
5645 if(swapped)
5646 swap_sparc_thread_state_fpu(fpu, host_byte_sex);
5647 state += sizeof(struct sparc_thread_state_fpu);
5648 break;
5649 default:
5650 if(swapped){
5651 Mach_O_error(ofile, "malformed object (unknown "
5652 "flavor for flavor number %u in %s command"
5653 " %u can't byte swap it)", nflavor,
5654 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5655 "LC_THREAD", i);
5656 goto return_bad;
5658 state += count * sizeof(uint32_t);
5659 break;
5661 nflavor++;
5663 break;
5665 if(cputype == CPU_TYPE_ARM){
5666 arm_thread_state_t *cpu;
5668 nflavor = 0;
5669 p = (char *)ut + ut->cmdsize;
5670 while(state < p){
5671 if(state + sizeof(uint32_t) >
5672 (char *)ut + ut->cmdsize){
5673 Mach_O_error(ofile, "malformed object (flavor in "
5674 "%s command %u extends past end of command)",
5675 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5676 "LC_THREAD", i);
5677 goto return_bad;
5679 flavor = *((uint32_t *)state);
5680 if(swapped){
5681 flavor = SWAP_INT(flavor);
5682 *((uint32_t *)state) = flavor;
5684 state += sizeof(uint32_t);
5685 if(state + sizeof(uint32_t) >
5686 (char *)ut + ut->cmdsize){
5687 Mach_O_error(ofile, "malformed object (count in "
5688 "%s command %u extends past end of command)",
5689 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5690 "LC_THREAD", i);
5691 goto return_bad;
5693 count = *((uint32_t *)state);
5694 if(swapped){
5695 count = SWAP_INT(count);
5696 *((uint32_t *)state) = count;
5698 state += sizeof(uint32_t);
5699 switch(flavor){
5700 case ARM_THREAD_STATE:
5701 if(count != ARM_THREAD_STATE_COUNT){
5702 Mach_O_error(ofile, "malformed object (count "
5703 "not ARM_THREAD_STATE_COUNT for "
5704 "flavor number %u which is a ARM_THREAD_"
5705 "STATE flavor in %s command %u)",
5706 nflavor, ut->cmd == LC_UNIXTHREAD ?
5707 "LC_UNIXTHREAD" : "LC_THREAD", i);
5708 goto return_bad;
5710 cpu = (arm_thread_state_t *)state;
5711 if(state + sizeof(arm_thread_state_t) >
5712 (char *)ut + ut->cmdsize){
5713 Mach_O_error(ofile, "malformed object ("
5714 "ARM_THREAD_STATE in %s command %u "
5715 "extends past end of command)", ut->cmd ==
5716 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5717 "LC_THREAD", i);
5718 goto return_bad;
5720 if(swapped)
5721 swap_arm_thread_state_t(cpu, host_byte_sex);
5722 state += sizeof(arm_thread_state_t);
5723 break;
5724 default:
5725 if(swapped){
5726 Mach_O_error(ofile, "malformed object (unknown "
5727 "flavor for flavor number %u in %s command"
5728 " %u can't byte swap it)", nflavor,
5729 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5730 "LC_THREAD", i);
5731 goto return_bad;
5733 state += count * sizeof(uint32_t);
5734 break;
5736 nflavor++;
5738 break;
5740 if(swapped){
5741 Mach_O_error(ofile, "malformed object (unknown cputype and "
5742 "cpusubtype of object and can't byte swap and check %s "
5743 "command %u)", ut->cmd == LC_UNIXTHREAD ?
5744 "LC_UNIXTHREAD" : "LC_THREAD", i);
5745 goto return_bad;
5747 break;
5748 case LC_IDENT:
5749 if(l.cmdsize < sizeof(struct ident_command)){
5750 Mach_O_error(ofile, "malformed object (LC_IDENT cmdsize "
5751 "too small) in command %u", i);
5752 goto return_bad;
5754 id = (struct ident_command *)lc;
5755 if(swapped)
5756 swap_ident_command(id, host_byte_sex);
5758 * Note the cmdsize field if the LC_IDENT command was checked
5759 * as part of checking all load commands cmdsize field before
5760 * the switch statement on the cmd field of the load command.
5762 break;
5763 case LC_RPATH:
5764 if(l.cmdsize < sizeof(struct rpath_command)){
5765 Mach_O_error(ofile, "malformed object (LC_RPATH: cmdsize "
5766 "too small) in command %u", i);
5767 goto return_bad;
5769 rpath = (struct rpath_command *)lc;
5770 if(swapped)
5771 swap_rpath_command(rpath, host_byte_sex);
5772 if(rpath->cmdsize < sizeof(struct rpath_command)){
5773 Mach_O_error(ofile, "malformed object (LC_RPATH command "
5774 "%u has too small cmdsize field)", i);
5775 goto return_bad;
5777 if(rpath->path.offset >= rpath->cmdsize){
5778 Mach_O_error(ofile, "truncated or malformed object (path."
5779 "offset field of LC_RPATH command %u extends past the "
5780 "end of the file)", i);
5781 goto return_bad;
5783 break;
5785 #ifndef OFI
5786 default:
5787 Mach_O_error(ofile, "malformed object (unknown load command "
5788 "%u)", i);
5789 goto return_bad;
5790 #endif /* !defined(OFI) */
5793 lc = (struct load_command *)((char *)lc + l.cmdsize);
5794 /* check that next load command does not extends past the end */
5795 if((char *)lc > (char *)load_commands + sizeofcmds){
5796 Mach_O_error(ofile, "truncated or malformed object (load "
5797 "command %u extends past the end of the file)",
5798 i + 1);
5799 goto return_bad;
5802 if(st == NULL){
5803 if(dyst != NULL){
5804 Mach_O_error(ofile, "truncated or malformed object (contains "
5805 "LC_DYSYMTAB load command without a LC_SYMTAB load command)");
5806 goto return_bad;
5809 else{
5810 if(dyst != NULL){
5811 if(dyst->nlocalsym != 0 &&
5812 dyst->ilocalsym > st->nsyms){
5813 Mach_O_error(ofile, "truncated or malformed object "
5814 "(ilocalsym in LC_DYSYMTAB load command extends past "
5815 "the end of the symbol table)");
5816 goto return_bad;
5818 big_size = dyst->ilocalsym;
5819 big_size += dyst->nlocalsym;
5820 if(dyst->nlocalsym != 0 && big_size > st->nsyms){
5821 Mach_O_error(ofile, "truncated or malformed object "
5822 "(ilocalsym plus nlocalsym in LC_DYSYMTAB load command "
5823 "extends past the end of the symbol table)");
5824 goto return_bad;
5827 if(dyst->nextdefsym != 0 &&
5828 dyst->iextdefsym > st->nsyms){
5829 Mach_O_error(ofile, "truncated or malformed object "
5830 "(iextdefsym in LC_DYSYMTAB load command extends past "
5831 "the end of the symbol table)");
5832 goto return_bad;
5834 big_size = dyst->iextdefsym;
5835 big_size += dyst->nextdefsym;
5836 if(dyst->nextdefsym != 0 && big_size > st->nsyms){
5837 Mach_O_error(ofile, "truncated or malformed object "
5838 "(iextdefsym plus nextdefsym in LC_DYSYMTAB load "
5839 "command extends past the end of the symbol table)");
5840 goto return_bad;
5843 if(dyst->nundefsym != 0 &&
5844 dyst->iundefsym > st->nsyms){
5845 Mach_O_error(ofile, "truncated or malformed object "
5846 "(iundefsym in LC_DYSYMTAB load command extends past "
5847 "the end of the symbol table)");
5848 goto return_bad;
5850 big_size = dyst->iundefsym;
5851 big_size += dyst->nundefsym;
5852 if(dyst->nundefsym != 0 && big_size > st->nsyms){
5853 Mach_O_error(ofile, "truncated or malformed object "
5854 "(iundefsym plus nundefsym in LC_DYSYMTAB load command "
5855 "extends past the end of the symbol table)");
5856 goto return_bad;
5858 if(rc != NULL){
5859 if(rc->init_module > dyst->nmodtab){
5860 Mach_O_error(ofile, "malformed object (init_module in "
5861 "LC_ROUTINES load command extends past the "
5862 "end of the module table)");
5863 goto return_bad;
5866 if(rc64 != NULL){
5867 if(rc64->init_module > dyst->nmodtab){
5868 Mach_O_error(ofile, "malformed object (init_module in "
5869 "LC_ROUTINES_64 load command extends past the "
5870 "end of the module table)");
5871 goto return_bad;
5874 if(hints != NULL){
5875 if(hints->nhints != dyst->nundefsym){
5876 Mach_O_error(ofile, "malformed object (nhints in "
5877 "LC_TWOLEVEL_HINTS load command not the same as "
5878 "nundefsym in LC_DYSYMTAB load command)");
5879 goto return_bad;
5884 /* check for an inconsistent size of the load commands */
5885 if((char *)load_commands + sizeofcmds != (char *)lc){
5886 Mach_O_error(ofile, "malformed object (inconsistent sizeofcmds "
5887 "field in mach header)");
5888 goto return_bad;
5892 * Mark this ofile so we know its headers have been swapped. We do this
5893 * in case we don't process it the first time so we can swap them back
5894 * in case we loop back to it in a fat file to process it later.
5896 if(swapped == TRUE)
5897 ofile->headers_swapped = TRUE;
5899 /* looks good return ok */
5900 free_elements(&elements);
5901 return(CHECK_GOOD);
5903 return_bad:
5904 free_elements(&elements);
5905 return(CHECK_BAD);
5906 #endif /* OTOOL */
5910 * swap_back_Mach_O() is called after the ofile has been processed to swap back
5911 * the mach header and load commands if check_Mach_O() above swapped them.
5913 static
5914 void
5915 swap_back_Mach_O(
5916 struct ofile *ofile)
5918 if(ofile->headers_swapped == TRUE){
5919 ofile->headers_swapped = FALSE;
5920 if(ofile->mh != NULL)
5921 swap_object_headers(ofile->mh, ofile->load_commands);
5922 else if(ofile->mh64 != NULL)
5923 swap_object_headers(ofile->mh64, ofile->load_commands);
5927 #ifndef OTOOL
5929 * check_overlaping_element() checks that the element in the ofile described by
5930 * offset, size and name does not overlap in list of elements in head. If it
5931 * does CHECK_BAD is returned and an error message is generated. If it doesn't
5932 * then an element is added in the ordered list and CHECK_GOOD is returned
5934 static
5935 enum check_type
5936 check_overlaping_element(
5937 struct ofile *ofile,
5938 struct element *head,
5939 uint32_t offset,
5940 uint32_t size,
5941 char *name)
5943 struct element *e, *p, *n;
5945 if(size == 0)
5946 return(CHECK_GOOD);
5948 if(head->next == NULL){
5949 n = allocate(sizeof(struct element));
5950 n->offset = offset;
5951 n->size = size;
5952 n->name = name;
5953 n->next = NULL;
5954 head->next = n;
5955 return(CHECK_GOOD);
5958 p = NULL;
5959 e = head;
5960 while(e->next != NULL){
5961 p = e;
5962 e = e->next;
5963 if((offset >= e->offset &&
5964 offset < e->offset + e->size) ||
5965 (offset + size > e->offset &&
5966 offset + size < e->offset + e->size) ||
5967 (offset <= e->offset &&
5968 offset + size >= e->offset + e->size)){
5969 Mach_O_error(ofile, "malformed object (%s at offset %u with a "
5970 "size of %u, overlaps %s at offset %u with a size of %u)",
5971 name, offset, size, e->name, e->offset, e->size);
5972 return(CHECK_BAD);
5974 if(e->next != NULL && offset + size <= e->next->offset){
5975 n = allocate(sizeof(struct element));
5976 n->offset = offset;
5977 n->size = size;
5978 n->name = name;
5979 n->next = e;
5980 p->next = n;
5981 return(CHECK_GOOD);
5984 n = allocate(sizeof(struct element));
5985 n->offset = offset;
5986 n->size = size;
5987 n->name = name;
5988 n->next = NULL;
5989 e->next = n;
5990 return(CHECK_GOOD);
5994 * free_elements() frees the list of elements on the list head.
5996 static
5997 void
5998 free_elements(
5999 struct element *head)
6001 struct element *e, *e_next;
6003 e = head->next;
6004 while(e != NULL){
6005 e_next = e->next;
6006 free(e);
6007 e = e_next;
6010 #endif /* !defined(OTOOL) */
6013 * check_dylib_module() checks the object file's dylib_module as referenced
6014 * by the dylib_module field in the ofile for correctness.
6016 static
6017 enum check_type
6018 check_dylib_module(
6019 struct ofile *ofile,
6020 struct symtab_command *st,
6021 struct dysymtab_command *dyst,
6022 char *strings,
6023 uint32_t module_index)
6025 #ifdef OTOOL
6026 return(CHECK_GOOD);
6027 #else /* !defined OTOOL */
6028 uint32_t i;
6029 enum byte_sex host_byte_sex;
6030 enum bool swapped;
6031 struct dylib_module m;
6032 struct dylib_module_64 m64;
6033 uint32_t module_name, nextdefsym, iextdefsym, nlocalsym, ilocalsym, nrefsym;
6034 uint32_t irefsym, nextrel, iextrel;
6036 host_byte_sex = get_host_byte_sex();
6037 swapped = (enum bool)(host_byte_sex != ofile->object_byte_sex);
6038 if(ofile->mh != NULL){
6039 m = *ofile->dylib_module;
6040 if(swapped)
6041 swap_dylib_module(&m, 1, host_byte_sex);
6042 module_name = m.module_name;
6043 nextdefsym = m.nextdefsym;
6044 iextdefsym = m.iextdefsym;
6045 nlocalsym = m.nlocalsym;
6046 ilocalsym = m.ilocalsym;
6047 nrefsym = m.nrefsym;
6048 irefsym = m.irefsym;
6049 nextrel = m.nextrel;
6050 iextrel = m.iextrel;
6052 else{
6053 m64 = *ofile->dylib_module64;
6054 if(swapped)
6055 swap_dylib_module_64(&m64, 1, host_byte_sex);
6056 module_name = m64.module_name;
6057 nextdefsym = m64.nextdefsym;
6058 iextdefsym = m64.iextdefsym;
6059 nlocalsym = m64.nlocalsym;
6060 ilocalsym = m64.ilocalsym;
6061 nrefsym = m64.nrefsym;
6062 irefsym = m64.irefsym;
6063 nextrel = m64.nextrel;
6064 iextrel = m64.iextrel;
6067 if(module_name > st->strsize){
6068 Mach_O_error(ofile, "truncated or malformed object (module_name "
6069 "of module table entry %u past the end of the string table)",
6070 module_index);
6071 return(CHECK_BAD);
6073 for(i = module_name; i < st->strsize && strings[i] != '\0'; i++)
6075 if(i >= st->strsize){
6076 Mach_O_error(ofile, "truncated or malformed object (module_name "
6077 "of module table entry %u extends past the end of the string "
6078 "table)", module_index);
6079 return(CHECK_BAD);
6082 if(nextdefsym != 0){
6083 if(iextdefsym > st->nsyms){
6084 Mach_O_error(ofile, "truncated or malformed object (iextdefsym "
6085 "field of module table entry %u past the end of the "
6086 "symbol table", module_index);
6087 return(CHECK_BAD);
6089 if(iextdefsym + nextdefsym > st->nsyms){
6090 Mach_O_error(ofile, "truncated or malformed object (iextdefsym "
6091 "field of module table entry %u plus nextdefsym field "
6092 "extends past the end of the symbol table", module_index);
6093 return(CHECK_BAD);
6096 if(nlocalsym != 0){
6097 if(ilocalsym > st->nsyms){
6098 Mach_O_error(ofile, "truncated or malformed object (ilocalsym "
6099 "field of module table entry %u past the end of the "
6100 "symbol table", module_index);
6101 return(CHECK_BAD);
6103 if(ilocalsym + nlocalsym > st->nsyms){
6104 Mach_O_error(ofile, "truncated or malformed object (ilocalsym "
6105 "field of module table entry %u plus nlocalsym field "
6106 "extends past the end of the symbol table", module_index);
6107 return(CHECK_BAD);
6110 if(nrefsym != 0){
6111 if(irefsym > dyst->nextrefsyms){
6112 Mach_O_error(ofile, "truncated or malformed object (irefsym "
6113 "field of module table entry %u past the end of the "
6114 "reference table", module_index);
6115 return(CHECK_BAD);
6117 if(irefsym + nrefsym > dyst->nextrefsyms){
6118 Mach_O_error(ofile, "truncated or malformed object (irefsym "
6119 "field of module table entry %u plus nrefsym field "
6120 "extends past the end of the reference table",module_index);
6121 return(CHECK_BAD);
6124 if(nextrel != 0){
6125 if(iextrel > dyst->extreloff){
6126 Mach_O_error(ofile, "truncated or malformed object (iextrel "
6127 "field of module table entry %u past the end of the "
6128 "external relocation enrties", module_index);
6129 return(CHECK_BAD);
6131 if(iextrel + nextrel > dyst->extreloff){
6132 Mach_O_error(ofile, "truncated or malformed object (iextrel "
6133 "field of module table entry %u plus nextrel field "
6134 "extends past the end of the external relocation enrties",
6135 module_index);
6136 return(CHECK_BAD);
6139 return(CHECK_GOOD);
6140 #endif /* OTOOL */
6143 __private_extern__
6144 uint32_t
6145 size_ar_name(
6146 const struct ar_hdr *ar_hdr)
6148 int32_t i;
6150 i = sizeof(ar_hdr->ar_name) - 1;
6151 if(ar_hdr->ar_name[i] == ' '){
6153 if(ar_hdr->ar_name[i] != ' ')
6154 break;
6155 i--;
6156 }while(i > 0);
6158 return(i + 1);
6160 #endif /* !defined(RLD) */