0

so there are quite some question about this already and thank to threads like this one I have the file and line number kind of working.

The issue is that I am not getting what I was expecting in some case and try to figure out why and if there is a way to work around it.

Example

typedef struct _sig_ucontext {
    unsigned long uc_flags;
    struct ucontext *uc_link;
    stack_t uc_stack;
    struct sigcontext uc_mcontext;
    sigset_t uc_sigmask;
} sig_ucontext_t;

void crit_err_hdlr(int sig_num, siginfo_t * info, void * ucontext)
{
    void * array[50];
    void * caller_address;
    char ** messages;
    int size, i;
    sig_ucontext_t * uc;

    uc = (sig_ucontext_t *) ucontext;

    /* Get the address at the time the signal was raised */
#if defined(__i386__) // gcc specific
    caller_address = (void *) uc->uc_mcontext.eip; // EIP: x86 specific
#elif defined(__x86_64__) // gcc specific
    caller_address = (void *) uc->uc_mcontext.rip; // RIP: x86_64 specific
#endif

    fprintf(stderr, "signal %d (%s), address is %p from %p\n", sig_num, strsignal(sig_num), info->si_addr, (void *) caller_address);

    size = backtrace(array, 50);

    /* overwrite sigaction with caller's address */
    array[1] = caller_address;

    messages = backtrace_symbols(array, size);

    /* skip first stack frame (points here) */
    for (i = 1; i < size && messages != NULL; ++i)
    {
        fprintf(stderr, "[bt]: (%d) %s\n", i, messages[i]);

        char syscom[256];
        sprintf(syscom, "addr2line %p -e GEBMerge", array[i]);
        system(syscom);
    }

    free(messages);

    exit(EXIT_FAILURE);
}

I prepare the signal handler then I have the main function.

int main(int argc, char **argv)
{
    //     std::cerr << "Entering main function of GEBMerge.cxx...\n";

    struct sigaction sigact;

    sigact.sa_sigaction = crit_err_hdlr;
    sigact.sa_flags = SA_RESTART | SA_SIGINFO;

    if (sigaction(SIGSEGV, &sigact, (struct sigaction *) NULL) != 0)
    {
        fprintf(stderr, "error setting signal handler for %d (%s)\n",
        SIGSEGV, strsignal(SIGSEGV));

        exit(EXIT_FAILURE);
    }

    int* crash = 0;
    *crash = 666;

    return 0;
}

This will produce

signal 11 (Segmentation fault), address is (nil) from 0x402423
[bt]: (1) ./GEBMerge(main+0x43) [0x402423]
/mnt/hgfs/Dropbox/ORNL/software/goddess_daq/source/GEBMerge.cxx:245
[bt]: (2) ./GEBMerge(main+0x43) [0x402423]
/mnt/hgfs/Dropbox/ORNL/software/goddess_daq/source/GEBMerge.cxx:245
[bt]: (3) /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7fd58e7c1830]
??:0
[bt]: (4) ./GEBMerge(_start+0x29) [0x402519]
??:?

Which seems fine (even though I am not sure why the first line appears twice).

But then if I use this in the main instead

int main(int argc, char **argv)
{
    //     std::cerr << "Entering main function of GEBMerge.cxx...\n";

    struct sigaction sigact;

    sigact.sa_sigaction = crit_err_hdlr;
    sigact.sa_flags = SA_RESTART | SA_SIGINFO;

    if (sigaction(SIGSEGV, &sigact, (struct sigaction *) NULL) != 0)
    {
        fprintf(stderr, "error setting signal handler for %d (%s)\n",
        SIGSEGV, strsignal(SIGSEGV));

        exit(EXIT_FAILURE);
    }

    char* crash = 0;
    sprintf(crash, "crash it damit!");

    return 0;
}

I get the following

signal 11 (Segmentation fault), address is (nil) from 0x403503
[bt]: (1) ./GEBMerge(main+0x73) [0x403503]
/usr/include/x86_64-linux-gnu/bits/stdio2.h:34
[bt]: (2) ./GEBMerge(main+0x73) [0x403503]
/usr/include/x86_64-linux-gnu/bits/stdio2.h:34
[bt]: (3) /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0) 
[0x7f5f74ba9830]
??:0
[bt]: (4) ./GEBMerge(_start+0x29) [0x406169]
??:?

I understand why the line /usr/include/x86_64-linux-gnu/bits/stdio2.h:34 appears (linked to the sprintf function I assume) but I was expecting to see, somewhere in this stacktrace, a reference to the line calling sprintf in the main of my program.

I guess there is something I am missing but cannot figure out what.

Thanks for any help

8
  • 1
    Did you compile with debugging symbols enabled (-g)? Commented Feb 13, 2018 at 23:55
  • I always use -g3, personally - depending on the compiler. Commented Feb 14, 2018 at 0:02
  • Since you tagged this a C++ and are programming in C++, get rid of the typedef before a struct, as it is not needed in C++. You also don't need the struct keyword when declaring a variable. Commented Feb 14, 2018 at 1:17
  • You should also use std::string instead of char *. With pointers, you have to deal with ownership and maybe deep copy as well as always allocating space for the character array. You can pass a std::string by reference so no copies are made and you don't need to worry about ownership or misplaced pointers. Commented Feb 14, 2018 at 1:18
  • You might try adding the flag -rdynamic to your compiler and linker arguments; I find that helps generate more useful stack traces. Commented Feb 14, 2018 at 5:05

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.