From 513ef0f12b49b89550b4061b67ee2b429ee6d919 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Mon, 13 Jul 2026 11:00:35 -0300 Subject: [PATCH] Move backward implementation to its own module but still have an special version for ecode. Integrate backward into unit-tests. --- .github/workflows/eepp-linux-build-check.yml | 2 +- .../workflows/eepp-windows-build-check.yml | 22 +++++++- premake4.lua | 25 ++++++--- premake5.lua | 20 ++++++-- .../backward/src}/backward.cpp | 51 +++++++++++++------ 5 files changed, 91 insertions(+), 29 deletions(-) rename src/{tools/ecode => modules/backward/src}/backward.cpp (87%) diff --git a/.github/workflows/eepp-linux-build-check.yml b/.github/workflows/eepp-linux-build-check.yml index d9e628a65..061a51850 100644 --- a/.github/workflows/eepp-linux-build-check.yml +++ b/.github/workflows/eepp-linux-build-check.yml @@ -24,7 +24,7 @@ jobs: tar xvzf premake-5.0.0-beta6-linux.tar.gz - name: Build run: | - ./premake5 --disable-static-build gmake + ./premake5 --disable-static-build --with-debug-symbols gmake cd make/linux make all -j$(nproc) -e config=release_x86_64 - name: Unit Tests diff --git a/.github/workflows/eepp-windows-build-check.yml b/.github/workflows/eepp-windows-build-check.yml index fb41a19aa..714aaec39 100644 --- a/.github/workflows/eepp-windows-build-check.yml +++ b/.github/workflows/eepp-windows-build-check.yml @@ -28,7 +28,7 @@ jobs: - name: Create project shell: powershell run: | - ./premake5.exe --windows-vc-build --disable-static-build vs2022 + ./premake5.exe --windows-vc-build --disable-static-build --with-debug-symbols vs2022 - name: Build shell: cmd run: | @@ -37,6 +37,15 @@ jobs: uses: f3d-app/install-mesa-windows-action@v1 with: path: ${{ github.workspace }}/bin/unit_tests + - name: Enable crash dumps + shell: powershell + run: | + $dumpDir = (New-Item -ItemType Directory -Force -Path "bin\unit_tests\output").FullName + $dumpKey = "HKCU:\Software\Microsoft\Windows\Windows Error Reporting\LocalDumps\eepp-unit_tests.exe" + New-Item -Path $dumpKey -Force | Out-Null + New-ItemProperty -Path $dumpKey -Name DumpFolder -PropertyType ExpandString -Value $dumpDir -Force | Out-Null + New-ItemProperty -Path $dumpKey -Name DumpType -PropertyType DWord -Value 2 -Force | Out-Null + New-ItemProperty -Path $dumpKey -Name DumpCount -PropertyType DWord -Value 2 -Force | Out-Null - name: Unit Tests shell: cmd env: @@ -49,3 +58,14 @@ jobs: with: name: windows-test-output path: bin\unit_tests\output\* + - name: Upload crash symbols + if: failure() + uses: actions/upload-artifact@v4 + with: + name: windows-crash-symbols + if-no-files-found: warn + path: | + bin\unit_tests\eepp-unit_tests.exe + bin\unit_tests\eepp-unit_tests.pdb + libs\windows\x86_64\eepp.dll + libs\windows\x86_64\eepp.pdb diff --git a/premake4.lua b/premake4.lua index 4ee7719f2..33c35f858 100644 --- a/premake4.lua +++ b/premake4.lua @@ -1010,6 +1010,21 @@ function eepp_module_physics_add() includedirs { "src/modules/physics/include/", "src/modules/physics/src/" } end +function eepp_module_backward_add( ecode_mode ) + files { "src/modules/backward/src/backward.cpp" } + if ecode_mode then + defines { "EE_BACKWARD_ECODE_MODE" } + end + configuration {} + if os.is_real("windows") or os.is_real("mingw32") or os.is_real("mingw64") then + links { "dbghelp", "psapi" } + end + if os.is_real("linux") or os.is_real("bsd") then + linkoptions { "-rdynamic" } + end + configuration {} +end + function build_eepp( build_name ) includedirs { "include", @@ -1818,6 +1833,7 @@ solution "eepp" set_kind() language "C++" files { "src/tools/ecode/**.cpp" } + eepp_module_backward_add( true ) includedirs { "src/thirdparty/efsw/include", "src/thirdparty", "src/modules/eterm/include/", "src/modules/languages-syntax-highlighting/src" } links { "efsw-static", "eterm-static", "languages-syntax-highlighting-static", "libyaml-static", "tinyexpr-static" } if os.is("windows") then @@ -1835,12 +1851,9 @@ solution "eepp" if os_findlib("dw") then links { "dw" } - defines { "ECODE_HAS_DW" } + defines { "EE_BACKWARD_HAS_DW" } end end - if os.is_real("windows") or os.is_real("mingw32") or os.is_real("mingw64") then - links { "dbghelp", "psapi" } - end if os.is("haiku") then links { "bsd", "network" } end @@ -1862,9 +1875,6 @@ solution "eepp" if os.is_real("linux") or os.is_real("macosx") or os.is_real("bsd") or os.is_real("haiku") then buildoptions { "-g1", "-fvisibility=default" } end - if os.is_real("linux") or os.is_real("bsd") then - linkoptions { "-rdynamic" } - end project "eterm" set_kind() @@ -1925,6 +1935,7 @@ solution "eepp" includedirs { "src/modules/eterm/include/", "src/thirdparty" } language "C++" files { "src/tests/unit_tests/*.cpp" } + eepp_module_backward_add( false ) build_link_configuration( "eepp-unit_tests", true ) if os.isfile("external_projects.lua") then diff --git a/premake5.lua b/premake5.lua index 5d74cfadf..b7164a735 100644 --- a/premake5.lua +++ b/premake5.lua @@ -909,6 +909,18 @@ function eepp_module_physics_add() incdirs { "src/modules/physics/include/", "src/modules/physics/src/" } end +function eepp_module_backward_add( ecode_mode ) + files { "src/modules/backward/src/backward.cpp" } + if ecode_mode then + defines { "EE_BACKWARD_ECODE_MODE" } + end + filter "system:windows" + links { "dbghelp", "psapi" } + filter "system:linux or system:bsd" + linkoptions { "-rdynamic" } + filter {} +end + function build_eepp( build_name ) files { "src/eepp/core/*.cpp", "src/eepp/math/*.cpp", @@ -1805,6 +1817,7 @@ workspace "eepp" set_kind() language "C++" files { "src/tools/ecode/**.cpp" } + eepp_module_backward_add( true ) incdirs { "src/thirdparty/efsw/include", "src/thirdparty", "src/modules/eterm/include/", "src/modules/languages-syntax-highlighting/src" } links { "efsw-static", "eterm-static", "languages-syntax-highlighting-static", "libyaml-static", "tinyexpr-static" } build_link_configuration( "ecode", false ) @@ -1829,14 +1842,10 @@ workspace "eepp" links { "util" } if os_findlib("dw") then links { "dw" } - defines { "ECODE_HAS_DW" } + defines { "EE_BACKWARD_HAS_DW" } end filter { "system:linux or system:macosx or system:haiku or system:bsd", "configurations:release*" } buildoptions { "-g1", "-fvisibility=default" } - filter { "system:linux or system:bsd", "configurations:release*" } - linkoptions { "-rdynamic" } - filter { "system:windows" } - links { "dbghelp", "psapi" } filter "system:haiku" links { "bsd", "network" } filter "system:bsd" @@ -1901,6 +1910,7 @@ workspace "eepp" incdirs { "src/modules/eterm/include/", "src/thirdparty" } language "C++" files { "src/tests/unit_tests/*.cpp" } + eepp_module_backward_add( false ) build_link_configuration( "eepp-unit_tests", true ) if os.isfile("external_projects.lua") then diff --git a/src/tools/ecode/backward.cpp b/src/modules/backward/src/backward.cpp similarity index 87% rename from src/tools/ecode/backward.cpp rename to src/modules/backward/src/backward.cpp index 274cbc6ba..a9b29357f 100644 --- a/src/tools/ecode/backward.cpp +++ b/src/modules/backward/src/backward.cpp @@ -8,15 +8,15 @@ using namespace EE::System; #if EE_PLATFORM != EE_PLATFORM_ANDROID && EE_PLATFORM != EE_PLATFORM_IOS -#if defined( ECODE_HAS_DW ) +#if defined( EE_BACKWARD_HAS_DW ) #define BACKWARD_HAS_DW 1 #endif #include #if EE_PLATFORM == EE_PLATFORM_WIN -#include #include // Added for ShellExecuteW +#include #endif namespace backward { @@ -165,6 +165,8 @@ class WindowsSignalHandling { cv().wait( lk, [] { return crashed() != crash_status::crashed; } ); } } + +#if defined( EE_BACKWARD_ECODE_MODE ) // Helper to safely convert UTF-8 strings to std::wstring for the Windows API static std::wstring utf8_to_wstring( const std::string& str ) { if ( str.empty() ) @@ -235,10 +237,11 @@ class WindowsSignalHandling { SendMessage( hLabel, WM_SETFONT, (WPARAM)hFont, TRUE ); // 4. Add the Text Area (Edit Control) for the Stack Trace - HWND hEdit = CreateWindowExW( 0, L"EDIT", utf8_to_wstring( stackTrace ).c_str(), - WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | WS_BORDER | - ES_MULTILINE | ES_READONLY | ES_AUTOVSCROLL | ES_AUTOHSCROLL, - 10, 68, 600, 320, hwnd, NULL, hInstance, NULL ); + HWND hEdit = + CreateWindowExW( 0, L"EDIT", utf8_to_wstring( stackTrace ).c_str(), + WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | WS_BORDER | + ES_MULTILINE | ES_READONLY | ES_AUTOVSCROLL | ES_AUTOHSCROLL, + 10, 68, 600, 320, hwnd, NULL, hInstance, NULL ); SendMessage( hEdit, WM_SETFONT, (WPARAM)hFont, TRUE ); // 5. Add "Close" Button (Now on the left) @@ -260,14 +263,24 @@ class WindowsSignalHandling { DispatchMessage( &msg ); } } +#endif static void handle_stacktrace( int skip_frames = 0 ) { +#if defined( EE_BACKWARD_ECODE_MODE ) const auto appendCrashesPath = []( std::string& crashesPath ) { FileSystem::dirAddSlashAtEnd( crashesPath ); crashesPath += "crashes"; FileSystem::dirAddSlashAtEnd( crashesPath ); }; +#endif +#if !defined( EE_BACKWARD_ECODE_MODE ) + std::string crashesPath( Sys::getProcessPath() ); + FileSystem::dirAddSlashAtEnd( crashesPath ); + crashesPath += "output"; + FileSystem::dirAddSlashAtEnd( crashesPath ); + FileSystem::makeDir( crashesPath, true ); +#else std::string crashesPath( Sys::getConfigPath( "ecode" ) ); appendCrashesPath( crashesPath ); @@ -276,6 +289,7 @@ class WindowsSignalHandling { appendCrashesPath( crashesPath ); FileSystem::makeDir( crashesPath, true ); } +#endif std::string dateTimeStr( Sys::getDateTimeStr() ); String::replaceAll( dateTimeStr, " ", "_" ); @@ -304,28 +318,35 @@ class WindowsSignalHandling { // Write string to file std::ofstream outFile( crashFilePath ); if ( !outFile.is_open() ) { - print_to_console( "Error: Failed to open " + crashFilePath + - " for writing stack trace\n" + stackTraceStr ); + print_to_console( "Error: Failed to open " + crashFilePath + + " for writing stack trace\n" + stackTraceStr ); } else { outFile << stackTraceStr; outFile.close(); } - // Display the custom Windows dialog + // The generic crash handler is non-interactive; only ecode opts into its branded dialog. +#if defined( EE_BACKWARD_ECODE_MODE ) String::replaceAll( stackTraceStr, "\n", "\r\n" ); display_crash_message( crashFilePath, stackTraceStr ); +#endif } static void print_to_console( const std::string& message ) { - if ( AttachConsole( ATTACH_PARENT_PROCESS ) ) { + const bool attached = AttachConsole( ATTACH_PARENT_PROCESS ) != FALSE; + if ( attached ) { FILE* console = nullptr; freopen_s( &console, "CONOUT$", "w", stderr ); - if ( console ) { - std::cerr << message; - fflush( stderr ); - } - FreeConsole(); } + + // Console applications already attached to their parent make AttachConsole() fail with + // ERROR_ACCESS_DENIED, but their stderr stream remains valid and must still receive the + // trace. + std::cerr << message; + std::cerr.flush(); + + if ( attached ) + FreeConsole(); } };