1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "ureg.h"
7 #include "../port/error.h"
8 #include "rdbg.h"
9
10 #include <kernel.h>
11 #include <interp.h>
12
13 /*
14 * The following should be set in the config file to override
15 * the defaults.
16 */
17 int dbgstart;
18 char *dbgdata;
19 char *dbgctl;
20 char *dbgctlstart;
21 char *dbgctlstop;
22 char *dbgctlflush;
23
24 //
25 // Error messages sent to the remote debugger
26 //
27 static uchar Ereset[9] = { 'r', 'e', 's', 'e', 't' };
28 static uchar Ecount[9] = { 'c', 'o', 'u', 'n', 't' };
29 static uchar Eunk[9] = { 'u', 'n', 'k' };
30 static uchar Einval[9] = { 'i', 'n', 'v', 'a', 'l' };
31 static uchar Ebadpid[9] = {'p', 'i', 'd'};
32 static uchar Eunsup[9] = { 'u', 'n', 's', 'u', 'p' };
33 static uchar Enotstop[9] = { 'n', 'o', 't', 's', 't', 'o', 'p' };
34
35 //
36 // Error messages raised via call to error()
37 //
38 static char Erunning[] = "Not allowed while debugger is running";
39 static char Enumarg[] = "Not enough args";
40 static char Ebadcmd[] = "Unknown command";
41
42 static int PROCREG;
43 static struct {
44 Rendez;
45 Bkpt *b;
46 } brk;
47
48 static Queue *logq;
49
50 int dbgchat = 0;
51
52 typedef struct Debugger Debugger;
53 struct Debugger {
54 RWlock;
55 int running;
56 char data[PRINTSIZE];
57 char ctl[PRINTSIZE];
58 char ctlstart[PRINTSIZE];
59 char ctlstop[PRINTSIZE];
60 char ctlflush[PRINTSIZE];
61 };
62
63 static Debugger debugger = {
64 .data= "#t/eia0",
65 .ctl= "#t/eia0ctl",
66 .ctlstart= "b19200",
67 .ctlstop= "h",
68 .ctlflush= "f",
69 };
70
71 enum {
72 BkptStackSize= 256,
73 };
74
75 typedef struct SkipArg SkipArg;
76 struct SkipArg
77 {
78 Bkpt *b;
79 Proc *p;
80 };
81
82 Bkpt *breakpoints;
83 void freecondlist(BkptCond *l);
84
85 static int
getbreaks(ulong addr,Bkpt ** a,int nb)86 getbreaks(ulong addr, Bkpt **a, int nb)
87 {
88 Bkpt *b;
89 int n;
90
91 n = 0;
92 for(b = breakpoints; b != nil; b = b->next){
93 if(b->addr == addr){
94 a[n++] = b;
95 if(n == nb)
96 break;
97 }
98 }
99 return n;
100 }
101
102 Bkpt*
newbreak(int id,ulong addr,BkptCond * conds,void (* handler)(Bkpt *),void * aux)103 newbreak(int id, ulong addr, BkptCond *conds, void(*handler)(Bkpt*), void *aux)
104 {
105 Bkpt *b;
106
107 b = malloc(sizeof(*b));
108 if(b == nil)
109 error(Enomem);
110
111 b->id = id;
112 b->conditions = conds;
113 b->addr = addr;
114 b->handler = handler;
115 b->aux = aux;
116 b->next = nil;
117
118 return b;
119 }
120
121 void
freebreak(Bkpt * b)122 freebreak(Bkpt *b)
123 {
124 freecondlist(b->conditions);
125 free(b);
126 }
127
128 BkptCond*
newcondition(uchar cmd,ulong val)129 newcondition(uchar cmd, ulong val)
130 {
131 BkptCond *c;
132
133 c = mallocz(sizeof(*c), 0);
134 if(c == nil)
135 error(Enomem);
136
137 c->op = cmd;
138 c->val = val;
139 c->next = nil;
140
141 return c;
142 }
143
144 void
freecondlist(BkptCond * l)145 freecondlist(BkptCond *l)
146 {
147 BkptCond *next;
148
149 while(l != nil){
150 next = l->next;
151 free(l);
152 l = next;
153 }
154 }
155
156
157 void
breakset(Bkpt * b)158 breakset(Bkpt *b)
159 {
160 Bkpt *e[1];
161
162 if(getbreaks(b->addr, e, 1) != 0){
163 b->instr = e[0]->instr;
164 } else {
165 b->instr = machinstr(b->addr);
166 machbreakset(b->addr);
167 }
168
169 b->next = breakpoints;
170 breakpoints = b;
171 }
172
173 void
breakrestore(Bkpt * b)174 breakrestore(Bkpt *b)
175 {
176 b->next = breakpoints;
177 breakpoints = b;
178 machbreakset(b->addr);
179 }
180
181 Bkpt*
breakclear(int id)182 breakclear(int id)
183 {
184 Bkpt *b, *e, *p;
185
186 for(b=breakpoints, p=nil; b != nil && b->id != id; p = b, b = b->next)
187 ;
188
189 if(b != nil){
190 if(p == nil)
191 breakpoints = b->next;
192 else
193 p->next = b->next;
194
195 if(getbreaks(b->addr, &e, 1) == 0)
196 machbreakclear(b->addr, b->instr);
197 }
198
199 return b;
200 }
201
202 void
breaknotify(Bkpt * b,Proc * p)203 breaknotify(Bkpt *b, Proc *p)
204 {
205 p->dbgstop = 1; // stop running this process.
206 b->handler(b);
207 }
208
209 int
breakmatch(BkptCond * cond,Ureg * ur,Proc * p)210 breakmatch(BkptCond *cond, Ureg *ur, Proc *p)
211 {
212 ulong a, b;
213 int pos;
214 ulong s[BkptStackSize];
215
216 memset(s, 0, sizeof(s));
217 pos = 0;
218
219 for(;cond != nil; cond = cond->next){
220 switch(cond->op){
221 default:
222 panic("breakmatch: unknown operator %c", cond->op);
223 break;
224 case 'k':
225 if(p == nil || p->pid != cond->val)
226 return 0;
227 s[pos++] = 1;
228 break;
229 case 'b':
230 if(ur->pc != cond->val)
231 return 0;
232 s[pos++] = 1;
233 break;
234 case 'p': s[pos++] = cond->val; break;
235 case '*': a = *(ulong*)s[--pos]; s[pos++] = a; break;
236 case '&': a = s[--pos]; b = s[--pos]; s[pos++] = a & b; break;
237 case '=': a = s[--pos]; b = s[--pos]; s[pos++] = a == b; break;
238 case '!': a = s[--pos]; b = s[--pos]; s[pos++] = a != b; break;
239 case 'a': a = s[--pos]; b = s[--pos]; s[pos++] = a && b; break;
240 case 'o': a = s[--pos]; b = s[--pos]; s[pos++] = a || b; break;
241 }
242 }
243
244 if(pos && s[pos-1])
245 return 1;
246 return 0;
247 }
248
249 void
breakinit(void)250 breakinit(void)
251 {
252 machbreakinit();
253 }
254
255 static void
dbglog(char * fmt,...)256 dbglog(char *fmt, ...)
257 {
258 int n;
259 va_list arg;
260 char buf[PRINTSIZE];
261
262 va_start(arg, fmt);
263 n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
264 va_end(arg);
265 qwrite(logq, buf, n);
266 }
267
268 static int
get(int dbgfd,uchar * b)269 get(int dbgfd, uchar *b)
270 {
271 int i;
272 uchar c;
273
274 if(kread(dbgfd, &c, 1) < 0)
275 error(Eio);
276 for(i=0; i<9; i++){
277 if(kread(dbgfd, b++, 1) < 0)
278 error(Eio);
279 }
280 return c;
281 }
282
283 static void
mesg(int dbgfd,int m,uchar * buf)284 mesg(int dbgfd, int m, uchar *buf)
285 {
286 int i;
287 uchar c;
288
289 c = m;
290 if(kwrite(dbgfd, &c, 1) < 0)
291 error(Eio);
292 for(i=0; i<9; i++){
293 if(kwrite(dbgfd, buf+i, 1) < 0)
294 error(Eio);
295 }
296 }
297
298 static ulong
dbglong(uchar * s)299 dbglong(uchar *s)
300 {
301 return (s[0]<<24)|(s[1]<<16)|(s[2]<<8)|(s[3]<<0);
302 }
303
304 static Proc *
dbgproc(ulong pid,int dbgok)305 dbgproc(ulong pid, int dbgok)
306 {
307 int i;
308 Proc *p;
309
310 if(!dbgok && pid == up->pid)
311 return 0;
312 p = proctab(0);
313 for(i = 0; i < conf.nproc; i++){
314 if(p->pid == pid)
315 return p;
316 p++;
317 }
318 return 0;
319 }
320
321 static void*
addr(uchar * s)322 addr(uchar *s)
323 {
324 ulong a;
325 Proc *p;
326 static Ureg ureg;
327
328 a = ((s[0]<<24)|(s[1]<<16)|(s[2]<<8)|(s[3]<<0));
329 if(a < sizeof(Ureg)){
330 p = dbgproc(PROCREG, 0);
331 if(p == 0){
332 dbglog("dbg: invalid pid\n");
333 return 0;
334 }
335 if(p->dbgreg){
336 /* in trap(), registers are all on stack */
337 memmove(&ureg, p->dbgreg, sizeof(ureg));
338 }
339 else {
340 /* not in trap, only pc and sp are available */
341 memset(&ureg, 0, sizeof(ureg));
342 ureg.sp = p->sched.sp;
343 ureg.pc = p->sched.pc;
344 }
345 return (uchar*)&ureg+a;
346 }
347 return (void*)a;
348 }
349
350
351 static void
dumpcmd(uchar cmd,uchar * min)352 dumpcmd(uchar cmd, uchar *min)
353 {
354 char *s;
355 int n;
356
357 switch(cmd){
358 case Terr: s = "Terr"; break;
359 case Tmget: s = "Tmget"; break;
360 case Tmput: s = "Tmput"; break;
361 case Tspid: s = "Tspid"; break;
362 case Tproc: s = "Tproc"; break;
363 case Tstatus: s = "Tstatus"; break;
364 case Trnote: s = "Trnote"; break;
365 case Tstartstop: s = "Tstartstop"; break;
366 case Twaitstop: s = "Twaitstop"; break;
367 case Tstart: s = "Tstart"; break;
368 case Tstop: s = "Tstop"; break;
369 case Tkill: s = "Tkill"; break;
370 case Tcondbreak: s = "Tcondbreak"; break;
371 default: s = "<Unknown>"; break;
372 }
373 dbglog("%s: [%2.2ux]: ", s, cmd);
374 for(n = 0; n < 9; n++)
375 dbglog("%2.2ux", min[n]);
376 dbglog("\n");
377 }
378
379 static int
brkpending(void * a)380 brkpending(void *a)
381 {
382 Proc *p;
383
384 p = a;
385 if(brk.b != nil) return 1;
386
387 p->dbgstop = 0; /* atomic */
388 if(p->state == Stopped)
389 ready(p);
390
391 return 0;
392 }
393
394 static void
gotbreak(Bkpt * b)395 gotbreak(Bkpt *b)
396 {
397 Bkpt *cur, *prev;
398
399 b->link = nil;
400
401 for(prev = nil, cur = brk.b; cur != nil; prev = cur, cur = cur->link)
402 ;
403 if(prev == nil)
404 brk.b = b;
405 else
406 prev->link = b;
407
408 wakeup(&brk);
409 }
410
411 static int
startstop(Proc * p)412 startstop(Proc *p)
413 {
414 int id;
415 int s;
416 Bkpt *b;
417
418 sleep(&brk, brkpending, p);
419
420 s = splhi();
421 b = brk.b;
422 brk.b = b->link;
423 splx(s);
424
425 id = b->id;
426
427 return id;
428 }
429
430 static int
condbreak(char cmd,ulong val)431 condbreak(char cmd, ulong val)
432 {
433 BkptCond *c;
434 static BkptCond *head = nil;
435 static BkptCond *tail = nil;
436 static Proc *p = nil;
437 static int id = -1;
438 int s;
439
440 if(waserror()){
441 dbglog(up->env->errstr);
442 freecondlist(head);
443 head = tail = nil;
444 p = nil;
445 id = -1;
446 return 0;
447 }
448
449 switch(cmd){
450 case 'b': case 'p':
451 case '*': case '&': case '=':
452 case '!': case 'a': case 'o':
453 break;
454 case 'n':
455 id = val;
456 poperror();
457 return 1;
458 case 'k':
459 p = dbgproc(val, 0);
460 if(p == nil)
461 error("k: unknown pid");
462 break;
463 case 'd': {
464 Bkpt *b;
465
466 s = splhi();
467 b = breakclear(val);
468 if(b != nil){
469 Bkpt *cur, *prev;
470
471 prev = nil;
472 cur = brk.b;
473 while(cur != nil){
474 if(cur->id == b->id){
475 if(prev == nil)
476 brk.b = cur->link;
477 else
478 prev->link = cur->link;
479 break;
480 }
481 cur = cur->link;
482 }
483 freebreak(b);
484 }
485 splx(s);
486 poperror();
487 return 1;
488 }
489 default:
490 dbglog("condbreak(): unknown op %c %lux\n", cmd, val);
491 error("unknown op");
492 }
493
494 c = newcondition(cmd, val);
495
496 //
497 // the 'b' command comes last, (so we know we have reached the end
498 // of the condition list), but it should be the first thing
499 // checked, so put it at the head.
500 //
501 if(cmd == 'b'){
502 if(p == nil) error("no pid");
503 if(id == -1) error("no id");
504
505 c->next = head;
506 s = splhi();
507 breakset(newbreak(id, val, c, gotbreak, p));
508 splx(s);
509 head = tail = nil;
510 p = nil;
511 id = -1;
512 } else if(tail != nil){
513 tail->next = c;
514 tail = c;
515 } else
516 head = tail = c;
517
518 poperror();
519
520 return 1;
521 }
522
523 static void
dbg(void *)524 dbg(void*)
525 {
526 Proc *p;
527 ulong val;
528 int n, cfd, dfd;
529 uchar cmd, *a, min[RDBMSGLEN-1], mout[RDBMSGLEN-1];
530
531 rlock(&debugger);
532
533 setpri(PriRealtime);
534
535 closefgrp(up->env->fgrp);
536 up->env->fgrp = newfgrp(nil);
537
538 if(waserror()){
539 dbglog("dbg: quits: %s\n", up->env->errstr);
540 runlock(&debugger);
541 wlock(&debugger);
542 debugger.running = 0;
543 wunlock(&debugger);
544 pexit("", 0);
545 }
546
547 dfd = kopen(debugger.data, ORDWR);
548 if(dfd < 0){
549 dbglog("dbg: can't open %s: %s\n",debugger.data, up->env->errstr);
550 error(Eio);
551 }
552 if(waserror()){
553 kclose(dfd);
554 nexterror();
555 }
556
557 if(debugger.ctl[0] != 0){
558 cfd = kopen(debugger.ctl, ORDWR);
559 if(cfd < 0){
560 dbglog("dbg: can't open %s: %s\n", debugger.ctl, up->env->errstr);
561 error(Eio);
562 }
563 if(kwrite(cfd, debugger.ctlstart, strlen(debugger.ctlstart)) < 0){
564 dbglog("dbg: write %s: %s\n", debugger.ctl, up->env->errstr);
565 error(Eio);
566 }
567 }else
568 cfd = -1;
569 if(waserror()){
570 if(cfd != -1){
571 kwrite(cfd, debugger.ctlflush, strlen(debugger.ctlflush));
572 kclose(cfd);
573 }
574 nexterror();
575 }
576
577 mesg(dfd, Rerr, Ereset);
578
579 for(;;){
580 memset(mout, 0, sizeof(mout));
581 cmd = get(dfd, min);
582 if(dbgchat)
583 dumpcmd(cmd, min);
584 switch(cmd){
585 case Tmget:
586 n = min[4];
587 if(n > 9){
588 mesg(dfd, Rerr, Ecount);
589 break;
590 }
591 a = addr(min+0);
592 if(!isvalid_va(a)){
593 mesg(dfd, Rerr, Einval);
594 break;
595 }
596 memmove(mout, a, n);
597 mesg(dfd, Rmget, mout);
598 break;
599 case Tmput:
600 n = min[4];
601 if(n > 4){
602 mesg(dfd, Rerr, Ecount);
603 break;
604 }
605 a = addr(min+0);
606 if(!isvalid_va(a)){
607 mesg(dfd, Rerr, Einval);
608 break;
609 }
610 memmove(a, min+5, n);
611 segflush(a, n);
612 mesg(dfd, Rmput, mout);
613 break;
614 case Tproc:
615 p = dbgproc(dbglong(min+0), 0);
616 if(p == 0){
617 mesg(dfd, Rerr, Ebadpid);
618 break;
619 }
620 PROCREG = p->pid; /* try this instead of Tspid */
621 sprint((char*)mout, "%8.8lux", p);
622 mesg(dfd, Rproc, mout);
623 break;
624 case Tstatus:
625 p = dbgproc(dbglong(min+0), 1);
626 if(p == 0){
627 mesg(dfd, Rerr, Ebadpid);
628 break;
629 }
630 if(p->state > Rendezvous || p->state < Dead)
631 sprint((char*)mout, "%8.8ux", p->state);
632 else if(p->dbgstop == 1)
633 strncpy((char*)mout, statename[Stopped], sizeof(mout));
634 else
635 strncpy((char*)mout, statename[p->state], sizeof(mout));
636 mesg(dfd, Rstatus, mout);
637 break;
638 case Trnote:
639 p = dbgproc(dbglong(min+0), 0);
640 if(p == 0){
641 mesg(dfd, Rerr, Ebadpid);
642 break;
643 }
644 mout[0] = 0; /* should be trap status, if any */
645 mesg(dfd, Rrnote, mout);
646 break;
647 case Tstop:
648 p = dbgproc(dbglong(min+0), 0);
649 if(p == 0){
650 mesg(dfd, Rerr, Ebadpid);
651 break;
652 }
653 p->dbgstop = 1; /* atomic */
654 mout[0] = 0;
655 mesg(dfd, Rstop, mout);
656 break;
657 case Tstart:
658 p = dbgproc(dbglong(min+0), 0);
659 if(p == 0){
660 mesg(dfd, Rerr, Ebadpid);
661 break;
662 }
663 p->dbgstop = 0; /* atomic */
664 if(p->state == Stopped)
665 ready(p);
666 mout[0] = 0;
667 mesg(dfd, Rstart, mout);
668 break;
669 case Tstartstop:
670 p = dbgproc(dbglong(min+0), 0);
671 if(p == 0){
672 mesg(dfd, Rerr, Ebadpid);
673 break;
674 }
675 if(!p->dbgstop){
676 mesg(dfd, Rerr, Enotstop);
677 break;
678 }
679 mout[0] = startstop(p);
680 mesg(dfd, Rstartstop, mout);
681 break;
682 case Tcondbreak:
683 val = dbglong(min+0);
684 if(!condbreak(min[4], val)){
685 mesg(dfd, Rerr, Eunk);
686 break;
687 }
688 mout[0] = 0;
689 mesg(dfd, Rcondbreak, mout);
690 break;
691 default:
692 dumpcmd(cmd, min);
693 mesg(dfd, Rerr, Eunk);
694 break;
695 }
696 }
697 }
698
699 static void
dbgnote(Proc * p,Ureg * ur)700 dbgnote(Proc *p, Ureg *ur)
701 {
702 if(p){
703 p->dbgreg = ur;
704 PROCREG = p->pid; /* acid can get the trap info from regs */
705 }
706 }
707
708 enum {
709 Qdir,
710 Qdbgctl,
711 Qdbglog,
712
713 DBGrun = 1,
714 DBGstop = 2,
715
716 Loglimit = 4096,
717 };
718
719 static Dirtab dbgdir[]=
720 {
721 ".", {Qdir, 0, QTDIR}, 0, 0555,
722 "dbgctl", {Qdbgctl}, 0, 0660,
723 "dbglog", {Qdbglog}, 0, 0440,
724 };
725
726 static void
start_debugger(void)727 start_debugger(void)
728 {
729 breakinit();
730 dbglog("starting debugger\n");
731 debugger.running++;
732 kproc("dbg", dbg, 0, KPDUPPG);
733 }
734
735 static void
dbginit(void)736 dbginit(void)
737 {
738
739 logq = qopen(Loglimit, 0, 0, 0);
740 if(logq == nil)
741 error(Enomem);
742 qnoblock(logq, 1);
743
744 wlock(&debugger);
745 if(waserror()){
746 wunlock(&debugger);
747 qfree(logq);
748 logq = nil;
749 nexterror();
750 }
751
752 if(dbgdata != nil){
753 strncpy(debugger.data, dbgdata, sizeof(debugger.data));
754 debugger.data[sizeof(debugger.data)-1] = 0;
755 }
756 if(dbgctl != nil){
757 strncpy(debugger.ctl, dbgctl, sizeof(debugger.ctl));
758 debugger.ctl[sizeof(debugger.ctl)-1] = 0;
759 }
760 if(dbgctlstart != nil){
761 strncpy(debugger.ctlstart, dbgctlstart, sizeof(debugger.ctlstart));
762 debugger.ctlstart[sizeof(debugger.ctlstart)-1] = 0;
763 }
764 if(dbgctlstop != nil){
765 strncpy(debugger.ctlstop, dbgctlstop, sizeof(debugger.ctlstop));
766 debugger.ctlstop[sizeof(debugger.ctlstop)-1] = 0;
767 }
768 if(dbgctlflush != nil){
769 strncpy(debugger.ctlflush, dbgctlflush, sizeof(debugger.ctlflush));
770 debugger.ctlflush[sizeof(debugger.ctlflush)-1] = 0;
771 }
772 if(dbgstart)
773 start_debugger();
774
775 poperror();
776 wunlock(&debugger);
777 }
778
779 static Chan*
dbgattach(char * spec)780 dbgattach(char *spec)
781 {
782 return devattach('b', spec);
783 }
784
785 static Walkqid*
dbgwalk(Chan * c,Chan * nc,char ** name,int nname)786 dbgwalk(Chan *c, Chan *nc, char **name, int nname)
787 {
788 return devwalk(c, nc, name, nname, dbgdir, nelem(dbgdir), devgen);
789 }
790
791 static int
dbgstat(Chan * c,uchar * dp,int n)792 dbgstat(Chan *c, uchar *dp, int n)
793 {
794 return devstat(c, dp, n, dbgdir, nelem(dbgdir), devgen);
795 }
796
797 static Chan*
dbgopen(Chan * c,int omode)798 dbgopen(Chan *c, int omode)
799 {
800 return devopen(c, omode, dbgdir, nelem(dbgdir), devgen);
801 }
802
803 static long
dbgread(Chan * c,void * buf,long n,vlong offset)804 dbgread(Chan *c, void *buf, long n, vlong offset)
805 {
806 char *ctlstate;
807
808 switch((ulong)c->qid.path){
809 case Qdir:
810 return devdirread(c, buf, n, dbgdir, nelem(dbgdir), devgen);
811 case Qdbgctl:
812 rlock(&debugger);
813 ctlstate = smprint("%s data %s ctl %s ctlstart %s ctlstop %s ctlflush %s\n",
814 debugger.running ? "running" : "stopped",
815 debugger.data, debugger.ctl,
816 debugger.ctlstart, debugger.ctlstop, debugger.ctlflush);
817 runlock(&debugger);
818 if(ctlstate == nil)
819 error(Enomem);
820 if(waserror()){
821 free(ctlstate);
822 nexterror();
823 }
824 n = readstr(offset, buf, n, ctlstate);
825 poperror();
826 free(ctlstate);
827 return n;
828 case Qdbglog:
829 return qread(logq, buf, n);
830 default:
831 error(Egreg);
832 }
833 return -1; /* never reached */
834 }
835
836 static void
ctl(Cmdbuf * cb)837 ctl(Cmdbuf *cb)
838 {
839 Debugger d;
840 int dbgstate = 0;
841 int i;
842 char *df;
843 int dfsize;
844 int setval;
845
846 memset(&d, 0, sizeof(d));
847 for(i=0; i < cb->nf; i++){
848 setval = 0;
849 df = nil;
850 dfsize = 0;
851 switch(cb->f[i][0]){
852 case 'd':
853 df = d.data;
854 dfsize = sizeof(d.data);
855 setval=1;
856 break;
857 case 'c':
858 df = d.ctl;
859 dfsize = sizeof(d.ctl);
860 setval=1;
861 break;
862 case 'i':
863 df = d.ctlstart;
864 dfsize = sizeof(d.ctlstart);
865 setval=1;
866 break;
867 case 'h':
868 df = d.ctlstop;
869 dfsize = sizeof(d.ctlstop);
870 setval=1;
871 break;
872 case 'f':
873 df = d.ctlflush;
874 dfsize = sizeof(d.ctlflush);
875 setval=1;
876 break;
877 case 'r':
878 dbgstate = DBGrun;
879 break;
880 case 's':
881 dbgstate = DBGstop;
882 break;
883 default:
884 error(Ebadcmd);
885 }
886 if(setval){
887 if(i+1 >= cb->nf)
888 cmderror(cb, Enumarg);
889 strncpy(df, cb->f[i+1], dfsize-1);
890 df[dfsize-1] = 0;
891 ++d.running;
892 ++i;
893 }
894 }
895
896 if(d.running){
897 wlock(&debugger);
898 if(debugger.running){
899 wunlock(&debugger);
900 error(Erunning);
901 }
902 if(d.data[0] != 0){
903 strcpy(debugger.data, d.data);
904 dbglog("data %s\n",debugger.data);
905 }
906 if(d.ctl[0] != 0){
907 strcpy(debugger.ctl, d.ctl);
908 dbglog("ctl %s\n",debugger.ctl);
909 }
910 if(d.ctlstart[0] != 0){
911 strcpy(debugger.ctlstart, d.ctlstart);
912 dbglog("ctlstart %s\n",debugger.ctlstart);
913 }
914 if(d.ctlstop[0] != 0){
915 strcpy(debugger.ctlstop, d.ctlstop);
916 dbglog("ctlstop %s\n",debugger.ctlstop);
917 }
918 wunlock(&debugger);
919 }
920
921 if(dbgstate == DBGrun){
922 if(!debugger.running){
923 wlock(&debugger);
924 if(waserror()){
925 wunlock(&debugger);
926 nexterror();
927 }
928 if(!debugger.running)
929 start_debugger();
930 else
931 dbglog("debugger already running\n");
932 poperror();
933 wunlock(&debugger);
934 } else
935 dbglog("debugger already running\n");
936 } else if(dbgstate == DBGstop){
937 if(debugger.running){
938 /* force hangup to stop the dbg process */
939 int cfd;
940 if(debugger.ctl[0] == 0)
941 return;
942 cfd = kopen(debugger.ctl, OWRITE);
943 if(cfd == -1)
944 error(up->env->errstr);
945 dbglog("stopping debugger\n");
946 if(kwrite(cfd, debugger.ctlstop, strlen(debugger.ctlstop)) == -1)
947 error(up->env->errstr);
948 kclose(cfd);
949 } else
950 dbglog("debugger not running\n");
951 }
952 }
953
954 static long
dbgwrite(Chan * c,void * va,long n,vlong)955 dbgwrite(Chan *c, void *va, long n, vlong)
956 {
957 Cmdbuf *cb;
958
959 switch((ulong)c->qid.path){
960 default:
961 error(Egreg);
962 break;
963 case Qdbgctl:
964 cb = parsecmd(va, n);
965 if(waserror()){
966 free(cb);
967 nexterror();
968 }
969 ctl(cb);
970 poperror();
971 break;
972 }
973 return n;
974 }
975
976 static void
dbgclose(Chan *)977 dbgclose(Chan*)
978 {
979 }
980
981 Dev dbgdevtab = {
982 'b',
983 "dbg",
984
985 devreset,
986 dbginit,
987 devshutdown,
988 dbgattach,
989 dbgwalk,
990 dbgstat,
991 dbgopen,
992 devcreate,
993 dbgclose,
994 dbgread,
995 devbread,
996 dbgwrite,
997 devbwrite,
998 devremove,
999 devwstat,
1000 };
1001