Skip to content

Commit

Permalink
8294211: Zero: Decode arch-specific error context if possible
Browse files Browse the repository at this point in the history
Reviewed-by: stuefe, luhenry
  • Loading branch information
shipilev committed Oct 19, 2022
1 parent f502ab8 commit 3f3d63d
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 26 deletions.
6 changes: 5 additions & 1 deletion src/hotspot/cpu/zero/globals_zero.hpp
Expand Up @@ -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

Expand Down
11 changes: 11 additions & 0 deletions src/hotspot/cpu/zero/vm_version_zero.cpp
Expand Up @@ -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
Expand Down
13 changes: 1 addition & 12 deletions src/hotspot/os/posix/signals_posix.cpp
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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();
}
Expand Down
143 changes: 130 additions & 13 deletions src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp
Expand Up @@ -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,
Expand Down Expand Up @@ -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.");
}

/////////////////////////////////////////////////////////////////////////////
Expand Down

0 comments on commit 3f3d63d

Please sign in to comment.