diff options
author | rsc <devnull@localhost> | 2004-12-25 22:03:28 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2004-12-25 22:03:28 +0000 |
commit | 1cc215aaf92a6cf3cea436f2c215a84839fd59bc (patch) | |
tree | dd8524135949b5bd7b3cb3b23e02b09f9646891e /src/libmach/mach386.c | |
parent | cdf1805191ba4ab5b8fbb1697a95fe0d32e25ee6 (diff) | |
download | plan9port-1cc215aaf92a6cf3cea436f2c215a84839fd59bc.tar.gz plan9port-1cc215aaf92a6cf3cea436f2c215a84839fd59bc.tar.bz2 plan9port-1cc215aaf92a6cf3cea436f2c215a84839fd59bc.zip |
better unwinding for 386.
command-line extraction from core files on linux and freebsd.
move linux ureg into ureg386.h (used in many places).
Diffstat (limited to 'src/libmach/mach386.c')
-rw-r--r-- | src/libmach/mach386.c | 119 |
1 files changed, 105 insertions, 14 deletions
diff --git a/src/libmach/mach386.c b/src/libmach/mach386.c index 4b43683e..b47fcd55 100644 --- a/src/libmach/mach386.c +++ b/src/libmach/mach386.c @@ -29,7 +29,7 @@ static int i386hexinst(Map*, ulong, char*, int); static int i386das(Map*, ulong, char, char*, int); static int i386instlen(Map*, ulong); static char *i386windregs[]; -static int i386unwind(Map*, Regs*, ulong*); +static int i386unwind(Map*, Regs*, ulong*, Symbol*); static Regdesc i386reglist[] = { {"DI", REGOFF(di), RINT, 'X'}, @@ -128,14 +128,37 @@ static char *i386windregs[] = { 0, }; +/* + * The wrapper code around Linux system calls + * saves AX on the stack before calling some calls + * (at least, __libc_nanosleep), when running in + * threaded programs. + */ +static void +syscallhack(Map *map, Regs *regs, int *spoff) +{ + ulong pc; + char buf[60]; + + rget(regs, "PC", &pc); + if(i386das(map, pc-2, 0, buf, sizeof buf) != 2 || strncmp(buf, "INTB\t$", 6) != 0) + return; + if(i386das(map, pc, 0, buf, sizeof buf) != 2 || strcmp(buf, "MOVL\tDX,BX") != 0) + return; + if(i386das(map, pc+2, 0, buf, sizeof buf) != 3 || strcmp(buf, "XCHGL\tAX,0(SP)") != 0) + return; + *spoff += 4; +} + static int -i386unwind(Map *map, Regs *regs, ulong *next) +i386unwind(Map *map, Regs *regs, ulong *next, Symbol *sym) { - int isp, ipc, ibp; - ulong bp; + int i, isp, ipc, ibp, havebp, n, spoff, off[9]; + ulong pc; u32int v; + char buf[60], *p; - /* No symbol information, use frame pointer and do the best we can. */ +//print("i386unwind %s\n", sym ? sym->name : nil); isp = windindex("SP"); ipc = windindex("PC"); ibp = windindex("BP"); @@ -144,19 +167,85 @@ i386unwind(Map *map, Regs *regs, ulong *next) return -1; } - bp = next[ibp]; + /* + * Disassemble entry to figure out + * where values have been saved. + * Perhaps should disassemble exit path + * instead -- a random walk on the code + * should suffice to get us to a RET. + */ + if(sym){ + pc = sym->loc.addr; +//print("startpc %lux\n", pc); + memset(off, 0xff, sizeof off); + spoff = 0; + havebp = 0; + for(;;){ + if((n = i386das(map, pc, 0, buf, sizeof buf)) < 0) + break; +//print("%s\n", buf); + pc += n; + if(strncmp(buf, "PUSHL\t", 6) == 0){ + spoff += 4; + if((i = windindex(buf+6)) >= 0) + off[i] = spoff; + }else if(strcmp(buf, "MOVL\tSP,BP") == 0 && spoff == 4 && off[ibp] == 4){ + havebp = 1; + }else if(strncmp(buf, "SUBL\t$", 6) == 0){ + if((p = strrchr(buf, ',')) && strcmp(p, ",SP") == 0){ +//print("spoff %s\n", buf+6); + spoff += strtol(buf+6, 0, 16); + } + break; + }else if(strncmp(buf, "XORL\t", 5) == 0 || strncmp(buf, "MOVL\t", 5) == 0){ + /* + * Hope these are rescheduled non-prologue instructions + * like XORL AX, AX or MOVL $0x3, AX and thus ignorable. + */ + }else + break; + } - if(get4(map, bp, &v) < 0) - return -1; - next[ibp] = v; + syscallhack(map, regs, &spoff); + + if(havebp){ +//print("havebp\n"); + rget(regs, "BP", &next[isp]); + get4(map, next[isp], &v); + next[ibp] = v; + next[isp] += 4; + }else{ + rget(regs, "SP", &next[isp]); +//print("old sp %lux + %d\n", next[isp], spoff); + next[isp] += spoff; + } + for(i=0; i<nelem(off); i++) + if(off[i] != -1){ + get4(map, next[isp]-off[i], &v); + next[i] = v; + } - next[isp] = bp+4; + if(get4(map, next[isp], &v) < 0) + return -1; +//print("new pc %lux => %lux\n", next[isp], v); + next[ipc] = v; + next[isp] += 4; + return 0; + } - if(get4(map, bp+4, &v) < 0) + /* + * Rely on bp chaining + */ + if(rget(regs, "BP", &next[isp]) < 0 + || get4(map, next[isp], &v) < 0) + return -1; + next[ibp] = v; + next[isp] += 4; + if(get4(map, next[isp], &v) < 0) return -1; next[ipc] = v; - - return 0; + next[isp] += 4; + return 0; } //static char STARTSYM[] = "_main"; @@ -1766,8 +1855,10 @@ pea(Instr *ip) else { if (ip->base < 0) immediate(ip, ip->disp); - else + else { + bprint(ip, "%lux", ip->disp); bprint(ip,"(%s%s)", ANAME(ip), reg[(uchar)ip->base]); + } } if (ip->index >= 0) bprint(ip,"(%s%s*%d)", ANAME(ip), reg[(uchar)ip->index], 1<<ip->ss); |