Monday, September 12, 2011

Update: I had previously posted a helper class for creating memory dumps of .NET processes. That class turned out to have some bugs in it, I've updated accordingly

Wednesday, August 24, 2011

Advanced .NET Debugging TechEd 2011 Presentation

I've just finished my TechEd 2011 presentation on advanced .NET debugging. I covered using WinDBG and SOS to troubleshoot memory leaks, deadlocks, race conditions.
You can download the powerpoint presentation here

Sunday, July 31, 2011

Helper class for creating memory dumps of a Managed Process

I'm giving a talk at TechEd NZ 2011 in about a month. As part of that talk, I'll mention creating memory dumps using the MiniDumpWriteDump function, and show a helper class which P/Invokes it

Here is that helper class (Updated 19 Sept 2011 to fix some bugs).

using System.Runtime.InteropServices;
using System;
using System.IO;
using System.Diagnostics;
using System.Threading;

public static class DbgHelp
    [StructLayout(LayoutKind.Sequential, Pack = 4)]
        public uint ThreadId;
        public IntPtr ExceptionPointers;

        public bool ClientPointers;

    static extern bool MiniDumpWriteDump(
        IntPtr hProcess,
        uint ProcessId,
        IntPtr hFile,
        [MarshalAs(UnmanagedType.I4)] MiniDumpType DumpType,
        IntPtr ExceptionParam, // Ptr to MINIDUMP_EXCEPTION_INFORMATION
        IntPtr UserStreamParam,
        IntPtr CallbackParam);

    static extern uint GetCurrentThreadId();

    enum MiniDumpType : int
        MiniDumpNormal = 0x00000000,
        MiniDumpWithDataSegs = 0x00000001,
        MiniDumpWithFullMemory = 0x00000002, // required for .NET apps
        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

    public static void WriteExceptionDump(string filePath)
        var proc = Process.GetCurrentProcess();
        int win32Error;
        if(!TryCreateDump(filePath, proc.Handle, (uint)proc.Id, GetCurrentThreadId(), Marshal.GetExceptionPointers(), out win32Error))
            throw new Exception("Couldn't create dump file! Error: 0x" + win32Error.ToString("X8"));

    public static bool TryCreateDump(string dumpFilePath, IntPtr processHandle, uint processId, uint threadId, IntPtr exceptionPointers, out int win32Error)
        bool success = false;
        int lastError = 0;

        // Dump on a seperate thread - IsBackground=false is important to stop the process exiting while we write the dump
        // also works around an issue of VS not being able to walk the callstack of the crashing thread
        var thread = new Thread(new ThreadStart(() => {
            // In-process dumps must ClientPointers = false
            // If ClientPointers is false, or if there are no ExceptionPointers we must pass IntPtr.Zero as ExceptionInfo
            var exceptionParam = IntPtr.Zero;
            if (processId != Process.GetCurrentProcess().Id && exceptionPointers != IntPtr.Zero)
                var ei = new MINIDUMP_EXCEPTION_INFORMATION {
                    ClientPointers = true, // in-process dump. True if we're dumping external processes
                    ExceptionPointers = exceptionPointers, // may be for CLR exceptions
                    ThreadId = threadId,
                exceptionParam = Marshal.AllocHGlobal(Marshal.SizeOf(ei));
                Marshal.PtrToStructure(exceptionParam, ei);

            using (var outputFile = new FileStream(dumpFilePath, FileMode.Create))
                success = MiniDumpWriteDump(

            if (!success)
                lastError = Marshal.GetLastWin32Error();

            if (exceptionParam != IntPtr.Zero)
        })) { IsBackground = false, Name = "MiniDump thread" };


        win32Error = lastError;
        return success;