1 /*
2  * Copyright (c) 2003, 2020, 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 
getTopFrame(LinuxDebugger dbg, Address rip, ThreadContext context)35    public static LinuxAMD64CFrame getTopFrame(LinuxDebugger dbg, Address rip, ThreadContext context) {
36       Address libptr = dbg.findLibPtrByAddress(rip);
37       Address cfa = context.getRegisterAsAddress(AMD64ThreadContext.RBP);
38       DwarfParser dwarf = null;
39 
40       if (libptr != null) { // Native frame
41         dwarf = new DwarfParser(libptr);
42         try {
43           dwarf.processDwarf(rip);
44         } catch (DebuggerException e) {
45           // DWARF processing should succeed when the frame is native
46           // but it might fail if Common Information Entry (CIE) has language
47           // personality routine and/or Language Specific Data Area (LSDA).
48           return new LinuxAMD64CFrame(dbg, cfa, rip, dwarf, true);
49         }
50         cfa = ((dwarf.getCFARegister() == AMD64ThreadContext.RBP) &&
51                !dwarf.isBPOffsetAvailable())
52                   ? context.getRegisterAsAddress(AMD64ThreadContext.RBP)
53                   : context.getRegisterAsAddress(dwarf.getCFARegister())
54                            .addOffsetTo(dwarf.getCFAOffset());
55       }
56 
57       return (cfa == null) ? null
58                            : new LinuxAMD64CFrame(dbg, cfa, rip, dwarf);
59    }
60 
LinuxAMD64CFrame(LinuxDebugger dbg, Address cfa, Address rip, DwarfParser dwarf)61    private LinuxAMD64CFrame(LinuxDebugger dbg, Address cfa, Address rip, DwarfParser dwarf) {
62       this(dbg, cfa, rip, dwarf, false);
63    }
64 
LinuxAMD64CFrame(LinuxDebugger dbg, Address cfa, Address rip, DwarfParser dwarf, boolean finalFrame)65    private LinuxAMD64CFrame(LinuxDebugger dbg, Address cfa, Address rip, DwarfParser dwarf, boolean finalFrame) {
66       super(dbg.getCDebugger());
67       this.cfa = cfa;
68       this.rip = rip;
69       this.dbg = dbg;
70       this.dwarf = dwarf;
71       this.finalFrame = finalFrame;
72    }
73 
74    // override base class impl to avoid ELF parsing
closestSymbolToPC()75    public ClosestSymbol closestSymbolToPC() {
76       // try native lookup in debugger.
77       return dbg.lookup(dbg.getAddressValue(pc()));
78    }
79 
pc()80    public Address pc() {
81       return rip;
82    }
83 
localVariableBase()84    public Address localVariableBase() {
85       return cfa;
86    }
87 
getNextPC(boolean useDwarf)88    private Address getNextPC(boolean useDwarf) {
89      try {
90        long offs = useDwarf ? dwarf.getReturnAddressOffsetFromCFA()
91                             : ADDRESS_SIZE;
92        return cfa.getAddressAt(offs);
93      } catch (UnmappedAddressException | UnalignedAddressException e) {
94        return null;
95      }
96    }
97 
isValidFrame(Address nextCFA, ThreadContext context)98    private boolean isValidFrame(Address nextCFA, ThreadContext context) {
99      return (nextCFA != null) &&
100              !nextCFA.lessThan(context.getRegisterAsAddress(AMD64ThreadContext.RSP));
101    }
102 
getNextCFA(DwarfParser nextDwarf, ThreadContext context)103    private Address getNextCFA(DwarfParser nextDwarf, ThreadContext context) {
104      Address nextCFA;
105 
106      if (nextDwarf == null) { // Next frame is Java
107        nextCFA = (dwarf == null) ? cfa.getAddressAt(0) // Current frame is Java (Use RBP)
108                                  : cfa.getAddressAt(dwarf.getBasePointerOffsetFromCFA()); // Current frame is Native
109      } else { // Next frame is Native
110        if (dwarf == null) { // Current frame is Java (Use RBP)
111          nextCFA = cfa.getAddressAt(0);
112        } else { // Current frame is Native
113          int nextCFAReg = nextDwarf.getCFARegister();
114          if (!dwarf.isBPOffsetAvailable() && // Use RBP as CFA
115              (nextCFAReg == AMD64ThreadContext.RBP) &&
116              (nextCFAReg != dwarf.getCFARegister())) {
117            nextCFA = context.getRegisterAsAddress(AMD64ThreadContext.RBP);
118            if (nextCFA == null) {
119              return null;
120            }
121            nextCFA = nextCFA.getAddressAt(0);
122          } else {
123            nextCFA = cfa.getAddressAt(dwarf.getBasePointerOffsetFromCFA());
124          }
125        }
126        if (nextCFA != null) {
127          nextCFA = nextCFA.addOffsetTo(-nextDwarf.getBasePointerOffsetFromCFA());
128        }
129      }
130 
131      return isValidFrame(nextCFA, context) ? nextCFA : null;
132    }
133 
134    @Override
sender(ThreadProxy thread)135    public CFrame sender(ThreadProxy thread) {
136      if (finalFrame) {
137        return null;
138      }
139 
140      ThreadContext context = thread.getContext();
141 
142      Address nextPC = getNextPC(dwarf != null);
143      if (nextPC == null) {
144        return null;
145      }
146 
147      DwarfParser nextDwarf = null;
148 
149      if ((dwarf != null) && dwarf.isIn(nextPC)) {
150        nextDwarf = dwarf;
151      } else {
152        Address libptr = dbg.findLibPtrByAddress(nextPC);
153        if (libptr != null) {
154          try {
155            nextDwarf = new DwarfParser(libptr);
156          } catch (DebuggerException e) {
157            // Bail out to Java frame
158          }
159        }
160      }
161 
162      if (nextDwarf != null) {
163        try {
164          nextDwarf.processDwarf(nextPC);
165        } catch (DebuggerException e) {
166          // DWARF processing should succeed when the frame is native
167          // but it might fail if Common Information Entry (CIE) has language
168          // personality routine and/or Language Specific Data Area (LSDA).
169          return new LinuxAMD64CFrame(dbg, null, nextPC, nextDwarf, true);
170        }
171      }
172 
173      Address nextCFA = getNextCFA(nextDwarf, context);
174      return isValidFrame(nextCFA, context) ? new LinuxAMD64CFrame(dbg, nextCFA, nextPC, nextDwarf)
175                                            : null;
176    }
177 
178    // package/class internals only
179    private static final int ADDRESS_SIZE = 8;
180    private Address rip;
181    private Address cfa;
182    private LinuxDebugger dbg;
183    private DwarfParser dwarf;
184    private boolean finalFrame;
185 }
186