2013-04-29 14:51:32

by Warlich, Christof

[permalink] [raw]
Subject: X86 fpu registers in a signal handler's ucontext

Hi,

I want my signal handler to return from a SIGFPE and continue normal
execution right _after_ the instruction that caused the signal.

My first attempt workes quite well: I just modify the EIP register
though the ucontext pointer being passed to the signal handler:

void fpeHandler(int, siginfo_t *info, void *context) {
// The following function calculates the size of the instruction being pointed to.
int size = instructionSize((unsigned char *) info->si_addr);
((ucontext_t *) context)->uc_mcontext.gregs[REG_EIP] += size;
}

Doing this, my main program continues as expected as long as no other
floating point instructions are involved, but as the exception
condition is still active in the FP status register, any subsequent
and _valid_ floating point calculation cause another exception.

Thus, I tried to clear the exceptions in a similar way:

void fpeHandler(int, siginfo_t *info, void *context) {
// This function calculates the size of the instruction being poined to.
int size = instructionSize((unsigned char *) info->si_addr);
((ucontext_t *) context)->uc_mcontext.gregs[REG_EIP] += size;
((ucontext_t *) context)->uc_mcontext.fpregs->status &= ~FE_ALL_EXCEPT
}

But unfortunately, this doesn't work:

First, this link:
http://valgrind.10908.n7.nabble.com/need-FPU-and-SSE-state-in-sigcontext-ucontext-td19844.html
suggests that unlike the GPRs, the FP registers are _not_ restored after
returnung from the signal handler.

Second, only FP state seems to be available through ucontext_t, and I would
need to clear exceptions for SSE as well.

Can anyone give me some advice on how to I could proceed?

Thanks a lot,

Chris-


2013-04-29 17:57:55

by Andi Kleen

[permalink] [raw]
Subject: Re: X86 fpu registers in a signal handler's ucontext

"Warlich, Christof" <[email protected]> writes:
>
> First, this link:
> http://valgrind.10908.n7.nabble.com/need-FPU-and-SSE-state-in-sigcontext-ucontext-td19844.html
> suggests that unlike the GPRs, the FP registers are _not_ restored after
> returnung from the signal handler.

The FP registers are restored lazily, but the state for this is kept in
the kernel.

One easy way may be to catch the FPU exception too and clear from there?

There can be some complications with different save formats too (XSAVE
vs FXSAVE). So your solution may not be necessarily 100% portable
to all systems.

-Andi

--
[email protected] -- Speaking for myself only

2013-04-30 06:35:52

by Warlich, Christof

[permalink] [raw]
Subject: RE: X86 fpu registers in a signal handler's ucontext

Andi Kleen <[email protected]> writes:
> The FP registers are restored lazily, but the state for this is kept in
> the kernel.

I'm not sure if I understand "lazily" in this context: Do you mean that FP
registers _are_ restored within the kernel, but _not_ from a (possibly modified)
ucontext of a userspace signal handler? If so, do you know a reason why the GP
registers are so nicely restored from userspace, but not the FP registers?

> One easy way may be to catch the FPU exception too and clear from there?

Hmm - I _do_ catch SIGFPE in my userspace signal handler, but I obviously
can't clear the FP exceptions from there. This, together with your answer
so far, makes me conclude that there may be no way to achieve my goal from
userspace, right :-(?

Ok, still assuming I'm (terribly) right so far: The kernel calls
do_coprocessor_error() when the FP exception occurs. As I don't want to patch
the kernel, is there a "best practise" way to hook my module code into the FP
exception handler? The only way that comes to my mind is modifying the vector
table in modul_init() to let the FP exception point to my code and restoring
it in module_exit().

> There can be some complications with different save formats too (XSAVE
> vs FXSAVE). So your solution may not be necessarily 100% portable
> to all systems.
Yes, I'm certainly arch specific in many ways here, but that wouldn't be much
of a problem for me though.-

2013-04-30 11:37:37

by Mikael Pettersson

[permalink] [raw]
Subject: RE: X86 fpu registers in a signal handler's ucontext

Warlich, Christof writes:
> Andi Kleen <[email protected]> writes:
> > The FP registers are restored lazily, but the state for this is kept in
> > the kernel.
>
> I'm not sure if I understand "lazily" in this context: Do you mean that FP
> registers _are_ restored within the kernel, but _not_ from a (possibly modified)
> ucontext of a userspace signal handler? If so, do you know a reason why the GP
> registers are so nicely restored from userspace, but not the FP registers?
>
> > One easy way may be to catch the FPU exception too and clear from there?
>
> Hmm - I _do_ catch SIGFPE in my userspace signal handler, but I obviously
> can't clear the FP exceptions from there. This, together with your answer
> so far, makes me conclude that there may be no way to achieve my goal from
> userspace, right :-(?

Write to the fpstate ->mxcsr and ->swd fields in the sigaction handler's uc_mcontext.

2013-04-30 13:45:35

by Warlich, Christof

[permalink] [raw]
Subject: RE: X86 fpu registers in a signal handler's ucontext

Mikael Pettersson <[email protected]> writes:
> Write to the fpstate ->mxcsr and ->swd fields in the sigaction handler's uc_mcontext.

To me, "sigaction handler's uc_mcontext" sounds like userspace, which really confuses me:
Even in most recent glibc-2.17, uc_mcontext is of type mcontext_t, which us defined as:

typedef struct {
gregset_t gregs;
fpregset_t fpregs;
} mcontext_t;

typedef struct fpregset {
union {
struct fpchip_state {
int state[27];
int status;
} fpchip_state;
struct fp_emul_space {
char fp_emul[246];
char fp_epad[2];
} fp_emul_space;
int f_fpregs[62];
} fp_reg_set;
long int f_wregs[33];
} fpregset_t;

So there is no fpstate whatsoever.

However, these elements seem to be available in the uc_mcontext definition of the
kernel, but I can't have a sigaction handler there, can I? Then, how does the
kernel's uc_mcontext definition help me in my (userspace) signal handler?

2013-04-30 14:44:32

by Mikael Pettersson

[permalink] [raw]
Subject: RE: X86 fpu registers in a signal handler's ucontext

Warlich, Christof writes:
> Mikael Pettersson <[email protected]> writes:
> > Write to the fpstate ->mxcsr and ->swd fields in the sigaction handler's uc_mcontext.
>
> To me, "sigaction handler's uc_mcontext" sounds like userspace, which really confuses me:
> Even in most recent glibc-2.17, uc_mcontext is of type mcontext_t, which us defined as:
>
> typedef struct {
> gregset_t gregs;
> fpregset_t fpregs;
> } mcontext_t;
>
> typedef struct fpregset {
> union {
> struct fpchip_state {
> int state[27];
> int status;
> } fpchip_state;
> struct fp_emul_space {
> char fp_emul[246];
> char fp_epad[2];
> } fp_emul_space;
> int f_fpregs[62];
> } fp_reg_set;
> long int f_wregs[33];
> } fpregset_t;
>
> So there is no fpstate whatsoever.

You're looking at the wrong header: glibc-2.17/sysdeps/i386/sys/ucontext.h is legacy SVR4.
Instead look at glibc-2.17/sysdeps/unix/sysv/linux/x86/sys/ucontext.h.

(If the old one got installed on your system then something there is seriously wrong.)

The only quirk is that to access ->mxcsr on 32-bit you have to check if the high half of
->status contains FXSR_MAGIC and if so you need to cast that pointer to struct _fpstate*.

2013-05-02 05:43:06

by Warlich, Christof

[permalink] [raw]
Subject: RE: X86 fpu registers in a signal handler's ucontext

Mikael Pettersson <[email protected]> writes:
> You're looking at the wrong header: glibc-2.17/sysdeps/i386/sys/ucontext.h is legacy SVR4.
> Instead look at glibc-2.17/sysdeps/unix/sysv/linux/x86/sys/ucontext.h.
>
> (If the old one got installed on your system then something there is seriously wrong.)

Oh-oh: It looks like my system was simply too old: Initially, I was looking at Ubuntu 11.10
with an eglibc-2.13, and a double-check with a newly downloaded glibc-2.17 lead me to the
wrong file.

Many thanks for your help!
-

2013-05-02 07:06:53

by Richard Weinberger

[permalink] [raw]
Subject: Re: X86 fpu registers in a signal handler's ucontext

On Thu, May 2, 2013 at 7:42 AM, Warlich, Christof
<[email protected]> wrote:
> Mikael Pettersson <[email protected]> writes:
>> You're looking at the wrong header: glibc-2.17/sysdeps/i386/sys/ucontext.h is legacy SVR4.
>> Instead look at glibc-2.17/sysdeps/unix/sysv/linux/x86/sys/ucontext.h.
>>
>> (If the old one got installed on your system then something there is seriously wrong.)
>
> Oh-oh: It looks like my system was simply too old: Initially, I was looking at Ubuntu 11.10
> with an eglibc-2.13, and a double-check with a newly downloaded glibc-2.17 lead me to the
> wrong file.

Are you telling us that Ubuntu shipped the wrong header file?

--
Thanks,
//richard

2013-05-02 07:44:08

by Warlich, Christof

[permalink] [raw]
Subject: RE: X86 fpu registers in a signal handler's ucontext

richard -rw- weinberger <[email protected]> writes:
> Are you telling us that Ubuntu shipped the wrong header file?

Grmpf ... no. :-*

Here again, I obviously started looking at the wrong file
(i386-linux-gnu/sys/ucontext.h), which defines uc_mcontext
to be of type mcontext_t.

So the right header to be used seems to be asm-generic/ucontext.h,
which _does_ include the right definition of uc_mcontext to be of
type struct sigcontext even in Ubuntu 11.10.

Thanks again and sorry for the confusion, I hope I have my lesson
learned.

2013-05-02 09:05:17

by Warlich, Christof

[permalink] [raw]
Subject: RE: X86 fpu registers in a signal handler's ucontext

richard -rw- weinberger <[email protected]> writes:
> Are you telling us that Ubuntu shipped the wrong header file?

Hmm - at least I still don't know how to get the right definition
of uc_mcontext (with eglibc-2.13 on Ubuntu 11.10) ...

If I include both signal.h and asm-generic/ucontext.h, gcc reports
this error:

/usr/include/asm-generic/ucontext.h:4:8: error: redefinition of 'struct ucontext'
/usr/include/i386-linux-gnu/sys/ucontext.h:119:16: error: previous definition of 'struct ucontext'

Thus, signal.h obviously includes the wrong i386-linux-gnu/sys/ucontext.h
defining uc_mcontext to be of type mcontext_t.

So is it still me doing something wrong or or _did_ Ubuntu ship
the wrong header files?-

2013-05-02 11:14:54

by Mikael Pettersson

[permalink] [raw]
Subject: RE: X86 fpu registers in a signal handler's ucontext

Warlich, Christof writes:
> richard -rw- weinberger <[email protected]> writes:
> > Are you telling us that Ubuntu shipped the wrong header file?
>
> Hmm - at least I still don't know how to get the right definition
> of uc_mcontext (with eglibc-2.13 on Ubuntu 11.10) ...
>
> If I include both signal.h and asm-generic/ucontext.h, gcc reports
> this error:
>
> /usr/include/asm-generic/ucontext.h:4:8: error: redefinition of 'struct ucontext'
> /usr/include/i386-linux-gnu/sys/ucontext.h:119:16: error: previous definition of 'struct ucontext'
>
> Thus, signal.h obviously includes the wrong i386-linux-gnu/sys/ucontext.h
> defining uc_mcontext to be of type mcontext_t.
>
> So is it still me doing something wrong or or _did_ Ubuntu ship
> the wrong header files?

#include <signal.h>
#include <ucontext.h>

has worked for my SIGFPE handlers on Linux for the last 10+ years on various distros
and target architectures.

Can we stop this thread now? There is no _kernel_ issue here.

2013-05-03 03:18:12

by H. Peter Anvin

[permalink] [raw]
Subject: Re: X86 fpu registers in a signal handler's ucontext

On 04/29/2013 07:34 AM, Warlich, Christof wrote:
> Second, only FP state seems to be available through ucontext_t, and I would
> need to clear exceptions for SSE as well.

Not true.

> Can anyone give me some advice on how to I could proceed?

To optimize the common case, if the signal handler doesn't touch the FPU
the state is not reloaded from the signal stack. Therefore you need to
execute an FPU instruction -- pretty much any FPU instruction -- in your
signal handler in order to force the reload.

-hpa