8258606: os::print_signal_handlers() should resolve the function name of the handlers
Reviewed-by: dholmes, coleenp, gziemski
This commit is contained in:
parent
bd34418429
commit
e0d748d56f
@ -650,29 +650,13 @@ static void UserHandler(int sig, void *siginfo, void *context) {
|
||||
os::signal_notify(sig);
|
||||
}
|
||||
|
||||
static const char* get_signal_handler_name(address handler,
|
||||
char* buf, int buflen) {
|
||||
int offset = 0;
|
||||
bool found = os::dll_address_to_library_name(handler, buf, buflen, &offset);
|
||||
if (found) {
|
||||
// skip directory names
|
||||
const char *p1, *p2;
|
||||
p1 = buf;
|
||||
size_t len = strlen(os::file_separator());
|
||||
while ((p2 = strstr(p1, os::file_separator())) != NULL) p1 = p2 + len;
|
||||
#if !defined(AIX)
|
||||
jio_snprintf(buf, buflen, "%s+0x%x", p1, offset);
|
||||
#else
|
||||
// The way os::dll_address_to_library_name is implemented on Aix
|
||||
// right now, it always returns -1 for the offset which is not
|
||||
// terribly informative.
|
||||
// Will fix that. For now, omit the offset.
|
||||
jio_snprintf(buf, buflen, "%s", p1);
|
||||
#endif
|
||||
} else {
|
||||
jio_snprintf(buf, buflen, PTR_FORMAT, handler);
|
||||
}
|
||||
return buf;
|
||||
static void print_signal_handler_name(outputStream* os, address handler, char* buf, size_t buflen) {
|
||||
// We demangle, but omit arguments - signal handlers should have always the same prototype.
|
||||
os::print_function_and_library_name(os, handler, buf, buflen,
|
||||
true, // shorten_path
|
||||
true, // demangle
|
||||
true // omit arguments
|
||||
);
|
||||
}
|
||||
|
||||
// Writes one-line description of a combination of sigaction.sa_flags into a user
|
||||
@ -826,8 +810,10 @@ static void check_signal_handler(int sig) {
|
||||
|
||||
if (thisHandler != jvmHandler) {
|
||||
tty->print("Warning: %s handler ", os::exception_name(sig, buf, O_BUFLEN));
|
||||
tty->print("expected:%s", get_signal_handler_name(jvmHandler, buf, O_BUFLEN));
|
||||
tty->print_cr(" found:%s", get_signal_handler_name(thisHandler, buf, O_BUFLEN));
|
||||
tty->print_raw("expected:");
|
||||
print_signal_handler_name(tty, jvmHandler, buf, O_BUFLEN);
|
||||
tty->print_raw(" found:");
|
||||
print_signal_handler_name(tty, thisHandler, buf, O_BUFLEN);
|
||||
// No need to check this sig any longer
|
||||
sigaddset(&check_signal_done, sig);
|
||||
// Running under non-interactive shell, SHUTDOWN2_SIGNAL will be reassigned SIG_IGN
|
||||
@ -1368,7 +1354,7 @@ void PosixSignals::print_signal_handler(outputStream* st, int sig,
|
||||
// See comment for SA_RESTORER_FLAG_MASK
|
||||
LINUX_ONLY(sa.sa_flags &= SA_RESTORER_FLAG_MASK;)
|
||||
|
||||
st->print("%s: ", os::exception_name(sig, buf, buflen));
|
||||
st->print("%10s: ", os::exception_name(sig, buf, buflen));
|
||||
|
||||
address handler = get_signal_handler(&sa);
|
||||
|
||||
@ -1377,7 +1363,7 @@ void PosixSignals::print_signal_handler(outputStream* st, int sig,
|
||||
} else if (handler == CAST_FROM_FN_PTR(address, SIG_IGN)) {
|
||||
st->print("SIG_IGN");
|
||||
} else {
|
||||
st->print("[%s]", get_signal_handler_name(handler, buf, buflen));
|
||||
print_signal_handler_name(st, handler, buf, O_BUFLEN);
|
||||
}
|
||||
|
||||
st->print(", sa_mask[0]=");
|
||||
|
@ -882,6 +882,60 @@ void os::abort(bool dump_core) {
|
||||
//---------------------------------------------------------------------------
|
||||
// Helper functions for fatal error handler
|
||||
|
||||
bool os::print_function_and_library_name(outputStream* st,
|
||||
address addr,
|
||||
char* buf, int buflen,
|
||||
bool shorten_paths,
|
||||
bool demangle,
|
||||
bool strip_arguments) {
|
||||
// If no scratch buffer given, allocate one here on stack.
|
||||
// (used during error handling; its a coin toss, really, if on-stack allocation
|
||||
// is worse than (raw) C-heap allocation in that case).
|
||||
char* p = buf;
|
||||
if (p == NULL) {
|
||||
p = (char*)::alloca(O_BUFLEN);
|
||||
buflen = O_BUFLEN;
|
||||
}
|
||||
int offset = 0;
|
||||
const bool have_function_name = dll_address_to_function_name(addr, p, buflen,
|
||||
&offset, demangle);
|
||||
if (have_function_name) {
|
||||
// Print function name, optionally demangled
|
||||
if (demangle && strip_arguments) {
|
||||
char* args_start = strchr(p, '(');
|
||||
if (args_start != NULL) {
|
||||
*args_start = '\0';
|
||||
}
|
||||
}
|
||||
// Print offset. Omit printing if offset is zero, which makes the output
|
||||
// more readable if we print function pointers.
|
||||
if (offset == 0) {
|
||||
st->print("%s", p);
|
||||
} else {
|
||||
st->print("%s+%d", p, offset);
|
||||
}
|
||||
} else {
|
||||
st->print(PTR_FORMAT, p2i(addr));
|
||||
}
|
||||
offset = 0;
|
||||
|
||||
const bool have_library_name = dll_address_to_library_name(addr, p, buflen, &offset);
|
||||
if (have_library_name) {
|
||||
// Cut path parts
|
||||
if (shorten_paths) {
|
||||
char* p2 = strrchr(p, os::file_separator()[0]);
|
||||
if (p2 != NULL) {
|
||||
p = p2 + 1;
|
||||
}
|
||||
}
|
||||
st->print(" in %s", p);
|
||||
if (!have_function_name) { // Omit offset if we already printed the function offset
|
||||
st->print("+%d", offset);
|
||||
}
|
||||
}
|
||||
return have_function_name || have_library_name;
|
||||
}
|
||||
|
||||
void os::print_hex_dump(outputStream* st, address start, address end, int unitsize,
|
||||
int bytes_per_line, address logical_start) {
|
||||
assert(unitsize == 1 || unitsize == 2 || unitsize == 4 || unitsize == 8, "just checking");
|
||||
|
@ -589,6 +589,24 @@ class os: AllStatic {
|
||||
static bool dll_address_to_library_name(address addr, char* buf,
|
||||
int buflen, int* offset);
|
||||
|
||||
// Given an address, attempt to locate both the symbol and the library it
|
||||
// resides in. If at least one of these steps was successful, prints information
|
||||
// and returns true.
|
||||
// - if no scratch buffer is given, stack is used
|
||||
// - shorten_paths: path is omitted from library name
|
||||
// - demangle: function name is demangled
|
||||
// - strip_arguments: arguments are stripped (requires demangle=true)
|
||||
// On success prints either one of:
|
||||
// "<function name>+<offset> in <library>"
|
||||
// "<function name>+<offset>"
|
||||
// "<address> in <library>+<offset>"
|
||||
static bool print_function_and_library_name(outputStream* st,
|
||||
address addr,
|
||||
char* buf = NULL, int buflen = 0,
|
||||
bool shorten_paths = true,
|
||||
bool demangle = true,
|
||||
bool strip_arguments = false);
|
||||
|
||||
// Find out whether the pc is in the static code for jvm.dll/libjvm.so.
|
||||
static bool address_is_in_vm(address addr);
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "memory/allocation.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
@ -696,3 +697,101 @@ TEST_VM(os, pagesizes_test_print) {
|
||||
pss.print_on(&ss);
|
||||
ASSERT_EQ(strcmp(expected, buffer), 0);
|
||||
}
|
||||
|
||||
TEST_VM(os, dll_address_to_function_and_library_name) {
|
||||
char tmp[1024];
|
||||
char output[1024];
|
||||
stringStream st(output, sizeof(output));
|
||||
|
||||
#define EXPECT_CONTAINS(haystack, needle) \
|
||||
EXPECT_NE(::strstr(haystack, needle), (char*)NULL)
|
||||
#define EXPECT_DOES_NOT_CONTAIN(haystack, needle) \
|
||||
EXPECT_EQ(::strstr(haystack, needle), (char*)NULL)
|
||||
// #define LOG(...) tty->print_cr(__VA_ARGS__); // enable if needed
|
||||
#define LOG(...)
|
||||
|
||||
// Invalid addresses
|
||||
address addr = (address)(intptr_t)-1;
|
||||
EXPECT_FALSE(os::print_function_and_library_name(&st, addr));
|
||||
addr = NULL;
|
||||
EXPECT_FALSE(os::print_function_and_library_name(&st, addr));
|
||||
|
||||
// Valid addresses
|
||||
// Test with or without shorten-paths, demangle, and scratch buffer
|
||||
for (int i = 0; i < 16; i++) {
|
||||
const bool shorten_paths = (i & 1) != 0;
|
||||
const bool demangle = (i & 2) != 0;
|
||||
const bool strip_arguments = (i & 4) != 0;
|
||||
const bool provide_scratch_buffer = (i & 8) != 0;
|
||||
LOG("shorten_paths=%d, demangle=%d, strip_arguments=%d, provide_scratch_buffer=%d",
|
||||
shorten_paths, demangle, strip_arguments, provide_scratch_buffer);
|
||||
|
||||
// Should show os::min_page_size in libjvm
|
||||
addr = CAST_FROM_FN_PTR(address, Threads::create_vm);
|
||||
st.reset();
|
||||
EXPECT_TRUE(os::print_function_and_library_name(&st, addr,
|
||||
provide_scratch_buffer ? tmp : NULL,
|
||||
sizeof(tmp),
|
||||
shorten_paths, demangle,
|
||||
strip_arguments));
|
||||
EXPECT_CONTAINS(output, "Threads");
|
||||
EXPECT_CONTAINS(output, "create_vm");
|
||||
EXPECT_CONTAINS(output, "jvm"); // "jvm.dll" or "libjvm.so" or similar
|
||||
#ifndef _WIN32 // Demangler gives us no arguments on Windows
|
||||
if (demangle) {
|
||||
if (strip_arguments) {
|
||||
EXPECT_DOES_NOT_CONTAIN(output, "(");
|
||||
} else {
|
||||
EXPECT_CONTAINS(output, "(");
|
||||
}
|
||||
}
|
||||
#endif // _WIN32
|
||||
LOG("%s", output);
|
||||
|
||||
// Test truncation on scratch buffer
|
||||
if (provide_scratch_buffer) {
|
||||
st.reset();
|
||||
tmp[10] = 'X';
|
||||
EXPECT_TRUE(os::print_function_and_library_name(&st, addr, tmp, 10,
|
||||
shorten_paths, demangle));
|
||||
EXPECT_EQ(tmp[10], 'X');
|
||||
LOG("%s", output);
|
||||
}
|
||||
|
||||
// Pointer (probably) outside function, should show at least the library name
|
||||
addr -= 10;
|
||||
st.reset();
|
||||
EXPECT_TRUE(os::print_function_and_library_name(&st, addr,
|
||||
provide_scratch_buffer ? tmp : NULL,
|
||||
sizeof(tmp),
|
||||
shorten_paths, demangle));
|
||||
EXPECT_CONTAINS(output, "jvm"); // "jvm.dll" or "libjvm.so" or similar
|
||||
LOG("%s", output);
|
||||
|
||||
// Pointer into system library
|
||||
#ifndef _WIN32
|
||||
addr = CAST_FROM_FN_PTR(address, ::malloc);
|
||||
st.reset();
|
||||
EXPECT_TRUE(os::print_function_and_library_name(&st, addr,
|
||||
provide_scratch_buffer ? tmp : NULL,
|
||||
sizeof(tmp),
|
||||
shorten_paths, demangle));
|
||||
EXPECT_CONTAINS(output, "malloc");
|
||||
LINUX_ONLY(EXPECT_CONTAINS(output, "libc"));
|
||||
MACOS_ONLY(EXPECT_CONTAINS(output, "libsystem"));
|
||||
LOG("%s", output);
|
||||
#else
|
||||
addr = CAST_FROM_FN_PTR(address, CreateFileA);
|
||||
st.reset(); // this also zero-terminates start of output
|
||||
EXPECT_TRUE(os::print_function_and_library_name(&st, addr,
|
||||
provide_scratch_buffer ? tmp : NULL,
|
||||
sizeof(tmp),
|
||||
shorten_paths, demangle));
|
||||
for (char* p = output; *p; p++) {
|
||||
*p = ::toupper(*p);
|
||||
}
|
||||
EXPECT_CONTAINS(output, "KERNEL32.DLL");
|
||||
LOG("%s", output);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user