I'm having problems handling SIGSEGV and SIGILL on Linux 2.6/Itanium ...
new to Linux, so I'm probably missing something obvious, but the same
program works fine on an AMD processor.

What I'm getting is that my SECOND signal exit doesn't happen, and I
get a core dump instead. I was attempting to figure out which Itanium
registers were readable from user-space by attempting to read each of
them from each processor in my system. It takes the SIGILL exit on
each processor for the FIRST instruction that fails, but the SECOND
failure gets me a core dump without getting to the signal handling
routine. On further testing, I found I can take as many SIGILL or
SIGSEGV exits as I want as long as they come from the SAME address
but as soon as I take either from a different address the signal
exit does not happen and I get a core dump instead. I can handle
one SIGILL and one SIGSEGV from different addresses, but the second
of either at a different address nets a core dump.

The program uses the Intel ICC compiler because it needs access to
the Itanium internal registers that are defined within ICC.

Here's the program I'm using to test (badly formatted by my email program).
Anyone have any idea why I'm seeing this behavior? Am I missing something
basic in my understanding of how signal handlers are supposed to work?
(that could easily be the case since I'm a s/390 mainframe programmer who's
pretty well lost trying to learn Linux)

The results I get from this program are three SIGSEGV exits from the first
occurrence of "*(long *)0 = 0;", three SIGILL exits from the first
"__getReg(_IA64_REG_PSR)", and then a core dump from the second instance
of "*(long *)0 = 0;".

On the AMD processor, I get the results I expected ... the program takes
all the SEGV and ILL handler exits and ends normally.



#include
#include
#include
#include
#include
#ifdef __ia64
#include
#include
#define BAD_OP __getReg(_IA64_REG_PSR)
#else
#define __USE_GNU
#include
#define BAD_OP asm(".byte 0xf,0xff")
#endif

static struct sigaction sa_segv, sa_segv_save, sa_ill, sa_ill_save;
static jmp_buf sigexit_save;
static int ruptcount = 0;
static int rupt_retries = 0;

//----------------------------------------------------------
// signal handler
//----------------------------------------------------------
void signal_handler(int signo, siginfo_t *info, void *ptr)
{
ucontext_t *uc;
printf("SIGNAL signo=%d, info=%p, ptr=%p\n", signo, info, ptr);
printf(" si_signo=%d, si_errno=%d, si_code=%d, si_value=%i, si_addr=%p\n",
info->si_signo, info->si_errno, info->si_code, info->si_value.sival_int, info->si_addr);
uc = (ucontext_t *)ptr;
#ifdef __ia64
struct sigcontext *sc = &uc->uc_mcontext;
printf(" sc_ip=%016lx\n", sc->sc_ip);
#else /* not __ia64 */
mcontext_t *mc = &uc->uc_mcontext;
#if __WORDSIZE == 64
printf(" IP=%016lx\n", mc->gregs[REG_RIP]);
#else
printf(" EIP=%08lx\n", mc->gregs[REG_EIP]);
#endif
#endif

// this mess with the counter is for debugging itanium handlers
// it seems to take any number of ints from the SAME address, but die on a second address
if(++ruptcount > 20) {printf("rupt count %i\n", ruptcount); exit(0); }
if (--rupt_retries <= 0) longjmp(sigexit_save, 1); // exit to just after setjmp() with non-zero rc after retries exhausted
// otherwise, just fall through to return
}

int main (int argc, char *argv[])
{
int rc;
int testno = 0;

sa_segv.sa_flags = SA_SIGINFO; // setup SEGSIGV handler
sa_segv.sa_sigaction = signal_handler;
sigemptyset(&sa_segv.sa_mask);
sigaction(SIGSEGV, &sa_segv, &sa_segv_save);

sa_ill.sa_flags = SA_SIGINFO; // setup SEGILL handler
sa_ill.sa_sigaction = signal_handler;
sigemptyset(&sa_ill.sa_mask);
sigaction(SIGILL, &sa_ill, &sa_ill_save);

rupt_retries = 3;
printf("Begin Test %i\n", ++testno);
rc = setjmp(sigexit_save);
if (rc == 0) {
*(long *)0 = 0;
} else {
printf("Returned from sigsegv\n");
}

rupt_retries = 3;
printf("Begin Test %i\n", ++testno);
rc = setjmp(sigexit_save);
if (rc == 0) {
BAD_OP;
} else {
printf("Returned from sigill\n");
}

printf("Begin Test %i\n", ++testno);
rc = setjmp(sigexit_save);
if (rc == 0) {
*(long *)0 = 0;
} else {
printf("Returned from sigsegv again\n");
}

printf("Begin Test %i\n", ++testno);
rc = setjmp(sigexit_save);
if (rc == 0) {
BAD_OP;
} else {
printf("Returned from sigill again\n");
}

sigaction(SIGSEGV, &sa_segv_save, NULL); // restore prior handlers
sigaction(SIGSEGV, &sa_ill_save, NULL);
printf("Bye\n");
return 0;
}