Generar gráfico de llamadas para código C ++

Intento generar un gráfico de llamadas con el que averiguar todas las posibles rutas de ejecución que están golpeando una función en particular (para no tener que descubrir todas las rutas manualmente, ya que hay muchas rutas que conducen a esta función). ) Por ejemplo:

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

He intentado Codeviz y Doxygen, de alguna manera ambos resultados no muestran más que llamadas de la función objective, D. En mi caso, D es una función miembro de una clase cuyo objeto se ajustará dentro de un puntero inteligente. Los clientes siempre obtendrán el objeto del puntero inteligente a través de una fábrica para invocar a D.

¿Alguien sabe como lograr esto?

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

    Entonces

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

    Otorga una imagen shiny (hay un “nodo externo”, porque main tiene un enlace externo y podría ser llamado desde fuera de esa unidad de traducción también):

    Callgraph

    Es posible que desee posprocesar esto con c++filt , de modo que pueda obtener los nombres no marcados de las funciones y clases involucradas. Como en el siguiente

     #include  struct A { A(int); void f(); // not defined, prevents inlining it! }; int main() { std::vector 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 

    Otorga esta belleza (¡oh, el tamaño sin optimizaciones activadas era demasiado grande!)

    Belleza

    Esa función mística sin nombre, Node0x884c4e0 , es un marcador de posición que se supone que es invocado por cualquier función cuya definición no se conoce.

    Puede lograr eso usando doxygen (con la opción de usar punto para la generación de gráficos).

    enter image description here

    Con Johannes Schaub – litb main.cpp, genera esto:

    enter image description here

    doxygen / dot es probablemente más fácil que clang / opt para instalar y ejecutar. No logré instalarlo yo mismo y es por eso que traté de encontrar una solución alternativa.

    El cálculo estático de un gráfico preciso de llamadas de C ++ es difícil, ya que necesita un analizador de lenguaje preciso, una búsqueda correcta de nombres y un buen analizador de puntos que respete la semántica del lenguaje de forma adecuada. Doxygen no tiene ninguno de estos, no sé por qué las personas dicen que les gusta para C ++; es fácil construir un ejemplo de C ++ de 10 líneas que Doxygen analiza erróneamente).

    Tal vez sea mejor que ejecute un generador de perfiles de tiempo que recolecta un gráfico de llamadas dinámicamente (esto describe el nuestro) y simplemente ejerce una gran cantidad de casos. Tales perfiladores le mostrarán el gráfico de llamada real ejercido.

    EDITAR: de repente recordé Understand for C ++ , que afirma construir gráficos de llamadas. No sé qué usan para un analizador sintáctico, o si hacen el análisis detallado correcto; No tengo experiencia específica con su producto.

    Estoy impresionado por la respuesta de Schaub, usando Clang; Esperaría que Clang tuviera todos los elementos correctos.

    Puede usar CppDepend , puede generar muchos tipos de gráficos

    • Gráfico de dependencia
    • Call Graph
    • Gráfico de herencia de clase
    • Gráfico de acoplamiento
    • Gráfico de ruta
    • Gráfico de todas las rutas
    • Gráfico de ciclo

    enter image description here

    Para que el comando clang++ pueda encontrar archivos de encabezado estándar como mpi.h , se deben usar dos opciones adicionales -### -fsyntax-only , es decir, el comando completo debe verse como:

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

    El “Analizador de C ++ Bsc” puede mostrar gráficos de llamadas, leyendo el archivo generado por la utilidad bscmake.