#include #include #include #include #include #include <9p.h> #include #include #include #include "gdb.h" #define BUFSIZE (64*1024) static char Ebadcmd[] = "invalid command"; static char Egreg[] = "stallion is a lazy bum"; static char Enomem[] = "out of memory"; static Fhdr fhdr; static int text; static uchar *regs; /* cf. gdb/i386-tdep.c */ static int i386regmap[] = { 7, 6, 5, 4, /* di, si, bp, nsp */ 3, 2, 1, 0, /* bx, dx, cx, ax */ 15, 14, 13, 12, /* gs, fs, es, ds */ -1, -1, 8, 10, /* trap, ecode, pc, cs */ 9, 4, 11, /* flags, sp, ss */ }; /* cf. gdb/arm-tdep.c */ static int armregmap[] = { 1, 2, 3, 4, /* r0, r1, r2, r3 */ 5, 6, 7, 8, /* r4, r5, r6, r7 */ 9, 10, 11, 12, /* r8, r9, r10, r11 */ 13, 14, 15, -1, /* r12, r13, r14, type */ 0, 16, /* psr, r15 */ }; static int *regmap[] = { [MMIPS] = nil, [MSPARC] = nil, [M68020] = nil, [MI386] = i386regmap, [MMIPS2] = nil, [NMIPS2] = nil, [MARM] = armregmap, [MPOWER] = nil, [NMIPS] = nil, [MAMD64] = nil, [MPOWER64] = nil, [MARM64] = nil, }; enum { Fctl, Ffpregs, Fkregs, Fmem, Fnote, Fproc, Fregs, Ftext, Fstatus, }; static struct { char *name; ulong mode; } files[] = { [Fctl] "ctl", 0222, [Ffpregs] "fpregs", 0666, [Fkregs] "kregs", 0666, [Fmem] "mem", 0666, [Fnote] "note", 0222, [Fproc] "proc", 0444, [Fregs] "regs", 0666, [Ftext] "text", 0444, [Fstatus] "status", 0444, }; static int getfile(Req *r) { char *name; int i; name = r->fid->file->name; for (i = 0; i < nelem(files); ++i) if (strcmp(files[i].name, name) == 0) return i; return -1; } static void ctlwrite(Req *r) { r->ofcall.count = r->ifcall.count; if(strncmp(r->ifcall.data, "kill", 4) == 0){ gdbkill(); respond(r, nil); exits(nil); } else respond(r, Ebadcmd); } static void regsopen(Req *r) { uchar *p, *e; int i, n, off; static char buf[BUFSIZE]; static char err[ERRMAX]; /* * Registers are initialized to a known pattern to better * highlight Ureg entries that are not tied to actual * register values. */ if(regs == nil){ regs = malloc(mach->regsize); if(regs == nil) sysfatal(Enomem); } memset(regs, 0xaa, mach->regsize); if(gdbcommand("g", buf, sizeof buf) < 0){ rerrstr(err, sizeof err); respond(r, err); return; } if(waserror()){ respond(r, buf); return; } p = regs; e = regs + mach->regsize; n = mach->szreg * 2; for(i = 0; p < e; ++i, p += mach->szreg){ off = regmap[mach->mtype][i] * n; if(off < 0) continue; dec16(p, mach->regsize, buf + off, n); } respond(r, nil); } static void regsread(Req *r) { readbuf(r, regs, mach->regsize); respond(r, nil); } static void memread(Req *r) { vlong offset; ulong count; int n; static char buf[BUFSIZE]; static char err[ERRMAX]; offset = r->ifcall.offset; count = r->ifcall.count; snprint(buf, sizeof buf, "m%ullx,%ulx", offset, count); n = gdbcommand(buf, buf, sizeof buf); if(n < 0){ rerrstr(err, sizeof err); respond(r, err); return; } else if(waserror()){ respond(r, buf); return; } n = dec16((uchar *)r->ofcall.data, count, buf, n); if(n < 0){ rerrstr(err, sizeof err); respond(r, err); } else{ r->ofcall.count = n; respond(r, nil); } } static void textread(Req *r) { vlong offset; ulong count; long n; static char err[ERRMAX]; offset = r->ifcall.offset; count = r->ifcall.count; n = pread(text, r->ofcall.data, count, offset); if(n < 0){ rerrstr(err, sizeof err); respond(r, err); } else{ r->ofcall.count = n; respond(r, nil); } } static void statusread(Req *r) { char *p, *e; char buf[512]; int i; p = buf; e = buf + sizeof buf; p = seprint(p, e, "%-28s%-28s%-28s", "gdbfs", getuser(), "Broken"); for(i = 0; i < 9; ++i) p = seprint(p, e, "%-12d", 0); readstr(r, buf); respond(r, nil); } static void fsopen(Req *r) { switch(getfile(r)){ case Fregs: case Fkregs: regsopen(r); break; default: respond(r, nil); } } static void fsread(Req *r) { switch(getfile(r)){ case Fregs: case Fkregs: regsread(r); break; case Fmem: memread(r); break; case Ftext: textread(r); break; case Fstatus: statusread(r); break; default: respond(r, Egreg); } } static void fswrite(Req *r) { switch(getfile(r)){ case Fctl: case Fnote: ctlwrite(r); break; default: respond(r, Egreg); } } static Srv fs = { .open = fsopen, .read = fsread, .write = fswrite, }; static void usage(void) { fprint(2, "usage: %s [-Dd] [-m mtpt] [-p pid] [-s srvname] text target\n", argv0); exits("usage"); } void main(int argc, char *argv[]) { char *mtpt, *pid, *srvname; File *dir; int i; mtpt = "/proc"; pid = "1"; srvname = nil; ARGBEGIN{ case 'D': chatty9p++; break; case 'd': chattygdb++; break; case 'm': mtpt = EARGF(usage()); break; case 'p': pid = EARGF(usage()); break; case 's': srvname = EARGF(usage()); break; default: usage(); }ARGEND if(argc < 2) usage(); text = open(argv[0], OREAD); if(text < 0) sysfatal("can't open %s: %r", argv[0]); if(!crackhdr(text, &fhdr)) sysfatal("can't decode file header: %s", argv[0]); if(regmap[mach->mtype] == nil) sysfatal("%s not supported", mach->name); if(gdbopen(argv[1]) < 0) sysfatal("can't open %s: %r", argv[1]); fs.tree = alloctree("gdbfs", "gdbfs", DMDIR|0555, nil); dir = createfile(fs.tree->root, pid, "gdbfs", DMDIR|0555, nil); for(i = 0; i < nelem(files); ++i) createfile(dir, files[i].name, dir->uid, files[i].mode, nil); postmountsrv(&fs, srvname, mtpt, MBEFORE); exits(nil); }