[PATCH 26/33] introduce PT_SINGLE_STEP and PT_SINGLE_BLOCK

Oleg Nesterov oleg at redhat.com
Mon Nov 21 20:02:36 UTC 2011


Add the new internal ptrace flags, PT_SINGLE_STEP and PT_SINGLE_BLOCK.

Like PT_SYSCALL_TRACE, this is needed to avoid the unnecessary ptrace
reports when TIF_SINGLESTEP was set by another engine, not by ptrace.
Also, we need these bits to coordinate the user_*_single_step() calls
from ptrace and utrace.

TODO: update the !x86 ptrace code which does user_disable_single_step().

Signed-off-by: Oleg Nesterov <oleg at redhat.com>
---
 arch/x86/kernel/ptrace.c  |    1 +
 include/linux/ptrace.h    |    5 ++++-
 include/linux/tracehook.h |    7 +++++--
 kernel/ptrace.c           |    3 +++
 4 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 8252879..d1557dc 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -808,6 +808,7 @@ static int ioperm_get(struct task_struct *target,
  */
 void ptrace_disable(struct task_struct *child)
 {
+	child->ptrace &= ~(PT_SINGLE_STEP | PT_SINGLE_BLOCK);
 	user_disable_single_step(child);
 #ifdef TIF_SYSCALL_EMU
 	clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index c10f610..2743315 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -105,6 +105,8 @@
 #define PT_TRACE_MASK	0x000003f4
 
 #define PT_SYSCALL_TRACE	0x00020000
+#define PT_SINGLE_STEP		0x00040000
+#define PT_SINGLE_BLOCK		0x00080000
 
 /* single stepping state bits (used on ARM and PA-RISC) */
 #define PT_SINGLESTEP_BIT	31
@@ -229,7 +231,8 @@ static inline void ptrace_init_task(struct task_struct *child, bool ptrace)
 
 	if (unlikely(ptrace) && current->ptrace) {
 		child->ptrace = current->ptrace;
-		child->ptrace &= ~PT_SYSCALL_TRACE;
+		child->ptrace &=
+			~(PT_SYSCALL_TRACE | PT_SINGLE_STEP | PT_SINGLE_BLOCK);
 		__ptrace_link(child, current->parent);
 
 		if (child->ptrace & PT_SEIZED)
diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h
index eb9fe30..21c8ca2 100644
--- a/include/linux/tracehook.h
+++ b/include/linux/tracehook.h
@@ -104,6 +104,9 @@ static inline __must_check int tracehook_report_syscall_entry(
 	return 0;
 }
 
+#define ptrace_wants_step()	\
+	(current->ptrace & (PT_SINGLE_STEP | PT_SINGLE_BLOCK))
+
 /**
  * tracehook_report_syscall_exit - task has just finished a system call
  * @regs:		user register state of current task
@@ -126,7 +129,7 @@ static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step)
 	if (task_utrace_flags(current) & UTRACE_EVENT(SYSCALL_EXIT))
 		utrace_report_syscall_exit(regs);
 
-	if (step) {
+	if (step && ptrace_wants_step()) {
 		siginfo_t info;
 		user_single_step_siginfo(current, regs, &info);
 		force_sig_info(SIGTRAP, &info, current);
@@ -157,7 +160,7 @@ static inline void tracehook_signal_handler(int sig, siginfo_t *info,
 {
 	if (task_utrace_flags(current))
 		utrace_signal_handler(current, stepping);
-	if (stepping)
+	if (stepping && ptrace_wants_step())
 		ptrace_notify(SIGTRAP);
 }
 
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 739183a..792080d 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -630,13 +630,16 @@ static int ptrace_resume(struct task_struct *child, long request,
 		clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
 #endif
 
+	child->ptrace &= ~(PT_SINGLE_STEP | PT_SINGLE_BLOCK);
 	if (is_singleblock(request)) {
 		if (unlikely(!arch_has_block_step()))
 			return -EIO;
+		child->ptrace |= PT_SINGLE_BLOCK;
 		user_enable_block_step(child);
 	} else if (is_singlestep(request) || is_sysemu_singlestep(request)) {
 		if (unlikely(!arch_has_single_step()))
 			return -EIO;
+		child->ptrace |= PT_SINGLE_STEP;
 		user_enable_single_step(child);
 	} else {
 		user_disable_single_step(child);
-- 
1.5.5.1



More information about the kernel mailing list