1 /*
   2  * Copyright (c) 2003, 2019, 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 package sun.jvm.hotspot.debugger.linux.amd64;
  26 
  27 import sun.jvm.hotspot.debugger.*;
  28 import sun.jvm.hotspot.debugger.amd64.*;
  29 import sun.jvm.hotspot.debugger.linux.*;
  30 import sun.jvm.hotspot.debugger.cdbg.*;
  31 import sun.jvm.hotspot.debugger.cdbg.basic.*;
  32 
  33 final public class LinuxAMD64CFrame extends BasicCFrame {
  34    public LinuxAMD64CFrame(LinuxDebugger dbg, Address cfa, Address rip, DwarfParser dwarf) {
  35       super(dbg.getCDebugger());
  36       this.cfa = cfa;
  37       this.rip = rip;
  38       this.dbg = dbg;
  39       this.dwarf = dwarf;
  40    }
  41 
  42    // override base class impl to avoid ELF parsing
  43    public ClosestSymbol closestSymbolToPC() {
  44       // try native lookup in debugger.
  45       return dbg.lookup(dbg.getAddressValue(pc()));
  46    }
  47 
  48    public Address pc() {
  49       return rip;
  50    }
  51 
  52    public Address localVariableBase() {
  53       return cfa;
  54    }
  55 
  56    private boolean isValidFrame(Address nextCFA, ThreadProxy thread) {
  57      return (nextCFA != null) &&
  58              !nextCFA.addOffsetTo(1 * 1024 * 1024 * 1024).lessThan(cfa) && // FIXME: assume to 1GB diff
  59              !nextCFA.lessThan(thread.getContext().getRegisterAsAddress(AMD64ThreadContext.RSP));
  60    }
  61 
  62    private CFrame javaSender(ThreadProxy thread) {
  63       Address nextCFA;
  64       Address nextPC;
  65       try { // FIXME: cannot read RBP from CFA in some case
  66         nextCFA = cfa.getAddressAt(0);
  67         // FIXME: assume to 1GB diff of stack
  68         if (!isValidFrame(nextCFA, thread)) {
  69           return null;
  70         }
  71 
  72         nextPC  = nextCFA.getAddressAt( 1 * ADDRESS_SIZE);
  73         if (nextPC == null) {
  74           return null;
  75         }
  76       } catch (UnmappedAddressException | UnalignedAddressException e) {
  77         return null;
  78       }
  79 
  80       DwarfParser nextDwarf = null;
  81       long libptr = dbg.findLibPtrByAddress(nextPC);
  82       if (libptr != 0L) { // Native frame
  83         try {
  84           nextDwarf = new DwarfParser(libptr);
  85         } catch (DebuggerException e) {
  86           return new LinuxAMD64CFrame(dbg, nextCFA, nextPC, null);
  87         }
  88         nextDwarf.processDwarf(nextPC);
  89         nextCFA = nextCFA.addOffsetTo(- nextDwarf.getBasePointerOffsetFromCFA());
  90         if (!isValidFrame(nextCFA, thread)) {
  91           return null;
  92         }
  93       }
  94 
  95       return new LinuxAMD64CFrame(dbg, nextCFA, nextPC, nextDwarf);
  96    }
  97 
  98    public CFrame sender(ThreadProxy thread) {
  99       if (dwarf == null) { // Java frame
 100         return javaSender(thread);
 101       }
 102 
 103       Address nextPC;
 104       Address nextCFA;
 105       try { // FIXME: cannot read RBP from CFA in some case
 106         nextPC  = cfa.getAddressAt(dwarf.getReturnAddressOffsetFromCFA());
 107         if (nextPC == null) {
 108           return null;
 109         }
 110 
 111         nextCFA = cfa.getAddressAt(dwarf.getBasePointerOffsetFromCFA());
 112         if (!isValidFrame(nextCFA, thread)) {
 113           return null;
 114         }
 115       } catch (UnmappedAddressException | UnalignedAddressException e) {
 116         return null;
 117       }
 118 
 119       DwarfParser nextDwarf = dwarf;
 120       if (!dwarf.isIn(nextPC)) {
 121         long libptr = dbg.findLibPtrByAddress(nextPC);
 122         if (libptr == 0L) {
 123           // Next frame might be Java frame
 124           return new LinuxAMD64CFrame(dbg, nextCFA, nextPC, null);
 125         }
 126         try {
 127           nextDwarf = new DwarfParser(libptr);
 128         } catch (DebuggerException e) {
 129           nextCFA = cfa.getAddressAt(0);
 130           return isValidFrame(nextCFA, thread) ? new LinuxAMD64CFrame(dbg, nextCFA, nextPC, null)
 131                                                : null;
 132         }
 133       }
 134 
 135       nextDwarf.processDwarf(nextPC);
 136 
 137       int nextCFAReg = nextDwarf.getCFARegister();
 138       if (!dwarf.isBPOffsetAvailable() &&
 139           (nextCFAReg == AMD64ThreadContext.RBP) &&
 140           (nextCFAReg != dwarf.getCFARegister())) {
 141         nextCFA = thread.getContext()
 142                         .getRegisterAsAddress(AMD64ThreadContext.RBP);
 143         if (!isValidFrame(nextCFA, thread)) {
 144           return null;
 145         }
 146       }
 147 
 148       nextCFA = nextCFA.addOffsetTo(- nextDwarf.getBasePointerOffsetFromCFA());
 149       return isValidFrame(nextCFA, thread) ? new LinuxAMD64CFrame(dbg, nextCFA, nextPC, nextDwarf)
 150                                            : null;
 151    }
 152 
 153    // package/class internals only
 154    private static final int ADDRESS_SIZE = 8;
 155    private Address rip;
 156    private Address cfa;
 157    private LinuxDebugger dbg;
 158    private DwarfParser dwarf;
 159 }