/* * Read in symbol table */ static void getsymtab(FILE *nfile, const char *filename) { register long i; int askfor; struct nlist nbuf; /* pass1 - count symbols */ fseek(nfile, (long)N_SYMOFF(xbuf), 0); nname = 0; for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { fread(&nbuf, sizeof(nbuf), 1, nfile); if ( ! funcsymbol( &nbuf ) ) { continue; } nname++; } if (nname == 0) errx( 1 , "%s: no symbols" , filename ); askfor = nname + 1; nl = (nltype *) calloc( askfor , sizeof(nltype) ); if (nl == 0) errx( 1 , "no room for %d bytes of symbol table" , askfor * sizeof(nltype) ); /* pass2 - read symbols */ fseek(nfile, (long)N_SYMOFF(xbuf), 0); npe = nl; nname = 0; for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { fread(&nbuf, sizeof(nbuf), 1, nfile); if ( ! funcsymbol( &nbuf ) ) { # ifdef DEBUG if ( debug & AOUTDEBUG ) { printf( "[getsymtab] rejecting: 0x%x %s\n" , nbuf.n_type , strtab + nbuf.n_un.n_strx ); } # endif /* DEBUG */ continue; } npe->value = nbuf.n_value; npe->name = strtab+nbuf.n_un.n_strx; # ifdef DEBUG if ( debug & AOUTDEBUG ) { printf( "[getsymtab] %d %s 0x%08lx\n" , nname , npe -> name , npe -> value ); } # endif /* DEBUG */ npe++; nname++; } npe->value = -1; }
/* Set parameters about this a.out file that are machine-dependent. This routine is called from some_aout_object_p just before it returns. */ static const bfd_target * MY (callback) (bfd *abfd) { struct internal_exec *execp = exec_hdr (abfd); /* Calculate the file positions of the parts of a newly read aout header */ obj_textsec (abfd)->size = N_TXTSIZE (*execp); /* The virtual memory addresses of the sections */ obj_textsec (abfd)->vma = N_TXTADDR (*execp); obj_datasec (abfd)->vma = N_DATADDR (*execp); obj_bsssec (abfd)->vma = N_BSSADDR (*execp); obj_textsec (abfd)->lma = obj_textsec (abfd)->vma; obj_datasec (abfd)->lma = obj_datasec (abfd)->vma; obj_bsssec (abfd)->lma = obj_bsssec (abfd)->vma; /* The file offsets of the sections */ obj_textsec (abfd)->filepos = N_TXTOFF (*execp); obj_datasec (abfd)->filepos = N_DATOFF (*execp); /* The file offsets of the relocation info */ obj_textsec (abfd)->rel_filepos = N_TRELOFF (*execp); obj_datasec (abfd)->rel_filepos = N_DRELOFF (*execp); /* The file offsets of the string table and symbol table. */ obj_sym_filepos (abfd) = N_SYMOFF (*execp); obj_str_filepos (abfd) = N_STROFF (*execp); /* Determine the architecture and machine type of the object file. */ #ifdef SET_ARCH_MACH SET_ARCH_MACH (abfd, *execp); #else bfd_default_set_arch_mach (abfd, DEFAULT_ARCH, 0); #endif if (obj_aout_subformat (abfd) == gnu_encap_format) { /* The file offsets of the relocation info */ obj_textsec (abfd)->rel_filepos = N_GNU_TRELOFF (*execp); obj_datasec (abfd)->rel_filepos = N_GNU_DRELOFF (*execp); /* The file offsets of the string table and symbol table. */ obj_sym_filepos (abfd) = N_GNU_SYMOFF (*execp); obj_str_filepos (abfd) = (obj_sym_filepos (abfd) + execp->a_syms); abfd->flags |= HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS; bfd_get_symcount (abfd) = execp->a_syms / 12; obj_symbol_entry_size (abfd) = 12; obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; } return abfd->xvec; }
static struct nlist * load_sym(int fd, struct exec *hdrp, long disp) { struct nlist * buffer; struct nlist * sym; struct nlist * end; long displ; int size; lseek(fd, N_SYMOFF(*hdrp) + hdrp->a_syms + disp, 0); if (read(fd, &size, sizeof(int)) != sizeof(int)) { goto err_noexec; } buffer = (struct nlist*)xmalloc(hdrp->a_syms + size); if (buffer == NULL) { dln_errno = errno; return NULL; } lseek(fd, disp + N_SYMOFF(*hdrp), 0); if (read(fd, buffer, hdrp->a_syms + size) != hdrp->a_syms + size) { free(buffer); goto err_noexec; } sym = buffer; end = sym + hdrp->a_syms / sizeof(struct nlist); displ = (long)buffer + (long)(hdrp->a_syms); while (sym < end) { sym->n_un.n_name = (char*)sym->n_un.n_strx + displ; sym++; } return buffer; err_noexec: dln_errno = DLN_ENOEXEC; return NULL; }
int read_nlist(char *systemfile) { int fd; struct exec hdr; unsigned symsize, size; if ((fd = open(systemfile, O_RDONLY)) < 0) { perror(systemfile); exit(1); } if (read(fd, (char *) &hdr, sizeof(hdr)) != sizeof(hdr)) { perror(systemfile); exit(1); } if (N_BADMAG(hdr)) { fprintf(stderr, "%s: bad magic number\n", systemfile); exit(1); } if (N_STROFF(hdr) == 0) { fprintf(stderr, "%s has no symbols\n", systemfile); exit(1); } lseek(fd, N_STROFF(hdr), SEEK_SET); read(fd, (char *) &stringsize, sizeof(stringsize)); symsize = N_STROFF(hdr) - N_SYMOFF(hdr); size = symsize + stringsize; namelist = (struct nlist *) xmalloc(size); lseek(fd, N_SYMOFF(hdr), SEEK_SET); if (read(fd, (char *) namelist, size) != size) { perror(systemfile); exit(1); } close(fd); strings = ((char *) namelist) + symsize; nsym = symsize / sizeof(struct nlist); if (Debug > 1) fprintf(stderr, "read %d symbols from %s\n", nsym, systemfile); return(0); }
static void getstrtab(FILE *nfile, const char *filename) { fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0); if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) errx( 1 , "%s: no string table (old format?)" , filename ); strtab = calloc(ssiz, 1); if (strtab == NULL) errx( 1 , "%s: no room for %ld bytes of string table", filename , ssiz); if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) errx( 1 , "%s: error reading string table" , filename ); }
/* build the new symbol and string tables */ static void buildNewTables(const HDR *x, long nsyms) { long remaining = nsyms; // total number of symbol table entries remaining to process #if FAST_NONPORTABLE_STRUCT_ARRAY_READ const int bunch = 1024; // number of symbol table entries to process at a time #else const int bunch = 1; #endif char *syms = new char[bunch*SYMSZ]; // buffer of old symbol table entries fseek(sym, N_SYMOFF(*x), 0); // go to old symbol table // fill the buffer int numInBuffer = xfread(syms, SYMSZ, min(bunch, remaining), sym); int symsi = 0; // index in buffer char *thisSym = syms; // pointer to entry symsi in buffer int auxEntries = 0; // number of aux entries still to skip over while (remaining) { if (auxEntries) // skip over them { if (auxEntries < 0) fatalError("Bad symbol table"); int skip = min(numInBuffer-symsi, auxEntries); if (remaining < skip) fatalError("Bad symbol table (missing auxiliary entries)"); auxEntries -= skip; remaining -= skip; symsi += skip; thisSym += skip*SYMSZ; } else { transformSymEntry((SYM*)thisSym); auxEntries = N_AUX(*(SYM*)thisSym); remaining--; symsi++; thisSym += SYMSZ; } assert (symsi <= bunch); if (symsi == bunch) // write and then refill the buffer { xfwrite(syms, SYMSZ, numInBuffer, newSym); numInBuffer = xfread(syms, SYMSZ, min(bunch, remaining), sym); symsi = 0; thisSym = syms; } } xfwrite(syms, SYMSZ, numInBuffer, newSym); delete syms; }
static void overwriteOldTables(const HDR *x) { // write the new symbol table to the original a.out, // beginning at the beginning of the original symbol table fseek(sym, N_SYMOFF(*x), 0); overwrite(newSym, sym); // write the new string table to the original a.out, // beginning right after the new symbol table long len = ftell(newSng) + 4; xfwrite(&len, 4, 1, sym); overwrite(newSng, sym); // rem: truncate, but probably doesn't need it. }
SYMTAB *Snarf_Symbols (FILE *f, struct exec *ep) { SYMTAB *tab; register SYM *sp, **nextp; int nsyms, strsiz; struct nlist nl; tab = (SYMTAB *)Safe_Malloc (sizeof (SYMTAB)); tab->first = 0; tab->strings = 0; nextp = &tab->first; (void)fseek (f, (long)N_SYMOFF(*ep), 0); for (nsyms = ep->a_syms / sizeof (nl); nsyms > 0; nsyms--) { if (fread ((char *)&nl, sizeof (nl), 1, f) != 1) { Free_Symbols (tab); (void)fclose (f); Primitive_Error ("corrupt symbol table in object file"); } if (nl.n_un.n_strx == 0 || nl.n_type & N_STAB) continue; #ifndef ibm023 if ((nl.n_type & N_TYPE) != N_TEXT) continue; #endif sp = (SYM *)Safe_Malloc (sizeof (SYM)); sp->name = (char *)nl.n_un.n_strx; sp->value = nl.n_value; *nextp = sp; nextp = &sp->next; *nextp = 0; } if (fread ((char *)&strsiz, sizeof (strsiz), 1, f) != 1) { strerr: Free_Symbols (tab); (void)fclose (f); Primitive_Error ("corrupt string table in object file"); } if (strsiz <= 4) goto strerr; tab->strings = Safe_Malloc (strsiz); strsiz -= 4; if (fread (tab->strings+4, 1, strsiz, f) != strsiz) goto strerr; for (sp = tab->first; sp; sp = sp->next) sp->name = tab->strings + (long)sp->name; return tab; }
void a_out_mod_symload(int strtablen) { struct lmc_loadbuf ldbuf; char buf[MODIOBUF]; int bytesleft, sz; /* * Seek to the symbol table to start loading it... */ if (lseek(modfd, N_SYMOFF(sinfo_buf), SEEK_SET) == -1) err(12, "lseek"); /* * we've fixed the symbol table entries, now load them */ for (bytesleft = sinfo_buf.a_syms; bytesleft > 0; bytesleft -= sz) { sz = MIN(bytesleft, MODIOBUF); if (read(modfd, buf, sz) != sz) err(14, "read"); ldbuf.cnt = sz; ldbuf.data = buf; if (ioctl(devfd, LMLOADSYMS, &ldbuf) == -1) err(11, "error transferring sym buffer"); } /* and now read the string table and load it. */ for (bytesleft = strtablen; bytesleft > 0; bytesleft -= sz) { sz = MIN(bytesleft, MODIOBUF); if (read(modfd, buf, sz) != sz) err(14, "read"); ldbuf.cnt = sz; ldbuf.data = buf; if (ioctl(devfd, LMLOADSYMS, &ldbuf) == -1) err(11, "error transferring stringtable buffer"); } }
void hide_syms(char *filename) { int inf, outf, rc; struct stat infstat; struct relocation_info *relp; struct nlist *symp; char *buf; u_char zero = 0; /* * Open the file and do some error checking. */ if ((inf = open(filename, O_RDWR)) == -1) { perror(filename); return; } if (fstat(inf, &infstat) == -1) { perror(filename); close(inf); return; } if (infstat.st_size < sizeof(struct exec)) { fprintf(stderr, "%s: short file\n", filename); close(inf); return; } if ((buf = mmap(NULL, infstat.st_size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, inf, 0)) == MAP_FAILED) { fprintf(stderr, "%s: cannot map\n", filename); close(inf); return; } #ifdef _NLIST_DO_ELF if (buf[0] == 0x7f && (buf[1] == 'E' || buf[1] == 'O') && buf[2] == 'L' && buf[3] == 'F') { elf_hide(inf, buf); return; } #endif /* _NLIST_DO_ELF */ #ifdef _NLIST_DO_ECOFF if (!ECOFF_BADMAG((struct ecoff_exechdr *) buf)) { ecoff_hide(inf, buf); return; } #endif /* _NLIST_DO_ECOFF */ #ifdef DO_AOUT aoutdata = buf; /* * Check the header and calculate offsets and sizes from it. */ hdrp = (struct exec *) aoutdata; if (N_BADMAG(*hdrp)) { fprintf(stderr, "%s: bad magic: not an a.out, ecoff or elf file\n", filename); close(inf); return; } textrel = (struct relocation_info *) (aoutdata + N_TRELOFF(*hdrp)); datarel = (struct relocation_info *) (aoutdata + N_DRELOFF(*hdrp)); symbase = (struct nlist *) (aoutdata + N_SYMOFF(*hdrp)); strbase = (char *) (aoutdata + N_STROFF(*hdrp)); ntextrel = hdrp->a_trsize / sizeof(struct relocation_info); ndatarel = hdrp->a_drsize / sizeof(struct relocation_info); nsyms = hdrp->a_syms / sizeof(struct nlist); /* * Zap the type field of all globally-defined symbols. The linker will * subsequently ignore these entries. Don't zap any symbols in the * keep list. */ for (symp = symbase; symp < symbase + nsyms; symp++) if (IS_GLOBAL_DEFINED(symp) && !in_keep_list(SYMSTR(symp))) { /* * XXX Our VM system has some problems, so * avoid the VM system.... */ lseek(inf, (off_t) ((void *) &symp->n_type - (void *) buf), SEEK_SET); write(inf, &zero, sizeof zero); symp->n_type = 0; } /* * Check whether the relocation entries reference any symbols that we * just zapped. I don't know whether ld can handle this case, but I * haven't encountered it yet. These checks are here so that the program * doesn't fail silently should such symbols be encountered. */ for (relp = textrel; relp < textrel + ntextrel; relp++) check_reloc(filename, relp); for (relp = datarel; relp < datarel + ndatarel; relp++) check_reloc(filename, relp); msync(buf, infstat.st_size, MS_SYNC); munmap(buf, infstat.st_size); close(inf); #endif /* DO_AOUT */ }
int __fdnlist_aout(int fd, struct nlist *list) { struct nlist *p, *s; char *strtab; off_t stroff, symoff; int nent; size_t strsize, symsize, cc; struct nlist nbuf[1024]; struct exec exec; struct stat st; char *scoreboard, *scored; _DIAGASSERT(fd != -1); _DIAGASSERT(list != NULL); if (pread(fd, &exec, sizeof(exec), (off_t)0) != sizeof(exec) || N_BADMAG(exec) || fstat(fd, &st) < 0) return (-1); symoff = N_SYMOFF(exec); symsize = (size_t)exec.a_syms; stroff = symoff + symsize; /* Check for files too large to mmap. */ if ((uintmax_t)(st.st_size - stroff) > (uintmax_t)SIZE_T_MAX) { errno = EFBIG; return (-1); } /* * Map string table into our address space. This gives us * an easy way to randomly access all the strings, without * making the memory allocation permanent as with malloc/free * (i.e., munmap will return it to the system). */ strsize = (size_t)(st.st_size - stroff); strtab = mmap(NULL, strsize, PROT_READ, MAP_PRIVATE|MAP_FILE, fd, stroff); if (strtab == (char *)-1) return (-1); /* * clean out any left-over information for all valid entries. * Type and value defined to be 0 if not found; historical * versions cleared other and desc as well. Also figure out * the largest string length so don't read any more of the * string table than we have to. * * XXX clearing anything other than n_type and n_value violates * the semantics given in the man page. */ nent = 0; for (p = list; !ISLAST(p); ++p) { p->n_type = 0; p->n_other = 0; p->n_desc = 0; p->n_value = 0; ++nent; } if (lseek(fd, symoff, SEEK_SET) == -1) return (-1); #if defined(__SSP__) || defined(__SSP_ALL__) scoreboard = malloc((size_t)nent); #else scoreboard = alloca((size_t)nent); #endif if (scoreboard == NULL) return (-1); (void)memset(scoreboard, 0, (size_t)nent); while (symsize > 0) { cc = MIN(symsize, sizeof(nbuf)); if (read(fd, nbuf, cc) != (ssize_t) cc) break; symsize -= cc; for (s = nbuf; cc > 0; ++s, cc -= sizeof(*s)) { long soff = s->n_un.n_strx; if (soff == 0 || (s->n_type & N_STAB) != 0) continue; for (p = list, scored = scoreboard; !ISLAST(p); p++, scored++) if (*scored == 0 && !strcmp(&strtab[(size_t)soff], p->n_un.n_name)) { p->n_value = s->n_value; p->n_type = s->n_type; p->n_desc = s->n_desc; p->n_other = s->n_other; *scored = 1; if (--nent <= 0) break; } } } munmap(strtab, strsize); #if defined(__SSP__) || defined(__SSP_ALL__) free(scoreboard); #endif return (nent); }
/* * show_file() * show symbols from the object file pointed to by fp. The current * file pointer for fp is expected to be at the beginning of an object * file header. */ int show_file(int count, int warn_fmt, const char *name, FILE *fp, off_t foff, union hdr *head) { u_long text, data, bss, total; struct nlist *np, *names, **snames; char *stab; int i, aout, nnames; size_t stabsize; off_t staboff; aout = 0; if (!elf32_chk_header(&head->elf32)) { struct elf_symtab es; es.name = name; es.ehdr = &head->elf32; if (head->elf32.e_ehsize < sizeof head->elf32) { warnx("%s: ELF header is too short", name); return 1; } if (!(es.shdr = elf32_load_shdrs(name, fp, foff, es.ehdr))) return (1); elf32_fix_shdrs(es.ehdr, es.shdr); es.shstr = NULL; if (issize) i = elf32_size(es.ehdr, es.shdr, &text, &data, &bss); else { nrawnames = 0; names = NULL; i = elf32_symload(&es, fp, foff, elf_symadd, &names); stab = es.stab; stabsize = es.stabsz; } free(es.shstr); free(es.shdr); if (i) return (i); } else if (!elf64_chk_header(&head->elf64)) { struct elf_symtab es; es.name = name; es.ehdr = &head->elf64; if (head->elf64.e_ehsize < sizeof head->elf64) { warnx("%s: ELF header is too short", name); return 1; } if (!(es.shdr = elf64_load_shdrs(name, fp, foff, es.ehdr))) return (1); elf64_fix_shdrs(es.ehdr, es.shdr); es.shstr = NULL; if (issize) i = elf64_size(es.ehdr, es.shdr, &text, &data, &bss); else { nrawnames = 0; names = NULL; i = elf64_symload(&es, fp, foff, elf_symadd, &names); stab = es.stab; stabsize = es.stabsz; } free(es.shstr); free(es.shdr); if (i) return (i); } else if (BAD_OBJECT(head->aout)) { if (warn_fmt) warnx("%s: bad format", name); return (1); } else do { u_int32_t w; aout++; fix_header_order(&head->aout); if (issize) { text = head->aout.a_text; data = head->aout.a_data; bss = head->aout.a_bss; break; } /* stop if the object file contains no symbol table */ if (!head->aout.a_syms) { warnx("%s: no name list", name); return(1); } if (fseeko(fp, foff + N_SYMOFF(head->aout), SEEK_SET)) { warn("%s", name); return(1); } #ifdef __LP64__ nrawnames = head->aout.a_syms / sizeof(struct nlist32); #else nrawnames = head->aout.a_syms / sizeof(*names); #endif /* get memory for the symbol table */ if ((names = calloc(nrawnames, sizeof(struct nlist))) == NULL) { warn("%s: malloc names", name); return (1); } #ifdef __LP64__ for (np = names, i = nrawnames; i--; np++) { struct nlist32 nl32; if (fread(&nl32, sizeof(nl32), 1, fp) != 1) { warnx("%s: cannot read symbol table", name); free(names); return (1); } np->n_type = nl32.type; np->n_other = nl32.other; if (byte_sex(N_GETMID(head->aout)) != BYTE_ORDER) { np->n_un.n_strx = swap32(nl32.strx); np->n_desc = swap16(nl32.desc); np->n_value = swap32(nl32.value); } else { np->n_un.n_strx = nl32.strx; np->n_desc = nl32.desc; np->n_value = nl32.value; } } #else if (fread(names, head->aout.a_syms, 1, fp) != 1) { warnx("%s: cannot read symbol table", name); free(names); return (1); } fix_nlists_order(names, nrawnames, N_GETMID(head->aout)); #endif staboff = ftello(fp); /* * Following the symbol table comes the string table. * The first 4-byte-integer gives the total size of the * string table _including_ the size specification itself. */ if (fread(&w, sizeof(w), (size_t)1, fp) != 1) { warnx("%s: cannot read stab size", name); free(names); return(1); } stabsize = fix_32_order(w, N_GETMID(head->aout)); if ((stab = malloc(stabsize)) == NULL) { warn("%s: malloc", name); return 1; } if (pread(fileno(fp), stab, stabsize, staboff) != stabsize) { free(stab); warn("%s: pread", name); return 1; } stabsize -= 4; /* we already have the size */ for (np = names, i = nnames = 0; i < nrawnames; np++, i++) { /* * make n_un.n_name a character pointer by adding * the string table's base to n_un.n_strx * * don't mess with zero offsets */ if (np->n_un.n_strx) np->n_un.n_name = stab + np->n_un.n_strx; else np->n_un.n_name = ""; } } while (0); if (issize) { static int first = 1; if (first) { first = 0; printf("text\tdata\tbss\tdec\thex\n"); } total = text + data + bss; printf("%lu\t%lu\t%lu\t%lu\t%lx", text, data, bss, total, total); if (count > 1) (void)printf("\t%s", name); total_text += text; total_data += data; total_bss += bss; total_total += total; printf("\n"); return (0); } /* else we are nm */ /* * it seems that string table is sequential * relative to the symbol table order */ if ((snames = calloc(nrawnames, sizeof *snames)) == NULL) { warn("%s: malloc snames", name); free(names); return (1); } /* * fix up the symbol table and filter out unwanted entries * * common symbols are characterized by a n_type of N_UNDF and a * non-zero n_value -- change n_type to N_COMM for all such * symbols to make life easier later. * * filter out all entries which we don't want to print anyway */ for (np = names, i = nnames = 0; i < nrawnames; np++, i++) { if (aout && SYMBOL_TYPE(np->n_type) == N_UNDF && np->n_value) np->n_type = N_COMM | (np->n_type & N_EXT); if (!print_all_symbols && IS_DEBUGGER_SYMBOL(np->n_type)) continue; if (print_only_external_symbols && !IS_EXTERNAL(np->n_type)) continue; if (print_only_undefined_symbols && SYMBOL_TYPE(np->n_type) != N_UNDF) continue; snames[nnames++] = np; } /* sort the symbol table if applicable */ if (sfunc) qsort(snames, (size_t)nnames, sizeof(*snames), sfunc); if (count > 1) (void)printf("\n%s:\n", name); /* print out symbols */ for (i = 0; i < nnames; i++) { if (show_extensions && snames[i] != names && SYMBOL_TYPE((snames[i] -1)->n_type) == N_INDR) continue; print_symbol(name, snames[i], aout); } free(snames); free(names); free(stab); return(0); }
/* * rexec * Read the exec structure; ignore any files that don't look * exactly right. Return MID. * return -1 for files that don't look right. * XXX it's hard to be sure when to ignore files, and when to error * out. */ static int rexec(int rfd, int wfd) { RLIB *rp; long nsyms; int nr, symlen; char *strtab = 0; char *sym; struct exec ebuf; struct nlist nl; off_t r_off, w_off; long strsize; int result = -1; /* Get current offsets for original and tmp files. */ r_off = lseek(rfd, (off_t)0, SEEK_CUR); w_off = lseek(wfd, (off_t)0, SEEK_CUR); /* Read in exec structure. */ nr = read(rfd, (char *)&ebuf, sizeof(struct exec)); if (nr != sizeof(struct exec)) goto bad; /* Check magic number and symbol count. */ if (BAD_OBJECT(ebuf) || ebuf.a_syms == 0) goto bad; fix_header_order(&ebuf); /* Seek to string table. */ if (lseek(rfd, N_STROFF(ebuf) + r_off, SEEK_SET) == (off_t)-1) { if (errno == EINVAL) goto bad; else error(archive); } /* Read in size of the string table. */ nr = read(rfd, (char *)&strsize, sizeof(strsize)); if (nr != sizeof(strsize)) goto bad; strsize = fix_32_order(strsize, N_GETMID(ebuf)); /* Read in the string table. */ strsize -= sizeof(strsize); strtab = (char *)emalloc(strsize); nr = read(rfd, strtab, strsize); if (nr != strsize) goto bad; /* Seek to symbol table. */ if (fseek(fp, N_SYMOFF(ebuf) + r_off, SEEK_SET) == (off_t)-1) goto bad; result = N_GETMID(ebuf); /* For each symbol read the nlist entry and save it as necessary. */ nsyms = ebuf.a_syms / sizeof(struct nlist); while (nsyms--) { if (!fread((char *)&nl, sizeof(struct nlist), 1, fp)) { if (feof(fp)) badfmt(); error(archive); } fix_nlist_order(&nl, N_GETMID(ebuf)); /* Ignore if no name or local. */ if (!nl.n_un.n_strx || !(nl.n_type & N_EXT)) continue; /* * If the symbol is an undefined external and the n_value * field is non-zero, keep it. */ if ((nl.n_type & N_TYPE) == N_UNDF && !nl.n_value) continue; /* First four bytes are the table size. */ sym = strtab + nl.n_un.n_strx - sizeof(long); symlen = strlen(sym) + 1; rp = (RLIB *)emalloc(sizeof(RLIB)); rp->sym = (char *)emalloc(symlen); bcopy(sym, rp->sym, symlen); rp->symlen = symlen; rp->pos = w_off; /* Build in forward order for "ar -m" command. */ *pnext = rp; pnext = &rp->next; ++symcnt; tsymlen += symlen; } bad: if (nr < 0) error(archive); free(strtab); (void)lseek(rfd, (off_t)r_off, SEEK_SET); return result; }
int main(int argc, char **argv) { struct nlist *p, *symp; FILE *f, *xfile; int i; char *start, *t, *xfilename; int ch, n, o; xfilename = NULL; while ((ch = getopt(argc, argv, "cmtx:")) != -1) switch(ch) { case 'c': clean = 1; break; case 'm': missing = 1; break; case 't': small = 1; break; case 'x': if (xfilename != NULL) usage(); xfilename = optarg; break; case '?': default: usage(); } argc -= optind; argv += optind; if (argc != 2) usage(); if ((f = fopen(argv[0], "r")) == NULL) err(ERREXIT, "%s", argv[0]); for (p = order; fgets(asym, sizeof(asym), f) != NULL;) { for (t = asym; isspace(*t); ++t); if (!*(start = t)) continue; while (*++t); if (*--t == '\n') *t = '\0'; p->n_un.n_name = strdup(start); ++p; if (++nsym >= sizeof order / sizeof order[0]) break; } (void)fclose(f); if (xfilename != NULL) { if ((xfile = fopen(xfilename, "r")) == NULL) err(ERREXIT, "%s", xfilename); for (; fgets(asym, sizeof(asym), xfile) != NULL;) { for (t = asym; isspace(*t); ++t); if (!*(start = t)) continue; while (*++t); if (*--t == '\n') *t = '\0'; exclude[nexclude] = strdup(start); if (++nexclude >= sizeof exclude / sizeof exclude[0]) break; } (void)fclose(xfile); } kfile = argv[1]; if ((f = fopen(kfile, "r")) == NULL) err(ERREXIT, "%s", kfile); if ((o = open(kfile, O_WRONLY)) < 0) err(ERREXIT, "%s", kfile); /* read exec header */ if ((fread(&exec, sizeof(exec), 1, f)) != 1) badfmt("no exec header"); if (N_BADMAG(exec)) badfmt("bad magic number"); if (exec.a_syms == 0) badfmt("stripped"); (void)fstat(fileno(f), &stb); if (stb.st_size < N_STROFF(exec) + sizeof(off_t)) badfmt("no string table"); /* seek to and read the symbol table */ sa = N_SYMOFF(exec); (void)fseek(f, sa, SEEK_SET); n = exec.a_syms; if (!(symtab = (struct nlist *)malloc(n))) err(ERREXIT, NULL); if (fread((void *)symtab, 1, n, f) != n) badfmt("corrupted symbol table"); /* read string table size and string table */ if (fread((void *)&strtabsize, sizeof(int), 1, f) != 1 || strtabsize <= 0) badfmt("corrupted string table"); strings = malloc(strtabsize); if (strings == NULL) err(ERREXIT, NULL); /* * Subtract four from strtabsize since strtabsize includes itself, * and we've already read it. */ if (fread(strings, 1, strtabsize - sizeof(int), f) != strtabsize - sizeof(int)) badfmt("corrupted string table"); i = n / sizeof(struct nlist); if (!clean) { newtab = (struct nlist *)malloc(n); if (newtab == NULL) err(ERREXIT, NULL); memset(newtab, 0, n); reorder(symtab, newtab, i); free((void *)symtab); symtab = newtab; } else { symkept = i; } newstrings = malloc(strtabsize); if (newstrings == NULL) err(ERREXIT, NULL); t = newstrings; for (symp = symtab; --i >= 0; symp++) { if (symp->n_un.n_strx == 0) continue; if (inlist(symp) < 0) { if (small) continue; if (clean && !savesymb(symp)) symp->n_type &= ~N_EXT; } else if (clean) symfound++; symp->n_un.n_strx -= sizeof(int); (void)strcpy(t, &strings[symp->n_un.n_strx]); symp->n_un.n_strx = (t - newstrings) + sizeof(int); t += strlen(t) + 1; } /* update shrunk sizes */ strtabsize = t - newstrings + sizeof(int); n = symkept * sizeof(struct nlist); /* fix exec sym size */ (void)lseek(o, (off_t)0, SEEK_SET); exec.a_syms = n; if (write(o, (void *)&exec, sizeof(exec)) != sizeof(exec)) err(ERREXIT, "%s", kfile); (void)lseek(o, sa, SEEK_SET); if (write(o, (void *)symtab, n) != n) err(ERREXIT, "%s", kfile); if (write(o, (void *)&strtabsize, sizeof(int)) != sizeof(int)) err(ERREXIT, "%s", kfile); if (write(o, newstrings, strtabsize - sizeof(int)) != strtabsize - sizeof(int)) err(ERREXIT, "%s", kfile); ftruncate(o, lseek(o, (off_t)0, SEEK_CUR)); if ((i = nsym - symfound) > 0) { (void)printf("symorder: %d symbol%s not found:\n", i, i == 1 ? "" : "s"); for (i = 0; i < nsym; i++) if (order[i].n_value == 0) printf("%s\n", order[i].n_un.n_name); if (!missing) exit(NOTFOUNDEXIT); } exit(OKEXIT); }
int __aout_fdnlist(int fd, struct nlist *list) { struct nlist *p, *s; char *strtab; off_t symoff, stroff; u_long symsize; int nent, cc; int strsize, usemalloc = 0; struct nlist nbuf[1024]; struct exec exec; if (pread(fd, &exec, sizeof(exec), (off_t)0) != sizeof(exec) || N_BADMAG(exec) || exec.a_syms == NULL) return (-1); stroff = N_STROFF(exec); symoff = N_SYMOFF(exec); symsize = exec.a_syms; /* Read in the size of the string table. */ if (pread(fd, (void *)&strsize, sizeof(strsize), stroff) != sizeof(strsize)) return (-1); else stroff += sizeof(strsize); /* * Read in the string table. We try mmap, but that will fail * for /dev/ksyms so fall back on malloc. Since OpenBSD's malloc(3) * returns memory to the system on free this does not cause bloat. */ strsize -= sizeof(strsize); strtab = mmap(NULL, (size_t)strsize, PROT_READ, MAP_SHARED|MAP_FILE, fd, stroff); if (strtab == MAP_FAILED) { usemalloc = 1; if ((strtab = (char *)malloc(strsize)) == NULL) return (-1); errno = EIO; if (pread(fd, strtab, strsize, stroff) != strsize) { nent = -1; goto aout_done; } } /* * clean out any left-over information for all valid entries. * Type and value defined to be 0 if not found; historical * versions cleared other and desc as well. Also figure out * the largest string length so don't read any more of the * string table than we have to. * * XXX clearing anything other than n_type and n_value violates * the semantics given in the man page. */ nent = 0; for (p = list; !ISLAST(p); ++p) { p->n_type = 0; p->n_other = 0; p->n_desc = 0; p->n_value = 0; ++nent; } while (symsize > 0) { cc = MIN(symsize, sizeof(nbuf)); if (pread(fd, nbuf, cc, symoff) != cc) break; symsize -= cc; symoff += cc; for (s = nbuf; cc > 0; ++s, cc -= sizeof(*s)) { char *sname = strtab + s->n_un.n_strx - sizeof(int); if (s->n_un.n_strx == 0 || (s->n_type & N_STAB) != 0) continue; for (p = list; !ISLAST(p); p++) { char *pname = p->n_un.n_name; if (*sname != '_' && *pname == '_') pname++; if (!strcmp(sname, pname)) { p->n_value = s->n_value; p->n_type = s->n_type; p->n_desc = s->n_desc; p->n_other = s->n_other; if (--nent <= 0) break; } } } } aout_done: if (usemalloc) free(strtab); else munmap(strtab, strsize); return (nent); }
/* * read_exec * Read the exec structure; ignore any files that don't look * exactly right. Return MID. * return -1 for files that don't look right. * XXX it's hard to be sure when to ignore files, and when to error * out. */ int read_exec(FILE *rfp, FILE *wfp, long *symcnt, long *tsymlen) { union { struct exec exec; Elf32_Ehdr elf32; Elf64_Ehdr elf64; } eh; struct nlist nl; off_t r_off, w_off; char *strtab = NULL; long strsize, nsyms; int i; /* Get current offsets for original and tmp files. */ r_off = ftello(rfp); w_off = ftello(wfp); /* Read in exec structure. */ if (fread(&eh, sizeof(eh), 1, rfp) != 1) err(1, "fread: %s", archive); if (!elf32_chk_header(&eh.elf32)) { Elf32_Sym sbuf; char *shstr; Elf32_Shdr *shdr; size_t stabsize; elf32_fix_header(&eh.elf32); if (eh.elf32.e_ehsize < sizeof eh.elf32) { warnx("%s: ELF header is too short", archive); goto bad; } if (!(shdr = elf32_load_shdrs(archive, rfp, r_off, &eh.elf32))) goto bad; elf32_fix_shdrs(&eh.elf32, shdr); if (!(shstr = elf32_shstrload(archive, rfp, r_off, &eh.elf32, shdr))) { free(shdr); goto bad; } if (!(strtab = elf32_strload(archive, rfp, r_off, &eh.elf32, shdr, shstr, ELF_STRTAB, &stabsize))) { free(shstr); free(shdr); goto bad; } /* find the symtab section */ for (i = 0; i < eh.elf32.e_shnum; i++) if (!strcmp(shstr + shdr[i].sh_name, ELF_SYMTAB)) { nsyms = shdr[i].sh_size / sizeof(Elf32_Sym); break; } if (i == eh.elf32.e_shnum) { free(shstr); free(shdr); goto bad; } if (fseeko(rfp, r_off + shdr[i].sh_offset, SEEK_SET)) err(1, "fseeko: %s", archive); for (i = 0; i < nsyms; i++) { if (fread(&sbuf, sizeof(sbuf), 1, rfp) != 1) err(1, "fread: %s", archive); elf32_fix_sym(&eh.elf32, &sbuf); if (!sbuf.st_name || sbuf.st_name > stabsize) continue; if (elf32_2nlist(&sbuf, &eh.elf32, shdr, shstr, &nl)) continue; addsym(&nl, strtab, r_off - r_fuzz - sizeof(struct ar_hdr), symcnt, tsymlen, archive); } free(strtab); free(shstr); free(shdr); (void)fseeko(rfp, r_off, SEEK_SET); return MID_ELFFL | eh.elf32.e_machine; } else if (!elf64_chk_header(&eh.elf64)) { Elf64_Sym sbuf; char *shstr; Elf64_Shdr *shdr; size_t stabsize; elf64_fix_header(&eh.elf64); if (eh.elf64.e_ehsize < sizeof eh.elf64) { warnx("%s: ELF header is too short", archive); goto bad; } if (!(shdr = elf64_load_shdrs(archive, rfp, r_off, &eh.elf64))) goto bad; elf64_fix_shdrs(&eh.elf64, shdr); if (!(shstr = elf64_shstrload(archive, rfp, r_off, &eh.elf64, shdr))) { free(shdr); goto bad; } if (!(strtab = elf64_strload(archive, rfp, r_off, &eh.elf64, shdr, shstr, ELF_STRTAB, &stabsize))) { free(shstr); free(shdr); goto bad; } /* find the symtab section */ for (i = 0; i < eh.elf64.e_shnum; i++) if (!strcmp(shstr + shdr[i].sh_name, ELF_SYMTAB)) { nsyms = shdr[i].sh_size / sizeof(Elf64_Sym); break; } if (i == eh.elf64.e_shnum) { free(shstr); free(shdr); goto bad; } if (fseeko(rfp, r_off + shdr[i].sh_offset, SEEK_SET)) err(1, "fseeko: %s", archive); for (i = 0; i < nsyms; i++) { if (fread(&sbuf, sizeof(sbuf), 1, rfp) != 1) err(1, "fread: %s", archive); elf64_fix_sym(&eh.elf64, &sbuf); if (!sbuf.st_name || sbuf.st_name > stabsize) continue; if (elf64_2nlist(&sbuf, &eh.elf64, shdr, shstr, &nl)) continue; addsym(&nl, strtab, r_off - r_fuzz - sizeof(struct ar_hdr), symcnt, tsymlen, archive); } free(strtab); free(shstr); free(shdr); (void)fseeko(rfp, r_off, SEEK_SET); return MID_ELFFL | eh.elf64.e_machine; } else if (BAD_OBJECT(eh.exec) || eh.exec.a_syms == 0) goto bad; fix_header_order(&eh.exec); /* Seek to string table. */ if (fseeko(rfp, N_STROFF(eh.exec) + r_off, SEEK_SET) == -1) { if (errno == EINVAL) goto bad; else err(1, "lseek: %s", archive); } /* Read in size of the string table. */ if (fread((char *)&strsize, sizeof(strsize), 1, rfp) != 1) err(1, "fread: %s", archive); strsize = fix_32_order(strsize, N_GETMID(eh.exec)); /* Read in the string table. */ strsize -= sizeof(strsize); strtab = malloc(strsize); if (!strtab) err(1, "malloc: %s", archive); if (fread(strtab, strsize, 1, rfp) != 1) err(1, "fread: %s", archive); /* Seek to symbol table. */ if (fseek(rfp, N_SYMOFF(eh.exec) + r_off, SEEK_SET) == (off_t)-1) err(1, "fseeko: %s", archive); /* For each symbol read the nlist entry and save it as necessary. */ nsyms = eh.exec.a_syms / sizeof(struct nlist); while (nsyms--) { if (!fread((char *)&nl, sizeof(struct nlist), 1, rfp)) { if (feof(rfp)) badfmt(); err(1, "fread: %s", archive); } fix_nlist_order(&nl, N_GETMID(eh.exec)); addsym(&nl, strtab - sizeof(long), r_off - r_fuzz - sizeof(struct ar_hdr), symcnt, tsymlen, archive); } bad: free(strtab); (void)fseeko(rfp, r_off, SEEK_SET); return N_GETMID(eh.exec); }
static const bfd_target * aout_adobe_callback (bfd *abfd) { struct internal_exec *execp = exec_hdr (abfd); asection *sect; struct external_segdesc ext[1]; char *section_name; char try_again[30]; /* Name and number. */ char *newname; int trynum; flagword flags; /* Architecture and machine type -- unknown in this format. */ bfd_set_arch_mach (abfd, bfd_arch_unknown, 0L); /* The positions of the string table and symbol table. */ obj_str_filepos (abfd) = N_STROFF (*execp); obj_sym_filepos (abfd) = N_SYMOFF (*execp); /* Suck up the section information from the file, one section at a time. */ for (;;) { bfd_size_type amt = sizeof (*ext); if (bfd_bread ( ext, amt, abfd) != amt) { if (bfd_get_error () != bfd_error_system_call) bfd_set_error (bfd_error_wrong_format); return NULL; } switch (ext->e_type[0]) { case N_TEXT: section_name = ".text"; flags = SEC_CODE | SEC_LOAD | SEC_ALLOC | SEC_HAS_CONTENTS; break; case N_DATA: section_name = ".data"; flags = SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_HAS_CONTENTS; break; case N_BSS: section_name = ".bss"; flags = SEC_DATA | SEC_HAS_CONTENTS; break; case 0: goto no_more_sections; default: (*_bfd_error_handler) (_("%B: Unknown section type in a.out.adobe file: %x\n"), abfd, ext->e_type[0]); goto no_more_sections; } /* First one is called ".text" or whatever; subsequent ones are ".text1", ".text2", ... */ bfd_set_error (bfd_error_no_error); sect = bfd_make_section_with_flags (abfd, section_name, flags); trynum = 0; while (!sect) { if (bfd_get_error () != bfd_error_no_error) /* Some other error -- slide into the sunset. */ return NULL; sprintf (try_again, "%s%d", section_name, ++trynum); sect = bfd_make_section_with_flags (abfd, try_again, flags); } /* Fix the name, if it is a sprintf'd name. */ if (sect->name == try_again) { amt = strlen (sect->name); newname = bfd_zalloc (abfd, amt); if (newname == NULL) return NULL; strcpy (newname, sect->name); sect->name = newname; } /* Assumed big-endian. */ sect->size = ((ext->e_size[0] << 8) | ext->e_size[1] << 8 | ext->e_size[2]); sect->vma = H_GET_32 (abfd, ext->e_virtbase); sect->filepos = H_GET_32 (abfd, ext->e_filebase); /* FIXME XXX alignment? */ /* Set relocation information for first section of each type. */ if (trynum == 0) switch (ext->e_type[0]) { case N_TEXT: sect->rel_filepos = N_TRELOFF (*execp); sect->reloc_count = execp->a_trsize; break; case N_DATA: sect->rel_filepos = N_DRELOFF (*execp); sect->reloc_count = execp->a_drsize; break; default: break; } } no_more_sections: adata (abfd).reloc_entry_size = sizeof (struct reloc_std_external); adata (abfd).symbol_entry_size = sizeof (struct external_nlist); adata (abfd).page_size = 1; /* Not applicable. */ adata (abfd).segment_size = 1; /* Not applicable. */ adata (abfd).exec_bytes_size = EXEC_BYTES_SIZE; return abfd->xvec; }
int main (int argc, char *argv[]) { register struct nlist *s; register caddr_t strtab; register off_t stroff, symoff; register u_long symsize; register int cc; size_t strsize; struct nlist nbuf[1024]; struct exec exec; struct stat st; int fd; int pageOffset; if ((fd = open (argv[1], O_RDONLY)) < 0) { fprintf (stderr, "could not open %s\n", argv[1]); return -1; } if (lseek(fd, (off_t)0, SEEK_SET) == -1 || read(fd, &exec, sizeof(exec)) != sizeof(exec) || fstat(fd, &st) < 0) { fprintf (stderr, "Invalid binary file\n"); return -1; } if (N_BADMAG (exec) || N_GETMID (exec) != MID_I386) { fprintf (stderr, "invalid executable file N_BADMAG(exec) %d N_GETMID (exec) %d MID_I386 %d\n", N_BADMAG(exec), N_GETMID(exec), MID_I386); exit (1); } if (N_GETFLAG (exec) & EX_DYNAMIC) { fprintf (stderr, "are you giving me a dynamically linked executable??\n"); return -1; } symoff = N_SYMOFF(exec); symsize = exec.a_syms; stroff = symoff + symsize; #ifndef __linux__ /* Check for files too large to mmap. */ if (st.st_size - stroff > SIZE_T_MAX) { fprintf (stderr, "file too large\n"); return -1; } #endif /* * Map string table into our address space. This gives us * an easy way to randomly access all the strings, without * making the memory allocation permanent as with malloc/free * (i.e., munmap will return it to the system). */ strsize = st.st_size - stroff; pageOffset = stroff % 4096; stroff -= pageOffset; strsize += pageOffset; strtab = mmap(NULL, (size_t)strsize, PROT_READ, MAP_SHARED, fd, stroff); if (strtab == (char *)-1) { warn ("could not mmap string table"); return -1; } strtab += pageOffset; strsize -= pageOffset; if (lseek(fd, symoff, SEEK_SET) == -1) { fprintf (stderr, "could not lseek to symbol table\n"); return -1; } while (symsize > 0) { int i; cc = my_min(symsize, sizeof(nbuf)); if (read(fd, nbuf, cc) != cc) break; symsize -= cc; for (s = nbuf; cc > 0; ++s, cc -= sizeof(*s)) { register int soff = s->n_un.n_strx; if (soff == 0 || (s->n_type & N_STAB) != 0) continue; for (i = 0; exclude[i]; i++) { if (!strcmp (&strtab[soff], exclude[i])) goto skip; } /* hack to avoid symbol with name equal to tmp filename used to build us */ if (strchr (&strtab[soff], '.') || strchr (&strtab[soff], '/')) goto skip; if (s->n_type & N_EXT) { printf ("\t.globl\t%s\n\t.set\t%s,0x%lx\n\t.weak\t%s\n\n", &strtab[soff], &strtab[soff], s->n_value, &strtab[soff]); } skip: ; } } munmap(strtab, strsize); return 0; }
main(int ac,char *av[]) { const char *aoutfile; FILE *aout; struct exec exec; struct nlist nlist; int nsyms,si,soff; int nrels; if( ac < 2 ){ fprintf(stderr,"Usage: %s a.out-filename\n",av[0]); exit(1); } aoutfile = av[1]; aout = fopen(aoutfile,"r+"); if( aout == NULL ){ fprintf(stderr,"Cannot open %s\n",aoutfile); exit(1); } fread(&exec,1,sizeof(exec),aout); if( N_BADMAG(exec) ){ fprintf(stderr,"%s: not a a.out file\n",aoutfile); exit(1); } if( exec.a_text != 0 ){ if( exec.a_data ) fprintf(stderr,"cannot move data to text.\n"); else fprintf(stderr,"no data segment.\n"); exit(1); } fprintf(stderr,"%6d text\n",exec.a_text); fprintf(stderr,"%6d data\n",exec.a_data); nsyms = exec.a_syms/sizeof(struct nlist); fprintf(stderr,"%6d syms\n",nsyms); fprintf(stderr,"%6d drels\n",exec.a_drsize); if( exec.a_drsize ){ fprintf(stderr,"cannot move data with relocation.\n"); exit(1); } fseek(aout,N_SYMOFF(exec),0); for( si = 0; si < nsyms; si++ ){ soff = ftell(aout); fread(&nlist,1,sizeof(struct nlist),aout); if( nlist.n_type & N_DATA ){ nlist.n_type = (nlist.n_type & ~N_DATA) | N_TEXT; fseek(aout,soff,0); fwrite(&nlist,1,sizeof(struct nlist),aout); fflush(aout); } } exec.a_text = exec.a_data; exec.a_data = 0; fseek(aout,0,0); fwrite(&exec,1,sizeof(exec),aout); fflush(aout); fclose(aout); fprintf(stderr,"%d bytes of data moved to text segment.\n",exec.a_text); exit(0); }
int __aout_fdnlist(int fd, struct nlist *list) { struct nlist *p, *symtab; caddr_t strtab, a_out_mmap; off_t stroff, symoff; u_long symsize; int nent; struct exec * exec; struct stat st; /* check that file is at least as large as struct exec! */ if ((_fstat(fd, &st) < 0) || (st.st_size < sizeof(struct exec))) return (-1); /* Check for files too large to mmap. */ if (st.st_size > SIZE_T_MAX) { errno = EFBIG; return (-1); } /* * Map the whole a.out file into our address space. * We then find the string table withing this area. * We do not just mmap the string table, as it probably * does not start at a page boundary - we save ourselves a * lot of nastiness by mmapping the whole file. * * This gives us an easy way to randomly access all the strings, * without making the memory allocation permanent as with * malloc/free (i.e., munmap will return it to the system). */ a_out_mmap = mmap(NULL, (size_t)st.st_size, PROT_READ, MAP_PRIVATE, fd, (off_t)0); if (a_out_mmap == MAP_FAILED) return (-1); exec = (struct exec *)a_out_mmap; if (N_BADMAG(*exec)) { munmap(a_out_mmap, (size_t)st.st_size); return (-1); } symoff = N_SYMOFF(*exec); symsize = exec->a_syms; stroff = symoff + symsize; /* find the string table in our mmapped area */ strtab = a_out_mmap + stroff; symtab = (struct nlist *)(a_out_mmap + symoff); /* * clean out any left-over information for all valid entries. * Type and value defined to be 0 if not found; historical * versions cleared other and desc as well. Also figure out * the largest string length so don't read any more of the * string table than we have to. * * XXX clearing anything other than n_type and n_value violates * the semantics given in the man page. */ nent = 0; for (p = list; !ISLAST(p); ++p) { p->n_type = 0; p->n_other = 0; p->n_desc = 0; p->n_value = 0; ++nent; } while (symsize > 0) { int soff; symsize-= sizeof(struct nlist); soff = symtab->n_un.n_strx; if (soff != 0 && (symtab->n_type & N_STAB) == 0) for (p = list; !ISLAST(p); p++) if (!strcmp(&strtab[soff], p->n_un.n_name)) { p->n_value = symtab->n_value; p->n_type = symtab->n_type; p->n_desc = symtab->n_desc; p->n_other = symtab->n_other; if (--nent <= 0) break; } symtab++; } munmap(a_out_mmap, (size_t)st.st_size); return (nent); }
setsym() { off_t loc; struct exec hdr; register struct nlist *sp; int ssiz; char *strtab; fsym = getfile(symfil, 1); txtmap.ufd = fsym; if (read(fsym, (char *)&hdr, sizeof hdr) != sizeof hdr || N_BADMAG(hdr)) { txtmap.e1 = MAXFILE; return; } filhdr = hdr; loc = filhdr.a_text+filhdr.a_data; txtmap.f1 = txtmap.f2 = N_TXTOFF(filhdr); txtmap.b1 = 0; switch (filhdr.a_magic) { case OMAGIC: txtmap.b1 = txtmap.e1 = 0; txtmap.b2 = datbas = 0; txtmap.e2 = loc; break; case ZMAGIC: case NMAGIC: txtmap.e1 = filhdr.a_text; txtmap.b2 = datbas = round(filhdr.a_text, PAGSIZ); txtmap.e2 = datbas + filhdr.a_data; txtmap.f2 += txtmap.e1; } loc = N_SYMOFF(filhdr); symtab = (struct nlist *) malloc(filhdr.a_syms); esymtab = &symtab[filhdr.a_syms / sizeof (struct nlist)]; if (symtab == NULL) goto nospac; lseek(fsym, loc, L_SET); if (filhdr.a_syms == 0) goto nosymt; /* SHOULD SQUISH OUT STABS HERE!!! */ if (read(fsym, symtab, filhdr.a_syms) != filhdr.a_syms) goto readerr; if (read(fsym, &ssiz, sizeof (ssiz)) != sizeof (ssiz)) goto oldfmt; strtab = (char *) malloc(ssiz); if (strtab == 0) goto nospac; *(int *)strtab = ssiz; ssiz -= sizeof (ssiz); if (read(fsym, strtab + sizeof (ssiz), ssiz) != ssiz) goto readerr; for (sp = symtab; sp < esymtab; sp++) if (sp->n_strx) /* SHOULD PERFORM RANGE CHECK HERE */ sp->n_un.n_name = strtab + sp->n_un.n_strx; nosymt: if (INKERNEL(filhdr.a_entry)) { txtmap.b1 += KERNOFF; txtmap.e1 += KERNOFF; txtmap.b2 += KERNOFF; txtmap.e2 += KERNOFF; } return; readerr: printf("Error reading symbol|string table\n"); exit(1); nospac: printf("Not enough space for symbol|string table\n"); exit(1); oldfmt: printf("Old format a.out - no string table\n"); exit(1); }
static #endif void dump_file(const char *fname) { int fd; struct stat sb; caddr_t objbase; if (stat(fname, &sb) == -1) { warnx("cannot stat \"%s\"", fname); ++error_count; return; } if ((sb.st_mode & S_IFMT) != S_IFREG) { warnx("\"%s\" is not a regular file", fname); ++error_count; return; } if ((fd = open(fname, O_RDONLY, 0)) == -1) { warnx("cannot open \"%s\"", fname); ++error_count; return; } objbase = mmap(0, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); if (objbase == (caddr_t) -1) { warnx("cannot mmap \"%s\"", fname); ++error_count; close(fd); return; } close(fd); file_base = (const char *) objbase; /* Makes address arithmetic easier */ if (IS_ELF(*(const Elf32_Ehdr*) align_struct(file_base))) { warnx("%s: this is an ELF program; use objdump to examine", fname); ++error_count; munmap(objbase, sb.st_size); return; } ex = (const struct exec *) align_struct(file_base); printf("%s: a_midmag = 0x%lx\n", fname, (long)ex->a_midmag); printf(" magic = 0x%lx = 0%lo, netmagic = 0x%lx = 0%lo\n", (long)N_GETMAGIC(*ex), (long)N_GETMAGIC(*ex), (long)N_GETMAGIC_NET(*ex), (long)N_GETMAGIC_NET(*ex)); if (N_BADMAG(*ex)) { warnx("%s: bad magic number", fname); ++error_count; munmap(objbase, sb.st_size); return; } printf(" a_text = 0x%lx\n", (long)ex->a_text); printf(" a_data = 0x%lx\n", (long)ex->a_data); printf(" a_bss = 0x%lx\n", (long)ex->a_bss); printf(" a_syms = 0x%lx\n", (long)ex->a_syms); printf(" a_entry = 0x%lx\n", (long)ex->a_entry); printf(" a_trsize = 0x%lx\n", (long)ex->a_trsize); printf(" a_drsize = 0x%lx\n", (long)ex->a_drsize); text_base = file_base + N_TXTOFF(*ex); data_base = file_base + N_DATOFF(*ex); rel_base = (const struct relocation_info *) align_struct(file_base + N_RELOFF(*ex)); sym_base = (const struct nlist *) align_struct(file_base + N_SYMOFF(*ex)); str_base = file_base + N_STROFF(*ex); rel_count = (ex->a_trsize + ex->a_drsize) / sizeof rel_base[0]; assert(rel_count * sizeof rel_base[0] == ex->a_trsize + ex->a_drsize); sym_count = ex->a_syms / sizeof sym_base[0]; assert(sym_count * sizeof sym_base[0] == ex->a_syms); if (sym_count != 0) { sym_used = (unsigned char *) calloc(sym_count, sizeof(unsigned char)); assert(sym_used != NULL); } printf(" Entry = 0x%lx\n", (long)ex->a_entry); printf(" Text offset = %x, address = %lx\n", N_TXTOFF(*ex), (long)N_TXTADDR(*ex)); printf(" Data offset = %lx, address = %lx\n", (long)N_DATOFF(*ex), (long)N_DATADDR(*ex)); /* * In an executable program file, everything is relocated relative to * the assumed run-time load address, i.e., N_TXTADDR(*ex), i.e., 0x1000. * * In a shared library file, everything is relocated relative to the * start of the file, i.e., N_TXTOFF(*ex), i.e., 0. * * The way to tell the difference is by looking at ex->a_entry. If it * is >= 0x1000, then we have an executable program. Otherwise, we * have a shared library. * * When a program is executed, the entire file is mapped into memory, * including the a.out header and so forth. But it is not mapped at * address 0; rather it is mapped at address 0x1000. The first page * of the user's address space is left unmapped in order to catch null * pointer dereferences. * * In this program, when we map in an executable program, we have to * simulate the empty page by decrementing our assumed base address by * a pagesize. */ text_addr = text_base; data_addr = data_base; origin = 0; if (ex->a_entry >= PAGE_SIZE) { /* Executable, not a shared library */ /* * The fields in the object have already been relocated on the * assumption that the object will be loaded at N_TXTADDR(*ex). * We have to compensate for that. */ text_addr -= PAGE_SIZE; data_addr -= PAGE_SIZE; origin = PAGE_SIZE; printf(" Program, origin = %lx\n", origin); } else if (N_GETFLAG(*ex) & EX_DYNAMIC) printf(" Shared library, origin = %lx\n", origin); else printf(" Object file, origin = %lx\n", origin); if (N_GETFLAG(*ex) & EX_DYNAMIC) { dyn = (const struct _dynamic *) align_struct(data_base); printf(" Dynamic version = %d\n", dyn->d_version); sdt = (const struct section_dispatch_table *) align_struct(text_addr + (unsigned long) dyn->d_un.d_sdt); rtrel_base = (const struct relocation_info *) align_struct(text_addr + sdt->sdt_rel); rtrel_count = (sdt->sdt_hash - sdt->sdt_rel) / sizeof rtrel_base[0]; assert(rtrel_count * sizeof rtrel_base[0] == (size_t)(sdt->sdt_hash - sdt->sdt_rel)); rtsym_base = (const struct nzlist *) align_struct(text_addr + sdt->sdt_nzlist); rtsym_count = (sdt->sdt_strings - sdt->sdt_nzlist) / sizeof rtsym_base[0]; assert(rtsym_count * sizeof rtsym_base[0] == (size_t)(sdt->sdt_strings - sdt->sdt_nzlist)); if (rtsym_count != 0) { rtsym_used = (unsigned char *) calloc(rtsym_count, sizeof(unsigned char)); assert(rtsym_used != NULL); } rtstr_base = text_addr + sdt->sdt_strings; } dump_segs(); dump_sods(); dump_rels("Relocations", rel_base, rel_count, sym_name, sym_used); dump_syms(); dump_rels("Run-time relocations", rtrel_base, rtrel_count, rtsym_name, rtsym_used); dump_rtsyms(); if (rtsym_used != NULL) { free(rtsym_used); rtsym_used = NULL; } if (sym_used != NULL) { free(sym_used); sym_used = NULL; } munmap(objbase, sb.st_size); }
void a_out_mod_symload(int strtablen) { struct exec info_buf; struct lmc_loadbuf ldbuf; struct nlist *nlp; char buf[10 * BUFSIZ]; char *symbuf; int bytesleft, sz; int numsyms; /* XXX unused? */ if (a_out_read_header(modfd, &info_buf) < 0) return; /* * Seek to the symbol table to start loading it... */ if (lseek(modfd, N_SYMOFF(info_buf), SEEK_SET) == -1) err(12, "lseek"); /* * Transfer the symbol table entries. First, read them all in, * then adjust their string table pointers, then * copy in bulk. Then copy the string table itself. */ symbuf = malloc(info_buf.a_syms); if (symbuf == 0) err(13, "malloc"); if (read(modfd, symbuf, info_buf.a_syms) != info_buf.a_syms) err(14, "read"); numsyms = info_buf.a_syms / sizeof(struct nlist); for (nlp = (struct nlist *)symbuf; (char *)nlp < symbuf + info_buf.a_syms; nlp++) { int strx; strx = nlp->n_un.n_strx; if (strx != 0) { /* * If a valid name, set the name ptr to point at the * loaded address for the string in the string table. */ if (strx > strtablen) nlp->n_un.n_name = 0; else nlp->n_un.n_name = (char *)(strx + resrv.sym_addr + info_buf.a_syms); } } /* * we've fixed the symbol table entries, now load them */ for (bytesleft = info_buf.a_syms; bytesleft > 0; bytesleft -= sz) { sz = MIN(bytesleft, MODIOBUF); ldbuf.cnt = sz; ldbuf.data = symbuf; if (ioctl(devfd, LMLOADSYMS, &ldbuf) == -1) err(11, "error transferring sym buffer"); symbuf += sz; } free(symbuf - info_buf.a_syms); /* and now read the string table and load it. */ for (bytesleft = strtablen; bytesleft > 0; bytesleft -= sz) { sz = MIN(bytesleft, MODIOBUF); read(modfd, buf, sz); ldbuf.cnt = sz; ldbuf.data = buf; if (ioctl(devfd, LMLOADSYMS, &ldbuf) == -1) err(11, "error transferring stringtable buffer"); } }
int main(int ac, char **av) { FILE *fin = NULL; struct exec *exhdr = NULL; char *fname = NULL; char *stringtable; int strtbl_sz; struct relocation_info *data_reloc = NULL, *text_reloc = NULL; struct nlist *symbol_table = NULL; int show_header = 0; int show_data_reloc = 0; int show_text_reloc = 0; int show_symbol_table = 0; int print_symnames = 1; int correspondence = 0; int hdr_info = 0; int opt; while (-1 != (opt = getopt(ac, av, "hdtsacxn"))) { switch (opt) { case 'h': show_header = 1; break; case 'x': show_header = hdr_info = 1; break; /* show_header implied */ case 'd': show_data_reloc = 1; break; case 't': show_text_reloc = 1; break; case 's': show_symbol_table = 1; break; case 'c': correspondence = 1; break; case 'n': print_symnames = 0; break; case 'a': show_header = show_data_reloc = show_text_reloc = show_symbol_table = correspondence = hdr_info = 1; break; default: errout: fprintf(stderr, "%s: show exec header, relocation and symbol table data\n", av[0]); fprintf(stderr, "usage: %s [-h] [-d] [-t] [-s] [-c] [-x] [-a] <filename>\n", av[0]); fprintf(stderr, " -h: show exec header\n" " -x: show info derivable from exec header \n" " -d: show data segment relocations\n" " -t: show text segment relocations\n" " -c: show symbols that correspond to relocations\n" " -s: show symbol table\n" " -n: when showing symbol table, don't print symbol names\n" " -a: show it all\n"); return 1; break; } } if (0 == show_header && 0 == show_data_reloc && 0 == show_text_reloc && 0 == show_symbol_table) show_header = show_data_reloc = show_text_reloc = show_symbol_table = correspondence = 1; if (optind < ac) fname = av[optind]; if (NULL == fname) { fprintf(stderr, "Need a file to examine\n"); goto errout; } if (NULL == (fin = fopen(fname, "r"))) { fprintf(stderr, "Couldn't open \"%s\" for reading: %s\n", fname, strerror(errno)); return 1; } if (stat(fname, &attributes) < 0) { fprintf(stderr, "Problem on stat(2) of \"%s\": %s\n", fname, strerror(errno)); fclose(fin); return 1; } exhdr = (struct exec *)read_extent(fin, sizeof(*exhdr), 0, __LINE__); if (NULL == exhdr) { cleanup(fin, 1, exhdr); return 2; } if (show_header) { puts("a.out header:"); run_header(exhdr, hdr_info); } if (N_BADMAG(*exhdr)) { fprintf(stderr, "%s isn't a recognized NetBSD a.out file\n", fname); cleanup(fin, 1, exhdr); return 3; } stringtable = read_stringtable(fin, exhdr, &strtbl_sz); data_reloc = (struct relocation_info *)read_extent(fin, exhdr->a_drsize, N_DRELOFF(*exhdr), __LINE__); text_reloc = (struct relocation_info *)read_extent(fin, exhdr->a_trsize, N_TRELOFF(*exhdr), __LINE__); symbol_table = (struct nlist *) read_extent(fin, exhdr->a_syms, N_SYMOFF(*exhdr), __LINE__); if (show_data_reloc) { puts("\nData relocations:"); run_reloc(exhdr, exhdr->a_drsize, data_reloc, symbol_table, stringtable, strtbl_sz, correspondence); } if (show_text_reloc) { puts("\nText relocations:"); run_reloc(exhdr, exhdr->a_trsize, text_reloc, symbol_table, stringtable, strtbl_sz, correspondence); } if (show_symbol_table) { puts("\nSymbol table:"); run_symtable(exhdr, symbol_table, stringtable, strtbl_sz, print_symnames); } cleanup(fin, 5, exhdr, stringtable, data_reloc, text_reloc, symbol_table); return 0; }
int util_save_image(char *orig_file_name, char *save_file_name) { int origFd = -1, saveFd = -1; char *start_data, *end_data, *start_text, *end_round; struct exec old_hdr, new_hdr; struct stat old_stat; int n, page_size, length_text, length_data; if ((origFd = open(orig_file_name, 0)) < 0) { perror(orig_file_name); (void) fprintf(stderr, "Cannot open original a.out file\n"); goto bad; } if (fstat(origFd, &old_stat) < 0) { perror(orig_file_name); (void) fprintf(stderr, "Cannot stat original a.out file\n"); goto bad; } /* * Read the a.out header from the original file. */ if (read(origFd, (char *) &old_hdr, sizeof(old_hdr)) != sizeof(old_hdr)) { perror(orig_file_name); (void) fprintf(stderr, "Cannot read original a.out header\n"); goto bad; } if (N_BADMAG(old_hdr)) { (void) fprintf(stderr, "File %s has a bad magic number (%o)\n", orig_file_name, old_hdr.a_magic); goto bad; } if (old_hdr.a_magic != ZMAGIC) { (void) fprintf(stderr, "File %s is not demand-paged\n", orig_file_name); goto bad; } /* * Open the output file. */ if (access(save_file_name, /* F_OK */ 0) == 0) { (void) unlink(save_file_name); } if ((saveFd = creat(save_file_name, 0777)) < 0) { if (errno == ETXTBSY) { (void) unlink(save_file_name); saveFd = creat(save_file_name, 0777); } if (saveFd < 0) { perror(save_file_name); (void) fprintf(stderr, "Cannot create save file.\n"); goto bad; } } /* * Find out how far the data segment extends. */ new_hdr = old_hdr; end_data = sbrk(0); page_size = getpagesize(); n = ((((int) end_data) + page_size - 1) / page_size) * page_size; end_round = (char *) n; if (end_round > end_data) { end_data = sbrk(end_round - end_data); } #ifdef vax start_text = 0; length_text = new_hdr.a_text; start_data = (char *) old_hdr.a_text; length_data = end_data - start_data; #endif vax #ifdef sun start_text = (char *) N_TXTADDR(old_hdr) + sizeof(old_hdr); length_text = old_hdr.a_text - sizeof(old_hdr); start_data = (char *) N_DATADDR(old_hdr); length_data = end_data - start_data; #endif sun new_hdr.a_data = end_data - start_data; new_hdr.a_bss = 0; /* * First, the header plus enough pad to extend up to N_TXTOFF. */ if (write(saveFd, (char *) &new_hdr, (int) sizeof(new_hdr)) != sizeof(new_hdr)) { perror("write"); (void) fprintf(stderr, "Error while copying header.\n"); goto bad; } if (! pad_file(saveFd, N_TXTOFF(old_hdr) - sizeof(new_hdr))) { (void) fprintf(stderr, "Error while padding.\n"); goto bad; } /* * Copy our text segment */ if (write(saveFd, start_text, length_text) != length_text) { perror("write"); (void) fprintf(stderr, "Error while copying text segment.\n"); goto bad; } /* * Copy our data segment */ if (write(saveFd, start_data, length_data) != length_data) { perror("write"); (void) fprintf(stderr, "Error while copying data segment.\n"); goto bad; } /* * Copy the symbol table and everything else. * This takes us to the end of the original file. */ (void) lseek(origFd, (long) N_SYMOFF(old_hdr), 0); if (! copy_file(origFd, saveFd, old_stat.st_size - N_SYMOFF(old_hdr))) { (void) fprintf(stderr, "Error while copying symbol table.\n"); goto bad; } (void) close(origFd); (void) close(saveFd); return 1; bad: if (origFd >= 0) (void) close(origFd); if (saveFd >= 0) (void) close(saveFd); return 0; }
static bfd_boolean aout_adobe_write_object_contents (bfd *abfd) { struct external_exec swapped_hdr; static struct external_segdesc sentinel[1]; /* Initialized to zero. */ asection *sect; bfd_size_type amt; exec_hdr (abfd)->a_info = ZMAGIC; /* Calculate text size as total of text sections, etc. */ exec_hdr (abfd)->a_text = 0; exec_hdr (abfd)->a_data = 0; exec_hdr (abfd)->a_bss = 0; exec_hdr (abfd)->a_trsize = 0; exec_hdr (abfd)->a_drsize = 0; for (sect = abfd->sections; sect; sect = sect->next) { if (sect->flags & SEC_CODE) { exec_hdr (abfd)->a_text += sect->size; exec_hdr (abfd)->a_trsize += sect->reloc_count * sizeof (struct reloc_std_external); } else if (sect->flags & SEC_DATA) { exec_hdr (abfd)->a_data += sect->size; exec_hdr (abfd)->a_drsize += sect->reloc_count * sizeof (struct reloc_std_external); } else if (sect->flags & SEC_ALLOC && !(sect->flags & SEC_LOAD)) exec_hdr (abfd)->a_bss += sect->size; } exec_hdr (abfd)->a_syms = bfd_get_symcount (abfd) * sizeof (struct external_nlist); exec_hdr (abfd)->a_entry = bfd_get_start_address (abfd); aout_adobe_swap_exec_header_out (abfd, exec_hdr (abfd), &swapped_hdr); amt = EXEC_BYTES_SIZE; if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 || bfd_bwrite (& swapped_hdr, amt, abfd) != amt) return FALSE; /* Now write out the section information. Text first, data next, rest afterward. */ for (sect = abfd->sections; sect; sect = sect->next) if (sect->flags & SEC_CODE) aout_adobe_write_section (abfd, sect); for (sect = abfd->sections; sect; sect = sect->next) if (sect->flags & SEC_DATA) aout_adobe_write_section (abfd, sect); for (sect = abfd->sections; sect; sect = sect->next) if (!(sect->flags & (SEC_CODE | SEC_DATA))) aout_adobe_write_section (abfd, sect); /* Write final `sentinel` section header (with type of 0). */ amt = sizeof (*sentinel); if (bfd_bwrite (sentinel, amt, abfd) != amt) return FALSE; /* Now write out reloc info, followed by syms and strings. */ if (bfd_get_symcount (abfd) != 0) { if (bfd_seek (abfd, (file_ptr) (N_SYMOFF (*exec_hdr (abfd))), SEEK_SET) != 0) return FALSE; if (! aout_32_write_syms (abfd)) return FALSE; if (bfd_seek (abfd, (file_ptr) (N_TRELOFF (*exec_hdr (abfd))), SEEK_SET) != 0) return FALSE; for (sect = abfd->sections; sect; sect = sect->next) if (sect->flags & SEC_CODE) if (!aout_32_squirt_out_relocs (abfd, sect)) return FALSE; if (bfd_seek (abfd, (file_ptr) (N_DRELOFF (*exec_hdr (abfd))), SEEK_SET) != 0) return FALSE; for (sect = abfd->sections; sect; sect = sect->next) if (sect->flags & SEC_DATA) if (!aout_32_squirt_out_relocs (abfd, sect)) return FALSE; } return TRUE; }
void run_header(struct exec *exhdr, int extended_info) { char *id = NULL; assert(NULL != exhdr); /* print raw values */ printf( "\ta_midmag 0x%08x (mid %d, magic 0%o, flag 0x%x)\n" "\ta_text 0x%08x\n" "\ta_data 0x%08x\n" "\ta_bss 0x%08x\n" "\ta_syms 0x%08x\n" "\ta_entry 0x%08x\n" "\ta_trsize 0x%08x\n" "\ta_drsize 0x%08x\n", exhdr->a_midmag, N_GETMID(*exhdr), N_GETMAGIC(*exhdr), N_GETFLAG(*exhdr), exhdr->a_text, exhdr->a_data, exhdr->a_bss, exhdr->a_syms, exhdr->a_entry, exhdr->a_trsize, exhdr->a_drsize ); printf( "magic number %04o: %s\n", N_GETMAGIC(*exhdr), N_GETMAGIC(*exhdr) == OMAGIC ? "old impure format" : N_GETMAGIC(*exhdr) == NMAGIC ? "read-only text" : N_GETMAGIC(*exhdr) == ZMAGIC ? "demand load format" : N_GETMAGIC(*exhdr) == QMAGIC ? "deprecated format" : "totally funky" ); switch (N_GETMID(*exhdr)) { case MID_ZERO: id = "unknown - implementation dependent"; break; case MID_SUN010: id = "sun 68010/68020 binary"; break; case MID_SUN020: id = "sun 68020-only binary"; break; case MID_PC386: id = "386 PC binary. (so quoth BFD)"; break; case MID_HP200: id = "hp200 (68010) BSD binary"; break; case MID_I386: id = "i386 BSD binary"; break; case MID_M68K: id = "m68k BSD binary with 8K page sizes"; break; case MID_M68K4K: id = "m68k BSD binary with 4K page sizes"; break; case MID_NS32532: id = "ns32532"; break; case MID_SPARC: id = "sparc"; break; case MID_PMAX: id = "pmax"; break; case MID_VAX: id = "vax"; break; case MID_ALPHA: id = "Alpha BSD binary"; break; case MID_MIPS: id = "big-endian MIPS"; break; case MID_ARM6: id = "ARM6"; break; case MID_HP300: id = "hp300 (68020+68881) BSD binary"; break; case MID_HPUX: id = "hp200/300 HP-UX binary"; break; case MID_HPUX800: id = "hp800 HP-UX binary"; break; default: id = "don't know"; break; } printf("type %d, %s\n", N_GETMID(*exhdr), id); /* this left shift seems a bit bogus */ switch((N_GETFLAG(*exhdr) & EX_DPMASK)>>4) { case 0: id = "traditional executable or object file"; break; case 1: id = "object file contains PIC code"; break; case 2: id = "dynamic executable"; break; case 3: id = "position independent executable image"; break; default: id = NULL; } if (NULL != id) printf("flags: 0x%x, %s\n", N_GETFLAG(*exhdr), id); else printf("flags: 0x%x\n", N_GETFLAG(*exhdr)); if (extended_info) { unsigned long txt_addr; unsigned long dat_addr; unsigned long bss_addr; /* N_TXTADDR and N_DATADDR macros DON'T WORK */ if (N_GETMAGIC(*exhdr) == ZMAGIC) { txt_addr = __LDPGSZ; dat_addr = ((txt_addr + exhdr->a_text + __LDPGSZ - 1) & ~(__LDPGSZ - 1)); } else if (N_GETMAGIC(*exhdr) == OMAGIC) { txt_addr = 0; dat_addr = txt_addr + exhdr->a_text; } else { txt_addr = 0xdeadbeef; dat_addr = 0xcafebabe; } bss_addr = dat_addr + exhdr->a_data; printf(" text segment size = 0x%lx, text segment file offset = %ld\n", exhdr->a_text, N_TXTOFF(*exhdr)); printf(" data segment size = 0x%lx, data segment file offset = %ld\n", exhdr->a_data, N_DATOFF(*exhdr)); printf(" bss segment size = 0x%lx\n", exhdr->a_bss); printf(" text segment relocation size = 0x%lx, file offset = %ld, %d text relocations\n", exhdr->a_trsize, N_TRELOFF(*exhdr), exhdr->a_trsize/sizeof(struct relocation_info)); printf(" data segment relocation size = 0x%lx, file offset = %ld, %d data relocations\n", exhdr->a_drsize, N_DRELOFF(*exhdr), exhdr->a_drsize/sizeof(struct relocation_info)); printf(" symbol table size = 0x%lx, symbol table file offset = %ld (%d symbols)\n", exhdr->a_syms, N_SYMOFF(*exhdr), exhdr->a_syms/sizeof(struct nlist)); printf(" string table file offset = 0x%lx (%d)\n", N_STROFF(*exhdr), N_STROFF(*exhdr)); printf(" entry point = 0x%lx\n", exhdr->a_entry); printf(" text address = 0x%lx\n\tdata address = 0x%lx\n" "\tbss address = 0x%lx\n", txt_addr, dat_addr, bss_addr /* N_TXTADDR(*exhdr), N_DATADDR(*exhdr), N_BSSADDR(*exhdr) */ ); } }
int hide_aout(int inf, const char *filename) { struct stat infstat; struct relocation_info *relp; struct nlist *symp; int rc; /* * do some error checking. */ if(fstat(inf, &infstat) == -1) { perror(filename); return 1; } /* * Read the entire file into memory. XXX - Really, we only need to * read the header and from TRELOFF to the end of the file. */ if((aoutdata = (char *) malloc(infstat.st_size)) == NULL) { fprintf(stderr, "%s: too big to read into memory\n", filename); return 1; } if((rc = read(inf, aoutdata, infstat.st_size)) < infstat.st_size) { fprintf(stderr, "%s: read error: %s\n", filename, rc == -1? strerror(errno) : "short read"); return 1; } /* * Calculate offsets and sizes from the header. */ hdrp = (struct exec *) aoutdata; #ifdef __FreeBSD__ textrel = (struct relocation_info *) (aoutdata + N_RELOFF(*hdrp)); datarel = (struct relocation_info *) (aoutdata + N_RELOFF(*hdrp) + hdrp->a_trsize); #else textrel = (struct relocation_info *) (aoutdata + N_TRELOFF(*hdrp)); datarel = (struct relocation_info *) (aoutdata + N_DRELOFF(*hdrp)); #endif symbase = (struct nlist *) (aoutdata + N_SYMOFF(*hdrp)); strbase = (char *) (aoutdata + N_STROFF(*hdrp)); ntextrel = hdrp->a_trsize / sizeof(struct relocation_info); ndatarel = hdrp->a_drsize / sizeof(struct relocation_info); nsyms = hdrp->a_syms / sizeof(struct nlist); /* * Zap the type field of all globally-defined symbols. The linker will * subsequently ignore these entries. Don't zap any symbols in the * keep list. */ for(symp = symbase; symp < symbase + nsyms; symp++) { if(!IS_GLOBAL_DEFINED(symp)) /* keep undefined syms */ continue; /* keep (C) symbols which are on the keep list */ if(SYMSTR(symp)[0] == '_' && in_keep_list(SYMSTR(symp) + 1)) continue; symp->n_type = 0; } /* * Check whether the relocation entries reference any symbols that we * just zapped. I don't know whether ld can handle this case, but I * haven't encountered it yet. These checks are here so that the program * doesn't fail silently should such symbols be encountered. */ for(relp = textrel; relp < textrel + ntextrel; relp++) check_reloc(filename, relp); for(relp = datarel; relp < datarel + ndatarel; relp++) check_reloc(filename, relp); /* * Write the .o file back out to disk. XXX - Really, we only need to * write the symbol table entries back out. */ lseek(inf, 0, SEEK_SET); if((rc = write(inf, aoutdata, infstat.st_size)) < infstat.st_size) { fprintf(stderr, "%s: write error: %s\n", filename, rc == -1? strerror(errno) : "short write"); return 1; } return 0; }
static ssize_t MSMachONameList_(const void *stuff, struct MSSymbolData *list, size_t nreq) { // XXX: ok, this is just pathetic; API fail much? size_t slide(0); for (uint32_t image(0), images(_dyld_image_count()); image != images; ++image) if (_dyld_get_image_header(image) == stuff) { slide = _dyld_get_image_vmaddr_slide(image); goto fat; } return -1; fat: const uint8_t *base(reinterpret_cast<const uint8_t *>(stuff)); const struct exec *buf(reinterpret_cast<const struct exec *>(base)); if (OSSwapBigToHostInt32(buf->a_magic) == FAT_MAGIC) { struct host_basic_info hbi; { host_t host(mach_host_self()); mach_msg_type_number_t count(HOST_BASIC_INFO_COUNT); if (host_info(host, HOST_BASIC_INFO, reinterpret_cast<host_info_t>(&hbi), &count) != KERN_SUCCESS) return -1; mach_port_deallocate(mach_task_self(), host); } const struct fat_header *fh(reinterpret_cast<const struct fat_header *>(base)); uint32_t nfat_arch(OSSwapBigToHostInt32(fh->nfat_arch)); const struct fat_arch *fat_archs(reinterpret_cast<const struct fat_arch *>(fh + 1)); for (uint32_t i(0); i != nfat_arch; ++i) if (static_cast<cpu_type_t>(OSSwapBigToHostInt32(fat_archs[i].cputype)) == hbi.cpu_type) { buf = reinterpret_cast<const struct exec *>(base + OSSwapBigToHostInt32(fat_archs[i].offset)); goto thin; } return -1; } thin: const nlist_xx *symbols; const char *strings; size_t n; // XXX: this check looks really scary when it fails if (buf->a_magic == MH_MAGIC_XX) { const mach_header_xx *mh(reinterpret_cast<const mach_header_xx *>(base)); const struct load_command *load_commands(reinterpret_cast<const struct load_command *>(mh + 1)); const struct symtab_command *stp(NULL); const struct load_command *lcp; /* forlc (command, mh, LC_SYMTAB, struct symtab_command) { stp = command; goto found; } */ lcp = load_commands; for (uint32_t i(0); i != mh->ncmds; ++i) { if ( lcp->cmdsize % sizeof(long) != 0 || lcp->cmdsize <= 0 || reinterpret_cast<const uint8_t *>(lcp) + lcp->cmdsize > reinterpret_cast<const uint8_t *>(load_commands) + mh->sizeofcmds ) return -1; if (lcp->cmd == LC_SYMTAB) { if (lcp->cmdsize != sizeof(struct symtab_command)) return -1; stp = reinterpret_cast<const struct symtab_command *>(lcp); goto found; } lcp = reinterpret_cast<const struct load_command *>(reinterpret_cast<const uint8_t *>(lcp) + lcp->cmdsize); } return -1; found: n = stp->nsyms; symbols = NULL; strings = NULL; /* forlc (command, mh, LC_SEGMENT_XX, segment_command_xx) { stp = command; goto found; } */ lcp = load_commands; for (uint32_t i(0); i != mh->ncmds; ++i) { if ( lcp->cmdsize % sizeof(long) != 0 || lcp->cmdsize <= 0 || reinterpret_cast<const uint8_t *>(lcp) + lcp->cmdsize > reinterpret_cast<const uint8_t *>(load_commands) + mh->sizeofcmds ) return -1; if (lcp->cmd == LC_SEGMENT_XX) { if (lcp->cmdsize < sizeof(segment_command_xx)) return -1; const segment_command_xx *segment(reinterpret_cast<const segment_command_xx *>(lcp)); if (stp->symoff >= segment->fileoff && stp->symoff < segment->fileoff + segment->filesize) symbols = reinterpret_cast<const nlist_xx *>(stp->symoff - segment->fileoff + segment->vmaddr + slide); if (stp->stroff >= segment->fileoff && stp->stroff < segment->fileoff + segment->filesize) strings = reinterpret_cast<const char *>(stp->stroff - segment->fileoff + segment->vmaddr + slide); } lcp = reinterpret_cast<const struct load_command *>(reinterpret_cast<const uint8_t *>(lcp) + lcp->cmdsize); } if (symbols == NULL || strings == NULL) return -1; // XXX: detect a.out somehow? } else if (false) { /* XXX: is this right anymore?!? */ symbols = reinterpret_cast<const nlist_xx *>(base + N_SYMOFF(*buf)); strings = reinterpret_cast<const char *>(reinterpret_cast<const uint8_t *>(symbols) + buf->a_syms); n = buf->a_syms / sizeof(nlist_xx); } else return -1; size_t result(nreq); for (size_t m(0); m != n; ++m) { const nlist_xx *q(&symbols[m]); if (q->n_un.n_strx == 0 || (q->n_type & N_STAB) != 0) continue; const char *nambuf(strings + q->n_un.n_strx); //fprintf(stderr, " == %s\n", nambuf); for (size_t item(0); item != nreq; ++item) { struct MSSymbolData *p(list + item); if (p->name_ == NULL || strcmp(p->name_, nambuf) != 0) continue; p->name_ = NULL; p->value_ = q->n_value; if (p->value_ != 0) p->value_ += slide; p->type_ = q->n_type; p->desc_ = q->n_desc; p->sect_ = q->n_sect; if (--result == 0) return 0; break; } } return result; }