Как сгенерировать граф вызовов для кода C ++ - PullRequest
77 голосов
/ 21 марта 2011

Я пытаюсь сгенерировать граф вызовов, с помощью которого можно найти все возможные пути выполнения, которые затрагивают определенную функцию (чтобы мне не приходилось выяснять все пути вручную, поскольку существует много путей, которые приводят к к этой функции). Например:

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: ...

Я пробовал Codeviz и Doxygen, так или иначе оба результата показывают только вызываемые объекты целевой функции D. В моем случае D является функцией-членом класса, объект которого будет заключен в интеллектуальный указатель. Клиенты всегда получают объект смарт-указателя через фабрику для вызова D.

Кто-нибудь знает, как этого добиться?

Ответы [ 8 ]

107 голосов
/ 21 марта 2011
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();
}

Тогда

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

Получает некоторую блестящую картинку (есть «внешний узел», потому что main имеет внешнюю связь и может также вызываться извне этой единицы перевода):

Callgraph

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

#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    

Даёт эту красоту (о боже, размер без включенных оптимизаций был слишком большим!)

Beauty

Эта мистическая безымянная функция, Node0x884c4e0 - это заполнитель, который предполагается вызывать любой функцией, определение которой неизвестно.

14 голосов
/ 03 декабря 2015

Этого можно добиться с помощью doxygen (с возможностью использовать точку для генерации графиков).

enter image description here

С Йоханнесом Шаубом - litb main.cpp, он генерирует это:

enter image description here

doxygen / dot, вероятно, проще, чем clang / opt, установить и запустить.Мне не удалось установить его самостоятельно, поэтому я попытался найти альтернативное решение!

6 голосов
/ 21 марта 2011

Статически вычислить точный граф вызовов C ++ сложно, потому что вам нужен точный синтаксический анализатор языка, правильный поиск имени и хороший анализатор точек, который должным образом учитывает семантику языка.Doxygen не имеет ничего из этого, я не знаю, почему люди утверждают, что им нравится C ++;Легко построить 10-строчный пример C ++, который Doxygen ошибочно анализирует.осуществлять много дел.Такие профилировщики покажут вам действительный граф вызовов.

РЕДАКТИРОВАТЬ: я вдруг вспомнил Понимание для C ++ , который утверждает, что создает графы вызовов.Я не знаю, что они используют для синтаксического анализатора, или они делают детальный анализ правильно;У меня нет конкретного опыта работы с их продуктом.

Я впечатлен ответом Шауба, используя Clang;Я ожидаю, что у Кланга все элементы будут правильными.

5 голосов
/ 06 февраля 2018

Вы можете использовать CppDepend , он может генерировать много видов графиков

  • График зависимостей
  • График вызовов
  • График наследования классов
  • График сцепления
  • Путь График
  • График всех путей
  • Цикл График

enter image description here

2 голосов
/ 03 июля 2014

Чтобы команда clang++ могла найти стандартные заголовочные файлы, такие как mpi.h, необходимо использовать две дополнительные опции -### -fsyntax-only, то есть полная команда должна выглядеть так:

clang++ -### -fsyntax-only -S -emit-llvm main1.cpp -o - | opt -analyze -dot-callgraph
1 голос
/ 25 сентября 2014

«C ++ Bsc Analyzer» может отображать графики вызовов, читая файл, сгенерированный утилитой bscmake.

0 голосов
/ 21 мая 2019

Scitools Understand - это фантастический инструмент, лучше, чем все, что я знаю для реверс-инжиниринга , и генерирующий высококачественные графики .

Но обратите внимание, что это довольно дорого, и что у пробной версии есть график вызовов бабочек , ограниченный только одним уровнем вызова (ИМХО, я полагаю, они не помогают себе сделать это ...)

0 голосов
/ 17 сентября 2018

doxygen + graphviz может решить большинство проблем, когда мы хотим сгенерировать граф вызовов, который затем будет передан рабочей силе.

...