martes, 22 de abril de 2014

Pon libSegFault en tu $LD_PRELOAD

Todo programa que se ejecuta en un ordenador con GNU Linux termina usando glibc o derivados, ya sea un programa escrito en C++, en Java o en Vala. En lo mas hondo han de tirar de glibc.
Todos esos programas pueden generar lo que se llama violación de segmento (Segmentation Fault) que aparece cuando se accede una dirección de memoria no válida. Si has escrito programas en C o C++ seguramente te hayas encontrado con dicho error en el transcurso del desarrollo del programa. Desearías con toda seguridad que la violación de segmento diera algo más de información y no tuvieras que arrancar el GDB. Para eso existe libSegFault.
libSegFault.so es una biblioteca que forma parte de la colección de bibliotecas GNU y en distribuciones Ubuntu está en las rutas /lib/i386-linux-gnu/libSegFault.so y /lib/x86_64-linux-gnu/libSegFault.so. Siempre puedes usar locate para saber dónde está.
Una vez tienes localizada la biblioteca puedes exportar la variable LD_PRELOAD asignándole o añadiéndole la ruta a la biblioteca (export LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so:$LD_PRELOAD).

Si tienes un programa ofensivo violador de segmentos como el siguiente:

#include iostream

using namespace std;

void print_something_awful(int *p);

int main(int argc, char **argv) {
        int *p = 0;
        print_something_awful(p);
        return 0;
}

void print_something_awful(int *p) {
        cout << "This print accesses a null pointer (p==0) " << *p << endl;
        return;
}

Si lo compilas y ejecutas te hará una bonita violación de segmento. Al tener la biblioteca libSegFault cargada, obtendrás información adicional:
*** Segmentation fault
Register dump:

 RAX: 0000000000000000   RBX: 0000000000000000   RCX: 000000000040089d
 RDX: 00007fff453f6758   RSI: 00007fff453f6748   RDI: 0000000000000000
 RBP: 00007fff453f6630   R8 : 00007f69bcea0e80   R9 : 00007f69bd18df90
 R10: 00007fff453f63a0   R11: 00007f69bcb1a330   R12: 00000000004007b0
 R13: 00007fff453f6740   R14: 0000000000000000   R15: 0000000000000000
 RSP: 00007fff453f6610

 RIP: 00000000004008d8   EFLAGS: 00010202

 CS: 0033   FS: 0000   GS: 0000

 Trap: 0000000e   Error: 00000004   OldMask: 00000000   CR2: 00000000

 FPUCW: 0000037f   FPUSW: 00000000   TAG: 00000000
 RIP: 00000000   RDP: 00000000

 ST(0) 0000 0000000000000000   ST(1) 0000 0000000000000000
 ST(2) 0000 0000000000000000   ST(3) 0000 0000000000000000
 ST(4) 0000 0000000000000000   ST(5) 0000 0000000000000000
 ST(6) 0000 0000000000000000   ST(7) 0000 0000000000000000
 mxcsr: 1f80
 XMM0:  000000000000000000000000ff0000ff XMM1:  000000000000000000000000ff0000ff
 XMM2:  000000000000000000000000ff0000ff XMM3:  000000000000000000000000ff0000ff
 XMM4:  000000000000000000000000ff0000ff XMM5:  000000000000000000000000ff0000ff
 XMM6:  000000000000000000000000ff0000ff XMM7:  000000000000000000000000ff0000ff
 XMM8:  000000000000000000000000ff0000ff XMM9:  000000000000000000000000ff0000ff
 XMM10: 000000000000000000000000ff0000ff XMM11: 000000000000000000000000ff0000ff
 XMM12: 000000000000000000000000ff0000ff XMM13: 000000000000000000000000ff0000ff
 XMM14: 000000000000000000000000ff0000ff XMM15: 000000000000000000000000ff0000ff

Backtrace:
./mainfault[0x4008d8]
./mainfault[0x4008c0]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5)[0x7f69bcaffde5]
./mainfault[0x4007d9]

Memory map:

00400000-00401000 r-xp 00000000 fc:01 9463345                            /home/...
00600000-00601000 r--p 00000000 fc:01 9463345                            /home/...
00601000-00602000 rw-p 00001000 fc:01 9463345                            /home/...
023aa000-023cb000 rw-p 00000000 00:00 0                                  [heap]
7f69bc5c4000-7f69bc5d9000 r-xp 00000000 fc:01 4849990                    /lib/x8...
7f69bc5d9000-7f69bc7d8000 ---p 00015000 fc:01 4849990                    /lib/x8...
7f69bc7d8000-7f69bc7d9000 r--p 00014000 fc:01 4849990                    /lib/x8...
7f69bc7d9000-7f69bc7da000 rw-p 00015000 fc:01 4849990                    /lib/x8...
7f69bc7da000-7f69bc8dd000 r-xp 00000000 fc:01 4850205                    /lib/x8...
7f69bc8dd000-7f69bcadc000 ---p 00103000 fc:01 4850205                    /lib/x8...
7f69bcadc000-7f69bcadd000 r--p 00102000 fc:01 4850205                    /lib/x8...
7f69bcadd000-7f69bcade000 rw-p 00103000 fc:01 4850205                    /lib/x8...
7f69bcade000-7f69bcc9b000 r-xp 00000000 fc:01 4850219                    /lib/x8...
7f69bcc9b000-7f69bce9b000 ---p 001bd000 fc:01 4850219                    /lib/x8...
7f69bce9b000-7f69bce9f000 r--p 001bd000 fc:01 4850219                    /lib/x8...
7f69bce9f000-7f69bcea1000 rw-p 001c1000 fc:01 4850219                    /lib/x8...
7f69bcea1000-7f69bcea6000 rw-p 00000000 00:00 0 
7f69bcea6000-7f69bcf8c000 r-xp 00000000 fc:01 7611199                    /usr/li...
7f69bcf8c000-7f69bd18b000 ---p 000e6000 fc:01 7611199                    /usr/li...
7f69bd18b000-7f69bd193000 r--p 000e5000 fc:01 7611199                    /usr/li...
7f69bd193000-7f69bd195000 rw-p 000ed000 fc:01 7611199                    /usr/li...
7f69bd195000-7f69bd1aa000 rw-p 00000000 00:00 0 
7f69bd1aa000-7f69bd1ae000 r-xp 00000000 fc:01 4850201                    /lib/x8...
7f69bd1ae000-7f69bd3ad000 ---p 00004000 fc:01 4850201                    /lib/x8...
7f69bd3ad000-7f69bd3ae000 r--p 00003000 fc:01 4850201                    /lib/x8...
7f69bd3ae000-7f69bd3af000 rw-p 00004000 fc:01 4850201                    /lib/x8...
7f69bd3af000-7f69bd3d2000 r-xp 00000000 fc:01 4850208                    /lib/x8...
7f69bd5a2000-7f69bd5a7000 rw-p 00000000 00:00 0 
7f69bd5cf000-7f69bd5d1000 rw-p 00000000 00:00 0 
7f69bd5d1000-7f69bd5d2000 r--p 00022000 fc:01 4850208                    /lib/x8...
7f69bd5d2000-7f69bd5d4000 rw-p 00023000 fc:01 4850208                    /lib/x...
7fff453d7000-7fff453f9000 rw-p 00000000 00:00 0                          [stack]
7fff453fe000-7fff45400000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Violación de segmento (`core' generado) 

Aparecen los valores de los distintos registros del procesador incluidos los registros vectoriales XMM junto con la traza (backtrace) y el mapa de memoria (bibliotecas enlazadas con el programa y sus respectivas direcciones de memoria en la memoria del programa. En última instancia el mensaje de Violación de segmento aparece, pero ahora le precede más información acerca de lo ocurrido.

Lo único que hecho en falta es que la traza debería de llevar los nombres de las funciones sin embargo no aparecen. Esta libSegFault es la que lleva Ubuntu 13.10. El programa lo he compilado con los símbolos de depuración (g++ -g). He visto por Internet otras trazas obtenidas con libSegFault y en unas sí que aparecen los nombres y en otras no. ¿Motivo? lo único que se me ocurre son diferencias en la versión de la biblioteca o en las opciones con las que haya sido compilada por los empaquetadores de la distribución GNU Linux.

Actualizado:
No basta con compilar con -g, hay que añadir -rdynamic (g++ -g -rdynamic):

Backtrace:
./mainfault(_Z21print_something_awfulPi+0x11)[0x400ad8]
./mainfault(main+0x23)[0x400ac0]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5)[0x7fd815194de5]
./mainfault[0x4009d9]

El flag -rdynamic hace lo siguiente:
Pass the flag -export-dynamic to the ELF linker, on targets that support it. This instructs the linker to add all symbols, not only used ones, to the dynamic symbol table. This option is needed for some uses of "dlopen" or to allow obtaining backtraces from within a program.

No hay comentarios:

Publicar un comentario en la entrada