773
[darwin-xtools.git] / cctools / misc / lipo.c
blobb66b1b3489f2b7062703e11a90751660aa9af4a3
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 * The lipo(1) program. This program creates, thins and operates on fat files.
25 * This program takes the following options:
26 * <input_file>
27 * -output <filename>
28 * -create
29 * -info
30 * -detailed_info
31 * -arch <arch_type> <input_file>
32 * -arch_blank <arch_type>
33 * -thin <arch_type>
34 * -extract <arch_type>
35 * -remove <arch_type>
36 * -replace <arch_type> <file_name>
37 * -segalign <arch_type> <value>
38 * -verify_arch <arch_type> ...
40 #include <stdio.h>
41 #include <string.h>
42 #include <stdlib.h>
43 #include <ar.h>
44 #ifndef AR_EFMT1
45 #define AR_EFMT1 "#1/" /* extended format #1 */
46 #endif
47 #include <limits.h>
48 #include <errno.h>
49 #include <ctype.h>
50 #include <libc.h>
51 #ifndef __OPENSTEP__
52 #include <utime.h>
53 #endif
54 #include <sys/file.h>
55 #include <sys/types.h>
56 #include <sys/stat.h>
57 #include <sys/mman.h>
58 #include <mach/mach.h>
59 #include <mach-o/loader.h>
60 #include <mach-o/fat.h>
61 #include "stuff/arch.h"
62 #include "stuff/errors.h"
63 #include "stuff/allocate.h"
65 /* The maximum section alignment allowed to be specified, as a power of two */
66 #define MAXSECTALIGN 15 /* 2**15 or 0x8000 */
68 /* These #undef's are because of the #define's in <mach.h> */
69 #undef TRUE
70 #undef FALSE
72 /* name of the program for error messages (argv[0]) */
73 char *progname = NULL;
75 /* names and types (if any) of input file specified on the commmand line */
76 struct input_file {
77 char *name;
78 struct arch_flag arch_flag;
79 struct fat_header *fat_header;
80 struct fat_arch *fat_arches;
81 enum bool is_thin;
83 static struct input_file *input_files = NULL;
84 static uint32_t ninput_files = 0;
86 /* Thin files from the input files to operate on */
87 struct thin_file {
88 char *name;
89 char *addr;
90 struct fat_arch fat_arch;
91 enum bool from_fat;
92 enum bool extract;
93 enum bool remove;
94 enum bool replace;
96 static struct thin_file *thin_files = NULL;
97 static uint32_t nthin_files = 0;
99 /* The specified output file */
100 static char *output_file = NULL;
101 static uint32_t output_filemode = 0;
102 #ifndef __OPENSTEP__
103 static struct utimbuf output_timep = { 0 };
104 #else
105 static time_t output_timep[2] = { 0 };
106 #endif
107 static enum bool archives_in_input = FALSE;
109 /* flags set from command line arguments to specify the operation */
110 static enum bool create_flag = FALSE;
111 static enum bool info_flag = FALSE;
112 static enum bool detailed_info_flag = FALSE;
114 static enum bool thin_flag = FALSE;
115 static struct arch_flag thin_arch_flag = { 0 };
117 static enum bool remove_flag = FALSE;
118 static struct arch_flag *remove_arch_flags = NULL;
119 static uint32_t nremove_arch_flags = 0;
121 static enum bool extract_flag = FALSE;
122 static struct arch_flag *extract_arch_flags = NULL;
123 static uint32_t nextract_arch_flags = 0;
124 static enum bool extract_family_flag = FALSE;
126 static enum bool replace_flag = FALSE;
127 struct replace {
128 struct arch_flag arch_flag;
129 struct thin_file thin_file;
131 static struct replace *replaces = NULL;
132 static uint32_t nreplaces = 0;
134 struct segalign {
135 struct arch_flag arch_flag;
136 uint32_t align;
138 static struct segalign *segaligns = NULL;
139 static uint32_t nsegaligns = 0;
141 static enum bool arch_blank_flag = FALSE;
143 static struct fat_header fat_header = { 0 };
145 static enum bool verify_flag = FALSE;
146 static struct arch_flag *verify_archs = NULL;
147 static uint32_t nverify_archs = 0;
149 static void create_fat(
150 void);
151 static void process_input_file(
152 struct input_file *input);
153 static void process_replace_file(
154 struct replace *replace);
155 static void check_archive(
156 char *name,
157 char *addr,
158 uint32_t size,
159 cpu_type_t *cputype,
160 cpu_subtype_t *cpusubtype);
161 static void check_extend_format_1(
162 char *name,
163 struct ar_hdr *ar_hdr,
164 uint32_t size_left,
165 uint32_t *member_name_size);
166 static uint32_t get_align(
167 struct mach_header *mhp,
168 struct load_command *load_commands,
169 uint32_t size,
170 char *name,
171 enum bool swapped);
172 static uint32_t get_align_64(
173 struct mach_header_64 *mhp64,
174 struct load_command *load_commands,
175 uint32_t size,
176 char *name,
177 enum bool swapped);
178 static uint32_t guess_align(
179 uint32_t vmaddr);
180 static void print_arch(
181 struct fat_arch *fat_arch);
182 static void print_cputype(
183 cpu_type_t cputype,
184 cpu_subtype_t cpusubtype);
185 static int size_ar_name(
186 char *ar_name);
187 static struct input_file *new_input(
188 void);
189 static struct thin_file *new_thin(
190 void);
191 static struct arch_flag *new_arch_flag(
192 struct arch_flag **arch_flags,
193 uint32_t *narch_flags);
194 static struct replace *new_replace(
195 void);
196 static struct segalign *new_segalign(
197 void);
198 static int cmp_qsort(
199 const struct thin_file *thin1,
200 const struct thin_file *thin2);
201 static uint32_t round(
202 uint32_t v,
203 uint32_t r);
204 static enum bool ispoweroftwo(
205 uint32_t x);
206 static void check_arch(
207 struct input_file *input,
208 struct thin_file *thin);
209 static void usage(
210 void);
211 static struct thin_file *new_blank_dylib(
212 struct arch_flag *arch);
215 main(
216 int argc,
217 char *argv[],
218 char *envp[])
220 int fd, a;
221 uint32_t i, j, k, value;
222 char *p, *endp;
223 struct input_file *input;
224 struct arch_flag *arch_flag;
225 struct replace *replace;
226 struct segalign *segalign;
227 const struct arch_flag *arch_flags;
228 enum bool found;
229 struct arch_flag blank_arch;
231 input = NULL;
233 * Process the command line arguments.
235 progname = argv[0];
236 for(a = 1; a < argc; a++){
237 if(argv[a][0] == '-'){
238 p = &(argv[a][1]);
239 switch(*p){
240 case 'a':
241 if(strcmp(p, "arch") == 0 || strcmp(p, "a") == 0){
242 if(a + 2 >= argc){
243 error("missing argument(s) to %s option", argv[a]);
244 usage();
246 input = new_input();
247 if(get_arch_from_flag(argv[a+1],
248 &(input->arch_flag)) == 0){
249 error("unknown architecture specification flag: %s "
250 "in specifying input file %s %s %s", argv[a+1],
251 argv[a], argv[a+1], argv[a+2]);
252 arch_usage();
253 usage();
255 input->name = argv[a+2];
256 a += 2;
258 else if(strcmp(p, "arch_blank") == 0){
259 arch_blank_flag = TRUE;
260 if(a + 1 >= argc){
261 error("missing argument(s) to %s option", argv[a]);
262 usage();
264 if(get_arch_from_flag(argv[a+1], &blank_arch) == 0){
265 error("unknown architecture specification flag: %s "
266 "in specifying input file %s %s", argv[a+1],
267 argv[a], argv[a+1]);
268 arch_usage();
269 usage();
271 new_blank_dylib(&blank_arch);
272 a += 1;
274 else
275 goto unknown_flag;
276 break;
277 case 'c':
278 if(strcmp(p, "create") == 0 || strcmp(p, "c") == 0){
279 create_flag = TRUE;
281 else
282 goto unknown_flag;
283 break;
284 case 'd':
285 if(strcmp(p, "detailed_info") == 0 || strcmp(p, "d") == 0){
286 detailed_info_flag = TRUE;
288 else
289 goto unknown_flag;
290 break;
291 case 'e':
292 if(strcmp(p, "extract") == 0 ||
293 strcmp(p, "extract_family") == 0 ||
294 strcmp(p, "e") == 0){
295 extract_flag = TRUE;
296 if(strcmp(p, "extract_family") == 0)
297 extract_family_flag = TRUE;
298 if(a + 1 >= argc){
299 error("missing argument to %s option", argv[a]);
300 usage();
302 arch_flag = new_arch_flag(&extract_arch_flags,
303 &nextract_arch_flags);
304 if(get_arch_from_flag(argv[a+1], arch_flag) == 0){
305 error("unknown architecture specification flag: "
306 "%s in specifying extract operation: %s %s",
307 argv[a+1], argv[a], argv[a+1]);
308 arch_usage();
309 usage();
311 a++;
313 else
314 goto unknown_flag;
315 break;
316 case 'i':
317 if(strcmp(p, "info") == 0 || strcmp(p, "i") == 0){
318 info_flag = TRUE;
320 else
321 goto unknown_flag;
322 break;
323 case 'o':
324 if(strcmp(p, "output") == 0 || strcmp(p, "o") == 0){
325 if(a + 1 >= argc){
326 error("missing argument to %s option", argv[a]);
327 usage();
329 if(output_file != NULL)
330 fatal("more than one %s option specified", argv[a]);
331 output_file = argv[a + 1];
332 a++;
334 else
335 goto unknown_flag;
336 break;
337 case 'r':
338 if(strcmp(p, "remove") == 0 || strcmp(p, "rem") == 0){
339 remove_flag = TRUE;
340 if(a + 1 >= argc){
341 error("missing argument to %s option", argv[a]);
342 usage();
344 arch_flag = new_arch_flag(&remove_arch_flags,
345 &nremove_arch_flags);
346 if(get_arch_from_flag(argv[a+1], arch_flag) == 0){
347 error("unknown architecture specification flag: "
348 "%s in specifying remove operation: %s %s",
349 argv[a+1], argv[a], argv[a+1]);
350 arch_usage();
351 usage();
353 a++;
355 else if(strcmp(p, "replace") == 0 || strcmp(p, "rep") == 0){
356 replace_flag = TRUE;
357 if(a + 2 >= argc){
358 error("missing argument(s) to %s option", argv[a]);
359 usage();
361 replace = new_replace();
362 if(get_arch_from_flag(argv[a+1],
363 &(replace->arch_flag)) == 0){
364 error("unknown architecture specification flag: "
365 "%s in specifying replace operation: %s %s %s",
366 argv[a+1], argv[a], argv[a+1], argv[a+2]);
367 arch_usage();
368 usage();
370 replace->thin_file.name = argv[a+2];
371 a += 2;
373 else
374 goto unknown_flag;
375 break;
376 case 's':
377 if(strcmp(p, "segalign") == 0 || strcmp(p, "s") == 0){
378 if(a + 2 >= argc){
379 error("missing argument(s) to %s option", argv[a]);
380 usage();
382 segalign = new_segalign();
383 if(get_arch_from_flag(argv[a+1],
384 &(segalign->arch_flag)) == 0){
385 error("unknown architecture specification flag: "
386 "%s in specifying segment alignment: %s %s %s",
387 argv[a+1], argv[a], argv[a+1], argv[a+2]);
388 arch_usage();
389 usage();
391 value = strtoul(argv[a+2], &endp, 16);
392 if(*endp != '\0')
393 fatal("argument for -segalign <arch_type> %s not a "
394 "proper hexadecimal number", argv[a+2]);
395 if(!ispoweroftwo(value) || value == 0)
396 fatal("argument to -segalign <arch_type> %x (hex) "
397 "must be a non-zero power of two", value);
398 if(value > (1 << MAXSECTALIGN))
399 fatal("argument to -segalign <arch_type> %x (hex) "
400 "must equal to or less than %x (hex)",
401 value, (unsigned int)(1 << MAXSECTALIGN));
402 segalign->align = 0;
403 while((value & 0x1) != 1){
404 value >>= 1;
405 segalign->align++;
407 a += 2;
409 else
410 goto unknown_flag;
411 break;
412 case 't':
413 if(strcmp(p, "thin") == 0 || strcmp(p, "t") == 0){
414 if(thin_flag == TRUE)
415 fatal("more than one %s option specified", argv[a]);
416 thin_flag = TRUE;
417 if(a + 1 >= argc){
418 error("missing argument to %s option", argv[a]);
419 usage();
421 if(get_arch_from_flag(argv[a+1], &thin_arch_flag) == 0){
422 error("unknown architecture specification flag: "
423 "%s in specifying thin operation: %s %s",
424 argv[a+1], argv[a], argv[a+1]);
425 arch_usage();
426 usage();
428 a++;
430 else
431 goto unknown_flag;
432 break;
433 case 'v':
434 if(strcmp(p, "verify_arch") == 0){
435 verify_flag = TRUE;
436 if(a + 1 >= argc){
437 error("missing argument(s) to %s option", argv[a]);
438 usage();
440 a++;
441 nverify_archs = argc - a;
442 verify_archs = (struct arch_flag *)allocate(
443 sizeof(struct arch_flag) * nverify_archs);
444 for(i = 0; a < argc; a++, i++){
445 if(get_arch_from_flag(argv[a],
446 verify_archs + i) == 0){
447 error("unknown architecture specification "
448 "flag: %s in specifying -verify_arch "
449 "operation", argv[a]);
450 arch_usage();
451 usage();
455 else
456 goto unknown_flag;
457 break;
458 default:
459 unknown_flag:
460 fatal("unknown flag: %s", argv[a]);
463 else{
464 input = new_input();
465 input->name = argv[a];
470 * Check to see the specified arguments are valid.
472 if(info_flag == FALSE && detailed_info_flag == FALSE &&
473 create_flag == FALSE && thin_flag == FALSE &&
474 extract_flag == FALSE && remove_flag == FALSE &&
475 replace_flag == FALSE && verify_flag == FALSE){
476 error("one of -create, -thin <arch_type>, -extract <arch_type>, "
477 "-remove <arch_type>, -replace <arch_type> <file_name>, "
478 "-verify_arch <arch_type> ... , "
479 "-info or -detailed_info must be specified");
480 usage();
482 if((create_flag == TRUE || thin_flag == TRUE || extract_flag == TRUE ||
483 remove_flag == TRUE || replace_flag == TRUE) &&
484 output_file == NULL){
485 error("no output file specified");
486 usage();
488 if(ninput_files == 0){
489 error("no input files specified");
490 usage();
492 if(verify_flag == TRUE && ninput_files != 1){
493 error("only one input file allowed with -verify_arch");
494 usage();
496 if(create_flag + thin_flag + extract_flag + remove_flag + replace_flag +
497 info_flag + detailed_info_flag + verify_flag > 1){
498 error("only one of -create, -thin <arch_type>, -extract <arch_type>"
499 ", -remove <arch_type>, -replace <arch_type> <file_name>, "
500 "-verify_arch <arch_type> ..., "
501 "-info or -detailed_info can be specified");
502 usage();
504 if(arch_blank_flag == TRUE && create_flag == FALSE){
505 error("-arch_blank may only be used with -create");
506 usage();
510 * Determine the types of the input files.
512 for(i = 0; i < ninput_files; i++)
513 process_input_file(input_files + i);
516 * Do the specified operation.
519 if(create_flag){
520 /* check to make sure no two files have the same architectures */
521 for(i = 0; i < nthin_files; i++)
522 for(j = i + 1; j < nthin_files; j++)
523 if(thin_files[i].fat_arch.cputype ==
524 thin_files[j].fat_arch.cputype &&
525 (thin_files[i].fat_arch.cpusubtype & ~CPU_SUBTYPE_MASK)==
526 (thin_files[j].fat_arch.cpusubtype & ~CPU_SUBTYPE_MASK)){
527 arch_flags = get_arch_flags();
528 for(k = 0; arch_flags[k].name != NULL; k++){
529 if(arch_flags[k].cputype ==
530 thin_files[j].fat_arch.cputype &&
531 (arch_flags[k].cpusubtype &
532 ~CPU_SUBTYPE_MASK) ==
533 (thin_files[j].fat_arch.cpusubtype &
534 ~CPU_SUBTYPE_MASK))
535 fatal("%s and %s have the same architectures (%s) "
536 "and can't be in the same fat output file",
537 thin_files[i].name, thin_files[j].name,
538 arch_flags[k].name);
540 fatal("%s and %s have the same architectures (cputype "
541 "(%d) and cpusubtype (%d)) and can't be in the "
542 "same fat output file", thin_files[i].name,
543 thin_files[j].name,thin_files[i].fat_arch.cputype,
544 thin_files[i].fat_arch.cpusubtype &
545 ~CPU_SUBTYPE_MASK);
547 create_fat();
550 if(thin_flag){
551 if(ninput_files != 1)
552 fatal("only one input file can be specified with the -thin "
553 "option");
554 if(input_files[0].fat_header == NULL)
555 fatal("input file (%s) must be a fat file when the -thin "
556 "option is specified", input_files[0].name);
557 for(i = 0; i < nthin_files; i++){
558 if(thin_files[i].fat_arch.cputype == thin_arch_flag.cputype &&
559 (thin_files[i].fat_arch.cpusubtype & ~CPU_SUBTYPE_MASK) ==
560 (thin_arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK)){
561 (void)unlink(output_file);
562 if((fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC,
563 output_filemode)) == -1)
564 system_fatal("can't create output file: %s",
565 output_file);
567 if(write(fd, thin_files[i].addr,thin_files[i].fat_arch.size)
568 != (int)(thin_files[i].fat_arch.size))
569 system_fatal("can't write thin file to output file: %s",
570 output_file);
571 if(close(fd) == -1)
572 system_fatal("can't close output file: %s",output_file);
573 if(utime(output_file,
574 #ifndef __OPENSTEP__
575 &output_timep) == -1)
576 #else
577 output_timep) == -1)
578 #endif
579 system_fatal("can't set the modifiy times for "
580 "output file: %s", output_file);
581 break;
584 if(i == nthin_files)
585 fatal("fat input file (%s) does not contain the specified "
586 "architecture (%s) to thin it to", input->name,
587 thin_arch_flag.name);
590 if(extract_flag){
591 if(ninput_files != 1)
592 fatal("only one input file can be specified with the -extract "
593 "option");
594 if(input_files[0].fat_header == NULL)
595 fatal("input file (%s) must be a fat file when the -extract "
596 "option is specified", input_files[0].name);
597 for(i = 0; i < nextract_arch_flags; i++){
598 for(j = i + 1; j < nextract_arch_flags; j++){
599 if(extract_arch_flags[i].cputype ==
600 extract_arch_flags[j].cputype &&
601 (extract_arch_flags[i].cpusubtype & ~CPU_SUBTYPE_MASK) ==
602 (thin_files[j].fat_arch.cpusubtype & ~CPU_SUBTYPE_MASK))
603 fatal("-extract %s specified multiple times",
604 extract_arch_flags[i].name);
607 /* mark those thin files for extraction */
608 for(i = 0; i < nextract_arch_flags; i++){
609 found = FALSE;
610 for(j = 0; j < nthin_files; j++){
611 if(extract_arch_flags[i].cputype ==
612 thin_files[j].fat_arch.cputype &&
613 ((extract_arch_flags[i].cpusubtype &
614 ~CPU_SUBTYPE_MASK)==
615 (thin_files[j].fat_arch.cpusubtype &
616 ~CPU_SUBTYPE_MASK) ||
617 extract_family_flag == TRUE)){
618 thin_files[j].extract = TRUE;
619 found = TRUE;
622 if(found == FALSE)
623 fatal("-extract %s specified but fat file: %s does not "
624 "contain that architecture",
625 extract_arch_flags[i].name, input_files[0].name);
627 /* remove those thin files not marked for extraction */
628 for(i = 0; i < nthin_files; ){
629 if(thin_files[i].extract == FALSE){
630 for(j = i; j < nthin_files - 1; j++)
631 thin_files[j] = thin_files[j + 1];
632 nthin_files--;
634 else
635 i++;
637 create_fat();
640 if(remove_flag){
641 if(ninput_files != 1)
642 fatal("only one input file can be specified with the -remove "
643 "option");
644 if(input_files[0].fat_header == NULL)
645 fatal("input file (%s) must be a fat file when the -remove "
646 "option is specified", input_files[0].name);
647 for(i = 0; i < nremove_arch_flags; i++){
648 for(j = i + 1; j < nremove_arch_flags; j++){
649 if(remove_arch_flags[i].cputype ==
650 remove_arch_flags[j].cputype &&
651 (remove_arch_flags[i].cpusubtype & ~CPU_SUBTYPE_MASK) ==
652 (remove_arch_flags[j].cpusubtype & ~CPU_SUBTYPE_MASK))
653 fatal("-remove %s specified multiple times",
654 remove_arch_flags[i].name);
657 /* mark those thin files for removal */
658 for(i = 0; i < nremove_arch_flags; i++){
659 for(j = 0; j < nthin_files; j++){
660 if(remove_arch_flags[i].cputype ==
661 thin_files[j].fat_arch.cputype &&
662 (remove_arch_flags[i].cpusubtype &
663 ~CPU_SUBTYPE_MASK) ==
664 (thin_files[j].fat_arch.cpusubtype &
665 ~CPU_SUBTYPE_MASK)){
666 thin_files[j].remove = TRUE;
667 break;
670 if(j == nthin_files)
671 fatal("-remove %s specified but fat file: %s does not "
672 "contain that architecture",
673 remove_arch_flags[i].name, input_files[0].name);
675 /* remove those thin files marked for removal */
676 for(i = 0; i < nthin_files; ){
677 if(thin_files[i].remove == TRUE){
678 for(j = i; j < nthin_files; j++)
679 thin_files[j] = thin_files[j + 1];
680 nthin_files--;
682 else
683 i++;
685 if(nthin_files == 0)
686 fatal("-remove's specified would result in an empty fat file");
687 create_fat();
690 if(replace_flag){
691 if(ninput_files != 1)
692 fatal("only one input file can be specified with the -replace "
693 "option");
694 if(input_files[0].fat_header == NULL)
695 fatal("input file (%s) must be a fat file when the -replace "
696 "option is specified", input_files[0].name);
697 for(i = 0; i < nreplaces; i++){
698 for(j = i + 1; j < nreplaces; j++){
699 if(replaces[i].arch_flag.cputype ==
700 replaces[j].arch_flag.cputype &&
701 (replaces[i].arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK) ==
702 (replaces[j].arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK))
703 fatal("-replace %s <file_name> specified multiple times",
704 replaces[j].arch_flag.name);
707 for(i = 0; i < nreplaces; i++){
708 process_replace_file(replaces + i);
709 for(j = 0; j < nthin_files; j++){
710 if(replaces[i].arch_flag.cputype ==
711 thin_files[j].fat_arch.cputype &&
712 (replaces[i].arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK) ==
713 (thin_files[j].fat_arch.cpusubtype & ~CPU_SUBTYPE_MASK)){
714 thin_files[j] = replaces[i].thin_file;
715 break;
718 if(j == nthin_files)
719 fatal("-replace %s <file_name> specified but fat file: %s "
720 "does not contain that architecture",
721 replaces[i].arch_flag.name, input_files[0].name);
723 create_fat();
726 if(info_flag){
727 for(i = 0; i < ninput_files; i++){
728 if(input_files[i].fat_header != NULL){
729 printf("Architectures in the fat file: %s are: ",
730 input_files[i].name);
731 for(j = 0; j < input_files[i].fat_header->nfat_arch; j++){
732 print_arch(&(input_files[i].fat_arches[j]));
733 printf(" ");
735 printf("\n");
737 else{
738 if(input_files[i].is_thin == FALSE)
739 printf("input file %s is not a fat file\n",
740 input_files[i].name);
743 for(i = 0; i < nthin_files; i++){
744 if(thin_files[i].from_fat == TRUE)
745 continue;
746 printf("Non-fat file: %s is architecture: %s\n",
747 thin_files[i].name,
748 get_arch_name_from_types(thin_files[i].fat_arch.cputype,
749 thin_files[i].fat_arch.cpusubtype & ~CPU_SUBTYPE_MASK));
753 if(detailed_info_flag){
754 for(i = 0; i < ninput_files; i++){
755 if(input_files[i].fat_header != NULL){
756 printf("Fat header in: %s\n", input_files[i].name);
757 printf("fat_magic 0x%x\n",
758 (unsigned int)(input_files[i].fat_header->magic));
759 printf("nfat_arch %u\n",
760 input_files[i].fat_header->nfat_arch);
761 for(j = 0; j < input_files[i].fat_header->nfat_arch; j++){
762 printf("architecture ");
763 print_arch(&(input_files[i].fat_arches[j]));
764 printf("\n");
765 print_cputype(input_files[i].fat_arches[j].cputype,
766 input_files[i].fat_arches[j].cpusubtype &
767 ~CPU_SUBTYPE_MASK);
768 printf(" offset %u\n",
769 input_files[i].fat_arches[j].offset);
770 printf(" size %u\n",
771 input_files[i].fat_arches[j].size);
772 printf(" align 2^%u (%d)\n",
773 input_files[i].fat_arches[j].align,
774 1 << input_files[i].fat_arches[j].align);
777 else{
778 printf("input file %s is not a fat file\n",
779 input_files[i].name);
782 for(i = 0; i < nthin_files; i++){
783 if(thin_files[i].from_fat == TRUE)
784 continue;
785 printf("Non-fat file: %s is architecture: %s\n",
786 thin_files[i].name,
787 get_arch_name_from_types(thin_files[i].fat_arch.cputype,
788 thin_files[i].fat_arch.cpusubtype & ~CPU_SUBTYPE_MASK));
792 if(verify_flag == TRUE){
793 for(i = 0; i < nverify_archs; i++){
794 found = FALSE;
795 for(j = 0; j < nthin_files; j++){
796 if(verify_archs[i].cputype ==
797 thin_files[j].fat_arch.cputype &&
798 (verify_archs[i].cpusubtype & ~CPU_SUBTYPE_MASK) ==
799 (thin_files[j].fat_arch.cpusubtype & ~CPU_SUBTYPE_MASK)){
800 found = TRUE;
801 break;
804 if(found == FALSE)
805 exit(1);
809 return(0);
813 * create_fat() creates a fat output file from the thin files.
815 static
816 void
817 create_fat(void)
819 uint32_t i, j, offset;
820 int fd;
822 /* fold in specified segment alignments */
823 for(i = 0; i < nsegaligns; i++){
824 for(j = i + 1; j < nsegaligns; j++){
825 if(segaligns[i].arch_flag.cputype ==
826 segaligns[j].arch_flag.cputype &&
827 (segaligns[i].arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK) ==
828 (segaligns[j].arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK))
829 fatal("-segalign %s <value> specified multiple times",
830 segaligns[j].arch_flag.name);
833 for(i = 0; i < nsegaligns; i++){
834 for(j = 0; j < nthin_files; j++){
835 if(segaligns[i].arch_flag.cputype ==
836 thin_files[j].fat_arch.cputype &&
837 (segaligns[i].arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK) ==
838 (thin_files[j].fat_arch.cpusubtype & ~CPU_SUBTYPE_MASK)){
840 Since this program has to guess at alignments and guesses high when unsure this
841 check shouldn't be used so the the correct alignment can be specified by the
842 the user.
843 if(thin_files[j].fat_arch.align > segaligns[i].align)
844 fatal("specified segment alignment: %d for "
845 "architecture %s is less than the alignment: %d "
846 "required from the input file",
847 1 << segaligns[i].align,
848 segaligns[i].arch_flag.name,
849 1 << thin_files[j].fat_arch.align);
851 thin_files[j].fat_arch.align = segaligns[i].align;
852 break;
855 if(j == nthin_files)
856 fatal("-segalign %s <value> specified but resulting fat "
857 "file does not contain that architecture",
858 segaligns[i].arch_flag.name);
861 /* sort the files by alignment to save space in the output file */
862 qsort(thin_files, nthin_files, sizeof(struct thin_file),
863 (int (*)(const void *, const void *))cmp_qsort);
865 /* Fill in the fat header and the fat_arch's offsets. */
866 fat_header.magic = FAT_MAGIC;
867 fat_header.nfat_arch = nthin_files;
868 offset = sizeof(struct fat_header) +
869 nthin_files * sizeof(struct fat_arch);
870 for(i = 0; i < nthin_files; i++){
871 offset = round(offset, 1 << thin_files[i].fat_arch.align);
872 thin_files[i].fat_arch.offset = offset;
873 offset += thin_files[i].fat_arch.size;
877 * Create the output file. The unlink() is done to handle the
878 * problem when the outputfile is not writable but the directory
879 * allows the file to be removed and thus created (since the file
880 * may not be there the return code of the unlink() is ignored).
882 (void)unlink(output_file);
883 if((fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC,
884 output_filemode)) == -1)
885 system_fatal("can't create output file: %s", output_file);
888 * If this is an extract_family_flag operation and the is just one
889 * thin file on the list don't create a fat file.
891 if(extract_family_flag != TRUE || nthin_files != 1){
892 #ifdef __LITTLE_ENDIAN__
893 swap_fat_header(&fat_header, BIG_ENDIAN_BYTE_SEX);
894 #endif /* __LITTLE_ENDIAN__ */
895 if(write(fd, &fat_header, sizeof(struct fat_header)) !=
896 sizeof(struct fat_header))
897 system_fatal("can't wtite fat header to output file: %s",
898 output_file);
899 #ifdef __LITTLE_ENDIAN__
900 swap_fat_header(&fat_header, LITTLE_ENDIAN_BYTE_SEX);
901 #endif /* __LITTLE_ENDIAN__ */
902 for(i = 0; i < nthin_files; i++){
903 #ifdef __LITTLE_ENDIAN__
904 swap_fat_arch(&(thin_files[i].fat_arch), 1,BIG_ENDIAN_BYTE_SEX);
905 #endif /* __LITTLE_ENDIAN__ */
906 if(write(fd, &(thin_files[i].fat_arch),
907 sizeof(struct fat_arch)) != sizeof(struct fat_arch))
908 system_fatal("can't write fat arch to output file: %s",
909 output_file);
910 #ifdef __LITTLE_ENDIAN__
911 swap_fat_arch(&(thin_files[i].fat_arch), 1,
912 LITTLE_ENDIAN_BYTE_SEX);
913 #endif /* __LITTLE_ENDIAN__ */
916 for(i = 0; i < nthin_files; i++){
917 if(extract_family_flag == FALSE || nthin_files > 1)
918 if(lseek(fd, thin_files[i].fat_arch.offset, L_SET) == -1)
919 system_fatal("can't lseek in output file: %s", output_file);
920 if(write(fd, thin_files[i].addr, thin_files[i].fat_arch.size)
921 != (int)(thin_files[i].fat_arch.size))
922 system_fatal("can't write to output file: %s", output_file);
924 if(close(fd) == -1)
925 system_fatal("can't close output file: %s", output_file);
929 * process_input_file() checks input file and breaks it down into thin files
930 * for later operations.
932 static
933 void
934 process_input_file(
935 struct input_file *input)
937 int fd;
938 struct stat stat_buf;
939 uint32_t size, i, j;
940 char *addr;
941 struct thin_file *thin;
942 struct mach_header *mhp, mh;
943 struct mach_header_64 *mhp64, mh64;
944 struct load_command *lcp;
945 cpu_type_t cputype;
946 cpu_subtype_t cpusubtype;
947 enum bool swapped;
948 uint64_t big_size;
950 /* Open the input file and map it in */
951 if((fd = open(input->name, O_RDONLY)) == -1)
952 system_fatal("can't open input file: %s", input->name);
953 if(fstat(fd, &stat_buf) == -1)
954 system_fatal("Can't stat input file: %s", input->name);
955 size = stat_buf.st_size;
956 /* pick up set uid, set gid and sticky text bits */
957 output_filemode = stat_buf.st_mode & 07777;
959 * Select the eariliest modifiy time so that if the output file
960 * contains archives with table of contents lipo will not make them
961 * out of date. This logic however could make an out of date table of
962 * contents appear up todate if another file is combined with it that
963 * has a date early enough.
965 #ifndef __OPENSTEP__
966 if(output_timep.modtime == 0 ||
967 output_timep.modtime > stat_buf.st_mtime){
968 output_timep.actime = stat_buf.st_atime;
969 output_timep.modtime = stat_buf.st_mtime;
971 #else
972 if(output_timep[1] == 0 || output_timep[1] > stat_buf.st_mtime){
973 output_timep[0] = stat_buf.st_atime;
974 output_timep[1] = stat_buf.st_mtime;
976 #endif
978 * mmap() can't handle mapping regular files with zero size. So this
979 * is handled separately.
981 if((stat_buf.st_mode & S_IFREG) == S_IFREG && size == 0)
982 addr = NULL;
983 else
984 addr = mmap(0, size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_PRIVATE,
985 fd, 0);
986 if((intptr_t)addr == -1)
987 system_fatal("Can't map input file: %s", input->name);
988 close(fd);
990 /* Try to figure out what kind of file this is */
992 /* see if this file is a fat file */
993 if(size >= sizeof(struct fat_header) &&
994 #ifdef __BIG_ENDIAN__
995 *((uint32_t *)addr) == FAT_MAGIC)
996 #endif /* __BIG_ENDIAN__ */
997 #ifdef __LITTLE_ENDIAN__
998 *((uint32_t *)addr) == SWAP_INT(FAT_MAGIC))
999 #endif /* __LITTLE_ENDIAN__ */
1002 if(input->arch_flag.name != NULL)
1003 fatal("architecture specifed for fat input file: %s "
1004 "(architectures can't be specifed for fat input files)",
1005 input->name);
1007 input->fat_header = (struct fat_header *)addr;
1008 #ifdef __LITTLE_ENDIAN__
1009 swap_fat_header(input->fat_header, LITTLE_ENDIAN_BYTE_SEX);
1010 #endif /* __LITTLE_ENDIAN__ */
1011 big_size = input->fat_header->nfat_arch;
1012 big_size *= sizeof(struct fat_arch);
1013 big_size += sizeof(struct fat_header);
1014 if(big_size > size)
1015 fatal("truncated or malformed fat file (fat_arch structs would "
1016 "extend past the end of the file) %s", input->name);
1017 input->fat_arches = (struct fat_arch *)(addr +
1018 sizeof(struct fat_header));
1019 #ifdef __LITTLE_ENDIAN__
1020 swap_fat_arch(input->fat_arches, input->fat_header->nfat_arch,
1021 LITTLE_ENDIAN_BYTE_SEX);
1022 #endif /* __LITTLE_ENDIAN__ */
1023 for(i = 0; i < input->fat_header->nfat_arch; i++){
1024 if(input->fat_arches[i].offset + input->fat_arches[i].size >
1025 size)
1026 fatal("truncated or malformed fat file (offset plus size "
1027 "of cputype (%d) cpusubtype (%d) extends past the "
1028 "end of the file) %s", input->fat_arches[i].cputype,
1029 input->fat_arches[i].cpusubtype & ~CPU_SUBTYPE_MASK,
1030 input->name);
1031 if(input->fat_arches[i].align > MAXSECTALIGN)
1032 fatal("align (2^%u) too large of fat file %s (cputype (%d)"
1033 " cpusubtype (%d)) (maximum 2^%d)",
1034 input->fat_arches[i].align, input->name,
1035 input->fat_arches[i].cputype,
1036 input->fat_arches[i].cpusubtype & ~CPU_SUBTYPE_MASK,
1037 MAXSECTALIGN);
1038 if(input->fat_arches[i].offset %
1039 (1 << input->fat_arches[i].align) != 0)
1040 fatal("offset %u of fat file %s (cputype (%d) cpusubtype "
1041 "(%d)) not aligned on its alignment (2^%u)",
1042 input->fat_arches[i].offset, input->name,
1043 input->fat_arches[i].cputype,
1044 input->fat_arches[i].cpusubtype & ~CPU_SUBTYPE_MASK,
1045 input->fat_arches[i].align);
1047 for(i = 0; i < input->fat_header->nfat_arch; i++){
1048 for(j = i + 1; j < input->fat_header->nfat_arch; j++){
1049 if(input->fat_arches[i].cputype ==
1050 input->fat_arches[j].cputype &&
1051 (input->fat_arches[i].cpusubtype & ~CPU_SUBTYPE_MASK) ==
1052 (input->fat_arches[j].cpusubtype & ~CPU_SUBTYPE_MASK))
1053 fatal("fat file %s contains two of the same architecture "
1054 "(cputype (%d) cpusubtype (%d))", input->name,
1055 input->fat_arches[i].cputype,
1056 input->fat_arches[i].cpusubtype & ~CPU_SUBTYPE_MASK);
1060 /* create a thin file struct for each arch in the fat file */
1061 for(i = 0; i < input->fat_header->nfat_arch; i++){
1062 thin = new_thin();
1063 thin->name = input->name;
1064 thin->addr = addr + input->fat_arches[i].offset;
1065 thin->fat_arch = input->fat_arches[i];
1066 thin->from_fat = TRUE;
1067 if(input->fat_arches[i].size >= SARMAG &&
1068 strncmp(thin->addr, ARMAG, SARMAG) == 0)
1069 archives_in_input = TRUE;
1072 /* see if this file is Mach-O file for 32-bit architectures */
1073 else if(size >= sizeof(struct mach_header) &&
1074 (*((uint32_t *)addr) == MH_MAGIC ||
1075 *((uint32_t *)addr) == SWAP_INT(MH_MAGIC))){
1077 /* this is a Mach-O file so create a thin file struct for it */
1078 thin = new_thin();
1079 input->is_thin = TRUE;
1080 thin->name = input->name;
1081 thin->addr = addr;
1082 mhp = (struct mach_header *)addr;
1083 lcp = (struct load_command *)((char *)mhp +
1084 sizeof(struct mach_header));
1085 if(mhp->magic == SWAP_INT(MH_MAGIC)){
1086 swapped = TRUE;
1087 mh = *mhp;
1088 swap_mach_header(&mh, get_host_byte_sex());
1089 mhp = &mh;
1091 else
1092 swapped = FALSE;
1093 thin->fat_arch.cputype = mhp->cputype;
1094 thin->fat_arch.cpusubtype = mhp->cpusubtype;
1095 thin->fat_arch.offset = 0;
1096 thin->fat_arch.size = size;
1097 thin->fat_arch.align = get_align(mhp, lcp, size, input->name,
1098 swapped);
1100 /* if the arch type is specified make sure it matches the object */
1101 if(input->arch_flag.name != NULL)
1102 check_arch(input, thin);
1104 /* see if this file is Mach-O file for 64-bit architectures */
1105 else if(size >= sizeof(struct mach_header_64) &&
1106 (*((uint32_t *)addr) == MH_MAGIC_64 ||
1107 *((uint32_t *)addr) == SWAP_INT(MH_MAGIC_64))){
1109 /* this is a Mach-O file so create a thin file struct for it */
1110 thin = new_thin();
1111 input->is_thin = TRUE;
1112 thin->name = input->name;
1113 thin->addr = addr;
1114 mhp64 = (struct mach_header_64 *)addr;
1115 lcp = (struct load_command *)((char *)mhp64 +
1116 sizeof(struct mach_header_64));
1117 if(mhp64->magic == SWAP_INT(MH_MAGIC_64)){
1118 swapped = TRUE;
1119 mh64 = *mhp64;
1120 swap_mach_header_64(&mh64, get_host_byte_sex());
1121 mhp64 = &mh64;
1123 else
1124 swapped = FALSE;
1125 thin->fat_arch.cputype = mhp64->cputype;
1126 thin->fat_arch.cpusubtype = mhp64->cpusubtype;
1127 thin->fat_arch.offset = 0;
1128 thin->fat_arch.size = size;
1129 thin->fat_arch.align = get_align_64(mhp64, lcp, size, input->name,
1130 swapped);
1132 /* if the arch type is specified make sure it matches the object */
1133 if(input->arch_flag.name != NULL)
1134 check_arch(input, thin);
1136 /* see if this file is an archive file */
1137 else if(size >= SARMAG && strncmp(addr, ARMAG, SARMAG) == 0){
1139 check_archive(input->name, addr, size, &cputype, &cpusubtype);
1140 archives_in_input = TRUE;
1142 /* create a thin file struct for this archive */
1143 thin = new_thin();
1144 thin->name = input->name;
1145 thin->addr = addr;
1146 thin->fat_arch.cputype = cputype;
1147 thin->fat_arch.cpusubtype = cpusubtype;
1148 thin->fat_arch.offset = 0;
1149 thin->fat_arch.size = size;
1150 thin->fat_arch.align = 2; /* 2^2, sizeof(uint32_t) */
1152 /* if the arch type is specified make sure it matches the object */
1153 if(input->arch_flag.name != NULL){
1154 if(cputype == 0){
1155 thin->fat_arch.cputype = input->arch_flag.cputype;
1156 thin->fat_arch.cpusubtype = input->arch_flag.cpusubtype;
1158 else
1159 check_arch(input, thin);
1161 else{
1162 if(cputype == 0)
1163 fatal("archive with no architecture specification: %s "
1164 "(can't determine architecture for it)", input->name);
1167 /* this file type is now known to be unknown to this program */
1168 else{
1170 if(input->arch_flag.name != NULL){
1171 /* create a thin file struct for it */
1172 thin = new_thin();
1173 thin->name = input->name;
1174 thin->addr = addr;
1175 thin->fat_arch.cputype = input->arch_flag.cputype;
1176 thin->fat_arch.cpusubtype = input->arch_flag.cpusubtype;
1177 thin->fat_arch.offset = 0;
1178 thin->fat_arch.size = size;
1179 thin->fat_arch.align = 0;
1181 else{
1182 fatal("can't figure out the architecture type of: %s",
1183 input->name);
1189 * process_replace_file() checks the replacement file and maps it in for later
1190 * processing.
1192 static
1193 void
1194 process_replace_file(
1195 struct replace *replace)
1197 int fd;
1198 struct stat stat_buf;
1199 uint32_t size;
1200 char *addr;
1201 struct mach_header *mhp, mh;
1202 struct mach_header_64 *mhp64, mh64;
1203 struct load_command *lcp;
1204 cpu_type_t cputype;
1205 cpu_subtype_t cpusubtype;
1206 enum bool swapped;
1208 /* Open the replacement file and map it in */
1209 if((fd = open(replace->thin_file.name, O_RDONLY)) == -1)
1210 system_fatal("can't open replacement file: %s",
1211 replace->thin_file.name);
1212 if(fstat(fd, &stat_buf) == -1)
1213 system_fatal("Can't stat replacement file: %s",
1214 replace->thin_file.name);
1215 size = stat_buf.st_size;
1217 * mmap() can't handle mapping regular files with zero size. So this
1218 * is handled separately.
1220 if((stat_buf.st_mode & S_IFREG) == S_IFREG && size == 0)
1221 addr = NULL;
1222 else
1223 addr = mmap(0, size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_PRIVATE,
1224 fd, 0);
1225 if((intptr_t)addr == -1)
1226 system_error("Can't map replacement file: %s",
1227 replace->thin_file.name);
1228 close(fd);
1230 /* Try to figure out what kind of file this is */
1232 /* see if this file is a fat file */
1233 if(size >= sizeof(struct fat_header) &&
1234 *((uint32_t *)addr) == FAT_MAGIC){
1236 fatal("replacement file: %s is a fat file (must be a thin file)",
1237 replace->thin_file.name);
1239 /* see if this file is Mach-O file for 32-bit architectures */
1240 else if(size >= sizeof(struct mach_header) &&
1241 (*((uint32_t *)addr) == MH_MAGIC ||
1242 *((uint32_t *)addr) == SWAP_INT(MH_MAGIC))){
1244 /* this is a Mach-O file so fill in the thin file struct for it */
1245 replace->thin_file.addr = addr;
1246 mhp = (struct mach_header *)addr;
1247 lcp = (struct load_command *)((char *)mhp +
1248 sizeof(struct mach_header));
1249 if(mhp->magic == SWAP_INT(MH_MAGIC)){
1250 swapped = TRUE;
1251 mh = *mhp;
1252 swap_mach_header(&mh, get_host_byte_sex());
1253 mhp = &mh;
1255 else
1256 swapped = FALSE;
1257 replace->thin_file.fat_arch.cputype = mhp->cputype;
1258 replace->thin_file.fat_arch.cpusubtype = mhp->cpusubtype;
1259 replace->thin_file.fat_arch.offset = 0;
1260 replace->thin_file.fat_arch.size = size;
1261 replace->thin_file.fat_arch.align =
1262 get_align(mhp, lcp, size, replace->thin_file.name, swapped);
1264 /* see if this file is Mach-O file for 64-bit architectures */
1265 else if(size >= sizeof(struct mach_header_64) &&
1266 (*((uint32_t *)addr) == MH_MAGIC_64 ||
1267 *((uint32_t *)addr) == SWAP_INT(MH_MAGIC_64))){
1269 /* this is a Mach-O file so fill in the thin file struct for it */
1270 replace->thin_file.addr = addr;
1271 mhp64 = (struct mach_header_64 *)addr;
1272 lcp = (struct load_command *)((char *)mhp64 +
1273 sizeof(struct mach_header_64));
1274 if(mhp64->magic == SWAP_INT(MH_MAGIC_64)){
1275 swapped = TRUE;
1276 mh64 = *mhp64;
1277 swap_mach_header_64(&mh64, get_host_byte_sex());
1278 mhp64 = &mh64;
1280 else
1281 swapped = FALSE;
1282 replace->thin_file.fat_arch.cputype = mhp64->cputype;
1283 replace->thin_file.fat_arch.cpusubtype = mhp64->cpusubtype;
1284 replace->thin_file.fat_arch.offset = 0;
1285 replace->thin_file.fat_arch.size = size;
1286 replace->thin_file.fat_arch.align =
1287 get_align_64(mhp64, lcp, size, replace->thin_file.name, swapped);
1289 /* see if this file is an archive file */
1290 else if(size >= SARMAG && strncmp(addr, ARMAG, SARMAG) == 0){
1292 check_archive(replace->thin_file.name, addr, size,
1293 &cputype, &cpusubtype);
1295 /* fill in the thin file struct for this archive */
1296 replace->thin_file.addr = addr;
1297 replace->thin_file.fat_arch.cputype = cputype;
1298 replace->thin_file.fat_arch.cpusubtype = cpusubtype;
1299 replace->thin_file.fat_arch.offset = 0;
1300 replace->thin_file.fat_arch.size = size;
1301 replace->thin_file.fat_arch.align = 2; /* 2^2, sizeof(uint32_t) */
1303 else{
1304 /* fill in the thin file struct for it */
1305 replace->thin_file.addr = addr;
1306 replace->thin_file.fat_arch.cputype = replace->arch_flag.cputype;
1307 replace->thin_file.fat_arch.cpusubtype =
1308 replace->arch_flag.cpusubtype;
1309 replace->thin_file.fat_arch.offset = 0;
1310 replace->thin_file.fat_arch.size = size;
1311 replace->thin_file.fat_arch.align = 0;
1314 if(replace->thin_file.fat_arch.cputype != replace->arch_flag.cputype ||
1315 (replace->thin_file.fat_arch.cpusubtype & ~CPU_SUBTYPE_MASK) !=
1316 (replace->arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK))
1317 fatal("specified architecture: %s for replacement file: %s does "
1318 "not match the file's architecture", replace->arch_flag.name,
1319 replace->thin_file.name);
1323 * check_archive() checks an archive (mapped in at 'addr' of size 'size') to
1324 * make sure it can be included in a fat file (all members are the same
1325 * architecture, no fat files, etc). It returns the cputype and cpusubtype.
1327 static
1328 void
1329 check_archive(
1330 char *name,
1331 char *addr,
1332 uint32_t size,
1333 cpu_type_t *cputype,
1334 cpu_subtype_t *cpusubtype)
1336 uint32_t offset, magic, i, ar_name_size;
1337 struct mach_header mh;
1338 struct mach_header_64 mh64;
1339 struct ar_hdr *ar_hdr;
1340 char *ar_name;
1343 * Check this archive out to make sure that it does not contain
1344 * any fat files and that all object files it contains have the
1345 * same cputype and subsubtype.
1347 *cputype = 0;
1348 *cpusubtype = 0;
1349 offset = SARMAG;
1350 if(offset == size)
1351 fatal("empty archive with no architecture specification: %s "
1352 "(can't determine architecture for it)", name);
1353 if(offset != size && offset + sizeof(struct ar_hdr) > size)
1354 fatal("truncated or malformed archive: %s (archive header of "
1355 "first member extends past the end of the file)", name);
1356 while(size > offset){
1357 ar_hdr = (struct ar_hdr *)(addr + offset);
1358 offset += sizeof(struct ar_hdr);
1359 if(strncmp(ar_hdr->ar_name, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0){
1360 check_extend_format_1(name, ar_hdr, size-offset, &ar_name_size);
1361 i = ar_name_size;
1362 ar_name = ar_hdr->ar_name + sizeof(struct ar_hdr);
1364 else{
1365 i = size_ar_name(ar_hdr->ar_name);
1366 ar_name = ar_hdr->ar_name;
1367 ar_name_size = 0;
1369 if(size + ar_name_size - offset > sizeof(uint32_t)){
1370 memcpy(&magic, addr + offset + ar_name_size,
1371 sizeof(uint32_t));
1372 if(magic == FAT_MAGIC)
1373 fatal("archive member %s(%.*s) is a fat file (not "
1374 "allowed in an archive)", name, (int)i, ar_name);
1375 if((size - ar_name_size) - offset >=
1376 sizeof(struct mach_header) &&
1377 (magic == MH_MAGIC || magic == SWAP_INT(MH_MAGIC))){
1378 memcpy(&mh, addr + offset + ar_name_size,
1379 sizeof(struct mach_header));
1380 if(mh.magic == SWAP_INT(MH_MAGIC))
1381 swap_mach_header(&mh, get_host_byte_sex());
1382 if(*cputype == 0){
1383 *cputype = mh.cputype;
1384 *cpusubtype = mh.cpusubtype;
1386 else if(*cputype != mh.cputype){
1387 fatal("archive member %s(%.*s) cputype (%d) and "
1388 "cpusubtype (%d) does not match previous "
1389 "archive members cputype (%d) and cpusubtype"
1390 " (%d) (all members must match)", name,
1391 (int)i, ar_name, mh.cputype, mh.cpusubtype &
1392 ~CPU_SUBTYPE_MASK, *cputype, (*cpusubtype) &
1393 ~CPU_SUBTYPE_MASK);
1396 else if((size - ar_name_size) - offset >=
1397 sizeof(struct mach_header_64) &&
1398 (magic == MH_MAGIC_64 || magic == SWAP_INT(MH_MAGIC_64))){
1399 memcpy(&mh64, addr + offset + ar_name_size,
1400 sizeof(struct mach_header_64));
1401 if(mh64.magic == SWAP_INT(MH_MAGIC_64))
1402 swap_mach_header_64(&mh64, get_host_byte_sex());
1403 if(*cputype == 0){
1404 *cputype = mh64.cputype;
1405 *cpusubtype = mh64.cpusubtype;
1407 else if(*cputype != mh64.cputype){
1408 fatal("archive member %s(%.*s) cputype (%d) and "
1409 "cpusubtype (%d) does not match previous "
1410 "archive members cputype (%d) and cpusubtype"
1411 " (%d) (all members must match)", name,
1412 (int)i, ar_name, mh64.cputype, mh64.cpusubtype &
1413 ~CPU_SUBTYPE_MASK, *cputype, (*cpusubtype) &
1414 ~CPU_SUBTYPE_MASK);
1418 offset += round(strtoul(ar_hdr->ar_size, NULL, 10),
1419 sizeof(short));
1423 * check_extend_format_1() checks the archive header for extened format1.
1425 static
1426 void
1427 check_extend_format_1(
1428 char *name,
1429 struct ar_hdr *ar_hdr,
1430 uint32_t size_left,
1431 uint32_t *member_name_size)
1433 char *p, *endp, buf[sizeof(ar_hdr->ar_name)+1];
1434 uint32_t ar_name_size;
1436 *member_name_size = 0;
1438 buf[sizeof(ar_hdr->ar_name)] = '\0';
1439 memcpy(buf, ar_hdr->ar_name, sizeof(ar_hdr->ar_name));
1440 p = buf + sizeof(AR_EFMT1) - 1;
1441 if(isdigit(*p) == 0)
1442 fatal("archive: %s malformed (ar_name: %.*s for archive extend "
1443 "format #1 starts with non-digit)", name,
1444 (int)sizeof(ar_hdr->ar_name), ar_hdr->ar_name);
1445 ar_name_size = strtoul(p, &endp, 10);
1446 if(ar_name_size == UINT_MAX && errno == ERANGE)
1447 fatal("archive: %s malformed (size in ar_name: %.*s for archive "
1448 "extend format #1 overflows uint32_t)", name,
1449 (int)sizeof(ar_hdr->ar_name), ar_hdr->ar_name);
1450 while(*endp == ' ' && *endp != '\0')
1451 endp++;
1452 if(*endp != '\0')
1453 fatal("archive: %s malformed (size in ar_name: %.*s for archive "
1454 "extend format #1 contains non-digit and non-space "
1455 "characters)", name, (int)sizeof(ar_hdr->ar_name),
1456 ar_hdr->ar_name);
1457 if(ar_name_size > size_left)
1458 fatal("archive: %s truncated or malformed (archive name "
1459 "of member extends past the end of the file)", name);
1460 *member_name_size = ar_name_size;
1464 * get_align is passed a pointer to a mach header and size of the object. It
1465 * returns the segment alignment the object was created with. It guesses but
1466 * it is conservative. The maximum alignment is that the link editor will allow
1467 * MAXSECTALIGN and the minimum is the conserative alignment for a uint32_t
1468 * which appears in a mach object files (2^2 worst case for all current 32-bit
1469 * machines).
1471 static
1472 uint32_t
1473 get_align(
1474 struct mach_header *mhp,
1475 struct load_command *load_commands,
1476 uint32_t size,
1477 char *name,
1478 enum bool swapped)
1480 uint32_t i, j, cur_align, align;
1481 struct load_command *lcp, l;
1482 struct segment_command *sgp, sg;
1483 struct section *sp, s;
1484 enum byte_sex host_byte_sex;
1487 * Special case ppc, ppc64, i386 and x86_64 architectures and return 12.
1488 * We know that with those architectures that the kernel and mmap only
1489 * need file offsets to be page (4096 byte) aligned.
1491 if(mhp->cputype == CPU_TYPE_POWERPC ||
1492 mhp->cputype == CPU_TYPE_POWERPC64 ||
1493 mhp->cputype == CPU_TYPE_I386 ||
1494 mhp->cputype == CPU_TYPE_X86_64)
1495 return(12);
1497 host_byte_sex = get_host_byte_sex();
1499 /* set worst case the link editor uses first */
1500 cur_align = MAXSECTALIGN;
1501 if(mhp->sizeofcmds + sizeof(struct mach_header) > size)
1502 fatal("truncated or malformed object (load commands would "
1503 "extend past the end of the file) in: %s", name);
1504 lcp = load_commands;
1505 for(i = 0; i < mhp->ncmds; i++){
1506 l = *lcp;
1507 if(swapped)
1508 swap_load_command(&l, host_byte_sex);
1509 if(l.cmdsize % sizeof(uint32_t) != 0)
1510 error("load command %u size not a multiple of "
1511 "sizeof(uint32_t) in: %s", i, name);
1512 if(l.cmdsize <= 0)
1513 fatal("load command %u size is less than or equal to zero "
1514 "in: %s", i, name);
1515 if((char *)lcp + l.cmdsize >
1516 (char *)load_commands + mhp->sizeofcmds)
1517 fatal("load command %u extends past end of all load "
1518 "commands in: %s", i, name);
1519 if(l.cmd == LC_SEGMENT){
1520 sgp = (struct segment_command *)lcp;
1521 sg = *sgp;
1522 if(swapped)
1523 swap_segment_command(&sg, host_byte_sex);
1524 if(mhp->filetype == MH_OBJECT){
1525 /* this is the minimum alignment, then take largest */
1526 align = 2; /* 2^2 sizeof(uint32_t) */
1527 sp = (struct section *)((char *)sgp +
1528 sizeof(struct segment_command));
1529 for(j = 0; j < sg.nsects; j++){
1530 s = *sp;
1531 if(swapped)
1532 swap_section(&s, 1, host_byte_sex);
1533 if(s.align > align)
1534 align = s.align;
1535 sp++;
1537 if(align < cur_align)
1538 cur_align = align;
1540 else{
1541 /* guess the smallest alignment and use that */
1542 align = guess_align(sg.vmaddr);
1543 if(align < cur_align)
1544 cur_align = align;
1547 lcp = (struct load_command *)((char *)lcp + l.cmdsize);
1549 return(cur_align);
1553 * get_align_64 is passed a pointer to a mach_header_64 and size of the object.
1554 * It returns the segment alignment the object was created with. It guesses but
1555 * it is conservative. The maximum alignment is that the link editor will allow
1556 * MAXSECTALIGN and the minimum is the conserative alignment for a long long
1557 * which appears in a mach object files (2^3 worst case for all 64-bit
1558 * machines).
1560 static
1561 uint32_t
1562 get_align_64(
1563 struct mach_header_64 *mhp64,
1564 struct load_command *load_commands,
1565 uint32_t size,
1566 char *name,
1567 enum bool swapped)
1569 uint32_t i, j, cur_align, align;
1570 struct load_command *lcp, l;
1571 struct segment_command_64 *sgp, sg;
1572 struct section_64 *sp, s;
1573 enum byte_sex host_byte_sex;
1576 * Special case ppc, ppc64, i386 and x86_64 architectures and return 12.
1577 * We know that with those architectures that the kernel and mmap only
1578 * need file offsets to be page (4096 byte) aligned.
1580 if(mhp64->cputype == CPU_TYPE_POWERPC ||
1581 mhp64->cputype == CPU_TYPE_POWERPC64 ||
1582 mhp64->cputype == CPU_TYPE_I386 ||
1583 mhp64->cputype == CPU_TYPE_X86_64)
1584 return(12);
1586 host_byte_sex = get_host_byte_sex();
1588 /* set worst case the link editor uses first */
1589 cur_align = MAXSECTALIGN;
1590 if(mhp64->sizeofcmds + sizeof(struct mach_header_64) > size)
1591 fatal("truncated or malformed object (load commands would "
1592 "extend past the end of the file) in: %s", name);
1593 lcp = load_commands;
1594 for(i = 0; i < mhp64->ncmds; i++){
1595 l = *lcp;
1596 if(swapped)
1597 swap_load_command(&l, host_byte_sex);
1598 if(l.cmdsize % sizeof(long long) != 0)
1599 error("load command %u size not a multiple of "
1600 "sizeof(long long) in: %s", i, name);
1601 if(l.cmdsize <= 0)
1602 fatal("load command %u size is less than or equal to zero "
1603 "in: %s", i, name);
1604 if((char *)lcp + l.cmdsize >
1605 (char *)load_commands + mhp64->sizeofcmds)
1606 fatal("load command %u extends past end of all load "
1607 "commands in: %s", i, name);
1608 if(l.cmd == LC_SEGMENT_64){
1609 sgp = (struct segment_command_64 *)lcp;
1610 sg = *sgp;
1611 if(swapped)
1612 swap_segment_command_64(&sg, host_byte_sex);
1613 if(mhp64->filetype == MH_OBJECT){
1614 /* this is the minimum alignment, then take largest */
1615 align = 3; /* 2^3 sizeof(long long) */
1616 sp = (struct section_64 *)((char *)sgp +
1617 sizeof(struct segment_command_64));
1618 for(j = 0; j < sg.nsects; j++){
1619 s = *sp;
1620 if(swapped)
1621 swap_section_64(&s, 1, host_byte_sex);
1622 if(s.align > align)
1623 align = s.align;
1624 sp++;
1626 if(align < cur_align)
1627 cur_align = align;
1629 else{
1630 /* guess the smallest alignment and use that */
1631 align = guess_align(sg.vmaddr);
1632 if(align < cur_align)
1633 cur_align = align;
1636 lcp = (struct load_command *)((char *)lcp + l.cmdsize);
1638 return(cur_align);
1642 * guess_align is passed a vmaddr of a segment and guesses what the segment
1643 * alignment was. It uses the most conservative guess up to the maximum
1644 * alignment that the link editor uses.
1646 static
1647 uint32_t
1648 guess_align(
1649 uint32_t vmaddr)
1651 uint32_t align, segalign;
1653 if(vmaddr == 0)
1654 return(MAXSECTALIGN);
1656 align = 0;
1657 segalign = 1;
1658 while((segalign & vmaddr) == 0){
1659 segalign = segalign << 1;
1660 align++;
1663 if(align < 2)
1664 return(2);
1665 if(align > MAXSECTALIGN)
1666 return(MAXSECTALIGN);
1668 return(align);
1672 * print_arch() helps implement -info and -detailed_info by printing the
1673 * architecture name for the cputype and cpusubtype.
1675 static
1676 void
1677 print_arch(
1678 struct fat_arch *fat_arch)
1680 switch(fat_arch->cputype){
1681 case CPU_TYPE_MC680x0:
1682 switch(fat_arch->cpusubtype & ~CPU_SUBTYPE_MASK){
1683 case CPU_SUBTYPE_MC680x0_ALL:
1684 printf("m68k");
1685 break;
1686 case CPU_SUBTYPE_MC68030_ONLY:
1687 printf("m68030");
1688 break;
1689 case CPU_SUBTYPE_MC68040:
1690 printf("m68040");
1691 break;
1692 default:
1693 goto print_arch_unknown;
1695 break;
1696 case CPU_TYPE_POWERPC:
1697 switch(fat_arch->cpusubtype & ~CPU_SUBTYPE_MASK){
1698 case CPU_SUBTYPE_POWERPC_ALL:
1699 printf("ppc");
1700 break;
1701 case CPU_SUBTYPE_POWERPC_601:
1702 printf("ppc601");
1703 break;
1704 case CPU_SUBTYPE_POWERPC_603:
1705 printf("ppc603");
1706 break;
1707 case CPU_SUBTYPE_POWERPC_603e:
1708 printf("ppc603e");
1709 break;
1710 case CPU_SUBTYPE_POWERPC_603ev:
1711 printf("ppc603ev");
1712 break;
1713 case CPU_SUBTYPE_POWERPC_604:
1714 printf("ppc604");
1715 break;
1716 case CPU_SUBTYPE_POWERPC_604e:
1717 printf("ppc604e");
1718 break;
1719 case CPU_SUBTYPE_POWERPC_750:
1720 printf("ppc750");
1721 break;
1722 case CPU_SUBTYPE_POWERPC_7400:
1723 printf("ppc7400");
1724 break;
1725 case CPU_SUBTYPE_POWERPC_7450:
1726 printf("ppc7450");
1727 break;
1728 case CPU_SUBTYPE_POWERPC_970:
1729 printf("ppc970");
1730 break;
1731 default:
1732 goto print_arch_unknown;
1734 break;
1735 case CPU_TYPE_POWERPC64:
1736 switch(fat_arch->cpusubtype & ~CPU_SUBTYPE_MASK){
1737 case CPU_SUBTYPE_POWERPC_ALL:
1738 printf("ppc64");
1739 break;
1740 case CPU_SUBTYPE_POWERPC_970:
1741 printf("ppc970-64");
1742 break;
1743 default:
1744 goto print_arch_unknown;
1746 break;
1747 case CPU_TYPE_VEO:
1748 switch(fat_arch->cpusubtype & ~CPU_SUBTYPE_MASK){
1749 case CPU_SUBTYPE_VEO_1:
1750 printf("veo1");
1751 break;
1752 case CPU_SUBTYPE_VEO_2:
1753 printf("veo2");
1754 break;
1755 case CPU_SUBTYPE_VEO_3:
1756 printf("veo3");
1757 break;
1758 case CPU_SUBTYPE_VEO_4:
1759 printf("veo4");
1760 break;
1761 default:
1762 goto print_arch_unknown;
1764 break;
1765 case CPU_TYPE_MC88000:
1766 switch(fat_arch->cpusubtype & ~CPU_SUBTYPE_MASK){
1767 case CPU_SUBTYPE_MC88000_ALL:
1768 case CPU_SUBTYPE_MC88110:
1769 printf("m88k");
1770 break;
1771 default:
1772 goto print_arch_unknown;
1774 break;
1775 case CPU_TYPE_I386:
1776 switch(fat_arch->cpusubtype & ~CPU_SUBTYPE_MASK){
1777 case CPU_SUBTYPE_I386_ALL:
1778 /* case CPU_SUBTYPE_386: same as above */
1779 printf("i386");
1780 break;
1781 case CPU_SUBTYPE_486:
1782 printf("i486");
1783 break;
1784 case CPU_SUBTYPE_486SX:
1785 printf("i486SX");
1786 break;
1787 case CPU_SUBTYPE_PENT: /* same as 586 */
1788 printf("pentium");
1789 break;
1790 case CPU_SUBTYPE_PENTPRO:
1791 printf("pentpro");
1792 break;
1793 case CPU_SUBTYPE_PENTII_M3:
1794 printf("pentIIm3");
1795 break;
1796 case CPU_SUBTYPE_PENTII_M5:
1797 printf("pentIIm5");
1798 break;
1799 default:
1800 goto print_arch_unknown;
1802 break;
1803 case CPU_TYPE_X86_64:
1804 switch(fat_arch->cpusubtype & ~CPU_SUBTYPE_MASK){
1805 case CPU_SUBTYPE_X86_64_ALL:
1806 printf("x86_64");
1807 break;
1808 default:
1809 goto print_arch_unknown;
1811 break;
1812 case CPU_TYPE_I860:
1813 switch(fat_arch->cpusubtype & ~CPU_SUBTYPE_MASK){
1814 case CPU_SUBTYPE_I860_ALL:
1815 case CPU_SUBTYPE_I860_860:
1816 printf("i860");
1817 break;
1818 default:
1819 goto print_arch_unknown;
1821 break;
1822 case CPU_TYPE_HPPA:
1823 switch(fat_arch->cpusubtype & ~CPU_SUBTYPE_MASK){
1824 case CPU_SUBTYPE_HPPA_ALL:
1825 case CPU_SUBTYPE_HPPA_7100LC:
1826 printf("hppa");
1827 break;
1828 default:
1829 goto print_arch_unknown;
1831 break;
1832 case CPU_TYPE_SPARC:
1833 switch(fat_arch->cpusubtype & ~CPU_SUBTYPE_MASK){
1834 case CPU_SUBTYPE_SPARC_ALL:
1835 printf("sparc");
1836 break;
1837 default:
1838 goto print_arch_unknown;
1840 break;
1841 case CPU_TYPE_ARM:
1842 switch(fat_arch->cpusubtype){
1843 case CPU_SUBTYPE_ARM_ALL:
1844 printf("arm");
1845 break;
1846 case CPU_SUBTYPE_ARM_V4T:
1847 printf("armv4t");
1848 break;
1849 case CPU_SUBTYPE_ARM_V5TEJ:
1850 printf("armv5");
1851 break;
1852 case CPU_SUBTYPE_ARM_XSCALE:
1853 printf("xscale");
1854 break;
1855 case CPU_SUBTYPE_ARM_V6:
1856 printf("armv6");
1857 break;
1858 case CPU_SUBTYPE_ARM_V7:
1859 printf("armv7");
1860 break;
1861 default:
1862 goto print_arch_unknown;
1864 break;
1865 case CPU_TYPE_ANY:
1866 switch(fat_arch->cpusubtype & ~CPU_SUBTYPE_MASK){
1867 case CPU_SUBTYPE_MULTIPLE:
1868 printf("any");
1869 break;
1870 case CPU_SUBTYPE_LITTLE_ENDIAN:
1871 printf("little");
1872 break;
1873 case CPU_SUBTYPE_BIG_ENDIAN:
1874 printf("big");
1875 break;
1876 default:
1877 goto print_arch_unknown;
1879 break;
1880 print_arch_unknown:
1881 default:
1882 printf("(cputype (%d) cpusubtype (%d))", fat_arch->cputype,
1883 fat_arch->cpusubtype & ~CPU_SUBTYPE_MASK);
1884 break;
1889 * print_cputype() helps implement -detailed_info by printing the cputype and
1890 * cpusubtype (symbolicly for the one's it knows about).
1892 static
1893 void
1894 print_cputype(
1895 cpu_type_t cputype,
1896 cpu_subtype_t cpusubtype)
1898 switch(cputype){
1899 case CPU_TYPE_MC680x0:
1900 switch(cpusubtype & ~CPU_SUBTYPE_MASK){
1901 case CPU_SUBTYPE_MC680x0_ALL:
1902 printf(" cputype CPU_TYPE_MC680x0\n"
1903 " cpusubtype CPU_SUBTYPE_MC680x0_ALL\n");
1904 break;
1905 case CPU_SUBTYPE_MC68030_ONLY:
1906 printf(" cputype CPU_TYPE_MC680x0\n"
1907 " cpusubtype CPU_SUBTYPE_MC68030_ONLY\n");
1908 break;
1909 case CPU_SUBTYPE_MC68040:
1910 printf(" cputype CPU_TYPE_MC680x0\n"
1911 " cpusubtype CPU_SUBTYPE_MC68040\n");
1912 break;
1913 default:
1914 goto print_arch_unknown;
1916 break;
1917 case CPU_TYPE_POWERPC:
1918 switch(cpusubtype & ~CPU_SUBTYPE_MASK){
1919 case CPU_SUBTYPE_POWERPC_ALL:
1920 printf(" cputype CPU_TYPE_POWERPC\n"
1921 " cpusubtype CPU_SUBTYPE_POWERPC_ALL\n");
1922 break;
1923 case CPU_SUBTYPE_POWERPC_601:
1924 printf(" cputype CPU_TYPE_POWERPC\n"
1925 " cpusubtype CPU_SUBTYPE_POWERPC_601\n");
1926 break;
1927 case CPU_SUBTYPE_POWERPC_603:
1928 printf(" cputype CPU_TYPE_POWERPC\n"
1929 " cpusubtype CPU_SUBTYPE_POWERPC_603\n");
1930 break;
1931 case CPU_SUBTYPE_POWERPC_603e:
1932 printf(" cputype CPU_TYPE_POWERPC\n"
1933 " cpusubtype CPU_SUBTYPE_POWERPC_603e\n");
1934 break;
1935 case CPU_SUBTYPE_POWERPC_603ev:
1936 printf(" cputype CPU_TYPE_POWERPC\n"
1937 " cpusubtype CPU_SUBTYPE_POWERPC_603ev\n");
1938 break;
1939 case CPU_SUBTYPE_POWERPC_604:
1940 printf(" cputype CPU_TYPE_POWERPC\n"
1941 " cpusubtype CPU_SUBTYPE_POWERPC_604\n");
1942 break;
1943 case CPU_SUBTYPE_POWERPC_604e:
1944 printf(" cputype CPU_TYPE_POWERPC\n"
1945 " cpusubtype CPU_SUBTYPE_POWERPC_604e\n");
1946 break;
1947 case CPU_SUBTYPE_POWERPC_750:
1948 printf(" cputype CPU_TYPE_POWERPC\n"
1949 " cpusubtype CPU_SUBTYPE_POWERPC_750\n");
1950 break;
1951 case CPU_SUBTYPE_POWERPC_7400:
1952 printf(" cputype CPU_TYPE_POWERPC\n"
1953 " cpusubtype CPU_SUBTYPE_POWERPC_7400\n");
1954 break;
1955 case CPU_SUBTYPE_POWERPC_7450:
1956 printf(" cputype CPU_TYPE_POWERPC\n"
1957 " cpusubtype CPU_SUBTYPE_POWERPC_7450\n");
1958 break;
1959 case CPU_SUBTYPE_POWERPC_970:
1960 printf(" cputype CPU_TYPE_POWERPC\n"
1961 " cpusubtype CPU_SUBTYPE_POWERPC_970\n");
1962 break;
1963 default:
1964 goto print_arch_unknown;
1966 break;
1967 case CPU_TYPE_POWERPC64:
1968 switch(cpusubtype & ~CPU_SUBTYPE_MASK){
1969 case CPU_SUBTYPE_POWERPC_ALL:
1970 printf(" cputype CPU_TYPE_POWERPC64\n"
1971 " cpusubtype CPU_SUBTYPE_POWERPC_ALL\n");
1972 break;
1973 case CPU_SUBTYPE_POWERPC_970:
1974 printf(" cputype CPU_TYPE_POWERPC64\n"
1975 " cpusubtype CPU_SUBTYPE_POWERPC_970\n");
1976 break;
1977 default:
1978 goto print_arch_unknown;
1980 break;
1981 case CPU_TYPE_VEO:
1982 switch(cpusubtype & ~CPU_SUBTYPE_MASK){
1983 case CPU_SUBTYPE_VEO_1:
1984 printf(" cputype CPU_TYPE_VEO\n"
1985 " cpusubtype CPU_SUBTYPE_VEO_1\n");
1986 break;
1987 case CPU_SUBTYPE_VEO_2:
1988 printf(" cputype CPU_TYPE_VEO\n"
1989 " cpusubtype CPU_SUBTYPE_VEO_2\n");
1990 break;
1991 case CPU_SUBTYPE_VEO_3:
1992 printf(" cputype CPU_TYPE_VEO\n"
1993 " cpusubtype CPU_SUBTYPE_VEO_3\n");
1994 break;
1995 case CPU_SUBTYPE_VEO_4:
1996 printf(" cputype CPU_TYPE_VEO\n"
1997 " cpusubtype CPU_SUBTYPE_VEO_4\n");
1998 break;
1999 default:
2000 goto print_arch_unknown;
2002 break;
2003 case CPU_TYPE_MC88000:
2004 switch(cpusubtype & ~CPU_SUBTYPE_MASK){
2005 case CPU_SUBTYPE_MC88000_ALL:
2006 printf(" cputype CPU_TYPE_MC88000\n"
2007 " cpusubtype CPU_SUBTYPE_MC88000_ALL\n");
2008 break;
2009 case CPU_SUBTYPE_MC88110:
2010 printf(" cputype CPU_TYPE_MC88000\n"
2011 " cpusubtype CPU_SUBTYPE_MC88110\n");
2012 break;
2013 default:
2014 goto print_arch_unknown;
2016 break;
2017 case CPU_TYPE_I386:
2018 switch(cpusubtype & ~CPU_SUBTYPE_MASK){
2019 case CPU_SUBTYPE_I386_ALL:
2020 /* case CPU_SUBTYPE_386: same as above */
2021 printf(" cputype CPU_TYPE_I386\n"
2022 " cpusubtype CPU_SUBTYPE_I386_ALL\n");
2023 break;
2024 case CPU_SUBTYPE_486:
2025 printf(" cputype CPU_TYPE_I386\n"
2026 " cpusubtype CPU_SUBTYPE_486\n");
2027 break;
2028 case CPU_SUBTYPE_486SX:
2029 printf(" cputype CPU_TYPE_I386\n"
2030 " cpusubtype CPU_SUBTYPE_486SX\n");
2031 break;
2032 case CPU_SUBTYPE_PENT: /* same as 586 */
2033 printf(" cputype CPU_TYPE_I386\n"
2034 " cpusubtype CPU_SUBTYPE_PENT\n");
2035 break;
2036 case CPU_SUBTYPE_PENTPRO:
2037 printf(" cputype CPU_TYPE_I386\n"
2038 " cpusubtype CPU_SUBTYPE_PENTPRO\n");
2039 break;
2040 case CPU_SUBTYPE_PENTII_M3:
2041 printf(" cputype CPU_TYPE_I386\n"
2042 " cpusubtype CPU_SUBTYPE_PENTII_M3\n");
2043 break;
2044 case CPU_SUBTYPE_PENTII_M5:
2045 printf(" cputype CPU_TYPE_I386\n"
2046 " cpusubtype CPU_SUBTYPE_PENTII_M5\n");
2047 break;
2048 default:
2049 goto print_arch_unknown;
2051 break;
2052 case CPU_TYPE_X86_64:
2053 switch(cpusubtype & ~CPU_SUBTYPE_MASK){
2054 case CPU_SUBTYPE_X86_64_ALL:
2055 printf(" cputype CPU_TYPE_X86_64\n"
2056 " cpusubtype CPU_SUBTYPE_X86_64_ALL\n");
2057 break;
2058 default:
2059 goto print_arch_unknown;
2061 break;
2062 case CPU_TYPE_I860:
2063 switch(cpusubtype & ~CPU_SUBTYPE_MASK){
2064 case CPU_SUBTYPE_I860_ALL:
2065 printf(" cputype CPU_TYPE_I860\n"
2066 " cpusubtype CPU_SUBTYPE_I860_ALL\n");
2067 break;
2068 case CPU_SUBTYPE_I860_860:
2069 printf(" cputype CPU_TYPE_I860\n"
2070 " cpusubtype CPU_SUBTYPE_I860_860\n");
2071 break;
2072 default:
2073 goto print_arch_unknown;
2075 break;
2076 case CPU_TYPE_HPPA:
2077 switch(cpusubtype & ~CPU_SUBTYPE_MASK){
2078 case CPU_SUBTYPE_HPPA_ALL:
2079 printf(" cputype CPU_TYPE_HPPA\n"
2080 " cpusubtype CPU_SUBTYPE_HPPA_ALL\n");
2081 break;
2082 case CPU_SUBTYPE_HPPA_7100LC:
2083 printf(" cputype CPU_TYPE_HPPA\n"
2084 " cpusubtype CPU_SUBTYPE_HPPA_7100LC\n");
2085 break;
2086 default:
2087 goto print_arch_unknown;
2089 break;
2090 case CPU_TYPE_SPARC:
2091 switch(cpusubtype & ~CPU_SUBTYPE_MASK){
2092 case CPU_SUBTYPE_SPARC_ALL:
2093 printf(" cputype CPU_TYPE_SPARC\n"
2094 " cpusubtype CPU_SUBTYPE_SPARC_ALL\n");
2095 break;
2096 default:
2097 goto print_arch_unknown;
2099 break;
2100 case CPU_TYPE_ARM:
2101 switch(cpusubtype){
2102 case CPU_SUBTYPE_ARM_V4T:
2103 printf(" cputype CPU_TYPE_ARM\n"
2104 " cpusubtype CPU_SUBTYPE_ARM_V4T\n");
2105 break;
2106 case CPU_SUBTYPE_ARM_V5TEJ:
2107 printf(" cputype CPU_TYPE_ARM\n"
2108 " cpusubtype CPU_SUBTYPE_ARM_V5TEJ\n");
2109 break;
2110 case CPU_SUBTYPE_ARM_XSCALE:
2111 printf(" cputype CPU_TYPE_ARM\n"
2112 " cpusubtype CPU_SUBTYPE_ARM_XSCALE\n");
2113 break;
2114 case CPU_SUBTYPE_ARM_V6:
2115 printf(" cputype CPU_TYPE_ARM\n"
2116 " cpusubtype CPU_SUBTYPE_ARM_V6\n");
2117 break;
2118 case CPU_SUBTYPE_ARM_ALL:
2119 printf(" cputype CPU_TYPE_ARM\n"
2120 " cpusubtype CPU_SUBTYPE_ARM_ALL\n");
2121 break;
2122 default:
2123 goto print_arch_unknown;
2125 break;
2126 case CPU_TYPE_ANY:
2127 switch(cpusubtype & ~CPU_SUBTYPE_MASK){
2128 case CPU_SUBTYPE_MULTIPLE:
2129 printf(" cputype CPU_TYPE_ANY\n"
2130 " cpusubtype CPU_SUBTYPE_MULTIPLE\n");
2131 break;
2132 case CPU_SUBTYPE_LITTLE_ENDIAN:
2133 printf(" cputype CPU_TYPE_ANY\n"
2134 " cpusubtype CPU_SUBTYPE_LITTLE_ENDIAN\n");
2135 break;
2136 case CPU_SUBTYPE_BIG_ENDIAN:
2137 printf(" cputype CPU_TYPE_ANY\n"
2138 " cpusubtype CPU_SUBTYPE_BIG_ENDIAN\n");
2139 break;
2140 default:
2141 goto print_arch_unknown;
2143 break;
2144 print_arch_unknown:
2145 default:
2146 printf(" cputype (%d)\n"
2147 " cpusubtype cpusubtype (%d)\n", cputype,
2148 cpusubtype & ~CPU_SUBTYPE_MASK);
2149 break;
2154 * size_ar_name is used to return the size of the name of an archive member
2155 * for printing it without blanks (with printf string "%.*s").
2157 static
2159 size_ar_name(
2160 char *ar_name)
2162 uint32_t j;
2163 struct ar_hdr ar_hdr;
2165 for(j = 0; j < sizeof(ar_hdr.ar_name); j++){
2166 if(ar_name[j] == ' ')
2167 break;
2169 return(j);
2173 * Create a new input file struct, clear it and return it.
2175 static
2176 struct input_file *
2177 new_input(void)
2179 struct input_file *input;
2181 input_files = reallocate(input_files,
2182 (ninput_files + 1) * sizeof(struct input_file));
2183 input = input_files + ninput_files;
2184 ninput_files++;
2185 memset(input, '\0', sizeof(struct input_file));
2186 return(input);
2190 * Create a new thin file struct, clear it and return it.
2192 static
2193 struct thin_file *
2194 new_thin(void)
2196 struct thin_file *thin;
2198 thin_files = reallocate(thin_files,
2199 (nthin_files + 1) * sizeof(struct thin_file));
2200 thin = thin_files + nthin_files;
2201 nthin_files++;
2202 memset(thin, '\0', sizeof(struct thin_file));
2203 return(thin);
2207 * Create a new arch_flag struct on the specified list, clear it and return it.
2209 static
2210 struct arch_flag *
2211 new_arch_flag(
2212 struct arch_flag **arch_flags,
2213 uint32_t *narch_flags)
2215 struct arch_flag *arch_flag;
2217 *arch_flags = reallocate(*arch_flags,
2218 (*narch_flags + 1) * sizeof(struct arch_flag));
2219 arch_flag = *arch_flags + *narch_flags;
2220 *narch_flags = *narch_flags + 1;
2221 memset(arch_flag, '\0', sizeof(struct arch_flag));
2222 return(arch_flag);
2226 * Create a new replace struct, clear it and return it.
2228 static
2229 struct replace *
2230 new_replace(void)
2232 struct replace *replace;
2234 replaces = reallocate(replaces,
2235 (nreplaces + 1) * sizeof(struct replace));
2236 replace = replaces + nreplaces;
2237 nreplaces++;
2238 memset(replace, '\0', sizeof(struct replace));
2239 return(replace);
2243 * Create a new segalign struct, clear it and return it.
2245 static
2246 struct segalign *
2247 new_segalign(void)
2249 struct segalign *segalign;
2251 segaligns = reallocate(segaligns,
2252 (nsegaligns + 1) * sizeof(struct segalign));
2253 segalign = segaligns + nsegaligns;
2254 nsegaligns++;
2255 memset(segalign, '\0', sizeof(struct segalign));
2256 return(segalign);
2260 * Function for qsort for comparing thin file's alignment
2262 static
2264 cmp_qsort(
2265 const struct thin_file *thin1,
2266 const struct thin_file *thin2)
2268 return(thin1->fat_arch.align - thin2->fat_arch.align);
2272 * round() rounds v to a multiple of r.
2274 static
2275 uint32_t
2276 round(
2277 uint32_t v,
2278 uint32_t r)
2280 r--;
2281 v += r;
2282 v &= ~(int32_t)r;
2283 return(v);
2287 * ispoweroftwo() returns TRUE or FALSE depending if x is a power of two.
2289 static
2290 enum
2291 bool
2292 ispoweroftwo(
2293 uint32_t x)
2295 if(x == 0)
2296 return(TRUE);
2297 while((x & 0x1) != 0x1){
2298 x >>= 1;
2300 if((x & ~0x1) != 0)
2301 return(FALSE);
2302 else
2303 return(TRUE);
2307 * check_arch is called when an input file is specified with a -arch flag input
2308 * and that the architecture can be determined from the input to check that
2309 * both architectures match.
2311 static
2312 void
2313 check_arch(
2314 struct input_file *input,
2315 struct thin_file *thin)
2317 if(input->arch_flag.cputype != thin->fat_arch.cputype)
2318 fatal("specifed architecture type (%s) for file (%s) does "
2319 "not match its cputype (%d) and cpusubtype (%d) "
2320 "(should be cputype (%d) and cpusubtype (%d))",
2321 input->arch_flag.name, input->name,
2322 thin->fat_arch.cputype, thin->fat_arch.cpusubtype &
2323 ~CPU_SUBTYPE_MASK, input->arch_flag.cputype,
2324 input->arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK);
2328 * Create a blank dylib. This is a stub dylib with no load commands.
2329 * It is a target page size block of bytes of zero except for the mach_header.
2331 static
2332 struct thin_file *
2333 new_blank_dylib(
2334 struct arch_flag *arch)
2336 uint32_t target_page_size, align, onebit;
2337 struct thin_file *file;
2338 enum byte_sex host_byte_sex, target_byte_sex;
2339 struct mach_header *mh;
2340 struct mach_header_64 *mh64;
2342 file = new_thin();
2343 file->name = "blank dylib";
2344 target_page_size = get_segalign_from_flag(arch);
2345 file->addr = allocate(target_page_size);
2346 memset(file->addr, '\0', target_page_size);
2347 file->fat_arch.cputype = arch->cputype;
2348 file->fat_arch.cpusubtype = arch->cpusubtype;
2349 file->fat_arch.offset = 0;
2350 file->fat_arch.size = target_page_size;
2351 onebit = 1;
2352 for(align = 1; (target_page_size & onebit) != onebit; align++)
2353 onebit = onebit << 1;
2354 file->fat_arch.align = align;
2356 host_byte_sex = get_host_byte_sex();
2357 target_byte_sex = get_byte_sex_from_flag(arch);
2359 if((arch->cputype & CPU_ARCH_ABI64) == CPU_ARCH_ABI64){
2360 mh64 = (struct mach_header_64 *)file->addr;
2361 mh64->magic = MH_MAGIC_64;
2362 mh64->cputype = arch->cputype;
2363 mh64->cpusubtype = arch->cpusubtype;
2364 mh64->filetype = MH_DYLIB_STUB;
2365 if(target_byte_sex != host_byte_sex)
2366 swap_mach_header_64(mh64, target_byte_sex);
2368 else{
2369 mh = (struct mach_header *)file->addr;
2370 mh->magic = MH_MAGIC;
2371 mh->cputype = arch->cputype;
2372 mh->cpusubtype = arch->cpusubtype;
2373 mh->filetype = MH_DYLIB_STUB;
2374 if(target_byte_sex != host_byte_sex)
2375 swap_mach_header(mh, target_byte_sex);
2377 return(file);
2381 * Print the current usage line and exit (by calling fatal).
2383 static
2384 void
2385 usage(void)
2387 fatal("Usage: %s [input_file] ... [-arch <arch_type> input_file] ... "
2388 "[-info] [-detailed_info] [-output output_file] [-create] "
2389 "[-arch_blank <arch_type>] [-thin <arch_type>] "
2390 "[-remove <arch_type>] ... [-extract <arch_type>] ... "
2391 "[-extract_family <arch_type>] ... "
2392 "[-verify_arch <arch_type> ...] "
2393 "[-replace <arch_type> <file_name>] ...", progname);