2010-09-20 73 views
8

我正在尋找一種方法來在我的應用程序中生成小型轉儲文件,類似於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

回答

6

所以有想到的,並符合下列目標之一的解決方案:

  • 的二進制文件的大小將左右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

5

您可以從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

相關問題