xref: /plan9/sys/src/cmd/venti/srv/hproc.c (revision c65cf52c968b3e4454fbdf2cbd1ee2e54eea2c58)
1*c65cf52cSDavid du Colombier #include "stdinc.h"
2*c65cf52cSDavid du Colombier #include <bio.h>
3*c65cf52cSDavid du Colombier #include <mach.h>
4*c65cf52cSDavid du Colombier #include <ureg.h>
5*c65cf52cSDavid du Colombier #include "/sys/src/libthread/threadimpl.h"
6*c65cf52cSDavid du Colombier #include "dat.h"
7*c65cf52cSDavid du Colombier #include "fns.h"
8*c65cf52cSDavid du Colombier 
9*c65cf52cSDavid du Colombier typedef struct Ureg Ureg;
10*c65cf52cSDavid du Colombier typedef struct Debug Debug;
11*c65cf52cSDavid du Colombier 
12*c65cf52cSDavid du Colombier struct Debug
13*c65cf52cSDavid du Colombier {
14*c65cf52cSDavid du Colombier 	int textfd;
15*c65cf52cSDavid du Colombier 	QLock lock;
16*c65cf52cSDavid du Colombier 	Fhdr fhdr;
17*c65cf52cSDavid du Colombier 	Map *map;
18*c65cf52cSDavid du Colombier 	Fmt *fmt;
19*c65cf52cSDavid du Colombier 	int pid;
20*c65cf52cSDavid du Colombier 	char *stkprefix;
21*c65cf52cSDavid du Colombier };
22*c65cf52cSDavid du Colombier 
23*c65cf52cSDavid du Colombier static Debug debug = { -1 };
24*c65cf52cSDavid du Colombier 
25*c65cf52cSDavid du Colombier static int
26*c65cf52cSDavid du Colombier text(int pid)
27*c65cf52cSDavid du Colombier {
28*c65cf52cSDavid du Colombier 	int fd;
29*c65cf52cSDavid du Colombier 	char buf[100];
30*c65cf52cSDavid du Colombier 
31*c65cf52cSDavid du Colombier 	if(debug.textfd >= 0){
32*c65cf52cSDavid du Colombier 		close(debug.textfd);
33*c65cf52cSDavid du Colombier 		debug.textfd = -1;
34*c65cf52cSDavid du Colombier 	}
35*c65cf52cSDavid du Colombier 	memset(&debug.fhdr, 0, sizeof debug.fhdr);
36*c65cf52cSDavid du Colombier 
37*c65cf52cSDavid du Colombier 	snprint(buf, sizeof buf, "#p/%d/text", pid);
38*c65cf52cSDavid du Colombier 	fd = open(buf, OREAD);
39*c65cf52cSDavid du Colombier 	if(fd < 0)
40*c65cf52cSDavid du Colombier 		return -1;
41*c65cf52cSDavid du Colombier 	if(crackhdr(fd, &debug.fhdr) < 0){
42*c65cf52cSDavid du Colombier 		close(fd);
43*c65cf52cSDavid du Colombier 		return -1;
44*c65cf52cSDavid du Colombier 	}
45*c65cf52cSDavid du Colombier 	if(syminit(fd, &debug.fhdr) < 0){
46*c65cf52cSDavid du Colombier 		memset(&debug.fhdr, 0, sizeof debug.fhdr);
47*c65cf52cSDavid du Colombier 		close(fd);
48*c65cf52cSDavid du Colombier 		return -1;
49*c65cf52cSDavid du Colombier 	}
50*c65cf52cSDavid du Colombier 	debug.textfd = fd;
51*c65cf52cSDavid du Colombier 	machbytype(debug.fhdr.type);
52*c65cf52cSDavid du Colombier 	return 0;
53*c65cf52cSDavid du Colombier }
54*c65cf52cSDavid du Colombier 
55*c65cf52cSDavid du Colombier static void
56*c65cf52cSDavid du Colombier unmap(Map *m)
57*c65cf52cSDavid du Colombier {
58*c65cf52cSDavid du Colombier 	int i;
59*c65cf52cSDavid du Colombier 
60*c65cf52cSDavid du Colombier 	for(i=0; i<m->nsegs; i++)
61*c65cf52cSDavid du Colombier 		if(m->seg[i].inuse)
62*c65cf52cSDavid du Colombier 			close(m->seg[i].fd);
63*c65cf52cSDavid du Colombier 	free(m);
64*c65cf52cSDavid du Colombier }
65*c65cf52cSDavid du Colombier 
66*c65cf52cSDavid du Colombier static Map*
67*c65cf52cSDavid du Colombier map(int pid)
68*c65cf52cSDavid du Colombier {
69*c65cf52cSDavid du Colombier 	int mem;
70*c65cf52cSDavid du Colombier 	char buf[100];
71*c65cf52cSDavid du Colombier 	Map *m;
72*c65cf52cSDavid du Colombier 
73*c65cf52cSDavid du Colombier 	snprint(buf, sizeof buf, "#p/%d/mem", pid);
74*c65cf52cSDavid du Colombier 	mem = open(buf, OREAD);
75*c65cf52cSDavid du Colombier 	if(mem < 0)
76*c65cf52cSDavid du Colombier 		return nil;
77*c65cf52cSDavid du Colombier 
78*c65cf52cSDavid du Colombier 	m = attachproc(pid, 0, mem, &debug.fhdr);
79*c65cf52cSDavid du Colombier 	if(m == 0){
80*c65cf52cSDavid du Colombier 		close(mem);
81*c65cf52cSDavid du Colombier 		return nil;
82*c65cf52cSDavid du Colombier 	}
83*c65cf52cSDavid du Colombier 
84*c65cf52cSDavid du Colombier 	if(debug.map)
85*c65cf52cSDavid du Colombier 		unmap(debug.map);
86*c65cf52cSDavid du Colombier 	debug.map = m;
87*c65cf52cSDavid du Colombier 	debug.pid = pid;
88*c65cf52cSDavid du Colombier 	return m;
89*c65cf52cSDavid du Colombier }
90*c65cf52cSDavid du Colombier 
91*c65cf52cSDavid du Colombier static void
92*c65cf52cSDavid du Colombier dprint(char *fmt, ...)
93*c65cf52cSDavid du Colombier {
94*c65cf52cSDavid du Colombier 	va_list arg;
95*c65cf52cSDavid du Colombier 
96*c65cf52cSDavid du Colombier 	va_start(arg, fmt);
97*c65cf52cSDavid du Colombier 	fmtvprint(debug.fmt, fmt, arg);
98*c65cf52cSDavid du Colombier 	va_end(arg);
99*c65cf52cSDavid du Colombier }
100*c65cf52cSDavid du Colombier 
101*c65cf52cSDavid du Colombier static void
102*c65cf52cSDavid du Colombier openfiles(void)
103*c65cf52cSDavid du Colombier {
104*c65cf52cSDavid du Colombier 	char buf[4096];
105*c65cf52cSDavid du Colombier 	int fd, n;
106*c65cf52cSDavid du Colombier 
107*c65cf52cSDavid du Colombier 	snprint(buf, sizeof buf, "#p/%d/fd", getpid());
108*c65cf52cSDavid du Colombier 	if((fd = open(buf, OREAD)) < 0){
109*c65cf52cSDavid du Colombier 		dprint("open %s: %r\n", buf);
110*c65cf52cSDavid du Colombier 		return;
111*c65cf52cSDavid du Colombier 	}
112*c65cf52cSDavid du Colombier 	n = readn(fd, buf, sizeof buf-1);
113*c65cf52cSDavid du Colombier 	close(fd);
114*c65cf52cSDavid du Colombier 	if(n >= 0){
115*c65cf52cSDavid du Colombier 		buf[n] = 0;
116*c65cf52cSDavid du Colombier 		fmtstrcpy(debug.fmt, buf);
117*c65cf52cSDavid du Colombier 	}
118*c65cf52cSDavid du Colombier }
119*c65cf52cSDavid du Colombier 
120*c65cf52cSDavid du Colombier /*
121*c65cf52cSDavid du Colombier  *	dump the raw symbol table
122*c65cf52cSDavid du Colombier  */
123*c65cf52cSDavid du Colombier static void
124*c65cf52cSDavid du Colombier printsym(void)
125*c65cf52cSDavid du Colombier {
126*c65cf52cSDavid du Colombier 	int i;
127*c65cf52cSDavid du Colombier 	Sym *sp;
128*c65cf52cSDavid du Colombier 
129*c65cf52cSDavid du Colombier 	for (i = 0; sp = getsym(i); i++) {
130*c65cf52cSDavid du Colombier 		switch(sp->type) {
131*c65cf52cSDavid du Colombier 		case 't':
132*c65cf52cSDavid du Colombier 		case 'l':
133*c65cf52cSDavid du Colombier 			dprint("%16#llux t %s\n", sp->value, sp->name);
134*c65cf52cSDavid du Colombier 			break;
135*c65cf52cSDavid du Colombier 		case 'T':
136*c65cf52cSDavid du Colombier 		case 'L':
137*c65cf52cSDavid du Colombier 			dprint("%16#llux T %s\n", sp->value, sp->name);
138*c65cf52cSDavid du Colombier 			break;
139*c65cf52cSDavid du Colombier 		case 'D':
140*c65cf52cSDavid du Colombier 		case 'd':
141*c65cf52cSDavid du Colombier 		case 'B':
142*c65cf52cSDavid du Colombier 		case 'b':
143*c65cf52cSDavid du Colombier 		case 'a':
144*c65cf52cSDavid du Colombier 		case 'p':
145*c65cf52cSDavid du Colombier 		case 'm':
146*c65cf52cSDavid du Colombier 			dprint("%16#llux %c %s\n", sp->value, sp->type, sp->name);
147*c65cf52cSDavid du Colombier 			break;
148*c65cf52cSDavid du Colombier 		default:
149*c65cf52cSDavid du Colombier 			break;
150*c65cf52cSDavid du Colombier 		}
151*c65cf52cSDavid du Colombier 	}
152*c65cf52cSDavid du Colombier }
153*c65cf52cSDavid du Colombier 
154*c65cf52cSDavid du Colombier static void
155*c65cf52cSDavid du Colombier printmap(char *s, Map *map)
156*c65cf52cSDavid du Colombier {
157*c65cf52cSDavid du Colombier 	int i;
158*c65cf52cSDavid du Colombier 
159*c65cf52cSDavid du Colombier 	if (!map)
160*c65cf52cSDavid du Colombier 		return;
161*c65cf52cSDavid du Colombier 	dprint("%s\n", s);
162*c65cf52cSDavid du Colombier 	for (i = 0; i < map->nsegs; i++) {
163*c65cf52cSDavid du Colombier 		if (map->seg[i].inuse)
164*c65cf52cSDavid du Colombier 			dprint("%-16s %-16#llux %-16#llux %-16#llux\n",
165*c65cf52cSDavid du Colombier 				map->seg[i].name, map->seg[i].b,
166*c65cf52cSDavid du Colombier 				map->seg[i].e, map->seg[i].f);
167*c65cf52cSDavid du Colombier 	}
168*c65cf52cSDavid du Colombier }
169*c65cf52cSDavid du Colombier 
170*c65cf52cSDavid du Colombier #define ADDR ulong
171*c65cf52cSDavid du Colombier 
172*c65cf52cSDavid du Colombier static void
173*c65cf52cSDavid du Colombier printlocals(Map *map, Symbol *fn, ADDR fp)
174*c65cf52cSDavid du Colombier {
175*c65cf52cSDavid du Colombier 	int i;
176*c65cf52cSDavid du Colombier 	ulong w;
177*c65cf52cSDavid du Colombier 	Symbol s;
178*c65cf52cSDavid du Colombier 	char buf[100];
179*c65cf52cSDavid du Colombier 
180*c65cf52cSDavid du Colombier 	s = *fn;
181*c65cf52cSDavid du Colombier 	for (i = 0; localsym(&s, i); i++) {
182*c65cf52cSDavid du Colombier 		if (s.class != CAUTO)
183*c65cf52cSDavid du Colombier 			continue;
184*c65cf52cSDavid du Colombier 		snprint(buf, sizeof buf, "%s%s/", debug.stkprefix, s.name);
185*c65cf52cSDavid du Colombier 		if (get4(map, fp-s.value, &w) > 0)
186*c65cf52cSDavid du Colombier 			dprint("\t%-10s %10#lux %ld\n", buf, w, w);
187*c65cf52cSDavid du Colombier 		else
188*c65cf52cSDavid du Colombier 			dprint("\t%-10s ?\n", buf);
189*c65cf52cSDavid du Colombier 	}
190*c65cf52cSDavid du Colombier }
191*c65cf52cSDavid du Colombier 
192*c65cf52cSDavid du Colombier static void
193*c65cf52cSDavid du Colombier printparams(Map *map, Symbol *fn, ADDR fp)
194*c65cf52cSDavid du Colombier {
195*c65cf52cSDavid du Colombier 	int i;
196*c65cf52cSDavid du Colombier 	Symbol s;
197*c65cf52cSDavid du Colombier 	ulong w;
198*c65cf52cSDavid du Colombier 	int first = 0;
199*c65cf52cSDavid du Colombier 
200*c65cf52cSDavid du Colombier 	fp += mach->szaddr;			/* skip saved pc */
201*c65cf52cSDavid du Colombier 	s = *fn;
202*c65cf52cSDavid du Colombier 	for (i = 0; localsym(&s, i); i++) {
203*c65cf52cSDavid du Colombier 		if (s.class != CPARAM)
204*c65cf52cSDavid du Colombier 			continue;
205*c65cf52cSDavid du Colombier 		if (first++)
206*c65cf52cSDavid du Colombier 			dprint(", ");
207*c65cf52cSDavid du Colombier 		if (get4(map, fp+s.value, &w) > 0)
208*c65cf52cSDavid du Colombier 			dprint("%s=%#lux", s.name, w);
209*c65cf52cSDavid du Colombier 	}
210*c65cf52cSDavid du Colombier }
211*c65cf52cSDavid du Colombier 
212*c65cf52cSDavid du Colombier static void
213*c65cf52cSDavid du Colombier printsource(ADDR dot)
214*c65cf52cSDavid du Colombier {
215*c65cf52cSDavid du Colombier 	char str[100];
216*c65cf52cSDavid du Colombier 
217*c65cf52cSDavid du Colombier 	if (fileline(str, sizeof str, dot))
218*c65cf52cSDavid du Colombier 		dprint("%s", str);
219*c65cf52cSDavid du Colombier }
220*c65cf52cSDavid du Colombier 
221*c65cf52cSDavid du Colombier 
222*c65cf52cSDavid du Colombier /*
223*c65cf52cSDavid du Colombier  *	callback on stack trace
224*c65cf52cSDavid du Colombier  */
225*c65cf52cSDavid du Colombier static ulong nextpc;
226*c65cf52cSDavid du Colombier static void
227*c65cf52cSDavid du Colombier ptrace(Map *map, uvlong pc, uvlong sp, Symbol *sym)
228*c65cf52cSDavid du Colombier {
229*c65cf52cSDavid du Colombier 	if(nextpc == 0)
230*c65cf52cSDavid du Colombier 		nextpc = sym->value;
231*c65cf52cSDavid du Colombier 	if(debug.stkprefix == nil)
232*c65cf52cSDavid du Colombier 		debug.stkprefix = "";
233*c65cf52cSDavid du Colombier 	dprint("%s%s(", debug.stkprefix, sym->name);
234*c65cf52cSDavid du Colombier 	printparams(map, sym, sp);
235*c65cf52cSDavid du Colombier 	dprint(")");
236*c65cf52cSDavid du Colombier 	if(nextpc != sym->value)
237*c65cf52cSDavid du Colombier 		dprint("+%#lx ", nextpc - sym->value);
238*c65cf52cSDavid du Colombier 	printsource(nextpc);
239*c65cf52cSDavid du Colombier 	dprint("\n");
240*c65cf52cSDavid du Colombier 	printlocals(map, sym, sp);
241*c65cf52cSDavid du Colombier 	nextpc = pc;
242*c65cf52cSDavid du Colombier }
243*c65cf52cSDavid du Colombier 
244*c65cf52cSDavid du Colombier static void
245*c65cf52cSDavid du Colombier stacktracepcsp(Map *m, ulong pc, ulong sp)
246*c65cf52cSDavid du Colombier {
247*c65cf52cSDavid du Colombier 	nextpc = 0;
248*c65cf52cSDavid du Colombier 	if(machdata->ctrace==nil)
249*c65cf52cSDavid du Colombier 		dprint("no machdata->ctrace\n");
250*c65cf52cSDavid du Colombier 	else if(machdata->ctrace(m, pc, sp, 0, ptrace) <= 0)
251*c65cf52cSDavid du Colombier 		dprint("no stack frame: pc=%#lux sp=%#lux\n", pc, sp);
252*c65cf52cSDavid du Colombier }
253*c65cf52cSDavid du Colombier 
254*c65cf52cSDavid du Colombier static void
255*c65cf52cSDavid du Colombier stacktrace(Map *m)
256*c65cf52cSDavid du Colombier {
257*c65cf52cSDavid du Colombier 	ulong pc, sp;
258*c65cf52cSDavid du Colombier 
259*c65cf52cSDavid du Colombier 	if(get4(m, offsetof(Ureg, pc), &pc) < 0){
260*c65cf52cSDavid du Colombier 		dprint("get4 pc: %r");
261*c65cf52cSDavid du Colombier 		return;
262*c65cf52cSDavid du Colombier 	}
263*c65cf52cSDavid du Colombier 	if(get4(m, offsetof(Ureg, sp), &sp) < 0){
264*c65cf52cSDavid du Colombier 		dprint("get4 sp: %r");
265*c65cf52cSDavid du Colombier 		return;
266*c65cf52cSDavid du Colombier 	}
267*c65cf52cSDavid du Colombier 	stacktracepcsp(m, pc, sp);
268*c65cf52cSDavid du Colombier }
269*c65cf52cSDavid du Colombier 
270*c65cf52cSDavid du Colombier static ulong
271*c65cf52cSDavid du Colombier star(ulong addr)
272*c65cf52cSDavid du Colombier {
273*c65cf52cSDavid du Colombier 	ulong x;
274*c65cf52cSDavid du Colombier 	static int warned;
275*c65cf52cSDavid du Colombier 
276*c65cf52cSDavid du Colombier 	if(addr == 0)
277*c65cf52cSDavid du Colombier 		return 0;
278*c65cf52cSDavid du Colombier 
279*c65cf52cSDavid du Colombier 	if(debug.map == nil){
280*c65cf52cSDavid du Colombier 		if(!warned++)
281*c65cf52cSDavid du Colombier 			dprint("no debug.map\n");
282*c65cf52cSDavid du Colombier 		return 0;
283*c65cf52cSDavid du Colombier 	}
284*c65cf52cSDavid du Colombier 	if(get4(debug.map, addr, &x) < 0){
285*c65cf52cSDavid du Colombier 		dprint("get4 %#lux (pid=%d): %r\n", addr, debug.pid);
286*c65cf52cSDavid du Colombier 		return 0;
287*c65cf52cSDavid du Colombier 	}
288*c65cf52cSDavid du Colombier 	return x;
289*c65cf52cSDavid du Colombier }
290*c65cf52cSDavid du Colombier 
291*c65cf52cSDavid du Colombier static ulong
292*c65cf52cSDavid du Colombier resolvev(char *name)
293*c65cf52cSDavid du Colombier {
294*c65cf52cSDavid du Colombier 	Symbol s;
295*c65cf52cSDavid du Colombier 
296*c65cf52cSDavid du Colombier 	if(lookup(nil, name, &s) == 0)
297*c65cf52cSDavid du Colombier 		return 0;
298*c65cf52cSDavid du Colombier 	return s.value;
299*c65cf52cSDavid du Colombier }
300*c65cf52cSDavid du Colombier 
301*c65cf52cSDavid du Colombier static ulong
302*c65cf52cSDavid du Colombier resolvef(char *name)
303*c65cf52cSDavid du Colombier {
304*c65cf52cSDavid du Colombier 	Symbol s;
305*c65cf52cSDavid du Colombier 
306*c65cf52cSDavid du Colombier 	if(lookup(name, nil, &s) == 0)
307*c65cf52cSDavid du Colombier 		return 0;
308*c65cf52cSDavid du Colombier 	return s.value;
309*c65cf52cSDavid du Colombier }
310*c65cf52cSDavid du Colombier 
311*c65cf52cSDavid du Colombier #define FADDR(type, p, name) ((p) + offsetof(type, name))
312*c65cf52cSDavid du Colombier #define FIELD(type, p, name) star(FADDR(type, p, name))
313*c65cf52cSDavid du Colombier 
314*c65cf52cSDavid du Colombier static ulong threadpc;
315*c65cf52cSDavid du Colombier 
316*c65cf52cSDavid du Colombier static int
317*c65cf52cSDavid du Colombier strprefix(char *big, char *pre)
318*c65cf52cSDavid du Colombier {
319*c65cf52cSDavid du Colombier 	return strncmp(big, pre, strlen(pre));
320*c65cf52cSDavid du Colombier }
321*c65cf52cSDavid du Colombier static void
322*c65cf52cSDavid du Colombier tptrace(Map *map, uvlong pc, uvlong sp, Symbol *sym)
323*c65cf52cSDavid du Colombier {
324*c65cf52cSDavid du Colombier 	char buf[512];
325*c65cf52cSDavid du Colombier 
326*c65cf52cSDavid du Colombier 	USED(map);
327*c65cf52cSDavid du Colombier 	USED(sym);
328*c65cf52cSDavid du Colombier 	USED(sp);
329*c65cf52cSDavid du Colombier 
330*c65cf52cSDavid du Colombier 	if(threadpc != 0)
331*c65cf52cSDavid du Colombier 		return;
332*c65cf52cSDavid du Colombier 	if(!fileline(buf, sizeof buf, pc))
333*c65cf52cSDavid du Colombier 		return;
334*c65cf52cSDavid du Colombier 	if(strprefix(buf, "/sys/src/libc/") == 0)
335*c65cf52cSDavid du Colombier 		return;
336*c65cf52cSDavid du Colombier 	if(strprefix(buf, "/sys/src/libthread/") == 0)
337*c65cf52cSDavid du Colombier 		return;
338*c65cf52cSDavid du Colombier 	if(strprefix(buf, "/sys/src/libthread/") == 0)
339*c65cf52cSDavid du Colombier 		return;
340*c65cf52cSDavid du Colombier 	threadpc = pc;
341*c65cf52cSDavid du Colombier }
342*c65cf52cSDavid du Colombier 
343*c65cf52cSDavid du Colombier static char*
344*c65cf52cSDavid du Colombier threadstkline(ulong t)
345*c65cf52cSDavid du Colombier {
346*c65cf52cSDavid du Colombier 	ulong pc, sp;
347*c65cf52cSDavid du Colombier 	static char buf[500];
348*c65cf52cSDavid du Colombier 
349*c65cf52cSDavid du Colombier 	if(FIELD(Thread, t, state) == Running){
350*c65cf52cSDavid du Colombier 		get4(debug.map, offsetof(Ureg, pc), &pc);
351*c65cf52cSDavid du Colombier 		get4(debug.map, offsetof(Ureg, sp), &sp);
352*c65cf52cSDavid du Colombier 	}else{
353*c65cf52cSDavid du Colombier 		// pc = FIELD(Thread, t, sched[JMPBUFPC]);
354*c65cf52cSDavid du Colombier 		pc = resolvef("longjmp");
355*c65cf52cSDavid du Colombier 		sp = FIELD(Thread, t, sched[JMPBUFSP]);
356*c65cf52cSDavid du Colombier 	}
357*c65cf52cSDavid du Colombier 	if(machdata->ctrace == nil)
358*c65cf52cSDavid du Colombier 		return "";
359*c65cf52cSDavid du Colombier 	threadpc = 0;
360*c65cf52cSDavid du Colombier 	machdata->ctrace(debug.map, pc, sp, 0, tptrace);
361*c65cf52cSDavid du Colombier 	if(!fileline(buf, sizeof buf, threadpc))
362*c65cf52cSDavid du Colombier 		buf[0] = 0;
363*c65cf52cSDavid du Colombier 	return buf;
364*c65cf52cSDavid du Colombier }
365*c65cf52cSDavid du Colombier 
366*c65cf52cSDavid du Colombier static void
367*c65cf52cSDavid du Colombier proc(ulong p)
368*c65cf52cSDavid du Colombier {
369*c65cf52cSDavid du Colombier 	dprint("p=(Proc)%#lux pid %d ", p, FIELD(Proc, p, pid));
370*c65cf52cSDavid du Colombier 	if(FIELD(Proc, p, thread) == 0)
371*c65cf52cSDavid du Colombier 		dprint(" Sched\n");
372*c65cf52cSDavid du Colombier 	else
373*c65cf52cSDavid du Colombier 		dprint(" Running\n");
374*c65cf52cSDavid du Colombier }
375*c65cf52cSDavid du Colombier 
376*c65cf52cSDavid du Colombier static void
377*c65cf52cSDavid du Colombier fmtbufinit(Fmt *f, char *buf, int len)
378*c65cf52cSDavid du Colombier {
379*c65cf52cSDavid du Colombier 	memset(f, 0, sizeof *f);
380*c65cf52cSDavid du Colombier 	f->runes = 0;
381*c65cf52cSDavid du Colombier 	f->start = buf;
382*c65cf52cSDavid du Colombier 	f->to = buf;
383*c65cf52cSDavid du Colombier 	f->stop = buf + len - 1;
384*c65cf52cSDavid du Colombier 	f->flush = nil;
385*c65cf52cSDavid du Colombier 	f->farg = nil;
386*c65cf52cSDavid du Colombier 	f->nfmt = 0;
387*c65cf52cSDavid du Colombier }
388*c65cf52cSDavid du Colombier 
389*c65cf52cSDavid du Colombier static char*
390*c65cf52cSDavid du Colombier fmtbufflush(Fmt *f)
391*c65cf52cSDavid du Colombier {
392*c65cf52cSDavid du Colombier 	*(char*)f->to = 0;
393*c65cf52cSDavid du Colombier 	return (char*)f->start;
394*c65cf52cSDavid du Colombier }
395*c65cf52cSDavid du Colombier 
396*c65cf52cSDavid du Colombier static char*
397*c65cf52cSDavid du Colombier debugstr(ulong s)
398*c65cf52cSDavid du Colombier {
399*c65cf52cSDavid du Colombier 	static char buf[4096];
400*c65cf52cSDavid du Colombier 	char *p, *e;
401*c65cf52cSDavid du Colombier 
402*c65cf52cSDavid du Colombier 	p = buf;
403*c65cf52cSDavid du Colombier 	e = buf+sizeof buf - 1;
404*c65cf52cSDavid du Colombier 	while(p < e){
405*c65cf52cSDavid du Colombier 		if(get1(debug.map, s++, (uchar*)p, 1) < 0)
406*c65cf52cSDavid du Colombier 			break;
407*c65cf52cSDavid du Colombier 		if(*p == 0)
408*c65cf52cSDavid du Colombier 			break;
409*c65cf52cSDavid du Colombier 		p++;
410*c65cf52cSDavid du Colombier 	}
411*c65cf52cSDavid du Colombier 	*p = 0;
412*c65cf52cSDavid du Colombier 	return buf;
413*c65cf52cSDavid du Colombier }
414*c65cf52cSDavid du Colombier 
415*c65cf52cSDavid du Colombier static char*
416*c65cf52cSDavid du Colombier threadfmt(ulong t)
417*c65cf52cSDavid du Colombier {
418*c65cf52cSDavid du Colombier 	static char buf[4096];
419*c65cf52cSDavid du Colombier 	Fmt fmt;
420*c65cf52cSDavid du Colombier 	int s;
421*c65cf52cSDavid du Colombier 
422*c65cf52cSDavid du Colombier 	fmtbufinit(&fmt, buf, sizeof buf);
423*c65cf52cSDavid du Colombier 
424*c65cf52cSDavid du Colombier 	fmtprint(&fmt, "t=(Thread)%#lux ", t);
425*c65cf52cSDavid du Colombier 	switch(s = FIELD(Thread, t, state)){
426*c65cf52cSDavid du Colombier 	case Running:
427*c65cf52cSDavid du Colombier 		fmtprint(&fmt, " Running   ");
428*c65cf52cSDavid du Colombier 		break;
429*c65cf52cSDavid du Colombier 	case Ready:
430*c65cf52cSDavid du Colombier 		fmtprint(&fmt, " Ready     ");
431*c65cf52cSDavid du Colombier 		break;
432*c65cf52cSDavid du Colombier 	case Rendezvous:
433*c65cf52cSDavid du Colombier 		fmtprint(&fmt, " Rendez    ");
434*c65cf52cSDavid du Colombier 		break;
435*c65cf52cSDavid du Colombier 	default:
436*c65cf52cSDavid du Colombier 		fmtprint(&fmt, " bad state %d ", s);
437*c65cf52cSDavid du Colombier 		break;
438*c65cf52cSDavid du Colombier 	}
439*c65cf52cSDavid du Colombier 
440*c65cf52cSDavid du Colombier 	fmtprint(&fmt, "%s", threadstkline(t));
441*c65cf52cSDavid du Colombier 
442*c65cf52cSDavid du Colombier 	if(FIELD(Thread, t, moribund) == 1)
443*c65cf52cSDavid du Colombier 		fmtprint(&fmt, " Moribund");
444*c65cf52cSDavid du Colombier 	if(s = FIELD(Thread, t, cmdname)){
445*c65cf52cSDavid du Colombier 		fmtprint(&fmt, " [%s]", debugstr(s));
446*c65cf52cSDavid du Colombier 	}
447*c65cf52cSDavid du Colombier 
448*c65cf52cSDavid du Colombier 	fmtbufflush(&fmt);
449*c65cf52cSDavid du Colombier 	return buf;
450*c65cf52cSDavid du Colombier }
451*c65cf52cSDavid du Colombier 
452*c65cf52cSDavid du Colombier 
453*c65cf52cSDavid du Colombier static void
454*c65cf52cSDavid du Colombier thread(ulong t)
455*c65cf52cSDavid du Colombier {
456*c65cf52cSDavid du Colombier 	dprint("%s\n", threadfmt(t));
457*c65cf52cSDavid du Colombier }
458*c65cf52cSDavid du Colombier 
459*c65cf52cSDavid du Colombier static void
460*c65cf52cSDavid du Colombier threadapply(ulong p, void (*fn)(ulong))
461*c65cf52cSDavid du Colombier {
462*c65cf52cSDavid du Colombier 	int oldpid, pid;
463*c65cf52cSDavid du Colombier 	ulong tq, t;
464*c65cf52cSDavid du Colombier 
465*c65cf52cSDavid du Colombier 	oldpid = debug.pid;
466*c65cf52cSDavid du Colombier 	pid = FIELD(Proc, p, pid);
467*c65cf52cSDavid du Colombier 	if(map(pid) == nil)
468*c65cf52cSDavid du Colombier 		return;
469*c65cf52cSDavid du Colombier 	tq = FADDR(Proc, p, threads);
470*c65cf52cSDavid du Colombier 	t = FIELD(Tqueue, tq, head);
471*c65cf52cSDavid du Colombier 	while(t != 0){
472*c65cf52cSDavid du Colombier 		fn(t);
473*c65cf52cSDavid du Colombier 		t = FIELD(Thread, t, nextt);
474*c65cf52cSDavid du Colombier 	}
475*c65cf52cSDavid du Colombier 	map(oldpid);
476*c65cf52cSDavid du Colombier }
477*c65cf52cSDavid du Colombier 
478*c65cf52cSDavid du Colombier static void
479*c65cf52cSDavid du Colombier pthreads1(ulong t)
480*c65cf52cSDavid du Colombier {
481*c65cf52cSDavid du Colombier 	dprint("\t");
482*c65cf52cSDavid du Colombier 	thread(t);
483*c65cf52cSDavid du Colombier }
484*c65cf52cSDavid du Colombier 
485*c65cf52cSDavid du Colombier static void
486*c65cf52cSDavid du Colombier pthreads(ulong p)
487*c65cf52cSDavid du Colombier {
488*c65cf52cSDavid du Colombier 	threadapply(p, pthreads1);
489*c65cf52cSDavid du Colombier }
490*c65cf52cSDavid du Colombier 
491*c65cf52cSDavid du Colombier static void
492*c65cf52cSDavid du Colombier lproc(ulong p)
493*c65cf52cSDavid du Colombier {
494*c65cf52cSDavid du Colombier 	proc(p);
495*c65cf52cSDavid du Colombier 	pthreads(p);
496*c65cf52cSDavid du Colombier }
497*c65cf52cSDavid du Colombier 
498*c65cf52cSDavid du Colombier static void
499*c65cf52cSDavid du Colombier procapply(void (*fn)(ulong))
500*c65cf52cSDavid du Colombier {
501*c65cf52cSDavid du Colombier 	ulong proc;
502*c65cf52cSDavid du Colombier 	ulong pq;
503*c65cf52cSDavid du Colombier 
504*c65cf52cSDavid du Colombier 	pq = resolvev("_threadpq");
505*c65cf52cSDavid du Colombier 	if(pq == 0){
506*c65cf52cSDavid du Colombier 		dprint("no thread run queue\n");
507*c65cf52cSDavid du Colombier 		return;
508*c65cf52cSDavid du Colombier 	}
509*c65cf52cSDavid du Colombier 
510*c65cf52cSDavid du Colombier 	proc = FIELD(Pqueue, pq, head);
511*c65cf52cSDavid du Colombier 	while(proc){
512*c65cf52cSDavid du Colombier 		fn(proc);
513*c65cf52cSDavid du Colombier 		proc = FIELD(Proc, proc, next);
514*c65cf52cSDavid du Colombier 	}
515*c65cf52cSDavid du Colombier }
516*c65cf52cSDavid du Colombier 
517*c65cf52cSDavid du Colombier static void
518*c65cf52cSDavid du Colombier threads(HConnect *c)
519*c65cf52cSDavid du Colombier {
520*c65cf52cSDavid du Colombier 	USED(c);
521*c65cf52cSDavid du Colombier 	procapply(lproc);
522*c65cf52cSDavid du Colombier }
523*c65cf52cSDavid du Colombier 
524*c65cf52cSDavid du Colombier static void
525*c65cf52cSDavid du Colombier procs(HConnect *c)
526*c65cf52cSDavid du Colombier {
527*c65cf52cSDavid du Colombier 	USED(c);
528*c65cf52cSDavid du Colombier 	procapply(proc);
529*c65cf52cSDavid du Colombier }
530*c65cf52cSDavid du Colombier 
531*c65cf52cSDavid du Colombier static void
532*c65cf52cSDavid du Colombier threadstack(ulong t)
533*c65cf52cSDavid du Colombier {
534*c65cf52cSDavid du Colombier 	ulong pc, sp;
535*c65cf52cSDavid du Colombier 
536*c65cf52cSDavid du Colombier 	if(FIELD(Thread, t, state) == Running){
537*c65cf52cSDavid du Colombier 		stacktrace(debug.map);
538*c65cf52cSDavid du Colombier 	}else{
539*c65cf52cSDavid du Colombier 		// pc = FIELD(Thread, t, sched[JMPBUFPC]);
540*c65cf52cSDavid du Colombier 		pc = resolvef("longjmp");
541*c65cf52cSDavid du Colombier 		sp = FIELD(Thread, t, sched[JMPBUFSP]);
542*c65cf52cSDavid du Colombier 		stacktracepcsp(debug.map, pc, sp);
543*c65cf52cSDavid du Colombier 	}
544*c65cf52cSDavid du Colombier }
545*c65cf52cSDavid du Colombier 
546*c65cf52cSDavid du Colombier 
547*c65cf52cSDavid du Colombier static void
548*c65cf52cSDavid du Colombier tstacks(ulong t)
549*c65cf52cSDavid du Colombier {
550*c65cf52cSDavid du Colombier 	dprint("\t");
551*c65cf52cSDavid du Colombier 	thread(t);
552*c65cf52cSDavid du Colombier 	threadstack(t);
553*c65cf52cSDavid du Colombier 	dprint("\n");
554*c65cf52cSDavid du Colombier }
555*c65cf52cSDavid du Colombier 
556*c65cf52cSDavid du Colombier static void
557*c65cf52cSDavid du Colombier pstacks(ulong p)
558*c65cf52cSDavid du Colombier {
559*c65cf52cSDavid du Colombier 	proc(p);
560*c65cf52cSDavid du Colombier 	threadapply(p, tstacks);
561*c65cf52cSDavid du Colombier }
562*c65cf52cSDavid du Colombier 
563*c65cf52cSDavid du Colombier static void
564*c65cf52cSDavid du Colombier stacks(HConnect *c)
565*c65cf52cSDavid du Colombier {
566*c65cf52cSDavid du Colombier 	USED(c);
567*c65cf52cSDavid du Colombier 	debug.stkprefix = "\t\t";
568*c65cf52cSDavid du Colombier 	procapply(pstacks);
569*c65cf52cSDavid du Colombier 	debug.stkprefix = "";
570*c65cf52cSDavid du Colombier }
571*c65cf52cSDavid du Colombier 
572*c65cf52cSDavid du Colombier static void
573*c65cf52cSDavid du Colombier symbols(HConnect *c)
574*c65cf52cSDavid du Colombier {
575*c65cf52cSDavid du Colombier 	USED(c);
576*c65cf52cSDavid du Colombier 	printsym();
577*c65cf52cSDavid du Colombier }
578*c65cf52cSDavid du Colombier 
579*c65cf52cSDavid du Colombier static void
580*c65cf52cSDavid du Colombier segments(HConnect *c)
581*c65cf52cSDavid du Colombier {
582*c65cf52cSDavid du Colombier 	USED(c);
583*c65cf52cSDavid du Colombier 	printmap("segments", debug.map);
584*c65cf52cSDavid du Colombier }
585*c65cf52cSDavid du Colombier 
586*c65cf52cSDavid du Colombier static void
587*c65cf52cSDavid du Colombier fds(HConnect *c)
588*c65cf52cSDavid du Colombier {
589*c65cf52cSDavid du Colombier 	USED(c);
590*c65cf52cSDavid du Colombier 	openfiles();
591*c65cf52cSDavid du Colombier }
592*c65cf52cSDavid du Colombier 
593*c65cf52cSDavid du Colombier static void
594*c65cf52cSDavid du Colombier all(HConnect *c)
595*c65cf52cSDavid du Colombier {
596*c65cf52cSDavid du Colombier 	dprint("/proc/segment\n");
597*c65cf52cSDavid du Colombier 	segments(c);
598*c65cf52cSDavid du Colombier 	dprint("\n/proc/fd\n");
599*c65cf52cSDavid du Colombier 	fds(c);
600*c65cf52cSDavid du Colombier 	dprint("\n/proc/procs\n");
601*c65cf52cSDavid du Colombier 	procs(c);
602*c65cf52cSDavid du Colombier 	dprint("\n/proc/threads\n");
603*c65cf52cSDavid du Colombier 	threads(c);
604*c65cf52cSDavid du Colombier 	dprint("\n/proc/stacks\n");
605*c65cf52cSDavid du Colombier 	stacks(c);
606*c65cf52cSDavid du Colombier 	dprint("\n# /proc/symbols\n");
607*c65cf52cSDavid du Colombier 	// symbols(c);
608*c65cf52cSDavid du Colombier }
609*c65cf52cSDavid du Colombier 
610*c65cf52cSDavid du Colombier int
611*c65cf52cSDavid du Colombier hproc(HConnect *c)
612*c65cf52cSDavid du Colombier {
613*c65cf52cSDavid du Colombier 	void (*fn)(HConnect*);
614*c65cf52cSDavid du Colombier 	static char buf[65536];
615*c65cf52cSDavid du Colombier 	Fmt fmt;
616*c65cf52cSDavid du Colombier 
617*c65cf52cSDavid du Colombier 	if(strcmp(c->req.uri, "/proc/all") == 0)
618*c65cf52cSDavid du Colombier 		fn = all;
619*c65cf52cSDavid du Colombier 	else if(strcmp(c->req.uri, "/proc/segment") == 0)
620*c65cf52cSDavid du Colombier 		fn = segments;
621*c65cf52cSDavid du Colombier 	else if(strcmp(c->req.uri, "/proc/fd") == 0)
622*c65cf52cSDavid du Colombier 		fn = fds;
623*c65cf52cSDavid du Colombier 	else if(strcmp(c->req.uri, "/proc/procs") == 0)
624*c65cf52cSDavid du Colombier 		fn = procs;
625*c65cf52cSDavid du Colombier 	else if(strcmp(c->req.uri, "/proc/threads") == 0)
626*c65cf52cSDavid du Colombier 		fn = threads;
627*c65cf52cSDavid du Colombier 	else if(strcmp(c->req.uri, "/proc/stacks") == 0)
628*c65cf52cSDavid du Colombier 		fn = stacks;
629*c65cf52cSDavid du Colombier 	else if(strcmp(c->req.uri, "/proc/symbols") == 0)
630*c65cf52cSDavid du Colombier 		fn = symbols;
631*c65cf52cSDavid du Colombier 	else
632*c65cf52cSDavid du Colombier 		return hnotfound(c);
633*c65cf52cSDavid du Colombier 
634*c65cf52cSDavid du Colombier 	if(hsettext(c) < 0)
635*c65cf52cSDavid du Colombier 		return -1;
636*c65cf52cSDavid du Colombier 	if(!canqlock(&debug.lock)){
637*c65cf52cSDavid du Colombier 		hprint(&c->hout, "debugger is busy\n");
638*c65cf52cSDavid du Colombier 		return 0;
639*c65cf52cSDavid du Colombier 	}
640*c65cf52cSDavid du Colombier 	if(debug.textfd < 0){
641*c65cf52cSDavid du Colombier 		if(text(getpid()) < 0){
642*c65cf52cSDavid du Colombier 			hprint(&c->hout, "cannot attach self text: %r\n");
643*c65cf52cSDavid du Colombier 			goto out;
644*c65cf52cSDavid du Colombier 		}
645*c65cf52cSDavid du Colombier 	}
646*c65cf52cSDavid du Colombier 	if(map(getpid()) == nil){
647*c65cf52cSDavid du Colombier 		hprint(&c->hout, "cannot map self: %r\n");
648*c65cf52cSDavid du Colombier 		goto out;
649*c65cf52cSDavid du Colombier 	}
650*c65cf52cSDavid du Colombier 
651*c65cf52cSDavid du Colombier 	fmtbufinit(&fmt, buf, sizeof buf);
652*c65cf52cSDavid du Colombier 	debug.fmt = &fmt;
653*c65cf52cSDavid du Colombier 	fn(c);
654*c65cf52cSDavid du Colombier 	hprint(&c->hout, "%s\n", fmtbufflush(&fmt));
655*c65cf52cSDavid du Colombier 	debug.fmt = nil;
656*c65cf52cSDavid du Colombier out:
657*c65cf52cSDavid du Colombier 	qunlock(&debug.lock);
658*c65cf52cSDavid du Colombier 	return 0;
659*c65cf52cSDavid du Colombier }
660