Как разбить WinDbg анонимным методом? - PullRequest
8 голосов
/ 12 марта 2010

Название вроде говорит само за себя. Обычная команда SOS ! Bpmd не приносит пользы без имени.

Некоторые идеи у меня были:

  • сбросьте каждый метод, затем используйте ! Bpmd -md , когда вы найдете соответствующий MethodDesc
    • не практично в реальном мире, насколько я могу судить. Даже если бы я написал макрос, чтобы ограничить дамп анонимными типами / методами, нет очевидного способа отличить их.
  • используйте Reflector для вывода имени MSIL
    • не помогает при работе с динамическими сборками и / или Reflection.Emit. Неспособность Visual Studio читать локальные переменные внутри таких сценариев - это единственная причина, по которой я в первую очередь обратился к Windbg ...
  • установить точку останова в VS, подождать, пока она не достигнет, затем изменить на Windbg, используя неинвазивный трюк
  • установить точку останова в каком-либо другом месте, известном как вызов анонимного метода, а затем пошагово пройти
    • мой план резервного копирования, хотя я бы не стал прибегать к нему, если этот Q & A покажет лучший способ

Ответы [ 3 ]

9 голосов
/ 12 марта 2010

Анонимный метод на самом деле не анонимный. Он просто прячется за именем, сгенерированным компилятором.

Рассмотрим небольшой пример:

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.

0 голосов
/ 09 декабря 2012

Дамп дескриптор метода, на который указывает действие. Направления здесь .

0 голосов
/ 12 марта 2010

Если найти имя «<> ....» сложно для вашего сценария, как насчет сделать его обычным методом? Это обычно очень просто; Единственная сложность - это захваченные переменные, но это не так уж плохо - например, они делают то же самое:

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