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