summaryrefslogtreecommitdiff
path: root/sys/src/cmd/ktrace.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/ktrace.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/ktrace.c')
-rwxr-xr-xsys/src/cmd/ktrace.c403
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);
+}