Where does VMError::print_native_stack and os::get_sender_for_C_frame load/use the frame pointer?
Julian Waters
tanksherman27 at gmail.com
Tue Jul 9 05:14:58 UTC 2024
Hi David,
I just looked at the code for both, and it weirdly doesn't seem that
fetch_frame_from_context is used in either. Out of curiosity I tried
removing HAVE_PLATFORM_PRINT_NATIVE_STACK from Windows/x64 and
deliberately crashed HotSpot after compiling the JDK, and the
resulting hs_err file had almost no frame information as a result:
--------------- S U M M A R Y ------------
Command Line: --enable-preview Crash
Host: AMD Ryzen 9 7845HX with Radeon Graphics , 24 cores, 15G,
Windows 11 , 64 bit Build 22621 (10.0.22621.3672)
Time: Tue Jul 9 02:41:20 2024 Malay Peninsula Standard Time elapsed
time: 0.070338 seconds (0d 0h 0m 0s)
--------------- T H R E A D ---------------
Current thread (0x0000017e8cead250): JavaThread "main"
[_thread_in_vm, id=33760, stack(0x0000005c11f00000,0x0000005c12000000)
(1024K)]
Stack: [0x0000005c11f00000,0x0000005c12000000],
sp=0x0000005c11fff000, free space=1020k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V [jvm.dll+0x195ab57]
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j jdk.internal.misc.Unsafe.putLong(Ljava/lang/Object;JJ)V+0
java.base at 24-internal
j jdk.internal.misc.Unsafe.putAddress(Ljava/lang/Object;JJ)V+24
java.base at 24-internal
j jdk.internal.misc.Unsafe.putAddress(JJ)V+4 java.base at 24-internal
j sun.misc.Unsafe.putAddress(JJ)V+8 jdk.unsupported at 24-internal
j Crash.main()V+53
v ~StubRoutines::call_stub 0x0000017e9fc70fcd
siginfo: EXCEPTION_ACCESS_VIOLATION (0xc0000005), writing address
0x0000000000000000
Native frames only has 1 frame in it, indicative of further frames not
being found. I can't really tell what else is required to get it to
work with the regular VMError::print_native_stack without requiring
the Windows specific os::win32::platform_print_native_stack. I
compiled HotSpot with gcc and verified that the frame pointer is
indeed saved, so this not working is a little odd to me (Was testing
in the off chance that the Microsoft compiler could be forced to
preserve the frame pointer). There has to somehow be a way to walk the
frames on Windows when the frame pointer is available for use
best regards,
Julian
P.S. The attempted patch is attached below, if anyone is curious
diff --git a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp
b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp
index 7e0814c014b..a4fa45ed78f 100644
--- a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp
+++ b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp
@@ -71,7 +71,7 @@ extern LONG WINAPI
topLevelExceptionFilter(_EXCEPTION_POINTERS* );
// Install a win32 structured exception handler around thread.
void os::os_exception_wrapper(java_call_t f, JavaValue* value, const
methodHandle& method, JavaCallArguments* args, JavaThread* thread) {
- __try {
+ WIN32_TRY {
#ifndef AMD64
// We store the current thread in this wrapperthread location
@@ -111,7 +111,7 @@ void os::os_exception_wrapper(java_call_t f,
JavaValue* value, const methodHandl
#endif // !AMD64
f(value, method, args, thread);
- } __except(topLevelExceptionFilter((_EXCEPTION_POINTERS*)_exception_info()))
{
+ } WIN32_EXCEPT (topLevelExceptionFilter(GetExceptionInformation())) {
// Nothing to do.
}
}
@@ -396,16 +396,32 @@ bool
os::win32::get_frame_at_stack_banging_point(JavaThread* thread,
// VC++ does not save frame pointer on stack in optimized build. It
-// can be turned off by /Oy-. If we really want to walk C frames,
+// can be turned off by -Oy-. If we really want to walk C frames,
// we can use the StackWalk() API.
frame os::get_sender_for_C_frame(frame* fr) {
+#ifdef __GNUC__
+ return frame(fr->sender_sp(), fr->link(), fr->sender_pc());
+#elif defined(_MSC_VER)
ShouldNotReachHere();
return frame();
+#endif
}
frame os::current_frame() {
+#ifdef __GNUC__
+ frame f(reinterpret_cast<intptr_t*>(os::current_stack_pointer()),
+ reinterpret_cast<intptr_t*>(__builtin_frame_address(1)),
+ CAST_FROM_FN_PTR(address, &os::current_frame));
+ if (os::is_first_C_frame(&f)) {
+ // stack is not walkable
+ return frame();
+ } else {
+ return os::get_sender_for_C_frame(&f);
+ }
+#elif defined(_MSC_VER)
return frame(); // cannot walk Windows frames this way. See
os::get_native_stack
// and os::platform_print_native_stack
+#endif
}
void os::print_context(outputStream *st, const void *context) {
diff --git a/src/hotspot/os_cpu/windows_x86/os_windows_x86.inline.hpp
b/src/hotspot/os_cpu/windows_x86/os_windows_x86.inline.hpp
index f7622611da7..3461cd4c0b0 100644
--- a/src/hotspot/os_cpu/windows_x86/os_windows_x86.inline.hpp
+++ b/src/hotspot/os_cpu/windows_x86/os_windows_x86.inline.hpp
@@ -29,12 +29,14 @@
#include "os_windows.hpp"
#ifdef AMD64
+#ifdef _MSC_VER
#define HAVE_PLATFORM_PRINT_NATIVE_STACK 1
inline bool os::platform_print_native_stack(outputStream* st, const
void* context,
char *buf, int buf_size,
address& lastpc) {
return os::win32::platform_print_native_stack(st, context, buf,
buf_size, lastpc);
}
#endif
+#endif
inline jlong os::rdtsc() {
// 32 bit: 64 bit result in edx:eax
diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp
index 7b766707b0d..d3613652f45 100644
--- a/src/hotspot/share/runtime/os.cpp
+++ b/src/hotspot/share/runtime/os.cpp
@@ -179,7 +179,7 @@ char* os::iso8601_time(jlong
milliseconds_since_19700101, char* buffer, size_t b
// No offset when dealing with UTC
time_t UTC_to_local = 0;
if (!utc) {
-#if (defined(_ALLBSD_SOURCE) || defined(_GNU_SOURCE)) && !defined(AIX)
+#if (defined(_ALLBSD_SOURCE) || defined(_GNU_SOURCE)) &&
!defined(AIX) && !defined(_WIN32)
UTC_to_local = -(time_struct.tm_gmtoff);
#elif defined(_WINDOWS)
long zone;
@@ -1349,7 +1349,9 @@ static bool is_pointer_bad(intptr_t* ptr) {
bool os::is_first_C_frame(frame* fr) {
#ifdef _WINDOWS
+#ifdef _MSC_VER
return true; // native stack isn't walkable on windows this way.
+#endif
#endif
// Load up sp, fp, sender sp and sender fp, check for reasonable values.
// Check usp first, because if that's bad the other accessors may fault
On Mon, Jul 8, 2024 at 4:49 PM David Holmes <david.holmes at oracle.com> wrote:
>
> On 8/07/2024 5:59 pm, Julian Waters wrote:
> > Hi David,
> >
> > Ah, I think you misunderstood me, I'm aware that the frame pointer is
> > saved as required by the compiler (With the exception of the Microsoft
> > compiler, which doesn't save it at all). What I meant was that the
> > comments in Windows code imply that VMError::print_native_stack and
> > os::get_sender_for_C_frame need to use the frame pointer, yet I can't
> > seem to find where or how either of them obtain the frame pointer for
> > whatever they use it for on platforms and compilers where the frame
> > pointer is saved (For instance, on Linux), whether through handwritten
> > assembly code or some other means. It follows that if they need to use
> > the frame pointer, then they must grab it from somewhere, after all
>
> Ah sorry. AFAICS we just create the frame() objects and wallk the stack
> via those. We use fetch_frame_from_context to kick things off in the
> case of a crash.
>
> David
>
> > best regards,
> > Julian
More information about the hotspot-dev
mailing list