changeset 60082:983733bfb7ce

8248194: Need better support for running SA tests on core files Reviewed-by: amenkov, lmesnik
author cjplummer
date Tue, 07 Jul 2020 13:07:53 -0700
parents c4da87b3630c
children dfdd5131f6bd
files test/hotspot/jtreg/serviceability/sa/ClhsdbCDSCore.java test/hotspot/jtreg/serviceability/sa/ClhsdbFindPC.java test/hotspot/jtreg/serviceability/sa/TestJmapCore.java test/lib/jdk/test/lib/SA/SATestUtils.java test/lib/jdk/test/lib/apps/LingeredApp.java test/lib/jdk/test/lib/apps/libLingeredApp.c test/lib/jdk/test/lib/util/CoreUtils.java
diffstat 7 files changed, 365 insertions(+), 203 deletions(-) [+]
line wrap: on
line diff
--- a/test/hotspot/jtreg/serviceability/sa/ClhsdbCDSCore.java	Tue Jul 07 10:27:47 2020 -0700
+++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbCDSCore.java	Tue Jul 07 13:07:53 2020 -0700
@@ -27,7 +27,6 @@
  * @summary Test the clhsdb commands 'printmdo', 'printall', 'jstack' on a CDS enabled corefile.
  * @requires vm.cds
  * @requires vm.hasSA
- * @requires os.family != "windows"
  * @requires vm.flavor == "server"
  * @library /test/lib
  * @modules java.base/jdk.internal.misc
@@ -37,16 +36,12 @@
 import java.io.File;
 import java.io.IOException;
 import java.nio.file.Files;
-import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Scanner;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 import jdk.internal.misc.Unsafe;
 
@@ -56,7 +51,7 @@
 import jdk.test.lib.cds.CDSTestUtils;
 import jdk.test.lib.process.OutputAnalyzer;
 import jdk.test.lib.process.ProcessTools;
-import jdk.test.lib.SA.SATestUtils;
+import jdk.test.lib.util.CoreUtils;
 
 import jtreg.SkippedException;
 
@@ -67,12 +62,8 @@
 }
 
 public class ClhsdbCDSCore {
-
-    private static final String TEST_CDS_CORE_FILE_NAME = "cds_core_file";
-    private static final String LOCATIONS_STRING = "location: ";
-    private static final String RUN_SHELL_NO_LIMIT = "ulimit -c unlimited && ";
     private static final String SHARED_ARCHIVE_NAME = "ArchiveForClhsdbCDSCore.jsa";
-    private static final String CORE_PATTERN_FILE_NAME = "/proc/sys/kernel/core_pattern";
+    private static String coreFileName;
 
     public static void main(String[] args) throws Exception {
         System.out.println("Starting ClhsdbCDSCore test");
@@ -93,60 +84,23 @@
                 CrashApp.class.getName()
             };
 
-            OutputAnalyzer crashOut;
+            OutputAnalyzer crashOutput;
             try {
                List<String> options = new ArrayList<>();
                options.addAll(Arrays.asList(jArgs));
-               crashOut =
-                   ProcessTools.executeProcess(getTestJvmCommandlineWithPrefix(
-                   RUN_SHELL_NO_LIMIT, options.toArray(new String[0])));
+               ProcessBuilder pb = ProcessTools.createTestJvm(options);
+               // Add "ulimit -c unlimited" if we can since we are generating a core file.
+               pb = CoreUtils.addCoreUlimitCommand(pb);
+               crashOutput = ProcessTools.executeProcess(pb);
             } catch (Throwable t) {
                throw new Error("Can't execute the java cds process.", t);
             }
 
-            System.out.println(crashOut.getOutput());
-            String crashOutputString = crashOut.getOutput();
-            SATestUtils.unzipCores(new File("."));
-            String coreFileLocation = getCoreFileLocation(crashOutputString);
-            if (coreFileLocation == null) {
-                if (Platform.isOSX()) {
-                    File coresDir = new File("/cores");
-                    if (!coresDir.isDirectory()) {
-                        cleanup();
-                        throw new Error(coresDir + " is not a directory");
-                    }
-                    // the /cores directory is usually not writable on macOS 10.15
-                    if (!coresDir.canWrite()) {
-                        cleanup();
-                        throw new SkippedException("Directory \"" + coresDir +
-                            "\" is not writable");
-                    }
-                } else if (Platform.isLinux()) {
-                    // Check if a crash report tool is installed.
-                    File corePatternFile = new File(CORE_PATTERN_FILE_NAME);
-                    try (Scanner scanner = new Scanner(corePatternFile)) {
-                        while (scanner.hasNextLine()) {
-                            String line = scanner.nextLine();
-                            line = line.trim();
-                            System.out.println(line);
-                            if (line.startsWith("|")) {
-                                System.out.println(
-                                    "\nThis system uses a crash report tool ($cat /proc/sys/kernel/core_pattern).\n" +
-                                    "Core files might not be generated. Please reset /proc/sys/kernel/core_pattern\n" +
-                                    "to enable core generation. Skipping this test.");
-                                cleanup();
-                                throw new SkippedException("This system uses a crash report tool");
-                            }
-                        }
-                    }
-                }
-                throw new Error("Couldn't find core file location in: '" + crashOutputString + "'");
-            }
             try {
-                Asserts.assertGT(new File(coreFileLocation).length(), 0L, "Unexpected core size");
-                Files.move(Paths.get(coreFileLocation), Paths.get(TEST_CDS_CORE_FILE_NAME));
-            } catch (IOException ioe) {
-                throw new Error("Can't move core file: " + ioe, ioe);
+                coreFileName = CoreUtils.getCoreFileLocation(crashOutput.getStdout());
+            } catch (Exception e) {
+                cleanup();
+                throw e;
             }
 
             ClhsdbLauncher test = new ClhsdbLauncher();
@@ -154,8 +108,7 @@
             // Ensure that UseSharedSpaces is turned on.
             List<String> cmds = List.of("flags UseSharedSpaces");
 
-            String useSharedSpacesOutput = test.runOnCore(TEST_CDS_CORE_FILE_NAME, cmds,
-                                                          null, null);
+            String useSharedSpacesOutput = test.runOnCore(coreFileName, cmds, null, null);
 
             if (useSharedSpacesOutput == null) {
                 // Output could be null due to attach permission issues.
@@ -200,7 +153,7 @@
                 "Method*"));
             unExpStrMap.put("jstack -v", List.of(
                 "sun.jvm.hotspot.debugger.UnmappedAddressException"));
-            test.runOnCore(TEST_CDS_CORE_FILE_NAME, cmds, expStrMap, unExpStrMap);
+            test.runOnCore(coreFileName, cmds, expStrMap, unExpStrMap);
         } catch (SkippedException e) {
             throw e;
         } catch (Exception ex) {
@@ -210,60 +163,8 @@
         System.out.println("Test PASSED");
     }
 
-    // lets search for a few possible locations using process output and return existing location
-    private static String getCoreFileLocation(String crashOutputString) {
-        Asserts.assertTrue(crashOutputString.contains(LOCATIONS_STRING),
-            "Output doesn't contain the location of core file.");
-        String stringWithLocation = Arrays.stream(crashOutputString.split("\\r?\\n"))
-            .filter(str -> str.contains(LOCATIONS_STRING))
-            .findFirst()
-            .get();
-        stringWithLocation = stringWithLocation.substring(stringWithLocation
-            .indexOf(LOCATIONS_STRING) + LOCATIONS_STRING.length());
-        System.out.println("getCoreFileLocation found stringWithLocation = " + stringWithLocation);
-        String coreWithPid;
-        if (stringWithLocation.contains("or ")) {
-            Matcher m = Pattern.compile("or.* ([^ ]+[^\\)])\\)?").matcher(stringWithLocation);
-            if (!m.find()) {
-                throw new Error("Couldn't find path to core inside location string");
-            }
-            coreWithPid = m.group(1);
-        } else {
-            coreWithPid = stringWithLocation.trim();
-        }
-        if (new File(coreWithPid).exists()) {
-            return coreWithPid;
-        }
-        String justCore = Paths.get("core").toString();
-        if (new File(justCore).exists()) {
-            return justCore;
-        }
-        Path coreWithPidPath = Paths.get(coreWithPid);
-        String justFile = coreWithPidPath.getFileName().toString();
-        if (new File(justFile).exists()) {
-            return justFile;
-        }
-        Path parent = coreWithPidPath.getParent();
-        if (parent != null) {
-            String coreWithoutPid = parent.resolve("core").toString();
-            if (new File(coreWithoutPid).exists()) {
-                return coreWithoutPid;
-            }
-        }
-        return null;
-    }
-
-    private static String[] getTestJvmCommandlineWithPrefix(String prefix, String... args) {
-        try {
-            String cmd = ProcessTools.getCommandLine(ProcessTools.createTestJvm(args));
-            return new String[]{"sh", "-c", prefix + cmd};
-        } catch (Throwable t) {
-            throw new Error("Can't create process builder: " + t, t);
-        }
-    }
-
     private static void cleanup() {
-        remove(TEST_CDS_CORE_FILE_NAME);
+        if (coreFileName != null) remove(coreFileName);
         remove(SHARED_ARCHIVE_NAME);
     }
 
--- a/test/hotspot/jtreg/serviceability/sa/ClhsdbFindPC.java	Tue Jul 07 10:27:47 2020 -0700
+++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbFindPC.java	Tue Jul 07 13:07:53 2020 -0700
@@ -27,38 +27,63 @@
 import java.util.ArrayList;
 
 import jdk.test.lib.apps.LingeredApp;
+import jdk.test.lib.util.CoreUtils;
 import jtreg.SkippedException;
 
 /**
  * @test
  * @bug 8193124
- * @summary Test the clhsdb 'findpc' command
+ * @summary Test the clhsdb 'findpc' command with Xcomp on live process
  * @requires vm.hasSA
  * @requires vm.compiler1.enabled
  * @requires vm.opt.DeoptimizeALot != true
  * @library /test/lib
- * @run main/othervm/timeout=480 ClhsdbFindPC true
+ * @run main/othervm/timeout=480 ClhsdbFindPC true false
+ */
+
+/**
+ * @test
+ * @bug 8193124
+ * @summary Test the clhsdb 'findpc' command with Xcomp on core file
+ * @requires vm.compMode != "Xcomp"
+ * @requires vm.hasSA
+ * @requires vm.compiler1.enabled
+ * @library /test/lib
+ * @run main/othervm/timeout=480 ClhsdbFindPC true true
  */
 
 /**
  * @test
  * @bug 8193124
- * @summary Test the clhsdb 'findpc' command
+ * @summary Test the clhsdb 'findpc' command w/o Xcomp on live process
+ * @requires vm.hasSA
+ * @requires vm.compiler1.enabled
+ * @requires vm.opt.DeoptimizeALot != true
+ * @library /test/lib
+ * @run main/othervm/timeout=480 ClhsdbFindPC false false
+ */
+
+/**
+ * @test
+ * @bug 8193124
+ * @summary Test the clhsdb 'findpc' command w/o Xcomp on core file
  * @requires vm.compMode != "Xcomp"
  * @requires vm.hasSA
  * @requires vm.compiler1.enabled
  * @library /test/lib
- * @run main/othervm/timeout=480 ClhsdbFindPC false
+ * @run main/othervm/timeout=480 ClhsdbFindPC false true
  */
 
 public class ClhsdbFindPC {
 
-    private static void testFindPC(boolean withXcomp) throws Exception {
+    private static void testFindPC(boolean withXcomp, boolean withCore) throws Exception {
         LingeredApp theApp = null;
+        String coreFileName = null;
         try {
             ClhsdbLauncher test = new ClhsdbLauncher();
 
             theApp = new LingeredAppWithTrivialMain();
+            theApp.setForceCrash(withCore);
             if (withXcomp) {
                 LingeredApp.startApp(theApp, "-Xcomp");
             } else {
@@ -72,27 +97,41 @@
             }
             System.out.println("with pid " + theApp.getPid());
 
-            // Run 'jstack -v' command to get the pc
-            List<String> cmds = List.of("jstack -v");
-            String output = test.run(theApp.getPid(), cmds, null, null);
+            // Get the core file name if we are debugging a core instead of live process
+            if (withCore) {
+                coreFileName = CoreUtils.getCoreFileLocation(theApp.getOutput().getStdout());
+            }
 
-            // Test the 'findpc' command passing in the pc obtained from
-            // the 'jstack -v' command
-            cmds = new ArrayList<String>();
+            // Run 'jstack -v' command to get the findpc address
+            List<String> cmds = List.of("jstack -v");
+            String output;
+            if (withCore) {
+                output = test.runOnCore(coreFileName, cmds, null, null);
+            } else {
+                output = test.run(theApp.getPid(), cmds, null, null);
+            }
 
-            String cmdStr = null;
+            // Extract pc address from the following line:
+            //   - LingeredAppWithTrivialMain.main(java.lang.String[]) @bci=1, line=33, pc=0x00007ff18ff519f0, ...
+            String pcAddress = null;
             String[] parts = output.split("LingeredAppWithTrivialMain.main");
             String[] tokens = parts[1].split(" ");
             for (String token : tokens) {
                 if (token.contains("pc")) {
-                    String[] address = token.split("=");
-                    // address[1] represents the address of the Method
-                    cmdStr = "findpc " + address[1].replace(",","");
-                    cmds.add(cmdStr);
+                    String[] addresses = token.split("=");
+                    // addresses[1] represents the address of the Method
+                    pcAddress = addresses[1].replace(",","");
                     break;
                 }
             }
+            if (pcAddress == null) {
+                throw new RuntimeException("Cannot find LingeredAppWithTrivialMain.main pc in output");
+            }
 
+            // Test the 'findpc' command passing in the pc obtained from above
+            cmds = new ArrayList<String>();
+            String cmdStr = "findpc " + pcAddress;
+            cmds.add(cmdStr);
             Map<String, List<String>> expStrMap = new HashMap<>();
             if (withXcomp) {
                 expStrMap.put(cmdStr, List.of(
@@ -105,20 +144,27 @@
                             "In interpreter codelet"));
             }
 
-            test.run(theApp.getPid(), cmds, expStrMap, null);
+            if (withCore) {
+                test.runOnCore(coreFileName, cmds, expStrMap, null);
+            } else {
+                test.run(theApp.getPid(), cmds, expStrMap, null);
+            }
         } catch (SkippedException se) {
             throw se;
         } catch (Exception ex) {
             throw new RuntimeException("Test ERROR " + ex, ex);
         } finally {
-            LingeredApp.stopApp(theApp);
+            if (!withCore) {
+                LingeredApp.stopApp(theApp);
+            }
         }
     }
 
     public static void main(String[] args) throws Exception {
-        boolean xComp = Boolean.parseBoolean(args[0]);
+        boolean withXcomp = Boolean.parseBoolean(args[0]);
+        boolean withCore = Boolean.parseBoolean(args[1]);
         System.out.println("Starting the ClhsdbFindPC test");
-        testFindPC(xComp);
+        testFindPC(withXcomp, withCore);
         System.out.println("Test PASSED");
     }
 }
--- a/test/hotspot/jtreg/serviceability/sa/TestJmapCore.java	Tue Jul 07 10:27:47 2020 -0700
+++ b/test/hotspot/jtreg/serviceability/sa/TestJmapCore.java	Tue Jul 07 13:07:53 2020 -0700
@@ -40,20 +40,16 @@
 import jdk.test.lib.hprof.HprofParser;
 import jdk.test.lib.process.ProcessTools;
 import jdk.test.lib.process.OutputAnalyzer;
-import jdk.test.lib.SA.SATestUtils;
+import jdk.test.lib.util.CoreUtils;
 import jtreg.SkippedException;
 
 public class TestJmapCore {
-    static final String pidSeparator = ":KILLED_PID";
-
     public static final String HEAP_OOME = "heap";
     public static final String METASPACE_OOME = "metaspace";
 
 
     public static void main(String[] args) throws Throwable {
         if (args.length == 1) {
-            // If 1 argument is set prints pid so main process could find corefile
-            System.out.println(ProcessHandle.current().pid() + pidSeparator);
             try {
                 if (args[0].equals(HEAP_OOME)) {
                     Object[] oa = new Object[Integer.MAX_VALUE / 2];
@@ -74,50 +70,17 @@
         test(args[1]);
     }
 
-    // Test tries to run java with ulimit unlimited if it is possible
-    static boolean useDefaultUlimit() {
-        if (Platform.isWindows()) {
-            return true;
-        }
-        try {
-            OutputAnalyzer output = ProcessTools.executeProcess("sh", "-c", "ulimit -c unlimited && ulimit -c");
-            return !(output.getExitValue() == 0 && output.getStdout().contains("unlimited"));
-        } catch (Throwable t) {
-            return true;
-        }
-    }
-
     static void test(String type) throws Throwable {
         ProcessBuilder pb = ProcessTools.createTestJvm("-XX:+CreateCoredumpOnCrash",
                 "-Xmx512m", "-XX:MaxMetaspaceSize=64m", "-XX:+CrashOnOutOfMemoryError",
                 TestJmapCore.class.getName(), type);
 
-        boolean useDefaultUlimit = useDefaultUlimit();
-        System.out.println("Run test with ulimit: " + (useDefaultUlimit ? "default" : "unlimited"));
-        OutputAnalyzer output = useDefaultUlimit
-            ? ProcessTools.executeProcess(pb)
-            : ProcessTools.executeProcess("sh", "-c", "ulimit -c unlimited && "
-                    + ProcessTools.getCommandLine(pb));
-        File pwd = new File(".");
-        SATestUtils.unzipCores(pwd);
-        File core;
-        String pattern = Platform.isWindows() ? ".*\\.mdmp" : "core(\\.\\d+)?";
-        File[] cores = pwd.listFiles((dir, name) -> name.matches(pattern));
-        if (cores.length == 0) {
-            // /cores/core.$pid might be generated on macosx by default
-            String pid = output.firstMatch("^(\\d+)" + pidSeparator, 1);
-            core = new File("cores/core." + pid);
-            if (!core.exists()) {
-                throw new SkippedException("Has not been able to find coredump");
-            }
-        } else {
-            Asserts.assertTrue(cores.length == 1,
-                    "There are unexpected files containing core "
-                    + ": " + String.join(",", pwd.list()) + ".");
-            core = cores[0];
-        }
-        System.out.println("Found corefile: " + core.getAbsolutePath());
+        // If we are going to force a core dump, apply "ulimit -c unlimited" if we can.
+        pb = CoreUtils.addCoreUlimitCommand(pb);
+        OutputAnalyzer output =  ProcessTools.executeProcess(pb);
 
+        String coreFileName = CoreUtils.getCoreFileLocation(output.getStdout());
+        File core = new File(coreFileName);
         File dumpFile = new File("heap.hprof");
         JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jhsdb");
         launcher.addVMArgs(Utils.getTestJavaOpts());
--- a/test/lib/jdk/test/lib/SA/SATestUtils.java	Tue Jul 07 10:27:47 2020 -0700
+++ b/test/lib/jdk/test/lib/SA/SATestUtils.java	Tue Jul 07 13:07:53 2020 -0700
@@ -26,7 +26,6 @@
 import jdk.test.lib.Platform;
 import jtreg.SkippedException;
 
-import java.io.File;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Paths;
@@ -35,9 +34,8 @@
 import java.security.PrivilegedExceptionAction;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
 import java.util.List;
-import java.util.concurrent.TimeUnit;
-import java.util.zip.GZIPInputStream;
 
 public class SATestUtils {
     /**
@@ -209,17 +207,4 @@
         // Otherwise expect to be permitted:
         return true;
     }
-
-    public static void unzipCores(File dir) {
-        File[] gzCores = dir.listFiles((directory, name) -> name.matches("core(\\.\\d+)?\\.gz"));
-        for (File gzCore : gzCores) {
-            String coreFileName = gzCore.getName().replace(".gz", "");
-            System.out.println("Unzipping core into " + coreFileName);
-            try (GZIPInputStream gzis = new GZIPInputStream(Files.newInputStream(gzCore.toPath()))) {
-                Files.copy(gzis, Paths.get(coreFileName));
-            } catch (IOException e) {
-                throw new SkippedException("Not able to unzip file: " + gzCore.getAbsolutePath(), e);
-            }
-        }
-    }
 }
--- a/test/lib/jdk/test/lib/apps/LingeredApp.java	Tue Jul 07 10:27:47 2020 -0700
+++ b/test/lib/jdk/test/lib/apps/LingeredApp.java	Tue Jul 07 13:07:53 2020 -0700
@@ -44,6 +44,7 @@
 import jdk.test.lib.Utils;
 import jdk.test.lib.process.OutputBuffer;
 import jdk.test.lib.process.StreamPumper;
+import jdk.test.lib.util.CoreUtils;
 
 /**
  * This is a framework to launch an app that could be synchronized with caller
@@ -93,6 +94,8 @@
     protected static final int appWaitTime = 100;
     protected final String lockFileName;
 
+    protected boolean forceCrash = false; // set true to force a crash and core file
+
     /**
      * Create LingeredApp object on caller side. Lock file have be a valid filename
      * at writable location
@@ -108,6 +111,12 @@
         this.lockFileName = lockName;
     }
 
+    public void setForceCrash(boolean forceCrash) {
+        this.forceCrash = forceCrash;
+    }
+
+    native private static int crash();
+
     /**
      *
      * @return name of lock file
@@ -263,7 +272,11 @@
 
             // Make sure process didn't already exit
             if (!appProcess.isAlive()) {
-                throw new IOException("App exited unexpectedly with " + appProcess.exitValue());
+                if (forceCrash) {
+                    return; // This is expected. Just return.
+                } else {
+                    throw new IOException("App exited unexpectedly with " + appProcess.exitValue());
+                }
             }
 
             try {
@@ -289,6 +302,11 @@
         List<String> cmd = new ArrayList<>();
         cmd.add(JDKToolFinder.getTestJDKTool("java"));
         Collections.addAll(cmd, vmArguments);
+        if (forceCrash) {
+            cmd.add("-XX:+CreateCoredumpOnCrash");
+            // We need to find libLingeredApp.so for the crash() native method
+            cmd.add("-Djava.library.path=" + System.getProperty("java.library.path"));
+        }
 
         // Make sure we set correct classpath to run the app
         cmd.add("-cp");
@@ -329,10 +347,17 @@
 
         runAddAppName(cmd);
         cmd.add(lockFileName);
+        if (forceCrash) {
+            cmd.add("forceCrash"); // Let the subprocess know to force a crash
+        }
 
         printCommandLine(cmd);
 
         ProcessBuilder pb = new ProcessBuilder(cmd);
+        if (forceCrash) {
+            // If we are going to force a core dump, apply "ulimit -c unlimited" if we can.
+            pb = CoreUtils.addCoreUlimitCommand(pb);
+        }
         // ProcessBuilder.start can throw IOException
         appProcess = pb.start();
 
@@ -470,19 +495,37 @@
     }
 
     /**
-     * This part is the application it self
+     * This part is the application itself. First arg is optional "forceCrash".
+     * Following arg is the lock file name.
      */
     public static void main(String args[]) {
+        boolean forceCrash = false;
 
-        if (args.length != 1) {
+        if (args.length == 0) {
             System.err.println("Lock file name is not specified");
             System.exit(7);
+        } else if (args.length > 2) {
+            System.err.println("Too many arguments specified: "  + args.length);
+            System.exit(7);
+        }
+
+        if (args.length == 2) {
+            if (args[1].equals("forceCrash")) {
+                forceCrash = true;
+            } else {
+                System.err.println("Invalid 1st argment: " + args[1]);
+                System.exit(7);
+            }
         }
 
         String theLockFileName = args[0];
         Path path = Paths.get(theLockFileName);
 
         try {
+            if (forceCrash) {
+                System.loadLibrary("LingeredApp"); // location of native crash() method
+                crash();
+            }
             while (Files.exists(path)) {
                 // Touch the lock to indicate our readiness
                 setLastModified(theLockFileName, epoch());
--- a/test/lib/jdk/test/lib/apps/libLingeredApp.c	Tue Jul 07 10:27:47 2020 -0700
+++ b/test/lib/jdk/test/lib/apps/libLingeredApp.c	Tue Jul 07 13:07:53 2020 -0700
@@ -23,12 +23,20 @@
 
 #include <jni.h>
 
-/*
- * Class:     jdk_test_lib_apps_LingeredApp
- * Method:    crashMe
- * Signature: ()V
- */
-JNIEXPORT void JNICALL
-Java_jdk_test_lib_apps_LingeredApp_crashMe(JNIEnv *env, jclass klass) {
-  *((volatile int*)(1)) = 1;
+// Borrowed from hotspot vmError.cpp.
+// Returns an address which is guaranteed to generate a SIGSEGV on read,
+// which is not NULL and contains bits in every word
+void* get_segfault_address() {
+  return (void*)
+#ifdef _LP64
+    0xABC0000000000ABCULL;
+#else
+    0x00000ABC;
+#endif
 }
+
+JNIEXPORT jint JNICALL
+Java_jdk_test_lib_apps_LingeredApp_crash(JNIEnv *env, jclass clss)
+{
+    return *(jint *)get_segfault_address();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/util/CoreUtils.java	Tue Jul 07 13:07:53 2020 -0700
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2020, 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.
+ */
+
+package jdk.test.lib.util;
+
+import jdk.test.lib.Asserts;
+import jdk.test.lib.Platform;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+import jtreg.SkippedException;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.Scanner;
+import java.util.zip.GZIPInputStream;
+
+public class CoreUtils {
+
+    private static final String RUN_SHELL_NO_LIMIT = "ulimit -c unlimited && ";
+
+    /**
+     * Returns a {@code ulimit} command that will allow for an unlimited core file size
+     * if the platform supports it.
+     *
+     * @return {@code String} for the ulimit command if supported by the platform,
+     * otherwise {@code null}.
+     */
+    private static String getCoreUlimitCommand() {
+        String result = null;
+        try {
+            OutputAnalyzer output = ProcessTools.executeProcess("sh", "-c", RUN_SHELL_NO_LIMIT + "ulimit -c");
+            if (output.getExitValue() != 0) {
+                result = null;
+            } else if (!output.getStdout().contains("unlimited")) {
+                result = null;
+            } else {
+                result = RUN_SHELL_NO_LIMIT; // success
+            }
+        } catch (Throwable t) {
+            System.out.println("Exception in getCoreUlimitCommand(): " + t.toString());
+            result = null;
+        }
+        System.out.println("Run test with ulimit -c: " +
+                           (result == null ? "default" : "unlimited"));
+        return result;
+    }
+
+    /**
+     * Return a {@code ProcessBuilder} that has been prefixed with
+     * a {@code ulimit} command to allow for an unlimited core file size.
+     *
+     * @param pb {@code ProcessBuilder} to prefix with the ulimit command
+     * @return New {@code ProcessBuilder} with prefixed {@code ulimit} command if
+     * supported. Otherwise the passed in {@code ProcessBuilder} is returned.
+     */
+    public static ProcessBuilder addCoreUlimitCommand(ProcessBuilder pb) {
+        String cmd = ProcessTools.getCommandLine(pb);
+        String ulimitCmd = getCoreUlimitCommand();
+        if (ulimitCmd == null) {
+            return pb;
+        } else {
+            if (Platform.isWindows()) {
+                // In order to launch on Windows using "sh -c", we need to first
+                // convert the path to use forward slashes and do some extra quoting.
+                cmd = cmd.replace('\\', '/').replace(";", "\\;").replace("|", "\\|");
+            }
+            return new ProcessBuilder("sh", "-c", ulimitCmd + cmd);
+        }
+    }
+
+    /**
+     * Find the path to the core file mentioned in the output and return its path.
+     *
+     * @param crashOutputString {@code String} to search in for the core file path
+     * @return Location of core file if found in the output, otherwise {@code null}.
+     */
+    public static String getCoreFileLocation(String crashOutputString) throws IOException {
+        unzipCores(new File("."));
+
+        // Find the core file
+        String coreFileLocation = parseCoreFileLocationFromOutput(crashOutputString);
+        if (coreFileLocation != null) {
+            Asserts.assertGT(new File(coreFileLocation).length(), 0L, "Unexpected core size");
+            System.out.println("Found core file: " + coreFileLocation);
+            return coreFileLocation; // success!
+        }
+
+        // See if we can figure out the likely reason the core file was not found.
+        // Throw SkippedException if appropriate.
+        if (Platform.isOSX()) {
+            File coresDir = new File("/cores");
+            if (!coresDir.isDirectory()) {
+                throw new RuntimeException(coresDir + " is not a directory");
+            }
+            // The /cores directory is usually not writable on macOS 10.15
+            if (!coresDir.canWrite()) {
+                throw new SkippedException("Directory \"" + coresDir + "\" is not writable");
+            }
+        } else if (Platform.isLinux()) {
+            // Check if a crash report tool is installed.
+            File corePatternFile = new File(CORE_PATTERN_FILE_NAME);
+            try (Scanner scanner = new Scanner(corePatternFile)) {
+                while (scanner.hasNextLine()) {
+                    String line = scanner.nextLine();
+                    line = line.trim();
+                    System.out.println(line);
+                    if (line.startsWith("|")) {
+                        System.out.println(
+                            "\nThis system uses a crash report tool ($cat /proc/sys/kernel/core_pattern).\n" +
+                            "Core files might not be generated. Please reset /proc/sys/kernel/core_pattern\n" +
+                            "to enable core generation. Skipping this test.");
+                        throw new SkippedException("This system uses a crash report tool");
+                    }
+                }
+            }
+        }
+        throw new RuntimeException("Couldn't find core file location in: '" + crashOutputString + "'");
+    }
+
+    private static final String CORE_PATTERN_FILE_NAME = "/proc/sys/kernel/core_pattern";
+    private static final String LOCATION_STRING = "location: ";
+
+    private static String parseCoreFileLocationFromOutput(String crashOutputString) {
+        System.out.println("crashOutputString = [" + crashOutputString + "]");
+
+        // Find the line of output that contains LOCATION_STRING
+        Asserts.assertTrue(crashOutputString.contains(LOCATION_STRING),
+            "Output doesn't contain the location of core file.");
+        String stringWithLocation = Arrays.stream(crashOutputString.split("\\r?\\n"))
+            .filter(str -> str.contains(LOCATION_STRING))
+            .findFirst()
+            .get();
+        stringWithLocation = stringWithLocation.substring(stringWithLocation
+            .indexOf(LOCATION_STRING) + LOCATION_STRING.length());
+        System.out.println("getCoreFileLocation found stringWithLocation = " + stringWithLocation);
+
+        // Find the core file name in the output.
+        String coreWithPid;
+        if (stringWithLocation.contains("or ") && !Platform.isWindows()) {
+            Matcher m = Pattern.compile("or.* ([^ ]+[^\\)])\\)?").matcher(stringWithLocation);
+            if (!m.find()) {
+                throw new RuntimeException("Couldn't find path to core inside location string");
+            }
+            coreWithPid = m.group(1);
+        } else {
+            coreWithPid = stringWithLocation.trim();
+        }
+        if (new File(coreWithPid).exists()) {
+            return coreWithPid;
+        }
+
+        // Look for file named "core" in the cwd.
+        String justCore = Paths.get("core").toString();
+        if (new File(justCore).exists()) {
+            return justCore;
+        }
+
+        // Look for the core file name found in the output, but do so in the cwd.
+        Path coreWithPidPath = Paths.get(coreWithPid);
+        String justFile = coreWithPidPath.getFileName().toString();
+        if (new File(justFile).exists()) {
+            return justFile;
+        }
+
+        // Look for file named "core" in the path to the core file found in the output.
+        Path parent = coreWithPidPath.getParent();
+        if (parent != null) {
+            String coreWithoutPid = parent.resolve("core").toString();
+            if (new File(coreWithoutPid).exists()) {
+                return coreWithoutPid;
+            }
+        }
+        return null;
+    }
+
+    private static void unzipCores(File dir) {
+        File[] gzCores = dir.listFiles((directory, name) -> name.matches("core(\\.\\d+)?\\.gz"));
+        for (File gzCore : gzCores) {
+            String coreFileName = gzCore.getName().replace(".gz", "");
+            System.out.println("Unzipping core into " + coreFileName);
+            try (GZIPInputStream gzis = new GZIPInputStream(Files.newInputStream(gzCore.toPath()))) {
+                Files.copy(gzis, Paths.get(coreFileName));
+            } catch (IOException e) {
+                throw new SkippedException("Not able to unzip file: " + gzCore.getAbsolutePath(), e);
+            }
+        }
+    }
+
+}