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