summaryrefslogtreecommitdiff
path: root/sys/src/cmd/rdbfs.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/rdbfs.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/rdbfs.c')
-rwxr-xr-xsys/src/cmd/rdbfs.c433
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);
+}
+