66

How to get function's name from function's pointer in C?

Edit: The real case is: I'm writing a linux kernel module and I'm calling kernel functions. Some of these functions are pointers and I want to inspect the code of that function in the kernel source. But I don't know which function it is pointing to. I thought it could be done because, when the system fails (kernel panic) it prints out in the screen the current callstack with function's names. But, I guess I was wrong... am I?

pevik
  • 4,523
  • 3
  • 33
  • 44
Daniel Silveira
  • 41,125
  • 36
  • 100
  • 121
  • 1
    Perhaps if you explain why you need the function's name, someone could suggest an alternate way to get what you need. – Slapout Dec 08 '08 at 23:01
  • Something which is mentioned and not elaborated on is using debug symbols. However you get this to work the result is almost certainly going to be doing lookups into some source of debug symbols... as mentioned by one answer libdwarf is probably the way to go for linux kernelly things. – jheriko Jun 22 '12 at 14:21
  • C++ userland: https://stackoverflow.com/questions/40706805/how-to-convert-a-function-pointer-to-function-name/40706869 – Ciro Santilli OurBigBook.com Mar 02 '20 at 14:57

13 Answers13

69

I'm surprised why everybody says it is not possible. It is possible on Linux for non-static functions.

I know at least two ways to achieve this.

There are GNU functions for backtrace printing: backtrace() and backtrace_symbols() (See man). In your case you don't need backtrace() as you already have function pointer, you just pass it to backtrace_symbols().

Example (working code):

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

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

int main(int argc, char *argv[]) {
    void    *funptr = &foo;

    backtrace_symbols_fd(&funptr, 1, 1);

    return 0;
}

Compile with gcc test.c -rdynamic

Output: ./a.out(foo+0x0)[0x8048634]

It gives you binary name, function name, pointer offset from function start and pointer value so you can parse it.

Another way is to use dladdr() (another extension), I guess print_backtrace() uses dladdr(). dladdr() returns Dl_info structure that has function name in dli_sname field. I don't provide code example here but it is obvious - see man dladdr for details.

NB! Both approaches require function to be non-static!

Well, there is one more way - use debug information using libdwarf but it would require unstripped binary and not very easy to do so I don't recommend it.

qrdl
  • 34,062
  • 14
  • 56
  • 86
  • 1
    For the non-kernel case, the dladdr method should be the accepted answer. You should split it out from the backtrace stuff. – Todd Freed Oct 15 '16 at 20:13
36

That's not directly possible without additional assistance.

You could:

  1. maintain a table in your program mapping function pointers to names

  2. examine the executable's symbol table, if it has one.

The latter, however, is hard, and is not portable. The method will depend on the operating system's binary format (ELF, a.out, .exe, etc), and also on any relocation done by the linker.

EDIT: Since you've now explained what your real use case is, the answer is actually not that hard. The kernel symbol table is available in /proc/kallsyms, and there's an API for accessing it:

#include <linux/kallsyms.h>

const char *kallsyms_lookup(unsigned long addr, unsigned long *symbolsize,
                            unsigned long *ofset, char **modname, char *namebuf)

void print_symbol(const char *fmt, unsigned long addr)

For simple debug purposes the latter will probably do exactly what you need - it takes the address, formats it, and sends it to printk, or you can use printk with the %pF format specifier.

Alnitak
  • 334,560
  • 70
  • 407
  • 495
  • I don't think I can call kallsyms_lookup from a kernel module. When I compile, I get "kallsyms_lookup undefined" – Daniel Silveira Dec 09 '08 at 15:03
  • If you're getting a compile time error then you need to make sure that you've got the kernel headers available and in your include-path. – Alnitak Dec 09 '08 at 17:44
  • I'm getting a link time error. The headers are fine. #include – Daniel Silveira Dec 09 '08 at 18:24
  • ok, that suggests that your module compile stuff is wrong somewhere. Modules need to call symbols that are in the kernel, so by definition the symbol can't be resolved completely at link time. – Alnitak Dec 09 '08 at 19:30
  • p.s. sample Makefiles for compiling Linux kernel modules is probably a good candidate for another question. My reference stuff for this is at work where I can't get it at the moment. – Alnitak Dec 09 '08 at 19:35
  • look very far down at the answer of @Zskdan . `%pF` of `printk` is exactly what one is looking for! – Alexander Oh Jun 23 '14 at 12:05
26

In the Linux kernel, you can use directly "%pF" format of printk !

void *func = &foo;
printk("func: %pF at address: %p\n", func, func);
Zskdan
  • 799
  • 8
  • 17
7

The following works me on Linux:

  • printf the address of the function using %p
  • Then do an nm <program_path> | grep <address> (without the 0x prefix)
  • It should show you the function name.

It works only if the function in question is in the same program (not in a dynamically linked library or something).

If you can find out the load addresses of the loaded shared libraries, you can subtract the address from the printed number, and use nm on the library to find out the function name.

ideasman42
  • 42,413
  • 44
  • 197
  • 320
Calmarius
  • 18,570
  • 18
  • 110
  • 157
2

You can't diectly but you can implement a different approach to this problem if you want. You can make a struct pointer instead pointing to a function as well as a descriptive string you can set to whatever you want. I also added a debugging posebilety since you problably do not want these vars to be printet forever.

// Define it like this
typedef struct
{
  char        *dec_text;
  #ifdef _DEBUG_FUNC
  void        (*action)(char);
  #endif
} func_Struct;

// Initialize it like this
func_Struct func[3]= {
#ifdef _DEBUG_FUNC
{"my_Set(char input)",&my_Set}};
{"my_Get(char input)",&my_Get}};
{"my_Clr(char input)",&my_Clr}};
#else
{&my_Set}};
{&my_Get}};
{&my_Clr}};
#endif 

// And finally you can use it like this
func[0].action( 0x45 );
#ifdef _DEBUG_FUNC
printf("%s",func.dec_text);
#endif
eaanon01
  • 1,069
  • 7
  • 9
1

There is no way how to do it in general.

If you compile the corresponding code into a DLL/Shared Library, you should be able to enlist all entry points and compare with the pointer you've got. Haven't tried it yet, but I've got some experience with DLLs/Shared Libs and would expect it to work. This could even be implemented to work cross-plarform.

Someone else mentioned already to compile with debug symbols, then you could try to find a way to analyse these from the running application, similiar to what a debugger would do. But this is absolutely proprietary and not portable.

mh.
  • 650
  • 4
  • 8
1
  1. Use kallsyms_lookup_name() to find the address of kallsyms_lookup.

  2. Use a function pointer that points to kallsyms_lookup, to call it.

WindChaser
  • 960
  • 1
  • 10
  • 30
1

If the list of functions that can be pointed to is not too big or if you already suspect of a small group of functions you can print the addresses and compare them to the one used during execution. Ex:

typedef void (*simpleFP)();
typedef struct functionMETA {
    simpleFP funcPtr;
    char * funcName;
} functionMETA;

void f1() {/*do something*/}
void f2() {/*do something*/}
void f3() {/*do something*/}

int main()
{
    void (*funPointer)() = f2; // you ignore this
    funPointer(); // this is all you see

    printf("f1 %p\n", f1);
    printf("f2 %p\n", f2);
    printf("f3 %p\n", f3);

    printf("%p\n", funPointer);

    // if you want to print the name
    struct functionMETA arrFuncPtrs[3] = {{f1, "f1"}, {f2, "f2"} , {f3, "f3"}};

    int i;
    for(i=0; i<3; i++) {
        if( funPointer == arrFuncPtrs[i].funcPtr )
            printf("function name: %s\n", arrFuncPtrs[i].funcName);
    }
}

Output:

f1 0x40051b
f2 0x400521
f3 0x400527
0x400521
function name: f2

This approach will work for static functions too.

givanse
  • 14,503
  • 8
  • 51
  • 75
0

Check out Visual Leak Detector to see how they get their callstack printing working. This assumes you are using Windows, though.

Jim Buck
  • 20,482
  • 11
  • 57
  • 74
0

Alnitak's answer is very helpful to me when I was looking for a workaround to print out function's name in kernel module. But there is one thing I want to supplyment, which is that you might want to use %pS instead of %pF to print function's name, becasue %pF not works anymore at some newer verions of kernel, for example 5.10.x.

Rock Deng
  • 21
  • 2
-1

Not exactly what the question is asking for but after reading the answers here I though of this solution to a similar problem of mine:

/**
* search methods */
static int starts(const char *str, const char *c);
static int fuzzy(const char *str, const char *c);

int (*search_method)(const char *, const char *);

/* asign the search_method and do other stuff */
[...]

printf("The search method is %s\n", search_method == starts ? "starts" : "fuzzy")

If your program needs this a lot you could define the method names along with a string in an XMacro and use #define X(name, str) ... #undef X in the code to get the corresponding string from the function name.

The Gramm
  • 118
  • 2
  • 12
-5

You can't. The function name isn't attached to the function by the time it's compiled and linked. It's all by memory address at that point, not name.

sblundy
  • 60,628
  • 22
  • 121
  • 123
-6

You wouldn't know how you look like without a reflecting mirror. You'll have to use a reflection-capable language like C#.

yogman
  • 4,021
  • 4
  • 24
  • 27
  • 6
    Yea, sure. Write a linux kernel module in C#. I'm sure that works. – JesperE Dec 09 '08 at 08:34
  • You *can* do it in C. It just won't look as pretty as in most languages that do some compilation at runtime (and therefore need more data on the function calls). – yingted Mar 15 '12 at 21:57
  • i downvote because reflection is always a sledgehammer solution to problems. it enables nothing you can't do with pure C or assembler (by necessity of having to work on some machine this is fundamentally true). it has a convenience when it is there, but relying on it in general is bad practice. – jheriko Jun 22 '12 at 14:23