Adesso che sappiamo come tutto è cominciato, abbiamo le informazioni di base e conosciamo la terminologia, sappiamo perchè i simboli sono importanti, è venuto il momento di catturare il primo dump. Come? Quando? Con quali strumenti? Beh… dipende! Nerd

Dal secondo post di questa piccola serie conosciamo la differenza tra dump in hang mode e crash mode e quando utilizzare una modalità piuttosto che l’altra a seconda del problema che stiamo affrontando. Ci sono svariati modi per catturare un dump, ma credo che lo strumento più diffuso a questo scopo nel CSS sia adplus, ed in modo particolare nel team di supporto agli Sviluppatori Internet (del quale faccio parte Smile) utilizziamo DebugDiag; il risultato prodotto (il file di dump) è uguale, personalmente scelgo l’uno o l’altro a seconda di come possiamo catturare il dump (se in maniera automatica o manuale), del tipo di problema (memory leak in componenti Win32 o .NET, ad esempio) ecc…

Vediamo i principali modi di utilizzo e le differenze.

adplus.vbs

Sostanzialmente si tratta di un file VBScript (piuttosto complesso, che trovate installando i Debugging Tools for Windows) che può essere utilizzato alla riga di comando con alcuni parametri o un file di configurazione per indicare al tool che tipo di dump catturare, per quale processo, in quali circostanze ecc… I due argomenti che vanno obbligatoriamente specificati sono la modalità del crash (-hang o -crash) ed il processo target (-p <process ID> o -pm <process name>):

adplus -hang -pn w3wp.exe

È possibile passare più nomi di processi (o più PID) semplicemente ripetendo l’opzione -p(n); è anche possibile creare un dump di tutti i processi relativi ad IIS (inetinfo.exe, dllhost.exe e w3wp.exe/aspnet_wp.exe) usando l’opzione -IIS. Possiamo scegliere di non creare dump sulle first chance exceptions (-NoDumpOnFirst) o al contrario catturare un full dump anche sulle first chance exceptions (-FullOnFirst) ecc… Per maggiori dettagli vi rimando all’articolo How to use ADPlus to troubleshoot "hangs" and "crashes" ed all’help di Windbg (che fa sempre parte dei Debugging Tools for Windows).

File di configurazione

adplus utilizza file di configurazione in formato XML per evitare di digitare manualmente comandi lunghi e complessi; è anche possibile passare alcune opzioni tramite file di configurazione ed altre direttamente alla riga di comando. Ecco il formato di un file .cfg per adplus:

<ADPlus>   
<!-- Comments -->
<Settings>
<!-- defining basic settings (run mode, quiet mode, etc.) -->
</Settings>
<PreCommands>
<!-- defines a set of commands to execute before the sxe and bp commands -->
</PreCommands>
<PostCommands>
<!-- defines a set of commands to execute after the sxe and bp commands -->
</PostCommands>
<Exceptions>
<!-- commands acting on the exception actions -->
</Exceptions>
<Breakpoints>
<!-- defining breakpoints -->
</Breakpoints>
<HangActions>
<!-- defining actions for hang mode -->
</HangActions>
<LinkConfig>
<!-allows to link to another config file -->
</ LinkConfig >
</ADPlus>


La sezione Settings definisce i parametri principali da passare ad adplus e sono sostanzialmente equivalenti ai parametri che si possono passare direttamente alla command line; è possibile utilizzare istanze multiple dei tag ProcessID, ProcessName, Spawn e Notify:

<Settings>   
<RunMode> runmode </RunMode>
<Option> IIS </Option>
<Option> Quiet </Option>
<Option> NoTlist </Option>
<Option> NoTsCheck </Option>
<Option> NoFreeSpaceChecking </Option>
<OutputDir> OutputDirectoryName </OutputDir>
<ProcessID> PID </ProcessID>
<ProcessName> ProcessName </ProcessName>
<GenerateScript> ScriptName </GenerateScript>
<Spawn> Spawn Command </Spawn>
<Sympath> Symbol Path </Sympath>
<SympathPlus> Symbol Path to add </SympathPlus>
<Notify> { ComputerName | UserName } </Notify>
<Debugger> Debugger </ Debugger >
</Settings>


La sezione Exceptions permette di personalizzare l’azione che il debugger deve intraprendere quando viene lanciata l’eccezione specificata; è anche possibile monitorare eccezioni personalizzate:

<Exceptions>   
<!-- options act on all currently defined exceptions -->
<Option> FullDumpOnFirstChance </Option>
<Option> MiniDumpOnSecondChance </Option>
<Option> NoDumpOnFirstChance </Option>
<Option> NoDumpOnSecondChance </Option>

<!-Defining new exceptions -->
<NewException>
<Code> ExceptionCode </Code>
<Name> ExceptionName </Name>
</NewException>

<!-Configuring already defined exceptions -->
<Config>
<Code> { ExceptionCode | AllExceptions } </Code>
<Actions1> Actions </Actions1>
<CustomActions1> CustomActions </CustomActions1>
<Actions2> Actions </Actions2>
<CustomActions2> CustomActions </CustomActions2>
<ReturnAction1> { G | GN | GH | Q | QD } </ReturnAction1>
<ReturnAction2> { G | GN | GH | Q | QD } </ReturnAction2>
</Config>
</Exceptions>

I tag ReturnAction1 e ReturnAction2 vengono usati per definire azioni aggiuntive a seguito rispettivamente di una first chance exception e di una second chance exception; funzionano da Windows XP in poi

La sezione HangActions permette invece di specificare azioni da eseguire quando adplus viene lanciato in hang mode:

<HangActions>   
<Option> MiniDump </Option>
<Option> FullDump </Option>
<Option> NoDump </Option>
<Option> Clear </Option>
<Actions> Actions </Actions>
<CustomActions> CustomActions </CustomActions>
</HangActions>

Ecco un esempio di file di configurazione (preso dall’help di Windbg):

<ADPlus>   
<Settings>
<RunMode> CRASH </RunMode>
<Option> IIS </Option>
<OutputDir> c:\MyDumps </OutputDir>
</Settings>

<PreCommands>
<Cmd> .load sos\sos.dll </Cmd>
</PreCommands>

<!-- defining and configuring exceptions -->
<Exceptions>
<!-- First we redefine all exceptions -->
<Config>
<Code>AllExceptions</Code>
<Actions1>Log</Actions1>
<Actions2>MiniDump;Log;EventLog</Actions2>
</Config>
<!-- Next we define a special behavior for the Access Violation exception -->
<Config>
<Code> av </Code>
<Actions1>Log</Actions1>
<Actions2>FullDump;Log;EventLog</Actions2>
</Config>
<!-- Adding a custom exception -->
<NewException>
<Code> 0x80010005 </Code>
<Name> Custom_Exception_05 </Name>
</NewException>
<!-- Configuring the custom exception -->
<Config>
<Code> 0x80010005 </Code>
<Actions1>Log;Stack</Actions1>
<Actions2>FullDump;Log;EventLog</Actions2>
<CustomActions2> !heap;!locks </CustomActions2>
</Config>
</Exceptions>

<!-- defining breakpoints -->
<Breakpoints>
<NewBP>
<Address> MyModule!MyClass::MyMethod </Address>
<Actions> Log;Stack;MiniDump </Actions>
<ReturnAction> G </ReturnAction>
</NewBP>
</Breakpoints>
</ADPlus>

Per ulteriori dettagli potete fare riferimento all’help di Windbg.

DebugDiag

debugdiag report

Questo strumento è stato originariamente sviluppato dal team degli Escalation Engineers di IIS e permette di creare, tramite una comoda interfaccia grafica, una o più regole per catturare dump sia in crash mode che in hang mode, e permette anche di automatizzare il processo di monitoraggio (a differenza di adplus, che invece la eseguito per lo più manualmente).

Ci sono principalmente tre circostanze nelle quali trovo DebugDiag particolarmente utile e può facilitare la vita di chi fa troubleshooting rispetto ad adplus. Per prima cosa, rende veramente facile catturare dump se si lavora tramite Terminal Server, si tratta semplicemente di modificare un parametro nella finestra di configurazione. Secondo, è possibile creare una regola per monitorare un URL ed in caso non si ottenga una risposta DebugDiag può catturare automaticamente un dump dell’application pool; questo è molto comodo soprattutto se dobbiamo catturare un dump per un problema che si verifica sporadicamente, magari di notte, e non ha ovviamente senso tenere impegnata una persona giorno e notte per monitorare il sito e lanciare adplus al momento opportuno Sarcastic. Non è possibile creare un dump per un processo che gira su un altro server, quindi se abbiamo bisogno di questo tipo di regola dovremo installare DebugDiag sul server web che ospita il sito che ha il problema, e quando si specifica l’URL da monitorare, personalmente preferisco sempre utilizzare l’indirizzo esterno (e non localhost) per simulare il più possibile una chiamata che arriva effettivamente da un client. Dove DebugDiag ci può dare veramente una grossa mano e nell’analisi di memory leak quando sono coinvolti componenti Win32 (quindi non basati su .NET).

In questo caso dobbiamo creare una regola per il “memory and handle leak” e specificare qual’è il processo che vogliamo monitorare; è possibile anche dire a DebugDiag di catturare automaticamente uno o più dump ad intervalli prefissati, quando il processo raggiunge una certa allocazione di memoria. Una volta ottenuto il dump possiamo aprirlo con DebugDiag e tramite il tab “Advanced Analysis” possiamo avviare l’analisi automatica per problemi di “memory pressure”: al termine dell’analisi DebugDiag produce un report HTML (ne potete vedere un piccolo esempio qui sopra) che indica quali componenti sono responsabili del maggior numero di allocazioni di memoria, la dimensione dei vari heap presenti nel processo ecc…

Allo stesso modo è possibile utilizzare l’analisi automatica per i crash, ed il report dirà quale componente ha lanciato l’eccezione (e di che tipo era questa eccezione) che ha causato il crash del processo. Naturalmente questi script automatici non sono sufficienti per risolvere il problema, ma spesso possono dare utili indicazioni per la prosecuzione dell’analisi.

Live debubbing e Windbg

Il live debugging sarà oggetto di un mio prossimo post, ma qualora abbiate “attaccato” Windbg ad un processo live e vi chiediate come poter poterne creare un dump…:

.dump /ma <output_file>

options & settingsDebug in Terminal Server?

Non è possibile prendere il dump di un processo su Windows NT o Windows 2000 se si è collegati attraverso una Termian Session, questo perchè il debugger non può attaccarsi ad un processo che si trova in una differente Windows Station: solitamente in questa circostanza si riceve un errore di access denied.

Questo comportamento è by design e non può essere modificato, ma ci sono comunque un paio di soluzioni per aggirare il problema: per la prima vi rimando all’help di Windbg, le sezioni You cannot debug through a Terminal Server session o “Running in crash mode remotely”.

La seconda possibilità è offerta da DebugDiag, abilitando l’opzione “Use service mode to overcome terminal server limitations (not persisted)” (immagine qui a sinistra).

Conclusione

Abbiamo a disposizione strumenti differenti, da utilizzare a seconda del tipo di problema che stiamo analizzando ma anche per avvicinarsi alle abitudini di ogni sviluppatore: uno script alla riga di comando che permette un livello di controllo molto approfondito ed uno ad interfaccia grafica che aiuta non solo a catturare il dump ma facilita anche la prima parte dell’analisi. Quale scegliere è sostanzialmente una questione di gusto ed abitudine dell’utilizzatore, ma se posso permettermi di darvi un consiglio, provate a fare un po’ di pratica con entrambi, prima o poi potrebbe tornarvi molto utile…! Nerd

 

 

Carlo Cardella
Senior Support Engineer
EMEA IIS and Web Developer Support