xref: /csrg-svn/old/dbx/process.c (revision 18230)
19677Slinton /* Copyright (c) 1982 Regents of the University of California */
29677Slinton 
3*18230Slinton static	char sccsid[] = "@(#)process.c	1.17 (Berkeley) 03/01/85";
49677Slinton 
5*18230Slinton static char rcsid[] = "$Header: process.c,v 1.5 84/12/26 10:41:37 linton Exp $";
6*18230Slinton 
79677Slinton /*
89677Slinton  * Process management.
99677Slinton  *
109677Slinton  * This module contains the routines to manage the execution and
119677Slinton  * tracing of the debuggee process.
129677Slinton  */
139677Slinton 
149677Slinton #include "defs.h"
159677Slinton #include "process.h"
169677Slinton #include "machine.h"
179677Slinton #include "events.h"
189677Slinton #include "tree.h"
1914757Slinton #include "eval.h"
209677Slinton #include "operators.h"
219677Slinton #include "source.h"
229677Slinton #include "object.h"
239677Slinton #include "mappings.h"
249677Slinton #include "main.h"
259677Slinton #include "coredump.h"
269677Slinton #include <signal.h>
279677Slinton #include <errno.h>
289677Slinton #include <sys/param.h>
2916617Ssam #include <sys/dir.h>
3016617Ssam #include <sys/user.h>
319843Slinton #include <machine/reg.h>
329677Slinton #include <sys/stat.h>
339677Slinton 
349677Slinton #ifndef public
359677Slinton 
369677Slinton typedef struct Process *Process;
379677Slinton 
389677Slinton Process process;
399677Slinton 
4014757Slinton #define DEFSIG -1
4114757Slinton 
429677Slinton #include "machine.h"
439677Slinton 
449677Slinton #endif
459677Slinton 
469677Slinton #define NOTSTARTED 1
479677Slinton #define STOPPED 0177
489677Slinton #define FINISHED 0
499677Slinton 
509677Slinton /*
5116617Ssam  * A cache of the instruction segment is kept to reduce the number
5216617Ssam  * of system calls.  Might be better just to read the entire
5316617Ssam  * code space into memory.
549677Slinton  */
559677Slinton 
569677Slinton #define CSIZE 1003       /* size of instruction cache */
579677Slinton 
589677Slinton typedef struct {
599677Slinton     Word addr;
609677Slinton     Word val;
619677Slinton } CacheWord;
629677Slinton 
639677Slinton /*
649677Slinton  * This structure holds the information we need from the user structure.
659677Slinton  */
669677Slinton 
679677Slinton struct Process {
689677Slinton     int pid;			/* process being traced */
6911768Slinton     int mask;			/* process status word */
7011768Slinton     Word reg[NREG];		/* process' registers */
719677Slinton     Word oreg[NREG];		/* registers when process last stopped */
729677Slinton     short status;		/* either STOPPED or FINISHED */
739677Slinton     short signo;		/* signal that stopped process */
74*18230Slinton     short sigcode;		/* extra signal information */
759677Slinton     int exitval;		/* return value from exit() */
769677Slinton     long sigset;		/* bit array of traced signals */
779677Slinton     CacheWord word[CSIZE];	/* text segment cache */
7811768Slinton     Ttyinfo ttyinfo;		/* process' terminal characteristics */
7916617Ssam     Address sigstatus;		/* process' handler for current signal */
809677Slinton };
819677Slinton 
829677Slinton /*
839677Slinton  * These definitions are for the arguments to "pio".
849677Slinton  */
859677Slinton 
869677Slinton typedef enum { PREAD, PWRITE } PioOp;
879677Slinton typedef enum { TEXTSEG, DATASEG } PioSeg;
889677Slinton 
899677Slinton private struct Process pbuf;
909677Slinton 
91*18230Slinton #define MAXNCMDARGS 1000         /* maximum number of arguments to RUN */
929677Slinton 
9314395Slinton extern int errno;
9414395Slinton 
959677Slinton private Boolean just_started;
969677Slinton private int argc;
979677Slinton private String argv[MAXNCMDARGS];
989677Slinton private String infile, outfile;
999677Slinton 
1009677Slinton /*
1019677Slinton  * Initialize process information.
1029677Slinton  */
1039677Slinton 
1049677Slinton public process_init()
1059677Slinton {
1069677Slinton     register Integer i;
1079677Slinton     Char buf[10];
1089677Slinton 
1099677Slinton     process = &pbuf;
1109677Slinton     process->status = (coredump) ? STOPPED : NOTSTARTED;
1119677Slinton     setsigtrace();
1129677Slinton     for (i = 0; i < NREG; i++) {
1139677Slinton 	sprintf(buf, "$r%d", i);
1149677Slinton 	defregname(identname(buf, false), i);
1159677Slinton     }
1169677Slinton     defregname(identname("$ap", true), ARGP);
1179677Slinton     defregname(identname("$fp", true), FRP);
1189677Slinton     defregname(identname("$sp", true), STKP);
1199677Slinton     defregname(identname("$pc", true), PROGCTR);
1209677Slinton     if (coredump) {
1219677Slinton 	coredump_readin(process->mask, process->reg, process->signo);
12212484Slinton 	pc = process->reg[PROGCTR];
12312484Slinton 	getsrcpos();
1249677Slinton     }
12512484Slinton     arginit();
1269677Slinton }
1279677Slinton 
1289677Slinton /*
1299677Slinton  * Routines to get at process information from outside this module.
1309677Slinton  */
1319677Slinton 
1329677Slinton public Word reg(n)
1339677Slinton Integer n;
1349677Slinton {
1359677Slinton     register Word w;
1369677Slinton 
1379677Slinton     if (n == NREG) {
1389677Slinton 	w = process->mask;
1399677Slinton     } else {
1409677Slinton 	w = process->reg[n];
1419677Slinton     }
1429677Slinton     return w;
1439677Slinton }
1449677Slinton 
1459677Slinton public setreg(n, w)
1469677Slinton Integer n;
1479677Slinton Word w;
1489677Slinton {
1499677Slinton     process->reg[n] = w;
1509677Slinton }
1519677Slinton 
1529677Slinton /*
1539677Slinton  * Begin execution.
1549677Slinton  *
1559677Slinton  * We set a breakpoint at the end of the code so that the
1569677Slinton  * process data doesn't disappear after the program terminates.
1579677Slinton  */
1589677Slinton 
1599677Slinton private Boolean remade();
1609677Slinton 
1619677Slinton public start(argv, infile, outfile)
1629677Slinton String argv[];
1639677Slinton String infile, outfile;
1649677Slinton {
1659677Slinton     String pargv[4];
1669677Slinton     Node cond;
1679677Slinton 
1689677Slinton     if (coredump) {
1699677Slinton 	coredump = false;
1709677Slinton 	fclose(corefile);
1719677Slinton 	coredump_close();
1729677Slinton     }
1739677Slinton     if (argv == nil) {
1749677Slinton 	argv = pargv;
1759677Slinton 	pargv[0] = objname;
1769677Slinton 	pargv[1] = nil;
1779677Slinton     } else {
1789677Slinton 	argv[argc] = nil;
1799677Slinton     }
180*18230Slinton     pstart(process, argv, infile, outfile);
1819677Slinton     if (remade(objname)) {
1829677Slinton 	reinit(argv, infile, outfile);
1839677Slinton     }
1849677Slinton     if (process->status == STOPPED) {
1859677Slinton 	pc = 0;
18616617Ssam 	setcurfunc(program);
1879677Slinton 	if (objsize != 0) {
1889677Slinton 	    cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr()));
1899677Slinton 	    event_once(cond, buildcmdlist(build(O_ENDX)));
1909677Slinton 	}
1919677Slinton     }
1929677Slinton }
1939677Slinton 
1949677Slinton /*
1959677Slinton  * Check to see if the object file has changed since the symbolic
1969677Slinton  * information last was read.
1979677Slinton  */
1989677Slinton 
1999677Slinton private time_t modtime;
2009677Slinton 
2019677Slinton private Boolean remade(filename)
2029677Slinton String filename;
2039677Slinton {
2049677Slinton     struct stat s;
2059677Slinton     Boolean b;
2069677Slinton 
2079677Slinton     stat(filename, &s);
2089677Slinton     b = (Boolean) (modtime != 0 and modtime < s.st_mtime);
2099677Slinton     modtime = s.st_mtime;
2109677Slinton     return b;
2119677Slinton }
2129677Slinton 
2139677Slinton /*
2149677Slinton  * Set up what signals we want to trace.
2159677Slinton  */
2169677Slinton 
2179677Slinton private setsigtrace()
2189677Slinton {
2199677Slinton     register Integer i;
2209677Slinton     register Process p;
2219677Slinton 
2229677Slinton     p = process;
2239677Slinton     for (i = 1; i <= NSIG; i++) {
2249677Slinton 	psigtrace(p, i, true);
2259677Slinton     }
2269677Slinton     psigtrace(p, SIGHUP, false);
2279677Slinton     psigtrace(p, SIGKILL, false);
2289677Slinton     psigtrace(p, SIGALRM, false);
2299677Slinton     psigtrace(p, SIGTSTP, false);
2309677Slinton     psigtrace(p, SIGCONT, false);
2319677Slinton     psigtrace(p, SIGCHLD, false);
2329677Slinton }
2339677Slinton 
2349677Slinton /*
2359677Slinton  * Initialize the argument list.
2369677Slinton  */
2379677Slinton 
2389677Slinton public arginit()
2399677Slinton {
2409677Slinton     infile = nil;
2419677Slinton     outfile = nil;
2429677Slinton     argv[0] = objname;
2439677Slinton     argc = 1;
2449677Slinton }
2459677Slinton 
2469677Slinton /*
2479677Slinton  * Add an argument to the list for the debuggee.
2489677Slinton  */
2499677Slinton 
2509677Slinton public newarg(arg)
2519677Slinton String arg;
2529677Slinton {
2539677Slinton     if (argc >= MAXNCMDARGS) {
2549677Slinton 	error("too many arguments");
2559677Slinton     }
2569677Slinton     argv[argc++] = arg;
2579677Slinton }
2589677Slinton 
2599677Slinton /*
2609677Slinton  * Set the standard input for the debuggee.
2619677Slinton  */
2629677Slinton 
2639677Slinton public inarg(filename)
2649677Slinton String filename;
2659677Slinton {
2669677Slinton     if (infile != nil) {
2679677Slinton 	error("multiple input redirects");
2689677Slinton     }
2699677Slinton     infile = filename;
2709677Slinton }
2719677Slinton 
2729677Slinton /*
2739677Slinton  * Set the standard output for the debuggee.
2749677Slinton  * Probably should check to avoid overwriting an existing file.
2759677Slinton  */
2769677Slinton 
2779677Slinton public outarg(filename)
2789677Slinton String filename;
2799677Slinton {
2809677Slinton     if (outfile != nil) {
2819677Slinton 	error("multiple output redirect");
2829677Slinton     }
2839677Slinton     outfile = filename;
2849677Slinton }
2859677Slinton 
2869677Slinton /*
2879677Slinton  * Start debuggee executing.
2889677Slinton  */
2899677Slinton 
2909677Slinton public run()
2919677Slinton {
2929677Slinton     process->status = STOPPED;
2939677Slinton     fixbps();
2949677Slinton     curline = 0;
2959677Slinton     start(argv, infile, outfile);
2969677Slinton     just_started = true;
2979677Slinton     isstopped = false;
29814757Slinton     cont(0);
2999677Slinton }
3009677Slinton 
3019677Slinton /*
3029677Slinton  * Continue execution wherever we left off.
3039677Slinton  *
3049677Slinton  * Note that this routine never returns.  Eventually bpact() will fail
3059677Slinton  * and we'll call printstatus or step will call it.
3069677Slinton  */
3079677Slinton 
3089677Slinton typedef int Intfunc();
3099677Slinton 
3109677Slinton private Intfunc *dbintr;
3119677Slinton private intr();
3129677Slinton 
31311867Slinton public cont(signo)
31416617Ssam integer signo;
3159677Slinton {
31616617Ssam     integer s;
31716617Ssam 
3189677Slinton     dbintr = signal(SIGINT, intr);
3199677Slinton     if (just_started) {
3209677Slinton 	just_started = false;
3219677Slinton     } else {
3229677Slinton 	if (not isstopped) {
3239677Slinton 	    error("can't continue execution");
3249677Slinton 	}
3259677Slinton 	isstopped = false;
32611867Slinton 	stepover();
3279677Slinton     }
32816617Ssam     s = signo;
3299677Slinton     for (;;) {
3309677Slinton 	if (single_stepping) {
3319677Slinton 	    printnews();
3329677Slinton 	} else {
3339677Slinton 	    setallbps();
33416617Ssam 	    resume(s);
3359677Slinton 	    unsetallbps();
33616617Ssam 	    s = DEFSIG;
337*18230Slinton 	    if (not isbperr() or not bpact()) {
3389677Slinton 		printstatus();
3399677Slinton 	    }
3409677Slinton 	}
34111867Slinton 	stepover();
3429677Slinton     }
3439677Slinton     /* NOTREACHED */
3449677Slinton }
3459677Slinton 
3469677Slinton /*
347*18230Slinton  * This routine is called if we get an interrupt while "running"
3489677Slinton  * but actually in the debugger.  Could happen, for example, while
3499677Slinton  * processing breakpoints.
3509677Slinton  *
3519677Slinton  * We basically just want to keep going; the assumption is
352*18230Slinton  * that when the process resumes it will get the interrupt,
3539677Slinton  * which will then be handled.
3549677Slinton  */
3559677Slinton 
3569677Slinton private intr()
3579677Slinton {
3589677Slinton     signal(SIGINT, intr);
3599677Slinton }
3609677Slinton 
3619677Slinton public fixintr()
3629677Slinton {
3639677Slinton     signal(SIGINT, dbintr);
3649677Slinton }
3659677Slinton 
3669677Slinton /*
3679677Slinton  * Resume execution.
3689677Slinton  */
3699677Slinton 
37011867Slinton public resume(signo)
37111867Slinton int signo;
3729677Slinton {
3739677Slinton     register Process p;
3749677Slinton 
3759677Slinton     p = process;
37611867Slinton     pcont(p, signo);
3779677Slinton     pc = process->reg[PROGCTR];
37811832Slinton     if (p->status != STOPPED) {
37911867Slinton 	if (p->signo != 0) {
38011867Slinton 	    error("program terminated by signal %d", p->signo);
38114757Slinton 	} else if (not runfirst) {
382*18230Slinton 	    if (p->exitval == 0) {
383*18230Slinton 		error("program exited");
384*18230Slinton 	    } else {
385*18230Slinton 		error("program exited with code %d", p->exitval);
386*18230Slinton 	    }
38711867Slinton 	}
38811832Slinton     }
3899677Slinton }
3909677Slinton 
3919677Slinton /*
3929677Slinton  * Continue execution up to the next source line.
3939677Slinton  *
3949677Slinton  * There are two ways to define the next source line depending on what
3959677Slinton  * is desired when a procedure or function call is encountered.  Step
3969677Slinton  * stops at the beginning of the procedure or call; next skips over it.
3979677Slinton  */
3989677Slinton 
3999677Slinton /*
4009677Slinton  * Stepc is what is called when the step command is given.
4019677Slinton  * It has to play with the "isstopped" information.
4029677Slinton  */
4039677Slinton 
4049677Slinton public stepc()
4059677Slinton {
4069677Slinton     if (not isstopped) {
4079677Slinton 	error("can't continue execution");
4089677Slinton     }
4099677Slinton     isstopped = false;
4109677Slinton     dostep(false);
4119677Slinton     isstopped = true;
4129677Slinton }
4139677Slinton 
4149677Slinton public next()
4159677Slinton {
41616617Ssam     Address oldfrp, newfrp;
41716617Ssam 
4189677Slinton     if (not isstopped) {
4199677Slinton 	error("can't continue execution");
4209677Slinton     }
4219677Slinton     isstopped = false;
42216617Ssam     oldfrp = reg(FRP);
42316617Ssam     do {
42416617Ssam 	dostep(true);
42516617Ssam 	pc = reg(PROGCTR);
42616617Ssam 	newfrp = reg(FRP);
42716617Ssam     } while (newfrp < oldfrp and newfrp != 0);
4289677Slinton     isstopped = true;
4299677Slinton }
4309677Slinton 
43111867Slinton /*
43216617Ssam  * Continue execution until the current function returns, or,
43316617Ssam  * if the given argument is non-nil, until execution returns to
43416617Ssam  * somewhere within the given function.
43516617Ssam  */
43616617Ssam 
43716617Ssam public rtnfunc (f)
43816617Ssam Symbol f;
43916617Ssam {
44016617Ssam     Address addr;
44116617Ssam     Symbol t;
44216617Ssam 
44316617Ssam     if (not isstopped) {
44416617Ssam 	error("can't continue execution");
44516617Ssam     } else if (f != nil and not isactive(f)) {
44616617Ssam 	error("%s is not active", symname(f));
44716617Ssam     } else {
44816617Ssam 	addr = return_addr();
44916617Ssam 	if (addr == nil) {
45016617Ssam 	    error("no place to return to");
45116617Ssam 	} else {
45216617Ssam 	    isstopped = false;
45316617Ssam 	    contto(addr);
45416617Ssam 	    if (f != nil) {
45516617Ssam 		for (;;) {
45616617Ssam 		    t = whatblock(pc);
45716617Ssam 		    addr = return_addr();
45816617Ssam 		if (t == f or addr == nil) break;
45916617Ssam 		    contto(addr);
46016617Ssam 		}
46116617Ssam 	    }
462*18230Slinton 	    if (not bpact()) {
46316617Ssam 		isstopped = true;
46416617Ssam 		printstatus();
46516617Ssam 	    }
46616617Ssam 	}
46716617Ssam     }
46816617Ssam }
46916617Ssam 
47016617Ssam /*
47111867Slinton  * Single-step over the current machine instruction.
47211867Slinton  *
47311867Slinton  * If we're single-stepping by source line we want to step to the
47411867Slinton  * next source line.  Otherwise we're going to continue so there's
47511867Slinton  * no reason to do all the work necessary to single-step to the next
47611867Slinton  * source line.
47711867Slinton  */
47811867Slinton 
47916617Ssam public stepover()
4809677Slinton {
48111867Slinton     Boolean b;
48211867Slinton 
48316617Ssam     if (traceexec) {
48416617Ssam 	printf("!! stepping over 0x%x\n", process->reg[PROGCTR]);
48516617Ssam     }
48611867Slinton     if (single_stepping) {
48711867Slinton 	dostep(false);
48811867Slinton     } else {
48911867Slinton 	b = inst_tracing;
49011867Slinton 	inst_tracing = true;
49111867Slinton 	dostep(false);
49211867Slinton 	inst_tracing = b;
49311867Slinton     }
49416617Ssam     if (traceexec) {
49516617Ssam 	printf("!! stepped over to 0x%x\n", process->reg[PROGCTR]);
49616617Ssam     }
4979677Slinton }
4989677Slinton 
4999677Slinton /*
500*18230Slinton  * Resume execution up to the given address.  We can either ignore
501*18230Slinton  * breakpoints (stepto) or catch them (contto).
5029677Slinton  */
5039677Slinton 
5049677Slinton public stepto(addr)
5059677Slinton Address addr;
5069677Slinton {
50716617Ssam     xto(addr, false);
50816617Ssam }
50916617Ssam 
51016617Ssam private contto (addr)
51116617Ssam Address addr;
51216617Ssam {
51316617Ssam     xto(addr, true);
51416617Ssam }
51516617Ssam 
51616617Ssam private xto (addr, catchbps)
51716617Ssam Address addr;
51816617Ssam boolean catchbps;
51916617Ssam {
52016617Ssam     Address curpc;
52116617Ssam 
52216617Ssam     if (catchbps) {
52316617Ssam 	stepover();
5249677Slinton     }
52516617Ssam     curpc = process->reg[PROGCTR];
52616617Ssam     if (addr != curpc) {
52716617Ssam 	if (traceexec) {
52816617Ssam 	    printf("!! stepping from 0x%x to 0x%x\n", curpc, addr);
52916617Ssam 	}
53016617Ssam 	if (catchbps) {
53116617Ssam 	    setallbps();
53216617Ssam 	}
53316617Ssam 	setbp(addr);
53416617Ssam 	resume(DEFSIG);
53516617Ssam 	unsetbp(addr);
53616617Ssam 	if (catchbps) {
53716617Ssam 	    unsetallbps();
53816617Ssam 	}
53916617Ssam 	if (not isbperr()) {
54016617Ssam 	    printstatus();
54116617Ssam 	}
54216617Ssam     }
5439677Slinton }
5449677Slinton 
5459677Slinton /*
5469677Slinton  * Print the status of the process.
5479677Slinton  * This routine does not return.
5489677Slinton  */
5499677Slinton 
5509677Slinton public printstatus()
5519677Slinton {
55214395Slinton     int status;
55314395Slinton 
5549843Slinton     if (process->status == FINISHED) {
5559843Slinton 	exit(0);
5569843Slinton     } else {
55716617Ssam 	setcurfunc(whatblock(pc));
5589677Slinton 	getsrcpos();
5599843Slinton 	if (process->signo == SIGINT) {
5609843Slinton 	    isstopped = true;
5619843Slinton 	    printerror();
5629843Slinton 	} else if (isbperr() and isstopped) {
5639843Slinton 	    printf("stopped ");
56411172Slinton 	    printloc();
56511172Slinton 	    putchar('\n');
5669843Slinton 	    if (curline > 0) {
5679843Slinton 		printlines(curline, curline);
5689843Slinton 	    } else {
5699843Slinton 		printinst(pc, pc);
5709843Slinton 	    }
5719843Slinton 	    erecover();
5729677Slinton 	} else {
5739843Slinton 	    fixintr();
5749677Slinton 	    isstopped = true;
5759677Slinton 	    printerror();
5769677Slinton 	}
5779677Slinton     }
5789677Slinton }
5799677Slinton 
5809677Slinton /*
58111172Slinton  * Print out the current location in the debuggee.
58211172Slinton  */
58311172Slinton 
58411172Slinton public printloc()
58511172Slinton {
58611172Slinton     printf("in ");
58711172Slinton     printname(stdout, curfunc);
58811172Slinton     putchar(' ');
58914757Slinton     if (curline > 0 and not useInstLoc) {
59011172Slinton 	printsrcpos();
59111172Slinton     } else {
59214757Slinton 	useInstLoc = false;
59314757Slinton 	curline = 0;
59411172Slinton 	printf("at 0x%x", pc);
59511172Slinton     }
59611172Slinton }
59711172Slinton 
59811172Slinton /*
5999677Slinton  * Some functions for testing the state of the process.
6009677Slinton  */
6019677Slinton 
6029677Slinton public Boolean notstarted(p)
6039677Slinton Process p;
6049677Slinton {
6059677Slinton     return (Boolean) (p->status == NOTSTARTED);
6069677Slinton }
6079677Slinton 
6089677Slinton public Boolean isfinished(p)
6099677Slinton Process p;
6109677Slinton {
6119677Slinton     return (Boolean) (p->status == FINISHED);
6129677Slinton }
6139677Slinton 
6149677Slinton /*
615*18230Slinton  * Predicate to test if the reason the process stopped was because
616*18230Slinton  * of a breakpoint.  If so, as a side effect clear the local copy of
617*18230Slinton  * signal handler associated with process.  We must do this so as to
618*18230Slinton  * not confuse future stepping or continuing by possibly concluding
619*18230Slinton  * the process should continue with a SIGTRAP handler.
6209677Slinton  */
6219677Slinton 
622*18230Slinton public boolean isbperr()
623*18230Slinton {
624*18230Slinton     Process p;
625*18230Slinton     boolean b;
626*18230Slinton 
627*18230Slinton     p = process;
628*18230Slinton     if (p->status == STOPPED and p->signo == SIGTRAP) {
629*18230Slinton 	b = true;
630*18230Slinton 	p->sigstatus = 0;
631*18230Slinton     } else {
632*18230Slinton 	b = false;
633*18230Slinton     }
634*18230Slinton     return b;
635*18230Slinton }
636*18230Slinton 
637*18230Slinton /*
638*18230Slinton  * Return the signal number that stopped the process.
639*18230Slinton  */
640*18230Slinton 
641*18230Slinton public integer errnum (p)
6429677Slinton Process p;
6439677Slinton {
6449677Slinton     return p->signo;
6459677Slinton }
6469677Slinton 
647*18230Slinton /*
648*18230Slinton  * Return the signal code associated with the signal.
649*18230Slinton  */
650*18230Slinton 
651*18230Slinton public integer errcode (p)
65216931Ssam Process p;
65316931Ssam {
65416931Ssam     return p->sigcode;
65516931Ssam }
65616931Ssam 
6579677Slinton /*
6589677Slinton  * Return the termination code of the process.
6599677Slinton  */
6609677Slinton 
661*18230Slinton public integer exitcode (p)
6629677Slinton Process p;
6639677Slinton {
6649677Slinton     return p->exitval;
6659677Slinton }
6669677Slinton 
6679677Slinton /*
6689677Slinton  * These routines are used to access the debuggee process from
6699677Slinton  * outside this module.
6709677Slinton  *
6719677Slinton  * They invoke "pio" which eventually leads to a call to "ptrace".
67214757Slinton  * The system generates an I/O error when a ptrace fails.  During reads
67314757Slinton  * these are ignored, during writes they are reported as an error, and
67414757Slinton  * for anything else they cause a fatal error.
6759677Slinton  */
6769677Slinton 
6779677Slinton extern Intfunc *onsyserr();
6789677Slinton 
6799677Slinton private badaddr;
68014757Slinton private read_err(), write_err();
6819677Slinton 
6829677Slinton /*
6839677Slinton  * Read from the process' instruction area.
6849677Slinton  */
6859677Slinton 
6869677Slinton public iread(buff, addr, nbytes)
6879677Slinton char *buff;
6889677Slinton Address addr;
6899677Slinton int nbytes;
6909677Slinton {
6919677Slinton     Intfunc *f;
6929677Slinton 
69314757Slinton     f = onsyserr(EIO, read_err);
6949677Slinton     badaddr = addr;
6959677Slinton     if (coredump) {
6969677Slinton 	coredump_readtext(buff, addr, nbytes);
6979677Slinton     } else {
6989677Slinton 	pio(process, PREAD, TEXTSEG, buff, addr, nbytes);
6999677Slinton     }
7009677Slinton     onsyserr(EIO, f);
7019677Slinton }
7029677Slinton 
7039677Slinton /*
7049677Slinton  * Write to the process' instruction area, usually in order to set
7059677Slinton  * or unset a breakpoint.
7069677Slinton  */
7079677Slinton 
7089677Slinton public iwrite(buff, addr, nbytes)
7099677Slinton char *buff;
7109677Slinton Address addr;
7119677Slinton int nbytes;
7129677Slinton {
7139677Slinton     Intfunc *f;
7149677Slinton 
7159677Slinton     if (coredump) {
7169677Slinton 	error("no process to write to");
7179677Slinton     }
71814757Slinton     f = onsyserr(EIO, write_err);
7199677Slinton     badaddr = addr;
7209677Slinton     pio(process, PWRITE, TEXTSEG, buff, addr, nbytes);
7219677Slinton     onsyserr(EIO, f);
7229677Slinton }
7239677Slinton 
7249677Slinton /*
7259677Slinton  * Read for the process' data area.
7269677Slinton  */
7279677Slinton 
7289677Slinton public dread(buff, addr, nbytes)
7299677Slinton char *buff;
7309677Slinton Address addr;
7319677Slinton int nbytes;
7329677Slinton {
7339677Slinton     Intfunc *f;
7349677Slinton 
7359677Slinton     badaddr = addr;
7369677Slinton     if (coredump) {
737*18230Slinton 	f = onsyserr(EFAULT, read_err);
7389677Slinton 	coredump_readdata(buff, addr, nbytes);
739*18230Slinton 	onsyserr(EFAULT, f);
7409677Slinton     } else {
741*18230Slinton 	f = onsyserr(EIO, read_err);
7429677Slinton 	pio(process, PREAD, DATASEG, buff, addr, nbytes);
743*18230Slinton 	onsyserr(EIO, f);
7449677Slinton     }
7459677Slinton }
7469677Slinton 
7479677Slinton /*
7489677Slinton  * Write to the process' data area.
7499677Slinton  */
7509677Slinton 
7519677Slinton public dwrite(buff, addr, nbytes)
7529677Slinton char *buff;
7539677Slinton Address addr;
7549677Slinton int nbytes;
7559677Slinton {
7569677Slinton     Intfunc *f;
7579677Slinton 
7589677Slinton     if (coredump) {
7599677Slinton 	error("no process to write to");
7609677Slinton     }
76114757Slinton     f = onsyserr(EIO, write_err);
7629677Slinton     badaddr = addr;
7639677Slinton     pio(process, PWRITE, DATASEG, buff, addr, nbytes);
7649677Slinton     onsyserr(EIO, f);
7659677Slinton }
7669677Slinton 
7679677Slinton /*
76814757Slinton  * Trap for errors in reading or writing to a process.
76914757Slinton  * The current approach is to "ignore" read errors and complain
77014757Slinton  * bitterly about write errors.
7719677Slinton  */
7729677Slinton 
77314757Slinton private read_err()
7749677Slinton {
77511560Slinton     /*
77614757Slinton      * Ignore.
77711560Slinton      */
7789677Slinton }
7799677Slinton 
78014757Slinton private write_err()
78114757Slinton {
78214757Slinton     error("can't write to process (address 0x%x)", badaddr);
78314757Slinton }
78414757Slinton 
7859677Slinton /*
7869677Slinton  * Ptrace interface.
7879677Slinton  */
7889677Slinton 
7899677Slinton /*
7909677Slinton  * This magic macro enables us to look at the process' registers
79114757Slinton  * in its user structure.
7929677Slinton  */
7939677Slinton 
7949677Slinton #define regloc(reg)     (ctob(UPAGES) + ( sizeof(int) * (reg) ))
7959677Slinton 
7969677Slinton #define WMASK           (~(sizeof(Word) - 1))
7979677Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE))
7989677Slinton 
7999677Slinton #define FIRSTSIG        SIGINT
8009677Slinton #define LASTSIG         SIGQUIT
8019677Slinton #define ischild(pid)    ((pid) == 0)
802*18230Slinton #define traceme()       ptrace(0, 0, 0, 0)
8039677Slinton #define setrep(n)       (1 << ((n)-1))
8049677Slinton #define istraced(p)     (p->sigset&setrep(p->signo))
8059677Slinton 
8069677Slinton /*
807*18230Slinton  * Ptrace options (specified in first argument).
808*18230Slinton  */
809*18230Slinton 
810*18230Slinton #define UREAD   3       /* read from process's user structure */
811*18230Slinton #define UWRITE  6       /* write to process's user structure */
812*18230Slinton #define IREAD   1       /* read from process's instruction space */
813*18230Slinton #define IWRITE  4       /* write to process's instruction space */
814*18230Slinton #define DREAD   2       /* read from process's data space */
815*18230Slinton #define DWRITE  5       /* write to process's data space */
816*18230Slinton #define CONT    7       /* continue stopped process */
817*18230Slinton #define SSTEP   9       /* continue for approximately one instruction */
818*18230Slinton #define PKILL   8       /* terminate the process */
819*18230Slinton 
820*18230Slinton /*
8219677Slinton  * Start up a new process by forking and exec-ing the
8229677Slinton  * given argument list, returning when the process is loaded
8239677Slinton  * and ready to execute.  The PROCESS information (pointed to
8249677Slinton  * by the first argument) is appropriately filled.
8259677Slinton  *
8269677Slinton  * If the given PROCESS structure is associated with an already running
8279677Slinton  * process, we terminate it.
8289677Slinton  */
8299677Slinton 
8309677Slinton /* VARARGS2 */
8319677Slinton private pstart(p, argv, infile, outfile)
8329677Slinton Process p;
8339677Slinton String argv[];
8349677Slinton String infile;
8359677Slinton String outfile;
8369677Slinton {
8379677Slinton     int status;
8389677Slinton 
83916617Ssam     if (p->pid != 0) {
84016617Ssam 	pterm(p);
841*18230Slinton 	cacheflush(p);
8429677Slinton     }
843*18230Slinton     fflush(stdout);
8449677Slinton     psigtrace(p, SIGTRAP, true);
84514395Slinton     p->pid = vfork();
84614395Slinton     if (p->pid == -1) {
8479677Slinton 	panic("can't fork");
8489677Slinton     }
8499677Slinton     if (ischild(p->pid)) {
850*18230Slinton 	nocatcherrs();
8519677Slinton 	traceme();
8529677Slinton 	if (infile != nil) {
85316617Ssam 	    infrom(infile);
8549677Slinton 	}
8559677Slinton 	if (outfile != nil) {
85616617Ssam 	    outto(outfile);
8579677Slinton 	}
85811832Slinton 	execv(argv[0], argv);
85911172Slinton 	_exit(1);
8609677Slinton     }
8619677Slinton     pwait(p->pid, &status);
8629677Slinton     getinfo(p, status);
8639677Slinton     if (p->status != STOPPED) {
864*18230Slinton 	beginerrmsg();
865*18230Slinton 	fprintf(stderr, "warning: cannot execute %s\n", argv[0]);
866*18230Slinton     } else {
867*18230Slinton 	ptraced(p->pid);
8689677Slinton     }
8699677Slinton }
8709677Slinton 
8719677Slinton /*
87216617Ssam  * Terminate a ptrace'd process.
87316617Ssam  */
87416617Ssam 
87516617Ssam public pterm (p)
87616617Ssam Process p;
87716617Ssam {
87816617Ssam     integer status;
87916617Ssam 
88016617Ssam     if (p != nil and p->pid != 0) {
881*18230Slinton 	ptrace(PKILL, p->pid, 0, 0);
88216617Ssam 	pwait(p->pid, &status);
88316617Ssam 	unptraced(p->pid);
88416617Ssam     }
88516617Ssam }
88616617Ssam 
88716617Ssam /*
88811867Slinton  * Continue a stopped process.  The first argument points to a Process
88911867Slinton  * structure.  Before the process is restarted it's user area is modified
89011867Slinton  * according to the values in the structure.  When this routine finishes,
8919677Slinton  * the structure has the new values from the process's user area.
8929677Slinton  *
8939677Slinton  * Pcont terminates when the process stops with a signal pending that
8949677Slinton  * is being traced (via psigtrace), or when the process terminates.
8959677Slinton  */
8969677Slinton 
89711867Slinton private pcont(p, signo)
8989677Slinton Process p;
89911867Slinton int signo;
9009677Slinton {
90116617Ssam     int s, status;
9029677Slinton 
9039677Slinton     if (p->pid == 0) {
904*18230Slinton 	error("program is not active");
9059677Slinton     }
90616617Ssam     s = signo;
9079677Slinton     do {
90816617Ssam 	setinfo(p, s);
90916617Ssam 	if (traceexec) {
91016617Ssam 	    printf("!! pcont from 0x%x with signal %d (%d)\n",
91116617Ssam 		p->reg[PROGCTR], s, p->signo);
91216617Ssam 	    fflush(stdout);
91316617Ssam 	}
9149677Slinton 	sigs_off();
915*18230Slinton 	if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) {
91614395Slinton 	    panic("error %d trying to continue process", errno);
9179677Slinton 	}
9189677Slinton 	pwait(p->pid, &status);
9199677Slinton 	sigs_on();
9209677Slinton 	getinfo(p, status);
921*18230Slinton 	if (p->status == STOPPED and traceexec and not istraced(p)) {
922*18230Slinton 	    printf("!! ignored signal %d at 0x%x\n",
923*18230Slinton 		p->signo, p->reg[PROGCTR]);
92416617Ssam 	    fflush(stdout);
92516617Ssam 	}
92616617Ssam 	s = p->signo;
9279677Slinton     } while (p->status == STOPPED and not istraced(p));
92816617Ssam     if (traceexec) {
92916617Ssam 	printf("!! pcont to 0x%x on signal %d\n", p->reg[PROGCTR], p->signo);
93016617Ssam 	fflush(stdout);
93116617Ssam     }
9329677Slinton }
9339677Slinton 
9349677Slinton /*
9359677Slinton  * Single step as best ptrace can.
9369677Slinton  */
9379677Slinton 
93816617Ssam public pstep(p, signo)
9399677Slinton Process p;
94016617Ssam integer signo;
9419677Slinton {
942*18230Slinton     int s, status;
9439677Slinton 
944*18230Slinton     s = signo;
945*18230Slinton     do {
946*18230Slinton 	setinfo(p, s);
947*18230Slinton 	if (traceexec) {
948*18230Slinton 	    printf("!! pstep from 0x%x with signal %d (%d)\n",
949*18230Slinton 		p->reg[PROGCTR], s, p->signo);
950*18230Slinton 	    fflush(stdout);
951*18230Slinton 	}
952*18230Slinton 	sigs_off();
953*18230Slinton 	if (ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo) < 0) {
954*18230Slinton 	    panic("error %d trying to step process", errno);
955*18230Slinton 	}
956*18230Slinton 	pwait(p->pid, &status);
957*18230Slinton 	sigs_on();
958*18230Slinton 	getinfo(p, status);
959*18230Slinton 	if (p->status == STOPPED and traceexec and not istraced(p)) {
960*18230Slinton 	    printf("!! pstep ignored signal %d at 0x%x\n",
961*18230Slinton 		p->signo, p->reg[PROGCTR]);
962*18230Slinton 	    fflush(stdout);
963*18230Slinton 	}
964*18230Slinton 	s = p->signo;
965*18230Slinton     } while (p->status == STOPPED and not istraced(p));
96616617Ssam     if (traceexec) {
967*18230Slinton 	printf("!! pstep to 0x%x on signal %d\n",
968*18230Slinton 	    p->reg[PROGCTR], p->signo);
96916617Ssam 	fflush(stdout);
97016617Ssam     }
97116617Ssam     if (p->status != STOPPED) {
972*18230Slinton 	if (p->exitval == 0) {
973*18230Slinton 	    error("program exited\n");
974*18230Slinton 	} else {
975*18230Slinton 	    error("program exited with code %d\n", p->exitval);
976*18230Slinton 	}
97716617Ssam     }
9789677Slinton }
9799677Slinton 
9809677Slinton /*
9819677Slinton  * Return from execution when the given signal is pending.
9829677Slinton  */
9839677Slinton 
9849677Slinton public psigtrace(p, sig, sw)
9859677Slinton Process p;
9869677Slinton int sig;
9879677Slinton Boolean sw;
9889677Slinton {
9899677Slinton     if (sw) {
9909677Slinton 	p->sigset |= setrep(sig);
9919677Slinton     } else {
9929677Slinton 	p->sigset &= ~setrep(sig);
9939677Slinton     }
9949677Slinton }
9959677Slinton 
9969677Slinton /*
9979677Slinton  * Don't catch any signals.
9989677Slinton  * Particularly useful when letting a process finish uninhibited.
9999677Slinton  */
10009677Slinton 
10019677Slinton public unsetsigtraces(p)
10029677Slinton Process p;
10039677Slinton {
10049677Slinton     p->sigset = 0;
10059677Slinton }
10069677Slinton 
10079677Slinton /*
10089677Slinton  * Turn off attention to signals not being caught.
10099677Slinton  */
10109677Slinton 
10119677Slinton private Intfunc *sigfunc[NSIG];
10129677Slinton 
10139677Slinton private sigs_off()
10149677Slinton {
10159677Slinton     register int i;
10169677Slinton 
10179677Slinton     for (i = FIRSTSIG; i < LASTSIG; i++) {
10189677Slinton 	if (i != SIGKILL) {
10199677Slinton 	    sigfunc[i] = signal(i, SIG_IGN);
10209677Slinton 	}
10219677Slinton     }
10229677Slinton }
10239677Slinton 
10249677Slinton /*
10259677Slinton  * Turn back on attention to signals.
10269677Slinton  */
10279677Slinton 
10289677Slinton private sigs_on()
10299677Slinton {
10309677Slinton     register int i;
10319677Slinton 
10329677Slinton     for (i = FIRSTSIG; i < LASTSIG; i++) {
10339677Slinton 	if (i != SIGKILL) {
10349677Slinton 	    signal(i, sigfunc[i]);
10359677Slinton 	}
10369677Slinton     }
10379677Slinton }
10389677Slinton 
10399677Slinton /*
10409677Slinton  * Get process information from user area.
10419677Slinton  */
10429677Slinton 
10439677Slinton private int rloc[] ={
10449677Slinton     R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC
10459677Slinton };
10469677Slinton 
10479677Slinton private getinfo(p, status)
10489677Slinton register Process p;
10499677Slinton register int status;
10509677Slinton {
10519677Slinton     register int i;
105216617Ssam     Address addr;
10539677Slinton 
10549677Slinton     p->signo = (status&0177);
10559677Slinton     p->exitval = ((status >> 8)&0377);
10569677Slinton     if (p->signo != STOPPED) {
10579677Slinton 	p->status = FINISHED;
105814757Slinton 	p->pid = 0;
105916617Ssam 	p->reg[PROGCTR] = 0;
10609677Slinton     } else {
10619677Slinton 	p->status = p->signo;
10629677Slinton 	p->signo = p->exitval;
1063*18230Slinton 	p->sigcode = ptrace(UREAD, p->pid, &((struct user *) 0)->u_code, 0);
10649677Slinton 	p->exitval = 0;
1065*18230Slinton 	p->mask = ptrace(UREAD, p->pid, regloc(PS), 0);
10669677Slinton 	for (i = 0; i < NREG; i++) {
1067*18230Slinton 	    p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0);
10689677Slinton 	    p->oreg[i] = p->reg[i];
10699677Slinton 	}
107011768Slinton 	savetty(stdout, &(p->ttyinfo));
107116617Ssam 	addr = (Address) &(((struct user *) 0)->u_signal[p->signo]);
1072*18230Slinton 	p->sigstatus = (Address) ptrace(UREAD, p->pid, addr, 0);
10739677Slinton     }
10749677Slinton }
10759677Slinton 
10769677Slinton /*
10779677Slinton  * Set process's user area information from given process structure.
10789677Slinton  */
10799677Slinton 
108011867Slinton private setinfo(p, signo)
10819677Slinton register Process p;
108211867Slinton int signo;
10839677Slinton {
10849677Slinton     register int i;
10859677Slinton     register int r;
10869677Slinton 
108714757Slinton     if (signo == DEFSIG) {
108816617Ssam 	if (istraced(p) and (p->sigstatus == 0 or p->sigstatus == 1)) {
108914757Slinton 	    p->signo = 0;
109014757Slinton 	}
109114757Slinton     } else {
109211867Slinton 	p->signo = signo;
10939677Slinton     }
10949677Slinton     for (i = 0; i < NREG; i++) {
10959677Slinton 	if ((r = p->reg[i]) != p->oreg[i]) {
1096*18230Slinton 	    ptrace(UWRITE, p->pid, regloc(rloc[i]), r);
10979677Slinton 	}
10989677Slinton     }
109911768Slinton     restoretty(stdout, &(p->ttyinfo));
11009677Slinton }
11019677Slinton 
11029677Slinton /*
110316617Ssam  * Return the address associated with the current signal.
110416617Ssam  * (Plus two since the address points to the beginning of a procedure).
110516617Ssam  */
110616617Ssam 
110716617Ssam public Address usignal (p)
110816617Ssam Process p;
110916617Ssam {
111016617Ssam     Address r;
111116617Ssam 
111216617Ssam     r = p->sigstatus;
111316617Ssam     if (r != 0 and r != 1) {
111416617Ssam 	r += 2;
111516617Ssam     }
111616617Ssam     return r;
111716617Ssam }
111816617Ssam 
111916617Ssam /*
11209677Slinton  * Structure for reading and writing by words, but dealing with bytes.
11219677Slinton  */
11229677Slinton 
11239677Slinton typedef union {
11249677Slinton     Word pword;
11259677Slinton     Byte pbyte[sizeof(Word)];
11269677Slinton } Pword;
11279677Slinton 
11289677Slinton /*
11299677Slinton  * Read (write) from (to) the process' address space.
11309677Slinton  * We must deal with ptrace's inability to look anywhere other
11319677Slinton  * than at a word boundary.
11329677Slinton  */
11339677Slinton 
11349677Slinton private Word fetch();
11359677Slinton private store();
11369677Slinton 
11379677Slinton private pio(p, op, seg, buff, addr, nbytes)
11389677Slinton Process p;
11399677Slinton PioOp op;
11409677Slinton PioSeg seg;
11419677Slinton char *buff;
11429677Slinton Address addr;
11439677Slinton int nbytes;
11449677Slinton {
11459677Slinton     register int i;
11469677Slinton     register Address newaddr;
11479677Slinton     register char *cp;
11489677Slinton     char *bufend;
11499677Slinton     Pword w;
11509677Slinton     Address wordaddr;
11519677Slinton     int byteoff;
11529677Slinton 
11539677Slinton     if (p->status != STOPPED) {
11549677Slinton 	error("program is not active");
11559677Slinton     }
11569677Slinton     cp = buff;
11579677Slinton     newaddr = addr;
11589677Slinton     wordaddr = (newaddr&WMASK);
11599677Slinton     if (wordaddr != newaddr) {
11609677Slinton 	w.pword = fetch(p, seg, wordaddr);
11619677Slinton 	for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) {
11629677Slinton 	    if (op == PREAD) {
11639677Slinton 		*cp++ = w.pbyte[i];
11649677Slinton 	    } else {
11659677Slinton 		w.pbyte[i] = *cp++;
11669677Slinton 	    }
11679677Slinton 	    nbytes--;
11689677Slinton 	}
11699677Slinton 	if (op == PWRITE) {
11709677Slinton 	    store(p, seg, wordaddr, w.pword);
11719677Slinton 	}
11729677Slinton 	newaddr = wordaddr + sizeof(Word);
11739677Slinton     }
11749677Slinton     byteoff = (nbytes&(~WMASK));
11759677Slinton     nbytes -= byteoff;
11769677Slinton     bufend = cp + nbytes;
11779677Slinton     while (cp < bufend) {
11789677Slinton 	if (op == PREAD) {
11799677Slinton 	    *((Word *) cp) = fetch(p, seg, newaddr);
11809677Slinton 	} else {
11819677Slinton 	    store(p, seg, newaddr, *((Word *) cp));
11829677Slinton 	}
11839677Slinton 	cp += sizeof(Word);
11849677Slinton 	newaddr += sizeof(Word);
11859677Slinton     }
11869677Slinton     if (byteoff > 0) {
11879677Slinton 	w.pword = fetch(p, seg, newaddr);
11889677Slinton 	for (i = 0; i < byteoff; i++) {
11899677Slinton 	    if (op == PREAD) {
11909677Slinton 		*cp++ = w.pbyte[i];
11919677Slinton 	    } else {
11929677Slinton 		w.pbyte[i] = *cp++;
11939677Slinton 	    }
11949677Slinton 	}
11959677Slinton 	if (op == PWRITE) {
11969677Slinton 	    store(p, seg, newaddr, w.pword);
11979677Slinton 	}
11989677Slinton     }
11999677Slinton }
12009677Slinton 
12019677Slinton /*
12029677Slinton  * Get a word from a process at the given address.
12039677Slinton  * The address is assumed to be on a word boundary.
12049677Slinton  *
12059677Slinton  * A simple cache scheme is used to avoid redundant ptrace calls
12069677Slinton  * to the instruction space since it is assumed to be pure.
12079677Slinton  *
12089677Slinton  * It is necessary to use a write-through scheme so that
12099677Slinton  * breakpoints right next to each other don't interfere.
12109677Slinton  */
12119677Slinton 
12129677Slinton private Integer nfetchs, nreads, nwrites;
12139677Slinton 
12149677Slinton private Word fetch(p, seg, addr)
12159677Slinton Process p;
12169677Slinton PioSeg seg;
12179677Slinton register int addr;
12189677Slinton {
12199677Slinton     register CacheWord *wp;
12209677Slinton     register Word w;
12219677Slinton 
12229677Slinton     switch (seg) {
12239677Slinton 	case TEXTSEG:
12249677Slinton 	    ++nfetchs;
12259677Slinton 	    wp = &p->word[cachehash(addr)];
12269677Slinton 	    if (addr == 0 or wp->addr != addr) {
12279677Slinton 		++nreads;
1228*18230Slinton 		w = ptrace(IREAD, p->pid, addr, 0);
12299677Slinton 		wp->addr = addr;
12309677Slinton 		wp->val = w;
12319677Slinton 	    } else {
12329677Slinton 		w = wp->val;
12339677Slinton 	    }
12349677Slinton 	    break;
12359677Slinton 
12369677Slinton 	case DATASEG:
1237*18230Slinton 	    w = ptrace(DREAD, p->pid, addr, 0);
12389677Slinton 	    break;
12399677Slinton 
12409677Slinton 	default:
12419677Slinton 	    panic("fetch: bad seg %d", seg);
12429677Slinton 	    /* NOTREACHED */
12439677Slinton     }
12449677Slinton     return w;
12459677Slinton }
12469677Slinton 
12479677Slinton /*
12489677Slinton  * Put a word into the process' address space at the given address.
12499677Slinton  * The address is assumed to be on a word boundary.
12509677Slinton  */
12519677Slinton 
12529677Slinton private store(p, seg, addr, data)
12539677Slinton Process p;
12549677Slinton PioSeg seg;
12559677Slinton int addr;
12569677Slinton Word data;
12579677Slinton {
12589677Slinton     register CacheWord *wp;
12599677Slinton 
12609677Slinton     switch (seg) {
12619677Slinton 	case TEXTSEG:
12629677Slinton 	    ++nwrites;
12639677Slinton 	    wp = &p->word[cachehash(addr)];
12649677Slinton 	    wp->addr = addr;
12659677Slinton 	    wp->val = data;
1266*18230Slinton 	    ptrace(IWRITE, p->pid, addr, data);
12679677Slinton 	    break;
12689677Slinton 
12699677Slinton 	case DATASEG:
1270*18230Slinton 	    ptrace(DWRITE, p->pid, addr, data);
12719677Slinton 	    break;
12729677Slinton 
12739677Slinton 	default:
12749677Slinton 	    panic("store: bad seg %d", seg);
12759677Slinton 	    /* NOTREACHED */
12769677Slinton     }
12779677Slinton }
12789677Slinton 
1279*18230Slinton /*
1280*18230Slinton  * Flush the instruction cache associated with a process.
1281*18230Slinton  */
1282*18230Slinton 
1283*18230Slinton private cacheflush (p)
1284*18230Slinton Process p;
1285*18230Slinton {
1286*18230Slinton     bzero(p->word, sizeof(p->word));
1287*18230Slinton }
1288*18230Slinton 
12899677Slinton public printptraceinfo()
12909677Slinton {
12919677Slinton     printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites);
12929677Slinton }
12939677Slinton 
12949677Slinton /*
129516617Ssam  * Redirect input.
129616617Ssam  * Assuming this is called from a child, we should be careful to avoid
129716617Ssam  * (possibly) shared standard I/O buffers.
12989677Slinton  */
12999677Slinton 
130016617Ssam private infrom (filename)
130116617Ssam String filename;
130216617Ssam {
130316617Ssam     Fileid in;
130416617Ssam 
130516617Ssam     in = open(filename, 0);
130616617Ssam     if (in == -1) {
130716617Ssam 	write(2, "can't read ", 11);
130816617Ssam 	write(2, filename, strlen(filename));
130916617Ssam 	write(2, "\n", 1);
131016617Ssam 	_exit(1);
131116617Ssam     }
131216617Ssam     fswap(0, in);
131316617Ssam }
131416617Ssam 
131516617Ssam /*
131616617Ssam  * Redirect standard output.
131716617Ssam  * Same assumptions as for "infrom" above.
131816617Ssam  */
131916617Ssam 
132016617Ssam private outto (filename)
132116617Ssam String filename;
132216617Ssam {
132316617Ssam     Fileid out;
132416617Ssam 
132516617Ssam     out = creat(filename, 0666);
132616617Ssam     if (out == -1) {
132716617Ssam 	write(2, "can't write ", 12);
132816617Ssam 	write(2, filename, strlen(filename));
132916617Ssam 	write(2, "\n", 1);
133016617Ssam 	_exit(1);
133116617Ssam     }
133216617Ssam     fswap(1, out);
133316617Ssam }
133416617Ssam 
133516617Ssam /*
133616617Ssam  * Swap file numbers, useful for redirecting standard input or output.
133716617Ssam  */
133816617Ssam 
13399677Slinton private fswap(oldfd, newfd)
134016617Ssam Fileid oldfd;
134116617Ssam Fileid newfd;
13429677Slinton {
13439677Slinton     if (oldfd != newfd) {
13449677Slinton 	close(oldfd);
13459677Slinton 	dup(newfd);
13469677Slinton 	close(newfd);
13479677Slinton     }
13489677Slinton }
134916928Ssam 
135016928Ssam /*
1351*18230Slinton  * Signal name manipulation.
135216928Ssam  */
1353*18230Slinton 
1354*18230Slinton private String signames[NSIG] = {
1355*18230Slinton     0,
1356*18230Slinton     "HUP", "INT", "QUIT", "ILL", "TRAP",
1357*18230Slinton     "IOT", "EMT", "FPE", "KILL", "BUS",
1358*18230Slinton     "SEGV", "SYS", "PIPE", "ALRM", "TERM",
1359*18230Slinton     0, "STOP", "TSTP", "CONT", "CHLD",
1360*18230Slinton     "TTIN", "TTOU", "TINT", "XCPU", "XFSZ",
136116928Ssam };
136216928Ssam 
136316928Ssam /*
1364*18230Slinton  * Get the signal number associated with a given name.
1365*18230Slinton  * The name is first translated to upper case if necessary.
136616928Ssam  */
1367*18230Slinton 
1368*18230Slinton public integer siglookup (s)
136916928Ssam String s;
137016928Ssam {
1371*18230Slinton     register char *p, *q;
1372*18230Slinton     char buf[100];
1373*18230Slinton     integer i;
137416928Ssam 
1375*18230Slinton     p = s;
1376*18230Slinton     q = buf;
1377*18230Slinton     while (*p != '\0') {
1378*18230Slinton 	if (*p >= 'a' and *p <= 'z') {
1379*18230Slinton 	    *q = (*p - 'a') + 'A';
1380*18230Slinton 	} else {
1381*18230Slinton 	    *q = *p;
1382*18230Slinton 	}
1383*18230Slinton 	++p;
1384*18230Slinton 	++q;
1385*18230Slinton     }
1386*18230Slinton     *q = '\0';
1387*18230Slinton     p = buf;
1388*18230Slinton     if (buf[0] == 'S' and buf[1] == 'I' and buf[2] == 'G') {
1389*18230Slinton 	p += 3;
1390*18230Slinton     }
1391*18230Slinton     i = 1;
1392*18230Slinton     for (;;) {
1393*18230Slinton 	if (i >= sizeof(signames) div sizeof(signames[0])) {
1394*18230Slinton 	    error("signal \"%s\" unknown", s);
1395*18230Slinton 	    i = 0;
1396*18230Slinton 	    break;
1397*18230Slinton 	}
1398*18230Slinton 	if (signames[i] != nil and streq(signames[i], p)) {
1399*18230Slinton 	    break;
1400*18230Slinton 	}
1401*18230Slinton 	++i;
1402*18230Slinton     }
1403*18230Slinton     return i;
140416928Ssam }
140516928Ssam 
140616928Ssam /*
1407*18230Slinton  * Print all signals being ignored by the debugger.
1408*18230Slinton  * These signals are auotmatically
140916928Ssam  * passed on to the debugged process.
141016928Ssam  */
1411*18230Slinton 
1412*18230Slinton public printsigsignored (p)
141316931Ssam Process p;
141416928Ssam {
141516931Ssam     printsigs(~p->sigset);
141616928Ssam }
141716928Ssam 
141816928Ssam /*
141916928Ssam  * Print all signals being intercepted by
142016928Ssam  * the debugger for the specified process.
142116928Ssam  */
1422*18230Slinton 
142316931Ssam public printsigscaught(p)
142416931Ssam Process p;
142516928Ssam {
142616931Ssam     printsigs(p->sigset);
142716931Ssam }
142816931Ssam 
1429*18230Slinton private printsigs (set)
1430*18230Slinton integer set;
143116931Ssam {
1432*18230Slinton     integer s;
1433*18230Slinton     char separator[2];
143416931Ssam 
1435*18230Slinton     separator[0] = '\0';
1436*18230Slinton     for (s = 1; s < sizeof(signames) div sizeof(signames[0]); s++) {
1437*18230Slinton 	if (set & setrep(s)) {
1438*18230Slinton 	    if (signames[s] != nil) {
1439*18230Slinton 		printf("%s%s", separator, signames[s]);
1440*18230Slinton 		separator[0] = ' ';
1441*18230Slinton 		separator[1] = '\0';
1442*18230Slinton 	    }
144316928Ssam 	}
1444*18230Slinton     }
1445*18230Slinton     if (separator[0] == ' ') {
144616931Ssam 	putchar('\n');
144716931Ssam     }
144816928Ssam }
1449