< prev index next >

src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64CurrentFrameGuess.java

Print this page

        

*** 1,7 **** /* ! * 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. --- 1,7 ---- /* ! * Copyright (c) 2003, 2020, 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.
*** 26,37 **** --- 26,40 ---- import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.debugger.amd64.*; import sun.jvm.hotspot.code.*; import sun.jvm.hotspot.interpreter.*; + import sun.jvm.hotspot.oops.*; import sun.jvm.hotspot.runtime.*; import sun.jvm.hotspot.runtime.x86.*; + import sun.jvm.hotspot.types.*; + import sun.jvm.hotspot.utilities.*; /** <P> Should be able to be used on all amd64 platforms we support (Linux/amd64) to implement JavaThread's "currentFrameGuess()" functionality. Input is an AMD64ThreadContext; output is SP, FP, and PC for an AMD64Frame. Instantiation of the
*** 60,88 **** JavaThread thread) { this.context = context; this.thread = thread; } /** Returns false if not able to find a frame within a reasonable range. */ public boolean run(long regionInBytesToSearch) { Address sp = context.getRegisterAsAddress(AMD64ThreadContext.RSP); Address pc = context.getRegisterAsAddress(AMD64ThreadContext.RIP); Address fp = context.getRegisterAsAddress(AMD64ThreadContext.RBP); if (sp == null) { ! // Bail out if no last java frame either ! if (thread.getLastJavaSP() != null) { ! setValues(thread.getLastJavaSP(), thread.getLastJavaFP(), null); ! return true; ! } ! return false; } Address end = sp.addOffsetTo(regionInBytesToSearch); VM vm = VM.getVM(); setValues(null, null, null); // Assume we're not going to find anything ! if (vm.isJavaPCDbg(pc)) { if (vm.isClientCompiler()) { // If the topmost frame is a Java frame, we are (pretty much) // guaranteed to have a viable EBP. We should be more robust // than this (we have the potential for losing entire threads' // stack traces) but need to see how much work we really have --- 63,201 ---- JavaThread thread) { this.context = context; this.thread = thread; } + private boolean validateInterpreterFrame(Address sp, Address fp, Address pc) { + VM vm = VM.getVM(); + X86Frame f = new X86Frame(sp, fp, pc); + + // First validate that frame->method is really a Method* + Method method = null; + try { + method = f.getInterpreterFrameMethod(); + } catch (WrongTypeException | AddressException | NullPointerException e) { + // This just means frame->method is not valid. + if (DEBUG) { + System.out.println("CurrentFrameGuess: frame->method is invalid"); + } + } + + // Next make sure frame->bcp is really in the method's bytecodes + if (method != null && f.getInterpreterFrameBCP() != null) { + if (method.getConstMethod().isAddressInMethod(f.getInterpreterFrameBCP())) { + // All's good. This is the normal path when the PC is in the interpreter. + // The cases below are all exceptionally rare. + setValues(sp, fp, pc); + return true; + } else { + if (DEBUG) { + System.out.println("CurrentFrameGuess: frame->bcp is invalid"); + } + } + } + + // Either frame->method is not a Method* or frame->bcp is not valid. That means either + // we have pushed the new interpreter frame, but have not intialized it yet, or + // we have yet to push the new interpreter frame, and the "current" frame is not an + // interpreter frame. Figure out which is the case. + + // Try to find the return address in RAX or on the stack. If we can't + // find what appears to be a valid codecache address in either of these + // two locations, then we canot determine the frame. + Address returnAddress = context.getRegisterAsAddress(AMD64ThreadContext.RAX); + CodeCache c = VM.getVM().getCodeCache(); + if (returnAddress == null || !c.contains(returnAddress)) { + returnAddress = sp.getAddressAt(0); // check top of stack + if (returnAddress == null || !c.contains(returnAddress)) { + if (DEBUG) { + System.out.println("CurrentFrameGuess: Cannot find valid returnAddress"); + } + setValues(sp, fp, pc); + return false; // couldn't find a valid PC for frame. + } else { + if (DEBUG) { + System.out.println("CurrentFrameGuess: returnAddress found on stack: " + returnAddress); + } + } + } else { + if (DEBUG) { + System.out.println("CurrentFrameGuess: returnAddress found in RAX: " + returnAddress); + } + } + + // See what return address is stored in the frame. Most likely it is not valid, but + // it's validity will help us determine the state of the new frame push. + Address returnAddress2 = null; + try { + returnAddress2 = f.getSenderPC(); + } catch (AddressException e) { + // Just ignore. This is expected sometimes. + if (DEBUG) { + System.out.println("CurrentFrameGuess: senderPC is invalid"); + } + } + if (DEBUG) { + System.out.println("CurrentFrameGuess: returnAddress2: " + returnAddress2); + } + + if (returnAddress.equals(returnAddress2)) { + // If these two ways of fetching the return address produce the same address, + // then that means we have pushed the new frame, but have not finished + // initializing it yet. Otherwise we would also have found a valid frame->method + // and frame->bcp. Because this frame is incomplete, we instead use + // the previous frame as the current frame. + if (DEBUG) { + System.out.println("CurrentFrameGuess: frame pushed but not initaliazed."); + } + sp = f.getSenderSP(); + fp = f.getLink(); + setValues(sp, fp, returnAddress); + // If this previous frame is interpreted, then we are done and setValues() has been + // called with a valid interpreter frame. Otherwise return false and the caller will + // need to determine frame. + if (vm.getInterpreter().contains(returnAddress)) { + if (DEBUG) { + System.out.println("CurrentFrameGuess: Interpreted: using previous frame."); + } + return true; + } else { + if (DEBUG) { + System.out.println("CurrentFrameGuess: Not Interpreted: using previous frame."); + } + return false; + } + } else { + // We haven't even pushed the new frame yet. sp and fp are for the previous + // frame that is making the call to the interpreter. Since this frame is + // not a valid interpreter frame (we know either frame->method or frame->bcp + // are not valid), it must be something else. Assume compiled or native and + // let the caller figure it out. + setValues(sp, fp, returnAddress); + if (DEBUG) { + System.out.println("CurrentFrameGuess: Frame not yet pushed. Previous frame not interpreted."); + } + return false; + } + } + /** Returns false if not able to find a frame within a reasonable range. */ public boolean run(long regionInBytesToSearch) { Address sp = context.getRegisterAsAddress(AMD64ThreadContext.RSP); Address pc = context.getRegisterAsAddress(AMD64ThreadContext.RIP); Address fp = context.getRegisterAsAddress(AMD64ThreadContext.RBP); if (sp == null) { ! return checkLastJavaSP(); } Address end = sp.addOffsetTo(regionInBytesToSearch); VM vm = VM.getVM(); setValues(null, null, null); // Assume we're not going to find anything ! if (!vm.isJavaPCDbg(pc)) { ! return checkLastJavaSP(); ! } else { if (vm.isClientCompiler()) { // If the topmost frame is a Java frame, we are (pretty much) // guaranteed to have a viable EBP. We should be more robust // than this (we have the potential for losing entire threads' // stack traces) but need to see how much work we really have
*** 94,109 **** setValues(sp, fp, pc); return true; } else { if (vm.getInterpreter().contains(pc)) { if (DEBUG) { System.out.println("CurrentFrameGuess: choosing interpreter frame: sp = " + ! sp + ", fp = " + fp + ", pc = " + pc); } - setValues(sp, fp, pc); - return true; } // For the server compiler, EBP is not guaranteed to be valid // for compiled code. In addition, an earlier attempt at a // non-searching algorithm (see below) failed because the --- 207,245 ---- setValues(sp, fp, pc); return true; } else { if (vm.getInterpreter().contains(pc)) { + // pc points into the interpreter, but that doesn't necessarily mean the current + // frame is interpreted. We may be in interpreter method entry code before the frame + // has been pushed, or possibly after it has been pushed but before it has been + // initialized. See TemplateInterpreterGenerator::generate_normal_entry(). So we + // need to do a few sanity checks here, and try to correct the situation if + // we are in the middle of a frame push. + if (validateInterpreterFrame(sp, fp, pc)) { if (DEBUG) { System.out.println("CurrentFrameGuess: choosing interpreter frame: sp = " + ! spFound + ", fpFound = " + fp + ", pcFound = " + pc); ! } ! return true; // We're done. setValues() has been called for valid interpreter frame. ! } else { ! // This does not appear to be a valid interpreter frame. Possibly we are in the ! // middle of pushing a new frame. Update the frame values to those suggested ! // by validateInterpreterFrame() and then fall through to check if it is compiled. ! sp = spFound; ! fp = fpFound; ! pc = pcFound; ! setValues(null, null, null); ! if (pcFound == null) { ! return false; ! } ! // pc may have changed, so we need to redo the isJavaPCDbg(pc) check before ! // falling into code below that assumes the frame is compiled. ! if (!vm.isJavaPCDbg(pc)) { ! return checkLastJavaSP(); ! } } } // For the server compiler, EBP is not guaranteed to be valid // for compiled code. In addition, an earlier attempt at a // non-searching algorithm (see below) failed because the
*** 117,126 **** --- 253,265 ---- // // FIXME: there is something wrong with stackwalking across // adapter frames...this is likely to be the root cause of the // failure with the simpler algorithm below. + if (DEBUG) { + System.out.println("CurrentFrameGuess: sp = " + sp + ", pc = " + pc); + } for (long offset = 0; offset < regionInBytesToSearch; offset += vm.getAddressSize()) { try { Address curSP = sp.addOffsetTo(offset);
*** 141,151 **** frame = frame.sender(map); if (frame.getSP().lessThanOrEqual(oldFrame.getSP())) { // Frame points to itself or to a location in the wrong direction. // Break the loop and move on to next offset. if (DEBUG) { ! System.out.println("AMD64CurrentFrameGuess.run: frame <= oldFrame: " + frame); } break; } } } catch (Exception e) { --- 280,290 ---- frame = frame.sender(map); if (frame.getSP().lessThanOrEqual(oldFrame.getSP())) { // Frame points to itself or to a location in the wrong direction. // Break the loop and move on to next offset. if (DEBUG) { ! System.out.println("CurrentFrameGuess: frame <= oldFrame: " + frame); } break; } } } catch (Exception e) {
*** 186,196 **** setValues(sp, saved_fp, pc); return true; } */ } ! } else { // If the current program counter was not known to us as a Java // PC, we currently assume that we are in the run-time system // and attempt to look to thread-local storage for saved ESP and // EBP. Note that if these are null (because we were, in fact, // in Java code, i.e., vtable stubs or similar, and the SA --- 325,338 ---- setValues(sp, saved_fp, pc); return true; } */ } ! } ! } ! ! private boolean checkLastJavaSP() { // If the current program counter was not known to us as a Java // PC, we currently assume that we are in the run-time system // and attempt to look to thread-local storage for saved ESP and // EBP. Note that if these are null (because we were, in fact, // in Java code, i.e., vtable stubs or similar, and the SA
*** 206,216 **** return false; // No known Java frames on stack } setValues(thread.getLastJavaSP(), thread.getLastJavaFP(), null); return true; } - } public Address getSP() { return spFound; } public Address getFP() { return fpFound; } /** May be null if getting values from thread-local storage; take care to call the correct AMD64Frame constructor to recover this if --- 348,357 ----
< prev index next >