Mercurial > projects > ddbg_continued
diff src/minidump.d @ 1:4a9dcbd9e54f
-files of 0.13 beta
-fixes so that it now compiles with the current dmd version
author | marton@basel.hu |
---|---|
date | Tue, 05 Apr 2011 20:44:01 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/minidump.d Tue Apr 05 20:44:01 2011 +0200 @@ -0,0 +1,268 @@ +/* Ddbg - Win32 Debugger for the D programming language + * Copyright (c) 2007 Jascha Wetzel + * All rights reserved. See LICENSE.TXT for details. + */ + +import win32.dbghelp; +import win32.windef; +import win32.winbase; + +import std.string; + +import dbgprocess; +import util; + +/************************************************************************************************** + +**************************************************************************************************/ +class MiniDump +{ + enum UserStreamType : uint + { + DExceptionInfo = 0x10000, + ThreadInfo + } + + align(1) struct ThreadInfo + { + uint mainThreadId, + currentThreadId; + } + + static typeof(&win32.dbghelp.MiniDumpWriteDump) MiniDumpWriteDump; + static typeof(&win32.dbghelp.MiniDumpReadDumpStream) MiniDumpReadDumpStream; + + private void* map; + private HANDLE file, + fileMapping; + + MINIDUMP_THREAD[] threads; + uint selectedThread; + MINIDUMP_MEMORY_DESCRIPTOR[] memoryDescriptors; + EXCEPTION_RECORD* exceptionRecord; + + ThreadInfo* threadInfo; + + /********************************************************************************************** + + **********************************************************************************************/ + static this() + { + // TODO: load from exe dir if not XP + HINSTANCE dll = LoadLibrary(toStringz("dbghelp.dll")); + if ( dll !is null ) { + MiniDumpWriteDump = cast(typeof(MiniDumpWriteDump))GetProcAddress(dll, toStringz("MiniDumpWriteDump")); + MiniDumpReadDumpStream = cast(typeof(MiniDumpReadDumpStream))GetProcAddress(dll, toStringz("MiniDumpReadDumpStream")); + } + } + + /********************************************************************************************** + + **********************************************************************************************/ + this(string filename) + { + file = CreateFile(toStringz(filename), FILE_ALL_ACCESS, 0, null, OPEN_EXISTING, 0, null); + if ( file is null ) + throw new Exception("Couldn't read \""~filename~"\": "~lastError); + fileMapping = CreateFileMapping(file, null, PAGE_READONLY, 0, 0, null); + if ( fileMapping is null ) + throw new Exception("Couldn't create file mapping for \""~filename~"\": "~lastError); + map = MapViewOfFile(fileMapping, FILE_MAP_READ, 0, 0, 0); + if ( map is null ) + throw new Exception("Couldn't map view of file \""~filename~"\": "~lastError); + + MINIDUMP_DIRECTORY* mdDir; + void *streamPtr; + size_t streamSize; + + // load thread info + if ( !MiniDumpReadDumpStream(map, MINIDUMP_STREAM_TYPE.ThreadListStream, &mdDir, &streamPtr, &streamSize) ) + throw new Exception("Error no ThreadList in minidump \""~filename~"\": "~lastError); + MINIDUMP_THREAD_LIST* threadList = cast(MINIDUMP_THREAD_LIST*)streamPtr; + threads = (cast(MINIDUMP_THREAD*)(cast(ubyte*)streamPtr+4))[0..threadList.NumberOfThreads]; + + if ( !MiniDumpReadDumpStream(map, UserStreamType.ThreadInfo, &mdDir, &streamPtr, &streamSize) ) + throw new Exception("Error no Ddbg ThreadInfo in minidump \""~filename~"\": "~lastError); + threadInfo = cast(ThreadInfo*)streamPtr; + + // load memory info + if ( MiniDumpReadDumpStream(map, MINIDUMP_STREAM_TYPE.MemoryListStream, &mdDir, &streamPtr, &streamSize) ) + { + MINIDUMP_MEMORY_LIST* mml = cast(MINIDUMP_MEMORY_LIST*)streamPtr; + memoryDescriptors = (cast(MINIDUMP_MEMORY_DESCRIPTOR*)(cast(ubyte*)streamPtr+4))[0..mml.NumberOfMemoryRanges]; + } + + // load exception info + if ( MiniDumpReadDumpStream(map, MINIDUMP_STREAM_TYPE.ExceptionStream, &mdDir, &streamPtr, &streamSize) ) + { + MINIDUMP_EXCEPTION_STREAM* mes = cast(MINIDUMP_EXCEPTION_STREAM*)streamPtr; + foreach ( i, t; threads ) + { + if ( t.ThreadId == mes.ThreadId ) { + selectedThread = i; + break; + } + } + exceptionRecord = new EXCEPTION_RECORD; + exceptionRecord.ExceptionCode = mes.ExceptionRecord.ExceptionCode; + exceptionRecord.ExceptionFlags = mes.ExceptionRecord.ExceptionFlags; + exceptionRecord.ExceptionAddress = cast(void*)mes.ExceptionRecord.ExceptionAddress; + exceptionRecord.NumberParameters = 4; + exceptionRecord.ExceptionInformation[0] = 0; + exceptionRecord.ExceptionInformation[1] = 0; + exceptionRecord.ExceptionInformation[2] = 0; + exceptionRecord.ExceptionInformation[3] = 0; + } + + if ( exceptionRecord !is null && MiniDumpReadDumpStream(map, UserStreamType.DExceptionInfo, &mdDir, &streamPtr, &streamSize) ) + { + string className, + message; + void* ptr = streamPtr; + className = (cast(char*)(ptr+size_t.sizeof))[0..*cast(size_t*)ptr]; + ptr += className.length+size_t.sizeof; + message = (cast(char*)(ptr+size_t.sizeof))[0..*cast(size_t*)ptr]; + + exceptionRecord.NumberParameters = 4; + exceptionRecord.ExceptionInformation[0] = className.length; + exceptionRecord.ExceptionInformation[1] = cast(size_t)className.ptr; + exceptionRecord.ExceptionInformation[2] = message.length; + exceptionRecord.ExceptionInformation[3] = cast(size_t)message.ptr; + } + } + + /********************************************************************************************** + + **********************************************************************************************/ + ~this() + { + UnmapViewOfFile(map); + CloseHandle(fileMapping); + CloseHandle(file); + } + + static extern(Windows) bool callback(PVOID CallbackParam, PMINIDUMP_CALLBACK_INPUT CallbackInput, PMINIDUMP_CALLBACK_OUTPUT CallbackOutput) + { + DbgIO.println("MINIDUMP CALLBACK"); + return true; + } + + /********************************************************************************************** + + **********************************************************************************************/ + static bool haveMiniDump() + { + return MiniDumpWriteDump !is null; + } + + /********************************************************************************************** + + **********************************************************************************************/ + void* rvaToVa(size_t rva) + { + return map+rva; + } + + ubyte[] getMemory(MINIDUMP_LOCATION_DESCRIPTOR mld) + { + return (cast(ubyte*)rvaToVa(mld.Rva))[0..mld.DataSize]; + } + + CONTEXT* getContext() + { + return cast(CONTEXT*)rvaToVa(threads[selectedThread].ThreadContext.Rva); + } + + MINIDUMP_THREAD* thread() + { + return &threads[selectedThread]; + } + + ubyte[] readMemory(size_t ptr, size_t size) + { + foreach ( md; memoryDescriptors ) + { + size_t mdSize = md.Memory.DataSize, + mdBase = cast(size_t)md.StartOfMemoryRange; + debug DbgIO.println("MiniDump: Memory block 0x%x 0x%x", mdBase, mdSize); + + if ( ptr >= mdBase && ptr+size <= mdBase+mdSize ) + return getMemory(md.Memory)[ptr-mdBase..ptr-mdBase+size]; + } + debug DbgIO.println("Memory block 0x%x - 0x%x not available in minidump", ptr, ptr+size); + return null; + } + + void selectThread(size_t threadId) + { + foreach ( i, thread; threads ) + { + if ( threadId == thread.ThreadId ) { + selectedThread = i; + break; + } + } + } + + /********************************************************************************************** + + **********************************************************************************************/ + static bool writeMiniDump(string filename, DbgProcess process, uint threadId, EXCEPTION_RECORD* exrec=null, string exClassName=null, string exMsg=null) + { + if ( !haveMiniDump ) + return false; + + // create exception information + MINIDUMP_EXCEPTION_INFORMATION* eiPtr; + MINIDUMP_EXCEPTION_INFORMATION ei; + + MINIDUMP_USER_STREAM[] ustreams; + + if ( exrec !is null && (threadId in process.threads) !is null ) + { + EXCEPTION_POINTERS ep; + ep.ExceptionRecord = exrec; + CONTEXT ctx; + process.threads[threadId].getContext(ctx, CONTEXT_FULL | CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS); + ep.ContextRecord = &ctx; + + eiPtr = &ei; + ei.ExceptionPointers = &ep; + ei.ThreadId = threadId; + ei.ClientPointers = false; + + ustreams.length = ustreams.length+1; + ustreams[$-1].Type = UserStreamType.DExceptionInfo; + ubyte[] data; + size_t len = exClassName.length; + data ~= (cast(ubyte*)&len)[0..size_t.sizeof]; + data ~= cast(ubyte[])exClassName; + len = exMsg.length; + data ~= (cast(ubyte*)&len)[0..size_t.sizeof]; + data ~= cast(ubyte[])exMsg; + + ustreams[$-1].Buffer = data.ptr; + ustreams[$-1].BufferSize = data.length; + } + + // write custom thread info + ustreams.length = ustreams.length+1; + ustreams[$-1].Type = UserStreamType.ThreadInfo; + + ThreadInfo ti; + ti.mainThreadId = process.mainThreadId; + ti.currentThreadId = threadId; + ustreams[$-1].Buffer = &ti; + ustreams[$-1].BufferSize = ThreadInfo.sizeof; + + // write minidump + MINIDUMP_USER_STREAM_INFORMATION usi; + usi.UserStreamCount = ustreams.length; + usi.UserStreamArray = ustreams.ptr; + + auto file = CreateFile(toStringz(filename), FILE_ALL_ACCESS, 0, null, CREATE_ALWAYS, 0, null); + bool res = cast(bool)MiniDumpWriteDump(process.process_handle, process.processId, file, MINIDUMP_TYPE.MiniDumpNormal, eiPtr, &usi, null); + CloseHandle(file); + return res; + } +}