diff options
Diffstat (limited to 'gdb/x86-bsd-nat.c')
-rw-r--r-- | gdb/x86-bsd-nat.c | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/gdb/x86-bsd-nat.c b/gdb/x86-bsd-nat.c new file mode 100644 index 0000000..1998476 --- /dev/null +++ b/gdb/x86-bsd-nat.c @@ -0,0 +1,156 @@ +/* Native-dependent code for X86 BSD's. + + Copyright (C) 2003-2016 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 3 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, see <http://www.gnu.org/licenses/>. */ + +#include "defs.h" +#include "inferior.h" +#include "gdbthread.h" + +/* We include <signal.h> to make sure `struct fxsave64' is defined on + NetBSD, since NetBSD's <machine/reg.h> needs it. */ +#include <signal.h> +#include <sys/types.h> +#include <sys/ptrace.h> +#include <machine/reg.h> + +#include "x86-nat.h" +#include "x86-bsd-nat.h" +#include "inf-ptrace.h" + + +#ifdef PT_GETXSTATE_INFO +size_t x86bsd_xsave_len; +#endif + +/* Support for debug registers. */ + +#ifdef HAVE_PT_GETDBREGS +static void (*super_mourn_inferior) (struct target_ops *ops); + +/* Implement the "to_mourn_inferior" target_ops method. */ + +static void +x86bsd_mourn_inferior (struct target_ops *ops) +{ + x86_cleanup_dregs (); + super_mourn_inferior (ops); +} + +/* Not all versions of FreeBSD/i386 that support the debug registers + have this macro. */ +#ifndef DBREG_DRX +#define DBREG_DRX(d, x) ((&d->dr0)[x]) +#endif + +static unsigned long +x86bsd_dr_get (ptid_t ptid, int regnum) +{ + struct dbreg dbregs; + + if (ptrace (PT_GETDBREGS, get_ptrace_pid (inferior_ptid), + (PTRACE_TYPE_ARG3) &dbregs, 0) == -1) + perror_with_name (_("Couldn't read debug registers")); + + return DBREG_DRX ((&dbregs), regnum); +} + +static void +x86bsd_dr_set (int regnum, unsigned long value) +{ + struct thread_info *thread; + struct dbreg dbregs; + + if (ptrace (PT_GETDBREGS, get_ptrace_pid (inferior_ptid), + (PTRACE_TYPE_ARG3) &dbregs, 0) == -1) + perror_with_name (_("Couldn't get debug registers")); + + /* For some mysterious reason, some of the reserved bits in the + debug control register get set. Mask these off, otherwise the + ptrace call below will fail. */ + DBREG_DRX ((&dbregs), 7) &= ~(0xffffffff0000fc00); + + DBREG_DRX ((&dbregs), regnum) = value; + + ALL_NON_EXITED_THREADS (thread) + if (thread->inf == current_inferior ()) + { + if (ptrace (PT_SETDBREGS, get_ptrace_pid (thread->ptid), + (PTRACE_TYPE_ARG3) &dbregs, 0) == -1) + perror_with_name (_("Couldn't write debug registers")); + } +} + +static void +x86bsd_dr_set_control (unsigned long control) +{ + x86bsd_dr_set (7, control); +} + +static void +x86bsd_dr_set_addr (int regnum, CORE_ADDR addr) +{ + gdb_assert (regnum >= 0 && regnum <= 4); + + x86bsd_dr_set (regnum, addr); +} + +static CORE_ADDR +x86bsd_dr_get_addr (int regnum) +{ + return x86bsd_dr_get (inferior_ptid, regnum); +} + +static unsigned long +x86bsd_dr_get_status (void) +{ + return x86bsd_dr_get (inferior_ptid, 6); +} + +static unsigned long +x86bsd_dr_get_control (void) +{ + return x86bsd_dr_get (inferior_ptid, 7); +} + +#endif /* PT_GETDBREGS */ + +/* Create a prototype *BSD/x86 target. The client can override it + with local methods. */ + +struct target_ops * +x86bsd_target (void) +{ + struct target_ops *t; + + t = inf_ptrace_target (); + +#ifdef HAVE_PT_GETDBREGS + x86_use_watchpoints (t); + + x86_dr_low.set_control = x86bsd_dr_set_control; + x86_dr_low.set_addr = x86bsd_dr_set_addr; + x86_dr_low.get_addr = x86bsd_dr_get_addr; + x86_dr_low.get_status = x86bsd_dr_get_status; + x86_dr_low.get_control = x86bsd_dr_get_control; + x86_set_debug_register_length (sizeof (void *)); + super_mourn_inferior = t->to_mourn_inferior; + t->to_mourn_inferior = x86bsd_mourn_inferior; +#endif /* HAVE_PT_GETDBREGS */ + + return t; +} |