Create your own crash dumps

Sometimes programs will crash on your machine. Windows Error Reporting can send problem reports back to Microsoft. You can use the Windows Event log to see more detail about prior crashes. Some crashes will send crash dumps to Microsoft so that the crash can be fixed, perhaps in an update. Thousands of bugs in products, both Microsoft and non-Microsoft applications, have had bugs fixed due to this error reporting mechanism.

You can do something similar in your application: when you detect some faulting state of your application, you can create a crash dump file and examine it to see what happened.

In fact, a dump can be made even if the application has not crashed, and this could be useful for debugging non-fatal conditions.

Crash dumps can be examined by a variety of tools, including Visual Studio and WinDBG. Not all dumps are equal. A 64 bit dump of a 32 bit process is quite different from a 32 bit dump of the same process. There are both a 32 bit and 64 bit version of WinDbg.

Try examining a dump created by the code below in Visual Studio. File->Open->File-><point to the .DMP file>

Set the Debug->Symbol settings and click on one of the Debug options (highlighted). Then you’ll be presented with the debugger showing a debug environment for the crashed process.

clip_image002

There are many different kinds of crash dumps, or more exactly, there are many flags that can be specified when calling the API MiniDumpWriteDump. Also, a dump can be 32 bit or 64 bit.

The code has a minimal User Interface that allows the user to specify

· the name of the dump file to create

· the name of the process to dump, like ‘devenv’ for Visual Studio’s “devenv.exe” main process

· a list box with a bunch of flags which you can multi-select

· a button to Create the dump

The default flags set are those that include a full memory dump and

When done, the resulting dump file size and elapsed time are displayed in the status textbox. Thus you can quickly see how the size of the dump file is affected by the chosen flags.

Start Visual Studio, File->New Project->C# WPF application. Name it “CreateMiniDump”

Paste the code below to replace MainWindow.Xaml.cs

Try playing with creating a 64 bit dump: uncheck Project->Properties->Build->Prefer 32 bit

See also

Scan the Windows Event Log for your application crashes and hangs

Using Windows Error Reporting

<code>

 using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;

// !load \\ddelementary\autowatson\vsdbg\vsdbg.dll

namespace CreateMiniDump
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.Loaded += (ol, el) =>
            {
                IntPtr hFile = IntPtr.Zero;
                try
                {
                    if (IntPtr.Size == 4)
                    {
                        this.Title = "CreateMiniDump Running as 32 bit, creating 32 bit dumps";
                    }
                    else
                    {
                        this.Title = "CreateMiniDump Running as 64 bit, creating 64 bit dumps";
                    }
                    this.Height = 800;
                    this.Width = 800;
                    var sp = new StackPanel() { Orientation = Orientation.Vertical };
                    this.Content = sp;
                    var dumpFileName = System.IO.Path.Combine(
                              System.IO.Path.GetTempPath(),
                              "testdump.dmp");
                    var txtDumpFile = new TextBox()
                    {
                        Text = dumpFileName
                    };
                    sp.Children.Add(txtDumpFile);

                    var txtProcName = new TextBox()
                    {
                        ToolTip = "Process name without extension",
                        Text = "devenv"
                    };
                    sp.Children.Add(txtProcName);
                    var lstDumpType = new ListBox()
                    {
                        // allow multi select
                        SelectionMode = SelectionMode.Extended
                    };
                    lstDumpType.ItemsSource = Enum.GetValues(typeof(NativeMethods._MINIDUMP_TYPE));
                    // set initial value
                    // for a dump with memory info we want these:
                    foreach (var val in new[] {
                  NativeMethods._MINIDUMP_TYPE.MiniDumpWithFullMemory,
                  NativeMethods._MINIDUMP_TYPE.MiniDumpWithFullMemoryInfo,
                  NativeMethods._MINIDUMP_TYPE.MiniDumpWithHandleData,
                  NativeMethods._MINIDUMP_TYPE.MiniDumpWithThreadInfo
            })
                    {
                        var nval = (int)(Math.Log((int)val) / Math.Log(2)) + 1;
                        lstDumpType.SelectedItems.Add(
                                  lstDumpType.Items[nval]
                          );
                    }
                    sp.Children.Add(lstDumpType);

                    var btnGo = new Button()
                    {
                        Content = "_Create Dump",
                        Width = 200
                    };
                    sp.Children.Add(btnGo);
                    var txtStatus = new TextBox()
                    {
                        IsUndoEnabled = false,
                        VerticalScrollBarVisibility = ScrollBarVisibility.Auto,
                        MaxHeight = 400
                    };
                    sp.Children.Add(txtStatus);
                    btnGo.Click += (ob, eb) =>
                      {
                          try
                          {
                              var sw = new Stopwatch();
                              sw.Start();
                              dumpFileName = txtDumpFile.Text.Trim();
                              if (System.IO.File.Exists(dumpFileName))
                              {
                                  System.IO.File.Delete(dumpFileName);
                              }
                              hFile = NativeMethods.CreateFile(
                                dumpFileName,
                                NativeMethods.EFileAccess.GenericWrite,
                                NativeMethods.EFileShare.None,
                                lpSecurityAttributes: IntPtr.Zero,
                                dwCreationDisposition: NativeMethods.ECreationDisposition.CreateAlways,
                                dwFlagsAndAttributes: NativeMethods.EFileAttributes.Normal,
                                hTemplateFile: IntPtr.Zero
                              );
                              if (hFile == NativeMethods.INVALID_HANDLE_VALUE)
                              {
                                  var hr = Marshal.GetHRForLastWin32Error();
                                  var ex = Marshal.GetExceptionForHR(hr);
                                  throw ex;
                              }
                              NativeMethods._MINIDUMP_TYPE dumpType = NativeMethods._MINIDUMP_TYPE.MiniDumpNormal; // 0
                              foreach (var item in lstDumpType.SelectedItems)
                              {
                                  var dt = (NativeMethods._MINIDUMP_TYPE)item;
                                  dumpType |= dt;
                              }

                              var exceptInfo = new NativeMethods.MINIDUMP_EXCEPTION_INFORMATION();
                              var proc = Process.GetProcessesByName(
                                  txtProcName.Text.Trim()
                                  ).FirstOrDefault();

                              if (!proc.Is32BitProcess() && IntPtr.Size == 4)
                              {
                                  throw new InvalidOperationException(
                                    "Can't create 32 bit dump of 64 bit process"
                                    );
                              }

                              var result = NativeMethods.MiniDumpWriteDump(
                                        proc.Handle,
                                        proc.Id,
                                        hFile,
                                        dumpType,
                                        ref exceptInfo,
                                        UserStreamParam: IntPtr.Zero,
                                        CallbackParam: IntPtr.Zero
                                        );
                              if (result == false)
                              {
                                  var hr = Marshal.GetHRForLastWin32Error();
                                  var ex = Marshal.GetExceptionForHR(hr);
                                  throw ex;
                              }

                              txtStatus.Text = string.Format(
                                        "Dump Created. Pid= {0} {1}\r File size = {2:n0}\rElapsed = {3:n3}\r",
                                        proc.Id,
                                        dumpType,
                                        (new System.IO.FileInfo(dumpFileName)).Length,
                                        sw.Elapsed.TotalSeconds
                                        );
                          }
                          catch (Exception ex)
                          {
                              txtStatus.Text = ex.ToString();
                          }
                          finally
                          {
                              NativeMethods.CloseHandle(hFile);
                          }
                      };
                }
                catch (Exception ex)
                {
                    this.Content = ex.ToString();
                }
            };
        }
    }
    public static class ExtensionMethods
    {
        public static bool Is32BitProcess(this Process proc)
        {
            bool fIs32bit = false;
            // if we're runing on 32bit, default to true
            if (IntPtr.Size == 4)
            {
                fIs32bit = true;
            }
            bool fIsRunningUnderWow64 = false;
            // if machine is 32 bit then all procs are 32 bit
            if (NativeMethods.IsWow64Process(NativeMethods.GetCurrentProcess(), out fIsRunningUnderWow64)
                && fIsRunningUnderWow64)
            {
                // current OS is 64 bit
                if (NativeMethods.IsWow64Process(proc.Handle, out fIsRunningUnderWow64)
                      && fIsRunningUnderWow64)
                {
                    fIs32bit = true;
                }
                else
                {
                    fIs32bit = false;
                }
            }
            return fIs32bit;
        }
    }
    public static partial class NativeMethods
    {
        [DllImport("Dbghelp.dll")]
        public static extern bool MiniDumpWriteDump(
            IntPtr hProcess,
            int ProcessId,
            IntPtr hFile,
            _MINIDUMP_TYPE DumpType,
            ref MINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
            IntPtr UserStreamParam,
            IntPtr CallbackParam
            );
        //https://msdn.microsoft.com/en-us/library/windows/desktop/ms680519%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
        [Flags]
        public enum _MINIDUMP_TYPE
        {
            MiniDumpNormal = 0x00000000,
            MiniDumpWithDataSegs = 0x00000001,
            MiniDumpWithFullMemory = 0x00000002,
            MiniDumpWithHandleData = 0x00000004,
            MiniDumpFilterMemory = 0x00000008,
            MiniDumpScanMemory = 0x00000010,
            MiniDumpWithUnloadedModules = 0x00000020,
            MiniDumpWithIndirectlyReferencedMemory = 0x00000040,
            MiniDumpFilterModulePaths = 0x00000080,
            MiniDumpWithProcessThreadData = 0x00000100,
            MiniDumpWithPrivateReadWriteMemory = 0x00000200,
            MiniDumpWithoutOptionalData = 0x00000400,
            MiniDumpWithFullMemoryInfo = 0x00000800,
            MiniDumpWithThreadInfo = 0x00001000,
            MiniDumpWithCodeSegs = 0x00002000,
            MiniDumpWithoutAuxiliaryState = 0x00004000,
            MiniDumpWithFullAuxiliaryState = 0x00008000,
            MiniDumpWithPrivateWriteCopyMemory = 0x00010000,
            MiniDumpIgnoreInaccessibleMemory = 0x00020000,
            MiniDumpWithTokenInformation = 0x00040000,
            MiniDumpWithModuleHeaders = 0x00080000,
            MiniDumpFilterTriage = 0x00100000,
            MiniDumpValidTypeFlags = 0x001fffff,
        };
        /*
         * 
    https://msdn.microsoft.com/en-us/library/windows/desktop/bb513622(v=vs.85).aspx
    WER_DUMP_TYPE:
    WerDumpTypeHeapDump
        MiniDumpWithDataSegs
        MiniDumpWithProcessThreadData
        MiniDumpWithHandleData
        MiniDumpWithPrivateReadWriteMemory
        MiniDumpWithUnloadedModules
        MiniDumpWithFullMemoryInfo
        MiniDumpWithThreadInfo (Windows 7 and later)
        MiniDumpWithTokenInformation (Windows 7 and later)
        MiniDumpWithPrivateWriteCopyMemory 
    WerDumpTypeMicroDump
        MiniDumpWithDataSegs
        MiniDumpWithUnloadedModules
        MiniDumpWithProcessThreadData
        MiniDumpWithoutOptionalData

    WerDumpTypeMiniDump
        MiniDumpWithDataSegs
        MiniDumpWithUnloadedModules
        MiniDumpWithProcessThreadData
        MiniDumpWithTokenInformation 
         */

        [StructLayout(LayoutKind.Sequential, Pack = 4)]
        public struct MINIDUMP_EXCEPTION_INFORMATION
        {
            public uint ThreadId;
            public IntPtr ExceptionPointers;
            public int ClientPointers;
        }

        [DllImport("kernel32.dll",
          SetLastError = true,
          CharSet = CharSet.Auto)]
        public static extern IntPtr CreateFile(
                string lpFileName,
                EFileAccess dwDesiredAccess,
                EFileShare dwShareMode,
                IntPtr lpSecurityAttributes,
                ECreationDisposition dwCreationDisposition,
                EFileAttributes dwFlagsAndAttributes,
                IntPtr hTemplateFile
            );

        [DllImport("kernel32.dll",
          SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CloseHandle(IntPtr hObject);

        public static IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
        [Flags]
        public enum EFileAccess : uint
        {
            //
            // Standart Section
            //

            AccessSystemSecurity = 0x1000000,   // AccessSystemAcl access type
            MaximumAllowed = 0x2000000,     // MaximumAllowed access type

            Delete = 0x10000,
            ReadControl = 0x20000,
            WriteDAC = 0x40000,
            WriteOwner = 0x80000,
            Synchronize = 0x100000,

            StandardRightsRequired = 0xF0000,
            StandardRightsRead = ReadControl,
            StandardRightsWrite = ReadControl,
            StandardRightsExecute = ReadControl,
            StandardRightsAll = 0x1F0000,
            SpecificRightsAll = 0xFFFF,

            FILE_READ_DATA = 0x0001,        // file & pipe
            FILE_LIST_DIRECTORY = 0x0001,       // directory
            FILE_WRITE_DATA = 0x0002,       // file & pipe
            FILE_ADD_FILE = 0x0002,         // directory
            FILE_APPEND_DATA = 0x0004,      // file
            FILE_ADD_SUBDIRECTORY = 0x0004,     // directory
            FILE_CREATE_PIPE_INSTANCE = 0x0004, // named pipe
            FILE_READ_EA = 0x0008,          // file & directory
            FILE_WRITE_EA = 0x0010,         // file & directory
            FILE_EXECUTE = 0x0020,          // file
            FILE_TRAVERSE = 0x0020,         // directory
            FILE_DELETE_CHILD = 0x0040,     // directory
            FILE_READ_ATTRIBUTES = 0x0080,      // all
            FILE_WRITE_ATTRIBUTES = 0x0100,     // all

            //
            // Generic Section
            //

            GenericRead = 0x80000000,
            GenericWrite = 0x40000000,
            GenericExecute = 0x20000000,
            GenericAll = 0x10000000,

            SPECIFIC_RIGHTS_ALL = 0x00FFFF,
            FILE_ALL_ACCESS =
            StandardRightsRequired |
            Synchronize |
            0x1FF,

            FILE_GENERIC_READ =
            StandardRightsRead |
            FILE_READ_DATA |
            FILE_READ_ATTRIBUTES |
            FILE_READ_EA |
            Synchronize,

            FILE_GENERIC_WRITE =
            StandardRightsWrite |
            FILE_WRITE_DATA |
            FILE_WRITE_ATTRIBUTES |
            FILE_WRITE_EA |
            FILE_APPEND_DATA |
            Synchronize,

            FILE_GENERIC_EXECUTE =
            StandardRightsExecute |
              FILE_READ_ATTRIBUTES |
              FILE_EXECUTE |
              Synchronize
        }

        [Flags]
        public enum EFileShare : uint
        {
            /// <summary>
            /// 
            /// </summary>
            None = 0x00000000,
            /// <summary>
            /// Enables subsequent open operations on an object to request read access. 
            /// Otherwise, other processes cannot open the object if they request read access. 
            /// If this flag is not specified, but the object has been opened for read access, the function fails.
            /// </summary>
            Read = 0x00000001,
            /// <summary>
            /// Enables subsequent open operations on an object to request write access. 
            /// Otherwise, other processes cannot open the object if they request write access. 
            /// If this flag is not specified, but the object has been opened for write access, the function fails.
            /// </summary>
            Write = 0x00000002,
            /// <summary>
            /// Enables subsequent open operations on an object to request delete access. 
            /// Otherwise, other processes cannot open the object if they request delete access.
            /// If this flag is not specified, but the object has been opened for delete access, the function fails.
            /// </summary>
            Delete = 0x00000004
        }

        public enum ECreationDisposition : uint
        {
            /// <summary>
            /// Creates a new file. The function fails if a specified file exists.
            /// </summary>
            New = 1,
            /// <summary>
            /// Creates a new file, always. 
            /// If a file exists, the function overwrites the file, clears the existing attributes, combines the specified file attributes, 
            /// and flags with FILE_ATTRIBUTE_ARCHIVE, but does not set the security descriptor that the SECURITY_ATTRIBUTES structure specifies.
            /// </summary>
            CreateAlways = 2,
            /// <summary>
            /// Opens a file. The function fails if the file does not exist. 
            /// </summary>
            OpenExisting = 3,
            /// <summary>
            /// Opens a file, always. 
            /// If a file does not exist, the function creates a file as if dwCreationDisposition is CREATE_NEW.
            /// </summary>
            OpenAlways = 4,
            /// <summary>
            /// Opens a file and truncates it so that its size is 0 (zero) bytes. The function fails if the file does not exist.
            /// The calling process must open the file with the GENERIC_WRITE access right. 
            /// </summary>
            TruncateExisting = 5
        }

        [Flags]
        public enum EFileAttributes : uint
        {
            Readonly = 0x00000001,
            Hidden = 0x00000002,
            System = 0x00000004,
            Directory = 0x00000010,
            Archive = 0x00000020,
            Device = 0x00000040,
            Normal = 0x00000080,
            Temporary = 0x00000100,
            SparseFile = 0x00000200,
            ReparsePoint = 0x00000400,
            Compressed = 0x00000800,
            Offline = 0x00001000,
            NotContentIndexed = 0x00002000,
            Encrypted = 0x00004000,
            Write_Through = 0x80000000,
            Overlapped = 0x40000000,
            NoBuffering = 0x20000000,
            RandomAccess = 0x10000000,
            SequentialScan = 0x08000000,
            DeleteOnClose = 0x04000000,
            BackupSemantics = 0x02000000,
            PosixSemantics = 0x01000000,
            OpenReparsePoint = 0x00200000,
            OpenNoRecall = 0x00100000,
            FirstPipeInstance = 0x00080000
        }


        [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool IsWow64Process(
              [In] IntPtr hProcess,
              [Out, MarshalAs(UnmanagedType.Bool)] out bool wow64Process
              );
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr GetCurrentProcess();
    }
}

</code>

Comments

  • Anonymous
    September 06, 2015
    The comment has been removed