diff --git a/config.lib b/config.lib index 07985a4f83..5c7c994267 100644 --- a/config.lib +++ b/config.lib @@ -1554,6 +1554,37 @@ make_cflags_and_ldflags() { if [ "$os" != "CYGWIN" ] && [ "$os" != "HAIKU" ] && [ "$os" != "OPENBSD" ] && [ "$os" != "MINGW" ] && [ "$os" != "MORPHOS" ] && [ "$os" != "OSX" ] && [ "$os" != "DOS" ] && [ "$os" != "WINCE" ] && [ "$os" != "PSP" ] && [ "$os" != "OS2" ]; then LIBS="$LIBS -lpthread" fi + if [ "$os" != "CYGWIN" ] && [ "$os" != "HAIKU" ] && [ "$os" != "MINGW" ] && [ "$os" != "MORPHOS" ] && [ "$os" != "OSX" ] && [ "$os" != "DOS" ] && [ "$os" != "WINCE" ] && [ "$os" != "PSP" ] && [ "$os" != "OS2" ]; then + "$cc_host" -o /dev/null -x c++ - -ldl 2> /dev/null << EOL + #include + int main() { + Dl_info info; + return dladdr(0, &info); + } +EOL + if [ $? -ne 0 ]; then + log 1 "checking libdl... no" + else + log 1 "checking libdl... found" + LIBS="$LIBS -ldl" + CFLAGS="$CFLAGS -DWITH_DL" + fi + + "$cc_host" -o /dev/null -x c++ - -lstdc++ 2> /dev/null << EOL + #include + int main() { + int status = -1; + char *demangled = abi::__cxa_demangle("test", 0, 0, &status); + return 0; + } +EOL + if [ $? -ne 0 ]; then + log 1 "checking abi::__cxa_demangle... no" + else + log 1 "checking abi::__cxa_demangle... found" + CFLAGS="$CFLAGS -DWITH_DEMANGLE" + fi + fi if [ "$os" != "CYGWIN" ] && [ "$os" != "HAIKU" ] && [ "$os" != "MINGW" ] && [ "$os" != "DOS" ] && [ "$os" != "WINCE" ]; then LIBS="$LIBS -lc" diff --git a/src/os/unix/crashlog_unix.cpp b/src/os/unix/crashlog_unix.cpp index 47de057f7e..1bcbe63fde 100644 --- a/src/os/unix/crashlog_unix.cpp +++ b/src/os/unix/crashlog_unix.cpp @@ -22,6 +22,12 @@ #if defined(__GLIBC__) /* Execinfo (and thus making stacktraces) is a GNU extension */ # include +#if defined(WITH_DL) +# include +#endif +#if defined(WITH_DEMANGLE) +# include +#endif #elif defined(SUNOS) # include # include @@ -114,6 +120,26 @@ class CrashLogUnix : public CrashLog { char **messages = backtrace_symbols(trace, trace_size); for (int i = 0; i < trace_size; i++) { +#if defined(WITH_DL) + Dl_info info; + int dladdr_result = dladdr(trace[i], &info); + if (dladdr_result && info.dli_sname) { + int status = -1; + char *demangled = NULL; +#if defined(WITH_DEMANGLE) + demangled = abi::__cxa_demangle(info.dli_sname, NULL, 0, &status); +#endif + const char *name = (demangled != NULL && status == 0) ? demangled : info.dli_sname; + buffer += seprintf(buffer, last, " [%02i] %*p %-40s %s + 0x%zx\n", i, int(2 + sizeof(void*) * 2), + trace[i], info.dli_fname, name, (char *)trace[i] - (char *)info.dli_saddr); + free(demangled); + continue; + } else if (dladdr_result && info.dli_fname) { + buffer += seprintf(buffer, last, " [%02i] %*p %-40s + 0x%zx\n", i, int(2 + sizeof(void*) * 2), + trace[i], info.dli_fname, (char *)trace[i] - (char *)info.dli_fbase); + continue; + } +#endif buffer += seprintf(buffer, last, " [%02i] %s\n", i, messages[i]); } free(messages);