diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/ktrace.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/ktrace.c')
-rwxr-xr-x | sys/src/cmd/ktrace.c | 403 |
1 files changed, 403 insertions, 0 deletions
diff --git a/sys/src/cmd/ktrace.c b/sys/src/cmd/ktrace.c new file mode 100755 index 000000000..1b9ab8bdc --- /dev/null +++ b/sys/src/cmd/ktrace.c @@ -0,0 +1,403 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <mach.h> +#include <ctype.h> + +static int rtrace(uvlong, uvlong, uvlong); +static int ctrace(uvlong, uvlong, uvlong); +static int i386trace(uvlong, uvlong, uvlong); +static int amd64trace(uvlong, uvlong, uvlong); +static uvlong getval(uvlong); +static void inithdr(int); +static void fatal(char*, ...); +static void readstack(void); + +static Fhdr fhdr; +static int interactive; + +#define FRAMENAME ".frame" + +static void +usage(void) +{ + fprint(2, "usage: ktrace [-i] kernel pc sp [link]\n"); + exits("usage"); +} + +static void +printaddr(char *addr, uvlong pc) +{ + int i; + char *p; + + /* + * reformat the following. + * + * foo+1a1 -> src(foo+0x1a1); + * 10101010 -> src(0x10101010); + */ + + if(strlen(addr) == 8 && strchr(addr, '+') == nil){ + for(i=0; i<8; i++) + if(!isxdigit(addr[i])) + break; + if(i == 8){ + print("src(%#.8llux); // 0x%s\n", pc, addr); + return; + } + } + + if(p=strchr(addr, '+')){ + *p++ = 0; + print("src(%#.8llux); // %s+0x%s\n", pc, addr, p); + }else + print("src(%#.8llux); // %s\n", pc, addr); +} + +static void (*fmt)(char*, uvlong) = printaddr; + +void +main(int argc, char *argv[]) +{ + int (*t)(uvlong, uvlong, uvlong); + uvlong pc, sp, link; + int fd; + + ARGBEGIN{ + case 'i': + interactive++; + break; + default: + usage(); + }ARGEND + + link = 0; + t = ctrace; + switch(argc){ + case 4: + t = rtrace; + link = strtoull(argv[3], 0, 16); + break; + case 3: + break; + default: + usage(); + } + pc = strtoull(argv[1], 0, 16); + sp = strtoull(argv[2], 0, 16); + if(!interactive) + readstack(); + + fd = open(argv[0], OREAD); + if(fd < 0) + fatal("can't open %s: %r", argv[0]); + inithdr(fd); + switch(fhdr.magic){ + case I_MAGIC: /* intel 386 */ + t = i386trace; + break; + case S_MAGIC: /* amd64 */ + t = amd64trace; + break; + case A_MAGIC: /* 68020 */ + case J_MAGIC: /* intel 960 */ + t = ctrace; + break; + case K_MAGIC: /* sparc */ + case D_MAGIC: /* amd 29000 */ + case V_MAGIC: /* mips 3000 */ + case M_MAGIC: /* mips 4000 */ + case E_MAGIC: /* arm 7-something */ + case Q_MAGIC: /* powerpc */ + case N_MAGIC: /* mips 4000 LE */ + case L_MAGIC: /* dec alpha */ + t = rtrace; + break; + case X_MAGIC: /* att dsp 3210 */ + sysfatal("can't ktrace %s", argv[0]); + break; + default: + fprint(2, "%s: warning: can't tell what type of stack %s uses; assuming it's %s\n", + argv0, argv[0], argc == 4 ? "risc" : "cisc"); + break; + } + (*t)(pc, sp, link); + exits(0); +} + +static void +inithdr(int fd) +{ + seek(fd, 0, 0); + if(!crackhdr(fd, &fhdr)) + fatal("read text header"); + + if(syminit(fd, &fhdr) < 0) + fatal("%r\n"); +} + +static int +rtrace(uvlong pc, uvlong sp, uvlong link) +{ + Symbol s, f; + char buf[128]; + uvlong oldpc; + int i; + + i = 0; + while(findsym(pc, CTEXT, &s)) { + if(pc == s.value) /* at first instruction */ + f.value = 0; + else if(findlocal(&s, FRAMENAME, &f) == 0) + break; + + symoff(buf, sizeof buf, pc, CANY); + fmt(buf, pc); + + oldpc = pc; + if(s.type == 'L' || s.type == 'l' || pc <= s.value+mach->pcquant){ + if(link == 0) + fprint(2, "%s: need to supply a valid link register\n", argv0); + pc = link; + }else{ + pc = getval(sp); + if(pc == 0) + break; + } + + if(pc == 0 || (pc == oldpc && f.value == 0)) + break; + + sp += f.value; + + if(++i > 40) + break; + } + return i; +} + +static int +ctrace(uvlong pc, uvlong sp, uvlong link) +{ + Symbol s; + char buf[128]; + int found; + uvlong opc, moved; + long j; + + USED(link); + j = 0; + opc = 0; + while(pc && opc != pc) { + moved = pc2sp(pc); + if (moved == ~0){ + print("pc2sp(%#.8llux) = -1 %r\n", pc); + break; + } + found = findsym(pc, CTEXT, &s); + if (!found){ + print("findsym fails\n"); + break; + } + symoff(buf, sizeof buf, pc, CANY); + fmt(buf, pc); + + sp += moved; + opc = pc; + pc = getval(sp); + if(pc == 0) + break; + sp += mach->szaddr; /*assumes address size = stack width*/ + if(++j > 40) + break; + } + return j; +} + +static int +i386trace(uvlong pc, uvlong sp, uvlong link) +{ + int i; + uvlong osp; + Symbol s, f; + char buf[128]; + + USED(link); + i = 0; + osp = 0; + while(findsym(pc, CTEXT, &s)) { + + symoff(buf, sizeof buf, pc, CANY); + fmt(buf, pc); + +//XXX s.value &= ~(uintptr)0; + if(pc != s.value) { /* not at first instruction */ + if(findlocal(&s, FRAMENAME, &f) == 0) + break; + sp += f.value-mach->szaddr; + }else if(strcmp(s.name, "forkret") == 0){ +//XXX + print("//passing interrupt frame; last pc found at sp=%#llux\n", osp); + + sp += 15 * mach->szaddr; /* pop interrupt frame */ + } + + pc = getval(sp); +//XXX + if(pc == 0 && strcmp(s.name, "forkret") == 0){ + sp += 3 * mach->szaddr; /* pop iret eip, cs, eflags */ + print("//guessing call through invalid pointer, try again at sp=%#llux\n", sp); + s.name = ""; + pc = getval(sp); + } + if(pc == 0) { + print("//didn't find pc at sp=%#llux, last pc found at sp=%#llux\n", sp, osp); + break; + } + osp = sp; + + sp += mach->szaddr; +//XXX + if(strcmp(s.name, "forkret") == 0) + sp += 2 * mach->szaddr; /* pop iret cs, eflags */ + + if(++i > 40) + break; + } + return i; +} + +static int +amd64trace(uvlong pc, uvlong sp, uvlong link) +{ + int i, isintrr; + uvlong osp; + Symbol s, f; + char buf[128]; + + USED(link); + i = 0; + osp = 0; + while(findsym(pc, CTEXT, &s)) { + + symoff(buf, sizeof buf, pc, CANY); + fmt(buf, pc); + + if(strcmp(s.name, "_intrr") == 0) + isintrr = 1; + else + isintrr = 0; + if(pc != s.value) { /* not at first instruction */ + if(findlocal(&s, FRAMENAME, &f) == 0) + break; + sp += f.value-mach->szaddr; + } + else if(isintrr){ + print("//passing interrupt frame; last pc found at sp=%#llux\n", osp); + /* + * Pop interrupt frame (ureg.h) up to the IP value. + */ + sp += 19 * mach->szaddr; + } + + pc = getval(sp); + if(pc == 0 && isintrr){ + /* + * Pop IP, CS and FLAGS to get to the SP. + * The AMD64 aligns the interrupt stack on + * a 16-byte boundary so have the get the + * SP from the saved frame. + */ + sp += 3 * mach->szaddr; + print("//guessing call through invalid pointer; try again at sp=%#llux\n", sp); + s.name = ""; + sp = getval(sp); + pc = getval(sp); + } + if(pc == 0) { + print("//didn't find pc at sp=%#llux, last pc found at sp=%#llux\n", sp, osp); + break; + } + osp = sp; + + if(!isintrr) + sp += mach->szaddr; + + if(++i > 40) + break; + } + return i; +} + +int naddr; +uvlong addr[1024]; +uvlong val[1024]; + +static void +putval(uvlong a, uvlong v) +{ + if(naddr < nelem(addr)){ + addr[naddr] = a; + val[naddr] = v; + naddr++; + } +} + +static void +readstack(void) +{ + Biobuf b; + char *p; + char *f[64]; + int nf, i; + + Binit(&b, 0, OREAD); + while(p=Brdline(&b, '\n')){ + p[Blinelen(&b)-1] = 0; + nf = tokenize(p, f, nelem(f)); + for(i=0; i<nf; i++){ + if(p=strchr(f[i], '=')){ + *p++ = 0; + putval(strtoull(f[i], 0, 16), strtoull(p, 0, 16)); + } + } + } +} + +static uvlong +getval(uvlong a) +{ + char buf[256]; + int i, n; + uvlong r; + + if(interactive){ + print("// data at %#8.8llux? ", a); + n = read(0, buf, sizeof(buf)-1); + if(n <= 0) + return 0; + buf[n] = '\0'; + r = strtoull(buf, 0, 16); + }else{ + r = 0; + for(i=0; i<naddr; i++) + if(addr[i] == a) + r = val[i]; + } + + return r; +} + +static void +fatal(char *fmt, ...) +{ + char buf[4096]; + va_list arg; + + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + fprint(2, "ktrace: %s\n", buf); + exits(buf); +} |