Escolhendo quais símbolos públicos remover
O PDBCopy fornece as opções -f e -F para que você possa remover um conjunto arbitrário de símbolos públicos de um arquivo de símbolo despojado, deixando apenas os símbolos que seu público precisa acessar para executar a depuração.
Um uso comum do PDBCopy é criar uma versão especial do arquivo de símbolo para uso pela Microsoft em seu programa OCA (Análise de Falhas Online). O OCA pode designar determinadas funções como inertes, o que significa que, se a função for encontrada no rastreamento de pilha, ela será ignorada. Uma função normalmente seria declarada inerte se fosse simplesmente uma função wrapper ou "passagem" que não executa cálculos significativos. Se essa função for encontrada na pilha em uma análise de falha, pode-se supor que essa função em si não foi uma falha e, no máximo, ela passou dados inválidos ou corrompidos que recebeu de rotinas anteriormente na pilha. Ignorando essas funções, o OCA pode determinar melhor a causa real do erro ou corrupção.
Naturalmente, qualquer função que você deseja declarar "inerte" precisa ser incluída na tabela de símbolos públicos do arquivo de símbolo usado pelo OCA. No entanto, essas não são as únicas funções que precisam ser incluídas, como mostra o exemplo a seguir.
Suponha que você escreva um driver do Windows e use PDBCopy para remover todos os símbolos públicos de seu arquivo de símbolo, exceto FunctionOne e FunctionSix, duas funções inertes. Sua expectativa é que, se FunctionOne ou FunctionSix forem encontrados na pilha após uma falha, eles serão ignorados pelo OCA. Se qualquer outra parte do driver estiver na pilha, a Microsoft fornecerá o endereço de memória correspondente e você poderá usar o endereço para depurar o driver.
No entanto, vamos supor que o driver ocupe a memória no seguinte layout:
Endereço | Conteúdo da memória |
---|---|
0x1000 |
Endereço base do módulo |
0x2000 |
Início do FunctionOne |
0x203F |
Fim do FunctionOne |
0x3000 |
Início do FunctionSix |
0x305F |
Fim do FunctionSix |
0x7fff |
Fim do módulo na memória |
Se o depurador encontrar um endereço na pilha, ele selecionará o símbolo com o próximo endereço inferior. Como a tabela de símbolos públicos contém o endereço de cada símbolo, mas nenhuma informação de tamanho, não há como o depurador saber se um endereço realmente está dentro dos limites de qualquer símbolo específico.
Portanto, se ocorrer uma falha no endereço 0x2031, o depurador executado pelo Microsoft OCA identificará corretamente a falha como em FunctionOne. Como essa é uma função inerte, o depurador continua percorrendo a pilha para encontrar a causa da falha.
No entanto, se ocorrer uma falha em 0x2052, o depurador ainda corresponderá esse endereço a FunctionOne, mesmo que ele esteja além do final real dessa função (0x203F).
Consequentemente, você deve incluir no arquivo de símbolo removido não apenas as funções que deseja expor, mas também os símbolos imediatamente após essas funções. Neste exemplo, você gostaria de expor FunctionOne, FunctionTwo, FunctionSix e FunctionSeven:
Endereço | Conteúdo da memória |
---|---|
0x1000 |
Endereço base do módulo |
0x2000 |
Início do FunctionOne |
0x203F |
Fim do FunctionOne |
0x2040 |
Início de FunctionTwo |
0x3000 |
Início do FunctionSix |
0x305F |
Fim do FunctionSix |
0x3060 |
Início do FunctionSeven |
0x7fff |
Fim do módulo na memória |
Se você incluir todas essas quatro funções no arquivo de símbolo removido, a análise do Microsoft OCA não tratará erroneamente o endereço 0x2052 como parte do FunctionOne. Neste exemplo, ele assumirá que esse endereço faz parte de FunctionTwo, mas isso não é importante porque você não registrou FunctionTwo com OCA como uma função inerte. O importante é que o endereço 0x2052 é reconhecido como não se enquadrando em uma função inerte e, portanto, o OCA reconhecerá isso como uma falha significativa no driver e poderá informá-lo sobre a falha.
Se você não quiser divulgar os nomes das funções após cada função inerte, poderá inserir funções não importantes em seu código seguindo cada função inerte para que os nomes dessas funções possam ser incluídos no arquivo de símbolo público. Certifique-se de verificar se essas funções adicionadas realmente seguem suas funções inerte no espaço de endereço do binário, pois algumas rotinas de otimização podem alterar isso ou até mesmo remover algumas funções inteiramente.