diff --git a/.github/workflows/cibuild.yml b/.github/workflows/cibuild.yml index de48121a37b..c4d232bff64 100644 --- a/.github/workflows/cibuild.yml +++ b/.github/workflows/cibuild.yml @@ -110,7 +110,7 @@ jobs: with: arch: ${{ matrix.platform.arch }} branch: 'latest-stable' - packages: build-base cmake git mold sdl2-dev lzo-dev libjpeg-turbo-dev openal-soft-dev libogg-dev libtheora-dev libvorbis-dev + packages: build-base cmake git mold sdl2-dev lzo-dev libjpeg-turbo-dev openal-soft-dev libogg-dev libtheora-dev libvorbis-dev elfutils-dev - name: Install Ubuntu packages if: ${{ matrix.platform.name == 'Ubuntu' }} @@ -124,7 +124,8 @@ jobs: libopenal-dev:${{ matrix.platform.arch }} \ libogg-dev:${{ matrix.platform.arch }} \ libtheora-dev:${{ matrix.platform.arch }} \ - libvorbis-dev:${{ matrix.platform.arch }} + libvorbis-dev:${{ matrix.platform.arch }} \ + libdw-dev:${{ matrix.platform.arch }} - name: Install Clang Ubuntu packages if: ${{ matrix.platform.name == 'Ubuntu' && matrix.platform.cxx == 'clang++' }} @@ -138,7 +139,7 @@ jobs: - name: Install Fedora packages if: ${{ matrix.platform.name == 'Fedora' }} - run: dnf install -y git gcc gcc-c++ rpmdevtools cmake SDL2-devel lzo-devel libjpeg-turbo-devel openal-soft-devel libogg-devel libtheora-devel libvorbis-devel + run: dnf install -y git gcc gcc-c++ rpmdevtools cmake SDL2-devel lzo-devel libjpeg-turbo-devel openal-soft-devel libogg-devel libtheora-devel libvorbis-devel elfutils-devel - name: Set environment variables if: ${{ matrix.platform.cc != '' && matrix.platform.cxx != '' }} diff --git a/src/xrCore/CMakeLists.txt b/src/xrCore/CMakeLists.txt index 7e1fc50a178..7a4815d1c2b 100644 --- a/src/xrCore/CMakeLists.txt +++ b/src/xrCore/CMakeLists.txt @@ -456,6 +456,7 @@ target_link_libraries(xrCore PUBLIC pthread $<$:execinfo> + $<$:dw> SDL2::SDL2 PRIVATE diff --git a/src/xrCore/Debug/StackTrace.cpp b/src/xrCore/Debug/StackTrace.cpp index 72eed67dd80..80136328d0b 100644 --- a/src/xrCore/Debug/StackTrace.cpp +++ b/src/xrCore/Debug/StackTrace.cpp @@ -3,6 +3,8 @@ #include "StackTrace.h" #include "Threading/ScopeLock.hpp" +#include +#include #ifdef XR_PLATFORM_WINDOWS # include @@ -11,7 +13,8 @@ # include # define BACKTRACE_AVAILABLE -# if __has_include() +# if __has_include() && __has_include() +# include # include # include # define CXXABI_AVAILABLE @@ -260,6 +263,64 @@ xr_vector BuildStackTrace(u16 maxFramesCount) return BuildStackTrace(¤tThreadCtx, maxFramesCount); } #elif defined(BACKTRACE_AVAILABLE) + +#ifdef CXXABI_AVAILABLE +struct DebugInfoSession { + Dwfl_Callbacks callbacks = {}; + char* debuginfo_path = nullptr; + Dwfl* dwfl = nullptr; + + DebugInfoSession() { + callbacks.find_elf = dwfl_linux_proc_find_elf; + callbacks.find_debuginfo = dwfl_standard_find_debuginfo; + callbacks.debuginfo_path = &debuginfo_path; + + dwfl = dwfl_begin(&callbacks); + + int r; + r = dwfl_linux_proc_report(dwfl, getpid()); + r = dwfl_report_end(dwfl, nullptr, nullptr); + static_cast(r); + } + + ~DebugInfoSession() { + dwfl_end(dwfl); + } + + DebugInfoSession(DebugInfoSession const&) = delete; + DebugInfoSession& operator=(DebugInfoSession const&) = delete; +}; + +struct DebugInfo { + void* ip; + std::string function; + char const* file; + int line; + + DebugInfo(DebugInfoSession const& dis, void* ip) + : ip(ip) + , file() + , line(-1) + { + // Get function name. + uintptr_t ip2 = reinterpret_cast(ip); + Dwfl_Module* module = dwfl_addrmodule(dis.dwfl, ip2); + char const* name = dwfl_module_addrname(module, ip2); + + char* demangledName = abi::__cxa_demangle(name, NULL, NULL, NULL); + + function = demangledName ? demangledName : name ? name : ""; + ::free(demangledName); + + // Get source filename and line number. + if(Dwfl_Line* dwfl_line = dwfl_module_getsrc(module, ip2)) { + Dwarf_Addr addr; + file = dwfl_lineinfo(dwfl_line, &addr, &line, nullptr, nullptr, nullptr); + } + } +}; +#endif + xr_vector BuildStackTrace(u16 maxFramesCount) { xr_vector result; @@ -270,31 +331,21 @@ xr_vector BuildStackTrace(u16 maxFramesCount) if (strings) { - size_t demangledBufSize = 0; - char* demangledName = nullptr; +# ifdef CXXABI_AVAILABLE + DebugInfoSession dis; +# endif for (int i = 1; i < nptrs; i++) // skip this function { char* functionName = strings[i]; # ifdef CXXABI_AVAILABLE - Dl_info info; - - if (dladdr(array[i], &info)) - { - if (info.dli_sname) - { - int status = -1; - demangledName = abi::__cxa_demangle(info.dli_sname, demangledName, &demangledBufSize, &status); - if (status == 0) - { - functionName = demangledName; - } - } - } + DebugInfo dinfo = DebugInfo(dis, array[i]); + char func [2048]; + std::snprintf(func, 2048, ">> \033[31;1m%s\033[0m at \033[32;1;4m%s\033[0m:%d", dinfo.function.data(), dinfo.file, dinfo.line); + functionName = func; # endif result.emplace_back(functionName); } - ::free(demangledName); } return result;