Ignore -L flag so can get passed to rlogin
[unix-history] / usr / src / old / dbx / process.c
CommitLineData
9a3bab7a
ML
1/* Copyright (c) 1982 Regents of the University of California */
2
0022c355
ML
3static char sccsid[] = "@(#)process.c 1.17 (Berkeley) %G%";
4
5static char rcsid[] = "$Header: process.c,v 1.5 84/12/26 10:41:37 linton Exp $";
9a3bab7a
ML
6
7/*
8 * Process management.
9 *
10 * This module contains the routines to manage the execution and
11 * tracing of the debuggee process.
12 */
13
14#include "defs.h"
15#include "process.h"
16#include "machine.h"
17#include "events.h"
18#include "tree.h"
8ee6535a 19#include "eval.h"
9a3bab7a
ML
20#include "operators.h"
21#include "source.h"
22#include "object.h"
23#include "mappings.h"
24#include "main.h"
25#include "coredump.h"
26#include <signal.h>
27#include <errno.h>
28#include <sys/param.h>
2fd0f574
SL
29#include <sys/dir.h>
30#include <sys/user.h>
b0edae1c 31#include <machine/reg.h>
9a3bab7a
ML
32#include <sys/stat.h>
33
34#ifndef public
35
36typedef struct Process *Process;
37
38Process process;
39
8ee6535a
ML
40#define DEFSIG -1
41
9a3bab7a
ML
42#include "machine.h"
43
44#endif
45
46#define NOTSTARTED 1
47#define STOPPED 0177
48#define FINISHED 0
49
50/*
2fd0f574
SL
51 * A cache of the instruction segment is kept to reduce the number
52 * of system calls. Might be better just to read the entire
53 * code space into memory.
9a3bab7a
ML
54 */
55
56#define CSIZE 1003 /* size of instruction cache */
57
58typedef struct {
59 Word addr;
60 Word val;
61} CacheWord;
62
63/*
64 * This structure holds the information we need from the user structure.
65 */
66
67struct Process {
68 int pid; /* process being traced */
5870175c
ML
69 int mask; /* process status word */
70 Word reg[NREG]; /* process' registers */
9a3bab7a
ML
71 Word oreg[NREG]; /* registers when process last stopped */
72 short status; /* either STOPPED or FINISHED */
73 short signo; /* signal that stopped process */
0022c355 74 short sigcode; /* extra signal information */
9a3bab7a
ML
75 int exitval; /* return value from exit() */
76 long sigset; /* bit array of traced signals */
77 CacheWord word[CSIZE]; /* text segment cache */
5870175c 78 Ttyinfo ttyinfo; /* process' terminal characteristics */
2fd0f574 79 Address sigstatus; /* process' handler for current signal */
9a3bab7a
ML
80};
81
82/*
83 * These definitions are for the arguments to "pio".
84 */
85
86typedef enum { PREAD, PWRITE } PioOp;
87typedef enum { TEXTSEG, DATASEG } PioSeg;
88
89private struct Process pbuf;
90
0022c355 91#define MAXNCMDARGS 1000 /* maximum number of arguments to RUN */
9a3bab7a 92
ca69b757
ML
93extern int errno;
94
9a3bab7a
ML
95private Boolean just_started;
96private int argc;
97private String argv[MAXNCMDARGS];
98private String infile, outfile;
99
100/*
101 * Initialize process information.
102 */
103
104public process_init()
105{
106 register Integer i;
107 Char buf[10];
108
109 process = &pbuf;
110 process->status = (coredump) ? STOPPED : NOTSTARTED;
111 setsigtrace();
112 for (i = 0; i < NREG; i++) {
113 sprintf(buf, "$r%d", i);
114 defregname(identname(buf, false), i);
115 }
116 defregname(identname("$ap", true), ARGP);
117 defregname(identname("$fp", true), FRP);
118 defregname(identname("$sp", true), STKP);
119 defregname(identname("$pc", true), PROGCTR);
120 if (coredump) {
121 coredump_readin(process->mask, process->reg, process->signo);
4e067a2c
ML
122 pc = process->reg[PROGCTR];
123 getsrcpos();
9a3bab7a 124 }
4e067a2c 125 arginit();
9a3bab7a
ML
126}
127
128/*
129 * Routines to get at process information from outside this module.
130 */
131
132public Word reg(n)
133Integer n;
134{
135 register Word w;
136
137 if (n == NREG) {
138 w = process->mask;
139 } else {
140 w = process->reg[n];
141 }
142 return w;
143}
144
145public setreg(n, w)
146Integer n;
147Word w;
148{
149 process->reg[n] = w;
150}
151
152/*
153 * Begin execution.
154 *
155 * We set a breakpoint at the end of the code so that the
156 * process data doesn't disappear after the program terminates.
157 */
158
159private Boolean remade();
160
161public start(argv, infile, outfile)
162String argv[];
163String infile, outfile;
164{
165 String pargv[4];
166 Node cond;
167
168 if (coredump) {
169 coredump = false;
170 fclose(corefile);
171 coredump_close();
172 }
173 if (argv == nil) {
174 argv = pargv;
175 pargv[0] = objname;
176 pargv[1] = nil;
177 } else {
178 argv[argc] = nil;
179 }
0022c355 180 pstart(process, argv, infile, outfile);
9a3bab7a
ML
181 if (remade(objname)) {
182 reinit(argv, infile, outfile);
183 }
9a3bab7a
ML
184 if (process->status == STOPPED) {
185 pc = 0;
2fd0f574 186 setcurfunc(program);
9a3bab7a
ML
187 if (objsize != 0) {
188 cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr()));
189 event_once(cond, buildcmdlist(build(O_ENDX)));
190 }
191 }
192}
193
194/*
195 * Check to see if the object file has changed since the symbolic
196 * information last was read.
197 */
198
199private time_t modtime;
200
201private Boolean remade(filename)
202String filename;
203{
204 struct stat s;
205 Boolean b;
206
207 stat(filename, &s);
208 b = (Boolean) (modtime != 0 and modtime < s.st_mtime);
209 modtime = s.st_mtime;
210 return b;
211}
212
213/*
214 * Set up what signals we want to trace.
215 */
216
217private setsigtrace()
218{
219 register Integer i;
220 register Process p;
221
222 p = process;
223 for (i = 1; i <= NSIG; i++) {
224 psigtrace(p, i, true);
225 }
226 psigtrace(p, SIGHUP, false);
227 psigtrace(p, SIGKILL, false);
228 psigtrace(p, SIGALRM, false);
229 psigtrace(p, SIGTSTP, false);
230 psigtrace(p, SIGCONT, false);
231 psigtrace(p, SIGCHLD, false);
232}
233
234/*
235 * Initialize the argument list.
236 */
237
238public arginit()
239{
240 infile = nil;
241 outfile = nil;
242 argv[0] = objname;
243 argc = 1;
244}
245
246/*
247 * Add an argument to the list for the debuggee.
248 */
249
250public newarg(arg)
251String arg;
252{
253 if (argc >= MAXNCMDARGS) {
254 error("too many arguments");
255 }
256 argv[argc++] = arg;
257}
258
259/*
260 * Set the standard input for the debuggee.
261 */
262
263public inarg(filename)
264String filename;
265{
266 if (infile != nil) {
267 error("multiple input redirects");
268 }
269 infile = filename;
270}
271
272/*
273 * Set the standard output for the debuggee.
274 * Probably should check to avoid overwriting an existing file.
275 */
276
277public outarg(filename)
278String filename;
279{
280 if (outfile != nil) {
281 error("multiple output redirect");
282 }
283 outfile = filename;
284}
285
286/*
287 * Start debuggee executing.
288 */
289
290public run()
291{
292 process->status = STOPPED;
293 fixbps();
294 curline = 0;
295 start(argv, infile, outfile);
296 just_started = true;
297 isstopped = false;
8ee6535a 298 cont(0);
9a3bab7a
ML
299}
300
301/*
302 * Continue execution wherever we left off.
303 *
304 * Note that this routine never returns. Eventually bpact() will fail
305 * and we'll call printstatus or step will call it.
306 */
307
308typedef int Intfunc();
309
310private Intfunc *dbintr;
311private intr();
312
36fd36ba 313public cont(signo)
2fd0f574 314integer signo;
9a3bab7a 315{
2fd0f574
SL
316 integer s;
317
9a3bab7a
ML
318 dbintr = signal(SIGINT, intr);
319 if (just_started) {
320 just_started = false;
321 } else {
322 if (not isstopped) {
323 error("can't continue execution");
324 }
325 isstopped = false;
36fd36ba 326 stepover();
9a3bab7a 327 }
2fd0f574 328 s = signo;
9a3bab7a
ML
329 for (;;) {
330 if (single_stepping) {
331 printnews();
332 } else {
333 setallbps();
2fd0f574 334 resume(s);
9a3bab7a 335 unsetallbps();
2fd0f574 336 s = DEFSIG;
0022c355 337 if (not isbperr() or not bpact()) {
9a3bab7a
ML
338 printstatus();
339 }
340 }
36fd36ba 341 stepover();
9a3bab7a
ML
342 }
343 /* NOTREACHED */
344}
345
346/*
0022c355 347 * This routine is called if we get an interrupt while "running"
9a3bab7a
ML
348 * but actually in the debugger. Could happen, for example, while
349 * processing breakpoints.
350 *
351 * We basically just want to keep going; the assumption is
0022c355 352 * that when the process resumes it will get the interrupt,
9a3bab7a
ML
353 * which will then be handled.
354 */
355
356private intr()
357{
358 signal(SIGINT, intr);
359}
360
361public fixintr()
362{
363 signal(SIGINT, dbintr);
364}
365
366/*
367 * Resume execution.
368 */
369
36fd36ba
ML
370public resume(signo)
371int signo;
9a3bab7a
ML
372{
373 register Process p;
374
375 p = process;
36fd36ba 376 pcont(p, signo);
9a3bab7a 377 pc = process->reg[PROGCTR];
e0a80343 378 if (p->status != STOPPED) {
36fd36ba
ML
379 if (p->signo != 0) {
380 error("program terminated by signal %d", p->signo);
8ee6535a 381 } else if (not runfirst) {
0022c355
ML
382 if (p->exitval == 0) {
383 error("program exited");
384 } else {
385 error("program exited with code %d", p->exitval);
386 }
36fd36ba 387 }
e0a80343 388 }
9a3bab7a
ML
389}
390
391/*
392 * Continue execution up to the next source line.
393 *
394 * There are two ways to define the next source line depending on what
395 * is desired when a procedure or function call is encountered. Step
396 * stops at the beginning of the procedure or call; next skips over it.
397 */
398
399/*
400 * Stepc is what is called when the step command is given.
401 * It has to play with the "isstopped" information.
402 */
403
404public stepc()
405{
406 if (not isstopped) {
407 error("can't continue execution");
408 }
409 isstopped = false;
410 dostep(false);
411 isstopped = true;
412}
413
414public next()
415{
2fd0f574
SL
416 Address oldfrp, newfrp;
417
9a3bab7a
ML
418 if (not isstopped) {
419 error("can't continue execution");
420 }
421 isstopped = false;
2fd0f574
SL
422 oldfrp = reg(FRP);
423 do {
424 dostep(true);
425 pc = reg(PROGCTR);
426 newfrp = reg(FRP);
427 } while (newfrp < oldfrp and newfrp != 0);
9a3bab7a
ML
428 isstopped = true;
429}
430
2fd0f574
SL
431/*
432 * Continue execution until the current function returns, or,
433 * if the given argument is non-nil, until execution returns to
434 * somewhere within the given function.
435 */
436
437public rtnfunc (f)
438Symbol f;
439{
440 Address addr;
441 Symbol t;
442
443 if (not isstopped) {
444 error("can't continue execution");
445 } else if (f != nil and not isactive(f)) {
446 error("%s is not active", symname(f));
447 } else {
448 addr = return_addr();
449 if (addr == nil) {
450 error("no place to return to");
451 } else {
452 isstopped = false;
453 contto(addr);
454 if (f != nil) {
455 for (;;) {
456 t = whatblock(pc);
457 addr = return_addr();
458 if (t == f or addr == nil) break;
459 contto(addr);
460 }
461 }
0022c355 462 if (not bpact()) {
2fd0f574
SL
463 isstopped = true;
464 printstatus();
465 }
466 }
467 }
468}
469
36fd36ba
ML
470/*
471 * Single-step over the current machine instruction.
472 *
473 * If we're single-stepping by source line we want to step to the
474 * next source line. Otherwise we're going to continue so there's
475 * no reason to do all the work necessary to single-step to the next
476 * source line.
477 */
478
2fd0f574 479public stepover()
9a3bab7a 480{
36fd36ba
ML
481 Boolean b;
482
2fd0f574
SL
483 if (traceexec) {
484 printf("!! stepping over 0x%x\n", process->reg[PROGCTR]);
485 }
36fd36ba
ML
486 if (single_stepping) {
487 dostep(false);
488 } else {
489 b = inst_tracing;
490 inst_tracing = true;
491 dostep(false);
492 inst_tracing = b;
493 }
2fd0f574
SL
494 if (traceexec) {
495 printf("!! stepped over to 0x%x\n", process->reg[PROGCTR]);
496 }
9a3bab7a
ML
497}
498
499/*
0022c355
ML
500 * Resume execution up to the given address. We can either ignore
501 * breakpoints (stepto) or catch them (contto).
9a3bab7a
ML
502 */
503
504public stepto(addr)
505Address addr;
506{
2fd0f574
SL
507 xto(addr, false);
508}
509
510private contto (addr)
511Address addr;
512{
513 xto(addr, true);
514}
515
516private xto (addr, catchbps)
517Address addr;
518boolean catchbps;
519{
520 Address curpc;
521
522 if (catchbps) {
523 stepover();
524 }
525 curpc = process->reg[PROGCTR];
526 if (addr != curpc) {
527 if (traceexec) {
528 printf("!! stepping from 0x%x to 0x%x\n", curpc, addr);
529 }
530 if (catchbps) {
531 setallbps();
532 }
533 setbp(addr);
534 resume(DEFSIG);
535 unsetbp(addr);
536 if (catchbps) {
537 unsetallbps();
538 }
539 if (not isbperr()) {
540 printstatus();
541 }
9a3bab7a
ML
542 }
543}
544
545/*
546 * Print the status of the process.
547 * This routine does not return.
548 */
549
550public printstatus()
551{
ca69b757
ML
552 int status;
553
b0edae1c
ML
554 if (process->status == FINISHED) {
555 exit(0);
9a3bab7a 556 } else {
2fd0f574 557 setcurfunc(whatblock(pc));
b0edae1c
ML
558 getsrcpos();
559 if (process->signo == SIGINT) {
560 isstopped = true;
561 printerror();
562 } else if (isbperr() and isstopped) {
563 printf("stopped ");
86d0cc79
ML
564 printloc();
565 putchar('\n');
b0edae1c 566 if (curline > 0) {
b0edae1c
ML
567 printlines(curline, curline);
568 } else {
b0edae1c
ML
569 printinst(pc, pc);
570 }
571 erecover();
9a3bab7a 572 } else {
b0edae1c 573 fixintr();
9a3bab7a
ML
574 isstopped = true;
575 printerror();
576 }
577 }
578}
579
86d0cc79
ML
580/*
581 * Print out the current location in the debuggee.
582 */
583
584public printloc()
585{
586 printf("in ");
587 printname(stdout, curfunc);
588 putchar(' ');
8ee6535a 589 if (curline > 0 and not useInstLoc) {
86d0cc79
ML
590 printsrcpos();
591 } else {
8ee6535a
ML
592 useInstLoc = false;
593 curline = 0;
86d0cc79
ML
594 printf("at 0x%x", pc);
595 }
596}
597
9a3bab7a
ML
598/*
599 * Some functions for testing the state of the process.
600 */
601
602public Boolean notstarted(p)
603Process p;
604{
605 return (Boolean) (p->status == NOTSTARTED);
606}
607
608public Boolean isfinished(p)
609Process p;
610{
611 return (Boolean) (p->status == FINISHED);
612}
613
614/*
0022c355
ML
615 * Predicate to test if the reason the process stopped was because
616 * of a breakpoint. If so, as a side effect clear the local copy of
617 * signal handler associated with process. We must do this so as to
618 * not confuse future stepping or continuing by possibly concluding
619 * the process should continue with a SIGTRAP handler.
9a3bab7a
ML
620 */
621
0022c355
ML
622public boolean isbperr()
623{
624 Process p;
625 boolean b;
626
627 p = process;
628 if (p->status == STOPPED and p->signo == SIGTRAP) {
629 b = true;
630 p->sigstatus = 0;
631 } else {
632 b = false;
633 }
634 return b;
635}
636
637/*
638 * Return the signal number that stopped the process.
639 */
640
641public integer errnum (p)
9a3bab7a
ML
642Process p;
643{
644 return p->signo;
645}
646
0022c355
ML
647/*
648 * Return the signal code associated with the signal.
649 */
650
651public integer errcode (p)
57a9bb29
SL
652Process p;
653{
654 return p->sigcode;
655}
656
9a3bab7a
ML
657/*
658 * Return the termination code of the process.
659 */
660
0022c355 661public integer exitcode (p)
9a3bab7a
ML
662Process p;
663{
664 return p->exitval;
665}
666
667/*
668 * These routines are used to access the debuggee process from
669 * outside this module.
670 *
671 * They invoke "pio" which eventually leads to a call to "ptrace".
8ee6535a
ML
672 * The system generates an I/O error when a ptrace fails. During reads
673 * these are ignored, during writes they are reported as an error, and
674 * for anything else they cause a fatal error.
9a3bab7a
ML
675 */
676
677extern Intfunc *onsyserr();
678
679private badaddr;
8ee6535a 680private read_err(), write_err();
9a3bab7a
ML
681
682/*
683 * Read from the process' instruction area.
684 */
685
686public iread(buff, addr, nbytes)
687char *buff;
688Address addr;
689int nbytes;
690{
691 Intfunc *f;
692
8ee6535a 693 f = onsyserr(EIO, read_err);
9a3bab7a
ML
694 badaddr = addr;
695 if (coredump) {
696 coredump_readtext(buff, addr, nbytes);
697 } else {
698 pio(process, PREAD, TEXTSEG, buff, addr, nbytes);
699 }
700 onsyserr(EIO, f);
701}
702
703/*
704 * Write to the process' instruction area, usually in order to set
705 * or unset a breakpoint.
706 */
707
708public iwrite(buff, addr, nbytes)
709char *buff;
710Address addr;
711int nbytes;
712{
713 Intfunc *f;
714
715 if (coredump) {
716 error("no process to write to");
717 }
8ee6535a 718 f = onsyserr(EIO, write_err);
9a3bab7a
ML
719 badaddr = addr;
720 pio(process, PWRITE, TEXTSEG, buff, addr, nbytes);
721 onsyserr(EIO, f);
722}
723
724/*
725 * Read for the process' data area.
726 */
727
728public dread(buff, addr, nbytes)
729char *buff;
730Address addr;
731int nbytes;
732{
733 Intfunc *f;
734
9a3bab7a
ML
735 badaddr = addr;
736 if (coredump) {
0022c355 737 f = onsyserr(EFAULT, read_err);
9a3bab7a 738 coredump_readdata(buff, addr, nbytes);
0022c355 739 onsyserr(EFAULT, f);
9a3bab7a 740 } else {
0022c355 741 f = onsyserr(EIO, read_err);
9a3bab7a 742 pio(process, PREAD, DATASEG, buff, addr, nbytes);
0022c355 743 onsyserr(EIO, f);
9a3bab7a 744 }
9a3bab7a
ML
745}
746
747/*
748 * Write to the process' data area.
749 */
750
751public dwrite(buff, addr, nbytes)
752char *buff;
753Address addr;
754int nbytes;
755{
756 Intfunc *f;
757
758 if (coredump) {
759 error("no process to write to");
760 }
8ee6535a 761 f = onsyserr(EIO, write_err);
9a3bab7a
ML
762 badaddr = addr;
763 pio(process, PWRITE, DATASEG, buff, addr, nbytes);
764 onsyserr(EIO, f);
765}
766
767/*
8ee6535a
ML
768 * Trap for errors in reading or writing to a process.
769 * The current approach is to "ignore" read errors and complain
770 * bitterly about write errors.
9a3bab7a
ML
771 */
772
8ee6535a 773private read_err()
9a3bab7a 774{
ae743e15 775 /*
8ee6535a 776 * Ignore.
ae743e15 777 */
9a3bab7a
ML
778}
779
8ee6535a
ML
780private write_err()
781{
782 error("can't write to process (address 0x%x)", badaddr);
783}
784
9a3bab7a
ML
785/*
786 * Ptrace interface.
787 */
788
789/*
790 * This magic macro enables us to look at the process' registers
8ee6535a 791 * in its user structure.
9a3bab7a
ML
792 */
793
794#define regloc(reg) (ctob(UPAGES) + ( sizeof(int) * (reg) ))
795
796#define WMASK (~(sizeof(Word) - 1))
797#define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE))
798
799#define FIRSTSIG SIGINT
800#define LASTSIG SIGQUIT
801#define ischild(pid) ((pid) == 0)
0022c355 802#define traceme() ptrace(0, 0, 0, 0)
9a3bab7a
ML
803#define setrep(n) (1 << ((n)-1))
804#define istraced(p) (p->sigset&setrep(p->signo))
805
0022c355
ML
806/*
807 * Ptrace options (specified in first argument).
808 */
809
810#define UREAD 3 /* read from process's user structure */
811#define UWRITE 6 /* write to process's user structure */
812#define IREAD 1 /* read from process's instruction space */
813#define IWRITE 4 /* write to process's instruction space */
814#define DREAD 2 /* read from process's data space */
815#define DWRITE 5 /* write to process's data space */
816#define CONT 7 /* continue stopped process */
817#define SSTEP 9 /* continue for approximately one instruction */
818#define PKILL 8 /* terminate the process */
819
9a3bab7a
ML
820/*
821 * Start up a new process by forking and exec-ing the
822 * given argument list, returning when the process is loaded
823 * and ready to execute. The PROCESS information (pointed to
824 * by the first argument) is appropriately filled.
825 *
826 * If the given PROCESS structure is associated with an already running
827 * process, we terminate it.
828 */
829
830/* VARARGS2 */
831private pstart(p, argv, infile, outfile)
832Process p;
833String argv[];
834String infile;
835String outfile;
836{
837 int status;
9a3bab7a 838
2fd0f574
SL
839 if (p->pid != 0) {
840 pterm(p);
0022c355 841 cacheflush(p);
9a3bab7a 842 }
0022c355 843 fflush(stdout);
9a3bab7a 844 psigtrace(p, SIGTRAP, true);
ca69b757
ML
845 p->pid = vfork();
846 if (p->pid == -1) {
9a3bab7a
ML
847 panic("can't fork");
848 }
849 if (ischild(p->pid)) {
0022c355 850 nocatcherrs();
9a3bab7a
ML
851 traceme();
852 if (infile != nil) {
2fd0f574 853 infrom(infile);
9a3bab7a
ML
854 }
855 if (outfile != nil) {
2fd0f574 856 outto(outfile);
9a3bab7a 857 }
e0a80343 858 execv(argv[0], argv);
86d0cc79 859 _exit(1);
9a3bab7a
ML
860 }
861 pwait(p->pid, &status);
862 getinfo(p, status);
863 if (p->status != STOPPED) {
0022c355
ML
864 beginerrmsg();
865 fprintf(stderr, "warning: cannot execute %s\n", argv[0]);
866 } else {
867 ptraced(p->pid);
9a3bab7a
ML
868 }
869}
870
2fd0f574
SL
871/*
872 * Terminate a ptrace'd process.
873 */
874
875public pterm (p)
876Process p;
877{
878 integer status;
879
880 if (p != nil and p->pid != 0) {
0022c355 881 ptrace(PKILL, p->pid, 0, 0);
2fd0f574
SL
882 pwait(p->pid, &status);
883 unptraced(p->pid);
884 }
885}
886
9a3bab7a 887/*
36fd36ba
ML
888 * Continue a stopped process. The first argument points to a Process
889 * structure. Before the process is restarted it's user area is modified
890 * according to the values in the structure. When this routine finishes,
9a3bab7a
ML
891 * the structure has the new values from the process's user area.
892 *
893 * Pcont terminates when the process stops with a signal pending that
894 * is being traced (via psigtrace), or when the process terminates.
895 */
896
36fd36ba 897private pcont(p, signo)
9a3bab7a 898Process p;
36fd36ba 899int signo;
9a3bab7a 900{
2fd0f574 901 int s, status;
9a3bab7a
ML
902
903 if (p->pid == 0) {
0022c355 904 error("program is not active");
9a3bab7a 905 }
2fd0f574 906 s = signo;
9a3bab7a 907 do {
2fd0f574
SL
908 setinfo(p, s);
909 if (traceexec) {
910 printf("!! pcont from 0x%x with signal %d (%d)\n",
911 p->reg[PROGCTR], s, p->signo);
912 fflush(stdout);
913 }
9a3bab7a 914 sigs_off();
0022c355 915 if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) {
ca69b757 916 panic("error %d trying to continue process", errno);
9a3bab7a
ML
917 }
918 pwait(p->pid, &status);
919 sigs_on();
920 getinfo(p, status);
0022c355
ML
921 if (p->status == STOPPED and traceexec and not istraced(p)) {
922 printf("!! ignored signal %d at 0x%x\n",
923 p->signo, p->reg[PROGCTR]);
2fd0f574
SL
924 fflush(stdout);
925 }
926 s = p->signo;
9a3bab7a 927 } while (p->status == STOPPED and not istraced(p));
2fd0f574
SL
928 if (traceexec) {
929 printf("!! pcont to 0x%x on signal %d\n", p->reg[PROGCTR], p->signo);
930 fflush(stdout);
931 }
9a3bab7a
ML
932}
933
934/*
935 * Single step as best ptrace can.
936 */
937
2fd0f574 938public pstep(p, signo)
9a3bab7a 939Process p;
2fd0f574 940integer signo;
9a3bab7a 941{
0022c355 942 int s, status;
9a3bab7a 943
0022c355
ML
944 s = signo;
945 do {
946 setinfo(p, s);
947 if (traceexec) {
948 printf("!! pstep from 0x%x with signal %d (%d)\n",
949 p->reg[PROGCTR], s, p->signo);
950 fflush(stdout);
951 }
952 sigs_off();
953 if (ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo) < 0) {
954 panic("error %d trying to step process", errno);
955 }
956 pwait(p->pid, &status);
957 sigs_on();
958 getinfo(p, status);
959 if (p->status == STOPPED and traceexec and not istraced(p)) {
960 printf("!! pstep ignored signal %d at 0x%x\n",
961 p->signo, p->reg[PROGCTR]);
962 fflush(stdout);
963 }
964 s = p->signo;
965 } while (p->status == STOPPED and not istraced(p));
2fd0f574 966 if (traceexec) {
0022c355
ML
967 printf("!! pstep to 0x%x on signal %d\n",
968 p->reg[PROGCTR], p->signo);
2fd0f574
SL
969 fflush(stdout);
970 }
971 if (p->status != STOPPED) {
0022c355
ML
972 if (p->exitval == 0) {
973 error("program exited\n");
974 } else {
975 error("program exited with code %d\n", p->exitval);
976 }
2fd0f574 977 }
9a3bab7a
ML
978}
979
980/*
981 * Return from execution when the given signal is pending.
982 */
983
984public psigtrace(p, sig, sw)
985Process p;
986int sig;
987Boolean sw;
988{
989 if (sw) {
990 p->sigset |= setrep(sig);
991 } else {
992 p->sigset &= ~setrep(sig);
993 }
994}
995
996/*
997 * Don't catch any signals.
998 * Particularly useful when letting a process finish uninhibited.
999 */
1000
1001public unsetsigtraces(p)
1002Process p;
1003{
1004 p->sigset = 0;
1005}
1006
1007/*
1008 * Turn off attention to signals not being caught.
1009 */
1010
1011private Intfunc *sigfunc[NSIG];
1012
1013private sigs_off()
1014{
1015 register int i;
1016
1017 for (i = FIRSTSIG; i < LASTSIG; i++) {
1018 if (i != SIGKILL) {
1019 sigfunc[i] = signal(i, SIG_IGN);
1020 }
1021 }
1022}
1023
1024/*
1025 * Turn back on attention to signals.
1026 */
1027
1028private sigs_on()
1029{
1030 register int i;
1031
1032 for (i = FIRSTSIG; i < LASTSIG; i++) {
1033 if (i != SIGKILL) {
1034 signal(i, sigfunc[i]);
1035 }
1036 }
1037}
1038
1039/*
1040 * Get process information from user area.
1041 */
1042
1043private int rloc[] ={
1044 R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC
1045};
1046
1047private getinfo(p, status)
1048register Process p;
1049register int status;
1050{
1051 register int i;
2fd0f574 1052 Address addr;
9a3bab7a
ML
1053
1054 p->signo = (status&0177);
1055 p->exitval = ((status >> 8)&0377);
1056 if (p->signo != STOPPED) {
1057 p->status = FINISHED;
8ee6535a 1058 p->pid = 0;
2fd0f574 1059 p->reg[PROGCTR] = 0;
9a3bab7a
ML
1060 } else {
1061 p->status = p->signo;
1062 p->signo = p->exitval;
0022c355 1063 p->sigcode = ptrace(UREAD, p->pid, &((struct user *) 0)->u_code, 0);
9a3bab7a 1064 p->exitval = 0;
0022c355 1065 p->mask = ptrace(UREAD, p->pid, regloc(PS), 0);
9a3bab7a 1066 for (i = 0; i < NREG; i++) {
0022c355 1067 p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0);
9a3bab7a
ML
1068 p->oreg[i] = p->reg[i];
1069 }
5870175c 1070 savetty(stdout, &(p->ttyinfo));
2fd0f574 1071 addr = (Address) &(((struct user *) 0)->u_signal[p->signo]);
0022c355 1072 p->sigstatus = (Address) ptrace(UREAD, p->pid, addr, 0);
9a3bab7a
ML
1073 }
1074}
1075
1076/*
1077 * Set process's user area information from given process structure.
1078 */
1079
36fd36ba 1080private setinfo(p, signo)
9a3bab7a 1081register Process p;
36fd36ba 1082int signo;
9a3bab7a
ML
1083{
1084 register int i;
1085 register int r;
1086
8ee6535a 1087 if (signo == DEFSIG) {
2fd0f574 1088 if (istraced(p) and (p->sigstatus == 0 or p->sigstatus == 1)) {
8ee6535a
ML
1089 p->signo = 0;
1090 }
1091 } else {
36fd36ba 1092 p->signo = signo;
9a3bab7a
ML
1093 }
1094 for (i = 0; i < NREG; i++) {
1095 if ((r = p->reg[i]) != p->oreg[i]) {
0022c355 1096 ptrace(UWRITE, p->pid, regloc(rloc[i]), r);
9a3bab7a
ML
1097 }
1098 }
5870175c 1099 restoretty(stdout, &(p->ttyinfo));
9a3bab7a
ML
1100}
1101
2fd0f574
SL
1102/*
1103 * Return the address associated with the current signal.
1104 * (Plus two since the address points to the beginning of a procedure).
1105 */
1106
1107public Address usignal (p)
1108Process p;
1109{
1110 Address r;
1111
1112 r = p->sigstatus;
1113 if (r != 0 and r != 1) {
1114 r += 2;
1115 }
1116 return r;
1117}
1118
9a3bab7a
ML
1119/*
1120 * Structure for reading and writing by words, but dealing with bytes.
1121 */
1122
1123typedef union {
1124 Word pword;
1125 Byte pbyte[sizeof(Word)];
1126} Pword;
1127
1128/*
1129 * Read (write) from (to) the process' address space.
1130 * We must deal with ptrace's inability to look anywhere other
1131 * than at a word boundary.
1132 */
1133
1134private Word fetch();
1135private store();
1136
1137private pio(p, op, seg, buff, addr, nbytes)
1138Process p;
1139PioOp op;
1140PioSeg seg;
1141char *buff;
1142Address addr;
1143int nbytes;
1144{
1145 register int i;
1146 register Address newaddr;
1147 register char *cp;
1148 char *bufend;
1149 Pword w;
1150 Address wordaddr;
1151 int byteoff;
1152
1153 if (p->status != STOPPED) {
1154 error("program is not active");
1155 }
1156 cp = buff;
1157 newaddr = addr;
1158 wordaddr = (newaddr&WMASK);
1159 if (wordaddr != newaddr) {
1160 w.pword = fetch(p, seg, wordaddr);
1161 for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) {
1162 if (op == PREAD) {
1163 *cp++ = w.pbyte[i];
1164 } else {
1165 w.pbyte[i] = *cp++;
1166 }
1167 nbytes--;
1168 }
1169 if (op == PWRITE) {
1170 store(p, seg, wordaddr, w.pword);
1171 }
1172 newaddr = wordaddr + sizeof(Word);
1173 }
1174 byteoff = (nbytes&(~WMASK));
1175 nbytes -= byteoff;
1176 bufend = cp + nbytes;
1177 while (cp < bufend) {
1178 if (op == PREAD) {
1179 *((Word *) cp) = fetch(p, seg, newaddr);
1180 } else {
1181 store(p, seg, newaddr, *((Word *) cp));
1182 }
1183 cp += sizeof(Word);
1184 newaddr += sizeof(Word);
1185 }
1186 if (byteoff > 0) {
1187 w.pword = fetch(p, seg, newaddr);
1188 for (i = 0; i < byteoff; i++) {
1189 if (op == PREAD) {
1190 *cp++ = w.pbyte[i];
1191 } else {
1192 w.pbyte[i] = *cp++;
1193 }
1194 }
1195 if (op == PWRITE) {
1196 store(p, seg, newaddr, w.pword);
1197 }
1198 }
1199}
1200
1201/*
1202 * Get a word from a process at the given address.
1203 * The address is assumed to be on a word boundary.
1204 *
1205 * A simple cache scheme is used to avoid redundant ptrace calls
1206 * to the instruction space since it is assumed to be pure.
1207 *
1208 * It is necessary to use a write-through scheme so that
1209 * breakpoints right next to each other don't interfere.
1210 */
1211
1212private Integer nfetchs, nreads, nwrites;
1213
1214private Word fetch(p, seg, addr)
1215Process p;
1216PioSeg seg;
1217register int addr;
1218{
1219 register CacheWord *wp;
1220 register Word w;
1221
1222 switch (seg) {
1223 case TEXTSEG:
1224 ++nfetchs;
1225 wp = &p->word[cachehash(addr)];
1226 if (addr == 0 or wp->addr != addr) {
1227 ++nreads;
0022c355 1228 w = ptrace(IREAD, p->pid, addr, 0);
9a3bab7a
ML
1229 wp->addr = addr;
1230 wp->val = w;
1231 } else {
1232 w = wp->val;
1233 }
1234 break;
1235
1236 case DATASEG:
0022c355 1237 w = ptrace(DREAD, p->pid, addr, 0);
9a3bab7a
ML
1238 break;
1239
1240 default:
1241 panic("fetch: bad seg %d", seg);
1242 /* NOTREACHED */
1243 }
1244 return w;
1245}
1246
1247/*
1248 * Put a word into the process' address space at the given address.
1249 * The address is assumed to be on a word boundary.
1250 */
1251
1252private store(p, seg, addr, data)
1253Process p;
1254PioSeg seg;
1255int addr;
1256Word data;
1257{
1258 register CacheWord *wp;
1259
1260 switch (seg) {
1261 case TEXTSEG:
1262 ++nwrites;
1263 wp = &p->word[cachehash(addr)];
1264 wp->addr = addr;
1265 wp->val = data;
0022c355 1266 ptrace(IWRITE, p->pid, addr, data);
9a3bab7a
ML
1267 break;
1268
1269 case DATASEG:
0022c355 1270 ptrace(DWRITE, p->pid, addr, data);
9a3bab7a
ML
1271 break;
1272
1273 default:
1274 panic("store: bad seg %d", seg);
1275 /* NOTREACHED */
1276 }
1277}
1278
0022c355
ML
1279/*
1280 * Flush the instruction cache associated with a process.
1281 */
1282
1283private cacheflush (p)
1284Process p;
1285{
1286 bzero(p->word, sizeof(p->word));
1287}
1288
9a3bab7a
ML
1289public printptraceinfo()
1290{
1291 printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites);
1292}
1293
1294/*
2fd0f574
SL
1295 * Redirect input.
1296 * Assuming this is called from a child, we should be careful to avoid
1297 * (possibly) shared standard I/O buffers.
1298 */
1299
1300private infrom (filename)
1301String filename;
1302{
1303 Fileid in;
1304
1305 in = open(filename, 0);
1306 if (in == -1) {
1307 write(2, "can't read ", 11);
1308 write(2, filename, strlen(filename));
1309 write(2, "\n", 1);
1310 _exit(1);
1311 }
1312 fswap(0, in);
1313}
1314
1315/*
1316 * Redirect standard output.
1317 * Same assumptions as for "infrom" above.
1318 */
1319
1320private outto (filename)
1321String filename;
1322{
1323 Fileid out;
1324
1325 out = creat(filename, 0666);
1326 if (out == -1) {
1327 write(2, "can't write ", 12);
1328 write(2, filename, strlen(filename));
1329 write(2, "\n", 1);
1330 _exit(1);
1331 }
1332 fswap(1, out);
1333}
1334
1335/*
1336 * Swap file numbers, useful for redirecting standard input or output.
9a3bab7a
ML
1337 */
1338
1339private fswap(oldfd, newfd)
2fd0f574
SL
1340Fileid oldfd;
1341Fileid newfd;
9a3bab7a
ML
1342{
1343 if (oldfd != newfd) {
1344 close(oldfd);
1345 dup(newfd);
1346 close(newfd);
1347 }
1348}
f7adfe8e 1349
f7adfe8e 1350/*
0022c355 1351 * Signal name manipulation.
f7adfe8e 1352 */
0022c355
ML
1353
1354private String signames[NSIG] = {
1355 0,
1356 "HUP", "INT", "QUIT", "ILL", "TRAP",
1357 "IOT", "EMT", "FPE", "KILL", "BUS",
1358 "SEGV", "SYS", "PIPE", "ALRM", "TERM",
1359 0, "STOP", "TSTP", "CONT", "CHLD",
1360 "TTIN", "TTOU", "TINT", "XCPU", "XFSZ",
f7adfe8e
SL
1361};
1362
1363/*
0022c355
ML
1364 * Get the signal number associated with a given name.
1365 * The name is first translated to upper case if necessary.
f7adfe8e 1366 */
0022c355
ML
1367
1368public integer siglookup (s)
f7adfe8e
SL
1369String s;
1370{
0022c355
ML
1371 register char *p, *q;
1372 char buf[100];
1373 integer i;
1374
1375 p = s;
1376 q = buf;
1377 while (*p != '\0') {
1378 if (*p >= 'a' and *p <= 'z') {
1379 *q = (*p - 'a') + 'A';
1380 } else {
1381 *q = *p;
1382 }
1383 ++p;
1384 ++q;
1385 }
1386 *q = '\0';
1387 p = buf;
1388 if (buf[0] == 'S' and buf[1] == 'I' and buf[2] == 'G') {
1389 p += 3;
1390 }
1391 i = 1;
1392 for (;;) {
1393 if (i >= sizeof(signames) div sizeof(signames[0])) {
1394 error("signal \"%s\" unknown", s);
1395 i = 0;
1396 break;
1397 }
1398 if (signames[i] != nil and streq(signames[i], p)) {
1399 break;
1400 }
1401 ++i;
1402 }
1403 return i;
f7adfe8e
SL
1404}
1405
1406/*
0022c355
ML
1407 * Print all signals being ignored by the debugger.
1408 * These signals are auotmatically
f7adfe8e
SL
1409 * passed on to the debugged process.
1410 */
0022c355
ML
1411
1412public printsigsignored (p)
57a9bb29 1413Process p;
f7adfe8e 1414{
57a9bb29 1415 printsigs(~p->sigset);
f7adfe8e
SL
1416}
1417
1418/*
1419 * Print all signals being intercepted by
1420 * the debugger for the specified process.
1421 */
0022c355 1422
57a9bb29
SL
1423public printsigscaught(p)
1424Process p;
f7adfe8e 1425{
57a9bb29 1426 printsigs(p->sigset);
f7adfe8e
SL
1427}
1428
0022c355
ML
1429private printsigs (set)
1430integer set;
57a9bb29 1431{
0022c355
ML
1432 integer s;
1433 char separator[2];
1434
1435 separator[0] = '\0';
1436 for (s = 1; s < sizeof(signames) div sizeof(signames[0]); s++) {
1437 if (set & setrep(s)) {
1438 if (signames[s] != nil) {
1439 printf("%s%s", separator, signames[s]);
1440 separator[0] = ' ';
1441 separator[1] = '\0';
1442 }
57a9bb29 1443 }
0022c355
ML
1444 }
1445 if (separator[0] == ' ') {
57a9bb29 1446 putchar('\n');
57a9bb29
SL
1447 }
1448}