Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import datadog.crashtracking.buildid.BuildInfo;
import datadog.crashtracking.dto.CrashLog;
import datadog.crashtracking.dto.ErrorData;
import datadog.crashtracking.dto.Experimental;
import datadog.crashtracking.dto.Metadata;
import datadog.crashtracking.dto.OSInfo;
import datadog.crashtracking.dto.ProcInfo;
Expand All @@ -21,8 +22,10 @@
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

Expand All @@ -36,6 +39,7 @@
*
* <ul>
* <li>TITLE - Contains dump event type and timestamp
* <li>GPINFO - General information including OS level and CPU architecture
* <li>ENVINFO - Environment info including process ID
* <li>THREADS - Thread information and stack traces
* </ul>
Expand All @@ -58,6 +62,7 @@ public J9JavacoreParser() {
// Section markers
private static final String SECTION_MARKER = "0SECTION";
private static final String SECTION_TITLE = "TITLE";
private static final String SECTION_GPINFO = "GPINFO";
private static final String SECTION_ENVINFO = "ENVINFO";
private static final String SECTION_THREADS = "THREADS";

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

enum Section {
NONE,
TITLE,
GPINFO,
ENVINFO,
THREADS,
OTHER
Expand All @@ -104,6 +115,8 @@ public CrashLog parse(String uuid, String javacoreContent) {
boolean incomplete = false;
boolean foundThreadSection = false;

Map<String, String> registers = null;

String[] lines = NEWLINE_SPLITTER.split(javacoreContent);

for (String line : lines) {
Expand Down Expand Up @@ -140,6 +153,17 @@ public CrashLog parse(String uuid, String javacoreContent) {
}
break;

case GPINFO:
if (line.startsWith("1XHREGISTERS")) {
registers = new LinkedHashMap<>();
} else if (registers != null && line.startsWith("2XHREGISTER")) {
final Matcher m = REGISTER_ENTRY_PARSER.matcher(line);
while (m.find()) {
registers.put(m.group(1), "0x" + m.group(2));
}
}
break;

case ENVINFO:
// Extract process ID
Matcher pidMatcher = PID_PATTERN.matcher(line);
Expand Down Expand Up @@ -257,9 +281,20 @@ public CrashLog parse(String uuid, String javacoreContent) {
Metadata metadata = new Metadata("dd-trace-java", VersionInfo.VERSION, "java", null);
Integer parsedPid = safelyParseInt(pid);
ProcInfo procInfo = parsedPid != null ? new ProcInfo(parsedPid) : null;
Experimental experimental =
(registers != null && !registers.isEmpty()) ? new Experimental(registers) : null;

return new CrashLog(
uuid, incomplete, datetime, error, metadata, OSInfo.current(), procInfo, sigInfo, "1.0");
uuid,
incomplete,
datetime,
error,
metadata,
OSInfo.current(),
procInfo,
sigInfo,
"1.0",
experimental);
}

private static Integer safelyParseInt(String value) {
Expand All @@ -276,6 +311,8 @@ private static Integer safelyParseInt(String value) {
private static Section detectSection(String line) {
if (line.contains(SECTION_TITLE)) {
return Section.TITLE;
} else if (line.contains(SECTION_GPINFO)) {
return Section.GPINFO;
} else if (line.contains(SECTION_ENVINFO)) {
return Section.ENVINFO;
} else if (line.contains(SECTION_THREADS)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.util.UUID;
import java.util.stream.Collectors;
import org.junit.jupiter.api.Test;
import org.tabletest.junit.TableTest;

public class J9JavacoreParserTest {

Expand Down Expand Up @@ -67,6 +68,26 @@ public void testParseGpfCrash() throws Exception {
assertNotNull(crashLog.osInfo);
}

@TableTest({
"scenario | resource | pcRegister | spRegister",
"IBM J9 8 (amd64) | sample-ibmj9-8-javacore-gpf.txt | RIP | RSP ",
"OpenJ9 11 (aarch64) | sample-openj9-11-javacore-gpf.txt | PC | SP "
})
public void testParseRealGpfCrash(String resource, String pcRegister, String spRegister)
throws Exception {
final CrashLog crashLog =
new J9JavacoreParser().parse(UUID.randomUUID().toString(), readFileAsString(resource));

assertFalse(crashLog.incomplete);
assertEquals("SIGSEGV", crashLog.sigInfo.name);
assertEquals(11, crashLog.sigInfo.number);

assertNotNull(crashLog.experimental);
assertFalse(crashLog.experimental.ucontext.isEmpty());
assertTrue(crashLog.experimental.ucontext.containsKey(pcRegister));
assertTrue(crashLog.experimental.ucontext.containsKey(spRegister));
}

@Test
public void testParseOomCrash() throws Exception {
// Given
Expand Down
Loading
Loading