From f489192a7c2396e64b7a6deb2e8d7a2768b492de Mon Sep 17 00:00:00 2001 From: Christophe Bedard Date: Wed, 3 Jul 2019 13:53:08 +0200 Subject: [PATCH] Implement symbol resolution for non-funct ptr std::function objects --- tracetools/include/tracetools/utils.hpp | 40 +++++++++++++++++++------ tracetools/src/utils.cpp | 37 +++++++++++------------ tracetools/test/test_utils.cpp | 6 +--- 3 files changed, 50 insertions(+), 33 deletions(-) diff --git a/tracetools/include/tracetools/utils.hpp b/tracetools/include/tracetools/utils.hpp index e73030b..5a0d995 100644 --- a/tracetools/include/tracetools/utils.hpp +++ b/tracetools/include/tracetools/utils.hpp @@ -18,18 +18,40 @@ #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_non_funcptr(std::function f) { - typedef T (fnType)(U...); - fnType ** fnPointer = f.template target(); - // Might be a lambda - if (fnPointer == nullptr) { - return 0; - } - return reinterpret_cast(*fnPointer); +#if defined(TRACETOOLS_LTTNG_ENABLED) && !defined(_WIN32) + return _demangle_symbol(f.target_type().name()); +#else + (void)f; + return SYMBOL_UNKNOWN; +#endif } -const char * get_symbol(void * funptr); +template +const char * get_symbol(std::function f) +{ +#if defined(TRACETOOLS_LTTNG_ENABLED) && !defined(_WIN32) + typedef T (fnType)(U...); + fnType ** fnPointer = f.template target(); + // If we get an actual address + if (fnPointer != nullptr) { + void * funcptr = reinterpret_cast(*fnPointer); + return _get_symbol_funcptr(funcptr); + } + // Otherwise we have to go through target_type() + return _get_symbol_non_funcptr(f); +#else + (void)f; + return SYMBOL_UNKNOWN; +#endif +} #endif // TRACETOOLS__UTILS_HPP_ diff --git a/tracetools/src/utils.cpp b/tracetools/src/utils.cpp index 2190df9..e9667b1 100644 --- a/tracetools/src/utils.cpp +++ b/tracetools/src/utils.cpp @@ -12,38 +12,37 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include - #if defined(TRACETOOLS_LTTNG_ENABLED) && !defined(_WIN32) #include #include #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) { - std::cout << "lamba!" << std::endl; - return SYMBOL_LAMBDA; - } - - Dl_info info; - if (dladdr(funptr, &info) == 0) { - std::cout << "unknown!" << std::endl; - 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); + const char * demangled_val = (status == 0 ? demangled : mangled); return demangled_val != 0 ? demangled_val : SYMBOL_UNKNOWN; #else - (void)funptr; + (void)mangled; + return SYMBOL_UNKNOWN; +#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 SYMBOL_UNKNOWN; #endif } diff --git a/tracetools/test/test_utils.cpp b/tracetools/test/test_utils.cpp index 455b0a4..d75233c 100644 --- a/tracetools/test/test_utils.cpp +++ b/tracetools/test/test_utils.cpp @@ -44,14 +44,11 @@ TEST(TestUtils, valid_address_symbol) { // Function pointer std::function)> f = &function_shared; // Address for one with an actual underlying function should be non-zero - ASSERT_GT(get_address(f), (void *)0) << "get_address() for function not valid"; - ASSERT_STREQ(get_symbol(get_address(f)), "function_shared(std::shared_ptr)") << + ASSERT_STREQ(get_symbol(f), "function_shared(std::shared_ptr)") << "invalid function name"; // Lambda std::function l = [](int num) {return num + 1;}; - // Address for an std::function with an underlying lambda should be nullptr - ASSERT_EQ(get_address(l), nullptr) << "get_address() for lambda std::function not 0"; // TODO(christophebedard) check symbol // Bind (to member function) @@ -62,6 +59,5 @@ TEST(TestUtils, valid_address_symbol) { std::placeholders::_1, std::placeholders::_2 ); - ASSERT_EQ(get_address(fscwc), nullptr) << "get_address() for std::bind std::function not 0"; // TODO(christophebedard) check symbol }