1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "error.h"
7 #include <interp.h>
8 #include <isa.h>
9 #include "runt.h"
10
11 /*
12 * Enable the heap device for environments that allow debugging =>
13 * Must be 1 for a production environment.
14 */
15 int SECURE = 0;
16
17 enum
18 {
19 Qdir,
20 Qctl,
21 Qdbgctl,
22 Qheap,
23 Qns,
24 Qnsgrp,
25 Qpgrp,
26 Qstack,
27 Qstatus,
28 Qtext,
29 Qwait,
30 Qfd,
31 Qexception,
32 };
33
34 /*
35 * must be in same order as enum
36 */
37 Dirtab progdir[] =
38 {
39 "ctl", {Qctl}, 0, 0200,
40 "dbgctl", {Qdbgctl}, 0, 0600,
41 "heap", {Qheap}, 0, 0600,
42 "ns", {Qns}, 0, 0400,
43 "nsgrp", {Qnsgrp}, 0, 0444,
44 "pgrp", {Qpgrp}, 0, 0444,
45 "stack", {Qstack}, 0, 0400,
46 "status", {Qstatus}, 0, 0444,
47 "text", {Qtext}, 0, 0000,
48 "wait", {Qwait}, 0, 0400,
49 "fd", {Qfd}, 0, 0400,
50 "exception", {Qexception}, 0, 0400,
51 };
52
53 enum
54 {
55 CMkill,
56 CMkillgrp,
57 CMrestricted,
58 CMexceptions,
59 CMprivate
60 };
61
62 static
63 Cmdtab progcmd[] = {
64 CMkill, "kill", 1,
65 CMkillgrp, "killgrp", 1,
66 CMrestricted, "restricted", 1,
67 CMexceptions, "exceptions", 2,
68 CMprivate, "private", 1,
69 };
70
71 enum
72 {
73 CDstep,
74 CDtoret,
75 CDcont,
76 CDstart,
77 CDstop,
78 CDunstop,
79 CDmaim,
80 CDbpt
81 };
82
83 static
84 Cmdtab progdbgcmd[] = {
85 CDstep, "step", 0, /* known below to be first, to cope with stepN */
86 CDtoret, "toret", 1,
87 CDcont, "cont", 1,
88 CDstart, "start", 1,
89 CDstop, "stop", 1,
90 CDunstop, "unstop", 1,
91 CDmaim, "maim", 1,
92 CDbpt, "bpt", 4,
93 };
94
95 typedef struct Heapqry Heapqry;
96 struct Heapqry
97 {
98 char fmt;
99 ulong addr;
100 ulong module;
101 int count;
102 };
103
104 typedef struct Bpt Bpt;
105
106 struct Bpt
107 {
108 Bpt *next;
109 int pc;
110 char *file;
111 char path[1];
112 };
113
114 typedef struct Progctl Progctl;
115 struct Progctl
116 {
117 Rendez r;
118 int ref;
119 Proc *debugger; /* waiting for dbgxec */
120 char *msg; /* reply from dbgxec */
121 int step; /* instructions to try */
122 int stop; /* stop running the program */
123 Bpt* bpts; /* active breakpoints */
124 Queue* q; /* status queue */
125 };
126
127 #define QSHIFT 4 /* location in qid of pid */
128 #define QID(q) (((ulong)(q).path&0x0000000F)>>0)
129 #define QPID(pid) (((pid)<<QSHIFT))
130 #define PID(q) ((q).vers)
131 #define PATH(q) ((ulong)(q).path&~((1<<QSHIFT)-1))
132
133 static char *progstate[] = /* must correspond to include/interp.h */
134 {
135 "alt", /* blocked in alt instruction */
136 "send", /* waiting to send */
137 "recv", /* waiting to recv */
138 "debug", /* debugged */
139 "ready", /* ready to be scheduled */
140 "release", /* interpreter released */
141 "exiting", /* exit because of kill or error */
142 "broken", /* thread crashed */
143 };
144
145 static void dbgstep(Progctl*, Prog*, int);
146 static void dbgstart(Prog*);
147 static void freebpts(Bpt*);
148 static Bpt* delbpt(Bpt*, char*, int);
149 static Bpt* setbpt(Bpt*, char*, int);
150 static void mntscan(Mntwalk*, Pgrp*);
151 extern Type *Trdchan;
152 extern Type *Twrchan;
153 extern Module* modules;
154 static char Emisalign[] = "misaligned address";
155
156 static int
proggen(Chan * c,char * name,Dirtab * tab,int,int s,Dir * dp)157 proggen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp)
158 {
159 Qid qid;
160 Prog *p;
161 char *e;
162 Osenv *o;
163 ulong pid, path, perm, len;
164
165 if(s == DEVDOTDOT){
166 mkqid(&qid, Qdir, 0, QTDIR);
167 devdir(c, qid, "#p", 0, eve, DMDIR|0555, dp);
168 return 1;
169 }
170
171 if((ulong)c->qid.path == Qdir) {
172 if(name != nil){
173 /* ignore s and use name to find pid */
174 pid = strtoul(name, &e, 0);
175 if(pid == 0 || *e != '\0')
176 return -1;
177 acquire();
178 p = progpid(pid);
179 if(p == nil){
180 release();
181 return -1;
182 }
183 }else{
184 acquire();
185 p = progn(s);
186 if(p == nil) {
187 release();
188 return -1;
189 }
190 pid = p->pid;
191 }
192 o = p->osenv;
193 sprint(up->genbuf, "%lud", pid);
194 if(name != nil && strcmp(name, up->genbuf) != 0){
195 release();
196 return -1;
197 }
198 mkqid(&qid, pid<<QSHIFT, pid, QTDIR);
199 devdir(c, qid, up->genbuf, 0, o->user, DMDIR|0555, dp);
200 release();
201 return 1;
202 }
203
204 if(s >= nelem(progdir))
205 return -1;
206 tab = &progdir[s];
207 path = PATH(c->qid);
208
209 acquire();
210 p = progpid(PID(c->qid));
211 if(p == nil) {
212 release();
213 return -1;
214 }
215
216 o = p->osenv;
217
218 perm = tab->perm;
219 if((perm & 7) == 0)
220 perm = (perm|(perm>>3)|(perm>>6)) & o->pgrp->progmode;
221
222 len = tab->length;
223 mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE);
224 devdir(c, qid, tab->name, len, o->user, perm, dp);
225 release();
226 return 1;
227 }
228
229 static Chan*
progattach(char * spec)230 progattach(char *spec)
231 {
232 return devattach('p', spec);
233 }
234
235 static Walkqid*
progwalk(Chan * c,Chan * nc,char ** name,int nname)236 progwalk(Chan *c, Chan *nc, char **name, int nname)
237 {
238 return devwalk(c, nc, name, nname, 0, 0, proggen);
239 }
240
241 static int
progstat(Chan * c,uchar * db,int n)242 progstat(Chan *c, uchar *db, int n)
243 {
244 return devstat(c, db, n, 0, 0, proggen);
245 }
246
247 static Chan*
progopen(Chan * c,int omode)248 progopen(Chan *c, int omode)
249 {
250 Prog *p;
251 Osenv *o;
252 Progctl *ctl;
253 int perm;
254
255 if(c->qid.type & QTDIR)
256 return devopen(c, omode, 0, 0, proggen);
257
258 acquire();
259 if (waserror()) {
260 release();
261 nexterror();
262 }
263 p = progpid(PID(c->qid));
264 if(p == nil)
265 error(Ethread);
266
267 o = p->osenv;
268 perm = progdir[QID(c->qid)-1].perm;
269 if((perm & 7) == 0)
270 perm = (perm|(perm>>3)|(perm>>6)) & o->pgrp->progmode;
271 devpermcheck(o->user, perm, omode);
272 omode = openmode(omode);
273
274 switch(QID(c->qid)){
275 default:
276 error(Egreg);
277 case Qnsgrp:
278 case Qpgrp:
279 case Qtext:
280 case Qstatus:
281 case Qstack:
282 case Qctl:
283 case Qfd:
284 case Qexception:
285 break;
286 case Qwait:
287 c->aux = qopen(1024, Qmsg, nil, nil);
288 if(c->aux == nil)
289 error(Enomem);
290 o->childq = c->aux;
291 break;
292 case Qns:
293 c->aux = malloc(sizeof(Mntwalk));
294 if(c->aux == nil)
295 error(Enomem);
296 break;
297 case Qheap:
298 if(SECURE || p->group->flags&Pprivatemem || omode != ORDWR)
299 error(Eperm);
300 c->aux = malloc(sizeof(Heapqry));
301 if(c->aux == nil)
302 error(Enomem);
303 break;
304 case Qdbgctl:
305 if(SECURE || p->group->flags&Pprivatemem || omode != ORDWR)
306 error(Eperm);
307 ctl = malloc(sizeof(Progctl));
308 if(ctl == nil)
309 error(Enomem);
310 ctl->q = qopen(1024, Qmsg, nil, nil);
311 if(ctl->q == nil) {
312 free(ctl);
313 error(Enomem);
314 }
315 ctl->bpts = nil;
316 ctl->ref = 1;
317 c->aux = ctl;
318 break;
319 }
320 if(p->state != Pexiting)
321 c->qid.vers = p->pid;
322
323 poperror();
324 release();
325 c->offset = 0;
326 c->mode = omode;
327 c->flag |= COPEN;
328 return c;
329 }
330
331 static int
progwstat(Chan * c,uchar * db,int n)332 progwstat(Chan *c, uchar *db, int n)
333 {
334 Dir d;
335 Prog *p;
336 char *u;
337 Osenv *o;
338
339 if(c->qid.type&QTDIR)
340 error(Eperm);
341 acquire();
342 p = progpid(PID(c->qid));
343 if(p == nil) {
344 release();
345 error(Ethread);
346 }
347
348 u = up->env->user;
349 o = p->osenv;
350 if(strcmp(u, o->user) != 0 && strcmp(u, eve) != 0) {
351 release();
352 error(Eperm);
353 }
354
355 n = convM2D(db, n, &d, nil);
356 if(n == 0){
357 release();
358 error(Eshortstat);
359 }
360 if(d.mode != ~0UL)
361 o->pgrp->progmode = d.mode&0777;
362 release();
363 return n;
364 }
365
366 static void
closedbgctl(Progctl * ctl,Prog * p)367 closedbgctl(Progctl *ctl, Prog *p)
368 {
369 Osenv *o;
370
371 if(ctl->ref-- > 1)
372 return;
373 freebpts(ctl->bpts);
374 if(p != nil){
375 o = p->osenv;
376 if(o->debug == ctl){
377 o->debug = nil;
378 p->xec = xec;
379 }
380 }
381 qfree(ctl->q);
382 free(ctl);
383 }
384
385 static void
progclose(Chan * c)386 progclose(Chan *c)
387 {
388 int i;
389 Prog *f;
390 Osenv *o;
391 Progctl *ctl;
392
393 switch(QID(c->qid)) {
394 case Qns:
395 case Qheap:
396 free(c->aux);
397 break;
398 case Qdbgctl:
399 if((c->flag & COPEN) == 0)
400 return;
401 ctl = c->aux;
402 acquire();
403 closedbgctl(ctl, progpid(PID(c->qid)));
404 release();
405 break;
406 case Qwait:
407 acquire();
408 i = 0;
409 for(;;) {
410 f = progn(i++);
411 if(f == nil)
412 break;
413 o = f->osenv;
414 if(o->waitq == c->aux)
415 o->waitq = nil;
416 if(o->childq == c->aux)
417 o->childq = nil;
418 }
419 release();
420 qfree(c->aux);
421 }
422 }
423
424 static int
progsize(Prog * p)425 progsize(Prog *p)
426 {
427 int size;
428 Frame *f;
429 uchar *fp;
430 Modlink *m;
431
432 m = p->R.M;
433 size = 0;
434 if(m->MP != H)
435 size += hmsize(D2H(m->MP));
436 if(m->prog != nil)
437 size += msize(m->prog);
438
439 fp = p->R.FP;
440 while(fp != nil) {
441 f = (Frame*)fp;
442 fp = f->fp;
443 if(f->mr != nil) {
444 if(f->mr->MP != H)
445 size += hmsize(D2H(f->mr->MP));
446 if(f->mr->prog != nil)
447 size += msize(f->mr->prog);
448 }
449 if(f->t == nil)
450 size += msize(SEXTYPE(f));
451 }
452 return size/1024;
453 }
454
455 static long
progoffset(long offset,char * va,int * np)456 progoffset(long offset, char *va, int *np)
457 {
458 if(offset > 0) {
459 offset -= *np;
460 if(offset < 0) {
461 memmove(va, va+*np+offset, -offset);
462 *np = -offset;
463 }
464 else
465 *np = 0;
466 }
467 return offset;
468 }
469
470 static int
progqidwidth(Chan * c)471 progqidwidth(Chan *c)
472 {
473 char buf[32];
474
475 return sprint(buf, "%lud", c->qid.vers);
476 }
477
478 int
progfdprint(Chan * c,int fd,int w,char * s,int ns)479 progfdprint(Chan *c, int fd, int w, char *s, int ns)
480 {
481 int n;
482
483 if(w == 0)
484 w = progqidwidth(c);
485 n = snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %*lud %.2ux) %5ld %8lld %s\n",
486 fd,
487 &"r w rw"[(c->mode&3)<<1],
488 devtab[c->type]->dc, c->dev,
489 c->qid.path, w, c->qid.vers, c->qid.type,
490 c->iounit, c->offset, c->name->s);
491 return n;
492 }
493
494 static int
progfds(Osenv * o,char * va,int count,long offset)495 progfds(Osenv *o, char *va, int count, long offset)
496 {
497 Fgrp *f;
498 Chan *c;
499 int n, i, w, ww;
500
501 f = o->fgrp; /* f is not locked because we've acquired */
502 n = readstr(0, va, count, o->pgrp->dot->name->s);
503 n += snprint(va+n, count-n, "\n");
504 offset = progoffset(offset, va, &n);
505 /* compute width of qid.path */
506 w = 0;
507 for(i = 0; i <= f->maxfd; i++) {
508 c = f->fd[i];
509 if(c == nil)
510 continue;
511 ww = progqidwidth(c);
512 if(ww > w)
513 w = ww;
514 }
515 for(i = 0; i <= f->maxfd; i++) {
516 c = f->fd[i];
517 if(c == nil)
518 continue;
519 n += progfdprint(c, i, w, va+n, count-n);
520 offset = progoffset(offset, va, &n);
521 }
522 return n;
523 }
524
525 Inst *
pc2dispc(Inst * pc,Module * mod)526 pc2dispc(Inst *pc, Module *mod)
527 {
528 ulong l, u, m, v;
529 ulong *tab = mod->pctab;
530
531 v = (ulong)pc - (ulong)mod->prog;
532 l = 0;
533 u = mod->nprog-1;
534 while(l < u){
535 m = (l+u+1)/2;
536 if(tab[m] < v)
537 l = m;
538 else if(tab[m] > v)
539 u = m-1;
540 else
541 l = u = m;
542 }
543 if(l == u && tab[u] <= v && u != mod->nprog-1 && tab[u+1] > v)
544 return &mod->prog[u];
545 return 0;
546 }
547
548 static int
progstack(REG * reg,int state,char * va,int count,long offset)549 progstack(REG *reg, int state, char *va, int count, long offset)
550 {
551 int n;
552 Frame *f;
553 Inst *pc;
554 uchar *fp;
555 Modlink *m;
556
557 n = 0;
558 m = reg->M;
559 fp = reg->FP;
560 pc = reg->PC;
561
562 /*
563 * all states other than debug and ready block,
564 * but interp has already advanced the PC
565 */
566 if(!m->compiled && state != Pready && state != Pdebug && pc > m->prog)
567 pc--;
568 if(m->compiled && m->m->pctab != nil)
569 pc = pc2dispc(pc, m->m);
570
571 while(fp != nil) {
572 f = (Frame*)fp;
573 n += snprint(va+n, count-n, "%.8lux %.8lux %.8lux %.8lux %d %s\n",
574 (ulong)f, /* FP */
575 (ulong)(pc - m->prog), /* PC in dis instructions */
576 (ulong)m->MP, /* MP */
577 (ulong)m->prog, /* Code for module */
578 m->compiled && m->m->pctab == nil, /* True if native assembler: fool stack utility for now */
579 m->m->path); /* File system path */
580
581 if(offset > 0) {
582 offset -= n;
583 if(offset < 0) {
584 memmove(va, va+n+offset, -offset);
585 n = -offset;
586 }
587 else
588 n = 0;
589 }
590
591 pc = f->lr;
592 fp = f->fp;
593 if(f->mr != nil)
594 m = f->mr;
595 if(!m->compiled)
596 pc--;
597 else if(m->m->pctab != nil)
598 pc = pc2dispc(pc, m->m)-1;
599 }
600 return n;
601 }
602
603 static int
calldepth(REG * reg)604 calldepth(REG *reg)
605 {
606 int n;
607 uchar *fp;
608
609 n = 0;
610 for(fp = reg->FP; fp != nil; fp = ((Frame*)fp)->fp)
611 n++;
612 return n;
613 }
614
615 static int
progheap(Heapqry * hq,char * va,int count,ulong offset)616 progheap(Heapqry *hq, char *va, int count, ulong offset)
617 {
618 WORD *w;
619 void *p;
620 List *hd;
621 Array *a;
622 char *fmt, *str;
623 Module *m;
624 Modlink *ml;
625 Channel *c;
626 ulong addr;
627 String *ss;
628 union { REAL r; LONG l; WORD w[2]; } rock;
629 int i, s, n, len, signed_off;
630 Type *t;
631
632 n = 0;
633 s = 0;
634 signed_off = offset;
635 addr = hq->addr;
636 for(i = 0; i < hq->count; i++) {
637 switch(hq->fmt) {
638 case 'W':
639 if(addr & 3)
640 return -1;
641 n += snprint(va+n, count-n, "%d\n", *(WORD*)addr);
642 s = sizeof(WORD);
643 break;
644 case 'B':
645 n += snprint(va+n, count-n, "%d\n", *(BYTE*)addr);
646 s = sizeof(BYTE);
647 break;
648 case 'V':
649 if(addr & 3)
650 return -1;
651 w = (WORD*)addr;
652 rock.w[0] = w[0];
653 rock.w[1] = w[1];
654 n += snprint(va+n, count-n, "%lld\n", rock.l);
655 s = sizeof(LONG);
656 break;
657 case 'R':
658 if(addr & 3)
659 return -1;
660 w = (WORD*)addr;
661 rock.w[0] = w[0];
662 rock.w[1] = w[1];
663 n += snprint(va+n, count-n, "%g\n", rock.r);
664 s = sizeof(REAL);
665 break;
666 case 'I':
667 if(addr & 3)
668 return -1;
669 for(m = modules; m != nil; m = m->link)
670 if(m == (Module*)hq->module)
671 break;
672 if(m == nil)
673 error(Ebadctl);
674 addr = (ulong)(m->prog+addr);
675 n += snprint(va+n, count-n, "%D\n", (Inst*)addr);
676 s = sizeof(Inst);
677 break;
678 case 'P':
679 if(addr & 3)
680 return -1;
681 p = *(void**)addr;
682 fmt = "nil\n";
683 if(p != H)
684 fmt = "%lux\n";
685 n += snprint(va+n, count-n, fmt, p);
686 s = sizeof(WORD);
687 break;
688 case 'L':
689 if(addr & 3)
690 return -1;
691 hd = *(List**)addr;
692 if(hd == H || D2H(hd)->t != &Tlist)
693 return -1;
694 n += snprint(va+n, count-n, "%lux.%lux\n", (ulong)&hd->tail, (ulong)hd->data);
695 s = sizeof(WORD);
696 break;
697 case 'A':
698 if(addr & 3)
699 return -1;
700 a = *(Array**)addr;
701 if(a == H)
702 n += snprint(va+n, count-n, "nil\n");
703 else {
704 if(D2H(a)->t != &Tarray)
705 return -1;
706 n += snprint(va+n, count-n, "%d.%lux\n", a->len, (ulong)a->data);
707 }
708 s = sizeof(WORD);
709 break;
710 case 'C':
711 if(addr & 3)
712 return -1;
713 ss = *(String**)addr;
714 if(ss == H)
715 ss = &snil;
716 else
717 if(D2H(ss)->t != &Tstring)
718 return -1;
719 n += snprint(va+n, count-n, "%d.", abs(ss->len));
720 str = string2c(ss);
721 len = strlen(str);
722 if(count-n < len)
723 len = count-n;
724 if(len > 0) {
725 memmove(va+n, str, len);
726 n += len;
727 }
728 break;
729 case 'M':
730 if(addr & 3)
731 return -1;
732 ml = *(Modlink**)addr;
733 fmt = ml == H ? "nil\n" : "%lux\n";
734 n += snprint(va+n, count-n, fmt, ml->MP);
735 s = sizeof(WORD);
736 break;
737 case 'c':
738 if(addr & 3)
739 return -1;
740 c = *(Channel**)addr;
741 if(c == H)
742 n += snprint(va+n, count-n, "nil\n");
743 else{
744 t = D2H(c)->t;
745 if(t != &Tchannel && t != Trdchan && t != Twrchan)
746 return -1;
747 if(c->buf == H)
748 n += snprint(va+n, count-n, "0.%lux\n", (ulong)c);
749 else
750 n += snprint(va+n, count-n, "%d.%lux.%d.%d\n", c->buf->len, (ulong)c->buf->data, c->front, c->size);
751 }
752 break;
753
754 }
755 addr += s;
756 if(signed_off > 0) {
757 signed_off -= n;
758 if(signed_off < 0) {
759 memmove(va, va+n+signed_off, -signed_off);
760 n = -signed_off;
761 }
762 else
763 n = 0;
764 }
765 }
766 return n;
767 }
768
769 WORD
modstatus(REG * r,char * ptr,int len)770 modstatus(REG *r, char *ptr, int len)
771 {
772 Inst *PC;
773 Frame *f;
774
775 if(r->M->m->name[0] == '$') {
776 f = (Frame*)r->FP;
777 snprint(ptr, len, "%s[%s]", f->mr->m->name, r->M->m->name);
778 if(f->mr->compiled)
779 return (WORD)f->lr;
780 return f->lr - f->mr->prog;
781 }
782 memmove(ptr, r->M->m->name, len);
783 if(r->M->compiled)
784 return (WORD)r->PC;
785 PC = r->PC;
786 /* should really check for blocked states */
787 if(PC > r->M->prog)
788 PC--;
789 return PC - r->M->prog;
790 }
791
792 static void
int2flag(int flag,char * s)793 int2flag(int flag, char *s)
794 {
795 if(flag == 0){
796 *s = '\0';
797 return;
798 }
799 *s++ = '-';
800 if(flag & MAFTER)
801 *s++ = 'a';
802 if(flag & MBEFORE)
803 *s++ = 'b';
804 if(flag & MCREATE)
805 *s++ = 'c';
806 if(flag & MCACHE)
807 *s++ = 'C';
808 *s = '\0';
809 }
810
811 static char*
progtime(ulong msec,char * buf,char * ebuf)812 progtime(ulong msec, char *buf, char *ebuf)
813 {
814 int tenths, sec;
815
816 tenths = msec/100;
817 sec = tenths/10;
818 seprint(buf, ebuf, "%4d:%2.2d.%d", sec/60, sec%60, tenths%10);
819 return buf;
820 }
821
822 static long
progread(Chan * c,void * va,long n,vlong offset)823 progread(Chan *c, void *va, long n, vlong offset)
824 {
825 int i;
826 Prog *p;
827 Osenv *o;
828 Mntwalk *mw;
829 ulong grpid;
830 char *a = va;
831 Progctl *ctl;
832 char mbuf[64], timebuf[12];
833 char flag[10];
834
835 if(c->qid.type & QTDIR)
836 return devdirread(c, a, n, 0, 0, proggen);
837
838 switch(QID(c->qid)){
839 case Qdbgctl:
840 ctl = c->aux;
841 return qread(ctl->q, va, n);
842 case Qstatus:
843 acquire();
844 p = progpid(PID(c->qid));
845 if(p == nil || p->state == Pexiting || p->R.M == H) {
846 release();
847 snprint(up->genbuf, sizeof(up->genbuf), "%8lud %8d %10s %s %10s %5dK %s",
848 PID(c->qid),
849 0,
850 eve,
851 progtime(0, timebuf, timebuf+sizeof(timebuf)),
852 progstate[Pexiting],
853 0,
854 "[$Sys]");
855 return readstr(offset, va, n, up->genbuf);
856 }
857 modstatus(&p->R, mbuf, sizeof(mbuf));
858 o = p->osenv;
859 snprint(up->genbuf, sizeof(up->genbuf), "%8d %8d %10s %s %10s %5dK %s",
860 p->pid,
861 p->group!=nil? p->group->id: 0,
862 o->user,
863 progtime(TK2MS(p->ticks), timebuf, timebuf+sizeof(timebuf)),
864 progstate[p->state],
865 progsize(p),
866 mbuf);
867 release();
868 return readstr(offset, va, n, up->genbuf);
869 case Qwait:
870 return qread(c->aux, va, n);
871 case Qns:
872 acquire();
873 if(waserror()){
874 release();
875 nexterror();
876 }
877 p = progpid(PID(c->qid));
878 if(p == nil)
879 error(Ethread);
880 mw = c->aux;
881 if(mw->cddone){
882 poperror();
883 release();
884 return 0;
885 }
886 o = p->osenv;
887 mntscan(mw, o->pgrp);
888 if(mw->mh == 0) {
889 mw->cddone = 1;
890 i = snprint(a, n, "cd %s\n", o->pgrp->dot->name->s);
891 poperror();
892 release();
893 return i;
894 }
895 int2flag(mw->cm->mflag, flag);
896 if(strcmp(mw->cm->to->name->s, "#M") == 0){
897 i = snprint(a, n, "mount %s %s %s %s\n", flag,
898 mw->cm->to->mchan->name->s,
899 mw->mh->from->name->s, mw->cm->spec? mw->cm->spec : "");
900 }else
901 i = snprint(a, n, "bind %s %s %s\n", flag,
902 mw->cm->to->name->s, mw->mh->from->name->s);
903 poperror();
904 release();
905 return i;
906 case Qnsgrp:
907 acquire();
908 p = progpid(PID(c->qid));
909 if(p == nil) {
910 release();
911 error(Ethread);
912 }
913 grpid = ((Osenv *)p->osenv)->pgrp->pgrpid;
914 release();
915 return readnum(offset, va, n, grpid, NUMSIZE);
916 case Qpgrp:
917 acquire();
918 p = progpid(PID(c->qid));
919 if(p == nil) {
920 release();
921 error(Ethread);
922 }
923 grpid = p->group!=nil? p->group->id: 0;
924 release();
925 return readnum(offset, va, n, grpid, NUMSIZE);
926 case Qstack:
927 acquire();
928 p = progpid(PID(c->qid));
929 if(p == nil || p->state == Pexiting) {
930 release();
931 error(Ethread);
932 }
933 if(p->state == Pready) {
934 release();
935 error(Estopped);
936 }
937 n = progstack(&p->R, p->state, va, n, offset);
938 release();
939 return n;
940 case Qheap:
941 acquire();
942 if(waserror()){
943 release();
944 nexterror();
945 }
946 n = progheap(c->aux, va, n, offset);
947 if(n == -1)
948 error(Emisalign);
949 poperror();
950 release();
951 return n;
952 case Qfd:
953 acquire();
954 if(waserror()) {
955 release();
956 nexterror();
957 }
958 p = progpid(PID(c->qid));
959 if(p == nil)
960 error(Ethread);
961 o = p->osenv;
962 n = progfds(o, va, n, offset);
963 poperror();
964 release();
965 return n;
966 case Qexception:
967 acquire();
968 p = progpid(PID(c->qid));
969 if(p == nil) {
970 release();
971 error(Ethread);
972 }
973 if(p->exstr == nil)
974 up->genbuf[0] = 0;
975 else
976 snprint(up->genbuf, sizeof(up->genbuf), p->exstr);
977 release();
978 return readstr(offset, va, n, up->genbuf);
979 }
980 error(Egreg);
981 return 0;
982 }
983
984 static void
mntscan(Mntwalk * mw,Pgrp * pg)985 mntscan(Mntwalk *mw, Pgrp *pg)
986 {
987 Mount *t;
988 Mhead *f;
989 int nxt, i;
990 ulong last, bestmid;
991
992 rlock(&pg->ns);
993
994 nxt = 0;
995 bestmid = ~0;
996
997 last = 0;
998 if(mw->mh)
999 last = mw->cm->mountid;
1000
1001 for(i = 0; i < MNTHASH; i++) {
1002 for(f = pg->mnthash[i]; f; f = f->hash) {
1003 for(t = f->mount; t; t = t->next) {
1004 if(mw->mh == 0 ||
1005 (t->mountid > last && t->mountid < bestmid)) {
1006 mw->cm = t;
1007 mw->mh = f;
1008 bestmid = mw->cm->mountid;
1009 nxt = 1;
1010 }
1011 }
1012 }
1013 }
1014 if(nxt == 0)
1015 mw->mh = 0;
1016
1017 runlock(&pg->ns);
1018 }
1019
1020 static long
progwrite(Chan * c,void * va,long n,vlong offset)1021 progwrite(Chan *c, void *va, long n, vlong offset)
1022 {
1023 Prog *p, *f;
1024 Heapqry *hq;
1025 char buf[128];
1026 Progctl *ctl;
1027 char *b;
1028 int i, pc;
1029 Cmdbuf *cb;
1030 Cmdtab *ct;
1031
1032 USED(offset);
1033 USED(va);
1034
1035 if(c->qid.type & QTDIR)
1036 error(Eisdir);
1037
1038 acquire();
1039 if(waserror()) {
1040 release();
1041 nexterror();
1042 }
1043 p = progpid(PID(c->qid));
1044 if(p == nil)
1045 error(Ethread);
1046
1047 switch(QID(c->qid)){
1048 case Qctl:
1049 cb = parsecmd(va, n);
1050 if(waserror()){
1051 free(cb);
1052 nexterror();
1053 }
1054 ct = lookupcmd(cb, progcmd, nelem(progcmd));
1055 switch(ct->index){
1056 case CMkillgrp:
1057 killgrp(p, "killed");
1058 break;
1059 case CMkill:
1060 killprog(p, "killed");
1061 break;
1062 case CMrestricted:
1063 p->flags |= Prestrict;
1064 break;
1065 case CMexceptions:
1066 if(p->group->id != p->pid)
1067 error(Eperm);
1068 if(strcmp(cb->f[1], "propagate") == 0)
1069 p->flags |= Ppropagate;
1070 else if(strcmp(cb->f[1], "notifyleader") == 0)
1071 p->flags |= Pnotifyleader;
1072 else
1073 error(Ebadctl);
1074 break;
1075 case CMprivate:
1076 p->group->flags |= Pprivatemem;
1077 break;
1078 }
1079 poperror();
1080 free(cb);
1081 break;
1082 case Qdbgctl:
1083 cb = parsecmd(va, n);
1084 if(waserror()){
1085 free(cb);
1086 nexterror();
1087 }
1088 if(cb->nf == 1 && strncmp(cb->f[0], "step", 4) == 0)
1089 ct = progdbgcmd;
1090 else
1091 ct = lookupcmd(cb, progdbgcmd, nelem(progdbgcmd));
1092 switch(ct->index){
1093 case CDstep:
1094 if(cb->nf == 1)
1095 i = strtoul(cb->f[0]+4, nil, 0);
1096 else
1097 i = strtoul(cb->f[1], nil, 0);
1098 dbgstep(c->aux, p, i);
1099 break;
1100 case CDtoret:
1101 f = currun();
1102 i = calldepth(&p->R);
1103 while(f->kill == nil) {
1104 dbgstep(c->aux, p, 1024);
1105 if(i > calldepth(&p->R))
1106 break;
1107 }
1108 break;
1109 case CDcont:
1110 f = currun();
1111 while(f->kill == nil)
1112 dbgstep(c->aux, p, 1024);
1113 break;
1114 case CDstart:
1115 dbgstart(p);
1116 break;
1117 case CDstop:
1118 ctl = c->aux;
1119 ctl->stop = 1;
1120 break;
1121 case CDunstop:
1122 ctl = c->aux;
1123 ctl->stop = 0;
1124 break;
1125 case CDbpt:
1126 pc = strtoul(cb->f[3], nil, 10);
1127 ctl = c->aux;
1128 if(strcmp(cb->f[1], "set") == 0)
1129 ctl->bpts = setbpt(ctl->bpts, cb->f[2], pc);
1130 else if(strcmp(cb->f[1], "del") == 0)
1131 ctl->bpts = delbpt(ctl->bpts, cb->f[2], pc);
1132 else
1133 error(Ebadctl);
1134 break;
1135 case CDmaim:
1136 p->kill = "maim";
1137 break;
1138 }
1139 poperror();
1140 free(cb);
1141 break;
1142 case Qheap:
1143 /*
1144 * Heap query:
1145 * addr.Fn
1146 * pc+module.In
1147 */
1148 i = n;
1149 if(i > sizeof(buf)-1)
1150 i = sizeof(buf)-1;
1151 memmove(buf, va, i);
1152 buf[i] = '\0';
1153 hq = c->aux;
1154 hq->addr = strtoul(buf, &b, 0);
1155 if(*b == '+')
1156 hq->module = strtoul(b, &b, 0);
1157 if(*b++ != '.')
1158 error(Ebadctl);
1159 hq->fmt = *b++;
1160 hq->count = strtoul(b, nil, 0);
1161 break;
1162 default:
1163 print("unknown qid in procwrite\n");
1164 error(Egreg);
1165 }
1166 poperror();
1167 release();
1168 return n;
1169 }
1170
1171 static Bpt*
setbpt(Bpt * bpts,char * path,int pc)1172 setbpt(Bpt *bpts, char *path, int pc)
1173 {
1174 int n;
1175 Bpt *b;
1176
1177 n = strlen(path);
1178 b = mallocz(sizeof *b + n, 0);
1179 if(b == nil)
1180 return bpts;
1181 b->pc = pc;
1182 memmove(b->path, path, n+1);
1183 b->file = b->path;
1184 path = strrchr(b->path, '/');
1185 if(path != nil)
1186 b->file = path + 1;
1187 b->next = bpts;
1188 return b;
1189 }
1190
1191 static Bpt*
delbpt(Bpt * bpts,char * path,int pc)1192 delbpt(Bpt *bpts, char *path, int pc)
1193 {
1194 Bpt *b, **last;
1195
1196 last = &bpts;
1197 for(b = bpts; b != nil; b = b->next){
1198 if(b->pc == pc && strcmp(b->path, path) == 0) {
1199 *last = b->next;
1200 free(b);
1201 break;
1202 }
1203 last = &b->next;
1204 }
1205 return bpts;
1206 }
1207
1208 static void
freebpts(Bpt * b)1209 freebpts(Bpt *b)
1210 {
1211 Bpt *next;
1212
1213 for(; b != nil; b = next){
1214 next = b->next;
1215 free(b);
1216 }
1217 }
1218
1219 static void
telldbg(Progctl * ctl,char * msg)1220 telldbg(Progctl *ctl, char *msg)
1221 {
1222 kstrcpy(ctl->msg, msg, ERRMAX);
1223 ctl->debugger = nil;
1224 wakeup(&ctl->r);
1225 }
1226
1227 static void
dbgstart(Prog * p)1228 dbgstart(Prog *p)
1229 {
1230 Osenv *o;
1231 Progctl *ctl;
1232
1233 o = p->osenv;
1234 ctl = o->debug;
1235 if(ctl != nil && ctl->debugger != nil)
1236 error("prog debugged");
1237 if(p->state == Pdebug)
1238 addrun(p);
1239 o->debug = nil;
1240 p->xec = xec;
1241 }
1242
1243 static int
xecdone(void * vc)1244 xecdone(void *vc)
1245 {
1246 Progctl *ctl = vc;
1247
1248 return ctl->debugger == nil;
1249 }
1250
1251 static void
dbgstep(Progctl * vctl,Prog * p,int n)1252 dbgstep(Progctl *vctl, Prog *p, int n)
1253 {
1254 Osenv *o;
1255 Progctl *ctl;
1256 char buf[ERRMAX+20], *msg;
1257
1258 if(p == currun())
1259 error("cannot step yourself");
1260
1261 if(p->state == Pbroken)
1262 error("prog broken");
1263
1264 ctl = vctl;
1265 if(ctl->debugger != nil)
1266 error("prog already debugged");
1267
1268 o = p->osenv;
1269 if(o->debug == nil) {
1270 o->debug = ctl;
1271 p->xec = dbgxec;
1272 }else if(o->debug != ctl)
1273 error("prog already debugged");
1274
1275 ctl->step = n;
1276 if(p->state == Pdebug)
1277 addrun(p);
1278 ctl->debugger = up;
1279 strcpy(buf, "child: ");
1280 msg = buf+7;
1281 ctl->msg = msg;
1282
1283 /*
1284 * wait for reply from dbgxec; release is okay because prog is now
1285 * debugged, cannot exit.
1286 */
1287 if(waserror()){
1288 acquire();
1289 ctl->debugger = nil;
1290 ctl->msg = nil;
1291 o->debug = nil;
1292 p->xec = xec;
1293 nexterror();
1294 }
1295 release();
1296 sleep(&ctl->r, xecdone, ctl);
1297 poperror();
1298 acquire();
1299 if(msg[0] != '\0')
1300 error(buf);
1301 }
1302
1303 void
dbgexit(Prog * kid,int broken,char * estr)1304 dbgexit(Prog *kid, int broken, char *estr)
1305 {
1306 int n;
1307 Osenv *e;
1308 Progctl *ctl;
1309 char buf[ERRMAX+20];
1310
1311 e = kid->osenv;
1312 ctl = e->debug;
1313 e->debug = nil;
1314 kid->xec = xec;
1315
1316 if(broken)
1317 n = snprint(buf, sizeof(buf), "broken: %s", estr);
1318 else
1319 n = snprint(buf, sizeof(buf), "exited");
1320 if(ctl->debugger)
1321 telldbg(ctl, buf);
1322 qproduce(ctl->q, buf, n);
1323 }
1324
1325 static void
dbgaddrun(Prog * p)1326 dbgaddrun(Prog *p)
1327 {
1328 Osenv *o;
1329
1330 p->state = Pdebug;
1331 p->addrun = nil;
1332 o = p->osenv;
1333 if(o->rend != nil)
1334 wakeup(o->rend);
1335 o->rend = nil;
1336 }
1337
1338 static int
bdone(void * vp)1339 bdone(void *vp)
1340 {
1341 Prog *p = vp;
1342
1343 return p->addrun == nil;
1344 }
1345
1346 static void
dbgblock(Prog * p)1347 dbgblock(Prog *p)
1348 {
1349 Osenv *o;
1350 Progctl *ctl;
1351
1352 o = p->osenv;
1353 ctl = o->debug;
1354 qproduce(ctl->q, progstate[p->state], strlen(progstate[p->state]));
1355 pushrun(p);
1356 p->addrun = dbgaddrun;
1357 o->rend = &up->sleep;
1358
1359 /*
1360 * bdone(p) is safe after release because p is being debugged,
1361 * so cannot exit.
1362 */
1363 if(waserror()){
1364 acquire();
1365 nexterror();
1366 }
1367 release();
1368 if(o->rend != nil)
1369 sleep(o->rend, bdone, p);
1370 poperror();
1371 acquire();
1372 if(p->kill != nil)
1373 error(p->kill);
1374 ctl = o->debug;
1375 if(ctl != nil)
1376 qproduce(ctl->q, "run", 3);
1377 }
1378
1379 void
dbgxec(Prog * p)1380 dbgxec(Prog *p)
1381 {
1382 Bpt *b;
1383 Prog *kid;
1384 Osenv *env;
1385 Progctl *ctl;
1386 int op, pc, n;
1387 char buf[ERRMAX+10];
1388 extern void (*dec[])(void);
1389
1390 env = p->osenv;
1391 ctl = env->debug;
1392 ctl->ref++;
1393 if(waserror()){
1394 closedbgctl(ctl, p);
1395 nexterror();
1396 }
1397
1398 R = p->R;
1399 R.MP = R.M->MP;
1400
1401 R.IC = p->quanta;
1402 if((ulong)R.IC > ctl->step)
1403 R.IC = ctl->step;
1404 if(ctl->stop)
1405 R.IC = 0;
1406
1407
1408 buf[0] = '\0';
1409
1410 if(R.IC != 0 && R.M->compiled) {
1411 comvec();
1412 if(p != currun())
1413 dbgblock(p);
1414 goto save;
1415 }
1416
1417 while(R.IC != 0) {
1418 if(0)
1419 print("step: %lux: %s %4ld %D\n",
1420 (ulong)p, R.M->m->name, R.PC-R.M->prog, R.PC);
1421
1422 dec[R.PC->add]();
1423 op = R.PC->op;
1424 R.PC++;
1425 optab[op]();
1426
1427 /*
1428 * check notification about new progs
1429 */
1430 if(op == ISPAWN || op == IMSPAWN) {
1431 /* pick up the kid from the end of the run queue */
1432 kid = delruntail(Pdebug);
1433 n = snprint(buf, sizeof buf, "new %d", kid->pid);
1434 qproduce(ctl->q, buf, n);
1435 buf[0] = '\0';
1436 }
1437 if(op == ILOAD) {
1438 n = snprint(buf, sizeof buf, "load %s", string2c(*(String**)R.s));
1439 qproduce(ctl->q, buf, n);
1440 buf[0] = '\0';
1441 }
1442
1443 /*
1444 * check for returns at big steps
1445 */
1446 if(op == IRET)
1447 R.IC = 1;
1448
1449 /*
1450 * check for blocked progs
1451 */
1452 if(R.IC == 1 && p != currun())
1453 dbgblock(p);
1454 if(ctl->stop)
1455 R.IC = 1;
1456 R.IC--;
1457 if(ctl->bpts == nil)
1458 continue;
1459 pc = R.PC - R.M->prog;
1460 for(b = ctl->bpts; b != nil; b = b->next) {
1461 if(pc == b->pc &&
1462 (strcmp(R.M->m->path, b->path) == 0 ||
1463 strcmp(R.M->m->path, b->file) == 0)) {
1464 strcpy(buf, "breakpoint");
1465 goto save;
1466 }
1467 }
1468 }
1469
1470 save:
1471 if(ctl->stop)
1472 strcpy(buf, "stopped");
1473
1474 p->R = R;
1475
1476 if(env->debug == nil) {
1477 poperror();
1478 return;
1479 }
1480
1481 if(p == currun())
1482 delrun(Pdebug);
1483
1484 telldbg(env->debug, buf);
1485 poperror();
1486 closedbgctl(env->debug, p);
1487 }
1488
1489 Dev progdevtab = {
1490 'p',
1491 "prog",
1492
1493 devreset,
1494 devinit,
1495 devshutdown,
1496 progattach,
1497 progwalk,
1498 progstat,
1499 progopen,
1500 devcreate,
1501 progclose,
1502 progread,
1503 devbread,
1504 progwrite,
1505 devbwrite,
1506 devremove,
1507 progwstat,
1508 };
1509