Skip to content

Commit c5d514a

Browse files
committed
Clean up the initial code origin set up instrumentation
1 parent 22535c7 commit c5d514a

File tree

24 files changed

+260
-125
lines changed

24 files changed

+260
-125
lines changed

dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/DebuggerContext.java

+7-11
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ public interface ExceptionDebugger {
116116
public interface CodeOriginRecorder {
117117
String captureCodeOrigin(boolean entry);
118118

119-
String captureCodeOrigin(Method method, boolean entry, boolean instrument);
119+
String captureCodeOrigin(Method method, boolean entry);
120120
}
121121

122122
private static volatile ProductConfigUpdater productConfigUpdater;
@@ -466,32 +466,28 @@ public static void commit(
466466
}
467467
}
468468

469-
public static String captureCodeOrigin(boolean entry) {
469+
public static void marker() {}
470+
471+
public static void captureCodeOrigin(boolean entry) {
470472
try {
471473
CodeOriginRecorder recorder = codeOriginRecorder;
472474
if (recorder != null) {
473-
return recorder.captureCodeOrigin(entry);
475+
recorder.captureCodeOrigin(entry);
474476
}
475477
} catch (Exception ex) {
476478
LOGGER.debug("Error in captureCodeOrigin: ", ex);
477479
}
478-
return null;
479-
}
480-
481-
public static String captureCodeOrigin(Method method, boolean entry) {
482-
return captureCodeOrigin(method, entry, true);
483480
}
484481

485-
public static String captureCodeOrigin(Method method, boolean entry, boolean instrument) {
482+
public static void captureCodeOrigin(Method method, boolean entry) {
486483
try {
487484
CodeOriginRecorder recorder = codeOriginRecorder;
488485
if (recorder != null) {
489-
return recorder.captureCodeOrigin(method, entry, instrument);
486+
recorder.captureCodeOrigin(method, entry);
490487
}
491488
} catch (Exception ex) {
492489
LOGGER.debug("Error in captureCodeOrigin: ", ex);
493490
}
494-
return null;
495491
}
496492

497493
public static void handleException(Throwable t, AgentSpan span) {

dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/spanorigin/CodeOriginInfo.java

-24
This file was deleted.

dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/codeorigin/DefaultCodeOriginRecorder.java

+18-25
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public class DefaultCodeOriginRecorder implements CodeOriginRecorder {
4545

4646
private final int maxUserFrames;
4747

48-
private AgentTaskScheduler scheduler = AgentTaskScheduler.INSTANCE;
48+
private AgentTaskScheduler scheduler;
4949

5050
public DefaultCodeOriginRecorder(Config config, ConfigurationUpdater configurationUpdater) {
5151
this(config, configurationUpdater, AgentTaskScheduler.INSTANCE);
@@ -70,51 +70,44 @@ public String captureCodeOrigin(boolean entry) {
7070
element.getMethodName(),
7171
null,
7272
String.valueOf(element.getLineNumber()));
73-
probe = createProbe(fingerprint, entry, where, true);
73+
probe = createProbe(fingerprint, entry, where);
7474

7575
LOG.debug("Creating probe for location {}", where);
7676
}
7777
return probe.getId();
7878
}
7979

8080
@Override
81-
public String captureCodeOrigin(Method method, boolean entry, boolean instrument) {
81+
public String captureCodeOrigin(Method method, boolean entry) {
8282
String fingerprint = method.toString();
8383
CodeOriginProbe probe = probesByFingerprint.get(fingerprint);
8484
if (probe == null) {
85-
probe = createProbe(fingerprint, entry, Where.of(method), instrument);
85+
probe = createProbe(fingerprint, entry, Where.of(method));
8686
LOG.debug("Creating probe for method {}", fingerprint);
87-
} else if (!instrument) {
88-
// direct call to fill code origin info without using probe instrumentation
89-
// buildLocation should be called before in order to gather location info
90-
probe.commit(
91-
CapturedContext.EMPTY_CONTEXT, CapturedContext.EMPTY_CONTEXT, Collections.emptyList());
9287
}
9388
return probe.getId();
9489
}
9590

9691
public void registerLogProbe(CodeOriginProbe probe) {
97-
LogProbe logProbe =
98-
logProbes.computeIfAbsent(
99-
probe.getId(),
100-
key ->
101-
new Builder()
102-
.language(probe.getLanguage())
103-
.probeId(ProbeId.newId())
104-
.where(probe.getWhere())
105-
.evaluateAt(probe.getEvaluateAt())
106-
.captureSnapshot(true)
107-
.tags("session_id:*")
108-
.snapshotProcessor(new CodeOriginSnapshotConsumer(probe.entrySpanProbe()))
109-
.build());
92+
logProbes.computeIfAbsent(
93+
probe.getId(),
94+
key ->
95+
new Builder()
96+
.language(probe.getLanguage())
97+
.probeId(ProbeId.newId())
98+
.where(probe.getWhere())
99+
.evaluateAt(probe.getEvaluateAt())
100+
.captureSnapshot(true)
101+
.tags("session_id:*")
102+
.snapshotProcessor(new CodeOriginSnapshotConsumer(probe.entrySpanProbe()))
103+
.build());
110104
}
111105

112-
private CodeOriginProbe createProbe(
113-
String fingerPrint, boolean entry, Where where, boolean instrument) {
106+
private CodeOriginProbe createProbe(String fingerPrint, boolean entry, Where where) {
114107
CodeOriginProbe probe;
115108
AgentSpan span = AgentTracer.activeSpan();
116109

117-
probe = new CodeOriginProbe(ProbeId.newId(), entry, where, instrument);
110+
probe = new CodeOriginProbe(ProbeId.newId(), entry, where);
118111
addFingerprint(fingerPrint, probe);
119112
CodeOriginProbe installed = probes.putIfAbsent(probe.getId(), probe);
120113

dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/ASMHelper.java

+65-1
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,29 @@
11
package com.datadog.debugger.instrumentation;
22

33
import static com.datadog.debugger.instrumentation.Types.REFLECTIVE_FIELD_VALUE_RESOLVER_TYPE;
4+
import static java.lang.String.format;
45
import static org.objectweb.asm.Type.getMethodDescriptor;
56
import static org.objectweb.asm.Type.getObjectType;
67

78
import com.datadog.debugger.agent.Generated;
89
import datadog.trace.util.Strings;
10+
import de.thetaphi.forbiddenapis.SuppressForbidden;
11+
import java.io.File;
12+
import java.io.FileOutputStream;
13+
import java.io.IOException;
14+
import java.io.PrintWriter;
15+
import java.io.StringWriter;
916
import java.lang.reflect.Field;
1017
import java.lang.reflect.Modifier;
1118
import java.util.ArrayList;
19+
import java.util.Arrays;
1220
import java.util.Collections;
1321
import java.util.Comparator;
1422
import java.util.List;
23+
import java.util.StringJoiner;
1524
import java.util.stream.Collectors;
25+
import org.objectweb.asm.ClassWriter;
1626
import org.objectweb.asm.Opcodes;
17-
import org.objectweb.asm.Type;
1827
import org.objectweb.asm.signature.SignatureReader;
1928
import org.objectweb.asm.signature.SignatureVisitor;
2029
import org.objectweb.asm.tree.AbstractInsnNode;
@@ -24,10 +33,14 @@
2433
import org.objectweb.asm.tree.InsnList;
2534
import org.objectweb.asm.tree.InsnNode;
2635
import org.objectweb.asm.tree.LdcInsnNode;
36+
import org.objectweb.asm.tree.LineNumberNode;
2737
import org.objectweb.asm.tree.LocalVariableNode;
2838
import org.objectweb.asm.tree.MethodInsnNode;
2939
import org.objectweb.asm.tree.MethodNode;
3040
import org.objectweb.asm.tree.TypeInsnNode;
41+
import org.objectweb.asm.util.Printer;
42+
import org.objectweb.asm.util.Textifier;
43+
import org.objectweb.asm.util.TraceClassVisitor;
3144

3245
/** Helper class for bytecode generation */
3346
public class ASMHelper {
@@ -36,6 +49,45 @@ public class ASMHelper {
3649
public static final Type STRING_TYPE = new Type(Types.STRING_TYPE);
3750
public static final Type LONG_TYPE = new Type(org.objectweb.asm.Type.LONG_TYPE);
3851

52+
public static void dumpMethod(ClassNode classNode, String method, String suffix) {
53+
String content = extractMethod(classNode, method);
54+
File output;
55+
int count = 0;
56+
do {
57+
output = new File(format("build/%s-%d-%s.txt", method, count++, suffix));
58+
} while (output.exists());
59+
output.getParentFile().mkdirs();
60+
try (PrintWriter writer = new PrintWriter(output)) {
61+
writer.println(content);
62+
String absolutePath = output.getAbsolutePath();
63+
absolutePath = absolutePath.substring(0, absolutePath.lastIndexOf('.'));
64+
absolutePath += ".class";
65+
ClassWriter classWriter = new ClassWriter(0);
66+
classNode.accept(classWriter);
67+
try (FileOutputStream stream = new FileOutputStream(absolutePath)) {
68+
stream.write(classWriter.toByteArray());
69+
}
70+
} catch (IOException e) {
71+
throw new RuntimeException(e);
72+
}
73+
}
74+
75+
@SuppressForbidden
76+
static String extractMethod(ClassNode classNode, String method) {
77+
StringJoiner joiner = new StringJoiner("\n");
78+
joiner.add("Class: " + classNode.name);
79+
StringWriter writer = new StringWriter();
80+
classNode.accept(new TraceClassVisitor(null, new Textifier(), new PrintWriter(writer)));
81+
List<String> strings = Arrays.asList(writer.toString().split("\n"));
82+
for (int i = 0; i < strings.size(); i++) {
83+
if (strings.get(i).matches(format(".*(private|public).* %s\\(.*", method))) {
84+
while (!strings.get(i).equals(""))
85+
joiner.add(String.format("[%3d] %s", i, strings.get(i++)));
86+
}
87+
}
88+
return joiner.toString();
89+
}
90+
3991
public static void invokeInterface(
4092
InsnList insnList,
4193
org.objectweb.asm.Type owner,
@@ -322,6 +374,18 @@ public static boolean isStoreCompatibleType(
322374
return previousSort == currentSort;
323375
}
324376

377+
public static String toString(AbstractInsnNode node) {
378+
String opcode = node.getOpcode() >= 0 ? Printer.OPCODES[node.getOpcode()] : node.toString();
379+
if (node instanceof LineNumberNode) {
380+
return String.format("LineNumber: %s", ((LineNumberNode) node).line);
381+
} else if (node instanceof MethodInsnNode) {
382+
MethodInsnNode method = (MethodInsnNode) node;
383+
return String.format("%s: [%s] %s", opcode, method.name, method.desc);
384+
} else {
385+
return opcode;
386+
}
387+
}
388+
325389
private static int widenIntType(int sort) {
326390
switch (sort) {
327391
case org.objectweb.asm.Type.BOOLEAN:

dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/CodeOriginInstrumentor.java

+54-8
Original file line numberDiff line numberDiff line change
@@ -5,35 +5,81 @@
55
import static com.datadog.debugger.instrumentation.Types.DEBUGGER_CONTEXT_TYPE;
66
import static com.datadog.debugger.instrumentation.Types.STRING_TYPE;
77
import static java.lang.Integer.parseInt;
8+
import static java.lang.String.format;
89

910
import com.datadog.debugger.instrumentation.InstrumentationResult.Status;
1011
import com.datadog.debugger.probe.CodeOriginProbe;
1112
import com.datadog.debugger.probe.ProbeDefinition;
13+
import datadog.trace.bootstrap.debugger.DebuggerContext;
1214
import datadog.trace.bootstrap.debugger.ProbeId;
1315
import java.util.List;
16+
import java.util.ListIterator;
1417
import org.objectweb.asm.Type;
1518
import org.objectweb.asm.tree.AbstractInsnNode;
1619
import org.objectweb.asm.tree.InsnList;
1720
import org.objectweb.asm.tree.LabelNode;
21+
import org.objectweb.asm.tree.MethodInsnNode;
1822

1923
public class CodeOriginInstrumentor extends Instrumentor {
24+
private static final String CAPTURE;
25+
private static final String MARKER;
26+
27+
static {
28+
String className = DebuggerContext.class.getName().replace('.', '/');
29+
CAPTURE = format("%s#%s", className, "captureCodeOrigin");
30+
MARKER = format("%s#%s", className, "marker");
31+
}
32+
2033
public CodeOriginInstrumentor(
21-
ProbeDefinition definition,
22-
MethodInfo methodInfo,
23-
List<DiagnosticMessage> diagnostics,
24-
List<ProbeId> probeIds) {
25-
super(definition, methodInfo, diagnostics, probeIds);
34+
ProbeDefinition definition, MethodInfo methodInfo, List<ProbeId> probeIds) {
35+
super(definition, methodInfo, null, probeIds);
2636
}
2737

2838
@Override
2939
public Status instrument() {
30-
InsnList insnList = new InsnList();
40+
AbstractInsnNode insertionPoint = stripSetup();
41+
methodNode.instructions.insert(
42+
insertionPoint != null ? insertionPoint : findInsertionPoint(), codeOriginCall());
3143

44+
return Status.INSTALLED;
45+
}
46+
47+
private static String buildDescription(AbstractInsnNode node) {
48+
if (!(node instanceof MethodInsnNode)) return "";
49+
MethodInsnNode method = (MethodInsnNode) node;
50+
return format("%s#%s", method.owner, method.name);
51+
}
52+
53+
private InsnList codeOriginCall() {
54+
InsnList insnList = new InsnList();
3255
ldc(insnList, probeIds.get(0).getEncodedId());
3356
invokeStatic(insnList, DEBUGGER_CONTEXT_TYPE, "codeOrigin", Type.VOID_TYPE, STRING_TYPE);
34-
methodNode.instructions.insert(findInsertionPoint(), insnList);
57+
return insnList;
58+
}
3559

36-
return InstrumentationResult.Status.INSTALLED;
60+
private AbstractInsnNode stripSetup() {
61+
try {
62+
ListIterator<AbstractInsnNode> iterator = methodNode.instructions.iterator();
63+
AbstractInsnNode insertionPoint = null;
64+
InsnList list = new InsnList();
65+
while (iterator.hasNext()) {
66+
AbstractInsnNode next = iterator.next();
67+
if (buildDescription(next).equals(MARKER)) {
68+
insertionPoint = next.getPrevious();
69+
while (iterator.hasNext() && !buildDescription(next = iterator.next()).equals(CAPTURE)) {}
70+
71+
if (!iterator.hasNext()) {
72+
return null;
73+
}
74+
} else {
75+
list.add(next);
76+
}
77+
}
78+
methodNode.instructions = list;
79+
return insertionPoint;
80+
} catch (Exception e) {
81+
return null;
82+
}
3783
}
3884

3985
private AbstractInsnNode findInsertionPoint() {

dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/probe/CodeOriginProbe.java

+2-7
Original file line numberDiff line numberDiff line change
@@ -26,23 +26,18 @@
2626
public class CodeOriginProbe extends ProbeDefinition {
2727
private static final Logger LOGGER = LoggerFactory.getLogger(CodeOriginProbe.class);
2828

29-
private final boolean instrument;
3029
private final boolean entrySpanProbe;
3130
private String signature;
3231

33-
public CodeOriginProbe(ProbeId probeId, boolean entry, Where where, boolean instrument) {
32+
public CodeOriginProbe(ProbeId probeId, boolean entry, Where where) {
3433
super(LANGUAGE, probeId, (Tag[]) null, where, MethodLocation.ENTRY);
35-
this.instrument = instrument;
3634
this.entrySpanProbe = entry;
3735
}
3836

3937
@Override
4038
public Status instrument(
4139
MethodInfo methodInfo, List<DiagnosticMessage> diagnostics, List<ProbeId> probeIds) {
42-
if (instrument) {
43-
return new CodeOriginInstrumentor(this, methodInfo, diagnostics, probeIds).instrument();
44-
}
45-
return Status.INSTALLED;
40+
return new CodeOriginInstrumentor(this, methodInfo, probeIds).instrument();
4641
}
4742

4843
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.datadog.debugger.origin;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Target;
5+
6+
@Target(ElementType.METHOD)
7+
public @interface CodeOrigin {}

0 commit comments

Comments
 (0)