Commit | Line | Data |
---|---|---|
6f7a3ac3 KB |
1 | /*- |
2 | * Copyright (c) 1991 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
ad787160 C |
5 | * This module is believed to contain source code proprietary to AT&T. |
6 | * Use and redistribution is subject to the Berkeley Software License | |
7 | * Agreement and your Software Agreement with AT&T (Western Electric). | |
6f7a3ac3 KB |
8 | */ |
9 | ||
f582ecdc | 10 | #ifndef lint |
ad787160 | 11 | static char sccsid[] = "@(#)machdep.c 5.5 (Berkeley) 4/4/91"; |
6f7a3ac3 | 12 | #endif /* not lint */ |
f582ecdc KB |
13 | |
14 | /* | |
15 | * adb - miscellaneous machine dependent routines. | |
16 | */ | |
17 | ||
18 | #define RLOCALS /* enable alternate $C stack trace */ | |
19 | ||
20 | #include "defs.h" | |
21 | #include "bkpt.h" | |
22 | #include <machine/pte.h> | |
23 | #include <machine/frame.h> | |
24 | #include <machine/reg.h> | |
25 | #include <machine/vmparam.h> | |
26 | #include <sys/ptrace.h> | |
27 | #include <sys/vmmac.h> | |
28 | #include <stab.h> | |
29 | ||
30 | struct pte *sbr; | |
31 | int slr; | |
32 | struct pcb pcb; | |
33 | int masterpcbb; | |
34 | ||
35 | /* | |
36 | * Activation records. | |
37 | */ | |
38 | ||
39 | /* | |
40 | * Set up a stack frame based on the registers in the core image | |
41 | * (or in the kernel core file ... not yet!). | |
42 | */ | |
43 | a_init(ap) | |
44 | register struct activation *ap; | |
45 | { | |
46 | ||
47 | ap->a_valid = 1; | |
48 | if (kcore) { | |
49 | ap->a_fp = pcb.pcb_fp; | |
50 | ap->a_pc = pcb.pcb_pc; | |
51 | } else { | |
52 | ap->a_fp = u.u_ar0[FP]; | |
53 | ap->a_pc = u.u_ar0[PC]; | |
54 | } | |
55 | } | |
56 | ||
57 | /* | |
58 | * Back up one stack frame in the call stack. | |
59 | * ap points to the activation record from the previous frame. | |
60 | * Clear a_valid field if we ran out of frames. | |
61 | */ | |
62 | a_back(ap) | |
63 | register struct activation *ap; | |
64 | { | |
65 | struct frame fr; | |
66 | ||
67 | if (adbread(SP_DATA, ap->a_fp - FRAMEOFF, &fr, sizeof fr) != sizeof fr) | |
68 | ap->a_valid = 0; | |
69 | else { | |
70 | ap->a_fp = fr.fr_savfp; | |
71 | ap->a_pc = fr.fr_savpc; | |
72 | if (ap->a_fp == 0) | |
73 | ap->a_valid = 0; | |
74 | } | |
75 | } | |
76 | ||
77 | /* | |
78 | * Evaluate a local symbol (N_LSYM or N_PSYM) using the activation | |
79 | * record pointed to by ap. | |
80 | */ | |
81 | addr_t | |
82 | eval_localsym(sp, ap) | |
83 | register struct nlist *sp; | |
84 | struct activation *ap; | |
85 | { | |
86 | ||
87 | switch (sp->n_type) { | |
88 | ||
89 | case N_LSYM: | |
90 | return (ap->a_fp - sp->n_value); | |
91 | ||
92 | case N_PSYM: | |
93 | return (ap->a_fp + sp->n_value); | |
94 | } | |
95 | panic("eval_localsym"); | |
96 | /* NOTREACHED */ | |
97 | } | |
98 | ||
99 | ||
100 | /* true iff address a is in instruction space */ | |
101 | #define ispace(a) ((a) < txtmap.m1.e) | |
102 | ||
103 | /* | |
104 | * Delete a (single) breakpoint. Return 0 on success. | |
105 | */ | |
106 | int | |
107 | clr_bpt(b) | |
108 | struct bkpt *b; | |
109 | { | |
110 | addr_t a = b->loc; | |
111 | ||
112 | return (adbwrite(ispace(a) ? SP_INSTR : SP_DATA, a, &b->ins, 1) != 1); | |
113 | } | |
114 | ||
115 | /* | |
116 | * Set a (single) breakpoint. Return 0 on success. | |
117 | */ | |
118 | set_bpt(b) | |
119 | struct bkpt *b; | |
120 | { | |
121 | addr_t a = b->loc; | |
122 | int space; | |
123 | char bpt = 0x30; /* breakpoint instruction */ | |
124 | ||
125 | space = ispace(a) ? SP_INSTR : SP_DATA; | |
126 | return (adbread(space, a, &b->ins, 1) != 1 || | |
127 | adbwrite(space, a, &bpt, 1) != 1); | |
128 | } | |
129 | ||
130 | /* | |
131 | * Check a float for `correctness' (reserved patterns, etc). Return | |
132 | * a pointer to a character string to be printed instead of the float, | |
133 | * or NULL to print the float as-is. | |
134 | * | |
135 | * The string returned, if any, should be no longer than 16 characters. | |
136 | * | |
137 | * On the Tahoe, we can simply check the second two bytes. Byte two | |
138 | * contains one bit of the exponent, and byte 3 has the remaining 7 | |
139 | * exponent bits and the sign bit. If the sign bit is set and the | |
140 | * exponent is zero, the value is reserved. | |
141 | * | |
142 | * PLEASE CHECK THE ABOVE, IT IS PROBABLY WRONG | |
143 | */ | |
144 | /* ARGSUSED */ | |
145 | char * | |
146 | checkfloat(fp, isdouble) | |
147 | caddr_t fp; | |
148 | int isdouble; | |
149 | { | |
150 | ||
151 | return ((((short *)fp)[1] & 0xff80) == 0x8000 ? | |
152 | "(reserved oprnd)" : NULL); | |
153 | } | |
154 | ||
155 | /* | |
156 | * Convert a value in `expr_t' format to float or double. | |
157 | */ | |
158 | etofloat(e, fp, isdouble) | |
159 | expr_t e; | |
160 | caddr_t fp; | |
161 | int isdouble; | |
162 | { | |
163 | ||
164 | if (isdouble) | |
165 | ((int *)fp)[1] = 0; | |
166 | *(int *)fp = e; | |
167 | } | |
168 | ||
169 | mch_init() | |
170 | { | |
171 | ||
172 | mkioptab(); | |
173 | } | |
174 | ||
175 | /* quietly read object obj from address addr */ | |
176 | #define GET(obj, addr) (void) adbread(SP_DATA, addr, &(obj), sizeof(obj)) | |
177 | ||
178 | /* set `current process' pcb */ | |
179 | setpcb(addr) | |
180 | addr_t addr; | |
181 | { | |
182 | int pte; | |
183 | ||
184 | GET(pte, addr); | |
185 | masterpcbb = (pte & PG_PFNUM) * NBPG; | |
186 | } | |
187 | ||
188 | getpcb() | |
189 | { | |
190 | ||
191 | /* maybe use adbread() here ... */ | |
192 | (void) readcore((off_t)masterpcbb & ~KERNBASE, | |
193 | (char *)&pcb, sizeof(struct pcb)); | |
194 | adbprintf("p0br %R p0lr %R p2br %R p2lr %R\n", | |
195 | pcb.pcb_p0br, pcb.pcb_p0lr, pcb.pcb_p2br, pcb.pcb_p2lr); | |
196 | } | |
197 | ||
198 | /* | |
199 | * Convert a kernel virtual address to a physical address, | |
200 | * a la the Tahoe hardware. Set *err if the resulting address | |
201 | * is invalid. | |
202 | */ | |
203 | addr_t | |
204 | vtophys(addr, err) | |
205 | addr_t addr; | |
206 | char **err; | |
207 | { | |
208 | register unsigned v = btop(addr & ~KERNBASE); | |
209 | register addr_t pteaddr; | |
210 | struct pte pte; | |
211 | ||
212 | switch ((int)(addr >> 30)) { /* select space */ | |
213 | ||
214 | case 3: | |
215 | /* system space: get system pte */ | |
216 | if (v >= slr) | |
217 | goto oor; | |
218 | pteaddr = (addr_t)(sbr + v) & ~KERNBASE; | |
219 | goto direct; | |
220 | ||
221 | case 2: | |
222 | /* P2 space: must not be in shadow region */ | |
223 | if (v < pcb.pcb_p2lr) | |
224 | goto oor; | |
225 | pteaddr = (addr_t)(pcb.pcb_p2br + v); | |
226 | break; | |
227 | ||
228 | case 1: | |
229 | /* P1 space: verboten (for now) */ | |
230 | goto oor; | |
231 | ||
232 | case 0: | |
233 | /* P0 space: must not be off end of region */ | |
234 | if (v >= pcb.pcb_p0lr) | |
235 | goto oor; | |
236 | pteaddr = (addr_t)(pcb.pcb_p0br + v); | |
237 | break; | |
238 | ||
239 | oor: | |
240 | *err = "address out of segment"; | |
241 | return (0); | |
242 | } | |
243 | ||
244 | /* in P0/P1/P2 space, pte should be in kernel virtual space */ | |
245 | if ((pteaddr & KERNBASE) != KERNBASE) { | |
246 | *err = "bad p0br, p1br, or p2br in pcb"; | |
247 | return (0); | |
248 | } | |
249 | pteaddr = vtophys(pteaddr, err); | |
250 | if (*err) | |
251 | return (0); | |
252 | ||
253 | direct: | |
254 | /* | |
255 | * Read system pte. If valid or reclaimable, | |
256 | * physical address is combination of its page number and | |
257 | * the page offset of the original address. | |
258 | */ | |
259 | if (readcore((off_t)pteaddr, (caddr_t)&pte, 4) != 4) { | |
260 | *err = "page table botch"; | |
261 | return (0); | |
262 | } | |
263 | /* SHOULD CHECK NOT I/O ADDRESS; NEED CPU TYPE! */ | |
264 | if (pte.pg_v == 0 && (pte.pg_fod || pte.pg_pfnum == 0)) { | |
265 | *err = "page not valid/reclaimable"; | |
266 | return (0); | |
267 | } | |
268 | return ((addr_t)(ptob(pte.pg_pfnum) + (addr & PGOFSET))); | |
269 | } | |
270 | ||
271 | /* | |
272 | * Print a stack trace ($c, $C). Trace backwards through nback | |
273 | * frames; if locals is set, print local variables. | |
274 | */ | |
275 | printstack(locals, nback) | |
276 | int locals, nback; | |
277 | { | |
278 | register int i; | |
279 | register addr_t a; | |
280 | struct nlist *sym; | |
281 | char *s; | |
282 | addr_t callpc; /* pc that called this frame */ | |
283 | int narg; /* number of arguments to this frame */ | |
284 | struct activation cur; /* this frame itself */ | |
285 | struct frame fr; /* the frame above this frame */ | |
286 | addr_t dummy; /* a variable to scribble on */ | |
287 | #define UNKNOWN -1 | |
288 | ||
289 | #ifdef RLOCALS | |
290 | /* if locals variables are broken, use an alternate strategy */ | |
291 | register int r; | |
292 | addr_t sp, prev_sp; | |
293 | int regs[13]; | |
294 | static char unknown[] = "<unknown>"; | |
295 | #endif | |
296 | ||
297 | #ifdef RLOCALS | |
298 | /* grab registers */ | |
299 | bcopy((caddr_t)(kcore ? &pcb.pcb_r0 : &u.u_ar0[R0]), (caddr_t)regs, | |
300 | sizeof(regs)); | |
301 | #endif | |
302 | ||
303 | /* set up the current stack frame */ | |
304 | if (gavedot) { | |
305 | cur.a_fp = dot; | |
306 | cur.a_pc = UNKNOWN; | |
307 | #ifdef RLOCALS | |
308 | sp = UNKNOWN; | |
309 | #endif | |
310 | } else if (kcore) { | |
311 | cur.a_fp = pcb.pcb_fp; | |
312 | cur.a_pc = pcb.pcb_pc; | |
313 | #ifdef RLOCALS | |
314 | sp = pcb.pcb_ksp; | |
315 | #endif | |
316 | } else { | |
317 | cur.a_fp = u.u_ar0[FP]; | |
318 | cur.a_pc = u.u_ar0[PC]; | |
319 | #ifdef RLOCALS | |
320 | sp = u.u_ar0[SP]; | |
321 | #endif | |
322 | } | |
323 | ||
324 | /* now back up through the stack */ | |
325 | while (nback-- && cur.a_fp != 0) { | |
326 | /* read this frame, but defer error check */ | |
327 | GET(fr, cur.a_fp - FRAMEOFF); | |
328 | ||
329 | /* where are we? ... if u. area, signal trampoline code */ | |
330 | if (cur.a_pc >= USRSTACK && cur.a_pc < KERNBASE) { | |
331 | narg = 0; | |
332 | GET(callpc, cur.a_fp + 44); /* XXX magic 44 */ | |
333 | s = "sigtramp"; | |
334 | } else { | |
335 | narg = (fr.fr_removed >> 2) - 1; | |
336 | callpc = fr.fr_savpc; | |
337 | if (cur.a_pc != UNKNOWN && | |
338 | (sym = findsym(cur.a_pc, SP_INSTR, &dummy)) != 0) { | |
339 | s = sym->n_un.n_name; | |
340 | if (eqstr(s, "start")) { | |
341 | errflag = NULL; | |
342 | break; | |
343 | } | |
344 | } else | |
345 | s = "?"; | |
346 | } | |
347 | /* safe at last to check for error reading frame */ | |
348 | checkerr(); | |
349 | ||
350 | /* arguments */ | |
351 | adbprintf("%s(", s); | |
352 | a = cur.a_fp; | |
1d00e0a0 | 353 | for (i = narg > 20 ? 20 : narg; i;) { |
f582ecdc KB |
354 | prfrom(a += 4, --i ? ',' : 0); |
355 | checkerr(); | |
356 | } | |
357 | printc(')'); | |
358 | if (cur.a_pc != UNKNOWN) { | |
359 | prints(" at "); | |
360 | psymoff("%R", cur.a_pc, SP_INSTR, -(addr_t)1, ""); | |
361 | } | |
362 | printc('\n'); | |
363 | ||
364 | /* local variables */ | |
365 | if (locals) { | |
366 | #ifdef busted | |
367 | if (cur.a_pc != UNKNOWN) { | |
368 | sym = findsym(cur.a_pc, SP_INSTR, &dummy); | |
369 | while ((sym = nextlocal(sym)) != NULL) { | |
370 | adbprintf("%8t"); | |
371 | printlsym(sym->n_un.n_name); | |
372 | adbprintf(":%12t"); | |
373 | prfrom(eval_localsym(sym, &cur), '\n'); | |
374 | } | |
375 | } | |
376 | #endif | |
377 | #ifdef RLOCALS | |
378 | adbprintf("\ | |
9b51ffc2 CT |
379 | fp: %R\%16tsp: %?s%?R%32tpc: %?s%?R%48tr0: %R\n\ |
380 | r1: %R\%16tr2: %R\%32tr3: %R\%48tr4: %R\n\ | |
381 | r5: %R\%16tr6: %R\%32tr7: %R\%48tr8: %R\n\ | |
382 | r9: %R\%16tr10: %R\%32tr11: %R\%48tr12: %R\n", | |
f582ecdc KB |
383 | #define q(s) s == UNKNOWN, unknown, s != UNKNOWN, s |
384 | cur.a_fp, q(sp), q(cur.a_pc), regs[0], | |
385 | #undef q | |
386 | regs[1], regs[2], regs[3], regs[4], | |
387 | regs[5], regs[6], regs[7], regs[8], | |
388 | regs[9], regs[10], regs[11], regs[12]); | |
389 | ||
390 | /* update registers, and find previous frame's sp */ | |
391 | a = cur.a_fp + 4; | |
392 | for (r = 0, i = fr.fr_mask; i != 0; r++, i >>= 1) | |
393 | if (i & 1) | |
394 | GET(regs[r], a += 4); | |
395 | a += narg * 4; | |
396 | prev_sp = a; | |
397 | ||
398 | /* now print automatics */ | |
399 | if (sp != UNKNOWN) { | |
400 | #define MAXPRINT 30 /* max # words to print */ | |
401 | /* XXX should be settable */ | |
402 | i = (cur.a_fp - sp) >> 2; | |
403 | if (i > MAXPRINT) | |
404 | i = MAXPRINT; | |
405 | for (a = cur.a_fp; --i >= 0;) { | |
406 | a -= 4; | |
407 | adbprintf("%R: %V(fp):%24t", | |
408 | a, a - cur.a_fp); | |
409 | prfrom(a, '\n'); | |
410 | } | |
411 | if (a > sp) | |
412 | adbprintf("\ | |
413 | %R: %V(fp) .. %R: %V(fp) not displayed\n", | |
414 | a, a - cur.a_fp, | |
415 | sp, sp - cur.a_fp); | |
416 | } | |
417 | #endif /* RLOCALS */ | |
418 | } | |
419 | ||
420 | errflag = NULL; /* clobber any read errors */ | |
421 | ||
422 | /* back up one frame */ | |
423 | if (fr.fr_savfp == 0) | |
424 | break; | |
425 | cur.a_fp = fr.fr_savfp; | |
426 | #ifdef RLOCALS | |
427 | sp = prev_sp; | |
428 | #endif | |
429 | cur.a_pc = callpc; | |
430 | ||
431 | if (!gavedot && !INSTACK(cur.a_fp) && !kcore) | |
432 | break; | |
433 | ||
434 | /* make sure we returned somewhere... */ | |
435 | (void) adbread(kcore ? SP_DATA : SP_INSTR, cur.a_pc, &dummy, 1); | |
436 | checkerr(); | |
437 | } | |
438 | } | |
439 | ||
440 | /* | |
441 | * Register offset to u. pointer, and register offset to ptrace value | |
442 | */ | |
443 | #define otoua(o) \ | |
444 | ((int *)(((o) < 0 ? (int)u.u_ar0 : (int)&u.u_pcb) + (o))) | |
445 | #define otopt(o) \ | |
446 | ((int *)((o) < 0 ? (o) + ctob(UPAGES) : (o))) | |
447 | ||
448 | /* | |
449 | * Return the value of some register. | |
450 | */ | |
451 | expr_t | |
452 | getreg(reg) | |
453 | register struct reglist *reg; | |
454 | { | |
455 | ||
456 | return (kcore ? *reg->r_pcbaddr : *otoua(reg->r_offset)); | |
457 | } | |
458 | ||
459 | ||
460 | /* | |
461 | * Set the value of some register. Return 0 if all goes well. | |
462 | */ | |
463 | setreg(reg, val) | |
464 | register struct reglist *reg; | |
465 | expr_t val; | |
466 | { | |
467 | ||
468 | if (kcore) | |
469 | *reg->r_pcbaddr = val; | |
470 | else { | |
471 | *otoua(reg->r_offset) = val; | |
472 | if (pid) { | |
473 | errno = 0; | |
474 | if (ptrace(PT_WRITE_U, pid, otopt(reg->r_offset), | |
475 | (int)val) == -1 && errno) | |
476 | return (-1); | |
477 | } | |
478 | } | |
479 | return (0); | |
480 | } | |
481 | ||
482 | /* | |
483 | * Read registers from current process. | |
484 | */ | |
485 | readregs() | |
486 | { | |
487 | register struct reglist *reg; | |
488 | extern struct reglist reglist[]; | |
489 | ||
490 | for (reg = reglist; reg->r_name != NULL; reg++) | |
491 | *otoua(reg->r_offset) = | |
492 | ptrace(PT_READ_U, pid, otopt(reg->r_offset), 0); | |
493 | } | |
494 | ||
495 | addr_t | |
496 | getpc() | |
497 | { | |
498 | ||
499 | return (kcore ? pcb.pcb_pc : u.u_ar0[PC]); | |
500 | } | |
501 | ||
502 | setpc(where) | |
503 | addr_t where; | |
504 | { | |
505 | ||
506 | if (kcore) | |
507 | pcb.pcb_pc = where; | |
508 | else | |
509 | u.u_ar0[PC] = where; | |
510 | } | |
511 | ||
512 | /* | |
513 | * udot returns true if u.u_pcb appears correct. More extensive | |
514 | * checking is possible.... | |
515 | */ | |
516 | udot() | |
517 | { | |
518 | ||
519 | /* user stack should be in stack segment */ | |
520 | if (!INSTACK(u.u_pcb.pcb_usp)) | |
521 | return (0); | |
522 | /* kernel stack should be in u. area */ | |
523 | if (u.u_pcb.pcb_ksp < USRSTACK || u.u_pcb.pcb_ksp >= KERNBASE) | |
524 | return (0); | |
525 | /* looks good to us... */ | |
526 | return (1); | |
527 | } | |
528 | ||
529 | sigprint() | |
530 | { | |
531 | extern char *sys_siglist[]; | |
532 | extern char *illinames[], *fpenames[]; | |
533 | extern int nillinames, nfpenames; | |
534 | ||
535 | if ((u_int)signo - 1 < NSIG - 1) | |
536 | prints(sys_siglist[signo]); | |
537 | switch (signo) { | |
538 | ||
539 | case SIGFPE: | |
540 | if ((u_int)sigcode < nfpenames) | |
541 | prints(fpenames[sigcode]); | |
542 | break; | |
543 | ||
544 | case SIGILL: | |
545 | if ((u_int)sigcode < nillinames) | |
546 | prints(illinames[sigcode]); | |
547 | break; | |
548 | } | |
549 | } |