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

发布于 2024-09-24 09:26:06 字数 764 浏览 8 评论 0原文

我正在寻找一种在我的应用程序中生成小型转储文件的方法,类似于 ProcDump 可以,但最好使用代码,而不必提取 3dparty 工具来完成它。

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

我的要求是:
1) 能够在致命崩溃中生成 mdump 文件。
2) 能够“暂停”应用程序进行转储,并且继续将是一个额外的好处

如果这不是一个真正的选择,是否有办法动态获取当前上下文中的局部变量的值?

旁注: 我确实找到了这篇文章,但它很旧所以我所以我犹豫是否要以此为基础进行我的工作。
IE 9 或网站似乎有问题,所以我遇到了标签问题。

Im looking for a way to generate minidump files in my applications simular to what ProcDump does but prefarably with code and not having to extract a 3dparty tool to do it.

The main reasons for not wanting to use ProcDump is:
1) Size of the binary would increase greatly ( This is a problem because my apps are freeware, and bandwith is not free).
2) Feels dirty.
3) No way i can port that app to run inn windows mobile.

My requirements are:
1) Ability to generate mdump files in a fatale crash.
2) Abilityt to do "pause" the app do a dump, and contiune would be a bonus
.

If this is not realy a option, is there a way to get the values of local varibales in the current context dynamicly?

Side note:
I did find this article, but its very old so i so im hesitant to base my work of it.
There seems to either be a issue with IE 9 or with the site, so i had problems with tags.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夏花。依旧 2024-10-01 09:26:06

因此,我想到了一个解决方案,它可以满足以下目标:

  • 二进制文件的大小将增加大约 300k
  • 能够在致命崩溃中生成 mdump 文件。
  • 能够“暂停”应用程序进行转储,然后继续将是一个额外的好处

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

  • 我无法将该应用程序移植到 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
    oleComponents=System.Collections.Hashtable
 cookieCounter=1
    activeComponent=System.Windows.Forms.Application.ThreadContext
 trackingComponent=<null>
 currentState=0" />
        <dwComponentID type="N/A" value="<N/A>" />
        <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="<null>" />
        <local_3 type="N/A" value="<N/A>" />
        <local_4 type="N/A" value="<N/A>" />
        <local_5 type="N/A" value="<N/A>" />
        <local_6 type="System.Windows.Forms.Application.ThreadContext" value="System.Windows.Forms.Application.ThreadContext
   contextHash=System.Collections.Hashtable
   tcInternalSyncObject=System.Object
 totalMessageLoopCount=1
    baseLoopReason=-1
  currentThreadContext=System.Windows.Forms.Application.ThreadContext
    threadExceptionHandler=System.Threading.ThreadExceptionEventHandler
    idleHandler=<null>
   enterModalHandler=<null>
 leaveModalHandler=<null>
 applicationContext=System.Windows.Forms.ApplicationContext
 parkingWindow=<null>
 marshalingControl=System.Windows.Forms.Application.MarshalingControl
   culture=<null>
   messageFilters=<null>
    messageFilterSnapshot=<null>
 handle=912
 id=17208
   messageLoopCount=1
 threadState=1
  modalCount=0
   activatingControlRef=<null>
  componentManager=System.Windows.Forms.Application.ComponentManager
 externalComponentManager=False
 fetchingComponentManager=False
 componentID=1
  currentForm=Program.MainForm
   threadWindows=<null>
 tempMsg=System.Windows.Forms.NativeMethods.MSG
 disposeCount=0
 ourModalLoop=False
 messageLoopCallback=<null>
   __identity=<null>" />
        <local_7 type="N/A" value="<N/A>" />
        <local_8 type="N/A" value="<N/A>" />
        <local_9 type="N/A" value="<N/A>" />
        <local_10 type="N/A" value="<N/A>" />
        <local_11 type="N/A" value="<N/A>" />
        <local_12 type="N/A" value="<N/A>" />
        <local_13 type="System.Boolean" value="False" />
        <local_14 type="System.Windows.Forms.NativeMethods.MSG[]" value="array [1]
 [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
  contextHash=System.Collections.Hashtable
   tcInternalSyncObject=System.Object
 totalMessageLoopCount=1
    baseLoopReason=-1
  currentThreadContext=System.Windows.Forms.Application.ThreadContext
    threadExceptionHandler=System.Threading.ThreadExceptionEventHandler
    idleHandler=<null>
   enterModalHandler=<null>
 leaveModalHandler=<null>
 applicationContext=System.Windows.Forms.ApplicationContext
 parkingWindow=<null>
 marshalingControl=System.Windows.Forms.Application.MarshalingControl
   culture=<null>
   messageFilters=<null>
    messageFilterSnapshot=<null>
 handle=912
 id=17208
   messageLoopCount=1
 threadState=1
  modalCount=0
   activatingControlRef=<null>
  componentManager=System.Windows.Forms.Application.ComponentManager
 externalComponentManager=False
 fetchingComponentManager=False
 componentID=1
  currentForm=Program.MainForm
   threadWindows=<null>
 tempMsg=System.Windows.Forms.NativeMethods.MSG
 disposeCount=0
 ourModalLoop=False
 messageLoopCallback=<null>
   __identity=<null>" />
        <reason type="System.Int32" value="-1" />
        <context type="System.Windows.Forms.ApplicationContext" value="System.Windows.Forms.ApplicationContext
 mainForm=Program.MainForm
  userData=<null>
  ThreadExit=System.EventHandler" />
    </args>
    <locals>
        <local_0 type="System.Windows.Forms.Form" value="<null>" />
        <local_1 type="System.Boolean" value="False" />
        <local_2 type="N/A" value="<N/A>" />
        <local_3 type="N/A" value="<N/A>" />
        <local_4 type="N/A" value="<N/A>" />
    </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

So there is one solution that comes to mind and meets the following goals:

  • Size of the binary would increase by around 300k
  • Ability to generate mdump files in a fatale crash.
  • Ability to do "pause" the app do a dump, and contiune would be a bonus

I'll give this requirement a complete unknown:

  • No way i can port that app to run inn windows mobile.

So what's the solution?

Integrate the required parts you need from the Microsoft Sample for MDbg.exe to provide you with a 'just-in-time' debugger that attaches, dumps, and detaches from the crashing process.

Step 1 - Start by downloading the source code to the mdbg from here: http://www.microsoft.com/downloads/en/details.aspx?FamilyID=38449a42-6b7a-4e28-80ce-c55645ab1310&DisplayLang=en

Step 2 - Create a 'crash' handler that spawns a debugger process and waits for completion. I used the following few lines of code to re-launch the same exe with a few extra arguments to invoke the debugger and output an xml file to 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));

Step 3 - Write the debug dump routine, this can be in the same exe or in a different exe. You will need to reference (or include the source from) the 'raw', 'corapi', and 'mdbgeng' modules from the sample. Then add a few lines to your 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();
}

Example 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
    oleComponents=System.Collections.Hashtable
 cookieCounter=1
    activeComponent=System.Windows.Forms.Application.ThreadContext
 trackingComponent=<null>
 currentState=0" />
        <dwComponentID type="N/A" value="<N/A>" />
        <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="<null>" />
        <local_3 type="N/A" value="<N/A>" />
        <local_4 type="N/A" value="<N/A>" />
        <local_5 type="N/A" value="<N/A>" />
        <local_6 type="System.Windows.Forms.Application.ThreadContext" value="System.Windows.Forms.Application.ThreadContext
   contextHash=System.Collections.Hashtable
   tcInternalSyncObject=System.Object
 totalMessageLoopCount=1
    baseLoopReason=-1
  currentThreadContext=System.Windows.Forms.Application.ThreadContext
    threadExceptionHandler=System.Threading.ThreadExceptionEventHandler
    idleHandler=<null>
   enterModalHandler=<null>
 leaveModalHandler=<null>
 applicationContext=System.Windows.Forms.ApplicationContext
 parkingWindow=<null>
 marshalingControl=System.Windows.Forms.Application.MarshalingControl
   culture=<null>
   messageFilters=<null>
    messageFilterSnapshot=<null>
 handle=912
 id=17208
   messageLoopCount=1
 threadState=1
  modalCount=0
   activatingControlRef=<null>
  componentManager=System.Windows.Forms.Application.ComponentManager
 externalComponentManager=False
 fetchingComponentManager=False
 componentID=1
  currentForm=Program.MainForm
   threadWindows=<null>
 tempMsg=System.Windows.Forms.NativeMethods.MSG
 disposeCount=0
 ourModalLoop=False
 messageLoopCallback=<null>
   __identity=<null>" />
        <local_7 type="N/A" value="<N/A>" />
        <local_8 type="N/A" value="<N/A>" />
        <local_9 type="N/A" value="<N/A>" />
        <local_10 type="N/A" value="<N/A>" />
        <local_11 type="N/A" value="<N/A>" />
        <local_12 type="N/A" value="<N/A>" />
        <local_13 type="System.Boolean" value="False" />
        <local_14 type="System.Windows.Forms.NativeMethods.MSG[]" value="array [1]
 [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
  contextHash=System.Collections.Hashtable
   tcInternalSyncObject=System.Object
 totalMessageLoopCount=1
    baseLoopReason=-1
  currentThreadContext=System.Windows.Forms.Application.ThreadContext
    threadExceptionHandler=System.Threading.ThreadExceptionEventHandler
    idleHandler=<null>
   enterModalHandler=<null>
 leaveModalHandler=<null>
 applicationContext=System.Windows.Forms.ApplicationContext
 parkingWindow=<null>
 marshalingControl=System.Windows.Forms.Application.MarshalingControl
   culture=<null>
   messageFilters=<null>
    messageFilterSnapshot=<null>
 handle=912
 id=17208
   messageLoopCount=1
 threadState=1
  modalCount=0
   activatingControlRef=<null>
  componentManager=System.Windows.Forms.Application.ComponentManager
 externalComponentManager=False
 fetchingComponentManager=False
 componentID=1
  currentForm=Program.MainForm
   threadWindows=<null>
 tempMsg=System.Windows.Forms.NativeMethods.MSG
 disposeCount=0
 ourModalLoop=False
 messageLoopCallback=<null>
   __identity=<null>" />
        <reason type="System.Int32" value="-1" />
        <context type="System.Windows.Forms.ApplicationContext" value="System.Windows.Forms.ApplicationContext
 mainForm=Program.MainForm
  userData=<null>
  ThreadExit=System.EventHandler" />
    </args>
    <locals>
        <local_0 type="System.Windows.Forms.Form" value="<null>" />
        <local_1 type="System.Boolean" value="False" />
        <local_2 type="N/A" value="<N/A>" />
        <local_3 type="N/A" value="<N/A>" />
        <local_4 type="N/A" value="<N/A>" />
    </locals>
</frame>
... etc
</thread>
</process>

Since you have the full power of a debugger there is nothing stopping you from writing as much or as little as you like, but the above example should get you started.

UPDATE

This works with the .Net 2.0 and/or 3.5 runtime without any further dependencies.

This can debug .Net 2.0/3.5 code running in a .Net 4.0 process; however, it does not work with 4.0 (yet).

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

岛歌少女 2024-10-01 09:26:06

您可以从 MiniDumpWriteDump 调用 < a href="https://learn.microsoft.com/en-us/dotnet/api/system.appdomain.unhandledException?view=net-5.0" rel="nofollow noreferrer">AppDomain.UnhandledException 或 < a href="https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.application.threadexception?view=net-5.0" rel="nofollow noreferrer">Application.ThreadException 用于创建小型转储的事件处理程序。本文详细介绍了该功能: 有效的小型转储

您还可以使用这个具有其他功能的库:使用 BugTrap 捕获所有错误!

编辑

看起来获得有用的小型转储并不那么容易。首先,当转储未满时,sos.dll 会抱怨(完整转储约为 100-150MB)。其次,不建议在 catch 块中编写转储: 在抛出异常时获得良好的转储。

如果您有一个 winforms 应用程序,这个问题有一些有用的信息: SetUnhandledExceptionFilter 如何在 .NET WinForms 应用程序中工作?< /a>

You can call MiniDumpWriteDump from AppDomain.UnhandledException or Application.ThreadException event handler to create the minidump. This article explains the function in great details: Effective minidumps

You can also use this library which has other functionality too: Catch All Bugs with BugTrap!

Edit

Looks like getting a useful minidump is not that easy. First of all sos.dll complains when the dump is not full (full dumps are about 100-150MB). Secondly, writing dump in catch block is not recommended: Getting good dumps when an exception is thrown.

If you have a winforms application this question has some usefull info: How does SetUnhandledExceptionFilter work in .NET WinForms applications?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文