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