.NET高级调试 | 通过JIT拦截无侵入调试 C# Emit 生成的动态代码
大家还记得上一篇的测试代码吗?我们用了:
Console.WriteLine("Function Pointer: 0x{0:x16}", Marshal.GetFunctionPointerForDelegate(addDelegate).ToInt64());
来获得 委托
的 函数指针
地址,通过这个突破口最终实现了 动态代码
的调试,这种方式可以是可以,但很显然这是侵入式的,那有没有办法实现 非侵入
调试动态代码呢?在 .NET高级调试
这本书上还真给找到了,方法就是在 JIT
编译动态方法时进行拦截,获取其中的 方法描述符
。
为了方便讲解,先上测试代码:
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));//Debugger.Break();//Console.WriteLine("Function Pointer: 0x{0:x16}", Marshal.GetFunctionPointerForDelegate(addDelegate).ToInt64());Console.WriteLine(addDelegate(10, 20));}}
可以看到,我把上面两行侵入式的代码给屏蔽掉了,接下来在 il.Emit(OpCodes.Ret);
处下断点,目的是为了在 clr 加载后寻找 JIT的 compileMethod
方法。
0:000> !mbp Program.cs 28
The CLR has not yet been initialized in the process.
Breakpoint resolution will be attempted when the CLR is initialized.
0:000> g
ModLoad: 76910000 7698a000 C:\Windows\SysWOW64\ADVAPI32.dll
...
ModLoad: 77190000 77226000 C:\Windows\SysWOW64\OLEAUT32.dll
Breakpoint: JIT notification received for method ConsoleApp1.Program.Main(System.String[]) in AppDomain 00783758.
Breakpoint set at ConsoleApp1.Program.Main(System.String[]) in AppDomain 00783758.
Breakpoint 1 hit
eax=00000001 ebx=0019f5ac ecx=023c3684 edx=ffffffff esi=023c230c edi=0019f4fc
eip=048a0a02 esp=0019f4ac ebp=0019f508 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
048a0a02 b901000000 mov ecx,1
接下来可以用 x 命令模糊搜索 compileMethod
签名,找出签名是为了更好的下断点。
0:000> x *!*compileMethod*
...
61413700 clrjit!CILJit::compileMethod (class ICorJitInfo *, struct CORINFO_METHOD_INFO *, unsigned int, unsigned char **, unsigned long *)
可以看到 compileMethod
的完整签名是 clrjit!CILJit::compileMethod
, 并且它的方法入口点地址是 61413700
,有了它就可以对其下断点啦!
0:000> bp 61413700
0:000> g
Breakpoint 0 hit
eax=61494698 ebx=80000004 ecx=61413700 edx=00005c10 esi=6148b3fc edi=0019efa4
eip=61413700 esp=0019ede0 ebp=0019ee38 iopl=0 nv up ei ng nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000282
clrjit!CILJit::compileMethod:
61413700 55 push ebp
0:000> kb# ChildEBP RetAddr Args to Child
00 0019ee38 62a4ccc3 61494698 0019efa4 0019ef1c clrjit!CILJit::compileMethod [f:\dd\ndp\clr\src\jit32\ee_il_dll.cpp @ 151]
01 0019ee38 62a4cd9b 0019ef1c 0019f06c 0019f024 clr!invokeCompileMethodHelper+0x10b
很开心,成功命中,接下来提取 compileMethod
方法的第三个参数,它就是需要编译方法所指向的 方法描述符
地址,可以用 dp
给提取出来。
0:000> dp 0019ef1c L1
0019ef1c 0071537c
0:000> !dumpmd 0071537c
Method Name: DynamicClass.Add(Int32, Int32)
Class: 007152e8
MethodTable: 0071533c
mdToken: 06000000
Module: 00714ea8
IsJitted: no
CodeAddr: ffffffff
Transparency: Transparent
方法描述符果然给调出来了,但这里的方法字节码是 CodeAddr: ffffffff
,说明此时动态方法
还没有开始编译,为了能够使其编译,我们在 Console.WriteLine(addDelegate(10, 20));
处再下一个断点,因为代码到此处时, JIT 肯定编译了该办法,自然就能看到编译后的 CodeAddr
地址。
0:000> !mbp Program.cs 35
Breakpoint set at ConsoleApp1.Program.Main(System.String[]) in AppDomain 00783758.
0:000> g
Breakpoint 3 hit
eax=023c5f88 ebx=0019f5ac ecx=023c5f3c edx=00008f17 esi=023c230c edi=0019f4fc
eip=048a0a9b esp=0019f4ac ebp=0019f508 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
048a0a9b 6a14 push 14h
0:000> !dumpmd 0071537c
Method Name: DynamicClass.Add(Int32, Int32)
Class: 007152e8
MethodTable: 0071533c
mdToken: 06000000
Module: 00714ea8
IsJitted: yes
CodeAddr: 04a00050
Transparency: Transparent
可以看到,此时的 CodeAddr: 04a00050
,也就表明已经编译完成了,接下来继续 bp 。
0:000> bp 04a00050
0:000> g
Breakpoint 4 hit
eax=023c5f98 ebx=0019f5ac ecx=0000000a edx=00000014 esi=023c230c edi=0019f4fc
eip=04a00050 esp=0019f4a8 ebp=0019f508 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
04a00050 8bc1 mov eax,ecx
可以看到,全部搞定,非侵入式,
.NET高级调试 | 通过JIT拦截无侵入调试 C# Emit 生成的动态代码相关推荐
- 微服务应用性能分析实战11 资源节点树:通过 Sentinel 无侵入实现流量链生成规则
前两个课时,我们重点围绕 SkyWalking 进行了原理解析.讲完了 SkyWalking,接下来我们就进入 Sentinel. 这一讲开始,我将用两个课时围绕 Sentinel 的技术骨架展开,来 ...
- Spring Boot 无侵入式 实现 API 接口统一 JSON 格式返回
点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 无侵入式 统一返回JSON格式 其实本没有没打算写这篇博客 ...
- JAVA服务治理实践之无侵入的应用服务监控--转
原文地址:http://chuansong.me/n/603660351655 之前在分享微智能的话题中提到了应用服务监控,本文将会着重介绍Java环境下如何实现无侵入的监控,以及无侵入模式对实现各种 ...
- 基于WASM的无侵入式全链路A/B Test实践
简介:我们都知道,服务网格(ServiceMesh)可以为运行其上的微服务提供无侵入式的流量治理能力.通过配置VirtualService和DestinationRule,即可实现流量管理.超时重试. ...
- Spring Boot 无侵入式 实现API接口统一JSON格式返回
作者 | 小魏小魏我们去那里呀 来源 | blog.csdn.net/qq_34347620/article/details/102239179 无侵入式 统一返回JSON格式 其实本没有没打算写这篇 ...
- spring学习笔记(14)引介增强详解:定时器实例:无侵入式动态增强类功能
引介增强实例需求 在前面我们已经提到了前置.后置.环绕.最终.异常等增强形式,它们的增强对象都是针对方法级别的,而引介增强,则是对类级别的增强,我们可以通过引介增强为目标类添加新的属性和方法,更为诱人 ...
- Dexposed:Android平台免Root无侵入AOP框架
本文来自阿里巴巴技术协会(ATA) 本文首发于 http://www.infoq.com/cn/news/2015/07/dexposed 近日,阿里巴巴无线事业部推出首个重量级Android开源项目 ...
- Android新技术学习——阿里巴巴免Root无侵入AOP框架Dexposed
阿里巴巴无线事业部近期开源的Android平台下的无侵入运行期AOP框架Dexposed,该框架基于AOP思想,支持经典的AOP使用场景.可应用于日志记录,性能统计,安全控制.事务处理.异常处理等方面 ...
- delphi ui编辑工具源码_一种无侵入比swagger-ui兼容性更好更简单的API文档生成方案
在后端项目中,难免遇到需要写接口文档方便第三方调用的场景,一般业界最常用的方案是使用swagger.Java项目中,一般采用springfox项目,它集成了swagger和swagger-ui,不需要 ...
最新文章
- 网游运营基础知识与专业术语
- input border IE6 bug
- 「JOISC 2020 Day4」治疗计划(线段树+dijkstra最短路)
- RuntimeError: DataLoader worker (pid(s) 13512, 280, 21040) exited unexpectedly
- 在res/values下创建attrs.xml
- spi app理解和编写测试
- 从C语言到C++的进阶之C到C++的转变(篇一)
- 基于visual Studio2013解决C语言竞赛题之1071打印工资
- Linux系统服务及其创建详解(service/chkconfig)
- 【缺陷识别】基于matlab GUI SVM金属表面缺陷分类与测量(带面板)【含Matlab源码 1652期】
- Mac UE各版本破解方法
- 欧氏空间距离和内积_希尔伯特空间(Hilbert Space)
- 如何使用IconFont?——矢量图标
- 北京计算机专业考研录取分数线,2018北京航空航天大学计算机考研复试分数线_计算机考研分数线...
- python-opencv第四期:threshold函数详解
- app 显示未验证应用解决
- linux 运行有道词典,Ubuntu中使用有道词典
- PLC-Recorder常用授权功能详解
- Java实现蓝桥杯二项式的系数规律
- 继续BT的研究-第二部份关于BT中的tracker
热门文章
- spring mvc 入门配置
- 在Centos中yum安装和卸载软件的使用方法
- 标准MD5 .Net,实现!的对与错!
- qemu+linux+x86+64,kvm 内部错误:无法找到适合 x86_64 的模拟器
- 基于.NET2.0的System.Net.Mail发送邮件Demo
- 用了30天整理的一些GO语言学习资料,2019请你加油
- [Swift]LeetCode1013. 将数组分成和相等的三个部分 | Partition Array Into Three Parts With Equal Sum...
- Visual Studio 2019 preview中体验C# 8.0新语法
- PHP 多维数组转json对象
- Windows下怎样安装Tomcat