/* * Copyright (c) 2016, 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. */ import java.io.IOException; import java.util.Arrays; import java.util.concurrent.CountDownLatch; import java.util.Set; import java.util.HashSet; import static jdk.test.lib.Asserts.assertTrue; /** * @test * @summary Tests the modules-related JDWP commands * @library /test/lib * @ignore 8170541 * @modules jdk.jdwp.agent * @modules java.base/jdk.internal.misc * @compile AllModulesCommandTestDebuggee.java * @run main/othervm AllModulesCommandTest */ public class AllModulesCommandTest implements DebuggeeLauncher.Listener { private DebuggeeLauncher launcher; private JdwpChannel channel; private CountDownLatch jdwpLatch = new CountDownLatch(1); private Set<String> jdwpModuleNames = new HashSet<>(); private Set<String> javaModuleNames = new HashSet<>(); public static void main(String[] args) throws Throwable { new AllModulesCommandTest().doTest(); } private void doTest() throws Throwable { launcher = new DebuggeeLauncher(this); launcher.launchDebuggee(); // Await till the debuggee sends all the necessary modules info to check against // then start the JDWP session jdwpLatch.await(); doJdwp(); } @Override public void onDebuggeeModuleInfo(String modName) { // The debuggee has sent out info about a loaded module javaModuleNames.add(modName); } @Override public void onDebuggeeSendingCompleted() { // The debuggee has completed sending all the info // We can start the JDWP session jdwpLatch.countDown(); } @Override public void onDebuggeeError(String message) { System.err.println("Debuggee error: '" + message + "'"); System.exit(1); } private void doJdwp() throws Exception { try { // Establish JDWP socket connection channel = new JdwpChannel(); channel.connect(); // Send out ALLMODULES JDWP command // and verify the reply JdwpAllModulesReply reply = new JdwpAllModulesCmd().send(channel); assertReply(reply); for (int i = 0; i < reply.getModulesCount(); ++i) { long modId = reply.getModuleId(i); // For each module reported by JDWP get its name using the JDWP NAME command // and store the reply String modName = getModuleName(modId); System.out.println("i=" + i + ", modId=" + modId + ", modName=" + modName); if (modName != null) { // JDWP reports unnamed modules, ignore them jdwpModuleNames.add(modName); } // Assert the CLASSLOADER commands assertClassLoader(modId, modName); } System.out.println("Module names reported by JDWP: " + Arrays.toString(jdwpModuleNames.toArray())); System.out.println("Module names reported by Java: " + Arrays.toString(javaModuleNames.toArray())); // Modules reported by the JDWP should be the same as reported by the Java API if (!jdwpModuleNames.equals(javaModuleNames)) { throw new RuntimeException("Modules info reported by Java API differs from that reported by JDWP."); } else { System.out.println("Test passed!"); } } finally { launcher.terminateDebuggee(); try { new JdwpExitCmd(0).send(channel); channel.disconnect(); } catch (Exception x) { } } } private String getModuleName(long modId) throws IOException { JdwpModNameReply reply = new JdwpModNameCmd(modId).send(channel); assertReply(reply); return reply.getModuleName(); } private void assertReply(JdwpReply reply) { // Simple assert for any JDWP reply if (reply.getErrorCode() != 0) { throw new RuntimeException("Unexpected reply error code " + reply.getErrorCode() + " for reply " + reply); } } private void assertClassLoader(long modId, String modName) throws IOException { // Verify that the module classloader id is valid JdwpClassLoaderReply reply = new JdwpClassLoaderCmd(modId).send(channel); assertReply(reply); long moduleClassLoader = reply.getClassLoaderId(); assertTrue(moduleClassLoader >= 0, "bad classloader refId " + moduleClassLoader + " for module '" + modName + "', moduleId=" + modId); String clsModName = getModuleName(modId); if ("java.base".equals(clsModName)) { // For the java.base module, because there will be some loaded classes, we can verify // that some of the loaded classes do report the java.base module as the module they belong to assertGetModule(moduleClassLoader, modId); } } private void assertGetModule(long moduleClassLoader, long modId) throws IOException { // Get all the visible classes for the module classloader JdwpVisibleClassesReply visibleClasses = new JdwpVisibleClassesCmd(moduleClassLoader).send(channel); assertReply(visibleClasses); boolean moduleFound = false; for (long clsId : visibleClasses.getVisibleClasses()) { // For each visible class get the module the class belongs to JdwpModuleReply modReply = new JdwpModuleCmd(clsId).send(channel); assertReply(modReply); long clsModId = modReply.getModuleId(); // At least one of the visible classes should belong to our module if (modId == clsModId) { moduleFound = true; break; } } assertTrue(moduleFound, "None of the visible classes for the classloader of the module " + getModuleName(modId) + " reports the module as its own"); } }