4.3BSD beta release manual page
[unix-history] / usr / src / old / dbx / vax.c
CommitLineData
cd6e9098
ML
1/* Copyright (c) 1982 Regents of the University of California */
2
0022c355
ML
3static char sccsid[] = "@(#)vax.c 1.13 (Berkeley) %G%";
4
5static char rcsid[] = "$Header: machine.c,v 1.5 84/12/26 10:40:05 linton Exp $";
cd6e9098
ML
6
7/*
8 * Target machine dependent stuff.
9 */
10
11#include "defs.h"
12#include "machine.h"
13#include "process.h"
2fd0f574 14#include "runtime.h"
cd6e9098
ML
15#include "events.h"
16#include "main.h"
17#include "symbols.h"
18#include "source.h"
19#include "mappings.h"
20#include "object.h"
0022c355 21#include "keywords.h"
9882bead 22#include "ops.h"
cd6e9098
ML
23#include <signal.h>
24
25#ifndef public
26typedef unsigned int Address;
27typedef unsigned char Byte;
28typedef unsigned int Word;
29
30#define NREG 16
31
32#define ARGP 12
33#define FRP 13
34#define STKP 14
35#define PROGCTR 15
36
37#define BITSPERBYTE 8
38#define BITSPERWORD (BITSPERBYTE * sizeof(Word))
39
40#define nargspassed(frame) argn(0, frame)
41
42#include "source.h"
43#include "symbols.h"
44
45Address pc;
46Address prtaddr;
47
48#endif
49
50private Address printop();
51
52/*
53 * Decode and print the instructions within the given address range.
54 */
55
56public printinst(lowaddr, highaddr)
57Address lowaddr;
58Address highaddr;
59{
60 register Address addr;
61
62 for (addr = lowaddr; addr <= highaddr; ) {
63 addr = printop(addr);
64 }
65 prtaddr = addr;
66}
67
68/*
69 * Another approach: print n instructions starting at the given address.
70 */
71
72public printninst(count, addr)
73int count;
74Address addr;
75{
76 register Integer i;
77 register Address newaddr;
78
79 if (count <= 0) {
80 error("non-positive repetition count");
81 } else {
82 newaddr = addr;
83 for (i = 0; i < count; i++) {
84 newaddr = printop(newaddr);
85 }
86 prtaddr = newaddr;
87 }
88}
89
90/*
91 * Hacked version of adb's VAX instruction decoder.
92 */
93
94private Address printop(addr)
95Address addr;
96{
97 Optab op;
98 VaxOpcode ins;
99 unsigned char mode;
100 int argtype, amode, argno, argval;
101 String reg;
102 Boolean indexf;
103 short offset;
104
105 argval = 0;
106 indexf = false;
107 printf("%08x ", addr);
108 iread(&ins, addr, sizeof(ins));
109 addr += 1;
110 op = optab[ins];
111 printf("%s", op.iname);
112 for (argno = 0; argno < op.numargs; argno++) {
113 if (indexf == true) {
114 indexf = false;
115 } else if (argno == 0) {
116 printf("\t");
117 } else {
118 printf(",");
119 }
120 argtype = op.argtype[argno];
121 if (is_branch_disp(argtype)) {
122 mode = 0xAF + (typelen(argtype) << 5);
123 } else {
124 iread(&mode, addr, sizeof(mode));
125 addr += 1;
126 }
127 reg = regname[regnm(mode)];
128 amode = addrmode(mode);
129 switch (amode) {
130 case LITSHORT:
131 case LITUPTO31:
132 case LITUPTO47:
133 case LITUPTO63:
134 if (typelen(argtype) == TYPF || typelen(argtype) ==TYPD)
135 printf("$%s", fltimm[mode]);
136 else
137 printf("$%x", mode);
138 argval = mode;
139 break;
140
141 case INDEX:
142 printf("[%s]", reg);
143 indexf = true;
144 argno--;
145 break;
146
147 case REG:
148 printf("%s", reg);
149 break;
150
151 case REGDEF:
152 printf("(%s)", reg);
153 break;
154
155 case AUTODEC:
156 printf("-(%s)", reg);
157 break;
158
159 case AUTOINC:
160 if (reg != regname[PROGCTR]) {
161 printf("(%s)+", reg);
162 } else {
163 printf("$");
164 switch (typelen(argtype)) {
165 case TYPB:
166 argval = printdisp(addr, 1, reg, amode);
167 addr += 1;
168 break;
169
170 case TYPW:
171 argval = printdisp(addr, 2, reg, amode);
172 addr += 2;
173 break;
174
175 case TYPL:
176 argval = printdisp(addr, 4, reg, amode);
177 addr += 4;
178 break;
179
180 case TYPF:
181 iread(&argval, addr, sizeof(argval));
182 printf("%06x", argval);
183 addr += 4;
184 break;
185
186 case TYPQ:
187 case TYPD:
188 iread(&argval, addr, sizeof(argval));
189 printf("%06x", argval);
190 iread(&argval, addr+4, sizeof(argval));
191 printf("%06x", argval);
192 addr += 8;
193 break;
194 }
195 }
196 break;
197
198 case AUTOINCDEF:
199 if (reg == regname[PROGCTR]) {
200 printf("*$");
201 argval = printdisp(addr, 4, reg, amode);
202 addr += 4;
203 } else {
204 printf("*(%s)+", reg);
205 }
206 break;
207
208 case BYTEDISP:
209 argval = printdisp(addr, 1, reg, amode);
210 addr += 1;
211 break;
212
213 case BYTEDISPDEF:
214 printf("*");
215 argval = printdisp(addr, 1, reg, amode);
216 addr += 1;
217 break;
218
219 case WORDDISP:
220 argval = printdisp(addr, 2, reg, amode);
221 addr += 2;
222 break;
223
224 case WORDDISPDEF:
225 printf("*");
226 argval = printdisp(addr, 2, reg, amode);
227 addr += 2;
228 break;
229
230 case LONGDISP:
231 argval = printdisp(addr, 4, reg, amode);
232 addr += 4;
233 break;
234
235 case LONGDISPDEF:
236 printf("*");
237 argval = printdisp(addr, 4, reg, amode);
238 addr += 4;
239 break;
240 }
241 }
242 if (ins == O_CASEB || ins == O_CASEW || ins == O_CASEL) {
243 for (argno = 0; argno <= argval; argno++) {
244 iread(&offset, addr, sizeof(offset));
245 printf("\n\t\t%d", offset);
246 addr += 2;
247 }
248 }
249 printf("\n");
250 return addr;
251}
252
253/*
254 * Print the displacement of an instruction that uses displacement
255 * addressing.
256 */
257
258private int printdisp(addr, nbytes, reg, mode)
259Address addr;
260int nbytes;
261char *reg;
262int mode;
263{
264 char byte;
265 short hword;
266 int argval;
5d8fcc0a 267 Symbol f;
cd6e9098
ML
268
269 switch (nbytes) {
270 case 1:
271 iread(&byte, addr, sizeof(byte));
272 argval = byte;
273 break;
274
275 case 2:
276 iread(&hword, addr, sizeof(hword));
277 argval = hword;
278 break;
279
280 case 4:
281 iread(&argval, addr, sizeof(argval));
282 break;
283 }
284 if (reg == regname[PROGCTR] && mode >= BYTEDISP) {
285 argval += addr + nbytes;
286 }
287 if (reg == regname[PROGCTR]) {
5d8fcc0a
ML
288 f = whatblock((Address) argval + 2);
289 if (codeloc(f) == argval + 2) {
290 printf("%s", symname(f));
291 } else {
292 printf("%x", argval);
293 }
cd6e9098 294 } else {
0022c355
ML
295 if (varIsSet("$hexoffsets")) {
296 if (argval < 0) {
297 printf("-%x(%s)", -(argval), reg);
298 } else {
299 printf("%x(%s)", argval, reg);
300 }
301 } else {
302 printf("%d(%s)", argval, reg);
303 }
cd6e9098
ML
304 }
305 return argval;
306}
307
308/*
309 * Print the contents of the addresses within the given range
310 * according to the given format.
311 */
312
313typedef struct {
314 String name;
315 String printfstring;
316 int length;
317} Format;
318
319private Format fmt[] = {
320 { "d", " %d", sizeof(short) },
321 { "D", " %ld", sizeof(long) },
322 { "o", " %o", sizeof(short) },
323 { "O", " %lo", sizeof(long) },
324 { "x", " %04x", sizeof(short) },
325 { "X", " %08x", sizeof(long) },
326 { "b", " \\%o", sizeof(char) },
327 { "c", " '%c'", sizeof(char) },
328 { "s", "%c", sizeof(char) },
5d8fcc0a 329 { "f", " %f", sizeof(float) },
cd6e9098
ML
330 { "g", " %g", sizeof(double) },
331 { nil, nil, 0 }
332};
333
08cf9c08
ML
334private Format *findformat(s)
335String s;
336{
337 register Format *f;
338
339 f = &fmt[0];
340 while (f->name != nil and not streq(f->name, s)) {
341 ++f;
342 }
343 if (f->name == nil) {
344 error("bad print format \"%s\"", s);
345 }
346 return f;
347}
348
cd6e9098
ML
349public Address printdata(lowaddr, highaddr, format)
350Address lowaddr;
351Address highaddr;
352String format;
353{
354 register int n;
355 register Address addr;
356 register Format *f;
357 int value;
358
359 if (lowaddr > highaddr) {
360 error("first address larger than second");
361 }
08cf9c08 362 f = findformat(format);
cd6e9098
ML
363 n = 0;
364 value = 0;
365 for (addr = lowaddr; addr <= highaddr; addr += f->length) {
366 if (n == 0) {
367 printf("%08x: ", addr);
368 }
369 dread(&value, addr, f->length);
370 printf(f->printfstring, value);
371 ++n;
372 if (n >= (16 div f->length)) {
373 putchar('\n');
374 n = 0;
375 }
376 }
377 if (n != 0) {
378 putchar('\n');
379 }
380 prtaddr = addr;
381 return addr;
382}
383
384/*
385 * The other approach is to print n items starting with a given address.
386 */
387
388public printndata(count, startaddr, format)
389int count;
390Address startaddr;
391String format;
392{
393 register int i, n;
394 register Address addr;
395 register Format *f;
396 register Boolean isstring;
5d8fcc0a
ML
397 char c;
398 union {
399 char charv;
400 short shortv;
401 int intv;
402 float floatv;
403 double doublev;
404 } value;
cd6e9098
ML
405
406 if (count <= 0) {
407 error("non-positive repetition count");
408 }
08cf9c08 409 f = findformat(format);
cd6e9098
ML
410 isstring = (Boolean) streq(f->name, "s");
411 n = 0;
412 addr = startaddr;
5d8fcc0a 413 value.intv = 0;
cd6e9098
ML
414 for (i = 0; i < count; i++) {
415 if (n == 0) {
416 printf("%08x: ", addr);
417 }
418 if (isstring) {
419 putchar('"');
5d8fcc0a
ML
420 dread(&c, addr, sizeof(char));
421 while (c != '\0') {
422 printchar(c);
cd6e9098 423 ++addr;
5d8fcc0a 424 dread(&c, addr, sizeof(char));
cd6e9098
ML
425 }
426 putchar('"');
427 putchar('\n');
428 n = 0;
429 addr += sizeof(String);
430 } else {
431 dread(&value, addr, f->length);
432 printf(f->printfstring, value);
433 ++n;
434 if (n >= (16 div f->length)) {
435 putchar('\n');
436 n = 0;
437 }
438 addr += f->length;
439 }
440 }
441 if (n != 0) {
442 putchar('\n');
443 }
444 prtaddr = addr;
445}
446
08cf9c08
ML
447/*
448 * Print out a value according to the given format.
449 */
450
451public printvalue(v, format)
452long v;
453String format;
454{
455 Format *f;
456 char *p, *q;
457
458 f = findformat(format);
459 if (streq(f->name, "s")) {
460 putchar('"');
461 p = (char *) &v;
462 q = p + sizeof(v);
463 while (p < q) {
464 printchar(*p);
465 ++p;
466 }
467 putchar('"');
468 } else {
469 printf(f->printfstring, v);
470 }
471 putchar('\n');
472}
473
cd6e9098
ML
474/*
475 * Print out an execution time error.
8026876b 476 * Assumes the source position of the error has been calculated.
cd6e9098
ML
477 *
478 * Have to check if the -r option was specified; if so then
479 * the object file information hasn't been read in yet.
480 */
481
482public printerror()
483{
484 extern Integer sys_nsig;
485 extern String sys_siglist[];
0022c355 486 integer err;
cd6e9098
ML
487
488 if (isfinished(process)) {
1853d822 489 err = exitcode(process);
0022c355
ML
490 if (err == 0) {
491 printf("\"%s\" terminated normally\n", objname);
492 } else {
493 printf("\"%s\" terminated abnormally (exit code %d)\n",
494 objname, err
495 );
496 }
cd6e9098
ML
497 erecover();
498 }
499 if (runfirst) {
0022c355 500 fprintf(stderr, "Entering debugger ...\n");
cd6e9098 501 init();
cd6e9098 502 }
cd6e9098 503 err = errnum(process);
1853d822
SL
504 putchar('\n');
505 printsig(err);
0022c355 506 putchar(' ');
1853d822 507 printloc();
cd6e9098
ML
508 putchar('\n');
509 if (curline > 0) {
510 printlines(curline, curline);
511 } else {
512 printinst(pc, pc);
513 }
514 erecover();
515}
516
0022c355
ML
517/*
518 * Print out a signal.
519 */
520
1853d822 521private String illinames[] = {
0022c355
ML
522 "reserved addressing fault",
523 "priviliged instruction fault",
524 "reserved operand fault"
1853d822 525};
0022c355 526
1853d822 527private String fpenames[] = {
0022c355
ML
528 nil,
529 "integer overflow trap",
530 "integer divide by zero trap",
531 "floating overflow trap",
532 "floating/decimal divide by zero trap",
533 "floating underflow trap",
534 "decimal overflow trap",
535 "subscript out of range trap",
536 "floating overflow fault",
537 "floating divide by zero fault",
538 "floating undeflow fault"
1853d822
SL
539};
540
0022c355
ML
541public printsig (signo)
542integer signo;
1853d822 543{
0022c355 544 integer code;
1853d822 545
0022c355
ML
546 if (signo < 0 or signo > sys_nsig) {
547 printf("[signal %d]", signo);
548 } else {
549 printf("%s", sys_siglist[signo]);
550 }
551 code = errcode(process);
552 if (signo == SIGILL) {
553 if (code >= 0 and code < sizeof(illinames) / sizeof(illinames[0])) {
554 printf(" (%s)", illinames[code]);
555 }
556 } else if (signo == SIGFPE) {
557 if (code > 0 and code < sizeof(fpenames) / sizeof(fpenames[0])) {
558 printf(" (%s)", fpenames[code]);
559 }
1853d822
SL
560 }
561}
562
cd6e9098
ML
563/*
564 * Note the termination of the program. We do this so as to avoid
565 * having the process exit, which would make the values of variables
566 * inaccessible. We do want to flush all output buffers here,
567 * otherwise it'll never get done.
568 */
569
570public endprogram()
571{
572 Integer exitcode;
573
574 stepto(nextaddr(pc, true));
575 printnews();
576 exitcode = argn(1, nil);
0022c355
ML
577 if (exitcode != 0) {
578 printf("\nexecution completed (exit code %d)\n", exitcode);
579 } else {
580 printf("\nexecution completed\n");
581 }
cd6e9098
ML
582 getsrcpos();
583 erecover();
584}
585
586/*
587 * Single step the machine a source line (or instruction if "inst_tracing"
38f911d6 588 * is true). If "isnext" is true, skip over procedure calls.
cd6e9098
ML
589 */
590
591private Address getcall();
592
593public dostep(isnext)
594Boolean isnext;
595{
596 register Address addr;
597 register Lineno line;
598 String filename;
0022c355 599 Address startaddr;
cd6e9098 600
2fd0f574 601 startaddr = pc;
cd6e9098 602 addr = nextaddr(pc, isnext);
38f911d6 603 if (not inst_tracing and nlhdr.nlines != 0) {
cd6e9098
ML
604 line = linelookup(addr);
605 while (line == 0) {
0022c355 606 addr = nextaddr(addr, isnext);
cd6e9098
ML
607 line = linelookup(addr);
608 }
38f911d6
ML
609 curline = line;
610 } else {
611 curline = 0;
cd6e9098
ML
612 }
613 stepto(addr);
cd6e9098
ML
614 filename = srcfilename(addr);
615 setsource(filename);
616}
617
618/*
619 * Compute the next address that will be executed from the given one.
620 * If "isnext" is true then consider a procedure call as straight line code.
621 *
622 * We must unfortunately do much of the same work that is necessary
623 * to print instructions. In addition we have to deal with branches.
624 * Unconditional branches we just follow, for conditional branches
625 * we continue execution to the current location and then single step
626 * the machine. We assume that the last argument in an instruction
627 * that branches is the branch address (or relative offset).
628 */
629
0022c355
ML
630private Address findnextaddr();
631
cd6e9098
ML
632public Address nextaddr(startaddr, isnext)
633Address startaddr;
2fd0f574
SL
634boolean isnext;
635{
636 Address addr;
637
638 addr = usignal(process);
639 if (addr == 0 or addr == 1) {
640 addr = findnextaddr(startaddr, isnext);
641 }
642 return addr;
643}
644
0022c355
ML
645/*
646 * Determine if it's ok to skip function f entered by instruction ins.
647 * If so, we're going to compute the return address and step to it.
648 * Therefore we cannot skip over a function entered by a jsb or bsb,
649 * since the return address is not easily computed for them.
650 */
651
652private boolean skipfunc (ins, f)
653VaxOpcode ins;
654Symbol f;
655{
656 boolean b;
657
658 b = (boolean) (
659 ins != O_JSB and ins != O_BSBB and ins != O_BSBW and
660 not inst_tracing and nlhdr.nlines != 0 and
661 nosource(curfunc) and canskip(curfunc)
662 );
663 return b;
664}
665
2fd0f574
SL
666private Address findnextaddr(startaddr, isnext)
667Address startaddr;
cd6e9098
ML
668Boolean isnext;
669{
670 register Address addr;
671 Optab op;
672 VaxOpcode ins;
673 unsigned char mode;
674 int argtype, amode, argno, argval;
675 String r;
676 Boolean indexf;
677 enum { KNOWN, SEQUENTIAL, BRANCH } addrstatus;
678
679 argval = 0;
680 indexf = false;
681 addr = startaddr;
682 iread(&ins, addr, sizeof(ins));
683 switch (ins) {
0022c355
ML
684 /*
685 * It used to be that unconditional jumps and branches were handled
686 * by taking their destination address as the next address. While
687 * saving the cost of starting up the process, this approach
688 * doesn't work when jumping indirect (since the value in the
689 * register might not yet have been set).
690 *
691 * So unconditional jumps and branches are now handled the same way
692 * as conditional jumps and branches.
693 *
cd6e9098
ML
694 case O_BRB:
695 case O_BRW:
cd6e9098
ML
696 addrstatus = BRANCH;
697 break;
0022c355
ML
698 *
699 */
cd6e9098
ML
700
701 case O_BSBB:
702 case O_BSBW:
703 case O_JSB:
704 case O_CALLG:
705 case O_CALLS:
0022c355
ML
706 addrstatus = KNOWN;
707 stepto(addr);
708 pstep(process, DEFSIG);
709 addr = reg(PROGCTR);
710 pc = addr;
711 setcurfunc(whatblock(pc));
712 if (not isbperr()) {
713 printstatus();
714 /* NOTREACHED */
715 }
716 bpact();
717 if (isnext or skipfunc(ins, curfunc)) {
cd6e9098 718 addrstatus = KNOWN;
0022c355 719 addr = return_addr();
cd6e9098 720 stepto(addr);
eac2165c 721 bpact();
0022c355
ML
722 } else {
723 callnews(/* iscall = */ true);
cd6e9098
ML
724 }
725 break;
726
727 case O_RSB:
728 case O_RET:
729 addrstatus = KNOWN;
0022c355 730 stepto(addr);
cd6e9098 731 callnews(/* iscall = */ false);
0022c355
ML
732 pstep(process, DEFSIG);
733 addr = reg(PROGCTR);
734 pc = addr;
735 if (not isbperr()) {
736 printstatus();
2fd0f574 737 }
3b5f59dc 738 bpact();
cd6e9098
ML
739 break;
740
0022c355 741 case O_BRB: case O_BRW:
2fd0f574 742 case O_JMP: /* because it may be jmp (r1) */
cd6e9098
ML
743 case O_BNEQ: case O_BEQL: case O_BGTR:
744 case O_BLEQ: case O_BGEQ: case O_BLSS:
745 case O_BGTRU: case O_BLEQU: case O_BVC:
746 case O_BVS: case O_BCC: case O_BCS:
747 case O_CASEB: case O_CASEW: case O_CASEL:
748 case O_BBS: case O_BBC: case O_BBSS: case O_BBCS:
749 case O_BBSC: case O_BBCC: case O_BBSSI:
750 case O_BBCCI: case O_BLBS: case O_BLBC:
751 case O_ACBL: case O_AOBLSS: case O_AOBLEQ:
752 case O_SOBGEQ: case O_SOBGTR:
753 addrstatus = KNOWN;
754 stepto(addr);
2fd0f574 755 pstep(process, DEFSIG);
cd6e9098
ML
756 addr = reg(PROGCTR);
757 pc = addr;
758 if (not isbperr()) {
759 printstatus();
760 }
761 break;
762
763 default:
764 addrstatus = SEQUENTIAL;
765 break;
766 }
767 if (addrstatus != KNOWN) {
768 addr += 1;
769 op = optab[ins];
770 for (argno = 0; argno < op.numargs; argno++) {
771 if (indexf == true) {
772 indexf = false;
773 }
774 argtype = op.argtype[argno];
775 if (is_branch_disp(argtype)) {
776 mode = 0xAF + (typelen(argtype) << 5);
777 } else {
778 iread(&mode, addr, sizeof(mode));
779 addr += 1;
780 }
781 r = regname[regnm(mode)];
782 amode = addrmode(mode);
783 switch (amode) {
784 case LITSHORT:
785 case LITUPTO31:
786 case LITUPTO47:
787 case LITUPTO63:
788 argval = mode;
789 break;
790
791 case INDEX:
792 indexf = true;
793 --argno;
794 break;
795
796 case REG:
797 case REGDEF:
798 case AUTODEC:
799 break;
800
801 case AUTOINC:
802 if (r == regname[PROGCTR]) {
803 switch (typelen(argtype)) {
804 case TYPB:
805 argval = getdisp(addr, 1, r, amode);
806 addr += 1;
807 break;
808
809 case TYPW:
810 argval = getdisp(addr, 2, r, amode);
811 addr += 2;
812 break;
813
814 case TYPL:
815 argval = getdisp(addr, 4, r, amode);
816 addr += 4;
817 break;
818
819 case TYPF:
820 iread(&argval, addr, sizeof(argval));
821 addr += 4;
822 break;
823
824 case TYPQ:
825 case TYPD:
826 iread(&argval, addr+4, sizeof(argval));
827 addr += 8;
828 break;
829 }
830 }
831 break;
832
833 case AUTOINCDEF:
834 if (r == regname[PROGCTR]) {
835 argval = getdisp(addr, 4, r, amode);
836 addr += 4;
837 }
838 break;
839
840 case BYTEDISP:
841 case BYTEDISPDEF:
842 argval = getdisp(addr, 1, r, amode);
843 addr += 1;
844 break;
845
846 case WORDDISP:
847 case WORDDISPDEF:
848 argval = getdisp(addr, 2, r, amode);
849 addr += 2;
850 break;
851
852 case LONGDISP:
853 case LONGDISPDEF:
854 argval = getdisp(addr, 4, r, amode);
855 addr += 4;
856 break;
857 }
858 }
859 if (ins == O_CALLS or ins == O_CALLG) {
860 argval += 2;
861 }
862 if (addrstatus == BRANCH) {
863 addr = argval;
864 }
865 }
866 return addr;
867}
868
869/*
870 * Get the displacement of an instruction that uses displacement addressing.
871 */
872
873private int getdisp(addr, nbytes, reg, mode)
874Address addr;
875int nbytes;
876String reg;
877int mode;
878{
879 char byte;
880 short hword;
881 int argval;
882
883 switch (nbytes) {
884 case 1:
885 iread(&byte, addr, sizeof(byte));
886 argval = byte;
887 break;
888
889 case 2:
890 iread(&hword, addr, sizeof(hword));
891 argval = hword;
892 break;
893
894 case 4:
895 iread(&argval, addr, sizeof(argval));
896 break;
897 }
898 if (reg == regname[PROGCTR] && mode >= BYTEDISP) {
899 argval += addr + nbytes;
900 }
901 return argval;
902}
903
904#define BP_OP O_BPT /* breakpoint trap */
905#define BP_ERRNO SIGTRAP /* signal received at a breakpoint */
906
907/*
908 * Setting a breakpoint at a location consists of saving
909 * the word at the location and poking a BP_OP there.
910 *
911 * We save the locations and words on a list for use in unsetting.
912 */
913
914typedef struct Savelist *Savelist;
915
916struct Savelist {
917 Address location;
918 Byte save;
919 Byte refcount;
920 Savelist link;
921};
922
923private Savelist savelist;
924
925/*
926 * Set a breakpoint at the given address. Only save the word there
927 * if it's not already a breakpoint.
928 */
929
930public setbp(addr)
931Address addr;
932{
933 Byte w;
934 Byte save;
935 register Savelist newsave, s;
936
937 for (s = savelist; s != nil; s = s->link) {
938 if (s->location == addr) {
939 s->refcount++;
940 return;
941 }
942 }
08cf9c08 943 iread(&save, addr, sizeof(save));
cd6e9098
ML
944 newsave = new(Savelist);
945 newsave->location = addr;
946 newsave->save = save;
947 newsave->refcount = 1;
948 newsave->link = savelist;
949 savelist = newsave;
950 w = BP_OP;
951 iwrite(&w, addr, sizeof(w));
952}
953
954/*
955 * Unset a breakpoint; unfortunately we have to search the SAVELIST
956 * to find the saved value. The assumption is that the SAVELIST will
957 * usually be quite small.
958 */
959
960public unsetbp(addr)
961Address addr;
962{
963 register Savelist s, prev;
964
965 prev = nil;
966 for (s = savelist; s != nil; s = s->link) {
967 if (s->location == addr) {
968 iwrite(&s->save, addr, sizeof(s->save));
969 s->refcount--;
970 if (s->refcount == 0) {
971 if (prev == nil) {
972 savelist = s->link;
973 } else {
974 prev->link = s->link;
975 }
976 dispose(s);
977 }
978 return;
979 }
980 prev = s;
981 }
982 panic("unsetbp: couldn't find address %d", addr);
983}
984
cd6e9098
ML
985/*
986 * Enter a procedure by creating and executing a call instruction.
987 */
988
989#define CALLSIZE 7 /* size of call instruction */
990
991public beginproc(p, argc)
992Symbol p;
993Integer argc;
994{
995 char save[CALLSIZE];
996 struct {
997 VaxOpcode op;
998 unsigned char numargs;
999 unsigned char mode;
1000 char addr[sizeof(long)]; /* unaligned long */
1001 } call;
1002 long dest;
1003
1004 pc = 2;
1005 iread(save, pc, sizeof(save));
1006 call.op = O_CALLS;
1007 call.numargs = argc;
1008 call.mode = 0xef;
1009 dest = codeloc(p) - 2 - (pc + 7);
1010 mov(&dest, call.addr, sizeof(call.addr));
1011 iwrite(&call, pc, sizeof(call));
1012 setreg(PROGCTR, pc);
2fd0f574 1013 pstep(process, DEFSIG);
cd6e9098
ML
1014 iwrite(save, pc, sizeof(save));
1015 pc = reg(PROGCTR);
1016 if (not isbperr()) {
1017 printstatus();
1018 }
1019}