1 /* 2 * Copyright (c) 2018, 2019, 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 /** 25 * @test 26 * @bug 8174994 8200613 27 * @summary Test the clhsdb commands 'printmdo', 'printall', 'jstack' on a CDS enabled corefile. 28 * @requires vm.cds 29 * @requires vm.hasSA 30 * @requires os.family != "windows" 31 * @requires vm.flavor == "server" 32 * @library /test/lib 33 * @modules java.base/jdk.internal.misc 34 * @run main/othervm/timeout=2400 -Xmx1g ClhsdbCDSCore 35 */ 36 37 import java.io.File; 38 import java.io.IOException; 39 import java.nio.file.Files; 40 import java.nio.file.Path; 41 import java.nio.file.Paths; 42 import java.util.ArrayList; 43 import java.util.Arrays; 44 import java.util.HashMap; 45 import java.util.List; 46 import java.util.Map; 47 import java.util.Scanner; 48 import java.util.regex.Matcher; 49 import java.util.regex.Pattern; 50 51 import jdk.internal.misc.Unsafe; 52 53 import jdk.test.lib.Asserts; 54 import jdk.test.lib.Platform; 55 import jdk.test.lib.cds.CDSOptions; 56 import jdk.test.lib.cds.CDSTestUtils; 57 import jdk.test.lib.process.OutputAnalyzer; 58 import jdk.test.lib.process.ProcessTools; 59 import jdk.test.lib.SA.SATestUtils; 60 61 import jtreg.SkippedException; 62 63 class CrashApp { 64 public static void main(String[] args) { 65 Unsafe.getUnsafe().putInt(0L, 0); 66 } 67 } 68 69 public class ClhsdbCDSCore { 70 71 private static final String TEST_CDS_CORE_FILE_NAME = "cds_core_file"; 72 private static final String LOCATIONS_STRING = "location: "; 73 private static final String RUN_SHELL_NO_LIMIT = "ulimit -c unlimited && "; 74 private static final String SHARED_ARCHIVE_NAME = "ArchiveForClhsdbCDSCore.jsa"; 75 private static final String CORE_PATTERN_FILE_NAME = "/proc/sys/kernel/core_pattern"; 76 77 public static void main(String[] args) throws Exception { 78 System.out.println("Starting ClhsdbCDSCore test"); 79 cleanup(); 80 81 try { 82 CDSOptions opts = (new CDSOptions()).setArchiveName(SHARED_ARCHIVE_NAME); 83 CDSTestUtils.createArchiveAndCheck(opts); 84 85 String[] jArgs = { 86 "-Xmx512m", 87 "-XX:+UnlockDiagnosticVMOptions", 88 "-XX:SharedArchiveFile=" + SHARED_ARCHIVE_NAME, 89 "-XX:+CreateCoredumpOnCrash", 90 "-Xshare:auto", 91 "-XX:+ProfileInterpreter", 92 "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED", 93 CrashApp.class.getName() 94 }; 95 96 OutputAnalyzer crashOut; 97 try { 98 List<String> options = new ArrayList<>(); 99 options.addAll(Arrays.asList(jArgs)); 100 crashOut = 101 ProcessTools.executeProcess(getTestJavaCommandlineWithPrefix( 102 RUN_SHELL_NO_LIMIT, options.toArray(new String[0]))); 103 } catch (Throwable t) { 104 throw new Error("Can't execute the java cds process.", t); 105 } 106 107 System.out.println(crashOut.getOutput()); 108 String crashOutputString = crashOut.getOutput(); 109 SATestUtils.unzipCores(new File(".")); 110 String coreFileLocation = getCoreFileLocation(crashOutputString); 111 if (coreFileLocation == null) { 112 if (Platform.isOSX()) { 113 File coresDir = new File("/cores"); 114 if (!coresDir.isDirectory()) { 115 throw new Error("cores is not a directory"); 116 } 117 // the /cores directory is usually not writable on macOS 10.15 118 final String osVersion = System.getProperty("os.version"); 119 if (osVersion == null) { 120 throw new Error("Cannot query the 'os.version' property!"); 121 } 122 if (!coresDir.canWrite()) { 123 if (osVersion.startsWith("10.15")) { 124 throw new SkippedException("/cores is not writable"); 125 } else { 126 throw new Error("cores does not have write permissions"); 127 } 128 } 129 } else if (Platform.isLinux()) { 130 // Check if a crash report tool is installed. 131 File corePatternFile = new File(CORE_PATTERN_FILE_NAME); 132 Scanner scanner = new Scanner(corePatternFile); 133 while (scanner.hasNextLine()) { 134 String line = scanner.nextLine(); 135 line = line.trim(); 136 System.out.println(line); 137 if (line.startsWith("|")) { 138 System.out.println( 139 "\nThis system uses a crash report tool ($cat /proc/sys/kernel/core_pattern).\n" + 140 "Core files might not be generated. Please reset /proc/sys/kernel/core_pattern\n" + 141 "to enable core generation. Skipping this test."); 142 cleanup(); 143 throw new SkippedException("This system uses a crash report tool"); 144 } 145 } 146 } 147 throw new Error("Couldn't find core file location in: '" + crashOutputString + "'"); 148 } 149 try { 150 Asserts.assertGT(new File(coreFileLocation).length(), 0L, "Unexpected core size"); 151 Files.move(Paths.get(coreFileLocation), Paths.get(TEST_CDS_CORE_FILE_NAME)); 152 } catch (IOException ioe) { 153 throw new Error("Can't move core file: " + ioe, ioe); 154 } 155 156 ClhsdbLauncher test = new ClhsdbLauncher(); 157 158 // Ensure that UseSharedSpaces is turned on. 159 List<String> cmds = List.of("flags UseSharedSpaces"); 160 161 String useSharedSpacesOutput = test.runOnCore(TEST_CDS_CORE_FILE_NAME, cmds, 162 null, null); 163 164 if (useSharedSpacesOutput == null) { 165 // Output could be null due to attach permission issues. 166 cleanup(); 167 throw new SkippedException("Could not determine the UseSharedSpaces value"); 168 } 169 170 if (!useSharedSpacesOutput.contains("true")) { 171 // CDS archive is not mapped. Skip the rest of the test. 172 cleanup(); 173 throw new SkippedException("The CDS archive is not mapped"); 174 } 175 176 cmds = List.of("printmdo -a", "printall", "jstack -v"); 177 178 Map<String, List<String>> expStrMap = new HashMap<>(); 179 Map<String, List<String>> unExpStrMap = new HashMap<>(); 180 expStrMap.put("printmdo -a", List.of( 181 "CounterData", 182 "BranchData")); 183 unExpStrMap.put("printmdo -a", List.of( 184 "No suitable match for type of address")); 185 expStrMap.put("printall", List.of( 186 "aload_0", 187 "_nofast_aload_0", 188 "_nofast_getfield", 189 "_nofast_putfield", 190 "Constant Pool of", 191 "public static void main\\(java.lang.String\\[\\]\\)", 192 "Bytecode", 193 "invokevirtual", 194 "checkcast", 195 "Exception Table", 196 "invokedynamic")); 197 unExpStrMap.put("printall", List.of( 198 "sun.jvm.hotspot.types.WrongTypeException", 199 "illegal code", 200 "Failure occurred at bci", 201 "No suitable match for type of address")); 202 expStrMap.put("jstack -v", List.of( 203 "Common-Cleaner", 204 "Method*")); 205 unExpStrMap.put("jstack -v", List.of( 206 "sun.jvm.hotspot.debugger.UnmappedAddressException")); 207 test.runOnCore(TEST_CDS_CORE_FILE_NAME, cmds, expStrMap, unExpStrMap); 208 } catch (SkippedException e) { 209 throw e; 210 } catch (Exception ex) { 211 throw new RuntimeException("Test ERROR " + ex, ex); 212 } 213 cleanup(); 214 System.out.println("Test PASSED"); 215 } 216 217 // lets search for a few possible locations using process output and return existing location 218 private static String getCoreFileLocation(String crashOutputString) { 219 Asserts.assertTrue(crashOutputString.contains(LOCATIONS_STRING), 220 "Output doesn't contain the location of core file."); 221 String stringWithLocation = Arrays.stream(crashOutputString.split("\\r?\\n")) 222 .filter(str -> str.contains(LOCATIONS_STRING)) 223 .findFirst() 224 .get(); 225 stringWithLocation = stringWithLocation.substring(stringWithLocation 226 .indexOf(LOCATIONS_STRING) + LOCATIONS_STRING.length()); 227 System.out.println("getCoreFileLocation found stringWithLocation = " + stringWithLocation); 228 String coreWithPid; 229 if (stringWithLocation.contains("or ")) { 230 Matcher m = Pattern.compile("or.* ([^ ]+[^\\)])\\)?").matcher(stringWithLocation); 231 if (!m.find()) { 232 throw new Error("Couldn't find path to core inside location string"); 233 } 234 coreWithPid = m.group(1); 235 } else { 236 coreWithPid = stringWithLocation.trim(); 237 } 238 if (new File(coreWithPid).exists()) { 239 return coreWithPid; 240 } 241 String justCore = Paths.get("core").toString(); 242 if (new File(justCore).exists()) { 243 return justCore; 244 } 245 Path coreWithPidPath = Paths.get(coreWithPid); 246 String justFile = coreWithPidPath.getFileName().toString(); 247 if (new File(justFile).exists()) { 248 return justFile; 249 } 250 Path parent = coreWithPidPath.getParent(); 251 if (parent != null) { 252 String coreWithoutPid = parent.resolve("core").toString(); 253 if (new File(coreWithoutPid).exists()) { 254 return coreWithoutPid; 255 } 256 } 257 return null; 258 } 259 260 private static String[] getTestJavaCommandlineWithPrefix(String prefix, String... args) { 261 try { 262 String cmd = ProcessTools.getCommandLine(ProcessTools.createJavaProcessBuilder(true, args)); 263 return new String[]{"sh", "-c", prefix + cmd}; 264 } catch (Throwable t) { 265 throw new Error("Can't create process builder: " + t, t); 266 } 267 } 268 269 private static void cleanup() { 270 remove(TEST_CDS_CORE_FILE_NAME); 271 remove(SHARED_ARCHIVE_NAME); 272 } 273 274 private static void remove(String item) { 275 File toDelete = new File(item); 276 toDelete.delete(); 277 } 278 }