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 48 public static void main(String[] args) throws Throwable { 49 new AllModulesCommandTest().doTest(); 50 } 51 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 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 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 75 public void onDebuggeeError(String message) { 76 System.err.println("Debuggee error: '" + message + "'"); 77 System.exit(1); 78 } 79 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 JDWP CANREAD and CLASSLOADER commands 99 assertCanRead(modId, modName); 100 assertClassLoader(modId, modName); 101 } 102 103 System.out.println("Module names reported by JDWP: " + Arrays.toString(jdwpModuleNames.toArray())); 104 System.out.println("Module names reported by Java: " + Arrays.toString(javaModuleNames.toArray())); 105 106 // Modules reported by the JDWP should be the same as reported by the Java API 107 if (!jdwpModuleNames.equals(javaModuleNames)) { 108 throw new RuntimeException("Modules info reported by Java API differs from that reported by JDWP."); 109 } else { 110 System.out.println("Test passed!"); 111 } 112 113 } finally { 114 launcher.terminateDebuggee(); 115 try { 116 new JdwpExitCmd(0).send(channel); 117 channel.disconnect(); 118 } catch (Exception x) { 119 } 120 } 121 } 122 123 private String getModuleName(long modId) throws IOException { 124 JdwpModNameReply reply = new JdwpModNameCmd(modId).send(channel); 125 assertReply(reply); 126 return reply.getModuleName(); 127 } 128 129 private void assertReply(JdwpReply reply) { 130 // Simple assert for any JDWP reply 131 if (reply.getErrorCode() != 0) { 132 throw new RuntimeException("Unexpected reply error code " + reply.getErrorCode() + " for reply " + reply); 133 } 134 } 135 136 private void assertCanRead(long modId, String modName) throws IOException { 137 // Simple assert for the CANREAD command 138 JdwpCanReadReply reply = new JdwpCanReadCmd(modId, modId).send(channel); 139 assertReply(reply); 140 assertTrue(reply.canRead(), "canRead() reports false for reading from the same module '" + modName + "', moduleId=" + modId); 141 } 142 143 private void assertClassLoader(long modId, String modName) throws IOException { 144 // Verify that the module classloader id is valid 145 JdwpClassLoaderReply reply = new JdwpClassLoaderCmd(modId).send(channel); 146 assertReply(reply); 147 long moduleClassLoader = reply.getClassLoaderId(); 148 assertTrue(moduleClassLoader >= 0, "bad classloader refId " + moduleClassLoader + " for module '" + modName + "', moduleId=" + modId); 149 150 String clsModName = getModuleName(modId); 151 if ("java.base".equals(clsModName)) { 152 // For the java.base module, because there will be some loaded classes, we can verify 153 // that some of the loaded classes do report the java.base module as the module they belong to 154 assertGetModule(moduleClassLoader, modId); 155 } 156 } 157 158 private void assertGetModule(long moduleClassLoader, long modId) throws IOException { 159 // Get all the visible classes for the module classloader 160 JdwpVisibleClassesReply visibleClasses = new JdwpVisibleClassesCmd(moduleClassLoader).send(channel); 161 assertReply(visibleClasses); 162 163 boolean moduleFound = false; 164 for (long clsId : visibleClasses.getVisibleClasses()) { 165 // For each visible class get the module the class belongs to 166 JdwpModuleReply modReply = new JdwpModuleCmd(clsId).send(channel); 167 assertReply(modReply); 168 long clsModId = modReply.getModuleId(); 169 170 // At least one of the visible classes should belong to our module 171 if (modId == clsModId) { 172 moduleFound = true; 173 break; 174 } 175 } 176 assertTrue(moduleFound, "None of the visible classes for the classloader of the module " + getModuleName(modId) + " reports the module as its own"); 177 } 178 179 }