xref: /inferno-os/emu/port/devprog.c (revision cb6deecc455ddb2a6a83cedaafc576838587d217)
137da2899SCharles.Forsyth #include	"dat.h"
237da2899SCharles.Forsyth #include	"fns.h"
337da2899SCharles.Forsyth #include	"error.h"
437da2899SCharles.Forsyth #include	<interp.h>
537da2899SCharles.Forsyth #include	<isa.h>
637da2899SCharles.Forsyth #include	"runt.h"
737da2899SCharles.Forsyth 
837da2899SCharles.Forsyth /*
937da2899SCharles.Forsyth  * Enable the heap device for environments that allow debugging =>
1037da2899SCharles.Forsyth  * Must be 1 for a production environment.
1137da2899SCharles.Forsyth  */
1237da2899SCharles.Forsyth int	SECURE = 0;
1337da2899SCharles.Forsyth 
1437da2899SCharles.Forsyth enum
1537da2899SCharles.Forsyth {
1637da2899SCharles.Forsyth 	Qdir,
1737da2899SCharles.Forsyth 	Qctl,
1837da2899SCharles.Forsyth 	Qdbgctl,
1937da2899SCharles.Forsyth 	Qheap,
2037da2899SCharles.Forsyth 	Qns,
2137da2899SCharles.Forsyth 	Qnsgrp,
2237da2899SCharles.Forsyth 	Qpgrp,
2337da2899SCharles.Forsyth 	Qstack,
2437da2899SCharles.Forsyth 	Qstatus,
2537da2899SCharles.Forsyth 	Qtext,
2637da2899SCharles.Forsyth 	Qwait,
2737da2899SCharles.Forsyth 	Qfd,
2837da2899SCharles.Forsyth 	Qexception,
2937da2899SCharles.Forsyth };
3037da2899SCharles.Forsyth 
3137da2899SCharles.Forsyth /*
3237da2899SCharles.Forsyth  * must be in same order as enum
3337da2899SCharles.Forsyth  */
3437da2899SCharles.Forsyth Dirtab progdir[] =
3537da2899SCharles.Forsyth {
3637da2899SCharles.Forsyth 	"ctl",		{Qctl},		0,			0200,
3737da2899SCharles.Forsyth 	"dbgctl",	{Qdbgctl},	0,			0600,
3837da2899SCharles.Forsyth 	"heap",		{Qheap},	0,			0600,
3937da2899SCharles.Forsyth 	"ns",		{Qns},		0,			0400,
4037da2899SCharles.Forsyth 	"nsgrp",	{Qnsgrp},	0,			0444,
4137da2899SCharles.Forsyth 	"pgrp",		{Qpgrp},	0,			0444,
4237da2899SCharles.Forsyth 	"stack",	{Qstack},	0,			0400,
4337da2899SCharles.Forsyth 	"status",	{Qstatus},	0,			0444,
4437da2899SCharles.Forsyth 	"text",		{Qtext},	0,			0000,
4537da2899SCharles.Forsyth 	"wait",		{Qwait},	0,			0400,
4637da2899SCharles.Forsyth 	"fd",		{Qfd},		0,			0400,
4737da2899SCharles.Forsyth 	"exception",	{Qexception},	0,	0400,
4837da2899SCharles.Forsyth };
4937da2899SCharles.Forsyth 
5037da2899SCharles.Forsyth enum
5137da2899SCharles.Forsyth {
5237da2899SCharles.Forsyth 	CMkill,
5337da2899SCharles.Forsyth 	CMkillgrp,
5437da2899SCharles.Forsyth 	CMrestricted,
5537da2899SCharles.Forsyth 	CMexceptions,
5637da2899SCharles.Forsyth 	CMprivate
5737da2899SCharles.Forsyth };
5837da2899SCharles.Forsyth 
5937da2899SCharles.Forsyth static
6037da2899SCharles.Forsyth Cmdtab progcmd[] = {
6137da2899SCharles.Forsyth 	CMkill,	"kill",	1,
6237da2899SCharles.Forsyth 	CMkillgrp,	"killgrp",	1,
6337da2899SCharles.Forsyth 	CMrestricted, "restricted", 1,
6437da2899SCharles.Forsyth 	CMexceptions, "exceptions", 2,
6537da2899SCharles.Forsyth 	CMprivate, "private",	1,
6637da2899SCharles.Forsyth };
6737da2899SCharles.Forsyth 
6837da2899SCharles.Forsyth enum
6937da2899SCharles.Forsyth {
7037da2899SCharles.Forsyth 	CDstep,
7137da2899SCharles.Forsyth 	CDtoret,
7237da2899SCharles.Forsyth 	CDcont,
7337da2899SCharles.Forsyth 	CDstart,
7437da2899SCharles.Forsyth 	CDstop,
7537da2899SCharles.Forsyth 	CDunstop,
7637da2899SCharles.Forsyth 	CDmaim,
7737da2899SCharles.Forsyth 	CDbpt
7837da2899SCharles.Forsyth };
7937da2899SCharles.Forsyth 
8037da2899SCharles.Forsyth static
8137da2899SCharles.Forsyth Cmdtab progdbgcmd[] = {
8237da2899SCharles.Forsyth 	CDstep,	"step",	0,	/* known below to be first, to cope with stepN */
8337da2899SCharles.Forsyth 	CDtoret,	"toret",	1,
8437da2899SCharles.Forsyth 	CDcont,	"cont",	1,
8537da2899SCharles.Forsyth 	CDstart,	"start",	1,
8637da2899SCharles.Forsyth 	CDstop,	"stop",	1,
8737da2899SCharles.Forsyth 	CDunstop,	"unstop",	1,
8837da2899SCharles.Forsyth 	CDmaim,	"maim",	1,
8937da2899SCharles.Forsyth 	CDbpt,	"bpt",	4,
9037da2899SCharles.Forsyth };
9137da2899SCharles.Forsyth 
9237da2899SCharles.Forsyth typedef struct Heapqry Heapqry;
9337da2899SCharles.Forsyth struct Heapqry
9437da2899SCharles.Forsyth {
9537da2899SCharles.Forsyth 	char	fmt;
9637da2899SCharles.Forsyth 	ulong	addr;
9737da2899SCharles.Forsyth 	ulong	module;
9837da2899SCharles.Forsyth 	int	count;
9937da2899SCharles.Forsyth };
10037da2899SCharles.Forsyth 
10137da2899SCharles.Forsyth typedef struct Bpt	Bpt;
10237da2899SCharles.Forsyth 
10337da2899SCharles.Forsyth struct Bpt
10437da2899SCharles.Forsyth {
10537da2899SCharles.Forsyth 	Bpt	*next;
10637da2899SCharles.Forsyth 	int	pc;
10737da2899SCharles.Forsyth 	char	*file;
10837da2899SCharles.Forsyth 	char	path[1];
10937da2899SCharles.Forsyth };
11037da2899SCharles.Forsyth 
11137da2899SCharles.Forsyth typedef struct Progctl Progctl;
11237da2899SCharles.Forsyth struct Progctl
11337da2899SCharles.Forsyth {
11437da2899SCharles.Forsyth 	Rendez	r;
11537da2899SCharles.Forsyth 	int	ref;
11637da2899SCharles.Forsyth 	Proc	*debugger;	/* waiting for dbgxec */
11737da2899SCharles.Forsyth 	char	*msg;		/* reply from dbgxec */
11837da2899SCharles.Forsyth 	int	step;		/* instructions to try */
11937da2899SCharles.Forsyth 	int	stop;		/* stop running the program */
12037da2899SCharles.Forsyth 	Bpt*	bpts;		/* active breakpoints */
12137da2899SCharles.Forsyth 	Queue*	q;		/* status queue */
12237da2899SCharles.Forsyth };
12337da2899SCharles.Forsyth 
12437da2899SCharles.Forsyth #define	QSHIFT		4		/* location in qid of pid */
12537da2899SCharles.Forsyth #define	QID(q)		(((ulong)(q).path&0x0000000F)>>0)
12637da2899SCharles.Forsyth #define QPID(pid)	(((pid)<<QSHIFT))
12737da2899SCharles.Forsyth #define	PID(q)		((q).vers)
12837da2899SCharles.Forsyth #define PATH(q)		((ulong)(q).path&~((1<<QSHIFT)-1))
12937da2899SCharles.Forsyth 
13037da2899SCharles.Forsyth static char *progstate[] =			/* must correspond to include/interp.h */
13137da2899SCharles.Forsyth {
13237da2899SCharles.Forsyth 	"alt",				/* blocked in alt instruction */
13337da2899SCharles.Forsyth 	"send",				/* waiting to send */
13437da2899SCharles.Forsyth 	"recv",				/* waiting to recv */
13537da2899SCharles.Forsyth 	"debug",			/* debugged */
13637da2899SCharles.Forsyth 	"ready",			/* ready to be scheduled */
13737da2899SCharles.Forsyth 	"release",			/* interpreter released */
13837da2899SCharles.Forsyth 	"exiting",			/* exit because of kill or error */
13937da2899SCharles.Forsyth 	"broken",			/* thread crashed */
14037da2899SCharles.Forsyth };
14137da2899SCharles.Forsyth 
14237da2899SCharles.Forsyth static	void	dbgstep(Progctl*, Prog*, int);
14337da2899SCharles.Forsyth static	void	dbgstart(Prog*);
14437da2899SCharles.Forsyth static	void	freebpts(Bpt*);
14537da2899SCharles.Forsyth static	Bpt*	delbpt(Bpt*, char*, int);
14637da2899SCharles.Forsyth static	Bpt*	setbpt(Bpt*, char*, int);
14737da2899SCharles.Forsyth static	void	mntscan(Mntwalk*, Pgrp*);
14837da2899SCharles.Forsyth extern	Type	*Trdchan;
14937da2899SCharles.Forsyth extern	Type	*Twrchan;
15037da2899SCharles.Forsyth extern	Module*	modules;
15137da2899SCharles.Forsyth static  char 	Emisalign[] = "misaligned address";
15237da2899SCharles.Forsyth 
15337da2899SCharles.Forsyth static int
proggen(Chan * c,char * name,Dirtab * tab,int ntab,int s,Dir * dp)15437da2899SCharles.Forsyth proggen(Chan *c, char *name, Dirtab *tab, int ntab, int s, Dir *dp)
15537da2899SCharles.Forsyth {
15637da2899SCharles.Forsyth 	Qid qid;
15737da2899SCharles.Forsyth 	Prog *p;
15837da2899SCharles.Forsyth 	char *e;
15937da2899SCharles.Forsyth 	Osenv *o;
16037da2899SCharles.Forsyth 	ulong pid, path, perm, len;
16137da2899SCharles.Forsyth 
16237da2899SCharles.Forsyth 	USED(ntab);
16337da2899SCharles.Forsyth 
16437da2899SCharles.Forsyth 	if(s == DEVDOTDOT){
16537da2899SCharles.Forsyth 		mkqid(&qid, Qdir, 0, QTDIR);
16637da2899SCharles.Forsyth 		devdir(c, qid, "#p", 0, eve, DMDIR|0555, dp);
16737da2899SCharles.Forsyth 		return 1;
16837da2899SCharles.Forsyth 	}
16937da2899SCharles.Forsyth 
17037da2899SCharles.Forsyth 	if((ulong)c->qid.path == Qdir) {
17137da2899SCharles.Forsyth 		if(name != nil){
17237da2899SCharles.Forsyth 			/* ignore s and use name to find pid */
17337da2899SCharles.Forsyth 			pid = strtoul(name, &e, 0);
17437da2899SCharles.Forsyth 			if(pid == 0 || *e != '\0')
17537da2899SCharles.Forsyth 				return -1;
17637da2899SCharles.Forsyth 			acquire();
17737da2899SCharles.Forsyth 			p = progpid(pid);
17837da2899SCharles.Forsyth 			if(p == nil){
17937da2899SCharles.Forsyth 				release();
18037da2899SCharles.Forsyth 				return -1;
18137da2899SCharles.Forsyth 			}
18237da2899SCharles.Forsyth 		}else{
18337da2899SCharles.Forsyth 			acquire();
18437da2899SCharles.Forsyth 			p = progn(s);
18537da2899SCharles.Forsyth 			if(p == nil) {
18637da2899SCharles.Forsyth 				release();
18737da2899SCharles.Forsyth 				return -1;
18837da2899SCharles.Forsyth 			}
18937da2899SCharles.Forsyth 			pid = p->pid;
19037da2899SCharles.Forsyth 		}
19137da2899SCharles.Forsyth 		o = p->osenv;
19237da2899SCharles.Forsyth 		sprint(up->genbuf, "%lud", pid);
19337da2899SCharles.Forsyth 		if(name != nil && strcmp(name, up->genbuf) != 0){
19437da2899SCharles.Forsyth 			release();
19537da2899SCharles.Forsyth 			return -1;
19637da2899SCharles.Forsyth 		}
19737da2899SCharles.Forsyth 		mkqid(&qid, pid<<QSHIFT, pid, QTDIR);
19837da2899SCharles.Forsyth 		devdir(c, qid, up->genbuf, 0, o->user, DMDIR|0555, dp);
19937da2899SCharles.Forsyth 		release();
20037da2899SCharles.Forsyth 		return 1;
20137da2899SCharles.Forsyth 	}
20237da2899SCharles.Forsyth 
20337da2899SCharles.Forsyth 	if(s >= nelem(progdir))
20437da2899SCharles.Forsyth 		return -1;
20537da2899SCharles.Forsyth 	tab = &progdir[s];
20637da2899SCharles.Forsyth 	path = PATH(c->qid);
20737da2899SCharles.Forsyth 
20837da2899SCharles.Forsyth 	acquire();
20937da2899SCharles.Forsyth 	p = progpid(PID(c->qid));
21037da2899SCharles.Forsyth 	if(p == nil) {
21137da2899SCharles.Forsyth 		release();
21237da2899SCharles.Forsyth 		return -1;
21337da2899SCharles.Forsyth 	}
21437da2899SCharles.Forsyth 
21537da2899SCharles.Forsyth 	o = p->osenv;
21637da2899SCharles.Forsyth 
21737da2899SCharles.Forsyth 	perm = tab->perm;
21837da2899SCharles.Forsyth 	if((perm & 7) == 0)
21937da2899SCharles.Forsyth 		perm = (perm|(perm>>3)|(perm>>6)) & o->pgrp->progmode;
22037da2899SCharles.Forsyth 
22137da2899SCharles.Forsyth 	len = tab->length;
22237da2899SCharles.Forsyth 	mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE);
22337da2899SCharles.Forsyth 	devdir(c, qid, tab->name, len, o->user, perm, dp);
22437da2899SCharles.Forsyth 	release();
22537da2899SCharles.Forsyth 	return 1;
22637da2899SCharles.Forsyth }
22737da2899SCharles.Forsyth 
22837da2899SCharles.Forsyth static Chan*
progattach(char * spec)22937da2899SCharles.Forsyth progattach(char *spec)
23037da2899SCharles.Forsyth {
23137da2899SCharles.Forsyth 	return devattach('p', spec);
23237da2899SCharles.Forsyth }
23337da2899SCharles.Forsyth 
23437da2899SCharles.Forsyth static Walkqid*
progwalk(Chan * c,Chan * nc,char ** name,int nname)23537da2899SCharles.Forsyth progwalk(Chan *c, Chan *nc, char **name, int nname)
23637da2899SCharles.Forsyth {
23737da2899SCharles.Forsyth 	return devwalk(c, nc, name, nname, 0, 0, proggen);
23837da2899SCharles.Forsyth }
23937da2899SCharles.Forsyth 
24037da2899SCharles.Forsyth static int
progstat(Chan * c,uchar * db,int n)24137da2899SCharles.Forsyth progstat(Chan *c, uchar *db, int n)
24237da2899SCharles.Forsyth {
24337da2899SCharles.Forsyth 	return devstat(c, db, n, 0, 0, proggen);
24437da2899SCharles.Forsyth }
24537da2899SCharles.Forsyth 
24637da2899SCharles.Forsyth static Chan*
progopen(Chan * c,int omode)24737da2899SCharles.Forsyth progopen(Chan *c, int omode)
24837da2899SCharles.Forsyth {
24937da2899SCharles.Forsyth 	Prog *p;
25037da2899SCharles.Forsyth 	Osenv *o;
25137da2899SCharles.Forsyth 	Progctl *ctl;
25237da2899SCharles.Forsyth 	int perm;
25337da2899SCharles.Forsyth 
25437da2899SCharles.Forsyth 	if(c->qid.type & QTDIR)
25537da2899SCharles.Forsyth 		return devopen(c, omode, 0, 0, proggen);
25637da2899SCharles.Forsyth 
25737da2899SCharles.Forsyth 	acquire();
25837da2899SCharles.Forsyth 	if (waserror()) {
25937da2899SCharles.Forsyth 		release();
26037da2899SCharles.Forsyth 		nexterror();
26137da2899SCharles.Forsyth 	}
26237da2899SCharles.Forsyth 	p = progpid(PID(c->qid));
26337da2899SCharles.Forsyth 	if(p == nil)
26437da2899SCharles.Forsyth 		error(Ethread);
26537da2899SCharles.Forsyth 	o = p->osenv;
26637da2899SCharles.Forsyth 	perm = progdir[QID(c->qid)-1].perm;
26737da2899SCharles.Forsyth 	if((perm & 7) == 0)
26837da2899SCharles.Forsyth 		perm = (perm|(perm>>3)|(perm>>6)) & o->pgrp->progmode;
26937da2899SCharles.Forsyth 	devpermcheck(o->user, perm, omode);
27037da2899SCharles.Forsyth 	omode = openmode(omode);
27137da2899SCharles.Forsyth 
27237da2899SCharles.Forsyth 	switch(QID(c->qid)){
27337da2899SCharles.Forsyth 	default:
27437da2899SCharles.Forsyth 		error(Egreg);
27537da2899SCharles.Forsyth 	case Qnsgrp:
27637da2899SCharles.Forsyth 	case Qpgrp:
27737da2899SCharles.Forsyth 	case Qtext:
27837da2899SCharles.Forsyth 	case Qstatus:
27937da2899SCharles.Forsyth 	case Qstack:
28037da2899SCharles.Forsyth 	case Qctl:
28137da2899SCharles.Forsyth 	case Qfd:
28237da2899SCharles.Forsyth 	case Qexception:
28337da2899SCharles.Forsyth 		break;
28437da2899SCharles.Forsyth 	case Qwait:
28537da2899SCharles.Forsyth 		c->aux = qopen(1024, Qmsg, nil, nil);
28637da2899SCharles.Forsyth 		if(c->aux == nil)
28737da2899SCharles.Forsyth 			error(Enomem);
28837da2899SCharles.Forsyth 		o->childq = c->aux;
28937da2899SCharles.Forsyth 		break;
29037da2899SCharles.Forsyth 	case Qns:
29137da2899SCharles.Forsyth 		c->aux = malloc(sizeof(Mntwalk));
29237da2899SCharles.Forsyth 		if(c->aux == nil)
29337da2899SCharles.Forsyth 			error(Enomem);
29437da2899SCharles.Forsyth 		break;
29537da2899SCharles.Forsyth 	case Qheap:
296*cb6deeccSforsyth 		if(SECURE || p->group->flags&Pprivatemem || omode != ORDWR)
29737da2899SCharles.Forsyth 			error(Eperm);
29837da2899SCharles.Forsyth 		c->aux = malloc(sizeof(Heapqry));
29937da2899SCharles.Forsyth 		if(c->aux == nil)
30037da2899SCharles.Forsyth 			error(Enomem);
30137da2899SCharles.Forsyth 		break;
30237da2899SCharles.Forsyth 	case Qdbgctl:
303*cb6deeccSforsyth 		if(SECURE || p->group->flags&Pprivatemem || omode != ORDWR)
30437da2899SCharles.Forsyth 			error(Eperm);
30537da2899SCharles.Forsyth 		ctl = malloc(sizeof(Progctl));
30637da2899SCharles.Forsyth 		if(ctl == nil)
30737da2899SCharles.Forsyth 			error(Enomem);
30837da2899SCharles.Forsyth 		ctl->q = qopen(1024, Qmsg, nil, nil);
30937da2899SCharles.Forsyth 		if(ctl->q == nil) {
31037da2899SCharles.Forsyth 			free(ctl);
31137da2899SCharles.Forsyth 			error(Enomem);
31237da2899SCharles.Forsyth 		}
31337da2899SCharles.Forsyth 		ctl->bpts = nil;
31437da2899SCharles.Forsyth 		ctl->ref = 1;
31537da2899SCharles.Forsyth 		c->aux = ctl;
31637da2899SCharles.Forsyth 		break;
31737da2899SCharles.Forsyth 	}
31837da2899SCharles.Forsyth 	if(p->state != Pexiting)
31937da2899SCharles.Forsyth 		c->qid.vers = p->pid;
32037da2899SCharles.Forsyth 
32137da2899SCharles.Forsyth 	poperror();
32237da2899SCharles.Forsyth 	release();
32337da2899SCharles.Forsyth 	c->offset = 0;
32437da2899SCharles.Forsyth 	c->mode = omode;
32537da2899SCharles.Forsyth 	c->flag |= COPEN;
32637da2899SCharles.Forsyth 	return c;
32737da2899SCharles.Forsyth }
32837da2899SCharles.Forsyth 
32937da2899SCharles.Forsyth static int
progwstat(Chan * c,uchar * db,int n)33037da2899SCharles.Forsyth progwstat(Chan *c, uchar *db, int n)
33137da2899SCharles.Forsyth {
33237da2899SCharles.Forsyth 	Dir d;
33337da2899SCharles.Forsyth 	Prog *p;
33437da2899SCharles.Forsyth 	char *u;
33537da2899SCharles.Forsyth 	Osenv *o;
33637da2899SCharles.Forsyth 
33737da2899SCharles.Forsyth 	if(c->qid.type&QTDIR)
33837da2899SCharles.Forsyth 		error(Eperm);
33937da2899SCharles.Forsyth 	acquire();
34037da2899SCharles.Forsyth 	p = progpid(PID(c->qid));
34137da2899SCharles.Forsyth 	if(p == nil) {
34237da2899SCharles.Forsyth 		release();
34337da2899SCharles.Forsyth 		error(Ethread);
34437da2899SCharles.Forsyth 	}
34537da2899SCharles.Forsyth 
34637da2899SCharles.Forsyth 	u = up->env->user;
34737da2899SCharles.Forsyth 	o = p->osenv;
34837da2899SCharles.Forsyth 	if(strcmp(u, o->user) != 0 && strcmp(u, eve) != 0) {
34937da2899SCharles.Forsyth 		release();
35037da2899SCharles.Forsyth 		error(Eperm);
35137da2899SCharles.Forsyth 	}
35237da2899SCharles.Forsyth 
35337da2899SCharles.Forsyth 	n = convM2D(db, n, &d, nil);
35437da2899SCharles.Forsyth 	if(n == 0){
35537da2899SCharles.Forsyth 		release();
35637da2899SCharles.Forsyth 		error(Eshortstat);
35737da2899SCharles.Forsyth 	}
35837da2899SCharles.Forsyth 	if(d.mode != ~0UL)
35937da2899SCharles.Forsyth 		o->pgrp->progmode = d.mode&0777;
36037da2899SCharles.Forsyth 	release();
36137da2899SCharles.Forsyth 	return n;
36237da2899SCharles.Forsyth }
36337da2899SCharles.Forsyth 
36437da2899SCharles.Forsyth static void
closedbgctl(Progctl * ctl,Prog * p)36537da2899SCharles.Forsyth closedbgctl(Progctl *ctl, Prog *p)
36637da2899SCharles.Forsyth {
36737da2899SCharles.Forsyth 	Osenv *o;
36837da2899SCharles.Forsyth 
36937da2899SCharles.Forsyth 	if(ctl->ref-- > 1)
37037da2899SCharles.Forsyth 		return;
37137da2899SCharles.Forsyth 	freebpts(ctl->bpts);
37237da2899SCharles.Forsyth 	if(p != nil){
37337da2899SCharles.Forsyth 		o = p->osenv;
37437da2899SCharles.Forsyth 		if(o->debug == ctl){
37537da2899SCharles.Forsyth 			o->debug = nil;
37637da2899SCharles.Forsyth 			p->xec = xec;
37737da2899SCharles.Forsyth 		}
37837da2899SCharles.Forsyth 	}
37937da2899SCharles.Forsyth 	qfree(ctl->q);
38037da2899SCharles.Forsyth 	free(ctl);
38137da2899SCharles.Forsyth }
38237da2899SCharles.Forsyth 
38337da2899SCharles.Forsyth static void
progclose(Chan * c)38437da2899SCharles.Forsyth progclose(Chan *c)
38537da2899SCharles.Forsyth {
38637da2899SCharles.Forsyth 	int i;
38737da2899SCharles.Forsyth 	Prog *f;
38837da2899SCharles.Forsyth 	Osenv *o;
38937da2899SCharles.Forsyth 	Progctl *ctl;
39037da2899SCharles.Forsyth 
39137da2899SCharles.Forsyth 	switch(QID(c->qid)) {
39237da2899SCharles.Forsyth 	case Qns:
39337da2899SCharles.Forsyth 	case Qheap:
39437da2899SCharles.Forsyth 		free(c->aux);
39537da2899SCharles.Forsyth 		break;
39637da2899SCharles.Forsyth 	case Qdbgctl:
39737da2899SCharles.Forsyth 		if((c->flag & COPEN) == 0)
39837da2899SCharles.Forsyth 			return;
39937da2899SCharles.Forsyth 		ctl = c->aux;
40037da2899SCharles.Forsyth 		acquire();
40137da2899SCharles.Forsyth 		closedbgctl(ctl, progpid(PID(c->qid)));
40237da2899SCharles.Forsyth 		release();
40337da2899SCharles.Forsyth 		break;
40437da2899SCharles.Forsyth 	case Qwait:
40537da2899SCharles.Forsyth 		acquire();
40637da2899SCharles.Forsyth 		i = 0;
40737da2899SCharles.Forsyth 		for(;;) {
40837da2899SCharles.Forsyth 			f = progn(i++);
40937da2899SCharles.Forsyth 			if(f == nil)
41037da2899SCharles.Forsyth 				break;
41137da2899SCharles.Forsyth 			o = f->osenv;
41237da2899SCharles.Forsyth 			if(o->waitq == c->aux)
41337da2899SCharles.Forsyth 				o->waitq = nil;
41437da2899SCharles.Forsyth 			if(o->childq == c->aux)
41537da2899SCharles.Forsyth 				o->childq = nil;
41637da2899SCharles.Forsyth 		}
41737da2899SCharles.Forsyth 		release();
41837da2899SCharles.Forsyth 		qfree(c->aux);
41937da2899SCharles.Forsyth 	}
42037da2899SCharles.Forsyth }
42137da2899SCharles.Forsyth 
42237da2899SCharles.Forsyth static int
progsize(Prog * p)42337da2899SCharles.Forsyth progsize(Prog *p)
42437da2899SCharles.Forsyth {
42537da2899SCharles.Forsyth 	int size;
42637da2899SCharles.Forsyth 	Frame *f;
42737da2899SCharles.Forsyth 	uchar *fp;
42837da2899SCharles.Forsyth 	Modlink *m;
42937da2899SCharles.Forsyth 
43037da2899SCharles.Forsyth 	m = p->R.M;
43137da2899SCharles.Forsyth 	size = 0;
43237da2899SCharles.Forsyth 	if(m->MP != H)
43337da2899SCharles.Forsyth 		size += hmsize(D2H(m->MP));
43437da2899SCharles.Forsyth 	if(m->prog != nil)
43537da2899SCharles.Forsyth 		size += msize(m->prog);
43637da2899SCharles.Forsyth 
43737da2899SCharles.Forsyth 	fp = p->R.FP;
43837da2899SCharles.Forsyth 	while(fp != nil) {
43937da2899SCharles.Forsyth 		f = (Frame*)fp;
44037da2899SCharles.Forsyth 		fp = f->fp;
44137da2899SCharles.Forsyth 		if(f->mr != nil) {
44237da2899SCharles.Forsyth 			if(f->mr->MP != H)
44337da2899SCharles.Forsyth 				size += hmsize(D2H(f->mr->MP));
44437da2899SCharles.Forsyth 			if(f->mr->prog != nil)
44537da2899SCharles.Forsyth 				size += msize(f->mr->prog);
44637da2899SCharles.Forsyth 		}
44737da2899SCharles.Forsyth 		if(f->t == nil)
44837da2899SCharles.Forsyth 			size += msize(SEXTYPE(f));
44937da2899SCharles.Forsyth 	}
45037da2899SCharles.Forsyth 	return size/1024;
45137da2899SCharles.Forsyth }
45237da2899SCharles.Forsyth 
45337da2899SCharles.Forsyth static long
progoffset(long offset,char * va,int * np)45437da2899SCharles.Forsyth progoffset(long offset, char *va, int *np)
45537da2899SCharles.Forsyth {
45637da2899SCharles.Forsyth 	if(offset > 0) {
45737da2899SCharles.Forsyth 		offset -= *np;
45837da2899SCharles.Forsyth 		if(offset < 0) {
45937da2899SCharles.Forsyth 			memmove(va, va+*np+offset, -offset);
46037da2899SCharles.Forsyth 			*np = -offset;
46137da2899SCharles.Forsyth 		}
46237da2899SCharles.Forsyth 		else
46337da2899SCharles.Forsyth 			*np = 0;
46437da2899SCharles.Forsyth 	}
46537da2899SCharles.Forsyth 	return offset;
46637da2899SCharles.Forsyth }
46737da2899SCharles.Forsyth 
46837da2899SCharles.Forsyth static int
progqidwidth(Chan * c)46937da2899SCharles.Forsyth progqidwidth(Chan *c)
47037da2899SCharles.Forsyth {
47137da2899SCharles.Forsyth 	char buf[32];
47237da2899SCharles.Forsyth 
47337da2899SCharles.Forsyth 	return sprint(buf, "%lud", c->qid.vers);
47437da2899SCharles.Forsyth }
47537da2899SCharles.Forsyth 
47637da2899SCharles.Forsyth int
progfdprint(Chan * c,int fd,int w,char * s,int ns)47737da2899SCharles.Forsyth progfdprint(Chan *c, int fd, int w, char *s, int ns)
47837da2899SCharles.Forsyth {
47937da2899SCharles.Forsyth 	int n;
48037da2899SCharles.Forsyth 
48137da2899SCharles.Forsyth 	if(w == 0)
48237da2899SCharles.Forsyth 		w = progqidwidth(c);
48337da2899SCharles.Forsyth 	n = snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %*lud %.2ux) %5ld %8lld %s\n",
48437da2899SCharles.Forsyth 		fd,
48537da2899SCharles.Forsyth 		&"r w rw"[(c->mode&3)<<1],
48637da2899SCharles.Forsyth 		devtab[c->type]->dc, c->dev,
48737da2899SCharles.Forsyth 		c->qid.path, w, c->qid.vers, c->qid.type,
48837da2899SCharles.Forsyth 		c->iounit, c->offset, c->name->s);
48937da2899SCharles.Forsyth 	return n;
49037da2899SCharles.Forsyth }
49137da2899SCharles.Forsyth 
49237da2899SCharles.Forsyth static int
progfds(Osenv * o,char * va,int count,long offset)49337da2899SCharles.Forsyth progfds(Osenv *o, char *va, int count, long offset)
49437da2899SCharles.Forsyth {
49537da2899SCharles.Forsyth 	Fgrp *f;
49637da2899SCharles.Forsyth 	Chan *c;
49737da2899SCharles.Forsyth 	int n, i, w, ww;
49837da2899SCharles.Forsyth 
49937da2899SCharles.Forsyth 	f = o->fgrp;	/* f is not locked because we've acquired */
50037da2899SCharles.Forsyth 	n = readstr(0, va, count, o->pgrp->dot->name->s);
50137da2899SCharles.Forsyth 	n += snprint(va+n, count-n, "\n");
50237da2899SCharles.Forsyth 	offset = progoffset(offset, va, &n);
50337da2899SCharles.Forsyth 	/* compute width of qid.path */
50437da2899SCharles.Forsyth 	w = 0;
50537da2899SCharles.Forsyth 	for(i = 0; i <= f->maxfd; i++) {
50637da2899SCharles.Forsyth 		c = f->fd[i];
50737da2899SCharles.Forsyth 		if(c == nil)
50837da2899SCharles.Forsyth 			continue;
50937da2899SCharles.Forsyth 		ww = progqidwidth(c);
51037da2899SCharles.Forsyth 		if(ww > w)
51137da2899SCharles.Forsyth 			w = ww;
51237da2899SCharles.Forsyth 	}
51337da2899SCharles.Forsyth 	for(i = 0; i <= f->maxfd; i++) {
51437da2899SCharles.Forsyth 		c = f->fd[i];
51537da2899SCharles.Forsyth 		if(c == nil)
51637da2899SCharles.Forsyth 			continue;
51737da2899SCharles.Forsyth 		n += progfdprint(c, i, w, va+n, count-n);
51837da2899SCharles.Forsyth 		offset = progoffset(offset, va, &n);
51937da2899SCharles.Forsyth 	}
52037da2899SCharles.Forsyth 	return n;
52137da2899SCharles.Forsyth }
52237da2899SCharles.Forsyth 
52337da2899SCharles.Forsyth Inst *
pc2dispc(Inst * pc,Module * mod)52437da2899SCharles.Forsyth pc2dispc(Inst *pc, Module *mod)
52537da2899SCharles.Forsyth {
52637da2899SCharles.Forsyth 	ulong l, u, m, v;
52737da2899SCharles.Forsyth 	ulong *tab = mod->pctab;
52837da2899SCharles.Forsyth 
52937da2899SCharles.Forsyth 	v = (ulong)pc - (ulong)mod->prog;
53037da2899SCharles.Forsyth 	l = 0;
53137da2899SCharles.Forsyth 	u = mod->nprog-1;
53237da2899SCharles.Forsyth 	while(l < u){
53337da2899SCharles.Forsyth 		m = (l+u+1)/2;
53437da2899SCharles.Forsyth 		if(tab[m] < v)
53537da2899SCharles.Forsyth 			l = m;
53637da2899SCharles.Forsyth 		else if(tab[m] > v)
53737da2899SCharles.Forsyth 			u = m-1;
53837da2899SCharles.Forsyth 		else
53937da2899SCharles.Forsyth 			l = u = m;
54037da2899SCharles.Forsyth 	}
54137da2899SCharles.Forsyth 	if(l == u && tab[u] <= v && u != mod->nprog-1 && tab[u+1] > v)
54237da2899SCharles.Forsyth 		return &mod->prog[u];
54337da2899SCharles.Forsyth 	return 0;
54437da2899SCharles.Forsyth }
54537da2899SCharles.Forsyth 
54637da2899SCharles.Forsyth static int
progstack(REG * reg,int state,char * va,int count,long offset)54737da2899SCharles.Forsyth progstack(REG *reg, int state, char *va, int count, long offset)
54837da2899SCharles.Forsyth {
54937da2899SCharles.Forsyth 	int n;
55037da2899SCharles.Forsyth 	Frame *f;
55137da2899SCharles.Forsyth 	Inst *pc;
55237da2899SCharles.Forsyth 	uchar *fp;
55337da2899SCharles.Forsyth 	Modlink *m;
55437da2899SCharles.Forsyth 
55537da2899SCharles.Forsyth 	n = 0;
55637da2899SCharles.Forsyth 	m = reg->M;
55737da2899SCharles.Forsyth 	fp = reg->FP;
55837da2899SCharles.Forsyth 	pc = reg->PC;
55937da2899SCharles.Forsyth 
56037da2899SCharles.Forsyth 	/*
56137da2899SCharles.Forsyth 	 * all states other than debug and ready block,
56237da2899SCharles.Forsyth 	 * but interp has already advanced the PC
56337da2899SCharles.Forsyth 	 */
56437da2899SCharles.Forsyth 	if(!m->compiled && state != Pready && state != Pdebug && pc > m->prog)
56537da2899SCharles.Forsyth 		pc--;
56637da2899SCharles.Forsyth 	if(m->compiled && m->m->pctab != nil)
56737da2899SCharles.Forsyth 		pc = pc2dispc(pc, m->m);
56837da2899SCharles.Forsyth 
56937da2899SCharles.Forsyth 	while(fp != nil) {
57037da2899SCharles.Forsyth 		f = (Frame*)fp;
57137da2899SCharles.Forsyth 		n += snprint(va+n, count-n, "%.8lux %.8lux %.8lux %.8lux %d %s\n",
57237da2899SCharles.Forsyth 				(ulong)f,		/* FP */
57337da2899SCharles.Forsyth 				(ulong)(pc - m->prog),	/* PC in dis instructions */
57437da2899SCharles.Forsyth 				(ulong)m->MP,		/* MP */
57537da2899SCharles.Forsyth 				(ulong)m->prog,	/* Code for module */
57637da2899SCharles.Forsyth 				m->compiled && m->m->pctab == nil,	/* True if native assembler: fool stack utility for now */
57737da2899SCharles.Forsyth 				m->m->path);	/* File system path */
57837da2899SCharles.Forsyth 
57937da2899SCharles.Forsyth 		if(offset > 0) {
58037da2899SCharles.Forsyth 			offset -= n;
58137da2899SCharles.Forsyth 			if(offset < 0) {
58237da2899SCharles.Forsyth 				memmove(va, va+n+offset, -offset);
58337da2899SCharles.Forsyth 				n = -offset;
58437da2899SCharles.Forsyth 			}
58537da2899SCharles.Forsyth 			else
58637da2899SCharles.Forsyth 				n = 0;
58737da2899SCharles.Forsyth 		}
58837da2899SCharles.Forsyth 
58937da2899SCharles.Forsyth 		pc = f->lr;
59037da2899SCharles.Forsyth 		fp = f->fp;
59137da2899SCharles.Forsyth 		if(f->mr != nil)
59237da2899SCharles.Forsyth 			m = f->mr;
59337da2899SCharles.Forsyth 		if(!m->compiled)
59437da2899SCharles.Forsyth 			pc--;
59537da2899SCharles.Forsyth 		else if(m->m->pctab != nil)
59637da2899SCharles.Forsyth 			pc = pc2dispc(pc, m->m)-1;
59737da2899SCharles.Forsyth 	}
59837da2899SCharles.Forsyth 	return n;
59937da2899SCharles.Forsyth }
60037da2899SCharles.Forsyth 
60137da2899SCharles.Forsyth static int
calldepth(REG * reg)60237da2899SCharles.Forsyth calldepth(REG *reg)
60337da2899SCharles.Forsyth {
60437da2899SCharles.Forsyth 	int n;
60537da2899SCharles.Forsyth 	uchar *fp;
60637da2899SCharles.Forsyth 
60737da2899SCharles.Forsyth 	n = 0;
60837da2899SCharles.Forsyth 	for(fp = reg->FP; fp != nil; fp = ((Frame*)fp)->fp)
60937da2899SCharles.Forsyth 		n++;
61037da2899SCharles.Forsyth 	return n;
61137da2899SCharles.Forsyth }
61237da2899SCharles.Forsyth 
61337da2899SCharles.Forsyth static int
progheap(Heapqry * hq,char * va,int count,ulong offset)61437da2899SCharles.Forsyth progheap(Heapqry *hq, char *va, int count, ulong offset)
61537da2899SCharles.Forsyth {
61637da2899SCharles.Forsyth 	WORD *w;
61737da2899SCharles.Forsyth 	void *p;
61837da2899SCharles.Forsyth 	List *hd;
61937da2899SCharles.Forsyth 	Array *a;
62037da2899SCharles.Forsyth 	char *fmt, *str;
62137da2899SCharles.Forsyth 	Module *m;
62237da2899SCharles.Forsyth 	Modlink *ml;
62337da2899SCharles.Forsyth 	Channel *c;
62437da2899SCharles.Forsyth 	ulong addr;
62537da2899SCharles.Forsyth 	String *ss;
62637da2899SCharles.Forsyth 	union { REAL r; LONG l; WORD w[2]; } rock;
62737da2899SCharles.Forsyth 	int i, s, n, len, signed_off;
62837da2899SCharles.Forsyth 	Type *t;
62937da2899SCharles.Forsyth 
63037da2899SCharles.Forsyth 	n = 0;
63137da2899SCharles.Forsyth 	s = 0;
63237da2899SCharles.Forsyth 	signed_off = offset;
63337da2899SCharles.Forsyth 	addr = hq->addr;
63437da2899SCharles.Forsyth 	for(i = 0; i < hq->count; i++) {
63537da2899SCharles.Forsyth 		switch(hq->fmt) {
63637da2899SCharles.Forsyth 		case 'W':
63737da2899SCharles.Forsyth 			if(addr & 3)
63837da2899SCharles.Forsyth 				return -1;
63937da2899SCharles.Forsyth 			n += snprint(va+n, count-n, "%d\n", *(WORD*)addr);
64037da2899SCharles.Forsyth 			s = sizeof(WORD);
64137da2899SCharles.Forsyth 			break;
64237da2899SCharles.Forsyth 		case 'B':
64337da2899SCharles.Forsyth 			n += snprint(va+n, count-n, "%d\n", *(BYTE*)addr);
64437da2899SCharles.Forsyth 			s = sizeof(BYTE);
64537da2899SCharles.Forsyth 			break;
64637da2899SCharles.Forsyth 		case 'V':
64737da2899SCharles.Forsyth 			if(addr & 3)
64837da2899SCharles.Forsyth 				return -1;
64937da2899SCharles.Forsyth 			w = (WORD*)addr;
65037da2899SCharles.Forsyth 			rock.w[0] = w[0];
65137da2899SCharles.Forsyth 			rock.w[1] = w[1];
65237da2899SCharles.Forsyth 			n += snprint(va+n, count-n, "%lld\n", rock.l);
65337da2899SCharles.Forsyth 			s = sizeof(LONG);
65437da2899SCharles.Forsyth 			break;
65537da2899SCharles.Forsyth 		case 'R':
65637da2899SCharles.Forsyth 			if(addr & 3)
65737da2899SCharles.Forsyth 				return -1;
65837da2899SCharles.Forsyth 			w = (WORD*)addr;
65937da2899SCharles.Forsyth 			rock.w[0] = w[0];
66037da2899SCharles.Forsyth 			rock.w[1] = w[1];
66137da2899SCharles.Forsyth 			n += snprint(va+n, count-n, "%g\n", rock.r);
66237da2899SCharles.Forsyth 			s = sizeof(REAL);
66337da2899SCharles.Forsyth 			break;
66437da2899SCharles.Forsyth 		case 'I':
66537da2899SCharles.Forsyth 			if(addr & 3)
66637da2899SCharles.Forsyth 				return -1;
66737da2899SCharles.Forsyth 			for(m = modules; m != nil; m = m->link)
66837da2899SCharles.Forsyth 				if(m == (Module*)hq->module)
66937da2899SCharles.Forsyth 					break;
67037da2899SCharles.Forsyth 			if(m == nil)
67137da2899SCharles.Forsyth 				error(Ebadctl);
67237da2899SCharles.Forsyth 			addr = (ulong)(m->prog+addr);
67337da2899SCharles.Forsyth 			n += snprint(va+n, count-n, "%D\n", (Inst*)addr);
67437da2899SCharles.Forsyth 			s = sizeof(Inst);
67537da2899SCharles.Forsyth 			break;
67637da2899SCharles.Forsyth 		case 'P':
67737da2899SCharles.Forsyth 			if(addr & 3)
67837da2899SCharles.Forsyth 				return -1;
67937da2899SCharles.Forsyth 			p = *(void**)addr;
68037da2899SCharles.Forsyth 			fmt = "nil\n";
68137da2899SCharles.Forsyth 			if(p != H)
68237da2899SCharles.Forsyth 				fmt = "%lux\n";
68337da2899SCharles.Forsyth 			n += snprint(va+n, count-n, fmt, p);
68437da2899SCharles.Forsyth 			s = sizeof(WORD);
68537da2899SCharles.Forsyth 			break;
68637da2899SCharles.Forsyth 		case 'L':
68737da2899SCharles.Forsyth 			if(addr & 3)
68837da2899SCharles.Forsyth 				return -1;
68937da2899SCharles.Forsyth 			hd = *(List**)addr;
69037da2899SCharles.Forsyth 			if(hd == H || D2H(hd)->t != &Tlist)
69137da2899SCharles.Forsyth 				return -1;
69237da2899SCharles.Forsyth 			n += snprint(va+n, count-n, "%lux.%lux\n", (ulong)&hd->tail, (ulong)hd->data);
69337da2899SCharles.Forsyth 			s = sizeof(WORD);
69437da2899SCharles.Forsyth 			break;
69537da2899SCharles.Forsyth 		case 'A':
69637da2899SCharles.Forsyth 			if(addr & 3)
69737da2899SCharles.Forsyth 				return -1;
69837da2899SCharles.Forsyth 			a = *(Array**)addr;
69937da2899SCharles.Forsyth 			if(a == H)
70037da2899SCharles.Forsyth 				n += snprint(va+n, count-n, "nil\n");
70137da2899SCharles.Forsyth 			else {
70237da2899SCharles.Forsyth 				if(D2H(a)->t != &Tarray)
70337da2899SCharles.Forsyth 					return -1;
70437da2899SCharles.Forsyth 				n += snprint(va+n, count-n, "%d.%lux\n", a->len, (ulong)a->data);
70537da2899SCharles.Forsyth 			}
70637da2899SCharles.Forsyth 			s = sizeof(WORD);
70737da2899SCharles.Forsyth 			break;
70837da2899SCharles.Forsyth 		case 'C':
70937da2899SCharles.Forsyth 			if(addr & 3)
71037da2899SCharles.Forsyth 				return -1;
71137da2899SCharles.Forsyth 			ss = *(String**)addr;
71237da2899SCharles.Forsyth 			if(ss == H)
71337da2899SCharles.Forsyth 				ss = &snil;
71437da2899SCharles.Forsyth 			else
71537da2899SCharles.Forsyth 			if(D2H(ss)->t != &Tstring)
71637da2899SCharles.Forsyth 				return -1;
71737da2899SCharles.Forsyth 			n += snprint(va+n, count-n, "%d.", abs(ss->len));
71837da2899SCharles.Forsyth 			str = string2c(ss);
71937da2899SCharles.Forsyth 			len = strlen(str);
72037da2899SCharles.Forsyth 			if(count-n < len)
72137da2899SCharles.Forsyth 				len = count-n;
72237da2899SCharles.Forsyth 			if(len > 0) {
72337da2899SCharles.Forsyth 				memmove(va+n, str, len);
72437da2899SCharles.Forsyth 				n += len;
72537da2899SCharles.Forsyth 			}
72637da2899SCharles.Forsyth 			break;
72737da2899SCharles.Forsyth 		case 'M':
72837da2899SCharles.Forsyth 			if(addr & 3)
72937da2899SCharles.Forsyth 				return -1;
73037da2899SCharles.Forsyth 			ml = *(Modlink**)addr;
73137da2899SCharles.Forsyth 			fmt = ml == H ? "nil\n" : "%lux\n";
73237da2899SCharles.Forsyth 			n += snprint(va+n, count-n, fmt, ml->MP);
73337da2899SCharles.Forsyth 			s = sizeof(WORD);
73437da2899SCharles.Forsyth 			break;
73537da2899SCharles.Forsyth 		case 'c':
73637da2899SCharles.Forsyth 			if(addr & 3)
73737da2899SCharles.Forsyth 				return -1;
73837da2899SCharles.Forsyth 			c = *(Channel**)addr;
73937da2899SCharles.Forsyth 			if(c == H)
74037da2899SCharles.Forsyth 				n += snprint(va+n, count-n, "nil\n");
74137da2899SCharles.Forsyth 			else{
74237da2899SCharles.Forsyth 				t = D2H(c)->t;
74337da2899SCharles.Forsyth 				if(t != &Tchannel && t != Trdchan && t != Twrchan)
74437da2899SCharles.Forsyth 					return -1;
74537da2899SCharles.Forsyth 				if(c->buf == H)
74637da2899SCharles.Forsyth 					n += snprint(va+n, count-n, "0.%lux\n", (ulong)c);
74737da2899SCharles.Forsyth 				else
74837da2899SCharles.Forsyth 					n += snprint(va+n, count-n, "%d.%lux.%d.%d\n", c->buf->len, (ulong)c->buf->data, c->front, c->size);
74937da2899SCharles.Forsyth 			}
75037da2899SCharles.Forsyth 			break;
75137da2899SCharles.Forsyth 
75237da2899SCharles.Forsyth 		}
75337da2899SCharles.Forsyth 		addr += s;
75437da2899SCharles.Forsyth 		if(signed_off > 0) {
75537da2899SCharles.Forsyth 			signed_off -= n;
75637da2899SCharles.Forsyth 			if(signed_off < 0) {
75737da2899SCharles.Forsyth 				memmove(va, va+n+signed_off, -signed_off);
75837da2899SCharles.Forsyth 				n = -signed_off;
75937da2899SCharles.Forsyth 			}
76037da2899SCharles.Forsyth 			else
76137da2899SCharles.Forsyth 				n = 0;
76237da2899SCharles.Forsyth 		}
76337da2899SCharles.Forsyth 	}
76437da2899SCharles.Forsyth 	return n;
76537da2899SCharles.Forsyth }
76637da2899SCharles.Forsyth 
76737da2899SCharles.Forsyth WORD
modstatus(REG * r,char * ptr,int len)76837da2899SCharles.Forsyth modstatus(REG *r, char *ptr, int len)
76937da2899SCharles.Forsyth {
77037da2899SCharles.Forsyth 	Inst *PC;
77137da2899SCharles.Forsyth 	Frame *f;
77237da2899SCharles.Forsyth 
77337da2899SCharles.Forsyth 	if(r->M->m->name[0] == '$') {
77437da2899SCharles.Forsyth 		f = (Frame*)r->FP;
77537da2899SCharles.Forsyth 		snprint(ptr, len, "%s[%s]", f->mr->m->name, r->M->m->name);
77637da2899SCharles.Forsyth 		if(f->mr->compiled)
77737da2899SCharles.Forsyth 			return (WORD)f->lr;
77837da2899SCharles.Forsyth 		return f->lr - f->mr->prog;
77937da2899SCharles.Forsyth 	}
78037da2899SCharles.Forsyth 	memmove(ptr, r->M->m->name, len);
78137da2899SCharles.Forsyth 	if(r->M->compiled)
78237da2899SCharles.Forsyth 		return (WORD)r->PC;
78337da2899SCharles.Forsyth 	PC = r->PC;
78437da2899SCharles.Forsyth 	/* should really check for blocked states */
78537da2899SCharles.Forsyth 	if(PC > r->M->prog)
78637da2899SCharles.Forsyth 		PC--;
78737da2899SCharles.Forsyth 	return PC - r->M->prog;
78837da2899SCharles.Forsyth }
78937da2899SCharles.Forsyth 
79037da2899SCharles.Forsyth static void
int2flag(int flag,char * s)79137da2899SCharles.Forsyth int2flag(int flag, char *s)
79237da2899SCharles.Forsyth {
79337da2899SCharles.Forsyth 	if(flag == 0){
79437da2899SCharles.Forsyth 		*s = '\0';
79537da2899SCharles.Forsyth 		return;
79637da2899SCharles.Forsyth 	}
79737da2899SCharles.Forsyth 	*s++ = '-';
79837da2899SCharles.Forsyth 	if(flag & MAFTER)
79937da2899SCharles.Forsyth 		*s++ = 'a';
80037da2899SCharles.Forsyth 	if(flag & MBEFORE)
80137da2899SCharles.Forsyth 		*s++ = 'b';
80237da2899SCharles.Forsyth 	if(flag & MCREATE)
80337da2899SCharles.Forsyth 		*s++ = 'c';
80437da2899SCharles.Forsyth 	if(flag & MCACHE)
80537da2899SCharles.Forsyth 		*s++ = 'C';
80637da2899SCharles.Forsyth 	*s = '\0';
80737da2899SCharles.Forsyth }
80837da2899SCharles.Forsyth 
80937da2899SCharles.Forsyth static char*
progtime(ulong msec,char * buf,char * ebuf)81037da2899SCharles.Forsyth progtime(ulong msec, char *buf, char *ebuf)
81137da2899SCharles.Forsyth {
81237da2899SCharles.Forsyth 	int tenths, sec;
81337da2899SCharles.Forsyth 
81437da2899SCharles.Forsyth 	tenths = msec/100;
81537da2899SCharles.Forsyth 	sec = tenths/10;
81637da2899SCharles.Forsyth 	seprint(buf, ebuf, "%4d:%2.2d.%d", sec/60, sec%60, tenths%10);
81737da2899SCharles.Forsyth 	return buf;
81837da2899SCharles.Forsyth }
81937da2899SCharles.Forsyth 
82037da2899SCharles.Forsyth static long
progread(Chan * c,void * va,long n,vlong offset)82137da2899SCharles.Forsyth progread(Chan *c, void *va, long n, vlong offset)
82237da2899SCharles.Forsyth {
82337da2899SCharles.Forsyth 	int i;
82437da2899SCharles.Forsyth 	Prog *p;
82537da2899SCharles.Forsyth 	Osenv *o;
82637da2899SCharles.Forsyth 	Mntwalk *mw;
82737da2899SCharles.Forsyth 	ulong grpid;
82837da2899SCharles.Forsyth 	char *a = va;
82937da2899SCharles.Forsyth 	Progctl *ctl;
83037da2899SCharles.Forsyth 	char mbuf[64], timebuf[12];
83137da2899SCharles.Forsyth 	char flag[10];
83237da2899SCharles.Forsyth 
83337da2899SCharles.Forsyth 	if(c->qid.type & QTDIR)
83437da2899SCharles.Forsyth 		return devdirread(c, a, n, 0, 0, proggen);
83537da2899SCharles.Forsyth 
83637da2899SCharles.Forsyth 	switch(QID(c->qid)){
83737da2899SCharles.Forsyth 	case Qdbgctl:
83837da2899SCharles.Forsyth 		ctl = c->aux;
83937da2899SCharles.Forsyth 		return qread(ctl->q, va, n);
84037da2899SCharles.Forsyth 	case Qstatus:
84137da2899SCharles.Forsyth 		acquire();
84237da2899SCharles.Forsyth 		p = progpid(PID(c->qid));
84337da2899SCharles.Forsyth 		if(p == nil || p->state == Pexiting || p->R.M == H) {
84437da2899SCharles.Forsyth 			release();
84537da2899SCharles.Forsyth 			snprint(up->genbuf, sizeof(up->genbuf), "%8lud %8d %10s %s %10s %5dK %s",
84637da2899SCharles.Forsyth 				PID(c->qid),
84737da2899SCharles.Forsyth 				0,
84837da2899SCharles.Forsyth 				eve,
84937da2899SCharles.Forsyth 				progtime(0, timebuf, timebuf+sizeof(timebuf)),
85037da2899SCharles.Forsyth 				progstate[Pexiting],
85137da2899SCharles.Forsyth 				0,
85237da2899SCharles.Forsyth 				"[$Sys]");
85337da2899SCharles.Forsyth 			return readstr(offset, va, n, up->genbuf);
85437da2899SCharles.Forsyth 		}
85537da2899SCharles.Forsyth 		modstatus(&p->R, mbuf, sizeof(mbuf));
85637da2899SCharles.Forsyth 		o = p->osenv;
85737da2899SCharles.Forsyth 		snprint(up->genbuf, sizeof(up->genbuf), "%8d %8d %10s %s %10s %5dK %s",
85837da2899SCharles.Forsyth 			p->pid,
85937da2899SCharles.Forsyth 			p->group!=nil? p->group->id: 0,
86037da2899SCharles.Forsyth 			o->user,
86137da2899SCharles.Forsyth 			progtime(p->ticks, timebuf, timebuf+sizeof(timebuf)),
86237da2899SCharles.Forsyth 			progstate[p->state],
86337da2899SCharles.Forsyth 			progsize(p),
86437da2899SCharles.Forsyth 			mbuf);
86537da2899SCharles.Forsyth 		release();
86637da2899SCharles.Forsyth 		return readstr(offset, va, n, up->genbuf);
86737da2899SCharles.Forsyth 	case Qwait:
86837da2899SCharles.Forsyth 		return qread(c->aux, va, n);
86937da2899SCharles.Forsyth 	case Qns:
87037da2899SCharles.Forsyth 		acquire();
87137da2899SCharles.Forsyth 		if(waserror()){
87237da2899SCharles.Forsyth 			release();
87337da2899SCharles.Forsyth 			nexterror();
87437da2899SCharles.Forsyth 		}
87537da2899SCharles.Forsyth 		p = progpid(PID(c->qid));
87637da2899SCharles.Forsyth 		if(p == nil)
87737da2899SCharles.Forsyth 			error(Ethread);
87837da2899SCharles.Forsyth 		mw = c->aux;
87937da2899SCharles.Forsyth 		if(mw->cddone){
88037da2899SCharles.Forsyth 			poperror();
88137da2899SCharles.Forsyth 			release();
88237da2899SCharles.Forsyth 			return 0;
88337da2899SCharles.Forsyth 		}
88437da2899SCharles.Forsyth 		o = p->osenv;
88537da2899SCharles.Forsyth 		mntscan(mw, o->pgrp);
88637da2899SCharles.Forsyth 		if(mw->mh == 0) {
88737da2899SCharles.Forsyth 			mw->cddone = 1;
88837da2899SCharles.Forsyth 			i = snprint(a, n, "cd %s\n", o->pgrp->dot->name->s);
88937da2899SCharles.Forsyth 			poperror();
89037da2899SCharles.Forsyth 			release();
89137da2899SCharles.Forsyth 			return i;
89237da2899SCharles.Forsyth 		}
89337da2899SCharles.Forsyth 		int2flag(mw->cm->mflag, flag);
89437da2899SCharles.Forsyth 		if(strcmp(mw->cm->to->name->s, "#M") == 0){
89537da2899SCharles.Forsyth 			i = snprint(a, n, "mount %s %s %s %s\n", flag,
89637da2899SCharles.Forsyth 				mw->cm->to->mchan->name->s,
89737da2899SCharles.Forsyth 				mw->mh->from->name->s, mw->cm->spec? mw->cm->spec : "");
89837da2899SCharles.Forsyth 		}else
89937da2899SCharles.Forsyth 			i = snprint(a, n, "bind %s %s %s\n", flag,
90037da2899SCharles.Forsyth 				mw->cm->to->name->s, mw->mh->from->name->s);
90137da2899SCharles.Forsyth 		poperror();
90237da2899SCharles.Forsyth 		release();
90337da2899SCharles.Forsyth 		return i;
90437da2899SCharles.Forsyth 	case Qnsgrp:
90537da2899SCharles.Forsyth 		acquire();
90637da2899SCharles.Forsyth 		p = progpid(PID(c->qid));
90737da2899SCharles.Forsyth 		if(p == nil) {
90837da2899SCharles.Forsyth 			release();
90937da2899SCharles.Forsyth 			error(Ethread);
91037da2899SCharles.Forsyth 		}
91137da2899SCharles.Forsyth 		grpid = ((Osenv *)p->osenv)->pgrp->pgrpid;
91237da2899SCharles.Forsyth 		release();
91337da2899SCharles.Forsyth 		return readnum(offset, va, n, grpid, NUMSIZE);
91437da2899SCharles.Forsyth 	case Qpgrp:
91537da2899SCharles.Forsyth 		acquire();
91637da2899SCharles.Forsyth 		p = progpid(PID(c->qid));
91737da2899SCharles.Forsyth 		if(p == nil) {
91837da2899SCharles.Forsyth 			release();
91937da2899SCharles.Forsyth 			error(Ethread);
92037da2899SCharles.Forsyth 		}
92137da2899SCharles.Forsyth 		grpid = p->group!=nil? p->group->id: 0;
92237da2899SCharles.Forsyth 		release();
92337da2899SCharles.Forsyth 		return readnum(offset, va, n, grpid, NUMSIZE);
92437da2899SCharles.Forsyth 	case Qstack:
92537da2899SCharles.Forsyth 		acquire();
92637da2899SCharles.Forsyth 		p = progpid(PID(c->qid));
92737da2899SCharles.Forsyth 		if(p == nil || p->state == Pexiting) {
92837da2899SCharles.Forsyth 			release();
92937da2899SCharles.Forsyth 			error(Ethread);
93037da2899SCharles.Forsyth 		}
93137da2899SCharles.Forsyth 		if(p->state == Pready) {
93237da2899SCharles.Forsyth 			release();
93337da2899SCharles.Forsyth 			error(Estopped);
93437da2899SCharles.Forsyth 		}
93537da2899SCharles.Forsyth 		n = progstack(&p->R, p->state, va, n, offset);
93637da2899SCharles.Forsyth 		release();
93737da2899SCharles.Forsyth 		return n;
93837da2899SCharles.Forsyth 	case Qheap:
93937da2899SCharles.Forsyth 		acquire();
94037da2899SCharles.Forsyth 		if(waserror()){
94137da2899SCharles.Forsyth 			release();
94237da2899SCharles.Forsyth 			nexterror();
94337da2899SCharles.Forsyth 		}
94437da2899SCharles.Forsyth 		n = progheap(c->aux, va, n, offset);
94537da2899SCharles.Forsyth 		if(n == -1)
94637da2899SCharles.Forsyth 			error(Emisalign);
94737da2899SCharles.Forsyth 		poperror();
94837da2899SCharles.Forsyth 		release();
94937da2899SCharles.Forsyth 		return n;
95037da2899SCharles.Forsyth 	case Qfd:
95137da2899SCharles.Forsyth 		acquire();
95237da2899SCharles.Forsyth 		if(waserror()) {
95337da2899SCharles.Forsyth 			release();
95437da2899SCharles.Forsyth 			nexterror();
95537da2899SCharles.Forsyth 		}
95637da2899SCharles.Forsyth 		p = progpid(PID(c->qid));
95737da2899SCharles.Forsyth 		if(p == nil)
95837da2899SCharles.Forsyth 			error(Ethread);
95937da2899SCharles.Forsyth 		o = p->osenv;
96037da2899SCharles.Forsyth 		n = progfds(o, va, n, offset);
96137da2899SCharles.Forsyth 		poperror();
96237da2899SCharles.Forsyth 		release();
96337da2899SCharles.Forsyth 		return n;
96437da2899SCharles.Forsyth 	case Qexception:
96537da2899SCharles.Forsyth 		acquire();
96637da2899SCharles.Forsyth 		p = progpid(PID(c->qid));
96737da2899SCharles.Forsyth 		if(p == nil) {
96837da2899SCharles.Forsyth 			release();
96937da2899SCharles.Forsyth 			error(Ethread);
97037da2899SCharles.Forsyth 		}
97137da2899SCharles.Forsyth 		if(p->exstr == nil)
97237da2899SCharles.Forsyth 			up->genbuf[0] = 0;
97337da2899SCharles.Forsyth 		else
97437da2899SCharles.Forsyth 			snprint(up->genbuf, sizeof(up->genbuf), p->exstr);
97537da2899SCharles.Forsyth 		release();
97637da2899SCharles.Forsyth 		return readstr(offset, va, n, up->genbuf);
97737da2899SCharles.Forsyth 	}
97837da2899SCharles.Forsyth 	error(Egreg);
97937da2899SCharles.Forsyth 	return 0;
98037da2899SCharles.Forsyth }
98137da2899SCharles.Forsyth 
98237da2899SCharles.Forsyth static void
mntscan(Mntwalk * mw,Pgrp * pg)98337da2899SCharles.Forsyth mntscan(Mntwalk *mw, Pgrp *pg)
98437da2899SCharles.Forsyth {
98537da2899SCharles.Forsyth 	Mount *t;
98637da2899SCharles.Forsyth 	Mhead *f;
98737da2899SCharles.Forsyth 	int nxt, i;
98837da2899SCharles.Forsyth 	ulong last, bestmid;
98937da2899SCharles.Forsyth 
99037da2899SCharles.Forsyth 	rlock(&pg->ns);
99137da2899SCharles.Forsyth 
99237da2899SCharles.Forsyth 	nxt = 0;
99337da2899SCharles.Forsyth 	bestmid = ~0;
99437da2899SCharles.Forsyth 
99537da2899SCharles.Forsyth 	last = 0;
99637da2899SCharles.Forsyth 	if(mw->mh)
99737da2899SCharles.Forsyth 		last = mw->cm->mountid;
99837da2899SCharles.Forsyth 
99937da2899SCharles.Forsyth 	for(i = 0; i < MNTHASH; i++) {
100037da2899SCharles.Forsyth 		for(f = pg->mnthash[i]; f; f = f->hash) {
100137da2899SCharles.Forsyth 			for(t = f->mount; t; t = t->next) {
100237da2899SCharles.Forsyth 				if(mw->mh == 0 ||
100337da2899SCharles.Forsyth 				  (t->mountid > last && t->mountid < bestmid)) {
100437da2899SCharles.Forsyth 					mw->cm = t;
100537da2899SCharles.Forsyth 					mw->mh = f;
100637da2899SCharles.Forsyth 					bestmid = mw->cm->mountid;
100737da2899SCharles.Forsyth 					nxt = 1;
100837da2899SCharles.Forsyth 				}
100937da2899SCharles.Forsyth 			}
101037da2899SCharles.Forsyth 		}
101137da2899SCharles.Forsyth 	}
101237da2899SCharles.Forsyth 	if(nxt == 0)
101337da2899SCharles.Forsyth 		mw->mh = 0;
101437da2899SCharles.Forsyth 
101537da2899SCharles.Forsyth 	runlock(&pg->ns);
101637da2899SCharles.Forsyth }
101737da2899SCharles.Forsyth 
101837da2899SCharles.Forsyth static long
progwrite(Chan * c,void * va,long n,vlong offset)101937da2899SCharles.Forsyth progwrite(Chan *c, void *va, long n, vlong offset)
102037da2899SCharles.Forsyth {
102137da2899SCharles.Forsyth 	Prog *p, *f;
102237da2899SCharles.Forsyth 	Heapqry *hq;
102337da2899SCharles.Forsyth 	char buf[512];
102437da2899SCharles.Forsyth 	Progctl *ctl;
102537da2899SCharles.Forsyth 	char *b;
102637da2899SCharles.Forsyth 	int i, pc;
102737da2899SCharles.Forsyth 	Cmdbuf *cb;
102837da2899SCharles.Forsyth 	Cmdtab *ct;
102937da2899SCharles.Forsyth 
103037da2899SCharles.Forsyth 	USED(offset);
103137da2899SCharles.Forsyth 	USED(va);
103237da2899SCharles.Forsyth 
103337da2899SCharles.Forsyth 	if(c->qid.type & QTDIR)
103437da2899SCharles.Forsyth 		error(Eisdir);
103537da2899SCharles.Forsyth 
103637da2899SCharles.Forsyth 	acquire();
103737da2899SCharles.Forsyth 	if(waserror()) {
103837da2899SCharles.Forsyth 		release();
103937da2899SCharles.Forsyth 		nexterror();
104037da2899SCharles.Forsyth 	}
104137da2899SCharles.Forsyth 	p = progpid(PID(c->qid));
104237da2899SCharles.Forsyth 	if(p == nil)
104337da2899SCharles.Forsyth 		error(Ethread);
104437da2899SCharles.Forsyth 
104537da2899SCharles.Forsyth 	switch(QID(c->qid)){
104637da2899SCharles.Forsyth 	case Qctl:
104737da2899SCharles.Forsyth 		cb = parsecmd(va, n);
104837da2899SCharles.Forsyth 		if(waserror()){
104937da2899SCharles.Forsyth 			free(cb);
105037da2899SCharles.Forsyth 			nexterror();
105137da2899SCharles.Forsyth 		}
105237da2899SCharles.Forsyth 		ct = lookupcmd(cb, progcmd, nelem(progcmd));
105337da2899SCharles.Forsyth 		switch(ct->index){
105437da2899SCharles.Forsyth 		case CMkillgrp:
105537da2899SCharles.Forsyth 			killgrp(p, "killed");
105637da2899SCharles.Forsyth 			break;
105737da2899SCharles.Forsyth 		case CMkill:
105837da2899SCharles.Forsyth 			killprog(p, "killed");
105937da2899SCharles.Forsyth 			break;
106037da2899SCharles.Forsyth 		case CMrestricted:
106137da2899SCharles.Forsyth 			p->flags |= Prestrict;
106237da2899SCharles.Forsyth 			break;
106337da2899SCharles.Forsyth 		case CMexceptions:
106437da2899SCharles.Forsyth 			if(p->group->id != p->pid)
106537da2899SCharles.Forsyth 				error(Eperm);
106637da2899SCharles.Forsyth 			if(strcmp(cb->f[1], "propagate") == 0)
106737da2899SCharles.Forsyth 				p->flags |= Ppropagate;
106837da2899SCharles.Forsyth 			else if(strcmp(cb->f[1], "notifyleader") == 0)
106937da2899SCharles.Forsyth 				p->flags |= Pnotifyleader;
107037da2899SCharles.Forsyth 			else
107137da2899SCharles.Forsyth 				error(Ebadctl);
107237da2899SCharles.Forsyth 			break;
107337da2899SCharles.Forsyth 		case CMprivate:
1074*cb6deeccSforsyth 			p->group->flags |= Pprivatemem;
107537da2899SCharles.Forsyth 			break;
107637da2899SCharles.Forsyth 		}
107737da2899SCharles.Forsyth 		poperror();
107837da2899SCharles.Forsyth 		free(cb);
107937da2899SCharles.Forsyth 		break;
108037da2899SCharles.Forsyth 	case Qdbgctl:
108137da2899SCharles.Forsyth 		cb = parsecmd(va, n);
108237da2899SCharles.Forsyth 		if(waserror()){
108337da2899SCharles.Forsyth 			free(cb);
108437da2899SCharles.Forsyth 			nexterror();
108537da2899SCharles.Forsyth 		}
108637da2899SCharles.Forsyth 		if(cb->nf == 1 && strncmp(cb->f[0], "step", 4) == 0)
108737da2899SCharles.Forsyth 			ct = progdbgcmd;
108837da2899SCharles.Forsyth 		else
108937da2899SCharles.Forsyth 			ct = lookupcmd(cb, progdbgcmd, nelem(progdbgcmd));
109037da2899SCharles.Forsyth 		switch(ct->index){
109137da2899SCharles.Forsyth 		case CDstep:
109237da2899SCharles.Forsyth 			if(cb->nf == 1)
109337da2899SCharles.Forsyth 				i = strtoul(cb->f[0]+4, nil, 0);
109437da2899SCharles.Forsyth 			else
109537da2899SCharles.Forsyth 				i = strtoul(cb->f[1], nil, 0);
109637da2899SCharles.Forsyth 			dbgstep(c->aux, p, i);
109737da2899SCharles.Forsyth 			break;
109837da2899SCharles.Forsyth 		case CDtoret:
109937da2899SCharles.Forsyth 			f = currun();
110037da2899SCharles.Forsyth 			i = calldepth(&p->R);
110137da2899SCharles.Forsyth 			while(f->kill == nil) {
110237da2899SCharles.Forsyth 				dbgstep(c->aux, p, 1024);
110337da2899SCharles.Forsyth 				if(i > calldepth(&p->R))
110437da2899SCharles.Forsyth 					break;
110537da2899SCharles.Forsyth 			}
110637da2899SCharles.Forsyth 			break;
110737da2899SCharles.Forsyth 		case CDcont:
110837da2899SCharles.Forsyth 			f = currun();
110937da2899SCharles.Forsyth 			while(f->kill == nil)
111037da2899SCharles.Forsyth 				dbgstep(c->aux, p, 1024);
111137da2899SCharles.Forsyth 			break;
111237da2899SCharles.Forsyth 		case CDstart:
111337da2899SCharles.Forsyth 			dbgstart(p);
111437da2899SCharles.Forsyth 			break;
111537da2899SCharles.Forsyth 		case CDstop:
111637da2899SCharles.Forsyth 			ctl = c->aux;
111737da2899SCharles.Forsyth 			ctl->stop = 1;
111837da2899SCharles.Forsyth 			break;
111937da2899SCharles.Forsyth 		case CDunstop:
112037da2899SCharles.Forsyth 			ctl = c->aux;
112137da2899SCharles.Forsyth 			ctl->stop = 0;
112237da2899SCharles.Forsyth 			break;
112337da2899SCharles.Forsyth 		case CDbpt:
112437da2899SCharles.Forsyth 			pc = strtoul(cb->f[3], nil, 10);
112537da2899SCharles.Forsyth 			ctl = c->aux;
112637da2899SCharles.Forsyth 			if(strcmp(cb->f[1], "set") == 0)
112737da2899SCharles.Forsyth 				ctl->bpts = setbpt(ctl->bpts, cb->f[2], pc);
112837da2899SCharles.Forsyth 			else if(strcmp(cb->f[1], "del") == 0)
112937da2899SCharles.Forsyth 				ctl->bpts = delbpt(ctl->bpts, cb->f[2], pc);
113037da2899SCharles.Forsyth 			else
113137da2899SCharles.Forsyth 				error(Ebadctl);
113237da2899SCharles.Forsyth 			break;
113337da2899SCharles.Forsyth 		case CDmaim:
113437da2899SCharles.Forsyth 			p->kill = "maim";
113537da2899SCharles.Forsyth 			break;
113637da2899SCharles.Forsyth 		}
113737da2899SCharles.Forsyth 		poperror();
113837da2899SCharles.Forsyth 		free(cb);
113937da2899SCharles.Forsyth 		break;
114037da2899SCharles.Forsyth 	case Qheap:
114137da2899SCharles.Forsyth 		/*
114237da2899SCharles.Forsyth 		 * Heap query:
114337da2899SCharles.Forsyth 		 *	addr.Fn
114437da2899SCharles.Forsyth 		 *	pc+module.In
114537da2899SCharles.Forsyth 		 */
114637da2899SCharles.Forsyth 		i = n;
114737da2899SCharles.Forsyth 		if(i > sizeof(buf)-1)
114837da2899SCharles.Forsyth 			i = sizeof(buf)-1;
114937da2899SCharles.Forsyth 		memmove(buf, va, i);
115037da2899SCharles.Forsyth 		buf[i] = '\0';
115137da2899SCharles.Forsyth 		hq = c->aux;
115237da2899SCharles.Forsyth 		hq->addr = strtoul(buf, &b, 0);
115337da2899SCharles.Forsyth 		if(*b == '+')
115437da2899SCharles.Forsyth 			hq->module = strtoul(b, &b, 0);
115537da2899SCharles.Forsyth 		if(*b++ != '.')
115637da2899SCharles.Forsyth 			error(Ebadctl);
115737da2899SCharles.Forsyth 		hq->fmt = *b++;
115837da2899SCharles.Forsyth 		hq->count = strtoul(b, nil, 0);
115937da2899SCharles.Forsyth 		break;
116037da2899SCharles.Forsyth 	default:
116137da2899SCharles.Forsyth 		print("unknown qid in procwrite\n");
116237da2899SCharles.Forsyth 		error(Egreg);
116337da2899SCharles.Forsyth 	}
116437da2899SCharles.Forsyth 	poperror();
116537da2899SCharles.Forsyth 	release();
116637da2899SCharles.Forsyth 	return n;
116737da2899SCharles.Forsyth }
116837da2899SCharles.Forsyth 
116937da2899SCharles.Forsyth static Bpt*
setbpt(Bpt * bpts,char * path,int pc)117037da2899SCharles.Forsyth setbpt(Bpt *bpts, char *path, int pc)
117137da2899SCharles.Forsyth {
117237da2899SCharles.Forsyth 	int n;
117337da2899SCharles.Forsyth 	Bpt *b;
117437da2899SCharles.Forsyth 
117537da2899SCharles.Forsyth 	n = strlen(path);
117637da2899SCharles.Forsyth 	b = mallocz(sizeof *b + n, 0);
117737da2899SCharles.Forsyth 	if(b == nil)
117837da2899SCharles.Forsyth 		return bpts;
117937da2899SCharles.Forsyth 	b->pc = pc;
118037da2899SCharles.Forsyth 	memmove(b->path, path, n+1);
118137da2899SCharles.Forsyth 	b->file = b->path;
118237da2899SCharles.Forsyth 	path = strrchr(b->path, '/');
118337da2899SCharles.Forsyth 	if(path != nil)
118437da2899SCharles.Forsyth 		b->file = path + 1;
118537da2899SCharles.Forsyth 	b->next = bpts;
118637da2899SCharles.Forsyth 	return b;
118737da2899SCharles.Forsyth }
118837da2899SCharles.Forsyth 
118937da2899SCharles.Forsyth static Bpt*
delbpt(Bpt * bpts,char * path,int pc)119037da2899SCharles.Forsyth delbpt(Bpt *bpts, char *path, int pc)
119137da2899SCharles.Forsyth {
119237da2899SCharles.Forsyth 	Bpt *b, **last;
119337da2899SCharles.Forsyth 
119437da2899SCharles.Forsyth 	last = &bpts;
119537da2899SCharles.Forsyth 	for(b = bpts; b != nil; b = b->next){
119637da2899SCharles.Forsyth 		if(b->pc == pc && strcmp(b->path, path) == 0) {
119737da2899SCharles.Forsyth 			*last = b->next;
119837da2899SCharles.Forsyth 			free(b);
119937da2899SCharles.Forsyth 			break;
120037da2899SCharles.Forsyth 		}
120137da2899SCharles.Forsyth 		last = &b->next;
120237da2899SCharles.Forsyth 	}
120337da2899SCharles.Forsyth 	return bpts;
120437da2899SCharles.Forsyth }
120537da2899SCharles.Forsyth 
120637da2899SCharles.Forsyth static void
freebpts(Bpt * b)120737da2899SCharles.Forsyth freebpts(Bpt *b)
120837da2899SCharles.Forsyth {
120937da2899SCharles.Forsyth 	Bpt *next;
121037da2899SCharles.Forsyth 
121137da2899SCharles.Forsyth 	for(; b != nil; b = next){
121237da2899SCharles.Forsyth 		next = b->next;
121337da2899SCharles.Forsyth 		free(b);
121437da2899SCharles.Forsyth 	}
121537da2899SCharles.Forsyth }
121637da2899SCharles.Forsyth 
121737da2899SCharles.Forsyth static void
telldbg(Progctl * ctl,char * msg)121837da2899SCharles.Forsyth telldbg(Progctl *ctl, char *msg)
121937da2899SCharles.Forsyth {
122037da2899SCharles.Forsyth 	kstrcpy(ctl->msg, msg, ERRMAX);
122137da2899SCharles.Forsyth 	ctl->debugger = nil;
122237da2899SCharles.Forsyth 	Wakeup(&ctl->r);
122337da2899SCharles.Forsyth }
122437da2899SCharles.Forsyth 
122537da2899SCharles.Forsyth static void
dbgstart(Prog * p)122637da2899SCharles.Forsyth dbgstart(Prog *p)
122737da2899SCharles.Forsyth {
122837da2899SCharles.Forsyth 	Osenv *o;
122937da2899SCharles.Forsyth 	Progctl *ctl;
123037da2899SCharles.Forsyth 
123137da2899SCharles.Forsyth 	o = p->osenv;
123237da2899SCharles.Forsyth 	ctl = o->debug;
123337da2899SCharles.Forsyth 	if(ctl != nil && ctl->debugger != nil)
123437da2899SCharles.Forsyth 		error("prog debugged");
123537da2899SCharles.Forsyth 	if(p->state == Pdebug)
123637da2899SCharles.Forsyth 		addrun(p);
123737da2899SCharles.Forsyth 	o->debug = nil;
123837da2899SCharles.Forsyth 	p->xec = xec;
123937da2899SCharles.Forsyth }
124037da2899SCharles.Forsyth 
124137da2899SCharles.Forsyth static int
xecdone(void * vc)124237da2899SCharles.Forsyth xecdone(void *vc)
124337da2899SCharles.Forsyth {
124437da2899SCharles.Forsyth 	Progctl *ctl = vc;
124537da2899SCharles.Forsyth 
124637da2899SCharles.Forsyth 	return ctl->debugger == nil;
124737da2899SCharles.Forsyth }
124837da2899SCharles.Forsyth 
124937da2899SCharles.Forsyth static void
dbgstep(Progctl * vctl,Prog * p,int n)125037da2899SCharles.Forsyth dbgstep(Progctl *vctl, Prog *p, int n)
125137da2899SCharles.Forsyth {
125237da2899SCharles.Forsyth 	Osenv * volatile o;
125337da2899SCharles.Forsyth 	Progctl * volatile ctl;
125437da2899SCharles.Forsyth 	char buf[ERRMAX+20], *msg;
125537da2899SCharles.Forsyth 
125637da2899SCharles.Forsyth 	if(p == currun())
125737da2899SCharles.Forsyth 		error("cannot step yourself");
125837da2899SCharles.Forsyth 
125937da2899SCharles.Forsyth 	if(p->state == Pbroken)
126037da2899SCharles.Forsyth 		error("prog broken");
126137da2899SCharles.Forsyth 
126237da2899SCharles.Forsyth 	ctl = vctl;
126337da2899SCharles.Forsyth 	if(ctl->debugger != nil)
126437da2899SCharles.Forsyth 		error("prog already debugged");
126537da2899SCharles.Forsyth 
126637da2899SCharles.Forsyth 	o = p->osenv;
126737da2899SCharles.Forsyth 	if(o->debug == nil) {
126837da2899SCharles.Forsyth 		o->debug = ctl;
126937da2899SCharles.Forsyth 		p->xec = dbgxec;
127037da2899SCharles.Forsyth 	}else if(o->debug != ctl)
127137da2899SCharles.Forsyth 		error("prog already debugged");
127237da2899SCharles.Forsyth 
127337da2899SCharles.Forsyth 	ctl->step = n;
127437da2899SCharles.Forsyth 	if(p->state == Pdebug)
127537da2899SCharles.Forsyth 		addrun(p);
127637da2899SCharles.Forsyth 	ctl->debugger = up;
127737da2899SCharles.Forsyth 	strcpy(buf, "child: ");
127837da2899SCharles.Forsyth 	msg = buf+7;
127937da2899SCharles.Forsyth 	ctl->msg = msg;
128037da2899SCharles.Forsyth 
128137da2899SCharles.Forsyth 	/*
128237da2899SCharles.Forsyth 	 * wait for reply from dbgxec; release is okay because prog is now
128337da2899SCharles.Forsyth 	 * debugged, cannot exit.
128437da2899SCharles.Forsyth 	 */
128537da2899SCharles.Forsyth 	if(waserror()){
128637da2899SCharles.Forsyth 		acquire();
128737da2899SCharles.Forsyth 		ctl->debugger = nil;
128837da2899SCharles.Forsyth 		ctl->msg = nil;
128937da2899SCharles.Forsyth 		o->debug = nil;
129037da2899SCharles.Forsyth 		p->xec = xec;
129137da2899SCharles.Forsyth 		nexterror();
129237da2899SCharles.Forsyth 	}
129337da2899SCharles.Forsyth 	release();
129437da2899SCharles.Forsyth 	Sleep(&ctl->r, xecdone, ctl);
129537da2899SCharles.Forsyth 	poperror();
129637da2899SCharles.Forsyth 	acquire();
129737da2899SCharles.Forsyth 	if(msg[0] != '\0')
129837da2899SCharles.Forsyth 		error(buf);
129937da2899SCharles.Forsyth }
130037da2899SCharles.Forsyth 
130137da2899SCharles.Forsyth void
dbgexit(Prog * kid,int broken,char * estr)130237da2899SCharles.Forsyth dbgexit(Prog *kid, int broken, char *estr)
130337da2899SCharles.Forsyth {
130437da2899SCharles.Forsyth 	int n;
130537da2899SCharles.Forsyth 	Osenv *e;
130637da2899SCharles.Forsyth 	Progctl *ctl;
130737da2899SCharles.Forsyth 	char buf[ERRMAX+20];
130837da2899SCharles.Forsyth 
130937da2899SCharles.Forsyth 	e = kid->osenv;
131037da2899SCharles.Forsyth 	ctl = e->debug;
131137da2899SCharles.Forsyth 	e->debug = nil;
131237da2899SCharles.Forsyth 	kid->xec = xec;
131337da2899SCharles.Forsyth 
131437da2899SCharles.Forsyth 	if(broken)
131537da2899SCharles.Forsyth 		n = snprint(buf, sizeof(buf), "broken: %s", estr);
131637da2899SCharles.Forsyth 	else
131737da2899SCharles.Forsyth 		n = snprint(buf, sizeof(buf), "exited");
131837da2899SCharles.Forsyth 	if(ctl->debugger)
131937da2899SCharles.Forsyth 		telldbg(ctl, buf);
132037da2899SCharles.Forsyth 	qproduce(ctl->q, buf, n);
132137da2899SCharles.Forsyth }
132237da2899SCharles.Forsyth 
132337da2899SCharles.Forsyth static void
dbgaddrun(Prog * p)132437da2899SCharles.Forsyth dbgaddrun(Prog *p)
132537da2899SCharles.Forsyth {
132637da2899SCharles.Forsyth 	Osenv *o;
132737da2899SCharles.Forsyth 
132837da2899SCharles.Forsyth 	p->state = Pdebug;
132937da2899SCharles.Forsyth 	p->addrun = nil;
133037da2899SCharles.Forsyth 	o = p->osenv;
133137da2899SCharles.Forsyth 	if(o->rend != nil)
133237da2899SCharles.Forsyth 		Wakeup(o->rend);
133337da2899SCharles.Forsyth 	o->rend = nil;
133437da2899SCharles.Forsyth }
133537da2899SCharles.Forsyth 
133637da2899SCharles.Forsyth static int
bdone(void * vp)133737da2899SCharles.Forsyth bdone(void *vp)
133837da2899SCharles.Forsyth {
133937da2899SCharles.Forsyth 	Prog *p = vp;
134037da2899SCharles.Forsyth 
134137da2899SCharles.Forsyth 	return p->addrun == nil;
134237da2899SCharles.Forsyth }
134337da2899SCharles.Forsyth 
134437da2899SCharles.Forsyth static void
dbgblock(Prog * p)134537da2899SCharles.Forsyth dbgblock(Prog *p)
134637da2899SCharles.Forsyth {
134737da2899SCharles.Forsyth 	Osenv *o;
134837da2899SCharles.Forsyth 	Progctl *ctl;
134937da2899SCharles.Forsyth 
135037da2899SCharles.Forsyth 	o = p->osenv;
135137da2899SCharles.Forsyth 	ctl = o->debug;
135237da2899SCharles.Forsyth 	qproduce(ctl->q, progstate[p->state], strlen(progstate[p->state]));
135337da2899SCharles.Forsyth 	pushrun(p);
135437da2899SCharles.Forsyth 	p->addrun = dbgaddrun;
135537da2899SCharles.Forsyth 	o->rend = &up->sleep;
135637da2899SCharles.Forsyth 
135737da2899SCharles.Forsyth 	/*
135837da2899SCharles.Forsyth 	 * bdone(p) is safe after release because p is being debugged,
135937da2899SCharles.Forsyth 	 * so cannot exit.
136037da2899SCharles.Forsyth 	 */
136137da2899SCharles.Forsyth 	if(waserror()){
136237da2899SCharles.Forsyth 		acquire();
136337da2899SCharles.Forsyth 		nexterror();
136437da2899SCharles.Forsyth 	}
136537da2899SCharles.Forsyth 	release();
136637da2899SCharles.Forsyth 	if(o->rend != nil)
136737da2899SCharles.Forsyth 		Sleep(o->rend, bdone, p);
136837da2899SCharles.Forsyth 	poperror();
136937da2899SCharles.Forsyth 	acquire();
137037da2899SCharles.Forsyth 	if(p->kill != nil)
137137da2899SCharles.Forsyth 		error(p->kill);
137237da2899SCharles.Forsyth 	ctl = o->debug;
137337da2899SCharles.Forsyth 	if(ctl != nil)
137437da2899SCharles.Forsyth 		qproduce(ctl->q, "run", 3);
137537da2899SCharles.Forsyth }
137637da2899SCharles.Forsyth 
137737da2899SCharles.Forsyth void
dbgxec(Prog * p)137837da2899SCharles.Forsyth dbgxec(Prog *p)
137937da2899SCharles.Forsyth {
138037da2899SCharles.Forsyth 	Bpt *b;
138137da2899SCharles.Forsyth 	Prog *kid;
138237da2899SCharles.Forsyth 	Osenv *env;
138337da2899SCharles.Forsyth 	Progctl *ctl;
138437da2899SCharles.Forsyth 	int op, pc, n;
138537da2899SCharles.Forsyth 	char buf[ERRMAX+10];
138637da2899SCharles.Forsyth 	extern void (*dec[])(void);
138737da2899SCharles.Forsyth 
138837da2899SCharles.Forsyth 	env = p->osenv;
138937da2899SCharles.Forsyth 	ctl = env->debug;
139037da2899SCharles.Forsyth 	ctl->ref++;
139137da2899SCharles.Forsyth 	if(waserror()){
139237da2899SCharles.Forsyth 		closedbgctl(ctl, p);
139337da2899SCharles.Forsyth 		nexterror();
139437da2899SCharles.Forsyth 	}
139537da2899SCharles.Forsyth 
139637da2899SCharles.Forsyth 	R = p->R;
139737da2899SCharles.Forsyth 	R.MP = R.M->MP;
139837da2899SCharles.Forsyth 
139937da2899SCharles.Forsyth 	R.IC = p->quanta;
140037da2899SCharles.Forsyth 	if((ulong)R.IC > ctl->step)
140137da2899SCharles.Forsyth 		R.IC = ctl->step;
140237da2899SCharles.Forsyth 	if(ctl->stop)
140337da2899SCharles.Forsyth 		R.IC = 0;
140437da2899SCharles.Forsyth 
140537da2899SCharles.Forsyth 
140637da2899SCharles.Forsyth 	buf[0] = '\0';
140737da2899SCharles.Forsyth 
140837da2899SCharles.Forsyth 	if(R.IC != 0 && R.M->compiled) {
140937da2899SCharles.Forsyth 		comvec();
141037da2899SCharles.Forsyth 		if(p != currun())
141137da2899SCharles.Forsyth 			dbgblock(p);
141237da2899SCharles.Forsyth 		goto save;
141337da2899SCharles.Forsyth 	}
141437da2899SCharles.Forsyth 
141537da2899SCharles.Forsyth 	while(R.IC != 0) {
141637da2899SCharles.Forsyth 		if(0)
141737da2899SCharles.Forsyth 			print("step: %lux: %s %4ld %D\n",
141837da2899SCharles.Forsyth 				(ulong)p, R.M->m->name, R.PC-R.M->prog, R.PC);
141937da2899SCharles.Forsyth 
142037da2899SCharles.Forsyth 		dec[R.PC->add]();
142137da2899SCharles.Forsyth 		op = R.PC->op;
142237da2899SCharles.Forsyth 		R.PC++;
142337da2899SCharles.Forsyth 		optab[op]();
142437da2899SCharles.Forsyth 
142537da2899SCharles.Forsyth 		/*
142637da2899SCharles.Forsyth 		 * check notification about new progs
142737da2899SCharles.Forsyth 		 */
142837da2899SCharles.Forsyth 		if(op == ISPAWN || op == IMSPAWN) {
142937da2899SCharles.Forsyth 			/* pick up the kid from the end of the run queue */
143037da2899SCharles.Forsyth 			kid = delruntail(Pdebug);
143137da2899SCharles.Forsyth 			n = snprint(buf, sizeof buf, "new %d", kid->pid);
143237da2899SCharles.Forsyth 			qproduce(ctl->q, buf, n);
143337da2899SCharles.Forsyth 			buf[0] = '\0';
143437da2899SCharles.Forsyth 		}
143537da2899SCharles.Forsyth 		if(op == ILOAD) {
143637da2899SCharles.Forsyth 			n = snprint(buf, sizeof buf, "load %s", string2c(*(String**)R.s));
143737da2899SCharles.Forsyth 			qproduce(ctl->q, buf, n);
143837da2899SCharles.Forsyth 			buf[0] = '\0';
143937da2899SCharles.Forsyth 		}
144037da2899SCharles.Forsyth 
144137da2899SCharles.Forsyth 		/*
144237da2899SCharles.Forsyth 		 * check for returns at big steps
144337da2899SCharles.Forsyth 		 */
144437da2899SCharles.Forsyth 		if(op == IRET)
144537da2899SCharles.Forsyth 			R.IC = 1;
144637da2899SCharles.Forsyth 
144737da2899SCharles.Forsyth 		/*
144837da2899SCharles.Forsyth 		 * check for blocked progs
144937da2899SCharles.Forsyth 		 */
145037da2899SCharles.Forsyth 		if(R.IC == 1 && p != currun())
145137da2899SCharles.Forsyth 			dbgblock(p);
145237da2899SCharles.Forsyth 		if(ctl->stop)
145337da2899SCharles.Forsyth 			R.IC = 1;
145437da2899SCharles.Forsyth 		R.IC--;
145537da2899SCharles.Forsyth 
145637da2899SCharles.Forsyth 		if(ctl->bpts == nil)
145737da2899SCharles.Forsyth 			continue;
145837da2899SCharles.Forsyth 
145937da2899SCharles.Forsyth 		pc = R.PC - R.M->prog;
146037da2899SCharles.Forsyth 		for(b = ctl->bpts; b != nil; b = b->next) {
146137da2899SCharles.Forsyth 			if(pc == b->pc &&
146237da2899SCharles.Forsyth 			  (strcmp(R.M->m->path, b->path) == 0 ||
146337da2899SCharles.Forsyth 			   strcmp(R.M->m->path, b->file) == 0)) {
146437da2899SCharles.Forsyth 				strcpy(buf, "breakpoint");
146537da2899SCharles.Forsyth 				goto save;
146637da2899SCharles.Forsyth 			}
146737da2899SCharles.Forsyth 		}
146837da2899SCharles.Forsyth 	}
146937da2899SCharles.Forsyth save:
147037da2899SCharles.Forsyth 	if(ctl->stop)
147137da2899SCharles.Forsyth 		strcpy(buf, "stopped");
147237da2899SCharles.Forsyth 
147337da2899SCharles.Forsyth 	p->R = R;
147437da2899SCharles.Forsyth 
147537da2899SCharles.Forsyth 	if(env->debug == nil) {
147637da2899SCharles.Forsyth 		poperror();
147737da2899SCharles.Forsyth 		return;
147837da2899SCharles.Forsyth 	}
147937da2899SCharles.Forsyth 
148037da2899SCharles.Forsyth 	if(p == currun())
148137da2899SCharles.Forsyth 		delrun(Pdebug);
148237da2899SCharles.Forsyth 
148337da2899SCharles.Forsyth 	telldbg(env->debug, buf);
148437da2899SCharles.Forsyth 	poperror();
148537da2899SCharles.Forsyth 	closedbgctl(env->debug, p);
148637da2899SCharles.Forsyth }
148737da2899SCharles.Forsyth 
148837da2899SCharles.Forsyth Dev progdevtab = {
148937da2899SCharles.Forsyth 	'p',
149037da2899SCharles.Forsyth 	"prog",
149137da2899SCharles.Forsyth 
149237da2899SCharles.Forsyth 	devinit,
149337da2899SCharles.Forsyth 	progattach,
149437da2899SCharles.Forsyth 	progwalk,
149537da2899SCharles.Forsyth 	progstat,
149637da2899SCharles.Forsyth 	progopen,
149737da2899SCharles.Forsyth 	devcreate,
149837da2899SCharles.Forsyth 	progclose,
149937da2899SCharles.Forsyth 	progread,
150037da2899SCharles.Forsyth 	devbread,
150137da2899SCharles.Forsyth 	progwrite,
150237da2899SCharles.Forsyth 	devbwrite,
150337da2899SCharles.Forsyth 	devremove,
150437da2899SCharles.Forsyth 	progwstat
150537da2899SCharles.Forsyth };
1506