xref: /csrg-svn/old/dbx/process.c (revision 33331)
121620Sdist /*
221620Sdist  * Copyright (c) 1983 Regents of the University of California.
321620Sdist  * All rights reserved.  The Berkeley software License Agreement
421620Sdist  * specifies the terms and conditions for redistribution.
521620Sdist  */
69677Slinton 
721620Sdist #ifndef lint
8*33331Sdonn static char sccsid[] = "@(#)process.c	5.3 (Berkeley) 01/12/88";
921620Sdist #endif not lint
109677Slinton 
11*33331Sdonn static char rcsid[] = "$Header: process.c,v 1.4 88/01/10 00:49:31 donn Exp $";
1218230Slinton 
139677Slinton /*
149677Slinton  * Process management.
159677Slinton  *
169677Slinton  * This module contains the routines to manage the execution and
179677Slinton  * tracing of the debuggee process.
189677Slinton  */
199677Slinton 
209677Slinton #include "defs.h"
219677Slinton #include "process.h"
229677Slinton #include "machine.h"
239677Slinton #include "events.h"
249677Slinton #include "tree.h"
2514757Slinton #include "eval.h"
269677Slinton #include "operators.h"
279677Slinton #include "source.h"
289677Slinton #include "object.h"
299677Slinton #include "mappings.h"
309677Slinton #include "main.h"
319677Slinton #include "coredump.h"
329677Slinton #include <signal.h>
339677Slinton #include <errno.h>
349677Slinton #include <sys/stat.h>
359677Slinton 
369677Slinton #ifndef public
379677Slinton 
389677Slinton typedef struct Process *Process;
399677Slinton 
409677Slinton Process process;
419677Slinton 
4214757Slinton #define DEFSIG -1
4314757Slinton 
449677Slinton #include "machine.h"
459677Slinton 
469677Slinton #endif
479677Slinton 
489677Slinton #define NOTSTARTED 1
499677Slinton #define STOPPED 0177
509677Slinton #define FINISHED 0
519677Slinton 
529677Slinton /*
5316617Ssam  * A cache of the instruction segment is kept to reduce the number
5416617Ssam  * of system calls.  Might be better just to read the entire
5516617Ssam  * code space into memory.
569677Slinton  */
579677Slinton 
58*33331Sdonn #define CACHESIZE 1003
599677Slinton 
609677Slinton typedef struct {
619677Slinton     Word addr;
629677Slinton     Word val;
639677Slinton } CacheWord;
649677Slinton 
659677Slinton /*
669677Slinton  * This structure holds the information we need from the user structure.
679677Slinton  */
689677Slinton 
699677Slinton struct Process {
709677Slinton     int pid;			/* process being traced */
7111768Slinton     int mask;			/* process status word */
7211768Slinton     Word reg[NREG];		/* process' registers */
739677Slinton     Word oreg[NREG];		/* registers when process last stopped */
749677Slinton     short status;		/* either STOPPED or FINISHED */
759677Slinton     short signo;		/* signal that stopped process */
7618230Slinton     short sigcode;		/* extra signal information */
779677Slinton     int exitval;		/* return value from exit() */
789677Slinton     long sigset;		/* bit array of traced signals */
79*33331Sdonn     CacheWord word[CACHESIZE];	/* text segment cache */
8011768Slinton     Ttyinfo ttyinfo;		/* process' terminal characteristics */
8116617Ssam     Address sigstatus;		/* process' handler for current signal */
829677Slinton };
839677Slinton 
849677Slinton /*
859677Slinton  * These definitions are for the arguments to "pio".
869677Slinton  */
879677Slinton 
889677Slinton typedef enum { PREAD, PWRITE } PioOp;
899677Slinton typedef enum { TEXTSEG, DATASEG } PioSeg;
909677Slinton 
919677Slinton private struct Process pbuf;
929677Slinton 
9318230Slinton #define MAXNCMDARGS 1000         /* maximum number of arguments to RUN */
949677Slinton 
9514395Slinton extern int errno;
9614395Slinton 
979677Slinton private Boolean just_started;
989677Slinton private int argc;
999677Slinton private String argv[MAXNCMDARGS];
1009677Slinton private String infile, outfile;
1019677Slinton 
1029677Slinton /*
1039677Slinton  * Initialize process information.
1049677Slinton  */
1059677Slinton 
1069677Slinton public process_init()
1079677Slinton {
108*33331Sdonn     register integer i;
109*33331Sdonn     char buf[10];
1109677Slinton 
1119677Slinton     process = &pbuf;
1129677Slinton     process->status = (coredump) ? STOPPED : NOTSTARTED;
1139677Slinton     setsigtrace();
114*33331Sdonn #   if vax || tahoe
115*33331Sdonn 	for (i = 0; i < NREG; i++) {
116*33331Sdonn 	    sprintf(buf, "$r%d", i);
117*33331Sdonn 	    defregname(identname(buf, false), i);
118*33331Sdonn 	}
119*33331Sdonn #	ifdef vax
120*33331Sdonn 	    defregname(identname("$ap", true), ARGP);
121*33331Sdonn #	endif
122*33331Sdonn #   else
123*33331Sdonn #       ifdef mc68000
124*33331Sdonn 	    for (i = 0; i < 8; i++) {
125*33331Sdonn 		sprintf(buf, "$d%d", i);
126*33331Sdonn 		defregname(identname(buf, false), i);
127*33331Sdonn 		sprintf(buf, "$a%d", i);
128*33331Sdonn 		defregname(identname(buf, false), i + 8);
129*33331Sdonn 	    }
130*33331Sdonn #       endif
131*33331Sdonn #   endif
1329677Slinton     defregname(identname("$fp", true), FRP);
1339677Slinton     defregname(identname("$sp", true), STKP);
1349677Slinton     defregname(identname("$pc", true), PROGCTR);
1359677Slinton     if (coredump) {
1369677Slinton 	coredump_readin(process->mask, process->reg, process->signo);
13712484Slinton 	pc = process->reg[PROGCTR];
1389677Slinton     }
13912484Slinton     arginit();
1409677Slinton }
1419677Slinton 
1429677Slinton /*
1439677Slinton  * Routines to get at process information from outside this module.
1449677Slinton  */
1459677Slinton 
1469677Slinton public Word reg(n)
1479677Slinton Integer n;
1489677Slinton {
1499677Slinton     register Word w;
1509677Slinton 
1519677Slinton     if (n == NREG) {
1529677Slinton 	w = process->mask;
1539677Slinton     } else {
1549677Slinton 	w = process->reg[n];
1559677Slinton     }
1569677Slinton     return w;
1579677Slinton }
1589677Slinton 
1599677Slinton public setreg(n, w)
1609677Slinton Integer n;
1619677Slinton Word w;
1629677Slinton {
1639677Slinton     process->reg[n] = w;
1649677Slinton }
1659677Slinton 
1669677Slinton /*
1679677Slinton  * Begin execution.
1689677Slinton  *
1699677Slinton  * We set a breakpoint at the end of the code so that the
1709677Slinton  * process data doesn't disappear after the program terminates.
1719677Slinton  */
1729677Slinton 
1739677Slinton private Boolean remade();
1749677Slinton 
1759677Slinton public start(argv, infile, outfile)
1769677Slinton String argv[];
1779677Slinton String infile, outfile;
1789677Slinton {
1799677Slinton     String pargv[4];
1809677Slinton     Node cond;
1819677Slinton 
1829677Slinton     if (coredump) {
1839677Slinton 	coredump = false;
1849677Slinton 	fclose(corefile);
1859677Slinton 	coredump_close();
1869677Slinton     }
1879677Slinton     if (argv == nil) {
1889677Slinton 	argv = pargv;
1899677Slinton 	pargv[0] = objname;
1909677Slinton 	pargv[1] = nil;
1919677Slinton     } else {
1929677Slinton 	argv[argc] = nil;
1939677Slinton     }
19418230Slinton     pstart(process, argv, infile, outfile);
1959677Slinton     if (remade(objname)) {
1969677Slinton 	reinit(argv, infile, outfile);
1979677Slinton     }
1989677Slinton     if (process->status == STOPPED) {
199*33331Sdonn 	pc = CODESTART;
20016617Ssam 	setcurfunc(program);
2019677Slinton 	if (objsize != 0) {
2029677Slinton 	    cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr()));
2039677Slinton 	    event_once(cond, buildcmdlist(build(O_ENDX)));
2049677Slinton 	}
2059677Slinton     }
2069677Slinton }
2079677Slinton 
2089677Slinton /*
2099677Slinton  * Check to see if the object file has changed since the symbolic
2109677Slinton  * information last was read.
2119677Slinton  */
2129677Slinton 
2139677Slinton private time_t modtime;
2149677Slinton 
2159677Slinton private Boolean remade(filename)
2169677Slinton String filename;
2179677Slinton {
2189677Slinton     struct stat s;
2199677Slinton     Boolean b;
2209677Slinton 
2219677Slinton     stat(filename, &s);
2229677Slinton     b = (Boolean) (modtime != 0 and modtime < s.st_mtime);
2239677Slinton     modtime = s.st_mtime;
2249677Slinton     return b;
2259677Slinton }
2269677Slinton 
2279677Slinton /*
2289677Slinton  * Set up what signals we want to trace.
2299677Slinton  */
2309677Slinton 
2319677Slinton private setsigtrace()
2329677Slinton {
2339677Slinton     register Integer i;
2349677Slinton     register Process p;
2359677Slinton 
2369677Slinton     p = process;
2379677Slinton     for (i = 1; i <= NSIG; i++) {
2389677Slinton 	psigtrace(p, i, true);
2399677Slinton     }
2409677Slinton     psigtrace(p, SIGHUP, false);
2419677Slinton     psigtrace(p, SIGKILL, false);
2429677Slinton     psigtrace(p, SIGALRM, false);
243*33331Sdonn #   ifdef SIGTSTP
244*33331Sdonn 	psigtrace(p, SIGTSTP, false);
245*33331Sdonn 	psigtrace(p, SIGCONT, false);
246*33331Sdonn #   endif
2479677Slinton     psigtrace(p, SIGCHLD, false);
24826333Ssam     psigtrace(p, SIGWINCH, false);
2499677Slinton }
2509677Slinton 
2519677Slinton /*
2529677Slinton  * Initialize the argument list.
2539677Slinton  */
2549677Slinton 
2559677Slinton public arginit()
2569677Slinton {
2579677Slinton     infile = nil;
2589677Slinton     outfile = nil;
2599677Slinton     argv[0] = objname;
2609677Slinton     argc = 1;
2619677Slinton }
2629677Slinton 
2639677Slinton /*
2649677Slinton  * Add an argument to the list for the debuggee.
2659677Slinton  */
2669677Slinton 
2679677Slinton public newarg(arg)
2689677Slinton String arg;
2699677Slinton {
2709677Slinton     if (argc >= MAXNCMDARGS) {
2719677Slinton 	error("too many arguments");
2729677Slinton     }
2739677Slinton     argv[argc++] = arg;
2749677Slinton }
2759677Slinton 
2769677Slinton /*
2779677Slinton  * Set the standard input for the debuggee.
2789677Slinton  */
2799677Slinton 
2809677Slinton public inarg(filename)
2819677Slinton String filename;
2829677Slinton {
2839677Slinton     if (infile != nil) {
2849677Slinton 	error("multiple input redirects");
2859677Slinton     }
2869677Slinton     infile = filename;
2879677Slinton }
2889677Slinton 
2899677Slinton /*
2909677Slinton  * Set the standard output for the debuggee.
2919677Slinton  * Probably should check to avoid overwriting an existing file.
2929677Slinton  */
2939677Slinton 
2949677Slinton public outarg(filename)
2959677Slinton String filename;
2969677Slinton {
2979677Slinton     if (outfile != nil) {
2989677Slinton 	error("multiple output redirect");
2999677Slinton     }
3009677Slinton     outfile = filename;
3019677Slinton }
3029677Slinton 
3039677Slinton /*
3049677Slinton  * Start debuggee executing.
3059677Slinton  */
3069677Slinton 
3079677Slinton public run()
3089677Slinton {
3099677Slinton     process->status = STOPPED;
3109677Slinton     fixbps();
3119677Slinton     curline = 0;
3129677Slinton     start(argv, infile, outfile);
3139677Slinton     just_started = true;
3149677Slinton     isstopped = false;
31514757Slinton     cont(0);
3169677Slinton }
3179677Slinton 
3189677Slinton /*
3199677Slinton  * Continue execution wherever we left off.
3209677Slinton  *
3219677Slinton  * Note that this routine never returns.  Eventually bpact() will fail
3229677Slinton  * and we'll call printstatus or step will call it.
3239677Slinton  */
3249677Slinton 
3259677Slinton typedef int Intfunc();
3269677Slinton 
3279677Slinton private Intfunc *dbintr;
3289677Slinton private intr();
3299677Slinton 
33011867Slinton public cont(signo)
33116617Ssam integer signo;
3329677Slinton {
33316617Ssam     integer s;
33416617Ssam 
3359677Slinton     dbintr = signal(SIGINT, intr);
3369677Slinton     if (just_started) {
3379677Slinton 	just_started = false;
3389677Slinton     } else {
3399677Slinton 	if (not isstopped) {
3409677Slinton 	    error("can't continue execution");
3419677Slinton 	}
3429677Slinton 	isstopped = false;
34311867Slinton 	stepover();
3449677Slinton     }
34516617Ssam     s = signo;
3469677Slinton     for (;;) {
3479677Slinton 	if (single_stepping) {
3489677Slinton 	    printnews();
3499677Slinton 	} else {
3509677Slinton 	    setallbps();
35116617Ssam 	    resume(s);
3529677Slinton 	    unsetallbps();
35316617Ssam 	    s = DEFSIG;
35418230Slinton 	    if (not isbperr() or not bpact()) {
3559677Slinton 		printstatus();
3569677Slinton 	    }
3579677Slinton 	}
35811867Slinton 	stepover();
3599677Slinton     }
3609677Slinton     /* NOTREACHED */
3619677Slinton }
3629677Slinton 
3639677Slinton /*
36418230Slinton  * This routine is called if we get an interrupt while "running"
3659677Slinton  * but actually in the debugger.  Could happen, for example, while
3669677Slinton  * processing breakpoints.
3679677Slinton  *
3689677Slinton  * We basically just want to keep going; the assumption is
36918230Slinton  * that when the process resumes it will get the interrupt,
3709677Slinton  * which will then be handled.
3719677Slinton  */
3729677Slinton 
3739677Slinton private intr()
3749677Slinton {
3759677Slinton     signal(SIGINT, intr);
3769677Slinton }
3779677Slinton 
3789677Slinton public fixintr()
3799677Slinton {
3809677Slinton     signal(SIGINT, dbintr);
3819677Slinton }
3829677Slinton 
3839677Slinton /*
3849677Slinton  * Resume execution.
3859677Slinton  */
3869677Slinton 
38711867Slinton public resume(signo)
38811867Slinton int signo;
3899677Slinton {
3909677Slinton     register Process p;
3919677Slinton 
3929677Slinton     p = process;
39311867Slinton     pcont(p, signo);
3949677Slinton     pc = process->reg[PROGCTR];
39511832Slinton     if (p->status != STOPPED) {
39611867Slinton 	if (p->signo != 0) {
39711867Slinton 	    error("program terminated by signal %d", p->signo);
39814757Slinton 	} else if (not runfirst) {
39918230Slinton 	    if (p->exitval == 0) {
40018230Slinton 		error("program exited");
40118230Slinton 	    } else {
40218230Slinton 		error("program exited with code %d", p->exitval);
40318230Slinton 	    }
40411867Slinton 	}
40511832Slinton     }
4069677Slinton }
4079677Slinton 
4089677Slinton /*
4099677Slinton  * Continue execution up to the next source line.
4109677Slinton  *
4119677Slinton  * There are two ways to define the next source line depending on what
4129677Slinton  * is desired when a procedure or function call is encountered.  Step
4139677Slinton  * stops at the beginning of the procedure or call; next skips over it.
4149677Slinton  */
4159677Slinton 
4169677Slinton /*
4179677Slinton  * Stepc is what is called when the step command is given.
4189677Slinton  * It has to play with the "isstopped" information.
4199677Slinton  */
4209677Slinton 
4219677Slinton public stepc()
4229677Slinton {
4239677Slinton     if (not isstopped) {
4249677Slinton 	error("can't continue execution");
4259677Slinton     }
4269677Slinton     isstopped = false;
4279677Slinton     dostep(false);
4289677Slinton     isstopped = true;
4299677Slinton }
4309677Slinton 
4319677Slinton public next()
4329677Slinton {
43316617Ssam     Address oldfrp, newfrp;
43416617Ssam 
4359677Slinton     if (not isstopped) {
4369677Slinton 	error("can't continue execution");
4379677Slinton     }
4389677Slinton     isstopped = false;
43916617Ssam     oldfrp = reg(FRP);
44016617Ssam     do {
44116617Ssam 	dostep(true);
44216617Ssam 	pc = reg(PROGCTR);
44316617Ssam 	newfrp = reg(FRP);
44416617Ssam     } while (newfrp < oldfrp and newfrp != 0);
4459677Slinton     isstopped = true;
4469677Slinton }
4479677Slinton 
44811867Slinton /*
44916617Ssam  * Continue execution until the current function returns, or,
45016617Ssam  * if the given argument is non-nil, until execution returns to
45116617Ssam  * somewhere within the given function.
45216617Ssam  */
45316617Ssam 
45416617Ssam public rtnfunc (f)
45516617Ssam Symbol f;
45616617Ssam {
45716617Ssam     Address addr;
45816617Ssam     Symbol t;
45916617Ssam 
46016617Ssam     if (not isstopped) {
46116617Ssam 	error("can't continue execution");
46216617Ssam     } else if (f != nil and not isactive(f)) {
46316617Ssam 	error("%s is not active", symname(f));
46416617Ssam     } else {
46516617Ssam 	addr = return_addr();
46616617Ssam 	if (addr == nil) {
46716617Ssam 	    error("no place to return to");
46816617Ssam 	} else {
46916617Ssam 	    isstopped = false;
47016617Ssam 	    contto(addr);
47116617Ssam 	    if (f != nil) {
47216617Ssam 		for (;;) {
47316617Ssam 		    t = whatblock(pc);
47416617Ssam 		    addr = return_addr();
47516617Ssam 		if (t == f or addr == nil) break;
47616617Ssam 		    contto(addr);
47716617Ssam 		}
47816617Ssam 	    }
47918230Slinton 	    if (not bpact()) {
48016617Ssam 		isstopped = true;
48116617Ssam 		printstatus();
48216617Ssam 	    }
48316617Ssam 	}
48416617Ssam     }
48516617Ssam }
48616617Ssam 
48716617Ssam /*
48811867Slinton  * Single-step over the current machine instruction.
48911867Slinton  *
49011867Slinton  * If we're single-stepping by source line we want to step to the
49111867Slinton  * next source line.  Otherwise we're going to continue so there's
49211867Slinton  * no reason to do all the work necessary to single-step to the next
49311867Slinton  * source line.
49411867Slinton  */
49511867Slinton 
49616617Ssam public stepover()
4979677Slinton {
49811867Slinton     Boolean b;
49911867Slinton 
50016617Ssam     if (traceexec) {
50116617Ssam 	printf("!! stepping over 0x%x\n", process->reg[PROGCTR]);
50216617Ssam     }
50311867Slinton     if (single_stepping) {
50411867Slinton 	dostep(false);
50511867Slinton     } else {
50611867Slinton 	b = inst_tracing;
50711867Slinton 	inst_tracing = true;
50811867Slinton 	dostep(false);
50911867Slinton 	inst_tracing = b;
51011867Slinton     }
51116617Ssam     if (traceexec) {
51216617Ssam 	printf("!! stepped over to 0x%x\n", process->reg[PROGCTR]);
51316617Ssam     }
5149677Slinton }
5159677Slinton 
5169677Slinton /*
51718230Slinton  * Resume execution up to the given address.  We can either ignore
51818230Slinton  * breakpoints (stepto) or catch them (contto).
5199677Slinton  */
5209677Slinton 
5219677Slinton public stepto(addr)
5229677Slinton Address addr;
5239677Slinton {
52416617Ssam     xto(addr, false);
52516617Ssam }
52616617Ssam 
52716617Ssam private contto (addr)
52816617Ssam Address addr;
52916617Ssam {
53016617Ssam     xto(addr, true);
53116617Ssam }
53216617Ssam 
53316617Ssam private xto (addr, catchbps)
53416617Ssam Address addr;
53516617Ssam boolean catchbps;
53616617Ssam {
53716617Ssam     Address curpc;
53816617Ssam 
53916617Ssam     if (catchbps) {
54016617Ssam 	stepover();
5419677Slinton     }
54216617Ssam     curpc = process->reg[PROGCTR];
54316617Ssam     if (addr != curpc) {
54416617Ssam 	if (traceexec) {
54516617Ssam 	    printf("!! stepping from 0x%x to 0x%x\n", curpc, addr);
54616617Ssam 	}
54716617Ssam 	if (catchbps) {
54816617Ssam 	    setallbps();
54916617Ssam 	}
55016617Ssam 	setbp(addr);
55116617Ssam 	resume(DEFSIG);
55216617Ssam 	unsetbp(addr);
55316617Ssam 	if (catchbps) {
55416617Ssam 	    unsetallbps();
55516617Ssam 	}
55616617Ssam 	if (not isbperr()) {
55716617Ssam 	    printstatus();
55816617Ssam 	}
55916617Ssam     }
5609677Slinton }
5619677Slinton 
5629677Slinton /*
5639677Slinton  * Print the status of the process.
5649677Slinton  * This routine does not return.
5659677Slinton  */
5669677Slinton 
567*33331Sdonn public printstatus ()
5689677Slinton {
56914395Slinton     int status;
57014395Slinton 
5719843Slinton     if (process->status == FINISHED) {
5729843Slinton 	exit(0);
5739843Slinton     } else {
574*33331Sdonn 	if (runfirst) {
575*33331Sdonn 	    fprintf(stderr, "\nEntering debugger ...\n");
576*33331Sdonn 	    printheading();
577*33331Sdonn 	    init();
578*33331Sdonn 	}
57916617Ssam 	setcurfunc(whatblock(pc));
5809677Slinton 	getsrcpos();
5819843Slinton 	if (process->signo == SIGINT) {
5829843Slinton 	    isstopped = true;
5839843Slinton 	    printerror();
5849843Slinton 	} else if (isbperr() and isstopped) {
5859843Slinton 	    printf("stopped ");
58611172Slinton 	    printloc();
58711172Slinton 	    putchar('\n');
5889843Slinton 	    if (curline > 0) {
5899843Slinton 		printlines(curline, curline);
5909843Slinton 	    } else {
5919843Slinton 		printinst(pc, pc);
5929843Slinton 	    }
5939843Slinton 	    erecover();
5949677Slinton 	} else {
5959843Slinton 	    fixintr();
5969677Slinton 	    isstopped = true;
5979677Slinton 	    printerror();
5989677Slinton 	}
5999677Slinton     }
6009677Slinton }
6019677Slinton 
6029677Slinton /*
60311172Slinton  * Print out the current location in the debuggee.
60411172Slinton  */
60511172Slinton 
60611172Slinton public printloc()
60711172Slinton {
60811172Slinton     printf("in ");
60911172Slinton     printname(stdout, curfunc);
61011172Slinton     putchar(' ');
61114757Slinton     if (curline > 0 and not useInstLoc) {
61211172Slinton 	printsrcpos();
61311172Slinton     } else {
61414757Slinton 	useInstLoc = false;
61514757Slinton 	curline = 0;
61611172Slinton 	printf("at 0x%x", pc);
61711172Slinton     }
61811172Slinton }
61911172Slinton 
62011172Slinton /*
6219677Slinton  * Some functions for testing the state of the process.
6229677Slinton  */
6239677Slinton 
6249677Slinton public Boolean notstarted(p)
6259677Slinton Process p;
6269677Slinton {
6279677Slinton     return (Boolean) (p->status == NOTSTARTED);
6289677Slinton }
6299677Slinton 
6309677Slinton public Boolean isfinished(p)
6319677Slinton Process p;
6329677Slinton {
6339677Slinton     return (Boolean) (p->status == FINISHED);
6349677Slinton }
6359677Slinton 
6369677Slinton /*
63718230Slinton  * Predicate to test if the reason the process stopped was because
63818230Slinton  * of a breakpoint.  If so, as a side effect clear the local copy of
63918230Slinton  * signal handler associated with process.  We must do this so as to
64018230Slinton  * not confuse future stepping or continuing by possibly concluding
64118230Slinton  * the process should continue with a SIGTRAP handler.
6429677Slinton  */
6439677Slinton 
64418230Slinton public boolean isbperr()
64518230Slinton {
64618230Slinton     Process p;
64718230Slinton     boolean b;
64818230Slinton 
64918230Slinton     p = process;
65018230Slinton     if (p->status == STOPPED and p->signo == SIGTRAP) {
65118230Slinton 	b = true;
65218230Slinton 	p->sigstatus = 0;
65318230Slinton     } else {
65418230Slinton 	b = false;
65518230Slinton     }
65618230Slinton     return b;
65718230Slinton }
65818230Slinton 
65918230Slinton /*
66018230Slinton  * Return the signal number that stopped the process.
66118230Slinton  */
66218230Slinton 
66318230Slinton public integer errnum (p)
6649677Slinton Process p;
6659677Slinton {
6669677Slinton     return p->signo;
6679677Slinton }
6689677Slinton 
66918230Slinton /*
67018230Slinton  * Return the signal code associated with the signal.
67118230Slinton  */
67218230Slinton 
67318230Slinton public integer errcode (p)
67416931Ssam Process p;
67516931Ssam {
67616931Ssam     return p->sigcode;
67716931Ssam }
67816931Ssam 
6799677Slinton /*
6809677Slinton  * Return the termination code of the process.
6819677Slinton  */
6829677Slinton 
68318230Slinton public integer exitcode (p)
6849677Slinton Process p;
6859677Slinton {
6869677Slinton     return p->exitval;
6879677Slinton }
6889677Slinton 
6899677Slinton /*
6909677Slinton  * These routines are used to access the debuggee process from
6919677Slinton  * outside this module.
6929677Slinton  *
6939677Slinton  * They invoke "pio" which eventually leads to a call to "ptrace".
69414757Slinton  * The system generates an I/O error when a ptrace fails.  During reads
69514757Slinton  * these are ignored, during writes they are reported as an error, and
69614757Slinton  * for anything else they cause a fatal error.
6979677Slinton  */
6989677Slinton 
6999677Slinton extern Intfunc *onsyserr();
7009677Slinton 
7019677Slinton private badaddr;
70214757Slinton private read_err(), write_err();
7039677Slinton 
7049677Slinton /*
7059677Slinton  * Read from the process' instruction area.
7069677Slinton  */
7079677Slinton 
7089677Slinton public iread(buff, addr, nbytes)
7099677Slinton char *buff;
7109677Slinton Address addr;
7119677Slinton int nbytes;
7129677Slinton {
7139677Slinton     Intfunc *f;
7149677Slinton 
71514757Slinton     f = onsyserr(EIO, read_err);
7169677Slinton     badaddr = addr;
7179677Slinton     if (coredump) {
7189677Slinton 	coredump_readtext(buff, addr, nbytes);
7199677Slinton     } else {
7209677Slinton 	pio(process, PREAD, TEXTSEG, buff, addr, nbytes);
7219677Slinton     }
7229677Slinton     onsyserr(EIO, f);
7239677Slinton }
7249677Slinton 
7259677Slinton /*
7269677Slinton  * Write to the process' instruction area, usually in order to set
7279677Slinton  * or unset a breakpoint.
7289677Slinton  */
7299677Slinton 
7309677Slinton public iwrite(buff, addr, nbytes)
7319677Slinton char *buff;
7329677Slinton Address addr;
7339677Slinton int nbytes;
7349677Slinton {
7359677Slinton     Intfunc *f;
7369677Slinton 
7379677Slinton     if (coredump) {
7389677Slinton 	error("no process to write to");
7399677Slinton     }
74014757Slinton     f = onsyserr(EIO, write_err);
7419677Slinton     badaddr = addr;
7429677Slinton     pio(process, PWRITE, TEXTSEG, buff, addr, nbytes);
7439677Slinton     onsyserr(EIO, f);
7449677Slinton }
7459677Slinton 
7469677Slinton /*
7479677Slinton  * Read for the process' data area.
7489677Slinton  */
7499677Slinton 
7509677Slinton public dread(buff, addr, nbytes)
7519677Slinton char *buff;
7529677Slinton Address addr;
7539677Slinton int nbytes;
7549677Slinton {
7559677Slinton     Intfunc *f;
7569677Slinton 
7579677Slinton     badaddr = addr;
7589677Slinton     if (coredump) {
75918230Slinton 	f = onsyserr(EFAULT, read_err);
7609677Slinton 	coredump_readdata(buff, addr, nbytes);
76118230Slinton 	onsyserr(EFAULT, f);
7629677Slinton     } else {
76318230Slinton 	f = onsyserr(EIO, read_err);
7649677Slinton 	pio(process, PREAD, DATASEG, buff, addr, nbytes);
76518230Slinton 	onsyserr(EIO, f);
7669677Slinton     }
7679677Slinton }
7689677Slinton 
7699677Slinton /*
7709677Slinton  * Write to the process' data area.
7719677Slinton  */
7729677Slinton 
7739677Slinton public dwrite(buff, addr, nbytes)
7749677Slinton char *buff;
7759677Slinton Address addr;
7769677Slinton int nbytes;
7779677Slinton {
7789677Slinton     Intfunc *f;
7799677Slinton 
7809677Slinton     if (coredump) {
7819677Slinton 	error("no process to write to");
7829677Slinton     }
78314757Slinton     f = onsyserr(EIO, write_err);
7849677Slinton     badaddr = addr;
7859677Slinton     pio(process, PWRITE, DATASEG, buff, addr, nbytes);
7869677Slinton     onsyserr(EIO, f);
7879677Slinton }
7889677Slinton 
7899677Slinton /*
79014757Slinton  * Trap for errors in reading or writing to a process.
79114757Slinton  * The current approach is to "ignore" read errors and complain
79214757Slinton  * bitterly about write errors.
7939677Slinton  */
7949677Slinton 
79514757Slinton private read_err()
7969677Slinton {
79711560Slinton     /*
79814757Slinton      * Ignore.
79911560Slinton      */
8009677Slinton }
8019677Slinton 
80214757Slinton private write_err()
80314757Slinton {
80414757Slinton     error("can't write to process (address 0x%x)", badaddr);
80514757Slinton }
80614757Slinton 
8079677Slinton /*
8089677Slinton  * Ptrace interface.
8099677Slinton  */
8109677Slinton 
8119677Slinton #define WMASK           (~(sizeof(Word) - 1))
812*33331Sdonn #define cachehash(addr) ((unsigned) ((addr >> 2) % CACHESIZE))
8139677Slinton 
8149677Slinton #define FIRSTSIG        SIGINT
8159677Slinton #define LASTSIG         SIGQUIT
8169677Slinton #define ischild(pid)    ((pid) == 0)
81718230Slinton #define traceme()       ptrace(0, 0, 0, 0)
8189677Slinton #define setrep(n)       (1 << ((n)-1))
8199677Slinton #define istraced(p)     (p->sigset&setrep(p->signo))
8209677Slinton 
8219677Slinton /*
82218230Slinton  * Ptrace options (specified in first argument).
82318230Slinton  */
82418230Slinton 
82518230Slinton #define UREAD   3       /* read from process's user structure */
82618230Slinton #define UWRITE  6       /* write to process's user structure */
82718230Slinton #define IREAD   1       /* read from process's instruction space */
82818230Slinton #define IWRITE  4       /* write to process's instruction space */
82918230Slinton #define DREAD   2       /* read from process's data space */
83018230Slinton #define DWRITE  5       /* write to process's data space */
83118230Slinton #define CONT    7       /* continue stopped process */
83218230Slinton #define SSTEP   9       /* continue for approximately one instruction */
83318230Slinton #define PKILL   8       /* terminate the process */
83418230Slinton 
835*33331Sdonn #ifdef IRIS
836*33331Sdonn #   define readreg(p, r)	ptrace(10, p->pid, r, 0)
837*33331Sdonn #   define writereg(p, r, v)	ptrace(11, p->pid, r, v)
838*33331Sdonn #else
839*33331Sdonn #   define readreg(p, r)	ptrace(UREAD, p->pid, regloc(r), 0);
840*33331Sdonn #   define writereg(p, r, v)	ptrace(UWRITE, p->pid, regloc(r), v);
841*33331Sdonn #endif
842*33331Sdonn 
84318230Slinton /*
8449677Slinton  * Start up a new process by forking and exec-ing the
8459677Slinton  * given argument list, returning when the process is loaded
8469677Slinton  * and ready to execute.  The PROCESS information (pointed to
8479677Slinton  * by the first argument) is appropriately filled.
8489677Slinton  *
8499677Slinton  * If the given PROCESS structure is associated with an already running
8509677Slinton  * process, we terminate it.
8519677Slinton  */
8529677Slinton 
8539677Slinton /* VARARGS2 */
8549677Slinton private pstart(p, argv, infile, outfile)
8559677Slinton Process p;
8569677Slinton String argv[];
8579677Slinton String infile;
8589677Slinton String outfile;
8599677Slinton {
8609677Slinton     int status;
8619677Slinton 
86216617Ssam     if (p->pid != 0) {
86316617Ssam 	pterm(p);
86418230Slinton 	cacheflush(p);
8659677Slinton     }
86618230Slinton     fflush(stdout);
8679677Slinton     psigtrace(p, SIGTRAP, true);
868*33331Sdonn #   ifdef IRIS
869*33331Sdonn 	p->pid = fork();
870*33331Sdonn #   else
871*33331Sdonn 	p->pid = vfork();
872*33331Sdonn #   endif
87314395Slinton     if (p->pid == -1) {
8749677Slinton 	panic("can't fork");
8759677Slinton     }
8769677Slinton     if (ischild(p->pid)) {
87718230Slinton 	nocatcherrs();
8789677Slinton 	traceme();
8799677Slinton 	if (infile != nil) {
88016617Ssam 	    infrom(infile);
8819677Slinton 	}
8829677Slinton 	if (outfile != nil) {
88316617Ssam 	    outto(outfile);
8849677Slinton 	}
88511832Slinton 	execv(argv[0], argv);
88611172Slinton 	_exit(1);
8879677Slinton     }
8889677Slinton     pwait(p->pid, &status);
8899677Slinton     getinfo(p, status);
8909677Slinton     if (p->status != STOPPED) {
89118230Slinton 	beginerrmsg();
89218230Slinton 	fprintf(stderr, "warning: cannot execute %s\n", argv[0]);
89318230Slinton     } else {
89418230Slinton 	ptraced(p->pid);
8959677Slinton     }
8969677Slinton }
8979677Slinton 
8989677Slinton /*
89916617Ssam  * Terminate a ptrace'd process.
90016617Ssam  */
90116617Ssam 
90216617Ssam public pterm (p)
90316617Ssam Process p;
90416617Ssam {
90516617Ssam     integer status;
90616617Ssam 
90716617Ssam     if (p != nil and p->pid != 0) {
90818230Slinton 	ptrace(PKILL, p->pid, 0, 0);
90916617Ssam 	pwait(p->pid, &status);
91016617Ssam 	unptraced(p->pid);
91116617Ssam     }
91216617Ssam }
91316617Ssam 
91416617Ssam /*
91511867Slinton  * Continue a stopped process.  The first argument points to a Process
91611867Slinton  * structure.  Before the process is restarted it's user area is modified
91711867Slinton  * according to the values in the structure.  When this routine finishes,
9189677Slinton  * the structure has the new values from the process's user area.
9199677Slinton  *
9209677Slinton  * Pcont terminates when the process stops with a signal pending that
9219677Slinton  * is being traced (via psigtrace), or when the process terminates.
9229677Slinton  */
9239677Slinton 
92411867Slinton private pcont(p, signo)
9259677Slinton Process p;
92611867Slinton int signo;
9279677Slinton {
92816617Ssam     int s, status;
9299677Slinton 
9309677Slinton     if (p->pid == 0) {
93118230Slinton 	error("program is not active");
9329677Slinton     }
93316617Ssam     s = signo;
9349677Slinton     do {
93516617Ssam 	setinfo(p, s);
93616617Ssam 	if (traceexec) {
93716617Ssam 	    printf("!! pcont from 0x%x with signal %d (%d)\n",
93816617Ssam 		p->reg[PROGCTR], s, p->signo);
93916617Ssam 	    fflush(stdout);
94016617Ssam 	}
9419677Slinton 	sigs_off();
94218230Slinton 	if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) {
94314395Slinton 	    panic("error %d trying to continue process", errno);
9449677Slinton 	}
9459677Slinton 	pwait(p->pid, &status);
9469677Slinton 	sigs_on();
9479677Slinton 	getinfo(p, status);
94818230Slinton 	if (p->status == STOPPED and traceexec and not istraced(p)) {
94918230Slinton 	    printf("!! ignored signal %d at 0x%x\n",
95018230Slinton 		p->signo, p->reg[PROGCTR]);
95116617Ssam 	    fflush(stdout);
95216617Ssam 	}
95316617Ssam 	s = p->signo;
9549677Slinton     } while (p->status == STOPPED and not istraced(p));
95516617Ssam     if (traceexec) {
95616617Ssam 	printf("!! pcont to 0x%x on signal %d\n", p->reg[PROGCTR], p->signo);
95716617Ssam 	fflush(stdout);
95816617Ssam     }
9599677Slinton }
9609677Slinton 
9619677Slinton /*
9629677Slinton  * Single step as best ptrace can.
9639677Slinton  */
9649677Slinton 
96516617Ssam public pstep(p, signo)
9669677Slinton Process p;
96716617Ssam integer signo;
9689677Slinton {
96918230Slinton     int s, status;
9709677Slinton 
97118230Slinton     s = signo;
97218230Slinton     do {
97318230Slinton 	setinfo(p, s);
97418230Slinton 	if (traceexec) {
97518230Slinton 	    printf("!! pstep from 0x%x with signal %d (%d)\n",
97618230Slinton 		p->reg[PROGCTR], s, p->signo);
97718230Slinton 	    fflush(stdout);
97818230Slinton 	}
97918230Slinton 	sigs_off();
98018230Slinton 	if (ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo) < 0) {
98118230Slinton 	    panic("error %d trying to step process", errno);
98218230Slinton 	}
98318230Slinton 	pwait(p->pid, &status);
98418230Slinton 	sigs_on();
98518230Slinton 	getinfo(p, status);
986*33331Sdonn #	if mc68000 || m68000
987*33331Sdonn 	    if (p->status == STOPPED and p->signo == SIGTRAP) {
988*33331Sdonn 		p->reg[PROGCTR] += 2;
989*33331Sdonn 	    }
990*33331Sdonn #	endif
99118230Slinton 	if (p->status == STOPPED and traceexec and not istraced(p)) {
99218230Slinton 	    printf("!! pstep ignored signal %d at 0x%x\n",
99318230Slinton 		p->signo, p->reg[PROGCTR]);
99418230Slinton 	    fflush(stdout);
99518230Slinton 	}
99618230Slinton 	s = p->signo;
99718230Slinton     } while (p->status == STOPPED and not istraced(p));
99816617Ssam     if (traceexec) {
99918230Slinton 	printf("!! pstep to 0x%x on signal %d\n",
100018230Slinton 	    p->reg[PROGCTR], p->signo);
100116617Ssam 	fflush(stdout);
100216617Ssam     }
100316617Ssam     if (p->status != STOPPED) {
100418230Slinton 	if (p->exitval == 0) {
100518230Slinton 	    error("program exited\n");
100618230Slinton 	} else {
100718230Slinton 	    error("program exited with code %d\n", p->exitval);
100818230Slinton 	}
100916617Ssam     }
10109677Slinton }
10119677Slinton 
10129677Slinton /*
10139677Slinton  * Return from execution when the given signal is pending.
10149677Slinton  */
10159677Slinton 
10169677Slinton public psigtrace(p, sig, sw)
10179677Slinton Process p;
10189677Slinton int sig;
10199677Slinton Boolean sw;
10209677Slinton {
10219677Slinton     if (sw) {
10229677Slinton 	p->sigset |= setrep(sig);
10239677Slinton     } else {
10249677Slinton 	p->sigset &= ~setrep(sig);
10259677Slinton     }
10269677Slinton }
10279677Slinton 
10289677Slinton /*
10299677Slinton  * Don't catch any signals.
10309677Slinton  * Particularly useful when letting a process finish uninhibited.
10319677Slinton  */
10329677Slinton 
10339677Slinton public unsetsigtraces(p)
10349677Slinton Process p;
10359677Slinton {
10369677Slinton     p->sigset = 0;
10379677Slinton }
10389677Slinton 
10399677Slinton /*
10409677Slinton  * Turn off attention to signals not being caught.
10419677Slinton  */
10429677Slinton 
10439677Slinton private Intfunc *sigfunc[NSIG];
10449677Slinton 
10459677Slinton private sigs_off()
10469677Slinton {
10479677Slinton     register int i;
10489677Slinton 
10499677Slinton     for (i = FIRSTSIG; i < LASTSIG; i++) {
10509677Slinton 	if (i != SIGKILL) {
10519677Slinton 	    sigfunc[i] = signal(i, SIG_IGN);
10529677Slinton 	}
10539677Slinton     }
10549677Slinton }
10559677Slinton 
10569677Slinton /*
10579677Slinton  * Turn back on attention to signals.
10589677Slinton  */
10599677Slinton 
10609677Slinton private sigs_on()
10619677Slinton {
10629677Slinton     register int i;
10639677Slinton 
10649677Slinton     for (i = FIRSTSIG; i < LASTSIG; i++) {
10659677Slinton 	if (i != SIGKILL) {
10669677Slinton 	    signal(i, sigfunc[i]);
10679677Slinton 	}
10689677Slinton     }
10699677Slinton }
10709677Slinton 
10719677Slinton /*
10729677Slinton  * Get process information from user area.
10739677Slinton  */
10749677Slinton 
1075*33331Sdonn private getinfo (p, status)
10769677Slinton register Process p;
10779677Slinton register int status;
10789677Slinton {
10799677Slinton     register int i;
108016617Ssam     Address addr;
10819677Slinton 
10829677Slinton     p->signo = (status&0177);
10839677Slinton     p->exitval = ((status >> 8)&0377);
10849677Slinton     if (p->signo != STOPPED) {
10859677Slinton 	p->status = FINISHED;
108614757Slinton 	p->pid = 0;
108716617Ssam 	p->reg[PROGCTR] = 0;
10889677Slinton     } else {
10899677Slinton 	p->status = p->signo;
10909677Slinton 	p->signo = p->exitval;
10919677Slinton 	p->exitval = 0;
1092*33331Sdonn #       ifdef IRIS
1093*33331Sdonn 	    p->mask = readreg(p, RPS);
1094*33331Sdonn #       else
1095*33331Sdonn 	    p->sigcode = ptrace(UREAD, p->pid, &((struct user *)0)->u_code, 0);
1096*33331Sdonn 	    p->mask = readreg(p, PS);
1097*33331Sdonn #       endif
10989677Slinton 	for (i = 0; i < NREG; i++) {
1099*33331Sdonn 	    p->reg[i] = readreg(p, rloc[i]);
11009677Slinton 	    p->oreg[i] = p->reg[i];
11019677Slinton 	}
1102*33331Sdonn #       ifdef mc68000
1103*33331Sdonn 	    if (p->status == STOPPED and p->signo == SIGTRAP and
1104*33331Sdonn 		p->reg[PROGCTR] > CODESTART
1105*33331Sdonn 	    ) {
1106*33331Sdonn 		p->reg[PROGCTR] -= 2;
1107*33331Sdonn 	    }
1108*33331Sdonn #       endif
110911768Slinton 	savetty(stdout, &(p->ttyinfo));
111016617Ssam 	addr = (Address) &(((struct user *) 0)->u_signal[p->signo]);
111118230Slinton 	p->sigstatus = (Address) ptrace(UREAD, p->pid, addr, 0);
11129677Slinton     }
11139677Slinton }
11149677Slinton 
11159677Slinton /*
11169677Slinton  * Set process's user area information from given process structure.
11179677Slinton  */
11189677Slinton 
1119*33331Sdonn private setinfo (p, signo)
11209677Slinton register Process p;
112111867Slinton int signo;
11229677Slinton {
11239677Slinton     register int i;
11249677Slinton     register int r;
11259677Slinton 
112614757Slinton     if (signo == DEFSIG) {
112716617Ssam 	if (istraced(p) and (p->sigstatus == 0 or p->sigstatus == 1)) {
112814757Slinton 	    p->signo = 0;
112914757Slinton 	}
113014757Slinton     } else {
113111867Slinton 	p->signo = signo;
11329677Slinton     }
11339677Slinton     for (i = 0; i < NREG; i++) {
11349677Slinton 	if ((r = p->reg[i]) != p->oreg[i]) {
1135*33331Sdonn 	    writereg(p, rloc[i], r);
11369677Slinton 	}
11379677Slinton     }
113811768Slinton     restoretty(stdout, &(p->ttyinfo));
11399677Slinton }
11409677Slinton 
11419677Slinton /*
114216617Ssam  * Return the address associated with the current signal.
114316617Ssam  * (Plus two since the address points to the beginning of a procedure).
114416617Ssam  */
114516617Ssam 
114616617Ssam public Address usignal (p)
114716617Ssam Process p;
114816617Ssam {
114916617Ssam     Address r;
115016617Ssam 
115116617Ssam     r = p->sigstatus;
115216617Ssam     if (r != 0 and r != 1) {
1153*33331Sdonn 	r += FUNCOFFSET;
115416617Ssam     }
115516617Ssam     return r;
115616617Ssam }
115716617Ssam 
115816617Ssam /*
11599677Slinton  * Structure for reading and writing by words, but dealing with bytes.
11609677Slinton  */
11619677Slinton 
11629677Slinton typedef union {
11639677Slinton     Word pword;
11649677Slinton     Byte pbyte[sizeof(Word)];
11659677Slinton } Pword;
11669677Slinton 
11679677Slinton /*
11689677Slinton  * Read (write) from (to) the process' address space.
11699677Slinton  * We must deal with ptrace's inability to look anywhere other
11709677Slinton  * than at a word boundary.
11719677Slinton  */
11729677Slinton 
11739677Slinton private Word fetch();
11749677Slinton private store();
11759677Slinton 
11769677Slinton private pio(p, op, seg, buff, addr, nbytes)
11779677Slinton Process p;
11789677Slinton PioOp op;
11799677Slinton PioSeg seg;
11809677Slinton char *buff;
11819677Slinton Address addr;
11829677Slinton int nbytes;
11839677Slinton {
11849677Slinton     register int i;
11859677Slinton     register Address newaddr;
11869677Slinton     register char *cp;
11879677Slinton     char *bufend;
11889677Slinton     Pword w;
11899677Slinton     Address wordaddr;
11909677Slinton     int byteoff;
11919677Slinton 
11929677Slinton     if (p->status != STOPPED) {
11939677Slinton 	error("program is not active");
11949677Slinton     }
11959677Slinton     cp = buff;
11969677Slinton     newaddr = addr;
11979677Slinton     wordaddr = (newaddr&WMASK);
11989677Slinton     if (wordaddr != newaddr) {
11999677Slinton 	w.pword = fetch(p, seg, wordaddr);
12009677Slinton 	for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) {
12019677Slinton 	    if (op == PREAD) {
12029677Slinton 		*cp++ = w.pbyte[i];
12039677Slinton 	    } else {
12049677Slinton 		w.pbyte[i] = *cp++;
12059677Slinton 	    }
12069677Slinton 	    nbytes--;
12079677Slinton 	}
12089677Slinton 	if (op == PWRITE) {
12099677Slinton 	    store(p, seg, wordaddr, w.pword);
12109677Slinton 	}
12119677Slinton 	newaddr = wordaddr + sizeof(Word);
12129677Slinton     }
12139677Slinton     byteoff = (nbytes&(~WMASK));
12149677Slinton     nbytes -= byteoff;
12159677Slinton     bufend = cp + nbytes;
121626333Ssam #ifdef tahoe
121726333Ssam     if (((int)cp)&WMASK) {
121826333Ssam 	/*
121926333Ssam 	 * Must copy a byte at a time, buffer not word addressable.
122026333Ssam 	 */
122126333Ssam 	while (cp < bufend) {
122226333Ssam 	    if (op == PREAD) {
122326333Ssam 		w.pword = fetch(p, seg, newaddr);
122426333Ssam 		for (i = 0; i < sizeof(Word); i++)
122526333Ssam 		    *cp++ = w.pbyte[i];
122626333Ssam 	    } else {
122726333Ssam 		for (i = 0; i < sizeof(Word); i++)
122826333Ssam 		    w.pbyte[i] = *cp++;
122926333Ssam 		store(p, seg, newaddr, w.pword);
123026333Ssam 	    }
123126333Ssam 	    newaddr += sizeof(Word);
123226333Ssam 	}
123326333Ssam     } else {
123426333Ssam     /*
123526333Ssam      * Buffer, word aligned, act normally...
123626333Ssam      */
123726333Ssam #endif
12389677Slinton     while (cp < bufend) {
12399677Slinton 	if (op == PREAD) {
12409677Slinton 	    *((Word *) cp) = fetch(p, seg, newaddr);
12419677Slinton 	} else {
12429677Slinton 	    store(p, seg, newaddr, *((Word *) cp));
12439677Slinton 	}
12449677Slinton 	cp += sizeof(Word);
12459677Slinton 	newaddr += sizeof(Word);
12469677Slinton     }
124726333Ssam #ifdef tahoe
124826333Ssam     }
124926333Ssam #endif
12509677Slinton     if (byteoff > 0) {
12519677Slinton 	w.pword = fetch(p, seg, newaddr);
12529677Slinton 	for (i = 0; i < byteoff; i++) {
12539677Slinton 	    if (op == PREAD) {
12549677Slinton 		*cp++ = w.pbyte[i];
12559677Slinton 	    } else {
12569677Slinton 		w.pbyte[i] = *cp++;
12579677Slinton 	    }
12589677Slinton 	}
12599677Slinton 	if (op == PWRITE) {
12609677Slinton 	    store(p, seg, newaddr, w.pword);
12619677Slinton 	}
12629677Slinton     }
12639677Slinton }
12649677Slinton 
12659677Slinton /*
12669677Slinton  * Get a word from a process at the given address.
12679677Slinton  * The address is assumed to be on a word boundary.
12689677Slinton  *
12699677Slinton  * A simple cache scheme is used to avoid redundant ptrace calls
12709677Slinton  * to the instruction space since it is assumed to be pure.
12719677Slinton  *
12729677Slinton  * It is necessary to use a write-through scheme so that
12739677Slinton  * breakpoints right next to each other don't interfere.
12749677Slinton  */
12759677Slinton 
12769677Slinton private Integer nfetchs, nreads, nwrites;
12779677Slinton 
12789677Slinton private Word fetch(p, seg, addr)
12799677Slinton Process p;
12809677Slinton PioSeg seg;
12819677Slinton register int addr;
12829677Slinton {
12839677Slinton     register CacheWord *wp;
12849677Slinton     register Word w;
12859677Slinton 
12869677Slinton     switch (seg) {
12879677Slinton 	case TEXTSEG:
12889677Slinton 	    ++nfetchs;
12899677Slinton 	    wp = &p->word[cachehash(addr)];
12909677Slinton 	    if (addr == 0 or wp->addr != addr) {
12919677Slinton 		++nreads;
129218230Slinton 		w = ptrace(IREAD, p->pid, addr, 0);
12939677Slinton 		wp->addr = addr;
12949677Slinton 		wp->val = w;
12959677Slinton 	    } else {
12969677Slinton 		w = wp->val;
12979677Slinton 	    }
12989677Slinton 	    break;
12999677Slinton 
13009677Slinton 	case DATASEG:
130118230Slinton 	    w = ptrace(DREAD, p->pid, addr, 0);
13029677Slinton 	    break;
13039677Slinton 
13049677Slinton 	default:
13059677Slinton 	    panic("fetch: bad seg %d", seg);
13069677Slinton 	    /* NOTREACHED */
13079677Slinton     }
13089677Slinton     return w;
13099677Slinton }
13109677Slinton 
13119677Slinton /*
13129677Slinton  * Put a word into the process' address space at the given address.
13139677Slinton  * The address is assumed to be on a word boundary.
13149677Slinton  */
13159677Slinton 
13169677Slinton private store(p, seg, addr, data)
13179677Slinton Process p;
13189677Slinton PioSeg seg;
13199677Slinton int addr;
13209677Slinton Word data;
13219677Slinton {
13229677Slinton     register CacheWord *wp;
13239677Slinton 
13249677Slinton     switch (seg) {
13259677Slinton 	case TEXTSEG:
13269677Slinton 	    ++nwrites;
13279677Slinton 	    wp = &p->word[cachehash(addr)];
13289677Slinton 	    wp->addr = addr;
13299677Slinton 	    wp->val = data;
133018230Slinton 	    ptrace(IWRITE, p->pid, addr, data);
13319677Slinton 	    break;
13329677Slinton 
13339677Slinton 	case DATASEG:
133418230Slinton 	    ptrace(DWRITE, p->pid, addr, data);
13359677Slinton 	    break;
13369677Slinton 
13379677Slinton 	default:
13389677Slinton 	    panic("store: bad seg %d", seg);
13399677Slinton 	    /* NOTREACHED */
13409677Slinton     }
13419677Slinton }
13429677Slinton 
134318230Slinton /*
134418230Slinton  * Flush the instruction cache associated with a process.
134518230Slinton  */
134618230Slinton 
134718230Slinton private cacheflush (p)
134818230Slinton Process p;
134918230Slinton {
135018230Slinton     bzero(p->word, sizeof(p->word));
135118230Slinton }
135218230Slinton 
13539677Slinton public printptraceinfo()
13549677Slinton {
13559677Slinton     printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites);
13569677Slinton }
13579677Slinton 
13589677Slinton /*
135916617Ssam  * Redirect input.
136016617Ssam  * Assuming this is called from a child, we should be careful to avoid
136116617Ssam  * (possibly) shared standard I/O buffers.
13629677Slinton  */
13639677Slinton 
136416617Ssam private infrom (filename)
136516617Ssam String filename;
136616617Ssam {
136716617Ssam     Fileid in;
136816617Ssam 
136916617Ssam     in = open(filename, 0);
137016617Ssam     if (in == -1) {
137116617Ssam 	write(2, "can't read ", 11);
137216617Ssam 	write(2, filename, strlen(filename));
137316617Ssam 	write(2, "\n", 1);
137416617Ssam 	_exit(1);
137516617Ssam     }
137616617Ssam     fswap(0, in);
137716617Ssam }
137816617Ssam 
137916617Ssam /*
138016617Ssam  * Redirect standard output.
138116617Ssam  * Same assumptions as for "infrom" above.
138216617Ssam  */
138316617Ssam 
138416617Ssam private outto (filename)
138516617Ssam String filename;
138616617Ssam {
138716617Ssam     Fileid out;
138816617Ssam 
138916617Ssam     out = creat(filename, 0666);
139016617Ssam     if (out == -1) {
139116617Ssam 	write(2, "can't write ", 12);
139216617Ssam 	write(2, filename, strlen(filename));
139316617Ssam 	write(2, "\n", 1);
139416617Ssam 	_exit(1);
139516617Ssam     }
139616617Ssam     fswap(1, out);
139716617Ssam }
139816617Ssam 
139916617Ssam /*
140016617Ssam  * Swap file numbers, useful for redirecting standard input or output.
140116617Ssam  */
140216617Ssam 
14039677Slinton private fswap(oldfd, newfd)
140416617Ssam Fileid oldfd;
140516617Ssam Fileid newfd;
14069677Slinton {
14079677Slinton     if (oldfd != newfd) {
14089677Slinton 	close(oldfd);
14099677Slinton 	dup(newfd);
14109677Slinton 	close(newfd);
14119677Slinton     }
14129677Slinton }
141316928Ssam 
141416928Ssam /*
141518230Slinton  * Signal name manipulation.
141616928Ssam  */
141718230Slinton 
141818230Slinton private String signames[NSIG] = {
141918230Slinton     0,
142018230Slinton     "HUP", "INT", "QUIT", "ILL", "TRAP",
142118230Slinton     "IOT", "EMT", "FPE", "KILL", "BUS",
142218230Slinton     "SEGV", "SYS", "PIPE", "ALRM", "TERM",
142318230Slinton     0, "STOP", "TSTP", "CONT", "CHLD",
142418230Slinton     "TTIN", "TTOU", "TINT", "XCPU", "XFSZ",
142526333Ssam     "VTALRM", "PROF", "WINCH", "USR1", "USR2"
142616928Ssam };
142716928Ssam 
142816928Ssam /*
142918230Slinton  * Get the signal number associated with a given name.
143018230Slinton  * The name is first translated to upper case if necessary.
143116928Ssam  */
143218230Slinton 
143318230Slinton public integer siglookup (s)
143416928Ssam String s;
143516928Ssam {
143618230Slinton     register char *p, *q;
143718230Slinton     char buf[100];
143818230Slinton     integer i;
143916928Ssam 
144018230Slinton     p = s;
144118230Slinton     q = buf;
144218230Slinton     while (*p != '\0') {
144318230Slinton 	if (*p >= 'a' and *p <= 'z') {
144418230Slinton 	    *q = (*p - 'a') + 'A';
144518230Slinton 	} else {
144618230Slinton 	    *q = *p;
144718230Slinton 	}
144818230Slinton 	++p;
144918230Slinton 	++q;
145018230Slinton     }
145118230Slinton     *q = '\0';
145218230Slinton     p = buf;
145318230Slinton     if (buf[0] == 'S' and buf[1] == 'I' and buf[2] == 'G') {
145418230Slinton 	p += 3;
145518230Slinton     }
145618230Slinton     i = 1;
145718230Slinton     for (;;) {
145818230Slinton 	if (i >= sizeof(signames) div sizeof(signames[0])) {
145918230Slinton 	    error("signal \"%s\" unknown", s);
146018230Slinton 	    i = 0;
146118230Slinton 	    break;
146218230Slinton 	}
146318230Slinton 	if (signames[i] != nil and streq(signames[i], p)) {
146418230Slinton 	    break;
146518230Slinton 	}
146618230Slinton 	++i;
146718230Slinton     }
146818230Slinton     return i;
146916928Ssam }
147016928Ssam 
147116928Ssam /*
147218230Slinton  * Print all signals being ignored by the debugger.
147318230Slinton  * These signals are auotmatically
147416928Ssam  * passed on to the debugged process.
147516928Ssam  */
147618230Slinton 
147718230Slinton public printsigsignored (p)
147816931Ssam Process p;
147916928Ssam {
148016931Ssam     printsigs(~p->sigset);
148116928Ssam }
148216928Ssam 
148316928Ssam /*
148416928Ssam  * Print all signals being intercepted by
148516928Ssam  * the debugger for the specified process.
148616928Ssam  */
148718230Slinton 
148816931Ssam public printsigscaught(p)
148916931Ssam Process p;
149016928Ssam {
149116931Ssam     printsigs(p->sigset);
149216931Ssam }
149316931Ssam 
149418230Slinton private printsigs (set)
149518230Slinton integer set;
149616931Ssam {
149718230Slinton     integer s;
149818230Slinton     char separator[2];
149916931Ssam 
150018230Slinton     separator[0] = '\0';
150118230Slinton     for (s = 1; s < sizeof(signames) div sizeof(signames[0]); s++) {
150218230Slinton 	if (set & setrep(s)) {
150318230Slinton 	    if (signames[s] != nil) {
150418230Slinton 		printf("%s%s", separator, signames[s]);
150518230Slinton 		separator[0] = ' ';
150618230Slinton 		separator[1] = '\0';
150718230Slinton 	    }
150816928Ssam 	}
150918230Slinton     }
151018230Slinton     if (separator[0] == ' ') {
151116931Ssam 	putchar('\n');
151216931Ssam     }
151316928Ssam }
1514