8241807: JDWP needs update for hidden classes
Introduce test coverage for hidden class events Reviewed-by: lmesnik, amenkov
This commit is contained in:
parent
7f49c9167a
commit
0783dd69a5
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package nsk.jdi.HiddenClass.events;
|
||||
|
||||
import nsk.share.Log;
|
||||
import nsk.jdi.HiddenClass.events.DebuggerBase;
|
||||
import nsk.share.jdi.ArgumentHandler;
|
||||
import nsk.share.jpda.IOPipe;
|
||||
|
||||
/* Debuggee base class. */
|
||||
class DebuggeeBase {
|
||||
private final IOPipe pipe;
|
||||
private final Log log;
|
||||
|
||||
protected void logMsg(String msg) { log.display(msg); }
|
||||
|
||||
protected DebuggeeBase(ArgumentHandler argHandler) {
|
||||
pipe = argHandler.createDebugeeIOPipe();
|
||||
log = argHandler.createDebugeeLog();
|
||||
}
|
||||
|
||||
protected void syncWithDebugger() {
|
||||
// Notify debugger that debuggee is ready.
|
||||
logMsg("Debuggee: Sending command: " + DebuggerBase.COMMAND_READY);
|
||||
pipe.println(DebuggerBase.COMMAND_READY);
|
||||
|
||||
// Wait for COMMAND_RUN from debugger to continue execution.
|
||||
logMsg("Debuggee: Waiting for command: " + DebuggerBase.COMMAND_RUN);
|
||||
String command = pipe.readln();
|
||||
if (command == null || !command.equals(DebuggerBase.COMMAND_RUN)) {
|
||||
logMsg("FAIL: Debugee: unknown command: " + command);
|
||||
throw new RuntimeException("Failed in sync with debugger. ");
|
||||
}
|
||||
}
|
||||
|
||||
protected void quitSyncWithDebugger() {
|
||||
// Notify debugger about debuggee completed status.
|
||||
logMsg("Debuggee: Sending command: " + DebuggerBase.COMMAND_DONE);
|
||||
pipe.println(DebuggerBase.COMMAND_DONE);
|
||||
|
||||
// Wait for command QUIT from debugger to release started threads and exit.
|
||||
logMsg("Debuggee: Waiting for command: " + DebuggerBase.COMMAND_QUIT);
|
||||
String command = pipe.readln();
|
||||
if (command == null || !command.equals(DebuggerBase.COMMAND_QUIT)) {
|
||||
logMsg("FAIL: Debugee: unknown command: " + command);
|
||||
throw new RuntimeException("Failed in sync with debugger. ");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,260 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package nsk.jdi.HiddenClass.events;
|
||||
|
||||
import com.sun.jdi.ClassType;
|
||||
import com.sun.jdi.ClassObjectReference;
|
||||
import com.sun.jdi.Field;
|
||||
import com.sun.jdi.Method;
|
||||
import com.sun.jdi.ReferenceType;
|
||||
import com.sun.jdi.ThreadReference;
|
||||
import com.sun.jdi.Value;
|
||||
import com.sun.jdi.VirtualMachine;
|
||||
|
||||
import com.sun.jdi.event.EventSet;
|
||||
import com.sun.jdi.request.EventRequest;
|
||||
import com.sun.jdi.request.EventRequestManager;
|
||||
import com.sun.jdi.request.BreakpointRequest;
|
||||
import com.sun.jdi.request.ClassPrepareRequest;
|
||||
import com.sun.jdi.request.ClassUnloadRequest;
|
||||
import com.sun.jdi.request.ModificationWatchpointRequest;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import jdk.test.lib.Asserts;
|
||||
|
||||
import nsk.share.Log;
|
||||
import nsk.share.jdi.ArgumentHandler;
|
||||
import nsk.share.jdi.Binder;
|
||||
import nsk.share.jdi.Debugee;
|
||||
import nsk.share.jpda.IOPipe;
|
||||
|
||||
// This class is the test debugger base class
|
||||
public class DebuggerBase {
|
||||
public static final int PASSED = 0;
|
||||
public static final int FAILED = 2;
|
||||
public static final int JCK_STATUS_BASE = 95;
|
||||
|
||||
public static final String COMMAND_READY = "ready";
|
||||
public static final String COMMAND_RUN = "run";
|
||||
public static final String COMMAND_DONE = "done";
|
||||
public static final String COMMAND_ERROR = "error";
|
||||
public static final String COMMAND_QUIT = "quit";
|
||||
|
||||
public final Log log;
|
||||
|
||||
private VirtualMachine vm;
|
||||
private Debugee debuggee = null;
|
||||
private IOPipe pipe = null;
|
||||
private EventRequestManager erManager = null;
|
||||
|
||||
protected DebuggerBase(ArgumentHandler argHandler) {
|
||||
log = new Log(System.out, argHandler);
|
||||
}
|
||||
|
||||
VirtualMachine vm() {
|
||||
return vm;
|
||||
}
|
||||
|
||||
// Find a ReferenceType by a given type name.
|
||||
ReferenceType getReferenceType(String typeName) {
|
||||
List<ReferenceType> list = vm.classesByName(typeName);
|
||||
|
||||
Asserts.assertFalse(list.size() == 0, "FAIL: type not found: " + typeName);
|
||||
Asserts.assertFalse(list.size() > 1, "FAIL: multiple types found: " + typeName);
|
||||
log.display(" Found type: " + typeName);
|
||||
return list.get(0);
|
||||
}
|
||||
|
||||
// Find a Field by a given ReferenceType and a field name.
|
||||
Field findField(ReferenceType refType, String fieldName) {
|
||||
Field field = refType.fieldByName(fieldName);
|
||||
String fullName = refType.name() + "::" + fieldName;
|
||||
|
||||
Asserts.assertNotNull(field, "FAIL: field not found: " + fullName);
|
||||
log.display(" Found field: " + fullName);
|
||||
return field;
|
||||
}
|
||||
|
||||
// Find a Method by a given ReferenceType and a method name.
|
||||
Method findMethod(ReferenceType refType, String methodName) {
|
||||
List<Method> list = refType.methodsByName(methodName);
|
||||
String fullName = refType.name() + "::" + methodName;
|
||||
|
||||
Asserts.assertFalse(list.size() == 0, "FAIL: method not found: " + fullName);
|
||||
Asserts.assertFalse(list.size() > 1, "FAIL: multiple methods found: " + fullName);
|
||||
|
||||
log.display(" Found method: " + fullName);
|
||||
return list.get(0);
|
||||
}
|
||||
|
||||
// Invoke a given static method in debuggee VM at an eventpoint.
|
||||
boolean invokeStaticMethod(ThreadReference thread, Method methodToInvoke) {
|
||||
boolean failedStatus = false;
|
||||
List<? extends Value> args = new ArrayList<>();
|
||||
int flags = (ClassObjectReference.INVOKE_NONVIRTUAL |
|
||||
ClassObjectReference.INVOKE_SINGLE_THREADED);
|
||||
try {
|
||||
log.display(" invoking method: " + methodToInvoke);
|
||||
ClassType type = (ClassType)methodToInvoke.declaringType();
|
||||
Value val = type.invokeMethod(thread, methodToInvoke, args, flags);
|
||||
log.display(" method getHCField returned result: " + val);
|
||||
} catch (Exception ex) {
|
||||
log.complain("Exception in HC::getHCField method invocation: " + ex);
|
||||
failedStatus = true;
|
||||
}
|
||||
return failedStatus;
|
||||
}
|
||||
|
||||
protected void launchDebuggee(ArgumentHandler argHandler, String debuggeeName) {
|
||||
Binder binder = new Binder(argHandler, log);
|
||||
log.display("\n# Connecting to debuggee");
|
||||
|
||||
debuggee = binder.bindToDebugee(debuggeeName);
|
||||
debuggee.redirectStderr(log, "debuggee >");
|
||||
|
||||
pipe = debuggee.createIOPipe();
|
||||
vm = debuggee.VM();
|
||||
erManager = vm.eventRequestManager();
|
||||
|
||||
log.display("# Resuming debuggee");
|
||||
debuggee.resume();
|
||||
}
|
||||
|
||||
protected boolean shutdownDebuggee() {
|
||||
boolean debuggeeFailed = false;
|
||||
log.display("\n# Shutting down debuggee");
|
||||
|
||||
// wait for debuggee exits and analize its exit code
|
||||
log.display("# Waiting for debuggee terminating");
|
||||
int debuggeeStatus = debuggee.endDebugee();
|
||||
if (debuggeeStatus == PASSED + JCK_STATUS_BASE) {
|
||||
log.display("# Debuggee PASSED with exit code: " + debuggeeStatus);
|
||||
} else {
|
||||
log.complain("# Debuggee FAILED with exit code: " + debuggeeStatus);
|
||||
debuggeeFailed = true;
|
||||
}
|
||||
return debuggeeFailed;
|
||||
}
|
||||
|
||||
protected EventRequest enableBreakpointRequest(Method method) {
|
||||
log.display("\n# Creating BreakpointRequest");
|
||||
BreakpointRequest request = erManager.createBreakpointRequest(method.location());
|
||||
Asserts.assertNotNull(request, "FAIL: unable to create BreakpointRequest");
|
||||
|
||||
// enable event request
|
||||
request.enable();
|
||||
log.display(" Enabled BreakpointRequest");
|
||||
return request;
|
||||
}
|
||||
|
||||
protected EventRequest enableClassPrepareRequest(String classFilter) {
|
||||
log.display("\n# Creating ClassPrepareRequest");
|
||||
ClassPrepareRequest request = erManager.createClassPrepareRequest();
|
||||
Asserts.assertNotNull(request, "FAIL: unable to create ClassPrepareRequest");
|
||||
|
||||
if (classFilter != null) {
|
||||
log.display(" Adding filter to ClassPrepareRequest: " + classFilter);
|
||||
request.addClassFilter(classFilter);
|
||||
}
|
||||
// enable event request
|
||||
request.enable();
|
||||
log.display(" Enabled ClassPrepareRequest");
|
||||
return request;
|
||||
}
|
||||
|
||||
protected EventRequest enableClassUnloadRequest(String classFilter) {
|
||||
log.display("\n# Creating request for ClassUnloadEvent");
|
||||
ClassUnloadRequest request = erManager.createClassUnloadRequest();
|
||||
Asserts.assertNotNull(request, "FAIL: unable to create ClassUnloadRequest");
|
||||
|
||||
if (classFilter != null) {
|
||||
log.display(" Adding filter to ClassUnloadRequest: " + classFilter);
|
||||
request.addClassFilter(classFilter);
|
||||
}
|
||||
// enable event request
|
||||
request.enable();
|
||||
log.display(" Enabled ClassUnloadRequest");
|
||||
return request;
|
||||
}
|
||||
|
||||
protected EventRequest enableModificationWatchpointRequest(Field field, String classFilter) {
|
||||
log.display("\n# Creating request for ModificationWatchpointRequest");
|
||||
|
||||
ModificationWatchpointRequest request = erManager.createModificationWatchpointRequest(field);
|
||||
Asserts.assertNotNull(request, "FAIL: unable to create ModificationWatchpointRequest");
|
||||
|
||||
if (classFilter != null) {
|
||||
log.display(" Adding filter to ModificationWatchpointRequest: " + classFilter);
|
||||
request.addClassFilter(classFilter);
|
||||
}
|
||||
// enable event request
|
||||
request.enable();
|
||||
log.display(" Enabled ModificationWatchpointRequest");
|
||||
return request;
|
||||
}
|
||||
|
||||
protected void disableRequest(EventRequest eq, String reqestName) {
|
||||
// disable event requests to prevent appearance of further events
|
||||
if (eq != null && eq.isEnabled()) {
|
||||
log.display(" Disabling " + reqestName);
|
||||
eq.disable();
|
||||
}
|
||||
}
|
||||
|
||||
// sync on the COMMAND_READY
|
||||
protected void readyCmdSync() {
|
||||
// wait for READY signal from debugee
|
||||
log.display("\n# Waiting for command: " + COMMAND_READY);
|
||||
String command = pipe.readln();
|
||||
Asserts.assertFalse(command == null || !command.equals(COMMAND_READY),
|
||||
"FAIL: unexpected debuggee's command: " + command);
|
||||
log.display("\n# Got command: " + COMMAND_READY);
|
||||
}
|
||||
|
||||
// sync on the COMMAND_RUN
|
||||
protected void runCmdSync() {
|
||||
// activate debugee
|
||||
log.display("\n# Sending command: " + COMMAND_RUN);
|
||||
pipe.println(COMMAND_RUN);
|
||||
}
|
||||
|
||||
// sync on the COMMAND_DONE
|
||||
protected void doneCmdSync() {
|
||||
// wait for DONE signal from debugee
|
||||
log.display("\n# Waiting for command: " + COMMAND_DONE);
|
||||
String command = pipe.readln();
|
||||
Asserts.assertFalse(command == null || !command.equals(COMMAND_DONE),
|
||||
"FAIL: unexpected debuggee's command: " + command);
|
||||
log.display("\n# Got command: " + COMMAND_DONE);
|
||||
}
|
||||
|
||||
// sync on the COMMAND_QUIT
|
||||
protected void quitCmdSync() {
|
||||
// force debugee to exit
|
||||
log.display("\n# Sending command: " + COMMAND_QUIT);
|
||||
pipe.println(COMMAND_QUIT);
|
||||
}
|
||||
}
|
@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package nsk.jdi.HiddenClass.events;
|
||||
|
||||
import com.sun.jdi.ClassType;
|
||||
import com.sun.jdi.Field;
|
||||
import com.sun.jdi.Method;
|
||||
import com.sun.jdi.ReferenceType;
|
||||
import com.sun.jdi.ThreadReference;
|
||||
|
||||
import com.sun.jdi.event.Event;
|
||||
import com.sun.jdi.event.EventIterator;
|
||||
import com.sun.jdi.event.EventSet;
|
||||
import com.sun.jdi.event.BreakpointEvent;
|
||||
import com.sun.jdi.event.ClassPrepareEvent;
|
||||
import com.sun.jdi.event.ClassUnloadEvent;
|
||||
import com.sun.jdi.event.ModificationWatchpointEvent;
|
||||
import com.sun.jdi.request.EventRequest;
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
import nsk.jdi.HiddenClass.events.DebuggerBase;
|
||||
|
||||
import nsk.share.Log;
|
||||
|
||||
/* This is a special thread to handle hidden class related events.
|
||||
* The thread is looping on accepting events until all the expected
|
||||
* event types are received. */
|
||||
public class EventHandler extends Thread {
|
||||
private static final int TIMEOUT_DELTA = 1000; // milliseconds
|
||||
private final DebuggerBase debuggerBase;
|
||||
private final Log log;
|
||||
|
||||
private volatile boolean testFailed = false;
|
||||
private boolean breakpointEventRecieived = false;
|
||||
private boolean classPrepareEventRecieived = false;
|
||||
private boolean classUnloadEventRecieived = false;
|
||||
private boolean modificationWatchpointEventRecieived = false;
|
||||
|
||||
// Hidden class ReferenceType which is saved for debugger.
|
||||
private ReferenceType hcRefType = null;
|
||||
|
||||
// This method is called by the debugger main thread.
|
||||
static EventHandler createAndStart(DebuggerBase debuggerBase) {
|
||||
// start EventHandler thread
|
||||
EventHandler handler = new EventHandler(debuggerBase);
|
||||
handler.start();
|
||||
return handler;
|
||||
}
|
||||
|
||||
// Constructor
|
||||
private EventHandler(DebuggerBase debuggerBase) {
|
||||
this.debuggerBase = debuggerBase;
|
||||
this.log = debuggerBase.log;
|
||||
log.display("\n# EventHandler is started");
|
||||
}
|
||||
|
||||
// This method is called by the debugger main thread.
|
||||
void waitForCompleteness() {
|
||||
log.display("\n# Waiting for EventHandler to complete");
|
||||
// wait for all expected events received or timeout exceeds
|
||||
try {
|
||||
super.join();
|
||||
if (isAlive()) {
|
||||
log.complain("FAILURE: Timeout for waiting event was exceeded");
|
||||
interrupt();
|
||||
testFailed = true;
|
||||
} else {
|
||||
log.display("# EventHandler completed");
|
||||
}
|
||||
} catch (InterruptedException ie) {
|
||||
log.complain("FAIL: InterruptedException caught while waiting for eventHandler's death");
|
||||
testFailed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// This method is called by the debugger main thread to wait and get
|
||||
// the hidden class reference type from its ClassPrepare event.
|
||||
// The readyCmdSync with the debuggeee is not enough because a
|
||||
// ClassPrepare event is delivered over JDWP protocol with a delay.
|
||||
// A wait/notify sync is to ensure the debugger gets non-null value.
|
||||
synchronized ReferenceType waitAndGetHCRefType() throws InterruptedException {
|
||||
while (hcRefType == null) {
|
||||
wait();
|
||||
}
|
||||
return hcRefType;
|
||||
}
|
||||
|
||||
// This method is called by the debugger main thread.
|
||||
boolean failedStatus() { return testFailed; }
|
||||
|
||||
// Save hidden class ReferenceType when its ClassPrepare event is received.
|
||||
private synchronized void setHCRefType(ReferenceType type) {
|
||||
hcRefType = type;
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
private EventSet getNextEventSet() throws InterruptedException {
|
||||
EventSet eventSet = debuggerBase.vm().eventQueue().remove(TIMEOUT_DELTA);
|
||||
return eventSet;
|
||||
}
|
||||
|
||||
// Breakpoint event handler.
|
||||
private void checkBreakpointEvent(BreakpointEvent event) {
|
||||
Method method = event.location().method();
|
||||
ClassType type = (ClassType)method.declaringType();
|
||||
|
||||
// got expected event in a hidden class method
|
||||
log.display("\nBreakpointEvent: " + event.toString());
|
||||
log.display("BreakpointEvent: " + type.name() + "::" + method.name());
|
||||
breakpointEventRecieived = true;
|
||||
|
||||
// find another method in the same hidden class
|
||||
ThreadReference thread = event.thread();
|
||||
Method methodToInvoke = debuggerBase.findMethod(type, "getHCField");
|
||||
|
||||
// invoke hidden class static method getNCField in debuggee VM
|
||||
testFailed |= debuggerBase.invokeStaticMethod(thread, methodToInvoke);
|
||||
}
|
||||
|
||||
// ClassPrepare event handler.
|
||||
private void checkClassPrepareEvent(ClassPrepareEvent event) {
|
||||
ReferenceType type = event.referenceType();
|
||||
String name = type.name();
|
||||
String sign = type.signature();
|
||||
|
||||
// set hidden class ReferenceType object for debugger
|
||||
setHCRefType(type);
|
||||
|
||||
log.display("\nClassPrepareEvent: " + event.toString());
|
||||
log.display("ClassPrepareEvent class name: " + name);
|
||||
log.display("ClassPrepareEvent class sign: " + sign);
|
||||
classPrepareEventRecieived = true;
|
||||
Asserts.assertTrue(name.indexOf("HiddenClass") > 0 && name.indexOf("/0x") > 0,
|
||||
"FAIL: unexpected class in ClassPrepareEvent");
|
||||
}
|
||||
|
||||
// ClassUnload event handler.
|
||||
private void checkClassUnloadEvent(ClassUnloadEvent event) {
|
||||
EventRequest request = event.request();
|
||||
String name = event.className();
|
||||
|
||||
log.display("\nClassUnloadEvent class name: " + name);
|
||||
log.display("ClassUnloadEvent class sign: " + event.classSignature());
|
||||
classUnloadEventRecieived = true;
|
||||
Asserts.assertTrue(name.indexOf("HiddenClass") > 0 && name.indexOf("/0x") > 0,
|
||||
"FAIL: unexpected class in ClassUnloadEvent");
|
||||
}
|
||||
|
||||
// ModificationWatchpoint event handler.
|
||||
private void checkModificationWatchpointEvent(ModificationWatchpointEvent event) {
|
||||
EventRequest request = event.request();
|
||||
Field field = event.field();
|
||||
ReferenceType type = field.declaringType();
|
||||
log.display("\nModificationWatchpointEvent: " + event.toString());
|
||||
log.display("ModificationWatchpointEvent: field: " + type.name() + "::" + field.name());
|
||||
log.display("ModificationWatchpointEvent: value: " + event.valueToBe().toString());
|
||||
modificationWatchpointEventRecieived = true;
|
||||
}
|
||||
|
||||
private void processEventSet(EventSet eventSet) throws InterruptedException {
|
||||
// handle each event from the event set
|
||||
EventIterator eventIterator = eventSet.eventIterator();
|
||||
while (eventIterator.hasNext()) {
|
||||
Event event = eventIterator.nextEvent();
|
||||
|
||||
if (!breakpointEventRecieived &&
|
||||
event instanceof BreakpointEvent) {
|
||||
checkBreakpointEvent((BreakpointEvent)event);
|
||||
}
|
||||
if (!classPrepareEventRecieived &&
|
||||
event instanceof ClassPrepareEvent) {
|
||||
checkClassPrepareEvent((ClassPrepareEvent)event);
|
||||
}
|
||||
if (!classUnloadEventRecieived &&
|
||||
event instanceof ClassUnloadEvent) {
|
||||
checkClassUnloadEvent((ClassUnloadEvent)event);
|
||||
}
|
||||
if (!modificationWatchpointEventRecieived &&
|
||||
event instanceof ModificationWatchpointEvent) {
|
||||
checkModificationWatchpointEvent((ModificationWatchpointEvent)event);
|
||||
}
|
||||
// ignore all other events
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
log.display("\nEventHandler started");
|
||||
try {
|
||||
// Handle events until all expected events are received.
|
||||
while (!breakpointEventRecieived ||
|
||||
!classPrepareEventRecieived ||
|
||||
!classUnloadEventRecieived ||
|
||||
!modificationWatchpointEventRecieived
|
||||
) {
|
||||
EventSet eventSet = getNextEventSet();
|
||||
if (eventSet == null) {
|
||||
continue;
|
||||
}
|
||||
processEventSet(eventSet);
|
||||
eventSet.resume();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
log.complain("Throwable in EventHandler: " + t);
|
||||
testFailed = true;
|
||||
}
|
||||
log.display("\nEventHandler finished");
|
||||
}
|
||||
} // class EventHandler
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package nsk.jdi.HiddenClass.events;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodHandles.Lookup;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import nsk.share.classload.ClassLoadUtils;
|
||||
|
||||
/* Interface for tested hidden class to implement. */
|
||||
interface HCInterf {
|
||||
void hcMethod();
|
||||
}
|
||||
|
||||
/* Hidden class definition used to define tested hidden class
|
||||
* with lookup.defineHiddenClass. */
|
||||
public class HiddenClass implements HCInterf {
|
||||
static String hcField = "<Not initialized>";
|
||||
static String getHCField() { return hcField; }
|
||||
|
||||
private String getClassName() {
|
||||
return this.getClass().getName();
|
||||
}
|
||||
|
||||
public void hcMethod() {
|
||||
hcField = getClassName();
|
||||
if (hcField.indexOf("HiddenClass") == -1) {
|
||||
throw new RuntimeException("Debuggee: Unexpected HiddenClass name: " + hcField);
|
||||
}
|
||||
}
|
||||
|
||||
public static Class<?> defineHiddenClass() throws Exception {
|
||||
final String HC_NAME = HiddenClass.class.getName();
|
||||
final String HC_PATH = ClassLoadUtils.getClassPath(HC_NAME) + File.separator +
|
||||
HC_NAME.replace(".", File.separator) + ".class";
|
||||
Class<?> hc = defineHiddenClass(HC_PATH);
|
||||
return hc;
|
||||
}
|
||||
|
||||
private static Class<?> defineHiddenClass(String classFileName) throws Exception {
|
||||
try {
|
||||
Lookup lookup = MethodHandles.lookup();
|
||||
byte[] bytes = Files.readAllBytes(Paths.get(classFileName));
|
||||
Class<?> hc = lookup.defineHiddenClass(bytes, false).lookupClass();
|
||||
return hc;
|
||||
} catch (Exception ex) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary JDI test for hidden classes
|
||||
*
|
||||
* @library /vmTestbase
|
||||
* /test/lib
|
||||
* @modules java.base/jdk.internal.misc:+open
|
||||
* @build sun.hotspot.WhiteBox
|
||||
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
|
||||
*
|
||||
* @run driver jdk.test.lib.FileInstaller . .
|
||||
* @build nsk.jdi.HiddenClass.events.*
|
||||
*
|
||||
* @run main/othervm PropertyResolvingWrapper
|
||||
* nsk.jdi.HiddenClass.events.events001
|
||||
* -verbose
|
||||
* -arch=${os.family}-${os.simpleArch}
|
||||
* -waittime=5
|
||||
* -debugee.vmkind=java
|
||||
* -transport.address=dynamic
|
||||
* "-debugee.vmkeys=-Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI ${test.vm.opts} ${test.java.opts}"
|
||||
*/
|
||||
|
||||
package nsk.jdi.HiddenClass.events;
|
||||
|
||||
import com.sun.jdi.Field;
|
||||
import com.sun.jdi.Method;
|
||||
import com.sun.jdi.ReferenceType;
|
||||
|
||||
import com.sun.jdi.request.EventRequest;
|
||||
|
||||
import nsk.jdi.HiddenClass.events.DebuggerBase;
|
||||
import nsk.jdi.HiddenClass.events.EventHandler;
|
||||
|
||||
import nsk.share.Log;
|
||||
import nsk.share.jdi.ArgumentHandler;
|
||||
|
||||
// This class is the test debugger
|
||||
public class events001 extends DebuggerBase {
|
||||
static final String PACKAGE_NAME = "nsk.jdi.HiddenClass.events";
|
||||
static final String DEBUGGEE_NAME = PACKAGE_NAME + ".events001a";
|
||||
static final String CHECKED_CLASS = PACKAGE_NAME + ".HiddenClass";
|
||||
static final String HC_FILTER = CHECKED_CLASS + "/0x*";
|
||||
|
||||
private events001(ArgumentHandler argHandler) {
|
||||
super(argHandler);
|
||||
}
|
||||
|
||||
public static void main (String args[]) {
|
||||
ArgumentHandler argHandler = new ArgumentHandler(args);
|
||||
|
||||
events001 debugger = new events001(argHandler);
|
||||
System.exit(debugger.run(argHandler) + JCK_STATUS_BASE);
|
||||
}
|
||||
|
||||
public int run(ArgumentHandler argHandler) {
|
||||
boolean testFailed = false;
|
||||
EventRequest breakpointRequest = null;
|
||||
EventRequest classPrepareRequest = null;
|
||||
EventRequest classUnloadRequest = null;
|
||||
EventRequest modWatchpointRequest = null;
|
||||
launchDebuggee(argHandler, DEBUGGEE_NAME);
|
||||
|
||||
try {
|
||||
EventHandler eventHandler = EventHandler.createAndStart(this);
|
||||
|
||||
// sync with debuggee
|
||||
readyCmdSync();
|
||||
|
||||
// request a ClassPrepare event for the hidden class "HiddenClass/0x*"
|
||||
classPrepareRequest = enableClassPrepareRequest(HC_FILTER);
|
||||
|
||||
// request a ClassUnload event for the hidden class "HiddenClass/0x*"
|
||||
classUnloadRequest = enableClassUnloadRequest(HC_FILTER);
|
||||
|
||||
// sync with debuggee
|
||||
runCmdSync();
|
||||
readyCmdSync();
|
||||
|
||||
// There is a latency in getting events from the debuggee
|
||||
// on the debugger side over the wire protocol, so we may
|
||||
// need to wait for ClassPrepareEvent to be posted.
|
||||
ReferenceType hcRefType = eventHandler.waitAndGetHCRefType();
|
||||
|
||||
/* Hidden class has to be prepared at this point. */
|
||||
|
||||
// request a Breakpoint event in the hidden class method "hcMethod"
|
||||
Method method = findMethod(hcRefType, "hcMethod");
|
||||
breakpointRequest = enableBreakpointRequest(method);
|
||||
|
||||
// request a ModificationWatchpoint event on the hidden class field "hcField"
|
||||
Field field = findField(hcRefType, "hcField");
|
||||
modWatchpointRequest = enableModificationWatchpointRequest(field, HC_FILTER);
|
||||
|
||||
// sync with debuggee
|
||||
runCmdSync();
|
||||
doneCmdSync();
|
||||
|
||||
eventHandler.waitForCompleteness();
|
||||
testFailed |= eventHandler.failedStatus();
|
||||
} catch (Throwable t) {
|
||||
log.complain("FAIL: " + t.getMessage());
|
||||
t.printStackTrace(log.getOutStream());
|
||||
testFailed = true;
|
||||
} finally {
|
||||
// disable event requests
|
||||
disableRequest(breakpointRequest, "BreakpointRequest");
|
||||
disableRequest(classPrepareRequest, "ClassPrepareRequest");
|
||||
disableRequest(classUnloadRequest, "ClassUnloadRequest");
|
||||
disableRequest(modWatchpointRequest, "ModificationWatchpointRequest");
|
||||
|
||||
// sync with debuggee
|
||||
quitCmdSync();
|
||||
testFailed |= shutdownDebuggee();
|
||||
}
|
||||
// check test results
|
||||
if (testFailed) {
|
||||
log.complain("# TEST FAILED");
|
||||
return FAILED;
|
||||
}
|
||||
log.display("# TEST PASSED");
|
||||
return PASSED;
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package nsk.jdi.HiddenClass.events;
|
||||
|
||||
import nsk.jdi.HiddenClass.events.DebuggeeBase;
|
||||
import nsk.jdi.HiddenClass.events.HiddenClass;
|
||||
import nsk.jdi.HiddenClass.events.HCInterf;
|
||||
import nsk.share.jdi.ArgumentHandler;
|
||||
import sun.hotspot.WhiteBox;
|
||||
|
||||
/* Debuggee class. */
|
||||
class events001a extends DebuggeeBase {
|
||||
private final WhiteBox WB = WhiteBox.getWhiteBox();
|
||||
|
||||
private events001a(ArgumentHandler argHandler) {
|
||||
super(argHandler);
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
ArgumentHandler argHandler = new ArgumentHandler(args);
|
||||
events001a testApp = new events001a(argHandler);
|
||||
int status = testApp.runIt();
|
||||
System.exit(DebuggerBase.JCK_STATUS_BASE + status);
|
||||
}
|
||||
|
||||
public int runIt() {
|
||||
int status = DebuggerBase.PASSED;
|
||||
logMsg("\nDebuggee: started");
|
||||
|
||||
try {
|
||||
testHiddenClass();
|
||||
} catch (Throwable t) {
|
||||
status = DebuggerBase.FAILED;
|
||||
logMsg("FAIL: Throwable was caught in debuggee main: " + t);
|
||||
}
|
||||
logMsg("\nDebuggee: finished");
|
||||
return status;
|
||||
}
|
||||
|
||||
public void testHiddenClass() throws Exception {
|
||||
syncWithDebugger();
|
||||
|
||||
// Define a hidden class.
|
||||
Class<?> hc = HiddenClass.defineHiddenClass();
|
||||
logMsg("Debuggee: defined a hidden class: " + hc.getName());
|
||||
|
||||
// It is impossible to use a hidden class name to define a variable,
|
||||
// so we use the interface which the tested hidden class implements.
|
||||
HCInterf hcObj = (HCInterf)hc.newInstance();
|
||||
logMsg("Debuggee: created an instance of a hidden class: " + hc.getName());
|
||||
|
||||
syncWithDebugger();
|
||||
|
||||
// Invoke a hidden class method.
|
||||
logMsg("Debuggee: invoking a method of a hidden class: " + hc.getName());
|
||||
hcObj.hcMethod();
|
||||
|
||||
// Provoke a hidden class unload event.
|
||||
// One more hidden class has to be defined to provoke class unload.
|
||||
// The first hidden class can not be unloaded. There are some JDI Field's
|
||||
// or Method's associated with the hidden class which keep it alive.
|
||||
logMsg("Debuggee: started provoking class unload events");
|
||||
Class<?> hcForUnload = HiddenClass.defineHiddenClass();
|
||||
hcForUnload = null;
|
||||
WB.fullGC(); // force full GC with WB to get hidden class unloaded
|
||||
logMsg("Debuggee: finished provoking class unload events");
|
||||
|
||||
quitSyncWithDebugger();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user