Lazer
Lazer

Reputation: 94830

How are segmentation faults reported?

I was just wondering how segmentation faults might get reported.

Which one of these reports the segmentation faults (just an example), and how?

Upvotes: 4

Views: 162

Answers (4)

Charlie Martin
Charlie Martin

Reputation: 112366

okay, to start with, a segmentation fault happens when the CPU attempts to access an address to which the process doesn't have access. At the lowest level, the implementation of memory mapping has to detect that, which in general produces an interrupt. The kernel receives that interrupt, and has a table of addresses of other segments of code, each of which is intended to handle that interrupt.

When the kernel receives that interrupt, it translates it into a specific value (I'm being vague because the exact details vary both with hardware architecture and kernel implementation). SIGSEGV is usually defined to have the value 11, but the exact value isn't important; it's defined in signal.h.

At that point, the signal value is passed to another table inside the kernel, which contains the addresses of "signal handlers". One of those handlers is at the offset represented by SIGSEGV. Unless you have done something to change it, that address is usually of a routine that causes a core dump, assuming the appropriate limits permit, but you can replace that with the address of your own routine, which can do anything you like.

Upvotes: 1

Sam Liao
Sam Liao

Reputation: 46043

You can have some code like this which will call the GDB command to dump the call trace:

void BacktraceOnSegv() {
  struct sigaction action = {};
  action.sa_handler = DumpBacktrace;
  if (sigaction(SIGSEGV, &action, NULL) < 0) {
    perror("sigaction(SEGV)");
  }
}

void DumpBacktrace(int) {
  pid_t dying_pid = getpid();
  pid_t child_pid = fork();
  if (child_pid < 0) {
    perror("fork() while collecting backtrace:");
  } else if (child_pid == 0) {
    char buf[1024];
    sprintf(buf, "gdb -p %d -batch -ex bt 2>/dev/null | "
            "sed '0,/<signal handler/d'", dying_pid);
    const char* argv[] = {"sh", "-c", buf, NULL};
    execve("/bin/sh", (char**)argv, NULL);
    _exit(1);
  } else {
    waitpid(child_pid, NULL, 0);
  }
  _exit(1);
}

Here is an implementation that support more platforms.

Upvotes: 2

Jonathan Leffler
Jonathan Leffler

Reputation: 753695

If you take a look at the functions wait() or waitpid(), you will find that one of the bits in the exit status indicates a core dump. The POSIX specification mentions WIFSIGNALED [sic] and WTERMSIG to get the signal that terminated the process. The POSIX specification doesn't mention it, but on Mac OS X (10.7.4) for example, there's a WCOREDUMP() macro to test whether a core file was created.

Upvotes: 2

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 798626

The process will just die, so obviously it cannot report it.

This is actually false. It is possible to install a SIGSEGV handler to replace the default one, which simply dumps core and dies. A preload library can do so to catch a segmentation violation and use the limited facilities available to notify another process running on the system of what has happened before exiting.

Upvotes: 3

Related Questions