1 /* 2 * Copyright (c) 2001, 2018, 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 * @test 26 * @bug 8187143 27 * @summary JDI crash in ~BufferBlob::MethodHandles adapters 28 * 29 * @run build TestScaffold VMConnection TargetListener TargetAdapter 30 * @run compile -g NashornPopFrameTest.java 31 * @run driver NashornPopFrameTest 32 */ 33 import com.sun.jdi.*; 34 import com.sun.jdi.event.*; 35 import com.sun.jdi.request.*; 36 37 import jdk.nashorn.api.scripting.NashornScriptEngineFactory; 38 import javax.script.*; 39 40 import java.io.PrintStream; 41 42 43 // The debuggee, creates and uses a Nashorn engine to evaluate a simple script. 44 45 // The debugger tries to set a breakpoint in Nashorn internal DEBUGGER method. 46 // When the breakpoint is reached, it looks for stack frame whose method's 47 // declaring type name starts with jdk.nashorn.internal.scripts.Script$. 48 // (nashorn dynamically generated classes) 49 // It then pops stack frames using the ThreadReference.popFrames() call, up to 50 // and including the above stackframe. 51 // The execution of the debuggee application is resumed after the needed 52 // frames have been popped. 53 54 class ScriptDebuggee { 55 public final static int BKPT_LINE = 74; 56 static ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine(); 57 static public String failReason = null; 58 doit()59 static void doit() throws Exception { 60 System.out.println("Debugee: started!"); 61 String script = 62 "function f() {\r\n" + 63 " debugger;\r\n" + 64 " debugger;\r\n" + 65 "}\r\n" + 66 "f();"; 67 try { 68 engine.eval(script); 69 } catch (Exception ex) { 70 failReason = "ScriptDebuggee failed: Exception in engine.eval(): " 71 + ex.toString(); 72 ex.printStackTrace(); 73 } 74 System.out.println("Debugee: finished!"); // BKPT_LINE 75 } 76 main(String[] args)77 public static void main(String[] args) throws Exception { 78 doit(); 79 } 80 } 81 82 /********** test program **********/ 83 84 public class NashornPopFrameTest extends TestScaffold { 85 static PrintStream out = System.out; 86 static boolean breakpointReached = false; 87 String debuggeeFailReason = null; 88 ClassType targetClass; 89 ThreadReference mainThread; 90 BreakpointRequest bkptRequest; 91 NashornPopFrameTest(String args[])92 NashornPopFrameTest(String args[]) { 93 super(args); 94 } 95 main(String[] args)96 public static void main(String[] args) throws Exception { 97 NashornPopFrameTest nashornPopFrameTest = new NashornPopFrameTest(args); 98 nashornPopFrameTest.startTests(); 99 } 100 101 /********** test core **********/ 102 runTests()103 protected void runTests() throws Exception { 104 /* 105 * Get to the top of main() to determine targetClass and mainThread 106 */ 107 BreakpointEvent bpe = startToMain("ScriptDebuggee"); 108 targetClass = (ClassType)bpe.location().declaringType(); 109 out.println("Agent: runTests: after startToMain()"); 110 111 mainThread = bpe.thread(); 112 EventRequestManager erm = vm().eventRequestManager(); 113 114 Location loc = findLocation(targetClass, ScriptDebuggee.BKPT_LINE); 115 116 try { 117 addListener(this); 118 } catch (Exception ex){ 119 ex.printStackTrace(); 120 failure("Failed: Could not add listener"); 121 throw new Exception("NashornPopFrameTest: failed with Exception in AddListener"); 122 } 123 124 pauseAtDebugger(vm()); 125 bkptRequest = erm.createBreakpointRequest(loc); 126 bkptRequest.enable(); 127 128 vm().resume(); 129 130 try { 131 listen(vm()); 132 } catch (Exception exp) { 133 exp.printStackTrace(); 134 failure("Failed: Caught Exception while Listening"); 135 throw new Exception("NashornPopFrameTest: failed with Exception in listen()"); 136 } 137 138 // Debugger continues to run until it receives a VMdisconnect event either because 139 // the Debuggee crashed / got exception / finished successfully. 140 while (!vmDisconnected) { 141 try { 142 Thread.sleep(100); 143 } catch (InterruptedException ee) { 144 } 145 } 146 147 removeListener(this); 148 149 if (breakpointReached) { 150 if (debuggeeFailReason != null) { 151 failure(debuggeeFailReason); 152 } 153 } else { 154 failure("Expected breakpoint in ScriptDebuggee:" + 155 ScriptDebuggee.BKPT_LINE + " was not reached"); 156 } 157 if (testFailed) { 158 throw new Exception("NashornPopFrameTest: failed"); 159 } 160 out.println("NashornPopFrameTest: passed"); 161 } 162 pauseAtDebugger(VirtualMachine vm)163 private static void pauseAtDebugger(VirtualMachine vm) throws AbsentInformationException { 164 for (ReferenceType t : vm.allClasses()) pauseAtDebugger(t); 165 } 166 167 // Set a breakpoint in Nashorn internal DEBUGGER method. pauseAtDebugger(ReferenceType t)168 private static void pauseAtDebugger(ReferenceType t) throws AbsentInformationException { 169 if (!t.name().endsWith(".ScriptRuntime")) { 170 return; 171 } 172 for (Location l : t.allLineLocations()) { 173 if (!l.method().name().equals("DEBUGGER")) continue; 174 BreakpointRequest bkptReq = t.virtualMachine().eventRequestManager().createBreakpointRequest(l); 175 out.println("Setting breakpoint for " + l); 176 bkptReq.enable(); 177 break; 178 } 179 } 180 listen(VirtualMachine vm)181 private static void listen(VirtualMachine vm) throws Exception { 182 EventQueue eventQueue = vm.eventQueue(); 183 EventSet es = eventQueue.remove(); 184 if (es != null) { 185 handle(es); 186 } 187 } 188 189 // Handle event when breakpoint is reached handle(EventSet eventSet)190 private static void handle(EventSet eventSet) throws Exception { 191 out.println("Agent handle(): started"); 192 for (Event event : eventSet) { 193 if (event instanceof BreakpointEvent) { 194 findFrameAndPop(event); 195 } 196 } 197 eventSet.resume(); 198 out.println("Agent handle(): finished"); 199 } 200 findFrameAndPop(Event event)201 private static void findFrameAndPop(Event event) throws Exception { 202 ThreadReference thread = ((BreakpointEvent) event).thread(); 203 out.println("Agent: handling Breakpoint " + " at " + 204 ((BreakpointEvent) event).location() + 205 " in thread: " + thread); 206 StackFrame sf = findScriptFrame(thread); 207 if (sf != null) { 208 out.println("Thread Pop Frame on StackFrame = " + sf); 209 thread.popFrames(sf); 210 } 211 } 212 213 // Find stack frame whose method's declaring type name starts with 214 // jdk.nashorn.internal.scripts.Script$ and return that frame findScriptFrame(ThreadReference t)215 private static StackFrame findScriptFrame(ThreadReference t) throws IncompatibleThreadStateException { 216 for (int i = 0; i < t.frameCount(); i++) { 217 StackFrame sf = t.frame(i); 218 String typeName = sf.location().method().declaringType().name(); 219 if (typeName.startsWith("jdk.nashorn.internal.scripts.Script$")) { 220 out.println("Agent: in findScriptFrame: TypeName = " + typeName); 221 return sf; 222 } 223 } 224 throw new RuntimeException("no script frame"); 225 } 226 227 static int bkptCount = 0; 228 229 /********** event handlers **********/ 230 breakpointReached(BreakpointEvent event)231 public void breakpointReached(BreakpointEvent event) { 232 ThreadReference thread = ((BreakpointEvent) event).thread(); 233 String locStr = "" + ((BreakpointEvent) event).location(); 234 out.println("Agent: BreakpointEvent #" + (bkptCount++) + 235 " at " + locStr + " in thread: " + thread); 236 if (locStr.equals("ScriptDebuggee:" + ScriptDebuggee.BKPT_LINE)) { 237 breakpointReached = true; 238 Field failReasonField = targetClass.fieldByName("failReason"); 239 Value failReasonVal = targetClass.getValue(failReasonField); 240 if (failReasonVal != null) { 241 debuggeeFailReason = ((StringReference)failReasonVal).value(); 242 } 243 bkptRequest.disable(); 244 } 245 } 246 eventSetComplete(EventSet set)247 public void eventSetComplete(EventSet set) { 248 set.resume(); 249 } 250 vmDisconnected(VMDisconnectEvent event)251 public void vmDisconnected(VMDisconnectEvent event) { 252 println("Agent: Got VMDisconnectEvent"); 253 } 254 255 } 256