2007-11-25 21:55:59

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 01/27] ptrace: arch_has_single_step

This defines the new macro arch_has_single_step() in linux/ptrace.h, a
default for when asm/ptrace.h does not define it. It declares the new
user_enable_single_step and user_disable_single_step functions.
This is not used yet, but paves the way to harmonize on this interface
for the arch-specific calls on all machines.

Signed-off-by: Roland McGrath <[email protected]>
---
include/linux/ptrace.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 46 insertions(+), 0 deletions(-)

diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index ae8146a..a6effc8 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -128,6 +128,52 @@ int generic_ptrace_pokedata(struct task_struct *tsk, long addr, long data);
#define force_successful_syscall_return() do { } while (0)
#endif

+/*
+ * <asm/ptrace.h> should define the following things inside #ifdef __KERNEL__.
+ *
+ * These do-nothing inlines are used when the arch does not
+ * implement single-step. The kerneldoc comments are here
+ * to document the interface for all arch definitions.
+ */
+
+#ifndef arch_has_single_step
+/**
+ * arch_has_single_step - does this CPU support user-mode single-step?
+ *
+ * If this is defined, then there must be function declarations or
+ * inlines for user_enable_single_step() and user_disable_single_step().
+ * arch_has_single_step() should evaluate to nonzero iff the machine
+ * supports instruction single-step for user mode.
+ * It can be a constant or it can test a CPU feature bit.
+ */
+#define arch_has_single_step() (0)
+
+/**
+ * user_enable_single_step - single-step in user-mode task
+ * @task: either current or a task stopped in %TASK_TRACED
+ *
+ * This can only be called when arch_has_single_step() has returned nonzero.
+ * Set @task so that when it returns to user mode, it will trap after the
+ * next single instruction executes.
+ */
+static inline void user_enable_single_step(struct task_struct *task)
+{
+ BUG(); /* This can never be called. */
+}
+
+/**
+ * user_disable_single_step - cancel user-mode single-step
+ * @task: either current or a task stopped in %TASK_TRACED
+ *
+ * Clear @task of the effects of user_enable_single_step(). This can
+ * be called whether or not user_enable_single_step() was ever called
+ * on @task, and even if arch_has_single_step() returned zero.
+ */
+static inline void user_disable_single_step(struct task_struct *task)
+{
+}
+#endif /* arch_has_single_step */
+
#endif

#endif
--
1.5.3.4


2007-11-25 21:59:17

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 02/27] x86: segment selector macros


This copies into asm-x86/segment_64.h some macros from asm-x86/segment_32.h
for dissecting segment selectors. This lets other code use these macros
uniformly on 32/64-bit rather than duplicating the constants elsewhere.

Signed-off-by: Roland McGrath <[email protected]>
---
include/asm-x86/segment_64.h | 11 +++++++++++
1 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/include/asm-x86/segment_64.h b/include/asm-x86/segment_64.h
index 04b8ab2..dce7421 100644
--- a/include/asm-x86/segment_64.h
+++ b/include/asm-x86/segment_64.h
@@ -50,4 +50,15 @@
#define GDT_SIZE (GDT_ENTRIES * 8)
#define TLS_SIZE (GDT_ENTRY_TLS_ENTRIES * 8)

+/* Bottom two bits of selector give the ring privilege level */
+#define SEGMENT_RPL_MASK 0x3
+/* Bit 2 is table indicator (LDT/GDT) */
+#define SEGMENT_TI_MASK 0x4
+
+/* User mode is privilege level 3 */
+#define USER_RPL 0x3
+/* LDT segment has TI set, GDT has it cleared */
+#define SEGMENT_LDT 0x4
+#define SEGMENT_GDT 0x0
+
#endif

2007-11-25 21:59:34

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 04/27] x86: arch_has_single_step


This defines the new standard arch_has_single_step macro. It makes the
existing set_singlestep and clear_singlestep entry points global, and
renames them to the new standard names user_enable_single_step and
user_disable_single_step, respectively.

Signed-off-by: Roland McGrath <[email protected]>
---
arch/x86/kernel/ptrace_32.c | 12 ++++++------
arch/x86/kernel/ptrace_64.c | 12 ++++++------
include/asm-x86/ptrace.h | 7 +++++++
3 files changed, 19 insertions(+), 12 deletions(-)

diff --git a/arch/x86/kernel/ptrace_32.c b/arch/x86/kernel/ptrace_32.c
index 2b4fcb5..d1d74e1 100644
--- a/arch/x86/kernel/ptrace_32.c
+++ b/arch/x86/kernel/ptrace_32.c
@@ -218,7 +218,7 @@ static inline int is_setting_trap_flag(struct task_struct *child, struct pt_regs
return 0;
}

-static void set_singlestep(struct task_struct *child)
+void user_enable_single_step(struct task_struct *child)
{
struct pt_regs *regs = get_child_regs(child);

@@ -249,7 +249,7 @@ static void set_singlestep(struct task_struct *child)
child->ptrace |= PT_DTRACE;
}

-static void clear_singlestep(struct task_struct *child)
+void user_disable_single_step(struct task_struct *child)
{
/* Always clear TIF_SINGLESTEP... */
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
@@ -269,7 +269,7 @@ static void clear_singlestep(struct task_struct *child)
*/
void ptrace_disable(struct task_struct *child)
{
- clear_singlestep(child);
+ user_disable_single_step(child);
clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
}

@@ -403,7 +403,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
}
child->exit_code = data;
/* make sure the single step bit is not set. */
- clear_singlestep(child);
+ user_disable_single_step(child);
wake_up_process(child);
ret = 0;
break;
@@ -419,7 +419,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
child->exit_code = SIGKILL;
/* make sure the single step bit is not set. */
- clear_singlestep(child);
+ user_disable_single_step(child);
wake_up_process(child);
break;

@@ -435,7 +435,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);

clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- set_singlestep(child);
+ user_enable_single_step(child);
child->exit_code = data;
/* give it a chance to run. */
wake_up_process(child);
diff --git a/arch/x86/kernel/ptrace_64.c b/arch/x86/kernel/ptrace_64.c
index e907e2e..c2e1a13 100644
--- a/arch/x86/kernel/ptrace_64.c
+++ b/arch/x86/kernel/ptrace_64.c
@@ -170,7 +170,7 @@ static int is_setting_trap_flag(struct task_struct *child, struct pt_regs *regs)
return 0;
}

-static void set_singlestep(struct task_struct *child)
+void user_enable_single_step(struct task_struct *child)
{
struct pt_regs *regs = task_pt_regs(child);

@@ -201,7 +201,7 @@ static void set_singlestep(struct task_struct *child)
child->ptrace |= PT_DTRACE;
}

-static void clear_singlestep(struct task_struct *child)
+void user_disable_single_step(struct task_struct *child)
{
/* Always clear TIF_SINGLESTEP... */
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
@@ -221,7 +221,7 @@ static void clear_singlestep(struct task_struct *child)
*/
void ptrace_disable(struct task_struct *child)
{
- clear_singlestep(child);
+ user_disable_single_step(child);
}

static int putreg(struct task_struct *child,
@@ -461,7 +461,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
child->exit_code = data;
/* make sure the single step bit is not set. */
- clear_singlestep(child);
+ user_disable_single_step(child);
wake_up_process(child);
ret = 0;
break;
@@ -504,7 +504,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
child->exit_code = SIGKILL;
/* make sure the single step bit is not set. */
- clear_singlestep(child);
+ user_disable_single_step(child);
wake_up_process(child);
break;

@@ -513,7 +513,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
if (!valid_signal(data))
break;
clear_tsk_thread_flag(child,TIF_SYSCALL_TRACE);
- set_singlestep(child);
+ user_enable_single_step(child);
child->exit_code = data;
/* give it a chance to run. */
wake_up_process(child);
diff --git a/include/asm-x86/ptrace.h b/include/asm-x86/ptrace.h
index 105d153..fe75422 100644
--- a/include/asm-x86/ptrace.h
+++ b/include/asm-x86/ptrace.h
@@ -140,6 +140,13 @@ enum {

#ifdef __KERNEL__

+/*
+ * These are defined as per linux/ptrace.h, which see.
+ */
+#define arch_has_single_step() (1)
+extern void user_enable_single_step(struct task_struct *);
+extern void user_disable_single_step(struct task_struct *);
+
struct user_desc;
extern int do_get_thread_area(struct task_struct *p, int idx,
struct user_desc __user *info);

2007-11-25 21:59:48

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 03/27] x86: remove TRAP_FLAG


This gets rid of the local constant macro TRAP_FLAG.
It's redundant with the public constant macro X86_EFLAGS_TF.

Signed-off-by: Roland McGrath <[email protected]>
---
arch/x86/kernel/ptrace_32.c | 9 +++------
arch/x86/kernel/ptrace_64.c | 9 +++------
2 files changed, 6 insertions(+), 12 deletions(-)

diff --git a/arch/x86/kernel/ptrace_32.c b/arch/x86/kernel/ptrace_32.c
index 39a94a0..2b4fcb5 100644
--- a/arch/x86/kernel/ptrace_32.c
+++ b/arch/x86/kernel/ptrace_32.c
@@ -37,9 +37,6 @@
*/
#define FLAG_MASK 0x00050dd5

-/* set's the trap flag. */
-#define TRAP_FLAG 0x100
-
/*
* Offset of eflags on child stack..
*/
@@ -235,11 +232,11 @@ static void set_singlestep(struct task_struct *child)
/*
* If TF was already set, don't do anything else
*/
- if (regs->eflags & TRAP_FLAG)
+ if (regs->eflags & X86_EFLAGS_TF)
return;

/* Set TF on the kernel stack.. */
- regs->eflags |= TRAP_FLAG;
+ regs->eflags |= X86_EFLAGS_TF;

/*
* ..but if TF is changed by the instruction we will trace,
@@ -260,7 +257,7 @@ static void clear_singlestep(struct task_struct *child)
/* But touch TF only if it was set by us.. */
if (child->ptrace & PT_DTRACE) {
struct pt_regs *regs = get_child_regs(child);
- regs->eflags &= ~TRAP_FLAG;
+ regs->eflags &= ~X86_EFLAGS_TF;
child->ptrace &= ~PT_DTRACE;
}
}
diff --git a/arch/x86/kernel/ptrace_64.c b/arch/x86/kernel/ptrace_64.c
index 07de75d..e907e2e 100644
--- a/arch/x86/kernel/ptrace_64.c
+++ b/arch/x86/kernel/ptrace_64.c
@@ -42,9 +42,6 @@
*/
#define FLAG_MASK 0x54dd5UL

-/* set's the trap flag. */
-#define TRAP_FLAG 0x100UL
-
/*
* eflags and offset of eflags on child stack..
*/
@@ -187,11 +184,11 @@ static void set_singlestep(struct task_struct *child)
/*
* If TF was already set, don't do anything else
*/
- if (regs->eflags & TRAP_FLAG)
+ if (regs->eflags & X86_EFLAGS_TF)
return;

/* Set TF on the kernel stack.. */
- regs->eflags |= TRAP_FLAG;
+ regs->eflags |= X86_EFLAGS_TF;

/*
* ..but if TF is changed by the instruction we will trace,
@@ -212,7 +209,7 @@ static void clear_singlestep(struct task_struct *child)
/* But touch TF only if it was set by us.. */
if (child->ptrace & PT_DTRACE) {
struct pt_regs *regs = task_pt_regs(child);
- regs->eflags &= ~TRAP_FLAG;
+ regs->eflags &= ~X86_EFLAGS_TF;
child->ptrace &= ~PT_DTRACE;
}
}

2007-11-25 22:00:30

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 07/27] x86: single_step 0xf0


This fixes the 64-bit single-step handling code's instruction
decoder to grok the 0xf0 (lock) prefix, which the 32-bit code
already does correctly.

Signed-off-by: Roland McGrath <[email protected]>
---
arch/x86/kernel/step.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/x86/kernel/step.c b/arch/x86/kernel/step.c
index 3b70f20..6a93b93 100644
--- a/arch/x86/kernel/step.c
+++ b/arch/x86/kernel/step.c
@@ -66,7 +66,7 @@ static int is_setting_trap_flag(struct task_struct *child, struct pt_regs *regs)
case 0x26: case 0x2e:
case 0x36: case 0x3e:
case 0x64: case 0x65:
- case 0xf2: case 0xf3:
+ case 0xf0: case 0xf2: case 0xf3:
continue;

case 0x40 ... 0x4f:

2007-11-25 22:00:45

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 05/27] x86: single_step moved


This moves the single-step support code from ptrace_64.c into a new file
step.c, verbatim. This paves the way for consolidating this code between
64-bit and 32-bit versions.

Signed-off-by: Roland McGrath <[email protected]>
---
arch/x86/kernel/Makefile_64 | 2 +
arch/x86/kernel/ptrace_64.c | 134 -----------------------------------------
arch/x86/kernel/step.c | 140 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 142 insertions(+), 134 deletions(-)

diff --git a/arch/x86/kernel/Makefile_64 b/arch/x86/kernel/Makefile_64
index 203a9d8..d35ee6f 100644
--- a/arch/x86/kernel/Makefile_64
+++ b/arch/x86/kernel/Makefile_64
@@ -13,6 +13,8 @@ obj-y := process_64.o signal_64.o entry_64.o traps_64.o irq_64.o \
pci-dma_64.o pci-nommu_64.o alternative.o hpet.o tsc_64.o bugs_64.o \
i8253.o

+obj-y += step.o
+
obj-$(CONFIG_IA32_EMULATION) += tls.o

obj-$(CONFIG_STACKTRACE) += stacktrace.o
diff --git a/arch/x86/kernel/ptrace_64.c b/arch/x86/kernel/ptrace_64.c
index c2e1a13..52479b1 100644
--- a/arch/x86/kernel/ptrace_64.c
+++ b/arch/x86/kernel/ptrace_64.c
@@ -80,140 +80,6 @@ static inline long put_stack_long(struct task_struct *task, int offset,
return 0;
}

-#define LDT_SEGMENT 4
-
-unsigned long convert_rip_to_linear(struct task_struct *child, struct pt_regs *regs)
-{
- unsigned long addr, seg;
-
- addr = regs->rip;
- seg = regs->cs & 0xffff;
-
- /*
- * We'll assume that the code segments in the GDT
- * are all zero-based. That is largely true: the
- * TLS segments are used for data, and the PNPBIOS
- * and APM bios ones we just ignore here.
- */
- if (seg & LDT_SEGMENT) {
- u32 *desc;
- unsigned long base;
-
- seg &= ~7UL;
-
- mutex_lock(&child->mm->context.lock);
- if (unlikely((seg >> 3) >= child->mm->context.size))
- addr = -1L; /* bogus selector, access would fault */
- else {
- desc = child->mm->context.ldt + seg;
- base = ((desc[0] >> 16) |
- ((desc[1] & 0xff) << 16) |
- (desc[1] & 0xff000000));
-
- /* 16-bit code segment? */
- if (!((desc[1] >> 22) & 1))
- addr &= 0xffff;
- addr += base;
- }
- mutex_unlock(&child->mm->context.lock);
- }
-
- return addr;
-}
-
-static int is_setting_trap_flag(struct task_struct *child, struct pt_regs *regs)
-{
- int i, copied;
- unsigned char opcode[15];
- unsigned long addr = convert_rip_to_linear(child, regs);
-
- copied = access_process_vm(child, addr, opcode, sizeof(opcode), 0);
- for (i = 0; i < copied; i++) {
- switch (opcode[i]) {
- /* popf and iret */
- case 0x9d: case 0xcf:
- return 1;
-
- /* CHECKME: 64 65 */
-
- /* opcode and address size prefixes */
- case 0x66: case 0x67:
- continue;
- /* irrelevant prefixes (segment overrides and repeats) */
- case 0x26: case 0x2e:
- case 0x36: case 0x3e:
- case 0x64: case 0x65:
- case 0xf2: case 0xf3:
- continue;
-
- case 0x40 ... 0x4f:
- if (regs->cs != __USER_CS)
- /* 32-bit mode: register increment */
- return 0;
- /* 64-bit mode: REX prefix */
- continue;
-
- /* CHECKME: f2, f3 */
-
- /*
- * pushf: NOTE! We should probably not let
- * the user see the TF bit being set. But
- * it's more pain than it's worth to avoid
- * it, and a debugger could emulate this
- * all in user space if it _really_ cares.
- */
- case 0x9c:
- default:
- return 0;
- }
- }
- return 0;
-}
-
-void user_enable_single_step(struct task_struct *child)
-{
- struct pt_regs *regs = task_pt_regs(child);
-
- /*
- * Always set TIF_SINGLESTEP - this guarantees that
- * we single-step system calls etc.. This will also
- * cause us to set TF when returning to user mode.
- */
- set_tsk_thread_flag(child, TIF_SINGLESTEP);
-
- /*
- * If TF was already set, don't do anything else
- */
- if (regs->eflags & X86_EFLAGS_TF)
- return;
-
- /* Set TF on the kernel stack.. */
- regs->eflags |= X86_EFLAGS_TF;
-
- /*
- * ..but if TF is changed by the instruction we will trace,
- * don't mark it as being "us" that set it, so that we
- * won't clear it by hand later.
- */
- if (is_setting_trap_flag(child, regs))
- return;
-
- child->ptrace |= PT_DTRACE;
-}
-
-void user_disable_single_step(struct task_struct *child)
-{
- /* Always clear TIF_SINGLESTEP... */
- clear_tsk_thread_flag(child, TIF_SINGLESTEP);
-
- /* But touch TF only if it was set by us.. */
- if (child->ptrace & PT_DTRACE) {
- struct pt_regs *regs = task_pt_regs(child);
- regs->eflags &= ~X86_EFLAGS_TF;
- child->ptrace &= ~PT_DTRACE;
- }
-}
-
/*
* Called by kernel/ptrace.c when detaching..
*
diff --git a/arch/x86/kernel/step.c b/arch/x86/kernel/step.c
new file mode 100644
index 0000000..cb3c8bc
--- /dev/null
+++ b/arch/x86/kernel/step.c
@@ -0,0 +1,140 @@
+/*
+ * x86 single-step support code, common to 32-bit and 64-bit.
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/ptrace.h>
+
+#define LDT_SEGMENT 4
+
+unsigned long convert_rip_to_linear(struct task_struct *child, struct pt_regs *regs)
+{
+ unsigned long addr, seg;
+
+ addr = regs->rip;
+ seg = regs->cs & 0xffff;
+
+ /*
+ * We'll assume that the code segments in the GDT
+ * are all zero-based. That is largely true: the
+ * TLS segments are used for data, and the PNPBIOS
+ * and APM bios ones we just ignore here.
+ */
+ if (seg & LDT_SEGMENT) {
+ u32 *desc;
+ unsigned long base;
+
+ seg &= ~7UL;
+
+ mutex_lock(&child->mm->context.lock);
+ if (unlikely((seg >> 3) >= child->mm->context.size))
+ addr = -1L; /* bogus selector, access would fault */
+ else {
+ desc = child->mm->context.ldt + seg;
+ base = ((desc[0] >> 16) |
+ ((desc[1] & 0xff) << 16) |
+ (desc[1] & 0xff000000));
+
+ /* 16-bit code segment? */
+ if (!((desc[1] >> 22) & 1))
+ addr &= 0xffff;
+ addr += base;
+ }
+ mutex_unlock(&child->mm->context.lock);
+ }
+
+ return addr;
+}
+
+static int is_setting_trap_flag(struct task_struct *child, struct pt_regs *regs)
+{
+ int i, copied;
+ unsigned char opcode[15];
+ unsigned long addr = convert_rip_to_linear(child, regs);
+
+ copied = access_process_vm(child, addr, opcode, sizeof(opcode), 0);
+ for (i = 0; i < copied; i++) {
+ switch (opcode[i]) {
+ /* popf and iret */
+ case 0x9d: case 0xcf:
+ return 1;
+
+ /* CHECKME: 64 65 */
+
+ /* opcode and address size prefixes */
+ case 0x66: case 0x67:
+ continue;
+ /* irrelevant prefixes (segment overrides and repeats) */
+ case 0x26: case 0x2e:
+ case 0x36: case 0x3e:
+ case 0x64: case 0x65:
+ case 0xf2: case 0xf3:
+ continue;
+
+ case 0x40 ... 0x4f:
+ if (regs->cs != __USER_CS)
+ /* 32-bit mode: register increment */
+ return 0;
+ /* 64-bit mode: REX prefix */
+ continue;
+
+ /* CHECKME: f2, f3 */
+
+ /*
+ * pushf: NOTE! We should probably not let
+ * the user see the TF bit being set. But
+ * it's more pain than it's worth to avoid
+ * it, and a debugger could emulate this
+ * all in user space if it _really_ cares.
+ */
+ case 0x9c:
+ default:
+ return 0;
+ }
+ }
+ return 0;
+}
+
+void user_enable_single_step(struct task_struct *child)
+{
+ struct pt_regs *regs = task_pt_regs(child);
+
+ /*
+ * Always set TIF_SINGLESTEP - this guarantees that
+ * we single-step system calls etc.. This will also
+ * cause us to set TF when returning to user mode.
+ */
+ set_tsk_thread_flag(child, TIF_SINGLESTEP);
+
+ /*
+ * If TF was already set, don't do anything else
+ */
+ if (regs->eflags & X86_EFLAGS_TF)
+ return;
+
+ /* Set TF on the kernel stack.. */
+ regs->eflags |= X86_EFLAGS_TF;
+
+ /*
+ * ..but if TF is changed by the instruction we will trace,
+ * don't mark it as being "us" that set it, so that we
+ * won't clear it by hand later.
+ */
+ if (is_setting_trap_flag(child, regs))
+ return;
+
+ child->ptrace |= PT_DTRACE;
+}
+
+void user_disable_single_step(struct task_struct *child)
+{
+ /* Always clear TIF_SINGLESTEP... */
+ clear_tsk_thread_flag(child, TIF_SINGLESTEP);
+
+ /* But touch TF only if it was set by us.. */
+ if (child->ptrace & PT_DTRACE) {
+ struct pt_regs *regs = task_pt_regs(child);
+ regs->eflags &= ~X86_EFLAGS_TF;
+ child->ptrace &= ~PT_DTRACE;
+ }
+}

2007-11-25 22:01:00

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 06/27] x86: single_step segment macros


This cleans up the single-step code to use the asm/segment.h macros
for segment selector magic bits, rather than its own constant.

Signed-off-by: Roland McGrath <[email protected]>
---
arch/x86/kernel/step.c | 4 +---
1 files changed, 1 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kernel/step.c b/arch/x86/kernel/step.c
index cb3c8bc..3b70f20 100644
--- a/arch/x86/kernel/step.c
+++ b/arch/x86/kernel/step.c
@@ -5,8 +5,6 @@
#include <linux/mm.h>
#include <linux/ptrace.h>

-#define LDT_SEGMENT 4
-
unsigned long convert_rip_to_linear(struct task_struct *child, struct pt_regs *regs)
{
unsigned long addr, seg;
@@ -20,7 +18,7 @@ unsigned long convert_rip_to_linear(struct task_struct *child, struct pt_regs *r
* TLS segments are used for data, and the PNPBIOS
* and APM bios ones we just ignore here.
*/
- if (seg & LDT_SEGMENT) {
+ if ((seg & SEGMENT_TI_MASK) == SEGMENT_LDT) {
u32 *desc;
unsigned long base;

2007-11-25 22:01:22

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 08/27] x86: single_step: share code


This removes the single-step code from ptrace_32.c and uses the step.c code
shared with the 64-bit kernel. The two versions of the code were nearly
identical already, so the shared code has only a couple of simple #ifdef's.

Signed-off-by: Roland McGrath <[email protected]>
---
arch/x86/kernel/Makefile_32 | 1 +
arch/x86/kernel/ptrace_32.c | 125 -------------------------------------------
arch/x86/kernel/step.c | 14 +++++
3 files changed, 15 insertions(+), 125 deletions(-)

diff --git a/arch/x86/kernel/Makefile_32 b/arch/x86/kernel/Makefile_32
index e660584..959ad3c 100644
--- a/arch/x86/kernel/Makefile_32
+++ b/arch/x86/kernel/Makefile_32
@@ -11,6 +11,7 @@ obj-y := process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \
quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o

obj-y += tls.o
+obj-y += step.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-y += cpu/
obj-y += acpi/
diff --git a/arch/x86/kernel/ptrace_32.c b/arch/x86/kernel/ptrace_32.c
index d1d74e1..e599db5 100644
--- a/arch/x86/kernel/ptrace_32.c
+++ b/arch/x86/kernel/ptrace_32.c
@@ -137,131 +137,6 @@ static unsigned long getreg(struct task_struct *child,
return retval;
}

-#define LDT_SEGMENT 4
-
-static unsigned long convert_eip_to_linear(struct task_struct *child, struct pt_regs *regs)
-{
- unsigned long addr, seg;
-
- addr = regs->eip;
- seg = regs->xcs & 0xffff;
- if (regs->eflags & VM_MASK) {
- addr = (addr & 0xffff) + (seg << 4);
- return addr;
- }
-
- /*
- * We'll assume that the code segments in the GDT
- * are all zero-based. That is largely true: the
- * TLS segments are used for data, and the PNPBIOS
- * and APM bios ones we just ignore here.
- */
- if (seg & LDT_SEGMENT) {
- u32 *desc;
- unsigned long base;
-
- seg &= ~7UL;
-
- mutex_lock(&child->mm->context.lock);
- if (unlikely((seg >> 3) >= child->mm->context.size))
- addr = -1L; /* bogus selector, access would fault */
- else {
- desc = child->mm->context.ldt + seg;
- base = ((desc[0] >> 16) |
- ((desc[1] & 0xff) << 16) |
- (desc[1] & 0xff000000));
-
- /* 16-bit code segment? */
- if (!((desc[1] >> 22) & 1))
- addr &= 0xffff;
- addr += base;
- }
- mutex_unlock(&child->mm->context.lock);
- }
- return addr;
-}
-
-static inline int is_setting_trap_flag(struct task_struct *child, struct pt_regs *regs)
-{
- int i, copied;
- unsigned char opcode[15];
- unsigned long addr = convert_eip_to_linear(child, regs);
-
- copied = access_process_vm(child, addr, opcode, sizeof(opcode), 0);
- for (i = 0; i < copied; i++) {
- switch (opcode[i]) {
- /* popf and iret */
- case 0x9d: case 0xcf:
- return 1;
- /* opcode and address size prefixes */
- case 0x66: case 0x67:
- continue;
- /* irrelevant prefixes (segment overrides and repeats) */
- case 0x26: case 0x2e:
- case 0x36: case 0x3e:
- case 0x64: case 0x65:
- case 0xf0: case 0xf2: case 0xf3:
- continue;
-
- /*
- * pushf: NOTE! We should probably not let
- * the user see the TF bit being set. But
- * it's more pain than it's worth to avoid
- * it, and a debugger could emulate this
- * all in user space if it _really_ cares.
- */
- case 0x9c:
- default:
- return 0;
- }
- }
- return 0;
-}
-
-void user_enable_single_step(struct task_struct *child)
-{
- struct pt_regs *regs = get_child_regs(child);
-
- /*
- * Always set TIF_SINGLESTEP - this guarantees that
- * we single-step system calls etc.. This will also
- * cause us to set TF when returning to user mode.
- */
- set_tsk_thread_flag(child, TIF_SINGLESTEP);
-
- /*
- * If TF was already set, don't do anything else
- */
- if (regs->eflags & X86_EFLAGS_TF)
- return;
-
- /* Set TF on the kernel stack.. */
- regs->eflags |= X86_EFLAGS_TF;
-
- /*
- * ..but if TF is changed by the instruction we will trace,
- * don't mark it as being "us" that set it, so that we
- * won't clear it by hand later.
- */
- if (is_setting_trap_flag(child, regs))
- return;
-
- child->ptrace |= PT_DTRACE;
-}
-
-void user_disable_single_step(struct task_struct *child)
-{
- /* Always clear TIF_SINGLESTEP... */
- clear_tsk_thread_flag(child, TIF_SINGLESTEP);
-
- /* But touch TF only if it was set by us.. */
- if (child->ptrace & PT_DTRACE) {
- struct pt_regs *regs = get_child_regs(child);
- regs->eflags &= ~X86_EFLAGS_TF;
- child->ptrace &= ~PT_DTRACE;
- }
-}
-
/*
* Called by kernel/ptrace.c when detaching..
*
diff --git a/arch/x86/kernel/step.c b/arch/x86/kernel/step.c
index 6a93b93..6732272 100644
--- a/arch/x86/kernel/step.c
+++ b/arch/x86/kernel/step.c
@@ -5,12 +5,24 @@
#include <linux/mm.h>
#include <linux/ptrace.h>

+#ifdef CONFIG_X86_32
+static
+#endif
unsigned long convert_rip_to_linear(struct task_struct *child, struct pt_regs *regs)
{
unsigned long addr, seg;

+#ifdef CONFIG_X86_64
addr = regs->rip;
seg = regs->cs & 0xffff;
+#else
+ addr = regs->eip;
+ seg = regs->xcs & 0xffff;
+ if (regs->eflags & X86_EFLAGS_VM) {
+ addr = (addr & 0xffff) + (seg << 4);
+ return addr;
+ }
+#endif

/*
* We'll assume that the code segments in the GDT
@@ -69,12 +81,14 @@ static int is_setting_trap_flag(struct task_struct *child, struct pt_regs *regs)
case 0xf0: case 0xf2: case 0xf3:
continue;

+#ifdef CONFIG_X86_64
case 0x40 ... 0x4f:
if (regs->cs != __USER_CS)
/* 32-bit mode: register increment */
return 0;
/* 64-bit mode: REX prefix */
continue;
+#endif

/* CHECKME: f2, f3 */

2007-11-25 22:01:37

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 09/27] x86 single_step: TIF_FORCED_TF


This changes the single-step support to use a new thread_info flag
TIF_FORCED_TF instead of the PT_DTRACE flag in task_struct.ptrace.
This keeps arch implementation uses out of this non-arch field.

This changes the ptrace access to eflags to mask TF and maintain
the TIF_FORCED_TF flag directly if userland sets TF, instead of
relying on ptrace_signal_deliver. The 64-bit and 32-bit kernels
are harmonized on this same behavior. The ptrace_signal_deliver
approach works now, but this change makes the low-level register
access code reliable when called from different contexts than a
ptrace stop, which will be possible in the future.

The 64-bit do_debug exception handler is also changed not to clear TF
from user-mode registers. This matches the 32-bit kernel's behavior.

Signed-off-by: Roland McGrath <[email protected]>
---
arch/x86/ia32/ptrace32.c | 20 ++++++++++++++++++--
arch/x86/kernel/process_32.c | 3 ---
arch/x86/kernel/process_64.c | 5 -----
arch/x86/kernel/ptrace_32.c | 17 +++++++++++++++++
arch/x86/kernel/ptrace_64.c | 20 ++++++++++++++++++++
arch/x86/kernel/signal_32.c | 12 +++++-------
arch/x86/kernel/signal_64.c | 14 +++++---------
arch/x86/kernel/step.c | 9 +++------
arch/x86/kernel/traps_64.c | 23 +++++------------------
include/asm-x86/signal.h | 11 ++---------
include/asm-x86/thread_info_32.h | 2 ++
include/asm-x86/thread_info_64.h | 3 ++-
12 files changed, 79 insertions(+), 60 deletions(-)

diff --git a/arch/x86/ia32/ptrace32.c b/arch/x86/ia32/ptrace32.c
index 4a233ad..a9a5cd4 100644
--- a/arch/x86/ia32/ptrace32.c
+++ b/arch/x86/ia32/ptrace32.c
@@ -82,6 +82,15 @@ static int putreg32(struct task_struct *child, unsigned regno, u32 val)
case offsetof(struct user32, regs.eflags): {
__u64 *flags = &stack[offsetof(struct pt_regs, eflags)/8];
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;
*flags = val | (*flags & ~FLAG_MASK);
break;
}
@@ -168,9 +177,17 @@ static int getreg32(struct task_struct *child, unsigned regno, u32 *val)
R32(eax, rax);
R32(orig_eax, orig_rax);
R32(eip, rip);
- R32(eflags, eflags);
R32(esp, rsp);

+ case offsetof(struct user32, regs.eflags):
+ /*
+ * If the debugger set TF, hide it from the readout.
+ */
+ *val = stack[offsetof(struct pt_regs, eflags)/8];
+ if (test_tsk_thread_flag(child, TIF_FORCED_TF))
+ *val &= ~X86_EFLAGS_TF;
+ break;
+
case offsetof(struct user32, u_debugreg[0]):
*val = child->thread.debugreg0;
break;
@@ -401,4 +418,3 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
put_task_struct(child);
return ret;
}
-
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index ebbbfc5..f59544e 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -796,9 +796,6 @@ asmlinkage int sys_execve(struct pt_regs regs)
(char __user * __user *) regs.edx,
&regs);
if (error == 0) {
- task_lock(current);
- current->ptrace &= ~PT_DTRACE;
- task_unlock(current);
/* Make sure we don't return using sysenter.. */
set_thread_flag(TIF_IRET);
}
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 3fdbf78..586f88e 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -698,11 +698,6 @@ long sys_execve(char __user *name, char __user * __user *argv,
if (IS_ERR(filename))
return error;
error = do_execve(filename, argv, envp, &regs);
- if (error == 0) {
- task_lock(current);
- current->ptrace &= ~PT_DTRACE;
- task_unlock(current);
- }
putname(filename);
return error;
}
diff --git a/arch/x86/kernel/ptrace_32.c b/arch/x86/kernel/ptrace_32.c
index e599db5..a493017 100644
--- a/arch/x86/kernel/ptrace_32.c
+++ b/arch/x86/kernel/ptrace_32.c
@@ -104,6 +104,15 @@ static int putreg(struct task_struct *child,
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 |= get_stack_long(child, EFL_OFFSET) & ~FLAG_MASK;
break;
}
@@ -119,6 +128,14 @@ static unsigned long getreg(struct task_struct *child,
unsigned long retval = ~0UL;

switch (regno >> 2) {
+ case EFL:
+ /*
+ * If the debugger set TF, hide it from the readout.
+ */
+ retval = get_stack_long(child, EFL_OFFSET);
+ if (test_tsk_thread_flag(child, TIF_FORCED_TF))
+ retval &= ~X86_EFLAGS_TF;
+ break;
case GS:
retval = child->thread.gs;
break;
diff --git a/arch/x86/kernel/ptrace_64.c b/arch/x86/kernel/ptrace_64.c
index 52479b1..d8453da 100644
--- a/arch/x86/kernel/ptrace_64.c
+++ b/arch/x86/kernel/ptrace_64.c
@@ -143,6 +143,15 @@ static int putreg(struct task_struct *child,
return 0;
case offsetof(struct user_regs_struct, eflags):
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;
tmp = get_stack_long(child, EFL_OFFSET);
tmp &= ~FLAG_MASK;
value |= tmp;
@@ -189,6 +198,17 @@ static unsigned long getreg(struct task_struct *child, unsigned long regno)
if (child->thread.gsindex != GS_TLS_SEL)
return 0;
return get_desc_base(&child->thread.tls_array[GS_TLS]);
+ case offsetof(struct user_regs_struct, eflags):
+ /*
+ * If the debugger set TF, hide it from the readout.
+ */
+ regno = regno - sizeof(struct pt_regs);
+ val = get_stack_long(child, regno);
+ 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:
regno = regno - sizeof(struct pt_regs);
val = get_stack_long(child, regno);
diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c
index 9bdd830..d58d455 100644
--- a/arch/x86/kernel/signal_32.c
+++ b/arch/x86/kernel/signal_32.c
@@ -537,14 +537,12 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
}

/*
- * If TF is set due to a debugger (PT_DTRACE), clear the TF flag so
- * that register information in the sigcontext is correct.
+ * If TF is set due to a debugger (TIF_FORCED_TF), clear the TF
+ * flag so that register information in the sigcontext is correct.
*/
- if (unlikely(regs->eflags & TF_MASK)
- && likely(current->ptrace & PT_DTRACE)) {
- current->ptrace &= ~PT_DTRACE;
- regs->eflags &= ~TF_MASK;
- }
+ if (unlikely(regs->eflags & X86_EFLAGS_TF) &&
+ likely(test_and_clear_thread_flag(TIF_FORCED_TF)))
+ regs->eflags &= ~X86_EFLAGS_TF;

/* Set up the stack frame */
if (ka->sa.sa_flags & SA_SIGINFO)
diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c
index ab086b0..d96a8c2 100644
--- a/arch/x86/kernel/signal_64.c
+++ b/arch/x86/kernel/signal_64.c
@@ -349,16 +349,12 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
}

/*
- * If TF is set due to a debugger (PT_DTRACE), clear the TF
- * flag so that register information in the sigcontext is
- * correct.
+ * If TF is set due to a debugger (TIF_FORCED_TF), clear the TF
+ * flag so that register information in the sigcontext is correct.
*/
- if (unlikely(regs->eflags & TF_MASK)) {
- if (likely(current->ptrace & PT_DTRACE)) {
- current->ptrace &= ~PT_DTRACE;
- regs->eflags &= ~TF_MASK;
- }
- }
+ if (unlikely(regs->eflags & X86_EFLAGS_TF) &&
+ likely(test_and_clear_thread_flag(TIF_FORCED_TF)))
+ regs->eflags &= ~X86_EFLAGS_TF;

#ifdef CONFIG_IA32_EMULATION
if (test_thread_flag(TIF_IA32)) {
diff --git a/arch/x86/kernel/step.c b/arch/x86/kernel/step.c
index 6732272..243bff6 100644
--- a/arch/x86/kernel/step.c
+++ b/arch/x86/kernel/step.c
@@ -135,7 +135,7 @@ void user_enable_single_step(struct task_struct *child)
if (is_setting_trap_flag(child, regs))
return;

- child->ptrace |= PT_DTRACE;
+ set_tsk_thread_flag(child, TIF_FORCED_TF);
}

void user_disable_single_step(struct task_struct *child)
@@ -144,9 +144,6 @@ void user_disable_single_step(struct task_struct *child)
clear_tsk_thread_flag(child, TIF_SINGLESTEP);

/* But touch TF only if it was set by us.. */
- if (child->ptrace & PT_DTRACE) {
- struct pt_regs *regs = task_pt_regs(child);
- regs->eflags &= ~X86_EFLAGS_TF;
- child->ptrace &= ~PT_DTRACE;
- }
+ if (test_and_clear_tsk_thread_flag(child, TIF_FORCED_TF))
+ task_pt_regs(child)->eflags &= ~X86_EFLAGS_TF;
}
diff --git a/arch/x86/kernel/traps_64.c b/arch/x86/kernel/traps_64.c
index 4a6bd49..daf35a8 100644
--- a/arch/x86/kernel/traps_64.c
+++ b/arch/x86/kernel/traps_64.c
@@ -863,27 +863,14 @@ asmlinkage void __kprobes do_debug(struct pt_regs * regs,

tsk->thread.debugreg6 = condition;

- /* Mask out spurious TF errors due to lazy TF clearing */
+
+ /*
+ * Single-stepping through TF: make sure we ignore any events in
+ * kernel space (but re-enable TF when returning to user mode).
+ */
if (condition & DR_STEP) {
- /*
- * The TF error should be masked out only if the current
- * process is not traced and if the TRAP flag has been set
- * previously by a tracing process (condition detected by
- * the PT_DTRACE flag); remember that the i386 TRAP flag
- * can be modified by the process itself in user mode,
- * allowing programs to debug themselves without the ptrace()
- * interface.
- */
if (!user_mode(regs))
goto clear_TF_reenable;
- /*
- * Was the TF flag set by a debugger? If so, clear it now,
- * so that register information is correct.
- */
- if (tsk->ptrace & PT_DTRACE) {
- regs->eflags &= ~TF_MASK;
- tsk->ptrace &= ~PT_DTRACE;
- }
}

/* Ok, finally something we can handle */
diff --git a/include/asm-x86/signal.h b/include/asm-x86/signal.h
index 987a422..aee7eca 100644
--- a/include/asm-x86/signal.h
+++ b/include/asm-x86/signal.h
@@ -245,21 +245,14 @@ static __inline__ int sigfindinword(unsigned long word)

struct pt_regs;

-#define ptrace_signal_deliver(regs, cookie) \
- do { \
- if (current->ptrace & PT_DTRACE) { \
- current->ptrace &= ~PT_DTRACE; \
- (regs)->eflags &= ~TF_MASK; \
- } \
- } while (0)
-
#else /* __i386__ */

#undef __HAVE_ARCH_SIG_BITOPS

+#endif /* !__i386__ */
+
#define ptrace_signal_deliver(regs, cookie) do { } while (0)

-#endif /* !__i386__ */
#endif /* __KERNEL__ */
#endif /* __ASSEMBLY__ */

diff --git a/include/asm-x86/thread_info_32.h b/include/asm-x86/thread_info_32.h
index 22a8cbc..8a6483f 100644
--- a/include/asm-x86/thread_info_32.h
+++ b/include/asm-x86/thread_info_32.h
@@ -137,6 +137,7 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_IO_BITMAP 18 /* uses I/O bitmap */
#define TIF_FREEZE 19 /* is freezing for suspend */
#define TIF_NOTSC 20 /* TSC is not accessible in userland */
+#define TIF_FORCED_TF 21 /* true if TF in eflags artificially */

#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
@@ -151,6 +152,7 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_IO_BITMAP (1<<TIF_IO_BITMAP)
#define _TIF_FREEZE (1<<TIF_FREEZE)
#define _TIF_NOTSC (1<<TIF_NOTSC)
+#define _TIF_FORCED_TF (1<<TIF_FORCED_TF)

/* work to do on interrupt/exception return */
#define _TIF_WORK_MASK \
diff --git a/include/asm-x86/thread_info_64.h b/include/asm-x86/thread_info_64.h
index beae2bf..0ebcac4 100644
--- a/include/asm-x86/thread_info_64.h
+++ b/include/asm-x86/thread_info_64.h
@@ -115,7 +115,7 @@ static inline struct thread_info *stack_thread_info(void)
#define TIF_SECCOMP 8 /* secure computing */
#define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal */
#define TIF_MCE_NOTIFY 10 /* notify userspace of an MCE */
-/* 16 free */
+#define TIF_FORCED_TF 16 /* true if TF in eflags artificially */
#define TIF_IA32 17 /* 32bit process */
#define TIF_FORK 18 /* ret_from_fork */
#define TIF_ABI_PENDING 19
@@ -133,6 +133,7 @@ static inline struct thread_info *stack_thread_info(void)
#define _TIF_SECCOMP (1<<TIF_SECCOMP)
#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
#define _TIF_MCE_NOTIFY (1<<TIF_MCE_NOTIFY)
+#define _TIF_FORCED_TF (1<<TIF_FORCED_TF)
#define _TIF_IA32 (1<<TIF_IA32)
#define _TIF_FORK (1<<TIF_FORK)
#define _TIF_ABI_PENDING (1<<TIF_ABI_PENDING)

2007-11-25 22:01:52

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 12/27] x86-32: ptrace generic resume


This removes the handling for PTRACE_CONT et al from the 32-bit
ptrace code, so it uses the new generic code via ptrace_request.

Signed-off-by: Roland McGrath <[email protected]>
---
arch/x86/kernel/ptrace_32.c | 57 -------------------------------------------
1 files changed, 0 insertions(+), 57 deletions(-)

diff --git a/arch/x86/kernel/ptrace_32.c b/arch/x86/kernel/ptrace_32.c
index a493017..50882b3 100644
--- a/arch/x86/kernel/ptrace_32.c
+++ b/arch/x86/kernel/ptrace_32.c
@@ -277,63 +277,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
}
break;

- case PTRACE_SYSEMU: /* continue and stop at next syscall, which will not be executed */
- case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
- case PTRACE_CONT: /* restart after signal. */
- ret = -EIO;
- if (!valid_signal(data))
- break;
- if (request == PTRACE_SYSEMU) {
- set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- } else if (request == PTRACE_SYSCALL) {
- set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
- } else {
- clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- }
- child->exit_code = data;
- /* make sure the single step bit is not set. */
- user_disable_single_step(child);
- wake_up_process(child);
- ret = 0;
- break;
-
-/*
- * make the child exit. Best I can do is send it a sigkill.
- * perhaps it should be put in the status that it wants to
- * exit.
- */
- case PTRACE_KILL:
- ret = 0;
- if (child->exit_state == EXIT_ZOMBIE) /* already dead */
- break;
- child->exit_code = SIGKILL;
- /* make sure the single step bit is not set. */
- user_disable_single_step(child);
- wake_up_process(child);
- break;
-
- case PTRACE_SYSEMU_SINGLESTEP: /* Same as SYSEMU, but singlestep if not syscall */
- case PTRACE_SINGLESTEP: /* set the trap flag. */
- ret = -EIO;
- if (!valid_signal(data))
- break;
-
- if (request == PTRACE_SYSEMU_SINGLESTEP)
- set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
- else
- clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
-
- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- user_enable_single_step(child);
- child->exit_code = data;
- /* give it a chance to run. */
- wake_up_process(child);
- ret = 0;
- break;
-
case PTRACE_GETREGS: { /* Get all gp regs from the child. */
if (!access_ok(VERIFY_WRITE, datap, FRAME_SIZE*sizeof(long))) {
ret = -EIO;

2007-11-25 22:02:15

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 10/27] ptrace: generic resume


This makes ptrace_request handle all the ptrace requests that wake
up the traced task. These do low-level ptrace implementation magic
that is not arch-specific and should be kept out of arch code. The
implementations on each arch usually do the same thing. The new
generic code makes use of the arch_has_single_step macro and generic
entry points to handle PTRACE_SINGLESTEP.

Signed-off-by: Roland McGrath <[email protected]>
---
kernel/ptrace.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 61 insertions(+), 0 deletions(-)

diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 7c76f2f..309796a 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -366,6 +366,50 @@ static int ptrace_setsiginfo(struct task_struct *child, siginfo_t __user * data)
return error;
}

+
+#ifdef PTRACE_SINGLESTEP
+#define is_singlestep(request) ((request) == PTRACE_SINGLESTEP)
+#else
+#define is_singlestep(request) 0
+#endif
+
+#ifdef PTRACE_SYSEMU
+#define is_sysemu_singlestep(request) ((request) == PTRACE_SYSEMU_SINGLESTEP)
+#else
+#define is_sysemu_singlestep(request) 0
+#endif
+
+static int ptrace_resume(struct task_struct *child, long request, long data)
+{
+ if (!valid_signal(data))
+ return -EIO;
+
+ if (request == PTRACE_SYSCALL)
+ set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ else
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+
+#ifdef TIF_SYSCALL_EMU
+ if (request == PTRACE_SYSEMU || request == PTRACE_SYSEMU_SINGLESTEP)
+ set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+ else
+ clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+#endif
+
+ if (is_singlestep(request) || is_sysemu_singlestep(request)) {
+ if (unlikely(!arch_has_single_step()))
+ return -EIO;
+ user_enable_single_step(child);
+ }
+ else
+ user_disable_single_step(child);
+
+ child->exit_code = data;
+ wake_up_process(child);
+
+ return 0;
+}
+
int ptrace_request(struct task_struct *child, long request,
long addr, long data)
{
@@ -390,6 +434,23 @@ int ptrace_request(struct task_struct *child, long request,
case PTRACE_DETACH: /* detach a process that was attached. */
ret = ptrace_detach(child, data);
break;
+
+#ifdef PTRACE_SINGLESTEP
+ case PTRACE_SINGLESTEP:
+#endif
+#ifdef PTRACE_SYSEMU
+ case PTRACE_SYSEMU:
+ case PTRACE_SYSEMU_SINGLESTEP:
+#endif
+ case PTRACE_SYSCALL:
+ case PTRACE_CONT:
+ return ptrace_resume(child, request, data);
+
+ case PTRACE_KILL:
+ if (child->exit_state) /* already dead */
+ return 0;
+ return ptrace_resume(child, request, SIGKILL);
+
default:
break;
}

2007-11-25 22:02:33

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 11/27] x86-64: ptrace generic resume


This removes the handling for PTRACE_CONT et al from the 64-bit
ptrace code, so it uses the new generic code via ptrace_request.

Signed-off-by: Roland McGrath <[email protected]>
---
arch/x86/kernel/ptrace_64.c | 45 -------------------------------------------
1 files changed, 0 insertions(+), 45 deletions(-)

diff --git a/arch/x86/kernel/ptrace_64.c b/arch/x86/kernel/ptrace_64.c
index d8453da..85fba7b 100644
--- a/arch/x86/kernel/ptrace_64.c
+++ b/arch/x86/kernel/ptrace_64.c
@@ -334,23 +334,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
}
break;
}
- case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
- case PTRACE_CONT: /* restart after signal. */
-
- ret = -EIO;
- if (!valid_signal(data))
- break;
- if (request == PTRACE_SYSCALL)
- set_tsk_thread_flag(child,TIF_SYSCALL_TRACE);
- else
- clear_tsk_thread_flag(child,TIF_SYSCALL_TRACE);
- clear_tsk_thread_flag(child, TIF_SINGLESTEP);
- child->exit_code = data;
- /* make sure the single step bit is not set. */
- user_disable_single_step(child);
- wake_up_process(child);
- ret = 0;
- break;

#ifdef CONFIG_IA32_EMULATION
/* This makes only sense with 32bit programs. Allow a
@@ -378,34 +361,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
ret = do_arch_prctl(child, data, addr);
break;

-/*
- * make the child exit. Best I can do is send it a sigkill.
- * perhaps it should be put in the status that it wants to
- * exit.
- */
- case PTRACE_KILL:
- ret = 0;
- if (child->exit_state == EXIT_ZOMBIE) /* already dead */
- break;
- clear_tsk_thread_flag(child, TIF_SINGLESTEP);
- child->exit_code = SIGKILL;
- /* make sure the single step bit is not set. */
- user_disable_single_step(child);
- wake_up_process(child);
- break;
-
- case PTRACE_SINGLESTEP: /* set the trap flag. */
- ret = -EIO;
- if (!valid_signal(data))
- break;
- clear_tsk_thread_flag(child,TIF_SYSCALL_TRACE);
- user_enable_single_step(child);
- child->exit_code = data;
- /* give it a chance to run. */
- wake_up_process(child);
- ret = 0;
- break;
-
case PTRACE_GETREGS: { /* Get all gp regs from the child. */
if (!access_ok(VERIFY_WRITE, (unsigned __user *)data,
sizeof(struct user_regs_struct))) {

2007-11-25 22:04:20

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 14/27] powerpc: ptrace generic resume


This removes the handling for PTRACE_CONT et al from the powerpc
ptrace code, so it uses the new generic code via ptrace_request.

Signed-off-by: Roland McGrath <[email protected]>
---
arch/powerpc/kernel/ptrace.c | 46 ------------------------------------------
1 files changed, 0 insertions(+), 46 deletions(-)

diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index b970d79..8b056d2 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -445,52 +445,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
}

- case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
- case PTRACE_CONT: { /* restart after signal. */
- ret = -EIO;
- if (!valid_signal(data))
- break;
- if (request == PTRACE_SYSCALL)
- set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- else
- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- child->exit_code = data;
- /* make sure the single step bit is not set. */
- user_disable_single_step(child);
- wake_up_process(child);
- ret = 0;
- break;
- }
-
-/*
- * make the child exit. Best I can do is send it a sigkill.
- * perhaps it should be put in the status that it wants to
- * exit.
- */
- case PTRACE_KILL: {
- ret = 0;
- if (child->exit_state == EXIT_ZOMBIE) /* already dead */
- break;
- child->exit_code = SIGKILL;
- /* make sure the single step bit is not set. */
- user_disable_single_step(child);
- wake_up_process(child);
- break;
- }
-
- case PTRACE_SINGLESTEP: { /* set the trap flag. */
- ret = -EIO;
- if (!valid_signal(data))
- break;
- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- user_enable_single_step(child);
- child->exit_code = data;
- /* give it a chance to run. */
- wake_up_process(child);
- ret = 0;
- break;
- }
-
case PTRACE_GET_DEBUGREG: {
ret = -EINVAL;
/* We only support one DABR and no IABRS at the moment */

2007-11-25 22:04:35

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 13/27] powerpc: arch_has_single_step


This defines the new standard arch_has_single_step macro. It makes the
existing set_single_step and clear_single_step entry points global, and
renames them to the new standard names user_enable_single_step and
user_disable_single_step, respectively.

Signed-off-by: Roland McGrath <[email protected]>
---
arch/powerpc/kernel/ptrace.c | 12 ++++++------
include/asm-powerpc/ptrace.h | 7 +++++++
2 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 3e17d15..b970d79 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -256,7 +256,7 @@ static int set_evrregs(struct task_struct *task, unsigned long *data)
#endif /* CONFIG_SPE */


-static void set_single_step(struct task_struct *task)
+void user_enable_single_step(struct task_struct *task)
{
struct pt_regs *regs = task->thread.regs;

@@ -271,7 +271,7 @@ static void set_single_step(struct task_struct *task)
set_tsk_thread_flag(task, TIF_SINGLESTEP);
}

-static void clear_single_step(struct task_struct *task)
+void user_disable_single_step(struct task_struct *task)
{
struct pt_regs *regs = task->thread.regs;

@@ -313,7 +313,7 @@ static int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
void ptrace_disable(struct task_struct *child)
{
/* make sure the single step bit is not set. */
- clear_single_step(child);
+ user_disable_single_step(child);
}

/*
@@ -456,7 +456,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
child->exit_code = data;
/* make sure the single step bit is not set. */
- clear_single_step(child);
+ user_disable_single_step(child);
wake_up_process(child);
ret = 0;
break;
@@ -473,7 +473,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
child->exit_code = SIGKILL;
/* make sure the single step bit is not set. */
- clear_single_step(child);
+ user_disable_single_step(child);
wake_up_process(child);
break;
}
@@ -483,7 +483,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
if (!valid_signal(data))
break;
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- set_single_step(child);
+ user_enable_single_step(child);
child->exit_code = data;
/* give it a chance to run. */
wake_up_process(child);
diff --git a/include/asm-powerpc/ptrace.h b/include/asm-powerpc/ptrace.h
index 13fccc5..3063363 100644
--- a/include/asm-powerpc/ptrace.h
+++ b/include/asm-powerpc/ptrace.h
@@ -119,6 +119,13 @@ do { \
} while (0)
#endif /* __powerpc64__ */

+/*
+ * These are defined as per linux/ptrace.h, which see.
+ */
+#define arch_has_single_step() (1)
+extern void user_enable_single_step(struct task_struct *);
+extern void user_disable_single_step(struct task_struct *);
+
#endif /* __ASSEMBLY__ */

#endif /* __KERNEL__ */

2007-11-25 22:04:51

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 15/27] x86-32 ptrace: use task_pt_regs


This cleans up the 32-bit ptrace code to use task_pt_regs instead of its
own redundant code that does the same thing a different way.

Signed-off-by: Roland McGrath <[email protected]>
---
arch/x86/kernel/ptrace_32.c | 68 ++++++++++--------------------------------
1 files changed, 16 insertions(+), 52 deletions(-)

diff --git a/arch/x86/kernel/ptrace_32.c b/arch/x86/kernel/ptrace_32.c
index 50882b3..7c33244 100644
--- a/arch/x86/kernel/ptrace_32.c
+++ b/arch/x86/kernel/ptrace_32.c
@@ -37,53 +37,20 @@
*/
#define FLAG_MASK 0x00050dd5

-/*
- * Offset of eflags on child stack..
- */
-#define EFL_OFFSET offsetof(struct pt_regs, eflags)
-
-static inline struct pt_regs *get_child_regs(struct task_struct *task)
-{
- void *stack_top = (void *)task->thread.esp0;
- return stack_top - sizeof(struct pt_regs);
-}
-
-/*
- * This routine will get a word off of the processes privileged stack.
- * the offset is bytes into the pt_regs structure on the stack.
- * This routine assumes that all the privileged stacks are in our
- * data space.
- */
-static inline int get_stack_long(struct task_struct *task, int offset)
+static long *pt_regs_access(struct pt_regs *regs, unsigned long regno)
{
- unsigned char *stack;
-
- stack = (unsigned char *)task->thread.esp0 - sizeof(struct pt_regs);
- stack += offset;
- return (*((int *)stack));
-}
-
-/*
- * This routine will put a word on the processes privileged stack.
- * the offset is bytes into the pt_regs structure on the stack.
- * This routine assumes that all the privileged stacks are in our
- * data space.
- */
-static inline int put_stack_long(struct task_struct *task, int offset,
- unsigned long data)
-{
- unsigned char * stack;
-
- stack = (unsigned char *)task->thread.esp0 - sizeof(struct pt_regs);
- stack += offset;
- *(unsigned long *) stack = data;
- return 0;
+ BUILD_BUG_ON(offsetof(struct pt_regs, ebx) != 0);
+ if (regno > FS)
+ --regno;
+ return &regs->ebx + regno;
}

static int putreg(struct task_struct *child,
unsigned long regno, unsigned long value)
{
- switch (regno >> 2) {
+ struct pt_regs *regs = task_pt_regs(child);
+ regno >>= 2;
+ switch (regno) {
case GS:
if (value && (value & 3) != 3)
return -EIO;
@@ -113,26 +80,25 @@ static int putreg(struct task_struct *child,
clear_tsk_thread_flag(child, TIF_FORCED_TF);
else if (test_tsk_thread_flag(child, TIF_FORCED_TF))
value |= X86_EFLAGS_TF;
- value |= get_stack_long(child, EFL_OFFSET) & ~FLAG_MASK;
+ value |= regs->eflags & ~FLAG_MASK;
break;
}
- if (regno > FS*4)
- regno -= 1*4;
- put_stack_long(child, regno, value);
+ *pt_regs_access(regs, regno) = value;
return 0;
}

-static unsigned long getreg(struct task_struct *child,
- unsigned long regno)
+static unsigned long getreg(struct task_struct *child, unsigned long regno)
{
+ struct pt_regs *regs = task_pt_regs(child);
unsigned long retval = ~0UL;

- switch (regno >> 2) {
+ regno >>= 2;
+ switch (regno) {
case EFL:
/*
* If the debugger set TF, hide it from the readout.
*/
- retval = get_stack_long(child, EFL_OFFSET);
+ retval = regs->eflags;
if (test_tsk_thread_flag(child, TIF_FORCED_TF))
retval &= ~X86_EFLAGS_TF;
break;
@@ -147,9 +113,7 @@ static unsigned long getreg(struct task_struct *child,
retval = 0xffff;
/* fall through */
default:
- if (regno > FS*4)
- regno -= 1*4;
- retval &= get_stack_long(child, regno);
+ retval &= *pt_regs_access(regs, regno);
}
return retval;
}

2007-11-25 22:05:46

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 16/27] x86-64 ptrace: use task_pt_regs


This cleans up the 64-bit ptrace code to use task_pt_regs instead of its
own redundant code that does the same thing a different way.

Signed-off-by: Roland McGrath <[email protected]>
---
arch/x86/kernel/ptrace_64.c | 60 ++++++++----------------------------------
1 files changed, 12 insertions(+), 48 deletions(-)

diff --git a/arch/x86/kernel/ptrace_64.c b/arch/x86/kernel/ptrace_64.c
index 85fba7b..8123ecb 100644
--- a/arch/x86/kernel/ptrace_64.c
+++ b/arch/x86/kernel/ptrace_64.c
@@ -43,44 +43,6 @@
#define FLAG_MASK 0x54dd5UL

/*
- * eflags and offset of eflags on child stack..
- */
-#define EFLAGS offsetof(struct pt_regs, eflags)
-#define EFL_OFFSET ((int)(EFLAGS-sizeof(struct pt_regs)))
-
-/*
- * this routine will get a word off of the processes privileged stack.
- * the offset is how far from the base addr as stored in the TSS.
- * this routine assumes that all the privileged stacks are in our
- * data space.
- */
-static inline unsigned long get_stack_long(struct task_struct *task, int offset)
-{
- unsigned char *stack;
-
- stack = (unsigned char *)task->thread.rsp0;
- stack += offset;
- return (*((unsigned long *)stack));
-}
-
-/*
- * this routine will put a word on the processes privileged stack.
- * the offset is how far from the base addr as stored in the TSS.
- * this routine assumes that all the privileged stacks are in our
- * data space.
- */
-static inline long put_stack_long(struct task_struct *task, int offset,
- unsigned long data)
-{
- unsigned char * stack;
-
- stack = (unsigned char *) task->thread.rsp0;
- stack += offset;
- *(unsigned long *) stack = data;
- return 0;
-}
-
-/*
* Called by kernel/ptrace.c when detaching..
*
* Make sure the single step bit is not set.
@@ -90,11 +52,16 @@ 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)
{
- unsigned long tmp;
-
+ struct pt_regs *regs = task_pt_regs(child);
switch (regno) {
case offsetof(struct user_regs_struct,fs):
if (value && (value & 3) != 3)
@@ -152,9 +119,7 @@ static int putreg(struct task_struct *child,
clear_tsk_thread_flag(child, TIF_FORCED_TF);
else if (test_tsk_thread_flag(child, TIF_FORCED_TF))
value |= X86_EFLAGS_TF;
- tmp = get_stack_long(child, EFL_OFFSET);
- tmp &= ~FLAG_MASK;
- value |= tmp;
+ value |= regs->eflags & ~FLAG_MASK;
break;
case offsetof(struct user_regs_struct,cs):
if ((value & 3) != 3)
@@ -162,12 +127,13 @@ static int putreg(struct task_struct *child,
value &= 0xffff;
break;
}
- put_stack_long(child, regno - sizeof(struct pt_regs), value);
+ *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;
switch (regno) {
case offsetof(struct user_regs_struct, fs):
@@ -202,16 +168,14 @@ static unsigned long getreg(struct task_struct *child, unsigned long regno)
/*
* If the debugger set TF, hide it from the readout.
*/
- regno = regno - sizeof(struct pt_regs);
- val = get_stack_long(child, regno);
+ val = regs->eflags;
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:
- regno = regno - sizeof(struct pt_regs);
- val = get_stack_long(child, regno);
+ val = *pt_regs_access(regs, regno);
if (test_tsk_thread_flag(child, TIF_IA32))
val &= 0xffffffff;
return val;

2007-11-25 22:06:26

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 18/27] x86-64 ia32 ptrace debugreg cleanup


This cleans up the ia32 compat ptrace code to use shared code from
native ptrace for the implementation guts of debug register access.

Signed-off-by: Roland McGrath <[email protected]>
---
arch/x86/ia32/ptrace32.c | 63 ++++++----------------------------------------
1 files changed, 8 insertions(+), 55 deletions(-)

diff --git a/arch/x86/ia32/ptrace32.c b/arch/x86/ia32/ptrace32.c
index a9a5cd4..5661abd 100644
--- a/arch/x86/ia32/ptrace32.c
+++ b/arch/x86/ia32/ptrace32.c
@@ -40,7 +40,6 @@

static int putreg32(struct task_struct *child, unsigned regno, u32 val)
{
- int i;
__u64 *stack = (__u64 *)task_pt_regs(child);

switch (regno) {
@@ -95,43 +94,10 @@ static int putreg32(struct task_struct *child, unsigned regno, u32 val)
break;
}

- case offsetof(struct user32, u_debugreg[4]):
- case offsetof(struct user32, u_debugreg[5]):
- return -EIO;
-
- case offsetof(struct user32, u_debugreg[0]):
- child->thread.debugreg0 = val;
- break;
-
- case offsetof(struct user32, u_debugreg[1]):
- child->thread.debugreg1 = val;
- break;
-
- case offsetof(struct user32, u_debugreg[2]):
- child->thread.debugreg2 = val;
- break;
-
- case offsetof(struct user32, u_debugreg[3]):
- child->thread.debugreg3 = val;
- break;
-
- case offsetof(struct user32, u_debugreg[6]):
- child->thread.debugreg6 = val;
- break;
-
- case offsetof(struct user32, u_debugreg[7]):
- val &= ~DR_CONTROL_RESERVED;
- /* See arch/i386/kernel/ptrace.c for an explanation of
- * this awkward check.*/
- for(i=0; i<4; i++)
- if ((0x5454 >> ((val >> (16 + 4*i)) & 0xf)) & 1)
- return -EIO;
- child->thread.debugreg7 = val;
- if (val)
- set_tsk_thread_flag(child, TIF_DEBUG);
- else
- clear_tsk_thread_flag(child, TIF_DEBUG);
- 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))
@@ -188,23 +154,10 @@ static int getreg32(struct task_struct *child, unsigned regno, u32 *val)
*val &= ~X86_EFLAGS_TF;
break;

- case offsetof(struct user32, u_debugreg[0]):
- *val = child->thread.debugreg0;
- break;
- case offsetof(struct user32, u_debugreg[1]):
- *val = child->thread.debugreg1;
- break;
- case offsetof(struct user32, u_debugreg[2]):
- *val = child->thread.debugreg2;
- break;
- case offsetof(struct user32, u_debugreg[3]):
- *val = child->thread.debugreg3;
- break;
- case offsetof(struct user32, u_debugreg[6]):
- *val = child->thread.debugreg6;
- break;
- case offsetof(struct user32, u_debugreg[7]):
- *val = child->thread.debugreg7;
+ 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:

2007-11-25 22:06:42

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 17/27] x86-64 ptrace debugreg cleanup


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 <[email protected]>
---
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);

2007-11-25 22:06:59

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 19/27] x86-32 ptrace debugreg cleanup


This cleans up the 32-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 match the
new 64-bit entry points for parity, but they don't need to be global.

Signed-off-by: Roland McGrath <[email protected]>
---
arch/x86/kernel/ptrace_32.c | 119 +++++++++++++++++++++++++------------------
1 files changed, 69 insertions(+), 50 deletions(-)

diff --git a/arch/x86/kernel/ptrace_32.c b/arch/x86/kernel/ptrace_32.c
index 7c33244..0aa3756 100644
--- a/arch/x86/kernel/ptrace_32.c
+++ b/arch/x86/kernel/ptrace_32.c
@@ -119,6 +119,72 @@ static unsigned long getreg(struct task_struct *child, unsigned long regno)
}

/*
+ * 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)
+{
+ return child->thread.debugreg[n];
+}
+
+static int ptrace_set_debugreg(struct task_struct *child,
+ int n, unsigned long data)
+{
+ if (unlikely(n == 4 || n == 5))
+ return -EIO;
+
+ if (n < 4 && unlikely(data >= TASK_SIZE - 3))
+ return -EIO;
+
+ if (n == 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)
+ */
+ int i;
+ data &= ~DR_CONTROL_RESERVED;
+ for (i = 0; i < 4; i++)
+ if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
+ return -EIO;
+ if (data)
+ set_tsk_thread_flag(child, TIF_DEBUG);
+ else
+ clear_tsk_thread_flag(child, TIF_DEBUG);
+ }
+
+ child->thread.debugreg[n] = data;
+
+ return 0;
+}
+
+/*
* Called by kernel/ptrace.c when detaching..
*
* Make sure the single step bit is not set.
@@ -158,7 +224,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
addr <= (long) &dummy->u_debugreg[7]){
addr -= (long) &dummy->u_debugreg[0];
addr = addr >> 2;
- tmp = child->thread.debugreg[addr];
+ tmp = ptrace_get_debugreg(child, addr);
}
ret = put_user(tmp, datap);
break;
@@ -188,56 +254,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
ret = -EIO;
if(addr >= (long) &dummy->u_debugreg[0] &&
addr <= (long) &dummy->u_debugreg[7]){
-
- if(addr == (long) &dummy->u_debugreg[4]) break;
- if(addr == (long) &dummy->u_debugreg[5]) break;
- if(addr < (long) &dummy->u_debugreg[4] &&
- ((unsigned long) data) >= TASK_SIZE-3) break;
-
- /* 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)*/
-
- if(addr == (long) &dummy->u_debugreg[7]) {
- data &= ~DR_CONTROL_RESERVED;
- for(i=0; i<4; i++)
- if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
- goto out_tsk;
- if (data)
- set_tsk_thread_flag(child, TIF_DEBUG);
- else
- clear_tsk_thread_flag(child, TIF_DEBUG);
- }
addr -= (long) &dummy->u_debugreg;
addr = addr >> 2;
- child->thread.debugreg[addr] = data;
- ret = 0;
+ ret = ptrace_set_debugreg(child, addr, data);
}
break;

@@ -335,7 +354,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
ret = ptrace_request(child, request, addr, data);
break;
}
- out_tsk:
+
return ret;
}

2007-11-25 22:07:49

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 21/27] ptrace: generic PTRACE_SINGLEBLOCK


This makes ptrace_request handle PTRACE_SINGLEBLOCK along with
PTRACE_CONT et al. The new generic code makes use of the
arch_has_block_step macro and generic entry points on machines
that define them.

Signed-off-by: Roland McGrath <[email protected]>
---
kernel/ptrace.c | 15 ++++++++++++++-
1 files changed, 14 insertions(+), 1 deletions(-)

diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 309796a..2824726 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -373,6 +373,12 @@ static int ptrace_setsiginfo(struct task_struct *child, siginfo_t __user * data)
#define is_singlestep(request) 0
#endif

+#ifdef PTRACE_SINGLEBLOCK
+#define is_singleblock(request) ((request) == PTRACE_SINGLEBLOCK)
+#else
+#define is_singleblock(request) 0
+#endif
+
#ifdef PTRACE_SYSEMU
#define is_sysemu_singlestep(request) ((request) == PTRACE_SYSEMU_SINGLESTEP)
#else
@@ -396,7 +402,11 @@ static int ptrace_resume(struct task_struct *child, long request, long data)
clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
#endif

- if (is_singlestep(request) || is_sysemu_singlestep(request)) {
+ if (is_singleblock(request)) {
+ if (unlikely(!arch_has_block_step()))
+ return -EIO;
+ user_enable_block_step(child);
+ } else if (is_singlestep(request) || is_sysemu_singlestep(request)) {
if (unlikely(!arch_has_single_step()))
return -EIO;
user_enable_single_step(child);
@@ -438,6 +448,9 @@ int ptrace_request(struct task_struct *child, long request,
#ifdef PTRACE_SINGLESTEP
case PTRACE_SINGLESTEP:
#endif
+#ifdef PTRACE_SINGLEBLOCK
+ case PTRACE_SINGLEBLOCK:
+#endif
#ifdef PTRACE_SYSEMU
case PTRACE_SYSEMU:
case PTRACE_SYSEMU_SINGLESTEP:

2007-11-25 22:08:10

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 22/27] x86: debugctlmsr constants


This adds constant macros for a few of the bits in MSR_IA32_DEBUGCTLMSR.

Signed-off-by: Roland McGrath <[email protected]>
---
include/asm-x86/msr-index.h | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/include/asm-x86/msr-index.h b/include/asm-x86/msr-index.h
index a494473..4045bbe 100644
--- a/include/asm-x86/msr-index.h
+++ b/include/asm-x86/msr-index.h
@@ -63,6 +63,13 @@
#define MSR_IA32_LASTINTFROMIP 0x000001dd
#define MSR_IA32_LASTINTTOIP 0x000001de

+/* DEBUGCTLMSR bits (others vary by model): */
+#define _DEBUGCTLMSR_LBR 0 /* last branch recording */
+#define _DEBUGCTLMSR_BTF 1 /* single-step on branches */
+
+#define DEBUGCTLMSR_LBR (1UL << _DEBUGCTLMSR_LBR)
+#define DEBUGCTLMSR_BTF (1UL << _DEBUGCTLMSR_BTF)
+
#define MSR_IA32_MC0_CTL 0x00000400
#define MSR_IA32_MC0_STATUS 0x00000401
#define MSR_IA32_MC0_ADDR 0x00000402

2007-11-25 22:08:34

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 23/27] x86: debugctlmsr kconfig


This adds the (internal) Kconfig macro CONFIG_X86_DEBUGCTLMSR,
to be defined when configuring to support only hardware that
definitely supports MSR_IA32_DEBUGCTLMSR with the BTF flag.

The Intel documentation says "P6 family" and later processors all have it.
I think the Kconfig dependencies are right to have it set for those and
unset for others (i.e., when 586 and earlier are supported).

Signed-off-by: Roland McGrath <[email protected]>
---
arch/x86/Kconfig.cpu | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu
index c301622..69e2ee4 100644
--- a/arch/x86/Kconfig.cpu
+++ b/arch/x86/Kconfig.cpu
@@ -399,3 +399,7 @@ config X86_MINIMUM_CPU_FAMILY
default "4" if X86_32 && (X86_XADD || X86_CMPXCHG || X86_BSWAP || X86_WP_WORKS_OK)
default "3"

+config X86_DEBUGCTLMSR
+ bool
+ depends on !(M586MMX || M586TSC || M586 || M486 || M386)
+ default y

2007-11-25 22:08:49

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 24/27] x86: debugctlmsr context switch


This adds low-level support for a per-thread value of MSR_IA32_DEBUGCTLMSR.
The per-thread value is switched in when TIF_DEBUGCTLMSR is set.

Signed-off-by: Roland McGrath <[email protected]>
---
arch/x86/kernel/process_32.c | 6 +++++-
arch/x86/kernel/process_64.c | 3 +++
include/asm-x86/processor_32.h | 2 ++
include/asm-x86/processor_64.h | 2 ++
include/asm-x86/thread_info_32.h | 6 ++++--
include/asm-x86/thread_info_64.h | 4 +++-
6 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index f59544e..3a822e3 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -581,10 +581,14 @@ static noinline void
__switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
struct tss_struct *tss)
{
- struct thread_struct *next;
+ struct thread_struct *prev, *next;

+ prev = &prev_p->thread;
next = &next_p->thread;

+ if (next->debugctlmsr != prev->debugctlmsr)
+ 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);
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 586f88e..c1e2e9a 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -544,6 +544,9 @@ static inline void __switch_to_xtra(struct task_struct *prev_p,
prev = &prev_p->thread,
next = &next_p->thread;

+ if (next->debugctlmsr != prev->debugctlmsr)
+ wrmsrl(MSR_IA32_DEBUGCTLMSR, next->debugctlmsr);
+
if (test_tsk_thread_flag(next_p, TIF_DEBUG)) {
loaddebug(next, 0);
loaddebug(next, 1);
diff --git a/include/asm-x86/processor_32.h b/include/asm-x86/processor_32.h
index 34e8063..660d9b0 100644
--- a/include/asm-x86/processor_32.h
+++ b/include/asm-x86/processor_32.h
@@ -370,6 +370,8 @@ struct thread_struct {
unsigned long iopl;
/* max allowed port in the bitmap, in bytes: */
unsigned long io_bitmap_max;
+/* MSR_IA32_DEBUGCTLMSR value to switch in if TIF_DEBUGCTLMSR is set. */
+ unsigned long debugctlmsr;
};

#define INIT_THREAD { \
diff --git a/include/asm-x86/processor_64.h b/include/asm-x86/processor_64.h
index 2dd739a..1d6daa0 100644
--- a/include/asm-x86/processor_64.h
+++ b/include/asm-x86/processor_64.h
@@ -239,6 +239,8 @@ struct thread_struct {
int ioperm;
unsigned long *io_bitmap_ptr;
unsigned io_bitmap_max;
+/* MSR_IA32_DEBUGCTLMSR value to switch in if TIF_DEBUGCTLMSR is set. */
+ unsigned long debugctlmsr;
/* cached TLS descriptors. */
u64 tls_array[GDT_ENTRY_TLS_ENTRIES];
} __attribute__((aligned(16)));
diff --git a/include/asm-x86/thread_info_32.h b/include/asm-x86/thread_info_32.h
index 8a6483f..d5ae1e9 100644
--- a/include/asm-x86/thread_info_32.h
+++ b/include/asm-x86/thread_info_32.h
@@ -138,6 +138,7 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_FREEZE 19 /* is freezing for suspend */
#define TIF_NOTSC 20 /* TSC is not accessible in userland */
#define TIF_FORCED_TF 21 /* true if TF in eflags artificially */
+#define TIF_DEBUGCTLMSR 22 /* uses thread_struct.debugctlmsr */

#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
@@ -153,6 +154,7 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_FREEZE (1<<TIF_FREEZE)
#define _TIF_NOTSC (1<<TIF_NOTSC)
#define _TIF_FORCED_TF (1<<TIF_FORCED_TF)
+#define _TIF_DEBUGCTLMSR (1<<TIF_DEBUGCTLMSR)

/* work to do on interrupt/exception return */
#define _TIF_WORK_MASK \
@@ -162,8 +164,8 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_ALLWORK_MASK (0x0000FFFF & ~_TIF_SECCOMP)

/* flags to check in __switch_to() */
-#define _TIF_WORK_CTXSW_NEXT (_TIF_IO_BITMAP | _TIF_NOTSC | _TIF_DEBUG)
-#define _TIF_WORK_CTXSW_PREV (_TIF_IO_BITMAP | _TIF_NOTSC)
+#define _TIF_WORK_CTXSW_NEXT (_TIF_IO_BITMAP | _TIF_NOTSC | _TIF_DEBUG | _TIF_DEBUGCTLMSR)
+#define _TIF_WORK_CTXSW_PREV (_TIF_IO_BITMAP | _TIF_NOTSC | _TIF_DEBUGCTLMSR)

/*
* Thread-synchronous status.
diff --git a/include/asm-x86/thread_info_64.h b/include/asm-x86/thread_info_64.h
index 0ebcac4..8f36bbc 100644
--- a/include/asm-x86/thread_info_64.h
+++ b/include/asm-x86/thread_info_64.h
@@ -123,6 +123,7 @@ static inline struct thread_info *stack_thread_info(void)
#define TIF_DEBUG 21 /* uses debug registers */
#define TIF_IO_BITMAP 22 /* uses I/O bitmap */
#define TIF_FREEZE 23 /* is freezing for suspend */
+#define TIF_DEBUGCTLMSR 24 /* uses thread_struct.debugctlmsr */

#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
@@ -140,6 +141,7 @@ static inline struct thread_info *stack_thread_info(void)
#define _TIF_DEBUG (1<<TIF_DEBUG)
#define _TIF_IO_BITMAP (1<<TIF_IO_BITMAP)
#define _TIF_FREEZE (1<<TIF_FREEZE)
+#define _TIF_DEBUGCTLMSR (1<<TIF_DEBUGCTLMSR)

/* work to do on interrupt/exception return */
#define _TIF_WORK_MASK \
@@ -148,7 +150,7 @@ static inline struct thread_info *stack_thread_info(void)
#define _TIF_ALLWORK_MASK (0x0000FFFF & ~_TIF_SECCOMP)

/* flags to check in __switch_to() */
-#define _TIF_WORK_CTXSW (_TIF_DEBUG|_TIF_IO_BITMAP)
+#define _TIF_WORK_CTXSW (_TIF_DEBUG|_TIF_IO_BITMAP|_TIF_DEBUGCTLMSR)

#define PREEMPT_ACTIVE 0x10000000

2007-11-25 22:09:25

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 26/27] x86: debugctlmsr kprobes


This adjusts the x86 kprobes implementation to cope with per-thread
MSR_IA32_DEBUGCTLMSR being set for user mode. I haven't delved deep
enough into the kprobes code to be really sure this covers all the
cases where the user-mode BTF setting needs to be cleared or restored.
It looks about right to me.

Signed-off-by: Roland McGrath <[email protected]>
---
arch/x86/kernel/kprobes_32.c | 15 +++++++++++++++
arch/x86/kernel/kprobes_64.c | 15 +++++++++++++++
2 files changed, 30 insertions(+), 0 deletions(-)

diff --git a/arch/x86/kernel/kprobes_32.c b/arch/x86/kernel/kprobes_32.c
index d87a523..f151f06 100644
--- a/arch/x86/kernel/kprobes_32.c
+++ b/arch/x86/kernel/kprobes_32.c
@@ -217,8 +217,21 @@ static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
kcb->kprobe_saved_eflags &= ~IF_MASK;
}

+static __always_inline void clear_btf(void)
+{
+ if (test_thread_flag(TIF_DEBUGCTLMSR))
+ wrmsr(MSR_IA32_DEBUGCTLMSR, 0, 0);
+}
+
+static __always_inline void restore_btf(void)
+{
+ if (test_thread_flag(TIF_DEBUGCTLMSR))
+ wrmsr(MSR_IA32_DEBUGCTLMSR, current->thread.debugctlmsr, 0);
+}
+
static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
{
+ clear_btf();
regs->eflags |= TF_MASK;
regs->eflags &= ~IF_MASK;
/*single step inline if the instruction is an int3*/
@@ -542,6 +555,8 @@ static void __kprobes resume_execution(struct kprobe *p,
regs->eip = orig_eip + (regs->eip - copy_eip);

no_change:
+ restore_btf();
+
return;
}

diff --git a/arch/x86/kernel/kprobes_64.c b/arch/x86/kernel/kprobes_64.c
index 3db3611..d3be418 100644
--- a/arch/x86/kernel/kprobes_64.c
+++ b/arch/x86/kernel/kprobes_64.c
@@ -256,8 +256,21 @@ static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
kcb->kprobe_saved_rflags &= ~IF_MASK;
}

+static __always_inline void clear_btf(void)
+{
+ if (test_thread_flag(TIF_DEBUGCTLMSR))
+ wrmsrl(MSR_IA32_DEBUGCTLMSR, 0);
+}
+
+static __always_inline void restore_btf(void)
+{
+ if (test_thread_flag(TIF_DEBUGCTLMSR))
+ wrmsrl(MSR_IA32_DEBUGCTLMSR, current->thread.debugctlmsr);
+}
+
static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
{
+ clear_btf();
regs->eflags |= TF_MASK;
regs->eflags &= ~IF_MASK;
/*single step inline if the instruction is an int3*/
@@ -534,6 +547,8 @@ static void __kprobes resume_execution(struct kprobe *p,
} else {
regs->rip = orig_rip + (regs->rip - copy_rip);
}
+
+ restore_btf();
}

int __kprobes post_kprobe_handler(struct pt_regs *regs)

2007-11-25 22:09:42

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 27/27] x86: PTRACE_SINGLEBLOCK


This adds the PTRACE_SINGLEBLOCK request on x86, matching the ia64 feature.
The implementation comes from the generic ptrace code and relies on the
low-level machine support provided by arch_has_block_step() et al.

Signed-off-by: Roland McGrath <[email protected]>
---
arch/x86/ia32/ptrace32.c | 1 +
include/asm-x86/ptrace-abi.h | 2 ++
2 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/arch/x86/ia32/ptrace32.c b/arch/x86/ia32/ptrace32.c
index 5661abd..d1fe78c 100644
--- a/arch/x86/ia32/ptrace32.c
+++ b/arch/x86/ia32/ptrace32.c
@@ -212,6 +212,7 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
case PTRACE_KILL:
case PTRACE_CONT:
case PTRACE_SINGLESTEP:
+ case PTRACE_SINGLEBLOCK:
case PTRACE_DETACH:
case PTRACE_SYSCALL:
case PTRACE_OLDSETOPTIONS:
diff --git a/include/asm-x86/ptrace-abi.h b/include/asm-x86/ptrace-abi.h
index 7524e12..adce6b5 100644
--- a/include/asm-x86/ptrace-abi.h
+++ b/include/asm-x86/ptrace-abi.h
@@ -78,4 +78,6 @@
# define PTRACE_SYSEMU_SINGLESTEP 32
#endif

+#define PTRACE_SINGLEBLOCK 33 /* resume execution until next branch */
+
#endif

2007-11-25 22:09:59

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 25/27] x86: debugctlmsr arch_has_block_step


This implements user-mode step-until-branch on x86 using the BTF bit
in MSR_IA32_DEBUGCTLMSR. It's just like single-step, only less so.

Signed-off-by: Roland McGrath <[email protected]>
---
arch/x86/kernel/step.c | 64 +++++++++++++++++++++++++++++++++++++++++--
arch/x86/kernel/traps_32.c | 6 ++++
arch/x86/kernel/traps_64.c | 6 ++++
include/asm-x86/ptrace.h | 7 +++++
4 files changed, 80 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kernel/step.c b/arch/x86/kernel/step.c
index 243bff6..cf4b9da 100644
--- a/arch/x86/kernel/step.c
+++ b/arch/x86/kernel/step.c
@@ -107,7 +107,10 @@ static int is_setting_trap_flag(struct task_struct *child, struct pt_regs *regs)
return 0;
}

-void user_enable_single_step(struct task_struct *child)
+/*
+ * Enable single-stepping. Return nonzero if user mode is not using TF itself.
+ */
+static int enable_single_step(struct task_struct *child)
{
struct pt_regs *regs = task_pt_regs(child);

@@ -122,7 +125,7 @@ void user_enable_single_step(struct task_struct *child)
* If TF was already set, don't do anything else
*/
if (regs->eflags & X86_EFLAGS_TF)
- return;
+ return 0;

/* Set TF on the kernel stack.. */
regs->eflags |= X86_EFLAGS_TF;
@@ -133,13 +136,68 @@ void user_enable_single_step(struct task_struct *child)
* won't clear it by hand later.
*/
if (is_setting_trap_flag(child, regs))
- return;
+ return 0;

set_tsk_thread_flag(child, TIF_FORCED_TF);
+
+ return 1;
+}
+
+/*
+ * Install this value in MSR_IA32_DEBUGCTLMSR whenever child is running.
+ */
+static void write_debugctlmsr(struct task_struct *child, unsigned long val)
+{
+ child->thread.debugctlmsr = val;
+
+ if (child != current)
+ return;
+
+#ifdef CONFIG_X86_64
+ wrmsrl(MSR_IA32_DEBUGCTLMSR, val);
+#else
+ wrmsr(MSR_IA32_DEBUGCTLMSR, val, 0);
+#endif
+}
+
+/*
+ * Enable single or block step.
+ */
+static void enable_step(struct task_struct *child, bool block)
+{
+ /*
+ * Make sure block stepping (BTF) is not enabled unless it should be.
+ * Note that we don't try to worry about any is_setting_trap_flag()
+ * instructions after the first when using block stepping.
+ * So noone should try to use debugger block stepping in a program
+ * that uses user-mode single stepping itself.
+ */
+ if (enable_single_step(child) && block) {
+ set_tsk_thread_flag(child, TIF_DEBUGCTLMSR);
+ write_debugctlmsr(child, DEBUGCTLMSR_BTF);
+ } else if (test_and_clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR)) {
+ write_debugctlmsr(child, 0);
+ }
+}
+
+void user_enable_single_step(struct task_struct *child)
+{
+ enable_step(child, 0);
+}
+
+void user_enable_block_step(struct task_struct *child)
+{
+ enable_step(child, 1);
}

void user_disable_single_step(struct task_struct *child)
{
+ /*
+ * Make sure block stepping (BTF) is disabled.
+ */
+ if (test_and_clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR))
+ write_debugctlmsr(child, 0);
+
/* Always clear TIF_SINGLESTEP... */
clear_tsk_thread_flag(child, TIF_SINGLESTEP);

diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c
index 298d13e..03d5b41 100644
--- a/arch/x86/kernel/traps_32.c
+++ b/arch/x86/kernel/traps_32.c
@@ -830,6 +830,12 @@ fastcall void __kprobes do_debug(struct pt_regs * regs, long error_code)

get_debugreg(condition, 6);

+ /*
+ * The processor cleared BTF, so don't mark that we need it set.
+ */
+ clear_tsk_thread_flag(tsk, TIF_DEBUGCTLMSR);
+ tsk->thread.debugctlmsr = 0;
+
if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
SIGTRAP) == NOTIFY_STOP)
return;
diff --git a/arch/x86/kernel/traps_64.c b/arch/x86/kernel/traps_64.c
index daf35a8..ec70f5c 100644
--- a/arch/x86/kernel/traps_64.c
+++ b/arch/x86/kernel/traps_64.c
@@ -848,6 +848,12 @@ asmlinkage void __kprobes do_debug(struct pt_regs * regs,

get_debugreg(condition, 6);

+ /*
+ * The processor cleared BTF, so don't mark that we need it set.
+ */
+ clear_tsk_thread_flag(tsk, TIF_DEBUGCTLMSR);
+ tsk->thread.debugctlmsr = 0;
+
if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
SIGTRAP) == NOTIFY_STOP)
return;
diff --git a/include/asm-x86/ptrace.h b/include/asm-x86/ptrace.h
index d223dec..04204f3 100644
--- a/include/asm-x86/ptrace.h
+++ b/include/asm-x86/ptrace.h
@@ -150,6 +150,13 @@ enum {
extern void user_enable_single_step(struct task_struct *);
extern void user_disable_single_step(struct task_struct *);

+extern void user_enable_block_step(struct task_struct *);
+#ifdef CONFIG_X86_DEBUGCTLMSR
+#define arch_has_block_step() (1)
+#else
+#define arch_has_block_step() (boot_cpu_data.x86 >= 6)
+#endif
+
struct user_desc;
extern int do_get_thread_area(struct task_struct *p, int idx,
struct user_desc __user *info);

2007-11-25 22:22:42

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH 01/27] ptrace: arch_has_single_step

On Sun, Nov 25, 2007 at 01:55:07PM -0800, Roland McGrath wrote:
> This defines the new macro arch_has_single_step() in linux/ptrace.h, a
> default for when asm/ptrace.h does not define it. It declares the new
> user_enable_single_step and user_disable_single_step functions.
> This is not used yet, but paves the way to harmonize on this interface
> for the arch-specific calls on all machines.

Why should arch_has_single_step be a function-like macro? I can't thing
of a case were this wouln't be a compile-time constant. And given that
this is hopefully a transitionary ifdef because eventually all architectures
would use the generic code I'd prefer ifdefs in the code that clearly mark
this as transitional in this case.

> +static inline void user_enable_single_step(struct task_struct *task)

> +static inline void user_disable_single_step(struct task_struct *task)

And I don't think these should be provided at all as generic stubs. If
an arch doesn't use the generic code it simply shouldn't compile the
code using this.

Whats the reason for the user_ prefix btw, most architectures seems to
have these functions already anyway, just without the user_ prefix.

2007-11-25 22:24:19

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH 10/27] ptrace: generic resume

On Sun, Nov 25, 2007 at 02:01:09PM -0800, Roland McGrath wrote:
> This makes ptrace_request handle all the ptrace requests that wake
> up the traced task. These do low-level ptrace implementation magic
> that is not arch-specific and should be kept out of arch code. The
> implementations on each arch usually do the same thing. The new
> generic code makes use of the arch_has_single_step macro and generic
> entry points to handle PTRACE_SINGLESTEP.

Nice, I've been trying to get people to move this to common code for
a while :)


> +#ifdef PTRACE_SINGLESTEP
> +#define is_singlestep(request) ((request) == PTRACE_SINGLESTEP)
> +#else
> +#define is_singlestep(request) 0
> +#endif
> +
> +#ifdef PTRACE_SYSEMU
> +#define is_sysemu_singlestep(request) ((request) == PTRACE_SYSEMU_SINGLESTEP)
> +#else
> +#define is_sysemu_singlestep(request) 0
> +#endif

Could we by any chance just force every architecture using generic code
to implement PTRACE_SINGLESTEP and PTRACE_SYSEMU? This will lead to
both far less messy code and a more consistant user interface.

2007-11-25 22:37:58

by Roland McGrath

[permalink] [raw]
Subject: Re: [PATCH 10/27] ptrace: generic resume

> Could we by any chance just force every architecture using generic code
> to implement PTRACE_SINGLESTEP and PTRACE_SYSEMU? This will lead to
> both far less messy code and a more consistant user interface.

I'd like to look into that later after most arch's have moved to using the
generic code for their existing support. I am thoroughly in favor, but it
requires some more groundwork that can come after this initial stage.


Thanks,
Roland

2007-11-25 22:59:21

by Roland McGrath

[permalink] [raw]
Subject: Re: [PATCH 01/27] ptrace: arch_has_single_step

> Why should arch_has_single_step be a function-like macro? I can't thing
> of a case were this wouln't be a compile-time constant. And given that
> this is hopefully a transitionary ifdef because eventually all architectures
> would use the generic code I'd prefer ifdefs in the code that clearly mark
> this as transitional in this case.

I'm not sure it's true that there is no machine where some chips support
single-step and others don't, though I do think it's true that no arch code
has a conditional like this now. In the case of block-step (in later
patches), is is the case that a run-time check for availability of the
hardware feature comes up (on some x86 configurations). So a main reason
is to keep the two parallel macros with the same style and semantics.

> > +static inline void user_enable_single_step(struct task_struct *task)
>
> > +static inline void user_disable_single_step(struct task_struct *task)
>
> And I don't think these should be provided at all as generic stubs. If
> an arch doesn't use the generic code it simply shouldn't compile the
> code using this.

The code compiles away completely with if (0)'s. I did it this way to
avoid more #ifdef's in the generic ptrace code. Previous patch reviews
I've read (including ones from you) have said to use header-defined stubs
in #ifdef and unconditional calls in the code. Please be explicit in
proposing the specific alternatives you would prefer.

> Whats the reason for the user_ prefix btw, most architectures seems to
> have these functions already anyway, just without the user_ prefix.

The arch's are not consistent now, so I chose a new scheme to harmonize
on. I think the "set_foo" names are a bit too nonspecific-sounding,
especially given that we do have other things kicking around that use
single-step functionality in kernel mode. Also, I plan to submit some
more work harmonizing the arch-specific access to the user-mode view of
machine state, and a uniform prefix for the new, reliably coherent,
documented set of internal interfaces just seems like the right thing to
do. (I don't really care enough to argue about the names for functions.
Anyone who, for some reason I cannot fathom, cares enough to be contrary
about the subject, is welcome to set the standard.)


Thanks,
Roland

2007-11-26 01:09:20

by Denys Vlasenko

[permalink] [raw]
Subject: Re: [PATCH 23/27] x86: debugctlmsr kconfig

On Sunday 25 November 2007 14:08, Roland McGrath wrote:
> This adds the (internal) Kconfig macro CONFIG_X86_DEBUGCTLMSR,
> to be defined when configuring to support only hardware that
> definitely supports MSR_IA32_DEBUGCTLMSR with the BTF flag.
>
> The Intel documentation says "P6 family" and later processors all have it.
> I think the Kconfig dependencies are right to have it set for those and
> unset for others (i.e., when 586 and earlier are supported).
>
> +config X86_DEBUGCTLMSR
> + bool
> + depends on !(M586MMX || M586TSC || M586 || M486 || M386)
> + default y

Why is it defined in configuration system instead of some *.h file?
--
vda

2007-11-26 01:58:39

by Dave Jones

[permalink] [raw]
Subject: Re: [PATCH 23/27] x86: debugctlmsr kconfig

On Sun, Nov 25, 2007 at 02:08:02PM -0800, Roland McGrath wrote:
>
> This adds the (internal) Kconfig macro CONFIG_X86_DEBUGCTLMSR,
> to be defined when configuring to support only hardware that
> definitely supports MSR_IA32_DEBUGCTLMSR with the BTF flag.
>
> The Intel documentation says "P6 family" and later processors all have it.
> I think the Kconfig dependencies are right to have it set for those and
> unset for others (i.e., when 586 and earlier are supported).

What about the non-Intel vendors ?
Was this msr present on AMD K6 ? Geode? Winchip? VIA C3 ?
If not, then this patch isn't complete.

Dave

--
http://www.codemonkey.org.uk

2007-11-26 07:51:46

by Roland McGrath

[permalink] [raw]
Subject: Re: [PATCH 23/27] x86: debugctlmsr kconfig

> Why is it defined in configuration system instead of some *.h file?

That seems to be existing practice for this sort of thing.
I just followed what I saw.


Thanks,
Roland

2007-11-26 08:07:28

by Roland McGrath

[permalink] [raw]
Subject: Re: [PATCH 23/27] x86: debugctlmsr kconfig

> What about the non-Intel vendors ?
> Was this msr present on AMD K6 ? Geode? Winchip? VIA C3 ?
> If not, then this patch isn't complete.

I know modern AMD processors have it. I don't know about any others, nor
off hand where to look to find out. Is there a better way to compose the
"depends on" condition so that it will be true on the modern common
processors and future common flavors, but false on the various ones we
don't know about? (I really just looked around a little and figured that
!X86_F00F_BUG about corresponded to "P6 family".)


Thanks,
Roland

2007-11-26 22:52:49

by Denys Vlasenko

[permalink] [raw]
Subject: Re: [PATCH 23/27] x86: debugctlmsr kconfig

On Sunday 25 November 2007 23:51, Roland McGrath wrote:
> > Why is it defined in configuration system instead of some *.h file?
>
> That seems to be existing practice for this sort of thing.
> I just followed what I saw.

I think that if such conditional constants can be defined
in header files (IOW: if they are not used elsewhere in config system,
only in the C source code), they should not be put in config system.
Don't make it more complex than it needs to be.

Sam what do you think?
--
vda

2007-11-27 08:54:36

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH 01/27] ptrace: arch_has_single_step

On Sun, 25 Nov 2007 13:55:07 -0800 (PST) Roland McGrath <[email protected]> wrote:

> This defines the new macro arch_has_single_step() in linux/ptrace.h, a
> default for when asm/ptrace.h does not define it. It declares the new
> user_enable_single_step and user_disable_single_step functions.
> This is not used yet, but paves the way to harmonize on this interface
> for the arch-specific calls on all machines.

I think I'll duck this lot for now in view of the (relatively small) amount
of followup.

I did do an experimental will-it-apply and got a tremendous number of
rejects against the x86 git tree, almost all of which went away when `patch
-l' was used. Seems that someone has gone on a whitespace rampage through
arch/x86/ia32/ptrace32.c and arch/x86/ia32/ptrace64.c.

That's kinda/sorta OK, but `patch -l' is a bit more inclined to misplace
hunks and it's all a bit risky.

2007-11-27 10:39:18

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH 01/27] ptrace: arch_has_single_step


* Andrew Morton <[email protected]> wrote:

> On Sun, 25 Nov 2007 13:55:07 -0800 (PST) Roland McGrath <[email protected]> wrote:
>
> > This defines the new macro arch_has_single_step() in linux/ptrace.h,
> > a default for when asm/ptrace.h does not define it. It declares the
> > new user_enable_single_step and user_disable_single_step functions.
> > This is not used yet, but paves the way to harmonize on this
> > interface for the arch-specific calls on all machines.
>
> I think I'll duck this lot for now in view of the (relatively small)
> amount of followup.
>
> I did do an experimental will-it-apply and got a tremendous number of
> rejects against the x86 git tree, almost all of which went away when
> `patch -l' was used. Seems that someone has gone on a whitespace
> rampage through arch/x86/ia32/ptrace32.c and arch/x86/ia32/ptrace64.c.
>
> That's kinda/sorta OK, but `patch -l' is a bit more inclined to
> misplace hunks and it's all a bit risky.

actually, Thomas tried a tentative merge two days ago or so and the
result was pretty OK and functional. I'll try to do a more formal merge
and see what comes up.

Ingo

2007-11-27 23:06:17

by Roland McGrath

[permalink] [raw]
Subject: Re: [PATCH 01/27] ptrace: arch_has_single_step

> I think I'll duck this lot for now in view of the (relatively small) amount
> of followup.

The debugctlmsr bits (last few patches) are meant to be taken with a grain
of salt. Everything else in this set is pretty well ready for prime time.

> I did do an experimental will-it-apply and got a tremendous number of
> rejects against the x86 git tree, almost all of which went away when `patch
> -l' was used. Seems that someone has gone on a whitespace rampage through
> arch/x86/ia32/ptrace32.c and arch/x86/ia32/ptrace64.c.

Damn, sorry about that. I could have sworn I cranked everything through
the whitespace inoculation machine, but I guess I missed some.


Thanks,
Roland

2007-11-27 23:59:39

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH 01/27] ptrace: arch_has_single_step


* Roland McGrath <[email protected]> wrote:

> > I did do an experimental will-it-apply and got a tremendous number
> > of rejects against the x86 git tree, almost all of which went away
> > when `patch -l' was used. Seems that someone has gone on a
> > whitespace rampage through arch/x86/ia32/ptrace32.c and
> > arch/x86/ia32/ptrace64.c.
>
> Damn, sorry about that. I could have sworn I cranked everything
> through the whitespace inoculation machine, but I guess I missed some.

i've resolved those and i've added your 27 patches to x86.git. You can
pick it up from the 'mm' branch of x86.git:

git-pull git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86.git mm

it builds and boots fine here, and the patches certainly look very
clean. Unless there are major problems with it this looks like 2.6.25
stuff. Would you mind to send updates/fixes against this tree?

Ingo

2007-11-28 00:08:38

by Roland McGrath

[permalink] [raw]
Subject: Re: [PATCH 01/27] ptrace: arch_has_single_step

> clean. Unless there are major problems with it this looks like 2.6.25
> stuff. Would you mind to send updates/fixes against this tree?

I'd be glad to. I'd be very happy to see this stuff make 2.6.25.

Thanks,
Roland

2007-11-28 23:40:30

by David Wilder

[permalink] [raw]
Subject: Re: [PATCH 20/27] ptrace: arch_has_block_step

Roland McGrath wrote:
<snip>
>
> +#ifndef arch_has_block_step
> +/**
> + * arch_has_block_step - does this CPU support user-mode block-step?
> + *
> + * If this is defined, then there must be a function declaration or inline
> + * for user_enable_block_step(), and arch_has_single_step() must be defined
> + * too. arch_has_block_step() should evaluate to nonzero iff the machine
> + * supports step-until-branch for user mode. It can be a constant or it
> + * can test a CPU feature bit.
> + */
> +#define arch_has_single_step() (0)

should this be #define arch_has_block_step() (0)

> +
> +/**
> + * user_enable_block_step - step until branch in user-mode task
> + * @task: either current or a task stopped in %TASK_TRACED
> + *
> + * This can only be called when arch_has_block_step() has returned nonzero,
> + * and will never be called when single-instruction stepping is being used.
> + * Set @task so that when it returns to user mode, it will trap after the
> + * next branch or trap taken.
> + */
> +static inline void user_enable_block_step(struct task_struct *task)
> +{
> + BUG(); /* This can never be called. */
> +}
> +#endif /* arch_has_block_step */
> +
<snip>

2007-11-28 23:59:25

by Roland McGrath

[permalink] [raw]
Subject: Re: [PATCH 20/27] ptrace: arch_has_block_step

> Roland McGrath wrote:
> <snip>
> >
> > +#ifndef arch_has_block_step
> > +/**
> > + * arch_has_block_step - does this CPU support user-mode block-step?
> > + *
> > + * If this is defined, then there must be a function declaration or inline
> > + * for user_enable_block_step(), and arch_has_single_step() must be defined
> > + * too. arch_has_block_step() should evaluate to nonzero iff the machine
> > + * supports step-until-branch for user mode. It can be a constant or it
> > + * can test a CPU feature bit.
> > + */
> > +#define arch_has_single_step() (0)
>
> should this be #define arch_has_block_step() (0)

Oops, yes it should.


Thanks,
Roland

2007-11-25 22:07:34

by Roland McGrath

[permalink] [raw]
Subject: [PATCH 20/27] ptrace: arch_has_block_step


This defines the new macro arch_has_block_step() in linux/ptrace.h, a
default for when asm/ptrace.h does not define it. This is the analog
of arch_has_single_step() for step-until-branch on machines that have
it. It declares the new user_enable_block_step function, which goes
with the existing user_enable_single_step and user_disable_single_step.
This is not used yet, but paves the way to harmonize on this interface
for the arch-specific calls on all machines.

Signed-off-by: Roland McGrath <[email protected]>
---
include/linux/ptrace.h | 37 +++++++++++++++++++++++++++++++++----
1 files changed, 33 insertions(+), 4 deletions(-)

diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index a6effc8..dd8f751 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -154,7 +154,8 @@ int generic_ptrace_pokedata(struct task_struct *tsk, long addr, long data);
*
* This can only be called when arch_has_single_step() has returned nonzero.
* Set @task so that when it returns to user mode, it will trap after the
- * next single instruction executes.
+ * next single instruction executes. If arch_has_block_step() is defined,
+ * this must clear the effects of user_enable_block_step() too.
*/
static inline void user_enable_single_step(struct task_struct *task)
{
@@ -165,15 +166,43 @@ static inline void user_enable_single_step(struct task_struct *task)
* user_disable_single_step - cancel user-mode single-step
* @task: either current or a task stopped in %TASK_TRACED
*
- * Clear @task of the effects of user_enable_single_step(). This can
- * be called whether or not user_enable_single_step() was ever called
- * on @task, and even if arch_has_single_step() returned zero.
+ * Clear @task of the effects of user_enable_single_step() and
+ * user_enable_block_step(). This can be called whether or not either
+ * of those was ever called on @task, and even if arch_has_single_step()
+ * returned zero.
*/
static inline void user_disable_single_step(struct task_struct *task)
{
}
#endif /* arch_has_single_step */

+#ifndef arch_has_block_step
+/**
+ * arch_has_block_step - does this CPU support user-mode block-step?
+ *
+ * If this is defined, then there must be a function declaration or inline
+ * for user_enable_block_step(), and arch_has_single_step() must be defined
+ * too. arch_has_block_step() should evaluate to nonzero iff the machine
+ * supports step-until-branch for user mode. It can be a constant or it
+ * can test a CPU feature bit.
+ */
+#define arch_has_single_step() (0)
+
+/**
+ * user_enable_block_step - step until branch in user-mode task
+ * @task: either current or a task stopped in %TASK_TRACED
+ *
+ * This can only be called when arch_has_block_step() has returned nonzero,
+ * and will never be called when single-instruction stepping is being used.
+ * Set @task so that when it returns to user mode, it will trap after the
+ * next branch or trap taken.
+ */
+static inline void user_enable_block_step(struct task_struct *task)
+{
+ BUG(); /* This can never be called. */
+}
+#endif /* arch_has_block_step */
+
#endif

#endif

2007-12-03 08:13:20

by Srinivasa Ds

[permalink] [raw]
Subject: Re: [PATCH 14/27] powerpc: ptrace generic resume

Roland McGrath wrote:
> This removes the handling for PTRACE_CONT et al from the powerpc
> ptrace code, so it uses the new generic code via ptrace_request.

I have tested this patchset on powerpc successfully.

>
> Signed-off-by: Roland McGrath <[email protected]>
> ---
> arch/powerpc/kernel/ptrace.c | 46 ------------------------------------------
> 1 files changed, 0 insertions(+), 46 deletions(-)
>
> diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
> index b970d79..8b056d2 100644
> --- a/arch/powerpc/kernel/ptrace.c
> +++ b/arch/powerpc/kernel/ptrace.c
> @@ -445,52 +445,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
> break;
> }


Thanks
Srinivasa DS
Linux Technology Centre
IBM.