ktrace.c 7.6 KB

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