xref: /original-bsd/old/dbx/vax.c (revision f0fd5f8a)
1 /* Copyright (c) 1982 Regents of the University of California */
2 
3 static char sccsid[] = "@(#)vax.c 1.4 12/18/82";
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 "ops.h"
19 #include <signal.h>
20 
21 #ifndef public
22 typedef unsigned int Address;
23 typedef unsigned char Byte;
24 typedef 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 
41 Address pc;
42 Address prtaddr;
43 
44 #endif
45 
46 private Address printop();
47 
48 /*
49  * Decode and print the instructions within the given address range.
50  */
51 
52 public printinst(lowaddr, highaddr)
53 Address lowaddr;
54 Address 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 
68 public printninst(count, addr)
69 int count;
70 Address 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 
90 private Address printop(addr)
91 Address 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 
254 private int printdisp(addr, nbytes, reg, mode)
255 Address addr;
256 int nbytes;
257 char *reg;
258 int 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 
295 typedef struct {
296     String name;
297     String printfstring;
298     int length;
299 } Format;
300 
301 private 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 
316 public Address printdata(lowaddr, highaddr, format)
317 Address lowaddr;
318 Address highaddr;
319 String 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 
361 public printndata(count, startaddr, format)
362 int count;
363 Address startaddr;
364 String 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  * Assumes the source position of the error has been calculated.
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 
427 public printerror()
428 {
429     extern Integer sys_nsig;
430     extern String sys_siglist[];
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     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 
466 private 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 
488 public 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"
502  * is true.  If "isnext" is true, skip over procedure calls.
503  */
504 
505 private Address getcall();
506 
507 public dostep(isnext)
508 Boolean isnext;
509 {
510     register Address addr;
511     register Lineno line;
512     String filename;
513 
514     addr = nextaddr(pc, isnext);
515     if (not inst_tracing) {
516 	line = linelookup(addr);
517 	while (line == 0) {
518 	    addr = nextaddr(addr, isnext);
519 	    line = linelookup(addr);
520 	}
521     }
522     stepto(addr);
523     curline = line;
524     filename = srcfilename(addr);
525     setsource(filename);
526 }
527 
528 /*
529  * Compute the next address that will be executed from the given one.
530  * If "isnext" is true then consider a procedure call as straight line code.
531  *
532  * We must unfortunately do much of the same work that is necessary
533  * to print instructions.  In addition we have to deal with branches.
534  * Unconditional branches we just follow, for conditional branches
535  * we continue execution to the current location and then single step
536  * the machine.  We assume that the last argument in an instruction
537  * that branches is the branch address (or relative offset).
538  */
539 
540 public Address nextaddr(startaddr, isnext)
541 Address startaddr;
542 Boolean isnext;
543 {
544     register Address addr;
545     Optab op;
546     VaxOpcode ins;
547     unsigned char mode;
548     int argtype, amode, argno, argval;
549     String r;
550     Boolean indexf;
551     enum { KNOWN, SEQUENTIAL, BRANCH } addrstatus;
552 
553     argval = 0;
554     indexf = false;
555     addr = startaddr;
556     iread(&ins, addr, sizeof(ins));
557     switch (ins) {
558 	case O_BRB:
559 	case O_BRW:
560 	case O_JMP:
561 	    addrstatus = BRANCH;
562 	    break;
563 
564 	case O_BSBB:
565 	case O_BSBW:
566 	case O_JSB:
567 	case O_CALLG:
568 	case O_CALLS:
569 	    if (isnext) {
570 		addrstatus = SEQUENTIAL;
571 	    } else {
572 		addrstatus = KNOWN;
573 		stepto(addr);
574 		pstep(process);
575 		addr = reg(PROGCTR);
576 		pc = addr;
577 		callnews(/* iscall = */ true);
578 		if (not isbperr()) {
579 		    printstatus();
580 		} else {
581 		    bpact();
582 		}
583 	    }
584 	    break;
585 
586 	case O_RSB:
587 	case O_RET:
588 	    addrstatus = KNOWN;
589 	    callnews(/* iscall = */ false);
590 	    addr = return_addr();
591 	    stepto(addr);
592 	    break;
593 
594 	case O_BNEQ: case O_BEQL: case O_BGTR:
595 	case O_BLEQ: case O_BGEQ: case O_BLSS:
596 	case O_BGTRU: case O_BLEQU: case O_BVC:
597 	case O_BVS: case O_BCC: case O_BCS:
598 	case O_CASEB: case O_CASEW: case O_CASEL:
599 	case O_BBS: case O_BBC: case O_BBSS: case O_BBCS:
600 	case O_BBSC: case O_BBCC: case O_BBSSI:
601 	case O_BBCCI: case O_BLBS: case O_BLBC:
602 	case O_ACBL: case O_AOBLSS: case O_AOBLEQ:
603 	case O_SOBGEQ: case O_SOBGTR:
604 	    addrstatus = KNOWN;
605 	    stepto(addr);
606 	    pstep(process);
607 	    addr = reg(PROGCTR);
608 	    pc = addr;
609 	    if (not isbperr()) {
610 		printstatus();
611 	    }
612 	    break;
613 
614 	default:
615 	    addrstatus = SEQUENTIAL;
616 	    break;
617     }
618     if (addrstatus != KNOWN) {
619 	addr += 1;
620 	op = optab[ins];
621 	for (argno = 0; argno < op.numargs; argno++) {
622 	    if (indexf == true) {
623 		indexf = false;
624 	    }
625 	    argtype = op.argtype[argno];
626 	    if (is_branch_disp(argtype)) {
627 		mode = 0xAF + (typelen(argtype) << 5);
628 	    } else {
629 		iread(&mode, addr, sizeof(mode));
630 		addr += 1;
631 	    }
632 	    r = regname[regnm(mode)];
633 	    amode = addrmode(mode);
634 	    switch (amode) {
635 		case LITSHORT:
636 		case LITUPTO31:
637 		case LITUPTO47:
638 		case LITUPTO63:
639 		    argval = mode;
640 		    break;
641 
642 		case INDEX:
643 		    indexf = true;
644 		    --argno;
645 		    break;
646 
647 		case REG:
648 		case REGDEF:
649 		case AUTODEC:
650 		    break;
651 
652 		case AUTOINC:
653 		    if (r == regname[PROGCTR]) {
654 			switch (typelen(argtype)) {
655 			    case TYPB:
656 				argval = getdisp(addr, 1, r, amode);
657 				addr += 1;
658 				break;
659 
660 			    case TYPW:
661 				argval = getdisp(addr, 2, r, amode);
662 				addr += 2;
663 				break;
664 
665 			    case TYPL:
666 				argval = getdisp(addr, 4, r, amode);
667 				addr += 4;
668 				break;
669 
670 			    case TYPF:
671 				iread(&argval, addr, sizeof(argval));
672 				addr += 4;
673 				break;
674 
675 			    case TYPQ:
676 			    case TYPD:
677 				iread(&argval, addr+4, sizeof(argval));
678 				addr += 8;
679 				break;
680 			}
681 		    }
682 		    break;
683 
684 		case AUTOINCDEF:
685 		    if (r == regname[PROGCTR]) {
686 			argval = getdisp(addr, 4, r, amode);
687 			addr += 4;
688 		    }
689 		    break;
690 
691 		case BYTEDISP:
692 		case BYTEDISPDEF:
693 		    argval = getdisp(addr, 1, r, amode);
694 		    addr += 1;
695 		    break;
696 
697 		case WORDDISP:
698 		case WORDDISPDEF:
699 		    argval = getdisp(addr, 2, r, amode);
700 		    addr += 2;
701 		    break;
702 
703 		case LONGDISP:
704 		case LONGDISPDEF:
705 		    argval = getdisp(addr, 4, r, amode);
706 		    addr += 4;
707 		    break;
708 	    }
709 	}
710 	if (ins == O_CALLS or ins == O_CALLG) {
711 	    argval += 2;
712 	}
713 	if (addrstatus == BRANCH) {
714 	    addr = argval;
715 	}
716     }
717     return addr;
718 }
719 
720 /*
721  * Get the displacement of an instruction that uses displacement addressing.
722  */
723 
724 private int getdisp(addr, nbytes, reg, mode)
725 Address addr;
726 int nbytes;
727 String reg;
728 int mode;
729 {
730     char byte;
731     short hword;
732     int argval;
733 
734     switch (nbytes) {
735 	case 1:
736 	    iread(&byte, addr, sizeof(byte));
737 	    argval = byte;
738 	    break;
739 
740 	case 2:
741 	    iread(&hword, addr, sizeof(hword));
742 	    argval = hword;
743 	    break;
744 
745 	case 4:
746 	    iread(&argval, addr, sizeof(argval));
747 	    break;
748     }
749     if (reg == regname[PROGCTR] && mode >= BYTEDISP) {
750 	argval += addr + nbytes;
751     }
752     return argval;
753 }
754 
755 #define BP_OP       O_BPT       /* breakpoint trap */
756 #define BP_ERRNO    SIGTRAP     /* signal received at a breakpoint */
757 
758 /*
759  * Setting a breakpoint at a location consists of saving
760  * the word at the location and poking a BP_OP there.
761  *
762  * We save the locations and words on a list for use in unsetting.
763  */
764 
765 typedef struct Savelist *Savelist;
766 
767 struct Savelist {
768     Address location;
769     Byte save;
770     Byte refcount;
771     Savelist link;
772 };
773 
774 private Savelist savelist;
775 
776 /*
777  * Set a breakpoint at the given address.  Only save the word there
778  * if it's not already a breakpoint.
779  */
780 
781 public setbp(addr)
782 Address addr;
783 {
784     Byte w;
785     Byte save;
786     register Savelist newsave, s;
787 
788     for (s = savelist; s != nil; s = s->link) {
789 	if (s->location == addr) {
790 	    s->refcount++;
791 	    return;
792 	}
793     }
794     iread(&save, addr, sizeof(addr));
795     newsave = new(Savelist);
796     newsave->location = addr;
797     newsave->save = save;
798     newsave->refcount = 1;
799     newsave->link = savelist;
800     savelist = newsave;
801     w = BP_OP;
802     iwrite(&w, addr, sizeof(w));
803 }
804 
805 /*
806  * Unset a breakpoint; unfortunately we have to search the SAVELIST
807  * to find the saved value.  The assumption is that the SAVELIST will
808  * usually be quite small.
809  */
810 
811 public unsetbp(addr)
812 Address addr;
813 {
814     register Savelist s, prev;
815 
816     prev = nil;
817     for (s = savelist; s != nil; s = s->link) {
818 	if (s->location == addr) {
819 	    iwrite(&s->save, addr, sizeof(s->save));
820 	    s->refcount--;
821 	    if (s->refcount == 0) {
822 		if (prev == nil) {
823 		    savelist = s->link;
824 		} else {
825 		    prev->link = s->link;
826 		}
827 		dispose(s);
828 	    }
829 	    return;
830 	}
831 	prev = s;
832     }
833     panic("unsetbp: couldn't find address %d", addr);
834 }
835 
836 /*
837  * Predicate to test if the reason the process stopped was because
838  * of a breakpoint.
839  */
840 
841 public Boolean isbperr()
842 {
843     return (Boolean) (not isfinished(process) and errnum(process) == SIGTRAP);
844 }
845 
846 /*
847  * Enter a procedure by creating and executing a call instruction.
848  */
849 
850 #define CALLSIZE 7	/* size of call instruction */
851 
852 public beginproc(p, argc)
853 Symbol p;
854 Integer argc;
855 {
856     char save[CALLSIZE];
857     struct {
858 	VaxOpcode op;
859 	unsigned char numargs;
860 	unsigned char mode;
861 	char addr[sizeof(long)];	/* unaligned long */
862     } call;
863     long dest;
864 
865     pc = 2;
866     iread(save, pc, sizeof(save));
867     call.op = O_CALLS;
868     call.numargs = argc;
869     call.mode = 0xef;
870     dest = codeloc(p) - 2 - (pc + 7);
871     mov(&dest, call.addr, sizeof(call.addr));
872     iwrite(&call, pc, sizeof(call));
873     setreg(PROGCTR, pc);
874     pstep(process);
875     iwrite(save, pc, sizeof(save));
876     pc = reg(PROGCTR);
877     if (not isbperr()) {
878 	printstatus();
879     }
880 }
881