rdbfs.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. /*
  10. * Remote debugging file system
  11. */
  12. #include <u.h>
  13. #include <libc.h>
  14. #include <auth.h>
  15. #include <fcall.h>
  16. #include <bio.h>
  17. #include <thread.h>
  18. #include <9p.h>
  19. int dbg = 0;
  20. #define DBG if(dbg)fprint
  21. enum {
  22. NHASH = 4096,
  23. Readlen = 4,
  24. Pagequantum = 1024,
  25. };
  26. /* caching memory pages: a lot of space to avoid serial communications */
  27. Lock pglock;
  28. typedef struct Page Page;
  29. struct Page { /* cached memory contents */
  30. Page *link;
  31. uint32_t len;
  32. uint32_t addr;
  33. int count;
  34. uint8_t val[Readlen];
  35. };
  36. Page *pgtab[NHASH];
  37. Page *freelist;
  38. /* called with pglock locked */
  39. Page*
  40. newpg(void)
  41. {
  42. int i;
  43. Page *p, *q;
  44. if(freelist == nil){
  45. p = malloc(sizeof(Page)*Pagequantum);
  46. if(p == nil)
  47. sysfatal("out of memory");
  48. for(i=0, q=p; i<Pagequantum-1; i++, q++)
  49. q->link = q+1;
  50. q->link = nil;
  51. freelist = p;
  52. }
  53. p = freelist;
  54. freelist = freelist->link;
  55. return p;
  56. }
  57. #define PHIINV 0.61803398874989484820
  58. uint
  59. ahash(uint32_t addr)
  60. {
  61. return (uint)floor(NHASH*fmod(addr*PHIINV, 1.0));
  62. }
  63. int
  64. lookup(uint32_t addr, uint8_t *val, uint32_t count)
  65. {
  66. Page *p;
  67. lock(&pglock);
  68. for(p=pgtab[ahash(addr)]; p; p=p->link){
  69. if(p->addr == addr && p->count == count){
  70. memmove(val, p->val, count);
  71. unlock(&pglock);
  72. return 1;
  73. }
  74. }
  75. unlock(&pglock);
  76. return 0;
  77. }
  78. void
  79. insert(uint32_t addr, uint8_t *val, int count)
  80. {
  81. Page *p;
  82. uint h;
  83. lock(&pglock);
  84. p = newpg();
  85. p->addr = addr;
  86. p->count = count;
  87. memmove(p->val, val, count);
  88. h = ahash(addr);
  89. p->link = pgtab[h];
  90. p->len = pgtab[h] ? pgtab[h]->len+1 : 1;
  91. pgtab[h] = p;
  92. unlock(&pglock);
  93. }
  94. void
  95. flushcache(void)
  96. {
  97. int i;
  98. Page *p;
  99. lock(&pglock);
  100. for(i=0; i<NHASH; i++){
  101. if(p=pgtab[i]){
  102. for(;p->link; p=p->link)
  103. ;
  104. p->link = freelist;
  105. freelist = p;
  106. }
  107. pgtab[i] = nil;
  108. }
  109. unlock(&pglock);
  110. }
  111. enum
  112. {
  113. Xctl = 1,
  114. Xfpregs,
  115. Xkregs,
  116. Xmem,
  117. Xproc,
  118. Xregs,
  119. Xtext,
  120. Xstatus,
  121. };
  122. int textfd;
  123. int rfd;
  124. Biobuf rfb;
  125. char* portname = "/dev/eia0";
  126. char* textfile = "/386/9pc";
  127. char* procname = "1";
  128. char* srvname;
  129. Channel* rchan;
  130. void
  131. usage(void)
  132. {
  133. fprint(2, "usage: rdbfs [-p procnum] [-s srvname] [-t textfile] [serialport]\n");
  134. exits("usage");
  135. }
  136. void
  137. noalarm(void *v, char *msg)
  138. {
  139. if(strstr(msg, "alarm"))
  140. noted(NCONT);
  141. noted(NDFLT);
  142. }
  143. /*
  144. * send and receive responses on the serial line
  145. */
  146. void
  147. eiaread(void *v)
  148. {
  149. Req *r;
  150. char *p;
  151. uint8_t *data;
  152. char err[ERRMAX];
  153. char buf[1000];
  154. int i, tries;
  155. notify(noalarm);
  156. while(r = recvp(rchan)){
  157. DBG(2, "got %F: here goes...", &r->ifcall);
  158. if(r->ifcall.count > Readlen)
  159. r->ifcall.count = Readlen;
  160. r->ofcall.count = r->ifcall.count;
  161. if(r->type == Tread && lookup(r->ifcall.offset, (uint8_t*)r->ofcall.data, r->ofcall.count)){
  162. respond(r, nil);
  163. continue;
  164. }
  165. for(tries=0; tries<5; tries++){
  166. if(r->type == Twrite){
  167. DBG(2, "w%.8lux %.8lux...", (uint32_t)r->ifcall.offset, *(uint32_t*)r->ifcall.data);
  168. fprint(rfd, "w%.8lux %.8lux\n",
  169. (uint32_t)r->ifcall.offset,
  170. *(uint32_t*)r->ifcall.data);
  171. }else if(r->type == Tread){
  172. DBG(2, "r%.8lux...", (uint32_t)r->ifcall.offset);
  173. fprint(rfd, "r%.8lux\n",
  174. (uint32_t)r->ifcall.offset);
  175. }else{
  176. respond(r, "oops");
  177. break;
  178. }
  179. for(;;){
  180. werrstr("");
  181. alarm(500);
  182. p=Brdline(&rfb, '\n');
  183. alarm(0);
  184. if(p == nil){
  185. rerrstr(err, sizeof err);
  186. DBG(2, "error %s\n", err);
  187. if(strstr(err, "alarm") || strstr(err, "interrupted"))
  188. break;
  189. if(Blinelen(&rfb) == 0) // true eof
  190. sysfatal("eof on serial line?");
  191. Bread(&rfb, buf, Blinelen(&rfb)<sizeof buf ? Blinelen(&rfb) : sizeof buf);
  192. continue;
  193. }
  194. p[Blinelen(&rfb)-1] = 0;
  195. if(p[0] == '\r')
  196. p++;
  197. DBG(2, "serial %s\n", p);
  198. if(p[0] == 'R'){
  199. if(strtoul(p+1, 0, 16) == (uint32_t)r->ifcall.offset){
  200. /* we know that data can handle Readlen bytes */
  201. data = (uint8_t*)r->ofcall.data;
  202. for(i=0; i<r->ifcall.count; i++)
  203. data[i] = strtol(p+1+8+1+3*i, 0, 16);
  204. insert(r->ifcall.offset, data, r->ifcall.count);
  205. respond(r, nil);
  206. goto Break2;
  207. }else
  208. DBG(2, "%.8lux ≠ %.8lux\n", strtoul(p+1, 0, 16), (uint32_t)r->ifcall.offset);
  209. }else if(p[0] == 'W'){
  210. respond(r, nil);
  211. goto Break2;
  212. }else{
  213. DBG(2, "unknown message\n");
  214. }
  215. }
  216. }
  217. Break2:;
  218. }
  219. }
  220. void
  221. attachremote(char* name)
  222. {
  223. int fd;
  224. char buf[128];
  225. print("attach %s\n", name);
  226. rfd = open(name, ORDWR);
  227. if(rfd < 0)
  228. sysfatal("can't open remote %s", name);
  229. sprint(buf, "%sctl", name);
  230. fd = open(buf, OWRITE);
  231. if(fd < 0)
  232. sysfatal("can't set baud rate on %s", buf);
  233. write(fd, "B9600", 6);
  234. close(fd);
  235. Binit(&rfb, rfd, OREAD);
  236. }
  237. void
  238. fsopen(Req *r)
  239. {
  240. char buf[ERRMAX];
  241. switch((uintptr)r->fid->file->aux){
  242. case Xtext:
  243. close(textfd);
  244. textfd = open(textfile, OREAD);
  245. if(textfd < 0) {
  246. snprint(buf, sizeof buf, "text: %r");
  247. respond(r, buf);
  248. return;
  249. }
  250. break;
  251. }
  252. respond(r, nil);
  253. }
  254. void
  255. fsread(Req *r)
  256. {
  257. int i, n;
  258. char buf[512];
  259. switch((uintptr)r->fid->file->aux) {
  260. case Xfpregs:
  261. case Xproc:
  262. case Xregs:
  263. respond(r, "Egreg");
  264. break;
  265. case Xkregs:
  266. case Xmem:
  267. if(sendp(rchan, r) != 1){
  268. snprint(buf, sizeof buf, "rdbfs sendp: %r");
  269. respond(r, buf);
  270. return;
  271. }
  272. break;
  273. case Xtext:
  274. n = pread(textfd, r->ofcall.data, r->ifcall.count, r->ifcall.offset);
  275. if(n < 0) {
  276. rerrstr(buf, sizeof buf);
  277. respond(r, buf);
  278. break;
  279. }
  280. r->ofcall.count = n;
  281. respond(r, nil);
  282. break;
  283. case Xstatus:
  284. n = sprint(buf, "%-28s%-28s%-28s", "remote", "system", "New");
  285. for(i = 0; i < 9; i++)
  286. n += sprint(buf+n, "%-12d", 0);
  287. readstr(r, buf);
  288. respond(r, nil);
  289. break;
  290. default:
  291. respond(r, "unknown read");
  292. }
  293. }
  294. void
  295. fswrite(Req *r)
  296. {
  297. char buf[ERRMAX];
  298. switch((uintptr)r->fid->file->aux) {
  299. case Xctl:
  300. if(strncmp(r->ifcall.data, "kill", 4) == 0 ||
  301. strncmp(r->ifcall.data, "exit", 4) == 0) {
  302. respond(r, nil);
  303. postnote(PNGROUP, getpid(), "umount");
  304. exits(nil);
  305. }else if(strncmp(r->ifcall.data, "refresh", 7) == 0){
  306. flushcache();
  307. respond(r, nil);
  308. }else if(strncmp(r->ifcall.data, "hashstats", 9) == 0){
  309. int i;
  310. lock(&pglock);
  311. for(i=0; i<NHASH; i++)
  312. if(pgtab[i])
  313. print("%lud ", pgtab[i]->len);
  314. print("\n");
  315. unlock(&pglock);
  316. respond(r, nil);
  317. }else
  318. respond(r, "permission denied");
  319. break;
  320. case Xkregs:
  321. case Xmem:
  322. if(sendp(rchan, r) != 1) {
  323. snprint(buf, sizeof buf, "rdbfs sendp: %r");
  324. respond(r, buf);
  325. return;
  326. }
  327. break;
  328. default:
  329. respond(r, "Egreg");
  330. break;
  331. }
  332. }
  333. struct {
  334. char *s;
  335. int64_t id;
  336. int mode;
  337. } tab[] = {
  338. "ctl", Xctl, 0222,
  339. "fpregs", Xfpregs, 0666,
  340. "kregs", Xkregs, 0666,
  341. "mem", Xmem, 0666,
  342. "proc", Xproc, 0444,
  343. "regs", Xregs, 0666,
  344. "text", Xtext, 0444,
  345. "status", Xstatus, 0444,
  346. };
  347. void
  348. killall(Srv *s)
  349. {
  350. postnote(PNGROUP, getpid(), "kill");
  351. }
  352. Srv fs = {
  353. .open= fsopen,
  354. .read= fsread,
  355. .write= fswrite,
  356. .end= killall,
  357. };
  358. void
  359. threadmain(int argc, char **argv)
  360. {
  361. int i, p[2];
  362. File *dir;
  363. rfork(RFNOTEG);
  364. ARGBEGIN{
  365. case 'D':
  366. chatty9p++;
  367. break;
  368. case 'd':
  369. dbg = 1;
  370. break;
  371. case 'p':
  372. procname = EARGF(usage());
  373. break;
  374. case 's':
  375. srvname = EARGF(usage());
  376. break;
  377. case 't':
  378. textfile = EARGF(usage());
  379. break;
  380. default:
  381. usage();
  382. }ARGEND;
  383. switch(argc){
  384. case 0:
  385. break;
  386. case 1:
  387. portname = argv[0];
  388. break;
  389. default:
  390. usage();
  391. }
  392. rchan = chancreate(sizeof(Req*), 10);
  393. attachremote(portname);
  394. if(pipe(p) < 0)
  395. sysfatal("pipe: %r");
  396. fmtinstall('F', fcallfmt);
  397. proccreate(eiaread, nil, 8192);
  398. fs.tree = alloctree("rdbfs", "rdbfs", DMDIR|0555, nil);
  399. dir = createfile(fs.tree->root, procname, "rdbfs", DMDIR|0555, 0);
  400. for(i=0; i<nelem(tab); i++)
  401. closefile(createfile(dir, tab[i].s, "rdbfs", tab[i].mode, (void*)tab[i].id));
  402. closefile(dir);
  403. threadpostmountsrv(&fs, srvname, "/proc", MBEFORE);
  404. exits(0);
  405. }