8373110: jstack --mixed frames are broken on macOS after JDK-8371194

Reviewed-by: dholmes
Backport-of: b848ddf6d3bf4e76d409b03be7f36199dadb2c5f
This commit is contained in:
Yasumasa Suenaga 2025-12-23 09:17:05 +00:00
parent 8e0d736b13
commit cece06f1aa
3 changed files with 96 additions and 31 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, Azul Systems, Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -86,18 +86,22 @@ class BsdCDebugger implements CDebugger {
String cpu = dbg.getCPU();
if (cpu.equals("amd64") || cpu.equals("x86_64")) {
AMD64ThreadContext context = (AMD64ThreadContext) thread.getContext();
Address rsp = context.getRegisterAsAddress(AMD64ThreadContext.RSP);
if (rsp == null) return null;
Address rbp = context.getRegisterAsAddress(AMD64ThreadContext.RBP);
if (rbp == null) return null;
Address pc = context.getRegisterAsAddress(AMD64ThreadContext.RIP);
if (pc == null) return null;
return new BsdAMD64CFrame(dbg, rbp, pc);
return new BsdAMD64CFrame(dbg, rsp, rbp, pc);
} else if (cpu.equals("aarch64")) {
AARCH64ThreadContext context = (AARCH64ThreadContext) thread.getContext();
Address sp = context.getRegisterAsAddress(AARCH64ThreadContext.SP);
if (sp == null) return null;
Address fp = context.getRegisterAsAddress(AARCH64ThreadContext.FP);
if (fp == null) return null;
Address pc = context.getRegisterAsAddress(AARCH64ThreadContext.PC);
if (pc == null) return null;
return new BsdAARCH64CFrame(dbg, fp, pc);
return new BsdAARCH64CFrame(dbg, sp, fp, pc);
} else {
throw new DebuggerException(cpu + " is not yet supported");
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, Red Hat Inc.
* Copyright (c) 2021, Azul Systems, Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@ -26,15 +26,19 @@
package sun.jvm.hotspot.debugger.bsd.aarch64;
import sun.jvm.hotspot.code.*;
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.debugger.aarch64.*;
import sun.jvm.hotspot.debugger.bsd.*;
import sun.jvm.hotspot.debugger.cdbg.*;
import sun.jvm.hotspot.debugger.cdbg.basic.*;
import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.runtime.aarch64.*;
public final class BsdAARCH64CFrame extends BasicCFrame {
public BsdAARCH64CFrame(BsdDebugger dbg, Address fp, Address pc) {
public BsdAARCH64CFrame(BsdDebugger dbg, Address sp, Address fp, Address pc) {
super(dbg.getCDebugger());
this.sp = sp;
this.fp = fp;
this.pc = pc;
this.dbg = dbg;
@ -54,28 +58,65 @@ public final class BsdAARCH64CFrame extends BasicCFrame {
return fp;
}
@Override
public CFrame sender(ThreadProxy thread) {
AARCH64ThreadContext context = (AARCH64ThreadContext) thread.getContext();
Address rsp = context.getRegisterAsAddress(AARCH64ThreadContext.SP);
return sender(thread, null, null, null);
}
if ((fp == null) || fp.lessThan(rsp)) {
@Override
public CFrame sender(ThreadProxy thread, Address nextSP, Address nextFP, Address nextPC) {
// Check fp
// Skip if both nextFP and nextPC are given - do not need to load from fp.
if (nextFP == null && nextPC == null) {
if (fp == null) {
return null;
}
// Check alignment of fp
if (dbg.getAddressValue(fp) % (2 * ADDRESS_SIZE) != 0) {
return null;
}
}
if (nextFP == null) {
nextFP = fp.getAddressAt(0);
}
if (nextFP == null) {
return null;
}
// Check alignment of fp
if (dbg.getAddressValue(fp) % (2 * ADDRESS_SIZE) != 0) {
return null;
if (nextPC == null) {
nextPC = fp.getAddressAt(ADDRESS_SIZE);
}
Address nextFP = fp.getAddressAt(0 * ADDRESS_SIZE);
if (nextFP == null || nextFP.lessThanOrEqual(fp)) {
return null;
}
Address nextPC = fp.getAddressAt(1 * ADDRESS_SIZE);
if (nextPC == null) {
return null;
}
return new BsdAARCH64CFrame(dbg, nextFP, nextPC);
if (nextSP == null) {
CodeCache cc = VM.getVM().getCodeCache();
CodeBlob currentBlob = cc.findBlobUnsafe(pc());
// This case is different from HotSpot. See JDK-8371194 for details.
if (currentBlob != null && (currentBlob.isContinuationStub() || currentBlob.isNativeMethod())) {
// Use FP since it should always be valid for these cases.
// TODO: These should be walked as Frames not CFrames.
nextSP = fp.addOffsetTo(2 * ADDRESS_SIZE);
} else {
CodeBlob codeBlob = cc.findBlobUnsafe(nextPC);
boolean useCodeBlob = codeBlob != null && codeBlob.getFrameSize() > 0;
nextSP = useCodeBlob ? nextFP.addOffsetTo((2 * ADDRESS_SIZE) - codeBlob.getFrameSize()) : nextFP;
}
}
if (nextSP == null) {
return null;
}
return new BsdAARCH64CFrame(dbg, nextSP, nextFP, nextPC);
}
@Override
public Frame toFrame() {
return new AARCH64Frame(sp, fp, pc);
}
// package/class internals only

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -29,10 +29,13 @@ import sun.jvm.hotspot.debugger.amd64.*;
import sun.jvm.hotspot.debugger.bsd.*;
import sun.jvm.hotspot.debugger.cdbg.*;
import sun.jvm.hotspot.debugger.cdbg.basic.*;
import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.runtime.amd64.*;
public final class BsdAMD64CFrame extends BasicCFrame {
public BsdAMD64CFrame(BsdDebugger dbg, Address rbp, Address rip) {
public BsdAMD64CFrame(BsdDebugger dbg, Address rsp, Address rbp, Address rip) {
super(dbg.getCDebugger());
this.rsp = rsp;
this.rbp = rbp;
this.rip = rip;
this.dbg = dbg;
@ -52,32 +55,49 @@ public final class BsdAMD64CFrame extends BasicCFrame {
return rbp;
}
@Override
public CFrame sender(ThreadProxy thread) {
AMD64ThreadContext context = (AMD64ThreadContext) thread.getContext();
Address rsp = context.getRegisterAsAddress(AMD64ThreadContext.RSP);
return sender(thread, null, null, null);
}
if ( (rbp == null) || rbp.lessThan(rsp) ) {
return null;
@Override
public CFrame sender(ThreadProxy thread, Address sp, Address fp, Address pc) {
// Check fp
// Skip if both fp and pc are given - do not need to load from rbp.
if (fp == null && pc == null) {
if (rbp == null) {
return null;
}
// Check alignment of rbp
if (dbg.getAddressValue(rbp) % ADDRESS_SIZE != 0) {
return null;
}
}
// Check alignment of rbp
if (dbg.getAddressValue(rbp) % ADDRESS_SIZE != 0) {
Address nextRSP = sp != null ? sp : rbp.addOffsetTo(2 * ADDRESS_SIZE);
if (nextRSP == null) {
return null;
}
Address nextRBP = rbp.getAddressAt( 0 * ADDRESS_SIZE);
if (nextRBP == null || nextRBP.lessThanOrEqual(rbp)) {
Address nextRBP = fp != null ? fp : rbp.getAddressAt(0);
if (nextRBP == null) {
return null;
}
Address nextPC = rbp.getAddressAt( 1 * ADDRESS_SIZE);
Address nextPC = pc != null ? pc : rbp.getAddressAt(ADDRESS_SIZE);
if (nextPC == null) {
return null;
}
return new BsdAMD64CFrame(dbg, nextRBP, nextPC);
return new BsdAMD64CFrame(dbg, nextRSP, nextRBP, nextPC);
}
@Override
public Frame toFrame() {
return new AMD64Frame(rsp, rbp, rip);
}
// package/class internals only
private static final int ADDRESS_SIZE = 8;
private Address rsp;
private Address rip;
private Address rbp;
private BsdDebugger dbg;