#include <u.h>
#include <libc.h>
#include <auth.h>
#include <thread.h>
#include <fcall.h>
#include <9p.h>
#include <ureg.h>
#include <bio.h>
#include <mach.h>
#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);
}
|