Path: blob/master/test/hotspot/jtreg/vmTestbase/nsk/jdwp/VirtualMachine/RedefineClasses/redefinecls001.java
41161 views
/*1* Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223package nsk.jdwp.VirtualMachine.RedefineClasses;2425import java.io.*;2627import nsk.share.*;28import nsk.share.jpda.*;29import nsk.share.jdwp.*;3031/**32* Test for JDWP command: VirtualMachine.RedefineClasses.33*34* See redefinecls001.README for description of test execution.35*36* This class represents debugger part of the test.37* Test is executed by invoking method runIt().38* JDWP command is tested in the method testCommand().39*40* @see #runIt()41* @see #testCommand()42*/43public class redefinecls001 {4445// exit status constants46static final int JCK_STATUS_BASE = 95;47static final int PASSED = 0;48static final int FAILED = 2;4950// VM capability constatnts51static final int VM_CAPABILITY_NUMBER = JDWP.Capability.CAN_REDEFINE_CLASSES;52static final String VM_CAPABILITY_NAME = "canRedefineClasses";5354// package and classes names55static final String PACKAGE_NAME = "nsk.jdwp.VirtualMachine.RedefineClasses";56static final String TEST_CLASS_NAME = PACKAGE_NAME + "." + "redefinecls001";57static final String DEBUGEE_CLASS_NAME = TEST_CLASS_NAME + "a";5859// tested JDWP command60static final String JDWP_COMMAND_NAME = "VirtualMachine.RedefineClasses";61static final int JDWP_COMMAND_ID = JDWP.Command.VirtualMachine.RedefineClasses;6263// tested class name and signature64static final String TESTED_CLASS_NAME = TEST_CLASS_NAME + "b";65static final String TESTED_CLASS_SIGNATURE = "L" + TESTED_CLASS_NAME.replace('.', '/') + ";";6667// field and method names68static final String CONSTRUCTOR_FIELD_NAME = "constructorInvoked";69static final String STATIC_METHOD_FIELD_NAME = "staticMethodInvoked";70static final String OBJECT_METHOD_FIELD_NAME = "objectMethodInvoked";71static final String BREAKPOINT_METHOD_NAME = "runIt";72static final int BREAKPOINT_LINE_BEFORE = redefinecls001a.BREAKPOINT_LINE_BEFORE;73static final int BREAKPOINT_LINE_AFTER = redefinecls001a.BREAKPOINT_LINE_AFTER;7475// filename for redefined class76static final String REDEFINED_CLASS_FILE_NAME = "bin" + File.separator + "newclass"77+ File.separator + PACKAGE_NAME.replace('.',File.separatorChar)78+ File.separator + "redefinecls001b.class";7980// usual scaffold objects81ArgumentHandler argumentHandler = null;82Log log = null;83Binder binder = null;84Debugee debugee = null;85Transport transport = null;86int waitTime = 0; // minutes87long timeout = 0; // milliseconds88String testDir = null;89boolean dead = false;90boolean success = true;9192// data obtained from debuggee93long debugeeClassID = 0;94long testedClassID = 0;95long breakpointMethodID = 0;96ByteBuffer redefinedClassBytes = null;9798// -------------------------------------------------------------------99100/**101* Start test from command line.102*/103public static void main (String argv[]) {104System.exit(run(argv,System.out) + JCK_STATUS_BASE);105}106107/**108* Start JCK-compilant test.109*/110public static int run(String argv[], PrintStream out) {111return new redefinecls001().runIt(argv, out);112}113114// -------------------------------------------------------------------115116/**117* Perform test execution.118*/119public int runIt(String argv[], PrintStream out) {120121// make log for debugger messages122argumentHandler = new ArgumentHandler(argv);123log = new Log(out, argumentHandler);124waitTime = argumentHandler.getWaitTime(); // minutes125timeout = waitTime * 60 * 1000; // milliseconds126127// get testDir as first positional parameter128String args[] = argumentHandler.getArguments();129if (args.length < 1) {130log.complain("Test dir required as the first positional argument");131return FAILED;132}133testDir = args[0];134135// execute test and display results136try {137log.display("\n>>> Loading redefined class \n");138139// load class file for redefined class140log.display("Loading bytecode of redefined class from file: " +141REDEFINED_CLASS_FILE_NAME);142redefinedClassBytes = loadClassBytes(REDEFINED_CLASS_FILE_NAME, testDir);143log.display(" ... loaded bytes: " + redefinedClassBytes.length());144145log.display("\n>>> Starting debugee \n");146147// launch debuggee148binder = new Binder(argumentHandler, log);149log.display("Launching debugee VM");150debugee = binder.bindToDebugee(DEBUGEE_CLASS_NAME);151transport = debugee.getTransport();152log.display(" ... debuggee launched");153154// set timeout for debuggee responces155log.display("Setting timeout for debuggee responces: " + waitTime + " minute(s)");156transport.setReadTimeout(timeout);157log.display(" ... timeout set");158159// wait for VM_INIT event160log.display("Waiting for VM_INIT event");161debugee.waitForVMInit();162log.display(" ... VM_INIT event received");163164// query debugee for VM-dependent ID sizes165log.display("Querying for IDSizes");166debugee.queryForIDSizes();167log.display(" ... size of VM-dependent types adjusted");168169// check for VM capability170log.display("\n>>> Checking VM capability \n");171log.display("Getting new VM capability: " + VM_CAPABILITY_NAME);172boolean capable = debugee.getNewCapability(VM_CAPABILITY_NUMBER, VM_CAPABILITY_NAME);173log.display(" ... got VM capability: " + capable);174175// exit as PASSED if this capability is not supported176if (!capable) {177out.println("TEST PASSED: unsupported VM capability: "178+ VM_CAPABILITY_NAME);179return PASSED;180}181182// prepare debuggee for testing and obtain required data183log.display("\n>>> Getting prepared for testing \n");184prepareForTest();185186// test JDWP command187log.display("\n>> Testing JDWP command \n");188testCommand();189190// check command results191if (success) {192log.display("\n>>> Checking result of tested command \n");193checkResult();194}195196// finish debuggee197log.display("\n>> Finishing debuggee \n");198199// resume debuggee after testing command200log.display("Resuming debuggee");201debugee.resume();202log.display(" ... debuggee resumed");203204// wait for VM_DEATH event205log.display("Waiting for VM_DEATH event");206debugee.waitForVMDeath();207log.display(" ... VM_DEATH event received");208dead = true;209210} catch (Failure e) {211log.complain("TEST FAILED: " + e.getMessage());212success = false;213} catch (Exception e) {214e.printStackTrace(out);215log.complain("Caught unexpected exception while running the test:\n\t" + e);216success = false;217} finally {218log.display("\n>>> Finishing test \n");219220// disconnect debugee and wait for its exit221if (debugee != null) {222quitDebugee();223}224}225226// check result227if (!success) {228log.complain("TEST FAILED");229return FAILED;230}231out.println("TEST PASSED");232return PASSED;233}234235/**236* Get debuggee prepared for testing and obtain required data.237*/238void prepareForTest() {239// wait for debuggee and tested classes loaded on debuggee startup240log.display("Waiting for classes loaded:"241+ "\n\t" + DEBUGEE_CLASS_NAME242+ "\n\t" + TESTED_CLASS_NAME);243String classNames[] = {DEBUGEE_CLASS_NAME, TESTED_CLASS_NAME};244long classIDs[] = debugee.waitForClassesLoaded(classNames,245JDWP.SuspendPolicy.ALL);246debugeeClassID = classIDs[0];247log.display(" ... debuggee class loaded with classID: " + debugeeClassID);248testedClassID = classIDs[1];249log.display(" ... tested class loaded with classID: " + testedClassID);250log.display("");251252// set breakpoint before redefinition and wait for debugee reached it253log.display("Waiting for breakpoint before redefiniton reached at: "254+ BREAKPOINT_METHOD_NAME + ":" + BREAKPOINT_LINE_BEFORE);255long threadID = debugee.waitForBreakpointReached(debugeeClassID,256BREAKPOINT_METHOD_NAME,257BREAKPOINT_LINE_BEFORE,258JDWP.SuspendPolicy.ALL);259log.display(" ... breakpoint before redefinition reached with threadID: " + threadID);260log.display("");261}262263/**264* Perform testing JDWP command.265*/266void testCommand() {267int length = redefinedClassBytes.length();268// create command packet and fill requred out data269log.display("Create command packet:");270log.display("Command: " + JDWP_COMMAND_NAME);271CommandPacket command = new CommandPacket(JDWP_COMMAND_ID);272log.display(" classes: " + 1);273command.addInt(1);274log.display(" refTypeID: " + testedClassID);275command.addReferenceTypeID(testedClassID);276log.display(" classfile: " + length + " bytes");277command.addInt(length);278log.display(" classbytes:\n" + redefinedClassBytes);279command.addBytes(redefinedClassBytes.getBytes(), 0, length);280command.setLength();281282// send command packet to debugee283try {284log.display("Sending command packet:\n" + command);285transport.write(command);286} catch (IOException e) {287log.complain("Unable to send command packet:\n\t" + e);288success = false;289return;290}291292// receive reply packet from debugee293ReplyPacket reply = new ReplyPacket();294try {295log.display("Waiting for reply packet");296transport.read(reply);297log.display(" ... reply packet received:\n" + reply);298} catch (IOException e) {299log.complain("Unable to read reply packet for tested command:\n\t" + e);300success = false;301return;302}303304// check reply packet header305try{306log.display("Checking header of reply packet");307reply.checkHeader(command.getPacketID());308log.display(" ... packet header is correct");309} catch (BoundException e) {310log.complain("Wrong header of reply packet for tested command:\n\t"311+ e.getMessage());312success = false;313return;314}315316// start parsing reply packet data317log.display("Parsing reply packet data:");318reply.resetPosition();319320// no reply data to parse321log.display(" no reply data");322323// check for extra data in reply packet324if (!reply.isParsed()) {325log.complain("Extra trailing bytes found in reply packet at: "326+ reply.offsetString());327success = false;328}329330log.display(" ... packed data parsed");331}332333/**334* Check result of the tested JDWP command.335*/336void checkResult() {337// set breakpoint after redefinition and wait for debugee reached it338log.display("Waiting for breakpoint after redefiniton reached at: "339+ BREAKPOINT_METHOD_NAME + ":" + BREAKPOINT_LINE_AFTER);340long threadID = debugee.waitForBreakpointReached(debugeeClassID,341BREAKPOINT_METHOD_NAME,342BREAKPOINT_LINE_AFTER,343JDWP.SuspendPolicy.ALL);344log.display(" ... breakpoint after redefinition reached with threadID: " + threadID);345log.display("");346347// check invoked methods348log.display("Getting value of static field: " + CONSTRUCTOR_FIELD_NAME);349JDWP.Value value = debugee.getStaticFieldValue(testedClassID,350CONSTRUCTOR_FIELD_NAME, JDWP.Tag.INT);351int constructorInvoked = ((Integer)value.getValue()).intValue();352log.display(" ... got constructorInvoked: " + methodKind(constructorInvoked));353354if (constructorInvoked != redefinecls001b.NOT_REDEFINED_METHOD_INVOKED) {355log.complain("Constructor has been invoked after class redefinition");356success = false;357}358359log.display("Getting value of static field: " + STATIC_METHOD_FIELD_NAME);360value = debugee.getStaticFieldValue(testedClassID,361STATIC_METHOD_FIELD_NAME, JDWP.Tag.INT);362int staticMethodInvoked = ((Integer)value.getValue()).intValue();363log.display(" ... got staticMethodInvoked: " + methodKind(staticMethodInvoked));364365if (staticMethodInvoked != redefinecls001b.REDEFINED_METHOD_INVOKED) {366log.complain("Not redefined static method is invoked after class redefinition");367success = false;368}369370log.display("Getting value of static field: " + OBJECT_METHOD_FIELD_NAME);371value = debugee.getStaticFieldValue(testedClassID,372OBJECT_METHOD_FIELD_NAME, JDWP.Tag.INT);373int objectMethodInvoked = ((Integer)value.getValue()).intValue();374log.display(" ... got objectMethodInvoked: " + methodKind(objectMethodInvoked));375376if (objectMethodInvoked != redefinecls001b.REDEFINED_METHOD_INVOKED) {377log.complain("Not redefined object method is invoked after class redefinition");378success = false;379}380}381382/**383* Load class bytes form the given file.384*/385ByteBuffer loadClassBytes(String fileName, String dirName) {386String fileSep = System.getProperty("file.separator");387String filePath = dirName + fileSep + fileName;388389String error = "Unable to read bytes from class file:\n\t" + filePath;390391int length = 0;392byte bytes[] = null;393try {394File file = new File(filePath);395length = (int)file.length();396FileInputStream is = new FileInputStream(file);397bytes = new byte[length];398int number = is.read(bytes);399if (number < 0) {400log.complain("EOF reached while reading bytes from file");401throw new Failure(error);402} else if (number != length) {403log.complain("Unexpected number of bytes red from file: " + number404+ " (expected: " + length + ")");405throw new Failure(error);406}407is.close();408} catch ( IOException e ) {409log.complain("Caught IOException while reading bytes from file:\n\t" + e);410throw new Failure(error);411}412ByteBuffer byteBuffer = new ByteBuffer(length, 0);413byteBuffer.addBytes(bytes, 0, length);414return byteBuffer;415}416417/**418* Disconnect debuggee and wait for it exited.419*/420void quitDebugee() {421if (debugee == null)422return;423424// disconnect debugee425if (!dead) {426try {427log.display("Disconnecting debuggee");428debugee.dispose();429log.display(" ... debuggee disconnected");430} catch (Failure e) {431log.display("Failed to finally disconnect debuggee:\n\t"432+ e.getMessage());433}434}435436// wait for debugee exited437log.display("Waiting for debuggee exit");438int code = debugee.waitFor();439log.display(" ... debuggee exited with exit code: " + code);440441// analize debugee exit status code442if (code != JCK_STATUS_BASE + PASSED) {443log.complain("Debuggee FAILED with exit code: " + code);444success = false;445}446}447448// return string representation of kind of invoked method449private static String methodKind(int kind) {450switch (kind) {451case redefinecls001b.METHOD_NOT_INVOKED:452return "METHOD_NOT_INVOKED";453case redefinecls001b.REDEFINED_METHOD_INVOKED:454return "REDEFINED_METHOD_INVOKED";455case redefinecls001b.NOT_REDEFINED_METHOD_INVOKED:456return "NOT_REDEFINED_METHOD_INVOKED";457default:458return "UNKNOWN_METHOD_KIND";459}460}461}462463464