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
http://orionedwards.blogspot.co.nz/2011/07/helper-class-for-creating-memory-dumps.html
Monday, September 12, 2011
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
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).
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)]
struct MINIDUMP_EXCEPTION_INFORMATION
{
public uint ThreadId;
public IntPtr ExceptionPointers;
[MarshalAs(UnmanagedType.Bool)]
public bool ClientPointers;
}
[DllImport("Dbghelp.dll")]
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);
[DllImport("kernel32.dll")]
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 IntPtr.zero 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(
processHandle,
processId,
outputFile.SafeFileHandle.DangerousGetHandle(),
MiniDumpType.MiniDumpWithFullMemory,
exceptionParam,
IntPtr.Zero,
IntPtr.Zero);
}
if (!success)
lastError = Marshal.GetLastWin32Error();
if (exceptionParam != IntPtr.Zero)
Marshal.FreeHGlobal(exceptionParam);
})) { IsBackground = false, Name = "MiniDump thread" };
thread.Start();
thread.Join();
win32Error = lastError;
return success;
}
}
Subscribe to:
Posts (Atom)