xref: /csrg-svn/old/dbx/vax.c (revision 10621)
1 /* Copyright (c) 1982 Regents of the University of California */
2 
3 static char sccsid[] = "@(#)vax.c 1.5 01/25/83";
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 and nlhdr.nlines != 0) {
516 	line = linelookup(addr);
517 	while (line == 0) {
518 	    addr = nextaddr(addr, isnext);
519 	    line = linelookup(addr);
520 	}
521 	curline = line;
522     } else {
523 	curline = 0;
524     }
525     stepto(addr);
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 
542 public Address nextaddr(startaddr, isnext)
543 Address startaddr;
544 Boolean 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 
726 private int getdisp(addr, nbytes, reg, mode)
727 Address addr;
728 int nbytes;
729 String reg;
730 int 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 
767 typedef struct Savelist *Savelist;
768 
769 struct Savelist {
770     Address location;
771     Byte save;
772     Byte refcount;
773     Savelist link;
774 };
775 
776 private 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 
783 public setbp(addr)
784 Address 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 
813 public unsetbp(addr)
814 Address 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 
843 public 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 
854 public beginproc(p, argc)
855 Symbol p;
856 Integer 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 }
883