# HG changeset patch # User korDen # Date 1282978292 -14400 # Node ID 6bdecc3f4569e94dd2b0653d8a3b36b0e0fdffc2 # Parent c876339731a4d28779205467165e19c9db6b2d66 Get rid of win32 bindings diff -r c876339731a4 -r 6bdecc3f4569 commands.txt --- a/commands.txt Tue Aug 24 16:59:45 2010 +0400 +++ b/commands.txt Sat Aug 28 10:51:32 2010 +0400 @@ -19,11 +19,7 @@ ddmd.def C:\dmd2.032\src\dmd\dmd.lib main.d -win32\windef.d -win32\winuser.d -win32\wingdi.d -dlib\CrashHandler.d -dbg\ui\CrashWindow.d +dbg\CallStackInfo.d dbg\Debug.d dbg\symbol\CodeView.d dbg\image\PE.d diff -r c876339731a4 -r 6bdecc3f4569 dbg/CallStackInfo.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dbg/CallStackInfo.d Sat Aug 28 10:51:32 2010 +0400 @@ -0,0 +1,257 @@ +/** + A simple runtime crash handler which collects various informations about + the crash such as registers, stack traces, and loaded modules. + + TODO: + * Threading support + * Stack dumps + + Authors: + Jeremie Pelletier + + License: + Public Domain +*/ +module dbg.CallStackInfo; + +import dbg.Debug; +import dbg.image.PE; + +import core.stdc.stdio; +import core.sys.windows.windows; + +class CallStackInfo +{ + this(EXCEPTION_POINTERS* e = null) + { + size_t[16] buff; + size_t[] backtrace = buff[]; + size_t numTraces = 0; + + bool skipFirst = false; + + size_t ip = void, bp = void; + if (e !is null) { + ip = e.ContextRecord.Eip; + bp = e.ContextRecord.Ebp; + + error = _d_translate_se_to_d_exception(e.ExceptionRecord); + append(backtrace, numTraces, ip); + } else { + asm { + mov bp, EBP; + } + } + + while (true) { + ip = cast(size_t)*(cast(void**)bp + 1); + if (ip == 0) break; + + append(backtrace, numTraces, ip); + + bp = cast(size_t)*cast(void**)bp; + } + + frames = new StackFrameInfo[numTraces]; + ResolveStackFrames(backtrace[0..numTraces], frames); + } + + Throwable error; + StackFrameInfo[] frames; + + string toString() { + string text; + + if (error !is null) { + text ~= error.toString() ~ "\n"; + } + + text ~= "Stack trace:\n------------------\n"; + char buffer[128]; + foreach(ref frame; frames) { + with(frame.fileLine) if(line) { + auto len = snprintf(buffer.ptr, buffer.length, "%u", line); + text ~= file ~ ":" ~ buffer[0 .. len] ~ "\r\n"; + } + } + + text ~= '\0'; + + return text; + } + + void dump() { + if (error !is null) { + printf("%.*s\n", error.toString()); + } + + printf("Stack trace:\n------------------\n"); + foreach(ref frame; frames) { + with(frame.fileLine) if (line) { + printf("%.*s:%d\r\n", file, line); + } + } + } + +private: + + struct StackFrameInfo { + size_t va; + string moduleName; + SymbolInfo symbol; + FileLineInfo fileLine; + } + + struct DebugImage { + DebugImage* next; + string moduleName; + size_t baseAddress; + uint rvaOffset; + IExecutableImage exeModule; + ISymbolicDebugInfo debugInfo; + } + + void ResolveStackFrames(size_t[] backtrace, StackFrameInfo[] frames) const { + StackFrameInfo* frame = void; + DebugImage* imageList, image = void; + char[255] buffer = void; + uint len = void; + uint rva = void; + + version(Windows) MEMORY_BASIC_INFORMATION mbi = void; + + foreach(i, va; backtrace) { + frame = &frames[i]; + frame.va = va; + + // mbi.Allocation base is the handle to stack frame's module + VirtualQuery(cast(void*)va, &mbi, MEMORY_BASIC_INFORMATION.sizeof); + if(!mbi.AllocationBase) break; + + image = imageList; + while(image) { + if(image.baseAddress == cast(size_t)mbi.AllocationBase) break; + image = image.next; + } + + if(!image) { + image = new DebugImage; + + with(*image) { + next = imageList; + imageList = image; + baseAddress = cast(size_t)mbi.AllocationBase; + + len = GetModuleFileNameA(cast(HMODULE)baseAddress, buffer.ptr, buffer.length); + moduleName = buffer[0 .. len].idup; + if (len != 0) { + exeModule = new PEImage(moduleName); + rvaOffset = baseAddress + exeModule.codeOffset; + debugInfo = exeModule.debugInfo; + } + } + } + + frame.moduleName = image.moduleName; + + if(!image.debugInfo) continue; + + rva = va - image.rvaOffset; + + with(image.debugInfo) { + frame.symbol = ResolveSymbol(rva); + frame.fileLine = ResolveFileLine(rva); + } + } + + while(imageList) { + image = imageList.next; + delete imageList.debugInfo; + delete imageList.exeModule; + delete imageList; + imageList = image; + } + } +} + +void CrashHandlerInit() { + //SetErrorMode(SetErrorMode(0) | SEM_FAILCRITICALERRORS); + SetErrorMode(0); + SetUnhandledExceptionFilter(&UnhandledExceptionHandler); +} + +enum EXCEPTION_EXECUTE_HANDLER = 1; + +extern(Windows) int UnhandledExceptionHandler(EXCEPTION_POINTERS* e) { + scope CallStackInfo info = new CallStackInfo(e); + info.dump(); + + return EXCEPTION_EXECUTE_HANDLER; +} + +extern (Windows) extern UINT SetErrorMode(UINT); +alias LONG function(EXCEPTION_POINTERS*) PTOP_LEVEL_EXCEPTION_FILTER; +extern (Windows) PTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter(PTOP_LEVEL_EXCEPTION_FILTER); + +void append(T)(T[] array, ref size_t index, T value) +{ + size_t capacity = array.length; + assert(capacity >= index); + if (capacity == index) { + if (capacity < 8) { + capacity = 8; + } else { + array.length = capacity * 2; + } + } + + array[index++] = value; +} + +struct EXCEPTION_POINTERS { + EXCEPTION_RECORD* ExceptionRecord; + CONTEXT* ContextRecord; +} + +const size_t EXCEPTION_MAXIMUM_PARAMETERS = 15; + +struct EXCEPTION_RECORD { + DWORD ExceptionCode; + DWORD ExceptionFlags; + EXCEPTION_RECORD* ExceptionRecord; + PVOID ExceptionAddress; + DWORD NumberParameters; + DWORD[EXCEPTION_MAXIMUM_PARAMETERS] ExceptionInformation; +} + +const MAXIMUM_SUPPORTED_EXTENSION = 512; + +struct CONTEXT { + DWORD ContextFlags; + DWORD Dr0; + DWORD Dr1; + DWORD Dr2; + DWORD Dr3; + DWORD Dr6; + DWORD Dr7; + FLOATING_SAVE_AREA FloatSave; + DWORD SegGs; + DWORD SegFs; + DWORD SegEs; + DWORD SegDs; + DWORD Edi; + DWORD Esi; + DWORD Ebx; + DWORD Edx; + DWORD Ecx; + DWORD Eax; + DWORD Ebp; + DWORD Eip; + DWORD SegCs; + DWORD EFlags; + DWORD Esp; + DWORD SegSs; + BYTE[MAXIMUM_SUPPORTED_EXTENSION] ExtendedRegisters; +} + +extern(C) Throwable _d_translate_se_to_d_exception(EXCEPTION_RECORD* exception_record); \ No newline at end of file diff -r c876339731a4 -r 6bdecc3f4569 dbg/image/PE.d --- a/dbg/image/PE.d Tue Aug 24 16:59:45 2010 +0400 +++ b/dbg/image/PE.d Sat Aug 28 10:51:32 2010 +0400 @@ -12,9 +12,7 @@ */ module dbg.image.PE; -version(Windows) { - -import std.c.string : strncmp; +import core.stdc.string : strncmp; import dbg.Debug; import dbg.symbol.CodeView; //import dbg.symbol.COFF; @@ -24,24 +22,7 @@ //import sys.windows.Information : CloseHandle; //import sys.windows.Image; -import win32.windows; -import win32.winbase; - -enum IMAGE_SIZEOF_NT_OPTIONAL64_HEADER = 240; - -struct IMAGE_NT_HEADERS64 { - DWORD Signature; - IMAGE_FILE_HEADER FileHeader; - IMAGE_OPTIONAL_HEADER64 OptionalHeader; -} - -auto IMAGE_FIRST_SECTION64( const(IMAGE_NT_HEADERS64*) ntheader ) { - return cast(PIMAGE_SECTION_HEADER) ((cast(UINT_PTR)ntheader) + IMAGE_NT_HEADERS64.OptionalHeader.offsetof + (cast(PIMAGE_NT_HEADERS64)(ntheader)).FileHeader.SizeOfOptionalHeader); -} - -auto IMAGE_FIRST_SECTION32( const(IMAGE_NT_HEADERS32*) ntheader ) { - return cast(PIMAGE_SECTION_HEADER)((cast(UINT_PTR)ntheader) + IMAGE_NT_HEADERS32.OptionalHeader.offsetof + (cast(PIMAGE_NT_HEADERS32)ntheader).FileHeader.SizeOfOptionalHeader); -} +import core.sys.windows.windows; class PEImage : IExecutableImage { /** @@ -62,9 +43,9 @@ null, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, null); if(_file == INVALID_HANDLE_VALUE) SystemException(); - GetFileSizeEx(_file, &_fileSize); + _fileSize = GetFileSize(_file, null); - _map = CreateFileMapping(_file, null, PAGE_READONLY, 0, 0, null); + _map = CreateFileMappingA(_file, null, PAGE_READONLY, 0, 0, null); if(!_map) SystemException(); _view = cast(const(ubyte)*)MapViewOfFile(_map, FILE_MAP_READ, 0, 0, 0); @@ -139,7 +120,7 @@ Get the raw image data */ const(ubyte)[] data() const { - return _view[0 .. cast(size_t)_fileSize.QuadPart]; + return _view[0 .. _fileSize]; } /** @@ -310,13 +291,13 @@ Verify a file offset before accessing it */ void CheckOffset(long offset) const { - if(offset > _fileSize.QuadPart) throw new PECorruptedException(this); + if (offset > _fileSize) throw new PECorruptedException(this); } string _filename; HANDLE _file; HANDLE _map; - LARGE_INTEGER _fileSize; + size_t _fileSize; bool _is64; union { @@ -358,4 +339,267 @@ } } -} // version(Windows) +align(2): +struct IMAGE_DOS_HEADER { + WORD e_magic; + WORD e_cblp; + WORD e_cp; + WORD e_crlc; + WORD e_cparhdr; + WORD e_minalloc; + WORD e_maxalloc; + WORD e_ss; + WORD e_sp; + WORD e_csum; + WORD e_ip; + WORD e_cs; + WORD e_lfarlc; + WORD e_ovno; + WORD[4] e_res; + WORD e_oemid; + WORD e_oeminfo; + WORD[10] e_res2; + LONG e_lfanew; +} + +align(4) struct IMAGE_NT_HEADERS32 { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER32 OptionalHeader; +} + +align(4) struct IMAGE_NT_HEADERS64 { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER64 OptionalHeader; +} + +align(4): +struct IMAGE_FILE_HEADER { + WORD Machine; + WORD NumberOfSections; + DWORD TimeDateStamp; + DWORD PointerToSymbolTable; + DWORD NumberOfSymbols; + WORD SizeOfOptionalHeader; + WORD Characteristics; +} + +struct IMAGE_OPTIONAL_HEADER32 { + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + DWORD BaseOfData; + DWORD ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + DWORD SizeOfStackReserve; + DWORD SizeOfStackCommit; + DWORD SizeOfHeapReserve; + DWORD SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] DataDirectory; +} + +alias ulong ULONGLONG; + +struct IMAGE_OPTIONAL_HEADER64 { + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + ULONGLONG ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + ULONGLONG SizeOfStackReserve; + ULONGLONG SizeOfStackCommit; + ULONGLONG SizeOfHeapReserve; + ULONGLONG SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] DataDirectory; +} + +enum { + IMAGE_DOS_SIGNATURE = 0x5A4D, + IMAGE_OS2_SIGNATURE = 0x454E, + IMAGE_OS2_SIGNATURE_LE = 0x454C, + IMAGE_VXD_SIGNATURE = 0x454C, + IMAGE_NT_SIGNATURE = 0x4550 +} + +const size_t + IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16, + IMAGE_SIZEOF_ROM_OPTIONAL_HEADER = 56, + IMAGE_SIZEOF_STD_OPTIONAL_HEADER = 28, + IMAGE_SIZEOF_NT_OPTIONAL32_HEADER = 224, + IMAGE_SIZEOF_NT_OPTIONAL64_HEADER = 240, + IMAGE_SIZEOF_SHORT_NAME = 8, + IMAGE_SIZEOF_SECTION_HEADER = 40, + IMAGE_SIZEOF_SYMBOL = 18, + IMAGE_SIZEOF_AUX_SYMBOL = 18, + IMAGE_SIZEOF_RELOCATION = 10, + IMAGE_SIZEOF_BASE_RELOCATION = 8, + IMAGE_SIZEOF_LINENUMBER = 6, + IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR = 60, + SIZEOF_RFPO_DATA = 16; + +struct IMAGE_DATA_DIRECTORY { + DWORD VirtualAddress; + DWORD Size; +} + +// IMAGE_OPTIONAL_HEADER.Magic +enum : WORD { + IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x010B, + IMAGE_ROM_OPTIONAL_HDR_MAGIC = 0x0107, + IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x020B +} + +struct IMAGE_SECTION_HEADER { + BYTE[IMAGE_SIZEOF_SHORT_NAME] Name; + union _Misc { + DWORD PhysicalAddress; + DWORD VirtualSize; + } + _Misc Misc; + DWORD VirtualAddress; + DWORD SizeOfRawData; + DWORD PointerToRawData; + DWORD PointerToRelocations; + DWORD PointerToLinenumbers; + WORD NumberOfRelocations; + WORD NumberOfLinenumbers; + DWORD Characteristics; +} + +// IMAGE_SECTION_HEADER.Characteristics +const DWORD + IMAGE_SCN_TYPE_REG = 0x00000000, + IMAGE_SCN_TYPE_DSECT = 0x00000001, + IMAGE_SCN_TYPE_NOLOAD = 0x00000002, + IMAGE_SCN_TYPE_GROUP = 0x00000004, + IMAGE_SCN_TYPE_NO_PAD = 0x00000008, + IMAGE_SCN_TYPE_COPY = 0x00000010, + IMAGE_SCN_CNT_CODE = 0x00000020, + IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040, + IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080, + IMAGE_SCN_LNK_OTHER = 0x00000100, + IMAGE_SCN_LNK_INFO = 0x00000200, + IMAGE_SCN_TYPE_OVER = 0x00000400, + IMAGE_SCN_LNK_REMOVE = 0x00000800, + IMAGE_SCN_LNK_COMDAT = 0x00001000, + IMAGE_SCN_MEM_FARDATA = 0x00008000, + IMAGE_SCN_GPREL = 0x00008000, + IMAGE_SCN_MEM_PURGEABLE = 0x00020000, + IMAGE_SCN_MEM_16BIT = 0x00020000, + IMAGE_SCN_MEM_LOCKED = 0x00040000, + IMAGE_SCN_MEM_PRELOAD = 0x00080000, + IMAGE_SCN_ALIGN_1BYTES = 0x00100000, + IMAGE_SCN_ALIGN_2BYTES = 0x00200000, + IMAGE_SCN_ALIGN_4BYTES = 0x00300000, + IMAGE_SCN_ALIGN_8BYTES = 0x00400000, + IMAGE_SCN_ALIGN_16BYTES = 0x00500000, + IMAGE_SCN_ALIGN_32BYTES = 0x00600000, + IMAGE_SCN_ALIGN_64BYTES = 0x00700000, + IMAGE_SCN_ALIGN_128BYTES = 0x00800000, + IMAGE_SCN_ALIGN_256BYTES = 0x00900000, + IMAGE_SCN_ALIGN_512BYTES = 0x00A00000, + IMAGE_SCN_ALIGN_1024BYTES = 0x00B00000, + IMAGE_SCN_ALIGN_2048BYTES = 0x00C00000, + IMAGE_SCN_ALIGN_4096BYTES = 0x00D00000, + IMAGE_SCN_ALIGN_8192BYTES = 0x00E00000, + IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000, + IMAGE_SCN_MEM_DISCARDABLE = 0x02000000, + IMAGE_SCN_MEM_NOT_CACHED = 0x04000000, + IMAGE_SCN_MEM_NOT_PAGED = 0x08000000, + IMAGE_SCN_MEM_SHARED = 0x10000000, + IMAGE_SCN_MEM_EXECUTE = 0x20000000, + IMAGE_SCN_MEM_READ = 0x40000000, + IMAGE_SCN_MEM_WRITE = 0x80000000; + +// ImageDirectoryEntryToDataEx() +enum : USHORT { + IMAGE_DIRECTORY_ENTRY_EXPORT = 0, + IMAGE_DIRECTORY_ENTRY_IMPORT, + IMAGE_DIRECTORY_ENTRY_RESOURCE, + IMAGE_DIRECTORY_ENTRY_EXCEPTION, + IMAGE_DIRECTORY_ENTRY_SECURITY, + IMAGE_DIRECTORY_ENTRY_BASERELOC, + IMAGE_DIRECTORY_ENTRY_DEBUG, + IMAGE_DIRECTORY_ENTRY_COPYRIGHT, // = 7 + IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7, + IMAGE_DIRECTORY_ENTRY_GLOBALPTR, + IMAGE_DIRECTORY_ENTRY_TLS, + IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, + IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT, + IMAGE_DIRECTORY_ENTRY_IAT, + IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT, + IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, // = 14 +} + +IMAGE_SECTION_HEADER* IMAGE_FIRST_SECTION32(const(IMAGE_NT_HEADERS32)* h) { + return cast(IMAGE_SECTION_HEADER*)((cast(char*)&h.OptionalHeader) + h.FileHeader.SizeOfOptionalHeader); +} + +IMAGE_SECTION_HEADER* IMAGE_FIRST_SECTION64(const(IMAGE_NT_HEADERS64)* h) { + return cast(IMAGE_SECTION_HEADER*)((cast(char*)&h.OptionalHeader) + h.FileHeader.SizeOfOptionalHeader); +} + +struct IMAGE_DEBUG_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD Type; + DWORD SizeOfData; + DWORD AddressOfRawData; + DWORD PointerToRawData; +} + +enum : DWORD { + IMAGE_DEBUG_TYPE_UNKNOWN, + IMAGE_DEBUG_TYPE_COFF, + IMAGE_DEBUG_TYPE_CODEVIEW, + IMAGE_DEBUG_TYPE_FPO, + IMAGE_DEBUG_TYPE_MISC, + IMAGE_DEBUG_TYPE_EXCEPTION, + IMAGE_DEBUG_TYPE_FIXUP, + IMAGE_DEBUG_TYPE_OMAP_TO_SRC, + IMAGE_DEBUG_TYPE_OMAP_FROM_SRC, + IMAGE_DEBUG_TYPE_BORLAND // = 9 +} \ No newline at end of file diff -r c876339731a4 -r 6bdecc3f4569 dbg/ui/CrashWindow.d --- a/dbg/ui/CrashWindow.d Tue Aug 24 16:59:45 2010 +0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,372 +0,0 @@ -/** - A window used to display the data from a CrashInfo struct generated by the - runtime's crash handler. - - TODO: - * Send report - need SMTP implementation - * Save report - - Authors: - Jeremie Pelletier - - License: - Public Domain -*/ -module dbg.ui.CrashWindow; - -import std.c.string; -import dlib.CrashHandler; -import dbg.Debug : SystemException; - -import std.stdio; - -private enum { - ReportWindowWidth = 640, - ReportWindowHeight = 480, - ReportWindowMinWidth = 320, - ReportWindowMinHeight = 240, - ReportWindowTitle = "Unhandled exception!" -} - -// ---------------------------------------------------------------------------- -// W i n 3 2 -// ---------------------------------------------------------------------------- - -version(Windows) { - -import win32.windows; - -private enum { - ID_LABEL = 100, - ID_SAVE_BTN = 101, - ID_SEND_BTN = 102, - ID_CLOSE_BTN = 103, - ID_REPORT = 104 -} - -enum CLEARTYPE_QUALITY = 5; -enum LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x20; - -/** - Create the crash window for the given crash information, the routine will - return when the window is closed. -*/ -void ShowCrashWindow(CrashInfo* crashInfo) -in { - assert(crashInfo); -} -body { - try { - - HINSTANCE inst = GetModuleHandle(null); - - WNDCLASSEXA wc; - wc.cbSize = WNDCLASSEX.sizeof; - wc.lpfnWndProc = &ReportWndProc; - wc.hInstance = inst; - wc.hIcon = cast(HICON)LoadImage(HINSTANCE.init, MAKEINTRESOURCE(OIC_ERROR), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); - wc.hCursor = cast(HCURSOR)LoadImage(HINSTANCE.init, MAKEINTRESOURCE(OCR_NORMAL), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE); - wc.hbrBackground = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); - wc.lpszClassName = "CrashWindowClass"; - - if(!RegisterClassExA(&wc)) SystemException(); - scope(exit) if(!UnregisterClassA("CrashWindowClass", inst)) SystemException(); - - RECT rc = void; - GetClientRect(GetDesktopWindow(), &rc); - - writeln(crashInfo.toString); - - HWND wnd = CreateWindowExA( - WS_EX_WINDOWEDGE, - "CrashWindowClass", ReportWindowTitle, - WS_OVERLAPPEDWINDOW | WS_VISIBLE, - (rc.right >> 1) - (ReportWindowWidth >> 1), (rc.bottom >> 1) - (ReportWindowHeight >> 1), - ReportWindowWidth, ReportWindowHeight, - HWND.init, HMENU.init, inst, cast(void*)crashInfo.toString.ptr - ); - if(!wnd) SystemException(); - - MSG msg = void; - while(GetMessage(&msg, HWND.init, 0, 0)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - } // try - catch(Throwable e) { - MessageBoxA(HWND.init, (e.toString ~ '\0').ptr, "Crash Window Error!", MB_ICONERROR | MB_OK); - } -} - -private: - -__gshared HWND saveButton, sendButton, closeButton, reportField; - -extern(Windows) -LRESULT ReportWndProc(HWND wnd, uint msg, WPARAM w, LPARAM l) { - try { - - switch(msg) { - case WM_CREATE: - HINSTANCE inst = cast(HINSTANCE).GetModuleHandle(null); - CREATESTRUCT* cs = cast(CREATESTRUCT*)l; - - LOGFONTA lf; - lf.lfHeight = 15; - lf.lfWeight = FW_REGULAR; - lf.lfCharSet = DEFAULT_CHARSET; - lf.lfOutPrecision = OUT_DEFAULT_PRECIS; - lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; - lf.lfQuality = CLEARTYPE_QUALITY; - lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; - - HFONT font = .CreateFontIndirectA(&lf); - if(!font) SystemException(); - - HINSTANCE iconMod = LoadLibraryExA("shell32.dll", null, - DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE); - - HWND CreateButton(string caption, uint id, ushort iconId) { - HWND ret = CreateWindowExA( - 0, "BUTTON", caption.ptr, WS_CHILD | WS_VISIBLE, - 0, 0, 0, 0, wnd, cast(HMENU)id, inst, null - ); - if(!ret) SystemException(); - - SendMessageA(ret, WM_SETFONT, cast(WPARAM)font, 0); - - if(iconMod) { - HANDLE icon = LoadImage(iconMod, MAKEINTRESOURCE(iconId), IMAGE_ICON, 24, 24, 0); - if(icon) SendMessageA(ret, BM_SETIMAGE, IMAGE_ICON, cast(uint)icon); - } - - return ret; - } - - saveButton = CreateButton("Save Report", ID_SAVE_BTN, 7); - sendButton = CreateButton("Send Report", ID_SEND_BTN, 27); - closeButton = CreateButton("Close", ID_CLOSE_BTN, 28); - - if(iconMod) FreeLibrary(cast(HMODULE)iconMod); - - enum ReportFont = "Courier New\0"; - lf.lfHeight = 14; - lf.lfFaceName[0 .. ReportFont.length] = ReportFont; - - font = CreateFontIndirectA(&lf); - if(!font) SystemException(); - - reportField = CreateWindowExA( - WS_EX_CLIENTEDGE, "EDIT", null, - WS_CHILD | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE | - ES_READONLY | ES_MULTILINE | ES_AUTOVSCROLL, - 0, 0, 0, 0, wnd, cast(HMENU)ID_REPORT, inst, null - ); - if(!reportField) SystemException(); - - SendMessageA(reportField, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(5, 5)); - SendMessageA(reportField, WM_SETFONT, cast(WPARAM)font, 0); - SendMessageA(reportField, WM_SETTEXT, 0, cast(LPARAM)cs.lpCreateParams); - - break; - - case WM_DESTROY: - PostQuitMessage(0); - break; - - case WM_GETMINMAXINFO: - MINMAXINFO* mm = cast(MINMAXINFO*)l; - mm.ptMinTrackSize.x = ReportWindowMinWidth; - mm.ptMinTrackSize.y = ReportWindowMinHeight; - break; - - case WM_SIZE: - int width = LOWORD(l), halfWidth = width >> 1; - int height = HIWORD(l); - - enum { - BtnWidth = 125, - BtnHeight = 35, - NumBtns = 3, - Pad = 10, - ReportHPad = Pad * 2, - ReportVPad = BtnHeight + Pad * 3, - BtnVPad = BtnHeight + Pad, - BtnHalfWidth = (BtnWidth * NumBtns + (Pad * (NumBtns - 1))) >> 1 - } - - if(!MoveWindow(reportField, Pad, Pad, width - ReportHPad, height - ReportVPad, true)) - SystemException(); - - void Move(HWND wnd, int i) { - if(!MoveWindow(wnd, halfWidth - BtnHalfWidth + BtnWidth * i + Pad * i, - height - BtnVPad, BtnWidth, BtnHeight, true)) - SystemException(); - } - - Move(saveButton, 0); - Move(sendButton, 1); - Move(closeButton, 2); - - break; - - case WM_COMMAND: - if(HIWORD(w) != BN_CLICKED) break; - - int id = LOWORD(w); - - // GetSaveFileName fails on win7.. no idea why - if(id == ID_SAVE_BTN) { - /*char[256] path = void; - path[0 .. 11] = "Report.txt\0"; - - OPENFILENAMEA ofn; - ofn.lStructSize = OPENFILENAME.sizeof; - ofn.hwndOwner = wnd; - ofn.lpstrFilter = "Text File\0*.txt\0\0"; - ofn.lpstrFile = path.ptr; - ofn.nMaxFile = path.length; - ofn.Flags = OFN_OVERWRITEPROMPT; - - try { - if(!GetSaveFileNameA(&ofn)) SystemException(); - - uint len = strlen(path.ptr); - if(path[len-4 .. len] != ".txt") path[len .. len + 5] = ".txt\0"; - - HANDLE file = CreateFileA(path.ptr, GENERIC_WRITE, 0, - null, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, null); - - if(file == INVALID_HANDLE_VALUE) SystemException(); - scope(exit) if(!CloseHandle(file)) SystemException(); - - char* text; - SendMessageA(reportField, WM_GETTEXT, 0, cast(LPARAM)text); - len = strlen(text); - - uint written = void; - if(!WriteFile(file, text, len, &written, null)) - SystemException(); - - if(written != len) throw new SystemException("Couldn't write entire data."); - - id = ID_CLOSE_BTN; - } - catch(SystemException e) { - MessageBoxA(wnd, (e.toString ~ '\0').ptr, "Error!", MB_OK | MB_ICONERROR); - }*/ - - MessageBoxA(wnd, "TODO", "Error!", MB_OK | MB_ICONERROR); - } - - if(id == ID_SEND_BTN) - MessageBoxA(wnd, "TODO", "Error!", MB_OK | MB_ICONERROR); - - if(id == ID_CLOSE_BTN) - SendMessageA(wnd, WM_CLOSE, 0, 0); - - break; - - default: - return DefWindowProcA(wnd, msg, w, l); - } - - } // try - catch(Exception e) { - MessageBoxA(HWND.init, (e.toString ~ '\0').ptr, "Crash Window Handler Error!", MB_ICONERROR | MB_OK); - PostQuitMessage(0); - } - - return 0; -} - -} // version(Windows) - -else version(Gnome) { - -import std.c.stdio; - -import ext.Gnome.gtk; -import ext.Gnome.gobject; - -void ErrorGUI(in ErrorReport* report) { - int argc; - if(!gtk_init_check(&argc, null)) { - printf("gtk failed!\n"); - Pause; - } - - void SetSignal(A, B)(A* widget, string signal, B callback) { - g_signal_connect(cast(void*)widget, signal.ptr, cast(GCallback)callback, null); - } - - // Create the report window - GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_title(cast(GtkWindow*)window, ReportWindowTitle); - gtk_window_set_default_size(cast(GtkWindow*)window, ReportWindowWidth, ReportWindowHeight); - gtk_window_set_icon_name(cast(GtkWindow*)window, GTK_STOCK_DIALOG_ERROR); - - SetSignal(window, "destroy", >k_main_quit); - - // Create the root box - GtkWidget* vbox = gtk_vbox_new(false, 0); - gtk_container_add(cast(GtkContainer*)window, vbox); - - // Create the report edit - GtkWidget* view = gtk_text_view_new(); - gtk_text_view_set_editable(cast(GtkTextView*)view, false); - gtk_text_view_set_cursor_visible(cast(GtkTextView*)view, false); - - GtkTextBuffer* buffer = gtk_text_view_get_buffer(cast(GtkTextView*)view); - gtk_text_buffer_set_text(buffer, report.dumpText.ptr, -1); - - gtk_box_pack_start(cast(GtkBox*)vbox, view, true, true, 0); - - // Create the buttons box - GtkWidget* hbox = gtk_hbutton_box_new(); - gtk_box_set_spacing(cast(GtkBox*)hbox, 10); - gtk_button_box_set_layout(cast(GtkButtonBox*)hbox, GTK_BUTTONBOX_CENTER); - gtk_box_pack_start(cast(GtkBox*)vbox, hbox, false, true, 10); - - // Create the buttons - GtkWidget* CreateButton(B)(string label, string stockId, B callback) { - GtkWidget* button = gtk_button_new_with_label(label.ptr); - - GtkWidget* image = gtk_image_new_from_stock(stockId.ptr, GTK_ICON_SIZE_BUTTON); - gtk_button_set_image(cast(GtkButton*)button, image); - - gtk_container_add(cast(GtkContainer*)hbox, button); - - if(callback) SetSignal(button, "clicked", callback); - - return button; - } - - CreateButton("Save Report", GTK_STOCK_SAVE_AS, &OnClickSave); - CreateButton("Send Report", GTK_STOCK_CONNECT, &OnClickSend); - GtkWidget* close = CreateButton("Close", GTK_STOCK_CLOSE, null); - - g_signal_connect_swapped(cast(void*)close, "clicked", - cast(GCallback)(>k_widget_destroy), cast(void*)(window)); - - // Display the window and run the main loop - gtk_widget_show_all(window); - gtk_main(); -} - -extern(C): - -void OnClickSave(GtkButton* button, gpointer user_data) { - // TODO -} - -void OnClickSend(GtkButton* button, gpointer user_data) { - // TODO -} - -} // version(Gnome) -else version (NobodyCares) -{ -} -else static assert(0); diff -r c876339731a4 -r 6bdecc3f4569 dlib/CrashHandler.d --- a/dlib/CrashHandler.d Tue Aug 24 16:59:45 2010 +0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,465 +0,0 @@ -/** - A simple runtime crash handler which collects various informations about - the crash such as registers, stack traces, and loaded modules. - - TODO: - * Threading support - * Stack dumps - - Authors: - Jeremie Pelletier - - License: - Public Domain -*/ -module dlib.CrashHandler; - -debug = CrashHandler; - -import std.c.stdio; -import dbg.Debug; -import dbg.ui.CrashWindow; - -version(X86) {} -else static assert(0, "Unsupported architecture."); - -version(DigitalMars) { - //import dlib.dmd.ErrorHandling; -} -else static assert(0, "Unsupported compiler."); - -version(Windows) { - import win32.windows; - import win32.psapi; - import std.windows.syserror; - //import sys.windows.Memory; - //import dlib.Module; - import dbg.image.PE; - import dbg.symbol.CodeView; -} -else version(Posix) { - import core.sys.posix.ucontext; - import core.stdc.signal; - import core.stdc.stdlib : free, exit, EXIT_FAILURE; -} -else static assert(0, "Unsupported platform."); - -/** - Register the crash handler -*/ -void CrashHandlerInit() { - version(Windows) { - //SetErrorMode(SetErrorMode(0) | SEM_FAILCRITICALERRORS); - SetErrorMode(0); - SetUnhandledExceptionFilter(&UnhandledExceptionHandler); - } - else version(Posix) { - assert(0); - /+ sigaction_t sa; - sa.sa_handler = cast(sighandler_t)&SignalHandler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART | SA_SIGINFO; - - sigaction(SIGILL, &sa, null); - sigaction(SIGFPE, &sa, null); - sigaction(SIGSEGV, &sa, null);+/ - } - else static assert(0); -} - -/** - Information collected by the crash handler -*/ -struct CrashInfo { - struct Registers { - version(X86) { - uint EAX, EBX, ECX, EDX; - uint EDI, ESI; - uint EBP, ESP; - } - else static assert(0); - } - - struct Module { - string fileName; - ushort[4] fileVersion; - } - - Throwable error; - string moduleName; - Registers registers; - size_t[] backtrace; - Module[] modules; - - void Dump() { - // TODO: support more dump methods - version(Windows) ShowCrashWindow(&this); - } - - /** - Formats the crash info as plain-text - */ - string toString() { - string text; - char[255] buffer = void; - uint len = void; - - text ~= error.toString(); - text ~= "\r\n\r\n"; - - version(X86) { - with(registers) len = snprintf(buffer.ptr, buffer.length, - " Registers:\r\n" ~ - "========================================\r\n" ~ - " EAX=0x%08X EBX=0x%08X ECX=0x%08X EDX=0x%08X\r\n" ~ - " EDI=0x%08X ESI=0x%08X EBP=0x%08X ESP=0x%08X\r\n", - EAX, EBX, ECX, EDX, EDI, ESI, EBP, ESP - ); - text ~= buffer[0 .. len] ~ "\r\n"; - } - else static assert(0); - - text ~= " Stack Trace:\r\n" ~ - "========================================\r\n"; - - scope auto frames = new StackFrameInfo[backtrace.length]; - ResolveStackFrames(frames); - - foreach(ref frame; frames) { - //len = snprintf(buffer.ptr, buffer.length, "%p", frame.va); - //text ~= " " ~ buffer[0 .. len] ~ ": " ~ frame.moduleName ~ "\r\n"; - - //with(frame.symbol) if(name.length) { - // len = snprintf(buffer.ptr, buffer.length, "%X", offset); - // text ~= " " ~ name ~ " @ 0x" ~ buffer[0 .. len] ~ "\r\n"; - //} - - with(frame.fileLine) if(line) { - len = snprintf(buffer.ptr, buffer.length, "%u", line); - text ~= " " ~ file ~ ":" ~ buffer[0 .. len] ~ "\r\n"; - } - - //text ~= "\r\n"; - } -/+ - text ~= " Loaded Modules:\r\n" ~ - "========================================\r\n"; - - foreach(mod; modules) { - len = snprintf(buffer.ptr, buffer.length, "%hu.%hu.%hu.%hu", - mod.fileVersion[0], mod.fileVersion[1], - mod.fileVersion[2], mod.fileVersion[3]); - - text ~= " " ~ mod.fileName ~ "\r\n " ~ buffer[0 .. len] ~ "\r\n"; - } -+/ - text ~= '\0'; - - return text; - } - -private: - - struct StackFrameInfo { - size_t va; - string moduleName; - SymbolInfo symbol; - FileLineInfo fileLine; - } - - struct DebugImage { - DebugImage* next; - string moduleName; - size_t baseAddress; - uint rvaOffset; - IExecutableImage exeModule; - ISymbolicDebugInfo debugInfo; - } - - version(X86) { - void ResolveStackFrames(StackFrameInfo[] frames) const { - StackFrameInfo* frame = void; - DebugImage* imageList, image = void; - char[255] buffer = void; - uint len = void; - uint rva = void; - - version(Windows) MEMORY_BASIC_INFORMATION mbi = void; - - foreach(i, va; backtrace) { - frame = &frames[i]; - frame.va = va; - - version(Windows) { - // mbi.Allocation base is the handle to stack frame's module - VirtualQuery(cast(void*)va, &mbi, MEMORY_BASIC_INFORMATION.sizeof); - if(!mbi.AllocationBase) break; - - image = imageList; - while(image) { - if(image.baseAddress == cast(size_t)mbi.AllocationBase) break; - image = image.next; - } - - if(!image) { - image = new DebugImage; - - with(*image) { - next = imageList; - imageList = image; - baseAddress = cast(size_t)mbi.AllocationBase; - -// printf("%d\n", baseAddress); - - len = GetModuleFileNameA(cast(HMODULE)baseAddress, buffer.ptr, buffer.length); - moduleName = buffer[0 .. len].idup; - if (len == 0) { - MessageBox(HANDLE.init, moduleName.ptr, sysErrorString(GetLastError()).ptr, 0); - } - - exeModule = new PEImage(moduleName); - rvaOffset = baseAddress + exeModule.codeOffset; - debugInfo = exeModule.debugInfo; - } - } - } - else version(POSIX) - { - assert(0); - } - else static assert(0); - - frame.moduleName = image.moduleName; - - if(!image.debugInfo) continue; - - rva = va - image.rvaOffset; - - with(image.debugInfo) { - frame.symbol = ResolveSymbol(rva); - frame.fileLine = ResolveFileLine(rva); - } - } - - while(imageList) { - image = imageList.next; - delete imageList.debugInfo; - delete imageList.exeModule; - delete imageList; - imageList = image; - } - } - } // version(X86) - else static assert(0); -} - -// ---------------------------------------------------------------------------- -// W i n d o w s C r a s h H a n d l e r -// ---------------------------------------------------------------------------- - -version(Windows) { - -extern(C) Throwable _d_translate_se_to_d_exception(EXCEPTION_RECORD* exception_record); - -/** - D exceptions are built on top of Windows' SEH, a simple registered callback - will catch any exceptions unwinding past a thread's entry point. -*/ -extern(Windows) -int UnhandledExceptionHandler(EXCEPTION_POINTERS* e) { - CrashInfo crashInfo = void; - char[256] buffer = void; - uint len = void; - size_t ip = void, bp = void; - - try { - with(crashInfo) { - - version(DigitalMars) - error = _d_translate_se_to_d_exception(e.ExceptionRecord); - else - static assert(0); - - len = GetModuleFileNameA(GetModuleHandle(null), buffer.ptr, buffer.length); - moduleName = buffer[0 .. len].idup; - - version(X86) with(*e.ContextRecord) { - with(registers) { - EAX = Eax, EBX = Ebx, ECX = Ecx, EDX = Edx; - EDI = Edi, ESI = Esi; - EBP = Ebp, ESP = Esp; - } - - ip = Eip; - bp = Ebp; - } - else static assert(0); - - backtrace = null; - while(ip) { - backtrace ~= ip; - - ip = cast(size_t)*(cast(void**)bp + 1); - bp = cast(size_t)*cast(void**)bp; - } - - HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, - 0, GetCurrentProcessId()); - - if(process == INVALID_HANDLE_VALUE) SystemException(); - scope(exit) if(!CloseHandle(process)) SystemException(); - - scope HMODULE[] hmodules = new HMODULE[64]; - uint size = HMODULE.sizeof * hmodules.length; - uint sizeNeeded = void; - uint nModules = void; - - GetModules: - /* - if(!EnumProcessModules(process, hmodules.ptr, size, &sizeNeeded)) - SystemException(); - - nModules = sizeNeeded / HMODULE.sizeof; - /*/ - nModules = 0; - //*/ - - if(sizeNeeded > size) { - hmodules.length = nModules; - size = sizeNeeded; - goto GetModules; - } - - Module mod = void; - char[] versionInfo; - VS_FIXEDFILEINFO* fixedVersionInfo = void; - - modules = null; - foreach(i; 0 .. nModules) { - len = GetModuleFileNameA(hmodules[i], buffer.ptr, buffer.length); - mod.fileName = buffer[0 .. len].idup; - - sizeNeeded = GetFileVersionInfoSizeA(buffer.ptr, &size); - - if(sizeNeeded) { - if(versionInfo.length < sizeNeeded) versionInfo.length = sizeNeeded; - - if(!GetFileVersionInfoA(buffer.ptr, 0, versionInfo.length, versionInfo.ptr)) - SystemException(); - - if(!VerQueryValueA(versionInfo.ptr, cast(char*)"\\".ptr, cast(void**)&fixedVersionInfo, &size)) - SystemException(); - - with(*fixedVersionInfo) with(mod) { - fileVersion[0] = HIWORD(dwProductVersionMS); - fileVersion[1] = LOWORD(dwProductVersionMS); - fileVersion[2] = HIWORD(dwProductVersionLS); - fileVersion[3] = LOWORD(dwProductVersionLS); - } - } - else { - mod.fileVersion[] = 0; - } - - modules ~= mod; - } - - } // with(crashInfo) - - crashInfo.Dump(); - } - catch(Throwable e) { - debug MessageBoxA(HWND.init, (e.toString ~ '\0').ptr, "Exception Handler Error!", MB_ICONERROR | MB_OK); - } - - return EXCEPTION_EXECUTE_HANDLER; -} - -} // version(Windows) - -// ---------------------------------------------------------------------------- -// P o s i x C r a s h H a n d l e r -// ---------------------------------------------------------------------------- - -else version(Posix) { - -/** - This handler catches system signals and throws the appropriate D exception. - The exception will unwind down to the thread's entry point where it is catched - and sent to UnhandledExceptionHandler(). -*/ -extern(C) -void SignalHandler(int signum, siginfo_t* siginfo, ucontext_t* ucontext) { - string msg = void; - - switch(signum) { - case SIGILL: msg = "Illegal instruction"; break; - case SIGFPE: msg = "Floating-point exception"; break; - case SIGSEGV: msg = "Segmentation fault"; break; - default: msg = "Unknown signal"; - } - assert(0); -/+ - SystemException e = new SystemException(msg); - - e._context = ucontext; - e.GetBackTrace(); - - // The kernel fixed the stack frame to make us believe we called this - // routine ourselves, with the nasty side effect of losing the faulty - // routine's address. The undocumented parameter ucontext contains our - // lost EIP. - version(X86) { - // It should be the 3rd frame: - // SignalHandler() -> GetBackTrace() -> backtrace() - if(e._backtrace.length > 2) - e._backtrace[2] = cast(void*)ucontext.uc_mcontext.gregs[REG_EIP]; - } - else static assert(0); - throw e;+/ -} - -/** - This handler is called when an exception unwinds down to the thread's entry - point, which should catch it and manually call this routine. -*/ -void UnhandledExceptionHandler(Throwable e) { -assert(0); -/+ ErrorReport crashInfo = void; - - with(crashInfo) { - /+error = e; - - // Get the module filename - // TODO - - // Dump the general purpose registers - if(e._context) { - gregset_t gregs = e._context.uc_mcontext.gregs; - - version(X86) { - registers.Eax = gregs[REG_EAX]; - registers.Ebx = gregs[REG_EBX]; - registers.Ecx = gregs[REG_ECX]; - registers.Edx = gregs[REG_EDX]; - registers.Edi = gregs[REG_EDI]; - registers.Esi = gregs[REG_ESI]; - registers.Ebp = gregs[REG_EBP]; - registers.Esp = gregs[REG_ESP]; - } - else static assert(0); - } - - // Dump stack backtrace - addresses = e._backtrace; - - // Dump the loaded modules - // TODO+/ - - } // with(crashInfo) - - crashInfo.Dump();+/ -} - -} // version(Posix) -else static assert(0); diff -r c876339731a4 -r 6bdecc3f4569 main.d --- a/main.d Tue Aug 24 16:59:45 2010 +0400 +++ b/main.d Sat Aug 28 10:51:32 2010 +0400 @@ -31,8 +31,7 @@ import core.memory; -import dlib.CrashHandler; -import dbg.ui.CrashWindow; +import dbg.CallStackInfo; import dmd.Util; @@ -41,10 +40,142 @@ EXIT_SUCCESS = 0, } -extern (C) extern __gshared bool rt_trapExceptions; +version (Windows) +{ + private import core.stdc.wchar_; + + extern (Windows) alias int function() FARPROC; + extern (Windows) FARPROC GetProcAddress(void*, in char*); + extern (Windows) void* LoadLibraryA(in char*); + extern (Windows) int FreeLibrary(void*); + extern (Windows) void* LocalFree(void*); + extern (Windows) wchar_t* GetCommandLineW(); + extern (Windows) wchar_t** CommandLineToArgvW(wchar_t*, int*); + extern (Windows) export int WideCharToMultiByte(uint, uint, wchar_t*, int, char*, int, char*, int); + pragma(lib, "shell32.lib"); // needed for CommandLineToArgvW +} + +shared bool _d_isHalting = false; +__gshared string[] _d_args = null; + +extern (C) void gc_init(); +extern (C) void gc_term(); +extern (C) void _minit(); +extern (C) void _moduleCtor(); +extern (C) void _moduleDtor(); +extern (C) bool runModuleUnitTests(); +extern (C) void thread_joinAll(); + +import rt.memory; + +extern (C) int main(int argc, char** argv) +{ + char[][] args; + int result; + + version (OSX) + { /* OSX does not provide a way to get at the top of the + * stack, except for the magic value 0xC0000000. + * But as far as the gc is concerned, argv is at the top + * of the main thread's stack, so save the address of that. + */ + __osx_stack_end = cast(void*)&argv; + } + + version (FreeBSD) version (D_InlineAsm_X86) + { + /* + * FreeBSD/i386 sets the FPU precision mode to 53 bit double. + * Make it 64 bit extended. + */ + ushort fpucw; + asm + { + fstsw fpucw; + or fpucw, 0b11_00_111111; // 11: use 64 bit extended-precision + // 111111: mask all FP exceptions + fldcw fpucw; + } + } + + version (Posix) + { + _STI_monitor_staticctor(); + _STI_critical_init(); + } -static this() { - rt_trapExceptions = false; + version (Windows) + { + wchar_t* wcbuf = GetCommandLineW(); + size_t wclen = wcslen(wcbuf); + int wargc = 0; + wchar_t** wargs = CommandLineToArgvW(wcbuf, &wargc); + assert(wargc == argc); + + char* cargp = null; + size_t cargl = WideCharToMultiByte(65001, 0, wcbuf, wclen, null, 0, null, 0); + + cargp = cast(char*) alloca(cargl); + args = ((cast(char[]*) alloca(wargc * (char[]).sizeof)))[0 .. wargc]; + + for (size_t i = 0, p = 0; i < wargc; i++) + { + int wlen = wcslen(wargs[i]); + int clen = WideCharToMultiByte(65001, 0, &wargs[i][0], wlen, null, 0, null, 0); + args[i] = cargp[p .. p+clen]; + p += clen; assert(p <= cargl); + WideCharToMultiByte(65001, 0, &wargs[i][0], wlen, &args[i][0], clen, null, 0); + } + LocalFree(wargs); + wargs = null; + wargc = 0; + } + else version (Posix) + { + char[]* am = cast(char[]*) malloc(argc * (char[]).sizeof); + scope(exit) free(am); + + for (size_t i = 0; i < argc; i++) + { + auto len = strlen(argv[i]); + am[i] = argv[i][0 .. len]; + } + args = am[0 .. argc]; + } + _d_args = cast(string[]) args; + + void runMain() + { + result = main(_d_args); + } + + void runAll() + { + gc_init(); + initStaticDataGC(); + version (Windows) + _minit(); + _moduleCtor(); + _moduleTlsCtor(); + if (runModuleUnitTests()) + runMain(); + else + result = EXIT_FAILURE; + _moduleTlsDtor(); + thread_joinAll(); + _d_isHalting = true; + _moduleDtor(); + gc_term(); + } + + runAll(); + + version (Posix) + { + _STD_critical_term(); + _STD_monitor_staticdtor(); + } + return result; } int main(string[] args)