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