hproc.c 10 KB

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