2010-09-20 15 views
8

Sto cercando un modo per generare file minidump nelle mie applicazioni simulare a quello che ProcDump fa ma prefettamente con il codice e non dover estrarre uno strumento 3dparty per farlo.Genera/crea file mdump nella mia app

Le principali ragioni per non voler utilizzare ProcDump è:
1) Dimensione del binario aumenterebbe notevolmente (Questo è un problema perché le mie applicazioni sono freeware, e la larghezza di banda non è libero).
2) Si sente sporco.
3) In nessun modo posso portare quell'app per eseguire inn windows mobile.

I miei requisiti sono:
1) Possibilità di generare file mdump in un arresto anomalo.
2) Possibilità di fare "mettere in pausa" l'app fare un dump, e contiune sarebbe un bonus
.
Se questa non è davvero un'opzione, c'è un modo per ottenere i valori di varibales locali nel contesto corrente in modo dinamico?

Nota a margine: Ho did fin d questo articolo, ma è molto vecchio quindi ho così im esitante di basare il mio lavoro di esso.
Sembra che ci sia un problema con IE 9 o con il sito, quindi ho avuto problemi con i tag.

+0

qualsiasi buona soluzione definitiva di questo problema? con un buon codice sorgente dell'applicazione di esempio in .NET? – Kiquenet

risposta

6

Quindi non v'è una soluzione che viene in mente e che soddisfi i seguenti obiettivi:

  • Dimensioni del binario aumenterebbe di circa 300k
  • Capacità di generare file mdump in un incidente fatale.
  • Capacità di fare "pausa" l'applicazione fare una discarica, e contiune sarebbe un bonus

darò questo requisito un completo sconosciuto:

  • nessun modo posso porta app per eseguire inn windows mobile.

Quindi qual è la soluzione?

In Microsoft Sample for MDbg è possibile integrare le parti necessarie necessarie.exe per fornire un debugger "just-in-time" che collega, discarica e scollega dal processo di arresto anomalo.

Fase 1 - Iniziare scaricando il codice sorgente per il MDBG da qui: http://www.microsoft.com/downloads/en/details.aspx?FamilyID=38449a42-6b7a-4e28-80ce-c55645ab1310&DisplayLang=en

Passo 2 - Creare un gestore di 'incidente' che genera un processo debugger e attende per il completamento. Ho usato le seguenti poche righe di codice per rilanciare lo stesso exe con alcuni argomenti extra per richiamare il debugger e generare un file xml su 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)); 

Fase 3 - Scrivere la routine di debug discarica, questo può essere nello stesso exe o in un exe diverso. Dovrai fare riferimento (o includere la fonte da) ai moduli "raw", "corapi" e "mdbgeng" dell'esempio. Quindi aggiungere un paio di righe al 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(); 
} 

Esempio di output

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

Dal momento che hai tutta la potenza di un debugger non c'è nulla ti impedisce di scrivere tanto o poco come ti piace, ma l'esempio sopra dovrebbe iniziare.

UPDATE

Questo funziona con il .Net 2.0 e/o 3.5 runtime senza ulteriori dipendenze.

Questo può eseguire il debug. Codice di rete 2.0/3.5 in esecuzione in un processo .Net 4.0; tuttavia, non funziona con 4.0 (ancora).

Per 4.0 CLR vedi questo post: http://blogs.msdn.com/b/rmbyers/archive/2008/10/27/icordebug-re-architecture-in-clr-4-0.aspx

+0

@ csharptest.net - In base alla pagina collegata è necessario installare. NET 2.0 SDK da installare che potrebbe non essere disponibile sul computer client. Inoltre, supporta i programmi .Net 4? – Giorgi

+0

questa è una cosa reale da considerare - forse qualcuno conosce i requisiti minimi per la distribuzione degli utenti finali? –

+0

Anche se non l'ho verificato, non credo ci siano requisiti oltre al runtime .net. Per quanto riguarda .net 4.0 dovresti aver bisogno solo del campione da quella versione dell'SDK (supponendo che MS l'abbia aggiornato? IDK, potrebbe funzionare anche perché è tutto basato su COM. Lo proverò senza l'sdk installato quando lavoro –

5

È possibile chiamare MiniDumpWriteDump da AppDomain.UnhandledException o Application.ThreadException gestore di eventi per creare il minidump. Questo articolo spiega la funzione in grande dettaglio: Effective minidumps

È inoltre possibile utilizzare questa libreria che ha altre funzionalità anche: Catch All Bugs with BugTrap!

Modifica

Sembra ottenere un utile minidump non è così facile. Prima di tutto sos.dll si lamenta quando il dump non è pieno (i dump completi sono circa 100-150 MB). In secondo luogo, la scrittura discarica nel blocco catch non è raccomandato: Getting good dumps when an exception is thrown.

Se si dispone di un'applicazione WinForms questa domanda ha qualche info utile: How does SetUnhandledExceptionFilter work in .NET WinForms applications?

+0

Im già intrappolando Exeptions non modificati, ma ho bisogno di ottenere valori di variabili locali. E sto fondamentalmente cercando un modo per farlo in modo dinamico. E non penso di poter creare discariche complete, se questa è l'unica opzione lo farò, ma preferirei minidump sì. – EKS

+0

@EKS - avrete bisogno di discarica per questo. – Giorgi

+0

L'ho capito, per testare cosa hai postato domani. A una festa di lan atm :) – EKS

Problemi correlati