2010-09-20 15 views
8

Poszukuję sposobu na wygenerowanie plików minizrzutu w moich aplikacjach symulacyjnych do tego, co robi ProcDump z kodem i bez konieczności wyodrębniania narzędzia 3dparty, aby to zrobić.Generowanie/tworzenie plików mdump dla mojej aplikacji

Główne powody, dla których nie chce używać ProcDump jest:
1) Rozmiar pliku binarnego będzie znacznie zwiększyć (To jest problem, ponieważ moje aplikacje są darmowe, a przepustowość nie jest za darmo).
2) Czuje się brudno.
3) Nie ma mowy, że mogę przenieść aplikację do systemu Windows Mobile.

Moje wymagania są następujące:
1) Możliwość generowania plików mdump w razie awarii.
2) Zdolność do "pauzy" aplikacja robi zrzut, a contiune będzie premią
.
Jeśli nie jest to naprawdę opcja, czy istnieje sposób dynamicznego uzyskania wartości lokalnych zmiennych w bieżącym kontekście?

Notka poboczna: I did fin d tego artykułu, ale jest bardzo stary, więc nie mogę się oprzeć na jego pracy.
Wygląda na to, że istnieje problem z IE 9 lub ze stroną, więc miałem problemy z tagami.

+0

każdy końcowy dobre rozwiązanie na ten temat? z dobrym kodem źródłowym aplikacji przykładowej w .NET? – Kiquenet

Odpowiedz

6

Więc istnieje jedno rozwiązanie, które przychodzi do głowy i spełnia następujące cele:

  • Rozmiar pliku binarnego wzrośnie o około 300k
  • zdolność do generowania mdump plików w katastrofie fatale.
  • Możliwość zrobienia "pause" app zrobić zrzut i contiune będzie bonus

dam tego wymogu kompletnego nieznane:

  • Nie sposób mogę portu, który aplikacja do uruchomienia systemu Windows Mobile.

Jakie jest rozwiązanie?

Zintegruj wymagane części z próbki Microsoft dla MDbg.exe, aby zapewnić debugger "just-in-time", który dołącza, zrzuca i odłącza się od awarii.

Krok 1 - Start pobierając kod źródłowy do mdbg stąd: http://www.microsoft.com/downloads/en/details.aspx?FamilyID=38449a42-6b7a-4e28-80ce-c55645ab1310&DisplayLang=en

Krok 2 - Tworzenie obsługi „katastrofie”, które spawns procesu debuggera i czeka na zakończenie. Użyłem kilku kolejnych linii kodu, aby ponownie uruchomić ten sam exe z kilkoma dodatkowymi argumentami, aby wywołać debuggera i wypisać plik xml na 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)); 

Krok 3 - Napisz procedurę debug zrzutu, to może być w tym samym exe lub w innej exe. Będziesz musiał odnieść się (lub zawrzeć źródło) do modułów "raw", "corapi" i "mdbgeng" z próbki. Następnie dodać kilka linijek do 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(); 
} 

Przykład Wyjście

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

Skoro masz pełną moc debuggera nie ma nic Cię powstrzymuje od pisania za dużo lub za mało jak chcesz, ale powyższy przykład powinien zacząć.

UPDATE

działa z .NET 2.0 i/lub 3.5 starcie bez dalszych zależności.

Umożliwia to debugowanie kodu .Net 2.0/3.5 działającego w procesie .Net 4.0; jednak nie działa z 4.0 (jeszcze).

przez 4,0 CLR zobaczyć ten wpis: http://blogs.msdn.com/b/rmbyers/archive/2008/10/27/icordebug-re-architecture-in-clr-4-0.aspx

+0

@ csharptest.net - Według strony, którą połączyłeś, wymaga zainstalowania SDK .Net 2.0, który może nie być dostępny na komputerze klienckim. Czy obsługuje również programy .Net 4? – Giorgi

+0

to jest naprawdę rzecz do rozważenia - może ktoś zna minimalne wymagania dla wdrożenia użytkownika końcowego? –

+0

Mimo że nie zweryfikowałem tego, nie wierzę, że poza środowiskiem .net istnieją pewne wymagania. Jeśli chodzi o .net 4.0, powinieneś tylko pobrać próbkę z tej wersji SDK (zakładając, że MS ją zaktualizował - IDK, może nawet działać tak, jakby to było wszystko oparte na COM.) Wypróbuję to bez zainstalowanego SDK, kiedy dostanę pracę –

5

Możesz zadzwonić pod numer MiniDumpWriteDump z AppDomain.UnhandledException lub Application.ThreadException modułu obsługi zdarzeń, aby utworzyć minizrzutu. W tym artykule opisano funkcję w wielkich szczegółach: Effective minidumps

Można również korzystać z tej biblioteki, która ma inne funkcje też: Catch All Bugs with BugTrap!

Edycja

wygląda coraz przydatnych Minidump nie jest takie proste. Przede wszystkim sos.dll narzeka, gdy zrzut nie jest pełny (pełne zrzuty to około 100-150MB). Po drugie, pisanie wysypisko w bloku catch nie jest zalecane: Getting good dumps when an exception is thrown.

Jeśli masz aplikację WinForm kwestia ta ma pewne Przydatne informacje: How does SetUnhandledExceptionFilter work in .NET WinForms applications?

+0

Jestem już pułapką unhamlded Exeptions, ale muszę uzyskać lokalne wartości zmiennych. I im po prostu szukam sposobu na dynamiczne działanie. I nie sądzę, że mogę stworzyć pełne zrzuty, jeśli to jedyna opcja, którą zrobię, ale wolałabym minizrzuty tak. – EKS

+0

@EKS - do tego będzie potrzebny zrzut. – Giorgi

+0

Pomyślałem, że przetestuję to, co napisałeś jutro. W bankomacie lan party :) – EKS

Powiązane problemy