成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

如何調試 C# Emit 生成的動態代碼?

開發 前端
這是一個動態生成的 Add(int a,int b) 方法,那如何調試它的方法體呢?這里有兩個技巧。第一:使用 Debugger.Break();? 這個語句可以通知附加到該進程的 Debugger 中斷,也就是 Windbg。第二:使用 Marshal.GetFunctionPointerForDelegate? 獲取 委托方法 的函數指針地址。

首先聲明一下,這是一個很深的話題,也是朋友真實遇到的,它用 DynamicMethod + ILGenerator 生成了很多動態方法,然而這動態方法中有時候經常會遇到溢出異常,尋求如何調試 動態方法體,我知道如果用 visual studio 來調試的話,我個人覺得很難,這時候只能用 windbg 了,接下來我聊一下具體調試步驟。

1. 測試代碼

為了方便講解,上一段測試代碼。

class Program
    {
        private delegate int AddDelegate(int a, int b);

        static void Main(string[] args)
        {
            var dynamicAdd = new DynamicMethod("Add", typeof(int), new[] { typeof(int), typeof(int) }, true);
            var il = dynamicAdd.GetILGenerator();
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldarg_1);
            il.Emit(OpCodes.Add);
            il.Emit(OpCodes.Ret);

            var addDelegate = (AddDelegate)dynamicAdd.CreateDelegate(typeof(AddDelegate));

            Console.WriteLine(addDelegate(10, 20));
        }
    }

這是一個動態生成的 Add(int a,int b) 方法,那如何調試它的方法體呢?這里有兩個技巧。

第一:使用 Debugger.Break(); 這個語句可以通知附加到該進程的 Debugger 中斷,也就是 Windbg。

第二:使用 Marshal.GetFunctionPointerForDelegate 獲取 委托方法 的函數指針地址。

基于上面兩點,修改代碼如下:

static void Main(string[] args)
        {
            var dynamicAdd = new DynamicMethod("Add", typeof(int), new[] { typeof(int), typeof(int) }, true);
            var il = dynamicAdd.GetILGenerator();
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldarg_1);
            il.Emit(OpCodes.Add);
            il.Emit(OpCodes.Ret);

            var addDelegate = (AddDelegate)dynamicAdd.CreateDelegate(typeof(AddDelegate));
            Console.WriteLine("Function Pointer: 0x{0:x16}", Marshal.GetFunctionPointerForDelegate(addDelegate).ToInt64());

            Debugger.Break();

            Console.WriteLine(addDelegate(10, 20));
        }

接下來可以用 windbg 把 exe 程序啟動起來,可以看到console上的輸出如下:

圖片圖片

2. 尋找 codeheap 上的方法體字節碼

接下來我們反編譯下 0x00000000023d062e 這個函數指針。

0:000> !U 0x00000000023d062e
Unmanaged code
023d062e b818063d02      mov     eax,23D0618h
023d0633 e9e4c934fe      jmp     0071d01c
023d0638 ab              stos    dword ptr es:[edi]
023d0639 ab              stos    dword ptr es:[edi]
023d063a ab              stos    dword ptr es:[edi]
023d063b ab              stos    dword ptr es:[edi]
023d063c ab              stos    dword ptr es:[edi]
023d063d ab              stos    dword ptr es:[edi]
023d063e ab              stos    dword ptr es:[edi]
023d063f ab              stos    dword ptr es:[edi]

上面的 23D0618h 才是最后真實的 動態方法 指針地址,接下來我們用 dp 看看指針上的值。

0:000> dp 23D0618h L1
023d0618  00a90050

接下來我們反編譯下 00a90050 地址看看方法體的匯編代碼。

0:000> !U 00a90050
Normal JIT generated code
DynamicClass.Add(Int32, Int32)
Begin 00a90050, size 5
>>> 00a90050 8bc1            mov     eax,ecx
00a90052 03c2            add     eax,edx
00a90054 c3              ret

接下來有兩條路:

  • 熟路模式

使用非托管命令 bp 00a90050  直接下斷點調試。

  • 困難模式

使用托管命令 !bpmd xxx 尋找方法描述符下斷點調試。

這里我就選擇 困難模式 來處理。

3. 使用 bpmd 下斷點

要用 !bpmd 下斷點,必須要有 方法描述符, 現在我們有了 codeaddr 如何反向找描述符呢?這里可用 !mln。

0:000> !mln 00a90050
Method instance: (BEGIN=00a90050)(MD=0071537c disassemble)[DynamicClass.Add(Int32, Int32)]

上面輸出的 MD=0071537c 就是方法描述符的地址,接下來就可以用 !bpmd -md 0071537c 設置斷點即可。

0:000> !bpmd -md 0071537c
MethodDesc = 0071537c
Setting breakpoint: bp 00A90050 [DynamicClass.Add(Int32, Int32)]
0:000> g
Breakpoint 0 hit
eax=02505fe8 ebx=0019f5ac ecx=0000000a edx=00000014 esi=0250230c edi=0019f4fc
eip=00a90050 esp=0019f488 ebp=0019f508 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
00a90050 8bc1            mov     eax,ecx

從輸出看,已經成功命中斷點,而且 clr 也幫我自動轉接到了 bp 00A90050,接下來看下命中的斷點圖:

圖片圖片

上面的二條匯編指令就是 a+b 的結果,也就是 ecx 放了 a, edx 放了 b,不信的話可以 step 二次。

0:000> t
eax=0000000a ebx=0019f5ac ecx=0000000a edx=00000014 esi=0250230c edi=0019f4fc
eip=00a90052 esp=0019f488 ebp=0019f508 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
00a90052 03c2            add     eax,edx
0:000> t
eax=0000001e ebx=0019f5ac ecx=0000000a edx=00000014 esi=0250230c edi=0019f4fc
eip=00a90054 esp=0019f488 ebp=0019f508 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
00a90054 c3              ret

這里的 ecx=0000000a edx=00000014 便是。

責任編輯:武曉燕 來源: 一線碼農聊技術
相關推薦

2024-03-06 08:52:59

C#Emit代碼

2009-09-14 13:57:20

C# Lambda表達Lambda表達式

2009-04-03 10:25:32

C#XML擴展代碼

2024-10-11 14:42:59

2009-09-02 10:58:02

C#動態數組

2009-08-18 13:35:08

C#動態生成Word文

2009-08-24 15:58:00

Visual C#生成

2009-03-12 13:49:30

DataTemplatWPFC#

2009-08-04 13:31:35

C#自定義事件

2009-08-25 15:58:03

C#跟蹤和調試語句

2009-09-17 18:07:22

C#動態數組

2009-09-02 11:02:57

C#動態數組

2009-08-19 15:38:59

C#代碼

2009-08-27 16:29:18

C#動態編譯

2009-09-17 18:14:05

C#動態數組

2009-09-17 17:40:36

C#動態數組

2009-09-17 17:44:51

C#動態數組

2010-11-08 10:20:18

2009-09-02 11:18:10

C#動態數組

2009-01-19 10:03:58

C#XML動態分層菜單
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产美女永久免费无遮挡 | 精品一区二区三区在线观看 | 久久国产一区二区 | 欧美精品片 | 狠狠视频 | 91在线成人 | 91新视频 | 精品国产99| 日韩在线国产 | 欧美激情一区 | a级大片 | 国产精品久久久久久一区二区三区 | 国产精品欧美日韩 | 免费看国产片在线观看 | 91av久久久 | 国产精品日韩一区二区 | 亚洲成人精品 | 国产精品99久久久精品免费观看 | 81精品国产乱码久久久久久 | 欧美激情久久久 | 亚洲精品日本 | 中文字幕蜜臀av | 国产电影一区二区在线观看 | 亚洲高清在线 | 国产成人99久久亚洲综合精品 | 精品成人佐山爱一区二区 | 日韩精品专区在线影院重磅 | 毛片综合| 久久狠狠| 欧美日日日日bbbbb视频 | 欧美视频一区 | 全部免费毛片在线播放网站 | 日韩一区av| 99tv成人影院 | 免费永久av| 国产福利在线播放 | 欧美日韩在线一区二区 | 伊人网在线播放 | 狠狠亚洲 | 国产免费播放视频 | 久久小视频 |