xref: /csrg-svn/old/dbx/process.c (revision 38105)
121620Sdist /*
2*38105Sbostic  * Copyright (c) 1983 The Regents of the University of California.
3*38105Sbostic  * All rights reserved.
4*38105Sbostic  *
5*38105Sbostic  * Redistribution and use in source and binary forms are permitted
6*38105Sbostic  * provided that the above copyright notice and this paragraph are
7*38105Sbostic  * duplicated in all such forms and that any documentation,
8*38105Sbostic  * advertising materials, and other materials related to such
9*38105Sbostic  * distribution and use acknowledge that the software was developed
10*38105Sbostic  * by the University of California, Berkeley.  The name of the
11*38105Sbostic  * University may not be used to endorse or promote products derived
12*38105Sbostic  * from this software without specific prior written permission.
13*38105Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*38105Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*38105Sbostic  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1621620Sdist  */
179677Slinton 
1821620Sdist #ifndef lint
19*38105Sbostic static char sccsid[] = "@(#)process.c	5.4 (Berkeley) 05/23/89";
20*38105Sbostic #endif /* not lint */
219677Slinton 
229677Slinton /*
239677Slinton  * Process management.
249677Slinton  *
259677Slinton  * This module contains the routines to manage the execution and
269677Slinton  * tracing of the debuggee process.
279677Slinton  */
289677Slinton 
299677Slinton #include "defs.h"
309677Slinton #include "process.h"
319677Slinton #include "machine.h"
329677Slinton #include "events.h"
339677Slinton #include "tree.h"
3414757Slinton #include "eval.h"
359677Slinton #include "operators.h"
369677Slinton #include "source.h"
379677Slinton #include "object.h"
389677Slinton #include "mappings.h"
399677Slinton #include "main.h"
409677Slinton #include "coredump.h"
419677Slinton #include <signal.h>
429677Slinton #include <errno.h>
439677Slinton #include <sys/stat.h>
449677Slinton 
459677Slinton #ifndef public
469677Slinton 
479677Slinton typedef struct Process *Process;
489677Slinton 
499677Slinton Process process;
509677Slinton 
5114757Slinton #define DEFSIG -1
5214757Slinton 
539677Slinton #include "machine.h"
549677Slinton 
559677Slinton #endif
569677Slinton 
579677Slinton #define NOTSTARTED 1
589677Slinton #define STOPPED 0177
599677Slinton #define FINISHED 0
609677Slinton 
619677Slinton /*
6216617Ssam  * A cache of the instruction segment is kept to reduce the number
6316617Ssam  * of system calls.  Might be better just to read the entire
6416617Ssam  * code space into memory.
659677Slinton  */
669677Slinton 
6733331Sdonn #define CACHESIZE 1003
689677Slinton 
699677Slinton typedef struct {
709677Slinton     Word addr;
719677Slinton     Word val;
729677Slinton } CacheWord;
739677Slinton 
749677Slinton /*
759677Slinton  * This structure holds the information we need from the user structure.
769677Slinton  */
779677Slinton 
789677Slinton struct Process {
799677Slinton     int pid;			/* process being traced */
8011768Slinton     int mask;			/* process status word */
8111768Slinton     Word reg[NREG];		/* process' registers */
829677Slinton     Word oreg[NREG];		/* registers when process last stopped */
839677Slinton     short status;		/* either STOPPED or FINISHED */
849677Slinton     short signo;		/* signal that stopped process */
8518230Slinton     short sigcode;		/* extra signal information */
869677Slinton     int exitval;		/* return value from exit() */
879677Slinton     long sigset;		/* bit array of traced signals */
8833331Sdonn     CacheWord word[CACHESIZE];	/* text segment cache */
8911768Slinton     Ttyinfo ttyinfo;		/* process' terminal characteristics */
9016617Ssam     Address sigstatus;		/* process' handler for current signal */
919677Slinton };
929677Slinton 
939677Slinton /*
949677Slinton  * These definitions are for the arguments to "pio".
959677Slinton  */
969677Slinton 
979677Slinton typedef enum { PREAD, PWRITE } PioOp;
989677Slinton typedef enum { TEXTSEG, DATASEG } PioSeg;
999677Slinton 
1009677Slinton private struct Process pbuf;
1019677Slinton 
10218230Slinton #define MAXNCMDARGS 1000         /* maximum number of arguments to RUN */
1039677Slinton 
10414395Slinton extern int errno;
10514395Slinton 
1069677Slinton private Boolean just_started;
1079677Slinton private int argc;
1089677Slinton private String argv[MAXNCMDARGS];
1099677Slinton private String infile, outfile;
1109677Slinton 
1119677Slinton /*
1129677Slinton  * Initialize process information.
1139677Slinton  */
1149677Slinton 
1159677Slinton public process_init()
1169677Slinton {
11733331Sdonn     register integer i;
11833331Sdonn     char buf[10];
1199677Slinton 
1209677Slinton     process = &pbuf;
1219677Slinton     process->status = (coredump) ? STOPPED : NOTSTARTED;
1229677Slinton     setsigtrace();
12333331Sdonn #   if vax || tahoe
12433331Sdonn 	for (i = 0; i < NREG; i++) {
12533331Sdonn 	    sprintf(buf, "$r%d", i);
12633331Sdonn 	    defregname(identname(buf, false), i);
12733331Sdonn 	}
12833331Sdonn #	ifdef vax
12933331Sdonn 	    defregname(identname("$ap", true), ARGP);
13033331Sdonn #	endif
13133331Sdonn #   else
13233331Sdonn #       ifdef mc68000
13333331Sdonn 	    for (i = 0; i < 8; i++) {
13433331Sdonn 		sprintf(buf, "$d%d", i);
13533331Sdonn 		defregname(identname(buf, false), i);
13633331Sdonn 		sprintf(buf, "$a%d", i);
13733331Sdonn 		defregname(identname(buf, false), i + 8);
13833331Sdonn 	    }
13933331Sdonn #       endif
14033331Sdonn #   endif
1419677Slinton     defregname(identname("$fp", true), FRP);
1429677Slinton     defregname(identname("$sp", true), STKP);
1439677Slinton     defregname(identname("$pc", true), PROGCTR);
1449677Slinton     if (coredump) {
1459677Slinton 	coredump_readin(process->mask, process->reg, process->signo);
14612484Slinton 	pc = process->reg[PROGCTR];
1479677Slinton     }
14812484Slinton     arginit();
1499677Slinton }
1509677Slinton 
1519677Slinton /*
1529677Slinton  * Routines to get at process information from outside this module.
1539677Slinton  */
1549677Slinton 
1559677Slinton public Word reg(n)
1569677Slinton Integer n;
1579677Slinton {
1589677Slinton     register Word w;
1599677Slinton 
1609677Slinton     if (n == NREG) {
1619677Slinton 	w = process->mask;
1629677Slinton     } else {
1639677Slinton 	w = process->reg[n];
1649677Slinton     }
1659677Slinton     return w;
1669677Slinton }
1679677Slinton 
1689677Slinton public setreg(n, w)
1699677Slinton Integer n;
1709677Slinton Word w;
1719677Slinton {
1729677Slinton     process->reg[n] = w;
1739677Slinton }
1749677Slinton 
1759677Slinton /*
1769677Slinton  * Begin execution.
1779677Slinton  *
1789677Slinton  * We set a breakpoint at the end of the code so that the
1799677Slinton  * process data doesn't disappear after the program terminates.
1809677Slinton  */
1819677Slinton 
1829677Slinton private Boolean remade();
1839677Slinton 
1849677Slinton public start(argv, infile, outfile)
1859677Slinton String argv[];
1869677Slinton String infile, outfile;
1879677Slinton {
1889677Slinton     String pargv[4];
1899677Slinton     Node cond;
1909677Slinton 
1919677Slinton     if (coredump) {
1929677Slinton 	coredump = false;
1939677Slinton 	fclose(corefile);
1949677Slinton 	coredump_close();
1959677Slinton     }
1969677Slinton     if (argv == nil) {
1979677Slinton 	argv = pargv;
1989677Slinton 	pargv[0] = objname;
1999677Slinton 	pargv[1] = nil;
2009677Slinton     } else {
2019677Slinton 	argv[argc] = nil;
2029677Slinton     }
20318230Slinton     pstart(process, argv, infile, outfile);
2049677Slinton     if (remade(objname)) {
2059677Slinton 	reinit(argv, infile, outfile);
2069677Slinton     }
2079677Slinton     if (process->status == STOPPED) {
20833331Sdonn 	pc = CODESTART;
20916617Ssam 	setcurfunc(program);
2109677Slinton 	if (objsize != 0) {
2119677Slinton 	    cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr()));
2129677Slinton 	    event_once(cond, buildcmdlist(build(O_ENDX)));
2139677Slinton 	}
2149677Slinton     }
2159677Slinton }
2169677Slinton 
2179677Slinton /*
2189677Slinton  * Check to see if the object file has changed since the symbolic
2199677Slinton  * information last was read.
2209677Slinton  */
2219677Slinton 
2229677Slinton private time_t modtime;
2239677Slinton 
2249677Slinton private Boolean remade(filename)
2259677Slinton String filename;
2269677Slinton {
2279677Slinton     struct stat s;
2289677Slinton     Boolean b;
2299677Slinton 
2309677Slinton     stat(filename, &s);
2319677Slinton     b = (Boolean) (modtime != 0 and modtime < s.st_mtime);
2329677Slinton     modtime = s.st_mtime;
2339677Slinton     return b;
2349677Slinton }
2359677Slinton 
2369677Slinton /*
2379677Slinton  * Set up what signals we want to trace.
2389677Slinton  */
2399677Slinton 
2409677Slinton private setsigtrace()
2419677Slinton {
2429677Slinton     register Integer i;
2439677Slinton     register Process p;
2449677Slinton 
2459677Slinton     p = process;
2469677Slinton     for (i = 1; i <= NSIG; i++) {
2479677Slinton 	psigtrace(p, i, true);
2489677Slinton     }
2499677Slinton     psigtrace(p, SIGHUP, false);
2509677Slinton     psigtrace(p, SIGKILL, false);
2519677Slinton     psigtrace(p, SIGALRM, false);
25233331Sdonn #   ifdef SIGTSTP
25333331Sdonn 	psigtrace(p, SIGTSTP, false);
25433331Sdonn 	psigtrace(p, SIGCONT, false);
25533331Sdonn #   endif
2569677Slinton     psigtrace(p, SIGCHLD, false);
25726333Ssam     psigtrace(p, SIGWINCH, false);
2589677Slinton }
2599677Slinton 
2609677Slinton /*
2619677Slinton  * Initialize the argument list.
2629677Slinton  */
2639677Slinton 
2649677Slinton public arginit()
2659677Slinton {
2669677Slinton     infile = nil;
2679677Slinton     outfile = nil;
2689677Slinton     argv[0] = objname;
2699677Slinton     argc = 1;
2709677Slinton }
2719677Slinton 
2729677Slinton /*
2739677Slinton  * Add an argument to the list for the debuggee.
2749677Slinton  */
2759677Slinton 
2769677Slinton public newarg(arg)
2779677Slinton String arg;
2789677Slinton {
2799677Slinton     if (argc >= MAXNCMDARGS) {
2809677Slinton 	error("too many arguments");
2819677Slinton     }
2829677Slinton     argv[argc++] = arg;
2839677Slinton }
2849677Slinton 
2859677Slinton /*
2869677Slinton  * Set the standard input for the debuggee.
2879677Slinton  */
2889677Slinton 
2899677Slinton public inarg(filename)
2909677Slinton String filename;
2919677Slinton {
2929677Slinton     if (infile != nil) {
2939677Slinton 	error("multiple input redirects");
2949677Slinton     }
2959677Slinton     infile = filename;
2969677Slinton }
2979677Slinton 
2989677Slinton /*
2999677Slinton  * Set the standard output for the debuggee.
3009677Slinton  * Probably should check to avoid overwriting an existing file.
3019677Slinton  */
3029677Slinton 
3039677Slinton public outarg(filename)
3049677Slinton String filename;
3059677Slinton {
3069677Slinton     if (outfile != nil) {
3079677Slinton 	error("multiple output redirect");
3089677Slinton     }
3099677Slinton     outfile = filename;
3109677Slinton }
3119677Slinton 
3129677Slinton /*
3139677Slinton  * Start debuggee executing.
3149677Slinton  */
3159677Slinton 
3169677Slinton public run()
3179677Slinton {
3189677Slinton     process->status = STOPPED;
3199677Slinton     fixbps();
3209677Slinton     curline = 0;
3219677Slinton     start(argv, infile, outfile);
3229677Slinton     just_started = true;
3239677Slinton     isstopped = false;
32414757Slinton     cont(0);
3259677Slinton }
3269677Slinton 
3279677Slinton /*
3289677Slinton  * Continue execution wherever we left off.
3299677Slinton  *
3309677Slinton  * Note that this routine never returns.  Eventually bpact() will fail
3319677Slinton  * and we'll call printstatus or step will call it.
3329677Slinton  */
3339677Slinton 
3349677Slinton typedef int Intfunc();
3359677Slinton 
3369677Slinton private Intfunc *dbintr;
3379677Slinton private intr();
3389677Slinton 
33911867Slinton public cont(signo)
34016617Ssam integer signo;
3419677Slinton {
34216617Ssam     integer s;
34316617Ssam 
3449677Slinton     dbintr = signal(SIGINT, intr);
3459677Slinton     if (just_started) {
3469677Slinton 	just_started = false;
3479677Slinton     } else {
3489677Slinton 	if (not isstopped) {
3499677Slinton 	    error("can't continue execution");
3509677Slinton 	}
3519677Slinton 	isstopped = false;
35211867Slinton 	stepover();
3539677Slinton     }
35416617Ssam     s = signo;
3559677Slinton     for (;;) {
3569677Slinton 	if (single_stepping) {
3579677Slinton 	    printnews();
3589677Slinton 	} else {
3599677Slinton 	    setallbps();
36016617Ssam 	    resume(s);
3619677Slinton 	    unsetallbps();
36216617Ssam 	    s = DEFSIG;
36318230Slinton 	    if (not isbperr() or not bpact()) {
3649677Slinton 		printstatus();
3659677Slinton 	    }
3669677Slinton 	}
36711867Slinton 	stepover();
3689677Slinton     }
3699677Slinton     /* NOTREACHED */
3709677Slinton }
3719677Slinton 
3729677Slinton /*
37318230Slinton  * This routine is called if we get an interrupt while "running"
3749677Slinton  * but actually in the debugger.  Could happen, for example, while
3759677Slinton  * processing breakpoints.
3769677Slinton  *
3779677Slinton  * We basically just want to keep going; the assumption is
37818230Slinton  * that when the process resumes it will get the interrupt,
3799677Slinton  * which will then be handled.
3809677Slinton  */
3819677Slinton 
3829677Slinton private intr()
3839677Slinton {
3849677Slinton     signal(SIGINT, intr);
3859677Slinton }
3869677Slinton 
3879677Slinton public fixintr()
3889677Slinton {
3899677Slinton     signal(SIGINT, dbintr);
3909677Slinton }
3919677Slinton 
3929677Slinton /*
3939677Slinton  * Resume execution.
3949677Slinton  */
3959677Slinton 
39611867Slinton public resume(signo)
39711867Slinton int signo;
3989677Slinton {
3999677Slinton     register Process p;
4009677Slinton 
4019677Slinton     p = process;
40211867Slinton     pcont(p, signo);
4039677Slinton     pc = process->reg[PROGCTR];
40411832Slinton     if (p->status != STOPPED) {
40511867Slinton 	if (p->signo != 0) {
40611867Slinton 	    error("program terminated by signal %d", p->signo);
40714757Slinton 	} else if (not runfirst) {
40818230Slinton 	    if (p->exitval == 0) {
40918230Slinton 		error("program exited");
41018230Slinton 	    } else {
41118230Slinton 		error("program exited with code %d", p->exitval);
41218230Slinton 	    }
41311867Slinton 	}
41411832Slinton     }
4159677Slinton }
4169677Slinton 
4179677Slinton /*
4189677Slinton  * Continue execution up to the next source line.
4199677Slinton  *
4209677Slinton  * There are two ways to define the next source line depending on what
4219677Slinton  * is desired when a procedure or function call is encountered.  Step
4229677Slinton  * stops at the beginning of the procedure or call; next skips over it.
4239677Slinton  */
4249677Slinton 
4259677Slinton /*
4269677Slinton  * Stepc is what is called when the step command is given.
4279677Slinton  * It has to play with the "isstopped" information.
4289677Slinton  */
4299677Slinton 
4309677Slinton public stepc()
4319677Slinton {
4329677Slinton     if (not isstopped) {
4339677Slinton 	error("can't continue execution");
4349677Slinton     }
4359677Slinton     isstopped = false;
4369677Slinton     dostep(false);
4379677Slinton     isstopped = true;
4389677Slinton }
4399677Slinton 
4409677Slinton public next()
4419677Slinton {
44216617Ssam     Address oldfrp, newfrp;
44316617Ssam 
4449677Slinton     if (not isstopped) {
4459677Slinton 	error("can't continue execution");
4469677Slinton     }
4479677Slinton     isstopped = false;
44816617Ssam     oldfrp = reg(FRP);
44916617Ssam     do {
45016617Ssam 	dostep(true);
45116617Ssam 	pc = reg(PROGCTR);
45216617Ssam 	newfrp = reg(FRP);
45316617Ssam     } while (newfrp < oldfrp and newfrp != 0);
4549677Slinton     isstopped = true;
4559677Slinton }
4569677Slinton 
45711867Slinton /*
45816617Ssam  * Continue execution until the current function returns, or,
45916617Ssam  * if the given argument is non-nil, until execution returns to
46016617Ssam  * somewhere within the given function.
46116617Ssam  */
46216617Ssam 
46316617Ssam public rtnfunc (f)
46416617Ssam Symbol f;
46516617Ssam {
46616617Ssam     Address addr;
46716617Ssam     Symbol t;
46816617Ssam 
46916617Ssam     if (not isstopped) {
47016617Ssam 	error("can't continue execution");
47116617Ssam     } else if (f != nil and not isactive(f)) {
47216617Ssam 	error("%s is not active", symname(f));
47316617Ssam     } else {
47416617Ssam 	addr = return_addr();
47516617Ssam 	if (addr == nil) {
47616617Ssam 	    error("no place to return to");
47716617Ssam 	} else {
47816617Ssam 	    isstopped = false;
47916617Ssam 	    contto(addr);
48016617Ssam 	    if (f != nil) {
48116617Ssam 		for (;;) {
48216617Ssam 		    t = whatblock(pc);
48316617Ssam 		    addr = return_addr();
48416617Ssam 		if (t == f or addr == nil) break;
48516617Ssam 		    contto(addr);
48616617Ssam 		}
48716617Ssam 	    }
48818230Slinton 	    if (not bpact()) {
48916617Ssam 		isstopped = true;
49016617Ssam 		printstatus();
49116617Ssam 	    }
49216617Ssam 	}
49316617Ssam     }
49416617Ssam }
49516617Ssam 
49616617Ssam /*
49711867Slinton  * Single-step over the current machine instruction.
49811867Slinton  *
49911867Slinton  * If we're single-stepping by source line we want to step to the
50011867Slinton  * next source line.  Otherwise we're going to continue so there's
50111867Slinton  * no reason to do all the work necessary to single-step to the next
50211867Slinton  * source line.
50311867Slinton  */
50411867Slinton 
50516617Ssam public stepover()
5069677Slinton {
50711867Slinton     Boolean b;
50811867Slinton 
50916617Ssam     if (traceexec) {
51016617Ssam 	printf("!! stepping over 0x%x\n", process->reg[PROGCTR]);
51116617Ssam     }
51211867Slinton     if (single_stepping) {
51311867Slinton 	dostep(false);
51411867Slinton     } else {
51511867Slinton 	b = inst_tracing;
51611867Slinton 	inst_tracing = true;
51711867Slinton 	dostep(false);
51811867Slinton 	inst_tracing = b;
51911867Slinton     }
52016617Ssam     if (traceexec) {
52116617Ssam 	printf("!! stepped over to 0x%x\n", process->reg[PROGCTR]);
52216617Ssam     }
5239677Slinton }
5249677Slinton 
5259677Slinton /*
52618230Slinton  * Resume execution up to the given address.  We can either ignore
52718230Slinton  * breakpoints (stepto) or catch them (contto).
5289677Slinton  */
5299677Slinton 
5309677Slinton public stepto(addr)
5319677Slinton Address addr;
5329677Slinton {
53316617Ssam     xto(addr, false);
53416617Ssam }
53516617Ssam 
53616617Ssam private contto (addr)
53716617Ssam Address addr;
53816617Ssam {
53916617Ssam     xto(addr, true);
54016617Ssam }
54116617Ssam 
54216617Ssam private xto (addr, catchbps)
54316617Ssam Address addr;
54416617Ssam boolean catchbps;
54516617Ssam {
54616617Ssam     Address curpc;
54716617Ssam 
54816617Ssam     if (catchbps) {
54916617Ssam 	stepover();
5509677Slinton     }
55116617Ssam     curpc = process->reg[PROGCTR];
55216617Ssam     if (addr != curpc) {
55316617Ssam 	if (traceexec) {
55416617Ssam 	    printf("!! stepping from 0x%x to 0x%x\n", curpc, addr);
55516617Ssam 	}
55616617Ssam 	if (catchbps) {
55716617Ssam 	    setallbps();
55816617Ssam 	}
55916617Ssam 	setbp(addr);
56016617Ssam 	resume(DEFSIG);
56116617Ssam 	unsetbp(addr);
56216617Ssam 	if (catchbps) {
56316617Ssam 	    unsetallbps();
56416617Ssam 	}
56516617Ssam 	if (not isbperr()) {
56616617Ssam 	    printstatus();
56716617Ssam 	}
56816617Ssam     }
5699677Slinton }
5709677Slinton 
5719677Slinton /*
5729677Slinton  * Print the status of the process.
5739677Slinton  * This routine does not return.
5749677Slinton  */
5759677Slinton 
57633331Sdonn public printstatus ()
5779677Slinton {
57814395Slinton     int status;
57914395Slinton 
5809843Slinton     if (process->status == FINISHED) {
5819843Slinton 	exit(0);
5829843Slinton     } else {
58333331Sdonn 	if (runfirst) {
58433331Sdonn 	    fprintf(stderr, "\nEntering debugger ...\n");
58533331Sdonn 	    printheading();
58633331Sdonn 	    init();
58733331Sdonn 	}
58816617Ssam 	setcurfunc(whatblock(pc));
5899677Slinton 	getsrcpos();
5909843Slinton 	if (process->signo == SIGINT) {
5919843Slinton 	    isstopped = true;
5929843Slinton 	    printerror();
5939843Slinton 	} else if (isbperr() and isstopped) {
5949843Slinton 	    printf("stopped ");
59511172Slinton 	    printloc();
59611172Slinton 	    putchar('\n');
5979843Slinton 	    if (curline > 0) {
5989843Slinton 		printlines(curline, curline);
5999843Slinton 	    } else {
6009843Slinton 		printinst(pc, pc);
6019843Slinton 	    }
6029843Slinton 	    erecover();
6039677Slinton 	} else {
6049843Slinton 	    fixintr();
6059677Slinton 	    isstopped = true;
6069677Slinton 	    printerror();
6079677Slinton 	}
6089677Slinton     }
6099677Slinton }
6109677Slinton 
6119677Slinton /*
61211172Slinton  * Print out the current location in the debuggee.
61311172Slinton  */
61411172Slinton 
61511172Slinton public printloc()
61611172Slinton {
61711172Slinton     printf("in ");
61811172Slinton     printname(stdout, curfunc);
61911172Slinton     putchar(' ');
62014757Slinton     if (curline > 0 and not useInstLoc) {
62111172Slinton 	printsrcpos();
62211172Slinton     } else {
62314757Slinton 	useInstLoc = false;
62414757Slinton 	curline = 0;
62511172Slinton 	printf("at 0x%x", pc);
62611172Slinton     }
62711172Slinton }
62811172Slinton 
62911172Slinton /*
6309677Slinton  * Some functions for testing the state of the process.
6319677Slinton  */
6329677Slinton 
6339677Slinton public Boolean notstarted(p)
6349677Slinton Process p;
6359677Slinton {
6369677Slinton     return (Boolean) (p->status == NOTSTARTED);
6379677Slinton }
6389677Slinton 
6399677Slinton public Boolean isfinished(p)
6409677Slinton Process p;
6419677Slinton {
6429677Slinton     return (Boolean) (p->status == FINISHED);
6439677Slinton }
6449677Slinton 
6459677Slinton /*
64618230Slinton  * Predicate to test if the reason the process stopped was because
64718230Slinton  * of a breakpoint.  If so, as a side effect clear the local copy of
64818230Slinton  * signal handler associated with process.  We must do this so as to
64918230Slinton  * not confuse future stepping or continuing by possibly concluding
65018230Slinton  * the process should continue with a SIGTRAP handler.
6519677Slinton  */
6529677Slinton 
65318230Slinton public boolean isbperr()
65418230Slinton {
65518230Slinton     Process p;
65618230Slinton     boolean b;
65718230Slinton 
65818230Slinton     p = process;
65918230Slinton     if (p->status == STOPPED and p->signo == SIGTRAP) {
66018230Slinton 	b = true;
66118230Slinton 	p->sigstatus = 0;
66218230Slinton     } else {
66318230Slinton 	b = false;
66418230Slinton     }
66518230Slinton     return b;
66618230Slinton }
66718230Slinton 
66818230Slinton /*
66918230Slinton  * Return the signal number that stopped the process.
67018230Slinton  */
67118230Slinton 
67218230Slinton public integer errnum (p)
6739677Slinton Process p;
6749677Slinton {
6759677Slinton     return p->signo;
6769677Slinton }
6779677Slinton 
67818230Slinton /*
67918230Slinton  * Return the signal code associated with the signal.
68018230Slinton  */
68118230Slinton 
68218230Slinton public integer errcode (p)
68316931Ssam Process p;
68416931Ssam {
68516931Ssam     return p->sigcode;
68616931Ssam }
68716931Ssam 
6889677Slinton /*
6899677Slinton  * Return the termination code of the process.
6909677Slinton  */
6919677Slinton 
69218230Slinton public integer exitcode (p)
6939677Slinton Process p;
6949677Slinton {
6959677Slinton     return p->exitval;
6969677Slinton }
6979677Slinton 
6989677Slinton /*
6999677Slinton  * These routines are used to access the debuggee process from
7009677Slinton  * outside this module.
7019677Slinton  *
7029677Slinton  * They invoke "pio" which eventually leads to a call to "ptrace".
70314757Slinton  * The system generates an I/O error when a ptrace fails.  During reads
70414757Slinton  * these are ignored, during writes they are reported as an error, and
70514757Slinton  * for anything else they cause a fatal error.
7069677Slinton  */
7079677Slinton 
7089677Slinton extern Intfunc *onsyserr();
7099677Slinton 
7109677Slinton private badaddr;
71114757Slinton private read_err(), write_err();
7129677Slinton 
7139677Slinton /*
7149677Slinton  * Read from the process' instruction area.
7159677Slinton  */
7169677Slinton 
7179677Slinton public iread(buff, addr, nbytes)
7189677Slinton char *buff;
7199677Slinton Address addr;
7209677Slinton int nbytes;
7219677Slinton {
7229677Slinton     Intfunc *f;
7239677Slinton 
72414757Slinton     f = onsyserr(EIO, read_err);
7259677Slinton     badaddr = addr;
7269677Slinton     if (coredump) {
7279677Slinton 	coredump_readtext(buff, addr, nbytes);
7289677Slinton     } else {
7299677Slinton 	pio(process, PREAD, TEXTSEG, buff, addr, nbytes);
7309677Slinton     }
7319677Slinton     onsyserr(EIO, f);
7329677Slinton }
7339677Slinton 
7349677Slinton /*
7359677Slinton  * Write to the process' instruction area, usually in order to set
7369677Slinton  * or unset a breakpoint.
7379677Slinton  */
7389677Slinton 
7399677Slinton public iwrite(buff, addr, nbytes)
7409677Slinton char *buff;
7419677Slinton Address addr;
7429677Slinton int nbytes;
7439677Slinton {
7449677Slinton     Intfunc *f;
7459677Slinton 
7469677Slinton     if (coredump) {
7479677Slinton 	error("no process to write to");
7489677Slinton     }
74914757Slinton     f = onsyserr(EIO, write_err);
7509677Slinton     badaddr = addr;
7519677Slinton     pio(process, PWRITE, TEXTSEG, buff, addr, nbytes);
7529677Slinton     onsyserr(EIO, f);
7539677Slinton }
7549677Slinton 
7559677Slinton /*
7569677Slinton  * Read for the process' data area.
7579677Slinton  */
7589677Slinton 
7599677Slinton public dread(buff, addr, nbytes)
7609677Slinton char *buff;
7619677Slinton Address addr;
7629677Slinton int nbytes;
7639677Slinton {
7649677Slinton     Intfunc *f;
7659677Slinton 
7669677Slinton     badaddr = addr;
7679677Slinton     if (coredump) {
76818230Slinton 	f = onsyserr(EFAULT, read_err);
7699677Slinton 	coredump_readdata(buff, addr, nbytes);
77018230Slinton 	onsyserr(EFAULT, f);
7719677Slinton     } else {
77218230Slinton 	f = onsyserr(EIO, read_err);
7739677Slinton 	pio(process, PREAD, DATASEG, buff, addr, nbytes);
77418230Slinton 	onsyserr(EIO, f);
7759677Slinton     }
7769677Slinton }
7779677Slinton 
7789677Slinton /*
7799677Slinton  * Write to the process' data area.
7809677Slinton  */
7819677Slinton 
7829677Slinton public dwrite(buff, addr, nbytes)
7839677Slinton char *buff;
7849677Slinton Address addr;
7859677Slinton int nbytes;
7869677Slinton {
7879677Slinton     Intfunc *f;
7889677Slinton 
7899677Slinton     if (coredump) {
7909677Slinton 	error("no process to write to");
7919677Slinton     }
79214757Slinton     f = onsyserr(EIO, write_err);
7939677Slinton     badaddr = addr;
7949677Slinton     pio(process, PWRITE, DATASEG, buff, addr, nbytes);
7959677Slinton     onsyserr(EIO, f);
7969677Slinton }
7979677Slinton 
7989677Slinton /*
79914757Slinton  * Trap for errors in reading or writing to a process.
80014757Slinton  * The current approach is to "ignore" read errors and complain
80114757Slinton  * bitterly about write errors.
8029677Slinton  */
8039677Slinton 
80414757Slinton private read_err()
8059677Slinton {
80611560Slinton     /*
80714757Slinton      * Ignore.
80811560Slinton      */
8099677Slinton }
8109677Slinton 
81114757Slinton private write_err()
81214757Slinton {
81314757Slinton     error("can't write to process (address 0x%x)", badaddr);
81414757Slinton }
81514757Slinton 
8169677Slinton /*
8179677Slinton  * Ptrace interface.
8189677Slinton  */
8199677Slinton 
8209677Slinton #define WMASK           (~(sizeof(Word) - 1))
82133331Sdonn #define cachehash(addr) ((unsigned) ((addr >> 2) % CACHESIZE))
8229677Slinton 
8239677Slinton #define FIRSTSIG        SIGINT
8249677Slinton #define LASTSIG         SIGQUIT
8259677Slinton #define ischild(pid)    ((pid) == 0)
82618230Slinton #define traceme()       ptrace(0, 0, 0, 0)
8279677Slinton #define setrep(n)       (1 << ((n)-1))
8289677Slinton #define istraced(p)     (p->sigset&setrep(p->signo))
8299677Slinton 
8309677Slinton /*
83118230Slinton  * Ptrace options (specified in first argument).
83218230Slinton  */
83318230Slinton 
83418230Slinton #define UREAD   3       /* read from process's user structure */
83518230Slinton #define UWRITE  6       /* write to process's user structure */
83618230Slinton #define IREAD   1       /* read from process's instruction space */
83718230Slinton #define IWRITE  4       /* write to process's instruction space */
83818230Slinton #define DREAD   2       /* read from process's data space */
83918230Slinton #define DWRITE  5       /* write to process's data space */
84018230Slinton #define CONT    7       /* continue stopped process */
84118230Slinton #define SSTEP   9       /* continue for approximately one instruction */
84218230Slinton #define PKILL   8       /* terminate the process */
84318230Slinton 
84433331Sdonn #ifdef IRIS
84533331Sdonn #   define readreg(p, r)	ptrace(10, p->pid, r, 0)
84633331Sdonn #   define writereg(p, r, v)	ptrace(11, p->pid, r, v)
84733331Sdonn #else
84833331Sdonn #   define readreg(p, r)	ptrace(UREAD, p->pid, regloc(r), 0);
84933331Sdonn #   define writereg(p, r, v)	ptrace(UWRITE, p->pid, regloc(r), v);
85033331Sdonn #endif
85133331Sdonn 
85218230Slinton /*
8539677Slinton  * Start up a new process by forking and exec-ing the
8549677Slinton  * given argument list, returning when the process is loaded
8559677Slinton  * and ready to execute.  The PROCESS information (pointed to
8569677Slinton  * by the first argument) is appropriately filled.
8579677Slinton  *
8589677Slinton  * If the given PROCESS structure is associated with an already running
8599677Slinton  * process, we terminate it.
8609677Slinton  */
8619677Slinton 
8629677Slinton /* VARARGS2 */
8639677Slinton private pstart(p, argv, infile, outfile)
8649677Slinton Process p;
8659677Slinton String argv[];
8669677Slinton String infile;
8679677Slinton String outfile;
8689677Slinton {
8699677Slinton     int status;
8709677Slinton 
87116617Ssam     if (p->pid != 0) {
87216617Ssam 	pterm(p);
87318230Slinton 	cacheflush(p);
8749677Slinton     }
87518230Slinton     fflush(stdout);
8769677Slinton     psigtrace(p, SIGTRAP, true);
87733331Sdonn #   ifdef IRIS
87833331Sdonn 	p->pid = fork();
87933331Sdonn #   else
88033331Sdonn 	p->pid = vfork();
88133331Sdonn #   endif
88214395Slinton     if (p->pid == -1) {
8839677Slinton 	panic("can't fork");
8849677Slinton     }
8859677Slinton     if (ischild(p->pid)) {
88618230Slinton 	nocatcherrs();
8879677Slinton 	traceme();
8889677Slinton 	if (infile != nil) {
88916617Ssam 	    infrom(infile);
8909677Slinton 	}
8919677Slinton 	if (outfile != nil) {
89216617Ssam 	    outto(outfile);
8939677Slinton 	}
89411832Slinton 	execv(argv[0], argv);
89511172Slinton 	_exit(1);
8969677Slinton     }
8979677Slinton     pwait(p->pid, &status);
8989677Slinton     getinfo(p, status);
8999677Slinton     if (p->status != STOPPED) {
90018230Slinton 	beginerrmsg();
90118230Slinton 	fprintf(stderr, "warning: cannot execute %s\n", argv[0]);
90218230Slinton     } else {
90318230Slinton 	ptraced(p->pid);
9049677Slinton     }
9059677Slinton }
9069677Slinton 
9079677Slinton /*
90816617Ssam  * Terminate a ptrace'd process.
90916617Ssam  */
91016617Ssam 
91116617Ssam public pterm (p)
91216617Ssam Process p;
91316617Ssam {
91416617Ssam     integer status;
91516617Ssam 
91616617Ssam     if (p != nil and p->pid != 0) {
91718230Slinton 	ptrace(PKILL, p->pid, 0, 0);
91816617Ssam 	pwait(p->pid, &status);
91916617Ssam 	unptraced(p->pid);
92016617Ssam     }
92116617Ssam }
92216617Ssam 
92316617Ssam /*
92411867Slinton  * Continue a stopped process.  The first argument points to a Process
92511867Slinton  * structure.  Before the process is restarted it's user area is modified
92611867Slinton  * according to the values in the structure.  When this routine finishes,
9279677Slinton  * the structure has the new values from the process's user area.
9289677Slinton  *
9299677Slinton  * Pcont terminates when the process stops with a signal pending that
9309677Slinton  * is being traced (via psigtrace), or when the process terminates.
9319677Slinton  */
9329677Slinton 
93311867Slinton private pcont(p, signo)
9349677Slinton Process p;
93511867Slinton int signo;
9369677Slinton {
93716617Ssam     int s, status;
9389677Slinton 
9399677Slinton     if (p->pid == 0) {
94018230Slinton 	error("program is not active");
9419677Slinton     }
94216617Ssam     s = signo;
9439677Slinton     do {
94416617Ssam 	setinfo(p, s);
94516617Ssam 	if (traceexec) {
94616617Ssam 	    printf("!! pcont from 0x%x with signal %d (%d)\n",
94716617Ssam 		p->reg[PROGCTR], s, p->signo);
94816617Ssam 	    fflush(stdout);
94916617Ssam 	}
9509677Slinton 	sigs_off();
95118230Slinton 	if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) {
95214395Slinton 	    panic("error %d trying to continue process", errno);
9539677Slinton 	}
9549677Slinton 	pwait(p->pid, &status);
9559677Slinton 	sigs_on();
9569677Slinton 	getinfo(p, status);
95718230Slinton 	if (p->status == STOPPED and traceexec and not istraced(p)) {
95818230Slinton 	    printf("!! ignored signal %d at 0x%x\n",
95918230Slinton 		p->signo, p->reg[PROGCTR]);
96016617Ssam 	    fflush(stdout);
96116617Ssam 	}
96216617Ssam 	s = p->signo;
9639677Slinton     } while (p->status == STOPPED and not istraced(p));
96416617Ssam     if (traceexec) {
96516617Ssam 	printf("!! pcont to 0x%x on signal %d\n", p->reg[PROGCTR], p->signo);
96616617Ssam 	fflush(stdout);
96716617Ssam     }
9689677Slinton }
9699677Slinton 
9709677Slinton /*
9719677Slinton  * Single step as best ptrace can.
9729677Slinton  */
9739677Slinton 
97416617Ssam public pstep(p, signo)
9759677Slinton Process p;
97616617Ssam integer signo;
9779677Slinton {
97818230Slinton     int s, status;
9799677Slinton 
98018230Slinton     s = signo;
98118230Slinton     do {
98218230Slinton 	setinfo(p, s);
98318230Slinton 	if (traceexec) {
98418230Slinton 	    printf("!! pstep from 0x%x with signal %d (%d)\n",
98518230Slinton 		p->reg[PROGCTR], s, p->signo);
98618230Slinton 	    fflush(stdout);
98718230Slinton 	}
98818230Slinton 	sigs_off();
98918230Slinton 	if (ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo) < 0) {
99018230Slinton 	    panic("error %d trying to step process", errno);
99118230Slinton 	}
99218230Slinton 	pwait(p->pid, &status);
99318230Slinton 	sigs_on();
99418230Slinton 	getinfo(p, status);
99533331Sdonn #	if mc68000 || m68000
99633331Sdonn 	    if (p->status == STOPPED and p->signo == SIGTRAP) {
99733331Sdonn 		p->reg[PROGCTR] += 2;
99833331Sdonn 	    }
99933331Sdonn #	endif
100018230Slinton 	if (p->status == STOPPED and traceexec and not istraced(p)) {
100118230Slinton 	    printf("!! pstep ignored signal %d at 0x%x\n",
100218230Slinton 		p->signo, p->reg[PROGCTR]);
100318230Slinton 	    fflush(stdout);
100418230Slinton 	}
100518230Slinton 	s = p->signo;
100618230Slinton     } while (p->status == STOPPED and not istraced(p));
100716617Ssam     if (traceexec) {
100818230Slinton 	printf("!! pstep to 0x%x on signal %d\n",
100918230Slinton 	    p->reg[PROGCTR], p->signo);
101016617Ssam 	fflush(stdout);
101116617Ssam     }
101216617Ssam     if (p->status != STOPPED) {
101318230Slinton 	if (p->exitval == 0) {
101418230Slinton 	    error("program exited\n");
101518230Slinton 	} else {
101618230Slinton 	    error("program exited with code %d\n", p->exitval);
101718230Slinton 	}
101816617Ssam     }
10199677Slinton }
10209677Slinton 
10219677Slinton /*
10229677Slinton  * Return from execution when the given signal is pending.
10239677Slinton  */
10249677Slinton 
10259677Slinton public psigtrace(p, sig, sw)
10269677Slinton Process p;
10279677Slinton int sig;
10289677Slinton Boolean sw;
10299677Slinton {
10309677Slinton     if (sw) {
10319677Slinton 	p->sigset |= setrep(sig);
10329677Slinton     } else {
10339677Slinton 	p->sigset &= ~setrep(sig);
10349677Slinton     }
10359677Slinton }
10369677Slinton 
10379677Slinton /*
10389677Slinton  * Don't catch any signals.
10399677Slinton  * Particularly useful when letting a process finish uninhibited.
10409677Slinton  */
10419677Slinton 
10429677Slinton public unsetsigtraces(p)
10439677Slinton Process p;
10449677Slinton {
10459677Slinton     p->sigset = 0;
10469677Slinton }
10479677Slinton 
10489677Slinton /*
10499677Slinton  * Turn off attention to signals not being caught.
10509677Slinton  */
10519677Slinton 
10529677Slinton private Intfunc *sigfunc[NSIG];
10539677Slinton 
10549677Slinton private sigs_off()
10559677Slinton {
10569677Slinton     register int i;
10579677Slinton 
10589677Slinton     for (i = FIRSTSIG; i < LASTSIG; i++) {
10599677Slinton 	if (i != SIGKILL) {
10609677Slinton 	    sigfunc[i] = signal(i, SIG_IGN);
10619677Slinton 	}
10629677Slinton     }
10639677Slinton }
10649677Slinton 
10659677Slinton /*
10669677Slinton  * Turn back on attention to signals.
10679677Slinton  */
10689677Slinton 
10699677Slinton private sigs_on()
10709677Slinton {
10719677Slinton     register int i;
10729677Slinton 
10739677Slinton     for (i = FIRSTSIG; i < LASTSIG; i++) {
10749677Slinton 	if (i != SIGKILL) {
10759677Slinton 	    signal(i, sigfunc[i]);
10769677Slinton 	}
10779677Slinton     }
10789677Slinton }
10799677Slinton 
10809677Slinton /*
10819677Slinton  * Get process information from user area.
10829677Slinton  */
10839677Slinton 
108433331Sdonn private getinfo (p, status)
10859677Slinton register Process p;
10869677Slinton register int status;
10879677Slinton {
10889677Slinton     register int i;
108916617Ssam     Address addr;
10909677Slinton 
10919677Slinton     p->signo = (status&0177);
10929677Slinton     p->exitval = ((status >> 8)&0377);
10939677Slinton     if (p->signo != STOPPED) {
10949677Slinton 	p->status = FINISHED;
109514757Slinton 	p->pid = 0;
109616617Ssam 	p->reg[PROGCTR] = 0;
10979677Slinton     } else {
10989677Slinton 	p->status = p->signo;
10999677Slinton 	p->signo = p->exitval;
11009677Slinton 	p->exitval = 0;
110133331Sdonn #       ifdef IRIS
110233331Sdonn 	    p->mask = readreg(p, RPS);
110333331Sdonn #       else
110433331Sdonn 	    p->sigcode = ptrace(UREAD, p->pid, &((struct user *)0)->u_code, 0);
110533331Sdonn 	    p->mask = readreg(p, PS);
110633331Sdonn #       endif
11079677Slinton 	for (i = 0; i < NREG; i++) {
110833331Sdonn 	    p->reg[i] = readreg(p, rloc[i]);
11099677Slinton 	    p->oreg[i] = p->reg[i];
11109677Slinton 	}
111133331Sdonn #       ifdef mc68000
111233331Sdonn 	    if (p->status == STOPPED and p->signo == SIGTRAP and
111333331Sdonn 		p->reg[PROGCTR] > CODESTART
111433331Sdonn 	    ) {
111533331Sdonn 		p->reg[PROGCTR] -= 2;
111633331Sdonn 	    }
111733331Sdonn #       endif
111811768Slinton 	savetty(stdout, &(p->ttyinfo));
111916617Ssam 	addr = (Address) &(((struct user *) 0)->u_signal[p->signo]);
112018230Slinton 	p->sigstatus = (Address) ptrace(UREAD, p->pid, addr, 0);
11219677Slinton     }
11229677Slinton }
11239677Slinton 
11249677Slinton /*
11259677Slinton  * Set process's user area information from given process structure.
11269677Slinton  */
11279677Slinton 
112833331Sdonn private setinfo (p, signo)
11299677Slinton register Process p;
113011867Slinton int signo;
11319677Slinton {
11329677Slinton     register int i;
11339677Slinton     register int r;
11349677Slinton 
113514757Slinton     if (signo == DEFSIG) {
113616617Ssam 	if (istraced(p) and (p->sigstatus == 0 or p->sigstatus == 1)) {
113714757Slinton 	    p->signo = 0;
113814757Slinton 	}
113914757Slinton     } else {
114011867Slinton 	p->signo = signo;
11419677Slinton     }
11429677Slinton     for (i = 0; i < NREG; i++) {
11439677Slinton 	if ((r = p->reg[i]) != p->oreg[i]) {
114433331Sdonn 	    writereg(p, rloc[i], r);
11459677Slinton 	}
11469677Slinton     }
114711768Slinton     restoretty(stdout, &(p->ttyinfo));
11489677Slinton }
11499677Slinton 
11509677Slinton /*
115116617Ssam  * Return the address associated with the current signal.
115216617Ssam  * (Plus two since the address points to the beginning of a procedure).
115316617Ssam  */
115416617Ssam 
115516617Ssam public Address usignal (p)
115616617Ssam Process p;
115716617Ssam {
115816617Ssam     Address r;
115916617Ssam 
116016617Ssam     r = p->sigstatus;
116116617Ssam     if (r != 0 and r != 1) {
116233331Sdonn 	r += FUNCOFFSET;
116316617Ssam     }
116416617Ssam     return r;
116516617Ssam }
116616617Ssam 
116716617Ssam /*
11689677Slinton  * Structure for reading and writing by words, but dealing with bytes.
11699677Slinton  */
11709677Slinton 
11719677Slinton typedef union {
11729677Slinton     Word pword;
11739677Slinton     Byte pbyte[sizeof(Word)];
11749677Slinton } Pword;
11759677Slinton 
11769677Slinton /*
11779677Slinton  * Read (write) from (to) the process' address space.
11789677Slinton  * We must deal with ptrace's inability to look anywhere other
11799677Slinton  * than at a word boundary.
11809677Slinton  */
11819677Slinton 
11829677Slinton private Word fetch();
11839677Slinton private store();
11849677Slinton 
11859677Slinton private pio(p, op, seg, buff, addr, nbytes)
11869677Slinton Process p;
11879677Slinton PioOp op;
11889677Slinton PioSeg seg;
11899677Slinton char *buff;
11909677Slinton Address addr;
11919677Slinton int nbytes;
11929677Slinton {
11939677Slinton     register int i;
11949677Slinton     register Address newaddr;
11959677Slinton     register char *cp;
11969677Slinton     char *bufend;
11979677Slinton     Pword w;
11989677Slinton     Address wordaddr;
11999677Slinton     int byteoff;
12009677Slinton 
12019677Slinton     if (p->status != STOPPED) {
12029677Slinton 	error("program is not active");
12039677Slinton     }
12049677Slinton     cp = buff;
12059677Slinton     newaddr = addr;
12069677Slinton     wordaddr = (newaddr&WMASK);
12079677Slinton     if (wordaddr != newaddr) {
12089677Slinton 	w.pword = fetch(p, seg, wordaddr);
12099677Slinton 	for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) {
12109677Slinton 	    if (op == PREAD) {
12119677Slinton 		*cp++ = w.pbyte[i];
12129677Slinton 	    } else {
12139677Slinton 		w.pbyte[i] = *cp++;
12149677Slinton 	    }
12159677Slinton 	    nbytes--;
12169677Slinton 	}
12179677Slinton 	if (op == PWRITE) {
12189677Slinton 	    store(p, seg, wordaddr, w.pword);
12199677Slinton 	}
12209677Slinton 	newaddr = wordaddr + sizeof(Word);
12219677Slinton     }
12229677Slinton     byteoff = (nbytes&(~WMASK));
12239677Slinton     nbytes -= byteoff;
12249677Slinton     bufend = cp + nbytes;
122526333Ssam #ifdef tahoe
122626333Ssam     if (((int)cp)&WMASK) {
122726333Ssam 	/*
122826333Ssam 	 * Must copy a byte at a time, buffer not word addressable.
122926333Ssam 	 */
123026333Ssam 	while (cp < bufend) {
123126333Ssam 	    if (op == PREAD) {
123226333Ssam 		w.pword = fetch(p, seg, newaddr);
123326333Ssam 		for (i = 0; i < sizeof(Word); i++)
123426333Ssam 		    *cp++ = w.pbyte[i];
123526333Ssam 	    } else {
123626333Ssam 		for (i = 0; i < sizeof(Word); i++)
123726333Ssam 		    w.pbyte[i] = *cp++;
123826333Ssam 		store(p, seg, newaddr, w.pword);
123926333Ssam 	    }
124026333Ssam 	    newaddr += sizeof(Word);
124126333Ssam 	}
124226333Ssam     } else {
124326333Ssam     /*
124426333Ssam      * Buffer, word aligned, act normally...
124526333Ssam      */
124626333Ssam #endif
12479677Slinton     while (cp < bufend) {
12489677Slinton 	if (op == PREAD) {
12499677Slinton 	    *((Word *) cp) = fetch(p, seg, newaddr);
12509677Slinton 	} else {
12519677Slinton 	    store(p, seg, newaddr, *((Word *) cp));
12529677Slinton 	}
12539677Slinton 	cp += sizeof(Word);
12549677Slinton 	newaddr += sizeof(Word);
12559677Slinton     }
125626333Ssam #ifdef tahoe
125726333Ssam     }
125826333Ssam #endif
12599677Slinton     if (byteoff > 0) {
12609677Slinton 	w.pword = fetch(p, seg, newaddr);
12619677Slinton 	for (i = 0; i < byteoff; i++) {
12629677Slinton 	    if (op == PREAD) {
12639677Slinton 		*cp++ = w.pbyte[i];
12649677Slinton 	    } else {
12659677Slinton 		w.pbyte[i] = *cp++;
12669677Slinton 	    }
12679677Slinton 	}
12689677Slinton 	if (op == PWRITE) {
12699677Slinton 	    store(p, seg, newaddr, w.pword);
12709677Slinton 	}
12719677Slinton     }
12729677Slinton }
12739677Slinton 
12749677Slinton /*
12759677Slinton  * Get a word from a process at the given address.
12769677Slinton  * The address is assumed to be on a word boundary.
12779677Slinton  *
12789677Slinton  * A simple cache scheme is used to avoid redundant ptrace calls
12799677Slinton  * to the instruction space since it is assumed to be pure.
12809677Slinton  *
12819677Slinton  * It is necessary to use a write-through scheme so that
12829677Slinton  * breakpoints right next to each other don't interfere.
12839677Slinton  */
12849677Slinton 
12859677Slinton private Integer nfetchs, nreads, nwrites;
12869677Slinton 
12879677Slinton private Word fetch(p, seg, addr)
12889677Slinton Process p;
12899677Slinton PioSeg seg;
12909677Slinton register int addr;
12919677Slinton {
12929677Slinton     register CacheWord *wp;
12939677Slinton     register Word w;
12949677Slinton 
12959677Slinton     switch (seg) {
12969677Slinton 	case TEXTSEG:
12979677Slinton 	    ++nfetchs;
12989677Slinton 	    wp = &p->word[cachehash(addr)];
12999677Slinton 	    if (addr == 0 or wp->addr != addr) {
13009677Slinton 		++nreads;
130118230Slinton 		w = ptrace(IREAD, p->pid, addr, 0);
13029677Slinton 		wp->addr = addr;
13039677Slinton 		wp->val = w;
13049677Slinton 	    } else {
13059677Slinton 		w = wp->val;
13069677Slinton 	    }
13079677Slinton 	    break;
13089677Slinton 
13099677Slinton 	case DATASEG:
131018230Slinton 	    w = ptrace(DREAD, p->pid, addr, 0);
13119677Slinton 	    break;
13129677Slinton 
13139677Slinton 	default:
13149677Slinton 	    panic("fetch: bad seg %d", seg);
13159677Slinton 	    /* NOTREACHED */
13169677Slinton     }
13179677Slinton     return w;
13189677Slinton }
13199677Slinton 
13209677Slinton /*
13219677Slinton  * Put a word into the process' address space at the given address.
13229677Slinton  * The address is assumed to be on a word boundary.
13239677Slinton  */
13249677Slinton 
13259677Slinton private store(p, seg, addr, data)
13269677Slinton Process p;
13279677Slinton PioSeg seg;
13289677Slinton int addr;
13299677Slinton Word data;
13309677Slinton {
13319677Slinton     register CacheWord *wp;
13329677Slinton 
13339677Slinton     switch (seg) {
13349677Slinton 	case TEXTSEG:
13359677Slinton 	    ++nwrites;
13369677Slinton 	    wp = &p->word[cachehash(addr)];
13379677Slinton 	    wp->addr = addr;
13389677Slinton 	    wp->val = data;
133918230Slinton 	    ptrace(IWRITE, p->pid, addr, data);
13409677Slinton 	    break;
13419677Slinton 
13429677Slinton 	case DATASEG:
134318230Slinton 	    ptrace(DWRITE, p->pid, addr, data);
13449677Slinton 	    break;
13459677Slinton 
13469677Slinton 	default:
13479677Slinton 	    panic("store: bad seg %d", seg);
13489677Slinton 	    /* NOTREACHED */
13499677Slinton     }
13509677Slinton }
13519677Slinton 
135218230Slinton /*
135318230Slinton  * Flush the instruction cache associated with a process.
135418230Slinton  */
135518230Slinton 
135618230Slinton private cacheflush (p)
135718230Slinton Process p;
135818230Slinton {
135918230Slinton     bzero(p->word, sizeof(p->word));
136018230Slinton }
136118230Slinton 
13629677Slinton public printptraceinfo()
13639677Slinton {
13649677Slinton     printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites);
13659677Slinton }
13669677Slinton 
13679677Slinton /*
136816617Ssam  * Redirect input.
136916617Ssam  * Assuming this is called from a child, we should be careful to avoid
137016617Ssam  * (possibly) shared standard I/O buffers.
13719677Slinton  */
13729677Slinton 
137316617Ssam private infrom (filename)
137416617Ssam String filename;
137516617Ssam {
137616617Ssam     Fileid in;
137716617Ssam 
137816617Ssam     in = open(filename, 0);
137916617Ssam     if (in == -1) {
138016617Ssam 	write(2, "can't read ", 11);
138116617Ssam 	write(2, filename, strlen(filename));
138216617Ssam 	write(2, "\n", 1);
138316617Ssam 	_exit(1);
138416617Ssam     }
138516617Ssam     fswap(0, in);
138616617Ssam }
138716617Ssam 
138816617Ssam /*
138916617Ssam  * Redirect standard output.
139016617Ssam  * Same assumptions as for "infrom" above.
139116617Ssam  */
139216617Ssam 
139316617Ssam private outto (filename)
139416617Ssam String filename;
139516617Ssam {
139616617Ssam     Fileid out;
139716617Ssam 
139816617Ssam     out = creat(filename, 0666);
139916617Ssam     if (out == -1) {
140016617Ssam 	write(2, "can't write ", 12);
140116617Ssam 	write(2, filename, strlen(filename));
140216617Ssam 	write(2, "\n", 1);
140316617Ssam 	_exit(1);
140416617Ssam     }
140516617Ssam     fswap(1, out);
140616617Ssam }
140716617Ssam 
140816617Ssam /*
140916617Ssam  * Swap file numbers, useful for redirecting standard input or output.
141016617Ssam  */
141116617Ssam 
14129677Slinton private fswap(oldfd, newfd)
141316617Ssam Fileid oldfd;
141416617Ssam Fileid newfd;
14159677Slinton {
14169677Slinton     if (oldfd != newfd) {
14179677Slinton 	close(oldfd);
14189677Slinton 	dup(newfd);
14199677Slinton 	close(newfd);
14209677Slinton     }
14219677Slinton }
142216928Ssam 
142316928Ssam /*
142418230Slinton  * Signal name manipulation.
142516928Ssam  */
142618230Slinton 
142718230Slinton private String signames[NSIG] = {
142818230Slinton     0,
142918230Slinton     "HUP", "INT", "QUIT", "ILL", "TRAP",
143018230Slinton     "IOT", "EMT", "FPE", "KILL", "BUS",
143118230Slinton     "SEGV", "SYS", "PIPE", "ALRM", "TERM",
143218230Slinton     0, "STOP", "TSTP", "CONT", "CHLD",
143318230Slinton     "TTIN", "TTOU", "TINT", "XCPU", "XFSZ",
143426333Ssam     "VTALRM", "PROF", "WINCH", "USR1", "USR2"
143516928Ssam };
143616928Ssam 
143716928Ssam /*
143818230Slinton  * Get the signal number associated with a given name.
143918230Slinton  * The name is first translated to upper case if necessary.
144016928Ssam  */
144118230Slinton 
144218230Slinton public integer siglookup (s)
144316928Ssam String s;
144416928Ssam {
144518230Slinton     register char *p, *q;
144618230Slinton     char buf[100];
144718230Slinton     integer i;
144816928Ssam 
144918230Slinton     p = s;
145018230Slinton     q = buf;
145118230Slinton     while (*p != '\0') {
145218230Slinton 	if (*p >= 'a' and *p <= 'z') {
145318230Slinton 	    *q = (*p - 'a') + 'A';
145418230Slinton 	} else {
145518230Slinton 	    *q = *p;
145618230Slinton 	}
145718230Slinton 	++p;
145818230Slinton 	++q;
145918230Slinton     }
146018230Slinton     *q = '\0';
146118230Slinton     p = buf;
146218230Slinton     if (buf[0] == 'S' and buf[1] == 'I' and buf[2] == 'G') {
146318230Slinton 	p += 3;
146418230Slinton     }
146518230Slinton     i = 1;
146618230Slinton     for (;;) {
146718230Slinton 	if (i >= sizeof(signames) div sizeof(signames[0])) {
146818230Slinton 	    error("signal \"%s\" unknown", s);
146918230Slinton 	    i = 0;
147018230Slinton 	    break;
147118230Slinton 	}
147218230Slinton 	if (signames[i] != nil and streq(signames[i], p)) {
147318230Slinton 	    break;
147418230Slinton 	}
147518230Slinton 	++i;
147618230Slinton     }
147718230Slinton     return i;
147816928Ssam }
147916928Ssam 
148016928Ssam /*
148118230Slinton  * Print all signals being ignored by the debugger.
148218230Slinton  * These signals are auotmatically
148316928Ssam  * passed on to the debugged process.
148416928Ssam  */
148518230Slinton 
148618230Slinton public printsigsignored (p)
148716931Ssam Process p;
148816928Ssam {
148916931Ssam     printsigs(~p->sigset);
149016928Ssam }
149116928Ssam 
149216928Ssam /*
149316928Ssam  * Print all signals being intercepted by
149416928Ssam  * the debugger for the specified process.
149516928Ssam  */
149618230Slinton 
149716931Ssam public printsigscaught(p)
149816931Ssam Process p;
149916928Ssam {
150016931Ssam     printsigs(p->sigset);
150116931Ssam }
150216931Ssam 
150318230Slinton private printsigs (set)
150418230Slinton integer set;
150516931Ssam {
150618230Slinton     integer s;
150718230Slinton     char separator[2];
150816931Ssam 
150918230Slinton     separator[0] = '\0';
151018230Slinton     for (s = 1; s < sizeof(signames) div sizeof(signames[0]); s++) {
151118230Slinton 	if (set & setrep(s)) {
151218230Slinton 	    if (signames[s] != nil) {
151318230Slinton 		printf("%s%s", separator, signames[s]);
151418230Slinton 		separator[0] = ' ';
151518230Slinton 		separator[1] = '\0';
151618230Slinton 	    }
151716928Ssam 	}
151818230Slinton     }
151918230Slinton     if (separator[0] == ' ') {
152016931Ssam 	putchar('\n');
152116931Ssam     }
152216928Ssam }
1523