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

107

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

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

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

Золотая середина
источник
4
Связанный: stackoverflow.com/a/17844310/1959808
Иоаннис Филиппидис

Ответы:

54
филант
источник
2
вопрос о CodeViz, Если вы передадите свой код, он будет генерировать код или нет? Или вы должны сами сделать график по codevis?
Mohammad Reza Rezwani
5
Я только что попробовал Египет. Это ужасно. Насчет остальных я не уверен.
ar2015
29

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

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

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

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

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

  • перехватывает указатели на функции и виртуальные вызовы 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 выглядит так:

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

  • корневой узел is _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-functions`?

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

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

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

Чиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
источник
2
Просто обратите внимание, что динамический график вызовов охватывает только один запуск программы.
smwikipedia
1
@smwikipedia, да, я обновил ответ, чтобы было понятнее
Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
Также объясняется здесь - stackoverflow.com/questions/311840/…
tauseef_CuriousGuy
17

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

MattK
источник
9

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

Ира Бакстер
источник
1
Ах, здорово, сейчас 2016 год, и теперь появляется голосующий против. Я уверен, что его голос против был основан на точной оценке, что этот инструмент не может этого сделать. Ну может и нет. Он точно выполняет то, что просил OP.
Ира Бакстер,
1
Подайте голос, чтобы противостоять этому. Мне все равно, ваше программное обеспечение или проприетарное ПО, если оно выполняет свою работу :-)
Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
7

Вы можете попробовать CScope + tceetree + Graphviz .

Фабио Визона
источник
Как использовать эту комбинацию для получения графика, есть ли руководство или хотя бы какое-то объяснение.
Мухаммад Юсуф
@ Мухаммад Юсуф: да, есть вики-страница .
BillyJoe 02
5

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

Джейсон Ниберг
источник
4

ИМХО, Astrée - самый надежный и изощренный инструмент.

ЯegDwight
источник