xref: /csrg-svn/old/dbx/process.c (revision 21620)
1*21620Sdist /*
2*21620Sdist  * Copyright (c) 1983 Regents of the University of California.
3*21620Sdist  * All rights reserved.  The Berkeley software License Agreement
4*21620Sdist  * specifies the terms and conditions for redistribution.
5*21620Sdist  */
69677Slinton 
7*21620Sdist #ifndef lint
8*21620Sdist static char sccsid[] = "@(#)process.c	5.1 (Berkeley) 05/31/85";
9*21620Sdist #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/param.h>
3516617Ssam #include <sys/dir.h>
3616617Ssam #include <sys/user.h>
379843Slinton #include <machine/reg.h>
389677Slinton #include <sys/stat.h>
399677Slinton 
409677Slinton #ifndef public
419677Slinton 
429677Slinton typedef struct Process *Process;
439677Slinton 
449677Slinton Process process;
459677Slinton 
4614757Slinton #define DEFSIG -1
4714757Slinton 
489677Slinton #include "machine.h"
499677Slinton 
509677Slinton #endif
519677Slinton 
529677Slinton #define NOTSTARTED 1
539677Slinton #define STOPPED 0177
549677Slinton #define FINISHED 0
559677Slinton 
569677Slinton /*
5716617Ssam  * A cache of the instruction segment is kept to reduce the number
5816617Ssam  * of system calls.  Might be better just to read the entire
5916617Ssam  * code space into memory.
609677Slinton  */
619677Slinton 
629677Slinton #define CSIZE 1003       /* size of instruction cache */
639677Slinton 
649677Slinton typedef struct {
659677Slinton     Word addr;
669677Slinton     Word val;
679677Slinton } CacheWord;
689677Slinton 
699677Slinton /*
709677Slinton  * This structure holds the information we need from the user structure.
719677Slinton  */
729677Slinton 
739677Slinton struct Process {
749677Slinton     int pid;			/* process being traced */
7511768Slinton     int mask;			/* process status word */
7611768Slinton     Word reg[NREG];		/* process' registers */
779677Slinton     Word oreg[NREG];		/* registers when process last stopped */
789677Slinton     short status;		/* either STOPPED or FINISHED */
799677Slinton     short signo;		/* signal that stopped process */
8018230Slinton     short sigcode;		/* extra signal information */
819677Slinton     int exitval;		/* return value from exit() */
829677Slinton     long sigset;		/* bit array of traced signals */
839677Slinton     CacheWord word[CSIZE];	/* text segment cache */
8411768Slinton     Ttyinfo ttyinfo;		/* process' terminal characteristics */
8516617Ssam     Address sigstatus;		/* process' handler for current signal */
869677Slinton };
879677Slinton 
889677Slinton /*
899677Slinton  * These definitions are for the arguments to "pio".
909677Slinton  */
919677Slinton 
929677Slinton typedef enum { PREAD, PWRITE } PioOp;
939677Slinton typedef enum { TEXTSEG, DATASEG } PioSeg;
949677Slinton 
959677Slinton private struct Process pbuf;
969677Slinton 
9718230Slinton #define MAXNCMDARGS 1000         /* maximum number of arguments to RUN */
989677Slinton 
9914395Slinton extern int errno;
10014395Slinton 
1019677Slinton private Boolean just_started;
1029677Slinton private int argc;
1039677Slinton private String argv[MAXNCMDARGS];
1049677Slinton private String infile, outfile;
1059677Slinton 
1069677Slinton /*
1079677Slinton  * Initialize process information.
1089677Slinton  */
1099677Slinton 
1109677Slinton public process_init()
1119677Slinton {
1129677Slinton     register Integer i;
1139677Slinton     Char buf[10];
1149677Slinton 
1159677Slinton     process = &pbuf;
1169677Slinton     process->status = (coredump) ? STOPPED : NOTSTARTED;
1179677Slinton     setsigtrace();
1189677Slinton     for (i = 0; i < NREG; i++) {
1199677Slinton 	sprintf(buf, "$r%d", i);
1209677Slinton 	defregname(identname(buf, false), i);
1219677Slinton     }
1229677Slinton     defregname(identname("$ap", true), ARGP);
1239677Slinton     defregname(identname("$fp", true), FRP);
1249677Slinton     defregname(identname("$sp", true), STKP);
1259677Slinton     defregname(identname("$pc", true), PROGCTR);
1269677Slinton     if (coredump) {
1279677Slinton 	coredump_readin(process->mask, process->reg, process->signo);
12812484Slinton 	pc = process->reg[PROGCTR];
12912484Slinton 	getsrcpos();
1309677Slinton     }
13112484Slinton     arginit();
1329677Slinton }
1339677Slinton 
1349677Slinton /*
1359677Slinton  * Routines to get at process information from outside this module.
1369677Slinton  */
1379677Slinton 
1389677Slinton public Word reg(n)
1399677Slinton Integer n;
1409677Slinton {
1419677Slinton     register Word w;
1429677Slinton 
1439677Slinton     if (n == NREG) {
1449677Slinton 	w = process->mask;
1459677Slinton     } else {
1469677Slinton 	w = process->reg[n];
1479677Slinton     }
1489677Slinton     return w;
1499677Slinton }
1509677Slinton 
1519677Slinton public setreg(n, w)
1529677Slinton Integer n;
1539677Slinton Word w;
1549677Slinton {
1559677Slinton     process->reg[n] = w;
1569677Slinton }
1579677Slinton 
1589677Slinton /*
1599677Slinton  * Begin execution.
1609677Slinton  *
1619677Slinton  * We set a breakpoint at the end of the code so that the
1629677Slinton  * process data doesn't disappear after the program terminates.
1639677Slinton  */
1649677Slinton 
1659677Slinton private Boolean remade();
1669677Slinton 
1679677Slinton public start(argv, infile, outfile)
1689677Slinton String argv[];
1699677Slinton String infile, outfile;
1709677Slinton {
1719677Slinton     String pargv[4];
1729677Slinton     Node cond;
1739677Slinton 
1749677Slinton     if (coredump) {
1759677Slinton 	coredump = false;
1769677Slinton 	fclose(corefile);
1779677Slinton 	coredump_close();
1789677Slinton     }
1799677Slinton     if (argv == nil) {
1809677Slinton 	argv = pargv;
1819677Slinton 	pargv[0] = objname;
1829677Slinton 	pargv[1] = nil;
1839677Slinton     } else {
1849677Slinton 	argv[argc] = nil;
1859677Slinton     }
18618230Slinton     pstart(process, argv, infile, outfile);
1879677Slinton     if (remade(objname)) {
1889677Slinton 	reinit(argv, infile, outfile);
1899677Slinton     }
1909677Slinton     if (process->status == STOPPED) {
1919677Slinton 	pc = 0;
19216617Ssam 	setcurfunc(program);
1939677Slinton 	if (objsize != 0) {
1949677Slinton 	    cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr()));
1959677Slinton 	    event_once(cond, buildcmdlist(build(O_ENDX)));
1969677Slinton 	}
1979677Slinton     }
1989677Slinton }
1999677Slinton 
2009677Slinton /*
2019677Slinton  * Check to see if the object file has changed since the symbolic
2029677Slinton  * information last was read.
2039677Slinton  */
2049677Slinton 
2059677Slinton private time_t modtime;
2069677Slinton 
2079677Slinton private Boolean remade(filename)
2089677Slinton String filename;
2099677Slinton {
2109677Slinton     struct stat s;
2119677Slinton     Boolean b;
2129677Slinton 
2139677Slinton     stat(filename, &s);
2149677Slinton     b = (Boolean) (modtime != 0 and modtime < s.st_mtime);
2159677Slinton     modtime = s.st_mtime;
2169677Slinton     return b;
2179677Slinton }
2189677Slinton 
2199677Slinton /*
2209677Slinton  * Set up what signals we want to trace.
2219677Slinton  */
2229677Slinton 
2239677Slinton private setsigtrace()
2249677Slinton {
2259677Slinton     register Integer i;
2269677Slinton     register Process p;
2279677Slinton 
2289677Slinton     p = process;
2299677Slinton     for (i = 1; i <= NSIG; i++) {
2309677Slinton 	psigtrace(p, i, true);
2319677Slinton     }
2329677Slinton     psigtrace(p, SIGHUP, false);
2339677Slinton     psigtrace(p, SIGKILL, false);
2349677Slinton     psigtrace(p, SIGALRM, false);
2359677Slinton     psigtrace(p, SIGTSTP, false);
2369677Slinton     psigtrace(p, SIGCONT, false);
2379677Slinton     psigtrace(p, SIGCHLD, false);
2389677Slinton }
2399677Slinton 
2409677Slinton /*
2419677Slinton  * Initialize the argument list.
2429677Slinton  */
2439677Slinton 
2449677Slinton public arginit()
2459677Slinton {
2469677Slinton     infile = nil;
2479677Slinton     outfile = nil;
2489677Slinton     argv[0] = objname;
2499677Slinton     argc = 1;
2509677Slinton }
2519677Slinton 
2529677Slinton /*
2539677Slinton  * Add an argument to the list for the debuggee.
2549677Slinton  */
2559677Slinton 
2569677Slinton public newarg(arg)
2579677Slinton String arg;
2589677Slinton {
2599677Slinton     if (argc >= MAXNCMDARGS) {
2609677Slinton 	error("too many arguments");
2619677Slinton     }
2629677Slinton     argv[argc++] = arg;
2639677Slinton }
2649677Slinton 
2659677Slinton /*
2669677Slinton  * Set the standard input for the debuggee.
2679677Slinton  */
2689677Slinton 
2699677Slinton public inarg(filename)
2709677Slinton String filename;
2719677Slinton {
2729677Slinton     if (infile != nil) {
2739677Slinton 	error("multiple input redirects");
2749677Slinton     }
2759677Slinton     infile = filename;
2769677Slinton }
2779677Slinton 
2789677Slinton /*
2799677Slinton  * Set the standard output for the debuggee.
2809677Slinton  * Probably should check to avoid overwriting an existing file.
2819677Slinton  */
2829677Slinton 
2839677Slinton public outarg(filename)
2849677Slinton String filename;
2859677Slinton {
2869677Slinton     if (outfile != nil) {
2879677Slinton 	error("multiple output redirect");
2889677Slinton     }
2899677Slinton     outfile = filename;
2909677Slinton }
2919677Slinton 
2929677Slinton /*
2939677Slinton  * Start debuggee executing.
2949677Slinton  */
2959677Slinton 
2969677Slinton public run()
2979677Slinton {
2989677Slinton     process->status = STOPPED;
2999677Slinton     fixbps();
3009677Slinton     curline = 0;
3019677Slinton     start(argv, infile, outfile);
3029677Slinton     just_started = true;
3039677Slinton     isstopped = false;
30414757Slinton     cont(0);
3059677Slinton }
3069677Slinton 
3079677Slinton /*
3089677Slinton  * Continue execution wherever we left off.
3099677Slinton  *
3109677Slinton  * Note that this routine never returns.  Eventually bpact() will fail
3119677Slinton  * and we'll call printstatus or step will call it.
3129677Slinton  */
3139677Slinton 
3149677Slinton typedef int Intfunc();
3159677Slinton 
3169677Slinton private Intfunc *dbintr;
3179677Slinton private intr();
3189677Slinton 
31911867Slinton public cont(signo)
32016617Ssam integer signo;
3219677Slinton {
32216617Ssam     integer s;
32316617Ssam 
3249677Slinton     dbintr = signal(SIGINT, intr);
3259677Slinton     if (just_started) {
3269677Slinton 	just_started = false;
3279677Slinton     } else {
3289677Slinton 	if (not isstopped) {
3299677Slinton 	    error("can't continue execution");
3309677Slinton 	}
3319677Slinton 	isstopped = false;
33211867Slinton 	stepover();
3339677Slinton     }
33416617Ssam     s = signo;
3359677Slinton     for (;;) {
3369677Slinton 	if (single_stepping) {
3379677Slinton 	    printnews();
3389677Slinton 	} else {
3399677Slinton 	    setallbps();
34016617Ssam 	    resume(s);
3419677Slinton 	    unsetallbps();
34216617Ssam 	    s = DEFSIG;
34318230Slinton 	    if (not isbperr() or not bpact()) {
3449677Slinton 		printstatus();
3459677Slinton 	    }
3469677Slinton 	}
34711867Slinton 	stepover();
3489677Slinton     }
3499677Slinton     /* NOTREACHED */
3509677Slinton }
3519677Slinton 
3529677Slinton /*
35318230Slinton  * This routine is called if we get an interrupt while "running"
3549677Slinton  * but actually in the debugger.  Could happen, for example, while
3559677Slinton  * processing breakpoints.
3569677Slinton  *
3579677Slinton  * We basically just want to keep going; the assumption is
35818230Slinton  * that when the process resumes it will get the interrupt,
3599677Slinton  * which will then be handled.
3609677Slinton  */
3619677Slinton 
3629677Slinton private intr()
3639677Slinton {
3649677Slinton     signal(SIGINT, intr);
3659677Slinton }
3669677Slinton 
3679677Slinton public fixintr()
3689677Slinton {
3699677Slinton     signal(SIGINT, dbintr);
3709677Slinton }
3719677Slinton 
3729677Slinton /*
3739677Slinton  * Resume execution.
3749677Slinton  */
3759677Slinton 
37611867Slinton public resume(signo)
37711867Slinton int signo;
3789677Slinton {
3799677Slinton     register Process p;
3809677Slinton 
3819677Slinton     p = process;
38211867Slinton     pcont(p, signo);
3839677Slinton     pc = process->reg[PROGCTR];
38411832Slinton     if (p->status != STOPPED) {
38511867Slinton 	if (p->signo != 0) {
38611867Slinton 	    error("program terminated by signal %d", p->signo);
38714757Slinton 	} else if (not runfirst) {
38818230Slinton 	    if (p->exitval == 0) {
38918230Slinton 		error("program exited");
39018230Slinton 	    } else {
39118230Slinton 		error("program exited with code %d", p->exitval);
39218230Slinton 	    }
39311867Slinton 	}
39411832Slinton     }
3959677Slinton }
3969677Slinton 
3979677Slinton /*
3989677Slinton  * Continue execution up to the next source line.
3999677Slinton  *
4009677Slinton  * There are two ways to define the next source line depending on what
4019677Slinton  * is desired when a procedure or function call is encountered.  Step
4029677Slinton  * stops at the beginning of the procedure or call; next skips over it.
4039677Slinton  */
4049677Slinton 
4059677Slinton /*
4069677Slinton  * Stepc is what is called when the step command is given.
4079677Slinton  * It has to play with the "isstopped" information.
4089677Slinton  */
4099677Slinton 
4109677Slinton public stepc()
4119677Slinton {
4129677Slinton     if (not isstopped) {
4139677Slinton 	error("can't continue execution");
4149677Slinton     }
4159677Slinton     isstopped = false;
4169677Slinton     dostep(false);
4179677Slinton     isstopped = true;
4189677Slinton }
4199677Slinton 
4209677Slinton public next()
4219677Slinton {
42216617Ssam     Address oldfrp, newfrp;
42316617Ssam 
4249677Slinton     if (not isstopped) {
4259677Slinton 	error("can't continue execution");
4269677Slinton     }
4279677Slinton     isstopped = false;
42816617Ssam     oldfrp = reg(FRP);
42916617Ssam     do {
43016617Ssam 	dostep(true);
43116617Ssam 	pc = reg(PROGCTR);
43216617Ssam 	newfrp = reg(FRP);
43316617Ssam     } while (newfrp < oldfrp and newfrp != 0);
4349677Slinton     isstopped = true;
4359677Slinton }
4369677Slinton 
43711867Slinton /*
43816617Ssam  * Continue execution until the current function returns, or,
43916617Ssam  * if the given argument is non-nil, until execution returns to
44016617Ssam  * somewhere within the given function.
44116617Ssam  */
44216617Ssam 
44316617Ssam public rtnfunc (f)
44416617Ssam Symbol f;
44516617Ssam {
44616617Ssam     Address addr;
44716617Ssam     Symbol t;
44816617Ssam 
44916617Ssam     if (not isstopped) {
45016617Ssam 	error("can't continue execution");
45116617Ssam     } else if (f != nil and not isactive(f)) {
45216617Ssam 	error("%s is not active", symname(f));
45316617Ssam     } else {
45416617Ssam 	addr = return_addr();
45516617Ssam 	if (addr == nil) {
45616617Ssam 	    error("no place to return to");
45716617Ssam 	} else {
45816617Ssam 	    isstopped = false;
45916617Ssam 	    contto(addr);
46016617Ssam 	    if (f != nil) {
46116617Ssam 		for (;;) {
46216617Ssam 		    t = whatblock(pc);
46316617Ssam 		    addr = return_addr();
46416617Ssam 		if (t == f or addr == nil) break;
46516617Ssam 		    contto(addr);
46616617Ssam 		}
46716617Ssam 	    }
46818230Slinton 	    if (not bpact()) {
46916617Ssam 		isstopped = true;
47016617Ssam 		printstatus();
47116617Ssam 	    }
47216617Ssam 	}
47316617Ssam     }
47416617Ssam }
47516617Ssam 
47616617Ssam /*
47711867Slinton  * Single-step over the current machine instruction.
47811867Slinton  *
47911867Slinton  * If we're single-stepping by source line we want to step to the
48011867Slinton  * next source line.  Otherwise we're going to continue so there's
48111867Slinton  * no reason to do all the work necessary to single-step to the next
48211867Slinton  * source line.
48311867Slinton  */
48411867Slinton 
48516617Ssam public stepover()
4869677Slinton {
48711867Slinton     Boolean b;
48811867Slinton 
48916617Ssam     if (traceexec) {
49016617Ssam 	printf("!! stepping over 0x%x\n", process->reg[PROGCTR]);
49116617Ssam     }
49211867Slinton     if (single_stepping) {
49311867Slinton 	dostep(false);
49411867Slinton     } else {
49511867Slinton 	b = inst_tracing;
49611867Slinton 	inst_tracing = true;
49711867Slinton 	dostep(false);
49811867Slinton 	inst_tracing = b;
49911867Slinton     }
50016617Ssam     if (traceexec) {
50116617Ssam 	printf("!! stepped over to 0x%x\n", process->reg[PROGCTR]);
50216617Ssam     }
5039677Slinton }
5049677Slinton 
5059677Slinton /*
50618230Slinton  * Resume execution up to the given address.  We can either ignore
50718230Slinton  * breakpoints (stepto) or catch them (contto).
5089677Slinton  */
5099677Slinton 
5109677Slinton public stepto(addr)
5119677Slinton Address addr;
5129677Slinton {
51316617Ssam     xto(addr, false);
51416617Ssam }
51516617Ssam 
51616617Ssam private contto (addr)
51716617Ssam Address addr;
51816617Ssam {
51916617Ssam     xto(addr, true);
52016617Ssam }
52116617Ssam 
52216617Ssam private xto (addr, catchbps)
52316617Ssam Address addr;
52416617Ssam boolean catchbps;
52516617Ssam {
52616617Ssam     Address curpc;
52716617Ssam 
52816617Ssam     if (catchbps) {
52916617Ssam 	stepover();
5309677Slinton     }
53116617Ssam     curpc = process->reg[PROGCTR];
53216617Ssam     if (addr != curpc) {
53316617Ssam 	if (traceexec) {
53416617Ssam 	    printf("!! stepping from 0x%x to 0x%x\n", curpc, addr);
53516617Ssam 	}
53616617Ssam 	if (catchbps) {
53716617Ssam 	    setallbps();
53816617Ssam 	}
53916617Ssam 	setbp(addr);
54016617Ssam 	resume(DEFSIG);
54116617Ssam 	unsetbp(addr);
54216617Ssam 	if (catchbps) {
54316617Ssam 	    unsetallbps();
54416617Ssam 	}
54516617Ssam 	if (not isbperr()) {
54616617Ssam 	    printstatus();
54716617Ssam 	}
54816617Ssam     }
5499677Slinton }
5509677Slinton 
5519677Slinton /*
5529677Slinton  * Print the status of the process.
5539677Slinton  * This routine does not return.
5549677Slinton  */
5559677Slinton 
5569677Slinton public printstatus()
5579677Slinton {
55814395Slinton     int status;
55914395Slinton 
5609843Slinton     if (process->status == FINISHED) {
5619843Slinton 	exit(0);
5629843Slinton     } else {
56316617Ssam 	setcurfunc(whatblock(pc));
5649677Slinton 	getsrcpos();
5659843Slinton 	if (process->signo == SIGINT) {
5669843Slinton 	    isstopped = true;
5679843Slinton 	    printerror();
5689843Slinton 	} else if (isbperr() and isstopped) {
5699843Slinton 	    printf("stopped ");
57011172Slinton 	    printloc();
57111172Slinton 	    putchar('\n');
5729843Slinton 	    if (curline > 0) {
5739843Slinton 		printlines(curline, curline);
5749843Slinton 	    } else {
5759843Slinton 		printinst(pc, pc);
5769843Slinton 	    }
5779843Slinton 	    erecover();
5789677Slinton 	} else {
5799843Slinton 	    fixintr();
5809677Slinton 	    isstopped = true;
5819677Slinton 	    printerror();
5829677Slinton 	}
5839677Slinton     }
5849677Slinton }
5859677Slinton 
5869677Slinton /*
58711172Slinton  * Print out the current location in the debuggee.
58811172Slinton  */
58911172Slinton 
59011172Slinton public printloc()
59111172Slinton {
59211172Slinton     printf("in ");
59311172Slinton     printname(stdout, curfunc);
59411172Slinton     putchar(' ');
59514757Slinton     if (curline > 0 and not useInstLoc) {
59611172Slinton 	printsrcpos();
59711172Slinton     } else {
59814757Slinton 	useInstLoc = false;
59914757Slinton 	curline = 0;
60011172Slinton 	printf("at 0x%x", pc);
60111172Slinton     }
60211172Slinton }
60311172Slinton 
60411172Slinton /*
6059677Slinton  * Some functions for testing the state of the process.
6069677Slinton  */
6079677Slinton 
6089677Slinton public Boolean notstarted(p)
6099677Slinton Process p;
6109677Slinton {
6119677Slinton     return (Boolean) (p->status == NOTSTARTED);
6129677Slinton }
6139677Slinton 
6149677Slinton public Boolean isfinished(p)
6159677Slinton Process p;
6169677Slinton {
6179677Slinton     return (Boolean) (p->status == FINISHED);
6189677Slinton }
6199677Slinton 
6209677Slinton /*
62118230Slinton  * Predicate to test if the reason the process stopped was because
62218230Slinton  * of a breakpoint.  If so, as a side effect clear the local copy of
62318230Slinton  * signal handler associated with process.  We must do this so as to
62418230Slinton  * not confuse future stepping or continuing by possibly concluding
62518230Slinton  * the process should continue with a SIGTRAP handler.
6269677Slinton  */
6279677Slinton 
62818230Slinton public boolean isbperr()
62918230Slinton {
63018230Slinton     Process p;
63118230Slinton     boolean b;
63218230Slinton 
63318230Slinton     p = process;
63418230Slinton     if (p->status == STOPPED and p->signo == SIGTRAP) {
63518230Slinton 	b = true;
63618230Slinton 	p->sigstatus = 0;
63718230Slinton     } else {
63818230Slinton 	b = false;
63918230Slinton     }
64018230Slinton     return b;
64118230Slinton }
64218230Slinton 
64318230Slinton /*
64418230Slinton  * Return the signal number that stopped the process.
64518230Slinton  */
64618230Slinton 
64718230Slinton public integer errnum (p)
6489677Slinton Process p;
6499677Slinton {
6509677Slinton     return p->signo;
6519677Slinton }
6529677Slinton 
65318230Slinton /*
65418230Slinton  * Return the signal code associated with the signal.
65518230Slinton  */
65618230Slinton 
65718230Slinton public integer errcode (p)
65816931Ssam Process p;
65916931Ssam {
66016931Ssam     return p->sigcode;
66116931Ssam }
66216931Ssam 
6639677Slinton /*
6649677Slinton  * Return the termination code of the process.
6659677Slinton  */
6669677Slinton 
66718230Slinton public integer exitcode (p)
6689677Slinton Process p;
6699677Slinton {
6709677Slinton     return p->exitval;
6719677Slinton }
6729677Slinton 
6739677Slinton /*
6749677Slinton  * These routines are used to access the debuggee process from
6759677Slinton  * outside this module.
6769677Slinton  *
6779677Slinton  * They invoke "pio" which eventually leads to a call to "ptrace".
67814757Slinton  * The system generates an I/O error when a ptrace fails.  During reads
67914757Slinton  * these are ignored, during writes they are reported as an error, and
68014757Slinton  * for anything else they cause a fatal error.
6819677Slinton  */
6829677Slinton 
6839677Slinton extern Intfunc *onsyserr();
6849677Slinton 
6859677Slinton private badaddr;
68614757Slinton private read_err(), write_err();
6879677Slinton 
6889677Slinton /*
6899677Slinton  * Read from the process' instruction area.
6909677Slinton  */
6919677Slinton 
6929677Slinton public iread(buff, addr, nbytes)
6939677Slinton char *buff;
6949677Slinton Address addr;
6959677Slinton int nbytes;
6969677Slinton {
6979677Slinton     Intfunc *f;
6989677Slinton 
69914757Slinton     f = onsyserr(EIO, read_err);
7009677Slinton     badaddr = addr;
7019677Slinton     if (coredump) {
7029677Slinton 	coredump_readtext(buff, addr, nbytes);
7039677Slinton     } else {
7049677Slinton 	pio(process, PREAD, TEXTSEG, buff, addr, nbytes);
7059677Slinton     }
7069677Slinton     onsyserr(EIO, f);
7079677Slinton }
7089677Slinton 
7099677Slinton /*
7109677Slinton  * Write to the process' instruction area, usually in order to set
7119677Slinton  * or unset a breakpoint.
7129677Slinton  */
7139677Slinton 
7149677Slinton public iwrite(buff, addr, nbytes)
7159677Slinton char *buff;
7169677Slinton Address addr;
7179677Slinton int nbytes;
7189677Slinton {
7199677Slinton     Intfunc *f;
7209677Slinton 
7219677Slinton     if (coredump) {
7229677Slinton 	error("no process to write to");
7239677Slinton     }
72414757Slinton     f = onsyserr(EIO, write_err);
7259677Slinton     badaddr = addr;
7269677Slinton     pio(process, PWRITE, TEXTSEG, buff, addr, nbytes);
7279677Slinton     onsyserr(EIO, f);
7289677Slinton }
7299677Slinton 
7309677Slinton /*
7319677Slinton  * Read for the process' data area.
7329677Slinton  */
7339677Slinton 
7349677Slinton public dread(buff, addr, nbytes)
7359677Slinton char *buff;
7369677Slinton Address addr;
7379677Slinton int nbytes;
7389677Slinton {
7399677Slinton     Intfunc *f;
7409677Slinton 
7419677Slinton     badaddr = addr;
7429677Slinton     if (coredump) {
74318230Slinton 	f = onsyserr(EFAULT, read_err);
7449677Slinton 	coredump_readdata(buff, addr, nbytes);
74518230Slinton 	onsyserr(EFAULT, f);
7469677Slinton     } else {
74718230Slinton 	f = onsyserr(EIO, read_err);
7489677Slinton 	pio(process, PREAD, DATASEG, buff, addr, nbytes);
74918230Slinton 	onsyserr(EIO, f);
7509677Slinton     }
7519677Slinton }
7529677Slinton 
7539677Slinton /*
7549677Slinton  * Write to the process' data area.
7559677Slinton  */
7569677Slinton 
7579677Slinton public dwrite(buff, addr, nbytes)
7589677Slinton char *buff;
7599677Slinton Address addr;
7609677Slinton int nbytes;
7619677Slinton {
7629677Slinton     Intfunc *f;
7639677Slinton 
7649677Slinton     if (coredump) {
7659677Slinton 	error("no process to write to");
7669677Slinton     }
76714757Slinton     f = onsyserr(EIO, write_err);
7689677Slinton     badaddr = addr;
7699677Slinton     pio(process, PWRITE, DATASEG, buff, addr, nbytes);
7709677Slinton     onsyserr(EIO, f);
7719677Slinton }
7729677Slinton 
7739677Slinton /*
77414757Slinton  * Trap for errors in reading or writing to a process.
77514757Slinton  * The current approach is to "ignore" read errors and complain
77614757Slinton  * bitterly about write errors.
7779677Slinton  */
7789677Slinton 
77914757Slinton private read_err()
7809677Slinton {
78111560Slinton     /*
78214757Slinton      * Ignore.
78311560Slinton      */
7849677Slinton }
7859677Slinton 
78614757Slinton private write_err()
78714757Slinton {
78814757Slinton     error("can't write to process (address 0x%x)", badaddr);
78914757Slinton }
79014757Slinton 
7919677Slinton /*
7929677Slinton  * Ptrace interface.
7939677Slinton  */
7949677Slinton 
7959677Slinton /*
7969677Slinton  * This magic macro enables us to look at the process' registers
79714757Slinton  * in its user structure.
7989677Slinton  */
7999677Slinton 
8009677Slinton #define regloc(reg)     (ctob(UPAGES) + ( sizeof(int) * (reg) ))
8019677Slinton 
8029677Slinton #define WMASK           (~(sizeof(Word) - 1))
8039677Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE))
8049677Slinton 
8059677Slinton #define FIRSTSIG        SIGINT
8069677Slinton #define LASTSIG         SIGQUIT
8079677Slinton #define ischild(pid)    ((pid) == 0)
80818230Slinton #define traceme()       ptrace(0, 0, 0, 0)
8099677Slinton #define setrep(n)       (1 << ((n)-1))
8109677Slinton #define istraced(p)     (p->sigset&setrep(p->signo))
8119677Slinton 
8129677Slinton /*
81318230Slinton  * Ptrace options (specified in first argument).
81418230Slinton  */
81518230Slinton 
81618230Slinton #define UREAD   3       /* read from process's user structure */
81718230Slinton #define UWRITE  6       /* write to process's user structure */
81818230Slinton #define IREAD   1       /* read from process's instruction space */
81918230Slinton #define IWRITE  4       /* write to process's instruction space */
82018230Slinton #define DREAD   2       /* read from process's data space */
82118230Slinton #define DWRITE  5       /* write to process's data space */
82218230Slinton #define CONT    7       /* continue stopped process */
82318230Slinton #define SSTEP   9       /* continue for approximately one instruction */
82418230Slinton #define PKILL   8       /* terminate the process */
82518230Slinton 
82618230Slinton /*
8279677Slinton  * Start up a new process by forking and exec-ing the
8289677Slinton  * given argument list, returning when the process is loaded
8299677Slinton  * and ready to execute.  The PROCESS information (pointed to
8309677Slinton  * by the first argument) is appropriately filled.
8319677Slinton  *
8329677Slinton  * If the given PROCESS structure is associated with an already running
8339677Slinton  * process, we terminate it.
8349677Slinton  */
8359677Slinton 
8369677Slinton /* VARARGS2 */
8379677Slinton private pstart(p, argv, infile, outfile)
8389677Slinton Process p;
8399677Slinton String argv[];
8409677Slinton String infile;
8419677Slinton String outfile;
8429677Slinton {
8439677Slinton     int status;
8449677Slinton 
84516617Ssam     if (p->pid != 0) {
84616617Ssam 	pterm(p);
84718230Slinton 	cacheflush(p);
8489677Slinton     }
84918230Slinton     fflush(stdout);
8509677Slinton     psigtrace(p, SIGTRAP, true);
85114395Slinton     p->pid = vfork();
85214395Slinton     if (p->pid == -1) {
8539677Slinton 	panic("can't fork");
8549677Slinton     }
8559677Slinton     if (ischild(p->pid)) {
85618230Slinton 	nocatcherrs();
8579677Slinton 	traceme();
8589677Slinton 	if (infile != nil) {
85916617Ssam 	    infrom(infile);
8609677Slinton 	}
8619677Slinton 	if (outfile != nil) {
86216617Ssam 	    outto(outfile);
8639677Slinton 	}
86411832Slinton 	execv(argv[0], argv);
86511172Slinton 	_exit(1);
8669677Slinton     }
8679677Slinton     pwait(p->pid, &status);
8689677Slinton     getinfo(p, status);
8699677Slinton     if (p->status != STOPPED) {
87018230Slinton 	beginerrmsg();
87118230Slinton 	fprintf(stderr, "warning: cannot execute %s\n", argv[0]);
87218230Slinton     } else {
87318230Slinton 	ptraced(p->pid);
8749677Slinton     }
8759677Slinton }
8769677Slinton 
8779677Slinton /*
87816617Ssam  * Terminate a ptrace'd process.
87916617Ssam  */
88016617Ssam 
88116617Ssam public pterm (p)
88216617Ssam Process p;
88316617Ssam {
88416617Ssam     integer status;
88516617Ssam 
88616617Ssam     if (p != nil and p->pid != 0) {
88718230Slinton 	ptrace(PKILL, p->pid, 0, 0);
88816617Ssam 	pwait(p->pid, &status);
88916617Ssam 	unptraced(p->pid);
89016617Ssam     }
89116617Ssam }
89216617Ssam 
89316617Ssam /*
89411867Slinton  * Continue a stopped process.  The first argument points to a Process
89511867Slinton  * structure.  Before the process is restarted it's user area is modified
89611867Slinton  * according to the values in the structure.  When this routine finishes,
8979677Slinton  * the structure has the new values from the process's user area.
8989677Slinton  *
8999677Slinton  * Pcont terminates when the process stops with a signal pending that
9009677Slinton  * is being traced (via psigtrace), or when the process terminates.
9019677Slinton  */
9029677Slinton 
90311867Slinton private pcont(p, signo)
9049677Slinton Process p;
90511867Slinton int signo;
9069677Slinton {
90716617Ssam     int s, status;
9089677Slinton 
9099677Slinton     if (p->pid == 0) {
91018230Slinton 	error("program is not active");
9119677Slinton     }
91216617Ssam     s = signo;
9139677Slinton     do {
91416617Ssam 	setinfo(p, s);
91516617Ssam 	if (traceexec) {
91616617Ssam 	    printf("!! pcont from 0x%x with signal %d (%d)\n",
91716617Ssam 		p->reg[PROGCTR], s, p->signo);
91816617Ssam 	    fflush(stdout);
91916617Ssam 	}
9209677Slinton 	sigs_off();
92118230Slinton 	if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) {
92214395Slinton 	    panic("error %d trying to continue process", errno);
9239677Slinton 	}
9249677Slinton 	pwait(p->pid, &status);
9259677Slinton 	sigs_on();
9269677Slinton 	getinfo(p, status);
92718230Slinton 	if (p->status == STOPPED and traceexec and not istraced(p)) {
92818230Slinton 	    printf("!! ignored signal %d at 0x%x\n",
92918230Slinton 		p->signo, p->reg[PROGCTR]);
93016617Ssam 	    fflush(stdout);
93116617Ssam 	}
93216617Ssam 	s = p->signo;
9339677Slinton     } while (p->status == STOPPED and not istraced(p));
93416617Ssam     if (traceexec) {
93516617Ssam 	printf("!! pcont to 0x%x on signal %d\n", p->reg[PROGCTR], p->signo);
93616617Ssam 	fflush(stdout);
93716617Ssam     }
9389677Slinton }
9399677Slinton 
9409677Slinton /*
9419677Slinton  * Single step as best ptrace can.
9429677Slinton  */
9439677Slinton 
94416617Ssam public pstep(p, signo)
9459677Slinton Process p;
94616617Ssam integer signo;
9479677Slinton {
94818230Slinton     int s, status;
9499677Slinton 
95018230Slinton     s = signo;
95118230Slinton     do {
95218230Slinton 	setinfo(p, s);
95318230Slinton 	if (traceexec) {
95418230Slinton 	    printf("!! pstep from 0x%x with signal %d (%d)\n",
95518230Slinton 		p->reg[PROGCTR], s, p->signo);
95618230Slinton 	    fflush(stdout);
95718230Slinton 	}
95818230Slinton 	sigs_off();
95918230Slinton 	if (ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo) < 0) {
96018230Slinton 	    panic("error %d trying to step process", errno);
96118230Slinton 	}
96218230Slinton 	pwait(p->pid, &status);
96318230Slinton 	sigs_on();
96418230Slinton 	getinfo(p, status);
96518230Slinton 	if (p->status == STOPPED and traceexec and not istraced(p)) {
96618230Slinton 	    printf("!! pstep ignored signal %d at 0x%x\n",
96718230Slinton 		p->signo, p->reg[PROGCTR]);
96818230Slinton 	    fflush(stdout);
96918230Slinton 	}
97018230Slinton 	s = p->signo;
97118230Slinton     } while (p->status == STOPPED and not istraced(p));
97216617Ssam     if (traceexec) {
97318230Slinton 	printf("!! pstep to 0x%x on signal %d\n",
97418230Slinton 	    p->reg[PROGCTR], p->signo);
97516617Ssam 	fflush(stdout);
97616617Ssam     }
97716617Ssam     if (p->status != STOPPED) {
97818230Slinton 	if (p->exitval == 0) {
97918230Slinton 	    error("program exited\n");
98018230Slinton 	} else {
98118230Slinton 	    error("program exited with code %d\n", p->exitval);
98218230Slinton 	}
98316617Ssam     }
9849677Slinton }
9859677Slinton 
9869677Slinton /*
9879677Slinton  * Return from execution when the given signal is pending.
9889677Slinton  */
9899677Slinton 
9909677Slinton public psigtrace(p, sig, sw)
9919677Slinton Process p;
9929677Slinton int sig;
9939677Slinton Boolean sw;
9949677Slinton {
9959677Slinton     if (sw) {
9969677Slinton 	p->sigset |= setrep(sig);
9979677Slinton     } else {
9989677Slinton 	p->sigset &= ~setrep(sig);
9999677Slinton     }
10009677Slinton }
10019677Slinton 
10029677Slinton /*
10039677Slinton  * Don't catch any signals.
10049677Slinton  * Particularly useful when letting a process finish uninhibited.
10059677Slinton  */
10069677Slinton 
10079677Slinton public unsetsigtraces(p)
10089677Slinton Process p;
10099677Slinton {
10109677Slinton     p->sigset = 0;
10119677Slinton }
10129677Slinton 
10139677Slinton /*
10149677Slinton  * Turn off attention to signals not being caught.
10159677Slinton  */
10169677Slinton 
10179677Slinton private Intfunc *sigfunc[NSIG];
10189677Slinton 
10199677Slinton private sigs_off()
10209677Slinton {
10219677Slinton     register int i;
10229677Slinton 
10239677Slinton     for (i = FIRSTSIG; i < LASTSIG; i++) {
10249677Slinton 	if (i != SIGKILL) {
10259677Slinton 	    sigfunc[i] = signal(i, SIG_IGN);
10269677Slinton 	}
10279677Slinton     }
10289677Slinton }
10299677Slinton 
10309677Slinton /*
10319677Slinton  * Turn back on attention to signals.
10329677Slinton  */
10339677Slinton 
10349677Slinton private sigs_on()
10359677Slinton {
10369677Slinton     register int i;
10379677Slinton 
10389677Slinton     for (i = FIRSTSIG; i < LASTSIG; i++) {
10399677Slinton 	if (i != SIGKILL) {
10409677Slinton 	    signal(i, sigfunc[i]);
10419677Slinton 	}
10429677Slinton     }
10439677Slinton }
10449677Slinton 
10459677Slinton /*
10469677Slinton  * Get process information from user area.
10479677Slinton  */
10489677Slinton 
10499677Slinton private int rloc[] ={
10509677Slinton     R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC
10519677Slinton };
10529677Slinton 
10539677Slinton private getinfo(p, status)
10549677Slinton register Process p;
10559677Slinton register int status;
10569677Slinton {
10579677Slinton     register int i;
105816617Ssam     Address addr;
10599677Slinton 
10609677Slinton     p->signo = (status&0177);
10619677Slinton     p->exitval = ((status >> 8)&0377);
10629677Slinton     if (p->signo != STOPPED) {
10639677Slinton 	p->status = FINISHED;
106414757Slinton 	p->pid = 0;
106516617Ssam 	p->reg[PROGCTR] = 0;
10669677Slinton     } else {
10679677Slinton 	p->status = p->signo;
10689677Slinton 	p->signo = p->exitval;
106918230Slinton 	p->sigcode = ptrace(UREAD, p->pid, &((struct user *) 0)->u_code, 0);
10709677Slinton 	p->exitval = 0;
107118230Slinton 	p->mask = ptrace(UREAD, p->pid, regloc(PS), 0);
10729677Slinton 	for (i = 0; i < NREG; i++) {
107318230Slinton 	    p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0);
10749677Slinton 	    p->oreg[i] = p->reg[i];
10759677Slinton 	}
107611768Slinton 	savetty(stdout, &(p->ttyinfo));
107716617Ssam 	addr = (Address) &(((struct user *) 0)->u_signal[p->signo]);
107818230Slinton 	p->sigstatus = (Address) ptrace(UREAD, p->pid, addr, 0);
10799677Slinton     }
10809677Slinton }
10819677Slinton 
10829677Slinton /*
10839677Slinton  * Set process's user area information from given process structure.
10849677Slinton  */
10859677Slinton 
108611867Slinton private setinfo(p, signo)
10879677Slinton register Process p;
108811867Slinton int signo;
10899677Slinton {
10909677Slinton     register int i;
10919677Slinton     register int r;
10929677Slinton 
109314757Slinton     if (signo == DEFSIG) {
109416617Ssam 	if (istraced(p) and (p->sigstatus == 0 or p->sigstatus == 1)) {
109514757Slinton 	    p->signo = 0;
109614757Slinton 	}
109714757Slinton     } else {
109811867Slinton 	p->signo = signo;
10999677Slinton     }
11009677Slinton     for (i = 0; i < NREG; i++) {
11019677Slinton 	if ((r = p->reg[i]) != p->oreg[i]) {
110218230Slinton 	    ptrace(UWRITE, p->pid, regloc(rloc[i]), r);
11039677Slinton 	}
11049677Slinton     }
110511768Slinton     restoretty(stdout, &(p->ttyinfo));
11069677Slinton }
11079677Slinton 
11089677Slinton /*
110916617Ssam  * Return the address associated with the current signal.
111016617Ssam  * (Plus two since the address points to the beginning of a procedure).
111116617Ssam  */
111216617Ssam 
111316617Ssam public Address usignal (p)
111416617Ssam Process p;
111516617Ssam {
111616617Ssam     Address r;
111716617Ssam 
111816617Ssam     r = p->sigstatus;
111916617Ssam     if (r != 0 and r != 1) {
112016617Ssam 	r += 2;
112116617Ssam     }
112216617Ssam     return r;
112316617Ssam }
112416617Ssam 
112516617Ssam /*
11269677Slinton  * Structure for reading and writing by words, but dealing with bytes.
11279677Slinton  */
11289677Slinton 
11299677Slinton typedef union {
11309677Slinton     Word pword;
11319677Slinton     Byte pbyte[sizeof(Word)];
11329677Slinton } Pword;
11339677Slinton 
11349677Slinton /*
11359677Slinton  * Read (write) from (to) the process' address space.
11369677Slinton  * We must deal with ptrace's inability to look anywhere other
11379677Slinton  * than at a word boundary.
11389677Slinton  */
11399677Slinton 
11409677Slinton private Word fetch();
11419677Slinton private store();
11429677Slinton 
11439677Slinton private pio(p, op, seg, buff, addr, nbytes)
11449677Slinton Process p;
11459677Slinton PioOp op;
11469677Slinton PioSeg seg;
11479677Slinton char *buff;
11489677Slinton Address addr;
11499677Slinton int nbytes;
11509677Slinton {
11519677Slinton     register int i;
11529677Slinton     register Address newaddr;
11539677Slinton     register char *cp;
11549677Slinton     char *bufend;
11559677Slinton     Pword w;
11569677Slinton     Address wordaddr;
11579677Slinton     int byteoff;
11589677Slinton 
11599677Slinton     if (p->status != STOPPED) {
11609677Slinton 	error("program is not active");
11619677Slinton     }
11629677Slinton     cp = buff;
11639677Slinton     newaddr = addr;
11649677Slinton     wordaddr = (newaddr&WMASK);
11659677Slinton     if (wordaddr != newaddr) {
11669677Slinton 	w.pword = fetch(p, seg, wordaddr);
11679677Slinton 	for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) {
11689677Slinton 	    if (op == PREAD) {
11699677Slinton 		*cp++ = w.pbyte[i];
11709677Slinton 	    } else {
11719677Slinton 		w.pbyte[i] = *cp++;
11729677Slinton 	    }
11739677Slinton 	    nbytes--;
11749677Slinton 	}
11759677Slinton 	if (op == PWRITE) {
11769677Slinton 	    store(p, seg, wordaddr, w.pword);
11779677Slinton 	}
11789677Slinton 	newaddr = wordaddr + sizeof(Word);
11799677Slinton     }
11809677Slinton     byteoff = (nbytes&(~WMASK));
11819677Slinton     nbytes -= byteoff;
11829677Slinton     bufend = cp + nbytes;
11839677Slinton     while (cp < bufend) {
11849677Slinton 	if (op == PREAD) {
11859677Slinton 	    *((Word *) cp) = fetch(p, seg, newaddr);
11869677Slinton 	} else {
11879677Slinton 	    store(p, seg, newaddr, *((Word *) cp));
11889677Slinton 	}
11899677Slinton 	cp += sizeof(Word);
11909677Slinton 	newaddr += sizeof(Word);
11919677Slinton     }
11929677Slinton     if (byteoff > 0) {
11939677Slinton 	w.pword = fetch(p, seg, newaddr);
11949677Slinton 	for (i = 0; i < byteoff; i++) {
11959677Slinton 	    if (op == PREAD) {
11969677Slinton 		*cp++ = w.pbyte[i];
11979677Slinton 	    } else {
11989677Slinton 		w.pbyte[i] = *cp++;
11999677Slinton 	    }
12009677Slinton 	}
12019677Slinton 	if (op == PWRITE) {
12029677Slinton 	    store(p, seg, newaddr, w.pword);
12039677Slinton 	}
12049677Slinton     }
12059677Slinton }
12069677Slinton 
12079677Slinton /*
12089677Slinton  * Get a word from a process at the given address.
12099677Slinton  * The address is assumed to be on a word boundary.
12109677Slinton  *
12119677Slinton  * A simple cache scheme is used to avoid redundant ptrace calls
12129677Slinton  * to the instruction space since it is assumed to be pure.
12139677Slinton  *
12149677Slinton  * It is necessary to use a write-through scheme so that
12159677Slinton  * breakpoints right next to each other don't interfere.
12169677Slinton  */
12179677Slinton 
12189677Slinton private Integer nfetchs, nreads, nwrites;
12199677Slinton 
12209677Slinton private Word fetch(p, seg, addr)
12219677Slinton Process p;
12229677Slinton PioSeg seg;
12239677Slinton register int addr;
12249677Slinton {
12259677Slinton     register CacheWord *wp;
12269677Slinton     register Word w;
12279677Slinton 
12289677Slinton     switch (seg) {
12299677Slinton 	case TEXTSEG:
12309677Slinton 	    ++nfetchs;
12319677Slinton 	    wp = &p->word[cachehash(addr)];
12329677Slinton 	    if (addr == 0 or wp->addr != addr) {
12339677Slinton 		++nreads;
123418230Slinton 		w = ptrace(IREAD, p->pid, addr, 0);
12359677Slinton 		wp->addr = addr;
12369677Slinton 		wp->val = w;
12379677Slinton 	    } else {
12389677Slinton 		w = wp->val;
12399677Slinton 	    }
12409677Slinton 	    break;
12419677Slinton 
12429677Slinton 	case DATASEG:
124318230Slinton 	    w = ptrace(DREAD, p->pid, addr, 0);
12449677Slinton 	    break;
12459677Slinton 
12469677Slinton 	default:
12479677Slinton 	    panic("fetch: bad seg %d", seg);
12489677Slinton 	    /* NOTREACHED */
12499677Slinton     }
12509677Slinton     return w;
12519677Slinton }
12529677Slinton 
12539677Slinton /*
12549677Slinton  * Put a word into the process' address space at the given address.
12559677Slinton  * The address is assumed to be on a word boundary.
12569677Slinton  */
12579677Slinton 
12589677Slinton private store(p, seg, addr, data)
12599677Slinton Process p;
12609677Slinton PioSeg seg;
12619677Slinton int addr;
12629677Slinton Word data;
12639677Slinton {
12649677Slinton     register CacheWord *wp;
12659677Slinton 
12669677Slinton     switch (seg) {
12679677Slinton 	case TEXTSEG:
12689677Slinton 	    ++nwrites;
12699677Slinton 	    wp = &p->word[cachehash(addr)];
12709677Slinton 	    wp->addr = addr;
12719677Slinton 	    wp->val = data;
127218230Slinton 	    ptrace(IWRITE, p->pid, addr, data);
12739677Slinton 	    break;
12749677Slinton 
12759677Slinton 	case DATASEG:
127618230Slinton 	    ptrace(DWRITE, p->pid, addr, data);
12779677Slinton 	    break;
12789677Slinton 
12799677Slinton 	default:
12809677Slinton 	    panic("store: bad seg %d", seg);
12819677Slinton 	    /* NOTREACHED */
12829677Slinton     }
12839677Slinton }
12849677Slinton 
128518230Slinton /*
128618230Slinton  * Flush the instruction cache associated with a process.
128718230Slinton  */
128818230Slinton 
128918230Slinton private cacheflush (p)
129018230Slinton Process p;
129118230Slinton {
129218230Slinton     bzero(p->word, sizeof(p->word));
129318230Slinton }
129418230Slinton 
12959677Slinton public printptraceinfo()
12969677Slinton {
12979677Slinton     printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites);
12989677Slinton }
12999677Slinton 
13009677Slinton /*
130116617Ssam  * Redirect input.
130216617Ssam  * Assuming this is called from a child, we should be careful to avoid
130316617Ssam  * (possibly) shared standard I/O buffers.
13049677Slinton  */
13059677Slinton 
130616617Ssam private infrom (filename)
130716617Ssam String filename;
130816617Ssam {
130916617Ssam     Fileid in;
131016617Ssam 
131116617Ssam     in = open(filename, 0);
131216617Ssam     if (in == -1) {
131316617Ssam 	write(2, "can't read ", 11);
131416617Ssam 	write(2, filename, strlen(filename));
131516617Ssam 	write(2, "\n", 1);
131616617Ssam 	_exit(1);
131716617Ssam     }
131816617Ssam     fswap(0, in);
131916617Ssam }
132016617Ssam 
132116617Ssam /*
132216617Ssam  * Redirect standard output.
132316617Ssam  * Same assumptions as for "infrom" above.
132416617Ssam  */
132516617Ssam 
132616617Ssam private outto (filename)
132716617Ssam String filename;
132816617Ssam {
132916617Ssam     Fileid out;
133016617Ssam 
133116617Ssam     out = creat(filename, 0666);
133216617Ssam     if (out == -1) {
133316617Ssam 	write(2, "can't write ", 12);
133416617Ssam 	write(2, filename, strlen(filename));
133516617Ssam 	write(2, "\n", 1);
133616617Ssam 	_exit(1);
133716617Ssam     }
133816617Ssam     fswap(1, out);
133916617Ssam }
134016617Ssam 
134116617Ssam /*
134216617Ssam  * Swap file numbers, useful for redirecting standard input or output.
134316617Ssam  */
134416617Ssam 
13459677Slinton private fswap(oldfd, newfd)
134616617Ssam Fileid oldfd;
134716617Ssam Fileid newfd;
13489677Slinton {
13499677Slinton     if (oldfd != newfd) {
13509677Slinton 	close(oldfd);
13519677Slinton 	dup(newfd);
13529677Slinton 	close(newfd);
13539677Slinton     }
13549677Slinton }
135516928Ssam 
135616928Ssam /*
135718230Slinton  * Signal name manipulation.
135816928Ssam  */
135918230Slinton 
136018230Slinton private String signames[NSIG] = {
136118230Slinton     0,
136218230Slinton     "HUP", "INT", "QUIT", "ILL", "TRAP",
136318230Slinton     "IOT", "EMT", "FPE", "KILL", "BUS",
136418230Slinton     "SEGV", "SYS", "PIPE", "ALRM", "TERM",
136518230Slinton     0, "STOP", "TSTP", "CONT", "CHLD",
136618230Slinton     "TTIN", "TTOU", "TINT", "XCPU", "XFSZ",
136716928Ssam };
136816928Ssam 
136916928Ssam /*
137018230Slinton  * Get the signal number associated with a given name.
137118230Slinton  * The name is first translated to upper case if necessary.
137216928Ssam  */
137318230Slinton 
137418230Slinton public integer siglookup (s)
137516928Ssam String s;
137616928Ssam {
137718230Slinton     register char *p, *q;
137818230Slinton     char buf[100];
137918230Slinton     integer i;
138016928Ssam 
138118230Slinton     p = s;
138218230Slinton     q = buf;
138318230Slinton     while (*p != '\0') {
138418230Slinton 	if (*p >= 'a' and *p <= 'z') {
138518230Slinton 	    *q = (*p - 'a') + 'A';
138618230Slinton 	} else {
138718230Slinton 	    *q = *p;
138818230Slinton 	}
138918230Slinton 	++p;
139018230Slinton 	++q;
139118230Slinton     }
139218230Slinton     *q = '\0';
139318230Slinton     p = buf;
139418230Slinton     if (buf[0] == 'S' and buf[1] == 'I' and buf[2] == 'G') {
139518230Slinton 	p += 3;
139618230Slinton     }
139718230Slinton     i = 1;
139818230Slinton     for (;;) {
139918230Slinton 	if (i >= sizeof(signames) div sizeof(signames[0])) {
140018230Slinton 	    error("signal \"%s\" unknown", s);
140118230Slinton 	    i = 0;
140218230Slinton 	    break;
140318230Slinton 	}
140418230Slinton 	if (signames[i] != nil and streq(signames[i], p)) {
140518230Slinton 	    break;
140618230Slinton 	}
140718230Slinton 	++i;
140818230Slinton     }
140918230Slinton     return i;
141016928Ssam }
141116928Ssam 
141216928Ssam /*
141318230Slinton  * Print all signals being ignored by the debugger.
141418230Slinton  * These signals are auotmatically
141516928Ssam  * passed on to the debugged process.
141616928Ssam  */
141718230Slinton 
141818230Slinton public printsigsignored (p)
141916931Ssam Process p;
142016928Ssam {
142116931Ssam     printsigs(~p->sigset);
142216928Ssam }
142316928Ssam 
142416928Ssam /*
142516928Ssam  * Print all signals being intercepted by
142616928Ssam  * the debugger for the specified process.
142716928Ssam  */
142818230Slinton 
142916931Ssam public printsigscaught(p)
143016931Ssam Process p;
143116928Ssam {
143216931Ssam     printsigs(p->sigset);
143316931Ssam }
143416931Ssam 
143518230Slinton private printsigs (set)
143618230Slinton integer set;
143716931Ssam {
143818230Slinton     integer s;
143918230Slinton     char separator[2];
144016931Ssam 
144118230Slinton     separator[0] = '\0';
144218230Slinton     for (s = 1; s < sizeof(signames) div sizeof(signames[0]); s++) {
144318230Slinton 	if (set & setrep(s)) {
144418230Slinton 	    if (signames[s] != nil) {
144518230Slinton 		printf("%s%s", separator, signames[s]);
144618230Slinton 		separator[0] = ' ';
144718230Slinton 		separator[1] = '\0';
144818230Slinton 	    }
144916928Ssam 	}
145018230Slinton     }
145118230Slinton     if (separator[0] == ' ') {
145216931Ssam 	putchar('\n');
145316931Ssam     }
145416928Ssam }
1455