836
[darwin-xtools.git] / cctools / libstuff / ofile.c
blob1fcf0a2a0e5b27a15e429e972516cc8ff82ecd8b
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 uint64_t size;
836 uint32_t magic;
837 char *addr;
839 magic = 0; /* to shut up the compiler warning message */
840 memset(ofile, '\0', sizeof(struct ofile));
842 /* Open the file and map it in */
843 if((fd = open(file_name, O_RDONLY)) == -1){
844 #ifdef OFI
845 return(NSObjectFileImageAccess);
846 #else
847 system_error("can't open file: %s", file_name);
848 return(FALSE);
849 #endif
851 if(fstat(fd, &stat_buf) == -1){
852 close(fd);
853 #ifdef OFI
854 return(NSObjectFileImageAccess);
855 #else
856 system_error("can't stat file: %s", file_name);
857 return(FALSE);
858 #endif
860 size = stat_buf.st_size;
862 addr = NULL;
863 if(size != 0){
864 addr = mmap(0, size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_PRIVATE, fd,
866 if((intptr_t)addr == -1){
867 system_error("can't map file: %s", file_name);
868 close(fd);
869 return(FALSE);
872 close(fd);
873 #ifdef OTOOL
874 if(otool_first_ofile_map && Wflag)
875 printf("Modification time = %ld\n", (long int)stat_buf.st_mtime);
876 #endif /* OTOOL */
878 return(ofile_map_from_memory(addr, size, file_name, stat_buf.st_mtime,
879 arch_flag, object_name, ofile, archives_with_fat_objects));
883 * ofile_map_from_memory() is the guts of ofile_map() but with an interface
884 * to pass the address and size of the file already mapped in.
886 __private_extern__
887 #ifdef OFI
888 NSObjectFileImageReturnCode
889 #else
890 enum bool
891 #endif
892 ofile_map_from_memory(
893 char *addr,
894 uint64_t size,
895 const char *file_name,
896 uint64_t mtime,
897 const struct arch_flag *arch_flag, /* can be NULL */
898 const char *object_name, /* can be NULL */
899 struct ofile *ofile,
900 enum bool archives_with_fat_objects)
902 uint32_t i;
903 uint32_t magic;
904 enum byte_sex host_byte_sex;
905 struct arch_flag host_arch_flag;
906 enum bool family;
907 const struct arch_flag *family_arch_flag;
908 uint64_t big_size;
909 #ifdef OTOOL
910 uint32_t small_nfat_arch;
911 #endif /* OTOOL */
913 /* fill in the start of the ofile structure */
914 ofile->file_name = savestr(file_name);
915 if(ofile->file_name == NULL)
916 return(FALSE);
917 ofile->file_addr = addr;
918 ofile->file_size = size;
919 ofile->file_mtime = mtime;
921 /* Try to figure out what kind of file this is */
923 if(size >= sizeof(uint32_t)){
924 magic = *((uint32_t *)addr);
926 host_byte_sex = get_host_byte_sex();
928 /* see if this file is a fat file (always in big endian byte sex) */
929 #ifdef __BIG_ENDIAN__
930 if(size >= sizeof(struct fat_header) && magic == FAT_MAGIC)
931 #endif /* __BIG_ENDIAN__ */
932 #ifdef __LITTLE_ENDIAN__
933 if(size >= sizeof(struct fat_header) && SWAP_INT(magic) == FAT_MAGIC)
934 #endif /* __LITTLE_ENDIAN__ */
936 ofile->file_type = OFILE_FAT;
937 ofile->fat_header = (struct fat_header *)addr;
938 #ifdef __LITTLE_ENDIAN__
939 swap_fat_header(ofile->fat_header, host_byte_sex);
940 #endif /* __LITTLE_ENDIAN__ */
941 #ifdef OTOOL
942 if(otool_first_ofile_map && fflag)
943 printf("Fat headers\n");
944 #endif /* OTOOL */
945 big_size = ofile->fat_header->nfat_arch;
946 big_size *= sizeof(struct fat_arch);
947 big_size += sizeof(struct fat_header);
948 if(big_size > size){
949 #ifdef OTOOL
950 error("fat file: %s truncated or malformed (fat_arch structs "
951 "would extend past the end of the file)", file_name);
952 ofile->fat_archs = allocate(size - sizeof(struct fat_header));
953 memset(ofile->fat_archs, '\0',
954 size - sizeof(struct fat_header));
955 memcpy(ofile->fat_archs,
956 addr + sizeof(struct fat_header),
957 size - sizeof(struct fat_header));
958 small_nfat_arch = (size - sizeof(struct fat_header)) /
959 sizeof(struct fat_arch);
960 #ifdef __LITTLE_ENDIAN__
961 swap_fat_arch(ofile->fat_archs, small_nfat_arch,
962 host_byte_sex);
963 #endif /* __LITTLE_ENDIAN__ */
964 if(otool_first_ofile_map && fflag)
965 print_fat_headers(ofile->fat_header, ofile->fat_archs,
966 size, vflag);
967 free(ofile->fat_archs);
968 ofile_unmap(ofile);
969 return(FALSE);
970 #else /* !defined(OTOOL) */
971 goto unknown;
972 #endif /* OTOOL */
974 ofile->fat_archs = (struct fat_arch *)(addr +
975 sizeof(struct fat_header));
976 #ifdef __LITTLE_ENDIAN__
977 swap_fat_arch(ofile->fat_archs, ofile->fat_header->nfat_arch,
978 host_byte_sex);
979 #endif /* __LITTLE_ENDIAN__ */
980 #ifdef OTOOL
981 if(otool_first_ofile_map && fflag)
982 print_fat_headers(ofile->fat_header, ofile->fat_archs,
983 size, vflag);
984 #endif /* OTOOL */
985 if(check_fat(ofile) == CHECK_BAD){
986 ofile_unmap(ofile);
987 #ifdef OFI
988 return(NSObjectFileImageFormat);
989 #else
990 return(FALSE);
991 #endif
994 * Now that the fat file is mapped fill in the ofile to the level
995 * the caller wants based on the arch_flag and object_name passed.
996 * If the caller did not specify an arch_flag or an object_name
997 * then everything the caller wants is done.
999 if(arch_flag == NULL && object_name == NULL)
1000 goto success;
1001 if(arch_flag == NULL){
1002 if(get_arch_from_host(&host_arch_flag, NULL) == 0){
1003 error("can't determine the host architecture (specify an "
1004 "arch_flag or fix get_arch_from_host() )");
1005 goto cleanup;
1007 ofile->arch_flag.name = savestr(host_arch_flag.name);
1008 if(ofile->arch_flag.name == NULL)
1009 goto cleanup;
1010 ofile->arch_flag.cputype = host_arch_flag.cputype;
1011 ofile->arch_flag.cpusubtype = host_arch_flag.cpusubtype;
1013 else{
1014 ofile->arch_flag.name = savestr(arch_flag->name);
1015 if(ofile->arch_flag.name == NULL)
1016 goto cleanup;
1017 ofile->arch_flag.cputype = arch_flag->cputype;
1018 ofile->arch_flag.cpusubtype = arch_flag->cpusubtype;
1021 ofile->narch = UINT_MAX;
1022 for(i = 0; i < ofile->fat_header->nfat_arch; i++){
1023 if(ofile->fat_archs[i].cputype ==
1024 ofile->arch_flag.cputype &&
1025 (ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK) ==
1026 (ofile->arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK)){
1027 ofile->narch = i;
1028 break;
1031 if(ofile->narch == UINT_MAX){
1032 family = FALSE;
1033 family_arch_flag =
1034 get_arch_family_from_cputype(ofile->arch_flag.cputype);
1035 if(family_arch_flag != NULL)
1036 family = (enum bool)
1037 ((family_arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) ==
1038 (ofile->arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK));
1039 ofile->narch = UINT_MAX;
1040 for(i = 0; i < ofile->fat_header->nfat_arch; i++){
1041 if(ofile->fat_archs[i].cputype ==
1042 ofile->arch_flag.cputype &&
1043 (family == TRUE ||
1044 (ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK) ==
1045 (ofile->arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK))){
1046 ofile->arch_flag.cpusubtype =
1047 ofile->fat_archs[i].cpusubtype;
1048 ofile->narch = i;
1049 break;
1053 if(ofile->narch == UINT_MAX){
1054 #ifdef OFI
1055 ofile_unmap(ofile);
1056 return(NSObjectFileImageArch);
1057 #else
1058 error("fat file: %s does not contain architecture %s",
1059 ofile->file_name, arch_flag->name);
1060 ofile_unmap(ofile);
1061 return(FALSE);
1062 #endif
1064 /* Now determine the file type for this specific architecture */
1065 size = ofile->fat_archs[i].size;
1066 addr = addr + ofile->fat_archs[i].offset;
1067 if(size >= sizeof(struct mach_header))
1068 memcpy(&magic, addr, sizeof(uint32_t));
1069 /* see if this file is a 32-bit Mach-O file */
1070 if(size >= sizeof(struct mach_header) &&
1071 (magic == MH_MAGIC ||
1072 magic == SWAP_INT(MH_MAGIC))){
1073 #ifdef ALIGNMENT_CHECKS
1074 if(ofile->fat_archs[i].offset % 4 != 0){
1075 error("fat file: %s architecture %s malformed for a 32-bit "
1076 "object file (offset is not a multiple of 4)",
1077 ofile->file_name, arch_flag->name);
1078 ofile_unmap(ofile);
1079 #ifdef OFI
1080 return(NSObjectFileImageFormat);
1081 #else
1082 return(FALSE);
1083 #endif
1085 #endif /* ALIGNMENT_CHECKS */
1086 ofile->arch_type = OFILE_Mach_O;
1087 ofile->object_addr = addr;
1088 ofile->object_size = size;
1089 if(magic == MH_MAGIC)
1090 ofile->object_byte_sex = host_byte_sex;
1091 else
1092 ofile->object_byte_sex =
1093 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1094 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1095 ofile->mh = (struct mach_header *)addr;
1096 ofile->load_commands = (struct load_command *)(addr +
1097 sizeof(struct mach_header));
1098 if(check_Mach_O(ofile) == CHECK_BAD){
1099 ofile_unmap(ofile);
1100 #ifdef OFI
1101 return(NSObjectFileImageFormat);
1102 #else
1103 return(FALSE);
1104 #endif
1106 if(object_name != NULL){
1107 error("fat file: %s architecture %s is not an archive "
1108 "(object_name to ofile_map() can't be specified to "
1109 "be other than NULL)", ofile->file_name,
1110 arch_flag->name);
1111 goto cleanup;
1114 /* see if this file is a 64-bit Mach-O file */
1115 else if(size >= sizeof(struct mach_header_64) &&
1116 (magic == MH_MAGIC_64 ||
1117 magic == SWAP_INT(MH_MAGIC_64))){
1118 #ifdef ALIGNMENT_CHECKS
1119 if(ofile->fat_archs[i].offset % 8 != 0){
1120 error("fat file: %s architecture %s malformed for a 64-bit "
1121 "object file (offset is not a multiple of 8)",
1122 ofile->file_name, arch_flag->name);
1123 ofile_unmap(ofile);
1124 #ifdef OFI
1125 return(NSObjectFileImageFormat);
1126 #else
1127 return(FALSE);
1128 #endif
1130 #endif /* ALIGNMENT_CHECKS */
1131 ofile->arch_type = OFILE_Mach_O;
1132 ofile->object_addr = addr;
1133 ofile->object_size = size;
1134 if(magic == MH_MAGIC_64)
1135 ofile->object_byte_sex = host_byte_sex;
1136 else
1137 ofile->object_byte_sex =
1138 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1139 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1140 ofile->mh64 = (struct mach_header_64 *)addr;
1141 ofile->load_commands = (struct load_command *)(addr +
1142 sizeof(struct mach_header_64));
1143 if(check_Mach_O(ofile) == CHECK_BAD){
1144 ofile_unmap(ofile);
1145 #ifdef OFI
1146 return(NSObjectFileImageFormat);
1147 #else
1148 return(FALSE);
1149 #endif
1151 if(object_name != NULL){
1152 error("fat file: %s architecture %s is not an archive "
1153 "(object_name to ofile_map() can't be specified to "
1154 "be other than NULL)", ofile->file_name,
1155 arch_flag->name);
1156 goto cleanup;
1159 /* see if this file is an archive file */
1160 else if(size >= SARMAG && strncmp(addr, ARMAG, SARMAG) == 0){
1161 ofile->arch_type = OFILE_ARCHIVE;
1162 if(check_archive(ofile, FALSE) == CHECK_BAD){
1163 ofile_unmap(ofile);
1164 #ifdef OFI
1165 return(NSObjectFileImageInappropriateFile);
1166 #else
1167 return(FALSE);
1168 #endif
1170 #ifdef ALIGNMENT_CHECKS
1171 if(ofile->archive_cputype != 0 &&
1172 ofile->fat_archs[i].offset % sizeof(uint32_t) != 0){
1173 error("fat file: %s architecture %s malformed archive that "
1174 "contains object files (offset to archive is not a "
1175 "multiple of sizeof(uint32_t))",
1176 ofile->file_name, arch_flag->name);
1177 ofile_unmap(ofile);
1178 #ifdef OFI
1179 return(NSObjectFileImageInappropriateFile);
1180 #else
1181 return(FALSE);
1182 #endif
1184 #endif /* ALIGNMENT_CHECKS */
1185 if(object_name != NULL){
1186 if(ofile_specific_member(object_name, ofile) == FALSE)
1187 goto cleanup;
1190 /* this file type is now known to be unknown to this program */
1191 else{
1192 ofile->file_type = OFILE_UNKNOWN;
1193 if(object_name != NULL){
1194 error("fat file: %s architecture %s is not an archive "
1195 "(object_name to ofile_map() can't be specified to "
1196 "be other than NULL)", ofile->file_name,
1197 arch_flag->name);
1198 goto cleanup;
1202 /* see if this file is a 32-bit Mach-O file */
1203 else if(size >= sizeof(struct mach_header) &&
1204 (magic == MH_MAGIC ||
1205 magic == SWAP_INT(MH_MAGIC))){
1206 ofile->file_type = OFILE_Mach_O;
1207 ofile->object_addr = addr;
1208 ofile->object_size = size;
1209 if(magic == MH_MAGIC)
1210 ofile->object_byte_sex = host_byte_sex;
1211 else
1212 ofile->object_byte_sex = host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1213 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1214 ofile->mh = (struct mach_header *)addr;
1215 ofile->load_commands = (struct load_command *)(addr +
1216 sizeof(struct mach_header));
1217 if(check_Mach_O(ofile) == CHECK_BAD){
1218 ofile_unmap(ofile);
1219 #ifdef OFI
1220 return(NSObjectFileImageFormat);
1221 #else
1222 return(FALSE);
1223 #endif
1225 if(object_name != NULL){
1226 error("file: %s is not an archive (object_name to ofile_map() "
1227 "can't be specified to be other than NULL)",
1228 ofile->file_name);
1229 goto cleanup;
1231 if(arch_flag != NULL){
1232 if(arch_flag->cputype != ofile->mh_cputype &&
1233 (arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) !=
1234 (ofile->mh_cpusubtype & ~CPU_SUBTYPE_MASK)){
1235 #ifdef OFI
1236 ofile_unmap(ofile);
1237 return(NSObjectFileImageArch);
1238 #else
1239 error("object file: %s does not match specified arch_flag: "
1240 "%s passed to ofile_map()", ofile->file_name,
1241 arch_flag->name);
1242 ofile_unmap(ofile);
1243 return(FALSE);
1244 #endif
1245 goto cleanup;
1249 /* see if this file is a 64-bit Mach-O file */
1250 else if(size >= sizeof(struct mach_header_64) &&
1251 (magic == MH_MAGIC_64 ||
1252 magic == SWAP_INT(MH_MAGIC_64))){
1253 ofile->file_type = OFILE_Mach_O;
1254 ofile->object_addr = addr;
1255 ofile->object_size = size;
1256 if(magic == MH_MAGIC_64)
1257 ofile->object_byte_sex = host_byte_sex;
1258 else
1259 ofile->object_byte_sex = host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1260 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1261 ofile->mh64 = (struct mach_header_64 *)addr;
1262 ofile->load_commands = (struct load_command *)(addr +
1263 sizeof(struct mach_header_64));
1264 if(check_Mach_O(ofile) == CHECK_BAD){
1265 ofile_unmap(ofile);
1266 #ifdef OFI
1267 return(NSObjectFileImageFormat);
1268 #else
1269 return(FALSE);
1270 #endif
1272 if(object_name != NULL){
1273 error("file: %s is not an archive (object_name to ofile_map() "
1274 "can't be specified to be other than NULL)",
1275 ofile->file_name);
1276 goto cleanup;
1278 if(arch_flag != NULL){
1279 if(arch_flag->cputype != ofile->mh_cputype &&
1280 (arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) !=
1281 (ofile->mh_cpusubtype & ~CPU_SUBTYPE_MASK)){
1282 #ifdef OFI
1283 ofile_unmap(ofile);
1284 return(NSObjectFileImageArch);
1285 #else
1286 error("object file: %s does not match specified arch_flag: "
1287 "%s passed to ofile_map()", ofile->file_name,
1288 arch_flag->name);
1289 ofile_unmap(ofile);
1290 return(FALSE);
1291 #endif
1292 goto cleanup;
1296 /* see if this file is an archive file */
1297 else if(size >= SARMAG && strncmp(addr, ARMAG, SARMAG) == 0){
1298 ofile->file_type = OFILE_ARCHIVE;
1299 if(check_archive(ofile, archives_with_fat_objects) == CHECK_BAD)
1300 goto cleanup;
1301 if(object_name != NULL){
1302 if(ofile_specific_member(object_name, ofile) == FALSE)
1303 goto cleanup;
1304 if(arch_flag != NULL){
1305 if(arch_flag->cputype != ofile->mh_cputype &&
1306 (arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) !=
1307 (ofile->mh_cpusubtype & ~CPU_SUBTYPE_MASK)){
1308 error("object file: %s(%.*s) does not match specified "
1309 "arch_flag: %s passed to ofile_map()",
1310 ofile->file_name, (int)ofile->member_name_size,
1311 ofile->member_name, arch_flag->name);
1312 goto cleanup;
1316 else{
1317 if(arch_flag != NULL){
1318 if(arch_flag->cputype != ofile->archive_cputype &&
1319 (arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) !=
1320 (ofile->archive_cpusubtype & ~CPU_SUBTYPE_MASK)){
1321 error("archive file: %s objects do not match specified "
1322 "arch_flag: %s passed to ofile_map()",
1323 ofile->file_name, arch_flag->name);
1324 goto cleanup;
1329 /* this file type is now known to be unknown to this program */
1330 else{
1331 #ifndef OTOOL
1332 unknown:
1333 #endif
1334 #ifndef OFI
1335 #ifdef LTO_SUPPORT
1336 if(is_llvm_bitcode(ofile, ofile->file_addr, ofile->file_size) ==
1337 TRUE){
1338 ofile->file_type = OFILE_LLVM_BITCODE;
1339 if(arch_flag != NULL){
1340 if(arch_flag->cputype != ofile->lto_cputype &&
1341 (arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) !=
1342 (ofile->lto_cpusubtype & ~CPU_SUBTYPE_MASK)){
1343 error("llvm bitcode file: %s does not match specified "
1344 "arch_flag: %s passed to ofile_map()",
1345 ofile->file_name, arch_flag->name);
1346 goto cleanup;
1349 if(object_name != NULL){
1350 error("file: %s is not an archive (object_name to "
1351 "ofile_map() can't be specified to be other than "
1352 "NULL)", ofile->file_name);
1353 goto cleanup;
1355 goto success;
1357 else
1358 #endif /* LTO_SUPPORT */
1359 #endif /* OFI */
1360 ofile->file_type = OFILE_UNKNOWN;
1361 if(arch_flag != NULL){
1362 #ifdef OFI
1363 ofile_unmap(ofile);
1364 return(NSObjectFileImageInappropriateFile);
1365 #else
1366 error("file: %s is unknown type (arch_flag to ofile_map() "
1367 "can't be specified to be other than NULL)",
1368 ofile->file_name);
1369 ofile_unmap(ofile);
1370 return(FALSE);
1371 #endif
1373 if(object_name != NULL){
1374 error("file: %s is not an archive (object_name to ofile_map() "
1375 "can't be specified to be other than NULL)",
1376 ofile->file_name);
1377 goto cleanup;
1380 success:
1381 return(TRUE);
1383 cleanup:
1384 ofile_unmap(ofile);
1385 return(FALSE);
1389 * ofile_unmap() deallocates the memory associated with the specified ofile
1390 * struct.
1392 __private_extern__
1393 void
1394 ofile_unmap(
1395 struct ofile *ofile)
1397 kern_return_t r;
1399 if(ofile->file_addr != NULL){
1400 if((r = vm_deallocate(mach_task_self(),
1401 (vm_address_t)ofile->file_addr,
1402 (vm_size_t)ofile->file_size)) != KERN_SUCCESS){
1403 my_mach_error(r, "Can't vm_deallocate mapped memory for file: "
1404 "%s", ofile->file_name);
1407 if(ofile->file_name != NULL)
1408 free(ofile->file_name);
1409 if(ofile->arch_flag.name != NULL)
1410 free(ofile->arch_flag.name);
1411 memset(ofile, '\0', sizeof(struct ofile));
1415 * ofile_first_arch() sets up the ofile struct for a fat file to the first arch
1416 * in it.
1418 __private_extern__
1419 enum bool
1420 ofile_first_arch(
1421 struct ofile *ofile)
1423 if(ofile->file_type == OFILE_FAT ||
1424 (ofile->file_type == OFILE_ARCHIVE &&
1425 ofile->member_type == OFILE_FAT) )
1426 return(ofile_specific_arch(ofile, 0));
1427 else{
1428 error("ofile_first_arch() called and file type of: %s is not a fat "
1429 "file\n", ofile->file_name);
1430 return(FALSE);
1435 * ofile_next_arch() sets up the ofile struct for a fat file to the next arch
1436 * in it.
1438 __private_extern__
1439 enum bool
1440 ofile_next_arch(
1441 struct ofile *ofile)
1443 if(ofile->file_type == OFILE_FAT ||
1444 (ofile->file_type == OFILE_ARCHIVE &&
1445 ofile->member_type == OFILE_FAT) ){
1446 if(ofile->narch + 1 < ofile->fat_header->nfat_arch)
1447 return(ofile_specific_arch(ofile, ofile->narch + 1));
1448 else
1449 return(FALSE);
1451 else{
1452 error("ofile_next_arch() called and file type of: %s is not a fat "
1453 "file\n", ofile->file_name);
1454 return(FALSE);
1459 * ofile_specific_arch() sets up the ofile struct for the fat file for the
1460 * specified narch.
1462 static
1463 enum bool
1464 ofile_specific_arch(
1465 struct ofile *ofile,
1466 uint32_t narch)
1468 char *addr;
1469 uint32_t size;
1470 uint32_t magic;
1471 enum byte_sex host_byte_sex;
1473 ofile->narch = narch;
1474 ofile->arch_type = OFILE_UNKNOWN;
1475 if(ofile->arch_flag.name != NULL)
1476 free(ofile->arch_flag.name);
1477 ofile->arch_flag.name = NULL;
1478 ofile->arch_flag.cputype = 0;
1479 ofile->arch_flag.cpusubtype = 0;
1480 ofile->archive_cputype = 0;
1481 ofile->archive_cpusubtype = 0;
1482 ofile->object_addr = NULL;
1483 ofile->object_size = 0;
1484 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
1485 ofile->mh = NULL;
1486 ofile->mh64 = NULL;
1487 ofile->load_commands = NULL;
1489 ofile->arch_flag.cputype = ofile->fat_archs[ofile->narch].cputype;
1490 ofile->arch_flag.cpusubtype = ofile->fat_archs[ofile->narch].cpusubtype;
1491 set_arch_flag_name(&(ofile->arch_flag));
1494 /* Now determine the file type for this specific architecture */
1495 if(ofile->file_type == OFILE_FAT){
1496 ofile->member_offset = 0;
1497 ofile->member_addr = NULL;
1498 ofile->member_size = 0;
1499 ofile->member_ar_hdr = NULL;
1500 ofile->member_type = OFILE_UNKNOWN;
1502 size = ofile->fat_archs[ofile->narch].size;
1503 addr = ofile->file_addr + ofile->fat_archs[ofile->narch].offset;
1505 else{
1506 if(ofile->file_type != OFILE_ARCHIVE ||
1507 ofile->member_type != OFILE_FAT){
1508 error("internal error. ofile_specific_arch() called but file "
1509 "is not a fat file or an archive with a fat member ");
1511 size = ofile->fat_archs[ofile->narch].size;
1512 addr = ofile->file_addr +
1513 ofile->member_offset +
1514 ofile->fat_archs[ofile->narch].offset;
1517 #ifdef OTOOL
1518 if(addr - ofile->file_addr > (ptrdiff_t)ofile->file_size){
1519 error("fat file: %s offset to architecture %s extends past end "
1520 "of file", ofile->file_name, ofile->arch_flag.name);
1521 return(FALSE);
1523 if(addr + size > ofile->file_addr + ofile->file_size)
1524 size = (ofile->file_addr + ofile->file_size) - addr;
1525 #endif /* OTOOL */
1527 if(size >= sizeof(struct mach_header))
1528 memcpy(&magic, addr, sizeof(uint32_t));
1529 /* see if this file is a 32-bit Mach-O file */
1530 if(size >= sizeof(struct mach_header) &&
1531 (magic == MH_MAGIC || magic == SWAP_INT(MH_MAGIC))){
1532 #ifdef ALIGNMENT_CHECKS
1533 if(ofile->fat_archs[ofile->narch].offset % 4 != 0){
1534 if(ofile->file_type == OFILE_ARCHIVE){
1535 error("fat file: %s(%.*s) architecture %s malformed for a "
1536 "32-bit object file (offset is not a multiple of 4)",
1537 ofile->file_name, (int)ofile->member_name_size,
1538 ofile->member_name, ofile->arch_flag.name);
1540 else
1541 error("fat file: %s architecture %s malformed for a 32-bit "
1542 "object file (offset is not a multiple of 4)",
1543 ofile->file_name, ofile->arch_flag.name);
1544 goto cleanup;
1546 #endif /* ALIGNMENT_CHECKS */
1547 ofile->arch_type = OFILE_Mach_O;
1548 ofile->object_addr = addr;
1549 ofile->object_size = size;
1550 host_byte_sex = get_host_byte_sex();
1551 if(magic == MH_MAGIC)
1552 ofile->object_byte_sex = host_byte_sex;
1553 else
1554 ofile->object_byte_sex =
1555 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1556 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1557 ofile->mh = (struct mach_header *)addr;
1558 ofile->load_commands = (struct load_command *)(addr +
1559 sizeof(struct mach_header));
1560 if(check_Mach_O(ofile) == CHECK_BAD)
1561 goto cleanup;
1563 /* see if this file is a 64-bit Mach-O file */
1564 else if(size >= sizeof(struct mach_header_64) &&
1565 (magic == MH_MAGIC_64 || magic == SWAP_INT(MH_MAGIC_64))){
1566 #ifdef ALIGNMENT_CHECKS
1567 if(ofile->fat_archs[ofile->narch].offset % 8 != 0){
1568 if(ofile->file_type == OFILE_ARCHIVE){
1569 error("fat file: %s(%.*s) architecture %s malformed for an "
1570 "object file (offset is not a multiple of 8)",
1571 ofile->file_name, (int)ofile->member_name_size,
1572 ofile->member_name, ofile->arch_flag.name);
1574 else
1575 error("fat file: %s architecture %s malformed for a 64-bit "
1576 "object file (offset is not a multiple of 8",
1577 ofile->file_name, ofile->arch_flag.name);
1578 goto cleanup;
1580 #endif /* ALIGNMENT_CHECKS */
1581 ofile->arch_type = OFILE_Mach_O;
1582 ofile->object_addr = addr;
1583 ofile->object_size = size;
1584 host_byte_sex = get_host_byte_sex();
1585 if(magic == MH_MAGIC_64)
1586 ofile->object_byte_sex = host_byte_sex;
1587 else
1588 ofile->object_byte_sex =
1589 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1590 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1591 ofile->mh64 = (struct mach_header_64 *)addr;
1592 ofile->load_commands = (struct load_command *)(addr +
1593 sizeof(struct mach_header_64));
1594 if(check_Mach_O(ofile) == CHECK_BAD)
1595 goto cleanup;
1597 /* see if this file is an archive file */
1598 else if(size >= SARMAG && strncmp(addr, ARMAG, SARMAG) == 0){
1599 ofile->arch_type = OFILE_ARCHIVE;
1600 if(check_archive(ofile, FALSE) == CHECK_BAD)
1601 goto cleanup;
1602 #ifdef ALIGNMENT_CHECKS
1603 if(ofile->archive_cputype != 0 &&
1604 ofile->fat_archs[ofile->narch].offset %
1605 sizeof(uint32_t) != 0){
1606 error("fat file: %s architecture %s malformed archive that "
1607 "contains object files (offset to archive is not a "
1608 "multiple of sizeof(uint32_t))",
1609 ofile->file_name, ofile->arch_flag.name);
1610 goto cleanup;
1612 #endif /* ALIGNMENT_CHECKS */
1615 * This type for this architecture is now known to be unknown to this
1616 * program.
1618 else{
1619 #ifdef LTO_SUPPORT
1620 if(is_llvm_bitcode(ofile, addr, size) == TRUE){
1621 ofile->arch_type = OFILE_LLVM_BITCODE;
1622 ofile->object_addr = addr;
1623 ofile->object_size = size;
1625 else
1626 #endif /* LTO_SUPPORT */
1627 ofile->arch_type = OFILE_UNKNOWN;
1629 return(TRUE);
1630 cleanup:
1631 ofile->narch = 0;;
1632 ofile->arch_type = OFILE_UNKNOWN;
1633 if(ofile->arch_flag.name != NULL)
1634 free(ofile->arch_flag.name);
1635 ofile->arch_flag.name = NULL;
1636 ofile->arch_flag.cputype = 0;
1637 ofile->arch_flag.cpusubtype = 0;
1638 if(ofile->file_type != OFILE_ARCHIVE){
1639 ofile->member_offset = 0;
1640 ofile->member_addr = NULL;
1641 ofile->member_size = 0;
1642 ofile->member_ar_hdr = NULL;
1643 ofile->member_type = OFILE_UNKNOWN;
1645 ofile->archive_cputype = 0;
1646 ofile->archive_cpusubtype = 0;
1647 ofile->object_addr = NULL;
1648 ofile->object_size = 0;
1649 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
1650 ofile->mh = NULL;
1651 ofile->mh64 = NULL;
1652 ofile->load_commands = NULL;
1653 return(FALSE);
1657 * ofile_first_member() set up the ofile structure (the member_* fields and
1658 * the object file fields if the first member is an object file) for the first
1659 * member.
1661 __private_extern__
1662 enum bool
1663 ofile_first_member(
1664 struct ofile *ofile)
1666 char *addr;
1667 uint64_t size, offset;
1668 uint32_t magic;
1669 enum byte_sex host_byte_sex;
1670 struct ar_hdr *ar_hdr;
1671 uint32_t ar_name_size;
1673 /* These fields are to be filled in by this routine, clear them first */
1674 ofile->member_offset = 0;
1675 ofile->member_addr = NULL;
1676 ofile->member_size = 0;
1677 ofile->member_ar_hdr = NULL;
1678 ofile->member_name = NULL;
1679 ofile->member_name_size = 0;
1680 ofile->member_type = OFILE_UNKNOWN;
1681 ofile->object_addr = NULL;
1682 ofile->object_size = 0;
1683 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
1684 ofile->mh = NULL;
1685 ofile->mh64 = NULL;
1686 ofile->load_commands = NULL;
1687 #ifdef LTO_SUPPORT
1689 * Note: it is up to the caller if they want to call free_lto() on this
1690 * when iterating through the members of an archive.
1692 ofile->lto = NULL;
1693 #endif /* LTO_SUPPORT */
1696 * Get the address and size of the archive.
1698 if(ofile->file_type == OFILE_FAT){
1699 if(ofile->arch_type != OFILE_ARCHIVE){
1700 error("ofile_first_member() called on fat file: %s with a "
1701 "non-archive architecture or no architecture selected\n",
1702 ofile->file_name);
1703 return(FALSE);
1705 addr = ofile->file_addr + ofile->fat_archs[ofile->narch].offset;
1706 size = ofile->fat_archs[ofile->narch].size;
1708 else if(ofile->file_type == OFILE_ARCHIVE){
1709 addr = ofile->file_addr;
1710 size = ofile->file_size;
1712 else{
1713 error("ofile_first_member() called and file type of %s is "
1714 "OFILE_UNKNOWN\n", ofile->file_name);
1715 return(FALSE);
1717 #ifdef OTOOL
1718 if((addr + SARMAG) - ofile->file_addr > (ptrdiff_t)ofile->file_size){
1719 archive_error(ofile, "offset to first member extends past the end "
1720 "of the file");
1721 return(FALSE);
1723 if(addr + size > ofile->file_addr + ofile->file_size)
1724 size = (ofile->file_addr + ofile->file_size) - addr;
1725 #endif /* OTOOL */
1726 if(size < SARMAG || strncmp(addr, ARMAG, SARMAG) != 0){
1727 archive_error(ofile, "internal error. ofile_first_member() "
1728 "called but file does not have an archive magic "
1729 "string");
1730 return(FALSE);
1733 offset = SARMAG;
1734 if(offset != size && offset + sizeof(struct ar_hdr) > size){
1735 archive_error(ofile, "truncated or malformed (archive header of "
1736 "first member extends past the end of the file)");
1737 return(FALSE);
1740 /* check for empty archive */
1741 if(size == offset)
1742 return(FALSE);
1744 /* now we know there is a first member so set it up */
1745 ar_hdr = (struct ar_hdr *)(addr + offset);
1746 offset += sizeof(struct ar_hdr);
1747 ofile->member_offset = offset;
1748 ofile->member_addr = addr + offset;
1749 ofile->member_size = strtoul(ar_hdr->ar_size, NULL, 10);
1750 ofile->member_ar_hdr = ar_hdr;
1751 ofile->member_type = OFILE_UNKNOWN;
1752 ofile->member_name = ar_hdr->ar_name;
1753 if(strncmp(ofile->member_name, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0){
1754 ofile->member_name = ar_hdr->ar_name + sizeof(struct ar_hdr);
1755 ar_name_size = strtoul(ar_hdr->ar_name + sizeof(AR_EFMT1) - 1,
1756 NULL, 10);
1757 ofile->member_name_size = ar_name_size;
1758 ofile->member_offset += ar_name_size;
1759 ofile->member_addr += ar_name_size;
1760 ofile->member_size -= ar_name_size;
1762 else{
1763 ofile->member_name_size = size_ar_name(ar_hdr);
1764 ar_name_size = 0;
1766 /* Clear these in case there is no table of contents */
1767 ofile->toc_addr = NULL;
1768 ofile->toc_size = 0;
1769 ofile->toc_ar_hdr = NULL;
1770 ofile->toc_name = NULL;
1771 ofile->toc_name_size = 0;
1772 ofile->toc_ranlibs = NULL;
1773 ofile->toc_nranlibs = 0;
1774 ofile->toc_strings = NULL;
1775 ofile->toc_strsize = 0;
1776 ofile->toc_bad = FALSE;
1778 host_byte_sex = get_host_byte_sex();
1780 if(ofile->member_size > sizeof(uint32_t)){
1781 memcpy(&magic, ofile->member_addr, sizeof(uint32_t));
1782 #ifdef __BIG_ENDIAN__
1783 if(magic == FAT_MAGIC)
1784 #endif /* __BIG_ENDIAN__ */
1785 #ifdef __LITTLE_ENDIAN__
1786 if(magic == SWAP_INT(FAT_MAGIC))
1787 #endif /* __LITTLE_ENDIAN__ */
1789 ofile->member_type = OFILE_FAT;
1790 ofile->fat_header =
1791 (struct fat_header *)(ofile->member_addr);
1792 #ifdef __LITTLE_ENDIAN__
1793 swap_fat_header(ofile->fat_header, host_byte_sex);
1794 #endif /* __LITTLE_ENDIAN__ */
1795 if(sizeof(struct fat_header) +
1796 ofile->fat_header->nfat_arch *
1797 sizeof(struct fat_arch) > ofile->member_size){
1798 archive_member_error(ofile, "fat file truncated or "
1799 "malformed (fat_arch structs would extend past "
1800 "the end of the archive member)");
1801 goto fatcleanup;
1803 ofile->fat_archs = (struct fat_arch *)
1804 (ofile->member_addr + sizeof(struct fat_header));
1805 #ifdef __LITTLE_ENDIAN__
1806 swap_fat_arch(ofile->fat_archs,
1807 ofile->fat_header->nfat_arch, host_byte_sex);
1808 #endif /* __LITTLE_ENDIAN__ */
1809 if(check_fat_object_in_archive(ofile) == FALSE)
1810 goto fatcleanup;
1812 else if(size - (offset + ar_name_size) >=
1813 sizeof(struct mach_header) &&
1814 (magic == MH_MAGIC || magic == SWAP_INT(MH_MAGIC))){
1815 #ifdef ALIGNMENT_CHECKS
1816 if((offset + ar_name_size) % 4 != 0){
1817 archive_member_error(ofile, "offset in archive not a "
1818 "multiple of 4 (must be since member is a 32-bit "
1819 "object file)");
1820 goto cleanup;
1822 #endif /* ALIGNMENT_CHECKS */
1823 ofile->member_type = OFILE_Mach_O;
1824 ofile->object_addr = ofile->member_addr;
1825 ofile->object_size = ofile->member_size;
1826 if(magic == MH_MAGIC)
1827 ofile->object_byte_sex = host_byte_sex;
1828 else
1829 ofile->object_byte_sex =
1830 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1831 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1832 ofile->mh = (struct mach_header *)(ofile->object_addr);
1833 ofile->load_commands = (struct load_command *)
1834 (ofile->object_addr + sizeof(struct mach_header));
1835 if(check_Mach_O(ofile) == CHECK_BAD)
1836 goto cleanup;
1838 else if(size - (offset + ar_name_size) >=
1839 sizeof(struct mach_header_64) &&
1840 (magic == MH_MAGIC_64 || magic == SWAP_INT(MH_MAGIC_64))){
1841 #ifdef ALIGNMENT_CHECKS_ARCHIVE_64_BIT
1842 if(archive_64_bit_align_warning == FALSE &&
1843 (offset + ar_name_size) % 8 != 0){
1844 temporary_archive_member_warning(ofile, "offset in archive "
1845 "not a multiple of 8 (must be since member is an "
1846 "64-bit object file)");
1847 archive_64_bit_align_warning = TRUE;
1848 /* goto cleanup; */
1850 #endif /* ALIGNMENT_CHECKS_ARCHIVE_64_BIT */
1851 ofile->member_type = OFILE_Mach_O;
1852 ofile->object_addr = ofile->member_addr;
1853 ofile->object_size = ofile->member_size;
1854 if(magic == MH_MAGIC_64)
1855 ofile->object_byte_sex = host_byte_sex;
1856 else
1857 ofile->object_byte_sex =
1858 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
1859 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
1860 ofile->mh64 = (struct mach_header_64 *)(ofile->object_addr);
1861 ofile->load_commands = (struct load_command *)
1862 (ofile->object_addr + sizeof(struct mach_header_64));
1863 if(check_Mach_O(ofile) == CHECK_BAD)
1864 goto cleanup;
1866 if(ofile->member_type == OFILE_UNKNOWN &&
1867 (strncmp(ofile->member_name, SYMDEF_SORTED,
1868 sizeof(SYMDEF_SORTED) - 1) == 0 ||
1869 strncmp(ofile->member_name, SYMDEF,
1870 sizeof(SYMDEF) - 1) == 0)){
1871 ofile->toc_addr = ofile->member_addr;
1872 ofile->toc_size = ofile->member_size;
1873 ofile->toc_ar_hdr = ofile->member_ar_hdr;
1874 ofile->toc_name = ofile->member_name;
1875 ofile->toc_name_size = ofile->member_name_size;
1876 if(check_archive_toc(ofile) == CHECK_BAD)
1877 goto cleanup;
1879 #ifdef LTO_SUPPORT
1880 if(ofile->member_type == OFILE_UNKNOWN &&
1881 strncmp(ofile->member_name, SYMDEF_SORTED,
1882 sizeof(SYMDEF_SORTED) - 1) != 0 &&
1883 strncmp(ofile->member_name, SYMDEF,
1884 sizeof(SYMDEF) - 1) != 0 &&
1885 is_llvm_bitcode(ofile, ofile->member_addr, ofile->member_size) ==
1886 TRUE){
1887 ofile->member_type = OFILE_LLVM_BITCODE;
1888 ofile->object_addr = ofile->member_addr;
1889 ofile->object_size = ofile->member_size;
1891 #endif /* LTO_SUPPORT */
1893 return(TRUE);
1895 fatcleanup:
1896 ofile->fat_header = NULL;
1897 ofile->fat_archs = NULL;
1898 cleanup:
1899 ofile->member_offset = 0;
1900 ofile->member_addr = 0;
1901 ofile->member_size = 0;
1902 ofile->member_ar_hdr = NULL;
1903 ofile->member_name = NULL;
1904 ofile->member_name_size = 0;
1905 ofile->member_type = OFILE_UNKNOWN;
1906 ofile->object_addr = NULL;
1907 ofile->object_size = 0;
1908 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
1909 ofile->mh = NULL;
1910 ofile->mh64 = NULL;
1911 ofile->load_commands = NULL;
1912 #ifdef LTO_SUPPORT
1913 ofile->lto = NULL;
1914 ofile->lto_cputype = 0;
1915 ofile->lto_cpusubtype = 0;
1916 #endif /* LTO_SUPPORT */
1917 return(FALSE);
1921 * ofile_next_member() set up the ofile structure (the member_* fields and
1922 * the object file fields if the next member is an object file) for the next
1923 * member.
1925 __private_extern__
1926 enum bool
1927 ofile_next_member(
1928 struct ofile *ofile)
1930 char *addr;
1931 uint64_t size, offset;
1932 uint32_t magic;
1933 enum byte_sex host_byte_sex;
1934 struct ar_hdr *ar_hdr;
1935 uint32_t ar_name_size;
1938 * Get the address and size of the archive.
1940 if(ofile->file_type == OFILE_FAT){
1941 if(ofile->arch_type != OFILE_ARCHIVE){
1942 error("ofile_next_member() called on fat file: %s with a "
1943 "non-archive architecture or no architecture selected\n",
1944 ofile->file_name);
1945 return(FALSE);
1947 addr = ofile->file_addr + ofile->fat_archs[ofile->narch].offset;
1948 size = ofile->fat_archs[ofile->narch].size;
1950 else if(ofile->file_type == OFILE_ARCHIVE){
1951 addr = ofile->file_addr;
1952 size = ofile->file_size;
1954 else{
1955 error("ofile_next_member() called and file type of %s is "
1956 "OFILE_UNKNOWN\n", ofile->file_name);
1957 return(FALSE);
1959 if(size < SARMAG || strncmp(addr, ARMAG, SARMAG) != 0){
1960 archive_error(ofile, "internal error. ofile_next_member() "
1961 "called but file does not have an archive magic "
1962 "string");
1963 return(FALSE);
1965 if(ofile->member_ar_hdr == NULL){
1966 archive_error(ofile, "internal error. ofile_next_member() called "
1967 "but the ofile struct does not have an archive "
1968 "member selected");
1969 return(FALSE);
1972 /* figure out the offset to the next member */
1973 offset = ofile->member_offset + rnd(ofile->member_size,sizeof(short));
1974 #ifdef OTOOL
1975 if((addr - ofile->file_addr) + offset > ofile->file_size){
1976 archive_error(ofile, "offset to next member extends past the end "
1977 "of the file");
1978 return(FALSE);
1980 #endif /* OTOOL */
1981 /* if now at the end of the file then no more members */
1982 if(offset == size)
1983 goto cleanup;
1984 if(offset > size){
1985 archive_error(ofile, "truncated or malformed (archive header of "
1986 "next member extends past the end of the file)");
1987 return(FALSE);
1990 /* now we know there is a next member so set it up */
1991 ar_hdr = (struct ar_hdr *)(addr + offset);
1992 offset += sizeof(struct ar_hdr);
1993 ofile->member_offset = offset;
1994 ofile->member_addr = addr + offset;
1995 ofile->member_size = strtoul(ar_hdr->ar_size, NULL, 10);
1996 ofile->member_ar_hdr = ar_hdr;
1997 ofile->member_name = ar_hdr->ar_name;
1998 if(strncmp(ofile->member_name, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0){
1999 ofile->member_name = ar_hdr->ar_name + sizeof(struct ar_hdr);
2000 ar_name_size = strtoul(ar_hdr->ar_name + sizeof(AR_EFMT1) - 1,
2001 NULL, 10);
2002 ofile->member_name_size = ar_name_size;
2003 ofile->member_offset += ar_name_size;
2004 ofile->member_addr += ar_name_size;
2005 ofile->member_size -= ar_name_size;
2007 else{
2008 ofile->member_name_size = size_ar_name(ar_hdr);
2009 ar_name_size = 0;
2011 ofile->member_type = OFILE_UNKNOWN;
2012 ofile->object_addr = NULL;
2013 ofile->object_size = 0;
2014 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
2015 ofile->mh = NULL;
2016 ofile->mh64 = NULL;
2017 ofile->load_commands = NULL;
2019 host_byte_sex = get_host_byte_sex();
2021 if(ofile->member_size > sizeof(uint32_t)){
2022 memcpy(&magic, ofile->member_addr, sizeof(uint32_t));
2023 #ifdef __BIG_ENDIAN__
2024 if(magic == FAT_MAGIC)
2025 #endif /* __BIG_ENDIAN__ */
2026 #ifdef __LITTLE_ENDIAN__
2027 if(magic == SWAP_INT(FAT_MAGIC))
2028 #endif /* __LITTLE_ENDIAN__ */
2030 ofile->member_type = OFILE_FAT;
2031 ofile->fat_header = (struct fat_header *)(ofile->member_addr);
2032 #ifdef __LITTLE_ENDIAN__
2033 swap_fat_header(ofile->fat_header, host_byte_sex);
2034 #endif /* __LITTLE_ENDIAN__ */
2035 if(sizeof(struct fat_header) +
2036 ofile->fat_header->nfat_arch *
2037 sizeof(struct fat_arch) > ofile->member_size){
2038 archive_member_error(ofile, "fat file truncated or "
2039 "malformed (fat_arch structs would extend past "
2040 "the end of the archive member)");
2041 goto cleanup;
2043 ofile->fat_archs = (struct fat_arch *)(ofile->member_addr +
2044 sizeof(struct fat_header));
2045 #ifdef __LITTLE_ENDIAN__
2046 swap_fat_arch(ofile->fat_archs,
2047 ofile->fat_header->nfat_arch, host_byte_sex);
2048 #endif /* __LITTLE_ENDIAN__ */
2049 if(check_fat_object_in_archive(ofile) == FALSE)
2050 goto cleanup;
2052 else if(size - (offset + ar_name_size) >=
2053 sizeof(struct mach_header) &&
2054 (magic == MH_MAGIC ||
2055 magic == SWAP_INT(MH_MAGIC))){
2056 #ifdef ALIGNMENT_CHECKS
2057 if((offset + ar_name_size) % 4 != 0){
2058 archive_member_error(ofile, "offset in archive not "
2059 "a multiple of 4 (must be since member is an 32-bit "
2060 "object file)");
2061 goto cleanup;
2063 #endif /* ALIGNMENT_CHECKS */
2064 ofile->member_type = OFILE_Mach_O;
2065 ofile->object_addr = ofile->member_addr;
2066 ofile->object_size = ofile->member_size;
2067 if(magic == MH_MAGIC)
2068 ofile->object_byte_sex = host_byte_sex;
2069 else
2070 ofile->object_byte_sex =
2071 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
2072 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
2073 ofile->mh = (struct mach_header *)ofile->object_addr;
2074 ofile->load_commands = (struct load_command *)
2075 (ofile->object_addr + sizeof(struct mach_header));
2076 if(check_Mach_O(ofile) == CHECK_BAD)
2077 goto cleanup;
2079 else if(size - (offset + ar_name_size) >=
2080 sizeof(struct mach_header_64) &&
2081 (magic == MH_MAGIC_64 ||
2082 magic == SWAP_INT(MH_MAGIC_64))){
2083 #ifdef ALIGNMENT_CHECKS_ARCHIVE_64_BIT
2084 if(archive_64_bit_align_warning == FALSE &&
2085 (offset + ar_name_size) % 8 != 0){
2086 temporary_archive_member_warning(ofile, "offset in archive "
2087 "not a multiple of 8 (must be since member is an "
2088 "64-bit object file)");
2089 archive_64_bit_align_warning = TRUE;
2090 /* goto cleanup; */
2092 #endif /* ALIGNMENT_CHECKS_ARCHIVE_64_BIT */
2093 ofile->member_type = OFILE_Mach_O;
2094 ofile->object_addr = ofile->member_addr;
2095 ofile->object_size = ofile->member_size;
2096 if(magic == MH_MAGIC_64)
2097 ofile->object_byte_sex = host_byte_sex;
2098 else
2099 ofile->object_byte_sex =
2100 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
2101 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
2102 ofile->mh64 = (struct mach_header_64 *)ofile->object_addr;
2103 ofile->load_commands = (struct load_command *)
2104 (ofile->object_addr + sizeof(struct mach_header_64));
2105 if(check_Mach_O(ofile) == CHECK_BAD)
2106 goto cleanup;
2108 #ifdef LTO_SUPPORT
2109 if(ofile->member_type == OFILE_UNKNOWN &&
2110 is_llvm_bitcode(ofile, ofile->member_addr, ofile->member_size) ==
2111 TRUE){
2112 ofile->member_type = OFILE_LLVM_BITCODE;
2113 ofile->object_addr = ofile->member_addr;
2114 ofile->object_size = ofile->member_size;
2116 #endif /* LTO_SUPPORT */
2118 return(TRUE);
2120 cleanup:
2121 if(ofile->member_type == OFILE_FAT){
2122 ofile->fat_header = NULL;
2123 ofile->fat_archs = NULL;
2125 ofile->member_offset = 0;
2126 ofile->member_addr = NULL;
2127 ofile->member_size = 0;
2128 ofile->member_ar_hdr = NULL;
2129 ofile->member_name = NULL;
2130 ofile->member_name_size = 0;
2131 ofile->member_type = OFILE_UNKNOWN;
2132 ofile->object_addr = NULL;
2133 ofile->object_size = 0;
2134 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
2135 ofile->mh = NULL;
2136 ofile->mh64 = NULL;
2137 ofile->load_commands = NULL;
2138 #ifdef LTO_SUPPORT
2139 ofile->lto = NULL;
2140 ofile->lto_cputype = 0;
2141 ofile->lto_cpusubtype = 0;
2142 #endif /* LTO_SUPPORT */
2143 return(FALSE);
2147 * ofile_specific_member() set up the ofile structure (the member_* fields and
2148 * the object file fields if the member is an object file) for the specified
2149 * member member_name.
2151 __private_extern__
2152 enum bool
2153 ofile_specific_member(
2154 const char *member_name,
2155 struct ofile *ofile)
2157 int32_t i;
2158 char *addr;
2159 uint64_t size, offset;
2160 uint32_t magic;
2161 enum byte_sex host_byte_sex;
2162 char *ar_name;
2163 uint32_t ar_name_size;
2164 struct ar_hdr *ar_hdr;
2166 /* These fields are to be filled in by this routine, clear them first */
2167 ofile->member_offset = 0;
2168 ofile->member_addr = NULL;
2169 ofile->member_size = 0;
2170 ofile->member_ar_hdr = NULL;
2171 ofile->member_name = NULL;
2172 ofile->member_name_size = 0;
2173 ofile->member_type = OFILE_UNKNOWN;
2174 ofile->object_addr = NULL;
2175 ofile->object_size = 0;
2176 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
2177 ofile->mh = NULL;
2178 ofile->mh64 = NULL;
2179 ofile->load_commands = NULL;
2182 * Get the address and size of the archive.
2184 if(ofile->file_type == OFILE_FAT){
2185 if(ofile->arch_type != OFILE_ARCHIVE){
2186 error("ofile_specific_member() called on fat file: %s with a "
2187 "non-archive architecture or no architecture selected\n",
2188 ofile->file_name);
2189 return(FALSE);
2191 addr = ofile->file_addr + ofile->fat_archs[ofile->narch].offset;
2192 size = ofile->fat_archs[ofile->narch].size;
2194 else if(ofile->file_type == OFILE_ARCHIVE){
2195 addr = ofile->file_addr;
2196 size = ofile->file_size;
2198 else{
2199 error("ofile_specific_member() called and file type of %s is "
2200 "OFILE_UNKNOWN\n", ofile->file_name);
2201 return(FALSE);
2203 if(size < SARMAG || strncmp(addr, ARMAG, SARMAG) != 0){
2204 archive_error(ofile, "internal error. ofile_specific_member() "
2205 "called but file does not have an archive magic "
2206 "string");
2207 return(FALSE);
2210 offset = SARMAG;
2211 if(offset != size && offset + sizeof(struct ar_hdr) > size){
2212 archive_error(ofile, "truncated or malformed (archive header of "
2213 "first member extends past the end of the file)");
2214 return(FALSE);
2216 while(size > offset){
2217 ar_hdr = (struct ar_hdr *)(addr + offset);
2218 offset += sizeof(struct ar_hdr);
2219 if(strncmp(ar_hdr->ar_name, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0){
2220 #ifdef OTOOL
2221 if(check_extend_format_1(ofile, ar_hdr, size - offset,
2222 &ar_name_size) == CHECK_BAD){
2223 i = size_ar_name(ar_hdr);
2224 ar_name = ar_hdr->ar_name;
2225 ar_name_size = 0;
2227 else
2228 #endif /* OTOOL */
2230 i = strtoul(ar_hdr->ar_name + sizeof(AR_EFMT1) - 1,NULL,10);
2231 ar_name = ar_hdr->ar_name + sizeof(struct ar_hdr);
2232 ar_name_size = i;
2235 else{
2236 i = size_ar_name(ar_hdr);
2237 ar_name = ar_hdr->ar_name;
2238 ar_name_size = 0;
2240 if(i > 0 && strncmp(ar_name, member_name, i) == 0){
2242 ofile->member_name = ar_name;
2243 ofile->member_name_size = i;
2244 ofile->member_offset = offset + ar_name_size;
2245 ofile->member_addr = addr + offset + ar_name_size;
2246 ofile->member_size = strtoul(ar_hdr->ar_size, NULL, 10) -
2247 ar_name_size;
2248 ofile->member_ar_hdr = ar_hdr;
2249 ofile->member_type = OFILE_UNKNOWN;
2251 host_byte_sex = get_host_byte_sex();
2253 if(ofile->member_size > sizeof(uint32_t)){
2254 memcpy(&magic, addr + offset + ar_name_size,
2255 sizeof(uint32_t));
2256 #ifdef __BIG_ENDIAN__
2257 if(magic == FAT_MAGIC)
2258 #endif /* __BIG_ENDIAN__ */
2259 #ifdef __LITTLE_ENDIAN__
2260 if(magic == SWAP_INT(FAT_MAGIC))
2261 #endif /* __LITTLE_ENDIAN__ */
2263 ofile->member_type = OFILE_FAT;
2264 ofile->fat_header =
2265 (struct fat_header *)(addr + offset + ar_name_size);
2266 #ifdef __LITTLE_ENDIAN__
2267 swap_fat_header(ofile->fat_header, host_byte_sex);
2268 #endif /* __LITTLE_ENDIAN__ */
2269 if(sizeof(struct fat_header) +
2270 ofile->fat_header->nfat_arch *
2271 sizeof(struct fat_arch) > ofile->member_size){
2272 archive_member_error(ofile, "fat file truncated or "
2273 "malformed (fat_arch structs would extend "
2274 "past the end of the archive member)");
2275 goto fatcleanup;
2277 ofile->fat_archs =
2278 (struct fat_arch *)(addr + offset + ar_name_size +
2279 sizeof(struct fat_header));
2280 #ifdef __LITTLE_ENDIAN__
2281 swap_fat_arch(ofile->fat_archs,
2282 ofile->fat_header->nfat_arch,
2283 host_byte_sex);
2284 #endif /* __LITTLE_ENDIAN__ */
2285 if(check_fat_object_in_archive(ofile) == FALSE)
2286 goto fatcleanup;
2288 else if(size - (offset + ar_name_size) >=
2289 sizeof(struct mach_header) &&
2290 (magic == MH_MAGIC ||
2291 magic == SWAP_INT(MH_MAGIC))){
2292 #ifdef ALIGNMENT_CHECKS
2293 if((offset + ar_name_size) % 4 != 0){
2294 archive_member_error(ofile, "offset in archive not "
2295 "a multiple of 4) (must be since member is a "
2296 "32-bit object file)");
2297 goto cleanup;
2299 #endif /* ALIGNMENT_CHECKS */
2300 ofile->member_type = OFILE_Mach_O;
2301 ofile->object_addr = ofile->member_addr;
2302 ofile->object_size = ofile->member_size;
2303 if(magic == MH_MAGIC)
2304 ofile->object_byte_sex = host_byte_sex;
2305 else
2306 ofile->object_byte_sex =
2307 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
2308 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
2309 ofile->mh = (struct mach_header *)ofile->object_addr;
2310 ofile->load_commands = (struct load_command *)
2311 (ofile->object_addr + sizeof(struct mach_header));
2312 if(check_Mach_O(ofile) == CHECK_BAD)
2313 goto cleanup;
2315 else if(size - (offset + ar_name_size) >=
2316 sizeof(struct mach_header_64) &&
2317 (magic == MH_MAGIC_64 ||
2318 magic == SWAP_INT(MH_MAGIC_64))){
2319 #ifdef ALIGNMENT_CHECKS_ARCHIVE_64_BIT
2320 if(archive_64_bit_align_warning == FALSE &&
2321 (offset + ar_name_size) % 8 != 0){
2322 temporary_archive_member_warning(ofile, "offset in "
2323 "archive not a multiple of 8) (must be since "
2324 "member is a 64-bit object file)");
2325 archive_64_bit_align_warning = TRUE;
2326 /* goto cleanup; */
2328 #endif /* ALIGNMENT_CHECKS_ARCHIVE_64_BIT */
2329 ofile->member_type = OFILE_Mach_O;
2330 ofile->object_addr = ofile->member_addr;
2331 ofile->object_size = ofile->member_size;
2332 if(magic == MH_MAGIC_64)
2333 ofile->object_byte_sex = host_byte_sex;
2334 else
2335 ofile->object_byte_sex =
2336 host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
2337 LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
2338 ofile->mh64 = (struct mach_header_64 *)
2339 ofile->object_addr;
2340 ofile->load_commands = (struct load_command *)
2341 (ofile->object_addr +sizeof(struct mach_header_64));
2342 if(check_Mach_O(ofile) == CHECK_BAD)
2343 goto cleanup;
2346 #ifdef LTO_SUPPORT
2347 if(ofile->member_type == OFILE_UNKNOWN &&
2348 is_llvm_bitcode(ofile, ofile->member_addr,
2349 ofile->member_size) == TRUE){
2350 ofile->member_type = OFILE_LLVM_BITCODE;
2351 ofile->object_addr = ofile->member_addr;
2352 ofile->object_size = ofile->member_size;
2354 #endif /* LTO_SUPPORT */
2355 return(TRUE);
2357 offset += rnd(strtoul(ar_hdr->ar_size, NULL, 10),
2358 sizeof(short));
2360 archive_error(ofile, "does not contain a member named: %s",
2361 member_name);
2362 fatcleanup:
2363 ofile->fat_header = NULL;
2364 ofile->fat_archs = NULL;
2365 cleanup:
2366 ofile->member_offset = 0;
2367 ofile->member_addr = NULL;
2368 ofile->member_size = 0;
2369 ofile->member_ar_hdr = NULL;
2370 ofile->member_name = NULL;
2371 ofile->member_name_size = 0;
2372 ofile->member_type = OFILE_UNKNOWN;
2373 ofile->object_addr = NULL;
2374 ofile->object_size = 0;
2375 ofile->object_byte_sex = UNKNOWN_BYTE_SEX;
2376 ofile->mh = NULL;
2377 ofile->mh64 = NULL;
2378 ofile->load_commands = NULL;
2379 #ifdef LTO_SUPPORT
2380 ofile->lto = NULL;
2381 ofile->lto_cputype = 0;
2382 ofile->lto_cpusubtype = 0;
2383 #endif /* LTO_SUPPORT */
2384 return(FALSE);
2388 * ofile_first_module() set up the ofile structure (the dylib_module field)
2389 * for the first module of an MH_DYLIB or MH_DYLIB_STUB file.
2391 __private_extern__
2392 enum bool
2393 ofile_first_module(
2394 struct ofile *ofile)
2396 uint32_t i, ncmds;
2397 struct symtab_command *st;
2398 struct dysymtab_command *dyst;
2399 struct load_command *lc;
2400 enum bool swapped;
2401 enum byte_sex host_byte_sex;
2402 struct dylib_module m;
2403 struct dylib_module_64 m64;
2404 char *strings;
2406 /* These fields are to be filled in by this routine, clear them first */
2407 ofile->modtab = NULL;
2408 ofile->modtab64 = NULL;
2409 ofile->nmodtab = 0;
2410 ofile->dylib_module = NULL;
2411 ofile->dylib_module64 = NULL;
2412 ofile->dylib_module_name = NULL;
2414 if(ofile->file_type == OFILE_FAT){
2415 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 on fat file: %s with a "
2419 "non-MH_DYLIB architecture or no architecture selected\n",
2420 ofile->file_name);
2421 return(FALSE);
2424 else if(ofile->arch_type != OFILE_Mach_O &&
2425 (ofile->mh_filetype != MH_DYLIB &&
2426 ofile->mh_filetype != MH_DYLIB_STUB)){
2427 error("ofile_first_module() called and file type of %s is "
2428 "non-MH_DYLIB\n", ofile->file_name);
2429 return(FALSE);
2432 st = NULL;
2433 dyst = NULL;
2434 lc = ofile->load_commands;
2435 if(ofile->mh != NULL)
2436 ncmds = ofile->mh->ncmds;
2437 else
2438 ncmds = ofile->mh64->ncmds;
2439 for(i = 0; i < ncmds; i++){
2440 if(st == NULL && lc->cmd == LC_SYMTAB){
2441 st = (struct symtab_command *)lc;
2443 else if(lc->cmd == LC_DYSYMTAB){
2444 dyst = (struct dysymtab_command *)lc;
2446 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2448 if(st == NULL || dyst == NULL){
2449 #ifndef OTOOL
2450 Mach_O_error(ofile, "MH_DYLIB format error (does not have a symbol "
2451 "table and/or a dynamic symbol table)");
2452 #endif
2453 return(FALSE);
2455 if(dyst->nmodtab == 0)
2456 return(FALSE);
2458 ofile->nmodtab = dyst->nmodtab;
2459 host_byte_sex = get_host_byte_sex();
2460 swapped = (enum bool)(host_byte_sex != ofile->object_byte_sex);
2461 strings = (char *)(ofile->object_addr + st->stroff);
2463 if(ofile->mh != NULL){
2464 ofile->modtab = (struct dylib_module *)(ofile->object_addr +
2465 dyst->modtaboff);
2466 ofile->dylib_module = ofile->modtab;
2467 m = *ofile->dylib_module;
2468 if(swapped)
2469 swap_dylib_module(&m, 1, host_byte_sex);
2470 ofile->dylib_module_name = strings + m.module_name;
2472 else{
2473 ofile->modtab64 = (struct dylib_module_64 *)(ofile->object_addr +
2474 dyst->modtaboff);
2475 ofile->dylib_module64 = ofile->modtab64;
2476 m64 = *ofile->dylib_module64;
2477 if(swapped)
2478 swap_dylib_module_64(&m64, 1, host_byte_sex);
2479 ofile->dylib_module_name = strings + m64.module_name;
2482 if(check_dylib_module(ofile, st, dyst, strings, 0) == CHECK_BAD)
2483 return(FALSE);
2484 return(TRUE);
2488 * ofile_next_module() set up the ofile structure (the dylib_module field)
2489 * for the next module of an MH_DYLIB or MH_DYLIB_STUB file.
2491 __private_extern__
2492 enum bool
2493 ofile_next_module(
2494 struct ofile *ofile)
2496 uint32_t i, module_index, ncmds;
2497 struct symtab_command *st;
2498 struct dysymtab_command *dyst;
2499 struct load_command *lc;
2500 enum bool swapped;
2501 enum byte_sex host_byte_sex;
2502 struct dylib_module m;
2503 struct dylib_module_64 m64;
2504 char *strings;
2506 if(ofile->file_type == OFILE_FAT){
2507 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 on fat file: %s with a "
2511 "non-MH_DYLIB architecture or no architecture selected\n",
2512 ofile->file_name);
2513 return(FALSE);
2516 else if(ofile->arch_type != OFILE_Mach_O &&
2517 (ofile->mh_filetype != MH_DYLIB &&
2518 ofile->mh_filetype != MH_DYLIB_STUB)){
2519 error("ofile_next_module() called and file type of %s is "
2520 "non-MH_DYLIB\n", ofile->file_name);
2521 return(FALSE);
2523 st = NULL;
2524 dyst = NULL;
2525 lc = ofile->load_commands;
2526 if(ofile->mh != NULL)
2527 ncmds = ofile->mh->ncmds;
2528 else
2529 ncmds = ofile->mh64->ncmds;
2530 for(i = 0; i < ncmds; i++){
2531 if(st == NULL && lc->cmd == LC_SYMTAB){
2532 st = (struct symtab_command *)lc;
2534 else if(lc->cmd == LC_DYSYMTAB){
2535 dyst = (struct dysymtab_command *)lc;
2537 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2539 if(st == NULL || dyst == NULL){
2540 #ifndef OTOOL
2541 Mach_O_error(ofile, "MH_DYLIB format error (does not have a symbol "
2542 "table and/or a dynamic symbol table)");
2543 #endif
2544 return(FALSE);
2547 if(ofile->mh != NULL)
2548 module_index = (ofile->dylib_module + 1) - ofile->modtab;
2549 else
2550 module_index = (ofile->dylib_module64 + 1) - ofile->modtab64;
2551 if(module_index >= ofile->nmodtab)
2552 return(FALSE);
2554 host_byte_sex = get_host_byte_sex();
2555 swapped = (enum bool)(host_byte_sex != ofile->object_byte_sex);
2556 strings = (char *)(ofile->object_addr + st->stroff);
2558 if(ofile->mh != NULL){
2559 ofile->dylib_module++;
2560 m = *ofile->dylib_module;
2561 if(swapped)
2562 swap_dylib_module(&m, 1, host_byte_sex);
2563 ofile->dylib_module_name = strings + m.module_name;
2565 else{
2566 ofile->dylib_module64++;
2567 m64 = *ofile->dylib_module64;
2568 if(swapped)
2569 swap_dylib_module_64(&m64, 1, host_byte_sex);
2570 ofile->dylib_module_name = strings + m64.module_name;
2572 if(check_dylib_module(ofile, st, dyst, strings, module_index) ==
2573 CHECK_BAD)
2574 return(FALSE);
2575 return(TRUE);
2579 * ofile_specific_module() set up the ofile structure (the dylib_module fields)
2580 * for the specified module, module_name, of an MH_DYLIB or an MH_DYLIB_STUB
2581 * file.
2583 __private_extern__
2584 enum bool
2585 ofile_specific_module(
2586 const char *module_name,
2587 struct ofile *ofile)
2589 uint32_t i, ncmds;
2590 enum bool swapped;
2591 enum byte_sex host_byte_sex;
2592 struct symtab_command *st;
2593 struct dysymtab_command *dyst;
2594 struct load_command *lc;
2595 struct dylib_module *p, m;
2596 struct dylib_module_64 *p64, m64;
2597 char *strings;
2599 /* These fields are to be filled in by this routine, clear them first */
2600 ofile->modtab = NULL;
2601 ofile->modtab64 = NULL;
2602 ofile->nmodtab = 0;
2603 ofile->dylib_module = NULL;
2604 ofile->dylib_module64 = NULL;
2605 ofile->dylib_module_name = NULL;
2607 if(ofile->file_type == OFILE_FAT){
2608 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 on fat file: %s with a "
2612 "non-MH_DYLIB architecture or no architecture selected\n",
2613 ofile->file_name);
2614 return(FALSE);
2617 else if(ofile->arch_type != OFILE_Mach_O &&
2618 (ofile->mh_filetype != MH_DYLIB &&
2619 ofile->mh_filetype != MH_DYLIB_STUB)){
2620 error("ofile_specific_module() called and file type of %s is "
2621 "non-MH_DYLIB\n", ofile->file_name);
2622 return(FALSE);
2625 st = NULL;
2626 dyst = NULL;
2627 lc = ofile->load_commands;
2628 if(ofile->mh != NULL)
2629 ncmds = ofile->mh->ncmds;
2630 else
2631 ncmds = ofile->mh64->ncmds;
2632 for(i = 0; i < ncmds; i++){
2633 if(st == NULL && lc->cmd == LC_SYMTAB){
2634 st = (struct symtab_command *)lc;
2636 else if(lc->cmd == LC_DYSYMTAB){
2637 dyst = (struct dysymtab_command *)lc;
2639 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2641 if(st == NULL || dyst == NULL){
2642 #ifndef OTOOL
2643 Mach_O_error(ofile, "MH_DYLIB format error (does not have a symbol "
2644 "table and/or a dynamic symbol table)");
2645 #endif
2646 return(FALSE);
2648 if(dyst->nmodtab == 0)
2649 return(FALSE);
2651 host_byte_sex = get_host_byte_sex();
2652 swapped = (enum bool)(host_byte_sex != ofile->object_byte_sex);
2653 strings = (char *)(ofile->object_addr + st->stroff);
2655 if(ofile->mh != NULL){
2656 ofile->nmodtab = dyst->nmodtab;
2657 ofile->modtab = (struct dylib_module *)(ofile->object_addr +
2658 dyst->modtaboff);
2659 p = ofile->modtab;
2660 for(i = 0; i < dyst->nmodtab; i++){
2661 m = *p;
2662 if(swapped)
2663 swap_dylib_module(&m, 1, host_byte_sex);
2664 ofile->dylib_module = p;
2665 if(check_dylib_module(ofile, st, dyst, strings, i) == CHECK_BAD)
2666 return(FALSE);
2667 if(strcmp(module_name, strings + m.module_name) == 0){
2668 ofile->dylib_module_name = strings + m.module_name;
2669 return(TRUE);
2671 p++;
2673 m = *ofile->dylib_module;
2674 if(swapped)
2675 swap_dylib_module(&m, 1, host_byte_sex);
2676 ofile->dylib_module_name = strings + m.module_name;
2678 else{
2679 ofile->nmodtab = dyst->nmodtab;
2680 ofile->modtab64 = (struct dylib_module_64 *)(ofile->object_addr +
2681 dyst->modtaboff);
2682 p64 = ofile->modtab64;
2683 for(i = 0; i < dyst->nmodtab; i++){
2684 m64 = *p64;
2685 if(swapped)
2686 swap_dylib_module_64(&m64, 1, host_byte_sex);
2687 ofile->dylib_module64 = p64;
2688 if(check_dylib_module(ofile, st, dyst, strings, i) == CHECK_BAD)
2689 return(FALSE);
2690 if(strcmp(module_name, strings + m64.module_name) == 0){
2691 ofile->dylib_module_name = strings + m64.module_name;
2692 return(TRUE);
2694 p64++;
2696 m64 = *ofile->dylib_module64;
2697 if(swapped)
2698 swap_dylib_module_64(&m64, 1, host_byte_sex);
2699 ofile->dylib_module_name = strings + m64.module_name;
2701 #ifndef OTOOL
2702 Mach_O_error(ofile, "does not contain a module named: %s", module_name);
2703 #endif
2704 ofile->modtab = NULL;
2705 ofile->nmodtab = 0;
2706 ofile->dylib_module = NULL;
2707 ofile->dylib_module_name = NULL;
2708 return(FALSE);
2711 #ifdef DEBUG
2712 __private_extern__
2713 void
2714 ofile_print(
2715 struct ofile *ofile)
2717 printf("file_name = %s\n", ofile->file_name);
2718 printf("file_addr = 0x%x\n", (unsigned int)ofile->file_addr);
2719 printf("file_size = 0x%x\n", (unsigned int)ofile->file_size);
2720 printf("file_type = 0x%x\n", (unsigned int)ofile->file_type);
2721 printf("fat_header = 0x%x\n", (unsigned int)ofile->fat_header);
2722 printf("fat_archs = 0x%x\n", (unsigned int)ofile->fat_archs);
2723 printf("narch = 0x%x\n", (unsigned int)ofile->narch);
2724 printf("arch_type = 0x%x\n", (unsigned int)ofile->arch_type);
2725 printf("arch_flag.name = %s\n", ofile->arch_flag.name);
2726 printf("arch_flag.cputype = 0x%x\n",
2727 (unsigned int)ofile->arch_flag.cputype);
2728 printf("arch_flag.cpusubtype = 0x%x\n",
2729 (unsigned int)ofile->arch_flag.cpusubtype);
2730 printf("member_offset = 0x%x\n", (unsigned int)ofile->member_offset);
2731 printf("member_addr = 0x%x\n", (unsigned int)ofile->member_addr);
2732 printf("member_size = 0x%x\n", (unsigned int)ofile->member_size);
2733 printf("member_ar_hdr = 0x%x\n", (unsigned int)ofile->member_ar_hdr);
2734 printf("member_type = 0x%x\n", (unsigned int)ofile->member_type);
2735 printf("archive_cputype = 0x%x\n",
2736 (unsigned int)ofile->archive_cputype);
2737 printf("archive_cpusubtype = 0x%x\n",
2738 (unsigned int)ofile->archive_cpusubtype);
2739 printf("object_addr = 0x%x\n", (unsigned int)ofile->object_addr);
2740 printf("object_size = 0x%x\n", (unsigned int)ofile->object_size);
2741 printf("object_byte_sex = 0x%x\n",
2742 (unsigned int)ofile->object_byte_sex);
2743 printf("mh = 0x%x\n", (unsigned int)ofile->mh);
2744 printf("mh64 = 0x%x\n", (unsigned int)ofile->mh64);
2745 printf("load_commands = 0x%x\n", (unsigned int)ofile->load_commands);
2747 #endif /* DEBUG */
2750 * check_fat() checks the fat ofile for correctness (the fat_header and
2751 * fat_archs are assumed to be in the host byte sex).
2753 static
2754 enum check_type
2755 check_fat(
2756 struct ofile *ofile)
2758 #ifdef OTOOL
2759 return(CHECK_GOOD);
2760 #else /* !defined OTOOL */
2762 uint32_t i, j;
2763 uint64_t big_size;
2765 if(ofile->file_type != OFILE_FAT){
2766 error("internal error. check_fat() call and file type of: %s is "
2767 "not OFILE_FAT\n", ofile->file_name);
2768 return(CHECK_BAD);
2770 if(ofile->fat_header->nfat_arch == 0){
2771 error("fat file: %s malformed (contains zero architecture types)",
2772 ofile->file_name);
2773 return(CHECK_BAD);
2775 for(i = 0; i < ofile->fat_header->nfat_arch; i++){
2776 big_size = ofile->fat_archs[i].offset;
2777 big_size += ofile->fat_archs[i].size;
2778 if(big_size > ofile->file_size){
2779 error("fat file: %s truncated or malformed (offset plus size "
2780 "of cputype (%d) cpusubtype (%d) extends past the "
2781 "end of the file)", ofile->file_name,
2782 ofile->fat_archs[i].cputype,
2783 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK);
2784 return(CHECK_BAD);
2786 if(ofile->fat_archs[i].align > MAXSECTALIGN){
2787 error("fat file: %s align (2^%u) too large for cputype (%d) "
2788 "cpusubtype (%d) (maximum 2^%d)", ofile->file_name,
2789 ofile->fat_archs[i].align, ofile->fat_archs[i].cputype,
2790 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK,
2791 MAXSECTALIGN);
2792 return(CHECK_BAD);
2794 if(ofile->fat_archs[i].offset %
2795 (1 << ofile->fat_archs[i].align) != 0){
2796 error("fat file: %s offset: %u for cputype (%d) cpusubtype "
2797 "(%d)) not aligned on it's alignment (2^%u)",
2798 ofile->file_name,
2799 ofile->fat_archs[i].offset,
2800 ofile->fat_archs[i].cputype,
2801 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK,
2802 ofile->fat_archs[i].align);
2803 return(CHECK_BAD);
2806 for(i = 0; i < ofile->fat_header->nfat_arch; i++){
2807 for(j = i + 1; j < ofile->fat_header->nfat_arch; j++){
2808 if(ofile->fat_archs[i].cputype ==
2809 ofile->fat_archs[j].cputype &&
2810 (ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK) ==
2811 (ofile->fat_archs[j].cpusubtype & ~CPU_SUBTYPE_MASK)){
2812 error("fat file: %s contains two of the same "
2813 "architecture (cputype (%d) cpusubtype (%d))",
2814 ofile->file_name, ofile->fat_archs[i].cputype,
2815 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK);
2816 return(CHECK_BAD);
2820 return(CHECK_GOOD);
2821 #endif /* OTOOL */
2825 * check_fat_object_in_archive() checks the fat object file which is a member
2826 * of a thin archive for correctness (the fat_header and fat_archs are assumed
2827 * to be in the host byte sex). This is not a legal form but allowed when
2828 * archives_with_fat_objects is TRUE when ofile_map() is called.
2830 static
2831 enum check_type
2832 check_fat_object_in_archive(
2833 struct ofile *ofile)
2835 uint32_t i, j;
2836 uint32_t magic;
2838 if(ofile->file_type != OFILE_ARCHIVE){
2839 error("internal error. check_fat_object_in_archive() called and "
2840 "file type of: %s is not OFILE_ARCHIVE\n", ofile->file_name);
2841 return(CHECK_BAD);
2843 if(ofile->fat_header->nfat_arch == 0){
2844 archive_member_error(ofile, "fat file malformed (contains zero "
2845 "architecture types)");
2846 return(CHECK_BAD);
2848 for(i = 0; i < ofile->fat_header->nfat_arch; i++){
2849 if(ofile->fat_archs[i].offset + ofile->fat_archs[i].size >
2850 ofile->member_size){
2851 archive_member_error(ofile, "fat file truncated or malformed "
2852 "(offset plus size of cputype (%d) cpusubtype (%d) "
2853 "extends past the end of the file)",
2854 ofile->fat_archs[i].cputype,
2855 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK);
2856 return(CHECK_BAD);
2858 if(ofile->fat_archs[i].align > MAXSECTALIGN){
2859 archive_member_error(ofile, "fat file's align (2^%u) too "
2860 "large for cputype (%d) cpusubtype (%d) (maximum 2^%d)",
2861 ofile->fat_archs[i].align, ofile->fat_archs[i].cputype,
2862 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK,
2863 MAXSECTALIGN);
2864 return(CHECK_BAD);
2866 if(ofile->fat_archs[i].offset %
2867 (1 << ofile->fat_archs[i].align) != 0){
2868 archive_member_error(ofile, "fat file's offset: %u for "
2869 "cputype (%d) cpusubtype (%d) not aligned on it's "
2870 "alignment (2^%u)", ofile->fat_archs[i].offset,
2871 ofile->fat_archs[i].cputype,
2872 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK,
2873 ofile->fat_archs[i].align);
2874 return(CHECK_BAD);
2878 * The only supported format where fat files are allowed to appear
2879 * in archives is when the fat file contains only object files.
2881 if(ofile->fat_archs[i].size < sizeof(struct mach_header)){
2882 archive_member_error(ofile, "fat file for cputype (%d) "
2883 "cpusubtype (%d) is not an object file (size too small "
2884 "to be an object file)", ofile->fat_archs[i].cputype,
2885 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK);
2886 return(CHECK_BAD);
2888 memcpy(&magic,
2889 ofile->file_addr + ofile->member_offset +
2890 ofile->fat_archs[i].offset,
2891 sizeof(uint32_t));
2892 if(magic == MH_MAGIC || magic == SWAP_INT(MH_MAGIC)){
2893 #ifdef ALIGNMENT_CHECKS
2894 if((ofile->member_offset + ofile->fat_archs[i].offset) %
2895 4 != 0){
2896 archive_member_error(ofile, "fat object file's offset in "
2897 "archive not a multiple of 4) (must be since "
2898 "member is a 32-bit object file)");
2899 return(CHECK_BAD);
2901 #endif /* ALIGNMENT_CHECKS */
2903 else if(magic == MH_MAGIC_64 || magic == SWAP_INT(MH_MAGIC_64)){
2904 #ifdef ALIGNMENT_CHECKS_ARCHIVE_64_BIT
2905 if(archive_64_bit_align_warning == FALSE &&
2906 (ofile->member_offset + ofile->fat_archs[i].offset) %
2907 8 != 0){
2908 temporary_archive_member_warning(ofile, "fat object file's "
2909 "offset in archive not a multiple of 8) (must be since "
2910 "member is a 64-bit object file)");
2911 archive_64_bit_align_warning = TRUE;
2912 /* return(CHECK_BAD); */
2914 #endif /* ALIGNMENT_CHECKS_ARCHIVE_64_BIT */
2916 else{
2917 #ifdef LTO_SUPPORT
2918 if(is_llvm_bitcode(ofile, ofile->file_addr +
2919 ofile->member_offset + ofile->fat_archs[i].offset,
2920 ofile->fat_archs[i].size) == TRUE){
2921 ofile->member_type = OFILE_LLVM_BITCODE;
2922 ofile->object_addr = ofile->member_addr;
2923 ofile->object_size = ofile->member_size;
2925 else
2926 #endif /* LTO_SUPPORT */
2928 archive_member_error(ofile, "fat file for cputype (%d) "
2929 "cpusubtype (%d) is not an object file (bad magic "
2930 "number)", ofile->fat_archs[i].cputype,
2931 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK);
2932 return(CHECK_BAD);
2936 for(i = 0; i < ofile->fat_header->nfat_arch; i++){
2937 for(j = i + 1; j < ofile->fat_header->nfat_arch; j++){
2938 if(ofile->fat_archs[i].cputype ==
2939 ofile->fat_archs[j].cputype &&
2940 (ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK) ==
2941 (ofile->fat_archs[j].cpusubtype & ~CPU_SUBTYPE_MASK)){
2942 archive_member_error(ofile, "fat file contains two of the "
2943 "same architecture (cputype (%d) cpusubtype (%d))",
2944 ofile->fat_archs[i].cputype,
2945 ofile->fat_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK);
2946 return(CHECK_BAD);
2950 return(CHECK_GOOD);
2954 * check_archive() checks the archive referenced in the ofile for correctness.
2956 static
2957 enum check_type
2958 check_archive(
2959 struct ofile *ofile,
2960 enum bool archives_with_fat_objects)
2962 #ifdef OTOOL
2963 return(CHECK_GOOD);
2964 #else /* !defined OTOOL */
2965 char *addr;
2966 uint64_t size, offset;
2967 uint64_t big_size;
2968 uint32_t magic;
2969 enum byte_sex host_byte_sex;
2970 enum bool swapped;
2971 struct mach_header mh;
2972 struct mach_header_64 mh64;
2973 struct ar_hdr *ar_hdr;
2974 uint32_t ar_name_size;
2977 * Get the address and size of the archive (as well as the cputype and
2978 * cpusubtype if known) and make sure it is an archive.
2980 if(ofile->file_type == OFILE_FAT){
2981 addr = ofile->file_addr + ofile->fat_archs[ofile->narch].offset;
2982 size = ofile->fat_archs[ofile->narch].size;
2983 ofile->archive_cputype = ofile->fat_archs[ofile->narch].cputype;
2984 ofile->archive_cpusubtype =
2985 ofile->fat_archs[ofile->narch].cpusubtype;
2987 else if(ofile->file_type == OFILE_ARCHIVE){
2988 addr = ofile->file_addr;
2989 size = ofile->file_size;
2990 ofile->archive_cputype = 0;
2991 ofile->archive_cpusubtype = 0;
2993 else{
2994 error("internal error. check_archive() call and file type of %s is "
2995 "OFILE_UNKNOWN\n", ofile->file_name);
2996 return(CHECK_BAD);
2998 if(size < SARMAG || strncmp(addr, ARMAG, SARMAG) != 0){
2999 error("internal error. check_archive() call for file %s which does "
3000 "not have an archive magic string", ofile->file_name);
3001 return(CHECK_BAD);
3004 host_byte_sex = get_host_byte_sex();
3006 * Check this archive out to make sure that it does not contain
3007 * any fat files and that all object files it contains have the
3008 * same cputype and subsubtype.
3010 offset = SARMAG;
3011 if(offset == size)
3012 return(CHECK_GOOD);
3013 if(offset != size && offset + sizeof(struct ar_hdr) > size){
3014 archive_error(ofile, "truncated or malformed (archive header of "
3015 "first member extends past the end of the file)");
3016 return(CHECK_BAD);
3018 while(size > offset){
3019 ar_hdr = (struct ar_hdr *)(addr + offset);
3020 ofile->member_offset = offset;
3021 ofile->member_addr = addr + offset;
3022 ofile->member_size = strtoul(ar_hdr->ar_size, NULL, 10);
3023 ofile->member_ar_hdr = ar_hdr;
3024 ofile->member_name = ar_hdr->ar_name;
3025 ofile->member_name_size = size_ar_name(ofile->member_ar_hdr);
3026 offset += sizeof(struct ar_hdr);
3028 * See if this archive member is using extend format #1 where
3029 * the size of the name is in ar_name and the name follows the
3030 * archive header.
3032 ar_name_size = 0;
3033 if(strncmp(ofile->member_name,AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0){
3034 if(check_extend_format_1(ofile, ar_hdr, size - offset,
3035 &ar_name_size) == CHECK_BAD)
3036 return(CHECK_BAD);
3037 ofile->member_name = ar_hdr->ar_name + sizeof(struct ar_hdr);
3038 ofile->member_name_size = ar_name_size;
3039 offset += ar_name_size;
3040 ofile->member_offset += ar_name_size;
3041 ofile->member_addr += ar_name_size;
3042 ofile->member_size -= ar_name_size;
3044 big_size = rnd(ofile->member_size, sizeof(short));
3045 big_size += offset;
3046 if(big_size > size){
3047 archive_member_error(ofile, "size too large (archive "
3048 "member extends past the end of the file)");
3049 return(CHECK_BAD);
3051 if(size - offset > sizeof(uint32_t)){
3052 memcpy(&magic, addr + offset, sizeof(uint32_t));
3053 #ifdef __BIG_ENDIAN__
3054 if(magic == FAT_MAGIC)
3055 #endif /* __BIG_ENDIAN__ */
3056 #ifdef __LITTLE_ENDIAN__
3057 if(magic == SWAP_INT(FAT_MAGIC))
3058 #endif /* __LITTLE_ENDIAN__ */
3060 if(archives_with_fat_objects == FALSE ||
3061 ofile->file_type != OFILE_ARCHIVE){
3062 archive_member_error(ofile, "is a fat file (not "
3063 "allowed in an archive)");
3064 return(CHECK_BAD);
3067 else{
3068 if(size - offset >= sizeof(struct mach_header) &&
3069 (magic == MH_MAGIC || magic == SWAP_INT(MH_MAGIC))){
3070 memcpy(&mh, addr + offset, sizeof(struct mach_header));
3071 if(magic == SWAP_INT(MH_MAGIC)){
3072 magic = MH_MAGIC;
3073 swapped = TRUE;
3074 swap_mach_header(&mh, host_byte_sex);
3076 swapped = FALSE;
3078 else if(size - offset >= sizeof(struct mach_header_64) &&
3079 (magic == MH_MAGIC_64 ||
3080 magic == SWAP_INT(MH_MAGIC_64))){
3081 memcpy(&mh64, addr + offset,
3082 sizeof(struct mach_header_64));
3083 if(magic == SWAP_INT(MH_MAGIC_64)){
3084 magic = MH_MAGIC_64;
3085 swapped = TRUE;
3086 swap_mach_header_64(&mh64, host_byte_sex);
3088 swapped = FALSE;
3090 if(magic == MH_MAGIC){
3091 if(ofile->archive_cputype == 0){
3092 ofile->archive_cputype = mh.cputype;
3093 ofile->archive_cpusubtype = mh.cpusubtype;
3095 else if(ofile->archive_cputype != mh.cputype){
3096 archive_member_error(ofile, "cputype (%d) does not "
3097 "match previous archive members cputype (%d) "
3098 "(all members must match)", mh.cputype,
3099 ofile->archive_cputype);
3102 else if(magic == MH_MAGIC_64){
3103 if(ofile->archive_cputype == 0){
3104 ofile->archive_cputype = mh64.cputype;
3105 ofile->archive_cpusubtype = mh64.cpusubtype;
3107 else if(ofile->archive_cputype != mh64.cputype){
3108 archive_member_error(ofile, "cputype (%d) does not "
3109 "match previous archive members cputype (%d) "
3110 "(all members must match)", mh64.cputype,
3111 ofile->archive_cputype);
3116 offset += rnd(ofile->member_size, sizeof(short));
3118 ofile->member_offset = 0;
3119 ofile->member_addr = NULL;
3120 ofile->member_size = 0;
3121 ofile->member_ar_hdr = NULL;;
3122 ofile->member_name = NULL;
3123 ofile->member_name_size = 0;
3124 return(CHECK_GOOD);
3125 #endif /* OTOOL */
3129 * check_extend_format_1() checks the archive header for extended format #1.
3131 static
3132 enum check_type
3133 check_extend_format_1(
3134 struct ofile *ofile,
3135 struct ar_hdr *ar_hdr,
3136 uint32_t size_left,
3137 uint32_t *member_name_size)
3139 char *p, *endp, buf[sizeof(ar_hdr->ar_name)+1];
3140 uint32_t ar_name_size;
3142 *member_name_size = 0;
3144 buf[sizeof(ar_hdr->ar_name)] = '\0';
3145 memcpy(buf, ar_hdr->ar_name, sizeof(ar_hdr->ar_name));
3146 p = buf + sizeof(AR_EFMT1) - 1;
3147 if(isdigit(*p) == 0){
3148 archive_error(ofile, "malformed (ar_name: %.*s for archive "
3149 "extend format #1 starts with non-digit)",
3150 (int)sizeof(ar_hdr->ar_name), ar_hdr->ar_name);
3151 return(CHECK_BAD);
3153 ar_name_size = strtoul(p, &endp, 10);
3154 if(ar_name_size == UINT_MAX && errno == ERANGE){
3155 archive_error(ofile, "malformed (size in ar_name: %.*s for "
3156 "archive extend format #1 overflows uint32_t)",
3157 (int)sizeof(ar_hdr->ar_name), ar_hdr->ar_name);
3158 return(CHECK_BAD);
3160 while(*endp == ' ' && *endp != '\0')
3161 endp++;
3162 if(*endp != '\0'){
3163 archive_error(ofile, "malformed (size in ar_name: %.*s for "
3164 "archive extend format #1 contains non-digit and "
3165 "non-space characters)", (int)sizeof(ar_hdr->ar_name),
3166 ar_hdr->ar_name);
3167 return(CHECK_BAD);
3169 if(ar_name_size > size_left){
3170 archive_error(ofile, "truncated or malformed (archive name "
3171 "of member extends past the end of the file)");
3172 return(CHECK_BAD);
3174 *member_name_size = ar_name_size;
3175 return(CHECK_GOOD);
3179 * check_archive_toc() checks the archive table of contents referenced in the
3180 * thin archive via the ofile for correctness and if bad sets the bad_toc field
3181 * in the ofile struct to TRUE. If not it sets the other toc_* fields that
3182 * ranlib(1) uses to know it can't update the table of contents and doesn't
3183 * have to totally rebuild it. And by this always returning CHECK_GOOD it
3184 * allows otool(1) to print messed up tables of contents for debugging.
3186 static
3187 enum check_type
3188 check_archive_toc(
3189 struct ofile *ofile)
3191 uint32_t i, symdef_length, offset, nranlibs, strsize;
3192 enum byte_sex host_byte_sex, toc_byte_sex;
3193 struct ranlib *ranlibs;
3194 char *strings;
3196 ofile->toc_ranlibs = NULL;
3197 ofile->toc_nranlibs = 0;
3198 ofile->toc_strings = NULL;
3199 ofile->toc_strsize = 0;
3202 * Note this can only be called when the whole file is a thin archive.
3204 if(ofile->file_type != OFILE_ARCHIVE)
3205 return(CHECK_GOOD);
3207 symdef_length = ofile->toc_size;
3209 * The contents of a __.SYMDEF file is begins with a 32-bit word giving
3210 * the size in bytes of ranlib structures which immediately follow, and
3211 * then continues with a string table consisting of a 32-bit word giving
3212 * the number of bytes of strings which follow and then the strings
3213 * themselves. So the smallest valid size is two 32-bit words long.
3215 if(symdef_length < 2 * sizeof(uint32_t)){
3217 * Size of table of contents for archive too small to be a valid
3218 * table of contents.
3220 ofile->toc_bad = TRUE;
3221 return(CHECK_GOOD);
3223 host_byte_sex = get_host_byte_sex();
3224 toc_byte_sex = get_toc_byte_sex(ofile->file_addr, ofile->file_size);
3225 if(toc_byte_sex == UNKNOWN_BYTE_SEX){
3227 * Can't determine the byte order of table of contents as it
3228 * contains no Mach-O files.
3230 ofile->toc_bad = TRUE;
3231 return(CHECK_GOOD);
3233 offset = 0;
3234 nranlibs = *((uint32_t *)(ofile->toc_addr + offset));
3235 if(toc_byte_sex != host_byte_sex)
3236 nranlibs = SWAP_INT(nranlibs);
3237 nranlibs = nranlibs / sizeof(struct ranlib);
3238 offset += sizeof(uint32_t);
3239 ranlibs = (struct ranlib *)(ofile->toc_addr + offset);
3240 offset += sizeof(struct ranlib) * nranlibs;
3241 if(nranlibs == 0)
3242 return(CHECK_GOOD);
3243 if(offset - (2 * sizeof(uint32_t)) > symdef_length){
3245 * Truncated or malformed archive. The ranlib structures in table
3246 * of contents extends past the end of the table of contents.
3248 ofile->toc_bad = TRUE;
3249 return(CHECK_GOOD);
3251 strsize = *((uint32_t *)(ofile->toc_addr + offset));
3252 if(toc_byte_sex != host_byte_sex)
3253 strsize = SWAP_INT(strsize);
3254 offset += sizeof(uint32_t);
3255 strings = ofile->toc_addr + offset;
3256 offset += strsize;
3257 if(offset - (2 * sizeof(uint32_t)) > symdef_length){
3259 * Truncated or malformed archive. The ranlib strings in table of
3260 * contents extends past the end of the table of contents.
3262 ofile->toc_bad = TRUE;
3263 return(CHECK_GOOD);
3265 if(symdef_length == 2 * sizeof(uint32_t))
3266 return(CHECK_GOOD);
3269 * Check the string offset and the member offsets of the ranlib structs.
3271 if(toc_byte_sex != host_byte_sex)
3272 swap_ranlib(ranlibs, nranlibs, host_byte_sex);
3273 for(i = 0; i < nranlibs; i++){
3274 if(ranlibs[i].ran_un.ran_strx >= strsize){
3276 * Malformed table of contents. The ranlib struct at this index
3277 * has a bad string index field.
3279 ofile->toc_bad = TRUE;
3280 return(CHECK_GOOD);
3282 if(ranlibs[i].ran_off >= ofile->file_size){
3284 * Malformed table of contents. The ranlib struct at this index
3285 * has a bad library member offset field.
3287 ofile->toc_bad = TRUE;
3288 return(CHECK_GOOD);
3291 * These should be on 4 byte boundaries because the maximum
3292 * alignment of the header structures and relocation are 4 bytes.
3293 * But this is has to be 2 bytes because that's the way ar(1) has
3294 * worked historicly in the past. Fortunately this works on the
3295 * 68k machines but will have to change when this is on a real
3296 * machine.
3298 #if defined(mc68000) || defined(__i386__)
3299 if(ranlibs[i].ran_off % sizeof(short) != 0){
3301 * Malformed table of contents. This ranlib struct library
3302 * member offset not a multiple 2 bytes.
3304 ofile->toc_bad = TRUE;
3305 return(CHECK_GOOD);
3307 #else
3308 if(ranlibs[i].ran_off % sizeof(uint32_t) != 0){
3310 * Malformed table of contents. This ranlib struct library
3311 * member offset not a multiple of 4 bytes.
3313 ofile->toc_bad = TRUE;
3314 return(CHECK_GOOD);
3316 #endif
3318 ofile->toc_ranlibs = ranlibs;
3319 ofile->toc_nranlibs = nranlibs;
3320 ofile->toc_strings = strings;
3321 ofile->toc_strsize = strsize;
3322 return(CHECK_GOOD);
3326 * check_Mach_O() checks the object file's mach header and load commands
3327 * referenced in the ofile for correctness (this also swaps the mach header
3328 * and load commands into the host byte sex if needed).
3330 static
3331 enum check_type
3332 check_Mach_O(
3333 struct ofile *ofile)
3335 #ifdef OTOOL
3336 return(CHECK_GOOD);
3337 #else /* !defined OTOOL */
3338 uint32_t size, i, j, ncmds, sizeofcmds, load_command_multiple, sizeofhdrs;
3339 cpu_type_t cputype;
3340 char *addr, *cmd_name, *element_name;
3341 enum byte_sex host_byte_sex;
3342 enum bool swapped;
3343 struct mach_header *mh;
3344 struct mach_header_64 *mh64;
3345 struct load_command *load_commands, *lc, l;
3346 struct segment_command *sg;
3347 struct segment_command_64 *sg64;
3348 struct section *s;
3349 struct section_64 *s64;
3350 struct symtab_command *st;
3351 struct dysymtab_command *dyst;
3352 struct symseg_command *ss;
3353 struct fvmlib_command *fl;
3354 struct dylib_command *dl;
3355 struct sub_framework_command *sub;
3356 struct sub_umbrella_command *usub;
3357 struct sub_library_command *lsub;
3358 struct sub_client_command *csub;
3359 struct prebound_dylib_command *pbdylib;
3360 struct dylinker_command *dyld;
3361 struct thread_command *ut;
3362 struct ident_command *id;
3363 struct routines_command *rc;
3364 struct routines_command_64 *rc64;
3365 struct twolevel_hints_command *hints;
3366 struct linkedit_data_command *code_sig, *split_info, *func_starts,
3367 *data_in_code, *code_sign_drs, *linkedit_data;
3368 struct version_min_command *vers;
3369 struct prebind_cksum_command *cs;
3370 struct encryption_info_command *encrypt_info;
3371 struct encryption_info_command_64 *encrypt_info64;
3372 struct dyld_info_command *dyld_info;
3373 struct uuid_command *uuid;
3374 struct rpath_command *rpath;
3375 struct entry_point_command *ep;
3376 struct source_version_command *sv;
3377 uint32_t flavor, count, nflavor;
3378 char *p, *state;
3379 uint32_t sizeof_nlist, sizeof_dylib_module;
3380 char *struct_dylib_module_name, *struct_nlist_name;
3381 uint64_t big_size, big_end, big_load_end;
3382 struct element elements;
3384 elements.offset = 0;
3385 elements.size = 0;
3386 elements.name = NULL;
3387 elements.next = NULL;
3389 addr = ofile->object_addr;
3390 size = ofile->object_size;
3391 mh = ofile->mh;
3392 mh64 = ofile->mh64;
3393 load_commands = ofile->load_commands;
3394 host_byte_sex = get_host_byte_sex();
3395 swapped = (enum bool)(host_byte_sex != ofile->object_byte_sex);
3397 if(ofile->mh != NULL){
3398 if(swapped)
3399 swap_mach_header(mh, host_byte_sex);
3400 big_size = mh->sizeofcmds;
3401 big_size += sizeof(struct mach_header);
3402 if(big_size > size){
3403 Mach_O_error(ofile, "truncated or malformed object (load "
3404 "commands extend past the end of the file)");
3405 return(CHECK_BAD);
3407 sizeofhdrs = big_size;
3408 ofile->mh_cputype = mh->cputype;
3409 ofile->mh_cpusubtype = mh->cpusubtype;
3410 ofile->mh_filetype = mh->filetype;
3411 ncmds = mh->ncmds;
3412 sizeofcmds = mh->sizeofcmds;
3413 cputype = mh->cputype;
3414 load_command_multiple = 4;
3415 sizeof_nlist = sizeof(struct nlist);
3416 struct_nlist_name = "struct nlist";
3417 sizeof_dylib_module = sizeof(struct dylib_module);
3418 struct_dylib_module_name = "struct dylib_module";
3420 else{
3421 if(swapped)
3422 swap_mach_header_64(mh64, host_byte_sex);
3423 big_size = mh64->sizeofcmds;
3424 big_size += sizeof(struct mach_header_64);
3425 if(big_size > size){
3426 Mach_O_error(ofile, "truncated or malformed object (load "
3427 "commands extend past the end of the file)");
3428 return(CHECK_BAD);
3430 sizeofhdrs = big_size;
3431 ofile->mh_cputype = mh64->cputype;
3432 ofile->mh_cpusubtype = mh64->cpusubtype;
3433 ofile->mh_filetype = mh64->filetype;
3434 ncmds = mh64->ncmds;
3435 sizeofcmds = mh64->sizeofcmds;
3436 cputype = mh64->cputype;
3437 load_command_multiple = 8;
3438 sizeof_nlist = sizeof(struct nlist_64);
3439 struct_nlist_name = "struct nlist_64";
3440 sizeof_dylib_module = sizeof(struct dylib_module_64);
3441 struct_dylib_module_name = "struct dylib_module_64";
3443 if(check_overlaping_element(ofile, &elements, 0, sizeofhdrs,
3444 "Mach-O headers") == CHECK_BAD)
3445 goto return_bad;
3446 if(ofile->file_type == OFILE_FAT){
3447 if(ofile->fat_archs[ofile->narch].cputype != ofile->mh_cputype){
3448 Mach_O_error(ofile, "malformed fat file (fat header "
3449 "architecture: %u's cputype does not match "
3450 "object file's mach header)", ofile->narch);
3451 goto return_bad;
3455 * Make a pass through the load commands checking them to the level
3456 * that they can be parsed and all fields with offsets and sizes do
3457 * not extend past the end of the file.
3459 st = NULL;
3460 dyst = NULL;
3461 rc = NULL;
3462 rc64 = NULL;
3463 hints = NULL;
3464 code_sig = NULL;
3465 func_starts = NULL;
3466 data_in_code = NULL;
3467 code_sign_drs = NULL;
3468 split_info = NULL;
3469 cs = NULL;
3470 uuid = NULL;
3471 encrypt_info = NULL;
3472 dyld_info = NULL;
3473 vers = NULL;
3474 big_load_end = 0;
3475 for(i = 0, lc = load_commands; i < ncmds; i++){
3476 l = *lc;
3477 if(swapped)
3478 swap_load_command(&l, host_byte_sex);
3480 * Check load command size for a multiple of load_command_multiple.
3482 if(l.cmdsize % load_command_multiple != 0){
3484 * We have a hack here to allow 64-bit Mach-O core files to
3485 * have LC_THREAD commands that are only a multiple of 4 and
3486 * not 8 to be allowed since the kernel produces them.
3488 if(ofile->mh64 == NULL ||
3489 ofile->mh64->filetype != MH_CORE ||
3490 l.cmd != LC_THREAD ||
3491 l.cmdsize % 4 != 0){
3492 Mach_O_error(ofile, "malformed object (load command %u "
3493 "cmdsize not a multiple of %u)", i,
3494 load_command_multiple);
3495 goto return_bad;
3498 /* check that load command does not extends past end of commands */
3499 big_load_end += l.cmdsize;
3500 if(big_load_end > sizeofcmds){
3501 Mach_O_error(ofile, "truncated or malformed object (load "
3502 "command %u extends past the end of the file)",i);
3503 goto return_bad;
3505 /* check that the load command size is not zero */
3506 if(l.cmdsize == 0){
3507 Mach_O_error(ofile, "malformed object (load command %u cmdsize"
3508 " is zero)", i);
3509 goto return_bad;
3511 switch(l.cmd){
3512 case LC_SEGMENT:
3513 if(l.cmdsize < sizeof(struct segment_command)){
3514 Mach_O_error(ofile, "malformed object (LC_SEGMENT cmdsize "
3515 "too small) in command %u", i);
3516 goto return_bad;
3518 sg = (struct segment_command *)lc;
3519 if(swapped)
3520 swap_segment_command(sg, host_byte_sex);
3521 big_size = sg->nsects;
3522 big_size *= sizeof(struct section);
3523 big_size += sizeof(struct segment_command);
3524 if(sg->cmdsize != big_size){
3525 Mach_O_error(ofile, "malformed object (inconsistent "
3526 "cmdsize in LC_SEGMENT command %u for the "
3527 "number of sections)", i);
3528 goto return_bad;
3530 if(sg->fileoff > size){
3531 Mach_O_error(ofile, "truncated or malformed object ("
3532 "LC_SEGMENT command %u fileoff field "
3533 "extends past the end of the file)", i);
3534 goto return_bad;
3536 big_size = sg->fileoff;
3537 big_size += sg->filesize;
3538 if(big_size > size){
3539 Mach_O_error(ofile, "truncated or malformed object ("
3540 "LC_SEGMENT command %u fileoff field "
3541 "plus filesize field extends past the end of "
3542 "the file)", i);
3543 goto return_bad;
3545 if(sg->vmsize != 0 && sg->filesize > sg->vmsize){
3546 Mach_O_error(ofile, "malformed object (LC_SEGMENT command "
3547 "%u filesize field greater than vmsize field)",
3549 goto return_bad;
3551 s = (struct section *)
3552 ((char *)sg + sizeof(struct segment_command));
3553 if(swapped)
3554 swap_section(s, sg->nsects, host_byte_sex);
3555 for(j = 0 ; j < sg->nsects ; j++){
3556 if(mh->filetype != MH_DYLIB_STUB &&
3557 s->flags != S_ZEROFILL &&
3558 s->flags != S_THREAD_LOCAL_ZEROFILL && s->offset > size){
3559 Mach_O_error(ofile, "truncated or malformed object "
3560 "(offset field of section %u in LC_SEGMENT "
3561 "command %u extends past the end of the file)",
3562 j, i);
3563 goto return_bad;
3565 if(mh->filetype != MH_DYLIB_STUB &&
3566 s->flags != S_ZEROFILL &&
3567 s->flags != S_THREAD_LOCAL_ZEROFILL &&
3568 sg->fileoff == 0 && s->offset < sizeofhdrs &&
3569 s->size != 0){
3570 Mach_O_error(ofile, "malformed object (offset field of "
3571 "section %u in LC_SEGMENT command %u not "
3572 "past the headers of the file)", j, i);
3573 goto return_bad;
3575 big_size = s->offset;
3576 big_size += s->size;
3577 if(mh->filetype != MH_DYLIB_STUB &&
3578 s->flags != S_ZEROFILL &&
3579 s->flags != S_THREAD_LOCAL_ZEROFILL && big_size > size){
3580 Mach_O_error(ofile, "truncated or malformed object "
3581 "(offset field plus size field of section %u "
3582 "in LC_SEGMENT command %u extends "
3583 "past the end of the file)", j, i);
3584 goto return_bad;
3586 if(mh->filetype != MH_DYLIB_STUB &&
3587 s->flags != S_ZEROFILL &&
3588 s->flags != S_THREAD_LOCAL_ZEROFILL &&
3589 s->size > sg->filesize){
3590 Mach_O_error(ofile, "malformed object (size field of "
3591 "section %u in LC_SEGMENT command %u greater "
3592 "than the segment)", j, i);
3593 goto return_bad;
3595 if(mh->filetype != MH_DYLIB_STUB &&
3596 s->size != 0 && s->addr < sg->vmaddr){
3597 Mach_O_error(ofile, "malformed object (addr field of "
3598 "section %u in LC_SEGMENT command %u less than "
3599 "the segment's vmaddr)", j, i);
3600 goto return_bad;
3602 big_size = s->addr;
3603 big_size += s->size;
3604 big_end = sg->vmaddr;
3605 big_end += sg->vmsize;
3606 if(sg->vmsize != 0 && s->size != 0 && big_size > big_end){
3607 Mach_O_error(ofile, "malformed object (addr field plus "
3608 "size of section %u in LC_SEGMENT command %u "
3609 "greater than than the segment's vmaddr plus "
3610 "vmsize)", j, i);
3611 goto return_bad;
3613 if(mh->filetype != MH_DYLIB_STUB &&
3614 mh->filetype != MH_DSYM &&
3615 s->flags != S_ZEROFILL &&
3616 s->flags != S_THREAD_LOCAL_ZEROFILL &&
3617 check_overlaping_element(ofile, &elements, s->offset,
3618 s->size, "section contents") == CHECK_BAD)
3619 goto return_bad;
3620 if(s->reloff > size){
3621 Mach_O_error(ofile, "truncated or malformed object "
3622 "(reloff field of section %u in LC_SEGMENT "
3623 "command %u extends past the end of the file)",
3624 j, i);
3625 goto return_bad;
3627 big_size = s->nreloc;
3628 big_size *= sizeof(struct relocation_info);
3629 big_size += s->reloff;
3630 if(big_size > size){
3631 Mach_O_error(ofile, "truncated or malformed object "
3632 "(reloff field plus nreloc field times sizeof("
3633 "struct relocation_info) of section %u in "
3634 "LC_SEGMENT command %u extends past the "
3635 "end of the file)", j, i);
3636 goto return_bad;
3638 if(check_overlaping_element(ofile, &elements, s->reloff,
3639 s->nreloc * sizeof(struct relocation_info),
3640 "section relocation entries") == CHECK_BAD)
3641 goto return_bad;
3642 s++;
3644 break;
3646 case LC_SEGMENT_64:
3647 if(l.cmdsize < sizeof(struct segment_command_64)){
3648 Mach_O_error(ofile, "malformed object (LC_SEGMENT_64 "
3649 "cmdsize too small) in command %u", i);
3650 goto return_bad;
3652 sg64 = (struct segment_command_64 *)lc;
3653 if(swapped)
3654 swap_segment_command_64(sg64, host_byte_sex);
3655 big_size = sg64->nsects;
3656 big_size *= sizeof(struct section_64);
3657 big_size += sizeof(struct segment_command_64);
3658 if(sg64->cmdsize != big_size){
3659 Mach_O_error(ofile, "malformed object (inconsistent "
3660 "cmdsize in LC_SEGMENT_64 command %u for "
3661 "the number of sections)", i);
3662 goto return_bad;
3664 if(sg64->fileoff > size){
3665 Mach_O_error(ofile, "truncated or malformed object ("
3666 "LC_SEGMENT_64 command %u fileoff field "
3667 "extends past the end of the file)", i);
3668 goto return_bad;
3670 big_size = sg64->fileoff;
3671 big_size += sg64->filesize;
3672 if(big_size > size){
3673 Mach_O_error(ofile, "truncated or malformed object ("
3674 "LC_SEGMENT_64 command %u fileoff field "
3675 "plus filesize field extends past the end of "
3676 "the file)", i);
3677 goto return_bad;
3679 s64 = (struct section_64 *)
3680 ((char *)sg64 + sizeof(struct segment_command_64));
3681 if(swapped)
3682 swap_section_64(s64, sg64->nsects, host_byte_sex);
3683 for(j = 0 ; j < sg64->nsects ; j++){
3684 if(mh64->filetype != MH_DYLIB_STUB &&
3685 s64->flags != S_ZEROFILL &&
3686 s64->flags != S_THREAD_LOCAL_ZEROFILL &&
3687 s64->offset > size){
3688 Mach_O_error(ofile, "truncated or malformed object "
3689 "(offset field of section %u in LC_SEGMENT_64 "
3690 "command %u extends past the end of the file)",
3691 j, i);
3692 goto return_bad;
3694 big_size = s64->offset;
3695 big_size += s64->size;
3696 if(mh64->filetype != MH_DYLIB_STUB &&
3697 s64->flags != S_ZEROFILL &&
3698 s64->flags != S_THREAD_LOCAL_ZEROFILL &&
3699 big_size > size){
3700 Mach_O_error(ofile, "truncated or malformed object "
3701 "(offset field plus size field of section %u "
3702 "in LC_SEGMENT_64 command %u extends "
3703 "past the end of the file)", j, i);
3704 goto return_bad;
3706 if(mh64->filetype != MH_DYLIB_STUB &&
3707 mh64->filetype != MH_DSYM &&
3708 s64->flags != S_ZEROFILL &&
3709 s64->flags != S_THREAD_LOCAL_ZEROFILL &&
3710 check_overlaping_element(ofile, &elements, s64->offset,
3711 s64->size, "section contents") == CHECK_BAD)
3712 goto return_bad;
3713 if(s64->reloff > size){
3714 Mach_O_error(ofile, "truncated or malformed object "
3715 "(reloff field of section %u in LC_SEGMENT_64 "
3716 "command %u extends past the end of the file)",
3717 j, i);
3718 goto return_bad;
3720 big_size = s64->nreloc;
3721 big_size *= sizeof(struct relocation_info);
3722 big_size += s64->reloff;
3723 if(big_size > size){
3724 Mach_O_error(ofile, "truncated or malformed object "
3725 "(reloff field plus nreloc field times sizeof("
3726 "struct relocation_info) of section %u in "
3727 "LC_SEGMENT_64 command %u extends past the "
3728 "end of the file)", j, i);
3729 goto return_bad;
3731 if(check_overlaping_element(ofile, &elements, s64->reloff,
3732 s64->nreloc * sizeof(struct relocation_info),
3733 "section relocation entries") == CHECK_BAD)
3734 goto return_bad;
3735 s64++;
3737 break;
3739 case LC_SYMTAB:
3740 if(l.cmdsize < sizeof(struct symtab_command)){
3741 Mach_O_error(ofile, "malformed object (LC_SYMTAB cmdsize "
3742 "too small) in command %u", i);
3743 goto return_bad;
3745 if(st != NULL){
3746 Mach_O_error(ofile, "malformed object (more than one "
3747 "LC_SYMTAB command)");
3748 goto return_bad;
3750 st = (struct symtab_command *)lc;
3751 if(swapped)
3752 swap_symtab_command(st, host_byte_sex);
3753 if(st->cmdsize != sizeof(struct symtab_command)){
3754 Mach_O_error(ofile, "malformed object (LC_SYMTAB command "
3755 "%u has incorrect cmdsize)", i);
3756 goto return_bad;
3758 if(st->symoff > size){
3759 Mach_O_error(ofile, "truncated or malformed object (symoff "
3760 "field of LC_SYMTAB command %u extends past the end "
3761 "of the file)", i);
3762 goto return_bad;
3764 big_size = st->nsyms;
3765 big_size *= sizeof_nlist;
3766 big_size += st->symoff;
3767 if(big_size > size){
3768 Mach_O_error(ofile, "truncated or malformed object (symoff "
3769 "field plus nsyms field times sizeof(%s) of LC_SYMTAB "
3770 "command %u extends past the end of the file)",
3771 struct_nlist_name, i);
3772 goto return_bad;
3774 if(check_overlaping_element(ofile, &elements, st->symoff,
3775 st->nsyms * sizeof_nlist, "symbol table") == CHECK_BAD)
3776 goto return_bad;
3777 if(st->stroff > size){
3778 Mach_O_error(ofile, "truncated or malformed object (stroff "
3779 "field of LC_SYMTAB command %u extends past the end "
3780 "of the file)", i);
3781 goto return_bad;
3783 big_size = st->stroff;
3784 big_size += st->strsize;
3785 if(big_size > size){
3786 Mach_O_error(ofile, "truncated or malformed object (stroff "
3787 "field plus strsize field of LC_SYMTAB command %u "
3788 "extends past the end of the file)", i);
3789 goto return_bad;
3791 if(check_overlaping_element(ofile, &elements, st->stroff,
3792 st->strsize, "string table") == CHECK_BAD)
3793 goto return_bad;
3794 break;
3796 case LC_DYSYMTAB:
3797 if(l.cmdsize < sizeof(struct dysymtab_command)){
3798 Mach_O_error(ofile, "malformed object (LC_DYSYMTAB cmdsize "
3799 "too small) in command %u", i);
3800 goto return_bad;
3802 if(dyst != NULL){
3803 Mach_O_error(ofile, "malformed object (more than one "
3804 "LC_DYSYMTAB command)");
3805 goto return_bad;
3807 dyst = (struct dysymtab_command *)lc;
3808 if(swapped)
3809 swap_dysymtab_command(dyst, host_byte_sex);
3810 if(dyst->cmdsize != sizeof(struct dysymtab_command)){
3811 Mach_O_error(ofile, "malformed object (LC_DYSYMTAB command "
3812 "%u has incorrect cmdsize)", i);
3813 goto return_bad;
3815 if(dyst->tocoff > size){
3816 Mach_O_error(ofile, "truncated or malformed object (tocoff "
3817 "field of LC_DYSYMTAB command %u extends past the end "
3818 "of the file)", i);
3819 goto return_bad;
3821 big_size = dyst->ntoc;
3822 big_size *= sizeof(struct dylib_table_of_contents);
3823 big_size += dyst->tocoff;
3824 if(big_size > size){
3825 Mach_O_error(ofile, "truncated or malformed object (tocoff "
3826 "field plus ntoc field times sizeof(struct dylib_table"
3827 "_of_contents) of LC_DYSYMTAB command %u extends past "
3828 "the end of the file)", i);
3829 goto return_bad;
3831 if(check_overlaping_element(ofile, &elements, dyst->tocoff,
3832 dyst->ntoc * sizeof(struct dylib_table_of_contents),
3833 "table of contents") == CHECK_BAD)
3834 goto return_bad;
3835 if(dyst->modtaboff > size){
3836 Mach_O_error(ofile, "truncated or malformed object "
3837 "(modtaboff field of LC_DYSYMTAB command %u extends "
3838 "past the end of the file)", i);
3839 goto return_bad;
3841 big_size = dyst->nmodtab;
3842 big_size *= sizeof_dylib_module;
3843 big_size += dyst->modtaboff;
3844 if(big_size > size){
3845 Mach_O_error(ofile, "truncated or malformed object "
3846 "(modtaboff field plus nmodtab field times sizeof(%s) "
3847 "of LC_DYSYMTAB command %u extends past the end of "
3848 "the file)", struct_dylib_module_name, i);
3849 goto return_bad;
3851 if(check_overlaping_element(ofile, &elements, dyst->modtaboff,
3852 dyst->nmodtab * sizeof_dylib_module, "module table") ==
3853 CHECK_BAD)
3854 goto return_bad;
3855 if(dyst->extrefsymoff > size){
3856 Mach_O_error(ofile, "truncated or malformed object "
3857 "(extrefsymoff field of LC_DYSYMTAB command %u "
3858 "extends past the end of the file)", i);
3859 goto return_bad;
3861 big_size = dyst->nextrefsyms;
3862 big_size *= sizeof(struct dylib_reference);
3863 big_size += dyst->extrefsymoff;
3864 if(big_size > size){
3865 Mach_O_error(ofile, "truncated or malformed object "
3866 "(extrefsymoff field plus nextrefsyms field times "
3867 "sizeof(struct dylib_reference) of LC_DYSYMTAB command "
3868 "%u extends past the end of the file)", i);
3869 goto return_bad;
3871 if(check_overlaping_element(ofile, &elements,dyst->extrefsymoff,
3872 dyst->nextrefsyms * sizeof(struct dylib_reference),
3873 "reference table") == CHECK_BAD)
3874 goto return_bad;
3875 if(dyst->indirectsymoff > size){
3876 Mach_O_error(ofile, "truncated or malformed object "
3877 "(indirectsymoff field of LC_DYSYMTAB command %u "
3878 "extends past the end of the file)", i);
3879 goto return_bad;
3881 big_size = dyst->nindirectsyms;
3882 big_size *= sizeof(uint32_t);
3883 big_size += dyst->indirectsymoff;
3884 if(big_size > size){
3885 Mach_O_error(ofile, "truncated or malformed object "
3886 "(indirectsymoff field plus nindirectsyms field times "
3887 "sizeof(uint32_t) of LC_DYSYMTAB command "
3888 "%u extends past the end of the file)", i);
3889 goto return_bad;
3891 if(check_overlaping_element(ofile, &elements,
3892 dyst->indirectsymoff, dyst->nindirectsyms *
3893 sizeof(uint32_t), "indirect table") == CHECK_BAD)
3894 goto return_bad;
3895 if(dyst->extreloff > size){
3896 Mach_O_error(ofile, "truncated or malformed object "
3897 "(extreloff field of LC_DYSYMTAB command %u "
3898 "extends past the end of the file)", i);
3899 goto return_bad;
3901 big_size = dyst->nextrel;
3902 big_size *= sizeof(struct relocation_info);
3903 big_size += dyst->extreloff;
3904 if(big_size > size){
3905 Mach_O_error(ofile, "truncated or malformed object "
3906 "(extreloff field plus nextrel field times "
3907 "sizeof(struct relocation_info) of LC_DYSYMTAB command "
3908 "%u extends past the end of the file)", i);
3909 goto return_bad;
3911 if(check_overlaping_element(ofile, &elements, dyst->extreloff,
3912 dyst->nextrel * sizeof(struct relocation_info),
3913 "external relocation table") == CHECK_BAD)
3914 goto return_bad;
3915 if(dyst->locreloff > size){
3916 Mach_O_error(ofile, "truncated or malformed object "
3917 "(locreloff field of LC_DYSYMTAB command %u "
3918 "extends past the end of the file)", i);
3919 goto return_bad;
3921 big_size = dyst->nlocrel;
3922 big_size *= sizeof(struct relocation_info);
3923 big_size += dyst->locreloff;
3924 if(big_size > size){
3925 Mach_O_error(ofile, "truncated or malformed object "
3926 "(locreloff field plus nlocrel field times "
3927 "sizeof(struct relocation_info) of LC_DYSYMTAB command "
3928 "%u extends past the end of the file)", i);
3929 goto return_bad;
3931 if(check_overlaping_element(ofile, &elements, dyst->locreloff,
3932 dyst->nlocrel * sizeof(struct relocation_info),
3933 "local relocation table") == CHECK_BAD)
3934 goto return_bad;
3935 break;
3937 case LC_ROUTINES:
3938 if(l.cmdsize < sizeof(struct routines_command)){
3939 Mach_O_error(ofile, "malformed object (LC_ROUTINES cmdsize "
3940 "too small) in command %u", i);
3941 goto return_bad;
3943 if(rc != NULL){
3944 Mach_O_error(ofile, "malformed object (more than one "
3945 "LC_ROUTINES command)");
3946 goto return_bad;
3948 rc = (struct routines_command *)lc;
3949 if(swapped)
3950 swap_routines_command(rc, host_byte_sex);
3951 if(rc->cmdsize != sizeof(struct routines_command)){
3952 Mach_O_error(ofile, "malformed object (LC_ROUTINES "
3953 "command %u has incorrect cmdsize)", i);
3954 goto return_bad;
3956 break;
3958 case LC_ROUTINES_64:
3959 if(l.cmdsize < sizeof(struct routines_command_64)){
3960 Mach_O_error(ofile, "malformed object (LC_ROUTINES_64 "
3961 "cmdsize too small) in command %u", i);
3962 goto return_bad;
3964 if(rc64 != NULL){
3965 Mach_O_error(ofile, "malformed object (more than one "
3966 "LC_ROUTINES_64 command)");
3967 goto return_bad;
3969 rc64 = (struct routines_command_64 *)lc;
3970 if(swapped)
3971 swap_routines_command_64(rc64, host_byte_sex);
3972 if(rc64->cmdsize != sizeof(struct routines_command_64)){
3973 Mach_O_error(ofile, "malformed object (LC_ROUTINES_64 "
3974 "command %u has incorrect cmdsize)", i);
3975 goto return_bad;
3977 break;
3979 case LC_TWOLEVEL_HINTS:
3980 if(l.cmdsize < sizeof(struct twolevel_hints_command)){
3981 Mach_O_error(ofile, "malformed object (LC_TWOLEVEL_HINTS "
3982 "cmdsize too small) in command %u", i);
3983 goto return_bad;
3985 if(hints != NULL){
3986 Mach_O_error(ofile, "malformed object (more than one "
3987 "LC_TWOLEVEL_HINTS command)");
3988 goto return_bad;
3990 hints = (struct twolevel_hints_command *)lc;
3991 if(swapped)
3992 swap_twolevel_hints_command(hints, host_byte_sex);
3993 if(hints->cmdsize != sizeof(struct twolevel_hints_command)){
3994 Mach_O_error(ofile, "malformed object (LC_TWOLEVEL_HINTS "
3995 "command %u has incorrect cmdsize)", i);
3996 goto return_bad;
3998 if(hints->offset > size){
3999 Mach_O_error(ofile, "truncated or malformed object "
4000 "(offset field of LC_TWOLEVEL_HINTS command %u "
4001 "extends past the end of the file)", i);
4002 goto return_bad;
4004 big_size = hints->nhints;
4005 big_size *= sizeof(struct twolevel_hint);
4006 big_size += hints->offset;
4007 if(big_size > size){
4008 Mach_O_error(ofile, "truncated or malformed object "
4009 "(offset field plus nhints field times "
4010 "sizeof(struct twolevel_hint) of LC_TWOLEVEL_HINTS "
4011 " command %u extends past the end of the file)", i);
4012 goto return_bad;
4014 if(check_overlaping_element(ofile, &elements, hints->offset,
4015 hints->nhints * sizeof(struct twolevel_hint),
4016 "two level hints") == CHECK_BAD)
4017 goto return_bad;
4018 break;
4020 case LC_SEGMENT_SPLIT_INFO:
4021 cmd_name = "LC_SEGMENT_SPLIT_INFO";
4022 element_name = "split info data";
4023 if(split_info != NULL){
4024 Mach_O_error(ofile, "malformed object (more than one "
4025 "%s command)", cmd_name);
4026 goto return_bad;
4028 split_info = (struct linkedit_data_command *)lc;
4029 goto check_linkedit_data_command;
4031 case LC_CODE_SIGNATURE:
4032 cmd_name = "LC_CODE_SIGNATURE";
4033 element_name = "code signature data";
4034 if(code_sig != NULL){
4035 Mach_O_error(ofile, "malformed object (more than one "
4036 "%s command)", cmd_name);
4037 goto return_bad;
4039 code_sig = (struct linkedit_data_command *)lc;
4040 goto check_linkedit_data_command;
4042 case LC_FUNCTION_STARTS:
4043 cmd_name = "LC_FUNCTION_STARTS";
4044 element_name = "function starts data";
4045 if(func_starts != NULL){
4046 Mach_O_error(ofile, "malformed object (more than one "
4047 "%s command)", cmd_name);
4048 goto return_bad;
4050 func_starts = (struct linkedit_data_command *)lc;
4051 goto check_linkedit_data_command;
4053 case LC_DATA_IN_CODE:
4054 cmd_name = "LC_DATA_IN_CODE";
4055 element_name = "date in code info";
4056 if(data_in_code != NULL){
4057 Mach_O_error(ofile, "malformed object (more than one "
4058 "%s command)", cmd_name);
4059 goto return_bad;
4061 data_in_code = (struct linkedit_data_command *)lc;
4062 goto check_linkedit_data_command;
4064 case LC_DYLIB_CODE_SIGN_DRS:
4065 cmd_name = "LC_DYLIB_CODE_SIGN_DRS";
4066 element_name = "code signing RDs data";
4067 if(code_sign_drs != NULL){
4068 Mach_O_error(ofile, "malformed object (more than one "
4069 "%s command)", cmd_name);
4070 goto return_bad;
4072 code_sign_drs = (struct linkedit_data_command *)lc;
4073 goto check_linkedit_data_command;
4075 check_linkedit_data_command:
4076 if(l.cmdsize < sizeof(struct linkedit_data_command)){
4077 Mach_O_error(ofile, "malformed object (%s cmdsize too "
4078 "small) in command %u", cmd_name, i);
4079 goto return_bad;
4081 linkedit_data = (struct linkedit_data_command *)lc;
4082 if(swapped)
4083 swap_linkedit_data_command(linkedit_data, host_byte_sex);
4084 if(linkedit_data->cmdsize !=
4085 sizeof(struct linkedit_data_command)){
4086 Mach_O_error(ofile, "malformed object (%s command %u has "
4087 "incorrect cmdsize)", cmd_name, i);
4088 goto return_bad;
4090 if(linkedit_data->dataoff > size){
4091 Mach_O_error(ofile, "truncated or malformed object "
4092 "(dataoff field of %s command %u extends past the end "
4093 "of the file)", cmd_name, i);
4094 goto return_bad;
4096 big_size = linkedit_data->dataoff;
4097 big_size += linkedit_data->datasize;
4098 if(big_size > size){
4099 Mach_O_error(ofile, "truncated or malformed object "
4100 "(dataoff field plus datasize field of "
4101 "%s command %u extends past the end of "
4102 "the file)", cmd_name, i);
4103 goto return_bad;
4105 if(check_overlaping_element(ofile, &elements,
4106 linkedit_data->dataoff, linkedit_data->datasize,
4107 element_name) == CHECK_BAD)
4108 goto return_bad;
4109 break;
4111 case LC_VERSION_MIN_MACOSX:
4112 if(l.cmdsize < sizeof(struct version_min_command)){
4113 Mach_O_error(ofile, "malformed object (LC_VERSION_MIN_"
4114 "MACOSX cmdsize too small) in command %u", i);
4115 goto return_bad;
4117 if(vers != NULL){
4118 Mach_O_error(ofile, "malformed object (more than one "
4119 "LC_VERSION_MIN_IPHONEOS or LC_VERSION_MIN_MACOSX "
4120 "command)");
4121 goto return_bad;
4123 vers = (struct version_min_command *)lc;
4124 if(swapped)
4125 swap_version_min_command(vers, host_byte_sex);
4126 if(vers->cmdsize < sizeof(struct version_min_command)){
4127 Mach_O_error(ofile, "malformed object (LC_VERSION_MIN_"
4128 "MACOSX command %u has too small cmdsize field)", i);
4129 goto return_bad;
4131 break;
4133 case LC_VERSION_MIN_IPHONEOS:
4134 if(l.cmdsize < sizeof(struct version_min_command)){
4135 Mach_O_error(ofile, "malformed object (LC_VERSION_MIN_"
4136 "IPHONEOS cmdsize too small) in command %u",i);
4137 goto return_bad;
4139 if(vers != NULL){
4140 Mach_O_error(ofile, "malformed object (more than one "
4141 "LC_VERSION_MIN_IPHONEOS or LC_VERSION_MIN_MACOSX "
4142 "command)");
4143 goto return_bad;
4145 vers = (struct version_min_command *)lc;
4146 if(swapped)
4147 swap_version_min_command(vers, host_byte_sex);
4148 if(vers->cmdsize < sizeof(struct version_min_command)){
4149 Mach_O_error(ofile, "malformed object (LC_VERSION_MIN_"
4150 "IPHONEOS command %u has too small cmdsize field)", i);
4151 goto return_bad;
4153 break;
4155 case LC_ENCRYPTION_INFO:
4156 if(l.cmdsize < sizeof(struct encryption_info_command)){
4157 Mach_O_error(ofile, "malformed object (LC_ENCRYPTION_INFO "
4158 "cmdsize too small) in command %u", i);
4159 goto return_bad;
4161 encrypt_info = (struct encryption_info_command *)lc;
4162 if(swapped)
4163 swap_encryption_command(encrypt_info, host_byte_sex);
4164 if(encrypt_info->cmdsize !=
4165 sizeof(struct encryption_info_command)){
4166 Mach_O_error(ofile, "malformed object (LC_ENCRYPTION_INFO"
4167 "command %u has incorrect cmdsize)", i);
4168 goto return_bad;
4170 if(encrypt_info->cryptoff > size){
4171 Mach_O_error(ofile, "truncated or malformed object (cryptoff "
4172 "field of LC_ENCRYPTION_INFO command %u extends "
4173 "past the end of the file)", i);
4174 goto return_bad;
4176 big_size = encrypt_info->cryptoff;
4177 big_size += encrypt_info->cryptsize;
4178 if(big_size > size){
4179 Mach_O_error(ofile, "truncated or malformed object "
4180 "(cryptoff field plus cryptsize field of "
4181 "LC_ENCRYPTION_INFO command %u extends past "
4182 "the end of the file)", i);
4183 goto return_bad;
4185 break;
4187 case LC_ENCRYPTION_INFO_64:
4188 if(l.cmdsize < sizeof(struct encryption_info_command_64)){
4189 Mach_O_error(ofile, "malformed object (LC_ENCRYPTION_INFO"
4190 "_64 cmdsize too small) in command %u", i);
4191 goto return_bad;
4193 encrypt_info64 = (struct encryption_info_command_64 *)lc;
4194 if(swapped)
4195 swap_encryption_command_64(encrypt_info64, host_byte_sex);
4196 if(encrypt_info64->cmdsize !=
4197 sizeof(struct encryption_info_command_64)){
4198 Mach_O_error(ofile, "malformed object (LC_ENCRYPTION_INFO"
4199 "_64 command %u has incorrect cmdsize)", i);
4200 goto return_bad;
4202 if(encrypt_info64->cryptoff > size){
4203 Mach_O_error(ofile, "truncated or malformed object (cryptoff "
4204 "field of LC_ENCRYPTION_INFO_64 command %u extends"
4205 " past the end of the file)", i);
4206 goto return_bad;
4208 big_size = encrypt_info64->cryptoff;
4209 big_size += encrypt_info64->cryptsize;
4210 if(big_size > size){
4211 Mach_O_error(ofile, "truncated or malformed object "
4212 "(cryptoff field plus cryptsize field of "
4213 "LC_ENCRYPTION_INFO_64 command %u extends past"
4214 " the end of the file)", i);
4215 goto return_bad;
4217 break;
4219 case LC_DYLD_INFO:
4220 case LC_DYLD_INFO_ONLY:
4221 if(l.cmdsize < sizeof(struct dyld_info_command)){
4222 Mach_O_error(ofile, "malformed object (%s cmdsize "
4223 "too small) in command %u", l.cmd ==
4224 LC_DYLD_INFO ? "LC_DYLD_INFO" :
4225 "LC_DYLD_INFO_ONLY", i);
4226 goto return_bad;
4228 dyld_info = (struct dyld_info_command *)lc;
4229 if(swapped)
4230 swap_dyld_info_command(dyld_info, host_byte_sex);
4231 if(dyld_info->cmdsize !=
4232 sizeof(struct dyld_info_command)){
4233 Mach_O_error(ofile, "malformed object (LC_DYLD_INFO"
4234 "command %u has incorrect cmdsize)", i);
4235 goto return_bad;
4237 if(dyld_info->rebase_off != 0 && dyld_info->rebase_off > size){
4238 Mach_O_error(ofile, "truncated or malformed object "
4239 "(rebase_off field of LC_DYLD_INFO command %u "
4240 "extends past the end of the file)", i);
4241 goto return_bad;
4243 if(dyld_info->rebase_off != 0){
4244 big_size = dyld_info->rebase_off;
4245 big_size += dyld_info->rebase_size;
4246 if(big_size > size){
4247 Mach_O_error(ofile, "truncated or malformed object "
4248 "(rebase_off plus rebase_size of LC_DYLD_INFO "
4249 "command %u extends past the end of the file)", i);
4250 goto return_bad;
4253 if(check_overlaping_element(ofile, &elements,
4254 dyld_info->rebase_off, dyld_info->rebase_size,
4255 "dyld rebase info") == CHECK_BAD)
4256 goto return_bad;
4257 if(dyld_info->bind_off != 0 && dyld_info->bind_off > size){
4258 Mach_O_error(ofile, "truncated or malformed object "
4259 "(bind_off field of LC_DYLD_INFO command %u "
4260 "extends past the end of the file)", i);
4261 goto return_bad;
4263 if(dyld_info->bind_off != 0){
4264 big_size = dyld_info->bind_off;
4265 big_size += dyld_info->bind_size;
4266 if(big_size > size){
4267 Mach_O_error(ofile, "truncated or malformed object "
4268 "(bind_off plus bind_size of LC_DYLD_INFO command "
4269 "%u extends past the end of the file)", i);
4270 goto return_bad;
4273 if(check_overlaping_element(ofile, &elements,
4274 dyld_info->bind_off, dyld_info->bind_size,
4275 "dyld bind info") == CHECK_BAD)
4276 goto return_bad;
4277 if(dyld_info->weak_bind_off != 0 &&
4278 dyld_info->weak_bind_off > size){
4279 Mach_O_error(ofile, "truncated or malformed object "
4280 "(weak_bind_off field of LC_DYLD_INFO command %u "
4281 "extends past the end of the file)", i);
4282 goto return_bad;
4284 if(dyld_info->weak_bind_off != 0){
4285 big_size = dyld_info->weak_bind_off;
4286 big_size += dyld_info->weak_bind_size;
4287 if(big_size > size){
4288 Mach_O_error(ofile, "truncated or malformed object "
4289 "(weak_bind_off plus weak_bind_size of LC_DYLD_INFO"
4290 " command %u extends past the end of the file)", i);
4291 goto return_bad;
4294 if(check_overlaping_element(ofile, &elements,
4295 dyld_info->weak_bind_off, dyld_info->weak_bind_size,
4296 "dyld bind info") == CHECK_BAD)
4297 goto return_bad;
4298 if(dyld_info->lazy_bind_off != 0 &&
4299 dyld_info->lazy_bind_off > size){
4300 Mach_O_error(ofile, "truncated or malformed object "
4301 "(lazy_bind_off field of LC_DYLD_INFO command %u "
4302 "extends past the end of the file)", i);
4303 goto return_bad;
4305 if(dyld_info->lazy_bind_off != 0){
4306 big_size = dyld_info->lazy_bind_off;
4307 big_size += dyld_info->lazy_bind_size;
4308 if(big_size > size){
4309 Mach_O_error(ofile, "truncated or malformed object "
4310 "(lazy_bind_off plus lazy_bind_size of LC_DYLD_INFO"
4311 " command %u extends past the end of the file)", i);
4312 goto return_bad;
4315 if(check_overlaping_element(ofile, &elements,
4316 dyld_info->lazy_bind_off, dyld_info->lazy_bind_size,
4317 "dyld lazy bind info") == CHECK_BAD)
4318 goto return_bad;
4319 if(dyld_info->export_off != 0 && dyld_info->export_off > size){
4320 Mach_O_error(ofile, "truncated or malformed object "
4321 "(export_off field of LC_DYLD_INFO command %u "
4322 "extends past the end of the file)", i);
4323 goto return_bad;
4325 if(dyld_info->export_off != 0){
4326 big_size = dyld_info->export_off;
4327 big_size += dyld_info->export_size;
4328 if(big_size > size){
4329 Mach_O_error(ofile, "truncated or malformed object "
4330 "(export_off plus export_size of LC_DYLD_INFO "
4331 "command %u extends past the end of the file)", i);
4332 goto return_bad;
4335 if(check_overlaping_element(ofile, &elements,
4336 dyld_info->export_off, dyld_info->export_size,
4337 "dyld export info") == CHECK_BAD)
4338 goto return_bad;
4339 break;
4343 case LC_PREBIND_CKSUM:
4344 if(l.cmdsize < sizeof(struct prebind_cksum_command)){
4345 Mach_O_error(ofile, "malformed object (LC_PREBIND_CKSUM "
4346 "cmdsize too small) in command %u", i);
4347 goto return_bad;
4349 if(cs != NULL){
4350 Mach_O_error(ofile, "malformed object (more than one "
4351 "LC_PREBIND_CKSUM command)");
4352 goto return_bad;
4354 cs = (struct prebind_cksum_command *)lc;
4355 if(swapped)
4356 swap_prebind_cksum_command(cs, host_byte_sex);
4357 if(cs->cmdsize != sizeof(struct prebind_cksum_command)){
4358 Mach_O_error(ofile, "malformed object (LC_PREBIND_CKSUM "
4359 "command %u has incorrect cmdsize)", i);
4360 goto return_bad;
4362 break;
4364 case LC_UUID:
4365 if(l.cmdsize < sizeof(struct uuid_command)){
4366 Mach_O_error(ofile, "malformed object (LC_UUID cmdsize "
4367 "too small) in command %u", i);
4368 goto return_bad;
4370 if(uuid != NULL){
4371 Mach_O_error(ofile, "malformed object (more than one "
4372 "LC_UUID command)");
4373 goto return_bad;
4375 uuid = (struct uuid_command *)lc;
4376 if(swapped)
4377 swap_uuid_command(uuid, host_byte_sex);
4378 if(uuid->cmdsize != sizeof(struct uuid_command)){
4379 Mach_O_error(ofile, "malformed object (LC_UUID command %u " "has incorrect cmdsize)", i);
4380 goto return_bad;
4382 break;
4384 case LC_SYMSEG:
4385 if(l.cmdsize < sizeof(struct symseg_command)){
4386 Mach_O_error(ofile, "malformed object (LC_SYMSEG cmdsize "
4387 "too small) in command %u", i);
4388 goto return_bad;
4390 ss = (struct symseg_command *)lc;
4391 if(swapped)
4392 swap_symseg_command(ss, host_byte_sex);
4393 if(ss->cmdsize != sizeof(struct symseg_command)){
4394 Mach_O_error(ofile, "malformed object (LC_SYMSEG command "
4395 "%u has incorrect cmdsize)", i);
4396 goto return_bad;
4398 if(ss->offset > size){
4399 Mach_O_error(ofile, "truncated or malformed object (offset "
4400 "field of LC_SYMSEG command %u extends past the end "
4401 "of the file)", i);
4402 goto return_bad;
4404 big_size = ss->offset;
4405 big_size += ss->size;
4406 if(big_size > size){
4407 Mach_O_error(ofile, "truncated or malformed object (offset "
4408 "field plus size field of LC_SYMTAB command %u "
4409 "extends past the end of the file)", i);
4410 goto return_bad;
4412 if(check_overlaping_element(ofile, &elements, ss->offset,
4413 ss->size, "symseg info") == CHECK_BAD)
4414 goto return_bad;
4415 break;
4417 case LC_IDFVMLIB:
4418 case LC_LOADFVMLIB:
4419 if(l.cmdsize < sizeof(struct fvmlib_command)){
4420 Mach_O_error(ofile, "malformed object (%s cmdsize "
4421 "too small) in command %u", l.cmd ==
4422 LC_IDFVMLIB ? "LC_IDFVMLIB" :
4423 "LC_LOADFVMLIB", i);
4424 goto return_bad;
4426 fl = (struct fvmlib_command *)lc;
4427 if(swapped)
4428 swap_fvmlib_command(fl, host_byte_sex);
4429 if(fl->cmdsize < sizeof(struct fvmlib_command)){
4430 Mach_O_error(ofile, "malformed object (%s command %u has "
4431 "too small cmdsize field)", fl->cmd == LC_IDFVMLIB ?
4432 "LC_IDFVMLIB" : "LC_LOADFVMLIB", i);
4433 goto return_bad;
4435 if(fl->fvmlib.name.offset >= fl->cmdsize){
4436 Mach_O_error(ofile, "truncated or malformed object (name."
4437 "offset field of %s command %u extends past the end "
4438 "of the file)", fl->cmd == LC_IDFVMLIB ? "LC_IDFVMLIB"
4439 : "LC_LOADFVMLIB", i);
4440 goto return_bad;
4442 break;
4444 case LC_ID_DYLIB:
4445 cmd_name = "LC_ID_DYLIB";
4446 goto check_dylib_command;
4447 case LC_LOAD_DYLIB:
4448 cmd_name = "LC_LOAD_DYLIB";
4449 goto check_dylib_command;
4450 case LC_LOAD_WEAK_DYLIB:
4451 cmd_name = "LC_LOAD_WEAK_DYLIB";
4452 goto check_dylib_command;
4453 case LC_REEXPORT_DYLIB:
4454 cmd_name = "LC_REEXPORT_DYLIB";
4455 goto check_dylib_command;
4456 case LC_LOAD_UPWARD_DYLIB:
4457 cmd_name = "LC_LOAD_UPWARD_DYLIB";
4458 goto check_dylib_command;
4459 case LC_LAZY_LOAD_DYLIB:
4460 cmd_name = "LC_LAZY_LOAD_DYLIB";
4461 goto check_dylib_command;
4462 check_dylib_command:
4463 if(l.cmdsize < sizeof(struct dylib_command)){
4464 Mach_O_error(ofile, "malformed object (%s cmdsize too "
4465 "small) in command %u", cmd_name, i);
4466 goto return_bad;
4468 dl = (struct dylib_command *)lc;
4469 if(swapped)
4470 swap_dylib_command(dl, host_byte_sex);
4471 if(dl->cmdsize < sizeof(struct dylib_command)){
4472 Mach_O_error(ofile, "malformed object (%s command %u has "
4473 "too small cmdsize field)", cmd_name, i);
4474 goto return_bad;
4476 if(dl->dylib.name.offset >= dl->cmdsize){
4477 Mach_O_error(ofile, "truncated or malformed object (name."
4478 "offset field of %s command %u extends past the end "
4479 "of the file)", cmd_name, i);
4480 goto return_bad;
4482 break;
4484 case LC_SUB_FRAMEWORK:
4485 if(l.cmdsize < sizeof(struct sub_framework_command)){
4486 Mach_O_error(ofile, "malformed object (LC_SUB_FRAMEWORK "
4487 "cmdsize too small) in command %u", i);
4488 goto return_bad;
4490 sub = (struct sub_framework_command *)lc;
4491 if(swapped)
4492 swap_sub_framework_command(sub, host_byte_sex);
4493 if(sub->cmdsize < sizeof(struct sub_framework_command)){
4494 Mach_O_error(ofile, "malformed object (LC_SUB_FRAMEWORK "
4495 "command %u has too small cmdsize field)", i);
4496 goto return_bad;
4498 if(sub->umbrella.offset >= sub->cmdsize){
4499 Mach_O_error(ofile, "truncated or malformed object "
4500 "(umbrella.offset field of LC_SUB_FRAMEWORK command "
4501 "%u extends past the end of the file)", i);
4502 goto return_bad;
4504 break;
4506 case LC_SUB_UMBRELLA:
4507 if(l.cmdsize < sizeof(struct sub_umbrella_command)){
4508 Mach_O_error(ofile, "malformed object (LC_SUB_UMBRELLA "
4509 "cmdsize too small) in command %u", i);
4510 goto return_bad;
4512 usub = (struct sub_umbrella_command *)lc;
4513 if(swapped)
4514 swap_sub_umbrella_command(usub, host_byte_sex);
4515 if(usub->cmdsize < sizeof(struct sub_umbrella_command)){
4516 Mach_O_error(ofile, "malformed object (LC_SUB_UMBRELLA "
4517 "command %u has too small cmdsize field)", i);
4518 goto return_bad;
4520 if(usub->sub_umbrella.offset >= usub->cmdsize){
4521 Mach_O_error(ofile, "truncated or malformed object "
4522 "(sub_umbrella.offset field of LC_SUB_UMBRELLA command "
4523 "%u extends past the end of the file)", i);
4524 goto return_bad;
4526 break;
4528 case LC_SUB_LIBRARY:
4529 if(l.cmdsize < sizeof(struct sub_library_command)){
4530 Mach_O_error(ofile, "malformed object (LC_SUB_LIBRARY "
4531 "cmdsize too small) in command %u", i);
4532 goto return_bad;
4534 lsub = (struct sub_library_command *)lc;
4535 if(swapped)
4536 swap_sub_library_command(lsub, host_byte_sex);
4537 if(lsub->cmdsize < sizeof(struct sub_library_command)){
4538 Mach_O_error(ofile, "malformed object (LC_SUB_LIBRARY "
4539 "command %u has too small cmdsize field)", i);
4540 goto return_bad;
4542 if(lsub->sub_library.offset >= lsub->cmdsize){
4543 Mach_O_error(ofile, "truncated or malformed object "
4544 "(sub_library.offset field of LC_SUB_LIBRARY command "
4545 "%u extends past the end of the file)", i);
4546 goto return_bad;
4548 break;
4550 case LC_SUB_CLIENT:
4551 if(l.cmdsize < sizeof(struct sub_client_command)){
4552 Mach_O_error(ofile, "malformed object (LC_SUB_CLIENT "
4553 "cmdsize too small) in command %u", i);
4554 goto return_bad;
4556 csub = (struct sub_client_command *)lc;
4557 if(swapped)
4558 swap_sub_client_command(csub, host_byte_sex);
4559 if(csub->cmdsize < sizeof(struct sub_client_command)){
4560 Mach_O_error(ofile, "malformed object (LC_SUB_CLIENT "
4561 "command %u has too small cmdsize field)", i);
4562 goto return_bad;
4564 if(csub->client.offset >= csub->cmdsize){
4565 Mach_O_error(ofile, "truncated or malformed object "
4566 "(cleient.offset field of LC_SUB_CLIENT command "
4567 "%u extends past the end of the file)", i);
4568 goto return_bad;
4570 break;
4572 case LC_PREBOUND_DYLIB:
4573 if(l.cmdsize < sizeof(struct prebound_dylib_command)){
4574 Mach_O_error(ofile, "malformed object (LC_PREBOUND_DYLIB "
4575 "cmdsize too small) in command %u", i);
4576 goto return_bad;
4578 pbdylib = (struct prebound_dylib_command *)lc;
4579 if(swapped)
4580 swap_prebound_dylib_command(pbdylib, host_byte_sex);
4581 if(pbdylib->cmdsize < sizeof(struct dylib_command)){
4582 Mach_O_error(ofile, "malformed object (LC_PREBIND_DYLIB "
4583 "command %u has too small cmdsize field)", i);
4584 goto return_bad;
4586 if(pbdylib->name.offset >= pbdylib->cmdsize){
4587 Mach_O_error(ofile, "truncated or malformed object (name."
4588 "offset field of LC_PREBIND_DYLIB command %u extends "
4589 "past the end of the file)", i);
4590 goto return_bad;
4592 if(pbdylib->linked_modules.offset >= pbdylib->cmdsize){
4593 Mach_O_error(ofile, "truncated or malformed object (linked_"
4594 "modules.offset field of LC_PREBIND_DYLIB command %u "
4595 "extends past the end of the file)", i);
4596 goto return_bad;
4598 break;
4600 case LC_ID_DYLINKER:
4601 cmd_name = "LC_ID_DYLINKER";
4602 goto check_dylinker_command;
4603 case LC_LOAD_DYLINKER:
4604 cmd_name = "LC_LOAD_DYLINKER";
4605 goto check_dylinker_command;
4606 case LC_DYLD_ENVIRONMENT:
4607 cmd_name = "LC_DYLD_ENVIRONMENT";
4608 goto check_dylinker_command;
4609 check_dylinker_command:
4610 if(l.cmdsize < sizeof(struct dylinker_command)){
4611 Mach_O_error(ofile, "malformed object (%s cmdsize "
4612 "too small) in command %u", cmd_name, i);
4613 goto return_bad;
4615 dyld = (struct dylinker_command *)lc;
4616 if(swapped)
4617 swap_dylinker_command(dyld, host_byte_sex);
4618 if(dyld->cmdsize < sizeof(struct dylinker_command)){
4619 Mach_O_error(ofile, "malformed object (%s command %u has "
4620 "too small cmdsize field)", cmd_name, i);
4621 goto return_bad;
4623 if(dyld->name.offset >= dyld->cmdsize){
4624 Mach_O_error(ofile, "truncated or malformed object (name."
4625 "offset field of %s command %u extends past the end "
4626 "of the file)", cmd_name, i);
4627 goto return_bad;
4629 break;
4631 case LC_UNIXTHREAD:
4632 case LC_THREAD:
4633 if(l.cmdsize < sizeof(struct thread_command)){
4634 Mach_O_error(ofile, "malformed object (%s cmdsize "
4635 "too small) in command %u", l.cmd ==
4636 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4637 "LC_THREAD", i);
4638 goto return_bad;
4640 ut = (struct thread_command *)lc;
4641 if(swapped)
4642 swap_thread_command(ut, host_byte_sex);
4643 state = (char *)ut + sizeof(struct thread_command);
4645 if(cputype == CPU_TYPE_MC680x0){
4646 struct m68k_thread_state_regs *cpu;
4647 struct m68k_thread_state_68882 *fpu;
4648 struct m68k_thread_state_user_reg *user_reg;
4650 nflavor = 0;
4651 p = (char *)ut + ut->cmdsize;
4652 while(state < p){
4653 if(state + sizeof(uint32_t) >
4654 (char *)ut + ut->cmdsize){
4655 Mach_O_error(ofile, "malformed object (flavor in "
4656 "%s command %u extends past end of command)",
4657 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4658 "LC_THREAD", i);
4659 goto return_bad;
4661 flavor = *((uint32_t *)state);
4662 if(swapped){
4663 flavor = SWAP_INT(flavor);
4664 *((uint32_t *)state) = flavor;
4666 state += sizeof(uint32_t);
4667 if(state + sizeof(uint32_t) >
4668 (char *)ut + ut->cmdsize){
4669 Mach_O_error(ofile, "malformed object (count in "
4670 "%s command %u extends past end of command)",
4671 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4672 "LC_THREAD", i);
4673 goto return_bad;
4675 count = *((uint32_t *)state);
4676 if(swapped){
4677 count = SWAP_INT(count);
4678 *((uint32_t *)state) = count;
4680 state += sizeof(uint32_t);
4681 switch(flavor){
4682 case M68K_THREAD_STATE_REGS:
4683 if(count != M68K_THREAD_STATE_REGS_COUNT){
4684 Mach_O_error(ofile, "malformed object (count "
4685 "not M68K_THREAD_STATE_REGS_COUNT for "
4686 "flavor number %u which is a M68K_THREAD_"
4687 "STATE_REGS flavor in %s command %u)",
4688 nflavor, ut->cmd == LC_UNIXTHREAD ?
4689 "LC_UNIXTHREAD" : "LC_THREAD", i);
4690 goto return_bad;
4692 cpu = (struct m68k_thread_state_regs *)state;
4693 if(state + sizeof(struct m68k_thread_state_regs) >
4694 (char *)ut + ut->cmdsize){
4695 Mach_O_error(ofile, "malformed object ("
4696 "M68K_THREAD_STATE_REGS in %s command %u "
4697 "extends past end of command)", ut->cmd ==
4698 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4699 "LC_THREAD", i);
4700 goto return_bad;
4702 if(swapped)
4703 swap_m68k_thread_state_regs(cpu, host_byte_sex);
4704 state += sizeof(struct m68k_thread_state_regs);
4705 break;
4706 case M68K_THREAD_STATE_68882:
4707 if(count != M68K_THREAD_STATE_68882_COUNT){
4708 Mach_O_error(ofile, "malformed object (count "
4709 "not M68K_THREAD_STATE_68882_COUNT for "
4710 "flavor number %u which is a M68K_THREAD_"
4711 "STATE_68882 flavor in %s command %u)",
4712 nflavor, ut->cmd == LC_UNIXTHREAD ?
4713 "LC_UNIXTHREAD" : "LC_THREAD", i);
4714 goto return_bad;
4716 fpu = (struct m68k_thread_state_68882 *)state;
4717 if(state + sizeof(struct m68k_thread_state_68882) >
4718 (char *)ut + ut->cmdsize){
4719 Mach_O_error(ofile, "malformed object ("
4720 "M68K_THREAD_STATE_68882 in %s command %u "
4721 "extends past end of command)", ut->cmd ==
4722 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4723 "LC_THREAD", i);
4724 goto return_bad;
4726 if(swapped)
4727 swap_m68k_thread_state_68882(fpu,host_byte_sex);
4728 state += sizeof(struct m68k_thread_state_68882);
4729 break;
4730 case M68K_THREAD_STATE_USER_REG:
4731 if(count != M68K_THREAD_STATE_USER_REG_COUNT){
4732 Mach_O_error(ofile, "malformed object (count "
4733 "not M68K_THREAD_STATE_USER_REG_COUNT for "
4734 "flavor number %u which is a M68K_THREAD_"
4735 "STATE_USER_REG flavor in %s command %u)",
4736 nflavor, ut->cmd == LC_UNIXTHREAD ?
4737 "LC_UNIXTHREAD" : "LC_THREAD", i);
4738 goto return_bad;
4740 user_reg =
4741 (struct m68k_thread_state_user_reg *)state;
4742 if(state+sizeof(struct m68k_thread_state_user_reg) >
4743 (char *)ut + ut->cmdsize){
4744 Mach_O_error(ofile, "malformed object ("
4745 "M68K_THREAD_STATE_USER_REG in %s command "
4746 "%u extends past end of command)", ut->cmd==
4747 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4748 "LC_THREAD", i);
4749 goto return_bad;
4751 if(swapped)
4752 swap_m68k_thread_state_user_reg(user_reg,
4753 host_byte_sex);
4754 state += sizeof(struct m68k_thread_state_user_reg);
4755 break;
4756 default:
4757 if(swapped){
4758 Mach_O_error(ofile, "malformed object (unknown "
4759 "flavor for flavor number %u in %s command"
4760 " %u can't byte swap it)", nflavor,
4761 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4762 "LC_THREAD", i);
4763 goto return_bad;
4765 state += count * sizeof(uint32_t);
4766 break;
4768 nflavor++;
4770 break;
4772 if(cputype == CPU_TYPE_POWERPC ||
4773 cputype == CPU_TYPE_VEO){
4774 ppc_thread_state_t *nrw_cpu;
4776 nflavor = 0;
4777 p = (char *)ut + ut->cmdsize;
4778 while(state < p){
4779 if(state + sizeof(uint32_t) >
4780 (char *)ut + ut->cmdsize){
4781 Mach_O_error(ofile, "malformed object (flavor in "
4782 "%s command %u extends past end of command)",
4783 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4784 "LC_THREAD", i);
4785 goto return_bad;
4787 flavor = *((uint32_t *)state);
4788 if(swapped){
4789 flavor = SWAP_INT(flavor);
4790 *((uint32_t *)state) = flavor;
4792 state += sizeof(uint32_t);
4793 if(state + sizeof(uint32_t) >
4794 (char *)ut + ut->cmdsize){
4795 Mach_O_error(ofile, "malformed object (count in "
4796 "%s command %u extends past end of command)",
4797 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4798 "LC_THREAD", i);
4799 goto return_bad;
4801 count = *((uint32_t *)state);
4802 if(swapped){
4803 count = SWAP_INT(count);
4804 *((uint32_t *)state) = count;
4806 state += sizeof(uint32_t);
4807 switch(flavor){
4808 case PPC_THREAD_STATE:
4809 if(count != PPC_THREAD_STATE_COUNT){
4810 Mach_O_error(ofile, "malformed object (count "
4811 "not PPC_THREAD_STATE_COUNT for "
4812 "flavor number %u which is a PPC_THREAD_"
4813 "STATE flavor in %s command %u)",
4814 nflavor, ut->cmd == LC_UNIXTHREAD ?
4815 "LC_UNIXTHREAD" : "LC_THREAD", i);
4816 goto return_bad;
4818 nrw_cpu = (ppc_thread_state_t *)state;
4819 if(state + sizeof(ppc_thread_state_t) >
4820 (char *)ut + ut->cmdsize){
4821 Mach_O_error(ofile, "malformed object ("
4822 "PPC_THREAD_STATE in %s command %u extends"
4823 " past end of command)", ut->cmd ==
4824 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4825 "LC_THREAD", i);
4826 goto return_bad;
4828 if(swapped)
4829 swap_ppc_thread_state_t(nrw_cpu,
4830 host_byte_sex);
4831 state += sizeof(ppc_thread_state_t);
4832 break;
4833 default:
4834 if(swapped){
4835 Mach_O_error(ofile, "malformed object (unknown "
4836 "flavor for flavor number %u in %s command"
4837 " %u can't byte swap it)", nflavor,
4838 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4839 "LC_THREAD", i);
4840 goto return_bad;
4842 state += count * sizeof(uint32_t);
4843 break;
4845 nflavor++;
4847 break;
4849 #ifdef PPC_THREAD_STATE64_COUNT
4850 if(cputype == CPU_TYPE_POWERPC64){
4851 ppc_thread_state64_t *cpu;
4853 nflavor = 0;
4854 p = (char *)ut + ut->cmdsize;
4855 while(state < p){
4856 if(state + sizeof(uint32_t) >
4857 (char *)ut + ut->cmdsize){
4858 Mach_O_error(ofile, "malformed object (flavor in "
4859 "%s command %u extends past end of command)",
4860 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4861 "LC_THREAD", i);
4862 goto return_bad;
4864 flavor = *((uint32_t *)state);
4865 if(swapped){
4866 flavor = SWAP_INT(flavor);
4867 *((uint32_t *)state) = flavor;
4869 state += sizeof(uint32_t);
4870 if(state + sizeof(uint32_t) >
4871 (char *)ut + ut->cmdsize){
4872 Mach_O_error(ofile, "malformed object (count in "
4873 "%s command %u extends past end of command)",
4874 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4875 "LC_THREAD", i);
4876 goto return_bad;
4878 count = *((uint32_t *)state);
4879 if(swapped){
4880 count = SWAP_INT(count);
4881 *((uint32_t *)state) = count;
4883 state += sizeof(uint32_t);
4884 switch(flavor){
4885 case PPC_THREAD_STATE64:
4886 if(count != PPC_THREAD_STATE64_COUNT){
4887 Mach_O_error(ofile, "malformed object (count "
4888 "not PPC_THREAD_STATE64_COUNT for "
4889 "flavor number %u which is a PPC_THREAD_"
4890 "STATE64 flavor in %s command %u)",
4891 nflavor, ut->cmd == LC_UNIXTHREAD ?
4892 "LC_UNIXTHREAD" : "LC_THREAD", i);
4893 goto return_bad;
4895 cpu = (ppc_thread_state64_t *)state;
4896 if(state + sizeof(ppc_thread_state64_t) >
4897 (char *)ut + ut->cmdsize){
4898 Mach_O_error(ofile, "malformed object ("
4899 "PPC_THREAD_STATE64 in %s command %u "
4900 "extends past end of command)", ut->cmd ==
4901 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4902 "LC_THREAD", i);
4903 goto return_bad;
4905 if(swapped)
4906 swap_ppc_thread_state64_t(cpu, host_byte_sex);
4907 state += sizeof(ppc_thread_state64_t);
4908 break;
4909 default:
4910 if(swapped){
4911 Mach_O_error(ofile, "malformed object (unknown "
4912 "flavor for flavor number %u in %s command"
4913 " %u can't byte swap it)", nflavor,
4914 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4915 "LC_THREAD", i);
4916 goto return_bad;
4918 state += count * sizeof(uint32_t);
4919 break;
4921 nflavor++;
4923 break;
4925 #endif /* PPC_THREAD_STATE64_COUNT */
4926 if(cputype == CPU_TYPE_MC88000){
4927 m88k_thread_state_grf_t *cpu;
4928 m88k_thread_state_xrf_t *fpu;
4929 m88k_thread_state_user_t *user;
4930 m88110_thread_state_impl_t *spu;
4932 nflavor = 0;
4933 p = (char *)ut + ut->cmdsize;
4934 while(state < p){
4935 if(state + sizeof(uint32_t) >
4936 (char *)ut + ut->cmdsize){
4937 Mach_O_error(ofile, "malformed object (flavor in "
4938 "%s command %u extends past end of command)",
4939 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4940 "LC_THREAD", i);
4941 goto return_bad;
4943 flavor = *((uint32_t *)state);
4944 if(swapped){
4945 flavor = SWAP_INT(flavor);
4946 *((uint32_t *)state) = flavor;
4948 state += sizeof(uint32_t);
4949 if(state + sizeof(uint32_t) >
4950 (char *)ut + ut->cmdsize){
4951 Mach_O_error(ofile, "malformed object (count in "
4952 "%s command %u extends past end of command)",
4953 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4954 "LC_THREAD", i);
4955 goto return_bad;
4957 count = *((uint32_t *)state);
4958 if(swapped){
4959 count = SWAP_INT(count);
4960 *((uint32_t *)state) = count;
4962 state += sizeof(uint32_t);
4963 switch(flavor){
4964 case M88K_THREAD_STATE_GRF:
4965 if(count != M88K_THREAD_STATE_GRF_COUNT){
4966 Mach_O_error(ofile, "malformed object (count "
4967 "not M88K_THREAD_STATE_GRF_COUNT for "
4968 "flavor number %u which is a M88K_THREAD_"
4969 "STATE_GRF flavor in %s command %u)",
4970 nflavor, ut->cmd == LC_UNIXTHREAD ?
4971 "LC_UNIXTHREAD" : "LC_THREAD", i);
4972 goto return_bad;
4974 cpu = (m88k_thread_state_grf_t *)state;
4975 if(state + sizeof(m88k_thread_state_grf_t) >
4976 (char *)ut + ut->cmdsize){
4977 Mach_O_error(ofile, "malformed object ("
4978 "M88K_THREAD_STATE_GRF in %s command %u "
4979 "extends past end of command)", ut->cmd ==
4980 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
4981 "LC_THREAD", i);
4982 goto return_bad;
4984 if(swapped)
4985 swap_m88k_thread_state_grf_t(cpu,
4986 host_byte_sex);
4987 state += sizeof(m88k_thread_state_grf_t);
4988 break;
4989 case M88K_THREAD_STATE_XRF:
4990 if(count != M88K_THREAD_STATE_XRF_COUNT){
4991 Mach_O_error(ofile, "malformed object (count "
4992 "not M88K_THREAD_STATE_XRF_COUNT for "
4993 "flavor number %u which is a M88K_THREAD_"
4994 "STATE_XRF flavor in %s command %u)",
4995 nflavor, ut->cmd == LC_UNIXTHREAD ?
4996 "LC_UNIXTHREAD" : "LC_THREAD", i);
4997 goto return_bad;
4999 fpu = (m88k_thread_state_xrf_t *)state;
5000 if(state + sizeof(m88k_thread_state_xrf_t) >
5001 (char *)ut + ut->cmdsize){
5002 Mach_O_error(ofile, "malformed object ("
5003 "M88K_THREAD_STATE_XRF in %s command %u "
5004 "extends past end of command)", ut->cmd ==
5005 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5006 "LC_THREAD", i);
5007 goto return_bad;
5009 if(swapped)
5010 swap_m88k_thread_state_xrf_t(fpu,
5011 host_byte_sex);
5012 state += sizeof(m88k_thread_state_xrf_t);
5013 break;
5014 case M88K_THREAD_STATE_USER:
5015 if(count != M88K_THREAD_STATE_USER_COUNT){
5016 Mach_O_error(ofile, "malformed object (count "
5017 "not M88K_THREAD_STATE_USER_COUNT for "
5018 "flavor number %u which is a M88K_THREAD_"
5019 "STATE_USER flavor in %s command %u)",
5020 nflavor, ut->cmd == LC_UNIXTHREAD ?
5021 "LC_UNIXTHREAD" : "LC_THREAD", i);
5022 goto return_bad;
5024 user = (m88k_thread_state_user_t *)state;
5025 if(state + sizeof(m88k_thread_state_user_t) >
5026 (char *)ut + ut->cmdsize){
5027 Mach_O_error(ofile, "malformed object ("
5028 "M88K_THREAD_STATE_USER in %s command %u "
5029 "extends past end of command)", ut->cmd ==
5030 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5031 "LC_THREAD", i);
5032 goto return_bad;
5034 if(swapped)
5035 swap_m88k_thread_state_user_t(user,
5036 host_byte_sex);
5037 state += sizeof(m88k_thread_state_user_t);
5038 break;
5039 case M88110_THREAD_STATE_IMPL:
5040 if(count != M88110_THREAD_STATE_IMPL_COUNT){
5041 Mach_O_error(ofile, "malformed object (count "
5042 "not M88110_THREAD_STATE_IMPL_COUNT for "
5043 "flavor number %u which is a M88110_THREAD"
5044 "_STATE_IMPL flavor in %s command %u)",
5045 nflavor, ut->cmd == LC_UNIXTHREAD ?
5046 "LC_UNIXTHREAD" : "LC_THREAD", i);
5047 goto return_bad;
5049 spu = (m88110_thread_state_impl_t *)state;
5050 if(state + sizeof(m88110_thread_state_impl_t) >
5051 (char *)ut + ut->cmdsize){
5052 Mach_O_error(ofile, "malformed object ("
5053 "M88110_THREAD_STATE_IMPL in %s command %u "
5054 "extends past end of command)", ut->cmd ==
5055 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5056 "LC_THREAD", i);
5057 goto return_bad;
5059 if(swapped)
5060 swap_m88110_thread_state_impl_t(spu,
5061 host_byte_sex);
5062 state += sizeof(m88110_thread_state_impl_t);
5063 break;
5064 default:
5065 if(swapped){
5066 Mach_O_error(ofile, "malformed object (unknown "
5067 "flavor for flavor number %u in %s command"
5068 " %u can't byte swap it)", nflavor,
5069 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5070 "LC_THREAD", i);
5071 goto return_bad;
5073 state += count * sizeof(uint32_t);
5074 break;
5076 nflavor++;
5078 break;
5080 if(cputype == CPU_TYPE_I860){
5081 #ifdef m68k
5082 struct i860_thread_state_regs *cpu;
5083 #endif
5085 nflavor = 0;
5086 p = (char *)ut + ut->cmdsize;
5087 while(state < p){
5088 if(state + sizeof(uint32_t) >
5089 (char *)ut + ut->cmdsize){
5090 Mach_O_error(ofile, "malformed object (flavor in "
5091 "%s command %u extends past end of command)",
5092 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5093 "LC_THREAD", i);
5094 goto return_bad;
5096 flavor = *((uint32_t *)state);
5097 if(swapped){
5098 flavor = SWAP_INT(flavor);
5099 *((uint32_t *)state) = flavor;
5101 state += sizeof(uint32_t);
5102 if(state + sizeof(uint32_t) >
5103 (char *)ut + ut->cmdsize){
5104 Mach_O_error(ofile, "malformed object (count in "
5105 "%s command %u extends past end of command)",
5106 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5107 "LC_THREAD", i);
5108 return(CHECK_BAD);
5110 count = *((uint32_t *)state);
5111 if(swapped){
5112 count = SWAP_INT(count);
5113 *((uint32_t *)state) = count;
5115 state += sizeof(uint32_t);
5116 switch(flavor){
5117 case I860_THREAD_STATE_REGS:
5118 #ifdef m68k
5119 if(count != I860_THREAD_STATE_REGS_COUNT){
5120 Mach_O_error(ofile, "malformed object (count "
5121 "not I860_THREAD_STATE_REGS_COUNT for "
5122 "flavor number %u which is a I860_THREAD_"
5123 "STATE_REGS flavor in %s command %u)",
5124 nflavor, ut->cmd == LC_UNIXTHREAD ?
5125 "LC_UNIXTHREAD" : "LC_THREAD", i);
5126 goto return_bad;
5128 cpu = (struct i860_thread_state_regs *)state;
5129 if(state + sizeof(struct i860_thread_state_regs) >
5130 (char *)ut + ut->cmdsize){
5131 Mach_O_error(ofile, "malformed object ("
5132 "I860_THREAD_STATE_REGS in %s command %u "
5133 "extends past end of command)", ut->cmd ==
5134 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5135 "LC_THREAD", i);
5136 goto return_bad;
5138 if(swapped)
5139 swap_i860_thread_state_regs(cpu, host_byte_sex);
5140 state += sizeof(struct i860_thread_state_regs);
5141 #else
5142 state += count * sizeof(int);
5143 #endif
5144 break;
5145 default:
5146 if(swapped){
5147 Mach_O_error(ofile, "malformed object (unknown "
5148 "flavor for flavor number %u in %s command"
5149 " %u can't byte swap it)", nflavor,
5150 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5151 "LC_THREAD", i);
5152 goto return_bad;
5154 state += count * sizeof(uint32_t);
5155 break;
5157 nflavor++;
5159 break;
5161 if(cputype == CPU_TYPE_I386){
5162 i386_thread_state_t *cpu;
5163 /* current i386 thread states */
5164 #if i386_THREAD_STATE == 1
5165 struct i386_float_state *fpu;
5166 i386_exception_state_t *exc;
5167 #endif /* i386_THREAD_STATE == 1 */
5169 /* i386 thread states on older releases */
5170 #if i386_THREAD_STATE == -1
5171 i386_thread_fpstate_t *fpu;
5172 i386_thread_exceptstate_t *exc;
5173 i386_thread_cthreadstate_t *user;
5174 #endif /* i386_THREAD_STATE == -1 */
5176 nflavor = 0;
5177 p = (char *)ut + ut->cmdsize;
5178 while(state < p){
5179 if(state + sizeof(uint32_t) >
5180 (char *)ut + ut->cmdsize){
5181 Mach_O_error(ofile, "malformed object (flavor in "
5182 "%s command %u extends past end of command)",
5183 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5184 "LC_THREAD", i);
5185 goto return_bad;
5187 flavor = *((uint32_t *)state);
5188 if(swapped){
5189 flavor = SWAP_INT(flavor);
5190 *((uint32_t *)state) = flavor;
5192 state += sizeof(uint32_t);
5193 if(state + sizeof(uint32_t) >
5194 (char *)ut + ut->cmdsize){
5195 Mach_O_error(ofile, "malformed object (count in "
5196 "%s command %u extends past end of command)",
5197 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5198 "LC_THREAD", i);
5199 goto return_bad;
5201 count = *((uint32_t *)state);
5202 if(swapped){
5203 count = SWAP_INT(count);
5204 *((uint32_t *)state) = count;
5206 state += sizeof(uint32_t);
5207 switch((int)flavor){
5208 case i386_THREAD_STATE:
5209 #if i386_THREAD_STATE == 1
5210 case -1:
5211 #endif /* i386_THREAD_STATE == 1 */
5212 /* i386 thread states on older releases */
5213 #if i386_THREAD_STATE == -1
5214 case 1:
5215 #endif /* i386_THREAD_STATE == -1 */
5216 if(count != i386_THREAD_STATE_COUNT){
5217 Mach_O_error(ofile, "malformed object (count "
5218 "not i386_THREAD_STATE_COUNT for flavor "
5219 "number %u which is a i386_THREAD_STATE "
5220 "flavor in %s command %u)", nflavor,
5221 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5222 "LC_THREAD", i);
5223 goto return_bad;
5225 cpu = (i386_thread_state_t *)state;
5226 if(state + sizeof(i386_thread_state_t) >
5227 (char *)ut + ut->cmdsize){
5228 Mach_O_error(ofile, "malformed object ("
5229 "i386_THREAD_STATE in %s command %u "
5230 "extends past end of command)", ut->cmd ==
5231 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5232 "LC_THREAD", i);
5233 goto return_bad;
5235 if(swapped)
5236 swap_i386_thread_state(cpu, host_byte_sex);
5237 state += sizeof(i386_thread_state_t);
5238 break;
5239 /* current i386 thread states */
5240 #if i386_THREAD_STATE == 1
5241 case i386_FLOAT_STATE:
5242 if(count != i386_FLOAT_STATE_COUNT){
5243 Mach_O_error(ofile, "malformed object (count "
5244 "not i386_FLOAT_STATE_COUNT for flavor "
5245 "number %u which is a i386_FLOAT_STATE "
5246 "flavor in %s command %u)", nflavor,
5247 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5248 "LC_THREAD", i);
5249 goto return_bad;
5251 fpu = (struct i386_float_state *)state;
5252 if(state + sizeof(struct i386_float_state) >
5253 (char *)ut + ut->cmdsize){
5254 Mach_O_error(ofile, "malformed object ("
5255 "i386_FLOAT_STATE in %s command %u "
5256 "extends past end of command)", ut->cmd ==
5257 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5258 "LC_THREAD", i);
5259 goto return_bad;
5261 if(swapped)
5262 swap_i386_float_state(fpu, host_byte_sex);
5263 state += sizeof(struct i386_float_state);
5264 break;
5265 case i386_EXCEPTION_STATE:
5266 if(count != I386_EXCEPTION_STATE_COUNT){
5267 Mach_O_error(ofile, "malformed object (count "
5268 "not I386_EXCEPTION_STATE_COUNT for "
5269 "flavor number %u which is a i386_"
5270 "EXCEPTION_STATE flavor in %s command %u)",
5271 nflavor,
5272 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5273 "LC_THREAD", i);
5274 goto return_bad;
5276 exc = (i386_exception_state_t *)state;
5277 if(state + sizeof(i386_exception_state_t) >
5278 (char *)ut + ut->cmdsize){
5279 Mach_O_error(ofile, "malformed object ("
5280 "i386_EXCEPTION_STATE in %s command %u "
5281 "extends past end of command)", ut->cmd ==
5282 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5283 "LC_THREAD", i);
5284 goto return_bad;
5286 if(swapped)
5287 swap_i386_exception_state(exc,host_byte_sex);
5288 state += sizeof(i386_exception_state_t);
5289 break;
5290 #endif /* i386_THREAD_STATE == 1 */
5292 /* i386 thread states on older releases */
5293 #if i386_THREAD_STATE == -1
5294 case i386_THREAD_FPSTATE:
5295 if(count != i386_THREAD_FPSTATE_COUNT){
5296 Mach_O_error(ofile, "malformed object (count "
5297 "not i386_THREAD_FPSTATE_COUNT for flavor "
5298 "number %u which is a i386_THREAD_FPSTATE "
5299 "flavor in %s command %u)", nflavor,
5300 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5301 "LC_THREAD", i);
5302 goto return_bad;
5304 fpu = (i386_thread_fpstate_t *)state;
5305 if(state + sizeof(i386_thread_fpstate_t) >
5306 (char *)ut + ut->cmdsize){
5307 Mach_O_error(ofile, "malformed object ("
5308 "i386_THREAD_FPSTATE in %s command %u "
5309 "extends past end of command)", ut->cmd ==
5310 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5311 "LC_THREAD", i);
5312 goto return_bad;
5314 if(swapped)
5315 swap_i386_thread_fpstate(fpu, host_byte_sex);
5316 state += sizeof(i386_thread_fpstate_t);
5317 break;
5318 case i386_THREAD_EXCEPTSTATE:
5319 if(count != i386_THREAD_EXCEPTSTATE_COUNT){
5320 Mach_O_error(ofile, "malformed object (count "
5321 "not i386_THREAD_EXCEPTSTATE_COUNT for "
5322 "flavor number %u which is a i386_THREAD_"
5323 "EXCEPTSTATE flavor in %s command %u)",
5324 nflavor,
5325 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5326 "LC_THREAD", i);
5327 goto return_bad;
5329 exc = (i386_thread_exceptstate_t *)state;
5330 if(state + sizeof(i386_thread_exceptstate_t) >
5331 (char *)ut + ut->cmdsize){
5332 Mach_O_error(ofile, "malformed object ("
5333 "i386_THREAD_EXCEPTSTATE in %s command %u "
5334 "extends past end of command)", ut->cmd ==
5335 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5336 "LC_THREAD", i);
5337 goto return_bad;
5339 if(swapped)
5340 swap_i386_thread_exceptstate(exc,host_byte_sex);
5341 state += sizeof(i386_thread_exceptstate_t);
5342 break;
5343 case i386_THREAD_CTHREADSTATE:
5344 if(count != i386_THREAD_CTHREADSTATE_COUNT){
5345 Mach_O_error(ofile, "malformed object (count "
5346 "not i386_THREAD_CTHREADSTATE_COUNT for "
5347 "flavor number %u which is a i386_THREAD_"
5348 "CTHREADSTATE flavor in %s command %u)",
5349 nflavor,
5350 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5351 "LC_THREAD", i);
5352 goto return_bad;
5354 user = (i386_thread_cthreadstate_t *)state;
5355 if(state + sizeof(i386_thread_cthreadstate_t) >
5356 (char *)ut + ut->cmdsize){
5357 Mach_O_error(ofile, "malformed object ("
5358 "i386_THREAD_CTHREADSTATE in %s command %u "
5359 "extends past end of command)", ut->cmd ==
5360 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5361 "LC_THREAD", i);
5362 goto return_bad;
5364 if(swapped)
5365 swap_i386_thread_cthreadstate(user,
5366 host_byte_sex);
5367 state += sizeof(i386_thread_cthreadstate_t);
5368 break;
5369 #endif /* i386_THREAD_STATE == -1 */
5370 default:
5371 if(swapped){
5372 Mach_O_error(ofile, "malformed object (unknown "
5373 "flavor for flavor number %u in %s command"
5374 " %u can't byte swap it)", nflavor,
5375 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5376 "LC_THREAD", i);
5377 goto return_bad;
5379 state += count * sizeof(uint32_t);
5380 break;
5382 nflavor++;
5384 break;
5386 #ifdef x86_THREAD_STATE64_COUNT
5387 if(cputype == CPU_TYPE_X86_64){
5388 x86_thread_state64_t *cpu;
5390 nflavor = 0;
5391 p = (char *)ut + ut->cmdsize;
5392 while(state < p){
5393 if(state + sizeof(uint32_t) >
5394 (char *)ut + ut->cmdsize){
5395 Mach_O_error(ofile, "malformed object (flavor in "
5396 "%s command %u extends past end of command)",
5397 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5398 "LC_THREAD", i);
5399 goto return_bad;
5401 flavor = *((uint32_t *)state);
5402 if(swapped){
5403 flavor = SWAP_INT(flavor);
5404 *((uint32_t *)state) = flavor;
5406 state += sizeof(uint32_t);
5407 if(state + sizeof(uint32_t) >
5408 (char *)ut + ut->cmdsize){
5409 Mach_O_error(ofile, "malformed object (count in "
5410 "%s command %u extends past end of command)",
5411 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5412 "LC_THREAD", i);
5413 goto return_bad;
5415 count = *((uint32_t *)state);
5416 if(swapped){
5417 count = SWAP_INT(count);
5418 *((uint32_t *)state) = count;
5420 state += sizeof(uint32_t);
5421 switch(flavor){
5422 case x86_THREAD_STATE64:
5423 if(count != x86_THREAD_STATE64_COUNT){
5424 Mach_O_error(ofile, "malformed object (count "
5425 "not x86_THREAD_STATE64_COUNT for "
5426 "flavor number %u which is a x86_THREAD_"
5427 "STATE64 flavor in %s command %u)",
5428 nflavor, ut->cmd == LC_UNIXTHREAD ?
5429 "LC_UNIXTHREAD" : "LC_THREAD", i);
5430 goto return_bad;
5432 cpu = (x86_thread_state64_t *)state;
5433 if(state + sizeof(x86_thread_state64_t) >
5434 (char *)ut + ut->cmdsize){
5435 Mach_O_error(ofile, "malformed object ("
5436 "x86_THREAD_STATE64 in %s command %u "
5437 "extends past end of command)", ut->cmd ==
5438 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5439 "LC_THREAD", i);
5440 goto return_bad;
5442 if(swapped)
5443 swap_x86_thread_state64(cpu, host_byte_sex);
5444 state += sizeof(x86_thread_state64_t);
5445 break;
5446 default:
5447 if(swapped){
5448 Mach_O_error(ofile, "malformed object (unknown "
5449 "flavor for flavor number %u in %s command"
5450 " %u can't byte swap it)", nflavor,
5451 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5452 "LC_THREAD", i);
5453 goto return_bad;
5455 state += count * sizeof(uint32_t);
5456 break;
5458 nflavor++;
5460 break;
5462 #endif /* x86_THREAD_STATE64_COUNT */
5463 if(cputype == CPU_TYPE_HPPA){
5464 struct hp_pa_integer_thread_state *cpu;
5465 struct hp_pa_frame_thread_state *frame;
5466 struct hp_pa_fp_thread_state *fpu;
5468 nflavor = 0;
5469 p = (char *)ut + ut->cmdsize;
5470 while(state < p){
5471 if(state + sizeof(uint32_t) >
5472 (char *)ut + ut->cmdsize){
5473 Mach_O_error(ofile, "malformed object (flavor in "
5474 "%s command %u extends past end of command)",
5475 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5476 "LC_THREAD", i);
5477 goto return_bad;
5479 flavor = *((uint32_t *)state);
5480 if(swapped){
5481 flavor = SWAP_INT(flavor);
5482 *((uint32_t *)state) = flavor;
5484 state += sizeof(uint32_t);
5485 if(state + sizeof(uint32_t) >
5486 (char *)ut + ut->cmdsize){
5487 Mach_O_error(ofile, "malformed object (count in "
5488 "%s command %u extends past end of command)",
5489 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5490 "LC_THREAD", i);
5491 goto return_bad;
5493 count = *((uint32_t *)state);
5494 if(swapped){
5495 count = SWAP_INT(count);
5496 *((uint32_t *)state) = count;
5498 state += sizeof(uint32_t);
5499 switch(flavor){
5500 case HPPA_INTEGER_THREAD_STATE:
5501 if(count != HPPA_INTEGER_THREAD_STATE_COUNT){
5502 Mach_O_error(ofile, "malformed object (count "
5503 "not HPPA_INTEGER_THREAD_STATE_COUNT for "
5504 "flavor number %u which is a "
5505 "HPPA_INTEGER_THREAD_STATE "
5506 "flavor in %s command %u)", nflavor,
5507 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5508 "LC_THREAD", i);
5509 goto return_bad;
5511 cpu = (struct hp_pa_integer_thread_state *)state;
5512 if(state+sizeof(struct hp_pa_integer_thread_state) >
5513 (char *)ut + ut->cmdsize){
5514 Mach_O_error(ofile, "malformed object ("
5515 "HPPA_INTEGER_THREAD_STATE in %s command "
5516 "%u extends past end of command)",
5517 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5518 "LC_THREAD", i);
5519 goto return_bad;
5521 if(swapped)
5522 swap_hppa_integer_thread_state(cpu,
5523 host_byte_sex);
5524 state += sizeof(struct hp_pa_integer_thread_state);
5525 break;
5526 case HPPA_FRAME_THREAD_STATE:
5527 if(count != HPPA_FRAME_THREAD_STATE_COUNT){
5528 Mach_O_error(ofile, "malformed object (count "
5529 "not HPPA_FRAME_THREAD_STATE_COUNT for "
5530 "flavor number %u which is a HPPA_FRAME_"
5531 "THREAD_STATE flavor in %s command %u)",
5532 nflavor,
5533 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5534 "LC_THREAD", i);
5535 goto return_bad;
5537 frame = (struct hp_pa_frame_thread_state *)state;
5538 if(state + sizeof(struct hp_pa_frame_thread_state) >
5539 (char *)ut + ut->cmdsize){
5540 Mach_O_error(ofile, "malformed object ("
5541 "HPPA_FRAME_THREAD_STATE in %s command "
5542 "%u extends past end of command)",
5543 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5544 "LC_THREAD", i);
5545 goto return_bad;
5547 if(swapped)
5548 swap_hppa_frame_thread_state(frame,host_byte_sex);
5549 state += sizeof(struct hp_pa_frame_thread_state);
5550 break;
5551 case HPPA_FP_THREAD_STATE:
5552 if(count != HPPA_FP_THREAD_STATE_COUNT){
5553 Mach_O_error(ofile, "malformed object (count "
5554 "not HPPA_FP_THREAD_STATE_COUNT for "
5555 "flavor number %u which is a HPPA_FP_"
5556 "THREAD_STATE flavor in %s command %u)",
5557 nflavor,
5558 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5559 "LC_THREAD", i);
5560 goto return_bad;
5562 fpu = (struct hp_pa_fp_thread_state *)state;
5563 if(state + sizeof(struct hp_pa_fp_thread_state) >
5564 (char *)ut + ut->cmdsize){
5565 Mach_O_error(ofile, "malformed object ("
5566 "HPPA_FP_THREAD_STATE in %s command "
5567 "%u extends past end of command)",
5568 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5569 "LC_THREAD", i);
5570 goto return_bad;
5572 if(swapped)
5573 swap_hppa_fp_thread_state(fpu,host_byte_sex);
5574 state += sizeof(struct hp_pa_fp_thread_state);
5575 break;
5576 default:
5577 if(swapped){
5578 Mach_O_error(ofile, "malformed object (unknown "
5579 "flavor for flavor number %u in %s command"
5580 " %u can't byte swap it)", nflavor,
5581 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5582 "LC_THREAD", i);
5583 goto return_bad;
5585 state += count * sizeof(uint32_t);
5586 break;
5588 nflavor++;
5590 break;
5592 if(cputype == CPU_TYPE_SPARC){
5593 struct sparc_thread_state_regs *cpu;
5594 struct sparc_thread_state_fpu *fpu;
5596 nflavor = 0;
5597 p = (char *)ut + ut->cmdsize;
5598 while(state < p){
5599 if(state + sizeof(uint32_t) >
5600 (char *)ut + ut->cmdsize){
5601 Mach_O_error(ofile, "malformed object (flavor in "
5602 "%s command %u extends past end of command)",
5603 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5604 "LC_THREAD", i);
5605 goto return_bad;
5607 flavor = *((uint32_t *)state);
5608 if(swapped){
5609 flavor = SWAP_INT(flavor);
5610 *((uint32_t *)state) = flavor;
5612 state += sizeof(uint32_t);
5613 if(state + sizeof(uint32_t) >
5614 (char *)ut + ut->cmdsize){
5615 Mach_O_error(ofile, "malformed object (count in "
5616 "%s command %u extends past end of command)",
5617 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5618 "LC_THREAD", i);
5619 goto return_bad;
5621 count = *((uint32_t *)state);
5622 if(swapped){
5623 count = SWAP_INT(count);
5624 *((uint32_t *)state) = count;
5626 state += sizeof(uint32_t);
5627 switch(flavor){
5628 case SPARC_THREAD_STATE_REGS:
5629 if(count != SPARC_THREAD_STATE_REGS_COUNT){
5630 Mach_O_error(ofile, "malformed object (count "
5631 "not SPARC_THREAD_STATE_REGS_COUNT for "
5632 "flavor number %u which is a SPARC_THREAD_"
5633 "STATE_REGS flavor in %s command %u)",
5634 nflavor, ut->cmd == LC_UNIXTHREAD ?
5635 "LC_UNIXTHREAD" : "LC_THREAD", i);
5636 goto return_bad;
5638 cpu = (struct sparc_thread_state_regs *)state;
5639 if(state + sizeof(struct sparc_thread_state_regs) >
5640 (char *)ut + ut->cmdsize){
5641 Mach_O_error(ofile, "malformed object ("
5642 "SPARC_THREAD_STATE_REGS in %s command %u "
5643 "extends past end of command)", ut->cmd ==
5644 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5645 "LC_THREAD", i);
5646 goto return_bad;
5648 if(swapped)
5649 swap_sparc_thread_state_regs(cpu, host_byte_sex);
5650 state += sizeof(struct sparc_thread_state_regs);
5651 break;
5652 case SPARC_THREAD_STATE_FPU:
5653 if(count != SPARC_THREAD_STATE_FPU_COUNT){
5654 Mach_O_error(ofile, "malformed object (count "
5655 "not SPARC_THREAD_STATE_FPU_COUNT for "
5656 "flavor number %u which is a SPARC_THREAD_"
5657 "STATE_FPU flavor in %s command %u)",
5658 nflavor, ut->cmd == LC_UNIXTHREAD ?
5659 "LC_UNIXTHREAD" : "LC_THREAD", i);
5660 goto return_bad;
5662 fpu = (struct sparc_thread_state_fpu *)state;
5663 if(state + sizeof(struct sparc_thread_state_fpu) >
5664 (char *)ut + ut->cmdsize){
5665 Mach_O_error(ofile, "malformed object ("
5666 "SPARC_THREAD_STATE_FPU in %s command %u "
5667 "extends past end of command)", ut->cmd ==
5668 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5669 "LC_THREAD", i);
5670 goto return_bad;
5672 if(swapped)
5673 swap_sparc_thread_state_fpu(fpu, host_byte_sex);
5674 state += sizeof(struct sparc_thread_state_fpu);
5675 break;
5676 default:
5677 if(swapped){
5678 Mach_O_error(ofile, "malformed object (unknown "
5679 "flavor for flavor number %u in %s command"
5680 " %u can't byte swap it)", nflavor,
5681 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5682 "LC_THREAD", i);
5683 goto return_bad;
5685 state += count * sizeof(uint32_t);
5686 break;
5688 nflavor++;
5690 break;
5692 if(cputype == CPU_TYPE_ARM){
5693 arm_thread_state_t *cpu;
5695 nflavor = 0;
5696 p = (char *)ut + ut->cmdsize;
5697 while(state < p){
5698 if(state + sizeof(uint32_t) >
5699 (char *)ut + ut->cmdsize){
5700 Mach_O_error(ofile, "malformed object (flavor in "
5701 "%s command %u extends past end of command)",
5702 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5703 "LC_THREAD", i);
5704 goto return_bad;
5706 flavor = *((uint32_t *)state);
5707 if(swapped){
5708 flavor = SWAP_INT(flavor);
5709 *((uint32_t *)state) = flavor;
5711 state += sizeof(uint32_t);
5712 if(state + sizeof(uint32_t) >
5713 (char *)ut + ut->cmdsize){
5714 Mach_O_error(ofile, "malformed object (count in "
5715 "%s command %u extends past end of command)",
5716 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5717 "LC_THREAD", i);
5718 goto return_bad;
5720 count = *((uint32_t *)state);
5721 if(swapped){
5722 count = SWAP_INT(count);
5723 *((uint32_t *)state) = count;
5725 state += sizeof(uint32_t);
5726 switch(flavor){
5727 case ARM_THREAD_STATE:
5728 if(count != ARM_THREAD_STATE_COUNT){
5729 Mach_O_error(ofile, "malformed object (count "
5730 "not ARM_THREAD_STATE_COUNT for "
5731 "flavor number %u which is a ARM_THREAD_"
5732 "STATE flavor in %s command %u)",
5733 nflavor, ut->cmd == LC_UNIXTHREAD ?
5734 "LC_UNIXTHREAD" : "LC_THREAD", i);
5735 goto return_bad;
5737 cpu = (arm_thread_state_t *)state;
5738 if(state + sizeof(arm_thread_state_t) >
5739 (char *)ut + ut->cmdsize){
5740 Mach_O_error(ofile, "malformed object ("
5741 "ARM_THREAD_STATE in %s command %u "
5742 "extends past end of command)", ut->cmd ==
5743 LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5744 "LC_THREAD", i);
5745 goto return_bad;
5747 if(swapped)
5748 swap_arm_thread_state_t(cpu, host_byte_sex);
5749 state += sizeof(arm_thread_state_t);
5750 break;
5751 default:
5752 if(swapped){
5753 Mach_O_error(ofile, "malformed object (unknown "
5754 "flavor for flavor number %u in %s command"
5755 " %u can't byte swap it)", nflavor,
5756 ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" :
5757 "LC_THREAD", i);
5758 goto return_bad;
5760 state += count * sizeof(uint32_t);
5761 break;
5763 nflavor++;
5765 break;
5767 if(swapped){
5768 Mach_O_error(ofile, "malformed object (unknown cputype and "
5769 "cpusubtype of object and can't byte swap and check %s "
5770 "command %u)", ut->cmd == LC_UNIXTHREAD ?
5771 "LC_UNIXTHREAD" : "LC_THREAD", i);
5772 goto return_bad;
5774 break;
5775 case LC_MAIN:
5776 if(l.cmdsize < sizeof(struct entry_point_command)){
5777 Mach_O_error(ofile, "malformed object (LC_MAIN cmdsize "
5778 "too small) in command %u", i);
5779 goto return_bad;
5781 ep = (struct entry_point_command *)lc;
5782 if(swapped)
5783 swap_entry_point_command(ep, host_byte_sex);
5785 * If we really wanted we could check that the entryoff field
5786 * really is an offset into the __TEXT segment. But since it
5787 * is not used here, we won't needlessly check it.
5789 break;
5790 case LC_SOURCE_VERSION:
5791 if(l.cmdsize < sizeof(struct source_version_command)){
5792 Mach_O_error(ofile, "malformed object (LC_SOURCE_VERSION "
5793 "cmdsize too small) in command %u", i);
5794 goto return_bad;
5796 sv = (struct source_version_command *)lc;
5797 if(swapped)
5798 swap_source_version_command(sv, host_byte_sex);
5799 case LC_IDENT:
5800 if(l.cmdsize < sizeof(struct ident_command)){
5801 Mach_O_error(ofile, "malformed object (LC_IDENT cmdsize "
5802 "too small) in command %u", i);
5803 goto return_bad;
5805 id = (struct ident_command *)lc;
5806 if(swapped)
5807 swap_ident_command(id, host_byte_sex);
5809 * Note the cmdsize field if the LC_IDENT command was checked
5810 * as part of checking all load commands cmdsize field before
5811 * the switch statement on the cmd field of the load command.
5813 break;
5814 case LC_RPATH:
5815 if(l.cmdsize < sizeof(struct rpath_command)){
5816 Mach_O_error(ofile, "malformed object (LC_RPATH: cmdsize "
5817 "too small) in command %u", i);
5818 goto return_bad;
5820 rpath = (struct rpath_command *)lc;
5821 if(swapped)
5822 swap_rpath_command(rpath, host_byte_sex);
5823 if(rpath->cmdsize < sizeof(struct rpath_command)){
5824 Mach_O_error(ofile, "malformed object (LC_RPATH command "
5825 "%u has too small cmdsize field)", i);
5826 goto return_bad;
5828 if(rpath->path.offset >= rpath->cmdsize){
5829 Mach_O_error(ofile, "truncated or malformed object (path."
5830 "offset field of LC_RPATH command %u extends past the "
5831 "end of the file)", i);
5832 goto return_bad;
5834 break;
5836 #ifndef OFI
5837 default:
5838 Mach_O_error(ofile, "malformed object (unknown load command "
5839 "%u)", i);
5840 goto return_bad;
5841 #endif /* !defined(OFI) */
5844 lc = (struct load_command *)((char *)lc + l.cmdsize);
5845 /* check that next load command does not extends past the end */
5846 if((char *)lc > (char *)load_commands + sizeofcmds){
5847 Mach_O_error(ofile, "truncated or malformed object (load "
5848 "command %u extends past the end of the file)",
5849 i + 1);
5850 goto return_bad;
5853 if(st == NULL){
5854 if(dyst != NULL){
5855 Mach_O_error(ofile, "truncated or malformed object (contains "
5856 "LC_DYSYMTAB load command without a LC_SYMTAB load command)");
5857 goto return_bad;
5860 else{
5861 if(dyst != NULL){
5862 if(dyst->nlocalsym != 0 &&
5863 dyst->ilocalsym > st->nsyms){
5864 Mach_O_error(ofile, "truncated or malformed object "
5865 "(ilocalsym in LC_DYSYMTAB load command extends past "
5866 "the end of the symbol table)");
5867 goto return_bad;
5869 big_size = dyst->ilocalsym;
5870 big_size += dyst->nlocalsym;
5871 if(dyst->nlocalsym != 0 && big_size > st->nsyms){
5872 Mach_O_error(ofile, "truncated or malformed object "
5873 "(ilocalsym plus nlocalsym in LC_DYSYMTAB load command "
5874 "extends past the end of the symbol table)");
5875 goto return_bad;
5878 if(dyst->nextdefsym != 0 &&
5879 dyst->iextdefsym > st->nsyms){
5880 Mach_O_error(ofile, "truncated or malformed object "
5881 "(iextdefsym in LC_DYSYMTAB load command extends past "
5882 "the end of the symbol table)");
5883 goto return_bad;
5885 big_size = dyst->iextdefsym;
5886 big_size += dyst->nextdefsym;
5887 if(dyst->nextdefsym != 0 && big_size > st->nsyms){
5888 Mach_O_error(ofile, "truncated or malformed object "
5889 "(iextdefsym plus nextdefsym in LC_DYSYMTAB load "
5890 "command extends past the end of the symbol table)");
5891 goto return_bad;
5894 if(dyst->nundefsym != 0 &&
5895 dyst->iundefsym > st->nsyms){
5896 Mach_O_error(ofile, "truncated or malformed object "
5897 "(iundefsym in LC_DYSYMTAB load command extends past "
5898 "the end of the symbol table)");
5899 goto return_bad;
5901 big_size = dyst->iundefsym;
5902 big_size += dyst->nundefsym;
5903 if(dyst->nundefsym != 0 && big_size > st->nsyms){
5904 Mach_O_error(ofile, "truncated or malformed object "
5905 "(iundefsym plus nundefsym in LC_DYSYMTAB load command "
5906 "extends past the end of the symbol table)");
5907 goto return_bad;
5909 if(rc != NULL){
5910 if(rc->init_module > dyst->nmodtab){
5911 Mach_O_error(ofile, "malformed object (init_module in "
5912 "LC_ROUTINES load command extends past the "
5913 "end of the module table)");
5914 goto return_bad;
5917 if(rc64 != NULL){
5918 if(rc64->init_module > dyst->nmodtab){
5919 Mach_O_error(ofile, "malformed object (init_module in "
5920 "LC_ROUTINES_64 load command extends past the "
5921 "end of the module table)");
5922 goto return_bad;
5925 if(hints != NULL){
5926 if(hints->nhints != dyst->nundefsym){
5927 Mach_O_error(ofile, "malformed object (nhints in "
5928 "LC_TWOLEVEL_HINTS load command not the same as "
5929 "nundefsym in LC_DYSYMTAB load command)");
5930 goto return_bad;
5935 /* check for an inconsistent size of the load commands */
5936 if((char *)load_commands + sizeofcmds != (char *)lc){
5937 Mach_O_error(ofile, "malformed object (inconsistent sizeofcmds "
5938 "field in mach header)");
5939 goto return_bad;
5943 * Mark this ofile so we know its headers have been swapped. We do this
5944 * in case we don't process it the first time so we can swap them back
5945 * in case we loop back to it in a fat file to process it later.
5947 if(swapped == TRUE)
5948 ofile->headers_swapped = TRUE;
5950 /* looks good return ok */
5951 free_elements(&elements);
5952 return(CHECK_GOOD);
5954 return_bad:
5955 free_elements(&elements);
5956 return(CHECK_BAD);
5957 #endif /* OTOOL */
5961 * swap_back_Mach_O() is called after the ofile has been processed to swap back
5962 * the mach header and load commands if check_Mach_O() above swapped them.
5964 static
5965 void
5966 swap_back_Mach_O(
5967 struct ofile *ofile)
5969 if(ofile->headers_swapped == TRUE){
5970 ofile->headers_swapped = FALSE;
5971 if(ofile->mh != NULL)
5972 swap_object_headers(ofile->mh, ofile->load_commands);
5973 else if(ofile->mh64 != NULL)
5974 swap_object_headers(ofile->mh64, ofile->load_commands);
5978 #ifndef OTOOL
5980 * check_overlaping_element() checks that the element in the ofile described by
5981 * offset, size and name does not overlap in list of elements in head. If it
5982 * does CHECK_BAD is returned and an error message is generated. If it doesn't
5983 * then an element is added in the ordered list and CHECK_GOOD is returned
5985 static
5986 enum check_type
5987 check_overlaping_element(
5988 struct ofile *ofile,
5989 struct element *head,
5990 uint32_t offset,
5991 uint32_t size,
5992 char *name)
5994 struct element *e, *p, *n;
5996 if(size == 0)
5997 return(CHECK_GOOD);
5999 if(head->next == NULL){
6000 n = allocate(sizeof(struct element));
6001 n->offset = offset;
6002 n->size = size;
6003 n->name = name;
6004 n->next = NULL;
6005 head->next = n;
6006 return(CHECK_GOOD);
6009 p = NULL;
6010 e = head;
6011 while(e->next != NULL){
6012 p = e;
6013 e = e->next;
6014 if((offset >= e->offset &&
6015 offset < e->offset + e->size) ||
6016 (offset + size > e->offset &&
6017 offset + size < e->offset + e->size) ||
6018 (offset <= e->offset &&
6019 offset + size >= e->offset + e->size)){
6020 Mach_O_error(ofile, "malformed object (%s at offset %u with a "
6021 "size of %u, overlaps %s at offset %u with a size of %u)",
6022 name, offset, size, e->name, e->offset, e->size);
6023 return(CHECK_BAD);
6025 if(e->next != NULL && offset + size <= e->next->offset){
6026 n = allocate(sizeof(struct element));
6027 n->offset = offset;
6028 n->size = size;
6029 n->name = name;
6030 n->next = e;
6031 p->next = n;
6032 return(CHECK_GOOD);
6035 n = allocate(sizeof(struct element));
6036 n->offset = offset;
6037 n->size = size;
6038 n->name = name;
6039 n->next = NULL;
6040 e->next = n;
6041 return(CHECK_GOOD);
6045 * free_elements() frees the list of elements on the list head.
6047 static
6048 void
6049 free_elements(
6050 struct element *head)
6052 struct element *e, *e_next;
6054 e = head->next;
6055 while(e != NULL){
6056 e_next = e->next;
6057 free(e);
6058 e = e_next;
6061 #endif /* !defined(OTOOL) */
6064 * check_dylib_module() checks the object file's dylib_module as referenced
6065 * by the dylib_module field in the ofile for correctness.
6067 static
6068 enum check_type
6069 check_dylib_module(
6070 struct ofile *ofile,
6071 struct symtab_command *st,
6072 struct dysymtab_command *dyst,
6073 char *strings,
6074 uint32_t module_index)
6076 #ifdef OTOOL
6077 return(CHECK_GOOD);
6078 #else /* !defined OTOOL */
6079 uint32_t i;
6080 enum byte_sex host_byte_sex;
6081 enum bool swapped;
6082 struct dylib_module m;
6083 struct dylib_module_64 m64;
6084 uint32_t module_name, nextdefsym, iextdefsym, nlocalsym, ilocalsym, nrefsym;
6085 uint32_t irefsym, nextrel, iextrel;
6087 host_byte_sex = get_host_byte_sex();
6088 swapped = (enum bool)(host_byte_sex != ofile->object_byte_sex);
6089 if(ofile->mh != NULL){
6090 m = *ofile->dylib_module;
6091 if(swapped)
6092 swap_dylib_module(&m, 1, host_byte_sex);
6093 module_name = m.module_name;
6094 nextdefsym = m.nextdefsym;
6095 iextdefsym = m.iextdefsym;
6096 nlocalsym = m.nlocalsym;
6097 ilocalsym = m.ilocalsym;
6098 nrefsym = m.nrefsym;
6099 irefsym = m.irefsym;
6100 nextrel = m.nextrel;
6101 iextrel = m.iextrel;
6103 else{
6104 m64 = *ofile->dylib_module64;
6105 if(swapped)
6106 swap_dylib_module_64(&m64, 1, host_byte_sex);
6107 module_name = m64.module_name;
6108 nextdefsym = m64.nextdefsym;
6109 iextdefsym = m64.iextdefsym;
6110 nlocalsym = m64.nlocalsym;
6111 ilocalsym = m64.ilocalsym;
6112 nrefsym = m64.nrefsym;
6113 irefsym = m64.irefsym;
6114 nextrel = m64.nextrel;
6115 iextrel = m64.iextrel;
6118 if(module_name > st->strsize){
6119 Mach_O_error(ofile, "truncated or malformed object (module_name "
6120 "of module table entry %u past the end of the string table)",
6121 module_index);
6122 return(CHECK_BAD);
6124 for(i = module_name; i < st->strsize && strings[i] != '\0'; i++)
6126 if(i >= st->strsize){
6127 Mach_O_error(ofile, "truncated or malformed object (module_name "
6128 "of module table entry %u extends past the end of the string "
6129 "table)", module_index);
6130 return(CHECK_BAD);
6133 if(nextdefsym != 0){
6134 if(iextdefsym > st->nsyms){
6135 Mach_O_error(ofile, "truncated or malformed object (iextdefsym "
6136 "field of module table entry %u past the end of the "
6137 "symbol table", module_index);
6138 return(CHECK_BAD);
6140 if(iextdefsym + nextdefsym > st->nsyms){
6141 Mach_O_error(ofile, "truncated or malformed object (iextdefsym "
6142 "field of module table entry %u plus nextdefsym field "
6143 "extends past the end of the symbol table", module_index);
6144 return(CHECK_BAD);
6147 if(nlocalsym != 0){
6148 if(ilocalsym > st->nsyms){
6149 Mach_O_error(ofile, "truncated or malformed object (ilocalsym "
6150 "field of module table entry %u past the end of the "
6151 "symbol table", module_index);
6152 return(CHECK_BAD);
6154 if(ilocalsym + nlocalsym > st->nsyms){
6155 Mach_O_error(ofile, "truncated or malformed object (ilocalsym "
6156 "field of module table entry %u plus nlocalsym field "
6157 "extends past the end of the symbol table", module_index);
6158 return(CHECK_BAD);
6161 if(nrefsym != 0){
6162 if(irefsym > dyst->nextrefsyms){
6163 Mach_O_error(ofile, "truncated or malformed object (irefsym "
6164 "field of module table entry %u past the end of the "
6165 "reference table", module_index);
6166 return(CHECK_BAD);
6168 if(irefsym + nrefsym > dyst->nextrefsyms){
6169 Mach_O_error(ofile, "truncated or malformed object (irefsym "
6170 "field of module table entry %u plus nrefsym field "
6171 "extends past the end of the reference table",module_index);
6172 return(CHECK_BAD);
6175 if(nextrel != 0){
6176 if(iextrel > dyst->extreloff){
6177 Mach_O_error(ofile, "truncated or malformed object (iextrel "
6178 "field of module table entry %u past the end of the "
6179 "external relocation enrties", module_index);
6180 return(CHECK_BAD);
6182 if(iextrel + nextrel > dyst->extreloff){
6183 Mach_O_error(ofile, "truncated or malformed object (iextrel "
6184 "field of module table entry %u plus nextrel field "
6185 "extends past the end of the external relocation enrties",
6186 module_index);
6187 return(CHECK_BAD);
6190 return(CHECK_GOOD);
6191 #endif /* OTOOL */
6194 __private_extern__
6195 uint32_t
6196 size_ar_name(
6197 const struct ar_hdr *ar_hdr)
6199 int32_t i;
6201 i = sizeof(ar_hdr->ar_name) - 1;
6202 if(ar_hdr->ar_name[i] == ' '){
6204 if(ar_hdr->ar_name[i] != ' ')
6205 break;
6206 i--;
6207 }while(i > 0);
6209 return(i + 1);
6211 #endif /* !defined(RLD) */