Skip to content

Commit 82ccbb1

Browse files
committed
JIT debug agent using ASM
-This agent creates the hook needed to inject the code for running the debug agent tool Signed-off-by: Shane Killoran <shanegkilloran@gmail.com>
1 parent 4447a03 commit 82ccbb1

9 files changed

Lines changed: 412 additions & 0 deletions

File tree

jit-debug-agent/DebugAgent.mf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Manifest-Version: 1.0
2+
Premain-Class: DebugAgent
3+
Agent-Class: DebugAgent
4+
Class-path: asm-9.2.jar junit-4.12.jar
5+
Can-Redefine-Classes: true
6+
Can-Retransform-Classes: true

jit-debug-agent/README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# OpenJ9 JIT Debug Agent
2+
3+
This tool automatically obtains a limited JIT trace log for a miscompiled method. It works by using preexistence
4+
and a hooked internal API to repeatedly run a test by sequentially reverting JIT methods to be executed in the interpreter.
5+
By repeatedly executing a test in a controlled environment we are able to devertmine which JIT method needs to be interpreted
6+
for the test to start passing. This is how the tool determines which JIT method _may_ be responsible for the test case failure.
7+
8+
Once the JIT method is identified the tool performs a `lastOptIndex` search by recompiling the JIT method at different
9+
optimization levels. Once again, when the test starts passing we have determined the minimal `lastOptIndex` which causes the
10+
failure. At that point the tool gather a _"good"_ and _"bad"_ JIT trace log with the optimization included and excluded for
11+
JIT developers to investigate.
12+
13+
# When to use this tool
14+
15+
This tool should be used for highly intermittent JIT defects from automated testing environments where we are either not able
16+
to determine the JIT method responsible for the failure, or we are unable to trace the suspect JIT method due to a Heisenbug.
17+
18+
# How to use this tool
19+
20+
1. Using maven and running the command `$ mvn install` in this directory will package the agent into a jar file, you will find it in the `target` directory.
21+
2. add the java agent option to your `java` execution which would look like this: `-javaagent: jit-debug-agent-1.0.jar`
22+
3. Run the test by forcing preexistence.
23+
24+
Currently the tool is not robust enough to enable this automatically, so we have to force every JIT method compilation to use
25+
preexistence. This is to ensure that we have a _revert to interpreter_ stub inserted in the preprologue of every method.
26+
Inserting this stub happens at binary encoding and should not affect the semantics of the method itself.
27+
28+
```
29+
java -Xdump:none -Xnoaot -Xcheck:jni -Xjit:forceUsePreexistence -javaagent: jit-debug-agent-1.0.jar <test>

jit-debug-agent/pom.xml

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>org.openj9</groupId>
8+
<artifactId>jit-debug-agent</artifactId>
9+
<version>1.0</version>
10+
11+
<dependencies>
12+
<dependency>
13+
<groupId>org.ow2.asm</groupId>
14+
<artifactId>asm</artifactId>
15+
<version>9.2</version>
16+
</dependency>
17+
<dependency>
18+
<groupId>junit</groupId>
19+
<artifactId>junit</artifactId>
20+
<version>4.12</version>
21+
<scope>compile</scope>
22+
</dependency>
23+
</dependencies>
24+
25+
<properties>
26+
<maven.compiler.source>11</maven.compiler.source>
27+
<maven.compiler.target>11</maven.compiler.target>
28+
</properties>
29+
30+
<build>
31+
<plugins>
32+
<plugin>
33+
<artifactId>maven-assembly-plugin</artifactId>
34+
<configuration>
35+
<archive>
36+
<manifestEntries>
37+
<Premain-Class>
38+
DebugAgent
39+
</Premain-Class>
40+
<Can-Retransform-Classes>
41+
true
42+
</Can-Retransform-Classes>
43+
<Can-Redefine-Classes>
44+
true
45+
</Can-Redefine-Classes>
46+
</manifestEntries>
47+
</archive>
48+
<descriptorRefs>
49+
<descriptorRef>jar-with-dependencies</descriptorRef>
50+
</descriptorRefs>
51+
<appendAssemblyId>false</appendAssemblyId>
52+
</configuration>
53+
<executions>
54+
<execution>
55+
<id>make-assembly</id>
56+
<phase>package</phase>
57+
<goals>
58+
<goal>single</goal>
59+
</goals>
60+
</execution>
61+
</executions>
62+
</plugin>
63+
</plugins>
64+
</build>
65+
</project>
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
{{- /*******************************************************************************
2+
* Copyright (c) 2021, 2021 IBM Corp. and others
3+
*
4+
* This program and the accompanying materials are made available under
5+
* the terms of the Eclipse Public License 2.0 which accompanies this
6+
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7+
* or the Apache License, Version 2.0 which accompanies this distribution and
8+
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9+
*
10+
* This Source Code may also be made available under the following
11+
* Secondary Licenses when the conditions for such availability set
12+
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13+
* General Public License, version 2 with the GNU Classpath
14+
* Exception [1] and GNU General Public License, version 2 with the
15+
* OpenJDK Assembly Exception [2].
16+
*
17+
* [1] https://www.gnu.org/software/classpath/license.html
18+
* [2] http://openjdk.java.net/legal/assembly-exception.html
19+
*
20+
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
21+
*******************************************************************************/ -}}
22+
import java.lang.instrument.*;
23+
import java.security.ProtectionDomain;
24+
import java.io.IOException;
25+
26+
public class DebugAgent {
27+
28+
private static String REFLECT_METHOD_NAME = "java/lang/reflect/Method";
29+
private static String EXPECT_EXCEPTION_NAME = "org/junit/internal/runners/statements/ExpectException";
30+
private static Class REFLECT_METHOD_CLASS = java.lang.reflect.Method.class;
31+
private static Class EXPECT_EXCEPTION_CLASS = org.junit.internal.runners.statements.ExpectException.class;
32+
private static String INVOKE = "invoke";
33+
private static String EVALUATE = "evaluate";
34+
35+
public static void premain(String args, Instrumentation inst) throws Exception {
36+
inst.addTransformer(new ClassFileTransformer(){
37+
@Override
38+
public byte[] transform(
39+
ClassLoader l,
40+
String name,
41+
Class c,
42+
ProtectionDomain d,
43+
byte[] b
44+
) throws IllegalClassFormatException {
45+
if(name.equals(REFLECT_METHOD_NAME)) {
46+
try {
47+
DebugClassWriter writer = new DebugClassWriter(c.getName());
48+
return writer.applyDebugger(INVOKE);
49+
} catch (IOException e) {
50+
System.out.println(e);
51+
}
52+
}
53+
54+
if(name.equals(EXPECT_EXCEPTION_NAME)) {
55+
try{
56+
DebugClassWriter writer = new DebugClassWriter(c.getName());
57+
return writer.applyDebugger(EVALUATE);
58+
} catch (IOException e) {
59+
System.out.println(e);
60+
}
61+
}
62+
return b;
63+
}
64+
}, true);
65+
66+
Class[] classesToTransform = {EXPECT_EXCEPTION_CLASS, REFLECT_METHOD_CLASS};
67+
inst.retransformClasses(classesToTransform);
68+
}
69+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{{- /*******************************************************************************
2+
* Copyright (c) 2021, 2021 IBM Corp. and others
3+
*
4+
* This program and the accompanying materials are made available under
5+
* the terms of the Eclipse Public License 2.0 which accompanies this
6+
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7+
* or the Apache License, Version 2.0 which accompanies this distribution and
8+
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9+
*
10+
* This Source Code may also be made available under the following
11+
* Secondary Licenses when the conditions for such availability set
12+
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13+
* General Public License, version 2 with the GNU Classpath
14+
* Exception [1] and GNU General Public License, version 2 with the
15+
* OpenJDK Assembly Exception [2].
16+
*
17+
* [1] https://www.gnu.org/software/classpath/license.html
18+
* [2] http://openjdk.java.net/legal/assembly-exception.html
19+
*
20+
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
21+
*******************************************************************************/ -}}
22+
import org.objectweb.asm.*;
23+
import java.io.IOException;
24+
25+
public class DebugClassWriter {
26+
private ClassReader reader;
27+
private ClassWriter writer;
28+
private static String INVOKE = "invoke";
29+
30+
31+
public DebugClassWriter(String className) throws IOException {
32+
reader = new ClassReader(className);
33+
writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
34+
}
35+
36+
public byte[] applyDebugger(String methodName){
37+
if (methodName == INVOKE) {
38+
MethodDebugAdapter methodDebugAdapter = new MethodDebugAdapter(methodName, writer);
39+
reader.accept(methodDebugAdapter, 0);
40+
} else {
41+
ExpectDebugAdapter expectDebugAdapter = new ExpectDebugAdapter(methodName, writer);
42+
reader.accept(expectDebugAdapter, 0);
43+
}
44+
45+
return writer.toByteArray();
46+
}
47+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
{{- /*******************************************************************************
2+
* Copyright (c) 2021, 2021 IBM Corp. and others
3+
*
4+
* This program and the accompanying materials are made available under
5+
* the terms of the Eclipse Public License 2.0 which accompanies this
6+
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7+
* or the Apache License, Version 2.0 which accompanies this distribution and
8+
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9+
*
10+
* This Source Code may also be made available under the following
11+
* Secondary Licenses when the conditions for such availability set
12+
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13+
* General Public License, version 2 with the GNU Classpath
14+
* Exception [1] and GNU General Public License, version 2 with the
15+
* OpenJDK Assembly Exception [2].
16+
*
17+
* [1] https://www.gnu.org/software/classpath/license.html
18+
* [2] http://openjdk.java.net/legal/assembly-exception.html
19+
*
20+
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
21+
*******************************************************************************/ -}}
22+
import org.objectweb.asm.*;
23+
24+
public class EvaluateDebugAdapter extends MethodVisitor {
25+
26+
public EvaluateDebugAdapter(MethodVisitor mv) {
27+
super(Opcodes.ASM9, mv);
28+
this.mv = mv;
29+
}
30+
31+
@Override
32+
public void visitCode() {
33+
mv.visitCode();
34+
mv.visitVarInsn(Opcodes.ALOAD, 0);
35+
mv.visitFieldInsn(Opcodes.GETFIELD, "org/junit/internal/runners/statements/ExpectException", "expected", "Ljava/lang/Class;");
36+
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/ibm/jit/JITHelpers", "setExpectedException", "(Ljava/lang/Class;)V", false);
37+
}
38+
39+
@Override
40+
public void visitLineNumber(int line, Label start){
41+
mv.visitLineNumber(line, start);
42+
if (line == 31) {
43+
mv.visitInsn(Opcodes.ACONST_NULL);
44+
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/ibm/jit/JITHelpers", "setExpectedException", "(Ljava/lang/Class;)V", false);
45+
}
46+
}
47+
48+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
{{- /*******************************************************************************
2+
* Copyright (c) 2021, 2021 IBM Corp. and others
3+
*
4+
* This program and the accompanying materials are made available under
5+
* the terms of the Eclipse Public License 2.0 which accompanies this
6+
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7+
* or the Apache License, Version 2.0 which accompanies this distribution and
8+
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9+
*
10+
* This Source Code may also be made available under the following
11+
* Secondary Licenses when the conditions for such availability set
12+
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13+
* General Public License, version 2 with the GNU Classpath
14+
* Exception [1] and GNU General Public License, version 2 with the
15+
* OpenJDK Assembly Exception [2].
16+
*
17+
* [1] https://www.gnu.org/software/classpath/license.html
18+
* [2] http://openjdk.java.net/legal/assembly-exception.html
19+
*
20+
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
21+
*******************************************************************************/ -}}
22+
import org.objectweb.asm.*;
23+
24+
public class ExpectDebugAdapter extends ClassVisitor {
25+
private String methodName;
26+
private int access = org.objectweb.asm.Opcodes.ACC_PUBLIC;
27+
28+
public ExpectDebugAdapter(String methodName, ClassVisitor cv) {
29+
super(org.objectweb.asm.Opcodes.ASM9, cv);
30+
this.cv = cv;
31+
this.methodName = methodName;
32+
}
33+
34+
@Override
35+
public MethodVisitor visitMethod(
36+
int access,
37+
String name,
38+
String desc,
39+
String signature,
40+
String[] exceptions) {
41+
MethodVisitor mv;
42+
mv = cv.visitMethod(
43+
access,
44+
name,
45+
desc,
46+
signature,
47+
exceptions);
48+
if (name.equals(methodName) && mv != null) {
49+
return new EvaluateDebugAdapter(mv);
50+
}
51+
return mv;
52+
}
53+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{{- /*******************************************************************************
2+
* Copyright (c) 2021, 2021 IBM Corp. and others
3+
*
4+
* This program and the accompanying materials are made available under
5+
* the terms of the Eclipse Public License 2.0 which accompanies this
6+
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7+
* or the Apache License, Version 2.0 which accompanies this distribution and
8+
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9+
*
10+
* This Source Code may also be made available under the following
11+
* Secondary Licenses when the conditions for such availability set
12+
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13+
* General Public License, version 2 with the GNU Classpath
14+
* Exception [1] and GNU General Public License, version 2 with the
15+
* OpenJDK Assembly Exception [2].
16+
*
17+
* [1] https://www.gnu.org/software/classpath/license.html
18+
* [2] http://openjdk.java.net/legal/assembly-exception.html
19+
*
20+
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
21+
*******************************************************************************/ -}}
22+
import org.objectweb.asm.*;
23+
24+
public class InvokeDebugAdapter extends MethodVisitor {
25+
public InvokeDebugAdapter(MethodVisitor mv) {
26+
super(Opcodes.ASM9, mv);
27+
}
28+
29+
@Override
30+
public void visitMethodInsn(int opcode, java.lang.String owner, java.lang.String name, java.lang.String descriptor, boolean isInterface) {
31+
if(opcode==Opcodes.INVOKEINTERFACE){
32+
mv.visitMethodInsn(
33+
Opcodes.INVOKESTATIC,
34+
"com/ibm/jit/JITHelpers",
35+
"invoke",
36+
"(Ljdk/internal/reflect/MethodAccessor;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;",
37+
false);
38+
} else {
39+
mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
40+
}
41+
}
42+
}

0 commit comments

Comments
 (0)