Pregunta ¿Cómo puede uno agarrar un rastro de pila en C?


Sé que no hay una función C estándar para hacer esto. Me preguntaba ¿cuáles son las técnicas para esto en Windows y * nix? (Windows XP es mi sistema operativo más importante para hacer esto en este momento).


73
2017-09-19 21:11


origen


Respuestas:


Lo hemos usado para nuestros proyectos:

https://www.codeproject.com/kb/threads/stackwalker.aspx

El código es un poco desordenado en mi humilde opinión, pero funciona bien. Solo Windows


22
2017-09-19 21:21



glibc proporciona la función backtrace ().

http://www.gnu.org/software/libc/manual/html_node/Backtraces.html


76
2017-09-19 21:15



Hay backtrace () y backtrace_symbols ():

Desde la página man:

     #include <execinfo.h>
     #include <stdio.h>
     ...
     void* callstack[128];
     int i, frames = backtrace(callstack, 128);
     char** strs = backtrace_symbols(callstack, frames);
     for (i = 0; i < frames; ++i) {
         printf("%s\n", strs[i]);
     }
     free(strs);
     ...

Una forma de usar esto de una manera más conveniente / OOP es guardar el resultado de backtrace_symbols () en un constructor de clase de excepción. Por lo tanto, cada vez que arrojas ese tipo de excepción, tienes el rastro de la pila. Luego, solo proporcione una función para imprimirlo. Por ejemplo:


class MyException : public std::exception {

    char ** strs;
    MyException( const std::string & message ) {
         int i, frames = backtrace(callstack, 128);
         strs = backtrace_symbols(callstack, frames);
    }

    void printStackTrace() {
        for (i = 0; i 

...


tratar {
   throw MyException ("¡Uy!");
} catch (MyException e) {
    e.printStackTrace ();
}

23
2018-02-25 19:07



Para Windows, compruebe la API StackWalk64 () (también en Windows de 32 bits). Para UNIX, debe usar la forma nativa del sistema operativo para hacerlo, o recurrir a la barra posterior de glibc (), si está disponible.

Sin embargo, tenga en cuenta que tomar una Stacktrace en código nativo rara vez es una buena idea, no porque no sea posible, sino porque usualmente tratamos de lograr algo incorrecto.

La mayoría de las veces, la gente trata de obtener una pila en, por ejemplo, una circunstancia excepcional, como cuando se detecta una excepción, falla una afirmación o, peor y más equivocado de todos, cuando se produce una "excepción" fatal o señal como una violación de segmentación

Teniendo en cuenta el último problema, la mayoría de las API requerirá que asigne memoria explícitamente o puede hacerlo internamente. Hacerlo en el frágil estado en el que se encuentra actualmente su programa puede empeorar las cosas. Por ejemplo, el informe de bloqueo (o coredump) no reflejará la causa real del problema, sino su intento fallido de manejarlo).

Supongo que estás tratando de lograr esa cosa de manejo de errores fatales, ya que la mayoría de la gente parece intentar eso cuando se trata de obtener una stack stack. Si es así, me basaría en el depurador (durante el desarrollo) y dejaría que el proceso coredump en producción (o mini-volcado en Windows). Junto con la administración correcta de símbolos, no debería tener problemas para calcular la instrucción causante post-mortem.


20
2017-09-24 13:07



Para ventanas, CaptureStackBackTrace() también es una opción, que requiere menos código de preparación en el extremo del usuario que StackWalk64() hace. (También, para una situación similar que tuve, CaptureStackBackTrace() terminó trabajando mejor (más confiablemente) que StackWalk64().)


4
2017-10-01 21:35



Deberías estar usando el desenrollar la biblioteca.

unw_cursor_t cursor; unw_context_t uc;
unw_word_t ip, sp;
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
unsigned long a[100];
int ctr = 0;

while (unw_step(&cursor) > 0) {
  unw_get_reg(&cursor, UNW_REG_IP, &ip);
  unw_get_reg(&cursor, UNW_REG_SP, &sp);
  if (ctr >= 10) break;
  a[ctr++] = ip;
}

Su enfoque también funcionaría bien a menos que realice una llamada desde una biblioteca compartida.

Puedes usar el addr2line comando en Linux para obtener la función fuente / número de línea de la PC correspondiente.


4
2018-01-31 06:31



No hay una plataforma independiente para hacerlo.

Lo más cercano que puede hacer es ejecutar el código sin optimizaciones. De esta forma, puede conectarse al proceso (utilizando el depurador visual de c ++ o GDB) y obtener un seguimiento de pila utilizable.


3
2017-09-19 21:15



Solaris tiene el pstack comando, que también fue copiado en Linux.


2
2017-09-22 02:15



Puedo señalarle mi artículo. Son solo unas pocas líneas de código.

Depuración post mortem

Aunque actualmente tengo problemas con el x64 implementación de esto.


2
2018-02-27 16:58