121620Sdist /*
238105Sbostic * Copyright (c) 1983 The Regents of the University of California.
338105Sbostic * All rights reserved.
438105Sbostic *
5*42683Sbostic * %sccs.include.redist.c%
621620Sdist */
79677Slinton
821620Sdist #ifndef lint
9*42683Sbostic static char sccsid[] = "@(#)process.c 5.6 (Berkeley) 06/01/90";
1038105Sbostic #endif /* not lint */
119677Slinton
129677Slinton /*
139677Slinton * Process management.
149677Slinton *
159677Slinton * This module contains the routines to manage the execution and
169677Slinton * tracing of the debuggee process.
179677Slinton */
189677Slinton
199677Slinton #include "defs.h"
209677Slinton #include "process.h"
219677Slinton #include "machine.h"
229677Slinton #include "events.h"
239677Slinton #include "tree.h"
2414757Slinton #include "eval.h"
259677Slinton #include "operators.h"
269677Slinton #include "source.h"
279677Slinton #include "object.h"
289677Slinton #include "mappings.h"
299677Slinton #include "main.h"
309677Slinton #include "coredump.h"
319677Slinton #include <signal.h>
329677Slinton #include <errno.h>
339677Slinton #include <sys/stat.h>
349677Slinton
359677Slinton #ifndef public
369677Slinton
379677Slinton typedef struct Process *Process;
389677Slinton
399677Slinton Process process;
409677Slinton
4114757Slinton #define DEFSIG -1
4214757Slinton
439677Slinton #include "machine.h"
449677Slinton
459677Slinton #endif
469677Slinton
479677Slinton #define NOTSTARTED 1
489677Slinton #define STOPPED 0177
499677Slinton #define FINISHED 0
509677Slinton
519677Slinton /*
5216617Ssam * A cache of the instruction segment is kept to reduce the number
5316617Ssam * of system calls. Might be better just to read the entire
5416617Ssam * code space into memory.
559677Slinton */
569677Slinton
5733331Sdonn #define CACHESIZE 1003
589677Slinton
599677Slinton typedef struct {
609677Slinton Word addr;
619677Slinton Word val;
629677Slinton } CacheWord;
639677Slinton
649677Slinton /*
659677Slinton * This structure holds the information we need from the user structure.
669677Slinton */
679677Slinton
689677Slinton struct Process {
699677Slinton int pid; /* process being traced */
7011768Slinton int mask; /* process status word */
7111768Slinton Word reg[NREG]; /* process' registers */
729677Slinton Word oreg[NREG]; /* registers when process last stopped */
739677Slinton short status; /* either STOPPED or FINISHED */
749677Slinton short signo; /* signal that stopped process */
7518230Slinton short sigcode; /* extra signal information */
769677Slinton int exitval; /* return value from exit() */
779677Slinton long sigset; /* bit array of traced signals */
7833331Sdonn CacheWord word[CACHESIZE]; /* text segment cache */
7911768Slinton Ttyinfo ttyinfo; /* process' terminal characteristics */
8016617Ssam Address sigstatus; /* process' handler for current signal */
819677Slinton };
829677Slinton
839677Slinton /*
849677Slinton * These definitions are for the arguments to "pio".
859677Slinton */
869677Slinton
879677Slinton typedef enum { PREAD, PWRITE } PioOp;
889677Slinton typedef enum { TEXTSEG, DATASEG } PioSeg;
899677Slinton
909677Slinton private struct Process pbuf;
919677Slinton
9218230Slinton #define MAXNCMDARGS 1000 /* maximum number of arguments to RUN */
939677Slinton
9414395Slinton extern int errno;
9514395Slinton
969677Slinton private Boolean just_started;
979677Slinton private int argc;
989677Slinton private String argv[MAXNCMDARGS];
999677Slinton private String infile, outfile;
1009677Slinton
1019677Slinton /*
1029677Slinton * Initialize process information.
1039677Slinton */
1049677Slinton
process_init()1059677Slinton public process_init()
1069677Slinton {
10733331Sdonn register integer i;
10833331Sdonn char buf[10];
1099677Slinton
1109677Slinton process = &pbuf;
1119677Slinton process->status = (coredump) ? STOPPED : NOTSTARTED;
1129677Slinton setsigtrace();
11333331Sdonn # if vax || tahoe
11433331Sdonn for (i = 0; i < NREG; i++) {
11533331Sdonn sprintf(buf, "$r%d", i);
11633331Sdonn defregname(identname(buf, false), i);
11733331Sdonn }
11833331Sdonn # ifdef vax
11933331Sdonn defregname(identname("$ap", true), ARGP);
12033331Sdonn # endif
12133331Sdonn # else
12233331Sdonn # ifdef mc68000
12333331Sdonn for (i = 0; i < 8; i++) {
12433331Sdonn sprintf(buf, "$d%d", i);
12533331Sdonn defregname(identname(buf, false), i);
12633331Sdonn sprintf(buf, "$a%d", i);
12733331Sdonn defregname(identname(buf, false), i + 8);
12833331Sdonn }
12933331Sdonn # endif
13033331Sdonn # endif
1319677Slinton defregname(identname("$fp", true), FRP);
1329677Slinton defregname(identname("$sp", true), STKP);
1339677Slinton defregname(identname("$pc", true), PROGCTR);
1349677Slinton if (coredump) {
1359677Slinton coredump_readin(process->mask, process->reg, process->signo);
13612484Slinton pc = process->reg[PROGCTR];
1379677Slinton }
13812484Slinton arginit();
1399677Slinton }
1409677Slinton
1419677Slinton /*
1429677Slinton * Routines to get at process information from outside this module.
1439677Slinton */
1449677Slinton
reg(n)1459677Slinton public Word reg(n)
1469677Slinton Integer n;
1479677Slinton {
1489677Slinton register Word w;
1499677Slinton
1509677Slinton if (n == NREG) {
1519677Slinton w = process->mask;
1529677Slinton } else {
1539677Slinton w = process->reg[n];
1549677Slinton }
1559677Slinton return w;
1569677Slinton }
1579677Slinton
setreg(n,w)1589677Slinton public setreg(n, w)
1599677Slinton Integer n;
1609677Slinton Word w;
1619677Slinton {
1629677Slinton process->reg[n] = w;
1639677Slinton }
1649677Slinton
1659677Slinton /*
1669677Slinton * Begin execution.
1679677Slinton *
1689677Slinton * We set a breakpoint at the end of the code so that the
1699677Slinton * process data doesn't disappear after the program terminates.
1709677Slinton */
1719677Slinton
1729677Slinton private Boolean remade();
1739677Slinton
start(argv,infile,outfile)1749677Slinton public start(argv, infile, outfile)
1759677Slinton String argv[];
1769677Slinton String infile, outfile;
1779677Slinton {
1789677Slinton String pargv[4];
1799677Slinton Node cond;
1809677Slinton
1819677Slinton if (coredump) {
1829677Slinton coredump = false;
1839677Slinton fclose(corefile);
1849677Slinton coredump_close();
1859677Slinton }
1869677Slinton if (argv == nil) {
1879677Slinton argv = pargv;
1889677Slinton pargv[0] = objname;
1899677Slinton pargv[1] = nil;
1909677Slinton } else {
1919677Slinton argv[argc] = nil;
1929677Slinton }
19318230Slinton pstart(process, argv, infile, outfile);
1949677Slinton if (remade(objname)) {
1959677Slinton reinit(argv, infile, outfile);
1969677Slinton }
1979677Slinton if (process->status == STOPPED) {
19833331Sdonn pc = CODESTART;
19916617Ssam setcurfunc(program);
2009677Slinton if (objsize != 0) {
2019677Slinton cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr()));
2029677Slinton event_once(cond, buildcmdlist(build(O_ENDX)));
2039677Slinton }
2049677Slinton }
2059677Slinton }
2069677Slinton
2079677Slinton /*
2089677Slinton * Check to see if the object file has changed since the symbolic
2099677Slinton * information last was read.
2109677Slinton */
2119677Slinton
2129677Slinton private time_t modtime;
2139677Slinton
remade(filename)2149677Slinton private Boolean remade(filename)
2159677Slinton String filename;
2169677Slinton {
2179677Slinton struct stat s;
2189677Slinton Boolean b;
2199677Slinton
2209677Slinton stat(filename, &s);
2219677Slinton b = (Boolean) (modtime != 0 and modtime < s.st_mtime);
2229677Slinton modtime = s.st_mtime;
2239677Slinton return b;
2249677Slinton }
2259677Slinton
2269677Slinton /*
2279677Slinton * Set up what signals we want to trace.
2289677Slinton */
2299677Slinton
setsigtrace()2309677Slinton private setsigtrace()
2319677Slinton {
2329677Slinton register Integer i;
2339677Slinton register Process p;
2349677Slinton
2359677Slinton p = process;
2369677Slinton for (i = 1; i <= NSIG; i++) {
2379677Slinton psigtrace(p, i, true);
2389677Slinton }
2399677Slinton psigtrace(p, SIGHUP, false);
2409677Slinton psigtrace(p, SIGKILL, false);
2419677Slinton psigtrace(p, SIGALRM, false);
24233331Sdonn # ifdef SIGTSTP
24333331Sdonn psigtrace(p, SIGTSTP, false);
24433331Sdonn psigtrace(p, SIGCONT, false);
24533331Sdonn # endif
2469677Slinton psigtrace(p, SIGCHLD, false);
24726333Ssam psigtrace(p, SIGWINCH, false);
2489677Slinton }
2499677Slinton
2509677Slinton /*
2519677Slinton * Initialize the argument list.
2529677Slinton */
2539677Slinton
arginit()2549677Slinton public arginit()
2559677Slinton {
2569677Slinton infile = nil;
2579677Slinton outfile = nil;
2589677Slinton argv[0] = objname;
2599677Slinton argc = 1;
2609677Slinton }
2619677Slinton
2629677Slinton /*
2639677Slinton * Add an argument to the list for the debuggee.
2649677Slinton */
2659677Slinton
newarg(arg)2669677Slinton public newarg(arg)
2679677Slinton String arg;
2689677Slinton {
2699677Slinton if (argc >= MAXNCMDARGS) {
2709677Slinton error("too many arguments");
2719677Slinton }
2729677Slinton argv[argc++] = arg;
2739677Slinton }
2749677Slinton
2759677Slinton /*
2769677Slinton * Set the standard input for the debuggee.
2779677Slinton */
2789677Slinton
inarg(filename)2799677Slinton public inarg(filename)
2809677Slinton String filename;
2819677Slinton {
2829677Slinton if (infile != nil) {
2839677Slinton error("multiple input redirects");
2849677Slinton }
2859677Slinton infile = filename;
2869677Slinton }
2879677Slinton
2889677Slinton /*
2899677Slinton * Set the standard output for the debuggee.
2909677Slinton * Probably should check to avoid overwriting an existing file.
2919677Slinton */
2929677Slinton
outarg(filename)2939677Slinton public outarg(filename)
2949677Slinton String filename;
2959677Slinton {
2969677Slinton if (outfile != nil) {
2979677Slinton error("multiple output redirect");
2989677Slinton }
2999677Slinton outfile = filename;
3009677Slinton }
3019677Slinton
3029677Slinton /*
3039677Slinton * Start debuggee executing.
3049677Slinton */
3059677Slinton
run()3069677Slinton public run()
3079677Slinton {
3089677Slinton process->status = STOPPED;
3099677Slinton fixbps();
3109677Slinton curline = 0;
3119677Slinton start(argv, infile, outfile);
3129677Slinton just_started = true;
3139677Slinton isstopped = false;
31414757Slinton cont(0);
3159677Slinton }
3169677Slinton
3179677Slinton /*
3189677Slinton * Continue execution wherever we left off.
3199677Slinton *
3209677Slinton * Note that this routine never returns. Eventually bpact() will fail
3219677Slinton * and we'll call printstatus or step will call it.
3229677Slinton */
3239677Slinton
3249677Slinton typedef int Intfunc();
3259677Slinton
32639163Sbostic private sig_t dbintr;
32739163Sbostic private void intr();
3289677Slinton
cont(signo)32911867Slinton public cont(signo)
33016617Ssam integer signo;
3319677Slinton {
33216617Ssam integer s;
33316617Ssam
3349677Slinton dbintr = signal(SIGINT, intr);
3359677Slinton if (just_started) {
3369677Slinton just_started = false;
3379677Slinton } else {
3389677Slinton if (not isstopped) {
3399677Slinton error("can't continue execution");
3409677Slinton }
3419677Slinton isstopped = false;
34211867Slinton stepover();
3439677Slinton }
34416617Ssam s = signo;
3459677Slinton for (;;) {
3469677Slinton if (single_stepping) {
3479677Slinton printnews();
3489677Slinton } else {
3499677Slinton setallbps();
35016617Ssam resume(s);
3519677Slinton unsetallbps();
35216617Ssam s = DEFSIG;
35318230Slinton if (not isbperr() or not bpact()) {
3549677Slinton printstatus();
3559677Slinton }
3569677Slinton }
35711867Slinton stepover();
3589677Slinton }
3599677Slinton /* NOTREACHED */
3609677Slinton }
3619677Slinton
3629677Slinton /*
36318230Slinton * This routine is called if we get an interrupt while "running"
3649677Slinton * but actually in the debugger. Could happen, for example, while
3659677Slinton * processing breakpoints.
3669677Slinton *
3679677Slinton * We basically just want to keep going; the assumption is
36818230Slinton * that when the process resumes it will get the interrupt,
3699677Slinton * which will then be handled.
3709677Slinton */
3719677Slinton
intr()37239163Sbostic private void intr()
3739677Slinton {
3749677Slinton signal(SIGINT, intr);
3759677Slinton }
3769677Slinton
fixintr()3779677Slinton public fixintr()
3789677Slinton {
3799677Slinton signal(SIGINT, dbintr);
3809677Slinton }
3819677Slinton
3829677Slinton /*
3839677Slinton * Resume execution.
3849677Slinton */
3859677Slinton
resume(signo)38611867Slinton public resume(signo)
38711867Slinton int signo;
3889677Slinton {
3899677Slinton register Process p;
3909677Slinton
3919677Slinton p = process;
39211867Slinton pcont(p, signo);
3939677Slinton pc = process->reg[PROGCTR];
39411832Slinton if (p->status != STOPPED) {
39511867Slinton if (p->signo != 0) {
39611867Slinton error("program terminated by signal %d", p->signo);
39714757Slinton } else if (not runfirst) {
39818230Slinton if (p->exitval == 0) {
39918230Slinton error("program exited");
40018230Slinton } else {
40118230Slinton error("program exited with code %d", p->exitval);
40218230Slinton }
40311867Slinton }
40411832Slinton }
4059677Slinton }
4069677Slinton
4079677Slinton /*
4089677Slinton * Continue execution up to the next source line.
4099677Slinton *
4109677Slinton * There are two ways to define the next source line depending on what
4119677Slinton * is desired when a procedure or function call is encountered. Step
4129677Slinton * stops at the beginning of the procedure or call; next skips over it.
4139677Slinton */
4149677Slinton
4159677Slinton /*
4169677Slinton * Stepc is what is called when the step command is given.
4179677Slinton * It has to play with the "isstopped" information.
4189677Slinton */
4199677Slinton
stepc()4209677Slinton public stepc()
4219677Slinton {
4229677Slinton if (not isstopped) {
4239677Slinton error("can't continue execution");
4249677Slinton }
4259677Slinton isstopped = false;
4269677Slinton dostep(false);
4279677Slinton isstopped = true;
4289677Slinton }
4299677Slinton
next()4309677Slinton public next()
4319677Slinton {
43216617Ssam Address oldfrp, newfrp;
43316617Ssam
4349677Slinton if (not isstopped) {
4359677Slinton error("can't continue execution");
4369677Slinton }
4379677Slinton isstopped = false;
43816617Ssam oldfrp = reg(FRP);
43916617Ssam do {
44016617Ssam dostep(true);
44116617Ssam pc = reg(PROGCTR);
44216617Ssam newfrp = reg(FRP);
44316617Ssam } while (newfrp < oldfrp and newfrp != 0);
4449677Slinton isstopped = true;
4459677Slinton }
4469677Slinton
44711867Slinton /*
44816617Ssam * Continue execution until the current function returns, or,
44916617Ssam * if the given argument is non-nil, until execution returns to
45016617Ssam * somewhere within the given function.
45116617Ssam */
45216617Ssam
rtnfunc(f)45316617Ssam public rtnfunc (f)
45416617Ssam Symbol f;
45516617Ssam {
45616617Ssam Address addr;
45716617Ssam Symbol t;
45816617Ssam
45916617Ssam if (not isstopped) {
46016617Ssam error("can't continue execution");
46116617Ssam } else if (f != nil and not isactive(f)) {
46216617Ssam error("%s is not active", symname(f));
46316617Ssam } else {
46416617Ssam addr = return_addr();
46516617Ssam if (addr == nil) {
46616617Ssam error("no place to return to");
46716617Ssam } else {
46816617Ssam isstopped = false;
46916617Ssam contto(addr);
47016617Ssam if (f != nil) {
47116617Ssam for (;;) {
47216617Ssam t = whatblock(pc);
47316617Ssam addr = return_addr();
47416617Ssam if (t == f or addr == nil) break;
47516617Ssam contto(addr);
47616617Ssam }
47716617Ssam }
47818230Slinton if (not bpact()) {
47916617Ssam isstopped = true;
48016617Ssam printstatus();
48116617Ssam }
48216617Ssam }
48316617Ssam }
48416617Ssam }
48516617Ssam
48616617Ssam /*
48711867Slinton * Single-step over the current machine instruction.
48811867Slinton *
48911867Slinton * If we're single-stepping by source line we want to step to the
49011867Slinton * next source line. Otherwise we're going to continue so there's
49111867Slinton * no reason to do all the work necessary to single-step to the next
49211867Slinton * source line.
49311867Slinton */
49411867Slinton
stepover()49516617Ssam public stepover()
4969677Slinton {
49711867Slinton Boolean b;
49811867Slinton
49916617Ssam if (traceexec) {
50016617Ssam printf("!! stepping over 0x%x\n", process->reg[PROGCTR]);
50116617Ssam }
50211867Slinton if (single_stepping) {
50311867Slinton dostep(false);
50411867Slinton } else {
50511867Slinton b = inst_tracing;
50611867Slinton inst_tracing = true;
50711867Slinton dostep(false);
50811867Slinton inst_tracing = b;
50911867Slinton }
51016617Ssam if (traceexec) {
51116617Ssam printf("!! stepped over to 0x%x\n", process->reg[PROGCTR]);
51216617Ssam }
5139677Slinton }
5149677Slinton
5159677Slinton /*
51618230Slinton * Resume execution up to the given address. We can either ignore
51718230Slinton * breakpoints (stepto) or catch them (contto).
5189677Slinton */
5199677Slinton
stepto(addr)5209677Slinton public stepto(addr)
5219677Slinton Address addr;
5229677Slinton {
52316617Ssam xto(addr, false);
52416617Ssam }
52516617Ssam
contto(addr)52616617Ssam private contto (addr)
52716617Ssam Address addr;
52816617Ssam {
52916617Ssam xto(addr, true);
53016617Ssam }
53116617Ssam
xto(addr,catchbps)53216617Ssam private xto (addr, catchbps)
53316617Ssam Address addr;
53416617Ssam boolean catchbps;
53516617Ssam {
53616617Ssam Address curpc;
53716617Ssam
53816617Ssam if (catchbps) {
53916617Ssam stepover();
5409677Slinton }
54116617Ssam curpc = process->reg[PROGCTR];
54216617Ssam if (addr != curpc) {
54316617Ssam if (traceexec) {
54416617Ssam printf("!! stepping from 0x%x to 0x%x\n", curpc, addr);
54516617Ssam }
54616617Ssam if (catchbps) {
54716617Ssam setallbps();
54816617Ssam }
54916617Ssam setbp(addr);
55016617Ssam resume(DEFSIG);
55116617Ssam unsetbp(addr);
55216617Ssam if (catchbps) {
55316617Ssam unsetallbps();
55416617Ssam }
55516617Ssam if (not isbperr()) {
55616617Ssam printstatus();
55716617Ssam }
55816617Ssam }
5599677Slinton }
5609677Slinton
5619677Slinton /*
5629677Slinton * Print the status of the process.
5639677Slinton * This routine does not return.
5649677Slinton */
5659677Slinton
printstatus()56633331Sdonn public printstatus ()
5679677Slinton {
56814395Slinton int status;
56914395Slinton
5709843Slinton if (process->status == FINISHED) {
5719843Slinton exit(0);
5729843Slinton } else {
57333331Sdonn if (runfirst) {
57433331Sdonn fprintf(stderr, "\nEntering debugger ...\n");
57533331Sdonn printheading();
57633331Sdonn init();
57733331Sdonn }
57816617Ssam setcurfunc(whatblock(pc));
5799677Slinton getsrcpos();
5809843Slinton if (process->signo == SIGINT) {
5819843Slinton isstopped = true;
5829843Slinton printerror();
5839843Slinton } else if (isbperr() and isstopped) {
5849843Slinton printf("stopped ");
58511172Slinton printloc();
58611172Slinton putchar('\n');
5879843Slinton if (curline > 0) {
5889843Slinton printlines(curline, curline);
5899843Slinton } else {
5909843Slinton printinst(pc, pc);
5919843Slinton }
5929843Slinton erecover();
5939677Slinton } else {
5949843Slinton fixintr();
5959677Slinton isstopped = true;
5969677Slinton printerror();
5979677Slinton }
5989677Slinton }
5999677Slinton }
6009677Slinton
6019677Slinton /*
60211172Slinton * Print out the current location in the debuggee.
60311172Slinton */
60411172Slinton
printloc()60511172Slinton public printloc()
60611172Slinton {
60711172Slinton printf("in ");
60811172Slinton printname(stdout, curfunc);
60911172Slinton putchar(' ');
61014757Slinton if (curline > 0 and not useInstLoc) {
61111172Slinton printsrcpos();
61211172Slinton } else {
61314757Slinton useInstLoc = false;
61414757Slinton curline = 0;
61511172Slinton printf("at 0x%x", pc);
61611172Slinton }
61711172Slinton }
61811172Slinton
61911172Slinton /*
6209677Slinton * Some functions for testing the state of the process.
6219677Slinton */
6229677Slinton
notstarted(p)6239677Slinton public Boolean notstarted(p)
6249677Slinton Process p;
6259677Slinton {
6269677Slinton return (Boolean) (p->status == NOTSTARTED);
6279677Slinton }
6289677Slinton
isfinished(p)6299677Slinton public Boolean isfinished(p)
6309677Slinton Process p;
6319677Slinton {
6329677Slinton return (Boolean) (p->status == FINISHED);
6339677Slinton }
6349677Slinton
6359677Slinton /*
63618230Slinton * Predicate to test if the reason the process stopped was because
63718230Slinton * of a breakpoint. If so, as a side effect clear the local copy of
63818230Slinton * signal handler associated with process. We must do this so as to
63918230Slinton * not confuse future stepping or continuing by possibly concluding
64018230Slinton * the process should continue with a SIGTRAP handler.
6419677Slinton */
6429677Slinton
isbperr()64318230Slinton public boolean isbperr()
64418230Slinton {
64518230Slinton Process p;
64618230Slinton boolean b;
64718230Slinton
64818230Slinton p = process;
64918230Slinton if (p->status == STOPPED and p->signo == SIGTRAP) {
65018230Slinton b = true;
65118230Slinton p->sigstatus = 0;
65218230Slinton } else {
65318230Slinton b = false;
65418230Slinton }
65518230Slinton return b;
65618230Slinton }
65718230Slinton
65818230Slinton /*
65918230Slinton * Return the signal number that stopped the process.
66018230Slinton */
66118230Slinton
errnum(p)66218230Slinton public integer errnum (p)
6639677Slinton Process p;
6649677Slinton {
6659677Slinton return p->signo;
6669677Slinton }
6679677Slinton
66818230Slinton /*
66918230Slinton * Return the signal code associated with the signal.
67018230Slinton */
67118230Slinton
errcode(p)67218230Slinton public integer errcode (p)
67316931Ssam Process p;
67416931Ssam {
67516931Ssam return p->sigcode;
67616931Ssam }
67716931Ssam
6789677Slinton /*
6799677Slinton * Return the termination code of the process.
6809677Slinton */
6819677Slinton
exitcode(p)68218230Slinton public integer exitcode (p)
6839677Slinton Process p;
6849677Slinton {
6859677Slinton return p->exitval;
6869677Slinton }
6879677Slinton
6889677Slinton /*
6899677Slinton * These routines are used to access the debuggee process from
6909677Slinton * outside this module.
6919677Slinton *
6929677Slinton * They invoke "pio" which eventually leads to a call to "ptrace".
69314757Slinton * The system generates an I/O error when a ptrace fails. During reads
69414757Slinton * these are ignored, during writes they are reported as an error, and
69514757Slinton * for anything else they cause a fatal error.
6969677Slinton */
6979677Slinton
6989677Slinton extern Intfunc *onsyserr();
6999677Slinton
7009677Slinton private badaddr;
70114757Slinton private read_err(), write_err();
7029677Slinton
7039677Slinton /*
7049677Slinton * Read from the process' instruction area.
7059677Slinton */
7069677Slinton
iread(buff,addr,nbytes)7079677Slinton public iread(buff, addr, nbytes)
7089677Slinton char *buff;
7099677Slinton Address addr;
7109677Slinton int nbytes;
7119677Slinton {
7129677Slinton Intfunc *f;
7139677Slinton
71414757Slinton f = onsyserr(EIO, read_err);
7159677Slinton badaddr = addr;
7169677Slinton if (coredump) {
7179677Slinton coredump_readtext(buff, addr, nbytes);
7189677Slinton } else {
7199677Slinton pio(process, PREAD, TEXTSEG, buff, addr, nbytes);
7209677Slinton }
7219677Slinton onsyserr(EIO, f);
7229677Slinton }
7239677Slinton
7249677Slinton /*
7259677Slinton * Write to the process' instruction area, usually in order to set
7269677Slinton * or unset a breakpoint.
7279677Slinton */
7289677Slinton
iwrite(buff,addr,nbytes)7299677Slinton public iwrite(buff, addr, nbytes)
7309677Slinton char *buff;
7319677Slinton Address addr;
7329677Slinton int nbytes;
7339677Slinton {
7349677Slinton Intfunc *f;
7359677Slinton
7369677Slinton if (coredump) {
7379677Slinton error("no process to write to");
7389677Slinton }
73914757Slinton f = onsyserr(EIO, write_err);
7409677Slinton badaddr = addr;
7419677Slinton pio(process, PWRITE, TEXTSEG, buff, addr, nbytes);
7429677Slinton onsyserr(EIO, f);
7439677Slinton }
7449677Slinton
7459677Slinton /*
7469677Slinton * Read for the process' data area.
7479677Slinton */
7489677Slinton
dread(buff,addr,nbytes)7499677Slinton public dread(buff, addr, nbytes)
7509677Slinton char *buff;
7519677Slinton Address addr;
7529677Slinton int nbytes;
7539677Slinton {
7549677Slinton Intfunc *f;
7559677Slinton
7569677Slinton badaddr = addr;
7579677Slinton if (coredump) {
75818230Slinton f = onsyserr(EFAULT, read_err);
7599677Slinton coredump_readdata(buff, addr, nbytes);
76018230Slinton onsyserr(EFAULT, f);
7619677Slinton } else {
76218230Slinton f = onsyserr(EIO, read_err);
7639677Slinton pio(process, PREAD, DATASEG, buff, addr, nbytes);
76418230Slinton onsyserr(EIO, f);
7659677Slinton }
7669677Slinton }
7679677Slinton
7689677Slinton /*
7699677Slinton * Write to the process' data area.
7709677Slinton */
7719677Slinton
dwrite(buff,addr,nbytes)7729677Slinton public dwrite(buff, addr, nbytes)
7739677Slinton char *buff;
7749677Slinton Address addr;
7759677Slinton int nbytes;
7769677Slinton {
7779677Slinton Intfunc *f;
7789677Slinton
7799677Slinton if (coredump) {
7809677Slinton error("no process to write to");
7819677Slinton }
78214757Slinton f = onsyserr(EIO, write_err);
7839677Slinton badaddr = addr;
7849677Slinton pio(process, PWRITE, DATASEG, buff, addr, nbytes);
7859677Slinton onsyserr(EIO, f);
7869677Slinton }
7879677Slinton
7889677Slinton /*
78914757Slinton * Trap for errors in reading or writing to a process.
79014757Slinton * The current approach is to "ignore" read errors and complain
79114757Slinton * bitterly about write errors.
7929677Slinton */
7939677Slinton
read_err()79414757Slinton private read_err()
7959677Slinton {
79611560Slinton /*
79714757Slinton * Ignore.
79811560Slinton */
7999677Slinton }
8009677Slinton
write_err()80114757Slinton private write_err()
80214757Slinton {
80314757Slinton error("can't write to process (address 0x%x)", badaddr);
80414757Slinton }
80514757Slinton
8069677Slinton /*
8079677Slinton * Ptrace interface.
8089677Slinton */
8099677Slinton
8109677Slinton #define WMASK (~(sizeof(Word) - 1))
81133331Sdonn #define cachehash(addr) ((unsigned) ((addr >> 2) % CACHESIZE))
8129677Slinton
8139677Slinton #define FIRSTSIG SIGINT
8149677Slinton #define LASTSIG SIGQUIT
8159677Slinton #define ischild(pid) ((pid) == 0)
81618230Slinton #define traceme() ptrace(0, 0, 0, 0)
8179677Slinton #define setrep(n) (1 << ((n)-1))
8189677Slinton #define istraced(p) (p->sigset&setrep(p->signo))
8199677Slinton
8209677Slinton /*
82118230Slinton * Ptrace options (specified in first argument).
82218230Slinton */
82318230Slinton
82418230Slinton #define UREAD 3 /* read from process's user structure */
82518230Slinton #define UWRITE 6 /* write to process's user structure */
82618230Slinton #define IREAD 1 /* read from process's instruction space */
82718230Slinton #define IWRITE 4 /* write to process's instruction space */
82818230Slinton #define DREAD 2 /* read from process's data space */
82918230Slinton #define DWRITE 5 /* write to process's data space */
83018230Slinton #define CONT 7 /* continue stopped process */
83118230Slinton #define SSTEP 9 /* continue for approximately one instruction */
83218230Slinton #define PKILL 8 /* terminate the process */
83318230Slinton
83433331Sdonn #ifdef IRIS
83533331Sdonn # define readreg(p, r) ptrace(10, p->pid, r, 0)
83633331Sdonn # define writereg(p, r, v) ptrace(11, p->pid, r, v)
83733331Sdonn #else
83833331Sdonn # define readreg(p, r) ptrace(UREAD, p->pid, regloc(r), 0);
83933331Sdonn # define writereg(p, r, v) ptrace(UWRITE, p->pid, regloc(r), v);
84033331Sdonn #endif
84133331Sdonn
84218230Slinton /*
8439677Slinton * Start up a new process by forking and exec-ing the
8449677Slinton * given argument list, returning when the process is loaded
8459677Slinton * and ready to execute. The PROCESS information (pointed to
8469677Slinton * by the first argument) is appropriately filled.
8479677Slinton *
8489677Slinton * If the given PROCESS structure is associated with an already running
8499677Slinton * process, we terminate it.
8509677Slinton */
8519677Slinton
8529677Slinton /* VARARGS2 */
pstart(p,argv,infile,outfile)8539677Slinton private pstart(p, argv, infile, outfile)
8549677Slinton Process p;
8559677Slinton String argv[];
8569677Slinton String infile;
8579677Slinton String outfile;
8589677Slinton {
8599677Slinton int status;
8609677Slinton
86116617Ssam if (p->pid != 0) {
86216617Ssam pterm(p);
86318230Slinton cacheflush(p);
8649677Slinton }
86518230Slinton fflush(stdout);
8669677Slinton psigtrace(p, SIGTRAP, true);
86733331Sdonn # ifdef IRIS
86833331Sdonn p->pid = fork();
86933331Sdonn # else
87033331Sdonn p->pid = vfork();
87133331Sdonn # endif
87214395Slinton if (p->pid == -1) {
8739677Slinton panic("can't fork");
8749677Slinton }
8759677Slinton if (ischild(p->pid)) {
87618230Slinton nocatcherrs();
8779677Slinton traceme();
8789677Slinton if (infile != nil) {
87916617Ssam infrom(infile);
8809677Slinton }
8819677Slinton if (outfile != nil) {
88216617Ssam outto(outfile);
8839677Slinton }
88411832Slinton execv(argv[0], argv);
88511172Slinton _exit(1);
8869677Slinton }
8879677Slinton pwait(p->pid, &status);
8889677Slinton getinfo(p, status);
8899677Slinton if (p->status != STOPPED) {
89018230Slinton beginerrmsg();
89118230Slinton fprintf(stderr, "warning: cannot execute %s\n", argv[0]);
89218230Slinton } else {
89318230Slinton ptraced(p->pid);
8949677Slinton }
8959677Slinton }
8969677Slinton
8979677Slinton /*
89816617Ssam * Terminate a ptrace'd process.
89916617Ssam */
90016617Ssam
pterm(p)90116617Ssam public pterm (p)
90216617Ssam Process p;
90316617Ssam {
90416617Ssam integer status;
90516617Ssam
90616617Ssam if (p != nil and p->pid != 0) {
90718230Slinton ptrace(PKILL, p->pid, 0, 0);
90816617Ssam pwait(p->pid, &status);
90916617Ssam unptraced(p->pid);
91016617Ssam }
91116617Ssam }
91216617Ssam
91316617Ssam /*
91411867Slinton * Continue a stopped process. The first argument points to a Process
91511867Slinton * structure. Before the process is restarted it's user area is modified
91611867Slinton * according to the values in the structure. When this routine finishes,
9179677Slinton * the structure has the new values from the process's user area.
9189677Slinton *
9199677Slinton * Pcont terminates when the process stops with a signal pending that
9209677Slinton * is being traced (via psigtrace), or when the process terminates.
9219677Slinton */
9229677Slinton
pcont(p,signo)92311867Slinton private pcont(p, signo)
9249677Slinton Process p;
92511867Slinton int signo;
9269677Slinton {
92716617Ssam int s, status;
9289677Slinton
9299677Slinton if (p->pid == 0) {
93018230Slinton error("program is not active");
9319677Slinton }
93216617Ssam s = signo;
9339677Slinton do {
93416617Ssam setinfo(p, s);
93516617Ssam if (traceexec) {
93616617Ssam printf("!! pcont from 0x%x with signal %d (%d)\n",
93716617Ssam p->reg[PROGCTR], s, p->signo);
93816617Ssam fflush(stdout);
93916617Ssam }
9409677Slinton sigs_off();
94118230Slinton if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) {
94214395Slinton panic("error %d trying to continue process", errno);
9439677Slinton }
9449677Slinton pwait(p->pid, &status);
9459677Slinton sigs_on();
9469677Slinton getinfo(p, status);
94718230Slinton if (p->status == STOPPED and traceexec and not istraced(p)) {
94818230Slinton printf("!! ignored signal %d at 0x%x\n",
94918230Slinton p->signo, p->reg[PROGCTR]);
95016617Ssam fflush(stdout);
95116617Ssam }
95216617Ssam s = p->signo;
9539677Slinton } while (p->status == STOPPED and not istraced(p));
95416617Ssam if (traceexec) {
95516617Ssam printf("!! pcont to 0x%x on signal %d\n", p->reg[PROGCTR], p->signo);
95616617Ssam fflush(stdout);
95716617Ssam }
9589677Slinton }
9599677Slinton
9609677Slinton /*
9619677Slinton * Single step as best ptrace can.
9629677Slinton */
9639677Slinton
pstep(p,signo)96416617Ssam public pstep(p, signo)
9659677Slinton Process p;
96616617Ssam integer signo;
9679677Slinton {
96818230Slinton int s, status;
9699677Slinton
97018230Slinton s = signo;
97118230Slinton do {
97218230Slinton setinfo(p, s);
97318230Slinton if (traceexec) {
97418230Slinton printf("!! pstep from 0x%x with signal %d (%d)\n",
97518230Slinton p->reg[PROGCTR], s, p->signo);
97618230Slinton fflush(stdout);
97718230Slinton }
97818230Slinton sigs_off();
97918230Slinton if (ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo) < 0) {
98018230Slinton panic("error %d trying to step process", errno);
98118230Slinton }
98218230Slinton pwait(p->pid, &status);
98318230Slinton sigs_on();
98418230Slinton getinfo(p, status);
98533331Sdonn # if mc68000 || m68000
98633331Sdonn if (p->status == STOPPED and p->signo == SIGTRAP) {
98733331Sdonn p->reg[PROGCTR] += 2;
98833331Sdonn }
98933331Sdonn # endif
99018230Slinton if (p->status == STOPPED and traceexec and not istraced(p)) {
99118230Slinton printf("!! pstep ignored signal %d at 0x%x\n",
99218230Slinton p->signo, p->reg[PROGCTR]);
99318230Slinton fflush(stdout);
99418230Slinton }
99518230Slinton s = p->signo;
99618230Slinton } while (p->status == STOPPED and not istraced(p));
99716617Ssam if (traceexec) {
99818230Slinton printf("!! pstep to 0x%x on signal %d\n",
99918230Slinton p->reg[PROGCTR], p->signo);
100016617Ssam fflush(stdout);
100116617Ssam }
100216617Ssam if (p->status != STOPPED) {
100318230Slinton if (p->exitval == 0) {
100418230Slinton error("program exited\n");
100518230Slinton } else {
100618230Slinton error("program exited with code %d\n", p->exitval);
100718230Slinton }
100816617Ssam }
10099677Slinton }
10109677Slinton
10119677Slinton /*
10129677Slinton * Return from execution when the given signal is pending.
10139677Slinton */
10149677Slinton
psigtrace(p,sig,sw)10159677Slinton public psigtrace(p, sig, sw)
10169677Slinton Process p;
10179677Slinton int sig;
10189677Slinton Boolean sw;
10199677Slinton {
10209677Slinton if (sw) {
10219677Slinton p->sigset |= setrep(sig);
10229677Slinton } else {
10239677Slinton p->sigset &= ~setrep(sig);
10249677Slinton }
10259677Slinton }
10269677Slinton
10279677Slinton /*
10289677Slinton * Don't catch any signals.
10299677Slinton * Particularly useful when letting a process finish uninhibited.
10309677Slinton */
10319677Slinton
unsetsigtraces(p)10329677Slinton public unsetsigtraces(p)
10339677Slinton Process p;
10349677Slinton {
10359677Slinton p->sigset = 0;
10369677Slinton }
10379677Slinton
10389677Slinton /*
10399677Slinton * Turn off attention to signals not being caught.
10409677Slinton */
10419677Slinton
104239163Sbostic private sig_t sigfunc[NSIG];
10439677Slinton
sigs_off()10449677Slinton private sigs_off()
10459677Slinton {
10469677Slinton register int i;
10479677Slinton
10489677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) {
10499677Slinton if (i != SIGKILL) {
10509677Slinton sigfunc[i] = signal(i, SIG_IGN);
10519677Slinton }
10529677Slinton }
10539677Slinton }
10549677Slinton
10559677Slinton /*
10569677Slinton * Turn back on attention to signals.
10579677Slinton */
10589677Slinton
sigs_on()10599677Slinton private sigs_on()
10609677Slinton {
10619677Slinton register int i;
10629677Slinton
10639677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) {
10649677Slinton if (i != SIGKILL) {
10659677Slinton signal(i, sigfunc[i]);
10669677Slinton }
10679677Slinton }
10689677Slinton }
10699677Slinton
10709677Slinton /*
10719677Slinton * Get process information from user area.
10729677Slinton */
10739677Slinton
getinfo(p,status)107433331Sdonn private getinfo (p, status)
10759677Slinton register Process p;
10769677Slinton register int status;
10779677Slinton {
10789677Slinton register int i;
107916617Ssam Address addr;
10809677Slinton
10819677Slinton p->signo = (status&0177);
10829677Slinton p->exitval = ((status >> 8)&0377);
10839677Slinton if (p->signo != STOPPED) {
10849677Slinton p->status = FINISHED;
108514757Slinton p->pid = 0;
108616617Ssam p->reg[PROGCTR] = 0;
10879677Slinton } else {
10889677Slinton p->status = p->signo;
10899677Slinton p->signo = p->exitval;
10909677Slinton p->exitval = 0;
109133331Sdonn # ifdef IRIS
109233331Sdonn p->mask = readreg(p, RPS);
109333331Sdonn # else
109433331Sdonn p->sigcode = ptrace(UREAD, p->pid, &((struct user *)0)->u_code, 0);
109533331Sdonn p->mask = readreg(p, PS);
109633331Sdonn # endif
10979677Slinton for (i = 0; i < NREG; i++) {
109833331Sdonn p->reg[i] = readreg(p, rloc[i]);
10999677Slinton p->oreg[i] = p->reg[i];
11009677Slinton }
110133331Sdonn # ifdef mc68000
110233331Sdonn if (p->status == STOPPED and p->signo == SIGTRAP and
110333331Sdonn p->reg[PROGCTR] > CODESTART
110433331Sdonn ) {
110533331Sdonn p->reg[PROGCTR] -= 2;
110633331Sdonn }
110733331Sdonn # endif
110811768Slinton savetty(stdout, &(p->ttyinfo));
110916617Ssam addr = (Address) &(((struct user *) 0)->u_signal[p->signo]);
111018230Slinton p->sigstatus = (Address) ptrace(UREAD, p->pid, addr, 0);
11119677Slinton }
11129677Slinton }
11139677Slinton
11149677Slinton /*
11159677Slinton * Set process's user area information from given process structure.
11169677Slinton */
11179677Slinton
setinfo(p,signo)111833331Sdonn private setinfo (p, signo)
11199677Slinton register Process p;
112011867Slinton int signo;
11219677Slinton {
11229677Slinton register int i;
11239677Slinton register int r;
11249677Slinton
112514757Slinton if (signo == DEFSIG) {
112616617Ssam if (istraced(p) and (p->sigstatus == 0 or p->sigstatus == 1)) {
112714757Slinton p->signo = 0;
112814757Slinton }
112914757Slinton } else {
113011867Slinton p->signo = signo;
11319677Slinton }
11329677Slinton for (i = 0; i < NREG; i++) {
11339677Slinton if ((r = p->reg[i]) != p->oreg[i]) {
113433331Sdonn writereg(p, rloc[i], r);
11359677Slinton }
11369677Slinton }
113711768Slinton restoretty(stdout, &(p->ttyinfo));
11389677Slinton }
11399677Slinton
11409677Slinton /*
114116617Ssam * Return the address associated with the current signal.
114216617Ssam * (Plus two since the address points to the beginning of a procedure).
114316617Ssam */
114416617Ssam
usignal(p)114516617Ssam public Address usignal (p)
114616617Ssam Process p;
114716617Ssam {
114816617Ssam Address r;
114916617Ssam
115016617Ssam r = p->sigstatus;
115116617Ssam if (r != 0 and r != 1) {
115233331Sdonn r += FUNCOFFSET;
115316617Ssam }
115416617Ssam return r;
115516617Ssam }
115616617Ssam
115716617Ssam /*
11589677Slinton * Structure for reading and writing by words, but dealing with bytes.
11599677Slinton */
11609677Slinton
11619677Slinton typedef union {
11629677Slinton Word pword;
11639677Slinton Byte pbyte[sizeof(Word)];
11649677Slinton } Pword;
11659677Slinton
11669677Slinton /*
11679677Slinton * Read (write) from (to) the process' address space.
11689677Slinton * We must deal with ptrace's inability to look anywhere other
11699677Slinton * than at a word boundary.
11709677Slinton */
11719677Slinton
11729677Slinton private Word fetch();
11739677Slinton private store();
11749677Slinton
pio(p,op,seg,buff,addr,nbytes)11759677Slinton private pio(p, op, seg, buff, addr, nbytes)
11769677Slinton Process p;
11779677Slinton PioOp op;
11789677Slinton PioSeg seg;
11799677Slinton char *buff;
11809677Slinton Address addr;
11819677Slinton int nbytes;
11829677Slinton {
11839677Slinton register int i;
11849677Slinton register Address newaddr;
11859677Slinton register char *cp;
11869677Slinton char *bufend;
11879677Slinton Pword w;
11889677Slinton Address wordaddr;
11899677Slinton int byteoff;
11909677Slinton
11919677Slinton if (p->status != STOPPED) {
11929677Slinton error("program is not active");
11939677Slinton }
11949677Slinton cp = buff;
11959677Slinton newaddr = addr;
11969677Slinton wordaddr = (newaddr&WMASK);
11979677Slinton if (wordaddr != newaddr) {
11989677Slinton w.pword = fetch(p, seg, wordaddr);
11999677Slinton for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) {
12009677Slinton if (op == PREAD) {
12019677Slinton *cp++ = w.pbyte[i];
12029677Slinton } else {
12039677Slinton w.pbyte[i] = *cp++;
12049677Slinton }
12059677Slinton nbytes--;
12069677Slinton }
12079677Slinton if (op == PWRITE) {
12089677Slinton store(p, seg, wordaddr, w.pword);
12099677Slinton }
12109677Slinton newaddr = wordaddr + sizeof(Word);
12119677Slinton }
12129677Slinton byteoff = (nbytes&(~WMASK));
12139677Slinton nbytes -= byteoff;
12149677Slinton bufend = cp + nbytes;
121526333Ssam #ifdef tahoe
121626333Ssam if (((int)cp)&WMASK) {
121726333Ssam /*
121826333Ssam * Must copy a byte at a time, buffer not word addressable.
121926333Ssam */
122026333Ssam while (cp < bufend) {
122126333Ssam if (op == PREAD) {
122226333Ssam w.pword = fetch(p, seg, newaddr);
122326333Ssam for (i = 0; i < sizeof(Word); i++)
122426333Ssam *cp++ = w.pbyte[i];
122526333Ssam } else {
122626333Ssam for (i = 0; i < sizeof(Word); i++)
122726333Ssam w.pbyte[i] = *cp++;
122826333Ssam store(p, seg, newaddr, w.pword);
122926333Ssam }
123026333Ssam newaddr += sizeof(Word);
123126333Ssam }
123226333Ssam } else {
123326333Ssam /*
123426333Ssam * Buffer, word aligned, act normally...
123526333Ssam */
123626333Ssam #endif
12379677Slinton while (cp < bufend) {
12389677Slinton if (op == PREAD) {
12399677Slinton *((Word *) cp) = fetch(p, seg, newaddr);
12409677Slinton } else {
12419677Slinton store(p, seg, newaddr, *((Word *) cp));
12429677Slinton }
12439677Slinton cp += sizeof(Word);
12449677Slinton newaddr += sizeof(Word);
12459677Slinton }
124626333Ssam #ifdef tahoe
124726333Ssam }
124826333Ssam #endif
12499677Slinton if (byteoff > 0) {
12509677Slinton w.pword = fetch(p, seg, newaddr);
12519677Slinton for (i = 0; i < byteoff; i++) {
12529677Slinton if (op == PREAD) {
12539677Slinton *cp++ = w.pbyte[i];
12549677Slinton } else {
12559677Slinton w.pbyte[i] = *cp++;
12569677Slinton }
12579677Slinton }
12589677Slinton if (op == PWRITE) {
12599677Slinton store(p, seg, newaddr, w.pword);
12609677Slinton }
12619677Slinton }
12629677Slinton }
12639677Slinton
12649677Slinton /*
12659677Slinton * Get a word from a process at the given address.
12669677Slinton * The address is assumed to be on a word boundary.
12679677Slinton *
12689677Slinton * A simple cache scheme is used to avoid redundant ptrace calls
12699677Slinton * to the instruction space since it is assumed to be pure.
12709677Slinton *
12719677Slinton * It is necessary to use a write-through scheme so that
12729677Slinton * breakpoints right next to each other don't interfere.
12739677Slinton */
12749677Slinton
12759677Slinton private Integer nfetchs, nreads, nwrites;
12769677Slinton
fetch(p,seg,addr)12779677Slinton private Word fetch(p, seg, addr)
12789677Slinton Process p;
12799677Slinton PioSeg seg;
12809677Slinton register int addr;
12819677Slinton {
12829677Slinton register CacheWord *wp;
12839677Slinton register Word w;
12849677Slinton
12859677Slinton switch (seg) {
12869677Slinton case TEXTSEG:
12879677Slinton ++nfetchs;
12889677Slinton wp = &p->word[cachehash(addr)];
12899677Slinton if (addr == 0 or wp->addr != addr) {
12909677Slinton ++nreads;
129118230Slinton w = ptrace(IREAD, p->pid, addr, 0);
12929677Slinton wp->addr = addr;
12939677Slinton wp->val = w;
12949677Slinton } else {
12959677Slinton w = wp->val;
12969677Slinton }
12979677Slinton break;
12989677Slinton
12999677Slinton case DATASEG:
130018230Slinton w = ptrace(DREAD, p->pid, addr, 0);
13019677Slinton break;
13029677Slinton
13039677Slinton default:
13049677Slinton panic("fetch: bad seg %d", seg);
13059677Slinton /* NOTREACHED */
13069677Slinton }
13079677Slinton return w;
13089677Slinton }
13099677Slinton
13109677Slinton /*
13119677Slinton * Put a word into the process' address space at the given address.
13129677Slinton * The address is assumed to be on a word boundary.
13139677Slinton */
13149677Slinton
store(p,seg,addr,data)13159677Slinton private store(p, seg, addr, data)
13169677Slinton Process p;
13179677Slinton PioSeg seg;
13189677Slinton int addr;
13199677Slinton Word data;
13209677Slinton {
13219677Slinton register CacheWord *wp;
13229677Slinton
13239677Slinton switch (seg) {
13249677Slinton case TEXTSEG:
13259677Slinton ++nwrites;
13269677Slinton wp = &p->word[cachehash(addr)];
13279677Slinton wp->addr = addr;
13289677Slinton wp->val = data;
132918230Slinton ptrace(IWRITE, p->pid, addr, data);
13309677Slinton break;
13319677Slinton
13329677Slinton case DATASEG:
133318230Slinton ptrace(DWRITE, p->pid, addr, data);
13349677Slinton break;
13359677Slinton
13369677Slinton default:
13379677Slinton panic("store: bad seg %d", seg);
13389677Slinton /* NOTREACHED */
13399677Slinton }
13409677Slinton }
13419677Slinton
134218230Slinton /*
134318230Slinton * Flush the instruction cache associated with a process.
134418230Slinton */
134518230Slinton
cacheflush(p)134618230Slinton private cacheflush (p)
134718230Slinton Process p;
134818230Slinton {
134918230Slinton bzero(p->word, sizeof(p->word));
135018230Slinton }
135118230Slinton
printptraceinfo()13529677Slinton public printptraceinfo()
13539677Slinton {
13549677Slinton printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites);
13559677Slinton }
13569677Slinton
13579677Slinton /*
135816617Ssam * Redirect input.
135916617Ssam * Assuming this is called from a child, we should be careful to avoid
136016617Ssam * (possibly) shared standard I/O buffers.
13619677Slinton */
13629677Slinton
infrom(filename)136316617Ssam private infrom (filename)
136416617Ssam String filename;
136516617Ssam {
136616617Ssam Fileid in;
136716617Ssam
136816617Ssam in = open(filename, 0);
136916617Ssam if (in == -1) {
137016617Ssam write(2, "can't read ", 11);
137116617Ssam write(2, filename, strlen(filename));
137216617Ssam write(2, "\n", 1);
137316617Ssam _exit(1);
137416617Ssam }
137516617Ssam fswap(0, in);
137616617Ssam }
137716617Ssam
137816617Ssam /*
137916617Ssam * Redirect standard output.
138016617Ssam * Same assumptions as for "infrom" above.
138116617Ssam */
138216617Ssam
outto(filename)138316617Ssam private outto (filename)
138416617Ssam String filename;
138516617Ssam {
138616617Ssam Fileid out;
138716617Ssam
138816617Ssam out = creat(filename, 0666);
138916617Ssam if (out == -1) {
139016617Ssam write(2, "can't write ", 12);
139116617Ssam write(2, filename, strlen(filename));
139216617Ssam write(2, "\n", 1);
139316617Ssam _exit(1);
139416617Ssam }
139516617Ssam fswap(1, out);
139616617Ssam }
139716617Ssam
139816617Ssam /*
139916617Ssam * Swap file numbers, useful for redirecting standard input or output.
140016617Ssam */
140116617Ssam
fswap(oldfd,newfd)14029677Slinton private fswap(oldfd, newfd)
140316617Ssam Fileid oldfd;
140416617Ssam Fileid newfd;
14059677Slinton {
14069677Slinton if (oldfd != newfd) {
14079677Slinton close(oldfd);
14089677Slinton dup(newfd);
14099677Slinton close(newfd);
14109677Slinton }
14119677Slinton }
141216928Ssam
141316928Ssam /*
141418230Slinton * Signal name manipulation.
141516928Ssam */
141618230Slinton
141718230Slinton private String signames[NSIG] = {
141818230Slinton 0,
141918230Slinton "HUP", "INT", "QUIT", "ILL", "TRAP",
142018230Slinton "IOT", "EMT", "FPE", "KILL", "BUS",
142118230Slinton "SEGV", "SYS", "PIPE", "ALRM", "TERM",
142218230Slinton 0, "STOP", "TSTP", "CONT", "CHLD",
142318230Slinton "TTIN", "TTOU", "TINT", "XCPU", "XFSZ",
142426333Ssam "VTALRM", "PROF", "WINCH", "USR1", "USR2"
142516928Ssam };
142616928Ssam
142716928Ssam /*
142818230Slinton * Get the signal number associated with a given name.
142918230Slinton * The name is first translated to upper case if necessary.
143016928Ssam */
143118230Slinton
siglookup(s)143218230Slinton public integer siglookup (s)
143316928Ssam String s;
143416928Ssam {
143518230Slinton register char *p, *q;
143618230Slinton char buf[100];
143718230Slinton integer i;
143816928Ssam
143918230Slinton p = s;
144018230Slinton q = buf;
144118230Slinton while (*p != '\0') {
144218230Slinton if (*p >= 'a' and *p <= 'z') {
144318230Slinton *q = (*p - 'a') + 'A';
144418230Slinton } else {
144518230Slinton *q = *p;
144618230Slinton }
144718230Slinton ++p;
144818230Slinton ++q;
144918230Slinton }
145018230Slinton *q = '\0';
145118230Slinton p = buf;
145218230Slinton if (buf[0] == 'S' and buf[1] == 'I' and buf[2] == 'G') {
145318230Slinton p += 3;
145418230Slinton }
145518230Slinton i = 1;
145618230Slinton for (;;) {
145718230Slinton if (i >= sizeof(signames) div sizeof(signames[0])) {
145818230Slinton error("signal \"%s\" unknown", s);
145918230Slinton i = 0;
146018230Slinton break;
146118230Slinton }
146218230Slinton if (signames[i] != nil and streq(signames[i], p)) {
146318230Slinton break;
146418230Slinton }
146518230Slinton ++i;
146618230Slinton }
146718230Slinton return i;
146816928Ssam }
146916928Ssam
147016928Ssam /*
147118230Slinton * Print all signals being ignored by the debugger.
147218230Slinton * These signals are auotmatically
147316928Ssam * passed on to the debugged process.
147416928Ssam */
147518230Slinton
printsigsignored(p)147618230Slinton public printsigsignored (p)
147716931Ssam Process p;
147816928Ssam {
147916931Ssam printsigs(~p->sigset);
148016928Ssam }
148116928Ssam
148216928Ssam /*
148316928Ssam * Print all signals being intercepted by
148416928Ssam * the debugger for the specified process.
148516928Ssam */
148618230Slinton
printsigscaught(p)148716931Ssam public printsigscaught(p)
148816931Ssam Process p;
148916928Ssam {
149016931Ssam printsigs(p->sigset);
149116931Ssam }
149216931Ssam
printsigs(set)149318230Slinton private printsigs (set)
149418230Slinton integer set;
149516931Ssam {
149618230Slinton integer s;
149718230Slinton char separator[2];
149816931Ssam
149918230Slinton separator[0] = '\0';
150018230Slinton for (s = 1; s < sizeof(signames) div sizeof(signames[0]); s++) {
150118230Slinton if (set & setrep(s)) {
150218230Slinton if (signames[s] != nil) {
150318230Slinton printf("%s%s", separator, signames[s]);
150418230Slinton separator[0] = ' ';
150518230Slinton separator[1] = '\0';
150618230Slinton }
150716928Ssam }
150818230Slinton }
150918230Slinton if (separator[0] == ' ') {
151016931Ssam putchar('\n');
151116931Ssam }
151216928Ssam }
1513