xref: /csrg-svn/old/dbx/process.c (revision 11867)
19677Slinton /* Copyright (c) 1982 Regents of the University of California */
29677Slinton 
3*11867Slinton static char sccsid[] = "@(#)process.c 1.8 04/08/83";
49677Slinton 
59677Slinton /*
69677Slinton  * Process management.
79677Slinton  *
89677Slinton  * This module contains the routines to manage the execution and
99677Slinton  * tracing of the debuggee process.
109677Slinton  */
119677Slinton 
129677Slinton #include "defs.h"
139677Slinton #include "process.h"
149677Slinton #include "machine.h"
159677Slinton #include "events.h"
169677Slinton #include "tree.h"
179677Slinton #include "operators.h"
189677Slinton #include "source.h"
199677Slinton #include "object.h"
209677Slinton #include "mappings.h"
219677Slinton #include "main.h"
229677Slinton #include "coredump.h"
239677Slinton #include <signal.h>
249677Slinton #include <errno.h>
259677Slinton #include <sys/param.h>
269843Slinton #include <machine/reg.h>
279677Slinton #include <sys/stat.h>
289677Slinton 
299677Slinton #ifndef public
309677Slinton 
319677Slinton typedef struct Process *Process;
329677Slinton 
339677Slinton Process process;
349677Slinton 
359677Slinton #include "machine.h"
369677Slinton 
379677Slinton #endif
389677Slinton 
399677Slinton #define NOTSTARTED 1
409677Slinton #define STOPPED 0177
419677Slinton #define FINISHED 0
429677Slinton 
439677Slinton /*
449677Slinton  * Cache-ing of instruction segment is done to reduce the number
459677Slinton  * of system calls.
469677Slinton  */
479677Slinton 
489677Slinton #define CSIZE 1003       /* size of instruction cache */
499677Slinton 
509677Slinton typedef struct {
519677Slinton     Word addr;
529677Slinton     Word val;
539677Slinton } CacheWord;
549677Slinton 
559677Slinton /*
569677Slinton  * This structure holds the information we need from the user structure.
579677Slinton  */
589677Slinton 
599677Slinton struct Process {
609677Slinton     int pid;			/* process being traced */
6111768Slinton     int mask;			/* process status word */
6211768Slinton     Word reg[NREG];		/* process' registers */
639677Slinton     Word oreg[NREG];		/* registers when process last stopped */
649677Slinton     short status;		/* either STOPPED or FINISHED */
659677Slinton     short signo;		/* signal that stopped process */
669677Slinton     int exitval;		/* return value from exit() */
679677Slinton     long sigset;		/* bit array of traced signals */
689677Slinton     CacheWord word[CSIZE];	/* text segment cache */
6911768Slinton     Ttyinfo ttyinfo;		/* process' terminal characteristics */
709677Slinton };
719677Slinton 
729677Slinton /*
739677Slinton  * These definitions are for the arguments to "pio".
749677Slinton  */
759677Slinton 
769677Slinton typedef enum { PREAD, PWRITE } PioOp;
779677Slinton typedef enum { TEXTSEG, DATASEG } PioSeg;
789677Slinton 
799677Slinton private struct Process pbuf;
809677Slinton 
819677Slinton #define MAXNCMDARGS 10         /* maximum number of arguments to RUN */
829677Slinton 
839677Slinton private Boolean just_started;
849677Slinton private int argc;
859677Slinton private String argv[MAXNCMDARGS];
869677Slinton private String infile, outfile;
879677Slinton 
889677Slinton /*
899677Slinton  * Initialize process information.
909677Slinton  */
919677Slinton 
929677Slinton public process_init()
939677Slinton {
949677Slinton     register Integer i;
959677Slinton     Char buf[10];
969677Slinton 
979677Slinton     process = &pbuf;
989677Slinton     process->status = (coredump) ? STOPPED : NOTSTARTED;
999677Slinton     setsigtrace();
1009677Slinton     for (i = 0; i < NREG; i++) {
1019677Slinton 	sprintf(buf, "$r%d", i);
1029677Slinton 	defregname(identname(buf, false), i);
1039677Slinton     }
1049677Slinton     defregname(identname("$ap", true), ARGP);
1059677Slinton     defregname(identname("$fp", true), FRP);
1069677Slinton     defregname(identname("$sp", true), STKP);
1079677Slinton     defregname(identname("$pc", true), PROGCTR);
1089677Slinton     if (coredump) {
1099677Slinton 	coredump_readin(process->mask, process->reg, process->signo);
1109677Slinton     }
1119677Slinton }
1129677Slinton 
1139677Slinton /*
1149677Slinton  * Routines to get at process information from outside this module.
1159677Slinton  */
1169677Slinton 
1179677Slinton public Word reg(n)
1189677Slinton Integer n;
1199677Slinton {
1209677Slinton     register Word w;
1219677Slinton 
1229677Slinton     if (n == NREG) {
1239677Slinton 	w = process->mask;
1249677Slinton     } else {
1259677Slinton 	w = process->reg[n];
1269677Slinton     }
1279677Slinton     return w;
1289677Slinton }
1299677Slinton 
1309677Slinton public setreg(n, w)
1319677Slinton Integer n;
1329677Slinton Word w;
1339677Slinton {
1349677Slinton     process->reg[n] = w;
1359677Slinton }
1369677Slinton 
1379677Slinton /*
1389677Slinton  * Begin execution.
1399677Slinton  *
1409677Slinton  * We set a breakpoint at the end of the code so that the
1419677Slinton  * process data doesn't disappear after the program terminates.
1429677Slinton  */
1439677Slinton 
1449677Slinton private Boolean remade();
1459677Slinton 
1469677Slinton public start(argv, infile, outfile)
1479677Slinton String argv[];
1489677Slinton String infile, outfile;
1499677Slinton {
1509677Slinton     String pargv[4];
1519677Slinton     Node cond;
1529677Slinton 
1539677Slinton     if (coredump) {
1549677Slinton 	coredump = false;
1559677Slinton 	fclose(corefile);
1569677Slinton 	coredump_close();
1579677Slinton     }
1589677Slinton     if (argv == nil) {
1599677Slinton 	argv = pargv;
1609677Slinton 	pargv[0] = objname;
1619677Slinton 	pargv[1] = nil;
1629677Slinton     } else {
1639677Slinton 	argv[argc] = nil;
1649677Slinton     }
1659677Slinton     if (remade(objname)) {
1669677Slinton 	reinit(argv, infile, outfile);
1679677Slinton     }
1689677Slinton     pstart(process, argv, infile, outfile);
1699677Slinton     if (process->status == STOPPED) {
1709677Slinton 	pc = 0;
1719677Slinton 	curfunc = program;
1729677Slinton 	if (objsize != 0) {
1739677Slinton 	    cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr()));
1749677Slinton 	    event_once(cond, buildcmdlist(build(O_ENDX)));
1759677Slinton 	}
1769677Slinton     }
1779677Slinton }
1789677Slinton 
1799677Slinton /*
1809677Slinton  * Check to see if the object file has changed since the symbolic
1819677Slinton  * information last was read.
1829677Slinton  */
1839677Slinton 
1849677Slinton private time_t modtime;
1859677Slinton 
1869677Slinton private Boolean remade(filename)
1879677Slinton String filename;
1889677Slinton {
1899677Slinton     struct stat s;
1909677Slinton     Boolean b;
1919677Slinton 
1929677Slinton     stat(filename, &s);
1939677Slinton     b = (Boolean) (modtime != 0 and modtime < s.st_mtime);
1949677Slinton     modtime = s.st_mtime;
1959677Slinton     return b;
1969677Slinton }
1979677Slinton 
1989677Slinton /*
1999677Slinton  * Set up what signals we want to trace.
2009677Slinton  */
2019677Slinton 
2029677Slinton private setsigtrace()
2039677Slinton {
2049677Slinton     register Integer i;
2059677Slinton     register Process p;
2069677Slinton 
2079677Slinton     p = process;
2089677Slinton     for (i = 1; i <= NSIG; i++) {
2099677Slinton 	psigtrace(p, i, true);
2109677Slinton     }
2119677Slinton     psigtrace(p, SIGHUP, false);
2129677Slinton     psigtrace(p, SIGKILL, false);
2139677Slinton     psigtrace(p, SIGALRM, false);
2149677Slinton     psigtrace(p, SIGTSTP, false);
2159677Slinton     psigtrace(p, SIGCONT, false);
2169677Slinton     psigtrace(p, SIGCHLD, false);
2179677Slinton }
2189677Slinton 
2199677Slinton /*
2209677Slinton  * Initialize the argument list.
2219677Slinton  */
2229677Slinton 
2239677Slinton public arginit()
2249677Slinton {
2259677Slinton     infile = nil;
2269677Slinton     outfile = nil;
2279677Slinton     argv[0] = objname;
2289677Slinton     argc = 1;
2299677Slinton }
2309677Slinton 
2319677Slinton /*
2329677Slinton  * Add an argument to the list for the debuggee.
2339677Slinton  */
2349677Slinton 
2359677Slinton public newarg(arg)
2369677Slinton String arg;
2379677Slinton {
2389677Slinton     if (argc >= MAXNCMDARGS) {
2399677Slinton 	error("too many arguments");
2409677Slinton     }
2419677Slinton     argv[argc++] = arg;
2429677Slinton }
2439677Slinton 
2449677Slinton /*
2459677Slinton  * Set the standard input for the debuggee.
2469677Slinton  */
2479677Slinton 
2489677Slinton public inarg(filename)
2499677Slinton String filename;
2509677Slinton {
2519677Slinton     if (infile != nil) {
2529677Slinton 	error("multiple input redirects");
2539677Slinton     }
2549677Slinton     infile = filename;
2559677Slinton }
2569677Slinton 
2579677Slinton /*
2589677Slinton  * Set the standard output for the debuggee.
2599677Slinton  * Probably should check to avoid overwriting an existing file.
2609677Slinton  */
2619677Slinton 
2629677Slinton public outarg(filename)
2639677Slinton String filename;
2649677Slinton {
2659677Slinton     if (outfile != nil) {
2669677Slinton 	error("multiple output redirect");
2679677Slinton     }
2689677Slinton     outfile = filename;
2699677Slinton }
2709677Slinton 
2719677Slinton /*
2729677Slinton  * Start debuggee executing.
2739677Slinton  */
2749677Slinton 
2759677Slinton public run()
2769677Slinton {
2779677Slinton     process->status = STOPPED;
2789677Slinton     fixbps();
2799677Slinton     curline = 0;
2809677Slinton     start(argv, infile, outfile);
2819677Slinton     just_started = true;
2829677Slinton     isstopped = false;
2839677Slinton     cont();
2849677Slinton }
2859677Slinton 
2869677Slinton /*
2879677Slinton  * Continue execution wherever we left off.
2889677Slinton  *
2899677Slinton  * Note that this routine never returns.  Eventually bpact() will fail
2909677Slinton  * and we'll call printstatus or step will call it.
2919677Slinton  */
2929677Slinton 
2939677Slinton typedef int Intfunc();
2949677Slinton 
2959677Slinton private Intfunc *dbintr;
2969677Slinton private intr();
2979677Slinton 
2989677Slinton #define succeeds    == true
2999677Slinton #define fails       == false
3009677Slinton 
301*11867Slinton public cont(signo)
302*11867Slinton int signo;
3039677Slinton {
3049677Slinton     dbintr = signal(SIGINT, intr);
3059677Slinton     if (just_started) {
3069677Slinton 	just_started = false;
3079677Slinton     } else {
3089677Slinton 	if (not isstopped) {
3099677Slinton 	    error("can't continue execution");
3109677Slinton 	}
3119677Slinton 	isstopped = false;
312*11867Slinton 	stepover();
3139677Slinton     }
3149677Slinton     for (;;) {
3159677Slinton 	if (single_stepping) {
3169677Slinton 	    printnews();
3179677Slinton 	} else {
3189677Slinton 	    setallbps();
319*11867Slinton 	    resume(signo);
3209677Slinton 	    unsetallbps();
3219677Slinton 	    if (bpact() fails) {
3229677Slinton 		printstatus();
3239677Slinton 	    }
3249677Slinton 	}
325*11867Slinton 	stepover();
3269677Slinton     }
3279677Slinton     /* NOTREACHED */
3289677Slinton }
3299677Slinton 
3309677Slinton /*
3319677Slinton  * This routine is called if we get an interrupt while "running" px
3329677Slinton  * but actually in the debugger.  Could happen, for example, while
3339677Slinton  * processing breakpoints.
3349677Slinton  *
3359677Slinton  * We basically just want to keep going; the assumption is
3369677Slinton  * that when the process resumes it will get the interrupt
3379677Slinton  * which will then be handled.
3389677Slinton  */
3399677Slinton 
3409677Slinton private intr()
3419677Slinton {
3429677Slinton     signal(SIGINT, intr);
3439677Slinton }
3449677Slinton 
3459677Slinton public fixintr()
3469677Slinton {
3479677Slinton     signal(SIGINT, dbintr);
3489677Slinton }
3499677Slinton 
3509677Slinton /*
3519677Slinton  * Resume execution.
3529677Slinton  */
3539677Slinton 
354*11867Slinton public resume(signo)
355*11867Slinton int signo;
3569677Slinton {
3579677Slinton     register Process p;
3589677Slinton 
3599677Slinton     p = process;
3609677Slinton     if (traceexec) {
3619677Slinton 	printf("execution resumes at pc 0x%x\n", process->reg[PROGCTR]);
3629677Slinton 	fflush(stdout);
3639677Slinton     }
364*11867Slinton     pcont(p, signo);
3659677Slinton     pc = process->reg[PROGCTR];
3669677Slinton     if (traceexec) {
3679677Slinton 	printf("execution stops at pc 0x%x on sig %d\n",
3689677Slinton 	    process->reg[PROGCTR], p->signo);
3699677Slinton 	fflush(stdout);
3709677Slinton     }
37111832Slinton     if (p->status != STOPPED) {
372*11867Slinton 	if (p->signo != 0) {
373*11867Slinton 	    error("program terminated by signal %d", p->signo);
374*11867Slinton 	} else {
375*11867Slinton 	    error("program unexpectedly exited with %d", p->exitval);
376*11867Slinton 	}
37711832Slinton     }
3789677Slinton }
3799677Slinton 
3809677Slinton /*
3819677Slinton  * Continue execution up to the next source line.
3829677Slinton  *
3839677Slinton  * There are two ways to define the next source line depending on what
3849677Slinton  * is desired when a procedure or function call is encountered.  Step
3859677Slinton  * stops at the beginning of the procedure or call; next skips over it.
3869677Slinton  */
3879677Slinton 
3889677Slinton /*
3899677Slinton  * Stepc is what is called when the step command is given.
3909677Slinton  * It has to play with the "isstopped" information.
3919677Slinton  */
3929677Slinton 
3939677Slinton public stepc()
3949677Slinton {
3959677Slinton     if (not isstopped) {
3969677Slinton 	error("can't continue execution");
3979677Slinton     }
3989677Slinton     isstopped = false;
3999677Slinton     dostep(false);
4009677Slinton     isstopped = true;
4019677Slinton }
4029677Slinton 
4039677Slinton public next()
4049677Slinton {
4059677Slinton     if (not isstopped) {
4069677Slinton 	error("can't continue execution");
4079677Slinton     }
4089677Slinton     isstopped = false;
4099677Slinton     dostep(true);
4109677Slinton     isstopped = true;
4119677Slinton }
4129677Slinton 
413*11867Slinton /*
414*11867Slinton  * Single-step over the current machine instruction.
415*11867Slinton  *
416*11867Slinton  * If we're single-stepping by source line we want to step to the
417*11867Slinton  * next source line.  Otherwise we're going to continue so there's
418*11867Slinton  * no reason to do all the work necessary to single-step to the next
419*11867Slinton  * source line.
420*11867Slinton  */
421*11867Slinton 
422*11867Slinton private stepover()
4239677Slinton {
424*11867Slinton     Boolean b;
425*11867Slinton 
426*11867Slinton     if (single_stepping) {
427*11867Slinton 	dostep(false);
428*11867Slinton     } else {
429*11867Slinton 	b = inst_tracing;
430*11867Slinton 	inst_tracing = true;
431*11867Slinton 	dostep(false);
432*11867Slinton 	inst_tracing = b;
433*11867Slinton     }
4349677Slinton }
4359677Slinton 
4369677Slinton /*
4379677Slinton  * Resume execution up to the given address.  It is assumed that
4389677Slinton  * no breakpoints exist between the current address and the one
4399677Slinton  * we're stepping to.  This saves us from setting all the breakpoints.
4409677Slinton  */
4419677Slinton 
4429677Slinton public stepto(addr)
4439677Slinton Address addr;
4449677Slinton {
4459677Slinton     setbp(addr);
446*11867Slinton     resume(0);
4479677Slinton     unsetbp(addr);
4489677Slinton     if (not isbperr()) {
4499677Slinton 	printstatus();
4509677Slinton     }
4519677Slinton }
4529677Slinton 
4539677Slinton /*
4549677Slinton  * Print the status of the process.
4559677Slinton  * This routine does not return.
4569677Slinton  */
4579677Slinton 
4589677Slinton public printstatus()
4599677Slinton {
4609843Slinton     if (process->status == FINISHED) {
4619843Slinton 	exit(0);
4629843Slinton     } else {
4639843Slinton 	curfunc = whatblock(pc);
4649677Slinton 	getsrcpos();
4659843Slinton 	if (process->signo == SIGINT) {
4669843Slinton 	    isstopped = true;
4679843Slinton 	    printerror();
4689843Slinton 	} else if (isbperr() and isstopped) {
4699843Slinton 	    printf("stopped ");
47011172Slinton 	    printloc();
47111172Slinton 	    putchar('\n');
4729843Slinton 	    if (curline > 0) {
4739843Slinton 		printlines(curline, curline);
4749843Slinton 	    } else {
4759843Slinton 		printinst(pc, pc);
4769843Slinton 	    }
4779843Slinton 	    erecover();
4789677Slinton 	} else {
4799843Slinton 	    fixbps();
4809843Slinton 	    fixintr();
4819677Slinton 	    isstopped = true;
4829677Slinton 	    printerror();
4839677Slinton 	}
4849677Slinton     }
4859677Slinton }
4869677Slinton 
4879677Slinton /*
48811172Slinton  * Print out the current location in the debuggee.
48911172Slinton  */
49011172Slinton 
49111172Slinton public printloc()
49211172Slinton {
49311172Slinton     printf("in ");
49411172Slinton     printname(stdout, curfunc);
49511172Slinton     putchar(' ');
49611172Slinton     if (curline > 0) {
49711172Slinton 	printsrcpos();
49811172Slinton     } else {
49911172Slinton 	printf("at 0x%x", pc);
50011172Slinton     }
50111172Slinton }
50211172Slinton 
50311172Slinton /*
5049677Slinton  * Some functions for testing the state of the process.
5059677Slinton  */
5069677Slinton 
5079677Slinton public Boolean notstarted(p)
5089677Slinton Process p;
5099677Slinton {
5109677Slinton     return (Boolean) (p->status == NOTSTARTED);
5119677Slinton }
5129677Slinton 
5139677Slinton public Boolean isfinished(p)
5149677Slinton Process p;
5159677Slinton {
5169677Slinton     return (Boolean) (p->status == FINISHED);
5179677Slinton }
5189677Slinton 
5199677Slinton /*
5209677Slinton  * Return the signal number which stopped the process.
5219677Slinton  */
5229677Slinton 
5239677Slinton public Integer errnum(p)
5249677Slinton Process p;
5259677Slinton {
5269677Slinton     return p->signo;
5279677Slinton }
5289677Slinton 
5299677Slinton /*
5309677Slinton  * Return the termination code of the process.
5319677Slinton  */
5329677Slinton 
5339677Slinton public Integer exitcode(p)
5349677Slinton Process p;
5359677Slinton {
5369677Slinton     return p->exitval;
5379677Slinton }
5389677Slinton 
5399677Slinton /*
5409677Slinton  * These routines are used to access the debuggee process from
5419677Slinton  * outside this module.
5429677Slinton  *
5439677Slinton  * They invoke "pio" which eventually leads to a call to "ptrace".
54411560Slinton  * The system generates an I/O error when a ptrace fails, we assume
54511560Slinton  * during a read/write to the process that such an error is due to
54611560Slinton  * a misguided address and ignore it.
5479677Slinton  */
5489677Slinton 
5499677Slinton extern Intfunc *onsyserr();
5509677Slinton 
5519677Slinton private badaddr;
5529677Slinton private rwerr();
5539677Slinton 
5549677Slinton /*
5559677Slinton  * Read from the process' instruction area.
5569677Slinton  */
5579677Slinton 
5589677Slinton public iread(buff, addr, nbytes)
5599677Slinton char *buff;
5609677Slinton Address addr;
5619677Slinton int nbytes;
5629677Slinton {
5639677Slinton     Intfunc *f;
5649677Slinton 
5659677Slinton     f = onsyserr(EIO, rwerr);
5669677Slinton     badaddr = addr;
5679677Slinton     if (coredump) {
5689677Slinton 	coredump_readtext(buff, addr, nbytes);
5699677Slinton     } else {
5709677Slinton 	pio(process, PREAD, TEXTSEG, buff, addr, nbytes);
5719677Slinton     }
5729677Slinton     onsyserr(EIO, f);
5739677Slinton }
5749677Slinton 
5759677Slinton /*
5769677Slinton  * Write to the process' instruction area, usually in order to set
5779677Slinton  * or unset a breakpoint.
5789677Slinton  */
5799677Slinton 
5809677Slinton public iwrite(buff, addr, nbytes)
5819677Slinton char *buff;
5829677Slinton Address addr;
5839677Slinton int nbytes;
5849677Slinton {
5859677Slinton     Intfunc *f;
5869677Slinton 
5879677Slinton     if (coredump) {
5889677Slinton 	error("no process to write to");
5899677Slinton     }
5909677Slinton     f = onsyserr(EIO, rwerr);
5919677Slinton     badaddr = addr;
5929677Slinton     pio(process, PWRITE, TEXTSEG, buff, addr, nbytes);
5939677Slinton     onsyserr(EIO, f);
5949677Slinton }
5959677Slinton 
5969677Slinton /*
5979677Slinton  * Read for the process' data area.
5989677Slinton  */
5999677Slinton 
6009677Slinton public dread(buff, addr, nbytes)
6019677Slinton char *buff;
6029677Slinton Address addr;
6039677Slinton int nbytes;
6049677Slinton {
6059677Slinton     Intfunc *f;
6069677Slinton 
6079677Slinton     f = onsyserr(EIO, rwerr);
6089677Slinton     badaddr = addr;
6099677Slinton     if (coredump) {
6109677Slinton 	coredump_readdata(buff, addr, nbytes);
6119677Slinton     } else {
6129677Slinton 	pio(process, PREAD, DATASEG, buff, addr, nbytes);
6139677Slinton     }
6149677Slinton     onsyserr(EIO, f);
6159677Slinton }
6169677Slinton 
6179677Slinton /*
6189677Slinton  * Write to the process' data area.
6199677Slinton  */
6209677Slinton 
6219677Slinton public dwrite(buff, addr, nbytes)
6229677Slinton char *buff;
6239677Slinton Address addr;
6249677Slinton int nbytes;
6259677Slinton {
6269677Slinton     Intfunc *f;
6279677Slinton 
6289677Slinton     if (coredump) {
6299677Slinton 	error("no process to write to");
6309677Slinton     }
6319677Slinton     f = onsyserr(EIO, rwerr);
6329677Slinton     badaddr = addr;
6339677Slinton     pio(process, PWRITE, DATASEG, buff, addr, nbytes);
6349677Slinton     onsyserr(EIO, f);
6359677Slinton }
6369677Slinton 
6379677Slinton /*
6389677Slinton  * Error handler.
6399677Slinton  */
6409677Slinton 
6419677Slinton private rwerr()
6429677Slinton {
64311560Slinton     /*
64411560Slinton      * Current response is to ignore the error and let the result
64511560Slinton      * (-1) ripple back up to the process.
64611560Slinton      *
6479677Slinton     error("bad read/write process address 0x%x", badaddr);
64811560Slinton      */
6499677Slinton }
6509677Slinton 
6519677Slinton /*
6529677Slinton  * Ptrace interface.
6539677Slinton  */
6549677Slinton 
6559677Slinton /*
6569677Slinton  * This magic macro enables us to look at the process' registers
6579677Slinton  * in its user structure.  Very gross.
6589677Slinton  */
6599677Slinton 
6609677Slinton #define regloc(reg)     (ctob(UPAGES) + ( sizeof(int) * (reg) ))
6619677Slinton 
6629677Slinton #define WMASK           (~(sizeof(Word) - 1))
6639677Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE))
6649677Slinton 
6659677Slinton #define FIRSTSIG        SIGINT
6669677Slinton #define LASTSIG         SIGQUIT
6679677Slinton #define ischild(pid)    ((pid) == 0)
6689677Slinton #define traceme()       ptrace(0, 0, 0, 0)
6699677Slinton #define setrep(n)       (1 << ((n)-1))
6709677Slinton #define istraced(p)     (p->sigset&setrep(p->signo))
6719677Slinton 
6729677Slinton /*
6739677Slinton  * Ptrace options (specified in first argument).
6749677Slinton  */
6759677Slinton 
6769677Slinton #define UREAD   3       /* read from process's user structure */
6779677Slinton #define UWRITE  6       /* write to process's user structure */
6789677Slinton #define IREAD   1       /* read from process's instruction space */
6799677Slinton #define IWRITE  4       /* write to process's instruction space */
6809677Slinton #define DREAD   2       /* read from process's data space */
6819677Slinton #define DWRITE  5       /* write to process's data space */
6829677Slinton #define CONT    7       /* continue stopped process */
6839677Slinton #define SSTEP   9       /* continue for approximately one instruction */
6849677Slinton #define PKILL   8       /* terminate the process */
6859677Slinton 
6869677Slinton /*
6879677Slinton  * Start up a new process by forking and exec-ing the
6889677Slinton  * given argument list, returning when the process is loaded
6899677Slinton  * and ready to execute.  The PROCESS information (pointed to
6909677Slinton  * by the first argument) is appropriately filled.
6919677Slinton  *
6929677Slinton  * If the given PROCESS structure is associated with an already running
6939677Slinton  * process, we terminate it.
6949677Slinton  */
6959677Slinton 
6969677Slinton /* VARARGS2 */
6979677Slinton private pstart(p, argv, infile, outfile)
6989677Slinton Process p;
6999677Slinton String argv[];
7009677Slinton String infile;
7019677Slinton String outfile;
7029677Slinton {
7039677Slinton     int status;
7049677Slinton 
7059677Slinton     if (p->pid != 0) {          	/* child already running? */
7069677Slinton 	ptrace(PKILL, p->pid, 0, 0);    /* ... kill it! */
7079677Slinton     }
7089677Slinton     psigtrace(p, SIGTRAP, true);
70911172Slinton     if ((p->pid = vfork()) == -1) {
7109677Slinton 	panic("can't fork");
7119677Slinton     }
7129677Slinton     if (ischild(p->pid)) {
71311172Slinton 	Fileid in, out;
71411172Slinton 
7159677Slinton 	traceme();
7169677Slinton 	if (infile != nil) {
71711172Slinton 	    in = open(infile, 0);
71811172Slinton 	    if (in == -1) {
71911172Slinton 		write(2, "can't read ", 11);
72011172Slinton 		write(2, infile, strlen(infile));
72111172Slinton 		write(2, "\n", 1);
72211172Slinton 		_exit(1);
7239677Slinton 	    }
72411172Slinton 	    fswap(0, in);
7259677Slinton 	}
7269677Slinton 	if (outfile != nil) {
72711172Slinton 	    out = creat(outfile, 0666);
72811172Slinton 	    if (out == -1) {
72911172Slinton 		write(2, "can't write ", 12);
73011172Slinton 		write(2, outfile, strlen(outfile));
73111172Slinton 		write(2, "\n", 1);
73211172Slinton 		_exit(1);
7339677Slinton 	    }
73411172Slinton 	    fswap(1, out);
7359677Slinton 	}
73611832Slinton 	execv(argv[0], argv);
73711172Slinton 	write(2, "can't exec ", 11);
73811172Slinton 	write(2, argv[0], strlen(argv[0]));
73911172Slinton 	write(2, "\n", 1);
74011172Slinton 	_exit(1);
7419677Slinton     }
7429677Slinton     pwait(p->pid, &status);
7439677Slinton     getinfo(p, status);
7449677Slinton     if (p->status != STOPPED) {
7459677Slinton 	error("program could not begin execution");
7469677Slinton     }
7479677Slinton }
7489677Slinton 
7499677Slinton /*
750*11867Slinton  * Continue a stopped process.  The first argument points to a Process
751*11867Slinton  * structure.  Before the process is restarted it's user area is modified
752*11867Slinton  * according to the values in the structure.  When this routine finishes,
7539677Slinton  * the structure has the new values from the process's user area.
7549677Slinton  *
7559677Slinton  * Pcont terminates when the process stops with a signal pending that
7569677Slinton  * is being traced (via psigtrace), or when the process terminates.
7579677Slinton  */
7589677Slinton 
759*11867Slinton private pcont(p, signo)
7609677Slinton Process p;
761*11867Slinton int signo;
7629677Slinton {
7639677Slinton     int status;
7649677Slinton 
7659677Slinton     if (p->pid == 0) {
7669677Slinton 	error("program not active");
7679677Slinton     }
7689677Slinton     do {
769*11867Slinton 	setinfo(p, signo);
7709677Slinton 	sigs_off();
7719677Slinton 	if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) {
7729677Slinton 	    panic("can't continue process");
7739677Slinton 	}
7749677Slinton 	pwait(p->pid, &status);
7759677Slinton 	sigs_on();
7769677Slinton 	getinfo(p, status);
7779677Slinton     } while (p->status == STOPPED and not istraced(p));
7789677Slinton }
7799677Slinton 
7809677Slinton /*
7819677Slinton  * Single step as best ptrace can.
7829677Slinton  */
7839677Slinton 
7849677Slinton public pstep(p)
7859677Slinton Process p;
7869677Slinton {
7879677Slinton     int status;
7889677Slinton 
789*11867Slinton     setinfo(p, 0);
7909677Slinton     sigs_off();
7919677Slinton     ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo);
7929677Slinton     pwait(p->pid, &status);
7939677Slinton     sigs_on();
7949677Slinton     getinfo(p, status);
7959677Slinton }
7969677Slinton 
7979677Slinton /*
7989677Slinton  * Return from execution when the given signal is pending.
7999677Slinton  */
8009677Slinton 
8019677Slinton public psigtrace(p, sig, sw)
8029677Slinton Process p;
8039677Slinton int sig;
8049677Slinton Boolean sw;
8059677Slinton {
8069677Slinton     if (sw) {
8079677Slinton 	p->sigset |= setrep(sig);
8089677Slinton     } else {
8099677Slinton 	p->sigset &= ~setrep(sig);
8109677Slinton     }
8119677Slinton }
8129677Slinton 
8139677Slinton /*
8149677Slinton  * Don't catch any signals.
8159677Slinton  * Particularly useful when letting a process finish uninhibited.
8169677Slinton  */
8179677Slinton 
8189677Slinton public unsetsigtraces(p)
8199677Slinton Process p;
8209677Slinton {
8219677Slinton     p->sigset = 0;
8229677Slinton }
8239677Slinton 
8249677Slinton /*
8259677Slinton  * Turn off attention to signals not being caught.
8269677Slinton  */
8279677Slinton 
8289677Slinton private Intfunc *sigfunc[NSIG];
8299677Slinton 
8309677Slinton private sigs_off()
8319677Slinton {
8329677Slinton     register int i;
8339677Slinton 
8349677Slinton     for (i = FIRSTSIG; i < LASTSIG; i++) {
8359677Slinton 	if (i != SIGKILL) {
8369677Slinton 	    sigfunc[i] = signal(i, SIG_IGN);
8379677Slinton 	}
8389677Slinton     }
8399677Slinton }
8409677Slinton 
8419677Slinton /*
8429677Slinton  * Turn back on attention to signals.
8439677Slinton  */
8449677Slinton 
8459677Slinton private sigs_on()
8469677Slinton {
8479677Slinton     register int i;
8489677Slinton 
8499677Slinton     for (i = FIRSTSIG; i < LASTSIG; i++) {
8509677Slinton 	if (i != SIGKILL) {
8519677Slinton 	    signal(i, sigfunc[i]);
8529677Slinton 	}
8539677Slinton     }
8549677Slinton }
8559677Slinton 
8569677Slinton /*
8579677Slinton  * Get process information from user area.
8589677Slinton  */
8599677Slinton 
8609677Slinton private int rloc[] ={
8619677Slinton     R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC
8629677Slinton };
8639677Slinton 
8649677Slinton private getinfo(p, status)
8659677Slinton register Process p;
8669677Slinton register int status;
8679677Slinton {
8689677Slinton     register int i;
8699677Slinton 
8709677Slinton     p->signo = (status&0177);
8719677Slinton     p->exitval = ((status >> 8)&0377);
8729677Slinton     if (p->signo != STOPPED) {
8739677Slinton 	p->status = FINISHED;
8749677Slinton     } else {
8759677Slinton 	p->status = p->signo;
8769677Slinton 	p->signo = p->exitval;
8779677Slinton 	p->exitval = 0;
8789677Slinton 	p->mask = ptrace(UREAD, p->pid, regloc(PS), 0);
8799677Slinton 	for (i = 0; i < NREG; i++) {
8809677Slinton 	    p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0);
8819677Slinton 	    p->oreg[i] = p->reg[i];
8829677Slinton 	}
88311768Slinton 	savetty(stdout, &(p->ttyinfo));
8849677Slinton     }
8859677Slinton }
8869677Slinton 
8879677Slinton /*
8889677Slinton  * Set process's user area information from given process structure.
8899677Slinton  */
8909677Slinton 
891*11867Slinton private setinfo(p, signo)
8929677Slinton register Process p;
893*11867Slinton int signo;
8949677Slinton {
8959677Slinton     register int i;
8969677Slinton     register int r;
8979677Slinton 
8989677Slinton     if (istraced(p)) {
899*11867Slinton 	p->signo = signo;
9009677Slinton     }
9019677Slinton     for (i = 0; i < NREG; i++) {
9029677Slinton 	if ((r = p->reg[i]) != p->oreg[i]) {
9039677Slinton 	    ptrace(UWRITE, p->pid, regloc(rloc[i]), r);
9049677Slinton 	}
9059677Slinton     }
90611768Slinton     restoretty(stdout, &(p->ttyinfo));
9079677Slinton }
9089677Slinton 
9099677Slinton /*
9109677Slinton  * Structure for reading and writing by words, but dealing with bytes.
9119677Slinton  */
9129677Slinton 
9139677Slinton typedef union {
9149677Slinton     Word pword;
9159677Slinton     Byte pbyte[sizeof(Word)];
9169677Slinton } Pword;
9179677Slinton 
9189677Slinton /*
9199677Slinton  * Read (write) from (to) the process' address space.
9209677Slinton  * We must deal with ptrace's inability to look anywhere other
9219677Slinton  * than at a word boundary.
9229677Slinton  */
9239677Slinton 
9249677Slinton private Word fetch();
9259677Slinton private store();
9269677Slinton 
9279677Slinton private pio(p, op, seg, buff, addr, nbytes)
9289677Slinton Process p;
9299677Slinton PioOp op;
9309677Slinton PioSeg seg;
9319677Slinton char *buff;
9329677Slinton Address addr;
9339677Slinton int nbytes;
9349677Slinton {
9359677Slinton     register int i;
9369677Slinton     register Address newaddr;
9379677Slinton     register char *cp;
9389677Slinton     char *bufend;
9399677Slinton     Pword w;
9409677Slinton     Address wordaddr;
9419677Slinton     int byteoff;
9429677Slinton 
9439677Slinton     if (p->status != STOPPED) {
9449677Slinton 	error("program is not active");
9459677Slinton     }
9469677Slinton     cp = buff;
9479677Slinton     newaddr = addr;
9489677Slinton     wordaddr = (newaddr&WMASK);
9499677Slinton     if (wordaddr != newaddr) {
9509677Slinton 	w.pword = fetch(p, seg, wordaddr);
9519677Slinton 	for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) {
9529677Slinton 	    if (op == PREAD) {
9539677Slinton 		*cp++ = w.pbyte[i];
9549677Slinton 	    } else {
9559677Slinton 		w.pbyte[i] = *cp++;
9569677Slinton 	    }
9579677Slinton 	    nbytes--;
9589677Slinton 	}
9599677Slinton 	if (op == PWRITE) {
9609677Slinton 	    store(p, seg, wordaddr, w.pword);
9619677Slinton 	}
9629677Slinton 	newaddr = wordaddr + sizeof(Word);
9639677Slinton     }
9649677Slinton     byteoff = (nbytes&(~WMASK));
9659677Slinton     nbytes -= byteoff;
9669677Slinton     bufend = cp + nbytes;
9679677Slinton     while (cp < bufend) {
9689677Slinton 	if (op == PREAD) {
9699677Slinton 	    *((Word *) cp) = fetch(p, seg, newaddr);
9709677Slinton 	} else {
9719677Slinton 	    store(p, seg, newaddr, *((Word *) cp));
9729677Slinton 	}
9739677Slinton 	cp += sizeof(Word);
9749677Slinton 	newaddr += sizeof(Word);
9759677Slinton     }
9769677Slinton     if (byteoff > 0) {
9779677Slinton 	w.pword = fetch(p, seg, newaddr);
9789677Slinton 	for (i = 0; i < byteoff; i++) {
9799677Slinton 	    if (op == PREAD) {
9809677Slinton 		*cp++ = w.pbyte[i];
9819677Slinton 	    } else {
9829677Slinton 		w.pbyte[i] = *cp++;
9839677Slinton 	    }
9849677Slinton 	}
9859677Slinton 	if (op == PWRITE) {
9869677Slinton 	    store(p, seg, newaddr, w.pword);
9879677Slinton 	}
9889677Slinton     }
9899677Slinton }
9909677Slinton 
9919677Slinton /*
9929677Slinton  * Get a word from a process at the given address.
9939677Slinton  * The address is assumed to be on a word boundary.
9949677Slinton  *
9959677Slinton  * A simple cache scheme is used to avoid redundant ptrace calls
9969677Slinton  * to the instruction space since it is assumed to be pure.
9979677Slinton  *
9989677Slinton  * It is necessary to use a write-through scheme so that
9999677Slinton  * breakpoints right next to each other don't interfere.
10009677Slinton  */
10019677Slinton 
10029677Slinton private Integer nfetchs, nreads, nwrites;
10039677Slinton 
10049677Slinton private Word fetch(p, seg, addr)
10059677Slinton Process p;
10069677Slinton PioSeg seg;
10079677Slinton register int addr;
10089677Slinton {
10099677Slinton     register CacheWord *wp;
10109677Slinton     register Word w;
10119677Slinton 
10129677Slinton     switch (seg) {
10139677Slinton 	case TEXTSEG:
10149677Slinton 	    ++nfetchs;
10159677Slinton 	    wp = &p->word[cachehash(addr)];
10169677Slinton 	    if (addr == 0 or wp->addr != addr) {
10179677Slinton 		++nreads;
10189677Slinton 		w = ptrace(IREAD, p->pid, addr, 0);
10199677Slinton 		wp->addr = addr;
10209677Slinton 		wp->val = w;
10219677Slinton 	    } else {
10229677Slinton 		w = wp->val;
10239677Slinton 	    }
10249677Slinton 	    break;
10259677Slinton 
10269677Slinton 	case DATASEG:
10279677Slinton 	    w = ptrace(DREAD, p->pid, addr, 0);
10289677Slinton 	    break;
10299677Slinton 
10309677Slinton 	default:
10319677Slinton 	    panic("fetch: bad seg %d", seg);
10329677Slinton 	    /* NOTREACHED */
10339677Slinton     }
10349677Slinton     return w;
10359677Slinton }
10369677Slinton 
10379677Slinton /*
10389677Slinton  * Put a word into the process' address space at the given address.
10399677Slinton  * The address is assumed to be on a word boundary.
10409677Slinton  */
10419677Slinton 
10429677Slinton private store(p, seg, addr, data)
10439677Slinton Process p;
10449677Slinton PioSeg seg;
10459677Slinton int addr;
10469677Slinton Word data;
10479677Slinton {
10489677Slinton     register CacheWord *wp;
10499677Slinton 
10509677Slinton     switch (seg) {
10519677Slinton 	case TEXTSEG:
10529677Slinton 	    ++nwrites;
10539677Slinton 	    wp = &p->word[cachehash(addr)];
10549677Slinton 	    wp->addr = addr;
10559677Slinton 	    wp->val = data;
10569677Slinton 	    ptrace(IWRITE, p->pid, addr, data);
10579677Slinton 	    break;
10589677Slinton 
10599677Slinton 	case DATASEG:
10609677Slinton 	    ptrace(DWRITE, p->pid, addr, data);
10619677Slinton 	    break;
10629677Slinton 
10639677Slinton 	default:
10649677Slinton 	    panic("store: bad seg %d", seg);
10659677Slinton 	    /* NOTREACHED */
10669677Slinton     }
10679677Slinton }
10689677Slinton 
10699677Slinton public printptraceinfo()
10709677Slinton {
10719677Slinton     printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites);
10729677Slinton }
10739677Slinton 
10749677Slinton /*
10759677Slinton  * Swap file numbers so as to redirect standard input and output.
10769677Slinton  */
10779677Slinton 
10789677Slinton private fswap(oldfd, newfd)
10799677Slinton int oldfd;
10809677Slinton int newfd;
10819677Slinton {
10829677Slinton     if (oldfd != newfd) {
10839677Slinton 	close(oldfd);
10849677Slinton 	dup(newfd);
10859677Slinton 	close(newfd);
10869677Slinton     }
10879677Slinton }
1088