Hi,

I've experimented somewhat with throwing exceptions from within a signal 
handler.
Libunwind seems to work in the case of SIGILL, SIGBUS, SIGSEGV, but not always 
for SIGFPE.

The attached program shall demonstrate a failing SIGFPE-case
(sigfpe.sh contains all necessary steps to demonstrate this).

The program runs successfully if you use the default gcc unwinding routines,
but it crashes, if you preload libunwind. The only difference between
gcc and libunwind seems to be the returned flag `ip_before_ins`
when calling _Unwind_GetIPInfo. This is also shown in the test program.

As far as I can tell the following happens (See attached backtrace and output):
- personality routine is called for sighandler()-frame (#0)
- libunwind identifies a signal stack frame (with no personality routine) (#1)
- personality routine is called for fpe()-frame (#2)
  Here _Unwind_GetIPInfo returns 0 for ip_before_ins because this frame
  is identified as a regular frame.

As I'm not an expert on that unwinding stuff, maybe somebody else on this list
can explain, why this happens - Is it a feature of gcc or a bug in libunwind? :)

Regards
Stefan
bt of sigfpe_ip in gdb:
#0  0x0000000000400a4a in sighandler(int) ()
#1  <signal handler called>
#2  0x0000000000400a10 in fpe() ()
#3  0x0000000000400a9a in main ()


--- Executing ---
*** Running with gcc's unwind ***
caught...
*** Running with libunwind's unwind ***
terminate called after throwing an instance of 'int'
./sigfpe.sh: line 18:  6135 Aborted                 
LD_PRELOAD=/usr/lib/libunwind.so ./sigfpe

--- Printing ip and before flag ---
*** Running with gcc's unwind ***
ip: 0x400a76, ip-before-ins: 0
ip: 0x400a10, ip-before-ins: 1
*** Running with libunwind's unwind ***
ip: 0x400a76, ip-before-ins: 0
ip: 0x400a10, ip-before-ins: 0

// Ensure libunwind is compiled with exception handling code!
//
// To demonstrate the behaviour, compile with g++ -fnon-call-exceptions sigfpe.cpp -o sigfpe
// and then run ./sigfpe vs. LD_PRELOAD=/usr/lib/libunwind.so.7 ./sigfpe
//
// If you just want to see the ip and the before-flag, compile with '-D SHOW_IP
//

#include <signal.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

#ifdef SHOW_IP
extern "C" long _Unwind_GetIPInfo(void*, void*);

int counter = 0;

// Overwrite personality routine to demonstrate different behaviour
// of _Unwind_GetIPInfo for gcc and libunwind
extern "C" int
__gxx_personality_v0(int, int, uint64_t, void*, void* context)
{
    int before = 0;
    long ip = _Unwind_GetIPInfo(context, &before);
    printf("ip: 0x%lx, ip-before-ins: %d\n", ip, before);
    if (++counter == 2) {
        // Just exit after the second call
        // There should now be a difference between gcc and libunwind
        if (before == 0) {
            // Expected libunwind code path
            exit(1);
        }
        // Expected gcc code path
        exit(0);
    }
    return 8; // continue unwind...
}
#endif

struct Test
{
    ~Test()
    {
    }
};

int i;
void fpe()
{
    Test test;
    i = 1 / 0;
}

void sighandler(int signo)
{
    throw 0;
}

int main (int argc, char **argv)
{
    try {
        signal(SIGFPE, &sighandler);
        fpe();
    } catch (int) {
        printf("caught...\n");
    }
}

Attachment: sigfpe.sh
Description: Bourne shell script

_______________________________________________
Libunwind-devel mailing list
[email protected]
http://lists.nongnu.org/mailman/listinfo/libunwind-devel

Reply via email to