diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/rdbfs.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/rdbfs.c')
-rwxr-xr-x | sys/src/cmd/rdbfs.c | 433 |
1 files changed, 433 insertions, 0 deletions
diff --git a/sys/src/cmd/rdbfs.c b/sys/src/cmd/rdbfs.c new file mode 100755 index 000000000..1377e1f90 --- /dev/null +++ b/sys/src/cmd/rdbfs.c @@ -0,0 +1,433 @@ +/* + * 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; + ulong len; + ulong addr; + int count; + uchar 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(ulong addr) +{ + return (uint)floor(NHASH*fmod(addr*PHIINV, 1.0)); +} + +int +lookup(ulong addr, uchar *val, ulong 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(ulong addr, uchar *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"; +Channel* rchan; + +void +usage(void) +{ + fprint(2, "usage: rdbfs [-p procnum] [-t textfile] [serialport]\n"); + exits("usage"); +} + +void +noalarm(void*, char *msg) +{ + if(strstr(msg, "alarm")) + noted(NCONT); + noted(NDFLT); +} + +/* + * send and receive responses on the serial line + */ +void +eiaread(void*) +{ + Req *r; + char *p; + uchar *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, (uchar*)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...", (ulong)r->ifcall.offset, *(ulong*)r->ifcall.data); + fprint(rfd, "w%.8lux %.8lux\n", (ulong)r->ifcall.offset, *(ulong*)r->ifcall.data); + }else if(r->type == Tread){ + DBG(2, "r%.8lux...", (ulong)r->ifcall.offset); + fprint(rfd, "r%.8lux\n", (ulong)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) == (ulong)r->ifcall.offset){ + /* we know that data can handle Readlen bytes */ + data = (uchar*)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), (ulong)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; + int 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*) +{ + 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 '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, nil, "/proc", MBEFORE); + exits(0); +} + |