Как получить имя функции из указателя функции в ядре Linux?
Как получить имя функции из указатель функции в C?
Изменить: реальный случай: я пишу модуль ядра Linux, и я вызываю функции ядра. Некоторые из этих функций являются указателями, и я хочу проверить код этой функции в источнике ядра. Но я не знаю, на какую функцию он указывает. Я думал, что это можно сделать, потому что, когда система выходит из строя (паника ядра), она выводит на экран текущий столбец с именами функций. Но, я думаю, я ошибся... я?
Ответы
Ответ 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
.
Ответ 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
Ты не знаешь, как выглядишь без отражающего зеркала. Вам нужно будет использовать язык, способный отражать, например С#.