diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java index 70cd1fa72ce..2734504150b 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java @@ -115,12 +115,26 @@ public final class LinuxAMD64CFrame extends BasicCFrame { } } - private boolean isValidFrame(Address nextCFA, boolean isNative) { - // CFA should never be null. - // nextCFA must be greater than current CFA, if frame is native. - // Java interpreter frames can share the CFA (frame pointer). - return nextCFA != null && - (!isNative || (isNative && nextCFA.greaterThanOrEqual(cfa))); + private boolean isValidFrame(Address nextCFA, Address nextRBP) { + // Both CFA and RBP must not be null. + if (nextCFA == null && nextRBP == null) { + return false; + } + + // RBP must not be null if CFA is null - it happens between Java frame and Native frame. + // We cannot validate RBP value because it might be used as GPR. Thus returns true + // if RBP is not null. + if (nextCFA == null && nextRBP != null) { + return true; + } + + // nextCFA must be greater than current CFA. + if (nextCFA != null && nextCFA.greaterThanOrEqual(cfa)) { + return true; + } + + // Otherwise, the frame is not valid. + return false; } private Address getNextRSP() { @@ -129,48 +143,6 @@ public final class LinuxAMD64CFrame extends BasicCFrame { .addOffsetTo(ADDRESS_SIZE); // Native frame } - private Address getNextCFA(DwarfParser nextDwarf, Address senderFP, Address senderPC) { - Address nextCFA; - boolean isNative = false; - - if (nextDwarf == null) { // Next frame is Java - return null; - } else { // Next frame is Native - if (dwarf == null) { // Current frame is Java - int nextCFAReg = nextDwarf.getCFARegister(); - if (nextCFAReg == AMD64ThreadContext.RBP) { - nextCFA = nextDwarf.isBPOffsetAvailable() - ? rbp.getAddressAt(0) // We can use cfa as BP in Java frame - .addOffsetTo(-nextDwarf.getBasePointerOffsetFromCFA()) - : rbp; - } else if (nextCFAReg == AMD64ThreadContext.RSP) { - nextCFA = senderFP.addOffsetTo(2 * ADDRESS_SIZE) // skip BP and RA to get caller SP - .addOffsetTo(nextDwarf.getCFAOffset()); - } else { - throw new DebuggerException("Unsupported CFA register: " + nextCFAReg); - } - } else { // Current frame is Native - isNative = true; - int nextCFAReg = nextDwarf.getCFARegister(); - if (nextCFAReg == AMD64ThreadContext.RBP) { - Address nextRBP = getNextRBP(senderFP); - nextCFA = nextRBP.addOffsetTo(-nextDwarf.getBasePointerOffsetFromCFA()); - } else if (nextCFAReg == AMD64ThreadContext.RSP) { - nextCFA = getNextRSP().addOffsetTo(nextDwarf.getCFAOffset()); - } else { - throw new DebuggerException("Unsupported CFA register: " + nextCFAReg); - } - } - } - - if (dbg.isSignalTrampoline(senderPC)) { - // Return without frame check if sender is signal trampoline. - return nextCFA; - } else { - return isValidFrame(nextCFA, isNative) ? nextCFA : null; - } - } - private Address getNextRBP(Address senderFP) { if (senderFP != null) { return senderFP; @@ -183,6 +155,21 @@ public final class LinuxAMD64CFrame extends BasicCFrame { } } + private Address getNextCFA(DwarfParser nextDwarf, Address senderFP, Address senderPC) { + if (nextDwarf == null) { // Next frame is Java + // CFA is not available on Java frame + return null; + } + + // Next frame is Native + int nextCFAReg = nextDwarf.getCFARegister(); + return switch(nextCFAReg){ + case AMD64ThreadContext.RBP -> getNextRBP(senderFP).addOffsetTo(nextDwarf.getCFAOffset()); + case AMD64ThreadContext.RSP -> getNextRSP().addOffsetTo(nextDwarf.getCFAOffset()); + default -> throw new DebuggerException("Unsupported CFA register: " + nextCFAReg); + }; + } + @Override public CFrame sender(ThreadProxy th) { return sender(th, null, null, null); @@ -229,12 +216,19 @@ public final class LinuxAMD64CFrame extends BasicCFrame { try { Address nextCFA = getNextCFA(nextDwarf, fp, nextPC); - return (nextCFA == null && nextRBP == null) - ? null - : new LinuxAMD64CFrame(dbg, nextRSP, nextRBP, nextCFA, nextPC, nextDwarf, fallback); - } catch (DebuggerException _) { - return nextRBP == null ? null - : new LinuxAMD64CFrame(dbg, nextRSP, nextRBP, null, nextPC, null, fallback); + return isValidFrame(nextCFA, nextRBP) + ? new LinuxAMD64CFrame(dbg, nextRSP, nextRBP, nextCFA, nextPC, nextDwarf, fallback) + : null; + } catch (DebuggerException e) { + if (dbg.isSignalTrampoline(nextPC)) { + // We can through the caller frame if it is signal trampoline. + // getNextCFA() might fail because DwarfParser cannot find out CFA register. + return new LinuxAMD64CFrame(dbg, nextRSP, nextRBP, null, nextPC, nextDwarf, fallback); + } + + // Rethrow the original exception if getNextCFA() failed + // and the caller is not signal trampoline. + throw e; } }