On 11/18, Roland McGrath wrote:
>
> > Once again. The tracee sleeps in SYSCALL_ENTER. The tracer resumes
> > the tracee via utrace_control(UTRACE_SINGLESTEP).
>
> Right.  This is another strange corner.  It doesn't necessarily make
> especially good sense intrinsically for single-step to have this meaning
> from this place.  But it's the status quo in the ptrace interface.

Yes.

> > So, I think we should do something like
> >
> >     tracehook_report_syscall_exit(step)
> >
> >             // do not use step at all
> >             if (task_utrace_flags() != 0)
> >                     utrace_report_syscall_exit();
>
> The trouble here is that the arch code looks like this:
>
>       step = test_thread_flag(TIF_SINGLESTEP);
>       if (step || test_thread_flag(TIF_SYSCALL_TRACE))
>               tracehook_report_syscall_exit(regs, step);
>
> i.e. unless syscall tracing is enabled, we won't even get there at all.

You are right, I missed this.

> >     utrace_report_syscall_exit()
> >
> >             if (UTRACE_EVENT(SYSCALL_EXIT))
> >                     REPORT(report_syscall_exit);
> >
> >             if (utrace->resume == UTRACE_SINGLESTEP ||
> >                 utrace->resume == UTRACE_BLOCKSTEP)
> >                     send_sigtrap();
> >
> > What do you think?
>
> This can't work in the REPORT case.  There start_report() will have reset
> utrace->resume,

Yes, yes, the pseudo-code above was just for illustration.

> (This would go with un-reverting f19442c and reverting 3bd4be9.)
>
> --- a/kernel/utrace.c
> +++ b/kernel/utrace.c
> @@ -1584,20 +1584,25 @@ static inline u32 do_report_syscall_entr
>                        UTRACE_EVENT(SYSCALL_ENTRY), report_syscall_entry,
>                        resume_report | report->result | report->action,
>                        engine, current, regs);
> -     finish_report(task, utrace, report, false);
> +
> +     /*
> +      * Now we'll stop if asked.  If we're proceeding with the syscall,
> +      * now we'll first enable single-step if asked.  That leaves the
> +      * task in "stepping" state so tracehook_report_syscall_exit() and
> +      * the arch code that calls it will know.
> +      */
> +     finish_resume_report(task, utrace, report);

Hmm. not sure I understand how this can work. I mean, this won't
enable stepping (in this particular case we are discussing).

> -     } else if (utrace->resume == UTRACE_REPORT) {
> +     } else if (utrace->resume <= UTRACE_REPORT) {

perhaps, you meant ">= UTRACE_REPORT" ? In this case yes, UTRACE_SINGLESTEP
will be noticed after resume, and ptrace or another engine can reassert
it during the next reporting loop, and then finish_resume_report() will
enable the stepping. But we can't trust ">=", another engine can
do utrace_control(INTERRUPT) and change ->resume before the tracee
resumes.

OK, probably I missed the implemenation details, but I think I got
the idea, and this should fix the step-after-syscall_enter problem.

But. We have the same problem with utrace_finish_vfork(), no?


Instead of fixing utrace_report_syscall_entry(), perhaps we should
change utrace_stop() path to enable the stepping if needed, but this
means we return to "synchronous" utrace_control(UTRACE_XXXSTEP).

Oleg.

Reply via email to