C stack trace in Windows
TL;DR: It’s possible to generate a C stack trace in Windows with GCC, but it’s easier with MSVC or LLVM/Clang. Either way, you need to install the Windows SDK and then compile and link against DbgHelp. With GCC, you also need to convert the DWARF debug information to PDB, which can be done with a tool called cv2pdb, but that depends upon installing the Visual Studio build tools.
These notes cover how to print a stack trace from a C application built using Mingw-w64 (with GCC or LLVM/Clang)1 in CMake on Windows 11.
An easier, more cross-platform approach at getting the same information is to use gdb. You can set a breakpoint, or step through, and then use backtrace
(or bt
) to get a stack trace. Another approach I’ve not yet explored would be to use rr, which is like gdb but allows you to replay the execution.
Other shortcomings of the approach detailed below are:
- It adds more dependencies to the build, and adds complexity to the build process.
- It only works for debug builds.
- It only works on Windows.
- For GCC builds, it requires the
*.pdb
file in the same directory as the executable.
So why would you implement this? Well:
- For a quick developer feedback cycle: print the stack trace whenever an assertion fails to immediately get debug information.
- To aid with bug reports from users: providing you’re happy with delivering a debug build, it enables automatically capturing useful stack trace information from users.
End result §
The resulting function log_stacktrace()
walks the stack and prints the name, address and line of every function. The resulting stack trace, read from top to bottom, looks like this:
Stack trace:
Function Address Line
-------- ------- ----
log_stacktrace 0x00007FF7AE73ED8A C:\project\something\game\src\log\platform\windows\log_stacktrace.c:19
engine_obj_helper 0x00007FF7AE72FA9D C:\project\something\game\src\engine\engine_step.c:620
engine_obj_resolve 0x00007FF7AE731D5E C:\project\something\game\src\engine\engine_step.c:1207
engine_step_resolve 0x00007FF7AE7318A1 C:\project\something\game\src\engine\engine_step.c:1095
engine_action 0x00007FF7AE72BE17 C:\project\something\game\src\engine\engine_main.c:586
input_keydown 0x00007FF7AE72232B C:\project\something\game\src\app\app_play_main.c:149
app_play_main_input_keydown 0x00007FF7AE722533 C:\project\something\game\src\app\app_play_main.c:231
app_loop_main_unlimited 0x00007FF7AE7219C1 C:\project\something\game\src\app\app_loop.c:163
app_loop_main_limited 0x00007FF7AE721864 C:\project\something\game\src\app\app_loop.c:94
app_loop_main_normal 0x00007FF7AE721847 C:\project\something\game\src\app\app_loop.c:85
main 0x00007FF7AE72176E C:\project\something\game\app\main.c:40
public_all 0x00007FF7AE721340 Unknown
public_all 0x00007FF7AE721117 Unknown
BaseThreadInitThunk 0x00007FFBB210E8D7 Unknown
RtlUserThreadStart 0x00007FFBB437BF6C Unknown
Overview §
The Windows library DbgHelp provides the function StackWalk64()
, which provides access to the stack information, and SymFromAddr()
, which gets the human-readable name of each function. Using DbgHelp requires the C application to include dbghelp.h
at compile time, to link against DbgHelp, and DbgHelp.dll
must be present. Although Windows always includes a version of DbgHelp.dll
, developers should obtain the right version by installing Debugging Tools for Windows from the Windows SDK.
In order for SymFromAddr()
to get the human-readable function names, the executable must provide the PDB information. In simple terms, PDB (Program Database) is a file format by Microsoft which contains debug information. It can be embedded directly inside an executable, or can be a standalone *.pdb
file in the same directory as the corresponding executable2. Microsoft’s MSVC compiler can generate PDB information, and so can LLVM/Clang3. Mingw-w64 does not have PDB support4.
Mingw-w64’s lack of support for PDB can be solved using cv2pdb, which given an executable containing DWARF5 information will output a *.pdb
file with the PDB information. Running cv2pdb requires several other DLLs6 which are typically obtained by installing Microsoft Visual Studio. However, I discovered it is possible to “just” install MSVC v143 - VS 2022 C++ x86/64 build tools (Latest) (by manually selecting that component in the Microsoft Visual Studio installer) and that provides all the necessary DLLs.
In summary:
- Install Windows SDK to get DbgHelp.
- Update application to include
dbghelp.h
and link against DbgHelp. - Write the
log_stacktrace()
function:- Use
StackWalk64()
to get the stack. - Use
SymFromAddr()
to get the address of each item in the stack. - Use
SymGetLineFromAddr64()
to get the file name and line number of each item in the stack.
- Use
- Install the MSVC tool chains (from Microsoft Visual Studio installer) to get the DLLs required for cv2pdb.
- Build your application using Mingw-w64 with debug information (generates the DWARF information).
- Run cv2pdb to generate a
*.pdb
file (containing the PDB information from parsing the DWARF information). - Run your application and call
log_stacktrace()
.
Steps to generate stack trace §
Install Windows SDK §
The first step is to install DbgHelp:
- Go to DbgHelp Versions and follow the link for the Windows SDK.
- Download the installer.
- Run
winsdksetup.exe
. - When prompted, select the following:
- Debugging Tools for Windows: this provides DbgHelp.
- Windows SDK for Desktop C++ x86 Apps: this provides ImageHlp, which is requried by DbgHelp.
- Selecting this will also automatically select three other features.
Initially I just selected Debugging Tools for Windows, which appears to include DbgHelp but not ImageHelp. When compiling dbghelp.h
this caused the error fatal error: minidumpapiset.h: No such file or directory
. So make sure to install both.
Update CMake §
FindDbgHelp.cmake
§
Create FindDbgHelp.cmake
:
# - Try to find DbgHelp
# Once done, this will define
#
# DbgHelp_FOUND - system has DbgHelp
# DbgHelp_INCLUDE_DIRS - the DbgHelp include directory
# DbgHelp_LIBRARIES - the DbgHelp library
find_path(DbgHelp_INCLUDE_DIR dbghelp.h
PATHS
"$ENV{ProgramFiles}/Microsoft SDKs/Windows/v7.1/Include"
"$ENV{ProgramFiles}/Windows Kits/10/Include"
PATH_SUFFIXES um dbghelp
)
find_library(DbgHelp_LIBRARY dbghelp
PATHS
"$ENV{ProgramFiles}/Microsoft SDKs/Windows/v7.1/Lib"
"$ENV{ProgramFiles}/Windows Kits/10/Lib"
PATH_SUFFIXES x86 x64 um
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(DbgHelp DEFAULT_MSG DbgHelp_LIBRARY DbgHelp_INCLUDE_DIR)
if(DbgHelp_FOUND)
set(DbgHelp_LIBRARIES ${DbgHelp_LIBRARY})
set(DbgHelp_INCLUDE_DIRS ${DbgHelp_INCLUDE_DIR})
endif()
mark_as_advanced(DbgHelp_INCLUDE_DIR DbgHelp_LIBRARY)
Top-level CMakeLists.txt
§
Update the top-level CMakeLists.txt
to find DbgHelp:
# Add FindDbgHelp.cmake to the path.
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/dbghelp")
# DbgHelp is only valid on Windows.
if (WIN32)
find_package(DbgHelp)
if (DBGHELP_FOUND)
include_directories(${DBGHELP_INCLUDE_DIR})
endif()
set(GAME_USE_DBGHELP ${DBGHELP_FOUND})
endif()
Application-level CMakeLists.txt
§
Update the application-level CMakeLists.txt
to link against DbgHelp.
list(APPEND APP_LIBS game_lib_1)
list(APPEND APP_LIBS game_lib_2)
list(APPEND APP_LIBS game_lib_3)
# ...
if (DBGHELP_FOUND)
message("Linking against DbgHelp")
list(APPEND APP_LIBS DbgHelp)
endif()
# ...
target_link_libraries(my_game PUBLIC "${APP_LIBS}")
Create stack trace function §
Create header file:
void log_stacktrace();
Create source file:
#include "log/log_stacktrace.h"
#include <stdio.h>
#include <windows.h>
// Must come after windows.h
#include <dbghelp.h>
void log_stacktrace()
{
HANDLE process = GetCurrentProcess();
HANDLE thread = GetCurrentThread();
CONTEXT context;
STACKFRAME64 stack;
DWORD machine_type;
RtlCaptureContext(&context);
ZeroMemory(&stack, sizeof(STACKFRAME64));
#ifdef _M_IX86
machine_type = IMAGE_FILE_MACHINE_I386;
stack.AddrPC.Offset = context.Eip;
stack.AddrFrame.Offset = context.Ebp;
stack.AddrStack.Offset = context.Esp;
#elif _M_X64
machine_type = IMAGE_FILE_MACHINE_AMD64;
stack.AddrPC.Offset = context.Rip;
stack.AddrFrame.Offset = context.Rsp;
stack.AddrStack.Offset = context.Rsp;
#elif _M_ARM64
machine_type = IMAGE_FILE_MACHINE_ARM64;
stack.AddrPC.Offset = context.Pc;
stack.AddrFrame.Offset = context.Fp;
stack.AddrStack.Offset = context.Sp;
#else
#error "Unsupported platform"
#endif
stack.AddrPC.Mode = AddrModeFlat;
stack.AddrFrame.Mode = AddrModeFlat;
stack.AddrStack.Mode = AddrModeFlat;
SymInitialize(process, NULL, TRUE);
SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
printf("Stack trace:\n");
printf(" %-40s %-18s %s\n", "Function", "Address", "Line");
printf(" %-40s %-18s %s\n", "--------", "-------", "----");
DWORD frame_number = 0;
while (StackWalk64(
machine_type,
process,
thread,
&stack,
&context,
NULL,
SymFunctionTableAccess64,
SymGetModuleBase64,
NULL)) {
if (stack.AddrPC.Offset == 0)
break;
DWORD64 symbol_addr = stack.AddrPC.Offset;
DWORD64 displacement = 0;
char symbol_buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)] = {0};
SYMBOL_INFO *symbol = (SYMBOL_INFO *)symbol_buffer;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = MAX_SYM_NAME;
// Get line information
IMAGEHLP_LINE64 line = {0};
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
DWORD line_displacement = 0;
BOOL has_line = SymGetLineFromAddr64(process, symbol_addr, &line_displacement, &line);
char function_name[MAX_SYM_NAME] = "Unknown";
if (SymFromAddr(process, symbol_addr, &displacement, symbol)) {
strncpy(function_name, symbol->Name, MAX_SYM_NAME - 1);
function_name[MAX_SYM_NAME - 1] = '\0'; // Ensure null termination
}
// Format line information
char line_info[256] = "Unknown";
if (has_line) {
snprintf(line_info, sizeof(line_info), "%s:%lu", line.FileName, line.LineNumber);
}
// Print with better alignment using format specifiers
printf(" %-40.40s 0x%016llX %s\n",
function_name,
symbol_addr,
line_info);
frame_number++;
}
SymCleanup(process);
}
Build §
If DbgHelp is installed somewhere sensible, it should be possible to build with:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -G "MinGW Makefiles"
The CMAKE_BUILD_TYPE=Debug
is necessary to generate the DWARF debug information.
If CMake cannot find DbgHelp, help point it in the right direction with these options:
- Use
DbgHelp_INCLUDE_DIR
to specify the include directory (so it can finddbghelp.h
). - Use
DbgHelp_LIBRARY
to specify the directory where the DLL can be found (so it can findDbgHelp.dll
).
For example:
cmake -S . -B build -DDbgHelp_INCLUDE_DIR="C:\Program Files (x86)\Windows Kits\10" -DDbgHelp_LIBRARY="C:\Program Files (x86)\Windows Kits\10" -DCMAKE_BUILD_TYPE=Debug -G "MinGW Makefiles"
Check output §
Now run the program and give it a try. With GCC it should generate a stack trace like the following:
Stack trace:
Function Address Line
-------- ------- ----
log_stacktrace 0x00007FF7AE73ED8A Unknown
engine_obj_helper 0x00007FF7AE72FA9D Unknown
engine_obj_resolve 0x00007FF7AE731D5E Unknown
engine_step_resolve 0x00007FF7AE7318A1 Unknown
engine_action 0x00007FF7AE72BE17 Unknown
input_keydown 0x00007FF7AE72232B Unknown
app_play_main_input_keydown 0x00007FF7AE722533 Unknown
app_loop_main_unlimited 0x00007FF7AE7219C1 Unknown
app_loop_main_limited 0x00007FF7AE721864 Unknown
app_loop_main_normal 0x00007FF7AE721847 Unknown
main 0x00007FF7AE72176E Unknown
public_all 0x00007FF7AE721340 Unknown
public_all 0x00007FF7AE721117 Unknown
BaseThreadInitThunk 0x00007FFBB210E8D7 Unknown
RtlUserThreadStart 0x00007FFBB437BF6C Unknown
Pretty good, but we’re not quite there: all the line information is Unknown
.
Extract PDB information §
If your stack trace lists Unknown
for all the lines, this is most likely because your build does not contain PDB information.
MSVC and LLVM/Clang have PDB support3 but GCC does not. Fortunately, the tool cv2pdb can be used to extract the necessary PDB information from the DWARF information that GCC generates in a debug build.
As best as I can tell, there are two independent (but closely related) concepts of debug information and exception handling.
Each of the WinLibs versions provides a 32-bit/i686 release with dwarf
exception handling, and a 64-bit/x86_64 release with seh
exception handling. Both of these releases are capable of generating DWARF debug information in a debug build, despite only the 32-bit release having dwarf
in the name.
In other words, the following approach works for 32-bit and 64-bit builds, despite only 32-bit builds having dwarf
in the name, and cv2pdb relies upon there being DWARF debug information in the executable.
Install C++ build tools §
cv2pdb relies upon some libraries provided by Microsoft Visual Studio. While Microsoft will try to persuade you otherwise, you do not need to install the entirety of Visual Studio, nor do you need to install an entire so-called workload. Instead, you can install a single component weighing in at “only” 3.57 GB. (Unfortunately this appears to be as small a download as is possible to support cv2pdb via official means).
- Download Visual Studio with C++ (Community 2022).
- Run the downloaded file
VisualStudioSetup.exe
. - When prompted to choose workloads, instead click on the components tab at the top. This way you can save disk space by installing only the relevant MSVC build tools, rather than installing all the gumpf that a workload includes.
- Choose the relevant MSVC build tool. For me, that is: MSVC v143 - VS 2022 C++ x86/64 build tools (Latest).
- Once the install has finished, restart. (Not sure if necessary, but wanted to ensure the new tools are definitely on the
PATH
).
Run cv2pdb §
- Go to the cv2pdb GitHub release pages and download the latest ZIP (currently
cv2pdb-0.53.zip
). - Extract the ZIP.
- There are two executables:
cv2pdb.exe
for 32-bit executables, andcv2pdb64.exe
for 64-bit executables. - I am using 64-bit, chose
cv2pdb64.exe
. - Copy
cv2pdb64.exe
into the same directory as your executable. - Run:
./cv2pdb64.exe my_game.exe
- If it works, it will generate a file
my_game.pdb
in the same directory. - Now try running your application again. This time the stack trace should look like the end result, i.e. it should show line numbers for your application.
We’re almost done…
Automating cv2pdb §
It’s a pain to run manually cv2pdb64.exe
each time. Fortunately this can easily be automated with CMake using a POST_BUILD
custom command.
Update the application-level CMakeLists.txt
to call add_custom_command()
as follows:
if (DBGHELP_FOUND)
message("Linking against DbgHelp")
list(APPEND APP_LIBS DbgHelp)
# Automatically run cv2pdb64 as a post-build step
add_custom_command(TARGET my_game POST_BUILD
COMMAND $<TARGET_FILE_DIR:my_game>/cv2pdb64.exe $<TARGET_FILE:my_game>
COMMENT "Generating PDB using cv2pdb64.exe"
VERBATIM
)
endif()
Now, every time you perform a build with DbgHelp enabled, CMake will automatically run ./cv2pdb64.exe my_game.exe
.
We’re finally done, hurrah! 🎉
Conclusion §
This adds some big dependencies to the developer setup, but are at least implemented as optional (by using if (DBGHELP_FOUND)
). A proper debugger such as gdb or rr would get you the same information and save all the setup trouble, but that does require the developer to run the debugger. Once this stack trace implementation is up and running it provides some quick and useful feedback.
- For testing: the executable can be delivered to users along with the
*.pdb
file, but the users will need theDbgHelp.dll
to be present. This could potentially be included alongside the executable to save the user from having to intall the Windows SDK. - For production: this implementation is not applicable, because it only works for debug builds. However, by their very nature, production or “release” builds typically do not generate debug information.
Whether this makes sense for your situation is up to you!
Troubleshooting §
Following are some issues, and how I resolved them.
CMake cannot find DBGHELP
§
-- Could NOT find DBGHELP (missing: DBGHELP_LIBRARY DBGHELP_INCLUDE_DIR)
- Make sure that the Windows SDK is installed as described here.
- Make sure that
DBGHELP_INCLUDE_DIR
andDBGHELP_LIBRARY
are set correctly, e.g. by setting them at build time with-D
as described here.
Cannot find minidumpapiset.h
§
In file included from C:\project\game\src\log\platform\windows\log_stacktrace.c:5:
C:/PROGRA~2/WI3CF2~1/10/DEBUGG~1/inc/dbghelp.h:4364:10: fatal error: minidumpapiset.h: No such file or directory
4364 | #include <minidumpapiset.h>
| ^~~~~~~~~~~~~~~~~~
Had to go to Windows installed apps, find the “Windows Software Development Kit”, do “Change”, and select “Windows SDK for Desktop C++”. This also selected a bunch of other stuff.
Then minidumpapiset.h
was at: C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um
.
Also had to change DBGHELP_INCLUDE_DIR
from C:\Program Files (x86)\Windows Kits\10\Debuggers\inc
to C:\Program Files (x86)\Windows Kits\10
so that it can find both dbghelp.h
(which is in Debuggers\inc\
) and minidumpapiset.h
(which is in Include\10.0.26100.0\um\
).
Error linking against DbgHelp §
[ 97%] Built target game_app
[ 98%] Building C object app/CMakeFiles/my_game.dir/main.c.obj
[100%] Linking C executable my_game.exe
C:/Program Files (x86)/mingw-w64/winlibs-i686-posix-dwarf-gcc-13.2.0-llvm-18.1.3-mingw-w64ucrt-11.0.1-r7/mingw32/bin/../lib/gcc/i686-w64-mingw32/13.2.0/../../../../i686-w64-mingw32/bin/ld.exe: ../src/log/libuot_log.a(log_stacktrace.c.obj):log_stacktrace.:(.text+0x2a): undefined reference to `_imp__SymInitialize@12'
C:/Program Files (x86)/mingw-w64/winlibs-i686-posix-dwarf-gcc-13.2.0-llvm-18.1.3-mingw-w64ucrt-11.0.1-r7/mingw32/bin/../lib/gcc/i686-w64-mingw32/13.2.0/../../../../i686-w64-mingw32/bin/ld.exe: ../src/log/libuot_log.a(log_stacktrace.c.obj):log_stacktrace.:(.text+0x163): undefined reference to `_imp__SymFromAddr@20'
C:/Program Files (x86)/mingw-w64/winlibs-i686-posix-dwarf-gcc-13.2.0-llvm-18.1.3-mingw-w64ucrt-11.0.1-r7/mingw32/bin/../lib/gcc/i686-w64-mingw32/13.2.0/../../../../i686-w64-mingw32/bin/ld.exe: ../src/log/libuot_log.a(log_stacktrace.c.obj):log_stacktrace.:(.text+0x1e6): undefined reference to `_imp__SymGetModuleBase64@12'
C:/Program Files (x86)/mingw-w64/winlibs-i686-posix-dwarf-gcc-13.2.0-llvm-18.1.3-mingw-w64ucrt-11.0.1-r7/mingw32/bin/../lib/gcc/i686-w64-mingw32/13.2.0/../../../../i686-w64-mingw32/bin/ld.exe: ../src/log/libuot_log.a(log_stacktrace.c.obj):log_stacktrace.:(.text+0x1f0): undefined reference to `_imp__SymFunctionTableAccess64@12'
C:/Program Files (x86)/mingw-w64/winlibs-i686-posix-dwarf-gcc-13.2.0-llvm-18.1.3-mingw-w64ucrt-11.0.1-r7/mingw32/bin/../lib/gcc/i686-w64-mingw32/13.2.0/../../../../i686-w64-mingw32/bin/ld.exe: ../src/log/libuot_log.a(log_stacktrace.c.obj):log_stacktrace.:(.text+0x227): undefined reference to `_imp__StackWalk64@36'
C:/Program Files (x86)/mingw-w64/winlibs-i686-posix-dwarf-gcc-13.2.0-llvm-18.1.3-mingw-w64ucrt-11.0.1-r7/mingw32/bin/../lib/gcc/i686-w64-mingw32/13.2.0/../../../../i686-w64-mingw32/bin/ld.exe: ../src/log/libuot_log.a(log_stacktrace.c.obj):log_stacktrace.:(.text+0x23f): undefined reference to `_imp__SymCleanup@4'
collect2.exe: error: ld returned 1 exit status
mingw32-make[2]: *** [app\CMakeFiles\my_game.dir\build.make:120: app/my_game.exe] Error 1
mingw32-make[1]: *** [CMakeFiles\Makefile2:939: app/CMakeFiles/my_game.dir/all] Error 2
mingw32-make: *** [Makefile:90: all] Error 2
- Make sure you are not mixing up 32-bit and 64-bit.
- Make sure
target_link_libraries(...)
is linking your application againstDbgHelp
. - Make sure that the Windows SDK is installed as described here. Note that
DbgHelp
requiresImageHlp
.
Compiler error: unknown type name 'PSTR'
etc §
In file included from C:/Program Files (x86)/mingw-w64/winlibs-x86_64-posix-seh-gcc-14.2.0-llvm-19.1.7-mingw-w64ucrt-12.0.0-r3/mingw64/x86_64-w64-mingw32/include/dbghelp.h:17,
from C:\project\game\src\log\platform\windows\log_stacktrace.c:3:
C:/Program Files (x86)/mingw-w64/winlibs-x86_64-posix-seh-gcc-14.2.0-llvm-19.1.7-mingw-w64ucrt-12.0.0-r3/mingw64/x86_64-w64-mingw32/include/psdk_inc/_dbg_LOAD_IMAGE.h:24:5: error: unknown type name 'PSTR'
24 | PSTR ModuleName;
| ^~~~
C:/Program Files (x86)/mingw-w64/winlibs-x86_64-posix-seh-gcc-14.2.0-llvm-19.1.7-mingw-w64ucrt-12.0.0-r3/mingw64/x86_64-w64-mingw32/include/psdk_inc/_dbg_LOAD_IMAGE.h:25:5: error: unknown type name 'HANDLE'
25 | HANDLE hFile;
| ^~~~~~
C:/Program Files (x86)/mingw-w64/winlibs-x86_64-posix-seh-gcc-14.2.0-llvm-19.1.7-mingw-w64ucrt-12.0.0-r3/mingw64/x86_64-w64-mingw32/include/psdk_inc/_dbg_LOAD_IMAGE.h:26:5: error: unknown type name 'PUCHAR'
26 | PUCHAR MappedAddress;
| ^~~~~~
C:/Program Files (x86)/mingw-w64/winlibs-x86_64-posix-seh-gcc-14.2.0-llvm-19.1.7-mingw-w64ucrt-12.0.0-r3/mingw64/x86_64-w64-mingw32/include/psdk_inc/_dbg_LOAD_IMAGE.h:28:5: error: unknown type name 'PIMAGE_NT_HEADERS64'
28 | PIMAGE_NT_HEADERS64 FileHeader;
| ^~~~~~~~~~~~~~~~~~~
C:/Program Files (x86)/mingw-w64/winlibs-x86_64-posix-seh-gcc-14.2.0-llvm-19.1.7-mingw-w64ucrt-12.0.0-r3/mingw64/x86_64-w64-mingw32/include/psdk_inc/_dbg_LOAD_IMAGE.h:32:5: error: unknown type name 'PIMAGE_SECTION_HEADER'
32 | PIMAGE_SECTION_HEADER LastRvaSection;
| ^~~~~~~~~~~~~~~~~~~~~
C:/Program Files (x86)/mingw-w64/winlibs-x86_64-posix-seh-gcc-14.2.0-llvm-19.1.7-mingw-w64ucrt-12.0.0-r3/mingw64/x86_64-w64-mingw32/include/psdk_inc/_dbg_LOAD_IMAGE.h:33:5: error: unknown type name 'ULONG'
33 | ULONG NumberOfSections;
| ^~~~~
...and so on for a couple thousand lines...
Make sure that windows.h
is included before dbghelp.h
, e.g.:
#include <windows.h>
// Must come after windows.h
#include <dbghelp.h>
Beware that clang-format
may helpfully place dbghelp.h
above windows.h
.
Mingw-w64 was forked from MinGW in 2007. It is not a compiler, but is a collection of header files, libraries and tools that can be combined with a compiler toolchain (e.g. GCC or LLVM) to build native Windows applications. Mingw-w64 is released as source, not binaries. Most users install a pre-built toolchain from this list on the Mingw-w64 website. I chose to use the latest WinLibs 64-bit UCRT runtime with both GCC and LLVM. ↩︎
I may have over-simplified. See this excellent article for much more detail on PDB. ↩︎
LLVM/Clang has had PDB support since 2017. It requires some extra options, e.g.
-g -gcodeview --for-linker --pdb=file.pdb
. ↩︎ ↩︎According to the mingw-w64 “Contribute” page, PDB support is a topic “for which developer-time has been scarce”. ↩︎
DWARF is a very common debug file format which Mingw-w64 can generate. ↩︎
It’s not clear exactly which DLLs it requires. From this issue it looks like it requires
mspdb140.dll
, which spawnsmspdbsrv.exe
, which in turn requiresmspdbcore.dll
,msvcp140.dll
,msvcp140_atomic_wait.dll
,tbbmalloc.dll
,vcruntime140.dll
andmsobj140.dll
. ↩︎