转:使用IL的方式直接跟踪exception到行的方法
前言
本文介绍一种使用IL的方式直接跟踪exception到行的方法,让大家对exception不再感到恶心!特别是
System.NullReferenceException: 未将对象引用设置到对象的实例。
问题的导火线
今天在debug的时候,又出现了空指针,我这次真的火了!每次遇到空指针,.net给出的信息总是非常的少,我根本不知道是哪里Throw出来的,只能反复检查代码。
我火了!我要起义!于是,开始寻求一种能够出现exception后知道什么代码报出来的。例如以下代码:
![](/assets/blank.gif)
![](/assets/blank.gif)
{
static void Main( string [] args)
{
try
{
string hello3 = null ;
hello3 = hello3.ToUpper();
}
catch (Exception ex)
{
Console.Write(ex.ToString());
}
}
}
在release模式下,没有pdb的时候,微软给出的答案是:
在 Pixysoft.Testdriven.Consoles.Program.Main(String[] args)
我靠!鬼才知道哪里出现了空指针?我们的程序比这个复杂多了,在层层代码中、上百行的方法体内,神才知道空指针是什么地方报的。
于是我开始思考如何能够知道程序运行到什么地方出现异常。。
1. 首先是想到了aop,对方法体拦截。但是还是不能知道方法内部。
2. 然后想到了反射,问题还是同上。
3. 然后想到了StackTrace trace = new StackTrace(exception, true); 直接获取调用堆栈Frame。可是在没有pdb的时候,frame.GetFileLineNumber() 返回的是0. 傻逼了。
4. 然后想到了一个软件NCover。他就能够知道代码运行到什么阶段。于是开始查Ncover的源码。。不查不知道,一查吓一跳,原来NCover是对我们原方法进行重构,入侵了自己的计数器(c# code),然后动态编译出来的。郁闷。看来NCover要放弃了。
4. 最后,我会想起了曾经做过的IL。终于。。。看到了一丝希望:
int offset = frame.GetILOffset();
在没有pdb的时候,IL的偏移量仍然正常输出。
正文
思路大概是:
1. 获取exception的调用堆栈。
2. 获取exception相关的这个方法的方法的IL代码
3. 结合excpetion的IL偏移量和方法的IL,把调用源找出来。
代码如下:
![](/assets/blank.gif)
![](/assets/blank.gif)
{
static void Main( string [] args)
{
try
{
string hello3 = null ;
hello3 = hello3.ToUpper();
}
catch (Exception ex)
{
// 获取调用堆栈
StackTrace trace = new StackTrace(ex, true );
StackFrame frame = trace.GetFrame( 0 );
int offset = frame.GetILOffset();
byte [] il = frame.GetMethod().GetMethodBody().GetILAsByteArray();
// 获取调用指令
offset ++ ;
ushort instruction = il[offset ++ ];
// 打开潘多拉魔盒
ILGlobals global = new ILGlobals();
global .LoadOpCodes();
// 翻译
OpCode code = OpCodes.Nop;
if (instruction != 0xfe )
{
code = global .SingleByteOpCodes[( int )instruction];
}
else
{
instruction = il[offset ++ ];
code = global .MultiByteOpCodes[( int )instruction];
instruction = ( ushort )(instruction | 0xfe00 );
}
// 获取方法信息
int metadataToken = ReadInt32(il, ref offset);
MethodBase callmethod = frame.GetMethod().Module.ResolveMethod(metadataToken,
frame.GetMethod().DeclaringType.GetGenericArguments(),
frame.GetMethod().GetGenericArguments());
// 完成
Console.WriteLine(callmethod.DeclaringType + " . " + callmethod.Name);
Console.Read();
}
}
private static int ReadInt32( byte [] il, ref int position)
{
return (((il[position ++ ] | (il[position ++ ] << 8 )) | (il[position ++ ] << 0x10 )) | (il[position ++ ] << 0x18 ));
}
}
public class ILGlobals
{
private OpCode[] multiByteOpCodes;
private OpCode[] singleByteOpCodes;
/// <summary>
/// Loads the OpCodes for later use.
/// </summary>
public void LoadOpCodes()
{
singleByteOpCodes = new OpCode[ 0x100 ];
multiByteOpCodes = new OpCode[ 0x100 ];
FieldInfo[] infoArray1 = typeof (OpCodes).GetFields();
for ( int num1 = 0 ; num1 < infoArray1.Length; num1 ++ )
{
FieldInfo info1 = infoArray1[num1];
if (info1.FieldType == typeof (OpCode))
{
OpCode code1 = (OpCode)info1.GetValue( null );
ushort num2 = ( ushort )code1.Value;
if (num2 < 0x100 )
{
singleByteOpCodes[( int )num2] = code1;
}
else
{
if ((num2 & 0xff00 ) != 0xfe00 )
{
throw new Exception( " Invalid OpCode. " );
}
multiByteOpCodes[num2 & 0xff ] = code1;
}
}
}
}
/// <summary>
/// Retrieve the friendly name of a type
/// </summary>
/// <param name="typeName">
/// The complete name to the type
/// </param>
/// <returns>
/// The simplified name of the type (i.e. "int" instead f System.Int32)
/// </returns>
public static string ProcessSpecialTypes( string typeName)
{
string result = typeName;
switch (typeName)
{
case " System.string " :
case " System.String " :
case " String " :
result = " string " ; break ;
case " System.Int32 " :
case " Int " :
case " Int32 " :
result = " int " ; break ;
}
return result;
}
public OpCode[] MultiByteOpCodes
{
get { return multiByteOpCodes; }
}
public OpCode[] SingleByteOpCodes
{
get { return singleByteOpCodes; }
}
}
这样,输出的结果是:
在这里出现了空指针。
后续
看到这里,大家应该明白我为啥大骂微软了。
明明所有的信息都能够提供,都在IL里面,但是这个该死的微软就是不提供。给个exception还这么暧昧,让我们不断的浪费时间去debug。
实际上,微软的.net framework完全掌握了我们每一行代码的运行情况,内存情况。怪不得现在出了个VS2010,搞了个什么Intellitrace,所谓历史调试什么的。
希望通过这篇文章,唤醒大家,其实我们可以走的更远!
技术支持
zc22.cnblogs.com
reborn_zhang@hotmail.com
转载于:https://www.cnblogs.com/anjing/archive/2009/12/25/1632016.html
转:使用IL的方式直接跟踪exception到行的方法相关推荐
- 微软真是个十足的混蛋啊!让我们跟踪Exception到行把!(不明真相群众请入)...
前言 本文介绍一种使用IL的方式直接跟踪exception到行的方法,让大家对exception不再感到恶心!特别是 System.NullReferenceException: 未将对象引用设置到对 ...
- python PyQt5 Signal类 (Signal类提供了一种以pythonic方式声明和连接Qt信号的方法)(connect()、disconnect()、emit())
https://doc.qt.io/qtforpython/PySide2/QtCore/Signal.html?highlight=connect#PySide2.QtCore.Signal.con ...
- java post 提交数据_使用Post方式提交数据到Tomcat服务器的方法
我在上一篇文章中介绍了 使用Get方式提交数据到Tomcat服务器,这篇将介绍使用Post方式提交数据到服务器,由于Post的方式和Get方式创建Web工程是一模一样的,只用几个地方的代码不同所以,我 ...
- 中断方式下进行串口通讯的正确方法
转载:http://bbs.ednchina.com/BLOG_ARTICLE_277752.HTM 中断方式下进行串口通讯的正确方法 一般普遍的把串口通讯分为查询方式和中断方式.查询方式比较容易理解 ...
- python发送文件到服务器_python 使用poster模块进行http方式的文件传输到服务器的方法...
这几天帮内部人员做一个文件传输的小工具,要用http的方式,在用django搭建了个小框架之后,如何进行传输,特别是大文件的传输,成为主要问题.经过查资料,最后选择了通过poster这个模块来进行文件 ...
- 串口服务器工作方式及常见异常故障问题排除方法介绍
串口设备联网服务器就像一台带CPU.实时操作系统和TCP/IP协议的微型电脑,方便在串口和网络设备中传输数据.您可以在世界任何位置通过网络,用您的计算机来存取,管理和配置远程的设备.但是我们在实际使用 ...
- 点击网页跟踪php代码的工具,使用ltrace工具跟踪PHP库函数调用的方法
本文实例讲述了使用ltrace工具跟踪PHP库函数调用的方法.分享给大家供大家参考,具体如下: 可能大家已经很熟悉使用strace来跟踪系统调用,今天介绍一个跟踪库函数的利器ltrace 比如我有这么 ...
- python文件传输模块_[宜配屋]听图阁 - python 使用poster模块进行http方式的文件传输到服务器的方法...
这几天帮内部人员做一个文件传输的小工具,要用http的方式,在用django搭建了个小框架之后,如何进行传输,特别是大文件的传输,成为主要问题.经过查资料,最后选择了通过poster这个模块来进行文件 ...
- python调用http方法_python 使用poster模块进行http方式的文件传输到服务器的方法
这几天帮内部人员做一个文件传输的小工具,要用http的方式,在用django搭建了个小框架之后,如何进行传输,特别是大文件的传输,成为主要问题.经过查资料,最后选择了通过poster这个模块来进行文件 ...
最新文章
- protobuf编码
- 15年考的全国计算机应用技术,(2015年全国专业技术人员计算机应用能力考试.doc...
- 『数据库』朴实无华的数据库多表查询,连接查询、笛卡尔积
- k8s pod MySQL环境变量_Kubernetes 配置Pod和容器(一)定义容器环境变量
- C++与Java中的static成员总结
- MongoDB-与SpringBoot集成
- 《机器视觉算法与应用》第3章 机器视觉算法之光学字符识别(OCR)——学习笔记
- 网站/APP 流量分析、用户访问分析
- window新建文本快捷键
- 用js转换joson返回数据库的时间格式为/Date(*************)/
- 移动端统计分析工具Firebase、AppsFlyer、Adjust、Flurry、Tap stream、Kochava 、branch不完全对比分析
- php00截断原理,burpsuite上传截断及截断原理介绍
- vue项目性能优化(图片优化)
- Job for tomcat.service failed because the control process exited with error code 解决办法:
- 跨境电商必知的交叉销售和追加销售:2022终极指南
- 天翼云服务器挂载硬盘
- python自动填写腾讯文档_腾讯文档自动填充工具(工具),填写
- Kubernetes(k8s)集群安装(需要3台centos7)
- python电影推荐算法_基于Python的电影推荐算法
- python读取docx文件_Python读写docx文件的方法