/* * Copyright (c) 1992 Regents of the University of California. * All rights reserved. * * 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. */ #ifndef lint static char rcsid[] = "@(#) $Header: sparc-tdep.c,v 1.2 93/02/19 15:25:07 mccanne Exp $ (LBL)"; #endif #include <stdio.h> #include "defs.h" #include "frame.h" #include "target.h" #include <machine/reg.h> #ifdef KERNELDEBUG #include "kernel.h" #include <kvm.h> #include <sys/param.h> #include <sys/dir.h> #include <sys/user.h> #include <signal.h> #include <sys/ioctl.h> #include <fcntl.h> 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)))) #endif /* * Return the address of the saved pc in frame. */ CORE_ADDR addr_of_pc(frame) struct frame_info *frame; { register 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 locore_h, locore_t; if (locore_h == 0) { 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]; } } #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 proc *curproc; 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 (curproc == 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 proc *p; { CORE_ADDR kstack; if (intstack_top == 0) { 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). */ if (p == NULL) kstack = ksym_lookup("ubasic"); else { if (READMEM(&p->p_segu, &kstack)) error("cannot read kernel stack pointer at %x\n", &p->p_segu); } kernstack_bottom = kstack; kernstack_top = kstack + KERNSTACK; } /* * Return the current proc. masterprocp points to * current proc which points to current u area. */ struct proc * fetch_curproc() { struct proc *p; static CORE_ADDR addr; if (addr == 0) addr = ksym_lookup("masterprocp"); if (READMEM(addr, &p)) error("cannot read proc pointer at %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() { 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. */ void kvm_fetch_registers(p) struct proc *p; { struct user *uaddr; int i; u_long cps, reg, sp; float freg; struct rwindow win; struct pcb pcb; /* 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. */ 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); /* XXX There should be a WIM_REGNUM. */ supply_register(66, (char *)&pcb.pcb_uwm); /* * 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 += 92 + 12; /* XXX - MINFRAME + R_Y */ for (i = 1; i < 14; ++i) { u_long val; 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. */ int set_procaddr(paddr) CORE_ADDR paddr; { struct proc proc; struct user *uaddr; if (paddr == 0) paddr = (CORE_ADDR)fetch_curproc(); if (paddr < KERNELBASE) return (1); 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); return (1); } curproc = (struct proc *)paddr; set_kernel_boundaries(curproc); kvm_fetch_registers(curproc); 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(curproc); } /* * Building in support for stepping through a longjmp is silly. * Couldn't the gdb maintainers spend their time more productively? */ int get_longjmp_target(pc) CORE_ADDR *pc; { return (0); } #endif