Skip to content

Commit cb8bcea

Browse files
committed
feat(crashtracking): J9 register parsing
Parse the GPINFO register section (1XHREGISTERS / 2XHREGISTER tags) from J9/OpenJ9 javacore crash dumps mirroring what was done for HotSpot. Register format: 1XHREGISTERS Registers: 2XHREGISTER RIP: 00007F8B7C0B3D7D (x86-64) 2XHREGISTER PC: 0000FFFF98B9FB6C (aarch64) Added crash dumps from IBM J9 (Java 8) and IBM Semeru / OpenJ9 (Java 11) that were obtained using Docker and this crashing program: ```java import sun.misc.Unsafe; import java.lang.reflect.Field; public class Crash { public static void main(String[] args) throws Exception { Field f = Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); Unsafe unsafe = (Unsafe) f.get(null); unsafe.putInt(0L, 42); // SIGSEGV -> GPF dump } } ``` ``` docker run --rm -v /tmp/j9-crash-test:/work ibmjava:8-sdk \ bash -c "cd /work && javac Crash.java && \ java -Xdump:java:events=gpf,file=/work/javacore.ibmj9.txt Crash" ``` ``` docker run --rm -v /tmp/j9-crash-test:/work ibm-semeru-runtimes:open-11-jdk \ bash -c "cd /work && javac Crash.java && \ java -Xdump:java:events=gpf,file=/work/javacore.openj9.txt Crash" ```
1 parent fd08777 commit cb8bcea

File tree

4 files changed

+4946
-1
lines changed

4 files changed

+4946
-1
lines changed

dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/J9JavacoreParser.java

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import datadog.crashtracking.buildid.BuildInfo;
88
import datadog.crashtracking.dto.CrashLog;
99
import datadog.crashtracking.dto.ErrorData;
10+
import datadog.crashtracking.dto.Experimental;
1011
import datadog.crashtracking.dto.Metadata;
1112
import datadog.crashtracking.dto.OSInfo;
1213
import datadog.crashtracking.dto.ProcInfo;
@@ -21,8 +22,10 @@
2122
import java.time.format.DateTimeFormatter;
2223
import java.time.format.DateTimeParseException;
2324
import java.util.ArrayList;
25+
import java.util.LinkedHashMap;
2426
import java.util.List;
2527
import java.util.Locale;
28+
import java.util.Map;
2629
import java.util.regex.Matcher;
2730
import java.util.regex.Pattern;
2831

@@ -36,6 +39,7 @@
3639
*
3740
* <ul>
3841
* <li>TITLE - Contains dump event type and timestamp
42+
* <li>GPINFO - General information including OS level and CPU architecture
3943
* <li>ENVINFO - Environment info including process ID
4044
* <li>THREADS - Thread information and stack traces
4145
* </ul>
@@ -58,6 +62,7 @@ public J9JavacoreParser() {
5862
// Section markers
5963
private static final String SECTION_MARKER = "0SECTION";
6064
private static final String SECTION_TITLE = "TITLE";
65+
private static final String SECTION_GPINFO = "GPINFO";
6166
private static final String SECTION_ENVINFO = "ENVINFO";
6267
private static final String SECTION_THREADS = "THREADS";
6368

@@ -78,13 +83,19 @@ public J9JavacoreParser() {
7883
private static final Pattern NATIVE_STACK_PATTERN = Pattern.compile("4XENATIVESTACK\\s+(.+)");
7984
private static final Pattern EXCEPTION_DETAIL_PATTERN =
8085
Pattern.compile("1TISIGINFO.*[Dd]etail\\s+\"(.+?)\".*");
86+
// Matches register entries in J9 GPINFO section, e.g.:
87+
// 2XHREGISTER RDI: 0000000000000001 (x86-64)
88+
// 2XHREGISTER R29: 0000FFFF990CDB50 (aarch64)
89+
private static final Pattern REGISTER_ENTRY_PARSER =
90+
Pattern.compile("([A-Za-z][A-Za-z0-9]*)\\s*:\\s*([0-9a-fA-F]+)");
8191
// Date time formatter for J9 format: YYYY/MM/DD at HH:MM:SS
8292
private static final DateTimeFormatter J9_DATETIME_FORMATTER =
8393
DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss", Locale.ROOT);
8494

8595
enum Section {
8696
NONE,
8797
TITLE,
98+
GPINFO,
8899
ENVINFO,
89100
THREADS,
90101
OTHER
@@ -104,6 +115,8 @@ public CrashLog parse(String uuid, String javacoreContent) {
104115
boolean incomplete = false;
105116
boolean foundThreadSection = false;
106117

118+
Map<String, String> registers = null;
119+
107120
String[] lines = NEWLINE_SPLITTER.split(javacoreContent);
108121

109122
for (String line : lines) {
@@ -140,6 +153,17 @@ public CrashLog parse(String uuid, String javacoreContent) {
140153
}
141154
break;
142155

156+
case GPINFO:
157+
if (line.startsWith("1XHREGISTERS")) {
158+
registers = new LinkedHashMap<>();
159+
} else if (registers != null && line.startsWith("2XHREGISTER")) {
160+
final Matcher m = REGISTER_ENTRY_PARSER.matcher(line);
161+
while (m.find()) {
162+
registers.put(m.group(1), "0x" + m.group(2));
163+
}
164+
}
165+
break;
166+
143167
case ENVINFO:
144168
// Extract process ID
145169
Matcher pidMatcher = PID_PATTERN.matcher(line);
@@ -257,9 +281,20 @@ public CrashLog parse(String uuid, String javacoreContent) {
257281
Metadata metadata = new Metadata("dd-trace-java", VersionInfo.VERSION, "java", null);
258282
Integer parsedPid = safelyParseInt(pid);
259283
ProcInfo procInfo = parsedPid != null ? new ProcInfo(parsedPid) : null;
284+
Experimental experimental =
285+
(registers != null && !registers.isEmpty()) ? new Experimental(registers) : null;
260286

261287
return new CrashLog(
262-
uuid, incomplete, datetime, error, metadata, OSInfo.current(), procInfo, sigInfo, "1.0");
288+
uuid,
289+
incomplete,
290+
datetime,
291+
error,
292+
metadata,
293+
OSInfo.current(),
294+
procInfo,
295+
sigInfo,
296+
"1.0",
297+
experimental);
263298
}
264299

265300
private static Integer safelyParseInt(String value) {
@@ -276,6 +311,8 @@ private static Integer safelyParseInt(String value) {
276311
private static Section detectSection(String line) {
277312
if (line.contains(SECTION_TITLE)) {
278313
return Section.TITLE;
314+
} else if (line.contains(SECTION_GPINFO)) {
315+
return Section.GPINFO;
279316
} else if (line.contains(SECTION_ENVINFO)) {
280317
return Section.ENVINFO;
281318
} else if (line.contains(SECTION_THREADS)) {

dd-java-agent/agent-crashtracking/src/test/java/datadog/crashtracking/parsers/J9JavacoreParserTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import java.util.UUID;
1717
import java.util.stream.Collectors;
1818
import org.junit.jupiter.api.Test;
19+
import org.tabletest.junit.TableTest;
1920

2021
public class J9JavacoreParserTest {
2122

@@ -67,6 +68,26 @@ public void testParseGpfCrash() throws Exception {
6768
assertNotNull(crashLog.osInfo);
6869
}
6970

71+
@TableTest({
72+
"scenario | resource | pcRegister | spRegister",
73+
"IBM J9 8 (amd64) | sample-ibmj9-8-javacore-gpf.txt | RIP | RSP ",
74+
"OpenJ9 11 (aarch64) | sample-openj9-11-javacore-gpf.txt | PC | SP "
75+
})
76+
public void testParseRealGpfCrash(String resource, String pcRegister, String spRegister)
77+
throws Exception {
78+
final CrashLog crashLog =
79+
new J9JavacoreParser().parse(UUID.randomUUID().toString(), readFileAsString(resource));
80+
81+
assertFalse(crashLog.incomplete);
82+
assertEquals("SIGSEGV", crashLog.sigInfo.name);
83+
assertEquals(11, crashLog.sigInfo.number);
84+
85+
assertNotNull(crashLog.experimental);
86+
assertFalse(crashLog.experimental.ucontext.isEmpty());
87+
assertTrue(crashLog.experimental.ucontext.containsKey(pcRegister));
88+
assertTrue(crashLog.experimental.ucontext.containsKey(spRegister));
89+
}
90+
7091
@Test
7192
public void testParseOomCrash() throws Exception {
7293
// Given

0 commit comments

Comments
 (0)