Subject: Re: SIGTRAP for traced processes and COMPAT_MACH
To: None <tech-kern@netbsd.org>
From: Emmanuel Dreyfus <manu@netbsd.org>
List: tech-kern
Date: 11/30/2003 00:25:41
Martin Husemann <martin@duskware.de> wrote:

> Let me try to rephrase how I think it should work:
> 
>  - you have two emulation internal vectors, one for sigmask, one for
>    exceptions
>  - from this you calculate an effective sigmask and set it whenever one
>    of those vectors is changed
>  - when you catch a signal, you check the exception vector first and only
>    handle that if it has this signal enabled
> 
> Am I missing something obvious?

Well, maybe. I agree with the method, but the problem is: where do you
do this?

I made a quick top-down diagram of functions involved in signal
handling. There are basically two code path, one to send the signal
immediatly, one to queue it so that it is delivered at userret time.

immediatly:
trapsignal -> kpsendsig -> sendsig

defered:
psignal -> psignal1 -> kpsignal2 -> ksiginfo_put
kpsignal -> kpsignal1 -> kpsignal2 -> ksiginfo_put
trapsignal -> kpsignal -> kpsignal1 -> kpsignal2 -> ksiginfo_put

Currently, the only places where it is possible to hook some
emulation-specific work are trapsignal and sendsig. 

Our goal is to catch a signal and prevent it from being delivered in
some situations decided by emulation specific code. We have two ways of
doing this:
1) hack the signal mask so that the signal is not sent
2) add a test in the code path to inhibit the signal. 

In option 1 we would inhibit any signal that can generate a Mach
exception. We would install a kqueue listener to get notified of the
signal. And the kqueue listener would raise a Mach exception, or it
would send a signal if a Mach exception is not sent. This is the
problem: there is no simple way to generate the signal if the signal is
masked.

With option 2, sendsig is not the good place to do the tests, since we
do not reach that function for masked signals. Trapsignal is not the
right place either because defered signals do not always come there:
anything sent with psignal is invisible to trapsignal.

The fix here can be to hack the signal mask so that we always reach
sendsig. sendsig would then be able to raise the Mach exception, or to
really send the signal. We would have a shadow signal mask in
darwin_emuldata to decide if the signal should finnally be sent. Darwin
process would modify this shadow signal mask instead of the real signal
mask.

Another fix is to allow an emulation hook on kpsignal2. The Darwin
version of kpsignal2 would raise a Mach exception or call the native
kpsignal2, exactly like it is already done for trapsignal. There is just
one problem: darwin_trapsignal would call the native trapsignal, and
trapsignal can call kpsendsig2, so darwin_trapsignal should take care to
avoid the situation where two Mach exceptions are raised for the same
exception: one by darwin_trapsignal, and one by darwin_kpsignal2.

Or (third fix possible), add a call to an emulation-hooked test function
in both trapsignal and kpsignal2 and inhibit the signal there. It would
look like this:

if (p->p_emul->e_checksignal && (*p->p_emul->e_checksignal)(p, ksi))
        return; 

darwin_checksignal would try to raise a Mach exception and would return
a non zero value if it failed to do so.  

This seems the best way to me. This is clean code, and for native
processes, this just costs a check that p->p_emul->e_checksignal == NULL

filtersignal might be a better name than checksignal, I have no real
opinion on this. 

Comments?  
  
-- 
Emmanuel Dreyfus
Il y a 10 sortes de personnes dans le monde: ceux qui comprennent 
le binaire et ceux qui ne le comprennent pas.
manu@netbsd.org