Add libdl back-end and improve testing system (#4)

This commit is contained in:
Jeremy Rifkin 2023-07-04 16:11:40 -04:00 committed by GitHub
parent c73af83e23
commit b5af425d09
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 185 additions and 86 deletions

View File

@ -19,6 +19,7 @@ jobs:
]
symbols: [
CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE,
CPPTRACE_GET_SYMBOLS_WITH_LIBDL,
CPPTRACE_GET_SYMBOLS_WITH_NOTHING,
]
demangle: [

View File

@ -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

View File

@ -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()

View File

@ -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;
}

View File

@ -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);
};
}
}

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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 {};

View File

@ -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||

View 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

View File

@ -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

View File

@ -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: