* Copyright (c) 1992 Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Lawrence Berkeley Laboratory,
* Berkeley, CA. The name of the University may not be used to
* endorse or promote products derived from this software without
* specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* Target dependent code for a sparcstation running SunOS.
* This is mostly kernel debugging support.
* Common code is in sparc-tcmn.c.
"@(#) $Header: sparc-tdep.c,v 1.2 93/02/19 15:25:07 mccanne Exp $ (LBL)";
extern int kernel_debugging
;
extern CORE_ADDR
ksym_lookup();
* Read the "thing" at address 'addr' into the space pointed to by P.
* The length of the "thing" is determined by the type of P.
* Result is non-zero if transfer fails.
#define READMEM(addr, p) \
(target_read_memory((CORE_ADDR)(addr), (char *)(p), sizeof(*(p))))
* Return the address of the saved pc in frame.
struct frame_info
*frame
;
register struct rwindow
*rw
;
* If we are kernel debugging, we must special case trap frames.
* We can tell if we are a trap frame by looking at the return
* address of the frame below us. If it is in locore, then
* we are such a frame and we can find our saved pc in %l1.
if (kernel_debugging
&& frame
->next
) {
static CORE_ADDR locore_h
, locore_t
;
locore_h
= ksym_lookup("sys_trap");
locore_t
= ksym_lookup("kadb_tcode");
rw
= (struct rwindow
*)frame
->next
->bottom
;
addr
= read_memory_integer((CORE_ADDR
)&rw
->rw_in
[7], 4);
if (addr
> locore_h
&& addr
< locore_t
) {
rw
= (struct rwindow
*)frame
->bottom
;
return (CORE_ADDR
)&rw
->rw_local
[1];
rw
= (struct rwindow
*)frame
->bottom
;
return (CORE_ADDR
)&rw
->rw_in
[7];
* The code below implements kernel debugging of crashdumps (or /dev/kmem)
* or remote systems (via a serial link). For remote kernels, the remote
* context does most the work, so there is very little to do -- we just
* manage the kernel stack boundaries so we know where to stop a backtrace.
* The crashdump/kmem (kvm) support is a bit more grungy, but thanks to
* libkvm (see kcore.c) not too bad. The main work is kvm_fetch_registers
* which sucks the register state out of the current processes pcb.
* There is a command that let's you set the current process -- hopefully,
* to something that's blocked (in the live kernel case).
/* XXX For misc_function_vector. */
* Address ranges for the kernel interrupt stack (fixed) and the current
* process' kernel stack (dynamic).
static CORE_ADDR intstack_top
;
static CORE_ADDR intstack_bottom
;
static CORE_ADDR kernstack_top
;
static CORE_ADDR kernstack_bottom
;
static struct proc
*curproc
;
* Return true if ADDR is a valid stack address according to the
* current boundaries (which are determined by the currently running
return (addr
> intstack_bottom
&& addr
< intstack_top
) ||
(addr
> kernstack_bottom
&& addr
< kernstack_top
);
* (re-)set the variables that make inside_kernstack() work.
intstack_top
= ksym_lookup("eintstack");
intstack_bottom
= ksym_lookup("intstack");
* During boot, if masterprocp is still NULL the kernel
* stack lives in [ubasic..ubasic+KERNSTACK).
kstack
= ksym_lookup("ubasic");
if (READMEM(&p
->p_segu
, &kstack
))
error("cannot read kernel stack pointer at %x\n",
kernstack_bottom
= kstack
;
kernstack_top
= kstack
+ KERNSTACK
;
* Return the current proc. masterprocp points to
* current proc which points to current u area.
addr
= ksym_lookup("masterprocp");
error("cannot read proc pointer at %x\n", addr
);
* Called from remote_wait, after the remote kernel has stopped.
* Look up the current proc, and set up boundaries.
* This is for active kernels only.
curproc
= fetch_curproc();
set_kernel_boundaries(curproc
);
* All code below is exclusively for support of kernel core files.
* Fetch registers from a crashdump or /dev/kmem.
/* find the pcb for the current process */
if (READMEM(&p
->p_uarea
, &uaddr
))
error("cannot u area ptr for proc at 0x%x", p
);
if (READMEM(&uaddr
->u_pcb
, &pcb
))
error("cannot read pcb at 0x%x", &uaddr
->u_pcb
);
* Invalidate all the registers then fill in the ones we know about.
supply_register(SP_REGNUM
, (char *)&pcb
.pcb_sp
);
supply_register(PC_REGNUM
, (char *)&pcb
.pcb_pc
);
supply_register(15, (char *)&pcb
.pcb_pc
);
supply_register(PS_REGNUM
, (char *)&pcb
.pcb_psr
);
/* XXX There should be a WIM_REGNUM. */
supply_register(66, (char *)&pcb
.pcb_uwm
);
* Read last register window saved on stack.
printf("cannot read register window at sp=%x\n", pcb
.pcb_sp
);
bzero((char *)&win
, sizeof win
);
supply_register(i
+ 16, &win
.rw_local
[i
]);
supply_register(i
+ 24, &win
.rw_in
[i
]);
* read the globals & outs saved on the stack (for a trap frame).
sp
+= 92 + 12; /* XXX - MINFRAME + R_Y */
for (i
= 1; i
< 14; ++i
) {
if (READMEM(sp
+ i
*4, &val
) == 0)
supply_register(i
, (char *)&val
);
if (READMEM(pcb
.pcb_cpctxp
, &cps
) == 0)
supply_register(CPS_REGNUM
, (char *)&cps
);
* Set the process context to that of the proc structure at
* system address paddr. Read in the register state.
paddr
= (CORE_ADDR
)fetch_curproc();
if (READMEM(paddr
, &proc
))
error("cannot read proc struct at 0x%x", paddr
);
* This is REALLY STUPID. The only way to tell libkvm that we want to
* change user address maps is with kvm_getu.
* If the getu fails, revert to the old address.
if (kernel_getu((u_long
*)&proc
) == 0) {
(void)READMEM(curproc
, &proc
);
(void)kernel_getu((u_long
*)&proc
);
error("cannot read uarea for proc at 0x%x", paddr
);
curproc
= (struct proc
*)paddr
;
set_kernel_boundaries(curproc
);
kvm_fetch_registers(curproc
);
* Get the registers out of a crashdump or /dev/kmem.
* XXX This somehow belongs in kcore.c.
* We just get all the registers, so we don't use regno.
kernel_core_registers(regno
)
* Need to find current u area to get kernel stack and pcb
* where "panic" saved registers.
* (libkvm also needs to know current u area to get user
* address space mapping).
(void)set_procaddr(curproc
);
* Building in support for stepping through a longjmp is silly.
* Couldn't the gdb maintainers spend their time more productively?