使用.net中的用户错误报告重新生成带有行号的堆栈跟踪? [英] Recreate stack trace with line numbers from user bug-report in .net?

查看:158
本文介绍了使用.net中的用户错误报告重新生成带有行号的堆栈跟踪?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,问题:
我有几个免费项目,以及任何包含错误的软件。有些用户遇到bug时会发出一个bug堆栈跟踪报告。为了简化查找​​故障位置,我想在此堆栈中查看行号。如果应用程序没有发布.pdb文件,那么所有行信息都将丢失,因此目前我所有的部署了.pdb文件的项目,所以生成的堆栈跟踪都有这个数字。
但是!但是我不想在分发中看到这个文件,并且想要删除所有的.pdb。他们混淆用户,在安装程序中消耗空间等。

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 traces. In order to simplify finding fault place, I want to see line numbers in this stack traces. If application shipped without .pdb files, then all line information is lost, so currently all my projects deployed with .pdb files, and so generated stack traces has this numbers. But! But I do not want to see this files in distribution and want to remove all .pdb. They confuse users, consume space in installer, etc.

Delphi解决方案:
很久以前,当我是一个delphi程序员时,我使用以下技术:在异常我的应用程序走在堆栈和收集地址。然后,当我收到错误报告时,我使用一个工具,根据MY机器上收集的地址和相应的符号文件,使用函数名和行号重建有效的堆栈跟踪。

Delphi solution: Long time ago when I was a delphi programmer, I used the following technique: on exception my application walk on stack and collect addresses. Then, when I receive bug-report, I used a tool that reconstruct valid stack trace with function names and line numbers based on collected addresses and corresponding symbol files located on MY machine.

问题:
在.NET中有没有任何lib或技术或任何要做的事情?

Question: Is there any lib, or technique or whatever to do the same in .NET?

状态更新:非常有趣的是,经常提出问题是开展自己调查的最佳方式。例如,我想到这个问题一段时间,但是几天前才开始寻找答案。

Status Update: Very interesting, that often asking a question is the best way to start your own investigation. For example I think about this problem for some time, but start looking for answer only several days ago.

选项1:MiniDumps。经过很多的搜索,我找到了一种从代码创建小型转储的方法,以及如何从托管的微型转储重新创建堆栈。

Option 1: MiniDumps. After a lot googling I have found a way to create mini dump from code, and how to recreate stack from managed mini dump.

  • Redistributable assembly to create mini dump form code - clrdump
  • Blog post about using previous assembly - Creating and analyzing minidumps in .NET production applications

此解决方案需要重新分发两个额外的程序集(大小为1mb ),迷你转储占用空间,用户通过电子邮件发送不舒服。所以为了我的目的,现在是不能接受的。

This solution however need to redistribute two additional assemblies (~1mb in size), and mini dumps takes some space, and it is uncomfortable for user to send them by email. So for my purposes, right now, it is unacceptable.

选项2:感谢weiqure的线索。可以为每个堆栈帧提取管理的IL偏移量。现在的问题是如何根据这个偏移从.pdb获取行号。我发现:

Option 2: Thanks to weiqure for clue. It is possible to extract managed IL offset for every stack frame. Now the problem is how to get line numbers from .pdb based on this offsets. And what I have found:

  • PDB File Internals, just for information because:
  • ISymbolReader - managed interface to read program database files
  • And finally a tool to convert .pdb files to structured xml for easy xpath processing

使用此工具,可以为每个版本构建创建xml文件,并将其放入知识库。当用户的机器发生异常时,可以使用IL偏移创建格式化的错误消息。然后用户通过邮件发送此消息(非常小)。最后,可以创建一个简单的工具,从格式化的错误消息中重新生成结果堆栈。

Using this tool, it is possible to create xml files for every release build and put them into repositary. When exception occurs on user's machine, it is possible to create formatted error message with IL offsets. Then user send this message (very small) by mail. And finally, it is possible to create a simple tool that recreate resulting stack from formatted error message.

我只想知道为什么没有人没有实现这样的工具?我不相信这对我来说很有趣。

I only wondering why nobody else does not implement a tool like this? I don't believe that this is interesting for me only.

推荐答案

您可以从最后一个MSIL指令的偏移量使用System.Diagnostics.StackTrace的异常:

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());
}

输出:


在ConsoleApplicationN.exe.Program.Main(IL偏移量:0x7)
在ConsoleApplicationN.exe.Program.ThrowError(IL偏移量:0x1b)

在mscorlib.dll.DateTime..ctor(IL偏移量:0x9)

在mscorlib.dll.DateTime.DateToTicks(IL偏移量:0x61)

消息:年,月和日期参数描述不可表示的DateTime。

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.

然后可以使用反射器 ILSpy 解释偏移量:

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 
}

你知道0x1b之前的指令抛出异常。很容易找到C#代码:

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);

现在可以将IL代码映射到C#代码,但我认为收益会太小并且努力太大(虽然可能有一个反射器插件)。你应该对IL偏移很好。

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.

这篇关于使用.net中的用户错误报告重新生成带有行号的堆栈跟踪?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆