2008-11-14 9 views
6

Estoy tratando de averiguar cómo almacenar y luego imprimir la pila actual en mis aplicaciones de C++ en Mac OS X. El problema principal parece ser conseguir que dladdr devuelva el símbolo correcto cuando se le da una dirección dentro del ejecutable principal. Sospecho que el problema es en realidad una opción de compilación, pero no estoy seguro.Obtener el seguimiento de la pila actual en Mac OS X

He intentado el código backtrace de Darwin/Leopard pero llama a dladdr y tiene el mismo problema que mi propio código llamando a dladdr.

Original post: Actualmente estoy capturando la pila con este código:

int BackTrace(Addr *buffer, int max_frames) 
{ 
    void **frame = (void **)__builtin_frame_address(0); 
    void **bp = (void **)(*frame); 
    void *ip = frame[1]; 
    int i; 

    for (i = 0; bp && ip && i < max_frames; i++) 
    { 
     *(buffer++) = ip; 
     ip = bp[1]; 
     bp = (void**)(bp[0]); 
    } 

    return i; 
} 

que parece funcionar bien. A continuación, imprimir la pila que estoy buscando en el uso de dladdr así:

Dl_info dli; 
if (dladdr(Ip, &dli)) 
{ 
    ptrdiff_t  offset; 
    int c = 0; 

    if (dli.dli_fname && dli.dli_fbase) 
    { 
     offset = (ptrdiff_t)Ip - (ptrdiff_t)dli.dli_fbase; 
     c = snprintf(buf, buflen, "%s+0x%x", dli.dli_fname, offset); 
    } 
    if (dli.dli_sname && dli.dli_saddr) 
    { 
     offset = (ptrdiff_t)Ip - (ptrdiff_t)dli.dli_saddr; 
     c += snprintf(buf+c, buflen-c, "(%s+0x%x)", dli.dli_sname, offset); 
    } 

    if (c > 0) 
     snprintf(buf+c, buflen-c, " [%p]", Ip); 

los que casi funciona, algún ejemplo de salida:

/Users/matthew/Library/Frameworks/Lgi.framework/Versions/A/Lgi+0x2473d(LgiStackTrace+0x5d) [0x102c73d] 
/Users/matthew/Code/Lgi/LgiRes/build/Debug/LgiRes.app/Contents/MacOS/LgiRes+0x2a006(tart+0x28e72) [0x2b006] 
/Users/matthew/Code/Lgi/LgiRes/build/Debug/LgiRes.app/Contents/MacOS/LgiRes+0x2f438(tart+0x2e2a4) [0x30438] 
/Users/matthew/Code/Lgi/LgiRes/build/Debug/LgiRes.app/Contents/MacOS/LgiRes+0x35e9c(tart+0x34d08) [0x36e9c] 
/Users/matthew/Code/Lgi/LgiRes/build/Debug/LgiRes.app/Contents/MacOS/LgiRes+0x1296(tart+0x102) [0x2296] 
/Users/matthew/Code/Lgi/LgiRes/build/Debug/LgiRes.app/Contents/MacOS/LgiRes+0x11bd(tart+0x29) [0x21bd] 

Se está poniendo el nombre del método adecuado para el objeto compartido pero no para la aplicación principal Los que acaban de mapear a "tarta" (o "inicio" menos el primer carácter).

Idealmente me gustaría tener los números de línea y el nombre del método en ese punto. Pero me conformaré con el nombre correcto de la función/método para los principiantes. Tal vez disparar para los números de línea después de eso, en Linux escuché que tienes que escribir tu propio analizador para un bloque ELF privado que tiene su propio conjunto de instrucciones. Suena aterrador.

De todos modos, ¿alguien puede ordenar este código para que tenga los nombres del método correcto?

Respuesta

12

A qué versiones de OS X se dirige. Si está ejecutando en Mac OS X 10.5 y superior, puede usar las llamadas de libraray backtrace() y backtrace_symbols(). Están definidos en execinfo.h, y hay un manpage con algún código de muestra.

Editar:

Usted ha mencionado en los comentarios que usted necesita para ejecutar el tigre. Probablemente pueda incluir la implementación de Libc en su aplicación. La fuente está disponible en el sitio de código abierto de Apple. Aquí hay un enlace al relevante file.

+0

Actualmente mi objetivo son las versiones actuales y anteriores, es decir, Leopard y Tiger. También actualmente tengo Tiger en mi Macbook. Entonces, hasta que salga el leopardo de las nieves, mi código tendrá que compilar/ejecutar en Tiger. – user33847

+0

Bueno, el código fuente para esa función es de código abierto, por lo que probablemente pueda incluir la implementación en su aplicación. Estoy editando mi respuesta con la información relevante. –

+0

He echado un vistazo al código que publicó enlaces y finalmente usa dladdr de la misma manera que mi código. Lo que da los mismos resultados incorrectos, ya que cualquier cosa en mi ejecutable (es decir, no es un objeto compartido) tiene el símbolo "tarta". – user33847