digitalmars.D.learn - Any ways to get addr2line working with DMD? works fine with GDC
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
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? ThanksDid 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
On Friday, 17 March 2023 at 20:53:07 UTC, WB wrote:On Thursday, 16 March 2023 at 22:07:04 UTC, ryuukk_ wrote:Yes i did compile with -g, i should have mentioned it in the post I will try with `-gs` and `-gdward=5`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? ThanksDid 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
I found what was the issue!! https://stackoverflow.com/a/63856113The 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
I found what was the issue!! https://stackoverflow.com/a/63856113The 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