/* * 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); }
/* * 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; }