> Hmm. not sure I understand how this can work. I mean, this won't > enable stepping (in this particular case we are discussing).
I might be confused. I'm thinking of two cases: the report_syscall_entry pass yields UTRACE_SINGLESTEP, or that it yields UTRACE_STOP and then utrace_control() sets utrace->resume to UTRACE_SINGLESTEP. The former is e.g. PTRACE_SINGLESTEP while an unrelated engine uses UTRACE_EVENT(SYSCALL_ENTRY). The ptrace engine's report_quiesce returns UTRACE_SINGLESTEP. finish_resume_report() calls user_enable_single_step(). That seems fine. Right? The latter is e.g. PTRACE_SINGLESTEP after ptrace stop at syscall entry. I see. finish_resume_report() will only do utrace_stop() and then we'll go directly into the syscall unless someone used UTRACE_REPORT. utrace_stop() will only set TIF_NOTIFY_RESUME and utrace->resume. In the real resume-to-user cases, that's fine because we'll handle that in utrace_resume() or utrace_get_signal() before doing anything else. I think this maybe wouldn't hurt anything: @@ -1794,11 +1794,13 @@ static void finish_resume_report(struct { finish_report_reset(task, utrace, report); - switch (report->action) { - case UTRACE_STOP: - utrace_stop(task, utrace, report->resume_action); - break; + if (report->action == UTRACE_STOP) { + utrace_stop(task, utrace, report->resume_action, true); + report->action = start_report(utrace); + WARN_ON(report->action == UTRACE_STOP); + } + switch (report->action) { case UTRACE_INTERRUPT: if (!signal_pending(task)) set_tsk_thread_flag(task, TIF_SIGPENDING); (In the omitted part of the patch, the new flag to utrace_stop tells it never to bother with setting TIF_NOTIFY_RESUME for < UTRACE_REPORT.) Then even for the real resume-to-user cases, we skip a cycle out to arch asm and back into utrace_resume() for utrace_control(,,UTRACE_SINGLESTEP) after UTRACE_STOP. (That microoptimization does not really matter, but it falls naturally out of the change.) > > - } else if (utrace->resume == UTRACE_REPORT) { > > + } else if (utrace->resume <= UTRACE_REPORT) { > > perhaps, you meant ">= UTRACE_REPORT" ? No, it's to catch UTRACE_INTERRUPT as requesting a report too, as you noticed in the other email thread should be done. > OK, probably I missed the implemenation details, but I think I got > the idea, and this should fix the step-after-syscall_enter problem. Right. My implementation details are not quite right either. But this seems like the right idea for how to get tracehook_report_syscall_exit called in the cases where it is in old ptrace. > But. We have the same problem with utrace_finish_vfork(), no? Yes. But, hmm. utrace_stop(task, utrace, UTRACE_RESUME); /* XXX */ This XXX was there about passing UTRACE_RESUME, because that's not really right. I guess I was actually thinking of this very case, but didn't know at the time quite what the case was. > 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). I don't really follow what you mean by "synchronous". Your suggestion is equivalent to making utrace_finish_vfork call finish_resume_report instead of utrace_stop, isn't it? The callers of utrace_stop() are: * finish_resume_report -> the main guy -> proposed (above) to also handle utrace->resume immediately after stop * utrace_report_exit -> doesn't matter (?), nothing but UTRACE_STOP and possibly TIF_SIGPENDING are meaningful any more * do_report_syscall_entry -> proposed to call finish_resume_report instead * utrace_finish_vfork Ok. So I can see a bit of cleanup to be done in splitting finish_resume_report and utrace_finish_vfork calling the parts of it, as will the "We only got here to process utrace->resume." case. But it will be functionally equivalent to finish_resume_report with {.spurious=false, .action=utrace->resume}. That seems like it would cover it all, no? But I am still hesitant because I don't really understand your "return to synchronous..." comment. Thanks, Roland