Fri Jan 1 12:58:36 2021 UTC ()
Pull up following revision(s) (requested by rin in ticket #1172):

	sys/arch/aarch64/aarch64/trap.c: revision 1.30
	sys/arch/aarch64/include/ptrace.h: revision 1.10
	sys/arch/aarch64/include/netbsd32_machdep.h: revision 1.4 (patch)
	sys/arch/aarch64/aarch64/netbsd32_machdep.c: revision 1.14
	sys/arch/aarch64/aarch64/netbsd32_machdep.c: revision 1.15

Add support of ptrace(2) for COMPAT_NETBSD32.

Now, GDB for arm32 is usable for debugging 32bit applications.
OK ryo@

For rev 1.14 and before, netbsd32_process_write_regs() returns EINVAL
if non-modifiable bits are set in CPSR.
Instead, mask out non-modifiable bits and make this function success
regardless of value in CPSR. New behavior matches that of arm:
https://nxr.netbsd.org/xref/src/sys/arch/arm/arm/process_machdep.c#187

This fixes lib/libc/sys/t_ptrace_wait*:access_regs6 tests, in which
register contents retrieved by PT_GETREGS are set back by PT_SETREGS.

No new regression is observed in full ATF run.

OK ryo


(martin)
diff -r1.7.2.1 -r1.7.2.2 src/sys/arch/aarch64/aarch64/netbsd32_machdep.c
diff -r1.17.4.3 -r1.17.4.4 src/sys/arch/aarch64/aarch64/trap.c
diff -r1.2 -r1.2.4.1 src/sys/arch/aarch64/include/netbsd32_machdep.h
diff -r1.9 -r1.9.2.1 src/sys/arch/aarch64/include/ptrace.h

cvs diff -r1.7.2.1 -r1.7.2.2 src/sys/arch/aarch64/aarch64/netbsd32_machdep.c (expand / switch to context diff)
--- src/sys/arch/aarch64/aarch64/netbsd32_machdep.c 2020/05/02 16:26:04 1.7.2.1
+++ src/sys/arch/aarch64/aarch64/netbsd32_machdep.c 2021/01/01 12:58:35 1.7.2.2
@@ -1,4 +1,4 @@
-/*	$NetBSD: netbsd32_machdep.c,v 1.7.2.1 2020/05/02 16:26:04 martin Exp $	*/
+/*	$NetBSD: netbsd32_machdep.c,v 1.7.2.2 2021/01/01 12:58:35 martin Exp $	*/
 
 /*
  * Copyright (c) 2018 Ryo Shimizu <ryo@nerv.org>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.7.2.1 2020/05/02 16:26:04 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.7.2.2 2021/01/01 12:58:35 martin Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_compat_netbsd.h"
@@ -37,6 +37,7 @@
 #include <sys/core.h>
 #include <sys/exec.h>
 #include <sys/lwp.h>
+#include <sys/ptrace.h>
 #include <sys/ras.h>
 #include <sys/signalvar.h>
 #include <sys/syscallargs.h>
@@ -93,6 +94,30 @@
 		tf->tf_spsr |= SPSR_A32_T;
 }
 
+int
+netbsd32_ptrace_translate_request(int req)
+{
+
+	switch (req) {
+	case 0 ... PT_FIRSTMACH - 1:
+		return req;
+	case PT32_GETREGS:
+		return PT_GETREGS;
+	case PT32_SETREGS:
+		return PT_SETREGS;
+	case PT32_GETFPREGS:
+		return PT_GETFPREGS;
+	case PT32_SETFPREGS:
+		return PT_SETFPREGS;
+	/* not implemented for arm32 */
+	case PT32_STEP:
+	case PT32_SETSTEP:
+	case PT32_CLEARSTEP:
+	default:
+		return -1;
+	}
+}
+
 /* aarch32 fpscr register is assigned to two registers fpsr/fpcr on aarch64 */
 #define FPSR_BITS							\
 	(FPSR_N32|FPSR_Z32|FPSR_C32|FPSR_V32|FPSR_QC|			\
@@ -101,7 +126,7 @@
 	(FPCR_AHP|FPCR_DN|FPCR_FZ|FPCR_RMODE|FPCR_STRIDE|FPCR_LEN|	\
 	 FPCR_IDE|FPCR_IXE|FPCR_UFE|FPCR_OFE|FPCR_DZE|FPCR_IOE)
 
-static int
+int
 netbsd32_process_read_regs(struct lwp *l, struct reg32 *regs)
 {
 	struct proc * const p = l->l_proc;
@@ -125,7 +150,7 @@
 	return 0;
 }
 
-static int
+int
 netbsd32_process_read_fpregs(struct lwp *l, struct fpreg32 *fpregs,
     size_t *lenp)
 {
@@ -159,6 +184,68 @@
 #else
 		fpregs->fpr_vfp.vfp_regs[i] = pcb->pcb_fpregs.fp_reg[i].u64[0];
 #endif
+	}
+
+	return 0;
+}
+
+int
+netbsd32_process_write_regs(struct lwp *l, const struct reg32 *regs)
+{
+	struct proc * const p = l->l_proc;
+	struct trapframe *tf = l->l_md.md_utf;
+	int i;
+
+	if ((p->p_flag & PK_32) == 0)
+		return EINVAL;
+
+	if (regs->r_pc >= VM_MAXUSER_ADDRESS32 ||
+	    regs->r_sp >= VM_MAXUSER_ADDRESS32)
+		return EINVAL;
+
+	for (i = 0; i < 13; i++)
+		tf->tf_reg[i] = regs->r[i];	/* r0-r12 */
+	tf->tf_reg[13] = regs->r_sp;		/* r13 = sp */
+	tf->tf_reg[14] = regs->r_lr;		/* r14 = lr */
+	tf->tf_pc = regs->r_pc;			/* r15 = pc */
+	tf->tf_spsr &= ~(SPSR_NZCV | SPSR_A32_T);
+	tf->tf_spsr |= regs->r_cpsr & (SPSR_NZCV | SPSR_A32_T);
+
+	/* THUMB CODE? */
+	if (regs->r_pc & 1)
+		tf->tf_spsr |= SPSR_A32_T;
+
+	return 0;
+}
+
+int
+netbsd32_process_write_fpregs(struct lwp *l, const struct fpreg32 *fpregs,
+    size_t len)
+{
+	struct proc * const p = l->l_proc;
+	struct pcb * const pcb = lwp_getpcb(l);
+	int i;
+
+	if ((p->p_flag & PK_32) == 0)
+		return EINVAL;
+
+	KASSERT(len <= sizeof(*fpregs));
+	fpu_discard(l, true);		// set used flag
+
+	pcb->pcb_fpregs.fpsr = fpregs->fpr_vfp.vfp_fpscr & FPSR_BITS;
+	pcb->pcb_fpregs.fpcr = fpregs->fpr_vfp.vfp_fpscr & FPCR_BITS;
+
+	CTASSERT(__arraycount(fpregs->fpr_vfp.vfp_regs) ==
+	    __arraycount(pcb->pcb_fpregs.fp_reg) + 1);
+	for (i = 0; i < __arraycount(pcb->pcb_fpregs.fp_reg); i++) {
+#ifdef __AARCH64EB__
+		pcb->pcb_fpregs.fp_reg[i].u64[0] = 0;
+		pcb->pcb_fpregs.fp_reg[i].u64[1] =
+#else
+		pcb->pcb_fpregs.fp_reg[i].u64[1] = 0;
+		pcb->pcb_fpregs.fp_reg[i].u64[0] =
+#endif
+		    fpregs->fpr_vfp.vfp_regs[i];
 	}
 
 	return 0;

cvs diff -r1.17.4.3 -r1.17.4.4 src/sys/arch/aarch64/aarch64/trap.c (expand / switch to context diff)
--- src/sys/arch/aarch64/aarch64/trap.c 2021/01/01 12:31:19 1.17.4.3
+++ src/sys/arch/aarch64/aarch64/trap.c 2021/01/01 12:58:35 1.17.4.4
@@ -1,4 +1,4 @@
-/* $NetBSD: trap.c,v 1.17.4.3 2021/01/01 12:31:19 martin Exp $ */
+/* $NetBSD: trap.c,v 1.17.4.4 2021/01/01 12:58:35 martin Exp $ */
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.17.4.3 2021/01/01 12:31:19 martin Exp $");
+__KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.17.4.4 2021/01/01 12:58:35 martin Exp $");
 
 #include "opt_arm_intr_impl.h"
 #include "opt_compat_netbsd32.h"
@@ -396,6 +396,7 @@
 static enum emul_arm_result
 emul_arm_insn(struct trapframe *tf)
 {
+	struct lwp * const l = curlwp;
 	uint32_t insn;
 	int insn_size;
 
@@ -405,10 +406,26 @@
 	case 2:
 		/* T32-16bit instruction */
 
+		/*
+		 * Breakpoint used by GDB.
+		 */
+		if (insn == 0xdefe)
+			goto trap;
+
 		/* XXX: some T32 IT instruction deprecated should be emulated */
 		break;
 	case 4:
 		/* T32-32bit instruction, or A32 instruction */
+
+		/*
+		 * Breakpoint used by GDB.
+		 */
+		if (insn == 0xe6000011 || insn == 0xe7ffdefe) {
+ trap:
+			do_trapsignal(l, SIGTRAP, TRAP_BRKPT,
+			    (void *)tf->tf_pc, 0);
+			return 0;
+		}
 
 		/*
 		 * Emulate ARMv6 instructions with cache operations

cvs diff -r1.2 -r1.2.4.1 src/sys/arch/aarch64/include/netbsd32_machdep.h (expand / switch to context diff)
--- src/sys/arch/aarch64/include/netbsd32_machdep.h 2018/10/12 01:28:58 1.2
+++ src/sys/arch/aarch64/include/netbsd32_machdep.h 2021/01/01 12:58:35 1.2.4.1
@@ -1,4 +1,4 @@
-/*	$NetBSD: netbsd32_machdep.h,v 1.2 2018/10/12 01:28:58 ryo Exp $	*/
+/*	$NetBSD: netbsd32_machdep.h,v 1.2.4.1 2021/01/01 12:58:35 martin Exp $	*/
 
 #ifndef _MACHINE_NETBSD32_H_
 #define _MACHINE_NETBSD32_H_
@@ -7,6 +7,18 @@
 #include <compat/sys/ucontext.h>
 #include <compat/sys/siginfo.h>
 
+/*
+ * arm ptrace constants
+ * Please keep in sync with sys/arch/arm/include/ptrace.h.
+ */
+#define PT32_STEP	(PT_FIRSTMACH + 0) /* Not implemented */
+#define PT32_GETREGS	(PT_FIRSTMACH + 1)
+#define PT32_SETREGS	(PT_FIRSTMACH + 2)
+#define PT32_GETFPREGS	(PT_FIRSTMACH + 5)
+#define PT32_SETFPREGS	(PT_FIRSTMACH + 6)
+#define PT32_SETSTEP	(PT_FIRSTMACH + 7) /* Not implemented */
+#define PT32_CLEARSTEP	(PT_FIRSTMACH + 8) /* Not implemented */
+
 #define NETBSD32_POINTER_TYPE uint32_t
 typedef	struct { NETBSD32_POINTER_TYPE i32; } netbsd32_pointer_t;
 
@@ -103,8 +115,17 @@
 #define ARM_FPU_USED		3
 
 struct netbsd32_arm_sync_icache_args {
-	netbsd32_uintptr_t addr;	/* Virtual start address */
-	netbsd32_size_t len;		/* Region size */
+	uint32_t addr;		/* Virtual start address */
+	uint32_t len;		/* Region size */
 };
+
+/* Translate ptrace() PT_* request from 32-bit userland to kernel. */
+int netbsd32_ptrace_translate_request(int);
+
+int netbsd32_process_read_regs(struct lwp *, struct reg32 *);
+int netbsd32_process_read_fpregs(struct lwp *, struct fpreg32 *, size_t *);
+
+int netbsd32_process_write_regs(struct lwp *, const struct reg32 *);
+int netbsd32_process_write_fpregs(struct lwp *, const struct fpreg32 *, size_t);
 
 #endif /* _MACHINE_NETBSD32_H_ */

cvs diff -r1.9 -r1.9.2.1 src/sys/arch/aarch64/include/ptrace.h (expand / switch to context diff)
--- src/sys/arch/aarch64/include/ptrace.h 2019/06/18 21:18:11 1.9
+++ src/sys/arch/aarch64/include/ptrace.h 2021/01/01 12:58:35 1.9.2.1
@@ -1,4 +1,4 @@
-/* $NetBSD: ptrace.h,v 1.9 2019/06/18 21:18:11 kamil Exp $ */
+/* $NetBSD: ptrace.h,v 1.9.2.1 2021/01/01 12:58:35 martin Exp $ */
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -65,6 +65,25 @@
 #define PTRACE_BREAKPOINT	((const uint8_t[]) { 0xa0, 0x01, 0x20, 0xd4 })
 #define PTRACE_BREAKPOINT_ASM	__asm __volatile("brk #13" ::: "memory")
 #define PTRACE_BREAKPOINT_SIZE	4
+
+#ifdef _KERNEL_OPT
+#include "opt_compat_netbsd32.h"
+#endif
+
+#ifdef COMPAT_NETBSD32
+#include <machine/netbsd32_machdep.h>
+
+#define process_read_regs32	netbsd32_process_read_regs
+#define process_read_fpregs32	netbsd32_process_read_fpregs
+
+#define process_write_regs32	netbsd32_process_write_regs
+#define process_write_fpregs32	netbsd32_process_write_fpregs
+
+#define process_reg32		struct reg32
+#define process_fpreg32		struct fpreg32
+
+#define PTRACE_TRANSLATE_REQUEST32(x) netbsd32_ptrace_translate_request(x)
+#endif /* COMPAT_NETBSD32 */
 
 #elif defined(__arm__)