Símbolos públicos e privados

Quando um arquivo de símbolo .pdb ou .dbg de tamanho completo é criado por um vinculador, ele contém duas coleções distintas de informações: os dados de símbolo privado e uma tabela de símbolos públicos. Essas coleções diferem na lista de itens que contêm e nas informações que armazenam sobre cada item.

Os dados de símbolo privado incluem os seguintes itens:

  • Funções

  • Variáveis globais

  • Variáveis locais

  • Informações sobre estruturas, classes e tipos de dados definidos pelo usuário

  • O nome do arquivo de origem e o número de linha nesse arquivo correspondente a cada instrução binária

A tabela de símbolos públicos contém menos itens:

  • Funções (exceto para funções declaradas estáticas)

  • Variáveis globais especificadas como extern (e quaisquer outras variáveis globais visíveis em vários arquivos de objeto)

Como regra geral, a tabela de símbolos públicos contém exatamente os itens acessíveis de um arquivo de origem para outro. Os itens visíveis em apenas um arquivo de objeto, como funções estáticas , variáveis globais somente dentro de um único arquivo de origem e variáveis locais, não são incluídos na tabela de símbolos públicos.

Essas duas coleções de dados também diferem em quais informações elas incluem para cada item. Normalmente, as seguintes informações são incluídas para cada item contido nos dados de símbolo privado :

  • Nome do item

  • Endereço do item na memória virtual

  • Tipo de dados de cada variável, estrutura e função

  • Tipos e nomes dos parâmetros para cada função

  • Escopo de cada variável local

  • Símbolos associados a cada linha em cada arquivo de origem

  • Registros de FPO (omissão de ponteiro de quadro) para cada função usada para acessar a pilha

Por outro lado, a tabela de símbolos públicos armazena apenas as seguintes informações sobre cada item incluído nele:

  • O nome do item.

  • O endereço do item no espaço de memória virtual de seu módulo. Para uma função, esse é o endereço de seu ponto de entrada.

  • Registros de FPO (omissão de ponteiro de quadro) para cada função.

  • Pode incluir prefixo/sufixos de símbolos conhecidos como decorações.

Os dados de símbolo público podem ser considerados como um subconjunto dos dados de símbolo privado de duas maneiras: ele contém uma lista mais curta de itens e também contém menos informações sobre cada item. Por exemplo, os dados de símbolo público não incluem variáveis locais.

Cada variável local é incluída apenas nos dados de símbolo privado, com seu endereço, tipo de dados e escopo. As funções, por outro lado, são incluídas nos dados de símbolo privado e na tabela de símbolos públicos, mas enquanto os dados de símbolo privado incluem o nome da função, o endereço, os registros FPO, os nomes e tipos de parâmetro de entrada e o tipo de saída, a tabela de símbolos públicos inclui apenas o nome da função, o endereço e o registro FPO.

Há uma outra diferença entre os dados de símbolo privado e a tabela de símbolos públicos. Muitos dos itens na tabela de símbolos públicos têm nomes decorados com um prefixo, um sufixo ou ambos. Essas decorações são adicionadas pelo compilador C, pelo compilador C++ e pelo assembler MASM. Prefixos típicos incluem uma série de sublinhados ou a cadeia de caracteres __imp_ (designando uma função importada). Os sufixos típicos incluem um ou mais sinais ( @ ) seguidos por endereços ou outras cadeias de caracteres de identificação. Essas decorações são usadas pelo vinculador para desambiguar o símbolo, pois é possível que nomes de função ou nomes de variáveis globais possam ser repetidos em diferentes módulos. Essas decorações são uma exceção à regra geral de que a tabela de símbolos públicos é um subconjunto dos dados de símbolo privado.

Arquivos de símbolo completos e arquivos de símbolos removidos

Um arquivo de símbolo completo contém os dados de símbolo privado e a tabela de símbolos públicos. Esse tipo de arquivo às vezes é chamado de arquivo de símbolo privado, mas esse nome é enganoso, pois esse arquivo contém símbolos públicos e privados.

Um arquivo de símbolo despojado é um arquivo menor que contém apenas a tabela de símbolos públicos ou, em alguns casos, apenas um subconjunto da tabela de símbolos públicos. Às vezes, esse arquivo é chamado de arquivo de símbolo público.

Criando arquivos de símbolo completos e despojados

Se você criar seus binários com o Visual Studio, poderá criar arquivos de símbolo completos ou removidos. Para obter informações sobre como criar símbolos removidos, consulte /PDBSTRIPPED (Remover símbolos privados).

Usando a ferramenta BinPlace, você pode criar um arquivo de símbolo removido de um arquivo de símbolo completo. Quando as opções mais comuns do BinPlace são usadas (-a -x -s -n), os arquivos de símbolo removidos são colocados no diretório listado após a opção -s e os arquivos de símbolo completos são colocados no diretório listado após a opção -n . Quando o BinPlace remove um arquivo de símbolo, as versões despojadas e completas do arquivo recebem assinaturas idênticas e outras informações de identificação. Isso permite que você use qualquer versão para depuração. Para obter mais informações sobre o BinPlace, consulte BinPlace.

Usando a ferramenta PDBCopy, você pode criar um arquivo de símbolo removido de um arquivo de símbolo completo removendo os dados de símbolo privado. O PDBCopy também pode remover um subconjunto especificado da tabela de símbolos públicos. Para obter detalhes, consulte PDBCopy.

Usando a ferramenta SymChk, você pode determinar se um arquivo de símbolo contém símbolos privados. Para obter detalhes, consulte SymChk.

Exibindo símbolos públicos e privados no depurador

Você pode usar WinDbg, KD ou CDB para exibir símbolos. Quando um desses depuradores tem acesso a um arquivo de símbolo completo, ele tem as informações listadas nos dados de símbolo privado e as informações listadas na tabela de símbolos públicos. Os dados de símbolo público contêm decorações de símbolo.

Ao acessar símbolos privados, os dados de símbolo privado sempre são usados porque esses símbolos não são incluídos na tabela de símbolos públicos. Esses símbolos nunca são decorados.

O comando .symopt (Definir Opções de Símbolo) pode ser usado para controlar as opções de símbolo que determinam como os símbolos públicos e privados são usados pelo depurador. Por exemplo, este comando ativa as informações de depuração de símbolos.

 .symopt+ 0x80000000

As opções a seguir alteram como os símbolos públicos e privados são usados no depurador.

  • Quando a opção SYMOPT_UNDNAME está ativada, as decorações não são incluídas quando o nome de um símbolo público é exibido. Além disso, ao pesquisar símbolos, as decorações são ignoradas. Quando essa opção está desativada, as decorações são exibidas ao exibir símbolos públicos e as decorações são usadas em pesquisas. Símbolos privados nunca são decorados em nenhuma circunstância. Essa opção está ativada por padrão em todos os depuradores.

  • Quando a opção SYMOPT_PUBLICS_ONLY está ativada, os dados de símbolo privado são ignorados e apenas a tabela de símbolos públicos é usada. Essa opção está desativada por padrão em todos os depuradores.

  • Quando a opção SYMOPT_NO_PUBLICS está ativada, a tabela de símbolos públicos é ignorada e as pesquisas e as informações de símbolo usam apenas os dados de símbolo privado. Essa opção está desativada por padrão em todos os depuradores.

  • Quando a opção SYMOPT_AUTO_PUBLICS está ativada (e as SYMOPT_PUBLICS_ONLY e SYMOPT_NO_PUBLICS estão desativadas), a primeira pesquisa de símbolos é executada nos dados de símbolo privado. Se o símbolo desejado for encontrado lá, a pesquisa será encerrada. Caso contrário, a tabela de símbolos públicos será pesquisada. Como a tabela de símbolos públicos contém um subconjunto dos símbolos nos dados privados, normalmente isso faz com que a tabela de símbolos públicos seja ignorada.

  • Quando as opções SYMOPT_PUBLICS_ONLY, SYMOPT_NO_PUBLICS e SYMOPT_AUTO_PUBLICS estiverem desativadas, os dados de símbolo privado e a tabela de símbolos públicos serão pesquisados sempre que um símbolo for necessário. No entanto, quando as correspondências são encontradas em ambos os locais, a correspondência nos dados de símbolo privado é usada. Portanto, o comportamento nessa instância é o mesmo de quando SYMOPT_AUTO_PUBLICS está ativado, exceto que o uso de SYMOPT_AUTO_PUBLICS pode fazer com que as pesquisas de símbolos ocorram um pouco mais rapidamente.

Aqui está um exemplo no qual o comando x (Examinar Símbolos) é usado três vezes. Na primeira vez, as opções de símbolo padrão são usadas e, portanto, as informações são obtidas dos dados de símbolo privado. Observe que isso inclui informações sobre o endereço, o tamanho e o tipo de dados da matriz typingString. Em seguida, o comando .symopt+ 4000 é usado, fazendo com que o depurador ignore os dados do símbolo privado. Quando o comando x é executado novamente, a tabela de símbolos públicos é usada; desta vez, não há informações de tamanho e tipo de dados para typingString. Por fim, o comando .symopt- 2 é usado, o que faz com que o depurador inclua decorações. Quando o comando x é executado desta hora final, a versão decorada do nome da função, _typingString, é mostrada.

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> 

Exibindo símbolos públicos e privados com a ferramenta DBH

Outra maneira de exibir símbolos é usando a ferramenta DBH . Exiba as opções de ajuda usando a opção /? .

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

Use uma ferramenta como tlist para listar IDs de processo e a opção -p para anexar a um processo existente.

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

O DBH usa as mesmas opções de símbolo que o depurador. Assim como o depurador, o DBH deixa SYMOPT_PUBLICS_ONLY e SYMOPT_NO_PUBLICS desativados por padrão e ativa SYMOPT_UNDNAME e SYMOPT_AUTO_PUBLICS por padrão. Esses padrões podem ser substituídos por uma opção de linha de comando ou por um comando DBH.

Aqui está um exemplo no qual o adidor de comando DBH 414fe0 é usado três vezes. Na primeira vez, as opções de símbolo padrão são usadas e, portanto, as informações são obtidas dos dados de símbolo privado. Observe que isso inclui informações sobre o endereço, o tamanho e o tipo de dados dos fgets de função. Em seguida, o comando symopt +4000 é usado, o que faz com que a DBH ignore os dados do símbolo privado. Quando o complemento 414fe0 é executado novamente, a tabela de símbolos públicos é usada; desta vez, não há informações de tamanho e tipo de dados para os fgets de função. Por fim, o comando symopt -2 é usado, o que faz com que a DBH inclua decorações. Quando o suplemento 414fe0 é executado nesta hora final, a versão decorada do nome da função, _fgets, é mostrada.

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 

Informações adicionais

Para obter informações adicionais sobre símbolos, consulte Sintaxe de símbolo e correspondência de símbolos, opções de símbolo, abreviações de status de símbolo e carregamento de símbolo adiado.