Esempio n. 1
0
int
dwarfnextsymat(Dwarf *d, DwarfSym *parent, DwarfSym *child)
{
    uint sib;

    if (!parent->attrs.haskids || !parent->childoff)
        return -1;

	child->unit = parent->unit;
    child->aoff = parent->aoff;
    child->depth = parent->depth + 1;
    if(child->attrs.have.sibling){
        sib = child->attrs.sibling;
        if(sib < d->info.len && d->info.data+sib > child->b.p)
            child->b.p = d->info.data+sib;
        else if (sib >= d->info.len) {
            werrstr("sibling reported as out of bounds %d vs %d", sib, d->info.len);
            return -1;
        } else if (d->info.data+sib+parent->unit < child->b.p) {
            werrstr("subsequent sibling is listed before prev %d vs %d", sib+parent->unit, child->b.p - d->info.data);
            return -1;
        }
    }

    // Uninitialized
    if (!child->b.d) {
        child->b = parent->b;
        child->b.p = parent->childoff + parent->b.d->info.data;
        werrstr("Rewound to childoff %x\n", parent->childoff);
    }

    return dwarfnextsym(d, child);
}
Esempio n. 2
0
static int
_dwarfnametounit(Dwarf *d, char *name, DwarfBlock *bl, DwarfSym *s)
{
	int vers;
	ulong len, unit, off;
	uchar *next;
	char *str;
	DwarfBuf b;

	b.d = d;
	b.p = bl->data;
	b.ep = b.p + bl->len;

	while(b.p < b.ep){
		len = dwarfget4(&b);
		if(len > b.ep-b.p){
			werrstr("bad length in dwarf name header");
			return -1;
		}
		next = b.p + len;
		vers = dwarfget2(&b);
		if(vers != 1 && vers != 2){
			werrstr("bad version %d in dwarf name header", vers);
			return -1;
		}
		unit = dwarfget4(&b);
		dwarfget4(&b);	/* unit length */
		while(b.p < next){
			off = dwarfget4(&b);
			if(off == 0)
				break;
			str = dwarfgetstring(&b);
			if(strcmp(str, name) == 0){
				if(dwarfenumunit(d, unit, s) < 0)
					return -1;
				if(unit + off >= s->b.ep - d->info.data){
					werrstr("bad offset in name entry");
					return -1;
				}
				s->b.p = d->info.data + unit + off;
				if(dwarfnextsym(d, s) < 0)
					return -1;
				if(s->attrs.name==nil || strcmp(s->attrs.name, name)!=0){
					werrstr("unexpected name %#q in lookup for %#q", s->attrs.name, name);
					return -1;
				}
				return 0;
			}
		}
		b.p = next;
	}
	werrstr("unknown name '%s'", name);
	return -1;
}
Esempio n. 3
0
int
dwarflookupchildtag(Dwarf *d, DwarfSym *parent, ulong tag, DwarfSym *s)
{
    int rsym = dwarfnextsymat(d, parent, s);
    while (rsym == 0 && s->attrs.tag != tag) {
        if (s->attrs.haskids) {
            DwarfSym p = *s;
            int csym = dwarflookupchildtag(d, &p, tag, s);
            if (csym == 0) {
                return csym;
            }
        }
        rsym = dwarfnextsym(d, s);
    }
    return rsym;
}
Esempio n. 4
0
int
dwarflookuptag(Dwarf *d, ulong unit, ulong tag, DwarfSym *s)
{
    DwarfSym compunit = { };
    if (dwarfenumunit(d, unit, &compunit) < 0) {
        return -1;
    }
    do {
        if (compunit.attrs.tag == tag) {
            *s = compunit;
            return 0;
        }
        if (dwarflookupchildtag(d, &compunit, tag, s) == 0)
            return 0;
    } while(dwarfnextsym(d, &compunit) == 0);
    werrstr("symbol with tag 0x%lux not found", tag);
    return -1;
}
Esempio n. 5
0
int
dwarfnextsym(Dwarf *d, DwarfSym *s)
{
    ulong num;
    DwarfAbbrev *a;

    werrstr("sym at %x (left %x)\n", s->b.p - d->info.data, s->b.ep - s->b.p);

    num = dwarfget128(&s->b);
    werrstr("abbrev num %x\n", num);
    s->num = num;
    if(num == 0){
        return -1;
    }

    a = dwarfgetabbrev(d, s->aoff, num);
    werrstr("a %p\n", a);
    if(a == nil){
        werrstr("getabbrev %x %x for %x", s->aoff, num, s->unit);
        return -1;
    }

    if(parseattrs(d, &s->b, s->attrs.tag, s->unit, a, &s->attrs) < 0) {
        return -1;
    }

    if (s->attrs.haskids) {
        DwarfSym childSkip = { };
        s->childoff = s->b.p - d->info.data;
        werrstr("Set childoff at %x\n", s->childoff);
        int r = dwarfnextsymat(d, s, &childSkip);
        while (r == 0) {
            r = dwarfnextsym(d, &childSkip);
        }
        s->b = childSkip.b;
    } else {
        s->childoff = 0;
    }
    return 0;
}
Esempio n. 6
0
int
dwarfenumunit(Dwarf *d, ulong unit, DwarfSym *s)
{
    int i;
    ulong aoff, len;

    if(unit >= d->info.len){
        werrstr("dwarf unit address 0x%x >= 0x%x out of range", unit, d->info.len);
        return -1;
    }
    memset(s, 0, sizeof *s);
    memset(&s->b, 0, sizeof s->b);

    s->b.d = d;
    s->b.p = d->info.data + unit;
    s->b.ep = d->info.data + d->info.len;
    len = dwarfget4(&s->b);
	s->unit = unit;
    s->nextunit = unit + 4 + len;
    s->b.ep = d->info.data + s->nextunit;

    if(s->b.ep - s->b.p < len){
    badheader:
        werrstr("bad dwarf unit header at unit 0x%lux end %x start %x len %x", unit, s->b.ep - d->info.data, s->b.p - d->info.data, len);
        return -1;
    }
    s->b.ep = s->b.p+len;
    if((i=dwarfget2(&s->b)) > 4)
        goto badheader;
    aoff = dwarfget4(&s->b);
    s->b.addrsize = dwarfget1(&s->b);
    if(d->addrsize == 0)
        d->addrsize = s->b.addrsize;
    if(s->b.p == nil)
        goto badheader;

    s->aoff = aoff;

    return dwarfnextsym(d, s);
}
Esempio n. 7
0
void
main(int argc, char **argv)
{
	int c;
	Pe *pe;
	Dwarf *d;
	DwarfSym s;
	char *cdir, *dir, *file;
	ulong line, mtime, length;

	if(argc != 2)
		usage();

#if 0
	fmtinstall('R', exprfmt);
	fmtinstall('H', encodefmt);
#endif

	if((pe = peopen(argv[1])) == nil)
		sysfatal("elfopen %s: %r", argv[1]);
	if((d=dwarfopen(pe)) == nil)
		sysfatal("dwarfopen: %r");

	if(dwarfenum(d, &s) < 0)
		sysfatal("dwarfenumall: %r");

	while(dwarfnextsym(d, &s) == 1){
		switch(s.attrs.tag){
		case TagCompileUnit:
			print("compileunit %s\n", s.attrs.name);
			break;
		case TagSubprogram:
			c = 't';
			goto sym;
		case TagVariable:
			c = 'd';
			goto sym;
		case TagConstant:
			c = 'c';
			goto sym;
		case TagFormalParameter:
			if(!s.attrs.name)
				break;
			c = 'p';
		sym:
			if(s.attrs.isexternal)
				c += 'A' - 'a';
			print("%c %s", c, s.attrs.name);
			if(s.attrs.have.lowpc)
				print(" 0x%lux-0x%lux", s.attrs.lowpc, s.attrs.highpc);
			switch(s.attrs.have.location){
			case TBlock:
				print(" @ %.*H", s.attrs.location.b.len, s.attrs.location.b.data);
				break;
			case TConstant:
				print(" @ 0x%lux", s.attrs.location.c);
				break;
			}
			if(s.attrs.have.ranges)
				print(" ranges@0x%lux", s.attrs.ranges);
			print("\n");
			if(s.attrs.have.lowpc){
				if(dwarfpctoline(d, s.attrs.lowpc, &cdir, &dir, &file, &line, &mtime, &length) < 0)
					print("\tcould not find source: %r\n");
				else if(dir == nil)
					print("\t%s/%s:%lud mtime=%lud length=%lud\n",
						cdir, file, line, mtime, length);
				else
					print("\t%s/%s/%s:%lud mtime=%lud length=%lud\n",
						cdir, dir, file, line, mtime, length);

				if(0) printrules(d, s.attrs.lowpc);
				if(0) printrules(d, (s.attrs.lowpc+s.attrs.highpc)/2);
			}
			break;
		}
	}
	exits(0);
}
Esempio n. 8
0
int
dwarfpctoline(Dwarf *d, DwarfSym *proc, ulong pc, char **file, char **function, ulong *line)
{
	char *cdir;
    uchar *prog, *opcount, *end, *dirs;
    ulong off, unit, len, vers, x, start, lastline;
    int i, first, firstline, op, a, l, quantum, isstmt, linebase, linerange, opcodebase, nf;
    char *files, *s;
    DwarfBuf b;
    DwarfSym sym;
    State emit, cur, reset;
    char **f, **newf;

    f = nil;
    memset(proc, 0, sizeof(*proc));

    int runit = dwarfaddrtounit(d, pc, &unit);
    if (runit < 0)
        return -1;
    int rtag = dwarflookuptag(d, unit, TagCompileUnit, &sym);
    if (rtag < 0)
        return -1;

    if(!sym.attrs.have.stmtlist){
        werrstr("no line mapping information for 0x%x", pc);
        return -1;
    }
    off = sym.attrs.stmtlist;
    if(off >= d->line.len){
        werrstr("bad stmtlist");
        goto bad;
    }

    if(trace) werrstr("unit 0x%x stmtlist 0x%x", unit, sym.attrs.stmtlist);

    memset(&b, 0, sizeof b);
    b.d = d;
    b.p = d->line.data + off;
    b.ep = b.p + d->line.len;
    b.addrsize = sym.b.addrsize;	/* should i get this from somewhere else? */

    len = dwarfget4(&b);
    if(b.p==nil || b.p+len > b.ep || b.p+len < b.p){
        werrstr("bad len");
        goto bad;
    }

    b.ep = b.p+len;
    vers = dwarfget2(&b);
    if(vers != 2){
        werrstr("bad dwarf version 0x%x", vers);
        return -1;
    }

    len = dwarfget4(&b);
    if(b.p==nil || b.p+len > b.ep || b.p+len < b.p){
        werrstr("another bad len");
        goto bad;
    }
    prog = b.p+len;

    quantum = dwarfget1(&b);
    isstmt = dwarfget1(&b);
    linebase = (schar)dwarfget1(&b);
    linerange = (schar)dwarfget1(&b);
    opcodebase = dwarfget1(&b);

    opcount = b.p-1;
    dwarfgetnref(&b, opcodebase-1);
    if(b.p == nil){
        werrstr("bad opcode chart");
        goto bad;
    }

    /* just skip the files and dirs for now; we'll come back */
    dirs = b.p;
    while (b.p && *b.p)
        dwarfgetstring(&b);
    dwarfget1(&b);

    files = (char*)b.p;
    while(b.p!=nil && *b.p!=0){
        dwarfgetstring(&b);
        dwarfget128(&b);
        dwarfget128(&b);
        dwarfget128(&b);
    }
    dwarfget1(&b);

    /* move on to the program */
    if(b.p == nil || b.p > prog){
        werrstr("bad header");
        goto bad;
    }
    b.p = prog;

    reset.addr = 0;
    reset.file = 1;
    reset.line = 1;
    reset.column = 0;
    reset.flags = isstmt ? Isstmt : 0;
    reset.isa = 0;

    cur = reset;
    emit = reset;
    nf = 0;
    start = 0;
    if(trace) werrstr("program @ %lu ... %.*H opbase = %d", b.p - d->line.data, b.ep-b.p, b.p, opcodebase);
    first = 1;
    while(b.p != nil){
        firstline = 0;
        op = dwarfget1(&b);
        if(trace) werrstr("\tline %lu, addr 0x%x, op %d %.10H", cur.line, cur.addr, op, b.p);
        if(op >= opcodebase){
            a = (op - opcodebase) / linerange;
            l = (op - opcodebase) % linerange + linebase;
            cur.line += l;
            cur.addr += a * quantum;
            if(trace) werrstr(" +%d,%d", a, l);
        emit:
            if(first){
                if(cur.addr > pc){
                    werrstr("found wrong line mapping 0x%x for pc 0x%x", cur.addr, pc);
                    /* This is an overzealous check.  gcc can produce discontiguous ranges
                       and reorder statements, so it's possible for a future line to start
                       ahead of pc and still find a matching one. */
                    /*goto out;*/
                    firstline = 1;
                }
                first = 0;
                start = cur.addr;
            }
            if(cur.addr > pc && !firstline)
                break;
            if(b.p == nil){
                werrstr("buffer underflow in line mapping");
                goto out;
            }
            emit = cur;
            if(emit.flags & EndSequence){
                werrstr("found wrong line mapping 0x%x-0x%x for pc 0x%x", start, cur.addr, pc);
                goto out;
            }
            cur.flags &= ~(BasicDwarfBlock|PrologueEnd|EpilogueBegin);
        }else{
            switch(op){
            case 0:	/* extended op code */
                if(trace) werrstr(" ext");
                len = dwarfget128(&b);
                end = b.p+len;
                if(b.p == nil || end > b.ep || end < b.p || len < 1)
                    goto bad;
                switch(dwarfget1(&b)){
                case 1:	/* end sequence */
                    if(trace) werrstr(" end");
                    cur.flags |= EndSequence;
                    goto emit;
                case 2:	/* set address */
                    cur.addr = dwarfgetaddr(&b);
                    if(trace) werrstr(" set pc 0x%x", cur.addr);
                    break;
                case 3:	/* define file */
                    newf = malloc(nf+1*sizeof(f[0]));
                    if (newf)
                        RtlMoveMemory(newf, f, nf*sizeof(f[0]));
                    if(newf == nil)
                        goto out;
					free(f);
                    f = newf;
					f[nf++] = s = dwarfgetstring(&b);
					DPRINT1("str %s", s);
                    dwarfget128(&b);
                    dwarfget128(&b);
                    dwarfget128(&b);
                    if(trace) werrstr(" def file %s", s);
                    break;
                }
                if(b.p == nil || b.p > end)
                    goto bad;
                b.p = end;
                break;
            case 1:	/* emit */
                if(trace) werrstr(" emit");
                goto emit;
            case 2:	/* advance pc */
                a = dwarfget128(&b);
                if(trace) werrstr(" advance pc + %lu", a*quantum);
                cur.addr += a * quantum;
                break;
            case 3:	/* advance line */
                l = dwarfget128s(&b);
                if(trace) werrstr(" advance line + %ld", l);
                cur.line += l;
                break;
            case 4:	/* set file */
                if(trace) werrstr(" set file");
                cur.file = dwarfget128s(&b);
                break;
            case 5:	/* set column */
                if(trace) werrstr(" set column");
                cur.column = dwarfget128(&b);
                break;
            case 6:	/* negate stmt */
                if(trace) werrstr(" negate stmt");
                cur.flags ^= Isstmt;
                break;
            case 7:	/* set basic block */
                if(trace) werrstr(" set basic block");
                cur.flags |= BasicDwarfBlock;
                break;
            case 8:	/* const add pc */
                a = (255 - opcodebase) / linerange * quantum;
                if(trace) werrstr(" const add pc + %d", a);
                cur.addr += a;
                break;
            case 9:	/* fixed advance pc */
                a = dwarfget2(&b);
                if(trace) werrstr(" fixed advance pc + %d", a);
                cur.addr += a;
                break;
            case 10:	/* set prologue end */
                if(trace) werrstr(" set prologue end");
                cur.flags |= PrologueEnd;
                break;
            case 11:	/* set epilogue begin */
                if(trace) werrstr(" set epilogue begin");
                cur.flags |= EpilogueBegin;
                break;
            case 12:	/* set isa */
                if(trace) werrstr(" set isa");
                cur.isa = dwarfget128(&b);
                break;
            default:	/* something new - skip it */
                if(trace) werrstr(" unknown %d", opcount[op]);
                for(i=0; i<opcount[op]; i++)
                    dwarfget128(&b);
                break;
            }
        }
    }
    if(b.p == nil)
        goto bad;

    /* finally!  the data we seek is in "emit" */

    if(emit.file == 0){
        werrstr("invalid file index in mapping data");
        goto out;
    }
    if(line)
        *line = emit.line;

    /* skip over first emit.file-2 guys */
    b.p = (uchar*)files;
    for(i=emit.file-1; i > 0 && b.p!=nil && *b.p!=0; i--){
        dwarfgetstring(&b);
        dwarfget128(&b);
        dwarfget128(&b);
        dwarfget128(&b);
    }
    if(b.p == nil){
        werrstr("problem parsing file data second time (cannot happen)");
        goto bad;
    }
    if(*b.p == 0){
        if(i >= nf){
            werrstr("bad file index in mapping data");
            goto bad;
        }
        b.p = (uchar*)f[i];
    }
    s = dwarfgetstring(&b);
	*file = s;
    i = dwarfget128(&b);		/* directory */
    x = dwarfget128(&b);
    x = dwarfget128(&b);

    /* fetch dir name */
	cdir = sym.attrs.have.compdir ? sym.attrs.compdir : 0;

	char *dwarfdir;
	dwarfdir = nil;
	b.p = dirs;
	for (x = 1; b.p && *b.p; x++) {
		dwarfdir = dwarfgetstring(&b);
		if (x == i) break;
	}

	if (!cdir && dwarfdir)
		cdir = dwarfdir;
	
	char *filefull = malloc(strlen(cdir) + strlen(*file) + 2);
	strcpy(filefull, cdir);
	strcat(filefull, "/");
	strcat(filefull, *file);
	*file = filefull;
	
    *function = nil;
    lastline = 0;
	
    runit = dwarfaddrtounit(d, pc, &unit);
    if (runit == 0) {
        DwarfSym compunit = { };
        int renum = dwarfenumunit(d, unit, &compunit);
        if (renum < 0)
            return -1;
        renum = dwarfnextsymat(d, &compunit, proc);
        while (renum == 0) {
            if (proc->attrs.tag == TagSubprogram && 
				proc->attrs.have.name)
			{
                if (proc->attrs.lowpc <= pc && proc->attrs.highpc > pc) {
                    *function = malloc(strlen(proc->attrs.name)+1);
					strcpy(*function, proc->attrs.name);
                    goto done;
				}
			}
            renum = dwarfnextsym(d, proc);
        }
    }

    // Next search by declaration
    runit = dwarfaddrtounit(d, pc, &unit);
    if (runit == 0) {
        DwarfSym compunit = { };
        int renum = dwarfenumunit(d, unit, &compunit);
        if (renum < 0)
            return -1;
        renum = dwarfnextsymat(d, &compunit, proc);
        while (renum == 0) {
            if (proc->attrs.tag == TagSubprogram && 
				proc->attrs.have.name &&
				proc->attrs.declfile == emit.file)
			{
                if (proc->attrs.declline <= *line &&
                    proc->attrs.declline > lastline) {
                    free(*function);
                    *function = malloc(strlen(proc->attrs.name)+1);
					strcpy(*function, proc->attrs.name);
                    goto done;
				}
                lastline = proc->attrs.declline;
			}
            renum = dwarfnextsym(d, proc);
        }
    }

    /* free at last, free at last */
done:
    free(f);
    return 0;
bad:
    werrstr("corrupted line mapping for 0x%x", pc);
out:
    free(f);
    return -1;
}