From ak03@gte.com  Sat Dec 29 08:21:32 2001
Return-Path: <ak03@gte.com>
Received: from h132-197-179-27.gte.com (h132-197-179-27.gte.com [132.197.179.27])
	by hub.freebsd.org (Postfix) with ESMTP id 8D48937B41A
	for <FreeBSD-gnats-submit@freebsd.org>; Sat, 29 Dec 2001 08:21:31 -0800 (PST)
Received: (from ak03@localhost)
	by h132-197-179-27.gte.com (8.11.6/8.11.4) id fBTGLUW50719;
	Sat, 29 Dec 2001 11:21:30 -0500 (EST)
	(envelope-from ak03)
Message-Id: <200112291621.fBTGLUW50719@h132-197-179-27.gte.com>
Date: Sat, 29 Dec 2001 11:21:30 -0500 (EST)
From: "Alexander N. Kabaev" <ak03@gte.com>
Reply-To: "Alexander N. Kabaev" <ak03@gte.com>
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: -CURRENT ptrace(2) implementation for linux emulator on i386
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         33299
>Category:       i386
>Synopsis:       -CURRENT ptrace(2) implementation for linux emulator on i386
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    des
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Sat Dec 29 08:30:00 PST 2001
>Closed-Date:    Sat May 18 18:38:55 PDT 2002
>Last-Modified:  Sat May 18 18:38:55 PDT 2002
>Originator:     Alexander N. Kabaev
>Release:        FreeBSD 5.0-CURRENT i386
>Organization:
Verizon Data Services
>Environment:
System: FreeBSD kanpc.gte.com 5.0-CURRENT FreeBSD 5.0-CURRENT #13: Mon Dec 24 11:36:50 EST 2001 root@kanpc.gte.com:/usr/src/sys/i386/compile/KANPC i386


	
>Description:
	The patch below implements Linux ptrace syscall for linuxulator.
	With this patch applied, it is possible to use /compat/linux/usr/bin/gdb
	to debug Linux binaries. At the very least it provides much more
	meaningful backtraces. All gdb features I tried seem to be working
	correctly so far.

	The patch also fixes long-standing bug with FreeBSD native ptrace
	in kern/sys_process.c, where prace would not allow process using
	signal number > NSIG to be continued from gdb. The check for 
	signal validity should use _SIG_MAXSIG instead of obsoleted
	NSIG.
>How-To-Repeat:
	Apply the patch in /usr/src/sys. Do not forget to regenerate
	files from i386/linux/syscalls.master to get an undated 
	linux_ptrace syscall signature.
>Fix:

Index: conf/files.i386
===================================================================
RCS file: /home/ncvs/src/sys/conf/files.i386,v
retrieving revision 1.386
diff -u -r1.386 files.i386
--- conf/files.i386	22 Dec 2001 09:25:17 -0000	1.386
+++ conf/files.i386	29 Dec 2001 15:23:55 -0000
@@ -288,6 +288,7 @@
 i386/linux/linux_locore.s	optional	compat_linux		\
 	dependency 	"linux_assym.h"
 i386/linux/linux_machdep.c	optional	compat_linux
+i386/linux/linux_ptrace.c	optional	compat_linux
 i386/linux/linux_sysent.c	optional	compat_linux
 i386/linux/linux_sysvec.c	optional	compat_linux
 i386/pci/pci_cfgreg.c		optional	pci
Index: kern/sys_process.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/sys_process.c,v
retrieving revision 1.76
diff -u -r1.76 sys_process.c
--- kern/sys_process.c	21 Oct 2001 23:57:15 -0000	1.76
+++ kern/sys_process.c	26 Dec 2001 20:02:05 -0000
@@ -419,7 +419,7 @@
 	case PT_STEP:
 	case PT_CONTINUE:
 	case PT_DETACH:
-		if ((uap->req != PT_STEP) && ((unsigned)uap->data >= NSIG))
+		if ((uap->req != PT_STEP) && ((unsigned)uap->data > _SIG_MAXSIG))
 			return (EINVAL);
 
 		PHOLD(p);
Index: i386/linux/linux_ptrace.c
===================================================================
RCS file: i386/linux/linux_ptrace.c
diff -N i386/linux/linux_ptrace.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ i386/linux/linux_ptrace.c	26 Dec 2001 20:08:45 -0000
@@ -0,0 +1,499 @@
+/*
+ * Copyright (c) 2001 Alexander Kabaev
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer 
+ *    in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD:$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/ptrace.h>
+#include <sys/sysproto.h>
+#include <sys/user.h>
+
+#include <machine/md_var.h>
+#include <machine/npx.h>
+#include <machine/reg.h>
+
+#include <i386/linux/linux.h>
+#include <i386/linux/linux_proto.h>
+#include <compat/linux/linux_util.h>
+
+/* 
+ *   Linux ptrace requests numbers. Mostly identical to FreeBSD,
+ *   except for MD ones and PT_ATTACH/PT_DETACH.
+ */
+#define	PTRACE_TRACEME		0
+#define	PTRACE_PEEKTEXT		1
+#define	PTRACE_PEEKDATA		2
+#define	PTRACE_PEEKUSR		3
+#define	PTRACE_POKETEXT		4
+#define	PTRACE_POKEDATA		5
+#define	PTRACE_POKEUSR		6
+#define	PTRACE_CONT		7
+#define	PTRACE_KILL		8
+#define	PTRACE_SINGLESTEP	9
+
+#define PTRACE_ATTACH		16
+#define PTRACE_DETACH		17
+
+#define	PTRACE_SYSCALL		24
+
+#define PTRACE_GETREGS		12
+#define PTRACE_SETREGS		13
+#define PTRACE_GETFPREGS	14
+#define PTRACE_SETFPREGS	15
+#define PTRACE_GETFPXREGS	18
+#define PTRACE_SETFPXREGS	19
+
+#define PTRACE_SETOPTIONS	21
+
+/*
+ * Linux keeps debug registers at the following
+ * offset in the user struct
+ */
+#define LINUX_DBREG_OFFSET	252
+#define LINUX_DBREG_SIZE	8*sizeof(l_int)
+
+static __inline__ int 
+map_signum(int signum)
+{
+#ifndef __alpha__
+	if (signum > 0 && signum <= LINUX_SIGTBLSZ)
+		signum = linux_to_bsd_signal[_SIG_IDX(signum)];
+#endif
+	return ((signum == SIGSTOP)? 0 : signum);
+}
+
+struct linux_pt_reg {
+	l_long	ebx;
+	l_long	ecx;
+	l_long	edx;
+	l_long	esi;
+	l_long	edi;
+	l_long	ebp;
+	l_long	eax;
+	l_int	xds;
+	l_int	xes;
+	l_int	xfs;
+	l_int	xgs;
+	l_long	orig_eax;
+	l_long	eip;
+	l_int	xcs;
+	l_long	eflags;
+	l_long	esp;
+	l_int	xss;
+};
+
+
+/* 
+ *   Translate i386 ptrace registers between Linux and FreeBSD formats.
+ *   The translation is pretty straighforward, for all registers, but
+ *   orig_eax in Linux side and r_trapno and r_err in FreeBSD
+ */
+static int 
+map_regs_to_linux(struct reg *bsd_r, struct linux_pt_reg *linux_r)
+{
+	linux_r->ebx = bsd_r->r_ebx;
+	linux_r->ecx = bsd_r->r_ecx;
+	linux_r->edx = bsd_r->r_edx;
+	linux_r->esi = bsd_r->r_esi;
+	linux_r->edi = bsd_r->r_edi;
+	linux_r->ebp = bsd_r->r_ebp;
+	linux_r->eax = bsd_r->r_eax;
+	linux_r->xds = bsd_r->r_ds;
+	linux_r->xes = bsd_r->r_es;
+	linux_r->xfs = bsd_r->r_fs;
+	linux_r->xgs = bsd_r->r_gs;
+	linux_r->orig_eax = bsd_r->r_eax;
+	linux_r->eip = bsd_r->r_eip;
+	linux_r->xcs = bsd_r->r_cs;
+	linux_r->eflags = bsd_r->r_eflags;
+	linux_r->esp = bsd_r->r_esp;
+	linux_r->xss = bsd_r->r_ss;
+	return (0);
+}
+
+static int 
+map_regs_from_linux(struct reg *bsd_r, struct linux_pt_reg *linux_r)
+{
+	bsd_r->r_ebx = linux_r->ebx;
+	bsd_r->r_ecx = linux_r->ecx;
+	bsd_r->r_edx = linux_r->edx;
+	bsd_r->r_esi = linux_r->esi;
+	bsd_r->r_edi = linux_r->edi;
+	bsd_r->r_ebp = linux_r->ebp;
+	bsd_r->r_eax = linux_r->eax;
+	bsd_r->r_ds  = linux_r->xds;
+	bsd_r->r_es  = linux_r->xes;
+	bsd_r->r_fs  = linux_r->xfs;
+	bsd_r->r_gs  = linux_r->xgs;
+	bsd_r->r_eip = linux_r->eip;
+	bsd_r->r_cs  = linux_r->xcs;
+	bsd_r->r_eflags = linux_r->eflags;
+	bsd_r->r_esp = linux_r->esp;
+	bsd_r->r_ss = linux_r->xss;
+	return (0);
+}
+
+struct linux_pt_fpreg {
+	l_long cwd;
+	l_long swd;
+	l_long twd;
+	l_long fip;
+	l_long fcs;
+	l_long foo;
+	l_long fos;
+	l_long st_space[2*10];
+};
+
+static int 
+map_fpregs_to_linux(struct fpreg *bsd_r, struct linux_pt_fpreg *linux_r)
+{
+	linux_r->cwd = bsd_r->fpr_env[0];
+	linux_r->swd = bsd_r->fpr_env[1];
+	linux_r->twd = bsd_r->fpr_env[2];
+	linux_r->fip = bsd_r->fpr_env[3];
+	linux_r->fcs = bsd_r->fpr_env[4];
+	linux_r->foo = bsd_r->fpr_env[5];
+	linux_r->fos = bsd_r->fpr_env[6];
+	bcopy(bsd_r->fpr_acc, linux_r->st_space, sizeof(linux_r->st_space));
+	return (0);
+}
+
+static int 
+map_fpregs_from_linux(struct fpreg *bsd_r, struct linux_pt_fpreg *linux_r)
+{
+	bsd_r->fpr_env[0] = linux_r->cwd;
+	bsd_r->fpr_env[1] = linux_r->swd;
+	bsd_r->fpr_env[2] = linux_r->twd;
+	bsd_r->fpr_env[3] = linux_r->fip;
+	bsd_r->fpr_env[4] = linux_r->fcs;
+	bsd_r->fpr_env[5] = linux_r->foo;
+	bsd_r->fpr_env[6] = linux_r->fos;
+	bcopy(bsd_r->fpr_acc, linux_r->st_space, sizeof(bsd_r->fpr_acc));
+	return (0);
+}
+
+struct linux_pt_fpxreg {
+	l_ushort	cwd;
+	l_ushort	swd;
+	l_ushort	twd;
+	l_ushort	fop;
+	l_long		fip;
+	l_long		fcs;
+	l_long		foo;
+	l_long		fos;
+	l_long		mxcsr;
+	l_long		reserved;
+	l_long		st_space[32];
+	l_long		xmm_space[32];
+	l_long		padding[56];
+};
+
+static int 
+linux_proc_read_fpxregs(struct thread *td, struct linux_pt_fpxreg *fpxregs) 
+{
+#ifdef CPU_ENABLE_SSE
+	if (sizeof(*fpxregs) != sizeof(td->td_pcb->pcb_save.sv_xmm)) {
+		printf("linux: savexmm != linux_pt_fpxreg\n");
+		return (EIO);
+	}
+	if (cpu_fxsr == 0)
+#endif
+		return (EIO);
+	bcopy(&td->td_pcb->pcb_save.sv_xmm, fpxregs, sizeof *fpxregs);
+	return (0);
+}
+
+static int 
+linux_proc_write_fpxregs(struct thread *td, struct linux_pt_fpxreg *fpxregs)
+{
+#ifdef CPU_ENABLE_SSE
+	if (sizeof(*fpxregs) != sizeof(td->td_pcb->pcb_save.sv_xmm)) {
+		printf("linux: savexmm != linux_pt_fpxreg\n");
+		return (EIO);
+	}
+	if (cpu_fxsr == 0)
+#endif
+		return (EIO);
+	bcopy(fpxregs, &td->td_pcb->pcb_save.sv_xmm, sizeof *fpxregs);
+	return (0);
+}
+
+
+int
+linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
+{
+	struct ptrace_args bsd_args;
+	int	error;
+	caddr_t	sg;
+	union {
+		struct linux_pt_reg	reg;
+		struct linux_pt_fpreg	fpreg;
+		struct linux_pt_fpxreg	fpxreg;
+	} r;
+
+	sg = stackgap_init();
+
+	error = 0;
+
+	/* by default, just copy data intact */
+	bsd_args.req  = uap->req;
+	bsd_args.pid  = (pid_t)uap->pid;
+	bsd_args.addr = (caddr_t)uap->addr;
+	bsd_args.data = uap->data;
+
+	switch (uap->req) {
+	case PTRACE_TRACEME:
+	case PTRACE_POKETEXT:
+	case PTRACE_POKEDATA:
+	case PTRACE_KILL:
+		error = ptrace(td, &bsd_args);
+		break;
+	case PTRACE_PEEKTEXT:
+	case PTRACE_PEEKDATA: {
+		/* need to preserve return value */
+		int rval = td->td_retval[0];
+		bsd_args.data = 0;
+		error = ptrace(td, &bsd_args);
+		if (error == 0)
+			error = copyout(td->td_retval,
+			    (caddr_t)uap->data, sizeof(l_int));
+		td->td_retval[0] = rval;
+		break;
+	}
+	case PTRACE_DETACH:
+		bsd_args.req = PT_DETACH;
+		/* fall through */
+	case PTRACE_SINGLESTEP:
+	case PTRACE_CONT:
+		bsd_args.data = map_signum(uap->data);
+		bsd_args.addr = (caddr_t)1;
+		error = ptrace(td, &bsd_args);
+		break;
+	case PTRACE_ATTACH:
+		bsd_args.req = PT_ATTACH;
+		error = ptrace(td, &bsd_args);
+		break;
+	case PTRACE_GETREGS: {
+		struct reg *bsd_r = (struct reg*)stackgap_alloc(&sg,
+                    sizeof(*bsd_r));
+		/* Linux is using data where FreeBSD is using addr */
+		bsd_args.req  = PT_GETREGS;
+		bsd_args.addr = (caddr_t)bsd_r;
+		bsd_args.data = 0;
+		error = ptrace(td, &bsd_args);
+		if (error == 0)
+			error = map_regs_to_linux(bsd_r, &r.reg);
+		if (error == 0)
+			error = copyout(&r.reg, (caddr_t)uap->data, sizeof r.reg);
+		break;
+	}
+	case PTRACE_SETREGS: {
+		struct reg *bsd_r = (struct reg*)stackgap_alloc(&sg,
+                    sizeof(*bsd_r));
+		/* Linux is using data where FreeBSD is using addr */
+		bsd_args.req  = PT_SETREGS;
+		bsd_args.addr = (caddr_t)bsd_r;
+		bsd_args.data = 0;
+		error = copyin((caddr_t)uap->data, &r.reg, sizeof r.reg);
+		if (error == 0)
+			error = map_regs_from_linux(bsd_r, &r.reg);
+		if (error == 0)
+			error = ptrace(td, &bsd_args);
+		break;
+	}
+	case PTRACE_GETFPREGS: {
+		struct fpreg *bsd_r = (struct fpreg*)stackgap_alloc(&sg,
+                    sizeof(*bsd_r));
+		/* Linux is using data where FreeBSD is using addr */
+		bsd_args.req  = PT_GETFPREGS;
+		bsd_args.addr = (caddr_t)bsd_r;
+		bsd_args.data = 0;
+		error = ptrace(td, &bsd_args);
+		if (error == 0)
+			error = map_fpregs_to_linux(bsd_r, &r.fpreg);
+		if (error == 0)
+			error = copyout(&r.fpreg, (caddr_t)uap->data, sizeof r.fpreg);
+		break;
+	}
+	case PTRACE_SETFPREGS: {
+		struct fpreg *bsd_r = (struct fpreg*)stackgap_alloc(&sg,
+                    sizeof(*bsd_r));
+		/* Linux is using data where FreeBSD is using addr */
+		bsd_args.req  = PT_SETFPREGS;
+		bsd_args.addr = (caddr_t)bsd_r;
+		bsd_args.data = 0;
+		error = copyin((caddr_t)uap->data, &r.fpreg, sizeof r.fpreg);
+		if (error == 0)
+			error = map_fpregs_from_linux(bsd_r, &r.fpreg);
+		if (error == 0)
+			error = ptrace(td, &bsd_args);
+		break;
+	}
+	case PTRACE_SETFPXREGS:
+	case PTRACE_GETFPXREGS: {
+		struct proc *p;
+		struct fpreg *bsd_r;
+
+		/*
+		 * Use FreeBSD PT_GETFPREGS for permisson testing.
+		 */
+		bsd_r = (struct fpreg*)stackgap_alloc(&sg,
+                    sizeof(*bsd_r));
+		bsd_args.req  = PT_GETFPREGS;
+		bsd_args.addr = (caddr_t)bsd_r;
+		bsd_args.data = 0;
+		error = ptrace(td, &bsd_args);
+		/*
+		 * If this fails, PTRACE_GETFPXREGS should fail
+		 * for exactly the same reason. 
+		*/
+		if (error != 0) 			     
+			break;
+
+		if ((p = pfind(uap->pid)) == NULL) {
+			error = ESRCH;
+			break;
+		}
+		if (uap->req == PTRACE_GETFPXREGS) {
+			PHOLD(p);
+			error = linux_proc_read_fpxregs(
+				&p->p_thread, &r.fpxreg);
+			PRELE(p);
+			if (error == 0)
+				error = copyout(&r.fpxreg,
+				    (caddr_t)uap->data, sizeof r.fpxreg);
+		} else {
+			error = copyin((caddr_t)uap->data,
+			    &r.fpxreg, sizeof r.fpxreg);
+			if (error == 0) {
+				/* clear dangerous bits exactly as Linux does*/
+				r.fpxreg.mxcsr &= 0xffbf;
+				PHOLD(p);
+				error = linux_proc_write_fpxregs(
+					&p->p_thread, &r.fpxreg);
+				PRELE(p);
+			}
+		}
+		break;
+	}
+	case PTRACE_PEEKUSR:
+	case PTRACE_POKEUSR: {
+		error = EIO;
+
+		/* check addr for alignment */
+		if (uap->addr < 0 || uap->addr & (sizeof(l_int) - 1))
+			break;
+		/* 
+		 * Allow linux programs to access register values in
+		 * user struct. We simulate this through PT_GET/SETREGS
+		 * as necessary.
+		 */
+		if (uap->addr < sizeof(struct linux_pt_reg)) {
+			struct reg *bsd_r;
+
+			bsd_r = (struct reg*)stackgap_alloc(&sg,
+			    sizeof(*bsd_r));
+			bsd_args.req  = PT_GETREGS;
+			bsd_args.addr = (caddr_t)bsd_r;
+			bsd_args.data = 0;
+
+			error = ptrace(td, &bsd_args);
+			if (error != 0)
+				break;
+			
+			error = map_regs_to_linux(bsd_r, &r.reg);
+			if (error != 0)
+				break;
+
+			if (uap->req == PTRACE_PEEKUSR) {
+				error = copyout((char *)&r.reg + uap->addr,
+				    (caddr_t)uap->data, sizeof(l_int));
+				break;
+			}
+
+			*(l_int *)((char *)&r.reg + uap->addr) = (l_int)uap->data;
+
+			error = map_regs_from_linux(bsd_r, &r.reg);
+			if (error != 0)
+				break;
+
+			bsd_args.req  = PT_SETREGS;
+			bsd_args.addr = (caddr_t)bsd_r;
+			bsd_args.data = 0;
+			error = ptrace(td, &bsd_args);
+		}
+		
+		/* 
+		 * Simulate debug registers access
+		 */
+		if (uap->addr >= LINUX_DBREG_OFFSET && 
+		    uap->addr <= LINUX_DBREG_OFFSET + LINUX_DBREG_SIZE) {
+			struct dbreg *bsd_r;
+
+			bsd_r = (struct dbreg*)stackgap_alloc(&sg,
+			    sizeof(*bsd_r));
+			bsd_args.req  = PT_GETDBREGS;
+			bsd_args.addr = (caddr_t)bsd_r;
+			bsd_args.data = 0;
+			error = ptrace(td, &bsd_args);
+			if (error != 0)
+				break;
+			
+			uap->addr -= LINUX_DBREG_OFFSET;
+			if (uap->req == PTRACE_PEEKUSR) {
+				error = copyout((char *)bsd_r + uap->addr,
+				    (caddr_t)uap->data, sizeof(l_int));
+				break;
+			}
+
+			*(l_int *)((char *)bsd_r + uap->addr) = uap->data;
+			bsd_args.req  = PT_SETDBREGS;
+			bsd_args.addr = (caddr_t)bsd_r;
+			bsd_args.data = 0;
+			error = ptrace(td, &bsd_args);
+		}
+
+		break;
+	}
+	case PTRACE_SYSCALL:
+		/* fall through */
+	default:
+		error = EINVAL;
+		goto noimpl;
+	}
+	return (error);
+
+ noimpl:
+	printf("linux: ptrace(%u, ...) not implemented\n",
+	    (u_int32_t)uap->req);
+	return (error);
+}
Index: i386/linux/linux_dummy.c
===================================================================
RCS file: /home/ncvs/src/sys/i386/linux/linux_dummy.c,v
retrieving revision 1.32
diff -u -r1.32 linux_dummy.c
--- i386/linux/linux_dummy.c	16 Oct 2001 06:15:36 -0000	1.32
+++ i386/linux/linux_dummy.c	24 Dec 2001 22:02:11 -0000
@@ -38,7 +38,6 @@
 
 DUMMY(stat);
 DUMMY(stime);
-DUMMY(ptrace);
 DUMMY(fstat);
 DUMMY(olduname);
 DUMMY(syslog);
Index: i386/linux/syscalls.master
===================================================================
RCS file: /home/ncvs/src/sys/i386/linux/syscalls.master,v
retrieving revision 1.45
diff -u -r1.45 syscalls.master
--- i386/linux/syscalls.master	16 Oct 2001 06:11:11 -0000	1.45
+++ i386/linux/syscalls.master	24 Dec 2001 22:02:11 -0000
@@ -65,7 +65,8 @@
 23	STD	LINUX	{ int linux_setuid16(l_uid16_t uid); }
 24	STD	LINUX	{ int linux_getuid16(void); }
 25	STD	LINUX	{ int linux_stime(void); }
-26	STD	LINUX	{ int linux_ptrace(void); }
+26	STD	LINUX	{ int linux_ptrace(l_long req, l_long pid, l_long addr, \
+                            l_long data); }
 27	STD	LINUX	{ int linux_alarm(l_uint secs); }
 28	STD	LINUX	{ int linux_fstat(l_uint fd, struct ostat *up); }
 29	STD	LINUX	{ int linux_pause(void); }
Index: modules/linux/Makefile
===================================================================
RCS file: /home/ncvs/src/sys/modules/linux/Makefile,v
retrieving revision 1.54
diff -u -r1.54 Makefile
--- modules/linux/Makefile	18 Nov 2001 05:45:27 -0000	1.54
+++ modules/linux/Makefile	24 Dec 2001 22:03:37 -0000
@@ -8,7 +8,9 @@
 SRCS=	linux_dummy.c linux_file.c linux_getcwd.c linux_ioctl.c linux_ipc.c \
 	linux_machdep.c linux_mib.c linux_misc.c linux_signal.c linux_socket.c \
 	linux_stats.c linux_sysctl.c linux_sysent.c linux_sysvec.c \
-	linux_util.c opt_compat.h opt_linux.h opt_vmpage.h vnode_if.h
+	linux_util.c linux_ptrace.c opt_compat.h opt_linux.h opt_vmpage.h \
+	vnode_if.h
+
 OBJS=	linux_locore.o
 
 .if ${MACHINE_ARCH} == "i386"
>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->des 
Responsible-Changed-By: des 
Responsible-Changed-When: Wed Jan 30 13:53:43 PST 2002 
Responsible-Changed-Why:  
I'm familiar with ptrace(2) and the linuxulator. 

http://www.FreeBSD.org/cgi/query-pr.cgi?pr=33299 

From: "Alexander N. Kabaev" <ak03@gte.com>
To: freebsd-gnats-submit@FreeBSD.org
Cc: "Marcel Moolenaar"@FreeBSD.ORG, marcel@cup.hp.com,
	Dag-Erling Smorgrav <des@ofug.org>
Subject: Re: i386/33299: -CURRENT ptrace(2) implementation for linux emulator on i386
Date: Tue, 14 May 2002 10:36:50 -0400

 I tried to send an update to the Linux ptrace(2) implementation on
 i386-CURRENT yesterday but it seems to have vanished off the face of
 Earth, and no trace of it can be found in the GNATS database. This
 is a second try and I apologize for sending this e-mail twice.
 
 The patch I submitted yesterday was incomplete anyway (I forgot to scp
 the final version it from the test machine, so the copy in the letter
 was incomplete. The latest version of the patch which works fine on
 pre-GCC3 -CURRENT is below.
 
 Dag-Erling, do you have any objections for this code to be committed?
 
 
 Index: conf/files.i386
 ===================================================================
 RCS file: /home/ncvs/src/sys/conf/files.i386,v
 retrieving revision 1.398
 diff -u -r1.398 files.i386
 --- conf/files.i386	31 Mar 2002 22:28:28 -0000	1.398
 +++ conf/files.i386	3 Apr 2002 00:47:57 -0000
 @@ -303,6 +303,7 @@
  i386/linux/linux_locore.s	optional	compat_linux		\
  	dependency 	"linux_assym.h"
  i386/linux/linux_machdep.c	optional	compat_linux
 +i386/linux/linux_ptrace.c	optional	compat_linux
  i386/linux/linux_sysent.c	optional	compat_linux
  i386/linux/linux_sysvec.c	optional	compat_linux
  i386/pci/pci_cfgreg.c		optional	pci
 Index: kern/sys_process.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/kern/sys_process.c,v
 retrieving revision 1.91
 diff -u -r1.91 sys_process.c
 --- kern/sys_process.c	20 Apr 2002 21:56:42 -0000	1.91
 +++ kern/sys_process.c	14 May 2002 03:39:16 -0000
 @@ -516,7 +516,7 @@
  	case PT_CONTINUE:
  	case PT_DETACH:
  		/* XXX uap->data is used even in the PT_STEP case. */
 -		if ((uap->req != PT_STEP) && ((unsigned)uap->data >= NSIG)) {
 +		if (uap->req != PT_STEP && (unsigned)uap->data > _SIG_MAXSIG) {
  			error = EINVAL;
  			goto fail;
  		}
 Index: i386/linux/linux_ptrace.c
 ===================================================================
 RCS file: i386/linux/linux_ptrace.c
 diff -N i386/linux/linux_ptrace.c
 --- /dev/null	1 Jan 1970 00:00:00 -0000
 +++ i386/linux/linux_ptrace.c	14 May 2002 04:55:45 -0000
 @@ -0,0 +1,514 @@
 +/*
 + * Copyright (c) 2001 Alexander Kabaev
 + * All rights reserved.
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that the following conditions
 + * are met:
 + * 1. Redistributions of source code must retain the above copyright
 + *    notice, this list of conditions and the following disclaimer 
 + *    in this position and unchanged.
 + * 2. Redistributions in binary form must reproduce the above copyright
 + *    notice, this list of conditions and the following disclaimer in the
 + *    documentation and/or other materials provided with the distribution.
 + * 3. The name of the author may not be used to endorse or promote products
 + *    derived from this software without specific prior written permission.
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 + *
 + * $FreeBSD:$
 + */
 +
 +#include <sys/param.h>
 +#include <sys/systm.h>
 +#include <sys/lock.h>
 +#include <sys/mutex.h>
 +#include <sys/proc.h>
 +#include <sys/ptrace.h>
 +#include <sys/sysproto.h>
 +#include <sys/user.h>
 +
 +#include <machine/md_var.h>
 +#include <machine/npx.h>
 +#include <machine/reg.h>
 +
 +#include <i386/linux/linux.h>
 +#include <i386/linux/linux_proto.h>
 +#include <compat/linux/linux_util.h>
 +
 +/* 
 + *   Linux ptrace requests numbers. Mostly identical to FreeBSD,
 + *   except for MD ones and PT_ATTACH/PT_DETACH.
 + */
 +#define	PTRACE_TRACEME		0
 +#define	PTRACE_PEEKTEXT		1
 +#define	PTRACE_PEEKDATA		2
 +#define	PTRACE_PEEKUSR		3
 +#define	PTRACE_POKETEXT		4
 +#define	PTRACE_POKEDATA		5
 +#define	PTRACE_POKEUSR		6
 +#define	PTRACE_CONT		7
 +#define	PTRACE_KILL		8
 +#define	PTRACE_SINGLESTEP	9
 +
 +#define PTRACE_ATTACH		16
 +#define PTRACE_DETACH		17
 +
 +#define	PTRACE_SYSCALL		24
 +
 +#define PTRACE_GETREGS		12
 +#define PTRACE_SETREGS		13
 +#define PTRACE_GETFPREGS	14
 +#define PTRACE_SETFPREGS	15
 +#define PTRACE_GETFPXREGS	18
 +#define PTRACE_SETFPXREGS	19
 +
 +#define PTRACE_SETOPTIONS	21
 +
 +/*
 + * Linux keeps debug registers at the following
 + * offset in the user struct
 + */
 +#define LINUX_DBREG_OFFSET	252
 +#define LINUX_DBREG_SIZE	8*sizeof(l_int)
 +
 +static __inline__ int 
 +map_signum(int signum)
 +{
 +#ifndef __alpha__
 +	if (signum > 0 && signum <= LINUX_SIGTBLSZ)
 +		signum = linux_to_bsd_signal[_SIG_IDX(signum)];
 +#endif
 +	return ((signum == SIGSTOP)? 0 : signum);
 +}
 +
 +struct linux_pt_reg {
 +	l_long	ebx;
 +	l_long	ecx;
 +	l_long	edx;
 +	l_long	esi;
 +	l_long	edi;
 +	l_long	ebp;
 +	l_long	eax;
 +	l_int	xds;
 +	l_int	xes;
 +	l_int	xfs;
 +	l_int	xgs;
 +	l_long	orig_eax;
 +	l_long	eip;
 +	l_int	xcs;
 +	l_long	eflags;
 +	l_long	esp;
 +	l_int	xss;
 +};
 +
 +
 +/* 
 + *   Translate i386 ptrace registers between Linux and FreeBSD formats.
 + *   The translation is pretty straighforward, for all registers, but
 + *   orig_eax on Linux side and r_trapno and r_err in FreeBSD
 + */
 +static int 
 +map_regs_to_linux(struct reg *bsd_r, struct linux_pt_reg *linux_r)
 +{
 +	linux_r->ebx = bsd_r->r_ebx;
 +	linux_r->ecx = bsd_r->r_ecx;
 +	linux_r->edx = bsd_r->r_edx;
 +	linux_r->esi = bsd_r->r_esi;
 +	linux_r->edi = bsd_r->r_edi;
 +	linux_r->ebp = bsd_r->r_ebp;
 +	linux_r->eax = bsd_r->r_eax;
 +	linux_r->xds = bsd_r->r_ds;
 +	linux_r->xes = bsd_r->r_es;
 +	linux_r->xfs = bsd_r->r_fs;
 +	linux_r->xgs = bsd_r->r_gs;
 +	linux_r->orig_eax = bsd_r->r_eax;
 +	linux_r->eip = bsd_r->r_eip;
 +	linux_r->xcs = bsd_r->r_cs;
 +	linux_r->eflags = bsd_r->r_eflags;
 +	linux_r->esp = bsd_r->r_esp;
 +	linux_r->xss = bsd_r->r_ss;
 +	return (0);
 +}
 +
 +static int 
 +map_regs_from_linux(struct reg *bsd_r, struct linux_pt_reg *linux_r)
 +{
 +	bsd_r->r_ebx = linux_r->ebx;
 +	bsd_r->r_ecx = linux_r->ecx;
 +	bsd_r->r_edx = linux_r->edx;
 +	bsd_r->r_esi = linux_r->esi;
 +	bsd_r->r_edi = linux_r->edi;
 +	bsd_r->r_ebp = linux_r->ebp;
 +	bsd_r->r_eax = linux_r->eax;
 +	bsd_r->r_ds  = linux_r->xds;
 +	bsd_r->r_es  = linux_r->xes;
 +	bsd_r->r_fs  = linux_r->xfs;
 +	bsd_r->r_gs  = linux_r->xgs;
 +	bsd_r->r_eip = linux_r->eip;
 +	bsd_r->r_cs  = linux_r->xcs;
 +	bsd_r->r_eflags = linux_r->eflags;
 +	bsd_r->r_esp = linux_r->esp;
 +	bsd_r->r_ss = linux_r->xss;
 +	return (0);
 +}
 +
 +struct linux_pt_fpreg {
 +	l_long cwd;
 +	l_long swd;
 +	l_long twd;
 +	l_long fip;
 +	l_long fcs;
 +	l_long foo;
 +	l_long fos;
 +	l_long st_space[2*10];
 +};
 +
 +static int 
 +map_fpregs_to_linux(struct fpreg *bsd_r, struct linux_pt_fpreg *linux_r)
 +{
 +	linux_r->cwd = bsd_r->fpr_env[0];
 +	linux_r->swd = bsd_r->fpr_env[1];
 +	linux_r->twd = bsd_r->fpr_env[2];
 +	linux_r->fip = bsd_r->fpr_env[3];
 +	linux_r->fcs = bsd_r->fpr_env[4];
 +	linux_r->foo = bsd_r->fpr_env[5];
 +	linux_r->fos = bsd_r->fpr_env[6];
 +	bcopy(bsd_r->fpr_acc, linux_r->st_space, sizeof(linux_r->st_space));
 +	return (0);
 +}
 +
 +static int 
 +map_fpregs_from_linux(struct fpreg *bsd_r, struct linux_pt_fpreg *linux_r)
 +{
 +	bsd_r->fpr_env[0] = linux_r->cwd;
 +	bsd_r->fpr_env[1] = linux_r->swd;
 +	bsd_r->fpr_env[2] = linux_r->twd;
 +	bsd_r->fpr_env[3] = linux_r->fip;
 +	bsd_r->fpr_env[4] = linux_r->fcs;
 +	bsd_r->fpr_env[5] = linux_r->foo;
 +	bsd_r->fpr_env[6] = linux_r->fos;
 +	bcopy(bsd_r->fpr_acc, linux_r->st_space, sizeof(bsd_r->fpr_acc));
 +	return (0);
 +}
 +
 +struct linux_pt_fpxreg {
 +	l_ushort	cwd;
 +	l_ushort	swd;
 +	l_ushort	twd;
 +	l_ushort	fop;
 +	l_long		fip;
 +	l_long		fcs;
 +	l_long		foo;
 +	l_long		fos;
 +	l_long		mxcsr;
 +	l_long		reserved;
 +	l_long		st_space[32];
 +	l_long		xmm_space[32];
 +	l_long		padding[56];
 +};
 +
 +static int 
 +linux_proc_read_fpxregs(struct thread *td, struct linux_pt_fpxreg *fpxregs) 
 +{
 +#ifdef CPU_ENABLE_SSE
 +	if (sizeof(*fpxregs) != sizeof(td->td_pcb->pcb_save.sv_xmm)) {
 +		printf("linux: savexmm != linux_pt_fpxreg\n");
 +		return (EIO);
 +	}
 +	if (cpu_fxsr == 0)
 +#endif
 +		return (EIO);
 +	mtx_lock_spin(&sched_lock);
 +	if ((td->td_proc->p_sflag & PS_INMEM) == 0) {
 +		mtx_unlock_spin(&sched_lock); 
 +		return (EIO);
 +	}
 +	bcopy(&td->td_pcb->pcb_save.sv_xmm, fpxregs, sizeof *fpxregs);
 +	mtx_unlock_spin(&sched_lock); 
 +	return (0);
 +}
 +
 +static int 
 +linux_proc_write_fpxregs(struct thread *td, struct linux_pt_fpxreg *fpxregs)
 +{
 +#ifdef CPU_ENABLE_SSE
 +	if (sizeof(*fpxregs) != sizeof(td->td_pcb->pcb_save.sv_xmm)) {
 +		printf("linux: savexmm != linux_pt_fpxreg\n");
 +		return (EIO);
 +	}
 +	if (cpu_fxsr == 0)
 +#endif
 +		return (EIO);
 +	mtx_lock_spin(&sched_lock);
 +	if ((td->td_proc->p_sflag & PS_INMEM) == 0) {
 +		mtx_unlock_spin(&sched_lock); 
 +		return (EIO);
 +	}
 +	bcopy(fpxregs, &td->td_pcb->pcb_save.sv_xmm, sizeof *fpxregs);
 +	mtx_unlock_spin(&sched_lock); 
 +	return (0);
 +}
 +
 +
 +int
 +linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
 +{
 +	struct ptrace_args bsd_args;
 +	int	error;
 +	caddr_t	sg;
 +	union {
 +		struct linux_pt_reg	reg;
 +		struct linux_pt_fpreg	fpreg;
 +		struct linux_pt_fpxreg	fpxreg;
 +	} r;
 +
 +	sg = stackgap_init();
 +
 +	error = 0;
 +
 +	/* by default, just copy data intact */
 +	bsd_args.req  = uap->req;
 +	bsd_args.pid  = (pid_t)uap->pid;
 +	bsd_args.addr = (caddr_t)uap->addr;
 +	bsd_args.data = uap->data;
 +
 +	switch (uap->req) {
 +	case PTRACE_TRACEME:
 +	case PTRACE_POKETEXT:
 +	case PTRACE_POKEDATA:
 +	case PTRACE_KILL:
 +		error = ptrace(td, &bsd_args);
 +		break;
 +	case PTRACE_PEEKTEXT:
 +	case PTRACE_PEEKDATA: {
 +		/* need to preserve return value */
 +		int rval = td->td_retval[0];
 +		bsd_args.data = 0;
 +		error = ptrace(td, &bsd_args);
 +		if (error == 0)
 +			error = copyout(td->td_retval,
 +			    (caddr_t)uap->data, sizeof(l_int));
 +		td->td_retval[0] = rval;
 +		break;
 +	}
 +	case PTRACE_DETACH:
 +		bsd_args.req = PT_DETACH;
 +		/* fall through */
 +	case PTRACE_SINGLESTEP:
 +	case PTRACE_CONT:
 +		bsd_args.data = map_signum(uap->data);
 +		bsd_args.addr = (caddr_t)1;
 +		error = ptrace(td, &bsd_args);
 +		break;
 +	case PTRACE_ATTACH:
 +		bsd_args.req = PT_ATTACH;
 +		error = ptrace(td, &bsd_args);
 +		break;
 +	case PTRACE_GETREGS: {
 +		struct reg *bsd_r = (struct reg*)stackgap_alloc(&sg,
 +                    sizeof(*bsd_r));
 +		/* Linux is using data where FreeBSD is using addr */
 +		bsd_args.req  = PT_GETREGS;
 +		bsd_args.addr = (caddr_t)bsd_r;
 +		bsd_args.data = 0;
 +		error = ptrace(td, &bsd_args);
 +		if (error == 0)
 +			error = map_regs_to_linux(bsd_r, &r.reg);
 +		if (error == 0)
 +			error = copyout(&r.reg, (caddr_t)uap->data, sizeof r.reg);
 +		break;
 +	}
 +	case PTRACE_SETREGS: {
 +		struct reg *bsd_r = (struct reg*)stackgap_alloc(&sg,
 +                    sizeof(*bsd_r));
 +		/* Linux is using data where FreeBSD is using addr */
 +		bsd_args.req  = PT_SETREGS;
 +		bsd_args.addr = (caddr_t)bsd_r;
 +		bsd_args.data = 0;
 +		error = copyin((caddr_t)uap->data, &r.reg, sizeof r.reg);
 +		if (error == 0)
 +			error = map_regs_from_linux(bsd_r, &r.reg);
 +		if (error == 0)
 +			error = ptrace(td, &bsd_args);
 +		break;
 +	}
 +	case PTRACE_GETFPREGS: {
 +		struct fpreg *bsd_r = (struct fpreg*)stackgap_alloc(&sg,
 +                    sizeof(*bsd_r));
 +		/* Linux is using data where FreeBSD is using addr */
 +		bsd_args.req  = PT_GETFPREGS;
 +		bsd_args.addr = (caddr_t)bsd_r;
 +		bsd_args.data = 0;
 +		error = ptrace(td, &bsd_args);
 +		if (error == 0)
 +			error = map_fpregs_to_linux(bsd_r, &r.fpreg);
 +		if (error == 0)
 +			error = copyout(&r.fpreg, (caddr_t)uap->data, sizeof r.fpreg);
 +		break;
 +	}
 +	case PTRACE_SETFPREGS: {
 +		struct fpreg *bsd_r = (struct fpreg*)stackgap_alloc(&sg,
 +                    sizeof(*bsd_r));
 +		/* Linux is using data where FreeBSD is using addr */
 +		bsd_args.req  = PT_SETFPREGS;
 +		bsd_args.addr = (caddr_t)bsd_r;
 +		bsd_args.data = 0;
 +		error = copyin((caddr_t)uap->data, &r.fpreg, sizeof r.fpreg);
 +		if (error == 0)
 +			error = map_fpregs_from_linux(bsd_r, &r.fpreg);
 +		if (error == 0)
 +			error = ptrace(td, &bsd_args);
 +		break;
 +	}
 +	case PTRACE_SETFPXREGS:
 +	case PTRACE_GETFPXREGS: {
 +		struct proc *p;
 +		struct thread *td2;
 +		struct fpreg *bsd_r;
 +
 +		/*
 +		 * Use FreeBSD PT_GETFPREGS for permisson testing.
 +		 */
 +		bsd_r = (struct fpreg*)stackgap_alloc(&sg,
 +                    sizeof(*bsd_r));
 +		bsd_args.req  = PT_GETFPREGS;
 +		bsd_args.addr = (caddr_t)bsd_r;
 +		bsd_args.data = 0;
 +		error = ptrace(td, &bsd_args);
 +		/*
 +		 * If this fails, PTRACE_GETFPXREGS should fail
 +		 * for exactly the same reason. 
 +		*/
 +		if (error != 0) 			     
 +			break;
 +
 +		if ((p = pfind(uap->pid)) == NULL) {
 +			error = ESRCH;
 +			break;
 +		}
 +		td2 = FIRST_THREAD_IN_PROC(p);
 +		if (uap->req == PTRACE_GETFPXREGS) {
 +			_PHOLD(p);
 +			error = linux_proc_read_fpxregs(td2, &r.fpxreg);
 +			_PRELE(p);
 +			PROC_UNLOCK(p);
 +			if (error == 0)
 +				error = copyout(&r.fpxreg,
 +				    (caddr_t)uap->data, sizeof r.fpxreg);
 +		} else {
 +			error = copyin((caddr_t)uap->data,
 +			    &r.fpxreg, sizeof r.fpxreg);
 +			if (error == 0) {
 +				/* clear dangerous bits exactly as Linux does*/
 +				r.fpxreg.mxcsr &= 0xffbf;
 +				_PHOLD(p);
 +				error = linux_proc_write_fpxregs(
 +					td2, &r.fpxreg);
 +				_PRELE(p);
 +				PROC_UNLOCK(p);
 +			}
 +		}
 +		break;
 +	}
 +	case PTRACE_PEEKUSR:
 +	case PTRACE_POKEUSR: {
 +		error = EIO;
 +
 +		/* check addr for alignment */
 +		if (uap->addr < 0 || uap->addr & (sizeof(l_int) - 1))
 +			break;
 +		/* 
 +		 * Allow linux programs to access register values in
 +		 * user struct. We simulate this through PT_GET/SETREGS
 +		 * as necessary.
 +		 */
 +		if (uap->addr < sizeof(struct linux_pt_reg)) {
 +			struct reg *bsd_r;
 +
 +			bsd_r = (struct reg*)stackgap_alloc(&sg,
 +			    sizeof(*bsd_r));
 +			bsd_args.req  = PT_GETREGS;
 +			bsd_args.addr = (caddr_t)bsd_r;
 +			bsd_args.data = 0;
 +
 +			error = ptrace(td, &bsd_args);
 +			if (error != 0)
 +				break;
 +			
 +			error = map_regs_to_linux(bsd_r, &r.reg);
 +			if (error != 0)
 +				break;
 +
 +			if (uap->req == PTRACE_PEEKUSR) {
 +				error = copyout((char *)&r.reg + uap->addr,
 +				    (caddr_t)uap->data, sizeof(l_int));
 +				break;
 +			}
 +
 +			*(l_int *)((char *)&r.reg + uap->addr) = (l_int)uap->data;
 +
 +			error = map_regs_from_linux(bsd_r, &r.reg);
 +			if (error != 0)
 +				break;
 +
 +			bsd_args.req  = PT_SETREGS;
 +			bsd_args.addr = (caddr_t)bsd_r;
 +			bsd_args.data = 0;
 +			error = ptrace(td, &bsd_args);
 +		}
 +		
 +		/* 
 +		 * Simulate debug registers access
 +		 */
 +		if (uap->addr >= LINUX_DBREG_OFFSET && 
 +		    uap->addr <= LINUX_DBREG_OFFSET + LINUX_DBREG_SIZE) {
 +			struct dbreg *bsd_r;
 +
 +			bsd_r = (struct dbreg*)stackgap_alloc(&sg,
 +			    sizeof(*bsd_r));
 +			bsd_args.req  = PT_GETDBREGS;
 +			bsd_args.addr = (caddr_t)bsd_r;
 +			bsd_args.data = 0;
 +			error = ptrace(td, &bsd_args);
 +			if (error != 0)
 +				break;
 +			
 +			uap->addr -= LINUX_DBREG_OFFSET;
 +			if (uap->req == PTRACE_PEEKUSR) {
 +				error = copyout((char *)bsd_r + uap->addr,
 +				    (caddr_t)uap->data, sizeof(l_int));
 +				break;
 +			}
 +
 +			*(l_int *)((char *)bsd_r + uap->addr) = uap->data;
 +			bsd_args.req  = PT_SETDBREGS;
 +			bsd_args.addr = (caddr_t)bsd_r;
 +			bsd_args.data = 0;
 +			error = ptrace(td, &bsd_args);
 +		}
 +
 +		break;
 +	}
 +	case PTRACE_SYSCALL:
 +		/* fall through */
 +	default:
 +		error = EINVAL;
 +		goto noimpl;
 +	}
 +	return (error);
 +
 + noimpl:
 +	printf("linux: ptrace(%u, ...) not implemented\n",
 +	    (u_int32_t)uap->req);
 +	return (error);
 +}
 Index: i386/linux/linux_dummy.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/i386/linux/linux_dummy.c,v
 retrieving revision 1.32
 diff -u -r1.32 linux_dummy.c
 --- i386/linux/linux_dummy.c	16 Oct 2001 06:15:36 -0000	1.32
 +++ i386/linux/linux_dummy.c	24 Dec 2001 22:02:11 -0000
 @@ -38,7 +38,6 @@
  
  DUMMY(stat);
  DUMMY(stime);
 -DUMMY(ptrace);
  DUMMY(fstat);
  DUMMY(olduname);
  DUMMY(syslog);
 Index: i386/linux/syscalls.master
 ===================================================================
 RCS file: /home/ncvs/src/sys/i386/linux/syscalls.master,v
 retrieving revision 1.45
 diff -u -r1.45 syscalls.master
 --- i386/linux/syscalls.master	16 Oct 2001 06:11:11 -0000	1.45
 +++ i386/linux/syscalls.master	24 Dec 2001 22:02:11 -0000
 @@ -65,7 +65,8 @@
  23	STD	LINUX	{ int linux_setuid16(l_uid16_t uid); }
  24	STD	LINUX	{ int linux_getuid16(void); }
  25	STD	LINUX	{ int linux_stime(void); }
 -26	STD	LINUX	{ int linux_ptrace(void); }
 +26	STD	LINUX	{ int linux_ptrace(l_long req, l_long pid, l_long addr, \
 +                            l_long data); }
  27	STD	LINUX	{ int linux_alarm(l_uint secs); }
  28	STD	LINUX	{ int linux_fstat(l_uint fd, struct ostat *up); }
  29	STD	LINUX	{ int linux_pause(void); }
 Index: modules/linux/Makefile
 ===================================================================
 RCS file: /home/ncvs/src/sys/modules/linux/Makefile,v
 retrieving revision 1.56
 diff -u -r1.56 Makefile
 --- modules/linux/Makefile	22 Feb 2002 18:21:20 -0000	1.56
 +++ modules/linux/Makefile	23 Feb 2002 03:16:45 -0000
 @@ -8,7 +8,9 @@
  SRCS=	linux_dummy.c linux_file.c linux_getcwd.c linux_ioctl.c linux_ipc.c \
  	linux_machdep.c linux_mib.c linux_misc.c linux_signal.c linux_socket.c \
  	linux_stats.c linux_sysctl.c linux_sysent.c linux_sysvec.c \
 -	linux_util.c opt_compat.h opt_linux.h opt_vmpage.h vnode_if.h
 +	linux_util.c linux_ptrace.c opt_compat.h opt_linux.h opt_vmpage.h \
 +	vnode_if.h
 +
  OBJS=	linux_locore.o
  
  .if ${MACHINE_ARCH} == "i386"
State-Changed-From-To: open->closed 
State-Changed-By: marcel 
State-Changed-When: Sat May 18 18:38:15 PDT 2002 
State-Changed-Why:  
Committed. Thanks! 


http://www.freebsd.org/cgi/query-pr.cgi?pr=33299 
>Unformatted:
