ktrace.c 7.1 KB

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