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