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