5

I am reading the book - "C Interfaces and Implementations" by David Hanson. This exercise questions seems interesting and am unable to find a solution:

On some systems, a program can invoke a debugger on itself when it has detected an error. This facility is particularly useful during development, when assertion failures may be common.

Can you provide a short example on how to invoke a debugger.

void handle_seg_fault(int arg)
{
    /* how to invoke debugger from within here */
}

int main()
{
    int *ptr = NULL;
    signal(SIGSEGV, handle_seg_fault);
    /* generate segmentation fault */
    *ptr = 1;
}
sloth
  • 99,095
  • 21
  • 171
  • 219
user138645
  • 772
  • 1
  • 7
  • 18
  • Whatever you do, make sure you only use [async signal safe functions](http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html) from within your signal handler. For example, of all the `exec` variants only `execve` and `execle` are safe to execute in the context of a (async signal catching) signal handler. Now, wether it is generally wise to do that at all (in the face of a "state corrupting singal" like SIGSEGV) is another thing. I'd go with (a) an external debugger or (b) inspect the coredump post mortem. – Christian.K Jul 16 '12 at 07:12

2 Answers2

4

Elaborating on Christian.K's comment, fork()ing a debugger in the face of something like a SIGFPE or SIGSEGV might not be the best of ideas, because...

  1. your program is potentially corrupt to begin with, making the fork() unsafe;
  2. you might want to use something different for debugging than what the program has hardcoded;
  3. the average application user does not know how to handle a debugger;
  4. anyone competent with a debugger will usually prefer the coredump over the auto-invoked debugger.

A coredump that I can copy to a testbed beats a debugger instance at my customer's workplace any time of the day. A debugger interface makes for a lousy end-user error message.

DevSolar
  • 67,862
  • 21
  • 134
  • 209
3

I have got this:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <errno.h>

void exception_handler(int)
{
    int pid = getpid();
    if (fork() != 0) {
        while(true) sleep(1000);
    }
    char buf[20];
    sprintf(buf, "--pid=%u", pid);
    execlp("gdb", "gdb", buf, NULL);
    exit(-1);
}

int init()
{
    if (signal(SIGSEGV, exception_handler) < 0) {
       return errno;
    }
    if (signal(SIGILL, exception_handler) < 0) {
        return errno;
    }
    if (signal(SIGFPE, exception_handler) < 0) {
        return errno;
    }
    return 0;
}

int main()
{
    if (int rc = init()) {
       fprintf(stderr, "init error: %s\n", strerror(rc));
       return 1;
    }
    *((char*)(0)) = 1;
}
user138645
  • 772
  • 1
  • 7
  • 18
Dmitry Poroh
  • 3,705
  • 20
  • 34