首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在.net中用用户错误报告中的行号重新创建堆栈跟踪?

在.net中用用户错误报告中的行号重新创建堆栈跟踪?
EN

Stack Overflow用户
提问于 2009-06-24 12:01:32
回答 4查看 6.7K关注 0票数 16

首先,问题是:我有几个免费的项目,而且作为任何软件,它们都包含bug。一些其他用户遇到bug时,会给我发送带有堆栈跟踪的bug报告。为了简化故障位置的查找,我希望在这个堆栈跟踪中看到行号。如果应用程序没有.pdb文件,那么所有的行信息都丢失了,所以目前我所有的项目都部署在.pdb文件中,所以生成的堆栈跟踪都有这个编号。但!但是我不希望看到这个文件在发行版中,并且希望删除所有的.pdb。它们混淆了用户,占用了安装程序中的空间等。

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

问题:在.NET中是否有任何库、技术或其他方法来做同样的事情?

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

选项1: MiniDumps。在大量搜索之后,我找到了一种从代码创建迷你转储的方法,以及如何从托管的迷你转储重新创建堆栈。

  • 可再发行程序集以创建小型转储表单代码- 克雷转储
  • 关于使用以前的程序集- 在.NET生产应用程序中创建和分析微型转储的博客文章

然而,这个解决方案需要重新分发两个额外的程序集(~1mb的大小),微型转储占用了一些空间,用户通过电子邮件发送它们是不舒服的。所以就我而言,现在,这是不可接受的。

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

  • PDB文件内部,只是为了获取信息,因为:
  • 读取程序数据库文件的ISymbolReader托管接口
  • 最后是一个易于xpath处理的将.pdb文件转换为结构化xml的工具

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

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

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2009-06-24 13:25:56

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

代码语言:javascript
运行
复制
// 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) at ConsoleApplicationN.exe.Program.ThrowError (IL偏移量: 0x1b) 在mscorlib.dll.DateTime..ctor (IL偏移量: 0x9) 在mscorlib.dll.DateTime.DateToTicks (IL偏移: 0x61) 消息:年、月和日参数描述一个无法表示的DateTime。

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

代码语言:javascript
运行
复制
.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#代码:

代码语言:javascript
运行
复制
 myDateTime = new DateTime(2000, 5555555, 1);

您现在可以将IL代码映射到您的C#代码,但我认为增益太小,工作量太大(尽管可能有一个反射器插件)。你应该对IL偏移没什么意见。

票数 16
EN

Stack Overflow用户

发布于 2009-06-24 12:45:22

您应该使用Environment.FailFast,在Application.UnhandledException中调用FailFast,然后为您创建一个转储文件。

来自MSDN:

FailFast方法使用消息参数将日志条目写入日志,创建应用程序的转储,然后终止当前进程。 如果应用程序的状态损坏无法修复,则使用FailFast方法而不是Exit方法终止应用程序,并且执行应用程序的尝试--最终块和终结器将破坏程序资源。FailFast方法终止当前进程并执行任何CriticalFinalizerObject对象,但不执行任何活动的尝试-最终块或终结器。

您可以编写一个简单的应用程序来收集日志文件并将它们发送给您。

现在,打开转储文件有点棘手,Visual无法处理托管转储文件(固定在.NET 4.0中)--您可以使用WinDBG,但需要使用SOS

票数 5
EN

Stack Overflow用户

发布于 2009-06-24 12:38:49

当有bug时,您可以创建一个应用程序minidump,并使用它进行脱机分析。这不要求您在客户端计算机上部署pdbs。链接可以作为学习的良好起点。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1037925

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档