Bojian Zheng
Bojian Zheng

Reputation: 2797

How to convert a function pointer to function name?

I have an array of functions that have the same functionality:

func_pointer_t func_array[] = {func_1, func_2, func_3, ...};

I want to develop a program that traverses the array members and dumps the output to another .dat data file. The output should have the following format:

func_1 func_1_output
func_2 func_2_output
func_3 func_3_output
...

So my question is - when traversing through the array members, how could we let the program know which function name the function pointer is pointing to (e.g. func_array[0] is pointing to func_1)?

Upvotes: 3

Views: 13783

Answers (5)

Nicola Lissandrini
Nicola Lissandrini

Reputation: 365

There is a straightforward way in Linux using the DL library, if you have compiled your program with debug info. An example:

#include <iostream>
#include <dlfcn.h>

void test_fcn (int a, float b) {  }

int main () {
    Dl_info info;

    dladdr (reinterpret_cast<void *>(&test_fcn), &info);

    std::cout << info.dli_sname << std::endl;
}

info.dli_sname contains the (mangled) function name: _Z4test_fcnif in this case. You can also demangle the name:

#include <cxxabi.h>

...

std:: cout << abi::__cxa_demangle(info.dli_sname, NULL, NULL, NULL) << std::endl;

Upvotes: 5

backtrace_symbols_fd

This is not perfect, but maybe it indicates a path. Adapted from How to get function's name from function's pointer in Linux kernel?

main.cpp

#include <execinfo.h>
#include <stdio.h>
#include <unistd.h>

void foo(void) {
    printf("foo\n");
}

int main(int argc, char *argv[]) {
    void *funptr = &foo;
    backtrace_symbols_fd(&funptr, 1, STDOUT_FILENO);
    printf("%p\n", foo);
    return 0;
}

Compile and run:

g++ -std=c++11 main.cpp -rdynamic
./a.out 

Output:

./a.out(_Z3foov+0x0)[0x562ff384893a]
0x562ff384893a

So we see the mangled name of foo which is _Z3foov was output:

echo _Z3foov | c++filt

The downsides of this which I don't know how to solve are:

  • requires modifying build with -rdynamic, and therefore does not work with static linking and likely has other downsides
  • does not demangle automatically

But I do think that looking into backtrace mechanisms is a good bet, and I have investigated them further at: print call stack in C or C++

Maybe we can also get away with debug information: Programmatically get debug information that might actually be the most stable approach if it were possible. But no one knows how to do it currently.

Tested in Ubuntu 18.04, GCC 7.4.0.

Upvotes: 1

Guillaume Racicot
Guillaume Racicot

Reputation: 41750

You can simply keep track of the name by storing an array of pair that will match the function pointer with its name:

std::pair<const char*, func_pointer_t>[] func_array = {
    {"func_1", func_1},
    {"func_2", func_2},
    {"func_3", func_3}
};

You will now be able to use it's name too.

Is you want, you can even use a map:

std::map<std::string, func_ptr_t> func_array {
    {"func_1", func_1},
    {"func_2", func_2},
    {"func_3", func_3}
};

Upvotes: 1

Bodo Thiesen
Bodo Thiesen

Reputation: 2514

There is no standard way of archiving what you seek. All possible solutions either involve system dependent ways to resolve function addresses to their names (and even that does not necessarily always work) or changing the func_array like so:

struct {
    func_pointer_t func;
    const char * name;
} func_array[] = {
    { func_1, "func_1" },
    { func_2, "func_2" },
    { func_3, "func_3" },
    ...
};

you can use a macro, to ease the job:

#define FUNC_DEF(func) { func, #func },

and then use it like this:

struct {
    func_pointer_t func;
    const char * name;
} func_array[] = {
    FUNC_DEF(func_1)
    FUNC_DEF(func_2)
    FUNC_DEF(func_3)
    ...
};

So, if this is an option for you, you got your solution. If not, you gonna have to tell, what system you're targeting.

More C++ish solutions exist - like the std::map solutions hinted to by Govind Parmar where you could iterate and take the key <-> value pair.

Upvotes: 13

Govind Parmar
Govind Parmar

Reputation: 21532

You need to remember that at the assembly/machine code level there are no "function names" (unless you have debugging information in your build); there are only addresses that indicate where a function starts.

You will have to use a data structure to keep track of this stuff. If you're using C++, then use a map<string, function_pointer> as commenter @MyUsername112358 pointed out.

Upvotes: 0

Related Questions