diff options
Diffstat (limited to 'src/libmach/sym.c')
-rw-r--r-- | src/libmach/sym.c | 478 |
1 files changed, 478 insertions, 0 deletions
diff --git a/src/libmach/sym.c b/src/libmach/sym.c new file mode 100644 index 00000000..7953019b --- /dev/null +++ b/src/libmach/sym.c @@ -0,0 +1,478 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <mach.h> + +int machdebug = 0; + +Fhdr *fhdrlist; +static Fhdr *last; + +static void +relocsym(Symbol *dst, Symbol *src, ulong base) +{ + if(dst != src) + *dst = *src; + if(dst->loc.type == LADDR) + dst->loc.addr += base; + if(dst->hiloc.type == LADDR) + dst->hiloc.addr += base; +} + +void +_addhdr(Fhdr *h) +{ + h->next = nil; + if(fhdrlist == nil){ + fhdrlist = h; + last = h; + }else{ + last->next = h; + last = h; + } +} + +void +_delhdr(Fhdr *h) +{ + Fhdr *p; + + if(h == fhdrlist) + fhdrlist = h->next; + else{ + for(p=fhdrlist; p && p->next!=h; p=p->next) + ; + if(p) + p->next = h->next; + if(p->next == nil) + last = p; + } + h->next = nil; +} + +int +pc2file(ulong pc, char *file, uint nfile, ulong *line) +{ + Fhdr *p; + + for(p=fhdrlist; p; p=p->next) + if(p->pc2file && p->pc2file(p, pc-p->base, file, nfile, line) >= 0) + return 0; + werrstr("no source file for 0x%lux", pc); + return -1; +} + +int +pc2line(ulong pc, ulong *line) +{ + char tmp[10]; /* just in case */ + return pc2file(pc, tmp, sizeof tmp, line); +} + +int +file2pc(char *file, ulong line, ulong *addr) +{ + Fhdr *p; + + for(p=fhdrlist; p; p=p->next) + if(p->file2pc && p->file2pc(p, file, line, addr) >= 0){ + *addr += p->base; + return 0; + } + werrstr("no instructions at %s:%lud", file, line); + return -1; +} + +int +line2pc(ulong basepc, ulong line, ulong *pc) +{ + Fhdr *p; + + for(p=fhdrlist; p; p=p->next) + if(p->line2pc && p->line2pc(p, basepc-p->base, line, pc) >= 0){ + *pc += p->base; + return 0; + } + werrstr("no instructions on line %lud", line); + return -1; +} + +int +fnbound(ulong pc, ulong *bounds) +{ + Fhdr *p; + Loc l; + Symbol *s; + + for(p=fhdrlist; p; p=p->next){ + l = locaddr(pc - p->base); + if((s = ffindsym(p, l, CANY)) != nil){ + if(s->loc.type != LADDR){ + werrstr("function %s has weird location %L", s->name, s->loc); + return -1; + } + bounds[0] = s->loc.addr + p->base; + if(s->hiloc.type != LADDR){ + werrstr("can't find upper bound for function %s", s->name); + return -1; + } + bounds[1] = s->hiloc.addr + p->base; + return 0; + } + } + werrstr("no function contains 0x%lux", pc); + return -1; +} + +int +fileline(ulong pc, char *a, uint n) +{ + ulong line; + + if(pc2file(pc, a, n, &line) < 0) + return -1; + seprint(a+strlen(a), a+n, ":%lud", line); + return 0; +} + +Symbol* +flookupsym(Fhdr *fhdr, char *name) +{ + Symbol **a, *t; + uint n, m; + int i; + + a = fhdr->byname; + n = fhdr->nsym; + if(a == nil) + return nil; + + while(n > 0){ + m = n/2; + t = a[m]; + i = strcmp(name, t->name); + if(i < 0) + n = m; + else if(i > 0){ + n -= m+1; + a += m+1; + }else{ + /* found! */ + m += a - fhdr->byname; + a = fhdr->byname; + assert(strcmp(name, a[m]->name) == 0); + while(m > 0 && strcmp(name, a[m-1]->name) == 0) + m--; + return a[m]; + } + } + return nil; +} + +int +lookupsym(char *fn, char *var, Symbol *s) +{ + Symbol *t, s1; + Fhdr *p; + char *nam; + + nam = fn ? fn : var; + if(nam == nil) + return -1; + t = nil; + for(p=fhdrlist; p; p=p->next) + if((t=flookupsym(p, nam)) != nil){ + relocsym(&s1, t, p->base); + break; + } + if(t == nil) + goto err; + if(fn && var) + return lookuplsym(&s1, var, s); + *s = s1; + return 0; + +err: + werrstr("unknown symbol %s%s%s", fn ? fn : "", + fn && var ? ":" : "", var ? var : ""); + return -1; +} + +int +findexsym(Fhdr *fp, uint i, Symbol *s) +{ + if(i >= fp->nsym) + return -1; + relocsym(s, &fp->sym[i], fp->base); + return 0; +} + +int +indexsym(uint ndx, Symbol *s) +{ + uint t; + Fhdr *p; + + for(p=fhdrlist; p; p=p->next){ + t = p->nsym; + if(t < ndx) + ndx -= t; + else{ + relocsym(s, &p->sym[ndx], p->base); + return 0; + } + } + return -1; +} + +Symbol* +ffindsym(Fhdr *fhdr, Loc loc, uint class) +{ + Symbol *a, *t; + int n, i, hi, lo; + int cmp; + + a = fhdr->sym; + n = fhdr->nsym; + if(a == nil || n <= 0) + return nil; + + /* + * We have a list of possibly duplicate locations in a. + * We want to find the largest index i such that + * a[i] <= loc. This cannot be done with a simple + * binary search. Instead we binary search to find + * where the location should be. + */ + lo = 0; + hi = n; + while(lo < hi){ + i = (lo+hi)/2; + cmp = loccmp(&loc, &a[i].loc); + if(cmp < 0) /* loc < a[i].loc */ + hi = i; + if(cmp > 0) /* loc > a[i].loc */ + lo = i+1; + if(cmp == 0) + goto found; + } + + /* found position where value would go, but not there -- go back one */ + if(lo == 0) + return nil; + i = lo-1; + +found: + /* + * might be in a run of all-the-same -- go back to beginning of run. + * if runs were long, could binary search for a[i].loc instead. + */ + while(i > 0 && loccmp(&a[i-1].loc, &a[i].loc) == 0) + i--; + + t = &a[i]; + if(t->hiloc.type && loccmp(&loc, &t->hiloc) >= 0) + return nil; + if(class != CANY && class != t->class) + return nil; + return t; +} + +int +findsym(Loc loc, uint class, Symbol *s) +{ + Fhdr *p, *bestp; + Symbol *t, *best; + long bestd, d; + Loc l; + + l = loc; + best = nil; + bestp = nil; + bestd = 0; + for(p=fhdrlist; p; p=p->next){ + if(l.type == LADDR) + l.addr = loc.addr - p->base; + if((t = ffindsym(p, l, CANY)) != nil){ + d = l.addr - t->loc.addr; + if(d < 4096) + if(best == nil || d < bestd){ + best = t; + bestp = p; + bestd = d; + } + } + } + if(best){ + if(class != CANY && class != best->class) + goto err; + relocsym(s, best, bestp->base); + return 0; + } +err: + werrstr("could not find symbol at %L", loc); + return -1; +} + +int +lookuplsym(Symbol *s1, char *name, Symbol *s2) +{ + Fhdr *p; + + p = s1->fhdr; + if(p->lookuplsym && p->lookuplsym(p, s1, name, s2) >= 0){ + relocsym(s2, s2, p->base); + return 0; + } + return -1; +} + +int +indexlsym(Symbol *s1, uint ndx, Symbol *s2) +{ + Fhdr *p; + + p = s1->fhdr; + if(p->indexlsym && p->indexlsym(p, s1, ndx, s2) >= 0){ + relocsym(s2, s2, p->base); + return 0; + } + return -1; +} + +int +findlsym(Symbol *s1, Loc loc, Symbol *s2) +{ + Fhdr *p; + + p = s1->fhdr; + if(p->findlsym && p->findlsym(p, s1, loc, s2) >= 0){ + relocsym(s2, s2, p->base); + return 0; + } + return -1; +} + +int +unwindframe(Map *map, Regs *regs, ulong *next) +{ + Fhdr *p; + + for(p=fhdrlist; p; p=p->next) + if(p->unwind && p->unwind(p, map, regs, next) >= 0) + return 0; + if(mach->unwind && mach->unwind(map, regs, next) >= 0) + return 0; + return -1; +} + +int +symoff(char *a, uint n, ulong addr, uint class) +{ + Loc l; + Symbol s; + + l.type = LADDR; + l.addr = addr; + if(findsym(l, class, &s) < 0 || addr-s.loc.addr >= 4096){ + snprint(a, n, "%lux", addr); + return -1; + } + if(addr != s.loc.addr) + snprint(a, n, "%s+%ld", s.name, addr-s.loc.addr); + else + snprint(a, n, "%s", s.name); + return 0; +} + +/* location, class, name */ +static int +byloccmp(const void *va, const void *vb) +{ + int i; + Symbol *a, *b; + + a = (Symbol*)va; + b = (Symbol*)vb; + i = loccmp(&a->loc, &b->loc); + if(i != 0) + return i; + i = a->class - b->class; + if(i != 0) + return i; + return strcmp(a->name, b->name); +} + +/* name, location, class */ +static int +bynamecmp(const void *va, const void *vb) +{ + int i; + Symbol *a, *b; + + a = *(Symbol**)va; + b = *(Symbol**)vb; + i = strcmp(a->name, b->name); + if(i != 0) + return i; + i = loccmp(&a->loc, &b->loc); + if(i != 0) + return i; + return a->class - b->class; +} + +int +syminit(Fhdr *hdr) +{ + int i; + Symbol *r, *w, *es; + + if(hdr->syminit == nil){ + werrstr("no debugging symbols"); + return -1; + } + if(hdr->syminit(hdr) < 0) + return -1; + + qsort(hdr->sym, hdr->nsym, sizeof(hdr->sym[0]), byloccmp); + es = hdr->sym+hdr->nsym; + for(r=w=hdr->sym; r<es; r++){ + if(w > hdr->sym + && strcmp((w-1)->name, r->name) ==0 + && loccmp(&(w-1)->loc, &r->loc) == 0){ + /* skip it */ + }else + *w++ = *r; + } + hdr->nsym = w - hdr->sym; + + hdr->byname = malloc(hdr->nsym*sizeof(hdr->byname[0])); + if(hdr->byname == nil){ + fprint(2, "could not allocate table to sort by location\n"); + }else{ + for(i=0; i<hdr->nsym; i++) + hdr->byname[i] = &hdr->sym[i]; + qsort(hdr->byname, hdr->nsym, sizeof(hdr->byname[0]), bynamecmp); + } + return 0; +} + +Symbol* +addsym(Fhdr *fp, Symbol *sym) +{ + Symbol *s; + + if(fp->nsym%128 == 0){ + s = realloc(fp->sym, (fp->nsym+128)*sizeof(fp->sym[0])); + if(s == nil) + return nil; + fp->sym = s; + } + if(machdebug) + fprint(2, "sym %s %c %L\n", sym->name, sym->type, sym->loc); + sym->fhdr = fp; + s = &fp->sym[fp->nsym++]; + *s = *sym; + return s; +} + |