xref: /inferno-os/appl/cmd/stack.b (revision 3f1f06c5d12b24c4061e5123acabf72348ff45a2)
1implement Command;
2
3include "sys.m";
4	sys: Sys;
5	print, fprint, FD: import sys;
6	stderr: ref FD;
7
8include "draw.m";
9
10include "debug.m";
11	debug: Debug;
12	Prog, Module, Exp: import debug;
13
14include "arg.m";
15include "bufio.m";
16	bufio: Bufio;
17	Iobuf: import bufio;
18
19include "env.m";
20	env: Env;
21
22include "string.m";
23	str: String;
24
25include "dis.m";
26	dism: Dis;
27
28Command: module
29{
30	init: fn(ctxt: ref Draw->Context, argv: list of string);
31};
32
33usage()
34{
35	sys->fprint(stderr, "usage: stack [-v] pid\n");
36	raise "fail:usage";
37}
38
39badmodule(p: string)
40{
41	sys->fprint(stderr, "stack: cannot load %s: %r\n", p);
42	raise "fail:bad module";
43}
44
45sbldirs: list of (string, string);
46
47init(nil: ref Draw->Context, argv: list of string)
48{
49
50	sys = load Sys Sys->PATH;
51	stderr = sys->fildes(2);
52	arg := load Arg Arg->PATH;
53	if (arg == nil)
54		badmodule(Arg->PATH);
55	bufio = load Bufio Bufio->PATH;
56	if (bufio == nil)
57		badmodule(Bufio->PATH);
58	debug = load Debug Debug->PATH;
59	if(debug == nil)
60		badmodule(Debug->PATH);
61	env = load Env Env->PATH;
62	if (env != nil) {
63		str = load String String->PATH;
64		if (str == nil)
65			badmodule(String->PATH);
66	}
67	bout := bufio->fopen(sys->fildes(1), Sys->OWRITE);
68
69	arg->init(argv);
70	verbose := 0;
71	while ((opt := arg->opt()) != 0) {
72		case opt {
73		'v' =>
74			verbose = 1;
75		'p' =>
76			dispath := arg->arg();
77			sblpath := arg->arg();
78			if (dispath == nil || sblpath == nil)
79				usage();
80			sbldirs = (addslash(dispath), addslash(sblpath)) :: sbldirs;
81		* =>
82			usage();
83		}
84	}
85	if (env != nil && (pathl := env->getenv("sblpath")) != nil) {
86		toks := str->unquoted(pathl);
87		for (; toks != nil && tl toks != nil; toks = tl tl toks)
88			sbldirs = (addslash(hd toks), addslash(hd tl toks)) :: sbldirs;
89	}
90	t: list of (string, string);
91	for (; sbldirs != nil; sbldirs = tl sbldirs)
92		t = hd sbldirs :: t;
93	sbldirs = t;
94
95	argv = arg->argv();
96	if(argv == nil)
97		usage();
98
99	debug->init();
100
101	(p, err) := debug->prog(int hd argv);
102	if(err != nil){
103		fprint(stderr, "stack: %s\n", err);
104		return;
105	}
106	stk: array of ref Exp;
107	(stk, err) = p.stack();
108
109	if(err != nil){
110		fprint(stderr, "stack: %s\n", err);
111		return;
112	}
113
114	for(i := 0; i < len stk; i++){
115		stdsym(stk[i].m);
116		stk[i].m.stdsym();
117		stk[i].findsym();
118		bout.puts(stk[i].name + "(");
119		vs := stk[i].expand();
120		if(verbose && vs != nil){
121			for(j := 0; j < len vs; j++){
122				if(vs[j].name == "args"){
123					d := vs[j].expand();
124					s := "";
125					for(j = 0; j < len d; j++) {
126						bout.puts(sys->sprint("%s%s=%s", s, d[j].name, d[j].val().t0));
127						s = ", ";
128					}
129					break;
130				}
131			}
132		}
133		bout.puts(sys->sprint(") %s\n", stk[i].srcstr()));
134		if(verbose && vs != nil){
135			for(j := 0; j < len vs; j++){
136				if(vs[j].name == "locals"){
137					d := vs[j].expand();
138					for(j = 0; j < len d; j++)
139						bout.puts("\t" + d[j].name + "=" + d[j].val().t0 + "\n");
140					break;
141				}
142			}
143		}
144	}
145	bout.flush();
146}
147
148stdsym(m: ref Module)
149{
150	dis := m.dis();
151	if(dism == nil){
152		dism = load Dis Dis->PATH;
153		if(dism != nil)
154			dism->init();
155	}
156	if(dism != nil && (sp := dism->src(dis)) != nil){
157		sp = sp[0: len sp - 1] + "sbl";
158		(sym, nil) := debug->sym(sp);
159		if (sym != nil) {
160			m.addsym(sym);
161			return;
162		}
163	}
164	for (sbl := sbldirs; sbl != nil; sbl = tl sbl) {
165		(dispath, sblpath) := hd sbl;
166		if (len dis > len dispath && dis[0:len dispath] == dispath) {
167			sblpath = sblpath + dis[len dispath:];
168			if (len sblpath > 4 && sblpath[len sblpath - 4:] == ".dis")
169				sblpath = sblpath[0:len sblpath - 4] + ".sbl";
170			(sym, nil) := debug->sym(sblpath);
171			if (sym != nil) {
172				m.addsym(sym);
173				return;
174			}
175		}
176	}
177}
178
179addslash(p: string): string
180{
181	if (p != nil && p[len p - 1] != '/')
182		p[len p] = '/';
183	return p;
184}
185