studio programacion móviles libros desarrollo desarrollar curso con aprende aplicaciones c++ c linux callstack

c++ - móviles - manual de programacion android pdf



imprimir pila de llamadas en C o C++ (10)

¿Hay alguna forma de volcar la pila de llamadas en un proceso en C o C ++ cada vez que se llama a una determinada función?

No, no, aunque existan soluciones dependientes de la plataforma.

¿Hay alguna forma de volcar la pila de llamadas en un proceso en C o C ++ cada vez que se llama a una determinada función? Lo que tengo en mente es algo como esto:

void foo() { print_stack_trace(); // foo''s body return }

Donde print_stack_trace funciona de manera similar a la caller que caller en Perl.

O algo como esto:

int main (void) { // will print out debug info every time foo() is called register_stack_trace_function(foo); // etc... }

donde register_stack_trace_function pone algún tipo de punto de corte interno que hará que se imprima un rastro de pila cada vez que se llame a foo .

¿Existe algo como esto en alguna biblioteca C estándar?

Estoy trabajando en Linux, usando GCC.

Fondo

Tengo una ejecución de prueba que se comporta de manera diferente en función de algunos modificadores de línea de comandos que no deberían afectar este comportamiento. Mi código tiene un generador de números pseudoaleatorios que supongo que se llama de forma diferente en función de estos conmutadores. Quiero poder ejecutar la prueba con cada conjunto de conmutadores y ver si el generador de números aleatorios se llama de manera diferente para cada uno.


¿Hay alguna forma de volcar la pila de llamadas en un proceso en C o C ++ cada vez que se llama a una determinada función?

Puede usar una función de macro en lugar de return en la función específica.

Por ejemplo, en lugar de usar el retorno,

int foo(...) { if (error happened) return -1; ... do something ... return 0 }

Puedes usar una función macro.

#include "c-callstack.h" int foo(...) { if (error happened) NL_RETURN(-1); ... do something ... NL_RETURN(0); }

Cada vez que ocurre un error en una función, verá la pila de llamadas al estilo Java como se muestra a continuación.

Error(code:-1) at : so_topless_ranking_server (sample.c:23) Error(code:-1) at : nanolat_database (sample.c:31) Error(code:-1) at : nanolat_message_queue (sample.c:39) Error(code:-1) at : main (sample.c:47)

El código fuente completo está disponible aquí.

c-callstack en https://github.com/Nanolat


No hay una forma estandarizada para hacer eso. Para Windows, la funcionalidad se proporciona en la biblioteca DbgHelp


Otra respuesta a un hilo viejo.

Cuando necesito hacer esto, suelo usar system() y pstack

Entonces algo como esto:

#include <sys/types.h> #include <unistd.h> #include <string> #include <sstream> #include <cstdlib> void f() { pid_t myPid = getpid(); std::string pstackCommand = "pstack "; std::stringstream ss; ss << myPid; pstackCommand += ss.str(); system(pstackCommand.c_str()); } void g() { f(); } void h() { g(); } int main() { h(); }

Estas salidas

#0 0x00002aaaab62d61e in waitpid () from /lib64/libc.so.6 #1 0x00002aaaab5bf609 in do_system () from /lib64/libc.so.6 #2 0x0000000000400c3c in f() () #3 0x0000000000400cc5 in g() () #4 0x0000000000400cd1 in h() () #5 0x0000000000400cdd in main ()

Esto debería funcionar en Linux, FreeBSD y Solaris. No creo que macOS tenga pstack o un simple equivalente, pero este hilo parece tener una alternativa .


Para una solución de solo Linux, puede usar backtrace(3) que simplemente devuelve una matriz de void * (de hecho, cada uno de estos apunta a la dirección de retorno desde el marco de pila correspondiente). Para traducir esto a algo de uso, hay backtrace_symbols(3) .

Preste atención a la sección de notas en backtrace (3) :

Los nombres de los símbolos pueden no estar disponibles sin el uso de opciones especiales del vinculador. Para los sistemas que usan el enlazador GNU, es necesario usar la opción del enlazador -dinámico. Tenga en cuenta que los nombres de las funciones "estáticas" no están expuestos, y no estarán disponibles en el backtrace.


Por supuesto, la siguiente pregunta es: ¿será suficiente?

La principal desventaja de stack-traces es que por qué se llama a la función precisa no tiene nada más, como el valor de sus argumentos, que es muy útil para la depuración.

Si tiene acceso a gcc y gdb, sugeriría usar assert para verificar una condición específica, y producir un volcado de memoria si no se cumple. Por supuesto, esto significa que el proceso se detendrá, pero tendrá un informe completo en lugar de un simple seguimiento de la pila.

Si desea una forma menos molesta, siempre puede usar el registro. Hay instalaciones de registro muy eficientes, como Pantheios por ejemplo. Que una vez más podría darle una imagen mucho más precisa de lo que está sucediendo.


Puede implementar la funcionalidad usted mismo:

Use una pila global (cadena) y al inicio de cada función, inserte el nombre de la función y otros valores (por ejemplo, parámetros) en esta pila; al salir de la función, vuelve a abrirlo.

Escriba una función que imprima el contenido de la pila cuando se llame, y úsela en la función en la que desea ver la pila de llamadas.

Esto puede parecer mucho trabajo, pero es bastante útil.


Puedes usar Poppy para esto. Normalmente se usa para recopilar el seguimiento de la pila durante un bloqueo, pero también puede generarlo para un programa en ejecución.

Ahora esta es la parte buena: puede mostrar los valores de los parámetros reales para cada función en la pila, e incluso las variables locales, los contadores de bucle, etc.


Puedes usar el generador de perfiles GNU. ¡Muestra el call-graph también! el comando es gprof y necesitas compilar tu código con alguna opción.


Sé que este hilo es antiguo, pero creo que puede ser útil para otras personas. Si está utilizando gcc, puede usar sus funciones de instrumento (opción -finstrument-functions) para registrar cualquier llamada de función (entrada y salida). Eche un vistazo a esto para obtener más información: http://hacktalks.blogspot.fr/2013/08/gcc-instrument-functions.html

Por lo tanto, puede, por ejemplo, presionar y mostrar cada llamada en una pila, y cuando quiera imprimirla, simplemente observe lo que tiene en la pila.

Lo probé, funciona perfectamente y es muy útil

ACTUALIZACIÓN: también puede encontrar información sobre la opción de compilación de funciones de instrumentos en el documento de GCC sobre las opciones de Instrumentación: https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html