Linuxカーネルで関数のポインタから関数の名前を取得する方法は?

なぜ誰もがそれが不可能だと言うのか、私は驚いています。非静的関数については Linux で可能です。

これを達成する方法を少なくとも 2 つ知っています。

バックトレース印刷用の GNU 関数があります:backtrace()backtrace_symbols() (man を参照) )。あなたの場合、 backtrace() は必要ありません 既に関数ポインタがあるので、それを backtrace_symbols() に渡すだけです .

例 (作業コード):

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

gcc test.c -rdynamic でコンパイル

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

解析できるように、バイナリ名、関数名、関数の開始点からのポインター オフセット、およびポインター値が得られます。

別の方法は dladdr() を使用することです (別の拡張子) print_backtrace() だと思います dladdr() を使用 . dladdr() Dl_info を返します dli_sname に関数名を持つ構造体 分野。ここではコード例を提供しませんが、明らかです - man dladdr を参照してください 詳細はこちら

注意!どちらのアプローチも、関数が非静的である必要があります!

libdwarf を使用してデバッグ情報を使用する方法はもう 1 つあります。 しかし、これにはストリップされていないバイナリが必要であり、実行するのは簡単ではないため、お勧めしません.


追加の支援がなければ、それは直接不可能です。

次のことができます:

<オール> <リ>

関数ポインターを名前にマッピングするプログラム内のテーブルを維持します

<リ>

実行可能ファイルのシンボル テーブルがある場合は、それを調べます。

ただし、後者は難しく、移植性がありません。この方法は、オペレーティング システムのバイナリ形式 (ELF、a.out、.exe など) と、リンカーによって行われる再配置によって異なります。

編集:実際のユースケースが何であるかを説明したので、答えは実際にはそれほど難しくありません。カーネル シンボル テーブルは /proc/kallsyms で利用可能です にアクセスするための API があります:

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

単純なデバッグ目的では、後者はおそらく必要なことを正確に実行します-アドレスを取得し、フォーマットして、 printk に送信します 、または printk を使用できます %pF で フォーマット指定子。


Linux カーネルでは、"%pF" を直接使用できます。 printk のフォーマット !

void *func = &foo;
printk("func: %pF at address: %p\n", func, func);