Subject: coredumps under COMPAT_NETBSD32
To: None <tech-kern@netbsd.org>
From: Quentin Garnier <cube@cubidou.net>
List: tech-kern
Date: 03/02/2006 18:48:58
--4bvUAv41pAMZZO4U
Content-Type: multipart/mixed; boundary="aBfuQK/t93Uihhfq"
Content-Disposition: inline


--aBfuQK/t93Uihhfq
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

Hi folks,

It hasn't been possible to produce usable coredumps of netbsd32 binaries
for quite a while (something like 2001).

The attached patch adds the general framework to make it work again, as
well as the MD bits for amd64 (sparc64 is left as an exercise to the
reader).

I'm questioning the method, though.  The patch has the advantage of
being very simple, but I still think the information needed by the
function that produces the coredump should be in a mix of struct exec
and struct emul (e.g., do Linux and NetBSD use the same register dump
format?).  Then it raises the question of how things are supposed to
happen when compat_netbsd32 is loaded as LKM.

Also, the code that tries to convert the FPU registers from amd64 to
i386 doesn't seem to work correctly for my quick tests.  I could use
some help there.

Comments?

--=20
Quentin Garnier - cube@cubidou.net - cube@NetBSD.org
"When I find the controls, I'll go where I like, I'll know where I want
to be, but maybe for now I'll stay right here on a silent sea."
KT Tunstall, Silent Sea, Eye to the Telescope, 2004.

--aBfuQK/t93Uihhfq
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="netbsd32_coredump.diff"
Content-Transfer-Encoding: quoted-printable

Index: sys/arch/amd64/amd64/netbsd32_machdep.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/arch/amd64/amd64/netbsd32_machdep.c,v
retrieving revision 1.20
diff -u -r1.20 netbsd32_machdep.c
--- sys/arch/amd64/amd64/netbsd32_machdep.c	14 Jan 2006 17:14:46 -0000	1.20
+++ sys/arch/amd64/amd64/netbsd32_machdep.c	2 Mar 2006 16:14:15 -0000
@@ -54,6 +54,7 @@
 #include <sys/buf.h>
 #include <sys/vnode.h>
 #include <sys/ras.h>
+#include <sys/ptrace.h>
=20
 #include <machine/fpu.h>
 #include <machine/frame.h>
@@ -71,9 +72,6 @@
 const char	machine32[] =3D "i386";
 const char	machine_arch32[] =3D "i386";=09
=20
-int process_read_fpregs32(struct lwp *, struct fpreg32 *);
-int process_read_regs32(struct lwp *, struct reg32 *);
-
 extern void (osyscall_return) __P((void));
=20
 static int x86_64_get_mtrr32(struct lwp *, void *, register_t *);
@@ -436,12 +434,12 @@
 	}
=20
 	/* Save integer registers. */
-	error =3D process_read_regs32(l, &md_core.intreg);
+	error =3D netbsd32_process_read_regs(l, &md_core.intreg);
 	if (error)
 		return error;
=20
 	/* Save floating point registers. */
-	error =3D process_read_fpregs32(l, &md_core.freg);
+	error =3D netbsd32_process_read_fpregs(l, &md_core.freg);
 	if (error)
 		return error;
=20
@@ -458,9 +456,8 @@
 	    sizeof(md_core));
 }
=20
-
 int
-process_read_regs32(struct lwp *l, struct reg32 *regs)
+netbsd32_process_read_regs(struct lwp *l, struct reg32 *regs)
 {
 	struct trapframe *tf =3D l->l_md.md_regs;
=20
@@ -485,21 +482,82 @@
 	return (0);
 }
=20
+static int
+xmm_to_s87_tag(const uint8_t *fpac, int regno, uint8_t tw)
+{
+	static const uint8_t empty_significand[8] =3D { 0 };
+	int tag;
+	uint16_t exponent;
+
+	if (tw & (1U << regno)) {
+		exponent =3D fpac[8] | (fpac[9] << 8);
+		switch (exponent) {
+		case 0x7fff:
+			tag =3D 2;
+			break;
+
+		case 0x0000:
+			if (memcmp(empty_significand, fpac,
+				   sizeof(empty_significand)) =3D=3D 0)
+				tag =3D 1;
+			else
+				tag =3D 2;
+			break;
+
+		default:
+			if ((fpac[7] & 0x80) =3D=3D 0)
+				tag =3D 2;
+			else
+				tag =3D 0;
+			break;
+		}
+	} else
+		tag =3D 3;
+
+	return (tag);
+}
+
 int
-process_read_fpregs32(struct lwp *l, struct fpreg32 *regs)
+netbsd32_process_read_fpregs(struct lwp *l, struct fpreg32 *regs)
 {
-	struct oldfsave frame;
+	struct savefpu *sf =3D &l->l_addr->u_pcb.pcb_savefpu;
+	struct fpreg regs64;
+	struct save87 *s87 =3D (struct save87 *)regs;
+	int error, i;
=20
-	if (l->l_md.md_flags & MDP_USEDFPU) {
-		fpusave_lwp(l, 1);
-	} else {
-		memset(&frame, 0, sizeof(*regs));
-		frame.fs_control =3D __NetBSD_NPXCW__;
-		frame.fs_tag =3D 0xffff;
-		l->l_md.md_flags |=3D MDP_USEDFPU;
+	/*
+	 * All that stuff makes no sense in i386 code.
+	 */
+
+	error =3D process_read_fpregs(l, &regs64);
+	if (error)
+		return error;
+
+	s87->sv_env.en_cw =3D regs64.fxstate.fx_fcw;
+	s87->sv_env.en_sw =3D regs64.fxstate.fx_fsw;
+	s87->sv_env.en_fip =3D regs64.fxstate.fx_rip >> 16; /* XXX Order? */
+	s87->sv_env.en_fcs =3D regs64.fxstate.fx_rip & 0xffff;
+	s87->sv_env.en_opcode =3D regs64.fxstate.fx_fop;
+	s87->sv_env.en_foo =3D regs64.fxstate.fx_rdp >> 16; /* XXX See above */
+	s87->sv_env.en_fos =3D regs64.fxstate.fx_rdp & 0xffff;
+
+	s87->sv_env.en_tw =3D 0;
+	s87->sv_ex_tw =3D 0;
+	for (i =3D 0; i < 8; i++) {
+		s87->sv_env.en_tw |=3D
+		    (xmm_to_s87_tag((uint8_t *)&regs64.fxstate.fx_st[i][0], i,
+		     regs64.fxstate.fx_ftw) << (i * 2));
+
+		s87->sv_ex_tw |=3D
+		    (xmm_to_s87_tag((uint8_t *)&regs64.fxstate.fx_st[i][0], i,
+		     sf->fp_ex_tw) << (i * 2));
+
+		memcpy(&s87->sv_ac[i].fp_bytes, &regs64.fxstate.fx_st[i][0],
+		    sizeof(s87->sv_ac[i].fp_bytes));
 	}
=20
-	memcpy(regs, &frame, sizeof(*regs));
+	s87->sv_ex_sw =3D sf->fp_ex_sw;
+
 	return (0);
 }
=20
Index: sys/arch/amd64/include/netbsd32_machdep.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/arch/amd64/include/netbsd32_machdep.h,v
retrieving revision 1.8
diff -u -r1.8 netbsd32_machdep.h
--- sys/arch/amd64/include/netbsd32_machdep.h	11 Dec 2005 12:16:25 -0000	1.8
+++ sys/arch/amd64/include/netbsd32_machdep.h	2 Mar 2006 16:14:16 -0000
@@ -130,6 +130,32 @@
 	uint32_t n;
 };
=20
+struct env87 {
+	int32_t		en_cw;
+	int32_t		en_sw;
+	int32_t		en_tw;
+	int32_t		en_fip;
+	uint16_t	en_fcs;
+	uint16_t	en_opcode;
+	int32_t		en_foo;
+	int32_t		en_fos;
+} __attribute__((packed));
+
+struct fpacc87 {
+	uint8_t 	fp_bytes[10];
+} __attribute__((packed));
+
+struct save87 {
+	struct env87	sv_env;
+	struct fpacc87	sv_ac[8];
+	int32_t		sv_ex_sw;
+	int32_t		sv_ex_tw;
+	uint8_t		sv_pad[8 * 2 - 2 * 4];
+} __attribute__((packed));
+
 #define NETBSD32_MID_MACHINE MID_I386
=20
+int netbsd32_process_read_regs(struct lwp *, struct reg32 *);
+int netbsd32_process_read_fpregs(struct lwp *, struct fpreg32 *);
+
 #endif /* _MACHINE_NETBSD32_H_ */
Index: sys/arch/amd64/include/ptrace.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/arch/amd64/include/ptrace.h,v
retrieving revision 1.1
diff -u -r1.1 ptrace.h
--- sys/arch/amd64/include/ptrace.h	26 Apr 2003 18:39:47 -0000	1.1
+++ sys/arch/amd64/include/ptrace.h	2 Mar 2006 16:14:16 -0000
@@ -38,3 +38,17 @@
 #define	PT_SETREGS	(PT_FIRSTMACH + 2)
 #define	PT_GETFPREGS	(PT_FIRSTMACH + 3)
 #define	PT_SETFPREGS	(PT_FIRSTMACH + 4)
+
+#ifdef _KERNEL_OPT
+#include "opt_compat_netbsd32.h"
+
+#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_reg32		struct reg32
+#define process_fpreg32		struct fpreg32
+#endif
+#endif
Index: sys/kern/core_elf32.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/kern/core_elf32.c,v
retrieving revision 1.22
diff -u -r1.22 core_elf32.c
--- sys/kern/core_elf32.c	8 Dec 2005 03:05:40 -0000	1.22
+++ sys/kern/core_elf32.c	2 Mar 2006 16:14:39 -0000
@@ -83,6 +83,11 @@
 #define	ELFROUNDSIZE	4	/* XXX Should it be sizeof(Elf_Word)? */
 #define	elfround(x)	roundup((x), ELFROUNDSIZE)
=20
+#define elf_process_read_regs	CONCAT(process_read_regs, ELFSIZE)
+#define elf_process_read_fpregs	CONCAT(process_read_fpregs, ELFSIZE)
+#define elf_reg			CONCAT(process_reg, ELFSIZE)
+#define elf_fpreg		CONCAT(process_fpreg, ELFSIZE)
+
 int
 ELFNAMEEND(coredump)(struct lwp *l, void *cookie)
 {
@@ -395,9 +400,9 @@
 	int size, notesize, error;
 	int namesize;
 	char name[64+ELFROUNDSIZE];
-	struct reg intreg;
+	elf_reg intreg;
 #ifdef PT_GETFPREGS
-	struct fpreg freg;
+	elf_fpreg freg;
 #endif
=20
 	size =3D 0;
@@ -410,7 +415,7 @@
 	notesize =3D sizeof(nhdr) + elfround(namesize) + elfround(sizeof(intreg));
 	if (iocookie) {
 		PHOLD(l);
-		error =3D process_read_regs(l, &intreg);
+		error =3D elf_process_read_regs(l, &intreg);
 		PRELE(l);
 		if (error)
 			return (error);
@@ -431,7 +436,7 @@
 	notesize =3D sizeof(nhdr) + elfround(namesize) + elfround(sizeof(freg));
 	if (iocookie) {
 		PHOLD(l);
-		error =3D process_read_fpregs(l, &freg);
+		error =3D elf_process_read_fpregs(l, &freg);
 		PRELE(l);
 		if (error)
 			return (error);
Index: sys/sys/ptrace.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/sys/ptrace.h,v
retrieving revision 1.35
diff -u -r1.35 ptrace.h
--- sys/sys/ptrace.h	11 Dec 2005 12:25:21 -0000	1.35
+++ sys/sys/ptrace.h	2 Mar 2006 16:14:41 -0000
@@ -81,9 +81,21 @@
=20
 #if defined(PT_GETREGS) || defined(PT_SETREGS)
 struct reg;
+#ifndef process_reg32
+#define process_reg32 struct reg
+#endif
+#ifndef process_reg64
+#define process_reg64 struct reg
+#endif
 #endif
 #if defined(PT_GETFPREGS) || defined(PT_SETFPREGS)
 struct fpreg;
+#ifndef process_fpreg32
+#define process_fpreg32 struct fpreg
+#endif
+#ifndef process_fpreg64
+#define process_fpreg64 struct fpreg
+#endif
 #endif
=20
 int	process_doregs(struct lwp *, struct lwp *, struct uio *);
@@ -98,9 +110,21 @@
 void	proc_reparent(struct proc *, struct proc *);
 #ifdef PT_GETFPREGS
 int	process_read_fpregs(struct lwp *, struct fpreg *);
+#ifndef process_read_fpregs32
+#define process_read_fpregs32	process_read_fpregs
+#endif
+#ifndef process_read_fpregs64
+#define process_read_fpregs64	process_read_fpregs
+#endif
 #endif
 #ifdef PT_GETREGS
 int	process_read_regs(struct lwp *, struct reg *);
+#ifndef process_read_regs32
+#define process_read_regs32	process_read_regs
+#endif
+#ifndef process_read_regs64
+#define process_read_regs64	process_read_regs
+#endif
 #endif
 int	process_set_pc(struct lwp *, caddr_t);
 int	process_sstep(struct lwp *, int);

--aBfuQK/t93Uihhfq--

--4bvUAv41pAMZZO4U
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.6 (NetBSD)

iQEVAwUBRAcwCtgoQloHrPnoAQKIiAgAqzvEjXmCTMD5DIVIGTq3cLaTYnrVBDFT
pxOXmVgBhdSGwFcGpi5Je14I6CMerEysrjYHVhDOXxZy7bAvD4QOfP44OAS5lHin
ebyqOA5ys/TCgz7bIR+l/RQ/LBAZK2CjZHr/qAkKQpMAxlkh5YfDX0fd6IQ3iUNo
gLnmAqJOeSMktxSQailEeNArN9cutgg/pAijcmlJpH5xfV3JsYBY7NK7EA3saLip
2Uj6+SZ4Momo8lMGBvRiag70dHPjm3ZWfq8Oc843kSmKLpHYeCzYE5Mv0/kOQBs1
/SuPQ7VzHWrd/uw6zZFVgmZL7pAZnXVMzo2jSe27za1p7M1TIPMgEA==
=hT2H
-----END PGP SIGNATURE-----

--4bvUAv41pAMZZO4U--