2011-12-24 9 views
28

glibc proporciona backtrace() y backtrace_symbols() para obtener el seguimiento de la pila de un programa en ejecución. Pero para que esto funcione, el programa debe construirse con el indicador -rdynamic de linker.símbolos de depuración de gcc (indicador -g) vs opción -rdinámica del vinculador

¿Cuál es la diferencia entre -g bandera pasada a gcc vs linker's -rdynamic? Para un código de muestra que hice readelf para comparar las salidas. -rdynamic parece producir más información en Symbol table '.dynsym' Pero no estoy muy seguro de cuál es la información adicional.

Incluso si yo strip un programa binario construido usando -rdynamic, backtrace_symbols() continúo trabajando.

Cuando strip elimina todos los símbolos del binario ¿por qué está dejando atrás lo que haya sido agregado por la bandera -rdynamic?

Editar: Seguimiento de preguntas basadas en la respuesta de la estera debajo ..

Por el mismo código de ejemplo que tomó esta es la diferencia que veo con -g & -rdynamic

sin ninguna opción ..

Symbol table '.dynsym' contains 4 entries: 
     Num: Value   Size Type Bind Vis  Ndx Name 
     0: 0000000000000000  0 NOTYPE LOCAL DEFAULT UND 
     1: 0000000000000000 218 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2) 
     2: 0000000000000000  0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses 
     3: 0000000000000000  0 NOTYPE WEAK DEFAULT UND __gmon_start__ 

    Symbol table '.symtab' contains 70 entries: 
     Num: Value   Size Type Bind Vis  Ndx Name 
     0: 0000000000000000  0 NOTYPE LOCAL DEFAULT UND 
     1: 0000000000400200  0 SECTION LOCAL DEFAULT 1 
     2: 000000000040021c  0 SECTION LOCAL DEFAULT 2 

con -g hay más secciones, más entradas en .symtab tabla pero .dynsym sigue siendo el mismo ..

 [26] .debug_aranges PROGBITS   0000000000000000 0000095c 
      0000000000000030 0000000000000000   0  0  1 
     [27] .debug_pubnames PROGBITS   0000000000000000 0000098c 
      0000000000000023 0000000000000000   0  0  1 
     [28] .debug_info  PROGBITS   0000000000000000 000009af 
      00000000000000a9 0000000000000000   0  0  1 
     [29] .debug_abbrev  PROGBITS   0000000000000000 00000a58 
      0000000000000047 0000000000000000   0  0  1 
     [30] .debug_line  PROGBITS   0000000000000000 00000a9f 
      0000000000000038 0000000000000000   0  0  1 
     [31] .debug_frame  PROGBITS   0000000000000000 00000ad8 
      0000000000000058 0000000000000000   0  0  8 
     [32] .debug_loc  PROGBITS   0000000000000000 00000b30 
      0000000000000098 0000000000000000   0  0  1 

    Symbol table '.dynsym' contains 4 entries: 
     Num: Value   Size Type Bind Vis  Ndx Name 
     0: 0000000000000000  0 NOTYPE LOCAL DEFAULT UND 
     1: 0000000000000000 218 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2) 
     2: 0000000000000000  0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses 
     3: 0000000000000000  0 NOTYPE WEAK DEFAULT UND __gmon_start__ 

    Symbol table '.symtab' contains 77 entries: 
     Num: Value   Size Type Bind Vis  Ndx Name 
     0: 0000000000000000  0 NOTYPE LOCAL DEFAULT UND 
     1: 0000000000400200  0 SECTION LOCAL DEFAULT 1 

con -rdynamic no hay secciones adicionales de depuración, las entradas son .symtab 70 (igual que la invocación de vainilla gcc), pero más .dynsym entradas ..

Symbol table '.dynsym' contains 19 entries: 
     Num: Value   Size Type Bind Vis  Ndx Name 
     0: 0000000000000000  0 NOTYPE LOCAL DEFAULT UND 
     1: 0000000000000000 218 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2) 
     2: 00000000005008e8  0 OBJECT GLOBAL DEFAULT ABS _DYNAMIC 
     3: 0000000000400750 57 FUNC GLOBAL DEFAULT 12 __libc_csu_fini 
     4: 00000000004005e0  0 FUNC GLOBAL DEFAULT 10 _init 
     5: 0000000000400620  0 FUNC GLOBAL DEFAULT 12 _start 
     6: 00000000004006f0 86 FUNC GLOBAL DEFAULT 12 __libc_csu_init 
     7: 0000000000500ab8  0 NOTYPE GLOBAL DEFAULT ABS __bss_start 
     8: 00000000004006de 16 FUNC GLOBAL DEFAULT 12 main 
     9: 0000000000500aa0  0 NOTYPE WEAK DEFAULT 23 data_start 
     10: 00000000004007c8  0 FUNC GLOBAL DEFAULT 13 _fini 
     11: 00000000004006d8  6 FUNC GLOBAL DEFAULT 12 foo 
     12: 0000000000500ab8  0 NOTYPE GLOBAL DEFAULT ABS _edata 
     13: 0000000000500a80  0 OBJECT GLOBAL DEFAULT ABS _GLOBAL_OFFSET_TABLE_ 
     14: 0000000000500ac0  0 NOTYPE GLOBAL DEFAULT ABS _end 
     15: 00000000004007d8  4 OBJECT GLOBAL DEFAULT 14 _IO_stdin_used 
     16: 0000000000500aa0  0 NOTYPE GLOBAL DEFAULT 23 __data_start 
     17: 0000000000000000  0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses 
     18: 0000000000000000  0 NOTYPE WEAK DEFAULT UND __gmon_start__  

    Symbol table '.symtab' contains 70 entries: 
     Num: Value   Size Type Bind Vis  Ndx Name 
     0: 0000000000000000  0 NOTYPE LOCAL DEFAULT UND 
     1: 0000000000400200  0 SECTION LOCAL DEFAULT 1 
     2: 000000000040021c  0 SECTION LOCAL DEFAULT 2 

Estas son las preguntas que tengo ..

  1. En gdb puede hacer bt para obtener la bactrace. Si eso funciona solo con -g, ¿por qué necesitamos -rdynamic para que backtrace_symbols funcione?

  2. Comparando las adiciones a .symtab con -g & adiciones a .dynsym con -rdynamic no son exactamente lo mismo .. ¿Se contempla en cualquiera de los dos mejor información de depuración en comparación con el otro? FWIW, el tamaño de la salida producida es así: con -g> con -dinámica> sin la opción

  3. ¿Cuál es exactamente el uso de .dynsym? ¿Son todos los símbolos exportados por este binario? En ese caso, ¿por qué foo entrar en .dynsym porque no estamos compilando el código como una biblioteca?

  4. Si enlace mi código usando todas las bibliotecas estáticas entonces -rdinámica no es necesario para que backtrace_symbols funcione?

+1

Se da la circunstancia de que traza lamentablemente no utiliza símbolos de depuración [si hay] como la mayoría de otras herramientas, incluyendo el BGF, valgrind, etc. –

Respuesta

39

De acuerdo con los documentos:

Esto indica al enlazador para agregar todos los símbolos, no sólo a las usadas, a la tabla de símbolos dinámicos.

Estos no son símbolos de depuración, son símbolos dinámicos del enlazador. Esos no son eliminados por strip ya que (en la mayoría de los casos) rompería el ejecutable; el enlazador de tiempo de ejecución los utiliza para hacer la etapa de enlace final del ejecutable.

Ejemplo:

$ cat t.c 
void foo() {} 
int main() { foo(); return 0; } 

de compilación y enlace sin -rdynamic (y no hay optimizaciones, obviamente)

$ gcc -O0 -o t t.c 
$ readelf -s t 

Symbol table '.dynsym' contains 3 entries: 
    Num: Value   Size Type Bind Vis  Ndx Name 
    0: 0000000000000000  0 NOTYPE LOCAL DEFAULT UND 
    1: 0000000000000000  0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2) 
    2: 0000000000000000  0 NOTYPE WEAK DEFAULT UND __gmon_start__ 

Symbol table '.symtab' contains 50 entries: 
    Num: Value   Size Type Bind Vis  Ndx Name 
    0: 0000000000000000  0 NOTYPE LOCAL DEFAULT UND 
    1: 0000000000400270  0 SECTION LOCAL DEFAULT 1 
.... 
    27: 0000000000000000  0 FILE LOCAL DEFAULT ABS t.c 
    28: 0000000000600e14  0 NOTYPE LOCAL DEFAULT 18 __init_array_end 
    29: 0000000000600e40  0 OBJECT LOCAL DEFAULT 21 _DYNAMIC 

Así que el ejecutable tiene un .symtab con todo. Pero tenga en cuenta que .dynsym no menciona foo en absoluto, tiene los elementos esenciales que hay allí. Esto no es información suficiente para que backtrace_symbols funcione. Se basa en la información presente en esa sección para hacer coincidir las direcciones de los códigos con los nombres de las funciones.

Ahora compila con -rdynamic:

$ gcc -O0 -o t t.c -rdynamic 
$ readelf -s t 

Symbol table '.dynsym' contains 17 entries: 
    Num: Value   Size Type Bind Vis  Ndx Name 
    0: 0000000000000000  0 NOTYPE LOCAL DEFAULT UND 
    1: 0000000000000000  0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2) 
    2: 0000000000000000  0 NOTYPE WEAK DEFAULT UND __gmon_start__ 
    3: 0000000000000000  0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses 
    4: 0000000000601018  0 NOTYPE GLOBAL DEFAULT ABS _edata 
    5: 0000000000601008  0 NOTYPE GLOBAL DEFAULT 24 __data_start 
    6: 0000000000400734  6 FUNC GLOBAL DEFAULT 13 foo 
    7: 0000000000601028  0 NOTYPE GLOBAL DEFAULT ABS _end 
    8: 0000000000601008  0 NOTYPE WEAK DEFAULT 24 data_start 
    9: 0000000000400838  4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used 
    10: 0000000000400750 136 FUNC GLOBAL DEFAULT 13 __libc_csu_init 
    11: 0000000000400650  0 FUNC GLOBAL DEFAULT 13 _start 
    12: 0000000000601018  0 NOTYPE GLOBAL DEFAULT ABS __bss_start 
    13: 000000000040073a 16 FUNC GLOBAL DEFAULT 13 main 
    14: 0000000000400618  0 FUNC GLOBAL DEFAULT 11 _init 
    15: 00000000004007e0  2 FUNC GLOBAL DEFAULT 13 __libc_csu_fini 
    16: 0000000000400828  0 FUNC GLOBAL DEFAULT 14 _fini 

Symbol table '.symtab' contains 50 entries: 
    Num: Value   Size Type Bind Vis  Ndx Name 
    0: 0000000000000000  0 NOTYPE LOCAL DEFAULT UND 
    1: 0000000000400270  0 SECTION LOCAL DEFAULT 1 
.... 
    27: 0000000000000000  0 FILE LOCAL DEFAULT ABS t.c 
    28: 0000000000600e14  0 NOTYPE LOCAL DEFAULT 18 __init_array_end 
    29: 0000000000600e40  0 OBJECT LOCAL DEFAULT 21 _DYNAMIC 

Lo mismo para los símbolos en .symtab, pero ahora foo tiene un símbolo en la sección de símbolo dinámico (y un montón de otros símbolos aparecerá ahora también). Esto hace que backtrace_symbols funcione; ahora tiene suficiente información (en la mayoría de los casos) para asignar direcciones de código con nombres de funciones.

de Gaza que:

$ strip --strip-all t 
$ readelf -s t 

Symbol table '.dynsym' contains 17 entries: 
    Num: Value   Size Type Bind Vis  Ndx Name 
    0: 0000000000000000  0 NOTYPE LOCAL DEFAULT UND 
    1: 0000000000000000  0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2) 
    2: 0000000000000000  0 NOTYPE WEAK DEFAULT UND __gmon_start__ 
    3: 0000000000000000  0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses 
    4: 0000000000601018  0 NOTYPE GLOBAL DEFAULT ABS _edata 
    5: 0000000000601008  0 NOTYPE GLOBAL DEFAULT 24 __data_start 
    6: 0000000000400734  6 FUNC GLOBAL DEFAULT 13 foo 
    7: 0000000000601028  0 NOTYPE GLOBAL DEFAULT ABS _end 
    8: 0000000000601008  0 NOTYPE WEAK DEFAULT 24 data_start 
    9: 0000000000400838  4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used 
    10: 0000000000400750 136 FUNC GLOBAL DEFAULT 13 __libc_csu_init 
    11: 0000000000400650  0 FUNC GLOBAL DEFAULT 13 _start 
    12: 0000000000601018  0 NOTYPE GLOBAL DEFAULT ABS __bss_start 
    13: 000000000040073a 16 FUNC GLOBAL DEFAULT 13 main 
    14: 0000000000400618  0 FUNC GLOBAL DEFAULT 11 _init 
    15: 00000000004007e0  2 FUNC GLOBAL DEFAULT 13 __libc_csu_fini 
    16: 0000000000400828  0 FUNC GLOBAL DEFAULT 14 _fini 
$ ./t 
$ 

Sin .symtab se ha ido, pero la tabla de símbolos dinámica es todavía allí, y se ejecuta el ejecutable. Así que backtrace_symbols todavía funciona.

de Gaza la tabla dinámica símbolo:

$ strip -R .dynsym t 
$ ./t 
./t: relocation error: ./t: symbol , version GLIBC_2.2.5 not defined in file libc.so.6 with link time reference 

... y se obtiene un archivo ejecutable roto.

Una lectura interesante para lo que se usan .symtab y .dynsym aquí: Inside ELF Symbol Tables. Una de las cosas a tener en cuenta es que .symtab no es necesario en el tiempo de ejecución, por lo que el cargador lo descarta. Esa sección no permanece en la memoria del proceso. .dynsym, por otro lado, es necesario en tiempo de ejecución, por lo que se mantiene en la imagen del proceso. Por lo tanto, está disponible para cosas como backtrace_symbols para recopilar información sobre el proceso actual desde sí mismo.

Así que en resumen:

  • símbolos dinámicos no son despojados por strip ya que haría que los ejecutables no cargable
  • backtrace_symbols necesidades símbolos dinámicos de averiguar qué código pertenece que funcionan
  • backtrace_symbols hace no use símbolos de depuración

De ahí el comportamiento que ha notado.


Para sus preguntas específicas:

  1. gdb es un depurador. Utiliza información de depuración en el ejecutable y las bibliotecas para mostrar información relevante. Es mucho más complejo que backtrace_symbols, e inspecciona los archivos reales en su unidad, además del proceso en vivo. backtrace_symbols no, está completamente en proceso, por lo que no puede acceder a las secciones que no están cargadas en la imagen ejecutable. Las secciones de depuración no se cargan en la imagen de tiempo de ejecución, por lo que no pueden usarlas.
  2. .dynsym no es una sección de depuración. Es una sección utilizada por el enlazador dinámico. .symbtab tampoco es una sección de depuración, pero puede ser utilizada por un depurador que tenga acceso a los archivos ejecutables (y de biblioteca). -rdynamicno genera secciones de depuración, solo esa tabla extendida de símbolos dinámicos. El crecimiento ejecutable desde -rdynamic depende completamente del número de símbolos en ese ejecutable (y consideraciones de alineación/relleno). Debe ser considerablemente menor que -g.
  3. A excepción de los binarios enlazados estáticamente, los ejecutables necesitan dependencias externas resueltas en el momento de la carga. Me gusta vincular printf y algunos procedimientos de inicio de aplicaciones de la biblioteca C. Estos símbolos externos se deben indicar en algún lugar del ejecutable: para esto se usa .dynsym, y esta es la razón por la cual el exe tiene un .dynsym incluso si no especifica -rdynamic. Cuando lo especifica, el vinculador agrega otros símbolos que no son necesarios para que el proceso funcione, pero puede ser utilizado por elementos como backtrace_symbols.
  4. backtrace_symbols no resolverá ningún nombre de función si enlaza estáticamente. Incluso si especifica -rdynamic, la sección .dynsym no se emitirá al ejecutable. No se cargan tablas de símbolos en la imagen ejecutable, por lo que backtrace_symbols no puede asignar direcciones de códigos a símbolos.
+0

gracias por la respuesta .. pero todavía estoy muy confundido .. me deja entrar mis preguntas como una respuesta separada para que pueda ser mejor formateado. – Manohar

+0

No ** publique una respuesta como seguimiento, no es así como funciona este sitio. Edite su pregunta original (o publique una nueva si su nueva pregunta es suficientemente diferente). – Mat

+0

@Santhosh: agregué información al final e intenté aclarar todo el asunto. HTH. – Mat

Cuestiones relacionadas