--- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java 2019-11-25 14:00:57.900905400 +0900 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java 2019-11-25 14:00:57.235759200 +0900 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2019, 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 @@ -31,11 +31,12 @@ import sun.jvm.hotspot.debugger.cdbg.basic.*; final public class LinuxAMD64CFrame extends BasicCFrame { - public LinuxAMD64CFrame(LinuxDebugger dbg, Address rbp, Address rip) { + public LinuxAMD64CFrame(LinuxDebugger dbg, Address cfa, Address rip, DwarfParser dwarf) { super(dbg.getCDebugger()); - this.rbp = rbp; + this.cfa = cfa; this.rip = rip; this.dbg = dbg; + this.dwarf = dwarf; } // override base class impl to avoid ELF parsing @@ -49,36 +50,110 @@ } public Address localVariableBase() { - return rbp; + return cfa; } - public CFrame sender(ThreadProxy thread) { - AMD64ThreadContext context = (AMD64ThreadContext) thread.getContext(); - Address rsp = context.getRegisterAsAddress(AMD64ThreadContext.RSP); + private boolean isValidFrame(Address nextCFA, ThreadProxy thread) { + return (nextCFA != null) && + !nextCFA.addOffsetTo(1 * 1024 * 1024 * 1024).lessThan(cfa) && // FIXME: assume to 1GB diff + !nextCFA.lessThan(thread.getContext().getRegisterAsAddress(AMD64ThreadContext.RSP)); + } - if ( (rbp == null) || rbp.lessThan(rsp) ) { + private CFrame javaSender(ThreadProxy thread) { + Address nextCFA; + Address nextPC; + try { // FIXME: cannot read RBP from CFA in some case + nextCFA = cfa.getAddressAt(0); + // FIXME: assume to 1GB diff of stack + if (!isValidFrame(nextCFA, thread)) { + return null; + } + + nextPC = nextCFA.getAddressAt( 1 * ADDRESS_SIZE); + if (nextPC == null) { + return null; + } + } catch (UnmappedAddressException | UnalignedAddressException e) { return null; } - // Check alignment of rbp - if ( dbg.getAddressValue(rbp) % ADDRESS_SIZE != 0) { - return null; + DwarfParser nextDwarf = null; + long libptr = dbg.findLibPtrByAddress(nextPC); + if (libptr != 0L) { // Native frame + try { + nextDwarf = new DwarfParser(libptr); + } catch (DebuggerException e) { + return new LinuxAMD64CFrame(dbg, nextCFA, nextPC, null); + } + nextDwarf.processDwarf(nextPC); + nextCFA = nextCFA.addOffsetTo(- nextDwarf.getBasePointerOffsetFromCFA()); + if (!isValidFrame(nextCFA, thread)) { + return null; + } } - Address nextRBP = rbp.getAddressAt( 0 * ADDRESS_SIZE); - if (nextRBP == null || nextRBP.lessThanOrEqual(rbp)) { - return null; + return new LinuxAMD64CFrame(dbg, nextCFA, nextPC, nextDwarf); + } + + public CFrame sender(ThreadProxy thread) { + if (dwarf == null) { // Java frame + return javaSender(thread); } - Address nextPC = rbp.getAddressAt( 1 * ADDRESS_SIZE); - if (nextPC == null) { + + Address nextPC; + Address nextCFA; + try { // FIXME: cannot read RBP from CFA in some case + nextPC = cfa.getAddressAt(dwarf.getReturnAddressOffsetFromCFA()); + if (nextPC == null) { + return null; + } + + nextCFA = cfa.getAddressAt(dwarf.getBasePointerOffsetFromCFA()); + if (!isValidFrame(nextCFA, thread)) { + return null; + } + } catch (UnmappedAddressException | UnalignedAddressException e) { return null; } - return new LinuxAMD64CFrame(dbg, nextRBP, nextPC); + + DwarfParser nextDwarf = dwarf; + if (!dwarf.isIn(nextPC)) { + long libptr = dbg.findLibPtrByAddress(nextPC); + if (libptr == 0L) { + // Next frame might be Java frame + return new LinuxAMD64CFrame(dbg, nextCFA, nextPC, null); + } + try { + nextDwarf = new DwarfParser(libptr); + } catch (DebuggerException e) { + nextCFA = cfa.getAddressAt(0); + return isValidFrame(nextCFA, thread) ? new LinuxAMD64CFrame(dbg, nextCFA, nextPC, null) + : null; + } + } + + nextDwarf.processDwarf(nextPC); + + int nextCFAReg = nextDwarf.getCFARegister(); + if (!dwarf.isBPOffsetAvailable() && + (nextCFAReg == AMD64ThreadContext.RBP) && + (nextCFAReg != dwarf.getCFARegister())) { + nextCFA = thread.getContext() + .getRegisterAsAddress(AMD64ThreadContext.RBP); + if (!isValidFrame(nextCFA, thread)) { + return null; + } + } + + nextCFA = nextCFA.addOffsetTo(- nextDwarf.getBasePointerOffsetFromCFA()); + return isValidFrame(nextCFA, thread) ? new LinuxAMD64CFrame(dbg, nextCFA, nextPC, nextDwarf) + : null; } // package/class internals only private static final int ADDRESS_SIZE = 8; private Address rip; - private Address rbp; + private Address cfa; private LinuxDebugger dbg; + private DwarfParser dwarf; }