Öffentliche und private Symbole

Wenn eine vollständige PDB- oder DBG-Symboldatei von einem Linker erstellt wird, enthält sie zwei verschiedene Sammlungen von Informationen: die privaten Symboldaten und eine öffentliche Symboltabelle. Diese Auflistungen unterscheiden sich in der Liste der enthaltenen Elemente und den Informationen, die sie zu den einzelnen Elementen speichern.

Die Daten des privaten Symbols umfassen die folgenden Elemente:

  • Functions

  • Globale Variablen

  • Lokale Variablen

  • Informationen zu benutzerdefinierten Strukturen, Klassen und Datentypen

  • Der Name der Quelldatei und die Zeilennummer in dieser Datei, die den einzelnen binären Anweisungen entspricht

Die öffentliche Symboltabelle enthält weniger Elemente:

  • Funktionen (mit Ausnahme von statischen Funktionen)

  • Globale Variablen, die als extern angegeben sind (und alle anderen globalen Variablen, die über mehrere Objektdateien hinweg sichtbar sind)

In der Regel enthält die öffentliche Symboltabelle genau die Elemente, auf die von einer Quelldatei zur anderen zugegriffen werden kann. Elemente, die nur in einer Objektdatei sichtbar sind – z. B . statische Funktionen, Variablen, die nur innerhalb einer einzelnen Quelldatei global sind, und lokale Variablen – sind nicht in der öffentlichen Symboltabelle enthalten.

Diese beiden Datensammlungen unterscheiden sich auch darin, welche Informationen sie für jedes Element enthalten. Die folgenden Informationen sind in der Regel für jedes Element enthalten, das in den privaten Symboldaten enthalten ist:

  • Name des Elements

  • Adresse des Elements im virtuellen Speicher

  • Datentyp jeder Variablen, Struktur und Funktion

  • Typen und Namen der Parameter für jede Funktion

  • Bereich der einzelnen lokalen Variablen

  • Symbole, die jeder Zeile in jeder Quelldatei zugeordnet sind

  • Framepointer-Auslassungsdatensätze (Frame Pointer Omission, FPO) für jede Funktion, die für den Zugriff auf den Stapel verwendet wird

Andererseits speichert die öffentliche Symboltabelle nur die folgenden Informationen zu den einzelnen elementen, die darin enthalten sind:

  • Name des Elements.

  • Die Adresse des Elements im virtuellen Speicherbereich des Moduls. Bei einer Funktion ist dies die Adresse ihres Einstiegspunkts.

  • Framezeiger-Auslassungseinträge (Frame Pointer Omission, FPO) für jede Funktion.

  • Kann Symbolpräfixe/Suffixe enthalten, die als Dekorationen bezeichnet werden.

Die öffentlichen Symboldaten können auf zwei Arten als Teilmenge der privaten Symboldaten betrachtet werden: Sie enthalten eine kürzere Liste von Elementen und enthalten auch weniger Informationen zu den einzelnen Elementen. Beispielsweise enthalten die daten des öffentlichen Symbols überhaupt keine lokalen Variablen.

Jede lokale Variable ist nur in den privaten Symboldaten mit adresse, datentyp und bereich enthalten. Funktionen hingegen sind sowohl in den privaten Symboldaten als auch in der Tabelle für öffentliche Symbole enthalten, aber während die daten des privaten Symbols den Funktionsnamen, die Adresse, FPO-Datensätze, Eingabeparameternamen und -typen sowie den Ausgabetyp enthalten, enthält die öffentliche Symboltabelle nur den Funktionsnamen, die Adresse und den FPO-Eintrag.

Es gibt einen weiteren Unterschied zwischen den privaten Symboldaten und der öffentlichen Symboltabelle. Viele Der Elemente in der öffentlichen Symboltabelle haben Namen, die mit einem Präfix, einem Suffix oder beidem versehen sind. Diese Dekorationen werden vom C-Compiler, dem C++-Compiler und dem MASM-Assembler hinzugefügt. Typische Präfixe umfassen eine Reihe von Unterstrichen oder die Zeichenfolge __imp_ (Die Bezeichnung einer importierten Funktion). Typische Suffixe umfassen ein oder mehrere At-Zeichen ( @ ), gefolgt von Adressen oder anderen identifizierenden Zeichenfolgen. Diese Dekorationen werden vom Linker verwendet, um das Symbol zu unterscheiden, da es möglich ist, dass Funktionsnamen oder globale Variablennamen über verschiedene Module hinweg wiederholt werden können. Diese Dekorationen stellen eine Ausnahme von der allgemeinen Regel dar, dass die öffentliche Symboltabelle eine Teilmenge der privaten Symboldaten ist.

Vollständige Symboldateien und entfernte Symboldateien

Eine vollständige Symboldatei enthält sowohl die privaten Symboldaten als auch die öffentliche Symboltabelle. Diese Art von Datei wird manchmal als private Symboldatei bezeichnet, aber dieser Name ist irreführend, da eine solche Datei sowohl private als auch öffentliche Symbole enthält.

Eine Stripped-Symboldatei ist eine kleinere Datei, die nur die öffentliche Symboltabelle oder in einigen Fällen nur eine Teilmenge der öffentlichen Symboltabelle enthält. Diese Datei wird manchmal als öffentliche Symboldatei bezeichnet.

Erstellen vollständiger und entfernter Symboldateien

Wenn Sie Ihre Binärdateien mit Visual Studio erstellen, können Sie entweder vollständige oder entfernte Symboldateien erstellen. Informationen zum Erstellen von entfernten Symbolen finden Sie unter /PDBSTRIPPED (Strip Private Symbols).

Mit dem BinPlace-Tool können Sie eine Striped-Symboldatei aus einer vollständigen Symboldatei erstellen. Wenn die gängigsten BinPlace-Optionen verwendet werden (-a -x -s -n), werden die entfernten Symboldateien in dem Verzeichnis platziert, das nach dem Schalter -s aufgeführt ist, und die vollständigen Symboldateien werden in dem Verzeichnis platziert, das nach dem - n-Schalter aufgeführt ist. Wenn BinPlace eine Symboldatei entfernt, erhalten die stripped- und die Vollversion der Datei identische Signaturen und andere identifizierende Informationen. Dadurch können Sie beide Versionen zum Debuggen verwenden. Weitere Informationen zu BinPlace finden Sie unter BinPlace.

Mit dem PDBCopy-Tool können Sie eine striped-Symboldatei aus einer vollständigen Symboldatei erstellen, indem Sie die privaten Symboldaten entfernen. PDBCopy kann auch eine angegebene Teilmenge der öffentlichen Symboltabelle entfernen. Ausführliche Informationen finden Sie unter PDBCopy.

Mit dem SymChk-Tool können Sie ermitteln, ob eine Symboldatei private Symbole enthält. Ausführliche Informationen finden Sie unter SymChk.

Anzeigen öffentlicher und privater Symbole im Debugger

Sie können WinDbg, KD oder CDB verwenden, um Symbole anzuzeigen. Wenn einer dieser Debugger Zugriff auf eine vollständige Symboldatei hat, enthält er sowohl die in den privaten Symboldaten aufgeführten Informationen als auch die in der öffentlichen Symboltabelle aufgeführten Informationen. Die öffentlichen Symboldaten enthalten Symboldekorationen.

Beim Zugriff auf private Symbole werden immer private Symboldaten verwendet, da diese Symbole nicht in der öffentlichen Symboltabelle enthalten sind. Diese Symbole werden nie dekoriert.

Mit dem Befehl .symopt (Symboloptionen festlegen) können Sie die Symboloptionen steuern, die bestimmen, wie öffentliche und private Symbole vom Debugger verwendet werden. Mit diesem Befehl werden beispielsweise Debuginformationen für Symbole aktiviert.

 .symopt+ 0x80000000

Die folgenden Optionen ändern die Verwendung öffentlicher und privater Symbole im Debugger.

  • Wenn die Option SYMOPT_UNDNAME aktiviert ist, werden Keine Dekorationen eingeschlossen, wenn der Name eines öffentlichen Symbols angezeigt wird. Darüber hinaus werden bei der Suche nach Symbolen Dekorationen ignoriert. Wenn diese Option deaktiviert ist, werden Dekorationen angezeigt, wenn öffentliche Symbole angezeigt werden, und Dekorationen werden in Suchvorgängen verwendet. Private Symbole werden unter keinen Umständen dekoriert. Diese Option ist standardmäßig in allen Debuggern aktiviert.

  • Wenn die Option SYMOPT_PUBLICS_ONLY aktiviert ist, werden private Symboldaten ignoriert, und nur die öffentliche Symboltabelle wird verwendet. Diese Option ist in allen Debuggern standardmäßig deaktiviert.

  • Wenn die Option SYMOPT_NO_PUBLICS aktiviert ist, wird die öffentliche Symboltabelle ignoriert, und Suchen und Symbolinformationen verwenden allein die privaten Symboldaten. Diese Option ist in allen Debuggern standardmäßig deaktiviert.

  • Wenn die Option SYMOPT_AUTO_PUBLICS aktiviert ist (und sowohl SYMOPT_PUBLICS_ONLY als auch SYMOPT_NO_PUBLICS deaktiviert sind), wird die erste Symbolsuche in den privaten Symboldaten durchgeführt. Wenn das gewünschte Symbol dort gefunden wird, wird die Suche beendet. Andernfalls wird die öffentliche Symboltabelle durchsucht. Da die Öffentliche Symboltabelle eine Teilmenge der Symbole in den privaten Daten enthält, führt dies normalerweise dazu, dass die öffentliche Symboltabelle ignoriert wird.

  • Wenn die Optionen SYMOPT_PUBLICS_ONLY, SYMOPT_NO_PUBLICS und SYMOPT_AUTO_PUBLICS deaktiviert sind, werden sowohl private Symboldaten als auch die öffentliche Symboltabelle jedes Mal durchsucht, wenn ein Symbol benötigt wird. Wenn übereinstimmungen jedoch an beiden Stellen gefunden werden, wird die Übereinstimmung in den daten des privaten Symbols verwendet. Daher ist das Verhalten in diesem instance identisch mit dem Verhalten, wenn SYMOPT_AUTO_PUBLICS aktiviert ist, mit dem Unterschied, dass die Verwendung von SYMOPT_AUTO_PUBLICS dazu führen kann, dass Symbolsuchen etwas schneller erfolgen.

Hier sehen Sie ein Beispiel, in dem der Befehl x (Symbole untersuchen) dreimal verwendet wird. Beim ersten Mal werden die Standardsymboloptionen verwendet, sodass die Informationen aus den privaten Symboldaten übernommen werden. Beachten Sie, dass dies Informationen zu Adresse, Größe und Datentyp des Arrays typingString enthält. Als Nächstes wird der Befehl .symopt+ 4000 verwendet, sodass der Debugger die privaten Symboldaten ignoriert. Wenn der Befehl x erneut ausgeführt wird, wird die öffentliche Symboltabelle verwendet. Dieses Mal gibt es keine Größen- und Datentypinformationen für die TypisierungString. Schließlich wird der Befehl .symopt- 2 verwendet, wodurch der Debugger Dekorationen enthält. Wenn der x-Befehl dieses letzte Mal ausgeführt wird, wird die dekorierte Version des Funktionsnamens _typingString angezeigt.

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> 

Anzeigen öffentlicher und privater Symbole mit dem DBH-Tool

Eine weitere Möglichkeit zum Anzeigen von Symbolen ist die Verwendung des DBH-Tools . Zeigen Sie die Hilfeoptionen mithilfe der Option an /? .

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

Verwenden Sie ein Tool wie Tlist zum Auflisten von Prozess-IDs und die Option -p zum Anfügen an einen vorhandenen Prozess.

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

DBH verwendet dieselben Symboloptionen wie der Debugger. Wie der Debugger lässt DBH SYMOPT_PUBLICS_ONLY und SYMOPT_NO_PUBLICS standardmäßig aus und schaltet SYMOPT_UNDNAME und SYMOPT_AUTO_PUBLICS standardmäßig ein. Diese Standardwerte können durch eine Befehlszeilenoption oder durch einen DBH-Befehl überschrieben werden.

Hier ist ein Beispiel, in dem der DBH-Befehl addr 414fe0 dreimal verwendet wird. Beim ersten Mal werden die Standardsymboloptionen verwendet, sodass die Informationen aus den privaten Symboldaten übernommen werden. Beachten Sie, dass dies Informationen zu Adresse, Größe und Datentyp der Funktionsfgets enthält. Als Nächstes wird der Befehl symopt +4000 verwendet, wodurch DBH die privaten Symboldaten ignoriert. Wenn der Addr 414fe0 erneut ausgeführt wird, wird die öffentliche Symboltabelle verwendet. Dieses Mal gibt es keine Größen- und Datentypinformationen für die Funktionsfgets. Schließlich wird der Befehl symopt -2 verwendet, wodurch DBH Dekorationen enthält. Wenn der Addr 414fe0 dieses letzte Mal ausgeführt wird, wird die dekorierte Version des Funktionsnamens _fgets angezeigt.

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 

Zusätzliche Informationen

Weitere Informationen zu Symbolen finden Sie unter Symbolsyntax und Symbolabgleich, Symboloptionen, Symbolstatus-Abkürzungen und verzögertes Laden von Symbolen.