xref: /inferno-os/appl/lib/debug.b (revision 826972481bd5b858c29ebf34c1939832f5d5d4c9)
137da2899SCharles.Forsythimplement Debug;
237da2899SCharles.Forsyth
337da2899SCharles.Forsythinclude "sys.m";
437da2899SCharles.Forsythsys: Sys;
537da2899SCharles.Forsythsprint, FD: import sys;
637da2899SCharles.Forsyth
737da2899SCharles.Forsythinclude "string.m";
837da2899SCharles.Forsythstr: String;
937da2899SCharles.Forsyth
1037da2899SCharles.Forsythinclude "draw.m";
1137da2899SCharles.Forsyth
1237da2899SCharles.Forsythinclude "debug.m";
1337da2899SCharles.Forsyth
1437da2899SCharles.Forsythinclude "dis.m";
1537da2899SCharles.Forsyth	dism: Dis;
1637da2899SCharles.Forsyth
1737da2899SCharles.ForsythCommand: module
1837da2899SCharles.Forsyth{
1937da2899SCharles.Forsyth	init:	fn(ctxt: ref Draw->Context, argv: list of string);
2037da2899SCharles.Forsyth};
2137da2899SCharles.Forsyth
2237da2899SCharles.ForsythSpin: adt
2337da2899SCharles.Forsyth{
2437da2899SCharles.Forsyth	spin:	int;
2537da2899SCharles.Forsyth	pspin:	int;
2637da2899SCharles.Forsyth};
2737da2899SCharles.Forsyth
2837da2899SCharles.ForsythSrcState: adt
2937da2899SCharles.Forsyth{
3037da2899SCharles.Forsyth	files:	array of string;
3137da2899SCharles.Forsyth	lastf:	int;
3237da2899SCharles.Forsyth	lastl:	int;
3337da2899SCharles.Forsyth	vers:	int;			# version number
3437da2899SCharles.Forsyth					# 11 => more source states
3537da2899SCharles.Forsyth};
3637da2899SCharles.Forsyth
3737da2899SCharles.Forsythtypenames := array[] of {
3837da2899SCharles.Forsyth	Terror => "error",
3937da2899SCharles.Forsyth	Tid => "id",
4037da2899SCharles.Forsyth	Tadt => "adt",
4137da2899SCharles.Forsyth	Tadtpick => "adtpick",
4237da2899SCharles.Forsyth	Tarray => "array",
4337da2899SCharles.Forsyth	Tbig => "big",
4437da2899SCharles.Forsyth	Tbyte => "byte",
4537da2899SCharles.Forsyth	Tchan => "chan",
4637da2899SCharles.Forsyth	Treal => "real",
4737da2899SCharles.Forsyth	Tfn => "fn",
4837da2899SCharles.Forsyth	Targ => "arg",
4937da2899SCharles.Forsyth	Tlocal => "local",
5037da2899SCharles.Forsyth	Tglobal => "global",
5137da2899SCharles.Forsyth	Tint => "int",
5237da2899SCharles.Forsyth	Tlist => "list",
5337da2899SCharles.Forsyth	Tmodule => "module",
5437da2899SCharles.Forsyth	Tnil => "nil",
5537da2899SCharles.Forsyth	Tnone => "none",
5637da2899SCharles.Forsyth	Tref => "ref",
5737da2899SCharles.Forsyth	Tstring => "string",
5837da2899SCharles.Forsyth	Ttuple => "tuple",
5937da2899SCharles.Forsyth	Tend => "end",
6037da2899SCharles.Forsyth	Targs => "args",
6137da2899SCharles.Forsyth	Tslice => "slice",
6237da2899SCharles.Forsyth	Tpoly => "poly",
6337da2899SCharles.Forsyth};
6437da2899SCharles.Forsyth
6537da2899SCharles.Forsythtnone:		ref Type;
6637da2899SCharles.Forsythtnil:		ref Type;
6737da2899SCharles.Forsythtint:		ref Type;
6837da2899SCharles.Forsythtbyte:		ref Type;
6937da2899SCharles.Forsythtbig:		ref Type;
7037da2899SCharles.Forsythtreal:		ref Type;
7137da2899SCharles.Forsythtstring:	ref Type;
7237da2899SCharles.Forsythtpoly:	ref Type;
7337da2899SCharles.Forsyth
7437da2899SCharles.ForsythIBY2WD:		con 4;
7537da2899SCharles.ForsythIBY2LG:		con 8;
7637da2899SCharles.ForsythH:		con int 16rffffffff;
7737da2899SCharles.Forsyth
7837da2899SCharles.ForsythModHash:	con 32;
7937da2899SCharles.ForsythSymHash:	con 32;
8037da2899SCharles.Forsythmods:=		array[ModHash] of list of ref Module;
8137da2899SCharles.Forsythsyms:=		array[SymHash] of list of ref Sym;
8237da2899SCharles.Forsyth
8337da2899SCharles.Forsythsblpath :=	array[] of
8437da2899SCharles.Forsyth{
8537da2899SCharles.Forsyth	("/dis/",	"/appl/cmd/"),
8637da2899SCharles.Forsyth	("/dis/",	"/appl/"),
8737da2899SCharles.Forsyth};
8837da2899SCharles.Forsyth
8937da2899SCharles.Forsythinit(): int
9037da2899SCharles.Forsyth{
9137da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
9237da2899SCharles.Forsyth	str = load String String->PATH;
9337da2899SCharles.Forsyth	if(sys == nil || str == nil)
9437da2899SCharles.Forsyth		return 0;
9537da2899SCharles.Forsyth	tnone = ref Type(nil, Tnone, 0, "", nil, nil, nil);
9637da2899SCharles.Forsyth	tnil = ref Type(nil, Tnil, IBY2WD, "nil", nil, nil, nil);
9737da2899SCharles.Forsyth	tint = ref Type(nil, Tint, IBY2WD, "int", nil, nil, nil);
9837da2899SCharles.Forsyth	tbyte = ref Type(nil, Tbyte, 1, "byte", nil, nil, nil);
9937da2899SCharles.Forsyth	tbig = ref Type(nil, Tbig, IBY2LG, "big", nil, nil, nil);
10037da2899SCharles.Forsyth	treal = ref Type(nil, Treal, IBY2LG, "real", nil, nil, nil);
10137da2899SCharles.Forsyth	tstring = ref Type(nil, Tstring, IBY2WD, "string", nil, nil, nil);
10237da2899SCharles.Forsyth	tpoly = ref Type(nil, Tpoly, IBY2WD, "polymorphic", nil, nil, nil);
10337da2899SCharles.Forsyth	return 1;
10437da2899SCharles.Forsyth}
10537da2899SCharles.Forsyth
10637da2899SCharles.Forsythprog(pid: int): (ref Prog, string)
10737da2899SCharles.Forsyth{
10837da2899SCharles.Forsyth	spid := string pid;
10937da2899SCharles.Forsyth	h := sys->open("/prog/"+spid+"/heap", sys->ORDWR);
11037da2899SCharles.Forsyth	if(h == nil)
11137da2899SCharles.Forsyth		return (nil, sprint("can't open heap file: %r"));
11237da2899SCharles.Forsyth	c := sys->open("/prog/"+spid+"/ctl", sys->OWRITE);
11337da2899SCharles.Forsyth	if(c == nil)
11437da2899SCharles.Forsyth		return (nil, sprint("can't open ctl file: %r"));
11537da2899SCharles.Forsyth	d := sys->open("/prog/"+spid+"/dbgctl", sys->ORDWR);
11637da2899SCharles.Forsyth	if(d == nil)
11737da2899SCharles.Forsyth		return (nil, sprint("can't open debug ctl file: %r"));
11837da2899SCharles.Forsyth	s := sys->open("/prog/"+spid+"/stack", sys->OREAD);
11937da2899SCharles.Forsyth	if(s == nil)
12037da2899SCharles.Forsyth		return (nil, sprint("can't open stack file: %r"));
12137da2899SCharles.Forsyth	return (ref Prog(pid, h, c, d, s), "");
12237da2899SCharles.Forsyth}
12337da2899SCharles.Forsyth
12437da2899SCharles.Forsythstartprog(dis, dir: string, ctxt: ref Draw->Context, argv: list of string): (ref Prog, string)
12537da2899SCharles.Forsyth{
12637da2899SCharles.Forsyth	c := load Command dis;
12737da2899SCharles.Forsyth	if(c == nil)
12837da2899SCharles.Forsyth		return (nil, "module not loaded");
12937da2899SCharles.Forsyth
13037da2899SCharles.Forsyth	ack := chan of int;
13137da2899SCharles.Forsyth	spin := ref Spin(1, 1);
13237da2899SCharles.Forsyth	end := chan of int;
13337da2899SCharles.Forsyth	spawn execer(ack, dir, c, ctxt, argv, spin, end);
13437da2899SCharles.Forsyth	kid := <-ack;
13537da2899SCharles.Forsyth
13637da2899SCharles.Forsyth	fd := sys->open("/prog/"+string kid+"/dbgctl", sys->ORDWR);
13737da2899SCharles.Forsyth	if(fd == nil){
13837da2899SCharles.Forsyth		spin.spin = -1;
13937da2899SCharles.Forsyth		<- end;
14037da2899SCharles.Forsyth		return (nil, sprint("can't open debug ctl file: %r"));
14137da2899SCharles.Forsyth	}
14237da2899SCharles.Forsyth	done := chan of string;
14337da2899SCharles.Forsyth	spawn stepper(done, fd, spin);
14437da2899SCharles.Forsyth
14537da2899SCharles.Forsythwait:	for(;;){
14637da2899SCharles.Forsyth		alt{
14737da2899SCharles.Forsyth		<-ack =>
14837da2899SCharles.Forsyth			sys->sleep(0);
14937da2899SCharles.Forsyth		err := <-done =>
15037da2899SCharles.Forsyth			if(err != ""){
15137da2899SCharles.Forsyth				<- end;
15237da2899SCharles.Forsyth				return(nil, err);
15337da2899SCharles.Forsyth			}
15437da2899SCharles.Forsyth			break wait;
15537da2899SCharles.Forsyth		}
15637da2899SCharles.Forsyth	}
15737da2899SCharles.Forsyth
15837da2899SCharles.Forsyth	b := array[20] of byte;
15937da2899SCharles.Forsyth	n := sys->read(fd, b, len b);
16037da2899SCharles.Forsyth	if(n <= 0){
16137da2899SCharles.Forsyth		<- end;
16237da2899SCharles.Forsyth		return(nil, sprint("%r"));
16337da2899SCharles.Forsyth	}
16437da2899SCharles.Forsyth	msg := string b[:n];
16537da2899SCharles.Forsyth	if(!str->prefix("new ", msg)){
16637da2899SCharles.Forsyth		<- end;
16737da2899SCharles.Forsyth		return (nil, msg);
16837da2899SCharles.Forsyth	}
16937da2899SCharles.Forsyth
17037da2899SCharles.Forsyth	kid = int msg[len "new ":];
17137da2899SCharles.Forsyth
17237da2899SCharles.Forsyth	# clean up the execer slave
17337da2899SCharles.Forsyth	b = array of byte "start";
17437da2899SCharles.Forsyth	sys->write(fd, b, len b);
17537da2899SCharles.Forsyth
17637da2899SCharles.Forsyth	<- end;
17737da2899SCharles.Forsyth	return prog(kid);
17837da2899SCharles.Forsyth}
17937da2899SCharles.Forsyth
18037da2899SCharles.Forsythstepper(done: chan of string, ctl: ref FD, spin: ref Spin)
18137da2899SCharles.Forsyth{
18237da2899SCharles.Forsyth	b := array of byte "step1";
18337da2899SCharles.Forsyth	while(spin.pspin){
18437da2899SCharles.Forsyth		if(sys->write(ctl, b, len b) != len b)
18537da2899SCharles.Forsyth			done <-= sprint("can't start new thread: %r");
18637da2899SCharles.Forsyth		spin.spin = 0;
18737da2899SCharles.Forsyth	}
18837da2899SCharles.Forsyth	done <-= "";
18937da2899SCharles.Forsyth}
19037da2899SCharles.Forsyth
19137da2899SCharles.Forsythexecer(ack: chan of int, dir: string, c: Command, ctxt: ref Draw->Context, args: list of string, spin: ref Spin, end: chan of int)
19237da2899SCharles.Forsyth{
19337da2899SCharles.Forsyth	pid := sys->pctl(Sys->NEWPGRP|Sys->FORKNS|Sys->NEWFD, 0::1::2::nil);
19437da2899SCharles.Forsyth	sys->chdir(dir);
19537da2899SCharles.Forsyth	while(spin.spin == 1)
19637da2899SCharles.Forsyth		ack <-= pid;
19737da2899SCharles.Forsyth	if(spin.spin == -1){
19837da2899SCharles.Forsyth		end <-= 0;
19937da2899SCharles.Forsyth		exit;
20037da2899SCharles.Forsyth	}
20137da2899SCharles.Forsyth	spawn c->init(ctxt, args);
20237da2899SCharles.Forsyth	spin.pspin = 0;
20337da2899SCharles.Forsyth	end <-= 0;
20437da2899SCharles.Forsyth	exit;
20537da2899SCharles.Forsyth}
20637da2899SCharles.Forsyth
20737da2899SCharles.Forsyth# format of each line is
20837da2899SCharles.Forsyth# fp pc mp prog compiled path
20937da2899SCharles.Forsyth# fp, pc, mp, and prog are %.8lux
21037da2899SCharles.Forsyth# compile is  or 1
21137da2899SCharles.Forsyth# path is a string
21237da2899SCharles.ForsythProg.stack(p: self ref Prog): (array of ref Exp, string)
21337da2899SCharles.Forsyth{
21437da2899SCharles.Forsyth	buf := array[8192] of byte;
21537da2899SCharles.Forsyth	sys->seek(p.stk, big 0, 0);
21637da2899SCharles.Forsyth	n := sys->read(p.stk, buf, len buf - 1);
21737da2899SCharles.Forsyth	if(n < 0)
21837da2899SCharles.Forsyth		return (nil, sprint("can't read stack file: %r"));
21937da2899SCharles.Forsyth	buf[n] = byte 0;
22037da2899SCharles.Forsyth
22137da2899SCharles.Forsyth	t := 0;
22237da2899SCharles.Forsyth	nf := 0;
22337da2899SCharles.Forsyth	for(s := 0; s < n; s = t+1){
22437da2899SCharles.Forsyth		t = strchr(buf, s, '\n');
22537da2899SCharles.Forsyth		if(buf[t] != byte '\n' || t-s < 40)
22637da2899SCharles.Forsyth			continue;
22737da2899SCharles.Forsyth		nf++;
22837da2899SCharles.Forsyth	}
22937da2899SCharles.Forsyth
23037da2899SCharles.Forsyth	e := array[nf] of ref Exp;
23137da2899SCharles.Forsyth	nf = 0;
23237da2899SCharles.Forsyth	for(s = 0; s < n; s = t+1){
23337da2899SCharles.Forsyth		t = strchr(buf, s, '\n');
23437da2899SCharles.Forsyth		if(buf[t] != byte '\n' || t-s < 40)
23537da2899SCharles.Forsyth			continue;
23637da2899SCharles.Forsyth		e[nf] = ref Exp("unknown fn",
23737da2899SCharles.Forsyth				hex(buf[s+0:s+8]),
23837da2899SCharles.Forsyth				hex(buf[s+9:s+17]),
23937da2899SCharles.Forsyth				mkmod(hex(buf[s+18:s+26]), hex(buf[s+27:s+35]), buf[36] != byte '0', string buf[s+38:t]),
24037da2899SCharles.Forsyth				p,
24137da2899SCharles.Forsyth				nil);
24237da2899SCharles.Forsyth		nf++;
24337da2899SCharles.Forsyth	}
24437da2899SCharles.Forsyth
24537da2899SCharles.Forsyth	return (e, "");
24637da2899SCharles.Forsyth}
24737da2899SCharles.Forsyth
24837da2899SCharles.ForsythProg.step(p: self ref Prog, how: int): string
24937da2899SCharles.Forsyth{
25037da2899SCharles.Forsyth	(stack, nil) := p.stack();
25137da2899SCharles.Forsyth	if(stack == nil)
25237da2899SCharles.Forsyth		return "can't find initial pc";
25337da2899SCharles.Forsyth	src := stack[0].srcstr();
25437da2899SCharles.Forsyth	stmt := ftostmt(stack[0]);
25537da2899SCharles.Forsyth
25637da2899SCharles.Forsyth	if(stack[0].m.sym == nil)
25737da2899SCharles.Forsyth		how = -1;
25837da2899SCharles.Forsyth
25937da2899SCharles.Forsyth	buf := array of byte("step1");
26037da2899SCharles.Forsyth	if(how == StepOut)
26137da2899SCharles.Forsyth		buf = array of byte("toret");
26237da2899SCharles.Forsyth	while(sys->write(p.dbgctl, buf, len buf) == len buf){
26337da2899SCharles.Forsyth		(stk, err) := p.stack();
26437da2899SCharles.Forsyth		if(err != nil)
26537da2899SCharles.Forsyth			return "";
26637da2899SCharles.Forsyth		case how{
26737da2899SCharles.Forsyth		StepExp =>
26837da2899SCharles.Forsyth			if(src != stk[0].srcstr())
26937da2899SCharles.Forsyth				return "";
27037da2899SCharles.Forsyth		StepStmt =>
27137da2899SCharles.Forsyth			if(stmt != ftostmt(stk[0]))
27237da2899SCharles.Forsyth				return "";
27337da2899SCharles.Forsyth			if(stk[0].offset != stack[0].offset)
27437da2899SCharles.Forsyth				return "";
27537da2899SCharles.Forsyth		StepOut =>
27637da2899SCharles.Forsyth			if(returned(stack, stk))
27737da2899SCharles.Forsyth				return "";
27837da2899SCharles.Forsyth		StepOver =>
27937da2899SCharles.Forsyth			if(stk[0].offset == stack[0].offset){
28037da2899SCharles.Forsyth				if(stmt != ftostmt(stk[0]))
28137da2899SCharles.Forsyth					return "";
28237da2899SCharles.Forsyth				buf = array of byte("step1");
28337da2899SCharles.Forsyth				break;
28437da2899SCharles.Forsyth			}
28537da2899SCharles.Forsyth			if(returned(stack, stk))
28637da2899SCharles.Forsyth				return "";
28737da2899SCharles.Forsyth			buf = array of byte("toret");
28837da2899SCharles.Forsyth		* =>
28937da2899SCharles.Forsyth			return "";
29037da2899SCharles.Forsyth		}
29137da2899SCharles.Forsyth	}
29237da2899SCharles.Forsyth	return sprint("%r");
29337da2899SCharles.Forsyth}
29437da2899SCharles.Forsyth
29537da2899SCharles.ForsythProg.stop(p: self ref Prog): string
29637da2899SCharles.Forsyth{
29737da2899SCharles.Forsyth	return dbgctl(p, "stop");
29837da2899SCharles.Forsyth}
29937da2899SCharles.Forsyth
30037da2899SCharles.ForsythProg.unstop(p: self ref Prog): string
30137da2899SCharles.Forsyth{
30237da2899SCharles.Forsyth	return dbgctl(p, "unstop");
30337da2899SCharles.Forsyth}
30437da2899SCharles.Forsyth
30537da2899SCharles.ForsythProg.grab(p: self ref Prog): string
30637da2899SCharles.Forsyth{
30737da2899SCharles.Forsyth	return dbgctl(p, "step0");
30837da2899SCharles.Forsyth}
30937da2899SCharles.Forsyth
31037da2899SCharles.ForsythProg.start(p: self ref Prog): string
31137da2899SCharles.Forsyth{
31237da2899SCharles.Forsyth	return dbgctl(p, "start");
31337da2899SCharles.Forsyth}
31437da2899SCharles.Forsyth
31537da2899SCharles.ForsythProg.cont(p: self ref Prog): string
31637da2899SCharles.Forsyth{
31737da2899SCharles.Forsyth	return dbgctl(p, "cont");
31837da2899SCharles.Forsyth}
31937da2899SCharles.Forsyth
32037da2899SCharles.Forsythdbgctl(p: ref Prog, msg: string): string
32137da2899SCharles.Forsyth{
32237da2899SCharles.Forsyth	b := array of byte msg;
32337da2899SCharles.Forsyth	while(sys->write(p.dbgctl, b, len b) != len b)
32437da2899SCharles.Forsyth		return sprint("%r");
32537da2899SCharles.Forsyth	return "";
32637da2899SCharles.Forsyth}
32737da2899SCharles.Forsyth
32837da2899SCharles.Forsythreturned(old, new: array of ref Exp): int
32937da2899SCharles.Forsyth{
33037da2899SCharles.Forsyth	n := len old;
33137da2899SCharles.Forsyth	if(n > len new)
33237da2899SCharles.Forsyth		return 1;
33337da2899SCharles.Forsyth	return 0;
33437da2899SCharles.Forsyth}
33537da2899SCharles.Forsyth
33637da2899SCharles.ForsythProg.setbpt(p: self ref Prog, dis: string, pc:int): string
33737da2899SCharles.Forsyth{
33837da2899SCharles.Forsyth	b := array of byte("bpt set "+dis+" "+string pc);
33937da2899SCharles.Forsyth	if(sys->write(p.dbgctl, b, len b) != len b)
34037da2899SCharles.Forsyth		return sprint("can't set breakpoint: %r");
34137da2899SCharles.Forsyth	return "";
34237da2899SCharles.Forsyth}
34337da2899SCharles.Forsyth
34437da2899SCharles.ForsythProg.delbpt(p: self ref Prog, dis: string, pc:int): string
34537da2899SCharles.Forsyth{
34637da2899SCharles.Forsyth	b := array of byte("bpt del "+dis+" "+string pc);
34737da2899SCharles.Forsyth	if(sys->write(p.dbgctl, b, len b) != len b)
34837da2899SCharles.Forsyth		return sprint("can't del breakpoint: %r");
34937da2899SCharles.Forsyth	return "";
35037da2899SCharles.Forsyth}
35137da2899SCharles.Forsyth
35237da2899SCharles.ForsythProg.kill(p: self ref Prog): string
35337da2899SCharles.Forsyth{
35437da2899SCharles.Forsyth	b := array of byte "kill";
35537da2899SCharles.Forsyth	if(sys->write(p.ctl, b, len b) != len b)
35637da2899SCharles.Forsyth		return sprint("can't kill process: %r");
35737da2899SCharles.Forsyth	return "";
35837da2899SCharles.Forsyth}
35937da2899SCharles.Forsyth
36037da2899SCharles.ForsythProg.event(p: self ref Prog): string
36137da2899SCharles.Forsyth{
36237da2899SCharles.Forsyth	b := array[100] of byte;
36337da2899SCharles.Forsyth	n := sys->read(p.dbgctl, b, len b);
36437da2899SCharles.Forsyth	if(n < 0)
36537da2899SCharles.Forsyth		return sprint("error: %r");
36637da2899SCharles.Forsyth	return string b[:n];
36737da2899SCharles.Forsyth}
36837da2899SCharles.Forsyth
36937da2899SCharles.Forsythftostmt(e: ref Exp): int
37037da2899SCharles.Forsyth{
37137da2899SCharles.Forsyth	m := e.m;
37237da2899SCharles.Forsyth	if(!m.comp && m.sym != nil && e.pc < len m.sym.srcstmt)
37337da2899SCharles.Forsyth		return m.sym.srcstmt[e.pc];
37437da2899SCharles.Forsyth	return -1;
37537da2899SCharles.Forsyth}
37637da2899SCharles.Forsyth
37737da2899SCharles.ForsythExp.srcstr(e: self ref Exp): string
37837da2899SCharles.Forsyth{
37937da2899SCharles.Forsyth	m := e.m;
38037da2899SCharles.Forsyth	if(!m.comp && m.sym != nil && e.pc < len m.sym.src){
38137da2899SCharles.Forsyth		src := m.sym.src[e.pc];
38237da2899SCharles.Forsyth		ss := src.start.file+":"+string src.start.line+"."+string src.start.pos+", ";
38337da2899SCharles.Forsyth		if(src.stop.file != src.start.file)
38437da2899SCharles.Forsyth			ss += src.stop.file+":"+string src.stop.line+".";
38537da2899SCharles.Forsyth		else if(src.stop.line != src.start.line)
38637da2899SCharles.Forsyth			ss += string src.stop.line+".";
38737da2899SCharles.Forsyth		return ss+string src.stop.pos;
38837da2899SCharles.Forsyth	}
38937da2899SCharles.Forsyth	return sprint("Module %s PC %d", e.m.path, e.pc);
39037da2899SCharles.Forsyth}
39137da2899SCharles.Forsyth
39237da2899SCharles.ForsythExp.findsym(e: self ref Exp): string
39337da2899SCharles.Forsyth{
39437da2899SCharles.Forsyth	m := e.m;
39537da2899SCharles.Forsyth	if(m.comp)
39637da2899SCharles.Forsyth		return "compiled module";
39737da2899SCharles.Forsyth	if(m.sym != nil){
39837da2899SCharles.Forsyth		n := e.pc;
39937da2899SCharles.Forsyth		fns := m.sym.fns;
40037da2899SCharles.Forsyth		for(i := 0; i < len fns; i++){
40137da2899SCharles.Forsyth			if(n >= fns[i].offset && n < fns[i].stoppc){
40237da2899SCharles.Forsyth				e.name = fns[i].name;
40337da2899SCharles.Forsyth				e.id = fns[i];
40437da2899SCharles.Forsyth				return "";
40537da2899SCharles.Forsyth			}
40637da2899SCharles.Forsyth		}
40737da2899SCharles.Forsyth		return "pc out of bounds";
40837da2899SCharles.Forsyth	}
40937da2899SCharles.Forsyth	return "no symbol file";
41037da2899SCharles.Forsyth}
41137da2899SCharles.Forsyth
41237da2899SCharles.ForsythExp.src(e: self ref Exp): ref Src
41337da2899SCharles.Forsyth{
41437da2899SCharles.Forsyth	m := e.m;
41537da2899SCharles.Forsyth	if(e.id == nil || m.sym == nil)
41637da2899SCharles.Forsyth		return nil;
41737da2899SCharles.Forsyth	src := e.id.src;
41837da2899SCharles.Forsyth	if(src != nil)
41937da2899SCharles.Forsyth		return src;
42037da2899SCharles.Forsyth	if(e.id.t.kind == Tfn && !m.comp && e.pc < len m.sym.src && e.pc >= 0)
42137da2899SCharles.Forsyth		return m.sym.src[e.pc];
42237da2899SCharles.Forsyth	return nil;
42337da2899SCharles.Forsyth}
42437da2899SCharles.Forsyth
42537da2899SCharles.ForsythType.getkind(t: self ref Type, sym: ref Sym): int
42637da2899SCharles.Forsyth{
42737da2899SCharles.Forsyth	if(t == nil)
42837da2899SCharles.Forsyth		return -1;
42937da2899SCharles.Forsyth	if(t.kind == Tid)
43037da2899SCharles.Forsyth		return sym.adts[int t.name].getkind(sym);
43137da2899SCharles.Forsyth	return t.kind;
43237da2899SCharles.Forsyth}
43337da2899SCharles.Forsyth
43437da2899SCharles.ForsythType.text(t: self ref Type, sym: ref Sym): string
43537da2899SCharles.Forsyth{
43637da2899SCharles.Forsyth	if (t == nil)
43737da2899SCharles.Forsyth		return "no type";
43837da2899SCharles.Forsyth	s := typenames[t.kind];
43937da2899SCharles.Forsyth	case t.kind {
44037da2899SCharles.Forsyth	Tadt or
44137da2899SCharles.Forsyth	Tadtpick or
44237da2899SCharles.Forsyth	Tmodule =>
44337da2899SCharles.Forsyth		s = t.name;
44437da2899SCharles.Forsyth	Tid =>
44537da2899SCharles.Forsyth		return sym.adts[int t.name].text(sym);
44637da2899SCharles.Forsyth	Tarray or
44737da2899SCharles.Forsyth	Tlist or
44837da2899SCharles.Forsyth	Tchan or
44937da2899SCharles.Forsyth	Tslice =>
45037da2899SCharles.Forsyth		s += " of " + t.Of.text(sym);
45137da2899SCharles.Forsyth	Tref =>
45237da2899SCharles.Forsyth		s += " " + t.Of.text(sym);
45337da2899SCharles.Forsyth	Tfn =>
45437da2899SCharles.Forsyth		s += "(";
45537da2899SCharles.Forsyth		for(i := 0; i < len t.ids; i++)
45637da2899SCharles.Forsyth			s += t.ids[i].name + ": " + t.ids[i].t.text(sym);
45737da2899SCharles.Forsyth		s += "): " + t.Of.text(sym);
45837da2899SCharles.Forsyth	Ttuple or
45937da2899SCharles.Forsyth	Tlocal or
46037da2899SCharles.Forsyth	Tglobal or
46137da2899SCharles.Forsyth	Targ =>
46237da2899SCharles.Forsyth		if(t.kind == Ttuple)
46337da2899SCharles.Forsyth			s = "";
46437da2899SCharles.Forsyth		s += "(";
46537da2899SCharles.Forsyth		for (i := 0; i < len t.ids; i++) {
46637da2899SCharles.Forsyth			s += t.ids[i].t.text(sym);
46737da2899SCharles.Forsyth			if (i < len t.ids - 1)
46837da2899SCharles.Forsyth				s += ", ";
46937da2899SCharles.Forsyth		}
47037da2899SCharles.Forsyth		s += ")";
47137da2899SCharles.Forsyth	}
47237da2899SCharles.Forsyth	return s;
47337da2899SCharles.Forsyth}
47437da2899SCharles.Forsyth
47537da2899SCharles.ForsythExp.typename(e: self ref Exp): string
47637da2899SCharles.Forsyth{
47737da2899SCharles.Forsyth	if (e.id == nil)
47837da2899SCharles.Forsyth		return "no info";
47937da2899SCharles.Forsyth	return e.id.t.text(e.m.sym);
48037da2899SCharles.Forsyth}
48137da2899SCharles.Forsyth
48237da2899SCharles.ForsythExp.kind(e: self ref Exp): int
48337da2899SCharles.Forsyth{
48437da2899SCharles.Forsyth	if(e.id == nil)
48537da2899SCharles.Forsyth		return -1;
48637da2899SCharles.Forsyth	return e.id.t.getkind(e.m.sym);
48737da2899SCharles.Forsyth}
48837da2899SCharles.Forsyth
48937da2899SCharles.ForsythEXPLISTMAX : con	32;	# what's a good value for this ?
49037da2899SCharles.Forsyth
49137da2899SCharles.ForsythExp.expand(e: self ref Exp): array of ref Exp
49237da2899SCharles.Forsyth{
49337da2899SCharles.Forsyth	if(e.id == nil)
49437da2899SCharles.Forsyth		return nil;
49537da2899SCharles.Forsyth
49637da2899SCharles.Forsyth	t := e.id.t;
49737da2899SCharles.Forsyth	if(t.kind == Tid)
49837da2899SCharles.Forsyth		t = e.m.sym.adts[int t.name];
49937da2899SCharles.Forsyth
50037da2899SCharles.Forsyth	off := e.offset;
50137da2899SCharles.Forsyth	ids := t.ids;
50237da2899SCharles.Forsyth	case t.kind{
50337da2899SCharles.Forsyth	Tadt or Tfn or Targ or Tlocal or Ttuple =>
50437da2899SCharles.Forsyth		break;
50537da2899SCharles.Forsyth	Tadtpick =>
50637da2899SCharles.Forsyth		break;
50737da2899SCharles.Forsyth	Tglobal =>
50837da2899SCharles.Forsyth		ids = e.m.sym.vars;
50937da2899SCharles.Forsyth		off = e.m.data;
51037da2899SCharles.Forsyth	Tmodule =>
51137da2899SCharles.Forsyth		(s, err) := pdata(e.p, off, "M");
51237da2899SCharles.Forsyth		if(s == "nil" || err != "")
51337da2899SCharles.Forsyth			return nil;
51437da2899SCharles.Forsyth		off = hex(array of byte s);
51537da2899SCharles.Forsyth	Tref =>
51637da2899SCharles.Forsyth		(s, err) := pdata(e.p, off, "P");
51737da2899SCharles.Forsyth		if(s == "nil" || err != "")
51837da2899SCharles.Forsyth			return nil;
51937da2899SCharles.Forsyth		off = hex(array of byte s);
52037da2899SCharles.Forsyth		et := t.Of;
52137da2899SCharles.Forsyth		if(et.kind == Tid)
52237da2899SCharles.Forsyth			et = e.m.sym.adts[int et.name];
52337da2899SCharles.Forsyth		ids = et.ids;
52437da2899SCharles.Forsyth		if(et.kind == Tadtpick){
52537da2899SCharles.Forsyth			(s, err) = pdata(e.p, off, "W");
52637da2899SCharles.Forsyth			tg := int s;
52737da2899SCharles.Forsyth			if(tg < 0 || tg > len et.tags || err != "" )
52837da2899SCharles.Forsyth				return nil;
52937da2899SCharles.Forsyth			k := array[1 + len ids + len et.tags[tg].ids] of ref Exp;
53037da2899SCharles.Forsyth			k[0] = ref Exp(et.tags[tg].name, off+0, e.pc, e.m, e.p, ref Id(et.src, et.tags[tg].name, 0, 0, tint));
53137da2899SCharles.Forsyth			x := 1;
53237da2899SCharles.Forsyth			for(i := 0; i < len ids; i++){
53337da2899SCharles.Forsyth				id := ids[i];
53437da2899SCharles.Forsyth				k[i+x] = ref Exp(id.name, off+id.offset, e.pc, e.m, e.p, id);
53537da2899SCharles.Forsyth			}
53637da2899SCharles.Forsyth			x += len ids;
53737da2899SCharles.Forsyth			ids = et.tags[tg].ids;
53837da2899SCharles.Forsyth			for(i = 0; i < len ids; i++){
53937da2899SCharles.Forsyth				id := ids[i];
54037da2899SCharles.Forsyth				k[i+x] = ref Exp(id.name, off+id.offset, e.pc, e.m, e.p, id);
54137da2899SCharles.Forsyth			}
54237da2899SCharles.Forsyth			return k;
54337da2899SCharles.Forsyth		}
54437da2899SCharles.Forsyth	Tlist =>
54537da2899SCharles.Forsyth		(s, err) := pdata(e.p, off, "L");
54637da2899SCharles.Forsyth		if(err != "")
54737da2899SCharles.Forsyth			return nil;
54837da2899SCharles.Forsyth		(tloff, hdoff) := str->splitl(s, ".");
54937da2899SCharles.Forsyth		hdoff = hdoff[1:];
55037da2899SCharles.Forsyth		k := array[2] of ref Exp;
55137da2899SCharles.Forsyth		k[0] = ref Exp("hd", hex(array of byte hdoff), e.pc, e.m, e.p, ref Id(nil, "hd", H, H, t.Of));
55237da2899SCharles.Forsyth		k[1] = ref Exp("tl", hex(array of byte tloff), e.pc, e.m, e.p, ref Id(nil, "tl", H, H, t));
55337da2899SCharles.Forsyth		return k;
55437da2899SCharles.Forsyth	Tarray =>
5559b29ac7eSCharles.Forsyth		(s, nil) := pdata(e.p, e.offset, "A");
55637da2899SCharles.Forsyth		if(s == "nil")
55737da2899SCharles.Forsyth			return nil;
55837da2899SCharles.Forsyth		(sn, sa) := str->splitl(s, ".");
55937da2899SCharles.Forsyth		n := int sn;
56037da2899SCharles.Forsyth		if(sa == "" || n <= 0)
56137da2899SCharles.Forsyth			return nil;
56237da2899SCharles.Forsyth		(off, nil) = str->toint(sa[1:], 16);
56337da2899SCharles.Forsyth		et := t.Of;
56437da2899SCharles.Forsyth		if(et.kind == Tid)
56537da2899SCharles.Forsyth			et = e.m.sym.adts[int et.name];
56637da2899SCharles.Forsyth		esize := et.size;
56737da2899SCharles.Forsyth		if (n <= EXPLISTMAX || EXPLISTMAX == 0) {
56837da2899SCharles.Forsyth			k := array[n] of ref Exp;
56937da2899SCharles.Forsyth			for(i := 0; i < n; i++){
57037da2899SCharles.Forsyth				name := string i;
57137da2899SCharles.Forsyth				k[i] = ref Exp(name, off+i*esize, e.pc, e.m, e.p, ref Id(nil, name, H, H, et));
57237da2899SCharles.Forsyth			}
57337da2899SCharles.Forsyth			return k;
57437da2899SCharles.Forsyth		}
57537da2899SCharles.Forsyth		else {
57637da2899SCharles.Forsyth			# slice it
57737da2899SCharles.Forsyth			(p, q, r) := partition(n, EXPLISTMAX);
57837da2899SCharles.Forsyth			lb := 0;
57937da2899SCharles.Forsyth			k := array[p] of ref Exp;
58037da2899SCharles.Forsyth			st := ref Type(et.src, Tslice, 0, nil, et, nil, nil);
58137da2899SCharles.Forsyth			for (i := 0; i < p; i++){
58237da2899SCharles.Forsyth				ub := lb+q-1;
58337da2899SCharles.Forsyth				if (--r >= 0)
58437da2899SCharles.Forsyth					ub++;
58537da2899SCharles.Forsyth				name := string lb + ".." + string ub;
58637da2899SCharles.Forsyth				k[i] = ref Exp(name, off+lb*esize, e.pc, e.m, e.p, ref Id(nil, name, H, H, st));
58737da2899SCharles.Forsyth				lb = ub+1;
58837da2899SCharles.Forsyth			}
58937da2899SCharles.Forsyth			return k;
59037da2899SCharles.Forsyth		}
59137da2899SCharles.Forsyth	Tslice =>
59237da2899SCharles.Forsyth		(lb, ub) := bounds(e.name);
59337da2899SCharles.Forsyth		if (lb > ub)
59437da2899SCharles.Forsyth			return nil;
59537da2899SCharles.Forsyth		n := ub-lb+1;
59637da2899SCharles.Forsyth		et := t.Of;
59737da2899SCharles.Forsyth		if(et.kind == Tid)
59837da2899SCharles.Forsyth			et = e.m.sym.adts[int et.name];
59937da2899SCharles.Forsyth		esize := et.size;
60037da2899SCharles.Forsyth		if (n <= EXPLISTMAX || EXPLISTMAX == 0) {
60137da2899SCharles.Forsyth			k := array[n] of ref Exp;
60237da2899SCharles.Forsyth			for(i := 0; i < n; i++){
60337da2899SCharles.Forsyth				name := string (i+lb);
60437da2899SCharles.Forsyth				k[i] = ref Exp(name, off+i*esize, e.pc, e.m, e.p, ref Id(nil, name, H, H, et));
60537da2899SCharles.Forsyth			}
60637da2899SCharles.Forsyth			return k;
60737da2899SCharles.Forsyth		}
60837da2899SCharles.Forsyth		else {
60937da2899SCharles.Forsyth			# slice it again
61037da2899SCharles.Forsyth			(p, q, r) := partition(n, EXPLISTMAX);
61137da2899SCharles.Forsyth			lb0 := lb;
61237da2899SCharles.Forsyth			k := array[p] of ref Exp;
61337da2899SCharles.Forsyth			st := ref Type(et.src, Tslice, 0, nil, et, nil, nil);
61437da2899SCharles.Forsyth			for (i := 0; i < p; i++){
61537da2899SCharles.Forsyth				ub = lb+q-1;
61637da2899SCharles.Forsyth				if (--r >= 0)
61737da2899SCharles.Forsyth					ub++;
61837da2899SCharles.Forsyth				name := string lb + ".." + string ub;
61937da2899SCharles.Forsyth				k[i] = ref Exp(name, off+(lb-lb0)*esize, e.pc, e.m, e.p, ref Id(nil, name, H, H, st));
62037da2899SCharles.Forsyth				lb = ub+1;
62137da2899SCharles.Forsyth			}
62237da2899SCharles.Forsyth			return k;
62337da2899SCharles.Forsyth		}
62437da2899SCharles.Forsyth	Tchan =>
6259b29ac7eSCharles.Forsyth		(s, nil) := pdata(e.p, e.offset, "c");
62637da2899SCharles.Forsyth		if(s == "nil")
62737da2899SCharles.Forsyth			return nil;
62837da2899SCharles.Forsyth		(sn, sa) := str->splitl(s, ".");
62937da2899SCharles.Forsyth		n := int sn;
63037da2899SCharles.Forsyth		if(sa == "" || n <= 0)
63137da2899SCharles.Forsyth			return nil;
63237da2899SCharles.Forsyth		(off, nil) = str->toint(sa[1:], 16);
63337da2899SCharles.Forsyth		(nil, sa) = str->splitl(sa[1:], ".");
63437da2899SCharles.Forsyth		(sn, sa) = str->splitl(sa[1:], ".");
63537da2899SCharles.Forsyth		f := int sn;
63637da2899SCharles.Forsyth		sz := int sa[1:];
63737da2899SCharles.Forsyth		et := t.Of;
63837da2899SCharles.Forsyth		if(et.kind == Tid)
63937da2899SCharles.Forsyth			et = e.m.sym.adts[int et.name];
64037da2899SCharles.Forsyth		esize := et.size;
64137da2899SCharles.Forsyth		k := array[sz] of ref Exp;
64237da2899SCharles.Forsyth		for(i := 0; i < sz; i++){
64337da2899SCharles.Forsyth			name := string i;
64437da2899SCharles.Forsyth			j := (f+i)%n;
64537da2899SCharles.Forsyth			k[i] = ref Exp(name, off+j*esize, e.pc, e.m, e.p, ref Id(nil, name, H, H, et));
64637da2899SCharles.Forsyth		}
64737da2899SCharles.Forsyth		return k;
64837da2899SCharles.Forsyth	* =>
64937da2899SCharles.Forsyth		return nil;
65037da2899SCharles.Forsyth	}
65137da2899SCharles.Forsyth	k := array[len ids] of ref Exp;
65237da2899SCharles.Forsyth	for(i := 0; i < len k; i++){
65337da2899SCharles.Forsyth		id := ids[i];
65437da2899SCharles.Forsyth		k[i] = ref Exp(id.name, off+id.offset, e.pc, e.m, e.p, id);
65537da2899SCharles.Forsyth	}
65637da2899SCharles.Forsyth	return k;
65737da2899SCharles.Forsyth}
65837da2899SCharles.Forsyth
65937da2899SCharles.ForsythExp.val(e: self ref Exp): (string, int)
66037da2899SCharles.Forsyth{
66137da2899SCharles.Forsyth	if(e.id == nil)
66237da2899SCharles.Forsyth		return (e.m.path+" unknown fn", 0);
66337da2899SCharles.Forsyth	t := e.id.t;
66437da2899SCharles.Forsyth	if(t.kind == Tid)
66537da2899SCharles.Forsyth		t = e.m.sym.adts[int t.name];
66637da2899SCharles.Forsyth
66737da2899SCharles.Forsyth	w := 0;
66837da2899SCharles.Forsyth	s := "";
66937da2899SCharles.Forsyth	err := "";
67037da2899SCharles.Forsyth	p := e.p;
67137da2899SCharles.Forsyth	case t.kind{
67237da2899SCharles.Forsyth	Tfn =>
67337da2899SCharles.Forsyth		if(t.ids != nil)
67437da2899SCharles.Forsyth			w = 1;
67537da2899SCharles.Forsyth		src := e.m.sym.src[e.pc];
67637da2899SCharles.Forsyth		ss := src.start.file+":"+string src.start.line+"."+string src.start.pos+", ";
67737da2899SCharles.Forsyth		if(src.stop.file != src.start.file)
67837da2899SCharles.Forsyth			ss += src.stop.file+":"+string src.stop.line+".";
67937da2899SCharles.Forsyth		else if(src.stop.line != src.start.line)
68037da2899SCharles.Forsyth			ss += string src.stop.line+".";
68137da2899SCharles.Forsyth		return (ss+string src.stop.pos, w);
68237da2899SCharles.Forsyth	Targ or Tlocal or Tglobal or Tadtpick or Ttuple =>
68337da2899SCharles.Forsyth		return ("", 1);
68437da2899SCharles.Forsyth	Tadt =>
68537da2899SCharles.Forsyth		return ("#" + string e.offset, 1);
68637da2899SCharles.Forsyth	Tnil =>
68737da2899SCharles.Forsyth		s = "nil";
68837da2899SCharles.Forsyth	Tbyte =>
68937da2899SCharles.Forsyth		(s, err) = pdata(p, e.offset, "B");
69037da2899SCharles.Forsyth	Tint =>
69137da2899SCharles.Forsyth		(s, err) = pdata(p, e.offset, "W");
69237da2899SCharles.Forsyth	Tbig =>
69337da2899SCharles.Forsyth		(s, err) = pdata(p, e.offset, "V");
69437da2899SCharles.Forsyth	Treal =>
69537da2899SCharles.Forsyth		(s, err) = pdata(p, e.offset, "R");
69637da2899SCharles.Forsyth	Tarray =>
69737da2899SCharles.Forsyth		(s, err) = pdata(p, e.offset, "A");
69837da2899SCharles.Forsyth		if(s == "nil")
69937da2899SCharles.Forsyth			break;
70037da2899SCharles.Forsyth		(n, a) := str->splitl(s, ".");
70137da2899SCharles.Forsyth		if(a == "")
70237da2899SCharles.Forsyth			return ("", 0);
70337da2899SCharles.Forsyth		s = "["+n+"] @"+a[1:];
70437da2899SCharles.Forsyth		w = 1;
70537da2899SCharles.Forsyth	Tslice =>
70637da2899SCharles.Forsyth		(lb, ub) := bounds(e.name);
70737da2899SCharles.Forsyth		s = sys->sprint("[:%d] @ %x", ub-lb+1, e.offset);
70837da2899SCharles.Forsyth		w = 1;
70937da2899SCharles.Forsyth	Tstring =>
71037da2899SCharles.Forsyth		n : int;
71137da2899SCharles.Forsyth		(n, s, err) = pstring(p, e.offset);
71237da2899SCharles.Forsyth		if(err != "")
71337da2899SCharles.Forsyth			return ("", 0);
71437da2899SCharles.Forsyth		for(i := 0; i < len s; i++)
71537da2899SCharles.Forsyth			if(s[i] == '\n')
71637da2899SCharles.Forsyth				s[i] = '\u008a';
71737da2899SCharles.Forsyth		s = "["+string n+"] \""+s+"\"";
71837da2899SCharles.Forsyth	Tref or Tlist or Tmodule or Tpoly=>
71937da2899SCharles.Forsyth		(s, err) = pdata(p, e.offset, "P");
72037da2899SCharles.Forsyth		if(s == "nil")
72137da2899SCharles.Forsyth			break;
72237da2899SCharles.Forsyth		s = "@" + s;
72337da2899SCharles.Forsyth		w = 1;
72437da2899SCharles.Forsyth	Tchan =>
72537da2899SCharles.Forsyth		(s, err) = pdata(p, e.offset, "c");
72637da2899SCharles.Forsyth		if(s == "nil")
72737da2899SCharles.Forsyth			break;
72837da2899SCharles.Forsyth		(n, a) := str->splitl(s, ".");
72937da2899SCharles.Forsyth		if(a == "")
73037da2899SCharles.Forsyth			return ("", 0);
73137da2899SCharles.Forsyth		if(n == "0"){
73237da2899SCharles.Forsyth			s = "@" + a[1:];
73337da2899SCharles.Forsyth			w = 0;
73437da2899SCharles.Forsyth		}
73537da2899SCharles.Forsyth		else{
73637da2899SCharles.Forsyth			(a, nil) = str->splitl(a[1:], ".");
73737da2899SCharles.Forsyth			s = "["+n+"] @"+a;
73837da2899SCharles.Forsyth			w = 1;
73937da2899SCharles.Forsyth		}
74037da2899SCharles.Forsyth	}
74137da2899SCharles.Forsyth	if(err != "")
74237da2899SCharles.Forsyth		return ("", 0);
74337da2899SCharles.Forsyth	return (s, w);
74437da2899SCharles.Forsyth}
74537da2899SCharles.Forsyth
74637da2899SCharles.ForsythSym.srctopc(s: self ref Sym, src: ref Src): int
74737da2899SCharles.Forsyth{
74837da2899SCharles.Forsyth	srcs := s.src;
74937da2899SCharles.Forsyth	line := src.start.line;
75037da2899SCharles.Forsyth	pos := src.start.pos;
75137da2899SCharles.Forsyth	(nil, file) := str->splitr(src.start.file, "/");
75237da2899SCharles.Forsyth	backup := -1;
75337da2899SCharles.Forsyth	delta := 80;
75437da2899SCharles.Forsyth	for(i := 0; i < len srcs; i++){
75537da2899SCharles.Forsyth		ss := srcs[i];
75637da2899SCharles.Forsyth		if(ss.start.file != file)
75737da2899SCharles.Forsyth			continue;
75837da2899SCharles.Forsyth		if(ss.start.line <= line && ss.start.pos <= pos
75937da2899SCharles.Forsyth		&& ss.stop.line >= line && ss.stop.pos >= pos)
76037da2899SCharles.Forsyth			return i;
76137da2899SCharles.Forsyth		d := ss.start.line - line;
76237da2899SCharles.Forsyth		if(d >= 0 && d < delta){
76337da2899SCharles.Forsyth			delta = d;
76437da2899SCharles.Forsyth			backup = i;
76537da2899SCharles.Forsyth		}
76637da2899SCharles.Forsyth	}
76737da2899SCharles.Forsyth	return backup;
76837da2899SCharles.Forsyth}
76937da2899SCharles.Forsyth
77037da2899SCharles.ForsythSym.pctosrc(s: self ref Sym, pc: int): ref Src
77137da2899SCharles.Forsyth{
77237da2899SCharles.Forsyth	if(pc < 0 || pc >= len s.src)
77337da2899SCharles.Forsyth		return nil;
77437da2899SCharles.Forsyth	return s.src[pc];
77537da2899SCharles.Forsyth}
77637da2899SCharles.Forsyth
77737da2899SCharles.Forsythsym(sbl: string): (ref Sym, string)
77837da2899SCharles.Forsyth{
77937da2899SCharles.Forsyth	h := 0;
78037da2899SCharles.Forsyth	for(i := 0; i < len sbl; i++)
78137da2899SCharles.Forsyth		h = (h << 1) + sbl[i];
78237da2899SCharles.Forsyth	h &= SymHash - 1;
78337da2899SCharles.Forsyth	for(sl := syms[h]; sl != nil; sl = tl sl){
78437da2899SCharles.Forsyth		s := hd sl;
78537da2899SCharles.Forsyth		if(sbl == s.path)
78637da2899SCharles.Forsyth			return (s, "");
78737da2899SCharles.Forsyth	}
78837da2899SCharles.Forsyth	(sy, err) := loadsyms(sbl);
78937da2899SCharles.Forsyth	if(err != "")
79037da2899SCharles.Forsyth		return (nil, err);
79137da2899SCharles.Forsyth	syms[h] = sy :: syms[h];
79237da2899SCharles.Forsyth	return (sy, "");
79337da2899SCharles.Forsyth}
79437da2899SCharles.Forsyth
79537da2899SCharles.ForsythModule.addsym(m: self ref Module, sym: ref Sym)
79637da2899SCharles.Forsyth{
79737da2899SCharles.Forsyth	m.sym = sym;
79837da2899SCharles.Forsyth}
79937da2899SCharles.Forsyth
80037da2899SCharles.ForsythModule.sbl(m: self ref Module): string
80137da2899SCharles.Forsyth{
80237da2899SCharles.Forsyth	if(m.sym != nil)
80337da2899SCharles.Forsyth		return m.sym.path;
80437da2899SCharles.Forsyth	return "";
80537da2899SCharles.Forsyth}
80637da2899SCharles.Forsyth
80737da2899SCharles.ForsythModule.dis(m: self ref Module): string
80837da2899SCharles.Forsyth{
80937da2899SCharles.Forsyth	return m.path;
81037da2899SCharles.Forsyth}
81137da2899SCharles.Forsyth
81237da2899SCharles.Forsythfindsbl(dis: string): string
81337da2899SCharles.Forsyth{
81437da2899SCharles.Forsyth	n  := len dis;
81537da2899SCharles.Forsyth	if(n <= 4 || dis[n-4: n] != ".dis")
81637da2899SCharles.Forsyth		dis += ".dis";
81737da2899SCharles.Forsyth	if(dism == nil){
81837da2899SCharles.Forsyth		dism = load Dis Dis->PATH;
81937da2899SCharles.Forsyth		if(dism != nil)
82037da2899SCharles.Forsyth			dism->init();
82137da2899SCharles.Forsyth	}
82237da2899SCharles.Forsyth	if(dism != nil && (b := dism->src(dis)) != nil){
82337da2899SCharles.Forsyth		n = len b;
82437da2899SCharles.Forsyth		if(n > 2 && b[n-2: n] == ".b"){
82537da2899SCharles.Forsyth			sbl := b[0: n-2] + ".sbl";
82637da2899SCharles.Forsyth			if(sys->open(sbl, Sys->OREAD) != nil)
82737da2899SCharles.Forsyth				return sbl;
82837da2899SCharles.Forsyth		}
82937da2899SCharles.Forsyth	}
83037da2899SCharles.Forsyth	return nil;
83137da2899SCharles.Forsyth}
83237da2899SCharles.Forsyth
83337da2899SCharles.ForsythModule.stdsym(m: self ref Module)
83437da2899SCharles.Forsyth{
83537da2899SCharles.Forsyth	if(m.sym != nil)
83637da2899SCharles.Forsyth		return;
83737da2899SCharles.Forsyth	if((sbl := findsbl(m.path)) != nil){
83837da2899SCharles.Forsyth		(m.sym, nil) = sym(sbl);
83937da2899SCharles.Forsyth		return;
84037da2899SCharles.Forsyth	}
84137da2899SCharles.Forsyth	sbl = m.path;
84237da2899SCharles.Forsyth	n := len sbl;
84337da2899SCharles.Forsyth	if(n > 4 && sbl[n-4:n] == ".dis")
84437da2899SCharles.Forsyth		sbl = sbl[:n-4]+".sbl";
84537da2899SCharles.Forsyth	else
84637da2899SCharles.Forsyth		sbl = sbl+".sbl";
84737da2899SCharles.Forsyth	path := sbl;
84837da2899SCharles.Forsyth	fd := sys->open(sbl, sys->OREAD);
84937da2899SCharles.Forsyth	for(i := 0; fd == nil && i < len sblpath; i++){
85037da2899SCharles.Forsyth		(dis, src) := sblpath[i];
85137da2899SCharles.Forsyth		nd := len dis;
85237da2899SCharles.Forsyth		if(len sbl > nd && sbl[:nd] == dis){
85337da2899SCharles.Forsyth			path = src + sbl[nd:];
85437da2899SCharles.Forsyth			fd = sys->open(path, sys->OREAD);
85537da2899SCharles.Forsyth		}
85637da2899SCharles.Forsyth	}
85737da2899SCharles.Forsyth	if(fd == nil)
85837da2899SCharles.Forsyth		return;
85937da2899SCharles.Forsyth	(m.sym, nil) = sym(path);
86037da2899SCharles.Forsyth}
86137da2899SCharles.Forsyth
86237da2899SCharles.Forsythmkmod(data, code, comp: int, dis: string): ref Module
86337da2899SCharles.Forsyth{
86437da2899SCharles.Forsyth	h := 0;
86537da2899SCharles.Forsyth	for(i := 0; i < len dis; i++)
86637da2899SCharles.Forsyth		h = (h << 1) + dis[i];
86737da2899SCharles.Forsyth	h &= ModHash - 1;
86837da2899SCharles.Forsyth	sym : ref Sym;
86937da2899SCharles.Forsyth	for(ml := mods[h]; ml != nil; ml = tl ml){
87037da2899SCharles.Forsyth		m := hd ml;
87137da2899SCharles.Forsyth		if(m.path == dis && m.code == code && m.comp == comp){
87237da2899SCharles.Forsyth			sym = m.sym;
87337da2899SCharles.Forsyth			if(m.data == data)
87437da2899SCharles.Forsyth				return m;
87537da2899SCharles.Forsyth		}
87637da2899SCharles.Forsyth	}
87737da2899SCharles.Forsyth	m := ref Module(dis, code, data, comp, sym);
87837da2899SCharles.Forsyth	mods[h] = m :: mods[h];
87937da2899SCharles.Forsyth	return m;
88037da2899SCharles.Forsyth}
88137da2899SCharles.Forsyth
88237da2899SCharles.Forsythpdata(p: ref Prog, a: int, fmt: string): (string, string)
88337da2899SCharles.Forsyth{
88437da2899SCharles.Forsyth	b := array of byte sprint("0x%ux.%s1", a, fmt);
88537da2899SCharles.Forsyth	if(sys->write(p.heap, b, len b) != len b)
88637da2899SCharles.Forsyth		return ("", sprint("can't write heap: %r"));
88737da2899SCharles.Forsyth
88837da2899SCharles.Forsyth	buf := array[64] of byte;
88937da2899SCharles.Forsyth	sys->seek(p.heap, big 0, 0);
89037da2899SCharles.Forsyth	n := sys->read(p.heap, buf, len buf);
89137da2899SCharles.Forsyth	if(n <= 1)
89237da2899SCharles.Forsyth		return ("", sprint("can't read heap: %r"));
89337da2899SCharles.Forsyth	return (string buf[:n-1], "");
89437da2899SCharles.Forsyth}
89537da2899SCharles.Forsyth
89637da2899SCharles.Forsythpstring0(p: ref Prog, a: int, blen: int): (int, string, string)
89737da2899SCharles.Forsyth{
89837da2899SCharles.Forsyth	b := array of byte sprint("0x%ux.C1", a);
89937da2899SCharles.Forsyth	if(sys->write(p.heap, b, len b) != len b)
90037da2899SCharles.Forsyth		return (-1, "", sprint("can't write heap: %r"));
90137da2899SCharles.Forsyth
90237da2899SCharles.Forsyth	buf := array[blen] of byte;
90337da2899SCharles.Forsyth	sys->seek(p.heap, big 0, 0);
90437da2899SCharles.Forsyth	n := sys->read(p.heap, buf, len buf-1);
90537da2899SCharles.Forsyth	if(n <= 1)
90637da2899SCharles.Forsyth		return (-1, "", sprint("can't read heap: %r"));
90737da2899SCharles.Forsyth	buf[n] = byte 0;
90837da2899SCharles.Forsyth	m := strchr(buf, 0, '.');
90937da2899SCharles.Forsyth	if(buf[m++] != byte '.')
91037da2899SCharles.Forsyth		m = 0;
91137da2899SCharles.Forsyth	return (int string buf[0:m], string buf[m:n], "");
91237da2899SCharles.Forsyth}
91337da2899SCharles.Forsyth
91437da2899SCharles.Forsythpstring(p: ref Prog, a: int): (int, string, string)
91537da2899SCharles.Forsyth{
91637da2899SCharles.Forsyth	m, n: int;
91737da2899SCharles.Forsyth	s, err: string;
91837da2899SCharles.Forsyth
91937da2899SCharles.Forsyth	m = 64;
92037da2899SCharles.Forsyth	for(;;){
92137da2899SCharles.Forsyth		(n, s, err) = pstring0(p, a, m);
92237da2899SCharles.Forsyth		if(err != "" || n <= len s)
92337da2899SCharles.Forsyth			break;
924*82697248SCharles.Forsyth		# guard against broken devprog
925*82697248SCharles.Forsyth		if(m >= 3 * n)
926*82697248SCharles.Forsyth			return (-1, nil, "bad string");
92737da2899SCharles.Forsyth		m *= 2;
92837da2899SCharles.Forsyth	}
92937da2899SCharles.Forsyth	return (n, s, err);
93037da2899SCharles.Forsyth}
93137da2899SCharles.Forsyth
93237da2899SCharles.ForsythProg.status(p: self ref Prog): (int, string, string, string)
93337da2899SCharles.Forsyth{
93437da2899SCharles.Forsyth	fd := sys->open(sprint("/prog/%d/status", p.id), sys->OREAD);
93537da2899SCharles.Forsyth	if(fd == nil)
93637da2899SCharles.Forsyth		return (-1, "", sprint("can't open status file: %r"), "");
93737da2899SCharles.Forsyth	buf := array[256] of byte;
93837da2899SCharles.Forsyth	n := sys->read(fd, buf, len buf);
93937da2899SCharles.Forsyth	if(n <= 0)
94037da2899SCharles.Forsyth		return (-1, "", sprint("can't read status file: %r"), "");
94137da2899SCharles.Forsyth	(ni, info) := sys->tokenize(string buf[:n], " \t");
94237da2899SCharles.Forsyth	if(ni != 6 && ni != 7)
94337da2899SCharles.Forsyth		return (-1, "", "can't parse status file", "");
94437da2899SCharles.Forsyth	info = tl info;
94537da2899SCharles.Forsyth	if(ni == 6)
94637da2899SCharles.Forsyth		return (int hd info, hd tl info, hd tl tl info, hd tl tl tl tl info);
94737da2899SCharles.Forsyth	return (int hd info, hd tl info, hd tl tl tl info, hd tl tl tl tl tl info);
94837da2899SCharles.Forsyth}
94937da2899SCharles.Forsyth
95037da2899SCharles.Forsythloadsyms(sbl: string): (ref Sym, string)
95137da2899SCharles.Forsyth{
95237da2899SCharles.Forsyth	fd := sys->open(sbl, sys->OREAD);
95337da2899SCharles.Forsyth	if(fd == nil)
95437da2899SCharles.Forsyth		return (nil, sprint("Can't open symbol file '%s': %r", sbl));
95537da2899SCharles.Forsyth
95637da2899SCharles.Forsyth	(ok, dir) := sys->fstat(fd);
95737da2899SCharles.Forsyth	if(ok < 0)
95837da2899SCharles.Forsyth		return (nil, sprint("Can't read symbol file '%s': %r", sbl));
95937da2899SCharles.Forsyth	n := int dir.length;
96037da2899SCharles.Forsyth	buf := array[n+1] of byte;
96137da2899SCharles.Forsyth	if(sys->read(fd, buf, n) != n)
96237da2899SCharles.Forsyth		return (nil, sprint("Can't read symbol file '%s': %r", sbl));
96337da2899SCharles.Forsyth	fd = nil;
96437da2899SCharles.Forsyth	buf[n] = byte 0;
96537da2899SCharles.Forsyth
96637da2899SCharles.Forsyth	s := ref Sym;
96737da2899SCharles.Forsyth	s.path = sbl;
96837da2899SCharles.Forsyth
96937da2899SCharles.Forsyth	n = strchr(buf, 0, '\n');
97037da2899SCharles.Forsyth	vers := 0;
97137da2899SCharles.Forsyth	if(string buf[:n] == "limbo .sbl 1.")
97237da2899SCharles.Forsyth		vers = 10;
97337da2899SCharles.Forsyth	else if(string buf[:n] == "limbo .sbl 1.1")
97437da2899SCharles.Forsyth		vers = 11;
97537da2899SCharles.Forsyth	else if(string buf[:n] == "limbo .sbl 2.0")
97637da2899SCharles.Forsyth		vers = 20;
97737da2899SCharles.Forsyth	else if(string buf[:n] == "limbo .sbl 2.1")
97837da2899SCharles.Forsyth		vers = 21;
97937da2899SCharles.Forsyth	else
98037da2899SCharles.Forsyth		return (nil, "Symbol file "+sbl+" out of date");
98137da2899SCharles.Forsyth	o := n += 1;
98237da2899SCharles.Forsyth	n = strchr(buf, o, '\n');
98337da2899SCharles.Forsyth	if(buf[n] != byte '\n')
98437da2899SCharles.Forsyth		return (nil, "Corrupted symbol file "+sbl);
98537da2899SCharles.Forsyth	s.name = string buf[o:n++];
98637da2899SCharles.Forsyth	ss := ref SrcState(nil, 0, 0, vers);
98737da2899SCharles.Forsyth	err : string;
98837da2899SCharles.Forsyth	if(n >= 0){
98937da2899SCharles.Forsyth		err = "file";
99037da2899SCharles.Forsyth		n = debugfiles(ss, buf, n);
99137da2899SCharles.Forsyth	}
99237da2899SCharles.Forsyth	if(n >= 0){
99337da2899SCharles.Forsyth		err = "pc";
99437da2899SCharles.Forsyth		n = debugpc(ss, s, buf, n);
99537da2899SCharles.Forsyth	}
99637da2899SCharles.Forsyth	if(n >= 0){
99737da2899SCharles.Forsyth		err = "types";
99837da2899SCharles.Forsyth		n = debugtys(ss, s, buf, n);
99937da2899SCharles.Forsyth	}
100037da2899SCharles.Forsyth	if(n >= 0){
100137da2899SCharles.Forsyth		err = "fn";
100237da2899SCharles.Forsyth		n = debugfns(ss, s, buf, n);
100337da2899SCharles.Forsyth	}
100437da2899SCharles.Forsyth	vs: array of ref Id;
100537da2899SCharles.Forsyth	if(n >= 0){
100637da2899SCharles.Forsyth		err = "global";
100737da2899SCharles.Forsyth		(vs, n) = debugid(ss, buf, n);
100837da2899SCharles.Forsyth	}
100937da2899SCharles.Forsyth	if(n < 0)
101037da2899SCharles.Forsyth		return (nil, "Corrupted "+err+" symbol table in "+sbl);
101137da2899SCharles.Forsyth	s.vars = vs;
101237da2899SCharles.Forsyth	return (s, "");
101337da2899SCharles.Forsyth}
101437da2899SCharles.Forsyth
101537da2899SCharles.Forsyth#
101637da2899SCharles.Forsyth# parse a source location
101737da2899SCharles.Forsyth# format[file:][line.]pos,[file:][line.]pos' '
101837da2899SCharles.Forsyth#
101937da2899SCharles.Forsythdebugsrc(ss: ref SrcState, buf: array of byte, p: int): (ref Src, int)
102037da2899SCharles.Forsyth{
102137da2899SCharles.Forsyth	n: int;
102237da2899SCharles.Forsyth	src: ref Src;
102337da2899SCharles.Forsyth
102437da2899SCharles.Forsyth	(n, p) = strtoi(buf, p);
102537da2899SCharles.Forsyth	if(buf[p] == byte ':'){
102637da2899SCharles.Forsyth		ss.lastf = n;
102737da2899SCharles.Forsyth		(n, p) = strtoi(buf, p + 1);
102837da2899SCharles.Forsyth	}
102937da2899SCharles.Forsyth	if(buf[p] == byte '.'){
103037da2899SCharles.Forsyth		ss.lastl = n;
103137da2899SCharles.Forsyth		(n, p) = strtoi(buf, p + 1);
103237da2899SCharles.Forsyth	}
103337da2899SCharles.Forsyth	if(buf[p++] != byte ',' || ss.lastf >= len ss.files || ss.lastf < 0)
103437da2899SCharles.Forsyth		return (nil, -1);
103537da2899SCharles.Forsyth	src = ref Src;
103637da2899SCharles.Forsyth	src.start.file = ss.files[ss.lastf];
103737da2899SCharles.Forsyth	src.start.line = ss.lastl;
103837da2899SCharles.Forsyth	src.start.pos = n;
103937da2899SCharles.Forsyth
104037da2899SCharles.Forsyth	(n, p) = strtoi(buf, p);
104137da2899SCharles.Forsyth	if(buf[p] == byte ':'){
104237da2899SCharles.Forsyth		ss.lastf = n;
104337da2899SCharles.Forsyth		(n, p) = strtoi(buf, p+1);
104437da2899SCharles.Forsyth	}
104537da2899SCharles.Forsyth	if(buf[p] == byte '.'){
104637da2899SCharles.Forsyth		ss.lastl = n;
104737da2899SCharles.Forsyth		(n, p) = strtoi(buf, p + 1);
104837da2899SCharles.Forsyth	}
104937da2899SCharles.Forsyth	if(buf[p++] != byte ' ' || ss.lastf >= len ss.files || ss.lastf < 0)
105037da2899SCharles.Forsyth		return (nil, -1);
105137da2899SCharles.Forsyth	src.stop.file = ss.files[ss.lastf];
105237da2899SCharles.Forsyth	src.stop.line = ss.lastl;
105337da2899SCharles.Forsyth	src.stop.pos = n;
105437da2899SCharles.Forsyth	return (src, p);
105537da2899SCharles.Forsyth}
105637da2899SCharles.Forsyth
105737da2899SCharles.Forsyth#
105837da2899SCharles.Forsyth# parse the file table
105937da2899SCharles.Forsyth# item format: file: string
106037da2899SCharles.Forsyth#
106137da2899SCharles.Forsythdebugfiles(ss: ref SrcState, buf: array of byte, p: int): int
106237da2899SCharles.Forsyth{
106337da2899SCharles.Forsyth	n, q: int;
106437da2899SCharles.Forsyth
106537da2899SCharles.Forsyth	(n, p) = strtoi(buf, p);
106637da2899SCharles.Forsyth	if(buf[p++] != byte '\n')
106737da2899SCharles.Forsyth		return -1;
106837da2899SCharles.Forsyth	ss.files = array[n] of string;
106937da2899SCharles.Forsyth	for(i := 0; i < n; i++){
107037da2899SCharles.Forsyth		q = strchr(buf, p, '\n');
107137da2899SCharles.Forsyth		ss.files[i] = string buf[p:q];
107237da2899SCharles.Forsyth		p = q + 1;
107337da2899SCharles.Forsyth	}
107437da2899SCharles.Forsyth	return p;
107537da2899SCharles.Forsyth}
107637da2899SCharles.Forsyth
107737da2899SCharles.Forsyth#
107837da2899SCharles.Forsyth# parse the pc to source table
107937da2899SCharles.Forsyth# item format: Source stmt
108037da2899SCharles.Forsyth#
108137da2899SCharles.Forsythdebugpc(ss: ref SrcState, s: ref Sym, buf: array of byte, p: int): int
108237da2899SCharles.Forsyth{
108337da2899SCharles.Forsyth	ns: int;
108437da2899SCharles.Forsyth
108537da2899SCharles.Forsyth	(ns, p) = strtoi(buf, p);
108637da2899SCharles.Forsyth	if(buf[p++] != byte '\n')
108737da2899SCharles.Forsyth		return -1;
108837da2899SCharles.Forsyth	s.src = array[ns] of ref Src;
108937da2899SCharles.Forsyth	s.srcstmt = array[ns] of int;
109037da2899SCharles.Forsyth	for(i := 0; i < ns; i++){
109137da2899SCharles.Forsyth		(s.src[i], p) = debugsrc(ss, buf, p);
109237da2899SCharles.Forsyth		if(p < 0)
109337da2899SCharles.Forsyth			return -1;
109437da2899SCharles.Forsyth		(s.srcstmt[i], p) = strtoi(buf, p);
109537da2899SCharles.Forsyth		if(buf[p++] != byte '\n')
109637da2899SCharles.Forsyth			return -1;
109737da2899SCharles.Forsyth	}
109837da2899SCharles.Forsyth	return p;
109937da2899SCharles.Forsyth}
110037da2899SCharles.Forsyth
110137da2899SCharles.Forsyth#
110237da2899SCharles.Forsyth# parse the type table
110337da2899SCharles.Forsyth# format: linear list of types
110437da2899SCharles.Forsyth#
110537da2899SCharles.Forsythdebugtys(ss: ref SrcState, s: ref Sym, buf: array of byte, p: int): int
110637da2899SCharles.Forsyth{
110737da2899SCharles.Forsyth	na: int;
110837da2899SCharles.Forsyth
110937da2899SCharles.Forsyth	(na, p) = strtoi(buf, p);
111037da2899SCharles.Forsyth	if(buf[p++] != byte '\n')
111137da2899SCharles.Forsyth		return -1;
111237da2899SCharles.Forsyth	s.adts = array[na] of ref Type;
111337da2899SCharles.Forsyth	adts := s.adts;
111437da2899SCharles.Forsyth	for(i := 0; i < na; i++){
111537da2899SCharles.Forsyth		if(ss.vers < 20)
111637da2899SCharles.Forsyth			(adts[i], p) = debugadt(ss, buf, p);
111737da2899SCharles.Forsyth		else
111837da2899SCharles.Forsyth			(adts[i], p) = debugtype(ss, buf, p);
111937da2899SCharles.Forsyth		if(p < 0)
112037da2899SCharles.Forsyth			return -1;
112137da2899SCharles.Forsyth	}
112237da2899SCharles.Forsyth	return p;
112337da2899SCharles.Forsyth}
112437da2899SCharles.Forsyth
112537da2899SCharles.Forsyth#
112637da2899SCharles.Forsyth# parse the function table
112737da2899SCharles.Forsyth# format: pc:name:argids localids rettype
112837da2899SCharles.Forsyth#
112937da2899SCharles.Forsythdebugfns(ss: ref SrcState, s: ref Sym, buf: array of byte, p: int): int
113037da2899SCharles.Forsyth{
113137da2899SCharles.Forsyth	t: ref Type;
113237da2899SCharles.Forsyth	args, locals: array of ref Id;
113337da2899SCharles.Forsyth	nf, pc, q: int;
113437da2899SCharles.Forsyth
113537da2899SCharles.Forsyth	(nf, p) = strtoi(buf, p);
113637da2899SCharles.Forsyth	if(buf[p++] != byte '\n')
113737da2899SCharles.Forsyth		return -1;
113837da2899SCharles.Forsyth	s.fns = array[nf] of ref Id;
113937da2899SCharles.Forsyth	fns := s.fns;
114037da2899SCharles.Forsyth	for(i := 0; i < nf; i++){
114137da2899SCharles.Forsyth		(pc, p) = strtoi(buf, p);
114237da2899SCharles.Forsyth		if(buf[p++] != byte ':')
114337da2899SCharles.Forsyth			return -2;
114437da2899SCharles.Forsyth		q = strchr(buf, p, '\n');
114537da2899SCharles.Forsyth		if(buf[q] != byte '\n')
114637da2899SCharles.Forsyth			return -3;
114737da2899SCharles.Forsyth		name := string buf[p:q];
114837da2899SCharles.Forsyth		(args, p) = debugid(ss, buf, q + 1);
114937da2899SCharles.Forsyth		if(p == -1)
115037da2899SCharles.Forsyth			return -4;
115137da2899SCharles.Forsyth		(locals, p) = debugid(ss, buf, p);
115237da2899SCharles.Forsyth		if(p == -1)
115337da2899SCharles.Forsyth			return -5;
115437da2899SCharles.Forsyth		(t, p) = debugtype(ss, buf, p);
115537da2899SCharles.Forsyth		if(p == -1)
115637da2899SCharles.Forsyth			return -6;
115737da2899SCharles.Forsyth		nk := 1 + (len args != 0) + (len locals != 0);
115837da2899SCharles.Forsyth		kids := array[nk] of ref Id;
115937da2899SCharles.Forsyth		nk = 0;
116037da2899SCharles.Forsyth		if(len locals != 0)
116137da2899SCharles.Forsyth			kids[nk++] = ref Id(nil, "locals", 0, 0, ref Type(nil, Tlocal, 0, nil, nil, locals, nil));
116237da2899SCharles.Forsyth		if(len args != 0)
116337da2899SCharles.Forsyth			kids[nk++] = ref Id(nil, "args", 0, 0, ref Type(nil, Targ, 0, nil, nil, args, nil));
116437da2899SCharles.Forsyth		kids[nk++] = ref Id(nil, "module", 0, 0, ref Type(nil, Tglobal, 0, nil, nil, nil, nil));
116537da2899SCharles.Forsyth		args = nil;
116637da2899SCharles.Forsyth		locals = nil;
116737da2899SCharles.Forsyth		fns[i] = ref Id(nil, name, pc, 0, ref Type(nil, Tfn, 0, name, t, kids, nil));
116837da2899SCharles.Forsyth	}
116937da2899SCharles.Forsyth	for(i = 1; i < nf; i++)
117037da2899SCharles.Forsyth		fns[i-1].stoppc = fns[i].offset;
117137da2899SCharles.Forsyth	fns[i-1].stoppc = len s.src;
117237da2899SCharles.Forsyth	return p;
117337da2899SCharles.Forsyth}
117437da2899SCharles.Forsyth
117537da2899SCharles.Forsyth#
117637da2899SCharles.Forsyth# parse a list of ids
117737da2899SCharles.Forsyth# format: offset ':' name ':' src type '\n'
117837da2899SCharles.Forsyth#
117937da2899SCharles.Forsythdebugid(ss: ref SrcState, buf: array of byte, p: int): (array of ref Id, int)
118037da2899SCharles.Forsyth{
118137da2899SCharles.Forsyth	t: ref Type;
118237da2899SCharles.Forsyth	off, nd, q, qq, tq: int;
118337da2899SCharles.Forsyth	src: ref Src;
118437da2899SCharles.Forsyth
118537da2899SCharles.Forsyth	(nd, p) = strtoi(buf, p);
118637da2899SCharles.Forsyth	if(buf[p++] != byte '\n')
118737da2899SCharles.Forsyth		return (nil, -1);
118837da2899SCharles.Forsyth	d := array[nd] of ref Id;
118937da2899SCharles.Forsyth	for(i := 0; i < nd; i++){
119037da2899SCharles.Forsyth		(off, q) = strtoi(buf, p);
119137da2899SCharles.Forsyth		if(buf[q++] != byte ':')
119237da2899SCharles.Forsyth			return (nil, -1);
119337da2899SCharles.Forsyth		qq = strchr(buf, q, ':');
119437da2899SCharles.Forsyth		if(buf[qq] != byte ':')
119537da2899SCharles.Forsyth			return (nil, -1);
119637da2899SCharles.Forsyth		tq = qq + 1;
119737da2899SCharles.Forsyth		if(ss.vers > 10){
119837da2899SCharles.Forsyth			(src, tq) = debugsrc(ss, buf, tq);
119937da2899SCharles.Forsyth			if(tq < 0)
120037da2899SCharles.Forsyth				return (nil, -1);
120137da2899SCharles.Forsyth		}
120237da2899SCharles.Forsyth		(t, p) = debugtype(ss, buf, tq);
120337da2899SCharles.Forsyth		if(p == -1 || buf[p++] != byte '\n')
120437da2899SCharles.Forsyth			return (nil, -1);
120537da2899SCharles.Forsyth		d[i] = ref Id(src, string buf[q:qq], off, 0, t);
120637da2899SCharles.Forsyth	}
120737da2899SCharles.Forsyth	return (d, p);
120837da2899SCharles.Forsyth}
120937da2899SCharles.Forsyth
121037da2899SCharles.Forsythidlist(a: array of ref Id): list of ref Id
121137da2899SCharles.Forsyth{
121237da2899SCharles.Forsyth	n := len a;
121337da2899SCharles.Forsyth	ids : list of ref Id = nil;
121437da2899SCharles.Forsyth	while(n-- > 0)
121537da2899SCharles.Forsyth		ids = a[n] :: ids;
121637da2899SCharles.Forsyth	return ids;
121737da2899SCharles.Forsyth}
121837da2899SCharles.Forsyth
121937da2899SCharles.Forsyth#
122037da2899SCharles.Forsyth# parse a type description
122137da2899SCharles.Forsyth#
122237da2899SCharles.Forsythdebugtype(ss: ref SrcState, buf: array of byte, p: int): (ref Type, int)
122337da2899SCharles.Forsyth{
122437da2899SCharles.Forsyth	t: ref Type;
122537da2899SCharles.Forsyth	d: array of ref Id;
122637da2899SCharles.Forsyth	q, k: int;
122737da2899SCharles.Forsyth	src: ref Src;
122837da2899SCharles.Forsyth
122937da2899SCharles.Forsyth	size := 0;
123037da2899SCharles.Forsyth	case int buf[p++]{
123137da2899SCharles.Forsyth	'@' =>
123237da2899SCharles.Forsyth		k = Tid;
123337da2899SCharles.Forsyth	'A' =>
123437da2899SCharles.Forsyth		k = Tarray;
123537da2899SCharles.Forsyth		size = IBY2WD;
123637da2899SCharles.Forsyth	'B' =>
123737da2899SCharles.Forsyth		return (tbig, p);
123837da2899SCharles.Forsyth	'C' =>	k = Tchan;
123937da2899SCharles.Forsyth		size = IBY2WD;
124037da2899SCharles.Forsyth	'L' =>
124137da2899SCharles.Forsyth		k = Tlist;
124237da2899SCharles.Forsyth		size = IBY2WD;
124337da2899SCharles.Forsyth	'N' =>
124437da2899SCharles.Forsyth		return (tnil, p);
124537da2899SCharles.Forsyth	'R' =>
124637da2899SCharles.Forsyth		k = Tref;
124737da2899SCharles.Forsyth		size = IBY2WD;
124837da2899SCharles.Forsyth	'a' =>
124937da2899SCharles.Forsyth		k = Tadt;
125037da2899SCharles.Forsyth		if(ss.vers < 20)
125137da2899SCharles.Forsyth			size = -1;
125237da2899SCharles.Forsyth	'b' =>
125337da2899SCharles.Forsyth		return (tbyte, p);
125437da2899SCharles.Forsyth	'f' =>
125537da2899SCharles.Forsyth		return (treal, p);
125637da2899SCharles.Forsyth	'i' =>
125737da2899SCharles.Forsyth		return (tint, p);
125837da2899SCharles.Forsyth	'm' =>
125937da2899SCharles.Forsyth		k = Tmodule;
126037da2899SCharles.Forsyth		size = IBY2WD;
126137da2899SCharles.Forsyth	'n' =>
126237da2899SCharles.Forsyth		return (tnone, p);
126337da2899SCharles.Forsyth	'p' =>
126437da2899SCharles.Forsyth		k = Tadtpick;
126537da2899SCharles.Forsyth	's' =>
126637da2899SCharles.Forsyth		return (tstring, p);
126737da2899SCharles.Forsyth	't' =>
126837da2899SCharles.Forsyth		k = Ttuple;
126937da2899SCharles.Forsyth	 	size = -1;
127037da2899SCharles.Forsyth	'F' =>
127137da2899SCharles.Forsyth		k = Tfn;
127237da2899SCharles.Forsyth		size = IBY2WD;
127337da2899SCharles.Forsyth	'P' =>
127437da2899SCharles.Forsyth		return (tpoly, p);
127537da2899SCharles.Forsyth	* =>
127637da2899SCharles.Forsyth		k = Terror;
127737da2899SCharles.Forsyth	}
127837da2899SCharles.Forsyth
127937da2899SCharles.Forsyth	if(size == -1){
128037da2899SCharles.Forsyth		q = strchr(buf, p, '.');
128137da2899SCharles.Forsyth		if(buf[q] == byte '.'){
128237da2899SCharles.Forsyth			size = int string buf[p:q];
128337da2899SCharles.Forsyth			p = q+1;
128437da2899SCharles.Forsyth		}
128537da2899SCharles.Forsyth	}
128637da2899SCharles.Forsyth
128737da2899SCharles.Forsyth	case k{
128837da2899SCharles.Forsyth	Tid =>
128937da2899SCharles.Forsyth		q = strchr(buf, p, '\n');
129037da2899SCharles.Forsyth		if(buf[q] != byte '\n')
129137da2899SCharles.Forsyth			return (nil, -1);
129237da2899SCharles.Forsyth		t = ref Type(nil, Tid, -1, string buf[p:q], nil, nil, nil);
129337da2899SCharles.Forsyth		p = q + 1;
129437da2899SCharles.Forsyth	Tadt =>
129537da2899SCharles.Forsyth		if(ss.vers < 20){
129637da2899SCharles.Forsyth			q = strchr(buf, p, '\n');
129737da2899SCharles.Forsyth			if(buf[q] != byte '\n')
129837da2899SCharles.Forsyth				return (nil, -1);
129937da2899SCharles.Forsyth			t = ref Type(nil, Tid, size, string buf[p:q], nil, nil, nil);
130037da2899SCharles.Forsyth			p = q + 1;
130137da2899SCharles.Forsyth		}else
130237da2899SCharles.Forsyth			(t, p) = debugadt(ss, buf, p);
130337da2899SCharles.Forsyth	Tadtpick =>
130437da2899SCharles.Forsyth		(t, p) = debugadt(ss, buf, p);
130537da2899SCharles.Forsyth		t.kind = Tadtpick;
130637da2899SCharles.Forsyth		(t.tags, p) = debugtag(ss, buf, p);
130737da2899SCharles.Forsyth	Tmodule =>
130837da2899SCharles.Forsyth		q = strchr(buf, p, '\n');
130937da2899SCharles.Forsyth		if(buf[q] != byte '\n')
131037da2899SCharles.Forsyth			return (nil, -1);
131137da2899SCharles.Forsyth		t = ref Type(nil, k, size, string buf[p:q], nil, nil, nil);
131237da2899SCharles.Forsyth		p = q + 1;
131337da2899SCharles.Forsyth		if(ss.vers > 10){
131437da2899SCharles.Forsyth			(src, p) = debugsrc(ss, buf, p);
131537da2899SCharles.Forsyth			t.src = src;
131637da2899SCharles.Forsyth		}
131737da2899SCharles.Forsyth		if(ss.vers > 20)
131837da2899SCharles.Forsyth			(t.ids, p) = debugid(ss, buf, p);
131937da2899SCharles.Forsyth	Tref or Tarray or Tlist or Tchan =>		# ref, array, list, chan
132037da2899SCharles.Forsyth		(t, p) = debugtype(ss, buf, p);
132137da2899SCharles.Forsyth		t = ref Type(nil, k, size, "", t, nil, nil);
132237da2899SCharles.Forsyth
132337da2899SCharles.Forsyth	Ttuple =>						# tuple
132437da2899SCharles.Forsyth		(d, p) = debugid(ss, buf, p);
132537da2899SCharles.Forsyth		t = ref Type(nil, k, size, "", nil, d, nil);
132637da2899SCharles.Forsyth
132737da2899SCharles.Forsyth	Tfn =>						# fn
132837da2899SCharles.Forsyth		(d, p) = debugid(ss, buf, p);
132937da2899SCharles.Forsyth		(t, p) = debugtype(ss, buf, p);
133037da2899SCharles.Forsyth		t = ref Type(nil, k, size, "", t, d, nil);
133137da2899SCharles.Forsyth
133237da2899SCharles.Forsyth	* =>
133337da2899SCharles.Forsyth		p = -1;
133437da2899SCharles.Forsyth	}
133537da2899SCharles.Forsyth	return (t, p);
133637da2899SCharles.Forsyth}
133737da2899SCharles.Forsyth
133837da2899SCharles.Forsyth#
133937da2899SCharles.Forsyth# parse an adt type spec
134037da2899SCharles.Forsyth# format: name ' ' src size '\n' ids
134137da2899SCharles.Forsyth#
134237da2899SCharles.Forsythdebugadt(ss: ref SrcState, buf: array of byte, p: int): (ref Type, int)
134337da2899SCharles.Forsyth{
134437da2899SCharles.Forsyth	src: ref Src;
134537da2899SCharles.Forsyth
134637da2899SCharles.Forsyth	q := strchr(buf, p, ' ');
134737da2899SCharles.Forsyth	if(buf[q] != byte ' ')
134837da2899SCharles.Forsyth		return (nil, -1);
134937da2899SCharles.Forsyth	sq := q + 1;
135037da2899SCharles.Forsyth	if(ss.vers > 10){
135137da2899SCharles.Forsyth		(src, sq) = debugsrc(ss, buf, sq);
135237da2899SCharles.Forsyth		if(sq < 0)
135337da2899SCharles.Forsyth			return (nil, -1);
135437da2899SCharles.Forsyth	}
135537da2899SCharles.Forsyth	qq := strchr(buf, sq, '\n');
135637da2899SCharles.Forsyth	if(buf[qq] != byte '\n')
135737da2899SCharles.Forsyth		return (nil, -1);
135837da2899SCharles.Forsyth	(d, pp) := debugid(ss, buf, qq + 1);
135937da2899SCharles.Forsyth	if(pp == -1)
136037da2899SCharles.Forsyth		return (nil, -1);
136137da2899SCharles.Forsyth	t := ref Type(src, Tadt, int string buf[sq:qq], string buf[p:q], nil, d, nil);
136237da2899SCharles.Forsyth	return (t, pp);
136337da2899SCharles.Forsyth}
136437da2899SCharles.Forsyth
136537da2899SCharles.Forsyth#
136637da2899SCharles.Forsyth# parse a list of tags
136737da2899SCharles.Forsyth# format:
136837da2899SCharles.Forsyth#	name ':' src size '\n' ids
136937da2899SCharles.Forsyth# or
137037da2899SCharles.Forsyth#	name ':' src '\n'
137137da2899SCharles.Forsyth#
137237da2899SCharles.Forsythdebugtag(ss: ref SrcState, buf: array of byte, p: int): (array of ref Type, int)
137337da2899SCharles.Forsyth{
137437da2899SCharles.Forsyth	d: array of ref Id;
137537da2899SCharles.Forsyth	ntg, q, pp, np: int;
137637da2899SCharles.Forsyth	src: ref Src;
137737da2899SCharles.Forsyth
137837da2899SCharles.Forsyth	(ntg, p) = strtoi(buf, p);
137937da2899SCharles.Forsyth	if(buf[p++] != byte '\n')
138037da2899SCharles.Forsyth		return (nil, -1);
138137da2899SCharles.Forsyth	tg := array[ntg] of ref Type;
138237da2899SCharles.Forsyth	for(i := 0; i < ntg; i++){
138337da2899SCharles.Forsyth		pp = strchr(buf, p, ':');
138437da2899SCharles.Forsyth		if(buf[pp] != byte ':')
138537da2899SCharles.Forsyth			return (nil, -1);
138637da2899SCharles.Forsyth		q = pp + 1;
138737da2899SCharles.Forsyth		(src, q) = debugsrc(ss, buf, q);
138837da2899SCharles.Forsyth		if(q < 0)
138937da2899SCharles.Forsyth			return (nil, -1);
139037da2899SCharles.Forsyth		if(buf[q] == byte '\n'){
139137da2899SCharles.Forsyth			np = q + 1;
139237da2899SCharles.Forsyth			if(i <= 0)
139337da2899SCharles.Forsyth				return (nil, -1);
139437da2899SCharles.Forsyth			tg[i] = ref Type(src, Tadt, tg[i-1].size, string buf[p:pp], nil, tg[i-1].ids, nil);
139537da2899SCharles.Forsyth		}else{
139637da2899SCharles.Forsyth			np = strchr(buf, q, '\n');
139737da2899SCharles.Forsyth			if(buf[np] != byte '\n')
139837da2899SCharles.Forsyth				return (nil, -1);
139937da2899SCharles.Forsyth			size := int string buf[q:np];
140037da2899SCharles.Forsyth			(d, np) = debugid(ss, buf, np+1);
140137da2899SCharles.Forsyth			if(np == -1)
140237da2899SCharles.Forsyth				return (nil, -1);
140337da2899SCharles.Forsyth			tg[i] = ref Type(src, Tadt, size, string buf[p:pp], nil, d, nil);
140437da2899SCharles.Forsyth		}
140537da2899SCharles.Forsyth		p = np;
140637da2899SCharles.Forsyth	}
140737da2899SCharles.Forsyth	return (tg, p);
140837da2899SCharles.Forsyth}
140937da2899SCharles.Forsyth
141037da2899SCharles.Forsythstrchr(a: array of byte, p, c: int): int
141137da2899SCharles.Forsyth{
141237da2899SCharles.Forsyth	bc := byte c;
141337da2899SCharles.Forsyth	while((b := a[p]) != byte 0 && b != bc)
141437da2899SCharles.Forsyth		p++;
141537da2899SCharles.Forsyth	return p;
141637da2899SCharles.Forsyth}
141737da2899SCharles.Forsyth
141837da2899SCharles.Forsythstrtoi(a: array of byte, start: int): (int, int)
141937da2899SCharles.Forsyth{
142037da2899SCharles.Forsyth	p := start;
142137da2899SCharles.Forsyth	for(; c := int a[p]; p++){
142237da2899SCharles.Forsyth		case c{
142337da2899SCharles.Forsyth		' ' or '\t' or '\n' or '\r' =>
142437da2899SCharles.Forsyth			continue;
142537da2899SCharles.Forsyth		}
142637da2899SCharles.Forsyth		break;
142737da2899SCharles.Forsyth	}
142837da2899SCharles.Forsyth
142937da2899SCharles.Forsyth	# sign
143037da2899SCharles.Forsyth	neg := c == '-';
143137da2899SCharles.Forsyth	if(neg || c == '+')
143237da2899SCharles.Forsyth		p++;
143337da2899SCharles.Forsyth
143437da2899SCharles.Forsyth	# digits
143537da2899SCharles.Forsyth	n := 0;
143637da2899SCharles.Forsyth	nn := 0;
143737da2899SCharles.Forsyth	ndig := 0;
143837da2899SCharles.Forsyth	over := 0;
143937da2899SCharles.Forsyth	for(; c = int a[p]; p++){
144037da2899SCharles.Forsyth		if(c < '0' || c > '9')
144137da2899SCharles.Forsyth			break;
144237da2899SCharles.Forsyth		ndig++;
144337da2899SCharles.Forsyth		nn = n * 10 + (c - '0');
144437da2899SCharles.Forsyth		if(nn < n)
144537da2899SCharles.Forsyth			over = 1;
144637da2899SCharles.Forsyth		n = nn;
144737da2899SCharles.Forsyth	}
144837da2899SCharles.Forsyth	if(ndig == 0)
144937da2899SCharles.Forsyth		return (0, start);
145037da2899SCharles.Forsyth	if(neg)
145137da2899SCharles.Forsyth		n = -n;
145237da2899SCharles.Forsyth	if(over)
145337da2899SCharles.Forsyth		if(neg)
145437da2899SCharles.Forsyth			n = 2147483647;
145537da2899SCharles.Forsyth		else
145637da2899SCharles.Forsyth			n = int -2147483648;
145737da2899SCharles.Forsyth	return (n, p);
145837da2899SCharles.Forsyth}
145937da2899SCharles.Forsyth
146037da2899SCharles.Forsythhex(a: array of byte): int
146137da2899SCharles.Forsyth{
146237da2899SCharles.Forsyth	n := 0;
146337da2899SCharles.Forsyth	for(i := 0; i < len a; i++){
146437da2899SCharles.Forsyth		c := int a[i];
146537da2899SCharles.Forsyth		if(c >= '0' && c <= '9')
146637da2899SCharles.Forsyth			c -= '0';
146737da2899SCharles.Forsyth		else
146837da2899SCharles.Forsyth			c -= 'a' - 10;
146937da2899SCharles.Forsyth		n = (n << 4) + (c & 15);
147037da2899SCharles.Forsyth	}
147137da2899SCharles.Forsyth	return n;
147237da2899SCharles.Forsyth}
147337da2899SCharles.Forsyth
147437da2899SCharles.Forsythpartition(n : int, max : int) : (int, int, int)
147537da2899SCharles.Forsyth{
147637da2899SCharles.Forsyth	p := n/max;
147737da2899SCharles.Forsyth	if (n%max != 0)
147837da2899SCharles.Forsyth		p++;
147937da2899SCharles.Forsyth	if (p > max)
148037da2899SCharles.Forsyth		p = max;
148137da2899SCharles.Forsyth	q := n/p;
148237da2899SCharles.Forsyth	r := n-p*q;
148337da2899SCharles.Forsyth	return (p, q, r);
148437da2899SCharles.Forsyth}
148537da2899SCharles.Forsyth
148637da2899SCharles.Forsythbounds(s : string) : (int, int)
148737da2899SCharles.Forsyth{
148837da2899SCharles.Forsyth	lb := int s;
148937da2899SCharles.Forsyth	for (i := 0; i < len s; i++)
149037da2899SCharles.Forsyth		if (s[i] == '.')
149137da2899SCharles.Forsyth			break;
149237da2899SCharles.Forsyth	if (i+1 >= len s || s[i] != '.' || s[i+1] != '.')
149337da2899SCharles.Forsyth		return (1, 0);
149437da2899SCharles.Forsyth	ub := int s[i+2:];
149537da2899SCharles.Forsyth	return (lb, ub);
149637da2899SCharles.Forsyth}
1497