date and time created 82/12/15 04:07:50 by linton
[unix-history] / usr / src / old / dbx / vax.c
CommitLineData
cd6e9098
ML
1/* Copyright (c) 1982 Regents of the University of California */
2
3static char sccsid[] = "@(#)@(#)vax.c 1.1 %G%";
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"
18#include "vaxops.h"
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.
421 *
422 * Have to check if the -r option was specified; if so then
423 * the object file information hasn't been read in yet.
424 */
425
426public printerror()
427{
428 extern Integer sys_nsig;
429 extern String sys_siglist[];
430 String filename;
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 }
442 curline = srcline(pc);
443 curfunc = whatblock(pc);
444 filename = srcfilename(pc);
445 setsource(filename);
446 err = errnum(process);
447 if (err == SIGINT) {
448 printf("\n\ninterrupt ");
449 printloc();
450 } else if (err == SIGTRAP) {
451 printf("\nerror ");
452 printloc();
453 } else {
454 if (err < 0 or err > sys_nsig) {
455 printf("\nsignal %d ", err);
456 } else {
457 printf("\n%s ", sys_siglist[err]);
458 }
459 printloc();
460 }
461 putchar('\n');
462 if (curline > 0) {
463 printlines(curline, curline);
464 } else {
465 printinst(pc, pc);
466 }
467 erecover();
468}
469
470private printloc()
471{
472 if (curline > 0) {
473 if (nlhdr.nfiles > 1) {
474 printf("at line %d in file %s", curline, cursource);
475 } else {
476 printf("at line %d", curline);
477 }
478 } else {
479 printf("in ");
480 printname(stdout, curfunc);
481 printf(" at 0x%x", pc);
482 }
483}
484
485/*
486 * Note the termination of the program. We do this so as to avoid
487 * having the process exit, which would make the values of variables
488 * inaccessible. We do want to flush all output buffers here,
489 * otherwise it'll never get done.
490 */
491
492public endprogram()
493{
494 Integer exitcode;
495
496 stepto(nextaddr(pc, true));
497 printnews();
498 exitcode = argn(1, nil);
499 printf("\nexecution completed, exit code is %d\n", exitcode);
500 getsrcpos();
501 erecover();
502}
503
504/*
505 * Single step the machine a source line (or instruction if "inst_tracing"
506 * is true. If "isnext" is true, skip over procedure calls.
507 */
508
509private Address getcall();
510
511public dostep(isnext)
512Boolean isnext;
513{
514 register Address addr;
515 register Lineno line;
516 String filename;
517
518 addr = nextaddr(pc, isnext);
519 if (not inst_tracing) {
520 line = linelookup(addr);
521 while (line == 0) {
522 addr = nextaddr(addr, isnext);
523 line = linelookup(addr);
524 }
525 }
526 stepto(addr);
527 curline = line;
528 filename = srcfilename(addr);
529 setsource(filename);
530}
531
532/*
533 * Compute the next address that will be executed from the given one.
534 * If "isnext" is true then consider a procedure call as straight line code.
535 *
536 * We must unfortunately do much of the same work that is necessary
537 * to print instructions. In addition we have to deal with branches.
538 * Unconditional branches we just follow, for conditional branches
539 * we continue execution to the current location and then single step
540 * the machine. We assume that the last argument in an instruction
541 * that branches is the branch address (or relative offset).
542 */
543
544public Address nextaddr(startaddr, isnext)
545Address startaddr;
546Boolean isnext;
547{
548 register Address addr;
549 Optab op;
550 VaxOpcode ins;
551 unsigned char mode;
552 int argtype, amode, argno, argval;
553 String r;
554 Boolean indexf;
555 enum { KNOWN, SEQUENTIAL, BRANCH } addrstatus;
556
557 argval = 0;
558 indexf = false;
559 addr = startaddr;
560 iread(&ins, addr, sizeof(ins));
561 switch (ins) {
562 case O_BRB:
563 case O_BRW:
564 case O_JMP:
565 addrstatus = BRANCH;
566 break;
567
568 case O_BSBB:
569 case O_BSBW:
570 case O_JSB:
571 case O_CALLG:
572 case O_CALLS:
573 if (isnext) {
574 addrstatus = SEQUENTIAL;
575 } else {
576 addrstatus = KNOWN;
577 stepto(addr);
578 pstep(process);
579 addr = reg(PROGCTR);
580 pc = addr;
581 callnews(/* iscall = */ true);
582 if (not isbperr()) {
583 printstatus();
584 } else {
585 bpact();
586 }
587 }
588 break;
589
590 case O_RSB:
591 case O_RET:
592 addrstatus = KNOWN;
593 callnews(/* iscall = */ false);
594 addr = return_addr();
595 stepto(addr);
596 break;
597
598 case O_BNEQ: case O_BEQL: case O_BGTR:
599 case O_BLEQ: case O_BGEQ: case O_BLSS:
600 case O_BGTRU: case O_BLEQU: case O_BVC:
601 case O_BVS: case O_BCC: case O_BCS:
602 case O_CASEB: case O_CASEW: case O_CASEL:
603 case O_BBS: case O_BBC: case O_BBSS: case O_BBCS:
604 case O_BBSC: case O_BBCC: case O_BBSSI:
605 case O_BBCCI: case O_BLBS: case O_BLBC:
606 case O_ACBL: case O_AOBLSS: case O_AOBLEQ:
607 case O_SOBGEQ: case O_SOBGTR:
608 addrstatus = KNOWN;
609 stepto(addr);
610 pstep(process);
611 addr = reg(PROGCTR);
612 pc = addr;
613 if (not isbperr()) {
614 printstatus();
615 }
616 break;
617
618 default:
619 addrstatus = SEQUENTIAL;
620 break;
621 }
622 if (addrstatus != KNOWN) {
623 addr += 1;
624 op = optab[ins];
625 for (argno = 0; argno < op.numargs; argno++) {
626 if (indexf == true) {
627 indexf = false;
628 }
629 argtype = op.argtype[argno];
630 if (is_branch_disp(argtype)) {
631 mode = 0xAF + (typelen(argtype) << 5);
632 } else {
633 iread(&mode, addr, sizeof(mode));
634 addr += 1;
635 }
636 r = regname[regnm(mode)];
637 amode = addrmode(mode);
638 switch (amode) {
639 case LITSHORT:
640 case LITUPTO31:
641 case LITUPTO47:
642 case LITUPTO63:
643 argval = mode;
644 break;
645
646 case INDEX:
647 indexf = true;
648 --argno;
649 break;
650
651 case REG:
652 case REGDEF:
653 case AUTODEC:
654 break;
655
656 case AUTOINC:
657 if (r == regname[PROGCTR]) {
658 switch (typelen(argtype)) {
659 case TYPB:
660 argval = getdisp(addr, 1, r, amode);
661 addr += 1;
662 break;
663
664 case TYPW:
665 argval = getdisp(addr, 2, r, amode);
666 addr += 2;
667 break;
668
669 case TYPL:
670 argval = getdisp(addr, 4, r, amode);
671 addr += 4;
672 break;
673
674 case TYPF:
675 iread(&argval, addr, sizeof(argval));
676 addr += 4;
677 break;
678
679 case TYPQ:
680 case TYPD:
681 iread(&argval, addr+4, sizeof(argval));
682 addr += 8;
683 break;
684 }
685 }
686 break;
687
688 case AUTOINCDEF:
689 if (r == regname[PROGCTR]) {
690 argval = getdisp(addr, 4, r, amode);
691 addr += 4;
692 }
693 break;
694
695 case BYTEDISP:
696 case BYTEDISPDEF:
697 argval = getdisp(addr, 1, r, amode);
698 addr += 1;
699 break;
700
701 case WORDDISP:
702 case WORDDISPDEF:
703 argval = getdisp(addr, 2, r, amode);
704 addr += 2;
705 break;
706
707 case LONGDISP:
708 case LONGDISPDEF:
709 argval = getdisp(addr, 4, r, amode);
710 addr += 4;
711 break;
712 }
713 }
714 if (ins == O_CALLS or ins == O_CALLG) {
715 argval += 2;
716 }
717 if (addrstatus == BRANCH) {
718 addr = argval;
719 }
720 }
721 return addr;
722}
723
724/*
725 * Get the displacement of an instruction that uses displacement addressing.
726 */
727
728private int getdisp(addr, nbytes, reg, mode)
729Address addr;
730int nbytes;
731String reg;
732int mode;
733{
734 char byte;
735 short hword;
736 int argval;
737
738 switch (nbytes) {
739 case 1:
740 iread(&byte, addr, sizeof(byte));
741 argval = byte;
742 break;
743
744 case 2:
745 iread(&hword, addr, sizeof(hword));
746 argval = hword;
747 break;
748
749 case 4:
750 iread(&argval, addr, sizeof(argval));
751 break;
752 }
753 if (reg == regname[PROGCTR] && mode >= BYTEDISP) {
754 argval += addr + nbytes;
755 }
756 return argval;
757}
758
759#define BP_OP O_BPT /* breakpoint trap */
760#define BP_ERRNO SIGTRAP /* signal received at a breakpoint */
761
762/*
763 * Setting a breakpoint at a location consists of saving
764 * the word at the location and poking a BP_OP there.
765 *
766 * We save the locations and words on a list for use in unsetting.
767 */
768
769typedef struct Savelist *Savelist;
770
771struct Savelist {
772 Address location;
773 Byte save;
774 Byte refcount;
775 Savelist link;
776};
777
778private Savelist savelist;
779
780/*
781 * Set a breakpoint at the given address. Only save the word there
782 * if it's not already a breakpoint.
783 */
784
785public setbp(addr)
786Address addr;
787{
788 Byte w;
789 Byte save;
790 register Savelist newsave, s;
791
792 for (s = savelist; s != nil; s = s->link) {
793 if (s->location == addr) {
794 s->refcount++;
795 return;
796 }
797 }
798 iread(&save, addr, sizeof(addr));
799 newsave = new(Savelist);
800 newsave->location = addr;
801 newsave->save = save;
802 newsave->refcount = 1;
803 newsave->link = savelist;
804 savelist = newsave;
805 w = BP_OP;
806 iwrite(&w, addr, sizeof(w));
807}
808
809/*
810 * Unset a breakpoint; unfortunately we have to search the SAVELIST
811 * to find the saved value. The assumption is that the SAVELIST will
812 * usually be quite small.
813 */
814
815public unsetbp(addr)
816Address addr;
817{
818 register Savelist s, prev;
819
820 prev = nil;
821 for (s = savelist; s != nil; s = s->link) {
822 if (s->location == addr) {
823 iwrite(&s->save, addr, sizeof(s->save));
824 s->refcount--;
825 if (s->refcount == 0) {
826 if (prev == nil) {
827 savelist = s->link;
828 } else {
829 prev->link = s->link;
830 }
831 dispose(s);
832 }
833 return;
834 }
835 prev = s;
836 }
837 panic("unsetbp: couldn't find address %d", addr);
838}
839
840/*
841 * Predicate to test if the reason the process stopped was because
842 * of a breakpoint.
843 */
844
845public Boolean isbperr()
846{
847 return (Boolean) (not isfinished(process) and errnum(process) == SIGTRAP);
848}
849
850/*
851 * Enter a procedure by creating and executing a call instruction.
852 */
853
854#define CALLSIZE 7 /* size of call instruction */
855
856public beginproc(p, argc)
857Symbol p;
858Integer argc;
859{
860 char save[CALLSIZE];
861 struct {
862 VaxOpcode op;
863 unsigned char numargs;
864 unsigned char mode;
865 char addr[sizeof(long)]; /* unaligned long */
866 } call;
867 long dest;
868
869 pc = 2;
870 iread(save, pc, sizeof(save));
871 call.op = O_CALLS;
872 call.numargs = argc;
873 call.mode = 0xef;
874 dest = codeloc(p) - 2 - (pc + 7);
875 mov(&dest, call.addr, sizeof(call.addr));
876 iwrite(&call, pc, sizeof(call));
877 setreg(PROGCTR, pc);
878 pstep(process);
879 iwrite(save, pc, sizeof(save));
880 pc = reg(PROGCTR);
881 if (not isbperr()) {
882 printstatus();
883 }
884}