Recreate stack trace with line numbers from user bug-report in .net?

后端 未结 4 1040
旧巷少年郎
旧巷少年郎 2021-01-30 15:25

First, the problem: I have several free projects, and as any software they contains bugs. Some fellow users when encounter bug send me a bug-reports with stack

4条回答
  •  北荒
    北荒 (楼主)
    2021-01-30 15:54

    You can get the offset of the last MSIL instruction from the Exception using System.Diagnostics.StackTrace:

    // Using System.Diagnostics
    static void Main(string[] args)
    {
        try { ThrowError(); }
        catch (Exception e)
        {
            StackTrace st = new System.Diagnostics.StackTrace(e);
            string stackTrace = "";
            foreach (StackFrame frame in st.GetFrames())
            {
                stackTrace = "at " + frame.GetMethod().Module.Name + "." + 
                    frame.GetMethod().ReflectedType.Name + "." 
                    + frame.GetMethod().Name 
                    + "  (IL offset: 0x" + frame.GetILOffset().ToString("x") + ")\n" + stackTrace;
            }
            Console.Write(stackTrace);
            Console.WriteLine("Message: " + e.Message);
        }
        Console.ReadLine();
    }
    
    static void ThrowError()
    {
        DateTime myDateTime = new DateTime();
        myDateTime = new DateTime(2000, 5555555, 1); // won't work
        Console.WriteLine(myDateTime.ToString());
    }
    

    Output:

    at ConsoleApplicationN.exe.Program.Main (IL offset: 0x7)
    at ConsoleApplicationN.exe.Program.ThrowError (IL offset: 0x1b)
    at mscorlib.dll.DateTime..ctor (IL offset: 0x9)
    at mscorlib.dll.DateTime.DateToTicks (IL offset: 0x61)
    Message: Year, Month, and Day parameters describe an un-representable DateTime.

    You can then use Reflector or ILSpy to interpret the offset:

    .method private hidebysig static void ThrowError() cil managed
    {
        .maxstack 4
        .locals init (
            [0] valuetype [mscorlib]System.DateTime myDateTime)
        L_0000: nop 
        L_0001: ldloca.s myDateTime
        L_0003: initobj [mscorlib]System.DateTime
        L_0009: ldloca.s myDateTime
        L_000b: ldc.i4 0x7d0
        L_0010: ldc.i4 0x54c563
        L_0015: ldc.i4.1 
        L_0016: call instance void [mscorlib]System.DateTime::.ctor(int32, int32, int32)
        L_001b: nop 
        L_001c: ldloca.s myDateTime
        L_001e: constrained [mscorlib]System.DateTime
        L_0024: callvirt instance string [mscorlib]System.Object::ToString()
        L_0029: call void [mscorlib]System.Console::WriteLine(string)
        L_002e: nop 
        L_002f: ret 
    }
    

    You know that the instruction before 0x1b threw the exception. It's easy to find the C# code for that:

     myDateTime = new DateTime(2000, 5555555, 1);
    

    You could map the IL code to your C# code now, but I think the gain would be too little and the effort too big (though there might be a reflector plugin). You should be fine with the IL offset.

提交回复
热议问题