int excluded(struct nlist *p) { char *nam; int x; if (p->n_type & N_STAB || p->n_un.n_strx == 0) return (0); if (p->n_un.n_strx < sizeof(int) || p->n_un.n_strx >= strtabsize) badfmt("corrupted symbol table"); nam = &strings[p->n_un.n_strx - sizeof(int)]; for (x = nexclude; --x >= 0; ) if (strcmp(nam, exclude[x]) == 0) return (1); return (0); }
int inlist(struct nlist *p) { char *nam; struct nlist *op; if (p->n_type & N_STAB || p->n_un.n_strx == 0) return (-1); if (p->n_un.n_strx < sizeof(int) || p->n_un.n_strx >= strtabsize) badfmt("corrupted symbol table"); nam = &strings[p->n_un.n_strx - sizeof(int)]; for (op = &order[nsym]; --op >= order; ) { if (strcmp(op->n_un.n_name, nam) != 0) continue; op->n_value = 1; return (op - order); } return (-1); }
/* * Compare the types in the NULL-terminated array ap with the format * string fmt. */ static void scanflike(hte_t *hte, fcall_t *call, int n, const char *fmt, type_t **ap) { const char *fp; int fc; int noasgn, fwidth; tspec_t sz, t1 = NOTSPEC, t2 = NOTSPEC; type_t *tp = NULL; fp = fmt; fc = *fp++; for ( ; ; ) { if (fc == '\0') { if (*ap != NULL) tomanyarg(hte, call); break; } if (fc != '%') { badfmt(hte, call); break; } fc = *fp++; noasgn = fwidth = 0; sz = NOTSPEC; if (fc == '*') { noasgn = 1; fc = *fp++; } if (isdigit(fc)) { fwidth = 1; do { fc = *fp++; } while (isdigit(fc)); } if (fc == 'h') { sz = SHORT; } else if (fc == 'l') { sz = LONG; } else if (fc == 'q') { sz = QUAD; } else if (fc == 'L') { sz = LDOUBLE; } if (sz != NOTSPEC) fc = *fp++; if (fc == '%') { if (sz != NOTSPEC || noasgn || fwidth) badfmt(hte, call); fc = *fp++; continue; } if (!noasgn) { if ((tp = *ap++) == NULL) { tofewarg(hte, call); break; } n++; if ((t1 = tp->t_tspec) == PTR) t2 = tp->t_subt->t_tspec; } if (fc == 'd' || fc == 'i' || fc == 'n') { if (sz == LDOUBLE) badfmt(hte, call); if (sz != SHORT && sz != LONG && sz != QUAD) sz = INT; conv: if (!noasgn) { if (t1 != PTR) { inconarg(hte, call, n); } else if (t2 != styp(sz)) { inconarg(hte, call, n); } else if (hflag && t2 != sz) { inconarg(hte, call, n); } else if (tp->t_subt->t_const) { inconarg(hte, call, n); } } } else if (fc == 'o' || fc == 'u' || fc == 'x') { if (sz == LDOUBLE) badfmt(hte, call); if (sz == SHORT) { sz = USHORT; } else if (sz == LONG) { sz = ULONG; } else if (sz == QUAD) { sz = UQUAD; } else { sz = UINT; } goto conv; } else if (fc == 'D') { if (sz != NOTSPEC || !tflag) badfmt(hte, call); sz = LONG; goto conv; } else if (fc == 'O') { if (sz != NOTSPEC || !tflag) badfmt(hte, call); sz = ULONG; goto conv; } else if (fc == 'X') { /* * XXX valid in ANSI C, but in NetBSD's libc imple- * mented as "lx". Thats why it should be avoided. */ if (sz != NOTSPEC || !tflag) badfmt(hte, call); sz = ULONG; goto conv; } else if (fc == 'E') { /* * XXX valid in ANSI C, but in NetBSD's libc imple- * mented as "lf". Thats why it should be avoided. */ if (sz != NOTSPEC || !tflag) badfmt(hte, call); sz = DOUBLE; goto conv; } else if (fc == 'F') { /* XXX only for backward compatibility */ if (sz != NOTSPEC || !tflag) badfmt(hte, call); sz = DOUBLE; goto conv; } else if (fc == 'G') { /* * XXX valid in ANSI C, but in NetBSD's libc not * implemented */ if (sz != NOTSPEC && sz != LONG && sz != LDOUBLE) badfmt(hte, call); goto fconv; } else if (fc == 'e' || fc == 'f' || fc == 'g') { fconv: if (sz == NOTSPEC) { sz = FLOAT; } else if (sz == LONG) { sz = DOUBLE; } else if (sz != LDOUBLE) { badfmt(hte, call); sz = FLOAT; } goto conv; } else if (fc == 's' || fc == '[' || fc == 'c') { if (sz != NOTSPEC) badfmt(hte, call); if (fc == '[') { if ((fc = *fp++) == '-') { badfmt(hte, call); fc = *fp++; } if (fc != ']') { badfmt(hte, call); if (fc == '\0') break; } } if (!noasgn) { if (t1 != PTR) { inconarg(hte, call, n); } else if (t2 != CHAR && t2 != UCHAR && t2 != SCHAR) { inconarg(hte, call, n); } } } else if (fc == 'p') { if (sz != NOTSPEC) badfmt(hte, call); if (!noasgn) { if (t1 != PTR || t2 != PTR) { inconarg(hte, call, n); } else if (tp->t_subt->t_subt->t_tspec!=VOID) { if (hflag) inconarg(hte, call, n); } } } else { badfmt(hte, call); break; } fc = *fp++; } }
/* * Compare the types in the NULL-terminated array ap with the format * string fmt. */ static void printflike(hte_t *hte, fcall_t *call, int n, const char *fmt, type_t **ap) { const char *fp; int fc; int fwidth, prec, left, sign, space, alt, zero; tspec_t sz, t1, t2 = NOTSPEC; type_t *tp; fp = fmt; fc = *fp++; for ( ; ; ) { if (fc == '\0') { if (*ap != NULL) tomanyarg(hte, call); break; } if (fc != '%') { badfmt(hte, call); break; } fc = *fp++; fwidth = prec = left = sign = space = alt = zero = 0; sz = NOTSPEC; /* Flags */ for ( ; ; ) { if (fc == '-') { if (left) break; left = 1; } else if (fc == '+') { if (sign) break; sign = 1; } else if (fc == ' ') { if (space) break; space = 1; } else if (fc == '#') { if (alt) break; alt = 1; } else if (fc == '0') { if (zero) break; zero = 1; } else { break; } fc = *fp++; } /* field width */ if (isdigit(fc)) { fwidth = 1; do { fc = *fp++; } while (isdigit(fc)) ; } else if (fc == '*') { fwidth = 1; fc = *fp++; if ((tp = *ap++) == NULL) { tofewarg(hte, call); break; } n++; if ((t1 = tp->t_tspec) != INT && (hflag || t1 != UINT)) inconarg(hte, call, n); } /* precision */ if (fc == '.') { fc = *fp++; prec = 1; if (isdigit(fc)) { do { fc = *fp++; } while (isdigit(fc)); } else if (fc == '*') { fc = *fp++; if ((tp = *ap++) == NULL) { tofewarg(hte, call); break; } n++; if (tp->t_tspec != INT) inconarg(hte, call, n); } else { badfmt(hte, call); break; } } if (fc == 'h') { sz = SHORT; } else if (fc == 'l') { sz = LONG; } else if (fc == 'q') { sz = QUAD; } else if (fc == 'L') { sz = LDOUBLE; } if (sz != NOTSPEC) fc = *fp++; if (fc == '%') { if (sz != NOTSPEC || left || sign || space || alt || zero || prec || fwidth) { badfmt(hte, call); } fc = *fp++; continue; } if (fc == '\0') { badfmt(hte, call); break; } if ((tp = *ap++) == NULL) { tofewarg(hte, call); break; } n++; if ((t1 = tp->t_tspec) == PTR) t2 = tp->t_subt->t_tspec; if (fc == 'd' || fc == 'i') { if (alt || sz == LDOUBLE) { badfmt(hte, call); break; } int_conv: if (sz == LONG) { if (t1 != LONG && (hflag || t1 != ULONG)) inconarg(hte, call, n); } else if (sz == QUAD) { if (t1 != QUAD && (hflag || t1 != UQUAD)) inconarg(hte, call, n); } else { /* * SHORT is always promoted to INT, USHORT * to INT or UINT. */ if (t1 != INT && (hflag || t1 != UINT)) inconarg(hte, call, n); } } else if (fc == 'o' || fc == 'u' || fc == 'x' || fc == 'X') { if ((alt && fc == 'u') || sz == LDOUBLE) badfmt(hte, call); uint_conv: if (sz == LONG) { if (t1 != ULONG && (hflag || t1 != LONG)) inconarg(hte, call, n); } else if (sz == QUAD) { if (t1 != UQUAD && (hflag || t1 != QUAD)) inconarg(hte, call, n); } else if (sz == SHORT) { /* USHORT was promoted to INT or UINT */ if (t1 != UINT && t1 != INT) inconarg(hte, call, n); } else { if (t1 != UINT && (hflag || t1 != INT)) inconarg(hte, call, n); } } else if (fc == 'D' || fc == 'O' || fc == 'U') { if ((alt && fc != 'O') || sz != NOTSPEC || !tflag) badfmt(hte, call); sz = LONG; if (fc == 'D') { goto int_conv; } else { goto uint_conv; } } else if (fc == 'f' || fc == 'e' || fc == 'E' || fc == 'g' || fc == 'G') { if (sz == NOTSPEC) sz = DOUBLE; if (sz != DOUBLE && sz != LDOUBLE) badfmt(hte, call); if (t1 != sz) inconarg(hte, call, n); } else if (fc == 'c') { if (sz != NOTSPEC || alt || zero) badfmt(hte, call); if (t1 != INT) inconarg(hte, call, n); } else if (fc == 's') { if (sz != NOTSPEC || alt || zero) badfmt(hte, call); if (t1 != PTR || (t2 != CHAR && t2 != UCHAR && t2 != SCHAR)) { inconarg(hte, call, n); } } else if (fc == 'p') { if (fwidth || prec || sz != NOTSPEC || alt || zero) badfmt(hte, call); if (t1 != PTR || (hflag && t2 != VOID)) inconarg(hte, call, n); } else if (fc == 'n') { if (fwidth || prec || alt || zero || sz == LDOUBLE) badfmt(hte, call); if (t1 != PTR) { inconarg(hte, call, n); } else if (sz == LONG) { if (t2 != LONG && t2 != ULONG) inconarg(hte, call, n); } else if (sz == SHORT) { if (t2 != SHORT && t2 != USHORT) inconarg(hte, call, n); } else { if (t2 != INT && t2 != UINT) inconarg(hte, call, n); } } else { badfmt(hte, call); break; } fc = *fp++; } }
void add(const char *fmt) { const char *p; static FS **nextfs; FS *tfs; FU *tfu, **nextfu; const char *savep; /* start new linked list of format units */ tfs = ecalloc(1, sizeof(FS)); if (!fshead) fshead = tfs; else *nextfs = tfs; nextfs = &tfs->nextfs; nextfu = &tfs->nextfu; /* take the format string and break it up into format units */ for (p = fmt;;) { /* skip leading white space */ for (; isspace((unsigned char)*p); ++p); if (!*p) break; /* allocate a new format unit and link it in */ tfu = ecalloc(1, sizeof(FU)); *nextfu = tfu; nextfu = &tfu->nextfu; tfu->reps = 1; /* if leading digit, repetition count */ if (isdigit((unsigned char)*p)) { for (savep = p; isdigit((unsigned char)*p); ++p); if (!isspace((unsigned char)*p) && *p != '/') badfmt(fmt); /* may overwrite either white space or slash */ tfu->reps = atoi(savep); tfu->flags = F_SETREP; /* skip trailing white space */ for (++p; isspace((unsigned char)*p); ++p); } /* skip slash and trailing white space */ if (*p == '/') while (isspace((unsigned char)*++p)); /* byte count */ if (isdigit((unsigned char)*p)) { for (savep = p; isdigit((unsigned char)*p); ++p); if (!isspace((unsigned char)*p)) badfmt(fmt); tfu->bcnt = atoi(savep); /* skip trailing white space */ for (++p; isspace((unsigned char)*p); ++p); } /* format */ if (*p != '"') badfmt(fmt); for (savep = ++p; *p != '"';) if (*p++ == 0) badfmt(fmt); tfu->fmt = emalloc(p - savep + 1); (void) strncpy(tfu->fmt, savep, p - savep); tfu->fmt[p - savep] = '\0'; escape(tfu->fmt); p++; } }
/* * 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); }
jac0dim_ASL(ASL *asl, char *stub, ftnlen stub_len) #endif { FILE *nl; int i, k, nlv; char *s, *se; const char *opfmt; EdRead ER, *R; if (!asl) badasl_ASL(asl,0,"jac0dim"); fpinit_ASL(); /* get IEEE arithmetic, if possible */ if (stub_len <= 0) for(i = 0; stub[i]; i++); else for(i = stub_len; stub[i-1] == ' ' && i > 0; --i); filename = (char *)M1alloc(i + 5); s = stub_end = filename + i; strncpy(filename, stub, i); strcpy(s, ".nl"); nl = fopen(filename, "rb"); if (!nl && i > 3 && !strncmp(s-3, ".nl", 3)) { *s = 0; stub_end = s - 3; nl = fopen(filename, "rb"); } if (!nl) { if (return_nofile) return 0; fflush(stdout); what_prog(); fprintf(Stderr, "can't open %s\n", filename); exit(1); } R = EdReadInit_ASL(&ER, asl, nl, 0); R->Line = 0; s = read_line(R); binary_nl = 0; opfmt = "%d"; switch(*s) { #ifdef DEPRECATED case 'E': /* deprecated "-oe" format */ {int ncsi = 0; k = Sscanf(s, "E%d %d %d %d %d %d", &n_var, &n_con, &n_obj, &maxrownamelen, &maxcolnamelen, &ncsi); if (k < 5) badints(R, k, 5); if (ncsi) { if (ncsi != 6) { badread(R); fprintf(Stderr, "expected 6th integer to be 0 or 6, not %d\n", ncsi); exit(1); } s = read_line(R); k = Sscanf(s, " %d %d %d %d %d %d", &comb, &comc, &como, &comc1, &como1, &nfunc); if (k != 6) badints(R, k, 6); } } break; #endif case 'z': case 'Z': opfmt = "%hd"; case 'B': case 'b': binary_nl = 1; xscanf = bscanf; goto have_xscanf; case 'h': case 'H': opfmt = "%hd"; binary_nl = 1; xscanf = hscanf; goto have_xscanf; case 'G': case 'g': xscanf = ascanf; have_xscanf: if ((k = ampl_options[0] = strtol(++s, &se, 10))) { if (k > 9) { fprintf(Stderr, "ampl_options = %d is too large\n", k); exit(1); } for(i = 1; i <= k && se > s; i++) ampl_options[i] = strtol(s = se,&se,10); if (ampl_options[2] == 3) ampl_vbtol = strtod(s = se, &se); } s = read_line(R); n_eqn = -1; k = Sscanf(s, " %d %d %d %d %d %d", &n_var, &n_con, &n_obj, &nranges, &n_eqn, &n_lcon); if (k < 3) badints(R,k,3); nclcon = n_con + n_lcon; /* formerly read2(R, &nlc, &nlo); */ s = read_line(R); n_cc = nlcc = ndcc = nzlb = 0; k = Sscanf(s, " %d %d %d %d %d %d", &nlc, &nlo, &n_cc, &nlcc, &ndcc, &nzlb); if (k < 2) badints(R,k,2); if ((n_cc += nlcc) > 0 && k < 6) ndcc = -1; /* indicate unknown */ read2(R, &nlnc, &lnc); nlvb = -1; s = read_line(R); k = Sscanf(s, " %d %d %d", &nlvc, &nlvo, &nlvb); if (k < 2) badints(R,k,2); /* read2(R, &nwv, &nfunc); */ s = read_line(R); asl->i.flags = 0; k = Sscanf(s, " %d %d %d %d", &nwv, &nfunc, &i, &asl->i.flags); if (k < 2) badints(R,k,2); else if (k >= 3 && i != Arith_Kind_ASL && i) { #ifdef Want_bswap if (i > 0 && i + Arith_Kind_ASL == 3) { asl->i.iadjfcn = asl->i.dadjfcn = bswap_ASL; binary_nl = i << 1; } else #endif badfmt(R); } if (nlvb < 0) /* ampl versions < 19930630 */ read2(R, &nbv, &niv); else { s = read_line(R); k = Sscanf(s, " %d %d %d %d %d", &nbv, &niv, &nlvbi, &nlvci, &nlvoi); if (k != 5) badints(R,k,5); } /* formerly read2(R, &nzc, &nzo); */ s = read_line(R); k = Sscanf(s, " %D %D", &nZc, &nZo); if (k != 2) badints(R, k, 2); nzc = nZc; nzo = nZo; read2(R, &maxrownamelen, &maxcolnamelen); s = read_line(R); k = Sscanf(s, " %d %d %d %d %d", &comb, &comc, &como, &comc1, &como1); if (k != 5) badints(R,k,5); } student_check_ASL(asl); if (n_con < 0 || n_var <= 0 || n_obj < 0) { what_prog(); fprintf(Stderr, "jacdim: got M = %d, N = %d, NO = %d\n", n_con, n_var, n_obj); exit(1); } asl->i.opfmt = opfmt; asl->i.n_var0 = asl->i.n_var1 = n_var; asl->i.n_con0 = asl->i.n_con1 = n_con; if ((nlv = nlvc) < nlvo) nlv = nlvo; if (nlv <= 0) nlv = 1; x0len = nlv * sizeof(real); x0kind = ASL_first_x; n_conjac[0] = 0; n_conjac[1] = n_con; c_vars = o_vars = n_var; /* confusion arises otherwise */ return nl; }
/* * 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); }