symboles de débogage gcc (- drapeau g) vs option de linker-rdynamic

glibc fournit backtrace() et backtrace_symbols() pour obtenir la trace de la pile d'exécution d'un programme. Mais pour que cela fonctionne, le programme doit être construit avec linker -rdynamic drapeau.

Quelle est la différence entre -g drapeau passé à gcc vs linker -rdynamic drapeau ? Pour un exemple de code, je me suis lu pour comparer les sorties. -rdynamic semble produire plus d'infos sous Symbol table '.dynsym' mais je ne suis pas tout à fait sûr de ce qu'est l'info supplémentaire.

même si je strip un programme binaire en utilisant -rdynamic,backtrace_symbols() continuer à travailler.

Quand strip supprime tous les symboles du binaire pourquoi laisse-t-il ce qui a été ajouté par le -rdynamic drapeau ?

modifier: questions de suivi basées sur la réponse de Mat ci-dessous..

Pour le même exemple de code que vous avez pris c'est la différence que je vois avec -g& -rdynamic

sans aucune option..

    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 __libc_start_main@GLIBC_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 

-g il y a plus d'articles, plus d'entrées dans .symtab tableau .dynsym reste le même..

      [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 __libc_start_main@GLIBC_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 

-rdynamic pas de sections de débogage supplémentaires,.symtab entrées sont 70 (de même que la vanille gcc invocation), mais plus .dynsym entrées..

    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 __libc_start_main@GLIBC_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 

Maintenant, ce sont les questions que j'ai..

  1. dans gdb vous pouvez faire bt pour obtenir le bactrace. Si cela fonctionne avec juste -g pourquoi avons-nous besoin d' -rdynamic pour que backtrace_symbols fonctionne ?

  2. Comparaison de la ajouts .symtab-g & ajouts .dynsym-rdynamic ils ne sont pas exactement les mêmes.. Ne soit un fournir de meilleures informations de débogage par rapport à l'autre ? FWIW, la taille de la sortie produite est comme ceci: avec -g > avec -rdynamic > ni avec l'option

  3. Quelle est exactement l'utilisation de .dynsym ? Est-ce que tous les symboles exportés par ce binaire ? Dans ce cas, pourquoi est-foo .dynsym parce que nous ne compilons pas le code bibliothèque.

  4. si je lie mon code en utilisant toutes les bibliothèques statiques alors-rdynamic n'est pas nécessaire pour que backtrace_symbols fonctionne ?

29
demandé sur Dr. Tenma 2011-12-24 14:07:29

1 réponses

selon les docs:

Ceci indique au linker d'ajouter tous les symboles, pas seulement ceux utilisés, à la table de symboles dynamiques.

ce ne sont pas des symboles de débogage, ce sont des symboles de linker dynamique. Ceux-ci ne sont pas enlevés par strip puisqu'il briserait (dans la plupart des cas) l'exécutable - ils sont utilisés par le linker d'exécution pour faire l'étape finale du lien de votre exécutable.

Exemple:

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

Compiler et lier sans -rdynamic (et pas des optimisations, évidemment)

$ 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 __libc_start_main@GLIBC_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

donc l'exécutable a un .symtab avec tout. Mais remarquez que .dynsym ne mentionne pas foo - c'est l'essentiel. Ce n'est pas de suffisamment d'informations pour backtrace_symbols au travail. Il s'appuie sur les informations présentes dans cette section pour faire correspondre les adresses de code avec les noms de fonction.

Maintenant compiler -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 __libc_start_main@GLIBC_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

Même chose pour les symboles .symtab, mais maintenant foo a un symbole dans la section de symbole dynamique (et un tas d'autres symboles y apparaissent aussi maintenant). Cela rend backtrace_symbols work-it dispose maintenant de suffisamment d'informations (dans la plupart des cas) pour cartographier les adresses de code avec les noms de fonction.

Bande:

$ 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 __libc_start_main@GLIBC_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
$

Aucun .symtab est parti, mais la table de symboles dynamique est toujours là, et l'exécutable s'exécute. Donc backtrace_symbols fonctionne toujours trop.

la Bande de la dynamique de la table des symboles:

$ 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

... et vous obtenez une fracture de l'exécutable.

Une lecture intéressante pour ce qu' .symtab et .dynsym sont utilisés, c'est ici: à l'Intérieur de l'ELFE Tables de symboles. Une des choses à noter est que .symtab n'est pas nécessaire à l'exécution, il est donc rejeté par le chargeur. Cette section ne reste pas dans la mémoire du processus. .dynsym, par contre, nécessaire à l'exécution, il est donc conservé dans l'image process. Il est donc disponible pour des choses comme backtrace_symbols pour recueillir des informations sur l' processus actuel de l'intérieur de lui-même.

Donc en bref:

  • symboles dynamiques ne sont pas supprimés par strip puisque cela rendrait l'exécutable Non-chargeable
  • backtrace_symbols nécessite des symboles dynamiques pour comprendre quel code appartient à quelle fonction
  • backtrace_symbols n'utilise pas de symboles de débogage

D'où le comportement que vous avez remarqué.


Pour votre questions:

  1. gdb est un débogueur. Il utilise les informations de débogage dans l'exécutable et les bibliothèques pour afficher les informations pertinentes. C'est beaucoup plus complexe que backtrace_symbols, et inspecte les fichiers sur votre disque dur en plus du live processus. backtrace_symbols ne fonctionne pas, il est entièrement en cours de traitement-de sorte qu'il ne peut pas accéder aux sections qui ne sont pas chargées dans l'image exécutable. Les sections de débogage ne sont pas chargées dans l'image d'exécution, donc elle ne peut pas utiliser ils.
  2. .dynsym n'est pas une section débogage. C'est une section utilisée par le dynamic linker. .symbtab n'est pas non plus une section de débogage, mais elle peut être utilisée par les débogueurs qui ont accès aux fichiers exécutables (et à la bibliothèque). -rdynamicne pas générer des sections de débogage, seulement cette table étendue de symboles dynamiques. La croissance exécutable de -rdynamic dépend entièrement du nombre de symboles dans cet exécutable (et des considérations d'alignement/remplissage). Il devrait être beaucoup moins que -g.
  3. sauf pour les binaires statiquement liés, les exécutables ont besoin de dépendances externes résolues au moment du chargement. Comme lier printf et quelques procédures de démarrage d'application de la bibliothèque C. Ces symboles externes doivent être indiqués quelque part dans l'exécutable: c'est ce que .dynsym est utilisé pour, et c'est pourquoi le fichier exe a une .dynsym même si vous ne spécifiez pas -rdynamic. Lorsque vous ne spécifiez, le linker ajoute d'autres symboles qui ne sont pas nécessaires pour le processus de travail, mais peut être utilisé par des choses comme backtrace_symbols.
  4. backtrace_symbols ne résoudra aucun nom de fonction si vous faites un lien statique. Même si vous spécifiez -rdynamic, le .dynsym la section ne sera pas émise à l'exécutable. Aucune table de symboles n'est chargée dans l'image exécutable, donc backtrace_symbols impossible de cartographier les adresses des codes aux symboles.
39
répondu Mat 2011-12-24 20:23:41