engine interaction, callback order

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]


Renzo Davoli brought up the issue of the order of callbacks to different
engines for the same utrace event.  I know someone working on uprobes
brought this up before (probably on the systemtap mailing list some time

In both cases, the purpose behind the practical interest in callback order
is the same.  Both syscall interception and breakpoint assistance do
emulation or "warping" kinds of things.  In the breakpoint case, it's
useful to execute copied instructions, so the true PC (and other register
values) to be executed in user mode can be changed from the unmolested user
program.  In the syscall case, user register values are tweaked to affect
whether and what actual syscalls can execute.  

These engines temporarily change the user state that executes.  So, you
want them to do their work last, so that other observing engines see the
unmolested user state before they tweak it.  But, you want them to do their
work first, so they restore the user state to the proper values to be
observed before other engines look.

A related issue is an engine wanting the last word on a signal's
disposition.  You may want to be last in report_signal and force a
particular disposition (like terminate) no matter what other engines had
decided about the signal.  Conversely, an engine filling the core dump
function (or starting the bug-reporter robot or whatever) wants to be the
last resort, taking over only if any other engines (active debuggers, etc.)
want to let a fatal signal proceed.  

Whether you want your register values in place only at the last moment (to
be run but not seen), or want your signal disposition decision to go in
effect only at the last moment, the problem is the same.  No order of
callbacks alone helps you.  Another engine can leave QUIESCE set when
you've finished all your callbacks and cleared QUIESCE.  Then your warped
register values are there to be seen by any engine doing asynchronous
regset access while it has QUIESCE set.  Or, the signal disposition to take
effect can be changed by utrace_inject_signal (or perhaps can't, in the
current implementation).  You don't have any way to react to what other
engines are doing.

utrace_inject_signal can't do any queuing--it's injecting the particular
action (possibly fatal) to be taken the very next thing, not a signal to be
considered and dispatched later.  But then what are you supposed to do when
another engine injected first and you get -EBUSY?  There isn't an
opportunity to get your word in there, to examine or replace the competing
disposition scheduled.  

These issues lead to the idea of changing how report_quiesce and
report_signal work.  report_signal tells you "without intervention, user
mode will resume from right here and do this".  Currently report_quiesce
tells you that user mode might resume now if permitted, but also tells you
at some various places just that user mode is not running right now and
it's safe to look.  (At those latter, it's not about to get back to user
mode (or terminate) without passing through some more event points, though
it may be working and blocking nonquiescently before then.)  So perhaps
rename report_signal to report_resume, and call it when dequeuing a signal
and when dequeuing none and preparing to return to user mode after having
stopped for QUIESCE.  That is, it's called when there is the opportunity to
decide the disposition of resuming (fatal or signal handler or normal).
Then do away with utrace_inject_signal entirely.  The EVENT(SIGNAL_*) bits
say an engine wants report_resume for those dispositions, EVENT(QUIESCE)
says the engine wants it no matter what.  An engine uses QUIESCE to get the
thread to call report_resume.  Then every interested engine gets the
callback, and can see the disposition choice left by the last engine, and
whether it's been left in QUIESCE.  

With report_resume as the center of "final user status" cooperation, then
we can think about some sort of callback priority order covering the needs.

For the syscall emulation warping, I think it may be a happy special case
that can sidestep the whole complex engine interaction subject.  It may
make sense to have a first-class utrace feature via return values from
report_syscall callbacks, for skipping a syscall and for restoring register
values to their values before kernel entry.  Rather than an engine using
tracehook_abort_syscall et al, so that other engines can see its changes to
the user registers or pseudo-register, the utrace core would do it after
all callbacks and places engines could stop and look.  

I'd appreciate any feedback anyone has in any of these areas.


[Index of Archives]     [Kernel Discussion]     [Gimp]     [Yosemite News]

  Powered by Linux