cctools (lib), libtool, lipo, nm, otool - Add build support for LTO
[darwin-xtools.git] / cctools / otool / main.c
blob9e27874821a05a698644e4ac2562402312dd858d
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 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <limits.h>
35 #include <ar.h>
36 #include <mach-o/ranlib.h>
37 #include <libc.h>
38 #include "stuff/bool.h"
39 #include "stuff/ofile.h"
40 #include "stuff/errors.h"
41 #include "stuff/allocate.h"
42 #include "stuff/symbol.h"
43 #include "stuff/symbol.h"
44 #include "stuff/llvm.h"
45 #include "stuff/guess_short_name.h"
46 #include "stuff/execute.h"
47 #include "otool.h"
48 #include "dyld_bind_info.h"
49 #include "ofile_print.h"
50 #include "m68k_disasm.h"
51 #include "i860_disasm.h"
52 #include "i386_disasm.h"
53 #include "m88k_disasm.h"
54 #include "ppc_disasm.h"
55 #include "hppa_disasm.h"
56 #include "sparc_disasm.h"
57 #include "arm_disasm.h"
58 #include "arm64_disasm.h"
59 #include "llvm-c/Disassembler.h"
61 /* Name of this program for error messages (argv[0]) */
62 char *progname = NULL;
65 * The flags to indicate the actions to perform.
67 enum bool fflag = FALSE; /* print the fat headers */
68 enum bool aflag = FALSE; /* print the archive header */
69 enum bool hflag = FALSE; /* print the exec or mach header */
70 enum bool lflag = FALSE; /* print the load commands */
71 enum bool Lflag = FALSE; /* print the shared library names */
72 enum bool Dflag = FALSE; /* print the shared library id name */
73 enum bool tflag = FALSE; /* print the text */
74 enum bool Uflag = FALSE; /* print the text symbol by symbol,
75 for llvm-objdump testing must be used with -t */
76 enum bool no_show_raw_insn = FALSE; /* no raw inst, for llvm-objdump testing
77 with 32-bit arm */
78 #ifdef LLVM_OTOOL
79 enum bool show_objdump_command = FALSE; /* print the objdump command */
80 #endif /* LLVM_OTOOL */
81 enum bool dflag = FALSE; /* print the data */
82 enum bool oflag = FALSE; /* print the objctive-C info */
83 enum bool Oflag = FALSE; /* print the objctive-C selector strings only */
84 enum bool rflag = FALSE; /* print the relocation entries */
85 enum bool Tflag = FALSE; /* print the dylib table of contents */
86 enum bool Mflag = FALSE; /* print the dylib module table */
87 enum bool Rflag = FALSE; /* print the dylib reference table */
88 enum bool Iflag = FALSE; /* print the indirect symbol table entries */
89 enum bool Hflag = FALSE; /* print the two-level hints table */
90 enum bool Cflag = FALSE; /* print the linker optimization hints */
91 enum bool Gflag = FALSE; /* print the data in code table */
92 enum bool gflag = FALSE; /* group the disassembly */
93 enum bool eflag = FALSE; /* print enhanced disassembly */
94 enum bool Sflag = FALSE; /* print the contents of the __.SYMDEF file */
95 enum bool vflag = FALSE; /* print verbosely (symbolically) when possible */
96 enum bool Vflag = FALSE; /* print dissassembled operands verbosely */
97 enum bool cflag = FALSE; /* print the argument and environ strings of a core */
98 enum bool iflag = FALSE; /* print the shared library initialization table */
99 enum bool Wflag = FALSE; /* print the mod time of an archive as a number */
100 enum bool Xflag = FALSE; /* don't print leading address in disassembly */
101 enum bool Zflag = FALSE; /* don't use simplified ppc mnemonics in disassembly */
102 enum bool Bflag = FALSE; /* force Thumb disassembly (ARM objects only) */
103 enum bool Qflag = FALSE; /* use otool's disassembler */
104 enum bool qflag = FALSE; /* use 'C' Public llvm-mc disassembler */
105 enum bool jflag = FALSE; /* print opcode bytes */
106 enum bool Pflag = FALSE; /* print (__TEXT,__info_plist) section as strings */
107 char *pflag = NULL; /* procedure name to start disassembling from */
108 char *segname = NULL; /* name of the section to print the contents of */
109 char *sectname = NULL;
110 enum bool llvm_mc = FALSE; /* disassemble as llvm-mc will assemble */
111 char *mcpu = ""; /* the arg of the -mcpu=arg flag */
112 /* Print function offsets when disassembling when TRUE. */
113 enum bool function_offsets = FALSE;
114 enum bool print_bind_info = FALSE; /* print dyld bind information */
116 /* this is set when any of the flags that process object files is set */
117 enum bool object_processing = FALSE;
119 static void usage(
120 void);
122 #ifndef LLVM_OTOOL
124 static void processor(
125 struct ofile *ofile,
126 char *arch_name,
127 void *cookie);
129 static void get_symbol_table_info(
130 struct load_command *load_commands,
131 uint32_t ncmds,
132 uint32_t sizeofcmds,
133 cpu_type_t cputype,
134 enum byte_sex load_commands_byte_sex,
135 char *object_addr,
136 uint32_t object_size,
137 struct nlist **symbols,
138 struct nlist_64 **symbols64,
139 uint32_t *nsymbols,
140 char **strings,
141 uint32_t *strings_size);
143 static void get_toc_info(
144 struct load_command *load_commands,
145 uint32_t ncmds,
146 uint32_t sizeofcmds,
147 enum byte_sex load_commands_byte_sex,
148 char *object_addr,
149 uint32_t object_size,
150 struct dylib_table_of_contents **tocs,
151 uint32_t *ntocs);
153 static void get_module_table_info(
154 struct load_command *load_commands,
155 uint32_t ncmds,
156 uint32_t sizeofcmds,
157 cpu_type_t cputype,
158 enum byte_sex load_commands_byte_sex,
159 char *object_addr,
160 uint32_t object_size,
161 struct dylib_module **mods,
162 struct dylib_module_64 **mods64,
163 uint32_t *nmods);
165 static void get_ref_info(
166 struct load_command *load_commands,
167 uint32_t ncmds,
168 uint32_t sizeofcmds,
169 enum byte_sex load_commands_byte_sex,
170 char *object_addr,
171 uint32_t object_size,
172 struct dylib_reference **refs,
173 uint32_t *nrefs);
175 static void get_indirect_symbol_table_info(
176 struct load_command *load_commands,
177 uint32_t ncmds,
178 uint32_t sizeofcmds,
179 enum byte_sex load_commands_byte_sex,
180 char *object_addr,
181 uint32_t object_size,
182 uint32_t **indirect_symbols,
183 uint32_t *nindirect_symbols);
185 static enum bool get_dyst(
186 struct load_command *load_commands,
187 uint32_t ncmds,
188 uint32_t sizeofcmds,
189 enum byte_sex load_commands_byte_sex,
190 struct dysymtab_command *dyst);
192 static void get_hints_table_info(
193 struct load_command *load_commands,
194 uint32_t ncmds,
195 uint32_t sizeofcmds,
196 enum byte_sex load_commands_byte_sex,
197 char *object_addr,
198 uint32_t object_size,
199 struct twolevel_hint **hints,
200 uint32_t *nhints);
202 static enum bool get_hints_cmd(
203 struct load_command *load_commands,
204 uint32_t ncmds,
205 uint32_t sizeofcmds,
206 enum byte_sex load_commands_byte_sex,
207 struct twolevel_hints_command *hints_cmd);
209 static void get_link_opt_hints(
210 struct load_command *load_commands,
211 uint32_t ncmds,
212 uint32_t sizeofcmds,
213 enum byte_sex load_commands_byte_sex,
214 char *object_addr,
215 uint32_t object_size,
216 char **loh,
217 uint32_t *nloh);
219 static enum bool get_link_opt_hint_cmd(
220 struct load_command *load_commands,
221 uint32_t ncmds,
222 uint32_t sizeofcmds,
223 enum byte_sex load_commands_byte_sex,
224 struct linkedit_data_command *loh_cmd);
226 static void get_data_in_code_info(
227 struct load_command *load_commands,
228 uint32_t ncmds,
229 uint32_t sizeofcmds,
230 enum byte_sex load_commands_byte_sex,
231 char *object_addr,
232 uint32_t object_size,
233 struct data_in_code_entry **dices,
234 uint32_t *ndices);
236 static enum bool get_dices_cmd(
237 struct load_command *load_commands,
238 uint32_t ncmds,
239 uint32_t sizeofcmds,
240 enum byte_sex load_commands_byte_sex,
241 struct linkedit_data_command *dices_cmd);
243 static int sym_compare(
244 struct symbol *sym1,
245 struct symbol *sym2);
247 static int rel_compare(
248 struct relocation_info *rel1,
249 struct relocation_info *rel2);
251 static void get_linked_reloc_info(
252 struct load_command *load_commands,
253 uint32_t ncmds,
254 uint32_t sizeofcmds,
255 enum byte_sex load_commands_byte_sex,
256 char *object_addr,
257 uint32_t object_size,
258 struct relocation_info **ext_relocs,
259 uint32_t *next_relocs,
260 struct relocation_info **loc_relocs,
261 uint32_t *nloc_relocs);
263 static void setup_dyld_bind_info(
264 struct load_command *load_commands, /* input */
265 uint32_t ncmds,
266 uint32_t sizeofcmds,
267 enum byte_sex load_commands_byte_sex,
268 char *object_addr,
269 uint32_t object_size,
270 struct dyld_bind_info **dbi, /* output */
271 uint64_t *ndbi);
273 static void print_text_by_symbols(
274 cpu_type_t cputype,
275 enum byte_sex object_byte_sex,
276 char *sect,
277 uint32_t size,
278 uint64_t addr,
279 uint32_t sect_flags,
280 struct symbol *sorted_symbols,
281 uint32_t nsorted_symbols,
282 struct nlist *symbols,
283 struct nlist_64 *symbols64,
284 uint32_t nsymbols,
285 char *strings,
286 uint32_t strings_size,
287 struct relocation_info *relocs,
288 uint32_t nrelocs,
289 struct relocation_info *ext_relocs,
290 uint32_t next_relocs,
291 struct relocation_info *loc_relocs,
292 uint32_t nloc_relocs,
293 struct dyld_bind_info *dbi,
294 uint64_t ndbi,
295 uint32_t *indirect_symbols,
296 uint32_t nindirect_symbols,
297 struct load_command *load_commands,
298 uint32_t ncmds,
299 uint32_t sizeofcmds,
300 enum bool disassemble,
301 enum bool verbose,
302 cpu_subtype_t cpusubtype,
303 char *object_addr,
304 uint32_t object_size,
305 struct data_in_code_entry *dices,
306 uint32_t ndices,
307 uint64_t seg_addr);
309 static void print_text(
310 cpu_type_t cputype,
311 enum byte_sex object_byte_sex,
312 char *sect,
313 uint32_t size,
314 uint64_t addr,
315 uint32_t sect_flags,
316 struct symbol *sorted_symbols,
317 uint32_t nsorted_symbols,
318 struct nlist *symbols,
319 struct nlist_64 *symbols64,
320 uint32_t nsymbols,
321 char *strings,
322 uint32_t strings_size,
323 struct relocation_info *relocs,
324 uint32_t nrelocs,
325 struct relocation_info *ext_relocs,
326 uint32_t next_relocs,
327 struct relocation_info *loc_relocs,
328 uint32_t nloc_relocs,
329 struct dyld_bind_info *dbi,
330 uint64_t ndbi,
331 uint32_t *indirect_symbols,
332 uint32_t nindirect_symbols,
333 struct load_command *load_commands,
334 uint32_t ncmds,
335 uint32_t sizeofcmds,
336 enum bool disassemble,
337 enum bool verbose,
338 cpu_subtype_t cpusubtype,
339 char *object_addr,
340 uint32_t object_size,
341 struct data_in_code_entry *dices,
342 uint32_t ndices,
343 uint64_t seg_addr);
345 static void print_argstrings(
346 uint32_t magic,
347 struct load_command *load_commands,
348 uint32_t ncmds,
349 uint32_t sizeofcmds,
350 cpu_type_t cputype,
351 cpu_subtype_t cpusubtype,
352 enum byte_sex load_commands_byte_sex,
353 char *object_addr,
354 uint32_t object_size);
356 #else /* defined(LLVM_OTOOL) */
358 static void llvm_otool(
359 char **files,
360 uint32_t nfiles,
361 struct arch_flag *arch_flags,
362 uint32_t narch_flags,
363 enum bool all_archs,
364 enum bool version);
366 #endif /* LLVM_OTOOL */
368 /* apple_version is created by the libstuff/Makefile */
369 extern char apple_version[];
370 char *version = apple_version;
371 /* likewise lto_suport */
372 extern char lto_support[];
375 main(
376 int argc,
377 char **argv,
378 char **envp)
380 int i;
381 uint32_t j, nfiles;
382 struct arch_flag *arch_flags;
383 uint32_t narch_flags;
384 enum bool all_archs, use_member_syntax, version;
385 char **files;
386 #ifndef LLVM_OTOOL
387 const char *disssembler_version;
388 #endif /* !defined(LLVM_OTOOL) */
390 progname = argv[0];
391 arch_flags = NULL;
392 narch_flags = 0;
393 all_archs = FALSE;
394 use_member_syntax = TRUE;
395 llvm_mc = FALSE;
396 version = FALSE;
397 errors = 0;
399 if(argc <= 1)
400 usage();
403 * Parse the arguments.
405 nfiles = 0;
406 files = allocate(sizeof(char *) * argc);
407 for(i = 1; i < argc; i++){
408 if(argv[i][0] == '-' && argv[i][1] == '\0'){
409 for(i += 1 ; i < argc; i++)
410 files[nfiles++] = argv[i];
411 break;
413 if(argv[i][0] != '-'){
414 files[nfiles++] = argv[i];
415 continue;
417 if(strcmp(argv[i], "--version") == 0){
418 fprintf(stderr,
419 #ifndef LLVM_OTOOL
420 "otool(1):"
421 #else /* defined(LLVM_OTOOL) */
422 "llvm-otool(1):"
423 #endif /* LLVM_OTOOL */
424 " Apple Inc. version %s\n", apple_version);
425 #ifndef LLVM_OTOOL
426 disssembler_version = llvm_disasm_version_string();
427 if(disssembler_version != NULL)
428 fprintf(stderr, "disassmbler: %s\n", disssembler_version);
429 #endif /* !defined(LLVM_OTOOL) */
430 version = TRUE;
431 continue;
433 if(strcmp(argv[i], "-arch") == 0){
434 if(i + 1 == argc){
435 error("missing argument(s) to %s option", argv[i]);
436 usage();
438 if(strcmp("all", argv[i+1]) == 0){
439 all_archs = TRUE;
441 else{
442 arch_flags = reallocate(arch_flags,
443 (narch_flags + 1) * sizeof(struct arch_flag));
444 if(get_arch_from_flag(argv[i+1],
445 arch_flags + narch_flags) == 0){
446 error("unknown architecture specification flag: "
447 "%s %s", argv[i], argv[i+1]);
448 arch_usage();
449 usage();
451 narch_flags++;
453 i++;
454 continue;
456 if(strcmp(argv[i], "-llvm-mc") == 0){
457 llvm_mc = TRUE;
458 continue;
460 if(strcmp(argv[i], "-function_offsets") == 0){
461 function_offsets = TRUE;
462 continue;
464 if(strcmp(argv[i], "-bind_info") == 0){
465 print_bind_info = TRUE;
466 object_processing = TRUE;
467 continue;
469 if(strncmp(argv[i], "-mcpu=", sizeof("-mcpu=")-1) == 0){
470 mcpu = argv[i] + sizeof("-mcpu=")-1;
471 if(*mcpu == '\0'){
472 error("missing argument to -mcpu=");
473 usage();
475 continue;
477 if(strcmp(argv[i], "-no-show-raw-insn") == 0){
478 no_show_raw_insn = TRUE;
479 continue;
481 if(argv[i][1] == 'p'){
482 if(argc <= i + 1){
483 error("-p requires an argument (a text symbol name)");
484 usage();
486 if(pflag)
487 error("only one -p flag can be specified");
488 pflag = argv[i + 1];
489 i++;
490 continue;
492 #ifdef LLVM_OTOOL
493 if(strcmp(argv[i], "-show-objdump-command") == 0){
494 show_objdump_command = TRUE;
495 continue;
497 #endif /* LLVM_OTOOL */
498 if(argv[i][1] == 's'){
499 if(argc <= i + 2){
500 error("-s requires two arguments (a segment name and a "
501 "section name)");
502 usage();
504 if(sectname != NULL){
505 error("only one -s flag can be specified");
506 usage();
508 segname = argv[i + 1];
509 sectname = argv[i + 2];
510 i += 2;
511 object_processing = TRUE;
512 continue;
514 for(j = 1; argv[i][j] != '\0'; j++){
515 switch(argv[i][j]){
516 case 'V':
517 Vflag = TRUE;
518 case 'v':
519 vflag = TRUE;
520 break;
521 case 'f':
522 fflag = TRUE;
523 break;
524 case 'a':
525 aflag = TRUE;
526 break;
527 case 'g':
528 gflag = TRUE;
529 break;
530 case 'e':
531 eflag = TRUE;
532 break;
533 case 'h':
534 hflag = TRUE;
535 object_processing = TRUE;
536 break;
537 case 'l':
538 lflag = TRUE;
539 object_processing = TRUE;
540 break;
541 case 'L':
542 Lflag = TRUE;
543 object_processing = TRUE;
544 break;
545 case 'D':
546 Dflag = TRUE;
547 object_processing = TRUE;
548 break;
549 case 't':
550 tflag = TRUE;
551 object_processing = TRUE;
552 break;
553 case 'U':
554 Uflag = TRUE;
555 break;
556 case 'd':
557 dflag = TRUE;
558 object_processing = TRUE;
559 break;
560 case 'o':
561 oflag = TRUE;
562 object_processing = TRUE;
563 break;
564 case 'O':
565 Oflag = TRUE;
566 object_processing = TRUE;
567 break;
568 case 'r':
569 rflag = TRUE;
570 object_processing = TRUE;
571 break;
572 case 'T':
573 Tflag = TRUE;
574 object_processing = TRUE;
575 break;
576 case 'M':
577 Mflag = TRUE;
578 object_processing = TRUE;
579 break;
580 case 'R':
581 Rflag = TRUE;
582 object_processing = TRUE;
583 break;
584 case 'I':
585 Iflag = TRUE;
586 object_processing = TRUE;
587 break;
588 case 'H':
589 Hflag = TRUE;
590 object_processing = TRUE;
591 break;
592 case 'C':
593 Cflag = TRUE;
594 object_processing = TRUE;
595 break;
596 case 'G':
597 Gflag = TRUE;
598 object_processing = TRUE;
599 break;
600 case 'S':
601 Sflag = TRUE;
602 break;
603 case 'c':
604 cflag = TRUE;
605 object_processing = TRUE;
606 break;
607 case 'i':
608 iflag = TRUE;
609 object_processing = TRUE;
610 break;
611 case 'W':
612 Wflag = TRUE;
613 break;
614 case 'X':
615 Xflag = TRUE;
616 break;
617 case 'Z':
618 Zflag = TRUE;
619 break;
620 case 'm':
621 use_member_syntax = FALSE;
622 break;
623 case 'B':
624 Bflag = TRUE;
625 break;
626 case 'Q':
627 Qflag = TRUE;
628 break;
629 case 'q':
630 qflag = TRUE;
631 break;
632 case 'j':
633 jflag = TRUE;
634 break;
635 case 'P':
636 Pflag = TRUE;
637 object_processing = TRUE;
638 break;
639 default:
640 error("unknown char `%c' in flag %s\n", argv[i][j],argv[i]);
641 usage();
647 * Check for correctness of arguments.
649 if(!fflag && !aflag && !hflag && !lflag && !Lflag && !tflag && !dflag &&
650 !oflag && !Oflag && !rflag && !Tflag && !Mflag && !Rflag && !Iflag &&
651 !Cflag && !print_bind_info && !version && !Pflag &&
652 !Hflag && !Gflag && !Sflag && !cflag && !iflag && !Dflag &&!segname){
653 error("one of -fahlLtdoOrTMRIHCGScisP or --version must be "
654 "specified");
655 usage();
657 if(qflag && Qflag){
658 error("can't specify both -q and -Q");
659 usage();
662 * The default, without the -Q flag, is to use the llvm dissembler
663 * instead of otool's internal disassemblers.
665 if(!Qflag)
666 qflag = TRUE;
667 if(nfiles == 0 && version == FALSE){
668 error("at least one file must be specified");
669 usage();
671 if(segname != NULL && sectname != NULL){
672 /* treat "-s __TEXT __text" the same as -t */
673 if(strcmp(segname, SEG_TEXT) == 0 &&
674 strcmp(sectname, SECT_TEXT) == 0){
675 tflag = TRUE;
676 segname = NULL;
677 sectname = NULL;
679 /* treat "-s __TEXT __fvmlib0" the same as -i */
680 else if(strcmp(segname, SEG_TEXT) == 0 &&
681 strcmp(sectname, SECT_FVMLIB_INIT0) == 0){
682 iflag = TRUE;
683 segname = NULL;
684 sectname = NULL;
686 /* treat "-v -s __TEXT __info_plist" the same as -P */
687 else if(vflag == TRUE && strcmp(segname, SEG_TEXT) == 0 &&
688 strcmp(sectname, "__info_plist") == 0){
689 Pflag = TRUE;
690 segname = NULL;
691 sectname = NULL;
695 #ifndef LLVM_OTOOL
696 for(j = 0; j < nfiles; j++){
697 ofile_process(files[j], arch_flags, narch_flags, all_archs, TRUE,
698 TRUE, use_member_syntax, processor, NULL);
700 #else /* defined(LLVM_OTOOL) */
701 llvm_otool(files, nfiles, arch_flags, narch_flags, all_archs, version);
702 #endif /* LLVM_OTOOL */
704 if(errors)
705 return(EXIT_FAILURE);
706 else
707 return(EXIT_SUCCESS);
711 * Print the current usage message.
713 static
714 void
715 usage(
716 void)
718 fprintf(stderr,
719 "Usage: %s [-arch arch_type] [-fahlLDtdorSTMRIHGvVcXmqQjCP] "
720 "[-mcpu=arg] [--version] <object file> ...\n", progname);
722 fprintf(stderr, "\t-f print the fat headers\n");
723 fprintf(stderr, "\t-a print the archive header\n");
724 fprintf(stderr, "\t-h print the mach header\n");
725 fprintf(stderr, "\t-l print the load commands\n");
726 fprintf(stderr, "\t-L print shared libraries used\n");
727 fprintf(stderr, "\t-D print shared library id name\n");
728 fprintf(stderr, "\t-t print the text section (disassemble with -v)\n");
729 fprintf(stderr, "\t-p <routine name> start dissassemble from routine "
730 "name\n");
731 fprintf(stderr, "\t-s <segname> <sectname> print contents of "
732 "section\n");
733 fprintf(stderr, "\t-d print the data section\n");
734 fprintf(stderr, "\t-o print the Objective-C segment\n");
735 fprintf(stderr, "\t-r print the relocation entries\n");
736 fprintf(stderr, "\t-S print the table of contents of a library\n");
737 fprintf(stderr, "\t-T print the table of contents of a dynamic "
738 "shared library\n");
739 fprintf(stderr, "\t-M print the module table of a dynamic shared "
740 "library\n");
741 fprintf(stderr, "\t-R print the reference table of a dynamic shared "
742 "library\n");
743 fprintf(stderr, "\t-I print the indirect symbol table\n");
744 fprintf(stderr, "\t-H print the two-level hints table\n");
745 fprintf(stderr, "\t-G print the data in code table\n");
746 fprintf(stderr, "\t-v print verbosely (symbolically) when possible\n");
747 fprintf(stderr, "\t-V print disassembled operands symbolically\n");
748 fprintf(stderr, "\t-c print argument strings of a core file\n");
749 fprintf(stderr, "\t-X print no leading addresses or headers\n");
750 fprintf(stderr, "\t-m don't use archive(member) syntax\n");
751 fprintf(stderr, "\t-B force Thumb disassembly (ARM objects only)\n");
752 fprintf(stderr, "\t-q use llvm's disassembler (the default)\n");
753 fprintf(stderr, "\t-Q use otool(1)'s disassembler\n");
754 fprintf(stderr, "\t-mcpu=arg use `arg' as the cpu for disassembly\n");
755 fprintf(stderr, "\t-j print opcode bytes\n");
756 fprintf(stderr, "\t-P print the info plist section as strings\n");
757 fprintf(stderr, "\t-C print linker optimization hints\n");
758 fprintf(stderr, "\t--version print the version of %s\n", progname);
759 exit(EXIT_FAILURE);
762 #ifdef LLVM_OTOOL
764 static void llvm_otool(
765 char **files,
766 uint32_t nfiles,
767 struct arch_flag *arch_flags,
768 uint32_t narch_flags,
769 enum bool all_archs,
770 enum bool version)
772 char *objdump;
773 struct stat stat_buf;
774 uint32_t i;
776 objdump = cmd_with_prefix("objdump");
777 if(stat(objdump, &stat_buf) == -1)
778 objdump = cmd_with_prefix("llvm-objdump");
780 reset_execute_list();
781 add_execute_list(objdump);
782 add_execute_list("-macho");
784 if(fflag)
785 add_execute_list("-universal-headers");
786 if(aflag){
787 add_execute_list("-archive-headers");
788 if(Vflag)
789 add_execute_list("-archive-member-offsets");
791 if(hflag && !lflag)
792 add_execute_list("-private-header");
793 if(lflag)
794 add_execute_list("-private-headers");
795 if(tflag){
796 if(vflag)
797 add_execute_list("-disassemble");
798 else{
799 add_execute_list("-section");
800 add_execute_list("__TEXT,__text");
803 if(tflag || segname != NULL){
804 add_execute_list("-full-leading-addr");
805 add_execute_list("-print-imm-hex");
807 if(pflag != NULL){
808 add_execute_list("-dis-symname");
809 add_execute_list(pflag);
811 if(*mcpu != '\0')
812 add_execute_list(makestr("-mcpu=", mcpu, NULL));
813 if(Iflag)
814 add_execute_list("-indirect-symbols");
815 if(Gflag)
816 add_execute_list("-data-in-code");
817 if(Cflag)
818 add_execute_list("-link-opt-hints");
819 if(Pflag)
820 add_execute_list("-info-plist");
821 if(segname != NULL && sectname != NULL){
822 add_execute_list("-section");
823 add_execute_list(makestr(segname, ",", sectname, NULL));
825 if(dflag){
826 add_execute_list("-section");
827 add_execute_list("__DATA,__data");
829 if(rflag)
830 add_execute_list("-r");
831 if(Sflag)
832 error("for -S functionality, use llvm-nm with -print-armap");
833 if(version)
834 add_execute_list("-version");
835 if(print_bind_info)
836 add_execute_list("-bind");
837 if(Lflag)
838 add_execute_list("-dylibs-used");
839 if(Dflag)
840 add_execute_list("-dylib-id");
841 if(oflag)
842 add_execute_list("-objc-meta-data");
844 if(!vflag)
845 add_execute_list("-non-verbose");
846 if(!Vflag && (tflag || segname != NULL))
847 add_execute_list("-no-symbolic-operands");
848 if((!jflag && (tflag || segname != NULL)) || no_show_raw_insn)
849 add_execute_list("-no-show-raw-insn");
850 if(Xflag)
851 add_execute_list("-no-leading-addr");
853 if(all_archs){
854 add_execute_list("-arch");
855 add_execute_list("all");
857 for(i = 0; i < narch_flags; i++){
858 add_execute_list("-arch");
859 add_execute_list(arch_flags[i].name);
862 if(Bflag)
863 warning("-B functionality not implemented in objdump(1)");
864 if(cflag)
865 warning("-c functionality not implemented in objdump(1)");
866 if(Wflag)
867 warning("-W functionality not implemented in objdump(1)");
868 if(function_offsets)
869 warning("-function-offsets functionality not implemented in "
870 "objdump(1)");
871 if(Oflag)
872 warning("-O functionality obsolete");
873 if(Tflag)
874 warning("-T functionality obsolete");
875 if(Mflag)
876 warning("-M functionality obsolete");
877 if(Rflag)
878 warning("-R functionality obsolete");
879 if(iflag)
880 warning("-i functionality obsolete");
881 if(Qflag)
882 warning("-Q functionality obsolete");
884 for(i = 0; i < nfiles; i++)
885 add_execute_list(files[i]);
887 if(execute_list(show_objdump_command) == 0)
888 fatal("internal objdump command failed");
891 #else /* !defined(LLVM_OTOOL) */
893 static
894 void
895 processor(
896 struct ofile *ofile,
897 char *arch_name,
898 void *cookie) /* cookie is not used */
900 char *addr;
901 uint32_t i, magic;
902 uint64_t size;
903 struct mach_header mh;
904 struct mach_header_64 mh64;
905 cpu_type_t mh_cputype;
906 cpu_subtype_t mh_cpusubtype;
907 uint32_t mh_magic, mh_filetype, mh_ncmds, mh_sizeofcmds, sizeof_mach_header;
908 struct load_command *load_commands;
909 uint32_t nsymbols, nsorted_symbols, strings_size, len;
910 struct nlist *symbols, *allocated_symbols;
911 struct nlist_64 *symbols64, *allocated_symbols64;
912 struct symbol *sorted_symbols;
913 char *strings, *p;
914 uint32_t n_strx;
915 uint8_t n_type;
916 uint16_t n_desc;
917 uint64_t n_value;
918 char *sect;
919 uint32_t sect_nrelocs, sect_flags, nrelocs, next_relocs, nloc_relocs;
920 uint64_t sect_addr, sect_size;
921 struct relocation_info *sect_relocs, *relocs, *ext_relocs, *loc_relocs;
922 uint32_t *indirect_symbols, *allocated_indirect_symbols;
923 uint32_t nindirect_symbols;
924 struct dylib_module *mods, *allocated_mods;
925 struct dylib_module_64 *mods64, *allocated_mods64;
926 struct dylib_table_of_contents *tocs, *allocated_tocs;
927 struct dylib_reference *refs, *allocated_refs;
928 uint32_t nmods, ntocs, nrefs;
929 struct twolevel_hint *hints, *allocated_hints;
930 struct data_in_code_entry *dices, *allocated_dices;
931 uint32_t nhints, ndices;
932 uint64_t seg_addr;
933 char *loh;
934 uint32_t nloh;
935 struct dyld_bind_info *dbi;
936 uint64_t ndbi;
937 uint64_t big_size;
939 sorted_symbols = NULL;
940 nsorted_symbols = 0;
941 indirect_symbols = NULL;
942 nindirect_symbols = 0;
943 hints = NULL;
944 nhints = 0;
945 dices = NULL;
946 ndices = 0;
947 symbols = NULL;
948 symbols64 = NULL;
949 nsymbols = 0;
950 strings = NULL;
951 nmods = 0;
952 mods64 = NULL;
953 mods = NULL;
955 * These may or may not be allocated. If allocated they will not be
956 * NULL and then free'ed before returning.
958 load_commands = NULL;
959 allocated_symbols = NULL;
960 allocated_symbols64 = NULL;
961 sorted_symbols = NULL;
962 allocated_indirect_symbols = NULL;
963 allocated_tocs = NULL;
964 allocated_mods = NULL;
965 allocated_refs = NULL;
966 allocated_hints = NULL;
967 allocated_dices = NULL;
968 dbi = NULL;
969 ndbi = 0;
972 * The fat headers are printed in ofile_map() in ofile.c #ifdef'ed
973 * OTOOL.
977 * Archive headers.
979 if(aflag && ofile->member_ar_hdr != NULL){
980 uint64_t member_offset;
982 member_offset = ofile->member_offset - sizeof(struct ar_hdr);
983 if(strncmp(ofile->member_ar_hdr->ar_name, AR_EFMT1,
984 sizeof(AR_EFMT1) - 1) == 0)
985 member_offset -= ofile->member_name_size;
987 print_ar_hdr(ofile->member_ar_hdr, ofile->member_name,
988 ofile->member_name_size, member_offset, vflag, Vflag);
992 * Archive table of contents.
994 if(ofile->member_ar_hdr != NULL &&
995 (strncmp(ofile->member_name, SYMDEF, sizeof(SYMDEF)-1) == 0 ||
996 strncmp(ofile->member_name, "/ ", sizeof("/ ")-1) == 0)){
997 if(Sflag == FALSE)
998 return;
999 if(ofile->file_type == OFILE_FAT){
1000 if(ofile->fat_header->magic == FAT_MAGIC_64){
1001 addr = ofile->file_addr +
1002 ofile->fat_archs64[ofile->narch].offset;
1003 size = ofile->fat_archs64[ofile->narch].size;
1005 else{
1006 addr = ofile->file_addr +
1007 ofile->fat_archs[ofile->narch].offset;
1008 size = ofile->fat_archs[ofile->narch].size;
1011 else{
1012 addr = ofile->file_addr;
1013 size = ofile->file_size;
1015 if(addr + size > ofile->file_addr + ofile->file_size)
1016 size = (ofile->file_addr + ofile->file_size) - addr;
1017 if(strncmp(ofile->member_name, SYMDEF, sizeof(SYMDEF)-1) == 0)
1018 print_library_toc(ofile->member_ar_hdr, /* toc_ar_hdr */
1019 ofile->member_name, /* toc_name */
1020 ofile->member_name_size, /* toc_name_size */
1021 ofile->member_addr, /* toc_addr */
1022 ofile->member_size, /* toc_size */
1023 get_toc_byte_sex(addr, size),
1024 ofile->file_name, /* library_name */
1025 addr, /* library_addr */
1026 size, /* library_size */
1027 arch_name,
1028 vflag);
1029 else
1030 print_sysv_library_toc(ofile->member_ar_hdr, /* toc_ar_hdr */
1031 ofile->member_name, /* toc_name */
1032 ofile->member_name_size,
1033 /* toc_name_size */
1034 ofile->member_addr, /* toc_addr */
1035 ofile->member_size, /* toc_size */
1036 get_toc_byte_sex(addr, size),
1037 ofile->file_name, /* library_name */
1038 addr, /* library_addr */
1039 size, /* library_size */
1040 arch_name,
1041 vflag);
1042 return;
1045 * Quietly skip the System V archive string table member name which has
1046 * the name "//", just as we skip the table of contents above.
1048 if(ofile->member_ar_hdr != NULL &&
1049 strncmp(ofile->member_name, "// ", sizeof("// ")-1) == 0)
1050 return;
1052 if(object_processing == FALSE)
1053 return;
1056 * Print header for the object name if in an archive or an architecture
1057 * name is passed in.
1059 if(Xflag == FALSE){
1060 printf("%s", ofile->file_name);
1061 if(ofile->member_ar_hdr != NULL){
1062 printf("(%.*s)", (int)ofile->member_name_size,
1063 ofile->member_name);
1065 if(arch_name != NULL)
1066 printf(" (architecture %s):", arch_name);
1067 else
1068 printf(":");
1070 * If the mach_header pointer is NULL the file is not an object
1071 * file. Truncated object file (where the file size is less
1072 * than sizeof(struct mach_header) also does not have it's
1073 * mach_header set. So deal with both cases here and then
1074 * return as the rest of this routine deals only with things
1075 * in object files.
1077 if(ofile->mh == NULL && ofile->mh64 == NULL){
1078 if(ofile->file_type == OFILE_FAT){
1080 * This routine is not called on fat files where the
1081 * offset is past end of file. An error message is
1082 * printed in ofile_specific_arch() in ofile.c.
1084 if(ofile->arch_type == OFILE_ARCHIVE){
1085 addr = ofile->member_addr;
1086 size = ofile->member_size;
1088 else{
1089 if(ofile->fat_header->magic == FAT_MAGIC_64){
1090 addr = ofile->file_addr +
1091 ofile->fat_archs64[ofile->narch].offset;
1092 size = ofile->fat_archs64[ofile->narch].size;
1094 else{
1095 addr = ofile->file_addr +
1096 ofile->fat_archs[ofile->narch].offset;
1097 size = ofile->fat_archs[ofile->narch].size;
1100 if(addr + size > ofile->file_addr + ofile->file_size)
1101 size = (ofile->file_addr + ofile->file_size) - addr;
1103 else if(ofile->file_type == OFILE_ARCHIVE){
1104 addr = ofile->member_addr;
1105 size = ofile->member_size;
1107 else{ /* ofile->file_type == OFILE_UNKNOWN */
1108 addr = ofile->file_addr;
1109 size = ofile->file_size;
1111 if(size > sizeof(int32_t)){
1112 memcpy(&magic, addr, sizeof(uint32_t));
1113 if(magic == MH_MAGIC ||
1114 magic == SWAP_INT(MH_MAGIC)){
1115 printf(" is a truncated object file\n");
1116 memset(&mh, '\0', sizeof(struct mach_header));
1117 if(size > sizeof(struct mach_header))
1118 size = sizeof(struct mach_header);
1119 memcpy(&mh, addr, size);
1120 if(magic == SWAP_INT(MH_MAGIC))
1121 swap_mach_header(&mh, get_host_byte_sex());
1122 if(hflag)
1123 print_mach_header(mh.magic, mh.cputype,
1124 mh.cpusubtype, mh.filetype, mh.ncmds,
1125 mh.sizeofcmds, mh.flags, vflag);
1126 return;
1128 else if(magic == MH_MAGIC_64 ||
1129 magic == SWAP_INT(MH_MAGIC_64)){
1130 printf(" is a truncated object file\n");
1131 memset(&mh64, '\0', sizeof(struct mach_header_64));
1132 if(size > sizeof(struct mach_header_64))
1133 size = sizeof(struct mach_header_64);
1134 memcpy(&mh64, addr, size);
1135 if(magic == SWAP_INT(MH_MAGIC_64))
1136 swap_mach_header_64(&mh64, get_host_byte_sex());
1137 if(hflag)
1138 print_mach_header(mh64.magic, mh64.cputype,
1139 mh64.cpusubtype, mh64.filetype, mh64.ncmds,
1140 mh64.sizeofcmds, mh64.flags, vflag);
1141 return;
1144 #ifdef LTO_SUPPORT
1145 if(ofile->lto != NULL){
1146 printf(" is an LLVM bit-code file\n");
1147 return;
1149 #endif /* LTO_SUPPORT */
1150 printf(" is not an object file\n");
1151 return;
1154 if(ofile->mh != NULL){
1155 if((intptr_t)(ofile->mh) % sizeof(uint32_t)){
1156 if(Xflag == FALSE)
1157 printf("(object file offset is not a multiple of sizeof("
1158 "uint32_t))");
1159 memcpy(&mh, ofile->mh, sizeof(struct mach_header));
1160 if(mh.magic == SWAP_INT(MH_MAGIC))
1161 swap_mach_header(&mh, get_host_byte_sex());
1162 ofile->mh = &mh;
1164 else if(ofile->mh->magic == SWAP_INT(MH_MAGIC)){
1165 mh = *(ofile->mh);
1166 swap_mach_header(&mh, get_host_byte_sex());
1167 ofile->mh = &mh;
1170 else if(ofile->mh64 != NULL){
1171 if((intptr_t)(ofile->mh64) % sizeof(uint32_t)){
1172 if(Xflag == FALSE)
1173 printf("(object file offset is not a multiple of sizeof("
1174 "uint32_t))");
1175 memcpy(&mh64, ofile->mh64, sizeof(struct mach_header));
1176 if(mh64.magic == SWAP_INT(MH_MAGIC_64))
1177 swap_mach_header_64(&mh64, get_host_byte_sex());
1178 ofile->mh64 = &mh64;
1180 else if(ofile->mh64->magic == SWAP_INT(MH_MAGIC_64)){
1181 mh64 = *(ofile->mh64);
1182 swap_mach_header_64(&mh64, get_host_byte_sex());
1183 ofile->mh64 = &mh64;
1186 if(Xflag == FALSE)
1187 printf("\n");
1190 * If this is not an object file then just return.
1192 if(ofile->mh == NULL && ofile->mh64 == NULL)
1193 return;
1196 * Calculate the true number of bytes of the of the object file that
1197 * is in memory (in case this file is truncated).
1199 addr = ofile->object_addr;
1200 size = ofile->object_size;
1201 if(addr + size > ofile->file_addr + ofile->file_size)
1202 size = (ofile->file_addr + ofile->file_size) - addr;
1205 * Assign some local variables to the values in the mach_header for this
1206 * ofile to make passing arguments to the print routines easier.
1208 if(ofile->mh != NULL){
1209 mh_magic = ofile->mh->magic;
1210 mh_cputype = ofile->mh->cputype;
1211 mh_cpusubtype = ofile->mh->cpusubtype;
1212 mh_filetype = ofile->mh->filetype;
1213 mh_ncmds = ofile->mh->ncmds;
1214 mh_sizeofcmds = ofile->mh->sizeofcmds;
1215 sizeof_mach_header = sizeof(struct mach_header);
1217 else{
1218 mh_magic = ofile->mh64->magic;
1219 mh_cputype = ofile->mh64->cputype;
1220 mh_cpusubtype = ofile->mh64->cpusubtype;
1221 mh_filetype = ofile->mh64->filetype;
1222 mh_ncmds = ofile->mh64->ncmds;
1223 mh_sizeofcmds = ofile->mh64->sizeofcmds;
1224 sizeof_mach_header = sizeof(struct mach_header_64);
1228 * Mach header.
1230 if(hflag){
1231 if(ofile->mh != NULL)
1232 print_mach_header(ofile->mh->magic, ofile->mh->cputype,
1233 ofile->mh->cpusubtype, ofile->mh->filetype,
1234 ofile->mh->ncmds, ofile->mh->sizeofcmds,
1235 ofile->mh->flags, vflag);
1236 else
1237 print_mach_header(ofile->mh64->magic, ofile->mh64->cputype,
1238 ofile->mh64->cpusubtype,ofile->mh64->filetype,
1239 ofile->mh64->ncmds, ofile->mh64->sizeofcmds,
1240 ofile->mh64->flags, vflag);
1244 * Load commands.
1246 big_size = mh_sizeofcmds;
1247 big_size += sizeof_mach_header;
1248 if(big_size > size){
1250 * For malformed binaries trim the mh_sizeofcmds to be no bigger
1251 * than the size of the file after the mach_header. This will
1252 * limit the printing of the unknown load commands so it does not
1253 * appear to be in an infinite loop printing the zero's we created
1254 * with the memset().
1256 if(size > sizeof_mach_header)
1257 mh_sizeofcmds = size - sizeof_mach_header;
1258 else
1259 mh_sizeofcmds = sizeof(struct load_command);
1260 load_commands = allocate(mh_sizeofcmds);
1261 memset(load_commands, '\0', mh_sizeofcmds);
1262 if(size > sizeof_mach_header)
1263 memcpy(load_commands, ofile->load_commands, mh_sizeofcmds);
1264 ofile->load_commands = load_commands;
1266 if(lflag)
1267 print_loadcmds(ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1268 mh_cputype, mh_filetype, ofile->object_byte_sex,
1269 size, vflag, Vflag);
1271 if(Lflag || Dflag)
1272 print_libraries(ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1273 ofile->object_byte_sex, (Dflag && !Lflag), vflag);
1276 * If the indicated operation needs the symbol table get it.
1278 sect_flags = 0;
1279 if(segname != NULL && sectname != NULL){
1280 (void)get_sect_info(segname, sectname, ofile->load_commands,
1281 mh_ncmds, mh_sizeofcmds, mh_filetype,
1282 ofile->object_byte_sex,
1283 addr, size, &sect, &sect_size, &sect_addr,
1284 &sect_relocs, &sect_nrelocs, &sect_flags, &seg_addr);
1286 * The MH_DYLIB_STUB format has all section sizes set to zero
1287 * except sections with indirect symbol table entries (so that the
1288 * indirect symbol table table entries can be printed, which are
1289 * based on the section size). So if we are being asked to print
1290 * the section contents of one of these sections in a MH_DYLIB_STUB
1291 * we assume it has been stripped and set the section size to zero.
1293 if(mh_filetype == MH_DYLIB_STUB &&
1294 ((sect_flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ||
1295 (sect_flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ||
1296 (sect_flags & SECTION_TYPE) == S_LAZY_DYLIB_SYMBOL_POINTERS ||
1297 (sect_flags & SECTION_TYPE) == S_SYMBOL_STUBS))
1298 sect_size = 0;
1300 if(Rflag || Mflag)
1301 get_symbol_table_info(ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1302 mh_cputype, ofile->object_byte_sex, addr, size, &symbols,
1303 &symbols64, &nsymbols, &strings, &strings_size);
1304 if(vflag && (rflag || Tflag || Mflag || Rflag || Iflag || Hflag || tflag
1305 || iflag || oflag ||
1306 (sect_flags & SECTION_TYPE) == S_LITERAL_POINTERS ||
1307 (sect_flags & SECTION_TYPE) == S_MOD_INIT_FUNC_POINTERS ||
1308 (sect_flags & SECTION_TYPE) == S_MOD_TERM_FUNC_POINTERS ||
1309 (sect_flags & S_ATTR_PURE_INSTRUCTIONS) ==
1310 S_ATTR_PURE_INSTRUCTIONS ||
1311 (sect_flags & S_ATTR_SOME_INSTRUCTIONS) ==
1312 S_ATTR_SOME_INSTRUCTIONS ||
1313 segname != NULL)){
1314 get_symbol_table_info(ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1315 mh_cputype, ofile->object_byte_sex, addr, size, &symbols,
1316 &symbols64, &nsymbols, &strings, &strings_size);
1318 if(symbols != NULL){
1319 if((uintptr_t)symbols % sizeof(uint32_t) ||
1320 ofile->object_byte_sex != get_host_byte_sex()){
1321 allocated_symbols =
1322 allocate(nsymbols * sizeof(struct nlist));
1323 memcpy(allocated_symbols, symbols,
1324 nsymbols * sizeof(struct nlist));
1325 symbols = allocated_symbols;
1327 if(ofile->object_byte_sex != get_host_byte_sex())
1328 swap_nlist(symbols, nsymbols, get_host_byte_sex());
1330 else{
1331 if((uintptr_t)symbols64 % sizeof(uint32_t) ||
1332 ofile->object_byte_sex != get_host_byte_sex()){
1333 allocated_symbols64 =
1334 allocate(nsymbols * sizeof(struct nlist_64));
1335 memcpy(allocated_symbols64, symbols64,
1336 nsymbols * sizeof(struct nlist_64));
1337 symbols64 = allocated_symbols64;
1339 if(ofile->object_byte_sex != get_host_byte_sex())
1340 swap_nlist_64(symbols64, nsymbols, get_host_byte_sex());
1344 * If the operation needs a sorted symbol table create it.
1346 if(tflag || iflag || oflag ||
1347 (((sect_flags & SECTION_TYPE) == S_MOD_INIT_FUNC_POINTERS ||
1348 (sect_flags & SECTION_TYPE) == S_MOD_TERM_FUNC_POINTERS) &&
1349 Vflag) ||
1350 (sect_flags & S_ATTR_PURE_INSTRUCTIONS) ==
1351 S_ATTR_PURE_INSTRUCTIONS ||
1352 (sect_flags & S_ATTR_SOME_INSTRUCTIONS) ==
1353 S_ATTR_SOME_INSTRUCTIONS){
1354 sorted_symbols = allocate(nsymbols * sizeof(struct symbol));
1355 nsorted_symbols = 0;
1356 for(i = 0; i < nsymbols; i++){
1357 if(symbols != NULL){
1358 n_strx = symbols[i].n_un.n_strx;
1359 n_type = symbols[i].n_type;
1360 n_desc = symbols[i].n_desc;
1361 n_value = symbols[i].n_value;
1363 else{
1364 n_strx = symbols64[i].n_un.n_strx;
1365 n_type = symbols64[i].n_type;
1366 n_desc = symbols64[i].n_desc;
1367 n_value = symbols64[i].n_value;
1369 if(n_strx > 0 && n_strx < strings_size)
1370 p = strings + n_strx;
1371 else
1372 p = "symbol with bad string index";
1373 if(n_type & ~(N_TYPE|N_EXT|N_PEXT))
1374 continue;
1375 n_type = n_type & N_TYPE;
1376 if(n_type == N_ABS || n_type == N_SECT){
1377 len = strlen(p);
1378 if(len > sizeof(".o") - 1 &&
1379 strcmp(p + (len - (sizeof(".o") - 1)), ".o") == 0)
1380 continue;
1381 if(strcmp(p, "gcc_compiled.") == 0)
1382 continue;
1383 if(strncmp(p, "ltmp", sizeof("ltmp") - 1) == 0)
1384 continue;
1385 if(n_type == N_ABS && n_value == 0 && *p == '.')
1386 continue;
1387 sorted_symbols[nsorted_symbols].n_value = n_value;
1388 sorted_symbols[nsorted_symbols].name = p;
1389 sorted_symbols[nsorted_symbols].is_thumb =
1390 n_desc & N_ARM_THUMB_DEF;
1391 nsorted_symbols++;
1394 qsort(sorted_symbols, nsorted_symbols, sizeof(struct symbol),
1395 (int (*)(const void *, const void *))sym_compare);
1399 if(Mflag || Tflag || Rflag){
1400 get_module_table_info(ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1401 mh_cputype, ofile->object_byte_sex, addr, size, &mods, &mods64,
1402 &nmods);
1403 if(mods != NULL){
1404 if((intptr_t)mods % sizeof(uint32_t) ||
1405 ofile->object_byte_sex != get_host_byte_sex()){
1406 allocated_mods = allocate(nmods *
1407 sizeof(struct dylib_module));
1408 memcpy(allocated_mods, mods,
1409 nmods * sizeof(struct dylib_module));
1410 mods = allocated_mods;
1412 if(ofile->object_byte_sex != get_host_byte_sex())
1413 swap_dylib_module(mods, nmods, get_host_byte_sex());
1415 if(mods64 != NULL){
1416 if((intptr_t)mods64 % sizeof(uint64_t) ||
1417 ofile->object_byte_sex != get_host_byte_sex()){
1418 allocated_mods64 = allocate(nmods *
1419 sizeof(struct dylib_module_64));
1420 memcpy(allocated_mods64, mods64,
1421 nmods * sizeof(struct dylib_module_64));
1422 mods64 = allocated_mods64;
1424 if(ofile->object_byte_sex != get_host_byte_sex())
1425 swap_dylib_module_64(mods64, nmods, get_host_byte_sex());
1429 if(Tflag){
1430 get_toc_info(ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1431 ofile->object_byte_sex, addr, size, &tocs, &ntocs);
1432 if((intptr_t)tocs % sizeof(uint32_t) ||
1433 ofile->object_byte_sex != get_host_byte_sex()){
1434 allocated_tocs = allocate(ntocs *
1435 sizeof(struct dylib_table_of_contents));
1436 memcpy(allocated_tocs, tocs,
1437 ntocs * sizeof(struct dylib_table_of_contents));
1438 tocs = allocated_tocs;
1440 if(ofile->object_byte_sex != get_host_byte_sex())
1441 swap_dylib_table_of_contents(tocs, ntocs, get_host_byte_sex());
1442 print_toc(ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1443 ofile->object_byte_sex, addr, size, tocs, ntocs, mods, mods64,
1444 nmods, symbols, symbols64, nsymbols, strings, strings_size,
1445 vflag);
1448 if(Mflag){
1449 if(mods != NULL)
1450 print_module_table(mods, nmods, strings, strings_size, vflag);
1451 else
1452 print_module_table_64(mods64, nmods, strings, strings_size,
1453 vflag);
1456 if(Rflag){
1457 get_ref_info(ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1458 ofile->object_byte_sex, addr, size, &refs, &nrefs);
1459 if((intptr_t)refs % sizeof(uint32_t) ||
1460 ofile->object_byte_sex != get_host_byte_sex()){
1461 allocated_refs = allocate(nrefs *
1462 sizeof(struct dylib_reference));
1463 memcpy(allocated_refs, refs,
1464 nrefs * sizeof(struct dylib_reference));
1465 refs = allocated_refs;
1467 if(ofile->object_byte_sex != get_host_byte_sex())
1468 swap_dylib_reference(refs, nrefs, get_host_byte_sex());
1469 print_refs(refs, nrefs, mods, mods64, nmods, symbols, symbols64,
1470 nsymbols, strings, strings_size, vflag);
1473 if(Iflag || (tflag && vflag)){
1474 get_indirect_symbol_table_info(ofile->load_commands, mh_ncmds,
1475 mh_sizeofcmds, ofile->object_byte_sex, addr, size,
1476 &indirect_symbols, &nindirect_symbols);
1477 if((intptr_t)indirect_symbols % sizeof(uint32_t) ||
1478 ofile->object_byte_sex != get_host_byte_sex()){
1479 allocated_indirect_symbols = allocate(nindirect_symbols *
1480 sizeof(uint32_t));
1481 memcpy(allocated_indirect_symbols, indirect_symbols,
1482 nindirect_symbols * sizeof(uint32_t));
1483 indirect_symbols = allocated_indirect_symbols;
1485 if(ofile->object_byte_sex != get_host_byte_sex())
1486 swap_indirect_symbols(indirect_symbols, nindirect_symbols,
1487 get_host_byte_sex());
1489 if(Hflag){
1490 get_hints_table_info(ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1491 ofile->object_byte_sex, addr, size, &hints, &nhints);
1492 if((intptr_t)hints % sizeof(uint32_t) ||
1493 ofile->object_byte_sex != get_host_byte_sex()){
1494 allocated_hints = allocate(nhints *
1495 sizeof(struct twolevel_hint));
1496 memcpy(allocated_hints, hints,
1497 nhints * sizeof(struct twolevel_hint));
1498 hints = allocated_hints;
1500 if(ofile->object_byte_sex != get_host_byte_sex())
1501 swap_twolevel_hint(hints, nhints, get_host_byte_sex());
1502 print_hints(ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1503 ofile->object_byte_sex, hints, nhints, symbols, symbols64,
1504 nsymbols, strings, strings_size, vflag);
1506 if(Cflag){
1507 get_link_opt_hints(ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1508 ofile->object_byte_sex, addr, size, &loh, &nloh);
1509 print_link_opt_hints(loh, nloh);
1511 if(Gflag || (tflag && vflag)){
1512 get_data_in_code_info(ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1513 ofile->object_byte_sex, addr, size, &dices, &ndices);
1514 if((intptr_t)dices % sizeof(uint32_t) ||
1515 ofile->object_byte_sex != get_host_byte_sex()){
1516 allocated_dices = allocate(ndices *
1517 sizeof(struct data_in_code_entry));
1518 memcpy(allocated_dices, dices,
1519 ndices * sizeof(struct data_in_code_entry));
1520 dices = allocated_dices;
1522 if(ofile->object_byte_sex != get_host_byte_sex())
1523 swap_data_in_code_entry(dices, ndices, get_host_byte_sex());
1524 if(Gflag)
1525 print_dices(dices, ndices, vflag);
1527 if(Iflag)
1528 print_indirect_symbols(ofile->load_commands, mh_ncmds,mh_sizeofcmds,
1529 mh_cputype, ofile->object_byte_sex, indirect_symbols,
1530 nindirect_symbols, symbols, symbols64, nsymbols, strings,
1531 strings_size, vflag);
1533 if(rflag)
1534 print_reloc(ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1535 mh_cputype, ofile->object_byte_sex, addr, size, symbols,
1536 symbols64, nsymbols, strings, strings_size, vflag);
1537 if(print_bind_info){
1538 setup_dyld_bind_info(ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1539 ofile->object_byte_sex, ofile->object_addr, ofile->object_size,
1540 &dbi, &ndbi);
1541 print_dyld_bind_info(dbi, ndbi);
1544 if(tflag ||
1545 (sect_flags & S_ATTR_PURE_INSTRUCTIONS) ==
1546 S_ATTR_PURE_INSTRUCTIONS ||
1547 (sect_flags & S_ATTR_SOME_INSTRUCTIONS) ==
1548 S_ATTR_SOME_INSTRUCTIONS){
1549 if(tflag)
1550 (void)get_sect_info(SEG_TEXT, SECT_TEXT, ofile->load_commands,
1551 mh_ncmds, mh_sizeofcmds, mh_filetype,
1552 ofile->object_byte_sex,
1553 addr, size, &sect, &sect_size, &sect_addr,
1554 &sect_relocs, &sect_nrelocs, &sect_flags, &seg_addr);
1556 /* create aligned relocations entries as needed */
1557 relocs = NULL;
1558 nrelocs = 0;
1559 ext_relocs = NULL;
1560 next_relocs = 0;
1561 loc_relocs = NULL;
1562 nloc_relocs = 0;
1563 if(Vflag){
1564 if(mh_filetype == MH_KEXT_BUNDLE){
1565 get_linked_reloc_info(ofile->load_commands, mh_ncmds,
1566 mh_sizeofcmds, ofile->object_byte_sex,
1567 ofile->object_addr, ofile->object_size, &ext_relocs,
1568 &next_relocs, &loc_relocs, &nloc_relocs);
1569 /* create aligned relocations entries as needed */
1570 if((intptr_t)ext_relocs % sizeof(int32_t) != 0 ||
1571 ofile->object_byte_sex != get_host_byte_sex()){
1572 relocs = allocate(next_relocs *
1573 sizeof(struct relocation_info));
1574 memcpy(relocs, ext_relocs, next_relocs *
1575 sizeof(struct relocation_info));
1576 ext_relocs = relocs;
1578 if((intptr_t)loc_relocs % sizeof(int32_t) != 0 ||
1579 ofile->object_byte_sex != get_host_byte_sex()){
1580 relocs = allocate(nloc_relocs *
1581 sizeof(struct relocation_info));
1582 memcpy(relocs, loc_relocs, nloc_relocs *
1583 sizeof(struct relocation_info));
1584 loc_relocs = relocs;
1586 if(ofile->object_byte_sex != get_host_byte_sex()){
1587 swap_relocation_info(ext_relocs, next_relocs,
1588 get_host_byte_sex());
1589 swap_relocation_info(loc_relocs, nloc_relocs,
1590 get_host_byte_sex());
1592 relocs = NULL;
1594 if((intptr_t)sect_relocs % sizeof(int32_t) != 0 ||
1595 ofile->object_byte_sex != get_host_byte_sex()){
1596 nrelocs = sect_nrelocs;
1597 relocs = allocate(nrelocs *
1598 sizeof(struct relocation_info));
1599 memcpy(relocs, sect_relocs, nrelocs *
1600 sizeof(struct relocation_info));
1602 else{
1603 nrelocs = sect_nrelocs;
1604 relocs = sect_relocs;
1606 if(ofile->object_byte_sex != get_host_byte_sex())
1607 swap_relocation_info(relocs, nrelocs,
1608 get_host_byte_sex());
1609 setup_dyld_bind_info(ofile->load_commands, mh_ncmds,
1610 mh_sizeofcmds, ofile->object_byte_sex,
1611 ofile->object_addr, ofile->object_size,
1612 &dbi, &ndbi);
1614 if(Xflag == FALSE){
1615 if(tflag)
1616 printf("(%s,%s) section\n", SEG_TEXT, SECT_TEXT);
1617 else
1618 printf("Contents of (%.16s,%.16s) section\n", segname,
1619 sectname);
1621 if(Uflag)
1622 print_text_by_symbols(mh_cputype, ofile->object_byte_sex, sect,
1623 sect_size, sect_addr, sect_flags, sorted_symbols,
1624 nsorted_symbols, symbols, symbols64, nsymbols, strings,
1625 strings_size, relocs, nrelocs, ext_relocs, next_relocs,
1626 loc_relocs, nloc_relocs, dbi, ndbi, indirect_symbols,
1627 nindirect_symbols, ofile->load_commands, mh_ncmds,
1628 mh_sizeofcmds, vflag, Vflag, mh_cpusubtype,
1629 ofile->object_addr, ofile->object_size, dices, ndices,
1630 seg_addr);
1631 else
1632 print_text(mh_cputype, ofile->object_byte_sex, sect, sect_size,
1633 sect_addr, sect_flags, sorted_symbols,
1634 nsorted_symbols, symbols, symbols64, nsymbols, strings,
1635 strings_size, relocs, nrelocs, ext_relocs, next_relocs,
1636 loc_relocs, nloc_relocs, dbi, ndbi, indirect_symbols,
1637 nindirect_symbols, ofile->load_commands, mh_ncmds,
1638 mh_sizeofcmds, vflag, Vflag, mh_cpusubtype,
1639 ofile->object_addr, ofile->object_size, dices, ndices,
1640 seg_addr);
1642 if(relocs != NULL && relocs != sect_relocs)
1643 free(relocs);
1646 if(iflag){
1647 if(get_sect_info(SEG_TEXT, SECT_FVMLIB_INIT0, ofile->load_commands,
1648 mh_ncmds, mh_sizeofcmds, mh_filetype, ofile->object_byte_sex,
1649 addr, size, &sect, &sect_size, &sect_addr,
1650 &sect_relocs, &sect_nrelocs, &sect_flags, &seg_addr) == TRUE){
1652 /* create aligned, sorted relocations entries */
1653 nrelocs = sect_nrelocs;
1654 relocs = allocate(nrelocs * sizeof(struct relocation_info));
1655 memcpy(relocs, sect_relocs, nrelocs *
1656 sizeof(struct relocation_info));
1657 if(ofile->object_byte_sex != get_host_byte_sex())
1658 swap_relocation_info(relocs, nrelocs, get_host_byte_sex());
1659 qsort(relocs, nrelocs, sizeof(struct relocation_info),
1660 (int (*)(const void *, const void *))rel_compare);
1662 if(Xflag == FALSE)
1663 printf("Shared library initialization (%s,%s) section\n",
1664 SEG_TEXT, SECT_FVMLIB_INIT0);
1665 print_shlib_init(ofile->object_byte_sex, sect, sect_size,
1666 sect_addr, sorted_symbols, nsorted_symbols, symbols,
1667 symbols64, nsymbols, strings, strings_size, relocs,
1668 nrelocs, vflag);
1669 free(relocs);
1673 if(dflag){
1674 if(get_sect_info(SEG_DATA, SECT_DATA, ofile->load_commands,
1675 mh_ncmds, mh_sizeofcmds, mh_filetype, ofile->object_byte_sex,
1676 addr, size, &sect, &sect_size, &sect_addr,
1677 &sect_relocs, &sect_nrelocs, &sect_flags, &seg_addr) == TRUE){
1679 if(Xflag == FALSE)
1680 printf("(%s,%s) section\n", SEG_DATA, SECT_DATA);
1681 if(sect != NULL)
1682 print_sect(mh_cputype, ofile->object_byte_sex, sect, sect_size,
1683 sect_addr);
1687 if(Pflag){
1688 if(get_sect_info(SEG_TEXT, "__info_plist", ofile->load_commands,
1689 mh_ncmds, mh_sizeofcmds, mh_filetype, ofile->object_byte_sex,
1690 addr, size, &sect, &sect_size, &sect_addr,
1691 &sect_relocs, &sect_nrelocs, &sect_flags, &seg_addr) == TRUE){
1693 if(Xflag == FALSE)
1694 printf("(%s,%s) section\n", SEG_TEXT, "__info_plist");
1695 printf("%.*s\n", (int)sect_size, sect);
1699 if(segname != NULL && sectname != NULL &&
1700 (sect_flags & S_ATTR_PURE_INSTRUCTIONS) !=
1701 S_ATTR_PURE_INSTRUCTIONS &&
1702 (sect_flags & S_ATTR_SOME_INSTRUCTIONS) !=
1703 S_ATTR_SOME_INSTRUCTIONS){
1704 if(strcmp(segname, SEG_OBJC) == 0 &&
1705 strcmp(sectname, "__protocol") == 0 && vflag == TRUE){
1706 print_objc_protocol_section(ofile->load_commands, mh_ncmds,
1707 mh_sizeofcmds, ofile->object_byte_sex, ofile->object_addr,
1708 ofile->object_size, vflag);
1710 else if(strcmp(segname, SEG_OBJC) == 0 &&
1711 (strcmp(sectname, "__string_object") == 0 ||
1712 strcmp(sectname, "__cstring_object") == 0) &&
1713 vflag == TRUE){
1714 if(mh_cputype & CPU_ARCH_ABI64)
1715 print_objc_string_object_section_64(sectname,
1716 ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1717 ofile->object_byte_sex, ofile->object_addr,
1718 ofile->object_size, mh_cputype, symbols64, nsymbols,
1719 strings, strings_size, sorted_symbols, nsorted_symbols,
1720 vflag);
1721 else
1722 print_objc_string_object_section(sectname,
1723 ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1724 ofile->object_byte_sex, ofile->object_addr,
1725 ofile->object_size, vflag);
1727 else if(strcmp(segname, SEG_OBJC) == 0 &&
1728 strcmp(sectname, "__runtime_setup") == 0 && vflag == TRUE){
1729 print_objc_runtime_setup_section(ofile->load_commands, mh_ncmds,
1730 mh_sizeofcmds, ofile->object_byte_sex, ofile->object_addr,
1731 ofile->object_size, vflag);
1733 else if(strcmp(segname, "__LLVM") == 0 &&
1734 strcmp(sectname, "__bundle") == 0 &&
1735 (vflag == TRUE || Vflag == TRUE) &&
1736 get_sect_info(segname, sectname, ofile->load_commands,
1737 mh_ncmds, mh_sizeofcmds, mh_filetype, ofile->object_byte_sex,
1738 addr, size, &sect, &sect_size, &sect_addr, &sect_relocs,
1739 &sect_nrelocs, &sect_flags, &seg_addr) == TRUE){
1740 print_bitcode_section(sect, sect_size, vflag, Vflag, aflag,
1741 NULL);
1743 #ifdef EFI_SUPPORT
1744 else if(strcmp(segname, "__RELOC") == 0 &&
1745 strcmp(sectname, "__reloc") == 0 && vflag == TRUE){
1746 print_coff_reloc_section(ofile->load_commands, mh_ncmds,
1747 mh_sizeofcmds, mh_filetype, ofile->object_byte_sex,
1748 ofile->object_addr, ofile->object_size, vflag);
1750 #endif
1751 else if(get_sect_info(segname, sectname, ofile->load_commands,
1752 mh_ncmds, mh_sizeofcmds, mh_filetype, ofile->object_byte_sex,
1753 addr, size, &sect, &sect_size, &sect_addr,
1754 &sect_relocs, &sect_nrelocs, &sect_flags, &seg_addr) == TRUE){
1756 if(Xflag == FALSE)
1757 printf("Contents of (%.16s,%.16s) section\n", segname,
1758 sectname);
1760 if(vflag){
1761 switch((sect_flags & SECTION_TYPE)){
1762 case 0:
1763 print_sect(mh_cputype, ofile->object_byte_sex,
1764 sect, sect_size, sect_addr);
1765 break;
1766 case S_ZEROFILL:
1767 printf("zerofill section and has no contents in the "
1768 "file\n");
1769 break;
1770 case S_CSTRING_LITERALS:
1771 print_cstring_section(mh_cputype, sect, sect_size,
1772 sect_addr,
1773 Xflag == TRUE ? FALSE : TRUE);
1774 break;
1775 case S_4BYTE_LITERALS:
1776 print_literal4_section(mh_cputype, sect, sect_size,
1777 sect_addr,
1778 ofile->object_byte_sex,
1779 Xflag == TRUE ? FALSE : TRUE);
1780 break;
1781 case S_8BYTE_LITERALS:
1782 print_literal8_section(mh_cputype, sect, sect_size,
1783 sect_addr,
1784 ofile->object_byte_sex,
1785 Xflag == TRUE ? FALSE : TRUE);
1786 break;
1787 case S_16BYTE_LITERALS:
1788 print_literal16_section(mh_cputype, sect, sect_size,
1789 sect_addr,
1790 ofile->object_byte_sex,
1791 Xflag == TRUE ? FALSE : TRUE);
1792 break;
1793 case S_LITERAL_POINTERS:
1794 /* create aligned, sorted relocations entries */
1795 nrelocs = sect_nrelocs;
1796 relocs = allocate(nrelocs *
1797 sizeof(struct relocation_info));
1798 memcpy(relocs, sect_relocs, nrelocs *
1799 sizeof(struct relocation_info));
1800 if(ofile->object_byte_sex != get_host_byte_sex())
1801 swap_relocation_info(relocs, nrelocs,
1802 get_host_byte_sex());
1803 qsort(relocs, nrelocs, sizeof(struct relocation_info),
1804 (int (*)(const void *, const void *))rel_compare);
1805 print_literal_pointer_section(mh_cputype,
1806 ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1807 ofile->object_byte_sex, addr, size, sect,
1808 sect_size, sect_addr, symbols, symbols64,
1809 nsymbols, strings, strings_size, relocs,
1810 nrelocs, Xflag == TRUE ? FALSE : TRUE);
1811 free(relocs);
1813 break;
1815 case S_MOD_INIT_FUNC_POINTERS:
1816 case S_MOD_TERM_FUNC_POINTERS:
1817 print_init_term_pointer_section(mh_cputype, sect,
1818 sect_size, sect_addr, ofile->object_byte_sex,
1819 sorted_symbols, nsorted_symbols, Vflag);
1820 break;
1822 default:
1823 printf("Unknown section type (0x%x)\n",
1824 (unsigned int)(sect_flags & SECTION_TYPE));
1825 print_sect(mh_cputype, ofile->object_byte_sex, sect,
1826 sect_size, sect_addr);
1827 break;
1830 else{
1831 if((sect_flags & SECTION_TYPE) == S_ZEROFILL)
1832 printf("zerofill section and has no contents in the "
1833 "file\n");
1834 else
1835 print_sect(mh_cputype, ofile->object_byte_sex, sect,
1836 sect_size, sect_addr);
1841 if(cflag)
1842 print_argstrings(mh_magic, ofile->load_commands, mh_ncmds,
1843 mh_sizeofcmds, mh_cputype, mh_cpusubtype,
1844 ofile->object_byte_sex, ofile->object_addr,
1845 ofile->object_size);
1847 if(oflag){
1848 if(mh_cputype & CPU_ARCH_ABI64){
1849 get_linked_reloc_info(ofile->load_commands, mh_ncmds,
1850 mh_sizeofcmds, ofile->object_byte_sex,
1851 ofile->object_addr, ofile->object_size, &ext_relocs,
1852 &next_relocs, &loc_relocs, &nloc_relocs);
1853 /* create aligned relocations entries as needed */
1854 relocs = NULL;
1855 nrelocs = 0;
1856 if((intptr_t)ext_relocs % sizeof(int32_t) != 0 ||
1857 ofile->object_byte_sex != get_host_byte_sex()){
1858 relocs = allocate(next_relocs *
1859 sizeof(struct relocation_info));
1860 memcpy(relocs, ext_relocs, next_relocs *
1861 sizeof(struct relocation_info));
1862 ext_relocs = relocs;
1864 if((intptr_t)loc_relocs % sizeof(int32_t) != 0 ||
1865 ofile->object_byte_sex != get_host_byte_sex()){
1866 relocs = allocate(nloc_relocs *
1867 sizeof(struct relocation_info));
1868 memcpy(relocs, loc_relocs, nloc_relocs *
1869 sizeof(struct relocation_info));
1870 loc_relocs = relocs;
1872 if(ofile->object_byte_sex != get_host_byte_sex()){
1873 swap_relocation_info(ext_relocs, next_relocs,
1874 get_host_byte_sex());
1875 swap_relocation_info(loc_relocs, nloc_relocs,
1876 get_host_byte_sex());
1878 setup_dyld_bind_info(ofile->load_commands, mh_ncmds,
1879 mh_sizeofcmds, ofile->object_byte_sex,
1880 ofile->object_addr, ofile->object_size,
1881 &dbi, &ndbi);
1882 print_objc2_64bit(mh_cputype, ofile->load_commands, mh_ncmds,
1883 mh_sizeofcmds, ofile->object_byte_sex,
1884 ofile->object_addr, ofile->object_size, symbols64,
1885 nsymbols, strings, strings_size, sorted_symbols,
1886 nsorted_symbols, ext_relocs, next_relocs,
1887 loc_relocs, nloc_relocs, dbi, ndbi, vflag, Vflag);
1889 else if(mh_cputype == CPU_TYPE_ARM){
1890 get_linked_reloc_info(ofile->load_commands, mh_ncmds,
1891 mh_sizeofcmds, ofile->object_byte_sex,
1892 ofile->object_addr, ofile->object_size, &ext_relocs,
1893 &next_relocs, &loc_relocs, &nloc_relocs);
1894 /* create aligned relocations entries as needed */
1895 relocs = NULL;
1896 nrelocs = 0;
1897 if((intptr_t)ext_relocs % sizeof(int32_t) != 0 ||
1898 ofile->object_byte_sex != get_host_byte_sex()){
1899 relocs = allocate(next_relocs *
1900 sizeof(struct relocation_info));
1901 memcpy(relocs, ext_relocs, next_relocs *
1902 sizeof(struct relocation_info));
1903 ext_relocs = relocs;
1905 if((intptr_t)loc_relocs % sizeof(int32_t) != 0 ||
1906 ofile->object_byte_sex != get_host_byte_sex()){
1907 relocs = allocate(nloc_relocs *
1908 sizeof(struct relocation_info));
1909 memcpy(relocs, loc_relocs, nloc_relocs *
1910 sizeof(struct relocation_info));
1911 loc_relocs = relocs;
1913 if(ofile->object_byte_sex != get_host_byte_sex()){
1914 swap_relocation_info(ext_relocs, next_relocs,
1915 get_host_byte_sex());
1916 swap_relocation_info(loc_relocs, nloc_relocs,
1917 get_host_byte_sex());
1919 print_objc2_32bit(mh_cputype, ofile->load_commands, mh_ncmds,
1920 mh_sizeofcmds, ofile->object_byte_sex,
1921 ofile->object_addr, ofile->object_size, symbols,
1922 nsymbols, strings, strings_size, sorted_symbols,
1923 nsorted_symbols, ext_relocs, next_relocs,
1924 loc_relocs, nloc_relocs, vflag);
1926 else{
1928 * This is the 32-bit non-arm cputype case. Which is normally
1929 * the first Objective-C ABI. But it may be the case of a
1930 * binary for the iOS simulator which is the second Objective-C
1931 * ABI. In that case print_objc_segment() will determine that
1932 * and return FALSE.
1934 if(print_objc_segment(mh_cputype, ofile->load_commands,
1935 mh_ncmds, mh_sizeofcmds, ofile->object_byte_sex,
1936 ofile->object_addr, ofile->object_size, sorted_symbols,
1937 nsorted_symbols, vflag) == FALSE){
1938 get_linked_reloc_info(ofile->load_commands, mh_ncmds,
1939 mh_sizeofcmds, ofile->object_byte_sex,
1940 ofile->object_addr, ofile->object_size, &ext_relocs,
1941 &next_relocs, &loc_relocs, &nloc_relocs);
1942 /* create aligned relocations entries as needed */
1943 relocs = NULL;
1944 nrelocs = 0;
1945 if((intptr_t)ext_relocs % sizeof(int32_t) != 0 ||
1946 ofile->object_byte_sex != get_host_byte_sex()){
1947 relocs = allocate(next_relocs *
1948 sizeof(struct relocation_info));
1949 memcpy(relocs, ext_relocs, next_relocs *
1950 sizeof(struct relocation_info));
1951 ext_relocs = relocs;
1953 if((intptr_t)loc_relocs % sizeof(int32_t) != 0 ||
1954 ofile->object_byte_sex != get_host_byte_sex()){
1955 relocs = allocate(nloc_relocs *
1956 sizeof(struct relocation_info));
1957 memcpy(relocs, loc_relocs, nloc_relocs *
1958 sizeof(struct relocation_info));
1959 loc_relocs = relocs;
1961 if(ofile->object_byte_sex != get_host_byte_sex()){
1962 swap_relocation_info(ext_relocs, next_relocs,
1963 get_host_byte_sex());
1964 swap_relocation_info(loc_relocs, nloc_relocs,
1965 get_host_byte_sex());
1967 print_objc2_32bit(mh_cputype, ofile->load_commands,
1968 mh_ncmds, mh_sizeofcmds, ofile->object_byte_sex,
1969 ofile->object_addr, ofile->object_size, symbols,
1970 nsymbols, strings, strings_size, sorted_symbols,
1971 nsorted_symbols, ext_relocs, next_relocs,
1972 loc_relocs, nloc_relocs, vflag);
1977 if(load_commands != NULL)
1978 free(load_commands);
1979 if(allocated_symbols != NULL)
1980 free(allocated_symbols);
1981 if(sorted_symbols != NULL)
1982 free(sorted_symbols);
1983 if(allocated_indirect_symbols != NULL)
1984 free(allocated_indirect_symbols);
1985 if(allocated_hints != NULL)
1986 free(allocated_hints);
1987 if(allocated_dices != NULL)
1988 free(allocated_dices);
1989 if(allocated_tocs != NULL)
1990 free(allocated_tocs);
1991 if(allocated_mods != NULL)
1992 free(allocated_mods);
1993 if(allocated_refs != NULL)
1994 free(allocated_refs);
1995 if(dbi != NULL)
1996 free(dbi);
2000 * get_symbol_table_info() returns pointers to the symbol table and string
2001 * table as well as the number of symbols and size of the string table.
2002 * This routine handles the problems related to the file being truncated and
2003 * only returns valid pointers and sizes that can be used. This routine will
2004 * return pointers that are misaligned and it is up to the caller to deal with
2005 * alignment issues. It is also up to the caller to deal with byte sex of the
2006 * the symbol table.
2008 static
2009 void
2010 get_symbol_table_info(
2011 struct load_command *load_commands, /* input */
2012 uint32_t ncmds,
2013 uint32_t sizeofcmds,
2014 cpu_type_t cputype,
2015 enum byte_sex load_commands_byte_sex,
2016 char *object_addr,
2017 uint32_t object_size,
2018 struct nlist **symbols, /* output */
2019 struct nlist_64 **symbols64,
2020 uint32_t *nsymbols,
2021 char **strings,
2022 uint32_t *strings_size)
2024 enum byte_sex host_byte_sex;
2025 enum bool swapped;
2026 uint32_t i, left, size, st_cmd;
2027 struct load_command *lc, l;
2028 struct symtab_command st;
2029 uint64_t bigsize;
2031 *symbols = NULL;
2032 *symbols64 = NULL;
2033 *nsymbols = 0;
2034 *strings = NULL;
2035 *strings_size = 0;
2037 host_byte_sex = get_host_byte_sex();
2038 swapped = host_byte_sex != load_commands_byte_sex;
2040 st_cmd = UINT_MAX;
2041 lc = load_commands;
2042 memset((char *)&st, '\0', sizeof(struct symtab_command));
2043 for(i = 0 ; i < ncmds; i++){
2044 memcpy((char *)&l, (char *)lc, sizeof(struct load_command));
2045 if(swapped)
2046 swap_load_command(&l, host_byte_sex);
2047 if(l.cmdsize % sizeof(int32_t) != 0)
2048 printf("load command %u size not a multiple of "
2049 "sizeof(int32_t)\n", i);
2050 if((char *)lc + l.cmdsize >
2051 (char *)load_commands + sizeofcmds)
2052 printf("load command %u extends past end of load "
2053 "commands\n", i);
2054 left = sizeofcmds - ((char *)lc - (char *)load_commands);
2056 switch(l.cmd){
2057 case LC_SYMTAB:
2058 if(st_cmd != UINT_MAX){
2059 printf("more than one LC_SYMTAB command (using command %u)"
2060 "\n", st_cmd);
2061 break;
2063 size = left < sizeof(struct symtab_command) ?
2064 left : sizeof(struct symtab_command);
2065 memcpy((char *)&st, (char *)lc, size);
2066 if(swapped)
2067 swap_symtab_command(&st, host_byte_sex);
2068 st_cmd = i;
2070 if(l.cmdsize == 0){
2071 printf("load command %u size zero (can't advance to other "
2072 "load commands)\n", i);
2073 break;
2075 lc = (struct load_command *)((char *)lc + l.cmdsize);
2076 if((char *)lc > (char *)load_commands + sizeofcmds)
2077 break;
2079 if((char *)load_commands + sizeofcmds != (char *)lc)
2080 printf("Inconsistent sizeofcmds\n");
2082 if(st_cmd == UINT_MAX){
2083 return;
2086 if(st.symoff >= object_size){
2087 printf("symbol table offset is past end of file\n");
2089 else{
2090 if(cputype & CPU_ARCH_ABI64){
2091 *symbols64 = (struct nlist_64 *)(object_addr + st.symoff);
2092 bigsize = st.nsyms;
2093 bigsize *= sizeof(struct nlist_64);
2094 bigsize += st.symoff;
2095 if(bigsize > object_size){
2096 printf("symbol table extends past end of file\n");
2097 *nsymbols = (object_size - st.symoff) /
2098 sizeof(struct nlist_64);
2100 else
2101 *nsymbols = st.nsyms;
2103 else{
2104 *symbols = (struct nlist *)(object_addr + st.symoff);
2105 bigsize = st.nsyms;
2106 bigsize *= sizeof(struct nlist);
2107 bigsize += st.symoff;
2108 if(bigsize > object_size){
2109 printf("symbol table extends past end of file\n");
2110 *nsymbols = (object_size - st.symoff) /
2111 sizeof(struct nlist);
2113 else
2114 *nsymbols = st.nsyms;
2118 if(st.stroff >= object_size){
2119 printf("string table offset is past end of file\n");
2121 else{
2122 *strings = object_addr + st.stroff;
2123 bigsize = st.stroff;
2124 bigsize += st.strsize;
2125 if(bigsize > object_size){
2126 printf("string table extends past end of file\n");
2128 else
2129 *strings_size = st.strsize;
2134 * get_toc_info() returns a pointer and the size of the table of contents.
2135 * This routine handles the problems related to the file being truncated and
2136 * only returns valid pointers and sizes that can be used. This routine will
2137 * return pointers that are misaligned and it is up to the caller to deal with
2138 * alignment issues. It is also up to the caller to deal with byte sex of the
2139 * table.
2141 static
2142 void
2143 get_toc_info(
2144 struct load_command *load_commands,
2145 uint32_t ncmds,
2146 uint32_t sizeofcmds,
2147 enum byte_sex load_commands_byte_sex,
2148 char *object_addr,
2149 uint32_t object_size,
2150 struct dylib_table_of_contents **tocs, /* output */
2151 uint32_t *ntocs)
2153 struct dysymtab_command dyst;
2154 uint64_t bigsize;
2156 *tocs = NULL;
2157 *ntocs = 0;
2159 if(get_dyst(load_commands, ncmds, sizeofcmds, load_commands_byte_sex,
2160 &dyst) == FALSE)
2161 return;
2163 if(dyst.tocoff >= object_size){
2164 printf("table of contents offset is past end of file\n");
2166 else{
2167 *tocs = (struct dylib_table_of_contents *)(object_addr +
2168 dyst.tocoff);
2169 bigsize = dyst.ntoc;
2170 bigsize *= sizeof(struct dylib_table_of_contents);
2171 bigsize += dyst.tocoff;
2172 if(bigsize > object_size){
2173 printf("table of contents extends past end of file\n");
2174 *ntocs = (object_size - dyst.tocoff) /
2175 sizeof(struct dylib_table_of_contents);
2177 else
2178 *ntocs = dyst.ntoc;
2183 * get_module_table_info() returns a pointer and the size of the
2184 * module table. This routine handles the problems related to the file being
2185 * truncated and only returns valid pointers and sizes that can be used. This
2186 * routine will return pointers that are misaligned and it is up to the caller
2187 * to deal with alignment issues. It is also up to the caller to deal with
2188 * byte sex of the table.
2190 static
2191 void
2192 get_module_table_info(
2193 struct load_command *load_commands,
2194 uint32_t ncmds,
2195 uint32_t sizeofcmds,
2196 cpu_type_t cputype,
2197 enum byte_sex load_commands_byte_sex,
2198 char *object_addr,
2199 uint32_t object_size,
2200 struct dylib_module **mods, /* output */
2201 struct dylib_module_64 **mods64,
2202 uint32_t *nmods)
2204 struct dysymtab_command dyst;
2205 uint64_t bigsize;
2207 *mods = NULL;
2208 *mods64 = NULL;
2209 *nmods = 0;
2211 if(get_dyst(load_commands, ncmds, sizeofcmds, load_commands_byte_sex,
2212 &dyst) == FALSE)
2213 return;
2215 if(dyst.modtaboff >= object_size){
2216 printf("module table offset is past end of file\n");
2218 else{
2219 if(cputype & CPU_ARCH_ABI64){
2220 *mods64 = (struct dylib_module_64 *)(object_addr +
2221 dyst.modtaboff);
2222 bigsize = dyst.nmodtab;
2223 bigsize *= sizeof(struct dylib_module_64);
2224 bigsize += dyst.modtaboff;
2225 if(bigsize > object_size){
2226 printf("module table extends past end of file\n");
2227 *nmods = (object_size - dyst.modtaboff) /
2228 sizeof(struct dylib_module_64);
2230 else
2231 *nmods = dyst.nmodtab;
2233 else{
2234 *mods = (struct dylib_module *)(object_addr + dyst.modtaboff);
2235 if(dyst.modtaboff +
2236 dyst.nmodtab * sizeof(struct dylib_module) > object_size){
2237 printf("module table extends past end of file\n");
2238 *nmods = (object_size - dyst.modtaboff) /
2239 sizeof(struct dylib_module);
2241 else
2242 *nmods = dyst.nmodtab;
2248 * get_ref_info() returns a pointer and the size of the reference table.
2249 * This routine handles the problems related to the file being truncated and
2250 * only returns valid pointers and sizes that can be used. This routine will
2251 * return pointers that are misaligned and it is up to the caller to deal with
2252 * alignment issues. It is also up to the caller to deal with byte sex of the
2253 * table.
2255 static
2256 void
2257 get_ref_info(
2258 struct load_command *load_commands,
2259 uint32_t ncmds,
2260 uint32_t sizeofcmds,
2261 enum byte_sex load_commands_byte_sex,
2262 char *object_addr,
2263 uint32_t object_size,
2264 struct dylib_reference **refs, /* output */
2265 uint32_t *nrefs)
2267 struct dysymtab_command dyst;
2268 uint64_t bigsize;
2270 *refs = NULL;
2271 *nrefs = 0;
2273 if(get_dyst(load_commands, ncmds, sizeofcmds, load_commands_byte_sex,
2274 &dyst) == FALSE)
2275 return;
2277 if(dyst.extrefsymoff >= object_size){
2278 printf("reference table offset is past end of file\n");
2280 else{
2281 *refs = (struct dylib_reference *)(object_addr + dyst.extrefsymoff);
2282 bigsize = dyst.nextrefsyms;
2283 bigsize *= sizeof(struct dylib_reference);
2284 bigsize += dyst.extrefsymoff;
2285 if(bigsize > object_size){
2286 printf("reference table extends past end of file\n");
2287 *nrefs = (object_size - dyst.extrefsymoff) /
2288 sizeof(struct dylib_reference);
2290 else
2291 *nrefs = dyst.nextrefsyms;
2296 * get_indirect_symbol_table_info() returns a pointer and the size of the
2297 * indirect symbol table. This routine handles the problems related to the
2298 * file being truncated and only returns valid pointers and sizes that can be
2299 * used. This routine will return pointers that are misaligned and it is up to
2300 * the caller to deal with alignment issues. It is also up to the caller to
2301 * deal with byte sex of the table.
2303 static
2304 void
2305 get_indirect_symbol_table_info(
2306 struct load_command *load_commands,
2307 uint32_t ncmds,
2308 uint32_t sizeofcmds,
2309 enum byte_sex load_commands_byte_sex,
2310 char *object_addr,
2311 uint32_t object_size,
2312 uint32_t **indirect_symbols, /* output */
2313 uint32_t *nindirect_symbols)
2315 struct dysymtab_command dyst;
2316 uint64_t bigsize;
2318 *indirect_symbols = NULL;
2319 *nindirect_symbols = 0;
2321 if(get_dyst(load_commands, ncmds, sizeofcmds, load_commands_byte_sex,
2322 &dyst) == FALSE)
2323 return;
2325 if(dyst.indirectsymoff >= object_size){
2326 printf("indirect symbol table offset is past end of file\n");
2328 else{
2329 *indirect_symbols = (uint32_t *)(object_addr + dyst.indirectsymoff);
2330 bigsize = dyst.nindirectsyms;
2331 bigsize *= sizeof(uint32_t);
2332 bigsize += dyst.indirectsymoff;
2333 if(bigsize > object_size){
2334 printf("indirect symbol table extends past end of file\n");
2335 *nindirect_symbols = (object_size - dyst.indirectsymoff) /
2336 sizeof(uint32_t);
2338 else
2339 *nindirect_symbols = dyst.nindirectsyms;
2344 * get_dyst() gets the dysymtab_command from the mach header and load commands
2345 * passed to it and copys it into dyst. It if doesn't find one it returns FALSE
2346 * else it returns TRUE.
2348 static
2349 enum bool
2350 get_dyst(
2351 struct load_command *load_commands,
2352 uint32_t ncmds,
2353 uint32_t sizeofcmds,
2354 enum byte_sex load_commands_byte_sex,
2355 struct dysymtab_command *dyst)
2357 enum byte_sex host_byte_sex;
2358 enum bool swapped;
2359 uint32_t i, left, size, dyst_cmd;
2360 struct load_command *lc, l;
2362 host_byte_sex = get_host_byte_sex();
2363 swapped = host_byte_sex != load_commands_byte_sex;
2365 dyst_cmd = UINT_MAX;
2366 lc = load_commands;
2367 for(i = 0 ; i < ncmds; i++){
2368 memcpy((char *)&l, (char *)lc, sizeof(struct load_command));
2369 if(swapped)
2370 swap_load_command(&l, host_byte_sex);
2371 if(l.cmdsize % sizeof(int32_t) != 0)
2372 printf("load command %u size not a multiple of "
2373 "sizeof(int32_t)\n", i);
2374 if((char *)lc + l.cmdsize >
2375 (char *)load_commands + sizeofcmds)
2376 printf("load command %u extends past end of load "
2377 "commands\n", i);
2378 left = sizeofcmds - ((char *)lc - (char *)load_commands);
2380 switch(l.cmd){
2381 case LC_DYSYMTAB:
2382 if(dyst_cmd != UINT_MAX){
2383 printf("more than one LC_DYSYMTAB command (using command "
2384 "%u)\n", dyst_cmd);
2385 break;
2387 memset((char *)dyst, '\0', sizeof(struct dysymtab_command));
2388 size = left < sizeof(struct dysymtab_command) ?
2389 left : sizeof(struct dysymtab_command);
2390 memcpy((char *)dyst, (char *)lc, size);
2391 if(swapped)
2392 swap_dysymtab_command(dyst, host_byte_sex);
2393 dyst_cmd = i;
2395 if(l.cmdsize == 0){
2396 printf("load command %u size zero (can't advance to other "
2397 "load commands)\n", i);
2398 break;
2400 lc = (struct load_command *)((char *)lc + l.cmdsize);
2401 if((char *)lc > (char *)load_commands + sizeofcmds)
2402 break;
2404 if((char *)load_commands + sizeofcmds != (char *)lc)
2405 printf("Inconsistent sizeofcmds\n");
2407 if(dyst_cmd == UINT_MAX){
2408 return(FALSE);
2410 return(TRUE);
2414 * get_hints_table_info() returns a pointer and the size of the two-level hints
2415 * table. This routine handles the problems related to the file being truncated
2416 * and only returns valid pointers and sizes that can be used. This routine
2417 * will return pointers that are misaligned and it is up to the caller to deal
2418 * with alignment issues. It is also up to the caller to deal with byte sex of
2419 * the table.
2421 static
2422 void
2423 get_hints_table_info(
2424 struct load_command *load_commands,
2425 uint32_t ncmds,
2426 uint32_t sizeofcmds,
2427 enum byte_sex load_commands_byte_sex,
2428 char *object_addr,
2429 uint32_t object_size,
2430 struct twolevel_hint **hints, /* output */
2431 uint32_t *nhints)
2433 struct twolevel_hints_command hints_cmd;
2434 uint64_t bigsize;
2436 *hints = NULL;
2437 *nhints = 0;
2439 memset(&hints_cmd, '\0', sizeof(struct twolevel_hints_command));
2440 if(get_hints_cmd(load_commands, ncmds, sizeofcmds,
2441 load_commands_byte_sex, &hints_cmd) == FALSE)
2442 return;
2444 if(hints_cmd.offset >= object_size){
2445 printf("two-level hints offset is past end of file\n");
2447 else{
2448 *hints = (struct twolevel_hint *)(object_addr + hints_cmd.offset);
2449 bigsize = hints_cmd.nhints;
2450 bigsize *= sizeof(struct twolevel_hint);
2451 bigsize += hints_cmd.offset;
2452 if(bigsize > object_size){
2453 printf("two-level hints table extends past end of file\n");
2454 *nhints = (object_size - hints_cmd.offset) /
2455 sizeof(struct twolevel_hint);
2457 else
2458 *nhints = hints_cmd.nhints;
2463 * get_hints_cmd() gets the twolevel_hints_command from the mach header and
2464 * load commands passed to it and copys it into hints_cmd. It if doesn't find
2465 * one it returns FALSE else it returns TRUE.
2467 static
2468 enum bool
2469 get_hints_cmd(
2470 struct load_command *load_commands,
2471 uint32_t ncmds,
2472 uint32_t sizeofcmds,
2473 enum byte_sex load_commands_byte_sex,
2474 struct twolevel_hints_command *hints_cmd)
2476 enum byte_sex host_byte_sex;
2477 enum bool swapped;
2478 uint32_t i, left, size, cmd;
2479 struct load_command *lc, l;
2481 host_byte_sex = get_host_byte_sex();
2482 swapped = host_byte_sex != load_commands_byte_sex;
2484 cmd = UINT_MAX;
2485 lc = load_commands;
2486 for(i = 0 ; i < ncmds; i++){
2487 memcpy((char *)&l, (char *)lc, sizeof(struct load_command));
2488 if(swapped)
2489 swap_load_command(&l, host_byte_sex);
2490 if(l.cmdsize % sizeof(int32_t) != 0)
2491 printf("load command %u size not a multiple of "
2492 "sizeof(int32_t)\n", i);
2493 if((char *)lc + l.cmdsize >
2494 (char *)load_commands + sizeofcmds)
2495 printf("load command %u extends past end of load "
2496 "commands\n", i);
2497 left = sizeofcmds - ((char *)lc - (char *)load_commands);
2499 switch(l.cmd){
2500 case LC_TWOLEVEL_HINTS:
2501 if(cmd != UINT_MAX){
2502 printf("more than one LC_TWOLEVEL_HINTS command (using "
2503 "command %u)\n", cmd);
2504 break;
2506 memset((char *)hints_cmd, '\0',
2507 sizeof(struct twolevel_hints_command));
2508 size = left < sizeof(struct twolevel_hints_command) ?
2509 left : sizeof(struct twolevel_hints_command);
2510 memcpy((char *)hints_cmd, (char *)lc, size);
2511 if(swapped)
2512 swap_twolevel_hints_command(hints_cmd, host_byte_sex);
2513 cmd = i;
2515 if(l.cmdsize == 0){
2516 printf("load command %u size zero (can't advance to other "
2517 "load commands)\n", i);
2518 break;
2520 lc = (struct load_command *)((char *)lc + l.cmdsize);
2521 if((char *)lc > (char *)load_commands + sizeofcmds)
2522 break;
2524 if((char *)load_commands + sizeofcmds != (char *)lc)
2525 printf("Inconsistent sizeofcmds\n");
2527 if(cmd == UINT_MAX){
2528 return(FALSE);
2530 return(TRUE);
2534 * get_link_opt_hints() returns a pointer and the size of the linker
2535 * optimization hints table. This routine handles the problems related to the
2536 * file being truncated and only returns valid pointers and sizes that can be
2537 * used.
2539 static
2540 void
2541 get_link_opt_hints(
2542 struct load_command *load_commands,
2543 uint32_t ncmds,
2544 uint32_t sizeofcmds,
2545 enum byte_sex load_commands_byte_sex,
2546 char *object_addr,
2547 uint32_t object_size,
2548 char **loh,
2549 uint32_t *nloh)
2551 struct linkedit_data_command loh_cmd;
2552 uint64_t bigsize;
2554 *loh = NULL;
2555 *nloh = 0;
2557 memset(&loh_cmd, '\0', sizeof(struct linkedit_data_command));
2558 if(get_link_opt_hint_cmd(load_commands, ncmds, sizeofcmds,
2559 load_commands_byte_sex, &loh_cmd) == FALSE)
2560 return;
2562 if(loh_cmd.dataoff >= object_size){
2563 printf("linker optimization hints offset is past end of file\n");
2565 else{
2566 *loh = object_addr + loh_cmd.dataoff;
2567 bigsize = loh_cmd.dataoff;
2568 bigsize += loh_cmd.datasize;
2569 if(bigsize > object_size){
2570 printf("linker optimization hints extends past end of file\n");
2571 *nloh = object_size - loh_cmd.dataoff;
2573 else
2574 *nloh = loh_cmd.datasize;
2579 * get_link_opt_hint_cmd() gets the linker optimization hint command from the
2580 * mach header and load commands passed to it and copys it into loh_cmd. It if
2581 * doesn't find one it returns FALSE else it returns TRUE.
2583 static
2584 enum bool
2585 get_link_opt_hint_cmd(
2586 struct load_command *load_commands,
2587 uint32_t ncmds,
2588 uint32_t sizeofcmds,
2589 enum byte_sex load_commands_byte_sex,
2590 struct linkedit_data_command *loh_cmd)
2592 enum byte_sex host_byte_sex;
2593 enum bool swapped;
2594 uint32_t i, left, size, cmd;
2595 struct load_command *lc, l;
2597 host_byte_sex = get_host_byte_sex();
2598 swapped = host_byte_sex != load_commands_byte_sex;
2600 cmd = UINT_MAX;
2601 lc = load_commands;
2602 for(i = 0 ; i < ncmds; i++){
2603 memcpy((char *)&l, (char *)lc, sizeof(struct load_command));
2604 if(swapped)
2605 swap_load_command(&l, host_byte_sex);
2606 if(l.cmdsize % sizeof(int32_t) != 0)
2607 printf("load command %u size not a multiple of "
2608 "sizeof(int32_t)\n", i);
2609 if((char *)lc + l.cmdsize >
2610 (char *)load_commands + sizeofcmds)
2611 printf("load command %u extends past end of load "
2612 "commands\n", i);
2613 left = sizeofcmds - ((char *)lc - (char *)load_commands);
2615 switch(l.cmd){
2616 case LC_LINKER_OPTIMIZATION_HINT:
2617 if(cmd != UINT_MAX){
2618 printf("more than one LC_LINKER_OPTIMIZATION_HINT command "
2619 "(using command %u)\n", cmd);
2620 break;
2622 memset((char *)loh_cmd, '\0',
2623 sizeof(struct linkedit_data_command));
2624 size = left < sizeof(struct linkedit_data_command) ?
2625 left : sizeof(struct linkedit_data_command);
2626 memcpy((char *)loh_cmd, (char *)lc, size);
2627 if(swapped)
2628 swap_linkedit_data_command(loh_cmd, host_byte_sex);
2629 cmd = i;
2631 if(l.cmdsize == 0){
2632 printf("load command %u size zero (can't advance to other "
2633 "load commands)\n", i);
2634 break;
2636 lc = (struct load_command *)((char *)lc + l.cmdsize);
2637 if((char *)lc > (char *)load_commands + sizeofcmds)
2638 break;
2640 if((char *)load_commands + sizeofcmds != (char *)lc)
2641 printf("Inconsistent sizeofcmds\n");
2643 if(cmd == UINT_MAX){
2644 return(FALSE);
2646 return(TRUE);
2650 * get_data_in_code_info() returns a pointer and the size of the data in code
2651 * table. This routine handles the problems related to the file being truncated
2652 * and only returns valid pointers and sizes that can be used. This routine
2653 * will return pointers that are misaligned and it is up to the caller to deal
2654 * with alignment issues. It is also up to the caller to deal with byte sex of
2655 * the table.
2657 static
2658 void
2659 get_data_in_code_info(
2660 struct load_command *load_commands,
2661 uint32_t ncmds,
2662 uint32_t sizeofcmds,
2663 enum byte_sex load_commands_byte_sex,
2664 char *object_addr,
2665 uint32_t object_size,
2666 struct data_in_code_entry **dices, /* output */
2667 uint32_t *ndices)
2669 struct linkedit_data_command dices_cmd;
2670 uint64_t bigsize;
2672 *dices = NULL;
2673 *ndices = 0;
2675 memset(&dices_cmd, '\0', sizeof(struct linkedit_data_command));
2676 if(get_dices_cmd(load_commands, ncmds, sizeofcmds,
2677 load_commands_byte_sex, &dices_cmd) == FALSE)
2678 return;
2680 if(dices_cmd.dataoff >= object_size){
2681 printf("data in code offset is past end of file\n");
2683 else{
2684 *dices = (struct data_in_code_entry *)
2685 (object_addr + dices_cmd.dataoff);
2686 bigsize = dices_cmd.datasize;
2687 bigsize += dices_cmd.dataoff;
2688 if(bigsize > object_size){
2689 printf("data in code table extends past end of file\n");
2690 *ndices = (object_size - dices_cmd.dataoff) /
2691 sizeof(struct data_in_code_entry);
2693 else
2694 *ndices = dices_cmd.datasize /
2695 sizeof(struct data_in_code_entry);
2700 * get_dices_cmd() gets the linkedit_data_command for the data in code from the
2701 * mach header and load commands passed to it and copys it into dices_cmd. It
2702 * if doesn't find one it returns FALSE else it returns TRUE.
2704 static
2705 enum bool
2706 get_dices_cmd(
2707 struct load_command *load_commands,
2708 uint32_t ncmds,
2709 uint32_t sizeofcmds,
2710 enum byte_sex load_commands_byte_sex,
2711 struct linkedit_data_command *dices_cmd)
2713 enum byte_sex host_byte_sex;
2714 enum bool swapped;
2715 uint32_t i, left, size, cmd;
2716 struct load_command *lc, l;
2718 host_byte_sex = get_host_byte_sex();
2719 swapped = host_byte_sex != load_commands_byte_sex;
2721 cmd = UINT_MAX;
2722 lc = load_commands;
2723 for(i = 0 ; i < ncmds; i++){
2724 memcpy((char *)&l, (char *)lc, sizeof(struct load_command));
2725 if(swapped)
2726 swap_load_command(&l, host_byte_sex);
2727 if(l.cmdsize % sizeof(int32_t) != 0)
2728 printf("load command %u size not a multiple of "
2729 "sizeof(int32_t)\n", i);
2730 if((char *)lc + l.cmdsize >
2731 (char *)load_commands + sizeofcmds)
2732 printf("load command %u extends past end of load "
2733 "commands\n", i);
2734 left = sizeofcmds - ((char *)lc - (char *)load_commands);
2736 switch(l.cmd){
2737 case LC_DATA_IN_CODE:
2738 if(cmd != UINT_MAX){
2739 printf("more than one LC_DATA_IN_CODE command (using "
2740 "command %u)\n", cmd);
2741 break;
2743 memset((char *)dices_cmd, '\0',
2744 sizeof(struct linkedit_data_command));
2745 size = left < sizeof(struct linkedit_data_command) ?
2746 left : sizeof(struct linkedit_data_command);
2747 memcpy((char *)dices_cmd, (char *)lc, size);
2748 if(swapped)
2749 swap_linkedit_data_command(dices_cmd, host_byte_sex);
2750 cmd = i;
2752 if(l.cmdsize == 0){
2753 printf("load command %u size zero (can't advance to other "
2754 "load commands)\n", i);
2755 break;
2757 lc = (struct load_command *)((char *)lc + l.cmdsize);
2758 if((char *)lc > (char *)load_commands + sizeofcmds)
2759 break;
2761 if((char *)load_commands + sizeofcmds != (char *)lc)
2762 printf("Inconsistent sizeofcmds\n");
2764 if(cmd == UINT_MAX){
2765 return(FALSE);
2767 return(TRUE);
2771 * Function for qsort for comparing symbols.
2773 static
2775 sym_compare(
2776 struct symbol *sym1,
2777 struct symbol *sym2)
2779 if(sym1->n_value == sym2->n_value)
2780 return(0);
2781 if(sym1->n_value < sym2->n_value)
2782 return(-1);
2783 else
2784 return(1);
2788 * Function for qsort for comparing relocation entries.
2790 static
2792 rel_compare(
2793 struct relocation_info *rel1,
2794 struct relocation_info *rel2)
2796 struct scattered_relocation_info *srel;
2797 uint32_t r_address1, r_address2;
2799 if((rel1->r_address & R_SCATTERED) != 0){
2800 srel = (struct scattered_relocation_info *)rel1;
2801 r_address1 = srel->r_address;
2803 else
2804 r_address1 = rel1->r_address;
2805 if((rel2->r_address & R_SCATTERED) != 0){
2806 srel = (struct scattered_relocation_info *)rel2;
2807 r_address2 = srel->r_address;
2809 else
2810 r_address2 = rel2->r_address;
2812 if(r_address1 == r_address2)
2813 return(0);
2814 if(r_address1 < r_address2)
2815 return(-1);
2816 else
2817 return(1);
2820 enum bool
2821 get_sect_info(
2822 char *segname, /* input */
2823 char *sectname,
2824 struct load_command *load_commands,
2825 uint32_t ncmds,
2826 uint32_t sizeofcmds,
2827 uint32_t filetype,
2828 enum byte_sex load_commands_byte_sex,
2829 char *object_addr,
2830 uint32_t object_size,
2831 char **sect_pointer, /* output */
2832 uint64_t *sect_size,
2833 uint64_t *sect_addr,
2834 struct relocation_info **sect_relocs,
2835 uint32_t *sect_nrelocs,
2836 uint32_t *sect_flags,
2837 uint64_t *seg_addr)
2839 enum byte_sex host_byte_sex;
2840 enum bool found, swapped;
2841 uint32_t i, j, left, size;
2842 struct load_command *lc, l;
2843 uint32_t cmd;
2844 struct segment_command sg;
2845 struct segment_command_64 sg64;
2846 struct section s;
2847 struct section_64 s64;
2848 char *p;
2850 *sect_pointer = NULL;
2851 *sect_size = 0;
2852 *sect_addr = 0;
2853 *sect_relocs = NULL;
2854 *sect_nrelocs = 0;
2855 *sect_flags = 0;
2857 found = FALSE;
2858 cmd = 0;
2859 host_byte_sex = get_host_byte_sex();
2860 swapped = host_byte_sex != load_commands_byte_sex;
2862 lc = load_commands;
2863 for(i = 0 ; found == FALSE && i < ncmds; i++){
2864 memcpy((char *)&l, (char *)lc, sizeof(struct load_command));
2865 if(swapped)
2866 swap_load_command(&l, host_byte_sex);
2867 if(l.cmdsize % sizeof(int32_t) != 0)
2868 printf("load command %u size not a multiple of "
2869 "sizeof(int32_t)\n", i);
2870 if((char *)lc + l.cmdsize >
2871 (char *)load_commands + sizeofcmds)
2872 printf("load command %u extends past end of load "
2873 "commands\n", i);
2874 left = sizeofcmds - ((char *)lc - (char *)load_commands);
2876 switch(l.cmd){
2877 case LC_SEGMENT:
2878 memset((char *)&sg, '\0', sizeof(struct segment_command));
2879 size = left < sizeof(struct segment_command) ?
2880 left : sizeof(struct segment_command);
2881 memcpy((char *)&sg, (char *)lc, size);
2882 if(swapped)
2883 swap_segment_command(&sg, host_byte_sex);
2885 if((filetype == MH_OBJECT && sg.segname[0] == '\0') ||
2886 strncmp(sg.segname, segname, sizeof(sg.segname)) == 0){
2887 *seg_addr = sg.vmaddr;
2888 p = (char *)lc + sizeof(struct segment_command);
2889 for(j = 0 ; found == FALSE && j < sg.nsects ; j++){
2890 if(p + sizeof(struct section) >
2891 (char *)load_commands + sizeofcmds){
2892 printf("section structure command extends past "
2893 "end of load commands\n");
2895 left = sizeofcmds - (p - (char *)load_commands);
2896 memset((char *)&s, '\0', sizeof(struct section));
2897 size = left < sizeof(struct section) ?
2898 left : sizeof(struct section);
2899 memcpy((char *)&s, p, size);
2900 if(swapped)
2901 swap_section(&s, 1, host_byte_sex);
2903 if(strncmp(s.sectname, sectname,
2904 sizeof(s.sectname)) == 0 &&
2905 strncmp(s.segname, segname,
2906 sizeof(s.segname)) == 0){
2907 found = TRUE;
2908 cmd = LC_SEGMENT;
2909 break;
2912 if(p + sizeof(struct section) >
2913 (char *)load_commands + sizeofcmds)
2914 return(FALSE);
2915 p += size;
2918 break;
2919 case LC_SEGMENT_64:
2920 memset((char *)&sg64, '\0', sizeof(struct segment_command_64));
2921 size = left < sizeof(struct segment_command_64) ?
2922 left : sizeof(struct segment_command_64);
2923 memcpy((char *)&sg64, (char *)lc, size);
2924 if(swapped)
2925 swap_segment_command_64(&sg64, host_byte_sex);
2927 if((filetype == MH_OBJECT && sg64.segname[0] == '\0') ||
2928 strncmp(sg64.segname, segname, sizeof(sg64.segname)) == 0){
2929 *seg_addr = sg.vmaddr;
2930 p = (char *)lc + sizeof(struct segment_command_64);
2931 for(j = 0 ; found == FALSE && j < sg64.nsects ; j++){
2932 if(p + sizeof(struct section_64) >
2933 (char *)load_commands + sizeofcmds){
2934 printf("section structure command extends past "
2935 "end of load commands\n");
2937 left = sizeofcmds - (p - (char *)load_commands);
2938 memset((char *)&s64, '\0', sizeof(struct section_64));
2939 size = left < sizeof(struct section_64) ?
2940 left : sizeof(struct section_64);
2941 memcpy((char *)&s64, p, size);
2942 if(swapped)
2943 swap_section_64(&s64, 1, host_byte_sex);
2945 if(strncmp(s64.sectname, sectname,
2946 sizeof(s64.sectname)) == 0 &&
2947 strncmp(s64.segname, segname,
2948 sizeof(s64.segname)) == 0){
2949 found = TRUE;
2950 cmd = LC_SEGMENT_64;
2951 break;
2954 if(p + sizeof(struct section_64) >
2955 (char *)load_commands + sizeofcmds)
2956 return(FALSE);
2957 p += size;
2960 break;
2962 if(l.cmdsize == 0){
2963 printf("load command %u size zero (can't advance to other "
2964 "load commands)\n", i);
2965 break;
2967 lc = (struct load_command *)((char *)lc + l.cmdsize);
2968 if((char *)lc > (char *)load_commands + sizeofcmds)
2969 break;
2971 if(found == FALSE)
2972 return(FALSE);
2974 if(cmd == LC_SEGMENT){
2975 if((s.flags & SECTION_TYPE) == S_ZEROFILL){
2976 *sect_pointer = NULL;
2977 *sect_size = s.size;
2979 else{
2980 if(s.offset > object_size){
2981 printf("section offset for section (%.16s,%.16s) is past "
2982 "end of file\n", s.segname, s.sectname);
2984 else{
2985 *sect_pointer = object_addr + s.offset;
2986 if(s.size > object_size ||
2987 s.offset + s.size > object_size){
2988 printf("section (%.16s,%.16s) extends past end of "
2989 "file\n", s.segname, s.sectname);
2990 *sect_size = object_size - s.offset;
2992 else
2993 *sect_size = s.size;
2996 if(s.reloff >= object_size){
2997 printf("relocation entries offset for (%.16s,%.16s): is past "
2998 "end of file\n", s.segname, s.sectname);
3000 else{
3001 *sect_relocs = (struct relocation_info *)(object_addr +
3002 s.reloff);
3003 if(s.reloff + s.nreloc * sizeof(struct relocation_info) >
3004 object_size){
3005 printf("relocation entries for section (%.16s,%.16s) "
3006 "extends past end of file\n", s.segname, s.sectname);
3007 *sect_nrelocs = (object_size - s.reloff) /
3008 sizeof(struct relocation_info);
3010 else
3011 *sect_nrelocs = s.nreloc;
3013 *sect_addr = s.addr;
3014 *sect_flags = s.flags;
3016 else{
3017 if((s64.flags & SECTION_TYPE) == S_ZEROFILL){
3018 *sect_pointer = NULL;
3019 *sect_size = s64.size;
3021 else{
3022 if(s64.offset > object_size){
3023 printf("section offset for section (%.16s,%.16s) is past "
3024 "end of file\n", s64.segname, s64.sectname);
3026 else{
3027 *sect_pointer = object_addr + s64.offset;
3028 if(s64.size > object_size ||
3029 s64.offset + s64.size > object_size){
3030 printf("section (%.16s,%.16s) extends past end of "
3031 "file\n", s64.segname, s64.sectname);
3033 else
3034 *sect_size = s64.size;
3037 if(s64.reloff >= object_size){
3038 printf("relocation entries offset for (%.16s,%.16s): is past "
3039 "end of file\n", s64.segname, s64.sectname);
3041 else{
3042 *sect_relocs = (struct relocation_info *)(object_addr +
3043 s64.reloff);
3044 if(s64.reloff + s64.nreloc * sizeof(struct relocation_info) >
3045 object_size){
3046 printf("relocation entries for section (%.16s,%.16s) "
3047 "extends past end of file\n", s64.segname,
3048 s64.sectname);
3049 *sect_nrelocs = (object_size - s64.reloff) /
3050 sizeof(struct relocation_info);
3052 else
3053 *sect_nrelocs = s64.nreloc;
3055 *sect_addr = s64.addr;
3056 *sect_flags = s64.flags;
3058 return(TRUE);
3061 static
3062 void
3063 get_linked_reloc_info(
3064 struct load_command *load_commands, /* input */
3065 uint32_t ncmds,
3066 uint32_t sizeofcmds,
3067 enum byte_sex load_commands_byte_sex,
3068 char *object_addr,
3069 uint32_t object_size,
3070 struct relocation_info **ext_relocs, /* output */
3071 uint32_t *next_relocs,
3072 struct relocation_info **loc_relocs,
3073 uint32_t *nloc_relocs)
3075 struct dysymtab_command dyst;
3076 uint64_t bigsize;
3078 *ext_relocs = NULL;
3079 *next_relocs = 0;
3080 *loc_relocs = NULL;
3081 *nloc_relocs = 0;
3083 if(get_dyst(load_commands, ncmds, sizeofcmds, load_commands_byte_sex,
3084 &dyst) == FALSE)
3085 return;
3087 if(dyst.extreloff >= object_size){
3088 printf("external relocation entries offset is past end of file\n");
3090 else{
3091 *ext_relocs = (struct relocation_info *)(object_addr +
3092 dyst.extreloff);
3093 bigsize = dyst.nextrel;
3094 bigsize *= sizeof(struct relocation_info);
3095 bigsize += dyst.extreloff;
3096 if(bigsize > object_size){
3097 printf("external relocation entries extend past end of file\n");
3098 *next_relocs = (object_size - dyst.extreloff) /
3099 sizeof(struct relocation_info);
3101 else
3102 *next_relocs = dyst.nextrel;
3104 if(dyst.locreloff >= object_size){
3105 printf("local relocation entries offset is past end of file\n");
3107 else{
3108 *loc_relocs = (struct relocation_info *)(object_addr +
3109 dyst.locreloff);
3110 bigsize = dyst.nlocrel;
3111 bigsize *= sizeof(struct relocation_info);
3112 bigsize += dyst.locreloff;
3113 if(bigsize > object_size){
3114 printf("local relocation entries extend past end of file\n");
3115 *nloc_relocs = (object_size - dyst.locreloff) /
3116 sizeof(struct relocation_info);
3118 else
3119 *nloc_relocs = dyst.nlocrel;
3124 * setup_dyld_bind_info() looks for a LC_DYLD_INFO load command and if it has
3125 * bind info unpacks it and returns it in dbi and ndbi values for the internal
3126 * expanded structs.
3128 static
3129 void
3130 setup_dyld_bind_info(
3131 struct load_command *load_commands, /* input */
3132 uint32_t ncmds,
3133 uint32_t sizeofcmds,
3134 enum byte_sex load_commands_byte_sex,
3135 char *object_addr,
3136 uint32_t object_size,
3137 struct dyld_bind_info **dbi, /* output */
3138 uint64_t *ndbi)
3140 enum byte_sex host_byte_sex;
3141 enum bool swapped, found_bind;
3142 uint32_t pass, i, j, left, size, nsegs, nsegs64, ndylibs;
3143 uint64_t big_size;
3144 struct load_command *lc, l;
3145 struct dyld_info_command dyld_info;
3146 struct dylib_command dl;
3147 struct segment_command sg, **segs;
3148 struct segment_command_64 sg64, **segs64;
3149 struct section s;
3150 struct section_64 s64;
3151 char *short_name, *has_suffix;
3152 enum bool is_framework;
3153 char *p, *a;
3154 uint8_t *start, *end;
3155 const char **dylibs;
3157 /* If already setup just return. */
3158 if(*dbi != NULL)
3159 return;
3161 found_bind = FALSE;
3162 *dbi = NULL;
3163 *ndbi = 0;
3165 host_byte_sex = get_host_byte_sex();
3166 swapped = host_byte_sex != load_commands_byte_sex;
3168 nsegs = 0;
3169 nsegs64 = 0;
3170 ndylibs = 0;
3172 dylibs = NULL;
3173 segs = NULL;
3174 segs64 = NULL;
3176 * Make two passes over the load commands. On the first pass count the
3177 * number of load commands for dylibs and segments and look for an
3178 * LC_DYLD_INFO load commands If we find the bind info allocate space
3179 * arrays of pointers to dylibs and segments and fill them in on the
3180 * second pass.
3182 for(pass = 1; pass <= 2; pass++){
3183 ndylibs = 0;
3184 nsegs = 0;
3185 nsegs64 = 0;
3186 lc = load_commands;
3187 for(i = 0 ; i < ncmds; i++){
3188 memcpy((char *)&l, (char *)lc, sizeof(struct load_command));
3189 if(swapped)
3190 swap_load_command(&l, host_byte_sex);
3191 if(l.cmdsize % sizeof(int32_t) != 0)
3192 printf("load command %u size not a multiple of "
3193 "sizeof(int32_t)\n", i);
3194 if((char *)lc + l.cmdsize >
3195 (char *)load_commands + sizeofcmds)
3196 printf("load command %u extends past end of load "
3197 "commands\n", i);
3198 left = sizeofcmds - ((char *)lc - (char *)load_commands);
3200 switch(l.cmd){
3202 case LC_DYLD_INFO:
3203 case LC_DYLD_INFO_ONLY:
3204 if(pass == 1){
3205 memset((char *)&dyld_info, '\0',
3206 sizeof(struct dyld_info_command));
3207 size = left < sizeof(struct dyld_info_command) ?
3208 left : sizeof(struct dyld_info_command);
3209 memcpy((char *)&dyld_info, (char *)lc, size);
3210 if(swapped)
3211 swap_dyld_info_command(&dyld_info, host_byte_sex);
3212 if(dyld_info.bind_off > object_size){
3213 printf("bind_off in LC_DYLD_INFO load command %u "
3214 "past end of file\n", i);
3215 return;
3217 big_size = dyld_info.bind_off;
3218 big_size += dyld_info.bind_size;
3219 if(big_size > object_size){
3220 printf("bind_off plus bind_size in LC_DYLD_INFO "
3221 "load command %u past end of file\n", i);
3222 return;
3224 if(found_bind == TRUE){
3225 printf("more than one LC_DYLD_INFO load command\n");
3226 return;
3228 found_bind = TRUE;
3230 break;
3232 case LC_LOAD_DYLIB:
3233 case LC_LOAD_WEAK_DYLIB:
3234 case LC_REEXPORT_DYLIB:
3235 case LC_LOAD_UPWARD_DYLIB:
3236 case LC_LAZY_LOAD_DYLIB:
3237 if(pass == 1){
3238 ndylibs++;
3240 else{
3241 memset((char *)&dl, '\0', sizeof(struct dylib_command));
3242 size = left < sizeof(struct dylib_command) ?
3243 left : sizeof(struct dylib_command);
3244 memcpy((char *)&dl, (char *)lc, size);
3245 if(swapped)
3246 swap_dylib_command(&dl, host_byte_sex);
3247 short_name = NULL;
3248 if(dl.dylib.name.offset < dl.cmdsize &&
3249 dl.dylib.name.offset < left){
3250 p = (char *)lc + dl.dylib.name.offset;
3251 short_name = guess_short_name(p,
3252 &is_framework, &has_suffix);
3254 else
3255 p = "(bad offset for dylib.name.offset)";
3256 if(short_name != NULL)
3257 dylibs[ndylibs++] = short_name;
3258 else
3259 dylibs[ndylibs++] = p;
3261 break;
3263 case LC_SEGMENT:
3264 memset((char *)&sg, '\0', sizeof(struct segment_command));
3265 size = left < sizeof(struct segment_command) ?
3266 left : sizeof(struct segment_command);
3267 memcpy((char *)&sg, (char *)lc, size);
3268 if(swapped)
3269 swap_segment_command(&sg, host_byte_sex);
3270 if(pass == 2){
3271 a = allocate(sizeof(struct segment_command) +
3272 sg.nsects * sizeof(struct section));
3273 memcpy(a, (char *)&sg,
3274 sizeof(struct segment_command));
3275 segs[nsegs++] =
3276 (struct segment_command *)a;
3277 a += sizeof(struct segment_command);
3280 p = (char *)lc + sizeof(struct segment_command);
3281 for(j = 0 ; j < sg.nsects ; j++){
3282 if(p + sizeof(struct section) >
3283 (char *)load_commands + sizeofcmds){
3284 printf("section structure command extends past "
3285 "end of load commands\n");
3286 return;
3288 left = sizeofcmds - (p - (char *)load_commands);
3289 memset((char *)&s, '\0', sizeof(struct section));
3290 size = left < sizeof(struct section) ?
3291 left : sizeof(struct section);
3292 memcpy((char *)&s, p, size);
3293 if(swapped)
3294 swap_section(&s, 1, host_byte_sex);
3295 if(pass == 2){
3296 memcpy(a, (char *)&s, sizeof(struct section));
3297 a += sizeof(struct section);
3299 if(p + sizeof(struct section) >
3300 (char *)load_commands + sizeofcmds)
3301 return;
3302 p += size;
3304 if(pass == 1)
3305 nsegs++;
3306 break;
3307 case LC_SEGMENT_64:
3308 memset((char *)&sg64, '\0',
3309 sizeof(struct segment_command_64));
3310 size = left < sizeof(struct segment_command_64) ?
3311 left : sizeof(struct segment_command_64);
3312 memcpy((char *)&sg64, (char *)lc, size);
3313 if(swapped)
3314 swap_segment_command_64(&sg64, host_byte_sex);
3315 if(pass == 2){
3316 a = allocate(sizeof(struct segment_command_64) +
3317 sg64.nsects * sizeof(struct section_64));
3318 memcpy(a, (char *)&sg64,
3319 sizeof(struct segment_command_64));
3320 segs64[nsegs64++] =
3321 (struct segment_command_64 *)a;
3322 a += sizeof(struct segment_command_64);
3325 p = (char *)lc + sizeof(struct segment_command_64);
3326 for(j = 0 ; j < sg64.nsects ; j++){
3327 if(p + sizeof(struct section_64) >
3328 (char *)load_commands + sizeofcmds){
3329 printf("section structure command extends past "
3330 "end of load commands\n");
3332 left = sizeofcmds - (p - (char *)load_commands);
3333 memset((char *)&s64, '\0', sizeof(struct section_64));
3334 size = left < sizeof(struct section_64) ?
3335 left : sizeof(struct section_64);
3336 memcpy((char *)&s64, p, size);
3337 if(swapped)
3338 swap_section_64(&s64, 1, host_byte_sex);
3339 if(pass == 2){
3340 memcpy(a, (char *)&s64, sizeof(struct section_64));
3341 a += sizeof(struct section_64);
3343 if(p + sizeof(struct section_64) >
3344 (char *)load_commands + sizeofcmds)
3345 return;
3346 p += size;
3348 if(pass == 1)
3349 nsegs64++;
3350 break;
3352 if(l.cmdsize == 0){
3353 printf("load command %u size zero (can't advance to other "
3354 "load commands)\n", i);
3355 break;
3357 lc = (struct load_command *)((char *)lc + l.cmdsize);
3358 if((char *)lc > (char *)load_commands + sizeofcmds)
3359 break;
3361 if(found_bind == FALSE)
3362 return;
3363 if(pass == 1){
3364 dylibs = (const char **)allocate(ndylibs * sizeof(char *));
3365 segs = (struct segment_command **)allocate(
3366 nsegs * sizeof(struct segment_command *));
3367 segs64 = (struct segment_command_64 **)allocate(
3368 nsegs64 * sizeof(struct segment_command_64 *));
3372 start = (uint8_t *)(object_addr + dyld_info.bind_off);
3373 end = start + dyld_info.bind_size;
3374 get_dyld_bind_info(start, end, dylibs, ndylibs, segs, nsegs,
3375 segs64, nsegs64, dbi, ndbi);
3377 if(dylibs != NULL)
3378 free(dylibs);
3379 if(segs != NULL){
3380 for(i = 0; i < nsegs; i++)
3381 free(segs[i]);
3382 free(segs);
3384 if(segs64 != NULL){
3385 for(i = 0; i < nsegs64; i++)
3386 free(segs64[i]);
3387 free(segs64);
3391 static
3392 void
3393 print_text_by_symbols(
3394 cpu_type_t cputype,
3395 enum byte_sex object_byte_sex,
3396 char *sect,
3397 uint32_t size,
3398 uint64_t addr,
3399 uint32_t sect_flags,
3400 struct symbol *sorted_symbols,
3401 uint32_t nsorted_symbols,
3402 struct nlist *symbols,
3403 struct nlist_64 *symbols64,
3404 uint32_t nsymbols,
3405 char *strings,
3406 uint32_t strings_size,
3407 struct relocation_info *relocs,
3408 uint32_t nrelocs,
3409 struct relocation_info *ext_relocs,
3410 uint32_t next_relocs,
3411 struct relocation_info *loc_relocs,
3412 uint32_t nloc_relocs,
3413 struct dyld_bind_info *dbi,
3414 uint64_t ndbi,
3415 uint32_t *indirect_symbols,
3416 uint32_t nindirect_symbols,
3417 struct load_command *load_commands,
3418 uint32_t ncmds,
3419 uint32_t sizeofcmds,
3420 enum bool disassemble,
3421 enum bool verbose,
3422 cpu_subtype_t cpusubtype,
3423 char *object_addr,
3424 uint32_t object_size,
3425 struct data_in_code_entry *dices,
3426 uint32_t ndices,
3427 uint64_t seg_addr)
3429 uint32_t i, symbol_size;
3430 uint64_t symbol_addr, symbol_offset;
3432 for(i = 0; i < nsorted_symbols; i++){
3433 symbol_addr = sorted_symbols[i].n_value;
3434 if(symbol_addr < addr || symbol_addr >= addr + size)
3435 continue;
3436 symbol_offset = symbol_addr - addr;
3437 if(i+1 < nsorted_symbols &&
3438 sorted_symbols[i+1].n_value < addr + size)
3439 symbol_size = sorted_symbols[i+1].n_value - symbol_addr;
3440 else
3441 symbol_size = (addr + size) - symbol_addr;
3442 print_text(cputype, object_byte_sex, sect + symbol_offset,
3443 symbol_size, symbol_addr, sect_flags, sorted_symbols,
3444 nsorted_symbols, symbols, symbols64, nsymbols, strings,
3445 strings_size, relocs, nrelocs, ext_relocs, next_relocs,
3446 loc_relocs, nloc_relocs, dbi, ndbi, indirect_symbols,
3447 nindirect_symbols, load_commands, ncmds, sizeofcmds,
3448 disassemble, verbose, cpusubtype, object_addr,
3449 object_size, dices, ndices, seg_addr);
3453 static
3454 void
3455 print_text(
3456 cpu_type_t cputype,
3457 enum byte_sex object_byte_sex,
3458 char *sect,
3459 uint32_t size,
3460 uint64_t addr,
3461 uint32_t sect_flags,
3462 struct symbol *sorted_symbols,
3463 uint32_t nsorted_symbols,
3464 struct nlist *symbols,
3465 struct nlist_64 *symbols64,
3466 uint32_t nsymbols,
3467 char *strings,
3468 uint32_t strings_size,
3469 struct relocation_info *relocs,
3470 uint32_t nrelocs,
3471 struct relocation_info *ext_relocs,
3472 uint32_t next_relocs,
3473 struct relocation_info *loc_relocs,
3474 uint32_t nloc_relocs,
3475 struct dyld_bind_info *dbi,
3476 uint64_t ndbi,
3477 uint32_t *indirect_symbols,
3478 uint32_t nindirect_symbols,
3479 struct load_command *load_commands,
3480 uint32_t ncmds,
3481 uint32_t sizeofcmds,
3482 enum bool disassemble,
3483 enum bool verbose,
3484 cpu_subtype_t cpusubtype,
3485 char *object_addr,
3486 uint32_t object_size,
3487 struct data_in_code_entry *dices,
3488 uint32_t ndices,
3489 uint64_t seg_addr)
3491 enum byte_sex host_byte_sex;
3492 enum bool swapped;
3493 uint32_t i, j, offset, long_word, label_offset;
3494 uint64_t cur_addr;
3495 unsigned short short_word;
3496 unsigned char byte_word;
3497 LLVMDisasmContextRef arm64_dc;
3498 LLVMDisasmContextRef arm_dc, thumb_dc, i386_dc, x86_64_dc;
3499 uint32_t n, ninsts;
3500 struct inst *insts;
3501 char *sect_start;
3503 host_byte_sex = get_host_byte_sex();
3504 swapped = host_byte_sex != object_byte_sex;
3505 arm_dc = NULL;
3506 thumb_dc = NULL;
3507 i386_dc = NULL;
3508 x86_64_dc = NULL;
3509 arm64_dc = NULL;
3510 n = 0;
3511 ninsts = 0;
3512 insts = NULL;
3515 * If the section has a type of S_ZEROFILL then its section contents
3516 * pointer is NULL, so in this case just do nothing.
3518 if(sect == NULL)
3519 return;
3521 if(disassemble == TRUE){
3522 if(pflag){
3523 for(i = 0; i < nsorted_symbols; i++){
3524 if(strcmp(sorted_symbols[i].name, pflag) == 0)
3525 break;
3527 if(i == nsorted_symbols){
3528 printf("Can't find -p symbol: %s\n", pflag);
3529 return;
3531 if(sorted_symbols[i].n_value < addr ||
3532 sorted_symbols[i].n_value >= addr + size){
3533 printf("-p symbol: %s not in text section\n", pflag);
3534 return;
3536 offset = sorted_symbols[i].n_value - addr;
3537 sect += offset;
3538 cur_addr = sorted_symbols[i].n_value;
3539 sect_start = sect;
3541 else{
3542 offset = 0;
3543 cur_addr = addr;
3544 sect_start = sect;
3546 if(cputype == CPU_TYPE_ARM &&
3547 (cpusubtype == CPU_SUBTYPE_ARM_V7 ||
3548 cpusubtype == CPU_SUBTYPE_ARM_V7F ||
3549 cpusubtype == CPU_SUBTYPE_ARM_V7S ||
3550 cpusubtype == CPU_SUBTYPE_ARM_V7K)){
3551 if(sect_flags & S_SYMBOL_STUBS)
3552 in_thumb = FALSE;
3553 else
3554 in_thumb = TRUE;
3556 else
3557 in_thumb = FALSE;
3558 if((qflag || gflag) && cputype == CPU_TYPE_ARM){
3559 arm_dc = create_arm_llvm_disassembler(cpusubtype);
3560 if(arm_dc == NULL){
3561 printf("can't create arm llvm disassembler\n");
3562 return;
3564 thumb_dc = create_thumb_llvm_disassembler(cpusubtype);
3565 if(thumb_dc == NULL){
3566 printf("can't create thumb llvm disassembler\n");
3567 return;
3569 llvm_disasm_set_options(arm_dc,
3570 LLVMDisassembler_Option_PrintImmHex);
3571 llvm_disasm_set_options(thumb_dc,
3572 LLVMDisassembler_Option_PrintImmHex);
3573 if(eflag){
3574 llvm_disasm_set_options(arm_dc,
3575 LLVMDisassembler_Option_UseMarkup);
3576 llvm_disasm_set_options(thumb_dc,
3577 LLVMDisassembler_Option_UseMarkup);
3580 if((qflag || gflag) && cputype == CPU_TYPE_I386){
3581 i386_dc = create_i386_llvm_disassembler();
3582 if(i386_dc == NULL){
3583 printf("can't create i386 llvm disassembler\n");
3584 return;
3586 llvm_disasm_set_options(i386_dc,
3587 LLVMDisassembler_Option_PrintImmHex);
3588 llvm_disasm_set_options(i386_dc,
3589 LLVMDisassembler_Option_SetInstrComments);
3590 if(eflag)
3591 llvm_disasm_set_options(i386_dc,
3592 LLVMDisassembler_Option_UseMarkup);
3594 if((qflag || gflag) && cputype == CPU_TYPE_X86_64){
3595 x86_64_dc = create_x86_64_llvm_disassembler();
3596 if(x86_64_dc == NULL){
3597 printf("can't create x86_64 llvm disassembler\n");
3598 return;
3600 llvm_disasm_set_options(x86_64_dc,
3601 LLVMDisassembler_Option_PrintImmHex);
3602 llvm_disasm_set_options(x86_64_dc,
3603 LLVMDisassembler_Option_SetInstrComments);
3604 if(eflag)
3605 llvm_disasm_set_options(x86_64_dc,
3606 LLVMDisassembler_Option_UseMarkup);
3608 if(cputype == CPU_TYPE_ARM64){
3609 arm64_dc = create_arm64_llvm_disassembler(cpusubtype);
3610 if(arm64_dc == NULL){
3611 printf("can't create arm64 llvm disassembler\n");
3612 return;
3614 llvm_disasm_set_options(arm64_dc,
3615 LLVMDisassembler_Option_PrintImmHex);
3617 if(gflag){
3618 ninsts = 100;
3619 insts = allocate(sizeof(struct inst) * ninsts);
3621 label_offset = 0;
3622 for(i = offset ; i < size ; ){
3623 if(gflag &&
3624 (cputype == CPU_TYPE_X86_64 ||
3625 cputype == CPU_TYPE_I386 ||
3626 cputype == CPU_TYPE_ARM)){
3627 if(n > ninsts){
3628 ninsts += ninsts;
3629 insts = reallocate(insts, sizeof(struct inst) * ninsts);
3631 memset(&(insts[n]), '\0', sizeof(struct inst));
3632 insts[n].address = cur_addr;
3633 insts[n].label = get_label(cur_addr, sorted_symbols,
3634 nsorted_symbols);;
3636 else{
3637 if(print_label(cur_addr, TRUE, sorted_symbols,
3638 nsorted_symbols) == TRUE)
3639 label_offset = i;
3640 if(function_offsets)
3641 printf("%+6d ", (int)(i - label_offset));
3642 if(Xflag == FALSE){
3643 if(cputype & CPU_ARCH_ABI64)
3644 printf("%016llx", cur_addr);
3645 else
3646 printf("%08x", (uint32_t)cur_addr);
3647 if((qflag == FALSE ||
3648 (cputype == CPU_TYPE_POWERPC ||
3649 cputype == CPU_TYPE_POWERPC64)) &&
3650 cputype != CPU_TYPE_ARM64)
3651 printf("\t");
3654 if(cputype == CPU_TYPE_POWERPC64)
3655 j = ppc_disassemble(sect, size - i, cur_addr, addr,
3656 object_byte_sex, relocs, nrelocs, symbols,
3657 symbols64, nsymbols, sorted_symbols,
3658 nsorted_symbols, strings, strings_size,
3659 indirect_symbols, nindirect_symbols,
3660 load_commands, ncmds, sizeofcmds, verbose);
3661 else if(cputype == CPU_TYPE_X86_64)
3662 j = i386_disassemble(sect, size - i, cur_addr, addr,
3663 object_byte_sex, relocs, nrelocs, ext_relocs,
3664 next_relocs, loc_relocs, nloc_relocs, dbi, ndbi,
3665 NULL, symbols64, nsymbols, sorted_symbols,
3666 nsorted_symbols, strings, strings_size,
3667 indirect_symbols, nindirect_symbols, cputype,
3668 load_commands, ncmds, sizeofcmds, verbose,
3669 llvm_mc, i386_dc, x86_64_dc , object_addr,
3670 object_size, &(insts[n]), NULL, 0);
3671 else if(cputype == CPU_TYPE_MC680x0)
3672 j = m68k_disassemble(sect, size - i, cur_addr, addr,
3673 object_byte_sex, relocs, nrelocs, symbols,
3674 nsymbols, sorted_symbols, nsorted_symbols,
3675 strings, strings_size, indirect_symbols,
3676 nindirect_symbols, load_commands, ncmds,
3677 sizeofcmds, verbose);
3678 else if(cputype == CPU_TYPE_I860)
3679 j = i860_disassemble(sect, size - i, cur_addr, addr,
3680 object_byte_sex, relocs, nrelocs, symbols,
3681 nsymbols, sorted_symbols, nsorted_symbols,
3682 strings, strings_size, verbose);
3683 else if(cputype == CPU_TYPE_I386)
3684 j = i386_disassemble(sect, size - i, cur_addr, addr,
3685 object_byte_sex, relocs, nrelocs, ext_relocs,
3686 next_relocs, loc_relocs, nloc_relocs, dbi, ndbi,
3687 symbols, NULL, nsymbols, sorted_symbols,
3688 nsorted_symbols, strings, strings_size,
3689 indirect_symbols, nindirect_symbols, cputype,
3690 load_commands, ncmds, sizeofcmds, verbose,
3691 llvm_mc, i386_dc, x86_64_dc, object_addr,
3692 object_size, &(insts[n]), NULL, 0);
3693 else if(cputype == CPU_TYPE_MC88000)
3694 j = m88k_disassemble(sect, size - i, cur_addr, addr,
3695 object_byte_sex, relocs, nrelocs, symbols,
3696 nsymbols, sorted_symbols, nsorted_symbols,
3697 strings, strings_size, verbose);
3698 else if(cputype == CPU_TYPE_POWERPC ||
3699 cputype == CPU_TYPE_VEO)
3700 j = ppc_disassemble(sect, size - i, cur_addr, addr,
3701 object_byte_sex, relocs, nrelocs, symbols,
3702 symbols64, nsymbols, sorted_symbols,
3703 nsorted_symbols, strings, strings_size,
3704 indirect_symbols, nindirect_symbols,
3705 load_commands, ncmds, sizeofcmds, verbose);
3706 else if(cputype == CPU_TYPE_HPPA)
3707 j = hppa_disassemble(sect, size - i, cur_addr, addr,
3708 object_byte_sex, relocs, nrelocs, symbols,
3709 nsymbols, sorted_symbols, nsorted_symbols,
3710 strings, strings_size, verbose);
3711 else if(cputype == CPU_TYPE_SPARC)
3712 j = sparc_disassemble(sect, size - i, cur_addr, addr,
3713 object_byte_sex, relocs, nrelocs, symbols,
3714 nsymbols, sorted_symbols, nsorted_symbols,
3715 strings, strings_size, indirect_symbols,
3716 nindirect_symbols, load_commands, ncmds,
3717 sizeofcmds, verbose);
3718 else if(cputype == CPU_TYPE_ARM)
3719 j = arm_disassemble(sect, size - i, cur_addr, addr,
3720 object_byte_sex, relocs, nrelocs, symbols,
3721 nsymbols, sorted_symbols, nsorted_symbols,
3722 strings, strings_size, indirect_symbols,
3723 nindirect_symbols, load_commands, ncmds,
3724 sizeofcmds, cpusubtype, verbose, arm_dc,
3725 thumb_dc, object_addr, object_size, dices,
3726 ndices, seg_addr, &(insts[n]), NULL, 0);
3727 else if(cputype == CPU_TYPE_ARM64)
3728 j = arm64_disassemble(sect, size - i, cur_addr, addr,
3729 object_byte_sex, relocs, nrelocs, ext_relocs,
3730 next_relocs, loc_relocs, nloc_relocs, dbi, ndbi,
3731 symbols64, nsymbols, sorted_symbols,
3732 nsorted_symbols, strings, strings_size,
3733 indirect_symbols, nindirect_symbols,
3734 load_commands, ncmds, sizeofcmds, object_addr,
3735 object_size, verbose, arm64_dc);
3737 else{
3738 printf("Can't disassemble unknown cputype %d\n", cputype);
3739 return;
3741 sect += j;
3742 cur_addr += j;
3743 i += j;
3744 if(gflag)
3745 n++;
3747 if(gflag &&
3748 (cputype == CPU_TYPE_X86_64 ||
3749 cputype == CPU_TYPE_I386 ||
3750 cputype == CPU_TYPE_ARM)){
3751 char dst[4096];
3752 dst[4095] = '\0';
3754 /* Look for inits that need tmp labels. */
3755 for(i = 0 ; i < n ; i++){
3756 if(insts[i].has_raw_target_address){
3757 for(j = 0; j < n; j++){
3758 if(insts[i].raw_target_address == insts[j].address)
3759 insts[j].needs_tmp_label = TRUE;
3764 /* Create the needed tmp labels. */
3765 j = 1;
3766 for(i = 0 ; i < n ; i++){
3767 if(insts[i].needs_tmp_label == TRUE){
3768 insts[i].tmp_label = allocate(20);
3769 sprintf(insts[i].tmp_label, "L%d", j++);
3773 /* Now finally print the inits. */
3774 for(i = 0 ; i < n ; i++){
3775 if(insts[i].label != NULL)
3776 printf("%s:\n", insts[i].label);
3777 else if(insts[i].tmp_label != NULL)
3778 printf("%s:", insts[i].tmp_label);
3779 insts[i].print = TRUE;
3780 cur_addr = insts[i].address;
3781 offset = cur_addr - addr;
3782 sect = sect_start + offset;
3783 if(cputype == CPU_TYPE_X86_64 || cputype == CPU_TYPE_I386)
3784 j = i386_disassemble(sect, size - offset, cur_addr,
3785 addr, object_byte_sex, relocs, nrelocs,
3786 ext_relocs, next_relocs, loc_relocs,
3787 nloc_relocs, dbi, ndbi, symbols, NULL,
3788 nsymbols, sorted_symbols, nsorted_symbols,
3789 strings, strings_size, indirect_symbols,
3790 nindirect_symbols, cputype, load_commands,
3791 ncmds, sizeofcmds, verbose, llvm_mc, i386_dc,
3792 x86_64_dc, object_addr, object_size,
3793 &(insts[i]), insts, n);
3794 else if(cputype == CPU_TYPE_ARM)
3795 j = arm_disassemble(sect, size - offset, cur_addr, addr,
3796 object_byte_sex, relocs, nrelocs, symbols,
3797 nsymbols, sorted_symbols, nsorted_symbols,
3798 strings, strings_size, indirect_symbols,
3799 nindirect_symbols, load_commands, ncmds,
3800 sizeofcmds, cpusubtype, verbose, arm_dc,
3801 thumb_dc, object_addr, object_size, dices,
3802 ndices, seg_addr, &(insts[i]), insts, n);
3805 /* Free up allocated space */
3806 for(i = 0 ; i < n ; i++){
3807 if(insts[i].tmp_label != NULL)
3808 free(insts[i].tmp_label);
3810 free(insts);
3812 if(i386_dc != NULL)
3813 delete_arm_llvm_disassembler(i386_dc);
3814 if(x86_64_dc != NULL)
3815 delete_arm_llvm_disassembler(x86_64_dc);
3816 if(arm_dc != NULL)
3817 delete_arm_llvm_disassembler(arm_dc);
3818 if(thumb_dc != NULL)
3819 delete_arm_llvm_disassembler(thumb_dc);
3820 if(arm64_dc != NULL)
3821 delete_arm64_llvm_disassembler(arm64_dc);
3823 else{
3824 if(cputype == CPU_TYPE_I386 || cputype == CPU_TYPE_X86_64){
3825 for(i = 0 ; i < size ; i += j , addr += j){
3826 if(cputype & CPU_ARCH_ABI64)
3827 printf("%016llx ", addr);
3828 else
3829 printf("%08x ", (uint32_t)addr);
3830 for(j = 0;
3831 j < 16 * sizeof(char) && i + j < size;
3832 j += sizeof(char)){
3833 byte_word = *(sect + i + j);
3834 printf("%02x ", (unsigned int)byte_word);
3836 printf("\n");
3839 else if(cputype == CPU_TYPE_MC680x0){
3840 for(i = 0 ; i < size ; i += j , addr += j){
3841 printf("%08x ", (unsigned int)addr);
3842 for(j = 0;
3843 j < 8 * sizeof(short) && i + j < size;
3844 j += sizeof(short)){
3845 memcpy(&short_word, sect + i + j, sizeof(short));
3846 if(swapped)
3847 short_word = SWAP_SHORT(short_word);
3848 printf("%04x ", (unsigned int)short_word);
3850 printf("\n");
3853 else{
3854 for(i = 0 ; i < size ; i += j , addr += j){
3855 if(cputype & CPU_ARCH_ABI64)
3856 printf("%016llx ", addr);
3857 else
3858 printf("%08x ", (uint32_t)addr);
3859 for(j = 0;
3860 j < 4 * sizeof(int32_t) && i + j < size;
3861 j += sizeof(int32_t)){
3862 memcpy(&long_word, sect + i + j, sizeof(int32_t));
3863 if(swapped)
3864 long_word = SWAP_INT(long_word);
3865 printf("%08x ", (unsigned int)long_word);
3867 printf("\n");
3873 static
3874 void
3875 print_argstrings(
3876 uint32_t magic,
3877 struct load_command *load_commands,
3878 uint32_t ncmds,
3879 uint32_t sizeofcmds,
3880 cpu_type_t cputype,
3881 cpu_subtype_t cpusubtype,
3882 enum byte_sex load_commands_byte_sex,
3883 char *object_addr,
3884 uint32_t object_size)
3886 enum byte_sex host_byte_sex;
3887 enum bool swapped;
3888 uint32_t i, len, left, size, arg;
3889 uint64_t usrstack;
3890 struct load_command *lc, l;
3891 struct segment_command sg;
3892 struct segment_command_64 sg64;
3893 char *stack, *stack_top, *p, *q, *argv;
3894 struct arch_flag arch_flags;
3896 host_byte_sex = get_host_byte_sex();
3897 swapped = host_byte_sex != load_commands_byte_sex;
3899 arch_flags.cputype = cputype;
3900 if(magic == MH_MAGIC_64)
3901 arch_flags.cputype |= CPU_ARCH_ABI64;
3902 arch_flags.cpusubtype = cpusubtype;
3903 usrstack = get_stack_addr_from_flag(&arch_flags);
3904 if(usrstack == 0){
3905 printf("Don't know the value of USRSTACK for unknown cputype "
3906 "(%d)\n", cputype);
3907 return;
3909 printf("Argument strings on the stack at: ");
3910 if(cputype & CPU_ARCH_ABI64 || magic == MH_MAGIC_64)
3911 printf("%016llx\n", usrstack);
3912 else
3913 printf("%08x\n", (uint32_t)usrstack);
3914 lc = load_commands;
3915 for(i = 0 ; i < ncmds; i++){
3916 memcpy((char *)&l, (char *)lc, sizeof(struct load_command));
3917 if(swapped)
3918 swap_load_command(&l, host_byte_sex);
3919 if(cputype & CPU_ARCH_ABI64 || magic == MH_MAGIC_64){
3920 if(l.cmdsize % 8 != 0)
3921 printf("load command %u size not a multiple of 8\n", i);
3923 else{
3924 if(l.cmdsize % 4 != 0)
3925 printf("load command %u size not a multiple of 4\n", i);
3927 if((char *)lc + l.cmdsize >
3928 (char *)load_commands + sizeofcmds)
3929 printf("load command %u extends past end of load "
3930 "commands\n", i);
3931 left = sizeofcmds - ((char *)lc - (char *)load_commands);
3933 switch(l.cmd){
3934 case LC_SEGMENT:
3935 memset((char *)&sg, '\0', sizeof(struct segment_command));
3936 size = left < sizeof(struct segment_command) ?
3937 left : sizeof(struct segment_command);
3938 memcpy((char *)&sg, (char *)lc, size);
3939 if(swapped)
3940 swap_segment_command(&sg, host_byte_sex);
3942 if(cputype == CPU_TYPE_HPPA){
3943 if(sg.vmaddr == usrstack &&
3944 sg.fileoff + sg.filesize <= object_size){
3945 stack = object_addr + sg.fileoff;
3946 stack_top = stack + sg.filesize;
3948 * There appears to be some pointer then argc at the
3949 * bottom of the stack first before argv[].
3951 argv = stack + 2 * sizeof(uint32_t);
3952 memcpy(&arg, argv, sizeof(uint32_t));
3953 if(swapped)
3954 arg = SWAP_INT(arg);
3955 while(argv < stack_top &&
3956 arg != 0 &&
3957 arg >= usrstack && arg < usrstack + sg.filesize){
3958 p = stack + (arg - usrstack);
3959 printf("\t");
3960 while(p < stack_top && *p != '\0'){
3961 printf("%c", *p);
3962 p++;
3964 printf("\n");
3965 argv += sizeof(uint32_t);
3966 memcpy(&arg, argv, sizeof(uint32_t));
3967 if(swapped)
3968 arg = SWAP_INT(arg);
3970 /* after argv[] then there is envp[] */
3971 argv += sizeof(uint32_t);
3972 memcpy(&arg, argv, sizeof(uint32_t));
3973 if(swapped)
3974 arg = SWAP_INT(arg);
3975 while(argv < stack_top &&
3976 arg != 0 &&
3977 arg >= usrstack && arg < usrstack + sg.filesize){
3978 p = stack + (arg - usrstack);
3979 printf("\t");
3980 while(p < stack_top && *p != '\0'){
3981 printf("%c", *p);
3982 p++;
3984 printf("\n");
3985 argv += sizeof(uint32_t);
3986 memcpy(&arg, argv, sizeof(uint32_t));
3987 if(swapped)
3988 arg = SWAP_INT(arg);
3992 else{
3993 if(sg.vmaddr + sg.vmsize == usrstack &&
3994 sg.fileoff + sg.filesize <= object_size){
3995 stack = object_addr + sg.fileoff;
3996 stack_top = stack + sg.filesize;
3998 /* the first thing on the stack is a long 0 */
3999 stack_top -= 4;
4000 p = (char *)stack_top;
4002 /* find the first non-null character before the long 0*/
4003 while(p > stack && *p == '\0')
4004 p--;
4005 if(p != (char *)stack_top)
4006 p++;
4008 q = p;
4009 /* Stop when we find another long 0 */
4010 while(p > stack && (*p != '\0' || *(p-1) != '\0' ||
4011 *(p-2) != '\0' || *(p-3) != '\0')){
4012 p--;
4013 /* step back over the string to its start */
4014 while(p > stack && *p != '\0')
4015 p--;
4018 p++; /* step forward to the start of the first string */
4019 while(p < q){
4020 printf("\t");
4021 len = 0;
4022 while(p + len < q && p[len] != '\0'){
4023 printf("%c", p[len]);
4024 len++;
4026 printf("\n");
4027 p += len + 1;
4029 return;
4032 break;
4033 case LC_SEGMENT_64:
4034 memset((char *)&sg64, '\0', sizeof(struct segment_command_64));
4035 size = left < sizeof(struct segment_command_64) ?
4036 left : sizeof(struct segment_command_64);
4037 memcpy((char *)&sg64, (char *)lc, size);
4038 if(swapped)
4039 swap_segment_command_64(&sg64, host_byte_sex);
4040 if(sg64.vmaddr + sg64.vmsize == usrstack &&
4041 sg64.fileoff + sg64.filesize <= object_size){
4042 stack = object_addr + sg64.fileoff;
4043 stack_top = stack + sg64.filesize;
4045 /* the first thing on the stack is a uint64_t 0 */
4046 stack_top -= 8;
4047 p = (char *)stack_top;
4049 /* find the first non-null character before the uint64_t 0*/
4050 while(p > stack && *p == '\0')
4051 p--;
4052 if(p != (char *)stack_top)
4053 p++;
4055 q = p;
4056 /* Stop when we find another uint64_t 0 */
4057 while(p > stack && (*p != '\0' || *(p-1) != '\0' ||
4058 *(p-2) != '\0' || *(p-3) != '\0' || *(p-4) != '\0' ||
4059 *(p-5) != '\0' || *(p-6) != '\0' || *(p-7) != '\0')){
4060 p--;
4061 /* step back over the string to its start */
4062 while(p > stack && *p != '\0')
4063 p--;
4066 p++; /* step forward to the start of the first string */
4067 while(p < q){
4068 printf("\t");
4069 len = 0;
4070 while(p + len < q && p[len] != '\0'){
4071 printf("%c", p[len]);
4072 len++;
4074 printf("\n");
4075 p += len + 1;
4077 return;
4079 break;
4082 if(l.cmdsize == 0){
4083 printf("load command %u size zero (can't advance to other "
4084 "load commands)\n", i);
4085 break;
4087 lc = (struct load_command *)((char *)lc + l.cmdsize);
4088 if((char *)lc > (char *)load_commands + sizeofcmds)
4089 break;
4093 #ifndef __DYNAMIC__
4095 * To avoid linking in libm. These variables are defined as they are used in
4096 * pthread_init() to put in place a fast sqrt().
4098 size_t hw_sqrt_len = 0;
4100 double
4101 sqrt(double x)
4103 return(0.0);
4105 double
4106 hw_sqrt(double x)
4108 return(0.0);
4112 * More stubs to avoid linking in libm. This works as along as we don't use
4113 * long doubles.
4115 int32_t
4116 __fpclassifyd(double x)
4118 return(0);
4120 int32_t
4121 __fpclassify(long double x)
4123 return(0);
4125 #endif /* !defined(__DYNAMIC__) */
4127 #endif /* !defined(LLVM_OTOOL) */