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:
David E. O'Brien 2001-03-25 02:20:37 +00:00
parent 16004197c4
commit 3547b75e97
21 changed files with 4714 additions and 0 deletions

View 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>

View File

@ -0,0 +1,8 @@
#
# $FreeBSD$
#
XSRCS+= freebsd-nat.c alpha-tdep.c kvm-fbsd.c
LDADD+= -lkvm
.PATH: ${.CURDIR}/alpha

View File

@ -0,0 +1,7 @@
#
# $FreeBSD$
#
XSRCS+= freebsd-nat.c i386-tdep.c i387-tdep.c kvm-fbsd.c
.PATH: ${.CURDIR}/i386

View File

@ -0,0 +1,8 @@
#
# $FreeBSD$
#
XSRCS+= freebsd-nat.c ia64-tdep.c kvm-fbsd.c
LDADD+= -lkvm
.PATH: ${.CURDIR}/ia64

View 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) &regs, 0);
ptrace (PT_GETFPREGS, inferior_pid, (PTRACE_ARG3_TYPE) &fpregs, 0);
for (r = 0; r < 31; r++)
memcpy (&registers[REGISTER_BYTE (r)],
&regs.r_regs[r], sizeof(u_int64_t));
for (r = 0; r < 32; r++)
memcpy (&registers[REGISTER_BYTE (r + FP0_REGNUM)],
&fpregs.fpr_regs[r], sizeof(u_int64_t));
memcpy (&registers[REGISTER_BYTE (PC_REGNUM)],
&regs.r_regs[31], sizeof(u_int64_t));
memset (&registers[REGISTER_BYTE (ZERO_REGNUM)], 0, sizeof(u_int64_t));
memset (&registers[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 (&regs.r_regs[r],
&registers[REGISTER_BYTE (r)], sizeof(u_int64_t));
for (r = 0; r < 32; r++)
memcpy (&fpregs.fpr_regs[r],
&registers[REGISTER_BYTE (r + FP0_REGNUM)], sizeof(u_int64_t));
memcpy (&regs.r_regs[31],
&registers[REGISTER_BYTE (PC_REGNUM)], sizeof(u_int64_t));
ptrace (PT_SETREGS, inferior_pid, (PTRACE_ARG3_TYPE) &regs, 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 *) &registers[REGISTER_BYTE (SP_REGNUM)] =
pcbp->pcb_hw.apcb_ksp;
/* S0 through S6 */
memcpy (&registers[REGISTER_BYTE (S0_REGNUM)],
&pcbp->pcb_context[0], 7 * sizeof(long));
/* PC */
*(long *) &registers[REGISTER_BYTE (PC_REGNUM)] =
pcbp->pcb_context[7];
registers_fetched ();
}

View 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");
}

View 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;

View 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 */

View File

@ -0,0 +1,5 @@
/* $FreeBSD$ */
char *version = "4.18";
char *host_name = "alpha-unknown-freebsd";
char *target_name = "alpha-unknown-freebsd";

View 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>

View 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

File diff suppressed because it is too large Load Diff

View 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 (&registers[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], &registers[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 */

View 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");
}

View 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 */

View 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 */

View File

@ -0,0 +1,5 @@
/* $FreeBSD$ */
char *version = "4.18";
char *host_name = "i386-unknown-freebsd";
char *target_name = "i386-unknown-freebsd";

View 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 */

View 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>

View 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>

View 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 (&registers[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], &registers[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) &regs, 0);
ptrace (PT_GETFPREGS, inferior_pid, (PTRACE_ARG3_TYPE) &fpregs, 0);
for (r = 0; r < 31; r++)
memcpy (&registers[REGISTER_BYTE (r)],
&regs.r_regs[r], sizeof(u_int64_t));
for (r = 0; r < 32; r++)
memcpy (&registers[REGISTER_BYTE (r + FP0_REGNUM)],
&fpregs.fpr_regs[r], sizeof(u_int64_t));
memcpy (&registers[REGISTER_BYTE (PC_REGNUM)],
&regs.r_regs[31], sizeof(u_int64_t));
memset (&registers[REGISTER_BYTE (ZERO_REGNUM)], 0, sizeof(u_int64_t));
memset (&registers[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 (&regs.r_regs[r],
&registers[REGISTER_BYTE (r)], sizeof(u_int64_t));
for (r = 0; r < 32; r++)
memcpy (&fpregs.fpr_regs[r],
&registers[REGISTER_BYTE (r + FP0_REGNUM)], sizeof(u_int64_t));
memcpy (&regs.r_regs[31],
&registers[REGISTER_BYTE (PC_REGNUM)], sizeof(u_int64_t));
ptrace (PT_SETREGS, inferior_pid, (PTRACE_ARG3_TYPE) &regs, 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;
}