zoukankan      html  css  js  c++  java
  • 事后调试之MiniDump转储

    程序发布后,针对在用户使用过程中出现的一些问题进行调试,这个过程可以称为是事后调试。在程序Crash时转储MiniDump文件供软件开发工程师分析是一种比较常用的方法。下面介绍两种常用的在程序Crash时转储MiniDump文件的方法。

    1. MiniDumpWriteDump

    MiniDumpWriteDump是windows DbgHelp.dll提供的一个转储进程MiniDump的API,可以将其导入到C#程序中。

     1     using System;
     2     using System.Diagnostics;
     3     using System.IO;
     4     using System.Runtime.InteropServices;
     5     using System.Threading;
     6 
     7     public class MiniDumpUtil
     8     {
     9         [DllImport("kernel32.dll")]
    10         private static extern int GetCurrentThreadId();
    11 
    12         [DllImport("DbgHelp.dll")]
    13         private static extern bool MiniDumpWriteDump(IntPtr hProcess, int processId, IntPtr fileHandle, MiniDumpType dumpType, ref MiniDumpExceptionInfo excepInfo, IntPtr userInfo, IntPtr extInfo);
    14 
    15         [DllImport("DbgHelp.dll")]
    16         private static extern bool MiniDumpWriteDump(IntPtr hProcess, int processId, IntPtr fileHandle, MiniDumpType dumpType, IntPtr excepParam, IntPtr userInfo, IntPtr extInfo);
    17 
    18         public static bool TryWriteMiniDump(string dmpFileName, MiniDumpType dmpType)
    19         {
    20             using (FileStream stream = new FileStream(dmpFileName, FileMode.OpenOrCreate))
    21             {
    22                 Process process = Process.GetCurrentProcess();
    23                 MiniDumpExceptionInfo exceptionInfo = new MiniDumpExceptionInfo();
    24                 exceptionInfo.ThreadId = GetCurrentThreadId();
    25                 exceptionInfo.ExceptionPointers = Marshal.GetExceptionPointers();
    26                 exceptionInfo.ClientPointers = true;
    27                 if (exceptionInfo.ExceptionPointers == IntPtr.Zero)
    28                 {
    29                     return MiniDumpWriteDump(process.Handle, process.Id, stream.SafeFileHandle.DangerousGetHandle(), dmpType, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
    30                 }
    31                 else
    32                 {
    33                     return MiniDumpWriteDump(process.Handle, process.Id, stream.SafeFileHandle.DangerousGetHandle(), dmpType, ref exceptionInfo, IntPtr.Zero, IntPtr.Zero);
    34                 }
    35             }
    36         }
    37     }
    38 
    39     [Flags]
    40     public enum MiniDumpType
    41     {
    42         MiniDumpNormal = 0x00000000,
    43         MiniDumpWithDataSegs = 0x00000001,
    44         MiniDumpWithFullMemory = 0x00000002,
    45         MiniDumpWithHandleData = 0x00000004,
    46         MiniDumpFilterMemory = 0x00000008,
    47         MiniDumpScanMemory = 0x00000010,
    48         MiniDumpWithUnloadedModules = 0x00000020,
    49         MiniDumpWithIndirectlyReferencedMemory = 0x00000040,
    50         MiniDumpFilterModulePaths = 0x00000080,
    51         MiniDumpWithProcessThreadData = 0x00000100,
    52         MiniDumpWithPrivateReadWriteMemory = 0x00000200,
    53         MiniDumpWithoutOptionalData = 0x00000400,
    54         MiniDumpWithFullMemoryInfo = 0x00000800,
    55         MiniDumpWithThreadInfo = 0x00001000,
    56         MiniDumpWithCodeSegs = 0x00002000,
    57         MiniDumpWithoutAuxiliaryState = 0x00004000,
    58         MiniDumpWithFullAuxiliaryState = 0x00008000,
    59         MiniDumpWithPrivateWriteCopyMemory = 0x00010000,
    60         MiniDumpIgnoreInaccessibleMemory = 0x00020000,
    61         MiniDumpWithTokenInformation = 0x00040000,
    62         MiniDumpWithModuleHeaders = 0x00080000,
    63         MiniDumpFilterTriage = 0x00100000,
    64         MiniDumpValidTypeFlags = 0x001fffff
    65     }
    66 
    67     public struct MiniDumpExceptionInfo
    68     {
    69         public int ThreadId;
    70         public IntPtr ExceptionPointers;
    71         public bool ClientPointers;
    72     }
    View Code

    这里要注意的一点是当前线程的ID,不能用当前线程的托管线程ID(即Thread.CurrentThread.ManagedThreadId),而是用当前线程的操作系统ID(即OSID),否则用windbg加载dump文件时可能会出现一些错误信息:

    ERROR: Unable to find system thread 1
    ERROR: The thread being debugged has either exited or cannot be accessed
    ERROR: Many commands will not work properly

    当然,这似乎对调试影响并不是很大,切换线程很容易通过windbg命令完成。

    可以简单地在未处理异常中转储进程的MiniDump

     1     class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
     6 
     7             TestMethod(-1);
     8         }
     9 
    10         static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    11         {
    12             MiniDumpUtil.TryWriteMiniDump("E:\\dump\\test.dmp", MiniDumpType.MiniDumpWithFullMemory);
    13         }
    14 
    15         static void TestMethod(int num)
    16         {
    17             if (num < 0)
    18             {
    19                 throw new ArgumentException("The argument 'num' is less than zero!");
    20             }
    21         }
    22     }
    View Code

    运行程序后,会生成test.dmp文件,用windbg加载该dump文件,设置pdb路径,可以分析异常信息。以下是采用windbg分析输出的一些信息:

    Loading Dump File [E:\dump\test.dmp]

    User Mini Dump File with Full Memory: Only application data is available

    Symbol search path is: srv*

    Executable search path is:

    Windows 7 Version 7600 MP (4 procs) Free x86 compatible

    Product: WinNt, suite: SingleUserTS

    Machine Name:

    Debug session time: Tue Oct 29 21:42:14.000 2013 (UTC + 8:00)

    System Uptime: 0 days 2:42:59.907

    Process Uptime: not available

    ...............................

    This dump file has an exception of interest stored in it.

    The stored exception information can be accessed via .ecxr.

    (168.1474): CLR exception - code e0434352 (first/second chance not available)

    eax=fffffffd ebx=038b0d78 ecx=0013d7f8 edx=77886194 esi=038b0d38 edi=0013d898

    eip=77886194 esp=0013d558 ebp=0013d568 iopl=0         nv up ei pl zr na pe nc

    cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246

    ntdll!KiFastSystemCallRet:

    77886194 c3              ret

    0:000> .sympath+ E:\dump

    Symbol search path is: srv*;E:\dump

    Expanded Symbol search path is: cache*;SRV*http://msdl.microsoft.com/download/symbols;e:\dump

    0:000> .loadby sos clr

    0:000> !pe

    Exception object: 017eb58c

    Exception type:   System.ArgumentException

    Message:          The argument 'num' is less than zero!

    InnerException:   <none>

    StackTrace (generated):

        SP       IP       Function

        0013EC98 002B00E6 DumpUtilDemo!DumpUtilDemo.Program.Main(System.String[])+0x76

    StackTraceString: <none>

    HResult: 80070057

    加粗部分是输入的调试命令,具体命令这里不作过多的说明。

    2. Windows Error Reporting - Local Dump

    Windows系统在 Server 2008, Vista SP1以后的版本中,Windows Error Reporting能够自动转储Crash程序的Dump文件。可以通过修改注册表来设定Dump文件的路径,类型等等。

    运行regedit打开注册表,找到注册表项 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps ,如果没有可以自己建。这里包括以下几个值:

    (1) DumpFolder 转储Dump文件的目录,默认路径为%LOCALAPPDATA%\CrashDumps

    (2) DumpCount 最大Dump数,若转储的Dump数超出该限制,则会以最新转储的Dump文件替换最早的

    (3) DumpType 即Dump的类型,1-Mini Dump 2-Full Dump 0-Custom Dump

    (4) CustomDumpFlags 该值仅在DumpType=0时有效,可以定制转储Dump的内容。可以取前面定义的枚举类型MiniDumpType中某几个值之和,如MiniDumpWithDataSegs | MiniDumpWithUnloadedModules

    如果要针对某一个具体的应用程序来设置的话,可以在LocalDumps下面在以应用程序集的名称建一个项,然后同样要设置上述的几个值。

    例如,在上面的程序中将转储进程MiniDump的相关代码去掉,在LocalDumps下创建DumpDemo.exe项,设置DumpType=0,CustomDumpFlags=2(即MiniDumpWithFullMemory),DumpFolder=E:\dump\DumpDemo 。运行程序(DumpDemo.exe)后,在E:\dump\DumpDemo\ 目录下就可以得到一个Dump文件。

  • 相关阅读:
    android程序中界面太大太长太宽如何滚动?
    android textview段落开头空格问题
    android中textview设置为多行文本时,如何让文字从最顶开始显示
    论文写作
    spass按位置编码,进行排序题处理与分析
    Java基础知识
    秒杀系统-效果展示
    秒杀系统-高并发的优化
    秒杀系统-web
    秒杀系统-DAO
  • 原文地址:https://www.cnblogs.com/haihai1203/p/3395137.html
Copyright © 2011-2022 走看看