Plan 9 from Bell Labs’s /usr/web/sources/contrib/stallion/src/gdbfs/fs.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#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);
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].