Commit | Line | Data |
---|---|---|
96c5cff5 | 1 | /* |
8a90f3aa KB |
2 | * Copyright (c) 1985 The Regents of the University of California. |
3 | * All rights reserved. | |
4 | * | |
6ecf3d85 | 5 | * %sccs.include.redist.c% |
96c5cff5 SL |
6 | */ |
7 | ||
8 | #ifndef lint | |
6ecf3d85 | 9 | static char sccsid[] = "@(#)tahoe.c 5.8 (Berkeley) %G%"; |
8a90f3aa | 10 | #endif /* not lint */ |
96c5cff5 SL |
11 | |
12 | /* | |
13 | * Target machine dependent stuff. | |
14 | */ | |
15 | ||
16 | #include "defs.h" | |
17 | #include "machine.h" | |
18 | #include "process.h" | |
19 | #include "runtime.h" | |
20 | #include "events.h" | |
21 | #include "main.h" | |
22 | #include "symbols.h" | |
23 | #include "source.h" | |
24 | #include "mappings.h" | |
25 | #include "object.h" | |
26 | #include "keywords.h" | |
27 | #include "ops.h" | |
d244f11c | 28 | #include "eval.h" |
96c5cff5 SL |
29 | #include <signal.h> |
30 | ||
31 | #ifndef public | |
32 | typedef unsigned int Address; | |
33 | typedef unsigned char Byte; | |
34 | typedef unsigned int Word; | |
35 | ||
36 | #define NREG 16 | |
37 | ||
38 | #define FRP 13 | |
39 | #define STKP 14 | |
40 | #define PROGCTR 15 | |
41 | ||
d244f11c DS |
42 | #define CODESTART 0 |
43 | #define FUNCOFFSET 2 | |
44 | ||
96c5cff5 SL |
45 | #define BITSPERBYTE 8 |
46 | #define BITSPERWORD (BITSPERBYTE * sizeof(Word)) | |
47 | ||
b4ee78f0 | 48 | /* |
d244f11c DS |
49 | * This magic macro enables us to look at the process' registers |
50 | * in its user structure. | |
b4ee78f0 | 51 | */ |
d244f11c DS |
52 | |
53 | #define regloc(reg) (ctob(UPAGES) + (sizeof(Word) * (reg))) | |
54 | ||
55 | #define nargspassed(frame) (((argn(-1, frame)&0xffff)-4)/4) | |
b4ee78f0 SL |
56 | |
57 | #define SYSBASE 0xc0000000 /* base of system address space */ | |
58 | #define physaddr(a) ((a) &~ 0xc0000000) | |
96c5cff5 SL |
59 | |
60 | #include "source.h" | |
61 | #include "symbols.h" | |
b4ee78f0 | 62 | #include <sys/param.h> |
b4ee78f0 SL |
63 | #include <machine/psl.h> |
64 | #include <sys/user.h> | |
d244f11c | 65 | #undef DELETE /* XXX */ |
b4ee78f0 SL |
66 | #include <sys/vm.h> |
67 | #include <machine/reg.h> | |
68 | #include <machine/pte.h> | |
96c5cff5 SL |
69 | |
70 | Address pc; | |
71 | Address prtaddr; | |
72 | ||
73 | #endif | |
74 | ||
b4ee78f0 SL |
75 | /* |
76 | * Indices into u. for use in collecting registers values. | |
77 | */ | |
78 | public int rloc[] = | |
79 | { R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, FP, SP, PC }; | |
80 | ||
96c5cff5 SL |
81 | private Address printop(); |
82 | ||
83 | Optab *ioptab[256]; /* index by opcode to optab */ | |
84 | /* | |
85 | * Initialize the opcode lookup table. | |
86 | */ | |
87 | public optab_init() | |
88 | { | |
89 | register Optab *p; | |
90 | ||
91 | for (p = optab; p->iname; p++) | |
92 | ioptab[p->val & 0xff] = p; | |
93 | } | |
94 | ||
95 | /* | |
96 | * Decode and print the instructions within the given address range. | |
97 | */ | |
98 | public printinst(lowaddr, highaddr) | |
99 | Address lowaddr, highaddr; | |
100 | { | |
101 | register Address addr; | |
102 | ||
103 | for (addr = lowaddr; addr <= highaddr; ) | |
104 | addr = printop(addr); | |
105 | prtaddr = addr; | |
106 | } | |
107 | ||
108 | /* | |
109 | * Another approach: print n instructions starting at the given address. | |
110 | */ | |
111 | public printninst(count, addr) | |
112 | int count; | |
113 | Address addr; | |
114 | { | |
115 | register Integer i; | |
116 | register Address newaddr; | |
117 | ||
118 | if (count <= 0) | |
119 | error("non-positive repetition count"); | |
120 | for (newaddr = addr, i = 0; i < count; i++) | |
121 | newaddr = printop(newaddr); | |
122 | prtaddr = newaddr; | |
123 | } | |
124 | ||
125 | /* | |
126 | * Hacked version of adb's instruction decoder. | |
127 | */ | |
128 | private Address printop(addr) | |
129 | Address addr; | |
130 | { | |
131 | register Optab *op; | |
132 | Opcode ins; | |
133 | unsigned char mode; | |
134 | int argtype, amode, argno, argval, r; | |
135 | String reg; | |
136 | Boolean indexf; | |
137 | short offset; | |
138 | ||
139 | argval = 0; | |
140 | indexf = false; | |
141 | printf("%08x ", addr); | |
142 | iread(&ins, addr, sizeof(ins)); | |
143 | addr += 1; | |
144 | op = ioptab[ins]; | |
145 | printf("%s", op->iname); | |
146 | for (argno = 0; argno < op->numargs; argno++) { | |
147 | if (indexf == true) | |
148 | indexf = false; | |
149 | else | |
150 | printf(argno == 0 ? "\t" : ","); | |
151 | argtype = op->argtype[argno]; | |
152 | if (is_branch_disp(argtype)) | |
153 | mode = 0xAF + (typelen(argtype) << 5); | |
154 | else | |
155 | iread(&mode, addr, sizeof(mode)), addr += 1; | |
156 | reg = regname[regnm(mode)]; | |
157 | amode = addrmode(mode); | |
158 | switch (amode) { | |
159 | ||
160 | case LITSHORT: case LITUPTO31: | |
161 | case LITUPTO47: case LITUPTO63: | |
162 | if (ins == O_KCALL && mode >= 0 && mode < SYSSIZE && | |
163 | systab[mode]) | |
164 | printf("$%s", systab[mode]); | |
165 | else | |
166 | printf("$%x", mode); | |
167 | argval = mode; | |
168 | break; | |
169 | ||
170 | case INDEX: | |
171 | printf("[%s]", reg); | |
172 | indexf = true; | |
173 | argno--; | |
174 | break; | |
175 | ||
176 | case REG: | |
177 | printf("%s", reg); | |
178 | break; | |
179 | ||
180 | case REGDEF: | |
181 | printf("(%s)", reg); | |
182 | break; | |
183 | ||
184 | case AUTODEC: | |
185 | printf("-(%s)", reg); | |
186 | break; | |
187 | ||
188 | case AUTOINC: | |
189 | r = mode & 0xf; | |
190 | if (r == 0xf || r == 8 || r == 9) { | |
191 | int size = (mode&03) + 1; | |
192 | ||
193 | /* immediate mode */ | |
194 | printf("$"); | |
195 | argval = printdisp(addr, size, | |
196 | regname[PROGCTR], amode); | |
197 | addr += size; | |
198 | } else | |
199 | printf("(%s)+", reg); | |
200 | break; | |
201 | ||
202 | case AUTOINCDEF: | |
203 | if ((mode&0xf) == 0xf) { | |
204 | printf("*$"); | |
205 | argval = printdisp(addr, 4, reg, amode); | |
206 | addr += 4; | |
207 | } else | |
208 | printf("*(%s)+", reg); | |
209 | break; | |
210 | ||
211 | case BYTEDISP: | |
212 | argval = printdisp(addr, 1, reg, amode); | |
213 | addr += 1; | |
214 | break; | |
215 | ||
216 | case BYTEDISPDEF: | |
217 | printf("*"); | |
218 | argval = printdisp(addr, 1, reg, amode); | |
219 | addr += 1; | |
220 | break; | |
221 | ||
222 | case WORDDISP: | |
223 | argval = printdisp(addr, 2, reg, amode); | |
224 | addr += 2; | |
225 | break; | |
226 | ||
227 | case WORDDISPDEF: | |
228 | printf("*"); | |
229 | argval = printdisp(addr, 2, reg, amode); | |
230 | addr += 2; | |
231 | break; | |
232 | ||
233 | case LONGDISP: | |
234 | argval = printdisp(addr, 4, reg, amode); | |
235 | addr += 4; | |
236 | break; | |
237 | ||
238 | case LONGDISPDEF: | |
239 | printf("*"); | |
240 | argval = printdisp(addr, 4, reg, amode); | |
241 | addr += 4; | |
242 | break; | |
243 | } | |
244 | } | |
245 | if (ins == O_CASEL) | |
246 | for (argno = 0; argno <= argval; argno++) { | |
247 | iread(&offset, addr, sizeof(offset)); | |
248 | printf("\n\t\t%d", offset); | |
249 | addr += 2; | |
250 | } | |
251 | printf("\n"); | |
252 | return (addr); | |
253 | } | |
254 | ||
255 | /* | |
256 | * Print the displacement of an instruction that uses displacement | |
257 | * addressing. | |
258 | */ | |
259 | private int printdisp(addr, nbytes, reg, mode) | |
260 | Address addr; | |
261 | int nbytes; | |
262 | char *reg; | |
263 | int mode; | |
264 | { | |
265 | char byte; | |
266 | short hword; | |
267 | int argval; | |
268 | Symbol f; | |
269 | ||
270 | switch (nbytes) { | |
271 | ||
272 | case 1: | |
273 | iread(&byte, addr, sizeof(byte)); | |
274 | argval = byte; | |
275 | break; | |
276 | ||
277 | case 2: | |
278 | iread(&hword, addr, sizeof(hword)); | |
279 | argval = hword; | |
280 | break; | |
281 | ||
282 | case 4: | |
283 | iread(&argval, addr, sizeof(argval)); | |
284 | break; | |
285 | } | |
286 | if (reg == regname[PROGCTR] && mode >= BYTEDISP) | |
287 | argval += addr + nbytes; | |
288 | if (reg == regname[PROGCTR]) { | |
289 | f = whatblock((Address) argval + 2); | |
290 | if (codeloc(f) == argval + 2) | |
291 | printf("%s", symname(f)); | |
292 | else | |
293 | printf("%x", argval); | |
294 | } else { | |
295 | if (varIsSet("$hexoffsets")) { | |
296 | if (argval < 0) | |
297 | printf("-%x(%s)", -(argval), reg); | |
298 | else | |
299 | printf("%x(%s)", argval, reg); | |
300 | } else | |
301 | printf("%d(%s)", argval, reg); | |
302 | } | |
303 | return (argval); | |
304 | } | |
305 | ||
306 | /* | |
307 | * Print the contents of the addresses within the given range | |
308 | * according to the given format. | |
309 | */ | |
310 | typedef struct { | |
311 | String name; | |
312 | String printfstring; | |
313 | int length; | |
314 | } Format; | |
315 | ||
316 | private Format fmt[] = { | |
317 | { "d", " %d", sizeof(short) }, | |
318 | { "D", " %ld", sizeof(long) }, | |
319 | { "o", " %o", sizeof(short) }, | |
320 | { "O", " %lo", sizeof(long) }, | |
321 | { "x", " %04x", sizeof(short) }, | |
322 | { "X", " %08x", sizeof(long) }, | |
323 | { "b", " \\%o", sizeof(char) }, | |
324 | { "c", " '%c'", sizeof(char) }, | |
325 | { "s", "%c", sizeof(char) }, | |
326 | { "f", " %f", sizeof(float) }, | |
327 | { "g", " %g", sizeof(double) }, | |
328 | { nil, nil, 0 } | |
329 | }; | |
330 | ||
331 | private Format *findformat(s) | |
332 | String s; | |
333 | { | |
334 | register Format *f; | |
335 | ||
336 | for (f = &fmt[0]; f->name != nil && !streq(f->name, s); f++) | |
337 | ; | |
338 | if (f->name == nil) | |
339 | error("bad print format \"%s\"", s); | |
340 | return (f); | |
341 | } | |
342 | ||
343 | public Address printdata(lowaddr, highaddr, format) | |
344 | Address lowaddr; | |
345 | Address highaddr; | |
346 | String format; | |
347 | { | |
348 | register int n; | |
349 | register Address addr; | |
350 | register Format *f; | |
351 | int value; | |
352 | ||
353 | if (lowaddr > highaddr) | |
354 | error("first address larger than second"); | |
355 | f = findformat(format); | |
356 | n = 0; | |
357 | value = 0; | |
358 | for (addr = lowaddr; addr <= highaddr; addr += f->length) { | |
359 | if (n == 0) | |
360 | printf("%08x: ", addr); | |
361 | dread(&value, addr, f->length); | |
362 | printf(f->printfstring, value); | |
363 | ++n; | |
364 | if (n >= (16 div f->length)) { | |
365 | putchar('\n'); | |
366 | n = 0; | |
367 | } | |
368 | } | |
369 | if (n != 0) | |
370 | putchar('\n'); | |
371 | prtaddr = addr; | |
372 | return (addr); | |
373 | } | |
374 | ||
375 | /* | |
376 | * The other approach is to print n items starting with a given address. | |
377 | */ | |
378 | ||
379 | public printndata(count, startaddr, format) | |
380 | int count; | |
381 | Address startaddr; | |
382 | String format; | |
383 | { | |
384 | register int i, n; | |
385 | register Address addr; | |
386 | register Format *f; | |
387 | register Boolean isstring; | |
388 | char c; | |
389 | union { | |
390 | char charv; | |
391 | short shortv; | |
392 | int intv; | |
393 | float floatv; | |
394 | double doublev; | |
395 | } value; | |
396 | ||
397 | if (count <= 0) | |
398 | error("non-positive repetition count"); | |
399 | f = findformat(format); | |
400 | isstring = (Boolean) streq(f->name, "s"); | |
401 | n = 0; | |
402 | addr = startaddr; | |
403 | value.intv = 0; | |
404 | for (i = 0; i < count; i++) { | |
405 | if (n == 0) | |
406 | printf("%08x: ", addr); | |
407 | if (isstring) { | |
408 | putchar('"'); | |
409 | dread(&c, addr, sizeof(char)); | |
410 | while (c != '\0') { | |
411 | printchar(c); | |
412 | ++addr; | |
413 | dread(&c, addr, sizeof(char)); | |
414 | } | |
415 | putchar('"'); | |
416 | putchar('\n'); | |
417 | n = 0; | |
418 | addr += sizeof(String); | |
419 | continue; | |
420 | } | |
421 | dread(&value, addr, f->length); | |
422 | printf(f->printfstring, value); | |
423 | ++n; | |
424 | if (n >= (16 div f->length)) { | |
425 | putchar('\n'); | |
426 | n = 0; | |
427 | } | |
428 | addr += f->length; | |
429 | } | |
430 | if (n != 0) | |
431 | putchar('\n'); | |
432 | prtaddr = addr; | |
433 | } | |
434 | ||
435 | /* | |
436 | * Print out a value according to the given format. | |
437 | */ | |
438 | public printvalue(v, format) | |
439 | long v; | |
440 | String format; | |
441 | { | |
442 | Format *f; | |
443 | char *p, *q; | |
444 | ||
445 | f = findformat(format); | |
446 | if (streq(f->name, "s")) { | |
447 | putchar('"'); | |
448 | for (p = (char *) &v, q = p + sizeof(v); p < q; ++p) | |
449 | printchar(*p); | |
450 | putchar('"'); | |
451 | } else | |
452 | printf(f->printfstring, v); | |
453 | putchar('\n'); | |
454 | } | |
455 | ||
456 | /* | |
457 | * Print out an execution time error. | |
458 | * Assumes the source position of the error has been calculated. | |
459 | * | |
460 | * Have to check if the -r option was specified; if so then | |
461 | * the object file information hasn't been read in yet. | |
462 | */ | |
463 | public printerror() | |
464 | { | |
465 | extern Integer sys_nsig; | |
466 | extern String sys_siglist[]; | |
467 | integer err; | |
468 | ||
469 | if (isfinished(process)) { | |
470 | err = exitcode(process); | |
471 | if (err) { | |
472 | printf("\"%s\" terminated abnormally (exit code %d)\n", | |
473 | objname, err); | |
474 | erecover(); | |
475 | } else | |
476 | printf("\"%s\" terminated normally\n", objname); | |
477 | } | |
478 | if (runfirst) { | |
479 | fprintf(stderr, "Entering debugger ...\n"); | |
480 | init(); | |
481 | } | |
482 | err = errnum(process); | |
483 | putchar('\n'); | |
484 | printsig(err); | |
485 | putchar(' '); | |
486 | printloc(); | |
487 | putchar('\n'); | |
488 | if (curline > 0) | |
489 | printlines(curline, curline); | |
490 | else | |
491 | printinst(pc, pc); | |
492 | erecover(); | |
493 | } | |
494 | ||
495 | /* | |
496 | * Print out a signal. | |
497 | */ | |
498 | private String illinames[] = { | |
499 | "reserved addressing fault", | |
d244f11c | 500 | "privileged instruction fault", |
96c5cff5 SL |
501 | "reserved operand fault" |
502 | }; | |
503 | #define NILLINAMES (sizeof (illinames) / sizeof (illinames[0])) | |
504 | ||
505 | private String fpenames[] = { | |
506 | nil, | |
507 | "integer overflow trap", | |
508 | "integer divide by zero trap", | |
509 | "floating point divide by zero trap", | |
510 | "floating point overflow trap", | |
511 | "floating point underflow trap", | |
512 | }; | |
513 | #define NFPENAMES (sizeof (fpenames) / sizeof (fpenames[0])) | |
514 | ||
515 | public printsig(signo) | |
516 | integer signo; | |
517 | { | |
518 | integer code; | |
519 | ||
520 | if (signo < 0 or signo > sys_nsig) | |
521 | printf("[signal %d]", signo); | |
522 | else | |
523 | printf("%s", sys_siglist[signo]); | |
524 | code = errcode(process); | |
525 | if (signo == SIGILL) | |
526 | if (code >= 0 && code < NILLINAMES) | |
527 | printf(" (%s)", illinames[code]); | |
528 | if (signo == SIGFPE) | |
529 | if (code > 0 and code < NFPENAMES) | |
530 | printf(" (%s)", fpenames[code]); | |
531 | } | |
532 | ||
533 | /* | |
534 | * Note the termination of the program. We do this so as to avoid | |
535 | * having the process exit, which would make the values of variables | |
536 | * inaccessible. We do want to flush all output buffers here, | |
537 | * otherwise it'll never get done. | |
538 | */ | |
539 | public endprogram() | |
540 | { | |
541 | Integer exitcode; | |
542 | ||
543 | stepto(nextaddr(pc, true)); | |
544 | printnews(); | |
545 | exitcode = argn(1, nil); | |
546 | if (exitcode != 0) | |
547 | printf("\nexecution completed (exit code %d)\n", exitcode); | |
548 | else | |
549 | printf("\nexecution completed\n"); | |
550 | getsrcpos(); | |
551 | erecover(); | |
552 | } | |
553 | ||
554 | private Address getcall(); | |
555 | /* | |
556 | * Single step the machine a source line (or instruction if "inst_tracing" | |
557 | * is true). If "isnext" is true, skip over procedure calls. | |
558 | */ | |
559 | public dostep(isnext) | |
560 | Boolean isnext; | |
561 | { | |
562 | register Address addr; | |
563 | register Lineno line; | |
564 | String filename; | |
565 | Address startaddr; | |
566 | ||
567 | startaddr = pc; | |
568 | addr = nextaddr(pc, isnext); | |
569 | if (!inst_tracing && nlhdr.nlines != 0) { | |
570 | line = linelookup(addr); | |
571 | for (; line == 0; line = linelookup(addr)) | |
572 | addr = nextaddr(addr, isnext); | |
573 | curline = line; | |
574 | } else | |
575 | curline = 0; | |
576 | stepto(addr); | |
577 | filename = srcfilename(addr); | |
578 | setsource(filename); | |
579 | } | |
580 | ||
581 | private Address findnextaddr(); | |
582 | /* | |
583 | * Compute the next address that will be executed from the given one. | |
584 | * If "isnext" is true then consider a procedure call as straight line code. | |
585 | * | |
586 | * We must unfortunately do much of the same work that is necessary | |
587 | * to print instructions. In addition we have to deal with branches. | |
588 | * Unconditional branches we just follow, for conditional branches | |
589 | * we continue execution to the current location and then single step | |
590 | * the machine. We assume that the last argument in an instruction | |
591 | * that branches is the branch address (or relative offset). | |
592 | */ | |
593 | public Address nextaddr(startaddr, isnext) | |
594 | Address startaddr; | |
595 | boolean isnext; | |
596 | { | |
597 | Address addr; | |
598 | ||
599 | addr = usignal(process); | |
600 | if (addr == 0 or addr == 1) | |
601 | addr = findnextaddr(startaddr, isnext); | |
602 | return (addr); | |
603 | } | |
604 | ||
605 | /* | |
606 | * Determine if it's ok to skip function f entered by instruction ins. | |
607 | * If so, we're going to compute the return address and step to it. | |
608 | */ | |
609 | private boolean skipfunc(ins, f) | |
610 | Opcode ins; | |
611 | Symbol f; | |
612 | { | |
613 | ||
614 | return ((boolean) (!inst_tracing && nlhdr.nlines != 0 && | |
615 | nosource(curfunc) && canskip(curfunc))); | |
616 | } | |
617 | ||
618 | private Address findnextaddr(startaddr, isnext) | |
619 | Address startaddr; | |
620 | Boolean isnext; | |
621 | { | |
622 | register Address addr; | |
623 | Optab *op; | |
624 | Opcode ins; | |
625 | unsigned char mode; | |
626 | int argtype, amode, argno, argval, nib; | |
627 | String r; | |
628 | Boolean indexf; | |
629 | enum { KNOWN, SEQUENTIAL, BRANCH } addrstatus; | |
630 | ||
631 | argval = 0; | |
632 | indexf = false; | |
633 | addr = startaddr; | |
634 | iread(&ins, addr, sizeof(ins)); | |
635 | switch (ins) { | |
636 | ||
637 | case O_CALLF: | |
638 | case O_CALLS: | |
639 | addrstatus = KNOWN; | |
640 | stepto(addr); | |
641 | pstep(process, DEFSIG); | |
642 | addr = reg(PROGCTR); | |
643 | pc = addr; | |
644 | setcurfunc(whatblock(pc)); | |
645 | if (not isbperr()) { | |
646 | printstatus(); | |
647 | /* NOTREACHED */ | |
648 | } | |
649 | bpact(); | |
650 | if (isnext or skipfunc(ins, curfunc)) { | |
651 | addrstatus = KNOWN; | |
652 | addr = return_addr(); | |
653 | stepto(addr); | |
654 | bpact(); | |
655 | } else | |
656 | callnews(/* iscall = */ true); | |
657 | break; | |
658 | ||
659 | case O_RET: | |
660 | addrstatus = KNOWN; | |
661 | stepto(addr); | |
662 | callnews(/* iscall = */ false); | |
663 | pstep(process, DEFSIG); | |
664 | addr = reg(PROGCTR); | |
665 | pc = addr; | |
666 | if (not isbperr()) | |
667 | printstatus(); | |
668 | bpact(); | |
669 | break; | |
670 | ||
671 | case O_BRB: | |
672 | case O_BRW: | |
673 | case O_JMP: | |
674 | case O_BBSSI: | |
675 | case O_BCC: | |
676 | case O_BCS: | |
677 | case O_BEQL: | |
678 | case O_BGEQ: | |
679 | case O_BGTR: | |
680 | case O_BGTRU: | |
681 | case O_BLEQ: | |
682 | case O_BLEQU: | |
683 | case O_BLSS: | |
684 | case O_BNEQ: | |
685 | case O_BVC: | |
686 | case O_BVS: | |
687 | case O_CASEL: | |
688 | case O_AOBLSS: | |
689 | case O_AOBLEQ: | |
690 | addrstatus = KNOWN; | |
691 | stepto(addr); | |
692 | pstep(process, DEFSIG); | |
693 | addr = reg(PROGCTR); | |
694 | pc = addr; | |
695 | if (not isbperr()) | |
696 | printstatus(); | |
697 | break; | |
698 | ||
699 | default: | |
700 | addrstatus = SEQUENTIAL; | |
701 | break; | |
702 | } | |
703 | if (addrstatus == KNOWN) | |
704 | return (addr); | |
705 | addr += 1; | |
706 | op = ioptab[ins]; | |
707 | for (argno = 0; argno < op->numargs; argno++) { | |
708 | if (indexf == true) | |
709 | indexf = false; | |
710 | argtype = op->argtype[argno]; | |
711 | if (is_branch_disp(argtype)) | |
712 | mode = 0xAF + (typelen(argtype) << 5); | |
713 | else | |
714 | iread(&mode, addr, sizeof(mode)), addr += 1; | |
715 | r = regname[regnm(mode)]; | |
716 | amode = addrmode(mode); | |
717 | switch (amode) { | |
718 | ||
719 | case LITSHORT: | |
720 | case LITUPTO31: | |
721 | case LITUPTO47: | |
722 | case LITUPTO63: | |
723 | argval = mode; | |
724 | break; | |
725 | ||
726 | case INDEX: | |
727 | indexf = true; | |
728 | --argno; | |
729 | break; | |
730 | ||
731 | case REG: | |
732 | case REGDEF: | |
733 | case AUTODEC: | |
734 | break; | |
735 | ||
736 | case AUTOINC: | |
737 | nib = mode & 0xf; | |
738 | if (nib == 0xf || nib == 8 || nib == 9) { | |
739 | int size = (mode&03)+1; | |
740 | ||
741 | argval = getdisp(addr, size, | |
742 | regname[PROGCTR], amode); | |
743 | addr += size; | |
744 | } | |
745 | break; | |
746 | ||
747 | case AUTOINCDEF: | |
748 | if ((mode&0xf) != 0xf) | |
749 | break; | |
750 | argval = getdisp(addr, 4, r, amode); | |
751 | addr += 4; | |
752 | break; | |
753 | ||
754 | case BYTEDISP: | |
755 | case BYTEDISPDEF: | |
756 | argval = getdisp(addr, 1, r, amode); | |
757 | addr += 1; | |
758 | break; | |
759 | ||
760 | case WORDDISP: | |
761 | case WORDDISPDEF: | |
762 | argval = getdisp(addr, 2, r, amode); | |
763 | addr += 2; | |
764 | break; | |
765 | ||
766 | case LONGDISP: | |
767 | case LONGDISPDEF: | |
768 | argval = getdisp(addr, 4, r, amode); | |
769 | addr += 4; | |
770 | break; | |
771 | } | |
772 | } | |
773 | if (ins == O_CALLF or ins == O_CALLS) | |
774 | argval += 2; | |
775 | if (addrstatus == BRANCH) | |
776 | addr = argval; | |
777 | return (addr); | |
778 | } | |
779 | ||
780 | /* | |
781 | * Get the displacement of an instruction that uses displacement addressing. | |
782 | */ | |
783 | private int getdisp(addr, nbytes, reg, mode) | |
784 | Address addr; | |
785 | int nbytes; | |
786 | String reg; | |
787 | int mode; | |
788 | { | |
789 | char byte; | |
790 | short hword; | |
791 | int argval; | |
792 | ||
793 | switch (nbytes) { | |
794 | ||
795 | case 1: | |
796 | iread(&byte, addr, sizeof(byte)); | |
797 | argval = byte; | |
798 | break; | |
799 | ||
800 | case 2: | |
801 | iread(&hword, addr, sizeof(hword)); | |
802 | argval = hword; | |
803 | break; | |
804 | ||
805 | case 4: | |
806 | iread(&argval, addr, sizeof(argval)); | |
807 | break; | |
808 | } | |
809 | if (reg == regname[PROGCTR] && mode >= BYTEDISP) | |
810 | argval += addr + nbytes; | |
811 | return (argval); | |
812 | } | |
813 | ||
814 | #define BP_OP O_BPT /* breakpoint trap */ | |
815 | #define BP_ERRNO SIGTRAP /* signal received at a breakpoint */ | |
816 | ||
817 | /* | |
818 | * Setting a breakpoint at a location consists of saving | |
819 | * the word at the location and poking a BP_OP there. | |
820 | * | |
821 | * We save the locations and words on a list for use in unsetting. | |
822 | */ | |
823 | typedef struct Savelist *Savelist; | |
824 | ||
825 | struct Savelist { | |
826 | Address location; | |
827 | Byte save; | |
828 | Byte refcount; | |
829 | Savelist link; | |
830 | }; | |
831 | ||
832 | private Savelist savelist; | |
833 | ||
834 | /* | |
835 | * Set a breakpoint at the given address. Only save the word there | |
836 | * if it's not already a breakpoint. | |
837 | */ | |
838 | public setbp(addr) | |
839 | Address addr; | |
840 | { | |
841 | Byte w, save; | |
842 | register Savelist newsave, s; | |
843 | ||
844 | for (s = savelist; s != nil; s = s->link) | |
845 | if (s->location == addr) { | |
846 | s->refcount++; | |
847 | return; | |
848 | } | |
849 | iread(&save, addr, sizeof(save)); | |
850 | newsave = new(Savelist); | |
851 | newsave->location = addr; | |
852 | newsave->save = save; | |
853 | newsave->refcount = 1; | |
854 | newsave->link = savelist; | |
855 | savelist = newsave; | |
856 | w = BP_OP; | |
857 | iwrite(&w, addr, sizeof(w)); | |
858 | } | |
859 | ||
860 | /* | |
861 | * Unset a breakpoint; unfortunately we have to search the SAVELIST | |
862 | * to find the saved value. The assumption is that the SAVELIST will | |
863 | * usually be quite small. | |
864 | */ | |
865 | public unsetbp(addr) | |
866 | Address addr; | |
867 | { | |
868 | register Savelist s, prev; | |
869 | ||
870 | prev = nil; | |
871 | for (s = savelist; s != nil; s = s->link) { | |
872 | if (s->location == addr) { | |
873 | iwrite(&s->save, addr, sizeof(s->save)); | |
874 | s->refcount--; | |
875 | if (s->refcount == 0) { | |
876 | if (prev == nil) | |
877 | savelist = s->link; | |
878 | else | |
879 | prev->link = s->link; | |
880 | dispose(s); | |
881 | } | |
882 | return; | |
883 | } | |
884 | prev = s; | |
885 | } | |
886 | panic("unsetbp: couldn't find address %d", addr); | |
887 | } | |
888 | ||
889 | /* | |
890 | * Enter a procedure by creating and executing a call instruction. | |
891 | */ | |
892 | ||
893 | #define CALLSIZE 7 /* size of call instruction */ | |
894 | ||
895 | public beginproc(p, argc) | |
896 | Symbol p; | |
897 | Integer argc; | |
898 | { | |
899 | char save[CALLSIZE]; | |
900 | struct { | |
901 | Opcode op; | |
902 | unsigned char numargs; | |
903 | unsigned char mode; | |
904 | char addr[sizeof(long)]; /* unaligned long */ | |
905 | } call; | |
906 | long dest; | |
907 | ||
96c5cff5 SL |
908 | if (4*argc+4 > 256) |
909 | error("too many parameters (max %d)", 256/4 - 1); | |
910 | pc = 2; | |
911 | iread(save, pc, sizeof(save)); | |
912 | call.op = O_CALLF; | |
913 | call.numargs = 4*argc+4; | |
914 | call.mode = 0xef; /* longword relative */ | |
915 | dest = codeloc(p) - 2 - (pc + CALLSIZE); | |
916 | mov(&dest, call.addr, sizeof(call.addr)); | |
917 | iwrite(&call, pc, sizeof(call)); | |
918 | setreg(PROGCTR, pc); | |
919 | pstep(process, DEFSIG); | |
920 | iwrite(save, pc, sizeof(save)); | |
921 | pc = reg(PROGCTR); | |
922 | if (not isbperr()) | |
923 | printstatus(); | |
924 | } | |
b4ee78f0 SL |
925 | |
926 | /* | |
927 | * Special variables for debugging the kernel. | |
928 | */ | |
929 | ||
930 | public integer masterpcbb; | |
931 | public integer slr; | |
932 | public struct pte *sbr; | |
d244f11c | 933 | private struct pcb pcb; |
b4ee78f0 SL |
934 | |
935 | public getpcb () | |
936 | { | |
937 | fseek(corefile, masterpcbb & ~0xc0000000, 0); | |
938 | get(corefile, pcb); | |
939 | printf("p0br %lx p0lr %lx p2br %lx p2lr %lx\n", | |
940 | pcb.pcb_p0br, pcb.pcb_p0lr, pcb.pcb_p2br, pcb.pcb_p2lr | |
941 | ); | |
942 | setreg(0, pcb.pcb_r0); | |
943 | setreg(1, pcb.pcb_r1); | |
944 | setreg(2, pcb.pcb_r2); | |
945 | setreg(3, pcb.pcb_r3); | |
946 | setreg(4, pcb.pcb_r4); | |
947 | setreg(5, pcb.pcb_r5); | |
948 | setreg(6, pcb.pcb_r6); | |
949 | setreg(7, pcb.pcb_r7); | |
950 | setreg(8, pcb.pcb_r8); | |
951 | setreg(9, pcb.pcb_r9); | |
952 | setreg(10, pcb.pcb_r10); | |
953 | setreg(11, pcb.pcb_r11); | |
954 | setreg(12, pcb.pcb_r12); | |
955 | setreg(FRP, pcb.pcb_fp); | |
956 | setreg(STKP, pcb.pcb_ksp); | |
957 | setreg(PROGCTR, pcb.pcb_pc); | |
958 | } | |
959 | ||
960 | public copyregs (savreg, reg) | |
961 | Word savreg[], reg[]; | |
962 | { | |
963 | reg[0] = savreg[R0]; | |
964 | reg[1] = savreg[R1]; | |
965 | reg[2] = savreg[R2]; | |
966 | reg[3] = savreg[R3]; | |
967 | reg[4] = savreg[R4]; | |
968 | reg[5] = savreg[R5]; | |
969 | reg[6] = savreg[R6]; | |
970 | reg[7] = savreg[R7]; | |
971 | reg[8] = savreg[R8]; | |
972 | reg[9] = savreg[R9]; | |
973 | reg[10] = savreg[R10]; | |
974 | reg[11] = savreg[R11]; | |
975 | reg[12] = savreg[R12]; | |
976 | reg[FRP] = savreg[FP]; | |
977 | reg[STKP] = savreg[SP]; | |
978 | reg[PROGCTR] = savreg[PC]; | |
979 | } | |
980 | ||
981 | /* | |
982 | * Map a virtual address to a physical address. | |
983 | */ | |
984 | ||
985 | public Address vmap (addr) | |
986 | Address addr; | |
987 | { | |
988 | int oldaddr = addr, v; | |
989 | struct pte pte; | |
990 | ||
991 | addr &= ~0xc0000000; | |
992 | v = btop(addr); | |
993 | switch (oldaddr&0xc0000000) { | |
994 | ||
995 | case 0xc0000000: | |
996 | /* | |
997 | * In system space get system pte. If | |
998 | * valid or reclaimable then physical address | |
999 | * is combination of its page number and the page | |
1000 | * offset of the original address. | |
1001 | */ | |
1002 | if (v >= slr) | |
1003 | goto oor; | |
1004 | addr = ((long)(sbr+v)) &~ 0xc0000000; | |
1005 | goto simple; | |
1006 | ||
1007 | case 0x80000000: | |
1008 | /* | |
1009 | * In p2 spce must not be in shadow region. | |
1010 | */ | |
1011 | if (v < pcb.pcb_p2lr) | |
1012 | goto oor; | |
1013 | addr = (long)(pcb.pcb_p2br+v); | |
1014 | break; | |
1015 | ||
1016 | case 0x40000000: | |
1017 | /* | |
1018 | * In p1 space everything is verboten (for now). | |
1019 | */ | |
1020 | goto oor; | |
1021 | ||
1022 | case 0x00000000: | |
1023 | /* | |
1024 | * In p0 space must not be off end of region. | |
1025 | */ | |
1026 | if (v >= pcb.pcb_p0lr) | |
1027 | goto oor; | |
1028 | addr = (long)(pcb.pcb_p0br+v); | |
1029 | break; | |
1030 | oor: | |
1031 | error("address out of segment"); | |
1032 | } | |
1033 | /* | |
1034 | * For p0/p1/p2 address, user-level page table should | |
1035 | * be in kernel vm. Do second-level indirect by recursing. | |
1036 | */ | |
1037 | if ((addr & 0xc0000000) != 0xc0000000) | |
1038 | error("bad p0br, p1br, or p2br in pcb"); | |
1039 | addr = vmap(addr); | |
1040 | simple: | |
1041 | /* | |
1042 | * Addr is now address of the pte of the page we | |
1043 | * are interested in; get the pte and paste up the | |
1044 | * physical address. | |
1045 | */ | |
1046 | fseek(corefile, addr, 0); | |
1047 | if (fread(&pte, sizeof (pte), 1, corefile) != 1) | |
1048 | error("page table botch"); | |
1049 | /* SHOULD CHECK NOT I/O ADDRESS; NEED CPU TYPE! */ | |
1050 | if (pte.pg_v == 0 && (pte.pg_fod || pte.pg_pfnum == 0)) | |
1051 | error("page not valid/reclaimable"); | |
1052 | return ((long)(ptob(pte.pg_pfnum) + (oldaddr & PGOFSET))); | |
1053 | } | |
d244f11c DS |
1054 | |
1055 | /* | |
1056 | * Extract a bit field from an integer. | |
1057 | */ | |
1058 | ||
1059 | public integer extractField (s) | |
1060 | Symbol s; | |
1061 | { | |
1062 | integer nbytes, nbits, n, r, off, len; | |
1063 | ||
1064 | off = s->symvalue.field.offset; | |
1065 | len = s->symvalue.field.length; | |
1066 | nbytes = size(s); | |
1067 | n = 0; | |
1068 | if (nbytes > sizeof(n)) { | |
1069 | printf("[bad size in extractField -- word assumed]\n"); | |
1070 | nbytes = sizeof(n); | |
1071 | } | |
1072 | popn(nbytes, ((char *) &n) + (sizeof(Word) - nbytes)); | |
1073 | nbits = nbytes * BITSPERBYTE; | |
1074 | r = n >> (nbits - ((off mod nbits) + len)); | |
1075 | r &= ((1 << len) - 1); | |
1076 | return r; | |
1077 | } | |
1078 | ||
1079 | /* | |
1080 | * Change the length of a value in memory according to a given difference | |
1081 | * in the lengths of its new and old types. | |
1082 | */ | |
1083 | ||
1084 | public loophole (oldlen, newlen) | |
1085 | integer oldlen, newlen; | |
1086 | { | |
1087 | integer i, n; | |
1088 | Stack *oldsp; | |
1089 | ||
1090 | n = newlen - oldlen; | |
1091 | oldsp = sp - oldlen; | |
1092 | if (n > 0) { | |
1093 | for (i = oldlen - 1; i >= 0; i--) { | |
1094 | oldsp[n + i] = oldsp[i]; | |
1095 | } | |
1096 | for (i = 0; i < n; i++) { | |
1097 | oldsp[i] = '\0'; | |
1098 | } | |
1099 | } else { | |
1100 | for (i = 0; i < newlen; i++) { | |
1101 | oldsp[i] = oldsp[i - n]; | |
1102 | } | |
1103 | } | |
1104 | sp += n; | |
1105 | } |