ktrace.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  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. t = i386trace;
  85. break;
  86. case A_MAGIC: /* 68020 */
  87. case J_MAGIC: /* intel 960 */
  88. t = ctrace;
  89. break;
  90. case K_MAGIC: /* sparc */
  91. case D_MAGIC: /* amd 29000 */
  92. case V_MAGIC: /* mips 3000 */
  93. case M_MAGIC: /* mips 4000 */
  94. case E_MAGIC: /* arm 7-something */
  95. case Q_MAGIC: /* powerpc */
  96. case N_MAGIC: /* mips 4000 LE */
  97. case L_MAGIC: /* dec alpha */
  98. t = rtrace;
  99. break;
  100. case X_MAGIC: /* att dsp 3210 */
  101. sysfatal("can't ktrace %s\n", argv[0]);
  102. break;
  103. default:
  104. fprint(2, "%s: warning: can't tell what type of stack %s uses; assuming it's %s\n",
  105. argv0, argv[0], argc == 4 ? "risc" : "cisc");
  106. break;
  107. }
  108. (*t)(pc, sp, link);
  109. exits(0);
  110. }
  111. static void
  112. inithdr(int fd)
  113. {
  114. seek(fd, 0, 0);
  115. if(!crackhdr(fd, &fhdr))
  116. fatal("read text header");
  117. if(syminit(fd, &fhdr) < 0)
  118. fatal("%r\n");
  119. }
  120. static int
  121. rtrace(ulong pc, ulong sp, ulong link)
  122. {
  123. Symbol s, f;
  124. char buf[128];
  125. ulong oldpc;
  126. int i;
  127. i = 0;
  128. while(findsym(pc, CTEXT, &s)) {
  129. if(pc == s.value) /* at first instruction */
  130. f.value = 0;
  131. else if(findlocal(&s, FRAMENAME, &f) == 0)
  132. break;
  133. symoff(buf, sizeof buf, pc, CANY);
  134. fmt(buf, pc);
  135. oldpc = pc;
  136. if(s.type == 'L' || s.type == 'l' || pc <= s.value+mach->pcquant){
  137. if(link == 0)
  138. fprint(2, "%s: need to supply a valid link register\n", argv0);
  139. pc = link;
  140. }else{
  141. pc = getval(sp);
  142. if(pc == 0)
  143. break;
  144. }
  145. if(pc == 0 || (pc == oldpc && f.value == 0))
  146. break;
  147. sp += f.value;
  148. if(++i > 40)
  149. break;
  150. }
  151. return i;
  152. }
  153. static int
  154. ctrace(ulong pc, ulong sp, ulong link)
  155. {
  156. Symbol s;
  157. char buf[128];
  158. int found;
  159. ulong opc;
  160. long moved, j;
  161. USED(link);
  162. j = 0;
  163. opc = 0;
  164. while(pc && opc != pc) {
  165. moved = pc2sp(pc);
  166. if (moved == -1){
  167. print("pc2sp(%.8lux) = -1 %r\n", pc);
  168. break;
  169. }
  170. found = findsym(pc, CTEXT, &s);
  171. if (!found){
  172. print("findsym fails\n");
  173. break;
  174. }
  175. symoff(buf, sizeof buf, pc, CANY);
  176. fmt(buf, pc);
  177. sp += moved;
  178. opc = pc;
  179. pc = getval(sp);
  180. if(pc == 0)
  181. break;
  182. sp += mach->szaddr; /*assumes address size = stack width*/
  183. if(++j > 40)
  184. break;
  185. }
  186. return j;
  187. }
  188. static int
  189. i386trace(ulong pc, ulong sp, ulong link)
  190. {
  191. int i;
  192. ulong osp;
  193. Symbol s, f;
  194. char buf[128];
  195. USED(link);
  196. i = 0;
  197. osp = 0;
  198. while(findsym(pc, CTEXT, &s)) {
  199. symoff(buf, sizeof buf, pc, CANY);
  200. fmt(buf, pc);
  201. if(pc != s.value) { /* not at first instruction */
  202. if(findlocal(&s, FRAMENAME, &f) == 0)
  203. break;
  204. sp += f.value-mach->szaddr;
  205. }else if(strcmp(s.name, "forkret") == 0){
  206. print("//passing interrupt frame; last pc found at sp=%lux\n", osp);
  207. sp += 15 * mach->szaddr; /* pop interrupt frame */
  208. }
  209. pc = getval(sp);
  210. if(pc == 0 && strcmp(s.name, "forkret") == 0){
  211. sp += 3 * mach->szaddr; /* pop iret eip, cs, eflags */
  212. print("//guessing call through invalid pointer, try again at sp=%lux\n", sp);
  213. s.name = "";
  214. pc = getval(sp);
  215. }
  216. if(pc == 0) {
  217. print("//didn't find pc at sp=%lux, last pc found at sp=%lux\n", sp, osp);
  218. break;
  219. }
  220. osp = sp;
  221. sp += mach->szaddr;
  222. if(strcmp(s.name, "forkret") == 0)
  223. sp += 2 * mach->szaddr; /* pop iret cs, eflags */
  224. if(++i > 40)
  225. break;
  226. }
  227. return i;
  228. }
  229. int naddr;
  230. ulong addr[1024];
  231. ulong val[1024];
  232. static void
  233. putval(ulong a, ulong v)
  234. {
  235. if(naddr < nelem(addr)){
  236. addr[naddr] = a;
  237. val[naddr] = v;
  238. naddr++;
  239. }
  240. }
  241. static void
  242. readstack(void)
  243. {
  244. Biobuf b;
  245. char *p;
  246. char *f[64];
  247. int nf, i;
  248. Binit(&b, 0, OREAD);
  249. while(p=Brdline(&b, '\n')){
  250. p[Blinelen(&b)-1] = 0;
  251. nf = tokenize(p, f, nelem(f));
  252. for(i=0; i<nf; i++){
  253. if(p=strchr(f[i], '=')){
  254. *p++ = 0;
  255. putval(strtoul(f[i], 0, 16), strtoul(p, 0, 16));
  256. }
  257. }
  258. }
  259. }
  260. static ulong
  261. getval(ulong a)
  262. {
  263. char buf[256];
  264. int i, n;
  265. if(interactive){
  266. print("// data at 0x%8.8lux? ", a);
  267. n = read(0, buf, sizeof(buf)-1);
  268. if(n <= 0)
  269. return 0;
  270. buf[n] = '\0';
  271. return strtoul(buf, 0, 16);
  272. }else{
  273. for(i=0; i<naddr; i++)
  274. if(addr[i] == a)
  275. return val[i];
  276. return 0;
  277. }
  278. }
  279. static void
  280. fatal(char *fmt, ...)
  281. {
  282. char buf[4096];
  283. va_list arg;
  284. va_start(arg, fmt);
  285. vseprint(buf, buf+sizeof(buf), fmt, arg);
  286. va_end(arg);
  287. fprint(2, "ktrace: %s\n", buf);
  288. exits(buf);
  289. }