Pseudo-Register 語法
偵錯工具支援數個保存特定值的虛擬暫存器。
偵錯工具會將 自動虛擬暫存器 設定為特定的實用值。 使用者定義的虛擬暫存器 是您可以寫入或讀取的整數變數。
所有虛擬暫存器都是以貨幣符號開頭, ($) 。 如果您使用 MASM 語法,您可以在貨幣符號之前新增 at sign ( @ ) 。 這在符號上會告訴偵錯工具下列權杖是暫存器或虛擬暫存器,而不是符號。 如果您省略 at 符號,偵錯工具回應的速度會比較慢,因為它必須搜尋整個符號表。
例如,下列兩個命令會產生相同的輸出,但第二個命令的速度較快。
0:000> ? $exp
Evaluate expression: 143 = 0000008f
0:000> ? @$exp
Evaluate expression: 143 = 0000008f
如果符號與虛擬暫存器的名稱相同,您必須新增 at 符號。
如果您使用 C++ 運算式語法,則一律需要正負號 ( @ ) 。
r (Registers) 命令是此規則的例外狀況。 偵錯工具一律會將第一個引數解譯為暫存器或虛擬暫存器。 (不需要或允許 at 符號。) 如果 r 命令有第二個引數,則會根據預設運算式語法加以解譯。 如果預設運算式語法為 C++,您必須使用下列命令,將 $t 2 虛擬暫存器複製到 $t 1 虛擬暫存器。
0:000> r $t1 = @$t2
自動 Pseudo-Registers
偵錯工具會自動設定下列虛擬暫存器。
虛擬暫存器 | Description |
---|---|
$ea |
執行的最後一個指令的有效位址。 如果此指令沒有有效的位址,偵錯工具會顯示「註冊錯誤」。 如果此指令有兩個有效的位址,偵錯工具會顯示第一個位址。 |
$ea 2 |
執行的最後一個指令的第二個有效位址。 如果此指令沒有兩個有效位址,偵錯工具會顯示「註冊錯誤錯誤」。 |
$exp |
評估的最後一個運算式。 |
$ra |
目前位於堆疊上的傳回位址。 此位址在執行命令中特別有用。 例如, g @$ra 會繼續直到找到傳回位址 (雖然 gu (Go Up) 是更精確的目前函式) 「逐步執行」的有效方式。 |
$ip |
指令指標暫存器。 x86 處理器: 與 eip相同。 以 Itanium 為基礎的處理器: 與 iip相關。 (如需詳細資訊,請參閱下表後面的附注.) x64 型處理器: 與 擷取相同。 |
$eventip |
目前事件時的指令指標。 除非您切換執行緒或手動變更指令指標的值,否則此指標通常會符合 $ip。 |
$previp |
上一個事件時的指令指標。 (中斷至偵錯工具會計算為 event.) |
$relip |
與目前事件相關的指令指標。 當您進行分支追蹤時,此指標是分支來源的指標。 |
$scopeip |
目前 本機內容的 指令指標 (也稱為 範圍) 。 |
$exentry |
目前進程第一個可執行檔之進入點的位址。 |
$retreg |
主要傳回值暫存器。 x86 處理器: 與 eax相同。 以 Itanium 為基礎的處理器: 與 ret0相同。 x64 型處理器: 與 rax相同。 |
$retreg 64 |
主要傳回值暫存器,格式為 64 位。 x86 處理器: 與 edx:eax 配對相同。 |
$csp |
目前的呼叫堆疊指標。 此指標是最代表呼叫堆疊深度的暫存器。 x86 處理器: 與 esp相同。 以 Itanium 為基礎的處理器: 與 bsp相同。 x64 型處理器: 與 rsp相同。 |
$p |
最後 一個 d* (顯示記憶體) 命令列印的值。 |
$proc |
目前進程 (的位址,也就是 EPROCESS 區塊的位址) 。 |
$thread |
目前線程的位址。 在核心模式偵錯中,此位址是 ETHREAD 區塊的位址。 在使用者模式偵錯中,此位址是執行緒環境區塊的位址, (TEB) 。 |
$peb |
進程環境區塊的位址 (目前進程的 PEB) 。 |
$teb |
執行緒環境區塊的位址 (目前線程的 TEB) 。 |
$tpid |
擁有目前線程之進程的進程識別碼 (PID) 。 |
$tid |
目前線程的執行緒識別碼。 |
$dtid |
|
$DPId |
|
$dsid |
|
$bp編號 |
對應中斷點的位址。 例如, $bp 3 (或 $bp 03) 是指中斷點識別碼為 3 的中斷點。 數位 一律是十進位數。 如果沒有中斷點的識別碼為 Number, $bpNumber 會評估為零。 如需中斷點的詳細資訊,請參閱 使用中斷點。 |
$frame |
目前的框架索引。 這個索引與 .frame (設定本機內容) 命令所使用的畫面編號相同。 |
$dbgtime |
根據偵錯工具執行所在的電腦,目前的時間。 |
$callret |
.call (呼叫函式) 呼叫或用於.fnret /s命令的最後一個函式傳回值。 $callret的資料類型是這個傳回值的資料類型。 |
$extret |
|
$extin |
|
$clrex |
|
$lastclrex |
僅限 Managed 偵錯: 上次遇到的 Common Language Runtime 位址 (CLR) 例外狀況物件。 |
$ptrsize |
指標的大小。 在核心模式中,此大小是目的電腦上的指標大小。 |
$pagesize |
一頁記憶體中的位元組數目。 在核心模式中,此大小是目的電腦上的頁面大小。 |
$pcr |
|
$pcrb |
|
$argreg |
|
$exr_chance |
目前例外狀況記錄的機會。 |
$exr_code |
目前例外狀況記錄的例外狀況程式碼。 |
$exr_numparams |
目前例外狀況記錄中的參數數目。 |
$exr_param0 |
目前例外狀況記錄中的 Parameter 0 值。 |
$exr_param1 |
目前例外狀況記錄中的 Parameter 1 值。 |
$exr_param2 |
目前例外狀況記錄中的 Parameter 2 值。 |
$exr_param3 |
目前例外狀況記錄中的 Parameter 3 值。 |
$exr_param4 |
目前例外狀況記錄中的 Parameter 4 值。 |
$exr_param5 |
目前例外狀況記錄中的 Parameter 5 值。 |
$exr_param6 |
目前例外狀況記錄中的 Parameter 6 值。 |
$exr_param7 |
目前例外狀況記錄中的 Parameter 7 值。 |
$exr_param8 |
目前例外狀況記錄中的 Parameter 8 值。 |
$exr_param9 |
目前例外狀況記錄中的 Parameter 9 值。 |
$exr_param10 |
目前例外狀況記錄中的 Parameter 10 值。 |
$exr_param11 |
目前例外狀況記錄中的 Parameter 11 值。 |
$exr_param12 |
目前例外狀況記錄中的 Parameter 12 值。 |
$exr_param13 |
目前例外狀況記錄中的 Parameter 13 值。 |
$exr_param14 |
目前例外狀況記錄中的 Parameter 14 值。 |
$bug_code |
如果發生錯誤檢查,這是錯誤碼。 適用于即時核心模式偵錯和核心損毀傾印。 |
$bug_param1 |
如果發生錯誤檢查,這是參數 1 的值。 適用于即時核心模式偵錯和核心損毀傾印。 |
$bug_param2 |
如果發生錯誤檢查,這是參數 2 的值。 適用于即時核心模式偵錯和核心損毀傾印。 |
$bug_param3 |
如果發生錯誤檢查,這是參數 3 的值。 適用于即時核心模式偵錯和核心損毀傾印。 |
$bug_param4 |
如果發生錯誤檢查,這是參數 4 的值。 適用于即時核心模式偵錯和核心損毀傾印。 |
某些虛擬暫存器在某些偵錯案例中可能無法使用。 例如,當您偵錯使用者模式迷你傾印或特定核心模式傾印檔案時,無法使用 $peb、 $tid和 $tpid 。 在某些情況下,您可以從 ~ (執行緒狀態) ,但無法從 $tid學習執行緒資訊。 您無法在第一個偵錯工具事件上使用 $previp 虛擬暫存器。 除非您是分支追蹤,否則您無法使用 $relip 虛擬暫存器。 如果您使用無法使用的虛擬暫存器,就會發生語法錯誤。
保存結構位址的虛擬暫存器,例如$thread、$proc、$teb、$peb和$lastclrex ,將會根據 C++ 運算式評估工具中的適當資料類型進行評估,但不會在 MASM 運算式評估工具中評估。 例如,命令 ? $teb 會顯示 TEB 的位址,而命令 ?? @$teb 會顯示整個 TEB 結構。 如需詳細資訊,請參閱 評估運算式。
在 Itanium 型處理器上, iip 暫存器會 對齊套件組合,這表示它指向包含目前指令的套件組合中的位置 0,即使執行不同的位置也一樣。 因此 iip 不是完整的指令指標。 $ip虛擬暫存器是實際的指令指標,包括套件組合和位置。 另一個虛擬暫存器會保存位址指標 ($ra、$retreg、$eventip、$previp、$relip和$exentry) 結構與所有處理器上的$ip相同。
您可以使用 r 命令來變更 $ip的值。 這項變更也會自動變更對應的暫存器。 當執行繼續時,它會繼續位於新的指令指標位址。 此暫存器是您可以手動變更的唯一自動虛擬暫存器。
注意在 MASM 語法中,您可以使用句號 ( 來指出$ip虛擬暫存器。) 。 您在此句點之前不會新增 at sign (@) ,也不會使用句點做為 r 命令的第一個參數。 C++ 運算式中不允許此語法。
自動虛擬暫存器類似于 自動別名。 但是,您可以將自動別名與別名相關的權杖一起使用, (例如 ${ }) ,而且您無法搭配這類權杖使用虛擬暫存器。
使用者定義 Pseudo-Registers
有 20 個使用者定義的虛擬暫存器 ($t 0、 $t 1、...、 $t 19) 。 這些虛擬暫存器是您可以透過偵錯工具讀取和寫入的變數。 您可以將任何整數值儲存在這些虛擬暫存器中。 它們在迴圈變數中特別有用。
若要寫入這些虛擬暫存器之一,請使用 r (Registers) 命令,如下列範例所示。
0:000> r $t0 = 7
0:000> r $t1 = 128*poi(MyVar)
如同所有虛擬暫存器,您可以在任何運算式中使用使用者定義的虛擬暫存器,如下列範例所示。
0:000> bp $t3
0:000> bp @$t4
0:000> ?? @$t1 + 4*@$t2
除非您搭配r命令使用?參數,否則虛擬暫存器一律會輸入為整數。 如果您使用此參數,虛擬暫存器會取得指派給它的任何類型。 例如,下列命令會將 UNICODE_STRING** 類型和0x0012FFBC值指派給 $t 15。
0:000> r? $t15 = * (UNICODE_STRING*) 0x12ffbc
使用者定義虛擬暫存器會在偵錯工具啟動時使用零作為預設值。
注意 $u 0、 $u 1、...、 $u 9 別名不是虛擬暫存器,儘管其外觀類似。 如需這些別名的詳細資訊,請參閱 使用別名。
範例
下列範例會設定每次目前線程呼叫 NtOpenFile時所叫用的中斷點。 但當其他執行緒呼叫 NtOpenFile時,不會叫用此中斷點。
kd> bp /t @$thread nt!ntopenfile
範例
下列範例會執行命令,直到暫存器保留指定的值為止。 首先,將下列程式碼放在名為 「eaxstep」 的腳本檔案中,以設定條件式逐步執行。
.if (@eax == 1234) { .echo 1234 } .else { t "$<eaxstep" }
接下來,發出下列命令。
t "$<eaxstep"
偵錯工具會執行步驟,然後執行命令。 在此情況下,偵錯工具會執行腳本,該腳本會顯示 1234 或重複此程式。