1 /* 2 * Copyright (c) 2008, 2015, 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 6700889 27 * @summary Thread resume invalidates all stack frames, even from other threads 28 * 29 * @author jjh 30 * 31 * @modules jdk.jdi 32 * @run build TestScaffold VMConnection TargetListener TargetAdapter 33 * @run compile -g ResumeOneThreadTest.java 34 * @run driver ResumeOneThreadTest 35 */ 36 import com.sun.jdi.*; 37 import com.sun.jdi.event.*; 38 import com.sun.jdi.request.*; 39 40 import java.util.*; 41 42 class ResumeOneThreadTarg extends Thread { 43 static String name1 = "Thread 1"; 44 static String name2 = "Thread 2"; 45 46 public ResumeOneThreadTarg(String name) { 47 super(name); 48 } 49 50 public static void main(String[] args) { 51 System.out.println(" Debuggee: Howdy!"); 52 ResumeOneThreadTarg t1 = new ResumeOneThreadTarg(name1); 53 ResumeOneThreadTarg t2 = new ResumeOneThreadTarg(name2); 54 55 t1.start(); 56 t2.start(); 57 } 58 59 // This just starts two threads. Each runs to a bkpt. 60 public void run() { 61 if (getName().equals(name1)) { 62 run1(); 63 } else { 64 run2(); 65 } 66 } 67 68 public void bkpt1(String p1) { 69 System.out.println(" Debuggee: bkpt 1"); 70 } 71 72 public void run1() { 73 bkpt1("Hello Alviso!"); 74 } 75 76 77 78 public void bkpt2() { 79 System.out.println(" Debuggee: bkpt 2"); 80 } 81 82 public void run2() { 83 bkpt2(); 84 } 85 } 86 87 /********** test program **********/ 88 89 public class ResumeOneThreadTest extends TestScaffold { 90 ReferenceType targetClass; 91 ThreadReference mainThread; 92 93 BreakpointRequest request1; 94 BreakpointRequest request2; 95 96 ThreadReference thread1 = null; 97 ThreadReference thread2 = null;; 98 boolean theVMisDead = false; 99 100 ResumeOneThreadTest (String args[]) { 101 super(args); 102 } 103 104 public static void main(String[] args) throws Exception { 105 new ResumeOneThreadTest(args).startTests(); 106 } 107 108 109 synchronized public void breakpointReached(BreakpointEvent event) { 110 println("-- Got bkpt at: " + event.location()); 111 ThreadReference eventThread = event.thread(); 112 113 if (eventThread.name().equals(ResumeOneThreadTarg.name1)) { 114 thread1 = eventThread; 115 } 116 117 if (eventThread.name().equals(ResumeOneThreadTarg.name2)) { 118 thread2 = eventThread; 119 } 120 } 121 122 public void vmDied(VMDeathEvent event) { 123 theVMisDead = true; 124 } 125 126 synchronized public void eventSetComplete(EventSet set) { 127 if (theVMisDead) { 128 return; 129 } 130 if (thread1 == null || thread2 == null) { 131 // Don't do a set.resume(), just let the other thread 132 // keep running until it hits its bkpt. 133 return; 134 } 135 136 // Both threads are stopped at their bkpts. Get a StackFrame from 137 // Thread 1 then resume Thread 2 and verify that the saved StackFrame is 138 // still valid. 139 140 // suspend everything. 141 println("-- All threads suspended"); 142 vm().suspend(); 143 144 StackFrame t1sf0 = null; 145 try { 146 t1sf0 = thread1.frame(0); 147 } catch (IncompatibleThreadStateException ee) { 148 failure("FAILED: Exception: " + ee); 149 } 150 151 println("-- t1sf0 args: " + t1sf0.getArgumentValues()); 152 153 // Ok, we have a StackFrame for thread 1. Resume just thread 2 154 // Note that thread 2 has been suspended twice - by the SUSPEND_ALL 155 // bkpt, and by the above vm().suspend(), so we have to resume 156 // it twice. 157 request2.disable(); 158 159 thread2.resume(); 160 thread2.resume(); 161 println("-- Did Resume on thread 2"); 162 163 // Can we get frames for thread1? 164 try { 165 StackFrame t1sf0_1 = thread1.frame(0); 166 if (!t1sf0.equals(t1sf0_1)) { 167 failure("FAILED: Got a different frame 0 for thread 1 after resuming thread 2"); 168 } 169 } catch (IncompatibleThreadStateException ee) { 170 failure("FAILED: Could not get frames for thread 1: Exception: " + ee); 171 } catch (Exception ee) { 172 failure("FAILED: Could not get frames for thread 1: Exception: " + ee); 173 } 174 175 176 try { 177 println("-- t1sf0 args: " + t1sf0.getArgumentValues()); 178 } catch (InvalidStackFrameException ee) { 179 // This is the failure. 180 failure("FAILED Got InvalidStackFrameException"); 181 vm().dispose(); 182 throw(ee); 183 } 184 185 // Let the debuggee finish 186 request1.disable(); 187 thread1.resume(); 188 vm().resume(); 189 println("--------------"); 190 } 191 192 /********** test core **********/ 193 194 protected void runTests() throws Exception { 195 196 /* 197 * Get to the top of main() 198 * to determine targetClass and mainThread 199 */ 200 BreakpointEvent bpe = startToMain("ResumeOneThreadTarg"); 201 targetClass = bpe.location().declaringType(); 202 mainThread = bpe.thread(); 203 EventRequestManager erm = vm().eventRequestManager(); 204 final Thread mainThread = Thread.currentThread(); 205 206 /* 207 * Set event requests 208 */ 209 210 Location loc1 = findMethod(targetClass, "bkpt1", "(Ljava/lang/String;)V").location(); 211 request1 = erm.createBreakpointRequest(loc1); 212 request1.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); 213 request1.enable(); 214 215 Location loc2 = findMethod(targetClass, "bkpt2", "()V").location(); 216 request2 = erm.createBreakpointRequest(loc2); 217 request2.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); 218 request2.enable(); 219 220 /* 221 * resume the target, listening for events 222 */ 223 listenUntilVMDisconnect(); 224 /* 225 * deal with results of test 226 * if anything has called failure("foo") testFailed will be true 227 */ 228 if (!testFailed) { 229 println("ResumeOneThreadTest: passed"); 230 } else { 231 throw new Exception("ResumeOneThreadTest: failed"); 232 } 233 } 234 }