/* GNU/Linux on ARM native support.
- Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009,
- 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 1999-2013 Free Software Foundation, Inc.
This file is part of GDB.
/* Defines ps_err_e, struct ps_prochandle. */
#include "gdb_proc_service.h"
-#include "features/arm-with-iwmmxt.c"
-#include "features/arm-with-vfpv2.c"
-#include "features/arm-with-vfpv3.c"
-#include "features/arm-with-neon.c"
-
#ifndef PTRACE_GET_THREAD_AREA
#define PTRACE_GET_THREAD_AREA 22
#endif
#define PTRACE_SETHBPREGS 30
#endif
-/* These are in <asm/elf.h> in current kernels. */
-#define HWCAP_VFP 64
-#define HWCAP_IWMMXT 512
-#define HWCAP_NEON 4096
-#define HWCAP_VFPv3 8192
-#define HWCAP_VFPv3D16 16384
-
/* A flag for whether the WMMX registers are available. */
static int arm_linux_has_wmmx_registers;
extern int arm_apcs_32;
-/* The following variables are used to determine the version of the
- underlying GNU/Linux operating system. Examples:
-
- GNU/Linux 2.0.35 GNU/Linux 2.2.12
- os_version = 0x00020023 os_version = 0x0002020c
- os_major = 2 os_major = 2
- os_minor = 0 os_minor = 2
- os_release = 35 os_release = 12
-
- Note: os_version = (os_major << 16) | (os_minor << 8) | os_release
-
- These are initialized using get_linux_version() from
- _initialize_arm_linux_nat(). */
-
-static unsigned int os_version, os_major, os_minor, os_release;
-
/* On GNU/Linux, threads are implemented as pseudo-processes, in which
case we may be tracing more than one process at a time. In that
case, inferior_ptid will contain the main process ID and the
individual thread (process) ID. get_thread_id () is used to get
the thread id if it's available, and the process id otherwise. */
-int
+static int
get_thread_id (ptid_t ptid)
{
int tid = TIDGET (ptid);
return PS_OK;
}
-static unsigned int
-get_linux_version (unsigned int *vmajor,
- unsigned int *vminor,
- unsigned int *vrelease)
-{
- struct utsname info;
- char *pmajor, *pminor, *prelease, *tail;
-
- if (-1 == uname (&info))
- {
- warning (_("Unable to determine GNU/Linux version."));
- return -1;
- }
-
- pmajor = strtok (info.release, ".");
- pminor = strtok (NULL, ".");
- prelease = strtok (NULL, ".");
-
- *vmajor = (unsigned int) strtoul (pmajor, &tail, 0);
- *vminor = (unsigned int) strtoul (pminor, &tail, 0);
- *vrelease = (unsigned int) strtoul (prelease, &tail, 0);
-
- return ((*vmajor << 16) | (*vminor << 8) | *vrelease);
-}
-
static const struct target_desc *
arm_linux_read_description (struct target_ops *ops)
{
if (arm_hwcap & HWCAP_IWMMXT)
{
arm_linux_has_wmmx_registers = 1;
- if (tdesc_arm_with_iwmmxt == NULL)
- initialize_tdesc_arm_with_iwmmxt ();
return tdesc_arm_with_iwmmxt;
}
if (arm_hwcap & HWCAP_NEON)
{
arm_linux_vfp_register_count = 32;
- if (tdesc_arm_with_neon == NULL)
- initialize_tdesc_arm_with_neon ();
result = tdesc_arm_with_neon;
}
else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3)
{
arm_linux_vfp_register_count = 32;
- if (tdesc_arm_with_vfpv3 == NULL)
- initialize_tdesc_arm_with_vfpv3 ();
result = tdesc_arm_with_vfpv3;
}
else
{
arm_linux_vfp_register_count = 16;
- if (tdesc_arm_with_vfpv2 == NULL)
- initialize_tdesc_arm_with_vfpv2 ();
result = tdesc_arm_with_vfpv2;
}
/* We have to create a mask for the control register which says which bits
of the word pointed to by address to break on. */
if (arm_pc_is_thumb (gdbarch, address))
- mask = 0x3 << (address & 2);
+ {
+ mask = 0x3;
+ address &= ~1;
+ }
else
- mask = 0xf;
+ {
+ mask = 0xf;
+ address &= ~3;
+ }
- p->address = (unsigned int) (address & ~3);
+ p->address = (unsigned int) address;
p->control = arm_hwbp_control_initialize (mask, arm_hwbp_break, 1);
}
arm_linux_insert_hw_breakpoint (struct gdbarch *gdbarch,
struct bp_target_info *bp_tgt)
{
- ptid_t ptid;
struct lwp_info *lp;
struct arm_linux_hw_breakpoint p;
return -1;
arm_linux_hw_breakpoint_initialize (gdbarch, bp_tgt, &p);
- ALL_LWPS (lp, ptid)
- arm_linux_insert_hw_breakpoint1 (&p, TIDGET (ptid), 0);
+ ALL_LWPS (lp)
+ arm_linux_insert_hw_breakpoint1 (&p, TIDGET (lp->ptid), 0);
return 0;
}
arm_linux_remove_hw_breakpoint (struct gdbarch *gdbarch,
struct bp_target_info *bp_tgt)
{
- ptid_t ptid;
struct lwp_info *lp;
struct arm_linux_hw_breakpoint p;
return -1;
arm_linux_hw_breakpoint_initialize (gdbarch, bp_tgt, &p);
- ALL_LWPS (lp, ptid)
- arm_linux_remove_hw_breakpoint1 (&p, TIDGET (ptid), 0);
+ ALL_LWPS (lp)
+ arm_linux_remove_hw_breakpoint1 (&p, TIDGET (lp->ptid), 0);
return 0;
}
arm_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw,
struct expression *cond)
{
- ptid_t ptid;
struct lwp_info *lp;
struct arm_linux_hw_breakpoint p;
return -1;
arm_linux_hw_watchpoint_initialize (addr, len, rw, &p);
- ALL_LWPS (lp, ptid)
- arm_linux_insert_hw_breakpoint1 (&p, TIDGET (ptid), 1);
+ ALL_LWPS (lp)
+ arm_linux_insert_hw_breakpoint1 (&p, TIDGET (lp->ptid), 1);
return 0;
}
arm_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw,
struct expression *cond)
{
- ptid_t ptid;
struct lwp_info *lp;
struct arm_linux_hw_breakpoint p;
return -1;
arm_linux_hw_watchpoint_initialize (addr, len, rw, &p);
- ALL_LWPS (lp, ptid)
- arm_linux_remove_hw_breakpoint1 (&p, TIDGET (ptid), 1);
+ ALL_LWPS (lp)
+ arm_linux_remove_hw_breakpoint1 (&p, TIDGET (lp->ptid), 1);
return 0;
}
static int
arm_linux_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p)
{
- struct siginfo *siginfo_p = linux_nat_get_siginfo (inferior_ptid);
- int slot = siginfo_p->si_errno;
+ siginfo_t siginfo;
+ int slot;
+
+ if (!linux_nat_get_siginfo (inferior_ptid, &siginfo))
+ return 0;
/* This must be a hardware breakpoint. */
- if (siginfo_p->si_signo != SIGTRAP
- || (siginfo_p->si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */)
+ if (siginfo.si_signo != SIGTRAP
+ || (siginfo.si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */)
return 0;
/* We must be able to set hardware watchpoints. */
if (arm_linux_get_hw_watchpoint_count () == 0)
return 0;
+ slot = siginfo.si_errno;
+
/* If we are in a positive slot then we're looking at a breakpoint and not
a watchpoint. */
if (slot >= 0)
return 0;
- *addr_p = (CORE_ADDR) (uintptr_t) siginfo_p->si_addr;
+ *addr_p = (CORE_ADDR) (uintptr_t) siginfo.si_addr;
return 1;
}
/* Handle thread creation. We need to copy the breakpoints and watchpoints
in the parent thread to the child thread. */
static void
-arm_linux_new_thread (ptid_t ptid)
+arm_linux_new_thread (struct lwp_info *lp)
{
- int tid = TIDGET (ptid);
+ int tid = TIDGET (lp->ptid);
const struct arm_linux_hwbp_cap *info = arm_linux_get_hwbp_cap ();
if (info != NULL)
{
struct target_ops *t;
- os_version = get_linux_version (&os_major, &os_minor, &os_release);
-
/* Fill in the generic GNU/Linux methods. */
t = linux_target ();