From 418e850b2b1f76b204af87a5d930f5129055e09a Mon Sep 17 00:00:00 2001 From: Egor Tensin Date: Sun, 13 Sep 2020 13:47:30 +0300 Subject: call_stack: can't noinline w/ MSVC, let's try a DLL --- .appveyor.yml | 6 +++--- .clang-format | 12 +++++++----- test/CMakeLists.txt | 20 ++++++++++++-------- test/call_stack.cpp | 37 ++----------------------------------- test/symbols.cpp | 21 --------------------- test/test_lib.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++++ test/test_lib.hpp | 19 +++++++++++++++++++ test/test_lib_api.hpp | 7 +++++++ test/unit_tests/dbghelp.cpp | 14 +++++++------- 9 files changed, 101 insertions(+), 79 deletions(-) delete mode 100644 test/symbols.cpp create mode 100644 test/test_lib.cpp create mode 100644 test/test_lib.hpp create mode 100644 test/test_lib_api.hpp diff --git a/.appveyor.yml b/.appveyor.yml index 2215bfb..3d881b0 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -38,9 +38,9 @@ after_build: test_script: - '"%install_dir%\bin\test\unit_tests.exe" --log_level=all' - '"%install_dir%\bin\test\call_stack.exe"' - - ps: '$(& "$env:install_dir\bin\test\call_stack.exe" | Select-String -Pattern "[call_stack!test::baz" -SimpleMatch -Quiet) -or $(throw "test::baz not found in the call stack")' - - ps: '$(& "$env:install_dir\bin\test\call_stack.exe" | Select-String -Pattern "[call_stack!test::bar" -SimpleMatch -Quiet) -or $(throw "test::bar not found in the call stack")' - - ps: '$(& "$env:install_dir\bin\test\call_stack.exe" | Select-String -Pattern "[call_stack!test::foo" -SimpleMatch -Quiet) -or $(throw "test::foo not found in the call stack")' + - ps: '$(& "$env:install_dir\bin\test\call_stack.exe" | Select-String -Pattern "[test_lib!test::baz" -SimpleMatch -Quiet) -or $(throw "test::baz not found in the call stack")' + - ps: '$(& "$env:install_dir\bin\test\call_stack.exe" | Select-String -Pattern "[test_lib!test::bar" -SimpleMatch -Quiet) -or $(throw "test::bar not found in the call stack")' + - ps: '$(& "$env:install_dir\bin\test\call_stack.exe" | Select-String -Pattern "[test_lib!test::foo" -SimpleMatch -Quiet) -or $(throw "test::foo not found in the call stack")' for: # Only build Release builds on master to speed things up: diff --git a/.clang-format b/.clang-format index ea7323d..fb0d2f6 100644 --- a/.clang-format +++ b/.clang-format @@ -12,14 +12,16 @@ SpacesBeforeTrailingComments: 1 IncludeCategories: - Regex: '^".*' Priority: 1 - - Regex: '^$' + - Regex: '^$' + - Regex: '^$' Priority: 5 - - Regex: '.*' + - Regex: '^<.*\.h>$' Priority: 6 + - Regex: '.*' + Priority: 7 ... diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c4406c8..8851856 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,17 +1,21 @@ -add_executable(call_stack call_stack.cpp) -target_link_libraries(call_stack PRIVATE pdb_repo) -target_link_libraries(call_stack PRIVATE Boost::nowide) +add_library(test_lib SHARED test_lib.cpp) +target_link_libraries(test_lib PRIVATE pdb_repo) +target_link_libraries(test_lib PRIVATE Boost::nowide) +target_include_directories(test_lib PUBLIC .) +target_compile_definitions(test_lib PRIVATE TEST_LIB_EXPORTS) -install(TARGETS call_stack RUNTIME DESTINATION bin/test) +install(TARGETS test_lib RUNTIME DESTINATION bin/test) if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") - install(FILES "$" DESTINATION bin/test OPTIONAL) + install(FILES "$" DESTINATION bin/test OPTIONAL) endif() -add_executable(symbols symbols.cpp) +add_executable(call_stack call_stack.cpp) +target_link_libraries(call_stack PRIVATE test_lib) +target_link_libraries(call_stack PRIVATE Boost::nowide) -install(TARGETS symbols RUNTIME DESTINATION bin/test) +install(TARGETS call_stack RUNTIME DESTINATION bin/test) if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") - install(FILES "$" DESTINATION bin/test OPTIONAL) + install(FILES "$" DESTINATION bin/test OPTIONAL) endif() add_subdirectory(unit_tests) diff --git a/test/call_stack.cpp b/test/call_stack.cpp index 25f3985..e14f744 100644 --- a/test/call_stack.cpp +++ b/test/call_stack.cpp @@ -1,45 +1,12 @@ -#include "pdb/all.hpp" +#include -#include #include #include -namespace test { - -typedef void (*F)(); - -void call_stack() { - const auto dbghelp = pdb::DbgHelp::current_process(); - const auto call_stack = pdb::CallStack::capture(); - call_stack.dump(boost::nowide::cout, dbghelp); -} - -// Some tricks to prevent the functions from being inlined follow... -void baz() { - boost::nowide::cout << "baz " << &baz << '\n'; - F f = &call_stack; - f(); -} - -void bar() { - boost::nowide::cout << "bar " << &bar << '\n'; - F f = &baz; - f(); -} - -void foo() { - boost::nowide::cout << "foo " << &foo << '\n'; - F f = &bar; - f(); -} - -} // namespace test - int main() { try { - test::F f = &test::foo; - f(); + test::print_call_stack(); } catch (const std::exception& e) { boost::nowide::cerr << e.what() << '\n'; return 1; diff --git a/test/symbols.cpp b/test/symbols.cpp deleted file mode 100644 index 7ace3bb..0000000 --- a/test/symbols.cpp +++ /dev/null @@ -1,21 +0,0 @@ -namespace foobar_ns { - -int exit_code = 1; - -int __declspec(noinline) baz() { - return exit_code; -} - -int __declspec(noinline) bar() { - return baz() * 2; -} - -int __declspec(noinline) foo() { - return bar() * 2; -} - -} // namespace foobar_ns - -int main() { - return foobar_ns::foo() * 2; -} diff --git a/test/test_lib.cpp b/test/test_lib.cpp new file mode 100644 index 0000000..19c0d32 --- /dev/null +++ b/test/test_lib.cpp @@ -0,0 +1,44 @@ +#include "test_lib.hpp" + +#include + +#include + +// Prevent frame pointer omission (FPO) and/or inlining. +#ifdef _MSC_VER +#pragma optimize("", off) +#endif + +namespace test { +namespace { + +void do_print_call_stack() { + const auto dbghelp = pdb::DbgHelp::current_process(); + const auto call_stack = pdb::CallStack::capture(); + call_stack.dump(boost::nowide::cout, dbghelp); +} + +} // namespace + +volatile int var = 42; + +void baz(F f) { + boost::nowide::cout << "baz\n"; + f(); +} + +void bar(F f) { + boost::nowide::cout << "bar\n"; + baz(f); +} + +void foo(F f) { + boost::nowide::cout << "foo\n"; + bar(f); +} + +void print_call_stack() { + foo(&do_print_call_stack); +} + +} // namespace test diff --git a/test/test_lib.hpp b/test/test_lib.hpp new file mode 100644 index 0000000..f5fa017 --- /dev/null +++ b/test/test_lib.hpp @@ -0,0 +1,19 @@ +#pragma once + +// This is dumb library which exports a bunch of symbols. + +#include "test_lib_api.hpp" + +namespace test { + +typedef void (*F)(); + +TEST_LIB_API extern volatile int var; + +TEST_LIB_API void foo(F); +TEST_LIB_API void bar(F); +TEST_LIB_API void baz(F); + +TEST_LIB_API void print_call_stack(); + +} // namespace test diff --git a/test/test_lib_api.hpp b/test/test_lib_api.hpp new file mode 100644 index 0000000..6404200 --- /dev/null +++ b/test/test_lib_api.hpp @@ -0,0 +1,7 @@ +#pragma once + +#ifdef TEST_LIB_EXPORTS +#define TEST_LIB_API __declspec(dllexport) +#else +#define TEST_LIB_API __declspec(dllimport) +#endif diff --git a/test/unit_tests/dbghelp.cpp b/test/unit_tests/dbghelp.cpp index 86cf1ff..13d22b8 100644 --- a/test/unit_tests/dbghelp.cpp +++ b/test/unit_tests/dbghelp.cpp @@ -36,10 +36,10 @@ Set join(Set&& xs, Set&& ys) { class DbgHelpWithSymbols : public DbgHelp { public: - DbgHelpWithSymbols() { load_symbols_pdb(); } + DbgHelpWithSymbols() { load_test_lib_pdb(); } static const std::string& get_namespace() { - static const std::string name{"foobar_ns"}; + static const std::string name{"test"}; return name; } @@ -47,7 +47,7 @@ public: static SymbolList expected_functions() { return make_qualified({"foo", "bar", "baz"}); } - static SymbolList expected_variables() { return make_qualified({"exit_code"}); } + static SymbolList expected_variables() { return make_qualified({"var"}); } static SymbolList expected_symbols() { return join(expected_functions(), expected_variables()); @@ -62,14 +62,14 @@ private: return qualified; } - void load_symbols_pdb() { - const auto pdb_path = get_symbols_pdb_path().string(); + void load_test_lib_pdb() { + const auto pdb_path = get_test_lib_pdb_path().string(); BOOST_TEST_MESSAGE("Loading PDB: " << pdb_path); dbghelp.load_pdb(pdb_path); } - static boost::filesystem::path get_symbols_pdb_path() { - return Paths::get().exe_dir / "symbols.pdb"; + static boost::filesystem::path get_test_lib_pdb_path() { + return Paths::get().exe_dir / "test_lib.pdb"; } }; -- cgit v1.2.3