1 /* 2 * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. 3 * Copyright (c) 2015, Red Hat Inc. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 * 24 */ 25 26 package sun.jvm.hotspot.runtime.aarch64; 27 28 import sun.jvm.hotspot.debugger.*; 29 import sun.jvm.hotspot.debugger.aarch64.*; 30 import sun.jvm.hotspot.code.*; 31 import sun.jvm.hotspot.interpreter.*; 32 import sun.jvm.hotspot.runtime.*; 33 import sun.jvm.hotspot.runtime.aarch64.*; 34 35 /** <P> Should be able to be used on all aarch64 platforms we support 36 (Linux/aarch64) to implement JavaThread's "currentFrameGuess()" 37 functionality. Input is an AARCH64ThreadContext; output is SP, FP, 38 and PC for an AARCH64Frame. Instantiation of the AARCH64Frame is 39 left to the caller, since we may need to subclass AARCH64Frame to 40 support signal handler frames on Unix platforms. </P> 41 42 <P> Algorithm is to walk up the stack within a given range (say, 43 512K at most) looking for a plausible PC and SP for a Java frame, 44 also considering those coming in from the context. If we find a PC 45 that belongs to the VM (i.e., in generated code like the 46 interpreter or CodeCache) then we try to find an associated FP. 47 We repeat this until we either find a complete frame or run out of 48 stack to look at. </P> */ 49 50 public class AARCH64CurrentFrameGuess { 51 private AARCH64ThreadContext context; 52 private JavaThread thread; 53 private Address spFound; 54 private Address fpFound; 55 private Address pcFound; 56 57 private static final boolean DEBUG = System.getProperty("sun.jvm.hotspot.runtime.aarch64.AARCH64Frame.DEBUG") 58 != null; 59 60 public AARCH64CurrentFrameGuess(AARCH64ThreadContext context, 61 JavaThread thread) { 62 this.context = context; 63 this.thread = thread; 64 } 65 66 /** Returns false if not able to find a frame within a reasonable range. */ 67 public boolean run(long regionInBytesToSearch) { 68 Address sp = context.getRegisterAsAddress(AARCH64ThreadContext.SP); 69 Address pc = context.getRegisterAsAddress(AARCH64ThreadContext.PC); 70 Address fp = context.getRegisterAsAddress(AARCH64ThreadContext.FP); 71 if (sp == null) { 72 // Bail out if no last java frame either 73 if (thread.getLastJavaSP() != null) { 74 setValues(thread.getLastJavaSP(), thread.getLastJavaFP(), null); 75 return true; 76 } 77 return false; 78 } 79 Address end = sp.addOffsetTo(regionInBytesToSearch); 80 VM vm = VM.getVM(); 81 82 setValues(null, null, null); // Assume we're not going to find anything 83 84 if (vm.isJavaPCDbg(pc)) { 85 if (vm.isClientCompiler()) { 86 // If the topmost frame is a Java frame, we are (pretty much) 87 // guaranteed to have a viable FP. We should be more robust 88 // than this (we have the potential for losing entire threads' 89 // stack traces) but need to see how much work we really have 90 // to do here. Searching the stack for an (SP, FP) pair is 91 // hard since it's easy to misinterpret inter-frame stack 92 // pointers as base-of-frame pointers; we also don't know the 93 // sizes of C1 frames (not registered in the nmethod) so can't 94 // derive them from SP. 95 96 setValues(sp, fp, pc); 97 return true; 98 } else { 99 if (vm.getInterpreter().contains(pc)) { 100 if (DEBUG) { 101 System.out.println("CurrentFrameGuess: choosing interpreter frame: sp = " + 102 sp + ", fp = " + fp + ", pc = " + pc); 103 } 104 setValues(sp, fp, pc); 105 return true; 106 } 107 108 // For the server compiler, FP is not guaranteed to be valid 109 // for compiled code. In addition, an earlier attempt at a 110 // non-searching algorithm (see below) failed because the 111 // stack pointer from the thread context was pointing 112 // (considerably) beyond the ostensible end of the stack, into 113 // garbage; walking from the topmost frame back caused a crash. 114 // 115 // This algorithm takes the current PC as a given and tries to 116 // find the correct corresponding SP by walking up the stack 117 // and repeatedly performing stackwalks (very inefficient). 118 // 119 // FIXME: there is something wrong with stackwalking across 120 // adapter frames...this is likely to be the root cause of the 121 // failure with the simpler algorithm below. 122 123 for (long offset = 0; 124 offset < regionInBytesToSearch; 125 offset += vm.getAddressSize()) { 126 try { 127 Address curSP = sp.addOffsetTo(offset); 128 Frame frame = new AARCH64Frame(curSP, null, pc); 129 RegisterMap map = thread.newRegisterMap(false); 130 while (frame != null) { 131 if (frame.isEntryFrame() && frame.entryFrameIsFirst()) { 132 // We were able to traverse all the way to the 133 // bottommost Java frame. 134 // This sp looks good. Keep it. 135 if (DEBUG) { 136 System.out.println("CurrentFrameGuess: Choosing sp = " + curSP + ", pc = " + pc); 137 } 138 setValues(curSP, null, pc); 139 return true; 140 } 141 frame = frame.sender(map); 142 } 143 } catch (Exception e) { 144 if (DEBUG) { 145 System.out.println("CurrentFrameGuess: Exception " + e + " at offset " + offset); 146 } 147 // Bad SP. Try another. 148 } 149 } 150 151 // Were not able to find a plausible SP to go with this PC. 152 // Bail out. 153 return false; 154 155 /* 156 // Original algorithm which does not work because SP was 157 // pointing beyond where it should have: 158 159 // For the server compiler, FP is not guaranteed to be valid 160 // for compiled code. We see whether the PC is in the 161 // interpreter and take care of that, otherwise we run code 162 // (unfortunately) duplicated from AARCH64Frame.senderForCompiledFrame. 163 164 CodeCache cc = vm.getCodeCache(); 165 if (cc.contains(pc)) { 166 CodeBlob cb = cc.findBlob(pc); 167 168 // See if we can derive a frame pointer from SP and PC 169 // NOTE: This is the code duplicated from AARCH64Frame 170 Address saved_fp = null; 171 int llink_offset = cb.getLinkOffset(); 172 if (llink_offset >= 0) { 173 // Restore base-pointer, since next frame might be an interpreter frame. 174 Address fp_addr = sp.addOffsetTo(VM.getVM().getAddressSize() * llink_offset); 175 saved_fp = fp_addr.getAddressAt(0); 176 } 177 178 setValues(sp, saved_fp, pc); 179 return true; 180 } 181 */ 182 } 183 } else { 184 // If the current program counter was not known to us as a Java 185 // PC, we currently assume that we are in the run-time system 186 // and attempt to look to thread-local storage for saved SP and 187 // FP. Note that if these are null (because we were, in fact, 188 // in Java code, i.e., vtable stubs or similar, and the SA 189 // didn't have enough insight into the target VM to understand 190 // that) then we are going to lose the entire stack trace for 191 // the thread, which is sub-optimal. FIXME. 192 193 if (DEBUG) { 194 System.out.println("CurrentFrameGuess: choosing last Java frame: sp = " + 195 thread.getLastJavaSP() + ", fp = " + thread.getLastJavaFP()); 196 } 197 if (thread.getLastJavaSP() == null) { 198 return false; // No known Java frames on stack 199 } 200 201 // The runtime has a nasty habit of not saving fp in the frame 202 // anchor, leaving us to grovel about in the stack to find a 203 // plausible address. Fortunately, this only happens in 204 // compiled code; there we always have a valid PC, and we always 205 // push LR and FP onto the stack as a pair, with FP at the lower 206 // address. 207 pc = thread.getLastJavaPC(); 208 fp = thread.getLastJavaFP(); 209 sp = thread.getLastJavaSP(); 210 211 if (fp == null) { 212 CodeCache cc = vm.getCodeCache(); 213 if (cc.contains(pc)) { 214 CodeBlob cb = cc.findBlob(pc); 215 if (DEBUG) { 216 System.out.println("FP is null. Found blob frame size " + cb.getFrameSize()); 217 } 218 // See if we can derive a frame pointer from SP and PC 219 long link_offset = cb.getFrameSize() - 2 * VM.getVM().getAddressSize(); 220 if (link_offset >= 0) { 221 fp = sp.addOffsetTo(link_offset); 222 } 223 } 224 } 225 226 setValues(sp, fp, null); 227 228 return true; 229 } 230 } 231 232 public Address getSP() { return spFound; } 233 public Address getFP() { return fpFound; } 234 /** May be null if getting values from thread-local storage; take 235 care to call the correct AARCH64Frame constructor to recover this if 236 necessary */ 237 public Address getPC() { return pcFound; } 238 239 private void setValues(Address sp, Address fp, Address pc) { 240 spFound = sp; 241 fpFound = fp; 242 pcFound = pc; 243 } 244 }