5

私は大規模なアプリケーションで作業しており、WinDbgを頻繁に使用して、顧客からのDMPファイルに基づいて問題を診断しています。WinDbgの小さな拡張機能をいくつか作成しました。これらは、DMPファイルから情報を引き出すのに非常に役立つことが証明されています。私の拡張コードでは、c++クラスオブジェクトを同じ方法で何度も手作業で逆参照していることに気づきました。例えば:

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

それはうまく機能しますが、より優れた機能を備えた(そしてアプリケーションのDMPファイル内のより複雑なオブジェクトにアクセスする)拡張機能を作成するにつれて、より良いソリューションを待ち望んでいました。もちろん、私は自分のアプリケーションのソースにアクセスできるので、DMPファイルからオブジェクトをコピーし、そのメモリを使用して、関数を呼び出すことができるデバッガー拡張機能に実際のオブジェクトを作成する方法があるはずです(アプリケーションからdllにリンクすることによって)。これにより、DMPから手で物を引き出す手間を省くことができます。

これも可能ですか?拡張機能で新しいオブジェクトを作成し、それをDMPファイルから直接大きなReadMemoryで上書きするなど、明らかなことを試みました。これはデータを正しいフィールドに配置しているように見えましたが、関数を呼び出そうとするとびっくりしました。私は何かが欠けていると思います...多分c++は私が知らないいくつかのvtableファンキーさを引き出しますか?私のコードは次のようになります。

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

フォローアップ:EngExtCppのExtRemoteTypedが必要なようです。誰かがこれをうまく使用しましたか?いくつかのサンプルコードをグーグルで検索する必要がありますが、あまり運がありません。

フォローアップ2:私はこれについて2つの異なる調査ルートを追求しています。
1)ExtRemoteTypedを調べていますが、このクラスは実際にはReadMemory/GetFieldOffset呼び出しの単なるヘルパーであるようです。はい、それはALOTの速度を上げるのに役立ちますが、DMPファイルからオブジェクトを再作成する場合には実際には役立ちません。ドキュメントはスリムですが、私は何かを誤解している可能性があります。2)ReadMemoryを使用して、拡張機能で作成されたオブジェクトをDMPファイルのデータで上書きすることも検討しています。ただし、上記のようにsizeof(* thisClass)を使用するのではなく、データ要素のみを選択し、vtablesはそのままにしておくと考えていました。

4

4 に答える 4

1

興味深いアイデアですが、これは最も単純なオブジェクトでのみ機能することを期待しています。たとえば、オブジェクトに他のオブジェクト(またはvtables)へのポインターまたは参照が含まれている場合、それらは新しいアドレス空間にうまくコピーされません。

ただし、プロキシメソッドを呼び出すと、適切な呼び出しをReadMemory()行って情報を取得する「プロキシ」オブジェクトを機能させることができる場合があります。これはかなりの作業のように思えますが、プロキシしたいクラスごとに、多かれ少なかれカスタムのコードセットである必要があると思います。これについてはおそらくもっと良い方法がありますが、それが私の頭のてっぺんからやってきたことです。

于 2010-04-04T02:18:34.030 に答える
1

私は最初の予感をたどり、dmpファイルから新しいオブジェクトにデータをコピーすることになりました。次のようなリモートラッパーオブジェクトを作成することで、これを改善しました。

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

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

private:

    ULONG                   m_Address;

};

そして実装では:

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

これが基本ですが、必要に応じて特定のオーバーライドを追加して、dmpファイルからより多くの情報を取得します。この手法により、これらの新しいリモートオブジェクトを元のソースコードに戻して、さまざまなユーティリティ関数で処理できるようになります。これは、元のクラスから派生しているためです。

私のようなSEEMSは、これをなんとかしてテンプレート化できるはずです...しかし、各クラスがわずかに異なる方法で実装されている理由は常にあるようです。たとえば、より複雑なオブジェクトのいくつかには、いくつかのvtableがあり、両方ともスキップしました。

于 2010-04-06T20:50:11.860 に答える
0

windbgのgdiリークトレーサー拡張機能をハッキングするときに、似たようなものに近づきました。クライアントのデータストレージにstlコンテナを使用し、拡張機能からデータをトラバースする方法が必要でした。ExtRemoteTypedを使用して、拡張側に直接必要なhash_mapの部分を実装することになりました。これは満足のいくものでしたが、理解するのに時間がかかりました; o) これがソースコードです。

于 2010-04-04T22:27:01.917 に答える
0

メモリダンプを取得することが常に診断用の情報を取得する方法であることは知っていますが、ETWを使用すると、はるかに簡単になり、情報システムコールやユーザーコードを含むコールスタックとともに情報を取得できます。MSは、WindowsやVS.NETを含むすべての製品に対してこれを行ってきました。

これは、邪魔にならないデバッグ方法です。私は非常に長い間同じデバッグを行ってきましたが、ETWを使用すると、デバッガー内で多くの時間を費やすことなく、顧客の問題のほとんどを解決できます。これらは私の2セントです。

于 2010-04-04T14:42:11.787 に答える