Add baseline mingw support (#13)
This commit is contained in:
parent
7c9c4bc5be
commit
d7a5eb54fd
10
.github/workflows/build.yml
vendored
10
.github/workflows/build.yml
vendored
@ -43,3 +43,13 @@ jobs:
|
||||
run: |
|
||||
pip3 install colorama
|
||||
python3 ci/build-in-all-configs.py --clang-only
|
||||
build-windows-mingw:
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Enable Developer Command Prompt
|
||||
uses: ilammy/msvc-dev-cmd@v1.10.0
|
||||
- name: build
|
||||
run: |
|
||||
pip3 install colorama
|
||||
python3 ci/build-in-all-configs.py --mingw-only
|
||||
|
||||
10
.github/workflows/test.yml
vendored
10
.github/workflows/test.yml
vendored
@ -45,3 +45,13 @@ jobs:
|
||||
run: |
|
||||
pip3 install colorama
|
||||
python3 ci/test-all-configs.py --clang-only
|
||||
build-windows-mingw:
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Enable Developer Command Prompt
|
||||
uses: ilammy/msvc-dev-cmd@v1.10.0
|
||||
- name: build
|
||||
run: |
|
||||
pip3 install colorama
|
||||
python3 ci/test-all-configs.py --mingw-only
|
||||
|
||||
@ -133,7 +133,7 @@ if(
|
||||
if(HAS_STACKTRACE AND NOT WIN32) # Our trace is better than msvc's <stacktrace>
|
||||
set(CPPTRACE_FULL_TRACE_WITH_LIBBACKTRACE On)
|
||||
message(STATUS "Cpptrace auto config: Using C++23 <stacktrace> for the full trace")
|
||||
elseif(HAS_BACKTRACE)
|
||||
elseif(HAS_BACKTRACE AND NOT WIN32) # Mingw libbacktrace doesn't seem to be working
|
||||
set(CPPTRACE_FULL_TRACE_WITH_LIBBACKTRACE On)
|
||||
message(STATUS "Cpptrace auto config: Using libbacktrace for the full trace")
|
||||
endif()
|
||||
@ -163,6 +163,17 @@ if(
|
||||
set(CPPTRACE_UNWIND_WITH_NOTHING On)
|
||||
message(FATAL_ERROR "Cpptrace auto config: No unwinding back-end seems to be supported, stack tracing will not work. To compile anyway set CPPTRACE_UNWIND_WITH_NOTHING.")
|
||||
endif()
|
||||
elseif(WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") # mingw
|
||||
if(HAS_UNWIND)
|
||||
set(CPPTRACE_UNWIND_WITH_UNWIND On)
|
||||
message(STATUS "Cpptrace auto config: Using libgcc unwind for unwinding")
|
||||
elseif(HAS_EXECINFO)
|
||||
set(CPPTRACE_UNWIND_WITH_EXECINFO On)
|
||||
message(STATUS "Cpptrace auto config: Using execinfo.h for unwinding")
|
||||
else()
|
||||
set(CPPTRACE_UNWIND_WITH_WINAPI On)
|
||||
message(STATUS "Cpptrace auto config: Using winapi for unwinding")
|
||||
endif()
|
||||
elseif(WIN32)
|
||||
set(CPPTRACE_UNWIND_WITH_WINAPI On)
|
||||
message(STATUS "Cpptrace auto config: Using winapi for unwinding")
|
||||
@ -189,11 +200,14 @@ if(
|
||||
set(CPPTRACE_GET_SYMBOLS_WITH_LIBDL ON)
|
||||
elseif(UNIX)
|
||||
if(HAS_BACKTRACE)
|
||||
set(CPPTRACE_FULL_TRACE_WITH_LIBBACKTRACE On)
|
||||
set(CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE On)
|
||||
message(STATUS "Cpptrace auto config: Using libbacktrace for symbols")
|
||||
else()
|
||||
message(FATAL_ERROR "Cpptrace auto config: No symbol back-end could be automatically configured. To compile anyway set CPPTRACE_GET_SYMBOLS_WITH_NOTHING.")
|
||||
endif()
|
||||
elseif(WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") # mingw
|
||||
set(CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE On)
|
||||
message(STATUS "Cpptrace auto config: Using addr2line for symbols")
|
||||
elseif(WIN32)
|
||||
set(CPPTRACE_GET_SYMBOLS_WITH_DBGHELP On)
|
||||
message(STATUS "Cpptrace auto config: Using dbghelp for symbols")
|
||||
@ -260,7 +274,9 @@ endif()
|
||||
|
||||
if(CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE)
|
||||
target_compile_definitions(cpptrace PUBLIC CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE)
|
||||
target_link_libraries(cpptrace PRIVATE dl)
|
||||
if(UNIX)
|
||||
target_link_libraries(cpptrace PRIVATE dl)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CPPTRACE_GET_SYMBOLS_WITH_DBGHELP)
|
||||
|
||||
@ -54,7 +54,7 @@ def build(matrix):
|
||||
if succeeded:
|
||||
run_command("make", "-j")
|
||||
else:
|
||||
succeeded = run_command(
|
||||
args = [
|
||||
"cmake",
|
||||
"..",
|
||||
f"-DCMAKE_BUILD_TYPE={matrix['target']}",
|
||||
@ -63,9 +63,15 @@ def build(matrix):
|
||||
f"-D{matrix['unwind']}=On",
|
||||
f"-D{matrix['symbols']}=On",
|
||||
f"-D{matrix['demangle']}=On"
|
||||
)
|
||||
]
|
||||
if matrix["compiler"] == "g++":
|
||||
args.append("-GUnix Makefiles")
|
||||
succeeded = run_command(*args)
|
||||
if succeeded:
|
||||
run_command("msbuild", "cpptrace.sln")
|
||||
if matrix["compiler"] == "g++":
|
||||
run_command("make", "-j")
|
||||
else:
|
||||
run_command("msbuild", "cpptrace.sln")
|
||||
|
||||
os.chdir("..")
|
||||
print()
|
||||
@ -103,10 +109,14 @@ def build_full_or_auto(matrix):
|
||||
]
|
||||
if matrix["config"] != "":
|
||||
args.append(f"{matrix['config']}")
|
||||
print(args)
|
||||
if matrix["compiler"] == "g++":
|
||||
args.append("-GUnix Makefiles")
|
||||
succeeded = run_command(*args)
|
||||
if succeeded:
|
||||
run_command("msbuild", "cpptrace.sln")
|
||||
if matrix["compiler"] == "g++":
|
||||
run_command("make", "-j")
|
||||
else:
|
||||
run_command("msbuild", "cpptrace.sln")
|
||||
|
||||
os.chdir("..")
|
||||
print()
|
||||
@ -188,13 +198,19 @@ def main():
|
||||
"--msvc-only",
|
||||
action="store_true"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--mingw-only",
|
||||
action="store_true"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
compilers = ["cl", "clang++"]
|
||||
compilers = ["cl", "clang++", "g++"]
|
||||
if args.clang_only:
|
||||
compilers = ["clang++"]
|
||||
if args.msvc_only:
|
||||
compilers = ["cl"]
|
||||
if args.mingw_only:
|
||||
compilers = ["g++"]
|
||||
|
||||
matrix = {
|
||||
"compiler": compilers,
|
||||
@ -202,10 +218,12 @@ def main():
|
||||
"std": ["11", "20"],
|
||||
"unwind": [
|
||||
"CPPTRACE_UNWIND_WITH_WINAPI",
|
||||
"CPPTRACE_UNWIND_WITH_UNWIND",
|
||||
"CPPTRACE_UNWIND_WITH_NOTHING",
|
||||
],
|
||||
"symbols": [
|
||||
"CPPTRACE_GET_SYMBOLS_WITH_DBGHELP",
|
||||
"CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE",
|
||||
"CPPTRACE_GET_SYMBOLS_WITH_NOTHING",
|
||||
],
|
||||
"demangle": [
|
||||
@ -217,7 +235,27 @@ def main():
|
||||
{
|
||||
"demangle": "CPPTRACE_DEMANGLE_WITH_CXXABI",
|
||||
"compiler": "cl"
|
||||
}
|
||||
},
|
||||
{
|
||||
"unwind": "CPPTRACE_UNWIND_WITH_UNWIND",
|
||||
"compiler": "cl"
|
||||
},
|
||||
{
|
||||
"unwind": "CPPTRACE_UNWIND_WITH_UNWIND",
|
||||
"compiler": "clang++"
|
||||
},
|
||||
{
|
||||
"symbols": "CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE",
|
||||
"compiler": "cl"
|
||||
},
|
||||
{
|
||||
"symbols": "CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE",
|
||||
"compiler": "clang++"
|
||||
},
|
||||
{
|
||||
"symbols": "CPPTRACE_GET_SYMBOLS_WITH_DBGHELP",
|
||||
"compiler": "g++"
|
||||
},
|
||||
]
|
||||
run_matrix(matrix, exclude, build)
|
||||
matrix = {
|
||||
|
||||
@ -161,7 +161,7 @@ def build(matrix):
|
||||
if succeeded:
|
||||
return run_command("make", "-j")
|
||||
else:
|
||||
succeeded = run_command(
|
||||
args = [
|
||||
"cmake",
|
||||
"..",
|
||||
f"-DCMAKE_BUILD_TYPE={matrix['target']}",
|
||||
@ -172,9 +172,15 @@ def build(matrix):
|
||||
f"-D{matrix['demangle']}=On",
|
||||
"-DCPPTRACE_BUILD_TEST=On",
|
||||
"-DBUILD_SHARED_LIBS=On"
|
||||
)
|
||||
]
|
||||
if matrix["compiler"] == "g++":
|
||||
args.append("-GUnix Makefiles")
|
||||
succeeded = run_command(*args)
|
||||
if succeeded:
|
||||
return run_command("msbuild", "cpptrace.sln")
|
||||
if matrix["compiler"] == "g++":
|
||||
run_command("make", "-j")
|
||||
else:
|
||||
run_command("msbuild", "cpptrace.sln")
|
||||
|
||||
def build_full_or_auto(matrix):
|
||||
if platform.system() != "Windows":
|
||||
@ -205,10 +211,14 @@ def build_full_or_auto(matrix):
|
||||
]
|
||||
if matrix["config"] != "":
|
||||
args.append(f"{matrix['config']}")
|
||||
print(args)
|
||||
if matrix["compiler"] == "g++":
|
||||
args.append("-GUnix Makefiles")
|
||||
succeeded = run_command(*args)
|
||||
if succeeded:
|
||||
return run_command("msbuild", "cpptrace.sln")
|
||||
if matrix["compiler"] == "g++":
|
||||
run_command("make", "-j")
|
||||
else:
|
||||
run_command("msbuild", "cpptrace.sln")
|
||||
|
||||
def test(matrix):
|
||||
if platform.system() != "Windows":
|
||||
@ -217,10 +227,16 @@ def test(matrix):
|
||||
(matrix["compiler"], matrix["unwind"], matrix["symbols"], matrix["demangle"])
|
||||
)
|
||||
else:
|
||||
run_test(
|
||||
f".\\{matrix['target']}\\test.exe",
|
||||
(matrix["compiler"], matrix["unwind"], matrix["symbols"], matrix["demangle"])
|
||||
)
|
||||
if matrix["compiler"] == "g++":
|
||||
run_test(
|
||||
f".\\test.exe",
|
||||
(matrix["compiler"], matrix["unwind"], matrix["symbols"], matrix["demangle"])
|
||||
)
|
||||
else:
|
||||
run_test(
|
||||
f".\\{matrix['target']}\\test.exe",
|
||||
(matrix["compiler"], matrix["unwind"], matrix["symbols"], matrix["demangle"])
|
||||
)
|
||||
|
||||
def test_full_or_auto(matrix):
|
||||
if platform.system() != "Windows":
|
||||
@ -229,10 +245,16 @@ def test_full_or_auto(matrix):
|
||||
(matrix["compiler"],)
|
||||
)
|
||||
else:
|
||||
run_test(
|
||||
f".\\{matrix['target']}\\test.exe",
|
||||
(matrix["compiler"],)
|
||||
)
|
||||
if matrix["compiler"] == "g++":
|
||||
run_test(
|
||||
f".\\test.exe",
|
||||
(matrix["compiler"],)
|
||||
)
|
||||
else:
|
||||
run_test(
|
||||
f".\\{matrix['target']}\\test.exe",
|
||||
(matrix["compiler"],)
|
||||
)
|
||||
|
||||
def build_and_test(matrix):
|
||||
print(f"{Fore.BLUE}{Style.BRIGHT}{'=' * 10} Running build and test with config {', '.join(matrix.values())} {'=' * 10}{Style.RESET_ALL}")
|
||||
@ -341,13 +363,19 @@ def main():
|
||||
"--msvc-only",
|
||||
action="store_true"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--mingw-only",
|
||||
action="store_true"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
compilers = ["cl", "clang++"]
|
||||
compilers = ["cl", "clang++", "g++"]
|
||||
if args.clang_only:
|
||||
compilers = ["clang++"]
|
||||
if args.msvc_only:
|
||||
compilers = ["cl"]
|
||||
if args.mingw_only:
|
||||
compilers = ["g++"]
|
||||
|
||||
matrix = {
|
||||
"compiler": compilers,
|
||||
@ -355,10 +383,12 @@ def main():
|
||||
"std": ["11", "20"],
|
||||
"unwind": [
|
||||
"CPPTRACE_UNWIND_WITH_WINAPI",
|
||||
"CPPTRACE_UNWIND_WITH_UNWIND",
|
||||
#"CPPTRACE_UNWIND_WITH_NOTHING",
|
||||
],
|
||||
"symbols": [
|
||||
"CPPTRACE_GET_SYMBOLS_WITH_DBGHELP",
|
||||
"CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE",
|
||||
#"CPPTRACE_GET_SYMBOLS_WITH_NOTHING",
|
||||
],
|
||||
"demangle": [
|
||||
@ -370,6 +400,26 @@ def main():
|
||||
{
|
||||
"demangle": "CPPTRACE_DEMANGLE_WITH_CXXABI",
|
||||
"compiler": "cl"
|
||||
},
|
||||
{
|
||||
"unwind": "CPPTRACE_UNWIND_WITH_UNWIND",
|
||||
"compiler": "cl"
|
||||
},
|
||||
{
|
||||
"unwind": "CPPTRACE_UNWIND_WITH_UNWIND",
|
||||
"compiler": "clang++"
|
||||
},
|
||||
{
|
||||
"symbols": "CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE",
|
||||
"compiler": "cl"
|
||||
},
|
||||
{
|
||||
"symbols": "CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE",
|
||||
"compiler": "clang++"
|
||||
},
|
||||
{
|
||||
"symbols": "CPPTRACE_GET_SYMBOLS_WITH_DBGHELP",
|
||||
"compiler": "g++"
|
||||
}
|
||||
]
|
||||
run_matrix(matrix, exclude, build_and_test)
|
||||
|
||||
@ -19,9 +19,44 @@
|
||||
#include <ios>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#define IS_WINDOWS 0
|
||||
#define IS_LINUX 0
|
||||
#define IS_APPLE 0
|
||||
|
||||
#if defined(_WIN32)
|
||||
#undef IS_WINDOWS
|
||||
#define IS_WINDOWS 1
|
||||
#elif defined(__linux)
|
||||
#undef IS_LINUX
|
||||
#define IS_LINUX 1
|
||||
#elif defined(__APPLE__)
|
||||
#undef IS_APPLE
|
||||
#define IS_APPLE 1
|
||||
#else
|
||||
#error "Unexpected platform"
|
||||
#endif
|
||||
|
||||
#define IS_CLANG 0
|
||||
#define IS_GCC 0
|
||||
#define IS_MSVC 0
|
||||
|
||||
#if defined(__clang__)
|
||||
#undef IS_CLANG
|
||||
#define IS_CLANG 1
|
||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||
#undef IS_GCC
|
||||
#define IS_GCC 1
|
||||
#elif defined(_MSC_VER)
|
||||
#undef IS_MSVC
|
||||
#define IS_MSVC 1
|
||||
#else
|
||||
#error "Unsupported compiler"
|
||||
#endif
|
||||
|
||||
// Lightweight std::source_location.
|
||||
struct source_location {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
|
||||
@ -128,6 +163,61 @@ static std::string to_hex(uintptr_t addr) {
|
||||
return std::move(sstream).str();
|
||||
}
|
||||
|
||||
CPPTRACE_MAYBE_UNUSED
|
||||
static bool is_little_endian() {
|
||||
uint16_t num = 0x1;
|
||||
auto* ptr = (uint8_t*)#
|
||||
return ptr[0] == 1;
|
||||
}
|
||||
|
||||
// Modified from
|
||||
// https://stackoverflow.com/questions/105252/how-do-i-convert-between-big-endian-and-little-endian-values-in-c
|
||||
template<typename T, size_t N>
|
||||
struct byte_swapper;
|
||||
|
||||
template<typename T>
|
||||
struct byte_swapper<T, 1> {
|
||||
T operator()(T val) {
|
||||
return val;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct byte_swapper<T, 2> {
|
||||
T operator()(T val) {
|
||||
return ((((val) >> 8) & 0xff) | (((val) & 0xff) << 8));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct byte_swapper<T, 4> {
|
||||
T operator()(T val) {
|
||||
return ((((val) & 0xff000000) >> 24) |
|
||||
(((val) & 0x00ff0000) >> 8) |
|
||||
(((val) & 0x0000ff00) << 8) |
|
||||
(((val) & 0x000000ff) << 24));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct byte_swapper<T, 8> {
|
||||
T operator()(T val) {
|
||||
return ((((val) & 0xff00000000000000ull) >> 56) |
|
||||
(((val) & 0x00ff000000000000ull) >> 40) |
|
||||
(((val) & 0x0000ff0000000000ull) >> 24) |
|
||||
(((val) & 0x000000ff00000000ull) >> 8 ) |
|
||||
(((val) & 0x00000000ff000000ull) << 8 ) |
|
||||
(((val) & 0x0000000000ff0000ull) << 24) |
|
||||
(((val) & 0x000000000000ff00ull) << 40) |
|
||||
(((val) & 0x00000000000000ffull) << 56));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
|
||||
T byteswap(T value) {
|
||||
return byte_swapper<T, sizeof(T)>{}(value);
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
@ -12,11 +12,15 @@
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
// NOLINTNEXTLINE(misc-include-cleaner)
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#if IS_LINUX || IS_APPLE
|
||||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
// NOLINTNEXTLINE(misc-include-cleaner)
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#elif IS_WINDOWS
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace cpptrace {
|
||||
namespace detail {
|
||||
@ -27,6 +31,7 @@ namespace cpptrace {
|
||||
uintptr_t raw_address = 0;
|
||||
};
|
||||
|
||||
#if IS_LINUX || IS_APPLE
|
||||
// aladdr queries are needed to get pre-ASLR addresses and targets to run addr2line on
|
||||
std::vector<dlframe> backtrace_frames(const std::vector<void*>& addrs) {
|
||||
// reference: https://github.com/bminor/glibc/blob/master/debug/backtracesyms.c
|
||||
@ -41,7 +46,7 @@ namespace cpptrace {
|
||||
// but we don't really need dli_saddr
|
||||
frame.obj_path = info.dli_fname;
|
||||
frame.obj_base = reinterpret_cast<uintptr_t>(info.dli_fbase);
|
||||
frame.symbol = info.dli_sname ?: "?";
|
||||
frame.symbol = info.dli_sname ?: "";
|
||||
}
|
||||
frames.push_back(frame);
|
||||
}
|
||||
@ -113,6 +118,118 @@ namespace cpptrace {
|
||||
return output;
|
||||
}
|
||||
|
||||
uintptr_t get_module_image_base(const dlframe &entry) {
|
||||
(void)entry;
|
||||
return 0;
|
||||
}
|
||||
#elif IS_WINDOWS
|
||||
// aladdr queries are needed to get pre-ASLR addresses and targets to run addr2line on
|
||||
std::vector<dlframe> backtrace_frames(const std::vector<void*>& addrs) {
|
||||
// reference: https://github.com/bminor/glibc/blob/master/debug/backtracesyms.c
|
||||
std::vector<dlframe> frames;
|
||||
frames.reserve(addrs.size());
|
||||
for(const void* addr : addrs) {
|
||||
dlframe frame;
|
||||
frame.raw_address = reinterpret_cast<uintptr_t>(addr);
|
||||
HMODULE handle;
|
||||
if(GetModuleHandleExA(
|
||||
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
|
||||
static_cast<const char*>(addr),
|
||||
&handle
|
||||
)) {
|
||||
fflush(stderr);
|
||||
char path[MAX_PATH];
|
||||
if(GetModuleFileNameA(handle, path, sizeof(path))) {
|
||||
///fprintf(stderr, "path: %s base: %p\n", path, handle);
|
||||
frame.obj_path = path;
|
||||
frame.obj_base = reinterpret_cast<uintptr_t>(handle);
|
||||
frame.symbol = "";
|
||||
} else {
|
||||
fprintf(stderr, "%s\n", std::system_error(GetLastError(), std::system_category()).what());
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "%s\n", std::system_error(GetLastError(), std::system_category()).what());
|
||||
}
|
||||
frames.push_back(frame);
|
||||
}
|
||||
return frames;
|
||||
}
|
||||
|
||||
bool has_addr2line() {
|
||||
// TODO: Popen is a hack. Implement properly with CreateProcess and pipes later.
|
||||
FILE* p = popen("addr2line --version", "r");
|
||||
return pclose(p) == 0;
|
||||
}
|
||||
|
||||
std::string resolve_addresses(const std::string& addresses, const std::string& executable) {
|
||||
// TODO: Popen is a hack. Implement properly with CreateProcess and pipes later.
|
||||
///fprintf(stderr, ("addr2line -e " + executable + " -fCp " + addresses + "\n").c_str());
|
||||
FILE* p = popen(("addr2line -e " + executable + " -fCp " + addresses).c_str(), "r");
|
||||
std::string output;
|
||||
constexpr int buffer_size = 4096;
|
||||
char buffer[buffer_size];
|
||||
size_t count = 0;
|
||||
while((count = fread(buffer, 1, buffer_size, p)) > 0) {
|
||||
output.insert(output.end(), buffer, buffer + count);
|
||||
}
|
||||
pclose(p);
|
||||
///fprintf(stderr, "%s\n", output.c_str());
|
||||
return output;
|
||||
}
|
||||
|
||||
// TODO: Refactor into backtrace_frames...
|
||||
// TODO: Memoize
|
||||
uintptr_t get_module_image_base(const dlframe &entry) {
|
||||
// PE header values are little endian
|
||||
bool do_swap = !is_little_endian();
|
||||
FILE* file = fopen(entry.obj_path.c_str(), "rb");
|
||||
char magic[2];
|
||||
internal_verify(fread(magic, 1, 2, file) == 2); // file + 0x0
|
||||
internal_verify(memcmp(magic, "MZ", 2) == 0);
|
||||
DWORD e_lfanew;
|
||||
internal_verify(fseek(file, 0x3c, SEEK_SET) == 0);
|
||||
internal_verify(fread(&e_lfanew, sizeof(DWORD), 1, file) == 1); // file + 0x3c
|
||||
if(do_swap) e_lfanew = byteswap(e_lfanew);
|
||||
long nt_header_offset = e_lfanew;
|
||||
char signature[4];
|
||||
internal_verify(fseek(file, nt_header_offset, SEEK_SET) == 0);
|
||||
internal_verify(fread(signature, 1, 4, file) == 4); // NT header + 0x0
|
||||
internal_verify(memcmp(signature, "PE\0\0", 4) == 0);
|
||||
//WORD machine;
|
||||
//internal_verify(fseek(file, nt_header_offset + 4, SEEK_SET) == 0); // file header + 0x0
|
||||
//internal_verify(fread(&machine, sizeof(WORD), 1, file) == 1);
|
||||
WORD size_of_optional_header;
|
||||
internal_verify(fseek(file, nt_header_offset + 4 + 0x10, SEEK_SET) == 0); // file header + 0x10
|
||||
internal_verify(fread(&size_of_optional_header, sizeof(DWORD), 1, file) == 1);
|
||||
if(do_swap) size_of_optional_header = byteswap(size_of_optional_header);
|
||||
internal_verify(size_of_optional_header != 0);
|
||||
WORD optional_header_magic;
|
||||
internal_verify(fseek(file, nt_header_offset + 0x18, SEEK_SET) == 0); // optional header + 0x0
|
||||
internal_verify(fread(&optional_header_magic, sizeof(DWORD), 1, file) == 1);
|
||||
if(do_swap) optional_header_magic = byteswap(optional_header_magic);
|
||||
internal_verify(optional_header_magic == IMAGE_NT_OPTIONAL_HDR_MAGIC);
|
||||
uintptr_t image_base;
|
||||
if(optional_header_magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
|
||||
// 32 bit
|
||||
DWORD base;
|
||||
internal_verify(fseek(file, nt_header_offset + 0x18 + 0x1c, SEEK_SET) == 0); // optional header + 0x1c
|
||||
internal_verify(fread(&base, sizeof(DWORD), 1, file) == 1);
|
||||
if(do_swap) base = byteswap(base);
|
||||
image_base = base;
|
||||
} else {
|
||||
// 64 bit
|
||||
// I get an "error: 'QWORD' was not declared in this scope" for some reason when using QWORD
|
||||
unsigned __int64 base;
|
||||
internal_verify(fseek(file, nt_header_offset + 0x18 + 0x18, SEEK_SET) == 0); // optional header + 0x18
|
||||
internal_verify(fread(&base, sizeof(unsigned __int64), 1, file) == 1);
|
||||
if(do_swap) base = byteswap(base);
|
||||
image_base = base;
|
||||
}
|
||||
fclose(file);
|
||||
return image_base;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct symbolizer::impl {
|
||||
using target_vec = std::vector<std::pair<std::string, std::reference_wrapper<stacktrace_frame>>>;
|
||||
|
||||
@ -124,8 +241,9 @@ namespace cpptrace {
|
||||
std::unordered_map<std::string, target_vec> entries;
|
||||
for(std::size_t i = 0; i < dlframes.size(); i++) {
|
||||
const auto& entry = dlframes[i];
|
||||
///fprintf(stderr, "%s %s\n", to_hex(entry.raw_address).c_str(), to_hex(entry.raw_address - entry.obj_base + base).c_str());
|
||||
entries[entry.obj_path].emplace_back(
|
||||
to_hex(entry.raw_address - entry.obj_base),
|
||||
to_hex(entry.raw_address - entry.obj_base + get_module_image_base(entry)),
|
||||
trace[i]
|
||||
);
|
||||
// Set what is known for now, and resolutions from addr2line should overwrite
|
||||
@ -182,7 +300,11 @@ namespace cpptrace {
|
||||
std::string address_input;
|
||||
for(const auto& pair : entries_vec) {
|
||||
address_input += pair.first;
|
||||
address_input += '\n';
|
||||
#if !IS_WINDOWS
|
||||
address_input += '\n';
|
||||
#else
|
||||
address_input += ' ';
|
||||
#endif
|
||||
}
|
||||
auto output = split(trim(resolve_addresses(address_input, object_name)), "\n");
|
||||
internal_verify(output.size() == entries_vec.size());
|
||||
|
||||
Loading…
Reference in New Issue
Block a user