8058345: Refactor native stack printing from vmError.cpp to debug.cpp to make it available in gdb as well
Also fix stack trace on x86 to enable walking of runtime stubs and native wrappers Reviewed-by: kvn
This commit is contained in:
parent
f85f7d2832
commit
a1628426d3
@ -308,3 +308,10 @@ intptr_t *frame::initial_deoptimization_info() {
|
||||
// unused... but returns fp() to minimize changes introduced by 7087445
|
||||
return fp();
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
// This is a generic constructor which is only used by pns() in debug.cpp.
|
||||
frame::frame(void* sp, void* fp, void* pc) : _sp((intptr_t*)sp), _unextended_sp((intptr_t*)sp) {
|
||||
find_codeblob_and_set_pc_and_deopt_state((address)pc); // also sets _fp and adjusts _unextended_sp
|
||||
}
|
||||
#endif
|
||||
|
@ -343,7 +343,7 @@ bool frame::safe_for_sender(JavaThread *thread) {
|
||||
// constructors
|
||||
|
||||
// Construct an unpatchable, deficient frame
|
||||
frame::frame(intptr_t* sp, unpatchable_t, address pc, CodeBlob* cb) {
|
||||
void frame::init(intptr_t* sp, address pc, CodeBlob* cb) {
|
||||
#ifdef _LP64
|
||||
assert( (((intptr_t)sp & (wordSize-1)) == 0), "frame constructor passed an invalid sp");
|
||||
#endif
|
||||
@ -365,6 +365,10 @@ frame::frame(intptr_t* sp, unpatchable_t, address pc, CodeBlob* cb) {
|
||||
#endif // ASSERT
|
||||
}
|
||||
|
||||
frame::frame(intptr_t* sp, unpatchable_t, address pc, CodeBlob* cb) {
|
||||
init(sp, pc, cb);
|
||||
}
|
||||
|
||||
frame::frame(intptr_t* sp, intptr_t* younger_sp, bool younger_frame_is_interpreted) :
|
||||
_sp(sp),
|
||||
_younger_sp(younger_sp),
|
||||
@ -419,6 +423,13 @@ frame::frame(intptr_t* sp, intptr_t* younger_sp, bool younger_frame_is_interpret
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
// This is a generic constructor which is only used by pns() in debug.cpp.
|
||||
frame::frame(void* sp, void* fp, void* pc) {
|
||||
init((intptr_t*)sp, (address)pc, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool frame::is_interpreted_frame() const {
|
||||
return Interpreter::contains(pc());
|
||||
}
|
||||
|
@ -163,6 +163,8 @@
|
||||
enum unpatchable_t { unpatchable };
|
||||
frame(intptr_t* sp, unpatchable_t, address pc = NULL, CodeBlob* cb = NULL);
|
||||
|
||||
void init(intptr_t* sp, address pc, CodeBlob* cb);
|
||||
|
||||
// Walk from sp outward looking for old_sp, and return old_sp's predecessor
|
||||
// (i.e. return the sp from the frame where old_sp is the fp).
|
||||
// Register windows are assumed to be flushed for the stack in question.
|
||||
|
@ -715,3 +715,10 @@ intptr_t* frame::real_fp() const {
|
||||
assert(! is_compiled_frame(), "unknown compiled frame size");
|
||||
return fp();
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
// This is a generic constructor which is only used by pns() in debug.cpp.
|
||||
frame::frame(void* sp, void* fp, void* pc) {
|
||||
init((intptr_t*)sp, (intptr_t*)fp, (address)pc);
|
||||
}
|
||||
#endif
|
||||
|
@ -187,6 +187,8 @@
|
||||
|
||||
frame(intptr_t* sp, intptr_t* fp);
|
||||
|
||||
void init(intptr_t* sp, intptr_t* fp, address pc);
|
||||
|
||||
// accessors for the instance variables
|
||||
// Note: not necessarily the real 'frame pointer' (see real_fp)
|
||||
intptr_t* fp() const { return _fp; }
|
||||
|
@ -41,7 +41,7 @@ inline frame::frame() {
|
||||
_deopt_state = unknown;
|
||||
}
|
||||
|
||||
inline frame::frame(intptr_t* sp, intptr_t* fp, address pc) {
|
||||
inline void frame::init(intptr_t* sp, intptr_t* fp, address pc) {
|
||||
_sp = sp;
|
||||
_unextended_sp = sp;
|
||||
_fp = fp;
|
||||
@ -59,6 +59,10 @@ inline frame::frame(intptr_t* sp, intptr_t* fp, address pc) {
|
||||
}
|
||||
}
|
||||
|
||||
inline frame::frame(intptr_t* sp, intptr_t* fp, address pc) {
|
||||
init(sp, fp, pc);
|
||||
}
|
||||
|
||||
inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc) {
|
||||
_sp = sp;
|
||||
_unextended_sp = unextended_sp;
|
||||
|
@ -438,3 +438,10 @@ intptr_t *frame::initial_deoptimization_info() {
|
||||
// unused... but returns fp() to minimize changes introduced by 7087445
|
||||
return fp();
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
// This is a generic constructor which is only used by pns() in debug.cpp.
|
||||
frame::frame(void* sp, void* fp, void* pc) {
|
||||
Unimplemented();
|
||||
}
|
||||
#endif
|
||||
|
@ -265,7 +265,7 @@ frame os::current_frame() {
|
||||
CAST_FROM_FN_PTR(address, os::current_frame));
|
||||
if (os::is_first_C_frame(&myframe)) {
|
||||
// stack is not walkable
|
||||
return frame(NULL, NULL, NULL);
|
||||
return frame(NULL, NULL, false);
|
||||
} else {
|
||||
return os::get_sender_for_C_frame(&myframe);
|
||||
}
|
||||
|
@ -68,6 +68,15 @@ class frame VALUE_OBJ_CLASS_SPEC {
|
||||
// Constructors
|
||||
frame();
|
||||
|
||||
#ifndef PRODUCT
|
||||
// This is a generic constructor which is only used by pns() in debug.cpp.
|
||||
// pns (i.e. print native stack) uses this constructor to create a starting
|
||||
// frame for stack walking. The implementation of this constructor is platform
|
||||
// dependent (i.e. SPARC doesn't need an 'fp' argument an will ignore it) but
|
||||
// we want to keep the signature generic because pns() is shared code.
|
||||
frame(void* sp, void* fp, void* pc);
|
||||
#endif
|
||||
|
||||
// Accessors
|
||||
|
||||
// pc: Returns the pc at which this frame will continue normally.
|
||||
|
@ -653,6 +653,13 @@ void help() {
|
||||
tty->print_cr(" pm(int pc) - print Method* given compiled PC");
|
||||
tty->print_cr(" findm(intptr_t pc) - finds Method*");
|
||||
tty->print_cr(" find(intptr_t x) - finds & prints nmethod/stub/bytecode/oop based on pointer into it");
|
||||
tty->print_cr(" pns(void* sp, void* fp, void* pc) - print native (i.e. mixed) stack trace. E.g.");
|
||||
tty->print_cr(" pns($sp, $rbp, $pc) on Linux/amd64 and Solaris/amd64 or");
|
||||
tty->print_cr(" pns($sp, $ebp, $pc) on Linux/x86 or");
|
||||
tty->print_cr(" pns($sp, 0, $pc) on Linux/ppc64 or");
|
||||
tty->print_cr(" pns($sp + 0x7ff, 0, $pc) on Solaris/SPARC");
|
||||
tty->print_cr(" - in gdb do 'set overload-resolution off' before calling pns()");
|
||||
tty->print_cr(" - in dbx do 'frame 1' before calling pns()");
|
||||
|
||||
tty->print_cr("misc.");
|
||||
tty->print_cr(" flush() - flushes the log file");
|
||||
@ -665,3 +672,56 @@ void help() {
|
||||
}
|
||||
|
||||
#endif // !PRODUCT
|
||||
|
||||
void print_native_stack(outputStream* st, frame fr, Thread* t, char* buf, int buf_size) {
|
||||
|
||||
// see if it's a valid frame
|
||||
if (fr.pc()) {
|
||||
st->print_cr("Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)");
|
||||
|
||||
int count = 0;
|
||||
while (count++ < StackPrintLimit) {
|
||||
fr.print_on_error(st, buf, buf_size);
|
||||
st->cr();
|
||||
// Compiled code may use EBP register on x86 so it looks like
|
||||
// non-walkable C frame. Use frame.sender() for java frames.
|
||||
if (t && t->is_Java_thread()) {
|
||||
// Catch very first native frame by using stack address.
|
||||
// For JavaThread stack_base and stack_size should be set.
|
||||
if (!t->on_local_stack((address)(fr.real_fp() + 1))) {
|
||||
break;
|
||||
}
|
||||
if (fr.is_java_frame() || fr.is_native_frame() || fr.is_runtime_frame()) {
|
||||
RegisterMap map((JavaThread*)t, false); // No update
|
||||
fr = fr.sender(&map);
|
||||
} else {
|
||||
fr = os::get_sender_for_C_frame(&fr);
|
||||
}
|
||||
} else {
|
||||
// is_first_C_frame() does only simple checks for frame pointer,
|
||||
// it will pass if java compiled code has a pointer in EBP.
|
||||
if (os::is_first_C_frame(&fr)) break;
|
||||
fr = os::get_sender_for_C_frame(&fr);
|
||||
}
|
||||
}
|
||||
|
||||
if (count > StackPrintLimit) {
|
||||
st->print_cr("...<more frames>...");
|
||||
}
|
||||
|
||||
st->cr();
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
||||
extern "C" void pns(void* sp, void* fp, void* pc) { // print native stack
|
||||
Command c("pns");
|
||||
static char buf[O_BUFLEN];
|
||||
Thread* t = ThreadLocalStorage::get_thread_slow();
|
||||
// Call generic frame constructor (certain arguments may be ignored)
|
||||
frame fr(sp, fp, pc);
|
||||
print_native_stack(tty, fr, t, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
#endif // !PRODUCT
|
||||
|
@ -263,4 +263,7 @@ NOT_PRODUCT(void test_error_handler();)
|
||||
void pd_ps(frame f);
|
||||
void pd_obfuscate_location(char *buf, size_t buflen);
|
||||
|
||||
class outputStream;
|
||||
void print_native_stack(outputStream* st, frame fr, Thread* t, char* buf, int buf_size);
|
||||
|
||||
#endif // SHARE_VM_UTILITIES_DEBUG_HPP
|
||||
|
@ -577,7 +577,7 @@ void VMError::report(outputStream* st) {
|
||||
|
||||
STEP(120, "(printing native stack)" )
|
||||
|
||||
if (_verbose) {
|
||||
if (_verbose) {
|
||||
if (os::platform_print_native_stack(st, _context, buf, sizeof(buf))) {
|
||||
// We have printed the native stack in platform-specific code
|
||||
// Windows/x64 needs special handling.
|
||||
@ -585,43 +585,7 @@ void VMError::report(outputStream* st) {
|
||||
frame fr = _context ? os::fetch_frame_from_context(_context)
|
||||
: os::current_frame();
|
||||
|
||||
// see if it's a valid frame
|
||||
if (fr.pc()) {
|
||||
st->print_cr("Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)");
|
||||
|
||||
|
||||
int count = 0;
|
||||
while (count++ < StackPrintLimit) {
|
||||
fr.print_on_error(st, buf, sizeof(buf));
|
||||
st->cr();
|
||||
// Compiled code may use EBP register on x86 so it looks like
|
||||
// non-walkable C frame. Use frame.sender() for java frames.
|
||||
if (_thread && _thread->is_Java_thread()) {
|
||||
// Catch very first native frame by using stack address.
|
||||
// For JavaThread stack_base and stack_size should be set.
|
||||
if (!_thread->on_local_stack((address)(fr.sender_sp() + 1))) {
|
||||
break;
|
||||
}
|
||||
if (fr.is_java_frame()) {
|
||||
RegisterMap map((JavaThread*)_thread, false); // No update
|
||||
fr = fr.sender(&map);
|
||||
} else {
|
||||
fr = os::get_sender_for_C_frame(&fr);
|
||||
}
|
||||
} else {
|
||||
// is_first_C_frame() does only simple checks for frame pointer,
|
||||
// it will pass if java compiled code has a pointer in EBP.
|
||||
if (os::is_first_C_frame(&fr)) break;
|
||||
fr = os::get_sender_for_C_frame(&fr);
|
||||
}
|
||||
}
|
||||
|
||||
if (count > StackPrintLimit) {
|
||||
st->print_cr("...<more frames>...");
|
||||
}
|
||||
|
||||
st->cr();
|
||||
}
|
||||
print_native_stack(st, fr, _thread, buf, sizeof(buf));
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user