1/*
2 * Copyright © 2009 Apple Inc. All rights reserved.
3 *
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.
17 *
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.
28 *
29 * @APPLE_LICENSE_HEADER_END@
30 */
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 "otool.h"
46#include "ofile_print.h"
47#include "m68k_disasm.h"
48#include "i860_disasm.h"
49#include "i386_disasm.h"
50#include "m88k_disasm.h"
51#include "ppc_disasm.h"
52#include "hppa_disasm.h"
53#include "sparc_disasm.h"
54#include "arm_disasm.h"
55#include "llvm-c/Disassembler.h"
56
57/* Name of this program for error messages (argv[0]) */
58char *progname = NULL;
59
60/*
61 * The flags to indicate the actions to perform.
62 */
63enum bool fflag = FALSE; /* print the fat headers */
64enum bool aflag = FALSE; /* print the archive header */
65enum bool hflag = FALSE; /* print the exec or mach header */
66enum bool lflag = FALSE; /* print the load commands */
67enum bool Lflag = FALSE; /* print the shared library names */
68enum bool Dflag = FALSE; /* print the shared library id name */
69enum bool tflag = FALSE; /* print the text */
70enum bool dflag = FALSE; /* print the data */
71enum bool oflag = FALSE; /* print the objctive-C info */
72enum bool Oflag = FALSE; /* print the objctive-C selector strings only */
73enum bool rflag = FALSE; /* print the relocation entries */
74enum bool Tflag = FALSE; /* print the dylib table of contents */
75enum bool Mflag = FALSE; /* print the dylib module table */
76enum bool Rflag = FALSE; /* print the dylib reference table */
77enum bool Iflag = FALSE; /* print the indirect symbol table entries */
78enum bool Hflag = FALSE; /* print the two-level hints table */
79enum bool Gflag = FALSE; /* print the data in code table */
80enum bool gflag = FALSE; /* group the disassembly */
81enum bool eflag = FALSE; /* print enhanced disassembly */
82enum bool Sflag = FALSE; /* print the contents of the __.SYMDEF file */
83enum bool vflag = FALSE; /* print verbosely (symbolically) when possible */
84enum bool Vflag = FALSE; /* print dissassembled operands verbosely */
85enum bool cflag = FALSE; /* print the argument and environ strings of a core */
86enum bool iflag = FALSE; /* print the shared library initialization table */
87enum bool Wflag = FALSE; /* print the mod time of an archive as a number */
88enum bool Xflag = FALSE; /* don't print leading address in disassembly */
89enum bool Zflag = FALSE; /* don't use simplified ppc mnemonics in disassembly */
90enum bool Bflag = FALSE; /* force Thumb disassembly (ARM objects only) */
91enum bool Qflag = FALSE; /* use otool's disassembler */
92enum bool qflag = FALSE; /* use 'C' Public llvm-mc disassembler */
93enum bool jflag = FALSE; /* print opcode bytes */
94enum bool nflag = FALSE; /* use intel disassembly syntax */
95char *pflag = NULL; 	 /* procedure name to start disassembling from */
96char *segname = NULL;	 /* name of the section to print the contents of */
97char *sectname = NULL;
98enum bool llvm_mc = FALSE; /* disassemble as llvm-mc will assemble */
99char *mcpu = "";	/* the arg of the -mcpu=arg flag */
100
101/* this is set when any of the flags that process object files is set */
102enum bool object_processing = FALSE;
103
104static void usage(
105    void);
106
107static void processor(
108    struct ofile *ofile,
109    char *arch_name,
110    void *cookie);
111
112static void get_symbol_table_info(
113    struct load_command *load_commands,
114    uint32_t ncmds,
115    uint32_t sizeofcmds,
116    cpu_type_t cputype,
117    enum byte_sex load_commands_byte_sex,
118    char *object_addr,
119    uint32_t object_size,
120    struct nlist **symbols,
121    struct nlist_64 **symbols64,
122    uint32_t *nsymbols,
123    char **strings,
124    uint32_t *strings_size);
125
126static void get_toc_info(
127    struct load_command *load_commands,
128    uint32_t ncmds,
129    uint32_t sizeofcmds,
130    enum byte_sex load_commands_byte_sex,
131    char *object_addr,
132    uint32_t object_size,
133    struct dylib_table_of_contents **tocs,
134    uint32_t *ntocs);
135
136static void get_module_table_info(
137    struct load_command *load_commands,
138    uint32_t ncmds,
139    uint32_t sizeofcmds,
140    cpu_type_t cputype,
141    enum byte_sex load_commands_byte_sex,
142    char *object_addr,
143    uint32_t object_size,
144    struct dylib_module **mods,
145    struct dylib_module_64 **mods64,
146    uint32_t *nmods);
147
148static void get_ref_info(
149    struct load_command *load_commands,
150    uint32_t ncmds,
151    uint32_t sizeofcmds,
152    enum byte_sex load_commands_byte_sex,
153    char *object_addr,
154    uint32_t object_size,
155    struct dylib_reference **refs,
156    uint32_t *nrefs);
157
158static void get_indirect_symbol_table_info(
159    struct load_command *load_commands,
160    uint32_t ncmds,
161    uint32_t sizeofcmds,
162    enum byte_sex load_commands_byte_sex,
163    char *object_addr,
164    uint32_t object_size,
165    uint32_t **indirect_symbols,
166    uint32_t *nindirect_symbols);
167
168static enum bool get_dyst(
169    struct load_command *load_commands,
170    uint32_t ncmds,
171    uint32_t sizeofcmds,
172    enum byte_sex load_commands_byte_sex,
173    struct dysymtab_command *dyst);
174
175static void get_hints_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    struct twolevel_hint **hints,
183    uint32_t *nhints);
184
185static enum bool get_hints_cmd(
186    struct load_command *load_commands,
187    uint32_t ncmds,
188    uint32_t sizeofcmds,
189    enum byte_sex load_commands_byte_sex,
190    struct twolevel_hints_command *hints_cmd);
191
192static void get_data_in_code_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 data_in_code_entry **dices,
200    uint32_t *ndices);
201
202static enum bool get_dices_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 linkedit_data_command *dices_cmd);
208
209static int sym_compare(
210    struct symbol *sym1,
211    struct symbol *sym2);
212
213static int rel_compare(
214    struct relocation_info *rel1,
215    struct relocation_info *rel2);
216
217static void get_linked_reloc_info(
218    struct load_command *load_commands,
219    uint32_t ncmds,
220    uint32_t sizeofcmds,
221    enum byte_sex load_commands_byte_sex,
222    char *object_addr,
223    uint32_t object_size,
224    struct relocation_info **ext_relocs,
225    uint32_t *next_relocs,
226    struct relocation_info **loc_relocs,
227    uint32_t *nloc_relocs);
228
229static void print_text(
230    cpu_type_t cputype,
231    enum byte_sex object_byte_sex,
232    char *sect,
233    uint32_t size,
234    uint64_t addr,
235    uint32_t sect_flags,
236    struct symbol *sorted_symbols,
237    uint32_t nsorted_symbols,
238    struct nlist *symbols,
239    struct nlist_64 *symbols64,
240    uint32_t nsymbols,
241    char *strings,
242    uint32_t strings_size,
243    struct relocation_info *relocs,
244    uint32_t nrelocs,
245    uint32_t *indirect_symbols,
246    uint32_t nindirect_symbols,
247    struct load_command *load_commands,
248    uint32_t ncmds,
249    uint32_t sizeofcmds,
250    enum bool disassemble,
251    enum bool verbose,
252    cpu_subtype_t cpusubtype,
253    char *object_addr,
254    uint32_t object_size,
255    struct data_in_code_entry *dices,
256    uint32_t ndices,
257    uint64_t seg_addr,
258    uint32_t filetype);
259
260static void print_argstrings(
261    uint32_t magic,
262    struct load_command *load_commands,
263    uint32_t ncmds,
264    uint32_t sizeofcmds,
265    cpu_type_t cputype,
266    cpu_subtype_t cpusubtype,
267    enum byte_sex load_commands_byte_sex,
268    char *object_addr,
269    uint32_t object_size);
270
271/* apple_version is created by the libstuff/Makefile */
272extern char apple_version[];
273char *version = apple_version;
274
275int
276main(
277int argc,
278char **argv,
279char **envp)
280{
281    int i;
282    uint32_t j, nfiles;
283    struct arch_flag *arch_flags;
284    uint32_t narch_flags;
285    enum bool all_archs, use_member_syntax;
286    char **files;
287
288	progname = argv[0];
289	arch_flags = NULL;
290	narch_flags = 0;
291	all_archs = FALSE;
292	use_member_syntax = TRUE;
293	llvm_mc = FALSE;
294
295	if(argc <= 1)
296	    usage();
297
298	/*
299	 * Parse the arguments.
300	 */
301	nfiles = 0;
302        files = allocate(sizeof(char *) * argc);
303	for(i = 1; i < argc; i++){
304	    if(argv[i][0] == '-' && argv[i][1] == '\0'){
305		for(i += 1 ; i < argc; i++)
306		    files[nfiles++] = argv[i];
307		break;
308	    }
309	    if(argv[i][0] != '-'){
310		files[nfiles++] = argv[i];
311		continue;
312	    }
313	    if(strcmp(argv[i], "-arch") == 0){
314		if(i + 1 == argc){
315		    error("missing argument(s) to %s option", argv[i]);
316		    usage();
317		}
318		if(strcmp("all", argv[i+1]) == 0){
319		    all_archs = TRUE;
320		}
321		else{
322		    arch_flags = reallocate(arch_flags,
323			    (narch_flags + 1) * sizeof(struct arch_flag));
324		    if(get_arch_from_flag(argv[i+1],
325					  arch_flags + narch_flags) == 0){
326			error("unknown architecture specification flag: "
327			      "%s %s", argv[i], argv[i+1]);
328			arch_usage();
329			usage();
330		    }
331		    narch_flags++;
332		}
333		i++;
334		continue;
335	    }
336	    if(strcmp(argv[i], "-llvm-mc") == 0){
337		llvm_mc = TRUE;
338		continue;
339	    }
340	    if(strncmp(argv[i], "-mcpu=", sizeof("-mcpu=")-1) == 0){
341		mcpu = argv[i] + sizeof("-mcpu=")-1;
342		if(*mcpu == '\0'){
343		    error("missing argument to -mcpu=");
344		    usage();
345		}
346		continue;
347	    }
348	    if(argv[i][1] == 'p'){
349		if(argc <=  i + 1){
350		    error("-p requires an argument (a text symbol name)");
351		    usage();
352		}
353		if(pflag)
354		    error("only one -p flag can be specified");
355		pflag = argv[i + 1];
356		i++;
357		continue;
358	    }
359	    if(argv[i][1] == 's'){
360		if(argc <=  i + 2){
361		    error("-s requires two arguments (a segment name and a "
362			  "section name)");
363		    usage();
364		}
365		if(sectname != NULL){
366		    error("only one -s flag can be specified");
367		    usage();
368		}
369		segname  = argv[i + 1];
370		sectname = argv[i + 2];
371		i += 2;
372		object_processing = TRUE;
373		continue;
374	    }
375	    for(j = 1; argv[i][j] != '\0'; j++){
376		switch(argv[i][j]){
377		case 'V':
378		    Vflag = TRUE;
379		case 'v':
380		    vflag = TRUE;
381		    break;
382		case 'f':
383		    fflag = TRUE;
384		    break;
385		case 'a':
386		    aflag = TRUE;
387		    break;
388		case 'g':
389		    gflag = TRUE;
390		    break;
391		case 'e':
392		    eflag = TRUE;
393		    break;
394		case 'n':
395		    nflag = TRUE;
396		    break;
397		case 'h':
398		    hflag = TRUE;
399		    object_processing = TRUE;
400		    break;
401		case 'l':
402		    lflag = TRUE;
403		    object_processing = TRUE;
404		    break;
405		case 'L':
406		    Lflag = TRUE;
407		    object_processing = TRUE;
408		    break;
409		case 'D':
410		    Dflag = TRUE;
411		    object_processing = TRUE;
412		    break;
413		case 't':
414		    tflag = TRUE;
415		    object_processing = TRUE;
416		    break;
417		case 'd':
418		    dflag = TRUE;
419		    object_processing = TRUE;
420		    break;
421		case 'o':
422		    oflag = TRUE;
423		    object_processing = TRUE;
424		    break;
425		case 'O':
426		    Oflag = TRUE;
427		    object_processing = TRUE;
428		    break;
429		case 'r':
430		    rflag = TRUE;
431		    object_processing = TRUE;
432		    break;
433		case 'T':
434		    Tflag = TRUE;
435		    object_processing = TRUE;
436		    break;
437		case 'M':
438		    Mflag = TRUE;
439		    object_processing = TRUE;
440		    break;
441		case 'R':
442		    Rflag = TRUE;
443		    object_processing = TRUE;
444		    break;
445		case 'I':
446		    Iflag = TRUE;
447		    object_processing = TRUE;
448		    break;
449		case 'H':
450		    Hflag = TRUE;
451		    object_processing = TRUE;
452		    break;
453		case 'G':
454		    Gflag = TRUE;
455		    object_processing = TRUE;
456		    break;
457		case 'S':
458		    Sflag = TRUE;
459		    break;
460		case 'c':
461		    cflag = TRUE;
462		    object_processing = TRUE;
463		    break;
464		case 'i':
465		    iflag = TRUE;
466		    object_processing = TRUE;
467		    break;
468		case 'W':
469		    Wflag = TRUE;
470		    break;
471		case 'X':
472		    Xflag = TRUE;
473		    break;
474		case 'Z':
475		    Zflag = TRUE;
476		    break;
477		case 'm':
478		    use_member_syntax = FALSE;
479		    break;
480		case 'B':
481		    Bflag = TRUE;
482		    break;
483		case 'Q':
484		    Qflag = TRUE;
485		    break;
486		case 'q':
487		    qflag = TRUE;
488		    break;
489		case 'j':
490		    jflag = TRUE;
491		    break;
492		default:
493		    error("unknown char `%c' in flag %s\n", argv[i][j],argv[i]);
494		    usage();
495		}
496	    }
497	}
498
499	/*
500	 * Check for correctness of arguments.
501	 */
502	if(!fflag && !aflag && !hflag && !lflag && !Lflag && !tflag && !dflag &&
503	   !oflag && !Oflag && !rflag && !Tflag && !Mflag && !Rflag && !Iflag &&
504	   !Hflag && !Gflag && !Sflag && !cflag && !iflag && !Dflag &&!segname){
505	    error("one of -fahlLtdoOrTMRIHGScis must be specified");
506	    usage();
507	}
508	if(qflag && Qflag){
509	    error("can't specify both -q and -Q");
510	    usage();
511	}
512	/*
513	 * The default, without the -Q flag, is to use the llvm dissembler
514	 * instead of otool's internal disassemblers.
515	 */
516	if(!Qflag)
517	    qflag = TRUE;
518	if(nfiles == 0){
519	    error("at least one file must be specified");
520	    usage();
521	}
522	if(segname != NULL && sectname != NULL){
523	    /* treat "-s __TEXT __text" the same as -t */
524	    if(strcmp(segname, SEG_TEXT) == 0 &&
525	       strcmp(sectname, SECT_TEXT) == 0){
526		tflag = TRUE;
527		segname = NULL;
528		sectname = NULL;
529	    }
530	    /* treat "-s __TEXT __fvmlib0" the same as -i */
531	    else if(strcmp(segname, SEG_TEXT) == 0 &&
532	       strcmp(sectname, SECT_FVMLIB_INIT0) == 0){
533		iflag = TRUE;
534		segname = NULL;
535		sectname = NULL;
536	    }
537	}
538
539	for(j = 0; j < nfiles; j++){
540	    ofile_process(files[j], arch_flags, narch_flags, all_archs, TRUE,
541			  TRUE, use_member_syntax, processor, NULL);
542	}
543
544	if(errors)
545	    return(EXIT_FAILURE);
546	else
547	    return(EXIT_SUCCESS);
548}
549
550/*
551 * Print the current usage message.
552 */
553static
554void
555usage(
556void)
557{
558	fprintf(stderr,
559		"Usage: %s [-arch arch_type] [-fahlLDtdorSTMRIHGvVcXmqQ] "
560		"[-mcpu=arg] <object file> ...\n", progname);
561
562	fprintf(stderr, "\t-f print the fat headers\n");
563	fprintf(stderr, "\t-a print the archive header\n");
564	fprintf(stderr, "\t-h print the mach header\n");
565	fprintf(stderr, "\t-l print the load commands\n");
566	fprintf(stderr, "\t-L print shared libraries used\n");
567	fprintf(stderr, "\t-D print shared library id name\n");
568	fprintf(stderr, "\t-t print the text section (disassemble with -v)\n");
569	fprintf(stderr, "\t-p <routine name>  start dissassemble from routine "
570		"name\n");
571	fprintf(stderr, "\t-s <segname> <sectname> print contents of "
572		"section\n");
573	fprintf(stderr, "\t-d print the data section\n");
574	fprintf(stderr, "\t-o print the Objective-C segment\n");
575	fprintf(stderr, "\t-r print the relocation entries\n");
576	fprintf(stderr, "\t-S print the table of contents of a library\n");
577	fprintf(stderr, "\t-T print the table of contents of a dynamic "
578		"shared library\n");
579	fprintf(stderr, "\t-M print the module table of a dynamic shared "
580		"library\n");
581	fprintf(stderr, "\t-R print the reference table of a dynamic shared "
582		"library\n");
583	fprintf(stderr, "\t-I print the indirect symbol table\n");
584	fprintf(stderr, "\t-H print the two-level hints table\n");
585	fprintf(stderr, "\t-G print the data in code table\n");
586	fprintf(stderr, "\t-v print verbosely (symbolically) when possible\n");
587	fprintf(stderr, "\t-V print disassembled operands symbolically\n");
588	fprintf(stderr, "\t-c print argument strings of a core file\n");
589	fprintf(stderr, "\t-X print no leading addresses or headers\n");
590	fprintf(stderr, "\t-m don't use archive(member) syntax\n");
591	fprintf(stderr, "\t-B force Thumb disassembly (ARM objects only)\n");
592	fprintf(stderr, "\t-q use llvm's disassembler (the default)\n");
593	fprintf(stderr, "\t-Q use otool(1)'s disassembler\n");
594	fprintf(stderr, "\t-mcpu=arg use `arg' as the cpu for disassembly\n");
595	exit(EXIT_FAILURE);
596}
597
598static
599void
600processor(
601struct ofile *ofile,
602char *arch_name,
603void *cookie) /* cookie is not used */
604{
605    char *addr;
606    uint32_t i, magic;
607    uint64_t size;
608    struct mach_header mh;
609    struct mach_header_64 mh64;
610    cpu_type_t mh_cputype;
611    cpu_subtype_t mh_cpusubtype;
612    uint32_t mh_magic, mh_filetype, mh_ncmds, mh_sizeofcmds, sizeof_mach_header;
613    struct load_command *load_commands;
614    uint32_t nsymbols, nsorted_symbols, strings_size, len;
615    struct nlist *symbols, *allocated_symbols;
616    struct nlist_64 *symbols64, *allocated_symbols64;
617    struct symbol *sorted_symbols;
618    char *strings, *p;
619    uint32_t n_strx;
620    uint8_t n_type;
621    uint16_t n_desc;
622    uint64_t n_value;
623    char *sect;
624    uint32_t sect_nrelocs, sect_flags, nrelocs, next_relocs, nloc_relocs;
625    uint64_t sect_addr, sect_size;
626    struct relocation_info *sect_relocs, *relocs, *ext_relocs, *loc_relocs;
627    uint32_t *indirect_symbols, *allocated_indirect_symbols;
628    uint32_t nindirect_symbols;
629    struct dylib_module *mods, *allocated_mods;
630    struct dylib_module_64 *mods64, *allocated_mods64;
631    struct dylib_table_of_contents *tocs, *allocated_tocs;
632    struct dylib_reference *refs, *allocated_refs;
633    uint32_t nmods, ntocs, nrefs;
634    struct twolevel_hint *hints, *allocated_hints;
635    struct data_in_code_entry *dices, *allocated_dices;
636    uint32_t nhints, ndices;
637    uint64_t seg_addr;
638
639	sorted_symbols = NULL;
640	nsorted_symbols = 0;
641	indirect_symbols = NULL;
642	nindirect_symbols = 0;
643	hints = NULL;
644	nhints = 0;
645	dices = NULL;
646	ndices = 0;
647	symbols = NULL;
648	symbols64 = NULL;
649	nsymbols = 0;
650	strings = NULL;
651	nmods = 0;
652	mods64 = NULL;
653	mods = NULL;
654	/*
655	 * These may or may not be allocated.  If allocated they will not be
656	 * NULL and then free'ed before returning.
657	 */
658	load_commands = NULL;
659	allocated_symbols = NULL;
660	allocated_symbols64 = NULL;
661	sorted_symbols = NULL;
662	allocated_indirect_symbols = NULL;
663	allocated_tocs = NULL;
664	allocated_mods = NULL;
665	allocated_refs = NULL;
666	allocated_hints = NULL;
667	allocated_dices = NULL;
668
669	/*
670	 * The fat headers are printed in ofile_map() in ofile.c #ifdef'ed
671	 * OTOOL.
672	 */
673
674	/*
675	 * Archive headers.
676	 */
677	if(aflag && ofile->member_ar_hdr != NULL){
678	    uint32_t member_offset;
679
680	    member_offset = ofile->member_offset - sizeof(struct ar_hdr);
681	    if(strncmp(ofile->member_ar_hdr->ar_name, AR_EFMT1,
682		       sizeof(AR_EFMT1) - 1) == 0)
683		member_offset -= ofile->member_name_size;
684
685	    print_ar_hdr(ofile->member_ar_hdr, ofile->member_name,
686			 ofile->member_name_size, member_offset, vflag, Vflag);
687	}
688
689	/*
690	 * Archive table of contents.
691	 */
692	if(ofile->member_ar_hdr != NULL &&
693	   strncmp(ofile->member_name, SYMDEF, sizeof(SYMDEF)-1) == 0){
694	    if(Sflag == FALSE)
695		return;
696	    if(ofile->file_type == OFILE_FAT){
697		addr = ofile->file_addr + ofile->fat_archs[ofile->narch].offset;
698		size = ofile->fat_archs[ofile->narch].size;
699	    }
700	    else{
701		addr = ofile->file_addr;
702		size = ofile->file_size;
703	    }
704	    if(addr + size > ofile->file_addr + ofile->file_size)
705		size = (ofile->file_addr + ofile->file_size) - addr;
706	    print_library_toc(ofile->member_ar_hdr, /* toc_ar_hdr */
707			      ofile->member_name, /* toc_name */
708			      ofile->member_name_size, /* toc_name_size */
709			      ofile->member_addr, /* toc_addr */
710			      ofile->member_size, /* toc_size */
711			      get_toc_byte_sex(addr, size),
712			      ofile->file_name, /* library_name */
713			      addr, /* library_addr */
714			      size, /* library_size */
715			      arch_name,
716			      vflag);
717	    return;
718	}
719
720	if(object_processing == FALSE)
721	    return;
722
723	/*
724	 * Print header for the object name if in an archive or an architecture
725	 * name is passed in.
726	 */
727	if(Xflag == FALSE){
728	    printf("%s", ofile->file_name);
729	    if(ofile->member_ar_hdr != NULL){
730		printf("(%.*s)", (int)ofile->member_name_size,
731			ofile->member_name);
732	    }
733	    if(arch_name != NULL)
734		printf(" (architecture %s):", arch_name);
735	    else
736		printf(":");
737	    /*
738	     * If the mach_header pointer is NULL the file is not an object
739	     * file.  Truncated object file (where the file size is less
740	     * than sizeof(struct mach_header) also does not have it's
741	     * mach_header set.  So deal with both cases here and then
742	     * return as the rest of this routine deals only with things
743	     * in object files.
744	     */
745	    if(ofile->mh == NULL && ofile->mh64 == NULL){
746		if(ofile->file_type == OFILE_FAT){
747		    /*
748		     * This routine is not called on fat files where the
749		     * offset is past end of file.  An error message is
750		     * printed in ofile_specific_arch() in ofile.c.
751		     */
752		    if(ofile->arch_type == OFILE_ARCHIVE){
753			addr = ofile->member_addr;
754			size = ofile->member_size;
755		    }
756		    else{
757			addr = ofile->file_addr +
758			       ofile->fat_archs[ofile->narch].offset;
759			size = ofile->fat_archs[ofile->narch].size;
760		    }
761		    if(addr + size > ofile->file_addr + ofile->file_size)
762			size = (ofile->file_addr + ofile->file_size) - addr;
763		}
764		else if(ofile->file_type == OFILE_ARCHIVE){
765		    addr = ofile->member_addr;
766		    size = ofile->member_size;
767		}
768		else{ /* ofile->file_type == OFILE_UNKNOWN */
769		    addr = ofile->file_addr;
770		    size = ofile->file_size;
771		}
772		if(size > sizeof(int32_t)){
773		    memcpy(&magic, addr, sizeof(uint32_t));
774		    if(magic == MH_MAGIC ||
775		       magic == SWAP_INT(MH_MAGIC)){
776			printf(" is a truncated object file\n");
777			memset(&mh, '\0', sizeof(struct mach_header));
778			if(size > sizeof(struct mach_header))
779			    size = sizeof(struct mach_header);
780			memcpy(&mh, addr, size);
781			if(magic == SWAP_INT(MH_MAGIC))
782			    swap_mach_header(&mh, get_host_byte_sex());
783			if(hflag)
784			    print_mach_header(mh.magic, mh.cputype,
785				mh.cpusubtype, mh.filetype, mh.ncmds,
786				mh.sizeofcmds, mh.flags, vflag);
787			return;
788		    }
789		    else if(magic == MH_MAGIC_64 ||
790		            magic == SWAP_INT(MH_MAGIC_64)){
791			printf(" is a truncated object file\n");
792			memset(&mh64, '\0', sizeof(struct mach_header_64));
793			if(size > sizeof(struct mach_header_64))
794			    size = sizeof(struct mach_header_64);
795			memcpy(&mh64, addr, size);
796			if(magic == SWAP_INT(MH_MAGIC_64))
797			    swap_mach_header_64(&mh64, get_host_byte_sex());
798			if(hflag)
799			    print_mach_header(mh64.magic, mh64.cputype,
800				mh64.cpusubtype, mh64.filetype, mh64.ncmds,
801				mh64.sizeofcmds, mh64.flags, vflag);
802			return;
803		    }
804		}
805#ifdef LTO_SUPPORT
806		if(ofile->lto != NULL){
807		    printf(" is an LLVM bit-code file\n");
808		    return;
809		}
810#endif /* LTO_SUPPORT */
811		printf(" is not an object file\n");
812		return;
813	    }
814	}
815	if(ofile->mh != NULL){
816	    if((intptr_t)(ofile->mh) % sizeof(uint32_t)){
817		if(Xflag == FALSE)
818		    printf("(object file offset is not a multiple of sizeof("
819			   "uint32_t))");
820		memcpy(&mh, ofile->mh, sizeof(struct mach_header));
821		if(mh.magic == SWAP_INT(MH_MAGIC))
822		    swap_mach_header(&mh, get_host_byte_sex());
823		ofile->mh = &mh;
824	    }
825	    else if(ofile->mh->magic == SWAP_INT(MH_MAGIC)){
826		mh = *(ofile->mh);
827		swap_mach_header(&mh, get_host_byte_sex());
828		ofile->mh = &mh;
829	    }
830	}
831	else if(ofile->mh64 != NULL){
832	    if((intptr_t)(ofile->mh64) % sizeof(uint32_t)){
833		if(Xflag == FALSE)
834		    printf("(object file offset is not a multiple of sizeof("
835			   "uint32_t))");
836		memcpy(&mh64, ofile->mh64, sizeof(struct mach_header));
837		if(mh64.magic == SWAP_INT(MH_MAGIC_64))
838		    swap_mach_header_64(&mh64, get_host_byte_sex());
839		ofile->mh64 = &mh64;
840	    }
841	    else if(ofile->mh64->magic == SWAP_INT(MH_MAGIC_64)){
842		mh64 = *(ofile->mh64);
843		swap_mach_header_64(&mh64, get_host_byte_sex());
844		ofile->mh64 = &mh64;
845	    }
846	}
847	if(Xflag == FALSE)
848	    printf("\n");
849
850	/*
851	 * If this is not an object file then just return.
852	 */
853	if(ofile->mh == NULL && ofile->mh64 == NULL)
854	    return;
855
856	/*
857	 * Calculate the true number of bytes of the of the object file that
858	 * is in memory (in case this file is truncated).
859	 */
860	addr = ofile->object_addr;
861	size = ofile->object_size;
862	if(addr + size > ofile->file_addr + ofile->file_size)
863	    size = (ofile->file_addr + ofile->file_size) - addr;
864
865	/*
866	 * Assign some local variables to the values in the mach_header for this
867	 * ofile to make passing arguments to the print routines easier.
868	 */
869	if(ofile->mh != NULL){
870	    mh_magic = ofile->mh->magic;
871	    mh_cputype = ofile->mh->cputype;
872	    mh_cpusubtype = ofile->mh->cpusubtype;
873	    mh_filetype = ofile->mh->filetype;
874	    mh_ncmds = ofile->mh->ncmds;
875	    mh_sizeofcmds = ofile->mh->sizeofcmds;
876	    sizeof_mach_header = sizeof(struct mach_header);
877	}
878	else{
879	    mh_magic = ofile->mh64->magic;
880	    mh_cputype = ofile->mh64->cputype;
881	    mh_cpusubtype = ofile->mh64->cpusubtype;
882	    mh_filetype = ofile->mh64->filetype;
883	    mh_ncmds = ofile->mh64->ncmds;
884	    mh_sizeofcmds = ofile->mh64->sizeofcmds;
885	    sizeof_mach_header = sizeof(struct mach_header_64);
886	}
887
888	/*
889	 * Mach header.
890	 */
891	if(hflag){
892	    if(ofile->mh != NULL)
893		print_mach_header(ofile->mh->magic, ofile->mh->cputype,
894				  ofile->mh->cpusubtype, ofile->mh->filetype,
895				  ofile->mh->ncmds, ofile->mh->sizeofcmds,
896				  ofile->mh->flags, vflag);
897	    else
898		print_mach_header(ofile->mh64->magic, ofile->mh64->cputype,
899				  ofile->mh64->cpusubtype,ofile->mh64->filetype,
900				  ofile->mh64->ncmds, ofile->mh64->sizeofcmds,
901				  ofile->mh64->flags, vflag);
902	}
903
904	/*
905	 * Load commands.
906	 */
907	if(mh_sizeofcmds + sizeof_mach_header > size){
908	    load_commands = allocate(mh_sizeofcmds);
909	    memset(load_commands, '\0', mh_sizeofcmds);
910	    memcpy(load_commands, ofile->load_commands,
911		   size - sizeof_mach_header);
912	    ofile->load_commands = load_commands;
913	}
914	if(lflag)
915	    print_loadcmds(ofile->load_commands, mh_ncmds, mh_sizeofcmds,
916			   mh_cputype, mh_filetype, ofile->object_byte_sex,
917			   size, vflag, Vflag);
918
919	if(Lflag || Dflag)
920	    print_libraries(ofile->load_commands, mh_ncmds, mh_sizeofcmds,
921			    ofile->object_byte_sex, (Dflag && !Lflag), vflag);
922
923	/*
924	 * If the indicated operation needs the symbol table get it.
925	 */
926	sect_flags = 0;
927	if(segname != NULL && sectname != NULL){
928	    (void)get_sect_info(segname, sectname, ofile->load_commands,
929			mh_ncmds, mh_sizeofcmds, mh_filetype,
930			ofile->object_byte_sex,
931			addr, size, &sect, &sect_size, &sect_addr,
932			&sect_relocs, &sect_nrelocs, &sect_flags, &seg_addr);
933	    /*
934	     * The MH_DYLIB_STUB format has all section sizes set to zero
935	     * except sections with indirect symbol table entries (so that the
936	     * indirect symbol table table entries can be printed, which are
937	     * based on the section size).  So if we are being asked to print
938	     * the section contents of one of these sections in a MH_DYLIB_STUB
939	     * we assume it has been stripped and set the section size to zero.
940	     */
941	    if(mh_filetype == MH_DYLIB_STUB &&
942	       ((sect_flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ||
943	        (sect_flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ||
944		(sect_flags & SECTION_TYPE) == S_LAZY_DYLIB_SYMBOL_POINTERS ||
945	        (sect_flags & SECTION_TYPE) == S_SYMBOL_STUBS))
946		sect_size = 0;
947	}
948	if(Rflag || Mflag)
949	    get_symbol_table_info(ofile->load_commands, mh_ncmds, mh_sizeofcmds,
950		mh_cputype, ofile->object_byte_sex, addr, size, &symbols,
951		&symbols64, &nsymbols, &strings, &strings_size);
952	if(vflag && (rflag || Tflag || Mflag || Rflag || Iflag || Hflag || tflag
953	   || iflag || oflag ||
954	   (sect_flags & SECTION_TYPE) == S_LITERAL_POINTERS ||
955	   (sect_flags & SECTION_TYPE) == S_MOD_INIT_FUNC_POINTERS ||
956	   (sect_flags & SECTION_TYPE) == S_MOD_TERM_FUNC_POINTERS ||
957	   (sect_flags & S_ATTR_PURE_INSTRUCTIONS) ==
958		S_ATTR_PURE_INSTRUCTIONS ||
959	   (sect_flags & S_ATTR_SOME_INSTRUCTIONS) ==
960		S_ATTR_SOME_INSTRUCTIONS ||
961	   segname != NULL)){
962	    get_symbol_table_info(ofile->load_commands, mh_ncmds, mh_sizeofcmds,
963	        mh_cputype, ofile->object_byte_sex, addr, size, &symbols,
964		&symbols64, &nsymbols, &strings, &strings_size);
965
966	    if(symbols != NULL){
967		if((uintptr_t)symbols % sizeof(uint32_t) ||
968		   ofile->object_byte_sex != get_host_byte_sex()){
969		    allocated_symbols =
970			allocate(nsymbols * sizeof(struct nlist));
971		    memcpy(allocated_symbols, symbols,
972			   nsymbols * sizeof(struct nlist));
973		    symbols = allocated_symbols;
974		}
975		if(ofile->object_byte_sex != get_host_byte_sex())
976		    swap_nlist(symbols, nsymbols, get_host_byte_sex());
977	    }
978	    else{
979		if((uintptr_t)symbols64 % sizeof(uint32_t) ||
980		   ofile->object_byte_sex != get_host_byte_sex()){
981		    allocated_symbols64 =
982			allocate(nsymbols * sizeof(struct nlist_64));
983		    memcpy(allocated_symbols64, symbols64,
984			   nsymbols * sizeof(struct nlist_64));
985		    symbols64 = allocated_symbols64;
986		}
987		if(ofile->object_byte_sex != get_host_byte_sex())
988		    swap_nlist_64(symbols64, nsymbols, get_host_byte_sex());
989	    }
990
991	    /*
992	     * If the operation needs a sorted symbol table create it.
993	     */
994	    if(tflag || iflag || oflag ||
995	       (((sect_flags & SECTION_TYPE) == S_MOD_INIT_FUNC_POINTERS ||
996	         (sect_flags & SECTION_TYPE) == S_MOD_TERM_FUNC_POINTERS) &&
997		  Vflag) ||
998	       (sect_flags & S_ATTR_PURE_INSTRUCTIONS) ==
999		    S_ATTR_PURE_INSTRUCTIONS ||
1000	       (sect_flags & S_ATTR_SOME_INSTRUCTIONS) ==
1001		    S_ATTR_SOME_INSTRUCTIONS){
1002		sorted_symbols = allocate(nsymbols * sizeof(struct symbol));
1003		nsorted_symbols = 0;
1004		for(i = 0; i < nsymbols; i++){
1005		    if(symbols != NULL){
1006			n_strx = symbols[i].n_un.n_strx;
1007			n_type = symbols[i].n_type;
1008			n_desc = symbols[i].n_desc;
1009			n_value = symbols[i].n_value;
1010		    }
1011		    else{
1012			n_strx = symbols64[i].n_un.n_strx;
1013			n_type = symbols64[i].n_type;
1014			n_desc = symbols64[i].n_desc;
1015			n_value = symbols64[i].n_value;
1016		    }
1017		    if(n_strx > 0 && n_strx < strings_size)
1018			p = strings + n_strx;
1019		    else
1020			p = "symbol with bad string index";
1021		    if(n_type & ~(N_TYPE|N_EXT|N_PEXT))
1022			continue;
1023		    n_type = n_type & N_TYPE;
1024		    if(n_type == N_ABS || n_type == N_SECT){
1025			len = strlen(p);
1026			if(len > sizeof(".o") - 1 &&
1027			   strcmp(p + (len - (sizeof(".o") - 1)), ".o") == 0)
1028			    continue;
1029			if(strcmp(p, "gcc_compiled.") == 0)
1030			    continue;
1031			if(strcmp(p, "ltmp0") == 0)
1032			    continue;
1033			if(n_type == N_ABS && n_value == 0 && *p == '.')
1034			    continue;
1035			sorted_symbols[nsorted_symbols].n_value = n_value;
1036			sorted_symbols[nsorted_symbols].name = p;
1037			sorted_symbols[nsorted_symbols].is_thumb =
1038			    n_desc & N_ARM_THUMB_DEF;
1039			nsorted_symbols++;
1040		    }
1041		}
1042		qsort(sorted_symbols, nsorted_symbols, sizeof(struct symbol),
1043		      (int (*)(const void *, const void *))sym_compare);
1044	    }
1045	}
1046
1047	if(Mflag || Tflag || Rflag){
1048	    get_module_table_info(ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1049		mh_cputype, ofile->object_byte_sex, addr, size, &mods, &mods64,
1050		&nmods);
1051	    if(mods != NULL){
1052		if((intptr_t)mods % sizeof(uint32_t) ||
1053		   ofile->object_byte_sex != get_host_byte_sex()){
1054		    allocated_mods = allocate(nmods *
1055					      sizeof(struct dylib_module));
1056		    memcpy(allocated_mods, mods,
1057			   nmods * sizeof(struct dylib_module));
1058		    mods = allocated_mods;
1059		}
1060		if(ofile->object_byte_sex != get_host_byte_sex())
1061		    swap_dylib_module(mods, nmods, get_host_byte_sex());
1062	    }
1063	    if(mods64 != NULL){
1064		if((intptr_t)mods64 % sizeof(uint64_t) ||
1065		   ofile->object_byte_sex != get_host_byte_sex()){
1066		    allocated_mods64 = allocate(nmods *
1067					        sizeof(struct dylib_module_64));
1068		    memcpy(allocated_mods64, mods64,
1069			   nmods * sizeof(struct dylib_module_64));
1070		    mods64 = allocated_mods64;
1071		}
1072		if(ofile->object_byte_sex != get_host_byte_sex())
1073		    swap_dylib_module_64(mods64, nmods, get_host_byte_sex());
1074	    }
1075	}
1076
1077	if(Tflag){
1078	    get_toc_info(ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1079		ofile->object_byte_sex, addr, size, &tocs, &ntocs);
1080	    if((intptr_t)tocs % sizeof(uint32_t) ||
1081	       ofile->object_byte_sex != get_host_byte_sex()){
1082		allocated_tocs = allocate(ntocs *
1083					sizeof(struct dylib_table_of_contents));
1084		memcpy(allocated_tocs, tocs,
1085		       ntocs * sizeof(struct dylib_table_of_contents));
1086		tocs = allocated_tocs;
1087	    }
1088	    if(ofile->object_byte_sex != get_host_byte_sex())
1089		swap_dylib_table_of_contents(tocs, ntocs, get_host_byte_sex());
1090	    print_toc(ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1091		ofile->object_byte_sex, addr, size, tocs, ntocs, mods, mods64,
1092		nmods, symbols, symbols64, nsymbols, strings, strings_size,
1093		vflag);
1094	}
1095
1096	if(Mflag){
1097	    if(mods != NULL)
1098		print_module_table(mods, nmods, strings, strings_size, vflag);
1099	    else
1100		print_module_table_64(mods64, nmods, strings, strings_size,
1101				      vflag);
1102	}
1103
1104	if(Rflag){
1105	    get_ref_info(ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1106		ofile->object_byte_sex, addr, size, &refs, &nrefs);
1107	    if((intptr_t)refs % sizeof(uint32_t) ||
1108	       ofile->object_byte_sex != get_host_byte_sex()){
1109		allocated_refs = allocate(nrefs *
1110					sizeof(struct dylib_reference));
1111		memcpy(allocated_refs, refs,
1112		       nrefs * sizeof(struct dylib_reference));
1113		refs = allocated_refs;
1114	    }
1115	    if(ofile->object_byte_sex != get_host_byte_sex())
1116		swap_dylib_reference(refs, nrefs, get_host_byte_sex());
1117	    print_refs(refs, nrefs, mods, mods64, nmods, symbols, symbols64,
1118		       nsymbols, strings, strings_size, vflag);
1119	}
1120
1121	if(Iflag || (tflag && vflag)){
1122	    get_indirect_symbol_table_info(ofile->load_commands, mh_ncmds,
1123		mh_sizeofcmds, ofile->object_byte_sex, addr, size,
1124		&indirect_symbols, &nindirect_symbols);
1125	    if((intptr_t)indirect_symbols % sizeof(uint32_t) ||
1126	       ofile->object_byte_sex != get_host_byte_sex()){
1127		allocated_indirect_symbols = allocate(nindirect_symbols *
1128						     sizeof(uint32_t));
1129		memcpy(allocated_indirect_symbols, indirect_symbols,
1130		       nindirect_symbols * sizeof(uint32_t));
1131		indirect_symbols = allocated_indirect_symbols;
1132	    }
1133	    if(ofile->object_byte_sex != get_host_byte_sex())
1134		swap_indirect_symbols(indirect_symbols, nindirect_symbols,
1135				      get_host_byte_sex());
1136	}
1137	if(Hflag){
1138	    get_hints_table_info(ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1139		ofile->object_byte_sex, addr, size, &hints, &nhints);
1140	    if((intptr_t)hints % sizeof(uint32_t) ||
1141	       ofile->object_byte_sex != get_host_byte_sex()){
1142		allocated_hints = allocate(nhints *
1143					   sizeof(struct twolevel_hint));
1144		memcpy(allocated_hints, hints,
1145		       nhints * sizeof(struct twolevel_hint));
1146		hints = allocated_hints;
1147	    }
1148	    if(ofile->object_byte_sex != get_host_byte_sex())
1149		swap_twolevel_hint(hints, nhints, get_host_byte_sex());
1150	    print_hints(ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1151		ofile->object_byte_sex, hints, nhints, symbols, symbols64,
1152		nsymbols, strings, strings_size, vflag);
1153	}
1154	if(Gflag || (tflag && vflag)){
1155	    get_data_in_code_info(ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1156		ofile->object_byte_sex, addr, size, &dices, &ndices);
1157	    if((intptr_t)dices % sizeof(uint32_t) ||
1158	       ofile->object_byte_sex != get_host_byte_sex()){
1159		allocated_dices = allocate(ndices *
1160					   sizeof(struct data_in_code_entry));
1161		memcpy(allocated_dices, dices,
1162		       ndices * sizeof(struct data_in_code_entry));
1163		dices = allocated_dices;
1164	    }
1165	    if(ofile->object_byte_sex != get_host_byte_sex())
1166		swap_data_in_code_entry(dices, ndices, get_host_byte_sex());
1167	    if(Gflag)
1168		print_dices(dices, ndices, vflag);
1169	}
1170	if(Iflag)
1171	    print_indirect_symbols(ofile->load_commands, mh_ncmds,mh_sizeofcmds,
1172		mh_cputype, ofile->object_byte_sex, indirect_symbols,
1173		nindirect_symbols, symbols, symbols64, nsymbols, strings,
1174		strings_size, vflag);
1175
1176	if(rflag)
1177	    print_reloc(ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1178			mh_cputype, ofile->object_byte_sex, addr, size, symbols,
1179		        symbols64, nsymbols, strings, strings_size, vflag);
1180
1181	if(tflag ||
1182	   (sect_flags & S_ATTR_PURE_INSTRUCTIONS) ==
1183		S_ATTR_PURE_INSTRUCTIONS ||
1184	   (sect_flags & S_ATTR_SOME_INSTRUCTIONS) ==
1185		S_ATTR_SOME_INSTRUCTIONS){
1186	    if(tflag)
1187		(void)get_sect_info(SEG_TEXT, SECT_TEXT, ofile->load_commands,
1188		    mh_ncmds, mh_sizeofcmds, mh_filetype,
1189		    ofile->object_byte_sex,
1190		    addr, size, &sect, &sect_size, &sect_addr,
1191		    &sect_relocs, &sect_nrelocs, &sect_flags, &seg_addr);
1192
1193	    /* create aligned relocations entries as needed */
1194	    relocs = NULL;
1195	    nrelocs = 0;
1196	    if(Vflag){
1197		if(mh_filetype != MH_KEXT_BUNDLE){
1198		    if((intptr_t)sect_relocs % sizeof(int32_t) != 0 ||
1199		       ofile->object_byte_sex != get_host_byte_sex()){
1200			nrelocs = sect_nrelocs;
1201			relocs = allocate(nrelocs *
1202					  sizeof(struct relocation_info));
1203			memcpy(relocs, sect_relocs, nrelocs *
1204			       sizeof(struct relocation_info));
1205		    }
1206		    else{
1207			nrelocs = sect_nrelocs;
1208			relocs = sect_relocs;
1209		    }
1210		}
1211		else{
1212		    get_linked_reloc_info(ofile->load_commands, mh_ncmds,
1213			    mh_sizeofcmds, ofile->object_byte_sex,
1214			    ofile->object_addr, ofile->object_size, &ext_relocs,
1215			    &next_relocs, &loc_relocs, &nloc_relocs);
1216		    if((intptr_t)ext_relocs % sizeof(int32_t) != 0 ||
1217		       ofile->object_byte_sex != get_host_byte_sex()){
1218			nrelocs = next_relocs;
1219			relocs = allocate(next_relocs *
1220					  sizeof(struct relocation_info));
1221			memcpy(relocs, ext_relocs, next_relocs *
1222				sizeof(struct relocation_info));
1223		    }
1224		    else{
1225			nrelocs = next_relocs;
1226			relocs = ext_relocs;
1227		    }
1228		}
1229		if(ofile->object_byte_sex != get_host_byte_sex())
1230		    swap_relocation_info(relocs, nrelocs,
1231					 get_host_byte_sex());
1232	    }
1233	    if(Xflag == FALSE){
1234		if(tflag)
1235		    printf("(%s,%s) section\n", SEG_TEXT, SECT_TEXT);
1236		else
1237		    printf("Contents of (%.16s,%.16s) section\n", segname,
1238			   sectname);
1239	    }
1240	    print_text(mh_cputype, ofile->object_byte_sex, sect, sect_size,
1241		       sect_addr, sect_flags, sorted_symbols,
1242		       nsorted_symbols, symbols, symbols64, nsymbols, strings,
1243		       strings_size, relocs, nrelocs, indirect_symbols,
1244		       nindirect_symbols, ofile->load_commands, mh_ncmds,
1245		       mh_sizeofcmds, vflag, Vflag, mh_cpusubtype,
1246		       ofile->object_addr, ofile->object_size, dices, ndices,
1247                       seg_addr, mh_filetype);
1248
1249	    if(mh_filetype != MH_KEXT_BUNDLE){
1250		if(relocs != NULL && relocs != sect_relocs)
1251		    free(relocs);
1252	    } else {
1253		if(relocs != NULL && relocs != ext_relocs)
1254		    free(relocs);
1255	    }
1256	}
1257
1258	if(iflag){
1259	    if(get_sect_info(SEG_TEXT, SECT_FVMLIB_INIT0, ofile->load_commands,
1260		mh_ncmds, mh_sizeofcmds, mh_filetype, ofile->object_byte_sex,
1261		addr, size, &sect, &sect_size, &sect_addr,
1262		&sect_relocs, &sect_nrelocs, &sect_flags, &seg_addr) == TRUE){
1263
1264		/* create aligned, sorted relocations entries */
1265		nrelocs = sect_nrelocs;
1266		relocs = allocate(nrelocs * sizeof(struct relocation_info));
1267		memcpy(relocs, sect_relocs, nrelocs *
1268		       sizeof(struct relocation_info));
1269		if(ofile->object_byte_sex != get_host_byte_sex())
1270		    swap_relocation_info(relocs, nrelocs, get_host_byte_sex());
1271		qsort(relocs, nrelocs, sizeof(struct relocation_info),
1272		      (int (*)(const void *, const void *))rel_compare);
1273
1274		if(Xflag == FALSE)
1275		    printf("Shared library initialization (%s,%s) section\n",
1276			   SEG_TEXT, SECT_FVMLIB_INIT0);
1277		print_shlib_init(ofile->object_byte_sex, sect, sect_size,
1278			sect_addr, sorted_symbols, nsorted_symbols, symbols,
1279			symbols64, nsymbols, strings, strings_size, relocs,
1280			nrelocs, vflag);
1281		free(relocs);
1282	    }
1283	}
1284
1285	if(dflag){
1286	    if(get_sect_info(SEG_DATA, SECT_DATA, ofile->load_commands,
1287		mh_ncmds, mh_sizeofcmds, mh_filetype, ofile->object_byte_sex,
1288		addr, size, &sect, &sect_size, &sect_addr,
1289		&sect_relocs, &sect_nrelocs, &sect_flags, &seg_addr) == TRUE){
1290
1291		if(Xflag == FALSE)
1292		    printf("(%s,%s) section\n", SEG_DATA, SECT_DATA);
1293		print_sect(mh_cputype, ofile->object_byte_sex, sect, sect_size,
1294			   sect_addr);
1295	    }
1296	}
1297
1298	if(segname != NULL && sectname != NULL &&
1299	   (sect_flags & S_ATTR_PURE_INSTRUCTIONS) !=
1300		S_ATTR_PURE_INSTRUCTIONS &&
1301	   (sect_flags & S_ATTR_SOME_INSTRUCTIONS) !=
1302		S_ATTR_SOME_INSTRUCTIONS){
1303	    if(strcmp(segname, SEG_OBJC) == 0 &&
1304	       strcmp(sectname, "__protocol") == 0 && vflag == TRUE){
1305		print_objc_protocol_section(ofile->load_commands, mh_ncmds,
1306		   mh_sizeofcmds, ofile->object_byte_sex, ofile->object_addr,
1307		   ofile->object_size, vflag);
1308	    }
1309	    else if(strcmp(segname, SEG_OBJC) == 0 &&
1310	            (strcmp(sectname, "__string_object") == 0 ||
1311	             strcmp(sectname, "__cstring_object") == 0) &&
1312		    vflag == TRUE){
1313		if(mh_cputype & CPU_ARCH_ABI64)
1314		    print_objc_string_object_section_64(sectname,
1315			ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1316			ofile->object_byte_sex, ofile->object_addr,
1317			ofile->object_size, mh_cputype, symbols64, nsymbols,
1318			strings, strings_size, sorted_symbols, nsorted_symbols,
1319			vflag);
1320		else
1321		    print_objc_string_object_section(sectname,
1322			ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1323			ofile->object_byte_sex, ofile->object_addr,
1324			ofile->object_size, vflag);
1325	    }
1326	    else if(strcmp(segname, SEG_OBJC) == 0 &&
1327	       strcmp(sectname, "__runtime_setup") == 0 && vflag == TRUE){
1328		print_objc_runtime_setup_section(ofile->load_commands, mh_ncmds,
1329		   mh_sizeofcmds, ofile->object_byte_sex, ofile->object_addr,
1330		   ofile->object_size, vflag);
1331	    }
1332#ifdef EFI_SUPPORT
1333	    else if(strcmp(segname, "__RELOC") == 0 &&
1334	       strcmp(sectname, "__reloc") == 0 && vflag == TRUE){
1335		print_coff_reloc_section(ofile->load_commands, mh_ncmds,
1336		   mh_sizeofcmds, mh_filetype, ofile->object_byte_sex,
1337		   ofile->object_addr, ofile->object_size, vflag);
1338	    }
1339#endif
1340	    else if(get_sect_info(segname, sectname, ofile->load_commands,
1341		mh_ncmds, mh_sizeofcmds, mh_filetype, ofile->object_byte_sex,
1342		addr, size, &sect, &sect_size, &sect_addr,
1343		&sect_relocs, &sect_nrelocs, &sect_flags, &seg_addr) == TRUE){
1344
1345		if(Xflag == FALSE)
1346		    printf("Contents of (%.16s,%.16s) section\n", segname,
1347			   sectname);
1348
1349		if(vflag){
1350		    switch((sect_flags & SECTION_TYPE)){
1351		    case 0:
1352			print_sect(mh_cputype, ofile->object_byte_sex,
1353				   sect, sect_size, sect_addr);
1354			break;
1355		    case S_ZEROFILL:
1356			printf("zerofill section and has no contents in the "
1357			       "file\n");
1358			break;
1359		    case S_CSTRING_LITERALS:
1360			print_cstring_section(mh_cputype, sect, sect_size,
1361					      sect_addr,
1362					      Xflag == TRUE ? FALSE : TRUE);
1363			break;
1364		    case S_4BYTE_LITERALS:
1365			print_literal4_section(sect, sect_size, sect_addr,
1366					      ofile->object_byte_sex,
1367					      Xflag == TRUE ? FALSE : TRUE);
1368			break;
1369		    case S_8BYTE_LITERALS:
1370			print_literal8_section(sect, sect_size, sect_addr,
1371					      ofile->object_byte_sex,
1372					      Xflag == TRUE ? FALSE : TRUE);
1373			break;
1374		    case S_16BYTE_LITERALS:
1375			print_literal16_section(sect, sect_size, sect_addr,
1376					       ofile->object_byte_sex,
1377					       Xflag == TRUE ? FALSE : TRUE);
1378			break;
1379		    case S_LITERAL_POINTERS:
1380			/* create aligned, sorted relocations entries */
1381			nrelocs = sect_nrelocs;
1382			relocs = allocate(nrelocs *
1383					  sizeof(struct relocation_info));
1384			memcpy(relocs, sect_relocs, nrelocs *
1385			       sizeof(struct relocation_info));
1386			if(ofile->object_byte_sex != get_host_byte_sex())
1387			    swap_relocation_info(relocs, nrelocs,
1388					         get_host_byte_sex());
1389			qsort(relocs, nrelocs, sizeof(struct relocation_info),
1390			      (int (*)(const void *, const void *))rel_compare);
1391			print_literal_pointer_section(mh_cputype,
1392				ofile->load_commands, mh_ncmds, mh_sizeofcmds,
1393				ofile->object_byte_sex, addr, size, sect,
1394				sect_size, sect_addr, symbols, symbols64,
1395				nsymbols, strings, strings_size, relocs,
1396				nrelocs, Xflag == TRUE ? FALSE : TRUE);
1397			free(relocs);
1398
1399			break;
1400
1401		    case S_MOD_INIT_FUNC_POINTERS:
1402		    case S_MOD_TERM_FUNC_POINTERS:
1403			print_init_term_pointer_section(mh_cputype, sect,
1404			    sect_size, sect_addr, ofile->object_byte_sex,
1405			    sorted_symbols, nsorted_symbols, Vflag);
1406			break;
1407
1408		    default:
1409			printf("Unknown section type (0x%x)\n",
1410			       (unsigned int)(sect_flags & SECTION_TYPE));
1411			print_sect(mh_cputype, ofile->object_byte_sex, sect,
1412				   sect_size, sect_addr);
1413			break;
1414		    }
1415		}
1416		else{
1417		    if((sect_flags & SECTION_TYPE) == S_ZEROFILL)
1418			printf("zerofill section and has no contents in the "
1419			       "file\n");
1420		    else
1421			print_sect(mh_cputype, ofile->object_byte_sex, sect,
1422				   sect_size, sect_addr);
1423		}
1424	    }
1425	}
1426
1427	if(cflag)
1428	    print_argstrings(mh_magic, ofile->load_commands, mh_ncmds,
1429			     mh_sizeofcmds, mh_cputype, mh_cpusubtype,
1430			     ofile->object_byte_sex, ofile->object_addr,
1431			     ofile->object_size);
1432
1433	if(oflag){
1434	    if(mh_cputype & CPU_ARCH_ABI64){
1435		get_linked_reloc_info(ofile->load_commands, mh_ncmds,
1436			mh_sizeofcmds, ofile->object_byte_sex,
1437			ofile->object_addr, ofile->object_size, &ext_relocs,
1438			&next_relocs, &loc_relocs, &nloc_relocs);
1439		/* create aligned relocations entries as needed */
1440		relocs = NULL;
1441		nrelocs = 0;
1442		if((intptr_t)ext_relocs % sizeof(int32_t) != 0 ||
1443		   ofile->object_byte_sex != get_host_byte_sex()){
1444		    relocs = allocate(next_relocs *
1445				      sizeof(struct relocation_info));
1446		    memcpy(relocs, ext_relocs, next_relocs *
1447			   sizeof(struct relocation_info));
1448		    ext_relocs = relocs;
1449		}
1450		if((intptr_t)loc_relocs % sizeof(int32_t) != 0 ||
1451		   ofile->object_byte_sex != get_host_byte_sex()){
1452		    relocs = allocate(nloc_relocs *
1453				      sizeof(struct relocation_info));
1454		    memcpy(relocs, loc_relocs, nloc_relocs *
1455			   sizeof(struct relocation_info));
1456		    loc_relocs = relocs;
1457		}
1458		if(ofile->object_byte_sex != get_host_byte_sex()){
1459		    swap_relocation_info(ext_relocs, next_relocs,
1460					 get_host_byte_sex());
1461		    swap_relocation_info(loc_relocs, nloc_relocs,
1462					 get_host_byte_sex());
1463		}
1464		print_objc2_64bit(mh_cputype, ofile->load_commands, mh_ncmds,
1465			    mh_sizeofcmds, ofile->object_byte_sex,
1466			    ofile->object_addr, ofile->object_size, symbols64,
1467			    nsymbols, strings, strings_size, sorted_symbols,
1468			    nsorted_symbols, ext_relocs, next_relocs,
1469			    loc_relocs, nloc_relocs, vflag, Vflag);
1470	    }
1471	    else if(mh_cputype == CPU_TYPE_ARM){
1472		get_linked_reloc_info(ofile->load_commands, mh_ncmds,
1473			mh_sizeofcmds, ofile->object_byte_sex,
1474			ofile->object_addr, ofile->object_size, &ext_relocs,
1475			&next_relocs, &loc_relocs, &nloc_relocs);
1476		/* create aligned relocations entries as needed */
1477		relocs = NULL;
1478		nrelocs = 0;
1479		if((intptr_t)ext_relocs % sizeof(int32_t) != 0 ||
1480		   ofile->object_byte_sex != get_host_byte_sex()){
1481		    relocs = allocate(next_relocs *
1482				      sizeof(struct relocation_info));
1483		    memcpy(relocs, ext_relocs, next_relocs *
1484			   sizeof(struct relocation_info));
1485		    ext_relocs = relocs;
1486		}
1487		if((intptr_t)loc_relocs % sizeof(int32_t) != 0 ||
1488		   ofile->object_byte_sex != get_host_byte_sex()){
1489		    relocs = allocate(nloc_relocs *
1490				      sizeof(struct relocation_info));
1491		    memcpy(relocs, loc_relocs, nloc_relocs *
1492			   sizeof(struct relocation_info));
1493		    loc_relocs = relocs;
1494		}
1495		if(ofile->object_byte_sex != get_host_byte_sex()){
1496		    swap_relocation_info(ext_relocs, next_relocs,
1497					 get_host_byte_sex());
1498		    swap_relocation_info(loc_relocs, nloc_relocs,
1499					 get_host_byte_sex());
1500		}
1501		print_objc2_32bit(mh_cputype, ofile->load_commands, mh_ncmds,
1502			    mh_sizeofcmds, ofile->object_byte_sex,
1503			    ofile->object_addr, ofile->object_size, symbols,
1504			    nsymbols, strings, strings_size, sorted_symbols,
1505			    nsorted_symbols, ext_relocs, next_relocs,
1506			    loc_relocs, nloc_relocs, vflag);
1507	    }
1508	    else{
1509		 /*
1510		  * This is the 32-bit non-arm cputype case.  Which is normally
1511		  * the first Objective-C ABI.  But it may be the case of a
1512		  * binary for the iOS simulator which is the second Objective-C
1513		  * ABI.  In that case print_objc_segment() will determine that
1514		  * and return FALSE.
1515		  */
1516		 if(print_objc_segment(mh_cputype, ofile->load_commands,
1517			mh_ncmds, mh_sizeofcmds, ofile->object_byte_sex,
1518			ofile->object_addr, ofile->object_size, sorted_symbols,
1519			nsorted_symbols, vflag) == FALSE){
1520		    get_linked_reloc_info(ofile->load_commands, mh_ncmds,
1521			    mh_sizeofcmds, ofile->object_byte_sex,
1522			    ofile->object_addr, ofile->object_size, &ext_relocs,
1523			    &next_relocs, &loc_relocs, &nloc_relocs);
1524		    /* create aligned relocations entries as needed */
1525		    relocs = NULL;
1526		    nrelocs = 0;
1527		    if((intptr_t)ext_relocs % sizeof(int32_t) != 0 ||
1528		       ofile->object_byte_sex != get_host_byte_sex()){
1529			relocs = allocate(next_relocs *
1530					  sizeof(struct relocation_info));
1531			memcpy(relocs, ext_relocs, next_relocs *
1532			       sizeof(struct relocation_info));
1533			ext_relocs = relocs;
1534		    }
1535		    if((intptr_t)loc_relocs % sizeof(int32_t) != 0 ||
1536		       ofile->object_byte_sex != get_host_byte_sex()){
1537			relocs = allocate(nloc_relocs *
1538					  sizeof(struct relocation_info));
1539			memcpy(relocs, loc_relocs, nloc_relocs *
1540			       sizeof(struct relocation_info));
1541			loc_relocs = relocs;
1542		    }
1543		    if(ofile->object_byte_sex != get_host_byte_sex()){
1544			swap_relocation_info(ext_relocs, next_relocs,
1545					     get_host_byte_sex());
1546			swap_relocation_info(loc_relocs, nloc_relocs,
1547					     get_host_byte_sex());
1548		    }
1549		    print_objc2_32bit(mh_cputype, ofile->load_commands,
1550			    mh_ncmds, mh_sizeofcmds, ofile->object_byte_sex,
1551			    ofile->object_addr, ofile->object_size, symbols,
1552			    nsymbols, strings, strings_size, sorted_symbols,
1553			    nsorted_symbols, ext_relocs, next_relocs,
1554			    loc_relocs, nloc_relocs, vflag);
1555		}
1556	    }
1557	}
1558
1559	if(load_commands != NULL)
1560	    free(load_commands);
1561	if(allocated_symbols != NULL)
1562	    free(allocated_symbols);
1563	if(sorted_symbols != NULL)
1564	    free(sorted_symbols);
1565	if(allocated_indirect_symbols != NULL)
1566	    free(allocated_indirect_symbols);
1567	if(allocated_hints != NULL)
1568	    free(allocated_hints);
1569	if(allocated_dices != NULL)
1570	    free(allocated_dices);
1571	if(allocated_tocs != NULL)
1572	    free(allocated_tocs);
1573	if(allocated_mods != NULL)
1574	    free(allocated_mods);
1575	if(allocated_refs != NULL)
1576	    free(allocated_refs);
1577}
1578
1579/*
1580 * get_symbol_table_info() returns pointers to the symbol table and string
1581 * table as well as the number of symbols and size of the string table.
1582 * This routine handles the problems related to the file being truncated and
1583 * only returns valid pointers and sizes that can be used.  This routine will
1584 * return pointers that are misaligned and it is up to the caller to deal with
1585 * alignment issues.  It is also up to the caller to deal with byte sex of the
1586 * the symbol table.
1587 */
1588static
1589void
1590get_symbol_table_info(
1591struct load_command *load_commands,	/* input */
1592uint32_t ncmds,
1593uint32_t sizeofcmds,
1594cpu_type_t cputype,
1595enum byte_sex load_commands_byte_sex,
1596char *object_addr,
1597uint32_t object_size,
1598struct nlist **symbols,			/* output */
1599struct nlist_64 **symbols64,
1600uint32_t *nsymbols,
1601char **strings,
1602uint32_t *strings_size)
1603{
1604    enum byte_sex host_byte_sex;
1605    enum bool swapped;
1606    uint32_t i, left, size, st_cmd;
1607    struct load_command *lc, l;
1608    struct symtab_command st;
1609    uint64_t bigsize;
1610
1611	*symbols = NULL;
1612	*symbols64 = NULL;
1613	*nsymbols = 0;
1614	*strings = NULL;
1615	*strings_size = 0;
1616
1617	host_byte_sex = get_host_byte_sex();
1618	swapped = host_byte_sex != load_commands_byte_sex;
1619
1620	st_cmd = UINT_MAX;
1621	lc = load_commands;
1622	memset((char *)&st, '\0', sizeof(struct symtab_command));
1623	for(i = 0 ; i < ncmds; i++){
1624	    memcpy((char *)&l, (char *)lc, sizeof(struct load_command));
1625	    if(swapped)
1626		swap_load_command(&l, host_byte_sex);
1627	    if(l.cmdsize % sizeof(int32_t) != 0)
1628		printf("load command %u size not a multiple of "
1629		       "sizeof(int32_t)\n", i);
1630	    if((char *)lc + l.cmdsize >
1631	       (char *)load_commands + sizeofcmds)
1632		printf("load command %u extends past end of load "
1633		       "commands\n", i);
1634	    left = sizeofcmds - ((char *)lc - (char *)load_commands);
1635
1636	    switch(l.cmd){
1637	    case LC_SYMTAB:
1638		if(st_cmd != UINT_MAX){
1639		    printf("more than one LC_SYMTAB command (using command %u)"
1640			   "\n", st_cmd);
1641		    break;
1642		}
1643		size = left < sizeof(struct symtab_command) ?
1644		       left : sizeof(struct symtab_command);
1645		memcpy((char *)&st, (char *)lc, size);
1646		if(swapped)
1647		    swap_symtab_command(&st, host_byte_sex);
1648		st_cmd = i;
1649	    }
1650	    if(l.cmdsize == 0){
1651		printf("load command %u size zero (can't advance to other "
1652		       "load commands)\n", i);
1653		break;
1654	    }
1655	    lc = (struct load_command *)((char *)lc + l.cmdsize);
1656	    if((char *)lc > (char *)load_commands + sizeofcmds)
1657		break;
1658	}
1659	if((char *)load_commands + sizeofcmds != (char *)lc)
1660	    printf("Inconsistent sizeofcmds\n");
1661
1662	if(st_cmd == UINT_MAX){
1663	    return;
1664	}
1665
1666	if(st.symoff >= object_size){
1667	    printf("symbol table offset is past end of file\n");
1668	}
1669	else{
1670	    if(cputype & CPU_ARCH_ABI64){
1671		*symbols64 = (struct nlist_64 *)(object_addr + st.symoff);
1672		bigsize = st.nsyms;
1673		bigsize *= sizeof(struct nlist_64);
1674		bigsize += st.symoff;
1675		if(bigsize > object_size){
1676		    printf("symbol table extends past end of file\n");
1677		    *nsymbols = (object_size - st.symoff) /
1678			        sizeof(struct nlist_64);
1679		}
1680		else
1681		    *nsymbols = st.nsyms;
1682	    }
1683	    else{
1684		*symbols = (struct nlist *)(object_addr + st.symoff);
1685		bigsize = st.nsyms;
1686		bigsize *= sizeof(struct nlist);
1687		bigsize += st.symoff;
1688		if(bigsize > object_size){
1689		    printf("symbol table extends past end of file\n");
1690		    *nsymbols = (object_size - st.symoff) /
1691			        sizeof(struct nlist);
1692		}
1693		else
1694		    *nsymbols = st.nsyms;
1695	    }
1696	}
1697
1698	if(st.stroff >= object_size){
1699	    printf("string table offset is past end of file\n");
1700	}
1701	else{
1702	    *strings = object_addr + st.stroff;
1703	    if(st.stroff + st.strsize > object_size){
1704		printf("string table extends past end of file\n");
1705		*strings_size = object_size - st.symoff;
1706	    }
1707	    else
1708		*strings_size = st.strsize;
1709	}
1710}
1711
1712/*
1713 * get_toc_info() returns a pointer and the size of the table of contents.
1714 * This routine handles the problems related to the file being truncated and
1715 * only returns valid pointers and sizes that can be used.  This routine will
1716 * return pointers that are misaligned and it is up to the caller to deal with
1717 * alignment issues.  It is also up to the caller to deal with byte sex of the
1718 * table.
1719 */
1720static
1721void
1722get_toc_info(
1723struct load_command *load_commands,
1724uint32_t ncmds,
1725uint32_t sizeofcmds,
1726enum byte_sex load_commands_byte_sex,
1727char *object_addr,
1728uint32_t object_size,
1729struct dylib_table_of_contents **tocs,	/* output */
1730uint32_t *ntocs)
1731{
1732    struct dysymtab_command dyst;
1733    uint64_t bigsize;
1734
1735	*tocs = NULL;
1736	*ntocs = 0;
1737
1738	if(get_dyst(load_commands, ncmds, sizeofcmds, load_commands_byte_sex,
1739		    &dyst) == FALSE)
1740	    return;
1741
1742	if(dyst.tocoff >= object_size){
1743	    printf("table of contents offset is past end of file\n");
1744	}
1745	else{
1746	    *tocs = (struct dylib_table_of_contents *)(object_addr +
1747						       dyst.tocoff);
1748	    bigsize = dyst.ntoc;
1749	    bigsize *= sizeof(struct dylib_table_of_contents);
1750	    bigsize += dyst.tocoff;
1751	    if(bigsize > object_size){
1752		printf("table of contents extends past end of file\n");
1753		*ntocs = (object_size - dyst.tocoff) /
1754				     sizeof(struct dylib_table_of_contents);
1755	    }
1756	    else
1757		*ntocs = dyst.ntoc;
1758	}
1759}
1760
1761/*
1762 * get_module_table_info() returns a pointer and the size of the
1763 * module table.  This routine handles the problems related to the file being
1764 * truncated and only returns valid pointers and sizes that can be used.  This
1765 * routine will return pointers that are misaligned and it is up to the caller
1766 * to deal with alignment issues.  It is also up to the caller to deal with
1767 * byte sex of the table.
1768 */
1769static
1770void
1771get_module_table_info(
1772struct load_command *load_commands,
1773uint32_t ncmds,
1774uint32_t sizeofcmds,
1775cpu_type_t cputype,
1776enum byte_sex load_commands_byte_sex,
1777char *object_addr,
1778uint32_t object_size,
1779struct dylib_module **mods,			/* output */
1780struct dylib_module_64 **mods64,
1781uint32_t *nmods)
1782{
1783    struct dysymtab_command dyst;
1784    uint64_t bigsize;
1785
1786	*mods = NULL;
1787	*mods64 = NULL;
1788	*nmods = 0;
1789
1790	if(get_dyst(load_commands, ncmds, sizeofcmds, load_commands_byte_sex,
1791		    &dyst) == FALSE)
1792	    return;
1793
1794	if(dyst.modtaboff >= object_size){
1795	    printf("module table offset is past end of file\n");
1796	}
1797	else{
1798	    if(cputype & CPU_ARCH_ABI64){
1799		*mods64 = (struct dylib_module_64 *)(object_addr +
1800						     dyst.modtaboff);
1801		bigsize = dyst.nmodtab;
1802		bigsize *= sizeof(struct dylib_module_64);
1803		bigsize += dyst.modtaboff;
1804		if(bigsize > object_size){
1805		    printf("module table extends past end of file\n");
1806		    *nmods = (object_size - dyst.modtaboff) /
1807					 sizeof(struct dylib_module_64);
1808		}
1809		else
1810		    *nmods = dyst.nmodtab;
1811	    }
1812	    else{
1813		*mods = (struct dylib_module *)(object_addr + dyst.modtaboff);
1814		if(dyst.modtaboff +
1815		   dyst.nmodtab * sizeof(struct dylib_module) > object_size){
1816		    printf("module table extends past end of file\n");
1817		    *nmods = (object_size - dyst.modtaboff) /
1818					 sizeof(struct dylib_module);
1819		}
1820		else
1821		    *nmods = dyst.nmodtab;
1822	    }
1823	}
1824}
1825
1826/*
1827 * get_ref_info() returns a pointer and the size of the reference table.
1828 * This routine handles the problems related to the file being truncated and
1829 * only returns valid pointers and sizes that can be used.  This routine will
1830 * return pointers that are misaligned and it is up to the caller to deal with
1831 * alignment issues.  It is also up to the caller to deal with byte sex of the
1832 * table.
1833 */
1834static
1835void
1836get_ref_info(
1837struct load_command *load_commands,
1838uint32_t ncmds,
1839uint32_t sizeofcmds,
1840enum byte_sex load_commands_byte_sex,
1841char *object_addr,
1842uint32_t object_size,
1843struct dylib_reference **refs,		/* output */
1844uint32_t *nrefs)
1845{
1846    struct dysymtab_command dyst;
1847    uint64_t bigsize;
1848
1849	*refs = NULL;
1850	*nrefs = 0;
1851
1852	if(get_dyst(load_commands, ncmds, sizeofcmds, load_commands_byte_sex,
1853		    &dyst) == FALSE)
1854	    return;
1855
1856	if(dyst.extrefsymoff >= object_size){
1857	    printf("reference table offset is past end of file\n");
1858	}
1859	else{
1860	    *refs = (struct dylib_reference *)(object_addr + dyst.extrefsymoff);
1861	    bigsize = dyst.nextrefsyms;
1862	    bigsize *= sizeof(struct dylib_reference);
1863	    bigsize += dyst.extrefsymoff;
1864	    if(bigsize > object_size){
1865		printf("reference table extends past end of file\n");
1866		*nrefs = (object_size - dyst.extrefsymoff) /
1867				     sizeof(struct dylib_reference);
1868	    }
1869	    else
1870		*nrefs = dyst.nextrefsyms;
1871	}
1872}
1873
1874/*
1875 * get_indirect_symbol_table_info() returns a pointer and the size of the
1876 * indirect symbol table.  This routine handles the problems related to the
1877 * file being truncated and only returns valid pointers and sizes that can be
1878 * used.  This routine will return pointers that are misaligned and it is up to
1879 * the caller to deal with alignment issues.  It is also up to the caller to
1880 * deal with byte sex of the table.
1881 */
1882static
1883void
1884get_indirect_symbol_table_info(
1885struct load_command *load_commands,
1886uint32_t ncmds,
1887uint32_t sizeofcmds,
1888enum byte_sex load_commands_byte_sex,
1889char *object_addr,
1890uint32_t object_size,
1891uint32_t **indirect_symbols,	/* output */
1892uint32_t *nindirect_symbols)
1893{
1894    struct dysymtab_command dyst;
1895    uint64_t bigsize;
1896
1897	*indirect_symbols = NULL;
1898	*nindirect_symbols = 0;
1899
1900	if(get_dyst(load_commands, ncmds, sizeofcmds, load_commands_byte_sex,
1901		    &dyst) == FALSE)
1902	    return;
1903
1904	if(dyst.indirectsymoff >= object_size){
1905	    printf("indirect symbol table offset is past end of file\n");
1906	}
1907	else{
1908	    *indirect_symbols = (uint32_t *)(object_addr + dyst.indirectsymoff);
1909	    bigsize = dyst.nindirectsyms;
1910	    bigsize *= sizeof(uint32_t);
1911	    bigsize += dyst.indirectsymoff;
1912	    if(bigsize > object_size){
1913		printf("indirect symbol table extends past end of file\n");
1914		*nindirect_symbols = (object_size - dyst.indirectsymoff) /
1915				     sizeof(uint32_t);
1916	    }
1917	    else
1918		*nindirect_symbols = dyst.nindirectsyms;
1919	}
1920}
1921
1922/*
1923 * get_dyst() gets the dysymtab_command from the mach header and load commands
1924 * passed to it and copys it into dyst.  It if doesn't find one it returns FALSE
1925 * else it returns TRUE.
1926 */
1927static
1928enum bool
1929get_dyst(
1930struct load_command *load_commands,
1931uint32_t ncmds,
1932uint32_t sizeofcmds,
1933enum byte_sex load_commands_byte_sex,
1934struct dysymtab_command *dyst)
1935{
1936    enum byte_sex host_byte_sex;
1937    enum bool swapped;
1938    uint32_t i, left, size, dyst_cmd;
1939    struct load_command *lc, l;
1940
1941	host_byte_sex = get_host_byte_sex();
1942	swapped = host_byte_sex != load_commands_byte_sex;
1943
1944	dyst_cmd = UINT_MAX;
1945	lc = load_commands;
1946	for(i = 0 ; i < ncmds; i++){
1947	    memcpy((char *)&l, (char *)lc, sizeof(struct load_command));
1948	    if(swapped)
1949		swap_load_command(&l, host_byte_sex);
1950	    if(l.cmdsize % sizeof(int32_t) != 0)
1951		printf("load command %u size not a multiple of "
1952		       "sizeof(int32_t)\n", i);
1953	    if((char *)lc + l.cmdsize >
1954	       (char *)load_commands + sizeofcmds)
1955		printf("load command %u extends past end of load "
1956		       "commands\n", i);
1957	    left = sizeofcmds - ((char *)lc - (char *)load_commands);
1958
1959	    switch(l.cmd){
1960	    case LC_DYSYMTAB:
1961		if(dyst_cmd != UINT_MAX){
1962		    printf("more than one LC_DYSYMTAB command (using command "
1963			   "%u)\n", dyst_cmd);
1964		    break;
1965		}
1966		memset((char *)dyst, '\0', sizeof(struct dysymtab_command));
1967		size = left < sizeof(struct dysymtab_command) ?
1968		       left : sizeof(struct dysymtab_command);
1969		memcpy((char *)dyst, (char *)lc, size);
1970		if(swapped)
1971		    swap_dysymtab_command(dyst, host_byte_sex);
1972		dyst_cmd = i;
1973	    }
1974	    if(l.cmdsize == 0){
1975		printf("load command %u size zero (can't advance to other "
1976		       "load commands)\n", i);
1977		break;
1978	    }
1979	    lc = (struct load_command *)((char *)lc + l.cmdsize);
1980	    if((char *)lc > (char *)load_commands + sizeofcmds)
1981		break;
1982	}
1983	if((char *)load_commands + sizeofcmds != (char *)lc)
1984	    printf("Inconsistent sizeofcmds\n");
1985
1986	if(dyst_cmd == UINT_MAX){
1987	    return(FALSE);
1988	}
1989	return(TRUE);
1990}
1991
1992/*
1993 * get_hints_table_info() returns a pointer and the size of the two-level hints
1994 * table.  This routine handles the problems related to the file being truncated
1995 * and only returns valid pointers and sizes that can be used.  This routine
1996 * will return pointers that are misaligned and it is up to the caller to deal
1997 * with alignment issues.  It is also up to the caller to deal with byte sex of
1998 * the table.
1999 */
2000static
2001void
2002get_hints_table_info(
2003struct load_command *load_commands,
2004uint32_t ncmds,
2005uint32_t sizeofcmds,
2006enum byte_sex load_commands_byte_sex,
2007char *object_addr,
2008uint32_t object_size,
2009struct twolevel_hint **hints,	/* output */
2010uint32_t *nhints)
2011{
2012    struct twolevel_hints_command hints_cmd;
2013    uint64_t bigsize;
2014
2015	*hints = NULL;
2016	*nhints = 0;
2017
2018	memset(&hints_cmd, '\0', sizeof(struct twolevel_hints_command));
2019	if(get_hints_cmd(load_commands, ncmds, sizeofcmds,
2020		         load_commands_byte_sex, &hints_cmd) == FALSE)
2021	    return;
2022
2023	if(hints_cmd.offset >= object_size){
2024	    printf("two-level hints offset is past end of file\n");
2025	}
2026	else{
2027	    *hints = (struct twolevel_hint *)(object_addr + hints_cmd.offset);
2028	    bigsize = hints_cmd.nhints;
2029	    bigsize *= sizeof(struct twolevel_hint);
2030	    bigsize += hints_cmd.offset;
2031	    if(bigsize > object_size){
2032		printf("two-level hints table extends past end of file\n");
2033		*nhints = (object_size - hints_cmd.offset) /
2034			  sizeof(struct twolevel_hint);
2035	    }
2036	    else
2037		*nhints = hints_cmd.nhints;
2038	}
2039}
2040
2041/*
2042 * get_hints_cmd() gets the twolevel_hints_command from the mach header and
2043 * load commands passed to it and copys it into hints_cmd.  It if doesn't find
2044 * one it returns FALSE else it returns TRUE.
2045 */
2046static
2047enum bool
2048get_hints_cmd(
2049struct load_command *load_commands,
2050uint32_t ncmds,
2051uint32_t sizeofcmds,
2052enum byte_sex load_commands_byte_sex,
2053struct twolevel_hints_command *hints_cmd)
2054{
2055    enum byte_sex host_byte_sex;
2056    enum bool swapped;
2057    uint32_t i, left, size, cmd;
2058    struct load_command *lc, l;
2059
2060	host_byte_sex = get_host_byte_sex();
2061	swapped = host_byte_sex != load_commands_byte_sex;
2062
2063	cmd = UINT_MAX;
2064	lc = load_commands;
2065	for(i = 0 ; i < ncmds; i++){
2066	    memcpy((char *)&l, (char *)lc, sizeof(struct load_command));
2067	    if(swapped)
2068		swap_load_command(&l, host_byte_sex);
2069	    if(l.cmdsize % sizeof(int32_t) != 0)
2070		printf("load command %u size not a multiple of "
2071		       "sizeof(int32_t)\n", i);
2072	    if((char *)lc + l.cmdsize >
2073	       (char *)load_commands + sizeofcmds)
2074		printf("load command %u extends past end of load "
2075		       "commands\n", i);
2076	    left = sizeofcmds - ((char *)lc - (char *)load_commands);
2077
2078	    switch(l.cmd){
2079	    case LC_TWOLEVEL_HINTS:
2080		if(cmd != UINT_MAX){
2081		    printf("more than one LC_TWOLEVEL_HINTS command (using "
2082			   "command %u)\n", cmd);
2083		    break;
2084		}
2085		memset((char *)hints_cmd, '\0',
2086		       sizeof(struct twolevel_hints_command));
2087		size = left < sizeof(struct twolevel_hints_command) ?
2088		       left : sizeof(struct twolevel_hints_command);
2089		memcpy((char *)hints_cmd, (char *)lc, size);
2090		if(swapped)
2091		    swap_twolevel_hints_command(hints_cmd, host_byte_sex);
2092		cmd = i;
2093	    }
2094	    if(l.cmdsize == 0){
2095		printf("load command %u size zero (can't advance to other "
2096		       "load commands)\n", i);
2097		break;
2098	    }
2099	    lc = (struct load_command *)((char *)lc + l.cmdsize);
2100	    if((char *)lc > (char *)load_commands + sizeofcmds)
2101		break;
2102	}
2103	if((char *)load_commands + sizeofcmds != (char *)lc)
2104	    printf("Inconsistent sizeofcmds\n");
2105
2106	if(cmd == UINT_MAX){
2107	    return(FALSE);
2108	}
2109	return(TRUE);
2110}
2111
2112/*
2113 * get_data_in_code_info() returns a pointer and the size of the data in code
2114 * table.  This routine handles the problems related to the file being truncated
2115 * and only returns valid pointers and sizes that can be used.  This routine
2116 * will return pointers that are misaligned and it is up to the caller to deal
2117 * with alignment issues.  It is also up to the caller to deal with byte sex of
2118 * the table.
2119 */
2120static
2121void
2122get_data_in_code_info(
2123struct load_command *load_commands,
2124uint32_t ncmds,
2125uint32_t sizeofcmds,
2126enum byte_sex load_commands_byte_sex,
2127char *object_addr,
2128uint32_t object_size,
2129struct data_in_code_entry **dices,	/* output */
2130uint32_t *ndices)
2131{
2132    struct linkedit_data_command dices_cmd;
2133    uint64_t bigsize;
2134
2135	*dices = NULL;
2136	*ndices = 0;
2137
2138	memset(&dices_cmd, '\0', sizeof(struct linkedit_data_command));
2139	if(get_dices_cmd(load_commands, ncmds, sizeofcmds,
2140		         load_commands_byte_sex, &dices_cmd) == FALSE)
2141	    return;
2142
2143	if(dices_cmd.dataoff >= object_size){
2144	    printf("data in code offset is past end of file\n");
2145	}
2146	else{
2147	    *dices = (struct data_in_code_entry *)
2148		     (object_addr + dices_cmd.dataoff);
2149	    bigsize = dices_cmd.datasize;
2150	    bigsize += dices_cmd.dataoff;
2151	    if(bigsize > object_size){
2152		printf("data in code table extends past end of file\n");
2153		*ndices = (object_size - dices_cmd.dataoff) /
2154			  sizeof(struct data_in_code_entry);
2155	    }
2156	    else
2157		*ndices = dices_cmd.datasize /
2158			  sizeof(struct data_in_code_entry);
2159	}
2160}
2161
2162/*
2163 * get_dices_cmd() gets the linkedit_data_command for the data in code from the
2164 * mach header and load commands passed to it and copys it into dices_cmd.  It
2165 * if doesn't find one it returns FALSE else it returns TRUE.
2166 */
2167static
2168enum bool
2169get_dices_cmd(
2170struct load_command *load_commands,
2171uint32_t ncmds,
2172uint32_t sizeofcmds,
2173enum byte_sex load_commands_byte_sex,
2174struct linkedit_data_command *dices_cmd)
2175{
2176    enum byte_sex host_byte_sex;
2177    enum bool swapped;
2178    uint32_t i, left, size, cmd;
2179    struct load_command *lc, l;
2180
2181	host_byte_sex = get_host_byte_sex();
2182	swapped = host_byte_sex != load_commands_byte_sex;
2183
2184	cmd = UINT_MAX;
2185	lc = load_commands;
2186	for(i = 0 ; i < ncmds; i++){
2187	    memcpy((char *)&l, (char *)lc, sizeof(struct load_command));
2188	    if(swapped)
2189		swap_load_command(&l, host_byte_sex);
2190	    if(l.cmdsize % sizeof(int32_t) != 0)
2191		printf("load command %u size not a multiple of "
2192		       "sizeof(int32_t)\n", i);
2193	    if((char *)lc + l.cmdsize >
2194	       (char *)load_commands + sizeofcmds)
2195		printf("load command %u extends past end of load "
2196		       "commands\n", i);
2197	    left = sizeofcmds - ((char *)lc - (char *)load_commands);
2198
2199	    switch(l.cmd){
2200	    case LC_DATA_IN_CODE:
2201		if(cmd != UINT_MAX){
2202		    printf("more than one LC_DATA_IN_CODE command (using "
2203			   "command %u)\n", cmd);
2204		    break;
2205		}
2206		memset((char *)dices_cmd, '\0',
2207		       sizeof(struct linkedit_data_command));
2208		size = left < sizeof(struct linkedit_data_command) ?
2209		       left : sizeof(struct linkedit_data_command);
2210		memcpy((char *)dices_cmd, (char *)lc, size);
2211		if(swapped)
2212		    swap_linkedit_data_command(dices_cmd, host_byte_sex);
2213		cmd = i;
2214	    }
2215	    if(l.cmdsize == 0){
2216		printf("load command %u size zero (can't advance to other "
2217		       "load commands)\n", i);
2218		break;
2219	    }
2220	    lc = (struct load_command *)((char *)lc + l.cmdsize);
2221	    if((char *)lc > (char *)load_commands + sizeofcmds)
2222		break;
2223	}
2224	if((char *)load_commands + sizeofcmds != (char *)lc)
2225	    printf("Inconsistent sizeofcmds\n");
2226
2227	if(cmd == UINT_MAX){
2228	    return(FALSE);
2229	}
2230	return(TRUE);
2231}
2232
2233/*
2234 * Function for qsort for comparing symbols.
2235 */
2236static
2237int
2238sym_compare(
2239struct symbol *sym1,
2240struct symbol *sym2)
2241{
2242	if(sym1->n_value == sym2->n_value)
2243	    return(0);
2244	if(sym1->n_value < sym2->n_value)
2245	    return(-1);
2246	else
2247	    return(1);
2248}
2249
2250/*
2251 * Function for qsort for comparing relocation entries.
2252 */
2253static
2254int
2255rel_compare(
2256struct relocation_info *rel1,
2257struct relocation_info *rel2)
2258{
2259    struct scattered_relocation_info *srel;
2260    uint32_t r_address1, r_address2;
2261
2262	if((rel1->r_address & R_SCATTERED) != 0){
2263	    srel = (struct scattered_relocation_info *)rel1;
2264	    r_address1 = srel->r_address;
2265	}
2266	else
2267	    r_address1 = rel1->r_address;
2268	if((rel2->r_address & R_SCATTERED) != 0){
2269	    srel = (struct scattered_relocation_info *)rel2;
2270	    r_address2 = srel->r_address;
2271	}
2272	else
2273	    r_address2 = rel2->r_address;
2274
2275	if(r_address1 == r_address2)
2276	    return(0);
2277	if(r_address1 < r_address2)
2278	    return(-1);
2279	else
2280	    return(1);
2281}
2282
2283enum bool
2284get_sect_info(
2285char *segname,				/* input */
2286char *sectname,
2287struct load_command *load_commands,
2288uint32_t ncmds,
2289uint32_t sizeofcmds,
2290uint32_t filetype,
2291enum byte_sex load_commands_byte_sex,
2292char *object_addr,
2293uint32_t object_size,
2294char **sect_pointer,			/* output */
2295uint64_t *sect_size,
2296uint64_t *sect_addr,
2297struct relocation_info **sect_relocs,
2298uint32_t *sect_nrelocs,
2299uint32_t *sect_flags,
2300uint64_t *seg_addr)
2301{
2302    enum byte_sex host_byte_sex;
2303    enum bool found, swapped;
2304    uint32_t i, j, left, size;
2305    struct load_command *lc, l;
2306    uint32_t cmd;
2307    struct segment_command sg;
2308    struct segment_command_64 sg64;
2309    struct section s;
2310    struct section_64 s64;
2311    char *p;
2312
2313	*sect_pointer = NULL;
2314	*sect_size = 0;
2315	*sect_addr = 0;
2316	*sect_relocs = NULL;
2317	*sect_nrelocs = 0;
2318	*sect_flags = 0;
2319
2320	found = FALSE;
2321	cmd = 0;
2322	host_byte_sex = get_host_byte_sex();
2323	swapped = host_byte_sex != load_commands_byte_sex;
2324
2325	lc = load_commands;
2326	for(i = 0 ; found == FALSE && i < ncmds; i++){
2327	    memcpy((char *)&l, (char *)lc, sizeof(struct load_command));
2328	    if(swapped)
2329		swap_load_command(&l, host_byte_sex);
2330	    if(l.cmdsize % sizeof(int32_t) != 0)
2331		printf("load command %u size not a multiple of "
2332		       "sizeof(int32_t)\n", i);
2333	    if((char *)lc + l.cmdsize >
2334	       (char *)load_commands + sizeofcmds)
2335		printf("load command %u extends past end of load "
2336		       "commands\n", i);
2337	    left = sizeofcmds - ((char *)lc - (char *)load_commands);
2338
2339	    switch(l.cmd){
2340	    case LC_SEGMENT:
2341		memset((char *)&sg, '\0', sizeof(struct segment_command));
2342		size = left < sizeof(struct segment_command) ?
2343		       left : sizeof(struct segment_command);
2344		memcpy((char *)&sg, (char *)lc, size);
2345		if(swapped)
2346		    swap_segment_command(&sg, host_byte_sex);
2347
2348		if((filetype == MH_OBJECT && sg.segname[0] == '\0') ||
2349		   strncmp(sg.segname, segname, sizeof(sg.segname)) == 0){
2350                    *seg_addr = sg.vmaddr;
2351		    p = (char *)lc + sizeof(struct segment_command);
2352		    for(j = 0 ; found == FALSE && j < sg.nsects ; j++){
2353			if(p + sizeof(struct section) >
2354			   (char *)load_commands + sizeofcmds){
2355			    printf("section structure command extends past "
2356				   "end of load commands\n");
2357			}
2358			left = sizeofcmds - (p - (char *)load_commands);
2359			memset((char *)&s, '\0', sizeof(struct section));
2360			size = left < sizeof(struct section) ?
2361			       left : sizeof(struct section);
2362			memcpy((char *)&s, p, size);
2363			if(swapped)
2364			    swap_section(&s, 1, host_byte_sex);
2365
2366			if(strncmp(s.sectname, sectname,
2367				   sizeof(s.sectname)) == 0 &&
2368			   strncmp(s.segname, segname,
2369				   sizeof(s.segname)) == 0){
2370			    found = TRUE;
2371			    cmd = LC_SEGMENT;
2372			    break;
2373			}
2374
2375			if(p + sizeof(struct section) >
2376			   (char *)load_commands + sizeofcmds)
2377			    return(FALSE);
2378			p += size;
2379		    }
2380		}
2381		break;
2382	    case LC_SEGMENT_64:
2383		memset((char *)&sg64, '\0', sizeof(struct segment_command_64));
2384		size = left < sizeof(struct segment_command_64) ?
2385		       left : sizeof(struct segment_command_64);
2386		memcpy((char *)&sg64, (char *)lc, size);
2387		if(swapped)
2388		    swap_segment_command_64(&sg64, host_byte_sex);
2389
2390		if((filetype == MH_OBJECT && sg64.segname[0] == '\0') ||
2391		   strncmp(sg64.segname, segname, sizeof(sg64.segname)) == 0){
2392                    *seg_addr = sg.vmaddr;
2393		    p = (char *)lc + sizeof(struct segment_command_64);
2394		    for(j = 0 ; found == FALSE && j < sg64.nsects ; j++){
2395			if(p + sizeof(struct section_64) >
2396			   (char *)load_commands + sizeofcmds){
2397			    printf("section structure command extends past "
2398				   "end of load commands\n");
2399			}
2400			left = sizeofcmds - (p - (char *)load_commands);
2401			memset((char *)&s64, '\0', sizeof(struct section_64));
2402			size = left < sizeof(struct section_64) ?
2403			       left : sizeof(struct section_64);
2404			memcpy((char *)&s64, p, size);
2405			if(swapped)
2406			    swap_section_64(&s64, 1, host_byte_sex);
2407
2408			if(strncmp(s64.sectname, sectname,
2409				   sizeof(s64.sectname)) == 0 &&
2410			   strncmp(s64.segname, segname,
2411				   sizeof(s64.segname)) == 0){
2412			    found = TRUE;
2413			    cmd = LC_SEGMENT_64;
2414			    break;
2415			}
2416
2417			if(p + sizeof(struct section_64) >
2418			   (char *)load_commands + sizeofcmds)
2419			    return(FALSE);
2420			p += size;
2421		    }
2422		}
2423		break;
2424	    }
2425	    if(l.cmdsize == 0){
2426		printf("load command %u size zero (can't advance to other "
2427		       "load commands)\n", i);
2428		break;
2429	    }
2430	    lc = (struct load_command *)((char *)lc + l.cmdsize);
2431	    if((char *)lc > (char *)load_commands + sizeofcmds)
2432		break;
2433	}
2434	if(found == FALSE)
2435	    return(FALSE);
2436
2437	if(cmd == LC_SEGMENT){
2438	    if((s.flags & SECTION_TYPE) == S_ZEROFILL){
2439		*sect_pointer = NULL;
2440		*sect_size = s.size;
2441	    }
2442	    else{
2443		if(s.offset > object_size){
2444		    printf("section offset for section (%.16s,%.16s) is past "
2445			   "end of file\n", s.segname, s.sectname);
2446		}
2447		else{
2448		    *sect_pointer = object_addr + s.offset;
2449		    if(s.offset + s.size > object_size){
2450			printf("section (%.16s,%.16s) extends past end of "
2451			       "file\n", s.segname, s.sectname);
2452			*sect_size = object_size - s.offset;
2453		    }
2454		    else
2455			*sect_size = s.size;
2456		}
2457	    }
2458	    if(s.reloff >= object_size){
2459		printf("relocation entries offset for (%.16s,%.16s): is past "
2460		       "end of file\n", s.segname, s.sectname);
2461	    }
2462	    else{
2463		*sect_relocs = (struct relocation_info *)(object_addr +
2464							  s.reloff);
2465		if(s.reloff + s.nreloc * sizeof(struct relocation_info) >
2466								object_size){
2467		    printf("relocation entries for section (%.16s,%.16s) "
2468			   "extends past end of file\n", s.segname, s.sectname);
2469		    *sect_nrelocs = (object_size - s.reloff) /
2470				    sizeof(struct relocation_info);
2471		}
2472		else
2473		    *sect_nrelocs = s.nreloc;
2474	    }
2475	    *sect_addr = s.addr;
2476	    *sect_flags = s.flags;
2477	}
2478	else{
2479	    if((s64.flags & SECTION_TYPE) == S_ZEROFILL){
2480		*sect_pointer = NULL;
2481		*sect_size = s64.size;
2482	    }
2483	    else{
2484		if(s64.offset > object_size){
2485		    printf("section offset for section (%.16s,%.16s) is past "
2486			   "end of file\n", s64.segname, s64.sectname);
2487		}
2488		else{
2489		    *sect_pointer = object_addr + s64.offset;
2490		    if(s64.offset + s64.size > object_size){
2491			printf("section (%.16s,%.16s) extends past end of "
2492			       "file\n", s64.segname, s64.sectname);
2493			*sect_size = object_size - s64.offset;
2494		    }
2495		    else
2496			*sect_size = s64.size;
2497		}
2498	    }
2499	    if(s64.reloff >= object_size){
2500		printf("relocation entries offset for (%.16s,%.16s): is past "
2501		       "end of file\n", s64.segname, s64.sectname);
2502	    }
2503	    else{
2504		*sect_relocs = (struct relocation_info *)(object_addr +
2505							  s64.reloff);
2506		if(s64.reloff + s64.nreloc * sizeof(struct relocation_info) >
2507								object_size){
2508		    printf("relocation entries for section (%.16s,%.16s) "
2509			   "extends past end of file\n", s64.segname,
2510			   s64.sectname);
2511		    *sect_nrelocs = (object_size - s64.reloff) /
2512				    sizeof(struct relocation_info);
2513		}
2514		else
2515		    *sect_nrelocs = s64.nreloc;
2516	    }
2517	    *sect_addr = s64.addr;
2518	    *sect_flags = s64.flags;
2519	}
2520	return(TRUE);
2521}
2522
2523static
2524void
2525get_linked_reloc_info(
2526struct load_command *load_commands, 	/* input */
2527uint32_t ncmds,
2528uint32_t sizeofcmds,
2529enum byte_sex load_commands_byte_sex,
2530char *object_addr,
2531uint32_t object_size,
2532struct relocation_info **ext_relocs,	/* output */
2533uint32_t *next_relocs,
2534struct relocation_info **loc_relocs,
2535uint32_t *nloc_relocs)
2536{
2537    struct dysymtab_command dyst;
2538    uint64_t bigsize;
2539
2540	*ext_relocs = NULL;
2541	*next_relocs = 0;
2542	*loc_relocs = NULL;
2543	*nloc_relocs = 0;
2544
2545	if(get_dyst(load_commands, ncmds, sizeofcmds, load_commands_byte_sex,
2546		    &dyst) == FALSE)
2547	    return;
2548
2549	if(dyst.extreloff >= object_size){
2550	    printf("external relocation entries offset is past end of file\n");
2551	}
2552	else{
2553	    *ext_relocs = (struct relocation_info *)(object_addr +
2554			   dyst.extreloff);
2555	    bigsize = dyst.nextrel;
2556	    bigsize *= sizeof(struct relocation_info);
2557	    bigsize += dyst.extreloff;
2558	    if(bigsize > object_size){
2559		printf("external relocation entries extend past end of file\n");
2560		*next_relocs = (object_size - dyst.extreloff) /
2561				     sizeof(struct relocation_info);
2562	    }
2563	    else
2564		*next_relocs = dyst.nextrel;
2565	}
2566	if(dyst.locreloff >= object_size){
2567	    printf("local relocation entries offset is past end of file\n");
2568	}
2569	else{
2570	    *loc_relocs = (struct relocation_info *)(object_addr +
2571			   dyst.locreloff);
2572	    bigsize = dyst.nlocrel;
2573	    bigsize *= sizeof(struct relocation_info);
2574	    bigsize += dyst.locreloff;
2575	    if(bigsize > object_size){
2576		printf("local relocation entries extend past end of file\n");
2577		*nloc_relocs = (object_size - dyst.locreloff) /
2578				     sizeof(struct relocation_info);
2579	    }
2580	    else
2581		*nloc_relocs = dyst.nlocrel;
2582	}
2583}
2584
2585static
2586void
2587print_text(
2588cpu_type_t cputype,
2589enum byte_sex object_byte_sex,
2590char *sect,
2591uint32_t size,
2592uint64_t addr,
2593uint32_t sect_flags,
2594struct symbol *sorted_symbols,
2595uint32_t nsorted_symbols,
2596struct nlist *symbols,
2597struct nlist_64 *symbols64,
2598uint32_t nsymbols,
2599char *strings,
2600uint32_t strings_size,
2601struct relocation_info *relocs,
2602uint32_t nrelocs,
2603uint32_t *indirect_symbols,
2604uint32_t nindirect_symbols,
2605struct load_command *load_commands,
2606uint32_t ncmds,
2607uint32_t sizeofcmds,
2608enum bool disassemble,
2609enum bool verbose,
2610cpu_subtype_t cpusubtype,
2611char *object_addr,
2612uint32_t object_size,
2613struct data_in_code_entry *dices,
2614uint32_t ndices,
2615uint64_t seg_addr,
2616uint32_t filetype)
2617{
2618    enum byte_sex host_byte_sex;
2619    enum bool swapped;
2620    uint32_t i, j, offset, long_word;
2621    uint64_t cur_addr;
2622    unsigned short short_word;
2623    unsigned char byte_word;
2624    LLVMDisasmContextRef arm_dc, thumb_dc, i386_dc, x86_64_dc;
2625    uint32_t n, ninsts;
2626    struct inst *insts;
2627    char *sect_start;
2628
2629	host_byte_sex = get_host_byte_sex();
2630	swapped = host_byte_sex != object_byte_sex;
2631	arm_dc = NULL;
2632	thumb_dc = NULL;
2633	i386_dc = NULL;
2634	x86_64_dc = NULL;
2635	n = 0;
2636	ninsts = 0;
2637	insts = NULL;
2638
2639	if(disassemble == TRUE){
2640	    if(pflag){
2641		for(i = 0; i < nsorted_symbols; i++){
2642		    if(strcmp(sorted_symbols[i].name, pflag) == 0)
2643			break;
2644		}
2645		if(i == nsorted_symbols){
2646		    printf("Can't find -p symbol: %s\n", pflag);
2647		    return;
2648		}
2649		if(sorted_symbols[i].n_value < addr ||
2650		   sorted_symbols[i].n_value >= addr + size){
2651		    printf("-p symbol: %s not in text section\n", pflag);
2652		    return;
2653		}
2654		offset = sorted_symbols[i].n_value - addr;
2655		sect += offset;
2656		cur_addr = sorted_symbols[i].n_value;
2657		sect_start = sect;
2658	    }
2659	    else{
2660		offset = 0;
2661		cur_addr = addr;
2662		sect_start = sect;
2663	    }
2664	    if(cputype == CPU_TYPE_ARM &&
2665	       (cpusubtype == CPU_SUBTYPE_ARM_V7 ||
2666	        cpusubtype == CPU_SUBTYPE_ARM_V7F ||
2667	        cpusubtype == CPU_SUBTYPE_ARM_V7S ||
2668	        cpusubtype == CPU_SUBTYPE_ARM_V7K)){
2669		if(sect_flags & S_SYMBOL_STUBS)
2670		    in_thumb = FALSE;
2671		else
2672		    in_thumb = TRUE;
2673	    }
2674	    else
2675		in_thumb = FALSE;
2676	    if((qflag || gflag) && cputype == CPU_TYPE_ARM){
2677		arm_dc = create_arm_llvm_disassembler(cpusubtype);
2678		if(arm_dc == NULL){
2679		    printf("can't create arm llvm disassembler\n");
2680		    return;
2681		}
2682		thumb_dc = create_thumb_llvm_disassembler(cpusubtype);
2683		if(thumb_dc == NULL){
2684		    printf("can't create thumb llvm disassembler\n");
2685		    return;
2686		}
2687		llvm_disasm_set_options(arm_dc,
2688		    LLVMDisassembler_Option_PrintImmHex);
2689		llvm_disasm_set_options(thumb_dc,
2690		    LLVMDisassembler_Option_PrintImmHex);
2691		if(eflag){
2692		    llvm_disasm_set_options(arm_dc,
2693			LLVMDisassembler_Option_UseMarkup);
2694		    llvm_disasm_set_options(thumb_dc,
2695			LLVMDisassembler_Option_UseMarkup);
2696		}
2697	    }
2698	    if((qflag || gflag) && cputype == CPU_TYPE_I386){
2699		i386_dc = create_i386_llvm_disassembler();
2700		if(i386_dc == NULL){
2701		    printf("can't create i386 llvm disassembler\n");
2702		    return;
2703		}
2704		llvm_disasm_set_options(i386_dc,
2705		    LLVMDisassembler_Option_PrintImmHex);
2706		if(nflag)
2707		    llvm_disasm_set_options(i386_dc,
2708			LLVMDisassembler_Option_AsmPrinterVariant);
2709		if(eflag)
2710		    llvm_disasm_set_options(i386_dc,
2711			LLVMDisassembler_Option_UseMarkup);
2712	    }
2713	    if((qflag || gflag) && cputype == CPU_TYPE_X86_64){
2714		x86_64_dc = create_x86_64_llvm_disassembler();
2715		if(x86_64_dc == NULL){
2716		    printf("can't create x86_64 llvm disassembler\n");
2717		    return;
2718		}
2719		llvm_disasm_set_options(x86_64_dc,
2720		    LLVMDisassembler_Option_PrintImmHex);
2721		if(nflag)
2722		    llvm_disasm_set_options(x86_64_dc,
2723			LLVMDisassembler_Option_AsmPrinterVariant);
2724		if(eflag)
2725		    llvm_disasm_set_options(x86_64_dc,
2726			LLVMDisassembler_Option_UseMarkup);
2727	    }
2728	    if(gflag){
2729		ninsts = 100;
2730		insts = allocate(sizeof(struct inst) * ninsts);
2731	    }
2732	    for(i = offset ; i < size ; ){
2733		if(gflag &&
2734		   (cputype == CPU_TYPE_X86_64 ||
2735		    cputype == CPU_TYPE_I386 ||
2736		    cputype == CPU_TYPE_ARM)){
2737		    if(n > ninsts){
2738			ninsts += ninsts;
2739			insts = reallocate(insts, sizeof(struct inst) * ninsts);
2740		    }
2741		    memset(&(insts[n]), '\0', sizeof(struct inst));
2742		    insts[n].address = cur_addr;
2743		    insts[n].label = get_label(cur_addr, sorted_symbols,
2744					       nsorted_symbols);;
2745		}
2746		else{
2747		    print_label(cur_addr, TRUE, sorted_symbols,nsorted_symbols);
2748		    if(Xflag == FALSE){
2749			if(cputype & CPU_ARCH_ABI64)
2750			    printf("%016llx", cur_addr);
2751			else
2752			    printf("%08x", (uint32_t)cur_addr);
2753			if(qflag == FALSE)
2754			    printf("\t");
2755		    }
2756		}
2757		if(cputype == CPU_TYPE_POWERPC64)
2758		    j = ppc_disassemble(sect, size - i, cur_addr, addr,
2759				object_byte_sex, relocs, nrelocs, symbols,
2760				symbols64, nsymbols, sorted_symbols,
2761				nsorted_symbols, strings, strings_size,
2762				indirect_symbols, nindirect_symbols,
2763				load_commands, ncmds, sizeofcmds, verbose);
2764		else if(cputype == CPU_TYPE_X86_64)
2765		    j = i386_disassemble(sect, size - i, cur_addr, addr,
2766				object_byte_sex, relocs, nrelocs, NULL,
2767				symbols64, nsymbols, sorted_symbols,
2768				nsorted_symbols, strings, strings_size,
2769				indirect_symbols, nindirect_symbols, cputype,
2770				load_commands, ncmds, sizeofcmds, verbose,
2771				llvm_mc, i386_dc, x86_64_dc , object_addr,
2772				object_size, &(insts[n]), NULL, 0,
2773				filetype);
2774	 	else if(cputype == CPU_TYPE_MC680x0)
2775		    j = m68k_disassemble(sect, size - i, cur_addr, addr,
2776				object_byte_sex, relocs, nrelocs, symbols,
2777				nsymbols, sorted_symbols, nsorted_symbols,
2778				strings, strings_size, indirect_symbols,
2779				nindirect_symbols, load_commands, ncmds,
2780				sizeofcmds, verbose);
2781		else if(cputype == CPU_TYPE_I860)
2782		    j = i860_disassemble(sect, size - i, cur_addr, addr,
2783				object_byte_sex, relocs, nrelocs, symbols,
2784				nsymbols, sorted_symbols, nsorted_symbols,
2785				strings, strings_size, verbose);
2786		else if(cputype == CPU_TYPE_I386)
2787		    j = i386_disassemble(sect, size - i, cur_addr, addr,
2788				object_byte_sex, relocs, nrelocs, symbols, NULL,
2789				nsymbols, sorted_symbols, nsorted_symbols,
2790				strings, strings_size, indirect_symbols,
2791				nindirect_symbols, cputype, load_commands,
2792				ncmds, sizeofcmds, verbose, llvm_mc, i386_dc,
2793				x86_64_dc, object_addr, object_size,
2794				&(insts[n]), NULL, 0, filetype);
2795		else if(cputype == CPU_TYPE_MC88000)
2796		    j = m88k_disassemble(sect, size - i, cur_addr, addr,
2797				object_byte_sex, relocs, nrelocs, symbols,
2798				nsymbols, sorted_symbols, nsorted_symbols,
2799				strings, strings_size, verbose);
2800		else if(cputype == CPU_TYPE_POWERPC ||
2801			cputype == CPU_TYPE_VEO)
2802		    j = ppc_disassemble(sect, size - i, cur_addr, addr,
2803				object_byte_sex, relocs, nrelocs, symbols,
2804				symbols64, nsymbols, sorted_symbols,
2805				nsorted_symbols, strings, strings_size,
2806				indirect_symbols, nindirect_symbols,
2807				load_commands, ncmds, sizeofcmds, verbose);
2808		else if(cputype == CPU_TYPE_HPPA)
2809		    j = hppa_disassemble(sect, size - i, cur_addr, addr,
2810				object_byte_sex, relocs, nrelocs, symbols,
2811				nsymbols, sorted_symbols, nsorted_symbols,
2812				strings, strings_size, verbose);
2813		else if(cputype == CPU_TYPE_SPARC)
2814		    j = sparc_disassemble(sect, size - i, cur_addr, addr,
2815				object_byte_sex, relocs, nrelocs, symbols,
2816				nsymbols, sorted_symbols, nsorted_symbols,
2817				strings, strings_size, indirect_symbols,
2818				nindirect_symbols, load_commands, ncmds,
2819				sizeofcmds, verbose);
2820		else if(cputype == CPU_TYPE_ARM)
2821		    j = arm_disassemble(sect, size - i, cur_addr, addr,
2822				object_byte_sex, relocs, nrelocs, symbols,
2823				nsymbols, sorted_symbols, nsorted_symbols,
2824				strings, strings_size, indirect_symbols,
2825				nindirect_symbols, load_commands, ncmds,
2826				sizeofcmds, cpusubtype, verbose, arm_dc,
2827				thumb_dc, object_addr, object_size, dices,
2828				ndices, seg_addr, &(insts[n]), NULL, 0);
2829		else{
2830		    printf("Can't disassemble unknown cputype %d\n", cputype);
2831		    return;
2832		}
2833		sect += j;
2834		cur_addr += j;
2835		i += j;
2836		if(gflag)
2837		    n++;
2838	    }
2839	    if(gflag &&
2840	       (cputype == CPU_TYPE_X86_64 ||
2841		cputype == CPU_TYPE_I386 ||
2842		cputype == CPU_TYPE_ARM)){
2843		char dst[4096];
2844		dst[4095] = '\0';
2845
2846		/* Look for inits that need tmp labels. */
2847		for(i = 0 ; i < n ; i++){
2848		    if(insts[i].has_raw_target_address){
2849			for(j = 0; j < n; j++){
2850			    if(insts[i].raw_target_address == insts[j].address)
2851				insts[j].needs_tmp_label = TRUE;
2852			}
2853		    }
2854		}
2855
2856		/* Create the needed tmp labels. */
2857		j = 1;
2858		for(i = 0 ; i < n ; i++){
2859		    if(insts[i].needs_tmp_label == TRUE){
2860			insts[i].tmp_label = allocate(20);
2861			sprintf(insts[i].tmp_label, "L%d", j++);
2862		    }
2863		}
2864
2865		/* Now finally print the inits. */
2866		for(i = 0 ; i < n ; i++){
2867		    if(insts[i].label != NULL)
2868			printf("%s:\n", insts[i].label);
2869		    else if(insts[i].tmp_label != NULL)
2870			printf("%s:", insts[i].tmp_label);
2871		    insts[i].print = TRUE;
2872		    cur_addr = insts[i].address;
2873		    offset = cur_addr - addr;
2874		    sect = sect_start + offset;
2875		    if(cputype == CPU_TYPE_X86_64 || cputype == CPU_TYPE_I386)
2876			j = i386_disassemble(sect, size - offset, cur_addr, addr,
2877				object_byte_sex, relocs, nrelocs, symbols, NULL,
2878				nsymbols, sorted_symbols, nsorted_symbols,
2879				strings, strings_size, indirect_symbols,
2880				nindirect_symbols, cputype, load_commands,
2881				ncmds, sizeofcmds, verbose, llvm_mc, i386_dc,
2882				x86_64_dc, object_addr, object_size,
2883				&(insts[i]), insts, n, filetype);
2884		    else if(cputype == CPU_TYPE_ARM)
2885			j = arm_disassemble(sect, size - offset, cur_addr, addr,
2886				    object_byte_sex, relocs, nrelocs, symbols,
2887				    nsymbols, sorted_symbols, nsorted_symbols,
2888				    strings, strings_size, indirect_symbols,
2889				    nindirect_symbols, load_commands, ncmds,
2890				    sizeofcmds, cpusubtype, verbose, arm_dc,
2891				    thumb_dc, object_addr, object_size, dices,
2892				    ndices, seg_addr, &(insts[i]), insts, n);
2893		}
2894
2895		/* Free up allocated space */
2896		for(i = 0 ; i < n ; i++){
2897		    if(insts[i].tmp_label != NULL)
2898			free(insts[i].tmp_label);
2899		}
2900		free(insts);
2901	    }
2902	    if(i386_dc != NULL)
2903		delete_arm_llvm_disassembler(i386_dc);
2904	    if(x86_64_dc != NULL)
2905		delete_arm_llvm_disassembler(x86_64_dc);
2906	    if(arm_dc != NULL)
2907		delete_arm_llvm_disassembler(arm_dc);
2908	    if(thumb_dc != NULL)
2909		delete_arm_llvm_disassembler(thumb_dc);
2910	}
2911	else{
2912	    if(cputype == CPU_TYPE_I386 || cputype == CPU_TYPE_X86_64){
2913		for(i = 0 ; i < size ; i += j , addr += j){
2914		    if(cputype & CPU_ARCH_ABI64)
2915			printf("%016llx ", addr);
2916		    else
2917			printf("%08x ", (uint32_t)addr);
2918		    for(j = 0;
2919			j < 16 * sizeof(char) && i + j < size;
2920			j += sizeof(char)){
2921			byte_word = *(sect + i + j);
2922			printf("%02x ", (unsigned int)byte_word);
2923		    }
2924		    printf("\n");
2925		}
2926	    }
2927	    else if(cputype == CPU_TYPE_MC680x0){
2928		for(i = 0 ; i < size ; i += j , addr += j){
2929		    printf("%08x ", (unsigned int)addr);
2930		    for(j = 0;
2931			j < 8 * sizeof(short) && i + j < size;
2932			j += sizeof(short)){
2933			memcpy(&short_word, sect + i + j, sizeof(short));
2934			if(swapped)
2935			    short_word = SWAP_SHORT(short_word);
2936			printf("%04x ", (unsigned int)short_word);
2937		    }
2938		    printf("\n");
2939		}
2940	    }
2941	    else{
2942		for(i = 0 ; i < size ; i += j , addr += j){
2943		    if(cputype & CPU_ARCH_ABI64)
2944			printf("%016llx ", addr);
2945		    else
2946			printf("%08x ", (uint32_t)addr);
2947		    for(j = 0;
2948			j < 4 * sizeof(int32_t) && i + j < size;
2949			j += sizeof(int32_t)){
2950			memcpy(&long_word, sect + i + j, sizeof(int32_t));
2951			if(swapped)
2952			    long_word = SWAP_INT(long_word);
2953			printf("%08x ", (unsigned int)long_word);
2954		    }
2955		    printf("\n");
2956		}
2957	    }
2958	}
2959}
2960
2961static
2962void
2963print_argstrings(
2964uint32_t magic,
2965struct load_command *load_commands,
2966uint32_t ncmds,
2967uint32_t sizeofcmds,
2968cpu_type_t cputype,
2969cpu_subtype_t cpusubtype,
2970enum byte_sex load_commands_byte_sex,
2971char *object_addr,
2972uint32_t object_size)
2973{
2974    enum byte_sex host_byte_sex;
2975    enum bool swapped;
2976    uint32_t i, len, left, size, arg;
2977    uint64_t usrstack;
2978    struct load_command *lc, l;
2979    struct segment_command sg;
2980    struct segment_command_64 sg64;
2981    char *stack, *stack_top, *p, *q, *argv;
2982    struct arch_flag arch_flags;
2983
2984	host_byte_sex = get_host_byte_sex();
2985	swapped = host_byte_sex != load_commands_byte_sex;
2986
2987	arch_flags.cputype = cputype;
2988	if(magic == MH_MAGIC_64)
2989	    arch_flags.cputype |= CPU_ARCH_ABI64;
2990	arch_flags.cpusubtype = cpusubtype;
2991	usrstack = get_stack_addr_from_flag(&arch_flags);
2992	if(usrstack == 0){
2993	    printf("Don't know the value of USRSTACK for unknown cputype "
2994		   "(%d)\n", cputype);
2995	    return;
2996	}
2997	printf("Argument strings on the stack at: ");
2998	if(cputype & CPU_ARCH_ABI64 || magic == MH_MAGIC_64)
2999	    printf("%016llx\n", usrstack);
3000	else
3001	    printf("%08x\n", (uint32_t)usrstack);
3002	lc = load_commands;
3003	for(i = 0 ; i < ncmds; i++){
3004	    memcpy((char *)&l, (char *)lc, sizeof(struct load_command));
3005	    if(swapped)
3006		swap_load_command(&l, host_byte_sex);
3007	    if(cputype & CPU_ARCH_ABI64 || magic == MH_MAGIC_64){
3008		if(l.cmdsize % 8 != 0)
3009		    printf("load command %u size not a multiple of 8\n", i);
3010	    }
3011	    else{
3012		if(l.cmdsize % 4 != 0)
3013		    printf("load command %u size not a multiple of 4\n", i);
3014	    }
3015	    if((char *)lc + l.cmdsize >
3016	       (char *)load_commands + sizeofcmds)
3017		printf("load command %u extends past end of load "
3018		       "commands\n", i);
3019	    left = sizeofcmds - ((char *)lc - (char *)load_commands);
3020
3021	    switch(l.cmd){
3022	    case LC_SEGMENT:
3023		memset((char *)&sg, '\0', sizeof(struct segment_command));
3024		size = left < sizeof(struct segment_command) ?
3025		       left : sizeof(struct segment_command);
3026		memcpy((char *)&sg, (char *)lc, size);
3027		if(swapped)
3028		    swap_segment_command(&sg, host_byte_sex);
3029
3030		if(cputype == CPU_TYPE_HPPA){
3031		    if(sg.vmaddr == usrstack &&
3032		       sg.fileoff + sg.filesize <= object_size){
3033			stack = object_addr + sg.fileoff;
3034			stack_top = stack + sg.filesize;
3035			/*
3036			 * There appears to be some pointer then argc at the
3037			 * bottom of the stack first before argv[].
3038			 */
3039			argv = stack + 2 * sizeof(uint32_t);
3040			memcpy(&arg, argv, sizeof(uint32_t));
3041			if(swapped)
3042			    arg = SWAP_INT(arg);
3043			while(argv < stack_top &&
3044			      arg != 0 &&
3045			      arg >= usrstack && arg < usrstack + sg.filesize){
3046			    p = stack + (arg - usrstack);
3047			    printf("\t");
3048			    while(p < stack_top && *p != '\0'){
3049				printf("%c", *p);
3050				p++;
3051			    }
3052			    printf("\n");
3053			    argv += sizeof(uint32_t);
3054			    memcpy(&arg, argv, sizeof(uint32_t));
3055			    if(swapped)
3056				arg = SWAP_INT(arg);
3057			}
3058			/* after argv[] then there is envp[] */
3059			argv += sizeof(uint32_t);
3060			memcpy(&arg, argv, sizeof(uint32_t));
3061			if(swapped)
3062			    arg = SWAP_INT(arg);
3063			while(argv < stack_top &&
3064			      arg != 0 &&
3065			      arg >= usrstack && arg < usrstack + sg.filesize){
3066			    p = stack + (arg - usrstack);
3067			    printf("\t");
3068			    while(p < stack_top && *p != '\0'){
3069				printf("%c", *p);
3070				p++;
3071			    }
3072			    printf("\n");
3073			    argv += sizeof(uint32_t);
3074			    memcpy(&arg, argv, sizeof(uint32_t));
3075			    if(swapped)
3076				arg = SWAP_INT(arg);
3077			}
3078		    }
3079		}
3080		else{
3081		    if(sg.vmaddr + sg.vmsize == usrstack &&
3082		       sg.fileoff + sg.filesize <= object_size){
3083			stack = object_addr + sg.fileoff;
3084			stack_top = stack + sg.filesize;
3085
3086			/* the first thing on the stack is a long 0 */
3087			stack_top -= 4;
3088			p = (char *)stack_top;
3089
3090			/* find the first non-null character before the long 0*/
3091			while(p > stack && *p == '\0')
3092			    p--;
3093			if(p != (char *)stack_top)
3094			    p++;
3095
3096			q = p;
3097			/* Stop when we find another long 0 */
3098			while(p > stack && (*p != '\0' || *(p-1) != '\0' ||
3099			      *(p-2) != '\0' || *(p-3) != '\0')){
3100			    p--;
3101			    /* step back over the string to its start */
3102			    while(p > stack && *p != '\0')
3103				p--;
3104			}
3105
3106			p++; /* step forward to the start of the first string */
3107			while(p < q){
3108			    printf("\t");
3109			    len = 0;
3110			    while(p + len < q && p[len] != '\0'){
3111				printf("%c", p[len]);
3112				len++;
3113			    }
3114			    printf("\n");
3115			    p += len + 1;
3116			}
3117			return;
3118		    }
3119		}
3120		break;
3121	    case LC_SEGMENT_64:
3122		memset((char *)&sg64, '\0', sizeof(struct segment_command_64));
3123		size = left < sizeof(struct segment_command_64) ?
3124		       left : sizeof(struct segment_command_64);
3125		memcpy((char *)&sg64, (char *)lc, size);
3126		if(swapped)
3127		    swap_segment_command_64(&sg64, host_byte_sex);
3128		if(sg64.vmaddr + sg64.vmsize == usrstack &&
3129		   sg64.fileoff + sg64.filesize <= object_size){
3130		    stack = object_addr + sg64.fileoff;
3131		    stack_top = stack + sg64.filesize;
3132
3133		    /* the first thing on the stack is a uint64_t 0 */
3134		    stack_top -= 8;
3135		    p = (char *)stack_top;
3136
3137		    /* find the first non-null character before the uint64_t 0*/
3138		    while(p > stack && *p == '\0')
3139			p--;
3140		    if(p != (char *)stack_top)
3141			p++;
3142
3143		    q = p;
3144		    /* Stop when we find another uint64_t 0 */
3145		    while(p > stack && (*p != '\0' || *(p-1) != '\0' ||
3146			  *(p-2) != '\0' || *(p-3) != '\0' || *(p-4) != '\0' ||
3147			  *(p-5) != '\0' || *(p-6) != '\0' || *(p-7) != '\0')){
3148			p--;
3149			/* step back over the string to its start */
3150			while(p > stack && *p != '\0')
3151			    p--;
3152		    }
3153
3154		    p++; /* step forward to the start of the first string */
3155		    while(p < q){
3156			printf("\t");
3157			len = 0;
3158			while(p + len < q && p[len] != '\0'){
3159			    printf("%c", p[len]);
3160			    len++;
3161			}
3162			printf("\n");
3163			p += len + 1;
3164		    }
3165		    return;
3166		}
3167		break;
3168	    }
3169
3170	    if(l.cmdsize == 0){
3171		printf("load command %u size zero (can't advance to other "
3172		       "load commands)\n", i);
3173		break;
3174	    }
3175	    lc = (struct load_command *)((char *)lc + l.cmdsize);
3176	    if((char *)lc > (char *)load_commands + sizeofcmds)
3177		break;
3178	}
3179}
3180
3181#ifndef __DYNAMIC__
3182/*
3183 * To avoid linking in libm.  These variables are defined as they are used in
3184 * pthread_init() to put in place a fast sqrt().
3185 */
3186size_t hw_sqrt_len = 0;
3187
3188double
3189sqrt(double x)
3190{
3191	return(0.0);
3192}
3193double
3194hw_sqrt(double x)
3195{
3196	return(0.0);
3197}
3198
3199/*
3200 * More stubs to avoid linking in libm.  This works as along as we don't use
3201 * long doubles.
3202 */
3203int32_t
3204__fpclassifyd(double x)
3205{
3206	return(0);
3207}
3208int32_t
3209__fpclassify(long double x)
3210{
3211	return(0);
3212}
3213#endif /* !defined(__DYNAMIC__) */
3214