On 09/23, Roland McGrath wrote:
>
> > OK, finish_callback_report() and utrace_control(DETACH) can set
> > TIF_NOTIFY_RESUME.
>
> Right.  Those utrace_resume has the report.action==UTRACE_RESUME bail-out
> case.  So either that would change or detach would also do UTRACE_REPORT.
>
> > But what if there are no more attached engines?
> > Looks like, utrace_resume(UTRACE_RESUME) needs to handle this special
> > case. And utrace_reset() shouldn't clear task->utrace_flags, otherwise
> > utrace_resume/utrace_get_signal won't be called.
>
> Right.  Or else tracehook_notify_resume could call utrace_resume
> unconditionally, but I'm not at all sure that is not worse.  The
> original theory was that it should always be OK to have some
> utrace_flags bits stay set when they are "stale", because any kind of
> reporting pass that got enabled would hit the report->spurious case
> and clean the state up synchronously when it's safe.

I tried to make the patch which addresses this issue, but surprisingly
I failed. Because I think there are more (minor) problems here. When
it comes to multitracing, we can have the unwanted trap even without
detaching.

In short: I no longer understand why utrace->resume can be UTRACE_*STEP
when the tracee is stopped, and in fact I think this is not right.

For example. Consider two engines, E1 and E2. To simplify the discussion
suppose that both engines have engine->data->resume and ->report_quiesce()
just returns ->resume. So, if the debugger wants, say, single-step, it
does

        engine->data->resume = UTRACE_SINGLESTEP;
        utrace_control(UTRACE_SINGLESTEP);

Actually, any engine should do something like this.

Now suppose that E1 wants UTRACE_SINGLESTEP, E2 asks for UTRACE_STOP.
In this case utrace_resume() results in utrace_stop() which sets
utrace->resume = UTRACE_SINGLESTEP before sleeping.

First of all - why? Yes, the theory is that we have another reporting
loop after wake_up, but utrace->resume = UTRACE_REPORT is enough, E1
should always acquire UTRACE_SINGLESTEP if needed or it is buggy.

But more importantly, this doesn't look right or I missed something.
Suppose that, before E2 resumes the tracee, E1 does utrace_control(STOP)
which immediately succeeds and allows E1 to play with the stopped tracee.
Again, to simplify the discussion, suppose that E2 does UTRACE_RESUME
and nothing more after that.

Now. E1 wants to resume the tracee too and it does

        engine->data->resume = UTRACE_RESUME;
        utrace_control(UTRACE_RESUME);

utrace_control(RESUME) correctly clears TIF_SINGLESTEP, but it doesn't
change utrace->resume. This means utrace_resume() doesn't do the
reporting loop, it just calls user_enable_single_step() and returns
to user-mode.

So. Could you explain why utrace_stop() should ever keep UTRACE_STEP
in utrace->resume? finish_report() does the same but this looks fine.


Also. I am not sure utrace_control(UTRACE_STEP) should always set
utrace->resume = UTRACE_STEP. If the tracee is stopped but there
is another ENGINE_STOP engine (iow, the tracee won't be resumed
right now) we have the same problem.



Off-topic,

        #define UTRACE_RESUME_BITS      (ilog2(UTRACE_RESUME_MAX) + 1)

why UTRACE_RESUME_MAX? it should be (ilog2(UTRACE_RESUME_MAX - 1) + 1), no?

Oleg.

Reply via email to