Thread overview
Any ways to get addr2line working with DMD? works fine with GDC
Mar 16, 2023
ryuukk_
Mar 17, 2023
WB
Mar 17, 2023
ryuukk_
Mar 21, 2023
ryuukk_
Mar 21, 2023
ryuukk_
March 16, 2023

Hello,

I'm trying to catch segfaults, after reading lot of ressources online, i came up with this:

import core.stdc.signal: SIGSEGV, SIGFPE, SIGILL, SIGABRT, signal;
import core.stdc.stdlib: free;
import core.stdc.string: strlen;
import core.sys.posix.unistd: STDERR_FILENO, readlink;
import core.sys.posix.signal: SIGUSR1;
import core.sys.posix.stdio: popen, pclose;
import core.sys.linux.execinfo: backtrace, backtrace_symbols;

import core.stdc.stdlib;
import core.stdc.stdio;
import core.stdc.string;


extern (C) void main()
{
    signal(SIGSEGV, &handler);
    signal(SIGUSR1, &handler);

    test();
}

void test()
{
    int* a;

    *a = 1;
}

extern (C) void handler(int sig) nothrow @nogc
{
    enum STACK_HIST = 6;
    void*[STACK_HIST] array;
    int size;

    string signal_string;
    switch (sig)
    {
    case SIGSEGV:
        signal_string = "SIGSEGV";
        break;
    case SIGFPE:
        signal_string = "SIGFPE";
        break;
    case SIGILL:
        signal_string = "SIGILL";
        break;
    case SIGABRT:
        signal_string = "SIGABRT";
        break;
    default:
        signal_string = "unknown";
        break;
    }

    import core.stdc.stdio : fprintf, stderr;

    fprintf(stderr, "-------------------------------------------------------------------+\r\n");
    fprintf(stderr, "Received signal %s (%d)\r\n", signal_string.ptr, sig);
    fprintf(stderr, "-------------------------------------------------------------------+\r\n");

    // get void*'s for all entries on the stack
    size = backtrace(&array[0], STACK_HIST);
    char** strings = backtrace_symbols(&array[0], size);

    enum BUF_SIZE = 1024;
    char[BUF_SIZE] syscom;
    char[BUF_SIZE] my_exe;
    ulong path_size = readlink("/proc/self/exe", &my_exe[0], BUF_SIZE);
    my_exe[path_size] = 0;

    printf("executable: %s\n", &my_exe[0]);
    printf("backtrace: %i\n", size);

    for (auto i = 2; i < size; ++i)
    {
        auto line = strings[i];
        auto len = strlen(line);
        bool insideParenthesis;
        int startParenthesis;
        int endParenthesis;
        bool insideShit;
        int startShit;
        int endShit;
        for(int j = 0; j < len; j++)
        {
            // ()
            if (!insideParenthesis && line[j] == '(')
            {
                insideParenthesis = true;
                startParenthesis = j+1;
            }
            else if (insideParenthesis && line[j] == ')')
            {
                insideParenthesis = false;
                endParenthesis = j;
            }
            // []
            if (!insideShit && line[j] == '[')
            {
                insideShit = true;
                startShit = j+1;
            }
            else if (insideShit && line[j] == ']')
            {
                insideShit = false;
                endShit = j;
            }
        }

        // printf("%.*s ::  %.*s\n", (endParenthesis - startParenthesis), &line[startParenthesis],  (endShit - startShit), &line[startShit]);
        // char[256] addr = 0;
        // memcpy(addr.ptr, &line[startShit], (endShit-startShit));

        sprintf(&syscom[0], "addr2line %s -e %s | ddemangle", array[i], &my_exe[0]);
        system(&syscom[0]);

        printf("  >%s\n", strings[i]);


        //sprintf(&syscom[0], "addr2line %p -f -e %s | ddemangle", strings[i], &my_exe[0]);
        //system(&syscom[0]);
    }

    exit(-1);
}

The problem is when i compile with DMD i get:

??:0

When i compile it with GDC i get proper file + line

What does GDC do different than DMD?

Is there a way to get the same result as GDC with DMD?

Thanks

March 17, 2023

On Thursday, 16 March 2023 at 22:07:04 UTC, ryuukk_ wrote:

>

Hello,

The problem is when i compile with DMD i get:

??:0

When i compile it with GDC i get proper file + line

What does GDC do different than DMD?

Is there a way to get the same result as GDC with DMD?

Thanks

Did you compile with -g? You can also play with -gs, and -gdwarf=5. In the past there was also -gc option, but it should be avoided.

March 17, 2023

On Friday, 17 March 2023 at 20:53:07 UTC, WB wrote:

>

On Thursday, 16 March 2023 at 22:07:04 UTC, ryuukk_ wrote:

>

Hello,

The problem is when i compile with DMD i get:

??:0

When i compile it with GDC i get proper file + line

What does GDC do different than DMD?

Is there a way to get the same result as GDC with DMD?

Thanks

Did you compile with -g? You can also play with -gs, and -gdwarf=5. In the past there was also -gc option, but it should be avoided.

Yes i did compile with -g, i should have mentioned it in the post

I will try with -gs and -gdward=5

March 21, 2023

I found what was the issue!! https://stackoverflow.com/a/63856113

>

The 0x55XXXXXXXXXX address you got is most likely the memory address of the function after the EXE is loaded from disk. addr2line only recognizes VMA addresses like the ones that you got from disassembling with objdump.

It now works, using the code that was provided in that answer!

Now i can catch segfaults and get a precise location in my code without fuss!

Hopefully it is as easy with windows..

extern (C) void main()
{
    signal(SIGSEGV, &handler);
    signal(SIGUSR1, &handler);

    test();
}

void test()
{
    int* a;

    *a = 1;
}
-------------------------------------------------------------------+
Received signal SIGSEGV (11)
-------------------------------------------------------------------+
executable: /mnt/c/tmp/backtrace/app
backtrace: 6
/mnt/c/tmp/backtrace/app.d:25 void app.test()+0xe
/mnt/c/tmp/backtrace/app.d:19 main+0x2b
??:0 __libc_start_main+0xf3
??:? _start+0x2e

Here is the fullcode so far (needs cleanup and, selective imports to keep track of what's really neded):

import core.stdc.signal : SIGSEGV, SIGFPE, SIGILL, SIGABRT, signal;
import core.stdc.stdlib : free, exit;
import core.stdc.string : strlen, memcpy;
import core.stdc.stdio : fprintf, stderr, printf, sprintf, fgets, fclose, FILE;
import core.sys.posix.unistd : STDERR_FILENO, readlink;
import core.sys.posix.signal : SIGUSR1;
import core.sys.posix.stdio : popen, pclose;
import core.sys.linux.execinfo : backtrace, backtrace_symbols;
import core.sys.linux.dlfcn : dladdr, dladdr1, Dl_info, RTLD_DL_LINKMAP;
import core.sys.linux.link : link_map;


extern (C) void main()
{
    signal(SIGSEGV, &handler);
    signal(SIGUSR1, &handler);

    test();
}

void test()
{
    int* a;

    *a = 1;
}

extern (C) void handler(int sig) nothrow @nogc
{
    enum MAX_DEPTH = 6;

    string signal_string;
    switch (sig)
    {
    case SIGSEGV:
        signal_string = "SIGSEGV";
        break;
    case SIGFPE:
        signal_string = "SIGFPE";
        break;
    case SIGILL:
        signal_string = "SIGILL";
        break;
    case SIGABRT:
        signal_string = "SIGABRT";
        break;
    default:
        signal_string = "unknown";
        break;
    }


    fprintf(stderr, "-------------------------------------------------------------------+\r\n");
    fprintf(stderr, "Received signal %s (%d)\r\n", signal_string.ptr, sig);
    fprintf(stderr, "-------------------------------------------------------------------+\r\n");

    void*[MAX_DEPTH] trace;
    int stack_depth = backtrace(&trace[0], MAX_DEPTH);
    char** strings = backtrace_symbols(&trace[0], stack_depth);

    enum BUF_SIZE = 1024;
    char[BUF_SIZE] syscom = 0;
    char[BUF_SIZE] my_exe = 0;
    char[BUF_SIZE] output = 0;

    readlink("/proc/self/exe", &my_exe[0], BUF_SIZE);

    printf("executable: %s\n", &my_exe[0]);
    printf("backtrace: %i\n", stack_depth);

    for (auto i = 2; i < stack_depth; ++i)
    {
        auto line = strings[i];
        auto len = strlen(line);
        bool insideParenthesis;
        int startParenthesis;
        int endParenthesis;
        for (int j = 0; j < len; j++)
        {
            // ()
            if (!insideParenthesis && line[j] == '(')
            {
                insideParenthesis = true;
                startParenthesis = j + 1;
            }
            else if (insideParenthesis && line[j] == ')')
            {
                insideParenthesis = false;
                endParenthesis = j;
            }
        }
        auto addr = convert_to_vma(cast(size_t) trace[i]);
        FILE* fp;

        auto locLen = sprintf(&syscom[0], "addr2line -e %s %p | ddemangle", &my_exe[0], addr);
        fp = popen(&syscom[0], "r");

        auto loc = fgets(&output[0], output.length, fp);
        fclose(fp);

        // printf("loc: %s\n", loc);

        auto getLen = strlen(output.ptr);

        char[256] func = 0;
        memcpy(func.ptr, &line[startParenthesis], (endParenthesis - startParenthesis));
        sprintf(&syscom[0], "echo '%s' | ddemangle", func.ptr);
        fp = popen(&syscom[0], "r");

        output[getLen - 1] = ' '; // strip new line
        auto locD = fgets(&output[getLen], cast(int)(output.length - getLen), fp);
        fclose(fp);

        printf("%s", output.ptr);
    }
    exit(-1);
}

size_t convert_to_vma(size_t addr) nothrow @nogc
{
    Dl_info info;
    link_map* link_map;
    dladdr1(cast(void*) addr, &info, cast(void**)&link_map, RTLD_DL_LINKMAP);
    return addr - link_map.l_addr;
}

March 21, 2023

I found what was the issue!! https://stackoverflow.com/a/63856113

>

The 0x55XXXXXXXXXX address you got is most likely the memory address of the function after the EXE is loaded from disk. addr2line only recognizes VMA addresses like the ones that you got from disassembling with objdump.

It now works, using the code that was provided in that answer!

Now i can catch segfaults and get a precise location in my code without fuss!

Hopefully it is as easy with windows..

extern (C) void main()
{
    signal(SIGSEGV, &handler);
    signal(SIGUSR1, &handler);

    test();
}

void test()
{
    int* a;

    *a = 1;
}
-------------------------------------------------------------------+
Received signal SIGSEGV (11)
-------------------------------------------------------------------+
executable: /mnt/c/tmp/backtrace/app
backtrace: 6
/mnt/c/tmp/backtrace/app.d:25 void app.test()+0xe
/mnt/c/tmp/backtrace/app.d:19 main+0x2b
??:0 __libc_start_main+0xf3
??:? _start+0x2e

Here is the fullcode so far (needs cleanup and, selective imports to keep track of what's really neded):

import core.stdc.signal : SIGSEGV, SIGFPE, SIGILL, SIGABRT, signal;
import core.stdc.stdlib : free, exit;
import core.stdc.string : strlen, memcpy;
import core.stdc.stdio : fprintf, stderr, printf, sprintf, fgets, fclose, FILE;
import core.sys.posix.unistd : STDERR_FILENO, readlink;
import core.sys.posix.signal : SIGUSR1;
import core.sys.posix.stdio : popen, pclose;
import core.sys.linux.execinfo : backtrace, backtrace_symbols;
import core.sys.linux.dlfcn : dladdr, dladdr1, Dl_info, RTLD_DL_LINKMAP;
import core.sys.linux.link : link_map;


extern (C) void main()
{
    signal(SIGSEGV, &handler);
    signal(SIGUSR1, &handler);

    test();
}

void test()
{
    int* a;

    *a = 1;
}

extern (C) void handler(int sig) nothrow @nogc
{
    enum MAX_DEPTH = 6;

    string signal_string;
    switch (sig)
    {
    case SIGSEGV:
        signal_string = "SIGSEGV";
        break;
    case SIGFPE:
        signal_string = "SIGFPE";
        break;
    case SIGILL:
        signal_string = "SIGILL";
        break;
    case SIGABRT:
        signal_string = "SIGABRT";
        break;
    default:
        signal_string = "unknown";
        break;
    }


    fprintf(stderr, "-------------------------------------------------------------------+\r\n");
    fprintf(stderr, "Received signal %s (%d)\r\n", signal_string.ptr, sig);
    fprintf(stderr, "-------------------------------------------------------------------+\r\n");

    void*[MAX_DEPTH] trace;
    int stack_depth = backtrace(&trace[0], MAX_DEPTH);
    char** strings = backtrace_symbols(&trace[0], stack_depth);

    enum BUF_SIZE = 1024;
    char[BUF_SIZE] syscom = 0;
    char[BUF_SIZE] my_exe = 0;
    char[BUF_SIZE] output = 0;

    readlink("/proc/self/exe", &my_exe[0], BUF_SIZE);

    printf("executable: %s\n", &my_exe[0]);
    printf("backtrace: %i\n", stack_depth);

    for (auto i = 2; i < stack_depth; ++i)
    {
        auto line = strings[i];
        auto len = strlen(line);
        bool insideParenthesis;
        int startParenthesis;
        int endParenthesis;
        for (int j = 0; j < len; j++)
        {
            // ()
            if (!insideParenthesis && line[j] == '(')
            {
                insideParenthesis = true;
                startParenthesis = j + 1;
            }
            else if (insideParenthesis && line[j] == ')')
            {
                insideParenthesis = false;
                endParenthesis = j;
            }
        }
        auto addr = convert_to_vma(cast(size_t) trace[i]);
        FILE* fp;

        auto locLen = sprintf(&syscom[0], "addr2line -e %s %p | ddemangle", &my_exe[0], addr);
        fp = popen(&syscom[0], "r");

        auto loc = fgets(&output[0], output.length, fp);
        fclose(fp);

        // printf("loc: %s\n", loc);

        auto getLen = strlen(output.ptr);

        char[256] func = 0;
        memcpy(func.ptr, &line[startParenthesis], (endParenthesis - startParenthesis));
        sprintf(&syscom[0], "echo '%s' | ddemangle", func.ptr);
        fp = popen(&syscom[0], "r");

        output[getLen - 1] = ' '; // strip new line
        auto locD = fgets(&output[getLen], cast(int)(output.length - getLen), fp);
        fclose(fp);

        printf("%s", output.ptr);
    }
    exit(-1);
}

size_t convert_to_vma(size_t addr) nothrow @nogc
{
    Dl_info info;
    link_map* link_map;
    dladdr1(cast(void*) addr, &info, cast(void**)&link_map, RTLD_DL_LINKMAP);
    return addr - link_map.l_addr;
}