Инструменты для получения наглядного графика вызовов функций кода

У меня большое рабочее пространство с множеством исходных файлов кода C. Хотя я могу видеть функции, вызываемые из функции в MS VS2005 с помощью обозревателя объектов, а также в MSVC 6.0, здесь показаны только функции, вызываемые из конкретной функции, в неграфическом виде. Кроме того, он не показывает функцию, вызываемую, скажем, с main(), а затем функции, вызываемые из нее, и так далее, глубже до функции конечного уровня.

Мне нужен инструмент, который наглядно даст мне график вызовов функций с функциями callee и caller, соединенными стрелками или чем-то подобным, начиная с main() до последнего уровня функции, или, по крайней мере, показывая график вызовов всех функций в одном источнике C файл наглядно. Было бы здорово, если бы я мог распечатать этот график.

Есть ли для этого хорошие инструменты (не обязательно бесплатные)?


person goldenmean    schedule 05.02.2009    source источник
comment
Связанный: stackoverflow.com/a/17844310/1959808   -  person Ioannis Filippidis    schedule 03.05.2015
comment
en.wikipedia.org/wiki/Call_graph#Software   -  person 象嘉道    schedule 01.12.2020


Ответы (7)


person philant    schedule 05.02.2009
comment
вопрос о CodeViz, Если вы передадите свой код, он будет генерировать код или нет? Или вы должны сами сделать график по codevis? - person Mohammad Reza Rezwani; 05.04.2014
comment
Я только что попробовал Египет. Это ужасно. Насчет остальных я не уверен. - person ar2015; 28.05.2016

Методы динамического анализа

Здесь я описываю несколько методов динамического анализа.

Динамические методы фактически запускают программу для определения графа вызовов.

Противоположностью динамическим методам являются статические методы, которые пытаются определить его только из источника без запуска программы.

Преимущества динамических методов:

  • перехватывает указатели на функции и виртуальные вызовы C ++. Они присутствуют в большом количестве в любом нетривиальном программном обеспечении.

Недостатки динамических методов:

  • вам нужно запустить программу, которая может быть медленной или требовать установки, которой у вас нет, например кросс-компиляция
  • будут показаны только те функции, которые действительно были вызваны. Например, некоторые функции могут быть вызваны или нет, в зависимости от аргументов командной строки.

KcacheGrind

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

Программа испытаний:

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

Использование:

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

Теперь вы остались внутри великолепной программы с графическим интерфейсом, которая содержит много интересных данных о производительности.

В правом нижнем углу выберите вкладку «График звонков». Это показывает интерактивный график вызовов, который коррелирует с показателями производительности в других окнах, когда вы щелкаете по функциям.

Чтобы экспортировать график, щелкните его правой кнопкой мыши и выберите «Экспорт графика». Экспортированный PNG выглядит так:

Из этого мы видим, что:

  • корневой узел _start, который является фактической точкой входа в ELF и содержит шаблон инициализации glibc
  • f0, f1 и f2 вызываются, как и ожидалось друг от друга
  • pointed также отображается, хотя мы вызывали его с помощью указателя на функцию. Возможно, он не был бы вызван, если бы мы передали аргумент командной строки.
  • not_called не отображается, потому что он не был вызван при выполнении, потому что мы не передали дополнительный аргумент командной строки.

В valgrind замечательно то, что он не требует каких-либо специальных параметров компиляции.

Следовательно, вы можете использовать его, даже если у вас нет исходного кода, только исполняемый файл.

valgrind удается это сделать, запустив ваш код через легкую «виртуальную машину». Это также делает выполнение чрезвычайно медленным по сравнению с собственным исполнением.

Как видно на графике, также получается информация о времени для каждого вызова функции, и ее можно использовать для профилирования программы, что, вероятно, является исходным вариантом использования этой настройки, а не только для просмотра графиков вызовов: Как я могу профилировать код C ++, работающий в Linux?

Проверено на Ubuntu 18.04.

gcc -finstrument-functions + etrace

https://github.com/elcritch/etrace

-finstrument-functions добавляет обратные вызовы, etrace анализирует файл ELF и реализует все обратные вызовы.

К сожалению, мне не удалось заставить его работать: Почему не работает `-finstrument- у меня работают функции?

Заявленный вывод имеет формат:

\-- 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

Вероятно, это наиболее эффективный метод, помимо поддержки конкретной аппаратной трассировки, но имеет обратную сторону: вам придется перекомпилировать код.

person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 02.07.2015
comment
Просто обратите внимание, что динамический график вызовов охватывает только один запуск программы. - person smwikipedia; 30.09.2018
comment
@smwikipedia да, я обновил ответ, чтобы было понятнее - person Ciro Santilli 新疆再教育营六四事件ۍ 30.09.2018
comment
Также здесь объясняется - stackoverflow.com/questions/311840/ - person tauseef_CuriousGuy; 18.03.2019

Understand отлично справляется с созданием графиков звонков.

person MattK    schedule 05.02.2009

В нашем DMS Software Reengineering Toolkit есть анализ статического управления / потока данных / точек / вызовов, который был применен к огромным системам (~~ 25 миллионов строк) C код и создавал такие графики вызовов, включая функции, вызываемые через указатели функций.

person Ira Baxter    schedule 04.12.2010
comment
Ах, здорово, сейчас 2016 год, и теперь появляется голосующий против. Я уверен, что его голос против был основан на точной оценке того, что этот инструмент не может этого сделать. Ну, может, и нет. Он точно выполняет то, что просил OP. - person Ira Baxter; 31.03.2016
comment
Подайте голос, чтобы противостоять этому. Мне все равно, это ваше программное обеспечение или проприетарное ПО, если оно выполняет свою работу :-) - person Ciro Santilli 新疆再教育营六四事件ۍ 12.04.2016


Вы можете проверить мой генератор дерева вызовов C на основе bash здесь. Он позволяет вам указать одну или несколько функций C, для которых вы хотите получить информацию о вызывающем и / или вызываемом, или вы можете указать набор функций и определить график достижимости вызовов функций, которые их соединяют ... расскажите мне обо всех способах связи main (), foo () и bar (). Он использует graphviz / dot для графического движка.

person Jason Nyberg    schedule 03.07.2015

Astrée - это самый надежный и сложный инструмент, IMHO.

person ЯegDwight    schedule 17.02.2009