Reputation: 19918
Let's say I have a C++ template function.
template <class T>
int foo(T& t) {
...
}
How can I calculate programmatically (not by using nm) the mangled name of a function?
Note, I am not interested in demangling. I am already familiar with the cxxabi header file that does the demangling.
Upvotes: 6
Views: 2024
Reputation: 157344
It's possible to do it with typeid
; the trick is to encode a pointer to the function into a type name by creating a type with a non-type template parameter whose value is the function pointer. For example:
template <class T> int foo(T&);
template <auto> struct IntegralConstant {};
std::cout << typeid(IntegralConstant<foo<int>>).name() << '\n';
This outputs 16IntegralConstantIXadL_Z3fooIiEiRT_EEE
, which when piped through c++filt -t
gives IntegralConstant<&(int foo<int>(int&))>
. The tricky bit is to isolate the symbol _Z3fooIiEiRT_
(demangling to int foo<int>(int&)
) from the full type name; this can be done by comparing the mangled type name to the equivalent when 0
is passed in place of the function pointer:
template <auto> struct IntegralConstant {};
template <auto& u> std::string mangledSymbolName() {
std::string null = typeid(IntegralConstant<0>).name();
std::string symbol = typeid(IntegralConstant<u>).name();
return symbol.substr(null.size() - 1, symbol.size() - null.size() - 2);
}
Example: https://gcc.godbolt.org/z/P3eaaYhv6
The magic constants 1
and 2
are dependent on the encodings in the C++ ABI of 0
, pointers to external symbols, and class templates; they'll also require adjustment if IntegralConstant
is placed in a namespace.
Upvotes: 6
Reputation: 1480
You could try getting the callstack and getting the function name from there like so:
#include <iostream>
#include <string>
#include <regex>
#include <execinfo.h>
std::string GetMangledSymbol(const std::string& str)
{
static const std::regex regex(R"((\([a-zA-Z0-9_+]*\)))");
std::smatch matches;
std::regex_search( str, matches, regex );
if( ! matches.empty() )
{
auto symbolName = matches[1].str().substr(1);
auto pos = symbolName.find_first_of('+');
if( pos == std::string::npos)
return symbolName;
symbolName.erase( pos );
return symbolName;
}
return {};
}
void printCurrentFunction()
{
void* array[50] = { nullptr };
char** strings = nullptr;
size_t size = backtrace(array, 50);
strings = backtrace_symbols(array, size);
std::cout << GetMangledSymbol(strings[1]) << std::endl;
free(strings);
}
template <class T>
int foo(T&) {
printCurrentFunction();
return 0;
}
int main()
{
int i = 2;
foo(i);
std::string k;
foo(k);
}
Tested on linux with gcc (needs -rdynamic flag).
Upvotes: -1