Temporary build structure for GDB 5.0 so people can test the new version
before pulling the switch to making it the default version.
This commit is contained in:
parent
16004197c4
commit
3547b75e97
115
gnu/usr.bin/binutils/gdb5/Makefile
Normal file
115
gnu/usr.bin/binutils/gdb5/Makefile
Normal file
@ -0,0 +1,115 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.include "../Makefile.inc0"
|
||||
|
||||
.PATH: ${SRCDIR}/binutils
|
||||
|
||||
.if ${MACHINE_ARCH} == "i386"
|
||||
CFLAGS+= -Dprint_insn_i386=print_insn_i386_att
|
||||
.endif
|
||||
|
||||
PROG= gdb
|
||||
XSRCS= annotate.c ax-general.c ax-gdb.c bcache.c blockframe.c \
|
||||
breakpoint.c buildsym.c c-exp.y c-lang.c c-typeprint.c \
|
||||
c-valprint.c ch-exp.c ch-lang.c ch-typeprint.c ch-valprint.c \
|
||||
coffread.c command.c complaints.c copying.c core-regset.c \
|
||||
corefile.c corelow.c cp-valprint.c dcache.c dbxread.c \
|
||||
demangle.c dwarfread.c dwarf2read.c elfread.c environ.c eval.c \
|
||||
exec.c expprint.c f-exp.y f-lang.c f-typeprint.c f-valprint.c \
|
||||
findvar.c fork-child.c freebsd-uthread.c gdbarch.c gdbtypes.c \
|
||||
infcmd.c inflow.c infptrace.c infrun.c inftarg.c language.c \
|
||||
jv-exp.y jv-lang.c jv-valprint.c jv-typeprint.c nlmread.c \
|
||||
m2-lang.c m2-exp.y m2-typeprint.c m2-valprint.c main.c maint.c \
|
||||
mdebugread.c mem-break.c minsyms.c objfiles.c parse.c \
|
||||
printcmd.c remote.c remote-utils.c scm-exp.c scm-lang.c \
|
||||
scm-valprint.c solib.c source.c stabsread.c stack.c symfile.c \
|
||||
symmisc.c symtab.c target.c thread.c top.c tracepoint.c \
|
||||
typeprint.c utils.c valarith.c valops.c valprint.c values.c \
|
||||
version.c serial.c ser-unix.c ser-tcp.c
|
||||
SRCS= init.c ${XSRCS}
|
||||
SRCS+= wait.h
|
||||
|
||||
.if exists(${.CURDIR}/Makefile.${MACHINE_ARCH})
|
||||
.include "${.CURDIR}/Makefile.${MACHINE_ARCH}"
|
||||
.endif
|
||||
|
||||
#CFLAGS+= -I${.CURDIR}/${RELTOP}/libbinutils
|
||||
CFLAGS+= -I${.CURDIR}/${MACHINE_ARCH}
|
||||
CFLAGS+= -I${SRCDIR}/binutils
|
||||
CFLAGS+= -I${SRCDIR}/bfd
|
||||
CFLAGS+= -I${GDBDIR}/gdb
|
||||
CFLAGS+= -I${GDBDIR}/gdb/config
|
||||
DPADD= ${RELTOP}/libbfd/libbfd.a
|
||||
DPADD+= ${RELTOP}/libopcodes/libopcodes.a
|
||||
DPADD+= ${LIBREADLINE}
|
||||
DPADD+= ${LIBGNUREGEX}
|
||||
DPADD+= ${RELTOP}/libiberty/libiberty.a
|
||||
DPADD+= ${LIBTERMCAP}
|
||||
LDADD+= ${RELTOP}/libbfd/libbfd.a
|
||||
LDADD+= ${RELTOP}/libopcodes/libopcodes.a
|
||||
LDADD+= -lreadline
|
||||
LDADD+= -lgnuregex
|
||||
LDADD+= ${RELTOP}/libiberty/libiberty.a
|
||||
LDADD+= -ltermcap
|
||||
|
||||
GDBDIR= ${.CURDIR}/../../../../contrib/gdb.291
|
||||
.PATH: ${GDBDIR}/gdb
|
||||
.PATH: ${SRCDIR}/opcodes
|
||||
|
||||
CFLAGS+= -DFREEBSD_ELF
|
||||
|
||||
CFLAGS+= -I$(.CURDIR) -I${DESTDIR}/usr/include/readline
|
||||
# use phkmalloc
|
||||
CFLAGS+= -DNO_MMALLOC
|
||||
# uncomment the next line if you want to debug gdb
|
||||
#CFLAGS+= -g
|
||||
YFLAGS=
|
||||
|
||||
CLEANFILES= init.c init.c-tmp wait.h
|
||||
|
||||
# We do this by grepping through sources. If that turns out to be too slow,
|
||||
# maybe we could just require every .o file to have an initialization routine
|
||||
# of a given name (remote-udi.o -> _initialize_remote_udi, etc.).
|
||||
#
|
||||
# Formatting conventions: The name of the _initialize_* routines must start
|
||||
# in column zero, and must not be inside #if.
|
||||
#
|
||||
# Note that the set of files with init functions might change, or the names
|
||||
# of the functions might change, so this files needs to depend on all the
|
||||
# object files that will be linked into gdb.
|
||||
|
||||
init.c: ${XSRCS}
|
||||
@${ECHO} Making ${.TARGET}
|
||||
@rm -f init.c-tmp
|
||||
@echo '/* Do not modify this file. */' >init.c-tmp
|
||||
@echo '/* It is created automatically by the Makefile. */'>>init.c-tmp
|
||||
@echo 'void initialize_all_files () {' >>init.c-tmp
|
||||
@for i in ${.ALLSRC} ; do \
|
||||
filename=`echo $$i | sed \
|
||||
-e '/^Onindy.c/d' \
|
||||
-e '/^nindy.c/d' \
|
||||
-e '/ttyflush.c/d' \
|
||||
-e '/xdr_ld.c/d' \
|
||||
-e '/xdr_ptrace.c/d' \
|
||||
-e '/xdr_rdb.c/d' \
|
||||
-e '/udr.c/d' \
|
||||
-e '/udip2soc.c/d' \
|
||||
-e '/udi2go32.c/d' \
|
||||
-e '/version.c/d' \
|
||||
-e '/^[a-z0-9A-Z_]*_[SU].c/d' \
|
||||
-e '/[a-z0-9A-Z_]*-exp.tab.c/d'` ; \
|
||||
case $$filename in \
|
||||
"") ;; \
|
||||
*) sed <$$filename >>init.c-tmp -n \
|
||||
-e '/^_initialize_[a-z_0-9A-Z]* *(/s/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (); \1 ();}/p' ; ;; \
|
||||
esac ; \
|
||||
done
|
||||
@echo '}' >>init.c-tmp
|
||||
@mv init.c-tmp ${.TARGET}
|
||||
|
||||
.PRECIOUS: init.c
|
||||
|
||||
wait.h:
|
||||
ln -sf ${.CURDIR}/../../../../sys/sys/wait.h ${.TARGET}
|
||||
|
||||
.include <bsd.prog.mk>
|
8
gnu/usr.bin/binutils/gdb5/Makefile.alpha
Normal file
8
gnu/usr.bin/binutils/gdb5/Makefile.alpha
Normal file
@ -0,0 +1,8 @@
|
||||
#
|
||||
# $FreeBSD$
|
||||
#
|
||||
|
||||
XSRCS+= freebsd-nat.c alpha-tdep.c kvm-fbsd.c
|
||||
LDADD+= -lkvm
|
||||
|
||||
.PATH: ${.CURDIR}/alpha
|
7
gnu/usr.bin/binutils/gdb5/Makefile.i386
Normal file
7
gnu/usr.bin/binutils/gdb5/Makefile.i386
Normal file
@ -0,0 +1,7 @@
|
||||
#
|
||||
# $FreeBSD$
|
||||
#
|
||||
|
||||
XSRCS+= freebsd-nat.c i386-tdep.c i387-tdep.c kvm-fbsd.c
|
||||
|
||||
.PATH: ${.CURDIR}/i386
|
8
gnu/usr.bin/binutils/gdb5/Makefile.ia64
Normal file
8
gnu/usr.bin/binutils/gdb5/Makefile.ia64
Normal file
@ -0,0 +1,8 @@
|
||||
#
|
||||
# $FreeBSD$
|
||||
#
|
||||
|
||||
XSRCS+= freebsd-nat.c ia64-tdep.c kvm-fbsd.c
|
||||
LDADD+= -lkvm
|
||||
|
||||
.PATH: ${.CURDIR}/ia64
|
175
gnu/usr.bin/binutils/gdb5/alpha/freebsd-nat.c
Normal file
175
gnu/usr.bin/binutils/gdb5/alpha/freebsd-nat.c
Normal file
@ -0,0 +1,175 @@
|
||||
/* Native-dependent code for BSD Unix running on i386's, for GDB.
|
||||
Copyright 1988, 1989, 1991, 1992, 1994, 1996 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* $FreeBSD$ */
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <machine/reg.h>
|
||||
#include <machine/frame.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/user.h>
|
||||
#include <string.h>
|
||||
#include "gdbcore.h"
|
||||
#include "value.h"
|
||||
#include "inferior.h"
|
||||
|
||||
#if defined(HAVE_GREGSET_T)
|
||||
#include <sys/procfs.h>
|
||||
#endif
|
||||
|
||||
int kernel_debugging = 0;
|
||||
|
||||
/* Size of elements in jmpbuf */
|
||||
|
||||
#define JB_ELEMENT_SIZE 8
|
||||
|
||||
/* The definition for JB_PC in machine/reg.h is wrong.
|
||||
And we can't get at the correct definition in setjmp.h as it is
|
||||
not always available (eg. if _POSIX_SOURCE is defined which is the
|
||||
default). As the defintion is unlikely to change (see comment
|
||||
in <setjmp.h>, define the correct value here. */
|
||||
|
||||
#undef JB_PC
|
||||
#define JB_PC 2
|
||||
|
||||
/* Figure out where the longjmp will land.
|
||||
We expect the first arg to be a pointer to the jmp_buf structure from which
|
||||
we extract the pc (JB_PC) that we will land at. The pc is copied into PC.
|
||||
This routine returns true on success. */
|
||||
|
||||
int
|
||||
get_longjmp_target (pc)
|
||||
CORE_ADDR *pc;
|
||||
{
|
||||
CORE_ADDR jb_addr;
|
||||
char raw_buffer[MAX_REGISTER_RAW_SIZE];
|
||||
|
||||
jb_addr = read_register(A0_REGNUM);
|
||||
|
||||
if (target_read_memory(jb_addr + JB_PC * JB_ELEMENT_SIZE, raw_buffer,
|
||||
sizeof(CORE_ADDR)))
|
||||
return 0;
|
||||
|
||||
*pc = extract_address (raw_buffer, sizeof(CORE_ADDR));
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
fetch_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
struct reg regs; /* ptrace order, not gcc/gdb order */
|
||||
struct fpreg fpregs;
|
||||
int r;
|
||||
|
||||
ptrace (PT_GETREGS, inferior_pid, (PTRACE_ARG3_TYPE) ®s, 0);
|
||||
ptrace (PT_GETFPREGS, inferior_pid, (PTRACE_ARG3_TYPE) &fpregs, 0);
|
||||
|
||||
for (r = 0; r < 31; r++)
|
||||
memcpy (®isters[REGISTER_BYTE (r)],
|
||||
®s.r_regs[r], sizeof(u_int64_t));
|
||||
for (r = 0; r < 32; r++)
|
||||
memcpy (®isters[REGISTER_BYTE (r + FP0_REGNUM)],
|
||||
&fpregs.fpr_regs[r], sizeof(u_int64_t));
|
||||
memcpy (®isters[REGISTER_BYTE (PC_REGNUM)],
|
||||
®s.r_regs[31], sizeof(u_int64_t));
|
||||
|
||||
memset (®isters[REGISTER_BYTE (ZERO_REGNUM)], 0, sizeof(u_int64_t));
|
||||
memset (®isters[REGISTER_BYTE (FP_REGNUM)], 0, sizeof(u_int64_t));
|
||||
|
||||
registers_fetched ();
|
||||
}
|
||||
|
||||
void
|
||||
store_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
struct reg regs; /* ptrace order, not gcc/gdb order */
|
||||
struct fpreg fpregs;
|
||||
int r;
|
||||
|
||||
for (r = 0; r < 31; r++)
|
||||
memcpy (®s.r_regs[r],
|
||||
®isters[REGISTER_BYTE (r)], sizeof(u_int64_t));
|
||||
for (r = 0; r < 32; r++)
|
||||
memcpy (&fpregs.fpr_regs[r],
|
||||
®isters[REGISTER_BYTE (r + FP0_REGNUM)], sizeof(u_int64_t));
|
||||
memcpy (®s.r_regs[31],
|
||||
®isters[REGISTER_BYTE (PC_REGNUM)], sizeof(u_int64_t));
|
||||
|
||||
ptrace (PT_SETREGS, inferior_pid, (PTRACE_ARG3_TYPE) ®s, 0);
|
||||
ptrace (PT_SETFPREGS, inferior_pid, (PTRACE_ARG3_TYPE) &fpregs, 0);
|
||||
}
|
||||
|
||||
#ifdef HAVE_GREGSET_T
|
||||
void
|
||||
supply_gregset (gp)
|
||||
gregset_t *gp;
|
||||
{
|
||||
int regno = 0;
|
||||
|
||||
/* These must be ordered the same as REGISTER_NAMES in
|
||||
config/alpha/tm-alpha.h. */
|
||||
for (regno = 0; regno < 31; regno++)
|
||||
supply_register (regno, (char *)&gp->r_regs[regno]);
|
||||
supply_register (PC_REGNUM, (char *)&gp->r_regs[regno]);
|
||||
}
|
||||
#endif /* HAVE_GREGSET_T */
|
||||
|
||||
#ifdef HAVE_FPREGSET_T
|
||||
void
|
||||
supply_fpregset (fp)
|
||||
fpregset_t *fp;
|
||||
{
|
||||
int regno = 0;
|
||||
|
||||
for (regno = 0; regno < 32; regno++)
|
||||
supply_register (regno + 32, (char *)&fp->fpr_regs[regno]);
|
||||
}
|
||||
#endif /* HAVE_FPREGSET_T */
|
||||
|
||||
/*
|
||||
* Get registers from a kernel crash dump or live kernel.
|
||||
* Called by kvm-fbsd.c:get_kcore_registers().
|
||||
*/
|
||||
fetch_kcore_registers (pcbp)
|
||||
struct pcb *pcbp;
|
||||
{
|
||||
|
||||
/* First clear out any garbage. */
|
||||
memset(registers, '\0', REGISTER_BYTES);
|
||||
|
||||
/* SP */
|
||||
*(long *) ®isters[REGISTER_BYTE (SP_REGNUM)] =
|
||||
pcbp->pcb_hw.apcb_ksp;
|
||||
|
||||
/* S0 through S6 */
|
||||
memcpy (®isters[REGISTER_BYTE (S0_REGNUM)],
|
||||
&pcbp->pcb_context[0], 7 * sizeof(long));
|
||||
|
||||
/* PC */
|
||||
*(long *) ®isters[REGISTER_BYTE (PC_REGNUM)] =
|
||||
pcbp->pcb_context[7];
|
||||
|
||||
registers_fetched ();
|
||||
}
|
||||
|
438
gnu/usr.bin/binutils/gdb5/alpha/kvm-fbsd.c
Normal file
438
gnu/usr.bin/binutils/gdb5/alpha/kvm-fbsd.c
Normal file
@ -0,0 +1,438 @@
|
||||
/* Kernel core dump functions below target vector, for GDB.
|
||||
Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995
|
||||
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* $FreeBSD$ */
|
||||
|
||||
/*
|
||||
* This works like "remote" but, you use it like this:
|
||||
* target kcore /dev/mem
|
||||
* or
|
||||
* target kcore /var/crash/host/core.0
|
||||
*
|
||||
* This way makes it easy to short-circut the whole bfd monster,
|
||||
* and direct the inferior stuff to our libkvm implementation.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/user.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <kvm.h>
|
||||
#include <paths.h>
|
||||
|
||||
#include "defs.h"
|
||||
#include "gdb_string.h"
|
||||
#include "frame.h" /* required by inferior.h */
|
||||
#include "inferior.h"
|
||||
#include "symtab.h"
|
||||
#include "command.h"
|
||||
#include "bfd.h"
|
||||
#include "target.h"
|
||||
#include "gdbcore.h"
|
||||
|
||||
static void
|
||||
kcore_files_info PARAMS ((struct target_ops *));
|
||||
|
||||
static void
|
||||
kcore_close PARAMS ((int));
|
||||
|
||||
static void
|
||||
get_kcore_registers PARAMS ((int));
|
||||
|
||||
static int
|
||||
xfer_mem PARAMS ((CORE_ADDR, char *, int, int, struct target_ops *));
|
||||
|
||||
static int
|
||||
xfer_umem PARAMS ((CORE_ADDR, char *, int, int));
|
||||
|
||||
static char *core_file;
|
||||
static kvm_t *core_kd;
|
||||
static struct pcb cur_pcb;
|
||||
|
||||
static struct target_ops kcore_ops;
|
||||
int kernel_writablecore;
|
||||
|
||||
/*
|
||||
* Read the "thing" at kernel address 'addr' into the space pointed to
|
||||
* by point. The length of the "thing" is determined by the type of p.
|
||||
* Result is non-zero if transfer fails.
|
||||
*/
|
||||
#define kvread(addr, p) \
|
||||
(target_read_memory((CORE_ADDR)(addr), (char *)(p), sizeof(*(p))))
|
||||
|
||||
|
||||
CORE_ADDR
|
||||
ksym_lookup(name)
|
||||
const char *name;
|
||||
{
|
||||
struct minimal_symbol *sym;
|
||||
|
||||
sym = lookup_minimal_symbol(name, NULL, NULL);
|
||||
if (sym == NULL)
|
||||
error("kernel symbol `%s' not found.", name);
|
||||
|
||||
return SYMBOL_VALUE_ADDRESS(sym);
|
||||
}
|
||||
|
||||
/*
|
||||
* Provide the address of an initial PCB to use.
|
||||
* If this is a crash dump, try for "dumppcb".
|
||||
* If no "dumppcb" or it's /dev/mem, use proc0.
|
||||
* Return the core address of the PCB we found.
|
||||
*/
|
||||
static CORE_ADDR
|
||||
initial_pcb()
|
||||
{
|
||||
struct minimal_symbol *sym;
|
||||
CORE_ADDR addr;
|
||||
void *val;
|
||||
|
||||
/* Make sure things are open... */
|
||||
if (!core_kd || !core_file)
|
||||
return (0);
|
||||
|
||||
/* If this is NOT /dev/mem try for dumppcb. */
|
||||
if (strncmp(core_file, _PATH_DEV, sizeof _PATH_DEV - 1)) {
|
||||
sym = lookup_minimal_symbol("dumppcb", NULL, NULL);
|
||||
if (sym != NULL) {
|
||||
addr = SYMBOL_VALUE_ADDRESS(sym);
|
||||
return (addr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* OK, just use proc0pcb. Note that curproc might
|
||||
* not exist, and if it does, it will point to gdb.
|
||||
* Therefore, just use proc0 and let the user set
|
||||
* some other context if they care about it.
|
||||
*/
|
||||
addr = ksym_lookup("proc0paddr");
|
||||
if (kvread(addr, &val)) {
|
||||
error("cannot read proc0paddr pointer at %x\n", addr);
|
||||
val = 0;
|
||||
}
|
||||
|
||||
return ((CORE_ADDR)val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the current context to that of the PCB struct
|
||||
* at the system address passed.
|
||||
*/
|
||||
static int
|
||||
set_context(addr)
|
||||
CORE_ADDR addr;
|
||||
{
|
||||
|
||||
if (kvread(addr, &cur_pcb))
|
||||
error("cannot read pcb at %#x", addr);
|
||||
|
||||
/* Fetch all registers from core file */
|
||||
target_fetch_registers (-1);
|
||||
|
||||
/* Now, set up the frame cache, and print the top of stack */
|
||||
flush_cached_frames();
|
||||
set_current_frame (create_new_frame (read_fp (), read_pc ()));
|
||||
select_frame (get_current_frame (), 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Discard all vestiges of any previous core file and mark data and stack
|
||||
spaces as empty. */
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
kcore_close (quitting)
|
||||
int quitting;
|
||||
{
|
||||
|
||||
inferior_pid = 0; /* Avoid confusion from thread stuff */
|
||||
|
||||
if (core_kd) {
|
||||
kvm_close(core_kd);
|
||||
free(core_file);
|
||||
core_file = NULL;
|
||||
core_kd = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* This routine opens and sets up the core file bfd. */
|
||||
|
||||
static void
|
||||
kcore_open (filename, from_tty)
|
||||
char *filename; /* the core file */
|
||||
int from_tty;
|
||||
{
|
||||
kvm_t *kd;
|
||||
const char *p;
|
||||
struct cleanup *old_chain;
|
||||
char buf[256], *cp;
|
||||
int ontop;
|
||||
CORE_ADDR addr;
|
||||
|
||||
target_preopen (from_tty);
|
||||
|
||||
/* The exec file is required for symbols. */
|
||||
if (exec_bfd == NULL)
|
||||
error("No kernel exec file specified");
|
||||
|
||||
if (core_kd) {
|
||||
error ("No core file specified."
|
||||
" (Use `detach' to stop debugging a core file.)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!filename) {
|
||||
error ("No core file specified.");
|
||||
return;
|
||||
}
|
||||
|
||||
filename = tilde_expand (filename);
|
||||
if (filename[0] != '/') {
|
||||
cp = concat (current_directory, "/", filename, NULL);
|
||||
free (filename);
|
||||
filename = cp;
|
||||
}
|
||||
|
||||
old_chain = make_cleanup (free, filename);
|
||||
|
||||
kd = kvm_open (bfd_get_filename(exec_bfd), filename, NULL,
|
||||
kernel_writablecore ? O_RDWR: O_RDONLY, 0);
|
||||
if (kd == NULL) {
|
||||
perror_with_name (filename);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Looks semi-reasonable. Toss the old core file and work on the new. */
|
||||
|
||||
discard_cleanups (old_chain); /* Don't free filename any more */
|
||||
core_file = filename;
|
||||
unpush_target (&kcore_ops);
|
||||
ontop = !push_target (&kcore_ops);
|
||||
|
||||
/* Note unpush_target (above) calls kcore_close. */
|
||||
core_kd = kd;
|
||||
|
||||
/* print out the panic string if there is one */
|
||||
if (kvread(ksym_lookup("panicstr"), &addr) == 0 &&
|
||||
addr != 0 &&
|
||||
target_read_memory(addr, buf, sizeof(buf)) == 0) {
|
||||
|
||||
for (cp = buf; cp < &buf[sizeof(buf)] && *cp; cp++)
|
||||
if (!isascii(*cp) || (!isprint(*cp) && !isspace(*cp)))
|
||||
*cp = '?';
|
||||
*cp = '\0';
|
||||
if (buf[0] != '\0')
|
||||
printf_filtered("panic: %s\n", buf);
|
||||
}
|
||||
|
||||
if (!ontop) {
|
||||
warning (
|
||||
"you won't be able to access this core file until you terminate\n\
|
||||
your %s; do ``info files''", target_longname);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now, set up process context, and print the top of stack */
|
||||
(void)set_context(initial_pcb());
|
||||
print_stack_frame (selected_frame, selected_frame_level, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
kcore_detach (args, from_tty)
|
||||
char *args;
|
||||
int from_tty;
|
||||
{
|
||||
if (args)
|
||||
error ("Too many arguments");
|
||||
unpush_target (&kcore_ops);
|
||||
reinit_frame_cache ();
|
||||
if (from_tty)
|
||||
printf_filtered ("No kernel core file now.\n");
|
||||
}
|
||||
|
||||
/* Get the registers out of a core file. This is the machine-
|
||||
independent part. Fetch_core_registers is the machine-dependent
|
||||
part, typically implemented in the xm-file for each architecture. */
|
||||
|
||||
/* We just get all the registers, so we don't use regno. */
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
get_kcore_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
|
||||
/*
|
||||
* XXX - Only read the pcb when set_context() is called.
|
||||
* When looking at a live kernel this may be a problem,
|
||||
* but the user can do another "proc" or "pcb" command to
|
||||
* grab a new copy of the pcb...
|
||||
*/
|
||||
|
||||
/*
|
||||
* Zero out register set then fill in the ones we know about.
|
||||
*/
|
||||
fetch_kcore_registers (&cur_pcb);
|
||||
}
|
||||
|
||||
static void
|
||||
kcore_files_info (t)
|
||||
struct target_ops *t;
|
||||
{
|
||||
printf_filtered ("\t`%s'\n", core_file);
|
||||
}
|
||||
|
||||
/* If mourn is being called in all the right places, this could be say
|
||||
`gdb internal error' (since generic_mourn calls breakpoint_init_inferior). */
|
||||
|
||||
static int
|
||||
ignore (addr, contents)
|
||||
CORE_ADDR addr;
|
||||
char *contents;
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
xfer_kmem (memaddr, myaddr, len, write, target)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
int write;
|
||||
struct target_ops *target;
|
||||
{
|
||||
int n;
|
||||
|
||||
#if 0 /* XXX */
|
||||
if (it is a user address)
|
||||
return xfer_umem(memaddr, myaddr, len, write);
|
||||
#endif
|
||||
|
||||
if (core_kd == NULL)
|
||||
return 0;
|
||||
|
||||
if (write)
|
||||
n = kvm_write(core_kd, memaddr, myaddr, len);
|
||||
else
|
||||
n = kvm_read (core_kd, memaddr, myaddr, len) ;
|
||||
if (n < 0) {
|
||||
fprintf_unfiltered (gdb_stderr, "can not access 0x%x, %s\n",
|
||||
memaddr, kvm_geterr(core_kd));
|
||||
n = 0;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
#if 0 /* XXX */
|
||||
static int
|
||||
xfer_umem (memaddr, myaddr, len, write)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
int write; /* ignored */
|
||||
{
|
||||
int n;
|
||||
struct proc proc;
|
||||
|
||||
if (kvread(cur_proc, &proc))
|
||||
error("cannot read proc at %#x", cur_proc);
|
||||
n = kvm_uread(core_kd, &proc, memaddr, myaddr, len) ;
|
||||
|
||||
if (n < 0)
|
||||
return 0;
|
||||
return n;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
set_proc_cmd(arg)
|
||||
char *arg;
|
||||
{
|
||||
CORE_ADDR addr;
|
||||
void *val;
|
||||
|
||||
if (!arg)
|
||||
error_no_arg("proc address for the new context");
|
||||
|
||||
if (core_kd == NULL)
|
||||
error("no kernel core file");
|
||||
|
||||
addr = (CORE_ADDR)parse_and_eval_address(arg);
|
||||
|
||||
/* Read the PCB address in proc structure. */
|
||||
addr += (int) &((struct proc *)0)->p_addr;
|
||||
if (kvread(addr, &val))
|
||||
error("cannot read u area ptr");
|
||||
|
||||
if (set_context((CORE_ADDR)val))
|
||||
error("invalid proc address");
|
||||
}
|
||||
|
||||
static void
|
||||
set_pcb_cmd(arg)
|
||||
char *arg;
|
||||
{
|
||||
CORE_ADDR addr;
|
||||
void *val;
|
||||
|
||||
if (!arg)
|
||||
error_no_arg("pcb address for the new context");
|
||||
|
||||
if (core_kd == NULL)
|
||||
error("no kernel core file");
|
||||
|
||||
addr = (CORE_ADDR)parse_and_eval_address(arg);
|
||||
|
||||
if (set_context(addr))
|
||||
error("invalid pcb address");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
_initialize_kcorelow()
|
||||
{
|
||||
kcore_ops.to_shortname = "kcore";
|
||||
kcore_ops.to_longname = "Kernel core dump file";
|
||||
kcore_ops.to_doc =
|
||||
"Use a core file as a target. Specify the filename of the core file.";
|
||||
kcore_ops.to_open = kcore_open;
|
||||
kcore_ops.to_close = kcore_close;
|
||||
kcore_ops.to_attach = find_default_attach;
|
||||
kcore_ops.to_detach = kcore_detach;
|
||||
kcore_ops.to_fetch_registers = get_kcore_registers;
|
||||
kcore_ops.to_xfer_memory = xfer_kmem;
|
||||
kcore_ops.to_files_info = kcore_files_info;
|
||||
kcore_ops.to_create_inferior = find_default_create_inferior;
|
||||
kcore_ops.to_stratum = kcore_stratum;
|
||||
kcore_ops.to_has_memory = 1;
|
||||
kcore_ops.to_has_stack = 1;
|
||||
kcore_ops.to_has_registers = 1;
|
||||
kcore_ops.to_magic = OPS_MAGIC;
|
||||
|
||||
add_target (&kcore_ops);
|
||||
add_com ("proc", class_obscure, set_proc_cmd, "Set current process context");
|
||||
}
|
96
gnu/usr.bin/binutils/gdb5/alpha/nm.h
Normal file
96
gnu/usr.bin/binutils/gdb5/alpha/nm.h
Normal file
@ -0,0 +1,96 @@
|
||||
/* Native definitions for alpha running FreeBSD.
|
||||
Copyright (C) 1993, 1994 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. */
|
||||
|
||||
/* Figure out where the longjmp will land. We expect that we have just entered
|
||||
longjmp and haven't yet setup the stack frame, so the args are still in the
|
||||
argument regs. A0_REGNUM points at the jmp_buf structure from which we
|
||||
extract the pc (JB_PC) that we will land at. The pc is copied into ADDR.
|
||||
This routine returns true on success */
|
||||
|
||||
/* $FreeBSD$ */
|
||||
|
||||
#define GET_LONGJMP_TARGET(ADDR) get_longjmp_target(ADDR)
|
||||
extern int
|
||||
get_longjmp_target PARAMS ((CORE_ADDR *));
|
||||
|
||||
/* Tell gdb that we can attach and detach other processes */
|
||||
#define ATTACH_DETACH
|
||||
|
||||
/* We define our own fetch/store methods */
|
||||
#define FETCH_INFERIOR_REGISTERS
|
||||
|
||||
extern CORE_ADDR alpha_u_regs_offset();
|
||||
#define U_REGS_OFFSET alpha_u_regs_offset()
|
||||
|
||||
#define PTRACE_ARG3_TYPE char*
|
||||
|
||||
/* ptrace transfers longs, the ptrace man page is lying. */
|
||||
|
||||
#define PTRACE_XFER_TYPE int
|
||||
|
||||
/* The alpha does not step over a breakpoint, the manpage is lying again. */
|
||||
|
||||
#define CANNOT_STEP_BREAKPOINT
|
||||
|
||||
/* Linux has shared libraries. */
|
||||
|
||||
#define GDB_TARGET_HAS_SHARED_LIBS
|
||||
|
||||
/* Support for shared libraries. */
|
||||
|
||||
#include "solib.h"
|
||||
|
||||
#ifdef __ELF__
|
||||
#define SVR4_SHARED_LIBS
|
||||
#define TARGET_ELF64
|
||||
#endif
|
||||
|
||||
/* This is a lie. It's actually in stdio.h. */
|
||||
|
||||
#define PSIGNAL_IN_SIGNAL_H
|
||||
|
||||
/* Given a pointer to either a gregset_t or fpregset_t, return a
|
||||
pointer to the first register. */
|
||||
#define ALPHA_REGSET_BASE(regsetp) ((long *) (regsetp))
|
||||
|
||||
extern int kernel_debugging;
|
||||
extern int kernel_writablecore;
|
||||
|
||||
#define ADDITIONAL_OPTIONS \
|
||||
{"kernel", no_argument, &kernel_debugging, 1}, \
|
||||
{"k", no_argument, &kernel_debugging, 1}, \
|
||||
{"wcore", no_argument, &kernel_writablecore, 1}, \
|
||||
{"w", no_argument, &kernel_writablecore, 1},
|
||||
|
||||
#define ADDITIONAL_OPTION_HELP \
|
||||
"\
|
||||
--kernel Enable kernel debugging.\n\
|
||||
--wcore Make core file writable (only works for /dev/mem).\n\
|
||||
This option only works while debugging a kernel !!\n\
|
||||
"
|
||||
|
||||
#define DEFAULT_PROMPT kernel_debugging?"(kgdb) ":"(gdb) "
|
||||
|
||||
/* misuse START_PROGRESS to test whether we're running as kgdb */
|
||||
/* START_PROGRESS is called at the top of main */
|
||||
#undef START_PROGRESS
|
||||
#define START_PROGRESS(STR,N) \
|
||||
if (!strcmp(STR, "kgdb")) \
|
||||
kernel_debugging = 1;
|
||||
|
45
gnu/usr.bin/binutils/gdb5/alpha/tm.h
Normal file
45
gnu/usr.bin/binutils/gdb5/alpha/tm.h
Normal file
@ -0,0 +1,45 @@
|
||||
/* $FreeBSD$ */
|
||||
/* Definitions to make GDB run on an Alpha box under FreeBSD. The
|
||||
definitions here are used when the _target_ system is running Linux.
|
||||
Copyright 1996 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef TM_FREEBSDALPHA_H
|
||||
#define TM_FREEBSDALPHA_H
|
||||
|
||||
#include "alpha/tm-alpha.h"
|
||||
#ifndef S0_REGNUM
|
||||
#define S0_REGNUM (T7_REGNUM+1)
|
||||
#endif
|
||||
|
||||
|
||||
/* Number of traps that happen between exec'ing the shell to run an
|
||||
inferior, and when we finally get to the inferior code. This is 2
|
||||
on FreeBSD and most implementations. */
|
||||
|
||||
#undef START_INFERIOR_TRAPS_EXPECTED
|
||||
#define START_INFERIOR_TRAPS_EXPECTED 2
|
||||
|
||||
struct objfile;
|
||||
void freebsd_uthread_new_objfile PARAMS ((struct objfile *objfile));
|
||||
#define target_new_objfile(OBJFILE) freebsd_uthread_new_objfile (OBJFILE)
|
||||
|
||||
extern char *freebsd_uthread_pid_to_str PARAMS ((int pid));
|
||||
#define target_pid_to_str(PID) freebsd_uthread_pid_to_str (PID)
|
||||
|
||||
#endif /* TM_FREEBSDALPHA_H */
|
5
gnu/usr.bin/binutils/gdb5/alpha/version.c
Normal file
5
gnu/usr.bin/binutils/gdb5/alpha/version.c
Normal file
@ -0,0 +1,5 @@
|
||||
/* $FreeBSD$ */
|
||||
|
||||
char *version = "4.18";
|
||||
char *host_name = "alpha-unknown-freebsd";
|
||||
char *target_name = "alpha-unknown-freebsd";
|
32
gnu/usr.bin/binutils/gdb5/alpha/xm.h
Normal file
32
gnu/usr.bin/binutils/gdb5/alpha/xm.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* Host definitions for GDB running on an Alpha under FreeBSD
|
||||
Copyright (C) 1996 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. */
|
||||
|
||||
/* $FreeBSD$ */
|
||||
|
||||
#if !defined (HOST_BYTE_ORDER)
|
||||
#define HOST_BYTE_ORDER LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
/* The alpha has no siginterrupt routine. */
|
||||
#define NO_SIGINTERRUPT
|
||||
|
||||
#define HAVE_TERMIOS
|
||||
#define HAVE_SIGSETMASK 1
|
||||
|
||||
#include <limits.h>
|
328
gnu/usr.bin/binutils/gdb5/config.h
Normal file
328
gnu/usr.bin/binutils/gdb5/config.h
Normal file
@ -0,0 +1,328 @@
|
||||
/* $FreeBSD$ */
|
||||
|
||||
/* config.h. Generated automatically by configure. */
|
||||
/* config.in. Generated automatically from configure.in by autoheader. */
|
||||
|
||||
/* Whether malloc must be declared even if <stdlib.h> is included. */
|
||||
/* #undef NEED_DECLARATION_MALLOC */
|
||||
|
||||
/* Whether realloc must be declared even if <stdlib.h> is included. */
|
||||
/* #undef NEED_DECLARATION_REALLOC */
|
||||
|
||||
/* Whether free must be declared even if <stdlib.h> is included. */
|
||||
/* #undef NEED_DECLARATION_FREE */
|
||||
|
||||
/* Whether strerror must be declared even if <string.h> is included. */
|
||||
/* #undef NEED_DECLARATION_STRERROR */
|
||||
|
||||
/* Define if on AIX 3.
|
||||
System headers sometimes define this.
|
||||
We just want to avoid a redefinition error message. */
|
||||
#ifndef _ALL_SOURCE
|
||||
/* #undef _ALL_SOURCE */
|
||||
#endif
|
||||
|
||||
/* Define if using alloca.c. */
|
||||
/* #undef C_ALLOCA */
|
||||
|
||||
/* Define to empty if the keyword does not work. */
|
||||
/* #undef const */
|
||||
|
||||
/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
|
||||
This function is required for alloca.c support on those systems. */
|
||||
/* #undef CRAY_STACKSEG_END */
|
||||
|
||||
/* Define if you have alloca, as a function or macro. */
|
||||
#define HAVE_ALLOCA 1
|
||||
|
||||
/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
|
||||
/* #undef HAVE_ALLOCA_H */
|
||||
|
||||
/* Define if the `long double' type works. */
|
||||
#define HAVE_LONG_DOUBLE 1
|
||||
|
||||
/* Define if you have a working `mmap' system call. */
|
||||
#define HAVE_MMAP 1
|
||||
|
||||
/* Define as __inline if that's what the C compiler calls it. */
|
||||
/* #undef inline */
|
||||
|
||||
/* Define to `long' if <sys/types.h> doesn't define. */
|
||||
/* #undef off_t */
|
||||
|
||||
/* Define if you need to in order for stat and other things to work. */
|
||||
/* #undef _POSIX_SOURCE */
|
||||
|
||||
/* Define as the return type of signal handlers (int or void). */
|
||||
#define RETSIGTYPE void
|
||||
|
||||
/* Define to `unsigned' if <sys/types.h> doesn't define. */
|
||||
/* #undef size_t */
|
||||
|
||||
/* If using the C implementation of alloca, define if you know the
|
||||
direction of stack growth for your system; otherwise it will be
|
||||
automatically deduced at run-time.
|
||||
STACK_DIRECTION > 0 => grows toward higher addresses
|
||||
STACK_DIRECTION < 0 => grows toward lower addresses
|
||||
STACK_DIRECTION = 0 => direction of growth unknown
|
||||
*/
|
||||
/* #undef STACK_DIRECTION */
|
||||
|
||||
/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly. */
|
||||
/* #undef STAT_MACROS_BROKEN */
|
||||
|
||||
/* Define if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Define if ioctl argument PIOCSET is available. */
|
||||
/* #undef HAVE_PROCFS_PIOCSET */
|
||||
|
||||
/* /proc PID entries are directories containing the files
|
||||
ctl as map status */
|
||||
/* #undef HAVE_MULTIPLE_PROC_FDS */
|
||||
|
||||
/* Define if the `long long' type works. */
|
||||
#define CC_HAS_LONG_LONG 1
|
||||
|
||||
/* Define if the "ll" format works to print long long ints. */
|
||||
#define PRINTF_HAS_LONG_LONG 1
|
||||
|
||||
/* Define if the "%Lg" format works to print long doubles. */
|
||||
#define PRINTF_HAS_LONG_DOUBLE 1
|
||||
|
||||
/* Define if the "%Lg" format works to scan long doubles. */
|
||||
#define SCANF_HAS_LONG_DOUBLE 1
|
||||
|
||||
/* Define if using Solaris thread debugging. */
|
||||
/* #undef HAVE_THREAD_DB_LIB */
|
||||
|
||||
/* Define on a GNU/Linux system to work around problems in sys/procfs.h. */
|
||||
/* #undef START_INFERIOR_TRAPS_EXPECTED */
|
||||
/* #undef sys_quotactl */
|
||||
|
||||
/* Define if you have HPUX threads */
|
||||
/* #undef HAVE_HPUX_THREAD_SUPPORT */
|
||||
|
||||
/* Define if you want to use the memory mapped malloc package (mmalloc). */
|
||||
/* #undef USE_MMALLOC */
|
||||
|
||||
/* Define if the runtime uses a routine from mmalloc before gdb has a chance
|
||||
to initialize mmalloc, and we want to force checking to be used anyway.
|
||||
This may cause spurious memory corruption messages if the runtime tries
|
||||
to explicitly deallocate that memory when gdb calls exit. */
|
||||
/* #undef MMCHECK_FORCE */
|
||||
|
||||
/* Define if you want to use the full-screen terminal user interface. */
|
||||
/* #undef TUI */
|
||||
|
||||
/* Define if <proc_service.h> on solaris uses int instead of
|
||||
size_t, and assorted other type changes. */
|
||||
/* #undef PROC_SERVICE_IS_OLD */
|
||||
|
||||
/* Set to true if the save_state_t structure is present */
|
||||
#define HAVE_STRUCT_SAVE_STATE_T 0
|
||||
|
||||
/* Set to true if the save_state_t structure has the ss_wide member */
|
||||
#define HAVE_STRUCT_MEMBER_SS_WIDE 0
|
||||
|
||||
/* Define if you have the __argz_count function. */
|
||||
/* #undef HAVE___ARGZ_COUNT */
|
||||
|
||||
/* Define if you have the __argz_next function. */
|
||||
/* #undef HAVE___ARGZ_NEXT */
|
||||
|
||||
/* Define if you have the __argz_stringify function. */
|
||||
/* #undef HAVE___ARGZ_STRINGIFY */
|
||||
|
||||
/* Define if you have the bcopy function. */
|
||||
#define HAVE_BCOPY 1
|
||||
|
||||
/* Define if you have the btowc function. */
|
||||
/* #undef HAVE_BTOWC */
|
||||
|
||||
/* Define if you have the bzero function. */
|
||||
#define HAVE_BZERO 1
|
||||
|
||||
/* Define if you have the dcgettext function. */
|
||||
/* #undef HAVE_DCGETTEXT */
|
||||
|
||||
/* Define if you have the getcwd function. */
|
||||
#define HAVE_GETCWD 1
|
||||
|
||||
/* Define if you have the getpagesize function. */
|
||||
#define HAVE_GETPAGESIZE 1
|
||||
|
||||
/* Define if you have the isascii function. */
|
||||
#define HAVE_ISASCII 1
|
||||
|
||||
/* Define if you have the munmap function. */
|
||||
#define HAVE_MUNMAP 1
|
||||
|
||||
/* Define if you have the putenv function. */
|
||||
#define HAVE_PUTENV 1
|
||||
|
||||
/* Define if you have the sbrk function. */
|
||||
#define HAVE_SBRK 1
|
||||
|
||||
/* Define if you have the setenv function. */
|
||||
#define HAVE_SETENV 1
|
||||
|
||||
/* Define if you have the setlocale function. */
|
||||
#define HAVE_SETLOCALE 1
|
||||
|
||||
/* Define if you have the setpgid function. */
|
||||
#define HAVE_SETPGID 1
|
||||
|
||||
/* Define if you have the sigaction function. */
|
||||
#define HAVE_SIGACTION 1
|
||||
|
||||
/* Define if you have the stpcpy function. */
|
||||
/* #undef HAVE_STPCPY */
|
||||
|
||||
/* Define if you have the strcasecmp function. */
|
||||
#define HAVE_STRCASECMP 1
|
||||
|
||||
/* Define if you have the strchr function. */
|
||||
#define HAVE_STRCHR 1
|
||||
|
||||
/* Define if you have the <argz.h> header file. */
|
||||
/* #undef HAVE_ARGZ_H */
|
||||
|
||||
/* Define if you have the <asm/debugreg.h> header file. */
|
||||
/* #undef HAVE_ASM_DEBUGREG_H */
|
||||
|
||||
/* Define if you have the <ctype.h> header file. */
|
||||
#define HAVE_CTYPE_H 1
|
||||
|
||||
/* Define if you have the <curses.h> header file. */
|
||||
#define HAVE_CURSES_H 1
|
||||
|
||||
/* Define if you have the <endian.h> header file. */
|
||||
/* #undef HAVE_ENDIAN_H */
|
||||
|
||||
/* Define if you have the <limits.h> header file. */
|
||||
#define HAVE_LIMITS_H 1
|
||||
|
||||
/* Define if you have the <link.h> header file. */
|
||||
#define HAVE_LINK_H 1
|
||||
|
||||
/* Define if you have the <locale.h> header file. */
|
||||
#define HAVE_LOCALE_H 1
|
||||
|
||||
/* Define if you have the <malloc.h> header file. */
|
||||
/* #undef HAVE_MALLOC_H */
|
||||
|
||||
/* Define if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
/* Define if you have the <nl_types.h> header file. */
|
||||
#define HAVE_NL_TYPES_H 1
|
||||
|
||||
/* Define if you have the <objlist.h> header file. */
|
||||
/* #undef HAVE_OBJLIST_H */
|
||||
|
||||
/* Define if you have the <ptrace.h> header file. */
|
||||
/* #undef HAVE_PTRACE_H */
|
||||
|
||||
/* Define if you have the <sgtty.h> header file. */
|
||||
#define HAVE_SGTTY_H 1
|
||||
|
||||
/* Define if you have the <stddef.h> header file. */
|
||||
#define HAVE_STDDEF_H 1
|
||||
|
||||
/* Define if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define if you have the <sys/debugreg.h> header file. */
|
||||
/* #undef HAVE_SYS_DEBUGREG_H */
|
||||
|
||||
/* Define if you have the <sys/param.h> header file. */
|
||||
#define HAVE_SYS_PARAM_H 1
|
||||
|
||||
/* Define if you have the <sys/procfs.h> header file. */
|
||||
#define HAVE_SYS_PROCFS_H 1
|
||||
|
||||
/* Define if you have the <sys/ptrace.h> header file. */
|
||||
#define HAVE_SYS_PTRACE_H 1
|
||||
|
||||
/* Define if you have the <sys/reg.h> header file. */
|
||||
/* #undef HAVE_SYS_REG_H */
|
||||
|
||||
/* Define if you have the <sys/wait.h> header file. */
|
||||
#define HAVE_SYS_WAIT_H 1
|
||||
|
||||
/* Define if you have the <term.h> header file. */
|
||||
#define HAVE_TERM_H 1
|
||||
|
||||
/* Define if you have the <termio.h> header file. */
|
||||
/* #undef HAVE_TERMIO_H */
|
||||
|
||||
/* Define if you have the <termios.h> header file. */
|
||||
#define HAVE_TERMIOS_H 1
|
||||
|
||||
/* Define if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* Define if you have the <values.h> header file. */
|
||||
/* #undef HAVE_VALUES_H */
|
||||
|
||||
/* Define if you have the <wait.h> header file. */
|
||||
/* #undef HAVE_WAIT_H */
|
||||
|
||||
/* Define if you have the <wchar.h> header file. */
|
||||
/* #undef HAVE_WCHAR_H */
|
||||
|
||||
/* Define if you have the <wctype.h> header file. */
|
||||
/* #undef HAVE_WCTYPE_H */
|
||||
|
||||
/* Define if you have the dl library (-ldl). */
|
||||
/* #undef HAVE_LIBDL */
|
||||
|
||||
/* Define if you have the m library (-lm). */
|
||||
#define HAVE_LIBM 1
|
||||
|
||||
/* Define if you have the w library (-lw). */
|
||||
/* #undef HAVE_LIBW */
|
||||
|
||||
/* Define if you have the stpcpy function */
|
||||
/* #undef HAVE_STPCPY */
|
||||
|
||||
/* Define if your locale.h file contains LC_MESSAGES. */
|
||||
#define HAVE_LC_MESSAGES 1
|
||||
|
||||
/* Define to 1 if NLS is requested */
|
||||
#define ENABLE_NLS 1
|
||||
|
||||
/* Define as 1 if you have gettext and don't want to use GNU gettext. */
|
||||
/* #undef HAVE_GETTEXT */
|
||||
|
||||
/* Define if malloc is not declared in system header files. */
|
||||
/* #undef NEED_DECLARATION_MALLOC */
|
||||
|
||||
/* Define if realloc is not declared in system header files. */
|
||||
/* #undef NEED_DECLARATION_REALLOC */
|
||||
|
||||
/* Define if free is not declared in system header files. */
|
||||
/* #undef NEED_DECLARATION_FREE */
|
||||
|
||||
/* Define if strerror is not declared in system header files. */
|
||||
/* #undef NEED_DECLARATION_STRERROR */
|
||||
|
||||
/* Define if strdup is not declared in system header files. */
|
||||
/* #undef NEED_DECLARATION_STRDUP */
|
||||
|
||||
/* Define if <sys/procfs.h> has pstatus_t. */
|
||||
/* #undef HAVE_PSTATUS_T */
|
||||
|
||||
/* Define if <sys/procfs.h> has prrun_t. */
|
||||
/* #undef HAVE_PRRUN_T */
|
||||
|
||||
/* Define if <sys/procfs.h> has gregset_t. */
|
||||
#define HAVE_GREGSET_T 1
|
||||
|
||||
/* Define if <sys/procfs.h> has fpregset_t. */
|
||||
#define HAVE_FPREGSET_T 1
|
||||
|
1139
gnu/usr.bin/binutils/gdb5/freebsd-uthread.c
Normal file
1139
gnu/usr.bin/binutils/gdb5/freebsd-uthread.c
Normal file
File diff suppressed because it is too large
Load Diff
670
gnu/usr.bin/binutils/gdb5/i386/freebsd-nat.c
Normal file
670
gnu/usr.bin/binutils/gdb5/i386/freebsd-nat.c
Normal file
@ -0,0 +1,670 @@
|
||||
/* $FreeBSD$ */
|
||||
/* Native-dependent code for BSD Unix running on i386's, for GDB.
|
||||
Copyright 1988, 1989, 1991, 1992, 1994, 1996 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* $FreeBSD$ */
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <machine/reg.h>
|
||||
#include <machine/frame.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/user.h>
|
||||
#include "gdbcore.h"
|
||||
#include "value.h"
|
||||
#include "inferior.h"
|
||||
|
||||
#if defined(HAVE_GREGSET_T) || defined(HAVE_FPREGSET_T)
|
||||
#include <sys/procfs.h>
|
||||
#endif
|
||||
|
||||
/* this table must line up with REGISTER_NAMES in tm-i386v.h */
|
||||
/* symbols like 'tEAX' come from <machine/reg.h> */
|
||||
static int tregmap[] =
|
||||
{
|
||||
tEAX, tECX, tEDX, tEBX,
|
||||
tESP, tEBP, tESI, tEDI,
|
||||
tEIP, tEFLAGS, tCS, tSS,
|
||||
tDS, tES, tFS, tGS,
|
||||
};
|
||||
|
||||
static struct save87 pcb_savefpu;
|
||||
|
||||
void
|
||||
fetch_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
struct reg inferior_registers; /* ptrace order, not gcc/gdb order */
|
||||
int r;
|
||||
|
||||
ptrace (PT_GETREGS, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) &inferior_registers, 0);
|
||||
|
||||
for (r = 0; r < NUM_REGS; r++)
|
||||
memcpy (®isters[REGISTER_BYTE (r)], ((int *)&inferior_registers) + tregmap[r], 4);
|
||||
|
||||
registers_fetched ();
|
||||
}
|
||||
|
||||
void
|
||||
store_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
struct reg inferior_registers; /* ptrace order, not gcc/gdb order */
|
||||
int r;
|
||||
|
||||
for (r = 0; r < NUM_REGS; r++)
|
||||
memcpy (((int *)&inferior_registers) + tregmap[r], ®isters[REGISTER_BYTE (r)], 4);
|
||||
|
||||
ptrace (PT_SETREGS, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) &inferior_registers, 0);
|
||||
}
|
||||
|
||||
/* Extract the register values out of the core file and store
|
||||
them where `read_register' will find them.
|
||||
Extract the floating point state out of the core file and store
|
||||
it where `float_info' will find it.
|
||||
|
||||
CORE_REG_SECT points to the register values themselves, read into memory.
|
||||
CORE_REG_SIZE is the size of that area.
|
||||
WHICH says which set of registers we are handling (0 = int, 2 = float
|
||||
on machines where they are discontiguous).
|
||||
REG_ADDR is the offset from u.u_ar0 to the register values relative to
|
||||
core_reg_sect. This is used with old-fashioned core files to
|
||||
locate the registers in a large upage-plus-stack ".reg" section.
|
||||
Original upage address X is at location core_reg_sect+x+reg_addr.
|
||||
*/
|
||||
|
||||
static void
|
||||
fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr)
|
||||
char *core_reg_sect;
|
||||
unsigned core_reg_size;
|
||||
int which;
|
||||
CORE_ADDR reg_addr;
|
||||
{
|
||||
register int regno;
|
||||
register int cregno;
|
||||
register int addr;
|
||||
int bad_reg = -1;
|
||||
int offset;
|
||||
struct user *tmp_uaddr;
|
||||
|
||||
/*
|
||||
* First get virtual address of user structure. Then calculate offset.
|
||||
*/
|
||||
memcpy(&tmp_uaddr,
|
||||
&((struct user *) core_reg_sect)->u_kproc.ki_addr,
|
||||
sizeof(tmp_uaddr));
|
||||
offset = -reg_addr - (int) tmp_uaddr;
|
||||
|
||||
for (regno = 0; regno < NUM_REGS; regno++)
|
||||
{
|
||||
cregno = tregmap[regno];
|
||||
if (cregno == tGS)
|
||||
addr = offsetof (struct user, u_pcb) + offsetof (struct pcb, pcb_gs);
|
||||
else
|
||||
addr = offset + 4 * cregno;
|
||||
if (addr < 0 || addr >= core_reg_size)
|
||||
{
|
||||
if (bad_reg < 0)
|
||||
bad_reg = regno;
|
||||
}
|
||||
else
|
||||
{
|
||||
supply_register (regno, core_reg_sect + addr);
|
||||
}
|
||||
}
|
||||
if (bad_reg >= 0)
|
||||
{
|
||||
error ("Register %s not found in core file.", gdb_register_names[bad_reg]);
|
||||
}
|
||||
|
||||
addr = offsetof (struct user, u_pcb) + offsetof (struct pcb, pcb_savefpu);
|
||||
memcpy (&pcb_savefpu, core_reg_sect + addr, sizeof pcb_savefpu);
|
||||
}
|
||||
|
||||
#ifdef FLOAT_INFO
|
||||
#include "expression.h"
|
||||
#include "language.h" /* for local_hex_string */
|
||||
#include "floatformat.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <signal.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <a.out.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/uio.h>
|
||||
#define curpcb Xcurpcb /* XXX avoid leaking declaration from pcb.h */
|
||||
#include <sys/user.h>
|
||||
#undef curpcb
|
||||
#include <sys/file.h>
|
||||
#include "gdb_stat.h"
|
||||
#include <sys/ptrace.h>
|
||||
|
||||
extern void print_387_control_word (); /* i387-tdep.h */
|
||||
extern void print_387_status_word ();
|
||||
|
||||
#define fpstate save87
|
||||
#define U_FPSTATE(u) u.u_pcb.pcb_savefpu
|
||||
|
||||
static void
|
||||
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 */
|
||||
}
|
||||
|
||||
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 void
|
||||
print_387_status (status, ep)
|
||||
unsigned short status;
|
||||
struct env387 *ep;
|
||||
{
|
||||
int i;
|
||||
int bothstatus;
|
||||
int top;
|
||||
int fpreg;
|
||||
|
||||
bothstatus = ((status != 0) && (ep->status != 0));
|
||||
if (status != 0)
|
||||
{
|
||||
if (bothstatus)
|
||||
printf_unfiltered ("u: ");
|
||||
print_387_status_word ((unsigned int)status);
|
||||
}
|
||||
|
||||
if (ep->status != 0)
|
||||
{
|
||||
if (bothstatus)
|
||||
printf_unfiltered ("e: ");
|
||||
print_387_status_word ((unsigned int)ep->status);
|
||||
}
|
||||
|
||||
print_387_control_word ((unsigned int)ep->control);
|
||||
printf_unfiltered ("last instruction: ");
|
||||
printf_unfiltered ("opcode %s; ", local_hex_string(ep->opcode));
|
||||
printf_unfiltered ("pc %s:", local_hex_string(ep->code_seg));
|
||||
printf_unfiltered ("%s; ", local_hex_string(ep->eip));
|
||||
printf_unfiltered ("operand %s", local_hex_string(ep->operand_seg));
|
||||
printf_unfiltered (":%s\n", local_hex_string(ep->operand));
|
||||
|
||||
top = (ep->status >> 11) & 7;
|
||||
|
||||
printf_unfiltered (" regno tag msb lsb value\n");
|
||||
for (fpreg = 7; fpreg >= 0; fpreg--)
|
||||
{
|
||||
int exp;
|
||||
int mantissa_or;
|
||||
int normal;
|
||||
char *sign;
|
||||
int st_regno;
|
||||
unsigned short *usregs;
|
||||
double val;
|
||||
|
||||
/* The physical regno `fpreg' is only relevant as an index into the
|
||||
* tag word. Logical `%st' numbers are required for indexing ep->regs.
|
||||
*/
|
||||
st_regno = (fpreg + 8 - top) & 7;
|
||||
|
||||
printf_unfiltered ("%%st(%d) %s ", st_regno, fpreg == top ? "=>" : " ");
|
||||
|
||||
switch ((ep->tag >> (fpreg * 2)) & 3)
|
||||
{
|
||||
case 0: printf_unfiltered ("valid "); break;
|
||||
case 1: printf_unfiltered ("zero "); break;
|
||||
case 2: printf_unfiltered ("trap "); break;
|
||||
case 3: printf_unfiltered ("empty "); break;
|
||||
}
|
||||
for (i = 9; i >= 0; i--)
|
||||
printf_unfiltered ("%02x", ep->regs[st_regno][i]);
|
||||
|
||||
printf_unfiltered (" ");
|
||||
|
||||
/*
|
||||
* Handle weird cases better than floatformat_to_double () and
|
||||
* printf ().
|
||||
*/
|
||||
usregs = (unsigned short *) ep->regs[st_regno];
|
||||
sign = usregs[4] & 0x8000 ? "-" : "";
|
||||
exp = usregs[4] & 0x7fff;
|
||||
normal = usregs[3] & 0x8000;
|
||||
mantissa_or = usregs[0] | usregs[1] | usregs[2] | (usregs[3] & 0x7fff);
|
||||
if (exp == 0)
|
||||
{
|
||||
if (normal)
|
||||
printf_unfiltered ("Pseudo Denormal (0 as a double)");
|
||||
else if (mantissa_or == 0)
|
||||
printf_unfiltered ("%s0", sign);
|
||||
else
|
||||
printf_unfiltered ("Denormal (0 as a double)");
|
||||
}
|
||||
else if (exp == 0x7fff)
|
||||
{
|
||||
if (!normal)
|
||||
printf_unfiltered ("Pseudo ");
|
||||
if (mantissa_or == 0)
|
||||
printf_unfiltered ("%sInf", sign);
|
||||
else
|
||||
printf_unfiltered ("%s NaN",
|
||||
usregs[3] & 0x4000 ? "Quiet" : "Signaling");
|
||||
if (!normal)
|
||||
printf_unfiltered (" (NaN)");
|
||||
}
|
||||
else if (!normal)
|
||||
printf_unfiltered ("Unnormal (NaN)");
|
||||
else
|
||||
{
|
||||
#if 0
|
||||
/* Use this we stop trapping on overflow. */
|
||||
floatformat_to_double(&floatformat_i387_ext,
|
||||
(char *) ep->regs[st_regno], &val);
|
||||
#else
|
||||
i387_to_double((char *) ep->regs[st_regno], (char *) &val);
|
||||
#endif
|
||||
printf_unfiltered ("%g", val);
|
||||
}
|
||||
printf_unfiltered ("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
i386_float_info ()
|
||||
{
|
||||
struct user u; /* just for address computations */
|
||||
int i;
|
||||
/* fpstate defined in <sys/user.h> */
|
||||
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;
|
||||
extern int inferior_pid;
|
||||
|
||||
uaddr = (char *)&U_FPSTATE(u) - (char *)&u;
|
||||
if (inferior_pid != 0 && core_bfd == NULL)
|
||||
{
|
||||
int pid = inferior_pid & ((1 << 17) - 1); /* XXX extract pid from tid */
|
||||
ptrace(PT_GETFPREGS, pid, &buf[0], sizeof(struct fpreg));
|
||||
fpstatep = (struct fpstate *)&buf[0];
|
||||
}
|
||||
else
|
||||
fpstatep = &pcb_savefpu;
|
||||
|
||||
print_387_status (fpstatep->sv_ex_sw, (struct env387 *)fpstatep);
|
||||
}
|
||||
#endif /* FLOAT_INFO */
|
||||
|
||||
int
|
||||
kernel_u_size ()
|
||||
{
|
||||
return (sizeof (struct user));
|
||||
}
|
||||
|
||||
#ifdef SETUP_ARBITRARY_FRAME
|
||||
#include "frame.h"
|
||||
struct frame_info *
|
||||
setup_arbitrary_frame (argc, argv)
|
||||
int argc;
|
||||
CORE_ADDR *argv;
|
||||
{
|
||||
if (argc != 2)
|
||||
error ("i386 frame specifications require two arguments: sp and pc");
|
||||
|
||||
return create_new_frame (argv[0], argv[1]);
|
||||
}
|
||||
#endif /* SETUP_ARBITRARY_FRAME */
|
||||
|
||||
#ifdef HAVE_GREGSET_T
|
||||
void
|
||||
supply_gregset (gp)
|
||||
gregset_t *gp;
|
||||
{
|
||||
int regno = 0;
|
||||
|
||||
/* These must be ordered the same as REGISTER_NAMES in
|
||||
config/i386/tm-i386.h. */
|
||||
supply_register (regno++, (char *)&gp->r_eax);
|
||||
supply_register (regno++, (char *)&gp->r_ecx);
|
||||
supply_register (regno++, (char *)&gp->r_edx);
|
||||
supply_register (regno++, (char *)&gp->r_ebx);
|
||||
supply_register (regno++, (char *)&gp->r_esp);
|
||||
supply_register (regno++, (char *)&gp->r_ebp);
|
||||
supply_register (regno++, (char *)&gp->r_esi);
|
||||
supply_register (regno++, (char *)&gp->r_edi);
|
||||
supply_register (regno++, (char *)&gp->r_eip);
|
||||
supply_register (regno++, (char *)&gp->r_eflags);
|
||||
supply_register (regno++, (char *)&gp->r_cs);
|
||||
supply_register (regno++, (char *)&gp->r_ss);
|
||||
supply_register (regno++, (char *)&gp->r_ds);
|
||||
supply_register (regno++, (char *)&gp->r_es);
|
||||
supply_register (regno++, (char *)&gp->r_fs);
|
||||
supply_register (regno++, (char *)&gp->r_gs);
|
||||
}
|
||||
#endif /* HAVE_GREGSET_T */
|
||||
|
||||
#ifdef HAVE_FPREGSET_T
|
||||
void
|
||||
supply_fpregset (fp)
|
||||
fpregset_t *fp;
|
||||
{
|
||||
memcpy (&pcb_savefpu, fp, sizeof pcb_savefpu);
|
||||
}
|
||||
#endif /* HAVE_FPREGSET_T */
|
||||
|
||||
/* Register that we are able to handle aout (trad-core) file formats. */
|
||||
|
||||
static struct core_fns aout_core_fns =
|
||||
{
|
||||
bfd_target_unknown_flavour,
|
||||
fetch_core_registers,
|
||||
NULL
|
||||
};
|
||||
|
||||
void
|
||||
_initialize_core_aout ()
|
||||
{
|
||||
add_core_fns (&aout_core_fns);
|
||||
}
|
||||
|
||||
#ifdef PT_GETDBREGS
|
||||
|
||||
/*
|
||||
* 0: no trace output
|
||||
* 1: trace watchpoint requests
|
||||
* 2: trace `watchpoint hit?' tests, too
|
||||
*/
|
||||
#define WATCHPOINT_DEBUG 0
|
||||
|
||||
#include "breakpoint.h"
|
||||
|
||||
int
|
||||
can_watch(type, cnt, ot)
|
||||
int type, cnt, ot;
|
||||
{
|
||||
int rv;
|
||||
static int cnt_watch, cnt_awatch;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case bp_hardware_watchpoint:
|
||||
cnt_watch = cnt;
|
||||
break;
|
||||
|
||||
case bp_access_watchpoint:
|
||||
cnt_awatch = cnt;
|
||||
break;
|
||||
|
||||
default:
|
||||
rv = 0;
|
||||
goto overandout;
|
||||
}
|
||||
|
||||
rv = cnt_watch + cnt_awatch <= 4? 1: -1;
|
||||
|
||||
overandout:
|
||||
#if WATCHPOINT_DEBUG
|
||||
printf_filtered("can_watch(%d, %d, %d) = %d (counts: w: %d, rw: %d)\n",
|
||||
type, cnt, ot, rv, cnt_watch, cnt_awatch);
|
||||
#endif
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int
|
||||
stopped_by_watchpoint()
|
||||
{
|
||||
struct dbreg dbr;
|
||||
extern int inferior_pid;
|
||||
|
||||
if (current_target.to_shortname == 0 ||
|
||||
! (strcmp(current_target.to_shortname, "child") == 0 ||
|
||||
strcmp(current_target.to_shortname, "freebsd-uthreads") == 0))
|
||||
return 0;
|
||||
|
||||
if (inferior_pid != 0 && core_bfd == NULL)
|
||||
{
|
||||
int pid = inferior_pid & ((1 << 17) - 1); /* XXX extract pid from tid */
|
||||
|
||||
if (ptrace(PT_GETDBREGS, pid, (caddr_t)&dbr, 0) == -1)
|
||||
{
|
||||
perror("ptrace(PT_GETDBREGS) failed");
|
||||
return 0;
|
||||
}
|
||||
#if WATCHPOINT_DEBUG > 1
|
||||
printf_filtered("stopped_by_watchpoint(): DR6 = %#x\n", dbr.dr6);
|
||||
#endif
|
||||
/*
|
||||
* If a hardware watchpoint was hit, one of the lower 4 bits in
|
||||
* DR6 is set (the actual bit indicates which of DR0...DR3 triggered
|
||||
* the trap).
|
||||
*/
|
||||
return dbr.dr6 & 0x0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
warning("Can't set a watchpoint on a core file.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
insert_watchpoint(addr, len, type)
|
||||
int addr, len, type;
|
||||
{
|
||||
struct dbreg dbr;
|
||||
extern int inferior_pid;
|
||||
|
||||
if (current_target.to_shortname == 0 ||
|
||||
! (strcmp(current_target.to_shortname, "child") == 0 ||
|
||||
strcmp(current_target.to_shortname, "freebsd-uthreads") == 0))
|
||||
return 0;
|
||||
|
||||
if (inferior_pid != 0 && core_bfd == NULL)
|
||||
{
|
||||
int pid = inferior_pid & ((1 << 17) - 1); /* XXX extract pid from tid */
|
||||
int i, mask;
|
||||
unsigned int sbits;
|
||||
|
||||
if (ptrace(PT_GETDBREGS, pid, (caddr_t)&dbr, 0) == -1)
|
||||
{
|
||||
perror("ptrace(PT_GETDBREGS) failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0, mask = 0x03; i < 4; i++, mask <<= 2)
|
||||
if ((dbr.dr7 & mask) == 0)
|
||||
break;
|
||||
if (i >= 4) {
|
||||
warning("no more hardware watchpoints available");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* paranoia */
|
||||
if (len > 4)
|
||||
{
|
||||
warning("watchpoint length %d unsupported, using lenght = 4",
|
||||
len);
|
||||
len = 4;
|
||||
}
|
||||
else if (len == 3)
|
||||
{
|
||||
warning("weird watchpoint length 3, using 2");
|
||||
len = 2;
|
||||
}
|
||||
else if (len == 0)
|
||||
{
|
||||
warning("weird watchpoint length 0, using 1");
|
||||
len = 1;
|
||||
}
|
||||
|
||||
switch (len)
|
||||
{
|
||||
case 1: sbits = 0; break;
|
||||
case 2: sbits = 4; break;
|
||||
case 4: sbits = 0x0c; break;
|
||||
}
|
||||
|
||||
/*
|
||||
* The `type' value is 0 for `watch on write', 1 for `watch on
|
||||
* read', 2 for `watch on both'. The i386 debug register
|
||||
* breakpoint types are 0 for `execute' (not used in GDB), 1 for
|
||||
* `write', and 4 for `read/write'. Plain `read' trapping is
|
||||
* not supported on i386, value 3 is illegal.
|
||||
*/
|
||||
switch (type)
|
||||
{
|
||||
default:
|
||||
warning("weird watchpoint type %d, using a write watchpoint");
|
||||
/* FALLTHROUGH */
|
||||
case 0:
|
||||
sbits |= 1;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
sbits |= 3;
|
||||
break;
|
||||
}
|
||||
sbits <<= 4 * i + 16;
|
||||
sbits |= 1 << 2 * i;
|
||||
|
||||
dbr.dr7 |= sbits;
|
||||
*(&dbr.dr0 + i) = (unsigned int)addr;
|
||||
|
||||
#if WATCHPOINT_DEBUG
|
||||
printf_filtered("insert_watchpoint(), inserting DR7 = %#x, DR%d = %#x\n",
|
||||
dbr.dr7, i, addr);
|
||||
#endif
|
||||
if (ptrace(PT_SETDBREGS, pid, (caddr_t)&dbr, 0) == -1)
|
||||
{
|
||||
perror("ptrace(PT_SETDBREGS) failed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
warning("Can't set a watchpoint on a core file.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
remove_watchpoint(addr, len, type)
|
||||
int addr, len, type;
|
||||
{
|
||||
struct dbreg dbr;
|
||||
extern int inferior_pid;
|
||||
|
||||
if (current_target.to_shortname == 0 ||
|
||||
! (strcmp(current_target.to_shortname, "child") == 0 ||
|
||||
strcmp(current_target.to_shortname, "freebsd-uthreads") == 0))
|
||||
return 0;
|
||||
|
||||
if (inferior_pid != 0 && core_bfd == NULL)
|
||||
{
|
||||
int pid = inferior_pid & ((1 << 17) - 1); /* XXX extract pid from tid */
|
||||
int i;
|
||||
unsigned int sbits, *dbregp;
|
||||
|
||||
if (ptrace(PT_GETDBREGS, pid, (caddr_t)&dbr, 0) == -1)
|
||||
{
|
||||
perror("ptrace(PT_GETDBREGS) failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0, dbregp = &dbr.dr0; i < 4; i++, dbregp++)
|
||||
if (*dbregp == (unsigned int)addr)
|
||||
break;
|
||||
if (i >= 4)
|
||||
{
|
||||
warning("watchpoint for address %#x not found", addr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*dbregp = 0;
|
||||
sbits = 0xf << (4 * i + 16);
|
||||
sbits |= 3 << 2 * i;
|
||||
dbr.dr7 &= ~sbits;
|
||||
|
||||
#if WATCHPOINT_DEBUG
|
||||
printf_filtered("remove_watchpoint(): removing watchpoint for %#x, DR7 = %#x\n",
|
||||
addr, dbr.dr7);
|
||||
#endif
|
||||
if (ptrace(PT_SETDBREGS, pid, (caddr_t)&dbr, 0) == -1)
|
||||
{
|
||||
perror("ptrace(PT_SETDBREGS) failed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
warning("Can't set a watchpoint on a core file.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* PT_GETDBREGS */
|
995
gnu/usr.bin/binutils/gdb5/i386/kvm-fbsd.c
Normal file
995
gnu/usr.bin/binutils/gdb5/i386/kvm-fbsd.c
Normal file
@ -0,0 +1,995 @@
|
||||
/* Live and postmortem kernel debugging functions for FreeBSD.
|
||||
Copyright 1996 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* $FreeBSD$ */
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <paths.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/user.h>
|
||||
#include "frame.h" /* required by inferior.h */
|
||||
#include "inferior.h"
|
||||
#include "symtab.h"
|
||||
#include "symfile.h"
|
||||
#include "objfiles.h"
|
||||
#include "command.h"
|
||||
#include "bfd.h"
|
||||
#include "target.h"
|
||||
#include "gdbcore.h"
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_param.h>
|
||||
|
||||
#include <machine/vmparam.h>
|
||||
#include <machine/pcb.h>
|
||||
#include <machine/tss.h>
|
||||
#include <machine/frame.h>
|
||||
#include <machine/globaldata.h>
|
||||
|
||||
static void kcore_files_info PARAMS ((struct target_ops *));
|
||||
|
||||
static void kcore_close PARAMS ((int));
|
||||
|
||||
static void get_kcore_registers PARAMS ((int));
|
||||
|
||||
static int kcore_xfer_kmem PARAMS ((CORE_ADDR, char *, int, int, struct target_ops *));
|
||||
|
||||
static int xfer_umem PARAMS ((CORE_ADDR, char *, int, int));
|
||||
|
||||
static CORE_ADDR ksym_lookup PARAMS ((const char *));
|
||||
|
||||
static int read_pcb PARAMS ((int, CORE_ADDR));
|
||||
|
||||
static struct proc * curProc PARAMS ((void));
|
||||
|
||||
static int set_proc_context PARAMS ((CORE_ADDR paddr));
|
||||
|
||||
static void kcore_open PARAMS ((char *filename, int from_tty));
|
||||
|
||||
static void kcore_detach PARAMS ((char *args, int from_tty));
|
||||
|
||||
static void set_proc_cmd PARAMS ((char *arg, int from_tty));
|
||||
|
||||
static void set_cpu_cmd PARAMS ((char *arg, int from_tty));
|
||||
|
||||
static CORE_ADDR kvtophys PARAMS ((int, CORE_ADDR));
|
||||
|
||||
static int physrd PARAMS ((int, u_int, char*, int));
|
||||
|
||||
static int kvm_open PARAMS ((const char *efile, char *cfile, char *sfile,
|
||||
int perm, char *errout));
|
||||
|
||||
static int kvm_close PARAMS ((int fd));
|
||||
|
||||
static int kvm_write PARAMS ((int core_kd, CORE_ADDR memaddr,
|
||||
char *myaddr, int len));
|
||||
|
||||
static int kvm_read PARAMS ((int core_kd, CORE_ADDR memaddr,
|
||||
char *myaddr, int len));
|
||||
|
||||
static int kvm_uread PARAMS ((int core_kd, struct proc *p,
|
||||
CORE_ADDR memaddr, char *myaddr,
|
||||
int len));
|
||||
|
||||
static int kernel_core_file_hook PARAMS ((int fd, CORE_ADDR addr,
|
||||
char *buf, int len));
|
||||
|
||||
static CORE_ADDR kvm_getpcpu PARAMS ((int cfd, int cpuid));
|
||||
|
||||
static struct kinfo_proc * kvm_getprocs PARAMS ((int cfd, int op,
|
||||
CORE_ADDR proc, int *cnt));
|
||||
|
||||
extern struct target_ops kcore_ops; /* Forward decl */
|
||||
|
||||
/* Non-zero means we are debugging a kernel core file */
|
||||
int kernel_debugging = 0;
|
||||
int kernel_writablecore = 0;
|
||||
|
||||
static char *core_file;
|
||||
static int core_kd = -1;
|
||||
static struct proc *cur_proc;
|
||||
static CORE_ADDR kernel_start;
|
||||
|
||||
static CORE_ADDR pcpu;
|
||||
#define PCPU_OFFSET(name) \
|
||||
offsetof(struct globaldata, gd_ ## name)
|
||||
|
||||
/*
|
||||
* Symbol names of kernel entry points. Use special frames.
|
||||
*/
|
||||
#define KSYM_TRAP "calltrap"
|
||||
#define KSYM_INTERRUPT "Xresume"
|
||||
#define KSYM_SYSCALL "Xsyscall"
|
||||
|
||||
/*
|
||||
* Read the "thing" at kernel address 'addr' into the space pointed to
|
||||
* by point. The length of the "thing" is determined by the type of p.
|
||||
* Result is non-zero if transfer fails.
|
||||
*/
|
||||
#define kvread(addr, p) \
|
||||
(target_read_memory ((CORE_ADDR)(addr), (char *)(p), sizeof(*(p))))
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* The following is FreeBSD-specific hackery to decode special frames
|
||||
* and elide the assembly-language stub. This could be made faster by
|
||||
* defining a frame_type field in the machine-dependent frame information,
|
||||
* but we don't think that's too important right now.
|
||||
*/
|
||||
enum frametype { tf_normal, tf_trap, tf_interrupt, tf_syscall };
|
||||
|
||||
CORE_ADDR
|
||||
fbsd_kern_frame_saved_pc (fr)
|
||||
struct frame_info *fr;
|
||||
{
|
||||
struct minimal_symbol *sym;
|
||||
CORE_ADDR this_saved_pc;
|
||||
enum frametype frametype;
|
||||
|
||||
this_saved_pc = read_memory_integer (fr->frame + 4, 4);
|
||||
sym = lookup_minimal_symbol_by_pc (this_saved_pc);
|
||||
frametype = tf_normal;
|
||||
if (sym != NULL) {
|
||||
if (strcmp (SYMBOL_NAME(sym), KSYM_TRAP) == 0)
|
||||
frametype = tf_trap;
|
||||
else if (strncmp (SYMBOL_NAME(sym), KSYM_INTERRUPT, 7) == 0)
|
||||
frametype = tf_interrupt;
|
||||
else if (strcmp (SYMBOL_NAME(sym), KSYM_SYSCALL) == 0)
|
||||
frametype = tf_syscall;
|
||||
}
|
||||
|
||||
switch (frametype) {
|
||||
case tf_normal:
|
||||
return (this_saved_pc);
|
||||
|
||||
#define oEIP offsetof(struct trapframe, tf_eip)
|
||||
|
||||
case tf_trap:
|
||||
return (read_memory_integer (fr->frame + 8 + oEIP, 4));
|
||||
|
||||
case tf_interrupt:
|
||||
return (read_memory_integer (fr->frame + 16 + oEIP, 4));
|
||||
|
||||
case tf_syscall:
|
||||
return (read_memory_integer (fr->frame + 8 + oEIP, 4));
|
||||
#undef oEIP
|
||||
}
|
||||
}
|
||||
|
||||
static CORE_ADDR
|
||||
ksym_lookup (name)
|
||||
const char *name;
|
||||
{
|
||||
struct minimal_symbol *sym;
|
||||
|
||||
sym = lookup_minimal_symbol (name, NULL, NULL);
|
||||
if (sym == NULL)
|
||||
error ("kernel symbol `%s' not found.", name);
|
||||
|
||||
return SYMBOL_VALUE_ADDRESS (sym);
|
||||
}
|
||||
|
||||
static struct proc *
|
||||
curProc ()
|
||||
{
|
||||
struct proc *p;
|
||||
CORE_ADDR addr = pcpu + PCPU_OFFSET (curproc);
|
||||
|
||||
if (kvread (addr, &p))
|
||||
error ("cannot read proc pointer at %x\n", addr);
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the process context to that of the proc structure at
|
||||
* system address paddr.
|
||||
*/
|
||||
static int
|
||||
set_proc_context (paddr)
|
||||
CORE_ADDR paddr;
|
||||
{
|
||||
struct proc p;
|
||||
|
||||
if (paddr < kernel_start)
|
||||
return (1);
|
||||
|
||||
cur_proc = (struct proc *)paddr;
|
||||
#ifdef notyet
|
||||
set_kernel_boundaries (cur_proc);
|
||||
#endif
|
||||
|
||||
/* Fetch all registers from core file */
|
||||
target_fetch_registers (-1);
|
||||
|
||||
/* Now, set up the frame cache, and print the top of stack */
|
||||
flush_cached_frames ();
|
||||
set_current_frame (create_new_frame (read_fp (), read_pc ()));
|
||||
select_frame (get_current_frame (), 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Discard all vestiges of any previous core file
|
||||
and mark data and stack spaces as empty. */
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
kcore_close (quitting)
|
||||
int quitting;
|
||||
{
|
||||
inferior_pid = 0; /* Avoid confusion from thread stuff */
|
||||
|
||||
if (core_kd)
|
||||
{
|
||||
kvm_close (core_kd);
|
||||
free (core_file);
|
||||
core_file = NULL;
|
||||
core_kd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* This routine opens and sets up the core file bfd */
|
||||
|
||||
static void
|
||||
kcore_open (filename, from_tty)
|
||||
char *filename;
|
||||
int from_tty;
|
||||
{
|
||||
const char *p;
|
||||
struct cleanup *old_chain;
|
||||
char buf[256], *cp;
|
||||
int ontop;
|
||||
CORE_ADDR addr;
|
||||
struct pcb pcb;
|
||||
|
||||
target_preopen (from_tty);
|
||||
|
||||
unpush_target (&kcore_ops);
|
||||
|
||||
if (!filename)
|
||||
{
|
||||
/*error (core_kd?*/
|
||||
error ( (core_kd >= 0)?
|
||||
"No core file specified. (Use `detach' to stop debugging a core file.)"
|
||||
: "No core file specified.");
|
||||
}
|
||||
|
||||
filename = tilde_expand (filename);
|
||||
if (filename[0] != '/')
|
||||
{
|
||||
cp = concat (current_directory, "/", filename, NULL);
|
||||
free (filename);
|
||||
filename = cp;
|
||||
}
|
||||
|
||||
old_chain = make_cleanup (free, filename);
|
||||
|
||||
/*
|
||||
* gdb doesn't really do anything if the exec-file couldn't
|
||||
* be opened (in that case exec_bfd is NULL). Usually that's
|
||||
* no big deal, but kvm_open needs the exec-file's name,
|
||||
* which results in dereferencing a NULL pointer, a real NO-NO !
|
||||
* So, check here if the open of the exec-file succeeded.
|
||||
*/
|
||||
if (exec_bfd == NULL) /* the open failed */
|
||||
error ("kgdb could not open the exec-file, please check the name you used !");
|
||||
|
||||
core_kd = kvm_open (exec_bfd->filename, filename, NULL,
|
||||
kernel_writablecore? O_RDWR : O_RDONLY, "kgdb: ");
|
||||
if (core_kd < 0)
|
||||
perror_with_name (filename);
|
||||
|
||||
/* Looks semi-reasonable. Toss the old core file and work on the new. */
|
||||
|
||||
discard_cleanups (old_chain); /* Don't free filename any more */
|
||||
core_file = filename;
|
||||
ontop = !push_target (&kcore_ops);
|
||||
|
||||
kernel_start = bfd_get_start_address (exec_bfd); /* XXX */
|
||||
|
||||
/* print out the panic string if there is one */
|
||||
if (kvread (ksym_lookup ("panicstr"), &addr) == 0
|
||||
&& addr != 0
|
||||
&& target_read_memory (addr, buf, sizeof (buf)) == 0)
|
||||
{
|
||||
for (cp = buf; cp < &buf[sizeof (buf)] && *cp; cp++)
|
||||
if (!isascii (*cp) || (!isprint (*cp) && !isspace (*cp)))
|
||||
*cp = '?';
|
||||
*cp = '\0';
|
||||
if (buf[0] != '\0')
|
||||
printf ("panicstr: %s\n", buf);
|
||||
}
|
||||
|
||||
/* Print all the panic messages if possible. */
|
||||
if (symfile_objfile != NULL)
|
||||
{
|
||||
printf ("panic messages:\n---\n");
|
||||
snprintf (buf, sizeof buf,
|
||||
"/sbin/dmesg -N %s -M %s | \
|
||||
/usr/bin/awk '/^(panic:|Fatal trap) / { printing = 1 } \
|
||||
{ if (printing) print $0 }'",
|
||||
symfile_objfile->name, filename);
|
||||
fflush(stdout);
|
||||
system (buf);
|
||||
printf ("---\n");
|
||||
}
|
||||
|
||||
if (!ontop)
|
||||
{
|
||||
warning ("you won't be able to access this core file until you terminate\n\
|
||||
your %s; do ``info files''", target_longname);
|
||||
return;
|
||||
}
|
||||
|
||||
/* we may need this later */
|
||||
cur_proc = (struct proc *)curProc ();
|
||||
/* Now, set up the frame cache, and print the top of stack */
|
||||
flush_cached_frames ();
|
||||
set_current_frame (create_new_frame (read_fp (), read_pc ()));
|
||||
select_frame (get_current_frame (), 0);
|
||||
print_stack_frame (selected_frame, selected_frame_level, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
kcore_detach (args, from_tty)
|
||||
char *args;
|
||||
int from_tty;
|
||||
{
|
||||
if (args)
|
||||
error ("Too many arguments");
|
||||
unpush_target (&kcore_ops);
|
||||
reinit_frame_cache ();
|
||||
if (from_tty)
|
||||
printf_filtered ("No kernel core file now.\n");
|
||||
}
|
||||
|
||||
/* Get the registers out of a core file. This is the machine-
|
||||
independent part. Fetch_core_registers is the machine-dependent
|
||||
part, typically implemented in the xm-file for each architecture. */
|
||||
|
||||
/* We just get all the registers, so we don't use regno. */
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
get_kcore_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
struct user *uaddr;
|
||||
|
||||
/* find the pcb for the current process */
|
||||
if (cur_proc == NULL || kvread (&cur_proc->p_addr, &uaddr))
|
||||
error ("cannot read u area ptr for proc at %#x", cur_proc);
|
||||
if (read_pcb (core_kd, (CORE_ADDR)&uaddr->u_pcb) < 0)
|
||||
error ("cannot read pcb at %#x", &uaddr->u_pcb);
|
||||
}
|
||||
|
||||
static void
|
||||
kcore_files_info (t)
|
||||
struct target_ops *t;
|
||||
{
|
||||
printf ("\t`%s'\n", core_file);
|
||||
}
|
||||
|
||||
static int
|
||||
kcore_xfer_kmem (memaddr, myaddr, len, write, target)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
int write;
|
||||
struct target_ops *target;
|
||||
{
|
||||
int ns;
|
||||
int nu;
|
||||
|
||||
if (memaddr >= (CORE_ADDR)VM_MAXUSER_ADDRESS)
|
||||
nu = 0;
|
||||
else
|
||||
{
|
||||
nu = xfer_umem (memaddr, myaddr, len, write);
|
||||
if (nu <= 0)
|
||||
return (0);
|
||||
if (nu == len)
|
||||
return (nu);
|
||||
memaddr += nu;
|
||||
if (memaddr != (CORE_ADDR)VM_MAXUSER_ADDRESS)
|
||||
return (nu);
|
||||
myaddr += nu;
|
||||
len -= nu;
|
||||
}
|
||||
|
||||
ns = (write ? kvm_write : kvm_read) (core_kd, memaddr, myaddr, len);
|
||||
if (ns < 0)
|
||||
ns = 0;
|
||||
|
||||
return (nu + ns);
|
||||
}
|
||||
|
||||
static int
|
||||
xfer_umem (memaddr, myaddr, len, write)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
int write; /* ignored */
|
||||
{
|
||||
int n;
|
||||
struct proc proc;
|
||||
|
||||
if (cur_proc == NULL || kvread (cur_proc, &proc))
|
||||
error ("cannot read proc at %#x", cur_proc);
|
||||
n = kvm_uread (core_kd, &proc, memaddr, myaddr, len) ;
|
||||
|
||||
if (n < 0)
|
||||
return 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
#define KERNOFF ((unsigned)KERNBASE)
|
||||
#define INKERNEL(x) ((x) >= KERNOFF)
|
||||
|
||||
static CORE_ADDR sbr;
|
||||
static CORE_ADDR curpcb;
|
||||
static int found_pcb;
|
||||
static int devmem;
|
||||
static int kfd;
|
||||
static struct pcb pcb;
|
||||
|
||||
static void
|
||||
set_proc_cmd (arg, from_tty)
|
||||
char *arg;
|
||||
int from_tty;
|
||||
{
|
||||
CORE_ADDR paddr;
|
||||
struct kinfo_proc *kp;
|
||||
int cnt = 0;
|
||||
|
||||
if (!arg)
|
||||
error_no_arg ("proc address for new current process");
|
||||
if (!kernel_debugging)
|
||||
error ("not debugging kernel");
|
||||
|
||||
paddr = (CORE_ADDR)parse_and_eval_address (arg);
|
||||
/* assume it's a proc pointer if it's in the kernel */
|
||||
if (paddr >= kernel_start) {
|
||||
if (set_proc_context(paddr))
|
||||
error("invalid proc address");
|
||||
} else {
|
||||
kp = kvm_getprocs(core_kd, KERN_PROC_PID, paddr, &cnt);
|
||||
if (!cnt)
|
||||
error("invalid pid");
|
||||
if (set_proc_context((CORE_ADDR)kp->ki_paddr))
|
||||
error("invalid proc address");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_cpu_cmd (arg, from_tty)
|
||||
char *arg;
|
||||
int from_tty;
|
||||
{
|
||||
CORE_ADDR paddr;
|
||||
CORE_ADDR pcaddr;
|
||||
struct kinfo_proc *kp;
|
||||
int cpu, cfd;
|
||||
|
||||
if (!arg)
|
||||
error_no_arg ("cpu number");
|
||||
if (!kernel_debugging)
|
||||
error ("not debugging kernel");
|
||||
|
||||
cfd = core_kd;
|
||||
cpu = (int)parse_and_eval_address (arg);
|
||||
if ((pcaddr = kvm_getpcpu (cfd, cpu)) == NULL)
|
||||
error ("cpu number out of range");
|
||||
|
||||
pcpu = pcaddr;
|
||||
curpcb = kvtophys(cfd, pcpu + PCPU_OFFSET (curpcb));
|
||||
physrd (cfd, curpcb, (char*)&curpcb, sizeof curpcb);
|
||||
|
||||
if (!devmem)
|
||||
paddr = ksym_lookup ("dumppcb") - KERNOFF;
|
||||
else
|
||||
paddr = kvtophys (cfd, curpcb);
|
||||
read_pcb (cfd, paddr);
|
||||
printf ("initial pcb at %lx\n", (unsigned long)paddr);
|
||||
|
||||
if ((cur_proc = curProc()))
|
||||
target_fetch_registers (-1);
|
||||
|
||||
/* Now, set up the frame cache, and print the top of stack */
|
||||
flush_cached_frames ();
|
||||
set_current_frame (create_new_frame (read_fp (), read_pc ()));
|
||||
select_frame (get_current_frame (), 0);
|
||||
print_stack_frame (selected_frame, selected_frame_level, 1);
|
||||
}
|
||||
|
||||
/* substitutes for the stuff in libkvm which doesn't work */
|
||||
/* most of this was taken from the old kgdb */
|
||||
|
||||
/* we don't need all this stuff, but the call should look the same */
|
||||
|
||||
static int
|
||||
kvm_open (efile, cfile, sfile, perm, errout)
|
||||
const char *efile;
|
||||
char *cfile;
|
||||
char *sfile; /* makes this kvm_open more compatible to the one in libkvm */
|
||||
int perm;
|
||||
char *errout; /* makes this kvm_open more compatible to the one in libkvm */
|
||||
{
|
||||
struct stat stb;
|
||||
int cfd;
|
||||
CORE_ADDR paddr;
|
||||
|
||||
if ((cfd = open (cfile, perm, 0)) < 0)
|
||||
return (cfd);
|
||||
|
||||
if ((pcpu = kvm_getpcpu (cfd, 0)) == NULL)
|
||||
return (-1);
|
||||
|
||||
fstat (cfd, &stb);
|
||||
if ((stb.st_mode & S_IFMT) == S_IFCHR
|
||||
&& stb.st_rdev == makedev (2, 0))
|
||||
{
|
||||
devmem = 1;
|
||||
kfd = open (_PATH_KMEM, perm, 0);
|
||||
}
|
||||
|
||||
physrd (cfd, ksym_lookup ("IdlePTD") - KERNOFF, (char*)&sbr, sizeof sbr);
|
||||
printf ("IdlePTD %lu\n", (unsigned long)sbr);
|
||||
curpcb = kvtophys(cfd, pcpu + PCPU_OFFSET (curpcb));
|
||||
physrd (cfd, curpcb, (char*)&curpcb, sizeof curpcb);
|
||||
|
||||
found_pcb = 1; /* for vtophys */
|
||||
if (!devmem)
|
||||
paddr = ksym_lookup ("dumppcb") - KERNOFF;
|
||||
else
|
||||
paddr = kvtophys (cfd, curpcb);
|
||||
read_pcb (cfd, paddr);
|
||||
printf ("initial pcb at %lx\n", (unsigned long)paddr);
|
||||
|
||||
return (cfd);
|
||||
}
|
||||
|
||||
static int
|
||||
kvm_close (fd)
|
||||
int fd;
|
||||
{
|
||||
return (close (fd));
|
||||
}
|
||||
|
||||
static int
|
||||
kvm_write (core_kd, memaddr, myaddr, len)
|
||||
int core_kd;
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
{
|
||||
int cc;
|
||||
|
||||
if (devmem)
|
||||
{
|
||||
if (kfd > 0)
|
||||
{
|
||||
/*
|
||||
* Just like kvm_read, only we write.
|
||||
*/
|
||||
errno = 0;
|
||||
if (lseek (kfd, (off_t)memaddr, 0) < 0
|
||||
&& errno != 0)
|
||||
{
|
||||
error ("kvm_write:invalid address (%x)", memaddr);
|
||||
return (0);
|
||||
}
|
||||
cc = write (kfd, myaddr, len);
|
||||
if (cc < 0)
|
||||
{
|
||||
error ("kvm_write:write failed");
|
||||
return (0);
|
||||
}
|
||||
else if (cc < len)
|
||||
error ("kvm_write:short write");
|
||||
return (cc);
|
||||
}
|
||||
else
|
||||
return (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("kvm_write not implemented for dead kernels\n");
|
||||
return (0);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static int
|
||||
kvm_read (core_kd, memaddr, myaddr, len)
|
||||
int core_kd;
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
{
|
||||
return (kernel_core_file_hook (core_kd, memaddr, myaddr, len));
|
||||
}
|
||||
|
||||
static int
|
||||
kvm_uread (core_kd, p, memaddr, myaddr, len)
|
||||
int core_kd;
|
||||
register struct proc *p;
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
{
|
||||
register char *cp;
|
||||
char procfile[MAXPATHLEN];
|
||||
ssize_t amount;
|
||||
int fd;
|
||||
|
||||
if (devmem)
|
||||
{
|
||||
sprintf (procfile, "/proc/%d/mem", p->p_pid);
|
||||
fd = open (procfile, O_RDONLY, 0);
|
||||
if (fd < 0)
|
||||
{
|
||||
error ("cannot open %s", procfile);
|
||||
close (fd);
|
||||
return (0);
|
||||
}
|
||||
|
||||
cp = myaddr;
|
||||
while (len > 0)
|
||||
{
|
||||
errno = 0;
|
||||
if (lseek (fd, (off_t)memaddr, 0) == -1 && errno != 0)
|
||||
{
|
||||
error ("invalid address (%x) in %s", memaddr, procfile);
|
||||
break;
|
||||
}
|
||||
amount = read (fd, cp, len);
|
||||
if (amount < 0)
|
||||
{
|
||||
error ("error reading %s", procfile);
|
||||
break;
|
||||
}
|
||||
if (amount == 0)
|
||||
{
|
||||
error ("EOF reading %s", procfile);
|
||||
break;
|
||||
}
|
||||
cp += amount;
|
||||
memaddr += amount;
|
||||
len -= amount;
|
||||
}
|
||||
|
||||
close (fd);
|
||||
return ((ssize_t) (cp - myaddr));
|
||||
}
|
||||
else
|
||||
return (kernel_core_file_hook (core_kd, memaddr, myaddr, len));
|
||||
}
|
||||
|
||||
static struct kinfo_proc kp;
|
||||
|
||||
/*
|
||||
* try to do what kvm_proclist in libkvm would do
|
||||
*/
|
||||
static int
|
||||
kvm_proclist (cfd, pid, p, cnt)
|
||||
int cfd, pid, *cnt;
|
||||
struct proc *p;
|
||||
{
|
||||
struct proc lp;
|
||||
|
||||
for (; p != NULL; p = LIST_NEXT(&lp, p_list)) {
|
||||
if (!kvm_read(cfd, (CORE_ADDR)p, (char *)&lp, sizeof (lp)))
|
||||
return (0);
|
||||
if (lp.p_pid != pid)
|
||||
continue;
|
||||
kp.ki_paddr = p;
|
||||
*cnt = 1;
|
||||
return (1);
|
||||
}
|
||||
*cnt = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* try to do what kvm_deadprocs in libkvm would do
|
||||
*/
|
||||
static struct kinfo_proc *
|
||||
kvm_deadprocs (cfd, pid, cnt)
|
||||
int cfd, pid, *cnt;
|
||||
{
|
||||
CORE_ADDR allproc, zombproc;
|
||||
struct proc *p;
|
||||
|
||||
allproc = ksym_lookup("allproc");
|
||||
if (kvm_read(cfd, allproc, (char *)&p, sizeof (p)) == 0)
|
||||
return (NULL);
|
||||
kvm_proclist (cfd, pid, p, cnt);
|
||||
if (!*cnt) {
|
||||
zombproc = ksym_lookup("zombproc");
|
||||
if (kvm_read(cfd, zombproc, (char *)&p, sizeof (p)) == 0)
|
||||
return (NULL);
|
||||
kvm_proclist (cfd, pid, p, cnt);
|
||||
}
|
||||
return (&kp);
|
||||
}
|
||||
|
||||
static CORE_ADDR
|
||||
kvm_getpcpu (cfd, cpuid)
|
||||
int cfd, cpuid;
|
||||
{
|
||||
SLIST_HEAD(, globaldata) pcpu_head;
|
||||
struct globaldata lgd;
|
||||
struct globaldata *gd;
|
||||
|
||||
physrd (cfd, ksym_lookup ("cpuhead") - KERNOFF, (char*)&pcpu_head,
|
||||
sizeof pcpu_head);
|
||||
gd = SLIST_FIRST (&pcpu_head);
|
||||
for (; gd != NULL; gd = SLIST_NEXT (&lgd, gd_allcpu))
|
||||
{
|
||||
kvm_read (cfd, (CORE_ADDR)gd, (char*)&lgd, sizeof lgd);
|
||||
if (lgd.gd_cpuid == cpuid)
|
||||
break;
|
||||
}
|
||||
|
||||
return ((CORE_ADDR)gd);
|
||||
}
|
||||
|
||||
/*
|
||||
* try to do what kvm_getprocs in libkvm would do
|
||||
*/
|
||||
static struct kinfo_proc *
|
||||
kvm_getprocs (cfd, op, proc, cnt)
|
||||
int cfd, op, *cnt;
|
||||
CORE_ADDR proc;
|
||||
{
|
||||
int mib[4], size;
|
||||
|
||||
*cnt = 0;
|
||||
/* assume it's a pid */
|
||||
if (devmem) { /* "live" kernel, use sysctl */
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC;
|
||||
mib[2] = KERN_PROC_PID;
|
||||
mib[3] = (int)proc;
|
||||
size = sizeof (kp);
|
||||
if (sysctl (mib, 4, &kp, &size, NULL, 0) < 0) {
|
||||
perror("sysctl");
|
||||
*cnt = 0;
|
||||
return (NULL);
|
||||
}
|
||||
if (!size)
|
||||
*cnt = 0;
|
||||
else
|
||||
*cnt = 1;
|
||||
return (&kp);
|
||||
} else
|
||||
return (kvm_deadprocs (cfd, (int)proc, cnt));
|
||||
}
|
||||
|
||||
static int
|
||||
physrd (cfd, addr, dat, len)
|
||||
int cfd;
|
||||
u_int addr;
|
||||
char *dat;
|
||||
int len;
|
||||
{
|
||||
if (lseek (cfd, (off_t)addr, L_SET) == -1)
|
||||
return (-1);
|
||||
return (read (cfd, dat, len));
|
||||
}
|
||||
|
||||
static CORE_ADDR
|
||||
kvtophys (fd, addr)
|
||||
int fd;
|
||||
CORE_ADDR addr;
|
||||
{
|
||||
CORE_ADDR v;
|
||||
unsigned int pte;
|
||||
static CORE_ADDR PTD = -1;
|
||||
CORE_ADDR current_ptd;
|
||||
|
||||
/*
|
||||
* 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 = kvtophys (fd, ksym_lookup ("PTD"));
|
||||
current_ptd = PTD;
|
||||
}
|
||||
else
|
||||
current_ptd = pcb.pcb_cr3;
|
||||
|
||||
/*
|
||||
* Read the first-level page table (ptd).
|
||||
*/
|
||||
v = current_ptd + ( (unsigned)addr >> PDRSHIFT) * sizeof pte;
|
||||
if (physrd (fd, v, (char *)&pte, sizeof pte) < 0 || (pte&PG_V) == 0)
|
||||
return (~0);
|
||||
|
||||
if (pte & PG_PS)
|
||||
{
|
||||
/*
|
||||
* No second-level page table; ptd describes one 4MB page.
|
||||
* (We assume that the kernel wouldn't set PG_PS without enabling
|
||||
* it cr0, and that the kernel doesn't support 36-bit physical
|
||||
* addresses).
|
||||
*/
|
||||
#define PAGE4M_MASK (NBPDR - 1)
|
||||
#define PG_FRAME4M (~PAGE4M_MASK)
|
||||
addr = (pte & PG_FRAME4M) + (addr & PAGE4M_MASK);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Read the second-level page table.
|
||||
*/
|
||||
v = (pte&PG_FRAME) + ((addr >> PAGE_SHIFT)&(NPTEPG-1)) * sizeof pte;
|
||||
if (physrd (fd, v, (char *) &pte, sizeof (pte)) < 0 || (pte&PG_V) == 0)
|
||||
return (~0);
|
||||
|
||||
addr = (pte & PG_FRAME) + (addr & PAGE_MASK);
|
||||
}
|
||||
#if 0
|
||||
printf ("vtophys (%x) -> %x\n", oldaddr, addr);
|
||||
#endif
|
||||
return (addr);
|
||||
}
|
||||
|
||||
static int
|
||||
read_pcb (fd, uaddr)
|
||||
int fd;
|
||||
CORE_ADDR uaddr;
|
||||
{
|
||||
int i;
|
||||
int noreg;
|
||||
CORE_ADDR nuaddr = uaddr;
|
||||
|
||||
/* need this for the `proc' command to work */
|
||||
if (INKERNEL(uaddr))
|
||||
nuaddr = kvtophys(fd, uaddr);
|
||||
|
||||
if (physrd (fd, nuaddr, (char *)&pcb, sizeof pcb) < 0)
|
||||
{
|
||||
error ("cannot read pcb at %x\n", uaddr);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* get the register values out of the sys pcb and
|
||||
* store them where `read_register' will find them.
|
||||
*/
|
||||
/*
|
||||
* XXX many registers aren't available.
|
||||
* XXX for the non-core case, the registers are stale - they are for
|
||||
* the last context switch to the debugger.
|
||||
* XXX gcc's register numbers aren't all #defined in tm-i386.h.
|
||||
*/
|
||||
noreg = 0;
|
||||
for (i = 0; i < 3; ++i) /* eax,ecx,edx */
|
||||
supply_register (i, (char *)&noreg);
|
||||
supply_register (3, (char *)&pcb.pcb_ebx);
|
||||
supply_register (SP_REGNUM, (char *)&pcb.pcb_esp);
|
||||
supply_register (FP_REGNUM, (char *)&pcb.pcb_ebp);
|
||||
supply_register (6, (char *)&pcb.pcb_esi);
|
||||
supply_register (7, (char *)&pcb.pcb_edi);
|
||||
supply_register (PC_REGNUM, (char *)&pcb.pcb_eip);
|
||||
for (i = 9; i < 14; ++i) /* eflags, cs, ss, ds, es, fs */
|
||||
supply_register (i, (char *)&noreg);
|
||||
supply_register (15, (char *)&pcb.pcb_gs);
|
||||
|
||||
/* XXX 80387 registers? */
|
||||
}
|
||||
|
||||
/*
|
||||
* read len bytes from kernel virtual address 'addr' into local
|
||||
* buffer 'buf'. Return numbert of bytes if read ok, 0 otherwise. On read
|
||||
* errors, portion of buffer not read is zeroed.
|
||||
*/
|
||||
|
||||
static int
|
||||
kernel_core_file_hook (fd, addr, buf, len)
|
||||
int fd;
|
||||
CORE_ADDR addr;
|
||||
char *buf;
|
||||
int len;
|
||||
{
|
||||
int i;
|
||||
CORE_ADDR paddr;
|
||||
register char *cp;
|
||||
int cc;
|
||||
|
||||
cp = buf;
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
paddr = kvtophys (fd, addr);
|
||||
if (paddr == ~0)
|
||||
{
|
||||
memset (buf, '\000', len);
|
||||
break;
|
||||
}
|
||||
/* we can't read across a page boundary */
|
||||
i = min (len, PAGE_SIZE - (addr & PAGE_MASK));
|
||||
if ( (cc = physrd (fd, paddr, cp, i)) <= 0)
|
||||
{
|
||||
memset (cp, '\000', len);
|
||||
return (cp - buf);
|
||||
}
|
||||
cp += cc;
|
||||
addr += cc;
|
||||
len -= cc;
|
||||
}
|
||||
return (cp - buf);
|
||||
}
|
||||
|
||||
static struct target_ops kcore_ops;
|
||||
|
||||
void
|
||||
_initialize_kcorelow()
|
||||
{
|
||||
kcore_ops.to_shortname = "kcore";
|
||||
kcore_ops.to_longname = "Kernel core dump file";
|
||||
kcore_ops.to_doc =
|
||||
"Use a core file as a target. Specify the filename of the core file.";
|
||||
kcore_ops.to_open = kcore_open;
|
||||
kcore_ops.to_close = kcore_close;
|
||||
kcore_ops.to_attach = find_default_attach;
|
||||
kcore_ops.to_detach = kcore_detach;
|
||||
kcore_ops.to_fetch_registers = get_kcore_registers;
|
||||
kcore_ops.to_xfer_memory = kcore_xfer_kmem;
|
||||
kcore_ops.to_files_info = kcore_files_info;
|
||||
kcore_ops.to_create_inferior = find_default_create_inferior;
|
||||
kcore_ops.to_stratum = kcore_stratum;
|
||||
kcore_ops.to_has_memory = 1;
|
||||
kcore_ops.to_has_stack = 1;
|
||||
kcore_ops.to_has_registers = 1;
|
||||
kcore_ops.to_magic = OPS_MAGIC;
|
||||
|
||||
add_target (&kcore_ops);
|
||||
add_com ("proc", class_obscure, set_proc_cmd, "Set current process context");
|
||||
add_com ("cpu", class_obscure, set_cpu_cmd, "Set current cpu");
|
||||
}
|
170
gnu/usr.bin/binutils/gdb5/i386/nm.h
Normal file
170
gnu/usr.bin/binutils/gdb5/i386/nm.h
Normal file
@ -0,0 +1,170 @@
|
||||
/* $FreeBSD$ */
|
||||
/* Native-dependent definitions for Intel 386 running BSD Unix, for GDB.
|
||||
Copyright 1986, 1987, 1989, 1992, 1996 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* $FreeBSD$ */
|
||||
|
||||
#ifndef NM_FREEBSD_H
|
||||
#define NM_FREEBSD_H
|
||||
|
||||
#define ATTACH_DETACH
|
||||
|
||||
/* Be shared lib aware */
|
||||
#include "solib.h"
|
||||
#ifdef FREEBSD_ELF
|
||||
#define SVR4_SHARED_LIBS
|
||||
#endif
|
||||
|
||||
/* This is the amount to subtract from u.u_ar0
|
||||
to get the offset in the core file of the register values. */
|
||||
|
||||
#include <machine/vmparam.h>
|
||||
#define KERNEL_U_ADDR USRSTACK
|
||||
|
||||
#define REGISTER_U_ADDR(addr, blockend, regno) \
|
||||
(addr) = i386_register_u_addr ((blockend),(regno));
|
||||
|
||||
/* We define our own fetch/store methods */
|
||||
#define FETCH_INFERIOR_REGISTERS
|
||||
|
||||
extern int
|
||||
i386_register_u_addr PARAMS ((int, int));
|
||||
|
||||
#define PTRACE_ARG3_TYPE char*
|
||||
|
||||
#ifndef FREEBSD_ELF
|
||||
|
||||
/* make structure definitions match up with those expected in solib.c */
|
||||
#define link_object sod
|
||||
#define lo_name sod_name
|
||||
#define lo_library sod_library
|
||||
#define lo_unused sod_reserved
|
||||
#define lo_major sod_major
|
||||
#define lo_minor sod_minor
|
||||
#define lo_next sod_next
|
||||
|
||||
#define link_map so_map
|
||||
#define lm_addr som_addr
|
||||
#define lm_name som_path
|
||||
#define lm_next som_next
|
||||
#define lm_lop som_sod
|
||||
#define lm_lob som_sodbase
|
||||
#define lm_rwt som_write
|
||||
#define lm_ld som_dynamic
|
||||
#define lm_lpd som_spd
|
||||
|
||||
#define link_dynamic_2 section_dispatch_table
|
||||
#define ld_loaded sdt_loaded
|
||||
#define ld_need sdt_sods
|
||||
#define ld_rules sdt_filler1
|
||||
#define ld_got sdt_got
|
||||
#define ld_plt sdt_plt
|
||||
#define ld_rel sdt_rel
|
||||
#define ld_hash sdt_hash
|
||||
#define ld_stab sdt_nzlist
|
||||
#define ld_stab_hash sdt_filler2
|
||||
#define ld_buckets sdt_buckets
|
||||
#define ld_symbols sdt_strings
|
||||
#define ld_symb_size sdt_str_sz
|
||||
#define ld_text sdt_text_sz
|
||||
#define ld_plt_sz sdt_plt_sz
|
||||
|
||||
#define rtc_symb rt_symbol
|
||||
#define rtc_sp rt_sp
|
||||
#define rtc_next rt_next
|
||||
|
||||
#define ld_debug so_debug
|
||||
#define ldd_version dd_version
|
||||
#define ldd_in_debugger dd_in_debugger
|
||||
#define ldd_sym_loaded dd_sym_loaded
|
||||
#define ldd_bp_addr dd_bpt_addr
|
||||
#define ldd_bp_inst dd_bpt_shadow
|
||||
#define ldd_cp dd_cc
|
||||
|
||||
#define link_dynamic _dynamic
|
||||
#define ld_version d_version
|
||||
#define ldd d_debug
|
||||
#define ld_un d_un
|
||||
#define ld_2 d_sdt
|
||||
|
||||
#endif
|
||||
|
||||
/* Return sizeof user struct to callers in less machine dependent routines */
|
||||
|
||||
#define KERNEL_U_SIZE kernel_u_size()
|
||||
extern int kernel_u_size PARAMS ((void));
|
||||
|
||||
#define ADDITIONAL_OPTIONS \
|
||||
{"kernel", no_argument, &kernel_debugging, 1}, \
|
||||
{"k", no_argument, &kernel_debugging, 1}, \
|
||||
{"wcore", no_argument, &kernel_writablecore, 1}, \
|
||||
{"w", no_argument, &kernel_writablecore, 1},
|
||||
|
||||
#define ADDITIONAL_OPTION_HELP \
|
||||
"\
|
||||
--kernel Enable kernel debugging.\n\
|
||||
--wcore Make core file writable (only works for /dev/mem).\n\
|
||||
This option only works while debugging a kernel !!\n\
|
||||
"
|
||||
|
||||
extern int kernel_debugging;
|
||||
extern int kernel_writablecore;
|
||||
|
||||
#define DEFAULT_PROMPT kernel_debugging?"(kgdb) ":"(gdb) "
|
||||
|
||||
/* misuse START_PROGRESS to test whether we're running as kgdb */
|
||||
/* START_PROGRESS is called at the top of main */
|
||||
#undef START_PROGRESS
|
||||
#define START_PROGRESS(STR,N) \
|
||||
if (!strcmp(STR, "kgdb")) \
|
||||
kernel_debugging = 1;
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ptrace.h>
|
||||
|
||||
#ifdef PT_GETDBREGS
|
||||
#define TARGET_HAS_HARDWARE_WATCHPOINTS
|
||||
|
||||
extern int can_watch PARAMS((int type, int cnt, int othertype));
|
||||
extern int stopped_by_watchpoint PARAMS((void));
|
||||
extern int insert_watchpoint PARAMS((int addr, int len, int type));
|
||||
extern int remove_watchpoint PARAMS((int addr, int len, int type));
|
||||
|
||||
#define TARGET_CAN_USE_HARDWARE_WATCHPOINT(type, cnt, ot) \
|
||||
can_watch(type, cnt, ot)
|
||||
|
||||
/* After a watchpoint trap, the PC points to the instruction after
|
||||
the one that caused the trap. Therefore we don't need to step over it.
|
||||
But we do need to reset the status register to avoid another trap. */
|
||||
#define HAVE_CONTINUABLE_WATCHPOINT
|
||||
|
||||
#define STOPPED_BY_WATCHPOINT(W) \
|
||||
stopped_by_watchpoint()
|
||||
|
||||
/* Use these macros for watchpoint insertion/removal. */
|
||||
|
||||
#define target_insert_watchpoint(addr, len, type) \
|
||||
insert_watchpoint(addr, len, type)
|
||||
|
||||
#define target_remove_watchpoint(addr, len, type) \
|
||||
remove_watchpoint(addr, len, type)
|
||||
|
||||
#endif /* PT_GETDBREGS */
|
||||
|
||||
#endif /* NM_FREEBSD_H */
|
66
gnu/usr.bin/binutils/gdb5/i386/tm.h
Normal file
66
gnu/usr.bin/binutils/gdb5/i386/tm.h
Normal file
@ -0,0 +1,66 @@
|
||||
/* $FreeBSD$ */
|
||||
/* Target macro definitions for i386 running FreeBSD
|
||||
Copyright (C) 1997 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. */
|
||||
|
||||
#ifndef TM_FBSD_H
|
||||
#define TM_FBSD_H 1
|
||||
|
||||
#include "i386/tm-i386bsd.h"
|
||||
|
||||
#undef NUM_REGS
|
||||
#define NUM_REGS 16
|
||||
|
||||
extern struct frame_info *setup_arbitrary_frame PARAMS ((int, CORE_ADDR *));
|
||||
|
||||
#define SETUP_ARBITRARY_FRAME(argc, argv) setup_arbitrary_frame (argc, argv)
|
||||
|
||||
extern void i386_float_info PARAMS ((void));
|
||||
|
||||
#define FLOAT_INFO i386_float_info ()
|
||||
|
||||
#define IN_SOLIB_CALL_TRAMPOLINE(pc, name) STREQ (name, "_DYNAMIC")
|
||||
|
||||
/* Saved Pc. Get it from sigcontext if within sigtramp. */
|
||||
|
||||
extern CORE_ADDR fbsd_kern_frame_saved_pc (struct frame_info *);
|
||||
#undef FRAME_SAVED_PC
|
||||
#define FRAME_SAVED_PC(FRAME) \
|
||||
(kernel_debugging ? fbsd_kern_frame_saved_pc(FRAME) : \
|
||||
(((FRAME)->signal_handler_caller \
|
||||
? sigtramp_saved_pc (FRAME) \
|
||||
: read_memory_integer ((FRAME)->frame + 4, 4)) \
|
||||
))
|
||||
|
||||
/* On FreeBSD, sigtramp has size 0x18 and is immediately below the
|
||||
ps_strings struct which has size 0x10 and is at the top of the
|
||||
user stack. */
|
||||
|
||||
#undef SIGTRAMP_START
|
||||
#undef SIGTRAMP_END
|
||||
#define SIGTRAMP_START(pc) 0xbfbfdfd8
|
||||
#define SIGTRAMP_END(pc) 0xbfbfdff0
|
||||
|
||||
struct objfile;
|
||||
void freebsd_uthread_new_objfile PARAMS ((struct objfile *objfile));
|
||||
#define target_new_objfile(OBJFILE) freebsd_uthread_new_objfile (OBJFILE)
|
||||
|
||||
extern char *freebsd_uthread_pid_to_str PARAMS ((int pid));
|
||||
#define target_pid_to_str(PID) freebsd_uthread_pid_to_str (PID)
|
||||
|
||||
#endif /* ifndef TM_FBSD_H */
|
5
gnu/usr.bin/binutils/gdb5/i386/version.c
Normal file
5
gnu/usr.bin/binutils/gdb5/i386/version.c
Normal file
@ -0,0 +1,5 @@
|
||||
/* $FreeBSD$ */
|
||||
|
||||
char *version = "4.18";
|
||||
char *host_name = "i386-unknown-freebsd";
|
||||
char *target_name = "i386-unknown-freebsd";
|
25
gnu/usr.bin/binutils/gdb5/i386/xm.h
Normal file
25
gnu/usr.bin/binutils/gdb5/i386/xm.h
Normal file
@ -0,0 +1,25 @@
|
||||
/* Host-dependent definitions for Intel 386 running BSD Unix, for GDB.
|
||||
Copyright 1986, 1987, 1989, 1992 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* $FreeBSD$ */
|
||||
|
||||
#define HOST_BYTE_ORDER LITTLE_ENDIAN
|
||||
|
||||
#include <machine/limits.h> /* for INT_MIN, to avoid "INT_MIN
|
||||
redefined" warnings from defs.h */
|
23
gnu/usr.bin/binutils/gdbreplay5/Makefile
Normal file
23
gnu/usr.bin/binutils/gdbreplay5/Makefile
Normal file
@ -0,0 +1,23 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.include "../Makefile.inc0"
|
||||
|
||||
# Not elf specific so don't install in /usr/libexec/elf
|
||||
BINDIR=/usr/bin
|
||||
|
||||
GDBDIR= ${.CURDIR}/../../../../contrib/gdb.291
|
||||
.PATH: ${GDBDIR}/gdb/gdbserver
|
||||
.PATH: ${GDBDIR}/gdb
|
||||
|
||||
PROG= gdbreplay
|
||||
NOMAN= yes
|
||||
|
||||
SRCS= gdbreplay.c
|
||||
|
||||
CFLAGS+= -I${.CURDIR}/../gdb/${MACHINE_ARCH}
|
||||
CFLAGS+= -I${GDBDIR}/gdb
|
||||
CFLAGS+= -I${GDBDIR}/gdb/config
|
||||
CFLAGS+= -I${GDBDIR}/gdb/gdbserver
|
||||
CFLAGS+= -DNO_MMALLOC
|
||||
|
||||
.include <bsd.prog.mk>
|
23
gnu/usr.bin/binutils/gdbserver5/Makefile
Normal file
23
gnu/usr.bin/binutils/gdbserver5/Makefile
Normal file
@ -0,0 +1,23 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.include "../Makefile.inc0"
|
||||
|
||||
# Not elf specific so don't install in /usr/libexec/elf
|
||||
BINDIR=/usr/bin
|
||||
|
||||
GDBDIR= ${.CURDIR}/../../../../contrib/gdb.291
|
||||
.PATH: ${GDBDIR}/gdb/gdbserver
|
||||
.PATH: ${GDBDIR}/gdb
|
||||
|
||||
PROG= gdbserver
|
||||
|
||||
SRCS= remote-utils.c utils.c server.c
|
||||
SRCS+= low-fbsd.c
|
||||
|
||||
CFLAGS+= -I${.CURDIR}/../gdb/${MACHINE_ARCH}
|
||||
CFLAGS+= -I${GDBDIR}/gdb
|
||||
CFLAGS+= -I${GDBDIR}/gdb/config
|
||||
CFLAGS+= -I${GDBDIR}/gdb/gdbserver
|
||||
CFLAGS+= -DNO_MMALLOC
|
||||
|
||||
.include <bsd.prog.mk>
|
341
gnu/usr.bin/binutils/gdbserver5/low-fbsd.c
Normal file
341
gnu/usr.bin/binutils/gdbserver5/low-fbsd.c
Normal file
@ -0,0 +1,341 @@
|
||||
/* Low level interface to ptrace, for the remote server for GDB.
|
||||
Copyright (C) 1995 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* $FreeBSD$ */
|
||||
|
||||
#include "defs.h"
|
||||
#include <sys/wait.h>
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/param.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/user.h>
|
||||
#include <signal.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sgtty.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
/***************Begin MY defs*********************/
|
||||
int quit_flag = 0;
|
||||
char registers[REGISTER_BYTES];
|
||||
|
||||
/* Index within `registers' of the first byte of the space for
|
||||
register N. */
|
||||
|
||||
|
||||
char buf2[MAX_REGISTER_RAW_SIZE];
|
||||
/***************End MY defs*********************/
|
||||
|
||||
#include <sys/ptrace.h>
|
||||
#include <machine/reg.h>
|
||||
|
||||
extern char **environ;
|
||||
extern int inferior_pid;
|
||||
void quit (), perror_with_name ();
|
||||
int query ();
|
||||
|
||||
/* Start an inferior process and returns its pid.
|
||||
ALLARGS is a vector of program-name and args.
|
||||
ENV is the environment vector to pass. */
|
||||
|
||||
int
|
||||
create_inferior (program, allargs)
|
||||
char *program;
|
||||
char **allargs;
|
||||
{
|
||||
int pid;
|
||||
|
||||
pid = fork ();
|
||||
if (pid < 0)
|
||||
perror_with_name ("fork");
|
||||
|
||||
if (pid == 0)
|
||||
{
|
||||
ptrace (PT_TRACE_ME, 0, 0, 0);
|
||||
|
||||
execv (program, allargs);
|
||||
|
||||
fprintf (stderr, "Cannot exec %s: %s.\n", program, strerror(errno));
|
||||
fflush (stderr);
|
||||
_exit (0177);
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
/* Kill the inferior process. Make us have no inferior. */
|
||||
|
||||
void
|
||||
kill_inferior ()
|
||||
{
|
||||
if (inferior_pid == 0)
|
||||
return;
|
||||
ptrace (PT_KILL, inferior_pid, 0, 0);
|
||||
wait (0);
|
||||
/*************inferior_died ();****VK**************/
|
||||
}
|
||||
|
||||
/* Return nonzero if the given thread is still alive. */
|
||||
int
|
||||
mythread_alive (pid)
|
||||
int pid;
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Wait for process, returns status */
|
||||
|
||||
unsigned char
|
||||
mywait (status)
|
||||
char *status;
|
||||
{
|
||||
int pid;
|
||||
int w;
|
||||
|
||||
pid = wait (&w);
|
||||
if (pid != inferior_pid)
|
||||
perror_with_name ("wait");
|
||||
|
||||
if (WIFEXITED (w))
|
||||
{
|
||||
fprintf (stderr, "\nChild exited with retcode = %x \n", WEXITSTATUS (w));
|
||||
*status = 'W';
|
||||
return ((unsigned char) WEXITSTATUS (w));
|
||||
}
|
||||
else if (!WIFSTOPPED (w))
|
||||
{
|
||||
fprintf (stderr, "\nChild terminated with signal = %x \n", WTERMSIG (w));
|
||||
*status = 'X';
|
||||
return ((unsigned char) WTERMSIG (w));
|
||||
}
|
||||
|
||||
fetch_inferior_registers (0);
|
||||
|
||||
*status = 'T';
|
||||
return ((unsigned char) WSTOPSIG (w));
|
||||
}
|
||||
|
||||
/* Resume execution of the inferior process.
|
||||
If STEP is nonzero, single-step it.
|
||||
If SIGNAL is nonzero, give it that signal. */
|
||||
|
||||
void
|
||||
myresume (step, signal)
|
||||
int step;
|
||||
int signal;
|
||||
{
|
||||
errno = 0;
|
||||
ptrace (step ? PT_STEP : PT_CONTINUE, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) 1, signal);
|
||||
if (errno)
|
||||
perror_with_name ("ptrace");
|
||||
}
|
||||
|
||||
#if defined(__i386__)
|
||||
|
||||
/* this table must line up with REGISTER_NAMES in tm-i386v.h */
|
||||
/* symbols like 'tEAX' come from <machine/reg.h> */
|
||||
static int tregmap[] =
|
||||
{
|
||||
tEAX, tECX, tEDX, tEBX,
|
||||
tESP, tEBP, tESI, tEDI,
|
||||
tEIP, tEFLAGS, tCS, tSS,
|
||||
tDS, tES, tFS, tGS,
|
||||
};
|
||||
|
||||
static struct save87 pcb_savefpu;
|
||||
|
||||
void
|
||||
fetch_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
struct reg inferior_registers; /* ptrace order, not gcc/gdb order */
|
||||
int r;
|
||||
|
||||
ptrace (PT_GETREGS, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) &inferior_registers, 0);
|
||||
|
||||
for (r = 0; r < NUM_REGS; r++)
|
||||
memcpy (®isters[REGISTER_BYTE (r)], ((int *)&inferior_registers) + tregmap[r], 4);
|
||||
}
|
||||
|
||||
void
|
||||
store_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
struct reg inferior_registers; /* ptrace order, not gcc/gdb order */
|
||||
int r;
|
||||
|
||||
ptrace (PT_GETREGS, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) &inferior_registers, 0);
|
||||
|
||||
for (r = 0; r < NUM_REGS; r++)
|
||||
memcpy (((int *)&inferior_registers) + tregmap[r], ®isters[REGISTER_BYTE (r)], 4);
|
||||
|
||||
ptrace (PT_SETREGS, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) &inferior_registers, 0);
|
||||
}
|
||||
|
||||
#elif defined(__alpha__)
|
||||
|
||||
void
|
||||
fetch_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
struct reg regs; /* ptrace order, not gcc/gdb order */
|
||||
struct fpreg fpregs;
|
||||
int r;
|
||||
|
||||
ptrace (PT_GETREGS, inferior_pid, (PTRACE_ARG3_TYPE) ®s, 0);
|
||||
ptrace (PT_GETFPREGS, inferior_pid, (PTRACE_ARG3_TYPE) &fpregs, 0);
|
||||
|
||||
for (r = 0; r < 31; r++)
|
||||
memcpy (®isters[REGISTER_BYTE (r)],
|
||||
®s.r_regs[r], sizeof(u_int64_t));
|
||||
for (r = 0; r < 32; r++)
|
||||
memcpy (®isters[REGISTER_BYTE (r + FP0_REGNUM)],
|
||||
&fpregs.fpr_regs[r], sizeof(u_int64_t));
|
||||
memcpy (®isters[REGISTER_BYTE (PC_REGNUM)],
|
||||
®s.r_regs[31], sizeof(u_int64_t));
|
||||
|
||||
memset (®isters[REGISTER_BYTE (ZERO_REGNUM)], 0, sizeof(u_int64_t));
|
||||
memset (®isters[REGISTER_BYTE (FP_REGNUM)], 0, sizeof(u_int64_t));
|
||||
}
|
||||
|
||||
void
|
||||
store_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
struct reg regs; /* ptrace order, not gcc/gdb order */
|
||||
struct fpreg fpregs;
|
||||
int r;
|
||||
|
||||
for (r = 0; r < 31; r++)
|
||||
memcpy (®s.r_regs[r],
|
||||
®isters[REGISTER_BYTE (r)], sizeof(u_int64_t));
|
||||
for (r = 0; r < 32; r++)
|
||||
memcpy (&fpregs.fpr_regs[r],
|
||||
®isters[REGISTER_BYTE (r + FP0_REGNUM)], sizeof(u_int64_t));
|
||||
memcpy (®s.r_regs[31],
|
||||
®isters[REGISTER_BYTE (PC_REGNUM)], sizeof(u_int64_t));
|
||||
|
||||
ptrace (PT_SETREGS, inferior_pid, (PTRACE_ARG3_TYPE) ®s, 0);
|
||||
ptrace (PT_SETFPREGS, inferior_pid, (PTRACE_ARG3_TYPE) &fpregs, 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory
|
||||
in the NEW_SUN_PTRACE case.
|
||||
It ought to be straightforward. But it appears that writing did
|
||||
not write the data that I specified. I cannot understand where
|
||||
it got the data that it actually did write. */
|
||||
|
||||
/* Copy LEN bytes from inferior's memory starting at MEMADDR
|
||||
to debugger memory starting at MYADDR. */
|
||||
|
||||
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));
|
||||
|
||||
/* Read all the longwords */
|
||||
for (i = 0; i < count; i++, addr += sizeof (int))
|
||||
{
|
||||
buffer[i] = ptrace (PT_READ_I, inferior_pid, (PTRACE_ARG3_TYPE) addr, 0);
|
||||
}
|
||||
|
||||
/* Copy appropriate bytes out of the buffer. */
|
||||
memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
||||
buffer[0] = ptrace (PT_READ_I, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) addr, 0);
|
||||
|
||||
if (count > 1)
|
||||
{
|
||||
buffer[count - 1]
|
||||
= ptrace (PT_READ_I, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) addr + (count - 1) * sizeof (int), 0);
|
||||
}
|
||||
|
||||
/* Copy data to be written over corresponding part of buffer */
|
||||
|
||||
memcpy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
|
||||
|
||||
/* Write the entire buffer. */
|
||||
|
||||
for (i = 0; i < count; i++, addr += sizeof (int))
|
||||
{
|
||||
errno = 0;
|
||||
ptrace (PT_WRITE_I, inferior_pid, (PTRACE_ARG3_TYPE) addr, buffer[i]);
|
||||
if (errno)
|
||||
return errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
initialize ()
|
||||
{
|
||||
inferior_pid = 0;
|
||||
}
|
||||
|
||||
int
|
||||
have_inferior_p ()
|
||||
{
|
||||
return inferior_pid != 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user