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 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* 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 122 freebreak(Bkpt *b) 123 { 124 freecondlist(b->conditions); 125 free(b); 126 } 127 128 BkptCond* 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 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 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 174 breakrestore(Bkpt *b) 175 { 176 b->next = breakpoints; 177 breakpoints = b; 178 machbreakset(b->addr); 179 } 180 181 Bkpt* 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 203 breaknotify(Bkpt *b, Proc *p) 204 { 205 p->dbgstop = 1; // stop running this process. 206 b->handler(b); 207 } 208 209 int 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 250 breakinit(void) 251 { 252 machbreakinit(); 253 } 254 255 static void 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 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 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 299 dbglong(uchar *s) 300 { 301 return (s[0]<<24)|(s[1]<<16)|(s[2]<<8)|(s[3]<<0); 302 } 303 304 static Proc * 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* 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 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 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 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 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 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 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 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 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 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* 780 dbgattach(char *spec) 781 { 782 return devattach('b', spec); 783 } 784 785 static Walkqid* 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 792 dbgstat(Chan *c, uchar *dp, int n) 793 { 794 return devstat(c, dp, n, dbgdir, nelem(dbgdir), devgen); 795 } 796 797 static Chan* 798 dbgopen(Chan *c, int omode) 799 { 800 return devopen(c, omode, dbgdir, nelem(dbgdir), devgen); 801 } 802 803 static long 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 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 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 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