从用户错误报告的.NET创建具有行号的堆栈跟踪? [英] Recreate stack trace with line numbers from user bug-report in .net?

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

问题描述

一,问题: 我有一些免费的项目,任何软件,它们包含错误。一些老乡用户时遇到的错误给我的一个错误,报告与堆栈跟踪。为了简化找茬的地方,我想看看行号在这个堆栈跟踪。如果应用程序没有运.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 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.

问: 是否有任何lib或技术或任何在.NET做?

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:小型转储。很多谷歌上搜索后,我已经找到一种方法来创建code小型转储,以及如何重新创建管理的小型转储堆栈。

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.

  • 可再发行组件创建小型转储形式code - clrdump
  • 在博客有关使用previous组装后 - <一个href="http://voneinem-windbg.blogspot.com/2007/03/creating-and-analyzing-minidumps-in-net.html">Creating而在.NET生产应用分析小型转储
  • 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文件,每一个发布版本,并付诸repositary。当异常的用户的机器发生时,有可能创建格式化的错误信息与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.

推荐答案

使用System.Diagnostics.StackTrace除了最后MSIL指令就可以得到补偿:

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)
  消息:年,月,日和参数描述了一个未再presentable日期时间。

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 间preT偏移:

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#code为:

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 code到C#code现在,但我认为增益将是太少,努力过大(虽然有可能是一个反射器插件)。你应该罚款与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天全站免登陆