Pseudo-Register Syntax
The debugger supports several pseudo-registers that hold certain values.
The debugger sets automatic pseudo-registers to certain useful values. User-defined pseudo-registers are integer variables that you can write to or read.
All pseudo-registers begin with a dollar sign ($). If you are using MASM syntax, you can add an at sign ( @ ) before the dollar sign. This at sign tells the debugger that the following token is a register or pseudo-register, not a symbol. If you omit the at sign, the debugger responds more slowly, because it has to search the whole symbol table.
For example, the following two commands produce the same output, but the second command is faster.
0:000> ? $exp
Evaluate expression: 143 = 0000008f
0:000> ? @$exp
Evaluate expression: 143 = 0000008f
If a symbol exists with the same name as the pseudo-register, you must add the at sign.
If you are using C++ expression syntax, the at sign ( @ ) is always required.
The r (Registers) command is an exception to this rule. The debugger always interprets its first argument as a register or pseudo-register. (An at sign is not required or permitted.) If there is a second argument for the r command, it is interpreted according to the default expression syntax. If the default expression syntax is C++, you must use the following command to copy the $t2 pseudo-register to the $t1 pseudo-register.
0:000> r $t1 = @$t2
Automatic Pseudo-Registers
The debugger automatically sets the following pseudo-registers.
Pseudo-register | Description |
---|---|
$ea |
The effective address of the last instruction that was executed. If this instruction does not have an effective address, the debugger displays "Bad register error". If this instruction has two effective addresses, the debugger displays the first address. |
$ea2 |
The second effective address of the last instruction that was executed. If this instruction does not have two effective addresses, the debugger displays "Bad register error". |
$exp |
The last expression that was evaluated. |
$ra |
The return address that is currently on the stack. This address is especially useful in execution commands. For example, g @$ra continues until the return address is found (although gu (Go Up) is a more precise effective way of "stepping out" of the current function). |
$ip |
The instruction pointer register. x86-based processors: The same as eip. Itanium-based processors: Related to iip. (For more information, see the note following this table.) x64-based processors: The same as rip. |
$eventip |
The instruction pointer at the time of the current event. This pointer typically matches $ip, unless you switched threads or manually changed the value of the instruction pointer. |
$previp |
The instruction pointer at the time of the previous event. (Breaking into the debugger counts as an event.) |
$relip |
An instruction pointer that is related to the current event. When you are branch tracing, this pointer is the pointer to the branch source. |
$scopeip |
The instruction pointer for the current local context (also known as the scope). |
$exentry |
The address of the entry point of the first executable of the current process. |
$retreg |
The primary return value register. x86-based processors: The same as eax. Itanium-based processors: The same as ret0. x64-based processors: The same as rax. |
$retreg64 |
The primary return value register, in 64-bit format. x86 processor: The same as the edx:eax pair. |
$csp |
The current call stack pointer. This pointer is the register that is most representative of call stack depth. x86-based processors: The same as esp. Itanium-based processors: The same as bsp. x64-based processors: The same as rsp. |
$p |
The value that the last d* (Display Memory) command printed. |
$proc |
The address of the current process (that is, the address of the EPROCESS block). |
$thread |
The address of the current thread. In kernel-mode debugging, this address is the address of the ETHREAD block. In user-mode debugging, this address is the address of the thread environment block (TEB). |
$peb |
The address of the process environment block (PEB) of the current process. |
$teb |
The address of the thread environment block (TEB) of the current thread. |
$tpid |
The process ID (PID) for the process that owns the current thread. |
$tid |
The thread ID for the current thread. |
$dtid |
|
$dpid |
|
$dsid |
|
$bpNumber |
The address of the corresponding breakpoint. For example, $bp3 (or $bp03) refers to the breakpoint whose breakpoint ID is 3. Number is always a decimal number. If no breakpoint has an ID of Number, $bpNumber evaluates to zero. For more information about breakpoints, see Using Breakpoints. |
$frame |
The current frame index. This index is the same frame number that the .frame (Set Local Context) command uses. |
$dbgtime |
The current time, according to the computer that the debugger is running on. |
$callret |
The return value of the last function that .call (Call Function) called or that is used in an .fnret /s command. The data type of $callret is the data type of this return value. |
$extret |
|
$extin |
|
$clrex |
|
$lastclrex |
Managed debugging only: The address of the last-encountered common language runtime (CLR) exception object. |
$ptrsize |
The size of a pointer. In kernel mode, this size is the pointer size on the target computer. |
$pagesize |
The number of bytes in one page of memory. In kernel mode, this size is the page size on the target computer. |
$pcr |
|
$pcrb |
|
$argreg |
|
$exr_chance |
The chance of the current exception record. |
$exr_code |
The exception code for the current exception record. |
$exr_numparams |
The number of parameters in the current exception record. |
$exr_param0 |
The value of Parameter 0 in the current exception record. |
$exr_param1 |
The value of Parameter 1 in the current exception record. |
$exr_param2 |
The value of Parameter 2 in the current exception record. |
$exr_param3 |
The value of Parameter 3 in the current exception record. |
$exr_param4 |
The value of Parameter 4 in the current exception record. |
$exr_param5 |
The value of Parameter 5 in the current exception record. |
$exr_param6 |
The value of Parameter 6 in the current exception record. |
$exr_param7 |
The value of Parameter 7 in the current exception record. |
$exr_param8 |
The value of Parameter 8 in the current exception record. |
$exr_param9 |
The value of Parameter 9 in the current exception record. |
$exr_param10 |
The value of Parameter 10 in the current exception record. |
$exr_param11 |
The value of Parameter 11 in the current exception record. |
$exr_param12 |
The value of Parameter 12 in the current exception record. |
$exr_param13 |
The value of Parameter 13 in the current exception record. |
$exr_param14 |
The value of Parameter 14 in the current exception record. |
$bug_code |
If a bug check has occurred, this is the bug code. Applies to live kernel-mode debugging and kernel crash dumps. |
$bug_param1 |
If a bug check has occurred, this is the value of Parameter 1. Applies to live kernel-mode debugging and kernel crash dumps. |
$bug_param2 |
If a bug check has occurred, this is the value of Parameter 2. Applies to live kernel-mode debugging and kernel crash dumps. |
$bug_param3 |
If a bug check has occurred, this is the value of Parameter 3. Applies to live kernel-mode debugging and kernel crash dumps. |
$bug_param4 |
If a bug check has occurred, this is the value of Parameter 4. Applies to live kernel-mode debugging and kernel crash dumps. |
Some of these pseudo-registers might not be available in certain debugging scenarios. For example, you cannot use $peb, $tid, and $tpid when you are debugging a user-mode minidump or certain kernel-mode dump files. There will be situations where you can learn thread information from ~ (Thread Status) but not from $tid. You cannot use the $previp pseudo-register on the first debugger event. You cannot use the $relip pseudo-register unless you are branch tracing. If you use an unavailable pseudo-register, a syntax error occurs.
A pseudo-register that holds the address of a structure -- such as $thread, $proc, $teb, $peb, and $lastclrex -- will be evaluated according to the proper data type in the C++ expression evaluator, but not in the MASM expression evaluator. For example, the command ? $teb displays the address of the TEB, while the command ?? @$teb displays the entire TEB structure. For more information, see Evaluating Expressions.
On an Itanium-based processor, the iip register is bundle-aligned, which means that it points to slot 0 in the bundle containing the current instruction, even if a different slot is being executed. So iip is not the full instruction pointer. The $ip pseudo-register is the actual instruction pointer, including the bundle and the slot. The other pseudo-registers that hold address pointers ($ra, $retreg, $eventip, $previp, $relip, and $exentry) have the same structure as $ip on all processors.
You can use the r command to change the value of $ip. This change also automatically changes the corresponding register. When execution resumes, it resumes at the new instruction pointer address. This register is the only automatic pseudo-register that you can change manually.
Note In MASM syntax, you can indicate the $ip pseudo-register with a period ( . ). You do not add an at sign (@) before this period, and do not use the period as the first parameter of the r command. This syntax is not permitted within a C++ expression.
Automatic pseudo-registers are similar to automatic aliases. But you can use automatic aliases together with alias-related tokens (such as ${ }), and you cannot use pseudo-registers with such tokens.
User-Defined Pseudo-Registers
There are 20 user-defined pseudo-registers ($t0, $t1, ..., $t19). These pseudo-register are variables that you can read and write through the debugger. You can store any integer value in these pseudo-registers. They can be especially useful as loop variables.
To write to one of these pseudo-registers, use the r (Registers) command, as the following example shows.
0:000> r $t0 = 7
0:000> r $t1 = 128*poi(MyVar)
Like all pseudo-registers, you can use the user-defined pseudo-register in any expression, as the following example shows.
0:000> bp $t3
0:000> bp @$t4
0:000> ?? @$t1 + 4*@$t2
A pseudo-register is always typed as an integer, unless you use the ? switch together with the r command. If you use this switch, the pseudo-register acquires the type of whatever is assigned to it. For example, the following command assigns the UNICODE_STRING** type and the 0x0012FFBC value to $t15.
0:000> r? $t15 = * (UNICODE_STRING*) 0x12ffbc
User-defined pseudo-registers use zero as the default value when the debugger is started.
Note The aliases $u0, $u1, ..., $u9 are not pseudo-registers, despite their similar appearance. For more information about these aliases, see Using Aliases.
Example
The following example sets a breakpoint that is hit every time that the current thread calls NtOpenFile. But this breakpoint is not hit when other threads call NtOpenFile.
kd> bp /t @$thread nt!ntopenfile
Example
The following example executes a command until the register holds a specified value. First, put the following code for conditional stepping in a script file named "eaxstep".
.if (@eax == 1234) { .echo 1234 } .else { t "$<eaxstep" }
Next, issue the following command.
t "$<eaxstep"
The debugger performs a step and then runs your command. In this case, the debugger runs the script, which either displays 1234 or repeats the process.