Outils pour obtenir un graphe d’appel de fonction picturale de code [fermé]


107

J'ai un grand espace de travail qui contient de nombreux fichiers source de code C. Bien que je puisse voir les fonctions appelées à partir d'une fonction dans MS VS2005 à l'aide du navigateur d'objets, et également dans MSVC 6.0, cela ne montre que les fonctions appelées à partir d'une fonction particulière dans un type d'affichage non graphique. De plus, il n'affiche pas la fonction appelée à partir de say main(), puis les fonctions appelées à partir de celle-ci, et ainsi de suite, plus profondément à l'intérieur de la fonction de niveau feuille.

J'ai besoin d'un outil qui me donnera un graphe d'appel de fonction en image avec des fonctions calleeet callerconnecté par des flèches ou quelque chose comme ça, en commençant par main()le dernier niveau de fonction, ou au moins en montrant un graphe d'appel de toutes les fonctions dans un fichier source C en image. Ce serait formidable si je pouvais imprimer ce graphique.

Y a-t-il de bons outils pour faire cela (ne doivent pas être des outils gratuits)?


Réponses:



29

Méthodes d'analyse dynamique

Je décris ici quelques méthodes d'analyse dynamique.

Les méthodes dynamiques exécutent en fait le programme pour déterminer le graphe d'appel.

Le contraire des méthodes dynamiques sont les méthodes statiques, qui tentent de le déterminer à partir de la source seule sans exécuter le programme.

Avantages des méthodes dynamiques:

  • attrape les pointeurs de fonction et les appels virtuels C ++. Ceux-ci sont présents en grand nombre dans tout logiciel non trivial.

Inconvénients des méthodes dynamiques:

  • vous devez exécuter le programme, ce qui peut être lent, ou nécessiter une configuration que vous n'avez pas, par exemple une compilation croisée
  • seules les fonctions qui ont été réellement appelées s'affichent. Par exemple, certaines fonctions peuvent être appelées ou non en fonction des arguments de la ligne de commande.

KcacheGrind

https://kcachegrind.github.io/html/Home.html

Programme de test:

int f2(int i) { return i + 2; }
int f1(int i) { return f2(2) + i + 1; }
int f0(int i) { return f1(1) + f2(2); }
int pointed(int i) { return i; }
int not_called(int i) { return 0; }

int main(int argc, char **argv) {
    int (*f)(int);
    f0(1);
    f1(1);
    f = pointed;
    if (argc == 1)
        f(1);
    if (argc == 2)
        not_called(1);
    return 0;
}

Usage:

sudo apt-get install -y kcachegrind valgrind

# Compile the program as usual, no special flags.
gcc -ggdb3 -O0 -o main -std=c99 main.c

# Generate a callgrind.out.<PID> file.
valgrind --tool=callgrind ./main

# Open a GUI tool to visualize callgrind data.
kcachegrind callgrind.out.1234

Vous êtes maintenant laissé dans un programme GUI génial qui contient beaucoup de données de performances intéressantes.

En bas à droite, sélectionnez l'onglet "Graphique d'appel". Cela affiche un graphique d'appel interactif qui correspond aux mesures de performances dans d'autres fenêtres lorsque vous cliquez sur les fonctions.

Pour exporter le graphique, cliquez dessus avec le bouton droit de la souris et sélectionnez "Exporter le graphique". Le PNG exporté ressemble à ceci:

À partir de là, nous pouvons voir que:

  • le nœud racine est _start, qui est le point d'entrée ELF réel, et contient le passe-partout d'initialisation de la glibc
  • f0, f1et f2sont appelés comme attendu l'un de l'autre
  • pointedest également affiché, même si nous l'avons appelé avec un pointeur de fonction. Il n'aurait peut-être pas été appelé si nous avions passé un argument de ligne de commande.
  • not_called n'est pas affiché car il n'a pas été appelé lors de l'exécution, car nous n'avons pas passé d'argument de ligne de commande supplémentaire.

Ce qui est cool, valgrindc'est qu'il ne nécessite aucune option de compilation spéciale.

Par conséquent, vous pouvez l'utiliser même si vous n'avez pas le code source, seulement l'exécutable.

valgrindparvient à le faire en exécutant votre code via une "machine virtuelle" légère. Cela rend également l'exécution extrêmement lente par rapport à l'exécution native.

Comme on peut le voir sur le graphique, des informations de synchronisation sur chaque appel de fonction sont également obtenues, et cela peut être utilisé pour profiler le programme, ce qui est probablement le cas d'utilisation d'origine de cette configuration, pas seulement pour voir les graphiques d'appel: Comment puis-je profiler Code C ++ fonctionnant sous Linux?

Testé sur Ubuntu 18.04.

gcc -finstrument-functions + etrace

https://github.com/elcritch/etrace

-finstrument-functions ajoute des callbacks , etrace analyse le fichier ELF et implémente tous les callbacks.

Malheureusement, je n'ai pas pu le faire fonctionner: pourquoi `-finstrument-functions` ne fonctionne-t-il pas pour moi?

La sortie revendiquée est de format:

\-- main
|   \-- Crumble_make_apple_crumble
|   |   \-- Crumble_buy_stuff
|   |   |   \-- Crumble_buy
|   |   |   \-- Crumble_buy
|   |   |   \-- Crumble_buy
|   |   |   \-- Crumble_buy
|   |   |   \-- Crumble_buy
|   |   \-- Crumble_prepare_apples
|   |   |   \-- Crumble_skin_and_dice
|   |   \-- Crumble_mix
|   |   \-- Crumble_finalize
|   |   |   \-- Crumble_put
|   |   |   \-- Crumble_put
|   |   \-- Crumble_cook
|   |   |   \-- Crumble_put
|   |   |   \-- Crumble_bake

Probablement la méthode la plus efficace en plus de la prise en charge du traçage matériel spécifique, mais présente l'inconvénient de devoir recompiler le code.


2
Notez simplement que le graphe d'appel dynamique ne couvre qu'une seule exécution du programme.
smwikipedia

1
@smwikipedia oui, j'ai mis à jour la réponse pour rendre cela plus clair
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功



9

Notre boîte à outils de réingénierie logicielle DMS a une analyse statique de contrôle / flux de données / points à / appel qui a été appliquée à d'énormes systèmes (~~ 25 millions de lignes) de code C, et a produit de tels graphiques d'appel, y compris des fonctions appelées via des pointeurs de fonction .


1
Ah, bien, c'est 2016 et maintenant un downvoter se présente. Je suis sûr que son vote défavorable était basé sur une évaluation précise que cet outil ne peut pas faire cela. Eh bien, peut-être pas. Il fait certainement ce qu'OP a demandé.
Ira Baxter

1
Prenez un vote pour contrer cela. Je m'en fiche que ce soit votre logiciel ou propriétaire tant qu'il fait le travail :-)
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功


5

Vous pouvez consulter mon générateur d'arbre d'appels C basé sur bash ici . Il vous permet de spécifier une ou plusieurs fonctions C pour lesquelles vous voulez des informations sur l'appelant et / ou appelé, ou vous pouvez spécifier un ensemble de fonctions et déterminer le graphe d'accessibilité des appels de fonction qui les connecte ... Ie me dire toutes les manières principales ( ), foo () et bar () sont connectés. Il utilise graphviz / dot pour un moteur graphique.


En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.