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