1*9677Slinton /* Copyright (c) 1982 Regents of the University of California */ 2*9677Slinton 3*9677Slinton static char sccsid[] = "@(#)@(#)process.c 1.1 12/15/82"; 4*9677Slinton 5*9677Slinton /* 6*9677Slinton * Process management. 7*9677Slinton * 8*9677Slinton * This module contains the routines to manage the execution and 9*9677Slinton * tracing of the debuggee process. 10*9677Slinton */ 11*9677Slinton 12*9677Slinton #include "defs.h" 13*9677Slinton #include "process.h" 14*9677Slinton #include "machine.h" 15*9677Slinton #include "events.h" 16*9677Slinton #include "tree.h" 17*9677Slinton #include "operators.h" 18*9677Slinton #include "source.h" 19*9677Slinton #include "object.h" 20*9677Slinton #include "mappings.h" 21*9677Slinton #include "main.h" 22*9677Slinton #include "coredump.h" 23*9677Slinton #include <signal.h> 24*9677Slinton #include <errno.h> 25*9677Slinton #include <sys/param.h> 26*9677Slinton #include <sys/reg.h> 27*9677Slinton #include <sys/stat.h> 28*9677Slinton 29*9677Slinton #ifndef public 30*9677Slinton 31*9677Slinton typedef struct Process *Process; 32*9677Slinton 33*9677Slinton Process process; 34*9677Slinton 35*9677Slinton #include "machine.h" 36*9677Slinton 37*9677Slinton #endif 38*9677Slinton 39*9677Slinton #define NOTSTARTED 1 40*9677Slinton #define STOPPED 0177 41*9677Slinton #define FINISHED 0 42*9677Slinton 43*9677Slinton /* 44*9677Slinton * Cache-ing of instruction segment is done to reduce the number 45*9677Slinton * of system calls. 46*9677Slinton */ 47*9677Slinton 48*9677Slinton #define CSIZE 1003 /* size of instruction cache */ 49*9677Slinton 50*9677Slinton typedef struct { 51*9677Slinton Word addr; 52*9677Slinton Word val; 53*9677Slinton } CacheWord; 54*9677Slinton 55*9677Slinton /* 56*9677Slinton * This structure holds the information we need from the user structure. 57*9677Slinton */ 58*9677Slinton 59*9677Slinton struct Process { 60*9677Slinton int pid; /* process being traced */ 61*9677Slinton int mask; /* ps */ 62*9677Slinton Word reg[NREG]; /* process's registers */ 63*9677Slinton Word oreg[NREG]; /* registers when process last stopped */ 64*9677Slinton short status; /* either STOPPED or FINISHED */ 65*9677Slinton short signo; /* signal that stopped process */ 66*9677Slinton int exitval; /* return value from exit() */ 67*9677Slinton long sigset; /* bit array of traced signals */ 68*9677Slinton CacheWord word[CSIZE]; /* text segment cache */ 69*9677Slinton }; 70*9677Slinton 71*9677Slinton /* 72*9677Slinton * These definitions are for the arguments to "pio". 73*9677Slinton */ 74*9677Slinton 75*9677Slinton typedef enum { PREAD, PWRITE } PioOp; 76*9677Slinton typedef enum { TEXTSEG, DATASEG } PioSeg; 77*9677Slinton 78*9677Slinton private struct Process pbuf; 79*9677Slinton 80*9677Slinton #define MAXNCMDARGS 10 /* maximum number of arguments to RUN */ 81*9677Slinton 82*9677Slinton private Boolean just_started; 83*9677Slinton private int argc; 84*9677Slinton private String argv[MAXNCMDARGS]; 85*9677Slinton private String infile, outfile; 86*9677Slinton 87*9677Slinton /* 88*9677Slinton * Initialize process information. 89*9677Slinton */ 90*9677Slinton 91*9677Slinton public process_init() 92*9677Slinton { 93*9677Slinton register Integer i; 94*9677Slinton Char buf[10]; 95*9677Slinton 96*9677Slinton process = &pbuf; 97*9677Slinton process->status = (coredump) ? STOPPED : NOTSTARTED; 98*9677Slinton setsigtrace(); 99*9677Slinton for (i = 0; i < NREG; i++) { 100*9677Slinton sprintf(buf, "$r%d", i); 101*9677Slinton defregname(identname(buf, false), i); 102*9677Slinton } 103*9677Slinton defregname(identname("$ap", true), ARGP); 104*9677Slinton defregname(identname("$fp", true), FRP); 105*9677Slinton defregname(identname("$sp", true), STKP); 106*9677Slinton defregname(identname("$pc", true), PROGCTR); 107*9677Slinton if (coredump) { 108*9677Slinton coredump_readin(process->mask, process->reg, process->signo); 109*9677Slinton } 110*9677Slinton } 111*9677Slinton 112*9677Slinton /* 113*9677Slinton * Routines to get at process information from outside this module. 114*9677Slinton */ 115*9677Slinton 116*9677Slinton public Word reg(n) 117*9677Slinton Integer n; 118*9677Slinton { 119*9677Slinton register Word w; 120*9677Slinton 121*9677Slinton if (n == NREG) { 122*9677Slinton w = process->mask; 123*9677Slinton } else { 124*9677Slinton w = process->reg[n]; 125*9677Slinton } 126*9677Slinton return w; 127*9677Slinton } 128*9677Slinton 129*9677Slinton public setreg(n, w) 130*9677Slinton Integer n; 131*9677Slinton Word w; 132*9677Slinton { 133*9677Slinton process->reg[n] = w; 134*9677Slinton } 135*9677Slinton 136*9677Slinton /* 137*9677Slinton * Begin execution. 138*9677Slinton * 139*9677Slinton * We set a breakpoint at the end of the code so that the 140*9677Slinton * process data doesn't disappear after the program terminates. 141*9677Slinton */ 142*9677Slinton 143*9677Slinton private Boolean remade(); 144*9677Slinton 145*9677Slinton public start(argv, infile, outfile) 146*9677Slinton String argv[]; 147*9677Slinton String infile, outfile; 148*9677Slinton { 149*9677Slinton String pargv[4]; 150*9677Slinton Node cond; 151*9677Slinton 152*9677Slinton if (coredump) { 153*9677Slinton coredump = false; 154*9677Slinton fclose(corefile); 155*9677Slinton coredump_close(); 156*9677Slinton } 157*9677Slinton if (argv == nil) { 158*9677Slinton argv = pargv; 159*9677Slinton pargv[0] = objname; 160*9677Slinton pargv[1] = nil; 161*9677Slinton } else { 162*9677Slinton argv[argc] = nil; 163*9677Slinton } 164*9677Slinton if (remade(objname)) { 165*9677Slinton reinit(argv, infile, outfile); 166*9677Slinton } 167*9677Slinton pstart(process, argv, infile, outfile); 168*9677Slinton if (process->status == STOPPED) { 169*9677Slinton pc = 0; 170*9677Slinton curfunc = program; 171*9677Slinton if (objsize != 0) { 172*9677Slinton cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr())); 173*9677Slinton event_once(cond, buildcmdlist(build(O_ENDX))); 174*9677Slinton } 175*9677Slinton } 176*9677Slinton } 177*9677Slinton 178*9677Slinton /* 179*9677Slinton * Check to see if the object file has changed since the symbolic 180*9677Slinton * information last was read. 181*9677Slinton */ 182*9677Slinton 183*9677Slinton private time_t modtime; 184*9677Slinton 185*9677Slinton private Boolean remade(filename) 186*9677Slinton String filename; 187*9677Slinton { 188*9677Slinton struct stat s; 189*9677Slinton Boolean b; 190*9677Slinton 191*9677Slinton stat(filename, &s); 192*9677Slinton b = (Boolean) (modtime != 0 and modtime < s.st_mtime); 193*9677Slinton modtime = s.st_mtime; 194*9677Slinton return b; 195*9677Slinton } 196*9677Slinton 197*9677Slinton /* 198*9677Slinton * Set up what signals we want to trace. 199*9677Slinton */ 200*9677Slinton 201*9677Slinton private setsigtrace() 202*9677Slinton { 203*9677Slinton register Integer i; 204*9677Slinton register Process p; 205*9677Slinton 206*9677Slinton p = process; 207*9677Slinton for (i = 1; i <= NSIG; i++) { 208*9677Slinton psigtrace(p, i, true); 209*9677Slinton } 210*9677Slinton psigtrace(p, SIGHUP, false); 211*9677Slinton psigtrace(p, SIGKILL, false); 212*9677Slinton psigtrace(p, SIGALRM, false); 213*9677Slinton psigtrace(p, SIGTSTP, false); 214*9677Slinton psigtrace(p, SIGCONT, false); 215*9677Slinton psigtrace(p, SIGCHLD, false); 216*9677Slinton } 217*9677Slinton 218*9677Slinton /* 219*9677Slinton * Initialize the argument list. 220*9677Slinton */ 221*9677Slinton 222*9677Slinton public arginit() 223*9677Slinton { 224*9677Slinton infile = nil; 225*9677Slinton outfile = nil; 226*9677Slinton argv[0] = objname; 227*9677Slinton argc = 1; 228*9677Slinton } 229*9677Slinton 230*9677Slinton /* 231*9677Slinton * Add an argument to the list for the debuggee. 232*9677Slinton */ 233*9677Slinton 234*9677Slinton public newarg(arg) 235*9677Slinton String arg; 236*9677Slinton { 237*9677Slinton if (argc >= MAXNCMDARGS) { 238*9677Slinton error("too many arguments"); 239*9677Slinton } 240*9677Slinton argv[argc++] = arg; 241*9677Slinton } 242*9677Slinton 243*9677Slinton /* 244*9677Slinton * Set the standard input for the debuggee. 245*9677Slinton */ 246*9677Slinton 247*9677Slinton public inarg(filename) 248*9677Slinton String filename; 249*9677Slinton { 250*9677Slinton if (infile != nil) { 251*9677Slinton error("multiple input redirects"); 252*9677Slinton } 253*9677Slinton infile = filename; 254*9677Slinton } 255*9677Slinton 256*9677Slinton /* 257*9677Slinton * Set the standard output for the debuggee. 258*9677Slinton * Probably should check to avoid overwriting an existing file. 259*9677Slinton */ 260*9677Slinton 261*9677Slinton public outarg(filename) 262*9677Slinton String filename; 263*9677Slinton { 264*9677Slinton if (outfile != nil) { 265*9677Slinton error("multiple output redirect"); 266*9677Slinton } 267*9677Slinton outfile = filename; 268*9677Slinton } 269*9677Slinton 270*9677Slinton /* 271*9677Slinton * Start debuggee executing. 272*9677Slinton */ 273*9677Slinton 274*9677Slinton public run() 275*9677Slinton { 276*9677Slinton process->status = STOPPED; 277*9677Slinton fixbps(); 278*9677Slinton curline = 0; 279*9677Slinton start(argv, infile, outfile); 280*9677Slinton just_started = true; 281*9677Slinton isstopped = false; 282*9677Slinton cont(); 283*9677Slinton } 284*9677Slinton 285*9677Slinton /* 286*9677Slinton * Continue execution wherever we left off. 287*9677Slinton * 288*9677Slinton * Note that this routine never returns. Eventually bpact() will fail 289*9677Slinton * and we'll call printstatus or step will call it. 290*9677Slinton */ 291*9677Slinton 292*9677Slinton typedef int Intfunc(); 293*9677Slinton 294*9677Slinton private Intfunc *dbintr; 295*9677Slinton private intr(); 296*9677Slinton 297*9677Slinton #define succeeds == true 298*9677Slinton #define fails == false 299*9677Slinton 300*9677Slinton public cont() 301*9677Slinton { 302*9677Slinton dbintr = signal(SIGINT, intr); 303*9677Slinton if (just_started) { 304*9677Slinton just_started = false; 305*9677Slinton } else { 306*9677Slinton if (not isstopped) { 307*9677Slinton error("can't continue execution"); 308*9677Slinton } 309*9677Slinton isstopped = false; 310*9677Slinton step(); 311*9677Slinton } 312*9677Slinton for (;;) { 313*9677Slinton if (single_stepping) { 314*9677Slinton printnews(); 315*9677Slinton } else { 316*9677Slinton setallbps(); 317*9677Slinton resume(); 318*9677Slinton unsetallbps(); 319*9677Slinton if (bpact() fails) { 320*9677Slinton printstatus(); 321*9677Slinton } 322*9677Slinton } 323*9677Slinton step(); 324*9677Slinton } 325*9677Slinton /* NOTREACHED */ 326*9677Slinton } 327*9677Slinton 328*9677Slinton /* 329*9677Slinton * This routine is called if we get an interrupt while "running" px 330*9677Slinton * but actually in the debugger. Could happen, for example, while 331*9677Slinton * processing breakpoints. 332*9677Slinton * 333*9677Slinton * We basically just want to keep going; the assumption is 334*9677Slinton * that when the process resumes it will get the interrupt 335*9677Slinton * which will then be handled. 336*9677Slinton */ 337*9677Slinton 338*9677Slinton private intr() 339*9677Slinton { 340*9677Slinton signal(SIGINT, intr); 341*9677Slinton } 342*9677Slinton 343*9677Slinton public fixintr() 344*9677Slinton { 345*9677Slinton signal(SIGINT, dbintr); 346*9677Slinton } 347*9677Slinton 348*9677Slinton /* 349*9677Slinton * Resume execution. 350*9677Slinton */ 351*9677Slinton 352*9677Slinton public resume() 353*9677Slinton { 354*9677Slinton register Process p; 355*9677Slinton 356*9677Slinton p = process; 357*9677Slinton if (traceexec) { 358*9677Slinton printf("execution resumes at pc 0x%x\n", process->reg[PROGCTR]); 359*9677Slinton fflush(stdout); 360*9677Slinton } 361*9677Slinton pcont(p); 362*9677Slinton pc = process->reg[PROGCTR]; 363*9677Slinton if (traceexec) { 364*9677Slinton printf("execution stops at pc 0x%x on sig %d\n", 365*9677Slinton process->reg[PROGCTR], p->signo); 366*9677Slinton fflush(stdout); 367*9677Slinton } 368*9677Slinton } 369*9677Slinton 370*9677Slinton /* 371*9677Slinton * Continue execution up to the next source line. 372*9677Slinton * 373*9677Slinton * There are two ways to define the next source line depending on what 374*9677Slinton * is desired when a procedure or function call is encountered. Step 375*9677Slinton * stops at the beginning of the procedure or call; next skips over it. 376*9677Slinton */ 377*9677Slinton 378*9677Slinton /* 379*9677Slinton * Stepc is what is called when the step command is given. 380*9677Slinton * It has to play with the "isstopped" information. 381*9677Slinton */ 382*9677Slinton 383*9677Slinton public stepc() 384*9677Slinton { 385*9677Slinton if (not isstopped) { 386*9677Slinton error("can't continue execution"); 387*9677Slinton } 388*9677Slinton isstopped = false; 389*9677Slinton dostep(false); 390*9677Slinton isstopped = true; 391*9677Slinton } 392*9677Slinton 393*9677Slinton public next() 394*9677Slinton { 395*9677Slinton if (not isstopped) { 396*9677Slinton error("can't continue execution"); 397*9677Slinton } 398*9677Slinton isstopped = false; 399*9677Slinton dostep(true); 400*9677Slinton isstopped = true; 401*9677Slinton } 402*9677Slinton 403*9677Slinton public step() 404*9677Slinton { 405*9677Slinton dostep(false); 406*9677Slinton } 407*9677Slinton 408*9677Slinton /* 409*9677Slinton * Resume execution up to the given address. It is assumed that 410*9677Slinton * no breakpoints exist between the current address and the one 411*9677Slinton * we're stepping to. This saves us from setting all the breakpoints. 412*9677Slinton */ 413*9677Slinton 414*9677Slinton public stepto(addr) 415*9677Slinton Address addr; 416*9677Slinton { 417*9677Slinton setbp(addr); 418*9677Slinton resume(); 419*9677Slinton unsetbp(addr); 420*9677Slinton if (not isbperr()) { 421*9677Slinton printstatus(); 422*9677Slinton } 423*9677Slinton } 424*9677Slinton 425*9677Slinton /* 426*9677Slinton * Print the status of the process. 427*9677Slinton * This routine does not return. 428*9677Slinton */ 429*9677Slinton 430*9677Slinton public printstatus() 431*9677Slinton { 432*9677Slinton curfunc = whatblock(pc); 433*9677Slinton if (process->signo == SIGINT) { 434*9677Slinton isstopped = true; 435*9677Slinton printerror(); 436*9677Slinton } 437*9677Slinton if (isbperr() and isstopped) { 438*9677Slinton printf("stopped "); 439*9677Slinton getsrcpos(); 440*9677Slinton if (curline > 0) { 441*9677Slinton printsrcpos(); 442*9677Slinton putchar('\n'); 443*9677Slinton printlines(curline, curline); 444*9677Slinton } else { 445*9677Slinton printf("in "); 446*9677Slinton printwhich(stdout, curfunc); 447*9677Slinton printf(" at 0x%x\n", pc); 448*9677Slinton printinst(pc, pc); 449*9677Slinton } 450*9677Slinton erecover(); 451*9677Slinton } else { 452*9677Slinton fixbps(); 453*9677Slinton fixintr(); 454*9677Slinton if (process->status == FINISHED) { 455*9677Slinton exit(0); 456*9677Slinton } else { 457*9677Slinton isstopped = true; 458*9677Slinton printerror(); 459*9677Slinton } 460*9677Slinton } 461*9677Slinton } 462*9677Slinton 463*9677Slinton /* 464*9677Slinton * Some functions for testing the state of the process. 465*9677Slinton */ 466*9677Slinton 467*9677Slinton public Boolean notstarted(p) 468*9677Slinton Process p; 469*9677Slinton { 470*9677Slinton return (Boolean) (p->status == NOTSTARTED); 471*9677Slinton } 472*9677Slinton 473*9677Slinton public Boolean isfinished(p) 474*9677Slinton Process p; 475*9677Slinton { 476*9677Slinton return (Boolean) (p->status == FINISHED); 477*9677Slinton } 478*9677Slinton 479*9677Slinton /* 480*9677Slinton * Return the signal number which stopped the process. 481*9677Slinton */ 482*9677Slinton 483*9677Slinton public Integer errnum(p) 484*9677Slinton Process p; 485*9677Slinton { 486*9677Slinton return p->signo; 487*9677Slinton } 488*9677Slinton 489*9677Slinton /* 490*9677Slinton * Return the termination code of the process. 491*9677Slinton */ 492*9677Slinton 493*9677Slinton public Integer exitcode(p) 494*9677Slinton Process p; 495*9677Slinton { 496*9677Slinton return p->exitval; 497*9677Slinton } 498*9677Slinton 499*9677Slinton /* 500*9677Slinton * These routines are used to access the debuggee process from 501*9677Slinton * outside this module. 502*9677Slinton * 503*9677Slinton * They invoke "pio" which eventually leads to a call to "ptrace". 504*9677Slinton * The system generates an I/O error when a ptrace fails, we catch 505*9677Slinton * that here and assume its due to a misguided address. 506*9677Slinton */ 507*9677Slinton 508*9677Slinton extern Intfunc *onsyserr(); 509*9677Slinton 510*9677Slinton private badaddr; 511*9677Slinton private rwerr(); 512*9677Slinton 513*9677Slinton /* 514*9677Slinton * Read from the process' instruction area. 515*9677Slinton */ 516*9677Slinton 517*9677Slinton public iread(buff, addr, nbytes) 518*9677Slinton char *buff; 519*9677Slinton Address addr; 520*9677Slinton int nbytes; 521*9677Slinton { 522*9677Slinton Intfunc *f; 523*9677Slinton 524*9677Slinton f = onsyserr(EIO, rwerr); 525*9677Slinton badaddr = addr; 526*9677Slinton if (coredump) { 527*9677Slinton coredump_readtext(buff, addr, nbytes); 528*9677Slinton } else { 529*9677Slinton pio(process, PREAD, TEXTSEG, buff, addr, nbytes); 530*9677Slinton } 531*9677Slinton onsyserr(EIO, f); 532*9677Slinton } 533*9677Slinton 534*9677Slinton /* 535*9677Slinton * Write to the process' instruction area, usually in order to set 536*9677Slinton * or unset a breakpoint. 537*9677Slinton */ 538*9677Slinton 539*9677Slinton public iwrite(buff, addr, nbytes) 540*9677Slinton char *buff; 541*9677Slinton Address addr; 542*9677Slinton int nbytes; 543*9677Slinton { 544*9677Slinton Intfunc *f; 545*9677Slinton 546*9677Slinton if (coredump) { 547*9677Slinton error("no process to write to"); 548*9677Slinton } 549*9677Slinton f = onsyserr(EIO, rwerr); 550*9677Slinton badaddr = addr; 551*9677Slinton pio(process, PWRITE, TEXTSEG, buff, addr, nbytes); 552*9677Slinton onsyserr(EIO, f); 553*9677Slinton } 554*9677Slinton 555*9677Slinton /* 556*9677Slinton * Read for the process' data area. 557*9677Slinton */ 558*9677Slinton 559*9677Slinton public dread(buff, addr, nbytes) 560*9677Slinton char *buff; 561*9677Slinton Address addr; 562*9677Slinton int nbytes; 563*9677Slinton { 564*9677Slinton Intfunc *f; 565*9677Slinton 566*9677Slinton f = onsyserr(EIO, rwerr); 567*9677Slinton badaddr = addr; 568*9677Slinton if (coredump) { 569*9677Slinton coredump_readdata(buff, addr, nbytes); 570*9677Slinton } else { 571*9677Slinton pio(process, PREAD, DATASEG, buff, addr, nbytes); 572*9677Slinton } 573*9677Slinton onsyserr(EIO, f); 574*9677Slinton } 575*9677Slinton 576*9677Slinton /* 577*9677Slinton * Write to the process' data area. 578*9677Slinton */ 579*9677Slinton 580*9677Slinton public dwrite(buff, addr, nbytes) 581*9677Slinton char *buff; 582*9677Slinton Address addr; 583*9677Slinton int nbytes; 584*9677Slinton { 585*9677Slinton Intfunc *f; 586*9677Slinton 587*9677Slinton if (coredump) { 588*9677Slinton error("no process to write to"); 589*9677Slinton } 590*9677Slinton f = onsyserr(EIO, rwerr); 591*9677Slinton badaddr = addr; 592*9677Slinton pio(process, PWRITE, DATASEG, buff, addr, nbytes); 593*9677Slinton onsyserr(EIO, f); 594*9677Slinton } 595*9677Slinton 596*9677Slinton /* 597*9677Slinton * Error handler. 598*9677Slinton */ 599*9677Slinton 600*9677Slinton private rwerr() 601*9677Slinton { 602*9677Slinton error("bad read/write process address 0x%x", badaddr); 603*9677Slinton } 604*9677Slinton 605*9677Slinton /* 606*9677Slinton * Ptrace interface. 607*9677Slinton */ 608*9677Slinton 609*9677Slinton /* 610*9677Slinton * This magic macro enables us to look at the process' registers 611*9677Slinton * in its user structure. Very gross. 612*9677Slinton */ 613*9677Slinton 614*9677Slinton #define regloc(reg) (ctob(UPAGES) + ( sizeof(int) * (reg) )) 615*9677Slinton 616*9677Slinton #define WMASK (~(sizeof(Word) - 1)) 617*9677Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE)) 618*9677Slinton 619*9677Slinton #define FIRSTSIG SIGINT 620*9677Slinton #define LASTSIG SIGQUIT 621*9677Slinton #define ischild(pid) ((pid) == 0) 622*9677Slinton #define traceme() ptrace(0, 0, 0, 0) 623*9677Slinton #define setrep(n) (1 << ((n)-1)) 624*9677Slinton #define istraced(p) (p->sigset&setrep(p->signo)) 625*9677Slinton 626*9677Slinton /* 627*9677Slinton * Ptrace options (specified in first argument). 628*9677Slinton */ 629*9677Slinton 630*9677Slinton #define UREAD 3 /* read from process's user structure */ 631*9677Slinton #define UWRITE 6 /* write to process's user structure */ 632*9677Slinton #define IREAD 1 /* read from process's instruction space */ 633*9677Slinton #define IWRITE 4 /* write to process's instruction space */ 634*9677Slinton #define DREAD 2 /* read from process's data space */ 635*9677Slinton #define DWRITE 5 /* write to process's data space */ 636*9677Slinton #define CONT 7 /* continue stopped process */ 637*9677Slinton #define SSTEP 9 /* continue for approximately one instruction */ 638*9677Slinton #define PKILL 8 /* terminate the process */ 639*9677Slinton 640*9677Slinton /* 641*9677Slinton * Start up a new process by forking and exec-ing the 642*9677Slinton * given argument list, returning when the process is loaded 643*9677Slinton * and ready to execute. The PROCESS information (pointed to 644*9677Slinton * by the first argument) is appropriately filled. 645*9677Slinton * 646*9677Slinton * If the given PROCESS structure is associated with an already running 647*9677Slinton * process, we terminate it. 648*9677Slinton */ 649*9677Slinton 650*9677Slinton /* VARARGS2 */ 651*9677Slinton private pstart(p, argv, infile, outfile) 652*9677Slinton Process p; 653*9677Slinton String argv[]; 654*9677Slinton String infile; 655*9677Slinton String outfile; 656*9677Slinton { 657*9677Slinton int status; 658*9677Slinton File in, out; 659*9677Slinton 660*9677Slinton if (p->pid != 0) { /* child already running? */ 661*9677Slinton ptrace(PKILL, p->pid, 0, 0); /* ... kill it! */ 662*9677Slinton } 663*9677Slinton psigtrace(p, SIGTRAP, true); 664*9677Slinton if ((p->pid = fork()) == -1) { 665*9677Slinton panic("can't fork"); 666*9677Slinton } 667*9677Slinton if (ischild(p->pid)) { 668*9677Slinton traceme(); 669*9677Slinton if (infile != nil) { 670*9677Slinton in = fopen(infile, "r"); 671*9677Slinton if (in == nil) { 672*9677Slinton printf("can't read %s\n", infile); 673*9677Slinton exit(1); 674*9677Slinton } 675*9677Slinton fswap(0, fileno(in)); 676*9677Slinton } 677*9677Slinton if (outfile != nil) { 678*9677Slinton out = fopen(outfile, "w"); 679*9677Slinton if (out == nil) { 680*9677Slinton printf("can't write %s\n", outfile); 681*9677Slinton exit(1); 682*9677Slinton } 683*9677Slinton fswap(1, fileno(out)); 684*9677Slinton } 685*9677Slinton execvp(argv[0], argv); 686*9677Slinton panic("can't exec %s", argv[0]); 687*9677Slinton } 688*9677Slinton pwait(p->pid, &status); 689*9677Slinton getinfo(p, status); 690*9677Slinton if (p->status != STOPPED) { 691*9677Slinton error("program could not begin execution"); 692*9677Slinton } 693*9677Slinton } 694*9677Slinton 695*9677Slinton /* 696*9677Slinton * Continue a stopped process. The argument points to a PROCESS structure. 697*9677Slinton * Before the process is restarted it's user area is modified according to 698*9677Slinton * the values in the structure. When this routine finishes, 699*9677Slinton * the structure has the new values from the process's user area. 700*9677Slinton * 701*9677Slinton * Pcont terminates when the process stops with a signal pending that 702*9677Slinton * is being traced (via psigtrace), or when the process terminates. 703*9677Slinton */ 704*9677Slinton 705*9677Slinton private pcont(p) 706*9677Slinton Process p; 707*9677Slinton { 708*9677Slinton int status; 709*9677Slinton 710*9677Slinton if (p->pid == 0) { 711*9677Slinton error("program not active"); 712*9677Slinton } 713*9677Slinton do { 714*9677Slinton setinfo(p); 715*9677Slinton sigs_off(); 716*9677Slinton if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) { 717*9677Slinton panic("can't continue process"); 718*9677Slinton } 719*9677Slinton pwait(p->pid, &status); 720*9677Slinton sigs_on(); 721*9677Slinton getinfo(p, status); 722*9677Slinton } while (p->status == STOPPED and not istraced(p)); 723*9677Slinton } 724*9677Slinton 725*9677Slinton /* 726*9677Slinton * Single step as best ptrace can. 727*9677Slinton */ 728*9677Slinton 729*9677Slinton public pstep(p) 730*9677Slinton Process p; 731*9677Slinton { 732*9677Slinton int status; 733*9677Slinton 734*9677Slinton setinfo(p); 735*9677Slinton sigs_off(); 736*9677Slinton ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo); 737*9677Slinton pwait(p->pid, &status); 738*9677Slinton sigs_on(); 739*9677Slinton getinfo(p, status); 740*9677Slinton } 741*9677Slinton 742*9677Slinton /* 743*9677Slinton * Return from execution when the given signal is pending. 744*9677Slinton */ 745*9677Slinton 746*9677Slinton public psigtrace(p, sig, sw) 747*9677Slinton Process p; 748*9677Slinton int sig; 749*9677Slinton Boolean sw; 750*9677Slinton { 751*9677Slinton if (sw) { 752*9677Slinton p->sigset |= setrep(sig); 753*9677Slinton } else { 754*9677Slinton p->sigset &= ~setrep(sig); 755*9677Slinton } 756*9677Slinton } 757*9677Slinton 758*9677Slinton /* 759*9677Slinton * Don't catch any signals. 760*9677Slinton * Particularly useful when letting a process finish uninhibited. 761*9677Slinton */ 762*9677Slinton 763*9677Slinton public unsetsigtraces(p) 764*9677Slinton Process p; 765*9677Slinton { 766*9677Slinton p->sigset = 0; 767*9677Slinton } 768*9677Slinton 769*9677Slinton /* 770*9677Slinton * Turn off attention to signals not being caught. 771*9677Slinton */ 772*9677Slinton 773*9677Slinton private Intfunc *sigfunc[NSIG]; 774*9677Slinton 775*9677Slinton private sigs_off() 776*9677Slinton { 777*9677Slinton register int i; 778*9677Slinton 779*9677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 780*9677Slinton if (i != SIGKILL) { 781*9677Slinton sigfunc[i] = signal(i, SIG_IGN); 782*9677Slinton } 783*9677Slinton } 784*9677Slinton } 785*9677Slinton 786*9677Slinton /* 787*9677Slinton * Turn back on attention to signals. 788*9677Slinton */ 789*9677Slinton 790*9677Slinton private sigs_on() 791*9677Slinton { 792*9677Slinton register int i; 793*9677Slinton 794*9677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 795*9677Slinton if (i != SIGKILL) { 796*9677Slinton signal(i, sigfunc[i]); 797*9677Slinton } 798*9677Slinton } 799*9677Slinton } 800*9677Slinton 801*9677Slinton /* 802*9677Slinton * Get process information from user area. 803*9677Slinton */ 804*9677Slinton 805*9677Slinton private int rloc[] ={ 806*9677Slinton R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC 807*9677Slinton }; 808*9677Slinton 809*9677Slinton private getinfo(p, status) 810*9677Slinton register Process p; 811*9677Slinton register int status; 812*9677Slinton { 813*9677Slinton register int i; 814*9677Slinton 815*9677Slinton p->signo = (status&0177); 816*9677Slinton p->exitval = ((status >> 8)&0377); 817*9677Slinton if (p->signo != STOPPED) { 818*9677Slinton p->status = FINISHED; 819*9677Slinton } else { 820*9677Slinton p->status = p->signo; 821*9677Slinton p->signo = p->exitval; 822*9677Slinton p->exitval = 0; 823*9677Slinton p->mask = ptrace(UREAD, p->pid, regloc(PS), 0); 824*9677Slinton for (i = 0; i < NREG; i++) { 825*9677Slinton p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0); 826*9677Slinton p->oreg[i] = p->reg[i]; 827*9677Slinton } 828*9677Slinton } 829*9677Slinton } 830*9677Slinton 831*9677Slinton /* 832*9677Slinton * Set process's user area information from given process structure. 833*9677Slinton */ 834*9677Slinton 835*9677Slinton private setinfo(p) 836*9677Slinton register Process p; 837*9677Slinton { 838*9677Slinton register int i; 839*9677Slinton register int r; 840*9677Slinton 841*9677Slinton if (istraced(p)) { 842*9677Slinton p->signo = 0; 843*9677Slinton } 844*9677Slinton for (i = 0; i < NREG; i++) { 845*9677Slinton if ((r = p->reg[i]) != p->oreg[i]) { 846*9677Slinton ptrace(UWRITE, p->pid, regloc(rloc[i]), r); 847*9677Slinton } 848*9677Slinton } 849*9677Slinton } 850*9677Slinton 851*9677Slinton /* 852*9677Slinton * Structure for reading and writing by words, but dealing with bytes. 853*9677Slinton */ 854*9677Slinton 855*9677Slinton typedef union { 856*9677Slinton Word pword; 857*9677Slinton Byte pbyte[sizeof(Word)]; 858*9677Slinton } Pword; 859*9677Slinton 860*9677Slinton /* 861*9677Slinton * Read (write) from (to) the process' address space. 862*9677Slinton * We must deal with ptrace's inability to look anywhere other 863*9677Slinton * than at a word boundary. 864*9677Slinton */ 865*9677Slinton 866*9677Slinton private Word fetch(); 867*9677Slinton private store(); 868*9677Slinton 869*9677Slinton private pio(p, op, seg, buff, addr, nbytes) 870*9677Slinton Process p; 871*9677Slinton PioOp op; 872*9677Slinton PioSeg seg; 873*9677Slinton char *buff; 874*9677Slinton Address addr; 875*9677Slinton int nbytes; 876*9677Slinton { 877*9677Slinton register int i; 878*9677Slinton register Address newaddr; 879*9677Slinton register char *cp; 880*9677Slinton char *bufend; 881*9677Slinton Pword w; 882*9677Slinton Address wordaddr; 883*9677Slinton int byteoff; 884*9677Slinton 885*9677Slinton if (p->status != STOPPED) { 886*9677Slinton error("program is not active"); 887*9677Slinton } 888*9677Slinton cp = buff; 889*9677Slinton newaddr = addr; 890*9677Slinton wordaddr = (newaddr&WMASK); 891*9677Slinton if (wordaddr != newaddr) { 892*9677Slinton w.pword = fetch(p, seg, wordaddr); 893*9677Slinton for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) { 894*9677Slinton if (op == PREAD) { 895*9677Slinton *cp++ = w.pbyte[i]; 896*9677Slinton } else { 897*9677Slinton w.pbyte[i] = *cp++; 898*9677Slinton } 899*9677Slinton nbytes--; 900*9677Slinton } 901*9677Slinton if (op == PWRITE) { 902*9677Slinton store(p, seg, wordaddr, w.pword); 903*9677Slinton } 904*9677Slinton newaddr = wordaddr + sizeof(Word); 905*9677Slinton } 906*9677Slinton byteoff = (nbytes&(~WMASK)); 907*9677Slinton nbytes -= byteoff; 908*9677Slinton bufend = cp + nbytes; 909*9677Slinton while (cp < bufend) { 910*9677Slinton if (op == PREAD) { 911*9677Slinton *((Word *) cp) = fetch(p, seg, newaddr); 912*9677Slinton } else { 913*9677Slinton store(p, seg, newaddr, *((Word *) cp)); 914*9677Slinton } 915*9677Slinton cp += sizeof(Word); 916*9677Slinton newaddr += sizeof(Word); 917*9677Slinton } 918*9677Slinton if (byteoff > 0) { 919*9677Slinton w.pword = fetch(p, seg, newaddr); 920*9677Slinton for (i = 0; i < byteoff; i++) { 921*9677Slinton if (op == PREAD) { 922*9677Slinton *cp++ = w.pbyte[i]; 923*9677Slinton } else { 924*9677Slinton w.pbyte[i] = *cp++; 925*9677Slinton } 926*9677Slinton } 927*9677Slinton if (op == PWRITE) { 928*9677Slinton store(p, seg, newaddr, w.pword); 929*9677Slinton } 930*9677Slinton } 931*9677Slinton } 932*9677Slinton 933*9677Slinton /* 934*9677Slinton * Get a word from a process at the given address. 935*9677Slinton * The address is assumed to be on a word boundary. 936*9677Slinton * 937*9677Slinton * A simple cache scheme is used to avoid redundant ptrace calls 938*9677Slinton * to the instruction space since it is assumed to be pure. 939*9677Slinton * 940*9677Slinton * It is necessary to use a write-through scheme so that 941*9677Slinton * breakpoints right next to each other don't interfere. 942*9677Slinton */ 943*9677Slinton 944*9677Slinton private Integer nfetchs, nreads, nwrites; 945*9677Slinton 946*9677Slinton private Word fetch(p, seg, addr) 947*9677Slinton Process p; 948*9677Slinton PioSeg seg; 949*9677Slinton register int addr; 950*9677Slinton { 951*9677Slinton register CacheWord *wp; 952*9677Slinton register Word w; 953*9677Slinton 954*9677Slinton switch (seg) { 955*9677Slinton case TEXTSEG: 956*9677Slinton ++nfetchs; 957*9677Slinton wp = &p->word[cachehash(addr)]; 958*9677Slinton if (addr == 0 or wp->addr != addr) { 959*9677Slinton ++nreads; 960*9677Slinton w = ptrace(IREAD, p->pid, addr, 0); 961*9677Slinton wp->addr = addr; 962*9677Slinton wp->val = w; 963*9677Slinton } else { 964*9677Slinton w = wp->val; 965*9677Slinton } 966*9677Slinton break; 967*9677Slinton 968*9677Slinton case DATASEG: 969*9677Slinton w = ptrace(DREAD, p->pid, addr, 0); 970*9677Slinton break; 971*9677Slinton 972*9677Slinton default: 973*9677Slinton panic("fetch: bad seg %d", seg); 974*9677Slinton /* NOTREACHED */ 975*9677Slinton } 976*9677Slinton return w; 977*9677Slinton } 978*9677Slinton 979*9677Slinton /* 980*9677Slinton * Put a word into the process' address space at the given address. 981*9677Slinton * The address is assumed to be on a word boundary. 982*9677Slinton */ 983*9677Slinton 984*9677Slinton private store(p, seg, addr, data) 985*9677Slinton Process p; 986*9677Slinton PioSeg seg; 987*9677Slinton int addr; 988*9677Slinton Word data; 989*9677Slinton { 990*9677Slinton register CacheWord *wp; 991*9677Slinton 992*9677Slinton switch (seg) { 993*9677Slinton case TEXTSEG: 994*9677Slinton ++nwrites; 995*9677Slinton wp = &p->word[cachehash(addr)]; 996*9677Slinton wp->addr = addr; 997*9677Slinton wp->val = data; 998*9677Slinton ptrace(IWRITE, p->pid, addr, data); 999*9677Slinton break; 1000*9677Slinton 1001*9677Slinton case DATASEG: 1002*9677Slinton ptrace(DWRITE, p->pid, addr, data); 1003*9677Slinton break; 1004*9677Slinton 1005*9677Slinton default: 1006*9677Slinton panic("store: bad seg %d", seg); 1007*9677Slinton /* NOTREACHED */ 1008*9677Slinton } 1009*9677Slinton } 1010*9677Slinton 1011*9677Slinton public printptraceinfo() 1012*9677Slinton { 1013*9677Slinton printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites); 1014*9677Slinton } 1015*9677Slinton 1016*9677Slinton /* 1017*9677Slinton * Swap file numbers so as to redirect standard input and output. 1018*9677Slinton */ 1019*9677Slinton 1020*9677Slinton private fswap(oldfd, newfd) 1021*9677Slinton int oldfd; 1022*9677Slinton int newfd; 1023*9677Slinton { 1024*9677Slinton if (oldfd != newfd) { 1025*9677Slinton close(oldfd); 1026*9677Slinton dup(newfd); 1027*9677Slinton close(newfd); 1028*9677Slinton } 1029*9677Slinton } 1030