diff --git a/tracetools/CMakeLists.txt b/tracetools/CMakeLists.txt index a6327a5..ca6062a 100644 --- a/tracetools/CMakeLists.txt +++ b/tracetools/CMakeLists.txt @@ -57,7 +57,7 @@ if(TRACING_ENABLED) list(APPEND SOURCES ${LTTNG_TP_FILES}) endif() -add_library(${PROJECT_NAME} ${SOURCES}) +add_library(${PROJECT_NAME} SHARED ${SOURCES}) if(TRACING_ENABLED) target_compile_definitions(${PROJECT_NAME} PUBLIC TRACETOOLS_LTTNG_ENABLED) target_link_libraries(${PROJECT_NAME} ${LTTNG_LIBRARIES} -ldl) @@ -87,8 +87,14 @@ else() endif() if(BUILD_TESTING) + find_package(ament_cmake_gtest REQUIRED) find_package(ament_lint_auto REQUIRED) ament_lint_auto_find_test_dependencies() + + ament_add_gtest(test_utils test/test_utils.cpp) + if(TARGET test_utils) + target_link_libraries(test_utils ${PROJECT_NAME} -rdynamic) + endif() endif() ament_package() diff --git a/tracetools/include/tracetools/utils.hpp b/tracetools/include/tracetools/utils.hpp index e73030b..2e882bc 100644 --- a/tracetools/include/tracetools/utils.hpp +++ b/tracetools/include/tracetools/utils.hpp @@ -18,18 +18,24 @@ #include #include +#define SYMBOL_UNKNOWN "UNKNOWN" + +const char * _demangle_symbol(const char * mangled); + +const char * _get_symbol_funcptr(void * funcptr); + template -void * get_address(std::function f) +const char * get_symbol(std::function f) { typedef T (fnType)(U...); fnType ** fnPointer = f.template target(); - // Might be a lambda - if (fnPointer == nullptr) { - return 0; + // If we get an actual address + if (fnPointer != nullptr) { + void * funcptr = reinterpret_cast(*fnPointer); + return _get_symbol_funcptr(funcptr); } - return reinterpret_cast(*fnPointer); + // Otherwise we have to go through target_type() + return _demangle_symbol(f.target_type().name()); } -const char * get_symbol(void * funptr); - #endif // TRACETOOLS__UTILS_HPP_ diff --git a/tracetools/package.xml b/tracetools/package.xml index a3cf0c5..45e574a 100644 --- a/tracetools/package.xml +++ b/tracetools/package.xml @@ -15,6 +15,7 @@ liblttng-ust-dev + ament_cmake_gtest ament_lint_auto ament_lint_common diff --git a/tracetools/src/utils.cpp b/tracetools/src/utils.cpp index acb49cb..807fe87 100644 --- a/tracetools/src/utils.cpp +++ b/tracetools/src/utils.cpp @@ -18,28 +18,31 @@ #endif #include "tracetools/utils.hpp" -const char * get_symbol(void * funptr) +const char * _demangle_symbol(const char * mangled) { -#define SYMBOL_UNKNOWN "UNKNOWN" #if defined(TRACETOOLS_LTTNG_ENABLED) && !defined(_WIN32) -#define SYMBOL_LAMBDA "[lambda]" - if (funptr == 0) { - return SYMBOL_LAMBDA; - } - - Dl_info info; - if (dladdr(funptr, &info) == 0) { - return SYMBOL_UNKNOWN; - } - char * demangled = nullptr; int status; - demangled = abi::__cxa_demangle(info.dli_sname, NULL, 0, &status); + demangled = abi::__cxa_demangle(mangled, NULL, 0, &status); // Use demangled symbol if possible - const char * demangled_val = (status == 0 ? demangled : info.dli_sname); - return demangled_val != 0 ? demangled_val : SYMBOL_UNKNOWN; + const char * demangled_val = (status == 0 ? demangled : mangled); + return demangled_val != 0 ? demangled_val : "UNKNOWN_demangling_failed"; #else - (void)funptr; - return SYMBOL_UNKNOWN; + (void)mangled; + return "DISABLED__demangle_symbol"; +#endif +} + +const char * _get_symbol_funcptr(void * funcptr) +{ +#if defined(TRACETOOLS_LTTNG_ENABLED) && !defined(_WIN32) + Dl_info info; + if (dladdr(funcptr, &info) == 0) { + return SYMBOL_UNKNOWN; + } + return _demangle_symbol(info.dli_sname); +#else + (void)funcptr; + return "DISABLED__get_symbol_funcptr"; #endif } diff --git a/tracetools/test/test_utils.cpp b/tracetools/test/test_utils.cpp new file mode 100644 index 0000000..ab94037 --- /dev/null +++ b/tracetools/test/test_utils.cpp @@ -0,0 +1,79 @@ +// Copyright 2019 Robert Bosch GmbH +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +#include +#include + +#include "tracetools/utils.hpp" + +void function_shared(const std::shared_ptr p) +{ + (void)p; +} + +class SomeClassWithCallback +{ +public: + SomeClassWithCallback() {} + + void my_callback(int some_number, std::string some_string) + { + (void)some_number; + (void)some_string; + } +}; + +/* + Testing symbol resolution for std::function object created from a function pointer. + */ +TEST(TestUtils, valid_symbol_funcptr) { + std::function)> f = &function_shared; + EXPECT_STREQ(get_symbol(f), "function_shared(std::shared_ptr)") << + "invalid symbol"; +} + +/* + Testing symbol resolution for std::function object created from a lambda. + */ +TEST(TestUtils, valid_symbol_lambda) { + std::function l = [](int num) {return num + 1;}; + EXPECT_STREQ( + get_symbol(l), + "TestUtils_valid_symbol_lambda_Test::TestBody()::{lambda(int)#1}") << + "invalid symbol"; +} + +/* + Testing symbol resolution for std::function object created from std::bind. + */ +TEST(TestUtils, valid_symbol_bind) { + SomeClassWithCallback scwc; + std::function fscwc = std::bind( + &SomeClassWithCallback::my_callback, + &scwc, + std::placeholders::_1, + std::placeholders::_2 + ); + EXPECT_STREQ( + get_symbol( + fscwc), + "std::_Bind, std::_Placeholder<2>))(int, std::__cxx11::basic_string" + ", std::allocator >)>") + << + "invalid symbol"; +} diff --git a/tracetools_test/CMakeLists.txt b/tracetools_test/CMakeLists.txt index 142ad6f..b09e2a0 100644 --- a/tracetools_test/CMakeLists.txt +++ b/tracetools_test/CMakeLists.txt @@ -25,62 +25,80 @@ if(BUILD_TESTING) ament_target_dependencies(test_publisher rclcpp std_msgs + tracetools ) + target_link_libraries(test_publisher -rdynamic) add_executable(test_subscription src/test_subscription.cpp ) ament_target_dependencies(test_subscription rclcpp std_msgs + tracetools ) + target_link_libraries(test_subscription -rdynamic) add_executable(test_intra src/test_intra.cpp ) ament_target_dependencies(test_intra rclcpp std_msgs + tracetools ) + target_link_libraries(test_intra -rdynamic) add_executable(test_ping src/test_ping.cpp ) ament_target_dependencies(test_ping rclcpp std_msgs + tracetools ) + target_link_libraries(test_ping -rdynamic) add_executable(test_pong src/test_pong.cpp ) ament_target_dependencies(test_pong rclcpp std_msgs + tracetools ) + target_link_libraries(test_pong -rdynamic) add_executable(test_timer src/test_timer.cpp ) ament_target_dependencies(test_timer rclcpp + tracetools ) + target_link_libraries(test_timer -rdynamic) add_executable(test_service src/test_service.cpp ) ament_target_dependencies(test_service rclcpp std_srvs + tracetools ) + target_link_libraries(test_service -rdynamic) add_executable(test_service_ping src/test_service_ping.cpp ) ament_target_dependencies(test_service_ping rclcpp std_srvs + tracetools ) + target_link_libraries(test_service_ping -rdynamic) add_executable(test_service_pong src/test_service_pong.cpp ) ament_target_dependencies(test_service_pong rclcpp std_srvs + tracetools ) + target_link_libraries(test_service_pong -rdynamic) install(TARGETS test_intra