Подтвердить что ты не робот

Как получить имя функции из указателя функции в ядре Linux?

Как получить имя функции из указатель функции в C?

Изменить: реальный случай: я пишу модуль ядра Linux, и я вызываю функции ядра. Некоторые из этих функций являются указателями, и я хочу проверить код этой функции в источнике ядра. Но я не знаю, на какую функцию он указывает. Я думал, что это можно сделать, потому что, когда система выходит из строя (паника ядра), она выводит на экран текущий столбец с именами функций. Но, я думаю, я ошибся... я?

4b9b3361

Ответ 1

Это невозможно напрямую без дополнительной помощи.

Вы могли бы:

  1. поддерживать таблицу в вашей программе, отображающую указатели на имена

  2. проверить таблицу исполняемых символов, если она есть.

Последний, однако, сложен и не переносим. Метод будет зависеть от двоичного формата операционной системы (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.

Ответ 2

Я удивлен, почему все говорят, что это невозможно. Это возможно для Linux для нестатических функций.

Я знаю, по крайней мере, два способа добиться этого.

Существуют функции GNU для печати backtrace: 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 для деталей.

NB! Оба подхода требуют, чтобы функция была нестатической!

Ну, есть еще один способ - использовать отладочную информацию с помощью libdwarf, но для этого потребуется нерасширенный двоичный код и не очень легко сделать это, я не рекомендую его.

Ответ 3

В ядре Linux вы можете напрямую использовать формат "% pF" printk!

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

Ответ 4

В Linux работает следующее:

  • printf адрес функции с помощью %p
  • Затем выполните nm <program_path> | grep <address> (без префикса 0x)
  • Он должен показать вам имя функции.

Он работает, только если рассматриваемая функция находится в одной и той же программе (не в динамически связанной библиотеке или что-то в этом роде).

Если вы можете узнать адреса загрузки загруженных разделяемых библиотек, вы можете вычесть адрес из напечатанного номера и использовать nm в библиотеке, чтобы узнать имя функции.

Ответ 5

Вы не можете по-разному, но вы можете реализовать другой подход к этой проблеме, если хотите. Вы можете сделать указатель структуры, вместо этого указывая на функцию, а также на описательную строку, которую вы можете установить, как хотите. Я также добавил отладочную posebilety, так как вы, вероятно, не хотите, чтобы эти vars были напечатаны навсегда.

// 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

Ответ 6

Если список функций, на которые можно обратить внимание, не слишком велик или если вы уже подозреваете о небольшой группе функций, вы можете распечатать адреса и сравнить их с тем, который использовался во время выполнения. Пример:

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

Вывод:

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

Этот подход будет работать и для статических функций.

Ответ 7

Нет способа, как это сделать вообще.

Если вы скомпилируете соответствующий код в библиотеку DLL/Shared Library, вы сможете заручиться всеми точками входа и сравнить с указателем, который у вас есть. Еще не пробовал, но у меня есть некоторый опыт работы с DLL/Shared Libs и ожидал, что он сработает. Это может быть даже реализовано для работы с перекрестными формами.

Кто-то еще упомянул, что для компиляции с отладочными символами, вы можете попытаться найти способ проанализировать их из запущенного приложения, аналогично тому, что сделает отладчик. Но это абсолютно проприетарный и не переносимый.

Ответ 8

  • Используйте kallsyms_lookup_name(), чтобы найти адрес kallsyms_lookup.

  • Используйте указатель функции, который указывает на kallsyms_lookup, чтобы вызвать его.

Ответ 9

Отметьте визуальный детектор утечки, чтобы увидеть, как они получают свою печать столбика. Это предполагает, что вы используете Windows.

Ответ 10

Не совсем то, о чем спрашивает вопрос, но после прочтения ответов здесь Я думаю об этом решении моей аналогичной проблемы:

/**
* 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")

Если вашей программе это очень нужно, вы можете определить имена методов вместе со строкой в XMacro и использовать #define X(name, str) ... #undef X в коде, чтобы получить соответствующую строку из имени функции.

Ответ 11

Вы не можете. Имя функции не привязывается к функции к моменту ее компиляции и привязки. Все это по адресу памяти в этой точке, а не по имени.

Ответ 12

Ты не знаешь, как выглядишь без отражающего зеркала. Вам нужно будет использовать язык, способный отражать, например С#.