Ändern von Kontexten

Beim Debuggen im Kernel-Modus gibt es viele Prozesse, Threads und manchmal auch Benutzersitzungen, die zur gleichen Zeit ausgeführt werden. Daher sind Ausdrücke wie „virtuelle Adresse 0x80002000“ oder „das eax-Register“ zweideutig. Sie müssen den Kontext angeben, in dem solche Ausdrücke verstanden werden können.

Der Debugger verfügt über fünf verschiedene Kontexte, die Sie während des Debuggens festlegen können:

  1. Der Sitzungskontext gibt die standardmäßige Benutzersitzung an.

  2. Der Prozesskontext bestimmt, wie der Debugger virtuelle Adressen interpretiert.

  3. Der Benutzermodus-Adresskontext wird fast nie direkt festgelegt. Dieser Kontext wird automatisch festgelegt, wenn Sie den Prozesskontext ändern.

  4. Der Registerkontext bestimmt, wie der Debugger Register interpretiert und steuert auch die Ergebnisse einer Stack-Abfrage. Dieser Kontext wird auch als Thread-Kontext bezeichnet, obwohl dieser Begriff nicht ganz zutreffend ist. Ein expliziter Kontext ist ebenfalls eine Art von Registerkontext. Wenn Sie einen expliziten Kontext angeben, wird dieser Kontext anstelle des aktuellen Registerkontexts verwendet.

  5. Der lokale Kontext bestimmt, wie der Debugger die lokalen Variablen interpretiert. Dieser Kontext wird auch als Bereich bezeichnet.

Sitzungskontext

Mehrere Anmeldesitzungen können gleichzeitig ausgeführt werden. Jede Anmeldesitzung hat ihre eigenen Prozesse.

Die Erweiterung !session zeigt alle Anmeldesitzungen an oder ändert den aktuellen Sitzungskontext.

Der Sitzungskontext wird von den Erweiterungen !sprocess und !spoolused verwendet, wenn die Sitzungsnummer als „-2“ eingegeben wird.

Wenn der Sitzungskontext geändert wird, wird der Prozesskontext automatisch auf den aktiven Prozess für diese Sitzung geändert.

Prozesskontext

Jeder Prozess hat sein eigenes Seiten-Verzeichnis, das die Zuordnung von virtuellen Adressen zu physischen Adressen speichert. Wenn ein Thread innerhalb eines Prozesses ausgeführt wird, verwendet das Windows-Betriebssystem dieses Seiten-Verzeichnis, um virtuelle Adressen zu interpretieren.

Während der Fehlersuche im Benutzermodus bestimmt der aktuelle Prozess den Prozesskontext. Virtuelle Adressen, die in Debugger-Befehlen, Erweiterungen und Debugging-Informationsfenstern verwendet werden, werden unter Verwendung des Seiten-Verzeichnisses des aktuellen Prozesses interpretiert.

Während des Debuggens im Kernel-Modus können Sie den Prozesskontext mit dem Befehl .process (Prozesskontext festlegen) festlegen. Verwenden Sie diesen Befehl, um auszuwählen, welches Seiten-Verzeichnis des Prozesses für die Interpretation virtueller Adressen verwendet werden soll. Nachdem Sie den Prozesskontext festgelegt haben, können Sie diesen Kontext in jedem Befehl verwenden, der Adressen verarbeitet. Sie können sogar Haltepunkte an dieser Adresse festlegen. Indem Sie eine Option /i in den Befehl .process einfügen, um invasives Debugging festzulegen, können Sie den Kernel-Debugger auch zum Festlegen von Haltepunkten im Benutzermodus verwenden.

Sie können auch vom Kernel-Debugger aus Haltepunkte im Benutzermodus festlegen, indem Sie einen prozessspezifischen Haltepunkt für eine Funktion im Kernel-Space verwenden. Legen Sie strategische Haltepunkte fest, und warten Sie, bis der entsprechende Kontext angezeigt wird.

Der Benutzermodus-Adresskontext ist Teil des Prozesskontextes. Normalerweise müssen Sie den Benutzermodus-Adresskontext nicht direkt festlegen. Wenn Sie den Prozesskontext festlegen, wechselt der Adresskontext für den Benutzermodus automatisch in die Verzeichnisbasis der entsprechenden Seitentabelle für den Prozess.

Wenn Sie den Prozesskontext während des Debuggens des Kernels festlegen, wird dieser Prozesskontext beibehalten, bis ein weiterer .process Befehl den Kontext ändert. Der Adresskontext im Benutzermodus wird ebenfalls beibehalten, bis er durch einen .process- oder .context-Befehl geändert wird. Diese Kontexte werden nicht geändert, wenn der Zielcomputer ausgeführt wird, und sie werden von Änderungen des Registerkontexts oder des lokalen Kontexts nicht beeinflusst.

Register-Kontext

Jeder Thread hat seine eigenen Registerwerte. Diese Werte werden in den CPU-Registern gespeichert, wenn der Thread ausgeführt wird, und sie werden im Speicher abgelegt, wenn ein anderer Thread ausgeführt wird.

Während des Debuggens im Benutzermodus bestimmt normalerweise der aktuelle Thread den Registerkontext. Jeder Verweis auf Register in Debugger-Befehlen, Erweiterungen und Debugging-Informationsfenstern wird entsprechend den Registern des aktuellen Threads interpretiert.

Sie können den Register-Kontext auf einen anderen Wert als den des aktuellen Threads ändern, während Sie das Debugging im Benutzermodus durchführen, indem Sie einen der folgenden Befehle verwenden:

.cxr (Kontext-Datensatz anzeigen)

.ecxr (Kontext-Datensatz für Ausnahme anzeigen)

Während des Debuggens im Kernel-Modus können Sie den Register-Kontext mit einer Reihe von Debugger-Befehlen steuern, darunter die folgenden Befehle:

.thread (Set Register Context)

.cxr (Kontext-Datensatz anzeigen)

.trap (Display Trap Frame)

Diese Befehle ändern nicht die Werte der CPU-Register. Stattdessen ruft der Debugger den angegebenen Register-Kontext von seinem Speicherplatz im Speicher ab. Eigentlich kann der Debugger nur die gespeicherten Registerwerte abrufen. (Andere Werte werden dynamisch festgelegt und werden nicht gespeichert. Die gespeicherten Werte reichen aus, um einen Stack-Trace neu zu erstellen.

Nachdem der Register-Kontext festgelegt wurde, wird der neue Register-Kontext für alle Befehle verwendet, die Registerwerte verwenden, wie k (Stack-Backtrace anzeigen) und r (Register).

Bei der Fehlersuche in Multiprozessor-Computern können Sie jedoch bei einigen Befehlen einen Prozessor angeben. (Weitere Informationen über solche Befehle finden Sie unter Multiprozessor-Syntax.) Wenn Sie einen Prozessor für einen Befehl angeben, verwendet der Befehl den Register-Kontext des aktiven Threads auf dem angegebenen Prozessor anstelle des aktuellen Register-Kontextes, auch wenn der angegebene Prozessor der derzeit aktive Prozessor ist.

Wenn der Register-Kontext nicht mit der aktuellen Einstellung des Prozessormodus übereinstimmt, erzeugen diese Befehle außerdem eine falsche oder sinnlose Ausgabe. Um diese Ausgabefehler zu vermeiden, schlagen Befehle, die vom Status des Registers abhängen, fehl, bis Sie den Prozessormodus so ändern, dass er mit dem Register-Kontext übereinstimmt. Um den Prozessormodus zu ändern, verwenden Sie den Befehl .effmach (effektiver Computer),

Eine Änderung des Register-Kontextes kann auch den lokalen Kontext ändern. Auf diese Weise kann der Register-Kontext die Anzeige der lokalen Variablen beeinflussen.

Wenn eine Anwendungsausführung, ein Stepping oder ein Tracing stattfindet, wird der Register-Kontext sofort zurückgesetzt, damit er mit der Position des Programmzählers übereinstimmt. Im Benutzermodus wird der Register-Kontext auch zurückgesetzt, wenn der aktuelle Prozess oder Thread gewechselt wird.

Der Register-Kontext wirkt sich auf Stack-Traces aus, denn der Stack-Trace beginnt an der Stelle, auf die das Stack-Pointer-Register (esp auf einem x86-basierten Prozessor) zeigt. Wenn der Register-Kontext auf einen ungültigen oder unzugänglichen Wert festgelegt ist, können keine Stack-Traces abgerufen werden.

Sie können einen Haltepunkt des Prozessors (Daten-Haltepunkt) auf einen bestimmten Register-Kontext anwenden, indem Sie den Befehl .apply_dbp (Daten-Haltepunkt auf Kontext anwenden) verwenden.

Lokaler Kontext

Wenn ein Programm ausgeführt wird, hängt die Bedeutung lokaler Variablen von der Position des Programmzählers ab, denn der Bereich solcher Variablen erstreckt sich nur auf die Funktion, in der sie definiert sind.

Wenn Sie das Debugging im Benutzermodus oder im Kernel-Modus durchführen, verwendet der Debugger den Bereich der aktuellen Funktion (den aktuellen Frame auf dem Stack) als lokalen Kontext. Um diesen Kontext zu ändern, verwenden Sie den Befehl .frame (lokalen Kontext festlegen) oder doppelklicken Sie auf den gewünschten Frame im Fenster Calls.

Beim Debuggen im Benutzermodus ist der lokale Kontext immer ein Frame innerhalb der Stack-Trace des aktuellen Threads. Beim Debuggen im Kernel-Modus ist der lokale Kontext immer ein Frame innerhalb der Stack-Trace des aktuellen Threads des Register-Kontextes.

Sie können jeweils nur einen Stack-Frame für den lokalen Kontext verwenden. Auf lokale Variablen in anderen Frames kann nicht zugegriffen werden.

Der lokale Kontext wird zurückgesetzt, wenn eines der folgenden Ereignisse eintritt:

  • Jede Programmausführung, Stepping oder Tracing

  • Jede Verwendung des Thread-Trennzeichens (~) in einem Befehl

  • Jede Änderung des Register-Kontextes

Mit der Erweiterung !for_each_frame können Sie einen einzelnen Befehl wiederholt ausführen, und zwar einmal für jeden Frame im Stack. Dieser Befehl ändert den lokalen Kontext für jeden Frame, führt den angegebenen Befehl aus und setzt dann den lokalen Kontext auf seinen ursprünglichen Wert zurück.