static char sccsid
[] = "@(#)machdep.c 5.2 (Berkeley) %G%";
* adb - miscellaneous machine dependent routines.
#define RLOCALS /* enable alternate $C stack trace */
#include <machine/frame.h>
#include <machine/vmparam.h>
* Set up a stack frame based on the registers in the core image
* (or in the kernel core file ... not yet!).
register struct activation
*ap
;
* Back up one stack frame in the call stack.
* ap points to the activation record from the previous frame.
* Clear a_valid field if we ran out of frames.
register struct activation
*ap
;
* The magic constants below allow us to read just the part of
* the frame that we need.
if (adbread(SP_DATA
, ap
->a_fp
+ 8, &fr
.fr_savap
, 12) != 12)
* Evaluate a local symbol (N_LSYM or N_PSYM) using the activation
* record pointed to by ap.
register struct nlist
*sp
;
return (ap
->a_fp
- sp
->n_value
); /* ??? */
return (ap
->a_ap
+ sp
->n_value
); /* ??? */
/* true iff address a is in instruction space */
#define ispace(a) ((a) < txtmap.m1.e)
* Delete a (single) breakpoint. Return 0 on success.
return (adbwrite(ispace(a
) ? SP_INSTR
: SP_DATA
, a
, &b
->ins
, 1) != 1);
* Set a (single) breakpoint. Return 0 on success.
char bpt
= 0x03; /* breakpoint instruction */
space
= ispace(a
) ? SP_INSTR
: SP_DATA
;
return (adbread(space
, a
, &b
->ins
, 1) != 1 ||
adbwrite(space
, a
, &bpt
, 1) != 1);
* Check a float for `correctness' (reserved patterns, etc). Return
* a pointer to a character string to be printed instead of the float,
* or NULL to print the float as-is.
* The string returned, if any, should be no longer than 16 characters.
* On the VAX, we can simply check the first two bytes. Byte zero
* contains one bit of the exponent, and byte 1 has the remaining 7
* exponent bits and the sign bit. If the sign bit is set and the
* exponent is zero, the value is reserved.
return ((*(short *)fp
& 0xff80) == 0x8000 ? "(reserved oprnd)" : NULL
);
* Convert a value in `expr_t' format to float or double.
etofloat(e
, fp
, isdouble
)
/* quietly read object obj from address addr */
#define GET(obj, addr) (void) adbread(SP_DATA, addr, &(obj), sizeof(obj))
/* set `current process' pcb */
masterpcbb
= (pte
& PG_PFNUM
) * NBPG
;
/* maybe use adbread() here ... */
(void) readcore((off_t
)masterpcbb
& ~KERNBASE
,
(char *)&pcb
, sizeof(struct pcb
));
pcb
.pcb_p0lr
&= ~AST_CLR
;
adbprintf("p0br %R p0lr %R p1br %R p1lr %R\n",
pcb
.pcb_p0br
, pcb
.pcb_p0lr
, pcb
.pcb_p1br
, pcb
.pcb_p1lr
);
* Convert a kernel virtual address to a physical address,
* a la the VAX hardware. Set *err if the resulting address
register unsigned v
= btop(addr
& ~0xc0000000);
#define issys(a) ((a) & 0x80000000)
#define isp1(a) ((a) & 0x40000000)
/* system space: get system pte */
if (isp1(addr
) || v
>= slr
) {
*err
= "address out of segment";
pteaddr
= (addr_t
)(sbr
+ v
) & ~0x80000000;
/* P1 space: must not be in shadow region */
pteaddr
= (addr_t
)(pcb
.pcb_p1br
+ v
);
/* P0 space: must not be off end of region */
pteaddr
= (addr_t
)(pcb
.pcb_p0br
+ v
);
if (!issys(pteaddr
) || isp1(pteaddr
)) {
*err
= "bad p0br or p1br in pcb";
/* in either case, find system pte by recursing */
pteaddr
= vtophys(pteaddr
, err
);
* Read system pte. If valid or reclaimable,
* physical address is combination of its page number and
* the page offset of the original address.
if (readcore((off_t
)pteaddr
, (caddr_t
)&pte
, 4) != 4) {
*err
= "page table botch";
/* SHOULD CHECK NOT I/O ADDRESS; NEED CPU TYPE! */
if (pte
.pg_v
== 0 && (pte
.pg_fod
|| pte
.pg_pfnum
== 0)) {
*err
= "page not valid/reclaimable";
return ((addr_t
)(ptob(pte
.pg_pfnum
) + (addr
& PGOFSET
)));
* Print a stack trace ($c, $C). Trace backwards through nback
* frames; if locals is set, print local variables.
printstack(locals
, nback
)
/* addr_t callpc; /* pc that called this frame */
struct activation cur
; /* this frame itself */
struct frame fr
; /* the frame above this frame */
u_char narg
; /* number of int-args to this frame */
addr_t dummy
; /* a variable to scribble on */
/* if locals variables are broken, use an alternate strategy */
static char unknown
[] = "<unknown>";
/* fr_savpc==UNKNOWN implies fr is invalid */
bcopy((caddr_t
)(kcore
? &pcb
.pcb_r0
: &u
.u_ar0
[R0
]), (caddr_t
)regs
,
/* set up the current stack frame */
if (fr
.fr_s
) { /* was a `calls'; can figure out ap */
cur
.a_ap
= cur
.a_fp
+ sizeof(fr
) + fr
.fr_spa
;
for (i
= fr
.fr_mask
; i
!= 0; i
>>= 1)
} else /* `callg': cannot find ap */
/* now back up through the stack */
if (fr
.fr_savpc
== UNKNOWN
)
/* where are we? ... if u. area, signal trampoline code */
if ((int)cur
.a_pc
>= USRSTACK
) {
/* GET(callpc, cur.a_fp + 92); /* XXX magic 92 */
/* callpc = fr.fr_savpc; */
if (cur
.a_pc
!= UNKNOWN
&&
(sym
= findsym(cur
.a_pc
, SP_INSTR
, &dummy
)) != 0) {
if ((a
= cur
.a_ap
) != UNKNOWN
) {
prfrom(a
+= 4, --i
? ',' : 0);
if (cur
.a_pc
!= UNKNOWN
) {
psymoff("%R", cur
.a_pc
, SP_INSTR
, -(addr_t
)1, "");
if (cur
.a_pc
!= UNKNOWN
) {
sym
= findsym(cur
.a_pc
, SP_INSTR
, &dummy
);
while ((sym
= nextlocal(sym
)) != NULL
) {
printlsym(sym
->n_un
.n_name
);
prfrom(eval_localsym(sym
, &cur
), '\n');
fp: %R\%16tap: %?s%?R%32tsp: %?s%?R%48tpc: %?s%?R\n\
r0: %R\%16tr1: %R\%32tr2: %R\%48tr3: %R\n\
r4: %R\%16tr5: %R\%32tr6: %R\%48tr7: %R\n\
r8: %R\%16tr9: %R\%32tr10: %R\%48tr11: %R\n",
#define q(s) s == UNKNOWN, unknown, s != UNKNOWN, s
cur
.a_fp
, q(cur
.a_ap
), q(sp
), q(cur
.a_pc
),
regs
[0], regs
[1], regs
[2], regs
[3],
regs
[4], regs
[5], regs
[6], regs
[7],
regs
[8], regs
[9], regs
[10], regs
[11]);
/* update registers, and find previous frame's sp */
for (r
= 0, i
= fr
.fr_mask
; i
!= 0; r
++, i
>>= 1)
/* now print automatics */
#define MAXPRINT 30 /* max # words to print */
/* XXX should be settable */
i
= (cur
.a_fp
- sp
) >> 2;
for (a
= cur
.a_fp
; --i
>= 0;) {
adbprintf("%R: %V(fp):%24t",
%R: %V(fp) .. %R: %V(fp) not displayed\n",
errflag
= NULL
; /* clobber any read errors */
fr
.fr_savpc
= UNKNOWN
; /* until we read it again */
if (!gavedot
&& !INSTACK(cur
.a_fp
) && !kcore
)
/* make sure we returned somewhere... */
(void) adbread(kcore
? SP_DATA
: SP_INSTR
, cur
.a_pc
, &dummy
, 1);
* Register offset to u. pointer, and register offset to ptrace value
((int *)(((o) < 0 ? (int)u.u_ar0 : (int)&u.u_pcb) + (o)))
((int *)((o) < 0 ? (o) + ctob(UPAGES) : (o)))
* Return the value of some register.
register struct reglist
*reg
;
return (kcore
? *reg
->r_pcbaddr
: *otoua(reg
->r_offset
));
* Set the value of some register. Return 0 if all goes well.
register struct reglist
*reg
;
*otoua(reg
->r_offset
) = val
;
if (ptrace(PT_WRITE_U
, pid
, otopt(reg
->r_offset
),
(int)val
) == -1 && errno
)
* Read registers from current process.
register struct reglist
*reg
;
extern struct reglist reglist
[];
for (reg
= reglist
; reg
->r_name
!= NULL
; reg
++)
ptrace(PT_READ_U
, pid
, otopt(reg
->r_offset
), 0);
* udot returns true if u.u_pcb appears correct. More extensive
* checking is possible....
/* user stack should be in stack segment */
if (!INSTACK(u
.u_pcb
.pcb_usp
))
/* kernel stack should be in u. area */
if (u
.u_pcb
.pcb_ksp
< USRSTACK
)
/* looks good to us... */
extern char *sys_siglist
[];
extern char *illinames
[], *fpenames
[];
extern int nillinames
, nfpenames
;
if ((u_int
)signo
- 1 < NSIG
- 1)
prints(sys_siglist
[signo
]);
if ((u_int
)sigcode
< nfpenames
)
prints(fpenames
[sigcode
]);
if ((u_int
)sigcode
< nillinames
)
prints(illinames
[sigcode
]);