1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23#include <stdint.h>
24#import <stdio.h>
25#import <stdlib.h>
26#import <string.h>
27#import "stuff/ofile.h"
28#import "stuff/errors.h"
29#import "stuff/allocate.h"
30
31enum file_part_type {
32    FP_FAT_HEADERS,
33    FP_MACH_O,
34    FP_EMPTY_SPACE
35};
36char *file_part_type_names[] = {
37    "FP_FAT_HEADERS",
38    "FP_MACH_O",
39    "FP_EMPTY_SPACE"
40};
41
42struct file_part {
43    uint64_t offset;
44    uint64_t size;
45    enum file_part_type type;
46    struct mach_o_part *mp;
47    struct mach_header *mh;
48    struct mach_header_64 *mh64;
49    struct symtab_command *st;
50    struct nlist *symbols;
51    struct nlist_64 *symbols64;
52    char *strings;
53    struct file_part *prev;
54    struct file_part *next;
55};
56struct file_part *file_parts = NULL;
57
58enum mach_o_part_type {
59    MP_MACH_HEADERS,
60    MP_SECTION,
61    MP_SECTION_64,
62    MP_RELOCS,
63    MP_RELOCS_64,
64    MP_LOCAL_SYMBOLS,
65    MP_EXTDEF_SYMBOLS,
66    MP_UNDEF_SYMBOLS,
67    MP_TOC,
68    MP_MODULE_TABLE,
69    MP_REFERENCE_TABLE,
70    MP_INDIRECT_SYMBOL_TABLE,
71    MP_EXT_RELOCS,
72    MP_LOC_RELOCS,
73    MP_SPLIT_INFO,
74    MP_SYMBOL_TABLE,
75    MP_HINTS_TABLE,
76    MP_STRING_TABLE,
77    MP_EXT_STRING_TABLE,
78    MP_LOC_STRING_TABLE,
79    MP_CODE_SIG,
80    MP_FUNCTION_STARTS,
81    MP_DATA_IN_CODE,
82    MP_CODE_SIGN_DRS,
83    MP_DYLD_INFO_REBASE,
84    MP_DYLD_INFO_BIND,
85    MP_DYLD_INFO_WEAK_BIND,
86    MP_DYLD_INFO_LAZY_BIND,
87    MP_DYLD_INFO_EXPORT,
88    MP_EMPTY_SPACE
89};
90static char *mach_o_part_type_names[] = {
91    "MP_MACH_HEADERS",
92    "MP_SECTION",
93    "MP_SECTION_64",
94    "MP_RELOCS",
95    "MP_RELOCS_64",
96    "MP_LOCAL_SYMBOLS",
97    "MP_EXTDEF_SYMBOLS",
98    "MP_UNDEF_SYMBOLS",
99    "MP_TOC",
100    "MP_MODULE_TABLE",
101    "MP_REFERENCE_TABLE",
102    "MP_INDIRECT_SYMBOL_TABLE",
103    "MP_EXT_RELOCS",
104    "MP_LOC_RELOCS",
105    "MP_SPLIT_INFO",
106    "MP_SYMBOL_TABLE",
107    "MP_HINTS_TABLE",
108    "MP_STRING_TABLE",
109    "MP_EXT_STRING_TABLE",
110    "MP_LOC_STRING_TABLE",
111    "MP_CODE_SIG",
112    "MP_FUNCTION_STARTS",
113    "MP_DATA_IN_CODE",
114    "MP_CODE_SIGN_DRS",
115    "MP_DYLD_INFO_REBASE",
116    "MP_DYLD_INFO_BIND",
117    "MP_DYLD_INFO_WEAK_BIND",
118    "MP_DYLD_INFO_LAZY_BIND",
119    "MP_DYLD_INFO_EXPORT",
120    "MP_EMPTY_SPACE"
121};
122
123struct mach_o_part {
124    uint64_t offset;
125    uint64_t size;
126    enum mach_o_part_type type;
127    struct section *s;
128    struct section_64 *s64;
129    struct mach_o_part *prev;
130    struct mach_o_part *next;
131};
132
133/* The name of the program for error messages */
134char *progname = NULL;
135
136/* The ofile for the Mach-O file argument to the program */
137static struct ofile ofile;
138
139/* The -arch flag if any, and its offset and size in the file */
140static struct arch_flag *arch_flag = NULL;
141uint64_t arch_offset = 0;
142uint64_t arch_size = 0;
143enum bool arch_found = FALSE;
144
145static struct nlist *sorted_symbols = NULL;
146static struct nlist_64 *sorted_symbols64 = NULL;
147
148static void usage(void);
149
150static void create_file_parts(
151    char *file_name);
152static struct file_part *new_file_part(
153    void);
154static void insert_file_part(
155    struct file_part *new);
156static void print_file_parts(
157    void);
158
159static void create_mach_o_parts(
160    struct file_part *fp);
161static struct mach_o_part *new_mach_o_part(
162    void);
163static void insert_mach_o_part(
164    struct file_part *fp,
165    struct mach_o_part *new);
166static void print_mach_o_parts(
167    struct mach_o_part *mp);
168
169static void print_parts_for_page(
170    uint32_t page_number);
171static void print_arch(
172    struct file_part *fp);
173static void print_file_part(
174    struct file_part *fp);
175static void print_mach_o_part(
176    struct mach_o_part *mp);
177static void print_symbols(
178    struct file_part *fp,
179    uint64_t low_addr,
180    uint64_t high_addr);
181static void print_symbols64(
182    struct file_part *fp,
183    uint64_t low_addr,
184    uint64_t high_addr);
185static int compare(
186    struct nlist *p1,
187    struct nlist *p2);
188static int compare64(
189    struct nlist_64 *p1,
190    struct nlist_64 *p2);
191
192/* apple_version is created by the libstuff/Makefile */
193extern char apple_version[];
194char *version = apple_version;
195
196/*
197 * pagestuff is invoked as follows:
198 *
199 *	% pagestuff mach-o [-arch name] [-p] [-a] pagenumber [pagenumber ...]
200 *
201 * It prints out what stuff is on the page numbers listed.
202 */
203int
204main(
205int argc,
206char *argv[])
207{
208    int i, start;
209    uint32_t j, page_number;
210    char *endp;
211    struct arch_flag a;
212
213	progname = argv[0];
214	if(argc < 3)
215	    usage();
216	start = 2;
217
218	if(strcmp(argv[start], "-arch") == 0){
219	    if(start + 1 == argc){
220		error("missing argument to -arch option");
221		exit(EXIT_FAILURE);
222	    }
223	    if(get_arch_from_flag(argv[start+1], &a) == 0){
224		error("unknown architecture specification flag: "
225		      "%s %s", argv[start], argv[start+1]);
226		exit(EXIT_FAILURE);
227	    }
228	    arch_flag = &a;
229	    start += 2;
230	    if(argc < 5)
231		usage();
232        }
233
234	create_file_parts(argv[1]);
235	if(arch_flag != NULL && arch_found == FALSE){
236	    error("file: %s does not contain architecture: %s", argv[1],
237		  arch_flag->name);
238	    exit(EXIT_FAILURE);
239	}
240	if(strcmp(argv[start], "-p") == 0){
241	    print_file_parts();
242	    start++;
243	}
244	if(errors)
245	    exit(EXIT_FAILURE);
246	if(start >= argc)
247	    exit(EXIT_SUCCESS);
248
249	if(strcmp(argv[start], "-a") == 0){
250	    if(arch_flag == NULL)
251		page_number = (ofile.file_size + vm_page_size - 1) /
252			      vm_page_size;
253	    else
254		page_number = (arch_size + vm_page_size - 1) /
255			      vm_page_size;
256	    for(j = 0; j < page_number; j++){
257		print_parts_for_page(j);
258	    }
259	    start++;
260	}
261	if(start >= argc)
262	    exit(EXIT_SUCCESS);
263
264	for(i = start; i < argc; i++){
265	    page_number = strtoul(argv[i], &endp, 10);
266	    if(*endp != '\0')
267		fatal("page number argument: %s is not a proper unsigned "
268		      "number", argv[i]);
269	    print_parts_for_page(page_number);
270	}
271
272	return(EXIT_SUCCESS);
273}
274
275static
276void
277usage(void)
278{
279	fprintf(stderr, "Usage: %s mach-o [-arch name] [-p] [-a] "
280		"pagenumber [pagenumber ...]\n",
281		progname);
282	exit(EXIT_FAILURE);
283}
284
285static
286void
287create_file_parts(
288char *file_name)
289{
290    static struct file_part *fp;
291
292	if(ofile_map(file_name, arch_flag, NULL, &ofile, FALSE) == FALSE)
293	    exit(EXIT_FAILURE);
294
295	/* first create an empty space for the whole file */
296	fp = new_file_part();
297	fp->offset = 0;
298	fp->size = ofile.file_size;
299	fp->type = FP_EMPTY_SPACE;
300	file_parts = fp;
301
302	if(ofile.file_type == OFILE_FAT){
303	    fp = new_file_part();
304	    fp->offset = 0;
305	    fp->size = sizeof(struct fat_header) +
306		       ofile.fat_header->nfat_arch * sizeof(struct fat_arch);
307	    fp->type = FP_FAT_HEADERS;
308	    insert_file_part(fp);
309
310	    (void)ofile_first_arch(&ofile);
311	    do{
312		if(ofile.arch_type == OFILE_ARCHIVE){
313		    error("for architecture: %s file: %s is an archive (not "
314			"supported with %s)", ofile.arch_flag.name, file_name,
315			progname);
316		}
317		else if(ofile.arch_type == OFILE_Mach_O){
318		    if(arch_flag != NULL && arch_found == FALSE &&
319		       arch_flag->cputype == ofile.mh_cputype &&
320		       (arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) ==
321			(ofile.mh_cpusubtype & ~CPU_SUBTYPE_MASK)){
322			arch_offset = ofile.fat_archs[ofile.narch].offset;
323			arch_size = ofile.fat_archs[ofile.narch].size;
324			arch_found = TRUE;
325		    }
326		    /* make mach-o parts for this */
327		    fp = new_file_part();
328		    fp->offset = ofile.fat_archs[ofile.narch].offset;
329		    fp->size = ofile.fat_archs[ofile.narch].size;
330		    fp->type = FP_MACH_O;
331		    insert_file_part(fp);
332		    create_mach_o_parts(fp);
333		}
334		else if(ofile.arch_type == OFILE_UNKNOWN){
335		    error("for architecture: %s file: %s is not an object file "
336			"(not supported with %s)", ofile.arch_flag.name,
337			file_name, progname);
338		}
339	    }while(ofile_next_arch(&ofile) == TRUE);
340	}
341	else if(ofile.file_type == OFILE_ARCHIVE){
342	    error("file: %s is an archive (not supported with %s)", file_name,
343		progname);
344	}
345	else if(ofile.file_type == OFILE_Mach_O){
346	    if(arch_flag != NULL && arch_found == FALSE &&
347	       arch_flag->cputype == ofile.mh_cputype &&
348	       (arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) ==
349		(ofile.mh_cpusubtype & ~CPU_SUBTYPE_MASK)){
350		arch_offset = 0;
351		arch_size = ofile.file_size;
352		arch_found = TRUE;
353	    }
354	    /* make mach-o parts for this */
355	    fp = new_file_part();
356	    fp->offset = 0;
357	    fp->size = ofile.file_size;
358	    fp->type = FP_MACH_O;
359	    insert_file_part(fp);
360	    create_mach_o_parts(fp);
361	}
362	else{ /* ofile.file_type == OFILE_UNKNOWN */
363	    error("file: %s is not an object file (not supported with %s)",
364		file_name, progname);
365	}
366}
367
368static
369struct file_part *
370new_file_part(
371void)
372{
373    struct file_part *fp;
374
375	fp = allocate(sizeof(struct file_part));
376	memset(fp, '\0', sizeof(struct file_part));
377	return(fp);
378}
379
380static
381void
382insert_file_part(
383struct file_part *new)
384{
385    struct file_part *p, *q;
386
387	for(p = file_parts; p != NULL; p = p->next){
388	    /* find an existing part that contains the new part */
389	    if(new->offset >= p->offset &&
390	       new->offset + new->size <= p->offset + p->size){
391		if(p->type != FP_EMPTY_SPACE)
392		    fatal("internal error: new file part not contained in "
393			"empty space");
394		/* if new is the same as p replace p with new */
395		if(new->offset == p->offset &&
396	           new->size == p->size){
397		    new->prev = p->prev;
398		    new->next = p->next;
399		    if(p->next != NULL)
400			p->next->prev = new;
401		    if(p->prev != NULL)
402			p->prev->next = new;
403		    if(file_parts == p)
404			file_parts = new;
405		    free(p);
406		    return;
407		}
408		/* if new starts at p put new before p and move p's offset */
409		if(new->offset == p->offset){
410		    p->offset = new->offset + new->size;
411		    p->size = p->size - new->size;
412		    if(p->prev != NULL)
413			p->prev->next = new;
414		    new->prev = p->prev;
415		    p->prev = new;
416		    new->next = p;
417		    if(file_parts == p)
418			file_parts = new;
419		    return;
420		}
421		/* if new ends at p put new after p and change p's size */
422		if(new->offset + new->size == p->offset + p->size){
423		    p->size = new->offset - p->offset;
424		    new->next = p->next;
425		    if(p->next != NULL)
426			p->next->prev = new;
427		    p->next = new;
428		    new->prev = p;
429		    return;
430		}
431		/* new is in the middle of p */
432		q = new_file_part();
433		q->type = FP_EMPTY_SPACE;
434		q->offset = new->offset + new->size;
435		q->size = p->offset + p->size - (new->offset + new->size);
436		p->size = new->offset - p->offset;
437		new->prev = p;
438		new->next = q;
439		q->prev = new;
440		q->next = p->next;
441		if(p->next != NULL)
442		    p->next->prev = q;
443		p->next = new;
444		return;
445	    }
446	}
447	fatal("internal error: new file part not found in existing part");
448}
449
450static
451void
452print_file_parts(
453void)
454{
455    struct file_part *p, *prev;
456    uint64_t offset;
457
458	prev = NULL;
459	offset = 0;
460	for(p = file_parts; p != NULL; p = p->next){
461	    if(arch_flag == NULL){
462		printf("%s\n", file_part_type_names[p->type]);
463		printf("    offset = %llu\n", p->offset);
464		printf("    size = %llu\n", p->size);
465	    }
466	    if(prev != NULL)
467		if(prev != p->prev)
468		    printf("bad prev pointer\n");
469	    prev = p;
470	    if(offset != p->offset)
471		    printf("bad offset\n");
472	    offset += p->size;
473	    if(p->type == FP_MACH_O){
474		if(arch_flag == NULL || p->offset == arch_offset)
475		    print_mach_o_parts(p->mp);
476	    }
477	}
478}
479
480static
481void
482create_mach_o_parts(
483struct file_part *fp)
484{
485    uint32_t i, j;
486    uint32_t ncmds, filetype;
487    struct mach_o_part *mp;
488    struct load_command *lc;
489    struct symtab_command *st;
490    struct dysymtab_command *dyst;
491    struct dyld_info_command *dyld_info;
492    struct twolevel_hints_command *hints;
493    struct segment_command *sg;
494    struct segment_command_64 *sg64;
495    struct section *s;
496    struct section_64 *s64;
497    struct nlist *allocated_symbols, *symbols;
498    struct nlist_64 *allocated_symbols64, *symbols64;
499    uint32_t ext_low, ext_high, local_low, local_high, n_strx, n_type;
500    char *strings;
501    struct dylib_module *modtab;
502    struct dylib_module_64 *modtab64;
503    struct linkedit_data_command *split_info, *code_sig, *func_starts,
504			         *data_in_code, *code_sign_drs;
505    enum bool dylib_stub;
506
507	mp = new_mach_o_part();
508	mp->offset = fp->offset;
509	mp->size = ofile.object_size;
510	mp->type = MP_EMPTY_SPACE;
511	fp->mp = mp;
512
513	mp = new_mach_o_part();
514	mp->offset = fp->offset;
515	if(ofile.mh != NULL){
516	    fp->mh = ofile.mh;
517	    fp->mh64 = NULL;
518	    mp->size = sizeof(struct mach_header) + ofile.mh->sizeofcmds;
519	    ncmds = ofile.mh->ncmds;
520	    dylib_stub = ofile.mh->filetype == MH_DYLIB_STUB;
521	}
522	else{
523	    fp->mh64 = ofile.mh64;
524	    fp->mh = NULL;
525	    mp->size = sizeof(struct mach_header_64) + ofile.mh64->sizeofcmds;
526	    ncmds = ofile.mh64->ncmds;
527	    dylib_stub = ofile.mh64->filetype == MH_DYLIB_STUB;
528	}
529	mp->type = MP_MACH_HEADERS;
530	insert_mach_o_part(fp, mp);
531
532
533	st = NULL;
534	dyst = NULL;
535	dyld_info = NULL;
536	hints = NULL;
537	symbols = NULL;
538	symbols64 = NULL;
539	strings = NULL;
540	split_info = NULL;
541	code_sig = NULL;
542	func_starts = NULL;
543	data_in_code = NULL;
544	code_sign_drs = NULL;
545
546	lc = ofile.load_commands;
547	for(i = 0; i < ncmds; i++){
548	    if(st == NULL && lc->cmd == LC_SYMTAB){
549		st = (struct symtab_command *)lc;
550	    }
551	    else if(dyst == NULL && lc->cmd == LC_DYSYMTAB){
552		dyst = (struct dysymtab_command *)lc;
553	    }
554	    else if(dyld_info == NULL && lc->cmd == LC_DYLD_INFO_ONLY){
555		dyld_info = (struct dyld_info_command *)lc;
556	    }
557	    else if(hints == NULL && lc->cmd == LC_TWOLEVEL_HINTS){
558		hints = (struct twolevel_hints_command *)lc;
559	    }
560	    else if(split_info == NULL && lc->cmd == LC_SEGMENT_SPLIT_INFO){
561		split_info = (struct linkedit_data_command *)lc;
562	    }
563	    else if(code_sig == NULL && lc->cmd == LC_CODE_SIGNATURE){
564		code_sig = (struct linkedit_data_command *)lc;
565	    }
566	    else if(func_starts == NULL && lc->cmd == LC_FUNCTION_STARTS){
567		func_starts = (struct linkedit_data_command *)lc;
568	    }
569	    else if(data_in_code == NULL && lc->cmd == LC_DATA_IN_CODE){
570		data_in_code = (struct linkedit_data_command *)lc;
571	    }
572	    else if(code_sign_drs == NULL && lc->cmd == LC_DYLIB_CODE_SIGN_DRS){
573		code_sign_drs = (struct linkedit_data_command *)lc;
574	    }
575	    else if(lc->cmd == LC_SEGMENT && dylib_stub == FALSE){
576		sg = (struct segment_command *)lc;
577		s = (struct section *)
578		      ((char *)sg + sizeof(struct segment_command));
579		for(j = 0; j < sg->nsects; j++){
580		    if(s->nreloc != 0){
581			mp = new_mach_o_part();
582			mp->offset = fp->offset + s->reloff;
583			mp->size = s->nreloc * sizeof(struct relocation_info);
584			mp->type = MP_RELOCS;
585			mp->s = s;
586			mp->s64 = NULL;
587			insert_mach_o_part(fp, mp);
588		    }
589		    if((s->flags & SECTION_TYPE) != S_ZEROFILL &&
590		       (s->flags & SECTION_TYPE) != S_THREAD_LOCAL_ZEROFILL &&
591		       s->size != 0){
592			mp = new_mach_o_part();
593			mp->offset = fp->offset + s->offset;
594			mp->size = s->size;
595			mp->type = MP_SECTION;
596			mp->s = s;
597			mp->s64 = NULL;
598			insert_mach_o_part(fp, mp);
599		    }
600		    if(((s->flags & SECTION_TYPE) == S_ZEROFILL ||
601			(s->flags & SECTION_TYPE) == S_THREAD_LOCAL_ZEROFILL) &&
602		       s->size != 0){
603			if(s->addr - sg->vmaddr < sg->filesize){
604			    mp = new_mach_o_part();
605			    mp->offset = fp->offset + sg->fileoff +
606					 s->addr - sg->vmaddr;
607			    if(s->addr - sg->vmaddr + s->size <= sg->filesize)
608				mp->size = s->size;
609			    else
610				mp->size = sg->filesize -(s->addr - sg->vmaddr);
611			    mp->type = MP_SECTION;
612			    mp->s = s;
613			    mp->s64 = NULL;
614			    insert_mach_o_part(fp, mp);
615			}
616		    }
617		    s++;
618		}
619	    }
620	    else if(lc->cmd == LC_SEGMENT_64 && dylib_stub == FALSE){
621		sg64 = (struct segment_command_64 *)lc;
622		s64 = (struct section_64 *)
623		      ((char *)sg64 + sizeof(struct segment_command_64));
624		for(j = 0; j < sg64->nsects; j++){
625		    if(s64->nreloc != 0){
626			mp = new_mach_o_part();
627			mp->offset = fp->offset + s64->reloff;
628			mp->size = s64->nreloc * sizeof(struct relocation_info);
629			mp->type = MP_RELOCS_64;
630			mp->s64 = s64;
631			mp->s = NULL;
632			insert_mach_o_part(fp, mp);
633		    }
634		    if((s64->flags & SECTION_TYPE) != S_ZEROFILL &&
635		       (s64->flags & SECTION_TYPE) != S_THREAD_LOCAL_ZEROFILL &&
636		       s64->size != 0){
637			mp = new_mach_o_part();
638			mp->offset = fp->offset + s64->offset;
639			mp->size = s64->size;
640			mp->type = MP_SECTION_64;
641			mp->s64 = s64;
642			mp->s = NULL;
643			insert_mach_o_part(fp, mp);
644		    }
645		    if(((s64->flags & SECTION_TYPE) == S_ZEROFILL ||
646			(s64->flags & SECTION_TYPE) ==
647						    S_THREAD_LOCAL_ZEROFILL) &&
648		       s64->size != 0){
649			if(s64->addr - sg64->vmaddr < sg64->filesize){
650			    mp = new_mach_o_part();
651			    mp->offset = fp->offset + sg64->fileoff +
652					 s64->addr - sg64->vmaddr;
653			    if(s64->addr - sg64->vmaddr + s64->size <=
654			       sg64->filesize)
655				mp->size = s64->size;
656			    else
657				mp->size = sg64->filesize -
658					   (s64->addr - sg64->vmaddr);
659			    mp->type = MP_SECTION_64;
660			    mp->s64 = s64;
661			    mp->s = NULL;
662			    insert_mach_o_part(fp, mp);
663			}
664		    }
665		    s64++;
666		}
667	    }
668	    lc = (struct load_command *)((char *)lc + lc->cmdsize);
669	}
670	if(st != NULL){
671	    if(ofile.mh != NULL){
672		allocated_symbols = NULL;
673		symbols = (struct nlist *)(ofile.object_addr + st->symoff);
674		if(ofile.object_byte_sex != get_host_byte_sex()){
675		    allocated_symbols = allocate(sizeof(struct nlist) *
676						 st->nsyms);
677		    memcpy(allocated_symbols, symbols,
678			   sizeof(struct nlist) * st->nsyms);
679		    swap_nlist(allocated_symbols, st->nsyms,
680			       get_host_byte_sex());
681		    symbols = allocated_symbols;
682		}
683		fp->symbols = symbols;
684		fp->symbols64 = NULL;
685	    }
686	    else{
687		allocated_symbols64 = NULL;
688		symbols64 = (struct nlist_64 *)(ofile.object_addr + st->symoff);
689		if(ofile.object_byte_sex != get_host_byte_sex()){
690		    allocated_symbols64 = allocate(sizeof(struct nlist_64) *
691						   st->nsyms);
692		    memcpy(allocated_symbols64, symbols64,
693			   sizeof(struct nlist_64) * st->nsyms);
694		    swap_nlist_64(allocated_symbols64, st->nsyms,
695			       get_host_byte_sex());
696		    symbols64 = allocated_symbols64;
697		}
698		fp->symbols64 = symbols64;
699		fp->symbols = NULL;
700	    }
701	    strings = ofile.object_addr + st->stroff;
702	    fp->st = st;
703	    fp->strings = strings;
704	}
705
706	if(dyst != NULL && st != NULL){
707	    if(dyst->nlocalsym != 0){
708		mp = new_mach_o_part();
709		if(ofile.mh != NULL){
710		    mp->offset = fp->offset + st->symoff +
711				 dyst->ilocalsym * sizeof(struct nlist);
712		    mp->size = dyst->nlocalsym * sizeof(struct nlist);
713		}
714		else{
715		    mp->offset = fp->offset + st->symoff +
716				 dyst->ilocalsym * sizeof(struct nlist_64);
717		    mp->size = dyst->nlocalsym * sizeof(struct nlist_64);
718		}
719		mp->type = MP_LOCAL_SYMBOLS;
720		insert_mach_o_part(fp, mp);
721	    }
722	    if(dyst->nextdefsym != 0){
723		mp = new_mach_o_part();
724		if(ofile.mh != NULL){
725		    mp->offset = fp->offset + st->symoff +
726				 dyst->iextdefsym * sizeof(struct nlist);
727		    mp->size = dyst->nextdefsym * sizeof(struct nlist);
728		}
729		else{
730		    mp->offset = fp->offset + st->symoff +
731				 dyst->iextdefsym * sizeof(struct nlist_64);
732		    mp->size = dyst->nextdefsym * sizeof(struct nlist_64);
733		}
734		mp->type = MP_EXTDEF_SYMBOLS;
735		insert_mach_o_part(fp, mp);
736	    }
737	    if(dyst->nundefsym != 0){
738		mp = new_mach_o_part();
739		if(ofile.mh != NULL){
740		    mp->offset = fp->offset + st->symoff +
741				 dyst->iundefsym * sizeof(struct nlist);
742		    mp->size = dyst->nundefsym * sizeof(struct nlist);
743		}
744		else{
745		    mp->offset = fp->offset + st->symoff +
746				 dyst->iundefsym * sizeof(struct nlist_64);
747		    mp->size = dyst->nundefsym * sizeof(struct nlist_64);
748		}
749		mp->type = MP_UNDEF_SYMBOLS;
750		insert_mach_o_part(fp, mp);
751	    }
752	    if(hints != NULL && hints->nhints != 0){
753		mp = new_mach_o_part();
754		mp->offset = fp->offset + hints->offset;
755		mp->size = hints->nhints *
756			   sizeof(struct twolevel_hint);
757		mp->type = MP_HINTS_TABLE;
758		insert_mach_o_part(fp, mp);
759	    }
760	    if(split_info != NULL && split_info->datasize != 0){
761		mp = new_mach_o_part();
762		mp->offset = fp->offset + split_info->dataoff;
763		mp->size = split_info->datasize;
764		mp->type = MP_SPLIT_INFO;
765		insert_mach_o_part(fp, mp);
766	    }
767	    if(dyst->ntoc != 0){
768		mp = new_mach_o_part();
769		mp->offset = fp->offset + dyst->tocoff;
770		mp->size = dyst->ntoc * sizeof(struct dylib_table_of_contents);
771		mp->type = MP_TOC;
772		insert_mach_o_part(fp, mp);
773	    }
774	    if(dyst->nmodtab != 0){
775		mp = new_mach_o_part();
776		mp->offset = fp->offset + dyst->modtaboff;
777		if(ofile.mh != NULL)
778		    mp->size = dyst->nmodtab * sizeof(struct dylib_module);
779		else
780		    mp->size = dyst->nmodtab * sizeof(struct dylib_module_64);
781		mp->type = MP_MODULE_TABLE;
782		insert_mach_o_part(fp, mp);
783	    }
784	    if(dyst->nextrefsyms != 0){
785		mp = new_mach_o_part();
786		mp->offset = fp->offset + dyst->extrefsymoff;
787		mp->size = dyst->nextrefsyms * sizeof(struct dylib_reference);
788		mp->type = MP_REFERENCE_TABLE;
789		insert_mach_o_part(fp, mp);
790	    }
791	    if(dyst->nindirectsyms != 0){
792		mp = new_mach_o_part();
793		mp->offset = fp->offset + dyst->indirectsymoff;
794		mp->size = dyst->nindirectsyms * sizeof(uint32_t);
795		mp->type = MP_INDIRECT_SYMBOL_TABLE;
796		insert_mach_o_part(fp, mp);
797	    }
798	    if(dyst->nextrel != 0){
799		mp = new_mach_o_part();
800		mp->offset = fp->offset + dyst->extreloff;
801		mp->size = dyst->nextrel * sizeof(struct relocation_info);
802		mp->type = MP_EXT_RELOCS;
803		insert_mach_o_part(fp, mp);
804	    }
805	    if(dyst->nlocrel != 0){
806		mp = new_mach_o_part();
807		mp->offset = fp->offset + dyst->locreloff;
808		mp->size = dyst->nlocrel * sizeof(struct relocation_info);
809		mp->type = MP_LOC_RELOCS;
810		insert_mach_o_part(fp, mp);
811	    }
812	    if(dyst->nlocalsym != 0 &&
813	       (dyst->nextdefsym != 0 || dyst->nundefsym != 0)){
814		/*
815		 * Try to break the string table into the local and external
816		 * parts knowing the tools should put all the external strings
817		 * first and all the local string last.
818		 */
819		ext_low = st->strsize;
820		local_low = st->strsize;
821		ext_high = 0;
822		local_high = 0;
823		for(i = 0; i < st->nsyms; i++){
824		    if(ofile.mh != NULL){
825			n_strx = symbols[i].n_un.n_strx;
826			n_type = symbols[i].n_type;
827		        filetype = fp->mh->filetype;
828		    }
829		    else{
830			n_strx = symbols64[i].n_un.n_strx;
831			n_type = symbols64[i].n_type;
832		        filetype = fp->mh64->filetype;
833		    }
834		    if(n_strx == 0)
835			continue;
836		    /*
837		     * If this object has any bad string indexes don't try to
838		     * break the string table into the local and external
839		     * parts.
840		     */
841		    if(n_strx > st->strsize){
842			ext_low = st->strsize;
843			local_low = st->strsize;
844			ext_high = 0;
845			local_high = 0;
846			break;
847		    }
848		    if(n_type & N_EXT ||
849		       (filetype == MH_EXECUTE && n_type & N_PEXT)){
850			if(n_strx > ext_high)
851			    ext_high = n_strx;
852			if(n_strx < ext_low)
853			    ext_low = n_strx;
854		    }
855		    else{
856			if(n_strx > local_high)
857			    local_high = n_strx;
858			if(n_strx < local_low)
859			    local_low = n_strx;
860		    }
861		}
862
863		if(ofile.mh != NULL){
864		    modtab = (struct dylib_module *)(ofile.object_addr +
865						     dyst->modtaboff);
866		    if(ofile.object_byte_sex != get_host_byte_sex())
867			swap_dylib_module(modtab, dyst->nmodtab,
868			       get_host_byte_sex());
869		    for(i = 0; i < dyst->nmodtab; i++){
870			if(modtab[i].module_name > local_high)
871			    local_high = modtab[i].module_name;
872			if(modtab[i].module_name < local_low)
873			    local_low = modtab[i].module_name;
874		    }
875		}
876		else{
877		    modtab64 = (struct dylib_module_64 *)(ofile.object_addr +
878						          dyst->modtaboff);
879		    if(ofile.object_byte_sex != get_host_byte_sex())
880			swap_dylib_module_64(modtab64, dyst->nmodtab,
881			       get_host_byte_sex());
882		    for(i = 0; i < dyst->nmodtab; i++){
883			if(modtab64[i].module_name > local_high)
884			    local_high = modtab64[i].module_name;
885			if(modtab64[i].module_name < local_low)
886			    local_low = modtab64[i].module_name;
887		    }
888		}
889
890		if(ext_high < local_low && local_low < local_high){
891		    mp = new_mach_o_part();
892		    mp->offset = fp->offset + st->stroff + ext_low;
893		    mp->size = ext_high - ext_low +
894			       strlen(strings + ext_high) + 1;
895		    mp->type = MP_EXT_STRING_TABLE;
896		    insert_mach_o_part(fp, mp);
897
898		    mp = new_mach_o_part();
899		    mp->offset = fp->offset + st->stroff + local_low;
900		    mp->size = local_high - local_low +
901			       strlen(strings + local_high) + 1;
902		    mp->type = MP_LOC_STRING_TABLE;
903		    insert_mach_o_part(fp, mp);
904		}
905		else{
906		    mp = new_mach_o_part();
907		    mp->offset = fp->offset + st->stroff;
908		    mp->size = st->strsize;
909		    mp->type = MP_STRING_TABLE;
910		    insert_mach_o_part(fp, mp);
911		}
912	    }
913	    else if(dyst->nextdefsym != 0 || dyst->nundefsym != 0){
914		if(st->strsize != 0){
915		    mp = new_mach_o_part();
916		    mp->offset = fp->offset + st->stroff;
917		    mp->size = st->strsize;
918		    mp->type = MP_EXT_STRING_TABLE;
919		    insert_mach_o_part(fp, mp);
920		}
921	    }
922	    else{
923		if(st->strsize != 0){
924		    mp = new_mach_o_part();
925		    mp->offset = fp->offset + st->stroff;
926		    mp->size = st->strsize;
927		    mp->type = MP_LOC_STRING_TABLE;
928		    insert_mach_o_part(fp, mp);
929		}
930	    }
931	}
932	else if(st != NULL){
933	    if(st->nsyms != 0){
934		mp = new_mach_o_part();
935		mp->offset = fp->offset + st->symoff;
936		if(ofile.mh != NULL)
937		    mp->size = st->nsyms * sizeof(struct nlist);
938		else
939		    mp->size = st->nsyms * sizeof(struct nlist_64);
940		mp->type = MP_SYMBOL_TABLE;
941		insert_mach_o_part(fp, mp);
942	    }
943	    if(st->strsize != 0){
944		mp = new_mach_o_part();
945		mp->offset = fp->offset + st->stroff;
946		mp->size = st->strsize;
947		mp->type = MP_STRING_TABLE;
948		insert_mach_o_part(fp, mp);
949	    }
950	}
951	if(dyld_info != NULL){
952	    if(dyld_info->rebase_size != 0){
953		mp = new_mach_o_part();
954		mp->offset = fp->offset + dyld_info->rebase_off;
955		mp->size = dyld_info->rebase_size;
956		mp->type = MP_DYLD_INFO_REBASE;
957		insert_mach_o_part(fp, mp);
958	    }
959	    if(dyld_info->bind_size != 0){
960		mp = new_mach_o_part();
961		mp->offset = fp->offset + dyld_info->bind_off;
962		mp->size = dyld_info->bind_size;
963		mp->type = MP_DYLD_INFO_BIND;
964		insert_mach_o_part(fp, mp);
965	    }
966	    if(dyld_info->weak_bind_size != 0){
967		mp = new_mach_o_part();
968		mp->offset = fp->offset + dyld_info->weak_bind_off;
969		mp->size = dyld_info->weak_bind_size;
970		mp->type = MP_DYLD_INFO_WEAK_BIND;
971		insert_mach_o_part(fp, mp);
972	    }
973	    if(dyld_info->lazy_bind_size != 0){
974		mp = new_mach_o_part();
975		mp->offset = fp->offset + dyld_info->lazy_bind_off;
976		mp->size = dyld_info->lazy_bind_size;
977		mp->type = MP_DYLD_INFO_LAZY_BIND;
978		insert_mach_o_part(fp, mp);
979	    }
980	    if(dyld_info->export_size != 0){
981		mp = new_mach_o_part();
982		mp->offset = fp->offset + dyld_info->export_off;
983		mp->size = dyld_info->export_size;
984		mp->type = MP_DYLD_INFO_EXPORT;
985		insert_mach_o_part(fp, mp);
986	    }
987	}
988	if(code_sig != NULL && code_sig->datasize != 0){
989	    mp = new_mach_o_part();
990	    mp->offset = fp->offset + code_sig->dataoff;
991	    mp->size = code_sig->datasize;
992	    mp->type = MP_CODE_SIG;
993	    insert_mach_o_part(fp, mp);
994	}
995	if(func_starts != NULL && func_starts->datasize != 0){
996	    mp = new_mach_o_part();
997	    mp->offset = fp->offset + func_starts->dataoff;
998	    mp->size = func_starts->datasize;
999	    mp->type = MP_FUNCTION_STARTS;
1000	    insert_mach_o_part(fp, mp);
1001	}
1002	if(data_in_code != NULL && data_in_code->datasize != 0){
1003	    mp = new_mach_o_part();
1004	    mp->offset = fp->offset + data_in_code->dataoff;
1005	    mp->size = data_in_code->datasize;
1006	    mp->type = MP_DATA_IN_CODE;
1007	    insert_mach_o_part(fp, mp);
1008	}
1009	if(code_sign_drs != NULL && code_sign_drs->datasize != 0){
1010	    mp = new_mach_o_part();
1011	    mp->offset = fp->offset + code_sign_drs->dataoff;
1012	    mp->size = code_sign_drs->datasize;
1013	    mp->type = MP_CODE_SIGN_DRS;
1014	    insert_mach_o_part(fp, mp);
1015	}
1016}
1017
1018static
1019struct mach_o_part *
1020new_mach_o_part(
1021void)
1022{
1023    struct mach_o_part *mp;
1024
1025	mp = allocate(sizeof(struct mach_o_part));
1026	memset(mp, '\0', sizeof(struct mach_o_part));
1027	return(mp);
1028}
1029
1030static
1031void
1032insert_mach_o_part(
1033struct file_part *fp,
1034struct mach_o_part *new)
1035{
1036    struct mach_o_part *p, *q;
1037
1038	for(p = fp->mp; p != NULL; p = p->next){
1039	    /* find an existing part that contains the new part */
1040	    if(new->offset >= p->offset &&
1041	       new->offset + new->size <= p->offset + p->size){
1042		if(p->type != MP_EMPTY_SPACE)
1043		    fatal("internal error: new mach_o part not contained in "
1044			"empty space");
1045		/* if new is the same as p replace p with new */
1046		if(new->offset == p->offset &&
1047	           new->size == p->size){
1048		    new->prev = p->prev;
1049		    new->next = p->next;
1050		    if(p->next != NULL)
1051			p->next->prev = new;
1052		    if(p->prev != NULL)
1053			p->prev->next = new;
1054		    if(fp->mp == p)
1055			fp->mp = new;
1056		    free(p);
1057		    return;
1058		}
1059		/* if new starts at p put new before p and move p's offset */
1060		if(new->offset == p->offset){
1061		    p->offset = new->offset + new->size;
1062		    p->size = p->size - new->size;
1063		    new->prev = p->prev;
1064		    if(p->prev != NULL)
1065			p->prev->next = new;
1066		    p->prev = new;
1067		    new->next = p;
1068		    if(fp->mp == p)
1069			fp->mp = new;
1070		    return;
1071		}
1072		/* if new ends at p put new after p and change p's size */
1073		if(new->offset + new->size == p->offset + p->size){
1074		    p->size = new->offset - p->offset;
1075		    new->next = p->next;
1076		    if(p->next != NULL)
1077			p->next->prev = new;
1078		    p->next = new;
1079		    new->prev = p;
1080		    return;
1081		}
1082		/* new is in the middle of p */
1083		q = new_mach_o_part();
1084		q->type = MP_EMPTY_SPACE;
1085		q->offset = new->offset + new->size;
1086		q->size = p->offset + p->size - (new->offset + new->size);
1087		p->size = new->offset - p->offset;
1088		new->prev = p;
1089		new->next = q;
1090		q->prev = new;
1091		q->next = p->next;
1092		if(p->next != NULL)
1093		    p->next->prev = q;
1094		p->next = new;
1095		return;
1096	    }
1097	}
1098	fatal("internal error: new mach_o part not found in existing part");
1099}
1100
1101static
1102void
1103print_mach_o_parts(
1104struct mach_o_part *mp)
1105{
1106    struct mach_o_part *p, *prev;
1107    uint32_t offset;
1108    char *indent;
1109
1110	if(arch_flag == NULL)
1111	    indent = "    ";
1112	else
1113	    indent = "";
1114	offset = 0;
1115	prev = NULL;
1116	if(mp != NULL)
1117	    offset = mp->offset;
1118	for(p = mp; p != NULL; p = p->next){
1119	    if(p->type == MP_SECTION)
1120		printf("%sMP_SECTION (%.16s,%.16s)\n", indent,
1121		p->s->segname, p->s->sectname);
1122	    else if(p->type == MP_SECTION_64)
1123		printf("%sMP_SECTION_64 (%.16s,%.16s)\n", indent,
1124		p->s64->segname, p->s64->sectname);
1125	    else
1126		printf("%s%s\n", indent, mach_o_part_type_names[p->type]);
1127	    printf("%s    offset = %llu\n", indent, p->offset - arch_offset);
1128	    printf("%s    size = %llu\n", indent, p->size);
1129	    if(prev != NULL)
1130		if(prev != p->prev)
1131		    printf("bad prev pointer\n");
1132	    prev = p;
1133	    if(offset != p->offset)
1134		    printf("bad offset\n");
1135	    offset += p->size;
1136	}
1137}
1138
1139static
1140void
1141print_parts_for_page(
1142uint32_t page_number)
1143{
1144    uint64_t offset, size, low_addr, high_addr, new_low_addr, new_high_addr;
1145    struct file_part *fp;
1146    struct mach_o_part *mp;
1147    enum bool printed;
1148    enum bool sections, sections64;
1149    const char *arch_name;
1150
1151	offset = page_number * vm_page_size;
1152	size = vm_page_size;
1153	low_addr = 0;
1154	high_addr = 0;
1155
1156	if(arch_flag == NULL){
1157	    if(offset > ofile.file_size){
1158		printf("File has no page %u (file has only %u pages)\n",
1159		       page_number, (uint32_t)((ofile.file_size +
1160					        vm_page_size -1) /
1161					      vm_page_size));
1162	        return;
1163	    }
1164	}
1165	else{
1166	    if(offset > arch_size){
1167		printf("File for architecture %s has no page %u (has only %u "
1168		       "pages)\n", arch_flag->name,
1169		       page_number, (uint32_t)((arch_size +
1170					        vm_page_size -1) /
1171					      vm_page_size));
1172	        return;
1173	    }
1174	}
1175
1176	/*
1177	 * First pass through the file printing whats on the page ignoring the
1178	 * empty spaces.
1179	 */
1180	printed = FALSE;
1181	for(fp = file_parts; fp != NULL; fp = fp->next){
1182	    if(offset + size <= fp->offset - arch_offset)
1183		continue;
1184	    if(offset > fp->offset - arch_offset + fp->size)
1185		continue;
1186	    switch(fp->type){
1187	    case FP_FAT_HEADERS:
1188		printf("File Page %u contains fat file headers\n",
1189		       page_number);
1190		printed = TRUE;
1191		break;
1192	    case FP_MACH_O:
1193		sections = FALSE;
1194		sections64 = FALSE;
1195		for(mp = fp->mp; mp != NULL; mp = mp->next){
1196		    if(offset + size <= mp->offset - arch_offset)
1197			continue;
1198		    if(offset > mp->offset - arch_offset + mp->size)
1199			continue;
1200		    switch(mp->type){
1201		    case MP_MACH_HEADERS:
1202			printf("File Page %u contains Mach-O headers",
1203			       page_number);
1204			print_arch(fp);
1205			printed = TRUE;
1206			break;
1207		    case MP_SECTION:
1208			printf("File Page %u contains contents of "
1209			       "section (%.16s,%.16s)", page_number,
1210			       mp->s->segname, mp->s->sectname);
1211			print_arch(fp);
1212			printed = TRUE;
1213			if(offset < mp->offset - arch_offset)
1214			    new_low_addr = mp->s->addr;
1215			else
1216			    new_low_addr = mp->s->addr + offset - mp->offset -
1217					   arch_offset;
1218			if(offset + size > mp->offset - arch_offset + mp->size)
1219			    new_high_addr = mp->s->addr + mp->s->size;
1220			else
1221			    new_high_addr = mp->s->addr +
1222				(offset + size - (mp->offset - arch_offset));
1223			if(sections == FALSE){
1224			    low_addr = new_low_addr;
1225			    high_addr = new_high_addr;
1226			}
1227			else{
1228			    if(new_low_addr < low_addr)
1229				low_addr = new_low_addr;
1230			    if(new_high_addr > high_addr)
1231				high_addr = new_high_addr;
1232		        }
1233			sections = TRUE;
1234			break;
1235		    case MP_SECTION_64:
1236			printf("File Page %u contains contents of "
1237			       "section (%.16s,%.16s)", page_number,
1238			       mp->s64->segname, mp->s64->sectname);
1239			print_arch(fp);
1240			printed = TRUE;
1241			if(offset < mp->offset - arch_offset)
1242			    new_low_addr = mp->s64->addr;
1243			else
1244			    new_low_addr = mp->s64->addr + offset -
1245					   (mp->offset - arch_offset);
1246			if(offset + size > (mp->offset - arch_offset) +
1247					   mp->size)
1248			    new_high_addr = mp->s64->addr + mp->s64->size;
1249			else
1250			    new_high_addr = mp->s64->addr +
1251				(offset + size - (mp->offset - arch_offset));
1252			if(sections64 == FALSE){
1253			    low_addr = new_low_addr;
1254			    high_addr = new_high_addr;
1255			}
1256			else{
1257			    if(new_low_addr < low_addr)
1258				low_addr = new_low_addr;
1259			    if(new_high_addr > high_addr)
1260				high_addr = new_high_addr;
1261		        }
1262			sections64 = TRUE;
1263			break;
1264		    case MP_RELOCS:
1265			printf("File Page %u contains relocation entries for "
1266			       "section (%.16s,%.16s)", page_number,
1267			       mp->s->segname, mp->s->sectname);
1268			print_arch(fp);
1269			printed = TRUE;
1270			break;
1271		    case MP_RELOCS_64:
1272			printf("File Page %u contains relocation entries for "
1273			       "section (%.16s,%.16s)", page_number,
1274			       mp->s64->segname, mp->s64->sectname);
1275			print_arch(fp);
1276			printed = TRUE;
1277			break;
1278		    case MP_SPLIT_INFO:
1279			printf("File Page %u contains local of info to split "
1280			       "segments", page_number);
1281			print_arch(fp);
1282			printed = TRUE;
1283			break;
1284		    case MP_LOCAL_SYMBOLS:
1285			printf("File Page %u contains symbol table for "
1286			       "non-global symbols", page_number);
1287			print_arch(fp);
1288			printed = TRUE;
1289			break;
1290		    case MP_EXTDEF_SYMBOLS:
1291			printf("File Page %u contains symbol table for "
1292			       "defined global symbols", page_number);
1293			print_arch(fp);
1294			printed = TRUE;
1295			break;
1296		    case MP_UNDEF_SYMBOLS:
1297			printf("File Page %u contains symbol table for "
1298			       "undefined symbols", page_number);
1299			print_arch(fp);
1300			printed = TRUE;
1301			break;
1302		    case MP_TOC:
1303			printf("File Page %u contains table of contents",
1304			       page_number);
1305			print_arch(fp);
1306			printed = TRUE;
1307			break;
1308		    case MP_MODULE_TABLE:
1309			printf("File Page %u contains module table",
1310			       page_number);
1311			print_arch(fp);
1312			printed = TRUE;
1313			break;
1314		    case MP_REFERENCE_TABLE:
1315			printf("File Page %u contains reference table",
1316			       page_number);
1317			print_arch(fp);
1318			printed = TRUE;
1319			break;
1320		    case MP_INDIRECT_SYMBOL_TABLE:
1321			printf("File Page %u contains indirect symbols table",
1322			       page_number);
1323			print_arch(fp);
1324			printed = TRUE;
1325			break;
1326		    case MP_EXT_RELOCS:
1327			printf("File Page %u contains external relocation "
1328			       "entries", page_number);
1329			print_arch(fp);
1330			printed = TRUE;
1331			break;
1332		    case MP_LOC_RELOCS:
1333			printf("File Page %u contains local relocation "
1334			       "entries", page_number);
1335			print_arch(fp);
1336			printed = TRUE;
1337			break;
1338		    case MP_SYMBOL_TABLE:
1339			printf("File Page %u contains symbol table",
1340			       page_number);
1341			print_arch(fp);
1342			printed = TRUE;
1343			break;
1344		    case MP_HINTS_TABLE:
1345			printf("File Page %u contains hints table",
1346			       page_number);
1347			print_arch(fp);
1348			printed = TRUE;
1349			break;
1350		    case MP_STRING_TABLE:
1351			printf("File Page %u contains string table",
1352			       page_number);
1353			print_arch(fp);
1354			printed = TRUE;
1355			break;
1356		    case MP_EXT_STRING_TABLE:
1357			printf("File Page %u contains string table for "
1358			       "external symbols", page_number);
1359			print_arch(fp);
1360			printed = TRUE;
1361			break;
1362		    case MP_LOC_STRING_TABLE:
1363			printf("File Page %u contains string table for "
1364			       "local symbols", page_number);
1365			print_arch(fp);
1366			printed = TRUE;
1367			break;
1368		    case MP_CODE_SIG:
1369			printf("File Page %u contains data of code signature",
1370			       page_number);
1371			print_arch(fp);
1372			printed = TRUE;
1373			break;
1374		    case MP_FUNCTION_STARTS:
1375			printf("File Page %u contains data of function starts",
1376			       page_number);
1377			print_arch(fp);
1378			printed = TRUE;
1379			break;
1380		    case MP_DATA_IN_CODE:
1381			printf("File Page %u contains info for data in code",
1382			       page_number);
1383			print_arch(fp);
1384			printed = TRUE;
1385			break;
1386		    case MP_CODE_SIGN_DRS:
1387			printf("File Page %u contains info for code signing "
1388			       "DRs copied from linked dylib", page_number);
1389			print_arch(fp);
1390			printed = TRUE;
1391			break;
1392		    case MP_DYLD_INFO_REBASE:
1393			printf("File Page %u contains dyld info for sliding "
1394			       "an image", page_number);
1395			print_arch(fp);
1396			printed = TRUE;
1397			break;
1398		    case MP_DYLD_INFO_BIND:
1399			printf("File Page %u contains dyld info for binding "
1400			       "symbols", page_number);
1401			print_arch(fp);
1402			printed = TRUE;
1403			break;
1404		    case MP_DYLD_INFO_WEAK_BIND:
1405			printf("File Page %u contains dyld info for weak bound "
1406			       "symbols", page_number);
1407			print_arch(fp);
1408			printed = TRUE;
1409			break;
1410		    case MP_DYLD_INFO_LAZY_BIND:
1411			printf("File Page %u contains dyld info for lazy bound "
1412			       "symbols", page_number);
1413			print_arch(fp);
1414			printed = TRUE;
1415			break;
1416		    case MP_DYLD_INFO_EXPORT:
1417			printf("File Page %u contains dyld info for symbols "
1418			       "exported by a dylib", page_number);
1419			print_arch(fp);
1420			printed = TRUE;
1421			break;
1422		    case MP_EMPTY_SPACE:
1423			break;
1424		    }
1425		}
1426		if(sections == TRUE || sections64 == TRUE){
1427		    printf("Symbols on file page %u virtual address 0x%llx to "
1428			   "0x%llx\n", page_number, low_addr, high_addr);
1429		    if(sections == TRUE)
1430			print_symbols(fp, low_addr, high_addr);
1431		    else
1432			print_symbols64(fp, low_addr, high_addr);
1433		}
1434		break;
1435
1436	    case FP_EMPTY_SPACE:
1437		break;
1438	    }
1439	}
1440
1441	/*
1442	 * Make a second pass through the file if nothing got printing on the
1443	 * first pass because the page covers empty space in the file.
1444	 */
1445	if(printed == TRUE)
1446	    return;
1447	for(fp = file_parts; fp != NULL; fp = fp->next){
1448	    if(offset + size <= fp->offset)
1449		continue;
1450	    if(offset > fp->offset + fp->size)
1451		continue;
1452	    if(fp->type == FP_MACH_O){
1453		for(mp = fp->mp; mp != NULL; mp = mp->next){
1454		    if(offset + size <= mp->offset - arch_offset)
1455			continue;
1456		    if(offset > (mp->offset - arch_offset) + mp->size)
1457			continue;
1458		    if(fp->mh != NULL)
1459			arch_name = get_arch_name_from_types(fp->mh->cputype,
1460						    	fp->mh->cpusubtype);
1461		    else
1462			arch_name = get_arch_name_from_types(fp->mh64->cputype,
1463						    	fp->mh64->cpusubtype);
1464		    printf("File Page %u contains empty space in the Mach-O "
1465			   "file for %s between:\n", page_number, arch_name);
1466		    if(mp->prev == NULL)
1467			printf("    the start of the Mach-O file");
1468		    else{
1469			printf("    ");
1470			print_mach_o_part(mp->prev);
1471		    }
1472		    printf(" and\n");
1473		    if(mp->next == NULL)
1474			printf("    the end of the Mach-O file\n");
1475		    else{
1476			printf("    ");
1477			print_mach_o_part(mp->next);
1478		    }
1479		    printf("\n");
1480		    return;
1481		}
1482		break;
1483	    }
1484	    printf("File Page %u contains empty space in the file between:\n",
1485		   page_number);
1486	    if(fp->prev == NULL)
1487		printf("    the start of the file");
1488	    else{
1489		printf("    ");
1490		print_file_part(fp->prev);
1491	    }
1492	    printf(" and\n");
1493	    if(fp->next == NULL)
1494		printf("    the end of the file\n");
1495	    else{
1496		printf("    ");
1497		print_file_part(fp->next);
1498	    }
1499	    printf("\n");
1500	    return;
1501	}
1502}
1503
1504static
1505void
1506print_arch(
1507struct file_part *fp)
1508{
1509	if(ofile.file_type == OFILE_FAT){
1510	    if(fp->mh != NULL)
1511		printf(" (%s)\n",
1512		   get_arch_name_from_types(fp->mh->cputype,
1513					    fp->mh->cpusubtype));
1514	    else
1515		printf(" (%s)\n",
1516		   get_arch_name_from_types(fp->mh64->cputype,
1517					    fp->mh64->cpusubtype));
1518	}
1519	else
1520	    printf("\n");
1521}
1522
1523static
1524void
1525print_file_part(
1526struct file_part *fp)
1527{
1528    const char *arch_name;
1529
1530	switch(fp->type){
1531	case FP_FAT_HEADERS:
1532	    printf("fat file headers");
1533	    break;
1534	case FP_MACH_O:
1535	    if(fp->mh != NULL)
1536		arch_name = get_arch_name_from_types(fp->mh->cputype,
1537						fp->mh->cpusubtype);
1538	    else
1539		arch_name = get_arch_name_from_types(fp->mh64->cputype,
1540						fp->mh64->cpusubtype);
1541	    printf("Mach-O file for %s", arch_name);
1542	    break;
1543	case FP_EMPTY_SPACE:
1544	    printf("empty space");
1545	    break;
1546	}
1547}
1548
1549static
1550void
1551print_mach_o_part(
1552struct mach_o_part *mp)
1553{
1554	switch(mp->type){
1555	case MP_MACH_HEADERS:
1556	    printf("Mach-O headers");
1557	    break;
1558	case MP_SECTION:
1559	    printf("contents of section (%.16s,%.16s)",
1560		   mp->s->segname, mp->s->sectname);
1561	    break;
1562	case MP_SECTION_64:
1563	    printf("contents of section (%.16s,%.16s)",
1564		   mp->s64->segname, mp->s64->sectname);
1565	    break;
1566	case MP_RELOCS:
1567	    printf("relocation entries for section (%.16s,%.16s)",
1568		   mp->s->segname, mp->s->sectname);
1569	    break;
1570	case MP_RELOCS_64:
1571	    printf("relocation entries for section (%.16s,%.16s)",
1572		   mp->s64->segname, mp->s64->sectname);
1573	    break;
1574	case MP_SPLIT_INFO:
1575	    printf("local of info to split segments");
1576	    break;
1577	case MP_LOCAL_SYMBOLS:
1578	    printf("symbol table for non-global symbols");
1579	    break;
1580	case MP_EXTDEF_SYMBOLS:
1581	    printf("symbol table for defined global symbols");
1582	    break;
1583	case MP_UNDEF_SYMBOLS:
1584	    printf("symbol table for undefined symbols");
1585	    break;
1586	case MP_TOC:
1587	    printf("table of contents");
1588	    break;
1589	case MP_MODULE_TABLE:
1590	    printf("module table");
1591	    break;
1592	case MP_REFERENCE_TABLE:
1593	    printf("reference table");
1594	    break;
1595	case MP_INDIRECT_SYMBOL_TABLE:
1596	    printf("indirect symbol table");
1597	    break;
1598	case MP_EXT_RELOCS:
1599	    printf("external relocation entries");
1600	    break;
1601	case MP_LOC_RELOCS:
1602	    printf("local relocation entries");
1603	    break;
1604	case MP_SYMBOL_TABLE:
1605	    printf("symbol table");
1606	    break;
1607	case MP_HINTS_TABLE:
1608	    printf("hints table");
1609	    break;
1610	case MP_STRING_TABLE:
1611	    printf("string table");
1612	    break;
1613	case MP_EXT_STRING_TABLE:
1614	    printf("string table for external symbols");
1615	    break;
1616	case MP_LOC_STRING_TABLE:
1617	    printf("string table for local symbols");
1618	    break;
1619	case MP_CODE_SIG:
1620	    printf("data of code signature");
1621	    break;
1622	case MP_FUNCTION_STARTS:
1623	    printf("data of function starts");
1624	    break;
1625	case MP_DATA_IN_CODE:
1626	    printf("info for data in code");
1627	    break;
1628	case MP_CODE_SIGN_DRS:
1629	    printf("info for code signing DRs copied from linked dylibs");
1630	    break;
1631	case MP_DYLD_INFO_REBASE:
1632	    printf("dyld info for sliding an image");
1633	    break;
1634	case MP_DYLD_INFO_BIND:
1635	    printf("dyld info for binding symbols");
1636	    break;
1637	case MP_DYLD_INFO_WEAK_BIND:
1638	    printf("dyld info for binding weak symbols");
1639	    break;
1640	case MP_DYLD_INFO_LAZY_BIND:
1641	    printf("dyld info for binding lazy symbols");
1642	    break;
1643	case MP_DYLD_INFO_EXPORT:
1644	    printf("dyld info for exported symbols");
1645	    break;
1646	case MP_EMPTY_SPACE:
1647	    printf("empty space");
1648	    break;
1649	}
1650}
1651
1652static
1653void
1654print_symbols(
1655struct file_part *fp,
1656uint64_t low_addr,
1657uint64_t high_addr)
1658{
1659    uint32_t i, count;
1660
1661	if(fp->st == NULL)
1662	    return;
1663
1664	if(sorted_symbols == NULL)
1665	    sorted_symbols = allocate(sizeof(struct nlist) * fp->st->nsyms);
1666
1667	count = 0;
1668	for(i = 0; i < fp->st->nsyms; i++){
1669	    if((fp->symbols[i].n_type & N_STAB) != 0)
1670		continue;
1671	    if(fp->symbols[i].n_value >= low_addr &&
1672	       fp->symbols[i].n_value <= high_addr){
1673		sorted_symbols[count] = fp->symbols[i];
1674		count++;
1675	    }
1676	}
1677
1678	qsort(sorted_symbols, count, sizeof(struct nlist),
1679	      (int (*)(const void *, const void *))compare);
1680
1681	for(i = 0; i < count; i++){
1682	    printf("  0x%08x %s\n", (unsigned int)sorted_symbols[i].n_value,
1683		fp->strings + sorted_symbols[i].n_un.n_strx);
1684	}
1685}
1686
1687static
1688void
1689print_symbols64(
1690struct file_part *fp,
1691uint64_t low_addr,
1692uint64_t high_addr)
1693{
1694    uint32_t i, count;
1695
1696	if(fp->st == NULL)
1697	    return;
1698
1699	if(sorted_symbols64 == NULL)
1700	    sorted_symbols64 = allocate(sizeof(struct nlist_64) *
1701					fp->st->nsyms);
1702
1703	count = 0;
1704	for(i = 0; i < fp->st->nsyms; i++){
1705	    if((fp->symbols64[i].n_type & N_STAB) != 0)
1706		continue;
1707	    if(fp->symbols64[i].n_value >= low_addr &&
1708	       fp->symbols64[i].n_value <= high_addr){
1709		sorted_symbols64[count] = fp->symbols64[i];
1710		count++;
1711	    }
1712	}
1713
1714	qsort(sorted_symbols64, count, sizeof(struct nlist_64),
1715	      (int (*)(const void *, const void *))compare64);
1716
1717	for(i = 0; i < count; i++){
1718	    printf("  0x%016llx %s\n", sorted_symbols64[i].n_value,
1719		fp->strings + sorted_symbols64[i].n_un.n_strx);
1720	}
1721}
1722
1723static
1724int
1725compare(
1726struct nlist *p1,
1727struct nlist *p2)
1728{
1729	if(p1->n_value > p2->n_value)
1730	    return(1);
1731	else if(p1->n_value < p2->n_value)
1732	    return(-1);
1733	else
1734	    return(0);
1735}
1736
1737static
1738int
1739compare64(
1740struct nlist_64 *p1,
1741struct nlist_64 *p2)
1742{
1743	if(p1->n_value > p2->n_value)
1744	    return(1);
1745	else if(p1->n_value < p2->n_value)
1746	    return(-1);
1747	else
1748	    return(0);
1749}
1750