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