xref: /csrg-svn/old/dbx/vax.c (revision 11874)
1 /* Copyright (c) 1982 Regents of the University of California */
2 
3 static char sccsid[] = "@(#)vax.c 1.8 04/08/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 private Format *findformat(s)
317 String 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 
331 public Address printdata(lowaddr, highaddr, format)
332 Address lowaddr;
333 Address highaddr;
334 String 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     }
344     f = findformat(format);
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 
370 public printndata(count, startaddr, format)
371 int count;
372 Address startaddr;
373 String 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     }
384     f = findformat(format);
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 
422 /*
423  * Print out a value according to the given format.
424  */
425 
426 public printvalue(v, format)
427 long v;
428 String 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 
449 /*
450  * Print out an execution time error.
451  * Assumes the source position of the error has been calculated.
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 
457 public printerror()
458 {
459     extern Integer sys_nsig;
460     extern String sys_siglist[];
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     }
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 
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 
503 public 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"
517  * is true).  If "isnext" is true, skip over procedure calls.
518  */
519 
520 private Address getcall();
521 
522 public dostep(isnext)
523 Boolean isnext;
524 {
525     register Address addr;
526     register Lineno line;
527     String filename;
528 
529     addr = nextaddr(pc, isnext);
530     if (not inst_tracing and nlhdr.nlines != 0) {
531 	line = linelookup(addr);
532 	while (line == 0) {
533 	    addr = nextaddr(addr, isnext);
534 	    line = linelookup(addr);
535 	}
536 	curline = line;
537     } else {
538 	curline = 0;
539     }
540     stepto(addr);
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 
557 public Address nextaddr(startaddr, isnext)
558 Address startaddr;
559 Boolean 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;
594 		curfunc = whatblock(pc);
595 		if (not isbperr()) {
596 		    printstatus();
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);
605 		    bpact();
606 		} else {
607 		    callnews(/* iscall = */ true);
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);
618 	    bpact();
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 
751 private int getdisp(addr, nbytes, reg, mode)
752 Address addr;
753 int nbytes;
754 String reg;
755 int 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 
792 typedef struct Savelist *Savelist;
793 
794 struct Savelist {
795     Address location;
796     Byte save;
797     Byte refcount;
798     Savelist link;
799 };
800 
801 private 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 
808 public setbp(addr)
809 Address 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     }
821     iread(&save, addr, sizeof(save));
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 
838 public unsetbp(addr)
839 Address 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 
868 public 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 
879 public beginproc(p, argc)
880 Symbol p;
881 Integer 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 }
908