date and time created 83/02/11 15:24:53 by rrh
[unix-history] / usr / src / old / dbx / vax.c
CommitLineData
cd6e9098
ML
1/* Copyright (c) 1982 Regents of the University of California */
2
38f911d6 3static char sccsid[] = "@(#)vax.c 1.5 %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;
263
264 switch (nbytes) {
265 case 1:
266 iread(&byte, addr, sizeof(byte));
267 argval = byte;
268 break;
269
270 case 2:
271 iread(&hword, addr, sizeof(hword));
272 argval = hword;
273 break;
274
275 case 4:
276 iread(&argval, addr, sizeof(argval));
277 break;
278 }
279 if (reg == regname[PROGCTR] && mode >= BYTEDISP) {
280 argval += addr + nbytes;
281 }
282 if (reg == regname[PROGCTR]) {
283 printf("%x", argval);
284 } else {
285 printf("%d(%s)", argval, reg);
286 }
287 return argval;
288}
289
290/*
291 * Print the contents of the addresses within the given range
292 * according to the given format.
293 */
294
295typedef struct {
296 String name;
297 String printfstring;
298 int length;
299} Format;
300
301private Format fmt[] = {
302 { "d", " %d", sizeof(short) },
303 { "D", " %ld", sizeof(long) },
304 { "o", " %o", sizeof(short) },
305 { "O", " %lo", sizeof(long) },
306 { "x", " %04x", sizeof(short) },
307 { "X", " %08x", sizeof(long) },
308 { "b", " \\%o", sizeof(char) },
309 { "c", " '%c'", sizeof(char) },
310 { "s", "%c", sizeof(char) },
311 { "f", " %f", sizeof(double) },
312 { "g", " %g", sizeof(double) },
313 { nil, nil, 0 }
314};
315
316public Address printdata(lowaddr, highaddr, format)
317Address lowaddr;
318Address highaddr;
319String format;
320{
321 register int n;
322 register Address addr;
323 register Format *f;
324 int value;
325
326 if (lowaddr > highaddr) {
327 error("first address larger than second");
328 }
329 f = &fmt[0];
330 while (f->name != nil and not streq(f->name, format)) {
331 ++f;
332 }
333 if (f->name == nil) {
334 error("bad print format \"%s\"", format);
335 }
336 n = 0;
337 value = 0;
338 for (addr = lowaddr; addr <= highaddr; addr += f->length) {
339 if (n == 0) {
340 printf("%08x: ", addr);
341 }
342 dread(&value, addr, f->length);
343 printf(f->printfstring, value);
344 ++n;
345 if (n >= (16 div f->length)) {
346 putchar('\n');
347 n = 0;
348 }
349 }
350 if (n != 0) {
351 putchar('\n');
352 }
353 prtaddr = addr;
354 return addr;
355}
356
357/*
358 * The other approach is to print n items starting with a given address.
359 */
360
361public printndata(count, startaddr, format)
362int count;
363Address startaddr;
364String format;
365{
366 register int i, n;
367 register Address addr;
368 register Format *f;
369 register Boolean isstring;
370 int value;
371
372 if (count <= 0) {
373 error("non-positive repetition count");
374 }
375 f = &fmt[0];
376 while (f->name != nil and not streq(f->name, format)) {
377 ++f;
378 }
379 if (f->name == nil) {
380 error("bad print format \"%s\"", format);
381 }
382 isstring = (Boolean) streq(f->name, "s");
383 n = 0;
384 addr = startaddr;
385 value = 0;
386 for (i = 0; i < count; i++) {
387 if (n == 0) {
388 printf("%08x: ", addr);
389 }
390 if (isstring) {
391 putchar('"');
392 dread(&value, addr, sizeof(char));
393 while (value != '\0') {
394 printchar((char) value);
395 ++addr;
396 dread(&value, addr, sizeof(char));
397 }
398 putchar('"');
399 putchar('\n');
400 n = 0;
401 addr += sizeof(String);
402 } else {
403 dread(&value, addr, f->length);
404 printf(f->printfstring, value);
405 ++n;
406 if (n >= (16 div f->length)) {
407 putchar('\n');
408 n = 0;
409 }
410 addr += f->length;
411 }
412 }
413 if (n != 0) {
414 putchar('\n');
415 }
416 prtaddr = addr;
417}
418
419/*
420 * Print out an execution time error.
8026876b 421 * Assumes the source position of the error has been calculated.
cd6e9098
ML
422 *
423 * Have to check if the -r option was specified; if so then
424 * the object file information hasn't been read in yet.
425 */
426
427public printerror()
428{
429 extern Integer sys_nsig;
430 extern String sys_siglist[];
cd6e9098
ML
431 Integer err;
432
433 if (isfinished(process)) {
434 printf("\"%s\" exits with code %d\n", objname, exitcode(process));
435 erecover();
436 }
437 if (runfirst) {
438 fprintf(stderr, "Entering debugger ...");
439 init();
440 fprintf(stderr, " type 'help' for help\n");
441 }
cd6e9098
ML
442 err = errnum(process);
443 if (err == SIGINT) {
444 printf("\n\ninterrupt ");
445 printloc();
446 } else if (err == SIGTRAP) {
447 printf("\nerror ");
448 printloc();
449 } else {
450 if (err < 0 or err > sys_nsig) {
451 printf("\nsignal %d ", err);
452 } else {
453 printf("\n%s ", sys_siglist[err]);
454 }
455 printloc();
456 }
457 putchar('\n');
458 if (curline > 0) {
459 printlines(curline, curline);
460 } else {
461 printinst(pc, pc);
462 }
463 erecover();
464}
465
466private printloc()
467{
468 if (curline > 0) {
469 if (nlhdr.nfiles > 1) {
470 printf("at line %d in file %s", curline, cursource);
471 } else {
472 printf("at line %d", curline);
473 }
474 } else {
475 printf("in ");
476 printname(stdout, curfunc);
477 printf(" at 0x%x", pc);
478 }
479}
480
481/*
482 * Note the termination of the program. We do this so as to avoid
483 * having the process exit, which would make the values of variables
484 * inaccessible. We do want to flush all output buffers here,
485 * otherwise it'll never get done.
486 */
487
488public endprogram()
489{
490 Integer exitcode;
491
492 stepto(nextaddr(pc, true));
493 printnews();
494 exitcode = argn(1, nil);
495 printf("\nexecution completed, exit code is %d\n", exitcode);
496 getsrcpos();
497 erecover();
498}
499
500/*
501 * Single step the machine a source line (or instruction if "inst_tracing"
38f911d6 502 * is true). If "isnext" is true, skip over procedure calls.
cd6e9098
ML
503 */
504
505private Address getcall();
506
507public dostep(isnext)
508Boolean isnext;
509{
510 register Address addr;
511 register Lineno line;
512 String filename;
513
514 addr = nextaddr(pc, isnext);
38f911d6 515 if (not inst_tracing and nlhdr.nlines != 0) {
cd6e9098
ML
516 line = linelookup(addr);
517 while (line == 0) {
518 addr = nextaddr(addr, isnext);
519 line = linelookup(addr);
520 }
38f911d6
ML
521 curline = line;
522 } else {
523 curline = 0;
cd6e9098
ML
524 }
525 stepto(addr);
cd6e9098
ML
526 filename = srcfilename(addr);
527 setsource(filename);
528}
529
530/*
531 * Compute the next address that will be executed from the given one.
532 * If "isnext" is true then consider a procedure call as straight line code.
533 *
534 * We must unfortunately do much of the same work that is necessary
535 * to print instructions. In addition we have to deal with branches.
536 * Unconditional branches we just follow, for conditional branches
537 * we continue execution to the current location and then single step
538 * the machine. We assume that the last argument in an instruction
539 * that branches is the branch address (or relative offset).
540 */
541
542public Address nextaddr(startaddr, isnext)
543Address startaddr;
544Boolean isnext;
545{
546 register Address addr;
547 Optab op;
548 VaxOpcode ins;
549 unsigned char mode;
550 int argtype, amode, argno, argval;
551 String r;
552 Boolean indexf;
553 enum { KNOWN, SEQUENTIAL, BRANCH } addrstatus;
554
555 argval = 0;
556 indexf = false;
557 addr = startaddr;
558 iread(&ins, addr, sizeof(ins));
559 switch (ins) {
560 case O_BRB:
561 case O_BRW:
562 case O_JMP:
563 addrstatus = BRANCH;
564 break;
565
566 case O_BSBB:
567 case O_BSBW:
568 case O_JSB:
569 case O_CALLG:
570 case O_CALLS:
571 if (isnext) {
572 addrstatus = SEQUENTIAL;
573 } else {
574 addrstatus = KNOWN;
575 stepto(addr);
576 pstep(process);
577 addr = reg(PROGCTR);
578 pc = addr;
579 callnews(/* iscall = */ true);
580 if (not isbperr()) {
581 printstatus();
582 } else {
583 bpact();
584 }
585 }
586 break;
587
588 case O_RSB:
589 case O_RET:
590 addrstatus = KNOWN;
591 callnews(/* iscall = */ false);
592 addr = return_addr();
593 stepto(addr);
594 break;
595
596 case O_BNEQ: case O_BEQL: case O_BGTR:
597 case O_BLEQ: case O_BGEQ: case O_BLSS:
598 case O_BGTRU: case O_BLEQU: case O_BVC:
599 case O_BVS: case O_BCC: case O_BCS:
600 case O_CASEB: case O_CASEW: case O_CASEL:
601 case O_BBS: case O_BBC: case O_BBSS: case O_BBCS:
602 case O_BBSC: case O_BBCC: case O_BBSSI:
603 case O_BBCCI: case O_BLBS: case O_BLBC:
604 case O_ACBL: case O_AOBLSS: case O_AOBLEQ:
605 case O_SOBGEQ: case O_SOBGTR:
606 addrstatus = KNOWN;
607 stepto(addr);
608 pstep(process);
609 addr = reg(PROGCTR);
610 pc = addr;
611 if (not isbperr()) {
612 printstatus();
613 }
614 break;
615
616 default:
617 addrstatus = SEQUENTIAL;
618 break;
619 }
620 if (addrstatus != KNOWN) {
621 addr += 1;
622 op = optab[ins];
623 for (argno = 0; argno < op.numargs; argno++) {
624 if (indexf == true) {
625 indexf = false;
626 }
627 argtype = op.argtype[argno];
628 if (is_branch_disp(argtype)) {
629 mode = 0xAF + (typelen(argtype) << 5);
630 } else {
631 iread(&mode, addr, sizeof(mode));
632 addr += 1;
633 }
634 r = regname[regnm(mode)];
635 amode = addrmode(mode);
636 switch (amode) {
637 case LITSHORT:
638 case LITUPTO31:
639 case LITUPTO47:
640 case LITUPTO63:
641 argval = mode;
642 break;
643
644 case INDEX:
645 indexf = true;
646 --argno;
647 break;
648
649 case REG:
650 case REGDEF:
651 case AUTODEC:
652 break;
653
654 case AUTOINC:
655 if (r == regname[PROGCTR]) {
656 switch (typelen(argtype)) {
657 case TYPB:
658 argval = getdisp(addr, 1, r, amode);
659 addr += 1;
660 break;
661
662 case TYPW:
663 argval = getdisp(addr, 2, r, amode);
664 addr += 2;
665 break;
666
667 case TYPL:
668 argval = getdisp(addr, 4, r, amode);
669 addr += 4;
670 break;
671
672 case TYPF:
673 iread(&argval, addr, sizeof(argval));
674 addr += 4;
675 break;
676
677 case TYPQ:
678 case TYPD:
679 iread(&argval, addr+4, sizeof(argval));
680 addr += 8;
681 break;
682 }
683 }
684 break;
685
686 case AUTOINCDEF:
687 if (r == regname[PROGCTR]) {
688 argval = getdisp(addr, 4, r, amode);
689 addr += 4;
690 }
691 break;
692
693 case BYTEDISP:
694 case BYTEDISPDEF:
695 argval = getdisp(addr, 1, r, amode);
696 addr += 1;
697 break;
698
699 case WORDDISP:
700 case WORDDISPDEF:
701 argval = getdisp(addr, 2, r, amode);
702 addr += 2;
703 break;
704
705 case LONGDISP:
706 case LONGDISPDEF:
707 argval = getdisp(addr, 4, r, amode);
708 addr += 4;
709 break;
710 }
711 }
712 if (ins == O_CALLS or ins == O_CALLG) {
713 argval += 2;
714 }
715 if (addrstatus == BRANCH) {
716 addr = argval;
717 }
718 }
719 return addr;
720}
721
722/*
723 * Get the displacement of an instruction that uses displacement addressing.
724 */
725
726private int getdisp(addr, nbytes, reg, mode)
727Address addr;
728int nbytes;
729String reg;
730int mode;
731{
732 char byte;
733 short hword;
734 int argval;
735
736 switch (nbytes) {
737 case 1:
738 iread(&byte, addr, sizeof(byte));
739 argval = byte;
740 break;
741
742 case 2:
743 iread(&hword, addr, sizeof(hword));
744 argval = hword;
745 break;
746
747 case 4:
748 iread(&argval, addr, sizeof(argval));
749 break;
750 }
751 if (reg == regname[PROGCTR] && mode >= BYTEDISP) {
752 argval += addr + nbytes;
753 }
754 return argval;
755}
756
757#define BP_OP O_BPT /* breakpoint trap */
758#define BP_ERRNO SIGTRAP /* signal received at a breakpoint */
759
760/*
761 * Setting a breakpoint at a location consists of saving
762 * the word at the location and poking a BP_OP there.
763 *
764 * We save the locations and words on a list for use in unsetting.
765 */
766
767typedef struct Savelist *Savelist;
768
769struct Savelist {
770 Address location;
771 Byte save;
772 Byte refcount;
773 Savelist link;
774};
775
776private Savelist savelist;
777
778/*
779 * Set a breakpoint at the given address. Only save the word there
780 * if it's not already a breakpoint.
781 */
782
783public setbp(addr)
784Address addr;
785{
786 Byte w;
787 Byte save;
788 register Savelist newsave, s;
789
790 for (s = savelist; s != nil; s = s->link) {
791 if (s->location == addr) {
792 s->refcount++;
793 return;
794 }
795 }
796 iread(&save, addr, sizeof(addr));
797 newsave = new(Savelist);
798 newsave->location = addr;
799 newsave->save = save;
800 newsave->refcount = 1;
801 newsave->link = savelist;
802 savelist = newsave;
803 w = BP_OP;
804 iwrite(&w, addr, sizeof(w));
805}
806
807/*
808 * Unset a breakpoint; unfortunately we have to search the SAVELIST
809 * to find the saved value. The assumption is that the SAVELIST will
810 * usually be quite small.
811 */
812
813public unsetbp(addr)
814Address addr;
815{
816 register Savelist s, prev;
817
818 prev = nil;
819 for (s = savelist; s != nil; s = s->link) {
820 if (s->location == addr) {
821 iwrite(&s->save, addr, sizeof(s->save));
822 s->refcount--;
823 if (s->refcount == 0) {
824 if (prev == nil) {
825 savelist = s->link;
826 } else {
827 prev->link = s->link;
828 }
829 dispose(s);
830 }
831 return;
832 }
833 prev = s;
834 }
835 panic("unsetbp: couldn't find address %d", addr);
836}
837
838/*
839 * Predicate to test if the reason the process stopped was because
840 * of a breakpoint.
841 */
842
843public Boolean isbperr()
844{
845 return (Boolean) (not isfinished(process) and errnum(process) == SIGTRAP);
846}
847
848/*
849 * Enter a procedure by creating and executing a call instruction.
850 */
851
852#define CALLSIZE 7 /* size of call instruction */
853
854public beginproc(p, argc)
855Symbol p;
856Integer argc;
857{
858 char save[CALLSIZE];
859 struct {
860 VaxOpcode op;
861 unsigned char numargs;
862 unsigned char mode;
863 char addr[sizeof(long)]; /* unaligned long */
864 } call;
865 long dest;
866
867 pc = 2;
868 iread(save, pc, sizeof(save));
869 call.op = O_CALLS;
870 call.numargs = argc;
871 call.mode = 0xef;
872 dest = codeloc(p) - 2 - (pc + 7);
873 mov(&dest, call.addr, sizeof(call.addr));
874 iwrite(&call, pc, sizeof(call));
875 setreg(PROGCTR, pc);
876 pstep(process);
877 iwrite(save, pc, sizeof(save));
878 pc = reg(PROGCTR);
879 if (not isbperr()) {
880 printstatus();
881 }
882}