diff --git a/src/os/linux/vm/os_linux.cpp b/src/os/linux/vm/os_linux.cpp index ace16e3fec9125e755be4e67edf63b1f0e561e5d..6bdcdd2165c8e2aa3d0ab341645556aabf12ae33 100644 --- a/src/os/linux/vm/os_linux.cpp +++ b/src/os/linux/vm/os_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -131,6 +131,7 @@ #define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF) #define SEC_IN_NANOSECS 1000000000LL +#define LARGEPAGES_BIT (1 << 6) //////////////////////////////////////////////////////////////////////////////// // global variables julong os::Linux::_physical_memory = 0; @@ -2817,6 +2818,43 @@ bool os::unguard_memory(char* addr, size_t size) { return linux_mprotect(addr, size, PROT_READ|PROT_WRITE); } +/* +* Set the coredump_filter bits to include largepages in core dump (bit 6) +* +* From the coredump_filter documentation: +* +* - (bit 0) anonymous private memory +* - (bit 1) anonymous shared memory +* - (bit 2) file-backed private memory +* - (bit 3) file-backed shared memory +* - (bit 4) ELF header pages in file-backed private memory areas (it is +* effective only if the bit 2 is cleared) +* - (bit 5) hugetlb private memory +* - (bit 6) hugetlb shared memory +*/ +static void set_coredump_filter(void) { + FILE *f; + long cdm; + + if ((f = fopen("/proc/self/coredump_filter", "r+")) == NULL) { + return; + } + + if (fscanf(f, "%lx", &cdm) != 1) { + fclose(f); + return; + } + + rewind(f); + + if ((cdm & LARGEPAGES_BIT) == 0) { + cdm |= LARGEPAGES_BIT; + fprintf(f, "%#lx", cdm); + } + + fclose(f); +} + // Large page support static size_t _large_page_size = 0; @@ -2874,6 +2912,8 @@ bool os::large_page_init() { _page_sizes[2] = 0; } + set_coredump_filter(); + // Large page support is available on 2.6 or newer kernel, some vendors // (e.g. Redhat) have backported it to their 2.4 based distributions. // We optimistically assume the support is available. If later it turns out diff --git a/src/os/posix/vm/os_posix.cpp b/src/os/posix/vm/os_posix.cpp new file mode 100644 index 0000000000000000000000000000000000000000..079fa7bc0b2406eb5233ebaee7644ad88ede1e43 --- /dev/null +++ b/src/os/posix/vm/os_posix.cpp @@ -0,0 +1,61 @@ +/* +* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* This code is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2 only, as +* published by the Free Software Foundation. +* +* This code is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +* version 2 for more details (a copy is included in the LICENSE file that +* accompanied this code). +* +* You should have received a copy of the GNU General Public License version +* 2 along with this work; if not, write to the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +* +* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +* or visit www.oracle.com if you need additional information or have any +* questions. +* +*/ + +#include "prims/jvm.h" +#include "runtime/os.hpp" +#include "utilities/vmError.hpp" + +#include +#include + +// Check core dump limit and report possible place where core can be found +void os::check_or_create_dump(void* exceptionRecord, void* contextRecord, char* buffer, size_t bufferSize) { + struct rlimit rlim; + static char cwd[O_BUFLEN]; + bool success; + + get_current_directory(cwd, sizeof(cwd)); + + if (getrlimit(RLIMIT_CORE, &rlim) != 0) { + jio_snprintf(buffer, bufferSize, "%s/core or core.%d (may not exist)", cwd, current_process_id()); + success = true; + } else { + switch(rlim.rlim_cur) { + case RLIM_INFINITY: + jio_snprintf(buffer, bufferSize, "%s/core or core.%d", cwd, current_process_id()); + success = true; + break; + case 0: + jio_snprintf(buffer, bufferSize, "Core dumps have been disabled. To enable core dumping, try \"ulimit -c unlimited\" before starting Java again"); + success = false; + break; + default: + jio_snprintf(buffer, bufferSize, "%s/core or core.%d (max size %lu kB). To ensure a full core dump, try \"ulimit -c unlimited\" before starting Java again", cwd, current_process_id(), (unsigned long)(rlim.rlim_cur >> 10)); + success = true; + break; + } + } + VMError::report_coredump_status(buffer, success); +} + diff --git a/src/os/windows/vm/os_windows.cpp b/src/os/windows/vm/os_windows.cpp index 2eeb3d3339297bbd41c8261d41a2c2700c00944b..50018200d9f75a4baa5ba4ce45c730c91cda9c75 100644 --- a/src/os/windows/vm/os_windows.cpp +++ b/src/os/windows/vm/os_windows.cpp @@ -1,5 +1,5 @@ /* - * CopyrighT (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -915,6 +915,80 @@ void os::shutdown() { } } + +static BOOL (WINAPI *_MiniDumpWriteDump) ( HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, PMINIDUMP_EXCEPTION_INFORMATION, + PMINIDUMP_USER_STREAM_INFORMATION, PMINIDUMP_CALLBACK_INFORMATION); + +void os::check_or_create_dump(void* exceptionRecord, void* contextRecord, char* buffer, size_t bufferSize) { + HINSTANCE dbghelp; + EXCEPTION_POINTERS ep; + MINIDUMP_EXCEPTION_INFORMATION mei; + HANDLE hProcess = GetCurrentProcess(); + DWORD processId = GetCurrentProcessId(); + HANDLE dumpFile; + MINIDUMP_TYPE dumpType; + static const char* cwd; + + // If running on a client version of Windows and user has not explicitly enabled dumping + if (!os::win32::is_windows_server() && !CreateMinidumpOnCrash) { + VMError::report_coredump_status("Minidumps are not enabled by default on client versions of Windows", false); + return; + // If running on a server version of Windows and user has explictly disabled dumping + } else if (os::win32::is_windows_server() && !FLAG_IS_DEFAULT(CreateMinidumpOnCrash) && !CreateMinidumpOnCrash) { + VMError::report_coredump_status("Minidump has been disabled from the command line", false); + return; + } + + dbghelp = LoadLibrary("DBGHELP.DLL"); + + if (dbghelp == NULL) { + VMError::report_coredump_status("Failed to load dbghelp.dll", false); + return; + } + + _MiniDumpWriteDump = CAST_TO_FN_PTR( + BOOL(WINAPI *)( HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, PMINIDUMP_EXCEPTION_INFORMATION, + PMINIDUMP_USER_STREAM_INFORMATION, PMINIDUMP_CALLBACK_INFORMATION), + GetProcAddress(dbghelp, "MiniDumpWriteDump")); + + if (_MiniDumpWriteDump == NULL) { + VMError::report_coredump_status("Failed to find MiniDumpWriteDump() in module dbghelp.dll", false); + return; + } + + dumpType = (MINIDUMP_TYPE)(MiniDumpWithFullMemory | MiniDumpWithFullMemoryInfo | + MiniDumpWithHandleData | MiniDumpWithThreadInfo | MiniDumpWithUnloadedModules); + + + cwd = get_current_directory(NULL, 0); + jio_snprintf(buffer, bufferSize, "%s\\hs_err_pid%u.mdmp",cwd, current_process_id()); + dumpFile = CreateFile(buffer, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + if (dumpFile == INVALID_HANDLE_VALUE) { + VMError::report_coredump_status("Failed to create file for dumping", false); + return; + } + + ep.ContextRecord = (PCONTEXT) contextRecord; + ep.ExceptionRecord = (PEXCEPTION_RECORD) exceptionRecord; + + mei.ThreadId = GetCurrentThreadId(); + mei.ExceptionPointers = &ep; + + // Older versions of dbghelp.dll (the one shipped with Win2003 for example) may not support all + // the dump types we really want. If first call fails, lets fall back to just use MiniDumpWithFullMemory then. + if (_MiniDumpWriteDump(hProcess, processId, dumpFile, dumpType, &mei, NULL, NULL) == false && + _MiniDumpWriteDump(hProcess, processId, dumpFile, (MINIDUMP_TYPE)MiniDumpWithFullMemory, &mei, NULL, NULL) == false) { + VMError::report_coredump_status("Call to MiniDumpWriteDump() failed", false); + } else { + VMError::report_coredump_status(buffer, true); + } + + CloseHandle(dumpFile); +} + + + void os::abort(bool dump_core) { os::shutdown(); @@ -3274,7 +3348,7 @@ volatile intx os::win32::_os_thread_count = 0; bool os::win32::_is_nt = false; bool os::win32::_is_windows_2003 = false; - +bool os::win32::_is_windows_server = false; void os::win32::initialize_system_info() { SYSTEM_INFO si; @@ -3293,9 +3367,9 @@ void os::win32::initialize_system_info() { GlobalMemoryStatusEx(&ms); _physical_memory = ms.ullTotalPhys; - OSVERSIONINFO oi; - oi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx(&oi); + OSVERSIONINFOEX oi; + oi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + GetVersionEx((OSVERSIONINFO*)&oi); switch(oi.dwPlatformId) { case VER_PLATFORM_WIN32_WINDOWS: _is_nt = false; break; case VER_PLATFORM_WIN32_NT: @@ -3305,6 +3379,10 @@ void os::win32::initialize_system_info() { if (os_vers == 5002) { _is_windows_2003 = true; } + if (oi.wProductType == VER_NT_DOMAIN_CONTROLLER || + oi.wProductType == VER_NT_SERVER) { + _is_windows_server = true; + } } break; default: fatal("Unknown platform"); diff --git a/src/os/windows/vm/os_windows.hpp b/src/os/windows/vm/os_windows.hpp index ddc7e2036574a23c676c5f272f9a01fc9e2ca98e..5576f0bc38d646928ccb8562df7a5e74227dc78c 100644 --- a/src/os/windows/vm/os_windows.hpp +++ b/src/os/windows/vm/os_windows.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,7 @@ class win32 { static size_t _default_stack_size; static bool _is_nt; static bool _is_windows_2003; + static bool _is_windows_server; public: // Windows-specific interface: @@ -64,6 +65,9 @@ class win32 { // Tells whether the platform is NT or Windown95 static bool is_nt() { return _is_nt; } + // Tells whether this is a server version of Windows + static bool is_windows_server() { return _is_windows_server; } + // Tells whether the platform is Windows 2003 static bool is_windows_2003() { return _is_windows_2003; } diff --git a/src/share/vm/runtime/globals.hpp b/src/share/vm/runtime/globals.hpp index 95a522b2c296a8f39254181242e36c74446d6ad3..e900b6ce8e2e992d564a170bdd3d633b4585a07b 100644 --- a/src/share/vm/runtime/globals.hpp +++ b/src/share/vm/runtime/globals.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -790,6 +790,9 @@ class CommandLineFlags { product(bool, ShowMessageBoxOnError, false, \ "Keep process alive on VM fatal error") \ \ + product(bool, CreateMinidumpOnCrash, false, \ + "Create minidump on VM fatal error") \ + \ product_pd(bool, UseOSErrorReporting, \ "Let VM fatal error propagate to the OS (ie. WER on Windows)") \ \ diff --git a/src/share/vm/runtime/os.hpp b/src/share/vm/runtime/os.hpp index c7f03462d54fbb8bf9c21472c6ca16bd25bc90b8..90ca497df550d70d291cce40052221cbce3d2378 100644 --- a/src/share/vm/runtime/os.hpp +++ b/src/share/vm/runtime/os.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -614,6 +614,9 @@ class os: AllStatic { // Structured OS Exception support static void os_exception_wrapper(java_call_t f, JavaValue* value, methodHandle* method, JavaCallArguments* args, Thread* thread); + // On Windows this will create an actual minidump, on Linux/Solaris it will simply check core dump limits + static void check_or_create_dump(void* exceptionRecord, void* contextRecord, char* buffer, size_t bufferSize); + // JVMTI & JVM monitoring and management support // The thread_cpu_time() and current_thread_cpu_time() are only // supported if is_thread_cpu_time_supported() returns true. diff --git a/src/share/vm/utilities/vmError.cpp b/src/share/vm/utilities/vmError.cpp index af05eed8a60551cfd45fb9781d5493642e67c9ba..9785d649d087e9b1793fa7ae2b7acdd6dcbd05e7 100644 --- a/src/share/vm/utilities/vmError.cpp +++ b/src/share/vm/utilities/vmError.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -201,6 +201,15 @@ static void print_bug_submit_message(outputStream *out, Thread *thread) { out->print_raw_cr("#"); } +bool VMError::coredump_status; +char VMError::coredump_message[O_BUFLEN]; + +void VMError::report_coredump_status(const char* message, bool status) { + coredump_status = status; + strncpy(coredump_message, message, sizeof(coredump_message)); + coredump_message[sizeof(coredump_message)-1] = 0; +} + // Return a string to describe the error char* VMError::error_string(char* buf, int buflen) { @@ -454,6 +463,15 @@ void VMError::report(outputStream* st) { st->cr(); st->print_cr("#"); } + STEP(63, "(printing core file information)") + st->print("# "); + if (coredump_status) { + st->print("Core dump written. Default location: %s", coredump_message); + } else { + st->print("Failed to write core dump. %s", coredump_message); + } + st->print_cr(""); + st->print_cr("#"); STEP(65, "(printing bug submit message)") @@ -792,6 +810,9 @@ void VMError::report_and_die() { ShowMessageBoxOnError = false; } + // Write a minidump on Windows, check core dump limits on Linux/Solaris + os::check_or_create_dump(_siginfo, _context, buffer, sizeof(buffer)); + // reset signal handlers or exception filter; make sure recursive crashes // are handled properly. reset_signal_handlers(); diff --git a/src/share/vm/utilities/vmError.hpp b/src/share/vm/utilities/vmError.hpp index e9d60b3a121f7f84608204cd7adcb705f7bd6f42..28f486940a4f9f681acc20430a25cf2ec7ac8b5e 100644 --- a/src/share/vm/utilities/vmError.hpp +++ b/src/share/vm/utilities/vmError.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,6 +67,14 @@ class VMError : public StackObj { static VMError* volatile first_error; static volatile jlong first_error_tid; + // Core dump status, false if we have been unable to write a core/minidump for some reason + static bool coredump_status; + + // When coredump_status is set to true this will contain the name/path to the core/minidump, + // if coredump_status if false, this will (hopefully) contain a useful error explaining why + // no core/minidump has been written to disk + static char coredump_message[O_BUFLEN]; + // used by reporting about OOM size_t _size; @@ -106,6 +114,9 @@ public: // return a string to describe the error char *error_string(char* buf, int buflen); + // Report status of core/minidump + static void report_coredump_status(const char* message, bool status); + // main error reporting function void report_and_die();