+static void
+arm_new_fork (struct process_info *parent, struct process_info *child)
+{
+ struct arch_process_info *parent_proc_info;
+ struct arch_process_info *child_proc_info;
+ struct lwp_info *child_lwp;
+ struct arch_lwp_info *child_lwp_info;
+ int i;
+
+ /* These are allocated by linux_add_process. */
+ gdb_assert (parent->priv != NULL
+ && parent->priv->arch_private != NULL);
+ gdb_assert (child->priv != NULL
+ && child->priv->arch_private != NULL);
+
+ parent_proc_info = parent->priv->arch_private;
+ child_proc_info = child->priv->arch_private;
+
+ /* Linux kernel before 2.6.33 commit
+ 72f674d203cd230426437cdcf7dd6f681dad8b0d
+ will inherit hardware debug registers from parent
+ on fork/vfork/clone. Newer Linux kernels create such tasks with
+ zeroed debug registers.
+
+ GDB core assumes the child inherits the watchpoints/hw
+ breakpoints of the parent, and will remove them all from the
+ forked off process. Copy the debug registers mirrors into the
+ new process so that all breakpoints and watchpoints can be
+ removed together. The debug registers mirror will become zeroed
+ in the end before detaching the forked off process, thus making
+ this compatible with older Linux kernels too. */
+
+ *child_proc_info = *parent_proc_info;
+
+ /* Mark all the hardware breakpoints and watchpoints as changed to
+ make sure that the registers will be updated. */
+ child_lwp = find_lwp_pid (ptid_t (child->pid));
+ child_lwp_info = child_lwp->arch_private;
+ for (i = 0; i < MAX_BPTS; i++)
+ child_lwp_info->bpts_changed[i] = 1;
+ for (i = 0; i < MAX_WPTS; i++)
+ child_lwp_info->wpts_changed[i] = 1;
+}
+
+/* Called when resuming a thread.
+ If the debug regs have changed, update the thread's copies. */
+static void
+arm_prepare_to_resume (struct lwp_info *lwp)
+{
+ struct thread_info *thread = get_lwp_thread (lwp);
+ int pid = lwpid_of (thread);
+ struct process_info *proc = find_process_pid (pid_of (thread));
+ struct arch_process_info *proc_info = proc->priv->arch_private;
+ struct arch_lwp_info *lwp_info = lwp->arch_private;
+ int i;
+
+ for (i = 0; i < arm_linux_get_hw_breakpoint_count (); i++)
+ if (lwp_info->bpts_changed[i])
+ {
+ errno = 0;
+
+ if (arm_hwbp_control_is_enabled (proc_info->bpts[i].control))
+ if (ptrace (PTRACE_SETHBPREGS, pid,
+ (PTRACE_TYPE_ARG3) ((i << 1) + 1),
+ &proc_info->bpts[i].address) < 0)
+ perror_with_name ("Unexpected error setting breakpoint address");
+
+ if (arm_hwbp_control_is_initialized (proc_info->bpts[i].control))
+ if (ptrace (PTRACE_SETHBPREGS, pid,
+ (PTRACE_TYPE_ARG3) ((i << 1) + 2),
+ &proc_info->bpts[i].control) < 0)
+ perror_with_name ("Unexpected error setting breakpoint");
+
+ lwp_info->bpts_changed[i] = 0;
+ }
+
+ for (i = 0; i < arm_linux_get_hw_watchpoint_count (); i++)
+ if (lwp_info->wpts_changed[i])
+ {
+ errno = 0;
+
+ if (arm_hwbp_control_is_enabled (proc_info->wpts[i].control))
+ if (ptrace (PTRACE_SETHBPREGS, pid,
+ (PTRACE_TYPE_ARG3) -((i << 1) + 1),
+ &proc_info->wpts[i].address) < 0)
+ perror_with_name ("Unexpected error setting watchpoint address");
+
+ if (arm_hwbp_control_is_initialized (proc_info->wpts[i].control))
+ if (ptrace (PTRACE_SETHBPREGS, pid,
+ (PTRACE_TYPE_ARG3) -((i << 1) + 2),
+ &proc_info->wpts[i].control) < 0)
+ perror_with_name ("Unexpected error setting watchpoint");
+
+ lwp_info->wpts_changed[i] = 0;
+ }
+}
+
+/* Find the next pc for a sigreturn or rt_sigreturn syscall. In
+ addition, set IS_THUMB depending on whether we will return to ARM
+ or Thumb code.
+ See arm-linux.h for stack layout details. */
+static CORE_ADDR
+arm_sigreturn_next_pc (struct regcache *regcache, int svc_number,
+ int *is_thumb)
+{
+ unsigned long sp;
+ unsigned long sp_data;
+ /* Offset of PC register. */
+ int pc_offset = 0;
+ CORE_ADDR next_pc = 0;
+ uint32_t cpsr;
+
+ gdb_assert (svc_number == __NR_sigreturn || svc_number == __NR_rt_sigreturn);
+
+ collect_register_by_name (regcache, "sp", &sp);
+ (*the_target->read_memory) (sp, (unsigned char *) &sp_data, 4);
+
+ pc_offset = arm_linux_sigreturn_next_pc_offset
+ (sp, sp_data, svc_number, __NR_sigreturn == svc_number ? 1 : 0);
+
+ (*the_target->read_memory) (sp + pc_offset, (unsigned char *) &next_pc, 4);
+
+ /* Set IS_THUMB according the CPSR saved on the stack. */
+ (*the_target->read_memory) (sp + pc_offset + 4, (unsigned char *) &cpsr, 4);
+ *is_thumb = ((cpsr & CPSR_T) != 0);
+
+ return next_pc;
+}
+
+/* When PC is at a syscall instruction, return the PC of the next
+ instruction to be executed. */
+static CORE_ADDR
+get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self)
+{
+ CORE_ADDR next_pc = 0;
+ CORE_ADDR pc = regcache_read_pc (self->regcache);
+ int is_thumb = arm_is_thumb_mode ();
+ ULONGEST svc_number = 0;
+ struct regcache *regcache = self->regcache;
+
+ if (is_thumb)
+ {
+ collect_register (regcache, 7, &svc_number);
+ next_pc = pc + 2;
+ }
+ else
+ {
+ unsigned long this_instr;
+ unsigned long svc_operand;
+
+ target_read_memory (pc, (unsigned char *) &this_instr, 4);
+ svc_operand = (0x00ffffff & this_instr);
+
+ if (svc_operand) /* OABI. */
+ {
+ svc_number = svc_operand - 0x900000;
+ }
+ else /* EABI. */
+ {
+ collect_register (regcache, 7, &svc_number);
+ }
+
+ next_pc = pc + 4;
+ }
+
+ /* This is a sigreturn or sigreturn_rt syscall. */
+ if (svc_number == __NR_sigreturn || svc_number == __NR_rt_sigreturn)
+ {
+ /* SIGRETURN or RT_SIGRETURN may affect the arm thumb mode, so
+ update IS_THUMB. */
+ next_pc = arm_sigreturn_next_pc (regcache, svc_number, &is_thumb);
+ }
+
+ /* Addresses for calling Thumb functions have the bit 0 set. */
+ if (is_thumb)
+ next_pc = MAKE_THUMB_ADDR (next_pc);
+
+ return next_pc;
+}
+
+static const struct target_desc *
+arm_read_description (void)
+{
+ unsigned long arm_hwcap = linux_get_hwcap (4);
+
+ if (arm_hwcap & HWCAP_IWMMXT)
+ return arm_linux_read_description (ARM_FP_TYPE_IWMMXT);
+
+ if (arm_hwcap & HWCAP_VFP)
+ {
+ /* Make sure that the kernel supports reading VFP registers. Support was
+ added in 2.6.30. */
+ int pid = lwpid_of (current_thread);
+ errno = 0;
+ char *buf = (char *) alloca (ARM_VFP3_REGS_SIZE);
+ if (ptrace (PTRACE_GETVFPREGS, pid, 0, buf) < 0 && errno == EIO)
+ return arm_linux_read_description (ARM_FP_TYPE_NONE);
+
+ /* NEON implies either no VFP, or VFPv3-D32. We only support
+ it with VFP. */
+ if (arm_hwcap & HWCAP_NEON)
+ return aarch32_linux_read_description ();
+ else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3)
+ return arm_linux_read_description (ARM_FP_TYPE_VFPV3);
+ else
+ return arm_linux_read_description (ARM_FP_TYPE_VFPV2);
+ }
+
+ /* The default configuration uses legacy FPA registers, probably
+ simulated. */
+ return arm_linux_read_description (ARM_FP_TYPE_NONE);
+}
+
+static void
+arm_arch_setup (void)
+{
+ int tid = lwpid_of (current_thread);
+ int gpregs[18];
+ struct iovec iov;
+
+ /* Query hardware watchpoint/breakpoint capabilities. */
+ arm_linux_init_hwbp_cap (tid);
+
+ current_process ()->tdesc = arm_read_description ();
+
+ iov.iov_base = gpregs;
+ iov.iov_len = sizeof (gpregs);
+
+ /* Check if PTRACE_GETREGSET works. */
+ if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, &iov) == 0)
+ have_ptrace_getregset = 1;
+ else
+ have_ptrace_getregset = 0;
+}
+
+/* Fetch the next possible PCs after the current instruction executes. */
+
+static std::vector<CORE_ADDR>
+arm_gdbserver_get_next_pcs (struct regcache *regcache)
+{
+ struct arm_get_next_pcs next_pcs_ctx;
+
+ arm_get_next_pcs_ctor (&next_pcs_ctx,
+ &get_next_pcs_ops,
+ /* Byte order is ignored assumed as host. */
+ 0,
+ 0,
+ 1,
+ regcache);
+
+ return arm_get_next_pcs (&next_pcs_ctx);
+}
+
+/* Support for hardware single step. */
+
+static int
+arm_supports_hardware_single_step (void)
+{
+ return 0;
+}
+
+/* Implementation of linux_target_ops method "get_syscall_trapinfo". */
+
+static void
+arm_get_syscall_trapinfo (struct regcache *regcache, int *sysno)
+{
+ if (arm_is_thumb_mode ())
+ collect_register_by_name (regcache, "r7", sysno);
+ else
+ {
+ unsigned long pc;
+ unsigned long insn;
+
+ collect_register_by_name (regcache, "pc", &pc);
+
+ if ((*the_target->read_memory) (pc - 4, (unsigned char *) &insn, 4))
+ *sysno = UNKNOWN_SYSCALL;
+ else
+ {
+ unsigned long svc_operand = (0x00ffffff & insn);
+
+ if (svc_operand)
+ {
+ /* OABI */
+ *sysno = svc_operand - 0x900000;
+ }
+ else
+ {
+ /* EABI */
+ collect_register_by_name (regcache, "r7", sysno);
+ }
+ }
+ }
+}
+
+/* Register sets without using PTRACE_GETREGSET. */
+
+static struct regset_info arm_regsets[] = {
+ { PTRACE_GETREGS, PTRACE_SETREGS, 0,
+ ARM_CORE_REGS_SIZE + ARM_INT_REGISTER_SIZE, GENERAL_REGS,