2021-10-08 08:06:53 +00:00
/ *
2022-04-26 15:26:21 +00:00
* Copyright ( c ) 2021 , 2022 , Oracle and / or its affiliates . All rights reserved .
2021-10-08 08:06:53 +00:00
* 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 .
* /
/ *
* @test
* @bug 8272586
* @requires vm . compiler2 . enabled
* @summary Test that abstract machine code is dumped for the top frames in a hs - err log
* @library / test / lib
* @modules java . base / jdk . internal . misc
* java . compiler
* java . management
* jdk . internal . jvmstat / sun . jvmstat . monitor
* @run driver MachCodeFramesInErrorFile
* /
2021-10-12 09:49:50 +00:00
import java.lang.annotation.Annotation ;
import java.lang.reflect.Method ;
2021-10-08 08:06:53 +00:00
import java.nio.file.Files ;
import java.nio.file.Path ;
import java.nio.file.Paths ;
import java.util.ArrayList ;
2021-10-12 09:49:50 +00:00
import java.util.HashSet ;
import java.util.List ;
import java.util.Set ;
2021-10-08 08:06:53 +00:00
import java.util.stream.Collectors ;
2021-10-12 09:49:50 +00:00
import java.util.stream.Stream ;
2021-10-08 08:06:53 +00:00
import java.util.regex.Pattern ;
import java.util.regex.Matcher ;
2022-04-26 15:26:21 +00:00
import jdk.test.lib.Platform ;
2021-10-08 08:06:53 +00:00
import jdk.test.lib.process.ProcessTools ;
import jdk.test.lib.process.OutputAnalyzer ;
import jdk.test.lib.Asserts ;
import jdk.internal.misc.Unsafe ;
public class MachCodeFramesInErrorFile {
private static class Crasher {
2021-10-12 09:49:50 +00:00
// Make Crasher.unsafe a compile-time constant so that
// C2 intrinsifies calls to Unsafe intrinsics.
2021-10-08 08:06:53 +00:00
private static final Unsafe unsafe = Unsafe . getUnsafe ( ) ;
2021-10-12 09:49:50 +00:00
public static void main ( String [ ] args ) throws Exception {
if ( args [ 0 ] . equals ( " crashInJava " ) ) {
// This test relies on Unsafe.putLong(Object, long, long) being intrinsified
if ( ! Stream . of ( Unsafe . class . getDeclaredMethod ( " putLong " , Object . class , long . class , long . class ) . getAnnotations ( ) ) .
anyMatch ( a - > a . annotationType ( ) . getName ( ) . equals ( " jdk.internal.vm.annotation.IntrinsicCandidate " ) ) ) {
throw new RuntimeException ( " Unsafe.putLong(Object, long, long) is not an intrinsic " ) ;
}
crashInJava1 ( 10 ) ;
} else {
assert args [ 0 ] . equals ( " crashInVM " ) ;
2022-04-26 15:26:21 +00:00
// Low address reads are allowed on PPC
crashInNative1 ( Platform . isPPC ( ) ? - 1 : 10 ) ;
2021-10-12 09:49:50 +00:00
}
2021-10-08 08:06:53 +00:00
}
2021-10-12 09:49:50 +00:00
static void crashInJava1 ( long address ) {
System . out . println ( " in crashInJava1 " ) ;
crashInJava2 ( address ) ;
2021-10-08 08:06:53 +00:00
}
2021-10-12 09:49:50 +00:00
static void crashInJava2 ( long address ) {
System . out . println ( " in crashInJava2 " ) ;
crashInJava3 ( address ) ;
2021-10-08 08:06:53 +00:00
}
2021-10-12 09:49:50 +00:00
static void crashInJava3 ( long address ) {
unsafe . putLong ( null , address , 42 ) ;
System . out . println ( " wrote value to 0x " + Long . toHexString ( address ) ) ;
}
static void crashInNative1 ( long address ) {
System . out . println ( " in crashInNative1 " ) ;
crashInNative2 ( address ) ;
}
static void crashInNative2 ( long address ) {
System . out . println ( " in crashInNative2 " ) ;
crashInNative3 ( address ) ;
2021-10-08 08:06:53 +00:00
}
2021-10-12 09:49:50 +00:00
static void crashInNative3 ( long address ) {
System . out . println ( " read value " + unsafe . getLong ( address ) + " from 0x " + Long . toHexString ( address ) ) ;
}
}
public static void main ( String [ ] args ) throws Exception {
run ( true ) ;
run ( false ) ;
2021-10-08 08:06:53 +00:00
}
/ * *
2021-10-12 09:49:50 +00:00
* Runs Crasher in Xcomp mode . The inner
2021-10-08 08:06:53 +00:00
* most method crashes the VM with Unsafe . The resulting hs - err log is
* expected to have a min number of MachCode sections .
* /
2021-10-12 09:49:50 +00:00
private static void run ( boolean crashInJava ) throws Exception {
2021-10-08 08:06:53 +00:00
ProcessBuilder pb = ProcessTools . createJavaProcessBuilder (
" -Xmx64m " , " --add-exports=java.base/jdk.internal.misc=ALL-UNNAMED " ,
" -XX:-CreateCoredumpOnCrash " ,
" -Xcomp " ,
2021-10-12 09:49:50 +00:00
" -XX:-TieredCompilation " ,
" -XX:CompileCommand=compileonly,MachCodeFramesInErrorFile$Crasher.crashIn* " ,
" -XX:CompileCommand=dontinline,MachCodeFramesInErrorFile$Crasher.crashIn* " ,
" -XX:CompileCommand=dontinline,*/Unsafe.getLong " , // ensures VM call when crashInJava == false
Crasher . class . getName ( ) ,
crashInJava ? " crashInJava " : " crashInVM " ) ;
2021-10-08 08:06:53 +00:00
OutputAnalyzer output = new OutputAnalyzer ( pb . start ( ) ) ;
// Extract hs_err_pid file.
String hs_err_file = output . firstMatch ( " # *( \\ S*hs_err_pid \\ d+ \\ .log) " , 1 ) ;
if ( hs_err_file = = null ) {
2022-04-26 15:26:21 +00:00
output . reportDiagnosticSummary ( ) ;
throw new RuntimeException ( " Did not find hs_err_pid file in output " ) ;
2021-10-08 08:06:53 +00:00
}
Path hsErrPath = Paths . get ( hs_err_file ) ;
if ( ! Files . exists ( hsErrPath ) ) {
throw new RuntimeException ( " hs_err_pid file missing at " + hsErrPath + " . \ n " ) ;
}
String hsErr = Files . readString ( hsErrPath ) ;
2021-10-12 09:49:50 +00:00
if ( System . getenv ( " DEBUG " ) ! = null ) {
System . err . println ( hsErr ) ;
}
Set < String > frames = new HashSet < > ( ) ;
extractFrames ( hsErr , frames , true ) ;
if ( ! crashInJava ) {
// A crash in native will have Java frames in the hs-err log
// as there is a Java frame anchor on the stack.
extractFrames ( hsErr , frames , false ) ;
2021-10-08 08:06:53 +00:00
}
2021-10-12 09:49:50 +00:00
int compiledJavaFrames = ( int ) frames . stream ( ) . filter ( f - > f . startsWith ( " J " ) ) . count ( ) ;
2021-10-08 08:06:53 +00:00
2021-10-12 06:22:13 +00:00
Matcher matcherDisasm = Pattern . compile ( " \\ [Disassembly \\ ].* \\ [/Disassembly \\ ] " , Pattern . DOTALL ) . matcher ( hsErr ) ;
if ( matcherDisasm . find ( ) ) {
// Real disassembly is present, no MachCode is expected.
return ;
}
2022-05-11 20:08:15 +00:00
String preCodeBlobSectionHeader = " Stack slot to memory mapping: " ;
if ( ! hsErr . contains ( preCodeBlobSectionHeader ) & &
System . getProperty ( " os.arch " ) . equals ( " aarch64 " ) & &
System . getProperty ( " os.name " ) . toLowerCase ( ) . startsWith ( " mac " ) ) {
// JDK-8282607: hs_err can be truncated. If the section preceding
// code blob dumping is missing, exit successfully.
System . out . println ( " Could not find \" " + preCodeBlobSectionHeader + " \" in " + hsErrPath ) ;
System . out . println ( " Looks like hs-err is truncated - exiting with success " ) ;
2022-05-14 15:28:53 +00:00
return ;
2022-05-11 20:08:15 +00:00
}
2021-10-08 08:06:53 +00:00
Matcher matcher = Pattern . compile ( " \\ [MachCode \\ ] \\ s* \\ [Verified Entry Point \\ ] \\ s* # \\ {method \\ } \\ {[^}]* \\ } '([^']+)' '([^']+)' in '([^']+)' " , Pattern . DOTALL ) . matcher ( hsErr ) ;
List < String > machCodeHeaders = matcher . results ( ) . map ( mr - > String . format ( " '%s' '%s' in '%s' " , mr . group ( 1 ) , mr . group ( 2 ) , mr . group ( 3 ) ) ) . collect ( Collectors . toList ( ) ) ;
int minExpectedMachCodeSections = Math . max ( 1 , compiledJavaFrames ) ;
2021-10-12 09:49:50 +00:00
if ( machCodeHeaders . size ( ) < minExpectedMachCodeSections ) {
Asserts . fail ( machCodeHeaders . size ( ) + " < " + minExpectedMachCodeSections ) ;
2021-10-08 08:06:53 +00:00
}
}
/ * *
2021-10-12 09:49:50 +00:00
* Extracts the lines in { @code hsErr } below the line starting with
2022-04-26 15:26:21 +00:00
* " Native frame " or " Java frame " up to the next blank line
2021-10-12 09:49:50 +00:00
* and adds them to { @code frames } .
2021-10-08 08:06:53 +00:00
* /
2021-10-12 09:49:50 +00:00
private static void extractFrames ( String hsErr , Set < String > frames , boolean nativeStack ) {
2022-04-26 15:26:21 +00:00
String marker = ( nativeStack ? " Native " : " Java " ) + " frame " ;
2021-10-12 09:49:50 +00:00
boolean seenMarker = false ;
2021-10-08 08:06:53 +00:00
for ( String line : hsErr . split ( System . lineSeparator ( ) ) ) {
2021-10-12 09:49:50 +00:00
if ( line . startsWith ( marker ) ) {
seenMarker = true ;
} else if ( seenMarker ) {
2021-10-08 08:06:53 +00:00
if ( line . trim ( ) . isEmpty ( ) ) {
2021-10-12 09:49:50 +00:00
return ;
2021-10-08 08:06:53 +00:00
}
2021-10-12 09:49:50 +00:00
frames . add ( line ) ;
2021-10-08 08:06:53 +00:00
}
}
2022-04-26 15:26:21 +00:00
System . err . println ( hsErr ) ;
throw new RuntimeException ( " \" " + marker + " \" line missing in hs_err_pid file " ) ;
2021-10-08 08:06:53 +00:00
}
}