4.4BSD/usr/src/contrib/gdb-4.7.lbl/gdb/sparcbsd-tdep.c
/* Target-dependent code for the SPARC for GDB, the GNU debugger.
Copyright 1986, 1987, 1989, 1991 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
* This is the target dependent code for a sparcstation running BSD.
* We cannot share this code with SunOS because many kernel data
* structures are different. The shareable code is in sparc-tcmn.c.
*/
#define __sys_stdtypes_h /* XXX defeat sun types file */
#include <sys/param.h>
#include <stdio.h>
#include "defs.h"
#include "frame.h"
#include "inferior.h"
#include "obstack.h"
#include "target.h"
#include "ieee-float.h"
#include <sys/ptrace.h>
#include "gdbcore.h"
#ifdef KERNELDEBUG
#include <kvm.h>
#include <sys/dir.h>
#include <sys/user.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <fcntl.h>
extern int kernel_debugging;
CORE_ADDR ksym_lookup();
CORE_ADDR addr_of_pc();
/*
* 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))))
#endif
/*
* Return the address of the saved pc in frame.
*/
CORE_ADDR
addr_of_pc(frame)
struct frame_info *frame;
{
CORE_ADDR addr;
register struct rwindow *rw;
#ifdef KERNELDEBUG
/*
* 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 tstart, tend;
if (tstart == 0) {
tstart = ksym_lookup("trapbase");
tend = ksym_lookup("endtrapcode");
}
rw = (struct rwindow *)frame->next->bottom;
addr = read_memory_integer((CORE_ADDR)&rw->rw_in[7], 4);
if (addr >= tstart && addr < tend) {
rw = (struct rwindow *)frame->bottom;
return (CORE_ADDR)&rw->rw_local[1];
}
}
#endif
rw = (struct rwindow *)frame->bottom;
return (CORE_ADDR)&rw->rw_in[7];
}
#ifdef KERNELDEBUG
/*
* 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. */
#include "symtab.h"
/*
* 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 pcb *cpcb;
void set_curproc();
/*
* Return true if ADDR is a valid stack address according to the
* current boundaries (which are determined by the currently running
* user process).
*/
int
inside_kernstack(addr)
CORE_ADDR addr;
{
if (cpcb == 0)
set_curproc();
return (addr > intstack_bottom && addr < intstack_top) ||
(addr > kernstack_bottom && addr < kernstack_top);
}
/*
* (re-)set the variables that make inside_kernstack() work.
*/
void
set_kernel_boundaries(p)
struct pcb *p;
{
register CORE_ADDR a = (CORE_ADDR)p;
if (intstack_top == 0) {
intstack_top = ksym_lookup("eintstack");
intstack_bottom = ksym_lookup("intstack");
}
kernstack_bottom = a;
kernstack_top = a + UPAGES * NBPG;
}
/*
* Return the current proc. masterprocp points to
* current proc which points to current u area.
*/
struct pcb *
fetch_cpcb()
{
struct pcb *p;
static CORE_ADDR addr;
if (addr == 0)
addr = ksym_lookup("cpcb");
if (READMEM(addr, &p))
error("cannot read cpcb pointer at 0x%x\n", addr);
return (p);
}
/*
* 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.
*/
void
set_curproc()
{
cpcb = fetch_cpcb();
set_kernel_boundaries(cpcb);
}
/*
* All code below is exclusively for support of kernel core files.
*/
/*
* Fetch registers from a crashdump or /dev/kmem.
*/
static void
kvm_fetch_registers(p)
struct pcb *p;
{
int i;
u_long reg, sp;
float freg;
struct rwindow win;
struct trapframe tf;
struct pcb pcb;
/* find the pcb for the current process */
if (READMEM(p, &pcb))
error("cannot read pcb at 0x%x", p);
/*
* Invalidate all the registers then fill in the ones we know about.
*/
registers_changed();
sp = pcb.pcb_sp;
supply_register(SP_REGNUM, (char *)&pcb.pcb_sp);
supply_register(PC_REGNUM, (char *)&pcb.pcb_pc);
/* PC came from o7. */
supply_register(15, (char *)&pcb.pcb_pc);
supply_register(PS_REGNUM, (char *)&pcb.pcb_psr);
#ifdef notyet
/* XXX There should be a WIM_REGNUM. */
/* XXX must compute 1 << pcb.pcb_wim */
supply_register(66, (char *)&pcb.pcb_uwm);
#endif
/*
* Read last register window saved on stack.
*/
if (READMEM(sp, &win)) {
printf("cannot read register window at sp=%x\n", pcb.pcb_sp);
bzero((char *)&win, sizeof win);
}
for (i = 0; i < 8; ++i)
supply_register(i + 16, &win.rw_local[i]);
for (i = 0; i < 8; ++i)
supply_register(i + 24, &win.rw_in[i]);
/*
* read the globals & outs saved on the stack (for a trap frame).
*/
sp += 96; /* XXX sizeof(struct frame) */
if (READMEM(sp, &tf) == 0) {
/* XXX 8+6 below knows that o0..o5 appear after g7 */
for (i = 1; i < 8 + 6; i++)
supply_register(i, (char *)&tf.tf_global[i]);
}
}
/*
* Set the process context to that of the proc structure at
* system address paddr. Read in the register state.
*/
int
set_procaddr(paddr)
CORE_ADDR paddr;
{
struct pcb *ppcb;
if (paddr == 0)
cpcb = fetch_cpcb();
else {
struct proc *p = (struct proc *)paddr;
if ((unsigned)p < KERNBASE)
return (1);
if (READMEM(&p->p_addr, &ppcb))
error("cannot read p_addr at 0x%x", &p->p_addr);
cpcb = ppcb;
}
set_kernel_boundaries(cpcb);
kvm_fetch_registers(cpcb);
return (0);
}
/*
* 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.
*/
/* ARGSUSED */
void
kernel_core_registers (regno)
int 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(cpcb);
}
#endif
/* Structure of SPARC extended floating point numbers.
This information is not currently used by GDB, since no current SPARC
implementations support extended float. */
const struct ext_format ext_format_sparc = {
/* tot sbyte smask expbyte manbyte */
16, 0, 0x80, 0,1, 4,8, /* sparc */
};