ktrace.c 5.6 KB

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