8

タイトルはちょっとそれをすべて言います。通常のSOSコマンド!bpmdは、名前がないとあまり効果がありません。

私が持っていたいくつかのアイデア:

  • すべてのメソッドをダンプし、対応するMethodDescが見つかったら !bpmd-mdを使用します
    • 私の知る限り、実際の使用法では実用的ではありません。ダンプを匿名の型/メソッドに制限するマクロを作成したとしても、それらを区別する明確な方法はありません。
  • リフレクターを使用してMSIL名をダンプします
    • 動的アセンブリやReflection.Emitを処理する場合は役に立ちません。Visual Studioがそのようなシナリオ内でローカル変数を読み取れないことが、私が最初にWindbgに目を向けた理由です...
  • VSにブレークポイントを設定し、ヒットするのを待ってから、非侵襲的なトリックを使用してWindbgに変更します
  • 匿名メソッドを呼び出すことがわかっている他の場所にブレークポイントを設定してから、シングルステップで
    • 私のバックアップ計画ですが、このQ&Aでより良い方法が明らかになった場合は、それに頼りたくありません。
4

3 に答える 3

9

匿名メソッドは実際には匿名ではありません。コンパイラが生成した名前の後ろに隠れているだけです。

この小さな例を考えてみましょう。

Func<int, int> a = (x) => x + 1;

Console.WriteLine(a.Invoke(1));

戻り値を見つけるには、メソッド実装の名前を見つける必要があります。そのためには、周囲のメソッドのMethodDescを見つける必要があります。この例ではMain()、次のようになります。

0:000> !name2ee * TestBench.Program.Main
Module: 6db11000 (mscorlib.dll)
--------------------------------------
Module: 00162c5c (TestBench.exe)
Token: 0x06000001
MethodDesc: 00163010
Name: TestBench.Program.Main()
JITTED Code Address: 001e0070

MethodDescを介して、次のILをダンプできます。Main()

0:000> !dumpil 00163010
ilAddr = 003f2068
IL_0000: nop 
IL_0001: ldstr "press enter"
IL_0006: call System.Console::WriteLine     
IL_000b: nop 
IL_000c: call System.Console::ReadLine 
IL_0011: pop 
IL_0012: ldsfld TestBench.Program::CS$<>9__CachedAnonymousMethodDelegate1
IL_0017: brtrue.s IL_002c
IL_0019: ldnull 
IL_001a: ldftn TestBench.Program::<Main>b__0
IL_0020: newobj class [System.Core]System.Func`2<int32,int32>::.ctor 
IL_0025: stsfld TestBench.Program::CS$<>9__CachedAnonymousMethodDelegate1
IL_002a: br.s IL_002c
IL_002c: ldsfld TestBench.Program::CS$<>9__CachedAnonymousMethodDelegate1
IL_0031: stloc.0 
IL_0032: ldloc.0 
IL_0033: ldc.i4.1 
IL_0034: callvirt class [System.Core]System.Func`2<int32,int32>::Invoke 
IL_0039: call System.Console::WriteLine 
IL_003e: nop 
IL_003f: ret 

変な格好の名前に注目してください。これらは、生成デリゲートタイプと実際のメソッドの名前です。このメソッドはと呼ばれ<Main>b__0ます。メソッドを見てみましょう:

0:000> !name2ee * TestBench.Program.<Main>b__0
Module: 6db11000 (mscorlib.dll)
--------------------------------------
Module: 00152c5c (TestBench.exe)
Token: 0x06000003
MethodDesc: 00153024
Name: TestBench.Program.<Main>b__0(Int32)
Not JITTED yet. Use !bpmd -md 00153024 to break on run. 

そこにあります。MethodDescは00153024であり、コメントにあるように、!bpmdを使用して、MethodDescを使用してブレークポイントを設定できます。

于 2010-03-12T07:07:01.523 に答える
0

「<>....」という名前を見つけるのが難しい場合は、通常の方法にしてみてはどうでしょうか。これは通常、非常に簡単です。唯一注意が必要なのはキャプチャされた変数ですが、それはそれほど悪くはありません。たとえば、これらは同じことを行います。

    static void Main()
    {
        List<int> list = new List<int> { 1, 2, 3, 4, 5 };
        int div = 2;
        foreach (var item in list.Where(x => x % div == 0))
        {
            Console.WriteLine(item);
        }

        ListSearcher ls = new ListSearcher();
        ls.div = 2;
        foreach (var item in list.Where(ls.Test))
        {
            Console.WriteLine(item);
        }
    }
    class ListSearcher
    {
        public int div;
        public bool Test(int x)
        {
            return x % div == 0;
        }
    }
于 2010-03-12T07:08:05.607 に答える
0

アクションが指すメソッド記述子をダンプします。ここへの道順。

于 2012-12-09T14:52:13.363 に答える