Domanda

Lavoro su una grande applicazione e uso spesso WindBG per diagnosticare i problemi in base a un file DMP di 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 fare il dereferencing C ++ oggetti di classe allo stesso modo, ancora e ancora, a mano. Per esempio:

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);

Funziona bene, ma come ho scritto più estensioni, con maggiori funzionalità (e accedere a oggetti più complicati nei nostri file DMP di applicazioni), ho desiderato una soluzione migliore. Ho accesso alla fonte della nostra applicazione ovviamente, quindi immagino che ci dovrebbe essere un modo per copiare un oggetto da un file DMP e utilizzare quella memoria per creare un oggetto reale nell'estensione del debugger su cui posso chiamare le funzioni ( collegando in DLLS dalla nostra applicazione). Questo mi salverebbe a mano il problema di estrarre le cose dal DMP.

È anche possibile? Ho provato cose ovvie come la creazione di un nuovo oggetto nell'estensione, quindi sovrascrivendolo con un grande Readmemory direttamente dal file DMP. Questo sembrava mettere i dati nei campi giusti, ma sono impazzito quando ho provato a chiamare una funzione. Immagino che mi manchi qualcosa ... forse C ++ tira un po 'di funky vtable che non conosco? Il mio codice sembra simile a questo:

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

Follow -up: sembra forse estremamentetetipato da enGextCPP è quello che voglio? Qualcuno l'ha usato con successo? Ho bisogno di su Google un codice di esempio, ma non ho molta fortuna.

Seguitore 2: sto perseguendo due diverse rotte di indagine su questo.
1) Sto esaminando estremotetipato, ma sembra che questa classe sia davvero solo un aiutante per le chiamate ReadMemory/GetFieldOffset. Sì, aiuterebbe ad accelerare molto le cose, ma non aiuta davvero quando si tratta di ricreare un oggetto da un file DMP. Sebbene la documentazione sia sottile, quindi potrei fraintendendo qualcosa. 2) Sto anche cercando di provare a utilizzare ReadMemory per sovrascrivere un oggetto creato nella mia estensione con i dati dal file DMP. Tuttavia, piuttosto che usare la dimensione di (*questa classe) come sopra, pensavo che avrei scelto solo gli elementi di dati e lasciare intatti i vtables.

È stato utile?

Soluzione

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

Tuttavia, potresti essere in grado di ottenere un oggetto "proxy" per funzionare che quando si chiama i metodi proxy effettuano le chiamate appropriate a ReadMemory() per ottenere le informazioni. Sembra un bel po 'di lavoro, e penso che dovrebbe essere più o meno un set personalizzato di codice per ogni classe che volevi proxy. Probabilmente c'è un modo migliore per farlo, ma è quello che mi è venuto fuori dalla testa.

Altri suggerimenti

Ho finito per seguire il mio abbonamento iniziale e copiare i dati dal file DMP in un nuovo oggetto. L'ho migliorato creando oggetti avvolgenti 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 nell'implementazione:

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);
}

Queste sono le basi, ma poi aggiungo sovraccarichi specifici, se necessario per ottenere maggiori informazioni dal file DMP. Questa tecnica mi consente di riportare questi nuovi oggetti remoti nel nostro codice sorgente originale per l'elaborazione in varie funzioni di utilità, perché derivano dalla classe originale.

Sembra sicuramente che dovrei essere in grado di templaterarlo in qualche modo ... ma sembra sempre esserci qualche motivo per cui ogni classe sia implementata in modo leggermente diverso, ad esempio alcuni dei nostri oggetti più complicati hanno un paio di vtables, entrambi i quali devono esserlo saltato.

So che ottenere dump di memoria è sempre stato il modo per ottenere informazioni per la diagnosi, ma con ETW è molto più facile e ottieni informazioni insieme a stack di chiamate che includono chiamate di sistema di informazione e codice utente. MS lo ha fatto per tutti i loro prodotti, tra cui Windows e Vs.NET.

È un modo non intrusivo di debug. Ho fatto lo stesso debug 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.

Mi sono avvicinato a qualcosa di simile durante l'hacking di un'estensione del tracciante di 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 dell'hash_map di cui avevo bisogno direttamente sul lato estensione usando estremotetipato che era soddisfacente ma mi ci è voluto un po 'per capire; o)Qui è il codice sorgente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top