[PATCH 17/27] x86-64 ptrace debugreg cleanup

Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]
From: Roland McGrath
Date: Sunday, November 25, 2007 - 3:04 pm

This cleans up the 64-bit ptrace code to separate the guts of the
debug register access from the implementation of PTRACE_PEEKUSR and
PTRACE_POKEUSR.  The new functions ptrace_[gs]et_debugreg are made
global so that the ia32 code can later be changed to call them too.

Signed-off-by: Roland McGrath <roland@redhat.com>
---
 arch/x86/kernel/ptrace_64.c |  140 ++++++++++++++++++++-----------------------
 include/asm-x86/ptrace.h    |    3 +
 2 files changed, 69 insertions(+), 74 deletions(-)

diff --git a/arch/x86/kernel/ptrace_64.c b/arch/x86/kernel/ptrace_64.c
index 8123ecb..bad8b3c 100644
--- a/arch/x86/kernel/ptrace_64.c
+++ b/arch/x86/kernel/ptrace_64.c
@@ -183,9 +183,63 @@ static unsigned long getreg(struct task_struct *child, unsigned long regno)
 
 }
 
+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 i, ret;
+	long ret;
 	unsigned ui;
 
 	switch (request) {
@@ -204,32 +258,14 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 		    addr > sizeof(struct user) - 7)
 			break;
 
-		switch (addr) {
-		case 0 ... sizeof(struct user_regs_struct) - sizeof(long):
+		tmp = 0;
+		if (addr < sizeof(struct user_regs_struct))
 			tmp = getreg(child, addr);
-			break;
-		case offsetof(struct user, u_debugreg[0]):
-			tmp = child->thread.debugreg0;
-			break;
-		case offsetof(struct user, u_debugreg[1]):
-			tmp = child->thread.debugreg1;
-			break;
-		case offsetof(struct user, u_debugreg[2]):
-			tmp = child->thread.debugreg2;
-			break;
-		case offsetof(struct user, u_debugreg[3]):
-			tmp = child->thread.debugreg3;
-			break;
-		case offsetof(struct user, u_debugreg[6]):
-			tmp = child->thread.debugreg6;
-			break;
-		case offsetof(struct user, u_debugreg[7]):
-			tmp = child->thread.debugreg7;
-			break;
-		default:
-			tmp = 0;
-			break;
+		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;
 	}
@@ -241,63 +277,19 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 		break;
 
 	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
-	{
-		int dsize = test_tsk_thread_flag(child, TIF_IA32) ? 3 : 7;
 		ret = -EIO;
 		if ((addr & 7) ||
 		    addr > sizeof(struct user) - 7)
 			break;
 
-		switch (addr) {
-		case 0 ... sizeof(struct user_regs_struct) - sizeof(long):
+		if (addr < sizeof(struct user_regs_struct))
 			ret = putreg(child, addr, data);
-			break;
-		/* Disallows to set a breakpoint into the vsyscall */
-		case offsetof(struct user, u_debugreg[0]):
-			if (data >= TASK_SIZE_OF(child) - dsize) break;
-			child->thread.debugreg0 = data;
-			ret = 0;
-			break;
-		case offsetof(struct user, u_debugreg[1]):
-			if (data >= TASK_SIZE_OF(child) - dsize) break;
-			child->thread.debugreg1 = data;
-			ret = 0;
-			break;
-		case offsetof(struct user, u_debugreg[2]):
-			if (data >= TASK_SIZE_OF(child) - dsize) break;
-			child->thread.debugreg2 = data;
-			ret = 0;
-			break;
-		case offsetof(struct user, u_debugreg[3]):
-			if (data >= TASK_SIZE_OF(child) - dsize) break;
-			child->thread.debugreg3 = data;
-			ret = 0;
-			break;
-		case offsetof(struct user, u_debugreg[6]):
-				  if (data >> 32)
-				break;
-			child->thread.debugreg6 = data;
-			ret = 0;
-			break;
-		case offsetof(struct user, u_debugreg[7]):
-			/* See arch/i386/kernel/ptrace.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)
-					break;
-			if (i == 4) {
-			  child->thread.debugreg7 = data;
-			  if (data)
-			  	set_tsk_thread_flag(child, TIF_DEBUG);
-			  else
-			  	clear_tsk_thread_flag(child, TIF_DEBUG);
-			  ret = 0;
-		  	}
-		  break;
+		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
diff --git a/include/asm-x86/ptrace.h b/include/asm-x86/ptrace.h
index fe75422..d223dec 100644
--- a/include/asm-x86/ptrace.h
+++ b/include/asm-x86/ptrace.h
@@ -110,6 +110,9 @@ 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);
 
-
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]

Messages in current thread:
[PATCH 01/27] ptrace: arch_has_single_step, Roland McGrath, (Sun Nov 25, 2:55 pm)
[PATCH 02/27] x86: segment selector macros, Roland McGrath, (Sun Nov 25, 2:58 pm)
[PATCH 03/27] x86: remove TRAP_FLAG, Roland McGrath, (Sun Nov 25, 2:58 pm)
[PATCH 04/27] x86: arch_has_single_step, Roland McGrath, (Sun Nov 25, 2:59 pm)
[PATCH 05/27] x86: single_step moved, Roland McGrath, (Sun Nov 25, 2:59 pm)
[PATCH 06/27] x86: single_step segment macros, Roland McGrath, (Sun Nov 25, 2:59 pm)
[PATCH 07/27] x86: single_step 0xf0, Roland McGrath, (Sun Nov 25, 3:00 pm)
[PATCH 08/27] x86: single_step: share code, Roland McGrath, (Sun Nov 25, 3:00 pm)
[PATCH 10/27] ptrace: generic resume, Roland McGrath, (Sun Nov 25, 3:01 pm)
[PATCH 11/27] x86-64: ptrace generic resume, Roland McGrath, (Sun Nov 25, 3:01 pm)
[PATCH 12/27] x86-32: ptrace generic resume, Roland McGrath, (Sun Nov 25, 3:01 pm)
[PATCH 13/27] powerpc: arch_has_single_step, Roland McGrath, (Sun Nov 25, 3:03 pm)
[PATCH 14/27] powerpc: ptrace generic resume, Roland McGrath, (Sun Nov 25, 3:04 pm)
[PATCH 15/27] x86-32 ptrace: use task_pt_regs, Roland McGrath, (Sun Nov 25, 3:04 pm)
[PATCH 16/27] x86-64 ptrace: use task_pt_regs, Roland McGrath, (Sun Nov 25, 3:04 pm)
[PATCH 17/27] x86-64 ptrace debugreg cleanup, Roland McGrath, (Sun Nov 25, 3:04 pm)
[PATCH 18/27] x86-64 ia32 ptrace debugreg cleanup, Roland McGrath, (Sun Nov 25, 3:05 pm)
[PATCH 19/27] x86-32 ptrace debugreg cleanup, Roland McGrath, (Sun Nov 25, 3:05 pm)
[PATCH 21/27] ptrace: generic PTRACE_SINGLEBLOCK, Roland McGrath, (Sun Nov 25, 3:06 pm)
[PATCH 22/27] x86: debugctlmsr constants, Roland McGrath, (Sun Nov 25, 3:06 pm)
[PATCH 23/27] x86: debugctlmsr kconfig, Roland McGrath, (Sun Nov 25, 3:08 pm)
[PATCH 24/27] x86: debugctlmsr context switch, Roland McGrath, (Sun Nov 25, 3:08 pm)
[PATCH 26/27] x86: debugctlmsr kprobes, Roland McGrath, (Sun Nov 25, 3:08 pm)
[PATCH 27/27] x86: PTRACE_SINGLEBLOCK, Roland McGrath, (Sun Nov 25, 3:08 pm)
Re: [PATCH 01/27] ptrace: arch_has_single_step, Christoph Hellwig, (Sun Nov 25, 3:22 pm)
Re: [PATCH 01/27] ptrace: arch_has_single_step, Roland McGrath, (Sun Nov 25, 3:59 pm)
Re: [PATCH 23/27] x86: debugctlmsr kconfig, Denys Vlasenko, (Sun Nov 25, 6:09 pm)
Re: [PATCH 23/27] x86: debugctlmsr kconfig, Roland McGrath, (Mon Nov 26, 12:51 am)
Re: [PATCH 23/27] x86: debugctlmsr kconfig, Roland McGrath, (Mon Nov 26, 1:06 am)
Re: [PATCH 23/27] x86: debugctlmsr kconfig, Denys Vlasenko, (Mon Nov 26, 3:52 pm)
Re: [PATCH 01/27] ptrace: arch_has_single_step, Andrew Morton, (Tue Nov 27, 1:53 am)
Re: [PATCH 01/27] ptrace: arch_has_single_step, Ingo Molnar, (Tue Nov 27, 3:38 am)
Re: [PATCH 01/27] ptrace: arch_has_single_step, Roland McGrath, (Tue Nov 27, 4:05 pm)
Re: [PATCH 01/27] ptrace: arch_has_single_step, Ingo Molnar, (Tue Nov 27, 4:58 pm)
Re: [PATCH 01/27] ptrace: arch_has_single_step, Roland McGrath, (Tue Nov 27, 5:08 pm)
Re: [PATCH 20/27] ptrace: arch_has_block_step, David Wilder, (Wed Nov 28, 4:39 pm)
Re: [PATCH 20/27] ptrace: arch_has_block_step, Roland McGrath, (Wed Nov 28, 4:58 pm)
Re: [PATCH 14/27] powerpc: ptrace generic resume, Srinivasa Ds, (Mon Dec 3, 1:12 am)