3

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)?

5
  • 1
    stackoverflow.com/questions/351134/… Commented Nov 20, 2016 at 17:06
  • 1
    You tagged c++, why not use a map<string, func_pointer>? Commented Nov 20, 2016 at 17:06
  • 2
    Variable/functions names are lost during compilation. They are just around to help the programmer. Commented Nov 20, 2016 at 17:07
  • It is C++. Sorry for not seeing previous post on this problem. Yes, having a map structure seems a brilliant idea : ) Commented Nov 20, 2016 at 17:09
  • 2
    @alk: Function names may hang around in the executable. It depends if it has symbols or not. Access to those symbols is very platform specific though. Commented Nov 20, 2016 at 17:11

5 Answers 5

13

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Nitting: You better capitalise the macro.
5

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;

1 Comment

To make this work, I had to pass these two options to gcc/g++ during the linking phase: -Wl,--gc-keep-exported and -Wl,--export-dynamic. Without these options, dladdr() returns a null pointer for info.dli_sname when &test_fcn is NOT an address within a shared object library.
1

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}
};

2 Comments

What does "artsy" mean here?
Yeah, I got one of those!
1

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.

Comments

0

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.

2 Comments

void *function_ptr; is always an error. You must not mix data pointers and function pointers.
@BodoThiesen ah you're right; removing the C portion of my answer regardless as he said that he was working strictly with C++

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.