Freigeben über


Erste Schritte mit WinDbg (Benutzermodus)

In diesem Handbuch wird gezeigt, wie Sie WinDbg zum Debuggen von Benutzermodusanwendungen verwenden. Sie üben essenzielle Debugging-Fähigkeiten, indem Sie sich mit einem laufenden Prozess verbinden, Haltepunkte festlegen und Anwendungsabstürze analysieren.

In diesem Artikel:

  • WinDbg an Notepad anfügen und grundlegendes Debugging erkunden
  • Debuggen Ihrer eigenen Anwendung und Analysieren eines Absturzes
  • Beherrsche die wesentlichen Debugging-Befehle

Lerninhalt

  • Anfügen von WinDbg an einen ausgeführten Prozess
  • Konfigurieren von Symboldateien für lesbare Debugausgabe
  • Festlegen von Haltepunkten und Steuern der Programmausführung
  • Analysieren von Anwendungsabstürzen
  • Navigieren in Threads und Aufrufstapeln

Voraussetzungen

Geschätzte Zeit bis zum Abschluss: 30 Minuten

Editor und Anfügen von WinDbg öffnen

  1. Wechseln Sie zu Ihrem Installationsverzeichnis, und öffnen Sie WinDbg.exe.

  2. Wählen Sie im Menü Datei die Option Ausführbare Datei starten aus. Wechseln Sie im Dialogfeld "Ausführbare Datei starten " zu dem Ordner, der notepad.exeenthält. (Die notepad.exe Datei befindet sich in der Regel in C:\Windows\System32.) Geben Sie für den Dateinamennotepad.exeein. Wählen Sie Öffnen aus.

    Screenshot von WinDbg mit geöffnetem Editor.

  3. Konfigurieren Sie Symboldateien, damit WinDbg lesbare Funktions- und Variablennamen anzeigen kann.

    Geben Sie in der Befehlszeile am unteren Rand des WinDbg-Fensters den folgenden Befehl ein:

    .sympath srv*

    Die Ausgabe sieht in etwa wie das folgende Beispiel aus:

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

    Was sind Symbole? Symboldateien (PDB) enthalten Informationen zu Codemodulen, z. B. Funktionsnamen und Variablennamen. Ohne Symbole werden nur Speicheradressen angezeigt.

    Geben Sie dann diesen Befehl ein:

    .nachladen

    Der Befehl .reload weist WinDbg an, seine anfängliche Suche durchzuführen, um Symboldateien zu suchen und zu laden.

  4. Um die Symbole für das Modul notepad.exe anzuzeigen, geben Sie diesen Befehl ein:

    x Notepad!*

    Anmerkung

    Wenn keine Ausgabe angezeigt wird, geben Sie die .reload /f ein, um das Laden des Symbols zu erzwingen. Verwenden Sie !sym noisy, um zusätzliche Informationen zum Laden von Symbolen anzuzeigen.

    Verwenden Sie den Befehl Symbole untersuchen, um Module aufzulisten, die mit der Maske übereinstimmen und Symbolen im notepad.exe Modul enthaltenmain.

    x notepad!wWin*

    Die Ausgabe sieht in etwa wie das folgende Beispiel aus:

    00007ff6`6e76b0a0 notepad!wWinMain (wWinMain)
    00007ff6`6e783db0 notepad!wWinMainCRTStartup (wWinMainCRTStartup)
    
  5. Um einen Haltepunkt anzulegen notepad!wWinMain, geben Sie diesen Befehl ein:

    bu Notepad!wWinMain

    Um zu überprüfen, ob Sie Ihren Haltepunkt festlegen, geben Sie diesen Befehl ein:

    bl

    Die Ausgabe sieht in etwa wie das folgende Beispiel aus:

    0 e Disable Clear  00007ff6`6e76b0a0     0001 (0001)  0:**** notepad!wWinMain
    
  6. Um den Notepad-Prozess zu starten, geben Sie diesen Befehl ein:

    g

    Editor wird ausgeführt, bis es zur WinMain Funktion kommt, und dann wird er in den Debugger umgebrochen.

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

    Um eine Liste der Code-Module anzuzeigen, die momentan im Notepad-Prozess geladen sind, geben Sie diesen Befehl ein:

    Lm

    Die Ausgabe sieht in etwa wie das folgende Beispiel aus:

    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)    
    

    Um eine Stapelüberwachung anzuzeigen, geben Sie diesen Befehl ein:

    k

    Die Ausgabe sieht in etwa wie das folgende Beispiel aus:

    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. Um Notepad erneut zu starten, geben Sie diesen Befehl ein:

    g

    Nächster: Sie unterbrechen die Ausführung und erkunden die geladenen Module.

  8. Um in Notepad zu pausieren, wählen Sie im Menü Datei die OptionPause aus.

  9. Um einen Haltepunkt festzulegen und zu ZwWriteFileüberprüfen, geben Sie die folgenden Befehle ein:

    bu ntdll! ZwWriteFile

    bl

  10. Um Notepad erneut zu starten, geben Sie g ein. Geben Sie im Notepad-Fenster einen Text ein. Klicken Sie im Menü File (Datei) auf Save (Speichern). Der ausgeführte Code pausiert, wenn ZwCreateFile eintritt. Geben Sie den Befehl k ein, um die Stapelüberwachung anzuzeigen.

    Screenshot einer Stapelüberwachung in WinDbg.

    Im WinDbg-Fenster links neben der Befehlszeile werden die Prozessor- und Threadnummern angezeigt. In diesem Beispiel ist die aktuelle Prozessornummer 0, und die aktuelle Threadnummer ist 11 (0:011>). Das Fenster zeigt die Stapelüberwachung für Thread 11 an, die auf Prozessor 0 ausgeführt wird.

  11. Um eine Liste aller Threads im Notepad-Prozess anzuzeigen, geben Sie diesen Befehl (die Tilde) ein:

    ~

    Die Ausgabe sieht in etwa wie das folgende Beispiel aus:

    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 diesem Beispiel haben 14 Threads Indizes 0 bis 13.

  12. Um die Stapelüberwachung für Thread 0 anzuzeigen, geben Sie die folgenden Befehle ein:

    ~0s

    k

    Die Ausgabe sieht in etwa wie das folgende Beispiel aus:

    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. Um das Debuggen zu beenden und sich vom Notepad-Prozess zu trennen, geben Sie diesen Befehl ein:

    Qd

Öffnen Sie Ihre eigene Anwendung und fügen Sie WinDbg hinzu

Gehen Sie beispielsweise davon aus, dass Sie diese kleine Konsolenanwendung geschrieben und erstellt haben:

...
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);
}

Gehen Sie für diese Übung davon aus, dass sich die integrierte Anwendung (MyApp.exe) und die Symboldatei (MyApp.pdb) in C:\MyApp\x64\Debug befinden. Gehen Sie außerdem davon aus, dass sich der Anwendungsquellcode in C:\MyApp\MyApp befindet und dass der Zielcomputer MyApp.exe kompiliert wurde.

  1. Öffnen Sie WinDbg.

  2. Wählen Sie im Menü Datei die Option Ausführbare Datei starten aus. Wechseln Sie im Dialogfeld "Ausführbare Datei starten " zu "C:\MyApp\x64\Debug". Geben Sie als DateinamenMyApp.exe ein. Wählen Sie Öffnen aus.

  3. Geben Sie die folgenden Befehle ein:

    .symfix

    .sympath+ C:\MyApp\x64\Debug

    Mit diesen Befehlen wird WinDbg mitgeteilt, wo Symbole und Quellcode für Ihre Anwendung gefunden werden sollen. In diesem Fall müssen Sie den Quellcodespeicherort nicht mithilfe von .srcpath festlegen, da die Symbole vollqualifizierte Pfade zu den Quelldateien haben.

  4. Geben Sie die folgenden Befehle ein:

    .nachladen

    bu MyApp!main

    g

    Ihre Anwendung tritt in den Debugger ein, wenn sie die main Funktion erreicht.

    WinDbg zeigt den Quellcode und das Befehlsfenster an.

    Screenshot des Quellcodes, der in WinDbg angezeigt wird.

  5. Wählen Sie im Menü Debug die Option Einzelschritt aus (oder wählen Sie F11 aus). Fahren Sie mit dem Schritt fort, bis Sie zu diesem Schritt gelangen MyFunction. Wenn Sie in die Zeile y = x / p2 wechseln, stürzt ihre Anwendung ab und pausiert den Debugger.

    Die Ausgabe sieht in etwa wie das folgende Beispiel aus:

    (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. Geben Sie diesen Befehl ein:

    !analyze -v

    WinDbg zeigt eine Analyse des Problems an (in diesem Fall Division durch 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;
    ...
    

Nächste Schritte

Nachdem Sie sowohl eine Systemanwendung als auch Ihren eigenen Code debuggen, können Sie erweiterte Debugszenarien untersuchen:

Zusammenfassung der Befehle

Hier sind die wesentlichen Befehle, die Sie in diesem Lernprogramm verwenden:

Setup und Symbole:

Steuern der Ausführung:

  • g (Go) – Programmausführung fortsetzen
  • bu (Haltepunkt festlegen) – Ausführung an einer bestimmten Funktion anhalten
  • Step Into (F11) – Eine Anweisung ausführen und in Funktionen eintreten

Überprüfung Ihres Programms:

Referenz:

Weitere Informationen

Erste Schritte mit WinDbg (Kernelmodus)

Debuggervorgang

Debugtechniken

Herunterladen und Installieren des WinDbg Windows-Debugger-

WinDbg-Features