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