diff --git a/class-match/src/main/java/datadog/instrument/classmatch/ClassFile.java b/class-match/src/main/java/datadog/instrument/classmatch/ClassFile.java index a9830ac..e1e3a33 100644 --- a/class-match/src/main/java/datadog/instrument/classmatch/ClassFile.java +++ b/class-match/src/main/java/datadog/instrument/classmatch/ClassFile.java @@ -52,7 +52,18 @@ private ClassFile() {} * @return class header containing class-name, super-name, interfaces */ public static ClassHeader header(byte[] bytecode) { - return parse(bytecode, true); + return parse(bytecode, 0, true); + } + + /** + * Extracts a {@link ClassHeader} from the given class-file content. + * + * @param bytecode the class-file content to parse + * @param offset the offset of the class-file content + * @return class header containing class-name, super-name, interfaces + */ + public static ClassHeader header(byte[] bytecode, int offset) { + return parse(bytecode, offset, true); } /** @@ -62,7 +73,18 @@ public static ClassHeader header(byte[] bytecode) { * @return class outline containing header, fields, methods, annotations */ public static ClassOutline outline(byte[] bytecode) { - return (ClassOutline) parse(bytecode, false); + return (ClassOutline) parse(bytecode, 0, false); + } + + /** + * Extracts a {@link ClassOutline} from the given class-file content. + * + * @param bytecode the class-file content to parse + * @param offset the offset of the class-file content + * @return class outline containing header, fields, methods, annotations + */ + public static ClassOutline outline(byte[] bytecode, int offset) { + return (ClassOutline) parse(bytecode, offset, false); } /** @@ -115,9 +137,9 @@ private static UtfKey annotationKey(String internalName) { } /** Parse class-file content, skipping over uninteresting sections, */ - private static ClassHeader parse(byte[] bytecode, boolean onlyHeader) { + private static ClassHeader parse(byte[] bytecode, int offset, boolean onlyHeader) { // skip preamble - int cursor = 8; + int cursor = offset + 8; int cpLen = u2(bytecode, cursor); cursor += 2; diff --git a/class-match/src/test/java/datadog/instrument/classmatch/ClassFileTest.java b/class-match/src/test/java/datadog/instrument/classmatch/ClassFileTest.java index 36e0a6d..d51c115 100644 --- a/class-match/src/test/java/datadog/instrument/classmatch/ClassFileTest.java +++ b/class-match/src/test/java/datadog/instrument/classmatch/ClassFileTest.java @@ -19,8 +19,11 @@ class ClassFileTest { + static int SAMPLE_OFFSET = 1357; + static final byte[] sampleUnicodeClass; static final byte[] sampleParametersClass; + static final byte[] sampleClassAtOffset; static { try { @@ -35,6 +38,9 @@ class ClassFileTest { } catch (IOException e) { throw new UncheckedIOException(e); } + sampleClassAtOffset = new byte[sampleUnicodeClass.length + SAMPLE_OFFSET]; + System.arraycopy( + sampleUnicodeClass, 0, sampleClassAtOffset, SAMPLE_OFFSET, sampleUnicodeClass.length); } @Test @@ -90,6 +96,21 @@ void parameterParsing() { outline.methods[1].descriptorBoundaries()); } + @Test + void offsetParsing() { + ClassHeader header = ClassFile.header(sampleClassAtOffset, SAMPLE_OFFSET); + assertEquals("sample/My例クラス", header.className); + assertEquals("java/util/AbstractCollection", header.superName); + assertArrayEquals(new String[] {"java/io/Serializable"}, header.interfaces); + + ClassOutline outline = ClassFile.outline(sampleClassAtOffset, SAMPLE_OFFSET); + assertEquals("sample/My例クラス", outline.className); + assertEquals("java/util/AbstractCollection", outline.superName); + assertArrayEquals(new String[] {"java/io/Serializable"}, outline.interfaces); + assertEquals(1, outline.fields.length); + assertEquals(2, outline.methods.length); + } + @SuppressWarnings("SameParameterValue") private static void testParsing(String sampleJar, Consumer parser) { byte[] buf = new byte[16384];