Pobieranie wykresu przepływu sterowania z kodu ANSI C
Buduję narzędzie do testowania aplikacji ansi C. Wystarczy załadować kod, wyświetlić wykres przepływu sterowania, uruchomić test, zaznaczyć wszystkie wierzchołki, które zostały trafione. Próbuję zbudować CFG sam z parsowania kodu. Niestety, jeśli kod jest zagnieżdżony, to się psuje. GCC daje możliwość pobierania CFG ze skompilowanego kodu. Mogę napisać parser dla jego wyjścia, ale potrzebuję numerów linii do ustawiania punktów przerwania. Czy istnieje sposób na uzyskanie numerów linii podczas wyprowadzania wykresu przepływu sterowania za pomocą -fdump-tree-cfg
lub -fdump-tree-vcg
?
3 answers
Dla wykresu przepływu sterowania programu C można spojrzeć na istniejące parsery Pythona dla C:
- PyCParser
- pycparser
- pyclibrary (fork of pyclibrary )
- joern
- CoFlo C / C++ control flow graph generator and analyzer
Wykresy Wywołania są ściśle powiązane z wykresami przepływu sterowania. Istnieje kilka metod tworzenia wykresów połączeń (zależności funkcyjne) dla kodu C. Może to okazać się pomocne w postępie z generowaniem wykresu przepływu sterowania. Sposoby tworzenia wykresów zależności W C:
-
Za pomocą cflow :
- cflow +pycflow2dot +Dot (GPL, BSD) cflow jest solidny, ponieważ potrafi obsługiwać kod, który nie może się skompilować, np. brakujące includes. Jeśli dyrektywy preprocesora są często używane, może być potrzebna opcja
--cpp
do wstępnego przetworzenia kodu. - cflow + cflow2dot + DOT (GPL v2, GPL v3, Eclipse Public License (EPL) v1) (zauważ, że cflow2dot wymaga poprawienia ścieżki zanim zadziała)
- cflow +cflow2dot.bash (GPL v2,?)
- cflow +cflow2vcg (GPL v2, GPL v2)
- enhanced cflow (GPL v2) with list to exclude symbols from graph
- cflow +pycflow2dot +Dot (GPL, BSD) cflow jest solidny, ponieważ potrafi obsługiwać kod, który nie może się skompilować, np. brakujące includes. Jeśli dyrektywy preprocesora są często używane, może być potrzebna opcja
-
Używając cscope :
- cscope (BSD)
- cscope +callgraphviz + dot + xdot
- cscope +vim CCTree (C Call-Tree Explorer)
- cscope +ccglue
- cscope +CodeQuery for C, C++, Python & Java
- cscope + Python html producer
- cscope + calltree.sh
-
Ncc (cflow like)
- KCachegrind (przeglądarka zależności KDE)
- Calltree
Następujące narzędzia niestety wymagają, aby kod może być kompilowany, ponieważ zależy od wyjścia z gcc:
- [118]} CodeViz (GPL v2) (słaby punkt: potrzebuje kompilowalnego źródła, ponieważ używa gcc do zrzutu plików cdepn)
-
gcc +egypt +dot (GPL v*, Perl = GPL / Artistic license, EPL v1) (
egypt
używa {[2] } do produkcjiRTL
, więc nie działa na żaden błędny kod źródłowy, a nawet jeśli chcesz skupić się na pojedynczym pliku z większego projektu. Dlatego nie jest to bardzo przydatne w porównaniu z bardziej solidne łańcuchy narzędzi oparte nacflow
. Zauważ, że Egipt ma domyślnie dobrą obsługę wyłączania wywołań bibliotek z wykresu, aby uczynić go czystszym.
Również wykresy zależności plików dla C / C++ mogą być tworzone za pomocą crowfood
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-03 19:40:50
Więc zrobiłem trochę więcej badań i nie jest trudno uzyskać numery linii dla węzłów. Wystarczy dodać opcję lineno
do jednej z tych opcji, aby ją uzyskać. Więc użyj -fdump-tree-cfg-lineno
lub -fdump-tree-vcg-lineno
. Zajęło mi trochę czasu, aby sprawdzić, czy te liczby są wiarygodne . W przypadku wykresu w formacie VCG Etykieta każdego węzła zawiera dwie liczby. Są to numery linii dla początku i końca części kodu reprezentowanej przez ten węzeł.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-09 06:15:52
Metody analizy dynamicznej
W tej odpowiedzi opiszę kilka metod analizy dynamicznej.
Dynamiczne metody uruchamiają program w celu określenia wykresu wywołania.
Przeciwieństwem metod dynamicznych są metody statyczne, które próbują określić je z samego źródła bez uruchamiania programu.
Zalety metod dynamicznych:
- łapie Wskaźniki funkcji i wirtualne wywołania C++. Są one obecne w dużych ilościach w każdym nietrywialne oprogramowanie.
Wady metod dynamicznych:
- musisz uruchomić program, który może być powolny lub wymagać konfiguracji, której nie masz, np. cross-compilation
- pokażą się tylko funkcje, które zostały faktycznie wywołane. Na przykład, niektóre funkcje mogą być wywoływane lub nie w zależności od argumentów wiersza poleceń.
KcacheGrind
Https://kcachegrind.github.io/html/Home.html
Test program:
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;
}
Użycie:
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
Zostajesz teraz w niesamowitym programie graficznym, który zawiera wiele interesujących danych o wydajności.
W prawym dolnym rogu wybierz zakładkę "Call graph". To pokazuje interaktywny wykres połączeń, który koreluje z metrykami wydajności w innych oknach podczas klikania funkcji.
Aby wyeksportować Wykres, kliknij go prawym przyciskiem myszy i wybierz "Eksportuj Wykres". Wyeksportowany PNG wygląda jak to:
Z tego widać, że:
- Jest to węzeł główny
- , który jest faktycznym punktem wejścia ELF i zawiera kocioł inicjalizacji glibc
-
f0
,f1
if2
są wywoływane zgodnie z oczekiwaniami od siebie -
pointed
jest również pokazana, mimo że nazwaliśmy ją wskaźnikiem funkcji. Może nie zostać wywołana, gdybyśmy przekazali argument wiersza poleceń. -
not_called
nie jest wyświetlany, ponieważ nie został wywołany w uruchomieniu, ponieważ nie przekazaliśmy dodatkowego argumentu wiersza poleceń.
Najfajniejsze w valgrind
jest to, że nie wymaga żadnych specjalnych opcji kompilacji.
Dlatego możesz go używać nawet jeśli nie masz kodu źródłowego, tylko wykonywalnego.
valgrind
udaje się to zrobić, uruchamiając kod za pomocą lekkiej "maszyny wirtualnej".
Testowane na Ubuntu 18.04.
gcc -finstrument-functions
+ etrace
Https://github.com/elcritch/etrace
-finstrument-functions
dodaje wywołania zwrotne , etrace przetwarza plik ELF i implementuje wszystkie wywołania zwrotne.
Niestety nie udało mi się go uruchomić: dlaczego `-finstrument-functions` nie działa dla mnie?
Deklarowane wyjście ma 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
Prawdopodobnie najbardziej wydajna metoda oprócz obsługi konkretnego śledzenia sprzętowego, ale ma tę zaletę, że musisz przekompilować kod.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-30 14:21:49