Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
name: CI

on:
push:
pull_request:

jobs:
Expand Down Expand Up @@ -42,7 +41,7 @@ jobs:
with:
msystem: MINGW64
update: true
install: mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-make mingw-w64-x86_64-gdb
install: mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-make mingw-w64-x86_64-gdb mingw-w64-x86_64-binutils

- name: Configure (MinGW POSIX)
shell: msys2 {0}
Expand Down
10 changes: 5 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ include_directories(
ust
)

IF(MINGW)
SET(
CORE_LIBRARIES
IF(MINGW OR CMAKE_CXX_COMPILER MATCHES "mingw32" OR CMAKE_CXX_COMPILER MATCHES "x86_64-w64-mingw32" OR (CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_CXX_COMPILER MATCHES "mingw"))
SET(
CORE_LIBRARIES

dbghelp
)
dbghelp
)
ELSEIF(WIN32)
SET(
CORE_LIBRARIES
Expand Down
2 changes: 1 addition & 1 deletion external/Catch2
Submodule Catch2 updated 252 files
62 changes: 56 additions & 6 deletions ust/ust_windows.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,24 @@
#define NOMINMAX
#endif
#include <windows.h>
#include <DbgHelp.h>
#ifdef _MSC_VER
#include <DbgHelp.h>
#include <shlwapi.h>
#pragma comment(lib, "dbghelp.lib")
#pragma comment(lib, "shlwapi.lib")
// Ensure PDB/debug info is retained for Sym* APIs.
// MSVC: /Zi is required; CMake should enable it for RelWithDebInfo.
// No additional flags can be set from header, but pragma ensures linking.
#else
// MinGW (Windows GCC/Clang) does not ship the Windows SDK's DbgHelp; use
// CaptureStackBackTrace + addr2line symbolication instead.
#include <array>
#include <cstdio>
#include <libgen.h>
#include <sys/stat.h>
#if !defined(_MSC_VER) && (defined(__MINGW32__) || defined(__MINGW64__))
#include <psapi.h>
#endif
#if defined(__MINGW32__) || defined(__MINGW64__)
#define WEXITSTATUS(w) (((w) >> 8) & 0xff)
#else
Expand Down Expand Up @@ -167,6 +173,36 @@ inline std::string SystemToStr(const char* cmd) {
return result;
}

// PE debug information records addresses relative to the image's preferred
// link-time base, while CaptureStackBackTrace returns addresses relative to
// the image's (possibly ASLR-relocated) load base. Translate between the two
// before invoking GNU addr2line.
inline uint64_t addr2lineAddress(void* address, HMODULE moduleHandle,
const std::string& fileName) {
if (!address || !moduleHandle) return uint64_t(address);

// The Windows loader rewrites OptionalHeader.ImageBase in the in-memory PE
// header after applying ASLR, so read the preferred base from the file.
IMAGE_DOS_HEADER dosHeader{};
IMAGE_NT_HEADERS ntHeaders{};
std::ifstream image(fileName, std::ios::binary);
image.read(reinterpret_cast<char*>(&dosHeader), sizeof(dosHeader));
if (!image || dosHeader.e_magic != IMAGE_DOS_SIGNATURE) {
return uint64_t(address);
}
image.seekg(dosHeader.e_lfanew);
image.read(reinterpret_cast<char*>(&ntHeaders), sizeof(ntHeaders));
if (!image || ntHeaders.Signature != IMAGE_NT_SIGNATURE) {
return uint64_t(address);
}

const uint64_t loadedBase = reinterpret_cast<uint64_t>(moduleHandle);
const uint64_t absoluteAddress = reinterpret_cast<uint64_t>(address);
if (absoluteAddress < loadedBase) return absoluteAddress;
return uint64_t(ntHeaders.OptionalHeader.ImageBase) +
(absoluteAddress - loadedBase);
}

UST_NOINLINE inline StackTrace generate_raw() {
std::vector<StackTraceEntry> stackTrace;
void* stack[MAX_STACK_FRAMES];
Expand Down Expand Up @@ -234,12 +270,26 @@ UST_NOINLINE inline StackTrace generate() {
// Fetch source file & line numbers via addr2line (same as Unix)
std::map<std::string, std::list<std::string>> fileAddresses;
std::map<std::string, std::list<std::string>> fileData;
for (const auto& it : stackTrace) {
if (it.binaryFileName.length()) {
if (fileAddresses.find(it.binaryFileName) == fileAddresses.end()) {
fileAddresses[it.binaryFileName] = {};
for (int a = 0; a < numFrames; a++) {
HMODULE moduleHandle;
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
(const char*)stack[a], &moduleHandle);
std::string fileName(4096, '\0');
auto fileNameSize =
GetModuleFileNameA(moduleHandle, &fileName[0], fileName.size());
if (fileNameSize == 0 || fileNameSize == (ssize_t)fileName.size()) {
fileName = "";
} else {
fileName = fileName.substr(0, fileNameSize);
std::replace(fileName.begin(), fileName.end(), '\\', '/');
}
std::string addrStr =
addressToString(addr2lineAddress(stack[a], moduleHandle, fileName));
if (fileName.length()) {
if (fileAddresses.find(fileName) == fileAddresses.end()) {
fileAddresses[fileName] = {};
}
fileAddresses.at(it.binaryFileName).push_back(it.address);
fileAddresses.at(fileName).push_back(addrStr);
}
}
for (const auto& it : fileAddresses) {
Expand Down
Loading