1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 #include <mach.h> 5 #include <ctype.h> 6 7 static int rtrace(uvlong, uvlong, uvlong); 8 static int ctrace(uvlong, uvlong, uvlong); 9 static int i386trace(uvlong, uvlong, uvlong); 10 static int amd64trace(uvlong, uvlong, uvlong); 11 static uvlong getval(uvlong); 12 static void inithdr(int); 13 static void fatal(char*, ...); 14 static void readstack(void); 15 16 static Fhdr fhdr; 17 static int interactive; 18 19 #define FRAMENAME ".frame" 20 21 static void 22 usage(void) 23 { 24 fprint(2, "usage: ktrace [-i] kernel pc sp [link]\n"); 25 exits("usage"); 26 } 27 28 static void 29 printaddr(char *addr, uvlong pc) 30 { 31 int i; 32 char *p; 33 34 /* 35 * reformat the following. 36 * 37 * foo+1a1 -> src(foo+0x1a1); 38 * 10101010 -> src(0x10101010); 39 */ 40 41 if(strlen(addr) == 8 && strchr(addr, '+') == nil){ 42 for(i=0; i<8; i++) 43 if(!isxdigit(addr[i])) 44 break; 45 if(i == 8){ 46 print("src(%#.8llux); // 0x%s\n", pc, addr); 47 return; 48 } 49 } 50 51 if(p=strchr(addr, '+')){ 52 *p++ = 0; 53 print("src(%#.8llux); // %s+0x%s\n", pc, addr, p); 54 }else 55 print("src(%#.8llux); // %s\n", pc, addr); 56 } 57 58 static void (*fmt)(char*, uvlong) = printaddr; 59 60 void 61 main(int argc, char *argv[]) 62 { 63 int (*t)(uvlong, uvlong, uvlong); 64 uvlong pc, sp, link; 65 int fd; 66 67 ARGBEGIN{ 68 case 'i': 69 interactive++; 70 break; 71 default: 72 usage(); 73 }ARGEND 74 75 link = 0; 76 t = ctrace; 77 switch(argc){ 78 case 4: 79 t = rtrace; 80 link = strtoull(argv[3], 0, 16); 81 break; 82 case 3: 83 break; 84 default: 85 usage(); 86 } 87 pc = strtoull(argv[1], 0, 16); 88 sp = strtoull(argv[2], 0, 16); 89 if(!interactive) 90 readstack(); 91 92 fd = open(argv[0], OREAD); 93 if(fd < 0) 94 fatal("can't open %s: %r", argv[0]); 95 inithdr(fd); 96 switch(fhdr.magic){ 97 case I_MAGIC: /* intel 386 */ 98 t = i386trace; 99 break; 100 case S_MAGIC: /* amd64 */ 101 t = amd64trace; 102 break; 103 case A_MAGIC: /* 68020 */ 104 case J_MAGIC: /* intel 960 */ 105 t = ctrace; 106 break; 107 case K_MAGIC: /* sparc */ 108 case D_MAGIC: /* amd 29000 */ 109 case V_MAGIC: /* mips 3000 */ 110 case M_MAGIC: /* mips 4000 */ 111 case E_MAGIC: /* arm 7-something */ 112 case Q_MAGIC: /* powerpc */ 113 case N_MAGIC: /* mips 4000 LE */ 114 case L_MAGIC: /* dec alpha */ 115 t = rtrace; 116 break; 117 case X_MAGIC: /* att dsp 3210 */ 118 sysfatal("can't ktrace %s\n", argv[0]); 119 break; 120 default: 121 fprint(2, "%s: warning: can't tell what type of stack %s uses; assuming it's %s\n", 122 argv0, argv[0], argc == 4 ? "risc" : "cisc"); 123 break; 124 } 125 (*t)(pc, sp, link); 126 exits(0); 127 } 128 129 static void 130 inithdr(int fd) 131 { 132 seek(fd, 0, 0); 133 if(!crackhdr(fd, &fhdr)) 134 fatal("read text header"); 135 136 if(syminit(fd, &fhdr) < 0) 137 fatal("%r\n"); 138 } 139 140 static int 141 rtrace(uvlong pc, uvlong sp, uvlong link) 142 { 143 Symbol s, f; 144 char buf[128]; 145 uvlong oldpc; 146 int i; 147 148 i = 0; 149 while(findsym(pc, CTEXT, &s)) { 150 if(pc == s.value) /* at first instruction */ 151 f.value = 0; 152 else if(findlocal(&s, FRAMENAME, &f) == 0) 153 break; 154 155 symoff(buf, sizeof buf, pc, CANY); 156 fmt(buf, pc); 157 158 oldpc = pc; 159 if(s.type == 'L' || s.type == 'l' || pc <= s.value+mach->pcquant){ 160 if(link == 0) 161 fprint(2, "%s: need to supply a valid link register\n", argv0); 162 pc = link; 163 }else{ 164 pc = getval(sp); 165 if(pc == 0) 166 break; 167 } 168 169 if(pc == 0 || (pc == oldpc && f.value == 0)) 170 break; 171 172 sp += f.value; 173 174 if(++i > 40) 175 break; 176 } 177 return i; 178 } 179 180 static int 181 ctrace(uvlong pc, uvlong sp, uvlong link) 182 { 183 Symbol s; 184 char buf[128]; 185 int found; 186 uvlong opc, moved; 187 long j; 188 189 USED(link); 190 j = 0; 191 opc = 0; 192 while(pc && opc != pc) { 193 moved = pc2sp(pc); 194 if (moved == ~0){ 195 print("pc2sp(%#.8llux) = -1 %r\n", pc); 196 break; 197 } 198 found = findsym(pc, CTEXT, &s); 199 if (!found){ 200 print("findsym fails\n"); 201 break; 202 } 203 symoff(buf, sizeof buf, pc, CANY); 204 fmt(buf, pc); 205 206 sp += moved; 207 opc = pc; 208 pc = getval(sp); 209 if(pc == 0) 210 break; 211 sp += mach->szaddr; /*assumes address size = stack width*/ 212 if(++j > 40) 213 break; 214 } 215 return j; 216 } 217 218 static int 219 i386trace(uvlong pc, uvlong sp, uvlong link) 220 { 221 int i; 222 uvlong osp; 223 Symbol s, f; 224 char buf[128]; 225 226 USED(link); 227 i = 0; 228 osp = 0; 229 while(findsym(pc, CTEXT, &s)) { 230 231 symoff(buf, sizeof buf, pc, CANY); 232 fmt(buf, pc); 233 234 //XXX s.value &= ~(uintptr)0; 235 if(pc != s.value) { /* not at first instruction */ 236 if(findlocal(&s, FRAMENAME, &f) == 0) 237 break; 238 sp += f.value-mach->szaddr; 239 }else if(strcmp(s.name, "forkret") == 0){ 240 //XXX 241 print("//passing interrupt frame; last pc found at sp=%#llux\n", osp); 242 243 sp += 15 * mach->szaddr; /* pop interrupt frame */ 244 } 245 246 pc = getval(sp); 247 //XXX 248 if(pc == 0 && strcmp(s.name, "forkret") == 0){ 249 sp += 3 * mach->szaddr; /* pop iret eip, cs, eflags */ 250 print("//guessing call through invalid pointer, try again at sp=%#llux\n", sp); 251 s.name = ""; 252 pc = getval(sp); 253 } 254 if(pc == 0) { 255 print("//didn't find pc at sp=%#llux, last pc found at sp=%#llux\n", sp, osp); 256 break; 257 } 258 osp = sp; 259 260 sp += mach->szaddr; 261 //XXX 262 if(strcmp(s.name, "forkret") == 0) 263 sp += 2 * mach->szaddr; /* pop iret cs, eflags */ 264 265 if(++i > 40) 266 break; 267 } 268 return i; 269 } 270 271 static int 272 amd64trace(uvlong pc, uvlong sp, uvlong link) 273 { 274 int i, isintrr; 275 uvlong osp; 276 Symbol s, f; 277 char buf[128]; 278 279 USED(link); 280 i = 0; 281 osp = 0; 282 while(findsym(pc, CTEXT, &s)) { 283 284 symoff(buf, sizeof buf, pc, CANY); 285 fmt(buf, pc); 286 287 if(strcmp(s.name, "_intrr") == 0) 288 isintrr = 1; 289 else 290 isintrr = 0; 291 if(pc != s.value) { /* not at first instruction */ 292 if(findlocal(&s, FRAMENAME, &f) == 0) 293 break; 294 sp += f.value-mach->szaddr; 295 } 296 else if(isintrr){ 297 print("//passing interrupt frame; last pc found at sp=%#llux\n", osp); 298 /* 299 * Pop interrupt frame (ureg.h) up to the IP value. 300 */ 301 sp += 19 * mach->szaddr; 302 } 303 304 pc = getval(sp); 305 if(pc == 0 && isintrr){ 306 /* 307 * Pop IP, CS and FLAGS to get to the SP. 308 * The AMD64 aligns the interrupt stack on 309 * a 16-byte boundary so have the get the 310 * SP from the saved frame. 311 */ 312 sp += 3 * mach->szaddr; 313 print("//guessing call through invalid pointer; try again at sp=%#llux\n", sp); 314 s.name = ""; 315 sp = getval(sp); 316 pc = getval(sp); 317 } 318 if(pc == 0) { 319 print("//didn't find pc at sp=%#llux, last pc found at sp=%#llux\n", sp, osp); 320 break; 321 } 322 osp = sp; 323 324 if(!isintrr) 325 sp += mach->szaddr; 326 327 if(++i > 40) 328 break; 329 } 330 return i; 331 } 332 333 int naddr; 334 uvlong addr[1024]; 335 uvlong val[1024]; 336 337 static void 338 putval(uvlong a, uvlong v) 339 { 340 if(naddr < nelem(addr)){ 341 addr[naddr] = a; 342 val[naddr] = v; 343 naddr++; 344 } 345 } 346 347 static void 348 readstack(void) 349 { 350 Biobuf b; 351 char *p; 352 char *f[64]; 353 int nf, i; 354 355 Binit(&b, 0, OREAD); 356 while(p=Brdline(&b, '\n')){ 357 p[Blinelen(&b)-1] = 0; 358 nf = tokenize(p, f, nelem(f)); 359 for(i=0; i<nf; i++){ 360 if(p=strchr(f[i], '=')){ 361 *p++ = 0; 362 putval(strtoull(f[i], 0, 16), strtoull(p, 0, 16)); 363 } 364 } 365 } 366 } 367 368 static uvlong 369 getval(uvlong a) 370 { 371 char buf[256]; 372 int i, n; 373 uvlong r; 374 375 if(interactive){ 376 print("// data at %#8.8llux? ", a); 377 n = read(0, buf, sizeof(buf)-1); 378 if(n <= 0) 379 return 0; 380 buf[n] = '\0'; 381 r = strtoull(buf, 0, 16); 382 }else{ 383 r = 0; 384 for(i=0; i<naddr; i++) 385 if(addr[i] == a) 386 r = val[i]; 387 } 388 389 return r; 390 } 391 392 static void 393 fatal(char *fmt, ...) 394 { 395 char buf[4096]; 396 va_list arg; 397 398 va_start(arg, fmt); 399 vseprint(buf, buf+sizeof(buf), fmt, arg); 400 va_end(arg); 401 fprint(2, "ktrace: %s\n", buf); 402 exits(buf); 403 } 404