PTRACE_EVENT_SIGTRAP

Oleg Nesterov oleg at redhat.com
Thu Oct 29 19:41:58 UTC 2009


On 10/27, Roland McGrath wrote:
>
> This is used only in the UTRACE_SIGNAL_HANDLER case.  That means after
> tracehook_signal_handler(), which is where a signal handler has just
> been set up.
>
> For reference, in old ptrace, tracehook_signal_handler() is:
>
> 	if (stepping)
> 		ptrace_notify(SIGTRAP);
>
> This means that when PTRACE_SINGLE{STEP,BLOCK},signr was used to
> deliver the handled signal, we stop there in ptrace_notify.  This is
> in lieu of a proper single-step trap, with the theory that what you
> meant to "step to" next was the first instruction of the signal
> handler, rather than the second instruction of the handler.
>
> The only purpose of PTRACE_EVENT_SIGTRAP is to distinguish this case
> from PTRACE_EVENT_SIGNAL as it would be for a real SIGTRAP after a
> normal instruction step.  The only purposes of this distinction are to
> make PTRACE_SETSIGINFO have no effect, and to make resumptions ignore
> the data/signr argument.  The former makes it consistent with other
> cases in utrace-ptrace that replace ptrace_notify() calls in the old
> ptrace, but that itself is a known nit incompatibility with the old
> behavior, so it's superfluous at best.  The latter is just intended
> for pure bug-compatibility with the old behavior.  Aside from these,
> there are no other reasons not to have the UTRACE_SIGNAL_HANDLER case
> result in PTRACE_EVENT_SIGNAL, with siginfo_t filled in to match what
> the old ptrace_notify() does.
>
> Is that all correct?
>
> In short, PTRACE_EVENT_SIGTRAP provides bug compatibility for
> PTRACE_SINGLESTEP,signr silently acting like PTRACE_SINGLESTEP,0 when

(s/PTRACE_SINGLESTEP/PTRACE_ANY/)

> called at the stop just provoked by the last PTRACE_SINGLESTEP,signr.
> Is that it?

Yes.

> I think this is a piece of bug compatibility that upstream will be
> happy to have "broken".  That is, I bet most people don't realize at
> all PTRACE_SINGLESTEP,signr will sometimes swallow a signal after what
> appears to be a normal single-step stop.  In fact, I suspect many
> might say that this is worse than the previous behavior my addition of
> this ptrace_notify() call (sometime before git so <2.6.12; Sep 2004,
> not sure what version that was, maybe 2.6.9).  That behavior was that
> PTRACE_SINGLESTEP,signr would stop at the second instruction of the
> signal handler and never the first--but that would be a real step
> (like you now get after PTRACE_SINGLESTEP,0 when stopped in
> ptrace_notify() at the first instruction of the handler).  I'm quite
> sure that at the time I never contemplated the signal-swallowing
> implication of using ptrace_notify() here.
>
> So, get rid of PTRACE_EVENT_SIGTRAP.  Instead for the case of
> UTRACE_SIGNAL_HANDLER when stepping, initialize *info to look
> like a vanilla SIGTRAP and then fall into the default case for
> real signals.

Yes, I already thought about this. The patch is trivial, please see
below.

> Does that all sound right to you, or did I miss something?

Don't ask me, I never know what can be changed ;)

But yes, I agree. The current behaviour looks strange (if not wrong).
With this change ptrace(PTRACE_WHATEVER, signr) after PTRACE_SINGLESTEP
never ignores signr. Even if perhaps this is not really useful, this is
consistent. Afaics, this case was a single exception when ptrace(signr)
or PTRACE_SETSIGINFO) was ignored after PTRACE_SINGLESTEP.

The only problem with this change (if we do it now), it is always nice
to have a separate changelog to document the behaviour change. But
hopefully nobody cares, I mean, nobody will notice the difference.

Oleg.

--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -73,7 +73,6 @@ struct ptrace_context {
 
 #define PTRACE_EVENT_SYSCALL_ENTRY	(1 << 16)
 #define PTRACE_EVENT_SYSCALL_EXIT	(2 << 16)
-#define PTRACE_EVENT_SIGTRAP		(3 << 16)
 #define PTRACE_EVENT_SIGNAL		(4 << 16)
 /* events visible to user-space */
 #define PTRACE_EVENT_MASK		0xFFFF
@@ -495,8 +494,8 @@ static u32 ptrace_report_signal(u32 acti
 			context->siginfo = NULL;
 
 		if (resume != UTRACE_RESUME) {
-			set_stop_code(context, PTRACE_EVENT_SIGTRAP);
-			return UTRACE_STOP | UTRACE_SIGNAL_IGN;
+			info->si_signo = SIGTRAO;
+			break;
 		}
 
 	case UTRACE_SIGNAL_REPORT:
@@ -509,21 +508,21 @@ static u32 ptrace_report_signal(u32 acti
 
 		return resume | resume_signal(task, context->signr,
 						info, return_ka);
-	default:
-		WARN_ON(context->siginfo);
-		context->siginfo = info;
-		/*
-		 * context->siginfo points to the caller's stack.
-		 * Make sure the subsequent UTRACE_SIGNAL_REPORT clears
-		 * ->siginfo before return from get_signal_to_deliver().
-		 */
-		utrace_control(task, engine, UTRACE_INTERRUPT);
+	}
 
-		context->stop_code = (PTRACE_EVENT_SIGNAL << 8) | info->si_signo;
-		context->signr   = info->si_signo;
+	WARN_ON(context->siginfo);
+	context->siginfo = info;
+	/*
+	 * context->siginfo points to the caller's stack.
+	 * Make sure the subsequent UTRACE_SIGNAL_REPORT clears
+	 * ->siginfo before return from get_signal_to_deliver().
+	 */
+	utrace_control(task, engine, UTRACE_INTERRUPT);
 
-		return UTRACE_STOP | UTRACE_SIGNAL_IGN;
-	}
+	context->stop_code = (PTRACE_EVENT_SIGNAL << 8) | info->si_signo;
+	context->signr   = info->si_signo;
+
+	return UTRACE_STOP | UTRACE_SIGNAL_IGN;
 }
 
 static u32 ptrace_report_quiesce(u32 action,




More information about the utrace-devel mailing list