Subject: emuldata addition
To: None <tech-kern@netbsd.org>
From: Jaromír Dolecek <dolecek@ibis.cz>
List: tech-kern
Date: 10/29/2000 13:09:39
Hi,
during an efford to make Linux ptrace(2) emulation work correctly on i386,
I came to a need to store somewhere some additional per-process data
Linux gdb uses for tracing. The easiest way how to avoid dirty hacks
and memory leaks would probably to add generic support for some emulation
specific data in struct proc. I noted erh even though about this
when he wrote sys/compat/linux/common/linux_emuldata.h.

I've implemented one of obvious ways to achieve that. struct emul
has got a new function pointer to emuldata alloc function - if non-NULL,
it's called in fork1() or sys_exec() to allocate emuldata. struct proc
has got one more field, void *p_emuldata, which can hold emulation-specific
data and is freed in exit1(). New malloc type M_EMULDATA is added,
emuldata allocation functions should use that type when allocating
memory for their structures.
Patch is appended (for reference, it contains also the Linux changes to use
the new mechanism). It seems it works as expected even for threaded Linux
programs - I've done some small testing of the change and I didn't observe
any problems.

Do you have any comments on this ? 

Jaromir

XXXXXX
Index: sys/proc.h
===================================================================
RCS file: /cvsroot/syssrc/sys/sys/proc.h,v
retrieving revision 1.105
diff -u -r1.105 proc.h
--- sys/proc.h	2000/09/05 16:27:51	1.105
+++ sys/proc.h	2000/10/29 12:03:49
@@ -103,6 +103,9 @@
 
 	char	*e_sigcode;		/* Start of sigcode */
 	char	*e_esigcode;		/* End of sigcode */
+					/* Allocate per-process emuldata. Malloc
+					 * type has to be of type M_EMULDATA */
+	void	*(*e_alloc_emuldata) __P((struct proc *));
 };
 
 /*
@@ -183,6 +186,8 @@
 
 	int	p_holdcnt;		/* If non-zero, don't swap. */
 	struct	emul *p_emul;		/* Emulation information */
+	void	*p_emuldata;		/* Per-process emulation data, or NULL
+					 * if not needed */
 
 /* End area that is zeroed on creation. */
 #define	p_endzero	p_startcopy
Index: sys/malloc.h
===================================================================
RCS file: /cvsroot/syssrc/sys/sys/malloc.h,v
retrieving revision 1.53
diff -u -r1.53 malloc.h
--- sys/malloc.h	2000/06/24 23:52:24	1.53
+++ sys/malloc.h	2000/10/29 12:03:50
@@ -173,7 +173,8 @@
 #define	M_IP6RR		112	/* IPv6 Router Renumbering Prefix */
 #define	M_RR_ADDR	113	/* IPv6 Router Renumbering Ifid */
 #define M_SOFTINTR	114	/* Softinterrupt structures */
-#define M_LAST		115	/* Must be last type + 1 */
+#define M_EMULDATA	115	/* Per-process emulation data */
+#define M_LAST		116	/* Must be last type + 1 */
 
 #define	INITKMEMNAMES { \
 	"free",		/* 0 M_FREE */ \
@@ -291,7 +292,8 @@
 	"ip6rr",	/* 112 M_IP6RR */ \
 	"rp_addr",	/* 113 M_RR_ADDR */ \
 	"softintr",	/* 114 M_SOFTINTR */ \
-	NULL,		/* 115 */ \
+	"emuldata",	/* 115 M_EMULDATA */ \
+	NULL,		/* 116 */ \
 }
 
 struct kmemstats {
Index: kern/kern_exit.c
===================================================================
RCS file: /cvsroot/syssrc/sys/kern/kern_exit.c,v
retrieving revision 1.85
diff -u -r1.85 kern_exit.c
--- kern/kern_exit.c	2000/08/22 17:28:28	1.85
+++ kern/kern_exit.c	2000/10/29 12:03:52
@@ -320,6 +320,12 @@
 	limfree(p->p_limit);
 	p->p_limit = NULL;
 
+	/* Free per-process emulation data, if there are any */
+	if (p->p_emuldata) {
+		free(p->p_emuldata, M_EMULDATA);
+		p->p_emuldata = NULL;
+	}
+
 	/* This process no longer needs to hold the kernel lock. */
 	KERNEL_PROC_UNLOCK(p);
 
Index: kern/kern_fork.c
===================================================================
RCS file: /cvsroot/syssrc/sys/kern/kern_fork.c,v
retrieving revision 1.73
diff -u -r1.73 kern_fork.c
--- kern/kern_fork.c	2000/09/06 14:06:42	1.73
+++ kern/kern_fork.c	2000/10/29 12:03:53
@@ -347,6 +347,14 @@
 		p2->p_sigacts = sigactsinit(p1);
 
 	/*
+	 * If alloc_emuldata is nonzero, call it now.
+	 */
+	if (p2->p_emul->e_alloc_emuldata)
+		p2->p_emuldata = (*p2->p_emul->e_alloc_emuldata)(p2);
+	else
+		p2->p_emuldata = NULL;
+
+	/*
 	 * This begins the section where we must prevent the parent
 	 * from being swapped.
 	 */
Index: kern/kern_exec.c
===================================================================
RCS file: /cvsroot/syssrc/sys/kern/kern_exec.c,v
retrieving revision 1.121
diff -u -r1.121 kern_exec.c
--- kern/kern_exec.c	2000/09/28 19:05:07	1.121
+++ kern/kern_exec.c	2000/10/29 12:03:54
@@ -523,6 +523,10 @@
 	/* setup new registers and do misc. setup. */
 	(*pack.ep_emul->e_setregs)(p, &pack, (u_long) stack);
 
+	/* allocate per-process emulation data, if given emulation needs it */
+	if (pack.ep_emul->e_alloc_emuldata)
+		p->p_emuldata = (*pack.ep_emul->e_alloc_emuldata)(p);
+
 	if (p->p_flag & P_TRACED)
 		psignal(p, SIGTRAP);
 
Index: compat/linux/common/linux_emuldata.h
===================================================================
RCS file: /cvsroot/syssrc/sys/compat/linux/common/linux_emuldata.h,v
retrieving revision 1.1
diff -u -r1.1 linux_emuldata.h
--- compat/linux/common/linux_emuldata.h	1998/12/08 21:00:11	1.1
+++ compat/linux/common/linux_emuldata.h	2000/10/29 12:03:54
@@ -7,9 +7,14 @@
  * This is auxillary data the linux compat code
  * needs to do its work.  A pointer to it is
  * stored in the emuldata field of the proc
- * structure. (NOTYET)
+ * structure.
  */
 struct linux_emuldata {
     sigset_t	ps_siginfo;		/* Which signals have a RT handler */
+    int		debugreg[8];		/* GDB information for ptrace - for use,
+					 * see ../arch/i386/linux_ptrace.c */
 };
+
+void *linux_alloc_emuldata __P((struct proc *));
+void linux_free_emuldata __P((struct proc *));
 #endif /* !_COMMON_LINUX_EMULDATA_H */
Index: compat/linux/common/linux_misc.c
===================================================================
RCS file: /cvsroot/syssrc/sys/compat/linux/common/linux_misc.c,v
retrieving revision 1.72
diff -u -r1.72 linux_misc.c
--- compat/linux/common/linux_misc.c	2000/09/07 22:20:45	1.72
+++ compat/linux/common/linux_misc.c	2000/10/29 12:03:57
@@ -106,8 +108,9 @@
 #include <compat/linux/common/linux_misc.h>
 #include <compat/linux/common/linux_ptrace.h>
 #include <compat/linux/common/linux_reboot.h>
+#include <compat/linux/common/linux_emuldata.h>
 
int linux_ptrace_request_map[] = {
 	LINUX_PTRACE_TRACEME,	PT_TRACE_ME,
 	LINUX_PTRACE_PEEKTEXT,	PT_READ_I,
 	LINUX_PTRACE_PEEKDATA,	PT_READ_D,
@@ -1151,4 +1167,18 @@
 	}
 
 	return(sys_reboot(p, &sra, retval));
+}
+
+/*
+ * Allocate per-process emuldata and return it. Used in sys_exec().
+ */
+void *
+linux_alloc_emuldata(p)
+	struct proc *p;
+{
+	struct linux_emuldata *emuldata;
+	MALLOC(emuldata, struct linux_emuldata *, sizeof(struct linux_emuldata),
+		M_EMULDATA, M_WAITOK);
+	memset(emuldata, '\0', sizeof(struct linux_emuldata));
+	return emuldata;
 }
Index: compat/linux/common/linux_exec_aout.c
===================================================================
RCS file: /cvsroot/syssrc/sys/compat/linux/common/linux_exec_aout.c,v
retrieving revision 1.40
diff -u -r1.40 linux_exec_aout.c
--- compat/linux/common/linux_exec_aout.c	2000/06/29 02:40:39	1.40
+++ compat/linux/common/linux_exec_aout.c	2000/10/29 12:03:58
@@ -63,6 +63,7 @@
 #include <compat/linux/common/linux_exec.h>
 #include <compat/linux/common/linux_machdep.h>
 #include <compat/linux/common/linux_errno.h>
+#include <compat/linux/common/linux_emuldata.h>
 
 #include <compat/linux/linux_syscallargs.h>
 #include <compat/linux/linux_syscall.h>
@@ -95,6 +96,7 @@
 	linux_setregs,
 	linux_sigcode,
 	linux_esigcode,
+	linux_alloc_emuldata,
 };
 
 static void *
Index: compat/linux/common/linux_exec_elf32.c
===================================================================
RCS file: /cvsroot/syssrc/sys/compat/linux/common/linux_exec_elf32.c,v
retrieving revision 1.45
diff -u -r1.45 linux_exec_elf32.c
--- compat/linux/common/linux_exec_elf32.c	2000/06/29 02:40:39	1.45
+++ compat/linux/common/linux_exec_elf32.c	2000/10/29 12:03:58
@@ -67,6 +67,7 @@
 #include <compat/linux/common/linux_exec.h>
 #include <compat/linux/common/linux_machdep.h>
 #include <compat/linux/common/linux_errno.h>
+#include <compat/linux/common/linux_emuldata.h>
 
 #include <compat/linux/linux_syscallargs.h>
 #include <compat/linux/linux_syscall.h>
@@ -98,6 +99,7 @@
 	linux_setregs,
 	linux_sigcode,
 	linux_esigcode,
+	linux_alloc_emuldata,
 };
 
XXXXXX
-- 
Jaromir Dolecek <jdolecek@NetBSD.org>      http://www.ics.muni.cz/~dolecek/
@@@@  Wanna a real operating system ? Go and get NetBSD, damn!  @@@@