xref: /csrg-svn/old/dbx/vax.c (revision 9687)
1 /* Copyright (c) 1982 Regents of the University of California */
2 
3 static char sccsid[] = "@(#)vax.c 1.2 12/15/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 "vaxops.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  *
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 
426 public 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 
470 private 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 
492 public 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 
509 private Address getcall();
510 
511 public dostep(isnext)
512 Boolean 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 
544 public Address nextaddr(startaddr, isnext)
545 Address startaddr;
546 Boolean 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 
728 private int getdisp(addr, nbytes, reg, mode)
729 Address addr;
730 int nbytes;
731 String reg;
732 int 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 
769 typedef struct Savelist *Savelist;
770 
771 struct Savelist {
772     Address location;
773     Byte save;
774     Byte refcount;
775     Savelist link;
776 };
777 
778 private 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 
785 public setbp(addr)
786 Address 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 
815 public unsetbp(addr)
816 Address 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 
845 public 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 
856 public beginproc(p, argc)
857 Symbol p;
858 Integer 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 }
885