Address of instruction causing SIGSEGV

From: Jeroen N. Witmond (jnw_at_xs4all.nl)
Date: 08/24/04


Date: 24 Aug 2004 07:11:56 -0700

This has been asked some times before, but I haven't found a single
answer that says it all. In my signal handler for SIGSEGV, I need to
determine the address of the instruction that caused the SIGSEGV. This
address is not the one found in siginfo.si_addr, as the latter is the
address of the memory that could not be accessed, and not of the
instruction referencing that address in memory.

>From a number of posts in a number of newsgroups, I gathered that the
address of the instruction causing the SIGSEGV could be found in
sigcontext.cr2. I also found references to field eip in the same
structure. A small program (see below) showed that cr2 equals zero and
eip contains something that could well be the address of the
instruction causing the SIGSEGV.

Questions:
- Is sigcontext.eip the correct field to look for the address of the
instruction causing the SIGSEGV?
- Is using an undeclared and undocumented parameter of the handler
(and a cast of the handler's address to sighandler_t to kill gcc's
warnings) the only way to access struct sigcontext?
- I am currently working with kernels 2.4.19 and 2.4.20. Does kernel
2.6 behave differently in this area? Does this behaviour depend on
other components, for instance libc?
- Is there a better newsgroup to ask these questions?

Thanks in advance,

Jeroen.

<cut here>
/* sigsegvhandler.c : Try to get address of instruction causing
SIGSEGV. */

#define _GNU_SOURCE

#include <signal.h>
#include <setjmp.h>
#include <stdio.h>
#include <string.h>

static int sigCaught;
static struct sigcontext sigContext;
static jmp_buf afterError;

static void sigcontextAction(int sig, struct sigcontext ctx)
{
  sigCaught = sig;
  sigContext = ctx;
  
  longjmp(afterError, 1);
}

int main()
{
  struct sigaction sigAction;
  memset(&sigAction, 0, sizeof(sigAction));
  sigAction.sa_handler = (sighandler_t)sigcontextAction;
  sigaction(SIGSEGV, &sigAction, 0);

  if (setjmp(afterError) == 0) {
    /* Cause a SIGSEGV. */
    int* invalid = 0;
    *invalid = 0;
    return 4; /* We should NOT get here. */
  }
  else {
    /* Show information about the signal caught. */
    printf("%s:%d: Cought signal %d, eip=0x%lx, cr2=0x%lx.\n",
           __FILE__, __LINE__, sigCaught, sigContext.eip, sigContext.cr2);
    return 0;
  }
}



Relevant Pages

  • Re: Address of instruction causing SIGSEGV
    ... >- Is sigcontext.eip the correct field to look for the address of the ... >instruction causing the SIGSEGV? ... >(and a cast of the handler's address to sighandler_t to kill gcc's ...
    (comp.os.linux.development.system)
  • Re: How to handle the same signal multiple times
    ... why the second SIGSEGV is not handled by the signal handler as the first ... And if I put a fprintfinto the signal handler it shows ... If setjmp/longjmp do save and restore the mask, ... void sigH(int sigNum) { ...
    (comp.os.linux.development.system)
  • Re: how to print instr ptr from stack in signal handler?
    ... > Want to catch SIGSEGV in a signal handler, print some meaningful info, then ... version, is to spawn a child process in the signal handler, which ...
    (comp.os.linux.development.apps)
  • Re: how to print instr ptr from stack in signal handler?
    ... > Want to catch SIGSEGV in a signal handler, print some meaningful info, then ... version, is to spawn a child process in the signal handler, which ...
    (comp.unix.programmer)
  • Re: 2.6.x signal handler bug
    ... > - Blocking a signal in its signal handler is explicitly allowed. ... > - The SIGSEGV that occurs during a stack overflow is of the GodFather kind. ... send the line "unsubscribe linux-kernel" in ...
    (Linux-Kernel)