iamacomputer
iamacomputer

Reputation: 565

get a c++ function mangled name at compile time (or runtime)

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

Answers (4)

TarmoPikaro
TarmoPikaro

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

iamacomputer
iamacomputer

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

Marco A.
Marco A.

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

Nishant Bhattacharya
Nishant Bhattacharya

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

Related Questions