Condividi tramite


Introduzione a WinDbg (modalità utente)

WinDbg è un debugger in modalità kernel e in modalità utente incluso in Strumenti di debug per Windows. Gli esercizi pratici seguenti consentono di iniziare a usare WinDbg come debugger in modalità utente.

Per informazioni su come ottenere gli strumenti di debug per Windows, vedere Scaricare e installare il debugger windows WinDbg.

Dopo aver installato gli strumenti di debug, trovare le directory di installazione per le versioni a 64 bit (x64) e ARM a 64 bit degli strumenti. Per esempio:

  • C:\Programmi (x86)\Windows Kits\10\Debuggers\x64
  • C:\Programmi (x86)\Windows Kits\10\Debuggers\arm64

Aprire il Blocco note e collegare WinDbg

  1. Vai alla directory di installazione e apri WinDbg.exe.

  2. Sul menu File, selezionare Eseguire programma eseguibile. Nella finestra di dialogo Avvia eseguibile passare alla cartella che contiene notepad.exe. Il file notepad.exe si trova in genere in C:\Windows\System32. Per Nome fileimmettere notepad.exe. Selezionare Apri.

    Screenshot di WinDbg con Blocco Note aperto.

  3. Nella riga di comando nella parte inferiore della finestra winDbg immettere questo comando:

    .sympath srv*

    L'output è simile a questo esempio:

    Symbol search path is: srv*
    Expanded Symbol search path is: cache*;SRV
    

    Il percorso di ricerca dei simboli indica a WinDbg dove cercare i file di simboli (PDB). Il debugger necessita di file di simboli per ottenere informazioni sui moduli di codice, ad esempio nomi di funzione e nomi di variabili.

    Immettere quindi questo comando:

    ricarica

    Il comando .reload indica a WinDbg di eseguire la ricerca iniziale per trovare e caricare i file di simboli.

  4. Per visualizzare i simboli per il modulo notepad.exe, immettere questo comando:

    blocco note!*

    Nota

    Se non viene visualizzato alcun output, immettere .reload /f per tentare di forzare il caricamento del simbolo. Usare !sym noisy per visualizzare informazioni aggiuntive riguardanti il caricamento dei simboli.

    Per visualizzare i simboli nel modulo notepad.exe che contengono main, usare il comando esaminare i simboli per elencare i moduli corrispondenti alla maschera:

    x notepad!wWin*

    L'output è simile a questo esempio:

    00007ff6`6e76b0a0 notepad!wWinMain (wWinMain)
    00007ff6`6e783db0 notepad!wWinMainCRTStartup (wWinMainCRTStartup)
    
  5. Per inserire un punto di interruzione in notepad!wWinMain, immettere questo comando:

    blocco note!wWinMain

    Per verificare che il punto di interruzione sia stato impostato, immettere questo comando:

    bl

    L'output è simile a questo esempio:

    0 e Disable Clear  00007ff6`6e76b0a0     0001 (0001)  0:**** notepad!wWinMain
    
  6. Per avviare Blocco note, immettere questo comando:

    g

    Il Blocco note viene eseguito fino a quando non arriva alla funzione WinMain e quindi si interrompe nel debugger.

    Breakpoint 0 hit
    notepad!wWinMain:
    00007ff6`6e76b0a0 488bc4          mov     rax,rsp
    

    Per visualizzare un elenco di moduli di codice attualmente caricati nel processo Blocco Note, immettere questo comando:

    lm

    L'output è simile a questo esempio:

    0:000> lm
    start             end                 module name
    00007ff6`6e760000 00007ff6`6e798000   notepad    (pdb symbols)          C:\ProgramData\Dbg\sym\notepad.pdb\BC04D9A431EDE299D4625AD6201C8A4A1\notepad.pdb
    00007ff8`066a0000 00007ff8`067ab000   gdi32full   (deferred)             
    00007ff8`067b0000 00007ff8`068b0000   ucrtbase   (deferred)             
    00007ff8`06a10000 00007ff8`06aad000   msvcp_win   (deferred)             
    00007ff8`06ab0000 00007ff8`06ad2000   win32u     (deferred)             
    00007ff8`06b40000 00007ff8`06e08000   KERNELBASE   (deferred)             
    00007ff8`07220000 00007ff8`072dd000   KERNEL32   (deferred)             
    00007ff8`07420000 00007ff8`07775000   combase    (deferred)             
    00007ff8`07820000 00007ff8`079c0000   USER32     (deferred)             
    00007ff8`079c0000 00007ff8`079f0000   IMM32      (deferred)             
    00007ff8`07c00000 00007ff8`07c2a000   GDI32      (deferred)             
    00007ff8`08480000 00007ff8`085ab000   RPCRT4     (deferred)             
    00007ff8`085b0000 00007ff8`0864e000   msvcrt     (deferred)             
    00007ff8`08c40000 00007ff8`08cee000   shcore     (deferred)             
    00007ff8`08db0000 00007ff8`08fa5000   ntdll      (pdb symbols)          C:\ProgramData\Dbg\sym\ntdll.pdb\53F12BFE149A2F50205C8D5D66290B481\ntdll.pdb
    00007fff`f8580000 00007fff`f881a000   COMCTL32   (deferred)    
    

    Per visualizzare un'analisi dello stack, immettere questo comando:

    k

    L'output è simile a questo esempio:

    0:000> k
    00 000000c8`2647f708 00007ff6`6e783d36     notepad!wWinMain
    01 000000c8`2647f710 00007ff8`07237034     notepad!__scrt_common_main_seh+0x106
    02 000000c8`2647f750 00007ff8`08e02651     KERNEL32!BaseThreadInitThunk+0x14
    03 000000c8`2647f780 00000000`00000000     ntdll!RtlUserThreadStart+0x21
    
  7. Per avviare di nuovo Blocco note, immettere questo comando:

    g

  8. Per accedere a Blocco note, nel menu File selezionare Interrompi.

  9. Per impostare e verificare un punto di interruzione in ZwWriteFile, immettere questi comandi:

    bu ntdll! ZwWriteFile

    bl

  10. Per avviare nuovamente l'esecuzione del Blocco note, immettere g. Nella finestra del Blocco note, inserisci del testo. Nel menu file selezionare Salva. Il codice in esecuzione si interrompe quando si tratta di ZwCreateFile. Immettere il comando k per visualizzare la traccia dello stack.

    Screenshot di una traccia dello stack in WinDbg.

    Nella finestra WinDbg, a sinistra della riga di comando, vengono visualizzati i numeri del processore e del thread. In questo esempio il numero corrente del processore è 0 e il numero di thread corrente è 11 (0:011>). Nella finestra viene visualizzata la traccia dello stack per il thread 11 in esecuzione sul processore 0.

  11. Per visualizzare un elenco di tutti i thread nel processo blocco note, immettere questo comando (la tilde):

    ~

    L'output è simile a questo esempio:

    0:011> ~
       0  Id: 5500.34d8 Suspend: 1 Teb: 000000c8`262c4000 Unfrozen
       1  Id: 5500.3960 Suspend: 1 Teb: 000000c8`262c6000 Unfrozen
        2  Id: 5500.5d68 Suspend: 1 Teb: 000000c8`262c8000 Unfrozen
        3  Id: 5500.4c90 Suspend: 1 Teb: 000000c8`262ca000 Unfrozen
        4  Id: 5500.4ac4 Suspend: 1 Teb: 000000c8`262cc000 Unfrozen
        5  Id: 5500.293c Suspend: 1 Teb: 000000c8`262ce000 Unfrozen
        6  Id: 5500.53a0 Suspend: 1 Teb: 000000c8`262d0000 Unfrozen
        7  Id: 5500.3ca4 Suspend: 1 Teb: 000000c8`262d4000 Unfrozen
        8  Id: 5500.808 Suspend: 1 Teb: 000000c8`262da000 Unfrozen
       10  Id: 5500.3940 Suspend: 1 Teb: 000000c8`262dc000 Unfrozen
     . 11  Id: 5500.28b0 Suspend: 1 Teb: 000000c8`262de000 Unfrozen
       12  Id: 5500.12bc Suspend: 1 Teb: 000000c8`262e0000 Unfrozen
       13  Id: 5500.4c34 Suspend: 1 Teb: 000000c8`262e2000 Unfrozen
    

    In questo esempio, 14 thread hanno indici da 0 a 13.

  12. Per esaminare la traccia dello stack per il thread 0, immettere questi comandi:

    circa 0s

    k

    L'output è simile a questo esempio:

    0:011> ~0s
    0:011> ~0s
    win32u!NtUserGetProp+0x14:
    00007ff8`06ab1204 c3              ret
    0:000> k
     # Child-SP          RetAddr               Call Site
    00 000000c8`2647bd08 00007ff8`07829fe1     win32u!NtUserGetProp+0x14
    01 000000c8`2647bd10 00007fff`f86099be     USER32!GetPropW+0xd1
    02 000000c8`2647bd40 00007ff8`07d12f4d     COMCTL32!DefSubclassProc+0x4e
    03 000000c8`2647bd90 00007fff`f8609aba     SHELL32!CAutoComplete::_EditWndProc+0xb1
    04 000000c8`2647bde0 00007fff`f86098b7     COMCTL32!CallNextSubclassProc+0x9a
    05 000000c8`2647be60 00007ff8`0782e858     COMCTL32!MasterSubclassProc+0xa7
    06 000000c8`2647bf00 00007ff8`0782de1b     USER32!UserCallWinProcCheckWow+0x2f8
    07 000000c8`2647c090 00007ff8`0782d68a     USER32!SendMessageWorker+0x70b
    08 000000c8`2647c130 00007ff8`07afa4db     USER32!SendMessageW+0xda
    
  13. Per uscire dal debug e scollegarsi dal processo del Blocco note, immettere questo comando:

    qd

Aprire un'applicazione personalizzata e collegare WinDbg

Si supponga, ad esempio, di aver scritto e compilato questa piccola applicazione console:

...
void MyFunction(long p1, long p2, long p3)
{
    long x = p1 + p2 + p3;
    long y = 0;
    y = x / p2;
}

void main ()
{
    long a = 2;
    long b = 0;
    MyFunction(a, b, 5);
}

Per questo esercizio si supponga che l'applicazione compilata (MyApp.exe) e il file di simboli (MyApp.pdb) si trovino in C:\MyApp\x64\Debug. Si supponga inoltre che il codice sorgente dell'applicazione si trova in C:\MyApp\MyApp and that the target machine compiled MyApp.exe.

  1. Apri WinDbg.

  2. Nel menu File , selezionare Avvia eseguibile . Nella finestra di dialogo 'Avvia eseguibile', passare a C:\MyApp\x64\Debug. Per Nome file, inserire MyApp.exe. Selezionare Apri.

  3. Immettere questi comandi:

    .symfix

    .sympath+ C:\MyApp\x64\Debug

    I comandi indicano a WinDbg dove trovare simboli e codice sorgente per l'applicazione. In questo caso, non è necessario impostare il percorso del codice sorgente usando .srcpath perché i simboli hanno percorsi completi ai file di origine.

  4. Immettere questi comandi:

    ricaricare

    bu MyApp!main

    g

    L'applicazione si interrompe nel debugger quando raggiunge la funzione main.

    WinDbg visualizza il codice sorgente e la finestra Comando.

    Screenshot del codice sorgente visualizzato in WinDbg.

  5. Nel menu Debug, selezionare Step Into (o selezionare F11). Continuare a camminare fino a quando non si entra in MyFunction. Quando si arriva alla riga y = x / p2, l'applicazione si arresta in modo anomalo ed entra nel debugger.

    L'output è simile a questo esempio:

    (1450.1424): Integer divide-by-zero - code c0000094 (first chance)
    First chance exceptions are reported before any exception handling.
    This exception may be expected and handled.
    MyApp!MyFunction+0x44:
    00007ff6`3be11064 f77c2428    idiv  eax,dword ptr [rsp+28h] ss:00000063`2036f808=00000000
    
  6. Immettere questo comando:

    !analyze -v

    WinDbg visualizza un'analisi del problema (in questo caso, divisione per 0).

    FAULTING_IP:
    MyApp!MyFunction+44 [c:\myapp\myapp\myapp.cpp @ 7]
    00007ff6`3be11064 f77c2428        idiv    eax,dword ptr [rsp+28h]
    
    EXCEPTION_RECORD:  ffffffffffffffff -- (.exr 0xffffffffffffffff)
    ExceptionAddress: 00007ff63be11064 (MyApp!MyFunction+0x0000000000000044)
       ExceptionCode: c0000094 (Integer divide-by-zero)
      ExceptionFlags: 00000000
    NumberParameters: 0
    ...
    STACK_TEXT:  
    00000063`2036f7e0 00007ff6`3be110b8 : ... : MyApp!MyFunction+0x44
    00000063`2036f800 00007ff6`3be1141d : ... : MyApp!main+0x38
    00000063`2036f840 00007ff6`3be1154e : ... : MyApp!__tmainCRTStartup+0x19d
    00000063`2036f8b0 00007ffc`b1cf16ad : ... : MyApp!mainCRTStartup+0xe
    00000063`2036f8e0 00007ffc`b1fc4629 : ... : KERNEL32!BaseThreadInitThunk+0xd
    00000063`2036f910 00000000`00000000 : ... : ntdll!RtlUserThreadStart+0x1d
    
    STACK_COMMAND: dt ntdll!LdrpLastDllInitializer BaseDllName ;dt ntdll!LdrpFailureData ;.cxr 0x0 ;kb
    
    FOLLOWUP_IP:
    MyApp!MyFunction+44 [c:\myapp\myapp\myapp.cpp @ 7]
    00007ff6`3be11064 f77c2428        idiv    eax,dword ptr [rsp+28h]
    
    FAULTING_SOURCE_LINE:  c:\myapp\myapp\myapp.cpp
    
    FAULTING_SOURCE_FILE:  c:\myapp\myapp\myapp.cpp
    
    FAULTING_SOURCE_LINE_NUMBER:  7
    
    FAULTING_SOURCE_CODE:  
         3: void MyFunction(long p1, long p2, long p3)
         4: {
         5:     long x = p1 + p2 + p3;
         6:     long y = 0;
    >    7:  y = x / p2;
         8: }
         9:
        10: void main ()
        11: {
        12:     long a = 2;
    ...
    

Riepilogo dei comandi

Vedere anche

Introduzione all' WinDbg (modalità kernel)

L'operazione debugger

tecniche di debug

Scaricare e installare il debugger windows WinDbg

Caratteristiche di WinDbg