Debug con simboli

Questo articolo offre una panoramica generale di come usare meglio i simboli nel processo di debug. Viene illustrato come usare il server dei simboli Microsoft e come configurare e usare il proprio server di simboli privato. Queste procedure consigliate consentono di aumentare l'efficacia e la capacità di eseguire il debug dei problemi, anche nei casi in cui tutti i simboli e i file eseguibili correlati a un problema non si trovano nel computer.

Simboli

Per il debug sono disponibili diversi tipi di simboli. Includono simboli CodeView, COFF, DBG, SYM, PDB e persino simboli di esportazione generati da una tabella di esportazione di file binari. Questo white paper illustra solo VS.NET e i simboli di formato PDB, perché sono il formato preferito più recente. Vengono generati per impostazione predefinita per i progetti compilati tramite Visual Studio.

La generazione di file PDB per i file eseguibili di versione non influisce sulle ottimizzazioni o modifica significativamente le dimensioni dei file generati. In genere, l'unica differenza è il percorso e il nome file del file PDB è incorporato nell'eseguibile. Per questo motivo, è consigliabile produrre sempre file PDB, anche se non si vuole spedirli con l'eseguibile.

I file PDB vengono generati se un progetto viene compilato usando l'opzione del compilatore /Zi o /ZI (Produce informazioni PDB), insieme all'opzione del linker /DEBUG (Generate Debug Info). I file PDB generati dal compilatore vengono combinati e scritti in un singolo file PDB inserito nella stessa directory del file eseguibile.

Per impostazione predefinita, i file PDB contengono le informazioni seguenti:

  • Simboli pubblici (in genere tutte le funzioni, variabili statiche e globali)
  • Elenco di file oggetto responsabili di sezioni di codice nel file eseguibile
  • Informazioni sull'ottimizzazione del puntatore a frame (FPO)
  • Informazioni sul nome e sul tipo per variabili e strutture di dati locali
  • Informazioni sul file di origine e sul numero di riga

Se si è preoccupati per gli utenti che usano le informazioni sul file PDB per aiutarli a decompilare il file eseguibile, è anche possibile generare file PDB rimossi usando l'opzione /PDBSTRIPPED:filename linker. Se si dispone di file PDB esistenti da cui si desidera rimuovere le informazioni private, è possibile usare uno strumento denominato pdbcopy, che fa parte degli strumenti di debug per Windows.

Per impostazione predefinita, i file PDB rimossi contengono le informazioni seguenti:

  • Simboli pubblici (in genere solo funzioni non statiche e variabili globali)
  • Elenco di file oggetto responsabili di sezioni di codice nel file eseguibile
  • Informazioni sull'ottimizzazione del puntatore a frame (FPO)

Si tratta delle informazioni minime necessarie per consentire il debug affidabile. Le informazioni minime rendono anche difficile ottenere informazioni aggiuntive sul codice sorgente originale. Poiché vengono generati sia un file PDB rimosso che un normale file PDB, è possibile fornire la versione rimossa agli utenti che potrebbero avere bisogno di capacità di debug limitate, ma mantenere riservati i FILE PDB completi. Si noti che /PDBSTRIPPED genera un secondo file PDB più piccolo, quindi assicurarsi di usare il file PDB corretto quando si generano compilazioni per la distribuzione su larga scala. Per un progetto tipico, un PDB normale può essere di pochi megabyte, ma una versione rimossa del PDB può essere solo di poche centinaia di kilobyte.

Uso dei simboli per il debug

Quando si esegue il debug di un'applicazione che si è arrestata in modo anomalo, il debugger tenta di visualizzare le funzioni nello stack che ha causato l'arresto anomalo. Senza un file PDB, il debugger non può risolvere i nomi delle funzioni, i relativi parametri o le variabili locali archiviate nello stack. Se si esegue il debug di file eseguibili a 32 bit, in alcune situazioni non è possibile ottenere analisi dello stack affidabili senza simboli. A volte è possibile esaminare i valori non elaborati nello stack e determinare quali valori possono essere restituiti dagli indirizzi, ma possono essere facilmente confusi con i riferimenti o i dati delle funzioni.

Se le funzioni nello stack corrente sono state compilate usando l'ottimizzazione Omit Frame Pointers (/Oy) e se i simboli non sono presenti, il debugger non può determinare in modo affidabile quale funzione ha chiamato la funzione corrente. Ciò è dovuto al fatto che senza le informazioni FPO (Frame Pointer Optimization) contenute nei PDB, il debugger non può basarsi sul registro dei puntatori di fotogrammi (EBP) per puntare al puntatore frame precedente salvato e all'indirizzo restituito della funzione padre. Invece, indovina. A volte lo fa bene. Tuttavia, spesso si sbaglia, che può essere fuorviante. Se viene visualizzato un avviso relativo ai simboli mancanti o nessun simbolo caricato, come nell'esempio seguente, non considerare attendibile lo stack da tale punto verso il basso.

SWPerfTest.exe!TextFunction(... ...)    Line 59    C++
d3dx9d.dll!008829b5()
[Frames below may be incorrect and/or missing, no symbols loaded for d3dx9d.dll]
SWPerfTest.exe!main(int argc=, const char * * argv=)  Line 328 + 0x12 bytes     C++
SWPerfTest.exe!__mainCRTStartup() Line 716 + 0x17 bytes    C
kernel32.dll!@BaseThreadInitThunk@12() + 0x12 bytes
ntdll.dll!__RtlUserThreadStart@8() + 0x27 bytes

In molti casi, è possibile continuare il debug senza simboli, perché il problema si trova in una posizione con simboli accurati e non è necessario esaminare le funzioni più avanti nello stack di chiamate. Anche se una libreria che si trova nello stack di chiamate non dispone di PDB disponibili, purché siano stati compilati con puntatori a fotogrammi, il debugger dovrebbe essere in grado di indovinare correttamente le funzioni padre. A partire da Windows XP Service Pack 2, tutti i file DLL e eseguibili di Windows vengono compilati con FPO disabilitato, perché rende il debug più accurato. La disabilitazione di FPO consente anche ai profiler di campionamento di camminare lo stack durante la fase di esecuzione, con un impatto minimo sulle prestazioni. Nelle versioni di Windows precedenti a Windows XP SP2, tutti i file binari del sistema operativo richiedono file di simboli corrispondenti contenenti informazioni FPO, per consentire debug e profilatura accurati.

Se si esegue il debug di file eseguibili nativi a 64 bit, non sono necessari file di simboli per produrre tracce dello stack valide, perché i sistemi operativi e i compilatori x64 sono progettati per non richiederli. Tuttavia, sono ancora necessari file di simboli per recuperare i nomi delle funzioni, chiamare i parametri e le variabili locali.

Tuttavia, alcuni casi sono particolarmente difficili da eseguire senza simboli. Ad esempio, se si esegue il debug di un programma per il quale è stato creato un file PDB e se si verifica un arresto anomalo in un callback da una funzione in una DLL per cui non si dispone di simboli, non sarà possibile vedere quale funzione ha causato il callback, perché non sarà possibile decodificare lo stack. Questo accade spesso nelle librerie di terze parti, se i PDB non vengono forniti o nei componenti precedenti del sistema operativo, se i PDB non sono disponibili. I callback spesso si verificano durante il passaggio, l'enumerazione, l'allocazione di memoria o la gestione delle eccezioni. Il debug di queste funzioni senza uno stack accurato può essere frustrante.

Per eseguire il debug affidabile di mini dump generati in un computer diverso o che si arresta in modo anomalo nel codice di cui non si è proprietari, è importante poter accedere a tutti i simboli e i file binari per i file eseguibili a cui si fa riferimento nel mini dump. Se i simboli e i file binari sono disponibili da un server di simboli, vengono ottenuti automaticamente dal debugger. Per altre informazioni sui mini dump, vedere il white paper Analisi dump di arresto anomalo del sistema .

Ottenere i simboli necessari

Visual Studio e altri debugger Microsoft, ad esempio WinDbg, sono in genere configurati per funzionare solo se si compila un'applicazione e lo si esegue il debug nel proprio computer. Se è necessario assegnare il file eseguibile a un altro utente, se si dispone di più versioni di una DLL o di un file con estensione exe nel computer o se si vuole eseguire con precisione il debug di un'applicazione che usa Windows o altre librerie, ad esempio DirectX, è necessario comprendere come i debugger trovano e caricano simboli. Il debugger usa il percorso di ricerca dei simboli specificato dall'utente, disponibile in Options\Debugging\Symbols in Visual Studio, oppure la variabile di ambiente _NT_SYMBOL_PATH. In genere, il debugger cerca i PDB corrispondenti nei percorsi seguenti:

  • Percorso specificato nella DLL o nel file eseguibile.

    Se è stata compilata una DLL o un file eseguibile nel computer, per impostazione predefinita il linker inserisce il percorso completo e il nome file del file PDB associato all'interno della DLL o del file eseguibile. Quando si esegue il debug, il debugger verifica innanzitutto se il file di simboli esiste nel percorso specificato all'interno della DLL o nel file eseguibile. Questo è utile, perché sono sempre disponibili simboli per il codice compilato nel computer.

  • PDB che possono essere presenti nella stessa cartella del file DLL o eseguibile.

  • Qualsiasi cartella della cache di simboli locale.

  • Qualsiasi server di simboli di condivisione file di rete locale.

  • Qualsiasi server di simboli Internet, ad esempio il server dei simboli Microsoft.

Per assicurarsi di disporre di tutti i PDB necessari per il debug accurato, installare gli strumenti di debug per Windows. Le versioni a 32 e 64 bit sono disponibili in Strumenti di debug per Windows.

Uno strumento utile installato con questo pacchetto è symchk.exe. Può essere utile per identificare i simboli mancanti o non corretti. Questo strumento include un numero elevato di opzioni della riga di comando potenziali. Ecco due dei più utili e di uso comune.

Controllare se una determinata DLL o file con estensione exe e PDB nella stessa cartella corrispondono

"c:\Program Files\Debugging Tools for Windows\symchk" testing.dll /s .

SYMCHK: FAILED files = 0
SYMCHK: PASSED + IGNORED files = 1

L'opzione /s indica a symchk di cercare i simboli solo nella cartella corrente e non di cercare in alcun server di simboli.

Controllare se tutte le DLL e i file eseguibili in un set di cartelle hanno FILE PDF corrispondenti

"c:\Program Files\Debugging Tools for Windows\symchk" *.* /r

L'opzione /r imposta symchk per attraversare in modo ricorsivo le cartelle, per verificare che tutti i file eseguibili abbiano file PDF corrispondenti. Senza l'opzione /s , symchk usa il _NT_SYMBOL_PATH corrente per cercare i simboli in qualsiasi server privato o locale o nei server dei simboli Microsoft. Lo strumento symchk cerca solo i simboli per i file eseguibili (.exe, DLL e simili). Non è possibile utilizzare caratteri jolly per cercare i simboli per i file non eseguibili.

Funzionamento di symchk

Quando il linker genera file DLL, eseguibili e PDB, archivia GUID identici in ogni file. Il GUID viene usato dagli strumenti per determinare se un determinato file PDB corrisponde a una DLL o a un file eseguibile. Se si modifica una DLL o un file eseguibile, usando un editor di risorse o la codifica di protezione della copia o modificandone le informazioni sulla versione, il GUID viene aggiornato e il debugger non può caricare il file PDB. Per questo motivo, è molto importante evitare di modificare la DLL o il file eseguibile dopo che è stato creato dal linker.

È anche possibile usare l'utilità DUMPBIN fornita con VS.NET per visualizzare i percorsi dei simboli ricercati e per verificare se vengono trovati file di simboli corrispondenti a una DLL o un file eseguibile specificato. Ad esempio:

DUMPBIN /PDBPATH:VERBOSE filename.exe

Server di simboli

Un server di simboli è un repository per più versioni di file eseguibili e di simboli. Contiene i file di simboli stessi o puntatori ai file di simboli associati. I debugger comprendono come usare i server di simboli e possono usarli per cercare simboli mancanti o sconosciuti.

I file DLL ed eseguibili sono disponibili anche dal server dei simboli Microsoft. In questo modo è possibile eseguire il debug degli arresti anomali ed esaminare il codice per i file del sistema operativo che potrebbero non esistere nel computer. Se un debugger rileva un file eseguibile o una DLL che non esiste nel sistema in uso per il debug, richiede automaticamente sia i simboli che una copia del file binario dai server di simboli Microsoft. Ciò è utile se si esegue il debug di un componente con molte versioni, ad esempio msvcrt.dll, ed è necessario esaminare il codice per una versione che non esiste nel computer. Ciò consente anche di eseguire il debug di mini dump generati in un sistema operativo diverso dal sistema usato per il debug.

Microsoft pubblica tutti i file PDB per tutti i sistemi operativi e altri componenti ridistribuiti, ad esempio DirectX SDK, nel server dei simboli accessibile esternamente. In questo modo è facile eseguire il debug di un'applicazione che usa questi file DLL o eseguibili. È possibile utilizzare il server dei simboli Microsoft per risolvere i simboli, insieme ai simboli locali per i componenti creati nel computer.

È possibile configurare il computer per l'uso del server dei simboli Microsoft, che consente di accedere a tutti i file di simboli Microsoft. È anche possibile configurare un server di simboli privato per l'azienda, il team o la rete, che può essere usato per archiviare più versioni precedenti di un progetto su cui si sta lavorando o per fornire una cache locale per i simboli usati dal server dei simboli Microsoft.

Per usare un server di simboli, specificare il percorso di ricerca in una variabile di ambiente denominata _NT_SYMBOL_PATH. I debugger e gli strumenti moderni, ad esempio WinDbg, NTSD o Visual Studio, usano automaticamente questo percorso per cercare i simboli.

Quando un debugger cerca i simboli, cerca prima in locale. Quindi sembra sui server di simboli. Quando trova un simbolo corrispondente, trasferisce il file di simboli nella cache locale. I simboli per un file DLL o eseguibile tipico sono compresi tra 1 e 100 MB. Pertanto, se si esegue il debug di un processo che include molte DLL, può essere necessario del tempo per risolvere tutti i simboli e trasferirli in una cache locale.

Utilizzo del server dei simboli Microsoft

Il server dei simboli Microsoft consente di ottenere tutti i simboli più recenti, inclusi i simboli per i file con patch o aggiornati. Il server dei simboli Microsoft è disponibile all'indirizzo https://msdl.microsoft.com/download/symbols.

È possibile accedere al server dei simboli in uno dei modi seguenti:

  • Immettere direttamente l'indirizzo del server. In Visual Studio scegliere Opzioni dal menu Strumenti, quindi debug e quindi simboli.

  • Usare la variabile di ambiente _NT_SYMBOL_PATH. È consigliabile usare questo metodo.

    Viene usato da tutti gli strumenti di debug. Viene usato anche da Visual Studio e viene letto e decodificato all'apertura di Visual Studio. Pertanto, se lo si modifica, è necessario riavviare Visual Studio.

    Questa variabile di ambiente consente di specificare più server di simboli, ad esempio un server di simboli privato interno. Consente inoltre di specificare una directory della cache locale per archiviare i PDB per tutti i simboli cercati dai server di simboli, sia internamente che tramite Internet.

La sintassi per la variabile _NT_SYMBOL_PATH è:

srv*[local cache]*[private symbol server]*https://msdl.microsoft.com/download/symbols

Sostituire [cache locale] con il nome di una directory nel computer in cui si desidera archiviare una cache di tutti i simboli usati, ad esempio %SYSTEMROOT%\Symbols o c:\symbols.

Il [server dei simboli privati] è facoltativo. Può puntare a un server di simboli che si trova nella rete oppure può puntare a un server di simboli condiviso dal team, dal gruppo di prodotti o dall'azienda.

Per usare solo il server dei simboli Microsoft insieme a una cache locale di simboli, per velocizzare l'accesso tramite Internet, utilizzare l'impostazione seguente per _NT_SYMBOL_PATH:

srv*c:\symbols*https://msdl.microsoft.com/download/symbols

È possibile trovare altre opzioni per il _NT_SYMBOL_PATH nel file della Guida installato con il pacchetto Microsoft Debugging Tools for Windows.

Gli eseguibili senza simboli possono aumentare il tempo necessario per avviare un debugger se si usa un server di simboli. Questo perché il debugger esegue una query sul server dei simboli ogni volta che tenta di caricare l'eseguibile. Per questo motivo, è consigliabile richiedere sempre simboli per tutti i componenti.

Potrebbe non essere possibile richiedere simboli per ogni componente, ad esempio i driver video potrebbero avere DLL nello spazio di elaborazione e i file PDB necessari sono disponibili nel server dei simboli Microsoft. In questo caso, si verifica un piccolo ritardo quando si avvia una sessione di debug.

Per evitare anche questo piccolo ritardo, è possibile eseguire il debugger una sola volta per memorizzare nella cache tutti i simboli in locale dal server dei simboli Microsoft. Modificare quindi il _NT_SYMBOL_PATH per rimuovere il server dei simboli Microsoft. A meno che i file eseguibili non cambino, i controlli per i file eseguibili che non dispongono di simboli non richiederanno una query su Internet, perché sono presenti copie memorizzate nella cache locale di tutti i simboli necessari dal server dei simboli Microsoft.

Recupero manuale dei simboli

Se il debugger è stato configurato correttamente, carica automaticamente tutti i simboli richiesti dalla cache locale o da un server di simboli. Se vuoi ottenere i simboli solo per un singolo eseguibile o per una cartella di eseguibili, puoi usare symchk. Ad esempio, se si desidera scaricare i simboli per il file d3dx9_30.dll nella cartella Di sistema di Windows nella directory corrente, è possibile usare il comando seguente:

"c:\Program Files\Debugging Tools for Windows\symchk" c:\Windows\System32\d3dx9_30.dll /oc \.

Lo strumento symchk ha molti altri usi. Per informazioni dettagliate, vedere symchk /?o consultare la documentazione relativa agli strumenti di debug Microsoft per Windows.

Configurazione di un server di simboli

La configurazione di un server di simboli è molto semplice. È utile per i motivi seguenti:

  • Per risparmiare larghezza di banda o per velocizzare la risoluzione dei simboli per l'azienda, il team o il prodotto. Un server di simboli interno in una condivisione file locale nella rete memorizza nella cache tutti i riferimenti ai server di simboli esterni, ad esempio il server dei simboli Microsoft. È possibile accedere rapidamente a un server di simboli locale o interno da molte persone contemporaneamente. Di conseguenza, consente di risparmiare larghezza di banda e la latenza che le richieste di simboli duplicate possono creare.
  • Per archiviare i simboli per build precedenti, versioni o versioni esterne dell'applicazione. Archiviando i simboli per queste compilazioni in un server di simboli a cui è possibile accedere facilmente, è possibile eseguire il debug di arresti anomali e problemi in queste build in qualsiasi computer con un debugger e una connessione al server dei simboli locale. Ciò è particolarmente utile se si esegue il debug di mini dump generati da file eseguibili che non sono stati compilati manualmente, ovvero le compilazioni generate da un altro programmatore o da un computer di compilazione. Se i simboli per queste compilazioni vengono archiviati nel server dei simboli, si avrà un debug affidabile e accurato.
  • Per mantenere aggiornati i simboli. Quando i componenti vengono aggiornati, ad esempio i componenti del sistema operativo modificati da Windows Update o da DirectX SDK, è comunque possibile eseguire il debug usando tutti i simboli più recenti.

La configurazione di un server di simboli nella propria rete locale è semplice come creare una condivisione file in un server e concedere agli utenti le autorizzazioni complete per accedere alla condivisione, per creare file e cartelle. Questa condivisione deve essere creata in un sistema operativo server, ad esempio Windows Server 2003, in modo che il numero di persone che possono accedere alla condivisione simultaneamente non sia limitato.

Ad esempio, se si configura una condivisione file in \\mainserver\symbols, i membri del team impostano il _NT_SYMBOL_PATH su quanto segue:

Srv*c:\symbols*\\mainserver\symbols*https://msdl.microsoft.com/download/symbols

Man mano che vengono recuperati i simboli, i file e le cartelle vengono visualizzati nella directory condivisa \\mainserver\symbols, nonché nelle singole cache, nella directory c:\symbols.

Questo è in genere tutto ciò che è coinvolto nella configurazione e nell'uso del proprio server di simboli o del server dei simboli Microsoft.

Aggiunta di simboli a un server di simboli

Per aggiungere, eliminare o modificare file in una condivisione server di simboli, usare lo strumento symstore.exe. Questo strumento fa parte del pacchetto Microsoft Debugging Tools for Windows. La documentazione completa sui server di simboli, lo strumento symstore e i simboli di indicizzazione sono inclusi nel pacchetto Strumenti di debug per Windows.

È possibile aggiungere simboli direttamente al server dei simboli, come parte di un processo di compilazione o per rendere i simboli disponibili per l'intero team per librerie o strumenti di terze parti. Il processo di aggiunta di un simbolo a una condivisione file del server di simboli è denominato simboli di indicizzazione. Esistono due modi comuni per indicizzare i simboli. È possibile copiare un file di simboli nel server dei simboli. In alternativa, un puntatore alla posizione del simbolo può essere copiato nel server dei simboli. Se si dispone di una cartella di archiviazione contenente le build precedenti, è possibile indicizzare i puntatori ai file PDB già presenti nella condivisione, anziché duplicare i simboli. Poiché a volte i simboli possono essere di decine di megabyte, è consigliabile pianificare in anticipo la quantità di spazio necessaria per archiviare tutte le compilazioni del progetto durante lo sviluppo. Se si indicizzano solo i puntatori ai simboli, è possibile che si verifichino problemi se si rimuovono le build precedenti o si modifica il nome di una condivisione file.

Ad esempio, per indicizzare in modo ricorsivo tutti i simboli in c:\dxsym\Extras\Symbols ottenuti dall'SDK DirectX di ottobre 2006 in una condivisione file del server di simboli denominata \\mainserver\symbols, è possibile usare il comando seguente:

"c:\Program Files\Debugging Tools for Windows\symstore" add /f "C:\dxsym\Extras\Symbols\*.pdb"
/s \\mainserver\symbols /t "October 2006 DirectX SDK " /r

Il parametro /t "comment" viene usato per aggiungere una descrizione alla transazione che ha aggiunto i simboli. Ciò può essere utile quando si eseguono attività amministrative sui simboli.

Consigli per iniziare

  • Configurare la condivisione file del server di simboli personalizzata per il team, la società o il prodotto.
  • Configurare _NT_SYMBOL_PATH in modo che punti a una cache locale, a un server di simboli privato e al server dei simboli Microsoft.
  • Se un debugger non è in grado di caricare i simboli per un componente di cui si sta eseguendo il debug, contattare il proprietario del componente per richiedere simboli, almeno un PDB rimosso.
  • Configurare un sistema di compilazione automatizzato per indicizzare i simboli nel server dei simboli privati per ogni compilazione prodotta. Assicurarsi che le compilazioni distribuite siano le compilazioni generate da questo processo. In questo modo, i simboli sono sempre disponibili per il debug dei problemi.
  • Configurare un server di simboli per consentire ai debugger di accedere al codice sorgente per un modulo specifico direttamente da un sistema di controllo del codice sorgente basato su Visual Source Cassaforte o Perforce. Se le informazioni e i simboli del file di origine per una versione rilasciata di un gioco vengono indicizzati, gli sviluppatori che hanno accesso al server dei simboli possono avere il debug completo a livello di origine dei problemi segnalati, senza mantenere gli ambienti di compilazione o le versioni precedenti dei file di origine nei computer di sviluppo. Per configurare il server dei simboli per consentire l'indicizzazione delle informazioni sui file di origine, vedere la documentazione del server di origine.