65 votes

Comment obtenir le nom de la fonction à partir du pointeur de la fonction en C?

Comment obtenir le nom de la fonction à partir de la fonction de pointeur en C?

Edit: Le cas réel est: je suis en train d'écrire un module du noyau linux et je suis l'appel de fonctions du noyau. Certaines de ces fonctions sont des pointeurs et je veux inspecter le code de cette fonction dans le source du noyau. Mais je ne sais pas quelle fonction il pointe. J'ai pensé qu'il pourrait être fait, parce que, lorsque le système tombe en panne (kernel panic) il imprime à l'écran le courant de la pile avec la fonction de noms. Mais, je suppose que je me trompais... suis-je?

69voto

qrdl Points 17813

Je suis surpris de voir pourquoi tout le monde dit qu'il n'est pas possible. Il est possible sur Linux pour les non-statique fonctions.

Je connais au moins deux façons d'y parvenir.

Il y a GNU fonctions de trace d'impression: backtrace() et backtrace_symbols() (Voir man). Dans votre cas, vous n'avez pas besoin d' backtrace() que vous avez déjà pointeur de fonction, vous venez de passer à l' backtrace_symbols().

Exemple (code du travail):

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

Compiler avec gcc test.c -rdynamic

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

Il vous donne binaires nom, nom de fonction offset du pointeur de fonction et la valeur du pointeur de sorte que vous pouvez l'analyser.

Une autre façon est d'utiliser des dladdr() (un autre poste), je suppose print_backtrace() utilise dladdr(). dladdr() retours Dl_info de la structure qui a le nom de la fonction dli_sname champ. Je n'ai pas fournir le code exemple ici, mais il est évident - voir man dladdr pour plus de détails.

NB! Les deux approches nécessitent de la fonction non-statique!

Eh bien, il ya une façon de plus pour utiliser les informations de débogage à l'aide de libdwarf mais il faudrait des remontées binaire et pas très facile à faire, donc je ne le recommande pas.

35voto

Alnitak Points 143355

Ce n'est pas directement possible sans l'aide supplémentaire.

Vous pouvez:

  1. maintenir une table dans votre programme de cartographie des pointeurs de fonction, les noms

  2. examiner le fichier exécutable de la table de symbole, s'il en a un.

Ce dernier, cependant, est difficile, et n'est pas portable. La méthode dépend du système d'exploitation (format binaire ELF, une.hors, .exe, etc), et aussi sur toute réinstallation réalisé par l'éditeur de liens.

EDIT: Depuis que vous avez expliqué ce que votre réel de cas d'utilisation est, la réponse est en fait pas si difficile. Le noyau de la table des symboles est disponible en /proc/kallsyms, et il y a une API pour pouvoir y accéder:

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

Pour de simples fins de débogage ce dernier sera probablement exactement ce que vous avez besoin - il prend l'adresse, les formats, et l'envoie printk.

25voto

Zskdan Points 166

Dans le noyau Linux, vous pouvez utiliser directement le format "% pF" de printk!

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

7voto

Calmarius Points 2626

Les œuvres suivantes de moi sur Linux:

  • printf l'adresse de la fonction à l'aide d' %p
  • Ensuite faire un nm <program_path> | grep <address> (sans l' 0x préfixe)
  • Il devrait vous montrer le nom de la fonction.

Il ne fonctionne que si la fonction en question est dans le même programme (et non pas dans une bibliothèque liée dynamiquement ou quelque chose).

Si vous pouvez trouver les adresses de chargement du chargement des bibliothèques partagées, vous pouvez soustraire l'adresse à partir du numéro imprimé, et l'utilisation nm sur la bibliothèque pour trouver le nom de la fonction.

2voto

eaanon01 Points 681

Vous ne pouvez pas choisir, mais vous pouvez mettre en œuvre une approche différente de ce problème si vous le souhaitez. Vous pouvez créer un pointeur struct pointant vers une fonction ainsi qu'une chaîne descriptive que vous pouvez définir comme bon vous semble. J'ai également ajouté un point de débogage puisque vous ne voulez certainement pas que ces vars soient imprimés pour toujours.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X