Reputation: 565
I have a function class method, ValueHolder::printValue
class ValueHolder {
public:
void printValue ();
} ;
How do I determine its mangled name at compile time (or runtime).
For instance I would like to do this:
const char *mangled_name = GetMangledNameOfSymbol(&ValueHolder::printValue);
This function might return a string like:
"_ZN11ValueHolder10printValueEv"
As per @Marco A. A prerequisite is a modern compiler. One that supports typeid, and with flags turned on to enable this feature.
I will also accept an answer which can work in practicality for Gcc & Clang, and a stub for MSVC.
Upvotes: 25
Views: 10538
Reputation: 5233
At the runtime for windows platform in theory it's possible to use dbghelp.h/lib
winapi get the mangled name from a function's address
DWORD options = SymGetOptions();
SymSetOptions(options & ~SYMOPT_UNDNAME);
if (SymFromAddr(hProcess, dwAddress, &dwDisplacement, pSymbol))
{
// etc...
}
SymSetOptions(options);
This would resolve mangled function name at runtime.
But the symbol MUST be exported (using __declspec(dllexport)
)
Upvotes: 1
Reputation: 565
I'll add an answer, but I'm not going to mark it correct. It is not complete. Too big to add as a comment. This is something along the lines which I can do, but I'm looking for a better way. And, yes, very tacky-hacky. But I figure there is some API somewhere which, although still will be a bit gross, will be guaranteed to work (if using a single compiler throughout a project).
template<typename R, typename C, typename... A>
struct MemberFunctionPointer
{
typedef R Return;
typedef C Class;
};
template<typename R, typename C, typename... A>
constexpr auto inferMemberFunctionPointer(R (C::*method)(A...))
{
return MemberFunctionPointer<R,C,A...>{};
}
template<typename M, M m, typename... A>
class GenerateMethodSignature
{
typedef typename decltype(inferMemberFunctionPointer(m))::Class T;
typedef typename decltype(inferMemberFunctionPointer(m))::Return R;
public:
static const char *mangledName (const char *fs)
{
const char *ts = typeid(T).name();
const char *rs = typeid(R).name();
const char *ms = typeid(M).name();
std::string r = "_Z";
if (ts[0] != 'N')
r += "N";
r += ts;
if (ts[0] == 'N')
r.pop_back();
r += std::to_string(strlen(fs));
r += fs;
r += "E";
r += ms + strlen ("M") + strlen(ts) + strlen ("F") + strlen(rs);
r.pop_back();
printf("calculated signature %s\n", r.c_str());
// this is very bad but... for demonstration purposes
return strdup(r.c_str());
}
} ;
namespace MyNamespace {
namespace MySubNamespace {
class MyClass
{
public:
int MyFunction (int myarg);
} ;
} // namespace
} // namespace
#define ExportSignature(T, M) GenerateMethodSignature<decltype(&T::M), &T::M>::mangledName(#M)
const char *myMethodSignature = ExportSignature(MyNamespace::MySubNamespace::MyClass, MyFunction);
Upvotes: 5
Reputation: 43662
There's no standard way of doing this, according to [lib.type.info]
The class type_info describes type information generated by the implementation. Objects of this class effectively store a pointer to a name for the type, and an encoded value suitable for comparing two types for equality or collating order. The names, encoding rule, and collating sequence for types are all unspecified and may differ between programs.
and to your compiler implementation you could use typeid(type/expression).name()
but it is nowhere specified or enforced that this name will be decorated (it is implementation-defined). It also depends on the compilation flags used (thanks malat).
Example:
class ValueHolder {
public:
void printValue();
};
int main() {
std::cout << typeid(&ValueHolder::printValue).name();
}
gcc7.0
M11ValueHolderFvvE
clang4.0
M11ValueHolderFvvE
MSVC14
void (__cdecl ValueHolder::*)(void) __ptr64
Upvotes: 12
Reputation: 92
Well what you can do is compile your C++ program using g++ and get the .o file. Run the 'nm' command on the .o file thus obtained to get the mangled names! This method is viable on Linux systems.
Upvotes: 2