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 <functional>
#define SYMBOL_UNKNOWN "UNKNOWN"
const char * _demangle_symbol(const char * mangled);
const char * _get_symbol_funcptr(void * funcptr);
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...);
fnType ** fnPointer = f.template target<fnType *>();
// Might be a lambda
if (fnPointer == nullptr) {
return 0;
}
return reinterpret_cast<void *>(*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<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_

View file

@ -12,38 +12,37 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <iostream>
#if defined(TRACETOOLS_LTTNG_ENABLED) && !defined(_WIN32)
#include <dlfcn.h>
#include <cxxabi.h>
#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
}

View file

@ -44,14 +44,11 @@ TEST(TestUtils, valid_address_symbol) {
// Function pointer
std::function<void(std::shared_ptr<int>)> 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<int>)") <<
ASSERT_STREQ(get_symbol(f), "function_shared(std::shared_ptr<int>)") <<
"invalid function name";
// Lambda
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
// 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
}