xref: /inferno-os/os/port/devprog.c (revision cb6deecc455ddb2a6a83cedaafc576838587d217)
174a4d8c2SCharles.Forsyth #include	"u.h"
274a4d8c2SCharles.Forsyth #include	"../port/lib.h"
374a4d8c2SCharles.Forsyth #include	"mem.h"
474a4d8c2SCharles.Forsyth #include	"dat.h"
574a4d8c2SCharles.Forsyth #include	"fns.h"
674a4d8c2SCharles.Forsyth #include	"error.h"
774a4d8c2SCharles.Forsyth #include	<interp.h>
874a4d8c2SCharles.Forsyth #include	<isa.h>
974a4d8c2SCharles.Forsyth #include	"runt.h"
1074a4d8c2SCharles.Forsyth 
1174a4d8c2SCharles.Forsyth /*
1274a4d8c2SCharles.Forsyth  * Enable the heap device for environments that allow debugging =>
1374a4d8c2SCharles.Forsyth  * Must be 1 for a production environment.
1474a4d8c2SCharles.Forsyth  */
1574a4d8c2SCharles.Forsyth int	SECURE = 0;
1674a4d8c2SCharles.Forsyth 
1774a4d8c2SCharles.Forsyth enum
1874a4d8c2SCharles.Forsyth {
1974a4d8c2SCharles.Forsyth 	Qdir,
2074a4d8c2SCharles.Forsyth 	Qctl,
2174a4d8c2SCharles.Forsyth 	Qdbgctl,
2274a4d8c2SCharles.Forsyth 	Qheap,
2374a4d8c2SCharles.Forsyth 	Qns,
2474a4d8c2SCharles.Forsyth 	Qnsgrp,
2574a4d8c2SCharles.Forsyth 	Qpgrp,
2674a4d8c2SCharles.Forsyth 	Qstack,
2774a4d8c2SCharles.Forsyth 	Qstatus,
2874a4d8c2SCharles.Forsyth 	Qtext,
2974a4d8c2SCharles.Forsyth 	Qwait,
3074a4d8c2SCharles.Forsyth 	Qfd,
3174a4d8c2SCharles.Forsyth 	Qexception,
3274a4d8c2SCharles.Forsyth };
3374a4d8c2SCharles.Forsyth 
3474a4d8c2SCharles.Forsyth /*
3574a4d8c2SCharles.Forsyth  * must be in same order as enum
3674a4d8c2SCharles.Forsyth  */
3774a4d8c2SCharles.Forsyth Dirtab progdir[] =
3874a4d8c2SCharles.Forsyth {
3974a4d8c2SCharles.Forsyth 	"ctl",		{Qctl},		0,			0200,
4074a4d8c2SCharles.Forsyth 	"dbgctl",	{Qdbgctl},	0,			0600,
4174a4d8c2SCharles.Forsyth 	"heap",		{Qheap},	0,			0600,
4274a4d8c2SCharles.Forsyth 	"ns",		{Qns},		0,			0400,
4374a4d8c2SCharles.Forsyth 	"nsgrp",	{Qnsgrp},	0,			0444,
4474a4d8c2SCharles.Forsyth 	"pgrp",		{Qpgrp},	0,			0444,
4574a4d8c2SCharles.Forsyth 	"stack",	{Qstack},	0,			0400,
4674a4d8c2SCharles.Forsyth 	"status",	{Qstatus},	0,			0444,
4774a4d8c2SCharles.Forsyth 	"text",		{Qtext},	0,			0000,
4874a4d8c2SCharles.Forsyth 	"wait",		{Qwait},	0,			0400,
4974a4d8c2SCharles.Forsyth 	"fd",		{Qfd},		0,			0400,
5074a4d8c2SCharles.Forsyth 	"exception",	{Qexception},	0,	0400,
5174a4d8c2SCharles.Forsyth };
5274a4d8c2SCharles.Forsyth 
5374a4d8c2SCharles.Forsyth enum
5474a4d8c2SCharles.Forsyth {
5574a4d8c2SCharles.Forsyth 	CMkill,
5674a4d8c2SCharles.Forsyth 	CMkillgrp,
5774a4d8c2SCharles.Forsyth 	CMrestricted,
5874a4d8c2SCharles.Forsyth 	CMexceptions,
5974a4d8c2SCharles.Forsyth 	CMprivate
6074a4d8c2SCharles.Forsyth };
6174a4d8c2SCharles.Forsyth 
6274a4d8c2SCharles.Forsyth static
6374a4d8c2SCharles.Forsyth Cmdtab progcmd[] = {
6474a4d8c2SCharles.Forsyth 	CMkill,	"kill",	1,
6574a4d8c2SCharles.Forsyth 	CMkillgrp,	"killgrp",	1,
6674a4d8c2SCharles.Forsyth 	CMrestricted, "restricted", 1,
6774a4d8c2SCharles.Forsyth 	CMexceptions, "exceptions", 2,
6874a4d8c2SCharles.Forsyth 	CMprivate, "private",	1,
6974a4d8c2SCharles.Forsyth };
7074a4d8c2SCharles.Forsyth 
7174a4d8c2SCharles.Forsyth enum
7274a4d8c2SCharles.Forsyth {
7374a4d8c2SCharles.Forsyth 	CDstep,
7474a4d8c2SCharles.Forsyth 	CDtoret,
7574a4d8c2SCharles.Forsyth 	CDcont,
7674a4d8c2SCharles.Forsyth 	CDstart,
7774a4d8c2SCharles.Forsyth 	CDstop,
7874a4d8c2SCharles.Forsyth 	CDunstop,
7974a4d8c2SCharles.Forsyth 	CDmaim,
8074a4d8c2SCharles.Forsyth 	CDbpt
8174a4d8c2SCharles.Forsyth };
8274a4d8c2SCharles.Forsyth 
8374a4d8c2SCharles.Forsyth static
8474a4d8c2SCharles.Forsyth Cmdtab progdbgcmd[] = {
8574a4d8c2SCharles.Forsyth 	CDstep,	"step",	0,	/* known below to be first, to cope with stepN */
8674a4d8c2SCharles.Forsyth 	CDtoret,	"toret",	1,
8774a4d8c2SCharles.Forsyth 	CDcont,	"cont",	1,
8874a4d8c2SCharles.Forsyth 	CDstart,	"start",	1,
8974a4d8c2SCharles.Forsyth 	CDstop,	"stop",	1,
9074a4d8c2SCharles.Forsyth 	CDunstop,	"unstop",	1,
9174a4d8c2SCharles.Forsyth 	CDmaim,	"maim",	1,
9274a4d8c2SCharles.Forsyth 	CDbpt,	"bpt",	4,
9374a4d8c2SCharles.Forsyth };
9474a4d8c2SCharles.Forsyth 
9574a4d8c2SCharles.Forsyth typedef struct Heapqry Heapqry;
9674a4d8c2SCharles.Forsyth struct Heapqry
9774a4d8c2SCharles.Forsyth {
9874a4d8c2SCharles.Forsyth 	char	fmt;
9974a4d8c2SCharles.Forsyth 	ulong	addr;
10074a4d8c2SCharles.Forsyth 	ulong	module;
10174a4d8c2SCharles.Forsyth 	int	count;
10274a4d8c2SCharles.Forsyth };
10374a4d8c2SCharles.Forsyth 
10474a4d8c2SCharles.Forsyth typedef struct Bpt	Bpt;
10574a4d8c2SCharles.Forsyth 
10674a4d8c2SCharles.Forsyth struct Bpt
10774a4d8c2SCharles.Forsyth {
10874a4d8c2SCharles.Forsyth 	Bpt	*next;
10974a4d8c2SCharles.Forsyth 	int	pc;
11074a4d8c2SCharles.Forsyth 	char	*file;
11174a4d8c2SCharles.Forsyth 	char	path[1];
11274a4d8c2SCharles.Forsyth };
11374a4d8c2SCharles.Forsyth 
11474a4d8c2SCharles.Forsyth typedef struct Progctl Progctl;
11574a4d8c2SCharles.Forsyth struct Progctl
11674a4d8c2SCharles.Forsyth {
11774a4d8c2SCharles.Forsyth 	Rendez	r;
11874a4d8c2SCharles.Forsyth 	int	ref;
11974a4d8c2SCharles.Forsyth 	Proc	*debugger;	/* waiting for dbgxec */
12074a4d8c2SCharles.Forsyth 	char	*msg;		/* reply from dbgxec */
12174a4d8c2SCharles.Forsyth 	int	step;		/* instructions to try */
12274a4d8c2SCharles.Forsyth 	int	stop;		/* stop running the program */
12374a4d8c2SCharles.Forsyth 	Bpt*	bpts;		/* active breakpoints */
12474a4d8c2SCharles.Forsyth 	Queue*	q;		/* status queue */
12574a4d8c2SCharles.Forsyth };
12674a4d8c2SCharles.Forsyth 
12774a4d8c2SCharles.Forsyth #define	QSHIFT		4		/* location in qid of pid */
12874a4d8c2SCharles.Forsyth #define	QID(q)		(((ulong)(q).path&0x0000000F)>>0)
12974a4d8c2SCharles.Forsyth #define QPID(pid)	(((pid)<<QSHIFT))
13074a4d8c2SCharles.Forsyth #define	PID(q)		((q).vers)
13174a4d8c2SCharles.Forsyth #define PATH(q)		((ulong)(q).path&~((1<<QSHIFT)-1))
13274a4d8c2SCharles.Forsyth 
13374a4d8c2SCharles.Forsyth static char *progstate[] =			/* must correspond to include/interp.h */
13474a4d8c2SCharles.Forsyth {
13574a4d8c2SCharles.Forsyth 	"alt",				/* blocked in alt instruction */
13674a4d8c2SCharles.Forsyth 	"send",				/* waiting to send */
13774a4d8c2SCharles.Forsyth 	"recv",				/* waiting to recv */
13874a4d8c2SCharles.Forsyth 	"debug",			/* debugged */
13974a4d8c2SCharles.Forsyth 	"ready",			/* ready to be scheduled */
14074a4d8c2SCharles.Forsyth 	"release",			/* interpreter released */
14174a4d8c2SCharles.Forsyth 	"exiting",			/* exit because of kill or error */
14274a4d8c2SCharles.Forsyth 	"broken",			/* thread crashed */
14374a4d8c2SCharles.Forsyth };
14474a4d8c2SCharles.Forsyth 
14574a4d8c2SCharles.Forsyth static	void	dbgstep(Progctl*, Prog*, int);
14674a4d8c2SCharles.Forsyth static	void	dbgstart(Prog*);
14774a4d8c2SCharles.Forsyth static	void	freebpts(Bpt*);
14874a4d8c2SCharles.Forsyth static	Bpt*	delbpt(Bpt*, char*, int);
14974a4d8c2SCharles.Forsyth static	Bpt*	setbpt(Bpt*, char*, int);
15074a4d8c2SCharles.Forsyth static	void	mntscan(Mntwalk*, Pgrp*);
15174a4d8c2SCharles.Forsyth extern	Type	*Trdchan;
15274a4d8c2SCharles.Forsyth extern	Type	*Twrchan;
15374a4d8c2SCharles.Forsyth extern	Module*	modules;
15474a4d8c2SCharles.Forsyth static  char 	Emisalign[] = "misaligned address";
15574a4d8c2SCharles.Forsyth 
15674a4d8c2SCharles.Forsyth static int
proggen(Chan * c,char * name,Dirtab * tab,int,int s,Dir * dp)15774a4d8c2SCharles.Forsyth proggen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp)
15874a4d8c2SCharles.Forsyth {
15974a4d8c2SCharles.Forsyth 	Qid qid;
16074a4d8c2SCharles.Forsyth 	Prog *p;
16174a4d8c2SCharles.Forsyth 	char *e;
16274a4d8c2SCharles.Forsyth 	Osenv *o;
16374a4d8c2SCharles.Forsyth 	ulong pid, path, perm, len;
16474a4d8c2SCharles.Forsyth 
16574a4d8c2SCharles.Forsyth 	if(s == DEVDOTDOT){
16674a4d8c2SCharles.Forsyth 		mkqid(&qid, Qdir, 0, QTDIR);
16774a4d8c2SCharles.Forsyth 		devdir(c, qid, "#p", 0, eve, DMDIR|0555, dp);
16874a4d8c2SCharles.Forsyth 		return 1;
16974a4d8c2SCharles.Forsyth 	}
17074a4d8c2SCharles.Forsyth 
17174a4d8c2SCharles.Forsyth 	if((ulong)c->qid.path == Qdir) {
17274a4d8c2SCharles.Forsyth 		if(name != nil){
17374a4d8c2SCharles.Forsyth 			/* ignore s and use name to find pid */
17474a4d8c2SCharles.Forsyth 			pid = strtoul(name, &e, 0);
17574a4d8c2SCharles.Forsyth 			if(pid == 0 || *e != '\0')
17674a4d8c2SCharles.Forsyth 				return -1;
17774a4d8c2SCharles.Forsyth 			acquire();
17874a4d8c2SCharles.Forsyth 			p = progpid(pid);
17974a4d8c2SCharles.Forsyth 			if(p == nil){
18074a4d8c2SCharles.Forsyth 				release();
18174a4d8c2SCharles.Forsyth 				return -1;
18274a4d8c2SCharles.Forsyth 			}
18374a4d8c2SCharles.Forsyth 		}else{
18474a4d8c2SCharles.Forsyth 			acquire();
18574a4d8c2SCharles.Forsyth 			p = progn(s);
18674a4d8c2SCharles.Forsyth 			if(p == nil) {
18774a4d8c2SCharles.Forsyth 				release();
18874a4d8c2SCharles.Forsyth 				return -1;
18974a4d8c2SCharles.Forsyth 			}
19074a4d8c2SCharles.Forsyth 			pid = p->pid;
19174a4d8c2SCharles.Forsyth 		}
19274a4d8c2SCharles.Forsyth 		o = p->osenv;
19374a4d8c2SCharles.Forsyth 		sprint(up->genbuf, "%lud", pid);
19474a4d8c2SCharles.Forsyth 		if(name != nil && strcmp(name, up->genbuf) != 0){
19574a4d8c2SCharles.Forsyth 			release();
19674a4d8c2SCharles.Forsyth 			return -1;
19774a4d8c2SCharles.Forsyth 		}
19874a4d8c2SCharles.Forsyth 		mkqid(&qid, pid<<QSHIFT, pid, QTDIR);
19974a4d8c2SCharles.Forsyth 		devdir(c, qid, up->genbuf, 0, o->user, DMDIR|0555, dp);
20074a4d8c2SCharles.Forsyth 		release();
20174a4d8c2SCharles.Forsyth 		return 1;
20274a4d8c2SCharles.Forsyth 	}
20374a4d8c2SCharles.Forsyth 
20474a4d8c2SCharles.Forsyth 	if(s >= nelem(progdir))
20574a4d8c2SCharles.Forsyth 		return -1;
20674a4d8c2SCharles.Forsyth 	tab = &progdir[s];
20774a4d8c2SCharles.Forsyth 	path = PATH(c->qid);
20874a4d8c2SCharles.Forsyth 
20974a4d8c2SCharles.Forsyth 	acquire();
21074a4d8c2SCharles.Forsyth 	p = progpid(PID(c->qid));
21174a4d8c2SCharles.Forsyth 	if(p == nil) {
21274a4d8c2SCharles.Forsyth 		release();
21374a4d8c2SCharles.Forsyth 		return -1;
21474a4d8c2SCharles.Forsyth 	}
21574a4d8c2SCharles.Forsyth 
21674a4d8c2SCharles.Forsyth 	o = p->osenv;
21774a4d8c2SCharles.Forsyth 
21874a4d8c2SCharles.Forsyth 	perm = tab->perm;
21974a4d8c2SCharles.Forsyth 	if((perm & 7) == 0)
22074a4d8c2SCharles.Forsyth 		perm = (perm|(perm>>3)|(perm>>6)) & o->pgrp->progmode;
22174a4d8c2SCharles.Forsyth 
22274a4d8c2SCharles.Forsyth 	len = tab->length;
22374a4d8c2SCharles.Forsyth 	mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE);
22474a4d8c2SCharles.Forsyth 	devdir(c, qid, tab->name, len, o->user, perm, dp);
22574a4d8c2SCharles.Forsyth 	release();
22674a4d8c2SCharles.Forsyth 	return 1;
22774a4d8c2SCharles.Forsyth }
22874a4d8c2SCharles.Forsyth 
22974a4d8c2SCharles.Forsyth static Chan*
progattach(char * spec)23074a4d8c2SCharles.Forsyth progattach(char *spec)
23174a4d8c2SCharles.Forsyth {
23274a4d8c2SCharles.Forsyth 	return devattach('p', spec);
23374a4d8c2SCharles.Forsyth }
23474a4d8c2SCharles.Forsyth 
23574a4d8c2SCharles.Forsyth static Walkqid*
progwalk(Chan * c,Chan * nc,char ** name,int nname)23674a4d8c2SCharles.Forsyth progwalk(Chan *c, Chan *nc, char **name, int nname)
23774a4d8c2SCharles.Forsyth {
23874a4d8c2SCharles.Forsyth 	return devwalk(c, nc, name, nname, 0, 0, proggen);
23974a4d8c2SCharles.Forsyth }
24074a4d8c2SCharles.Forsyth 
24174a4d8c2SCharles.Forsyth static int
progstat(Chan * c,uchar * db,int n)24274a4d8c2SCharles.Forsyth progstat(Chan *c, uchar *db, int n)
24374a4d8c2SCharles.Forsyth {
24474a4d8c2SCharles.Forsyth 	return devstat(c, db, n, 0, 0, proggen);
24574a4d8c2SCharles.Forsyth }
24674a4d8c2SCharles.Forsyth 
24774a4d8c2SCharles.Forsyth static Chan*
progopen(Chan * c,int omode)24874a4d8c2SCharles.Forsyth progopen(Chan *c, int omode)
24974a4d8c2SCharles.Forsyth {
25074a4d8c2SCharles.Forsyth 	Prog *p;
25174a4d8c2SCharles.Forsyth 	Osenv *o;
25274a4d8c2SCharles.Forsyth 	Progctl *ctl;
25374a4d8c2SCharles.Forsyth 	int perm;
25474a4d8c2SCharles.Forsyth 
25574a4d8c2SCharles.Forsyth 	if(c->qid.type & QTDIR)
25674a4d8c2SCharles.Forsyth 		return devopen(c, omode, 0, 0, proggen);
25774a4d8c2SCharles.Forsyth 
25874a4d8c2SCharles.Forsyth 	acquire();
25974a4d8c2SCharles.Forsyth 	if (waserror()) {
26074a4d8c2SCharles.Forsyth 		release();
26174a4d8c2SCharles.Forsyth 		nexterror();
26274a4d8c2SCharles.Forsyth 	}
26374a4d8c2SCharles.Forsyth 	p = progpid(PID(c->qid));
26474a4d8c2SCharles.Forsyth 	if(p == nil)
26574a4d8c2SCharles.Forsyth 		error(Ethread);
26674a4d8c2SCharles.Forsyth 
26774a4d8c2SCharles.Forsyth 	o = p->osenv;
26874a4d8c2SCharles.Forsyth 	perm = progdir[QID(c->qid)-1].perm;
26974a4d8c2SCharles.Forsyth 	if((perm & 7) == 0)
27074a4d8c2SCharles.Forsyth 		perm = (perm|(perm>>3)|(perm>>6)) & o->pgrp->progmode;
27174a4d8c2SCharles.Forsyth 	devpermcheck(o->user, perm, omode);
27274a4d8c2SCharles.Forsyth 	omode = openmode(omode);
27374a4d8c2SCharles.Forsyth 
27474a4d8c2SCharles.Forsyth 	switch(QID(c->qid)){
27574a4d8c2SCharles.Forsyth 	default:
27674a4d8c2SCharles.Forsyth 		error(Egreg);
27774a4d8c2SCharles.Forsyth 	case Qnsgrp:
27874a4d8c2SCharles.Forsyth 	case Qpgrp:
27974a4d8c2SCharles.Forsyth 	case Qtext:
28074a4d8c2SCharles.Forsyth 	case Qstatus:
28174a4d8c2SCharles.Forsyth 	case Qstack:
28274a4d8c2SCharles.Forsyth 	case Qctl:
28374a4d8c2SCharles.Forsyth 	case Qfd:
28474a4d8c2SCharles.Forsyth 	case Qexception:
28574a4d8c2SCharles.Forsyth 		break;
28674a4d8c2SCharles.Forsyth 	case Qwait:
28774a4d8c2SCharles.Forsyth 		c->aux = qopen(1024, Qmsg, nil, nil);
28874a4d8c2SCharles.Forsyth 		if(c->aux == nil)
28974a4d8c2SCharles.Forsyth 			error(Enomem);
29074a4d8c2SCharles.Forsyth 		o->childq = c->aux;
29174a4d8c2SCharles.Forsyth 		break;
29274a4d8c2SCharles.Forsyth 	case Qns:
29374a4d8c2SCharles.Forsyth 		c->aux = malloc(sizeof(Mntwalk));
29474a4d8c2SCharles.Forsyth 		if(c->aux == nil)
29574a4d8c2SCharles.Forsyth 			error(Enomem);
29674a4d8c2SCharles.Forsyth 		break;
29774a4d8c2SCharles.Forsyth 	case Qheap:
298*cb6deeccSforsyth 		if(SECURE || p->group->flags&Pprivatemem || omode != ORDWR)
29974a4d8c2SCharles.Forsyth 			error(Eperm);
30074a4d8c2SCharles.Forsyth 		c->aux = malloc(sizeof(Heapqry));
30174a4d8c2SCharles.Forsyth 		if(c->aux == nil)
30274a4d8c2SCharles.Forsyth 			error(Enomem);
30374a4d8c2SCharles.Forsyth 		break;
30474a4d8c2SCharles.Forsyth 	case Qdbgctl:
305*cb6deeccSforsyth 		if(SECURE || p->group->flags&Pprivatemem || omode != ORDWR)
30674a4d8c2SCharles.Forsyth 			error(Eperm);
30774a4d8c2SCharles.Forsyth 		ctl = malloc(sizeof(Progctl));
30874a4d8c2SCharles.Forsyth 		if(ctl == nil)
30974a4d8c2SCharles.Forsyth 			error(Enomem);
31074a4d8c2SCharles.Forsyth 		ctl->q = qopen(1024, Qmsg, nil, nil);
31174a4d8c2SCharles.Forsyth 		if(ctl->q == nil) {
31274a4d8c2SCharles.Forsyth 			free(ctl);
31374a4d8c2SCharles.Forsyth 			error(Enomem);
31474a4d8c2SCharles.Forsyth 		}
31574a4d8c2SCharles.Forsyth 		ctl->bpts = nil;
31674a4d8c2SCharles.Forsyth 		ctl->ref = 1;
31774a4d8c2SCharles.Forsyth 		c->aux = ctl;
31874a4d8c2SCharles.Forsyth 		break;
31974a4d8c2SCharles.Forsyth 	}
32074a4d8c2SCharles.Forsyth 	if(p->state != Pexiting)
32174a4d8c2SCharles.Forsyth 		c->qid.vers = p->pid;
32274a4d8c2SCharles.Forsyth 
32374a4d8c2SCharles.Forsyth 	poperror();
32474a4d8c2SCharles.Forsyth 	release();
32574a4d8c2SCharles.Forsyth 	c->offset = 0;
32674a4d8c2SCharles.Forsyth 	c->mode = omode;
32774a4d8c2SCharles.Forsyth 	c->flag |= COPEN;
32874a4d8c2SCharles.Forsyth 	return c;
32974a4d8c2SCharles.Forsyth }
33074a4d8c2SCharles.Forsyth 
33174a4d8c2SCharles.Forsyth static int
progwstat(Chan * c,uchar * db,int n)33274a4d8c2SCharles.Forsyth progwstat(Chan *c, uchar *db, int n)
33374a4d8c2SCharles.Forsyth {
33474a4d8c2SCharles.Forsyth 	Dir d;
33574a4d8c2SCharles.Forsyth 	Prog *p;
33674a4d8c2SCharles.Forsyth 	char *u;
33774a4d8c2SCharles.Forsyth 	Osenv *o;
33874a4d8c2SCharles.Forsyth 
33974a4d8c2SCharles.Forsyth 	if(c->qid.type&QTDIR)
34074a4d8c2SCharles.Forsyth 		error(Eperm);
34174a4d8c2SCharles.Forsyth 	acquire();
34274a4d8c2SCharles.Forsyth 	p = progpid(PID(c->qid));
34374a4d8c2SCharles.Forsyth 	if(p == nil) {
34474a4d8c2SCharles.Forsyth 		release();
34574a4d8c2SCharles.Forsyth 		error(Ethread);
34674a4d8c2SCharles.Forsyth 	}
34774a4d8c2SCharles.Forsyth 
34874a4d8c2SCharles.Forsyth 	u = up->env->user;
34974a4d8c2SCharles.Forsyth 	o = p->osenv;
35074a4d8c2SCharles.Forsyth 	if(strcmp(u, o->user) != 0 && strcmp(u, eve) != 0) {
35174a4d8c2SCharles.Forsyth 		release();
35274a4d8c2SCharles.Forsyth 		error(Eperm);
35374a4d8c2SCharles.Forsyth 	}
35474a4d8c2SCharles.Forsyth 
35574a4d8c2SCharles.Forsyth 	n = convM2D(db, n, &d, nil);
35674a4d8c2SCharles.Forsyth 	if(n == 0){
35774a4d8c2SCharles.Forsyth 		release();
35874a4d8c2SCharles.Forsyth 		error(Eshortstat);
35974a4d8c2SCharles.Forsyth 	}
36074a4d8c2SCharles.Forsyth 	if(d.mode != ~0UL)
36174a4d8c2SCharles.Forsyth 		o->pgrp->progmode = d.mode&0777;
36274a4d8c2SCharles.Forsyth 	release();
36374a4d8c2SCharles.Forsyth 	return n;
36474a4d8c2SCharles.Forsyth }
36574a4d8c2SCharles.Forsyth 
36674a4d8c2SCharles.Forsyth static void
closedbgctl(Progctl * ctl,Prog * p)36774a4d8c2SCharles.Forsyth closedbgctl(Progctl *ctl, Prog *p)
36874a4d8c2SCharles.Forsyth {
36974a4d8c2SCharles.Forsyth 	Osenv *o;
37074a4d8c2SCharles.Forsyth 
37174a4d8c2SCharles.Forsyth 	if(ctl->ref-- > 1)
37274a4d8c2SCharles.Forsyth 		return;
37374a4d8c2SCharles.Forsyth 	freebpts(ctl->bpts);
37474a4d8c2SCharles.Forsyth 	if(p != nil){
37574a4d8c2SCharles.Forsyth 		o = p->osenv;
37674a4d8c2SCharles.Forsyth 		if(o->debug == ctl){
37774a4d8c2SCharles.Forsyth 			o->debug = nil;
37874a4d8c2SCharles.Forsyth 			p->xec = xec;
37974a4d8c2SCharles.Forsyth 		}
38074a4d8c2SCharles.Forsyth 	}
38174a4d8c2SCharles.Forsyth 	qfree(ctl->q);
38274a4d8c2SCharles.Forsyth 	free(ctl);
38374a4d8c2SCharles.Forsyth }
38474a4d8c2SCharles.Forsyth 
38574a4d8c2SCharles.Forsyth static void
progclose(Chan * c)38674a4d8c2SCharles.Forsyth progclose(Chan *c)
38774a4d8c2SCharles.Forsyth {
38874a4d8c2SCharles.Forsyth 	int i;
38974a4d8c2SCharles.Forsyth 	Prog *f;
39074a4d8c2SCharles.Forsyth 	Osenv *o;
39174a4d8c2SCharles.Forsyth 	Progctl *ctl;
39274a4d8c2SCharles.Forsyth 
39374a4d8c2SCharles.Forsyth 	switch(QID(c->qid)) {
39474a4d8c2SCharles.Forsyth 	case Qns:
39574a4d8c2SCharles.Forsyth 	case Qheap:
39674a4d8c2SCharles.Forsyth 		free(c->aux);
39774a4d8c2SCharles.Forsyth 		break;
39874a4d8c2SCharles.Forsyth 	case Qdbgctl:
39974a4d8c2SCharles.Forsyth 		if((c->flag & COPEN) == 0)
40074a4d8c2SCharles.Forsyth 			return;
40174a4d8c2SCharles.Forsyth 		ctl = c->aux;
40274a4d8c2SCharles.Forsyth 		acquire();
40374a4d8c2SCharles.Forsyth 		closedbgctl(ctl, progpid(PID(c->qid)));
40474a4d8c2SCharles.Forsyth 		release();
40574a4d8c2SCharles.Forsyth 		break;
40674a4d8c2SCharles.Forsyth 	case Qwait:
40774a4d8c2SCharles.Forsyth 		acquire();
40874a4d8c2SCharles.Forsyth 		i = 0;
40974a4d8c2SCharles.Forsyth 		for(;;) {
41074a4d8c2SCharles.Forsyth 			f = progn(i++);
41174a4d8c2SCharles.Forsyth 			if(f == nil)
41274a4d8c2SCharles.Forsyth 				break;
41374a4d8c2SCharles.Forsyth 			o = f->osenv;
41474a4d8c2SCharles.Forsyth 			if(o->waitq == c->aux)
41574a4d8c2SCharles.Forsyth 				o->waitq = nil;
41674a4d8c2SCharles.Forsyth 			if(o->childq == c->aux)
41774a4d8c2SCharles.Forsyth 				o->childq = nil;
41874a4d8c2SCharles.Forsyth 		}
41974a4d8c2SCharles.Forsyth 		release();
42074a4d8c2SCharles.Forsyth 		qfree(c->aux);
42174a4d8c2SCharles.Forsyth 	}
42274a4d8c2SCharles.Forsyth }
42374a4d8c2SCharles.Forsyth 
42474a4d8c2SCharles.Forsyth static int
progsize(Prog * p)42574a4d8c2SCharles.Forsyth progsize(Prog *p)
42674a4d8c2SCharles.Forsyth {
42774a4d8c2SCharles.Forsyth 	int size;
42874a4d8c2SCharles.Forsyth 	Frame *f;
42974a4d8c2SCharles.Forsyth 	uchar *fp;
43074a4d8c2SCharles.Forsyth 	Modlink *m;
43174a4d8c2SCharles.Forsyth 
43274a4d8c2SCharles.Forsyth 	m = p->R.M;
43374a4d8c2SCharles.Forsyth 	size = 0;
43474a4d8c2SCharles.Forsyth 	if(m->MP != H)
43574a4d8c2SCharles.Forsyth 		size += hmsize(D2H(m->MP));
43674a4d8c2SCharles.Forsyth 	if(m->prog != nil)
43774a4d8c2SCharles.Forsyth 		size += msize(m->prog);
43874a4d8c2SCharles.Forsyth 
43974a4d8c2SCharles.Forsyth 	fp = p->R.FP;
44074a4d8c2SCharles.Forsyth 	while(fp != nil) {
44174a4d8c2SCharles.Forsyth 		f = (Frame*)fp;
44274a4d8c2SCharles.Forsyth 		fp = f->fp;
44374a4d8c2SCharles.Forsyth 		if(f->mr != nil) {
44474a4d8c2SCharles.Forsyth 			if(f->mr->MP != H)
44574a4d8c2SCharles.Forsyth 				size += hmsize(D2H(f->mr->MP));
44674a4d8c2SCharles.Forsyth 			if(f->mr->prog != nil)
44774a4d8c2SCharles.Forsyth 				size += msize(f->mr->prog);
44874a4d8c2SCharles.Forsyth 		}
44974a4d8c2SCharles.Forsyth 		if(f->t == nil)
45074a4d8c2SCharles.Forsyth 			size += msize(SEXTYPE(f));
45174a4d8c2SCharles.Forsyth 	}
45274a4d8c2SCharles.Forsyth 	return size/1024;
45374a4d8c2SCharles.Forsyth }
45474a4d8c2SCharles.Forsyth 
45574a4d8c2SCharles.Forsyth static long
progoffset(long offset,char * va,int * np)45674a4d8c2SCharles.Forsyth progoffset(long offset, char *va, int *np)
45774a4d8c2SCharles.Forsyth {
45874a4d8c2SCharles.Forsyth 	if(offset > 0) {
45974a4d8c2SCharles.Forsyth 		offset -= *np;
46074a4d8c2SCharles.Forsyth 		if(offset < 0) {
46174a4d8c2SCharles.Forsyth 			memmove(va, va+*np+offset, -offset);
46274a4d8c2SCharles.Forsyth 			*np = -offset;
46374a4d8c2SCharles.Forsyth 		}
46474a4d8c2SCharles.Forsyth 		else
46574a4d8c2SCharles.Forsyth 			*np = 0;
46674a4d8c2SCharles.Forsyth 	}
46774a4d8c2SCharles.Forsyth 	return offset;
46874a4d8c2SCharles.Forsyth }
46974a4d8c2SCharles.Forsyth 
47074a4d8c2SCharles.Forsyth static int
progqidwidth(Chan * c)47174a4d8c2SCharles.Forsyth progqidwidth(Chan *c)
47274a4d8c2SCharles.Forsyth {
47374a4d8c2SCharles.Forsyth 	char buf[32];
47474a4d8c2SCharles.Forsyth 
47574a4d8c2SCharles.Forsyth 	return sprint(buf, "%lud", c->qid.vers);
47674a4d8c2SCharles.Forsyth }
47774a4d8c2SCharles.Forsyth 
47874a4d8c2SCharles.Forsyth int
progfdprint(Chan * c,int fd,int w,char * s,int ns)47974a4d8c2SCharles.Forsyth progfdprint(Chan *c, int fd, int w, char *s, int ns)
48074a4d8c2SCharles.Forsyth {
48174a4d8c2SCharles.Forsyth 	int n;
48274a4d8c2SCharles.Forsyth 
48374a4d8c2SCharles.Forsyth 	if(w == 0)
48474a4d8c2SCharles.Forsyth 		w = progqidwidth(c);
48574a4d8c2SCharles.Forsyth 	n = snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %*lud %.2ux) %5ld %8lld %s\n",
48674a4d8c2SCharles.Forsyth 		fd,
48774a4d8c2SCharles.Forsyth 		&"r w rw"[(c->mode&3)<<1],
48874a4d8c2SCharles.Forsyth 		devtab[c->type]->dc, c->dev,
48974a4d8c2SCharles.Forsyth 		c->qid.path, w, c->qid.vers, c->qid.type,
49074a4d8c2SCharles.Forsyth 		c->iounit, c->offset, c->name->s);
49174a4d8c2SCharles.Forsyth 	return n;
49274a4d8c2SCharles.Forsyth }
49374a4d8c2SCharles.Forsyth 
49474a4d8c2SCharles.Forsyth static int
progfds(Osenv * o,char * va,int count,long offset)49574a4d8c2SCharles.Forsyth progfds(Osenv *o, char *va, int count, long offset)
49674a4d8c2SCharles.Forsyth {
49774a4d8c2SCharles.Forsyth 	Fgrp *f;
49874a4d8c2SCharles.Forsyth 	Chan *c;
49974a4d8c2SCharles.Forsyth 	int n, i, w, ww;
50074a4d8c2SCharles.Forsyth 
50174a4d8c2SCharles.Forsyth 	f = o->fgrp;	/* f is not locked because we've acquired */
50274a4d8c2SCharles.Forsyth 	n = readstr(0, va, count, o->pgrp->dot->name->s);
50374a4d8c2SCharles.Forsyth 	n += snprint(va+n, count-n, "\n");
50474a4d8c2SCharles.Forsyth 	offset = progoffset(offset, va, &n);
50574a4d8c2SCharles.Forsyth 	/* compute width of qid.path */
50674a4d8c2SCharles.Forsyth 	w = 0;
50774a4d8c2SCharles.Forsyth 	for(i = 0; i <= f->maxfd; i++) {
50874a4d8c2SCharles.Forsyth 		c = f->fd[i];
50974a4d8c2SCharles.Forsyth 		if(c == nil)
51074a4d8c2SCharles.Forsyth 			continue;
51174a4d8c2SCharles.Forsyth 		ww = progqidwidth(c);
51274a4d8c2SCharles.Forsyth 		if(ww > w)
51374a4d8c2SCharles.Forsyth 			w = ww;
51474a4d8c2SCharles.Forsyth 	}
51574a4d8c2SCharles.Forsyth 	for(i = 0; i <= f->maxfd; i++) {
51674a4d8c2SCharles.Forsyth 		c = f->fd[i];
51774a4d8c2SCharles.Forsyth 		if(c == nil)
51874a4d8c2SCharles.Forsyth 			continue;
51974a4d8c2SCharles.Forsyth 		n += progfdprint(c, i, w, va+n, count-n);
52074a4d8c2SCharles.Forsyth 		offset = progoffset(offset, va, &n);
52174a4d8c2SCharles.Forsyth 	}
52274a4d8c2SCharles.Forsyth 	return n;
52374a4d8c2SCharles.Forsyth }
52474a4d8c2SCharles.Forsyth 
52574a4d8c2SCharles.Forsyth Inst *
pc2dispc(Inst * pc,Module * mod)52674a4d8c2SCharles.Forsyth pc2dispc(Inst *pc, Module *mod)
52774a4d8c2SCharles.Forsyth {
52874a4d8c2SCharles.Forsyth 	ulong l, u, m, v;
52974a4d8c2SCharles.Forsyth 	ulong *tab = mod->pctab;
53074a4d8c2SCharles.Forsyth 
53174a4d8c2SCharles.Forsyth 	v = (ulong)pc - (ulong)mod->prog;
53274a4d8c2SCharles.Forsyth 	l = 0;
53374a4d8c2SCharles.Forsyth 	u = mod->nprog-1;
53474a4d8c2SCharles.Forsyth 	while(l < u){
53574a4d8c2SCharles.Forsyth 		m = (l+u+1)/2;
53674a4d8c2SCharles.Forsyth 		if(tab[m] < v)
53774a4d8c2SCharles.Forsyth 			l = m;
53874a4d8c2SCharles.Forsyth 		else if(tab[m] > v)
53974a4d8c2SCharles.Forsyth 			u = m-1;
54074a4d8c2SCharles.Forsyth 		else
54174a4d8c2SCharles.Forsyth 			l = u = m;
54274a4d8c2SCharles.Forsyth 	}
54374a4d8c2SCharles.Forsyth 	if(l == u && tab[u] <= v && u != mod->nprog-1 && tab[u+1] > v)
54474a4d8c2SCharles.Forsyth 		return &mod->prog[u];
54574a4d8c2SCharles.Forsyth 	return 0;
54674a4d8c2SCharles.Forsyth }
54774a4d8c2SCharles.Forsyth 
54874a4d8c2SCharles.Forsyth static int
progstack(REG * reg,int state,char * va,int count,long offset)54974a4d8c2SCharles.Forsyth progstack(REG *reg, int state, char *va, int count, long offset)
55074a4d8c2SCharles.Forsyth {
55174a4d8c2SCharles.Forsyth 	int n;
55274a4d8c2SCharles.Forsyth 	Frame *f;
55374a4d8c2SCharles.Forsyth 	Inst *pc;
55474a4d8c2SCharles.Forsyth 	uchar *fp;
55574a4d8c2SCharles.Forsyth 	Modlink *m;
55674a4d8c2SCharles.Forsyth 
55774a4d8c2SCharles.Forsyth 	n = 0;
55874a4d8c2SCharles.Forsyth 	m = reg->M;
55974a4d8c2SCharles.Forsyth 	fp = reg->FP;
56074a4d8c2SCharles.Forsyth 	pc = reg->PC;
56174a4d8c2SCharles.Forsyth 
56274a4d8c2SCharles.Forsyth 	/*
56374a4d8c2SCharles.Forsyth 	 * all states other than debug and ready block,
56474a4d8c2SCharles.Forsyth 	 * but interp has already advanced the PC
56574a4d8c2SCharles.Forsyth 	 */
56674a4d8c2SCharles.Forsyth 	if(!m->compiled && state != Pready && state != Pdebug && pc > m->prog)
56774a4d8c2SCharles.Forsyth 		pc--;
56874a4d8c2SCharles.Forsyth 	if(m->compiled && m->m->pctab != nil)
56974a4d8c2SCharles.Forsyth 		pc = pc2dispc(pc, m->m);
57074a4d8c2SCharles.Forsyth 
57174a4d8c2SCharles.Forsyth 	while(fp != nil) {
57274a4d8c2SCharles.Forsyth 		f = (Frame*)fp;
57374a4d8c2SCharles.Forsyth 		n += snprint(va+n, count-n, "%.8lux %.8lux %.8lux %.8lux %d %s\n",
57474a4d8c2SCharles.Forsyth 				(ulong)f,		/* FP */
57574a4d8c2SCharles.Forsyth 				(ulong)(pc - m->prog),	/* PC in dis instructions */
57674a4d8c2SCharles.Forsyth 				(ulong)m->MP,		/* MP */
57774a4d8c2SCharles.Forsyth 				(ulong)m->prog,	/* Code for module */
57874a4d8c2SCharles.Forsyth 				m->compiled && m->m->pctab == nil,	/* True if native assembler: fool stack utility for now */
57974a4d8c2SCharles.Forsyth 				m->m->path);	/* File system path */
58074a4d8c2SCharles.Forsyth 
58174a4d8c2SCharles.Forsyth 		if(offset > 0) {
58274a4d8c2SCharles.Forsyth 			offset -= n;
58374a4d8c2SCharles.Forsyth 			if(offset < 0) {
58474a4d8c2SCharles.Forsyth 				memmove(va, va+n+offset, -offset);
58574a4d8c2SCharles.Forsyth 				n = -offset;
58674a4d8c2SCharles.Forsyth 			}
58774a4d8c2SCharles.Forsyth 			else
58874a4d8c2SCharles.Forsyth 				n = 0;
58974a4d8c2SCharles.Forsyth 		}
59074a4d8c2SCharles.Forsyth 
59174a4d8c2SCharles.Forsyth 		pc = f->lr;
59274a4d8c2SCharles.Forsyth 		fp = f->fp;
59374a4d8c2SCharles.Forsyth 		if(f->mr != nil)
59474a4d8c2SCharles.Forsyth 			m = f->mr;
59574a4d8c2SCharles.Forsyth 		if(!m->compiled)
59674a4d8c2SCharles.Forsyth 			pc--;
59774a4d8c2SCharles.Forsyth 		else if(m->m->pctab != nil)
59874a4d8c2SCharles.Forsyth 			pc = pc2dispc(pc, m->m)-1;
59974a4d8c2SCharles.Forsyth 	}
60074a4d8c2SCharles.Forsyth 	return n;
60174a4d8c2SCharles.Forsyth }
60274a4d8c2SCharles.Forsyth 
60374a4d8c2SCharles.Forsyth static int
calldepth(REG * reg)60474a4d8c2SCharles.Forsyth calldepth(REG *reg)
60574a4d8c2SCharles.Forsyth {
60674a4d8c2SCharles.Forsyth 	int n;
60774a4d8c2SCharles.Forsyth 	uchar *fp;
60874a4d8c2SCharles.Forsyth 
60974a4d8c2SCharles.Forsyth 	n = 0;
61074a4d8c2SCharles.Forsyth 	for(fp = reg->FP; fp != nil; fp = ((Frame*)fp)->fp)
61174a4d8c2SCharles.Forsyth 		n++;
61274a4d8c2SCharles.Forsyth 	return n;
61374a4d8c2SCharles.Forsyth }
61474a4d8c2SCharles.Forsyth 
61574a4d8c2SCharles.Forsyth static int
progheap(Heapqry * hq,char * va,int count,ulong offset)61674a4d8c2SCharles.Forsyth progheap(Heapqry *hq, char *va, int count, ulong offset)
61774a4d8c2SCharles.Forsyth {
61874a4d8c2SCharles.Forsyth 	WORD *w;
61974a4d8c2SCharles.Forsyth 	void *p;
62074a4d8c2SCharles.Forsyth 	List *hd;
62174a4d8c2SCharles.Forsyth 	Array *a;
62274a4d8c2SCharles.Forsyth 	char *fmt, *str;
62374a4d8c2SCharles.Forsyth 	Module *m;
62474a4d8c2SCharles.Forsyth 	Modlink *ml;
62574a4d8c2SCharles.Forsyth 	Channel *c;
62674a4d8c2SCharles.Forsyth 	ulong addr;
62774a4d8c2SCharles.Forsyth 	String *ss;
62874a4d8c2SCharles.Forsyth 	union { REAL r; LONG l; WORD w[2]; } rock;
62974a4d8c2SCharles.Forsyth 	int i, s, n, len, signed_off;
63074a4d8c2SCharles.Forsyth 	Type *t;
63174a4d8c2SCharles.Forsyth 
63274a4d8c2SCharles.Forsyth 	n = 0;
63374a4d8c2SCharles.Forsyth 	s = 0;
63474a4d8c2SCharles.Forsyth 	signed_off = offset;
63574a4d8c2SCharles.Forsyth 	addr = hq->addr;
63674a4d8c2SCharles.Forsyth 	for(i = 0; i < hq->count; i++) {
63774a4d8c2SCharles.Forsyth 		switch(hq->fmt) {
63874a4d8c2SCharles.Forsyth 		case 'W':
63974a4d8c2SCharles.Forsyth 			if(addr & 3)
64074a4d8c2SCharles.Forsyth 				return -1;
64174a4d8c2SCharles.Forsyth 			n += snprint(va+n, count-n, "%d\n", *(WORD*)addr);
64274a4d8c2SCharles.Forsyth 			s = sizeof(WORD);
64374a4d8c2SCharles.Forsyth 			break;
64474a4d8c2SCharles.Forsyth 		case 'B':
64574a4d8c2SCharles.Forsyth 			n += snprint(va+n, count-n, "%d\n", *(BYTE*)addr);
64674a4d8c2SCharles.Forsyth 			s = sizeof(BYTE);
64774a4d8c2SCharles.Forsyth 			break;
64874a4d8c2SCharles.Forsyth 		case 'V':
64974a4d8c2SCharles.Forsyth 			if(addr & 3)
65074a4d8c2SCharles.Forsyth 				return -1;
65174a4d8c2SCharles.Forsyth 			w = (WORD*)addr;
65274a4d8c2SCharles.Forsyth 			rock.w[0] = w[0];
65374a4d8c2SCharles.Forsyth 			rock.w[1] = w[1];
65474a4d8c2SCharles.Forsyth 			n += snprint(va+n, count-n, "%lld\n", rock.l);
65574a4d8c2SCharles.Forsyth 			s = sizeof(LONG);
65674a4d8c2SCharles.Forsyth 			break;
65774a4d8c2SCharles.Forsyth 		case 'R':
65874a4d8c2SCharles.Forsyth 			if(addr & 3)
65974a4d8c2SCharles.Forsyth 				return -1;
66074a4d8c2SCharles.Forsyth 			w = (WORD*)addr;
66174a4d8c2SCharles.Forsyth 			rock.w[0] = w[0];
66274a4d8c2SCharles.Forsyth 			rock.w[1] = w[1];
66374a4d8c2SCharles.Forsyth 			n += snprint(va+n, count-n, "%g\n", rock.r);
66474a4d8c2SCharles.Forsyth 			s = sizeof(REAL);
66574a4d8c2SCharles.Forsyth 			break;
66674a4d8c2SCharles.Forsyth 		case 'I':
66774a4d8c2SCharles.Forsyth 			if(addr & 3)
66874a4d8c2SCharles.Forsyth 				return -1;
66974a4d8c2SCharles.Forsyth 			for(m = modules; m != nil; m = m->link)
67074a4d8c2SCharles.Forsyth 				if(m == (Module*)hq->module)
67174a4d8c2SCharles.Forsyth 					break;
67274a4d8c2SCharles.Forsyth 			if(m == nil)
67374a4d8c2SCharles.Forsyth 				error(Ebadctl);
67474a4d8c2SCharles.Forsyth 			addr = (ulong)(m->prog+addr);
67574a4d8c2SCharles.Forsyth 			n += snprint(va+n, count-n, "%D\n", (Inst*)addr);
67674a4d8c2SCharles.Forsyth 			s = sizeof(Inst);
67774a4d8c2SCharles.Forsyth 			break;
67874a4d8c2SCharles.Forsyth 		case 'P':
67974a4d8c2SCharles.Forsyth 			if(addr & 3)
68074a4d8c2SCharles.Forsyth 				return -1;
68174a4d8c2SCharles.Forsyth 			p = *(void**)addr;
68274a4d8c2SCharles.Forsyth 			fmt = "nil\n";
68374a4d8c2SCharles.Forsyth 			if(p != H)
68474a4d8c2SCharles.Forsyth 				fmt = "%lux\n";
68574a4d8c2SCharles.Forsyth 			n += snprint(va+n, count-n, fmt, p);
68674a4d8c2SCharles.Forsyth 			s = sizeof(WORD);
68774a4d8c2SCharles.Forsyth 			break;
68874a4d8c2SCharles.Forsyth 		case 'L':
68974a4d8c2SCharles.Forsyth 			if(addr & 3)
69074a4d8c2SCharles.Forsyth 				return -1;
69174a4d8c2SCharles.Forsyth 			hd = *(List**)addr;
69274a4d8c2SCharles.Forsyth 			if(hd == H || D2H(hd)->t != &Tlist)
69374a4d8c2SCharles.Forsyth 				return -1;
69474a4d8c2SCharles.Forsyth 			n += snprint(va+n, count-n, "%lux.%lux\n", (ulong)&hd->tail, (ulong)hd->data);
69574a4d8c2SCharles.Forsyth 			s = sizeof(WORD);
69674a4d8c2SCharles.Forsyth 			break;
69774a4d8c2SCharles.Forsyth 		case 'A':
69874a4d8c2SCharles.Forsyth 			if(addr & 3)
69974a4d8c2SCharles.Forsyth 				return -1;
70074a4d8c2SCharles.Forsyth 			a = *(Array**)addr;
70174a4d8c2SCharles.Forsyth 			if(a == H)
70274a4d8c2SCharles.Forsyth 				n += snprint(va+n, count-n, "nil\n");
70374a4d8c2SCharles.Forsyth 			else {
70474a4d8c2SCharles.Forsyth 				if(D2H(a)->t != &Tarray)
70574a4d8c2SCharles.Forsyth 					return -1;
70674a4d8c2SCharles.Forsyth 				n += snprint(va+n, count-n, "%d.%lux\n", a->len, (ulong)a->data);
70774a4d8c2SCharles.Forsyth 			}
70874a4d8c2SCharles.Forsyth 			s = sizeof(WORD);
70974a4d8c2SCharles.Forsyth 			break;
71074a4d8c2SCharles.Forsyth 		case 'C':
71174a4d8c2SCharles.Forsyth 			if(addr & 3)
71274a4d8c2SCharles.Forsyth 				return -1;
71374a4d8c2SCharles.Forsyth 			ss = *(String**)addr;
71474a4d8c2SCharles.Forsyth 			if(ss == H)
71574a4d8c2SCharles.Forsyth 				ss = &snil;
71674a4d8c2SCharles.Forsyth 			else
71774a4d8c2SCharles.Forsyth 			if(D2H(ss)->t != &Tstring)
71874a4d8c2SCharles.Forsyth 				return -1;
71974a4d8c2SCharles.Forsyth 			n += snprint(va+n, count-n, "%d.", abs(ss->len));
72074a4d8c2SCharles.Forsyth 			str = string2c(ss);
72174a4d8c2SCharles.Forsyth 			len = strlen(str);
72274a4d8c2SCharles.Forsyth 			if(count-n < len)
72374a4d8c2SCharles.Forsyth 				len = count-n;
72474a4d8c2SCharles.Forsyth 			if(len > 0) {
72574a4d8c2SCharles.Forsyth 				memmove(va+n, str, len);
72674a4d8c2SCharles.Forsyth 				n += len;
72774a4d8c2SCharles.Forsyth 			}
72874a4d8c2SCharles.Forsyth 			break;
72974a4d8c2SCharles.Forsyth 		case 'M':
73074a4d8c2SCharles.Forsyth 			if(addr & 3)
73174a4d8c2SCharles.Forsyth 				return -1;
73274a4d8c2SCharles.Forsyth 			ml = *(Modlink**)addr;
73374a4d8c2SCharles.Forsyth 			fmt = ml == H ? "nil\n" : "%lux\n";
73474a4d8c2SCharles.Forsyth 			n += snprint(va+n, count-n, fmt, ml->MP);
73574a4d8c2SCharles.Forsyth 			s = sizeof(WORD);
73674a4d8c2SCharles.Forsyth 			break;
73774a4d8c2SCharles.Forsyth 		case 'c':
73874a4d8c2SCharles.Forsyth 			if(addr & 3)
73974a4d8c2SCharles.Forsyth 				return -1;
74074a4d8c2SCharles.Forsyth 			c = *(Channel**)addr;
74174a4d8c2SCharles.Forsyth 			if(c == H)
74274a4d8c2SCharles.Forsyth 				n += snprint(va+n, count-n, "nil\n");
74374a4d8c2SCharles.Forsyth 			else{
74474a4d8c2SCharles.Forsyth 				t = D2H(c)->t;
74574a4d8c2SCharles.Forsyth 				if(t != &Tchannel && t != Trdchan && t != Twrchan)
74674a4d8c2SCharles.Forsyth 					return -1;
74774a4d8c2SCharles.Forsyth 				if(c->buf == H)
74874a4d8c2SCharles.Forsyth 					n += snprint(va+n, count-n, "0.%lux\n", (ulong)c);
74974a4d8c2SCharles.Forsyth 				else
75074a4d8c2SCharles.Forsyth 					n += snprint(va+n, count-n, "%d.%lux.%d.%d\n", c->buf->len, (ulong)c->buf->data, c->front, c->size);
75174a4d8c2SCharles.Forsyth 			}
75274a4d8c2SCharles.Forsyth 			break;
75374a4d8c2SCharles.Forsyth 
75474a4d8c2SCharles.Forsyth 		}
75574a4d8c2SCharles.Forsyth 		addr += s;
75674a4d8c2SCharles.Forsyth 		if(signed_off > 0) {
75774a4d8c2SCharles.Forsyth 			signed_off -= n;
75874a4d8c2SCharles.Forsyth 			if(signed_off < 0) {
75974a4d8c2SCharles.Forsyth 				memmove(va, va+n+signed_off, -signed_off);
76074a4d8c2SCharles.Forsyth 				n = -signed_off;
76174a4d8c2SCharles.Forsyth 			}
76274a4d8c2SCharles.Forsyth 			else
76374a4d8c2SCharles.Forsyth 				n = 0;
76474a4d8c2SCharles.Forsyth 		}
76574a4d8c2SCharles.Forsyth 	}
76674a4d8c2SCharles.Forsyth 	return n;
76774a4d8c2SCharles.Forsyth }
76874a4d8c2SCharles.Forsyth 
76974a4d8c2SCharles.Forsyth WORD
modstatus(REG * r,char * ptr,int len)77074a4d8c2SCharles.Forsyth modstatus(REG *r, char *ptr, int len)
77174a4d8c2SCharles.Forsyth {
77274a4d8c2SCharles.Forsyth 	Inst *PC;
77374a4d8c2SCharles.Forsyth 	Frame *f;
77474a4d8c2SCharles.Forsyth 
77574a4d8c2SCharles.Forsyth 	if(r->M->m->name[0] == '$') {
77674a4d8c2SCharles.Forsyth 		f = (Frame*)r->FP;
77774a4d8c2SCharles.Forsyth 		snprint(ptr, len, "%s[%s]", f->mr->m->name, r->M->m->name);
77874a4d8c2SCharles.Forsyth 		if(f->mr->compiled)
77974a4d8c2SCharles.Forsyth 			return (WORD)f->lr;
78074a4d8c2SCharles.Forsyth 		return f->lr - f->mr->prog;
78174a4d8c2SCharles.Forsyth 	}
78274a4d8c2SCharles.Forsyth 	memmove(ptr, r->M->m->name, len);
78374a4d8c2SCharles.Forsyth 	if(r->M->compiled)
78474a4d8c2SCharles.Forsyth 		return (WORD)r->PC;
78574a4d8c2SCharles.Forsyth 	PC = r->PC;
78674a4d8c2SCharles.Forsyth 	/* should really check for blocked states */
78774a4d8c2SCharles.Forsyth 	if(PC > r->M->prog)
78874a4d8c2SCharles.Forsyth 		PC--;
78974a4d8c2SCharles.Forsyth 	return PC - r->M->prog;
79074a4d8c2SCharles.Forsyth }
79174a4d8c2SCharles.Forsyth 
79274a4d8c2SCharles.Forsyth static void
int2flag(int flag,char * s)79374a4d8c2SCharles.Forsyth int2flag(int flag, char *s)
79474a4d8c2SCharles.Forsyth {
79574a4d8c2SCharles.Forsyth 	if(flag == 0){
79674a4d8c2SCharles.Forsyth 		*s = '\0';
79774a4d8c2SCharles.Forsyth 		return;
79874a4d8c2SCharles.Forsyth 	}
79974a4d8c2SCharles.Forsyth 	*s++ = '-';
80074a4d8c2SCharles.Forsyth 	if(flag & MAFTER)
80174a4d8c2SCharles.Forsyth 		*s++ = 'a';
80274a4d8c2SCharles.Forsyth 	if(flag & MBEFORE)
80374a4d8c2SCharles.Forsyth 		*s++ = 'b';
80474a4d8c2SCharles.Forsyth 	if(flag & MCREATE)
80574a4d8c2SCharles.Forsyth 		*s++ = 'c';
80674a4d8c2SCharles.Forsyth 	if(flag & MCACHE)
80774a4d8c2SCharles.Forsyth 		*s++ = 'C';
80874a4d8c2SCharles.Forsyth 	*s = '\0';
80974a4d8c2SCharles.Forsyth }
81074a4d8c2SCharles.Forsyth 
81174a4d8c2SCharles.Forsyth static char*
progtime(ulong msec,char * buf,char * ebuf)81274a4d8c2SCharles.Forsyth progtime(ulong msec, char *buf, char *ebuf)
81374a4d8c2SCharles.Forsyth {
81474a4d8c2SCharles.Forsyth 	int tenths, sec;
81574a4d8c2SCharles.Forsyth 
81674a4d8c2SCharles.Forsyth 	tenths = msec/100;
81774a4d8c2SCharles.Forsyth 	sec = tenths/10;
81874a4d8c2SCharles.Forsyth 	seprint(buf, ebuf, "%4d:%2.2d.%d", sec/60, sec%60, tenths%10);
81974a4d8c2SCharles.Forsyth 	return buf;
82074a4d8c2SCharles.Forsyth }
82174a4d8c2SCharles.Forsyth 
82274a4d8c2SCharles.Forsyth static long
progread(Chan * c,void * va,long n,vlong offset)82374a4d8c2SCharles.Forsyth progread(Chan *c, void *va, long n, vlong offset)
82474a4d8c2SCharles.Forsyth {
82574a4d8c2SCharles.Forsyth 	int i;
82674a4d8c2SCharles.Forsyth 	Prog *p;
82774a4d8c2SCharles.Forsyth 	Osenv *o;
82874a4d8c2SCharles.Forsyth 	Mntwalk *mw;
82974a4d8c2SCharles.Forsyth 	ulong grpid;
83074a4d8c2SCharles.Forsyth 	char *a = va;
83174a4d8c2SCharles.Forsyth 	Progctl *ctl;
83274a4d8c2SCharles.Forsyth 	char mbuf[64], timebuf[12];
83374a4d8c2SCharles.Forsyth 	char flag[10];
83474a4d8c2SCharles.Forsyth 
83574a4d8c2SCharles.Forsyth 	if(c->qid.type & QTDIR)
83674a4d8c2SCharles.Forsyth 		return devdirread(c, a, n, 0, 0, proggen);
83774a4d8c2SCharles.Forsyth 
83874a4d8c2SCharles.Forsyth 	switch(QID(c->qid)){
83974a4d8c2SCharles.Forsyth 	case Qdbgctl:
84074a4d8c2SCharles.Forsyth 		ctl = c->aux;
84174a4d8c2SCharles.Forsyth 		return qread(ctl->q, va, n);
84274a4d8c2SCharles.Forsyth 	case Qstatus:
84374a4d8c2SCharles.Forsyth 		acquire();
84474a4d8c2SCharles.Forsyth 		p = progpid(PID(c->qid));
84574a4d8c2SCharles.Forsyth 		if(p == nil || p->state == Pexiting || p->R.M == H) {
84674a4d8c2SCharles.Forsyth 			release();
84774a4d8c2SCharles.Forsyth 			snprint(up->genbuf, sizeof(up->genbuf), "%8lud %8d %10s %s %10s %5dK %s",
84874a4d8c2SCharles.Forsyth 				PID(c->qid),
84974a4d8c2SCharles.Forsyth 				0,
85074a4d8c2SCharles.Forsyth 				eve,
85174a4d8c2SCharles.Forsyth 				progtime(0, timebuf, timebuf+sizeof(timebuf)),
85274a4d8c2SCharles.Forsyth 				progstate[Pexiting],
85374a4d8c2SCharles.Forsyth 				0,
85474a4d8c2SCharles.Forsyth 				"[$Sys]");
85574a4d8c2SCharles.Forsyth 			return readstr(offset, va, n, up->genbuf);
85674a4d8c2SCharles.Forsyth 		}
85774a4d8c2SCharles.Forsyth 		modstatus(&p->R, mbuf, sizeof(mbuf));
85874a4d8c2SCharles.Forsyth 		o = p->osenv;
85974a4d8c2SCharles.Forsyth 		snprint(up->genbuf, sizeof(up->genbuf), "%8d %8d %10s %s %10s %5dK %s",
86074a4d8c2SCharles.Forsyth 			p->pid,
86174a4d8c2SCharles.Forsyth 			p->group!=nil? p->group->id: 0,
86274a4d8c2SCharles.Forsyth 			o->user,
86374a4d8c2SCharles.Forsyth 			progtime(TK2MS(p->ticks), timebuf, timebuf+sizeof(timebuf)),
86474a4d8c2SCharles.Forsyth 			progstate[p->state],
86574a4d8c2SCharles.Forsyth 			progsize(p),
86674a4d8c2SCharles.Forsyth 			mbuf);
86774a4d8c2SCharles.Forsyth 		release();
86874a4d8c2SCharles.Forsyth 		return readstr(offset, va, n, up->genbuf);
86974a4d8c2SCharles.Forsyth 	case Qwait:
87074a4d8c2SCharles.Forsyth 		return qread(c->aux, va, n);
87174a4d8c2SCharles.Forsyth 	case Qns:
87274a4d8c2SCharles.Forsyth 		acquire();
87374a4d8c2SCharles.Forsyth 		if(waserror()){
87474a4d8c2SCharles.Forsyth 			release();
87574a4d8c2SCharles.Forsyth 			nexterror();
87674a4d8c2SCharles.Forsyth 		}
87774a4d8c2SCharles.Forsyth 		p = progpid(PID(c->qid));
87874a4d8c2SCharles.Forsyth 		if(p == nil)
87974a4d8c2SCharles.Forsyth 			error(Ethread);
88074a4d8c2SCharles.Forsyth 		mw = c->aux;
88174a4d8c2SCharles.Forsyth 		if(mw->cddone){
88274a4d8c2SCharles.Forsyth 			poperror();
88374a4d8c2SCharles.Forsyth 			release();
88474a4d8c2SCharles.Forsyth 			return 0;
88574a4d8c2SCharles.Forsyth 		}
88674a4d8c2SCharles.Forsyth 		o = p->osenv;
88774a4d8c2SCharles.Forsyth 		mntscan(mw, o->pgrp);
88874a4d8c2SCharles.Forsyth 		if(mw->mh == 0) {
88974a4d8c2SCharles.Forsyth 			mw->cddone = 1;
89074a4d8c2SCharles.Forsyth 			i = snprint(a, n, "cd %s\n", o->pgrp->dot->name->s);
89174a4d8c2SCharles.Forsyth 			poperror();
89274a4d8c2SCharles.Forsyth 			release();
89374a4d8c2SCharles.Forsyth 			return i;
89474a4d8c2SCharles.Forsyth 		}
89574a4d8c2SCharles.Forsyth 		int2flag(mw->cm->mflag, flag);
89674a4d8c2SCharles.Forsyth 		if(strcmp(mw->cm->to->name->s, "#M") == 0){
89774a4d8c2SCharles.Forsyth 			i = snprint(a, n, "mount %s %s %s %s\n", flag,
89874a4d8c2SCharles.Forsyth 				mw->cm->to->mchan->name->s,
89974a4d8c2SCharles.Forsyth 				mw->mh->from->name->s, mw->cm->spec? mw->cm->spec : "");
90074a4d8c2SCharles.Forsyth 		}else
90174a4d8c2SCharles.Forsyth 			i = snprint(a, n, "bind %s %s %s\n", flag,
90274a4d8c2SCharles.Forsyth 				mw->cm->to->name->s, mw->mh->from->name->s);
90374a4d8c2SCharles.Forsyth 		poperror();
90474a4d8c2SCharles.Forsyth 		release();
90574a4d8c2SCharles.Forsyth 		return i;
90674a4d8c2SCharles.Forsyth 	case Qnsgrp:
90774a4d8c2SCharles.Forsyth 		acquire();
90874a4d8c2SCharles.Forsyth 		p = progpid(PID(c->qid));
90974a4d8c2SCharles.Forsyth 		if(p == nil) {
91074a4d8c2SCharles.Forsyth 			release();
91174a4d8c2SCharles.Forsyth 			error(Ethread);
91274a4d8c2SCharles.Forsyth 		}
91374a4d8c2SCharles.Forsyth 		grpid = ((Osenv *)p->osenv)->pgrp->pgrpid;
91474a4d8c2SCharles.Forsyth 		release();
91574a4d8c2SCharles.Forsyth 		return readnum(offset, va, n, grpid, NUMSIZE);
91674a4d8c2SCharles.Forsyth 	case Qpgrp:
91774a4d8c2SCharles.Forsyth 		acquire();
91874a4d8c2SCharles.Forsyth 		p = progpid(PID(c->qid));
91974a4d8c2SCharles.Forsyth 		if(p == nil) {
92074a4d8c2SCharles.Forsyth 			release();
92174a4d8c2SCharles.Forsyth 			error(Ethread);
92274a4d8c2SCharles.Forsyth 		}
92374a4d8c2SCharles.Forsyth 		grpid = p->group!=nil? p->group->id: 0;
92474a4d8c2SCharles.Forsyth 		release();
92574a4d8c2SCharles.Forsyth 		return readnum(offset, va, n, grpid, NUMSIZE);
92674a4d8c2SCharles.Forsyth 	case Qstack:
92774a4d8c2SCharles.Forsyth 		acquire();
92874a4d8c2SCharles.Forsyth 		p = progpid(PID(c->qid));
92974a4d8c2SCharles.Forsyth 		if(p == nil || p->state == Pexiting) {
93074a4d8c2SCharles.Forsyth 			release();
93174a4d8c2SCharles.Forsyth 			error(Ethread);
93274a4d8c2SCharles.Forsyth 		}
93374a4d8c2SCharles.Forsyth 		if(p->state == Pready) {
93474a4d8c2SCharles.Forsyth 			release();
93574a4d8c2SCharles.Forsyth 			error(Estopped);
93674a4d8c2SCharles.Forsyth 		}
93774a4d8c2SCharles.Forsyth 		n = progstack(&p->R, p->state, va, n, offset);
93874a4d8c2SCharles.Forsyth 		release();
93974a4d8c2SCharles.Forsyth 		return n;
94074a4d8c2SCharles.Forsyth 	case Qheap:
94174a4d8c2SCharles.Forsyth 		acquire();
94274a4d8c2SCharles.Forsyth 		if(waserror()){
94374a4d8c2SCharles.Forsyth 			release();
94474a4d8c2SCharles.Forsyth 			nexterror();
94574a4d8c2SCharles.Forsyth 		}
94674a4d8c2SCharles.Forsyth 		n = progheap(c->aux, va, n, offset);
94774a4d8c2SCharles.Forsyth 		if(n == -1)
94874a4d8c2SCharles.Forsyth 			error(Emisalign);
94974a4d8c2SCharles.Forsyth 		poperror();
95074a4d8c2SCharles.Forsyth 		release();
95174a4d8c2SCharles.Forsyth 		return n;
95274a4d8c2SCharles.Forsyth 	case Qfd:
95374a4d8c2SCharles.Forsyth 		acquire();
95474a4d8c2SCharles.Forsyth 		if(waserror()) {
95574a4d8c2SCharles.Forsyth 			release();
95674a4d8c2SCharles.Forsyth 			nexterror();
95774a4d8c2SCharles.Forsyth 		}
95874a4d8c2SCharles.Forsyth 		p = progpid(PID(c->qid));
95974a4d8c2SCharles.Forsyth 		if(p == nil)
96074a4d8c2SCharles.Forsyth 			error(Ethread);
96174a4d8c2SCharles.Forsyth 		o = p->osenv;
96274a4d8c2SCharles.Forsyth 		n = progfds(o, va, n, offset);
96374a4d8c2SCharles.Forsyth 		poperror();
96474a4d8c2SCharles.Forsyth 		release();
96574a4d8c2SCharles.Forsyth 		return n;
96674a4d8c2SCharles.Forsyth 	case Qexception:
96774a4d8c2SCharles.Forsyth 		acquire();
96874a4d8c2SCharles.Forsyth 		p = progpid(PID(c->qid));
96974a4d8c2SCharles.Forsyth 		if(p == nil) {
97074a4d8c2SCharles.Forsyth 			release();
97174a4d8c2SCharles.Forsyth 			error(Ethread);
97274a4d8c2SCharles.Forsyth 		}
97374a4d8c2SCharles.Forsyth 		if(p->exstr == nil)
97474a4d8c2SCharles.Forsyth 			up->genbuf[0] = 0;
97574a4d8c2SCharles.Forsyth 		else
97674a4d8c2SCharles.Forsyth 			snprint(up->genbuf, sizeof(up->genbuf), p->exstr);
97774a4d8c2SCharles.Forsyth 		release();
97874a4d8c2SCharles.Forsyth 		return readstr(offset, va, n, up->genbuf);
97974a4d8c2SCharles.Forsyth 	}
98074a4d8c2SCharles.Forsyth 	error(Egreg);
98174a4d8c2SCharles.Forsyth 	return 0;
98274a4d8c2SCharles.Forsyth }
98374a4d8c2SCharles.Forsyth 
98474a4d8c2SCharles.Forsyth static void
mntscan(Mntwalk * mw,Pgrp * pg)98574a4d8c2SCharles.Forsyth mntscan(Mntwalk *mw, Pgrp *pg)
98674a4d8c2SCharles.Forsyth {
98774a4d8c2SCharles.Forsyth 	Mount *t;
98874a4d8c2SCharles.Forsyth 	Mhead *f;
98974a4d8c2SCharles.Forsyth 	int nxt, i;
99074a4d8c2SCharles.Forsyth 	ulong last, bestmid;
99174a4d8c2SCharles.Forsyth 
99274a4d8c2SCharles.Forsyth 	rlock(&pg->ns);
99374a4d8c2SCharles.Forsyth 
99474a4d8c2SCharles.Forsyth 	nxt = 0;
99574a4d8c2SCharles.Forsyth 	bestmid = ~0;
99674a4d8c2SCharles.Forsyth 
99774a4d8c2SCharles.Forsyth 	last = 0;
99874a4d8c2SCharles.Forsyth 	if(mw->mh)
99974a4d8c2SCharles.Forsyth 		last = mw->cm->mountid;
100074a4d8c2SCharles.Forsyth 
100174a4d8c2SCharles.Forsyth 	for(i = 0; i < MNTHASH; i++) {
100274a4d8c2SCharles.Forsyth 		for(f = pg->mnthash[i]; f; f = f->hash) {
100374a4d8c2SCharles.Forsyth 			for(t = f->mount; t; t = t->next) {
100474a4d8c2SCharles.Forsyth 				if(mw->mh == 0 ||
100574a4d8c2SCharles.Forsyth 				  (t->mountid > last && t->mountid < bestmid)) {
100674a4d8c2SCharles.Forsyth 					mw->cm = t;
100774a4d8c2SCharles.Forsyth 					mw->mh = f;
100874a4d8c2SCharles.Forsyth 					bestmid = mw->cm->mountid;
100974a4d8c2SCharles.Forsyth 					nxt = 1;
101074a4d8c2SCharles.Forsyth 				}
101174a4d8c2SCharles.Forsyth 			}
101274a4d8c2SCharles.Forsyth 		}
101374a4d8c2SCharles.Forsyth 	}
101474a4d8c2SCharles.Forsyth 	if(nxt == 0)
101574a4d8c2SCharles.Forsyth 		mw->mh = 0;
101674a4d8c2SCharles.Forsyth 
101774a4d8c2SCharles.Forsyth 	runlock(&pg->ns);
101874a4d8c2SCharles.Forsyth }
101974a4d8c2SCharles.Forsyth 
102074a4d8c2SCharles.Forsyth static long
progwrite(Chan * c,void * va,long n,vlong offset)102174a4d8c2SCharles.Forsyth progwrite(Chan *c, void *va, long n, vlong offset)
102274a4d8c2SCharles.Forsyth {
102374a4d8c2SCharles.Forsyth 	Prog *p, *f;
102474a4d8c2SCharles.Forsyth 	Heapqry *hq;
102574a4d8c2SCharles.Forsyth 	char buf[128];
102674a4d8c2SCharles.Forsyth 	Progctl *ctl;
102774a4d8c2SCharles.Forsyth 	char *b;
102874a4d8c2SCharles.Forsyth 	int i, pc;
102974a4d8c2SCharles.Forsyth 	Cmdbuf *cb;
103074a4d8c2SCharles.Forsyth 	Cmdtab *ct;
103174a4d8c2SCharles.Forsyth 
103274a4d8c2SCharles.Forsyth 	USED(offset);
103374a4d8c2SCharles.Forsyth 	USED(va);
103474a4d8c2SCharles.Forsyth 
103574a4d8c2SCharles.Forsyth 	if(c->qid.type & QTDIR)
103674a4d8c2SCharles.Forsyth 		error(Eisdir);
103774a4d8c2SCharles.Forsyth 
103874a4d8c2SCharles.Forsyth 	acquire();
103974a4d8c2SCharles.Forsyth 	if(waserror()) {
104074a4d8c2SCharles.Forsyth 		release();
104174a4d8c2SCharles.Forsyth 		nexterror();
104274a4d8c2SCharles.Forsyth 	}
104374a4d8c2SCharles.Forsyth 	p = progpid(PID(c->qid));
104474a4d8c2SCharles.Forsyth 	if(p == nil)
104574a4d8c2SCharles.Forsyth 		error(Ethread);
104674a4d8c2SCharles.Forsyth 
104774a4d8c2SCharles.Forsyth 	switch(QID(c->qid)){
104874a4d8c2SCharles.Forsyth 	case Qctl:
104974a4d8c2SCharles.Forsyth 		cb = parsecmd(va, n);
105074a4d8c2SCharles.Forsyth 		if(waserror()){
105174a4d8c2SCharles.Forsyth 			free(cb);
105274a4d8c2SCharles.Forsyth 			nexterror();
105374a4d8c2SCharles.Forsyth 		}
105474a4d8c2SCharles.Forsyth 		ct = lookupcmd(cb, progcmd, nelem(progcmd));
105574a4d8c2SCharles.Forsyth 		switch(ct->index){
105674a4d8c2SCharles.Forsyth 		case CMkillgrp:
105774a4d8c2SCharles.Forsyth 			killgrp(p, "killed");
105874a4d8c2SCharles.Forsyth 			break;
105974a4d8c2SCharles.Forsyth 		case CMkill:
106074a4d8c2SCharles.Forsyth 			killprog(p, "killed");
106174a4d8c2SCharles.Forsyth 			break;
106274a4d8c2SCharles.Forsyth 		case CMrestricted:
106374a4d8c2SCharles.Forsyth 			p->flags |= Prestrict;
106474a4d8c2SCharles.Forsyth 			break;
106574a4d8c2SCharles.Forsyth 		case CMexceptions:
106674a4d8c2SCharles.Forsyth 			if(p->group->id != p->pid)
106774a4d8c2SCharles.Forsyth 				error(Eperm);
106874a4d8c2SCharles.Forsyth 			if(strcmp(cb->f[1], "propagate") == 0)
106974a4d8c2SCharles.Forsyth 				p->flags |= Ppropagate;
107074a4d8c2SCharles.Forsyth 			else if(strcmp(cb->f[1], "notifyleader") == 0)
107174a4d8c2SCharles.Forsyth 				p->flags |= Pnotifyleader;
107274a4d8c2SCharles.Forsyth 			else
107374a4d8c2SCharles.Forsyth 				error(Ebadctl);
107474a4d8c2SCharles.Forsyth 			break;
107574a4d8c2SCharles.Forsyth 		case CMprivate:
1076*cb6deeccSforsyth 			p->group->flags |= Pprivatemem;
107774a4d8c2SCharles.Forsyth 			break;
107874a4d8c2SCharles.Forsyth 		}
107974a4d8c2SCharles.Forsyth 		poperror();
108074a4d8c2SCharles.Forsyth 		free(cb);
108174a4d8c2SCharles.Forsyth 		break;
108274a4d8c2SCharles.Forsyth 	case Qdbgctl:
108374a4d8c2SCharles.Forsyth 		cb = parsecmd(va, n);
108474a4d8c2SCharles.Forsyth 		if(waserror()){
108574a4d8c2SCharles.Forsyth 			free(cb);
108674a4d8c2SCharles.Forsyth 			nexterror();
108774a4d8c2SCharles.Forsyth 		}
108874a4d8c2SCharles.Forsyth 		if(cb->nf == 1 && strncmp(cb->f[0], "step", 4) == 0)
108974a4d8c2SCharles.Forsyth 			ct = progdbgcmd;
109074a4d8c2SCharles.Forsyth 		else
109174a4d8c2SCharles.Forsyth 			ct = lookupcmd(cb, progdbgcmd, nelem(progdbgcmd));
109274a4d8c2SCharles.Forsyth 		switch(ct->index){
109374a4d8c2SCharles.Forsyth 		case CDstep:
109474a4d8c2SCharles.Forsyth 			if(cb->nf == 1)
109574a4d8c2SCharles.Forsyth 				i = strtoul(cb->f[0]+4, nil, 0);
109674a4d8c2SCharles.Forsyth 			else
109774a4d8c2SCharles.Forsyth 				i = strtoul(cb->f[1], nil, 0);
109874a4d8c2SCharles.Forsyth 			dbgstep(c->aux, p, i);
109974a4d8c2SCharles.Forsyth 			break;
110074a4d8c2SCharles.Forsyth 		case CDtoret:
110174a4d8c2SCharles.Forsyth 			f = currun();
110274a4d8c2SCharles.Forsyth 			i = calldepth(&p->R);
110374a4d8c2SCharles.Forsyth 			while(f->kill == nil) {
110474a4d8c2SCharles.Forsyth 				dbgstep(c->aux, p, 1024);
110574a4d8c2SCharles.Forsyth 				if(i > calldepth(&p->R))
110674a4d8c2SCharles.Forsyth 					break;
110774a4d8c2SCharles.Forsyth 			}
110874a4d8c2SCharles.Forsyth 			break;
110974a4d8c2SCharles.Forsyth 		case CDcont:
111074a4d8c2SCharles.Forsyth 			f = currun();
111174a4d8c2SCharles.Forsyth 			while(f->kill == nil)
111274a4d8c2SCharles.Forsyth 				dbgstep(c->aux, p, 1024);
111374a4d8c2SCharles.Forsyth 			break;
111474a4d8c2SCharles.Forsyth 		case CDstart:
111574a4d8c2SCharles.Forsyth 			dbgstart(p);
111674a4d8c2SCharles.Forsyth 			break;
111774a4d8c2SCharles.Forsyth 		case CDstop:
111874a4d8c2SCharles.Forsyth 			ctl = c->aux;
111974a4d8c2SCharles.Forsyth 			ctl->stop = 1;
112074a4d8c2SCharles.Forsyth 			break;
112174a4d8c2SCharles.Forsyth 		case CDunstop:
112274a4d8c2SCharles.Forsyth 			ctl = c->aux;
112374a4d8c2SCharles.Forsyth 			ctl->stop = 0;
112474a4d8c2SCharles.Forsyth 			break;
112574a4d8c2SCharles.Forsyth 		case CDbpt:
112674a4d8c2SCharles.Forsyth 			pc = strtoul(cb->f[3], nil, 10);
112774a4d8c2SCharles.Forsyth 			ctl = c->aux;
112874a4d8c2SCharles.Forsyth 			if(strcmp(cb->f[1], "set") == 0)
112974a4d8c2SCharles.Forsyth 				ctl->bpts = setbpt(ctl->bpts, cb->f[2], pc);
113074a4d8c2SCharles.Forsyth 			else if(strcmp(cb->f[1], "del") == 0)
113174a4d8c2SCharles.Forsyth 				ctl->bpts = delbpt(ctl->bpts, cb->f[2], pc);
113274a4d8c2SCharles.Forsyth 			else
113374a4d8c2SCharles.Forsyth 				error(Ebadctl);
113474a4d8c2SCharles.Forsyth 			break;
113574a4d8c2SCharles.Forsyth 		case CDmaim:
113674a4d8c2SCharles.Forsyth 			p->kill = "maim";
113774a4d8c2SCharles.Forsyth 			break;
113874a4d8c2SCharles.Forsyth 		}
113974a4d8c2SCharles.Forsyth 		poperror();
114074a4d8c2SCharles.Forsyth 		free(cb);
114174a4d8c2SCharles.Forsyth 		break;
114274a4d8c2SCharles.Forsyth 	case Qheap:
114374a4d8c2SCharles.Forsyth 		/*
114474a4d8c2SCharles.Forsyth 		 * Heap query:
114574a4d8c2SCharles.Forsyth 		 *	addr.Fn
114674a4d8c2SCharles.Forsyth 		 *	pc+module.In
114774a4d8c2SCharles.Forsyth 		 */
114874a4d8c2SCharles.Forsyth 		i = n;
114974a4d8c2SCharles.Forsyth 		if(i > sizeof(buf)-1)
115074a4d8c2SCharles.Forsyth 			i = sizeof(buf)-1;
115174a4d8c2SCharles.Forsyth 		memmove(buf, va, i);
115274a4d8c2SCharles.Forsyth 		buf[i] = '\0';
115374a4d8c2SCharles.Forsyth 		hq = c->aux;
115474a4d8c2SCharles.Forsyth 		hq->addr = strtoul(buf, &b, 0);
115574a4d8c2SCharles.Forsyth 		if(*b == '+')
115674a4d8c2SCharles.Forsyth 			hq->module = strtoul(b, &b, 0);
115774a4d8c2SCharles.Forsyth 		if(*b++ != '.')
115874a4d8c2SCharles.Forsyth 			error(Ebadctl);
115974a4d8c2SCharles.Forsyth 		hq->fmt = *b++;
116074a4d8c2SCharles.Forsyth 		hq->count = strtoul(b, nil, 0);
116174a4d8c2SCharles.Forsyth 		break;
116274a4d8c2SCharles.Forsyth 	default:
116374a4d8c2SCharles.Forsyth 		print("unknown qid in procwrite\n");
116474a4d8c2SCharles.Forsyth 		error(Egreg);
116574a4d8c2SCharles.Forsyth 	}
116674a4d8c2SCharles.Forsyth 	poperror();
116774a4d8c2SCharles.Forsyth 	release();
116874a4d8c2SCharles.Forsyth 	return n;
116974a4d8c2SCharles.Forsyth }
117074a4d8c2SCharles.Forsyth 
117174a4d8c2SCharles.Forsyth static Bpt*
setbpt(Bpt * bpts,char * path,int pc)117274a4d8c2SCharles.Forsyth setbpt(Bpt *bpts, char *path, int pc)
117374a4d8c2SCharles.Forsyth {
117474a4d8c2SCharles.Forsyth 	int n;
117574a4d8c2SCharles.Forsyth 	Bpt *b;
117674a4d8c2SCharles.Forsyth 
117774a4d8c2SCharles.Forsyth 	n = strlen(path);
117874a4d8c2SCharles.Forsyth 	b = mallocz(sizeof *b + n, 0);
117974a4d8c2SCharles.Forsyth 	if(b == nil)
118074a4d8c2SCharles.Forsyth 		return bpts;
118174a4d8c2SCharles.Forsyth 	b->pc = pc;
118274a4d8c2SCharles.Forsyth 	memmove(b->path, path, n+1);
118374a4d8c2SCharles.Forsyth 	b->file = b->path;
118474a4d8c2SCharles.Forsyth 	path = strrchr(b->path, '/');
118574a4d8c2SCharles.Forsyth 	if(path != nil)
118674a4d8c2SCharles.Forsyth 		b->file = path + 1;
118774a4d8c2SCharles.Forsyth 	b->next = bpts;
118874a4d8c2SCharles.Forsyth 	return b;
118974a4d8c2SCharles.Forsyth }
119074a4d8c2SCharles.Forsyth 
119174a4d8c2SCharles.Forsyth static Bpt*
delbpt(Bpt * bpts,char * path,int pc)119274a4d8c2SCharles.Forsyth delbpt(Bpt *bpts, char *path, int pc)
119374a4d8c2SCharles.Forsyth {
119474a4d8c2SCharles.Forsyth 	Bpt *b, **last;
119574a4d8c2SCharles.Forsyth 
119674a4d8c2SCharles.Forsyth 	last = &bpts;
119774a4d8c2SCharles.Forsyth 	for(b = bpts; b != nil; b = b->next){
119874a4d8c2SCharles.Forsyth 		if(b->pc == pc && strcmp(b->path, path) == 0) {
119974a4d8c2SCharles.Forsyth 			*last = b->next;
120074a4d8c2SCharles.Forsyth 			free(b);
120174a4d8c2SCharles.Forsyth 			break;
120274a4d8c2SCharles.Forsyth 		}
120374a4d8c2SCharles.Forsyth 		last = &b->next;
120474a4d8c2SCharles.Forsyth 	}
120574a4d8c2SCharles.Forsyth 	return bpts;
120674a4d8c2SCharles.Forsyth }
120774a4d8c2SCharles.Forsyth 
120874a4d8c2SCharles.Forsyth static void
freebpts(Bpt * b)120974a4d8c2SCharles.Forsyth freebpts(Bpt *b)
121074a4d8c2SCharles.Forsyth {
121174a4d8c2SCharles.Forsyth 	Bpt *next;
121274a4d8c2SCharles.Forsyth 
121374a4d8c2SCharles.Forsyth 	for(; b != nil; b = next){
121474a4d8c2SCharles.Forsyth 		next = b->next;
121574a4d8c2SCharles.Forsyth 		free(b);
121674a4d8c2SCharles.Forsyth 	}
121774a4d8c2SCharles.Forsyth }
121874a4d8c2SCharles.Forsyth 
121974a4d8c2SCharles.Forsyth static void
telldbg(Progctl * ctl,char * msg)122074a4d8c2SCharles.Forsyth telldbg(Progctl *ctl, char *msg)
122174a4d8c2SCharles.Forsyth {
122274a4d8c2SCharles.Forsyth 	kstrcpy(ctl->msg, msg, ERRMAX);
122374a4d8c2SCharles.Forsyth 	ctl->debugger = nil;
122474a4d8c2SCharles.Forsyth 	wakeup(&ctl->r);
122574a4d8c2SCharles.Forsyth }
122674a4d8c2SCharles.Forsyth 
122774a4d8c2SCharles.Forsyth static void
dbgstart(Prog * p)122874a4d8c2SCharles.Forsyth dbgstart(Prog *p)
122974a4d8c2SCharles.Forsyth {
123074a4d8c2SCharles.Forsyth 	Osenv *o;
123174a4d8c2SCharles.Forsyth 	Progctl *ctl;
123274a4d8c2SCharles.Forsyth 
123374a4d8c2SCharles.Forsyth 	o = p->osenv;
123474a4d8c2SCharles.Forsyth 	ctl = o->debug;
123574a4d8c2SCharles.Forsyth 	if(ctl != nil && ctl->debugger != nil)
123674a4d8c2SCharles.Forsyth 		error("prog debugged");
123774a4d8c2SCharles.Forsyth 	if(p->state == Pdebug)
123874a4d8c2SCharles.Forsyth 		addrun(p);
123974a4d8c2SCharles.Forsyth 	o->debug = nil;
124074a4d8c2SCharles.Forsyth 	p->xec = xec;
124174a4d8c2SCharles.Forsyth }
124274a4d8c2SCharles.Forsyth 
124374a4d8c2SCharles.Forsyth static int
xecdone(void * vc)124474a4d8c2SCharles.Forsyth xecdone(void *vc)
124574a4d8c2SCharles.Forsyth {
124674a4d8c2SCharles.Forsyth 	Progctl *ctl = vc;
124774a4d8c2SCharles.Forsyth 
124874a4d8c2SCharles.Forsyth 	return ctl->debugger == nil;
124974a4d8c2SCharles.Forsyth }
125074a4d8c2SCharles.Forsyth 
125174a4d8c2SCharles.Forsyth static void
dbgstep(Progctl * vctl,Prog * p,int n)125274a4d8c2SCharles.Forsyth dbgstep(Progctl *vctl, Prog *p, int n)
125374a4d8c2SCharles.Forsyth {
125474a4d8c2SCharles.Forsyth 	Osenv *o;
125574a4d8c2SCharles.Forsyth 	Progctl *ctl;
125674a4d8c2SCharles.Forsyth 	char buf[ERRMAX+20], *msg;
125774a4d8c2SCharles.Forsyth 
125874a4d8c2SCharles.Forsyth 	if(p == currun())
125974a4d8c2SCharles.Forsyth 		error("cannot step yourself");
126074a4d8c2SCharles.Forsyth 
126174a4d8c2SCharles.Forsyth 	if(p->state == Pbroken)
126274a4d8c2SCharles.Forsyth 		error("prog broken");
126374a4d8c2SCharles.Forsyth 
126474a4d8c2SCharles.Forsyth 	ctl = vctl;
126574a4d8c2SCharles.Forsyth 	if(ctl->debugger != nil)
126674a4d8c2SCharles.Forsyth 		error("prog already debugged");
126774a4d8c2SCharles.Forsyth 
126874a4d8c2SCharles.Forsyth 	o = p->osenv;
126974a4d8c2SCharles.Forsyth 	if(o->debug == nil) {
127074a4d8c2SCharles.Forsyth 		o->debug = ctl;
127174a4d8c2SCharles.Forsyth 		p->xec = dbgxec;
127274a4d8c2SCharles.Forsyth 	}else if(o->debug != ctl)
127374a4d8c2SCharles.Forsyth 		error("prog already debugged");
127474a4d8c2SCharles.Forsyth 
127574a4d8c2SCharles.Forsyth 	ctl->step = n;
127674a4d8c2SCharles.Forsyth 	if(p->state == Pdebug)
127774a4d8c2SCharles.Forsyth 		addrun(p);
127874a4d8c2SCharles.Forsyth 	ctl->debugger = up;
127974a4d8c2SCharles.Forsyth 	strcpy(buf, "child: ");
128074a4d8c2SCharles.Forsyth 	msg = buf+7;
128174a4d8c2SCharles.Forsyth 	ctl->msg = msg;
128274a4d8c2SCharles.Forsyth 
128374a4d8c2SCharles.Forsyth 	/*
128474a4d8c2SCharles.Forsyth 	 * wait for reply from dbgxec; release is okay because prog is now
128574a4d8c2SCharles.Forsyth 	 * debugged, cannot exit.
128674a4d8c2SCharles.Forsyth 	 */
128774a4d8c2SCharles.Forsyth 	if(waserror()){
128874a4d8c2SCharles.Forsyth 		acquire();
128974a4d8c2SCharles.Forsyth 		ctl->debugger = nil;
129074a4d8c2SCharles.Forsyth 		ctl->msg = nil;
129174a4d8c2SCharles.Forsyth 		o->debug = nil;
129274a4d8c2SCharles.Forsyth 		p->xec = xec;
129374a4d8c2SCharles.Forsyth 		nexterror();
129474a4d8c2SCharles.Forsyth 	}
129574a4d8c2SCharles.Forsyth 	release();
129674a4d8c2SCharles.Forsyth 	sleep(&ctl->r, xecdone, ctl);
129774a4d8c2SCharles.Forsyth 	poperror();
129874a4d8c2SCharles.Forsyth 	acquire();
129974a4d8c2SCharles.Forsyth 	if(msg[0] != '\0')
130074a4d8c2SCharles.Forsyth 		error(buf);
130174a4d8c2SCharles.Forsyth }
130274a4d8c2SCharles.Forsyth 
130374a4d8c2SCharles.Forsyth void
dbgexit(Prog * kid,int broken,char * estr)130474a4d8c2SCharles.Forsyth dbgexit(Prog *kid, int broken, char *estr)
130574a4d8c2SCharles.Forsyth {
130674a4d8c2SCharles.Forsyth 	int n;
130774a4d8c2SCharles.Forsyth 	Osenv *e;
130874a4d8c2SCharles.Forsyth 	Progctl *ctl;
130974a4d8c2SCharles.Forsyth 	char buf[ERRMAX+20];
131074a4d8c2SCharles.Forsyth 
131174a4d8c2SCharles.Forsyth 	e = kid->osenv;
131274a4d8c2SCharles.Forsyth 	ctl = e->debug;
131374a4d8c2SCharles.Forsyth 	e->debug = nil;
131474a4d8c2SCharles.Forsyth 	kid->xec = xec;
131574a4d8c2SCharles.Forsyth 
131674a4d8c2SCharles.Forsyth 	if(broken)
131774a4d8c2SCharles.Forsyth 		n = snprint(buf, sizeof(buf), "broken: %s", estr);
131874a4d8c2SCharles.Forsyth 	else
131974a4d8c2SCharles.Forsyth 		n = snprint(buf, sizeof(buf), "exited");
132074a4d8c2SCharles.Forsyth 	if(ctl->debugger)
132174a4d8c2SCharles.Forsyth 		telldbg(ctl, buf);
132274a4d8c2SCharles.Forsyth 	qproduce(ctl->q, buf, n);
132374a4d8c2SCharles.Forsyth }
132474a4d8c2SCharles.Forsyth 
132574a4d8c2SCharles.Forsyth static void
dbgaddrun(Prog * p)132674a4d8c2SCharles.Forsyth dbgaddrun(Prog *p)
132774a4d8c2SCharles.Forsyth {
132874a4d8c2SCharles.Forsyth 	Osenv *o;
132974a4d8c2SCharles.Forsyth 
133074a4d8c2SCharles.Forsyth 	p->state = Pdebug;
133174a4d8c2SCharles.Forsyth 	p->addrun = nil;
133274a4d8c2SCharles.Forsyth 	o = p->osenv;
133374a4d8c2SCharles.Forsyth 	if(o->rend != nil)
133474a4d8c2SCharles.Forsyth 		wakeup(o->rend);
133574a4d8c2SCharles.Forsyth 	o->rend = nil;
133674a4d8c2SCharles.Forsyth }
133774a4d8c2SCharles.Forsyth 
133874a4d8c2SCharles.Forsyth static int
bdone(void * vp)133974a4d8c2SCharles.Forsyth bdone(void *vp)
134074a4d8c2SCharles.Forsyth {
134174a4d8c2SCharles.Forsyth 	Prog *p = vp;
134274a4d8c2SCharles.Forsyth 
134374a4d8c2SCharles.Forsyth 	return p->addrun == nil;
134474a4d8c2SCharles.Forsyth }
134574a4d8c2SCharles.Forsyth 
134674a4d8c2SCharles.Forsyth static void
dbgblock(Prog * p)134774a4d8c2SCharles.Forsyth dbgblock(Prog *p)
134874a4d8c2SCharles.Forsyth {
134974a4d8c2SCharles.Forsyth 	Osenv *o;
135074a4d8c2SCharles.Forsyth 	Progctl *ctl;
135174a4d8c2SCharles.Forsyth 
135274a4d8c2SCharles.Forsyth 	o = p->osenv;
135374a4d8c2SCharles.Forsyth 	ctl = o->debug;
135474a4d8c2SCharles.Forsyth 	qproduce(ctl->q, progstate[p->state], strlen(progstate[p->state]));
135574a4d8c2SCharles.Forsyth 	pushrun(p);
135674a4d8c2SCharles.Forsyth 	p->addrun = dbgaddrun;
135774a4d8c2SCharles.Forsyth 	o->rend = &up->sleep;
135874a4d8c2SCharles.Forsyth 
135974a4d8c2SCharles.Forsyth 	/*
136074a4d8c2SCharles.Forsyth 	 * bdone(p) is safe after release because p is being debugged,
136174a4d8c2SCharles.Forsyth 	 * so cannot exit.
136274a4d8c2SCharles.Forsyth 	 */
136374a4d8c2SCharles.Forsyth 	if(waserror()){
136474a4d8c2SCharles.Forsyth 		acquire();
136574a4d8c2SCharles.Forsyth 		nexterror();
136674a4d8c2SCharles.Forsyth 	}
136774a4d8c2SCharles.Forsyth 	release();
136874a4d8c2SCharles.Forsyth 	if(o->rend != nil)
136974a4d8c2SCharles.Forsyth 		sleep(o->rend, bdone, p);
137074a4d8c2SCharles.Forsyth 	poperror();
137174a4d8c2SCharles.Forsyth 	acquire();
137274a4d8c2SCharles.Forsyth 	if(p->kill != nil)
137374a4d8c2SCharles.Forsyth 		error(p->kill);
137474a4d8c2SCharles.Forsyth 	ctl = o->debug;
137574a4d8c2SCharles.Forsyth 	if(ctl != nil)
137674a4d8c2SCharles.Forsyth 		qproduce(ctl->q, "run", 3);
137774a4d8c2SCharles.Forsyth }
137874a4d8c2SCharles.Forsyth 
137974a4d8c2SCharles.Forsyth void
dbgxec(Prog * p)138074a4d8c2SCharles.Forsyth dbgxec(Prog *p)
138174a4d8c2SCharles.Forsyth {
138274a4d8c2SCharles.Forsyth 	Bpt *b;
138374a4d8c2SCharles.Forsyth 	Prog *kid;
138474a4d8c2SCharles.Forsyth 	Osenv *env;
138574a4d8c2SCharles.Forsyth 	Progctl *ctl;
138674a4d8c2SCharles.Forsyth 	int op, pc, n;
138774a4d8c2SCharles.Forsyth 	char buf[ERRMAX+10];
138874a4d8c2SCharles.Forsyth 	extern void (*dec[])(void);
138974a4d8c2SCharles.Forsyth 
139074a4d8c2SCharles.Forsyth 	env = p->osenv;
139174a4d8c2SCharles.Forsyth 	ctl = env->debug;
139274a4d8c2SCharles.Forsyth 	ctl->ref++;
139374a4d8c2SCharles.Forsyth 	if(waserror()){
139474a4d8c2SCharles.Forsyth 		closedbgctl(ctl, p);
139574a4d8c2SCharles.Forsyth 		nexterror();
139674a4d8c2SCharles.Forsyth 	}
139774a4d8c2SCharles.Forsyth 
139874a4d8c2SCharles.Forsyth 	R = p->R;
139974a4d8c2SCharles.Forsyth 	R.MP = R.M->MP;
140074a4d8c2SCharles.Forsyth 
140174a4d8c2SCharles.Forsyth 	R.IC = p->quanta;
140274a4d8c2SCharles.Forsyth 	if((ulong)R.IC > ctl->step)
140374a4d8c2SCharles.Forsyth 		R.IC = ctl->step;
140474a4d8c2SCharles.Forsyth 	if(ctl->stop)
140574a4d8c2SCharles.Forsyth 		R.IC = 0;
140674a4d8c2SCharles.Forsyth 
140774a4d8c2SCharles.Forsyth 
140874a4d8c2SCharles.Forsyth 	buf[0] = '\0';
140974a4d8c2SCharles.Forsyth 
141074a4d8c2SCharles.Forsyth 	if(R.IC != 0 && R.M->compiled) {
141174a4d8c2SCharles.Forsyth 		comvec();
141274a4d8c2SCharles.Forsyth 		if(p != currun())
141374a4d8c2SCharles.Forsyth 			dbgblock(p);
141474a4d8c2SCharles.Forsyth 		goto save;
141574a4d8c2SCharles.Forsyth 	}
141674a4d8c2SCharles.Forsyth 
141774a4d8c2SCharles.Forsyth 	while(R.IC != 0) {
141874a4d8c2SCharles.Forsyth 		if(0)
141974a4d8c2SCharles.Forsyth 			print("step: %lux: %s %4ld %D\n",
142074a4d8c2SCharles.Forsyth 				(ulong)p, R.M->m->name, R.PC-R.M->prog, R.PC);
142174a4d8c2SCharles.Forsyth 
142274a4d8c2SCharles.Forsyth 		dec[R.PC->add]();
142374a4d8c2SCharles.Forsyth 		op = R.PC->op;
142474a4d8c2SCharles.Forsyth 		R.PC++;
142574a4d8c2SCharles.Forsyth 		optab[op]();
142674a4d8c2SCharles.Forsyth 
142774a4d8c2SCharles.Forsyth 		/*
142874a4d8c2SCharles.Forsyth 		 * check notification about new progs
142974a4d8c2SCharles.Forsyth 		 */
143074a4d8c2SCharles.Forsyth 		if(op == ISPAWN || op == IMSPAWN) {
143174a4d8c2SCharles.Forsyth 			/* pick up the kid from the end of the run queue */
143274a4d8c2SCharles.Forsyth 			kid = delruntail(Pdebug);
143374a4d8c2SCharles.Forsyth 			n = snprint(buf, sizeof buf, "new %d", kid->pid);
143474a4d8c2SCharles.Forsyth 			qproduce(ctl->q, buf, n);
143574a4d8c2SCharles.Forsyth 			buf[0] = '\0';
143674a4d8c2SCharles.Forsyth 		}
143774a4d8c2SCharles.Forsyth 		if(op == ILOAD) {
143874a4d8c2SCharles.Forsyth 			n = snprint(buf, sizeof buf, "load %s", string2c(*(String**)R.s));
143974a4d8c2SCharles.Forsyth 			qproduce(ctl->q, buf, n);
144074a4d8c2SCharles.Forsyth 			buf[0] = '\0';
144174a4d8c2SCharles.Forsyth 		}
144274a4d8c2SCharles.Forsyth 
144374a4d8c2SCharles.Forsyth 		/*
144474a4d8c2SCharles.Forsyth 		 * check for returns at big steps
144574a4d8c2SCharles.Forsyth 		 */
144674a4d8c2SCharles.Forsyth 		if(op == IRET)
144774a4d8c2SCharles.Forsyth 			R.IC = 1;
144874a4d8c2SCharles.Forsyth 
144974a4d8c2SCharles.Forsyth 		/*
145074a4d8c2SCharles.Forsyth 		 * check for blocked progs
145174a4d8c2SCharles.Forsyth 		 */
145274a4d8c2SCharles.Forsyth 		if(R.IC == 1 && p != currun())
145374a4d8c2SCharles.Forsyth 			dbgblock(p);
145474a4d8c2SCharles.Forsyth 		if(ctl->stop)
145574a4d8c2SCharles.Forsyth 			R.IC = 1;
145674a4d8c2SCharles.Forsyth 		R.IC--;
145774a4d8c2SCharles.Forsyth 		if(ctl->bpts == nil)
145874a4d8c2SCharles.Forsyth 			continue;
145974a4d8c2SCharles.Forsyth 		pc = R.PC - R.M->prog;
146074a4d8c2SCharles.Forsyth 		for(b = ctl->bpts; b != nil; b = b->next) {
146174a4d8c2SCharles.Forsyth 			if(pc == b->pc &&
146274a4d8c2SCharles.Forsyth 			  (strcmp(R.M->m->path, b->path) == 0 ||
146374a4d8c2SCharles.Forsyth 			   strcmp(R.M->m->path, b->file) == 0)) {
146474a4d8c2SCharles.Forsyth 				strcpy(buf, "breakpoint");
146574a4d8c2SCharles.Forsyth 				goto save;
146674a4d8c2SCharles.Forsyth 			}
146774a4d8c2SCharles.Forsyth 		}
146874a4d8c2SCharles.Forsyth 	}
146974a4d8c2SCharles.Forsyth 
147074a4d8c2SCharles.Forsyth save:
147174a4d8c2SCharles.Forsyth 	if(ctl->stop)
147274a4d8c2SCharles.Forsyth 		strcpy(buf, "stopped");
147374a4d8c2SCharles.Forsyth 
147474a4d8c2SCharles.Forsyth 	p->R = R;
147574a4d8c2SCharles.Forsyth 
147674a4d8c2SCharles.Forsyth 	if(env->debug == nil) {
147774a4d8c2SCharles.Forsyth 		poperror();
147874a4d8c2SCharles.Forsyth 		return;
147974a4d8c2SCharles.Forsyth 	}
148074a4d8c2SCharles.Forsyth 
148174a4d8c2SCharles.Forsyth 	if(p == currun())
148274a4d8c2SCharles.Forsyth 		delrun(Pdebug);
148374a4d8c2SCharles.Forsyth 
148474a4d8c2SCharles.Forsyth 	telldbg(env->debug, buf);
148574a4d8c2SCharles.Forsyth 	poperror();
148674a4d8c2SCharles.Forsyth 	closedbgctl(env->debug, p);
148774a4d8c2SCharles.Forsyth }
148874a4d8c2SCharles.Forsyth 
148974a4d8c2SCharles.Forsyth Dev progdevtab = {
149074a4d8c2SCharles.Forsyth 	'p',
149174a4d8c2SCharles.Forsyth 	"prog",
149274a4d8c2SCharles.Forsyth 
149374a4d8c2SCharles.Forsyth 	devreset,
149474a4d8c2SCharles.Forsyth 	devinit,
149574a4d8c2SCharles.Forsyth 	devshutdown,
149674a4d8c2SCharles.Forsyth 	progattach,
149774a4d8c2SCharles.Forsyth 	progwalk,
149874a4d8c2SCharles.Forsyth 	progstat,
149974a4d8c2SCharles.Forsyth 	progopen,
150074a4d8c2SCharles.Forsyth 	devcreate,
150174a4d8c2SCharles.Forsyth 	progclose,
150274a4d8c2SCharles.Forsyth 	progread,
150374a4d8c2SCharles.Forsyth 	devbread,
150474a4d8c2SCharles.Forsyth 	progwrite,
150574a4d8c2SCharles.Forsyth 	devbwrite,
150674a4d8c2SCharles.Forsyth 	devremove,
150774a4d8c2SCharles.Forsyth 	progwstat,
150874a4d8c2SCharles.Forsyth };
1509