2012-02-09 27 views
6

Necesito imprimir el seguimiento de la pila desde un manejador de señal de la aplicación C++ multiproceso de 64 bits que se ejecuta en Linux. Aunque encontré varios ejemplos de código, ninguno de ellos compila. Mi punto de bloqueo es obtener la dirección de la persona que llama (el punto donde se generó la señal) de la estructura ucontext_t. Toda la información que pude encontrar apunta al registro de EIP como uuctext.gregs [REG_EIP] o ucontext.eip. Parece que ambos son específicos de x86. Necesito un código compatible con 64 bits para las CPU Intel y AMD. ¿Alguien puede ayudar?Impresión del seguimiento de pila desde un manejador de señal

+0

No me sorprendería si no fuera posible. ¿Has intentado hacerlo en 32 bits? Además, ¿qué distro? –

+0

En 64 bits, el registro es RIP. Seguro que estará allí en alguna parte. –

+0

Es Red Hat 4.1.2-50. No puede ser una aplicación de 32 bits ya que trabajamos con áreas de memoria grande de hasta 60+ GB – GMichael

Respuesta

1

La forma más habitual de conseguir un seguimiento de pila es tomar la dirección de un variable local, a continuación, añadir un poco de número mágico a la misma, dependiendo de cómo el compilador genera código (que puede depender de las opciones de optimización utilizados para compilar el código), y trabajar desde allí. Todo el mismo sistema depende, pero posible si sabes lo que estás haciendo.

Si esto funciona en un controlador de señal es otra cuestión. No conozco la plataforma que describes, pero muchos sistemas instalan una pila separada para los manejadores de señal, sin ningún enlace a la pila interrumpida en la memoria accesible para el usuario.

+0

¿Quiere decir que no hay un enlace de regreso a la pila interrumpida? –

+0

@wood_brian No está en la memoria accesible para el usuario. (El sistema operativo obviamente conserva la información de alguna manera). –

+0

Usted escribió estática interrumpida. Pensé que te referías a la pila interrumpida. –

4

hay una función glibc traza inversa. La página man enumera un ejemplo de la llamada:

#define SIZE 100 
void myfunc3(void) { 
     int j, nptrs; 

     void *buffer[100]; 
     char **strings; 

     nptrs = backtrace(buffer, SIZE); 
     printf("backtrace() returned %d addresses\n", nptrs); 

     /* The call backtrace_symbols_fd(buffer, nptrs, STDOUT_FILENO) 
      would produce similar output to the following: */ 

     strings = backtrace_symbols(buffer, nptrs); 
     if (strings == NULL) { 
      perror("backtrace_symbols"); 
      exit(EXIT_FAILURE); 
     } 

     for (j = 0; j < nptrs; j++) 
      printf("%s\n", strings[j]); 

     free(strings); 
    } 

Consulte la página de manual para obtener más contexto.

es difícil decir si realmente se garantiza que funcione desde un manejador de señal, ya que posix solo enumera unas pocas funciones de reentrada que están garantizadas para funcionar. Recuerde: se puede llamar a un manejador de señal mientras el resto de su proceso está justo en el medio de una llamada malloc.

Mi supongo es que normalmente funciona, pero puede fallar de vez en cuando. Para la depuración esto puede ser suficiente.

Cuestiones relacionadas