123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- /*
- * Remote debugging file system
- */
- #include <u.h>
- #include <libc.h>
- #include <auth.h>
- #include <fcall.h>
- #include <bio.h>
- #include <thread.h>
- #include <9p.h>
- int dbg = 0;
- #define DBG if(dbg)fprint
- enum {
- NHASH = 4096,
- Readlen = 4,
- Pagequantum = 1024,
- };
- /* caching memory pages: a lot of space to avoid serial communications */
- Lock pglock;
- typedef struct Page Page;
- struct Page { /* cached memory contents */
- Page *link;
- uint32_t len;
- uint32_t addr;
- int count;
- uint8_t val[Readlen];
- };
- Page *pgtab[NHASH];
- Page *freelist;
- /* called with pglock locked */
- Page*
- newpg(void)
- {
- int i;
- Page *p, *q;
- if(freelist == nil){
- p = malloc(sizeof(Page)*Pagequantum);
- if(p == nil)
- sysfatal("out of memory");
- for(i=0, q=p; i<Pagequantum-1; i++, q++)
- q->link = q+1;
- q->link = nil;
- freelist = p;
- }
- p = freelist;
- freelist = freelist->link;
- return p;
- }
- #define PHIINV 0.61803398874989484820
- uint
- ahash(uint32_t addr)
- {
- return (uint)floor(NHASH*fmod(addr*PHIINV, 1.0));
- }
- int
- lookup(uint32_t addr, uint8_t *val, uint32_t count)
- {
- Page *p;
- lock(&pglock);
- for(p=pgtab[ahash(addr)]; p; p=p->link){
- if(p->addr == addr && p->count == count){
- memmove(val, p->val, count);
- unlock(&pglock);
- return 1;
- }
- }
- unlock(&pglock);
- return 0;
- }
- void
- insert(uint32_t addr, uint8_t *val, int count)
- {
- Page *p;
- uint h;
- lock(&pglock);
- p = newpg();
- p->addr = addr;
- p->count = count;
- memmove(p->val, val, count);
- h = ahash(addr);
- p->link = pgtab[h];
- p->len = pgtab[h] ? pgtab[h]->len+1 : 1;
- pgtab[h] = p;
- unlock(&pglock);
- }
- void
- flushcache(void)
- {
- int i;
- Page *p;
- lock(&pglock);
- for(i=0; i<NHASH; i++){
- if(p=pgtab[i]){
- for(;p->link; p=p->link)
- ;
- p->link = freelist;
- freelist = p;
- }
- pgtab[i] = nil;
- }
- unlock(&pglock);
- }
- enum
- {
- Xctl = 1,
- Xfpregs,
- Xkregs,
- Xmem,
- Xproc,
- Xregs,
- Xtext,
- Xstatus,
- };
- int textfd;
- int rfd;
- Biobuf rfb;
- char* portname = "/dev/eia0";
- char* textfile = "/386/9pc";
- char* procname = "1";
- char* srvname;
- Channel* rchan;
- void
- usage(void)
- {
- fprint(2, "usage: rdbfs [-p procnum] [-s srvname] [-t textfile] [serialport]\n");
- exits("usage");
- }
- void
- noalarm(void *v, char *msg)
- {
- if(strstr(msg, "alarm"))
- noted(NCONT);
- noted(NDFLT);
- }
- /*
- * send and receive responses on the serial line
- */
- void
- eiaread(void *v)
- {
- Req *r;
- char *p;
- uint8_t *data;
- char err[ERRMAX];
- char buf[1000];
- int i, tries;
- notify(noalarm);
- while(r = recvp(rchan)){
- DBG(2, "got %F: here goes...", &r->ifcall);
- if(r->ifcall.count > Readlen)
- r->ifcall.count = Readlen;
- r->ofcall.count = r->ifcall.count;
- if(r->type == Tread && lookup(r->ifcall.offset, (uint8_t*)r->ofcall.data, r->ofcall.count)){
- respond(r, nil);
- continue;
- }
- for(tries=0; tries<5; tries++){
- if(r->type == Twrite){
- DBG(2, "w%.8lux %.8lux...", (uint32_t)r->ifcall.offset, *(uint32_t*)r->ifcall.data);
- fprint(rfd, "w%.8lux %.8lux\n",
- (uint32_t)r->ifcall.offset,
- *(uint32_t*)r->ifcall.data);
- }else if(r->type == Tread){
- DBG(2, "r%.8lux...", (uint32_t)r->ifcall.offset);
- fprint(rfd, "r%.8lux\n",
- (uint32_t)r->ifcall.offset);
- }else{
- respond(r, "oops");
- break;
- }
- for(;;){
- werrstr("");
- alarm(500);
- p=Brdline(&rfb, '\n');
- alarm(0);
- if(p == nil){
- rerrstr(err, sizeof err);
- DBG(2, "error %s\n", err);
- if(strstr(err, "alarm") || strstr(err, "interrupted"))
- break;
- if(Blinelen(&rfb) == 0) // true eof
- sysfatal("eof on serial line?");
- Bread(&rfb, buf, Blinelen(&rfb)<sizeof buf ? Blinelen(&rfb) : sizeof buf);
- continue;
- }
- p[Blinelen(&rfb)-1] = 0;
- if(p[0] == '\r')
- p++;
- DBG(2, "serial %s\n", p);
- if(p[0] == 'R'){
- if(strtoul(p+1, 0, 16) == (uint32_t)r->ifcall.offset){
- /* we know that data can handle Readlen bytes */
- data = (uint8_t*)r->ofcall.data;
- for(i=0; i<r->ifcall.count; i++)
- data[i] = strtol(p+1+8+1+3*i, 0, 16);
- insert(r->ifcall.offset, data, r->ifcall.count);
- respond(r, nil);
- goto Break2;
- }else
- DBG(2, "%.8lux ≠ %.8lux\n", strtoul(p+1, 0, 16), (uint32_t)r->ifcall.offset);
- }else if(p[0] == 'W'){
- respond(r, nil);
- goto Break2;
- }else{
- DBG(2, "unknown message\n");
- }
- }
- }
- Break2:;
- }
- }
- void
- attachremote(char* name)
- {
- int fd;
- char buf[128];
- print("attach %s\n", name);
- rfd = open(name, ORDWR);
- if(rfd < 0)
- sysfatal("can't open remote %s", name);
- sprint(buf, "%sctl", name);
- fd = open(buf, OWRITE);
- if(fd < 0)
- sysfatal("can't set baud rate on %s", buf);
- write(fd, "B9600", 6);
- close(fd);
- Binit(&rfb, rfd, OREAD);
- }
- void
- fsopen(Req *r)
- {
- char buf[ERRMAX];
- switch((uintptr)r->fid->file->aux){
- case Xtext:
- close(textfd);
- textfd = open(textfile, OREAD);
- if(textfd < 0) {
- snprint(buf, sizeof buf, "text: %r");
- respond(r, buf);
- return;
- }
- break;
- }
- respond(r, nil);
- }
- void
- fsread(Req *r)
- {
- int i, n;
- char buf[512];
- switch((uintptr)r->fid->file->aux) {
- case Xfpregs:
- case Xproc:
- case Xregs:
- respond(r, "Egreg");
- break;
- case Xkregs:
- case Xmem:
- if(sendp(rchan, r) != 1){
- snprint(buf, sizeof buf, "rdbfs sendp: %r");
- respond(r, buf);
- return;
- }
- break;
- case Xtext:
- n = pread(textfd, r->ofcall.data, r->ifcall.count, r->ifcall.offset);
- if(n < 0) {
- rerrstr(buf, sizeof buf);
- respond(r, buf);
- break;
- }
- r->ofcall.count = n;
- respond(r, nil);
- break;
- case Xstatus:
- n = sprint(buf, "%-28s%-28s%-28s", "remote", "system", "New");
- for(i = 0; i < 9; i++)
- n += sprint(buf+n, "%-12d", 0);
- readstr(r, buf);
- respond(r, nil);
- break;
- default:
- respond(r, "unknown read");
- }
- }
- void
- fswrite(Req *r)
- {
- char buf[ERRMAX];
- switch((uintptr)r->fid->file->aux) {
- case Xctl:
- if(strncmp(r->ifcall.data, "kill", 4) == 0 ||
- strncmp(r->ifcall.data, "exit", 4) == 0) {
- respond(r, nil);
- postnote(PNGROUP, getpid(), "umount");
- exits(nil);
- }else if(strncmp(r->ifcall.data, "refresh", 7) == 0){
- flushcache();
- respond(r, nil);
- }else if(strncmp(r->ifcall.data, "hashstats", 9) == 0){
- int i;
- lock(&pglock);
- for(i=0; i<NHASH; i++)
- if(pgtab[i])
- print("%lud ", pgtab[i]->len);
- print("\n");
- unlock(&pglock);
- respond(r, nil);
- }else
- respond(r, "permission denied");
- break;
- case Xkregs:
- case Xmem:
- if(sendp(rchan, r) != 1) {
- snprint(buf, sizeof buf, "rdbfs sendp: %r");
- respond(r, buf);
- return;
- }
- break;
- default:
- respond(r, "Egreg");
- break;
- }
- }
- struct {
- char *s;
- int64_t id;
- int mode;
- } tab[] = {
- "ctl", Xctl, 0222,
- "fpregs", Xfpregs, 0666,
- "kregs", Xkregs, 0666,
- "mem", Xmem, 0666,
- "proc", Xproc, 0444,
- "regs", Xregs, 0666,
- "text", Xtext, 0444,
- "status", Xstatus, 0444,
- };
- void
- killall(Srv *s)
- {
- postnote(PNGROUP, getpid(), "kill");
- }
- Srv fs = {
- .open= fsopen,
- .read= fsread,
- .write= fswrite,
- .end= killall,
- };
- void
- threadmain(int argc, char **argv)
- {
- int i, p[2];
- File *dir;
- rfork(RFNOTEG);
- ARGBEGIN{
- case 'D':
- chatty9p++;
- break;
- case 'd':
- dbg = 1;
- break;
- case 'p':
- procname = EARGF(usage());
- break;
- case 's':
- srvname = EARGF(usage());
- break;
- case 't':
- textfile = EARGF(usage());
- break;
- default:
- usage();
- }ARGEND;
- switch(argc){
- case 0:
- break;
- case 1:
- portname = argv[0];
- break;
- default:
- usage();
- }
- rchan = chancreate(sizeof(Req*), 10);
- attachremote(portname);
- if(pipe(p) < 0)
- sysfatal("pipe: %r");
- fmtinstall('F', fcallfmt);
- proccreate(eiaread, nil, 8192);
- fs.tree = alloctree("rdbfs", "rdbfs", DMDIR|0555, nil);
- dir = createfile(fs.tree->root, procname, "rdbfs", DMDIR|0555, 0);
- for(i=0; i<nelem(tab); i++)
- closefile(createfile(dir, tab[i].s, "rdbfs", tab[i].mode, (void*)tab[i].id));
- closefile(dir);
- threadpostmountsrv(&fs, srvname, "/proc", MBEFORE);
- exits(0);
- }
|