2011-03-21 13 views
64

Próbuję wygenerować wykres wywołania, za pomocą którego można znaleźć wszystkie możliwe ścieżki wykonania, które trafiają w konkretną funkcję (tak, że nie muszę wymyślać wszystkich ścieżek ręcznie, jak istnieje wiele ścieżek, które prowadzą do tej funkcji). Na przykład:Generowanie wywoływania wykresu dla kodu C++

path 1: A -> B -> C -> D 
path 2: A -> B -> X -> Y -> D 
path 3: A -> G -> M -> N -> O -> P -> S -> D 
... 
path n: ... 

Próbowałem Codeviz i Doxygen, jakoś oba wyniki pokazują jedynie callees funkcji docelowej, D. W moim przypadku, D jest funkcja składowa klasy, której obiekt zostanie owinięty w ciągu inteligentny wskaźnik. Klienci zawsze otrzymają obiekt inteligentnego wskaźnika przez fabrykę, aby wywołać D.

Czy ktoś wie, jak to osiągnąć?

Odpowiedz

95
static void D() { } 
static void Y() { D(); } 
static void X() { Y(); } 
static void C() { D(); X(); } 
static void B() { C(); } 
static void S() { D(); } 
static void P() { S(); } 
static void O() { P(); } 
static void N() { O(); } 
static void M() { N(); } 
static void G() { M(); } 
static void A() { B(); G(); } 

int main() { 
    A(); 
} 

Następnie

$ clang++ -S -emit-llvm main1.cpp -o - | opt -analyze -dot-callgraph 
$ dot -Tpng -ocallgraph.png callgraph.dot 

oznacza pewną błyszczącą zdjęcie (tam jest „węzeł zewnętrzny”, ponieważ main ma zewnętrzne powiązania i może być wywołana z zewnątrz tej jednostki tłumaczeniowej zbyt):

Callgraph

Możesz chcieć przetworzyć ten proces za pomocą c++filt, aby uzyskać niezmienione nazwy zaangażowane funkcje i zajęcia. Podobnie jak w następujący

#include <vector> 

struct A { 
    A(int); 
    void f(); // not defined, prevents inlining it! 
}; 

int main() { 
    std::vector<A> v; 
    v.push_back(42); 
    v[0].f(); 
} 

$ clang++ -S -emit-llvm main1.cpp -o - | 
    opt -analyze -std-link-opts -dot-callgraph 
$ cat callgraph.dot | 
    c++filt | 
    sed 's,>,\\>,g; s,-\\>,->,g; s,<,\\<,g' | 
    gawk '/external node/{id=$1} $1 != id' | 
    dot -Tpng -ocallgraph.png  

Daje to piękno (oh my, wielkość bez optymalizacji włączona była zbyt duża!)

Beauty

To mistyczne nienazwany funkcja, Node0x884c4e0, jest symbolem zastępczym zakłada być wywołane przez jakąkolwiek funkcję, której definicja nie jest znana.

+17

Czy zrobić to na multi projektu pliku? wygląda bardzo fajnie jako narzędzie – dirvine

+0

Czy istnieje sposób, aby to zrobić, aby funkcje, które nie są lokalne dla pliku/plików, jak wszystkie funkcje std, które się nawzajem nie wywołują, nie są wywoływane? – soandos

+2

+1 Z jakiegoś powodu musiałem przekazać opcję -n do C++ filt dla nazw, które mają zostać usunięte. Pomyślałem, że wspomnę o tym tutaj na wypadek, gdyby ktoś inny stanął przed tym samym problemem. – Aky

3

Statyczne obliczanie dokładnego wykresu wywołania C++ jest trudne, ponieważ potrzebny jest precyzyjny analizator składni języka, poprawne wyszukiwanie nazw i dobry analizator punktów, który odpowiednio uwzględnia semantykę języka. Doxygen nie ma żadnego z nich, nie wiem, dlaczego ludzie twierdzą, że lubią to dla C++; łatwo jest skonstruować 10-wierszowy przykład C++, który Doxygen błędnie analizuje).

Być może lepiej będzie, jeśli uruchomisz timing profiler which collects a call graph dynamically (to opisuje naszą) i po prostu wykonujesz wiele zadań. Takie profilery pokazują aktualny wykres wywołań.

EDYCJA: Nagle przypomniałem sobie Understand for C++, który twierdzi, że tworzy wykresy połączeń. Nie wiem, czego używają dla parsera, ani czy wykonują szczegółową analizę; Nie mam konkretnego doświadczenia z ich produktem.

Jestem pod wrażeniem odpowiedzi Schauba, używając Clang; Spodziewałbym się, że Clang będzie miał wszystkie właściwe elementy.

+0

Niestety nie jestem świadomy wszystkich przypadków użycia, które mogą wywołać tę funkcję :(W rzeczywistości moim ostatecznym celem jest znalezienie dokładnej listy przypadków użycia, które wykorzystują tę funkcję do celów debugowania.Mogę znaleźć bezpośrednich dzwoniących za pomocą narzędzia do indeksowania kodu, ale muszę znaleźć wszystkie ścieżki wykonania do dalszej analizy. – shiouming

3

Aby komenda clang++ wybrać standardowe pliki nagłówkowe jak mpi.h dwóch dodatkowych opcji należy stosować -### -fsyntax-only, czyli pełne polecenie powinno wyglądać tak:

clang++ -### -fsyntax-only -S -emit-llvm main1.cpp -o - | opt -analyze -dot-callgraph 
1

„C++ Bsc Analyzer” może wyświetlać wykresy zadzwonić - czytając plik wygenerowany przez narzędzie bscmake.

11

Można to osiągnąć za pomocą doxygen (z opcją użycia kropki do generowania wykresów).

enter image description here

Johannes Schaub - litb main.cpp, generuje to:

enter image description here

doxygen/kropka są prawdopodobnie łatwiejsze niż dzyń/opt do zainstalowania i uruchomienia. Nie udało mi się zainstalować go samodzielnie i dlatego próbowałem znaleźć alternatywne rozwiązanie!

+1

Czy możesz dodać przykład, jak uruchomić doxygen, aby uzyskać dołączone okno? –

+0

@nimble_ninja: Czy zrzut ekranu z okna dialogowego doxywizard nie jest wystarczający? – jpo38

+0

Nie wiedziałem, że to z doxywizard. Dzięki! –

3

Można użyć CppDepend, może on generuje wiele rodzajów wykresów

  • Zależność Graph
  • połączeń Graph
  • dziedziczenia klas Graph
  • Sprzęgło Graph
  • Ścieżka Graph
  • wszystkie ścieżki Wykres
  • Wykres cyklu

enter image description here