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