#include <stdint.h>
#import <stdio.h>
#import <stdlib.h>
#import <string.h>
#import "stuff/ofile.h"
#import "stuff/errors.h"
#import "stuff/allocate.h"
enum file_part_type {
FP_FAT_HEADERS,
FP_MACH_O,
FP_EMPTY_SPACE
};
char *file_part_type_names[] = {
"FP_FAT_HEADERS",
"FP_MACH_O",
"FP_EMPTY_SPACE"
};
struct file_part {
uint64_t offset;
uint64_t size;
enum file_part_type type;
struct mach_o_part *mp;
struct mach_header *mh;
struct mach_header_64 *mh64;
struct symtab_command *st;
struct nlist *symbols;
struct nlist_64 *symbols64;
char *strings;
struct file_part *prev;
struct file_part *next;
};
struct file_part *file_parts = NULL;
enum mach_o_part_type {
MP_MACH_HEADERS,
MP_SECTION,
MP_SECTION_64,
MP_RELOCS,
MP_RELOCS_64,
MP_LOCAL_SYMBOLS,
MP_EXTDEF_SYMBOLS,
MP_UNDEF_SYMBOLS,
MP_TOC,
MP_MODULE_TABLE,
MP_REFERENCE_TABLE,
MP_INDIRECT_SYMBOL_TABLE,
MP_EXT_RELOCS,
MP_LOC_RELOCS,
MP_SPLIT_INFO,
MP_SYMBOL_TABLE,
MP_HINTS_TABLE,
MP_STRING_TABLE,
MP_EXT_STRING_TABLE,
MP_LOC_STRING_TABLE,
MP_CODE_SIG,
MP_FUNCTION_STARTS,
MP_EMPTY_SPACE
};
static char *mach_o_part_type_names[] = {
"MP_MACH_HEADERS",
"MP_SECTION",
"MP_SECTION_64",
"MP_RELOCS",
"MP_RELOCS_64",
"MP_LOCAL_SYMBOLS",
"MP_EXTDEF_SYMBOLS",
"MP_UNDEF_SYMBOLS",
"MP_TOC",
"MP_MODULE_TABLE",
"MP_REFERENCE_TABLE",
"MP_INDIRECT_SYMBOL_TABLE",
"MP_EXT_RELOCS",
"MP_LOC_RELOCS",
"MP_SPLIT_INFO",
"MP_SYMBOL_TABLE",
"MP_HINTS_TABLE",
"MP_STRING_TABLE",
"MP_EXT_STRING_TABLE",
"MP_LOC_STRING_TABLE",
"MP_CODE_SIG",
"MP_FUNCTION_STARTS",
"MP_EMPTY_SPACE"
};
struct mach_o_part {
uint64_t offset;
uint64_t size;
enum mach_o_part_type type;
struct section *s;
struct section_64 *s64;
struct mach_o_part *prev;
struct mach_o_part *next;
};
char *progname = NULL;
static struct ofile ofile;
static struct arch_flag *arch_flag = NULL;
uint64_t arch_offset = 0;
uint64_t arch_size = 0;
enum bool arch_found = FALSE;
static struct nlist *sorted_symbols = NULL;
static struct nlist_64 *sorted_symbols64 = NULL;
static void create_file_parts(
char *file_name);
static struct file_part *new_file_part(
void);
static void insert_file_part(
struct file_part *new);
static void print_file_parts(
void);
static void create_mach_o_parts(
struct file_part *fp);
static struct mach_o_part *new_mach_o_part(
void);
static void insert_mach_o_part(
struct file_part *fp,
struct mach_o_part *new);
static void print_mach_o_parts(
struct mach_o_part *mp);
static void print_parts_for_page(
uint32_t page_number);
static void print_arch(
struct file_part *fp);
static void print_file_part(
struct file_part *fp);
static void print_mach_o_part(
struct mach_o_part *mp);
static void print_symbols(
struct file_part *fp,
uint64_t low_addr,
uint64_t high_addr);
static void print_symbols64(
struct file_part *fp,
uint64_t low_addr,
uint64_t high_addr);
static int compare(
struct nlist *p1,
struct nlist *p2);
static int compare64(
struct nlist_64 *p1,
struct nlist_64 *p2);
int
main(
int argc,
char *argv[])
{
int i, start;
uint32_t j, page_number;
char *endp;
struct arch_flag a;
progname = argv[0];
if(argc < 3){
fprintf(stderr, "Usage: %s mach-o [-arch name] [-p] [-a] "
"pagenumber [pagenumber ...]\n",
progname);
exit(EXIT_FAILURE);
}
start = 2;
if(strcmp(argv[start], "-arch") == 0){
if(start + 1 == argc){
error("missing argument to -arch option");
exit(EXIT_FAILURE);
}
if(get_arch_from_flag(argv[start+1], &a) == 0){
error("unknown architecture specification flag: "
"%s %s", argv[start], argv[start+1]);
exit(EXIT_FAILURE);
}
arch_flag = &a;
start += 2;
}
create_file_parts(argv[1]);
if(arch_flag != NULL && arch_found == FALSE){
error("file: %s does not contain architecture: %s", argv[1],
arch_flag->name);
exit(EXIT_FAILURE);
}
if(strcmp(argv[start], "-p") == 0){
print_file_parts();
start++;
}
if(errors)
exit(EXIT_FAILURE);
if(start >= argc)
exit(EXIT_SUCCESS);
if(strcmp(argv[start], "-a") == 0){
if(arch_flag == NULL)
page_number = (ofile.file_size + vm_page_size - 1) /
vm_page_size;
else
page_number = (arch_size + vm_page_size - 1) /
vm_page_size;
for(j = 0; j < page_number; j++){
print_parts_for_page(j);
}
start++;
}
if(start >= argc)
exit(EXIT_SUCCESS);
for(i = start; i < argc; i++){
page_number = strtoul(argv[i], &endp, 10);
if(*endp != '\0')
fatal("page number argument: %s is not a proper unsigned "
"number", argv[i]);
print_parts_for_page(page_number);
}
return(EXIT_SUCCESS);
}
static
void
create_file_parts(
char *file_name)
{
static struct file_part *fp;
if(ofile_map(file_name, arch_flag, NULL, &ofile, FALSE) == FALSE)
exit(EXIT_FAILURE);
fp = new_file_part();
fp->offset = 0;
fp->size = ofile.file_size;
fp->type = FP_EMPTY_SPACE;
file_parts = fp;
if(ofile.file_type == OFILE_FAT){
fp = new_file_part();
fp->offset = 0;
fp->size = sizeof(struct fat_header) +
ofile.fat_header->nfat_arch * sizeof(struct fat_arch);
fp->type = FP_FAT_HEADERS;
insert_file_part(fp);
(void)ofile_first_arch(&ofile);
do{
if(ofile.arch_type == OFILE_ARCHIVE){
error("for architecture: %s file: %s is an archive (not "
"supported with %s)", ofile.arch_flag.name, file_name,
progname);
}
else if(ofile.arch_type == OFILE_Mach_O){
if(arch_flag != NULL && arch_found == FALSE &&
arch_flag->cputype == ofile.mh_cputype &&
(arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) ==
(ofile.mh_cpusubtype & ~CPU_SUBTYPE_MASK)){
arch_offset = ofile.fat_archs[ofile.narch].offset;
arch_size = ofile.fat_archs[ofile.narch].size;
arch_found = TRUE;
}
fp = new_file_part();
fp->offset = ofile.fat_archs[ofile.narch].offset;
fp->size = ofile.fat_archs[ofile.narch].size;
fp->type = FP_MACH_O;
insert_file_part(fp);
create_mach_o_parts(fp);
}
else if(ofile.arch_type == OFILE_UNKNOWN){
error("for architecture: %s file: %s is not an object file "
"(not supported with %s)", ofile.arch_flag.name,
file_name, progname);
}
}while(ofile_next_arch(&ofile) == TRUE);
}
else if(ofile.file_type == OFILE_ARCHIVE){
error("file: %s is an archive (not supported with %s)", file_name,
progname);
}
else if(ofile.file_type == OFILE_Mach_O){
if(arch_flag != NULL && arch_found == FALSE &&
arch_flag->cputype == ofile.mh_cputype &&
(arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) ==
(ofile.mh_cpusubtype & ~CPU_SUBTYPE_MASK)){
arch_offset = 0;
arch_size = ofile.file_size;
arch_found = TRUE;
}
fp = new_file_part();
fp->offset = 0;
fp->size = ofile.file_size;
fp->type = FP_MACH_O;
insert_file_part(fp);
create_mach_o_parts(fp);
}
else{
error("file: %s is not an object file (not supported with %s)",
file_name, progname);
}
}
static
struct file_part *
new_file_part(
void)
{
struct file_part *fp;
fp = allocate(sizeof(struct file_part));
memset(fp, '\0', sizeof(struct file_part));
return(fp);
}
static
void
insert_file_part(
struct file_part *new)
{
struct file_part *p, *q;
for(p = file_parts; p != NULL; p = p->next){
if(new->offset >= p->offset &&
new->offset + new->size <= p->offset + p->size){
if(p->type != FP_EMPTY_SPACE)
fatal("internal error: new file part not contained in "
"empty space");
if(new->offset == p->offset &&
new->size == p->size){
new->prev = p->prev;
new->next = p->next;
if(p->next != NULL)
p->next->prev = new;
if(p->prev != NULL)
p->prev->next = new;
if(file_parts == p)
file_parts = new;
free(p);
return;
}
if(new->offset == p->offset){
p->offset = new->offset + new->size;
p->size = p->size - new->size;
if(p->prev != NULL)
p->prev->next = new;
new->prev = p->prev;
p->prev = new;
new->next = p;
if(file_parts == p)
file_parts = new;
return;
}
if(new->offset + new->size == p->offset + p->size){
p->size = new->offset - p->offset;
new->next = p->next;
if(p->next != NULL)
p->next->prev = new;
p->next = new;
new->prev = p;
return;
}
q = new_file_part();
q->type = FP_EMPTY_SPACE;
q->offset = new->offset + new->size;
q->size = p->offset + p->size - (new->offset + new->size);
p->size = new->offset - p->offset;
new->prev = p;
new->next = q;
q->prev = new;
q->next = p->next;
if(p->next != NULL)
p->next->prev = q;
p->next = new;
return;
}
}
fatal("internal error: new file part not found in existing part");
}
static
void
print_file_parts(
void)
{
struct file_part *p, *prev;
uint64_t offset;
prev = NULL;
offset = 0;
for(p = file_parts; p != NULL; p = p->next){
if(arch_flag == NULL){
printf("%s\n", file_part_type_names[p->type]);
printf(" offset = %llu\n", p->offset);
printf(" size = %llu\n", p->size);
}
if(prev != NULL)
if(prev != p->prev)
printf("bad prev pointer\n");
prev = p;
if(offset != p->offset)
printf("bad offset\n");
offset += p->size;
if(p->type == FP_MACH_O){
if(arch_flag == NULL || p->offset == arch_offset)
print_mach_o_parts(p->mp);
}
}
}
static
void
create_mach_o_parts(
struct file_part *fp)
{
uint32_t i, j;
uint32_t ncmds, filetype;
struct mach_o_part *mp;
struct load_command *lc;
struct symtab_command *st;
struct dysymtab_command *dyst;
struct twolevel_hints_command *hints;
struct segment_command *sg;
struct segment_command_64 *sg64;
struct section *s;
struct section_64 *s64;
struct nlist *allocated_symbols, *symbols;
struct nlist_64 *allocated_symbols64, *symbols64;
uint32_t ext_low, ext_high, local_low, local_high, n_strx, n_type;
char *strings;
struct dylib_module *modtab;
struct dylib_module_64 *modtab64;
struct linkedit_data_command *split_info, *code_sig, *func_starts;
mp = new_mach_o_part();
mp->offset = fp->offset;
mp->size = ofile.object_size;
mp->type = MP_EMPTY_SPACE;
fp->mp = mp;
mp = new_mach_o_part();
mp->offset = fp->offset;
if(ofile.mh != NULL){
fp->mh = ofile.mh;
fp->mh64 = NULL;
mp->size = sizeof(struct mach_header) + ofile.mh->sizeofcmds;
ncmds = ofile.mh->ncmds;
}
else{
fp->mh64 = ofile.mh64;
fp->mh = NULL;
mp->size = sizeof(struct mach_header_64) + ofile.mh64->sizeofcmds;
ncmds = ofile.mh64->ncmds;
}
mp->type = MP_MACH_HEADERS;
insert_mach_o_part(fp, mp);
st = NULL;
dyst = NULL;
hints = NULL;
symbols = NULL;
symbols64 = NULL;
strings = NULL;
split_info = NULL;
code_sig = NULL;
func_starts = NULL;
lc = ofile.load_commands;
for(i = 0; i < ncmds; i++){
if(st == NULL && lc->cmd == LC_SYMTAB){
st = (struct symtab_command *)lc;
}
else if(dyst == NULL && lc->cmd == LC_DYSYMTAB){
dyst = (struct dysymtab_command *)lc;
}
else if(hints == NULL && lc->cmd == LC_TWOLEVEL_HINTS){
hints = (struct twolevel_hints_command *)lc;
}
else if(split_info == NULL && lc->cmd == LC_SEGMENT_SPLIT_INFO){
split_info = (struct linkedit_data_command *)lc;
}
else if(code_sig == NULL && lc->cmd == LC_CODE_SIGNATURE){
code_sig = (struct linkedit_data_command *)lc;
}
else if(func_starts == NULL && lc->cmd == LC_FUNCTION_STARTS){
func_starts = (struct linkedit_data_command *)lc;
}
else if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
s = (struct section *)
((char *)sg + sizeof(struct segment_command));
for(j = 0; j < sg->nsects; j++){
if(s->nreloc != 0){
mp = new_mach_o_part();
mp->offset = fp->offset + s->reloff;
mp->size = s->nreloc * sizeof(struct relocation_info);
mp->type = MP_RELOCS;
mp->s = s;
mp->s64 = NULL;
insert_mach_o_part(fp, mp);
}
if((s->flags & SECTION_TYPE) != S_ZEROFILL &&
(s->flags & SECTION_TYPE) != S_THREAD_LOCAL_ZEROFILL &&
s->size != 0){
mp = new_mach_o_part();
mp->offset = fp->offset + s->offset;
mp->size = s->size;
mp->type = MP_SECTION;
mp->s = s;
mp->s64 = NULL;
insert_mach_o_part(fp, mp);
}
if(((s->flags & SECTION_TYPE) == S_ZEROFILL ||
(s->flags & SECTION_TYPE) == S_THREAD_LOCAL_ZEROFILL) &&
s->size != 0){
if(s->addr - sg->vmaddr < sg->filesize){
mp = new_mach_o_part();
mp->offset = fp->offset + sg->fileoff +
s->addr - sg->vmaddr;
if(s->addr - sg->vmaddr + s->size <= sg->filesize)
mp->size = s->size;
else
mp->size = sg->filesize -(s->addr - sg->vmaddr);
mp->type = MP_SECTION;
mp->s = s;
mp->s64 = NULL;
insert_mach_o_part(fp, mp);
}
}
s++;
}
}
else if(lc->cmd == LC_SEGMENT_64){
sg64 = (struct segment_command_64 *)lc;
s64 = (struct section_64 *)
((char *)sg64 + sizeof(struct segment_command_64));
for(j = 0; j < sg64->nsects; j++){
if(s64->nreloc != 0){
mp = new_mach_o_part();
mp->offset = fp->offset + s64->reloff;
mp->size = s64->nreloc * sizeof(struct relocation_info);
mp->type = MP_RELOCS_64;
mp->s64 = s64;
mp->s = NULL;
insert_mach_o_part(fp, mp);
}
if((s64->flags & SECTION_TYPE) != S_ZEROFILL &&
(s64->flags & SECTION_TYPE) != S_THREAD_LOCAL_ZEROFILL &&
s64->size != 0){
mp = new_mach_o_part();
mp->offset = fp->offset + s64->offset;
mp->size = s64->size;
mp->type = MP_SECTION_64;
mp->s64 = s64;
mp->s = NULL;
insert_mach_o_part(fp, mp);
}
if(((s64->flags & SECTION_TYPE) == S_ZEROFILL ||
(s64->flags & SECTION_TYPE) ==
S_THREAD_LOCAL_ZEROFILL) &&
s64->size != 0){
if(s64->addr - sg64->vmaddr < sg64->filesize){
mp = new_mach_o_part();
mp->offset = fp->offset + sg64->fileoff +
s64->addr - sg64->vmaddr;
if(s64->addr - sg64->vmaddr + s64->size <=
sg64->filesize)
mp->size = s64->size;
else
mp->size = sg64->filesize -
(s64->addr - sg64->vmaddr);
mp->type = MP_SECTION_64;
mp->s64 = s64;
mp->s = NULL;
insert_mach_o_part(fp, mp);
}
}
s64++;
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
if(st != NULL){
if(ofile.mh != NULL){
allocated_symbols = NULL;
symbols = (struct nlist *)(ofile.object_addr + st->symoff);
if(ofile.object_byte_sex != get_host_byte_sex()){
allocated_symbols = allocate(sizeof(struct nlist) *
st->nsyms);
memcpy(allocated_symbols, symbols,
sizeof(struct nlist) * st->nsyms);
swap_nlist(allocated_symbols, st->nsyms,
get_host_byte_sex());
symbols = allocated_symbols;
}
fp->symbols = symbols;
fp->symbols64 = NULL;
}
else{
allocated_symbols64 = NULL;
symbols64 = (struct nlist_64 *)(ofile.object_addr + st->symoff);
if(ofile.object_byte_sex != get_host_byte_sex()){
allocated_symbols64 = allocate(sizeof(struct nlist_64) *
st->nsyms);
memcpy(allocated_symbols64, symbols64,
sizeof(struct nlist_64) * st->nsyms);
swap_nlist_64(allocated_symbols64, st->nsyms,
get_host_byte_sex());
symbols64 = allocated_symbols64;
}
fp->symbols64 = symbols64;
fp->symbols = NULL;
}
strings = ofile.object_addr + st->stroff;
fp->st = st;
fp->strings = strings;
}
if(dyst != NULL && st != NULL){
if(dyst->nlocalsym != 0){
mp = new_mach_o_part();
if(ofile.mh != NULL){
mp->offset = fp->offset + st->symoff +
dyst->ilocalsym * sizeof(struct nlist);
mp->size = dyst->nlocalsym * sizeof(struct nlist);
}
else{
mp->offset = fp->offset + st->symoff +
dyst->ilocalsym * sizeof(struct nlist_64);
mp->size = dyst->nlocalsym * sizeof(struct nlist_64);
}
mp->type = MP_LOCAL_SYMBOLS;
insert_mach_o_part(fp, mp);
}
if(dyst->nextdefsym != 0){
mp = new_mach_o_part();
if(ofile.mh != NULL){
mp->offset = fp->offset + st->symoff +
dyst->iextdefsym * sizeof(struct nlist);
mp->size = dyst->nextdefsym * sizeof(struct nlist);
}
else{
mp->offset = fp->offset + st->symoff +
dyst->iextdefsym * sizeof(struct nlist_64);
mp->size = dyst->nextdefsym * sizeof(struct nlist_64);
}
mp->type = MP_EXTDEF_SYMBOLS;
insert_mach_o_part(fp, mp);
}
if(dyst->nundefsym != 0){
mp = new_mach_o_part();
if(ofile.mh != NULL){
mp->offset = fp->offset + st->symoff +
dyst->iundefsym * sizeof(struct nlist);
mp->size = dyst->nundefsym * sizeof(struct nlist);
}
else{
mp->offset = fp->offset + st->symoff +
dyst->iundefsym * sizeof(struct nlist_64);
mp->size = dyst->nundefsym * sizeof(struct nlist_64);
}
mp->type = MP_UNDEF_SYMBOLS;
insert_mach_o_part(fp, mp);
}
if(hints != NULL && hints->nhints != 0){
mp = new_mach_o_part();
mp->offset = fp->offset + hints->offset;
mp->size = hints->nhints *
sizeof(struct twolevel_hint);
mp->type = MP_HINTS_TABLE;
insert_mach_o_part(fp, mp);
}
if(split_info != NULL && split_info->datasize != 0){
mp = new_mach_o_part();
mp->offset = fp->offset + split_info->dataoff;
mp->size = split_info->datasize;
mp->type = MP_SPLIT_INFO;
insert_mach_o_part(fp, mp);
}
if(dyst->ntoc != 0){
mp = new_mach_o_part();
mp->offset = fp->offset + dyst->tocoff;
mp->size = dyst->ntoc * sizeof(struct dylib_table_of_contents);
mp->type = MP_TOC;
insert_mach_o_part(fp, mp);
}
if(dyst->nmodtab != 0){
mp = new_mach_o_part();
mp->offset = fp->offset + dyst->modtaboff;
if(ofile.mh != NULL)
mp->size = dyst->nmodtab * sizeof(struct dylib_module);
else
mp->size = dyst->nmodtab * sizeof(struct dylib_module_64);
mp->type = MP_MODULE_TABLE;
insert_mach_o_part(fp, mp);
}
if(dyst->nextrefsyms != 0){
mp = new_mach_o_part();
mp->offset = fp->offset + dyst->extrefsymoff;
mp->size = dyst->nextrefsyms * sizeof(struct dylib_reference);
mp->type = MP_REFERENCE_TABLE;
insert_mach_o_part(fp, mp);
}
if(dyst->nindirectsyms != 0){
mp = new_mach_o_part();
mp->offset = fp->offset + dyst->indirectsymoff;
mp->size = dyst->nindirectsyms * sizeof(uint32_t);
mp->type = MP_INDIRECT_SYMBOL_TABLE;
insert_mach_o_part(fp, mp);
}
if(dyst->nextrel != 0){
mp = new_mach_o_part();
mp->offset = fp->offset + dyst->extreloff;
mp->size = dyst->nextrel * sizeof(struct relocation_info);
mp->type = MP_EXT_RELOCS;
insert_mach_o_part(fp, mp);
}
if(dyst->nlocrel != 0){
mp = new_mach_o_part();
mp->offset = fp->offset + dyst->locreloff;
mp->size = dyst->nlocrel * sizeof(struct relocation_info);
mp->type = MP_LOC_RELOCS;
insert_mach_o_part(fp, mp);
}
if(dyst->nlocalsym != 0 &&
(dyst->nextdefsym != 0 || dyst->nundefsym != 0)){
ext_low = st->strsize;
local_low = st->strsize;
ext_high = 0;
local_high = 0;
for(i = 0; i < st->nsyms; i++){
if(ofile.mh != NULL){
n_strx = symbols[i].n_un.n_strx;
n_type = symbols[i].n_type;
filetype = fp->mh->filetype;
}
else{
n_strx = symbols64[i].n_un.n_strx;
n_type = symbols64[i].n_type;
filetype = fp->mh64->filetype;
}
if(n_strx == 0)
continue;
if(n_type & N_EXT ||
(filetype == MH_EXECUTE && n_type & N_PEXT)){
if(n_strx > ext_high)
ext_high = n_strx;
if(n_strx < ext_low)
ext_low = n_strx;
}
else{
if(n_strx > local_high)
local_high = n_strx;
if(n_strx < local_low)
local_low = n_strx;
}
}
if(ofile.mh != NULL){
modtab = (struct dylib_module *)(ofile.object_addr +
dyst->modtaboff);
if(ofile.object_byte_sex != get_host_byte_sex())
swap_dylib_module(modtab, dyst->nmodtab,
get_host_byte_sex());
for(i = 0; i < dyst->nmodtab; i++){
if(modtab[i].module_name > local_high)
local_high = modtab[i].module_name;
if(modtab[i].module_name < local_low)
local_low = modtab[i].module_name;
}
}
else{
modtab64 = (struct dylib_module_64 *)(ofile.object_addr +
dyst->modtaboff);
if(ofile.object_byte_sex != get_host_byte_sex())
swap_dylib_module_64(modtab64, dyst->nmodtab,
get_host_byte_sex());
for(i = 0; i < dyst->nmodtab; i++){
if(modtab64[i].module_name > local_high)
local_high = modtab64[i].module_name;
if(modtab64[i].module_name < local_low)
local_low = modtab64[i].module_name;
}
}
if(ext_high < local_low && local_low < local_high){
mp = new_mach_o_part();
mp->offset = fp->offset + st->stroff + ext_low;
mp->size = ext_high - ext_low +
strlen(strings + ext_high) + 1;
mp->type = MP_EXT_STRING_TABLE;
insert_mach_o_part(fp, mp);
mp = new_mach_o_part();
mp->offset = fp->offset + st->stroff + local_low;
mp->size = local_high - local_low +
strlen(strings + local_high) + 1;
mp->type = MP_LOC_STRING_TABLE;
insert_mach_o_part(fp, mp);
}
else{
mp = new_mach_o_part();
mp->offset = fp->offset + st->stroff;
mp->size = st->strsize;
mp->type = MP_STRING_TABLE;
insert_mach_o_part(fp, mp);
}
}
else if(dyst->nextdefsym != 0 || dyst->nundefsym != 0){
if(st->strsize != 0){
mp = new_mach_o_part();
mp->offset = fp->offset + st->stroff;
mp->size = st->strsize;
mp->type = MP_EXT_STRING_TABLE;
insert_mach_o_part(fp, mp);
}
}
else{
if(st->strsize != 0){
mp = new_mach_o_part();
mp->offset = fp->offset + st->stroff;
mp->size = st->strsize;
mp->type = MP_LOC_STRING_TABLE;
insert_mach_o_part(fp, mp);
}
}
}
else if(st != NULL){
if(st->nsyms != 0){
mp = new_mach_o_part();
mp->offset = fp->offset + st->symoff;
if(ofile.mh != NULL)
mp->size = st->nsyms * sizeof(struct nlist);
else
mp->size = st->nsyms * sizeof(struct nlist_64);
mp->type = MP_SYMBOL_TABLE;
insert_mach_o_part(fp, mp);
}
if(st->strsize != 0){
mp = new_mach_o_part();
mp->offset = fp->offset + st->stroff;
mp->size = st->strsize;
mp->type = MP_STRING_TABLE;
insert_mach_o_part(fp, mp);
}
}
if(code_sig != NULL && code_sig->datasize != 0){
mp = new_mach_o_part();
mp->offset = fp->offset + code_sig->dataoff;
mp->size = code_sig->datasize;
mp->type = MP_CODE_SIG;
insert_mach_o_part(fp, mp);
}
if(func_starts != NULL && func_starts->datasize != 0){
mp = new_mach_o_part();
mp->offset = fp->offset + func_starts->dataoff;
mp->size = func_starts->datasize;
mp->type = MP_FUNCTION_STARTS;
insert_mach_o_part(fp, mp);
}
}
static
struct mach_o_part *
new_mach_o_part(
void)
{
struct mach_o_part *mp;
mp = allocate(sizeof(struct mach_o_part));
memset(mp, '\0', sizeof(struct mach_o_part));
return(mp);
}
static
void
insert_mach_o_part(
struct file_part *fp,
struct mach_o_part *new)
{
struct mach_o_part *p, *q;
for(p = fp->mp; p != NULL; p = p->next){
if(new->offset >= p->offset &&
new->offset + new->size <= p->offset + p->size){
if(p->type != MP_EMPTY_SPACE)
fatal("internal error: new mach_o part not contained in "
"empty space");
if(new->offset == p->offset &&
new->size == p->size){
new->prev = p->prev;
new->next = p->next;
if(p->next != NULL)
p->next->prev = new;
if(p->prev != NULL)
p->prev->next = new;
if(fp->mp == p)
fp->mp = new;
free(p);
return;
}
if(new->offset == p->offset){
p->offset = new->offset + new->size;
p->size = p->size - new->size;
new->prev = p->prev;
if(p->prev != NULL)
p->prev->next = new;
p->prev = new;
new->next = p;
if(fp->mp == p)
fp->mp = new;
return;
}
if(new->offset + new->size == p->offset + p->size){
p->size = new->offset - p->offset;
new->next = p->next;
if(p->next != NULL)
p->next->prev = new;
p->next = new;
new->prev = p;
return;
}
q = new_mach_o_part();
q->type = MP_EMPTY_SPACE;
q->offset = new->offset + new->size;
q->size = p->offset + p->size - (new->offset + new->size);
p->size = new->offset - p->offset;
new->prev = p;
new->next = q;
q->prev = new;
q->next = p->next;
if(p->next != NULL)
p->next->prev = q;
p->next = new;
return;
}
}
fatal("internal error: new mach_o part not found in existing part");
}
static
void
print_mach_o_parts(
struct mach_o_part *mp)
{
struct mach_o_part *p, *prev;
uint32_t offset;
char *indent;
if(arch_flag == NULL)
indent = " ";
else
indent = "";
offset = 0;
prev = NULL;
if(mp != NULL)
offset = mp->offset;
for(p = mp; p != NULL; p = p->next){
if(p->type == MP_SECTION)
printf("%sMP_SECTION (%.16s,%.16s)\n", indent,
p->s->segname, p->s->sectname);
else if(p->type == MP_SECTION_64)
printf("%sMP_SECTION_64 (%.16s,%.16s)\n", indent,
p->s64->segname, p->s64->sectname);
else
printf("%s%s\n", indent, mach_o_part_type_names[p->type]);
printf("%s offset = %llu\n", indent, p->offset - arch_offset);
printf("%s size = %llu\n", indent, p->size);
if(prev != NULL)
if(prev != p->prev)
printf("bad prev pointer\n");
prev = p;
if(offset != p->offset)
printf("bad offset\n");
offset += p->size;
}
}
static
void
print_parts_for_page(
uint32_t page_number)
{
uint64_t offset, size, low_addr, high_addr, new_low_addr, new_high_addr;
struct file_part *fp;
struct mach_o_part *mp;
enum bool printed;
enum bool sections, sections64;
const char *arch_name;
offset = page_number * vm_page_size;
size = vm_page_size;
low_addr = 0;
high_addr = 0;
if(arch_flag == NULL){
if(offset > ofile.file_size){
printf("File has no page %u (file has only %u pages)\n",
page_number, (uint32_t)((ofile.file_size +
vm_page_size -1) /
vm_page_size));
return;
}
}
else{
if(offset > arch_size){
printf("File for architecture %s has no page %u (has only %u "
"pages)\n", arch_flag->name,
page_number, (uint32_t)((arch_size +
vm_page_size -1) /
vm_page_size));
return;
}
}
printed = FALSE;
for(fp = file_parts; fp != NULL; fp = fp->next){
if(offset + size <= fp->offset - arch_offset)
continue;
if(offset > fp->offset - arch_offset + fp->size)
continue;
switch(fp->type){
case FP_FAT_HEADERS:
printf("File Page %u contains fat file headers\n",
page_number);
printed = TRUE;
break;
case FP_MACH_O:
sections = FALSE;
sections64 = FALSE;
for(mp = fp->mp; mp != NULL; mp = mp->next){
if(offset + size <= mp->offset - arch_offset)
continue;
if(offset > mp->offset - arch_offset + mp->size)
continue;
switch(mp->type){
case MP_MACH_HEADERS:
printf("File Page %u contains Mach-O headers",
page_number);
print_arch(fp);
printed = TRUE;
break;
case MP_SECTION:
printf("File Page %u contains contents of "
"section (%.16s,%.16s)", page_number,
mp->s->segname, mp->s->sectname);
print_arch(fp);
printed = TRUE;
if(offset < mp->offset - arch_offset)
new_low_addr = mp->s->addr;
else
new_low_addr = mp->s->addr + offset - mp->offset -
arch_offset;
if(offset + size > mp->offset - arch_offset + mp->size)
new_high_addr = mp->s->addr + mp->s->size;
else
new_high_addr = mp->s->addr +
(offset + size - (mp->offset - arch_offset));
if(sections == FALSE){
low_addr = new_low_addr;
high_addr = new_high_addr;
}
else{
if(new_low_addr < low_addr)
low_addr = new_low_addr;
if(new_high_addr > high_addr)
high_addr = new_high_addr;
}
sections = TRUE;
break;
case MP_SECTION_64:
printf("File Page %u contains contents of "
"section (%.16s,%.16s)", page_number,
mp->s64->segname, mp->s64->sectname);
print_arch(fp);
printed = TRUE;
if(offset < mp->offset - arch_offset)
new_low_addr = mp->s64->addr;
else
new_low_addr = mp->s64->addr + offset -
(mp->offset - arch_offset);
if(offset + size > (mp->offset - arch_offset) +
mp->size)
new_high_addr = mp->s64->addr + mp->s64->size;
else
new_high_addr = mp->s64->addr +
(offset + size - (mp->offset - arch_offset));
if(sections64 == FALSE){
low_addr = new_low_addr;
high_addr = new_high_addr;
}
else{
if(new_low_addr < low_addr)
low_addr = new_low_addr;
if(new_high_addr > high_addr)
high_addr = new_high_addr;
}
sections64 = TRUE;
break;
case MP_RELOCS:
printf("File Page %u contains relocation entries for "
"section (%.16s,%.16s)", page_number,
mp->s->segname, mp->s->sectname);
print_arch(fp);
printed = TRUE;
break;
case MP_RELOCS_64:
printf("File Page %u contains relocation entries for "
"section (%.16s,%.16s)", page_number,
mp->s64->segname, mp->s64->sectname);
print_arch(fp);
printed = TRUE;
break;
case MP_SPLIT_INFO:
printf("File Page %u contains local of info to split "
"segments", page_number);
print_arch(fp);
printed = TRUE;
break;
case MP_LOCAL_SYMBOLS:
printf("File Page %u contains symbol table for "
"non-global symbols", page_number);
print_arch(fp);
printed = TRUE;
break;
case MP_EXTDEF_SYMBOLS:
printf("File Page %u contains symbol table for "
"defined global symbols", page_number);
print_arch(fp);
printed = TRUE;
break;
case MP_UNDEF_SYMBOLS:
printf("File Page %u contains symbol table for "
"undefined symbols", page_number);
print_arch(fp);
printed = TRUE;
break;
case MP_TOC:
printf("File Page %u contains table of contents",
page_number);
print_arch(fp);
printed = TRUE;
break;
case MP_MODULE_TABLE:
printf("File Page %u contains module table",
page_number);
print_arch(fp);
printed = TRUE;
break;
case MP_REFERENCE_TABLE:
printf("File Page %u contains reference table",
page_number);
print_arch(fp);
printed = TRUE;
break;
case MP_INDIRECT_SYMBOL_TABLE:
printf("File Page %u contains indirect symbols table",
page_number);
print_arch(fp);
printed = TRUE;
break;
case MP_EXT_RELOCS:
printf("File Page %u contains external relocation "
"entries", page_number);
print_arch(fp);
printed = TRUE;
break;
case MP_LOC_RELOCS:
printf("File Page %u contains local relocation "
"entries", page_number);
print_arch(fp);
printed = TRUE;
break;
case MP_SYMBOL_TABLE:
printf("File Page %u contains symbol table",
page_number);
print_arch(fp);
printed = TRUE;
break;
case MP_HINTS_TABLE:
printf("File Page %u contains hints table",
page_number);
print_arch(fp);
printed = TRUE;
break;
case MP_STRING_TABLE:
printf("File Page %u contains string table",
page_number);
print_arch(fp);
printed = TRUE;
break;
case MP_EXT_STRING_TABLE:
printf("File Page %u contains string table for "
"external symbols", page_number);
print_arch(fp);
printed = TRUE;
break;
case MP_LOC_STRING_TABLE:
printf("File Page %u contains string table for "
"local symbols", page_number);
print_arch(fp);
printed = TRUE;
break;
case MP_CODE_SIG:
printf("File Page %u contains data of code signature",
page_number);
print_arch(fp);
printed = TRUE;
break;
case MP_FUNCTION_STARTS:
printf("File Page %u contains data of function starts",
page_number);
print_arch(fp);
printed = TRUE;
break;
case MP_EMPTY_SPACE:
break;
}
}
if(sections == TRUE || sections64 == TRUE){
printf("Symbols on file page %u virtual address 0x%llx to "
"0x%llx\n", page_number, low_addr, high_addr);
if(sections == TRUE)
print_symbols(fp, low_addr, high_addr);
else
print_symbols64(fp, low_addr, high_addr);
}
break;
case FP_EMPTY_SPACE:
break;
}
}
if(printed == TRUE)
return;
for(fp = file_parts; fp != NULL; fp = fp->next){
if(offset + size <= fp->offset)
continue;
if(offset > fp->offset + fp->size)
continue;
if(fp->type == FP_MACH_O){
for(mp = fp->mp; mp != NULL; mp = mp->next){
if(offset + size <= mp->offset - arch_offset)
continue;
if(offset > (mp->offset - arch_offset) + mp->size)
continue;
if(fp->mh != NULL)
arch_name = get_arch_name_from_types(fp->mh->cputype,
fp->mh->cpusubtype);
else
arch_name = get_arch_name_from_types(fp->mh64->cputype,
fp->mh64->cpusubtype);
printf("File Page %u contains empty space in the Mach-O "
"file for %s between:\n", page_number, arch_name);
if(mp->prev == NULL)
printf(" the start of the Mach-O file");
else{
printf(" ");
print_mach_o_part(mp->prev);
}
printf(" and\n");
if(mp->next == NULL)
printf(" the end of the Mach-O file\n");
else{
printf(" ");
print_mach_o_part(mp->next);
}
printf("\n");
return;
}
break;
}
printf("File Page %u contains empty space in the file between:\n",
page_number);
if(fp->prev == NULL)
printf(" the start of the file");
else{
printf(" ");
print_file_part(fp->prev);
}
printf(" and\n");
if(fp->next == NULL)
printf(" the end of the file\n");
else{
printf(" ");
print_file_part(fp->next);
}
printf("\n");
return;
}
}
static
void
print_arch(
struct file_part *fp)
{
if(ofile.file_type == OFILE_FAT){
if(fp->mh != NULL)
printf(" (%s)\n",
get_arch_name_from_types(fp->mh->cputype,
fp->mh->cpusubtype));
else
printf(" (%s)\n",
get_arch_name_from_types(fp->mh64->cputype,
fp->mh64->cpusubtype));
}
else
printf("\n");
}
static
void
print_file_part(
struct file_part *fp)
{
const char *arch_name;
switch(fp->type){
case FP_FAT_HEADERS:
printf("fat file headers");
break;
case FP_MACH_O:
if(fp->mh != NULL)
arch_name = get_arch_name_from_types(fp->mh->cputype,
fp->mh->cpusubtype);
else
arch_name = get_arch_name_from_types(fp->mh64->cputype,
fp->mh64->cpusubtype);
printf("Mach-O file for %s", arch_name);
break;
case FP_EMPTY_SPACE:
printf("empty space");
break;
}
}
static
void
print_mach_o_part(
struct mach_o_part *mp)
{
switch(mp->type){
case MP_MACH_HEADERS:
printf("Mach-O headers");
break;
case MP_SECTION:
printf("contents of section (%.16s,%.16s)",
mp->s->segname, mp->s->sectname);
break;
case MP_SECTION_64:
printf("contents of section (%.16s,%.16s)",
mp->s64->segname, mp->s64->sectname);
break;
case MP_RELOCS:
printf("relocation entries for section (%.16s,%.16s)",
mp->s->segname, mp->s->sectname);
break;
case MP_RELOCS_64:
printf("relocation entries for section (%.16s,%.16s)",
mp->s64->segname, mp->s64->sectname);
break;
case MP_SPLIT_INFO:
printf("local of info to split segments");
break;
case MP_LOCAL_SYMBOLS:
printf("symbol table for non-global symbols");
break;
case MP_EXTDEF_SYMBOLS:
printf("symbol table for defined global symbols");
break;
case MP_UNDEF_SYMBOLS:
printf("symbol table for undefined symbols");
break;
case MP_TOC:
printf("table of contents");
break;
case MP_MODULE_TABLE:
printf("module table");
break;
case MP_REFERENCE_TABLE:
printf("reference table");
break;
case MP_INDIRECT_SYMBOL_TABLE:
printf("indirect symbol table");
break;
case MP_EXT_RELOCS:
printf("external relocation entries");
break;
case MP_LOC_RELOCS:
printf("local relocation entries");
break;
case MP_SYMBOL_TABLE:
printf("symbol table");
break;
case MP_HINTS_TABLE:
printf("hints table");
break;
case MP_STRING_TABLE:
printf("string table");
break;
case MP_EXT_STRING_TABLE:
printf("string table for external symbols");
break;
case MP_LOC_STRING_TABLE:
printf("string table for local symbols");
break;
case MP_CODE_SIG:
printf("data of code signature");
break;
case MP_FUNCTION_STARTS:
printf("data of function starts");
break;
case MP_EMPTY_SPACE:
printf("empty space");
break;
}
}
static
void
print_symbols(
struct file_part *fp,
uint64_t low_addr,
uint64_t high_addr)
{
uint32_t i, count;
if(fp->st == NULL)
return;
if(sorted_symbols == NULL)
sorted_symbols = allocate(sizeof(struct nlist) * fp->st->nsyms);
count = 0;
for(i = 0; i < fp->st->nsyms; i++){
if((fp->symbols[i].n_type & N_STAB) != 0)
continue;
if(fp->symbols[i].n_value >= low_addr &&
fp->symbols[i].n_value <= high_addr){
sorted_symbols[count] = fp->symbols[i];
count++;
}
}
qsort(sorted_symbols, count, sizeof(struct nlist),
(int (*)(const void *, const void *))compare);
for(i = 0; i < count; i++){
printf(" 0x%08x %s\n", (unsigned int)sorted_symbols[i].n_value,
fp->strings + sorted_symbols[i].n_un.n_strx);
}
}
static
void
print_symbols64(
struct file_part *fp,
uint64_t low_addr,
uint64_t high_addr)
{
uint32_t i, count;
if(fp->st == NULL)
return;
if(sorted_symbols64 == NULL)
sorted_symbols64 = allocate(sizeof(struct nlist_64) *
fp->st->nsyms);
count = 0;
for(i = 0; i < fp->st->nsyms; i++){
if((fp->symbols64[i].n_type & N_STAB) != 0)
continue;
if(fp->symbols64[i].n_value >= low_addr &&
fp->symbols64[i].n_value <= high_addr){
sorted_symbols64[count] = fp->symbols64[i];
count++;
}
}
qsort(sorted_symbols64, count, sizeof(struct nlist_64),
(int (*)(const void *, const void *))compare64);
for(i = 0; i < count; i++){
printf(" 0x%016llx %s\n", sorted_symbols64[i].n_value,
fp->strings + sorted_symbols64[i].n_un.n_strx);
}
}
static
int
compare(
struct nlist *p1,
struct nlist *p2)
{
if(p1->n_value > p2->n_value)
return(1);
else if(p1->n_value < p2->n_value)
return(-1);
else
return(0);
}
static
int
compare64(
struct nlist_64 *p1,
struct nlist_64 *p2)
{
if(p1->n_value > p2->n_value)
return(1);
else if(p1->n_value < p2->n_value)
return(-1);
else
return(0);
}