在我的应用程序中生成/创建mdump文件

问题描述:

我正在寻找一种方法来在我的应用程序中生成小型转储文件,类似于ProcDump所做的,但是优先使用代码并且不必提取3dparty工具来执行此操作。在我的应用程序中生成/创建mdump文件

的主要原因不想使用ProcDump是:
1)的二进制文件的大小会大大增加(这是一个问题,因为我的应用程序是免费的,而带宽是不是免费的)。
2)感觉脏。
3)没有办法,我可以移植该应用程序来运行旅馆的Windows Mobile。

我的要求是:
1)能够在fatale崩溃中生成mdump文件。
2)有能力做“暂停”应用做转储,contiune将是一个奖金

如果这不是一个真正的选项,有没有办法在当前上下文中动态获取本地变量的值?

附注: 我did fin这篇文章,但它的非常老,所以我很犹豫,根据我的工作。
似乎要么是与IE 9或与网站的问题,所以我有问题与标签。

+0

关于这个问题的任何最终很好的解决方案?在.NET中有很好的示例应用程序源代码? – Kiquenet 2011-09-05 11:05:48

所以有想到的,并符合下列目标之一的解决方案:

  • 的二进制文件的大小将左右300K
  • 能够生成mdump文件在一个荡妇崩溃增加。
  • 能力做“暂停”的应用做了转储和contiune将是一个奖金

我给这要求一个完整的未知:

  • 没办法我只能端口应用运行旅馆的Windows Mobile。

那么有什么解决方案?

从Microsoft Sample for MDbg集成所需的所需部件。exe为您提供一个“即时”调试器,用于附加,转储和分离崩溃过程。

第1步 - 从这里下载源代码到MDBG开始:http://www.microsoft.com/downloads/en/details.aspx?FamilyID=38449a42-6b7a-4e28-80ce-c55645ab1310&DisplayLang=en

2步 - 创建一个“撞车”处理程序,生成一个调试的过程,并等待完成。我使用以下几行代码重新启动同一个exe文件,并添加一些额外的参数来调用调试器,并将xml文件输出到std :: out。

string tempFile = Path.GetTempFileName(); 
Mutex handle = new Mutex(true, typeof(Program).Namespace + "-self-debugging"); 
try 
{ 
    Process pDebug = Process.Start(typeof(Program).Assembly.Location, 
     "debug-dump " + Process.GetCurrentProcess().Id + " " + tempFile); 
    if (pDebug != null) 
     pDebug.WaitForExit(); 
} 
catch { } 
finally 
{ 
    handle.ReleaseMutex(); 
} 

Console.WriteLine(File.ReadAllText(tempFile)); 

第3步 - 编写调试转储例程,这可以在同一个exe或不同的exe中。您需要从样本中引用(或包含来源)'raw','corapi'和'mdbgeng'模块。然后添加几行到您的Main():

public static void Main(string[] args) 
{ 
    if (args.Length > 0 && args[0] == "debug-dump") 
    { //debug-dump process by id = args[1], output = args[2] 
     using (XmlTextWriter wtr = new XmlTextWriter(args[2], Encoding.ASCII)) 
     { 
      wtr.Formatting = Formatting.Indented; 
      PerformDebugDump(Int32.Parse(args[1]), wtr); 
     } 
     return; 
    } 
    //... continue normal program execution 
} 

static void PerformDebugDump(int process, XmlWriter x) 
{ 
    x.WriteStartElement("process"); 
    x.WriteAttributeString("id", process.ToString()); 
    x.WriteAttributeString("time", XmlConvert.ToString(DateTime.Now, XmlDateTimeSerializationMode.RoundtripKind)); 

    MDbgEngine e = new MDbgEngine(); 
    MDbgProcess me = e.Attach(process); 
    me.Go().WaitOne(); 

    try 
    { 
     x.WriteStartElement("modules"); 
     foreach (MDbgModule mod in me.Modules) 
      x.WriteElementString("module", mod.CorModule.Name); 
     x.WriteEndElement(); 

     foreach (MDbgThread thread in me.Threads) 
     { 
      x.WriteStartElement("thread"); 
      x.WriteAttributeString("id", thread.Id.ToString()); 
      x.WriteAttributeString("number", thread.Number.ToString()); 
      int ixstack = -1; 

      foreach (MDbgFrame frame in thread.Frames) 
      { 
       x.WriteStartElement("frame"); 
       x.WriteAttributeString("ix", (++ixstack).ToString()); 
       x.WriteAttributeString("loc", frame.ToString(String.Empty)); 
       string valueText = null; 

       x.WriteStartElement("args"); 
       try 
       { 
        foreach (MDbgValue value in frame.Function.GetArguments(frame)) 
        { 
         x.WriteStartElement(value.Name); 
         x.WriteAttributeString("type", value.TypeName); 
         try { x.WriteAttributeString("value", value.GetStringValue(1, false)); } 
         finally { x.WriteEndElement(); } 
        } 
       } 
       catch { } 
       x.WriteEndElement(); 

       x.WriteStartElement("locals"); 
       try 
       { 
        foreach (MDbgValue value in frame.Function.GetActiveLocalVars(frame)) 
        { 
         x.WriteStartElement(value.Name); 
         x.WriteAttributeString("type", value.TypeName); 
         try { x.WriteAttributeString("value", value.GetStringValue(1, false)); } 
         finally { x.WriteEndElement(); } 
        } 
       } 
       catch { } 
       x.WriteEndElement(); 
       x.WriteEndElement(); 
      } 
      x.WriteEndElement(); 
     } 
    } 
    finally 
    { 
     me.Detach().WaitOne(); 
    } 

    x.WriteEndElement(); 
} 

示例输出

<process id="8276" time="2010-10-18T16:03:59.3781465-05:00"> 
<modules> 
<module>C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll</module> 
...etc 
</modules> 
<thread id="17208" number="0"> 
<frame ix="0" loc="System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop (source line information unavailable)"> 
    <args> 
     <this type="System.Windows.Forms.Application.ComponentManager" value="System.Windows.Forms.Application.ComponentManager&#xA; oleComponents=System.Collections.Hashtable&#xA; cookieCounter=1&#xA; activeComponent=System.Windows.Forms.Application.ThreadContext&#xA; trackingComponent=&lt;null&gt;&#xA; currentState=0" /> 
     <dwComponentID type="N/A" value="&lt;N/A&gt;" /> 
     <reason type="System.Int32" value="-1" /> 
     <pvLoopData type="System.Int32" value="0" /> 
    </args> 
    <locals> 
     <local_0 type="System.Int32" value="0" /> 
     <local_1 type="System.Boolean" value="True" /> 
     <local_2 type="System.Windows.Forms.UnsafeNativeMethods.IMsoComponent" value="&lt;null&gt;" /> 
     <local_3 type="N/A" value="&lt;N/A&gt;" /> 
     <local_4 type="N/A" value="&lt;N/A&gt;" /> 
     <local_5 type="N/A" value="&lt;N/A&gt;" /> 
     <local_6 type="System.Windows.Forms.Application.ThreadContext" value="System.Windows.Forms.Application.ThreadContext&#xA; contextHash=System.Collections.Hashtable&#xA; tcInternalSyncObject=System.Object&#xA; totalMessageLoopCount=1&#xA; baseLoopReason=-1&#xA; currentThreadContext=System.Windows.Forms.Application.ThreadContext&#xA; threadExceptionHandler=System.Threading.ThreadExceptionEventHandler&#xA; idleHandler=&lt;null&gt;&#xA; enterModalHandler=&lt;null&gt;&#xA; leaveModalHandler=&lt;null&gt;&#xA; applicationContext=System.Windows.Forms.ApplicationContext&#xA; parkingWindow=&lt;null&gt;&#xA; marshalingControl=System.Windows.Forms.Application.MarshalingControl&#xA; culture=&lt;null&gt;&#xA; messageFilters=&lt;null&gt;&#xA; messageFilterSnapshot=&lt;null&gt;&#xA; handle=912&#xA; id=17208&#xA; messageLoopCount=1&#xA; threadState=1&#xA; modalCount=0&#xA; activatingControlRef=&lt;null&gt;&#xA; componentManager=System.Windows.Forms.Application.ComponentManager&#xA; externalComponentManager=False&#xA; fetchingComponentManager=False&#xA; componentID=1&#xA; currentForm=Program.MainForm&#xA; threadWindows=&lt;null&gt;&#xA; tempMsg=System.Windows.Forms.NativeMethods.MSG&#xA; disposeCount=0&#xA; ourModalLoop=False&#xA; messageLoopCallback=&lt;null&gt;&#xA; __identity=&lt;null&gt;" /> 
     <local_7 type="N/A" value="&lt;N/A&gt;" /> 
     <local_8 type="N/A" value="&lt;N/A&gt;" /> 
     <local_9 type="N/A" value="&lt;N/A&gt;" /> 
     <local_10 type="N/A" value="&lt;N/A&gt;" /> 
     <local_11 type="N/A" value="&lt;N/A&gt;" /> 
     <local_12 type="N/A" value="&lt;N/A&gt;" /> 
     <local_13 type="System.Boolean" value="False" /> 
     <local_14 type="System.Windows.Forms.NativeMethods.MSG[]" value="array [1]&#xA; [0] = System.Windows.Forms.NativeMethods.MSG" /> 
    </locals> 
</frame> 
<frame ix="1" loc="System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner (source line information unavailable)"> 
    <args> 
     <this type="System.Windows.Forms.Application.ThreadContext" value="System.Windows.Forms.Application.ThreadContext&#xA; contextHash=System.Collections.Hashtable&#xA; tcInternalSyncObject=System.Object&#xA; totalMessageLoopCount=1&#xA; baseLoopReason=-1&#xA; currentThreadContext=System.Windows.Forms.Application.ThreadContext&#xA; threadExceptionHandler=System.Threading.ThreadExceptionEventHandler&#xA; idleHandler=&lt;null&gt;&#xA; enterModalHandler=&lt;null&gt;&#xA; leaveModalHandler=&lt;null&gt;&#xA; applicationContext=System.Windows.Forms.ApplicationContext&#xA; parkingWindow=&lt;null&gt;&#xA; marshalingControl=System.Windows.Forms.Application.MarshalingControl&#xA; culture=&lt;null&gt;&#xA; messageFilters=&lt;null&gt;&#xA; messageFilterSnapshot=&lt;null&gt;&#xA; handle=912&#xA; id=17208&#xA; messageLoopCount=1&#xA; threadState=1&#xA; modalCount=0&#xA; activatingControlRef=&lt;null&gt;&#xA; componentManager=System.Windows.Forms.Application.ComponentManager&#xA; externalComponentManager=False&#xA; fetchingComponentManager=False&#xA; componentID=1&#xA; currentForm=Program.MainForm&#xA; threadWindows=&lt;null&gt;&#xA; tempMsg=System.Windows.Forms.NativeMethods.MSG&#xA; disposeCount=0&#xA; ourModalLoop=False&#xA; messageLoopCallback=&lt;null&gt;&#xA; __identity=&lt;null&gt;" /> 
     <reason type="System.Int32" value="-1" /> 
     <context type="System.Windows.Forms.ApplicationContext" value="System.Windows.Forms.ApplicationContext&#xA; mainForm=Program.MainForm&#xA; userData=&lt;null&gt;&#xA; ThreadExit=System.EventHandler" /> 
    </args> 
    <locals> 
     <local_0 type="System.Windows.Forms.Form" value="&lt;null&gt;" /> 
     <local_1 type="System.Boolean" value="False" /> 
     <local_2 type="N/A" value="&lt;N/A&gt;" /> 
     <local_3 type="N/A" value="&lt;N/A&gt;" /> 
     <local_4 type="N/A" value="&lt;N/A&gt;" /> 
    </locals> 
</frame> 
... etc 
</thread> 
</process> 

既然你有一个调试器的全部功能并没有什么从编写尽可能多或尽可能少阻止​​你只要你喜欢,但上面的例子应该让你开始。

UPDATE

此工作原理与NET 2.0和/或运行时3.5没有任何进一步的依赖关系。

这可以调试运行在.Net 4.0进程中的.Net 2.0/3.5代码;但是,它不适用于4.0(尚未)。

4.0 CLR看到这个帖子: http://blogs.msdn.com/b/rmbyers/archive/2008/10/27/icordebug-re-architecture-in-clr-4-0.aspx

+0

@ csharptest.net - 根据您链接的页面,需要安装可能无法在客户端计算机上使用的.Net 2.0 SDK。另外,它是否支持.Net 4程序? – Giorgi 2010-10-19 06:55:03

+0

这是一个真实的事情要考虑 - 也许有人知道对最终用户部署的最低要求? – 2010-10-19 13:33:57

+0

虽然我没有验证它,但我不相信除.net运行时之外还有任何其他要求。至于.net 4.0,你应该只需要该版本的SDK中的示例(假设MS已经更新了它?IDK,它甚至可以工作,因为它都是基于COM的。)当我开始工作时,我会尝试不使用sdk 。 – 2010-10-19 14:26:46

您可以从AppDomain.UnhandledExceptionApplication.ThreadException事件处理程序调用MiniDumpWriteDump来创建小型转储。本文介绍的功能很详细:Effective minidumps

您也可以使用这个库,它具有其它功能也:Catch All Bugs with BugTrap!

编辑

看起来像得到一个有用的转储不是那么容易。首先sos.dll抱怨转储不满(完整转储大约100-150MB)。其次,不建议在catch块写转储:Getting good dumps when an exception is thrown.

如果你有一个WinForms应用程序这个问题有一些有用的信息:How does SetUnhandledExceptionFilter work in .NET WinForms applications?

+0

我已经陷入不受欢迎的Exeptions,但我需要获取局部变量值。即时通讯基本上寻找一种动态的方式。我不认为我可以创建完整的转储,如果这是唯一的选择,我会做到这一点,但会提前小型转储是的。 – EKS 2010-10-16 11:16:41

+0

@EKS - 你需要转储。 – Giorgi 2010-10-16 19:03:28

+0

我认为,要测试明天发布的内容。在一个lan党atm :) – EKS 2010-10-17 11:20:58