Tools zum Abrufen eines Bildfunktionsaufrufgraphen des Codes [geschlossen]


106

Ich habe einen großen Arbeitsbereich mit vielen Quelldateien von C-Code. Obwohl ich die von einer Funktion in MS VS2005 mit dem Objektbrowser und auch in MSVC 6.0 aufgerufenen Funktionen sehen kann, werden hier nur Funktionen angezeigt, die von einer bestimmten Funktion in einer nicht grafischen Anzeige aufgerufen wurden. Außerdem wird die aufgerufene Funktion nicht angezeigt, beginnend mit say main(), und dann die von ihr aufgerufenen Funktionen usw., die sich tiefer in der Funktion auf Blattebene befinden.

Ich brauche ein Werkzeug , das mir einen Funktionsaufruf Graph bildhaft mit Funktionen geben wird calleeund callerdurch die Pfeile oder ähnliches verbunden, ausgehend main()bis zur letzten Stufe der Funktion oder zumindest bildlich einen Aufrufgraphen aller Funktionen in einer C - Quelldatei zeigen. Es wäre toll, wenn ich diese Grafik drucken könnte.

Irgendwelche guten Werkzeuge, um das zu tun (müssen keine freien Werkzeuge sein)?


Antworten:



29

Dynamische Analysemethoden

Hier beschreibe ich einige dynamische Analysemethoden.

Dynamische Methoden führen das Programm tatsächlich aus, um das Aufrufdiagramm zu bestimmen.

Das Gegenteil von dynamischen Methoden sind statische Methoden, die versuchen, sie allein aus der Quelle zu ermitteln, ohne das Programm auszuführen.

Vorteile dynamischer Methoden:

  • fängt Funktionszeiger und virtuelle C ++ - Aufrufe ab. Diese sind in jeder nicht trivialen Software in großer Anzahl vorhanden.

Nachteile dynamischer Methoden:

  • Sie müssen das Programm ausführen, das möglicherweise langsam ist oder ein Setup erfordert, das Sie nicht haben, z. B. Cross-Compilation
  • Es werden nur Funktionen angezeigt, die tatsächlich aufgerufen wurden. Beispielsweise können einige Funktionen abhängig von den Befehlszeilenargumenten aufgerufen werden oder nicht.

KcacheGrind

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

Testprogramm:

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

Verwendung:

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

Sie befinden sich jetzt in einem fantastischen GUI-Programm, das viele interessante Leistungsdaten enthält.

Wählen Sie unten rechts die Registerkarte "Anrufdiagramm". Dies zeigt ein interaktives Anrufdiagramm, das mit Leistungsmetriken in anderen Fenstern korreliert, wenn Sie auf die Funktionen klicken.

Um das Diagramm zu exportieren, klicken Sie mit der rechten Maustaste darauf und wählen Sie "Diagramm exportieren". Das exportierte PNG sieht folgendermaßen aus:

Daraus können wir das ersehen:

  • Der Wurzelknoten _startist der eigentliche ELF-Einstiegspunkt und enthält das Glibc-Initialisierungs-Boilerplate
  • f0, f1Und f2wie erwartet voneinander genannt
  • pointedwird auch gezeigt, obwohl wir es mit einem Funktionszeiger aufgerufen haben. Es wurde möglicherweise nicht aufgerufen, wenn wir ein Befehlszeilenargument übergeben hätten.
  • not_called wird nicht angezeigt, weil es im Lauf nicht aufgerufen wurde, weil wir kein zusätzliches Befehlszeilenargument übergeben haben.

Das Coole daran valgrindist, dass keine speziellen Kompilierungsoptionen erforderlich sind.

Daher können Sie es auch dann verwenden, wenn Sie nicht über den Quellcode, sondern nur über die ausführbare Datei verfügen.

valgrindDies gelingt Ihnen, indem Sie Ihren Code über eine einfache "virtuelle Maschine" ausführen. Dies macht die Ausführung im Vergleich zur nativen Ausführung extrem langsam.

Wie in der Grafik zu sehen ist, werden auch Zeitinformationen zu jedem Funktionsaufruf abgerufen. Diese können verwendet werden, um das Programm zu profilieren, was wahrscheinlich der ursprüngliche Anwendungsfall dieses Setups ist, und nicht nur, um Aufrufdiagramme anzuzeigen: Wie kann ich ein Profil erstellen? C ++ - Code unter Linux?

Getestet unter Ubuntu 18.04.

gcc -finstrument-functions + etrace

https://github.com/elcritch/etrace

-finstrument-functions Fügt Rückrufe hinzu , etrace analysiert die ELF-Datei und implementiert alle Rückrufe.

Ich konnte es jedoch leider nicht zum Laufen bringen : Warum funktionieren `-finstrument-Funktionen` bei mir nicht?

Die behauptete Ausgabe hat das 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

Wahrscheinlich die effizienteste Methode neben der Unterstützung spezifischer Hardware-Ablaufverfolgung, hat jedoch den Nachteil, dass Sie den Code neu kompilieren müssen.


2
Beachten Sie nur, dass das dynamische Aufrufdiagramm nur einen Programmlauf abdeckt.
Smwikipedia

1
@smwikipedia Ja, ich habe die Antwort aktualisiert, um das klarer zu machen
Ciro Santilli 法轮功 冠状 病 六四 事件 30



9

Unser DMS Software Reengineering Toolkit verfügt über eine statische Steuerung / Datenfluss- / Punkt-zu-Anruf-Diagrammanalyse , die auf große Systeme (~ ~ 25 Millionen Zeilen) von C-Code angewendet wurde, und hat solche Aufrufdiagramme erstellt, einschließlich Funktionen, die über Funktionszeiger aufgerufen werden .


1
Ah, schön, es ist 2016 und jetzt taucht ein Downvoter auf. Ich bin sicher, dass seine Ablehnung auf einer genauen Einschätzung beruhte, dass dieses Tool dies nicht kann. Na ja, vielleicht auch nicht. Es macht sicher, was OP angefordert hat.
Ira Baxter

1
Nehmen Sie eine Gegenstimme, um dem entgegenzuwirken. Es ist mir
egal, ob


5

Sie können meinen Bash-basierten C-Call-Tree-Generator hier ansehen . Hier können Sie eine oder mehrere C-Funktionen angeben, für die Sie Anrufer- und / oder angerufene Informationen benötigen, oder Sie können eine Reihe von Funktionen angeben und das Erreichbarkeitsdiagramm der Funktionsaufrufe bestimmen, die sie verbinden. ), foo () und bar () sind verbunden. Es verwendet graphviz / dot für eine Grafik-Engine.


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.