gdb/arm-linux-nat.c - gdb
Global variables defined
Data types defined
Functions defined
Macros defined
Source code
- #include "defs.h"
- #include "inferior.h"
- #include "gdbcore.h"
- #include "regcache.h"
- #include "target.h"
- #include "linux-nat.h"
- #include "target-descriptions.h"
- #include "auxv.h"
- #include "observer.h"
- #include "gdbthread.h"
- #include "arm-tdep.h"
- #include "arm-linux-tdep.h"
- #include <elf/common.h>
- #include <sys/user.h>
- #include <sys/ptrace.h>
- #include <sys/utsname.h>
- #include <sys/procfs.h>
- #include "gregset.h"
- #include "gdb_proc_service.h"
- #ifndef PTRACE_GET_THREAD_AREA
- #define PTRACE_GET_THREAD_AREA 22
- #endif
- #ifndef PTRACE_GETWMMXREGS
- #define PTRACE_GETWMMXREGS 18
- #define PTRACE_SETWMMXREGS 19
- #endif
- #ifndef PTRACE_GETVFPREGS
- #define PTRACE_GETVFPREGS 27
- #define PTRACE_SETVFPREGS 28
- #endif
- #ifndef PTRACE_GETHBPREGS
- #define PTRACE_GETHBPREGS 29
- #define PTRACE_SETHBPREGS 30
- #endif
- static int arm_linux_has_wmmx_registers;
- static int arm_linux_vfp_register_count;
- extern int arm_apcs_32;
- static int
- get_thread_id (ptid_t ptid)
- {
- int tid = ptid_get_lwp (ptid);
- if (0 == tid)
- tid = ptid_get_pid (ptid);
- return tid;
- }
- #define GET_THREAD_ID(PTID) get_thread_id (PTID)
- static void
- fetch_fpregister (struct regcache *regcache, int regno)
- {
- int ret, tid;
- gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
-
- tid = GET_THREAD_ID (inferior_ptid);
-
- ret = ptrace (PT_GETFPREGS, tid, 0, fp);
- if (ret < 0)
- {
- warning (_("Unable to fetch floating point register."));
- return;
- }
-
- if (ARM_FPS_REGNUM == regno)
- regcache_raw_supply (regcache, ARM_FPS_REGNUM,
- fp + NWFPE_FPSR_OFFSET);
-
- if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
- supply_nwfpe_register (regcache, regno, fp);
- }
- static void
- fetch_fpregs (struct regcache *regcache)
- {
- int ret, regno, tid;
- gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
-
- tid = GET_THREAD_ID (inferior_ptid);
-
- ret = ptrace (PT_GETFPREGS, tid, 0, fp);
- if (ret < 0)
- {
- warning (_("Unable to fetch the floating point registers."));
- return;
- }
-
- regcache_raw_supply (regcache, ARM_FPS_REGNUM,
- fp + NWFPE_FPSR_OFFSET);
-
- for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
- supply_nwfpe_register (regcache, regno, fp);
- }
- static void
- store_fpregister (const struct regcache *regcache, int regno)
- {
- int ret, tid;
- gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
-
- tid = GET_THREAD_ID (inferior_ptid);
-
- ret = ptrace (PT_GETFPREGS, tid, 0, fp);
- if (ret < 0)
- {
- warning (_("Unable to fetch the floating point registers."));
- return;
- }
-
- if (ARM_FPS_REGNUM == regno
- && REG_VALID == regcache_register_status (regcache, ARM_FPS_REGNUM))
- regcache_raw_collect (regcache, ARM_FPS_REGNUM, fp + NWFPE_FPSR_OFFSET);
-
- if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
- collect_nwfpe_register (regcache, regno, fp);
- ret = ptrace (PTRACE_SETFPREGS, tid, 0, fp);
- if (ret < 0)
- {
- warning (_("Unable to store floating point register."));
- return;
- }
- }
- static void
- store_fpregs (const struct regcache *regcache)
- {
- int ret, regno, tid;
- gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
-
- tid = GET_THREAD_ID (inferior_ptid);
-
- ret = ptrace (PT_GETFPREGS, tid, 0, fp);
- if (ret < 0)
- {
- warning (_("Unable to fetch the floating point registers."));
- return;
- }
-
- if (REG_VALID == regcache_register_status (regcache, ARM_FPS_REGNUM))
- regcache_raw_collect (regcache, ARM_FPS_REGNUM, fp + NWFPE_FPSR_OFFSET);
-
- for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
- if (REG_VALID == regcache_register_status (regcache, regno))
- collect_nwfpe_register (regcache, regno, fp);
- ret = ptrace (PTRACE_SETFPREGS, tid, 0, fp);
- if (ret < 0)
- {
- warning (_("Unable to store floating point registers."));
- return;
- }
- }
- static void
- fetch_register (struct regcache *regcache, int regno)
- {
- int ret, tid;
- elf_gregset_t regs;
-
- tid = GET_THREAD_ID (inferior_ptid);
- ret = ptrace (PTRACE_GETREGS, tid, 0, ®s);
- if (ret < 0)
- {
- warning (_("Unable to fetch general register."));
- return;
- }
- if (regno >= ARM_A1_REGNUM && regno < ARM_PC_REGNUM)
- regcache_raw_supply (regcache, regno, (char *) ®s[regno]);
- if (ARM_PS_REGNUM == regno)
- {
- if (arm_apcs_32)
- regcache_raw_supply (regcache, ARM_PS_REGNUM,
- (char *) ®s[ARM_CPSR_GREGNUM]);
- else
- regcache_raw_supply (regcache, ARM_PS_REGNUM,
- (char *) ®s[ARM_PC_REGNUM]);
- }
- if (ARM_PC_REGNUM == regno)
- {
- regs[ARM_PC_REGNUM] = gdbarch_addr_bits_remove
- (get_regcache_arch (regcache),
- regs[ARM_PC_REGNUM]);
- regcache_raw_supply (regcache, ARM_PC_REGNUM,
- (char *) ®s[ARM_PC_REGNUM]);
- }
- }
- static void
- fetch_regs (struct regcache *regcache)
- {
- int ret, regno, tid;
- elf_gregset_t regs;
-
- tid = GET_THREAD_ID (inferior_ptid);
- ret = ptrace (PTRACE_GETREGS, tid, 0, ®s);
- if (ret < 0)
- {
- warning (_("Unable to fetch general registers."));
- return;
- }
- for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
- regcache_raw_supply (regcache, regno, (char *) ®s[regno]);
- if (arm_apcs_32)
- regcache_raw_supply (regcache, ARM_PS_REGNUM,
- (char *) ®s[ARM_CPSR_GREGNUM]);
- else
- regcache_raw_supply (regcache, ARM_PS_REGNUM,
- (char *) ®s[ARM_PC_REGNUM]);
- regs[ARM_PC_REGNUM] = gdbarch_addr_bits_remove
- (get_regcache_arch (regcache), regs[ARM_PC_REGNUM]);
- regcache_raw_supply (regcache, ARM_PC_REGNUM,
- (char *) ®s[ARM_PC_REGNUM]);
- }
- static void
- store_register (const struct regcache *regcache, int regno)
- {
- int ret, tid;
- elf_gregset_t regs;
- if (REG_VALID != regcache_register_status (regcache, regno))
- return;
-
- tid = GET_THREAD_ID (inferior_ptid);
-
- ret = ptrace (PTRACE_GETREGS, tid, 0, ®s);
- if (ret < 0)
- {
- warning (_("Unable to fetch general registers."));
- return;
- }
- if (regno >= ARM_A1_REGNUM && regno <= ARM_PC_REGNUM)
- regcache_raw_collect (regcache, regno, (char *) ®s[regno]);
- else if (arm_apcs_32 && regno == ARM_PS_REGNUM)
- regcache_raw_collect (regcache, regno,
- (char *) ®s[ARM_CPSR_GREGNUM]);
- else if (!arm_apcs_32 && regno == ARM_PS_REGNUM)
- regcache_raw_collect (regcache, ARM_PC_REGNUM,
- (char *) ®s[ARM_PC_REGNUM]);
- ret = ptrace (PTRACE_SETREGS, tid, 0, ®s);
- if (ret < 0)
- {
- warning (_("Unable to store general register."));
- return;
- }
- }
- static void
- store_regs (const struct regcache *regcache)
- {
- int ret, regno, tid;
- elf_gregset_t regs;
-
- tid = GET_THREAD_ID (inferior_ptid);
-
- ret = ptrace (PTRACE_GETREGS, tid, 0, ®s);
- if (ret < 0)
- {
- warning (_("Unable to fetch general registers."));
- return;
- }
- for (regno = ARM_A1_REGNUM; regno <= ARM_PC_REGNUM; regno++)
- {
- if (REG_VALID == regcache_register_status (regcache, regno))
- regcache_raw_collect (regcache, regno, (char *) ®s[regno]);
- }
- if (arm_apcs_32 && REG_VALID == regcache_register_status (regcache, ARM_PS_REGNUM))
- regcache_raw_collect (regcache, ARM_PS_REGNUM,
- (char *) ®s[ARM_CPSR_GREGNUM]);
- ret = ptrace (PTRACE_SETREGS, tid, 0, ®s);
- if (ret < 0)
- {
- warning (_("Unable to store general registers."));
- return;
- }
- }
- #define IWMMXT_REGS_SIZE (16 * 8 + 6 * 4)
- static void
- fetch_wmmx_regs (struct regcache *regcache)
- {
- char regbuf[IWMMXT_REGS_SIZE];
- int ret, regno, tid;
-
- tid = GET_THREAD_ID (inferior_ptid);
- ret = ptrace (PTRACE_GETWMMXREGS, tid, 0, regbuf);
- if (ret < 0)
- {
- warning (_("Unable to fetch WMMX registers."));
- return;
- }
- for (regno = 0; regno < 16; regno++)
- regcache_raw_supply (regcache, regno + ARM_WR0_REGNUM,
- ®buf[regno * 8]);
- for (regno = 0; regno < 2; regno++)
- regcache_raw_supply (regcache, regno + ARM_WCSSF_REGNUM,
- ®buf[16 * 8 + regno * 4]);
- for (regno = 0; regno < 4; regno++)
- regcache_raw_supply (regcache, regno + ARM_WCGR0_REGNUM,
- ®buf[16 * 8 + 2 * 4 + regno * 4]);
- }
- static void
- store_wmmx_regs (const struct regcache *regcache)
- {
- char regbuf[IWMMXT_REGS_SIZE];
- int ret, regno, tid;
-
- tid = GET_THREAD_ID (inferior_ptid);
- ret = ptrace (PTRACE_GETWMMXREGS, tid, 0, regbuf);
- if (ret < 0)
- {
- warning (_("Unable to fetch WMMX registers."));
- return;
- }
- for (regno = 0; regno < 16; regno++)
- if (REG_VALID == regcache_register_status (regcache,
- regno + ARM_WR0_REGNUM))
- regcache_raw_collect (regcache, regno + ARM_WR0_REGNUM,
- ®buf[regno * 8]);
- for (regno = 0; regno < 2; regno++)
- if (REG_VALID == regcache_register_status (regcache,
- regno + ARM_WCSSF_REGNUM))
- regcache_raw_collect (regcache, regno + ARM_WCSSF_REGNUM,
- ®buf[16 * 8 + regno * 4]);
- for (regno = 0; regno < 4; regno++)
- if (REG_VALID == regcache_register_status (regcache,
- regno + ARM_WCGR0_REGNUM))
- regcache_raw_collect (regcache, regno + ARM_WCGR0_REGNUM,
- ®buf[16 * 8 + 2 * 4 + regno * 4]);
- ret = ptrace (PTRACE_SETWMMXREGS, tid, 0, regbuf);
- if (ret < 0)
- {
- warning (_("Unable to store WMMX registers."));
- return;
- }
- }
- #define VFP_REGS_SIZE (32 * 8 + 4)
- static void
- fetch_vfp_regs (struct regcache *regcache)
- {
- char regbuf[VFP_REGS_SIZE];
- int ret, regno, tid;
-
- tid = GET_THREAD_ID (inferior_ptid);
- ret = ptrace (PTRACE_GETVFPREGS, tid, 0, regbuf);
- if (ret < 0)
- {
- warning (_("Unable to fetch VFP registers."));
- return;
- }
- for (regno = 0; regno < arm_linux_vfp_register_count; regno++)
- regcache_raw_supply (regcache, regno + ARM_D0_REGNUM,
- (char *) regbuf + regno * 8);
- regcache_raw_supply (regcache, ARM_FPSCR_REGNUM,
- (char *) regbuf + 32 * 8);
- }
- static void
- store_vfp_regs (const struct regcache *regcache)
- {
- char regbuf[VFP_REGS_SIZE];
- int ret, regno, tid;
-
- tid = GET_THREAD_ID (inferior_ptid);
- ret = ptrace (PTRACE_GETVFPREGS, tid, 0, regbuf);
- if (ret < 0)
- {
- warning (_("Unable to fetch VFP registers (for update)."));
- return;
- }
- for (regno = 0; regno < arm_linux_vfp_register_count; regno++)
- regcache_raw_collect (regcache, regno + ARM_D0_REGNUM,
- (char *) regbuf + regno * 8);
- regcache_raw_collect (regcache, ARM_FPSCR_REGNUM,
- (char *) regbuf + 32 * 8);
- ret = ptrace (PTRACE_SETVFPREGS, tid, 0, regbuf);
- if (ret < 0)
- {
- warning (_("Unable to store VFP registers."));
- return;
- }
- }
- static void
- arm_linux_fetch_inferior_registers (struct target_ops *ops,
- struct regcache *regcache, int regno)
- {
- if (-1 == regno)
- {
- fetch_regs (regcache);
- fetch_fpregs (regcache);
- if (arm_linux_has_wmmx_registers)
- fetch_wmmx_regs (regcache);
- if (arm_linux_vfp_register_count > 0)
- fetch_vfp_regs (regcache);
- }
- else
- {
- if (regno < ARM_F0_REGNUM || regno == ARM_PS_REGNUM)
- fetch_register (regcache, regno);
- else if (regno >= ARM_F0_REGNUM && regno <= ARM_FPS_REGNUM)
- fetch_fpregister (regcache, regno);
- else if (arm_linux_has_wmmx_registers
- && regno >= ARM_WR0_REGNUM && regno <= ARM_WCGR7_REGNUM)
- fetch_wmmx_regs (regcache);
- else if (arm_linux_vfp_register_count > 0
- && regno >= ARM_D0_REGNUM
- && regno <= ARM_D0_REGNUM + arm_linux_vfp_register_count)
- fetch_vfp_regs (regcache);
- }
- }
- static void
- arm_linux_store_inferior_registers (struct target_ops *ops,
- struct regcache *regcache, int regno)
- {
- if (-1 == regno)
- {
- store_regs (regcache);
- store_fpregs (regcache);
- if (arm_linux_has_wmmx_registers)
- store_wmmx_regs (regcache);
- if (arm_linux_vfp_register_count > 0)
- store_vfp_regs (regcache);
- }
- else
- {
- if (regno < ARM_F0_REGNUM || regno == ARM_PS_REGNUM)
- store_register (regcache, regno);
- else if ((regno >= ARM_F0_REGNUM) && (regno <= ARM_FPS_REGNUM))
- store_fpregister (regcache, regno);
- else if (arm_linux_has_wmmx_registers
- && regno >= ARM_WR0_REGNUM && regno <= ARM_WCGR7_REGNUM)
- store_wmmx_regs (regcache);
- else if (arm_linux_vfp_register_count > 0
- && regno >= ARM_D0_REGNUM
- && regno <= ARM_D0_REGNUM + arm_linux_vfp_register_count)
- store_vfp_regs (regcache);
- }
- }
- void
- fill_gregset (const struct regcache *regcache,
- gdb_gregset_t *gregsetp, int regno)
- {
- arm_linux_collect_gregset (NULL, regcache, regno, gregsetp, 0);
- }
- void
- supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
- {
- arm_linux_supply_gregset (NULL, regcache, -1, gregsetp, 0);
- }
- void
- fill_fpregset (const struct regcache *regcache,
- gdb_fpregset_t *fpregsetp, int regno)
- {
- arm_linux_collect_nwfpe (NULL, regcache, regno, fpregsetp, 0);
- }
- void
- supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
- {
- arm_linux_supply_nwfpe (NULL, regcache, -1, fpregsetp, 0);
- }
- ps_err_e
- ps_get_thread_area (const struct ps_prochandle *ph,
- lwpid_t lwpid, int idx, void **base)
- {
- if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
- return PS_ERR;
-
- *base = (void *) ((char *)*base - idx);
- return PS_OK;
- }
- static const struct target_desc *
- arm_linux_read_description (struct target_ops *ops)
- {
- CORE_ADDR arm_hwcap = 0;
- arm_linux_has_wmmx_registers = 0;
- arm_linux_vfp_register_count = 0;
- if (target_auxv_search (ops, AT_HWCAP, &arm_hwcap) != 1)
- {
- return ops->beneath->to_read_description (ops->beneath);
- }
- if (arm_hwcap & HWCAP_IWMMXT)
- {
- arm_linux_has_wmmx_registers = 1;
- return tdesc_arm_with_iwmmxt;
- }
- if (arm_hwcap & HWCAP_VFP)
- {
- int pid;
- char *buf;
- const struct target_desc * result = NULL;
-
- if (arm_hwcap & HWCAP_NEON)
- {
- arm_linux_vfp_register_count = 32;
- result = tdesc_arm_with_neon;
- }
- else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3)
- {
- arm_linux_vfp_register_count = 32;
- result = tdesc_arm_with_vfpv3;
- }
- else
- {
- arm_linux_vfp_register_count = 16;
- result = tdesc_arm_with_vfpv2;
- }
-
- pid = ptid_get_lwp (inferior_ptid);
- errno = 0;
- buf = alloca (VFP_REGS_SIZE);
- if (ptrace (PTRACE_GETVFPREGS, pid, 0, buf) < 0
- && errno == EIO)
- result = NULL;
- return result;
- }
- return ops->beneath->to_read_description (ops->beneath);
- }
- struct arm_linux_hwbp_cap
- {
- gdb_byte arch;
- gdb_byte max_wp_length;
- gdb_byte wp_count;
- gdb_byte bp_count;
- };
- #define MAX_BPTS 16
- #define MAX_WPTS 16
- static const struct arm_linux_hwbp_cap *
- arm_linux_get_hwbp_cap (void)
- {
-
- static struct arm_linux_hwbp_cap info;
-
- static int available = -1;
- if (available == -1)
- {
- int tid;
- unsigned int val;
- tid = GET_THREAD_ID (inferior_ptid);
- if (ptrace (PTRACE_GETHBPREGS, tid, 0, &val) < 0)
- available = 0;
- else
- {
- info.arch = (gdb_byte)((val >> 24) & 0xff);
- info.max_wp_length = (gdb_byte)((val >> 16) & 0xff);
- info.wp_count = (gdb_byte)((val >> 8) & 0xff);
- info.bp_count = (gdb_byte)(val & 0xff);
- if (info.wp_count > MAX_WPTS)
- {
- warning (_("arm-linux-gdb supports %d hardware watchpoints but target \
- supports %d"), MAX_WPTS, info.wp_count);
- info.wp_count = MAX_WPTS;
- }
- if (info.bp_count > MAX_BPTS)
- {
- warning (_("arm-linux-gdb supports %d hardware breakpoints but target \
- supports %d"), MAX_BPTS, info.bp_count);
- info.bp_count = MAX_BPTS;
- }
- available = (info.arch != 0);
- }
- }
- return available == 1 ? &info : NULL;
- }
- static int
- arm_linux_get_hw_breakpoint_count (void)
- {
- const struct arm_linux_hwbp_cap *cap = arm_linux_get_hwbp_cap ();
- return cap != NULL ? cap->bp_count : 0;
- }
- static int
- arm_linux_get_hw_watchpoint_count (void)
- {
- const struct arm_linux_hwbp_cap *cap = arm_linux_get_hwbp_cap ();
- return cap != NULL ? cap->wp_count : 0;
- }
- static int
- arm_linux_can_use_hw_breakpoint (struct target_ops *self,
- int type, int cnt, int ot)
- {
- if (type == bp_hardware_watchpoint || type == bp_read_watchpoint
- || type == bp_access_watchpoint || type == bp_watchpoint)
- {
- if (cnt + ot > arm_linux_get_hw_watchpoint_count ())
- return -1;
- }
- else if (type == bp_hardware_breakpoint)
- {
- if (cnt > arm_linux_get_hw_breakpoint_count ())
- return -1;
- }
- else
- gdb_assert (FALSE);
- return 1;
- }
- typedef enum
- {
- arm_hwbp_break = 0,
- arm_hwbp_load = 1,
- arm_hwbp_store = 2,
- arm_hwbp_access = 3
- } arm_hwbp_type;
- typedef unsigned int arm_hwbp_control_t;
- struct arm_linux_hw_breakpoint
- {
-
- unsigned int address;
-
- arm_hwbp_control_t control;
- };
- struct arm_linux_debug_reg_state
- {
-
- struct arm_linux_hw_breakpoint bpts[MAX_BPTS];
-
- struct arm_linux_hw_breakpoint wpts[MAX_WPTS];
- };
- struct arm_linux_process_info
- {
-
- struct arm_linux_process_info *next;
-
- pid_t pid;
-
- struct arm_linux_debug_reg_state state;
- };
- struct arch_lwp_info
- {
-
- char bpts_changed[MAX_BPTS];
- char wpts_changed[MAX_WPTS];
- };
- static struct arm_linux_process_info *arm_linux_process_list = NULL;
- static struct arm_linux_process_info *
- arm_linux_find_process_pid (pid_t pid)
- {
- struct arm_linux_process_info *proc;
- for (proc = arm_linux_process_list; proc; proc = proc->next)
- if (proc->pid == pid)
- return proc;
- return NULL;
- }
- static struct arm_linux_process_info *
- arm_linux_add_process (pid_t pid)
- {
- struct arm_linux_process_info *proc;
- proc = xcalloc (1, sizeof (*proc));
- proc->pid = pid;
- proc->next = arm_linux_process_list;
- arm_linux_process_list = proc;
- return proc;
- }
- static struct arm_linux_process_info *
- arm_linux_process_info_get (pid_t pid)
- {
- struct arm_linux_process_info *proc;
- proc = arm_linux_find_process_pid (pid);
- if (proc == NULL)
- proc = arm_linux_add_process (pid);
- return proc;
- }
- static void
- arm_linux_forget_process (pid_t pid)
- {
- struct arm_linux_process_info *proc, **proc_link;
- proc = arm_linux_process_list;
- proc_link = &arm_linux_process_list;
- while (proc != NULL)
- {
- if (proc->pid == pid)
- {
- *proc_link = proc->next;
- xfree (proc);
- return;
- }
- proc_link = &proc->next;
- proc = *proc_link;
- }
- }
- static struct arm_linux_debug_reg_state *
- arm_linux_get_debug_reg_state (pid_t pid)
- {
- return &arm_linux_process_info_get (pid)->state;
- }
- static arm_hwbp_control_t
- arm_hwbp_control_initialize (unsigned byte_address_select,
- arm_hwbp_type hwbp_type,
- int enable)
- {
- gdb_assert ((byte_address_select & ~0xffU) == 0);
- gdb_assert (hwbp_type != arm_hwbp_break
- || ((byte_address_select & 0xfU) != 0));
- return (byte_address_select << 5) | (hwbp_type << 3) | (3 << 1) | enable;
- }
- static int
- arm_hwbp_control_is_enabled (arm_hwbp_control_t control)
- {
- return control & 0x1;
- }
- static arm_hwbp_control_t
- arm_hwbp_control_disable (arm_hwbp_control_t control)
- {
- return control & ~0x1;
- }
- static void
- arm_linux_hw_breakpoint_initialize (struct gdbarch *gdbarch,
- struct bp_target_info *bp_tgt,
- struct arm_linux_hw_breakpoint *p)
- {
- unsigned mask;
- CORE_ADDR address = bp_tgt->placed_address = bp_tgt->reqstd_address;
-
- if (arm_pc_is_thumb (gdbarch, address))
- {
- mask = 0x3;
- address &= ~1;
- }
- else
- {
- mask = 0xf;
- address &= ~3;
- }
- p->address = (unsigned int) address;
- p->control = arm_hwbp_control_initialize (mask, arm_hwbp_break, 1);
- }
- static arm_hwbp_type
- arm_linux_get_hwbp_type (int rw)
- {
- if (rw == hw_read)
- return arm_hwbp_load;
- else if (rw == hw_write)
- return arm_hwbp_store;
- else
- return arm_hwbp_access;
- }
- static void
- arm_linux_hw_watchpoint_initialize (CORE_ADDR addr, int len, int rw,
- struct arm_linux_hw_breakpoint *p)
- {
- const struct arm_linux_hwbp_cap *cap = arm_linux_get_hwbp_cap ();
- unsigned mask;
- gdb_assert (cap != NULL);
- gdb_assert (cap->max_wp_length != 0);
- mask = (1 << len) - 1;
- p->address = (unsigned int) addr;
- p->control = arm_hwbp_control_initialize (mask,
- arm_linux_get_hwbp_type (rw), 1);
- }
- static int
- arm_linux_hw_breakpoint_equal (const struct arm_linux_hw_breakpoint *p1,
- const struct arm_linux_hw_breakpoint *p2)
- {
- return p1->address == p2->address && p1->control == p2->control;
- }
- struct update_registers_data
- {
- int watch;
- int index;
- };
- static int
- update_registers_callback (struct lwp_info *lwp, void *arg)
- {
- struct update_registers_data *data = (struct update_registers_data *) arg;
- if (lwp->arch_private == NULL)
- lwp->arch_private = XCNEW (struct arch_lwp_info);
-
- if (data->watch)
- lwp->arch_private->wpts_changed[data->index] = 1;
- else
- lwp->arch_private->bpts_changed[data->index] = 1;
-
- if (!lwp->stopped)
- linux_stop_lwp (lwp);
- return 0;
- }
- static void
- arm_linux_insert_hw_breakpoint1 (const struct arm_linux_hw_breakpoint* bpt,
- int watchpoint)
- {
- int pid;
- ptid_t pid_ptid;
- gdb_byte count, i;
- struct arm_linux_hw_breakpoint* bpts;
- struct update_registers_data data;
- pid = ptid_get_pid (inferior_ptid);
- pid_ptid = pid_to_ptid (pid);
- if (watchpoint)
- {
- count = arm_linux_get_hw_watchpoint_count ();
- bpts = arm_linux_get_debug_reg_state (pid)->wpts;
- }
- else
- {
- count = arm_linux_get_hw_breakpoint_count ();
- bpts = arm_linux_get_debug_reg_state (pid)->bpts;
- }
- for (i = 0; i < count; ++i)
- if (!arm_hwbp_control_is_enabled (bpts[i].control))
- {
- data.watch = watchpoint;
- data.index = i;
- bpts[i] = *bpt;
- iterate_over_lwps (pid_ptid, update_registers_callback, &data);
- break;
- }
- gdb_assert (i != count);
- }
- static void
- arm_linux_remove_hw_breakpoint1 (const struct arm_linux_hw_breakpoint *bpt,
- int watchpoint)
- {
- int pid;
- gdb_byte count, i;
- ptid_t pid_ptid;
- struct arm_linux_hw_breakpoint* bpts;
- struct update_registers_data data;
- pid = ptid_get_pid (inferior_ptid);
- pid_ptid = pid_to_ptid (pid);
- if (watchpoint)
- {
- count = arm_linux_get_hw_watchpoint_count ();
- bpts = arm_linux_get_debug_reg_state (pid)->wpts;
- }
- else
- {
- count = arm_linux_get_hw_breakpoint_count ();
- bpts = arm_linux_get_debug_reg_state (pid)->bpts;
- }
- for (i = 0; i < count; ++i)
- if (arm_linux_hw_breakpoint_equal (bpt, bpts + i))
- {
- data.watch = watchpoint;
- data.index = i;
- bpts[i].control = arm_hwbp_control_disable (bpts[i].control);
- iterate_over_lwps (pid_ptid, update_registers_callback, &data);
- break;
- }
- gdb_assert (i != count);
- }
- static int
- arm_linux_insert_hw_breakpoint (struct target_ops *self,
- struct gdbarch *gdbarch,
- struct bp_target_info *bp_tgt)
- {
- struct lwp_info *lp;
- struct arm_linux_hw_breakpoint p;
- if (arm_linux_get_hw_breakpoint_count () == 0)
- return -1;
- arm_linux_hw_breakpoint_initialize (gdbarch, bp_tgt, &p);
- arm_linux_insert_hw_breakpoint1 (&p, 0);
- return 0;
- }
- static int
- arm_linux_remove_hw_breakpoint (struct target_ops *self,
- struct gdbarch *gdbarch,
- struct bp_target_info *bp_tgt)
- {
- struct lwp_info *lp;
- struct arm_linux_hw_breakpoint p;
- if (arm_linux_get_hw_breakpoint_count () == 0)
- return -1;
- arm_linux_hw_breakpoint_initialize (gdbarch, bp_tgt, &p);
- arm_linux_remove_hw_breakpoint1 (&p, 0);
- return 0;
- }
- static int
- arm_linux_region_ok_for_hw_watchpoint (struct target_ops *self,
- CORE_ADDR addr, int len)
- {
- const struct arm_linux_hwbp_cap *cap = arm_linux_get_hwbp_cap ();
- CORE_ADDR max_wp_length, aligned_addr;
-
- if (len <= 0)
- return 0;
-
- if (cap == NULL || cap->wp_count == 0)
- return 0;
-
- max_wp_length = (CORE_ADDR)cap->max_wp_length;
- aligned_addr = addr & ~(max_wp_length - 1);
- if (aligned_addr + max_wp_length < addr + len)
- return 0;
-
- if ((len & (len - 1)) != 0)
- return 0;
-
- return 1;
- }
- static int
- arm_linux_insert_watchpoint (struct target_ops *self,
- CORE_ADDR addr, int len, int rw,
- struct expression *cond)
- {
- struct lwp_info *lp;
- struct arm_linux_hw_breakpoint p;
- if (arm_linux_get_hw_watchpoint_count () == 0)
- return -1;
- arm_linux_hw_watchpoint_initialize (addr, len, rw, &p);
- arm_linux_insert_hw_breakpoint1 (&p, 1);
- return 0;
- }
- static int
- arm_linux_remove_watchpoint (struct target_ops *self,
- CORE_ADDR addr, int len, int rw,
- struct expression *cond)
- {
- struct lwp_info *lp;
- struct arm_linux_hw_breakpoint p;
- if (arm_linux_get_hw_watchpoint_count () == 0)
- return -1;
- arm_linux_hw_watchpoint_initialize (addr, len, rw, &p);
- arm_linux_remove_hw_breakpoint1 (&p, 1);
- return 0;
- }
- static int
- arm_linux_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p)
- {
- siginfo_t siginfo;
- int slot;
- if (!linux_nat_get_siginfo (inferior_ptid, &siginfo))
- return 0;
-
- if (siginfo.si_signo != SIGTRAP
- || (siginfo.si_code & 0xffff) != 0x0004 )
- return 0;
-
- if (arm_linux_get_hw_watchpoint_count () == 0)
- return 0;
- slot = siginfo.si_errno;
-
- if (slot >= 0)
- return 0;
- *addr_p = (CORE_ADDR) (uintptr_t) siginfo.si_addr;
- return 1;
- }
- static int
- arm_linux_stopped_by_watchpoint (struct target_ops *ops)
- {
- CORE_ADDR addr;
- return arm_linux_stopped_data_address (ops, &addr);
- }
- static int
- arm_linux_watchpoint_addr_within_range (struct target_ops *target,
- CORE_ADDR addr,
- CORE_ADDR start, int length)
- {
- return start <= addr && start + length - 1 >= addr;
- }
- static void
- arm_linux_new_thread (struct lwp_info *lp)
- {
- int i;
- struct arch_lwp_info *info = XCNEW (struct arch_lwp_info);
-
- for (i = 0; i < MAX_BPTS; i++)
- {
- info->bpts_changed[i] = 1;
- info->wpts_changed[i] = 1;
- }
- lp->arch_private = info;
- }
- static void
- arm_linux_prepare_to_resume (struct lwp_info *lwp)
- {
- int pid, i;
- struct arm_linux_hw_breakpoint *bpts, *wpts;
- struct arch_lwp_info *arm_lwp_info = lwp->arch_private;
- pid = ptid_get_lwp (lwp->ptid);
- bpts = arm_linux_get_debug_reg_state (ptid_get_pid (lwp->ptid))->bpts;
- wpts = arm_linux_get_debug_reg_state (ptid_get_pid (lwp->ptid))->wpts;
-
- if (arm_lwp_info == NULL)
- return;
- for (i = 0; i < arm_linux_get_hw_breakpoint_count (); i++)
- if (arm_lwp_info->bpts_changed[i])
- {
- errno = 0;
- if (arm_hwbp_control_is_enabled (bpts[i].control))
- if (ptrace (PTRACE_SETHBPREGS, pid,
- (PTRACE_TYPE_ARG3) ((i << 1) + 1), &bpts[i].address) < 0)
- perror_with_name (_("Unexpected error setting breakpoint"));
- if (bpts[i].control != 0)
- if (ptrace (PTRACE_SETHBPREGS, pid,
- (PTRACE_TYPE_ARG3) ((i << 1) + 2), &bpts[i].control) < 0)
- perror_with_name (_("Unexpected error setting breakpoint"));
- arm_lwp_info->bpts_changed[i] = 0;
- }
- for (i = 0; i < arm_linux_get_hw_watchpoint_count (); i++)
- if (arm_lwp_info->wpts_changed[i])
- {
- errno = 0;
- if (arm_hwbp_control_is_enabled (wpts[i].control))
- if (ptrace (PTRACE_SETHBPREGS, pid,
- (PTRACE_TYPE_ARG3) -((i << 1) + 1), &wpts[i].address) < 0)
- perror_with_name (_("Unexpected error setting watchpoint"));
- if (wpts[i].control != 0)
- if (ptrace (PTRACE_SETHBPREGS, pid,
- (PTRACE_TYPE_ARG3) -((i << 1) + 2), &wpts[i].control) < 0)
- perror_with_name (_("Unexpected error setting watchpoint"));
- arm_lwp_info->wpts_changed[i] = 0;
- }
- }
- static void
- arm_linux_new_fork (struct lwp_info *parent, pid_t child_pid)
- {
- pid_t parent_pid;
- struct arm_linux_debug_reg_state *parent_state;
- struct arm_linux_debug_reg_state *child_state;
-
- if (parent->arch_private == NULL)
- return;
-
- parent_pid = ptid_get_pid (parent->ptid);
- parent_state = arm_linux_get_debug_reg_state (parent_pid);
- child_state = arm_linux_get_debug_reg_state (child_pid);
- *child_state = *parent_state;
- }
- void _initialize_arm_linux_nat (void);
- void
- _initialize_arm_linux_nat (void)
- {
- struct target_ops *t;
-
- t = linux_target ();
-
- t->to_fetch_registers = arm_linux_fetch_inferior_registers;
- t->to_store_registers = arm_linux_store_inferior_registers;
-
- t->to_can_use_hw_breakpoint = arm_linux_can_use_hw_breakpoint;
- t->to_insert_hw_breakpoint = arm_linux_insert_hw_breakpoint;
- t->to_remove_hw_breakpoint = arm_linux_remove_hw_breakpoint;
- t->to_region_ok_for_hw_watchpoint = arm_linux_region_ok_for_hw_watchpoint;
- t->to_insert_watchpoint = arm_linux_insert_watchpoint;
- t->to_remove_watchpoint = arm_linux_remove_watchpoint;
- t->to_stopped_by_watchpoint = arm_linux_stopped_by_watchpoint;
- t->to_stopped_data_address = arm_linux_stopped_data_address;
- t->to_watchpoint_addr_within_range = arm_linux_watchpoint_addr_within_range;
- t->to_read_description = arm_linux_read_description;
-
- linux_nat_add_target (t);
-
- linux_nat_set_new_thread (t, arm_linux_new_thread);
- linux_nat_set_prepare_to_resume (t, arm_linux_prepare_to_resume);
-
- linux_nat_set_new_fork (t, arm_linux_new_fork);
- linux_nat_set_forget_process (t, arm_linux_forget_process);
- }