web-dev-qa-db-fra.com

Outils pour obtenir un graphe d'appel de fonction graphique

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 ne montre pas la fonction appelée à partir de say main(), puis les fonctions appelées à partir de celle-ci, et ainsi de suite, plus en profondeur dans la fonction de niveau feuille.

J'ai besoin d'un outil qui me donnera un graphe d'appel de fonction de manière imagée avec les fonctions callee et caller reliées par des flèches ou quelque chose comme ça, en partant de main() jusqu'au dernier niveau de fonction, ou du moins en affichant un graphique d’appel de toutes les fonctions dans un fichier source C de manière imagée. Ce serait formidable si je pouvais imprimer ce graphique.

Tous les bons outils pour le faire (ne doivent pas être des outils gratuits)?

102
goldenmean
49
philant

Méthodes d'analyse dynamique

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

Les méthodes dynamiques exécutent réellement le programme pour déterminer le graphe d'appels.

L'opposé des méthodes dynamiques sont les méthodes statiques, qui tentent de le déterminer à partir du source uniquement sans exécuter le programme.

Avantages des méthodes dynamiques:

  • intercepte les pointeurs de fonction et les appels C++ virtuels. Celles-ci sont présentes 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. compilation croisée
  • seules les fonctions réellement appelées apparaîtront. 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 vous retrouvez maintenant dans un programme graphique impressionnant contenant de nombreuses données de performances intéressantes.

En bas à droite, sélectionnez l'onglet "Graphique des appels". Cela montre un graphe d'appels interactif qui est corrélé aux métriques de performance 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 fichier PNG exporté ressemble à ceci:

À partir de cela, 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 glibc
  • f0, f1 et f2 sont appelés comme prévu les uns des autres
  • pointed est é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.

La bonne chose à propos de valgrind est qu’il ne nécessite aucune option de compilation particulière.

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

valgrind réussit à faire cela en exécutant votre code via une "machine virtuelle" légère.

Testé sur Ubuntu 18.04.

gcc -finstrument-functions + etrace

https://github.com/elcritch/etrace

-finstrument-functionsajoute des rappels , etrace analyse le fichier ELF et implémente tous les rappels.

Malheureusement, je n’ai pas réussi à le faire fonctionner: Pourquoi est-ce que `-finstrument-functions` ne fonctionne 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 du support de traçage matériel spécifique, mais elle a l'inconvénient de recompiler le code.

Comprendre fait un très bon travail de création de graphes d’appel.

17
MattK

Notre boîte à outils DMS Software Reengineering Toolkit a contrôle de flux statique/données/analyse de points/point d'appel qui a été appliqué à d'énormes systèmes (~ 25 millions de lignes) de code C, et produit de tels graphes d’appel , y compris des fonctions appelées via des pointeurs de fonction .

8
Ira Baxter

Vous pouvez essayer CScope + tceetree + Graphviz .

6
Fabio Visona'

Vous pouvez consulter mon générateur d’arbre d’appel C basé sur bash ici . Il vous permet de spécifier une ou plusieurs fonctions C pour lesquelles vous souhaitez un appelant et/ou des informations appelées, ou vous pouvez spécifier un ensemble de fonctions et déterminer le graphe d'accessibilité des appels de fonction qui les connecte ... I.e. dites-moi tous les moyens de connexion entre main (), foo () et bar (). Il utilise graphviz/dot pour un moteur graphique.

5
Jason Nyberg

Astrée est l'outil le plus robuste et le plus sophistiqué du marché, à mon humble avis.

3
ЯegDwight