nom de variable, arguments de la fonction au moment de l’exécution en C

Est-il possible de connaître les arguments d’une fonction et les types de nom de variables au moment de l’exécution dans le programme C? Par exemple, si j’ai une fonction:

int abc(int x, float y , somestruct z ){ char a; int b ; } 

Puis-je savoir à l’intérieur de cette fonction abc() quels sont les noms des arguments et des variables, c’est- à- dire que c’est x , y , z , a , b et qu’ils sont de type int , float , somestruct , char , int .

Dites s’il y a une autre fonction:

 float some_func(specialstruct my_struct, int index){ } 

Je devrais savoir que les arguments name sont my_struct , index et les types sont specialstruct , int .

J’ai besoin de cette information au moment de l’exécution?

J’ai access au pointeur de base et à l’adresse de retour, puis-je obtenir les informations requirejses à l’aide du pointeur ci-dessus.

J’ai pu extraire le nom de la fonction en utilisant l’adresse de retour et la fonction dladdr() .

Je vois que GDB fait cela, donc il devrait être possible d’extraire cette information?

Si vous voulez une telle installation, vous devez concevoir des utilitaires, des macros à cet effet et utiliser des règles de codage spéciales pour obtenir l’effet souhaité. Mais IMO – ce ne sera pas un code C lisible et compréhensible.

Il n’y a pas vraiment de manière native de faire cela en C. Dans d’autres langues, ce que vous recherchez serait une reflection. Vous pouvez la manipuler avec des macros et quelques astuces, mais sur un principe de base, vous devez connaître les noms de variables et les arguments au moment de la compilation.

Il existe un moyen limité d’introspection fourni par les fonctions de bibliothèque partagée dlsym et dladdr fournissant une dladdr nom-adresse et vice-versa. Cela ne fait cependant pas partie du langage C, mais plutôt d’une fonction fournie par le chargeur dynamic du système d’exploitation. Cependant, vous ne pouvez pas déduire, par exemple, si le symbole que vous avez trouvé est une variable ou une fonction.

backtrace et autres constituent une extension GNU au standard permettant d’parsingr la stack d’appels d’une fonction (historique des appels). Si des symboles (noms de fonctions) sont encore présents dans le fichier binary, les symboles backtrace_symbols vous permettront de les récupérer.

Les macros prédéfinies __LINE__ et __FILE__ permettent de vider votre __FILE__ là où vous vous trouvez et peuvent servir de base à des macros très utiles pour le traçage.

Et c’est tout . C ne fournit pas plus d’introspection que cela. Les noms et types de parameters sont supprimés dans le binary, les signatures de fonctions et les types de résultats de fonctions également.

Comme d’autres l’ont noté, la reflection n’est pas intégrée au langage C ou C ++. Il y a une variété d’idées ici

Toutefois, la reflection est possible en C / C ++ avec une bibliothèque tierce et des symboles de débogage dans l’exécutable ou dans un fichier externe.

Le fichier exécutable dwarfdump plus ou moins ce que vous espérez. Avec le DWARF, des informations détaillées sur la fonction, les variables, les types, etc. sont disponibles. De la même manière, la fonctionnalité libdwarfdump pourrait être utilisée par un processus pour se contrôler.

Voici un exemple manuel simple:

 typedef struct somestruct { int i; int j; } somestruct ; int abc(int x, float y , struct somestruct z ){ char a; int b ; } int main(int argc, char* argv[]) { struct somestruct z; abc(1,1.0f,z); return 0; } 

et la sortie partielle de Dwarfdump

 < 1><0x00000055> DW_TAG_subprogram DW_AT_external yes(1) DW_AT_name "abc" DW_AT_decl_file 0x00000001 /tmp/dwarf.c DW_AT_decl_line 0x00000009 DW_AT_prototyped yes(1) DW_AT_type <0x0000004e> DW_AT_low_pc 0x004004ed DW_AT_high_pc 18 DW_AT_frame_base len 0x0001: 9c: DW_OP_call_frame_cfa DW_AT_GNU_all_call_sites yes(1) DW_AT_sibling <0x000000ad> < 2><0x00000076> DW_TAG_formal_parameter DW_AT_name "x" DW_AT_decl_file 0x00000001 /tmp/dwarf.c DW_AT_decl_line 0x00000009 DW_AT_type <0x0000004e> DW_AT_location len 0x0002: 916c: DW_OP_fbreg -20 < 2><0x00000082> DW_TAG_formal_parameter DW_AT_name "y" DW_AT_decl_file 0x00000001 /tmp/dwarf.c DW_AT_decl_line 0x00000009 DW_AT_type <0x000000ad> DW_AT_location len 0x0002: 9168: DW_OP_fbreg -24 < 2><0x0000008e> DW_TAG_formal_parameter DW_AT_name "z" DW_AT_decl_file 0x00000001 /tmp/dwarf.c DW_AT_decl_line 0x00000009 DW_AT_type <0x0000002d> DW_AT_location len 0x0002: 9160: DW_OP_fbreg -32 

Avec une étude attentive, nous pouvons voir que le fragment définit la fonction ‘abc’ avec les arguments x, y et z.

Le type de paramètre x est une indirection vers une table de types avec la clé 0x4e.

En regardant ailleurs dans la sortie, nous pouvons voir la définition du type 0x4e. Le type 0x2d est le somestruct qui est lié au paramètre z.

 < 1><0x0000002d> DW_TAG_structure_type DW_AT_name "somestruct" DW_AT_byte_size 0x00000008 DW_AT_decl_file 0x00000001 /tmp/dwarf.c DW_AT_decl_line 0x00000003 DW_AT_sibling <0x0000004e> < 1><0x0000004e> DW_TAG_base_type DW_AT_byte_size 0x00000004 DW_AT_encoding DW_ATE_signed DW_AT_name "int" 

La combinaison de ptrace, ELF, DWARF et du système de fichiers / proc permet à gdb de lire des informations statiques et dynamics pour un processus. Un autre processus pourrait utiliser une fonctionnalité similaire pour créer une fonctionnalité de reflection.

J’ai utilisé des variantes de cette stratégie pour créer des débogueurs et des détecteurs de fuite de mémoire personnalisés. Je n’ai toutefois jamais vu cette stratégie utilisée pour la logique métier.