1 /* 2 * Copyright (c) 2016, 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 import java.io.IOException; 25 import java.util.Arrays; 26 import java.util.concurrent.CountDownLatch; 27 import java.util.Set; 28 import java.util.HashSet; 29 import static jdk.test.lib.Asserts.assertTrue; 30 31 /** 32 * @test 33 * @summary Tests the modules-related JDWP commands 34 * @library /test/lib 35 * @modules jdk.jdwp.agent 36 * @modules java.base/jdk.internal.misc 37 * @compile AllModulesCommandTestDebuggee.java 38 * @run main/othervm AllModulesCommandTest 39 */ 40 public class AllModulesCommandTest implements DebuggeeLauncher.Listener { 41 42 private DebuggeeLauncher launcher; 43 private JdwpChannel channel; 44 private CountDownLatch jdwpLatch = new CountDownLatch(1); 45 private Set<String> jdwpModuleNames = new HashSet<>(); 46 private Set<String> javaModuleNames = new HashSet<>(); 47 main(String[] args)48 public static void main(String[] args) throws Throwable { 49 new AllModulesCommandTest().doTest(); 50 } 51 doTest()52 private void doTest() throws Throwable { 53 launcher = new DebuggeeLauncher(this); 54 launcher.launchDebuggee(); 55 // Await till the debuggee sends all the necessary modules info to check against 56 // then start the JDWP session 57 jdwpLatch.await(); 58 doJdwp(); 59 } 60 61 @Override onDebuggeeModuleInfo(String modName)62 public void onDebuggeeModuleInfo(String modName) { 63 // The debuggee has sent out info about a loaded module 64 javaModuleNames.add(modName); 65 } 66 67 @Override onDebuggeeSendingCompleted()68 public void onDebuggeeSendingCompleted() { 69 // The debuggee has completed sending all the info 70 // We can start the JDWP session 71 jdwpLatch.countDown(); 72 } 73 74 @Override onDebuggeeError(String message)75 public void onDebuggeeError(String message) { 76 System.err.println("Debuggee error: '" + message + "'"); 77 System.exit(1); 78 } 79 doJdwp()80 private void doJdwp() throws Exception { 81 try { 82 // Establish JDWP socket connection 83 channel = new JdwpChannel(); 84 channel.connect(); 85 // Send out ALLMODULES JDWP command 86 // and verify the reply 87 JdwpAllModulesReply reply = new JdwpAllModulesCmd().send(channel); 88 assertReply(reply); 89 for (int i = 0; i < reply.getModulesCount(); ++i) { 90 long modId = reply.getModuleId(i); 91 // For each module reported by JDWP get its name using the JDWP NAME command 92 // and store the reply 93 String modName = getModuleName(modId); 94 System.out.println("i=" + i + ", modId=" + modId + ", modName=" + modName); 95 if (modName != null) { // JDWP reports unnamed modules, ignore them 96 jdwpModuleNames.add(modName); 97 } 98 // Assert the CLASSLOADER commands 99 assertClassLoader(modId, modName); 100 } 101 102 System.out.println("Module names reported by JDWP: " + Arrays.toString(jdwpModuleNames.toArray())); 103 System.out.println("Module names reported by Java: " + Arrays.toString(javaModuleNames.toArray())); 104 105 // Modules reported by the JDWP should be the same as reported by the Java API 106 if (!jdwpModuleNames.equals(javaModuleNames)) { 107 throw new RuntimeException("Modules info reported by Java API differs from that reported by JDWP."); 108 } else { 109 System.out.println("Test passed!"); 110 } 111 112 } finally { 113 launcher.terminateDebuggee(); 114 try { 115 new JdwpExitCmd(0).send(channel); 116 channel.disconnect(); 117 } catch (Exception x) { 118 } 119 } 120 } 121 getModuleName(long modId)122 private String getModuleName(long modId) throws IOException { 123 JdwpModNameReply reply = new JdwpModNameCmd(modId).send(channel); 124 assertReply(reply); 125 return reply.getModuleName(); 126 } 127 assertReply(JdwpReply reply)128 private void assertReply(JdwpReply reply) { 129 // Simple assert for any JDWP reply 130 if (reply.getErrorCode() != 0) { 131 throw new RuntimeException("Unexpected reply error code " + reply.getErrorCode() + " for reply " + reply); 132 } 133 } 134 assertClassLoader(long modId, String modName)135 private void assertClassLoader(long modId, String modName) throws IOException { 136 // Verify that the module classloader id is valid 137 JdwpClassLoaderReply reply = new JdwpClassLoaderCmd(modId).send(channel); 138 assertReply(reply); 139 long moduleClassLoader = reply.getClassLoaderId(); 140 assertTrue(moduleClassLoader >= 0, "bad classloader refId " + moduleClassLoader + " for module '" + modName + "', moduleId=" + modId); 141 142 String clsModName = getModuleName(modId); 143 if ("java.base".equals(clsModName)) { 144 // For the java.base module, because there will be some loaded classes, we can verify 145 // that some of the loaded classes do report the java.base module as the module they belong to 146 assertGetModule(moduleClassLoader, modId); 147 } 148 } 149 assertGetModule(long moduleClassLoader, long modId)150 private void assertGetModule(long moduleClassLoader, long modId) throws IOException { 151 // Get all the visible classes for the module classloader 152 JdwpVisibleClassesReply visibleClasses = new JdwpVisibleClassesCmd(moduleClassLoader).send(channel); 153 assertReply(visibleClasses); 154 155 boolean moduleFound = false; 156 for (long clsId : visibleClasses.getVisibleClasses()) { 157 // For each visible class get the module the class belongs to 158 JdwpModuleReply modReply = new JdwpModuleCmd(clsId).send(channel); 159 assertReply(modReply); 160 long clsModId = modReply.getModuleId(); 161 162 // At least one of the visible classes should belong to our module 163 if (modId == clsModId) { 164 moduleFound = true; 165 break; 166 } 167 } 168 assertTrue(moduleFound, "None of the visible classes for the classloader of the module " + getModuleName(modId) + " reports the module as its own"); 169 } 170 171 } 172