2010-02-17 5 views
24

Tengo un código fuente de terceros que debo investigar. Quiero ver en qué orden las funciones son los llamados pero no quiero perder mi tiempo escribiendo:Agregando automáticamente registros de función de entrada/salida a un proyecto

printf("Entered into %s", __FUNCTION__) 

y

printf("Exited from %s", __FUNCTION__) 

para cada función, ni quiero tocar cualquier fuente archivo.

¿Tiene alguna sugerencia? ¿Hay una bandera del compilador que automágicamente hace esto por mí?

Aclaraciones a los comentarios:

  • cruzaré-compilar el código fuente de ejecutarlo en el brazo.
  • Lo compilaré con gcc.
  • No quiero analizar el código estático. Quiero rastrear el tiempo de ejecución. Entonces doxygen no hará mi vida más fácil.
  • Tengo la fuente y puedo compilarla.
  • No deseo utilizar la Programación Orientada a Aspectos.

EDIT: He encontrado ese comando 'marco' en el BGF impresiones inmediatas del cuadro actual (o, nombre de la función, se podría decir) en ese punto en el tiempo. Quizás, es posible (usando scripts gdb) llamar al comando 'frame' cada vez que se llama a una función. ¿Qué piensas?

+0

¿Qué entorno? – t0mm13b

+0

http://stackoverflow.com/questions/1173962/run-code-before-every-function-call-for-a-class-in-c/1174652 –

+0

@bmm: ¿Tiene la fuente del tercero que en realidad puedes compilar? – t0mm13b

Respuesta

26

Además de la depuración habitual y las técnicas de programación orientadas a aspectos, también puede inyectar sus propias funciones de instrumentación utilizando las opciones de línea de comando -finstrument-functions de gcc. Tendrá que implementar sus propias funciones __cyg_profile_func_enter() y __cyg_profile_func_exit() (declare esto como extern "C" en C++).

Proporcionan un medio para rastrear de qué función se llamó desde dónde. Sin embargo, la interfaz es un poco difícil de usar ya que la dirección de la función que se llama y su sitio de llamada se pasan en lugar de un nombre de función, por ejemplo. Puede registrar las direcciones y luego extraer los nombres correspondientes de la tabla de símbolos usando algo como objdump --syms o nm, asumiendo que los símbolos no se han eliminado de los binarios en cuestión.

Simplemente puede ser más fácil de usar gdb. YMMV. :)

+0

Exactamente lo que estaba buscando :) –

+2

gcc FTW nuevamente =) –

+0

aunque ... creo que este tipo de cosas introduciría una sobrecarga significativa incluso si la función de antes/después personalizada es liviana. –

1

Si está utilizando gcc, el indicador del compilador mágico es -g. Compile con símbolos de depuración, ejecute el programa bajo gdb y genere rastros de pila. También puede usar ptrace, pero probablemente sea mucho más fácil simplemente usar gdb.

+0

Hasta donde sé, stack trace es el estado de la pila de llamadas de función en un momento específico. ¿Puedo enviar los nombres de funciones de las funciones llamadas en secuencia a un archivo utilizando la opción de rastreo de pila en gdb? –

2

De acuerdo con William, use gdb para ver el flujo de tiempo de ejecución.
Hay un analizador de código estático que puede decir qué funciones llaman y cuál puede darle algún gráfico de flujo de llamadas. Una herramienta es "Comprender C++" (compatible con C/C++) pero eso no es gratis, supongo. Pero puedes encontrar herramientas similares.

+0

escaso, "analizador semántico", tiene una utilidad de gráficos. Genera un archivo graphviz que se puede convertir a un gráfico. http://sparse.wiki.kernel.org/index.php/Main_Page –

+0

¿Cuál es la bandera de opción exacta para gdb, que le permitirá imprimir cada función que se está llamando en ese momento? –

4

Use /Gh (Enable _penter Hook Function) y /GH (Enable _pexit Hook Function) modificadores del compilador (si se puede compilar las fuentes ofcourse)

NOTA: usted no será capaz de utilizar los macros de. See here ("necesitará obtener la dirección de la función (en el registro EIP) y compararla con las direcciones en el archivo de mapa que puede generar el enlazador (suponiendo que no se haya producido ninguna rebase). Sin embargo, será muy lento").

+0

Gracias PoweRoy. ¿Conoce la bandera del compilador correspondiente para gcc? ¿O cuál es el nombre de esta técnica, para que pueda googlearla? –

+0

No sé para gcc, '-g' de William tiene el mismo aspecto. Busqué "gancho de la función de entrada/salida de C++" en google: http://gcc.gnu.org/onlinedocs/gccint/Function-Entry.html – RvdK

11

Has dicho "ni quiero tocar ningún archivo fuente" ... juego limpio si dejas que un script lo haga por ti?

Ejecuta esto en todos tus.cpp

sed 's/^{/{ENTRY/' 

Para que los transforma en esto:

void foo() 
{ENTRY 
    // code here 
} 

poner esto en un encabezado que se pueden #include por cada unidad:

#define ENTRY EntryRaiiObject obj ## __LINE__ (__FUNCTION__); 

struct EntryRaiiObject { 
    EntryRaiiObject(const char *f) : f_(f) { printf("Entered into %s", f_); } 
    ~EntryRaiiObject() { printf("Exited from %s", f_); } 
    const char *f_; 
}; 

Usted puede tener que conseguir más elegante con el script sed. También puede poner la macro ENTRY en cualquier otro lugar que desee sondear, como un alcance interior profundamente anidado de una función.

+6

Puedes tener muchas cosas comenzando con un '{' al comienzo de un línea: estructuras, etc. ¿Cómo se dirigen de manera confiable las funciones? – lalebarde

Cuestiones relacionadas