代码之家  ›  专栏  ›  技术社区  ›  EKS

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

  •  8
  • EKS  · 技术社区  · 15 年前

    我正在寻找一种在我的应用程序模拟器中生成小型转储文件的方法 ProcDump 只需预先编写代码,而不必提取3dparty工具。

    不想使用的主要原因 程序转储 是:
    1)二进制文件的大小会大大增加(这是个问题,因为我的应用程序是免费的,BandWith不是免费的)。
    2)感觉脏。
    3)我无法将该应用程序移植到运行Inn Windows Mobile。

    我的要求是:
    1)在致命崩溃中生成mdump文件的能力。
    2)能够“暂停”应用程序进行转储,并且Contiune将是一个奖励。
    .
    如果这不是一个真正的选项,有没有一种方法可以动态地获取当前上下文中本地变量的值?

    旁注: 我 did fin D这篇文章,但它很旧,所以我很犹豫是否要把它作为我工作的基础。
    似乎是IE 9或是该站点有问题,所以我对标签有问题。

    2 回复  |  直到 15 年前
        1
  •  6
  •   csharptest.net    15 年前

    因此,有一个解决方案浮现在脑海中,并满足以下目标:

    • 二进制文件的大小将增加大约30万。
    • 能够在致命的崩溃中生成mdump文件。
    • 能够“暂停”应用程序进行转储,继续将是一个奖励

    我将给出一个完全未知的要求:

    • 我无法将该应用程序移植到运行Inn Windows Mobile。

    那么解决方案是什么?

    从mdbg.exe的Microsoft示例中集成所需的部分,以便为您提供一个“实时”调试器,用于附加、转储和从崩溃过程中分离。

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

    由于您拥有调试程序的全部功能,所以没有任何东西可以阻止您编写您喜欢的那么多或那么少的内容,但是上面的示例应该可以让您开始编写。

    更新

    这与.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

        2
  •  5
  •   Community CDub    8 年前

    你可以打电话 MiniDumpWriteDump AppDomain.UnhandledException Application.ThreadException 创建小型转储的事件处理程序。本文详细介绍了该功能: Effective minidumps

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

    编辑

    看起来获得一个有用的小型转储文件并不容易。首先,当转储未满时,sos.dll会发出抱怨(满转储约为100-150MB)。其次,不建议在catch块中写入dump: Getting good dumps when an exception is thrown.

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