linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH x86/mm 01/11] x86-32 thread_struct.debugreg
@ 2007-11-29 11:57 Roland McGrath
  2007-11-29 11:59 ` [PATCH x86/mm 02/11] x86: ptrace_32 renamed Roland McGrath
                   ` (10 more replies)
  0 siblings, 11 replies; 29+ messages in thread
From: Roland McGrath @ 2007-11-29 11:57 UTC (permalink / raw)
  To: Andrew Morton, Linus Torvalds
  Cc: linux-kernel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin


This replaces the debugreg[7] member of thread_struct with individual
members debugreg0, etc.  This saves two words for the dummies 4 and 5,
and harmonizes the code between 32 and 64.

Signed-off-by: Roland McGrath <roland@redhat.com>
---
 arch/x86/kernel/process_32.c   |   31 ++++++++++++++++++++-----------
 arch/x86/kernel/ptrace_32.c    |   29 ++++++++++++++++++++++++-----
 arch/x86/kernel/signal_32.c    |    4 ++--
 arch/x86/kernel/traps_32.c     |    4 ++--
 arch/x86/power/cpu.c           |   14 +++++++-------
 include/asm-x86/processor_32.h |    7 ++++++-
 6 files changed, 61 insertions(+), 28 deletions(-)

diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 8234054..d37bf10 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -425,7 +425,12 @@ void flush_thread(void)
 {
 	struct task_struct *tsk = current;
 
-	memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8);
+	tsk->thread.debugreg0 = 0;
+	tsk->thread.debugreg1 = 0;
+	tsk->thread.debugreg2 = 0;
+	tsk->thread.debugreg3 = 0;
+	tsk->thread.debugreg6 = 0;
+	tsk->thread.debugreg7 = 0;
 	memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));	
 	clear_tsk_thread_flag(tsk, TIF_DEBUG);
 	/*
@@ -502,7 +507,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
  */
 void dump_thread(struct pt_regs * regs, struct user * dump)
 {
-	int i;
 	u16 gs;
 
 /* changed the size calculations - should hopefully work better. lbt */
@@ -513,8 +517,14 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
 	dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT;
 	dump->u_dsize -= dump->u_tsize;
 	dump->u_ssize = 0;
-	for (i = 0; i < 8; i++)
-		dump->u_debugreg[i] = current->thread.debugreg[i];  
+	dump->u_debugreg[0] = current->thread.debugreg0;
+	dump->u_debugreg[1] = current->thread.debugreg1;
+	dump->u_debugreg[2] = current->thread.debugreg2;
+	dump->u_debugreg[3] = current->thread.debugreg3;
+	dump->u_debugreg[4] = 0;
+	dump->u_debugreg[5] = 0;
+	dump->u_debugreg[6] = current->thread.debugreg6;
+	dump->u_debugreg[7] = current->thread.debugreg7;
 
 	if (dump->start_stack < TASK_SIZE)
 		dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;
@@ -592,13 +602,13 @@ __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
 		wrmsr(MSR_IA32_DEBUGCTLMSR, next->debugctlmsr, 0);
 
 	if (test_tsk_thread_flag(next_p, TIF_DEBUG)) {
-		set_debugreg(next->debugreg[0], 0);
-		set_debugreg(next->debugreg[1], 1);
-		set_debugreg(next->debugreg[2], 2);
-		set_debugreg(next->debugreg[3], 3);
+		set_debugreg(next->debugreg0, 0);
+		set_debugreg(next->debugreg1, 1);
+		set_debugreg(next->debugreg2, 2);
+		set_debugreg(next->debugreg3, 3);
 		/* no 4 and 5 */
-		set_debugreg(next->debugreg[6], 6);
-		set_debugreg(next->debugreg[7], 7);
+		set_debugreg(next->debugreg6, 6);
+		set_debugreg(next->debugreg7, 7);
 	}
 
 #ifdef CONFIG_SECCOMP
@@ -849,4 +859,3 @@ unsigned long arch_randomize_brk(struct mm_struct *mm)
 	unsigned long range_end = mm->brk + 0x02000000;
 	return randomize_range(mm->brk, range_end, 0) ? : mm->brk;
 }
-
diff --git a/arch/x86/kernel/ptrace_32.c b/arch/x86/kernel/ptrace_32.c
index 2607130..fed83d0 100644
--- a/arch/x86/kernel/ptrace_32.c
+++ b/arch/x86/kernel/ptrace_32.c
@@ -133,19 +133,39 @@ static unsigned long getreg(struct task_struct *child, unsigned long regno)
  */
 static unsigned long ptrace_get_debugreg(struct task_struct *child, int n)
 {
-	return child->thread.debugreg[n];
+	switch (n) {
+	case 0:		return child->thread.debugreg0;
+	case 1:		return child->thread.debugreg1;
+	case 2:		return child->thread.debugreg2;
+	case 3:		return child->thread.debugreg3;
+	case 6:		return child->thread.debugreg6;
+	case 7:		return child->thread.debugreg7;
+	}
+	return 0;
 }
 
 static int ptrace_set_debugreg(struct task_struct *child,
 			       int n, unsigned long data)
 {
+	int i;
+
 	if (unlikely(n == 4 || n == 5))
 		return -EIO;
 
 	if (n < 4 && unlikely(data >= TASK_SIZE - 3))
 		return -EIO;
 
-	if (n == 7) {
+	switch (n) {
+	case 0:		child->thread.debugreg0 = data; break;
+	case 1:		child->thread.debugreg1 = data; break;
+	case 2:		child->thread.debugreg2 = data; break;
+	case 3:		child->thread.debugreg3 = data; break;
+
+	case 6:
+		child->thread.debugreg6 = data;
+		break;
+
+	case 7:
 		/*
 		 * Sanity-check data. Take one half-byte at once with
 		 * check = (val >> (16 + 4*i)) & 0xf. It contains the
@@ -176,19 +196,18 @@ static int ptrace_set_debugreg(struct task_struct *child,
 		 * 64-bit kernel), so the x86_64 mask value is 0x5454.
 		 * See the AMD manual no. 24593 (AMD64 System Programming)
 		 */
-		int i;
 		data &= ~DR_CONTROL_RESERVED;
 		for (i = 0; i < 4; i++)
 			if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
 				return -EIO;
+		child->thread.debugreg7 = data;
 		if (data)
 			set_tsk_thread_flag(child, TIF_DEBUG);
 		else
 			clear_tsk_thread_flag(child, TIF_DEBUG);
+		break;
 	}
 
-	child->thread.debugreg[n] = data;
-
 	return 0;
 }
 
diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c
index e8ab332..985c197 100644
--- a/arch/x86/kernel/signal_32.c
+++ b/arch/x86/kernel/signal_32.c
@@ -605,8 +605,8 @@ static void fastcall do_signal(struct pt_regs *regs)
 		 * have been cleared if the watchpoint triggered
 		 * inside the kernel.
 		 */
-		if (unlikely(current->thread.debugreg[7]))
-			set_debugreg(current->thread.debugreg[7], 7);
+		if (unlikely(current->thread.debugreg7))
+			set_debugreg(current->thread.debugreg7, 7);
 
 		/* Whee!  Actually deliver the signal.  */
 		if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c
index f34842a..7858ccb 100644
--- a/arch/x86/kernel/traps_32.c
+++ b/arch/x86/kernel/traps_32.c
@@ -853,7 +853,7 @@ fastcall void __kprobes do_debug(struct pt_regs * regs, long error_code)
 
 	/* Mask out spurious debug traps due to lazy DR7 setting */
 	if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
-		if (!tsk->thread.debugreg[7])
+		if (!tsk->thread.debugreg7)
 			goto clear_dr7;
 	}
 
@@ -861,7 +861,7 @@ fastcall void __kprobes do_debug(struct pt_regs * regs, long error_code)
 		goto debug_vm86;
 
 	/* Save debug status register where ptrace can see it */
-	tsk->thread.debugreg[6] = condition;
+	tsk->thread.debugreg6 = condition;
 
 	/*
 	 * Single-stepping through TF: make sure we ignore any events in
diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c
index 998fd3e..5a98dc3 100644
--- a/arch/x86/power/cpu.c
+++ b/arch/x86/power/cpu.c
@@ -74,14 +74,14 @@ static void fix_processor_context(void)
 	/*
 	 * Now maybe reload the debug registers
 	 */
-	if (current->thread.debugreg[7]){
-		set_debugreg(current->thread.debugreg[0], 0);
-		set_debugreg(current->thread.debugreg[1], 1);
-		set_debugreg(current->thread.debugreg[2], 2);
-		set_debugreg(current->thread.debugreg[3], 3);
+	if (current->thread.debugreg7) {
+		set_debugreg(current->thread.debugreg0, 0);
+		set_debugreg(current->thread.debugreg1, 1);
+		set_debugreg(current->thread.debugreg2, 2);
+		set_debugreg(current->thread.debugreg3, 3);
 		/* no 4 and 5 */
-		set_debugreg(current->thread.debugreg[6], 6);
-		set_debugreg(current->thread.debugreg[7], 7);
+		set_debugreg(current->thread.debugreg6, 6);
+		set_debugreg(current->thread.debugreg7, 7);
 	}
 
 }
diff --git a/include/asm-x86/processor_32.h b/include/asm-x86/processor_32.h
index c85400f..d50a4b4 100644
--- a/include/asm-x86/processor_32.h
+++ b/include/asm-x86/processor_32.h
@@ -353,7 +353,12 @@ struct thread_struct {
 	unsigned long	fs;
 	unsigned long	gs;
 /* Hardware debugging registers */
-	unsigned long	debugreg[8];  /* %%db0-7 debug registers */
+	unsigned long	debugreg0;
+	unsigned long	debugreg1;
+	unsigned long	debugreg2;
+	unsigned long	debugreg3;
+	unsigned long	debugreg6;
+	unsigned long	debugreg7;
 /* fault info */
 	unsigned long	cr2, trap_no, error_code;
 /* floating point info */

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH x86/mm 02/11] x86: ptrace_32 renamed
  2007-11-29 11:57 [PATCH x86/mm 01/11] x86-32 thread_struct.debugreg Roland McGrath
@ 2007-11-29 11:59 ` Roland McGrath
  2007-11-29 11:59 ` [PATCH x86/mm 03/11] x86: ptrace FLAG_MASK cleanup Roland McGrath
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 29+ messages in thread
From: Roland McGrath @ 2007-11-29 11:59 UTC (permalink / raw)
  To: Andrew Morton, Linus Torvalds
  Cc: linux-kernel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin


This renames ptrace_32.c back to ptrace.c, in preparation
for merging the 32/64 versions of these files.

Signed-off-by: Roland McGrath <roland@redhat.com>
---
 arch/x86/kernel/Makefile_32 |    3 +-
 arch/x86/kernel/ptrace.c    |  484 +++++++++++++++++++++++++++++++++++++++++++
 arch/x86/kernel/ptrace_32.c |  484 -------------------------------------------
 3 files changed, 486 insertions(+), 485 deletions(-)

diff --git a/arch/x86/kernel/Makefile_32 b/arch/x86/kernel/Makefile_32
index 369b297..8946cc8 100644
--- a/arch/x86/kernel/Makefile_32
+++ b/arch/x86/kernel/Makefile_32
@@ -6,10 +6,11 @@ extra-y := head_32.o init_task.o vmlinux.lds
 CPPFLAGS_vmlinux.lds += -Ui386
 
 obj-y	:= process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \
-		ptrace_32.o time_32.o ioport_32.o ldt.o setup_32.o i8259_32.o sys_i386_32.o \
+		time_32.o ioport_32.o ldt.o setup_32.o i8259_32.o sys_i386_32.o \
 		pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\
 		quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o rtc.o
 
+obj-y				+= ptrace.o
 obj-y				+= tls.o
 obj-y				+= step.o
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
new file mode 100644
index 0000000..fed83d0
--- /dev/null
+++ b/arch/x86/kernel/ptrace.c
@@ -0,0 +1,484 @@
+/* By Ross Biro 1/23/92 */
+/*
+ * Pentium III FXSR, SSE support
+ *	Gareth Hughes <gareth@valinux.com>, May 2000
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/security.h>
+#include <linux/audit.h>
+#include <linux/seccomp.h>
+#include <linux/signal.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/processor.h>
+#include <asm/i387.h>
+#include <asm/debugreg.h>
+#include <asm/ldt.h>
+#include <asm/desc.h>
+
+/*
+ * does not yet catch signals sent when the child dies.
+ * in exit.c or in signal.c.
+ */
+
+/*
+ * Determines which flags the user has access to [1 = access, 0 = no access].
+ * Prohibits changing ID(21), VIP(20), VIF(19), VM(17), NT(14), IOPL(12-13), IF(9).
+ * Also masks reserved bits (31-22, 15, 5, 3, 1).
+ */
+#define FLAG_MASK 0x00050dd5
+
+static long *pt_regs_access(struct pt_regs *regs, unsigned long regno)
+{
+	BUILD_BUG_ON(offsetof(struct pt_regs, bx) != 0);
+	if (regno > FS)
+		--regno;
+	return &regs->bx + regno;
+}
+
+static int putreg(struct task_struct *child,
+	unsigned long regno, unsigned long value)
+{
+	struct pt_regs *regs = task_pt_regs(child);
+	regno >>= 2;
+	switch (regno) {
+	case GS:
+		if (value && (value & 3) != 3)
+			return -EIO;
+		child->thread.gs = value;
+		if (child == current)
+			/*
+			 * The user-mode %gs is not affected by
+			 * kernel entry, so we must update the CPU.
+			 */
+			loadsegment(gs, value);
+		return 0;
+	case DS:
+	case ES:
+	case FS:
+		if (value && (value & 3) != 3)
+			return -EIO;
+		value &= 0xffff;
+		break;
+	case SS:
+	case CS:
+		if ((value & 3) != 3)
+			return -EIO;
+		value &= 0xffff;
+		break;
+	case EFL:
+		value &= FLAG_MASK;
+		/*
+		 * If the user value contains TF, mark that
+		 * it was not "us" (the debugger) that set it.
+		 * If not, make sure it stays set if we had.
+		 */
+		if (value & X86_EFLAGS_TF)
+			clear_tsk_thread_flag(child, TIF_FORCED_TF);
+		else if (test_tsk_thread_flag(child, TIF_FORCED_TF))
+			value |= X86_EFLAGS_TF;
+		value |= regs->flags & ~FLAG_MASK;
+		break;
+	}
+	*pt_regs_access(regs, regno) = value;
+	return 0;
+}
+
+static unsigned long getreg(struct task_struct *child, unsigned long regno)
+{
+	struct pt_regs *regs = task_pt_regs(child);
+	unsigned long retval = ~0UL;
+
+	regno >>= 2;
+	switch (regno) {
+	case EFL:
+		/*
+		 * If the debugger set TF, hide it from the readout.
+		 */
+		retval = regs->flags;
+		if (test_tsk_thread_flag(child, TIF_FORCED_TF))
+			retval &= ~X86_EFLAGS_TF;
+		break;
+	case GS:
+		retval = child->thread.gs;
+		if (child == current)
+			savesegment(gs, retval);
+		break;
+	case DS:
+	case ES:
+	case FS:
+	case SS:
+	case CS:
+		retval = 0xffff;
+		/* fall through */
+	default:
+		retval &= *pt_regs_access(regs, regno);
+	}
+	return retval;
+}
+
+/*
+ * This function is trivial and will be inlined by the compiler.
+ * Having it separates the implementation details of debug
+ * registers from the interface details of ptrace.
+ */
+static unsigned long ptrace_get_debugreg(struct task_struct *child, int n)
+{
+	switch (n) {
+	case 0:		return child->thread.debugreg0;
+	case 1:		return child->thread.debugreg1;
+	case 2:		return child->thread.debugreg2;
+	case 3:		return child->thread.debugreg3;
+	case 6:		return child->thread.debugreg6;
+	case 7:		return child->thread.debugreg7;
+	}
+	return 0;
+}
+
+static int ptrace_set_debugreg(struct task_struct *child,
+			       int n, unsigned long data)
+{
+	int i;
+
+	if (unlikely(n == 4 || n == 5))
+		return -EIO;
+
+	if (n < 4 && unlikely(data >= TASK_SIZE - 3))
+		return -EIO;
+
+	switch (n) {
+	case 0:		child->thread.debugreg0 = data; break;
+	case 1:		child->thread.debugreg1 = data; break;
+	case 2:		child->thread.debugreg2 = data; break;
+	case 3:		child->thread.debugreg3 = data; break;
+
+	case 6:
+		child->thread.debugreg6 = data;
+		break;
+
+	case 7:
+		/*
+		 * Sanity-check data. Take one half-byte at once with
+		 * check = (val >> (16 + 4*i)) & 0xf. It contains the
+		 * R/Wi and LENi bits; bits 0 and 1 are R/Wi, and bits
+		 * 2 and 3 are LENi. Given a list of invalid values,
+		 * we do mask |= 1 << invalid_value, so that
+		 * (mask >> check) & 1 is a correct test for invalid
+		 * values.
+		 *
+		 * R/Wi contains the type of the breakpoint /
+		 * watchpoint, LENi contains the length of the watched
+		 * data in the watchpoint case.
+		 *
+		 * The invalid values are:
+		 * - LENi == 0x10 (undefined), so mask |= 0x0f00.
+		 * - R/Wi == 0x10 (break on I/O reads or writes), so
+		 *   mask |= 0x4444.
+		 * - R/Wi == 0x00 && LENi != 0x00, so we have mask |=
+		 *   0x1110.
+		 *
+		 * Finally, mask = 0x0f00 | 0x4444 | 0x1110 == 0x5f54.
+		 *
+		 * See the Intel Manual "System Programming Guide",
+		 * 15.2.4
+		 *
+		 * Note that LENi == 0x10 is defined on x86_64 in long
+		 * mode (i.e. even for 32-bit userspace software, but
+		 * 64-bit kernel), so the x86_64 mask value is 0x5454.
+		 * See the AMD manual no. 24593 (AMD64 System Programming)
+		 */
+		data &= ~DR_CONTROL_RESERVED;
+		for (i = 0; i < 4; i++)
+			if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
+				return -EIO;
+		child->thread.debugreg7 = data;
+		if (data)
+			set_tsk_thread_flag(child, TIF_DEBUG);
+		else
+			clear_tsk_thread_flag(child, TIF_DEBUG);
+		break;
+	}
+
+	return 0;
+}
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure the single step bit is not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{
+	user_disable_single_step(child);
+	clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+}
+
+long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+{
+	struct user * dummy = NULL;
+	int i, ret;
+	unsigned long __user *datap = (unsigned long __user *)data;
+
+	switch (request) {
+	/* when I and D space are separate, these will need to be fixed. */
+	case PTRACE_PEEKTEXT: /* read word at location addr. */
+	case PTRACE_PEEKDATA:
+		ret = generic_ptrace_peekdata(child, addr, data);
+		break;
+
+	/* read the word at location addr in the USER area. */
+	case PTRACE_PEEKUSR: {
+		unsigned long tmp;
+
+		ret = -EIO;
+		if ((addr & 3) || addr < 0 ||
+		    addr > sizeof(struct user) - 3)
+			break;
+
+		tmp = 0;  /* Default return condition */
+		if(addr < FRAME_SIZE*sizeof(long))
+			tmp = getreg(child, addr);
+		if(addr >= (long) &dummy->u_debugreg[0] &&
+		   addr <= (long) &dummy->u_debugreg[7]){
+			addr -= (long) &dummy->u_debugreg[0];
+			addr = addr >> 2;
+			tmp = ptrace_get_debugreg(child, addr);
+		}
+		ret = put_user(tmp, datap);
+		break;
+	}
+
+	/* when I and D space are separate, this will have to be fixed. */
+	case PTRACE_POKETEXT: /* write the word at location addr. */
+	case PTRACE_POKEDATA:
+		ret = generic_ptrace_pokedata(child, addr, data);
+		break;
+
+	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
+		ret = -EIO;
+		if ((addr & 3) || addr < 0 ||
+		    addr > sizeof(struct user) - 3)
+			break;
+
+		if (addr < FRAME_SIZE*sizeof(long)) {
+			ret = putreg(child, addr, data);
+			break;
+		}
+		/* We need to be very careful here.  We implicitly
+		   want to modify a portion of the task_struct, and we
+		   have to be selective about what portions we allow someone
+		   to modify. */
+
+		  ret = -EIO;
+		  if(addr >= (long) &dummy->u_debugreg[0] &&
+		     addr <= (long) &dummy->u_debugreg[7]){
+			  addr -= (long) &dummy->u_debugreg;
+			  addr = addr >> 2;
+			  ret = ptrace_set_debugreg(child, addr, data);
+		  }
+		  break;
+
+	case PTRACE_GETREGS: { /* Get all gp regs from the child. */
+	  	if (!access_ok(VERIFY_WRITE, datap, FRAME_SIZE*sizeof(long))) {
+			ret = -EIO;
+			break;
+		}
+		for ( i = 0; i < FRAME_SIZE*sizeof(long); i += sizeof(long) ) {
+			__put_user(getreg(child, i), datap);
+			datap++;
+		}
+		ret = 0;
+		break;
+	}
+
+	case PTRACE_SETREGS: { /* Set all gp regs in the child. */
+		unsigned long tmp;
+	  	if (!access_ok(VERIFY_READ, datap, FRAME_SIZE*sizeof(long))) {
+			ret = -EIO;
+			break;
+		}
+		for ( i = 0; i < FRAME_SIZE*sizeof(long); i += sizeof(long) ) {
+			__get_user(tmp, datap);
+			putreg(child, i, tmp);
+			datap++;
+		}
+		ret = 0;
+		break;
+	}
+
+	case PTRACE_GETFPREGS: { /* Get the child FPU state. */
+		if (!access_ok(VERIFY_WRITE, datap,
+			       sizeof(struct user_i387_struct))) {
+			ret = -EIO;
+			break;
+		}
+		ret = 0;
+		if (!tsk_used_math(child))
+			init_fpu(child);
+		get_fpregs((struct user_i387_struct __user *)data, child);
+		break;
+	}
+
+	case PTRACE_SETFPREGS: { /* Set the child FPU state. */
+		if (!access_ok(VERIFY_READ, datap,
+			       sizeof(struct user_i387_struct))) {
+			ret = -EIO;
+			break;
+		}
+		set_stopped_child_used_math(child);
+		set_fpregs(child, (struct user_i387_struct __user *)data);
+		ret = 0;
+		break;
+	}
+
+	case PTRACE_GETFPXREGS: { /* Get the child extended FPU state. */
+		if (!access_ok(VERIFY_WRITE, datap,
+			       sizeof(struct user_fxsr_struct))) {
+			ret = -EIO;
+			break;
+		}
+		if (!tsk_used_math(child))
+			init_fpu(child);
+		ret = get_fpxregs((struct user_fxsr_struct __user *)data, child);
+		break;
+	}
+
+	case PTRACE_SETFPXREGS: { /* Set the child extended FPU state. */
+		if (!access_ok(VERIFY_READ, datap,
+			       sizeof(struct user_fxsr_struct))) {
+			ret = -EIO;
+			break;
+		}
+		set_stopped_child_used_math(child);
+		ret = set_fpxregs(child, (struct user_fxsr_struct __user *)data);
+		break;
+	}
+
+	case PTRACE_GET_THREAD_AREA:
+		if (addr < 0)
+			return -EIO;
+		ret = do_get_thread_area(child, addr,
+					 (struct user_desc __user *) data);
+		break;
+
+	case PTRACE_SET_THREAD_AREA:
+		if (addr < 0)
+			return -EIO;
+		ret = do_set_thread_area(child, addr,
+					 (struct user_desc __user *) data, 0);
+		break;
+
+	default:
+		ret = ptrace_request(child, request, addr, data);
+		break;
+	}
+
+	return ret;
+}
+
+void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)
+{
+	struct siginfo info;
+
+	tsk->thread.trap_no = 1;
+	tsk->thread.error_code = error_code;
+
+	memset(&info, 0, sizeof(info));
+	info.si_signo = SIGTRAP;
+	info.si_code = TRAP_BRKPT;
+
+	/* User-mode ip? */
+	info.si_addr = user_mode_vm(regs) ? (void __user *) regs->ip : NULL;
+
+	/* Send us the fake SIGTRAP */
+	force_sig_info(SIGTRAP, &info, tsk);
+}
+
+/* notification of system call entry/exit
+ * - triggered by current->work.syscall_trace
+ */
+__attribute__((regparm(3)))
+int do_syscall_trace(struct pt_regs *regs, int entryexit)
+{
+	int is_sysemu = test_thread_flag(TIF_SYSCALL_EMU);
+	/*
+	 * With TIF_SYSCALL_EMU set we want to ignore TIF_SINGLESTEP for syscall
+	 * interception
+	 */
+	int is_singlestep = !is_sysemu && test_thread_flag(TIF_SINGLESTEP);
+	int ret = 0;
+
+	/* do the secure computing check first */
+	if (!entryexit)
+		secure_computing(regs->orig_ax);
+
+	if (unlikely(current->audit_context)) {
+		if (entryexit)
+			audit_syscall_exit(AUDITSC_RESULT(regs->ax),
+						regs->ax);
+		/* Debug traps, when using PTRACE_SINGLESTEP, must be sent only
+		 * on the syscall exit path. Normally, when TIF_SYSCALL_AUDIT is
+		 * not used, entry.S will call us only on syscall exit, not
+		 * entry; so when TIF_SYSCALL_AUDIT is used we must avoid
+		 * calling send_sigtrap() on syscall entry.
+		 *
+		 * Note that when PTRACE_SYSEMU_SINGLESTEP is used,
+		 * is_singlestep is false, despite his name, so we will still do
+		 * the correct thing.
+		 */
+		else if (is_singlestep)
+			goto out;
+	}
+
+	if (!(current->ptrace & PT_PTRACED))
+		goto out;
+
+	/* If a process stops on the 1st tracepoint with SYSCALL_TRACE
+	 * and then is resumed with SYSEMU_SINGLESTEP, it will come in
+	 * here. We have to check this and return */
+	if (is_sysemu && entryexit)
+		return 0;
+
+	/* Fake a debug trap */
+	if (is_singlestep)
+		send_sigtrap(current, regs, 0);
+
+ 	if (!test_thread_flag(TIF_SYSCALL_TRACE) && !is_sysemu)
+		goto out;
+
+	/* the 0x80 provides a way for the tracing parent to distinguish
+	   between a syscall stop and SIGTRAP delivery */
+	/* Note that the debugger could change the result of test_thread_flag!*/
+	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80:0));
+
+	/*
+	 * this isn't the same as continuing with a signal, but it will do
+	 * for normal use.  strace only continues with a signal if the
+	 * stopping signal is not SIGTRAP.  -brl
+	 */
+	if (current->exit_code) {
+		send_sig(current->exit_code, current, 1);
+		current->exit_code = 0;
+	}
+	ret = is_sysemu;
+out:
+	if (unlikely(current->audit_context) && !entryexit)
+		audit_syscall_entry(AUDIT_ARCH_I386, regs->orig_ax,
+				    regs->bx, regs->cx, regs->dx, regs->si);
+	if (ret == 0)
+		return 0;
+
+	regs->orig_ax = -1; /* force skip of syscall restarting */
+	if (unlikely(current->audit_context))
+		audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax);
+	return 1;
+}
diff --git a/arch/x86/kernel/ptrace_32.c b/arch/x86/kernel/ptrace_32.c
deleted file mode 100644
index fed83d0..0000000
--- a/arch/x86/kernel/ptrace_32.c
+++ /dev/null
@@ -1,484 +0,0 @@
-/* By Ross Biro 1/23/92 */
-/*
- * Pentium III FXSR, SSE support
- *	Gareth Hughes <gareth@valinux.com>, May 2000
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/errno.h>
-#include <linux/ptrace.h>
-#include <linux/user.h>
-#include <linux/security.h>
-#include <linux/audit.h>
-#include <linux/seccomp.h>
-#include <linux/signal.h>
-
-#include <asm/uaccess.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/processor.h>
-#include <asm/i387.h>
-#include <asm/debugreg.h>
-#include <asm/ldt.h>
-#include <asm/desc.h>
-
-/*
- * does not yet catch signals sent when the child dies.
- * in exit.c or in signal.c.
- */
-
-/*
- * Determines which flags the user has access to [1 = access, 0 = no access].
- * Prohibits changing ID(21), VIP(20), VIF(19), VM(17), NT(14), IOPL(12-13), IF(9).
- * Also masks reserved bits (31-22, 15, 5, 3, 1).
- */
-#define FLAG_MASK 0x00050dd5
-
-static long *pt_regs_access(struct pt_regs *regs, unsigned long regno)
-{
-	BUILD_BUG_ON(offsetof(struct pt_regs, bx) != 0);
-	if (regno > FS)
-		--regno;
-	return &regs->bx + regno;
-}
-
-static int putreg(struct task_struct *child,
-	unsigned long regno, unsigned long value)
-{
-	struct pt_regs *regs = task_pt_regs(child);
-	regno >>= 2;
-	switch (regno) {
-	case GS:
-		if (value && (value & 3) != 3)
-			return -EIO;
-		child->thread.gs = value;
-		if (child == current)
-			/*
-			 * The user-mode %gs is not affected by
-			 * kernel entry, so we must update the CPU.
-			 */
-			loadsegment(gs, value);
-		return 0;
-	case DS:
-	case ES:
-	case FS:
-		if (value && (value & 3) != 3)
-			return -EIO;
-		value &= 0xffff;
-		break;
-	case SS:
-	case CS:
-		if ((value & 3) != 3)
-			return -EIO;
-		value &= 0xffff;
-		break;
-	case EFL:
-		value &= FLAG_MASK;
-		/*
-		 * If the user value contains TF, mark that
-		 * it was not "us" (the debugger) that set it.
-		 * If not, make sure it stays set if we had.
-		 */
-		if (value & X86_EFLAGS_TF)
-			clear_tsk_thread_flag(child, TIF_FORCED_TF);
-		else if (test_tsk_thread_flag(child, TIF_FORCED_TF))
-			value |= X86_EFLAGS_TF;
-		value |= regs->flags & ~FLAG_MASK;
-		break;
-	}
-	*pt_regs_access(regs, regno) = value;
-	return 0;
-}
-
-static unsigned long getreg(struct task_struct *child, unsigned long regno)
-{
-	struct pt_regs *regs = task_pt_regs(child);
-	unsigned long retval = ~0UL;
-
-	regno >>= 2;
-	switch (regno) {
-	case EFL:
-		/*
-		 * If the debugger set TF, hide it from the readout.
-		 */
-		retval = regs->flags;
-		if (test_tsk_thread_flag(child, TIF_FORCED_TF))
-			retval &= ~X86_EFLAGS_TF;
-		break;
-	case GS:
-		retval = child->thread.gs;
-		if (child == current)
-			savesegment(gs, retval);
-		break;
-	case DS:
-	case ES:
-	case FS:
-	case SS:
-	case CS:
-		retval = 0xffff;
-		/* fall through */
-	default:
-		retval &= *pt_regs_access(regs, regno);
-	}
-	return retval;
-}
-
-/*
- * This function is trivial and will be inlined by the compiler.
- * Having it separates the implementation details of debug
- * registers from the interface details of ptrace.
- */
-static unsigned long ptrace_get_debugreg(struct task_struct *child, int n)
-{
-	switch (n) {
-	case 0:		return child->thread.debugreg0;
-	case 1:		return child->thread.debugreg1;
-	case 2:		return child->thread.debugreg2;
-	case 3:		return child->thread.debugreg3;
-	case 6:		return child->thread.debugreg6;
-	case 7:		return child->thread.debugreg7;
-	}
-	return 0;
-}
-
-static int ptrace_set_debugreg(struct task_struct *child,
-			       int n, unsigned long data)
-{
-	int i;
-
-	if (unlikely(n == 4 || n == 5))
-		return -EIO;
-
-	if (n < 4 && unlikely(data >= TASK_SIZE - 3))
-		return -EIO;
-
-	switch (n) {
-	case 0:		child->thread.debugreg0 = data; break;
-	case 1:		child->thread.debugreg1 = data; break;
-	case 2:		child->thread.debugreg2 = data; break;
-	case 3:		child->thread.debugreg3 = data; break;
-
-	case 6:
-		child->thread.debugreg6 = data;
-		break;
-
-	case 7:
-		/*
-		 * Sanity-check data. Take one half-byte at once with
-		 * check = (val >> (16 + 4*i)) & 0xf. It contains the
-		 * R/Wi and LENi bits; bits 0 and 1 are R/Wi, and bits
-		 * 2 and 3 are LENi. Given a list of invalid values,
-		 * we do mask |= 1 << invalid_value, so that
-		 * (mask >> check) & 1 is a correct test for invalid
-		 * values.
-		 *
-		 * R/Wi contains the type of the breakpoint /
-		 * watchpoint, LENi contains the length of the watched
-		 * data in the watchpoint case.
-		 *
-		 * The invalid values are:
-		 * - LENi == 0x10 (undefined), so mask |= 0x0f00.
-		 * - R/Wi == 0x10 (break on I/O reads or writes), so
-		 *   mask |= 0x4444.
-		 * - R/Wi == 0x00 && LENi != 0x00, so we have mask |=
-		 *   0x1110.
-		 *
-		 * Finally, mask = 0x0f00 | 0x4444 | 0x1110 == 0x5f54.
-		 *
-		 * See the Intel Manual "System Programming Guide",
-		 * 15.2.4
-		 *
-		 * Note that LENi == 0x10 is defined on x86_64 in long
-		 * mode (i.e. even for 32-bit userspace software, but
-		 * 64-bit kernel), so the x86_64 mask value is 0x5454.
-		 * See the AMD manual no. 24593 (AMD64 System Programming)
-		 */
-		data &= ~DR_CONTROL_RESERVED;
-		for (i = 0; i < 4; i++)
-			if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
-				return -EIO;
-		child->thread.debugreg7 = data;
-		if (data)
-			set_tsk_thread_flag(child, TIF_DEBUG);
-		else
-			clear_tsk_thread_flag(child, TIF_DEBUG);
-		break;
-	}
-
-	return 0;
-}
-
-/*
- * Called by kernel/ptrace.c when detaching..
- *
- * Make sure the single step bit is not set.
- */
-void ptrace_disable(struct task_struct *child)
-{
-	user_disable_single_step(child);
-	clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
-}
-
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
-{
-	struct user * dummy = NULL;
-	int i, ret;
-	unsigned long __user *datap = (unsigned long __user *)data;
-
-	switch (request) {
-	/* when I and D space are separate, these will need to be fixed. */
-	case PTRACE_PEEKTEXT: /* read word at location addr. */
-	case PTRACE_PEEKDATA:
-		ret = generic_ptrace_peekdata(child, addr, data);
-		break;
-
-	/* read the word at location addr in the USER area. */
-	case PTRACE_PEEKUSR: {
-		unsigned long tmp;
-
-		ret = -EIO;
-		if ((addr & 3) || addr < 0 ||
-		    addr > sizeof(struct user) - 3)
-			break;
-
-		tmp = 0;  /* Default return condition */
-		if(addr < FRAME_SIZE*sizeof(long))
-			tmp = getreg(child, addr);
-		if(addr >= (long) &dummy->u_debugreg[0] &&
-		   addr <= (long) &dummy->u_debugreg[7]){
-			addr -= (long) &dummy->u_debugreg[0];
-			addr = addr >> 2;
-			tmp = ptrace_get_debugreg(child, addr);
-		}
-		ret = put_user(tmp, datap);
-		break;
-	}
-
-	/* when I and D space are separate, this will have to be fixed. */
-	case PTRACE_POKETEXT: /* write the word at location addr. */
-	case PTRACE_POKEDATA:
-		ret = generic_ptrace_pokedata(child, addr, data);
-		break;
-
-	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
-		ret = -EIO;
-		if ((addr & 3) || addr < 0 ||
-		    addr > sizeof(struct user) - 3)
-			break;
-
-		if (addr < FRAME_SIZE*sizeof(long)) {
-			ret = putreg(child, addr, data);
-			break;
-		}
-		/* We need to be very careful here.  We implicitly
-		   want to modify a portion of the task_struct, and we
-		   have to be selective about what portions we allow someone
-		   to modify. */
-
-		  ret = -EIO;
-		  if(addr >= (long) &dummy->u_debugreg[0] &&
-		     addr <= (long) &dummy->u_debugreg[7]){
-			  addr -= (long) &dummy->u_debugreg;
-			  addr = addr >> 2;
-			  ret = ptrace_set_debugreg(child, addr, data);
-		  }
-		  break;
-
-	case PTRACE_GETREGS: { /* Get all gp regs from the child. */
-	  	if (!access_ok(VERIFY_WRITE, datap, FRAME_SIZE*sizeof(long))) {
-			ret = -EIO;
-			break;
-		}
-		for ( i = 0; i < FRAME_SIZE*sizeof(long); i += sizeof(long) ) {
-			__put_user(getreg(child, i), datap);
-			datap++;
-		}
-		ret = 0;
-		break;
-	}
-
-	case PTRACE_SETREGS: { /* Set all gp regs in the child. */
-		unsigned long tmp;
-	  	if (!access_ok(VERIFY_READ, datap, FRAME_SIZE*sizeof(long))) {
-			ret = -EIO;
-			break;
-		}
-		for ( i = 0; i < FRAME_SIZE*sizeof(long); i += sizeof(long) ) {
-			__get_user(tmp, datap);
-			putreg(child, i, tmp);
-			datap++;
-		}
-		ret = 0;
-		break;
-	}
-
-	case PTRACE_GETFPREGS: { /* Get the child FPU state. */
-		if (!access_ok(VERIFY_WRITE, datap,
-			       sizeof(struct user_i387_struct))) {
-			ret = -EIO;
-			break;
-		}
-		ret = 0;
-		if (!tsk_used_math(child))
-			init_fpu(child);
-		get_fpregs((struct user_i387_struct __user *)data, child);
-		break;
-	}
-
-	case PTRACE_SETFPREGS: { /* Set the child FPU state. */
-		if (!access_ok(VERIFY_READ, datap,
-			       sizeof(struct user_i387_struct))) {
-			ret = -EIO;
-			break;
-		}
-		set_stopped_child_used_math(child);
-		set_fpregs(child, (struct user_i387_struct __user *)data);
-		ret = 0;
-		break;
-	}
-
-	case PTRACE_GETFPXREGS: { /* Get the child extended FPU state. */
-		if (!access_ok(VERIFY_WRITE, datap,
-			       sizeof(struct user_fxsr_struct))) {
-			ret = -EIO;
-			break;
-		}
-		if (!tsk_used_math(child))
-			init_fpu(child);
-		ret = get_fpxregs((struct user_fxsr_struct __user *)data, child);
-		break;
-	}
-
-	case PTRACE_SETFPXREGS: { /* Set the child extended FPU state. */
-		if (!access_ok(VERIFY_READ, datap,
-			       sizeof(struct user_fxsr_struct))) {
-			ret = -EIO;
-			break;
-		}
-		set_stopped_child_used_math(child);
-		ret = set_fpxregs(child, (struct user_fxsr_struct __user *)data);
-		break;
-	}
-
-	case PTRACE_GET_THREAD_AREA:
-		if (addr < 0)
-			return -EIO;
-		ret = do_get_thread_area(child, addr,
-					 (struct user_desc __user *) data);
-		break;
-
-	case PTRACE_SET_THREAD_AREA:
-		if (addr < 0)
-			return -EIO;
-		ret = do_set_thread_area(child, addr,
-					 (struct user_desc __user *) data, 0);
-		break;
-
-	default:
-		ret = ptrace_request(child, request, addr, data);
-		break;
-	}
-
-	return ret;
-}
-
-void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)
-{
-	struct siginfo info;
-
-	tsk->thread.trap_no = 1;
-	tsk->thread.error_code = error_code;
-
-	memset(&info, 0, sizeof(info));
-	info.si_signo = SIGTRAP;
-	info.si_code = TRAP_BRKPT;
-
-	/* User-mode ip? */
-	info.si_addr = user_mode_vm(regs) ? (void __user *) regs->ip : NULL;
-
-	/* Send us the fake SIGTRAP */
-	force_sig_info(SIGTRAP, &info, tsk);
-}
-
-/* notification of system call entry/exit
- * - triggered by current->work.syscall_trace
- */
-__attribute__((regparm(3)))
-int do_syscall_trace(struct pt_regs *regs, int entryexit)
-{
-	int is_sysemu = test_thread_flag(TIF_SYSCALL_EMU);
-	/*
-	 * With TIF_SYSCALL_EMU set we want to ignore TIF_SINGLESTEP for syscall
-	 * interception
-	 */
-	int is_singlestep = !is_sysemu && test_thread_flag(TIF_SINGLESTEP);
-	int ret = 0;
-
-	/* do the secure computing check first */
-	if (!entryexit)
-		secure_computing(regs->orig_ax);
-
-	if (unlikely(current->audit_context)) {
-		if (entryexit)
-			audit_syscall_exit(AUDITSC_RESULT(regs->ax),
-						regs->ax);
-		/* Debug traps, when using PTRACE_SINGLESTEP, must be sent only
-		 * on the syscall exit path. Normally, when TIF_SYSCALL_AUDIT is
-		 * not used, entry.S will call us only on syscall exit, not
-		 * entry; so when TIF_SYSCALL_AUDIT is used we must avoid
-		 * calling send_sigtrap() on syscall entry.
-		 *
-		 * Note that when PTRACE_SYSEMU_SINGLESTEP is used,
-		 * is_singlestep is false, despite his name, so we will still do
-		 * the correct thing.
-		 */
-		else if (is_singlestep)
-			goto out;
-	}
-
-	if (!(current->ptrace & PT_PTRACED))
-		goto out;
-
-	/* If a process stops on the 1st tracepoint with SYSCALL_TRACE
-	 * and then is resumed with SYSEMU_SINGLESTEP, it will come in
-	 * here. We have to check this and return */
-	if (is_sysemu && entryexit)
-		return 0;
-
-	/* Fake a debug trap */
-	if (is_singlestep)
-		send_sigtrap(current, regs, 0);
-
- 	if (!test_thread_flag(TIF_SYSCALL_TRACE) && !is_sysemu)
-		goto out;
-
-	/* the 0x80 provides a way for the tracing parent to distinguish
-	   between a syscall stop and SIGTRAP delivery */
-	/* Note that the debugger could change the result of test_thread_flag!*/
-	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80:0));
-
-	/*
-	 * this isn't the same as continuing with a signal, but it will do
-	 * for normal use.  strace only continues with a signal if the
-	 * stopping signal is not SIGTRAP.  -brl
-	 */
-	if (current->exit_code) {
-		send_sig(current->exit_code, current, 1);
-		current->exit_code = 0;
-	}
-	ret = is_sysemu;
-out:
-	if (unlikely(current->audit_context) && !entryexit)
-		audit_syscall_entry(AUDIT_ARCH_I386, regs->orig_ax,
-				    regs->bx, regs->cx, regs->dx, regs->si);
-	if (ret == 0)
-		return 0;
-
-	regs->orig_ax = -1; /* force skip of syscall restarting */
-	if (unlikely(current->audit_context))
-		audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax);
-	return 1;
-}

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH x86/mm 03/11] x86: ptrace FLAG_MASK cleanup
  2007-11-29 11:57 [PATCH x86/mm 01/11] x86-32 thread_struct.debugreg Roland McGrath
  2007-11-29 11:59 ` [PATCH x86/mm 02/11] x86: ptrace_32 renamed Roland McGrath
@ 2007-11-29 11:59 ` Roland McGrath
  2007-11-29 11:59 ` [PATCH x86/mm 04/11] x86 ptrace getreg/putreg cleanup Roland McGrath
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 29+ messages in thread
From: Roland McGrath @ 2007-11-29 11:59 UTC (permalink / raw)
  To: Andrew Morton, Linus Torvalds
  Cc: linux-kernel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin


This cleans up the FLAG_MASK macro to use symbolic constants instead of a
magic number.

Signed-off-by: Roland McGrath <roland@redhat.com>
---
 arch/x86/kernel/ptrace.c |   11 ++++++++---
 1 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index fed83d0..b71226d 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -32,10 +32,15 @@
 
 /*
  * Determines which flags the user has access to [1 = access, 0 = no access].
- * Prohibits changing ID(21), VIP(20), VIF(19), VM(17), NT(14), IOPL(12-13), IF(9).
- * Also masks reserved bits (31-22, 15, 5, 3, 1).
  */
-#define FLAG_MASK 0x00050dd5
+#define FLAG_MASK_32		((unsigned long)			\
+				 (X86_EFLAGS_CF | X86_EFLAGS_PF |	\
+				  X86_EFLAGS_AF | X86_EFLAGS_ZF |	\
+				  X86_EFLAGS_SF | X86_EFLAGS_TF |	\
+				  X86_EFLAGS_DF | X86_EFLAGS_OF |	\
+				  X86_EFLAGS_RF | X86_EFLAGS_AC))
+
+#define FLAG_MASK		FLAG_MASK_32
 
 static long *pt_regs_access(struct pt_regs *regs, unsigned long regno)
 {

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH x86/mm 04/11] x86 ptrace getreg/putreg cleanup
  2007-11-29 11:57 [PATCH x86/mm 01/11] x86-32 thread_struct.debugreg Roland McGrath
  2007-11-29 11:59 ` [PATCH x86/mm 02/11] x86: ptrace_32 renamed Roland McGrath
  2007-11-29 11:59 ` [PATCH x86/mm 03/11] x86: ptrace FLAG_MASK cleanup Roland McGrath
@ 2007-11-29 11:59 ` Roland McGrath
  2007-11-29 11:59 ` [PATCH x86/mm 05/11] x86 ptrace getreg/putreg merge Roland McGrath
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 29+ messages in thread
From: Roland McGrath @ 2007-11-29 11:59 UTC (permalink / raw)
  To: Andrew Morton, Linus Torvalds
  Cc: linux-kernel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin


This cleans up the getreg/putreg functions to move the special cases
(segment registers and eflags) out into their own subroutines.

Signed-off-by: Roland McGrath <roland@redhat.com>
---
 arch/x86/kernel/ptrace.c |  162 +++++++++++++++++++++++++++-------------------
 1 files changed, 96 insertions(+), 66 deletions(-)

diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index b71226d..eaec75a 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -45,92 +45,122 @@
 static long *pt_regs_access(struct pt_regs *regs, unsigned long regno)
 {
 	BUILD_BUG_ON(offsetof(struct pt_regs, bx) != 0);
+	regno >>= 2;
 	if (regno > FS)
 		--regno;
 	return &regs->bx + regno;
 }
 
-static int putreg(struct task_struct *child,
-	unsigned long regno, unsigned long value)
+static u16 get_segment_reg(struct task_struct *task, unsigned long offset)
 {
-	struct pt_regs *regs = task_pt_regs(child);
-	regno >>= 2;
-	switch (regno) {
-	case GS:
-		if (value && (value & 3) != 3)
-			return -EIO;
-		child->thread.gs = value;
-		if (child == current)
+	/*
+	 * Returning the value truncates it to 16 bits.
+	 */
+	unsigned int retval;
+	if (offset != offsetof(struct user_regs_struct, gs))
+		retval = *pt_regs_access(task_pt_regs(task), offset);
+	else {
+		retval = task->thread.gs;
+		if (task == current)
+			savesegment(gs, retval);
+	}
+	return retval;
+}
+
+static int set_segment_reg(struct task_struct *task,
+			   unsigned long offset, u16 value)
+{
+	/*
+	 * The value argument was already truncated to 16 bits.
+	 */
+	if (value && (value & 3) != 3)
+		return -EIO;
+
+	if (offset != offsetof(struct user_regs_struct, gs))
+		*pt_regs_access(task_pt_regs(task), offset) = value;
+	else {
+		task->thread.gs = value;
+		if (task == current)
 			/*
 			 * The user-mode %gs is not affected by
 			 * kernel entry, so we must update the CPU.
 			 */
 			loadsegment(gs, value);
-		return 0;
-	case DS:
-	case ES:
-	case FS:
-		if (value && (value & 3) != 3)
-			return -EIO;
-		value &= 0xffff;
-		break;
-	case SS:
-	case CS:
-		if ((value & 3) != 3)
-			return -EIO;
-		value &= 0xffff;
-		break;
-	case EFL:
-		value &= FLAG_MASK;
-		/*
-		 * If the user value contains TF, mark that
-		 * it was not "us" (the debugger) that set it.
-		 * If not, make sure it stays set if we had.
-		 */
-		if (value & X86_EFLAGS_TF)
-			clear_tsk_thread_flag(child, TIF_FORCED_TF);
-		else if (test_tsk_thread_flag(child, TIF_FORCED_TF))
-			value |= X86_EFLAGS_TF;
-		value |= regs->flags & ~FLAG_MASK;
-		break;
 	}
-	*pt_regs_access(regs, regno) = value;
+
 	return 0;
 }
 
-static unsigned long getreg(struct task_struct *child, unsigned long regno)
+static unsigned long get_flags(struct task_struct *task)
 {
-	struct pt_regs *regs = task_pt_regs(child);
-	unsigned long retval = ~0UL;
+	unsigned long retval = task_pt_regs(task)->flags;
+
+	/*
+	 * If the debugger set TF, hide it from the readout.
+	 */
+	if (test_tsk_thread_flag(task, TIF_FORCED_TF))
+		retval &= ~X86_EFLAGS_TF;
 
-	regno >>= 2;
-	switch (regno) {
-	case EFL:
-		/*
-		 * If the debugger set TF, hide it from the readout.
-		 */
-		retval = regs->flags;
-		if (test_tsk_thread_flag(child, TIF_FORCED_TF))
-			retval &= ~X86_EFLAGS_TF;
-		break;
-	case GS:
-		retval = child->thread.gs;
-		if (child == current)
-			savesegment(gs, retval);
-		break;
-	case DS:
-	case ES:
-	case FS:
-	case SS:
-	case CS:
-		retval = 0xffff;
-		/* fall through */
-	default:
-		retval &= *pt_regs_access(regs, regno);
-	}
 	return retval;
 }
 
+static int set_flags(struct task_struct *task, unsigned long value)
+{
+	struct pt_regs *regs = task_pt_regs(task);
+
+	/*
+	 * If the user value contains TF, mark that
+	 * it was not "us" (the debugger) that set it.
+	 * If not, make sure it stays set if we had.
+	 */
+	if (value & X86_EFLAGS_TF)
+		clear_tsk_thread_flag(task, TIF_FORCED_TF);
+	else if (test_tsk_thread_flag(task, TIF_FORCED_TF))
+		value |= X86_EFLAGS_TF;
+
+	regs->flags = (regs->flags & ~FLAG_MASK) | (value & FLAG_MASK);
+
+	return 0;
+}
+
+static int putreg(struct task_struct *child,
+		  unsigned long offset, unsigned long value)
+{
+	switch (offset) {
+	case offsetof(struct user_regs_struct, cs):
+	case offsetof(struct user_regs_struct, ds):
+	case offsetof(struct user_regs_struct, es):
+	case offsetof(struct user_regs_struct, fs):
+	case offsetof(struct user_regs_struct, gs):
+	case offsetof(struct user_regs_struct, ss):
+		return set_segment_reg(child, offset, value);
+
+	case offsetof(struct user_regs_struct, flags):
+		return set_flags(child, value);
+	}
+
+	*pt_regs_access(task_pt_regs(child), offset) = value;
+	return 0;
+}
+
+static unsigned long getreg(struct task_struct *task, unsigned long offset)
+{
+	switch (offset) {
+	case offsetof(struct user_regs_struct, cs):
+	case offsetof(struct user_regs_struct, ds):
+	case offsetof(struct user_regs_struct, es):
+	case offsetof(struct user_regs_struct, fs):
+	case offsetof(struct user_regs_struct, gs):
+	case offsetof(struct user_regs_struct, ss):
+		return get_segment_reg(task, offset);
+
+	case offsetof(struct user_regs_struct, flags):
+		return get_flags(task);
+	}
+
+	return *pt_regs_access(task_pt_regs(task), offset);
+}
+
 /*
  * This function is trivial and will be inlined by the compiler.
  * Having it separates the implementation details of debug

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH x86/mm 05/11] x86 ptrace getreg/putreg merge
  2007-11-29 11:57 [PATCH x86/mm 01/11] x86-32 thread_struct.debugreg Roland McGrath
                   ` (2 preceding siblings ...)
  2007-11-29 11:59 ` [PATCH x86/mm 04/11] x86 ptrace getreg/putreg cleanup Roland McGrath
@ 2007-11-29 11:59 ` Roland McGrath
  2007-11-29 17:27   ` Andrew Morton
  2007-11-29 12:00 ` [PATCH x86/mm 06/11] x86 ptrace arch merge Roland McGrath
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 29+ messages in thread
From: Roland McGrath @ 2007-11-29 11:59 UTC (permalink / raw)
  To: Andrew Morton, Linus Torvalds
  Cc: linux-kernel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin


This merges 64-bit support into the low-level register access
functions in arch/x86/kernel/ptrace.c, paving the way to share
this file between 32-bit and 64-bit builds.

Signed-off-by: Roland McGrath <roland@redhat.com>
---
 arch/x86/kernel/ptrace.c |  215 +++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 211 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index eaec75a..f42f8d2 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -24,6 +24,8 @@
 #include <asm/debugreg.h>
 #include <asm/ldt.h>
 #include <asm/desc.h>
+#include <asm/prctl.h>
+#include <asm/proto.h>
 
 /*
  * does not yet catch signals sent when the child dies.
@@ -40,6 +42,14 @@
 				  X86_EFLAGS_DF | X86_EFLAGS_OF |	\
 				  X86_EFLAGS_RF | X86_EFLAGS_AC))
 
+/*
+ * Determines whether a value may be installed in a segment register.
+ */
+#define invalid_selector(value) \
+	((value) != 0 && ((value) & SEGMENT_RPL_MASK) != USER_RPL)
+
+#ifdef CONFIG_X86_32
+
 #define FLAG_MASK		FLAG_MASK_32
 
 static long *pt_regs_access(struct pt_regs *regs, unsigned long regno)
@@ -73,7 +83,7 @@ static int set_segment_reg(struct task_struct *task,
 	/*
 	 * The value argument was already truncated to 16 bits.
 	 */
-	if (value && (value & 3) != 3)
+	if (invalid_selector(value))
 		return -EIO;
 
 	if (offset != offsetof(struct user_regs_struct, gs))
@@ -91,6 +101,142 @@ static int set_segment_reg(struct task_struct *task,
 	return 0;
 }
 
+static unsigned long debugreg_addr_limit(struct task_struct *task)
+{
+	return TASK_SIZE - 3;
+}
+
+#else  /* CONFIG_X86_64 */
+
+#define FLAG_MASK		(FLAG_MASK_32 | X86_EFLAGS_NT)
+
+static unsigned long *pt_regs_access(struct pt_regs *regs, unsigned long offset)
+{
+	BUILD_BUG_ON(offsetof(struct pt_regs, r15) != 0);
+	return &regs->r15 + (offset / sizeof(regs->r15));
+}
+
+static u16 get_segment_reg(struct task_struct *task, unsigned long offset)
+{
+	/*
+	 * Returning the value truncates it to 16 bits.
+	 */
+	unsigned int seg;
+
+	switch (offset) {
+	case offsetof(struct user_regs_struct, fs):
+		if (task == current) {
+			/* Older gas can't assemble movq %?s,%r?? */
+			asm("movl %%fs,%0" : "=r" (seg));
+			return seg;
+		}
+		return task->thread.fsindex;
+	case offsetof(struct user_regs_struct, gs):
+		if (task == current) {
+			asm("movl %%gs,%0" : "=r" (seg));
+			return seg;
+		}
+		return task->thread.gsindex;
+	case offsetof(struct user_regs_struct, ds):
+		if (task == current) {
+			asm("movl %%ds,%0" : "=r" (seg));
+			return seg;
+		}
+		return task->thread.ds;
+	case offsetof(struct user_regs_struct, es):
+		if (task == current) {
+			asm("movl %%es,%0" : "=r" (seg));
+			return seg;
+		}
+		return task->thread.es;
+
+	case offsetof(struct user_regs_struct, cs):
+	case offsetof(struct user_regs_struct, ss):
+		break;
+	}
+	return *pt_regs_access(task_pt_regs(task), offset);
+}
+
+static int set_segment_reg(struct task_struct *task,
+			   unsigned long offset, u16 value)
+{
+	/*
+	 * The value argument was already truncated to 16 bits.
+	 */
+	if (invalid_selector(value))
+		return -EIO;
+
+	switch (offset) {
+	case offsetof(struct user_regs_struct,fs):
+		/*
+		 * If this is setting fs as for normal 64-bit use but
+		 * setting fs_base has implicitly changed it, leave it.
+		 */
+		if ((value == FS_TLS_SEL && task->thread.fsindex == 0 &&
+		     task->thread.fs != 0) ||
+		    (value == 0 && task->thread.fsindex == FS_TLS_SEL &&
+		     task->thread.fs == 0))
+			break;
+		task->thread.fsindex = value;
+		if (task == current)
+			loadsegment(fs, task->thread.fsindex);
+		break;
+	case offsetof(struct user_regs_struct,gs):
+		/*
+		 * If this is setting gs as for normal 64-bit use but
+		 * setting gs_base has implicitly changed it, leave it.
+		 */
+		if ((value == GS_TLS_SEL && task->thread.gsindex == 0 &&
+		     task->thread.gs != 0) ||
+		    (value == 0 && task->thread.gsindex == GS_TLS_SEL &&
+		     task->thread.gs == 0))
+			break;
+		task->thread.gsindex = value;
+		if (task == current)
+			load_gs_index(task->thread.gsindex);
+		break;
+	case offsetof(struct user_regs_struct,ds):
+		task->thread.ds = value;
+		if (task == current)
+			loadsegment(ds, task->thread.ds);
+		break;
+	case offsetof(struct user_regs_struct,es):
+		task->thread.es = value;
+		if (task == current)
+			loadsegment(es, task->thread.es);
+		break;
+
+		/*
+		 * Can't actually change these in 64-bit mode.
+		 */
+	case offsetof(struct user_regs_struct,cs):
+#ifdef CONFIG_IA32_EMULATION
+		if (test_tsk_thread_flag(task, TIF_IA32))
+			task_pt_regs(task)->cs = value;
+		break;
+#endif
+	case offsetof(struct user_regs_struct,ss):
+#ifdef CONFIG_IA32_EMULATION
+		if (test_tsk_thread_flag(task, TIF_IA32))
+			task_pt_regs(task)->ss = value;
+		break;
+#endif
+	}
+
+	return 0;
+}
+
+static unsigned long debugreg_addr_limit(struct task_struct *task)
+{
+#ifdef CONFIG_IA32_EMULATION
+	if (test_tsk_thread_flag(task, TIF_IA32))
+		return IA32_PAGE_OFFSET - 3;
+#endif
+	return TASK_SIZE64 - 7;
+}
+
+#endif	/* CONFIG_X86_32 */
+
 static unsigned long get_flags(struct task_struct *task)
 {
 	unsigned long retval = task_pt_regs(task)->flags;
@@ -137,6 +283,29 @@ static int putreg(struct task_struct *child,
 
 	case offsetof(struct user_regs_struct, flags):
 		return set_flags(child, value);
+
+#ifdef CONFIG_X86_64
+	case offsetof(struct user_regs_struct,fs_base):
+		if (value >= TASK_SIZE_OF(child))
+			return -EIO;
+		/*
+		 * When changing the segment base, use do_arch_prctl
+		 * to set either thread.fs or thread.fsindex and the
+		 * corresponding GDT slot.
+		 */
+		if (child->thread.fs != value)
+			return do_arch_prctl(child, ARCH_SET_FS, value);
+		return 0;
+	case offsetof(struct user_regs_struct,gs_base):
+		/*
+		 * Exactly the same here as the %fs handling above.
+		 */
+		if (value >= TASK_SIZE_OF(child))
+			return -EIO;
+		if (child->thread.gs != value)
+			return do_arch_prctl(child, ARCH_SET_GS, value);
+		return 0;
+#endif
 	}
 
 	*pt_regs_access(task_pt_regs(child), offset) = value;
@@ -156,6 +325,37 @@ static unsigned long getreg(struct task_struct *task, unsigned long offset)
 
 	case offsetof(struct user_regs_struct, flags):
 		return get_flags(task);
+
+#ifdef CONFIG_X86_64
+	case offsetof(struct user_regs_struct, fs_base): {
+		/*
+		 * do_arch_prctl may have used a GDT slot instead of
+		 * the MSR.  To userland, it appears the same either
+		 * way, except the %fs segment selector might not be 0.
+		 */
+		unsigned int seg = task->thread.fsindex;
+		if (task->thread.fs != 0)
+			return task->thread.fs;
+		if (task == current)
+			asm("movl %%fs,%0" : "=r" (seg));
+		if (seg != FS_TLS_SEL)
+			return 0;
+		return get_desc_base(&task->thread.tls_array[FS_TLS]);
+	}
+	case offsetof(struct user_regs_struct, gs_base): {
+		/*
+		 * Exactly the same here as the %fs handling above.
+		 */
+		unsigned int seg = task->thread.gsindex;
+		if (task->thread.gs != 0)
+			return task->thread.gs;
+		if (task == current)
+			asm("movl %%gs,%0" : "=r" (seg));
+		if (seg != GS_TLS_SEL)
+			return 0;
+		return get_desc_base(&task->thread.tls_array[GS_TLS]);
+	}
+#endif
 	}
 
 	return *pt_regs_access(task_pt_regs(task), offset);
@@ -187,7 +387,7 @@ static int ptrace_set_debugreg(struct task_struct *child,
 	if (unlikely(n == 4 || n == 5))
 		return -EIO;
 
-	if (n < 4 && unlikely(data >= TASK_SIZE - 3))
+	if (n < 4 && unlikely(data >= debugreg_addr_limit(child)))
 		return -EIO;
 
 	switch (n) {
@@ -197,6 +397,8 @@ static int ptrace_set_debugreg(struct task_struct *child,
 	case 3:		child->thread.debugreg3 = data; break;
 
 	case 6:
+		if ((data & ~0xffffffffUL) != 0)
+			return -EIO;
 		child->thread.debugreg6 = data;
 		break;
 
@@ -215,7 +417,7 @@ static int ptrace_set_debugreg(struct task_struct *child,
 		 * data in the watchpoint case.
 		 *
 		 * The invalid values are:
-		 * - LENi == 0x10 (undefined), so mask |= 0x0f00.
+		 * - LENi == 0x10 (undefined), so mask |= 0x0f00.	[32-bit]
 		 * - R/Wi == 0x10 (break on I/O reads or writes), so
 		 *   mask |= 0x4444.
 		 * - R/Wi == 0x00 && LENi != 0x00, so we have mask |=
@@ -231,9 +433,14 @@ static int ptrace_set_debugreg(struct task_struct *child,
 		 * 64-bit kernel), so the x86_64 mask value is 0x5454.
 		 * See the AMD manual no. 24593 (AMD64 System Programming)
 		 */
+#ifdef CONFIG_X86_32
+#define	DR7_MASK	0x5f54
+#else
+#define	DR7_MASK	0x5554
+#endif
 		data &= ~DR_CONTROL_RESERVED;
 		for (i = 0; i < 4; i++)
-			if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
+			if ((DR7_MASK >> ((data >> (16 + 4*i)) & 0xf)) & 1)
 				return -EIO;
 		child->thread.debugreg7 = data;
 		if (data)

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH x86/mm 06/11] x86 ptrace arch merge
  2007-11-29 11:57 [PATCH x86/mm 01/11] x86-32 thread_struct.debugreg Roland McGrath
                   ` (3 preceding siblings ...)
  2007-11-29 11:59 ` [PATCH x86/mm 05/11] x86 ptrace getreg/putreg merge Roland McGrath
@ 2007-11-29 12:00 ` Roland McGrath
  2007-11-29 17:28   ` Andrew Morton
  2007-11-29 12:00 ` [PATCH x86/mm 07/11] x86 ptrace merge syscall trace Roland McGrath
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 29+ messages in thread
From: Roland McGrath @ 2007-11-29 12:00 UTC (permalink / raw)
  To: Andrew Morton, Linus Torvalds
  Cc: linux-kernel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin


This adds 64-bit support to arch_ptrace in arch/x86/kernel/ptrace.c,
so this function can be used for native ptrace on both 32 and 64.

Signed-off-by: Roland McGrath <roland@redhat.com>
---
 arch/x86/kernel/ptrace.c |   65 ++++++++++++++++++++++++---------------------
 1 files changed, 35 insertions(+), 30 deletions(-)

diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index f42f8d2..f4355f3 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -461,12 +461,13 @@ static int ptrace_set_debugreg(struct task_struct *child,
 void ptrace_disable(struct task_struct *child)
 {
 	user_disable_single_step(child);
+#ifdef TIF_SYSCALL_EMU
 	clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+#endif
 }
 
 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 {
-	struct user * dummy = NULL;
 	int i, ret;
 	unsigned long __user *datap = (unsigned long __user *)data;
 
@@ -482,18 +483,17 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 		unsigned long tmp;
 
 		ret = -EIO;
-		if ((addr & 3) || addr < 0 ||
-		    addr > sizeof(struct user) - 3)
+		if ((addr & (sizeof(data) - 1)) || addr < 0 ||
+		    addr >= sizeof(struct user))
 			break;
 
 		tmp = 0;  /* Default return condition */
-		if(addr < FRAME_SIZE*sizeof(long))
+		if (addr < sizeof(struct user_regs_struct))
 			tmp = getreg(child, addr);
-		if(addr >= (long) &dummy->u_debugreg[0] &&
-		   addr <= (long) &dummy->u_debugreg[7]){
-			addr -= (long) &dummy->u_debugreg[0];
-			addr = addr >> 2;
-			tmp = ptrace_get_debugreg(child, addr);
+		else if (addr >= offsetof(struct user, u_debugreg[0]) &&
+			 addr <= offsetof(struct user, u_debugreg[7])) {
+			addr -= offsetof(struct user, u_debugreg[0]);
+			tmp = ptrace_get_debugreg(child, addr / sizeof(data));
 		}
 		ret = put_user(tmp, datap);
 		break;
@@ -507,34 +507,26 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 
 	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
 		ret = -EIO;
-		if ((addr & 3) || addr < 0 ||
-		    addr > sizeof(struct user) - 3)
+		if ((addr & (sizeof(data) - 1)) || addr < 0 ||
+		    addr >= sizeof(struct user))
 			break;
 
-		if (addr < FRAME_SIZE*sizeof(long)) {
+		if (addr < sizeof(struct user_regs_struct))
 			ret = putreg(child, addr, data);
-			break;
+		else if (addr >= offsetof(struct user, u_debugreg[0]) &&
+			 addr <= offsetof(struct user, u_debugreg[7])) {
+			addr -= offsetof(struct user, u_debugreg[0]);
+			ret = ptrace_set_debugreg(child,
+						  addr / sizeof(data), data);
 		}
-		/* We need to be very careful here.  We implicitly
-		   want to modify a portion of the task_struct, and we
-		   have to be selective about what portions we allow someone
-		   to modify. */
-
-		  ret = -EIO;
-		  if(addr >= (long) &dummy->u_debugreg[0] &&
-		     addr <= (long) &dummy->u_debugreg[7]){
-			  addr -= (long) &dummy->u_debugreg;
-			  addr = addr >> 2;
-			  ret = ptrace_set_debugreg(child, addr, data);
-		  }
-		  break;
+		break;
 
 	case PTRACE_GETREGS: { /* Get all gp regs from the child. */
-	  	if (!access_ok(VERIFY_WRITE, datap, FRAME_SIZE*sizeof(long))) {
+		if (!access_ok(VERIFY_WRITE, datap, sizeof(struct user_regs_struct))) {
 			ret = -EIO;
 			break;
 		}
-		for ( i = 0; i < FRAME_SIZE*sizeof(long); i += sizeof(long) ) {
+		for (i = 0; i < sizeof(struct user_regs_struct); i += sizeof(long)) {
 			__put_user(getreg(child, i), datap);
 			datap++;
 		}
@@ -544,11 +536,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 
 	case PTRACE_SETREGS: { /* Set all gp regs in the child. */
 		unsigned long tmp;
-	  	if (!access_ok(VERIFY_READ, datap, FRAME_SIZE*sizeof(long))) {
+		if (!access_ok(VERIFY_READ, datap, sizeof(struct user_regs_struct))) {
 			ret = -EIO;
 			break;
 		}
-		for ( i = 0; i < FRAME_SIZE*sizeof(long); i += sizeof(long) ) {
+		for (i = 0; i < sizeof(struct user_regs_struct); i += sizeof(long)) {
 			__get_user(tmp, datap);
 			putreg(child, i, tmp);
 			datap++;
@@ -582,6 +574,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 		break;
 	}
 
+#ifdef CONFIG_X86_32
 	case PTRACE_GETFPXREGS: { /* Get the child extended FPU state. */
 		if (!access_ok(VERIFY_WRITE, datap,
 			       sizeof(struct user_fxsr_struct))) {
@@ -604,7 +597,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 		ret = set_fpxregs(child, (struct user_fxsr_struct __user *)data);
 		break;
 	}
+#endif
 
+#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
 	case PTRACE_GET_THREAD_AREA:
 		if (addr < 0)
 			return -EIO;
@@ -618,6 +613,16 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 		ret = do_set_thread_area(child, addr,
 					 (struct user_desc __user *) data, 0);
 		break;
+#endif
+
+#ifdef CONFIG_X86_64
+		/* normal 64bit interface to access TLS data.
+		   Works just like arch_prctl, except that the arguments
+		   are reversed. */
+	case PTRACE_ARCH_PRCTL:
+		ret = do_arch_prctl(child, data, addr);
+		break;
+#endif
 
 	default:
 		ret = ptrace_request(child, request, addr, data);

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH x86/mm 07/11] x86 ptrace merge syscall trace
  2007-11-29 11:57 [PATCH x86/mm 01/11] x86-32 thread_struct.debugreg Roland McGrath
                   ` (4 preceding siblings ...)
  2007-11-29 12:00 ` [PATCH x86/mm 06/11] x86 ptrace arch merge Roland McGrath
@ 2007-11-29 12:00 ` Roland McGrath
  2007-11-29 12:00 ` [PATCH x86/mm 08/11] x86 ia32 ptrace getreg/putreg merge Roland McGrath
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 29+ messages in thread
From: Roland McGrath @ 2007-11-29 12:00 UTC (permalink / raw)
  To: Andrew Morton, Linus Torvalds
  Cc: linux-kernel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin


This moves the 64-bit syscall tracing functions into ptrace.c,
so that ptrace_64.c becomes entirely obsolete.

Signed-off-by: Roland McGrath <roland@redhat.com>
---
 arch/x86/kernel/ptrace.c |   64 ++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 64 insertions(+), 0 deletions(-)

diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index f4355f3..2eac631 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -632,6 +632,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 	return ret;
 }
 
+#ifdef CONFIG_X86_32
+
 void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)
 {
 	struct siginfo info;
@@ -729,3 +731,65 @@ out:
 		audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax);
 	return 1;
 }
+
+#else  /* CONFIG_X86_64 */
+
+static void syscall_trace(struct pt_regs *regs)
+{
+
+#if 0
+	printk("trace %s ip %lx sp %lx ax %d origrax %d caller %lx tiflags %x ptrace %x\n",
+	       current->comm,
+	       regs->ip, regs->sp, regs->ax, regs->orig_ax, __builtin_return_address(0),
+	       current_thread_info()->flags, current->ptrace);
+#endif
+
+	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+				? 0x80 : 0));
+	/*
+	 * this isn't the same as continuing with a signal, but it will do
+	 * for normal use.  strace only continues with a signal if the
+	 * stopping signal is not SIGTRAP.  -brl
+	 */
+	if (current->exit_code) {
+		send_sig(current->exit_code, current, 1);
+		current->exit_code = 0;
+	}
+}
+
+asmlinkage void syscall_trace_enter(struct pt_regs *regs)
+{
+	/* do the secure computing check first */
+	secure_computing(regs->orig_ax);
+
+	if (test_thread_flag(TIF_SYSCALL_TRACE)
+	    && (current->ptrace & PT_PTRACED))
+		syscall_trace(regs);
+
+	if (unlikely(current->audit_context)) {
+		if (test_thread_flag(TIF_IA32)) {
+			audit_syscall_entry(AUDIT_ARCH_I386,
+					    regs->orig_ax,
+					    regs->bx, regs->cx,
+					    regs->dx, regs->si);
+		} else {
+			audit_syscall_entry(AUDIT_ARCH_X86_64,
+					    regs->orig_ax,
+					    regs->di, regs->si,
+					    regs->dx, regs->r10);
+		}
+	}
+}
+
+asmlinkage void syscall_trace_leave(struct pt_regs *regs)
+{
+	if (unlikely(current->audit_context))
+		audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax);
+
+	if ((test_thread_flag(TIF_SYSCALL_TRACE)
+	     || test_thread_flag(TIF_SINGLESTEP))
+	    && (current->ptrace & PT_PTRACED))
+		syscall_trace(regs);
+}
+
+#endif	/* CONFIG_X86_32 */

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH x86/mm 08/11] x86 ia32 ptrace getreg/putreg merge
  2007-11-29 11:57 [PATCH x86/mm 01/11] x86-32 thread_struct.debugreg Roland McGrath
                   ` (5 preceding siblings ...)
  2007-11-29 12:00 ` [PATCH x86/mm 07/11] x86 ptrace merge syscall trace Roland McGrath
@ 2007-11-29 12:00 ` Roland McGrath
  2007-11-29 17:37   ` Christoph Hellwig
  2007-11-29 12:00 ` [PATCH x86/mm 09/11] x86 ia32 ptrace arch merge Roland McGrath
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 29+ messages in thread
From: Roland McGrath @ 2007-11-29 12:00 UTC (permalink / raw)
  To: Andrew Morton, Linus Torvalds
  Cc: linux-kernel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin


This reimplements the 64-bit IA32-emulation register access
functions in arch/x86/kernel/ptrace.c, where they can share
some guts with the native access functions directly.

These functions are not used yet, but this paves the way to move
IA32 ptrace support into this file to share its local functions.

Signed-off-by: Roland McGrath <roland@redhat.com>
---
 arch/x86/kernel/ptrace.c |  126 ++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 126 insertions(+), 0 deletions(-)

diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 2eac631..bac5058 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -632,6 +632,132 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 	return ret;
 }
 
+#ifdef CONFIG_IA32_EMULATION
+
+#include <asm/user32.h>
+
+#define R32(l,q)							\
+	case offsetof(struct user32, regs.l):				\
+		regs->q = value; break
+
+#define SEG32(rs)							\
+	case offsetof(struct user32, regs.rs):				\
+		return set_segment_reg(child,				\
+				       offsetof(struct user_regs_struct, rs), \
+				       value);				\
+		break
+
+static int putreg32(struct task_struct *child, unsigned regno, u32 value)
+{
+	struct pt_regs *regs = task_pt_regs(child);
+
+	switch (regno) {
+
+	SEG32(cs);
+	SEG32(ds);
+	SEG32(es);
+	SEG32(fs);
+	SEG32(gs);
+	SEG32(ss);
+
+	R32(ebx, bx);
+	R32(ecx, cx);
+	R32(edx, dx);
+	R32(edi, di);
+	R32(esi, si);
+	R32(ebp, bp);
+	R32(eax, ax);
+	R32(orig_eax, orig_ax);
+	R32(eip, ip);
+	R32(esp, sp);
+
+	case offsetof(struct user32, regs.eflags):
+		return set_flags(child, value);
+
+	case offsetof(struct user32, u_debugreg[0]) ...
+		offsetof(struct user32, u_debugreg[7]):
+		regno -= offsetof(struct user32, u_debugreg[0]);
+		return ptrace_set_debugreg(child, regno / 4, value);
+
+	default:
+		if (regno > sizeof(struct user32) || (regno & 3))
+			return -EIO;
+
+		/*
+		 * Other dummy fields in the virtual user structure
+		 * are ignored
+		 */
+		break;
+	}
+	return 0;
+}
+
+#undef R32
+#undef SEG32
+
+#define R32(l,q)							\
+	case offsetof(struct user32, regs.l):				\
+		*val = regs->q; break
+
+#define SEG32(rs)							\
+	case offsetof(struct user32, regs.rs):				\
+		*val = get_segment_reg(child,				\
+				       offsetof(struct user_regs_struct, rs)); \
+		break
+
+static int getreg32(struct task_struct *child, unsigned regno, u32 *val)
+{
+	struct pt_regs *regs = task_pt_regs(child);
+
+	switch (regno) {
+
+	SEG32(ds);
+	SEG32(es);
+	SEG32(fs);
+	SEG32(gs);
+
+	R32(cs, cs);
+	R32(ss, ss);
+	R32(ebx, bx);
+	R32(ecx, cx);
+	R32(edx, dx);
+	R32(edi, di);
+	R32(esi, si);
+	R32(ebp, bp);
+	R32(eax, ax);
+	R32(orig_eax, orig_ax);
+	R32(eip, ip);
+	R32(esp, sp);
+
+	case offsetof(struct user32, regs.eflags):
+		*val = get_flags(child);
+		break;
+
+	case offsetof(struct user32, u_debugreg[0]) ...
+		offsetof(struct user32, u_debugreg[7]):
+		regno -= offsetof(struct user32, u_debugreg[0]);
+		*val = ptrace_get_debugreg(child, regno / 4);
+		break;
+
+	default:
+		if (regno > sizeof(struct user32) || (regno & 3))
+			return -EIO;
+
+		/*
+		 * Other dummy fields in the virtual user structure
+		 * are ignored
+		 */
+		*val = 0;
+		break;
+	}
+	return 0;
+}
+
+#undef R32
+#undef SEG32
+
+#endif	/* CONFIG_IA32_EMULATION */
+
 #ifdef CONFIG_X86_32
 
 void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH x86/mm 09/11] x86 ia32 ptrace arch merge
  2007-11-29 11:57 [PATCH x86/mm 01/11] x86-32 thread_struct.debugreg Roland McGrath
                   ` (6 preceding siblings ...)
  2007-11-29 12:00 ` [PATCH x86/mm 08/11] x86 ia32 ptrace getreg/putreg merge Roland McGrath
@ 2007-11-29 12:00 ` Roland McGrath
  2007-11-29 20:58   ` Alexey Dobriyan
  2007-11-29 12:00 ` [PATCH x86/mm 10/11] x86 ptrace merge complete Roland McGrath
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 29+ messages in thread
From: Roland McGrath @ 2007-11-29 12:00 UTC (permalink / raw)
  To: Andrew Morton, Linus Torvalds
  Cc: linux-kernel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin


This moves the sys32_ptrace code into arch/x86/kernel/ptrace.c,
verbatim except for a few hard-coded sizes replaced with sizeof.
Here this code can use the shared local functions in this file.

Signed-off-by: Roland McGrath <roland@redhat.com>
---
 arch/x86/kernel/ptrace.c |  214 ++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 214 insertions(+), 0 deletions(-)

diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index bac5058..b3433e1 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -634,6 +634,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 
 #ifdef CONFIG_IA32_EMULATION
 
+#include <linux/compat.h>
+#include <linux/syscalls.h>
+#include <asm/ia32.h>
+#include <asm/fpu32.h>
 #include <asm/user32.h>
 
 #define R32(l,q)							\
@@ -756,6 +760,216 @@ static int getreg32(struct task_struct *child, unsigned regno, u32 *val)
 #undef R32
 #undef SEG32
 
+static long ptrace32_siginfo(unsigned request, u32 pid, u32 addr, u32 data)
+{
+	siginfo_t __user *si = compat_alloc_user_space(sizeof(siginfo_t));
+	compat_siginfo_t __user *si32 = compat_ptr(data);
+	siginfo_t ssi;
+	int ret;
+
+	if (request == PTRACE_SETSIGINFO) {
+		memset(&ssi, 0, sizeof(siginfo_t));
+		ret = copy_siginfo_from_user32(&ssi, si32);
+		if (ret)
+			return ret;
+		if (copy_to_user(si, &ssi, sizeof(siginfo_t)))
+			return -EFAULT;
+	}
+	ret = sys_ptrace(request, pid, addr, (unsigned long)si);
+	if (ret)
+		return ret;
+	if (request == PTRACE_GETSIGINFO) {
+		if (copy_from_user(&ssi, si, sizeof(siginfo_t)))
+			return -EFAULT;
+		ret = copy_siginfo_to_user32(si32, &ssi);
+	}
+	return ret;
+}
+
+asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
+{
+	struct task_struct *child;
+	struct pt_regs *childregs;
+	void __user *datap = compat_ptr(data);
+	int ret;
+	__u32 val;
+
+	switch (request) {
+	case PTRACE_TRACEME:
+	case PTRACE_ATTACH:
+	case PTRACE_KILL:
+	case PTRACE_CONT:
+	case PTRACE_SINGLESTEP:
+	case PTRACE_SINGLEBLOCK:
+	case PTRACE_DETACH:
+	case PTRACE_SYSCALL:
+	case PTRACE_OLDSETOPTIONS:
+	case PTRACE_SETOPTIONS:
+	case PTRACE_SET_THREAD_AREA:
+	case PTRACE_GET_THREAD_AREA:
+		return sys_ptrace(request, pid, addr, data);
+
+	default:
+		return -EINVAL;
+
+	case PTRACE_PEEKTEXT:
+	case PTRACE_PEEKDATA:
+	case PTRACE_POKEDATA:
+	case PTRACE_POKETEXT:
+	case PTRACE_POKEUSR:
+	case PTRACE_PEEKUSR:
+	case PTRACE_GETREGS:
+	case PTRACE_SETREGS:
+	case PTRACE_SETFPREGS:
+	case PTRACE_GETFPREGS:
+	case PTRACE_SETFPXREGS:
+	case PTRACE_GETFPXREGS:
+	case PTRACE_GETEVENTMSG:
+		break;
+
+	case PTRACE_SETSIGINFO:
+	case PTRACE_GETSIGINFO:
+		return ptrace32_siginfo(request, pid, addr, data);
+	}
+
+	child = ptrace_get_task_struct(pid);
+	if (IS_ERR(child))
+		return PTR_ERR(child);
+
+	ret = ptrace_check_attach(child, request == PTRACE_KILL);
+	if (ret < 0)
+		goto out;
+
+	childregs = task_pt_regs(child);
+
+	switch (request) {
+	case PTRACE_PEEKDATA:
+	case PTRACE_PEEKTEXT:
+		ret = 0;
+		if (access_process_vm(child, addr, &val, sizeof(u32), 0) !=
+		    sizeof(u32))
+			ret = -EIO;
+		else
+			ret = put_user(val, (unsigned int __user *)datap);
+		break;
+
+	case PTRACE_POKEDATA:
+	case PTRACE_POKETEXT:
+		ret = 0;
+		if (access_process_vm(child, addr, &data, sizeof(u32), 1) !=
+		    sizeof(u32))
+			ret = -EIO;
+		break;
+
+	case PTRACE_PEEKUSR:
+		ret = getreg32(child, addr, &val);
+		if (ret == 0)
+			ret = put_user(val, (__u32 __user *)datap);
+		break;
+
+	case PTRACE_POKEUSR:
+		ret = putreg32(child, addr, data);
+		break;
+
+	case PTRACE_GETREGS: { /* Get all gp regs from the child. */
+		int i;
+
+		if (!access_ok(VERIFY_WRITE, datap, 16*4)) {
+			ret = -EIO;
+			break;
+		}
+		ret = 0;
+		for (i = 0; i < sizeof(struct user_regs_struct32); i += sizeof(__u32)) {
+			getreg32(child, i, &val);
+			ret |= __put_user(val, (u32 __user *)datap);
+			datap += sizeof(u32);
+		}
+		break;
+	}
+
+	case PTRACE_SETREGS: { /* Set all gp regs in the child. */
+		unsigned long tmp;
+		int i;
+
+		if (!access_ok(VERIFY_READ, datap, 16*4)) {
+			ret = -EIO;
+			break;
+		}
+		ret = 0;
+		for (i = 0; i < sizeof(struct user_regs_struct32); i += sizeof(u32)) {
+			ret |= __get_user(tmp, (u32 __user *)datap);
+			putreg32(child, i, tmp);
+			datap += sizeof(u32);
+		}
+		break;
+	}
+
+	case PTRACE_GETFPREGS:
+		ret = -EIO;
+		if (!access_ok(VERIFY_READ, compat_ptr(data),
+			       sizeof(struct user_i387_struct)))
+			break;
+		save_i387_ia32(child, datap, childregs, 1);
+		ret = 0;
+			break;
+
+	case PTRACE_SETFPREGS:
+		ret = -EIO;
+		if (!access_ok(VERIFY_WRITE, datap,
+			       sizeof(struct user_i387_struct)))
+			break;
+		ret = 0;
+		/* don't check EFAULT to be bug-to-bug compatible to i386 */
+		restore_i387_ia32(child, datap, 1);
+		break;
+
+	case PTRACE_GETFPXREGS: {
+		struct user32_fxsr_struct __user *u = datap;
+
+		init_fpu(child);
+		ret = -EIO;
+		if (!access_ok(VERIFY_WRITE, u, sizeof(*u)))
+			break;
+			ret = -EFAULT;
+		if (__copy_to_user(u, &child->thread.i387.fxsave, sizeof(*u)))
+			break;
+		ret = __put_user(childregs->cs, &u->fcs);
+		ret |= __put_user(child->thread.ds, &u->fos);
+		break;
+	}
+	case PTRACE_SETFPXREGS: {
+		struct user32_fxsr_struct __user *u = datap;
+
+		unlazy_fpu(child);
+		ret = -EIO;
+		if (!access_ok(VERIFY_READ, u, sizeof(*u)))
+			break;
+		/*
+		 * no checking to be bug-to-bug compatible with i386.
+		 * but silence warning
+		 */
+		if (__copy_from_user(&child->thread.i387.fxsave, u, sizeof(*u)))
+			;
+		set_stopped_child_used_math(child);
+		child->thread.i387.fxsave.mxcsr &= mxcsr_feature_mask;
+		ret = 0;
+		break;
+	}
+
+	case PTRACE_GETEVENTMSG:
+		ret = put_user(child->ptrace_message,
+			       (unsigned int __user *)compat_ptr(data));
+		break;
+
+	default:
+		BUG();
+	}
+
+ out:
+	put_task_struct(child);
+	return ret;
+}
+
 #endif	/* CONFIG_IA32_EMULATION */
 
 #ifdef CONFIG_X86_32

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH x86/mm 10/11] x86 ptrace merge complete
  2007-11-29 11:57 [PATCH x86/mm 01/11] x86-32 thread_struct.debugreg Roland McGrath
                   ` (7 preceding siblings ...)
  2007-11-29 12:00 ` [PATCH x86/mm 09/11] x86 ia32 ptrace arch merge Roland McGrath
@ 2007-11-29 12:00 ` Roland McGrath
  2007-11-29 12:00 ` [PATCH x86/mm 11/11] x86 ptrace merge removals Roland McGrath
  2007-11-29 12:23 ` [PATCH x86/mm 01/11] x86-32 thread_struct.debugreg Ingo Molnar
  10 siblings, 0 replies; 29+ messages in thread
From: Roland McGrath @ 2007-11-29 12:00 UTC (permalink / raw)
  To: Andrew Morton, Linus Torvalds
  Cc: linux-kernel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin


This switches over the 64-bit build to use the shared ptrace code,
instead of the old ptrace_64.c and arch/x86/ia32/ptrace32.c code.

Signed-off-by: Roland McGrath <roland@redhat.com>
---
 arch/x86/ia32/Makefile      |    2 +-
 arch/x86/kernel/Makefile_64 |    3 ++-
 include/asm-x86/ptrace.h    |    3 ---
 3 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/arch/x86/ia32/Makefile b/arch/x86/ia32/Makefile
index ea60886..ec71cfe 100644
--- a/arch/x86/ia32/Makefile
+++ b/arch/x86/ia32/Makefile
@@ -3,7 +3,7 @@
 #
 
 obj-$(CONFIG_IA32_EMULATION) := ia32entry.o sys_ia32.o ia32_signal.o \
-	ia32_binfmt.o fpu32.o ptrace32.o
+	ia32_binfmt.o fpu32.o
 
 sysv-$(CONFIG_SYSVIPC) := ipc32.o
 obj-$(CONFIG_IA32_EMULATION) += $(sysv-y)
diff --git a/arch/x86/kernel/Makefile_64 b/arch/x86/kernel/Makefile_64
index d8d0a28..8c24601 100644
--- a/arch/x86/kernel/Makefile_64
+++ b/arch/x86/kernel/Makefile_64
@@ -7,12 +7,13 @@ CPPFLAGS_vmlinux.lds += -Ux86_64
 EXTRA_AFLAGS	:= -traditional
 
 obj-y	:= process_64.o signal_64.o entry_64.o traps_64.o irq_64.o \
-		ptrace_64.o time_64.o ioport_64.o ldt.o setup_64.o i8259_64.o sys_x86_64.o \
+		time_64.o ioport_64.o ldt.o setup_64.o i8259_64.o sys_x86_64.o \
 		x8664_ksyms_64.o i387_64.o syscall_64.o vsyscall_64.o \
 		setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \
 		pci-dma_64.o pci-nommu_64.o alternative.o hpet.o tsc_64.o bugs_64.o \
 		i8253.o rtc.o
 
+obj-y				+= ptrace.o
 obj-y				+= step.o
 
 obj-$(CONFIG_IA32_EMULATION)	+= tls.o
diff --git a/include/asm-x86/ptrace.h b/include/asm-x86/ptrace.h
index 1b7a8b8..9228870 100644
--- a/include/asm-x86/ptrace.h
+++ b/include/asm-x86/ptrace.h
@@ -164,9 +164,6 @@ void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
 
 struct task_struct;
 
-extern unsigned long ptrace_get_debugreg(struct task_struct *child, int n);
-extern int ptrace_set_debugreg(struct task_struct *child, int n, unsigned long);
-
 extern unsigned long
 convert_rip_to_linear(struct task_struct *child, struct pt_regs *regs);
 

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH x86/mm 11/11] x86 ptrace merge removals
  2007-11-29 11:57 [PATCH x86/mm 01/11] x86-32 thread_struct.debugreg Roland McGrath
                   ` (8 preceding siblings ...)
  2007-11-29 12:00 ` [PATCH x86/mm 10/11] x86 ptrace merge complete Roland McGrath
@ 2007-11-29 12:00 ` Roland McGrath
  2007-11-29 14:04   ` Jeff Dike
  2007-11-29 12:23 ` [PATCH x86/mm 01/11] x86-32 thread_struct.debugreg Ingo Molnar
  10 siblings, 1 reply; 29+ messages in thread
From: Roland McGrath @ 2007-11-29 12:00 UTC (permalink / raw)
  To: Andrew Morton, Linus Torvalds
  Cc: linux-kernel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin


This removes the old separate 64-bit and ia32 ptrace source files.
They are no longer used.

Signed-off-by: Roland McGrath <roland@redhat.com>
---
 arch/x86/ia32/ptrace32.c    |  411 -------------------------------------
 arch/x86/kernel/ptrace_64.c |  470 -------------------------------------------
 2 files changed, 0 insertions(+), 881 deletions(-)

diff --git a/arch/x86/ia32/ptrace32.c b/arch/x86/ia32/ptrace32.c
deleted file mode 100644
index d5663e2..0000000
--- a/arch/x86/ia32/ptrace32.c
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * 32bit ptrace for x86-64.
- *
- * Copyright 2001,2002 Andi Kleen, SuSE Labs.
- * Some parts copied from arch/i386/kernel/ptrace.c. See that file for earlier
- * copyright.
- *
- * This allows to access 64bit processes too; but there is no way to
- * see the extended register contents.
- */
-
-#include <linux/kernel.h>
-#include <linux/stddef.h>
-#include <linux/sched.h>
-#include <linux/syscalls.h>
-#include <linux/unistd.h>
-#include <linux/mm.h>
-#include <linux/err.h>
-#include <linux/ptrace.h>
-#include <asm/ptrace.h>
-#include <asm/compat.h>
-#include <asm/uaccess.h>
-#include <asm/user32.h>
-#include <asm/user.h>
-#include <asm/errno.h>
-#include <asm/debugreg.h>
-#include <asm/i387.h>
-#include <asm/fpu32.h>
-#include <asm/ia32.h>
-
-/*
- * Determines which flags the user has access to [1 = access, 0 = no access].
- * Prohibits changing ID(21), VIP(20), VIF(19), VM(17), IOPL(12-13), IF(9).
- * Also masks reserved bits (31-22, 15, 5, 3, 1).
- */
-#define FLAG_MASK 0x54dd5UL
-
-#define R32(l,q)							\
-	case offsetof(struct user32, regs.l):				\
-		regs->q = val; break;
-
-static int putreg32(struct task_struct *child, unsigned regno, u32 val)
-{
-	struct pt_regs *regs = task_pt_regs(child);
-
-	switch (regno) {
-	case offsetof(struct user32, regs.fs):
-		if (val && (val & 3) != 3)
-			return -EIO;
-		child->thread.fsindex = val & 0xffff;
-		if (child == current)
-			loadsegment(fs, child->thread.fsindex);
-		break;
-	case offsetof(struct user32, regs.gs):
-		if (val && (val & 3) != 3)
-			return -EIO;
-		child->thread.gsindex = val & 0xffff;
-		if (child == current)
-			load_gs_index(child->thread.gsindex);
-		break;
-	case offsetof(struct user32, regs.ds):
-		if (val && (val & 3) != 3)
-			return -EIO;
-		child->thread.ds = val & 0xffff;
-		if (child == current)
-			loadsegment(ds, child->thread.ds);
-		break;
-	case offsetof(struct user32, regs.es):
-		child->thread.es = val & 0xffff;
-		if (child == current)
-			loadsegment(es, child->thread.ds);
-		break;
-	case offsetof(struct user32, regs.ss):
-		if ((val & 3) != 3)
-			return -EIO;
-		regs->ss = val & 0xffff;
-		break;
-	case offsetof(struct user32, regs.cs):
-		if ((val & 3) != 3)
-			return -EIO;
-		regs->cs = val & 0xffff;
-		break;
-
-	R32(ebx, bx);
-	R32(ecx, cx);
-	R32(edx, dx);
-	R32(edi, di);
-	R32(esi, si);
-	R32(ebp, bp);
-	R32(eax, ax);
-	R32(orig_eax, orig_ax);
-	R32(eip, ip);
-	R32(esp, sp);
-
-	case offsetof(struct user32, regs.eflags):
-		val &= FLAG_MASK;
-		/*
-		 * If the user value contains TF, mark that
-		 * it was not "us" (the debugger) that set it.
-		 * If not, make sure it stays set if we had.
-		 */
-		if (val & X86_EFLAGS_TF)
-			clear_tsk_thread_flag(child, TIF_FORCED_TF);
-		else if (test_tsk_thread_flag(child, TIF_FORCED_TF))
-			val |= X86_EFLAGS_TF;
-		regs->flags = val | (regs->flags & ~FLAG_MASK);
-		break;
-
-	case offsetof(struct user32, u_debugreg[0]) ...
-		offsetof(struct user32, u_debugreg[7]):
-		regno -= offsetof(struct user32, u_debugreg[0]);
-		return ptrace_set_debugreg(child, regno / 4, val);
-
-	default:
-		if (regno > sizeof(struct user32) || (regno & 3))
-			return -EIO;
-
-		/*
-		 * Other dummy fields in the virtual user structure
-		 * are ignored
-		 */
-		break;
-	}
-	return 0;
-}
-
-#undef R32
-
-#define R32(l,q)							\
-	case offsetof(struct user32, regs.l):				\
-		*val = regs->q; break
-
-static int getreg32(struct task_struct *child, unsigned regno, u32 *val)
-{
-	struct pt_regs *regs = task_pt_regs(child);
-
-	switch (regno) {
-	case offsetof(struct user32, regs.fs):
-		*val = child->thread.fsindex;
-		if (child == current)
-			asm("movl %%fs,%0" : "=r" (*val));
-		break;
-	case offsetof(struct user32, regs.gs):
-		*val = child->thread.gsindex;
-		if (child == current)
-			asm("movl %%gs,%0" : "=r" (*val));
-		break;
-	case offsetof(struct user32, regs.ds):
-		*val = child->thread.ds;
-		if (child == current)
-			asm("movl %%ds,%0" : "=r" (*val));
-		break;
-	case offsetof(struct user32, regs.es):
-		*val = child->thread.es;
-		if (child == current)
-			asm("movl %%es,%0" : "=r" (*val));
-		break;
-
-	R32(cs, cs);
-	R32(ss, ss);
-	R32(ebx, bx);
-	R32(ecx, cx);
-	R32(edx, dx);
-	R32(edi, di);
-	R32(esi, si);
-	R32(ebp, bp);
-	R32(eax, ax);
-	R32(orig_eax, orig_ax);
-	R32(eip, ip);
-	R32(esp, sp);
-
-	case offsetof(struct user32, regs.eflags):
-		/*
-		 * If the debugger set TF, hide it from the readout.
-		 */
-		*val = regs->flags;
-		if (test_tsk_thread_flag(child, TIF_FORCED_TF))
-			*val &= ~X86_EFLAGS_TF;
-		break;
-
-	case offsetof(struct user32, u_debugreg[0]) ...
-		offsetof(struct user32, u_debugreg[7]):
-		regno -= offsetof(struct user32, u_debugreg[0]);
-		*val = ptrace_get_debugreg(child, regno / 4);
-		break;
-
-	default:
-		if (regno > sizeof(struct user32) || (regno & 3))
-			return -EIO;
-
-		/*
-		 * Other dummy fields in the virtual user structure
-		 * are ignored
-		 */
-		*val = 0;
-		break;
-	}
-	return 0;
-}
-
-#undef R32
-
-static long ptrace32_siginfo(unsigned request, u32 pid, u32 addr, u32 data)
-{
-	siginfo_t __user *si = compat_alloc_user_space(sizeof(siginfo_t));
-	compat_siginfo_t __user *si32 = compat_ptr(data);
-	siginfo_t ssi;
-	int ret;
-
-	if (request == PTRACE_SETSIGINFO) {
-		memset(&ssi, 0, sizeof(siginfo_t));
-		ret = copy_siginfo_from_user32(&ssi, si32);
-		if (ret)
-			return ret;
-		if (copy_to_user(si, &ssi, sizeof(siginfo_t)))
-			return -EFAULT;
-	}
-	ret = sys_ptrace(request, pid, addr, (unsigned long)si);
-	if (ret)
-		return ret;
-	if (request == PTRACE_GETSIGINFO) {
-		if (copy_from_user(&ssi, si, sizeof(siginfo_t)))
-			return -EFAULT;
-		ret = copy_siginfo_to_user32(si32, &ssi);
-	}
-	return ret;
-}
-
-asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
-{
-	struct task_struct *child;
-	struct pt_regs *childregs;
-	void __user *datap = compat_ptr(data);
-	int ret;
-	__u32 val;
-
-	switch (request) {
-	case PTRACE_TRACEME:
-	case PTRACE_ATTACH:
-	case PTRACE_KILL:
-	case PTRACE_CONT:
-	case PTRACE_SINGLESTEP:
-	case PTRACE_SINGLEBLOCK:
-	case PTRACE_DETACH:
-	case PTRACE_SYSCALL:
-	case PTRACE_OLDSETOPTIONS:
-	case PTRACE_SETOPTIONS:
-	case PTRACE_SET_THREAD_AREA:
-	case PTRACE_GET_THREAD_AREA:
-		return sys_ptrace(request, pid, addr, data);
-
-	default:
-		return -EINVAL;
-
-	case PTRACE_PEEKTEXT:
-	case PTRACE_PEEKDATA:
-	case PTRACE_POKEDATA:
-	case PTRACE_POKETEXT:
-	case PTRACE_POKEUSR:
-	case PTRACE_PEEKUSR:
-	case PTRACE_GETREGS:
-	case PTRACE_SETREGS:
-	case PTRACE_SETFPREGS:
-	case PTRACE_GETFPREGS:
-	case PTRACE_SETFPXREGS:
-	case PTRACE_GETFPXREGS:
-	case PTRACE_GETEVENTMSG:
-		break;
-
-	case PTRACE_SETSIGINFO:
-	case PTRACE_GETSIGINFO:
-		return ptrace32_siginfo(request, pid, addr, data);
-	}
-
-	child = ptrace_get_task_struct(pid);
-	if (IS_ERR(child))
-		return PTR_ERR(child);
-
-	ret = ptrace_check_attach(child, request == PTRACE_KILL);
-	if (ret < 0)
-		goto out;
-
-	childregs = task_pt_regs(child);
-
-	switch (request) {
-	case PTRACE_PEEKDATA:
-	case PTRACE_PEEKTEXT:
-		ret = 0;
-		if (access_process_vm(child, addr, &val, sizeof(u32), 0) !=
-		    sizeof(u32))
-			ret = -EIO;
-		else
-			ret = put_user(val, (unsigned int __user *)datap);
-		break;
-
-	case PTRACE_POKEDATA:
-	case PTRACE_POKETEXT:
-		ret = 0;
-		if (access_process_vm(child, addr, &data, sizeof(u32), 1) !=
-		    sizeof(u32))
-			ret = -EIO;
-		break;
-
-	case PTRACE_PEEKUSR:
-		ret = getreg32(child, addr, &val);
-		if (ret == 0)
-			ret = put_user(val, (__u32 __user *)datap);
-		break;
-
-	case PTRACE_POKEUSR:
-		ret = putreg32(child, addr, data);
-		break;
-
-	case PTRACE_GETREGS: { /* Get all gp regs from the child. */
-		int i;
-
-		if (!access_ok(VERIFY_WRITE, datap, 16*4)) {
-			ret = -EIO;
-			break;
-		}
-		ret = 0;
-		for (i = 0; i <= 16*4; i += sizeof(__u32)) {
-			getreg32(child, i, &val);
-			ret |= __put_user(val, (u32 __user *)datap);
-			datap += sizeof(u32);
-		}
-		break;
-	}
-
-	case PTRACE_SETREGS: { /* Set all gp regs in the child. */
-		unsigned long tmp;
-		int i;
-
-		if (!access_ok(VERIFY_READ, datap, 16*4)) {
-			ret = -EIO;
-			break;
-		}
-		ret = 0;
-		for (i = 0; i <= 16*4; i += sizeof(u32)) {
-			ret |= __get_user(tmp, (u32 __user *)datap);
-			putreg32(child, i, tmp);
-			datap += sizeof(u32);
-		}
-		break;
-	}
-
-	case PTRACE_GETFPREGS:
-		ret = -EIO;
-		if (!access_ok(VERIFY_READ, compat_ptr(data),
-			       sizeof(struct user_i387_struct)))
-			break;
-		save_i387_ia32(child, datap, childregs, 1);
-		ret = 0;
-			break;
-
-	case PTRACE_SETFPREGS:
-		ret = -EIO;
-		if (!access_ok(VERIFY_WRITE, datap,
-			       sizeof(struct user_i387_struct)))
-			break;
-		ret = 0;
-		/* don't check EFAULT to be bug-to-bug compatible to i386 */
-		restore_i387_ia32(child, datap, 1);
-		break;
-
-	case PTRACE_GETFPXREGS: {
-		struct user32_fxsr_struct __user *u = datap;
-
-		init_fpu(child);
-		ret = -EIO;
-		if (!access_ok(VERIFY_WRITE, u, sizeof(*u)))
-			break;
-			ret = -EFAULT;
-		if (__copy_to_user(u, &child->thread.i387.fxsave, sizeof(*u)))
-			break;
-		ret = __put_user(childregs->cs, &u->fcs);
-		ret |= __put_user(child->thread.ds, &u->fos);
-		break;
-	}
-	case PTRACE_SETFPXREGS: {
-		struct user32_fxsr_struct __user *u = datap;
-
-		unlazy_fpu(child);
-		ret = -EIO;
-		if (!access_ok(VERIFY_READ, u, sizeof(*u)))
-			break;
-		/*
-		 * no checking to be bug-to-bug compatible with i386.
-		 * but silence warning
-		 */
-		if (__copy_from_user(&child->thread.i387.fxsave, u, sizeof(*u)))
-			;
-		set_stopped_child_used_math(child);
-		child->thread.i387.fxsave.mxcsr &= mxcsr_feature_mask;
-		ret = 0;
-		break;
-	}
-
-	case PTRACE_GETEVENTMSG:
-		ret = put_user(child->ptrace_message,
-			       (unsigned int __user *)compat_ptr(data));
-		break;
-
-	default:
-		BUG();
-	}
-
- out:
-	put_task_struct(child);
-	return ret;
-}
diff --git a/arch/x86/kernel/ptrace_64.c b/arch/x86/kernel/ptrace_64.c
deleted file mode 100644
index 5979dbe..0000000
--- a/arch/x86/kernel/ptrace_64.c
+++ /dev/null
@@ -1,470 +0,0 @@
-/* By Ross Biro 1/23/92 */
-/*
- * Pentium III FXSR, SSE support
- *	Gareth Hughes <gareth@valinux.com>, May 2000
- *
- * x86-64 port 2000-2002 Andi Kleen
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/errno.h>
-#include <linux/ptrace.h>
-#include <linux/user.h>
-#include <linux/security.h>
-#include <linux/audit.h>
-#include <linux/seccomp.h>
-#include <linux/signal.h>
-
-#include <asm/uaccess.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/processor.h>
-#include <asm/prctl.h>
-#include <asm/i387.h>
-#include <asm/debugreg.h>
-#include <asm/ldt.h>
-#include <asm/desc.h>
-#include <asm/proto.h>
-#include <asm/ia32.h>
-
-/*
- * does not yet catch signals sent when the child dies.
- * in exit.c or in signal.c.
- */
-
-/*
- * Determines which flags the user has access to [1 = access, 0 = no access].
- * Prohibits changing ID(21), VIP(20), VIF(19), VM(17), IOPL(12-13), IF(9).
- * Also masks reserved bits (63-22, 15, 5, 3, 1).
- */
-#define FLAG_MASK 0x54dd5UL
-
-/*
- * Called by kernel/ptrace.c when detaching..
- *
- * Make sure the single step bit is not set.
- */
-void ptrace_disable(struct task_struct *child)
-{
-	user_disable_single_step(child);
-}
-
-static unsigned long *pt_regs_access(struct pt_regs *regs, unsigned long offset)
-{
-	BUILD_BUG_ON(offsetof(struct pt_regs, r15) != 0);
-	return &regs->r15 + (offset / sizeof(regs->r15));
-}
-
-static int putreg(struct task_struct *child,
-	unsigned long regno, unsigned long value)
-{
-	struct pt_regs *regs = task_pt_regs(child);
-	switch (regno) {
-	case offsetof(struct user_regs_struct,fs):
-		if (value && (value & 3) != 3)
-			return -EIO;
-		child->thread.fsindex = value & 0xffff;
-		if (child == current)
-			loadsegment(fs, child->thread.fsindex);
-		return 0;
-	case offsetof(struct user_regs_struct,gs):
-		if (value && (value & 3) != 3)
-			return -EIO;
-		child->thread.gsindex = value & 0xffff;
-		if (child == current)
-			load_gs_index(child->thread.gsindex);
-		return 0;
-	case offsetof(struct user_regs_struct,ds):
-		if (value && (value & 3) != 3)
-			return -EIO;
-		child->thread.ds = value & 0xffff;
-		if (child == current)
-			loadsegment(ds, child->thread.ds);
-		return 0;
-	case offsetof(struct user_regs_struct,es):
-		if (value && (value & 3) != 3)
-			return -EIO;
-		child->thread.es = value & 0xffff;
-		if (child == current)
-			loadsegment(es, child->thread.es);
-		return 0;
-	case offsetof(struct user_regs_struct,ss):
-		if ((value & 3) != 3)
-			return -EIO;
-		value &= 0xffff;
-		return 0;
-	case offsetof(struct user_regs_struct,fs_base):
-		if (value >= TASK_SIZE_OF(child))
-			return -EIO;
-		/*
-		 * When changing the segment base, use do_arch_prctl
-		 * to set either thread.fs or thread.fsindex and the
-		 * corresponding GDT slot.
-		 */
-		if (child->thread.fs != value)
-			return do_arch_prctl(child, ARCH_SET_FS, value);
-		return 0;
-	case offsetof(struct user_regs_struct,gs_base):
-		/*
-		 * Exactly the same here as the %fs handling above.
-		 */
-		if (value >= TASK_SIZE_OF(child))
-			return -EIO;
-		if (child->thread.gs != value)
-			return do_arch_prctl(child, ARCH_SET_GS, value);
-		return 0;
-	case offsetof(struct user_regs_struct,flags):
-		value &= FLAG_MASK;
-		/*
-		 * If the user value contains TF, mark that
-		 * it was not "us" (the debugger) that set it.
-		 * If not, make sure it stays set if we had.
-		 */
-		if (value & X86_EFLAGS_TF)
-			clear_tsk_thread_flag(child, TIF_FORCED_TF);
-		else if (test_tsk_thread_flag(child, TIF_FORCED_TF))
-			value |= X86_EFLAGS_TF;
-		value |= regs->flags & ~FLAG_MASK;
-		break;
-	case offsetof(struct user_regs_struct,cs):
-		if ((value & 3) != 3)
-			return -EIO;
-		value &= 0xffff;
-		break;
-	}
-	*pt_regs_access(regs, regno) = value;
-	return 0;
-}
-
-static unsigned long getreg(struct task_struct *child, unsigned long regno)
-{
-	struct pt_regs *regs = task_pt_regs(child);
-	unsigned long val;
-	unsigned int seg;
-	switch (regno) {
-	case offsetof(struct user_regs_struct, fs):
-		if (child == current) {
-			/* Older gas can't assemble movq %?s,%r?? */
-			asm("movl %%fs,%0" : "=r" (seg));
-			return seg;
-		}
-		return child->thread.fsindex;
-	case offsetof(struct user_regs_struct, gs):
-		if (child == current) {
-			asm("movl %%gs,%0" : "=r" (seg));
-			return seg;
-		}
-		return child->thread.gsindex;
-	case offsetof(struct user_regs_struct, ds):
-		if (child == current) {
-			asm("movl %%ds,%0" : "=r" (seg));
-			return seg;
-		}
-		return child->thread.ds;
-	case offsetof(struct user_regs_struct, es):
-		if (child == current) {
-			asm("movl %%es,%0" : "=r" (seg));
-			return seg;
-		}
-		return child->thread.es;
-	case offsetof(struct user_regs_struct, fs_base):
-		/*
-		 * do_arch_prctl may have used a GDT slot instead of
-		 * the MSR.  To userland, it appears the same either
-		 * way, except the %fs segment selector might not be 0.
-		 */
-		if (child->thread.fs != 0)
-			return child->thread.fs;
-		seg = child->thread.fsindex;
-		if (child == current)
-			asm("movl %%fs,%0" : "=r" (seg));
-		if (seg != FS_TLS_SEL)
-			return 0;
-		return get_desc_base(&child->thread.tls_array[FS_TLS]);
-	case offsetof(struct user_regs_struct, gs_base):
-		/*
-		 * Exactly the same here as the %fs handling above.
-		 */
-		if (child->thread.gs != 0)
-			return child->thread.gs;
-		seg = child->thread.gsindex;
-		if (child == current)
-			asm("movl %%gs,%0" : "=r" (seg));
-		if (seg != GS_TLS_SEL)
-			return 0;
-		return get_desc_base(&child->thread.tls_array[GS_TLS]);
-	case offsetof(struct user_regs_struct, flags):
-		/*
-		 * If the debugger set TF, hide it from the readout.
-		 */
-		val = regs->flags;
-		if (test_tsk_thread_flag(child, TIF_IA32))
-			val &= 0xffffffff;
-		if (test_tsk_thread_flag(child, TIF_FORCED_TF))
-			val &= ~X86_EFLAGS_TF;
-		return val;
-	default:
-		val = *pt_regs_access(regs, regno);
-		if (test_tsk_thread_flag(child, TIF_IA32))
-			val &= 0xffffffff;
-		return val;
-	}
-
-}
-
-unsigned long ptrace_get_debugreg(struct task_struct *child, int n)
-{
-	switch (n) {
-	case 0:		return child->thread.debugreg0;
-	case 1:		return child->thread.debugreg1;
-	case 2:		return child->thread.debugreg2;
-	case 3:		return child->thread.debugreg3;
-	case 6:		return child->thread.debugreg6;
-	case 7:		return child->thread.debugreg7;
-	}
-	return 0;
-}
-
-int ptrace_set_debugreg(struct task_struct *child, int n, unsigned long data)
-{
-	int i;
-
-	if (n < 4) {
-		int dsize = test_tsk_thread_flag(child, TIF_IA32) ? 3 : 7;
-		if (unlikely(data >= TASK_SIZE_OF(child) - dsize))
-			return -EIO;
-	}
-
-	switch (n) {
-	case 0:		child->thread.debugreg0 = data; break;
-	case 1:		child->thread.debugreg1 = data; break;
-	case 2:		child->thread.debugreg2 = data; break;
-	case 3:		child->thread.debugreg3 = data; break;
-
-	case 6:
-		if (data >> 32)
-			return -EIO;
-		child->thread.debugreg6 = data;
-		break;
-
-	case 7:
-		/*
-		 * See ptrace_32.c for an explanation of this awkward check.
-		 */
-		data &= ~DR_CONTROL_RESERVED;
-		for (i = 0; i < 4; i++)
-			if ((0x5554 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
-				return -EIO;
-		child->thread.debugreg7 = data;
-		if (data)
-			set_tsk_thread_flag(child, TIF_DEBUG);
-		else
-			clear_tsk_thread_flag(child, TIF_DEBUG);
-		break;
-	}
-
-	return 0;
-}
-
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
-{
-	long ret;
-	unsigned ui;
-
-	switch (request) {
-	/* when I and D space are separate, these will need to be fixed. */
-	case PTRACE_PEEKTEXT: /* read word at location addr. */
-	case PTRACE_PEEKDATA:
-		ret = generic_ptrace_peekdata(child, addr, data);
-		break;
-
-	/* read the word at location addr in the USER area. */
-	case PTRACE_PEEKUSR: {
-		unsigned long tmp;
-
-		ret = -EIO;
-		if ((addr & 7) ||
-		    addr > sizeof(struct user) - 7)
-			break;
-
-		tmp = 0;
-		if (addr < sizeof(struct user_regs_struct))
-			tmp = getreg(child, addr);
-		else if (addr >= offsetof(struct user, u_debugreg[0])) {
-			addr -= offsetof(struct user, u_debugreg[0]);
-			tmp = ptrace_get_debugreg(child, addr / sizeof(long));
-		}
-
-		ret = put_user(tmp,(unsigned long __user *) data);
-		break;
-	}
-
-	/* when I and D space are separate, this will have to be fixed. */
-	case PTRACE_POKETEXT: /* write the word at location addr. */
-	case PTRACE_POKEDATA:
-		ret = generic_ptrace_pokedata(child, addr, data);
-		break;
-
-	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
-		ret = -EIO;
-		if ((addr & 7) ||
-		    addr > sizeof(struct user) - 7)
-			break;
-
-		if (addr < sizeof(struct user_regs_struct))
-			ret = putreg(child, addr, data);
-		else if (addr >= offsetof(struct user, u_debugreg[0])) {
-			addr -= offsetof(struct user, u_debugreg[0]);
-			ret = ptrace_set_debugreg(child,
-						  addr / sizeof(long), data);
-		}
-		break;
-
-#ifdef CONFIG_IA32_EMULATION
-		/* This makes only sense with 32bit programs. Allow a
-		   64bit debugger to fully examine them too. Better
-		   don't use it against 64bit processes, use
-		   PTRACE_ARCH_PRCTL instead. */
-	case PTRACE_GET_THREAD_AREA:
-		if (addr < 0)
-			return -EIO;
-		ret = do_get_thread_area(child, addr,
-					 (struct user_desc __user *) data);
-
-		break;
-	case PTRACE_SET_THREAD_AREA:
-		if (addr < 0)
-			return -EIO;
-		ret = do_set_thread_area(child, addr,
-					 (struct user_desc __user *) data, 0);
-		break;
-#endif
-		/* normal 64bit interface to access TLS data.
-		   Works just like arch_prctl, except that the arguments
-		   are reversed. */
-	case PTRACE_ARCH_PRCTL:
-		ret = do_arch_prctl(child, data, addr);
-		break;
-
-	case PTRACE_GETREGS: { /* Get all gp regs from the child. */
-	  	if (!access_ok(VERIFY_WRITE, (unsigned __user *)data,
-			       sizeof(struct user_regs_struct))) {
-			ret = -EIO;
-			break;
-		}
-		ret = 0;
-		for (ui = 0; ui < sizeof(struct user_regs_struct); ui += sizeof(long)) {
-			ret |= __put_user(getreg(child, ui),(unsigned long __user *) data);
-			data += sizeof(long);
-		}
-		break;
-	}
-
-	case PTRACE_SETREGS: { /* Set all gp regs in the child. */
-		unsigned long tmp;
-	  	if (!access_ok(VERIFY_READ, (unsigned __user *)data,
-			       sizeof(struct user_regs_struct))) {
-			ret = -EIO;
-			break;
-		}
-		ret = 0;
-		for (ui = 0; ui < sizeof(struct user_regs_struct); ui += sizeof(long)) {
-			ret = __get_user(tmp, (unsigned long __user *) data);
-			if (ret)
-				break;
-			ret = putreg(child, ui, tmp);
-			if (ret)
-				break;
-			data += sizeof(long);
-		}
-		break;
-	}
-
-	case PTRACE_GETFPREGS: { /* Get the child extended FPU state. */
-		if (!access_ok(VERIFY_WRITE, (unsigned __user *)data,
-			       sizeof(struct user_i387_struct))) {
-			ret = -EIO;
-			break;
-		}
-		ret = get_fpregs((struct user_i387_struct __user *)data, child);
-		break;
-	}
-
-	case PTRACE_SETFPREGS: { /* Set the child extended FPU state. */
-		if (!access_ok(VERIFY_READ, (unsigned __user *)data,
-			       sizeof(struct user_i387_struct))) {
-			ret = -EIO;
-			break;
-		}
-		set_stopped_child_used_math(child);
-		ret = set_fpregs(child, (struct user_i387_struct __user *)data);
-		break;
-	}
-
-	default:
-		ret = ptrace_request(child, request, addr, data);
-		break;
-	}
-	return ret;
-}
-
-static void syscall_trace(struct pt_regs *regs)
-{
-
-#if 0
-	printk("trace %s ip %lx sp %lx ax %d origrax %d caller %lx tiflags %x ptrace %x\n",
-	       current->comm,
-	       regs->ip, regs->sp, regs->ax, regs->orig_ax, __builtin_return_address(0),
-	       current_thread_info()->flags, current->ptrace);
-#endif
-
-	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
-				? 0x80 : 0));
-	/*
-	 * this isn't the same as continuing with a signal, but it will do
-	 * for normal use.  strace only continues with a signal if the
-	 * stopping signal is not SIGTRAP.  -brl
-	 */
-	if (current->exit_code) {
-		send_sig(current->exit_code, current, 1);
-		current->exit_code = 0;
-	}
-}
-
-asmlinkage void syscall_trace_enter(struct pt_regs *regs)
-{
-	/* do the secure computing check first */
-	secure_computing(regs->orig_ax);
-
-	if (test_thread_flag(TIF_SYSCALL_TRACE)
-	    && (current->ptrace & PT_PTRACED))
-		syscall_trace(regs);
-
-	if (unlikely(current->audit_context)) {
-		if (test_thread_flag(TIF_IA32)) {
-			audit_syscall_entry(AUDIT_ARCH_I386,
-					    regs->orig_ax,
-					    regs->bx, regs->cx,
-					    regs->dx, regs->si);
-		} else {
-			audit_syscall_entry(AUDIT_ARCH_X86_64,
-					    regs->orig_ax,
-					    regs->di, regs->si,
-					    regs->dx, regs->r10);
-		}
-	}
-}
-
-asmlinkage void syscall_trace_leave(struct pt_regs *regs)
-{
-	if (unlikely(current->audit_context))
-		audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax);
-
-	if ((test_thread_flag(TIF_SYSCALL_TRACE)
-	     || test_thread_flag(TIF_SINGLESTEP))
-	    && (current->ptrace & PT_PTRACED))
-		syscall_trace(regs);
-}

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [PATCH x86/mm 01/11] x86-32 thread_struct.debugreg
  2007-11-29 11:57 [PATCH x86/mm 01/11] x86-32 thread_struct.debugreg Roland McGrath
                   ` (9 preceding siblings ...)
  2007-11-29 12:00 ` [PATCH x86/mm 11/11] x86 ptrace merge removals Roland McGrath
@ 2007-11-29 12:23 ` Ingo Molnar
  2007-11-29 21:50   ` Roland McGrath
  10 siblings, 1 reply; 29+ messages in thread
From: Ingo Molnar @ 2007-11-29 12:23 UTC (permalink / raw)
  To: Roland McGrath
  Cc: Andrew Morton, Linus Torvalds, linux-kernel, Thomas Gleixner,
	H. Peter Anvin


thanks, i've merged your 11 patches - they passed a basic build and boot 
test as well.

Roland, you've done a lot of gdb / strace / glibc development, what 
would you suggest for us to use as a ptrace regression checker? The 
problem is that ptrace is not normally used on a default bootup of a 
distro, and some of the ptrace features are really arcane. UML is an 
extensive ptrace user, so running it might be a good start, but do you 
know of any, more directed testsuite that is expected to hit all (or at 
least a substantial percentage of) the various ptrace features that we 
are affecting with these ptrace patches?

btw., your cleanup patches are having a nice effect on code quality as 
well:

                               errors   lines of code   errors/KLOC
   [before]    arch/x86/         5231          116998          44.7
   [after]     arch/x86/         5132          116656          43.9

(the 'errors' column is the sum of all .c files as per the error count 
of scripts/checkpatch.pl --file output)

it's refreshing to see life being brought back into the ptrace code 
again :-)

	Ingo

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH x86/mm 11/11] x86 ptrace merge removals
  2007-11-29 12:00 ` [PATCH x86/mm 11/11] x86 ptrace merge removals Roland McGrath
@ 2007-11-29 14:04   ` Jeff Dike
  2007-11-29 22:38     ` Roland McGrath
  0 siblings, 1 reply; 29+ messages in thread
From: Jeff Dike @ 2007-11-29 14:04 UTC (permalink / raw)
  To: Roland McGrath
  Cc: Andrew Morton, Linus Torvalds, linux-kernel, Thomas Gleixner,
	Ingo Molnar, H. Peter Anvin

On Thu, Nov 29, 2007 at 04:00:57AM -0800, Roland McGrath wrote:
...lots of ptrace merging...

Can you make sure that UML still runs when you're done with ptrace?

				Jeff

-- 
Work email - jdike at linux dot intel dot com

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH x86/mm 05/11] x86 ptrace getreg/putreg merge
  2007-11-29 11:59 ` [PATCH x86/mm 05/11] x86 ptrace getreg/putreg merge Roland McGrath
@ 2007-11-29 17:27   ` Andrew Morton
  2007-11-29 22:28     ` Roland McGrath
  0 siblings, 1 reply; 29+ messages in thread
From: Andrew Morton @ 2007-11-29 17:27 UTC (permalink / raw)
  To: Roland McGrath
  Cc: Linus Torvalds, linux-kernel, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin

On Thu, 29 Nov 2007 03:59:54 -0800 (PST) Roland McGrath <roland@redhat.com> wrote:

> +/*
> + * Determines whether a value may be installed in a segment register.
> + */
> +#define invalid_selector(value) \
> +	((value) != 0 && ((value) & SEGMENT_RPL_MASK) != USER_RPL)

This didn't need to be implemented as a macro hence it shouldn't have been.

It references its arg more than once and is dangerous.  Calling
invalid_selector(foo++) will increment foo by one or two, depending upon
foo's value.


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH x86/mm 06/11] x86 ptrace arch merge
  2007-11-29 12:00 ` [PATCH x86/mm 06/11] x86 ptrace arch merge Roland McGrath
@ 2007-11-29 17:28   ` Andrew Morton
  2007-11-29 21:33     ` Roland McGrath
  0 siblings, 1 reply; 29+ messages in thread
From: Andrew Morton @ 2007-11-29 17:28 UTC (permalink / raw)
  To: Roland McGrath
  Cc: Linus Torvalds, linux-kernel, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin

On Thu, 29 Nov 2007 04:00:14 -0800 (PST) Roland McGrath <roland@redhat.com> wrote:

> --- a/arch/x86/kernel/ptrace.c
> +++ b/arch/x86/kernel/ptrace.c
> @@ -461,12 +461,13 @@ static int ptrace_set_debugreg(struct task_struct *child,
>  void ptrace_disable(struct task_struct *child)
>  {
>  	user_disable_single_step(child);
> +#ifdef TIF_SYSCALL_EMU
>  	clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
> +#endif

Is TIF_SYSCALL_EMU ever undefined here?

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH x86/mm 08/11] x86 ia32 ptrace getreg/putreg merge
  2007-11-29 12:00 ` [PATCH x86/mm 08/11] x86 ia32 ptrace getreg/putreg merge Roland McGrath
@ 2007-11-29 17:37   ` Christoph Hellwig
  2007-11-29 17:59     ` H. Peter Anvin
  0 siblings, 1 reply; 29+ messages in thread
From: Christoph Hellwig @ 2007-11-29 17:37 UTC (permalink / raw)
  To: Roland McGrath
  Cc: Andrew Morton, Linus Torvalds, linux-kernel, Thomas Gleixner,
	Ingo Molnar, H. Peter Anvin

On Thu, Nov 29, 2007 at 04:00:31AM -0800, Roland McGrath wrote:
> +#define R32(l,q)							\
> +	case offsetof(struct user32, regs.l):				\
> +		regs->q = value; break
> +
> +#define SEG32(rs)							\
> +	case offsetof(struct user32, regs.rs):				\
> +		return set_segment_reg(child,				\
> +				       offsetof(struct user_regs_struct, rs), \
> +				       value);				\
> +		break

The code would be a lot more readable if you just opencoded this in the
caller instead of these obsfucated macros.

> +
> +static int putreg32(struct task_struct *child, unsigned regno, u32 value)
> +{
> +	struct pt_regs *regs = task_pt_regs(child);
> +
> +	switch (regno) {
> +
> +	SEG32(cs);
> +	SEG32(ds);
> +	SEG32(es);
> +	SEG32(fs);
> +	SEG32(gs);
> +	SEG32(ss);
> +
> +	R32(ebx, bx);
> +	R32(ecx, cx);
> +	R32(edx, dx);
> +	R32(edi, di);
> +	R32(esi, si);
> +	R32(ebp, bp);
> +	R32(eax, ax);
> +	R32(orig_eax, orig_ax);
> +	R32(eip, ip);
> +	R32(esp, sp);
> +
> +	case offsetof(struct user32, regs.eflags):
> +		return set_flags(child, value);
> +
> +	case offsetof(struct user32, u_debugreg[0]) ...
> +		offsetof(struct user32, u_debugreg[7]):
> +		regno -= offsetof(struct user32, u_debugreg[0]);
> +		return ptrace_set_debugreg(child, regno / 4, value);
> +
> +	default:
> +		if (regno > sizeof(struct user32) || (regno & 3))
> +			return -EIO;
> +
> +		/*
> +		 * Other dummy fields in the virtual user structure
> +		 * are ignored
> +		 */
> +		break;
> +	}
> +	return 0;
> +}
> +
> +#undef R32
> +#undef SEG32
> +
> +#define R32(l,q)							\
> +	case offsetof(struct user32, regs.l):				\
> +		*val = regs->q; break
> +
> +#define SEG32(rs)							\
> +	case offsetof(struct user32, regs.rs):				\
> +		*val = get_segment_reg(child,				\
> +				       offsetof(struct user_regs_struct, rs)); \
> +		break
> +
> +static int getreg32(struct task_struct *child, unsigned regno, u32 *val)
> +{
> +	struct pt_regs *regs = task_pt_regs(child);
> +
> +	switch (regno) {
> +
> +	SEG32(ds);
> +	SEG32(es);
> +	SEG32(fs);
> +	SEG32(gs);
> +
> +	R32(cs, cs);
> +	R32(ss, ss);
> +	R32(ebx, bx);
> +	R32(ecx, cx);
> +	R32(edx, dx);
> +	R32(edi, di);
> +	R32(esi, si);
> +	R32(ebp, bp);
> +	R32(eax, ax);
> +	R32(orig_eax, orig_ax);
> +	R32(eip, ip);
> +	R32(esp, sp);
> +
> +	case offsetof(struct user32, regs.eflags):
> +		*val = get_flags(child);
> +		break;
> +
> +	case offsetof(struct user32, u_debugreg[0]) ...
> +		offsetof(struct user32, u_debugreg[7]):
> +		regno -= offsetof(struct user32, u_debugreg[0]);
> +		*val = ptrace_get_debugreg(child, regno / 4);
> +		break;
> +
> +	default:
> +		if (regno > sizeof(struct user32) || (regno & 3))
> +			return -EIO;
> +
> +		/*
> +		 * Other dummy fields in the virtual user structure
> +		 * are ignored
> +		 */
> +		*val = 0;
> +		break;
> +	}
> +	return 0;
> +}
> +
> +#undef R32
> +#undef SEG32
> +
> +#endif	/* CONFIG_IA32_EMULATION */
> +
>  #ifdef CONFIG_X86_32
>  
>  void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
---end quoted text---

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH x86/mm 08/11] x86 ia32 ptrace getreg/putreg merge
  2007-11-29 17:37   ` Christoph Hellwig
@ 2007-11-29 17:59     ` H. Peter Anvin
  2007-11-29 19:50       ` Ingo Molnar
  0 siblings, 1 reply; 29+ messages in thread
From: H. Peter Anvin @ 2007-11-29 17:59 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Roland McGrath, Andrew Morton, Linus Torvalds, linux-kernel,
	Thomas Gleixner, Ingo Molnar

Christoph Hellwig wrote:
> On Thu, Nov 29, 2007 at 04:00:31AM -0800, Roland McGrath wrote:
>> +#define R32(l,q)							\
>> +	case offsetof(struct user32, regs.l):				\
>> +		regs->q = value; break
>> +
>> +#define SEG32(rs)							\
>> +	case offsetof(struct user32, regs.rs):				\
>> +		return set_segment_reg(child,				\
>> +				       offsetof(struct user_regs_struct, rs), \
>> +				       value);				\
>> +		break
> 
> The code would be a lot more readable if you just opencoded this in the
> caller instead of these obsfucated macros.
> 

For better or worse, though, that is style of existing code.  I 
personally found it easy to deal with when I went through the code recently.

	-hpa

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH x86/mm 08/11] x86 ia32 ptrace getreg/putreg merge
  2007-11-29 17:59     ` H. Peter Anvin
@ 2007-11-29 19:50       ` Ingo Molnar
  0 siblings, 0 replies; 29+ messages in thread
From: Ingo Molnar @ 2007-11-29 19:50 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Christoph Hellwig, Roland McGrath, Andrew Morton, Linus Torvalds,
	linux-kernel, Thomas Gleixner


* H. Peter Anvin <hpa@zytor.com> wrote:

> Christoph Hellwig wrote:
>> On Thu, Nov 29, 2007 at 04:00:31AM -0800, Roland McGrath wrote:
>>> +#define R32(l,q)							\
>>> +	case offsetof(struct user32, regs.l):				\
>>> +		regs->q = value; break
>>> +
>>> +#define SEG32(rs)							\
>>> +	case offsetof(struct user32, regs.rs):				\
>>> +		return set_segment_reg(child,				\
>>> +				       offsetof(struct user_regs_struct, rs), \
>>> +				       value);				\
>>> +		break
>>
>> The code would be a lot more readable if you just opencoded this in the
>> caller instead of these obsfucated macros.
>
> For better or worse, though, that is style of existing code.  I 
> personally found it easy to deal with when I went through the code 
> recently.

yep. The ptrace code has certainly lots of inconsistent style crap piled 
up during its 10 year history of only be touched with a 10 foot pole. 
I'd go for small patches that continuously improve the picture within 
the existing mechanisms than any "100% pure required" approach. With 48 
clean patches from Roland we are already on the right granularity level 
i think.

See how ptrace.c raw code quality has already increased leaps and 
bounds:

                                       errors   lines of code   errors/KLOC
 [before]
 arch/x86/kernel/ptrace_64.c               58             621          93.3
 arch/x86/kernel/ptrace_32.c               39             717          54.3

 [after]
 arch/x86/kernel/ptrace.c                  13            1135          11.4

so i'm not worried about that aspect. We are definitely "for the 
better".

	Ingo

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH x86/mm 09/11] x86 ia32 ptrace arch merge
  2007-11-29 12:00 ` [PATCH x86/mm 09/11] x86 ia32 ptrace arch merge Roland McGrath
@ 2007-11-29 20:58   ` Alexey Dobriyan
  2007-11-29 21:37     ` Roland McGrath
  0 siblings, 1 reply; 29+ messages in thread
From: Alexey Dobriyan @ 2007-11-29 20:58 UTC (permalink / raw)
  To: Roland McGrath
  Cc: Andrew Morton, Linus Torvalds, linux-kernel, Thomas Gleixner,
	Ingo Molnar, H. Peter Anvin

On Thu, Nov 29, 2007 at 04:00:41AM -0800, Roland McGrath wrote:
> This moves the sys32_ptrace code into arch/x86/kernel/ptrace.c,
> verbatim except for a few hard-coded sizes replaced with sizeof.
> Here this code can use the shared local functions in this file.

> --- a/arch/x86/kernel/ptrace.c
> +++ b/arch/x86/kernel/ptrace.c

> +asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
> +{
> +	struct task_struct *child;
> +	struct pt_regs *childregs;
> +	void __user *datap = compat_ptr(data);
> +	int ret;
> +	__u32 val;
> +
> +	switch (request) {
> +	case PTRACE_PEEKDATA:
> +	case PTRACE_PEEKTEXT:
> +		ret = 0;

Dead write.

> +		if (access_process_vm(child, addr, &val, sizeof(u32), 0) !=
> +		    sizeof(u32))
> +			ret = -EIO;
> +		else
> +			ret = put_user(val, (unsigned int __user *)datap);
> +		break;

> +	case PTRACE_GETFPREGS:
> +		ret = -EIO;
> +		if (!access_ok(VERIFY_READ, compat_ptr(data),
> +			       sizeof(struct user_i387_struct)))
> +			break;
> +		save_i387_ia32(child, datap, childregs, 1);
> +		ret = 0;
> +			break;

More indentation than needed.

> +	case PTRACE_GETFPXREGS: {
> +		struct user32_fxsr_struct __user *u = datap;
> +
> +		init_fpu(child);
> +		ret = -EIO;
> +		if (!access_ok(VERIFY_WRITE, u, sizeof(*u)))
> +			break;
> +			ret = -EFAULT;

Absent { }. :^)

> +		if (__copy_to_user(u, &child->thread.i387.fxsave, sizeof(*u)))
> +			break;
> +		ret = __put_user(childregs->cs, &u->fcs);
> +		ret |= __put_user(child->thread.ds, &u->fos);
> +		break;
> +	}

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH x86/mm 06/11] x86 ptrace arch merge
  2007-11-29 17:28   ` Andrew Morton
@ 2007-11-29 21:33     ` Roland McGrath
  0 siblings, 0 replies; 29+ messages in thread
From: Roland McGrath @ 2007-11-29 21:33 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Linus Torvalds, linux-kernel, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin

> > --- a/arch/x86/kernel/ptrace.c
> > +++ b/arch/x86/kernel/ptrace.c
> > @@ -461,12 +461,13 @@ static int ptrace_set_debugreg(struct task_struct *child,
> >  void ptrace_disable(struct task_struct *child)
> >  {
> >  	user_disable_single_step(child);
> > +#ifdef TIF_SYSCALL_EMU
> >  	clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
> > +#endif
> 
> Is TIF_SYSCALL_EMU ever undefined here?

Yes, it not defined on CONFIG_X86_64.
(That is something to be addressed later on.)


Thanks,
Roland

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH x86/mm 09/11] x86 ia32 ptrace arch merge
  2007-11-29 20:58   ` Alexey Dobriyan
@ 2007-11-29 21:37     ` Roland McGrath
  2007-11-30 11:34       ` Ingo Molnar
  0 siblings, 1 reply; 29+ messages in thread
From: Roland McGrath @ 2007-11-29 21:37 UTC (permalink / raw)
  To: Alexey Dobriyan
  Cc: Andrew Morton, Linus Torvalds, linux-kernel, Thomas Gleixner,
	Ingo Molnar, H. Peter Anvin

> On Thu, Nov 29, 2007 at 04:00:41AM -0800, Roland McGrath wrote:
> > This moves the sys32_ptrace code into arch/x86/kernel/ptrace.c,
> > verbatim except for a few hard-coded sizes replaced with sizeof.
    ^^^^^^^^
>[...]

I just moved this code, I didn't change it.  So let's leave style (or
other) problems with the existing code for a next round and not hold
up the moving/merging because of them.


Thanks,
Roland

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH x86/mm 01/11] x86-32 thread_struct.debugreg
  2007-11-29 12:23 ` [PATCH x86/mm 01/11] x86-32 thread_struct.debugreg Ingo Molnar
@ 2007-11-29 21:50   ` Roland McGrath
  2007-11-29 23:02     ` Chuck Ebbert
  2007-11-30  0:07     ` Jeff Dike
  0 siblings, 2 replies; 29+ messages in thread
From: Roland McGrath @ 2007-11-29 21:50 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Andrew Morton, Linus Torvalds, linux-kernel, Thomas Gleixner,
	H. Peter Anvin, jan.kratochvil

> thanks, i've merged your 11 patches - they passed a basic build and boot 
> test as well.

Thanks!

> Roland, you've done a lot of gdb / strace / glibc development, what 
> would you suggest for us to use as a ptrace regression checker? The 
> problem is that ptrace is not normally used on a default bootup of a 
> distro, and some of the ptrace features are really arcane. UML is an 
> extensive ptrace user, so running it might be a good start, but do you 
> know of any, more directed testsuite that is expected to hit all (or at 
> least a substantial percentage of) the various ptrace features that we 
> are affecting with these ptrace patches?

Jan Kratochvil has helped me a great deal with ptrace testing lately.
We have started to collect a small regression test suite, see
http://sourceware.org/systemtap/wiki/utrace/tests for pointers.  That
has tests for individual problems that have come up, and not anything
exhaustive for testing all ptrace functionality.  The gdb test suite
is moderately torturous and more or less the standard big smoke test.
UML is also a good test, though I have never been set up to verify
anything beyond "UML seems to boot far enough to complain I don't
have a userland filesystem for it".  

Most of the changes I've submitted lately are just moving code around
and not changing its logic substantially.  So for most iterations
I've been reaosnably confident after just a few quick smoke tests
with simple manual uses of strace and gdb.


Thanks,
Roland

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH x86/mm 05/11] x86 ptrace getreg/putreg merge
  2007-11-29 17:27   ` Andrew Morton
@ 2007-11-29 22:28     ` Roland McGrath
  2007-11-30 11:40       ` Ingo Molnar
  0 siblings, 1 reply; 29+ messages in thread
From: Roland McGrath @ 2007-11-29 22:28 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Linus Torvalds, linux-kernel, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin

> This didn't need to be implemented as a macro hence it shouldn't have been.

Ok.


diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index b3433e1..0000000 100644  
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -45,8 +45,10 @@
 /*
  * Determines whether a value may be installed in a segment register.
  */
-#define invalid_selector(value) \
-	((value) != 0 && ((value) & SEGMENT_RPL_MASK) != USER_RPL)
+static inline bool invalid_selector(u16 value)
+{
+	return unlikely(value != 0 && (value & SEGMENT_RPL_MASK) != USER_RPL);
+}
 
 #ifdef CONFIG_X86_32
 

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [PATCH x86/mm 11/11] x86 ptrace merge removals
  2007-11-29 14:04   ` Jeff Dike
@ 2007-11-29 22:38     ` Roland McGrath
  2007-11-30  0:03       ` Jeff Dike
  0 siblings, 1 reply; 29+ messages in thread
From: Roland McGrath @ 2007-11-29 22:38 UTC (permalink / raw)
  To: Jeff Dike
  Cc: Andrew Morton, Linus Torvalds, linux-kernel, Thomas Gleixner,
	Ingo Molnar, H. Peter Anvin

> On Thu, Nov 29, 2007 at 04:00:57AM -0800, Roland McGrath wrote:
> ...lots of ptrace merging...
> 
> Can you make sure that UML still runs when you're done with ptrace?

I'd be glad to, especially if you give me some advice on testing (.config
for um-i386 and um-x86_64, what do try that constitutes "UML still runs").
My patches are going into the x86/mm tree.  Right now (before these), UML
doesn't build for x86_64 or i386 from this tree to begin with.


Thanks,
Roland


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH x86/mm 01/11] x86-32 thread_struct.debugreg
  2007-11-29 21:50   ` Roland McGrath
@ 2007-11-29 23:02     ` Chuck Ebbert
  2007-11-30  0:07     ` Jeff Dike
  1 sibling, 0 replies; 29+ messages in thread
From: Chuck Ebbert @ 2007-11-29 23:02 UTC (permalink / raw)
  To: Roland McGrath
  Cc: Ingo Molnar, Andrew Morton, Linus Torvalds, linux-kernel,
	Thomas Gleixner, H. Peter Anvin, jan.kratochvil

On 11/29/2007 04:50 PM, Roland McGrath wrote:
> Jan Kratochvil has helped me a great deal with ptrace testing lately.
> We have started to collect a small regression test suite, see
> http://sourceware.org/systemtap/wiki/utrace/tests for pointers.  That
> has tests for individual problems that have come up, and not anything
> exhaustive for testing all ptrace functionality.

You could contribute them to LTP?

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH x86/mm 11/11] x86 ptrace merge removals
  2007-11-29 22:38     ` Roland McGrath
@ 2007-11-30  0:03       ` Jeff Dike
  0 siblings, 0 replies; 29+ messages in thread
From: Jeff Dike @ 2007-11-30  0:03 UTC (permalink / raw)
  To: Roland McGrath
  Cc: Andrew Morton, Linus Torvalds, linux-kernel, Thomas Gleixner,
	Ingo Molnar, H. Peter Anvin

On Thu, Nov 29, 2007 at 02:38:03PM -0800, Roland McGrath wrote:
> > Can you make sure that UML still runs when you're done with ptrace?
> 
> I'd be glad to, especially if you give me some advice on testing (.config
> for um-i386 and um-x86_64, what do try that constitutes "UML still runs").

Use defconfig and boot it.  If you break ptrace, I think it's
overwhelmingly likely that UML will stop booting.  So if UML boots,
I'd say you're good to go, with one caveat.  That is, UML should
report at boot that PTRACE_SYSEMU works.  I put in a fallback from
PTRACE_SYSEMU to PTRACE_SYSCALL when Fedora broke PTRACE_SYSEMU.

> Right now (before these), UML
> doesn't build for x86_64 or i386 from this tree to begin with.

For current -mm, you'll need
http://marc.info/?l=linux-kernel&m=119635496908681&q=raw to build.

				Jeff

-- 
Work email - jdike at linux dot intel dot com

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH x86/mm 01/11] x86-32 thread_struct.debugreg
  2007-11-29 21:50   ` Roland McGrath
  2007-11-29 23:02     ` Chuck Ebbert
@ 2007-11-30  0:07     ` Jeff Dike
  1 sibling, 0 replies; 29+ messages in thread
From: Jeff Dike @ 2007-11-30  0:07 UTC (permalink / raw)
  To: Roland McGrath
  Cc: Ingo Molnar, Andrew Morton, Linus Torvalds, linux-kernel,
	Thomas Gleixner, H. Peter Anvin, jan.kratochvil

On Thu, Nov 29, 2007 at 01:50:55PM -0800, Roland McGrath wrote:
> UML is also a good test, though I have never been set up to verify
> anything beyond "UML seems to boot far enough to complain I don't
> have a userland filesystem for it".  

BTW, this doesn't exercise ptrace at all.  Interesting ptrace things
only start happening when userspace runs.

Grab an interesting-looking image from http://uml.nagafix.co.uk,
uncompress it, and run
	./linux ubda=the-filesystem-image

				Jeff

-- 
Work email - jdike at linux dot intel dot com

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH x86/mm 09/11] x86 ia32 ptrace arch merge
  2007-11-29 21:37     ` Roland McGrath
@ 2007-11-30 11:34       ` Ingo Molnar
  0 siblings, 0 replies; 29+ messages in thread
From: Ingo Molnar @ 2007-11-30 11:34 UTC (permalink / raw)
  To: Roland McGrath
  Cc: Alexey Dobriyan, Andrew Morton, Linus Torvalds, linux-kernel,
	Thomas Gleixner, H. Peter Anvin


* Roland McGrath <roland@redhat.com> wrote:

> > On Thu, Nov 29, 2007 at 04:00:41AM -0800, Roland McGrath wrote:
> > > This moves the sys32_ptrace code into arch/x86/kernel/ptrace.c,
> > > verbatim except for a few hard-coded sizes replaced with sizeof.
>     ^^^^^^^^
> >[...]
> 
> I just moved this code, I didn't change it.  So let's leave style (or 
> other) problems with the existing code for a next round and not hold 
> up the moving/merging because of them.

yep - cleanups should then be posted against the unified codebase. (it's 
simpler that way)

	Ingo

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH x86/mm 05/11] x86 ptrace getreg/putreg merge
  2007-11-29 22:28     ` Roland McGrath
@ 2007-11-30 11:40       ` Ingo Molnar
  0 siblings, 0 replies; 29+ messages in thread
From: Ingo Molnar @ 2007-11-30 11:40 UTC (permalink / raw)
  To: Roland McGrath
  Cc: Andrew Morton, Linus Torvalds, linux-kernel, Thomas Gleixner,
	H. Peter Anvin


* Roland McGrath <roland@redhat.com> wrote:

> > This didn't need to be implemented as a macro hence it shouldn't have been.
> 
> Ok.
> 
> 
> diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
> index b3433e1..0000000 100644  
> --- a/arch/x86/kernel/ptrace.c
> +++ b/arch/x86/kernel/ptrace.c

i have added this to x86.git.

	Ingo

^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2007-11-30 11:41 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-11-29 11:57 [PATCH x86/mm 01/11] x86-32 thread_struct.debugreg Roland McGrath
2007-11-29 11:59 ` [PATCH x86/mm 02/11] x86: ptrace_32 renamed Roland McGrath
2007-11-29 11:59 ` [PATCH x86/mm 03/11] x86: ptrace FLAG_MASK cleanup Roland McGrath
2007-11-29 11:59 ` [PATCH x86/mm 04/11] x86 ptrace getreg/putreg cleanup Roland McGrath
2007-11-29 11:59 ` [PATCH x86/mm 05/11] x86 ptrace getreg/putreg merge Roland McGrath
2007-11-29 17:27   ` Andrew Morton
2007-11-29 22:28     ` Roland McGrath
2007-11-30 11:40       ` Ingo Molnar
2007-11-29 12:00 ` [PATCH x86/mm 06/11] x86 ptrace arch merge Roland McGrath
2007-11-29 17:28   ` Andrew Morton
2007-11-29 21:33     ` Roland McGrath
2007-11-29 12:00 ` [PATCH x86/mm 07/11] x86 ptrace merge syscall trace Roland McGrath
2007-11-29 12:00 ` [PATCH x86/mm 08/11] x86 ia32 ptrace getreg/putreg merge Roland McGrath
2007-11-29 17:37   ` Christoph Hellwig
2007-11-29 17:59     ` H. Peter Anvin
2007-11-29 19:50       ` Ingo Molnar
2007-11-29 12:00 ` [PATCH x86/mm 09/11] x86 ia32 ptrace arch merge Roland McGrath
2007-11-29 20:58   ` Alexey Dobriyan
2007-11-29 21:37     ` Roland McGrath
2007-11-30 11:34       ` Ingo Molnar
2007-11-29 12:00 ` [PATCH x86/mm 10/11] x86 ptrace merge complete Roland McGrath
2007-11-29 12:00 ` [PATCH x86/mm 11/11] x86 ptrace merge removals Roland McGrath
2007-11-29 14:04   ` Jeff Dike
2007-11-29 22:38     ` Roland McGrath
2007-11-30  0:03       ` Jeff Dike
2007-11-29 12:23 ` [PATCH x86/mm 01/11] x86-32 thread_struct.debugreg Ingo Molnar
2007-11-29 21:50   ` Roland McGrath
2007-11-29 23:02     ` Chuck Ebbert
2007-11-30  0:07     ` Jeff Dike

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).