调试空指针错误

本文介绍了一种通过分析异常调用堆栈和中间语言(IL)代码来精确定位异常源头的方法。具体步骤包括获取异常堆栈跟踪、提取IL代码及偏移量,并通过解析指令码来追溯引发异常的具体操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

思路大概是:

1. 获取exception的调用堆栈。

2. 获取exception相关的这个方法的方法的IL代码

3. 结合excpetion的IL偏移量和方法的IL,把调用源找出来。

代码
    class Program
    {
        
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; }
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值