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