hproc.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  1. #include "stdinc.h"
  2. #include <bio.h>
  3. #include <mach.h>
  4. #include <ureg.h>
  5. #include "/sys/src/libthread/threadimpl.h"
  6. #include "dat.h"
  7. #include "fns.h"
  8. typedef struct Ureg Ureg;
  9. typedef struct Debug Debug;
  10. struct Debug
  11. {
  12. int textfd;
  13. QLock lock;
  14. Fhdr fhdr;
  15. Map *map;
  16. Fmt *fmt;
  17. int pid;
  18. char *stkprefix;
  19. };
  20. static Debug debug = { -1 };
  21. static int
  22. text(int pid)
  23. {
  24. int fd;
  25. char buf[100];
  26. if(debug.textfd >= 0){
  27. close(debug.textfd);
  28. debug.textfd = -1;
  29. }
  30. memset(&debug.fhdr, 0, sizeof debug.fhdr);
  31. snprint(buf, sizeof buf, "#p/%d/text", pid);
  32. fd = open(buf, OREAD);
  33. if(fd < 0)
  34. return -1;
  35. if(crackhdr(fd, &debug.fhdr) < 0){
  36. close(fd);
  37. return -1;
  38. }
  39. if(syminit(fd, &debug.fhdr) < 0){
  40. memset(&debug.fhdr, 0, sizeof debug.fhdr);
  41. close(fd);
  42. return -1;
  43. }
  44. debug.textfd = fd;
  45. machbytype(debug.fhdr.type);
  46. return 0;
  47. }
  48. static void
  49. unmap(Map *m)
  50. {
  51. int i;
  52. for(i=0; i<m->nsegs; i++)
  53. if(m->seg[i].inuse)
  54. close(m->seg[i].fd);
  55. free(m);
  56. }
  57. static Map*
  58. map(int pid)
  59. {
  60. int mem;
  61. char buf[100];
  62. Map *m;
  63. snprint(buf, sizeof buf, "#p/%d/mem", pid);
  64. mem = open(buf, OREAD);
  65. if(mem < 0)
  66. return nil;
  67. m = attachproc(pid, 0, mem, &debug.fhdr);
  68. if(m == 0){
  69. close(mem);
  70. return nil;
  71. }
  72. if(debug.map)
  73. unmap(debug.map);
  74. debug.map = m;
  75. debug.pid = pid;
  76. return m;
  77. }
  78. static void
  79. dprint(char *fmt, ...)
  80. {
  81. va_list arg;
  82. va_start(arg, fmt);
  83. fmtvprint(debug.fmt, fmt, arg);
  84. va_end(arg);
  85. }
  86. static void
  87. openfiles(void)
  88. {
  89. char buf[4096];
  90. int fd, n;
  91. snprint(buf, sizeof buf, "#p/%d/fd", getpid());
  92. if((fd = open(buf, OREAD)) < 0){
  93. dprint("open %s: %r\n", buf);
  94. return;
  95. }
  96. n = readn(fd, buf, sizeof buf-1);
  97. close(fd);
  98. if(n >= 0){
  99. buf[n] = 0;
  100. fmtstrcpy(debug.fmt, buf);
  101. }
  102. }
  103. /*
  104. * dump the raw symbol table
  105. */
  106. static void
  107. printsym(void)
  108. {
  109. int i;
  110. Sym *sp;
  111. for (i = 0; sp = getsym(i); i++) {
  112. switch(sp->type) {
  113. case 't':
  114. case 'l':
  115. dprint("%16#llux t %s\n", sp->value, sp->name);
  116. break;
  117. case 'T':
  118. case 'L':
  119. dprint("%16#llux T %s\n", sp->value, sp->name);
  120. break;
  121. case 'D':
  122. case 'd':
  123. case 'B':
  124. case 'b':
  125. case 'a':
  126. case 'p':
  127. case 'm':
  128. dprint("%16#llux %c %s\n", sp->value, sp->type, sp->name);
  129. break;
  130. default:
  131. break;
  132. }
  133. }
  134. }
  135. static void
  136. printmap(char *s, Map *map)
  137. {
  138. int i;
  139. if (!map)
  140. return;
  141. dprint("%s\n", s);
  142. for (i = 0; i < map->nsegs; i++) {
  143. if (map->seg[i].inuse)
  144. dprint("%-16s %-16#llux %-16#llux %-16#llux\n",
  145. map->seg[i].name, map->seg[i].b,
  146. map->seg[i].e, map->seg[i].f);
  147. }
  148. }
  149. #define ADDR ulong
  150. static void
  151. printlocals(Map *map, Symbol *fn, ADDR fp)
  152. {
  153. int i;
  154. ulong w;
  155. Symbol s;
  156. char buf[100];
  157. s = *fn;
  158. for (i = 0; localsym(&s, i); i++) {
  159. if (s.class != CAUTO)
  160. continue;
  161. snprint(buf, sizeof buf, "%s%s/", debug.stkprefix, s.name);
  162. if (get4(map, fp-s.value, &w) > 0)
  163. dprint("\t%-10s %10#lux %ld\n", buf, w, w);
  164. else
  165. dprint("\t%-10s ?\n", buf);
  166. }
  167. }
  168. static void
  169. printparams(Map *map, Symbol *fn, ADDR fp)
  170. {
  171. int i;
  172. Symbol s;
  173. ulong w;
  174. int first = 0;
  175. fp += mach->szaddr; /* skip saved pc */
  176. s = *fn;
  177. for (i = 0; localsym(&s, i); i++) {
  178. if (s.class != CPARAM)
  179. continue;
  180. if (first++)
  181. dprint(", ");
  182. if (get4(map, fp+s.value, &w) > 0)
  183. dprint("%s=%#lux", s.name, w);
  184. }
  185. }
  186. static void
  187. printsource(ADDR dot)
  188. {
  189. char str[100];
  190. if (fileline(str, sizeof str, dot))
  191. dprint("%s", str);
  192. }
  193. /*
  194. * callback on stack trace
  195. */
  196. static ulong nextpc;
  197. static void
  198. ptrace(Map *map, uvlong pc, uvlong sp, Symbol *sym)
  199. {
  200. if(nextpc == 0)
  201. nextpc = sym->value;
  202. if(debug.stkprefix == nil)
  203. debug.stkprefix = "";
  204. dprint("%s%s(", debug.stkprefix, sym->name);
  205. printparams(map, sym, sp);
  206. dprint(")");
  207. if(nextpc != sym->value)
  208. dprint("+%#lx ", nextpc - sym->value);
  209. printsource(nextpc);
  210. dprint("\n");
  211. printlocals(map, sym, sp);
  212. nextpc = pc;
  213. }
  214. static void
  215. stacktracepcsp(Map *m, ulong pc, ulong sp)
  216. {
  217. nextpc = 0;
  218. if(machdata->ctrace==nil)
  219. dprint("no machdata->ctrace\n");
  220. else if(machdata->ctrace(m, pc, sp, 0, ptrace) <= 0)
  221. dprint("no stack frame: pc=%#lux sp=%#lux\n", pc, sp);
  222. }
  223. static void
  224. stacktrace(Map *m)
  225. {
  226. ulong pc, sp;
  227. if(get4(m, offsetof(Ureg, pc), &pc) < 0){
  228. dprint("get4 pc: %r");
  229. return;
  230. }
  231. if(get4(m, offsetof(Ureg, sp), &sp) < 0){
  232. dprint("get4 sp: %r");
  233. return;
  234. }
  235. stacktracepcsp(m, pc, sp);
  236. }
  237. static ulong
  238. star(ulong addr)
  239. {
  240. ulong x;
  241. static int warned;
  242. if(addr == 0)
  243. return 0;
  244. if(debug.map == nil){
  245. if(!warned++)
  246. dprint("no debug.map\n");
  247. return 0;
  248. }
  249. if(get4(debug.map, addr, &x) < 0){
  250. dprint("get4 %#lux (pid=%d): %r\n", addr, debug.pid);
  251. return 0;
  252. }
  253. return x;
  254. }
  255. static ulong
  256. resolvev(char *name)
  257. {
  258. Symbol s;
  259. if(lookup(nil, name, &s) == 0)
  260. return 0;
  261. return s.value;
  262. }
  263. static ulong
  264. resolvef(char *name)
  265. {
  266. Symbol s;
  267. if(lookup(name, nil, &s) == 0)
  268. return 0;
  269. return s.value;
  270. }
  271. #define FADDR(type, p, name) ((p) + offsetof(type, name))
  272. #define FIELD(type, p, name) star(FADDR(type, p, name))
  273. static ulong threadpc;
  274. static int
  275. strprefix(char *big, char *pre)
  276. {
  277. return strncmp(big, pre, strlen(pre));
  278. }
  279. static void
  280. tptrace(Map *map, uvlong pc, uvlong sp, Symbol *sym)
  281. {
  282. char buf[512];
  283. USED(map);
  284. USED(sym);
  285. USED(sp);
  286. if(threadpc != 0)
  287. return;
  288. if(!fileline(buf, sizeof buf, pc))
  289. return;
  290. if(strprefix(buf, "/sys/src/libc/") == 0)
  291. return;
  292. if(strprefix(buf, "/sys/src/libthread/") == 0)
  293. return;
  294. if(strprefix(buf, "/sys/src/libthread/") == 0)
  295. return;
  296. threadpc = pc;
  297. }
  298. static char*
  299. threadstkline(ulong t)
  300. {
  301. ulong pc, sp;
  302. static char buf[500];
  303. if(FIELD(Thread, t, state) == Running){
  304. get4(debug.map, offsetof(Ureg, pc), &pc);
  305. get4(debug.map, offsetof(Ureg, sp), &sp);
  306. }else{
  307. // pc = FIELD(Thread, t, sched[JMPBUFPC]);
  308. pc = resolvef("longjmp");
  309. sp = FIELD(Thread, t, sched[JMPBUFSP]);
  310. }
  311. if(machdata->ctrace == nil)
  312. return "";
  313. threadpc = 0;
  314. machdata->ctrace(debug.map, pc, sp, 0, tptrace);
  315. if(!fileline(buf, sizeof buf, threadpc))
  316. buf[0] = 0;
  317. return buf;
  318. }
  319. static void
  320. proc(ulong p)
  321. {
  322. dprint("p=(Proc)%#lux pid %d ", p, FIELD(Proc, p, pid));
  323. if(FIELD(Proc, p, thread) == 0)
  324. dprint(" Sched\n");
  325. else
  326. dprint(" Running\n");
  327. }
  328. static void
  329. fmtbufinit(Fmt *f, char *buf, int len)
  330. {
  331. memset(f, 0, sizeof *f);
  332. f->runes = 0;
  333. f->start = buf;
  334. f->to = buf;
  335. f->stop = buf + len - 1;
  336. f->flush = nil;
  337. f->farg = nil;
  338. f->nfmt = 0;
  339. }
  340. static char*
  341. fmtbufflush(Fmt *f)
  342. {
  343. *(char*)f->to = 0;
  344. return (char*)f->start;
  345. }
  346. static char*
  347. debugstr(ulong s)
  348. {
  349. static char buf[4096];
  350. char *p, *e;
  351. p = buf;
  352. e = buf+sizeof buf - 1;
  353. while(p < e){
  354. if(get1(debug.map, s++, (uchar*)p, 1) < 0)
  355. break;
  356. if(*p == 0)
  357. break;
  358. p++;
  359. }
  360. *p = 0;
  361. return buf;
  362. }
  363. static char*
  364. threadfmt(ulong t)
  365. {
  366. static char buf[4096];
  367. Fmt fmt;
  368. int s;
  369. fmtbufinit(&fmt, buf, sizeof buf);
  370. fmtprint(&fmt, "t=(Thread)%#lux ", t);
  371. switch(s = FIELD(Thread, t, state)){
  372. case Running:
  373. fmtprint(&fmt, " Running ");
  374. break;
  375. case Ready:
  376. fmtprint(&fmt, " Ready ");
  377. break;
  378. case Rendezvous:
  379. fmtprint(&fmt, " Rendez ");
  380. break;
  381. default:
  382. fmtprint(&fmt, " bad state %d ", s);
  383. break;
  384. }
  385. fmtprint(&fmt, "%s", threadstkline(t));
  386. if(FIELD(Thread, t, moribund) == 1)
  387. fmtprint(&fmt, " Moribund");
  388. if(s = FIELD(Thread, t, cmdname)){
  389. fmtprint(&fmt, " [%s]", debugstr(s));
  390. }
  391. fmtbufflush(&fmt);
  392. return buf;
  393. }
  394. static void
  395. thread(ulong t)
  396. {
  397. dprint("%s\n", threadfmt(t));
  398. }
  399. static void
  400. threadapply(ulong p, void (*fn)(ulong))
  401. {
  402. int oldpid, pid;
  403. ulong tq, t;
  404. oldpid = debug.pid;
  405. pid = FIELD(Proc, p, pid);
  406. if(map(pid) == nil)
  407. return;
  408. tq = FADDR(Proc, p, threads);
  409. t = FIELD(Tqueue, tq, head);
  410. while(t != 0){
  411. fn(t);
  412. t = FIELD(Thread, t, nextt);
  413. }
  414. map(oldpid);
  415. }
  416. static void
  417. pthreads1(ulong t)
  418. {
  419. dprint("\t");
  420. thread(t);
  421. }
  422. static void
  423. pthreads(ulong p)
  424. {
  425. threadapply(p, pthreads1);
  426. }
  427. static void
  428. lproc(ulong p)
  429. {
  430. proc(p);
  431. pthreads(p);
  432. }
  433. static void
  434. procapply(void (*fn)(ulong))
  435. {
  436. ulong proc;
  437. ulong pq;
  438. pq = resolvev("_threadpq");
  439. if(pq == 0){
  440. dprint("no thread run queue\n");
  441. return;
  442. }
  443. proc = FIELD(Pqueue, pq, head);
  444. while(proc){
  445. fn(proc);
  446. proc = FIELD(Proc, proc, next);
  447. }
  448. }
  449. static void
  450. threads(HConnect *c)
  451. {
  452. USED(c);
  453. procapply(lproc);
  454. }
  455. static void
  456. procs(HConnect *c)
  457. {
  458. USED(c);
  459. procapply(proc);
  460. }
  461. static void
  462. threadstack(ulong t)
  463. {
  464. ulong pc, sp;
  465. if(FIELD(Thread, t, state) == Running){
  466. stacktrace(debug.map);
  467. }else{
  468. // pc = FIELD(Thread, t, sched[JMPBUFPC]);
  469. pc = resolvef("longjmp");
  470. sp = FIELD(Thread, t, sched[JMPBUFSP]);
  471. stacktracepcsp(debug.map, pc, sp);
  472. }
  473. }
  474. static void
  475. tstacks(ulong t)
  476. {
  477. dprint("\t");
  478. thread(t);
  479. threadstack(t);
  480. dprint("\n");
  481. }
  482. static void
  483. pstacks(ulong p)
  484. {
  485. proc(p);
  486. threadapply(p, tstacks);
  487. }
  488. static void
  489. stacks(HConnect *c)
  490. {
  491. USED(c);
  492. debug.stkprefix = "\t\t";
  493. procapply(pstacks);
  494. debug.stkprefix = "";
  495. }
  496. static void
  497. symbols(HConnect *c)
  498. {
  499. USED(c);
  500. printsym();
  501. }
  502. static void
  503. segments(HConnect *c)
  504. {
  505. USED(c);
  506. printmap("segments", debug.map);
  507. }
  508. static void
  509. fds(HConnect *c)
  510. {
  511. USED(c);
  512. openfiles();
  513. }
  514. static void
  515. all(HConnect *c)
  516. {
  517. dprint("/proc/segment\n");
  518. segments(c);
  519. dprint("\n/proc/fd\n");
  520. fds(c);
  521. dprint("\n/proc/procs\n");
  522. procs(c);
  523. dprint("\n/proc/threads\n");
  524. threads(c);
  525. dprint("\n/proc/stacks\n");
  526. stacks(c);
  527. dprint("\n# /proc/symbols\n");
  528. // symbols(c);
  529. }
  530. int
  531. hproc(HConnect *c)
  532. {
  533. void (*fn)(HConnect*);
  534. static char buf[65536];
  535. Fmt fmt;
  536. if(strcmp(c->req.uri, "/proc/all") == 0)
  537. fn = all;
  538. else if(strcmp(c->req.uri, "/proc/segment") == 0)
  539. fn = segments;
  540. else if(strcmp(c->req.uri, "/proc/fd") == 0)
  541. fn = fds;
  542. else if(strcmp(c->req.uri, "/proc/procs") == 0)
  543. fn = procs;
  544. else if(strcmp(c->req.uri, "/proc/threads") == 0)
  545. fn = threads;
  546. else if(strcmp(c->req.uri, "/proc/stacks") == 0)
  547. fn = stacks;
  548. else if(strcmp(c->req.uri, "/proc/symbols") == 0)
  549. fn = symbols;
  550. else
  551. return hnotfound(c);
  552. if(hsettext(c) < 0)
  553. return -1;
  554. if(!canqlock(&debug.lock)){
  555. hprint(&c->hout, "debugger is busy\n");
  556. return 0;
  557. }
  558. if(debug.textfd < 0){
  559. if(text(getpid()) < 0){
  560. hprint(&c->hout, "cannot attach self text: %r\n");
  561. goto out;
  562. }
  563. }
  564. if(map(getpid()) == nil){
  565. hprint(&c->hout, "cannot map self: %r\n");
  566. goto out;
  567. }
  568. fmtbufinit(&fmt, buf, sizeof buf);
  569. debug.fmt = &fmt;
  570. fn(c);
  571. hprint(&c->hout, "%s\n", fmtbufflush(&fmt));
  572. debug.fmt = nil;
  573. out:
  574. qunlock(&debug.lock);
  575. return 0;
  576. }