8294211: Zero: Decode arch-specific error context if possible
Reviewed-by: stuefe, luhenry
This commit is contained in:
parent
f502ab85c9
commit
3f3d63d02a
src/hotspot
cpu/zero
os/posix
os_cpu/linux_zero
@ -83,7 +83,11 @@ define_pd_global(bool, CompactStrings, true);
|
||||
"Use fast method entry code for empty methods") \
|
||||
\
|
||||
product(bool, UseFastAccessorMethods, true, \
|
||||
"Use fast method entry code for accessor methods")
|
||||
"Use fast method entry code for accessor methods") \
|
||||
\
|
||||
product(bool, DecodeErrorContext, false, DIAGNOSTIC, \
|
||||
"Try to decode the architecture-specific context for better " \
|
||||
"diagnostics")
|
||||
|
||||
// end of ARCH_FLAGS
|
||||
|
||||
|
@ -116,6 +116,17 @@ void VM_Version::initialize() {
|
||||
FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false);
|
||||
}
|
||||
|
||||
// Enable error context decoding on known platforms
|
||||
#if defined(IA32) || defined(AMD64) || defined(ARM) || \
|
||||
defined(AARCH64) || defined(PPC) || defined(RISCV) || \
|
||||
defined(S390)
|
||||
if (FLAG_IS_DEFAULT(DecodeErrorContext)) {
|
||||
FLAG_SET_DEFAULT(DecodeErrorContext, true);
|
||||
}
|
||||
#else
|
||||
UNSUPPORTED_OPTION(DecodeErrorContext);
|
||||
#endif
|
||||
|
||||
// Not implemented
|
||||
UNSUPPORTED_OPTION(UseCompiler);
|
||||
#ifdef ASSERT
|
||||
|
@ -602,12 +602,6 @@ int JVM_HANDLE_XXX_SIGNAL(int sig, siginfo_t* info,
|
||||
if (uc != NULL) {
|
||||
if (S390_ONLY(sig == SIGILL || sig == SIGFPE) NOT_S390(false)) {
|
||||
pc = (address)info->si_addr;
|
||||
} else if (ZERO_ONLY(true) NOT_ZERO(false)) {
|
||||
// Non-arch-specific Zero code does not really know the pc.
|
||||
// This can be alleviated by making arch-specific os::Posix::ucontext_get_pc
|
||||
// available for Zero for known architectures. But for generic Zero
|
||||
// code, it would still remain unknown.
|
||||
pc = NULL;
|
||||
} else {
|
||||
pc = os::Posix::ucontext_get_pc(uc);
|
||||
}
|
||||
@ -664,12 +658,7 @@ int JVM_HANDLE_XXX_SIGNAL(int sig, siginfo_t* info,
|
||||
|
||||
// Invoke fatal error handling.
|
||||
if (!signal_was_handled && abort_if_unrecognized) {
|
||||
// For Zero, we ignore the crash context, because:
|
||||
// a) The crash would be in C++ interpreter code, so context is not really relevant;
|
||||
// b) Generic Zero code would not be able to parse it, so when generic error
|
||||
// reporting code asks e.g. about frames on stack, Zero would experience
|
||||
// a secondary ShouldNotCallThis() crash.
|
||||
VMError::report_and_die(t, sig, pc, info, NOT_ZERO(ucVoid) ZERO_ONLY(NULL));
|
||||
VMError::report_and_die(t, sig, pc, info, ucVoid);
|
||||
// VMError should not return.
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
@ -87,24 +87,130 @@ char* os::non_memory_address_word() {
|
||||
}
|
||||
|
||||
address os::Posix::ucontext_get_pc(const ucontext_t* uc) {
|
||||
ShouldNotCallThis();
|
||||
return NULL; // silence compile warnings
|
||||
if (DecodeErrorContext) {
|
||||
#if defined(IA32)
|
||||
return (address)uc->uc_mcontext.gregs[REG_EIP];
|
||||
#elif defined(AMD64)
|
||||
return (address)uc->uc_mcontext.gregs[REG_RIP];
|
||||
#elif defined(ARM)
|
||||
return (address)uc->uc_mcontext.arm_pc;
|
||||
#elif defined(AARCH64)
|
||||
return (address)uc->uc_mcontext.pc;
|
||||
#elif defined(PPC)
|
||||
return (address)uc->uc_mcontext.regs->nip;
|
||||
#elif defined(RISCV)
|
||||
return (address)uc->uc_mcontext.__gregs[REG_PC];
|
||||
#elif defined(S390)
|
||||
return (address)uc->uc_mcontext.psw.addr;
|
||||
#else
|
||||
// Non-arch-specific Zero code does not really know the PC.
|
||||
// If possible, add the arch-specific definition in this method.
|
||||
fatal("Cannot handle ucontext_get_pc");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Answer the default and hope for the best
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void os::Posix::ucontext_set_pc(ucontext_t * uc, address pc) {
|
||||
void os::Posix::ucontext_set_pc(ucontext_t* uc, address pc) {
|
||||
ShouldNotCallThis();
|
||||
}
|
||||
|
||||
intptr_t* os::Linux::ucontext_get_sp(const ucontext_t* uc) {
|
||||
if (DecodeErrorContext) {
|
||||
#if defined(IA32)
|
||||
return (intptr_t*)uc->uc_mcontext.gregs[REG_UESP];
|
||||
#elif defined(AMD64)
|
||||
return (intptr_t*)uc->uc_mcontext.gregs[REG_RSP];
|
||||
#elif defined(ARM)
|
||||
return (intptr_t*)uc->uc_mcontext.arm_sp;
|
||||
#elif defined(AARCH64)
|
||||
return (intptr_t*)uc->uc_mcontext.sp;
|
||||
#elif defined(PPC)
|
||||
return (intptr_t*)uc->uc_mcontext.regs->gpr[1/*REG_SP*/];
|
||||
#elif defined(RISCV)
|
||||
return (intptr_t*)uc->uc_mcontext.__gregs[REG_SP];
|
||||
#elif defined(S390)
|
||||
return (intptr_t*)uc->uc_mcontext.gregs[15/*REG_SP*/];
|
||||
#else
|
||||
// Non-arch-specific Zero code does not really know the SP.
|
||||
// If possible, add the arch-specific definition in this method.
|
||||
fatal("Cannot handle ucontext_get_sp");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Answer the default and hope for the best
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
intptr_t* os::Linux::ucontext_get_fp(const ucontext_t* uc) {
|
||||
if (DecodeErrorContext) {
|
||||
#if defined(IA32)
|
||||
return (intptr_t*)uc->uc_mcontext.gregs[REG_EBP];
|
||||
#elif defined(AMD64)
|
||||
return (intptr_t*)uc->uc_mcontext.gregs[REG_RBP];
|
||||
#elif defined(ARM)
|
||||
return (intptr_t*)uc->uc_mcontext.arm_fp;
|
||||
#elif defined(AARCH64)
|
||||
return (intptr_t*)uc->uc_mcontext.regs[29 /* REG_FP */];
|
||||
#elif defined(PPC)
|
||||
return nullptr;
|
||||
#elif defined(RISCV)
|
||||
return (intptr_t*)uc->uc_mcontext.__gregs[8 /* REG_FP */];
|
||||
#elif defined(S390)
|
||||
return nullptr;
|
||||
#else
|
||||
// Non-arch-specific Zero code does not really know the FP.
|
||||
// If possible, add the arch-specific definition in this method.
|
||||
fatal("Cannot handle ucontext_get_fp");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Answer the default and hope for the best
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
address os::fetch_frame_from_context(const void* ucVoid,
|
||||
intptr_t** ret_sp,
|
||||
intptr_t** ret_fp) {
|
||||
ShouldNotCallThis();
|
||||
return NULL; // silence compile warnings
|
||||
address epc;
|
||||
const ucontext_t* uc = (const ucontext_t*)ucVoid;
|
||||
|
||||
if (uc != NULL) {
|
||||
epc = os::Posix::ucontext_get_pc(uc);
|
||||
if (ret_sp) {
|
||||
*ret_sp = (intptr_t*) os::Linux::ucontext_get_sp(uc);
|
||||
}
|
||||
if (ret_fp) {
|
||||
*ret_fp = (intptr_t*) os::Linux::ucontext_get_fp(uc);
|
||||
}
|
||||
} else {
|
||||
epc = NULL;
|
||||
if (ret_sp) {
|
||||
*ret_sp = nullptr;
|
||||
}
|
||||
if (ret_fp) {
|
||||
*ret_fp = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return epc;
|
||||
}
|
||||
|
||||
frame os::fetch_frame_from_context(const void* ucVoid) {
|
||||
ShouldNotCallThis();
|
||||
return frame(NULL, NULL); // silence compile warnings
|
||||
// This code is only called from error handler to get PC and SP.
|
||||
// We don't have the ready ZeroFrame* at this point, so fake the
|
||||
// frame with bare minimum.
|
||||
if (ucVoid != NULL) {
|
||||
const ucontext_t* uc = (const ucontext_t*)ucVoid;
|
||||
frame dummy = frame();
|
||||
dummy.set_pc(os::Posix::ucontext_get_pc(uc));
|
||||
dummy.set_sp((intptr_t*)os::Linux::ucontext_get_sp(uc));
|
||||
return dummy;
|
||||
} else {
|
||||
return frame(nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
|
||||
@ -288,16 +394,27 @@ size_t os::current_stack_size() {
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// helper functions for fatal error handler
|
||||
|
||||
void os::print_context(outputStream* st, const void* context) {
|
||||
ShouldNotCallThis();
|
||||
void os::print_context(outputStream* st, const void* ucVoid) {
|
||||
st->print_cr("No context information.");
|
||||
}
|
||||
|
||||
void os::print_tos_pc(outputStream *st, const void *context) {
|
||||
ShouldNotCallThis();
|
||||
void os::print_tos_pc(outputStream *st, const void* ucVoid) {
|
||||
const ucontext_t* uc = (const ucontext_t*)ucVoid;
|
||||
|
||||
address sp = (address)os::Linux::ucontext_get_sp(uc);
|
||||
print_tos(st, sp);
|
||||
st->cr();
|
||||
|
||||
// Note: it may be unsafe to inspect memory near pc. For example, pc may
|
||||
// point to garbage if entry point in an nmethod is corrupted. Leave
|
||||
// this at the end, and hope for the best.
|
||||
address pc = os::Posix::ucontext_get_pc(uc);
|
||||
print_instructions(st, pc, sizeof(char));
|
||||
st->cr();
|
||||
}
|
||||
|
||||
void os::print_register_info(outputStream *st, const void *context) {
|
||||
ShouldNotCallThis();
|
||||
void os::print_register_info(outputStream *st, const void* ucVoid) {
|
||||
st->print_cr("No register info.");
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
Loading…
x
Reference in New Issue
Block a user