mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8191101: Show register content in hs-err file on assert
Reviewed-by: adinn, clanger, simonis
This commit is contained in:
parent
213862d866
commit
3e603a776e
15 changed files with 272 additions and 22 deletions
|
@ -27,6 +27,7 @@
|
||||||
#include "runtime/arguments.hpp"
|
#include "runtime/arguments.hpp"
|
||||||
#include "runtime/os.hpp"
|
#include "runtime/os.hpp"
|
||||||
#include "runtime/thread.hpp"
|
#include "runtime/thread.hpp"
|
||||||
|
#include "utilities/debug.hpp"
|
||||||
#include "utilities/vmError.hpp"
|
#include "utilities/vmError.hpp"
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
@ -122,11 +123,20 @@ static void crash_handler(int sig, siginfo_t* info, void* ucVoid) {
|
||||||
pc = (address) info->si_addr;
|
pc = (address) info->si_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Needed to make it possible to call SafeFetch.. APIs in error handling.
|
||||||
if (uc && pc && StubRoutines::is_safefetch_fault(pc)) {
|
if (uc && pc && StubRoutines::is_safefetch_fault(pc)) {
|
||||||
os::Posix::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc));
|
os::Posix::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Needed because asserts may happen in error handling too.
|
||||||
|
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
|
||||||
|
if ((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison) {
|
||||||
|
handle_assert_poison_fault(ucVoid, info->si_addr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif // CAN_SHOW_REGISTERS_ON_ASSERT
|
||||||
|
|
||||||
VMError::report_and_die(NULL, sig, pc, info, ucVoid);
|
VMError::report_and_die(NULL, sig, pc, info, ucVoid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
|
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
|
@ -50,6 +50,7 @@
|
||||||
#include "runtime/stubRoutines.hpp"
|
#include "runtime/stubRoutines.hpp"
|
||||||
#include "runtime/thread.inline.hpp"
|
#include "runtime/thread.inline.hpp"
|
||||||
#include "runtime/timer.hpp"
|
#include "runtime/timer.hpp"
|
||||||
|
#include "utilities/debug.hpp"
|
||||||
#include "utilities/events.hpp"
|
#include "utilities/events.hpp"
|
||||||
#include "utilities/vmError.hpp"
|
#include "utilities/vmError.hpp"
|
||||||
#ifdef BUILTIN_SIM
|
#ifdef BUILTIN_SIM
|
||||||
|
@ -306,6 +307,13 @@ JVM_handle_linux_signal(int sig,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
|
||||||
|
if ((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison) {
|
||||||
|
handle_assert_poison_fault(ucVoid, info->si_addr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
JavaThread* thread = NULL;
|
JavaThread* thread = NULL;
|
||||||
VMThread* vmthread = NULL;
|
VMThread* vmthread = NULL;
|
||||||
if (os::Linux::signal_handlers_are_installed) {
|
if (os::Linux::signal_handlers_are_installed) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -47,6 +47,7 @@
|
||||||
#include "runtime/sharedRuntime.hpp"
|
#include "runtime/sharedRuntime.hpp"
|
||||||
#include "runtime/stubRoutines.hpp"
|
#include "runtime/stubRoutines.hpp"
|
||||||
#include "runtime/timer.hpp"
|
#include "runtime/timer.hpp"
|
||||||
|
#include "utilities/debug.hpp"
|
||||||
#include "utilities/events.hpp"
|
#include "utilities/events.hpp"
|
||||||
#include "utilities/vmError.hpp"
|
#include "utilities/vmError.hpp"
|
||||||
|
|
||||||
|
@ -311,6 +312,13 @@ extern "C" int JVM_handle_linux_signal(int sig, siginfo_t* info,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
|
||||||
|
if ((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison) {
|
||||||
|
handle_assert_poison_fault(ucVoid, info->si_addr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
JavaThread* thread = NULL;
|
JavaThread* thread = NULL;
|
||||||
VMThread* vmthread = NULL;
|
VMThread* vmthread = NULL;
|
||||||
if (os::Linux::signal_handlers_are_installed) {
|
if (os::Linux::signal_handlers_are_installed) {
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
#include "runtime/stubRoutines.hpp"
|
#include "runtime/stubRoutines.hpp"
|
||||||
#include "runtime/thread.inline.hpp"
|
#include "runtime/thread.inline.hpp"
|
||||||
#include "runtime/timer.hpp"
|
#include "runtime/timer.hpp"
|
||||||
|
#include "utilities/debug.hpp"
|
||||||
#include "utilities/events.hpp"
|
#include "utilities/events.hpp"
|
||||||
#include "utilities/vmError.hpp"
|
#include "utilities/vmError.hpp"
|
||||||
|
|
||||||
|
@ -266,6 +267,13 @@ JVM_handle_linux_signal(int sig,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
|
||||||
|
if ((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison) {
|
||||||
|
handle_assert_poison_fault(ucVoid, info->si_addr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
JavaThread* thread = NULL;
|
JavaThread* thread = NULL;
|
||||||
VMThread* vmthread = NULL;
|
VMThread* vmthread = NULL;
|
||||||
if (os::Linux::signal_handlers_are_installed) {
|
if (os::Linux::signal_handlers_are_installed) {
|
||||||
|
|
|
@ -54,6 +54,7 @@
|
||||||
#include "runtime/thread.inline.hpp"
|
#include "runtime/thread.inline.hpp"
|
||||||
#include "runtime/timer.hpp"
|
#include "runtime/timer.hpp"
|
||||||
#include "utilities/events.hpp"
|
#include "utilities/events.hpp"
|
||||||
|
#include "utilities/debug.hpp"
|
||||||
#include "utilities/vmError.hpp"
|
#include "utilities/vmError.hpp"
|
||||||
|
|
||||||
// put OS-includes here
|
// put OS-includes here
|
||||||
|
@ -270,6 +271,13 @@ JVM_handle_linux_signal(int sig,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
|
||||||
|
if ((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison) {
|
||||||
|
handle_assert_poison_fault(ucVoid, info->si_addr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
JavaThread* thread = NULL;
|
JavaThread* thread = NULL;
|
||||||
VMThread* vmthread = NULL;
|
VMThread* vmthread = NULL;
|
||||||
if (os::Linux::signal_handlers_are_installed) {
|
if (os::Linux::signal_handlers_are_installed) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -49,6 +49,7 @@
|
||||||
#include "runtime/stubRoutines.hpp"
|
#include "runtime/stubRoutines.hpp"
|
||||||
#include "runtime/thread.inline.hpp"
|
#include "runtime/thread.inline.hpp"
|
||||||
#include "runtime/timer.hpp"
|
#include "runtime/timer.hpp"
|
||||||
|
#include "utilities/debug.hpp"
|
||||||
#include "utilities/events.hpp"
|
#include "utilities/events.hpp"
|
||||||
#include "utilities/vmError.hpp"
|
#include "utilities/vmError.hpp"
|
||||||
|
|
||||||
|
@ -513,6 +514,13 @@ JVM_handle_linux_signal(int sig,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
|
||||||
|
if ((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison) {
|
||||||
|
handle_assert_poison_fault(ucVoid, info->si_addr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
JavaThread* thread = NULL;
|
JavaThread* thread = NULL;
|
||||||
VMThread* vmthread = NULL;
|
VMThread* vmthread = NULL;
|
||||||
if (os::Linux::signal_handlers_are_installed) {
|
if (os::Linux::signal_handlers_are_installed) {
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
#include "runtime/timer.hpp"
|
#include "runtime/timer.hpp"
|
||||||
#include "services/memTracker.hpp"
|
#include "services/memTracker.hpp"
|
||||||
#include "utilities/align.hpp"
|
#include "utilities/align.hpp"
|
||||||
|
#include "utilities/debug.hpp"
|
||||||
#include "utilities/events.hpp"
|
#include "utilities/events.hpp"
|
||||||
#include "utilities/vmError.hpp"
|
#include "utilities/vmError.hpp"
|
||||||
|
|
||||||
|
@ -304,6 +305,13 @@ JVM_handle_linux_signal(int sig,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
|
||||||
|
if ((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison) {
|
||||||
|
handle_assert_poison_fault(ucVoid, info->si_addr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
JavaThread* thread = NULL;
|
JavaThread* thread = NULL;
|
||||||
VMThread* vmthread = NULL;
|
VMThread* vmthread = NULL;
|
||||||
if (os::Linux::signal_handlers_are_installed) {
|
if (os::Linux::signal_handlers_are_installed) {
|
||||||
|
|
|
@ -3412,6 +3412,10 @@ jint Arguments::finalize_vm_init_args(bool patch_mod_javabase) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef CAN_SHOW_REGISTERS_ON_ASSERT
|
||||||
|
UNSUPPORTED_OPTION(ShowRegistersOnAssert);
|
||||||
|
#endif // CAN_SHOW_REGISTERS_ON_ASSERT
|
||||||
|
|
||||||
return JNI_OK;
|
return JNI_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4062,6 +4062,9 @@ public:
|
||||||
develop(bool, VerifyMetaspace, false, \
|
develop(bool, VerifyMetaspace, false, \
|
||||||
"Verify metaspace on chunk movements.") \
|
"Verify metaspace on chunk movements.") \
|
||||||
\
|
\
|
||||||
|
diagnostic(bool, ShowRegistersOnAssert, false, \
|
||||||
|
"On internal errors, include registers in error report.") \
|
||||||
|
\
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3661,6 +3661,13 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
|
||||||
// Timing (must come after argument parsing)
|
// Timing (must come after argument parsing)
|
||||||
TraceTime timer("Create VM", TRACETIME_LOG(Info, startuptime));
|
TraceTime timer("Create VM", TRACETIME_LOG(Info, startuptime));
|
||||||
|
|
||||||
|
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
|
||||||
|
// Initialize assert poison page mechanism.
|
||||||
|
if (ShowRegistersOnAssert) {
|
||||||
|
initialize_assert_poison();
|
||||||
|
}
|
||||||
|
#endif // CAN_SHOW_REGISTERS_ON_ASSERT
|
||||||
|
|
||||||
// Initialize the os module after parsing the args
|
// Initialize the os module after parsing the args
|
||||||
jint os_init_2_result = os::init_2();
|
jint os_init_2_result = os::init_2();
|
||||||
if (os_init_2_result != JNI_OK) return os_init_2_result;
|
if (os_init_2_result != JNI_OK) return os_init_2_result;
|
||||||
|
|
|
@ -54,11 +54,20 @@
|
||||||
#include "utilities/defaultStream.hpp"
|
#include "utilities/defaultStream.hpp"
|
||||||
#include "utilities/events.hpp"
|
#include "utilities/events.hpp"
|
||||||
#include "utilities/formatBuffer.hpp"
|
#include "utilities/formatBuffer.hpp"
|
||||||
|
#include "utilities/globalDefinitions.hpp"
|
||||||
#include "utilities/macros.hpp"
|
#include "utilities/macros.hpp"
|
||||||
#include "utilities/vmError.hpp"
|
#include "utilities/vmError.hpp"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
// Support for showing register content on asserts/guarantees.
|
||||||
|
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
|
||||||
|
static char g_dummy;
|
||||||
|
char* g_assert_poison = &g_dummy;
|
||||||
|
static intx g_asserting_thread = 0;
|
||||||
|
static void* g_assertion_context = NULL;
|
||||||
|
#endif // CAN_SHOW_REGISTERS_ON_ASSERT
|
||||||
|
|
||||||
#ifndef ASSERT
|
#ifndef ASSERT
|
||||||
# ifdef _DEBUG
|
# ifdef _DEBUG
|
||||||
// NOTE: don't turn the lines below into a comment -- if you're getting
|
// NOTE: don't turn the lines below into a comment -- if you're getting
|
||||||
|
@ -212,7 +221,13 @@ void report_vm_error(const char* file, int line, const char* error_msg, const ch
|
||||||
if (Debugging || error_is_suppressed(file, line)) return;
|
if (Debugging || error_is_suppressed(file, line)) return;
|
||||||
va_list detail_args;
|
va_list detail_args;
|
||||||
va_start(detail_args, detail_fmt);
|
va_start(detail_args, detail_fmt);
|
||||||
VMError::report_and_die(Thread::current_or_null(), file, line, error_msg, detail_fmt, detail_args);
|
void* context = NULL;
|
||||||
|
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
|
||||||
|
if (g_assertion_context != NULL && os::current_thread_id() == g_asserting_thread) {
|
||||||
|
context = g_assertion_context;
|
||||||
|
}
|
||||||
|
#endif // CAN_SHOW_REGISTERS_ON_ASSERT
|
||||||
|
VMError::report_and_die(Thread::current_or_null(), context, file, line, error_msg, detail_fmt, detail_args);
|
||||||
va_end(detail_args);
|
va_end(detail_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,7 +241,13 @@ void report_fatal(const char* file, int line, const char* detail_fmt, ...)
|
||||||
if (Debugging || error_is_suppressed(file, line)) return;
|
if (Debugging || error_is_suppressed(file, line)) return;
|
||||||
va_list detail_args;
|
va_list detail_args;
|
||||||
va_start(detail_args, detail_fmt);
|
va_start(detail_args, detail_fmt);
|
||||||
VMError::report_and_die(Thread::current_or_null(), file, line, "fatal error", detail_fmt, detail_args);
|
void* context = NULL;
|
||||||
|
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
|
||||||
|
if (g_assertion_context != NULL && os::current_thread_id() == g_asserting_thread) {
|
||||||
|
context = g_assertion_context;
|
||||||
|
}
|
||||||
|
#endif // CAN_SHOW_REGISTERS_ON_ASSERT
|
||||||
|
VMError::report_and_die(Thread::current_or_null(), context, file, line, "fatal error", detail_fmt, detail_args);
|
||||||
va_end(detail_args);
|
va_end(detail_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -676,3 +697,50 @@ struct TestMultipleStaticAssertFormsInClassScope {
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // !PRODUCT
|
#endif // !PRODUCT
|
||||||
|
|
||||||
|
// Support for showing register content on asserts/guarantees.
|
||||||
|
#ifdef CAN_SHOW_REGISTERS_ON_ASSERT
|
||||||
|
|
||||||
|
static ucontext_t g_stored_assertion_context;
|
||||||
|
|
||||||
|
void initialize_assert_poison() {
|
||||||
|
char* page = os::reserve_memory(os::vm_page_size());
|
||||||
|
if (page) {
|
||||||
|
if (os::commit_memory(page, os::vm_page_size(), false) &&
|
||||||
|
os::protect_memory(page, os::vm_page_size(), os::MEM_PROT_NONE)) {
|
||||||
|
g_assert_poison = page;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool store_context(const void* context) {
|
||||||
|
if (memcpy(&g_stored_assertion_context, context, sizeof(ucontext_t)) == false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#if defined(__linux) && defined(PPC64)
|
||||||
|
// on Linux ppc64, ucontext_t contains pointers into itself which have to be patched up
|
||||||
|
// after copying the context (see comment in sys/ucontext.h):
|
||||||
|
*((void**) &g_stored_assertion_context.uc_mcontext.regs) = &(g_stored_assertion_context.uc_mcontext.gp_regs);
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool handle_assert_poison_fault(const void* ucVoid, const void* faulting_address) {
|
||||||
|
if (faulting_address == g_assert_poison) {
|
||||||
|
// Disarm poison page.
|
||||||
|
os::protect_memory((char*)g_assert_poison, os::vm_page_size(), os::MEM_PROT_RWX);
|
||||||
|
// Store Context away.
|
||||||
|
if (ucVoid) {
|
||||||
|
const jlong my_tid = os::current_thread_id();
|
||||||
|
if (Atomic::cmpxchg(my_tid, &g_asserting_thread, (intx)0) == 0) {
|
||||||
|
if (store_context(ucVoid)) {
|
||||||
|
g_assertion_context = &g_stored_assertion_context;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif // CAN_SHOW_REGISTERS_ON_ASSERT
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -31,6 +31,17 @@
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
// ShowRegistersOnAssert support (for now Linux only)
|
||||||
|
#if defined(LINUX) && !defined(ZERO)
|
||||||
|
#define CAN_SHOW_REGISTERS_ON_ASSERT
|
||||||
|
extern char* g_assert_poison;
|
||||||
|
#define TOUCH_ASSERT_POISON (*g_assert_poison) = 'X';
|
||||||
|
void initialize_assert_poison();
|
||||||
|
bool handle_assert_poison_fault(const void* ucVoid, const void* faulting_address);
|
||||||
|
#else
|
||||||
|
#define TOUCH_ASSERT_POISON
|
||||||
|
#endif // CAN_SHOW_REGISTERS_ON_ASSERT
|
||||||
|
|
||||||
// assertions
|
// assertions
|
||||||
#ifndef ASSERT
|
#ifndef ASSERT
|
||||||
#define vmassert(p, ...)
|
#define vmassert(p, ...)
|
||||||
|
@ -42,6 +53,7 @@
|
||||||
#define vmassert(p, ...) \
|
#define vmassert(p, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (!(p)) { \
|
if (!(p)) { \
|
||||||
|
TOUCH_ASSERT_POISON; \
|
||||||
if (is_executing_unit_tests()) { \
|
if (is_executing_unit_tests()) { \
|
||||||
report_assert_msg(__VA_ARGS__); \
|
report_assert_msg(__VA_ARGS__); \
|
||||||
} \
|
} \
|
||||||
|
@ -67,6 +79,7 @@ do { \
|
||||||
#define vmassert_status(p, status, msg) \
|
#define vmassert_status(p, status, msg) \
|
||||||
do { \
|
do { \
|
||||||
if (!(p)) { \
|
if (!(p)) { \
|
||||||
|
TOUCH_ASSERT_POISON; \
|
||||||
report_vm_status_error(__FILE__, __LINE__, "assert(" #p ") failed", \
|
report_vm_status_error(__FILE__, __LINE__, "assert(" #p ") failed", \
|
||||||
status, msg); \
|
status, msg); \
|
||||||
BREAKPOINT; \
|
BREAKPOINT; \
|
||||||
|
@ -83,6 +96,7 @@ do { \
|
||||||
#define guarantee(p, ...) \
|
#define guarantee(p, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (!(p)) { \
|
if (!(p)) { \
|
||||||
|
TOUCH_ASSERT_POISON; \
|
||||||
report_vm_error(__FILE__, __LINE__, "guarantee(" #p ") failed", __VA_ARGS__); \
|
report_vm_error(__FILE__, __LINE__, "guarantee(" #p ") failed", __VA_ARGS__); \
|
||||||
BREAKPOINT; \
|
BREAKPOINT; \
|
||||||
} \
|
} \
|
||||||
|
@ -90,6 +104,7 @@ do {
|
||||||
|
|
||||||
#define fatal(...) \
|
#define fatal(...) \
|
||||||
do { \
|
do { \
|
||||||
|
TOUCH_ASSERT_POISON; \
|
||||||
report_fatal(__FILE__, __LINE__, __VA_ARGS__); \
|
report_fatal(__FILE__, __LINE__, __VA_ARGS__); \
|
||||||
BREAKPOINT; \
|
BREAKPOINT; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
@ -103,18 +118,21 @@ do {
|
||||||
|
|
||||||
#define ShouldNotCallThis() \
|
#define ShouldNotCallThis() \
|
||||||
do { \
|
do { \
|
||||||
|
TOUCH_ASSERT_POISON; \
|
||||||
report_should_not_call(__FILE__, __LINE__); \
|
report_should_not_call(__FILE__, __LINE__); \
|
||||||
BREAKPOINT; \
|
BREAKPOINT; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define ShouldNotReachHere() \
|
#define ShouldNotReachHere() \
|
||||||
do { \
|
do { \
|
||||||
|
TOUCH_ASSERT_POISON; \
|
||||||
report_should_not_reach_here(__FILE__, __LINE__); \
|
report_should_not_reach_here(__FILE__, __LINE__); \
|
||||||
BREAKPOINT; \
|
BREAKPOINT; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define Unimplemented() \
|
#define Unimplemented() \
|
||||||
do { \
|
do { \
|
||||||
|
TOUCH_ASSERT_POISON; \
|
||||||
report_unimplemented(__FILE__, __LINE__); \
|
report_unimplemented(__FILE__, __LINE__); \
|
||||||
BREAKPOINT; \
|
BREAKPOINT; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
|
@ -1238,10 +1238,10 @@ void VMError::report_and_die(const char* message)
|
||||||
report_and_die(message, "%s", "");
|
report_and_die(message, "%s", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMError::report_and_die(Thread* thread, const char* filename, int lineno, const char* message,
|
void VMError::report_and_die(Thread* thread, void* context, const char* filename, int lineno, const char* message,
|
||||||
const char* detail_fmt, va_list detail_args)
|
const char* detail_fmt, va_list detail_args)
|
||||||
{
|
{
|
||||||
report_and_die(INTERNAL_ERROR, message, detail_fmt, detail_args, thread, NULL, NULL, NULL, filename, lineno, 0);
|
report_and_die(INTERNAL_ERROR, message, detail_fmt, detail_args, thread, NULL, NULL, context, filename, lineno, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMError::report_and_die(Thread* thread, const char* filename, int lineno, size_t size,
|
void VMError::report_and_die(Thread* thread, const char* filename, int lineno, size_t size,
|
||||||
|
@ -1674,24 +1674,24 @@ void VMError::controlled_crash(int how) {
|
||||||
// Case 16 is tested by test/hotspot/jtreg/runtime/ErrorHandling/ThreadsListHandleInErrorHandlingTest.java.
|
// Case 16 is tested by test/hotspot/jtreg/runtime/ErrorHandling/ThreadsListHandleInErrorHandlingTest.java.
|
||||||
// Case 17 is tested by test/hotspot/jtreg/runtime/ErrorHandling/NestedThreadsListHandleInErrorHandlingTest.java.
|
// Case 17 is tested by test/hotspot/jtreg/runtime/ErrorHandling/NestedThreadsListHandleInErrorHandlingTest.java.
|
||||||
switch (how) {
|
switch (how) {
|
||||||
case 1: vmassert(str == NULL, "expected null");
|
case 1: vmassert(str == NULL, "expected null"); break;
|
||||||
case 2: vmassert(num == 1023 && *str == 'X',
|
case 2: vmassert(num == 1023 && *str == 'X',
|
||||||
"num=" SIZE_FORMAT " str=\"%s\"", num, str);
|
"num=" SIZE_FORMAT " str=\"%s\"", num, str); break;
|
||||||
case 3: guarantee(str == NULL, "expected null");
|
case 3: guarantee(str == NULL, "expected null"); break;
|
||||||
case 4: guarantee(num == 1023 && *str == 'X',
|
case 4: guarantee(num == 1023 && *str == 'X',
|
||||||
"num=" SIZE_FORMAT " str=\"%s\"", num, str);
|
"num=" SIZE_FORMAT " str=\"%s\"", num, str); break;
|
||||||
case 5: fatal("expected null");
|
case 5: fatal("expected null"); break;
|
||||||
case 6: fatal("num=" SIZE_FORMAT " str=\"%s\"", num, str);
|
case 6: fatal("num=" SIZE_FORMAT " str=\"%s\"", num, str); break;
|
||||||
case 7: fatal("%s%s# %s%s# %s%s# %s%s# %s%s# "
|
case 7: fatal("%s%s# %s%s# %s%s# %s%s# %s%s# "
|
||||||
"%s%s# %s%s# %s%s# %s%s# %s%s# "
|
"%s%s# %s%s# %s%s# %s%s# %s%s# "
|
||||||
"%s%s# %s%s# %s%s# %s%s# %s",
|
"%s%s# %s%s# %s%s# %s%s# %s",
|
||||||
msg, eol, msg, eol, msg, eol, msg, eol, msg, eol,
|
msg, eol, msg, eol, msg, eol, msg, eol, msg, eol,
|
||||||
msg, eol, msg, eol, msg, eol, msg, eol, msg, eol,
|
msg, eol, msg, eol, msg, eol, msg, eol, msg, eol,
|
||||||
msg, eol, msg, eol, msg, eol, msg, eol, msg);
|
msg, eol, msg, eol, msg, eol, msg, eol, msg); break;
|
||||||
case 8: vm_exit_out_of_memory(num, OOM_MALLOC_ERROR, "ChunkPool::allocate");
|
case 8: vm_exit_out_of_memory(num, OOM_MALLOC_ERROR, "ChunkPool::allocate"); break;
|
||||||
case 9: ShouldNotCallThis();
|
case 9: ShouldNotCallThis(); break;
|
||||||
case 10: ShouldNotReachHere();
|
case 10: ShouldNotReachHere(); break;
|
||||||
case 11: Unimplemented();
|
case 11: Unimplemented(); break;
|
||||||
// There's no guarantee the bad data pointer will crash us
|
// There's no guarantee the bad data pointer will crash us
|
||||||
// so "break" out to the ShouldNotReachHere().
|
// so "break" out to the ShouldNotReachHere().
|
||||||
case 12: *dataPtr = '\0'; break;
|
case 12: *dataPtr = '\0'; break;
|
||||||
|
@ -1714,6 +1714,7 @@ void VMError::controlled_crash(int how) {
|
||||||
|
|
||||||
default: tty->print_cr("ERROR: %d: unexpected test_num value.", how);
|
default: tty->print_cr("ERROR: %d: unexpected test_num value.", how);
|
||||||
}
|
}
|
||||||
|
tty->print_cr("VMError::controlled_crash: survived intentional crash. Did you suppress the assert?");
|
||||||
ShouldNotReachHere();
|
ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
#endif // !PRODUCT
|
#endif // !PRODUCT
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -158,8 +158,8 @@ public:
|
||||||
static void report_and_die(Thread* thread, unsigned int sig, address pc,
|
static void report_and_die(Thread* thread, unsigned int sig, address pc,
|
||||||
void* siginfo, void* context);
|
void* siginfo, void* context);
|
||||||
|
|
||||||
static void report_and_die(Thread* thread,const char* filename, int lineno, const char* message,
|
static void report_and_die(Thread* thread, void* context, const char* filename, int lineno, const char* message,
|
||||||
const char* detail_fmt, va_list detail_args) ATTRIBUTE_PRINTF(5, 0);
|
const char* detail_fmt, va_list detail_args) ATTRIBUTE_PRINTF(6, 0);
|
||||||
|
|
||||||
static void report_and_die(Thread* thread, const char* filename, int lineno, size_t size,
|
static void report_and_die(Thread* thread, const char* filename, int lineno, size_t size,
|
||||||
VMErrorType vm_err_type, const char* detail_fmt,
|
VMErrorType vm_err_type, const char* detail_fmt,
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8191101
|
||||||
|
* @summary Show Registers on assert/guarantee
|
||||||
|
* @library /test/lib
|
||||||
|
* @requires (vm.debug == true) & (os.family == "linux")
|
||||||
|
* @author Thomas Stuefe (SAP)
|
||||||
|
* @modules java.base/jdk.internal.misc
|
||||||
|
* java.management
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Note: this test can only run on debug since it relies on VMError::controlled_crash() which
|
||||||
|
// only exists in debug builds.
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import jdk.test.lib.process.OutputAnalyzer;
|
||||||
|
import jdk.test.lib.Platform;
|
||||||
|
import jdk.test.lib.process.ProcessTools;
|
||||||
|
|
||||||
|
public class ShowRegistersOnAssertTest {
|
||||||
|
|
||||||
|
private static void do_test(boolean do_assert, // true - assert, false - guarantee
|
||||||
|
boolean suppress_assert,
|
||||||
|
boolean show_registers_on_assert) throws Exception
|
||||||
|
{
|
||||||
|
System.out.println("Testing " + (suppress_assert ? "suppressed" : "normal") + " " + (do_assert ? "assert" : "guarantee") +
|
||||||
|
" with " + (show_registers_on_assert ? "-XX:+ShowRegistersOnAssert" : "-XX:-ShowRegistersOnAssert") + "...");
|
||||||
|
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
|
||||||
|
"-XX:+UnlockDiagnosticVMOptions", "-Xmx100M", "-XX:-CreateCoredumpOnCrash",
|
||||||
|
"-XX:ErrorHandlerTest=" + (do_assert ? "1" : "3"),
|
||||||
|
(suppress_assert ? "-XX:SuppressErrorAt=/vmError.cpp" : ""),
|
||||||
|
(show_registers_on_assert ? "-XX:+ShowRegistersOnAssert" : "-XX:-ShowRegistersOnAssert"),
|
||||||
|
"-version");
|
||||||
|
|
||||||
|
OutputAnalyzer output_detail = new OutputAnalyzer(pb.start());
|
||||||
|
|
||||||
|
if (suppress_assert) {
|
||||||
|
// we should have not have crashed. See VMError::controlled_crash().
|
||||||
|
output_detail.shouldMatch(".*survived intentional crash.*");
|
||||||
|
} else {
|
||||||
|
// we should have crashed with an internal error. We should definitly NOT have crashed with a segfault
|
||||||
|
// (which would be a sign that the assert poison page mechanism does not work).
|
||||||
|
output_detail.shouldMatch("# A fatal error has been detected by the Java Runtime Environment:.*");
|
||||||
|
output_detail.shouldMatch("# +Internal Error.*");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
// Note: for now, this is only a regression test testing that the addition of ShowRegistersOnAssert does
|
||||||
|
// not break normal assert/guarantee handling. The feature is not implemented on all platforms and really testing
|
||||||
|
// it requires more effort.
|
||||||
|
do_test(false, false, false);
|
||||||
|
do_test(false, false, true);
|
||||||
|
do_test(false, true, false);
|
||||||
|
do_test(false, true, true);
|
||||||
|
do_test(true, false, false);
|
||||||
|
do_test(true, false, true);
|
||||||
|
do_test(true, true, false);
|
||||||
|
do_test(true, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue