xref: /csrg-svn/old/dbx/process.c (revision 9677)
1*9677Slinton /* Copyright (c) 1982 Regents of the University of California */
2*9677Slinton 
3*9677Slinton static char sccsid[] = "@(#)@(#)process.c 1.1 12/15/82";
4*9677Slinton 
5*9677Slinton /*
6*9677Slinton  * Process management.
7*9677Slinton  *
8*9677Slinton  * This module contains the routines to manage the execution and
9*9677Slinton  * tracing of the debuggee process.
10*9677Slinton  */
11*9677Slinton 
12*9677Slinton #include "defs.h"
13*9677Slinton #include "process.h"
14*9677Slinton #include "machine.h"
15*9677Slinton #include "events.h"
16*9677Slinton #include "tree.h"
17*9677Slinton #include "operators.h"
18*9677Slinton #include "source.h"
19*9677Slinton #include "object.h"
20*9677Slinton #include "mappings.h"
21*9677Slinton #include "main.h"
22*9677Slinton #include "coredump.h"
23*9677Slinton #include <signal.h>
24*9677Slinton #include <errno.h>
25*9677Slinton #include <sys/param.h>
26*9677Slinton #include <sys/reg.h>
27*9677Slinton #include <sys/stat.h>
28*9677Slinton 
29*9677Slinton #ifndef public
30*9677Slinton 
31*9677Slinton typedef struct Process *Process;
32*9677Slinton 
33*9677Slinton Process process;
34*9677Slinton 
35*9677Slinton #include "machine.h"
36*9677Slinton 
37*9677Slinton #endif
38*9677Slinton 
39*9677Slinton #define NOTSTARTED 1
40*9677Slinton #define STOPPED 0177
41*9677Slinton #define FINISHED 0
42*9677Slinton 
43*9677Slinton /*
44*9677Slinton  * Cache-ing of instruction segment is done to reduce the number
45*9677Slinton  * of system calls.
46*9677Slinton  */
47*9677Slinton 
48*9677Slinton #define CSIZE 1003       /* size of instruction cache */
49*9677Slinton 
50*9677Slinton typedef struct {
51*9677Slinton     Word addr;
52*9677Slinton     Word val;
53*9677Slinton } CacheWord;
54*9677Slinton 
55*9677Slinton /*
56*9677Slinton  * This structure holds the information we need from the user structure.
57*9677Slinton  */
58*9677Slinton 
59*9677Slinton struct Process {
60*9677Slinton     int pid;			/* process being traced */
61*9677Slinton     int mask;			/* ps */
62*9677Slinton     Word reg[NREG];		/* process's registers */
63*9677Slinton     Word oreg[NREG];		/* registers when process last stopped */
64*9677Slinton     short status;		/* either STOPPED or FINISHED */
65*9677Slinton     short signo;		/* signal that stopped process */
66*9677Slinton     int exitval;		/* return value from exit() */
67*9677Slinton     long sigset;		/* bit array of traced signals */
68*9677Slinton     CacheWord word[CSIZE];	/* text segment cache */
69*9677Slinton };
70*9677Slinton 
71*9677Slinton /*
72*9677Slinton  * These definitions are for the arguments to "pio".
73*9677Slinton  */
74*9677Slinton 
75*9677Slinton typedef enum { PREAD, PWRITE } PioOp;
76*9677Slinton typedef enum { TEXTSEG, DATASEG } PioSeg;
77*9677Slinton 
78*9677Slinton private struct Process pbuf;
79*9677Slinton 
80*9677Slinton #define MAXNCMDARGS 10         /* maximum number of arguments to RUN */
81*9677Slinton 
82*9677Slinton private Boolean just_started;
83*9677Slinton private int argc;
84*9677Slinton private String argv[MAXNCMDARGS];
85*9677Slinton private String infile, outfile;
86*9677Slinton 
87*9677Slinton /*
88*9677Slinton  * Initialize process information.
89*9677Slinton  */
90*9677Slinton 
91*9677Slinton public process_init()
92*9677Slinton {
93*9677Slinton     register Integer i;
94*9677Slinton     Char buf[10];
95*9677Slinton 
96*9677Slinton     process = &pbuf;
97*9677Slinton     process->status = (coredump) ? STOPPED : NOTSTARTED;
98*9677Slinton     setsigtrace();
99*9677Slinton     for (i = 0; i < NREG; i++) {
100*9677Slinton 	sprintf(buf, "$r%d", i);
101*9677Slinton 	defregname(identname(buf, false), i);
102*9677Slinton     }
103*9677Slinton     defregname(identname("$ap", true), ARGP);
104*9677Slinton     defregname(identname("$fp", true), FRP);
105*9677Slinton     defregname(identname("$sp", true), STKP);
106*9677Slinton     defregname(identname("$pc", true), PROGCTR);
107*9677Slinton     if (coredump) {
108*9677Slinton 	coredump_readin(process->mask, process->reg, process->signo);
109*9677Slinton     }
110*9677Slinton }
111*9677Slinton 
112*9677Slinton /*
113*9677Slinton  * Routines to get at process information from outside this module.
114*9677Slinton  */
115*9677Slinton 
116*9677Slinton public Word reg(n)
117*9677Slinton Integer n;
118*9677Slinton {
119*9677Slinton     register Word w;
120*9677Slinton 
121*9677Slinton     if (n == NREG) {
122*9677Slinton 	w = process->mask;
123*9677Slinton     } else {
124*9677Slinton 	w = process->reg[n];
125*9677Slinton     }
126*9677Slinton     return w;
127*9677Slinton }
128*9677Slinton 
129*9677Slinton public setreg(n, w)
130*9677Slinton Integer n;
131*9677Slinton Word w;
132*9677Slinton {
133*9677Slinton     process->reg[n] = w;
134*9677Slinton }
135*9677Slinton 
136*9677Slinton /*
137*9677Slinton  * Begin execution.
138*9677Slinton  *
139*9677Slinton  * We set a breakpoint at the end of the code so that the
140*9677Slinton  * process data doesn't disappear after the program terminates.
141*9677Slinton  */
142*9677Slinton 
143*9677Slinton private Boolean remade();
144*9677Slinton 
145*9677Slinton public start(argv, infile, outfile)
146*9677Slinton String argv[];
147*9677Slinton String infile, outfile;
148*9677Slinton {
149*9677Slinton     String pargv[4];
150*9677Slinton     Node cond;
151*9677Slinton 
152*9677Slinton     if (coredump) {
153*9677Slinton 	coredump = false;
154*9677Slinton 	fclose(corefile);
155*9677Slinton 	coredump_close();
156*9677Slinton     }
157*9677Slinton     if (argv == nil) {
158*9677Slinton 	argv = pargv;
159*9677Slinton 	pargv[0] = objname;
160*9677Slinton 	pargv[1] = nil;
161*9677Slinton     } else {
162*9677Slinton 	argv[argc] = nil;
163*9677Slinton     }
164*9677Slinton     if (remade(objname)) {
165*9677Slinton 	reinit(argv, infile, outfile);
166*9677Slinton     }
167*9677Slinton     pstart(process, argv, infile, outfile);
168*9677Slinton     if (process->status == STOPPED) {
169*9677Slinton 	pc = 0;
170*9677Slinton 	curfunc = program;
171*9677Slinton 	if (objsize != 0) {
172*9677Slinton 	    cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr()));
173*9677Slinton 	    event_once(cond, buildcmdlist(build(O_ENDX)));
174*9677Slinton 	}
175*9677Slinton     }
176*9677Slinton }
177*9677Slinton 
178*9677Slinton /*
179*9677Slinton  * Check to see if the object file has changed since the symbolic
180*9677Slinton  * information last was read.
181*9677Slinton  */
182*9677Slinton 
183*9677Slinton private time_t modtime;
184*9677Slinton 
185*9677Slinton private Boolean remade(filename)
186*9677Slinton String filename;
187*9677Slinton {
188*9677Slinton     struct stat s;
189*9677Slinton     Boolean b;
190*9677Slinton 
191*9677Slinton     stat(filename, &s);
192*9677Slinton     b = (Boolean) (modtime != 0 and modtime < s.st_mtime);
193*9677Slinton     modtime = s.st_mtime;
194*9677Slinton     return b;
195*9677Slinton }
196*9677Slinton 
197*9677Slinton /*
198*9677Slinton  * Set up what signals we want to trace.
199*9677Slinton  */
200*9677Slinton 
201*9677Slinton private setsigtrace()
202*9677Slinton {
203*9677Slinton     register Integer i;
204*9677Slinton     register Process p;
205*9677Slinton 
206*9677Slinton     p = process;
207*9677Slinton     for (i = 1; i <= NSIG; i++) {
208*9677Slinton 	psigtrace(p, i, true);
209*9677Slinton     }
210*9677Slinton     psigtrace(p, SIGHUP, false);
211*9677Slinton     psigtrace(p, SIGKILL, false);
212*9677Slinton     psigtrace(p, SIGALRM, false);
213*9677Slinton     psigtrace(p, SIGTSTP, false);
214*9677Slinton     psigtrace(p, SIGCONT, false);
215*9677Slinton     psigtrace(p, SIGCHLD, false);
216*9677Slinton }
217*9677Slinton 
218*9677Slinton /*
219*9677Slinton  * Initialize the argument list.
220*9677Slinton  */
221*9677Slinton 
222*9677Slinton public arginit()
223*9677Slinton {
224*9677Slinton     infile = nil;
225*9677Slinton     outfile = nil;
226*9677Slinton     argv[0] = objname;
227*9677Slinton     argc = 1;
228*9677Slinton }
229*9677Slinton 
230*9677Slinton /*
231*9677Slinton  * Add an argument to the list for the debuggee.
232*9677Slinton  */
233*9677Slinton 
234*9677Slinton public newarg(arg)
235*9677Slinton String arg;
236*9677Slinton {
237*9677Slinton     if (argc >= MAXNCMDARGS) {
238*9677Slinton 	error("too many arguments");
239*9677Slinton     }
240*9677Slinton     argv[argc++] = arg;
241*9677Slinton }
242*9677Slinton 
243*9677Slinton /*
244*9677Slinton  * Set the standard input for the debuggee.
245*9677Slinton  */
246*9677Slinton 
247*9677Slinton public inarg(filename)
248*9677Slinton String filename;
249*9677Slinton {
250*9677Slinton     if (infile != nil) {
251*9677Slinton 	error("multiple input redirects");
252*9677Slinton     }
253*9677Slinton     infile = filename;
254*9677Slinton }
255*9677Slinton 
256*9677Slinton /*
257*9677Slinton  * Set the standard output for the debuggee.
258*9677Slinton  * Probably should check to avoid overwriting an existing file.
259*9677Slinton  */
260*9677Slinton 
261*9677Slinton public outarg(filename)
262*9677Slinton String filename;
263*9677Slinton {
264*9677Slinton     if (outfile != nil) {
265*9677Slinton 	error("multiple output redirect");
266*9677Slinton     }
267*9677Slinton     outfile = filename;
268*9677Slinton }
269*9677Slinton 
270*9677Slinton /*
271*9677Slinton  * Start debuggee executing.
272*9677Slinton  */
273*9677Slinton 
274*9677Slinton public run()
275*9677Slinton {
276*9677Slinton     process->status = STOPPED;
277*9677Slinton     fixbps();
278*9677Slinton     curline = 0;
279*9677Slinton     start(argv, infile, outfile);
280*9677Slinton     just_started = true;
281*9677Slinton     isstopped = false;
282*9677Slinton     cont();
283*9677Slinton }
284*9677Slinton 
285*9677Slinton /*
286*9677Slinton  * Continue execution wherever we left off.
287*9677Slinton  *
288*9677Slinton  * Note that this routine never returns.  Eventually bpact() will fail
289*9677Slinton  * and we'll call printstatus or step will call it.
290*9677Slinton  */
291*9677Slinton 
292*9677Slinton typedef int Intfunc();
293*9677Slinton 
294*9677Slinton private Intfunc *dbintr;
295*9677Slinton private intr();
296*9677Slinton 
297*9677Slinton #define succeeds    == true
298*9677Slinton #define fails       == false
299*9677Slinton 
300*9677Slinton public cont()
301*9677Slinton {
302*9677Slinton     dbintr = signal(SIGINT, intr);
303*9677Slinton     if (just_started) {
304*9677Slinton 	just_started = false;
305*9677Slinton     } else {
306*9677Slinton 	if (not isstopped) {
307*9677Slinton 	    error("can't continue execution");
308*9677Slinton 	}
309*9677Slinton 	isstopped = false;
310*9677Slinton 	step();
311*9677Slinton     }
312*9677Slinton     for (;;) {
313*9677Slinton 	if (single_stepping) {
314*9677Slinton 	    printnews();
315*9677Slinton 	} else {
316*9677Slinton 	    setallbps();
317*9677Slinton 	    resume();
318*9677Slinton 	    unsetallbps();
319*9677Slinton 	    if (bpact() fails) {
320*9677Slinton 		printstatus();
321*9677Slinton 	    }
322*9677Slinton 	}
323*9677Slinton 	step();
324*9677Slinton     }
325*9677Slinton     /* NOTREACHED */
326*9677Slinton }
327*9677Slinton 
328*9677Slinton /*
329*9677Slinton  * This routine is called if we get an interrupt while "running" px
330*9677Slinton  * but actually in the debugger.  Could happen, for example, while
331*9677Slinton  * processing breakpoints.
332*9677Slinton  *
333*9677Slinton  * We basically just want to keep going; the assumption is
334*9677Slinton  * that when the process resumes it will get the interrupt
335*9677Slinton  * which will then be handled.
336*9677Slinton  */
337*9677Slinton 
338*9677Slinton private intr()
339*9677Slinton {
340*9677Slinton     signal(SIGINT, intr);
341*9677Slinton }
342*9677Slinton 
343*9677Slinton public fixintr()
344*9677Slinton {
345*9677Slinton     signal(SIGINT, dbintr);
346*9677Slinton }
347*9677Slinton 
348*9677Slinton /*
349*9677Slinton  * Resume execution.
350*9677Slinton  */
351*9677Slinton 
352*9677Slinton public resume()
353*9677Slinton {
354*9677Slinton     register Process p;
355*9677Slinton 
356*9677Slinton     p = process;
357*9677Slinton     if (traceexec) {
358*9677Slinton 	printf("execution resumes at pc 0x%x\n", process->reg[PROGCTR]);
359*9677Slinton 	fflush(stdout);
360*9677Slinton     }
361*9677Slinton     pcont(p);
362*9677Slinton     pc = process->reg[PROGCTR];
363*9677Slinton     if (traceexec) {
364*9677Slinton 	printf("execution stops at pc 0x%x on sig %d\n",
365*9677Slinton 	    process->reg[PROGCTR], p->signo);
366*9677Slinton 	fflush(stdout);
367*9677Slinton     }
368*9677Slinton }
369*9677Slinton 
370*9677Slinton /*
371*9677Slinton  * Continue execution up to the next source line.
372*9677Slinton  *
373*9677Slinton  * There are two ways to define the next source line depending on what
374*9677Slinton  * is desired when a procedure or function call is encountered.  Step
375*9677Slinton  * stops at the beginning of the procedure or call; next skips over it.
376*9677Slinton  */
377*9677Slinton 
378*9677Slinton /*
379*9677Slinton  * Stepc is what is called when the step command is given.
380*9677Slinton  * It has to play with the "isstopped" information.
381*9677Slinton  */
382*9677Slinton 
383*9677Slinton public stepc()
384*9677Slinton {
385*9677Slinton     if (not isstopped) {
386*9677Slinton 	error("can't continue execution");
387*9677Slinton     }
388*9677Slinton     isstopped = false;
389*9677Slinton     dostep(false);
390*9677Slinton     isstopped = true;
391*9677Slinton }
392*9677Slinton 
393*9677Slinton public next()
394*9677Slinton {
395*9677Slinton     if (not isstopped) {
396*9677Slinton 	error("can't continue execution");
397*9677Slinton     }
398*9677Slinton     isstopped = false;
399*9677Slinton     dostep(true);
400*9677Slinton     isstopped = true;
401*9677Slinton }
402*9677Slinton 
403*9677Slinton public step()
404*9677Slinton {
405*9677Slinton     dostep(false);
406*9677Slinton }
407*9677Slinton 
408*9677Slinton /*
409*9677Slinton  * Resume execution up to the given address.  It is assumed that
410*9677Slinton  * no breakpoints exist between the current address and the one
411*9677Slinton  * we're stepping to.  This saves us from setting all the breakpoints.
412*9677Slinton  */
413*9677Slinton 
414*9677Slinton public stepto(addr)
415*9677Slinton Address addr;
416*9677Slinton {
417*9677Slinton     setbp(addr);
418*9677Slinton     resume();
419*9677Slinton     unsetbp(addr);
420*9677Slinton     if (not isbperr()) {
421*9677Slinton 	printstatus();
422*9677Slinton     }
423*9677Slinton }
424*9677Slinton 
425*9677Slinton /*
426*9677Slinton  * Print the status of the process.
427*9677Slinton  * This routine does not return.
428*9677Slinton  */
429*9677Slinton 
430*9677Slinton public printstatus()
431*9677Slinton {
432*9677Slinton     curfunc = whatblock(pc);
433*9677Slinton     if (process->signo == SIGINT) {
434*9677Slinton 	isstopped = true;
435*9677Slinton 	printerror();
436*9677Slinton     }
437*9677Slinton     if (isbperr() and isstopped) {
438*9677Slinton 	printf("stopped ");
439*9677Slinton 	getsrcpos();
440*9677Slinton 	if (curline > 0) {
441*9677Slinton 	    printsrcpos();
442*9677Slinton 	    putchar('\n');
443*9677Slinton 	    printlines(curline, curline);
444*9677Slinton 	} else {
445*9677Slinton 	    printf("in ");
446*9677Slinton 	    printwhich(stdout, curfunc);
447*9677Slinton 	    printf(" at 0x%x\n", pc);
448*9677Slinton 	    printinst(pc, pc);
449*9677Slinton 	}
450*9677Slinton 	erecover();
451*9677Slinton     } else {
452*9677Slinton 	fixbps();
453*9677Slinton 	fixintr();
454*9677Slinton 	if (process->status == FINISHED) {
455*9677Slinton 	    exit(0);
456*9677Slinton 	} else {
457*9677Slinton 	    isstopped = true;
458*9677Slinton 	    printerror();
459*9677Slinton 	}
460*9677Slinton     }
461*9677Slinton }
462*9677Slinton 
463*9677Slinton /*
464*9677Slinton  * Some functions for testing the state of the process.
465*9677Slinton  */
466*9677Slinton 
467*9677Slinton public Boolean notstarted(p)
468*9677Slinton Process p;
469*9677Slinton {
470*9677Slinton     return (Boolean) (p->status == NOTSTARTED);
471*9677Slinton }
472*9677Slinton 
473*9677Slinton public Boolean isfinished(p)
474*9677Slinton Process p;
475*9677Slinton {
476*9677Slinton     return (Boolean) (p->status == FINISHED);
477*9677Slinton }
478*9677Slinton 
479*9677Slinton /*
480*9677Slinton  * Return the signal number which stopped the process.
481*9677Slinton  */
482*9677Slinton 
483*9677Slinton public Integer errnum(p)
484*9677Slinton Process p;
485*9677Slinton {
486*9677Slinton     return p->signo;
487*9677Slinton }
488*9677Slinton 
489*9677Slinton /*
490*9677Slinton  * Return the termination code of the process.
491*9677Slinton  */
492*9677Slinton 
493*9677Slinton public Integer exitcode(p)
494*9677Slinton Process p;
495*9677Slinton {
496*9677Slinton     return p->exitval;
497*9677Slinton }
498*9677Slinton 
499*9677Slinton /*
500*9677Slinton  * These routines are used to access the debuggee process from
501*9677Slinton  * outside this module.
502*9677Slinton  *
503*9677Slinton  * They invoke "pio" which eventually leads to a call to "ptrace".
504*9677Slinton  * The system generates an I/O error when a ptrace fails, we catch
505*9677Slinton  * that here and assume its due to a misguided address.
506*9677Slinton  */
507*9677Slinton 
508*9677Slinton extern Intfunc *onsyserr();
509*9677Slinton 
510*9677Slinton private badaddr;
511*9677Slinton private rwerr();
512*9677Slinton 
513*9677Slinton /*
514*9677Slinton  * Read from the process' instruction area.
515*9677Slinton  */
516*9677Slinton 
517*9677Slinton public iread(buff, addr, nbytes)
518*9677Slinton char *buff;
519*9677Slinton Address addr;
520*9677Slinton int nbytes;
521*9677Slinton {
522*9677Slinton     Intfunc *f;
523*9677Slinton 
524*9677Slinton     f = onsyserr(EIO, rwerr);
525*9677Slinton     badaddr = addr;
526*9677Slinton     if (coredump) {
527*9677Slinton 	coredump_readtext(buff, addr, nbytes);
528*9677Slinton     } else {
529*9677Slinton 	pio(process, PREAD, TEXTSEG, buff, addr, nbytes);
530*9677Slinton     }
531*9677Slinton     onsyserr(EIO, f);
532*9677Slinton }
533*9677Slinton 
534*9677Slinton /*
535*9677Slinton  * Write to the process' instruction area, usually in order to set
536*9677Slinton  * or unset a breakpoint.
537*9677Slinton  */
538*9677Slinton 
539*9677Slinton public iwrite(buff, addr, nbytes)
540*9677Slinton char *buff;
541*9677Slinton Address addr;
542*9677Slinton int nbytes;
543*9677Slinton {
544*9677Slinton     Intfunc *f;
545*9677Slinton 
546*9677Slinton     if (coredump) {
547*9677Slinton 	error("no process to write to");
548*9677Slinton     }
549*9677Slinton     f = onsyserr(EIO, rwerr);
550*9677Slinton     badaddr = addr;
551*9677Slinton     pio(process, PWRITE, TEXTSEG, buff, addr, nbytes);
552*9677Slinton     onsyserr(EIO, f);
553*9677Slinton }
554*9677Slinton 
555*9677Slinton /*
556*9677Slinton  * Read for the process' data area.
557*9677Slinton  */
558*9677Slinton 
559*9677Slinton public dread(buff, addr, nbytes)
560*9677Slinton char *buff;
561*9677Slinton Address addr;
562*9677Slinton int nbytes;
563*9677Slinton {
564*9677Slinton     Intfunc *f;
565*9677Slinton 
566*9677Slinton     f = onsyserr(EIO, rwerr);
567*9677Slinton     badaddr = addr;
568*9677Slinton     if (coredump) {
569*9677Slinton 	coredump_readdata(buff, addr, nbytes);
570*9677Slinton     } else {
571*9677Slinton 	pio(process, PREAD, DATASEG, buff, addr, nbytes);
572*9677Slinton     }
573*9677Slinton     onsyserr(EIO, f);
574*9677Slinton }
575*9677Slinton 
576*9677Slinton /*
577*9677Slinton  * Write to the process' data area.
578*9677Slinton  */
579*9677Slinton 
580*9677Slinton public dwrite(buff, addr, nbytes)
581*9677Slinton char *buff;
582*9677Slinton Address addr;
583*9677Slinton int nbytes;
584*9677Slinton {
585*9677Slinton     Intfunc *f;
586*9677Slinton 
587*9677Slinton     if (coredump) {
588*9677Slinton 	error("no process to write to");
589*9677Slinton     }
590*9677Slinton     f = onsyserr(EIO, rwerr);
591*9677Slinton     badaddr = addr;
592*9677Slinton     pio(process, PWRITE, DATASEG, buff, addr, nbytes);
593*9677Slinton     onsyserr(EIO, f);
594*9677Slinton }
595*9677Slinton 
596*9677Slinton /*
597*9677Slinton  * Error handler.
598*9677Slinton  */
599*9677Slinton 
600*9677Slinton private rwerr()
601*9677Slinton {
602*9677Slinton     error("bad read/write process address 0x%x", badaddr);
603*9677Slinton }
604*9677Slinton 
605*9677Slinton /*
606*9677Slinton  * Ptrace interface.
607*9677Slinton  */
608*9677Slinton 
609*9677Slinton /*
610*9677Slinton  * This magic macro enables us to look at the process' registers
611*9677Slinton  * in its user structure.  Very gross.
612*9677Slinton  */
613*9677Slinton 
614*9677Slinton #define regloc(reg)     (ctob(UPAGES) + ( sizeof(int) * (reg) ))
615*9677Slinton 
616*9677Slinton #define WMASK           (~(sizeof(Word) - 1))
617*9677Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE))
618*9677Slinton 
619*9677Slinton #define FIRSTSIG        SIGINT
620*9677Slinton #define LASTSIG         SIGQUIT
621*9677Slinton #define ischild(pid)    ((pid) == 0)
622*9677Slinton #define traceme()       ptrace(0, 0, 0, 0)
623*9677Slinton #define setrep(n)       (1 << ((n)-1))
624*9677Slinton #define istraced(p)     (p->sigset&setrep(p->signo))
625*9677Slinton 
626*9677Slinton /*
627*9677Slinton  * Ptrace options (specified in first argument).
628*9677Slinton  */
629*9677Slinton 
630*9677Slinton #define UREAD   3       /* read from process's user structure */
631*9677Slinton #define UWRITE  6       /* write to process's user structure */
632*9677Slinton #define IREAD   1       /* read from process's instruction space */
633*9677Slinton #define IWRITE  4       /* write to process's instruction space */
634*9677Slinton #define DREAD   2       /* read from process's data space */
635*9677Slinton #define DWRITE  5       /* write to process's data space */
636*9677Slinton #define CONT    7       /* continue stopped process */
637*9677Slinton #define SSTEP   9       /* continue for approximately one instruction */
638*9677Slinton #define PKILL   8       /* terminate the process */
639*9677Slinton 
640*9677Slinton /*
641*9677Slinton  * Start up a new process by forking and exec-ing the
642*9677Slinton  * given argument list, returning when the process is loaded
643*9677Slinton  * and ready to execute.  The PROCESS information (pointed to
644*9677Slinton  * by the first argument) is appropriately filled.
645*9677Slinton  *
646*9677Slinton  * If the given PROCESS structure is associated with an already running
647*9677Slinton  * process, we terminate it.
648*9677Slinton  */
649*9677Slinton 
650*9677Slinton /* VARARGS2 */
651*9677Slinton private pstart(p, argv, infile, outfile)
652*9677Slinton Process p;
653*9677Slinton String argv[];
654*9677Slinton String infile;
655*9677Slinton String outfile;
656*9677Slinton {
657*9677Slinton     int status;
658*9677Slinton     File in, out;
659*9677Slinton 
660*9677Slinton     if (p->pid != 0) {          	/* child already running? */
661*9677Slinton 	ptrace(PKILL, p->pid, 0, 0);    /* ... kill it! */
662*9677Slinton     }
663*9677Slinton     psigtrace(p, SIGTRAP, true);
664*9677Slinton     if ((p->pid = fork()) == -1) {
665*9677Slinton 	panic("can't fork");
666*9677Slinton     }
667*9677Slinton     if (ischild(p->pid)) {
668*9677Slinton 	traceme();
669*9677Slinton 	if (infile != nil) {
670*9677Slinton 	    in = fopen(infile, "r");
671*9677Slinton 	    if (in == nil) {
672*9677Slinton 		printf("can't read %s\n", infile);
673*9677Slinton 		exit(1);
674*9677Slinton 	    }
675*9677Slinton 	    fswap(0, fileno(in));
676*9677Slinton 	}
677*9677Slinton 	if (outfile != nil) {
678*9677Slinton 	    out = fopen(outfile, "w");
679*9677Slinton 	    if (out == nil) {
680*9677Slinton 		printf("can't write %s\n", outfile);
681*9677Slinton 		exit(1);
682*9677Slinton 	    }
683*9677Slinton 	    fswap(1, fileno(out));
684*9677Slinton 	}
685*9677Slinton 	execvp(argv[0], argv);
686*9677Slinton 	panic("can't exec %s", argv[0]);
687*9677Slinton     }
688*9677Slinton     pwait(p->pid, &status);
689*9677Slinton     getinfo(p, status);
690*9677Slinton     if (p->status != STOPPED) {
691*9677Slinton 	error("program could not begin execution");
692*9677Slinton     }
693*9677Slinton }
694*9677Slinton 
695*9677Slinton /*
696*9677Slinton  * Continue a stopped process.  The argument points to a PROCESS structure.
697*9677Slinton  * Before the process is restarted it's user area is modified according to
698*9677Slinton  * the values in the structure.  When this routine finishes,
699*9677Slinton  * the structure has the new values from the process's user area.
700*9677Slinton  *
701*9677Slinton  * Pcont terminates when the process stops with a signal pending that
702*9677Slinton  * is being traced (via psigtrace), or when the process terminates.
703*9677Slinton  */
704*9677Slinton 
705*9677Slinton private pcont(p)
706*9677Slinton Process p;
707*9677Slinton {
708*9677Slinton     int status;
709*9677Slinton 
710*9677Slinton     if (p->pid == 0) {
711*9677Slinton 	error("program not active");
712*9677Slinton     }
713*9677Slinton     do {
714*9677Slinton 	setinfo(p);
715*9677Slinton 	sigs_off();
716*9677Slinton 	if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) {
717*9677Slinton 	    panic("can't continue process");
718*9677Slinton 	}
719*9677Slinton 	pwait(p->pid, &status);
720*9677Slinton 	sigs_on();
721*9677Slinton 	getinfo(p, status);
722*9677Slinton     } while (p->status == STOPPED and not istraced(p));
723*9677Slinton }
724*9677Slinton 
725*9677Slinton /*
726*9677Slinton  * Single step as best ptrace can.
727*9677Slinton  */
728*9677Slinton 
729*9677Slinton public pstep(p)
730*9677Slinton Process p;
731*9677Slinton {
732*9677Slinton     int status;
733*9677Slinton 
734*9677Slinton     setinfo(p);
735*9677Slinton     sigs_off();
736*9677Slinton     ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo);
737*9677Slinton     pwait(p->pid, &status);
738*9677Slinton     sigs_on();
739*9677Slinton     getinfo(p, status);
740*9677Slinton }
741*9677Slinton 
742*9677Slinton /*
743*9677Slinton  * Return from execution when the given signal is pending.
744*9677Slinton  */
745*9677Slinton 
746*9677Slinton public psigtrace(p, sig, sw)
747*9677Slinton Process p;
748*9677Slinton int sig;
749*9677Slinton Boolean sw;
750*9677Slinton {
751*9677Slinton     if (sw) {
752*9677Slinton 	p->sigset |= setrep(sig);
753*9677Slinton     } else {
754*9677Slinton 	p->sigset &= ~setrep(sig);
755*9677Slinton     }
756*9677Slinton }
757*9677Slinton 
758*9677Slinton /*
759*9677Slinton  * Don't catch any signals.
760*9677Slinton  * Particularly useful when letting a process finish uninhibited.
761*9677Slinton  */
762*9677Slinton 
763*9677Slinton public unsetsigtraces(p)
764*9677Slinton Process p;
765*9677Slinton {
766*9677Slinton     p->sigset = 0;
767*9677Slinton }
768*9677Slinton 
769*9677Slinton /*
770*9677Slinton  * Turn off attention to signals not being caught.
771*9677Slinton  */
772*9677Slinton 
773*9677Slinton private Intfunc *sigfunc[NSIG];
774*9677Slinton 
775*9677Slinton private sigs_off()
776*9677Slinton {
777*9677Slinton     register int i;
778*9677Slinton 
779*9677Slinton     for (i = FIRSTSIG; i < LASTSIG; i++) {
780*9677Slinton 	if (i != SIGKILL) {
781*9677Slinton 	    sigfunc[i] = signal(i, SIG_IGN);
782*9677Slinton 	}
783*9677Slinton     }
784*9677Slinton }
785*9677Slinton 
786*9677Slinton /*
787*9677Slinton  * Turn back on attention to signals.
788*9677Slinton  */
789*9677Slinton 
790*9677Slinton private sigs_on()
791*9677Slinton {
792*9677Slinton     register int i;
793*9677Slinton 
794*9677Slinton     for (i = FIRSTSIG; i < LASTSIG; i++) {
795*9677Slinton 	if (i != SIGKILL) {
796*9677Slinton 	    signal(i, sigfunc[i]);
797*9677Slinton 	}
798*9677Slinton     }
799*9677Slinton }
800*9677Slinton 
801*9677Slinton /*
802*9677Slinton  * Get process information from user area.
803*9677Slinton  */
804*9677Slinton 
805*9677Slinton private int rloc[] ={
806*9677Slinton     R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC
807*9677Slinton };
808*9677Slinton 
809*9677Slinton private getinfo(p, status)
810*9677Slinton register Process p;
811*9677Slinton register int status;
812*9677Slinton {
813*9677Slinton     register int i;
814*9677Slinton 
815*9677Slinton     p->signo = (status&0177);
816*9677Slinton     p->exitval = ((status >> 8)&0377);
817*9677Slinton     if (p->signo != STOPPED) {
818*9677Slinton 	p->status = FINISHED;
819*9677Slinton     } else {
820*9677Slinton 	p->status = p->signo;
821*9677Slinton 	p->signo = p->exitval;
822*9677Slinton 	p->exitval = 0;
823*9677Slinton 	p->mask = ptrace(UREAD, p->pid, regloc(PS), 0);
824*9677Slinton 	for (i = 0; i < NREG; i++) {
825*9677Slinton 	    p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0);
826*9677Slinton 	    p->oreg[i] = p->reg[i];
827*9677Slinton 	}
828*9677Slinton     }
829*9677Slinton }
830*9677Slinton 
831*9677Slinton /*
832*9677Slinton  * Set process's user area information from given process structure.
833*9677Slinton  */
834*9677Slinton 
835*9677Slinton private setinfo(p)
836*9677Slinton register Process p;
837*9677Slinton {
838*9677Slinton     register int i;
839*9677Slinton     register int r;
840*9677Slinton 
841*9677Slinton     if (istraced(p)) {
842*9677Slinton 	p->signo = 0;
843*9677Slinton     }
844*9677Slinton     for (i = 0; i < NREG; i++) {
845*9677Slinton 	if ((r = p->reg[i]) != p->oreg[i]) {
846*9677Slinton 	    ptrace(UWRITE, p->pid, regloc(rloc[i]), r);
847*9677Slinton 	}
848*9677Slinton     }
849*9677Slinton }
850*9677Slinton 
851*9677Slinton /*
852*9677Slinton  * Structure for reading and writing by words, but dealing with bytes.
853*9677Slinton  */
854*9677Slinton 
855*9677Slinton typedef union {
856*9677Slinton     Word pword;
857*9677Slinton     Byte pbyte[sizeof(Word)];
858*9677Slinton } Pword;
859*9677Slinton 
860*9677Slinton /*
861*9677Slinton  * Read (write) from (to) the process' address space.
862*9677Slinton  * We must deal with ptrace's inability to look anywhere other
863*9677Slinton  * than at a word boundary.
864*9677Slinton  */
865*9677Slinton 
866*9677Slinton private Word fetch();
867*9677Slinton private store();
868*9677Slinton 
869*9677Slinton private pio(p, op, seg, buff, addr, nbytes)
870*9677Slinton Process p;
871*9677Slinton PioOp op;
872*9677Slinton PioSeg seg;
873*9677Slinton char *buff;
874*9677Slinton Address addr;
875*9677Slinton int nbytes;
876*9677Slinton {
877*9677Slinton     register int i;
878*9677Slinton     register Address newaddr;
879*9677Slinton     register char *cp;
880*9677Slinton     char *bufend;
881*9677Slinton     Pword w;
882*9677Slinton     Address wordaddr;
883*9677Slinton     int byteoff;
884*9677Slinton 
885*9677Slinton     if (p->status != STOPPED) {
886*9677Slinton 	error("program is not active");
887*9677Slinton     }
888*9677Slinton     cp = buff;
889*9677Slinton     newaddr = addr;
890*9677Slinton     wordaddr = (newaddr&WMASK);
891*9677Slinton     if (wordaddr != newaddr) {
892*9677Slinton 	w.pword = fetch(p, seg, wordaddr);
893*9677Slinton 	for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) {
894*9677Slinton 	    if (op == PREAD) {
895*9677Slinton 		*cp++ = w.pbyte[i];
896*9677Slinton 	    } else {
897*9677Slinton 		w.pbyte[i] = *cp++;
898*9677Slinton 	    }
899*9677Slinton 	    nbytes--;
900*9677Slinton 	}
901*9677Slinton 	if (op == PWRITE) {
902*9677Slinton 	    store(p, seg, wordaddr, w.pword);
903*9677Slinton 	}
904*9677Slinton 	newaddr = wordaddr + sizeof(Word);
905*9677Slinton     }
906*9677Slinton     byteoff = (nbytes&(~WMASK));
907*9677Slinton     nbytes -= byteoff;
908*9677Slinton     bufend = cp + nbytes;
909*9677Slinton     while (cp < bufend) {
910*9677Slinton 	if (op == PREAD) {
911*9677Slinton 	    *((Word *) cp) = fetch(p, seg, newaddr);
912*9677Slinton 	} else {
913*9677Slinton 	    store(p, seg, newaddr, *((Word *) cp));
914*9677Slinton 	}
915*9677Slinton 	cp += sizeof(Word);
916*9677Slinton 	newaddr += sizeof(Word);
917*9677Slinton     }
918*9677Slinton     if (byteoff > 0) {
919*9677Slinton 	w.pword = fetch(p, seg, newaddr);
920*9677Slinton 	for (i = 0; i < byteoff; i++) {
921*9677Slinton 	    if (op == PREAD) {
922*9677Slinton 		*cp++ = w.pbyte[i];
923*9677Slinton 	    } else {
924*9677Slinton 		w.pbyte[i] = *cp++;
925*9677Slinton 	    }
926*9677Slinton 	}
927*9677Slinton 	if (op == PWRITE) {
928*9677Slinton 	    store(p, seg, newaddr, w.pword);
929*9677Slinton 	}
930*9677Slinton     }
931*9677Slinton }
932*9677Slinton 
933*9677Slinton /*
934*9677Slinton  * Get a word from a process at the given address.
935*9677Slinton  * The address is assumed to be on a word boundary.
936*9677Slinton  *
937*9677Slinton  * A simple cache scheme is used to avoid redundant ptrace calls
938*9677Slinton  * to the instruction space since it is assumed to be pure.
939*9677Slinton  *
940*9677Slinton  * It is necessary to use a write-through scheme so that
941*9677Slinton  * breakpoints right next to each other don't interfere.
942*9677Slinton  */
943*9677Slinton 
944*9677Slinton private Integer nfetchs, nreads, nwrites;
945*9677Slinton 
946*9677Slinton private Word fetch(p, seg, addr)
947*9677Slinton Process p;
948*9677Slinton PioSeg seg;
949*9677Slinton register int addr;
950*9677Slinton {
951*9677Slinton     register CacheWord *wp;
952*9677Slinton     register Word w;
953*9677Slinton 
954*9677Slinton     switch (seg) {
955*9677Slinton 	case TEXTSEG:
956*9677Slinton 	    ++nfetchs;
957*9677Slinton 	    wp = &p->word[cachehash(addr)];
958*9677Slinton 	    if (addr == 0 or wp->addr != addr) {
959*9677Slinton 		++nreads;
960*9677Slinton 		w = ptrace(IREAD, p->pid, addr, 0);
961*9677Slinton 		wp->addr = addr;
962*9677Slinton 		wp->val = w;
963*9677Slinton 	    } else {
964*9677Slinton 		w = wp->val;
965*9677Slinton 	    }
966*9677Slinton 	    break;
967*9677Slinton 
968*9677Slinton 	case DATASEG:
969*9677Slinton 	    w = ptrace(DREAD, p->pid, addr, 0);
970*9677Slinton 	    break;
971*9677Slinton 
972*9677Slinton 	default:
973*9677Slinton 	    panic("fetch: bad seg %d", seg);
974*9677Slinton 	    /* NOTREACHED */
975*9677Slinton     }
976*9677Slinton     return w;
977*9677Slinton }
978*9677Slinton 
979*9677Slinton /*
980*9677Slinton  * Put a word into the process' address space at the given address.
981*9677Slinton  * The address is assumed to be on a word boundary.
982*9677Slinton  */
983*9677Slinton 
984*9677Slinton private store(p, seg, addr, data)
985*9677Slinton Process p;
986*9677Slinton PioSeg seg;
987*9677Slinton int addr;
988*9677Slinton Word data;
989*9677Slinton {
990*9677Slinton     register CacheWord *wp;
991*9677Slinton 
992*9677Slinton     switch (seg) {
993*9677Slinton 	case TEXTSEG:
994*9677Slinton 	    ++nwrites;
995*9677Slinton 	    wp = &p->word[cachehash(addr)];
996*9677Slinton 	    wp->addr = addr;
997*9677Slinton 	    wp->val = data;
998*9677Slinton 	    ptrace(IWRITE, p->pid, addr, data);
999*9677Slinton 	    break;
1000*9677Slinton 
1001*9677Slinton 	case DATASEG:
1002*9677Slinton 	    ptrace(DWRITE, p->pid, addr, data);
1003*9677Slinton 	    break;
1004*9677Slinton 
1005*9677Slinton 	default:
1006*9677Slinton 	    panic("store: bad seg %d", seg);
1007*9677Slinton 	    /* NOTREACHED */
1008*9677Slinton     }
1009*9677Slinton }
1010*9677Slinton 
1011*9677Slinton public printptraceinfo()
1012*9677Slinton {
1013*9677Slinton     printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites);
1014*9677Slinton }
1015*9677Slinton 
1016*9677Slinton /*
1017*9677Slinton  * Swap file numbers so as to redirect standard input and output.
1018*9677Slinton  */
1019*9677Slinton 
1020*9677Slinton private fswap(oldfd, newfd)
1021*9677Slinton int oldfd;
1022*9677Slinton int newfd;
1023*9677Slinton {
1024*9677Slinton     if (oldfd != newfd) {
1025*9677Slinton 	close(oldfd);
1026*9677Slinton 	dup(newfd);
1027*9677Slinton 	close(newfd);
1028*9677Slinton     }
1029*9677Slinton }
1030