Symboles publics et privés

Lorsqu’un fichier de symboles .pdb ou .dbg de taille réelle est créé par un éditeur de liens, il contient deux collections distinctes d’informations : les données de symboles privés et une table de symboles publics. Ces collections diffèrent par la liste des éléments qu’elles contiennent et les informations qu’elles stockent sur chaque élément.

Les données de symbole privé incluent les éléments suivants :

  • Fonctions

  • Variables globales

  • Variables locales

  • Informations sur les structures, classes et types de données définis par l’utilisateur

  • Nom du fichier source et numéro de ligne dans ce fichier correspondant à chaque instruction binaire

La table de symboles publics contient moins d’éléments :

  • Fonctions (à l’exception des fonctions déclarées statiques)

  • Variables globales spécifiées en tant qu’extern (et toutes les autres variables globales visibles dans plusieurs fichiers objet)

En règle générale, la table de symboles publics contient exactement les éléments accessibles d’un fichier source à un autre. Les éléments visibles dans un seul fichier objet, tels que les fonctions statiques , les variables globales uniquement dans un seul fichier source et les variables locales, ne sont pas inclus dans la table de symboles publics.

Ces deux collections de données diffèrent également par les informations qu’elles incluent pour chaque élément. Les informations suivantes sont généralement incluses pour chaque élément contenu dans les données de symboles privés :

  • Nom de l’élément

  • Adresse de l’élément dans la mémoire virtuelle

  • Type de données de chaque variable, structure et fonction

  • Types et noms des paramètres de chaque fonction

  • Étendue de chaque variable locale

  • Symboles associés à chaque ligne de chaque fichier source

  • Enregistrements d’omission de pointeur de trame (FPO) pour chaque fonction utilisée pour accéder à la pile

D’autre part, la table de symboles publics stocke uniquement les informations suivantes sur chaque élément qu’elle contient :

  • Nom de l'élément.

  • Adresse de l’élément dans l’espace de mémoire virtuel de son module. Pour une fonction, il s’agit de l’adresse de son point d’entrée.

  • Enregistrements d’omission de pointeur de trame (FPO) pour chaque fonction.

  • Peut inclure des préfixes/suffixes de symbole appelés décorations.

Les données de symboles publics peuvent être considérées comme un sous-ensemble des données de symboles privés de deux manières : elles contiennent une liste plus courte d’éléments et elles contiennent également moins d’informations sur chaque élément. Par exemple, les données de symbole public n’incluent pas du tout les variables locales.

Chaque variable locale est incluse uniquement dans les données de symbole privé, avec son adresse, son type de données et son étendue. Les fonctions, en revanche, sont incluses à la fois dans les données de symboles privés et dans la table de symboles publics, mais alors que les données de symboles privés incluent le nom de la fonction, l’adresse, les enregistrements FPO, les noms et types de paramètres d’entrée et le type de sortie, la table de symboles publics inclut uniquement le nom de la fonction, l’adresse et l’enregistrement FPO.

Il existe une autre différence entre les données de symboles privés et la table de symboles publics. La plupart des éléments de la table de symboles publics ont des noms décorés d’un préfixe, d’un suffixe ou des deux. Ces décorations sont ajoutées par le compilateur C, le compilateur C++ et l’assembleur MASM. Les préfixes classiques incluent une série de traits de soulignement ou la chaîne __imp_ (désignant une fonction importée). Les suffixes classiques incluent un ou plusieurs signes ( @ ) suivis d’adresses ou d’autres chaînes d’identification. Ces décorations sont utilisées par l’éditeur de liens pour lever l’ambiguïté du symbole, car il est possible que des noms de fonction ou des noms de variables globales puissent être répétés dans différents modules. Ces décorations constituent une exception à la règle générale selon laquelle la table de symboles publics est un sous-ensemble des données de symboles privés.

Fichiers de symboles complets et fichiers de symboles supprimés

Un fichier de symboles complet contient à la fois les données de symboles privés et la table de symboles publics. Ce type de fichier est parfois appelé fichier de symboles privé, mais ce nom est trompeur, car un tel fichier contient des symboles privés et publics.

Un fichier de symboles supprimé est un fichier plus petit qui contient uniquement la table de symboles publics ou, dans certains cas, uniquement un sous-ensemble de la table de symboles publics. Ce fichier est parfois appelé fichier de symboles publics.

Création de fichiers de symboles complets et supprimés

Si vous générez vos fichiers binaires avec Visual Studio, vous pouvez créer des fichiers de symboles complets ou supprimés. Pour plus d’informations sur la création de symboles supprimés, consultez /PDBSTRIPPED (Symboles privés de bande) .

À l’aide de l’outil BinPlace, vous pouvez créer un fichier de symboles supprimé à partir d’un fichier de symboles complet. Lorsque les options BinPlace les plus courantes sont utilisées (-a -x -s -n), les fichiers de symboles supprimés sont placés dans le répertoire répertorié après le commutateur -s , et les fichiers de symboles complets sont placés dans le répertoire répertorié après le commutateur -n . Lorsque BinPlace supprime un fichier de symboles, les versions supprimées et complètes du fichier reçoivent des signatures identiques et d’autres informations d’identification. Cela vous permet d’utiliser l’une ou l’autre version pour le débogage. Pour plus d’informations sur BinPlace, consultez BinPlace.

À l’aide de l’outil PDBCopy, vous pouvez créer un fichier de symboles supprimé à partir d’un fichier de symboles complet en supprimant les données de symboles privés. PDBCopy peut également supprimer un sous-ensemble spécifié de la table de symboles publics. Pour plus d’informations, consultez PDBCopy.

À l’aide de l’outil SymChk, vous pouvez déterminer si un fichier de symboles contient des symboles privés. Pour plus d’informations, consultez SymChk.

Affichage des symboles publics et privés dans le débogueur

Vous pouvez utiliser WinDbg, KD ou CDB pour afficher les symboles. Quand l’un de ces débogueurs a accès à un fichier de symboles complet, il a à la fois les informations répertoriées dans les données de symboles privés et les informations répertoriées dans la table de symboles publics. Les données de symbole public contiennent des décorations de symboles.

Lors de l’accès aux symboles privés, les données de symboles privés sont toujours utilisées, car ces symboles ne sont pas inclus dans la table de symboles publics. Ces symboles ne sont jamais décorés.

La commande .symopt (Définir les options de symbole) peut être utilisée pour contrôler les options de symbole qui déterminent la façon dont les symboles publics et privés sont utilisés par le débogueur. Par exemple, cette commande active les informations de débogage des symboles.

 .symopt+ 0x80000000

Les options suivantes modifient la façon dont les symboles publics et privés sont utilisés dans le débogueur.

  • Lorsque l’option SYMOPT_UNDNAME est activée, les décorations ne sont pas incluses lorsque le nom d’un symbole public est affiché. De plus, lors de la recherche de symboles, les décorations sont ignorées. Lorsque cette option est désactivée, les décorations sont affichées lors de l’affichage de symboles publics, et les décorations sont utilisées dans les recherches. Les symboles privés ne sont jamais décorés en aucune circonstance. Cette option est activée par défaut dans tous les débogueurs.

  • Lorsque l’option SYMOPT_PUBLICS_ONLY est activée, les données de symbole privé sont ignorées et seule la table de symboles publics est utilisée. Cette option est désactivée par défaut dans tous les débogueurs.

  • Lorsque l’option SYMOPT_NO_PUBLICS est activée, la table de symboles publics est ignorée et les recherches et les informations sur les symboles utilisent uniquement les données de symbole privé. Cette option est désactivée par défaut dans tous les débogueurs.

  • Lorsque l’option SYMOPT_AUTO_PUBLICS est activée (et que SYMOPT_PUBLICS_ONLY et SYMOPT_NO_PUBLICS sont désactivés), la première recherche de symboles est effectuée dans les données de symboles privés. Si le symbole souhaité y est trouvé, la recherche se termine. Si ce n’est pas le cas, la table de symboles publics fait l’objet d’une recherche. Étant donné que la table de symboles publics contient un sous-ensemble des symboles dans les données privées, la table de symboles publics est généralement ignorée.

  • Lorsque les options SYMOPT_PUBLICS_ONLY, SYMOPT_NO_PUBLICS et SYMOPT_AUTO_PUBLICS sont toutes désactivées, les données de symboles privés et la table de symboles publics sont recherchées chaque fois qu’un symbole est nécessaire. Toutefois, lorsque des correspondances sont trouvées dans les deux emplacements, la correspondance dans les données de symbole privé est utilisée. Par conséquent, le comportement dans cette instance est le même que lorsque SYMOPT_AUTO_PUBLICS est activé, sauf que l’utilisation de SYMOPT_AUTO_PUBLICS peut entraîner une légère accélération des recherches de symboles.

Voici un exemple dans lequel la commande x (Examiner les symboles) est utilisée trois fois. La première fois, les options de symbole par défaut sont utilisées, de sorte que les informations sont extraites des données de symbole privé. Notez que cela inclut des informations sur l’adresse, la taille et le type de données du tableau typingString. Ensuite, la commande .symopt+ 4000 est utilisée, ce qui fait que le débogueur ignore les données de symboles privés. Lorsque la commande x est réexécuter, la table de symboles publics est utilisée ; cette fois, il n’y a pas d’informations sur la taille et le type de données pour typingString. Enfin, la commande .symopt- 2 est utilisée, ce qui permet au débogueur d’inclure des décorations. Lorsque la commande x est exécutée cette dernière fois, la version décorée du nom de la fonction, _typingString, s’affiche.

0:000> x /t /d *!*typingstring* 
00434420 char [128] TimeTest!typingString = char [128] ""

0:000> .symopt+ 4000

0:000> x /t /d *!*typingstring* 
00434420 <NoType> TimeTest!typingString = <no type information>

0:000> .symopt- 2

0:000> x /t /d *!*typingstring* 
00434420 <NoType> TimeTest!_typingString = <no type information> 

Affichage des symboles publics et privés avec l’outil DBH

Une autre façon d’afficher les symboles consiste à utiliser l’outil DBH . Affichez les options d’aide à l’aide de l’option /? .

C:\Program Files (x86)\Windows Kits\10\Debuggers\x64>dbh /?
dbh dbghelp shell
usage: dbh [-n] [-c] [-d] [-?] [-??] [-p] [targetmodule] [command]
       [-n]             display noisy symbol spew
       [-d]             use decorated publics
       [-p:XXXX]        attaches to process ID XXXX
       [-s:SSSS]        set symbol path to SSSS
       [-c]             callbacks return false
       [targetmodule]   load symbols for specified module
       [command]        execute command and exit
       [-?]             display these usage instructions
       [-??]            display detailed usage instructions

Utilisez un outil tel que Tlist pour répertorier les ID de processus et l’option -p pour l’attacher à un processus existant.

C:\Program Files (x86)\Windows Kits\10\Debuggers\x64>dbh -p:4308

DBH utilise les mêmes options de symbole que le débogueur. Comme le débogueur, DBH laisse SYMOPT_PUBLICS_ONLY et SYMOPT_NO_PUBLICS désactivés par défaut, puis active SYMOPT_UNDNAME et SYMOPT_AUTO_PUBLICS activés par défaut. Ces valeurs par défaut peuvent être remplacées par une option de ligne de commande ou par une commande DBH.

Voici un exemple dans lequel le addr de commande DBH 414fe0 est utilisé trois fois. La première fois, les options de symbole par défaut sont utilisées et les informations sont donc extraites des données de symboles privés. Notez que cela inclut des informations sur l’adresse, la taille et le type de données de la fonction fgets. Ensuite, la commande symopt +4000 est utilisée, ce qui fait que DBH ignore les données de symboles privés. Lorsque l’addr 414fe0 est réexécuté, la table de symboles publics est utilisée ; cette fois, il n’existe aucune information de taille et de type de données pour la fonction fgets. Enfin, la commande symopt -2 est utilisée, ce qui amène DBH à inclure des décorations. Lorsque le module complémentaire 414fe0 est exécuté cette dernière fois, la version décorée du nom de la fonction, _fgets, s’affiche.

pid:4308 mod:TimeTest[400000]: addr 414fe0

fgets
   name : fgets
   addr :   414fe0
   size : 113
  flags : 0
   type : 7e
modbase :   400000
  value :        0
    reg : 0
  scope : SymTagNull (0)
    tag : SymTagFunction (5)
  index : 7d

pid:4308 mod:TimeTest[400000]: symopt +4000

Symbol Options: 0x10c13
Symbol Options: 0x14c13

pid:4308 mod:TimeTest[400000]: addr 414fe0

fgets
   name : fgets
   addr :   414fe0
   size : 0
  flags : 0
   type : 0
modbase :   400000
  value :        0
    reg : 0
  scope : SymTagNull (0)
    tag : SymTagPublicSymbol (a)
  index : 7f

pid:4308 mod:TimeTest[400000]: symopt -2

Symbol Options: 0x14c13
Symbol Options: 0x14c11

pid:4308 mod:TimeTest[400000]: addr 414fe0

_fgets
   name : _fgets
   addr :   414fe0
   size : 0
  flags : 0
   type : 0
modbase :   400000
  value :        0
    reg : 0
  scope : SymTagNull (0)
    tag : SymTagPublicSymbol (a)
  index : 7f 

Informations supplémentaires

Pour plus d’informations sur les symboles, consultez Syntaxe des symboles et correspondance de symboles, Options de symbole, Abréviations d’état des symboles et Chargement différé de symboles.