Add libdl back-end and improve testing system (#4)
This commit is contained in:
parent
c73af83e23
commit
b5af425d09
1
.github/workflows/build.yml
vendored
1
.github/workflows/build.yml
vendored
@ -19,6 +19,7 @@ jobs:
|
||||
]
|
||||
symbols: [
|
||||
CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE,
|
||||
CPPTRACE_GET_SYMBOLS_WITH_LIBDL,
|
||||
CPPTRACE_GET_SYMBOLS_WITH_NOTHING,
|
||||
]
|
||||
demangle: [
|
||||
|
||||
6
.github/workflows/test.yml
vendored
6
.github/workflows/test.yml
vendored
@ -21,6 +21,7 @@ jobs:
|
||||
]
|
||||
symbols: [
|
||||
CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE,
|
||||
CPPTRACE_GET_SYMBOLS_WITH_LIBDL,
|
||||
#CPPTRACE_GET_SYMBOLS_WITH_NOTHING,
|
||||
]
|
||||
demangle: [
|
||||
@ -44,12 +45,13 @@ jobs:
|
||||
-D${{matrix.demangle}}=On \
|
||||
-DCPPTRACE_BACKTRACE_PATH=/usr/lib/gcc/x86_64-linux-gnu/10/include/backtrace.h \
|
||||
-DCPPTRACE_BUILD_TEST=On \
|
||||
$(if [ "${{matrix.symbols}}" = "CPPTRACE_GET_SYMBOLS_WITH_LIBDL" ]; then echo "-DCPPTRACE_BUILD_TEST_RDYNAMIC=On"; else echo ""; fi) \
|
||||
-DBUILD_SHARED_LIBS=On
|
||||
make
|
||||
- name: test
|
||||
working-directory: build
|
||||
run: |
|
||||
./test | python3 ../test/test.py "${{matrix.compiler}}"
|
||||
./test | python3 ../test/test.py "${{matrix.compiler}}" "${{matrix.unwind}}" "${{matrix.symbols}}" "${{matrix.demangle}}"
|
||||
test-windows:
|
||||
runs-on: windows-2019
|
||||
strategy:
|
||||
@ -94,7 +96,7 @@ jobs:
|
||||
- name: test
|
||||
working-directory: build
|
||||
run: |
|
||||
.\${{matrix.target}}\test.exe | python3 ..\test\test.py "${{matrix.compiler}}"
|
||||
.\${{matrix.target}}\test.exe | python3 ..\test\test.py "${{matrix.compiler}}" "${{matrix.unwind}}" "${{matrix.symbols}}" "${{matrix.demangle}}"
|
||||
|
||||
test-linux-full-or-auto:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
@ -64,6 +64,7 @@ option(CPPTRACE_DEMANGLE_WITH_CXXABI "" OFF)
|
||||
option(CPPTRACE_DEMANGLE_WITH_NOTHING "" OFF)
|
||||
|
||||
option(CPPTRACE_BUILD_TEST "" OFF)
|
||||
option(CPPTRACE_BUILD_TEST_RDYNAMIC "" OFF)
|
||||
|
||||
set(CPPTRACE_BACKTRACE_PATH "" CACHE STRING "Path to backtrace.h, if the compiler doesn't already know it. Check /usr/lib/gcc/x86_64-linux-gnu/*/include.")
|
||||
set(CPPTRACE_HARD_MAX_FRAMES "" CACHE STRING "Hard limit on unwinding depth. Default is 100.")
|
||||
@ -238,10 +239,12 @@ endif()
|
||||
|
||||
if(CPPTRACE_GET_SYMBOLS_WITH_LIBDL)
|
||||
target_compile_definitions(cpptrace PUBLIC CPPTRACE_GET_SYMBOLS_WITH_LIBDL)
|
||||
target_link_libraries(cpptrace PRIVATE dl)
|
||||
endif()
|
||||
|
||||
if(CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE)
|
||||
target_compile_definitions(cpptrace PUBLIC CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE)
|
||||
target_link_libraries(cpptrace PRIVATE dl)
|
||||
endif()
|
||||
|
||||
if(CPPTRACE_GET_SYMBOLS_WITH_DBGHELP)
|
||||
@ -356,4 +359,7 @@ endif()
|
||||
if(CPPTRACE_BUILD_TEST)
|
||||
add_executable(test test/test.cpp)
|
||||
target_link_libraries(test PRIVATE cpptrace)
|
||||
if(CPPTRACE_BUILD_TEST_RDYNAMIC)
|
||||
set_property(TARGET test PROPERTY ENABLE_EXPORTS ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@ -16,12 +16,10 @@ namespace cpptrace {
|
||||
CPPTRACE_FORCE_NO_INLINE
|
||||
std::vector<stacktrace_frame> generate_trace() {
|
||||
std::vector<void*> frames = detail::capture_frames(1);
|
||||
std::vector<stacktrace_frame> trace;
|
||||
detail::symbolizer symbolizer;
|
||||
for(const auto frame : frames) {
|
||||
auto entry = symbolizer.resolve_frame(frame);
|
||||
entry.symbol = detail::demangle(entry.symbol);
|
||||
trace.push_back(entry);
|
||||
std::vector<stacktrace_frame> trace = symbolizer.resolve_frames(frames);
|
||||
for(auto& frame : trace) {
|
||||
frame.symbol = detail::demangle(frame.symbol);
|
||||
}
|
||||
return trace;
|
||||
}
|
||||
|
||||
@ -14,7 +14,8 @@ namespace cpptrace {
|
||||
public:
|
||||
symbolizer();
|
||||
~symbolizer();
|
||||
stacktrace_frame resolve_frame(void* addr);
|
||||
//stacktrace_frame resolve_frame(void* addr);
|
||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<void*>& frames);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -392,8 +392,17 @@ namespace cpptrace {
|
||||
symbolizer::symbolizer() : pimpl{new impl} {}
|
||||
symbolizer::~symbolizer() = default;
|
||||
|
||||
stacktrace_frame symbolizer::resolve_frame(void* addr) {
|
||||
return pimpl->resolve_frame(addr);
|
||||
//stacktrace_frame symbolizer::resolve_frame(void* addr) {
|
||||
// return pimpl->resolve_frame(addr);
|
||||
//}
|
||||
|
||||
std::vector<stacktrace_frame> symbolizer::resolve_frames(const std::vector<void*>& frames) {
|
||||
std::vector<stacktrace_frame> trace;
|
||||
trace.reserve(frames.size());
|
||||
for(const auto frame : frames) {
|
||||
trace.push_back(pimpl->resolve_frame(frame));
|
||||
}
|
||||
return trace;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,55 @@
|
||||
#ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBDL
|
||||
|
||||
#include <cpptrace/cpptrace.hpp>
|
||||
#include "cpptrace_symbols.hpp"
|
||||
#include "../platform/cpptrace_program_name.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
namespace cpptrace {
|
||||
namespace detail {
|
||||
struct symbolizer::impl {
|
||||
stacktrace_frame resolve_frame(void* addr) {
|
||||
Dl_info info;
|
||||
if(dladdr(addr, &info)) {
|
||||
return {
|
||||
reinterpret_cast<uintptr_t>(addr),
|
||||
0,
|
||||
0,
|
||||
info.dli_fname ? info.dli_fname : "",
|
||||
info.dli_sname ? info.dli_sname : ""
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
reinterpret_cast<uintptr_t>(addr),
|
||||
0,
|
||||
0,
|
||||
"",
|
||||
""
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
symbolizer::symbolizer() : pimpl{new impl} {}
|
||||
symbolizer::~symbolizer() = default;
|
||||
|
||||
//stacktrace_frame symbolizer::resolve_frame(void* addr) {
|
||||
// return pimpl->resolve_frame(addr);
|
||||
//}
|
||||
|
||||
std::vector<stacktrace_frame> symbolizer::resolve_frames(const std::vector<void*>& frames) {
|
||||
std::vector<stacktrace_frame> trace;
|
||||
trace.reserve(frames.size());
|
||||
for(const auto frame : frames) {
|
||||
trace.push_back(pimpl->resolve_frame(frame));
|
||||
}
|
||||
return trace;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -80,8 +80,17 @@ namespace cpptrace {
|
||||
symbolizer::symbolizer() : pimpl{new impl} {}
|
||||
symbolizer::~symbolizer() = default;
|
||||
|
||||
stacktrace_frame symbolizer::resolve_frame(void* addr) {
|
||||
return pimpl->resolve_frame(addr);
|
||||
//stacktrace_frame symbolizer::resolve_frame(void* addr) {
|
||||
// return pimpl->resolve_frame(addr);
|
||||
//}
|
||||
|
||||
std::vector<stacktrace_frame> symbolizer::resolve_frames(const std::vector<void*>& frames) {
|
||||
std::vector<stacktrace_frame> trace;
|
||||
trace.reserve(frames.size());
|
||||
for(const auto frame : frames) {
|
||||
trace.push_back(pimpl->resolve_frame(frame));
|
||||
}
|
||||
return trace;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,14 +11,24 @@ namespace cpptrace {
|
||||
symbolizer::symbolizer() = default;
|
||||
symbolizer::~symbolizer() = default;
|
||||
|
||||
stacktrace_frame symbolizer::resolve_frame(void*) {
|
||||
return {
|
||||
// stacktrace_frame symbolizer::resolve_frame(void*) {
|
||||
// return {
|
||||
// 0,
|
||||
// -1,
|
||||
// -1,
|
||||
// "",
|
||||
// "",
|
||||
// };
|
||||
// }
|
||||
|
||||
std::vector<stacktrace_frame> symbolizer::resolve_frames(const std::vector<void*>& frames) {
|
||||
return std::vector<stacktrace_frame>(frames.size(), {
|
||||
0,
|
||||
-1,
|
||||
-1,
|
||||
"",
|
||||
"",
|
||||
};
|
||||
""
|
||||
});
|
||||
}
|
||||
|
||||
struct symbolizer::impl {};
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
test/test.cpp||18||trace()
|
||||
test/test.cpp||34||foo(int)
|
||||
test/test.cpp||38||foo(int)
|
||||
test/test.cpp||38||foo(int)
|
||||
test/test.cpp||38||foo(int)
|
||||
test/test.cpp||38||foo(int)
|
||||
test/test.cpp||38||foo(int)
|
||||
test/test.cpp||38||foo(int)
|
||||
test/test.cpp||38||foo(int)
|
||||
test/test.cpp||38||foo(int)
|
||||
test/test.cpp||38||foo(int)
|
||||
test/test.cpp||38||foo(int)
|
||||
test/test.cpp||46||void foo<int>(int, int)
|
||||
test/test.cpp||46||void foo<int, int>(int, int, int)
|
||||
test/test.cpp||46||void foo<int, int, int>(int, int, int, int)
|
||||
test/test.cpp||46||void foo<int, int, int, int>(int, int, int, int, int)
|
||||
test/test.cpp||46||void foo<int, int, int, int, int>(int, int, int, int, int, int)
|
||||
test/test.cpp||46||void foo<int, int, int, int, int, int>(int, int, int, int, int, int, int)
|
||||
test/test.cpp||46||void foo<int, int, int, int, int, int, int>(int, int, int, int, int, int, int, int)
|
||||
test/test.cpp||46||void foo<int, int, int, int, int, int, int, int>(int, int, int, int, int, int, int, int, int)
|
||||
test/test.cpp||46||void foo<int, int, int, int, int, int, int, int, int>(int, int, int, int, int, int, int, int, int, int)
|
||||
test/test.cpp||52||function_two(int, float)
|
||||
test/test.cpp||58||function_one(int)
|
||||
test/test.cpp||64||main
|
||||
../csu/libc-start.c||308||__libc_start_main
|
||||
||0||_start
|
||||
||0||
|
||||
26
test/expected/linux.libdl.txt
Normal file
26
test/expected/linux.libdl.txt
Normal file
@ -0,0 +1,26 @@
|
||||
./test||0||trace()
|
||||
./test||0||foo(int)
|
||||
./test||0||foo(int)
|
||||
./test||0||foo(int)
|
||||
./test||0||foo(int)
|
||||
./test||0||foo(int)
|
||||
./test||0||foo(int)
|
||||
./test||0||foo(int)
|
||||
./test||0||foo(int)
|
||||
./test||0||foo(int)
|
||||
./test||0||foo(int)
|
||||
./test||0||foo(int)
|
||||
./test||0||void foo<int>(int, int)
|
||||
./test||0||void foo<int, int>(int, int, int)
|
||||
./test||0||void foo<int, int, int>(int, int, int, int)
|
||||
./test||0||void foo<int, int, int, int>(int, int, int, int, int)
|
||||
./test||0||void foo<int, int, int, int, int>(int, int, int, int, int, int)
|
||||
./test||0||void foo<int, int, int, int, int, int>(int, int, int, int, int, int, int)
|
||||
./test||0||void foo<int, int, int, int, int, int, int>(int, int, int, int, int, int, int, int)
|
||||
./test||0||void foo<int, int, int, int, int, int, int, int>(int, int, int, int, int, int, int, int, int)
|
||||
./test||0||void foo<int, int, int, int, int, int, int, int, int>(int, int, int, int, int, int, int, int, int, int)
|
||||
./test||0||function_two(int, float)
|
||||
./test||0||function_one(int)
|
||||
./test||0||main
|
||||
/lib/x86_64-linux-gnu/libc.so.6||0||__libc_start_main
|
||||
./test||0||_start
|
||||
@ -1,30 +0,0 @@
|
||||
test\test.cpp||18||trace()
|
||||
test\test.cpp||35||foo(int)
|
||||
test\test.cpp||39||foo(int)
|
||||
test\test.cpp||39||foo(int)
|
||||
test\test.cpp||39||foo(int)
|
||||
test\test.cpp||39||foo(int)
|
||||
test\test.cpp||39||foo(int)
|
||||
test\test.cpp||39||foo(int)
|
||||
test\test.cpp||39||foo(int)
|
||||
test\test.cpp||39||foo(int)
|
||||
test\test.cpp||39||foo(int)
|
||||
test\test.cpp||39||foo(int)
|
||||
test\test.cpp||47||foo<int>(int, int)
|
||||
test\test.cpp||47||foo<int, int>(int, int, int)
|
||||
test\test.cpp||47||foo<int, int, int>(int, int, int, int)
|
||||
test\test.cpp||47||foo<int, int, int, int>(int, int, int, int, int)
|
||||
test\test.cpp||47||foo<int, int, int, int, int>(int, int, int, int, int, int)
|
||||
test\test.cpp||47||foo<int, int, int, int, int, int>(int, int, int, int, int, int, int)
|
||||
test\test.cpp||47||foo<int, int, int, int, int, int, int>(int, int, int, int, int, int, int, int)
|
||||
test\test.cpp||47||foo<int, int, int, int, int, int, int, int>(int, int, int, int, int, int, int, int, int)
|
||||
test\test.cpp||47||foo<int, int, int, int, int, int, int, int, int>(int, int, int, int, int, int, int, int, int, int)
|
||||
test\test.cpp||53||function_two(int, float)
|
||||
test\test.cpp||59||function_one(int)
|
||||
test\test.cpp||65||main()
|
||||
D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl||79||invoke_main()
|
||||
D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl||288||__scrt_common_main_seh()
|
||||
D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl||331||__scrt_common_main()
|
||||
D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_main.cpp||17||mainCRTStartup(void*)
|
||||
||-1||BaseThreadInitThunk
|
||||
||-1||RtlUserThreadStart
|
||||
65
test/test.py
65
test/test.py
@ -1,23 +1,64 @@
|
||||
import os
|
||||
import sys
|
||||
from typing import List
|
||||
|
||||
MAX_LINE_DIFF = 2
|
||||
|
||||
def similarity(name: str, target: List[str]) -> int:
|
||||
parts = name.split(".txt")[0].split(".")
|
||||
c = 0
|
||||
for part in parts:
|
||||
if part in target:
|
||||
c += 1
|
||||
else:
|
||||
return -1
|
||||
return c
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 2:
|
||||
print("Expected one argument")
|
||||
if len(sys.argv) < 2:
|
||||
print("Expected at least one arg")
|
||||
sys.exit(1)
|
||||
|
||||
if sys.argv[1].startswith("gcc") or sys.argv[1].startswith("g++"):
|
||||
name = "gcc"
|
||||
elif sys.argv[1].startswith("clang"):
|
||||
name = "clang"
|
||||
elif sys.argv[1].startswith("cl"):
|
||||
name = "msvc"
|
||||
if os.name == "nt":
|
||||
name = "windows_" + name
|
||||
target = []
|
||||
|
||||
with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), "expected/", name + ".txt"), "r") as f:
|
||||
if sys.argv[1].startswith("gcc") or sys.argv[1].startswith("g++"):
|
||||
target.append("gcc")
|
||||
elif sys.argv[1].startswith("clang"):
|
||||
target.append("clang")
|
||||
elif sys.argv[1].startswith("cl"):
|
||||
target.append("msvc")
|
||||
|
||||
if os.name == "nt":
|
||||
target.append("windows")
|
||||
else:
|
||||
target.append("linux")
|
||||
|
||||
other_configs = sys.argv[2:]
|
||||
for config in other_configs:
|
||||
assert "WITH_" in config
|
||||
target.append(config.split("WITH_")[1].lower())
|
||||
|
||||
print(f"Searching for expected file best matching {target}")
|
||||
|
||||
expected_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "expected/")
|
||||
files = [f for f in os.listdir(expected_dir) if os.path.isfile(os.path.join(expected_dir, f))]
|
||||
if len(files) == 0:
|
||||
print(f"Error: No expected files to use (searching {expected_dir})", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
files = list(map(lambda f: (f, similarity(f, target)), files))
|
||||
m = max(files, key=lambda entry: entry[1])[1]
|
||||
if m <= 0:
|
||||
print(f"Error: Could not find match for {target} in {files}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
files = [entry[0] for entry in files if entry[1] == m]
|
||||
if len(files) > 1:
|
||||
print(f"Error: Ambiguous expected file to use ({files})", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
file = files[0]
|
||||
print(f"Reading from {file}")
|
||||
|
||||
with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), "expected/", file), "r") as f:
|
||||
expected = f.read()
|
||||
|
||||
output = sys.stdin.read()
|
||||
@ -49,8 +90,6 @@ def main():
|
||||
break
|
||||
|
||||
if errored:
|
||||
#print("Test output:", file=sys.stderr)
|
||||
#print(raw_output, file=sys.stderr)
|
||||
print("Test failed")
|
||||
sys.exit(1)
|
||||
else:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user