Freigeben über


Stapelbasierte Fehlerinjektion

Hinweis Die Anweisungen zum Aktivieren dieses Features gelten nur für den WDK für Windows 8. Für Windows 8.1 wurde dieses Feature in driver verifier integriert. Verwenden Sie auf Computern, auf denen Windows 8.1 ausgeführt werden, die Option Systematische Simulation mit niedrigen Ressourcen.

Die Option Stapelbasierte Fehlerinjektion fügt Ressourcenfehler in Kernelmodustreiber ein. Diese Option verwendet einen speziellen Treiber, KmAutoFail.sys in Verbindung mit Driver Verifier , um Treiberfehlerbehandlungspfade zu durchdringen. Das Testen dieser Pfade war in der Vergangenheit sehr schwierig. Die Option Stapelbasierte Fehlerinjektion fügt Ressourcenfehler auf vorhersagbare Weise ein, sodass die gefundenen Probleme reproduzierbar sind. Da die Fehlerpfade einfach zu reproduzieren sind, ist es auch einfach, Korrekturen für diese Probleme zu überprüfen.

Um die Grundursache des Fehlers zu ermitteln, wird eine Debuggererweiterung bereitgestellt, die Ihnen genau mitteilen kann, welche Fehler in welche Reihenfolge eingefügt wurden.

Wenn die Option Stack Based Failure Injection für einen bestimmten Treiber aktiviert ist, werden einige Aufrufe dieses Treibers an den Kernel und Ndis.sys abgefangen. Stapelbasierte Fehlerinjektion untersucht die Aufrufliste, insbesondere den Teil des Aufrufstapels, der von dem Treiber stammt, für den er aktiviert ist. Wenn dies das erste Mal ist, dass dieser Stapel angezeigt wird, schlägt der Aufruf gemäß der Semantik dieses Aufrufs fehl. Andernfalls wird der Anruf, wenn er diesen Aufruf bereits gesehen hat, unberührt durchlaufen. Stack Based Failure Injection enthält Logik zum Umgang mit der Tatsache, dass ein Treiber mehrmals geladen und entladen werden kann. Er erkennt, dass ein Aufrufstapel identisch ist, auch wenn der Treiber an einem anderen Speicherort neu geladen wird.

Aktivieren dieser Option

Sie können das Feature Stack Based Failure Injection für einen oder mehrere Treiber aktivieren, wenn Sie einen Treiber auf einem Testcomputer bereitstellen. Sie können die Option Stapelbasierte Fehlerinjektion auswählen, wenn Sie die Treiberüberprüfungseigenschaften für Treiberpaketprojekte konfigurieren. Sie müssen den Computer neu starten, um die Option Stack Based Failure Injection zu aktivieren oder zu deaktivieren. Sie können auch ein Testhilfsprogramm ausführen, um die Treiberüberprüfung und dieses Feature auf dem Testcomputer zu aktivieren.

Wichtig Wenn Sie Stack Based Failure Injection auf dem Testcomputer aktivieren, stellen Sie sicher, dass Sie nicht auch Simulation mit niedrigen Ressourcen auswählen.

  • Seite "Driver Verifier-Eigenschaft verwenden"

    1. Öffnen Sie die Eigenschaftenseiten für Ihr Treiberpaket. Klicken Sie in Projektmappen-Explorer mit der rechten Maustaste auf das Treiberpaketprojekt, und wählen Sie Eigenschaften aus.
    2. Klicken Sie auf den Eigenschaftenseiten für das Treiberpaket auf Konfigurationseigenschaften, klicken Sie auf Treiberinstallation und dann auf Treiberüberprüfung.
    3. Wählen Sie Treiberüberprüfung aktivieren aus. Wenn Sie die Treiberüberprüfung auf dem Testcomputer aktivieren, können Sie die Treiberüberprüfung für alle Treiber auf dem Computer, nur für das Treiberprojekt oder für eine Liste der angegebenen Treiber aktivieren.
    4. Wählen Sie unter Stapelbasierte Fehlerinjektor die Option Stapelbasierte Fehlerinjektion aus.
    5. Klicken Sie auf Übernehmen oder auf OK.
    6. Weitere Informationen finden Sie unter Bereitstellen eines Treibers auf einem Testcomputer . Der Testcomputer muss neu gestartet werden, um diese Option zu aktivieren.
  • Verwenden des Tests "Aktivieren und Deaktivieren der Treiberüberprüfung"

    1. Sie können die Treiberüberprüfung auch aktivieren, indem Sie einen Hilfsprogrammtest ausführen. Befolgen Sie die Anweisungen unter Testen eines Treibers zur Laufzeit mit Visual Studio. Wählen Sie unter der Testkategorie Alle Tests\Driver Verifier die Tests Driver Verifier aktivieren (möglicher Neustart erforderlich) und Driver Verifier deaktivieren (möglicher Neustart erforderlich) aus.

    2. Wählen Sie die Treiberüberprüfungsoptionen aus, indem Sie im Fenster Treibertestgruppe auf den Namen des Tests Driver Verifier aktivieren (möglicher Neustart erforderlich) klicken.

    3. Wählen Sie (überprüfen) Stapelbasierte Fehlerinjektion aus.

    4. Nachdem Sie diese Tests einer Testgruppe hinzugefügt haben, können Sie die Testgruppe speichern. Um die Stack Based Failure Injection zu aktivieren, führen Sie den Test Enable Driver Verifier (möglicher Neustart erforderlich) auf dem Computer aus, den Sie zum Testen konfiguriert haben.

      Führen Sie zum Deaktivieren der Treiberüberprüfung den Test Disable Driver Verifier (möglicher Neustart erforderlich) aus.

Verwenden der Option Stapelbasierte Fehlerinjektion

Eine wichtige Überlegung beim Testen mit Stack Based Failure Injection ist, dass die meisten gefundenen Fehler zu einer Fehlerüberprüfung führen. Dies kann sich als etwas schmerzhaft erweisen, wenn Ihr Treiber ein startgeladener Treiber ist. Aus diesem Grund deaktivieren wir automatisch Stack Based Failure Injection, wenn Driver Verifier deaktiviert ist. Dies bedeutet, dass Sie stapelbasierte Fehlerinjektion zur Startzeit über den Debugger deaktivieren können, indem Sie die Treiberüberprüfung mithilfe des Befehls !verifier –disable deaktivieren.

Wenn dies möglich ist, richten Sie für Ihre ersten Tests mit Stack Based Failure Injection Den Treiber so ein, dass er nicht zur Startzeit geladen wird. Anschließend können Sie einige einfache Auslastungs- und Entladetests ausführen. Viele der von Stack Based Failure Injection gefundenen Fehler treten während der Initialisierung oder Bereinigung auf. Das wiederholte Laden und Entladen Ihres Treibers ist eine gute Möglichkeit, diese zu finden.

Nachdem Sie alle Korrekturen vorgenommen haben, die erforderlich sind, damit die Tests zum Entladen der Last erfolgreich sind, können Sie mit IOCTL-basierten Tests, vollständigen Funktionstests und schließlich Stresstests fortfahren. Wenn Sie diesen Testverlauf verfolgen, werden Sie beim Stresstest im Allgemeinen nicht viele neue Probleme aufdecken, da die meisten Codepfade bereits ausgeführt wurden.

Verwenden der Debuggererweiterung "Stack Based Failure Injection" (SBFI)

Die meisten Probleme, die bei der Einschleusung von stackbasierten Fehlern gefunden wurden, führen zu Fehlerüberprüfungen. Um die Ursache dieser Codefehler zu ermitteln, stellt der WDK die Debuggererweiterung Stack Based Failure Injection und die erforderlichen Symbole bereit. Die Installationsprozedur installiert beide auf Ihrem Debuggersystem. Der Standardspeicherort ist C:\Programme (x86)\Windows Kits\8.0\Debuggers\<arch>.

So führen Sie die Debuggererweiterung aus

  • Geben Sie an der Debuggereingabeaufforderung den folgenden Befehl ein: !<path>\kmautofaildbg.dll.autofail. Angenommen, Debuggererweiterungen werden unter c:\dbgext installiert und kmautofail.pdb befindet sich im Symbolpfad, geben Sie den folgenden Befehl ein:

    !c:\dbgext\kmautofaildbg.dll.autofail
    

Dadurch werden Informationen an Ihren Debugger mit den Aufrufstapeln der zuletzt eingefügten Fehler angezeigt. Jeder Eintrag sieht in etwa wie folgt aus, der aus einem echten Testlauf stammt. Im folgenden Beispiel ist stapelbasierte Fehlerinjektion auf Mydriver.sys

Sequence: 2, Test Number: 0, Process ID: 0, Thread ID: 0
                 IRQ Level: 2, HASH: 0xea98a56083aae93c
 0xfffff8800129ed83 kmautofail!ShimHookExAllocatePoolWithTag+0x37
 0xfffff88003c77566 mydriver!AddDestination+0x66
 0xfffff88003c5eeb2 mydriver!ProcessPacketDestination+0x82
 0xfffff88003c7db82 mydriver!ProcessPacketSource+0x8b2
 0xfffff88003c5d0d8 mydriver!ForwardPackets+0xb8
 0xfffff88003c81102 mydriver!RoutePackets+0x142
 0xfffff88003c83826 mydriver!RouteNetBufferLists+0x306
 0xfffff88003c59a76 mydriver!DeviceSendPackets+0x156
 0xfffff88003c59754 mydriver!ProcessingComplete+0x4a4
 0xfffff88001b69b81 systemdriver2!ProcessEvent+0x1a1
 0xfffff88001b3edc4 systemdriver1!CallChildDriver+0x20
 0xfffff88001b3fc0a systemdriver1!ProcessEvent+0x3e
 0xfffff800c3ea6eb9 nt!KiRetireDpcList+0x209
 0xfffff800c3ea869a nt!KiIdleLoop+0x5a

Am oberen Rand der Ausgabe zählt die Sequenznummer die Anzahl der Fehler, die eingefügt werden. Dieses Beispiel zeigt den zweiten Fehler, der während dieses Testlaufs eingefügt wurde. Die Prozess-ID ist 0. Dies war also der Systemprozess. IRQL ist 2, daher wird dies auf Versandebene bezeichnet.

Aus dem Stapel ist KmAutoFail der Stack Based Failure Injection-Treiber. Der Name der KmAutoFail-Funktion gibt an, welcher Funktionsaufruf von Mydriver.sys abgefangen und Fehler eingefügt wurde. Hier war die Funktion, bei der ein Fehler aufgetreten ist , ExAllocatePoolWithTag. Alle Funktionen in KmAutoFail, die Aufrufe von Ntoskrnl.sys oder Ndis.sys abfangen, verwenden diese Benennungskonvention. Als Nächstes sehen wir den Aufrufstapel mit dem getesteten Treiber (Mydriver.sys). Dies ist der Teil des Aufrufstapels, der verwendet wird, um die Eindeutigkeit des Stapels zu bestimmen. Daher ist jeder eintrag, der von der Debuggererweiterung abgedumpt wird, in diesem Teil des Aufrufstapels eindeutig. Der Rest des Aufrufstapels gibt an, wer den Treiber aufgerufen hat. Der Standard ist wichtig, ob der Treiber aus dem Benutzermodus (mithilfe einer IOCTL) oder von einem Kernelmodustreiber aufgerufen wird.

Beachten Sie, dass ein Neuladeversuch normalerweise an einem anderen Speicherort stattfindet, wenn ein Treiber einen Fehler aus seiner DriverEntry-Routine zurückgegeben hat. In diesem Fall enthält der Aufrufstapel vom früheren Speicherort wahrscheinlich "Garbage" anstelle von Stapelinformationen vom Treiber. Aber das ist kein Problem; Sie teilt Ihnen mit, dass der Treiber den eingefügten Fehler ordnungsgemäß behandelt hat.

Dieser nächste Eintrag zeigt einen Aufruf des Treibers mithilfe einer IOCTL aus dem Benutzermodus. Notieren Sie sich die Prozess-ID und die IRQ-Ebene. Da Mydriver.sys ein NDIS-Filtertreiber ist, hat das IOCTL Ndis.sys. Beachten Sie, dass nt! NtDeviceIoControlFile befindet sich im Stapel. Alle Tests, die Sie für Ihren Treiber ausführen, der IOCTLs verwendet, durchlaufen diese Funktion.

Sequence: 5, Test Number: 0, Process ID: 2052, Thread ID: 4588
                 IRQ Level: 0, HASH: 0xecd4650e9c25ee4
 0xfffff8800129ed83 kmautofail!ShimHookExAllocatePoolWithTag+0x37
 0xfffff88003c6fb39 mydriver!SendMultipleOids+0x41
 0xfffff88003c7157b mydriver!PvtDisconnect+0x437
 0xfffff88003c71069 mydriver!NicDisconnect+0xd9
 0xfffff88003ca3538 mydriver!NicControl+0x10c
 0xfffff88003c99625 mydriver!DeviceControl+0x4c5
 0xfffff88001559d93 NDIS!ndisDummyIrpHandler+0x73
 0xfffff88001559339 NDIS!ndisDeviceControlIrpHandler+0xc9
 0xfffff800c445cc96 nt!IovCallDriver+0x3e6
 0xfffff800c42735ae nt!IopXxxControlFile+0x7cc
 0xfffff800c4274836 nt!NtDeviceIoControlFile+0x56
 0xfffff800c3e74753 nt!KiSystemServiceCopyEnd+0x13

Analysieren der Ergebnisse der stapelbasierten Fehlerinjektion

Sie führen Ihre Tests auf Ihrem Treiber aus, und plötzlich tritt ein Problem auf. Höchstwahrscheinlich handelte es sich hierbei um eine Fehlerprüfung, die aber auch daran lag, dass der Computer nicht mehr reagierte. Wie finden Sie die Ursache? Wenn es sich um eine Fehlerüberprüfung handelt, verwenden Sie zunächst die obige Erweiterung, um die Liste der eingefügten Fehler zu finden, und verwenden Sie dann den Debuggerbefehl: !analyze –v.

Die häufigste Fehlerprüfung wird dadurch verursacht, dass der Erfolg einer Zuordnung nicht überprüft wird. In diesem Fall ist der Stapel aus der Fehlerprüfungsanalyse wahrscheinlich fast identisch mit dem des letzten eingefügten Fehlers. Irgendwann nach der fehlerhaften Zuordnung (häufig die nächste Zeile) greift der Treiber auf den NULL-Zeiger zu. Diese Art von Fehler ist sehr einfach zu beheben. Manchmal ist die fehlerhafte Zuordnung ein oder zwei in der Liste, aber dieser Typ ist immer noch sehr einfach zu finden und zu beheben.

Die zweihäufigste Fehlerüberprüfung erfolgt während der Bereinigung. In diesem Fall hat der Treiber wahrscheinlich den Zuordnungsfehler erkannt und zur Bereinigung übersprungen. Während der Bereinigung hat der Treiber den Zeiger jedoch nicht überprüft und erneut auf einen NULL-Zeiger zugegriffen. Ein eng verwandter Fall ist, in dem die Bereinigung zweimal aufgerufen werden kann. Wenn die Bereinigung den Zeiger auf eine Struktur nicht auf NULL festgelegt hat, nachdem sie sie freigegeben hat, versucht die Bereinigungsfunktion beim zweiten Aufruf der Bereinigungsfunktion ein zweites Mal, die Struktur frei zu geben, was zu einer Fehlerüberprüfung führt.

Fehler, die dazu führen, dass der Computer nicht mehr reagiert, sind schwieriger zu diagnostizieren, aber die Vorgehensweise zum Debuggen ist ähnlich. Diese Fehler werden häufig durch Probleme mit der Verweisanzahl oder der Drehsperre verursacht. Glücklicherweise fängt Driver Verifier viele Probleme mit der Drehsperre ab, bevor sie zu Problemen führen würden. Brechen Sie in diesen Fällen in den Debugger ein, und verwenden Sie die Debuggererweiterung, um die Liste der Fehler abzuspeichern, die von der stapelbasierten Fehlerinjektion eingefügt wurden. Ein kurzer Blick auf den Code zu den neuesten Fehlern zeigt möglicherweise eine Referenzanzahl an, die vor dem Fehler erstellt, aber danach nicht freigegeben wird. Wenn dies nicht der Fall ist, suchen Sie nach einem Thread in Ihrem Treiber, der auf eine Drehsperre wartet, oder nach einer Referenzanzahl, die offensichtlich falsch ist.