From 55acf40cfd31fbe1176d0224ec155901bfb76a64 Mon Sep 17 00:00:00 2001 From: "William F. Jolitz" Date: Sun, 12 Jul 1992 19:29:41 -0800 Subject: [PATCH] 386BSD 0.1 development Work on file usr/src/usr.bin/gdb/config/i386bsd-dep.c Co-Authored-By: Lynne Greer Jolitz Synthesized-from: 386BSD-0.1 --- usr/src/usr.bin/gdb/config/i386bsd-dep.c | 1867 ++++++++++++++++++++++ 1 file changed, 1867 insertions(+) create mode 100644 usr/src/usr.bin/gdb/config/i386bsd-dep.c diff --git a/usr/src/usr.bin/gdb/config/i386bsd-dep.c b/usr/src/usr.bin/gdb/config/i386bsd-dep.c new file mode 100644 index 0000000000..6172cf7c30 --- /dev/null +++ b/usr/src/usr.bin/gdb/config/i386bsd-dep.c @@ -0,0 +1,1867 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + */ + +#ifndef lint +static char sccsid[] = "@(#)i386bsd-dep.c 6.10 (Berkeley) 6/26/91"; +#endif /* not lint */ + +/* Low level interface to ptrace, for GDB when running on the Intel 386. + Copyright (C) 1988, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB 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 1, or (at your option) +any later version. + +GDB 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 GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" +#include "value.h" + +#include +#include +#include +#include +#include + +#include + +#ifndef N_SET_MAGIC +#define N_SET_MAGIC(exec, val) ((exec).a_magic = (val)) +#endif + +#include +#include +#include +#define curpcb Xcurpcb /* XXX avoid leaking declaration from pcb.h */ +#include +#undef curpcb +#include +#include +#include + +#include + +#ifdef KERNELDEBUG +#ifndef NEWVM +#include +#include +#else +#include /* for curproc */ +#endif +#include +#include +#include +#include "symtab.h" /* XXX */ + +#undef vtophys /* XXX */ + +extern int kernel_debugging; + +#define KERNOFF ((unsigned)KERNBASE) +#ifndef NEWVM +#define INKERNEL(x) ((x) >= KERNOFF && (x) < KERNOFF + ctob(slr)) +#define INUPAGE(x) \ + ((x) >= KERNEL_U_ADDR && (x) < KERNEL_U_ADDR + NBPG) +#else +#define INKERNEL(x) ((x) >= KERNOFF) +#endif + +#define PT_ADDR_ANY ((caddr_t) 1) + +/* + * Convert from sysmap pte index to system virtual address & vice-versa. + * (why aren't these in one of the system vm macro files???) + */ +#define smxtob(a) (sbr + (a) * sizeof(pte)) +#define btosmx(b) (((b) - sbr) / sizeof(pte)) + +static int ok_to_cache(); +static int found_pcb; +#ifdef NEWVM +static CORE_ADDR curpcb; +static CORE_ADDR kstack; +#endif + +static void setregmap(); + +extern int errno; + +/* + * This function simply calls ptrace with the given arguments. It exists so + * that all calls to ptrace are isolated in this machine-dependent file. + */ +int +call_ptrace(request, pid, arg3, arg4) + int request; + pid_t pid; + caddr_t arg3; + int arg4; +{ + return(ptrace(request, pid, arg3, arg4)); +} + +kill_inferior() +{ + if (remote_debugging) { +#ifdef KERNELDEBUG + if (kernel_debugging) + /* + * It's a very, very bad idea to go away leaving + * breakpoints in a remote kernel or to leave it + * stopped at a breakpoint. + */ + clear_breakpoints(); +#endif + remote_close(0); + inferior_died(); + } else if (inferior_pid != 0) { + ptrace(PT_KILL, inferior_pid, 0, 0); + wait(0); + inferior_died(); + } +} + +/* + * This is used when GDB is exiting. It gives less chance of error. + */ +kill_inferior_fast() +{ + if (remote_debugging) { +#ifdef KERNELDEBUG + if (kernel_debugging) + clear_breakpoints(); +#endif + remote_close(0); + return; + } + if (inferior_pid == 0) + return; + + ptrace(PT_KILL, inferior_pid, 0, 0); + wait(0); +} + +/* + * Resume execution of the inferior process. If STEP is nonzero, single-step + * it. If SIGNAL is nonzero, give it that signal. + */ +void +resume(step, signal) + int step; + int signal; +{ + errno = 0; + if (remote_debugging) + remote_resume(step, signal); + else { + ptrace(step ? PT_STEP : PT_CONTINUE, inferior_pid, + PT_ADDR_ANY, signal); + if (errno) + perror_with_name("ptrace"); + } +} + +#ifdef ATTACH_DETACH +extern int attach_flag; + +/* + * Start debugging the process whose number is PID. + */ +attach(pid) + int pid; +{ + errno = 0; + ptrace(PT_ATTACH, pid, 0, 0); + if (errno) + perror_with_name("ptrace"); + attach_flag = 1; + return pid; +} + +/* + * Stop debugging the process whose number is PID and continue it + * with signal number SIGNAL. SIGNAL = 0 means just continue it. + */ +void +detach(signal) + int signal; +{ + errno = 0; + ptrace(PT_DETACH, inferior_pid, PT_ADDR_ANY, signal); + if (errno) + perror_with_name("ptrace"); + attach_flag = 0; +} +#endif /* ATTACH_DETACH */ + +static unsigned int +get_register_offset() +{ + unsigned int offset; + struct user u; /* XXX */ + unsigned int flags = (char *) &u.u_pcb.pcb_flags - (char *) &u; + + setregmap(ptrace(PT_READ_U, inferior_pid, (caddr_t)flags, 0)); + +#ifdef NEWVM + offset = (char *) &u.u_kproc.kp_proc.p_regs - (char *) &u; + offset = ptrace(PT_READ_U, inferior_pid, (caddr_t)offset, 0) - + USRSTACK; +#else + offset = (char *) &u.u_ar0 - (char *) &u; + offset = ptrace(PT_READ_U, inferior_pid, (caddr_t)offset, 0) - + KERNEL_U_ADDR; +#endif + + return offset; +} + +void +fetch_inferior_registers() +{ + register int regno; + register unsigned int regaddr; + char buf[MAX_REGISTER_RAW_SIZE]; + register int i; + unsigned int offset; + + if (remote_debugging) { + extern char registers[]; + + remote_fetch_registers(registers); + return; + } + + offset = get_register_offset(); + + for (regno = 0; regno < NUM_REGS; regno++) { + regaddr = register_addr(regno, offset); + for (i = 0; i < REGISTER_RAW_SIZE(regno); i += sizeof(int)) { + *(int *)&buf[i] = ptrace(PT_READ_U, inferior_pid, + (caddr_t)regaddr, 0); + regaddr += sizeof(int); + } + supply_register(regno, buf); + } +} + +/* + * Store our register values back into the inferior. If REGNO is -1, do this + * for all registers. Otherwise, REGNO specifies which register (so we can + * save time). + */ +store_inferior_registers(regno) + int regno; +{ + register unsigned int regaddr; + char buf[80]; + extern char registers[]; + register int i; + unsigned int offset; + + if (remote_debugging) { + extern char registers[]; + + remote_store_registers(registers); + return; + } + + offset = get_register_offset(); + + if (regno >= 0) { + regaddr = register_addr(regno, offset); + for (i = 0; i < REGISTER_RAW_SIZE(regno); i += sizeof(int)) { + errno = 0; + ptrace(PT_WRITE_U, inferior_pid, (caddr_t)regaddr, + *(int *) ®isters[REGISTER_BYTE(regno) + i]); + if (errno != 0) { + sprintf(buf, "writing register number %d(%d)", + regno, i); + perror_with_name(buf); + } + regaddr += sizeof(int); + } + } else + for (regno = 0; regno < NUM_REGS; regno++) { + regaddr = register_addr(regno, offset); + for (i = 0; i < REGISTER_RAW_SIZE(regno); + i += sizeof(int)) { + errno = 0; + ptrace(PT_WRITE_U, inferior_pid, + (caddr_t)regaddr, + *(int *) ®isters[REGISTER_BYTE(regno) + i]); + if (errno != 0) { + sprintf(buf, + "writing register number %d(%d)", + regno, i); + perror_with_name(buf); + } + regaddr += sizeof(int); + } + } +} + +/* + * Copy LEN bytes from inferior's memory starting at MEMADDR to debugger + * memory starting at MYADDR. On failure (cannot read from inferior, usually + * because address is out of bounds) returns the value of errno. + */ +int +read_inferior_memory(memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & -sizeof(int); + /* Round ending address up; get number of longwords that makes. */ + register int count = (((memaddr + len) - addr) + sizeof(int) - 1) / + sizeof(int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca(count * sizeof(int)); + extern int errno; + + if (remote_debugging) + return (remote_read_inferior_memory(memaddr, myaddr, len)); + + /* Read all the longwords */ + errno = 0; + for (i = 0; i < count && errno == 0; i++, addr += sizeof(int)) + buffer[i] = ptrace(PT_READ_I, inferior_pid, (caddr_t)addr, 0); + + /* Copy appropriate bytes out of the buffer. */ + bcopy((char *) buffer + (memaddr & (sizeof(int) - 1)), myaddr, len); + return(errno); +} + +/* + * Copy LEN bytes of data from debugger memory at MYADDR to inferior's memory + * at MEMADDR. On failure (cannot write the inferior) returns the value of + * errno. + */ + +int +write_inferior_memory(memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & -sizeof(int); + /* Round ending address up; get number of longwords that makes. */ + register int count = (((memaddr + len) - addr) + sizeof(int) - 1) / + sizeof(int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca(count * sizeof(int)); + extern int errno; + + /* + * Fill start and end extra bytes of buffer with existing memory + * data. + */ + if (remote_debugging) + return (remote_write_inferior_memory(memaddr, myaddr, len)); + + /* + * Fill start and end extra bytes of buffer with existing memory + * data. + */ + buffer[0] = ptrace(PT_READ_I, inferior_pid, (caddr_t)addr, 0); + + if (count > 1) + buffer[count - 1] = ptrace(PT_READ_I, inferior_pid, + (caddr_t)addr + (count - 1) * sizeof(int), 0); + + /* Copy data to be written over corresponding part of buffer */ + + bcopy(myaddr, (char *) buffer + (memaddr & (sizeof(int) - 1)), len); + + /* Write the entire buffer. */ + + errno = 0; + for (i = 0; i < count && errno == 0; i++, addr += sizeof(int)) + ptrace(PT_WRITE_I, inferior_pid, (caddr_t)addr, buffer[i]); + + return(errno); +} + + +/* + * Work with core dump and executable files, for GDB. + * This code would be in core.c if it weren't machine-dependent. + */ + +#ifndef N_TXTADDR +#define N_TXTADDR(hdr) 0 +#endif /* no N_TXTADDR */ + +#ifndef N_DATADDR +#define N_DATADDR(hdr) hdr.a_text +#endif /* no N_DATADDR */ + +/* + * Make COFF and non-COFF names for things a little more compatible to reduce + * conditionals later. + */ + +#ifndef AOUTHDR +#define AOUTHDR struct exec +#endif + +extern char *sys_siglist[]; + + +/* Hook for `exec_file_command' command to call. */ + +extern void (*exec_file_display_hook) (); + +/* File names of core file and executable file. */ + +extern char *corefile; +extern char *execfile; + +/* Descriptors on which core file and executable file are open. + Note that the execchan is closed when an inferior is created + and reopened if the inferior dies or is killed. */ + +extern int corechan; +extern int execchan; + +/* Last modification time of executable file. + Also used in source.c to compare against mtime of a source file. */ + +extern int exec_mtime; + +/* Virtual addresses of bounds of the two areas of memory in the core file. */ + +extern CORE_ADDR data_start; +extern CORE_ADDR data_end; +extern CORE_ADDR stack_start; +extern CORE_ADDR stack_end; + +/* Virtual addresses of bounds of two areas of memory in the exec file. + Note that the data area in the exec file is used only when there is no core file. */ + +extern CORE_ADDR text_start; +extern CORE_ADDR text_end; + +extern CORE_ADDR exec_data_start; +extern CORE_ADDR exec_data_end; + +/* Address in executable file of start of text area data. */ + +extern int text_offset; + +/* Address in executable file of start of data area data. */ + +extern int exec_data_offset; + +/* Address in core file of start of data area data. */ + +extern int data_offset; + +/* Address in core file of start of stack area data. */ + +extern int stack_offset; + +/* a.out header saved in core file. */ + +extern AOUTHDR core_aouthdr; + +/* a.out header of exec file. */ + +extern AOUTHDR exec_aouthdr; + +extern void validate_files (); + +extern int (*core_file_hook)(); + +#ifdef KERNELDEBUG +/* + * Kernel debugging routines. + */ + +#define IOTOP 0x100000 /* XXX should get this from include file */ +#define IOBASE 0xa0000 /* XXX should get this from include file */ + +static CORE_ADDR file_offset; +static CORE_ADDR lowram; +static CORE_ADDR sbr; +static CORE_ADDR slr; +static struct pcb pcb; + +static CORE_ADDR +ksym_lookup(name) + char *name; +{ + struct symbol *sym; + int i; + + if ((i = lookup_misc_func(name)) < 0) + error("kernel symbol `%s' not found.", name); + + return (misc_function_vector[i].address); +} + +/* + * return true if 'len' bytes starting at 'addr' can be read out as + * longwords and/or locally cached (this is mostly for memory mapped + * i/o register access when debugging remote kernels). + * + * XXX the HP code does this differently with NEWVM + */ +static int +ok_to_cache(addr, len) +{ + static CORE_ADDR atdevbase; + + if (! atdevbase) + atdevbase = ksym_lookup("atdevbase"); + + if (addr >= atdevbase && addr < atdevbase + (IOTOP - IOBASE)) + return (0); + + return (1); +} + +static +physrd(addr, dat, len) + u_int addr; + char *dat; +{ + if (lseek(corechan, addr - file_offset, L_SET) == -1) + return (-1); + if (read(corechan, dat, len) != len) + return (-1); + + return (0); +} + +/* + * When looking at kernel data space through /dev/mem or with a core file, do + * virtual memory mapping. + */ +#ifdef NEWVM +static CORE_ADDR +vtophys(addr) + CORE_ADDR addr; +{ + CORE_ADDR v; + struct pte pte; + static CORE_ADDR PTD = -1; + CORE_ADDR current_ptd; + + /* + * If we're looking at the kernel stack, + * munge the address to refer to the user space mapping instead; + * that way we get the requested process's kstack, not the running one. + */ + if (addr >= kstack && addr < kstack + ctob(UPAGES)) + addr = (addr - kstack) + curpcb; + + /* + * We may no longer have a linear system page table... + * + * Here's the scoop. IdlePTD contains the physical address + * of a page table directory that always maps the kernel. + * IdlePTD is in memory that is mapped 1-to-1, so we can + * find it easily given its 'virtual' address from ksym_lookup(). + * For hysterical reasons, the value of IdlePTD is stored in sbr. + * + * To look up a kernel address, we first convert it to a 1st-level + * address and look it up in IdlePTD. This gives us the physical + * address of a page table page; we extract the 2nd-level part of + * VA and read the 2nd-level pte. Finally, we add the offset part + * of the VA into the physical address from the pte and return it. + * + * User addresses are a little more complicated. If we don't have + * a current PCB from read_pcb(), we use PTD, which is the (fixed) + * virtual address of the current ptd. Since it's NOT in 1-to-1 + * kernel space, we must look it up using IdlePTD. If we do have + * a pcb, we get the ptd from pcb_ptd. + */ + + if (INKERNEL(addr)) + current_ptd = sbr; + else if (found_pcb == 0) { + if (PTD == -1) + PTD = vtophys(ksym_lookup("PTD")); + current_ptd = PTD; + } else + current_ptd = pcb.pcb_ptd; + + /* + * Read the first-level page table (ptd). + */ + v = current_ptd + ((unsigned)addr >> PD_SHIFT) * sizeof pte; + if (physrd(v, (char *)&pte, sizeof pte) || pte.pg_v == 0) + return (~0); + + /* + * Read the second-level page table. + */ + v = i386_ptob(pte.pg_pfnum) + ((addr&PT_MASK) >> PG_SHIFT) * sizeof pte; + if (physrd(v, (char *) &pte, sizeof(pte)) || pte.pg_v == 0) + return (~0); + + addr = i386_ptob(pte.pg_pfnum) + (addr & PGOFSET); +#if 0 + printf("vtophys(%x) -> %x\n", oldaddr, addr); +#endif + return (addr); +} +#else +static CORE_ADDR +vtophys(addr) + CORE_ADDR addr; +{ + CORE_ADDR v; + struct pte pte; + CORE_ADDR oldaddr = addr; + + if (found_pcb == 0 && INUPAGE(addr)) { + static CORE_ADDR pSwtchmap; + + if (pSwtchmap == 0) + pSwtchmap = vtophys(ksym_lookup("Swtchmap")); + addr = pSwtchmap; + } else if (INKERNEL(addr)) { + /* + * In system space get system pte. If valid or reclaimable + * then physical address is combination of its page number + * and the page offset of the original address. + */ + addr = smxtob(btop(addr - KERNOFF)) - KERNOFF; + } else { + v = btop(addr); + if (v < pcb.pcb_p0lr) + addr = (CORE_ADDR) pcb.pcb_p0br + + v * sizeof (struct pte); + else if (v >= pcb.pcb_p1lr && v < P1PAGES) + addr = (CORE_ADDR) pcb.pcb_p0br + + ((pcb.pcb_szpt * NPTEPG - HIGHPAGES) - + (BTOPUSRSTACK - v)) * sizeof (struct pte); + else + return (~0); + + /* + * For p0/p1 address, user-level page table should be in + * kernel vm. Do second-level indirect by recursing. + */ + if (!INKERNEL(addr)) + return (~0); + + addr = vtophys(addr); + } + /* + * Addr is now address of the pte of the page we are interested in; + * get the pte and paste up the physical address. + */ + if (physrd(addr, (char *) &pte, sizeof(pte))) + return (~0); + + if (pte.pg_v == 0 && (pte.pg_fod || pte.pg_pfnum == 0)) + return (~0); + + addr = (CORE_ADDR)ptob(pte.pg_pfnum) + (oldaddr & PGOFSET); +#if 0 + printf("vtophys(%x) -> %x\n", oldaddr, addr); +#endif + return (addr); +} + +#endif + +static +kvread(addr) + CORE_ADDR addr; +{ + CORE_ADDR paddr = vtophys(addr); + + if (paddr != ~0) + if (physrd(paddr, (char *)&addr, sizeof(addr)) == 0); + return (addr); + + return (~0); +} + +static void +read_pcb(uaddr) + u_int uaddr; +{ + int i; + int *pcb_regs = (int *)&pcb; + +#ifdef NEWVM + if (physrd(uaddr, (char *)&pcb, sizeof pcb)) + error("cannot read pcb at %x\n", uaddr); + printf("current pcb at %x\n", uaddr); +#else + if (physrd(uaddr, (char *)&pcb, sizeof pcb)) + error("cannot read pcb at %x\n", uaddr); + printf("p0br %x p0lr %x p1br %x p1lr %x\n", + pcb.pcb_p0br, pcb.pcb_p0lr, pcb.pcb_p1br, pcb.pcb_p1lr); +#endif + + /* + * get the register values out of the sys pcb and + * store them where `read_register' will find them. + */ + for (i = 0; i < 8; ++i) + supply_register(i, &pcb_regs[i+10]); + supply_register(8, &pcb_regs[8]); /* eip */ + supply_register(9, &pcb_regs[9]); /* eflags */ + for (i = 10; i < 13; ++i) /* cs, ss, ds */ + supply_register(i, &pcb_regs[i+9]); + supply_register(13, &pcb_regs[18]); /* es */ + for (i = 14; i < 16; ++i) /* fs, gs */ + supply_register(i, &pcb_regs[i+8]); + + /* XXX 80387 registers? */ +} + +static void +setup_kernel_debugging() +{ + struct stat stb; + int devmem = 0; + CORE_ADDR addr; + + fstat(corechan, &stb); + if ((stb.st_mode & S_IFMT) == S_IFCHR && stb.st_rdev == makedev(2, 0)) + devmem = 1; + +#ifdef NEWVM + physrd(ksym_lookup("IdlePTD") - KERNOFF, &sbr, sizeof sbr); + slr = 2 * NPTEPG; /* XXX temporary */ + printf("IdlePTD %x\n", sbr); + curpcb = ksym_lookup("curpcb") - KERNOFF; + physrd(curpcb, &curpcb, sizeof curpcb); + kstack = ksym_lookup("kstack"); +#else + sbr = ksym_lookup("Sysmap"); + slr = ksym_lookup("Syssize"); + printf("sbr %x slr %x\n", sbr, slr); +#endif + + /* + * pcb where "panic" saved registers in first thing in current + * u area. + */ +#ifndef NEWVM + read_pcb(vtophys(ksym_lookup("u"))); +#endif + found_pcb = 1; + if (!devmem) { + /* find stack frame */ + CORE_ADDR panicstr; + char buf[256]; + register char *cp; + + panicstr = kvread(ksym_lookup("panicstr")); + if (panicstr == ~0) + return; + (void) kernel_core_file_hook(panicstr, buf, sizeof(buf)); + for (cp = buf; cp < &buf[sizeof(buf)] && *cp; cp++) + if (!isascii(*cp) || (!isprint(*cp) && !isspace(*cp))) + *cp = '?'; + if (*cp) + *cp = '\0'; + printf("panic: %s\n", buf); + read_pcb(ksym_lookup("dumppcb") - KERNOFF); + } +#ifdef NEWVM + else + read_pcb(vtophys(kstack)); +#endif + + stack_start = USRSTACK; + stack_end = USRSTACK + ctob(UPAGES); +} + +set_paddr_command(arg) + char *arg; +{ + u_int uaddr; + + if (!arg) + error_no_arg("ps-style address for new current process"); + if (!kernel_debugging) + error("not debugging kernel"); + uaddr = (u_int) parse_and_eval_address(arg); +#ifndef NEWVM + read_pcb(ctob(uaddr)); +#else + /* p_addr is now a pcb virtual address */ + read_pcb(vtophys(uaddr)); + curpcb = uaddr; +#endif + + flush_cached_frames(); + set_current_frame(create_new_frame(read_register(FP_REGNUM), read_pc())); + select_frame(get_current_frame(), 0); +} + +/* + * read len bytes from kernel virtual address 'addr' into local + * buffer 'buf'. Return 0 if read ok, 1 otherwise. On read + * errors, portion of buffer not read is zeroed. + */ +kernel_core_file_hook(addr, buf, len) + CORE_ADDR addr; + char *buf; + int len; +{ + int i; + CORE_ADDR paddr; + + while (len > 0) { + paddr = vtophys(addr); + if (paddr == ~0) { + bzero(buf, len); + return (1); + } + /* we can't read across a page boundary */ + i = min(len, NBPG - (addr & PGOFSET)); + if (physrd(paddr, buf, i)) { + bzero(buf, len); + return (1); + } + buf += i; + addr += i; + len -= i; + } + return (0); +} +#endif + +core_file_command(filename, from_tty) + char *filename; + int from_tty; +{ + int val; + extern char registers[]; +#ifdef KERNELDEBUG + struct stat stb; +#endif + + /* + * Discard all vestiges of any previous core file and mark data and + * stack spaces as empty. + */ + if (corefile) + free(corefile); + corefile = 0; + core_file_hook = 0; + + if (corechan >= 0) + close(corechan); + corechan = -1; + + /* Now, if a new core file was specified, open it and digest it. */ + + if (filename == 0) { + if (from_tty) + printf("No core file now.\n"); + return; + } + filename = tilde_expand(filename); + make_cleanup(free, filename); + if (have_inferior_p()) + error("To look at a core file, you must kill the inferior with \"kill\"."); + corechan = open(filename, O_RDONLY, 0); + if (corechan < 0) + perror_with_name(filename); + +#ifdef KERNELDEBUG + fstat(corechan, &stb); + + if (kernel_debugging) { + setup_kernel_debugging(); + core_file_hook = kernel_core_file_hook; + } else if ((stb.st_mode & S_IFMT) == S_IFCHR && + stb.st_rdev == makedev(2, 1)) { + /* looking at /dev/kmem */ + data_offset = data_start = KERNOFF; + data_end = ~0; /* XXX */ + stack_end = stack_start = data_end; + } else +#endif + { + /* + * 4.2-style core dump file. + */ + struct user u; + unsigned int reg_offset; + + val = myread(corechan, &u, sizeof u); + if (val < 0) + perror_with_name("Not a core file: reading upage"); + if (val != sizeof u) + error("Not a core file: could only read %d bytes", val); + + /* + * We are depending on exec_file_command having been + * called previously to set exec_data_start. Since + * the executable and the core file share the same + * text segment, the address of the data segment will + * be the same in both. + */ + data_start = exec_data_start; + +#ifndef NEWVM + data_end = data_start + NBPG * u.u_dsize; + stack_start = stack_end - NBPG * u.u_ssize; + data_offset = NBPG * UPAGES; + stack_offset = NBPG * (UPAGES + u.u_dsize); + + /* + * Some machines put an absolute address in here and + * some put the offset in the upage of the regs. + */ + reg_offset = (int) u.u_ar0 - KERNEL_U_ADDR; +#else + data_end = data_start + + NBPG * u.u_kproc.kp_eproc.e_vm.vm_dsize; + stack_start = stack_end - + NBPG * u.u_kproc.kp_eproc.e_vm.vm_ssize; + data_offset = NBPG * UPAGES; + stack_offset = NBPG * + (UPAGES + u.u_kproc.kp_eproc.e_vm.vm_dsize); + + reg_offset = (int) u.u_kproc.kp_proc.p_regs - USRSTACK; +#endif + + setregmap(u.u_pcb.pcb_flags); + + /* + * I don't know where to find this info. So, for now, + * mark it as not available. + */ + /* N_SET_MAGIC (core_aouthdr, 0); */ + bzero ((char *) &core_aouthdr, sizeof core_aouthdr); + + /* + * Read the register values out of the core file and + * store them where `read_register' will find them. + */ + { + register int regno; + + for (regno = 0; regno < NUM_REGS; regno++) { + char buf[MAX_REGISTER_RAW_SIZE]; + + val = lseek(corechan, register_addr(regno, reg_offset), 0); + if (val < 0 + || (val = myread(corechan, buf, sizeof buf)) < 0) { + char *buffer = (char *) alloca(strlen(reg_names[regno]) + 30); + strcpy(buffer, "Reading register "); + strcat(buffer, reg_names[regno]); + perror_with_name(buffer); + } + supply_register(regno, buf); + } + } + } +#endif + if (filename[0] == '/') + corefile = savestring(filename, strlen(filename)); + else + corefile = concat(current_directory, "/", filename); + + set_current_frame(create_new_frame(read_register(FP_REGNUM), + read_pc())); + select_frame(get_current_frame(), 0); + validate_files(); +} + +exec_file_command(filename, from_tty) + char *filename; + int from_tty; +{ + int val; + + /* + * Eliminate all traces of old exec file. Mark text segment as empty. + */ + + if (execfile) + free(execfile); + execfile = 0; + data_start = 0; + data_end = 0; + stack_start = 0; + stack_end = 0; + text_start = 0; + text_end = 0; + exec_data_start = 0; + exec_data_end = 0; + if (execchan >= 0) + close(execchan); + execchan = -1; + + /* Now open and digest the file the user requested, if any. */ + + if (filename) { + filename = tilde_expand(filename); + make_cleanup(free, filename); + + execchan = openp(getenv("PATH"), 1, filename, O_RDONLY, 0, + &execfile); + if (execchan < 0) + perror_with_name(filename); + + { + struct stat st_exec; + +#ifdef HEADER_SEEK_FD + HEADER_SEEK_FD(execchan); +#endif + + val = myread(execchan, &exec_aouthdr, sizeof(AOUTHDR)); + + if (val < 0) + perror_with_name(filename); + +#ifdef KERNELDEBUG + if (kernel_debugging) { + /* Gross and disgusting XXX */ + text_start = KERNTEXT_BASE; + exec_data_start = KERNTEXT_BASE + + (exec_aouthdr.a_text + 4095) & ~ 4095; + } else { +#endif + text_start = N_TXTADDR(exec_aouthdr); + exec_data_start = N_DATADDR(exec_aouthdr); +#ifdef KERNELDEBUG + } +#endif + + text_offset = N_TXTOFF(exec_aouthdr); + exec_data_offset = N_TXTOFF(exec_aouthdr) + exec_aouthdr.a_text; + + text_end = text_start + exec_aouthdr.a_text; + exec_data_end = exec_data_start + exec_aouthdr.a_data; + + fstat(execchan, &st_exec); + exec_mtime = st_exec.st_mtime; + } + + validate_files(); + } else if (from_tty) + printf("No exec file now.\n"); + + /* Tell display code (if any) about the changed file name. */ + if (exec_file_display_hook) + (*exec_file_display_hook) (filename); +} + +int dummy_code[] = { + 0xb8909090, /* nop; nop; nop; movl $0x32323232,%eax */ + 0x32323232, +#define DUMMY_CALL_INDEX 1 + 0x90ccd0ff, /* call %eax; int3; nop */ +}; + +/* + * Build `dummy' call instructions on inferior's stack to cause + * it to call a subroutine. + * + * N.B. - code in wait_for_inferior requires that sp < pc < fp when + * we take the trap 2 above so it will recognize that we stopped + * at a `dummy' call. So, after the call sp is *not* decremented + * to clean the arguments, code & other stuff we lay on the stack. + * Since the regs are restored to saved values at the breakpoint, + * sp will get reset correctly. Also, this restore means we don't + * have to construct frame linkage info to save pc & fp. The lack + * of frame linkage means we can't do a backtrace, etc., if the + * called function gets a fault or hits a breakpoint but code in + * run_stack_dummy makes this impossible anyway. + */ +CORE_ADDR +setup_dummy(sp, funaddr, nargs, args, struct_return_bytes, pushfn) + CORE_ADDR sp; + CORE_ADDR funaddr; + int nargs; + value *args; + int struct_return_bytes; + CORE_ADDR (*pushfn)(); +{ + int padding, i; + CORE_ADDR top = sp, struct_addr, pc; + + i = arg_stacklen(nargs, args) + struct_return_bytes + + sizeof(dummy_code); + if (i & 3) + padding = 4 - (i & 3); + else + padding = 0; + pc = sp - sizeof(dummy_code); + sp = pc - padding - struct_return_bytes; + struct_addr = sp; + while (--nargs >= 0) + sp = (*pushfn)(sp, *args++); + if (struct_return_bytes) + STORE_STRUCT_RETURN(struct_addr, sp); + write_register(SP_REGNUM, sp); + + dummy_code[DUMMY_CALL_INDEX] = (int)funaddr; + write_memory(pc, (char *)dummy_code, sizeof(dummy_code)); + + return pc; +} + +/* helper functions for m-i386.h */ + +/* stdio style buffering to minimize calls to ptrace */ +static CORE_ADDR codestream_next_addr; +static CORE_ADDR codestream_addr; +static unsigned char codestream_buf[sizeof (int)]; +static int codestream_off; +static int codestream_cnt; + +#define codestream_tell() (codestream_addr + codestream_off) +#define codestream_peek() (codestream_cnt == 0 ? \ + codestream_fill(1): codestream_buf[codestream_off]) +#define codestream_get() (codestream_cnt-- == 0 ? \ + codestream_fill(0) : codestream_buf[codestream_off++]) + +static unsigned char +codestream_fill (peek_flag) +{ + codestream_addr = codestream_next_addr; + codestream_next_addr += sizeof (int); + codestream_off = 0; + codestream_cnt = sizeof (int); + read_memory (codestream_addr, + (unsigned char *)codestream_buf, + sizeof (int)); + + if (peek_flag) + return (codestream_peek()); + else + return (codestream_get()); +} + +static void +codestream_seek (place) +{ + codestream_next_addr = place & -sizeof (int); + codestream_cnt = 0; + codestream_fill (1); + while (codestream_tell() != place) + codestream_get (); +} + +static void +codestream_read (buf, count) + unsigned char *buf; +{ + unsigned char *p; + int i; + p = buf; + for (i = 0; i < count; i++) + *p++ = codestream_get (); +} + +/* next instruction is a jump, move to target */ +static +i386_follow_jump () +{ + int long_delta; + short short_delta; + char byte_delta; + int data16; + int pos; + + pos = codestream_tell (); + + data16 = 0; + if (codestream_peek () == 0x66) + { + codestream_get (); + data16 = 1; + } + + switch (codestream_get ()) + { + case 0xe9: + /* relative jump: if data16 == 0, disp32, else disp16 */ + if (data16) + { + codestream_read ((unsigned char *)&short_delta, 2); + pos += short_delta + 3; /* include size of jmp inst */ + } + else + { + codestream_read ((unsigned char *)&long_delta, 4); + pos += long_delta + 5; + } + break; + case 0xeb: + /* relative jump, disp8 (ignore data16) */ + codestream_read ((unsigned char *)&byte_delta, 1); + pos += byte_delta + 2; + break; + } + codestream_seek (pos + data16); +} + +/* + * find & return amound a local space allocated, and advance codestream to + * first register push (if any) + * + * if entry sequence doesn't make sense, return -1, and leave + * codestream pointer random + */ +static long +i386_get_frame_setup (pc) +{ + unsigned char op; + + codestream_seek (pc); + + i386_follow_jump (); + + op = codestream_get (); + + if (op == 0x58) /* popl %eax */ + { + /* + * this function must start with + * + * popl %eax 0x58 + * xchgl %eax, (%esp) 0x87 0x04 0x24 + * or xchgl %eax, 0(%esp) 0x87 0x44 0x24 0x00 + * + * (the system 5 compiler puts out the second xchg + * inst, and the assembler doesn't try to optimize it, + * so the 'sib' form gets generated) + * + * this sequence is used to get the address of the return + * buffer for a function that returns a structure + */ + int pos; + unsigned char buf[4]; + static unsigned char proto1[3] = { 0x87,0x04,0x24 }; + static unsigned char proto2[4] = { 0x87,0x44,0x24,0x00 }; + pos = codestream_tell (); + codestream_read (buf, 4); + if (bcmp (buf, proto1, 3) == 0) + pos += 3; + else if (bcmp (buf, proto2, 4) == 0) + pos += 4; + + codestream_seek (pos); + op = codestream_get (); /* update next opcode */ + } + + if (op == 0x55) /* pushl %esp */ + { + /* check for movl %esp, %ebp - can be written two ways */ + switch (codestream_get ()) + { + case 0x8b: + if (codestream_get () != 0xec) + return (-1); + break; + case 0x89: + if (codestream_get () != 0xe5) + return (-1); + break; + default: + return (-1); + } + /* check for stack adjustment + * + * subl $XXX, %esp + * + * note: you can't subtract a 16 bit immediate + * from a 32 bit reg, so we don't have to worry + * about a data16 prefix + */ + op = codestream_peek (); + if (op == 0x83) + { + /* subl with 8 bit immed */ + codestream_get (); + if (codestream_get () != 0xec) + return (-1); + /* subl with signed byte immediate + * (though it wouldn't make sense to be negative) + */ + return (codestream_get()); + } + else if (op == 0x81) + { + /* subl with 32 bit immed */ + int locals; + codestream_get(); + if (codestream_get () != 0xec) + return (-1); + /* subl with 32 bit immediate */ + codestream_read ((unsigned char *)&locals, 4); + return (locals); + } + else + { + return (0); + } + } + else if (op == 0xc8) + { + /* enter instruction: arg is 16 bit unsigned immed */ + unsigned short slocals; + codestream_read ((unsigned char *)&slocals, 2); + codestream_get (); /* flush final byte of enter instruction */ + return (slocals); + } + return (-1); +} + +/* Return number of args passed to a frame. + Can return -1, meaning no way to tell. */ + +/* on the 386, the instruction following the call could be: + * popl %ecx - one arg + * addl $imm, %esp - imm/4 args; imm may be 8 or 32 bits + * anything else - zero args + */ + +int +i386_frame_num_args (fi) + struct frame_info fi; +{ + int retpc; + unsigned char op; + struct frame_info *pfi; + + pfi = get_prev_frame_info ((fi)); + if (pfi == 0) + { + /* Note: this can happen if we are looking at the frame for + main, because FRAME_CHAIN_VALID won't let us go into + start. If we have debugging symbols, that's not really + a big deal; it just means it will only show as many arguments + to main as are declared. */ + return -1; + } + else + { + retpc = pfi->pc; + op = read_memory_integer (retpc, 1); + if (op == 0x59) + /* pop %ecx */ + return 1; + else if (op == 0x83) + { + op = read_memory_integer (retpc+1, 1); + if (op == 0xc4) + /* addl $, %esp */ + return (read_memory_integer (retpc+2,1)&0xff)/4; + else + return 0; + } + else if (op == 0x81) + { /* add with 32 bit immediate */ + op = read_memory_integer (retpc+1, 1); + if (op == 0xc4) + /* addl $, %esp */ + return read_memory_integer (retpc+2, 4) / 4; + else + return 0; + } + else + { + return 0; + } + } +} + +/* + * parse the first few instructions of the function to see + * what registers were stored. + * + * We handle these cases: + * + * The startup sequence can be at the start of the function, + * or the function can start with a branch to startup code at the end. + * + * %ebp can be set up with either the 'enter' instruction, or + * 'pushl %ebp, movl %esp, %ebp' (enter is too slow to be useful, + * but was once used in the sys5 compiler) + * + * Local space is allocated just below the saved %ebp by either the + * 'enter' instruction, or by 'subl $, %esp'. 'enter' has + * a 16 bit unsigned argument for space to allocate, and the + * 'addl' instruction could have either a signed byte, or + * 32 bit immediate. + * + * Next, the registers used by this function are pushed. In + * the sys5 compiler they will always be in the order: %edi, %esi, %ebx + * (and sometimes a harmless bug causes it to also save but not restore %eax); + * however, the code below is willing to see the pushes in any order, + * and will handle up to 8 of them. + * + * If the setup sequence is at the end of the function, then the + * next instruction will be a branch back to the start. + */ + +i386_frame_find_saved_regs (fip, fsrp) + struct frame_info *fip; + struct frame_saved_regs *fsrp; +{ + unsigned long locals; + unsigned char *p; + unsigned char op; + CORE_ADDR dummy_bottom; + CORE_ADDR adr; + int i; + + bzero (fsrp, sizeof *fsrp); + +#if 0 + /* if frame is the end of a dummy, compute where the + * beginning would be + */ + dummy_bottom = fip->frame - 4 - NUM_REGS*4 - CALL_DUMMY_LENGTH; + + /* check if the PC is in the stack, in a dummy frame */ + if (dummy_bottom <= fip->pc && fip->pc <= fip->frame) + { + /* all regs were saved by push_call_dummy () */ + adr = fip->frame - 4; + for (i = 0; i < NUM_REGS; i++) + { + fsrp->regs[i] = adr; + adr -= 4; + } + return; + } +#endif + + locals = i386_get_frame_setup (get_pc_function_start (fip->pc)); + + if (locals >= 0) + { + adr = fip->frame - 4 - locals; + for (i = 0; i < 8; i++) + { + op = codestream_get (); + if (op < 0x50 || op > 0x57) + break; + fsrp->regs[op - 0x50] = adr; + adr -= 4; + } + } + + fsrp->regs[PC_REGNUM] = fip->frame + 4; + fsrp->regs[FP_REGNUM] = fip->frame; +} + +/* return pc of first real instruction */ +i386_skip_prologue (pc) +{ + unsigned char op; + int i; + + if (i386_get_frame_setup (pc) < 0) + return (pc); + + /* found valid frame setup - codestream now points to + * start of push instructions for saving registers + */ + + /* skip over register saves */ + for (i = 0; i < 8; i++) + { + op = codestream_peek (); + /* break if not pushl inst */ + if (op < 0x50 || op > 0x57) + break; + codestream_get (); + } + + i386_follow_jump (); + + return (codestream_tell ()); +} + +i386_pop_frame () +{ + FRAME frame = get_current_frame (); + CORE_ADDR fp; + int regnum; + struct frame_saved_regs fsr; + struct frame_info *fi; + + fi = get_frame_info (frame); + fp = fi->frame; + get_frame_saved_regs (fi, &fsr); + for (regnum = 0; regnum < NUM_REGS; regnum++) + { + CORE_ADDR adr; + adr = fsr.regs[regnum]; + if (adr) + write_register (regnum, read_memory_integer (adr, 4)); + } + write_register (FP_REGNUM, read_memory_integer (fp, 4)); + write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); + write_register (SP_REGNUM, fp + 8); + flush_cached_frames (); + set_current_frame ( create_new_frame (read_register (FP_REGNUM), + read_pc ())); +} + +/* this table must line up with REGISTER_NAMES in m-i386.h */ +/* symbols like 'EAX' come from */ +static int trapmap[] = +{ + tEAX, tECX, tEDX, tEBX, + tESP, tEBP, tESI, tEDI, + tEIP, tEFLAGS, tCS, tSS, + tDS, tES, tES, tES /* lies: no fs or gs */ +}; +static int syscallmap[] = +{ + sEAX, sECX, sEDX, sEBX, + sESP, sEBP, sESI, sEDI, + sEIP, sEFLAGS, sCS, sSS, + sCS, sCS, sCS, sCS /* lies: no ds, es, fs or gs */ +}; +static int *regmap; + +static void +setregmap(flags) + int flags; +{ +#ifdef FM_TRAP + regmap = flags & FM_TRAP ? trapmap: syscallmap; +#elif EX_TRAPSTK + regmap = flags & EX_TRAPSTK ? trapmap : syscallmap; +#else + regmap = trapmap; /* the lesser evil */ +#endif +} + +/* blockend is the value of u.u_ar0, and points to the + * place where GS is stored + */ +i386_register_u_addr (blockend, regnum) +{ +#if 0 + /* this will be needed if fp registers are reinstated */ + /* for now, you can look at them with 'info float' + * sys5 wont let you change them with ptrace anyway + */ + if (regnum >= FP0_REGNUM && regnum <= FP7_REGNUM) + { + int ubase, fpstate; + struct user u; + ubase = blockend + 4 * (SS + 1) - KSTKSZ; + fpstate = ubase + ((char *)&u.u_fpstate - (char *)&u); + return (fpstate + 0x1c + 10 * (regnum - FP0_REGNUM)); + } + else +#endif + return (blockend + 4 * regmap[regnum]); +} + +i387_to_double (from, to) + char *from; + char *to; +{ + long *lp; + /* push extended mode on 387 stack, then pop in double mode + * + * first, set exception masks so no error is generated - + * number will be rounded to inf or 0, if necessary + */ + asm ("pushl %eax"); /* grab a stack slot */ + asm ("fstcw (%esp)"); /* get 387 control word */ + asm ("movl (%esp),%eax"); /* save old value */ + asm ("orl $0x3f,%eax"); /* mask all exceptions */ + asm ("pushl %eax"); + asm ("fldcw (%esp)"); /* load new value into 387 */ + + asm ("movl 8(%ebp),%eax"); + asm ("fldt (%eax)"); /* push extended number on 387 stack */ + asm ("fwait"); + asm ("movl 12(%ebp),%eax"); + asm ("fstpl (%eax)"); /* pop double */ + asm ("fwait"); + + asm ("popl %eax"); /* flush modified control word */ + asm ("fnclex"); /* clear exceptions */ + asm ("fldcw (%esp)"); /* restore original control word */ + asm ("popl %eax"); /* flush saved copy */ +} + +double_to_i387 (from, to) + char *from; + char *to; +{ + /* push double mode on 387 stack, then pop in extended mode + * no errors are possible because every 64-bit pattern + * can be converted to an extended + */ + asm ("movl 8(%ebp),%eax"); + asm ("fldl (%eax)"); + asm ("fwait"); + asm ("movl 12(%ebp),%eax"); + asm ("fstpt (%eax)"); + asm ("fwait"); +} + +struct env387 +{ + unsigned short control; + unsigned short r0; + unsigned short status; + unsigned short r1; + unsigned short tag; + unsigned short r2; + unsigned long eip; + unsigned short code_seg; + unsigned short opcode; + unsigned long operand; + unsigned short operand_seg; + unsigned short r3; + unsigned char regs[8][10]; +}; + +static +print_387_control_word (control) +unsigned short control; +{ + printf ("control 0x%04x: ", control); + printf ("compute to "); + switch ((control >> 8) & 3) + { + case 0: printf ("24 bits; "); break; + case 1: printf ("(bad); "); break; + case 2: printf ("53 bits; "); break; + case 3: printf ("64 bits; "); break; + } + printf ("round "); + switch ((control >> 10) & 3) + { + case 0: printf ("NEAREST; "); break; + case 1: printf ("DOWN; "); break; + case 2: printf ("UP; "); break; + case 3: printf ("CHOP; "); break; + } + if (control & 0x3f) + { + printf ("mask:"); + if (control & 0x0001) printf (" INVALID"); + if (control & 0x0002) printf (" DENORM"); + if (control & 0x0004) printf (" DIVZ"); + if (control & 0x0008) printf (" OVERF"); + if (control & 0x0010) printf (" UNDERF"); + if (control & 0x0020) printf (" LOS"); + printf (";"); + } + printf ("\n"); + if (control & 0xe080) printf ("warning: reserved bits on 0x%x\n", + control & 0xe080); +} + +static +print_387_status_word (status) + unsigned short status; +{ + printf ("status 0x%04x: ", status); + if (status & 0xff) + { + printf ("exceptions:"); + if (status & 0x0001) printf (" INVALID"); + if (status & 0x0002) printf (" DENORM"); + if (status & 0x0004) printf (" DIVZ"); + if (status & 0x0008) printf (" OVERF"); + if (status & 0x0010) printf (" UNDERF"); + if (status & 0x0020) printf (" LOS"); + if (status & 0x0040) printf (" FPSTACK"); + printf ("; "); + } + printf ("flags: %d%d%d%d; ", + (status & 0x4000) != 0, + (status & 0x0400) != 0, + (status & 0x0200) != 0, + (status & 0x0100) != 0); + + printf ("top %d\n", (status >> 11) & 7); +} + +static +print_387_status (status, ep) + unsigned short status; + struct env387 *ep; +{ + int i; + int bothstatus; + int top; + int fpreg; + unsigned char *p; + + bothstatus = ((status != 0) && (ep->status != 0)); + if (status != 0) + { + if (bothstatus) + printf ("u: "); + print_387_status_word (status); + } + + if (ep->status != 0) + { + if (bothstatus) + printf ("e: "); + print_387_status_word (ep->status); + } + + print_387_control_word (ep->control); + printf ("last exception: "); + printf ("opcode 0x%x; ", ep->opcode); + printf ("pc 0x%x:0x%x; ", ep->code_seg, ep->eip); + printf ("operand 0x%x:0x%x\n", ep->operand_seg, ep->operand); + + top = (ep->status >> 11) & 7; + + printf ("regno tag msb lsb value\n"); + for (fpreg = 7; fpreg >= 0; fpreg--) + { + double val; + + printf ("%s %d: ", fpreg == top ? "=>" : " ", fpreg); + + switch ((ep->tag >> (fpreg * 2)) & 3) + { + case 0: printf ("valid "); break; + case 1: printf ("zero "); break; + case 2: printf ("trap "); break; + case 3: printf ("empty "); break; + } + for (i = 9; i >= 0; i--) + printf ("%02x", ep->regs[fpreg][i]); + + i387_to_double (ep->regs[fpreg], (char *)&val); + printf (" %g\n", val); + } + if (ep->r0) + printf ("warning: reserved0 is 0x%x\n", ep->r0); + if (ep->r1) + printf ("warning: reserved1 is 0x%x\n", ep->r1); + if (ep->r2) + printf ("warning: reserved2 is 0x%x\n", ep->r2); + if (ep->r3) + printf ("warning: reserved3 is 0x%x\n", ep->r3); +} + +#ifndef U_FPSTATE +#define U_FPSTATE(u) u.u_fpstate +#endif + +i386_float_info () +{ + struct user u; /* just for address computations */ + int i; +#ifndef __386BSD__ + /* fpstate defined in */ + struct fpstate *fpstatep; + char buf[sizeof (struct fpstate) + 2 * sizeof (int)]; + unsigned int uaddr; + char fpvalid; + unsigned int rounded_addr; + unsigned int rounded_size; + extern int corechan; + int skip; + + uaddr = (char *)&u.u_fpvalid - (char *)&u; + if (have_inferior_p()) + { + unsigned int data; + unsigned int mask; + + rounded_addr = uaddr & -sizeof (int); + data = ptrace (3, inferior_pid, rounded_addr, 0); + mask = 0xff << ((uaddr - rounded_addr) * 8); + + fpvalid = ((data & mask) != 0); + } + else + { + if (lseek (corechan, uaddr, 0) < 0) + perror ("seek on core file"); + if (myread (corechan, &fpvalid, 1) < 0) + perror ("read on core file"); + + } + + if (fpvalid == 0) + { + printf ("no floating point status saved\n"); + return; + } + + uaddr = (char *)&U_FPSTATE(u) - (char *)&u; + if (have_inferior_p ()) + { + int *ip; + + rounded_addr = uaddr & -sizeof (int); + rounded_size = (((uaddr + sizeof (struct fpstate)) - uaddr) + + sizeof (int) - 1) / sizeof (int); + skip = uaddr - rounded_addr; + + ip = (int *)buf; + for (i = 0; i < rounded_size; i++) + { + *ip++ = ptrace (3, inferior_pid, rounded_addr, 0); + rounded_addr += sizeof (int); + } + } + else + { + if (lseek (corechan, uaddr, 0) < 0) + perror_with_name ("seek on core file"); + if (myread (corechan, buf, sizeof (struct fpstate)) < 0) + perror_with_name ("read from core file"); + skip = 0; + } + + fpstatep = (struct fpstate *)(buf + skip); + print_387_status (fpstatep->status, (struct env387 *)fpstatep->state); +#endif +} + +void +_initialize_i386bsd_dep() +{ +#ifdef KERNELDEBUG + add_com ("process-address", class_obscure, set_paddr_command, + "The process identified by (ps-style) ADDR becomes the\n\ +\"current\" process context for kernel debugging."); + add_com_alias ("paddr", "process-address", class_obscure, 0); +#endif +} -- 2.20.1