Pseudo-Register Syntax
Der Debugger unterstützt mehrere Pseudoregister, die bestimmte Werte enthalten.
Der Debugger legt automatische Pseudoregister auf bestimmte nützliche Werte fest. Benutzerdefinierte Pseudoregister sind ganzzahlige Variablen, in die Sie schreiben oder lesen können.
Alle Pseudoregister beginnen mit einem Dollarzeichen ($). Wenn Sie die MASM-Syntax verwenden, können Sie vor dem Dollarzeichen ein at-Zeichen ( @ ) hinzufügen. Dieses At-Zeichen teilt dem Debugger mit, dass das folgende Token ein Register oder Pseudoregister und kein Symbol ist. Wenn Sie das at-Zeichen weglassen, reagiert der Debugger langsamer, da er die gesamte Symboltabelle durchsuchen muss.
Beispielsweise erzeugen die folgenden beiden Befehle dieselbe Ausgabe, aber der zweite Befehl ist schneller.
0:000> ? $exp
Evaluate expression: 143 = 0000008f
0:000> ? @$exp
Evaluate expression: 143 = 0000008f
Wenn ein Symbol mit demselben Namen wie das Pseudoregister vorhanden ist, müssen Sie das At-Zeichen hinzufügen.
Wenn Sie die Syntax des C++-Ausdrucks verwenden, ist immer das At-Zeichen ( @ ) erforderlich.
Der Befehl r (Registers) ist eine Ausnahme von dieser Regel. Der Debugger interpretiert sein erstes Argument immer als Register oder Pseudoregister. (Ein At-Zeichen ist nicht erforderlich oder zulässig.) Wenn ein zweites Argument für den r-Befehl vorhanden ist, wird es gemäß der Standardausdruckssyntax interpretiert. Wenn die Standardausdruckssyntax C++ lautet, müssen Sie den folgenden Befehl verwenden, um das Pseudoregister $t 2 in das Pseudoregister $t 1 zu kopieren.
0:000> r $t1 = @$t2
Automatische Pseudo-Registers
Der Debugger legt automatisch die folgenden Pseudoregister fest.
Pseudoregister | BESCHREIBUNG |
---|---|
$ea |
Die effektive Adresse der letzten ausgeführten Anweisung. Wenn diese Anweisung keine effektive Adresse hat, zeigt der Debugger "Fehler beim ungültigen Register" an. Wenn diese Anweisung über zwei effektive Adressen verfügt, zeigt der Debugger die erste Adresse an. |
$ea 2 |
Die zweite effektive Adresse der letzten ausgeführten Anweisung. Wenn diese Anweisung nicht über zwei effektive Adressen verfügt, zeigt der Debugger "Ungültiger Registerfehler" an. |
$exp |
Der letzte ausgewertete Ausdruck. |
$ra |
Die Rückgabeadresse, die sich derzeit im Stapel befindet. Diese Adresse ist besonders bei Ausführungsbefehlen nützlich. Beispielsweise wird g @$ra so lange fortgesetzt, bis die Rückgabeadresse gefunden wird (obwohl gu (Go Up) eine präzisere Methode zum "Austreten" der aktuellen Funktion ist). |
$ip |
Das Anweisungszeigerregister. x86-basierte Prozessoren: Dasselbe wie eip. Itanium-basierte Prozessoren: Im Zusammenhang mit iip. (Weitere Informationen finden Sie im Hinweis nach dieser Tabelle.) x64-basierte Prozessoren: Dasselbe wie rip. |
$eventip |
Der Anweisungszeiger zum Zeitpunkt des aktuellen Ereignisses. Dieser Zeiger entspricht in der Regel $ip, es sei denn, Sie haben threads gewechselt oder den Wert des Anweisungszeigers manuell geändert. |
$previp |
Der Anweisungszeiger zum Zeitpunkt des vorherigen Ereignisses. (Das Unterbrechen des Debuggers zählt als Ereignis.) |
$relip |
Ein Anweisungszeiger, der sich auf das aktuelle Ereignis bezieht. Wenn Sie die Branchablaufverfolgung verwenden, ist dieser Zeiger der Zeiger auf die Branchquelle. |
$scopeip |
Der Anweisungszeiger für den aktuellen lokalen Kontext (auch als Bereich bezeichnet). |
$exentry |
Die Adresse des Einstiegspunkts der ersten ausführbaren Datei des aktuellen Prozesses. |
$retreg |
Das primäre Rückgabewertregister. x86-basierte Prozessoren: Dasselbe wie eax. Itanium-basierte Prozessoren: Dasselbe wie ret0. x64-basierte Prozessoren: Dasselbe wie rax. |
$retreg 64 |
Das primäre Rückgabewertregister im 64-Bit-Format. x86-Prozessor: Dasselbe wie das edx:eax-Paar . |
$csp |
Der aktuelle Aufrufstapelzeiger. Dieser Zeiger ist das Register, das für die Aufrufstapeltiefe am repräsentativsten ist. x86-basierte Prozessoren: Identisch mit esp. Itanium-basierte Prozessoren: Dasselbe wie bsp. x64-basierte Prozessoren: Identisch mit rsp. |
$p |
Der Wert, den der letzte d*-Befehl (Speicher anzeigen) ausgegeben hat. |
$proc |
Die Adresse des aktuellen Prozesses (d. h. die Adresse des EPROCESS-Blocks). |
$thread |
Die Adresse des aktuellen Threads. Beim Debuggen im Kernelmodus ist diese Adresse die Adresse des ETHREAD-Blocks. Beim Debuggen im Benutzermodus ist diese Adresse die Adresse des Threadumgebungsblocks (TEB). |
$peb |
Die Adresse des Prozessumgebungsblocks (PEB) des aktuellen Prozesses. |
$teb |
Die Adresse des Threadumgebungsblocks (TEB) des aktuellen Threads. |
$tpid |
Die Prozess-ID (PID) für den Prozess, der besitzer des aktuellen Threads ist. |
$tid |
Die Thread-ID für den aktuellen Thread. |
$dtid |
|
$dpid |
|
$dsid |
|
$bpNummer |
Die Adresse des entsprechenden Haltepunkts. Beispielsweise bezieht sich $bp 3 (oder $bp 03) auf den Haltepunkt, dessen Haltepunkt-ID 3 ist. Zahl ist immer eine Dezimalzahl. Wenn kein Haltepunkt über die ID "Number" verfügt, wird $bpZahl zu 0 (null) ausgewertet. Weitere Informationen zu Haltepunkten finden Sie unter Verwenden von Haltepunkten. |
$frame |
Der aktuelle Frameindex. Dieser Index ist die gleiche Framenummer, die vom Befehl .frame (Set Local Context) verwendet wird. |
$dbgtime |
Die aktuelle Uhrzeit entsprechend dem Computer, auf dem der Debugger ausgeführt wird. |
$callret |
Der Rückgabewert der letzten Funktion, die .call (Aufruffunktion) aufgerufen hat oder die in einem FNRET /s-Befehl verwendet wird. Der Datentyp von $callret ist der Datentyp dieses Rückgabewerts. |
$extret |
|
$extin |
|
$clrex |
|
$lastclrex |
Nur verwaltetes Debuggen: Die Adresse des zuletzt gefundenen CLR-Ausnahmeobjekts (Common Language Runtime). |
$ptrsize |
Die Größe eines Zeigers. Im Kernelmodus ist diese Größe die Zeigergröße auf dem Zielcomputer. |
$pagesize |
Die Anzahl der Bytes auf einer Seite des Arbeitsspeichers. Im Kernelmodus entspricht diese Größe der Seitengröße auf dem Zielcomputer. |
$pcr |
|
$pcrb |
|
$argreg |
|
$exr_chance |
Die Wahrscheinlichkeit des aktuellen Ausnahmedatensatzes. |
$exr_code |
Der Ausnahmecode für den aktuellen Ausnahmedatensatz. |
$exr_numparams |
Die Anzahl der Parameter im aktuellen Ausnahmedatensatz. |
$exr_param0 |
Der Wert von Parameter 0 im aktuellen Ausnahmedatensatz. |
$exr_param1 |
Der Wert von Parameter 1 im aktuellen Ausnahmedatensatz. |
$exr_param2 |
Der Wert von Parameter 2 im aktuellen Ausnahmedatensatz. |
$exr_param3 |
Der Wert von Parameter 3 im aktuellen Ausnahmedatensatz. |
$exr_param4 |
Der Wert von Parameter 4 im aktuellen Ausnahmedatensatz. |
$exr_param5 |
Der Wert von Parameter 5 im aktuellen Ausnahmedatensatz. |
$exr_param6 |
Der Wert von Parameter 6 im aktuellen Ausnahmedatensatz. |
$exr_param7 |
Der Wert von Parameter 7 im aktuellen Ausnahmedatensatz. |
$exr_param8 |
Der Wert von Parameter 8 im aktuellen Ausnahmedatensatz. |
$exr_param9 |
Der Wert von Parameter 9 im aktuellen Ausnahmedatensatz. |
$exr_param10 |
Der Wert von Parameter 10 im aktuellen Ausnahmedatensatz. |
$exr_param11 |
Der Wert von Parameter 11 im aktuellen Ausnahmedatensatz. |
$exr_param12 |
Der Wert von Parameter 12 im aktuellen Ausnahmedatensatz. |
$exr_param13 |
Der Wert von Parameter 13 im aktuellen Ausnahmedatensatz. |
$exr_param14 |
Der Wert von Parameter 14 im aktuellen Ausnahmedatensatz. |
$bug_code |
Wenn eine Fehlerüberprüfung durchgeführt wurde, ist dies der Fehlercode. Gilt für Debuggen im Aktiven Kernelmodus und Kernelabbilder mit Absturz. |
$bug_param1 |
Wenn eine Fehlerüberprüfung durchgeführt wurde, ist dies der Wert von Parameter 1. Gilt für Debuggen im Aktiven Kernelmodus und Kernelabbilder mit Absturz. |
$bug_param2 |
Wenn eine Fehlerüberprüfung durchgeführt wurde, ist dies der Wert von Parameter 2. Gilt für Debuggen im Aktiven Kernelmodus und Kernelabbilder mit Absturz. |
$bug_param3 |
Wenn eine Fehlerüberprüfung durchgeführt wurde, ist dies der Wert von Parameter 3. Gilt für Debuggen im Aktiven Kernelmodus und Kernelabbilder mit Absturz. |
$bug_param4 |
Wenn eine Fehlerüberprüfung durchgeführt wurde, ist dies der Wert von Parameter 4. Gilt für Debuggen im Aktiven Kernelmodus und Kernelabbilder mit Absturz. |
Einige dieser Pseudoregister sind in bestimmten Debugszenarien möglicherweise nicht verfügbar. Sie können beispielsweise $peb, $tid und $tpid nicht verwenden, wenn Sie eine Minidump-Datei im Benutzermodus oder bestimmte Kernelmodus-Dumpdateien debuggen. Es gibt Situationen, in denen Sie Threadinformationen von ~ (Threadstatus) lernen können, aber nicht von $tid. Sie können das $previp Pseudoregister nicht für das erste Debuggerereignis verwenden. Sie können das $relip Pseudoregister nur verwenden, wenn Sie die Branchablaufverfolgung verwenden. Wenn Sie ein nicht verfügbares Pseudoregister verwenden, tritt ein Syntaxfehler auf.
Ein Pseudoregister, das die Adresse einer Struktur wie $thread, $proc, $teb, $peb und $lastclrex enthält, wird nach dem richtigen Datentyp in der C++-Ausdrucksauswertung ausgewertet, jedoch nicht in der MASM-Ausdrucksauswertung. Beispielsweise zeigt der Befehl ? $teb die Adresse des TEB an, während der Befehl ?? @$teb die gesamte TEB-Struktur anzeigt. Weitere Informationen finden Sie unter Auswerten von Ausdrücken.
Auf einem Itanium-basierten Prozessor ist das iip-Register bündelbündig ausgerichtet, was bedeutet, dass es auf Slot 0 im Bundle zeigt, das die aktuelle Anweisung enthält, auch wenn ein anderer Slot ausgeführt wird. iip ist also nicht der vollständige Anweisungszeiger. Der $ip Pseudoregisters ist der eigentliche Anweisungszeiger, einschließlich des Bundles und des Slots. Die anderen Pseudoregister mit Adresszeigern ($ra, $retreg, $eventip, $previp, $relip und $exentry) haben dieselbe Struktur wie $ip auf allen Prozessoren.
Sie können den r-Befehl verwenden, um den Wert von $ip zu ändern. Diese Änderung ändert auch automatisch das entsprechende Register. Wenn die Ausführung fortgesetzt wird, wird sie an der neuen Anweisungszeigeradresse fortgesetzt. Dieses Register ist das einzige automatische Pseudoregister, das Sie manuell ändern können.
Hinweis In der MASM-Syntax können Sie das $ip Pseudoregister mit einem Punkt ( ) angeben. Sie fügen vor diesem Zeitraum kein at-Zeichen (@) hinzu und verwenden den Punkt nicht als ersten Parameter des r-Befehls . Diese Syntax ist in einem C++-Ausdruck nicht zulässig.
Automatische Pseudoregister ähneln automatischen Aliasen. Sie können jedoch automatische Aliase zusammen mit aliasbezogenen Token (z. B. ${ }) verwenden, und Sie können keine Pseudoregister mit solchen Token verwenden.
Benutzerdefinierte Pseudo-Registers
Es gibt 20 benutzerdefinierte Pseudoregister ($t 0, $t 1, ..., $t 19). Diese Pseudoregister sind Variablen, die Sie lesen und über den Debugger schreiben können. Sie können einen beliebigen ganzzahligen Wert in diesen Pseudoregistern speichern. Sie können als Schleifenvariablen besonders nützlich sein.
Um in eines dieser Pseudoregister zu schreiben, verwenden Sie den Befehl r (Registers), wie im folgenden Beispiel gezeigt.
0:000> r $t0 = 7
0:000> r $t1 = 128*poi(MyVar)
Wie bei allen Pseudoregistern können Sie das benutzerdefinierte Pseudoregister in einem beliebigen Ausdruck verwenden, wie im folgenden Beispiel gezeigt.
0:000> bp $t3
0:000> bp @$t4
0:000> ?? @$t1 + 4*@$t2
Ein Pseudoregister wird immer als ganze Zahl eingegeben, es sei denn, Sie verwenden den Schalter ? zusammen mit dem Befehl r . Wenn Sie diesen Schalter verwenden, ruft das Pseudoregister den Typ dessen ab, was ihm zugewiesen ist. Der folgende Befehl weist z. B. den Typ UNICODE_STRING** und den wert der 0x0012FFBC $t 15 zu.
0:000> r? $t15 = * (UNICODE_STRING*) 0x12ffbc
Benutzerdefinierte Pseudoregister verwenden null als Standardwert, wenn der Debugger gestartet wird.
Hinweis Die Aliase $u 0, $u 1, ..., $u 9 sind trotz ihrer ähnlichen Darstellung keine Pseudoregister. Weitere Informationen zu diesen Aliasen finden Sie unter Verwenden von Aliasen.
Beispiel
Im folgenden Beispiel wird ein Haltepunkt festgelegt, der jedes Mal erreicht wird, wenn der aktuelle Thread NtOpenFile aufruft. Dieser Haltepunkt wird jedoch nicht erreicht, wenn andere Threads NtOpenFile aufrufen.
kd> bp /t @$thread nt!ntopenfile
Beispiel
Im folgenden Beispiel wird ein Befehl ausgeführt, bis das Register einen angegebenen Wert enthält. Fügen Sie zunächst den folgenden Code für das bedingte Schrittschritt in eine Skriptdatei mit dem Namen "eaxstep" ein.
.if (@eax == 1234) { .echo 1234 } .else { t "$<eaxstep" }
Geben Sie als Nächstes den folgenden Befehl aus.
t "$<eaxstep"
Der Debugger führt einen Schritt aus und führt dann ihren Befehl aus. In diesem Fall führt der Debugger das Skript aus, das entweder 1234 anzeigt oder den Prozess wiederholt.