Herramientas para obtener un gráfico de código de llamadas a funciones pictóricas [cerrado]


107

Tengo un gran espacio de trabajo que tiene muchos archivos fuente de código C. Aunque puedo ver las funciones llamadas desde una función en MS VS2005 usando el navegador de objetos, y también en MSVC 6.0, esto solo muestra las funciones llamadas desde una función en particular en un tipo de pantalla no gráfica. Además, no muestra la función llamada comenzando por decir main(), y luego las funciones llamadas desde ella, y así sucesivamente, más adentro de la función de nivel de hoja.

Necesito una herramienta que me dé un gráfico de llamadas a funciones pictóricamente con funciones calleey callerconectado por flechas o algo así, comenzando desde main()el último nivel de función, o al menos mostrando un gráfico de llamadas de todas las funciones en un archivo fuente de C pictóricamente. Sería genial si pudiera imprimir este gráfico.

¿Alguna buena herramienta para hacer eso (no necesita ser herramientas gratuitas)?


Respuestas:



29

Métodos de análisis dinámico

Aquí describo algunos métodos de análisis dinámico.

Los métodos dinámicos realmente ejecutan el programa para determinar el gráfico de llamadas.

Lo contrario de los métodos dinámicos son los métodos estáticos, que intentan determinarlo solo desde la fuente sin ejecutar el programa.

Ventajas de los métodos dinámicos:

  • captura punteros de función y llamadas virtuales de C ++. Estos están presentes en grandes cantidades en cualquier software no trivial.

Desventajas de los métodos dinámicos:

  • tienes que ejecutar el programa, que puede ser lento o requerir una configuración que no tienes, por ejemplo, compilación cruzada
  • solo se mostrarán las funciones que fueron realmente llamadas. Por ejemplo, algunas funciones podrían llamarse o no dependiendo de los argumentos de la línea de comandos.

KcacheGrind

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

Programa de prueba:

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

Uso:

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

Ahora se encuentra dentro de un increíble programa GUI que contiene una gran cantidad de datos de rendimiento interesantes.

En la parte inferior derecha, seleccione la pestaña "Gráfico de llamadas". Esto muestra un gráfico de llamadas interactivo que se correlaciona con las métricas de rendimiento en otras ventanas a medida que hace clic en las funciones.

Para exportar el gráfico, haga clic derecho y seleccione "Exportar gráfico". El PNG exportado tiene este aspecto:

De eso podemos ver que:

  • el nodo raíz es _start, que es el punto de entrada de ELF real, y contiene el texto estándar de inicialización de glibc
  • f0, f1y f2se llaman como se esperaba el uno del otro
  • pointedtambién se muestra, aunque lo llamamos con un puntero de función. Es posible que no se haya llamado si hubiéramos pasado un argumento de línea de comando.
  • not_called no se muestra porque no se llamó en la ejecución, porque no pasamos un argumento de línea de comando adicional.

Lo bueno valgrindes que no requiere ninguna opción de compilación especial.

Por lo tanto, puede usarlo incluso si no tiene el código fuente, solo el ejecutable.

valgrindlogra hacerlo ejecutando su código a través de una "máquina virtual" ligera. Esto también hace que la ejecución sea extremadamente lenta en comparación con la ejecución nativa.

Como se puede ver en el gráfico, también se obtiene información de tiempo sobre cada llamada de función, y esto se puede usar para perfilar el programa, que probablemente sea el caso de uso original de esta configuración, no solo para ver gráficos de llamadas: ¿Cómo puedo perfilar ¿El código C ++ se ejecuta en Linux?

Probado en Ubuntu 18.04.

gcc -finstrument-functions + etrace

https://github.com/elcritch/etrace

-finstrument-functions agrega devoluciones de llamada , etrace analiza el archivo ELF e implementa todas las devoluciones de llamada.

Sin embargo, desafortunadamente no pude hacerlo funcionar: ¿Por qué `-finstrument-functions` no funciona para mí?

La salida reclamada tiene el formato:

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

Probablemente sea el método más eficiente además del soporte de rastreo de hardware específico, pero tiene la desventaja de que debe volver a compilar el código.


2
Solo tenga en cuenta que el gráfico de llamadas dinámicas solo cubre una ejecución del programa.
smwikipedia

1
@smwikipedia sí, he actualizado la respuesta para que
quede



9

Nuestro kit de herramientas de reingeniería de software DMS tiene análisis de gráficos de control / flujo de datos / puntos a / llamada estática que se ha aplicado a sistemas enormes (~~ 25 millones de líneas) de código C, y ha producido tales gráficos de llamadas, incluidas funciones llamadas mediante punteros de función .


1
Ah, bueno, es 2016 y ahora aparece un votante negativo. Estoy seguro de que su voto negativo se basó en una evaluación precisa de que esta herramienta no puede hacer esto. Bueno, tal vez no. Seguro que hace lo que OP pidió.
Ira Baxter

1
Acepta un voto a favor para contrarrestar eso. No me importa que sea su software o propietario siempre que haga el trabajo :-)
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功


5

Puede consultar mi generador de árbol de llamadas C basado en bash aquí . Le permite especificar una o más funciones C para las que desea información de la persona que llama y / o llamada, o puede especificar un conjunto de funciones y determinar el gráfico de accesibilidad de las llamadas a funciones que las conecta ... Es decir, dígame todas las formas principales ( ), foo () y bar () están conectados. Utiliza graphviz / dot para un motor gráfico.


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.