Skip to content

Commit db9eab3

Browse files
author
David Holmes
committed
8311542: Consolidate the native stack printing code
Reviewed-by: kbarrett, jwaters
1 parent 18e0b34 commit db9eab3

File tree

9 files changed

+256
-118
lines changed

9 files changed

+256
-118
lines changed

src/hotspot/share/oops/instanceKlass.cpp

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,9 @@
9797
#include "utilities/dtrace.hpp"
9898
#include "utilities/events.hpp"
9999
#include "utilities/macros.hpp"
100-
#include "utilities/stringUtils.hpp"
100+
#include "utilities/nativeStackPrinter.hpp"
101101
#include "utilities/pair.hpp"
102+
#include "utilities/stringUtils.hpp"
102103
#ifdef COMPILER1
103104
#include "c1/c1_Compiler.hpp"
104105
#endif
@@ -4009,14 +4010,9 @@ void InstanceKlass::print_class_load_cause_logging() const {
40094010
stringStream stack_stream;
40104011
char buf[O_BUFLEN];
40114012
address lastpc = nullptr;
4012-
if (os::platform_print_native_stack(&stack_stream, nullptr, buf, O_BUFLEN, lastpc)) {
4013-
// We have printed the native stack in platform-specific code,
4014-
// so nothing else to do in this case.
4015-
} else {
4016-
frame f = os::current_frame();
4017-
VMError::print_native_stack(&stack_stream, f, current, true /*print_source_info */,
4018-
-1 /* max stack_stream */, buf, O_BUFLEN);
4019-
}
4013+
NativeStackPrinter nsp(current);
4014+
nsp.print_stack(&stack_stream, buf, sizeof(buf), lastpc,
4015+
true /* print_source_info */, -1 /* max stack */);
40204016

40214017
LogMessage(class, load, cause, native) msg;
40224018
NonInterleavingLogStream info_stream{LogLevelType::Info, msg};

src/hotspot/share/runtime/frame.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1558,6 +1558,39 @@ void frame::describe(FrameValues& values, int frame_no, const RegisterMap* reg_m
15581558

15591559
#endif
15601560

1561+
/**
1562+
* Gets the caller frame of `fr` for thread `t`.
1563+
*
1564+
* @returns an invalid frame (i.e. fr.pc() === 0) if the caller cannot be obtained
1565+
*/
1566+
frame frame::next_frame(frame fr, Thread* t) {
1567+
// Compiled code may use EBP register on x86 so it looks like
1568+
// non-walkable C frame. Use frame.sender() for java frames.
1569+
frame invalid;
1570+
if (t != nullptr && t->is_Java_thread()) {
1571+
// Catch very first native frame by using stack address.
1572+
// For JavaThread stack_base and stack_size should be set.
1573+
if (!t->is_in_full_stack((address)(fr.real_fp() + 1))) {
1574+
return invalid;
1575+
}
1576+
if (fr.is_interpreted_frame() || (fr.cb() != nullptr && fr.cb()->frame_size() > 0)) {
1577+
RegisterMap map(JavaThread::cast(t),
1578+
RegisterMap::UpdateMap::skip,
1579+
RegisterMap::ProcessFrames::include,
1580+
RegisterMap::WalkContinuation::skip); // No update
1581+
return fr.sender(&map);
1582+
} else {
1583+
// is_first_C_frame() does only simple checks for frame pointer,
1584+
// it will pass if java compiled code has a pointer in EBP.
1585+
if (os::is_first_C_frame(&fr)) return invalid;
1586+
return os::get_sender_for_C_frame(&fr);
1587+
}
1588+
} else {
1589+
if (os::is_first_C_frame(&fr)) return invalid;
1590+
return os::get_sender_for_C_frame(&fr);
1591+
}
1592+
}
1593+
15611594
#ifndef PRODUCT
15621595

15631596
void FrameValues::describe(int owner, intptr_t* location, const char* description, int priority) {

src/hotspot/share/runtime/frame.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,7 @@ class frame {
440440
void interpreter_frame_print_on(outputStream* st) const;
441441
void print_on_error(outputStream* st, char* buf, int buflen, bool verbose = false) const;
442442
static void print_C_frame(outputStream* st, char* buf, int buflen, address pc);
443+
static frame next_frame(frame fr, Thread* t); // For native stack walking
443444

444445
#ifndef PRODUCT
445446
// Add annotated descriptions of memory locations belonging to this frame to values

src/hotspot/share/runtime/javaThread.cpp

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
#include "utilities/dtrace.hpp"
101101
#include "utilities/events.hpp"
102102
#include "utilities/macros.hpp"
103+
#include "utilities/nativeStackPrinter.hpp"
103104
#include "utilities/preserveException.hpp"
104105
#include "utilities/spinYield.hpp"
105106
#include "utilities/vmError.hpp"
@@ -1772,15 +1773,10 @@ void JavaThread::print_jni_stack() {
17721773
tty->print_cr("Unable to print native stack - out of memory");
17731774
return;
17741775
}
1776+
NativeStackPrinter nsp(this);
17751777
address lastpc = nullptr;
1776-
if (os::platform_print_native_stack(tty, nullptr, buf, O_BUFLEN, lastpc)) {
1777-
// We have printed the native stack in platform-specific code,
1778-
// so nothing else to do in this case.
1779-
} else {
1780-
frame f = os::current_frame();
1781-
VMError::print_native_stack(tty, f, this, true /*print_source_info */,
1782-
-1 /* max stack */, buf, O_BUFLEN);
1783-
}
1778+
nsp.print_stack(tty, buf, O_BUFLEN, lastpc,
1779+
true /*print_source_info */, -1 /* max stack */ );
17841780
} else {
17851781
print_active_stack_on(tty);
17861782
}

src/hotspot/share/utilities/debug.cpp

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
#include "utilities/formatBuffer.hpp"
6262
#include "utilities/globalDefinitions.hpp"
6363
#include "utilities/macros.hpp"
64+
#include "utilities/nativeStackPrinter.hpp"
6465
#include "utilities/unsigned5.hpp"
6566
#include "utilities/vmError.hpp"
6667

@@ -645,10 +646,11 @@ void help() {
645646
extern "C" DEBUGEXPORT void pns(void* sp, void* fp, void* pc) { // print native stack
646647
Command c("pns");
647648
static char buf[O_BUFLEN];
648-
Thread* t = Thread::current_or_null();
649649
// Call generic frame constructor (certain arguments may be ignored)
650650
frame fr(sp, fp, pc);
651-
VMError::print_native_stack(tty, fr, t, false, -1, buf, sizeof(buf));
651+
NativeStackPrinter nsp(Thread::current_or_null());
652+
nsp.print_stack_from_frame(tty, fr, buf, sizeof(buf),
653+
false /* print_source_info */, -1 /* max stack */);
652654
}
653655

654656
//
@@ -663,14 +665,9 @@ extern "C" DEBUGEXPORT void pns2() { // print native stack
663665
Command c("pns2");
664666
static char buf[O_BUFLEN];
665667
address lastpc = nullptr;
666-
if (os::platform_print_native_stack(tty, nullptr, buf, sizeof(buf), lastpc)) {
667-
// We have printed the native stack in platform-specific code,
668-
// so nothing else to do in this case.
669-
} else {
670-
Thread* t = Thread::current_or_null();
671-
frame fr = os::current_frame();
672-
VMError::print_native_stack(tty, fr, t, false, -1, buf, sizeof(buf));
673-
}
668+
NativeStackPrinter nsp(Thread::current_or_null());
669+
nsp.print_stack(tty, buf, sizeof(buf), lastpc,
670+
false /* print_source_info */, -1 /* max stack */);
674671
}
675672
#endif
676673

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*
23+
*/
24+
25+
#include "precompiled.hpp"
26+
#include "runtime/frame.inline.hpp"
27+
#include "runtime/os.inline.hpp"
28+
#include "utilities/decoder.hpp"
29+
#include "utilities/globalDefinitions.hpp"
30+
#include "utilities/nativeStackPrinter.hpp"
31+
#include "utilities/ostream.hpp"
32+
33+
bool NativeStackPrinter::print_stack(outputStream* st, char* buf, int buf_size,
34+
address& lastpc, bool print_source_info,
35+
int max_frames) {
36+
if (os::platform_print_native_stack(st, _context, buf, buf_size, lastpc)) {
37+
return true;
38+
} else {
39+
print_stack_from_frame(st, buf, buf_size, print_source_info, max_frames);
40+
return false;
41+
}
42+
}
43+
44+
void NativeStackPrinter::print_stack_from_frame(outputStream* st, frame fr,
45+
char* buf, int buf_size,
46+
bool print_source_info, int max_frames) {
47+
// see if it's a valid frame
48+
if (fr.pc()) {
49+
st->print_cr("Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)");
50+
const int limit = max_frames == -1 ? StackPrintLimit
51+
: MIN2(max_frames, StackPrintLimit);
52+
int count = 0;
53+
while (count++ < limit) {
54+
fr.print_on_error(st, buf, buf_size);
55+
if (fr.pc()) { // print source file and line, if available
56+
char filename[128];
57+
int line_no;
58+
if (count == 1 && _lineno != 0) {
59+
// We have source information for the first frame for internal errors,
60+
// there is no need to parse it from the symbols.
61+
st->print(" (%s:%d)", _filename, _lineno);
62+
} else if (print_source_info &&
63+
Decoder::get_source_info(fr.pc(), filename, sizeof(filename), &line_no, count != 1)) {
64+
st->print(" (%s:%d)", filename, line_no);
65+
}
66+
}
67+
st->cr();
68+
fr = frame::next_frame(fr, _current);
69+
if (fr.pc() == nullptr) {
70+
break;
71+
}
72+
}
73+
74+
if (count > limit) {
75+
st->print_cr("...<more frames>...");
76+
}
77+
78+
} else {
79+
st->print_cr("Native frames: <unavailable>");
80+
}
81+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*
23+
*/
24+
#ifndef SHARE_UTILITIES_NATIVESTACKPRINTER_HPP
25+
#define SHARE_UTILITIES_NATIVESTACKPRINTER_HPP
26+
27+
#include "memory/allocation.hpp"
28+
#include "runtime/frame.hpp"
29+
#include "runtime/os.hpp"
30+
#include "utilities/globalDefinitions.hpp"
31+
32+
// Forward declarations
33+
class outputStream;
34+
class Thread;
35+
36+
// Helper class to do native stack printing from various contexts
37+
// including during crash reporting.
38+
// The NativeStackPrinter is created with the basic context information
39+
// available from the caller. Then the print_stack function is called
40+
// to do the actual printing.
41+
class NativeStackPrinter : public StackObj {
42+
Thread* _current; // Current thread if known
43+
const void* _context; // OS crash context if known
44+
const char* _filename; // Source file name if known
45+
int _lineno; // Source file line number if known
46+
47+
public:
48+
// Creates a NativeStackPrinter using the given additional context
49+
// information:
50+
// - the current thread is used for frame-based stack walking
51+
// - context is the crash context from the OS and can be used to get a frame;
52+
// otherwise os::current_frame() will be used
53+
// - filename and lineno provide details from the fatal error handler so we
54+
// can skip use of the Decoder for the first line (optimization)
55+
NativeStackPrinter(Thread* current_or_null,
56+
const void* context,
57+
const char* filename,
58+
int lineno) :
59+
_current(current_or_null),
60+
_context(context),
61+
_filename(filename),
62+
_lineno(lineno) {
63+
assert((_lineno == 0 && _filename == nullptr) ||
64+
(_lineno > 0 && _filename != nullptr),
65+
"file name and line number need to be provided together");
66+
}
67+
68+
NativeStackPrinter(Thread* current_or_null)
69+
: NativeStackPrinter(current_or_null, nullptr, nullptr, 0) {}
70+
71+
// Prints the stack of the current thread to the given stream.
72+
// We first try to print via os::platform_print_native_stack. If that
73+
// succeeds then lastpc is set and we return true. Otherwise we do a
74+
// frame walk to print the stack, and return false.
75+
// - st: the stream to print to
76+
// - buf, buf_size: temporary buffer to use for formatting output
77+
// - print_source_info: see print_stack_from_frame
78+
// - max_frames: see print_stack_from_frame
79+
//
80+
bool print_stack(outputStream* st, char* buf, int buf_size,
81+
address& lastpc, bool print_source_info,
82+
int max_frames);
83+
84+
// Prints the stack to st by walking the frames starting from
85+
// either the context frame, else the current frame.
86+
// - st: the stream to print to
87+
// - buf, buf_size: temporary buffer to use when printing frames
88+
// - print_source_info: if true obtains source information from the Decoder
89+
// if available. (Useful but may slow down, timeout or
90+
// misfunction in error situations)
91+
// - max_frames: the maximum number of frames to print. -1 means print all.
92+
// However, StackPrintLimit sets a hard limit on the maximum.
93+
void print_stack_from_frame(outputStream* st, frame fr,
94+
char* buf, int buf_size,
95+
bool print_source_info, int max_frames);
96+
97+
// Prints the stack to st by walking the frames starting from
98+
// either the context frame, else the current frame.
99+
void print_stack_from_frame(outputStream* st,
100+
char* buf, int buf_size,
101+
bool print_source_info, int max_frames) {
102+
frame fr = _context != nullptr ? os::fetch_frame_from_context(_context)
103+
: os::current_frame();
104+
print_stack_from_frame(st, fr, buf, buf_size, print_source_info, max_frames);
105+
}
106+
};
107+
108+
#endif // SHARE_UTILITIES_NATIVESTACKPRINTER_HPP

0 commit comments

Comments
 (0)