xref: /csrg-svn/old/dbx/process.c (revision 26333)
121620Sdist /*
221620Sdist  * Copyright (c) 1983 Regents of the University of California.
321620Sdist  * All rights reserved.  The Berkeley software License Agreement
421620Sdist  * specifies the terms and conditions for redistribution.
521620Sdist  */
69677Slinton 
721620Sdist #ifndef lint
8*26333Ssam static char sccsid[] = "@(#)process.c	5.2 (Berkeley) 02/23/86";
921620Sdist #endif not lint
109677Slinton 
1118230Slinton static char rcsid[] = "$Header: process.c,v 1.5 84/12/26 10:41:37 linton Exp $";
1218230Slinton 
139677Slinton /*
149677Slinton  * Process management.
159677Slinton  *
169677Slinton  * This module contains the routines to manage the execution and
179677Slinton  * tracing of the debuggee process.
189677Slinton  */
199677Slinton 
209677Slinton #include "defs.h"
219677Slinton #include "process.h"
229677Slinton #include "machine.h"
239677Slinton #include "events.h"
249677Slinton #include "tree.h"
2514757Slinton #include "eval.h"
269677Slinton #include "operators.h"
279677Slinton #include "source.h"
289677Slinton #include "object.h"
299677Slinton #include "mappings.h"
309677Slinton #include "main.h"
319677Slinton #include "coredump.h"
329677Slinton #include <signal.h>
339677Slinton #include <errno.h>
349677Slinton #include <sys/stat.h>
359677Slinton 
369677Slinton #ifndef public
379677Slinton 
389677Slinton typedef struct Process *Process;
399677Slinton 
409677Slinton Process process;
419677Slinton 
4214757Slinton #define DEFSIG -1
4314757Slinton 
449677Slinton #include "machine.h"
459677Slinton 
469677Slinton #endif
479677Slinton 
489677Slinton #define NOTSTARTED 1
499677Slinton #define STOPPED 0177
509677Slinton #define FINISHED 0
519677Slinton 
529677Slinton /*
5316617Ssam  * A cache of the instruction segment is kept to reduce the number
5416617Ssam  * of system calls.  Might be better just to read the entire
5516617Ssam  * code space into memory.
569677Slinton  */
579677Slinton 
589677Slinton #define CSIZE 1003       /* size of instruction cache */
599677Slinton 
609677Slinton typedef struct {
619677Slinton     Word addr;
629677Slinton     Word val;
639677Slinton } CacheWord;
649677Slinton 
659677Slinton /*
669677Slinton  * This structure holds the information we need from the user structure.
679677Slinton  */
689677Slinton 
699677Slinton struct Process {
709677Slinton     int pid;			/* process being traced */
7111768Slinton     int mask;			/* process status word */
7211768Slinton     Word reg[NREG];		/* process' registers */
739677Slinton     Word oreg[NREG];		/* registers when process last stopped */
749677Slinton     short status;		/* either STOPPED or FINISHED */
759677Slinton     short signo;		/* signal that stopped process */
7618230Slinton     short sigcode;		/* extra signal information */
779677Slinton     int exitval;		/* return value from exit() */
789677Slinton     long sigset;		/* bit array of traced signals */
799677Slinton     CacheWord word[CSIZE];	/* text segment cache */
8011768Slinton     Ttyinfo ttyinfo;		/* process' terminal characteristics */
8116617Ssam     Address sigstatus;		/* process' handler for current signal */
829677Slinton };
839677Slinton 
849677Slinton /*
859677Slinton  * These definitions are for the arguments to "pio".
869677Slinton  */
879677Slinton 
889677Slinton typedef enum { PREAD, PWRITE } PioOp;
899677Slinton typedef enum { TEXTSEG, DATASEG } PioSeg;
909677Slinton 
919677Slinton private struct Process pbuf;
929677Slinton 
9318230Slinton #define MAXNCMDARGS 1000         /* maximum number of arguments to RUN */
949677Slinton 
9514395Slinton extern int errno;
9614395Slinton 
979677Slinton private Boolean just_started;
989677Slinton private int argc;
999677Slinton private String argv[MAXNCMDARGS];
1009677Slinton private String infile, outfile;
1019677Slinton 
1029677Slinton /*
1039677Slinton  * Initialize process information.
1049677Slinton  */
1059677Slinton 
1069677Slinton public process_init()
1079677Slinton {
1089677Slinton     register Integer i;
1099677Slinton     Char buf[10];
1109677Slinton 
1119677Slinton     process = &pbuf;
1129677Slinton     process->status = (coredump) ? STOPPED : NOTSTARTED;
1139677Slinton     setsigtrace();
1149677Slinton     for (i = 0; i < NREG; i++) {
1159677Slinton 	sprintf(buf, "$r%d", i);
1169677Slinton 	defregname(identname(buf, false), i);
1179677Slinton     }
118*26333Ssam #ifdef vax
1199677Slinton     defregname(identname("$ap", true), ARGP);
120*26333Ssam #endif
1219677Slinton     defregname(identname("$fp", true), FRP);
1229677Slinton     defregname(identname("$sp", true), STKP);
1239677Slinton     defregname(identname("$pc", true), PROGCTR);
1249677Slinton     if (coredump) {
1259677Slinton 	coredump_readin(process->mask, process->reg, process->signo);
12612484Slinton 	pc = process->reg[PROGCTR];
12712484Slinton 	getsrcpos();
1289677Slinton     }
12912484Slinton     arginit();
1309677Slinton }
1319677Slinton 
1329677Slinton /*
1339677Slinton  * Routines to get at process information from outside this module.
1349677Slinton  */
1359677Slinton 
1369677Slinton public Word reg(n)
1379677Slinton Integer n;
1389677Slinton {
1399677Slinton     register Word w;
1409677Slinton 
1419677Slinton     if (n == NREG) {
1429677Slinton 	w = process->mask;
1439677Slinton     } else {
1449677Slinton 	w = process->reg[n];
1459677Slinton     }
1469677Slinton     return w;
1479677Slinton }
1489677Slinton 
1499677Slinton public setreg(n, w)
1509677Slinton Integer n;
1519677Slinton Word w;
1529677Slinton {
1539677Slinton     process->reg[n] = w;
1549677Slinton }
1559677Slinton 
1569677Slinton /*
1579677Slinton  * Begin execution.
1589677Slinton  *
1599677Slinton  * We set a breakpoint at the end of the code so that the
1609677Slinton  * process data doesn't disappear after the program terminates.
1619677Slinton  */
1629677Slinton 
1639677Slinton private Boolean remade();
1649677Slinton 
1659677Slinton public start(argv, infile, outfile)
1669677Slinton String argv[];
1679677Slinton String infile, outfile;
1689677Slinton {
1699677Slinton     String pargv[4];
1709677Slinton     Node cond;
1719677Slinton 
1729677Slinton     if (coredump) {
1739677Slinton 	coredump = false;
1749677Slinton 	fclose(corefile);
1759677Slinton 	coredump_close();
1769677Slinton     }
1779677Slinton     if (argv == nil) {
1789677Slinton 	argv = pargv;
1799677Slinton 	pargv[0] = objname;
1809677Slinton 	pargv[1] = nil;
1819677Slinton     } else {
1829677Slinton 	argv[argc] = nil;
1839677Slinton     }
18418230Slinton     pstart(process, argv, infile, outfile);
1859677Slinton     if (remade(objname)) {
1869677Slinton 	reinit(argv, infile, outfile);
1879677Slinton     }
1889677Slinton     if (process->status == STOPPED) {
1899677Slinton 	pc = 0;
19016617Ssam 	setcurfunc(program);
1919677Slinton 	if (objsize != 0) {
1929677Slinton 	    cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr()));
1939677Slinton 	    event_once(cond, buildcmdlist(build(O_ENDX)));
1949677Slinton 	}
1959677Slinton     }
1969677Slinton }
1979677Slinton 
1989677Slinton /*
1999677Slinton  * Check to see if the object file has changed since the symbolic
2009677Slinton  * information last was read.
2019677Slinton  */
2029677Slinton 
2039677Slinton private time_t modtime;
2049677Slinton 
2059677Slinton private Boolean remade(filename)
2069677Slinton String filename;
2079677Slinton {
2089677Slinton     struct stat s;
2099677Slinton     Boolean b;
2109677Slinton 
2119677Slinton     stat(filename, &s);
2129677Slinton     b = (Boolean) (modtime != 0 and modtime < s.st_mtime);
2139677Slinton     modtime = s.st_mtime;
2149677Slinton     return b;
2159677Slinton }
2169677Slinton 
2179677Slinton /*
2189677Slinton  * Set up what signals we want to trace.
2199677Slinton  */
2209677Slinton 
2219677Slinton private setsigtrace()
2229677Slinton {
2239677Slinton     register Integer i;
2249677Slinton     register Process p;
2259677Slinton 
2269677Slinton     p = process;
2279677Slinton     for (i = 1; i <= NSIG; i++) {
2289677Slinton 	psigtrace(p, i, true);
2299677Slinton     }
2309677Slinton     psigtrace(p, SIGHUP, false);
2319677Slinton     psigtrace(p, SIGKILL, false);
2329677Slinton     psigtrace(p, SIGALRM, false);
2339677Slinton     psigtrace(p, SIGTSTP, false);
2349677Slinton     psigtrace(p, SIGCONT, false);
2359677Slinton     psigtrace(p, SIGCHLD, false);
236*26333Ssam     psigtrace(p, SIGWINCH, false);
2379677Slinton }
2389677Slinton 
2399677Slinton /*
2409677Slinton  * Initialize the argument list.
2419677Slinton  */
2429677Slinton 
2439677Slinton public arginit()
2449677Slinton {
2459677Slinton     infile = nil;
2469677Slinton     outfile = nil;
2479677Slinton     argv[0] = objname;
2489677Slinton     argc = 1;
2499677Slinton }
2509677Slinton 
2519677Slinton /*
2529677Slinton  * Add an argument to the list for the debuggee.
2539677Slinton  */
2549677Slinton 
2559677Slinton public newarg(arg)
2569677Slinton String arg;
2579677Slinton {
2589677Slinton     if (argc >= MAXNCMDARGS) {
2599677Slinton 	error("too many arguments");
2609677Slinton     }
2619677Slinton     argv[argc++] = arg;
2629677Slinton }
2639677Slinton 
2649677Slinton /*
2659677Slinton  * Set the standard input for the debuggee.
2669677Slinton  */
2679677Slinton 
2689677Slinton public inarg(filename)
2699677Slinton String filename;
2709677Slinton {
2719677Slinton     if (infile != nil) {
2729677Slinton 	error("multiple input redirects");
2739677Slinton     }
2749677Slinton     infile = filename;
2759677Slinton }
2769677Slinton 
2779677Slinton /*
2789677Slinton  * Set the standard output for the debuggee.
2799677Slinton  * Probably should check to avoid overwriting an existing file.
2809677Slinton  */
2819677Slinton 
2829677Slinton public outarg(filename)
2839677Slinton String filename;
2849677Slinton {
2859677Slinton     if (outfile != nil) {
2869677Slinton 	error("multiple output redirect");
2879677Slinton     }
2889677Slinton     outfile = filename;
2899677Slinton }
2909677Slinton 
2919677Slinton /*
2929677Slinton  * Start debuggee executing.
2939677Slinton  */
2949677Slinton 
2959677Slinton public run()
2969677Slinton {
2979677Slinton     process->status = STOPPED;
2989677Slinton     fixbps();
2999677Slinton     curline = 0;
3009677Slinton     start(argv, infile, outfile);
3019677Slinton     just_started = true;
3029677Slinton     isstopped = false;
30314757Slinton     cont(0);
3049677Slinton }
3059677Slinton 
3069677Slinton /*
3079677Slinton  * Continue execution wherever we left off.
3089677Slinton  *
3099677Slinton  * Note that this routine never returns.  Eventually bpact() will fail
3109677Slinton  * and we'll call printstatus or step will call it.
3119677Slinton  */
3129677Slinton 
3139677Slinton typedef int Intfunc();
3149677Slinton 
3159677Slinton private Intfunc *dbintr;
3169677Slinton private intr();
3179677Slinton 
31811867Slinton public cont(signo)
31916617Ssam integer signo;
3209677Slinton {
32116617Ssam     integer s;
32216617Ssam 
3239677Slinton     dbintr = signal(SIGINT, intr);
3249677Slinton     if (just_started) {
3259677Slinton 	just_started = false;
3269677Slinton     } else {
3279677Slinton 	if (not isstopped) {
3289677Slinton 	    error("can't continue execution");
3299677Slinton 	}
3309677Slinton 	isstopped = false;
33111867Slinton 	stepover();
3329677Slinton     }
33316617Ssam     s = signo;
3349677Slinton     for (;;) {
3359677Slinton 	if (single_stepping) {
3369677Slinton 	    printnews();
3379677Slinton 	} else {
3389677Slinton 	    setallbps();
33916617Ssam 	    resume(s);
3409677Slinton 	    unsetallbps();
34116617Ssam 	    s = DEFSIG;
34218230Slinton 	    if (not isbperr() or not bpact()) {
3439677Slinton 		printstatus();
3449677Slinton 	    }
3459677Slinton 	}
34611867Slinton 	stepover();
3479677Slinton     }
3489677Slinton     /* NOTREACHED */
3499677Slinton }
3509677Slinton 
3519677Slinton /*
35218230Slinton  * This routine is called if we get an interrupt while "running"
3539677Slinton  * but actually in the debugger.  Could happen, for example, while
3549677Slinton  * processing breakpoints.
3559677Slinton  *
3569677Slinton  * We basically just want to keep going; the assumption is
35718230Slinton  * that when the process resumes it will get the interrupt,
3589677Slinton  * which will then be handled.
3599677Slinton  */
3609677Slinton 
3619677Slinton private intr()
3629677Slinton {
3639677Slinton     signal(SIGINT, intr);
3649677Slinton }
3659677Slinton 
3669677Slinton public fixintr()
3679677Slinton {
3689677Slinton     signal(SIGINT, dbintr);
3699677Slinton }
3709677Slinton 
3719677Slinton /*
3729677Slinton  * Resume execution.
3739677Slinton  */
3749677Slinton 
37511867Slinton public resume(signo)
37611867Slinton int signo;
3779677Slinton {
3789677Slinton     register Process p;
3799677Slinton 
3809677Slinton     p = process;
38111867Slinton     pcont(p, signo);
3829677Slinton     pc = process->reg[PROGCTR];
38311832Slinton     if (p->status != STOPPED) {
38411867Slinton 	if (p->signo != 0) {
38511867Slinton 	    error("program terminated by signal %d", p->signo);
38614757Slinton 	} else if (not runfirst) {
38718230Slinton 	    if (p->exitval == 0) {
38818230Slinton 		error("program exited");
38918230Slinton 	    } else {
39018230Slinton 		error("program exited with code %d", p->exitval);
39118230Slinton 	    }
39211867Slinton 	}
39311832Slinton     }
3949677Slinton }
3959677Slinton 
3969677Slinton /*
3979677Slinton  * Continue execution up to the next source line.
3989677Slinton  *
3999677Slinton  * There are two ways to define the next source line depending on what
4009677Slinton  * is desired when a procedure or function call is encountered.  Step
4019677Slinton  * stops at the beginning of the procedure or call; next skips over it.
4029677Slinton  */
4039677Slinton 
4049677Slinton /*
4059677Slinton  * Stepc is what is called when the step command is given.
4069677Slinton  * It has to play with the "isstopped" information.
4079677Slinton  */
4089677Slinton 
4099677Slinton public stepc()
4109677Slinton {
4119677Slinton     if (not isstopped) {
4129677Slinton 	error("can't continue execution");
4139677Slinton     }
4149677Slinton     isstopped = false;
4159677Slinton     dostep(false);
4169677Slinton     isstopped = true;
4179677Slinton }
4189677Slinton 
4199677Slinton public next()
4209677Slinton {
42116617Ssam     Address oldfrp, newfrp;
42216617Ssam 
4239677Slinton     if (not isstopped) {
4249677Slinton 	error("can't continue execution");
4259677Slinton     }
4269677Slinton     isstopped = false;
42716617Ssam     oldfrp = reg(FRP);
42816617Ssam     do {
42916617Ssam 	dostep(true);
43016617Ssam 	pc = reg(PROGCTR);
43116617Ssam 	newfrp = reg(FRP);
43216617Ssam     } while (newfrp < oldfrp and newfrp != 0);
4339677Slinton     isstopped = true;
4349677Slinton }
4359677Slinton 
43611867Slinton /*
43716617Ssam  * Continue execution until the current function returns, or,
43816617Ssam  * if the given argument is non-nil, until execution returns to
43916617Ssam  * somewhere within the given function.
44016617Ssam  */
44116617Ssam 
44216617Ssam public rtnfunc (f)
44316617Ssam Symbol f;
44416617Ssam {
44516617Ssam     Address addr;
44616617Ssam     Symbol t;
44716617Ssam 
44816617Ssam     if (not isstopped) {
44916617Ssam 	error("can't continue execution");
45016617Ssam     } else if (f != nil and not isactive(f)) {
45116617Ssam 	error("%s is not active", symname(f));
45216617Ssam     } else {
45316617Ssam 	addr = return_addr();
45416617Ssam 	if (addr == nil) {
45516617Ssam 	    error("no place to return to");
45616617Ssam 	} else {
45716617Ssam 	    isstopped = false;
45816617Ssam 	    contto(addr);
45916617Ssam 	    if (f != nil) {
46016617Ssam 		for (;;) {
46116617Ssam 		    t = whatblock(pc);
46216617Ssam 		    addr = return_addr();
46316617Ssam 		if (t == f or addr == nil) break;
46416617Ssam 		    contto(addr);
46516617Ssam 		}
46616617Ssam 	    }
46718230Slinton 	    if (not bpact()) {
46816617Ssam 		isstopped = true;
46916617Ssam 		printstatus();
47016617Ssam 	    }
47116617Ssam 	}
47216617Ssam     }
47316617Ssam }
47416617Ssam 
47516617Ssam /*
47611867Slinton  * Single-step over the current machine instruction.
47711867Slinton  *
47811867Slinton  * If we're single-stepping by source line we want to step to the
47911867Slinton  * next source line.  Otherwise we're going to continue so there's
48011867Slinton  * no reason to do all the work necessary to single-step to the next
48111867Slinton  * source line.
48211867Slinton  */
48311867Slinton 
48416617Ssam public stepover()
4859677Slinton {
48611867Slinton     Boolean b;
48711867Slinton 
48816617Ssam     if (traceexec) {
48916617Ssam 	printf("!! stepping over 0x%x\n", process->reg[PROGCTR]);
49016617Ssam     }
49111867Slinton     if (single_stepping) {
49211867Slinton 	dostep(false);
49311867Slinton     } else {
49411867Slinton 	b = inst_tracing;
49511867Slinton 	inst_tracing = true;
49611867Slinton 	dostep(false);
49711867Slinton 	inst_tracing = b;
49811867Slinton     }
49916617Ssam     if (traceexec) {
50016617Ssam 	printf("!! stepped over to 0x%x\n", process->reg[PROGCTR]);
50116617Ssam     }
5029677Slinton }
5039677Slinton 
5049677Slinton /*
50518230Slinton  * Resume execution up to the given address.  We can either ignore
50618230Slinton  * breakpoints (stepto) or catch them (contto).
5079677Slinton  */
5089677Slinton 
5099677Slinton public stepto(addr)
5109677Slinton Address addr;
5119677Slinton {
51216617Ssam     xto(addr, false);
51316617Ssam }
51416617Ssam 
51516617Ssam private contto (addr)
51616617Ssam Address addr;
51716617Ssam {
51816617Ssam     xto(addr, true);
51916617Ssam }
52016617Ssam 
52116617Ssam private xto (addr, catchbps)
52216617Ssam Address addr;
52316617Ssam boolean catchbps;
52416617Ssam {
52516617Ssam     Address curpc;
52616617Ssam 
52716617Ssam     if (catchbps) {
52816617Ssam 	stepover();
5299677Slinton     }
53016617Ssam     curpc = process->reg[PROGCTR];
53116617Ssam     if (addr != curpc) {
53216617Ssam 	if (traceexec) {
53316617Ssam 	    printf("!! stepping from 0x%x to 0x%x\n", curpc, addr);
53416617Ssam 	}
53516617Ssam 	if (catchbps) {
53616617Ssam 	    setallbps();
53716617Ssam 	}
53816617Ssam 	setbp(addr);
53916617Ssam 	resume(DEFSIG);
54016617Ssam 	unsetbp(addr);
54116617Ssam 	if (catchbps) {
54216617Ssam 	    unsetallbps();
54316617Ssam 	}
54416617Ssam 	if (not isbperr()) {
54516617Ssam 	    printstatus();
54616617Ssam 	}
54716617Ssam     }
5489677Slinton }
5499677Slinton 
5509677Slinton /*
5519677Slinton  * Print the status of the process.
5529677Slinton  * This routine does not return.
5539677Slinton  */
5549677Slinton 
5559677Slinton public printstatus()
5569677Slinton {
55714395Slinton     int status;
55814395Slinton 
5599843Slinton     if (process->status == FINISHED) {
5609843Slinton 	exit(0);
5619843Slinton     } else {
56216617Ssam 	setcurfunc(whatblock(pc));
5639677Slinton 	getsrcpos();
5649843Slinton 	if (process->signo == SIGINT) {
5659843Slinton 	    isstopped = true;
5669843Slinton 	    printerror();
5679843Slinton 	} else if (isbperr() and isstopped) {
5689843Slinton 	    printf("stopped ");
56911172Slinton 	    printloc();
57011172Slinton 	    putchar('\n');
5719843Slinton 	    if (curline > 0) {
5729843Slinton 		printlines(curline, curline);
5739843Slinton 	    } else {
5749843Slinton 		printinst(pc, pc);
5759843Slinton 	    }
5769843Slinton 	    erecover();
5779677Slinton 	} else {
5789843Slinton 	    fixintr();
5799677Slinton 	    isstopped = true;
5809677Slinton 	    printerror();
5819677Slinton 	}
5829677Slinton     }
5839677Slinton }
5849677Slinton 
5859677Slinton /*
58611172Slinton  * Print out the current location in the debuggee.
58711172Slinton  */
58811172Slinton 
58911172Slinton public printloc()
59011172Slinton {
59111172Slinton     printf("in ");
59211172Slinton     printname(stdout, curfunc);
59311172Slinton     putchar(' ');
59414757Slinton     if (curline > 0 and not useInstLoc) {
59511172Slinton 	printsrcpos();
59611172Slinton     } else {
59714757Slinton 	useInstLoc = false;
59814757Slinton 	curline = 0;
59911172Slinton 	printf("at 0x%x", pc);
60011172Slinton     }
60111172Slinton }
60211172Slinton 
60311172Slinton /*
6049677Slinton  * Some functions for testing the state of the process.
6059677Slinton  */
6069677Slinton 
6079677Slinton public Boolean notstarted(p)
6089677Slinton Process p;
6099677Slinton {
6109677Slinton     return (Boolean) (p->status == NOTSTARTED);
6119677Slinton }
6129677Slinton 
6139677Slinton public Boolean isfinished(p)
6149677Slinton Process p;
6159677Slinton {
6169677Slinton     return (Boolean) (p->status == FINISHED);
6179677Slinton }
6189677Slinton 
6199677Slinton /*
62018230Slinton  * Predicate to test if the reason the process stopped was because
62118230Slinton  * of a breakpoint.  If so, as a side effect clear the local copy of
62218230Slinton  * signal handler associated with process.  We must do this so as to
62318230Slinton  * not confuse future stepping or continuing by possibly concluding
62418230Slinton  * the process should continue with a SIGTRAP handler.
6259677Slinton  */
6269677Slinton 
62718230Slinton public boolean isbperr()
62818230Slinton {
62918230Slinton     Process p;
63018230Slinton     boolean b;
63118230Slinton 
63218230Slinton     p = process;
63318230Slinton     if (p->status == STOPPED and p->signo == SIGTRAP) {
63418230Slinton 	b = true;
63518230Slinton 	p->sigstatus = 0;
63618230Slinton     } else {
63718230Slinton 	b = false;
63818230Slinton     }
63918230Slinton     return b;
64018230Slinton }
64118230Slinton 
64218230Slinton /*
64318230Slinton  * Return the signal number that stopped the process.
64418230Slinton  */
64518230Slinton 
64618230Slinton public integer errnum (p)
6479677Slinton Process p;
6489677Slinton {
6499677Slinton     return p->signo;
6509677Slinton }
6519677Slinton 
65218230Slinton /*
65318230Slinton  * Return the signal code associated with the signal.
65418230Slinton  */
65518230Slinton 
65618230Slinton public integer errcode (p)
65716931Ssam Process p;
65816931Ssam {
65916931Ssam     return p->sigcode;
66016931Ssam }
66116931Ssam 
6629677Slinton /*
6639677Slinton  * Return the termination code of the process.
6649677Slinton  */
6659677Slinton 
66618230Slinton public integer exitcode (p)
6679677Slinton Process p;
6689677Slinton {
6699677Slinton     return p->exitval;
6709677Slinton }
6719677Slinton 
6729677Slinton /*
6739677Slinton  * These routines are used to access the debuggee process from
6749677Slinton  * outside this module.
6759677Slinton  *
6769677Slinton  * They invoke "pio" which eventually leads to a call to "ptrace".
67714757Slinton  * The system generates an I/O error when a ptrace fails.  During reads
67814757Slinton  * these are ignored, during writes they are reported as an error, and
67914757Slinton  * for anything else they cause a fatal error.
6809677Slinton  */
6819677Slinton 
6829677Slinton extern Intfunc *onsyserr();
6839677Slinton 
6849677Slinton private badaddr;
68514757Slinton private read_err(), write_err();
6869677Slinton 
6879677Slinton /*
6889677Slinton  * Read from the process' instruction area.
6899677Slinton  */
6909677Slinton 
6919677Slinton public iread(buff, addr, nbytes)
6929677Slinton char *buff;
6939677Slinton Address addr;
6949677Slinton int nbytes;
6959677Slinton {
6969677Slinton     Intfunc *f;
6979677Slinton 
69814757Slinton     f = onsyserr(EIO, read_err);
6999677Slinton     badaddr = addr;
7009677Slinton     if (coredump) {
7019677Slinton 	coredump_readtext(buff, addr, nbytes);
7029677Slinton     } else {
7039677Slinton 	pio(process, PREAD, TEXTSEG, buff, addr, nbytes);
7049677Slinton     }
7059677Slinton     onsyserr(EIO, f);
7069677Slinton }
7079677Slinton 
7089677Slinton /*
7099677Slinton  * Write to the process' instruction area, usually in order to set
7109677Slinton  * or unset a breakpoint.
7119677Slinton  */
7129677Slinton 
7139677Slinton public iwrite(buff, addr, nbytes)
7149677Slinton char *buff;
7159677Slinton Address addr;
7169677Slinton int nbytes;
7179677Slinton {
7189677Slinton     Intfunc *f;
7199677Slinton 
7209677Slinton     if (coredump) {
7219677Slinton 	error("no process to write to");
7229677Slinton     }
72314757Slinton     f = onsyserr(EIO, write_err);
7249677Slinton     badaddr = addr;
7259677Slinton     pio(process, PWRITE, TEXTSEG, buff, addr, nbytes);
7269677Slinton     onsyserr(EIO, f);
7279677Slinton }
7289677Slinton 
7299677Slinton /*
7309677Slinton  * Read for the process' data area.
7319677Slinton  */
7329677Slinton 
7339677Slinton public dread(buff, addr, nbytes)
7349677Slinton char *buff;
7359677Slinton Address addr;
7369677Slinton int nbytes;
7379677Slinton {
7389677Slinton     Intfunc *f;
7399677Slinton 
7409677Slinton     badaddr = addr;
7419677Slinton     if (coredump) {
74218230Slinton 	f = onsyserr(EFAULT, read_err);
7439677Slinton 	coredump_readdata(buff, addr, nbytes);
74418230Slinton 	onsyserr(EFAULT, f);
7459677Slinton     } else {
74618230Slinton 	f = onsyserr(EIO, read_err);
7479677Slinton 	pio(process, PREAD, DATASEG, buff, addr, nbytes);
74818230Slinton 	onsyserr(EIO, f);
7499677Slinton     }
7509677Slinton }
7519677Slinton 
7529677Slinton /*
7539677Slinton  * Write to the process' data area.
7549677Slinton  */
7559677Slinton 
7569677Slinton public dwrite(buff, addr, nbytes)
7579677Slinton char *buff;
7589677Slinton Address addr;
7599677Slinton int nbytes;
7609677Slinton {
7619677Slinton     Intfunc *f;
7629677Slinton 
7639677Slinton     if (coredump) {
7649677Slinton 	error("no process to write to");
7659677Slinton     }
76614757Slinton     f = onsyserr(EIO, write_err);
7679677Slinton     badaddr = addr;
7689677Slinton     pio(process, PWRITE, DATASEG, buff, addr, nbytes);
7699677Slinton     onsyserr(EIO, f);
7709677Slinton }
7719677Slinton 
7729677Slinton /*
77314757Slinton  * Trap for errors in reading or writing to a process.
77414757Slinton  * The current approach is to "ignore" read errors and complain
77514757Slinton  * bitterly about write errors.
7769677Slinton  */
7779677Slinton 
77814757Slinton private read_err()
7799677Slinton {
78011560Slinton     /*
78114757Slinton      * Ignore.
78211560Slinton      */
7839677Slinton }
7849677Slinton 
78514757Slinton private write_err()
78614757Slinton {
78714757Slinton     error("can't write to process (address 0x%x)", badaddr);
78814757Slinton }
78914757Slinton 
7909677Slinton /*
7919677Slinton  * Ptrace interface.
7929677Slinton  */
7939677Slinton 
7949677Slinton /*
7959677Slinton  * This magic macro enables us to look at the process' registers
79614757Slinton  * in its user structure.
7979677Slinton  */
7989677Slinton 
7999677Slinton #define regloc(reg)     (ctob(UPAGES) + ( sizeof(int) * (reg) ))
8009677Slinton 
8019677Slinton #define WMASK           (~(sizeof(Word) - 1))
8029677Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE))
8039677Slinton 
8049677Slinton #define FIRSTSIG        SIGINT
8059677Slinton #define LASTSIG         SIGQUIT
8069677Slinton #define ischild(pid)    ((pid) == 0)
80718230Slinton #define traceme()       ptrace(0, 0, 0, 0)
8089677Slinton #define setrep(n)       (1 << ((n)-1))
8099677Slinton #define istraced(p)     (p->sigset&setrep(p->signo))
8109677Slinton 
8119677Slinton /*
81218230Slinton  * Ptrace options (specified in first argument).
81318230Slinton  */
81418230Slinton 
81518230Slinton #define UREAD   3       /* read from process's user structure */
81618230Slinton #define UWRITE  6       /* write to process's user structure */
81718230Slinton #define IREAD   1       /* read from process's instruction space */
81818230Slinton #define IWRITE  4       /* write to process's instruction space */
81918230Slinton #define DREAD   2       /* read from process's data space */
82018230Slinton #define DWRITE  5       /* write to process's data space */
82118230Slinton #define CONT    7       /* continue stopped process */
82218230Slinton #define SSTEP   9       /* continue for approximately one instruction */
82318230Slinton #define PKILL   8       /* terminate the process */
82418230Slinton 
82518230Slinton /*
8269677Slinton  * Start up a new process by forking and exec-ing the
8279677Slinton  * given argument list, returning when the process is loaded
8289677Slinton  * and ready to execute.  The PROCESS information (pointed to
8299677Slinton  * by the first argument) is appropriately filled.
8309677Slinton  *
8319677Slinton  * If the given PROCESS structure is associated with an already running
8329677Slinton  * process, we terminate it.
8339677Slinton  */
8349677Slinton 
8359677Slinton /* VARARGS2 */
8369677Slinton private pstart(p, argv, infile, outfile)
8379677Slinton Process p;
8389677Slinton String argv[];
8399677Slinton String infile;
8409677Slinton String outfile;
8419677Slinton {
8429677Slinton     int status;
8439677Slinton 
84416617Ssam     if (p->pid != 0) {
84516617Ssam 	pterm(p);
84618230Slinton 	cacheflush(p);
8479677Slinton     }
84818230Slinton     fflush(stdout);
8499677Slinton     psigtrace(p, SIGTRAP, true);
85014395Slinton     p->pid = vfork();
85114395Slinton     if (p->pid == -1) {
8529677Slinton 	panic("can't fork");
8539677Slinton     }
8549677Slinton     if (ischild(p->pid)) {
85518230Slinton 	nocatcherrs();
8569677Slinton 	traceme();
8579677Slinton 	if (infile != nil) {
85816617Ssam 	    infrom(infile);
8599677Slinton 	}
8609677Slinton 	if (outfile != nil) {
86116617Ssam 	    outto(outfile);
8629677Slinton 	}
86311832Slinton 	execv(argv[0], argv);
86411172Slinton 	_exit(1);
8659677Slinton     }
8669677Slinton     pwait(p->pid, &status);
8679677Slinton     getinfo(p, status);
8689677Slinton     if (p->status != STOPPED) {
86918230Slinton 	beginerrmsg();
87018230Slinton 	fprintf(stderr, "warning: cannot execute %s\n", argv[0]);
87118230Slinton     } else {
87218230Slinton 	ptraced(p->pid);
8739677Slinton     }
8749677Slinton }
8759677Slinton 
8769677Slinton /*
87716617Ssam  * Terminate a ptrace'd process.
87816617Ssam  */
87916617Ssam 
88016617Ssam public pterm (p)
88116617Ssam Process p;
88216617Ssam {
88316617Ssam     integer status;
88416617Ssam 
88516617Ssam     if (p != nil and p->pid != 0) {
88618230Slinton 	ptrace(PKILL, p->pid, 0, 0);
88716617Ssam 	pwait(p->pid, &status);
88816617Ssam 	unptraced(p->pid);
88916617Ssam     }
89016617Ssam }
89116617Ssam 
89216617Ssam /*
89311867Slinton  * Continue a stopped process.  The first argument points to a Process
89411867Slinton  * structure.  Before the process is restarted it's user area is modified
89511867Slinton  * according to the values in the structure.  When this routine finishes,
8969677Slinton  * the structure has the new values from the process's user area.
8979677Slinton  *
8989677Slinton  * Pcont terminates when the process stops with a signal pending that
8999677Slinton  * is being traced (via psigtrace), or when the process terminates.
9009677Slinton  */
9019677Slinton 
90211867Slinton private pcont(p, signo)
9039677Slinton Process p;
90411867Slinton int signo;
9059677Slinton {
90616617Ssam     int s, status;
9079677Slinton 
9089677Slinton     if (p->pid == 0) {
90918230Slinton 	error("program is not active");
9109677Slinton     }
91116617Ssam     s = signo;
9129677Slinton     do {
91316617Ssam 	setinfo(p, s);
91416617Ssam 	if (traceexec) {
91516617Ssam 	    printf("!! pcont from 0x%x with signal %d (%d)\n",
91616617Ssam 		p->reg[PROGCTR], s, p->signo);
91716617Ssam 	    fflush(stdout);
91816617Ssam 	}
9199677Slinton 	sigs_off();
92018230Slinton 	if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) {
92114395Slinton 	    panic("error %d trying to continue process", errno);
9229677Slinton 	}
9239677Slinton 	pwait(p->pid, &status);
9249677Slinton 	sigs_on();
9259677Slinton 	getinfo(p, status);
92618230Slinton 	if (p->status == STOPPED and traceexec and not istraced(p)) {
92718230Slinton 	    printf("!! ignored signal %d at 0x%x\n",
92818230Slinton 		p->signo, p->reg[PROGCTR]);
92916617Ssam 	    fflush(stdout);
93016617Ssam 	}
93116617Ssam 	s = p->signo;
9329677Slinton     } while (p->status == STOPPED and not istraced(p));
93316617Ssam     if (traceexec) {
93416617Ssam 	printf("!! pcont to 0x%x on signal %d\n", p->reg[PROGCTR], p->signo);
93516617Ssam 	fflush(stdout);
93616617Ssam     }
9379677Slinton }
9389677Slinton 
9399677Slinton /*
9409677Slinton  * Single step as best ptrace can.
9419677Slinton  */
9429677Slinton 
94316617Ssam public pstep(p, signo)
9449677Slinton Process p;
94516617Ssam integer signo;
9469677Slinton {
94718230Slinton     int s, status;
9489677Slinton 
94918230Slinton     s = signo;
95018230Slinton     do {
95118230Slinton 	setinfo(p, s);
95218230Slinton 	if (traceexec) {
95318230Slinton 	    printf("!! pstep from 0x%x with signal %d (%d)\n",
95418230Slinton 		p->reg[PROGCTR], s, p->signo);
95518230Slinton 	    fflush(stdout);
95618230Slinton 	}
95718230Slinton 	sigs_off();
95818230Slinton 	if (ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo) < 0) {
95918230Slinton 	    panic("error %d trying to step process", errno);
96018230Slinton 	}
96118230Slinton 	pwait(p->pid, &status);
96218230Slinton 	sigs_on();
96318230Slinton 	getinfo(p, status);
96418230Slinton 	if (p->status == STOPPED and traceexec and not istraced(p)) {
96518230Slinton 	    printf("!! pstep ignored signal %d at 0x%x\n",
96618230Slinton 		p->signo, p->reg[PROGCTR]);
96718230Slinton 	    fflush(stdout);
96818230Slinton 	}
96918230Slinton 	s = p->signo;
97018230Slinton     } while (p->status == STOPPED and not istraced(p));
97116617Ssam     if (traceexec) {
97218230Slinton 	printf("!! pstep to 0x%x on signal %d\n",
97318230Slinton 	    p->reg[PROGCTR], p->signo);
97416617Ssam 	fflush(stdout);
97516617Ssam     }
97616617Ssam     if (p->status != STOPPED) {
97718230Slinton 	if (p->exitval == 0) {
97818230Slinton 	    error("program exited\n");
97918230Slinton 	} else {
98018230Slinton 	    error("program exited with code %d\n", p->exitval);
98118230Slinton 	}
98216617Ssam     }
9839677Slinton }
9849677Slinton 
9859677Slinton /*
9869677Slinton  * Return from execution when the given signal is pending.
9879677Slinton  */
9889677Slinton 
9899677Slinton public psigtrace(p, sig, sw)
9909677Slinton Process p;
9919677Slinton int sig;
9929677Slinton Boolean sw;
9939677Slinton {
9949677Slinton     if (sw) {
9959677Slinton 	p->sigset |= setrep(sig);
9969677Slinton     } else {
9979677Slinton 	p->sigset &= ~setrep(sig);
9989677Slinton     }
9999677Slinton }
10009677Slinton 
10019677Slinton /*
10029677Slinton  * Don't catch any signals.
10039677Slinton  * Particularly useful when letting a process finish uninhibited.
10049677Slinton  */
10059677Slinton 
10069677Slinton public unsetsigtraces(p)
10079677Slinton Process p;
10089677Slinton {
10099677Slinton     p->sigset = 0;
10109677Slinton }
10119677Slinton 
10129677Slinton /*
10139677Slinton  * Turn off attention to signals not being caught.
10149677Slinton  */
10159677Slinton 
10169677Slinton private Intfunc *sigfunc[NSIG];
10179677Slinton 
10189677Slinton private sigs_off()
10199677Slinton {
10209677Slinton     register int i;
10219677Slinton 
10229677Slinton     for (i = FIRSTSIG; i < LASTSIG; i++) {
10239677Slinton 	if (i != SIGKILL) {
10249677Slinton 	    sigfunc[i] = signal(i, SIG_IGN);
10259677Slinton 	}
10269677Slinton     }
10279677Slinton }
10289677Slinton 
10299677Slinton /*
10309677Slinton  * Turn back on attention to signals.
10319677Slinton  */
10329677Slinton 
10339677Slinton private sigs_on()
10349677Slinton {
10359677Slinton     register int i;
10369677Slinton 
10379677Slinton     for (i = FIRSTSIG; i < LASTSIG; i++) {
10389677Slinton 	if (i != SIGKILL) {
10399677Slinton 	    signal(i, sigfunc[i]);
10409677Slinton 	}
10419677Slinton     }
10429677Slinton }
10439677Slinton 
10449677Slinton /*
10459677Slinton  * Get process information from user area.
10469677Slinton  */
10479677Slinton 
10489677Slinton private getinfo(p, status)
10499677Slinton register Process p;
10509677Slinton register int status;
10519677Slinton {
10529677Slinton     register int i;
105316617Ssam     Address addr;
10549677Slinton 
10559677Slinton     p->signo = (status&0177);
10569677Slinton     p->exitval = ((status >> 8)&0377);
10579677Slinton     if (p->signo != STOPPED) {
10589677Slinton 	p->status = FINISHED;
105914757Slinton 	p->pid = 0;
106016617Ssam 	p->reg[PROGCTR] = 0;
10619677Slinton     } else {
10629677Slinton 	p->status = p->signo;
10639677Slinton 	p->signo = p->exitval;
106418230Slinton 	p->sigcode = ptrace(UREAD, p->pid, &((struct user *) 0)->u_code, 0);
10659677Slinton 	p->exitval = 0;
106618230Slinton 	p->mask = ptrace(UREAD, p->pid, regloc(PS), 0);
10679677Slinton 	for (i = 0; i < NREG; i++) {
106818230Slinton 	    p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0);
10699677Slinton 	    p->oreg[i] = p->reg[i];
10709677Slinton 	}
107111768Slinton 	savetty(stdout, &(p->ttyinfo));
107216617Ssam 	addr = (Address) &(((struct user *) 0)->u_signal[p->signo]);
107318230Slinton 	p->sigstatus = (Address) ptrace(UREAD, p->pid, addr, 0);
10749677Slinton     }
10759677Slinton }
10769677Slinton 
10779677Slinton /*
10789677Slinton  * Set process's user area information from given process structure.
10799677Slinton  */
10809677Slinton 
108111867Slinton private setinfo(p, signo)
10829677Slinton register Process p;
108311867Slinton int signo;
10849677Slinton {
10859677Slinton     register int i;
10869677Slinton     register int r;
10879677Slinton 
108814757Slinton     if (signo == DEFSIG) {
108916617Ssam 	if (istraced(p) and (p->sigstatus == 0 or p->sigstatus == 1)) {
109014757Slinton 	    p->signo = 0;
109114757Slinton 	}
109214757Slinton     } else {
109311867Slinton 	p->signo = signo;
10949677Slinton     }
10959677Slinton     for (i = 0; i < NREG; i++) {
10969677Slinton 	if ((r = p->reg[i]) != p->oreg[i]) {
109718230Slinton 	    ptrace(UWRITE, p->pid, regloc(rloc[i]), r);
10989677Slinton 	}
10999677Slinton     }
110011768Slinton     restoretty(stdout, &(p->ttyinfo));
11019677Slinton }
11029677Slinton 
11039677Slinton /*
110416617Ssam  * Return the address associated with the current signal.
110516617Ssam  * (Plus two since the address points to the beginning of a procedure).
110616617Ssam  */
110716617Ssam 
110816617Ssam public Address usignal (p)
110916617Ssam Process p;
111016617Ssam {
111116617Ssam     Address r;
111216617Ssam 
111316617Ssam     r = p->sigstatus;
111416617Ssam     if (r != 0 and r != 1) {
111516617Ssam 	r += 2;
111616617Ssam     }
111716617Ssam     return r;
111816617Ssam }
111916617Ssam 
112016617Ssam /*
11219677Slinton  * Structure for reading and writing by words, but dealing with bytes.
11229677Slinton  */
11239677Slinton 
11249677Slinton typedef union {
11259677Slinton     Word pword;
11269677Slinton     Byte pbyte[sizeof(Word)];
11279677Slinton } Pword;
11289677Slinton 
11299677Slinton /*
11309677Slinton  * Read (write) from (to) the process' address space.
11319677Slinton  * We must deal with ptrace's inability to look anywhere other
11329677Slinton  * than at a word boundary.
11339677Slinton  */
11349677Slinton 
11359677Slinton private Word fetch();
11369677Slinton private store();
11379677Slinton 
11389677Slinton private pio(p, op, seg, buff, addr, nbytes)
11399677Slinton Process p;
11409677Slinton PioOp op;
11419677Slinton PioSeg seg;
11429677Slinton char *buff;
11439677Slinton Address addr;
11449677Slinton int nbytes;
11459677Slinton {
11469677Slinton     register int i;
11479677Slinton     register Address newaddr;
11489677Slinton     register char *cp;
11499677Slinton     char *bufend;
11509677Slinton     Pword w;
11519677Slinton     Address wordaddr;
11529677Slinton     int byteoff;
11539677Slinton 
11549677Slinton     if (p->status != STOPPED) {
11559677Slinton 	error("program is not active");
11569677Slinton     }
11579677Slinton     cp = buff;
11589677Slinton     newaddr = addr;
11599677Slinton     wordaddr = (newaddr&WMASK);
11609677Slinton     if (wordaddr != newaddr) {
11619677Slinton 	w.pword = fetch(p, seg, wordaddr);
11629677Slinton 	for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) {
11639677Slinton 	    if (op == PREAD) {
11649677Slinton 		*cp++ = w.pbyte[i];
11659677Slinton 	    } else {
11669677Slinton 		w.pbyte[i] = *cp++;
11679677Slinton 	    }
11689677Slinton 	    nbytes--;
11699677Slinton 	}
11709677Slinton 	if (op == PWRITE) {
11719677Slinton 	    store(p, seg, wordaddr, w.pword);
11729677Slinton 	}
11739677Slinton 	newaddr = wordaddr + sizeof(Word);
11749677Slinton     }
11759677Slinton     byteoff = (nbytes&(~WMASK));
11769677Slinton     nbytes -= byteoff;
11779677Slinton     bufend = cp + nbytes;
1178*26333Ssam #ifdef tahoe
1179*26333Ssam     if (((int)cp)&WMASK) {
1180*26333Ssam 	/*
1181*26333Ssam 	 * Must copy a byte at a time, buffer not word addressable.
1182*26333Ssam 	 */
1183*26333Ssam 	while (cp < bufend) {
1184*26333Ssam 	    if (op == PREAD) {
1185*26333Ssam 		w.pword = fetch(p, seg, newaddr);
1186*26333Ssam 		for (i = 0; i < sizeof(Word); i++)
1187*26333Ssam 		    *cp++ = w.pbyte[i];
1188*26333Ssam 	    } else {
1189*26333Ssam 		for (i = 0; i < sizeof(Word); i++)
1190*26333Ssam 		    w.pbyte[i] = *cp++;
1191*26333Ssam 		store(p, seg, newaddr, w.pword);
1192*26333Ssam 	    }
1193*26333Ssam 	    newaddr += sizeof(Word);
1194*26333Ssam 	}
1195*26333Ssam     } else {
1196*26333Ssam     /*
1197*26333Ssam      * Buffer, word aligned, act normally...
1198*26333Ssam      */
1199*26333Ssam #endif
12009677Slinton     while (cp < bufend) {
12019677Slinton 	if (op == PREAD) {
12029677Slinton 	    *((Word *) cp) = fetch(p, seg, newaddr);
12039677Slinton 	} else {
12049677Slinton 	    store(p, seg, newaddr, *((Word *) cp));
12059677Slinton 	}
12069677Slinton 	cp += sizeof(Word);
12079677Slinton 	newaddr += sizeof(Word);
12089677Slinton     }
1209*26333Ssam #ifdef tahoe
1210*26333Ssam     }
1211*26333Ssam #endif
12129677Slinton     if (byteoff > 0) {
12139677Slinton 	w.pword = fetch(p, seg, newaddr);
12149677Slinton 	for (i = 0; i < byteoff; i++) {
12159677Slinton 	    if (op == PREAD) {
12169677Slinton 		*cp++ = w.pbyte[i];
12179677Slinton 	    } else {
12189677Slinton 		w.pbyte[i] = *cp++;
12199677Slinton 	    }
12209677Slinton 	}
12219677Slinton 	if (op == PWRITE) {
12229677Slinton 	    store(p, seg, newaddr, w.pword);
12239677Slinton 	}
12249677Slinton     }
12259677Slinton }
12269677Slinton 
12279677Slinton /*
12289677Slinton  * Get a word from a process at the given address.
12299677Slinton  * The address is assumed to be on a word boundary.
12309677Slinton  *
12319677Slinton  * A simple cache scheme is used to avoid redundant ptrace calls
12329677Slinton  * to the instruction space since it is assumed to be pure.
12339677Slinton  *
12349677Slinton  * It is necessary to use a write-through scheme so that
12359677Slinton  * breakpoints right next to each other don't interfere.
12369677Slinton  */
12379677Slinton 
12389677Slinton private Integer nfetchs, nreads, nwrites;
12399677Slinton 
12409677Slinton private Word fetch(p, seg, addr)
12419677Slinton Process p;
12429677Slinton PioSeg seg;
12439677Slinton register int addr;
12449677Slinton {
12459677Slinton     register CacheWord *wp;
12469677Slinton     register Word w;
12479677Slinton 
12489677Slinton     switch (seg) {
12499677Slinton 	case TEXTSEG:
12509677Slinton 	    ++nfetchs;
12519677Slinton 	    wp = &p->word[cachehash(addr)];
12529677Slinton 	    if (addr == 0 or wp->addr != addr) {
12539677Slinton 		++nreads;
125418230Slinton 		w = ptrace(IREAD, p->pid, addr, 0);
12559677Slinton 		wp->addr = addr;
12569677Slinton 		wp->val = w;
12579677Slinton 	    } else {
12589677Slinton 		w = wp->val;
12599677Slinton 	    }
12609677Slinton 	    break;
12619677Slinton 
12629677Slinton 	case DATASEG:
126318230Slinton 	    w = ptrace(DREAD, p->pid, addr, 0);
12649677Slinton 	    break;
12659677Slinton 
12669677Slinton 	default:
12679677Slinton 	    panic("fetch: bad seg %d", seg);
12689677Slinton 	    /* NOTREACHED */
12699677Slinton     }
12709677Slinton     return w;
12719677Slinton }
12729677Slinton 
12739677Slinton /*
12749677Slinton  * Put a word into the process' address space at the given address.
12759677Slinton  * The address is assumed to be on a word boundary.
12769677Slinton  */
12779677Slinton 
12789677Slinton private store(p, seg, addr, data)
12799677Slinton Process p;
12809677Slinton PioSeg seg;
12819677Slinton int addr;
12829677Slinton Word data;
12839677Slinton {
12849677Slinton     register CacheWord *wp;
12859677Slinton 
12869677Slinton     switch (seg) {
12879677Slinton 	case TEXTSEG:
12889677Slinton 	    ++nwrites;
12899677Slinton 	    wp = &p->word[cachehash(addr)];
12909677Slinton 	    wp->addr = addr;
12919677Slinton 	    wp->val = data;
129218230Slinton 	    ptrace(IWRITE, p->pid, addr, data);
12939677Slinton 	    break;
12949677Slinton 
12959677Slinton 	case DATASEG:
129618230Slinton 	    ptrace(DWRITE, p->pid, addr, data);
12979677Slinton 	    break;
12989677Slinton 
12999677Slinton 	default:
13009677Slinton 	    panic("store: bad seg %d", seg);
13019677Slinton 	    /* NOTREACHED */
13029677Slinton     }
13039677Slinton }
13049677Slinton 
130518230Slinton /*
130618230Slinton  * Flush the instruction cache associated with a process.
130718230Slinton  */
130818230Slinton 
130918230Slinton private cacheflush (p)
131018230Slinton Process p;
131118230Slinton {
131218230Slinton     bzero(p->word, sizeof(p->word));
131318230Slinton }
131418230Slinton 
13159677Slinton public printptraceinfo()
13169677Slinton {
13179677Slinton     printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites);
13189677Slinton }
13199677Slinton 
13209677Slinton /*
132116617Ssam  * Redirect input.
132216617Ssam  * Assuming this is called from a child, we should be careful to avoid
132316617Ssam  * (possibly) shared standard I/O buffers.
13249677Slinton  */
13259677Slinton 
132616617Ssam private infrom (filename)
132716617Ssam String filename;
132816617Ssam {
132916617Ssam     Fileid in;
133016617Ssam 
133116617Ssam     in = open(filename, 0);
133216617Ssam     if (in == -1) {
133316617Ssam 	write(2, "can't read ", 11);
133416617Ssam 	write(2, filename, strlen(filename));
133516617Ssam 	write(2, "\n", 1);
133616617Ssam 	_exit(1);
133716617Ssam     }
133816617Ssam     fswap(0, in);
133916617Ssam }
134016617Ssam 
134116617Ssam /*
134216617Ssam  * Redirect standard output.
134316617Ssam  * Same assumptions as for "infrom" above.
134416617Ssam  */
134516617Ssam 
134616617Ssam private outto (filename)
134716617Ssam String filename;
134816617Ssam {
134916617Ssam     Fileid out;
135016617Ssam 
135116617Ssam     out = creat(filename, 0666);
135216617Ssam     if (out == -1) {
135316617Ssam 	write(2, "can't write ", 12);
135416617Ssam 	write(2, filename, strlen(filename));
135516617Ssam 	write(2, "\n", 1);
135616617Ssam 	_exit(1);
135716617Ssam     }
135816617Ssam     fswap(1, out);
135916617Ssam }
136016617Ssam 
136116617Ssam /*
136216617Ssam  * Swap file numbers, useful for redirecting standard input or output.
136316617Ssam  */
136416617Ssam 
13659677Slinton private fswap(oldfd, newfd)
136616617Ssam Fileid oldfd;
136716617Ssam Fileid newfd;
13689677Slinton {
13699677Slinton     if (oldfd != newfd) {
13709677Slinton 	close(oldfd);
13719677Slinton 	dup(newfd);
13729677Slinton 	close(newfd);
13739677Slinton     }
13749677Slinton }
137516928Ssam 
137616928Ssam /*
137718230Slinton  * Signal name manipulation.
137816928Ssam  */
137918230Slinton 
138018230Slinton private String signames[NSIG] = {
138118230Slinton     0,
138218230Slinton     "HUP", "INT", "QUIT", "ILL", "TRAP",
138318230Slinton     "IOT", "EMT", "FPE", "KILL", "BUS",
138418230Slinton     "SEGV", "SYS", "PIPE", "ALRM", "TERM",
138518230Slinton     0, "STOP", "TSTP", "CONT", "CHLD",
138618230Slinton     "TTIN", "TTOU", "TINT", "XCPU", "XFSZ",
1387*26333Ssam     "VTALRM", "PROF", "WINCH", "USR1", "USR2"
138816928Ssam };
138916928Ssam 
139016928Ssam /*
139118230Slinton  * Get the signal number associated with a given name.
139218230Slinton  * The name is first translated to upper case if necessary.
139316928Ssam  */
139418230Slinton 
139518230Slinton public integer siglookup (s)
139616928Ssam String s;
139716928Ssam {
139818230Slinton     register char *p, *q;
139918230Slinton     char buf[100];
140018230Slinton     integer i;
140116928Ssam 
140218230Slinton     p = s;
140318230Slinton     q = buf;
140418230Slinton     while (*p != '\0') {
140518230Slinton 	if (*p >= 'a' and *p <= 'z') {
140618230Slinton 	    *q = (*p - 'a') + 'A';
140718230Slinton 	} else {
140818230Slinton 	    *q = *p;
140918230Slinton 	}
141018230Slinton 	++p;
141118230Slinton 	++q;
141218230Slinton     }
141318230Slinton     *q = '\0';
141418230Slinton     p = buf;
141518230Slinton     if (buf[0] == 'S' and buf[1] == 'I' and buf[2] == 'G') {
141618230Slinton 	p += 3;
141718230Slinton     }
141818230Slinton     i = 1;
141918230Slinton     for (;;) {
142018230Slinton 	if (i >= sizeof(signames) div sizeof(signames[0])) {
142118230Slinton 	    error("signal \"%s\" unknown", s);
142218230Slinton 	    i = 0;
142318230Slinton 	    break;
142418230Slinton 	}
142518230Slinton 	if (signames[i] != nil and streq(signames[i], p)) {
142618230Slinton 	    break;
142718230Slinton 	}
142818230Slinton 	++i;
142918230Slinton     }
143018230Slinton     return i;
143116928Ssam }
143216928Ssam 
143316928Ssam /*
143418230Slinton  * Print all signals being ignored by the debugger.
143518230Slinton  * These signals are auotmatically
143616928Ssam  * passed on to the debugged process.
143716928Ssam  */
143818230Slinton 
143918230Slinton public printsigsignored (p)
144016931Ssam Process p;
144116928Ssam {
144216931Ssam     printsigs(~p->sigset);
144316928Ssam }
144416928Ssam 
144516928Ssam /*
144616928Ssam  * Print all signals being intercepted by
144716928Ssam  * the debugger for the specified process.
144816928Ssam  */
144918230Slinton 
145016931Ssam public printsigscaught(p)
145116931Ssam Process p;
145216928Ssam {
145316931Ssam     printsigs(p->sigset);
145416931Ssam }
145516931Ssam 
145618230Slinton private printsigs (set)
145718230Slinton integer set;
145816931Ssam {
145918230Slinton     integer s;
146018230Slinton     char separator[2];
146116931Ssam 
146218230Slinton     separator[0] = '\0';
146318230Slinton     for (s = 1; s < sizeof(signames) div sizeof(signames[0]); s++) {
146418230Slinton 	if (set & setrep(s)) {
146518230Slinton 	    if (signames[s] != nil) {
146618230Slinton 		printf("%s%s", separator, signames[s]);
146718230Slinton 		separator[0] = ' ';
146818230Slinton 		separator[1] = '\0';
146918230Slinton 	    }
147016928Ssam 	}
147118230Slinton     }
147218230Slinton     if (separator[0] == ' ') {
147316931Ssam 	putchar('\n');
147416931Ssam     }
147516928Ssam }
1476