1: /*
   2:  * Copyright (c) 1983 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  */
   6: 
   7: #ifndef lint
   8: static char sccsid[] = "@(#)process.c	5.1 (Berkeley) 5/31/85";
   9: #endif not lint
  10: 
  11: static char rcsid[] = "$Header: process.c,v 1.5 84/12/26 10:41:37 linton Exp $";
  12: 
  13: /*
  14:  * Process management.
  15:  *
  16:  * This module contains the routines to manage the execution and
  17:  * tracing of the debuggee process.
  18:  */
  19: 
  20: #include "defs.h"
  21: #include "process.h"
  22: #include "machine.h"
  23: #include "events.h"
  24: #include "tree.h"
  25: #include "eval.h"
  26: #include "operators.h"
  27: #include "source.h"
  28: #include "object.h"
  29: #include "mappings.h"
  30: #include "main.h"
  31: #include "coredump.h"
  32: #include <signal.h>
  33: #include <errno.h>
  34: #include <sys/param.h>
  35: #include <sys/dir.h>
  36: #include <sys/user.h>
  37: #include <machine/reg.h>
  38: #include <sys/stat.h>
  39: 
  40: #ifndef public
  41: 
  42: typedef struct Process *Process;
  43: 
  44: Process process;
  45: 
  46: #define DEFSIG -1
  47: 
  48: #include "machine.h"
  49: 
  50: #endif
  51: 
  52: #define NOTSTARTED 1
  53: #define STOPPED 0177
  54: #define FINISHED 0
  55: 
  56: /*
  57:  * A cache of the instruction segment is kept to reduce the number
  58:  * of system calls.  Might be better just to read the entire
  59:  * code space into memory.
  60:  */
  61: 
  62: #define CSIZE 1003       /* size of instruction cache */
  63: 
  64: typedef struct {
  65:     Word addr;
  66:     Word val;
  67: } CacheWord;
  68: 
  69: /*
  70:  * This structure holds the information we need from the user structure.
  71:  */
  72: 
  73: struct Process {
  74:     int pid;            /* process being traced */
  75:     int mask;           /* process status word */
  76:     Word reg[NREG];     /* process' registers */
  77:     Word oreg[NREG];        /* registers when process last stopped */
  78:     short status;       /* either STOPPED or FINISHED */
  79:     short signo;        /* signal that stopped process */
  80:     short sigcode;      /* extra signal information */
  81:     int exitval;        /* return value from exit() */
  82:     long sigset;        /* bit array of traced signals */
  83:     CacheWord word[CSIZE];  /* text segment cache */
  84:     Ttyinfo ttyinfo;        /* process' terminal characteristics */
  85:     Address sigstatus;      /* process' handler for current signal */
  86: };
  87: 
  88: /*
  89:  * These definitions are for the arguments to "pio".
  90:  */
  91: 
  92: typedef enum { PREAD, PWRITE } PioOp;
  93: typedef enum { TEXTSEG, DATASEG } PioSeg;
  94: 
  95: private struct Process pbuf;
  96: 
  97: #define MAXNCMDARGS 1000         /* maximum number of arguments to RUN */
  98: 
  99: extern int errno;
 100: 
 101: private Boolean just_started;
 102: private int argc;
 103: private String argv[MAXNCMDARGS];
 104: private String infile, outfile;
 105: 
 106: /*
 107:  * Initialize process information.
 108:  */
 109: 
 110: public process_init()
 111: {
 112:     register Integer i;
 113:     Char buf[10];
 114: 
 115:     process = &pbuf;
 116:     process->status = (coredump) ? STOPPED : NOTSTARTED;
 117:     setsigtrace();
 118:     for (i = 0; i < NREG; i++) {
 119:     sprintf(buf, "$r%d", i);
 120:     defregname(identname(buf, false), i);
 121:     }
 122:     defregname(identname("$ap", true), ARGP);
 123:     defregname(identname("$fp", true), FRP);
 124:     defregname(identname("$sp", true), STKP);
 125:     defregname(identname("$pc", true), PROGCTR);
 126:     if (coredump) {
 127:     coredump_readin(process->mask, process->reg, process->signo);
 128:     pc = process->reg[PROGCTR];
 129:     getsrcpos();
 130:     }
 131:     arginit();
 132: }
 133: 
 134: /*
 135:  * Routines to get at process information from outside this module.
 136:  */
 137: 
 138: public Word reg(n)
 139: Integer n;
 140: {
 141:     register Word w;
 142: 
 143:     if (n == NREG) {
 144:     w = process->mask;
 145:     } else {
 146:     w = process->reg[n];
 147:     }
 148:     return w;
 149: }
 150: 
 151: public setreg(n, w)
 152: Integer n;
 153: Word w;
 154: {
 155:     process->reg[n] = w;
 156: }
 157: 
 158: /*
 159:  * Begin execution.
 160:  *
 161:  * We set a breakpoint at the end of the code so that the
 162:  * process data doesn't disappear after the program terminates.
 163:  */
 164: 
 165: private Boolean remade();
 166: 
 167: public start(argv, infile, outfile)
 168: String argv[];
 169: String infile, outfile;
 170: {
 171:     String pargv[4];
 172:     Node cond;
 173: 
 174:     if (coredump) {
 175:     coredump = false;
 176:     fclose(corefile);
 177:     coredump_close();
 178:     }
 179:     if (argv == nil) {
 180:     argv = pargv;
 181:     pargv[0] = objname;
 182:     pargv[1] = nil;
 183:     } else {
 184:     argv[argc] = nil;
 185:     }
 186:     pstart(process, argv, infile, outfile);
 187:     if (remade(objname)) {
 188:     reinit(argv, infile, outfile);
 189:     }
 190:     if (process->status == STOPPED) {
 191:     pc = 0;
 192:     setcurfunc(program);
 193:     if (objsize != 0) {
 194:         cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr()));
 195:         event_once(cond, buildcmdlist(build(O_ENDX)));
 196:     }
 197:     }
 198: }
 199: 
 200: /*
 201:  * Check to see if the object file has changed since the symbolic
 202:  * information last was read.
 203:  */
 204: 
 205: private time_t modtime;
 206: 
 207: private Boolean remade(filename)
 208: String filename;
 209: {
 210:     struct stat s;
 211:     Boolean b;
 212: 
 213:     stat(filename, &s);
 214:     b = (Boolean) (modtime != 0 and modtime < s.st_mtime);
 215:     modtime = s.st_mtime;
 216:     return b;
 217: }
 218: 
 219: /*
 220:  * Set up what signals we want to trace.
 221:  */
 222: 
 223: private setsigtrace()
 224: {
 225:     register Integer i;
 226:     register Process p;
 227: 
 228:     p = process;
 229:     for (i = 1; i <= NSIG; i++) {
 230:     psigtrace(p, i, true);
 231:     }
 232:     psigtrace(p, SIGHUP, false);
 233:     psigtrace(p, SIGKILL, false);
 234:     psigtrace(p, SIGALRM, false);
 235:     psigtrace(p, SIGTSTP, false);
 236:     psigtrace(p, SIGCONT, false);
 237:     psigtrace(p, SIGCHLD, false);
 238: }
 239: 
 240: /*
 241:  * Initialize the argument list.
 242:  */
 243: 
 244: public arginit()
 245: {
 246:     infile = nil;
 247:     outfile = nil;
 248:     argv[0] = objname;
 249:     argc = 1;
 250: }
 251: 
 252: /*
 253:  * Add an argument to the list for the debuggee.
 254:  */
 255: 
 256: public newarg(arg)
 257: String arg;
 258: {
 259:     if (argc >= MAXNCMDARGS) {
 260:     error("too many arguments");
 261:     }
 262:     argv[argc++] = arg;
 263: }
 264: 
 265: /*
 266:  * Set the standard input for the debuggee.
 267:  */
 268: 
 269: public inarg(filename)
 270: String filename;
 271: {
 272:     if (infile != nil) {
 273:     error("multiple input redirects");
 274:     }
 275:     infile = filename;
 276: }
 277: 
 278: /*
 279:  * Set the standard output for the debuggee.
 280:  * Probably should check to avoid overwriting an existing file.
 281:  */
 282: 
 283: public outarg(filename)
 284: String filename;
 285: {
 286:     if (outfile != nil) {
 287:     error("multiple output redirect");
 288:     }
 289:     outfile = filename;
 290: }
 291: 
 292: /*
 293:  * Start debuggee executing.
 294:  */
 295: 
 296: public run()
 297: {
 298:     process->status = STOPPED;
 299:     fixbps();
 300:     curline = 0;
 301:     start(argv, infile, outfile);
 302:     just_started = true;
 303:     isstopped = false;
 304:     cont(0);
 305: }
 306: 
 307: /*
 308:  * Continue execution wherever we left off.
 309:  *
 310:  * Note that this routine never returns.  Eventually bpact() will fail
 311:  * and we'll call printstatus or step will call it.
 312:  */
 313: 
 314: typedef int Intfunc();
 315: 
 316: private Intfunc *dbintr;
 317: private intr();
 318: 
 319: public cont(signo)
 320: integer signo;
 321: {
 322:     integer s;
 323: 
 324:     dbintr = signal(SIGINT, intr);
 325:     if (just_started) {
 326:     just_started = false;
 327:     } else {
 328:     if (not isstopped) {
 329:         error("can't continue execution");
 330:     }
 331:     isstopped = false;
 332:     stepover();
 333:     }
 334:     s = signo;
 335:     for (;;) {
 336:     if (single_stepping) {
 337:         printnews();
 338:     } else {
 339:         setallbps();
 340:         resume(s);
 341:         unsetallbps();
 342:         s = DEFSIG;
 343:         if (not isbperr() or not bpact()) {
 344:         printstatus();
 345:         }
 346:     }
 347:     stepover();
 348:     }
 349:     /* NOTREACHED */
 350: }
 351: 
 352: /*
 353:  * This routine is called if we get an interrupt while "running"
 354:  * but actually in the debugger.  Could happen, for example, while
 355:  * processing breakpoints.
 356:  *
 357:  * We basically just want to keep going; the assumption is
 358:  * that when the process resumes it will get the interrupt,
 359:  * which will then be handled.
 360:  */
 361: 
 362: private intr()
 363: {
 364:     signal(SIGINT, intr);
 365: }
 366: 
 367: public fixintr()
 368: {
 369:     signal(SIGINT, dbintr);
 370: }
 371: 
 372: /*
 373:  * Resume execution.
 374:  */
 375: 
 376: public resume(signo)
 377: int signo;
 378: {
 379:     register Process p;
 380: 
 381:     p = process;
 382:     pcont(p, signo);
 383:     pc = process->reg[PROGCTR];
 384:     if (p->status != STOPPED) {
 385:     if (p->signo != 0) {
 386:         error("program terminated by signal %d", p->signo);
 387:     } else if (not runfirst) {
 388:         if (p->exitval == 0) {
 389:         error("program exited");
 390:         } else {
 391:         error("program exited with code %d", p->exitval);
 392:         }
 393:     }
 394:     }
 395: }
 396: 
 397: /*
 398:  * Continue execution up to the next source line.
 399:  *
 400:  * There are two ways to define the next source line depending on what
 401:  * is desired when a procedure or function call is encountered.  Step
 402:  * stops at the beginning of the procedure or call; next skips over it.
 403:  */
 404: 
 405: /*
 406:  * Stepc is what is called when the step command is given.
 407:  * It has to play with the "isstopped" information.
 408:  */
 409: 
 410: public stepc()
 411: {
 412:     if (not isstopped) {
 413:     error("can't continue execution");
 414:     }
 415:     isstopped = false;
 416:     dostep(false);
 417:     isstopped = true;
 418: }
 419: 
 420: public next()
 421: {
 422:     Address oldfrp, newfrp;
 423: 
 424:     if (not isstopped) {
 425:     error("can't continue execution");
 426:     }
 427:     isstopped = false;
 428:     oldfrp = reg(FRP);
 429:     do {
 430:     dostep(true);
 431:     pc = reg(PROGCTR);
 432:     newfrp = reg(FRP);
 433:     } while (newfrp < oldfrp and newfrp != 0);
 434:     isstopped = true;
 435: }
 436: 
 437: /*
 438:  * Continue execution until the current function returns, or,
 439:  * if the given argument is non-nil, until execution returns to
 440:  * somewhere within the given function.
 441:  */
 442: 
 443: public rtnfunc (f)
 444: Symbol f;
 445: {
 446:     Address addr;
 447:     Symbol t;
 448: 
 449:     if (not isstopped) {
 450:     error("can't continue execution");
 451:     } else if (f != nil and not isactive(f)) {
 452:     error("%s is not active", symname(f));
 453:     } else {
 454:     addr = return_addr();
 455:     if (addr == nil) {
 456:         error("no place to return to");
 457:     } else {
 458:         isstopped = false;
 459:         contto(addr);
 460:         if (f != nil) {
 461:         for (;;) {
 462:             t = whatblock(pc);
 463:             addr = return_addr();
 464:         if (t == f or addr == nil) break;
 465:             contto(addr);
 466:         }
 467:         }
 468:         if (not bpact()) {
 469:         isstopped = true;
 470:         printstatus();
 471:         }
 472:     }
 473:     }
 474: }
 475: 
 476: /*
 477:  * Single-step over the current machine instruction.
 478:  *
 479:  * If we're single-stepping by source line we want to step to the
 480:  * next source line.  Otherwise we're going to continue so there's
 481:  * no reason to do all the work necessary to single-step to the next
 482:  * source line.
 483:  */
 484: 
 485: public stepover()
 486: {
 487:     Boolean b;
 488: 
 489:     if (traceexec) {
 490:     printf("!! stepping over 0x%x\n", process->reg[PROGCTR]);
 491:     }
 492:     if (single_stepping) {
 493:     dostep(false);
 494:     } else {
 495:     b = inst_tracing;
 496:     inst_tracing = true;
 497:     dostep(false);
 498:     inst_tracing = b;
 499:     }
 500:     if (traceexec) {
 501:     printf("!! stepped over to 0x%x\n", process->reg[PROGCTR]);
 502:     }
 503: }
 504: 
 505: /*
 506:  * Resume execution up to the given address.  We can either ignore
 507:  * breakpoints (stepto) or catch them (contto).
 508:  */
 509: 
 510: public stepto(addr)
 511: Address addr;
 512: {
 513:     xto(addr, false);
 514: }
 515: 
 516: private contto (addr)
 517: Address addr;
 518: {
 519:     xto(addr, true);
 520: }
 521: 
 522: private xto (addr, catchbps)
 523: Address addr;
 524: boolean catchbps;
 525: {
 526:     Address curpc;
 527: 
 528:     if (catchbps) {
 529:     stepover();
 530:     }
 531:     curpc = process->reg[PROGCTR];
 532:     if (addr != curpc) {
 533:     if (traceexec) {
 534:         printf("!! stepping from 0x%x to 0x%x\n", curpc, addr);
 535:     }
 536:     if (catchbps) {
 537:         setallbps();
 538:     }
 539:     setbp(addr);
 540:     resume(DEFSIG);
 541:     unsetbp(addr);
 542:     if (catchbps) {
 543:         unsetallbps();
 544:     }
 545:     if (not isbperr()) {
 546:         printstatus();
 547:     }
 548:     }
 549: }
 550: 
 551: /*
 552:  * Print the status of the process.
 553:  * This routine does not return.
 554:  */
 555: 
 556: public printstatus()
 557: {
 558:     int status;
 559: 
 560:     if (process->status == FINISHED) {
 561:     exit(0);
 562:     } else {
 563:     setcurfunc(whatblock(pc));
 564:     getsrcpos();
 565:     if (process->signo == SIGINT) {
 566:         isstopped = true;
 567:         printerror();
 568:     } else if (isbperr() and isstopped) {
 569:         printf("stopped ");
 570:         printloc();
 571:         putchar('\n');
 572:         if (curline > 0) {
 573:         printlines(curline, curline);
 574:         } else {
 575:         printinst(pc, pc);
 576:         }
 577:         erecover();
 578:     } else {
 579:         fixintr();
 580:         isstopped = true;
 581:         printerror();
 582:     }
 583:     }
 584: }
 585: 
 586: /*
 587:  * Print out the current location in the debuggee.
 588:  */
 589: 
 590: public printloc()
 591: {
 592:     printf("in ");
 593:     printname(stdout, curfunc);
 594:     putchar(' ');
 595:     if (curline > 0 and not useInstLoc) {
 596:     printsrcpos();
 597:     } else {
 598:     useInstLoc = false;
 599:     curline = 0;
 600:     printf("at 0x%x", pc);
 601:     }
 602: }
 603: 
 604: /*
 605:  * Some functions for testing the state of the process.
 606:  */
 607: 
 608: public Boolean notstarted(p)
 609: Process p;
 610: {
 611:     return (Boolean) (p->status == NOTSTARTED);
 612: }
 613: 
 614: public Boolean isfinished(p)
 615: Process p;
 616: {
 617:     return (Boolean) (p->status == FINISHED);
 618: }
 619: 
 620: /*
 621:  * Predicate to test if the reason the process stopped was because
 622:  * of a breakpoint.  If so, as a side effect clear the local copy of
 623:  * signal handler associated with process.  We must do this so as to
 624:  * not confuse future stepping or continuing by possibly concluding
 625:  * the process should continue with a SIGTRAP handler.
 626:  */
 627: 
 628: public boolean isbperr()
 629: {
 630:     Process p;
 631:     boolean b;
 632: 
 633:     p = process;
 634:     if (p->status == STOPPED and p->signo == SIGTRAP) {
 635:     b = true;
 636:     p->sigstatus = 0;
 637:     } else {
 638:     b = false;
 639:     }
 640:     return b;
 641: }
 642: 
 643: /*
 644:  * Return the signal number that stopped the process.
 645:  */
 646: 
 647: public integer errnum (p)
 648: Process p;
 649: {
 650:     return p->signo;
 651: }
 652: 
 653: /*
 654:  * Return the signal code associated with the signal.
 655:  */
 656: 
 657: public integer errcode (p)
 658: Process p;
 659: {
 660:     return p->sigcode;
 661: }
 662: 
 663: /*
 664:  * Return the termination code of the process.
 665:  */
 666: 
 667: public integer exitcode (p)
 668: Process p;
 669: {
 670:     return p->exitval;
 671: }
 672: 
 673: /*
 674:  * These routines are used to access the debuggee process from
 675:  * outside this module.
 676:  *
 677:  * They invoke "pio" which eventually leads to a call to "ptrace".
 678:  * The system generates an I/O error when a ptrace fails.  During reads
 679:  * these are ignored, during writes they are reported as an error, and
 680:  * for anything else they cause a fatal error.
 681:  */
 682: 
 683: extern Intfunc *onsyserr();
 684: 
 685: private badaddr;
 686: private read_err(), write_err();
 687: 
 688: /*
 689:  * Read from the process' instruction area.
 690:  */
 691: 
 692: public iread(buff, addr, nbytes)
 693: char *buff;
 694: Address addr;
 695: int nbytes;
 696: {
 697:     Intfunc *f;
 698: 
 699:     f = onsyserr(EIO, read_err);
 700:     badaddr = addr;
 701:     if (coredump) {
 702:     coredump_readtext(buff, addr, nbytes);
 703:     } else {
 704:     pio(process, PREAD, TEXTSEG, buff, addr, nbytes);
 705:     }
 706:     onsyserr(EIO, f);
 707: }
 708: 
 709: /*
 710:  * Write to the process' instruction area, usually in order to set
 711:  * or unset a breakpoint.
 712:  */
 713: 
 714: public iwrite(buff, addr, nbytes)
 715: char *buff;
 716: Address addr;
 717: int nbytes;
 718: {
 719:     Intfunc *f;
 720: 
 721:     if (coredump) {
 722:     error("no process to write to");
 723:     }
 724:     f = onsyserr(EIO, write_err);
 725:     badaddr = addr;
 726:     pio(process, PWRITE, TEXTSEG, buff, addr, nbytes);
 727:     onsyserr(EIO, f);
 728: }
 729: 
 730: /*
 731:  * Read for the process' data area.
 732:  */
 733: 
 734: public dread(buff, addr, nbytes)
 735: char *buff;
 736: Address addr;
 737: int nbytes;
 738: {
 739:     Intfunc *f;
 740: 
 741:     badaddr = addr;
 742:     if (coredump) {
 743:     f = onsyserr(EFAULT, read_err);
 744:     coredump_readdata(buff, addr, nbytes);
 745:     onsyserr(EFAULT, f);
 746:     } else {
 747:     f = onsyserr(EIO, read_err);
 748:     pio(process, PREAD, DATASEG, buff, addr, nbytes);
 749:     onsyserr(EIO, f);
 750:     }
 751: }
 752: 
 753: /*
 754:  * Write to the process' data area.
 755:  */
 756: 
 757: public dwrite(buff, addr, nbytes)
 758: char *buff;
 759: Address addr;
 760: int nbytes;
 761: {
 762:     Intfunc *f;
 763: 
 764:     if (coredump) {
 765:     error("no process to write to");
 766:     }
 767:     f = onsyserr(EIO, write_err);
 768:     badaddr = addr;
 769:     pio(process, PWRITE, DATASEG, buff, addr, nbytes);
 770:     onsyserr(EIO, f);
 771: }
 772: 
 773: /*
 774:  * Trap for errors in reading or writing to a process.
 775:  * The current approach is to "ignore" read errors and complain
 776:  * bitterly about write errors.
 777:  */
 778: 
 779: private read_err()
 780: {
 781:     /*
 782:      * Ignore.
 783:      */
 784: }
 785: 
 786: private write_err()
 787: {
 788:     error("can't write to process (address 0x%x)", badaddr);
 789: }
 790: 
 791: /*
 792:  * Ptrace interface.
 793:  */
 794: 
 795: /*
 796:  * This magic macro enables us to look at the process' registers
 797:  * in its user structure.
 798:  */
 799: 
 800: #define regloc(reg)     (ctob(UPAGES) + ( sizeof(int) * (reg) ))
 801: 
 802: #define WMASK           (~(sizeof(Word) - 1))
 803: #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE))
 804: 
 805: #define FIRSTSIG        SIGINT
 806: #define LASTSIG         SIGQUIT
 807: #define ischild(pid)    ((pid) == 0)
 808: #define traceme()       ptrace(0, 0, 0, 0)
 809: #define setrep(n)       (1 << ((n)-1))
 810: #define istraced(p)     (p->sigset&setrep(p->signo))
 811: 
 812: /*
 813:  * Ptrace options (specified in first argument).
 814:  */
 815: 
 816: #define UREAD   3       /* read from process's user structure */
 817: #define UWRITE  6       /* write to process's user structure */
 818: #define IREAD   1       /* read from process's instruction space */
 819: #define IWRITE  4       /* write to process's instruction space */
 820: #define DREAD   2       /* read from process's data space */
 821: #define DWRITE  5       /* write to process's data space */
 822: #define CONT    7       /* continue stopped process */
 823: #define SSTEP   9       /* continue for approximately one instruction */
 824: #define PKILL   8       /* terminate the process */
 825: 
 826: /*
 827:  * Start up a new process by forking and exec-ing the
 828:  * given argument list, returning when the process is loaded
 829:  * and ready to execute.  The PROCESS information (pointed to
 830:  * by the first argument) is appropriately filled.
 831:  *
 832:  * If the given PROCESS structure is associated with an already running
 833:  * process, we terminate it.
 834:  */
 835: 
 836: /* VARARGS2 */
 837: private pstart(p, argv, infile, outfile)
 838: Process p;
 839: String argv[];
 840: String infile;
 841: String outfile;
 842: {
 843:     int status;
 844: 
 845:     if (p->pid != 0) {
 846:     pterm(p);
 847:     cacheflush(p);
 848:     }
 849:     fflush(stdout);
 850:     psigtrace(p, SIGTRAP, true);
 851:     p->pid = vfork();
 852:     if (p->pid == -1) {
 853:     panic("can't fork");
 854:     }
 855:     if (ischild(p->pid)) {
 856:     nocatcherrs();
 857:     traceme();
 858:     if (infile != nil) {
 859:         infrom(infile);
 860:     }
 861:     if (outfile != nil) {
 862:         outto(outfile);
 863:     }
 864:     execv(argv[0], argv);
 865:     _exit(1);
 866:     }
 867:     pwait(p->pid, &status);
 868:     getinfo(p, status);
 869:     if (p->status != STOPPED) {
 870:     beginerrmsg();
 871:     fprintf(stderr, "warning: cannot execute %s\n", argv[0]);
 872:     } else {
 873:     ptraced(p->pid);
 874:     }
 875: }
 876: 
 877: /*
 878:  * Terminate a ptrace'd process.
 879:  */
 880: 
 881: public pterm (p)
 882: Process p;
 883: {
 884:     integer status;
 885: 
 886:     if (p != nil and p->pid != 0) {
 887:     ptrace(PKILL, p->pid, 0, 0);
 888:     pwait(p->pid, &status);
 889:     unptraced(p->pid);
 890:     }
 891: }
 892: 
 893: /*
 894:  * Continue a stopped process.  The first argument points to a Process
 895:  * structure.  Before the process is restarted it's user area is modified
 896:  * according to the values in the structure.  When this routine finishes,
 897:  * the structure has the new values from the process's user area.
 898:  *
 899:  * Pcont terminates when the process stops with a signal pending that
 900:  * is being traced (via psigtrace), or when the process terminates.
 901:  */
 902: 
 903: private pcont(p, signo)
 904: Process p;
 905: int signo;
 906: {
 907:     int s, status;
 908: 
 909:     if (p->pid == 0) {
 910:     error("program is not active");
 911:     }
 912:     s = signo;
 913:     do {
 914:     setinfo(p, s);
 915:     if (traceexec) {
 916:         printf("!! pcont from 0x%x with signal %d (%d)\n",
 917:         p->reg[PROGCTR], s, p->signo);
 918:         fflush(stdout);
 919:     }
 920:     sigs_off();
 921:     if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) {
 922:         panic("error %d trying to continue process", errno);
 923:     }
 924:     pwait(p->pid, &status);
 925:     sigs_on();
 926:     getinfo(p, status);
 927:     if (p->status == STOPPED and traceexec and not istraced(p)) {
 928:         printf("!! ignored signal %d at 0x%x\n",
 929:         p->signo, p->reg[PROGCTR]);
 930:         fflush(stdout);
 931:     }
 932:     s = p->signo;
 933:     } while (p->status == STOPPED and not istraced(p));
 934:     if (traceexec) {
 935:     printf("!! pcont to 0x%x on signal %d\n", p->reg[PROGCTR], p->signo);
 936:     fflush(stdout);
 937:     }
 938: }
 939: 
 940: /*
 941:  * Single step as best ptrace can.
 942:  */
 943: 
 944: public pstep(p, signo)
 945: Process p;
 946: integer signo;
 947: {
 948:     int s, status;
 949: 
 950:     s = signo;
 951:     do {
 952:     setinfo(p, s);
 953:     if (traceexec) {
 954:         printf("!! pstep from 0x%x with signal %d (%d)\n",
 955:         p->reg[PROGCTR], s, p->signo);
 956:         fflush(stdout);
 957:     }
 958:     sigs_off();
 959:     if (ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo) < 0) {
 960:         panic("error %d trying to step process", errno);
 961:     }
 962:     pwait(p->pid, &status);
 963:     sigs_on();
 964:     getinfo(p, status);
 965:     if (p->status == STOPPED and traceexec and not istraced(p)) {
 966:         printf("!! pstep ignored signal %d at 0x%x\n",
 967:         p->signo, p->reg[PROGCTR]);
 968:         fflush(stdout);
 969:     }
 970:     s = p->signo;
 971:     } while (p->status == STOPPED and not istraced(p));
 972:     if (traceexec) {
 973:     printf("!! pstep to 0x%x on signal %d\n",
 974:         p->reg[PROGCTR], p->signo);
 975:     fflush(stdout);
 976:     }
 977:     if (p->status != STOPPED) {
 978:     if (p->exitval == 0) {
 979:         error("program exited\n");
 980:     } else {
 981:         error("program exited with code %d\n", p->exitval);
 982:     }
 983:     }
 984: }
 985: 
 986: /*
 987:  * Return from execution when the given signal is pending.
 988:  */
 989: 
 990: public psigtrace(p, sig, sw)
 991: Process p;
 992: int sig;
 993: Boolean sw;
 994: {
 995:     if (sw) {
 996:     p->sigset |= setrep(sig);
 997:     } else {
 998:     p->sigset &= ~setrep(sig);
 999:     }
1000: }
1001: 
1002: /*
1003:  * Don't catch any signals.
1004:  * Particularly useful when letting a process finish uninhibited.
1005:  */
1006: 
1007: public unsetsigtraces(p)
1008: Process p;
1009: {
1010:     p->sigset = 0;
1011: }
1012: 
1013: /*
1014:  * Turn off attention to signals not being caught.
1015:  */
1016: 
1017: private Intfunc *sigfunc[NSIG];
1018: 
1019: private sigs_off()
1020: {
1021:     register int i;
1022: 
1023:     for (i = FIRSTSIG; i < LASTSIG; i++) {
1024:     if (i != SIGKILL) {
1025:         sigfunc[i] = signal(i, SIG_IGN);
1026:     }
1027:     }
1028: }
1029: 
1030: /*
1031:  * Turn back on attention to signals.
1032:  */
1033: 
1034: private sigs_on()
1035: {
1036:     register int i;
1037: 
1038:     for (i = FIRSTSIG; i < LASTSIG; i++) {
1039:     if (i != SIGKILL) {
1040:         signal(i, sigfunc[i]);
1041:     }
1042:     }
1043: }
1044: 
1045: /*
1046:  * Get process information from user area.
1047:  */
1048: 
1049: private int rloc[] ={
1050:     R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC
1051: };
1052: 
1053: private getinfo(p, status)
1054: register Process p;
1055: register int status;
1056: {
1057:     register int i;
1058:     Address addr;
1059: 
1060:     p->signo = (status&0177);
1061:     p->exitval = ((status >> 8)&0377);
1062:     if (p->signo != STOPPED) {
1063:     p->status = FINISHED;
1064:     p->pid = 0;
1065:     p->reg[PROGCTR] = 0;
1066:     } else {
1067:     p->status = p->signo;
1068:     p->signo = p->exitval;
1069:     p->sigcode = ptrace(UREAD, p->pid, &((struct user *) 0)->u_code, 0);
1070:     p->exitval = 0;
1071:     p->mask = ptrace(UREAD, p->pid, regloc(PS), 0);
1072:     for (i = 0; i < NREG; i++) {
1073:         p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0);
1074:         p->oreg[i] = p->reg[i];
1075:     }
1076:     savetty(stdout, &(p->ttyinfo));
1077:     addr = (Address) &(((struct user *) 0)->u_signal[p->signo]);
1078:     p->sigstatus = (Address) ptrace(UREAD, p->pid, addr, 0);
1079:     }
1080: }
1081: 
1082: /*
1083:  * Set process's user area information from given process structure.
1084:  */
1085: 
1086: private setinfo(p, signo)
1087: register Process p;
1088: int signo;
1089: {
1090:     register int i;
1091:     register int r;
1092: 
1093:     if (signo == DEFSIG) {
1094:     if (istraced(p) and (p->sigstatus == 0 or p->sigstatus == 1)) {
1095:         p->signo = 0;
1096:     }
1097:     } else {
1098:     p->signo = signo;
1099:     }
1100:     for (i = 0; i < NREG; i++) {
1101:     if ((r = p->reg[i]) != p->oreg[i]) {
1102:         ptrace(UWRITE, p->pid, regloc(rloc[i]), r);
1103:     }
1104:     }
1105:     restoretty(stdout, &(p->ttyinfo));
1106: }
1107: 
1108: /*
1109:  * Return the address associated with the current signal.
1110:  * (Plus two since the address points to the beginning of a procedure).
1111:  */
1112: 
1113: public Address usignal (p)
1114: Process p;
1115: {
1116:     Address r;
1117: 
1118:     r = p->sigstatus;
1119:     if (r != 0 and r != 1) {
1120:     r += 2;
1121:     }
1122:     return r;
1123: }
1124: 
1125: /*
1126:  * Structure for reading and writing by words, but dealing with bytes.
1127:  */
1128: 
1129: typedef union {
1130:     Word pword;
1131:     Byte pbyte[sizeof(Word)];
1132: } Pword;
1133: 
1134: /*
1135:  * Read (write) from (to) the process' address space.
1136:  * We must deal with ptrace's inability to look anywhere other
1137:  * than at a word boundary.
1138:  */
1139: 
1140: private Word fetch();
1141: private store();
1142: 
1143: private pio(p, op, seg, buff, addr, nbytes)
1144: Process p;
1145: PioOp op;
1146: PioSeg seg;
1147: char *buff;
1148: Address addr;
1149: int nbytes;
1150: {
1151:     register int i;
1152:     register Address newaddr;
1153:     register char *cp;
1154:     char *bufend;
1155:     Pword w;
1156:     Address wordaddr;
1157:     int byteoff;
1158: 
1159:     if (p->status != STOPPED) {
1160:     error("program is not active");
1161:     }
1162:     cp = buff;
1163:     newaddr = addr;
1164:     wordaddr = (newaddr&WMASK);
1165:     if (wordaddr != newaddr) {
1166:     w.pword = fetch(p, seg, wordaddr);
1167:     for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) {
1168:         if (op == PREAD) {
1169:         *cp++ = w.pbyte[i];
1170:         } else {
1171:         w.pbyte[i] = *cp++;
1172:         }
1173:         nbytes--;
1174:     }
1175:     if (op == PWRITE) {
1176:         store(p, seg, wordaddr, w.pword);
1177:     }
1178:     newaddr = wordaddr + sizeof(Word);
1179:     }
1180:     byteoff = (nbytes&(~WMASK));
1181:     nbytes -= byteoff;
1182:     bufend = cp + nbytes;
1183:     while (cp < bufend) {
1184:     if (op == PREAD) {
1185:         *((Word *) cp) = fetch(p, seg, newaddr);
1186:     } else {
1187:         store(p, seg, newaddr, *((Word *) cp));
1188:     }
1189:     cp += sizeof(Word);
1190:     newaddr += sizeof(Word);
1191:     }
1192:     if (byteoff > 0) {
1193:     w.pword = fetch(p, seg, newaddr);
1194:     for (i = 0; i < byteoff; i++) {
1195:         if (op == PREAD) {
1196:         *cp++ = w.pbyte[i];
1197:         } else {
1198:         w.pbyte[i] = *cp++;
1199:         }
1200:     }
1201:     if (op == PWRITE) {
1202:         store(p, seg, newaddr, w.pword);
1203:     }
1204:     }
1205: }
1206: 
1207: /*
1208:  * Get a word from a process at the given address.
1209:  * The address is assumed to be on a word boundary.
1210:  *
1211:  * A simple cache scheme is used to avoid redundant ptrace calls
1212:  * to the instruction space since it is assumed to be pure.
1213:  *
1214:  * It is necessary to use a write-through scheme so that
1215:  * breakpoints right next to each other don't interfere.
1216:  */
1217: 
1218: private Integer nfetchs, nreads, nwrites;
1219: 
1220: private Word fetch(p, seg, addr)
1221: Process p;
1222: PioSeg seg;
1223: register int addr;
1224: {
1225:     register CacheWord *wp;
1226:     register Word w;
1227: 
1228:     switch (seg) {
1229:     case TEXTSEG:
1230:         ++nfetchs;
1231:         wp = &p->word[cachehash(addr)];
1232:         if (addr == 0 or wp->addr != addr) {
1233:         ++nreads;
1234:         w = ptrace(IREAD, p->pid, addr, 0);
1235:         wp->addr = addr;
1236:         wp->val = w;
1237:         } else {
1238:         w = wp->val;
1239:         }
1240:         break;
1241: 
1242:     case DATASEG:
1243:         w = ptrace(DREAD, p->pid, addr, 0);
1244:         break;
1245: 
1246:     default:
1247:         panic("fetch: bad seg %d", seg);
1248:         /* NOTREACHED */
1249:     }
1250:     return w;
1251: }
1252: 
1253: /*
1254:  * Put a word into the process' address space at the given address.
1255:  * The address is assumed to be on a word boundary.
1256:  */
1257: 
1258: private store(p, seg, addr, data)
1259: Process p;
1260: PioSeg seg;
1261: int addr;
1262: Word data;
1263: {
1264:     register CacheWord *wp;
1265: 
1266:     switch (seg) {
1267:     case TEXTSEG:
1268:         ++nwrites;
1269:         wp = &p->word[cachehash(addr)];
1270:         wp->addr = addr;
1271:         wp->val = data;
1272:         ptrace(IWRITE, p->pid, addr, data);
1273:         break;
1274: 
1275:     case DATASEG:
1276:         ptrace(DWRITE, p->pid, addr, data);
1277:         break;
1278: 
1279:     default:
1280:         panic("store: bad seg %d", seg);
1281:         /* NOTREACHED */
1282:     }
1283: }
1284: 
1285: /*
1286:  * Flush the instruction cache associated with a process.
1287:  */
1288: 
1289: private cacheflush (p)
1290: Process p;
1291: {
1292:     bzero(p->word, sizeof(p->word));
1293: }
1294: 
1295: public printptraceinfo()
1296: {
1297:     printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites);
1298: }
1299: 
1300: /*
1301:  * Redirect input.
1302:  * Assuming this is called from a child, we should be careful to avoid
1303:  * (possibly) shared standard I/O buffers.
1304:  */
1305: 
1306: private infrom (filename)
1307: String filename;
1308: {
1309:     Fileid in;
1310: 
1311:     in = open(filename, 0);
1312:     if (in == -1) {
1313:     write(2, "can't read ", 11);
1314:     write(2, filename, strlen(filename));
1315:     write(2, "\n", 1);
1316:     _exit(1);
1317:     }
1318:     fswap(0, in);
1319: }
1320: 
1321: /*
1322:  * Redirect standard output.
1323:  * Same assumptions as for "infrom" above.
1324:  */
1325: 
1326: private outto (filename)
1327: String filename;
1328: {
1329:     Fileid out;
1330: 
1331:     out = creat(filename, 0666);
1332:     if (out == -1) {
1333:     write(2, "can't write ", 12);
1334:     write(2, filename, strlen(filename));
1335:     write(2, "\n", 1);
1336:     _exit(1);
1337:     }
1338:     fswap(1, out);
1339: }
1340: 
1341: /*
1342:  * Swap file numbers, useful for redirecting standard input or output.
1343:  */
1344: 
1345: private fswap(oldfd, newfd)
1346: Fileid oldfd;
1347: Fileid newfd;
1348: {
1349:     if (oldfd != newfd) {
1350:     close(oldfd);
1351:     dup(newfd);
1352:     close(newfd);
1353:     }
1354: }
1355: 
1356: /*
1357:  * Signal name manipulation.
1358:  */
1359: 
1360: private String signames[NSIG] = {
1361:     0,
1362:     "HUP", "INT", "QUIT", "ILL", "TRAP",
1363:     "IOT", "EMT", "FPE", "KILL", "BUS",
1364:     "SEGV", "SYS", "PIPE", "ALRM", "TERM",
1365:     0, "STOP", "TSTP", "CONT", "CHLD",
1366:     "TTIN", "TTOU", "TINT", "XCPU", "XFSZ",
1367: };
1368: 
1369: /*
1370:  * Get the signal number associated with a given name.
1371:  * The name is first translated to upper case if necessary.
1372:  */
1373: 
1374: public integer siglookup (s)
1375: String s;
1376: {
1377:     register char *p, *q;
1378:     char buf[100];
1379:     integer i;
1380: 
1381:     p = s;
1382:     q = buf;
1383:     while (*p != '\0') {
1384:     if (*p >= 'a' and *p <= 'z') {
1385:         *q = (*p - 'a') + 'A';
1386:     } else {
1387:         *q = *p;
1388:     }
1389:     ++p;
1390:     ++q;
1391:     }
1392:     *q = '\0';
1393:     p = buf;
1394:     if (buf[0] == 'S' and buf[1] == 'I' and buf[2] == 'G') {
1395:     p += 3;
1396:     }
1397:     i = 1;
1398:     for (;;) {
1399:     if (i >= sizeof(signames) div sizeof(signames[0])) {
1400:         error("signal \"%s\" unknown", s);
1401:         i = 0;
1402:         break;
1403:     }
1404:     if (signames[i] != nil and streq(signames[i], p)) {
1405:         break;
1406:     }
1407:     ++i;
1408:     }
1409:     return i;
1410: }
1411: 
1412: /*
1413:  * Print all signals being ignored by the debugger.
1414:  * These signals are auotmatically
1415:  * passed on to the debugged process.
1416:  */
1417: 
1418: public printsigsignored (p)
1419: Process p;
1420: {
1421:     printsigs(~p->sigset);
1422: }
1423: 
1424: /*
1425:  * Print all signals being intercepted by
1426:  * the debugger for the specified process.
1427:  */
1428: 
1429: public printsigscaught(p)
1430: Process p;
1431: {
1432:     printsigs(p->sigset);
1433: }
1434: 
1435: private printsigs (set)
1436: integer set;
1437: {
1438:     integer s;
1439:     char separator[2];
1440: 
1441:     separator[0] = '\0';
1442:     for (s = 1; s < sizeof(signames) div sizeof(signames[0]); s++) {
1443:     if (set & setrep(s)) {
1444:         if (signames[s] != nil) {
1445:         printf("%s%s", separator, signames[s]);
1446:         separator[0] = ' ';
1447:         separator[1] = '\0';
1448:         }
1449:     }
1450:     }
1451:     if (separator[0] == ' ') {
1452:     putchar('\n');
1453:     }
1454: }

Defined functions

arginit defined in line 244; used 3 times
cacheflush defined in line 1289; used 1 times
cont defined in line 319; used 3 times
contto defined in line 516; used 2 times
dwrite defined in line 757; used 8 times
errcode defined in line 657; used 1 times
errnum defined in line 647; used 1 times
exitcode defined in line 667; used 5 times
fetch defined in line 1220; used 4 times
fixintr defined in line 367; used 1 times
fswap defined in line 1345; used 2 times
getinfo defined in line 1053; used 3 times
inarg defined in line 269; used 1 times
infrom defined in line 1306; used 1 times
intr defined in line 362; used 3 times
iread defined in line 692; used 18 times
isbperr defined in line 628; used 7 times
isfinished defined in line 614; used 3 times
iwrite defined in line 714; used 4 times
newarg defined in line 256; used 3 times
next defined in line 420; used 1 times
notstarted defined in line 608; used 1 times
outarg defined in line 283; used 1 times
outto defined in line 1326; used 1 times
pcont defined in line 903; used 1 times
pio defined in line 1143; used 4 times
printloc defined in line 590; used 2 times
printptraceinfo defined in line 1295; never used
printsigs defined in line 1435; used 2 times
printsigscaught defined in line 1429; used 1 times
printsigsignored defined in line 1418; used 1 times
printstatus defined in line 556; used 8 times
process_init defined in line 110; used 2 times
psigtrace defined in line 990; used 10 times
pstart defined in line 837; used 1 times
pstep defined in line 944; used 4 times
pterm defined in line 881; used 2 times
read_err defined in line 779; used 4 times
reg defined in line 138; used 55 times
remade defined in line 207; used 2 times
resume defined in line 376; used 2 times
rtnfunc defined in line 443; used 2 times
run defined in line 296; used 5 times
setinfo defined in line 1086; used 2 times
setsigtrace defined in line 223; used 1 times
siglookup defined in line 1374; used 1 times
sigs_off defined in line 1019; used 2 times
sigs_on defined in line 1034; used 2 times
start defined in line 167; used 3 times
stepc defined in line 410; used 1 times
stepover defined in line 485; used 3 times
stepto defined in line 510; used 8 times
store defined in line 1258; used 4 times
unsetsigtraces defined in line 1007; never used
usignal defined in line 1113; used 1 times
write_err defined in line 786; used 3 times
xto defined in line 522; used 2 times

Defined variables

argc defined in line 102; used 4 times
argv defined in line 103; used 15 times
infile defined in line 104; used 12 times
nfetchs defined in line 1218; used 2 times
nreads defined in line 1218; used 2 times
nwrites defined in line 1218; used 2 times
outfile defined in line 104; used 12 times
pbuf defined in line 95; used 1 times
process defined in line 44; used 25 times
rcsid defined in line 11; never used
rloc defined in line 1049; used 2 times
sccsid defined in line 8; never used
signames defined in line 1360; used 8 times

Defined struct's

Process defined in line 73; used 3 times

Defined typedef's

Process defined in line 42; used 24 times

Defined macros

CONT defined in line 822; used 1 times
CSIZE defined in line 62; used 2 times
DEFSIG defined in line 46; used 3 times
DREAD defined in line 820; used 1 times
DWRITE defined in line 821; used 1 times
FINISHED defined in line 54; used 3 times
FIRSTSIG defined in line 805; used 2 times
IREAD defined in line 818; used 1 times
IWRITE defined in line 819; used 1 times
LASTSIG defined in line 806; used 2 times
MAXNCMDARGS defined in line 97; used 2 times
NOTSTARTED defined in line 52; used 2 times
PKILL defined in line 824; used 1 times
SSTEP defined in line 823; used 1 times
STOPPED defined in line 53; used 13 times
UREAD defined in line 816; used 4 times
UWRITE defined in line 817; used 1 times
WMASK defined in line 802; used 2 times
cachehash defined in line 803; used 2 times
ischild defined in line 807; used 1 times
istraced defined in line 810; used 5 times
regloc defined in line 800; used 3 times
setrep defined in line 809; used 4 times
traceme defined in line 808; used 1 times
Last modified: 1985-05-31
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3961
Valid CSS Valid XHTML 1.0 Strict