/* * get_toc_byte_sex() guesses the byte sex of the table of contents of the * library mapped in at the address, addr, of size, size based on the first * object file's bytesex. If it can't figure it out, because the library has * no object file members or is malformed it will return UNKNOWN_BYTE_SEX. */ __private_extern__ enum byte_sex get_toc_byte_sex( char *addr, uint32_t size) { uint32_t magic; uint32_t ar_name_size; struct ar_hdr *ar_hdr; char *p; ar_hdr = (struct ar_hdr *)(addr + SARMAG); p = addr + SARMAG + sizeof(struct ar_hdr) + rnd(strtoul(ar_hdr->ar_size, NULL, 10), sizeof(short)); while(p + sizeof(struct ar_hdr) + sizeof(uint32_t) < addr + size){ ar_hdr = (struct ar_hdr *)p; if(strncmp(ar_hdr->ar_name, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0) ar_name_size = strtoul(ar_hdr->ar_name + sizeof(AR_EFMT1) - 1, NULL, 10); else ar_name_size = 0; p += sizeof(struct ar_hdr); memcpy(&magic, p + ar_name_size, sizeof(uint32_t)); if(magic == MH_MAGIC || magic == MH_MAGIC_64) return(get_host_byte_sex()); else if(magic == SWAP_INT(MH_MAGIC) || magic == SWAP_INT(MH_MAGIC_64)) return(get_host_byte_sex() == BIG_ENDIAN_BYTE_SEX ? LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX); p += rnd(strtoul(ar_hdr->ar_size, NULL, 10), sizeof(short)); } return(UNKNOWN_BYTE_SEX); }
/* * ofile_get_word() gets a 32 bit word for the address in the object file. */ __private_extern__ long ofile_get_word( unsigned long addr, unsigned long *word, void *get_word_data /* struct mach_object_file *ofile */ ) { unsigned long i, j; struct load_command *lc; struct segment_command *sg; struct section *s; struct ofile *ofile; ofile = (struct ofile *)get_word_data; for(i = 0, lc = ofile->load_commands; i < ofile->mh->ncmds; i++){ 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(addr >= s->addr && addr < s->addr + s->size){ if(s->flags == S_ZEROFILL) *word = 0; else { if(s->offset > ofile->object_size || s->offset + s->size > ofile->object_size || s->offset % sizeof(long) != 0 || (addr - s->addr) % sizeof(long) != 0) return(-1); else{ memcpy(word, (ofile->object_addr + (s->offset + addr - s->addr)), sizeof(unsigned long)); if(ofile->object_byte_sex !=get_host_byte_sex()) *word = SWAP_LONG(*word); } } return(0); } s++; } } lc = (struct load_command *)((char *)lc + lc->cmdsize); } return(-1); }
/* * The program cmpdylib. This compares an old and an new dynamic shared library * for compatiblity. Usage: * * cmpdylib old_dylib new_dylib * * It exits non-zero for incompatible libraries and prints why the libraries are * incompatible. It exit zero and prints nothing for compatible libraries. */ int main( int argc, char *argv[], char *envp[]) { progname = argv[0]; host_byte_sex = get_host_byte_sex(); if(argc != 3){ fprintf(stderr, "Usage: %s old_dylib new_dylib\n", progname); exit(EXIT_FAILURE); } old_dylib = argv[1]; new_dylib = argv[2]; ofile_process(old_dylib, NULL, 0, TRUE, TRUE, TRUE, FALSE, process_old, NULL); if(compatible == TRUE) return(EXIT_SUCCESS); else return(EXIT_FAILURE); }
/* * print_symbols() prints out the value of the data symbols * in the specified format. */ static void print_symbols( struct ofile *ofile, struct nlist *symbols, unsigned long nsymbols, char *strings, unsigned long strsize, struct cmd_flags *cmd_flags, struct process_flags *process_flags, char *arch_name) { unsigned long i; unsigned char c; unsigned long value; char *sect, *addr; unsigned long sect_size, sect_addr, sect_nrelocs, sect_flags, size; struct relocation_info *sect_relocs; enum bool swapped; if(ofile->file_type == OFILE_FAT){ addr = ofile->file_addr + ofile->fat_archs[ofile->narch].offset; size = ofile->fat_archs[ofile->narch].size; } else{ addr = ofile->file_addr; size = ofile->file_size; } if(addr + size > ofile->file_addr + ofile->file_size) size = (ofile->file_addr + ofile->file_size) - addr; swapped = ofile->object_byte_sex != get_host_byte_sex(); if(get_sect_info(SEG_DATA, SECT_DATA, ofile->mh, ofile->load_commands, ofile->object_byte_sex, addr, size, §, §_size, §_addr, §_relocs, §_nrelocs, §_flags) != TRUE) { error("No data section information\n"); return; } for(i = 0; i < nsymbols; i++){ c = symbols[i].n_type; if(c & N_STAB){ continue; } switch(c & N_TYPE){ case N_UNDF: c = 'u'; if(symbols[i].n_value != 0) c = 'c'; break; case N_ABS: c = 'a'; break; case N_SECT: if(symbols[i].n_sect == process_flags->text_nsect) c = 't'; else if(symbols[i].n_sect == process_flags->data_nsect) c = 'd'; else if(symbols[i].n_sect == process_flags->bss_nsect) c = 'b'; else c = 's'; break; case N_INDR: c = 'i'; break; default: c = '?'; break; } if((symbols[i].n_type & N_EXT) && c != '?') c = toupper(c); if(c == 'u' || c == 'U' || c == 'i' || c == 'I') fprintf(output, " "); else { if (c == 'D') { unsigned long offset; if (cmd_flags->c == TRUE) fprintf(output, "#define "); /* skip leading underscore of names */ fprintf(output, "%s\t", (symbols[i].n_un.n_name + 1)); /* Subtract section offset */ offset = sect_addr + symbols[i].n_value; /* Check range */ if (offset > (sect_size - sizeof(unsigned long))) { error("value for symbol '%s' located " "outside data section\n", (symbols[i].n_un.n_name + 1)); continue; } bcopy(sect + offset, &value, sizeof(value)); if (swapped) value = SWAP_LONG(value); /* SWAP_LONG */ if (cmd_flags->x == TRUE) fprintf(output, "0x%08lx\n", value); else fprintf(output, "%ld\n", value); } } } }
/* * select_symbols returns an allocated array of nlist structs as the symbols * that are to be printed based on the flags. The number of symbols in the * array returned in returned indirectly through nsymbols. */ static struct nlist * select_symbols( struct ofile *ofile, struct symtab_command *st, struct dysymtab_command *dyst, struct cmd_flags *cmd_flags, struct process_flags *process_flags, unsigned long *nsymbols) { unsigned long i, flags; struct nlist *all_symbols, *selected_symbols, undefined; struct dylib_module m; struct dylib_reference *refs; all_symbols = (struct nlist *)(ofile->object_addr + st->symoff); selected_symbols = allocate(sizeof(struct nlist) * st->nsyms); *nsymbols = 0; if(ofile->object_byte_sex != get_host_byte_sex()) swap_nlist(all_symbols, st->nsyms, get_host_byte_sex()); if(ofile->dylib_module != NULL){ m = *ofile->dylib_module; refs = (struct dylib_reference *)(ofile->object_addr + dyst->extrefsymoff); if(ofile->object_byte_sex != get_host_byte_sex()){ swap_dylib_module(&m, 1, get_host_byte_sex()); swap_dylib_reference(refs + m.irefsym, m.nrefsym, get_host_byte_sex()); } for(i = 0; i < m.nrefsym; i++){ flags = refs[i + m.irefsym].flags; if(flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY || flags == REFERENCE_FLAG_UNDEFINED_LAZY || flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY || flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY){ undefined = all_symbols[refs[i + m.irefsym].isym]; if(flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY || flags == REFERENCE_FLAG_UNDEFINED_LAZY) undefined.n_type = N_UNDF | N_EXT; else undefined.n_type = N_UNDF; undefined.n_desc = (undefined.n_desc &~ REFERENCE_TYPE) | flags; undefined.n_value = 0; selected_symbols[(*nsymbols)++] = undefined; } } for(i = 0; i < m.nextdefsym; i++){ selected_symbols[(*nsymbols)++] = all_symbols[m.iextdefsym + i]; } for(i = 0; i < m.nlocalsym; i++){ selected_symbols[(*nsymbols)++] = all_symbols[m.ilocalsym + i]; } } else{ for(i = 0; i < st->nsyms; i++){ selected_symbols[(*nsymbols)++] = all_symbols[i]; } } if(ofile->object_byte_sex != get_host_byte_sex()) swap_nlist(all_symbols, st->nsyms, ofile->object_byte_sex); /* * Could reallocate selected symbols to the exact size but it is more * of a time waste than a memory savings. */ return(selected_symbols); }
enum bool get_sect_info( char *segname, /* input */ char *sectname, struct mach_header *mh, struct load_command *load_commands, enum byte_sex load_commands_byte_sex, char *object_addr, unsigned long object_size, char **sect_pointer, /* output */ unsigned long *sect_size, unsigned long *sect_addr, struct relocation_info **sect_relocs, unsigned long *sect_nrelocs, unsigned long *sect_flags) { enum byte_sex host_byte_sex; enum bool found; unsigned long i, j, left, size; struct load_command *lc, l; struct segment_command sg; struct section s; char *p; *sect_pointer = NULL; *sect_size = 0; *sect_addr = 0; *sect_relocs = NULL; *sect_nrelocs = 0; *sect_flags = 0; found = FALSE; host_byte_sex = get_host_byte_sex(); lc = load_commands; for(i = 0 ; found == FALSE && i < mh->ncmds; i++){ memcpy((char *)&l, (char *)lc, sizeof(struct load_command)); if(l.cmdsize % sizeof(long) != 0) error("load command %lu size not a multiple of " "sizeof(long)\n", i); if((char *)lc + l.cmdsize > (char *)load_commands + mh->sizeofcmds) error("load command %lu extends past end of load " "commands\n", i); left = mh->sizeofcmds - ((char *)lc - (char *)load_commands); switch(l.cmd){ case LC_SEGMENT: memset((char *)&sg, '\0', sizeof(struct segment_command)); size = left < sizeof(struct segment_command) ? left : sizeof(struct segment_command); memcpy((char *)&sg, (char *)lc, size); if((mh->filetype == MH_OBJECT && sg.segname[0] == '\0') || strncmp(sg.segname, segname, sizeof(sg.segname)) == 0){ p = (char *)lc + sizeof(struct segment_command); for(j = 0 ; found == FALSE && j < sg.nsects ; j++){ if(p + sizeof(struct section) > (char *)load_commands + mh->sizeofcmds){ error("section structure command extends past " "end of load commands\n"); } left = mh->sizeofcmds - (p - (char *)load_commands); memset((char *)&s, '\0', sizeof(struct section)); size = left < sizeof(struct section) ? left : sizeof(struct section); memcpy((char *)&s, p, size); if(strncmp(s.sectname, sectname, sizeof(s.sectname)) == 0){ found = TRUE; break; } if(p + sizeof(struct section) > (char *)load_commands + mh->sizeofcmds) return(FALSE); p += size; } } break; } if(l.cmdsize == 0){ error("load command %lu size zero (can't advance to other " "load commands)\n", i); break; } lc = (struct load_command *)((char *)lc + l.cmdsize); if((char *)lc > (char *)load_commands + mh->sizeofcmds) break; } if(found == FALSE) return(FALSE); if((s.flags & SECTION_TYPE) == S_ZEROFILL){ *sect_pointer = NULL; *sect_size = s.size; } else{ if(s.offset >= object_size){ error("section offset for section (%.16s,%.16s) is past end " "of file\n", s.segname, s.sectname); } else{ *sect_pointer = object_addr + s.offset; if(s.offset + s.size > object_size){ error("section (%.16s,%.16s) extends past end of file\n", s.segname, s.sectname); *sect_size = object_size - s.offset; } else *sect_size = s.size; } } if(s.reloff >= object_size){ error("relocation entries offset for (%.16s,%.16s): is past end " "of file\n", s.segname, s.sectname); } else{ *sect_relocs = (struct relocation_info *)(object_addr + s.reloff); if(s.reloff + s.nreloc * sizeof(struct relocation_info) > object_size){ error("relocation entries for section (%.16s,%.16s) extends " "past end of file\n", s.segname, s.sectname); *sect_nrelocs = (object_size - s.reloff) / sizeof(struct relocation_info); } else *sect_nrelocs = s.nreloc; } *sect_addr = s.addr; *sect_flags = s.flags; return(TRUE); }
static void process( struct arch *archs, unsigned long narchs) { unsigned long i, j, k, offset, size; struct object *object; struct load_command *lc; struct segment_command *sg; for(i = 0; i < narchs; i++){ if(archs[i].type == OFILE_ARCHIVE){ for(j = 0; j < archs[i].nmembers; j++){ if(archs[i].members[j].type == OFILE_Mach_O){ object = archs[i].members[j].object; lc = object->load_commands; for(k = 0; k < object->mh->ncmds; k++){ if(lc->cmd == LC_SYMTAB){ object->st = (struct symtab_command *)lc; } else if(lc->cmd == LC_SEGMENT){ sg = (struct segment_command *)lc; hack_seg(object, lc, sg); } else if(lc->cmd == LC_DYSYMTAB){ error_arch(archs + i, archs[i].members + j, "can't process -dynamic object: "); return; } lc = (struct load_command *)((char *)lc + lc->cmdsize); } if(object->st != NULL && object->st->nsyms != 0){ object->output_symbols = (struct nlist *)(object->object_addr + object->st->symoff); if(object->object_byte_sex != get_host_byte_sex()) swap_nlist(object->output_symbols, object->st->nsyms, get_host_byte_sex()); object->output_nsymbols = object->st->nsyms; object->output_strings = object->object_addr + object->st->stroff; object->output_strings_size = object->st->strsize; object->input_sym_info_size = object->st->nsyms * sizeof(struct nlist) + object->st->strsize; object->output_sym_info_size = object->input_sym_info_size; } } } /* * Reset the library offsets and size. */ offset = 0; for(j = 0; j < archs[i].nmembers; j++){ archs[i].members[j].offset = offset; size = 0; if(archs[i].members[j].member_long_name == TRUE){ size = round(archs[i].members[j].member_name_size, sizeof(long)); archs[i].toc_long_name = TRUE; } if(archs[i].members[j].object != NULL){ size += archs[i].members[j].object->object_size - archs[i].members[j].object->input_sym_info_size + archs[i].members[j].object->output_sym_info_size; sprintf(archs[i].members[j].ar_hdr->ar_size, "%-*ld", (int)sizeof(archs[i].members[j].ar_hdr->ar_size), (long)(size)); /* * This has to be done by hand because sprintf puts a * null at the end of the buffer. */ memcpy(archs[i].members[j].ar_hdr->ar_fmag, ARFMAG, (int)sizeof(archs[i].members[j].ar_hdr->ar_fmag)); } else{ size += archs[i].members[j].unknown_size; } offset += sizeof(struct ar_hdr) + size; } archs[i].library_size = offset; } else if(archs[i].type == OFILE_Mach_O){ object = archs[i].object; lc = object->load_commands; for(j = 0; j < object->mh->ncmds; j++){ if(lc->cmd == LC_SYMTAB){ object->st = (struct symtab_command *)lc; } else if(lc->cmd == LC_SEGMENT){ sg = (struct segment_command *)lc; hack_seg(object, lc, sg); } else if(lc->cmd == LC_DYSYMTAB){ error_arch(archs + i, NULL, "can't process -dynamic " "object: "); return; } lc = (struct load_command *)((char *)lc + lc->cmdsize); } if(object->st != NULL && object->st->nsyms != 0){ object->output_symbols = (struct nlist *)(object->object_addr + object->st->symoff); if(object->object_byte_sex != get_host_byte_sex()){ swap_nlist(object->output_symbols, object->st->nsyms, get_host_byte_sex()); } object->output_nsymbols = object->st->nsyms; object->output_strings = object->object_addr + object->st->stroff; object->output_strings_size = object->st->strsize; object->input_sym_info_size = object->st->nsyms * sizeof(struct nlist) + object->st->strsize; object->output_sym_info_size = object->input_sym_info_size; } /* * Always clear the prebind checksum if any when creating a new * file. */ if(object->cs != NULL) object->cs->cksum = 0; } } }
unsigned long nsorted_symbols, char *strings, unsigned long strings_size, enum bool verbose) { enum byte_sex host_byte_sex; enum bool swapped; unsigned long opcode; unsigned int i, num, do_completers; char *format, c; int jbsr; unsigned long sect_offset; jbsr = 0; sect_offset = addr - sect_addr; host_byte_sex = get_host_byte_sex(); swapped = host_byte_sex != object_byte_sex; if(left < sizeof(unsigned long)){ if(left != 0){ memcpy(&opcode, sect, left); if(swapped) opcode = SWAP_LONG(opcode); printf(".long\t0x%08x\n", (unsigned int)opcode); } printf("(end of section)\n"); return(left); } memcpy(&opcode, sect, sizeof(unsigned long)); if(swapped)
enum bool swap_object_headers( void *mach_header, struct load_command *load_commands) { unsigned long i; uint32_t magic, ncmds, sizeofcmds, cmd_multiple; cpu_type_t cputype; cpu_subtype_t cpusubtype; struct mach_header *mh; struct mach_header_64 *mh64; enum byte_sex target_byte_sex; struct load_command *lc, l; struct segment_command *sg; struct segment_command_64 *sg64; struct section *s; struct section_64 *s64; struct symtab_command *st; struct dysymtab_command *dyst; struct symseg_command *ss; struct fvmlib_command *fl; struct thread_command *ut; struct ident_command *id; struct dylib_command *dl; struct sub_framework_command *sub; struct sub_umbrella_command *usub; struct sub_library_command *lsub; struct sub_client_command *csub; struct prebound_dylib_command *pbdylib; struct dylinker_command *dyld; struct routines_command *rc; struct routines_command_64 *rc64; struct twolevel_hints_command *hints; struct prebind_cksum_command *cs; struct uuid_command *uuid; unsigned long flavor, count, nflavor; char *p, *state; magic = *((uint32_t *)mach_header); if(magic == MH_MAGIC){ mh = (struct mach_header *)mach_header; ncmds = mh->ncmds; sizeofcmds = mh->sizeofcmds; cputype = mh->cputype; cpusubtype = mh->cpusubtype; cmd_multiple = 4; mh64 = NULL; } else{ mh64 = (struct mach_header_64 *)mach_header; ncmds = mh64->ncmds; sizeofcmds = mh64->sizeofcmds; cputype = mh64->cputype; cpusubtype = mh64->cpusubtype; cmd_multiple = 8; mh = NULL; } /* * Make a pass through the load commands checking them to the level * that they can be parsed and then swapped. */ for(i = 0, lc = load_commands; i < ncmds; i++){ l = *lc; /* check load command size for a correct multiple size */ if(lc->cmdsize % cmd_multiple != 0){ error("in swap_object_headers(): malformed load command %lu " "(cmdsize not a multiple of %u)", i, cmd_multiple); return(FALSE); } /* check that load command does not extends past end of commands */ if((char *)lc + lc->cmdsize > (char *)load_commands + sizeofcmds){ error("in swap_object_headers(): truncated or malformed load " "command %lu (extends past the end of the all load " "commands)", i); return(FALSE); } /* check that the load command size is not zero */ if(lc->cmdsize == 0){ error("in swap_object_headers(): malformed load command %lu " "(cmdsize is zero)", i); return(FALSE); } switch(lc->cmd){ case LC_SEGMENT: sg = (struct segment_command *)lc; if(sg->cmdsize != sizeof(struct segment_command) + sg->nsects * sizeof(struct section)){ error("in swap_object_headers(): malformed load command " "(inconsistent cmdsize in LC_SEGMENT command %lu for " "the number of sections)", i); return(FALSE); } break; case LC_SEGMENT_64: sg64 = (struct segment_command_64 *)lc; if(sg64->cmdsize != sizeof(struct segment_command_64) + sg64->nsects * sizeof(struct section_64)){ error("in swap_object_headers(): malformed load command " "(inconsistent cmdsize in LC_SEGMENT_64 command %lu " "for the number of sections)", i); return(FALSE); } break; case LC_SYMTAB: st = (struct symtab_command *)lc; if(st->cmdsize != sizeof(struct symtab_command)){ error("in swap_object_headers(): malformed load commands " "(LC_SYMTAB command %lu has incorrect cmdsize", i); return(FALSE); } break; case LC_DYSYMTAB: dyst = (struct dysymtab_command *)lc; if(dyst->cmdsize != sizeof(struct dysymtab_command)){ error("in swap_object_headers(): malformed load commands " "(LC_DYSYMTAB command %lu has incorrect cmdsize", i); return(FALSE); } break; case LC_SYMSEG: ss = (struct symseg_command *)lc; if(ss->cmdsize != sizeof(struct symseg_command)){ error("in swap_object_headers(): malformed load command " "(LC_SYMSEG command %lu has incorrect cmdsize", i); return(FALSE); } break; case LC_IDFVMLIB: case LC_LOADFVMLIB: fl = (struct fvmlib_command *)lc; if(fl->cmdsize < sizeof(struct fvmlib_command)){ error("in swap_object_headers(): malformed load commands " "(%s command %lu has too small cmdsize field)", fl->cmd == LC_IDFVMLIB ? "LC_IDFVMLIB" : "LC_LOADFVMLIB", i); return(FALSE); } if(fl->fvmlib.name.offset >= fl->cmdsize){ error("in swap_object_headers(): truncated or malformed " "load commands (name.offset field of %s command %lu " "extends past the end of all load commands)", fl->cmd == LC_IDFVMLIB ? "LC_IDFVMLIB" : "LC_LOADFVMLIB", i); return(FALSE); } break; case LC_ID_DYLIB: case LC_LOAD_DYLIB: case LC_LOAD_WEAK_DYLIB: dl = (struct dylib_command *)lc; if(dl->cmdsize < sizeof(struct dylib_command)){ error("in swap_object_headers(): malformed load commands " "(%s command %lu has too small cmdsize field)", dl->cmd == LC_ID_DYLIB ? "LC_ID_DYLIB" : (dl->cmd == LC_LOAD_DYLIB ? "LC_LOAD_DYLIB" : "LC_LOAD_WEAK_DYLIB"), i); return(FALSE); } if(dl->dylib.name.offset >= dl->cmdsize){ error("in swap_object_headers(): truncated or malformed " "load commands (name.offset field of %s command %lu " "extends past the end of all load commands)", dl->cmd == LC_ID_DYLIB ? "LC_ID_DYLIB" : (dl->cmd == LC_LOAD_DYLIB ? "LC_LOAD_DYLIB" : "LC_LOAD_WEAK_DYLIB"), i); return(FALSE); } break; case LC_SUB_FRAMEWORK: sub = (struct sub_framework_command *)lc; if(sub->cmdsize < sizeof(struct sub_framework_command)){ error("in swap_object_headers(): malformed load commands " "(LC_SUB_FRAMEWORK command %lu has too small cmdsize " "field)", i); return(FALSE); } if(sub->umbrella.offset >= sub->cmdsize){ error("in swap_object_headers(): truncated or malformed " "load commands (umbrella.offset field of " "LC_SUB_FRAMEWORK command %lu extends past the end " "of all load commands)", i); return(FALSE); } break; case LC_SUB_UMBRELLA: usub = (struct sub_umbrella_command *)lc; if(usub->cmdsize < sizeof(struct sub_umbrella_command)){ error("in swap_object_headers(): malformed load commands " "(LC_SUB_UMBRELLA command %lu has too small cmdsize " "field)", i); return(FALSE); } if(usub->sub_umbrella.offset >= usub->cmdsize){ error("in swap_object_headers(): truncated or malformed " "load commands (sub_umbrella.offset field of " "LC_SUB_UMBRELLA command %lu extends past the end " "of all load commands)", i); return(FALSE); } break; case LC_SUB_LIBRARY: lsub = (struct sub_library_command *)lc; if(lsub->cmdsize < sizeof(struct sub_library_command)){ error("in swap_object_headers(): malformed load commands " "(LC_SUB_LIBRARY command %lu has too small cmdsize " "field)", i); return(FALSE); } if(lsub->sub_library.offset >= lsub->cmdsize){ error("in swap_object_headers(): truncated or malformed " "load commands (sub_library.offset field of " "LC_SUB_LIBRARY command %lu extends past the end " "of all load commands)", i); return(FALSE); } break; case LC_SUB_CLIENT: csub = (struct sub_client_command *)lc; if(csub->cmdsize < sizeof(struct sub_client_command)){ error("in swap_object_headers(): malformed load commands " "(LC_SUB_CLIENT command %lu has too small cmdsize " "field)", i); return(FALSE); } if(csub->client.offset >= csub->cmdsize){ error("in swap_object_headers(): truncated or malformed " "load commands (client.offset field of " "LC_SUB_CLIENT command %lu extends past the end " "of all load commands)", i); return(FALSE); } break; case LC_PREBOUND_DYLIB: pbdylib = (struct prebound_dylib_command *)lc; if(pbdylib->cmdsize < sizeof(struct prebound_dylib_command)){ error("in swap_object_headers(): malformed load commands " "(LC_PREBOUND_DYLIB command %lu has too small " "cmdsize field)", i); return(FALSE); } if(pbdylib->name.offset >= pbdylib->cmdsize){ error("in swap_object_headers(): truncated or malformed " "load commands (name.offset field of " "LC_PREBOUND_DYLIB command %lu extends past the end " "of all load commands)", i); return(FALSE); } if(pbdylib->linked_modules.offset >= pbdylib->cmdsize){ error("in swap_object_headers(): truncated or malformed " "load commands (linked_modules.offset field of " "LC_PREBOUND_DYLIB command %lu extends past the end " "of all load commands)", i); return(FALSE); } break; case LC_ID_DYLINKER: case LC_LOAD_DYLINKER: dyld = (struct dylinker_command *)lc; if(dyld->cmdsize < sizeof(struct dylinker_command)){ error("in swap_object_headers(): malformed load commands " "(%s command %lu has too small cmdsize field)", dyld->cmd == LC_ID_DYLINKER ? "LC_ID_DYLINKER" : "LC_LOAD_DYLINKER", i); return(FALSE); } if(dyld->name.offset >= dyld->cmdsize){ error("in swap_object_headers(): truncated or malformed " "load commands (name.offset field of %s command %lu " "extends past the end of all load commands)", dyld->cmd == LC_ID_DYLINKER ? "LC_ID_DYLINKER" : "LC_LOAD_DYLINKER", i); return(FALSE); } break; case LC_UNIXTHREAD: case LC_THREAD: ut = (struct thread_command *)lc; state = (char *)ut + sizeof(struct thread_command); if(cputype == CPU_TYPE_MC680x0){ struct m68k_thread_state_regs *cpu; struct m68k_thread_state_68882 *fpu; struct m68k_thread_state_user_reg *user_reg; nflavor = 0; p = (char *)ut + ut->cmdsize; while(state < p){ flavor = *((unsigned long *)state); state += sizeof(unsigned long); count = *((unsigned long *)state); state += sizeof(unsigned long); switch(flavor){ case M68K_THREAD_STATE_REGS: if(count != M68K_THREAD_STATE_REGS_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not M68K_THREAD_STATE_REGS_COUNT for " "flavor number %lu which is a M68K_THREAD_" "STATE_REGS flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } cpu = (struct m68k_thread_state_regs *)state; state += sizeof(struct m68k_thread_state_regs); break; case M68K_THREAD_STATE_68882: if(count != M68K_THREAD_STATE_68882_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not M68K_THREAD_STATE_68882_COUNT for " "flavor number %lu which is a M68K_THREAD_" "STATE_68882 flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } fpu = (struct m68k_thread_state_68882 *)state; state += sizeof(struct m68k_thread_state_68882); break; case M68K_THREAD_STATE_USER_REG: if(count != M68K_THREAD_STATE_USER_REG_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not M68K_THREAD_STATE_USER_REG_COUNT for " "flavor number %lu which is a M68K_THREAD_" "STATE_USER_REG flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } user_reg = (struct m68k_thread_state_user_reg *)state; state += sizeof(struct m68k_thread_state_user_reg); break; default: error("in swap_object_headers(): malformed " "load commands (unknown " "flavor %lu for flavor number %lu in %s command" " %lu can't byte swap it)", flavor, nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } nflavor++; } break; } if(cputype == CPU_TYPE_POWERPC || cputype == CPU_TYPE_VEO || cputype == CPU_TYPE_POWERPC64){ ppc_thread_state_t *cpu; ppc_float_state_t *fpu; ppc_exception_state_t *except; ppc_thread_state64_t *cpu64; nflavor = 0; p = (char *)ut + ut->cmdsize; while(state < p){ flavor = *((unsigned long *)state); state += sizeof(unsigned long); count = *((unsigned long *)state); state += sizeof(unsigned long); switch(flavor){ case PPC_THREAD_STATE: if(count != PPC_THREAD_STATE_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not PPC_THREAD_STATE_COUNT for " "flavor number %lu which is a PPC_THREAD_" "STATE flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } cpu = (ppc_thread_state_t *)state; state += sizeof(ppc_thread_state_t); break; case PPC_FLOAT_STATE: if(count != PPC_FLOAT_STATE_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not PPC_FLOAT_STATE_COUNT for " "flavor number %lu which is a PPC_FLOAT_" "STATE flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } fpu = (ppc_float_state_t *)state; state += sizeof(ppc_float_state_t); break; case PPC_EXCEPTION_STATE: if(count != PPC_EXCEPTION_STATE_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not PPC_EXCEPTION_STATE_COUNT for " "flavor number %lu which is a PPC_EXCEPT" "ION_STATE flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } except = (ppc_exception_state_t *)state; state += sizeof(ppc_exception_state_t); break; case PPC_THREAD_STATE64: if(count != PPC_THREAD_STATE64_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not PPC_THREAD_STATE64_COUNT for " "flavor number %lu which is a PPC_THREAD_" "STATE64 flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } cpu64 = (ppc_thread_state64_t *)state; state += sizeof(ppc_thread_state64_t); break; default: error("in swap_object_headers(): malformed " "load commands (unknown " "flavor %lu for flavor number %lu in %s command" " %lu can't byte swap it)", flavor, nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } nflavor++; } break; } if(cputype == CPU_TYPE_MC88000){ m88k_thread_state_grf_t *cpu; m88k_thread_state_xrf_t *fpu; m88k_thread_state_user_t *user; m88110_thread_state_impl_t *spu; nflavor = 0; p = (char *)ut + ut->cmdsize; while(state < p){ flavor = *((unsigned long *)state); state += sizeof(unsigned long); count = *((unsigned long *)state); state += sizeof(unsigned long); switch(flavor){ case M88K_THREAD_STATE_GRF: if(count != M88K_THREAD_STATE_GRF_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not M88K_THREAD_STATE_GRF_COUNT for " "flavor number %lu which is a M88K_THREAD_" "STATE_GRF flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } cpu = (m88k_thread_state_grf_t *)state; state += sizeof(m88k_thread_state_grf_t); break; case M88K_THREAD_STATE_XRF: if(count != M88K_THREAD_STATE_XRF_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not M88K_THREAD_STATE_XRF_COUNT for " "flavor number %lu which is a M88K_THREAD_" "STATE_XRF flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } fpu = (m88k_thread_state_xrf_t *)state; state += sizeof(m88k_thread_state_xrf_t); break; case M88K_THREAD_STATE_USER: if(count != M88K_THREAD_STATE_USER_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not M88K_THREAD_STATE_USER_COUNT for " "flavor number %lu which is a M88K_THREAD_" "STATE_USER flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } user = (m88k_thread_state_user_t *)state; state += sizeof(m88k_thread_state_user_t); break; case M88110_THREAD_STATE_IMPL: if(count != M88110_THREAD_STATE_IMPL_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not M88110_THREAD_STATE_IMPL_COUNT for " "flavor number %lu which is a M88110_THREAD" "_STATE_IMPL flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } spu = (m88110_thread_state_impl_t *)state; state += sizeof(m88110_thread_state_impl_t); break; default: error("in swap_object_headers(): malformed " "load commands (unknown " "flavor %lu for flavor number %lu in %s command" " %lu can't byte swap it)", flavor, nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } nflavor++; } break; } if(cputype == CPU_TYPE_I860){ struct i860_thread_state_regs *cpu; nflavor = 0; p = (char *)ut + ut->cmdsize; while(state < p){ flavor = *((unsigned long *)state); state += sizeof(unsigned long); count = *((unsigned long *)state); state += sizeof(unsigned long); switch(flavor){ case I860_THREAD_STATE_REGS: if(count != I860_THREAD_STATE_REGS_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not I860_THREAD_STATE_REGS_COUNT for " "flavor number %lu which is a I860_THREAD_" "STATE_REGS flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } cpu = (struct i860_thread_state_regs *)state; state += sizeof(struct i860_thread_state_regs); break; default: error("in swap_object_headers(): malformed " "load commands (unknown " "flavor %lu for flavor number %lu in %s command" " %lu can't byte swap it)", flavor, nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } nflavor++; } break; } if(cputype == CPU_TYPE_I386 #ifdef x86_THREAD_STATE64 || cputype == CPU_TYPE_X86_64 #endif /* x86_THREAD_STATE64 */ ){ i386_thread_state_t *cpu; #ifdef x86_THREAD_STATE64 x86_thread_state64_t *cpu64; #endif /* x86_THREAD_STATE64 */ /* current i386 thread states */ #if i386_THREAD_STATE == 1 struct i386_float_state *fpu; i386_exception_state_t *exc; #endif /* i386_THREAD_STATE == 1 */ /* i386 thread states on older releases */ #if i386_THREAD_STATE == -1 i386_thread_fpstate_t *fpu; i386_thread_exceptstate_t *exc; i386_thread_cthreadstate_t *user; #endif /* i386_THREAD_STATE == -1 */ nflavor = 0; p = (char *)ut + ut->cmdsize; while(state < p){ flavor = *((unsigned long *)state); state += sizeof(unsigned long); count = *((unsigned long *)state); state += sizeof(unsigned long); switch(flavor){ case i386_THREAD_STATE: /* current i386 thread states */ #if i386_THREAD_STATE == 1 case -1: #endif /* i386_THREAD_STATE == 1 */ /* i386 thread states on older releases */ #if i386_THREAD_STATE == -1 case 1: #endif /* i386_THREAD_STATE == -1 */ if(count != i386_THREAD_STATE_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not i386_THREAD_STATE_COUNT for flavor " "number %lu which is a i386_THREAD_STATE " "flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } cpu = (i386_thread_state_t *)state; state += sizeof(i386_thread_state_t); break; /* current i386 thread states */ #if i386_THREAD_STATE == 1 case i386_FLOAT_STATE: if(count != i386_FLOAT_STATE_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not i386_FLOAT_STATE_COUNT for flavor " "number %lu which is a i386_FLOAT_STATE " "flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } fpu = (struct i386_float_state *)state; state += sizeof(struct i386_float_state); break; case i386_EXCEPTION_STATE: if(count != I386_EXCEPTION_STATE_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not I386_EXCEPTION_STATE_COUNT for " "flavor number %lu which is a i386_" "EXCEPTION_STATE flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } exc = (i386_exception_state_t *)state; state += sizeof(i386_exception_state_t); break; #endif /* i386_THREAD_STATE == 1 */ /* i386 thread states on older releases */ #if i386_THREAD_STATE == -1 case i386_THREAD_FPSTATE: if(count != i386_THREAD_FPSTATE_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not i386_THREAD_FPSTATE_COUNT for flavor " "number %lu which is a i386_THREAD_FPSTATE " "flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } fpu = (i386_thread_fpstate_t *)state; state += sizeof(i386_thread_fpstate_t); break; case i386_THREAD_EXCEPTSTATE: if(count != i386_THREAD_EXCEPTSTATE_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not i386_THREAD_EXCEPTSTATE_COUNT for " "flavor number %lu which is a i386_THREAD_" "EXCEPTSTATE flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } exc = (i386_thread_exceptstate_t *)state; state += sizeof(i386_thread_fpstate_t); break; case i386_THREAD_CTHREADSTATE: if(count != i386_THREAD_CTHREADSTATE_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not i386_THREAD_CTHREADSTATE_COUNT for " "flavor number %lu which is a i386_THREAD_" "CTHREADSTATE flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } user = (i386_thread_cthreadstate_t *)state; state += sizeof(i386_thread_fpstate_t); break; #endif /* i386_THREAD_STATE == -1 */ #ifdef x86_THREAD_STATE64 case x86_THREAD_STATE64: if(count != x86_THREAD_STATE64_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not x86_THREAD_STATE64_COUNT for " "flavor number %lu which is an x86_THREAD_" "STATE64 flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } cpu64 = (x86_thread_state64_t *)state; state += sizeof(x86_thread_state64_t); break; #endif /* x86_THREAD_STATE64 */ default: error("in swap_object_headers(): malformed " "load commands (unknown " "flavor %lu for flavor number %lu in %s command" " %lu can't byte swap it)", flavor, nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } nflavor++; } break; } if(cputype == CPU_TYPE_HPPA){ struct hp_pa_integer_thread_state *cpu; struct hp_pa_frame_thread_state *frame; struct hp_pa_fp_thread_state *fpu; nflavor = 0; p = (char *)ut + ut->cmdsize; while(state < p){ flavor = *((unsigned long *)state); state += sizeof(unsigned long); count = *((unsigned long *)state); state += sizeof(unsigned long); switch(flavor){ case HPPA_INTEGER_THREAD_STATE: if(count != HPPA_INTEGER_THREAD_STATE_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not HPPA_INTEGER_THREAD_STATE_COUNT for " "flavor number %lu which is a HPPA_INTEGER" "_THREAD_STATE flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } cpu = (struct hp_pa_integer_thread_state *)state; state += sizeof(struct hp_pa_integer_thread_state); break; case HPPA_FRAME_THREAD_STATE: if(count != HPPA_FRAME_THREAD_STATE_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not HPPA_FRAME_THREAD_STATE_COUNT for " "flavor number %lu which is a HPPA_FRAME" "_THREAD_STATE flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } frame = (struct hp_pa_frame_thread_state *)state; state += sizeof(struct hp_pa_frame_thread_state); break; case HPPA_FP_THREAD_STATE: if(count != HPPA_FP_THREAD_STATE_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not HPPA_FP_THREAD_STATE_COUNT for " "flavor number %lu which is a HPPA_FP" "_THREAD_STATE flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } fpu = (struct hp_pa_fp_thread_state *)state; state += sizeof(struct hp_pa_fp_thread_state); break; default: error("in swap_object_headers(): malformed " "load commands (unknown " "flavor %lu for flavor number %lu in %s command" " %lu can't byte swap it)", flavor, nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } nflavor++; } break; } if(cputype == CPU_TYPE_SPARC) { struct sparc_thread_state_regs *cpu; struct sparc_thread_state_fpu *fpu; nflavor = 0; p = (char *)ut + ut->cmdsize; while (state < p) { flavor = *((unsigned long *) state); state += sizeof(unsigned long); count = *((unsigned int *) state); state += sizeof(unsigned long); switch (flavor) { case SPARC_THREAD_STATE_REGS: if (count != SPARC_THREAD_STATE_REGS_COUNT) { error("in swap_object_headers(): malformed " "load commands (count " "not SPARC_THREAD_STATE_REGS_COUNT for " "flavor number %lu which is a SPARC_THREAD_" "STATE_REGS flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } cpu = (struct sparc_thread_state_regs *) state; state += sizeof(struct sparc_thread_state_regs); break; case SPARC_THREAD_STATE_FPU: if (count != SPARC_THREAD_STATE_FPU_COUNT) { error("in swap_object_headers(): malformed " "load commands (count " "not SPARC_THREAD_STATE_FPU_COUNT for " "flavor number %lu which is a SPARC_THREAD_" "STATE_FPU flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } fpu = (struct sparc_thread_state_fpu *) state; state += sizeof(struct sparc_thread_state_fpu); break; } } break; } if (cputype == CPU_TYPE_ARM) { nflavor = 0; p = (char *)ut + ut->cmdsize; while (state < p) { state += 8 + sizeof(arm_thread_state_t); nflavor++; } break; } error("in swap_object_headers(): malformed load commands " "(unknown cputype (%d) and cpusubtype (%d) of object and " "can't byte swap %s command %lu)", cputype, cpusubtype, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); case LC_IDENT: id = (struct ident_command *)lc; if((char *)id + id->cmdsize > (char *)load_commands + sizeofcmds){ error("in swap_object_headers(): truncated or malformed " "load commands (cmdsize field of LC_IDENT command %lu " "extends past the end of the load commands)", i); return(FALSE); } break; case LC_ROUTINES: rc = (struct routines_command *)lc; if(rc->cmdsize != sizeof(struct routines_command)){ error("in swap_object_headers(): malformed load commands (" "LC_ROUTINES command %lu has incorrect cmdsize", i); return(FALSE); } break; case LC_ROUTINES_64: rc64 = (struct routines_command_64 *)lc; if(rc64->cmdsize != sizeof(struct routines_command_64)){ error("in swap_object_headers(): malformed load commands (" "LC_ROUTINES_64 command %lu has incorrect cmdsize", i); return(FALSE); } break; case LC_TWOLEVEL_HINTS: hints = (struct twolevel_hints_command *)lc; if(hints->cmdsize != sizeof(struct twolevel_hints_command)){ error("in swap_object_headers(): malformed load commands " "(LC_TWOLEVEL_HINTS command %lu has incorrect " "cmdsize", i); return(FALSE); } break; case LC_PREBIND_CKSUM: cs = (struct prebind_cksum_command *)lc; if(cs->cmdsize != sizeof(struct prebind_cksum_command)){ error("in swap_object_headers(): malformed load commands " "(LC_PREBIND_CKSUM command %lu has incorrect cmdsize", i); return(FALSE); } break; case LC_UUID: uuid = (struct uuid_command *)lc; if(uuid->cmdsize != sizeof(struct uuid_command)){ error("in swap_object_headers(): malformed load commands " "(LC_UUID command %lu has incorrect cmdsize", i); return(FALSE); } break; default: error("in swap_object_headers(): malformed load commands " "(unknown load command %lu)", i); return(FALSE); } lc = (struct load_command *)((char *)lc + l.cmdsize); /* check that next load command does not extends past the end */ if((char *)lc > (char *)load_commands + sizeofcmds){ error("in swap_object_headers(): truncated or malformed load " "commands (load command %lu extends past the end of all " "load commands)", i + 1); return(FALSE); } } /* check for an inconsistent size of the load commands */ if((char *)load_commands + sizeofcmds != (char *)lc){ error("in swap_object_headers(): malformed load commands " "(inconsistent sizeofcmds field in mach header)"); return(FALSE); } /* * Now knowing the load commands can be parsed swap them. */ target_byte_sex = get_host_byte_sex() == BIG_ENDIAN_BYTE_SEX ? LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX; for(i = 0, lc = load_commands; i < ncmds; i++){ l = *lc; switch(lc->cmd){ case LC_SEGMENT: sg = (struct segment_command *)lc; s = (struct section *) ((char *)sg + sizeof(struct segment_command)); swap_section(s, sg->nsects, target_byte_sex); swap_segment_command(sg, target_byte_sex); break; case LC_SEGMENT_64: sg64 = (struct segment_command_64 *)lc; s64 = (struct section_64 *) ((char *)sg64 + sizeof(struct segment_command_64)); swap_section_64(s64, sg64->nsects, target_byte_sex); swap_segment_command_64(sg64, target_byte_sex); break; case LC_SYMTAB: st = (struct symtab_command *)lc; swap_symtab_command(st, target_byte_sex); break; case LC_DYSYMTAB: dyst = (struct dysymtab_command *)lc; swap_dysymtab_command(dyst, target_byte_sex); break; case LC_SYMSEG: ss = (struct symseg_command *)lc; swap_symseg_command(ss, target_byte_sex); break; case LC_IDFVMLIB: case LC_LOADFVMLIB: fl = (struct fvmlib_command *)lc; swap_fvmlib_command(fl, target_byte_sex); break; case LC_ID_DYLIB: case LC_LOAD_DYLIB: case LC_LOAD_WEAK_DYLIB: dl = (struct dylib_command *)lc; swap_dylib_command(dl, target_byte_sex); break; case LC_SUB_FRAMEWORK: sub = (struct sub_framework_command *)lc; swap_sub_framework_command(sub, target_byte_sex); break; case LC_SUB_UMBRELLA: usub = (struct sub_umbrella_command *)lc; swap_sub_umbrella_command(usub, target_byte_sex); break; case LC_SUB_LIBRARY: lsub = (struct sub_library_command *)lc; swap_sub_library_command(lsub, target_byte_sex); break; case LC_SUB_CLIENT: csub = (struct sub_client_command *)lc; swap_sub_client_command(csub, target_byte_sex); break; case LC_PREBOUND_DYLIB: pbdylib = (struct prebound_dylib_command *)lc; swap_prebound_dylib_command(pbdylib, target_byte_sex); break; case LC_ID_DYLINKER: case LC_LOAD_DYLINKER: dyld = (struct dylinker_command *)lc; swap_dylinker_command(dyld, target_byte_sex); break; case LC_UNIXTHREAD: case LC_THREAD: ut = (struct thread_command *)lc; state = (char *)ut + sizeof(struct thread_command); p = (char *)ut + ut->cmdsize; swap_thread_command(ut, target_byte_sex); if(cputype == CPU_TYPE_MC680x0){ struct m68k_thread_state_regs *cpu; struct m68k_thread_state_68882 *fpu; struct m68k_thread_state_user_reg *user_reg; while(state < p){ flavor = *((unsigned long *)state); *((unsigned long *)state) = SWAP_LONG(flavor); state += sizeof(unsigned long); count = *((unsigned long *)state); *((unsigned long *)state) = SWAP_LONG(count); state += sizeof(unsigned long); switch(flavor){ case M68K_THREAD_STATE_REGS: cpu = (struct m68k_thread_state_regs *)state; swap_m68k_thread_state_regs(cpu, target_byte_sex); state += sizeof(struct m68k_thread_state_regs); break; case M68K_THREAD_STATE_68882: fpu = (struct m68k_thread_state_68882 *)state; swap_m68k_thread_state_68882(fpu, target_byte_sex); state += sizeof(struct m68k_thread_state_68882); break; case M68K_THREAD_STATE_USER_REG: user_reg = (struct m68k_thread_state_user_reg *)state; swap_m68k_thread_state_user_reg(user_reg, target_byte_sex); state += sizeof(struct m68k_thread_state_user_reg); break; } } break; } if(cputype == CPU_TYPE_POWERPC || cputype == CPU_TYPE_VEO || cputype == CPU_TYPE_POWERPC64){ ppc_thread_state_t *cpu; ppc_thread_state64_t *cpu64; ppc_float_state_t *fpu; ppc_exception_state_t *except; while(state < p){ flavor = *((unsigned long *)state); *((unsigned long *)state) = SWAP_LONG(flavor); state += sizeof(unsigned long); count = *((unsigned long *)state); *((unsigned long *)state) = SWAP_LONG(count); state += sizeof(unsigned long); switch(flavor){ case PPC_THREAD_STATE: cpu = (ppc_thread_state_t *)state; swap_ppc_thread_state_t(cpu, target_byte_sex); state += sizeof(ppc_thread_state_t); break; case PPC_THREAD_STATE64: cpu64 = (ppc_thread_state64_t *)state; swap_ppc_thread_state64_t(cpu64, target_byte_sex); state += sizeof(ppc_thread_state64_t); break; case PPC_FLOAT_STATE: fpu = (ppc_float_state_t *)state; swap_ppc_float_state_t(fpu, target_byte_sex); state += sizeof(ppc_float_state_t); case PPC_EXCEPTION_STATE: except = (ppc_exception_state_t *)state; swap_ppc_exception_state_t(except, target_byte_sex); state += sizeof(ppc_exception_state_t); break; } } break; } if(cputype == CPU_TYPE_MC88000){ m88k_thread_state_grf_t *cpu; m88k_thread_state_xrf_t *fpu; m88k_thread_state_user_t *user; m88110_thread_state_impl_t *spu; while(state < p){ flavor = *((unsigned long *)state); *((unsigned long *)state) = SWAP_LONG(flavor); state += sizeof(unsigned long); count = *((unsigned long *)state); *((unsigned long *)state) = SWAP_LONG(count); state += sizeof(unsigned long); switch(flavor){ case M88K_THREAD_STATE_GRF: cpu = (m88k_thread_state_grf_t *)state; swap_m88k_thread_state_grf_t(cpu, target_byte_sex); state += sizeof(m88k_thread_state_grf_t); break; case M88K_THREAD_STATE_XRF: fpu = (m88k_thread_state_xrf_t *)state; swap_m88k_thread_state_xrf_t(fpu, target_byte_sex); state += sizeof(m88k_thread_state_xrf_t); break; case M88K_THREAD_STATE_USER: user = (m88k_thread_state_user_t *)state; swap_m88k_thread_state_user_t(user, target_byte_sex); state += sizeof(m88k_thread_state_user_t); break; case M88110_THREAD_STATE_IMPL: spu = (m88110_thread_state_impl_t *)state; swap_m88110_thread_state_impl_t(spu, target_byte_sex); state += sizeof(m88110_thread_state_impl_t); break; } } break; } if(cputype == CPU_TYPE_I860){ struct i860_thread_state_regs *cpu; while(state < p){ flavor = *((unsigned long *)state); *((unsigned long *)state) = SWAP_LONG(flavor); state += sizeof(unsigned long); count = *((unsigned long *)state); *((unsigned long *)state) = SWAP_LONG(count); state += sizeof(unsigned long); switch(flavor){ case I860_THREAD_STATE_REGS: cpu = (struct i860_thread_state_regs *)state; swap_i860_thread_state_regs(cpu, target_byte_sex); state += sizeof(struct i860_thread_state_regs); break; } } break; } if(cputype == CPU_TYPE_I386 #ifdef x86_THREAD_STATE64 || cputype == CPU_TYPE_X86_64 #endif /* x86_THREAD_STATE64 */ ){ i386_thread_state_t *cpu; #ifdef x86_THREAD_STATE64 x86_thread_state64_t *cpu64; #endif /* x86_THREAD_STATE64 */ /* current i386 thread states */ #if i386_THREAD_STATE == 1 struct i386_float_state *fpu; i386_exception_state_t *exc; #endif /* i386_THREAD_STATE == 1 */ /* i386 thread states on older releases */ #if i386_THREAD_STATE == -1 i386_thread_fpstate_t *fpu; i386_thread_exceptstate_t *exc; i386_thread_cthreadstate_t *user; #endif /* i386_THREAD_STATE == -1 */ while(state < p){ flavor = *((unsigned long *)state); *((unsigned long *)state) = SWAP_LONG(flavor); state += sizeof(unsigned long); count = *((unsigned long *)state); *((unsigned long *)state) = SWAP_LONG(count); state += sizeof(unsigned long); switch(flavor){ case i386_THREAD_STATE: /* current i386 thread states */ #if i386_THREAD_STATE == 1 case -1: #endif /* i386_THREAD_STATE == 1 */ /* i386 thread states on older releases */ #if i386_THREAD_STATE == -1 case 1: #endif /* i386_THREAD_STATE == -1 */ cpu = (i386_thread_state_t *)state; swap_i386_thread_state(cpu, target_byte_sex); state += sizeof(i386_thread_state_t); break; /* current i386 thread states */ #if i386_THREAD_STATE == 1 case i386_FLOAT_STATE: fpu = (struct i386_float_state *)state; swap_i386_float_state(fpu, target_byte_sex); state += sizeof(struct i386_float_state); break; case i386_EXCEPTION_STATE: exc = (i386_exception_state_t *)state; swap_i386_exception_state(exc, target_byte_sex); state += sizeof(i386_exception_state_t); break; #endif /* i386_THREAD_STATE == 1 */ /* i386 thread states on older releases */ #if i386_THREAD_STATE == -1 case i386_THREAD_FPSTATE: fpu = (i386_thread_fpstate_t *)state; swap_i386_thread_fpstate(fpu, target_byte_sex); state += sizeof(i386_thread_fpstate_t); break; case i386_THREAD_EXCEPTSTATE: exc = (i386_thread_exceptstate_t *)state; swap_i386_thread_exceptstate(exc, target_byte_sex); state += sizeof(i386_thread_exceptstate_t); break; case i386_THREAD_CTHREADSTATE: user = (i386_thread_cthreadstate_t *)state; swap_i386_thread_cthreadstate(user,target_byte_sex); state += sizeof(i386_thread_cthreadstate_t); break; #endif /* i386_THREAD_STATE == -1 */ #ifdef x86_THREAD_STATE64 case x86_THREAD_STATE64: cpu64 = (x86_thread_state64_t *)state; swap_x86_thread_state64(cpu64, target_byte_sex); state += sizeof(x86_thread_state64_t); break; #endif /* x86_THREAD_STATE64 */ } } break; } if(cputype == CPU_TYPE_HPPA){ struct hp_pa_integer_thread_state *cpu; struct hp_pa_frame_thread_state *frame; struct hp_pa_fp_thread_state *fpu; while(state < p){ flavor = *((unsigned long *)state); *((unsigned long *)state) = SWAP_LONG(flavor); state += sizeof(unsigned long); count = *((unsigned long *)state); *((unsigned long *)state) = SWAP_LONG(count); state += sizeof(unsigned long); switch(flavor){ case HPPA_INTEGER_THREAD_STATE: cpu = (struct hp_pa_integer_thread_state *)state; swap_hppa_integer_thread_state(cpu, target_byte_sex); state += sizeof(struct hp_pa_integer_thread_state); break; case HPPA_FRAME_THREAD_STATE: frame = (struct hp_pa_frame_thread_state *)state; swap_hppa_frame_thread_state(frame, target_byte_sex); state += sizeof(struct hp_pa_frame_thread_state); break; case HPPA_FP_THREAD_STATE: fpu = (struct hp_pa_fp_thread_state *)state; swap_hppa_fp_thread_state(fpu, target_byte_sex); state += sizeof(struct hp_pa_fp_thread_state); break; } } break; } if(cputype == CPU_TYPE_SPARC) { struct sparc_thread_state_regs *cpu; struct sparc_thread_state_fpu *fpu; while (state < p) { flavor = *((unsigned long *) state); *((unsigned long *) state) = SWAP_LONG(flavor); state += sizeof(unsigned long); count = *((unsigned int *) state); *((unsigned int *) state) = SWAP_LONG(count); state += sizeof(unsigned long); switch (flavor) { case SPARC_THREAD_STATE_REGS: cpu = (struct sparc_thread_state_regs *) state; swap_sparc_thread_state_regs(cpu, target_byte_sex); state += sizeof(struct sparc_thread_state_regs); break; case SPARC_THREAD_STATE_FPU: fpu = (struct sparc_thread_state_fpu *) state; swap_sparc_thread_state_fpu(fpu, target_byte_sex); state += sizeof(struct sparc_thread_state_fpu); break; } } break; } if (cputype == CPU_TYPE_ARM) { arm_thread_state_t *thread_state; while (state < p) { u_int32_t n; n = *((u_int32_t *)state); *((u_int32_t *)state) = SWAP_LONG(n); state += 4; n = *((u_int32_t *)state); *((u_int32_t *)state) = SWAP_LONG(n); state += 4; thread_state = (arm_thread_state_t *)state; swap_arm_thread_state(thread_state, target_byte_sex); state += sizeof(arm_thread_state_t); } } break; case LC_IDENT: id = (struct ident_command *)lc; swap_ident_command(id, target_byte_sex); break; case LC_ROUTINES: rc = (struct routines_command *)lc; swap_routines_command(rc, target_byte_sex); break; case LC_ROUTINES_64: rc64 = (struct routines_command_64 *)lc; swap_routines_command_64(rc64, target_byte_sex); break; case LC_TWOLEVEL_HINTS: hints = (struct twolevel_hints_command *)lc; swap_twolevel_hints_command(hints, target_byte_sex); break; case LC_PREBIND_CKSUM: cs = (struct prebind_cksum_command *)lc; swap_prebind_cksum_command(cs, target_byte_sex); break; case LC_UUID: uuid = (struct uuid_command *)lc; swap_uuid_command(uuid, target_byte_sex); break; } lc = (struct load_command *)((char *)lc + l.cmdsize); } if(mh != NULL) swap_mach_header(mh, target_byte_sex); else swap_mach_header_64(mh64, target_byte_sex); return(TRUE); }
static void setup_object_symbolic_info( struct object *object) { if(object->st != NULL && object->st->nsyms != 0){ object->output_symbols = (struct nlist *) (object->object_addr + object->st->symoff); if(object->object_byte_sex != get_host_byte_sex()) swap_nlist(object->output_symbols, object->st->nsyms, get_host_byte_sex()); object->output_nsymbols = object->st->nsyms; object->output_strings = object->object_addr + object->st->stroff; object->output_strings_size = object->st->strsize; object->input_sym_info_size = object->st->nsyms * sizeof(struct nlist) + object->st->strsize; object->output_sym_info_size = object->input_sym_info_size; } if(object->dyst != NULL){ object->output_ilocalsym = object->dyst->ilocalsym; object->output_nlocalsym = object->dyst->nlocalsym; object->output_iextdefsym = object->dyst->iextdefsym; object->output_nextdefsym = object->dyst->nextdefsym; object->output_iundefsym = object->dyst->iundefsym; object->output_nundefsym = object->dyst->nundefsym; object->output_loc_relocs = (struct relocation_info *) (object->object_addr + object->dyst->locreloff); object->output_ext_relocs = (struct relocation_info *) (object->object_addr + object->dyst->extreloff); object->output_indirect_symtab = (unsigned long *) (object->object_addr + object->dyst->indirectsymoff); object->output_tocs = (struct dylib_table_of_contents *) (object->object_addr + object->dyst->tocoff); object->output_ntoc = object->dyst->ntoc; object->output_mods = (struct dylib_module *) (object->object_addr + object->dyst->modtaboff); object->output_nmodtab = object->dyst->nmodtab; object->output_refs = (struct dylib_reference *) (object->object_addr + object->dyst->extrefsymoff); object->output_nextrefsyms = object->dyst->nextrefsyms; object->input_sym_info_size += object->dyst->nlocrel * sizeof(struct relocation_info) + object->dyst->nextrel * sizeof(struct relocation_info) + object->dyst->nindirectsyms * sizeof(unsigned long) + object->dyst->ntoc * sizeof(struct dylib_table_of_contents)+ object->dyst->nmodtab * sizeof(struct dylib_module) + object->dyst->nextrefsyms * sizeof(struct dylib_reference); object->output_sym_info_size += object->dyst->nlocrel * sizeof(struct relocation_info) + object->dyst->nextrel * sizeof(struct relocation_info) + object->dyst->nindirectsyms * sizeof(unsigned long) + object->dyst->ntoc * sizeof(struct dylib_table_of_contents)+ object->dyst->nmodtab * sizeof(struct dylib_module) + object->dyst->nextrefsyms * sizeof(struct dylib_reference); if(object->hints_cmd != NULL){ object->output_hints = (struct twolevel_hint *) (object->object_addr + object->hints_cmd->offset); object->input_sym_info_size += object->hints_cmd->nhints * sizeof(struct twolevel_hint); object->output_sym_info_size += object->hints_cmd->nhints * sizeof(struct twolevel_hint); } } }
/* * setup_code_signature() does the work to add or update the needed * LC_CODE_SIGNATURE load command for the specified broken out ofile if it * is of one of the architecures specifed with a -a command line options. */ static void setup_code_signature( struct arch *arch, struct member *member, struct object *object) { uint32_t i; cpu_type_t cputype; cpu_subtype_t cpusubtype; uint32_t flags, linkedit_end; uint32_t dyld_info_start; uint32_t dyld_info_end; uint32_t align_delta; linkedit_end = 0; /* * First set up all the pointers and sizes of the symbolic info. */ if(object->st != NULL && object->st->nsyms != 0) { if(object->mh != NULL) { object->output_symbols = (struct nlist *) (object->object_addr + object->st->symoff); if(object->object_byte_sex != get_host_byte_sex()) swap_nlist(object->output_symbols, object->st->nsyms, get_host_byte_sex()); object->output_symbols64 = NULL; } else { object->output_symbols64 = (struct nlist_64 *) (object->object_addr + object->st->symoff); if(object->object_byte_sex != get_host_byte_sex()) swap_nlist_64(object->output_symbols64, object->st->nsyms, get_host_byte_sex()); object->output_symbols = NULL; } object->output_nsymbols = object->st->nsyms; object->output_strings = object->object_addr + object->st->stroff; object->output_strings_size = object->st->strsize; if(object->mh != NULL) { object->input_sym_info_size = object->st->nsyms * sizeof(struct nlist) + object->st->strsize; } else { object->input_sym_info_size = object->st->nsyms * sizeof(struct nlist_64) + object->st->strsize; } } if(object->dyld_info != NULL) { /* there are five parts to the dyld info, but codesign_allocate does not alter them, so copy as a block */ dyld_info_start = 0; if (object->dyld_info->rebase_off != 0) dyld_info_start = object->dyld_info->rebase_off; else if (object->dyld_info->bind_off != 0) dyld_info_start = object->dyld_info->bind_off; else if (object->dyld_info->weak_bind_off != 0) dyld_info_start = object->dyld_info->weak_bind_off; else if (object->dyld_info->lazy_bind_off != 0) dyld_info_start = object->dyld_info->lazy_bind_off; else if (object->dyld_info->export_off != 0) dyld_info_start = object->dyld_info->export_off; dyld_info_end = 0; if (object->dyld_info->export_size != 0) dyld_info_end = object->dyld_info->export_off + object->dyld_info->export_size; else if (object->dyld_info->lazy_bind_size != 0) dyld_info_end = object->dyld_info->lazy_bind_off + object->dyld_info->lazy_bind_size; else if (object->dyld_info->weak_bind_size != 0) dyld_info_end = object->dyld_info->weak_bind_off + object->dyld_info->weak_bind_size; else if (object->dyld_info->bind_size != 0) dyld_info_end = object->dyld_info->bind_off + object->dyld_info->bind_size; else if (object->dyld_info->rebase_size != 0) dyld_info_end = object->dyld_info->rebase_off + object->dyld_info->rebase_size; object->output_dyld_info = object->object_addr + dyld_info_start; object->output_dyld_info_size = dyld_info_end - dyld_info_start; object->output_sym_info_size += object->output_dyld_info_size; } if(object->dyst != NULL) { object->output_ilocalsym = object->dyst->ilocalsym; object->output_nlocalsym = object->dyst->nlocalsym; object->output_iextdefsym = object->dyst->iextdefsym; object->output_nextdefsym = object->dyst->nextdefsym; object->output_iundefsym = object->dyst->iundefsym; object->output_nundefsym = object->dyst->nundefsym; object->output_indirect_symtab = (uint32_t *) (object->object_addr + object->dyst->indirectsymoff); object->output_loc_relocs = (struct relocation_info *) (object->object_addr + object->dyst->locreloff); if(object->split_info_cmd != NULL) { object->output_split_info_data = (object->object_addr + object->split_info_cmd->dataoff); object->output_split_info_data_size = object->split_info_cmd->datasize; } if(object->func_starts_info_cmd != NULL) { object->output_func_start_info_data = (object->object_addr + object->func_starts_info_cmd->dataoff); object->output_func_start_info_data_size = object->func_starts_info_cmd->datasize; } if(object->data_in_code_cmd != NULL) { object->output_data_in_code_info_data = (object->object_addr + object->data_in_code_cmd->dataoff); object->output_data_in_code_info_data_size = object->data_in_code_cmd->datasize; } if(object->code_sign_drs_cmd != NULL) { object->output_code_sign_drs_info_data = (object->object_addr + object->code_sign_drs_cmd->dataoff); object->output_code_sign_drs_info_data_size = object->code_sign_drs_cmd->datasize; } if(object->link_opt_hint_cmd != NULL) { object->output_link_opt_hint_info_data = (object->object_addr + object->link_opt_hint_cmd->dataoff); object->output_link_opt_hint_info_data_size = object->link_opt_hint_cmd->datasize; } object->output_ext_relocs = (struct relocation_info *) (object->object_addr + object->dyst->extreloff); object->output_tocs = (struct dylib_table_of_contents *) (object->object_addr + object->dyst->tocoff); object->output_ntoc = object->dyst->ntoc; if(object->mh != NULL) { object->output_mods = (struct dylib_module *) (object->object_addr + object->dyst->modtaboff); object->output_mods64 = NULL; } else { object->output_mods64 = (struct dylib_module_64 *) (object->object_addr + object->dyst->modtaboff); object->output_mods = NULL; } object->output_nmodtab = object->dyst->nmodtab; object->output_refs = (struct dylib_reference *) (object->object_addr + object->dyst->extrefsymoff); object->output_nextrefsyms = object->dyst->nextrefsyms; if(object->hints_cmd != NULL) { object->output_hints = (struct twolevel_hint *) (object->object_addr + object->hints_cmd->offset); } if(object->dyld_info != NULL) { object->input_sym_info_size += object->dyld_info->rebase_size + object->dyld_info->bind_size + object->dyld_info->weak_bind_size + object->dyld_info->lazy_bind_size + object->dyld_info->export_size; } object->input_sym_info_size += object->dyst->nlocrel * sizeof(struct relocation_info) + object->dyst->nextrel * sizeof(struct relocation_info) + object->dyst->ntoc * sizeof(struct dylib_table_of_contents)+ object->dyst->nextrefsyms * sizeof(struct dylib_reference); if(object->split_info_cmd != NULL) object->input_sym_info_size += object->split_info_cmd->datasize; if(object->func_starts_info_cmd != NULL) object->input_sym_info_size += object->func_starts_info_cmd->datasize; if(object->data_in_code_cmd != NULL) object->input_sym_info_size += object->data_in_code_cmd->datasize; if(object->code_sign_drs_cmd != NULL) object->input_sym_info_size += object->code_sign_drs_cmd->datasize; if(object->link_opt_hint_cmd != NULL) object->input_sym_info_size += object->link_opt_hint_cmd->datasize; if(object->mh != NULL) { object->input_sym_info_size += object->dyst->nmodtab * sizeof(struct dylib_module) + object->dyst->nindirectsyms * sizeof(uint32_t); } else { object->input_sym_info_size += object->dyst->nmodtab * sizeof(struct dylib_module_64) + object->dyst->nindirectsyms * sizeof(uint32_t) + object->input_indirectsym_pad; } if(object->hints_cmd != NULL) { object->input_sym_info_size += object->hints_cmd->nhints * sizeof(struct twolevel_hint); } } object->output_sym_info_size = object->input_sym_info_size; if(object->code_sig_cmd != NULL) { object->input_sym_info_size = rnd(object->input_sym_info_size, 16); object->input_sym_info_size += object->code_sig_cmd->datasize; } /* * Now see if one of the -a flags matches this object. */ if(object->mh != NULL) { cputype = object->mh->cputype; cpusubtype = object->mh->cpusubtype & ~CPU_SUBTYPE_MASK; flags = object->mh->flags; } else { cputype = object->mh64->cputype; cpusubtype = object->mh64->cpusubtype & ~CPU_SUBTYPE_MASK; flags = object->mh64->flags; } for(i = 0; i < narch_signs; i++) { if(arch_signs[i].arch_flag.cputype == cputype && arch_signs[i].arch_flag.cpusubtype == cpusubtype) break; } /* * If we didn't find a matching -a flag then just use the existing * code signature if any. */ if(i >= narch_signs) { if(object->code_sig_cmd != NULL) { object->output_code_sig_data_size = object->code_sig_cmd->datasize; } object->output_sym_info_size = object->input_sym_info_size; return; } /* * We did find a matching -a flag for this object */ arch_signs[i].found = TRUE; /* * We now allow statically linked objects as well as objects that are * input for the dynamic linker or an MH_OBJECT filetypes to have * code signatures. So no checks are done here anymore based on the * flags or filetype in the mach_header. */ /* * If this has a code signature load command reuse it and just change * the size of that data. But do not use the old data. */ if(object->code_sig_cmd != NULL) { if(object->seg_linkedit != NULL) { object->seg_linkedit->filesize += arch_signs[i].datasize - object->code_sig_cmd->datasize; if(object->seg_linkedit->filesize > object->seg_linkedit->vmsize) object->seg_linkedit->vmsize = rnd(object->seg_linkedit->filesize, get_segalign_from_flag(&arch_signs[i].arch_flag)); } else if(object->seg_linkedit64 != NULL) { object->seg_linkedit64->filesize += arch_signs[i].datasize; object->seg_linkedit64->filesize -= object->code_sig_cmd->datasize; if(object->seg_linkedit64->filesize > object->seg_linkedit64->vmsize) object->seg_linkedit64->vmsize = rnd(object->seg_linkedit64->filesize, get_segalign_from_flag(&arch_signs[i].arch_flag)); } object->code_sig_cmd->datasize = arch_signs[i].datasize; object->output_code_sig_data_size = arch_signs[i].datasize; object->output_code_sig_data = NULL; object->output_sym_info_size = rnd(object->output_sym_info_size, 16); object->output_sym_info_size += object->code_sig_cmd->datasize; } /* * The object does not have a code signature load command we add one. * And if that does not fail we then set the new load command's size and * offset of the code signature data to allocate in the object. We also * adjust the linkedit's segment size. */ else { object->code_sig_cmd = add_code_sig_load_command(arch, arch_signs[i].arch_flag.name); object->code_sig_cmd->datasize = arch_signs[i].datasize; if(object->seg_linkedit != NULL) linkedit_end = object->seg_linkedit->fileoff + object->seg_linkedit->filesize; else if(object->seg_linkedit64 != NULL) linkedit_end = object->seg_linkedit64->fileoff + object->seg_linkedit64->filesize; else if(object->mh_filetype == MH_OBJECT) linkedit_end = object->object_size; else fatal("can't allocate code signature data for: %s (for " "architecture %s) because file does not have a " SEG_LINKEDIT " segment", arch->file_name, arch_signs[i].arch_flag.name); object->code_sig_cmd->dataoff = rnd(linkedit_end, 16); object->output_code_sig_data_size = arch_signs[i].datasize; object->output_code_sig_data = NULL; align_delta = object->code_sig_cmd->dataoff - linkedit_end; if(object->output_sym_info_size != 0) object->output_sym_info_size = rnd(object->output_sym_info_size, 16); else object->output_sym_info_size = align_delta; object->output_sym_info_size += object->code_sig_cmd->datasize; if(object->seg_linkedit != NULL) { object->seg_linkedit->filesize = rnd(object->seg_linkedit->filesize, 16) + object->code_sig_cmd->datasize; if(object->seg_linkedit->filesize > object->seg_linkedit->vmsize) object->seg_linkedit->vmsize = rnd(object->seg_linkedit->filesize, get_segalign_from_flag(&arch_signs[i].arch_flag)); } else if(object->seg_linkedit64 != NULL) { object->seg_linkedit64->filesize = rnd(object->seg_linkedit64->filesize, 16) + object->code_sig_cmd->datasize; if(object->seg_linkedit64->filesize > object->seg_linkedit64->vmsize) object->seg_linkedit64->vmsize = rnd(object->seg_linkedit64->filesize, get_segalign_from_flag(&arch_signs[i].arch_flag)); } } }
static void setup_object_symbolic_info( struct object *object) { uint32_t output_indirectsym_pad_diff; if(object->st != NULL && object->st->nsyms != 0){ if(object->mh != NULL){ object->output_symbols = (struct nlist *) (object->object_addr + object->st->symoff); if(object->object_byte_sex != get_host_byte_sex()) swap_nlist(object->output_symbols, object->st->nsyms, get_host_byte_sex()); object->output_symbols64 = NULL; } else{ object->output_symbols64 = (struct nlist_64 *) (object->object_addr + object->st->symoff); if(object->object_byte_sex != get_host_byte_sex()) swap_nlist_64(object->output_symbols64, object->st->nsyms, get_host_byte_sex()); object->output_symbols = NULL; } object->output_nsymbols = object->st->nsyms; object->output_strings = object->object_addr + object->st->stroff; object->output_strings_size = object->st->strsize; if(object->mh != NULL){ object->input_sym_info_size = object->st->nsyms * sizeof(struct nlist) + object->st->strsize; } else{ object->input_sym_info_size = object->st->nsyms * sizeof(struct nlist_64) + object->st->strsize; } } output_indirectsym_pad_diff = 0; if(object->dyst != NULL){ object->output_ilocalsym = object->dyst->ilocalsym; object->output_nlocalsym = object->dyst->nlocalsym; object->output_iextdefsym = object->dyst->iextdefsym; object->output_nextdefsym = object->dyst->nextdefsym; object->output_iundefsym = object->dyst->iundefsym; object->output_nundefsym = object->dyst->nundefsym; object->output_indirect_symtab = (uint32_t *) (object->object_addr + object->dyst->indirectsymoff); object->output_loc_relocs = (struct relocation_info *) (object->object_addr + object->dyst->locreloff); if(object->split_info_cmd != NULL){ object->output_split_info_data = (object->object_addr + object->split_info_cmd->dataoff); object->output_split_info_data_size = object->split_info_cmd->datasize; } if(object->func_starts_info_cmd != NULL){ object->output_func_start_info_data = (object->object_addr + object->func_starts_info_cmd->dataoff); object->output_func_start_info_data_size = object->func_starts_info_cmd->datasize; } if(object->data_in_code_cmd != NULL){ object->output_data_in_code_info_data = (object->object_addr + object->data_in_code_cmd->dataoff); object->output_data_in_code_info_data_size = object->data_in_code_cmd->datasize; } if(object->code_sign_drs_cmd != NULL){ object->output_code_sign_drs_info_data = (object->object_addr + object->code_sign_drs_cmd->dataoff); object->output_code_sign_drs_info_data_size = object->code_sign_drs_cmd->datasize; } if(object->link_opt_hint_cmd != NULL){ object->output_link_opt_hint_info_data = (object->object_addr + object->link_opt_hint_cmd->dataoff); object->output_link_opt_hint_info_data_size = object->link_opt_hint_cmd->datasize; } object->output_ext_relocs = (struct relocation_info *) (object->object_addr + object->dyst->extreloff); object->output_tocs = (struct dylib_table_of_contents *) (object->object_addr + object->dyst->tocoff); object->output_ntoc = object->dyst->ntoc; if(object->mh != NULL){ object->output_mods = (struct dylib_module *) (object->object_addr + object->dyst->modtaboff); object->output_mods64 = NULL; } else{ object->output_mods64 = (struct dylib_module_64 *) (object->object_addr + object->dyst->modtaboff); object->output_mods = NULL; } object->output_nmodtab = object->dyst->nmodtab; object->output_refs = (struct dylib_reference *) (object->object_addr + object->dyst->extrefsymoff); object->output_nextrefsyms = object->dyst->nextrefsyms; if(object->hints_cmd != NULL){ object->output_hints = (struct twolevel_hint *) (object->object_addr + object->hints_cmd->offset); } if(object->code_sig_cmd != NULL){ object->output_code_sig_data = object->object_addr + object->code_sig_cmd->dataoff; object->output_code_sig_data_size = object->code_sig_cmd->datasize; } object->input_sym_info_size += object->dyst->nlocrel * sizeof(struct relocation_info) + object->dyst->nextrel * sizeof(struct relocation_info) + object->dyst->ntoc * sizeof(struct dylib_table_of_contents)+ object->dyst->nextrefsyms * sizeof(struct dylib_reference); if(object->split_info_cmd != NULL) object->input_sym_info_size += object->split_info_cmd->datasize; if(object->func_starts_info_cmd != NULL) object->input_sym_info_size += object->func_starts_info_cmd->datasize; if(object->data_in_code_cmd != NULL) object->input_sym_info_size += object->data_in_code_cmd->datasize; if(object->code_sign_drs_cmd != NULL) object->input_sym_info_size += object->code_sign_drs_cmd->datasize; if(object->link_opt_hint_cmd != NULL) object->input_sym_info_size += object->link_opt_hint_cmd->datasize; if(object->mh != NULL){ object->input_sym_info_size += object->dyst->nmodtab * sizeof(struct dylib_module) + object->dyst->nindirectsyms * sizeof(uint32_t); } else{ object->input_sym_info_size += object->dyst->nmodtab * sizeof(struct dylib_module_64)+ object->dyst->nindirectsyms * sizeof(uint32_t) + object->input_indirectsym_pad; if(object->input_indirectsym_pad == 0 && (object->dyst->nindirectsyms % 2) != 0) output_indirectsym_pad_diff = 4; } if(object->hints_cmd != NULL){ object->input_sym_info_size += object->hints_cmd->nhints * sizeof(struct twolevel_hint); } if(object->code_sig_cmd != NULL){ object->input_sym_info_size = rnd(object->input_sym_info_size, 16); object->input_sym_info_size += object->code_sig_cmd->datasize; } if(output_indirectsym_pad_diff != 0){ if(object->output_ntoc != 0) object->dyst->tocoff += output_indirectsym_pad_diff; if(object->output_nmodtab != 0) object->dyst->modtaboff += output_indirectsym_pad_diff; if(object->output_nextrefsyms != 0) object->dyst->extrefsymoff += output_indirectsym_pad_diff; if(object->output_strings_size != 0) object->st->stroff += output_indirectsym_pad_diff; object->seg_linkedit64->filesize += output_indirectsym_pad_diff; if(object->seg_linkedit64->filesize > object->seg_linkedit64->vmsize) object->seg_linkedit64->vmsize += output_indirectsym_pad_diff; } } object->output_sym_info_size = object->input_sym_info_size + output_indirectsym_pad_diff; }
/* * ctf_insert() does the work to add the ctf section in the specified broken * out ofile for the architecure specifed with a -arch command line option. */ static void ctf_insert( struct arch *arch, struct member *member, struct object *object) { uint32_t i, move_size; cpu_type_t cputype; cpu_subtype_t cpusubtype; uint32_t flags, offset; uint64_t addr; if(object->mh != NULL){ cputype = object->mh->cputype; cpusubtype = object->mh->cpusubtype & ~CPU_SUBTYPE_MASK; flags = object->mh->flags; offset = object->seg_linkedit->fileoff; addr = object->seg_linkedit->vmaddr; } else{ cputype = object->mh64->cputype; cpusubtype = object->mh64->cpusubtype & ~CPU_SUBTYPE_MASK; flags = object->mh64->flags; offset = object->seg_linkedit64->fileoff; addr = object->seg_linkedit64->vmaddr; } /* * Make sure this object is valid to process. Since the input should * be a mach_kernel that is statically linked we should not see any * dynamic symbol table info. Or a code signature at the point this * program is called in the build process. */ if((flags & MH_DYLDLINK) == MH_DYLDLINK || object->dyld_info != NULL || object->split_info_cmd != NULL || object->hints_cmd != NULL) fatal_arch(arch, member, "file is input for the dynamic linker so " "not a valid input for this program to process: "); /* * Allow a dynamic symbol table load command where it only has an * indirect symbol table and no other tables. */ if(object->dyst != NULL && (object->dyst->ntoc != 0 || object->dyst->nmodtab != 0 || object->dyst->nmodtab != 0 || object->dyst->nextrefsyms != 0 || object->dyst->nextrel != 0)) fatal_arch(arch, member, "file is input for the dynamic linker so " "not a valid input for this program to process: "); if(object->mh_filetype != MH_EXECUTE) fatal_arch(arch, member, "file type is not MH_EXECUTE so " "not a valid input for this program to process: "); if(object->seg_linkedit == NULL && object->seg_linkedit64 == NULL) fatal_arch(arch, member, "file type does not have a __LINKEDIT " "segment so not a valid input for this program to " "process: "); if(object->code_sig_cmd != NULL) fatal_arch(arch, member, "file type has code signature " "so not a valid input for this program to process: "); /* * Now see if one of the -arch flags matches this object. */ for(i = 0; i < narch_ctfs; i++){ if(arch_ctfs[i].arch_flag.cputype == cputype && arch_ctfs[i].arch_flag.cpusubtype == cpusubtype) break; } /* * If we didn't find a matching -arch flag it is an error. */ if(i >= narch_ctfs){ fatal_arch(arch, member, "no matching -arch option for this slice " "of file: "); return; } arch_ctfs[i].arch_found = TRUE; /* * Add the section for the ctf data for this arch. It is placed in * the file where the linkedit info was and that info will then be * moved. */ add_ctf_section(arch, arch_ctfs[i].arch_flag.name, offset, addr, arch_ctfs[i].size); /* * Now set up all the pointers and sizes of the symbol and string table. */ if(object->st != NULL && object->st->nsyms != 0){ if(object->mh != NULL){ object->output_symbols = (struct nlist *) (object->object_addr + object->st->symoff); if(object->object_byte_sex != get_host_byte_sex()) swap_nlist(object->output_symbols, object->st->nsyms, get_host_byte_sex()); object->output_symbols64 = NULL; } else{ object->output_symbols64 = (struct nlist_64 *) (object->object_addr + object->st->symoff); if(object->object_byte_sex != get_host_byte_sex()) swap_nlist_64(object->output_symbols64, object->st->nsyms, get_host_byte_sex()); object->output_symbols = NULL; } object->output_nsymbols = object->st->nsyms; object->output_strings = object->object_addr + object->st->stroff; object->output_strings_size = object->st->strsize; if(object->mh != NULL){ object->input_sym_info_size = object->st->nsyms * sizeof(struct nlist) + object->st->strsize; } else{ object->input_sym_info_size = object->st->nsyms * sizeof(struct nlist_64) + object->st->strsize; } } if(object->dyst != NULL){ object->output_ilocalsym = object->dyst->ilocalsym; object->output_nlocalsym = object->dyst->nlocalsym; object->output_iextdefsym = object->dyst->iextdefsym; object->output_nextdefsym = object->dyst->nextdefsym; object->output_iundefsym = object->dyst->iundefsym; object->output_nundefsym = object->dyst->nundefsym; object->output_indirect_symtab = (uint32_t *) (object->object_addr + object->dyst->indirectsymoff); object->output_loc_relocs = (struct relocation_info *) (object->object_addr + object->dyst->locreloff); if(object->mh != NULL){ object->input_sym_info_size += object->dyst->nindirectsyms * sizeof(uint32_t); } else{ object->input_sym_info_size += object->dyst->nindirectsyms * sizeof(uint32_t) + object->input_indirectsym_pad; } object->input_sym_info_size += object->dyst->nlocrel * sizeof(struct relocation_info); } if(object->func_starts_info_cmd != NULL){ object->output_func_start_info_data = object->object_addr + object->func_starts_info_cmd->dataoff; object->output_func_start_info_data_size = object->func_starts_info_cmd->datasize; object->input_sym_info_size += object->func_starts_info_cmd->datasize; } if(object->data_in_code_cmd != NULL){ object->output_data_in_code_info_data = object->object_addr + object->data_in_code_cmd->dataoff; object->output_data_in_code_info_data_size = object->data_in_code_cmd->datasize; object->input_sym_info_size += object->data_in_code_cmd->datasize; } if(object->code_sign_drs_cmd != NULL){ object->output_code_sign_drs_info_data = object->object_addr + object->code_sign_drs_cmd->dataoff; object->output_code_sign_drs_info_data_size = object->code_sign_drs_cmd->datasize; object->input_sym_info_size += object->code_sign_drs_cmd->datasize; } if(object->link_opt_hint_cmd != NULL){ object->output_link_opt_hint_info_data = object->object_addr + object->link_opt_hint_cmd->dataoff; object->output_link_opt_hint_info_data_size = object->link_opt_hint_cmd->datasize; object->input_sym_info_size += object->link_opt_hint_cmd->datasize; } object->output_sym_info_size = object->input_sym_info_size; /* * Now move the link edit info by the size of the ctf for this arch * rounded to the load command size for this arch. */ if(object->mh != NULL){ move_size = rnd(arch_ctfs[i].size, sizeof(uint32_t)); object->seg_linkedit->fileoff += move_size; } else{ move_size = rnd(arch_ctfs[i].size, sizeof(uint64_t)); object->seg_linkedit64->fileoff += move_size; } if(object->st != NULL && object->st->nsyms != 0){ object->st->symoff += move_size; object->st->stroff += move_size; } if(object->dyst != NULL){ if(object->dyst->nindirectsyms != 0) object->dyst->indirectsymoff += move_size; if(object->dyst->nlocrel != 0) object->dyst->locreloff += move_size; } if(object->func_starts_info_cmd != NULL) object->func_starts_info_cmd->dataoff += move_size; if(object->data_in_code_cmd != NULL) object->data_in_code_cmd->dataoff += move_size; if(object->code_sign_drs_cmd != NULL) object->code_sign_drs_cmd->dataoff += move_size; if(object->link_opt_hint_cmd != NULL) object->link_opt_hint_cmd->dataoff += move_size; /* * Record the new content for writeout() to put in to the output file. */ object->output_new_content = arch_ctfs[i].contents; object->output_new_content_size = move_size; }
/* * write_object() writes a Mach-O object file from the built up data structures. */ void write_object( char *out_file_name) { /* The structures for Mach-O relocatables */ mach_header_t header; segment_command_t reloc_segment; struct symtab_command symbol_table; struct dysymtab_command dynamic_symbol_table; uint32_t section_type; uint32_t *indirect_symbols; isymbolS *isymbolP; uint32_t i, j, nsects, nsyms, strsize, nindirectsyms; /* locals to fill in section struct fields */ uint32_t offset, zero; /* The GAS data structures */ struct frchain *frchainP, *p; struct symbol *symbolP; struct frag *fragP; struct fix *fixP; uint32_t output_size; char *output_addr; kern_return_t r; enum byte_sex host_byte_sex; uint32_t reloff, nrelocs; int32_t count; char *fill_literal; int32_t fill_size; int32_t num_bytes; char *symbol_name; int fd; uint32_t local; struct stat stat_buf; #ifdef I860 I860_tweeks(); #endif i = 0; /* to shut up a compiler "may be used uninitialized" warning */ /* * The first group of things to do is to set all the fields in the * header structures which includes offsets and determining the final * sizes of things. */ /* * Fill in the addr and size fields of each section structure and count * the number of sections. */ nsects = 0; for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){ frchainP->frch_section.addr = frchainP->frch_root->fr_address; frchainP->frch_section.size = frchainP->frch_last->fr_address - frchainP->frch_root->fr_address; nsects++; } /* * Setup the indirect symbol tables by looking up or creating symbol * from the indirect symbol names and recording the symbol pointers. */ nindirectsyms = layout_indirect_symbols(); /* * Setup the symbol table to include only those symbols that will be in * the object file, assign the string table offsets into the symbols * and size the string table. */ nsyms = 0; strsize = 0; layout_symbols((int32_t *)&nsyms, (int32_t *)&strsize); /* fill in the Mach-O header */ header.magic = MH_MAGIC_VALUE; header.cputype = md_cputype; if(archflag_cpusubtype != -1) header.cpusubtype = archflag_cpusubtype; else header.cpusubtype = md_cpusubtype; header.filetype = MH_OBJECT; header.ncmds = 0; header.sizeofcmds = 0; if(nsects != 0){ header.ncmds += 1; header.sizeofcmds += sizeof(segment_command_t) + nsects * sizeof(section_t); } if(nsyms != 0){ header.ncmds += 1; header.sizeofcmds += sizeof(struct symtab_command); if(flagseen['k']){ header.ncmds += 1; header.sizeofcmds += sizeof(struct dysymtab_command); } } else strsize = 0; header.flags = 0; if(subsections_via_symbols == TRUE) header.flags |= MH_SUBSECTIONS_VIA_SYMBOLS; #ifdef ARCH64 header.reserved = 0; #endif /* fill in the segment command */ memset(&reloc_segment, '\0', sizeof(segment_command_t)); reloc_segment.cmd = LC_SEGMENT_VALUE; reloc_segment.cmdsize = sizeof(segment_command_t) + nsects * sizeof(section_t); /* leave reloc_segment.segname full of zeros */ reloc_segment.vmaddr = 0; reloc_segment.vmsize = 0; reloc_segment.filesize = 0; offset = header.sizeofcmds + sizeof(mach_header_t); reloc_segment.fileoff = offset; reloc_segment.maxprot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE; reloc_segment.initprot= VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE; reloc_segment.nsects = nsects; reloc_segment.flags = 0; /* * Set the offsets to the contents of the sections (for non-zerofill * sections) and set the filesize and vmsize of the segment. This is * complicated by the fact that all the zerofill sections have addresses * after the non-zerofill sections and that the alignment of sections * produces gaps that are not in any section. For the vmsize we rely on * the fact the the sections start at address 0 so it is just the last * zerofill section or the last not-zerofill section. */ for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){ if((frchainP->frch_section.flags & SECTION_TYPE) == S_ZEROFILL) continue; for(p = frchainP->frch_next; p != NULL; p = p->frch_next) if((p->frch_section.flags & SECTION_TYPE) != S_ZEROFILL) break; if(p != NULL) i = p->frch_section.addr - frchainP->frch_section.addr; else i = frchainP->frch_section.size; reloc_segment.filesize += i; frchainP->frch_section.offset = offset; offset += i; reloc_segment.vmsize = frchainP->frch_section.addr + frchainP->frch_section.size; } for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){ if((frchainP->frch_section.flags & SECTION_TYPE) != S_ZEROFILL) continue; reloc_segment.vmsize = frchainP->frch_section.addr + frchainP->frch_section.size; } offset = round(offset, sizeof(int32_t)); /* * Count the number of relocation entries for each section. */ for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){ frchainP->frch_section.nreloc = 0; for(fixP = frchainP->frch_fix_root; fixP; fixP = fixP->fx_next){ frchainP->frch_section.nreloc += nrelocs_for_fix(fixP); } } /* * Fill in the offset to the relocation entries of the sections. */ offset = round(offset, sizeof(int32_t)); reloff = offset; nrelocs = 0; for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){ if(frchainP->frch_section.nreloc == 0) frchainP->frch_section.reloff = 0; else frchainP->frch_section.reloff = offset; offset += frchainP->frch_section.nreloc * sizeof(struct relocation_info); nrelocs += frchainP->frch_section.nreloc; } if(flagseen['k']){ /* fill in the fields of the dysymtab_command */ dynamic_symbol_table.cmd = LC_DYSYMTAB; dynamic_symbol_table.cmdsize = sizeof(struct dysymtab_command); dynamic_symbol_table.ilocalsym = ilocalsym; dynamic_symbol_table.nlocalsym = nlocalsym; dynamic_symbol_table.iextdefsym = iextdefsym; dynamic_symbol_table.nextdefsym = nextdefsym; dynamic_symbol_table.iundefsym = iundefsym; dynamic_symbol_table.nundefsym = nundefsym; if(nindirectsyms == 0){ dynamic_symbol_table.nindirectsyms = 0; dynamic_symbol_table.indirectsymoff = 0; } else{ dynamic_symbol_table.nindirectsyms = nindirectsyms; dynamic_symbol_table.indirectsymoff = offset; offset += nindirectsyms * sizeof(uint32_t); } dynamic_symbol_table.tocoff = 0; dynamic_symbol_table.ntoc = 0; dynamic_symbol_table.modtaboff = 0; dynamic_symbol_table.nmodtab = 0; dynamic_symbol_table.extrefsymoff = 0; dynamic_symbol_table.nextrefsyms = 0; dynamic_symbol_table.extreloff = 0; dynamic_symbol_table.nextrel = 0; dynamic_symbol_table.locreloff = 0; dynamic_symbol_table.nlocrel = 0; } /* fill in the fields of the symtab_command (except the string table) */ symbol_table.cmd = LC_SYMTAB; symbol_table.cmdsize = sizeof(struct symtab_command); if(nsyms == 0) symbol_table.symoff = 0; else symbol_table.symoff = offset; symbol_table.nsyms = nsyms; offset += symbol_table.nsyms * sizeof(nlist_t); /* fill in the string table fields of the symtab_command */ if(strsize == 0) symbol_table.stroff = 0; else symbol_table.stroff = offset; symbol_table.strsize = round(strsize, sizeof(uint32_t)); offset += round(strsize, sizeof(uint32_t)); /* * The second group of things to do is now with the size of everything * known the object file and the offsets set in the various structures * the contents of the object file can be created. */ /* * Create the buffer to copy the parts of the output file into. */ output_size = offset; if((r = vm_allocate(mach_task_self(), (vm_address_t *)&output_addr, output_size, TRUE)) != KERN_SUCCESS) as_fatal("can't vm_allocate() buffer for output file of size %u", output_size); /* put the headers in the output file's buffer */ host_byte_sex = get_host_byte_sex(); offset = 0; /* put the mach_header in the buffer */ memcpy(output_addr + offset, &header, sizeof(mach_header_t)); if(host_byte_sex != md_target_byte_sex) swap_mach_header_t((mach_header_t *)(output_addr + offset), md_target_byte_sex); offset += sizeof(mach_header_t); /* put the segment_command in the buffer */ if(nsects != 0){ memcpy(output_addr + offset, &reloc_segment, sizeof(segment_command_t)); if(host_byte_sex != md_target_byte_sex) swap_segment_command_t((segment_command_t *) (output_addr + offset), md_target_byte_sex); offset += sizeof(segment_command_t); } /* put the segment_command's section structures in the buffer */ for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){ memcpy(output_addr + offset, &(frchainP->frch_section), sizeof(section_t)); if(host_byte_sex != md_target_byte_sex) swap_section_t((section_t *)(output_addr + offset), 1, md_target_byte_sex); offset += sizeof(section_t); } /* put the symbol_command in the buffer */ if(nsyms != 0){ memcpy(output_addr + offset, &symbol_table, sizeof(struct symtab_command)); if(host_byte_sex != md_target_byte_sex) swap_symtab_command((struct symtab_command *) (output_addr + offset), md_target_byte_sex); offset += sizeof(struct symtab_command); } if(flagseen['k']){ /* put the dysymbol_command in the buffer */ if(nsyms != 0){ memcpy(output_addr + offset, &dynamic_symbol_table, sizeof(struct dysymtab_command)); if(host_byte_sex != md_target_byte_sex) swap_dysymtab_command((struct dysymtab_command *) (output_addr + offset), md_target_byte_sex); offset += sizeof(struct dysymtab_command); } } /* put the section contents (frags) in the buffer */ for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){ offset = frchainP->frch_section.offset; for(fragP = frchainP->frch_root; fragP; fragP = fragP->fr_next){ know(fragP->fr_type == rs_fill); /* put the fixed part of the frag in the buffer */ memcpy(output_addr + offset, fragP->fr_literal, fragP->fr_fix); offset += fragP->fr_fix; /* put the variable repeated part of the frag in the buffer */ fill_literal = fragP->fr_literal + fragP->fr_fix; fill_size = fragP->fr_var; num_bytes = fragP->fr_offset * fragP->fr_var; for(count = 0; count < num_bytes; count += fill_size){ memcpy(output_addr + offset, fill_literal, fill_size); offset += fill_size; } } } /* put the symbols in the output file's buffer */ offset = symbol_table.symoff; for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){ if((symbolP->sy_type & N_EXT) == 0){ symbol_name = symbolP->sy_name; symbolP->sy_nlist.n_un.n_strx = symbolP->sy_name_offset; if(symbolP->expression != 0) { expressionS *exp; exp = (expressionS *)symbolP->expression; if((exp->X_add_symbol->sy_type & N_TYPE) == N_UNDF) as_fatal("undefined symbol `%s' in operation setting " "`%s'", exp->X_add_symbol->sy_name, symbol_name); if((exp->X_subtract_symbol->sy_type & N_TYPE) == N_UNDF) as_fatal("undefined symbol `%s' in operation setting " "`%s'", exp->X_subtract_symbol->sy_name, symbol_name); if(exp->X_add_symbol->sy_other != exp->X_subtract_symbol->sy_other) as_fatal("invalid sections for operation on `%s' and " "`%s' setting `%s'",exp->X_add_symbol->sy_name, exp->X_subtract_symbol->sy_name, symbol_name); symbolP->sy_nlist.n_value += exp->X_add_symbol->sy_value - exp->X_subtract_symbol->sy_value; } memcpy(output_addr + offset, (char *)(&symbolP->sy_nlist), sizeof(nlist_t)); symbolP->sy_name = symbol_name; offset += sizeof(nlist_t); } } for(i = 0; i < nextdefsym; i++){ symbol_name = extdefsyms[i]->sy_name; extdefsyms[i]->sy_nlist.n_un.n_strx = extdefsyms[i]->sy_name_offset; memcpy(output_addr + offset, (char *)(&extdefsyms[i]->sy_nlist), sizeof(nlist_t)); extdefsyms[i]->sy_name = symbol_name; offset += sizeof(nlist_t); } for(j = 0; j < nundefsym; j++){ symbol_name = undefsyms[j]->sy_name; undefsyms[j]->sy_nlist.n_un.n_strx = undefsyms[j]->sy_name_offset; memcpy(output_addr + offset, (char *)(&undefsyms[j]->sy_nlist), sizeof(nlist_t)); undefsyms[j]->sy_name = symbol_name; offset += sizeof(nlist_t); } if(host_byte_sex != md_target_byte_sex) swap_nlist_t((nlist_t *)(output_addr + symbol_table.symoff), symbol_table.nsyms, md_target_byte_sex); /* * Put the relocation entries for each section in the buffer. */ for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){ offset = frchainP->frch_section.reloff; for(fixP = frchainP->frch_fix_root; fixP; fixP = fixP->fx_next){ offset += fix_to_relocation_entries( fixP, frchainP->frch_section.addr, (struct relocation_info *)(output_addr + offset), frchainP->frch_section.flags & S_ATTR_DEBUG); } } if(host_byte_sex != md_target_byte_sex) swap_relocation_info((struct relocation_info *) (output_addr + reloff), nrelocs, md_target_byte_sex); if(flagseen['k']){ /* put the indirect symbol table in the buffer */ offset = dynamic_symbol_table.indirectsymoff; for(frchainP = frchain_root; frchainP != NULL; frchainP = frchainP->frch_next){ section_type = frchainP->frch_section.flags & SECTION_TYPE; if(section_type == S_NON_LAZY_SYMBOL_POINTERS || section_type == S_LAZY_SYMBOL_POINTERS || section_type == S_SYMBOL_STUBS){ /* * For each indirect symbol put out the symbol number. */ for(isymbolP = frchainP->frch_isym_root; isymbolP != NULL; isymbolP = isymbolP->isy_next){ /* * If this is a non-lazy pointer symbol section and * if the symbol is a local symbol then put out * INDIRECT_SYMBOL_LOCAL as the indirect symbol table * entry. This is used with code gen for fix-n-continue * where the compiler generates indirection for static * data references. See the comments at the end of * fixup_section() that explains the assembly code used. */ if(section_type == S_NON_LAZY_SYMBOL_POINTERS && (isymbolP->isy_symbol->sy_nlist.n_type & N_EXT) != N_EXT){ local = INDIRECT_SYMBOL_LOCAL; if((isymbolP->isy_symbol->sy_nlist.n_type & N_TYPE) == N_ABS) local |= INDIRECT_SYMBOL_ABS; memcpy(output_addr + offset, (char *)(&local), sizeof(uint32_t)); } else{ memcpy(output_addr + offset, (char *)(&isymbolP->isy_symbol->sy_number), sizeof(uint32_t)); } offset += sizeof(uint32_t); } } } if(host_byte_sex != md_target_byte_sex){ indirect_symbols = (uint32_t *)(output_addr + dynamic_symbol_table.indirectsymoff); swap_indirect_symbols(indirect_symbols, nindirectsyms, md_target_byte_sex); } } /* put the strings in the output file's buffer */ offset = symbol_table.stroff; if(symbol_table.strsize != 0){ zero = 0; memcpy(output_addr + offset, (char *)&zero, sizeof(char)); offset += sizeof(char); } for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){ /* Ordinary case: not .stabd. */ if(symbolP->sy_name != NULL){ if((symbolP->sy_type & N_EXT) != 0){ memcpy(output_addr + offset, symbolP->sy_name, strlen(symbolP->sy_name) + 1); offset += strlen(symbolP->sy_name) + 1; } } } for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){ /* Ordinary case: not .stabd. */ if(symbolP->sy_name != NULL){ if((symbolP->sy_type & N_EXT) == 0){ memcpy(output_addr + offset, symbolP->sy_name, strlen(symbolP->sy_name) + 1); offset += strlen(symbolP->sy_name) + 1; } } } /* * Create the output file. The unlink() is done to handle the problem * when the out_file_name is not writable but the directory allows the * file to be removed (since the file may not be there the return code * of the unlink() is ignored). */ if(bad_error != 0) return; /* * Avoid doing the unlink() on special files, just unlink regular files * that exist. */ if(stat(out_file_name, &stat_buf) != -1){ if(stat_buf.st_mode & S_IFREG) (void)unlink(out_file_name); } if((fd = open(out_file_name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) as_fatal("can't create output file: %s", out_file_name); if(write(fd, output_addr, output_size) != (int)output_size) as_fatal("can't write output file"); if(close(fd) == -1) as_fatal("can't close output file"); }
/* * checksyms() is the routine that gets called by ofile_process() to process * single object files. */ static void checksyms( struct ofile *ofile, char *arch_name, void *cookie) { struct cmd_flags *cmd_flags; unsigned long i; struct load_command *lc; struct symtab_command *st; struct nlist *symbols; unsigned long nsymbols; char *strings; unsigned long strsize; unsigned long nfiledefs, ncats, nlocal, nstabs, nfun; unsigned long filedef_strings, cat_strings, local_strings, stab_strings; enum bool debug; if(ofile->mh == NULL) return; debug = FALSE; cmd_flags = (struct cmd_flags *)cookie; if(cmd_flags->check_dynamic_binary == TRUE) if((ofile->mh->flags & MH_DYLDLINK) == MH_DYLDLINK) check_dynamic_binary(ofile, arch_name, cmd_flags->detail, cmd_flags->verification); if(ofile->mh->filetype == MH_DYLIB || ofile->mh->filetype == MH_DYLIB_STUB) check_dylib(ofile, arch_name, cmd_flags->detail, cmd_flags->verification, &debug); st = NULL; lc = ofile->load_commands; for(i = 0; i < ofile->mh->ncmds; i++){ if(st == NULL && lc->cmd == LC_SYMTAB){ st = (struct symtab_command *)lc; } lc = (struct load_command *)((char *)lc + lc->cmdsize); } if(st == NULL || st->nsyms == 0){ return; } if(cmd_flags->rldtype == FALSE && cmd_flags->trey == FALSE && (ofile->mh->flags & MH_DYLDLINK) == 0 && (ofile->file_type != OFILE_FAT || ofile->arch_type != OFILE_ARCHIVE) && ofile->file_type != OFILE_ARCHIVE && ofile->mh->filetype != MH_FVMLIB){ if(st->nsyms == 0) return; if(cmd_flags->detail == TRUE){ if(arch_name != NULL) printf("(for architecture %s):", arch_name); if(ofile->member_ar_hdr != NULL){ printf("%s:%.*s:", ofile->file_name, (int)ofile->member_name_size, ofile->member_name); } else printf("%s:", ofile->file_name); printf(" has %u symbols and %u string bytes\n", st->nsyms, st->strsize); } if(cmd_flags->verification == TRUE) printf("unstripped_binary\n"); exit_status = EXIT_FAILURE; return; } symbols = (struct nlist *)(ofile->object_addr + st->symoff); nsymbols = st->nsyms; if(ofile->object_byte_sex != get_host_byte_sex()) swap_nlist(symbols, nsymbols, get_host_byte_sex()); strings = ofile->object_addr + st->stroff; strsize = st->strsize; for(i = 0; i < nsymbols; i++){ if(symbols[i].n_un.n_strx == 0) symbols[i].n_un.n_name = ""; else if(symbols[i].n_un.n_strx < 0 || (unsigned long)symbols[i].n_un.n_strx > st->strsize) symbols[i].n_un.n_name = "bad string index"; else symbols[i].n_un.n_name = symbols[i].n_un.n_strx + strings; if((symbols[i].n_type & N_TYPE) == N_INDR){ if(symbols[i].n_value == 0) symbols[i].n_value = (long)""; else if(symbols[i].n_value > st->strsize) symbols[i].n_value = (long)"bad string index"; else symbols[i].n_value = (long)(symbols[i].n_value + strings); } } nfiledefs = 0; ncats = 0; nlocal = 0; nstabs = 0; nfun = 0; filedef_strings = 0; cat_strings = 0; local_strings = 0; stab_strings = 0; for(i = 0; i < nsymbols; i++){ if(ofile->mh->filetype == MH_EXECUTE){ if(symbols[i].n_type == (N_ABS | N_EXT) && symbols[i].n_value == 0){ if(strncmp(symbols[i].n_un.n_name, ".file_definition_", sizeof(".file_definition_") - 1) == 0){ nfiledefs++; filedef_strings += strlen(symbols[i].n_un.n_name); } if(strncmp(symbols[i].n_un.n_name, ".objc_category_name_", sizeof(".objc_category_name_") - 1) == 0){ ncats++; cat_strings += strlen(symbols[i].n_un.n_name); } } } if((symbols[i].n_type & N_EXT) == 0){ nlocal++; local_strings += strlen(symbols[i].n_un.n_name); } if(symbols[i].n_type & N_STAB){ nstabs++; stab_strings += strlen(symbols[i].n_un.n_name); if(symbols[i].n_type == N_FUN) nfun++; } } if(nfiledefs == 0 && ncats == 0 && nlocal == 0 && nstabs == 0) return; if(cmd_flags->rldtype == TRUE && nstabs == 0) return; if((ofile->mh->flags & MH_DYLDLINK) == MH_DYLDLINK && (nstabs == 0 && nlocal == 0)) return; if(nstabs == 0 && ((ofile->file_type == OFILE_FAT && ofile->arch_type == OFILE_ARCHIVE) || ofile->file_type == OFILE_ARCHIVE || ofile->mh->filetype == MH_FVMLIB)) return; if((ofile->mh->filetype == MH_DYLIB || ofile->mh->filetype == MH_DYLIB_STUB || ofile->mh->filetype == MH_FVMLIB) && (nfun == 0 || debug == TRUE)) return; if(cmd_flags->detail == TRUE){ if(arch_name != NULL) printf("(for architecture %s):", arch_name); if(ofile->member_ar_hdr != NULL){ printf("%s:%.*s:", ofile->file_name, (int)ofile->member_name_size, ofile->member_name); } else printf("%s:", ofile->file_name); printf("\n"); if(nfiledefs != 0) printf(" has %lu .file_definition_ symbols and %lu string " "bytes\n", nfiledefs, filedef_strings); if(ncats != 0) printf(" has %lu .objc_category_name_ symbols and %lu string " "bytes\n", ncats, cat_strings); if(nlocal != 0) printf(" has %lu local symbols and %lu string " "bytes\n", nlocal, local_strings); if(nstabs != 0) printf(" has %lu debugging symbols and %lu string " "bytes\n", nstabs, stab_strings); } if(cmd_flags->verification == TRUE) printf("unstripped_binary\n"); if(cmd_flags->trey == TRUE && nstabs == 0) return; exit_status = EXIT_FAILURE; return; }