6

ここに私が持っているいくつかのコードがあります:

MyClass* MyClass::getInstance()
{
   static MyClass instance;
   return &instance;
}

このシングルトンの現在の値を調べたいと思います。しかし、私は現在実行を 3 時間停止しています。一時停止している理由は、メモリが不足しているためです。したがって、このメソッドにブレークポイントを配置して、値が何であるかを確認することはできません。

私の質問はinstance、グローバル スコープからこの変数を参照する方法です。私はそれを参照しようとしましたMyClass::getInstance::instanceが、うまくいきません。getInstanceなんらかの方法で装飾する必要があると思います。誰でも方法を知っていますか?

これは Visual Studio 2008 にあります。

4

3 に答える 3

5

さて、関数スコープの静的instance変数は、.mapによって生成されたファイルには表示されcl.exe /Fmません。また、WinDbgで使用すると表示されないx programname!*MyClass*ため、マングルされた名前にはまったく含まれていないようですMyClass

オプション1:分解するMyClass::getInstance

このアプローチは簡単なようです。

0:000> uf programname!MyClass :: getInstance
programname!MyClass :: getInstance [programname.cpp @ 14]:
   140040105055プッシュebp
   14 00401051 8bec mov ebp、esp
   15 00401053 a160b34200 mov eax、dword ptr [programname!$ S1(0042b360)]
   15 00401058 83e001およびeax、1
   15 0040105b 7526 jne funcstat!MyClass :: getInstance + 0x33(00401083)

programname!MyClass :: getInstance + 0xd [programname.cpp @ 15]:
   15 0040105d 8b0d60b34200 mov ecx、dword ptr [programname!$ S1(0042b360)]
   15 00401063 83c901またはecx、1
   15 00401066 890d60b34200 mov dword ptr [programname!$ S1(0042b360)]、ecx
   15 0040106c b9b0be4200 mov ecx、offset programname!instance(0042beb0)
   15 00401071 e88fffffff call programname!ILT + 0(?? 0MyClassQAEXZ)(00401005)
   15 00401076 68e03e4200プッシュオフセットプログラム名! `MyClass :: getInstance'::` 2':: `'インスタンス''の動的アテキシットデストラクタ(00423ee0)
   15 0040107b e8f3010000 call programname!atexit(00401273)
   15 00401080 83c404 add esp、4

programname!MyClass :: getInstance + 0x33 [programname.cpp @ 16]:
   16 00401083 b8b0be4200 mov eax、offset programname!instance(0042beb0)
   17 00401088 5d pop ebp
   17 00401089 c3 ret

これから、コンパイラがオブジェクトを呼び出したことがわかります$S1。もちろん、この名前は、プログラムにある関数スコープの静的変数の数によって異なります。

オプション2:オブジェクトのメモリを検索する

@gbjbaanbの提案を拡張するために、MyClass仮想関数がある場合、その場所を難しい方法で見つけることができるかもしれません。

  • プロセスのフルメモリダンプを作成します。
  • フルメモリダンプをWinDbgにロードします。
  • 次のコマンドを使用してx、MyClassのvtableのアドレスを検索します。
    0:000> x programname!MyClass :: `vftable '
    00425c64 programname!MyClass :: `vftable'=
  • 次のコマンドを使用しsて、プロセスの仮想アドレス空間(この例では0〜2GB)でMyClassのvtableへのポインターを検索します。
    0:000> s -d 0 L?7fffffff 00425c64
    004010dc 00425c64 c35de58b cccccccc cccccccc d \ B...]........。
    0040113c 00425c64 8bfc458b ccc35de5 cccccccc d \ B..E...].....。
    0042b360 00425c64 00000000 00000000 00000000 d \B............。
  • コマンドを使用しdtてクラスのvtableオフセットを検索し、検索から返されたアドレスからそれを減算します。これらは、オブジェクトの可能なアドレスです。
    0:000> dtプログラム名!MyClass
       + 0x000 __VFN_table:Ptr32
       + 0x008 x:Int4B
       + 0x010 y:フロート
  • dt programname!MyClass 0042b360オブジェクトのメンバー変数を調べ、オブジェクトが0042b360(または他のアドレス)にあるという仮説をテストするために使用します。上で行ったように、おそらくいくつかの誤検知が発生しますが、メンバー変数を調べることで、どれがシングルトンであるかを判断できる場合があります。

これはC++オブジェクトを見つけるための一般的な手法であり、分解するだけではやり過ぎですMyClass::getInstance

于 2008-11-15T19:41:44.243 に答える
1

そのコードは危険に見えます... :-)

とにかく、マングル名は呼び出し規約に依存する ため、マングル名を見つける前に、ビルド環境が呼び出し規約として何を使用しているかを知る必要があります。MSDN には、呼び出し規約に関するより多くの情報があります。

これに加えて、クラスに関するこのすべての情報を見つける 1 つの方法は、オブジェクトの最初の 4 バイトにある VTable を調べることです。リバーサーが使用する気の利いたトリックは、非表示の VC++ フラグreportSingleClassLayoutで、クラス構造を ASCII アートの方法で出力します。

于 2008-11-14T02:53:54.810 に答える
1

gdb では、変数の修飾名にウォッチポイントを設定できます。

たとえば、次の関数を使用します。

int f() {
    static int xyz = 0;
    ++xyz;

    return xyz;
}

_ZZ1fvE3xyz を見ることができます (gcc 3.2.3 または gcc 4.0.1 によって破壊されたものとして)。

于 2008-11-13T21:11:55.217 に答える