diff options
-rw-r--r-- | docs/users_guide/8.4.1-notes.rst | 4 | ||||
-rw-r--r-- | docs/users_guide/runtime_control.rst | 6 | ||||
-rw-r--r-- | includes/rts/Flags.h | 1 | ||||
-rw-r--r-- | libraries/base/GHC/RTS/Flags.hsc | 3 | ||||
-rw-r--r-- | libraries/base/changelog.md | 3 | ||||
-rw-r--r-- | rts/Linker.c | 15 | ||||
-rw-r--r-- | rts/LinkerInternals.h | 3 | ||||
-rw-r--r-- | rts/RtsFlags.c | 15 | ||||
-rw-r--r-- | rts/linker/PEi386.c | 196 | ||||
-rw-r--r-- | rts/linker/PEi386.h | 2 | ||||
-rw-r--r-- | rts/package.conf.in | 1 | ||||
-rw-r--r-- | rts/win32/veh_excn.c | 96 | ||||
-rw-r--r-- | rts/win32/veh_excn.h | 1 | ||||
-rw-r--r-- | testsuite/tests/rts/all.T | 8 | ||||
-rw-r--r-- | testsuite/tests/rts/derefnull.stdout-i386-unknown-mingw32 | 1 | ||||
-rw-r--r-- | testsuite/tests/rts/derefnull.stdout-x86_64-unknown-mingw32 | 1 | ||||
-rw-r--r-- | testsuite/tests/rts/divbyzero.stdout-i386-unknown-mingw32 | 1 | ||||
-rw-r--r-- | testsuite/tests/rts/divbyzero.stdout-x86_64-unknown-mingw32 | 1 |
18 files changed, 346 insertions, 12 deletions
diff --git a/docs/users_guide/8.4.1-notes.rst b/docs/users_guide/8.4.1-notes.rst index f59d266789..b787e2e626 100644 --- a/docs/users_guide/8.4.1-notes.rst +++ b/docs/users_guide/8.4.1-notes.rst @@ -188,6 +188,10 @@ Runtime system the list of search directories of GCC and querying the file system directly. This results in much better performance, especially on Windows. +- The GHC runtime on Windows can now generate stack traces on unhandled exceptions. + When running in GHCi more information is displayed about the symbols if available. + This behavior can be controlled with the RTS flag `--generate-stack-traces=<yes|no>`. + Template Haskell ~~~~~~~~~~~~~~~~ diff --git a/docs/users_guide/runtime_control.rst b/docs/users_guide/runtime_control.rst index 905048c69b..9b43277da4 100644 --- a/docs/users_guide/runtime_control.rst +++ b/docs/users_guide/runtime_control.rst @@ -235,6 +235,12 @@ Miscellaneous RTS options The dumps record all code, registers and threading information at the time of the crash. Note that this implies `--install-seh-handlers=yes`. +.. rts-flag:: --generate-stack-traces=<yes|no> + + If yes (the default), the RTS on Windows will generate a stack trace on + crashes if exception handling are enabled. In order to get more information + in compiled executables, C code or DLLs symbols need to be available. + .. rts-flag:: -xm ⟨address⟩ .. index:: diff --git a/includes/rts/Flags.h b/includes/rts/Flags.h index 4cc267072d..ff45bd378f 100644 --- a/includes/rts/Flags.h +++ b/includes/rts/Flags.h @@ -191,6 +191,7 @@ typedef struct _MISC_FLAGS { bool install_signal_handlers; bool install_seh_handlers; bool generate_dump_file; + bool generate_stack_trace; bool machineReadable; StgWord linkerMemBase; /* address to ask the OS for memory * for the linker, NULL ==> off */ diff --git a/libraries/base/GHC/RTS/Flags.hsc b/libraries/base/GHC/RTS/Flags.hsc index 7d5b705fd4..1f997c80db 100644 --- a/libraries/base/GHC/RTS/Flags.hsc +++ b/libraries/base/GHC/RTS/Flags.hsc @@ -133,6 +133,7 @@ data MiscFlags = MiscFlags , installSignalHandlers :: Bool , installSEHHandlers :: Bool , generateCrashDumpFile :: Bool + , generateStackTrace :: Bool , machineReadable :: Bool , linkerMemBase :: Word -- ^ address to ask the OS for memory for the linker, 0 ==> off @@ -423,6 +424,8 @@ getMiscFlags = do <*> (toBool <$> (#{peek MISC_FLAGS, generate_dump_file} ptr :: IO CBool)) <*> (toBool <$> + (#{peek MISC_FLAGS, generate_stack_trace} ptr :: IO CBool)) + <*> (toBool <$> (#{peek MISC_FLAGS, machineReadable} ptr :: IO CBool)) <*> #{peek MISC_FLAGS, linkerMemBase} ptr diff --git a/libraries/base/changelog.md b/libraries/base/changelog.md index 7c521f9683..bc0f4d4189 100644 --- a/libraries/base/changelog.md +++ b/libraries/base/changelog.md @@ -64,6 +64,9 @@ * Add `generateCrashDumpFile` to `MiscFlags` in `GHC.RTS.Flags` to determine if a core dump will be generated on crashes. + * Add `generateStackTrace` to `MiscFlags` in `GHC.RTS.Flags` to determine if + stack traces will be generated on unhandled exceptions by the RTS. + ## 4.10.0.0 *July 2017* * Bundled with GHC 8.2.1 diff --git a/rts/Linker.c b/rts/Linker.c index 30d7e87f92..8f55c296a6 100644 --- a/rts/Linker.c +++ b/rts/Linker.c @@ -980,6 +980,21 @@ void ghci_enquire(SymbolAddr* addr) } #endif +pathchar* +resolveSymbolAddr (pathchar* buffer, int size, + SymbolAddr* symbol, uintptr_t* top) +{ +#if defined(OBJFORMAT_PEi386) + return resolveSymbolAddr_PEi386 (buffer, size, symbol, top); +#else /* OBJFORMAT_PEi386 */ + (void)buffer; + (void)size; + (void)symbol; + (void)top; + return NULL; +#endif /* OBJFORMAT_PEi386 */ +} + #if RTS_LINKER_USE_MMAP // // Returns NULL on failure. diff --git a/rts/LinkerInternals.h b/rts/LinkerInternals.h index dd17be0992..21602f15aa 100644 --- a/rts/LinkerInternals.h +++ b/rts/LinkerInternals.h @@ -264,6 +264,9 @@ SymbolAddr* lookupSymbol_ (SymbolName* lbl); extern /*Str*/HashTable *symhash; +pathchar* +resolveSymbolAddr (pathchar* buffer, int size, + SymbolAddr* symbol, uintptr_t* top); /************************************************* * Various bits of configuration diff --git a/rts/RtsFlags.c b/rts/RtsFlags.c index 5bdf9922de..c0571368cd 100644 --- a/rts/RtsFlags.c +++ b/rts/RtsFlags.c @@ -226,6 +226,7 @@ void initRtsFlagsDefaults(void) RtsFlags.MiscFlags.install_signal_handlers = true; RtsFlags.MiscFlags.install_seh_handlers = true; + RtsFlags.MiscFlags.generate_stack_trace = true; RtsFlags.MiscFlags.generate_dump_file = false; RtsFlags.MiscFlags.machineReadable = false; RtsFlags.MiscFlags.linkerMemBase = 0; @@ -435,6 +436,10 @@ usage_text[] = { " Generate Windows crash dumps, requires exception handlers", " to be installed. Implies --install-signal-handlers=yes.", " (default: no)", +" --generate-stack-traces=<yes|no>", +" Generate a stack trace when your application encounters a", +" fatal error. When symbols are available an attempt will be", +" made to resolve addresses to names. (default: yes)", #endif #if defined(THREADED_RTS) " -e<n> Maximum number of outstanding local sparks (default: 4096)", @@ -860,6 +865,16 @@ error = true; OPTION_UNSAFE; RtsFlags.MiscFlags.install_seh_handlers = false; } + else if (strequal("generate-stack-traces=yes", + &rts_argv[arg][2])) { + OPTION_UNSAFE; + RtsFlags.MiscFlags.generate_stack_trace = true; + } + else if (strequal("generate-stack-traces=no", + &rts_argv[arg][2])) { + OPTION_UNSAFE; + RtsFlags.MiscFlags.generate_stack_trace = false; + } else if (strequal("generate-crash-dumps", &rts_argv[arg][2])) { OPTION_UNSAFE; diff --git a/rts/linker/PEi386.c b/rts/linker/PEi386.c index 4378a0a61d..3dcf8c4281 100644 --- a/rts/linker/PEi386.c +++ b/rts/linker/PEi386.c @@ -153,6 +153,10 @@ static uint8_t* cstring_from_COFF_symbol_name( uint8_t* name, uint8_t* strtab); +#include <inttypes.h> +#include <dbghelp.h> +#include <stdlib.h> +#include <Psapi.h> #if defined(x86_64_HOST_ARCH) static size_t makeSymbolExtra_PEi386( @@ -2059,4 +2063,196 @@ SymbolAddr *lookupSymbol_PEi386(SymbolName *lbl) } } +/* ----------------------------------------------------------------------------- + * Debugging operations. + */ + +pathchar* +resolveSymbolAddr_PEi386 (pathchar* buffer, int size, + SymbolAddr* symbol, uintptr_t* top ){ + SYMBOL_INFO sym; + ZeroMemory (&sym, sizeof(SYMBOL_INFO)); + sym.MaxNameLen = sizeof(char) * 1024; + + DWORD64 uDisplacement = 0; + HANDLE hProcess = GetCurrentProcess(); + ObjectCode* obj = NULL; + uintptr_t start, end; + *top = 0; + + pathprintf (buffer, size, WSTR("0x%" PRIxPTR), symbol); + + if (SymFromAddr (hProcess, (uintptr_t)symbol, &uDisplacement, &sym)) + { + /* Try using Windows symbols. */ + wcscat (buffer, WSTR(" ")); + pathchar* name = mkPath (sym.Name); + wcscat (buffer, name); + stgFree (name); + if (uDisplacement != 0) + { + int64_t displacement = (int64_t)uDisplacement; + pathchar s_disp[50]; + if (displacement < 0) + pathprintf ((pathchar*)s_disp, 50, WSTR("-%ld"), -displacement); + else + pathprintf ((pathchar*)s_disp, 50, WSTR("+%ld"), displacement); + + wcscat (buffer, s_disp); + } + } + else + { + /* Try to calculate from information inside the rts. */ + uintptr_t loc = (uintptr_t)symbol; + for (ObjectCode* oc = objects; oc; oc = oc->next) { + for (int i = 0; i < oc->n_sections; i++) { + Section section = oc->sections[i]; + start = (uintptr_t)section.start; + end = start + section.size; + if (loc > start && loc <= end) + { + wcscat (buffer, WSTR(" ")); + if (oc->archiveMemberName) + { + pathchar* name = mkPath (oc->archiveMemberName); + wcscat (buffer, name); + stgFree (name); + } + else + { + wcscat (buffer, oc->fileName); + } + pathchar s_disp[50]; + pathprintf (s_disp, 50, WSTR("+0x%" PRIxPTR), loc - start); + wcscat (buffer, s_disp); + obj = oc; + goto exit_loop; + } + } + } + + /* If we managed to make it here, we must not have any symbols nor be + dealing with code we've linked. The only thing left is an internal + segfault or one in a dynamic library. So let's enumerate the module + address space. */ + HMODULE *hMods = NULL; + DWORD cbNeeded; + EnumProcessModules (hProcess, hMods, 0, &cbNeeded); + hMods = stgMallocBytes (cbNeeded, "resolveSymbolAddr_PEi386"); + if (EnumProcessModules (hProcess, hMods, cbNeeded, &cbNeeded)) + { + uintptr_t loc = (uintptr_t)symbol; + MODULEINFO info; + for (uint32_t i = 0; i < cbNeeded / sizeof(HMODULE); i++) { + ZeroMemory (&info, sizeof (MODULEINFO)); + if (GetModuleInformation (hProcess, hMods[i], &info, + sizeof(MODULEINFO))) + { + uintptr_t start = (uintptr_t)info.lpBaseOfDll; + uintptr_t end = start + info.SizeOfImage; + if (loc >= start && loc < end) + { + /* Hoera, finally found some information. */ + pathchar tmp[MAX_PATH]; + if (GetModuleFileNameExW (hProcess, hMods[i], tmp, MAX_PATH)) + { + wcscat (buffer, WSTR(" ")); + wcscat (buffer, tmp); + pathprintf (tmp, MAX_PATH, WSTR("+0x%" PRIxPTR), loc - start); + wcscat (buffer, tmp); + } + break; + } + } + } + } + + stgFree(hMods); + } + + /* Finally any file/line number. */ + IMAGEHLP_LINE64 lineInfo = {0}; + DWORD dwDisplacement = 0; + exit_loop: + if (SymGetLineFromAddr64(hProcess, (uintptr_t)symbol, &dwDisplacement, + &lineInfo)) + { + /* Try using Windows symbols. */ + pathchar s_line[512]; + pathprintf ((pathchar*) s_line, 512, WSTR(" %ls (%lu)"), + lineInfo.FileName, lineInfo.LineNumber); + wcscat (buffer, s_line); + if (dwDisplacement != 0) + { + pathprintf ((pathchar*) s_line, 512, WSTR(" +%lu byte%s"), + dwDisplacement, + (dwDisplacement == 1 ? WSTR("") : WSTR("s"))); + } + wcscat (buffer, s_line); + } + else if (obj) + { + /* Try to calculate from information inside the rts. */ + typedef struct _SymX { SymbolName* name; uintptr_t loc; } SymX; + SymX* locs = stgCallocBytes (sizeof(SymX), obj->n_symbols, + "resolveSymbolAddr"); + int blanks = 0; + for (int i = 0; i < obj->n_symbols; i++) { + SymbolName* sym = obj->symbols[i]; + if (sym == NULL) + { + blanks++; + continue; + } + RtsSymbolInfo* a = NULL; + ghciLookupSymbolInfo(symhash, sym, &a); + if (a) { + SymX sx = {0}; + sx.name = sym; + sx.loc = (uintptr_t)a->value; + locs[i] = sx; + } + } + int comp (const void * elem1, const void * elem2) + { + SymX f = *((SymX*)elem1); + SymX s = *((SymX*)elem2); + if (f.loc > s.loc) return 1; + if (f.loc < s.loc) return -1; + return 0; + } + qsort (locs, obj->n_symbols, sizeof (SymX), comp); + uintptr_t key = (uintptr_t)symbol; + SymX* res = NULL; + + for (int x = blanks; x < obj->n_symbols; x++) { + if (x < (obj->n_symbols -1)) { + if (locs[x].loc >= key && key < locs[x+1].loc) { + res = &locs[x]; + break; + } + } + else + { + if (locs[x].loc >= key) { + res = &locs[x]; + break; + } + } + } + + if (res) { + pathchar s_disp[512]; + *top = (uintptr_t)res->loc; + pathprintf ((pathchar*)s_disp, 512, + WSTR("\n\t\t (%s+0x%" PRIxPTR ")"), + res->name, res->loc - key); + wcscat (buffer, s_disp); + } + stgFree (locs); + } + + return buffer; +} #endif /* mingw32_HOST_OS */ diff --git a/rts/linker/PEi386.h b/rts/linker/PEi386.h index e84e05232a..e6fef74af8 100644 --- a/rts/linker/PEi386.h +++ b/rts/linker/PEi386.h @@ -57,6 +57,8 @@ SymbolAddr *lookupSymbol_PEi386(SymbolName *lbl); bool ocAllocateSymbolExtras_PEi386 ( ObjectCode* oc ); SymbolAddr *lookupSymbolInDLLs ( unsigned char *lbl ); /* See Note [mingw-w64 name decoration scheme] */ +pathchar* resolveSymbolAddr_PEi386 ( pathchar* buffer, int size, + SymbolAddr* symbol, uintptr_t* top ); char * allocateImageAndTrampolines ( diff --git a/rts/package.conf.in b/rts/package.conf.in index 4eb75fc704..52d7ef8be2 100644 --- a/rts/package.conf.in +++ b/rts/package.conf.in @@ -46,6 +46,7 @@ extra-libraries: ,"gdi32" /* for the linker */ ,"winmm" /* for the linker */ ,"Dbghelp" /* for crash dump */ + ,"Psapi" /* for process information. */ #endif #if NEED_PTHREAD_LIB , "pthread" /* for pthread_getthreadid_np, pthread_create, etc. */ diff --git a/rts/win32/veh_excn.c b/rts/win32/veh_excn.c index 5105d7676f..3ac008d780 100644 --- a/rts/win32/veh_excn.c +++ b/rts/win32/veh_excn.c @@ -9,8 +9,12 @@ #include "Rts.h" #include "ghcconfig.h" #include "veh_excn.h" +#include "LinkerInternals.h" #include <assert.h> #include <stdbool.h> +#include <dbghelp.h> +#include <shellapi.h> +#include <shlobj.h> #include <wchar.h> #include <windows.h> #include <stdio.h> @@ -117,9 +121,14 @@ long WINAPI __hs_exception_handler(struct _EXCEPTION_POINTERS *exception_data) case EXCEPTION_ACCESS_VIOLATION: what = exception_data->ExceptionRecord->ExceptionInformation[0]; fprintf(stdout, "Access violation in generated code" - " when %s %p\n" - , what == 0 ? "reading" : what == 1 ? "writing" : what == 8 ? "executing data at" : "?" - , (void*) exception_data->ExceptionRecord->ExceptionInformation[1] + " when %s 0x%" PRIxPTR "\n" + , what == 0 ? "reading" + : what == 1 ? "writing" + : what == 8 ? "executing data at" + : "?" + , (uintptr_t) exception_data + ->ExceptionRecord + ->ExceptionInformation[1] ); action = EXCEPTION_CONTINUE_EXECUTION; break; @@ -132,6 +141,7 @@ long WINAPI __hs_exception_handler(struct _EXCEPTION_POINTERS *exception_data) if (EXCEPTION_CONTINUE_EXECUTION == action) { fflush(stdout); + generateStack (exception_data); generateDump (exception_data); stg_exit(EXIT_FAILURE); } @@ -153,7 +163,6 @@ long WINAPI __hs_exception_filter(struct _EXCEPTION_POINTERS *exception_data) } crash_dump = true; - return result; } @@ -240,3 +249,82 @@ void generateDump (EXCEPTION_POINTERS* pExceptionPointers) fprintf (stdout, "Crash dump created. Dump written to:\n\t%ls", szFileName); } + +// Generate stack trace information, we can piggy back on information we know +// about in the runtime linker to resolve symbols. So this is a good opportunity +// to make the output more useful. +void generateStack (EXCEPTION_POINTERS* pExceptionPointers) +{ + if (!RtsFlags.MiscFlags.generate_stack_trace) + return; + + PCONTEXT context = pExceptionPointers->ContextRecord; + STACKFRAME64 stackFrame = {0}; + DWORD machineType; + +#if defined(x86_64_HOST_ARCH) + machineType = IMAGE_FILE_MACHINE_AMD64; + stackFrame.AddrPC.Offset = context->Rip; + stackFrame.AddrPC.Mode = AddrModeFlat; + + stackFrame.AddrFrame.Offset = context->Rbp; + stackFrame.AddrFrame.Mode = AddrModeFlat; + + stackFrame.AddrStack.Offset = context->Rsp; + stackFrame.AddrStack.Mode = AddrModeFlat; +#else + machineType = IMAGE_FILE_MACHINE_I386; + stackFrame.AddrPC.Offset = context->Eip; + stackFrame.AddrPC.Mode = AddrModeFlat; + + stackFrame.AddrFrame.Offset = context->Ebp; + stackFrame.AddrFrame.Mode = AddrModeFlat; + + stackFrame.AddrStack.Offset = context->Esp; + stackFrame.AddrStack.Mode = AddrModeFlat; +#endif + fprintf (stdout, "\n Attempting to reconstruct a stack trace...\n\n"); + if (!SymInitialize (GetCurrentProcess (), NULL, true)) + fprintf (stdout, " \nNOTE: Symbols could not be loaded. Addresses may" + " be unresolved.\n\n"); + + /* Maximum amount of stack frames to show. */ + /* Phyx: I'm not sure if I should make this configurable or not. Would a + longer stack really be more useful? usually you only care about the top + few. */ + int max_frames = 35; + + fprintf (stdout, " Frame\tCode address\n"); + DWORD64 lastBp = 0; /* Prevent loops with optimized stackframes. */ + while (StackWalk64 (machineType, GetCurrentProcess(), GetCurrentThread(), + &stackFrame, context, NULL, SymFunctionTableAccess64, + SymGetModuleBase64, NULL) && max_frames > 0) + { + if (stackFrame.AddrPC.Offset == 0) + { + fprintf (stdout, "Null address\n"); + break; + } + wchar_t buffer[1024]; + uintptr_t topSp = 0; + fprintf (stdout, " * 0x%" PRIxPTR "\t%ls\n", + (uintptr_t)stackFrame.AddrFrame.Offset, + resolveSymbolAddr ((wchar_t*)&buffer, 1024, + (SymbolAddr*)stackFrame.AddrPC.Offset, + &topSp)); + if (lastBp >= stackFrame.AddrFrame.Offset) + { + fprintf (stdout, "Stack frame out of sequence...\n"); + break; + } + lastBp = stackFrame.AddrFrame.Offset; + + max_frames--; + if (max_frames ==0) + { + fprintf (stdout, "\n ... (maximum recursion depth reached.)\n"); + } + } + fprintf (stdout, "\n"); + fflush(stdout); +} diff --git a/rts/win32/veh_excn.h b/rts/win32/veh_excn.h index 4a2134861c..e0a11ade58 100644 --- a/rts/win32/veh_excn.h +++ b/rts/win32/veh_excn.h @@ -71,3 +71,4 @@ void __unregister_hs_exception_handler( void ); // prototypes for dump methods. void generateDump(EXCEPTION_POINTERS* pExceptionPointers); +void generateStack (EXCEPTION_POINTERS* pExceptionPointers); diff --git a/testsuite/tests/rts/all.T b/testsuite/tests/rts/all.T index e81940479e..935e10ecad 100644 --- a/testsuite/tests/rts/all.T +++ b/testsuite/tests/rts/all.T @@ -35,12 +35,12 @@ test('derefnull', when(platform('i386-apple-darwin'), [ignore_stderr, exit_code(139)]), when(platform('x86_64-apple-darwin'), [ignore_stderr, exit_code(139)]), when(platform('powerpc-apple-darwin'), [ignore_stderr, exit_code(139)]), - when(opsys('mingw32'), [exit_code(1), normalise_fun(normalise_address)]), + when(opsys('mingw32'), [ignore_stderr, exit_code(127)]), # since these test are supposed to crash the # profile report will be empty always. # so disable the check for profiling when(opsys('mingw32'), omit_ways(prof_ways))], - compile_and_run, ['']) + compile_and_run, ['-with-rtsopts="--generate-stack-traces=no"']) test('divbyzero', [# SIGFPE on Linux exit_code(136), @@ -54,7 +54,7 @@ test('divbyzero', # C programs compiled with gcc exit normally, so do we. when(platform('powerpc64-unknown-linux'), [ignore_stdout, exit_code(0)]), when(platform('powerpc64le-unknown-linux'), [ignore_stdout, exit_code(0)]), - when(opsys('mingw32'), exit_code(1)), + when(opsys('mingw32'), [ignore_stderr, exit_code(127)]), # The output under OS X is too unstable to readily compare when(platform('i386-apple-darwin'), [ignore_stderr, exit_code(136)]), when(platform('x86_64-apple-darwin'), [ignore_stderr, exit_code(136)]), @@ -63,7 +63,7 @@ test('divbyzero', # profile report will be empty always. # so disable the check for profiling when(opsys('mingw32'), omit_ways(prof_ways))], - compile_and_run, ['']) + compile_and_run, ['-with-rtsopts="--generate-stack-traces=no"']) test('outofmem', when(opsys('darwin'), skip), run_command, ['$MAKE -s --no-print-directory outofmem']) diff --git a/testsuite/tests/rts/derefnull.stdout-i386-unknown-mingw32 b/testsuite/tests/rts/derefnull.stdout-i386-unknown-mingw32 deleted file mode 100644 index 4541b7fb28..0000000000 --- a/testsuite/tests/rts/derefnull.stdout-i386-unknown-mingw32 +++ /dev/null @@ -1 +0,0 @@ -Access violation in generated code when reading ADDRESS diff --git a/testsuite/tests/rts/derefnull.stdout-x86_64-unknown-mingw32 b/testsuite/tests/rts/derefnull.stdout-x86_64-unknown-mingw32 deleted file mode 100644 index 4541b7fb28..0000000000 --- a/testsuite/tests/rts/derefnull.stdout-x86_64-unknown-mingw32 +++ /dev/null @@ -1 +0,0 @@ -Access violation in generated code when reading ADDRESS diff --git a/testsuite/tests/rts/divbyzero.stdout-i386-unknown-mingw32 b/testsuite/tests/rts/divbyzero.stdout-i386-unknown-mingw32 deleted file mode 100644 index 466709b368..0000000000 --- a/testsuite/tests/rts/divbyzero.stdout-i386-unknown-mingw32 +++ /dev/null @@ -1 +0,0 @@ -divide by zero diff --git a/testsuite/tests/rts/divbyzero.stdout-x86_64-unknown-mingw32 b/testsuite/tests/rts/divbyzero.stdout-x86_64-unknown-mingw32 deleted file mode 100644 index 466709b368..0000000000 --- a/testsuite/tests/rts/divbyzero.stdout-x86_64-unknown-mingw32 +++ /dev/null @@ -1 +0,0 @@ -divide by zero |