2016-03-12 19 views
8

Fondamentalmente, questa è la stessa domanda che è stata richiesta here.WinDbg non mostra i valori di registro

Durante l'esecuzione del debug del kernel di una macchina con Windows 7 o precedente, con WinDbg versione 6.2 e successive, il debugger non mostra nulla nella finestra dei registri. Premendo il pulsante Customize... si ottiene una finestra di messaggio che legge Registers are not yet known.

Allo stesso tempo, il comando r consente di stampare valori di registro perfettamente validi.

Qual è il motivo di questo comportamento e può essere risolto?

risposta

14

TL; DR: Ho scritto un'estensione DLL che corregge il bug. Disponibile here.

Il problema

per capire il problema, abbiamo prima bisogno di capire che WinDbg è fondamentalmente solo un frontend per di Windows Symbolic Debugger Engine di Microsoft, implementata all'interno dbgeng.dll. Altri frontend includono la riga di comando kd.exe (debugger kernel) e cdb.exe (debugger in modalità utente).

Il motore implementa tutto ciò che ci aspettiamo da un debugger: lavorare con file di simboli, leggere e scrivere memoria e registri, impostare breakpoitns, ecc. Il motore espone quindi tutte queste funzionalità attraverso interfacce COM-like (implementano IUnknown ma sono componenti non registrati). Questo ci consente, ad esempio, di scrivere il nostro debugger (come ha fatto this person).

Armati di questa conoscenza, ora possiamo formulare un'ipotesi su come WinDbg ottiene i valori dei registri sul computer di destinazione.

Il motore espone l'interfaccia IDebugRegisters per la manipolazione dei registri. Questa interfaccia dichiara il metodo GetValues per il recupero dei valori di più registri in una volta. Ma come fa WinDbg a sapere quanti registri ci sono? Ecco perché abbiamo il metodo GetNumberRegisters.

Così, per recuperare i valori di tutti i registri sul bersaglio, dovremo fare qualcosa di simile:

  1. chiamata IDebugRegisters::GetNumberRegisters per ottenere il numero totale di registri.
  2. chiamata IDebugRegisters::GetValues con il parametro Count impostata sul numero totale di registri, il parametro Indices impostato NULL, e il parametro Start impostato 0.

Un piccolo problema, tuttavia: la seconda chiamata ha esito negativo con E_INVALIDARG.

Ehm, mi scusi? Come può fallire? Particolarmente sconcertante è la documentazione per questo valore di ritorno:

Il valore dell'indice di uno dei registri è maggiore del numero di registri sulla macchina di destinazione.

Ma ti ho appena chiesto quanti registri ci sono, quindi come può essere fuori portata? Va bene, continuiamo a leggere la documentazione in ogni caso, forse qualcosa sarà chiaro:

Se il valore di ritorno non è S_OK, alcuni dei registri ancora potrebbe essere stato letto. Se la destinazione non era accessibile, il tipo di reso è E_UNEXPECTED e Valori è invariato; altrimenti, i valori conterranno i risultati parziali ei registri che non è stato possibile leggere avranno il tipo DEBUG_VALUE_INVALID.

(sottolineatura mia.)

Aha! Quindi forse il motore non poteva leggere uno dei registri! Ma quale? Risulta che il motore soffoca sul registro xcr0. Dal manuale il Intel 64 e IA-32 Architetture dello sviluppatore di software:

registro di controllo esteso XCR0 contiene una bitmap stato-componente che specifica i componenti dello stato di utente che il software ha permesso la XSAVE set di funzionalità per la gestione. Se il bit corrispondente a un componente di stato è chiaro in XCR0, le istruzioni nel set di funzionalità XSAVE non funzioneranno su quel componente di stato, indipendentemente dal valore della maschera di istruzioni.

Va bene, in modo che il registro controlla il funzionamento dell'istruzione XSAVE, che salva lo stato di funzionalità estese della CPU (come XMM e AVX). Secondo l'ultimo commento sulla pagina this, questa istruzione richiede supporto dal sistema operativo. Sebbene il commento affermi che Windows 7 (è quello su cui era in esecuzione la VM su cui stavo testando) supporta questa istruzione, sembra che il problema in questione sia comunque correlato all'OS, poiché quando l'obiettivo è Windows 8, tutto funziona correttamente.

Davvero, non è chiaro se il bug è all'interno del motore di debugger, che riporta più registri di quello che può recuperare i valori, o all'interno di WinDbg, che si rifiuta di mostrare i valori affatto se il motore non riesce a produrre tutto di loro.

La soluzione

Potremmo, ovviamente, stringere i denti e basta usare una vecchia versione di WinDbg per il debug di vecchie versioni di Windows. Ma dov'è la sfida in questo?

Invece, vi presento uno debugger extension che risolve questo problema. Lo fa agganciando (con l'aiuto di this library) i metodi del motore di debugger rilevanti e restituendo S_OK se l'unico registro che ha avuto esito negativo è stato xcr0. Altrimenti, si propaga l'errore. L'estensione supporta lo scaricamento di runtime, quindi se si verificano problemi è sempre possibile disabilitare i ganci.

Questo è tutto, buon divertimento!

+0

dovresti postarlo su quel thread. –

Problemi correlati