2010-09-20 5 views
8

Estoy buscando una manera de generar archivos de minivolcado en mis aplicaciones simuladas a lo que ProcDump hace pero prefaramente con código y no tener que extraer una herramienta 3dparty para hacerlo.Generar/crear archivos mdump para en mi aplicación

Las principales razones para no querer usar ProcDump es:
1) Tamaño del binario aumentaría en gran medida (Esto es un problema porque mis aplicaciones son freeware, y el ancho de banda no es gratuito).
2) Se siente sucio.
3) De ninguna manera puedo portar esa aplicación para ejecutar Inn Windows Mobile.

Mis requisitos son:
1) Posibilidad de generar archivos mdump en un accidente fatale.
2) Habilidad de hacer "pausar" la aplicación hacer un volcado, y contiune sería una bonificación
.
Si esto no es realmente una opción, ¿hay alguna forma de obtener los valores de varibales locales en el contexto actual de forma dinámica?

Nota al margen: I did fin d este artículo, pero es muy viejo, así que estoy tan indeciso de basar mi trabajo en él.
Parece que hay un problema con IE 9 o con el sitio, por lo que tuve problemas con las etiquetas.

+0

cualquier solución final bien acerca de este tema? con un buen código fuente de aplicación de muestra en .NET? – Kiquenet

Respuesta

6

Así que hay una solución que viene a la mente y cumple con los siguientes objetivos:

  • Tamaño del binario aumentaría en unos 300k
  • Capacidad de generar mdump archivos en un accidente fatal.
  • Posibilidad de hacer "pausa" la aplicación hacer un vertedero, y contiune sería una ventaja

Voy a dar este requisito un completo desconocido:

  • hay manera que pueda puerto de esa aplicación ejecutar inn windows mobile.

¿Cuál es la solución?

Integre las piezas necesarias que necesita de Microsoft Sample para MDbg.exe para proporcionarle un depurador 'justo a tiempo' que adjunta, volca y separa del proceso de bloqueo.

Paso 1 - Para empezar a descargar el código fuente para el MDBG desde aquí: http://www.microsoft.com/downloads/en/details.aspx?FamilyID=38449a42-6b7a-4e28-80ce-c55645ab1310&DisplayLang=en

Paso 2 - Crear un controlador de 'crash' que genera un proceso depurador y espera a la finalización. Usé las siguientes líneas de código para volver a ejecutar el mismo exe con algunos argumentos adicionales para invocar el depurador y enviar un archivo xml a 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)); 

Paso 3 - Escriba la rutina de depuración de errores, esta puede estar en el mismo exe o en un exe diferente. Tendrá que hacer referencia (o incluir la fuente de) los módulos 'raw', 'corapi' y 'mdbgeng' de la muestra. A continuación, añadir unas pocas líneas a su principal():

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(); 
} 

Ejemplo de salida

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

Puesto que usted tiene todo el poder de un depurador no hay nada que le para de escribir tanto o tan poco como quieras, pero el ejemplo anterior debería ayudarte a empezar.

ACTUALIZACIÓN

Esto funciona con .NET 2.0 y/o 3.5 tiempo de ejecución sin ningún dependencias adicionales.

Esto puede depurar el código .Net 2.0/3.5 ejecutándose en un proceso .Net 4.0; sin embargo, no funciona con 4.0 (todavía).

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

+0

@ csharptest.net - De acuerdo con la página que enlazó, se requiere .Net 2.0 SDK para instalar, que podría no estar disponible en la computadora cliente. Además, ¿es compatible con .NET 4 programas? – Giorgi

+0

esto es algo real de considerar, tal vez alguien conoce los requisitos mínimos para la implementación del usuario final? –

+0

Aunque no lo he verificado, no creo que existan requisitos además del tiempo de ejecución de .net. En cuanto a .net 4.0, solo debería necesitar el ejemplo de esa versión del SDK (suponiendo que MS lo haya actualizado, IDK, incluso puede funcionar, ya que está basado en COM. Lo intentaré sin tener el SDK instalado cuando empiece a trabajar –

5

Puede llamar al MiniDumpWriteDump desde AppDomain.UnhandledException o Application.ThreadException controlador de eventos para crear el minivolcado. En este artículo se explica la función en gran detalle: Effective minidumps

También puede utilizar esta biblioteca que tiene otra funcionalidad también: Catch All Bugs with BugTrap!

Editar

Parece que conseguir un minidump útil no es tan fácil. En primer lugar, sos.dll se queja cuando el volcado no está lleno (los volcados totales son de aproximadamente 100-150 MB). En segundo lugar, no se recomienda escribir volcado en el bloque catch: Getting good dumps when an exception is thrown.

Si usted tiene una aplicación de Windows Forms esta pregunta tiene algo de información útil: How does SetUnhandledExceptionFilter work in .NET WinForms applications?

+0

Ya estoy atrapando Excepciones sin respuesta, pero necesito obtener valores de variables locales. Y básicamente estoy buscando una forma de hacerlo de forma dinámica. Y no creo que pueda crear vertederos completos, si esa es la única opción lo haré, pero preferiría los minivolcados sí. – EKS

+0

@EKS - necesitarás un volcado para eso. – Giorgi

+0

Pensé que, voy a probar lo que publicaste mañana. En un bar de fiesta lan :) – EKS

Cuestiones relacionadas