2011-03-13 6 views
10

Mi programa está compilado estáticamente con dietlibc. Se compila en ubuntu x64 (compilado para x86 usando el indicador -m32) y se ejecuta en un centos x86.gdb backtrace extraño

El tamaño compilado es de solo unos 100 KB. Lo compilo con -ggdb3 y sin indicadores de optimización.

Mi programa usa signal.h para manejar una señal SIGSEGV y luego llama a abort().

El programa se ejecuta sin problemas durante días, pero a veces segfaults. Esto es cuando consigo trazas extrañas que no entiendo:

 
[email protected]:~/Desktop$ gdb -c core.28569 program-name 
GNU gdb (GDB) 7.2 
Copyright (C) 2010 Free Software Foundation, Inc. 
License GPLv3+: GNU GPL version 3 or later 
This is free software: you are free to change and redistribute it. 
There is NO WARRANTY, to the extent permitted by law. Type "show copying" 
and "show warranty" for details. 
This GDB was configured as "--host=x86_64-linux-gnu --target=i386-linux-gnu". 
For bug reporting instructions, please see: 
... 
Reading symbols from program-name...done. 
[New Thread 28569] 
Core was generated by `program-name'. 
Program terminated with signal 6, Aborted. 
#0 0x00914410 in __kernel_vsyscall() 
Setting up the environment for debugging gdb. 
Function "internal_error" not defined. 
Make breakpoint pending on future shared library load? (y or [n]) [answered N; input not from terminal] 
Function "info_command" not defined. 
Make breakpoint pending on future shared library load? (y or [n]) [answered N; input not from terminal] 
.gdbinit:8: Error in sourced command file: 
Argument required (one or more breakpoint numbers). 
(gdb) bt 
#0 0x00914410 in __kernel_vsyscall() 
During symbol reading, incomplete CFI data; unspecified registers (e.g., eax) at 0x914411. 
#1 0x0804d7f4 in __unified_syscall() 
#2 0xbf8966c0 in ??() 
#3 
#4 0x2054454e in ??() 
#5 0x20524c43 in ??() 
#6 0x2e352e33 in ??() 
#7 0x32373033 in ??() 
#8 0x2e203b39 in ??() 
#9 0x2054454e in ??() 
#10 0x20524c43 in ??() 
#11 0x2e302e33 in ??() 
#12 0x32373033 in ??() 
#13 0x4d203b39 in ??() 
#14 0x61696465 in ??() 
#15 0x6e654320 in ??() 
#16 0x20726574 in ??() 
#17 0x36204350 in ??() 
#18 0x203b302e in ??() 
#19 0x54454e2e in ??() 
#20 0x43302e34 in ??() 
#21 0x00000029 in ??() 
#22 0xbf8989a8 in ??() 
Backtrace stopped: previous frame inner to this frame (corrupt stack?) 
(gdb) bt full 
#0 0x00914410 in __kernel_vsyscall() 
No symbol table info available. 
#1 0x0804d7f4 in __unified_syscall() 
No symbol table info available. 
#2 0xbf8966c0 in ??() 
No symbol table info available. 
#3 
No symbol table info available. 
#4 0x2054454e in ??() 
No symbol table info available. 
#5 0x20524c43 in ??() 
No symbol table info available. 
#6 0x2e352e33 in ??() 
No symbol table info available. 
#7 0x32373033 in ??() 
No symbol table info available. 
#8 0x2e203b39 in ??() 
No symbol table info available. 
#9 0x2054454e in ??() 
No symbol table info available. 
#10 0x20524c43 in ??() 
No symbol table info available. 
#11 0x2e302e33 in ??() 
No symbol table info available. 
#12 0x32373033 in ??() 
No symbol table info available. 
#13 0x4d203b39 in ??() 
No symbol table info available. 
#14 0x61696465 in ??() 
No symbol table info available. 
#15 0x6e654320 in ??() 
No symbol table info available. 
#16 0x20726574 in ??() 
No symbol table info available. 
#17 0x36204350 in ??() 
No symbol table info available. 
#18 0x203b302e in ??() 
No symbol table info available. 
#19 0x54454e2e in ??() 
No symbol table info available. 
#20 0x43302e34 in ??() 
No symbol table info available. 
#21 0x00000029 in ??() 
No symbol table info available. 
#22 0xbf8989a8 in ??() 
No symbol table info available. 
Backtrace stopped: previous frame inner to this frame (corrupt stack?) 
(gdb) quit 

Respuesta

16

Es una anulación de la pila.

#4 0x2054454e in ??() 

que se ve como texto, "diez" o "NET"

#5 0x20524c43 in ??() 

"RLC" o "CLR"

Y así sucesivamente.

Trate las direcciones como si fueran texto - vea si puede identificar dónde sobrescribe este texto su pila.

+0

En realidad, Erik tiene razón. Fue un strncat en una variable no inicializada. Es por eso que a veces falla y otras veces no. Por cierto, el texto era de hecho "NETO" y "CLR". Gracias. –

+0

Incluso en ese caso, mi respuesta es probablemente * también * correcta, y será mejor que corrija dietlibc para la * próxima * vez que llame abortar. –

6

Su seguimiento de la pila es realmente muy fácil de entender:

  • Tienes SIGSEGV en alguna parte,
  • Su manejador de señales hizo todo lo que hace, entonces llamado abort()
  • que fue concedida raise(2) llamada al sistema, llamando __unified_syscall()

La razón no se obtiene ningún seguimiento de la pila en el BGF es que

  • __unified_syscall se implementa en el montaje, y
  • no utiliza puntero de marco, y
  • no tiene adecuados cfi directivas para describir cómo desconectar de ella.

Considero que esto es un error en dietlibc, bastante fácil de arreglar, en realidad. A ver si esto (no probado) parche corrige por usted:

--- dietlibc-0.31/i386/unified.S.orig 2011-03-13 10:16:23.000000000 -0700 
+++ dietlibc-0.31/i386/unified.S 2011-03-13 10:21:32.000000000 -0700 
@@ -31,8 +31,14 @@ __unified_syscall: 
    movzbl %al, %eax 
.L1: 
    push %edi 
+  cfi_adjust_cfa_offset (4) 
+  cfi_rel_offset (edi, 0) 
    push %esi 
+  cfi_adjust_cfa_offset (4) 
+  cfi_rel_offset (esi, 0) 
    push %ebx 
+  cfi_adjust_cfa_offset (4) 
+  cfi_rel_offset (ebx, 0) 
    movl %esp,%edi 
    /* we use movl instead of pop because otherwise a signal would 
     destroy the stack frame and crash the program, although it 
@@ -61,8 +67,11 @@ __unified_syscall: 
#endif 
.Lnoerror: 
    pop %ebx 
+  cfi_adjust_cfa_offset (-4) 
    pop %esi 
+  cfi_adjust_cfa_offset (-4) 
    pop %edi 
+  cfi_adjust_cfa_offset (-4) 

/* here we go and "reuse" the return for weak-void functions */ 
#include "dietuglyweaks.h" 

Si no puede reconstruir dietlibc, o si el parche es incorrecta, usted todavía puede ser capaz de analizar el seguimiento de la pila mejor. Por lo que puedo decir, __unified_syscall no toca %ebp. Por lo que podría ser capaz de obtener un seguimiento de pila razonable al hacer esto:

define xbt 
    set $xbp = (void **)$arg0 
    while 1 
    x/2a $xbp 
    set $xbp = (void **)$xbp[0] 
    end 
end 

xbt $ebp 

Nota: si los xbt obras, es probable que entrar en la maleza alrededor de la trama de señal SIGSEGV (ese marco no utiliza puntero de marco tampoco). Esto puede resultar en basura completa, o en un marco omitido o dos (que serían exactamente los cuadros donde ocurrió el SIGSEGV).

Así que realmente es mucho mejor obtener descripciones de desenrollado adecuadas en dietlibc.