2010-04-04 11 views
5

Lavoro su una grande applicazione e uso frequentemente WinDbg per diagnosticare problemi basati su un file DMP da un cliente. Ho scritto alcune piccole estensioni per WinDbg che si sono rivelate molto utili per estrarre bit di informazioni dai file DMP. Nel mio codice di estensione mi ritrovo a dereferenziare oggetti di classe C++ allo stesso modo, ripetutamente, a mano. Per esempio:Come posso creare oggetti basati sulla memoria di file di dump in un'estensione WinDbg?

Address = GetExpression("somemodule!somesymbol"); 
ReadMemory(Address, &addressOfPtr, sizeof(addressOfPtr), &cb); 

// get the actual address 
ReadMemory(addressOfObj, &addressOfObj, sizeof(addressOfObj), &cb); 

ULONG offset; 
ULONG addressOfField; 

GetFieldOffset("somemodule!somesymbolclass", "somefield", &offset); 
ReadMemory(addressOfObj+offset, &addressOfField, sizeof(addressOfField), &cb); 

che funziona bene, ma come ho scritto più estensioni, con una maggiore funzionalità (e accedere agli oggetti più complicati nelle nostre applicazioni file DMP), ho desiderato per una soluzione migliore. Naturalmente ho accesso alla fonte della nostra applicazione, quindi immagino che ci dovrebbe essere un modo per copiare un oggetto da un file DMP e usare quella memoria per creare un oggetto reale nell'estensione del debugger che posso chiamare funzioni su (collegando in DLL dalla nostra applicazione). Questo mi avrebbe risparmiato la fatica di estrarre le cose dalla DMP a mano.

È possibile? Ho provato cose ovvie come creare un nuovo oggetto nell'estensione, quindi sovrascriverlo con un grande ReadMemory direttamente dal file DMP. Questo sembrava mettere i dati nei campi giusti, ma è andato fuori di testa quando ho provato a chiamare una funzione. Immagino che mi manchi qualcosa ... forse il C++ richiama un funky brio che non conosco? Il mio codice è simile a questo:

SomeClass* thisClass = SomeClass::New(); 
ReadMemory(addressOfObj, &(*thisClass), sizeof(*thisClass), &cb); 

SEGUITO: Sembra EVENTUALMENTE ExtRemoteTyped da EngExtCpp è quello che voglio? Qualcuno ha usato con successo questo? Ho bisogno di google su qualche codice di esempio, ma non ho molta fortuna.

FOLLOWUP 2: Sto perseguendo due diversi percorsi di indagine su questo.
1) Sto cercando ExtRemoteTyped, ma sembra che questa classe sia davvero solo un aiuto per le chiamate ReadMemory/GetFieldOffset. Sì, aiuterebbe a velocizzare le cose, ma non è di grande aiuto quando si tratta di ricreare un oggetto da un file DMP. Sebbene la documentazione sia snella, potrei quindi fraintendere qualcosa. 2) Sto anche cercando di utilizzare ReadMemory per sovrascrivere un oggetto creato nella mia estensione con i dati del file DMP. Tuttavia, piuttosto che usare sizeof (* thisClass) come sopra, stavo pensando che avrei scelto solo gli elementi di dati e lasciato intatti i vtables.

+0

Ottima domanda PJ! –

risposta

1

Idea interessante, ma questo avrebbe la speranza di lavorare solo sugli oggetti più semplici. Ad esempio, se l'oggetto contiene puntatori o riferimenti ad altri oggetti (o vtables), questi non verranno copiati molto bene in un nuovo spazio indirizzo.

Tuttavia, è possibile ottenere un oggetto "proxy" che funzioni quando vengono chiamati i metodi proxy che effettuano le chiamate appropriate a ReadMemory() per ottenere le informazioni. Questo sembra essere un bel po 'di lavoro, e penso che dovrebbe essere più o meno un set personalizzato di codice per ogni classe che si desidera proxy. Probabilmente c'è un modo migliore per farlo, ma è quello che mi è venuto fuori di testa.

+0

Sì, stavo pensando la stessa cosa. Pensavo che i puntatori non avrebbero funzionato bene, a meno che non avessi seguito il puntatore con ReadMemory e copiassi anche quei dati. Ma dovrei comunque essere in grado di chiamare funzioni sulla classe, no? Cosa intendevi per i vtables che non copiavano bene? – pj4533

+0

@ pj4533: potresti essere in grado di chiamare funzioni sulla classe, ma se la classe contiene puntatori o riferimenti queste funzioni troveranno un oggetto molto incasinato. Probabilmente sarai in grado di cavartela con quello che stai facendo con le classi POD e forse con altre classi semplici, ma sarebbe una cosa abbastanza incerta. Ovviamente, devi assicurarti di costruire l'estensione debugger in modo tale che il layout dell'oggetto sia lo stesso. –

+0

@ pj4533: per vtables che non copiavano bene, intendevo il puntatore vtable che è in qualsiasi classe con una funzione virtuale. Punta a ciò che equivale a una tabella di salto di funzione e la posizione di tale tabella sarà a indirizzi diversi nei processi di debugger e debugger. –

0

So che ottenere i dump di memoria è sempre stato il modo di ottenere informazioni per la diagnosi, ma con ETW è molto più semplice e si ottiene un'informazione insieme a stack di chiamate che includono chiamate al sistema informativo e codice utente. MS ha fatto questo per tutti i loro prodotti, inclusi Windows e VS.NET.

È un metodo di debug non intrusivo. Ho fatto lo stesso debugging per molto tempo e ora con ETW sono in grado di risolvere la maggior parte dei problemi dei clienti senza passare molto tempo all'interno del debugger. Questi sono i miei due centesimi.

+0

Non ho davvero imparato molto su Event Tracing per Windows. Sembra che richieda molte modifiche al codice (aggiunta di chiamate all'API del registro di tracciamento degli eventi)? Questo non è possibile per tutte le diverse versioni della nostra applicazione, per non parlare delle versioni legacy multiple che supportiamo ancora che sono già sul campo! – pj4533

0

Mi sono avvicinato a qualcosa di simile quando ho hackerato un'estensione per tracciamento perdite gdi per windbg.Ho usato un contenitore stl per l'archiviazione dei dati nel client e avevo bisogno di un modo per attraversare i dati dall'estensione. Ho finito per implementare le parti della hash_map di cui avevo bisogno direttamente sul lato dell'estensione usando ExtRemoteTyped che era soddisfacente, ma mi ci è voluto un po 'per capire: o) Here è il codice sorgente.

+0

Questo è interessante, ma penso che il mio vero obiettivo sia riuscire a passare oggetti da un file di dump attraverso altre routine di utilità, e farli trattare esattamente come i tipi di oggetto che sono (cioè: non un tipo derivato 'remoto') . – pj4533

1

Ho finito per seguire la mia impressione iniziale e copiare i dati dal file dmp in un nuovo oggetto. Ho fatto questo migliore rendendo oggetti wrapper remoti come questo:

class SomeClassRemote : public SomeClass 
{ 
protected: 
    SomeClassRemote (void); 
    SomeClassRemote (ULONG inRemoteAddress); 

public: 
    static SomeClassRemote *  New(ULONG inRemoteAddress); 
    virtual ~SomeClassRemote (void); 

private: 

    ULONG     m_Address; 

}; 

E nella realizzazione:

SomeClassRemote::SomeClassRemote (ULONG inRemoteAddress) 
{ 
    ULONG cb; 

    m_Address = inRemoteAddress; 

    // copy in all the data to the new object, skipping the virtual function tables 
    ReadMemory(inRemoteAddress + 0x4, (PVOID) ((ULONG)&(*this) +0x4), sizeof(SomeClass) - 4, &cb); 
} 

SomeClassRemote::SomeClassRemote(void) 
{ 
} 

SomeClassRemote::~SomeClassRemote(void) 
{ 
} 

SomeClassRemote* SomeClassRemote::New(ULONG inRemoteAddress) 
{ 
    SomeClassRemote*x = new SomeClassRemote(inRemoteAddress); 

    return (x); 
} 

vale a dire le nozioni di base, ma poi aggiungo override specifici come necessario per afferrare più informazioni il file dmp. Questa tecnica mi consente di trasferire questi nuovi oggetti remoti nel nostro codice sorgente originale per l'elaborazione in varie funzioni di utilità, in quanto derivano dalla classe originale.

sembra certo come dovrei essere in grado di templatize questo in qualche modo ... ma ci sembra sempre di essere qualche ragione che ogni classe è implementata in modo leggermente diverso, ad esempio alcuni dei nostri oggetti più complessi hanno un paio VTables, entrambi che devono essere saltati.

Problemi correlati