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