backward-cpp icon indicating copy to clipboard operation
backward-cpp copied to clipboard

Usage on Windows with MinGW

Open SoraKatadzuma opened this issue 5 years ago • 12 comments

Preface

I looked through the code and saw that at Line 897 it says that StackWalk64 only works when using PDBs, and from what I could tell there aren't any other Windows specific StackTraceImpl that handle GCC or Clang (on Windows). Obviously, GCC doesn't produce PDBs and rather uses DWARF inside of the executable. It's reasonable to assume that is true for MinGW since it's built on top of GCC. Looking further into it, it doesn't attempt to use libgcc or (e)glib both of which should be present on an MinGW installation (libgcc is definitely present).

Question

How would I go about using the library in this situation? I looked at #50 hoping that there was some talk about this, but it was strictly implementation, of which seems to only have included MSVC.

SoraKatadzuma avatar Jul 01 '20 16:07 SoraKatadzuma

Looks like there is a distinction between GNU vs MS Windows then. There might be a way to set the #ifdef in such a ways, that if Windows + MingGW then it uses DWARF implementation.

bombela avatar Jul 01 '20 21:07 bombela

I think the problem is not only this. I just tried building backward.hpp and got a few errors. Used the MinGW 810 from Qt compiler.

backward-cpp/backward.hpp:316: warning: "NOMINMAX" redefined
 #define NOMINMAX
 
In file included from C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32/bits/c++config.h:508,
                 from C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/type_traits:38,
                 from C:/Qt/5.15.0/mingw81_64/include/QtCore/qglobal.h:45,
                 from C:/Qt/5.15.0/mingw81_64/include/QtCore/QtCore:4,
                 from C:/Qt/5.15.0/mingw81_64/include/QtTest/QtTestDepends:3,
                 from C:/Qt/5.15.0/mingw81_64/include/QtTest/QtTest:3,
                 from tst_deploytest.cpp:8:
C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32/bits/os_defines.h:45: note: this is the location of the previous definition
 #define NOMINMAX 1
 
In file included from tst_deploytest.cpp:32:
backward-cpp/backward.hpp:328: warning: ignoring #pragma comment  [-Wunknown-pragmas]
 #pragma comment(lib, "psapi.lib")
 
backward-cpp/backward.hpp:329: warning: ignoring #pragma comment  [-Wunknown-pragmas]
 #pragma comment(lib, "dbghelp.lib")
 
In file included from tst_deploytest.cpp:32:
backward-cpp/backward.hpp: In member function 'backward::module_data backward::get_mod_info::operator()(HMODULE)':
backward-cpp/backward.hpp:3303:42: error: cannot convert 'char*' to 'LPWSTR' {aka 'wchar_t*'}
     GetModuleFileNameEx(process, module, temp, sizeof(temp));
                                          ^~~~
In file included from backward-cpp/backward.hpp:320,
                 from tst_deploytest.cpp:32:
C:/Qt/Tools/mingw810_64/x86_64-w64-mingw32/include/Psapi.h:80:76: note:   initializing argument 3 of 'DWORD GetModuleFileNameExW(HANDLE, HMODULE, LPWSTR, DWORD)'
   DWORD WINAPI GetModuleFileNameExW(HANDLE hProcess,HMODULE hModule,LPWSTR lpFilename,DWORD nSize);
                                                                     ~~~~~~~^~~~~~~~~~
In file included from tst_deploytest.cpp:32:
backward-cpp/backward.hpp:3305:40: error: cannot convert 'char*' to 'LPWSTR' {aka 'wchar_t*'}
     GetModuleBaseName(process, module, temp, sizeof(temp));
                                        ^~~~
In file included from backward-cpp/backward.hpp:320,
                 from tst_deploytest.cpp:32:
C:/Qt/Tools/mingw810_64/x86_64-w64-mingw32/include/Psapi.h:78:74: note:   initializing argument 3 of 'DWORD GetModuleBaseNameW(HANDLE, HMODULE, LPWSTR, DWORD)'
   DWORD WINAPI GetModuleBaseNameW(HANDLE hProcess,HMODULE hModule,LPWSTR lpBaseName,DWORD nSize);
                                                                   ~~~~~~~^~~~~~~~~~
In file included from tst_deploytest.cpp:32:
backward-cpp/backward.hpp: In member function 'backward::ResolvedTrace backward::TraceResolverImpl<backward::system_tag::windows_tag>::resolve(backward::ResolvedTrace)':
backward-cpp/backward.hpp:3370:14: error: cannot convert 'LPTSTR' {aka 'wchar_t*'} to 'const char*'
       printf(lpMsgBuf);
              ^~~~~~~~
In file included from C:/Qt/Tools/mingw810_64/x86_64-w64-mingw32/include/locale.h:12,
                 from C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/clocale:42,
                 from C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32/bits/c++locale.h:41,
                 from C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/bits/localefwd.h:40,
                 from C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/string:43,
                 from C:/Qt/5.15.0/mingw81_64/include/QtCore/qbytearray.h:52,
                 from C:/Qt/5.15.0/mingw81_64/include/QtCore/qstring.h:50,
                 from C:/Qt/5.15.0/mingw81_64/include/QtCore/qobject.h:47,
                 from C:/Qt/5.15.0/mingw81_64/include/QtCore/qabstractanimation.h:43,
                 from C:/Qt/5.15.0/mingw81_64/include/QtCore/QtCore:6,
                 from C:/Qt/5.15.0/mingw81_64/include/QtTest/QtTestDepends:3,
                 from C:/Qt/5.15.0/mingw81_64/include/QtTest/QtTest:3,
                 from tst_deploytest.cpp:8:
C:/Qt/Tools/mingw810_64/x86_64-w64-mingw32/include/stdio.h:345:25: note:   initializing argument 1 of 'int printf(const char*, ...)'
 int printf (const char *__format, ...)
             ~~~~~~~~~~~~^~~~~~~~
In file included from tst_deploytest.cpp:32:
backward-cpp/backward.hpp: In constructor 'backward::SignalHandling::SignalHandling(const std::vector<int, std::allocator<int> >&)':
backward-cpp/backward.hpp:4019:5: error: 'set_terminate' was not declared in this scope
     set_terminate(&terminator);
     ^~~~~~~~~~~~~
backward-cpp/backward.hpp:4019:5: note: suggested alternative:
In file included from C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/new:40,
                 from C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/bits/stl_construct.h:59,
                 from C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/bits/stl_tempbuf.h:60,
                 from C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/bits/stl_algo.h:62,
                 from C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/algorithm:62,
                 from C:/Qt/5.15.0/mingw81_64/include/QtCore/qglobal.h:142,
                 from C:/Qt/5.15.0/mingw81_64/include/QtCore/QtCore:4,
                 from C:/Qt/5.15.0/mingw81_64/include/QtTest/QtTestDepends:3,
                 from C:/Qt/5.15.0/mingw81_64/include/QtTest/QtTest:3,
                 from tst_deploytest.cpp:8:
C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/exception:67:21: note:   'std::set_terminate'
   terminate_handler set_terminate(terminate_handler) _GLIBCXX_USE_NOEXCEPT;
                     ^~~~~~~~~~~~~
In file included from tst_deploytest.cpp:32:
backward-cpp/backward.hpp:4020:5: error: 'set_unexpected' was not declared in this scope
     set_unexpected(&terminator);
     ^~~~~~~~~~~~~~
backward-cpp/backward.hpp:4020:5: note: suggested alternative:
In file included from C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/new:40,
                 from C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/bits/stl_construct.h:59,
                 from C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/bits/stl_tempbuf.h:60,
                 from C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/bits/stl_algo.h:62,
                 from C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/algorithm:62,
                 from C:/Qt/5.15.0/mingw81_64/include/QtCore/qglobal.h:142,
                 from C:/Qt/5.15.0/mingw81_64/include/QtCore/QtCore:4,
                 from C:/Qt/5.15.0/mingw81_64/include/QtTest/QtTestDepends:3,
                 from C:/Qt/5.15.0/mingw81_64/include/QtTest/QtTest:3,
                 from tst_deploytest.cpp:8:
C:/Qt/Tools/mingw810_64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/exception:79:22: note:   'std::set_unexpected'
   unexpected_handler set_unexpected(unexpected_handler) _GLIBCXX_USE_NOEXCEPT;
                      ^~~~~~~~~~~~~~

EndrII avatar Sep 09 '20 11:09 EndrII

It seems to compile fine on Mingw-w64 8.1.0, but does not actually do anything.

vadi2 avatar Nov 27 '20 21:11 vadi2

You have to enable the stack walking and symbol resolver library/API to use. The "unwind" API is provided by GCC, and this might provide stack walking at least. Look at the preprocessor "defines" atop backward.hpp

On Fri, 27 Nov 2020, 13:15 Vadim Peretokin, [email protected] wrote:

It seems to compile fine on Mingw-w64 8.1.0, but does not actually do anything.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/bombela/backward-cpp/issues/176#issuecomment-734991334, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABUZDEI6NZRPXO5DXI2ZWTSSAJHTANCNFSM4ONSHS6Q .

bombela avatar Nov 30 '20 18:11 bombela

@EndrII With the following patch applied on release 1.5, I got that release building on mingw on Linux: This pach is compatible with MSVC because Windows filesystems are case insensitive.

--- backward.hpp
+++ backward.hpp
@@ -313,1 +313,1 @@
-#include <BaseTsd.h>
+#include <basetsd.h>
@@ -317,1 +317,1 @@
-#include <Windows.h>
+#include <windows.h>
@@ -320,1 +320,1 @@
-#include <Psapi.h>
+#include <psapi.h>
@@ -4017,2 +4017,2 @@
-    set_terminate(&terminator);
-    set_unexpected(&terminator);
+    std::set_terminate(&terminator);
+    std::set_unexpected(&terminator);

Note: this patch is used at https://github.com/conan-io/conan-center-index/pull/6665

madebr avatar Aug 03 '21 17:08 madebr

I opened a pr to add mingw support, when building on Linux. See https://github.com/bombela/backward-cpp/pull/234

madebr avatar Aug 06 '21 14:08 madebr

Hello world, Is there still any live issue here? I ask because I just used <unwind.h> + libbfd successfully to give another project backtraces with line numbers on Linux+Windows+macOS. (MSVC support was a non-goal. Good traces into macOS dylibs was also a non-goal.) I think I could do the same for this project, but it might be a mistake if your existing Windows implementation is MinGW-compatible and fully functional already...

UncombedCoconut avatar Aug 14 '22 21:08 UncombedCoconut

Hi, After trying many many things, I've managed to compile a test program on windows using mingw and gcc (g++). It only compiled with linking with msvcr90. But When I do, I don't see any output.

rm -fr backward.o main.o main main.exe
g++.exe -g -c backward.cpp
g++.exe -g -c main.cpp
g++.exe -o main backward.o main.o -mconsole -lmsvcr90 -ldbghelp -lpsapi
./main.exe

Has someone managed to make it work in this scenario?

Here is a minimal repository to reproduce the issue: https://github.com/ArnaudValensi/test-stacktrace/tree/85e427c5d4ad15b49821d8c4b190904f5d649ad3

For linux I have no issue, everything works perfectly.

PS: @UncombedCoconut I'm trying to do exactly what you've done.

ArnaudValensi avatar Jan 13 '23 10:01 ArnaudValensi

Hi, After trying many many things, I've managed to compile a test program on windows using mingw and gcc (g++). It only compiled with linking with msvcr90. But When I do, I don't see any output.

rm -fr backward.o main.o main main.exe
g++.exe -g -c backward.cpp
g++.exe -g -c main.cpp
g++.exe -o main backward.o main.o -mconsole -lmsvcr90 -ldbghelp -lpsapi
./main.exe

Has someone managed to make it work in this scenario?

Here is a minimal repository to reproduce the issue: https://github.com/ArnaudValensi/test-stacktrace

For linux I have no issue, everything works perfectly.

PS: @UncombedCoconut I'm trying to do exactly what you've done.

OK! If you prefer to try alternatives before waiting for a patch to "backward" (my offer is open, but not immediately and I don't know if the project is interested :)) I'd suggest trying https://github.com/ianlancetaylor/libbacktrace/. That works very similarly to what I proposed. (Apologies to this project for plugging a competing one. Both are very nice.)

UncombedCoconut avatar Jan 13 '23 12:01 UncombedCoconut

Thanks for the suggestions, actually I also tried libbacktrack but it doesn't handle mingw on windows. See my issue here https://github.com/ianlancetaylor/libbacktrace/issues/103

ArnaudValensi avatar Jan 13 '23 16:01 ArnaudValensi

@UncombedCoconut would you accept to share me an example of unwind + libbfd working with mingw? 🙏

ArnaudValensi avatar Jan 13 '23 18:01 ArnaudValensi

I've managed to make it work with clang on mingw. On linux, backward handles ELF executable with DWARF debug symbols. On windows, it handles PE executable with PDB (codeview) debug symbols. The thing is that with mingw on windows, gcc and clang create PE executable but with DWARF symbols. Fortunately, it's possible to generate PDB with clang, but for that we need to use lld as a linker, instead of the default ld linker:

clang++.exe -g -gcodeview -c backward.cpp
clang++.exe -g -gcodeview -c main.cpp
clang++.exe -o main *.o -ldbghelp -lucrt -Wl,--pdb= -fuse-ld=lld
  • -g -gcodeview is required to generate all the debug info that will be used by the linker to generate the PDB.
  • -Wl,--pdb= tells clang to forwad the parameter --pdb= to the linker (lld)
  • -fuse-ld=lld tells clang to use lld instead of ld (you might need to install it: pacman -S mingw-w64-x86_64-lld)
  • -ldbghelp links to dbghelp which is needed for some functions used by backward
  • -lucrt is needed for the following function in backward: https://github.com/bombela/backward-cpp/blob/90398eef20f4e7e0e939322d7e84f9c52078a325/backward.hpp#L4338

But linking with ucrt can create some complications if you also link with some library that was compiled with another *rt library. In this case, I think we can safely remove the call of _set_abort_behavior because I guess it just disable some default output when aborting (https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/set-abort-behavior?view=msvc-170).

Here is a minimal working example https://github.com/ArnaudValensi/test-stacktrace/tree/7fcfc0179a55ebd50027d8789c5010ac3c62d73c

Here some documentation about using PDB with clang: https://github.com/mstorsjo/llvm-mingw#pdb-support

As a final note, I think we could avoid doing all of this if we do as @bombela suggested: "There might be a way to set the #ifdef in such a ways, that if Windows + MingGW then it uses DWARF implementation."

ArnaudValensi avatar Jan 13 '23 22:01 ArnaudValensi