8241214: Test debugging of hidden classes using jdb
Add test and enable jdb support for hidden classes Reviewed-by: cjplummer, amenkov, mchung, lmesnik
This commit is contained in:
parent
8d388381ee
commit
e507405f5c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 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
|
||||
@ -101,6 +101,28 @@ class PatternReferenceTypeSpec implements ReferenceTypeSpec {
|
||||
}
|
||||
|
||||
private void checkClassName(String className) throws ClassNotFoundException {
|
||||
int slashIdx = className.indexOf("/");
|
||||
|
||||
// Slash is present in hidden class names only. It looks like p.Foo/0x1234.
|
||||
if (slashIdx != -1) {
|
||||
// A hidden class name is ending with a slash following by a suffix.
|
||||
int lastSlashIdx = className.lastIndexOf("/");
|
||||
int lastDotIdx = className.lastIndexOf(".");
|
||||
|
||||
// There must be just one slash with a following suffix but no dots.
|
||||
if (slashIdx != lastSlashIdx || lastDotIdx > slashIdx || slashIdx + 1 == className.length()) {
|
||||
throw new ClassNotFoundException();
|
||||
}
|
||||
// Check prefix and suffix separately.
|
||||
String[] parts = className.split("/");
|
||||
assert parts.length == 2;
|
||||
className = parts[0];
|
||||
String hcSuffix = parts[1];
|
||||
if (!isUnqualifiedName(hcSuffix)) {
|
||||
throw new ClassNotFoundException();
|
||||
}
|
||||
}
|
||||
|
||||
// Do stricter checking of class name validity on deferred
|
||||
// because if the name is invalid, it will
|
||||
// never match a future loaded class, and we'll be silent
|
||||
@ -118,6 +140,14 @@ class PatternReferenceTypeSpec implements ReferenceTypeSpec {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isUnqualifiedName(String s) {
|
||||
if (s.length() == 0) {
|
||||
return false;
|
||||
}
|
||||
// unqualified names should have no characters: ".;/["
|
||||
return !s.matches("[.;/\091]*"); // \091 is '['
|
||||
}
|
||||
|
||||
private boolean isJavaIdentifier(String s) {
|
||||
if (s.length() == 0) {
|
||||
return false;
|
||||
|
@ -0,0 +1,357 @@
|
||||
/*
|
||||
* 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 JDB test for hidden classes
|
||||
*
|
||||
* @library /vmTestbase
|
||||
* /test/lib
|
||||
* @modules jdk.jdi
|
||||
* jdk.jdwp.agent
|
||||
* @run driver jdk.test.lib.FileInstaller . .
|
||||
* @build nsk.jdb.hidden_class.hc001.hc001
|
||||
* nsk.jdb.hidden_class.hc001.hc001a
|
||||
*
|
||||
* @run main/othervm PropertyResolvingWrapper nsk.jdb.hidden_class.hc001.hc001
|
||||
* -arch=${os.family}-${os.simpleArch}
|
||||
* -waittime=5
|
||||
* -debugee.vmkind=java
|
||||
* -transport.address=dynamic
|
||||
* -jdb=${test.jdk}/bin/jdb
|
||||
* -java.options="${test.vm.opts} ${test.java.opts}"
|
||||
* -workdir=.
|
||||
* -debugee.vmkeys="${test.vm.opts} ${test.java.opts}"
|
||||
*/
|
||||
|
||||
package nsk.jdb.hidden_class.hc001;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import nsk.share.*;
|
||||
import nsk.share.jdb.*;
|
||||
|
||||
public class hc001 extends JdbTest {
|
||||
static final String DEBUGGEE_CLASS = hc001a.class.getTypeName();
|
||||
static final String HC_NAME_FIELD = DEBUGGEE_CLASS + ".hcName";
|
||||
static final String MAIN_METHOD_NAME = DEBUGGEE_CLASS + ".main";
|
||||
static final String EMPTY_METHOD_NAME = DEBUGGEE_CLASS + ".emptyMethod";
|
||||
static final String HC_METHOD_NAME = "hcMethod";
|
||||
static final String HC_FIELD_NAME = "hcField";
|
||||
static final int MAX_SLEEP_CNT = 3;
|
||||
|
||||
public static void main(String argv[]) {
|
||||
System.exit(run(argv, System.out) + JCK_STATUS_BASE);
|
||||
}
|
||||
|
||||
public static int run(String argv[], PrintStream out) {
|
||||
debuggeeClass = DEBUGGEE_CLASS; // needed for JdbTest.runTest
|
||||
firstBreak = MAIN_METHOD_NAME; // needed for JdbTest.runTest
|
||||
return new hc001().runTest(argv, out);
|
||||
}
|
||||
|
||||
static boolean checkPattern(String[] arr, String pattern) {
|
||||
for (int idx = 0; idx < arr.length; idx++) {
|
||||
String str = arr[idx];
|
||||
if (str.indexOf(pattern) != -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void throwFailure(String msg) throws Failure {
|
||||
throw new Failure(msg);
|
||||
}
|
||||
|
||||
/* Make a required cooperated setup with the debuggee:
|
||||
* - transition the debuggee's execution to expected execution point
|
||||
* (emptyMethod start) at which hidden class has been already loaded
|
||||
* - get the hidden class name from the debuggee
|
||||
* Return the hidden class name.
|
||||
*/
|
||||
private String runPrologue() {
|
||||
String[] reply = null;
|
||||
|
||||
log.println("\n### Debugger: runPrologue");
|
||||
|
||||
// uncomment this line to enable verbose output from jdb
|
||||
// log.enableVerbose(true);
|
||||
|
||||
// run jdb command "stop in"
|
||||
jdb.setBreakpointInMethod(EMPTY_METHOD_NAME);
|
||||
log.println("\nDebugger: breakpoint is set at:\n\t" + EMPTY_METHOD_NAME);
|
||||
|
||||
// run jdb command "cont"
|
||||
reply = jdb.receiveReplyFor(JdbCommand.cont);
|
||||
if (!jdb.isAtBreakpoint(reply, EMPTY_METHOD_NAME)) {
|
||||
throwFailure("Debugger: Missed breakpoint at:\n\t" + EMPTY_METHOD_NAME);
|
||||
}
|
||||
log.println("\nDebugger: breakpoint is hit at:\n\t" + EMPTY_METHOD_NAME);
|
||||
|
||||
// run jdb command "eval" for hidden class field HC_NAME_FIELD
|
||||
reply = jdb.receiveReplyFor(JdbCommand.eval + HC_NAME_FIELD);
|
||||
int beg = reply[0].indexOf('"') + 1;
|
||||
int end = reply[0].lastIndexOf('"');
|
||||
if (end == -1 || beg > end) {
|
||||
log.println("\nDebugger: the jdb command:\n\t" + JdbCommand.eval + HC_NAME_FIELD);
|
||||
log.println("\treturned bad reply:\n\t" + reply[0]);
|
||||
throwFailure("Debugger: failed to evaluate debuggee field:\n\t" + HC_NAME_FIELD);
|
||||
}
|
||||
String hiddenClassName = reply[0].substring(beg, end); // we know the hidden class name now
|
||||
log.println("\nDebugger: jdb command eval returned hidden class name:\n\t" + hiddenClassName);
|
||||
|
||||
return hiddenClassName;
|
||||
}
|
||||
|
||||
/* Test jdb commands "classes" and "class" for hidden class. */
|
||||
private void testClassCommands(String hcName) {
|
||||
String[] reply = null;
|
||||
|
||||
log.println("\n### Debugger: testClassCommands");
|
||||
|
||||
// run jdb command "classes"
|
||||
reply = jdb.receiveReplyFor(JdbCommand.classes);
|
||||
if (!checkPattern(reply, hcName)) {
|
||||
throwFailure("Debugger: expected jdb command classes to list hidden class:\n\t" + hcName);
|
||||
}
|
||||
log.println("\nDebugger: found matched class in jdb command classes reply:\n\t" + hcName);
|
||||
|
||||
// run jdb command "class" for hidden class
|
||||
reply = jdb.receiveReplyFor(JdbCommand._class + hcName);
|
||||
if (!checkPattern(reply, hcName)) {
|
||||
throwFailure("Debugger: expected hiddenclass name in jdb command class reply: " + hcName);
|
||||
}
|
||||
log.println("\nDebugger: found matched class in jdb command class reply:\n\t" + hcName);
|
||||
}
|
||||
|
||||
/* Transition the debuggee's execution to the hidden class method start. */
|
||||
private void stopInHiddenClassMethod(String hcName) {
|
||||
String hcMethodName = hcName + "." + HC_METHOD_NAME;
|
||||
String[] reply = null;
|
||||
|
||||
log.println("\n### Debugger: stopInHiddenClassMethod");
|
||||
|
||||
// set a breakpoint in hidden class method hcMethodName()
|
||||
jdb.setBreakpointInMethod(hcMethodName);
|
||||
log.println("\nDebugger: breakpoint is set at:\n\t" + hcMethodName);
|
||||
|
||||
// run jdb command "clear": should list breakpoint in hcMethodName
|
||||
reply = jdb.receiveReplyFor(JdbCommand.clear);
|
||||
if (!checkPattern(reply, hcMethodName)) {
|
||||
throwFailure("Debugger: expected jdb clear command to list breakpoint: " + hcMethodName);
|
||||
}
|
||||
log.println("\nDebugger: jdb command clear lists breakpoint at:\n\t" + hcMethodName);
|
||||
|
||||
// run jdb command "cont"
|
||||
jdb.receiveReplyFor(JdbCommand.cont);
|
||||
log.println("\nDebugger: executed jdb command cont");
|
||||
}
|
||||
|
||||
/* Test the jdb commands "up" and "where" for hidden class. */
|
||||
private void testUpWhereCommands(String hcName) {
|
||||
String hcMethodName = hcName + "." + HC_METHOD_NAME;
|
||||
String[] reply = null;
|
||||
|
||||
log.println("\n### Debugger: testUpWhereCommands");
|
||||
|
||||
// run jdb command "where": should list hcMethodName frame
|
||||
reply = jdb.receiveReplyFor(JdbCommand.where);
|
||||
if (!checkPattern(reply, hcMethodName)) {
|
||||
throwFailure("Debugger: jdb command where does not show expected frame: " + hcMethodName);
|
||||
}
|
||||
log.println("\nDebugger: jdb command where showed expected frame:\n\t" + hcMethodName);
|
||||
|
||||
// run jdb command "up"
|
||||
jdb.receiveReplyFor(JdbCommand.up);
|
||||
log.println("\nDebugger: executed jdb command up");
|
||||
|
||||
// run jdb command "where": should not list hcMethodName frame
|
||||
reply = jdb.receiveReplyFor(JdbCommand.where);
|
||||
if (checkPattern(reply, hcMethodName)) {
|
||||
throwFailure("Debugger: jdb command where showed unexpected frame: " + hcMethodName);
|
||||
}
|
||||
log.println("\nDebugger: jdb command where does not show unexpected frame:\n\t" + hcMethodName);
|
||||
}
|
||||
|
||||
/* Test the jdb commands "down" and "where" for hidden class. */
|
||||
private void testDownWhereCommands(String hcName) {
|
||||
String hcMethodName = hcName + "." + HC_METHOD_NAME;
|
||||
String[] reply = null;
|
||||
|
||||
log.println("\n### Debugger: testDownWhereCommands");
|
||||
|
||||
// run jdb command "down"
|
||||
jdb.receiveReplyFor(JdbCommand.down);
|
||||
log.println("\nDebugger: executed jdb command down");
|
||||
|
||||
// run jdb command "where": should list hcMethodName frame again
|
||||
reply = jdb.receiveReplyFor(JdbCommand.where);
|
||||
if (!checkPattern(reply, hcMethodName)) {
|
||||
throwFailure("Debugger: jdb command where does not show expected frame: " + hcMethodName);
|
||||
}
|
||||
log.println("\nDebugger: jdb command where showed expected frame:\n\t" + hcMethodName);
|
||||
}
|
||||
|
||||
/* Test the jdb commands "fields" and "methods" for hidden class. */
|
||||
private void testFieldsMethods(String hcName) {
|
||||
String[] reply = null;
|
||||
|
||||
log.println("\n### Debugger: testFieldsMethods");
|
||||
|
||||
// run jdb command "methods" for hidden class
|
||||
reply = jdb.receiveReplyFor(JdbCommand.methods + hcName);
|
||||
if (!checkPattern(reply, hcName)) {
|
||||
throwFailure("Debugger: no expected hidden class name in its methods: " + hcName);
|
||||
}
|
||||
log.println("\nDebugger: jdb command \"methods\" showed expected method:\n\t" + HC_METHOD_NAME);
|
||||
|
||||
// run jdb command "fields" for hidden class
|
||||
reply = jdb.receiveReplyFor(JdbCommand.fields + hcName);
|
||||
if (!checkPattern(reply, HC_FIELD_NAME)) {
|
||||
throwFailure("Debugger: no expected hidden class field in its fields: " + HC_FIELD_NAME);
|
||||
}
|
||||
log.println("\nDebugger: jdb command \"fields\" showed expected field:\n\t" + HC_FIELD_NAME);
|
||||
}
|
||||
|
||||
/* Test the jdb commands "watch" and "unwatch" for hidden class. */
|
||||
private void testWatchCommands(String hcName) {
|
||||
String hcFieldName = hcName + "." + HC_FIELD_NAME;
|
||||
String[] reply = null;
|
||||
|
||||
log.println("\n### Debugger: testWatchCommands");
|
||||
|
||||
// run jdb command "watch" for hidden class field HC_FIELD_NAME
|
||||
reply = jdb.receiveReplyFor(JdbCommand.watch + hcFieldName);
|
||||
if (!checkPattern(reply, HC_FIELD_NAME)) {
|
||||
throwFailure("Debugger: was not able to set watch point: " + hcFieldName);
|
||||
}
|
||||
log.println("\nDebugger: jdb command \"watch\" added expected field to watch:\n\t" + hcFieldName);
|
||||
|
||||
// run jdb command "cont"
|
||||
jdb.receiveReplyFor(JdbCommand.cont);
|
||||
jdb.receiveReplyFor(JdbCommand.next);
|
||||
|
||||
// run jdb command "unwatch" for hidden class field HC_FIELD_NAME
|
||||
reply = jdb.receiveReplyFor(JdbCommand.unwatch + hcFieldName);
|
||||
if (!checkPattern(reply, HC_FIELD_NAME)) {
|
||||
throwFailure("Debugger: expect field name in unwatch reply: " + hcFieldName);
|
||||
}
|
||||
log.println("\nDebugger: jdb command \"unwatch\" removed expected field from watch:\n\t" + hcFieldName);
|
||||
}
|
||||
|
||||
/* Test the jdb commands "eval", "print" and "dump" for hidden class. */
|
||||
private void testEvalCommands(String hcName) {
|
||||
String hcFieldName = hcName + "." + HC_FIELD_NAME;
|
||||
String[] reply = null;
|
||||
|
||||
log.println("\n### Debugger: testEvalCommands");
|
||||
|
||||
// run jdb command "eval" for hidden class field HC_FIELD_NAME
|
||||
reply = jdb.receiveReplyFor(JdbCommand.eval + hcFieldName);
|
||||
if (!checkPattern(reply, hcFieldName)) {
|
||||
throwFailure("Debugger: expected field name in jdb command eval field reply: " + hcFieldName);
|
||||
}
|
||||
log.println("\nDebugger: jdb command \"eval\" showed expected hidden class field name:\n\t" + hcFieldName);
|
||||
|
||||
// run jdb command "print" for hidden class field HC_FIELD_NAME
|
||||
reply = jdb.receiveReplyFor(JdbCommand.print + hcFieldName);
|
||||
if (!checkPattern(reply, hcFieldName)) {
|
||||
throwFailure("Debugger: expected field name in jdb command print field reply: " + hcFieldName);
|
||||
}
|
||||
log.println("\nDebugger: jdb command \"print\" showed expected hidden class field name:\n\t" + hcFieldName);
|
||||
|
||||
// execute jdb command "dump" for hidden class field HC_FIELD_NAME
|
||||
reply = jdb.receiveReplyFor(JdbCommand.dump + hcFieldName);
|
||||
if (!checkPattern(reply, hcFieldName)) {
|
||||
throwFailure("Debugger: expected field name in jdb command dump field reply: " + hcFieldName);
|
||||
}
|
||||
log.println("\nDebugger: jdb command \"dump\" showed expected hidden class field name:\n\t" + hcFieldName);
|
||||
}
|
||||
|
||||
/* Test the jdb command "watch" with an invalid class name. */
|
||||
private void testInvWatchCommand(String hcName) {
|
||||
String hcFieldName = hcName + "." + HC_FIELD_NAME;
|
||||
String MsgBase = "\nDebugger: jdb command \"watch\" with invalid field " + hcFieldName;
|
||||
String[] reply = null;
|
||||
|
||||
// run jdb command "watch" with an invalid class name
|
||||
reply = jdb.receiveReplyFor(JdbCommand.watch + hcFieldName);
|
||||
if (checkPattern(reply, "Deferring watch modification")) {
|
||||
throwFailure(MsgBase + " must not set deferred watch point");
|
||||
}
|
||||
log.println(MsgBase + " did not set deferred watch point");
|
||||
}
|
||||
|
||||
/* Test the jdb command "eval" with an invalid class name. */
|
||||
private void testInvEvalCommand(String hcName) {
|
||||
String hcFieldName = hcName + "." + HC_FIELD_NAME;
|
||||
String MsgBase = "\nDebugger: jdb command \"eval\" with invalid field " + hcFieldName;
|
||||
String[] reply = null;
|
||||
|
||||
// run jdb command "eval" with an invalid class name
|
||||
reply = jdb.receiveReplyFor(JdbCommand.eval + hcFieldName);
|
||||
if (!checkPattern(reply, "ParseException")) {
|
||||
throwFailure(MsgBase + " must be rejected with ParseException");
|
||||
}
|
||||
log.println(MsgBase + " was rejected with ParseException");
|
||||
}
|
||||
|
||||
/* Test the jdb commands "watch" and "eval" with various invalid class names. */
|
||||
private void testInvalidCommands() {
|
||||
String className = null;
|
||||
String[] invClassNames = {
|
||||
"xx.yyy/0x111/0x222",
|
||||
"xx./0x111.0x222",
|
||||
"xx.yyy.zzz/"
|
||||
};
|
||||
|
||||
log.println("\n### Debugger: testInvalidCommands");
|
||||
|
||||
// run jdb commands "watch" and "eval" with invalid class names
|
||||
for (int idx = 0; idx < invClassNames.length; idx++) {
|
||||
className = invClassNames[idx];
|
||||
testInvWatchCommand(className + "." + HC_FIELD_NAME);
|
||||
testInvEvalCommand(className + "." + HC_FIELD_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
/* Main testing method. */
|
||||
protected void runCases() {
|
||||
String hcName = runPrologue();
|
||||
|
||||
testClassCommands(hcName);
|
||||
stopInHiddenClassMethod(hcName);
|
||||
|
||||
testUpWhereCommands(hcName);
|
||||
testDownWhereCommands(hcName);
|
||||
|
||||
testFieldsMethods(hcName);
|
||||
testWatchCommands(hcName);
|
||||
|
||||
testEvalCommands(hcName);
|
||||
testInvalidCommands();
|
||||
|
||||
jdb.contToExit(1);
|
||||
}
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* 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.jdb.hidden_class.hc001;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodHandles.Lookup;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import nsk.share.jdb.*;
|
||||
|
||||
/* Interface for tested hidden class to implement. */
|
||||
interface HCInterf {
|
||||
void hcMethod();
|
||||
}
|
||||
|
||||
/* Hidden class definition used to define tested hidden class
|
||||
* with lookup.defineHiddenClass. */
|
||||
class HiddenClass implements HCInterf {
|
||||
static String hcField = null;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* This is debuggee aplication */
|
||||
public class hc001a {
|
||||
static PrintStream log = null;
|
||||
static void logMsg(String msg) { log.println(msg); log.flush(); }
|
||||
|
||||
static final String JAVA_CP = System.getProperty("java.class.path");
|
||||
static final String HC_NAME = HiddenClass.class.getName().replace(".", File.separator) + ".class";
|
||||
static final String HC_PATH = getClassPath(HiddenClass.class);
|
||||
static String hcName = null; // the debugger gets value of this field
|
||||
|
||||
static String getClassPath(Class<?> klass) {
|
||||
String classPath = klass.getTypeName().replace(".", File.separator) + ".class";
|
||||
for (String path: JAVA_CP.split(File.pathSeparator)) {
|
||||
String fullClassPath = path + File.separator + classPath;
|
||||
if (new File(fullClassPath).exists()) {
|
||||
return fullClassPath;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("class path for " + klass.getName() + " not found");
|
||||
}
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
// The Jdb framework uses stdout for commands reply,
|
||||
// so it is not usable for normal logging.
|
||||
// Use a separate log file for debuggee located in JTwork/scratch.
|
||||
log = new PrintStream("Debuggee.log");
|
||||
|
||||
hc001a testApp = new hc001a();
|
||||
int status = testApp.runIt(args);
|
||||
System.exit(hc001.JCK_STATUS_BASE + status);
|
||||
}
|
||||
|
||||
// This method is to hit a breakpoint at expected execution point.
|
||||
void emptyMethod() {}
|
||||
|
||||
public int runIt(String args[]) throws Exception {
|
||||
JdbArgumentHandler argumentHandler = new JdbArgumentHandler(args);
|
||||
|
||||
logMsg("Debuggee: runIt: started");
|
||||
logMsg("Debuggee: JAVA_CP: " + JAVA_CP);
|
||||
logMsg("Debuggee: HC_NAME: " + HC_NAME);
|
||||
logMsg("Debuggee: HC_PATH: " + HC_PATH);
|
||||
|
||||
// Define tested hidden class.
|
||||
Class<?> hc = defineHiddenClass(HC_PATH);
|
||||
|
||||
// A hidden class name has an unpredictable suffix at the end,
|
||||
// and so, can not be hard coded and known to debugger in advance.
|
||||
// Store the hidden class name in field, so the debugger can read it from there.
|
||||
hcName = hc.getName();
|
||||
logMsg("Debuggee: Defined HiddenClass: " + hcName);
|
||||
|
||||
// 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: " + hcName);
|
||||
|
||||
// It is for debuuger to set a breakpoint at a well known execution point.
|
||||
logMsg("Debuggee: invoking emptyMethod to hit expected breakpoint");
|
||||
emptyMethod();
|
||||
|
||||
// Invoke a hidden class method.
|
||||
logMsg("Debuggee: invoking a method of a hidden class: " + hcName);
|
||||
hcObj.hcMethod();
|
||||
|
||||
logMsg("Debuggee: runIt finished");
|
||||
return hc001.PASSED;
|
||||
}
|
||||
|
||||
static Class<?> defineHiddenClass(String classFileName) throws Exception {
|
||||
try {
|
||||
Lookup lookup = MethodHandles.lookup();
|
||||
byte[] bytes = Files.readAllBytes(Paths.get(classFileName));
|
||||
// The class name from class file is a normal binary name but the
|
||||
// defineHiddenClass appends a suffix "/<unqualified-name>" to it,
|
||||
// so it is not a valid binary name anymore.
|
||||
Class<?> hc = lookup.defineHiddenClass(bytes, false).lookupClass();
|
||||
return hc;
|
||||
} catch (Exception ex) {
|
||||
logMsg("Debuggee: defineHiddenClass: caught Exception " + ex.getMessage());
|
||||
ex.printStackTrace(log);
|
||||
log.flush();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user