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