www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Any ways to get addr2line working with DMD? works fine with GDC

reply ryuukk_ <ryuukk.dev gmail.com> writes:
Hello,

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

```D
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
Mar 16 2023
parent reply WB <witold.baryluk gmail.com> writes:
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.
Mar 17 2023
next sibling parent ryuukk_ <ryuukk.dev gmail.com> writes:
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`
Mar 17 2023
prev sibling next sibling parent ryuukk_ <ryuukk.dev gmail.com> writes:
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.. ```D 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): ```D 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; } ```
Mar 21 2023
prev sibling parent ryuukk_ <ryuukk.dev gmail.com> writes:
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.. ```D 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): ```D 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; } ```
Mar 21 2023