Implement symbol resolution for non-funct ptr std::function objects

This commit is contained in:
Christophe Bedard 2019-07-03 13:53:08 +02:00
parent 64cb3a2952
commit f489192a7c
3 changed files with 50 additions and 33 deletions

View file

@ -18,18 +18,40 @@
#include <stddef.h> #include <stddef.h>
#include <functional> #include <functional>
#define SYMBOL_UNKNOWN "UNKNOWN"
const char * _demangle_symbol(const char * mangled);
const char * _get_symbol_funcptr(void * funcptr);
template<typename T, typename ... U> template<typename T, typename ... U>
void * get_address(std::function<T(U...)> f) const char * _get_symbol_non_funcptr(std::function<T(U...)> f)
{ {
typedef T (fnType)(U...); #if defined(TRACETOOLS_LTTNG_ENABLED) && !defined(_WIN32)
fnType ** fnPointer = f.template target<fnType *>(); return _demangle_symbol(f.target_type().name());
// Might be a lambda #else
if (fnPointer == nullptr) { (void)f;
return 0; return SYMBOL_UNKNOWN;
} #endif
return reinterpret_cast<void *>(*fnPointer);
} }
const char * get_symbol(void * funptr); template<typename T, typename ... U>
const char * get_symbol(std::function<T(U...)> f)
{
#if defined(TRACETOOLS_LTTNG_ENABLED) && !defined(_WIN32)
typedef T (fnType)(U...);
fnType ** fnPointer = f.template target<fnType *>();
// If we get an actual address
if (fnPointer != nullptr) {
void * funcptr = reinterpret_cast<void *>(*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_ #endif // TRACETOOLS__UTILS_HPP_

View file

@ -12,38 +12,37 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include <iostream>
#if defined(TRACETOOLS_LTTNG_ENABLED) && !defined(_WIN32) #if defined(TRACETOOLS_LTTNG_ENABLED) && !defined(_WIN32)
#include <dlfcn.h> #include <dlfcn.h>
#include <cxxabi.h> #include <cxxabi.h>
#endif #endif
#include "tracetools/utils.hpp" #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) #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; char * demangled = nullptr;
int status; 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 // 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; return demangled_val != 0 ? demangled_val : SYMBOL_UNKNOWN;
#else #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; return SYMBOL_UNKNOWN;
#endif #endif
} }

View file

@ -44,14 +44,11 @@ TEST(TestUtils, valid_address_symbol) {
// Function pointer // Function pointer
std::function<void(std::shared_ptr<int>)> f = &function_shared; std::function<void(std::shared_ptr<int>)> f = &function_shared;
// Address for one with an actual underlying function should be non-zero // 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(f), "function_shared(std::shared_ptr<int>)") <<
ASSERT_STREQ(get_symbol(get_address(f)), "function_shared(std::shared_ptr<int>)") <<
"invalid function name"; "invalid function name";
// Lambda // Lambda
std::function<int(int)> l = [](int num) {return num + 1;}; std::function<int(int)> 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 // TODO(christophebedard) check symbol
// Bind (to member function) // Bind (to member function)
@ -62,6 +59,5 @@ TEST(TestUtils, valid_address_symbol) {
std::placeholders::_1, std::placeholders::_1,
std::placeholders::_2 std::placeholders::_2
); );
ASSERT_EQ(get_address(fscwc), nullptr) << "get_address() for std::bind std::function not 0";
// TODO(christophebedard) check symbol // TODO(christophebedard) check symbol
} }