aboutsummaryrefslogtreecommitdiff
path: root/src/libmach/sym.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libmach/sym.c')
-rw-r--r--src/libmach/sym.c478
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;
+}
+