Treiber debuggen – Schritt-für-Schritt-Lab (Sysvad-Kernelmodus)
Dieses Lab bietet praktische Übungen, die zeigen, wie man den Sysvad Audio-Kernelmodus-Gerätetreiber debuggt.
Microsoft Windows Debugger (WinDbg) ist ein leistungsfähiges Windows-basiertes Debugging-Tool, mit dem Sie sowohl im Benutzermodus als auch im Kernelmodus debuggen können. WinDbg bietet Debugging auf Quellcodeebene für den Windows-Kernel, Kernelmodustreiber und Systemdienste sowie für Anwendungen und Treiber im Benutzermodus.
WinDbg kann durch den Quellcode schreiten, Haltepunkte setzen, Variablen (einschließlich C++-Objekte), Spuren stapeln und Speicher anzeigen. Das Fenster „Debugger Command“ (Debuggerbefehl) ermöglicht es dem Benutzer, eine Vielzahl von Befehlen ausstellen zu können.
Setup der Übungsumgebung
Sie benötigen die folgende Hardware für das Lab:
- Einen Laptop oder Desktop-Computer (Host) mit Windows 10
- Einen Laptop oder Desktop-Computer (Ziel) mit Windows 10
- Einen Netzwerk-Hub/Router und Netzwerkkabel zur Verbindung der beiden PCs
- Zugang zum Internet, um Symboldateien herunterzuladen
Sie benötigen die folgende Software für das Lab:
- Microsoft Visual Studio 2017
- Windows Software Development Kit (SDK) für Windows 10
- Windows Driver Kit (WDK) für Windows 10
- Den Sysvad Audio-Treiber für Windows 10
Informationen zum Herunterladen und Installieren des WDK finden Sie unter Download the Windows Driver Kit (WDK).
Sysvad-Debugging-Walkthrough
Dieses Lab führt Sie durch den Prozess der Fehlersuche in einem Kernelmodustreiber. Die Übungen verwenden das Beispiel des virtuellen Audiotreibers Syvad. Da der Syvad-Audiotreiber nicht mit der eigentlichen Audiohardware interagiert, kann er auf den meisten Geräten verwendet werden. Das Lab umfasst die folgenden Aufgaben:
- Abschnitt 1: Verbindung zu einer WinDbg-Sitzung im Kernelmodus
- Abschnitt 2: Befehle und Techniken zum Debuggen im Kernelmodus
- Abschnitt 3: Herunterladen und Erstellen des Sysvad-Audiotreibers
- Abschnitt 4: Installieren des Sysvad-Audiotreibers auf dem Zielsystem
- Abschnitt 5: Verwenden von WinDbg, um Informationen über den Treiber anzuzeigen
- Abschnitt 6: Anzeigen von Plug-and-Play-Gerätestrukturinformationen
- Abschnitt 7: Arbeiten mit Haltepunkten und Quellcode
- Abschnitt 8: Betrachten der Variablen
- Abschnitt 9: Anzeigen von Aufrufstapeln
- Abschnitt 10: Anzeigen von Prozessen und Threads
- Abschnitt 11: IRQL, Register und Disassemblierung
- Abschnitt 12: Arbeiten mit Speicher
- Abschnitt 13: Abschluss der WinDbg-Sitzung
- Abschnitt 14: Ressourcen zum Debuggen unter Windows
Echo-Treiber-Lab
Der Echo-Treiber ist einfacher gestaltet als der Sysvad-Audiotreiber. Wenn Sie WinDbg noch nicht kennen, sollten Sie zunächst das Debuggen von universellen Treibern – Schritt-für-Schritt-Lab (Echo-Kernelmodus) absolvieren. In diesem Lab werden die Anweisungen für die Einrichtung aus diesem Lab wiederverwendet. Wenn Sie also dieses Lab abgeschlossen haben, können Sie die Abschnitte 1 und 2 hier überspringen.
Abschnitt 1: Verbindung zu einer WinDbg-Sitzung im Kernelmodus
In Abschnitt 1 werden Sie das Netzwerk-Debugging auf dem Host- und dem Zielsystem konfigurieren.
Die PCs in diesem Lab müssen so konfiguriert sein, dass sie eine Ethernet-Netzwerkverbindung für das Kernel-Debugging verwenden.
In diesem Lab werden zwei Computer verwendet. WinDbg läuft auf dem Hostsystem und der Sysvad-Treiber läuft auf dem Zielsystem .
Verwenden Sie einen Netzwerk-Hub/Router und Netzwerkkabel, um die beiden PCs zu verbinden.
Um mit Kernelmodus-Anwendungen zu arbeiten und WinDbg zu verwenden, empfehlen wir Ihnen, den KDNET-over-Ethernet-Transport zu verwenden. Informationen zur Verwendung des Ethernet-Transportprotokolls finden Sie unter Erste Schritte mit WinDbg (Kernelmodus). Weitere Informationen zum Einrichten des Zielcomputers finden Sie unter Vorbereiten eines Computers für die manuelle Treiberbereitstellung und Automatisches Einrichten des KDNET-Netzwerk-Kernel-Debugging.
Konfigurieren des Kernelmodus-Debugging über Ethernet
Um das Debugging im Kernelmodus auf dem Zielsystem zu aktivieren, führen Sie die folgenden Schritte aus.
<– Auf dem Hostsystem
- Öffnen Sie eine Eingabeaufforderung auf dem Hostsystem und geben Sie ipconfig /all ein, um seine IP-Adresse zu ermitteln.
C:\>ipconfig /all
Windows IP Configuration
Host Name . . . . . . . . . . . . : TARGETPC
...
Ethernet adapter Ethernet:
Connection-specific DNS Suffix . :
Link-local IPv6 Address . . . . . : fe80::c8b6:db13:d1e8:b13b3
Autoconfiguration IPv4 Address. . : 169.182.1.1
Subnet Mask . . . . . . . . . . . : 255.255.0.0
Default Gateway . . . . . . . . . :
Notieren Sie die IP-Adresse des Hostsystems: ______________________________________
Notieren Sie den Hostnamen des Hostsystems: ______________________________________
–> Auf dem Zielsystem
- Öffnen Sie eine Eingabeaufforderung auf dem Zielsystem und verwenden Sie den Befehl ping, um die Netzwerkkonnektivität zwischen den beiden Systemen zu überprüfen. Verwenden Sie die tatsächliche IP-Adresse des Hostsystems, das Sie aufgezeichnet haben, anstelle von 169.182.1.1, die in der Beispielausgabe angezeigt wird.
C:\> ping 169.182.1.1
Pinging 169.182.1.1 with 32 bytes of data:
Reply from 169.182.1.1: bytes=32 time=1ms TTL=255
Reply from 169.182.1.1: bytes=32 time<1ms TTL=255
Reply from 169.182.1.1: bytes=32 time<1ms TTL=255
Reply from 169.182.1.1: bytes=32 time<1ms TTL=255
Ping statistics for 169.182.1.1:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 0ms, Maximum = 1ms, Average = 0ms
Um das Dienstprogramm KDNET zu verwenden, um das Debugging im Kernelmodus auf dem Zielsystem zu aktivieren, führen Sie die folgenden Schritte durch.
Suchen Sie auf dem Hostsystem das Verzeichnis WDK KDNET. Standardmäßig befindet sie sich hier.
C:\Program Files (x86)\Windows Kits\10\Debuggers\x64
In diesem Lab wird davon ausgegangen, dass auf beiden PCs eine 64-Bit-Version von Windows läuft, sowohl auf dem Ziel als auch auf dem Host. Wenn dies nicht der Fall ist, besteht der beste Ansatz darin, die gleiche Bitanzahl von Tools auf dem Host auszuführen, den das Ziel ausführt. Wenn das Ziel beispielsweise mit einem 32-Bit-Windows läuft, führen Sie eine 32-Version des Debuggers auf dem Host aus. Weitere Informationen finden Sie unter Auswahl der 32-Bit- oder 64-Bit-Debugging-Tools.
Suchen Sie diese beiden Dateien und kopieren Sie sie auf eine Netzwerkfreigabe oder einen USB-Stick, so dass sie auf dem Zielcomputer verfügbar sind.
kdnet.exe
VerifiedNICList.xml
Öffnen Sie auf dem Zielcomputer ein Eingabeaufforderungsfenster als Administrator. Geben Sie diesen Befehl ein, um zu überprüfen, ob die Netzwerkkarte des Ziel-PCs unterstützt wird.
C:\KDNET>kdnet
Network debugging is supported on the following NICs:
busparams=0.25.0, Intel(R) 82579LM Gigabit Network Connection, KDNET is running on this NIC.kdnet.exe
- Geben Sie diesen Befehl ein, um die IP-Adresse des Hostsystems festzulegen. Verwenden Sie die tatsächliche IP-Adresse des Hostsystems, das Sie aufgezeichnet haben, anstelle von 169.182.1.1, die in der Beispielausgabe angezeigt wird. Wählen Sie für jedes Ziel/Host-Paar, mit dem Sie arbeiten, eine eindeutige Anschlussadresse, z. B. 50010.
C:\>kdnet 169.182.1.1 50010
Enabling network debugging on Intel(R) 82577LM Gigabit Network Connection.
Key=2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
Wichtig
Bevor Sie BCDEdit zum Ändern der Startinformationen verwenden, müssen Sie möglicherweise die Windows-Sicherheitsfunktionen wie BitLocker und Secure Boot auf dem Test-PC vorübergehend aussetzen. Aktivieren Sie diese Sicherheitsfeatures nach Abschluss des Tests erneut, und verwalten Sie den Test-PC entsprechend, wenn die Sicherheitsfeatures deaktiviert sind. Secure Boot ist in UEFI normalerweise deaktiviert. Um auf die UEFI-Einstellungen zuzugreifen, verwenden Sie System, Recovery, Advanced start-up. Wählen Sie beim Neustart Fehlerbehebung, Erweiterte Optionen, UEFI-Firmware-Einstellungen. Seien Sie vorsichtig, da eine falsche Einstellung der UEFI-Optionen oder die Deaktivierung von BitLocker das System funktionsunfähig machen kann.
- Geben Sie diesen Befehl ein, um zu bestätigen, dass die dbgsettings ordnungsgemäß festgelegt sind.
C:\> bcdedit /dbgsettings
busparams 0.25.0
key 2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
debugtype NET
hostip 169.182.1.1
port 50010
dhcp Yes
The operation completed successfully.
Kopieren Sie den automatisch generierten eindeutigen Schlüssel in eine Textdatei, damit Sie ihn nicht auf dem Host-PC eintippen müssen. Kopieren Sie die Textdatei mit dem Schlüssel auf das Hostsystem.
HinweisFirewalls und Debugger
Wenn Sie eine Popup-Meldung von der Firewall erhalten und den Debugger verwenden möchten, aktivieren Sie alle drei Kästchen .
<– Auf dem Hostsystem
- Öffnen Sie auf dem Host-Computer ein Eingabeaufforderungsfenster als Administrator. Wechseln Sie in das Verzeichnis WinDbg.exe. Wir werden die x64-Version von WinDbg.exe aus dem Windows Driver Kit (WDK) verwenden, das als Teil der Windows-Kit-Installation installiert wurde.
C:\> Cd C:\Program Files (x86)\Windows Kits\10\Debuggers\x64
- Starten Sie WinDbg mit Remote User Debug mit dem folgenden Befehl. Die Werte für den Schlüssel und den Anschluss entsprechen den Werten, die Sie zuvor mit BCDEdit auf dem Ziel festgelegt haben.
C:\> WinDbg –k net:port=50010,key=2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
->Auf dem Zielsystem
Starten Sie das Zielsystem neu.
<-Auf dem Hostsystem
In ein oder zwei Minuten sollte die Debug-Ausgabe auf dem Hostsystem angezeigt werden.
Das Debugger-Befehlsfenster ist das wichtigste Debugging-Informationsfenster in WinDbg. In diesem Fenster können Sie Debugger-Befehle eingeben und die Befehlsausgabe ansehen.
Das Debugger-Befehlsfenster ist in zwei Bereiche unterteilt. Sie geben Befehle in das kleinere Fenster (das Befehlseingabefenster) am unteren Rand des Fensters ein und sehen die Befehlsausgabe im größeren Fenster am oberen Rand des Fensters.
Verwenden Sie im Befehlseingabebereich die Pfeil-nach-oben- und Pfeil-nach-unten-Tasten, um durch den Befehlsverlauf zu blättern. Wenn ein Befehl erscheint, können Sie ihn bearbeiten oder die Eingabetaste drücken, um den Befehl auszuführen.
Abschnitt 2: Befehle und Techniken zum Debuggen im Kernelmodus
In Abschnitt 2 werden Sie Debug-Befehle verwenden, um Informationen über das Zielsystem anzuzeigen.
<– Auf dem Hostsystem
Aktivieren der Debugger Markup Language (DML) mit .prefer_dml
Einige Debug-Befehle zeigen Text in Debugger Markup Language an, den Sie auswählen können, um schnell weitere Informationen zu erhalten.
- Verwenden Sie Strg+Break (Rollen-Taste) in WinDBg, um in den auf dem Zielsystem laufenden Code einzudringen. Es kann einige Zeit dauern, bis das Zielsystem reagiert.
- Geben Sie den folgenden Befehl ein, um DML im Befehlsfenster des Debuggers zu aktivieren.
0: kd> .prefer_dml 1
DML versions of commands on by default
Verwenden Sie .hh, um Hilfe zu erhalten
Mit dem Befehl .hh können Sie die Hilfe für Referenzbefehle aufrufen.
- Geben Sie den folgenden Befehl ein, um die Befehlsreferenzhilfe für .prefer_dml anzuzeigen.
0: kd> .hh .prefer_dml
Die Hilfedatei des Debuggers zeigt die Hilfe für den Befehl .prefer_dml an.
Anzeige der Version von Windows auf dem Zielsystem
- Zeigen Sie detaillierte Versionsinformationen auf dem Zielsystem an, indem Sie im WinDbg-Fenster den Befehl vertarget (Show Target Computer Version) eingeben.
0: kd> vertarget
Windows 10 Kernel Version 9926 MP (4 procs) Free x64
Product: WinNt, suite: TerminalServer SingleUserTS
Built by: 9926.0.amd64fre.fbl_awesome1501.150119-1648
Machine Name: ""
Kernel base = 0xfffff801`8d283000 PsLoadedModuleList = 0xfffff801`8d58aef0
Debug session time: Fri Feb 20 10:15:17.807 2015 (UTC - 8:00)
System Uptime: 0 days 01:31:58.931
Liste der geladenen Module
- Sie können überprüfen, ob Sie mit dem richtigen Kernelmodus-Prozess arbeiten, indem Sie die geladenen Module anzeigen, indem Sie den Befehl lm (List Loaded Modules) in das WinDbg-Fenster eingeben.
0: Kd> lm
start end module name
fffff801`09200000 fffff801`0925f000 volmgrx (no symbols)
fffff801`09261000 fffff801`092de000 mcupdate_GenuineIntel (no symbols)
fffff801`092de000 fffff801`092ec000 werkernel (export symbols) werkernel.sys
fffff801`092ec000 fffff801`0934d000 CLFS (export symbols) CLFS.SYS
fffff801`0934d000 fffff801`0936f000 tm (export symbols) tm.sys
fffff801`0936f000 fffff801`09384000 PSHED (export symbols) PSHED.dll
fffff801`09384000 fffff801`0938e000 BOOTVID (export symbols) BOOTVID.dll
fffff801`0938e000 fffff801`093f7000 spaceport (no symbols)
fffff801`09400000 fffff801`094cf000 Wdf01000 (no symbols)
fffff801`094d9000 fffff801`09561000 CI (export symbols) CI.dll
...
Hinweis Ausgelassene Ausgaben sind in diesem Lab mit „...“ gekennzeichnet.
Da wir den Symbolpfad und die geladenen Symbole noch nicht festgelegt haben, sind im Debugger nur begrenzte Informationen verfügbar.
Abschnitt 3: Herunterladen und Erstellen des Sysvad-Audiotreibers
In Abschnitt 3 werden Sie den Sysvad-Audiotreiber herunterladen und erstellen.
Normalerweise arbeiten Sie mit Ihrem eigenen Treibercode, wenn Sie WinDbg verwenden. Um sich mit dem Debuggen von Audiotreibern vertraut zu machen, wird der virtuelle Audio-Beispieltreiber von Sysvad verwendet. Dieses Beispiel soll veranschaulichen, wie Sie in Einzelschritten durch nativen Kernelmodus-Code gehen können. Diese Technik kann bei der Fehlersuche in komplexem Kernelmodus-Code sehr nützlich sein.
Um den Sysvad-Beispieltreiber herunterzuladen und zu erstellen, führen Sie die folgenden Schritte aus.
Laden Sie das Sysvad-Audiobeispiel von GitHub herunter und extrahieren Sie es
Sie können einen Browser verwenden, um das Sysvad-Beispiel und die Readme.md-Datei hier anzusehen:
https://github.com/Microsoft/Windows-driver-samples/tree/main/audio/sysvad
Dieses Lab zeigt, wie man die universellen Treiberbeispiele in einer Zip-Datei herunterlädt.
a. Laden Sie die Datei master.zip auf Ihre lokale Festplatte herunter.
https://github.com/Microsoft/Windows-driver-samples/archive/master.zip
b. Wählen und halten Sie (oder klicken Sie mit der rechten Maustaste) Windows-driver-samples-master.zip, und wählen Sie Extract All. Geben Sie einen neuen Ordner an oder navigieren Sie zu einem vorhandenen Ordner, in dem die extrahierten Dateien gespeichert werden sollen. Sie könnten zum Beispiel C:\WDK_Samples\ als neuen Ordner angeben, in den die Dateien extrahiert werden.
c. Nachdem die Dateien extrahiert wurden, navigieren Sie zum folgenden Unterordner.
C:\WDK_Samples\Sysvad
Öffnen Sie die Treiberlösung in Visual Studio
Wählen Sie in Visual Studio File>Open>Project/Solution... und navigieren Sie zu dem Ordner, der die extrahierten Dateien enthält (z. B. C:\WDK_Samples\Sysvad). Doppelklicken Sie auf die Lösungsdatei Syvad.
Suchen Sie in Visual Studio den Solution Explorer. (Falls dieser nicht bereits geöffnet ist, wählen Sie Solution Explorer aus dem Menü View (Ansicht).) Im Projektmappen-Explorer sehen Sie eine Projektmappe, die eine Reihe von Projekten enthält.
Einstellen der Konfiguration und der Plattform der Probe
Wählen Sie im Projektmappen-Explorer mit der rechten Maustaste oder durch Halten Solution 'sysvad' (7 of 7 projects) und wählen Sie Configuration Manager. Stellen Sie sicher, dass die Konfigurations- und Plattformeinstellungen für alle vier Projekte gleich sind. Standardmäßig ist die Konfiguration auf „Win10 Debug“ und die Plattform auf „Win64“ für alle Projekte eingestellt. Wenn Sie bei einem Projekt Änderungen an der Konfiguration und/oder der Plattform vornehmen, müssen Sie die gleichen Änderungen auch bei den übrigen drei Projekten vornehmen.
Hinweis Diese Übung setzt voraus, dass 64-Bit-Windows verwendet wird. Wenn Sie 32-Bit-Windows verwenden, erstellen Sie den Treiber für 32-Bit.
Treibersignierung prüfen
Suchen Sie das TabletAudioSample. Öffnen Sie die Eigenschaftsseite des Sysvad-Treibers und stellen Sie sicher, dass Driver Signing>Sign Mode auf Test Sign eingestellt ist.
Treibermuster müssen geändert werden, um Werte zu verwenden, die sich nicht mit bestehenden Treibern überschneiden. Unter From Sample Code to Production Driver - What to Change in the Samples erfahren Sie, wie Sie ein einzigartiges Treiberbeispiel erstellen, das mit den in Windows installierten echten Treibern koexistiert.
Erstellen Sie das Beispiel mit Visual Studio
Wählen Sie in Visual Studio Build>Build Solution.
In den Build-Fenstern sollte eine Meldung erscheinen, die besagt, dass der Build für alle sechs Projekte erfolgreich war.
Tipp
Wenn Sie eine Build-Fehlermeldung erhalten, verwenden Sie die Build-Fehlernummer, um eine Lösung zu finden. Zum Beispiel beschreibt MSBuild-Fehler MSB8040, wie man mit Bibliotheken arbeitet, die durch Spectre abgeschwächt wurden.
Suchen Sie die erstellten Treiberdateien
Navigieren Sie im Datei-Explorer zu dem Ordner, der die extrahierten Dateien für das Beispiel enthält. Sie würden zum Beispiel zu C:\WDK_Samples\Sysvad navigieren, wenn dies der Ordner ist, den Sie zuvor angegeben haben. Der Speicherort der kompilierten Treiberdateien innerhalb dieses Ordners hängt von den Konfigurations- und Plattformeinstellungen ab, die Sie im Configuration Manager ausgewählt haben. Wenn Sie beispielsweise die Standardeinstellungen unverändert lassen, werden die kompilierten Treiberdateien in einem Ordner mit dem Namen \x64\Debug für ein 64-Bit-Debug-Build gespeichert.
Navigieren Sie zu dem Ordner, der die erstellten Dateien für den TabletAudioSample-Treiber enthält:
C:\WDK_Samples\Sysvad\TabletAudioSample\x64\Debug. Der Ordner enthält den TabletAudioSample .SYS-Treiber, das Symbol pdp-Datei und die inf-Datei. Sie müssen auch die DelayAPO, KWSApo und KeywordDetectorContosoAdapter dlls und Symboldateien finden.
Zur Installation des Treibers benötigen Sie die folgenden Dateien.
Dateiname Beschreibung TabletAudioSample.sys Die Treiberdatei. TabletAudioSample.pdb Die Treibersymboldatei. tabletaudiosample.inf Eine Informationsdatei (INF), die die für die Installation des Treibers erforderlichen Informationen enthält. KeywordDetectorContosoAdapter.dll Ein Beispiel für einen Schlüsselwortdetektor. KeywordDetectorContosoAdapter.pdb Die Beispieldatei des Schlüsselwortdetektors. DelayAPO.dll Eine Sampledelay-APO. DelayAPO.pdb Die Verzögerungs-APO-Symboldatei. KWSApo.dll Eine Sample-Schlüsselwort-Spotter-APO. KWSApo.pdb Die Schlüsselwort-Spotter-Symboldatei. TabletAudioSample.cer Die TabletAudioSample-Zertifikatsdatei. Suchen Sie einen USB-Stick oder richten Sie eine Netzwerkfreigabe ein, um die erstellten Treiberdateien vom Host auf das Zielsystem zu kopieren.
Im nächsten Abschnitt werden Sie den Code auf das Zielsystem kopieren und den Treiber installieren und testen.
Abschnitt 4: Installieren Sie das Sysvad-Audiotreiberbeispiel auf dem Zielsystem
In Abschnitt 4 werden Sie devcon verwenden, um den Sysvad-Audiotreiber zu installieren.
–> Auf dem Zielsystem
Der Computer, auf dem Sie den Treiber installieren, wird als Zielcomputer oder als Testcomputer bezeichnet. In der Regel handelt es sich dabei um einen Computer, der von dem Computer getrennt ist, auf dem Sie das Treiberpaket entwickeln und erstellen. Der Computer, auf dem Sie den Treiber entwickeln und erstellen, wird als Hostcomputer bezeichnet.
Der Prozess des Verschiebens des Treiberpakets auf den Zielcomputer und der Installation des Treibers wird als Deployment bezeichnet.
Bevor Sie einen Treiber bereitstellen, müssen Sie den Zielcomputer vorbereiten, indem Sie die Testsignierung einschalten. Danach sind Sie bereit, das erstellte Treiberbeispiel auf dem Zielsystem auszuführen.
Um den Treiber auf dem Zielsystem zu installieren, führen Sie folgende Schritte durch.
Aktivieren von signierten Testtreibern
Ermöglicht die Ausführung von signierten Testtreibern:
Öffnen Sie Windows-Einstellungen.
Unter Update und Sicherheit, wählen Sie Wiederherstellung.
Wählen Sie unter Erweitertes Starten, Jetzt neu starten.
Wenn der PC neu startet, wählen Sie Troubleshoot.
Wählen Sie dann Erweiterte Optionen, Starteinstellungen und dann Neustart.
Wählen Sie die Option Durchsetzung der Treibersignatur deaktivieren, indem Sie die Taste F7 drücken.
Der PC wird mit den neuen Werten gestartet.
–> Auf dem Zielsystem
Installieren des Treibers
Die folgenden Anweisungen zeigen Ihnen, wie Sie den Beispieltreiber installieren und testen können.
Die für die Installation dieses Treibers erforderliche INF-Datei lautet TabletAudioSample.inf. Öffnen Sie auf dem Zielcomputer ein Eingabeaufforderungsfenster als Administrator. Navigieren Sie zu Ihrem Treiberpaketordner, klicken Sie mit der rechten Maustaste auf die Datei TabletAudioSample.inf und wählen Sie dann Installieren.
Es erscheint ein Dialogfeld, das anzeigt, dass der Testtreiber ein unsignierter Treiber ist. Wählen Sie Diesen Treiber trotzdem installieren, um fortzufahren.
Tipp
Wenn Sie Probleme mit der Installation haben, finden Sie in der folgenden Datei weitere Informationen.
%windir%\inf\setupapi.dev.log
Ausführlichere Anweisungen finden Sie unter Konfigurieren eines Computers für die Bereitstellung, das Testen und das Debuggen von Treibern.
Die INF-Datei enthält die Hardware-ID für die Installation der tabletaudiosample.sys. Für das Syvad-Beispiel lautet die Hardware-ID:
root\sysvad_TabletAudioSample
Überprüfen Sie den Treiber im Geräte-Manager
Geben Sie auf dem Zielcomputer in einem Eingabeaufforderungsfenster devmgmt ein, um den Geräte-Manager zu öffnen. Wählen Sie im Geräte-Manager im Menü Ansicht die Option Geräte nach Typ.
Suchen Sie in der Gerätestruktur Virtuelles Audiogerät (WDM) - Tablet Sample im Knoten Audiogerät. Dies geschieht in der Regel unter dem Knoten Sound, video and game controllers. Vergewissern Sie sich, dass sie installiert und aktiv ist.
Markieren Sie den Treiber für die aktuelle Hardware auf dem PC im Geräte-Manager. Wählen und halten Sie dann den Treiber (oder klicken Sie mit der rechten Maustaste) und wählen Sie deaktivieren, um den Treiber zu deaktivieren.
Vergewissern Sie sich im Geräte-Manager, dass der Audio-Hardware-Treiber mit einem Pfeil nach unten angezeigt wird, der angibt, dass er deaktiviert ist.
Nachdem Sie den Beispieltreiber erfolgreich installiert haben, können Sie ihn nun testen.
Testen Sie den Sysvad-Audiotreiber
Geben Sie auf dem Zielcomputer in einem Eingabeaufforderungsfenster devmgmt ein, um den Geräte-Manager zu öffnen. Wählen Sie im Geräte-Manager im Menü Ansicht die Option Geräte nach Typ. Suchen Sie in der Gerätestruktur nach Virtual Audio Device (WDM) - Tablet Sample.
Öffnen Sie die Systemsteuerung und navigieren Sie zu Hardware und Sound>Audiogeräte verwalten. Wählen Sie im Dialogfeld Sound das Lautsprechersymbol mit der Bezeichnung Virtual Audio Device (WDM) - Tablet Sample, und wählen Sie dann Set Default, aber wählen Sie nicht OK. Dadurch bleibt das Dialogfeld Sound geöffnet.
Suchen Sie eine MP3- oder andere Audiodatei auf dem Zielcomputer und doppelklicken Sie darauf, um sie abzuspielen. Überprüfen Sie dann im Dialogfeld Sound, ob die Lautstärkeanzeige des Treibers Virtual Audio Device (WDM) - Tablet Sample aktiv ist.
Abschnitt 5: Verwenden von WinDbg, um Informationen über den Treiber anzuzeigen
In Abschnitt 5 werden Sie den Symbolpfad festlegen und Kernel-Debugger-Befehle verwenden, um Informationen über den Sysvad-Beispieltreiber anzuzeigen.
Mit Hilfe von Symbolen kann WinDbg zusätzliche Informationen wie Variablennamen anzeigen, die bei der Fehlersuche von unschätzbarem Wert sein können. WinDbg verwendet die Debugsymbolformate von Microsoft Visual Studio für das Debugging auf Quellcodeebene. Es kann auf jedes Symbol oder jede Variable eines Moduls zugreifen, das über PDB-Symboldateien verfügt.
Um den Debugger zu laden, führen Sie die folgenden Schritte aus.
<-Auf dem Hostsystem
Wenn Sie den Debugger geschlossen haben, öffnen Sie ihn wieder mit dem folgenden Befehl in der Administrator-Eingabeaufforderung. Ersetzen Sie den Schlüssel und den Anschluss mit dem, was Sie zuvor konfiguriert haben.
C:\> WinDbg –k net:port=50010,key=2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
Verwenden Sie die Tastenkombination Strg+Break (Rollen-Taste), um in den Code des Zielsystems einzudringen.
Einstellen des Symbolpfads
Um den Symbolpfad zum Microsoft-Symbolserver in der WinDbg-Umgebung festzulegen, verwenden Sie den Befehl .symfix.
0: kd> .symfix
Um Ihre lokalen Symbole zu verwenden, fügen Sie den Pfad mit .sympath+ und dann .reload /f hinzu.
0: kd> .sympath+ C:\WDK_Samples\Sysvad 0: kd> .reload /f
Hinweis Der Befehl .reload mit der Option /f-force löscht alle Symbolinformationen für das angegebene Modul und lädt die Symbole neu. In einigen Fällen wird mit diesem Befehl auch das Modul selbst neu geladen oder entladen.
Hinweis Sie müssen die richtigen Symbole laden, um die erweiterten Funktionen von WinDbg nutzen zu können. Wenn Sie keine Symbole ordnungsgemäß konfiguriert haben, erhalten Sie Meldungen, die angeben, dass Symbole nicht verfügbar sind, wenn Sie versuchen, Funktionen zu verwenden, die von Symbolen abhängig sind.
0:000> dv
Unable to enumerate locals, HRESULT 0x80004005
Private symbols (symbols.pri) are required for locals.
Type “.hh dbgerr005” for details.
HinweisSymbolserver
Es gibt eine Reihe von Ansätzen, die für die Arbeit mit Symbolen verwendet werden können. In vielen Situationen können Sie den PC so konfigurieren, dass er bei Bedarf auf Symbole von einem Symbolserver zugreift, den Microsoft bereitstellt. In dieser Anleitung wird davon ausgegangen, dass dieser Ansatz verwendet wird. Wenn sich die Symbole in Ihrer Umgebung an einem anderen Ort befinden, ändern Sie die Schritte, um diesen Ort zu verwenden. Weitere Informationen finden Sie unter Symbolpfad für Windows-Debugger.
HinweisAnforderungen an Quellcode-Symbole verstehen
Um Quellcode-Debugging durchzuführen, müssen Sie eine geprüfte (Debug-)Version Ihrer Binärdateien erstellen. Der Compiler erstellt Symboldateien (.pdb-Dateien). Diese Symboldateien zeigen dem Debugger, wie die Binäranweisungen den Quellzeilen entsprechen. Die eigentlichen Quelldateien selbst müssen auch für den Debugger zugänglich sein.
Die Symboldateien enthalten nicht den Text des Quellcodes. Für die Fehlersuche ist es am besten, wenn der Linker Ihren Code nicht optimiert. Das Debuggen des Quellcodes und der Zugriff auf lokale Variablen sind schwieriger und manchmal fast unmöglich, wenn der Code optimiert wurde. Wenn Sie Probleme mit der Anzeige von lokalen Variablen oder Quellcodezeilen haben, setzen Sie die folgenden Build-Optionen.
cOMPILE_DEBUG=1 einstellen
eNABLE_OPTIMIZER=0 setzen
Geben Sie Folgendes in den Befehlsbereich des Debuggers ein, um Informationen über den Sysvad-Treiber anzuzeigen.
0: kd> lm m tabletaudiosample v Browse full module list start end module name fffff801`14b40000 fffff801`14b86000 tabletaudiosample (private pdb symbols) C:\Debuggers\sym\TabletAudioSample.pdb\E992C4803EBE48C7B23DC1596495CE181\TabletAudioSample.pdb Loaded symbol image file: tabletaudiosample.sys Image path: \SystemRoot\system32\drivers\tabletaudiosample.sys Image name: tabletaudiosample.sys Browse all global symbols functions data Timestamp: Thu Dec 10 12:20:26 2015 (5669DE8A) CheckSum: 0004891E ...
Weitere Informationen finden Sie unter lm.
Wählen Sie den Link Browse all global symbols in der Debug-Ausgabe, um Informationen über Elemente anzuzeigen, die mit dem Buchstaben a beginnen.
Da DML aktiviert ist, sind einige Elemente der Ausgabe Hot Links, die Sie auswählen können. Wählen Sie den Link data in der Debug-Ausgabe, um Informationen über Elemente anzuzeigen, deren Symbole mit dem Buchstaben a beginnen.
0: kd> x /D /f tabletaudiosample!a* A B C D E F G H I J K L M N O P Q R S T U V W X Y Z fffff806`9adb1000 tabletaudiosample!AddDevice (struct _DRIVER_OBJECT *, struct _DEVICE_OBJECT *)
Informationen finden Sie unter x (Symbole untersuchen).
Die Erweiterung !lmi zeigt detaillierte Informationen über ein Modul an. Geben Sie !lmi tabletaudiosample ein. Die Ausgabe sollte in etwa so aussehen wie der nachstehende Text.
0: kd> !lmi tabletaudiosample Loaded Module Info: [tabletaudiosample] Module: tabletaudiosample Base Address: fffff8069ad90000 Image Name: tabletaudiosample.sys Machine Type: 34404 (X64) Time Stamp: 58ebe848 Mon Apr 10 13:17:12 2017 Size: 48000 CheckSum: 42df7 Characteristics: 22 Debug Data Dirs: Type Size VA Pointer CODEVIEW a7, e5f4, d1f4 RSDS - GUID: {5395F0C5-AE50-4C56-AD31-DD5473BD318F} Age: 1, Pdb: C:\Windows-driver-samples-master\audio\sysvad\TabletAudioSample\x64\Debug\TabletAudioSample.pdb ?? 250, e69c, d29c [Data not mapped] Image Type: MEMORY - Image read successfully from loaded memory. Symbol Type: PDB - Symbols loaded successfully from image header. C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\sym\TabletAudioSample.pdb\5395F0C5AE504C56AD31DD5473BD318F1\TabletAudioSample.pdb Compiler: Resource - front end [0.0 bld 0] - back end [14.0 bld 24210] Load Report: private symbols & lines, not source indexed C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\sym\TabletAudioSample.pdb\5395F0C5AE504C56AD31DD5473BD318F1\TabletAudioSample.pdb
Verwenden Sie die Erweiterung !dh, um Kopfzeileninformationen wie unten gezeigt anzuzeigen.
0: kd> !dh tabletaudiosample File Type: EXECUTABLE IMAGE FILE HEADER VALUES 8664 machine (X64) 9 number of sections 5669DE8A time date stamp Thu Dec 10 12:20:26 2015 0 file pointer to symbol table 0 number of symbols F0 size of optional header 22 characteristics Executable App can handle >2gb addresses ...
Abschnitt 6: Anzeige von Plug-and-Play-Gerätebauminformationen
In Abschnitt 6 werden Sie Informationen über den Sysvad-Beispielgerätetreiber und seine Position im Plug-and-Play-Gerätebaum anzeigen.
Informationen über den Gerätetreiber in der Plug-and-Play-Gerätestruktur können bei der Fehlersuche hilfreich sein. Wenn beispielsweise ein Gerätetreiber nicht im Gerätebaum vorhanden ist, kann es ein Problem mit der Installation des Gerätetreibers geben.
Weitere Informationen über die Debug-Erweiterung für Geräteknoten finden Sie unter !devnode.
<-Auf dem Hostsystem
Um alle Geräteknoten im Plug & Play-Gerätebaum anzuzeigen, geben Sie den Befehl !devnode 0 1 ein. Die Ausführung dieses Befehls kann ein oder zwei Minuten dauern. Während dieser Zeit wird im Statusbereich von WinDbg die Meldung „*Busy“ angezeigt.
0: kd> !devnode 0 1 Dumping IopRootDeviceNode (= 0xffffe0005a3a8d30) DevNode 0xffffe0005a3a8d30 for PDO 0xffffe0005a3a9e50 InstancePath is "HTREE\ROOT\0" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeEnumerateCompletion (0x30d) DevNode 0xffffe0005a3a3d30 for PDO 0xffffe0005a3a4e50 InstancePath is "ROOT\volmgr\0000" ServiceName is "volmgr" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeEnumerateCompletion (0x30d) DevNode 0xffffe0005a324560 for PDO 0xffffe0005bd95ca0… ...
Verwenden Sie Strg+F, um in der erzeugten Ausgabe nach dem Namen des Gerätetreibers zu suchen, sysvad.
Ein Geräteknoteneintrag mit dem Namen
sysvad_TabletAudioSample
wird in der !devnode-Ausgabe für Syvad vorhanden sein.DevNode 0xffffe00086e68190 for PDO 0xffffe00089c575a0 InstancePath is "ROOT\sysvad_TabletAudioSample\0000" ServiceName is "sysvad_tabletaudiosample" State = DeviceNodeStarted (0x308) ...
Beachten Sie, dass die PDO-Adresse und die DevNode-Adresse angezeigt werden.
Verwenden Sie den Befehl
!devnode 0 1 sysvad_TabletAudioSample
, um die mit unserem Sysvad-Gerätetreiber verbundenen Plug-and-Play-Informationen anzuzeigen.0: kd> !devnode 0 1 sysvad_TabletAudioSample Dumping IopRootDeviceNode (= 0xffffe00082df8d30) DevNode 0xffffe00086e68190 for PDO 0xffffe00089c575a0 InstancePath is "ROOT\sysvad_TabletAudioSample\0000" ServiceName is "sysvad_tabletaudiosample" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeEnumerateCompletion (0x30d) DevNode 0xffffe000897fb650 for PDO 0xffffe00089927e30 InstancePath is "SWD\MMDEVAPI\{0.0.0.00000000}.{64097438-cdc0-4007-a19e-62e789062e20}" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeStartPostWork (0x307) DevNode 0xffffe00086d2f5f0 for PDO 0xffffe00089939ae0 InstancePath is "SWD\MMDEVAPI\{0.0.0.00000000}.{78880f4e-9571-44a4-a9df-960bde446487}" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeStartPostWork (0x307) DevNode 0xffffe00089759bb0 for PDO 0xffffe000875aa060 InstancePath is "SWD\MMDEVAPI\{0.0.0.00000000}.{7cad07f2-d0a0-4b9b-8100-8dc735e9c447}" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeStartPostWork (0x307) DevNode 0xffffe00087735010 for PDO 0xffffe000872068c0 InstancePath is "SWD\MMDEVAPI\{0.0.0.00000000}.{fc38551b-e69f-4b86-9661-ae6da78bc3c6}" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeStartPostWork (0x307) DevNode 0xffffe00088457670 for PDO 0xffffe0008562b830 InstancePath is "SWD\MMDEVAPI\{0.0.1.00000000}.{0894b831-c9fe-4c56-86a6-092380fc5628}" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeStartPostWork (0x307) DevNode 0xffffe000893dbb70 for PDO 0xffffe00089d68060 InstancePath is "SWD\MMDEVAPI\{0.0.1.00000000}.{15eb6b5c-aa54-47b8-959a-0cff2c1500db}" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeStartPostWork (0x307) DevNode 0xffffe00088e6f250 for PDO 0xffffe00089f6e990 InstancePath is "SWD\MMDEVAPI\{0.0.1.00000000}.{778c07f0-af9f-43f2-8b8d-490024f87239}" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeStartPostWork (0x307) DevNode 0xffffe000862eb4b0 for PDO 0xffffe000884443a0 InstancePath is "SWD\MMDEVAPI\{0.0.1.00000000}.{e4b72c7c-be50-45df-94f5-0f2922b85983}" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeStartPostWork (0x307)
Die im vorherigen Befehl angezeigte Ausgabe enthält das PDO, das mit der laufenden Instanz unseres Treibers verbunden ist, in diesem Beispiel ist es 0xffffe00089c575a0. Geben Sie den Befehl !devobj<PDO-Adresse> ein, um die mit dem Sysvad-Gerätetreiber verbundenen Plug-and-Play-Informationen anzuzeigen. Verwenden Sie die PDO-Adresse, die !devnode auf Ihrem PC anzeigt, nicht die hier gezeigte.
0: kd> !devobj 0xffffe00089c575a0 Device object (ffffe00089c575a0) is for: 0000004e \Driver\PnpManager DriverObject ffffe00082d47e60 Current Irp 00000000 RefCount 65 Type 0000001d Flags 00001040 SecurityDescriptor ffffc102b0f6d171 DevExt 00000000 DevObjExt ffffe00089c576f0 DevNode ffffe00086e68190 ExtensionFlags (0000000000) Characteristics (0x00000180) FILE_AUTOGENERATED_DEVICE_NAME, FILE_DEVICE_SECURE_OPEN AttachedDevice (Upper) ffffe00088386a50 \Driver\sysvad_tabletaudiosample Device queue is not busy.
Die im Befehl !devobj angezeigte Ausgabe enthält den Namen des angeschlossenen Geräts: \Driver\sysvad_tabletaudiosample. Verwenden Sie den Befehl !drvobj mit einer Bitmaske von 2, um Informationen über das angeschlossene Gerät anzuzeigen.
0: kd> !drvobj \Driver\sysvad_tabletaudiosample 2 Driver object (ffffe0008834f670) is for: \Driver\sysvad_tabletaudiosample DriverEntry: fffff80114b45310 tabletaudiosample!FxDriverEntry DriverStartIo: 00000000 DriverUnload: fffff80114b5fea0 tabletaudiosample!DriverUnload AddDevice: fffff80114b5f000 tabletaudiosample!AddDevice Dispatch routines: [00] IRP_MJ_CREATE fffff80117b49a20 portcls!DispatchCreate [01] IRP_MJ_CREATE_NAMED_PIPE fffff8015a949a00 nt!IopInvalidDeviceRequest [02] IRP_MJ_CLOSE fffff80115e26f90 ks!DispatchCleanup [03] IRP_MJ_READ fffff80115e32710 ks!DispatchRead [04] IRP_MJ_WRITE fffff80115e327e0 ks!DispatchWrite [05] IRP_MJ_QUERY_INFORMATION fffff8015a949a00 nt!IopInvalidDeviceRequest [06] IRP_MJ_SET_INFORMATION fffff8015a949a00 nt!IopInvalidDeviceRequest [07] IRP_MJ_QUERY_EA fffff8015a949a00 nt!IopInvalidDeviceRequest [08] IRP_MJ_SET_EA fffff8015a949a00 nt!IopInvalidDeviceRequest [09] IRP_MJ_FLUSH_BUFFERS fffff80115e32640 ks!DispatchFlush [0a] IRP_MJ_QUERY_VOLUME_INFORMATION fffff8015a949a00 nt!IopInvalidDeviceRequest [0b] IRP_MJ_SET_VOLUME_INFORMATION fffff8015a949a00 nt!IopInvalidDeviceRequest [0c] IRP_MJ_DIRECTORY_CONTROL fffff8015a949a00 nt!IopInvalidDeviceRequest [0d] IRP_MJ_FILE_SYSTEM_CONTROL fffff8015a949a00 nt!IopInvalidDeviceRequest [0e] IRP_MJ_DEVICE_CONTROL fffff80115e27480 ks!DispatchDeviceIoControl [0f] IRP_MJ_INTERNAL_DEVICE_CONTROL fffff8015a949a00 nt!IopInvalidDeviceRequest [10] IRP_MJ_SHUTDOWN fffff8015a949a00 nt!IopInvalidDeviceRequest [11] IRP_MJ_LOCK_CONTROL fffff8015a949a00 nt!IopInvalidDeviceRequest [12] IRP_MJ_CLEANUP fffff8015a949a00 nt!IopInvalidDeviceRequest [13] IRP_MJ_CREATE_MAILSLOT fffff8015a949a00 nt!IopInvalidDeviceRequest [14] IRP_MJ_QUERY_SECURITY fffff80115e326a0 ks!DispatchQuerySecurity [15] IRP_MJ_SET_SECURITY fffff80115e32770 ks!DispatchSetSecurity [16] IRP_MJ_POWER fffff80117b3dce0 portcls!DispatchPower [17] IRP_MJ_SYSTEM_CONTROL fffff80117b13d30 portcls!PcWmiSystemControl [18] IRP_MJ_DEVICE_CHANGE fffff8015a949a00 nt!IopInvalidDeviceRequest [19] IRP_MJ_QUERY_QUOTA fffff8015a949a00 nt!IopInvalidDeviceRequest [1a] IRP_MJ_SET_QUOTA fffff8015a949a00 nt!IopInvalidDeviceRequest [1b] IRP_MJ_PNP fffff80114b5f7d0 tabletaudiosample!PnpHandler
Geben Sie den Befehl !devstack<PDO-Adresse> ein, um die mit dem Gerätetreiber verbundenen Plug-and-Play-Informationen anzuzeigen. Die im Befehl !devnode 0 1 angezeigte Ausgabe enthält die PDO-Adresse, die mit der laufenden Instanz unseres Treibers verbunden ist. In diesem Beispiel ist es 0xffffe00089c575a0. Verwenden Sie die PDO-Adresse, die !devnode auf Ihrem PC anzeigt, nicht die unten abgebildete.
0: kd> !devstack 0xffffe00089c575a0 !DevObj !DrvObj !DevExt ObjectName ffffe00088d212e0 \Driver\ksthunk ffffe00088d21430 0000007b ffffe00088386a50 \Driver\sysvad_tabletaudiosampleffffe00088386ba0 0000007a > ffffe00089c575a0 \Driver\PnpManager 00000000 0000004e !DevNode ffffe00086e68190 : DeviceInst is "ROOT\sysvad_TabletAudioSample\0000" ServiceName is "sysvad_tabletaudiosample"
Die Ausgabe zeigt, dass wir einen recht einfachen Gerätetreiberstapel haben. Der Treiber sysvad_TabletAudioSample ist ein untergeordnetes Element des Knotens PnPManager. Der PnPManager ist ein Wurzelknoten.
Dieses Diagramm zeigt einen komplexeren Geräteknotenbaum.
Hinweis Weitere Informationen zu komplexeren Treiberstapeln finden Sie unter Treiberstapel und Geräteknoten und Gerätestapel.
Abschnitt 7: Arbeiten mit Haltepunkten
In Abschnitt 7 werden Sie mit Haltepunkten arbeiten, um die Codeausführung an bestimmten Stellen anzuhalten.
Haltepunkte mit Befehlen setzen
Haltepunkte werden verwendet, um die Codeausführung an einer bestimmten Codezeile anzuhalten. Sie können dann von diesem Punkt aus im Code vorwärts gehen, um diesen speziellen Codeabschnitt zu debuggen.
Um einen Haltepunkt mit einem Debug-Befehl zu setzen, verwenden Sie einen der folgenden b-Befehle.
bp |
Setzt einen Haltepunkt, der aktiv bleibt, bis das Modul, in dem er sich befindet, entladen wird. |
bu |
Setzt einen Haltepunkt, der nicht aufgelöst wird, wenn das Modul entladen wird, und der wieder aktiviert wird, wenn das Modul neu geladen wird. |
bm |
Setzt einen Haltepunkt für ein Symbol. Dieser Befehl verwendet bu oder bp entsprechend und ermöglicht die Verwendung von Platzhaltern *, um Haltepunkte für alle übereinstimmenden Symbole zu setzen (z. B. alle Methoden in einer Klasse). |
Verwenden Sie die WinDbg-Benutzeroberfläche, um zu bestätigen, dass Debug>Source Mode in der aktuellen WinDbg-Sitzung aktiviert ist.
Fügen Sie den Ort Ihres lokalen Codes zum Quellcodepfad hinzu, indem Sie den folgenden Befehl eingeben.
.sympath+ C:\WDK_Samples\Sysvad
Fügen Sie Ihr lokales Symbol in den Symbolpfad ein, indem Sie den folgenden Befehl eingeben.
.sympath+ C:\WDK_Samples\Sysvad
Einstellen der Debug-Maske
Wenn Sie mit einem Treiber arbeiten, kann es praktisch sein, alle Meldungen zu sehen, die er anzeigt. Geben Sie Folgendes ein, um die Standard-Debug-Bitmaske so zu ändern, dass alle Debug-Meldungen des Zielsystems im Debugger angezeigt werden.
0: kd> ed nt!Kd_DEFAULT_MASK 0xFFFFFFFF
Setzen Sie den Haltepunkt mit dem bm-Befehl und geben Sie dabei den Namen des Treibers ein, gefolgt von dem Funktionsnamen (AddDevice), an dem Sie den Haltepunkt setzen wollen, getrennt durch ein Ausrufezeichen.
0: kd> bm tabletaudiosample!AddDevice breakpoint 1 redefined 1: fffff801`14b5f000 @!"tabletaudiosample!AddDevice"
Sie können verschiedene Syntax in Verbindung mit dem Setzen von Variablen wie <Modul>!<Symbol>, <Klasse>::<Methode>,'<file.cpp>:<Zeilennummer>', oder überspringen Sie eine Anzahl von Zeiten <Bedingung><#>. Weitere Informationen finden Sie unter Verwenden von Haltepunkten.
Listen Sie die aktuellen Haltepunkte auf, um zu bestätigen, dass der Haltepunkt durch Eingabe des Befehls bl gesetzt wurde.
0: kd> bl 1 e fffff801`14b5f000 0001 (0001) tabletaudiosample!AddDevice
Starten Sie die Codeausführung auf dem Zielsystem neu, indem Sie den Befehl go g eingeben.
->Auf dem Zielsystem
Öffnen Sie unter Windows den Gerätemanager über das Symbol oder durch Eingabe von mmc devmgmt.msc. Erweitern Sie im Geräte-Manager den Knoten Sound-, Video- und Gamecontroller. Halten Sie den Eintrag des virtuellen Audiotreibers gedrückt (oder klicken Sie mit der rechten Maustaste darauf) und wählen Sie im Menü Disable.
Halten Sie den Eintrag für den virtuellen Audiotreiber erneut gedrückt (oder klicken Sie mit der rechten Maustaste darauf) und wählen Sie im Menü Enable aus.
<– Auf dem Hostsystem
Dies sollte Windows veranlassen, den Treiber neu zu laden, der AddDevice aufruft. Dadurch wird der AddDevice-Debug-Haltepunkt ausgelöst und die Ausführung des Treibercodes auf dem Zielsystem sollte angehalten werden.
Breakpoint 1 hit tabletaudiosample!AddDevice: fffff801`14baf000 4889542410 mov qword ptr [rsp+10h],rdx
Wenn Ihr Quellpfad richtig eingestellt ist, sollten Sie bei der AddDevice-Routine in adapter.cpp anhalten
{ PAGED_CODE(); NTSTATUS ntStatus; ULONG maxObjects; DPF(D_TERSE, ("[AddDevice]")); maxObjects = g_MaxMiniports; #ifdef SYSVAD_BTH_BYPASS // // Allow three (3) Bluetooth hands-free profile devices. // maxObjects += g_MaxBthHfpMiniports * 3; #endif // SYSVAD_BTH_BYPASS // Tell the class driver to add the device. // ntStatus = PcAddAdapterDevice ( DriverObject, PhysicalDeviceObject, PCPFNSTARTDEVICE(StartDevice), maxObjects, 0 ); return ntStatus; } // AddDevice
Gehen Sie Zeile für Zeile durch den Code, indem Sie den Befehl p eingeben oder F10 drücken. Sie können aus dem Sysvad-AddDevice-Code zu PpvUtilCall, PnpCallAddDevice und dann zum PipCallDriverAddDevice-Windows-Code übergehen. Sie können dem Befehl p eine Zahl hinzufügen, um mehrere Zeilen vorwärts zu gehen, zum Beispiel p 5.
Wenn Sie mit dem Durchlaufen des Codes fertig sind, verwenden Sie den Befehl go g, um die Ausführung auf dem Zielsystem neu zu starten.
Setzen von Speicherzugriffs-Haltepunkten
Sie können auch Haltepunkte setzen, die ausgelöst werden, wenn auf eine Speicherstelle zugegriffen wird. Verwenden Sie den Befehl ba (break on access) mit der folgenden Syntax.
ba <access> <size> <address> {options}
Option | Beschreibung |
---|---|
e |
Ausführen (wenn die CPU einen Befehl von der Adresse abruft) |
r |
Lesen/Schreiben (wenn die CPU die Adresse liest oder schreibt) |
w |
Schreiben (wenn die CPU an die Adresse schreibt) |
Beachten Sie, dass Sie immer nur vier Daten-Haltepunkte setzen können, und es liegt an Ihnen, sicherzustellen, dass Sie Ihre Daten korrekt ausrichten, sonst wird der Haltepunkt nicht ausgelöst (Wörter müssen auf durch 2 teilbare Adressen enden, Wörter müssen durch 4 teilbar sein, und Quadwörter durch 0 oder 8)
Um zum Beispiel einen Lese-/Schreib-Haltepunkt an einer bestimmten Speicheradresse zu setzen, verwenden Sie einen Befehl wie diesen.
ba r 4 fffff800`7bc9eff0
Ändern des Haltepunktstatus
Sie können vorhandene Haltepunkte mit den folgenden Befehlen ändern.
bl |
Listet Haltepunkte auf. |
bc |
Löscht einen Haltepunkt aus der Liste. Verwenden Sie bc *, um alle Haltepunkte zu löschen. |
bd |
Deaktiviert einen Haltepunkt. Verwenden Sie bd *, um alle Haltepunkte zu deaktivieren. |
be |
Aktiviert einen Haltepunkt. Verwenden Sie be *, um alle Haltepunkte zu aktivieren. |
Alternativ können Sie Haltepunkte auch ändern, indem Sie edit>breakpoints wählen. Beachten Sie, dass das Haltepunkt-Dialogfeld nur mit vorhandenen Haltepunkten funktioniert. Neue Haltepunkte müssen über die Befehlszeile gesetzt werden.
Setzen eines Haltepunkts auf MixerVolume
Verschiedene Teile des Audiotreibercodes werden aufgerufen, um auf verschiedene Ereignisse zu reagieren, nachdem der Gerätetreiber geladen wurde. Im nächsten Abschnitt setzen wir einen Haltepunkt, der ausgelöst wird, wenn der Benutzer den Lautstärkeregler für den virtuellen Audiotreiber einstellt.
Um einen Haltepunkt für MixerVolume zu setzen, führen Sie die folgenden Schritte aus.
<– Auf dem Hostsystem
Um die Methode zu finden, die das Volumen ändert, verwenden Sie den Befehl x, um die Symbole in CAdapterCommon aufzulisten, die die Zeichenfolge volume enthalten.
kd> x tabletaudiosample!CAdapterCommon::* ... fffff800`7bce26a0 tabletaudiosample!CAdapterCommon::MixerVolumeWrite (unsigned long, unsigned long, long) …
Verwenden Sie STRG+F, um in der Ausgabe nach oben nach der Lautstärke zu suchen und die Methode MixerVolumeWrite zu finden.
Löschen Sie die vorherigen Haltepunkte mit bc *.
Setzen Sie einen Symbol-Haltepunkt in der Routine CAdapterCommon::MixerVolumeWrite mit dem folgenden Befehl.
kd> bm tabletaudiosample!CAdapterCommon::MixerVolumeWrite 1: fffff801`177b26a0 @!"tabletaudiosample!CAdapterCommon::MixerVolumeWrite"
Listen Sie die Haltepunkte auf, um zu bestätigen, dass der Haltepunkt richtig gesetzt ist.
kd> bl 1 e fffff801`177b26a0 [c:\WDK_Samples\audio\sysvad\common.cpp @ 1668] 0001 (0001) tabletaudiosample!CAdapterCommon::MixerVolumeWrite
Starten Sie die Codeausführung auf dem Zielsystem neu, indem Sie den Befehl go g eingeben.
Wählen Sie in der Systemsteuerung Hardware und Sound>Sound. Wählen und halten Sie (oder klicken Sie mit der rechten Maustaste) Sink Description Sample und wählen Sie Properties. Wählen Sie die Registerkarte Levels. Stellen Sie die Lautstärke des Schiebereglers ein.
Dies sollte dazu führen, dass der SetMixerVolume-Debug-Haltepunkt ausgelöst und die Ausführung des Treibercodes auf dem Zielsystem angehalten wird.
kd> g Breakpoint 1 hit tabletaudiosample!CAdapterCommon::MixerVolumeWrite: fffff801`177b26a0 44894c2420 mov dword ptr [rsp+20h],r9d
Sie sollten bei dieser Zeile in common.cpp aufhören
{ if (m_pHW) { m_pHW->SetMixerVolume(Index, Channel, Value); } } // MixerVolumeWrite
Verwenden Sie den Befehl dv, um die aktuellen Variablen und ihre Werte anzuzeigen. Weitere Informationen zu den Variablen finden Sie im nächsten Abschnitt dieses Labs.
2: kd> dv this = 0x00000000`00000010 ulNode = 0x344 ulChannel = 0x210a45f8 lVolume = 0n24
Drücken Sie F10, um den Code in Einzelschritten zu bearbeiten.
Drücken Sie F5, um die Ausführung des Codes MixerVolumeWrite zu beenden.
Zusammenfassung – Schritt für Schritt durch den Code aus dem Debugger-Befehlsfenster
Nachfolgend finden Sie die Befehle, mit denen Sie Ihren Code durchgehen können (die zugehörigen Tastaturkürzel sind in Klammern angegeben).
Break in (Strg+Break) – Dieser Befehl unterbricht ein System, solange es läuft und in Kommunikation mit WinDbg steht (die Sequenz im Kernel-Debugger ist Strg+C).
Step over (F10) – Mit diesem Befehl wird der Code anweisungsweise ausgeführt. Trifft man auf einen Aufruf, wird der Code über den Aufruf hinweg ausgeführt, ohne in die aufgerufene Routine einzutreten. (Wenn die Programmiersprache C oder C++ ist und WinDbg sich im Quellcode-Modus befindet, kann der Quellcode-Modus mit Debug>Source Mode ein- oder ausgeschaltet werden).
Step in (F11) – Dieser Befehl ist wie Step-over, nur dass die Ausführung eines Aufrufs in die aufgerufene Routine geht.
Step out (Shift+F11) – Dieser Befehl veranlasst die Ausführung bis zur aktuellen Routine (aktuelle Position im Aufrufstapel) und verlässt diese. Dies ist nützlich, wenn Sie genug von der Routine gesehen haben.
Bis zum Cursor ausführen (F7 oder Strg+F10) – Platzieren Sie den Cursor in einem Quellcode- oder Disassemblierungsfenster an der Stelle, an der die Ausführung unterbrochen werden soll, und drücken Sie dann F7; der Code wird bis zu dieser Stelle ausgeführt. Wenn der Ablauf der Codeausführung den vom Cursor angegebenen Punkt nicht erreicht (z. B. wenn eine IF-Anweisung nicht ausgeführt wird), bricht WinDbg nicht ab, da die Codeausführung den angegebenen Punkt nicht erreicht hat.
Ausführen (F5) – Ausführen, bis ein Haltepunkt erreicht wird oder ein Ereignis wie eine Fehlerprüfung eintritt.
Erweiterte Optionen
Anweisung auf die aktuelle Zeile setzen (Strg+Umschalt+I) – In einem Quelltextfenster können Sie den Cursor auf eine Zeile setzen, diese Tastenkombination eingeben und die Ausführung des Codes beginnt an dieser Stelle, sobald Sie ihn weiterlaufen lassen (z. B. mit F5 oder F10). Dies ist praktisch, wenn Sie eine Sequenz wiederholen wollen, erfordert aber eine gewisse Vorsicht. So werden z. B. Register und Variablen nicht auf den Zustand gesetzt, den sie hätten, wenn die Codeausführung diese Zeile auf natürliche Weise erreicht hätte.
Direkte Einstellung des eip-Registers – Sie können einen Wert in das eip-Register eingeben, und sobald Sie F5 (oder F10, F11 usw.) drücken, beginnt die Ausführung ab dieser Adresse. Dies ist vergleichbar mit dem Setzen eines Befehls auf die vom Cursor vorgegebene aktuelle Zeile, mit dem Unterschied, dass Sie die Adresse eines Assembler-Befehls angeben.
Es kann einfacher sein, durch die Benutzeroberfläche zu gehen als über die Befehlszeile, daher wird diese Methode empfohlen. Falls erforderlich, können die folgenden Befehle verwendet werden, um eine Quelldatei in der Befehlszeile zu durchlaufen:
.lines – Aktiviert die Quellzeileninformation.
bp main – Setzt den ersten Haltepunkt am Anfang des Moduls.
l+t – Das Steppen erfolgt pro Quellzeile.
Wählen Sie Debug>Quellmodus, um in den Quellmodus zu gelangen; der Befehl
L+t
ist nicht ausreichend.l+s – Die Quellzeilen werden an der Eingabeaufforderung angezeigt.
g – Programm ausführen, bis „main“ eingegeben wird.
p – Führt eine Quellzeile aus.
Weitere Informationen finden Sie unter Source Code Debugging in WinDbg (Classic) in der Debugging-Referenzdokumentation.
Haltepunkte im Code setzen
Sie können einen Haltepunkt im Code setzen, indem Sie die Anweisung DebugBreak()
hinzufügen, das Projekt neu erstellen und den Treiber neu installieren. Dieser Haltepunkt wird jedes Mal ausgelöst, wenn der Treiber aktiviert wird, so dass es sich um eine Technik handelt, die in den frühen Entwicklungsphasen und nicht im Produktionscode verwendet werden sollte. Diese Technik ist nicht so flexibel wie das dynamische Setzen von Haltepunkten mit Hilfe der Haltepunktbefehle.
Tipp: Vielleicht möchten Sie eine Kopie des Sysvad-Treibers ohne den hinzugefügten Haltepunkt für weitere Labarbeiten aufbewahren.
Legen Sie eine Unterbrechung fest, die bei jeder Ausführung der AddDevice-Methode erfolgt, indem Sie die Anweisung
DebugBreak()
zum Beispielcode hinzufügen.... // Insert the DebugBreak() statment before the PcAddAdapterDevice is called. // DebugBreak() // Tell the class driver to add the device. // ntStatus = PcAddAdapterDevice ( DriverObject, PhysicalDeviceObject, PCPFNSTARTDEVICE(StartDevice), maxObjects, 0 ); return ntStatus; } // AddDevice
Führen Sie alle zuvor beschriebenen Schritte aus, um den Treiber in Microsoft Visual Studio neu zu erstellen und ihn auf dem Zielcomputer neu zu installieren. Stellen Sie sicher, dass Sie den vorhandenen Treiber deinstallieren, bevor Sie den aktualisierten Treiber installieren.
Löschen Sie alle vorherigen Haltepunkte und stellen Sie sicher, dass der Debugger an den Ziel-PC angeschlossen ist.
Wenn der Code ausgeführt wird und die Anweisung
DebugBreak
erreicht, wird die Ausführung angehalten und eine Meldung angezeigt.KERNELBASE!DebugBreak: 77b3b770 defe __debugbreak
Abschnitt 8: Variablen anzeigen
In Abschnitt 8 werden Sie Debugger-Befehle verwenden, um Variablen anzuzeigen.
Es kann nützlich sein, Variablen während der Ausführung des Codes zu untersuchen, um zu bestätigen, dass der Code wie erwartet funktioniert. In diesem Lab werden die Variablen untersucht, mit denen der Audiotreiber den Ton erzeugt.
Verwenden Sie den Befehl dv, um die mit der TabelleTAudiosample!CMiniportWaveRT::New* verbundenen Gebietsschema-Variablen zu untersuchen.
kd> dv tabletaudiosample!CMiniportWaveRT::New*
Löschen der vorherigen Haltepunkte
bc *
Setzen Sie mit dem folgenden Befehl einen Symbol-Haltepunkt in den CMiniportWaveCyclicStreamMSVAD-Routinen.
0: kd> bm tabletaudiosample!CMiniportWaveRT::NewStream 1: fffff801`177dffc0 @!"tabletaudiosample!CMiniportWaveRT::NewStream"
Starten Sie die Codeausführung auf dem Zielsystem neu, indem Sie den Befehl go g eingeben.
–> Auf dem Zielsystem
Suchen Sie eine kleine Mediendatei (z. B. eine Windows-Benachrichtigung mit der Dateierweiterung .wav) und wählen Sie die Datei aus, um sie abzuspielen. Sie können zum Beispiel Ring05.wav aus dem Verzeichnis Windows\Media verwenden.
<– Auf dem Hostsystem
Wenn die Mediendatei abgespielt wird, sollte der Haltepunkt ausgelöst werden, und die Ausführung des Treibercodes auf dem Zielsystem sollte anhalten.
Breakpoint 1 hit tabletaudiosample!CMiniportWaveRT::NewStream: fffff801`177dffc0 44894c2420 mov dword ptr [rsp+20h],r9d
Im Quellcode-Fenster sollte die geschweifte Klammer am Eingang zur NewStream-Funktion hervorgehoben werden.
/*++ Routine Description: The NewStream function creates a new instance of a logical stream associated with a specified physical channel. Callers of NewStream should run at IRQL PASSIVE_LEVEL. Arguments: OutStream - OuterUnknown - Pin - Capture - DataFormat - Return Value: NT status code. --*/ { ...
Lokale Variablen
Sie können die Namen und Werte aller lokalen Variablen für einen bestimmten Frame anzeigen, indem Sie den Befehl dv eingeben.
0: kd> dv this = 0xffffe000`4436f8e0 OutStream = 0xffffe000`49d2f130 OuterUnknown = 0xffffe000`4436fa30 Pin = 0 Capture = 0x01 ' DataFormat = 0xffffe000`44227790 signalProcessingMode = {487E9220-E000-FFFF-30F1-D24900E0FFFF} ntStatus = 0n1055 stream = 0x00000000`00000200
DML zum Anzeigen von Variablen verwenden
Wählen Sie die unterstrichenen Elemente aus, um DML zum Erkunden von Variablen zu verwenden. Die Select-Aktion erstellt einen dx (Display NatVis Expression) Befehl, mit dem Sie verschachtelte Datenstrukturen aufschlüsseln können.
0: kd> dx -r1 (*((tabletaudiosample!CMiniportWaveRT *)0xffffe001d10b8380)) (*((tabletaudiosample!CMiniportWaveRT *)0xffffe001d10b8380)) : [Type: CMiniportWaveRT] [+0x020] m_lRefCount : 0 [+0x028] m_pUnknownOuter : 0xffffe001d1477e50 : [Type: IUnknown *] [+0x030] m_ulLoopbackAllocated : 0x2050 [+0x034] m_ulSystemAllocated : 0x180 [+0x038] m_ulOffloadAllocated : 0x0 [+0x03c] m_dwCaptureAllocatedModes : 0x0 0: kd> dx -r1 (*((tabletaudiosample!_GUID *)0xffffd001c8acd348)) (*((tabletaudiosample!_GUID *)0xffffd001c8acd348)) : {487E9220-E000-FFFF-30F1-D24900E0FFFF} [Type: _GUID] [<Raw View>] 0: kd> dx -r1 -n (*((tabletaudiosample!_GUID *)0xffffd001c8acd348)) (*((tabletaudiosample!_GUID *)0xffffd001c8acd348)) : [Type: _GUID] [+0x000] Data1 : 0x487e9220 [+0x004] Data2 : 0xe000 [+0x006] Data3 : 0xffff [+0x008] Data4 : [Type: unsigned char [8]] 0: kd> dx -r1 -n (*((tabletaudiosample!unsigned char (*)[8])0xffffd001c8acd350)) (*((tabletaudiosample!unsigned char (*)[8])0xffffd001c8acd350)) : [Type: unsigned char [8]] [0] : 0x30 [1] : 0xf1 [2] : 0xd2 [3] : 0x49 [4] : 0x0 [5] : 0xe0 [6] : 0xff [7] : 0xff
Globale Variablen
Sie können den Speicherplatz einer globalen Variablen ermitteln, indem Sie ? <Name der Variablen>.
0: kd> ? signalProcessingMode Evaluate expression: -52768896396472 = ffffd001`c8acd348
Dies gibt die Speicherstelle der Variablen zurück, in diesem Fall ffffd001`c8acd348. Sie können den Inhalt des Speicherplatzes anzeigen, indem Sie den Wert dieses Speicherplatzes mit dem Befehl dd unter Verwendung des vom vorherigen Befehl zurückgegebenen Speicherplatzes ausgeben.
0: kd> dd ffffd001`c8acd348 ffffd001`c8acd348 487e9220 ffffe000 49d2f130 ffffe000 ffffd001`c8acd358 4837c468 ffffe000 18221570 ffffc000 ffffd001`c8acd368 4436f8e0 ffffe000 487e9220 ffffe000 ffffd001`c8acd378 18ab145b fffff801 4837c420 ffffe000 ffffd001`c8acd388 4436f8e0 ffffe000 49d2f130 ffffe000 ffffd001`c8acd398 4436fa30 ffffe000 00000000 00000000 ffffd001`c8acd3a8 00000001 00000000 44227790 ffffe000 ffffd001`c8acd3b8 18adc7f9 fffff801 495972a0 ffffe000
Sie können auch Variablennamen mit dem Befehl dd verwenden.
0: kd> dd signalProcessingMode ffffd001`c8acd348 487e9220 ffffe000 49d2f130 ffffe000 ffffd001`c8acd358 4837c468 ffffe000 18221570 ffffc000 ffffd001`c8acd368 4436f8e0 ffffe000 487e9220 ffffe000 ffffd001`c8acd378 18ab145b fffff801 4837c420 ffffe000 ffffd001`c8acd388 4436f8e0 ffffe000 49d2f130 ffffe000 ffffd001`c8acd398 4436fa30 ffffe000 00000000 00000000 ffffd001`c8acd3a8 00000001 00000000 44227790 ffffe000 ffffd001`c8acd3b8 18adc7f9 fffff801 495972a0 ffffe000
Variablen anzeigen
Verwenden Sie den Menüpunkt View>Locals, um lokale Variablen anzuzeigen. Diese Schnittstelle bietet auch die Möglichkeit, komplexere Datenstrukturen aufzuschlüsseln.
Verwenden Sie p oder F10, um im Code etwa 10 Zeilen vorwärts zu gehen, bis Sie die Codezeile ntStatus = IsFormatSupported(Pin, Capture, DataFormat); markieren.
PAGED_CODE(); ASSERT(OutStream); ASSERT(DataFormat); DPF_ENTER(("[CMiniportWaveRT::NewStream]")); NTSTATUS ntStatus = STATUS_SUCCESS; PCMiniportWaveRTStream stream = NULL; GUID signalProcessingMode = AUDIO_SIGNALPROCESSINGMODE_DEFAULT; *OutStream = NULL; // // If the data format attributes were specified, extract them. // if ( DataFormat->Flags & KSDATAFORMAT_ATTRIBUTES ) { // The attributes are aligned (QWORD alignment) after the data format PKSMULTIPLE_ITEM attributes = (PKSMULTIPLE_ITEM) (((PBYTE)DataFormat) + ((DataFormat->FormatSize + FILE_QUAD_ALIGNMENT) & ~FILE_QUAD_ALIGNMENT)); ntStatus = GetAttributesFromAttributeList(attributes, attributes->Size, &signalProcessingMode); } // Check if we have enough streams. // if (NT_SUCCESS(ntStatus)) { ntStatus = ValidateStreamCreate(Pin, Capture, signalProcessingMode); } // Determine if the format is valid. // if (NT_SUCCESS(ntStatus)) { ntStatus = IsFormatSupported(Pin, Capture, DataFormat); } ...
Verwenden Sie den Befehl dv, um die Namen und Werte aller lokalen Variablen für einen bestimmten Frame anzuzeigen. Beachten Sie, dass die Werte erwartungsgemäß anders sind als bei der letzten Ausführung dieses Befehls, da zusätzlicher Code ausgeführt wurde, der die lokalen Variablen ändert, und einige Variablen jetzt nicht im aktuellen Frame sind oder ihre Werte sich geändert haben.
2: kd> dv this = 0xffffe001`d1182000 OutStream = 0xffffe001`d4776d20 OuterUnknown = 0xffffe001`d4776bc8 Pin = 0 Capture = 0x00 ' DataFormat = 0xffffe001`cd7609b0 signalProcessingMode = {4780004E-7133-41D8-8C74-660DADD2C0EE} ntStatus = 0n0 stream = 0x00000000`00000000
Abschnitt 9: Anzeigen von Aufrufstapeln
In Abschnitt 9 werden Sie Aufrufstapel betrachten, um den Aufrufer/Aufrufer-Code zu untersuchen.
Der Aufrufstapel ist die Kette von Funktionsaufrufen, die zur aktuellen Position des Programmzählers geführt haben. Die oberste Funktion auf dem Aufrufstapel ist die aktuelle Funktion, die nächste Funktion ist die Funktion, die die aktuelle Funktion aufgerufen hat, und so weiter.
Um den Aufrufstapel anzuzeigen, verwenden Sie die Befehle k*:
kb |
Zeigt den Stack und die ersten drei Parameter an. |
kp |
Zeigt die Stapel und die vollständige Liste der Parameter an. |
kn |
Ermöglicht die Anzeige des Stapels mit den daneben liegenden Frameinformationen. |
Wenn Sie den Aufrufstapel verfügbar halten möchten, können Sie Ansicht>Aufrufstapel wählen, um ihn anzuzeigen. Wählen Sie die Spalten am oberen Rand des Fensters aus, um die Anzeige zusätzlicher Informationen umzuschalten.
Diese Ausgabe zeigt den Aufrufstapel beim Debuggen des Beispieladaptercodes in einem Break-Status.
0: kd> kb
# RetAddr : Args to Child : Call Site
00 fffff800`7a0fa607 : ffffe001`d1182000 ffffe001`d4776d20 ffffe001`d4776bc8 ffffe001`00000000 : tabletaudiosample!CMiniportWaveRT::NewStream+0x1dc [c:\data1\threshold\audio\endpointscommon\minwavert.cpp @ 597]
01 fffff800`7a0fb2c3 : 00000000`00000000 ffffe001`d122bb10 ffffe001`ceb81750 ffffe001`d173f058 : portcls!CPortPinWaveRT::Init+0x2e7
02 fffff800`7a0fc7f9 : ffffe001`d4776bc0 00000000`00000000 ffffe001`d10b8380 ffffe001`d122bb10 : portcls!CPortFilterWaveRT::NewIrpTarget+0x193
03 fffff800`7a180552 : 00000000`00000000 ffffe001`d10b8380 ffffe001`d122bb10 ffffe001`d4565600 : portcls!xDispatchCreate+0xd9
04 fffff800`7a109a9a : ffffe001`d10b84d0 ffffe001`d10b8380 00000000`00000000 ffffe001`00000000 : ks!KsDispatchIrp+0x272
05 fffff800`7bd314b1 : ffffe001`d122bb10 ffffd001`c3098590 ffffe001`d122bd90 ffffe001`ce80da70 : portcls!DispatchCreate+0x7a
06 fffff803`cda1bfa8 : 00000000`00000024 00000000`00000000 00000000`00000000 ffffe001`d122bb10 : ksthunk!CKernelFilterDevice::DispatchIrp+0xf9
07 fffff803`cda7b306 : 00000000`000001f0 ffffe001`d48ce690 ffffe001`d13d6400 ffffe001`d13d64c0 : nt!IopParseDevice+0x7c8
08 fffff803`cda12916 : 00000000`000001f0 ffffd001`c30988d0 ffffe001`d13d6490 fffff803`cda7b250 : nt!IopParseFile+0xb6
09 fffff803`cda1131c : ffffe001`d2ccb001 ffffd001`c30989e0 00ffffe0`00000040 ffffe001`cd127dc0 : nt!ObpLookupObjectName+0x776
0a fffff803`cd9fedb8 : ffffe001`00000001 ffffe001`d48ce690 00000000`00000000 00000000`00000000 : nt!ObOpenObjectByNameEx+0x1ec
0b fffff803`cd9fe919 : 000000ee`6d1fc8d8 000000ee`6d1fc788 000000ee`6d1fc7e0 000000ee`6d1fc7d0 : nt!IopCreateFile+0x3d8
0c fffff803`cd752fa3 : ffffc000`1f296870 fffff803`cd9d9fbd ffffd001`c3098be8 00000000`00000000 : nt!NtCreateFile+0x79
0d 00007fff`69805b74 : 00007fff`487484e6 0000029b`00000003 00000000`0000012e 00000000`00000000 : nt!KiSystemServiceCopyEnd+0x13
0e 00007fff`487484e6 : 0000029b`00000003 00000000`0000012e 00000000`00000000 00000000`00000000 : 0x00007fff`69805b74
0f 0000029b`00000003 : 00000000`0000012e 00000000`00000000 00000000`00000000 00000000`00000000 : 0x00007fff`487484e6
10 00000000`0000012e : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000080 : 0x0000029b`00000003
11 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000080 00000000`00000000 : 0x12e
Sie können DML verwenden, um den Code weiter zu untersuchen. Wenn Sie den ersten 00-Eintrag auswählen, wird der Befehl .frame (Set Local Context) verwendet, um den Kontext festzulegen, und anschließend werden mit dem Befehl dv (Display Local Variables) die lokalen Variablen angezeigt.
0: kd> .frame 0n0;dv /t /v
00 ffffd001`c30981d0 fffff800`7a0fa607 tabletaudiosample!CMiniportWaveRT::NewStream+0x1dc [c:\data1\threshold\audio\endpointscommon\minwavert.cpp @ 597]
ffffd001`c30982b0 class CMiniportWaveRT * this = 0xffffe001`d1182000
ffffd001`c30982b8 struct IMiniportWaveRTStream ** OutStream = 0xffffe001`d4776d20
ffffd001`c30982c0 struct IPortWaveRTStream * OuterUnknown = 0xffffe001`d4776bc8
ffffd001`c30982c8 unsigned long Pin = 0
ffffd001`c30982d0 unsigned char Capture = 0x00 '
ffffd001`c30982d8 union KSDATAFORMAT * DataFormat = 0xffffe001`cd7609b0
ffffd001`c3098270 struct _GUID signalProcessingMode = {4780004E-7133-41D8-8C74-660DADD2C0EE}
ffffd001`c3098210 long ntStatus = 0n0
ffffd001`c3098218 class CMiniportWaveRTStream * stream = 0x00000000`00000000
Abschnitt 10: Anzeigen von Prozessen und Threads
In Abschnitt 10 werden Sie Debugger-Befehle verwenden, um Prozesse und Threads anzuzeigen.
Prozess
Um den aktuellen Prozesskontext zu ändern, verwenden Sie den Befehl .process <Prozess>. Das folgende Beispiel zeigt, wie man einen Prozess identifiziert und den Kontext zu ihm wechselt.
Verwenden Sie den Befehl
!process
, um den aktuellen Prozess anzuzeigen, der an der Wiedergabe des Tons beteiligt ist.Für weitere Informationen siehe !process
Die Ausgabe zeigt, dass der Prozess mit audiodg.exe verbunden ist. Wenn Sie sich immer noch an dem im vorherigen Abschnitt dieses Themas beschriebenen Haltepunkt befinden, sollte der aktuelle Prozess mit dem audiodg.exe-Image verknüpft sein.
<– Auf dem Hostsystem
0: kd> !process
PROCESS ffffe001d147c840
SessionId: 0 Cid: 10f0 Peb: ee6cf8a000 ParentCid: 0434
DirBase: d2122000 ObjectTable: ffffc0001f191ac0 HandleCount: <Data Not Accessible>
Image: audiodg.exe
VadRoot ffffe001d4222f70 Vads 70 Clone 0 Private 504. Modified 16. Locked 0.
DeviceMap ffffc00019113080
Token ffffc0001f1d4060
ElapsedTime <Invalid>
UserTime 00:00:00.000
KernelTime 00:00:00.000
QuotaPoolUsage[PagedPool] 81632
QuotaPoolUsage[NonPagedPool] 9704
Working Set Sizes (now,min,max) (2154, 1814, 2109) (8616KB, 7256KB, 8436KB)
PeakWorkingSetSize 2101
VirtualSize 2097192 Mb
PeakVirtualSize 2097192 Mb
PageFaultCount 2336
MemoryPriority BACKGROUND
BasePriority 8
CommitCharge 1573
THREAD ffffe001d173e840 Cid 10f0.1dac Teb: 000000ee6cf8b000 Win32Thread: ffffe001d1118cf0 WAIT: (UserRequest) UserMode Non-Alertable
ffffe001d16c4dd0 NotificationEvent
ffffe001d08b0840 ProcessObject
THREAD ffffe001ceb77080 Cid 10f0.16dc Teb: 000000ee6cf8d000 Win32Thread: 0000000000000000 WAIT: (WrQueue) UserMode Alertable
ffffe001cf2d1840 QueueObject
THREAD ffffe001d112c840 Cid 10f0.0a4c Teb: 000000ee6cf8f000 Win32Thread: 0000000000000000 WAIT: (WrQueue) UserMode Alertable
ffffe001cf2d1840 QueueObject
THREAD ffffe001d16c7840 Cid 10f0.13c4 Teb: 000000ee6cf91000 Win32Thread: 0000000000000000 WAIT: (WrQueue) UserMode Alertable
ffffe001cf2d1840 QueueObject
THREAD ffffe001cec67840 Cid 10f0.0dbc Teb: 000000ee6cf93000 Win32Thread: 0000000000000000 WAIT: (WrQueue) UserMode Alertable
ffffe001d173e5c0 QueueObject
THREAD ffffe001d1117840 Cid 10f0.1d6c Teb: 000000ee6cf95000 Win32Thread: 0000000000000000 WAIT: (WrQueue) UserMode Alertable
ffffe001d173e5c0 QueueObject
THREAD ffffe001cdeae840 Cid 10f0.0298 Teb: 000000ee6cf97000 Win32Thread: 0000000000000000 RUNNING on processor 2
Beachten Sie, dass sich einer der mit diesem Prozess verbundenen Threads im Zustand RUNNING befindet. Dieser Thread unterstützte das Abspielen des Medienclips, als der Haltepunkt erreicht wurde.
Verwenden Sie den Befehl !process 0 0, um zusammenfassende Informationen für alle Prozesse anzuzeigen. Verwenden Sie in der Befehlsausgabe die Tastenkombination STRG+F, um die Prozess-ID für den mit dem audiodg.exe-Image verbundenen Prozess zu finden. In dem unten gezeigten Beispiel lautet die Prozess-ID ffffe001d147c840.
Notieren Sie die Prozess-ID, die audiodg.exe auf Ihrem PC zugeordnet ist, um sie später in diesem Lab zu verwenden. ________________________
...
PROCESS ffffe001d147c840
SessionId: 0 Cid: 10f0 Peb: ee6cf8a000 ParentCid: 0434
DirBase: d2122000 ObjectTable: ffffc0001f191ac0 HandleCount: <Data Not Accessible>
Image: audiodg.exe
...
Geben Sie g in den Debugger ein, um den Code vorwärts laufen zu lassen, bis die Wiedergabe des Medienclips beendet ist. Wechseln Sie dann in den Debugger, indem Sie Strg+ScrLk (Strg+Break) drücken. Verwenden Sie den Befehl !process, um zu bestätigen, dass Sie jetzt einen anderen Prozess ausführen.
!process
PROCESS ffffe001cd0ad040
SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000
DirBase: 001aa000 ObjectTable: ffffc00017214000 HandleCount: <Data Not Accessible>
Image: System
VadRoot ffffe001d402b820 Vads 438 Clone 0 Private 13417. Modified 87866. Locked 64.
DeviceMap ffffc0001721a070
Token ffffc00017216a60
ElapsedTime 05:04:54.716
UserTime 00:00:00.000
KernelTime 00:00:20.531
QuotaPoolUsage[PagedPool] 0
QuotaPoolUsage[NonPagedPool] 0
Working Set Sizes (now,min,max) (1720, 50, 450) (6880KB, 200KB, 1800KB)
PeakWorkingSetSize 15853
VirtualSize 58 Mb
PeakVirtualSize 74 Mb
PageFaultCount 46128
MemoryPriority BACKGROUND
BasePriority 8
CommitCharge 66
THREAD ffffe001cd0295c0 Cid 0004.000c Teb: 0000000000000000 Win32Thread: 0000000000000000 WAIT: (Executive) KernelMode Non-Alertable
fffff803cd8e0120 SynchronizationEvent
THREAD ffffe001cd02a6c0 Cid 0004.0010 Teb: 0000000000000000 Win32Thread: 0000000000000000 WAIT: (Executive) KernelMode Non-Alertable
fffff803cd8e0ba0 Semaphore Limit 0x7fffffff
...
Die obige Ausgabe zeigt, dass ein anderer Systemprozess von ffffe001cd0ad040 läuft. Der Imagename lautet System, nicht audiodg.exe.
Verwenden Sie nun den Befehl !process, um zu dem Prozess zu wechseln, der mit audiodg.exe verbunden war. In diesem Beispiel lautet die Prozess-ID ffffe001d147c840. Ersetzen Sie die Prozess-ID im Beispiel durch Ihre Prozess-ID, die Sie zuvor aufgezeichnet haben.
0: kd> !process ffffe001d147c840
PROCESS ffffe001d147c840
SessionId: 0 Cid: 10f0 Peb: ee6cf8a000 ParentCid: 0434
DirBase: d2122000 ObjectTable: ffffc0001f191ac0 HandleCount: <Data Not Accessible>
Image: audiodg.exe
VadRoot ffffe001d4222f70 Vads 60 Clone 0 Private 299. Modified 152. Locked 0.
DeviceMap ffffc00019113080
Token ffffc0001f1d4060
ElapsedTime 1 Day 01:53:14.490
UserTime 00:00:00.031
KernelTime 00:00:00.031
QuotaPoolUsage[PagedPool] 81552
QuotaPoolUsage[NonPagedPool] 8344
Working Set Sizes (now,min,max) (1915, 1814, 2109) (7660KB, 7256KB, 8436KB)
PeakWorkingSetSize 2116
VirtualSize 2097189 Mb
PeakVirtualSize 2097192 Mb
PageFaultCount 2464
MemoryPriority BACKGROUND
BasePriority 8
CommitCharge 1418
THREAD ffffe001d173e840 Cid 10f0.1dac Teb: 000000ee6cf8b000 Win32Thread: ffffe001d1118cf0 WAIT: (UserRequest) UserMode Non-Alertable
ffffe001d16c4dd0 NotificationEvent
ffffe001d08b0840 ProcessObject
Not impersonating
DeviceMap ffffc00019113080
Owning Process ffffe001d147c840 Image: audiodg.exe
Attached Process N/A Image: N/A
Wait Start TickCount 338852 Ticks: 197682 (0:00:51:28.781)
Context Switch Count 36 IdealProcessor: 0
UserTime 00:00:00.015
KernelTime 00:00:00.000
Win32 Start Address 0x00007ff7fb928de0
Stack Init ffffd001c2ec6dd0 Current ffffd001c2ec60c0
Base ffffd001c2ec7000 Limit ffffd001c2ec1000 Call 0
Priority 8 BasePriority 8 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5
Kernel stack not resident.
THREAD ffffe001d115c080 Cid 10f0.15b4 Teb: 000000ee6cf9b000 Win32Thread: 0000000000000000 WAIT: (WrQueue) UserMode Alertable
ffffe001d0bf0640 QueueObject
Not impersonating
DeviceMap ffffc00019113080
Owning Process ffffe001d147c840 Image: audiodg.exe
Attached Process N/A Image: N/A
Wait Start TickCount 338852 Ticks: 197682 (0:00:51:28.781)
Context Switch Count 1 IdealProcessor: 0
UserTime 00:00:00.000
KernelTime 00:00:00.000
Win32 Start Address 0x00007fff6978b350
Stack Init ffffd001c3143dd0 Current ffffd001c3143520
Base ffffd001c3144000 Limit ffffd001c313e000 Call 0
Priority 8 BasePriority 8 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5
Kernel stack not resident.
THREAD ffffe001d3a27040 Cid 10f0.17f4 Teb: 000000ee6cf9d000 Win32Thread: 0000000000000000 WAIT: (WrQueue) UserMode Alertable
ffffe001d173e5c0 QueueObject
Not impersonating
DeviceMap ffffc00019113080
Owning Process ffffe001d147c840 Image: audiodg.exe
Attached Process N/A Image: N/A
Wait Start TickCount 518918 Ticks: 17616 (0:00:04:35.250)
Context Switch Count 9 IdealProcessor: 1
UserTime 00:00:00.000
KernelTime 00:00:00.000
Win32 Start Address 0x00007fff6978b350
Stack Init ffffd001c70c6dd0 Current ffffd001c70c6520
Base ffffd001c70c7000 Limit ffffd001c70c1000 Call 0
Priority 9 BasePriority 8 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5
Kernel stack not resident.
Da dieser Code nicht aktiv ist, befinden sich alle Threads wie erwartet im Zustand WAIT.
Threads
Die Befehle zum Anzeigen und Setzen von Threads sind denen von Prozessen sehr ähnlich. Verwenden Sie den Befehl !thread, um Threads anzuzeigen. Verwenden Sie .thread, um die aktuellen Threads festzulegen.
Um die mit dem Medienplayer verbundenen Threads zu erkunden, spielen Sie den Medienclip erneut ab. Wenn der im vorigen Abschnitt beschriebene Haltepunkt noch vorhanden ist, werden Sie im Kontext von audiodg.exe angehalten.
Verwenden Sie !thread -1 0, um kurze Informationen über den aktuellen Thread anzuzeigen. Dies zeigt die Thread-Adresse, die Thread- und Prozess-IDs, die Adresse des Thread-Umgebungsblocks (TEB), die Adresse der Win32-Funktion (falls vorhanden), für die der Thread erstellt wurde, und den Planungsstatus des Threads.
0: kd> !thread -1 0
THREAD ffffe001d3a27040 Cid 10f0.17f4 Teb: 000000ee6cf9d000 Win32Thread: 0000000000000000 RUNNING on processor 0
Um weitere Informationen über den laufenden Thread anzuzeigen, geben Sie !thread ein. Es sollten ähnliche Informationen wie die folgenden angezeigt werden.
0: kd> !thread
THREAD ffffe001d3a27040 Cid 10f0.17f4 Teb: 000000ee6cf9d000 Win32Thread: 0000000000000000 RUNNING on processor 0
IRP List:
ffffe001d429e580: (0006,02c8) Flags: 000008b4 Mdl: 00000000
Not impersonating
DeviceMap ffffc00019113080
Owning Process ffffe001d147c840 Image: audiodg.exe
Attached Process N/A Image: N/A
Wait Start TickCount 537630 Ticks: 0
Context Switch Count 63 IdealProcessor: 1
UserTime 00:00:00.000
KernelTime 00:00:00.015
Win32 Start Address 0x00007fff6978b350
Stack Init ffffd001c70c6dd0 Current ffffd001c70c6520
Base ffffd001c70c7000 Limit ffffd001c70c1000 Call 0
Priority 8 BasePriority 8 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5
Child-SP RetAddr : Args to Child : Call Site
ffffd001`c70c62a8 fffff800`7a0fa607 : ffffe001`d4aec5c0 ffffe001`cdefd3d8 ffffe001`d4aec5c0 ffffe001`cdefd390 : tabletaudiosample!CMiniportWaveRT::NewStream [c:\data1\threshold\audio\endpointscommon\minwavert.cpp @ 562]
ffffd001`c70c62b0 fffff800`7a0fb2c3 : 00000000`00000000 ffffe001`d429e580 ffffe001`d4ea47b0 ffffe001`cdefd3d8 : portcls!CPortPinWaveRT::Init+0x2e7
ffffd001`c70c6340 fffff800`7a0fc7f9 : ffffe001`d4aec430 00000000`00000000 ffffe001`d10b8380 ffffe001`d429e580 : portcls!CPortFilterWaveRT::NewIrpTarget+0x193
ffffd001`c70c63c0 fffff800`7a180552 : 00000000`00000000 ffffe001`d10b8380 ffffe001`d429e580 ffffe001`d4565600 : portcls!xDispatchCreate+0xd9
ffffd001`c70c6450 fffff800`7a109a9a : ffffe001`d10b84d0 ffffe001`d10b8380 00000000`00000000 ffffe001`00000000 : ks!KsDispatchIrp+0x272
ffffd001`c70c6510 fffff800`7bd314b1 : ffffe001`d429e580 ffffd001`c70c6590 ffffe001`d429e800 ffffe001`ce80da70 : portcls!DispatchCreate+0x7a
ffffd001`c70c6540 fffff803`cda1bfa8 : 00000000`00000025 00000000`00000000 00000000`00000000 ffffe001`d429e580 : ksthunk!CKernelFilterDevice::DispatchIrp+0xf9
ffffd001`c70c65a0 fffff803`cda7b306 : 00000000`000002fc ffffe001`d5e0d510 00000000`00000000 ffffe001`d3341bd0 : nt!IopParseDevice+0x7c8
ffffd001`c70c6770 fffff803`cda12916 : 00000000`000002fc ffffd001`c70c68d0 ffffe001`d3341ba0 fffff803`cda7b250 : nt!IopParseFile+0xb6
ffffd001`c70c67d0 fffff803`cda1131c : ffffe001`ceb6c601 ffffd001`c70c69e0 00000000`00000040 ffffe001`cd127dc0 : nt!ObpLookupObjectName+0x776
ffffd001`c70c6970 fffff803`cd9fedb8 : ffff8ab8`00000001 ffffe001`d5e0d510 00000000`00000000 00000000`00000000 : nt!ObOpenObjectByNameEx+0x1ec
ffffd001`c70c6a90 fffff803`cd9fe919 : 000000ee`6d37c6e8 00000004`6d37c500 000000ee`6d37c5f0 000000ee`6d37c5e0 : nt!IopCreateFile+0x3d8
ffffd001`c70c6b40 fffff803`cd752fa3 : fffff6fb`7da05360 fffff6fb`40a6c0a8 fffff681`4d815760 ffff8ab8`92895e23 : nt!NtCreateFile+0x79
ffffd001`c70c6bd0 00007fff`69805b74 : 00007fff`487484e6 0000029b`00000003 00000000`0000012e 00000000`00000000 : nt!KiSystemServiceCopyEnd+0x13 (TrapFrame @ ffffd001`c70c6c40)
000000ee`6d37c568 00007fff`487484e6 : 0000029b`00000003 00000000`0000012e 00000000`00000000 00000000`00000000 : 0x00007fff`69805b74
000000ee`6d37c570 0000029b`00000003 : 00000000`0000012e 00000000`00000000 00000000`00000000 00000000`00000000 : 0x00007fff`487484e6
000000ee`6d37c578 00000000`0000012e : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000080 : 0x0000029b`00000003
000000ee`6d37c580 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000080 00000000`00000000 : 0x12e
Verwenden Sie den Befehl k, um den mit dem Thread verbundenen Aufrufstapel anzuzeigen.
0: kd> k
# Child-SP RetAddr Call Site
00 ffffd001`c70c62a8 fffff800`7a0fa607 tabletaudiosample!CMiniportWaveRT::NewStream [c:\data1\threshold\audio\endpointscommon\minwavert.cpp @ 562]
01 ffffd001`c70c62b0 fffff800`7a0fb2c3 portcls!CPortPinWaveRT::Init+0x2e7
02 ffffd001`c70c6340 fffff800`7a0fc7f9 portcls!CPortFilterWaveRT::NewIrpTarget+0x193
03 ffffd001`c70c63c0 fffff800`7a180552 portcls!xDispatchCreate+0xd9
04 ffffd001`c70c6450 fffff800`7a109a9a ks!KsDispatchIrp+0x272
05 ffffd001`c70c6510 fffff800`7bd314b1 portcls!DispatchCreate+0x7a
06 ffffd001`c70c6540 fffff803`cda1bfa8 ksthunk!CKernelFilterDevice::DispatchIrp+0xf9
07 ffffd001`c70c65a0 fffff803`cda7b306 nt!IopParseDevice+0x7c8
08 ffffd001`c70c6770 fffff803`cda12916 nt!IopParseFile+0xb6
09 ffffd001`c70c67d0 fffff803`cda1131c nt!ObpLookupObjectName+0x776
0a ffffd001`c70c6970 fffff803`cd9fedb8 nt!ObOpenObjectByNameEx+0x1ec
0b ffffd001`c70c6a90 fffff803`cd9fe919 nt!IopCreateFile+0x3d8
0c ffffd001`c70c6b40 fffff803`cd752fa3 nt!NtCreateFile+0x79
0d ffffd001`c70c6bd0 00007fff`69805b74 nt!KiSystemServiceCopyEnd+0x13
0e 000000ee`6d37c568 00007fff`487484e6 0x00007fff`69805b74
0f 000000ee`6d37c570 0000029b`00000003 0x00007fff`487484e6
10 000000ee`6d37c578 00000000`0000012e 0x0000029b`00000003
11 000000ee`6d37c580 00000000`00000000 0x12e
Geben Sie g in den Debugger ein, um den Code vorwärts laufen zu lassen, bis die Wiedergabe des Medienclips beendet ist. Wechseln Sie dann in den Debugger, indem Sie Strg+Rollen-Taste (Strg-Break) drücken. Verwenden Sie den Befehl !thread, um zu bestätigen, dass Sie jetzt einen anderen Thread ausführen.
0: kd> !thread
THREAD ffffe001ce80b840 Cid 17e4.01ec Teb: 00000071fa9b9000 Win32Thread: ffffe001d41690d0 RUNNING on processor 0
Not impersonating
DeviceMap ffffc0001974e2c0
Owning Process ffffe001d1760840 Image: rundll32.exe
Attached Process N/A Image: N/A
Wait Start TickCount 538040 Ticks: 0
Context Switch Count 3181840 IdealProcessor: 0
UserTime 00:00:08.250
KernelTime 00:00:10.796
Win32 Start Address 0x00007ff6d2f24270
Stack Init ffffd001cd16afd0 Current ffffd001cd16a730
Base ffffd001cd16b000 Limit ffffd001cd165000 Call 0
Priority 8 BasePriority 8 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5
Child-SP RetAddr : Args to Child : Call Site
fffff803`cf373d18 fffff800`7a202852 : fffff803`cf373e60 00000000`00000001 ffffe001`cf4ed330 00000000`0000ffff : nt!DbgBreakPointWithStatus
fffff803`cf373d20 fffff803`cd6742c6 : ffffe001`cf4ed2f0 fffff803`cf373e60 00000000`00000001 00000000`0004e4b8 : kdnic!TXSendCompleteDpc+0x142
fffff803`cf373d60 fffff803`cd74d495 : 00000000`00000000 fffff803`cd923180 fffff803`cde1f4b0 fffff901`40669010 : nt!KiRetireDpcList+0x5f6
fffff803`cf373fb0 fffff803`cd74d2a0 : 00000000`00000090 0000000e`0000006a 00000000`00000092 00000000`00000000 : nt!KxRetireDpcList+0x5 (TrapFrame @ fffff803`cf373e70)
ffffd001`cd16a6c0 fffff803`cd74bd75 : 00000000`00000000 fffff803`cd74a031 00000000`00000000 00000000`00000000 : nt!KiDispatchInterruptContinue
ffffd001`cd16a6f0 fffff803`cd74a031 : 00000000`00000000 00000000`00000000 ffffe001`cff4d2a0 fffff803`cd67738e : nt!KiDpcInterruptBypass+0x25
ffffd001`cd16a700 fffff960`50cdb5a4 : fffff901`400006d0 00000000`00000001 fffff901`40000d60 ffffd001`cd16a9f0 : nt!KiInterruptDispatchNoLockNoEtw+0xb1 (TrapFrame @ ffffd001`cd16a700)
ffffd001`cd16a890 fffff960`50c66b2f : 00000000`00000000 fffff901`40669010 fffff901`42358580 fffff901`40000d60 : win32kfull!Win32FreePoolImpl+0x34
ffffd001`cd16a8c0 fffff960`50c68cd6 : 00000000`00000000 ffffd001`cd16a9f0 fffff901`400006d0 fffff901`400c0460 : win32kfull!EXLATEOBJ::vAltUnlock+0x1f
ffffd001`cd16a8f0 fffff803`cd752fa3 : 00000000`00000000 00000000`00000000 ffffe001`ce80b840 00000000`00000000 : win32kfull!NtGdiAlphaBlend+0x1d16
ffffd001`cd16add0 00007fff`674c1494 : 00007fff`674b1e97 0000a7c6`daee0559 00000000`00000001 0000020b`741f3c50 : nt!KiSystemServiceCopyEnd+0x13 (TrapFrame @ ffffd001`cd16ae40)
00000071`fa74c9a8 00007fff`674b1e97 : 0000a7c6`daee0559 00000000`00000001 0000020b`741f3c50 00000000`00ffffff : 0x00007fff`674c1494
00000071`fa74c9b0 0000a7c6`daee0559 : 00000000`00000001 0000020b`741f3c50 00000000`00ffffff 00000000`00000030 : 0x00007fff`674b1e97
00000071`fa74c9b8 00000000`00000001 : 0000020b`741f3c50 00000000`00ffffff 00000000`00000030 00000000`01010bff : 0x0000a7c6`daee0559
00000071`fa74c9c0 0000020b`741f3c50 : 00000000`00ffffff 00000000`00000030 00000000`01010bff 00000000`00000000 : 0x1
00000071`fa74c9c8 00000000`00ffffff : 00000000`00000030 00000000`01010bff 00000000`00000000 00000000`000000c0 : 0x0000020b`741f3c50
00000071`fa74c9d0 00000000`00000030 : 00000000`01010bff 00000000`00000000 00000000`000000c0 00000000`00000030 : 0xffffff
00000071`fa74c9d8 00000000`01010bff : 00000000`00000000 00000000`000000c0 00000000`00000030 00000071`00000030 : 0x30
00000071`fa74c9e0 00000000`00000000 : 00000000`000000c0 00000000`00000030 00000071`00000030 00000071`01ff8000 : 0x1010bff
Der Name des Images lautet rundll32.exe, was in der Tat nicht der Name des Images ist, das mit der Wiedergabe des Medienclips verbunden ist.
Hinweis Um den aktuellen Thread einzustellen, geben Sie .thread <thread number> ein.
Weitere Informationen über Threads und Prozesse finden Sie in den folgenden Verweisen:
Abschnitt 11: IRQL, Register und Disassemblierung
Ansicht des gespeicherten IRQL
In Abschnitt 11 werden Sie den IRQL und den Inhalt der Regsister anzeigen.
<– Auf dem Hostsystem
Die Unterbrechungsanforderungsebene (IRQL) wird verwendet, um die Priorität der Unterbrechungsabarbeitung zu verwalten. Jeder Prozessor hat eine IRQL-Einstellung, die Threads erhöhen oder senken können. Interrupts, die bei oder unterhalb der IRQL-Einstellung des Prozessors auftreten, werden maskiert und stören den laufenden Betrieb nicht. Interrupts, die oberhalb der IRQL-Einstellung des Prozessors auftreten, haben Vorrang vor der aktuellen Operation. Die Erweiterung !irql zeigt die Unterbrechungsanforderungsebene (IRQL) auf dem aktuellen Prozessor des Zielcomputers an, bevor die Unterbrechung durch den Debugger erfolgte. Wenn der Zielcomputer in den Debugger wechselt, ändert sich der IRQL, aber der IRQL, der kurz vor dem Debugger-Break wirksam war, wird gespeichert und von !irql angezeigt.
0: kd> !irql
Debugger saved IRQL for processor 0x0 -- 2 (DISPATCH_LEVEL)
<Ansicht der Register und Demontage
Ansicht der Register
Zeigen Sie den Inhalt der Register für den aktuellen Thread auf dem aktuellen Prozessor an, indem Sie den Befehl r (Registers) verwenden.
0: kd> r
rax=000000000000c301 rbx=ffffe00173eed880 rcx=0000000000000001
rdx=000000d800000000 rsi=ffffe00173eed8e0 rdi=ffffe00173eed8f0
rip=fffff803bb757020 rsp=ffffd001f01f8988 rbp=ffffe00173f0b620
r8=000000000000003e r9=ffffe00167a4a000 r10=000000000000001e
r11=ffffd001f01f88f8 r12=0000000000000000 r13=ffffd001f01efdc0
r14=0000000000000001 r15=0000000000000000
iopl=0 nv up ei pl nz na pe nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00000202
nt!DbgBreakPointWithStatus:
fffff803`bb757020 cc int 3
Alternativ können Sie den Inhalt der Register anzeigen, indem Sie View>Registers wählen.
Die Anzeige der Registerinhalte kann bei der schrittweisen Ausführung von Assemblercode und in anderen Szenarien hilfreich sein. Für weitere Informationen siehe r (Register).
Informationen zum Inhalt des Registers finden Sie unter x86 Architektur und x64 Architektur.
Disassemblierung
Sie können den Code, der gerade ausgeführt wird, disassemblieren, um den laufenden Assemblercode anzuzeigen, indem Sie View>Disassembly wählen.
Weitere Informationen zur Assembler-Disassemblierung finden Sie unter Annotated x86 Disassembly und Annotated x64 Disassembly.
Abschnitt 12: Arbeiten mit Speicher
In Abschnitt 12 werden Sie Debugger-Befehle verwenden, um den Inhalt des Speichers anzuzeigen.
Ansicht Speicher
Möglicherweise müssen Sie den Speicher untersuchen, um ein Problem zu identifizieren oder um Variablen, Zeiger usw. zu überprüfen. Sie können den Speicher anzeigen, indem Sie einen der folgenden Befehle eingeben: d* <address>.
db |
Zeigt Daten in Byte-Werten und ASCII-Zeichen an. |
dd |
Zeigt Daten als doppelt breite Wörter (4 Byte) an. |
du |
Zeigt Daten als Unicode-Zeichen an. |
dw |
Zeigt Daten als Wortwerte (2 Byte) und ASCII-Zeichen an. |
Hinweis Wenn Sie versuchen, eine ungültige Adresse anzuzeigen, wird ihr Inhalt als Fragezeichen (?) dargestellt.
Alternativ können Sie den Speicher auch anzeigen, indem Sie Ansicht>Speicher wählen. Verwenden Sie das Pull-Down-Menü Anzeigeformat, um die Art der Anzeige des Speichers zu ändern.
Um Daten im Zusammenhang mit der Lautstärkeregelung anzuzeigen, setzen Sie mit dem Befehl bm einen Haltepunkt, der in der Routine PropertyHandlerAudioEngineVolumeLevel ausgelöst wird. Bevor wir den neuen Haltepunkt setzen, löschen wir alle vorherigen Haltepunkte mit bc *.
kd> bc *
Setzen Sie mit dem Befehl bm einen Haltepunkt, der in der Routine PropertyHandlerAudioEngineVolumeLevel ausgelöst wird.
kd> bm tabletaudiosample!CMiniportWaveRT::SetDeviceChannelVolume 1: fffff80f`02c3a4b0 @!"tabletaudiosample!CMiniportWaveRT::SetDeviceChannelVolume"
Listen Sie die Haltepunkte auf, um zu bestätigen, dass der Haltepunkt richtig gesetzt ist.
kd> bl 1: fffff80f`02c3a4b0 @!"tabletaudiosample!CMiniportWaveRT::SetDeviceChannelVolume"
Verwenden Sie den Befehl g, um die Codeausführung erneut zu starten.
Stellen Sie auf dem Zielsystem die Lautstärke in der Systemablage ein. Dadurch wird der Haltepunkt ausgelöst.
Breakpoint 1 hit tabletaudiosample!CMiniportWaveRT::SetDeviceChannelVolume: fffff80f`02c3a4b0 44894c2420 mov dword ptr [rsp+20h],r9d
Verwenden Sie den Menüpunkt Ansicht>Lokale, um lokale Variablen anzuzeigen. Beachten Sie den aktuellen Wert der Variable IVolume.
Sie können den Datentyp und den aktuellen Wert für die Variable IVolume im Beispielcode anzeigen, indem Sie den Befehl dt und den Namen der Variablen eingeben.
kd> dt lVolume Local var @ 0xa011ea50 Type long 0n-6291456
Der Haltepunkt wird bei der Eingabe von SetDeviceChannelVolume erreicht.
STDMETHODIMP_(NTSTATUS) CMiniportWaveRT::SetDeviceChannelVolume(_In_ ULONG _ulNodeId, _In_ UINT32 _uiChannel, _In_ LONG _Volume) { NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; PAGED_CODE (); DPF_ENTER(("[CMiniportWaveRT::SetEndpointChannelVolume]")); IF_TRUE_ACTION_JUMP(_ulNodeId != KSNODE_WAVE_AUDIO_ENGINE, ntStatus = STATUS_INVALID_DEVICE_REQUEST, Exit); // Snap the volume level to our range of steppings. LONG lVolume = VOLUME_NORMALIZE_IN_RANGE(_Volume); ntStatus = SetChannelVolume(_uiChannel, lVolume); Exit: return ntStatus; }
Versuchen Sie, den Wert an der Speicherstelle von IVolume mit dem Befehl dt (Display Type) anzuzeigen.
kd> dt dt lVolume Local var @ 0xffffb780b7eee664 Type long 0n0
Da die Variable noch nicht definiert ist, enthält sie keine Informationen.
Drücken Sie F10, um zur letzten Codezeile in SetDeviceChannelVolume zu gelangen.
return ntStatus;
Zeigen Sie den Wert an der Speicherstelle von IVolume mit dem Befehl dt (Display Type) an.
kd> dt lVolume Local var @ 0xffffb780b7eee664 Type long 0n-6291456
Da die Variable nun aktiv ist, wird in diesem Beispiel ein Wert von 6291456 angezeigt.
Sie können den Speicherort von IVolume auch mit der Taste ? (Ausdruck auswerten) Befehl.
kd> ? lVolume Evaluate expression: -79711507126684 = ffffb780`b7eee664
Die angezeigte Adresse ffffb780`b7eee664 ist die Adresse der Variablen lVolume. Verwenden Sie den Befehl dd, um den Inhalt des Speichers an dieser Stelle anzuzeigen.
kd> dd ffffb780`b7eee664 ffffb780`b7eee664 ffa00000 00000018 00000000 c52d7008 ffffb780`b7eee674 ffffc98e e0495756 fffff80e c52d7008 ffffb780`b7eee684 ffffc98e 00000000 fffff80e 00000000 ffffb780`b7eee694 ffffc98e ffa00000 ffffb780 b7eee710 ffffb780`b7eee6a4 ffffb780 00000000 00000000 c7477260 ffffb780`b7eee6b4 ffffc98e b7eee7a0 ffffb780 b7eee6f0 ffffb780`b7eee6c4 ffffb780 e04959ca fffff80e 00000000 ffffb780`b7eee6d4 00000000 00000028 00000000 00000002
Sie können die ersten vier Bytes einer Adresse anzeigen, indem Sie den Bereichsparameter L4 angeben.
kd> dd ffffb780`b7eee664 l4 ffffb780`b7eee664 ffa00000 00000018 00000000 c52d7008
Um die verschiedenen Arten der Speicherausgabe anzuzeigen, geben Sie die Befehle du, da und db ein.
kd> du ffffb780`b7eee664 ffffb780`b7eee664 "" kd> a ffffb780`b7eee664 ffffb780`b7eee664 "" kd> db 0xffffae015ff97664 ffffae01`5ff97664 00 80 bc ff 18 00 00 00-00 00 00 00 08 50 e0 51 .............P.Q ffffae01`5ff97674 00 c0 ff ff 56 57 da 56-0e f8 ff ff 08 50 e0 51 ....VW.V.....P.Q ffffae01`5ff97684 00 c0 ff ff 00 00 00 00-0e f8 ff ff 00 00 00 00 ................ ffffae01`5ff97694 00 c0 ff ff aa 80 bc ff-01 ae ff ff 10 77 f9 5f .............w._ ffffae01`5ff976a4 01 ae ff ff 40 00 00 00-00 e6 ff ff 10 dc 30 55 ....@.........0U ffffae01`5ff976b4 00 c0 ff ff a0 77 f9 5f-01 ae ff ff f0 76 f9 5f .....w._.....v._ ffffae01`5ff976c4 01 ae ff ff ca 59 da 56-0e f8 ff ff 00 00 00 00 .....Y.V........ ffffae01`5ff976d4 00 00 00 00 28 00 00 00-00 00 00 00 02 00 00 00 ....(...........
Verwenden Sie die Option df float, um Daten als Gleitkommazahlen mit einfacher Genauigkeit (4 Byte) anzuzeigen.
df ffffb780`b7eee664 ffffb780`b7eee664 -1.#QNAN 3.3631163e-044 0 -2775.002 ffffb780`b7eee674 -1.#QNAN -5.8032637e+019 -1.#QNAN -2775.002 ffffb780`b7eee684 -1.#QNAN 0 -1.#QNAN 0 ffffb780`b7eee694 -1.#QNAN -1.#QNAN -1.#QNAN -2.8479408e-005
In den Speicher schreiben
Ähnlich wie bei den Befehlen zum Lesen des Speichers können Sie mit den e*-Befehlen den Speicherinhalt ändern.
Befehl | Beschreibung |
---|---|
Stck |
ASCII-String (nicht NULL-terminiert) |
eu |
Unicode-String (nicht NULL-terminiert) |
ew |
Wortwerte (2 Bytes) |
eza |
NULL-terminierte ASCII-Zeichenkette |
ezu |
NULL-terminierte Unicode-Zeichenkette |
eb |
Byte-Werte |
ed |
Doppelwortwerte (4 Bytes) |
Das folgende Beispiel zeigt, wie Sie den Speicher überschreiben können.
Suchen Sie zunächst die Adresse von lVolume, die im Beispielcode verwendet wird.
kd> ? lVolume Evaluate expression: -79711507126684 = ffffb780`b7eee664
Überschreiben Sie diese Speicheradresse mit neuen Zeichen, indem Sie den Befehl eb verwenden.
kd> eb 0xffffb780`b7eee664 11 11 11 11 11
Zeigen Sie den Speicherplatz an, um zu bestätigen, dass die Zeichen überschrieben wurden, indem Sie den Befehl db eingeben.
kd> db 0xffffb780`b7eee664 ffffb780`b7eee664 11 11 11 11 11 00 00 00-00 00 00 00 08 70 2d c5 .............p-. ffffb780`b7eee674 8e c9 ff ff 56 57 49 e0-0e f8 ff ff 08 70 2d c5 ....VWI......p-. ffffb780`b7eee684 8e c9 ff ff 00 00 00 00-0e f8 ff ff 00 00 00 00 ................ ffffb780`b7eee694 8e c9 ff ff 00 00 a0 ff-80 b7 ff ff 10 e7 ee b7 ................ ffffb780`b7eee6a4 80 b7 ff ff 00 00 00 00-00 00 00 00 60 72 47 c7 ............`rG. ffffb780`b7eee6b4 8e c9 ff ff a0 e7 ee b7-80 b7 ff ff f0 e6 ee b7 ................ ffffb780`b7eee6c4 80 b7 ff ff ca 59 49 e0-0e f8 ff ff 00 00 00 00 .....YI......... ffffb780`b7eee6d4 00 00 00 00 28 00 00 00-00 00 00 00 02 00 00 00 ....(...........
Alternativ können Sie den Inhalt des Speichers auch in einem Watch- oder Locals-Fenster ändern. Im Überwachungsfenster werden möglicherweise Variablen angezeigt, die nicht in den Kontext des aktuellen Frames passen. Sie zu ändern ist nicht sinnvoll, wenn sie nicht im Kontext stehen.
Abschnitt 13: Beenden der WinDbg-Sitzung
<-Auf dem Hostsystem
Wenn Sie den Debugger angeschlossen lassen, aber am Ziel arbeiten wollen, löschen Sie alle Haltepunkte mit bc *
, damit der Zielcomputer nicht versucht, eine Verbindung zum Debugger des Host-Computers herzustellen. Verwenden Sie dann den Befehl g
, um den Zielcomputer wieder zum Laufen zu bringen.
Um die Debugging-Sitzung zu beenden, rufen Sie auf dem Hostsystem den Debugger auf und geben den Befehl qd
(Quit and Detach) ein oder wählen Sie Stop Debugging aus dem Menü.
0: kd> qd
Weitere Informationen finden Sie unter Beenden einer Debugging-Sitzung in WinDbg (Classic) in der Debugging-Referenzdokumentation.
Abschnitt 14: Ressourcen zum Debuggen unter Windows
Weitere Informationen finden Sie unter Windows Debugging. Beachten Sie, dass einige dieser Bücher in ihren Beispielen ältere Windows-Versionen wie Windows Vista verwenden, aber die besprochenen Konzepte sind auf die meisten Windows-Versionen anwendbar.
Bücher
Erweitertes Windows Debugging von Mario Hewardt und Daniel Pravat
Debugging unter Windows: Ein praktischer Leitfaden zu Debugging- und Tracing-Strategien in Windows® von Tarik Soulami
Windows Internals von Pavel Yosifovich, Alex Ionescu, Mark Russinovich und David Solomon
Video
Die Defrag Tools Show WinDbg Episoden 13-29: </shows/defrag-tools/>
Anbieter von Schulungen:
OSR - https://www.osr.com/