/* PPC GNU/Linux native support.
- Copyright (C) 1988-2014 Free Software Foundation, Inc.
+ Copyright (C) 1988-2017 Free Software Foundation, Inc.
This file is part of GDB.
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
-#include <string.h>
#include "observer.h"
#include "frame.h"
#include "inferior.h"
#include "gdbthread.h"
#include "gdbcore.h"
#include "regcache.h"
-#include "gdb_assert.h"
#include "target.h"
#include "linux-nat.h"
-
-#include <stdint.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/user.h>
#include "gdb_wait.h"
#include <fcntl.h>
#include <sys/procfs.h>
-#include <sys/ptrace.h>
+#include "nat/gdb_ptrace.h"
+#include "inf-ptrace.h"
/* Prototypes for supply_gregset etc. */
#include "gregset.h"
#include "elf/common.h"
#include "auxv.h"
-/* This sometimes isn't defined. */
-#ifndef PT_ORIG_R3
-#define PT_ORIG_R3 34
-#endif
-#ifndef PT_TRAP
-#define PT_TRAP 40
-#endif
-
-/* The PPC_FEATURE_* defines should be provided by <asm/cputable.h>.
- If they aren't, we can provide them ourselves (their values are fixed
- because they are part of the kernel ABI). They are used in the AT_HWCAP
- entry of the AUXV. */
-#ifndef PPC_FEATURE_CELL
-#define PPC_FEATURE_CELL 0x00010000
-#endif
-#ifndef PPC_FEATURE_BOOKE
-#define PPC_FEATURE_BOOKE 0x00008000
-#endif
-#ifndef PPC_FEATURE_HAS_DFP
-#define PPC_FEATURE_HAS_DFP 0x00000400 /* Decimal Floating Point. */
-#endif
-
-/* Glibc's headers don't define PTRACE_GETVRREGS so we cannot use a
- configure time check. Some older glibc's (for instance 2.2.1)
- don't have a specific powerpc version of ptrace.h, and fall back on
- a generic one. In such cases, sys/ptrace.h defines
- PTRACE_GETFPXREGS and PTRACE_SETFPXREGS to the same numbers that
- ppc kernel's asm/ptrace.h defines PTRACE_GETVRREGS and
- PTRACE_SETVRREGS to be. This also makes a configury check pretty
- much useless. */
-
-/* These definitions should really come from the glibc header files,
- but Glibc doesn't know about the vrregs yet. */
-#ifndef PTRACE_GETVRREGS
-#define PTRACE_GETVRREGS 18
-#define PTRACE_SETVRREGS 19
-#endif
-
-/* PTRACE requests for POWER7 VSX registers. */
-#ifndef PTRACE_GETVSXREGS
-#define PTRACE_GETVSXREGS 27
-#define PTRACE_SETVSXREGS 28
-#endif
-
-/* Similarly for the ptrace requests for getting / setting the SPE
- registers (ev0 -- ev31, acc, and spefscr). See the description of
- gdb_evrregset_t for details. */
-#ifndef PTRACE_GETEVRREGS
-#define PTRACE_GETEVRREGS 20
-#define PTRACE_SETEVRREGS 21
-#endif
+#include "nat/ppc-linux.h"
/* Similarly for the hardware watchpoint support. These requests are used
when the PowerPC HWDEBUG ptrace interface is not available. */
ppc_linux_fetch_inferior_registers (struct target_ops *ops,
struct regcache *regcache, int regno)
{
- /* Overload thread id onto process id. */
- int tid = ptid_get_lwp (inferior_ptid);
-
- /* No thread id, just use process id. */
- if (tid == 0)
- tid = ptid_get_pid (inferior_ptid);
+ pid_t tid = get_ptrace_pid (regcache_get_ptid (regcache));
if (regno == -1)
fetch_ppc_registers (regcache, tid);
static int
ppc_linux_can_use_hw_breakpoint (struct target_ops *self,
- int type, int cnt, int ot)
+ enum bptype type, int cnt, int ot)
{
int total_hw_wp, total_hw_bp;
}
else if (type == bp_hardware_breakpoint)
{
+ if (total_hw_bp == 0)
+ {
+ /* No hardware breakpoint support. */
+ return 0;
+ }
if (cnt > total_hw_bp)
return -1;
}
}
static int
-ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
+ppc_linux_region_ok_for_hw_watchpoint (struct target_ops *self,
+ CORE_ADDR addr, int len)
{
/* Handle sub-8-byte quantities. */
if (len <= 0)
if the wanted one does not exist? */
if (alloc_new)
{
- t = xmalloc (sizeof (struct thread_points));
- t->hw_breaks
- = xzalloc (max_slots_number * sizeof (struct hw_break_tuple));
+ t = XNEW (struct thread_points);
+ t->hw_breaks = XCNEWVEC (struct hw_break_tuple, max_slots_number);
t->tid = tid;
VEC_safe_push (thread_points_p, ppc_threads, t);
}
{
int i;
long slot;
- struct ppc_hw_breakpoint *p = xmalloc (sizeof (struct ppc_hw_breakpoint));
+ struct ppc_hw_breakpoint *p = XNEW (struct ppc_hw_breakpoint);
struct hw_break_tuple *hw_breaks;
struct cleanup *c = make_cleanup (xfree, p);
struct thread_points *t;
p.version = PPC_DEBUG_CURRENT_VERSION;
p.trigger_type = PPC_BREAKPOINT_TRIGGER_EXECUTE;
p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
- p.addr = (uint64_t) bp_tgt->placed_address;
+ p.addr = (uint64_t) (bp_tgt->placed_address = bp_tgt->reqstd_address);
p.condition_value = 0;
if (bp_tgt->length)
}
static int
-ppc_linux_remove_hw_breakpoint (struct gdbarch *gdbarch,
+ppc_linux_remove_hw_breakpoint (struct target_ops *self,
+ struct gdbarch *gdbarch,
struct bp_target_info *bp_tgt)
{
struct lwp_info *lp;
}
static int
-get_trigger_type (int rw)
+get_trigger_type (enum target_hw_bp_type type)
{
int t;
- if (rw == hw_read)
+ if (type == hw_read)
t = PPC_BREAKPOINT_TRIGGER_READ;
- else if (rw == hw_write)
+ else if (type == hw_write)
t = PPC_BREAKPOINT_TRIGGER_WRITE;
else
t = PPC_BREAKPOINT_TRIGGER_READ | PPC_BREAKPOINT_TRIGGER_WRITE;
static int
ppc_linux_insert_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr,
- CORE_ADDR mask, int rw)
+ CORE_ADDR mask, enum target_hw_bp_type rw)
{
struct lwp_info *lp;
struct ppc_hw_breakpoint p;
static int
ppc_linux_remove_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr,
- CORE_ADDR mask, int rw)
+ CORE_ADDR mask, enum target_hw_bp_type rw)
{
struct lwp_info *lp;
struct ppc_hw_breakpoint p;
the condition expression, thus only triggering the watchpoint when it is
true. */
static int
-ppc_linux_can_accel_watchpoint_condition (CORE_ADDR addr, int len, int rw,
+ppc_linux_can_accel_watchpoint_condition (struct target_ops *self,
+ CORE_ADDR addr, int len, int rw,
struct expression *cond)
{
CORE_ADDR data_value;
static void
create_watchpoint_request (struct ppc_hw_breakpoint *p, CORE_ADDR addr,
- int len, int rw, struct expression *cond,
- int insert)
+ int len, enum target_hw_bp_type type,
+ struct expression *cond, int insert)
{
if (len == 1
|| !(hwdebug_info.features & PPC_DEBUG_FEATURE_DATA_BP_RANGE))
}
p->version = PPC_DEBUG_CURRENT_VERSION;
- p->trigger_type = get_trigger_type (rw);
+ p->trigger_type = get_trigger_type (type);
p->addr = (uint64_t) addr;
}
static int
-ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
+ppc_linux_insert_watchpoint (struct target_ops *self, CORE_ADDR addr, int len,
+ enum target_hw_bp_type type,
struct expression *cond)
{
struct lwp_info *lp;
{
struct ppc_hw_breakpoint p;
- create_watchpoint_request (&p, addr, len, rw, cond, 1);
+ create_watchpoint_request (&p, addr, len, type, cond, 1);
ALL_LWPS (lp)
hwdebug_insert_point (&p, ptid_get_lwp (lp->ptid));
}
dabr_value = addr & ~(read_mode | write_mode);
- switch (rw)
+ switch (type)
{
case hw_read:
/* Set read and translate bits. */
}
static int
-ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw,
+ppc_linux_remove_watchpoint (struct target_ops *self, CORE_ADDR addr, int len,
+ enum target_hw_bp_type type,
struct expression *cond)
{
struct lwp_info *lp;
{
struct ppc_hw_breakpoint p;
- create_watchpoint_request (&p, addr, len, rw, cond, 0);
+ create_watchpoint_request (&p, addr, len, type, cond, 0);
ALL_LWPS (lp)
hwdebug_remove_point (&p, ptid_get_lwp (lp->ptid));
ppc_linux_store_inferior_registers (struct target_ops *ops,
struct regcache *regcache, int regno)
{
- /* Overload thread id onto process id. */
- int tid = ptid_get_lwp (inferior_ptid);
-
- /* No thread id, just use process id. */
- if (tid == 0)
- tid = ptid_get_pid (inferior_ptid);
+ pid_t tid = get_ptrace_pid (regcache_get_ptid (regcache));
if (regno >= 0)
store_register (regcache, tid, regno);
errno = 0;
msr = (long) ptrace (PTRACE_PEEKUSER, tid, PT_MSR * 8, 0);
- if (errno == 0 && msr < 0)
+ if (errno == 0 && ppc64_64bit_inferior_p (msr))
wordsize = 8;
#endif
perror_with_name (_("Unable to fetch SPE registers"));
}
- if (have_ptrace_getsetvsxregs)
+ if (have_ptrace_getsetvsxregs
+ && (ppc_linux_get_hwcap () & PPC_FEATURE_HAS_VSX))
{
gdb_vsxregset_t vsxregset;
perror_with_name (_("Unable to fetch VSX registers"));
}
- if (have_ptrace_getvrregs)
+ if (have_ptrace_getvrregs
+ && (ppc_linux_get_hwcap () & PPC_FEATURE_HAS_ALTIVEC))
{
gdb_vrregset_t vrregset;