|
5 | 5 | import static com.datadog.debugger.instrumentation.Types.DEBUGGER_CONTEXT_TYPE;
|
6 | 6 | import static com.datadog.debugger.instrumentation.Types.STRING_TYPE;
|
7 | 7 | import static java.lang.Integer.parseInt;
|
| 8 | +import static java.lang.String.format; |
8 | 9 |
|
9 | 10 | import com.datadog.debugger.instrumentation.InstrumentationResult.Status;
|
10 | 11 | import com.datadog.debugger.probe.CodeOriginProbe;
|
11 | 12 | import com.datadog.debugger.probe.ProbeDefinition;
|
| 13 | +import datadog.trace.bootstrap.debugger.DebuggerContext; |
12 | 14 | import datadog.trace.bootstrap.debugger.ProbeId;
|
| 15 | +import java.util.ArrayList; |
13 | 16 | import java.util.List;
|
| 17 | +import java.util.ListIterator; |
14 | 18 | import org.objectweb.asm.Type;
|
15 | 19 | import org.objectweb.asm.tree.AbstractInsnNode;
|
16 | 20 | import org.objectweb.asm.tree.InsnList;
|
17 | 21 | import org.objectweb.asm.tree.LabelNode;
|
| 22 | +import org.objectweb.asm.tree.MethodInsnNode; |
18 | 23 |
|
19 | 24 | public class CodeOriginInstrumentor extends Instrumentor {
|
| 25 | + private static final String CAPTURE; |
| 26 | + |
| 27 | + static { |
| 28 | + String className = DebuggerContext.class.getName().replace('.', '/'); |
| 29 | + CAPTURE = format("%s#%s", className, "captureCodeOrigin"); |
| 30 | + } |
| 31 | + |
| 32 | + private static String buildDescription(AbstractInsnNode node) { |
| 33 | + if (!(node instanceof MethodInsnNode)) return ""; |
| 34 | + MethodInsnNode method = (MethodInsnNode) node; |
| 35 | + return format("%s#%s", method.owner, method.name); |
| 36 | + } |
| 37 | + |
20 | 38 | public CodeOriginInstrumentor(
|
21 |
| - ProbeDefinition definition, |
22 |
| - MethodInfo methodInfo, |
23 |
| - List<DiagnosticMessage> diagnostics, |
24 |
| - List<ProbeId> probeIds) { |
25 |
| - super(definition, methodInfo, diagnostics, probeIds); |
| 39 | + ProbeDefinition definition, MethodInfo methodInfo, List<ProbeId> probeIds) { |
| 40 | + super(definition, methodInfo, null, probeIds); |
26 | 41 | }
|
27 | 42 |
|
28 | 43 | @Override
|
29 | 44 | public Status instrument() {
|
30 |
| - InsnList insnList = new InsnList(); |
| 45 | + AbstractInsnNode insertionPoint = stripSetup(); |
| 46 | + methodNode.instructions.insert( |
| 47 | + insertionPoint != null ? insertionPoint : findInsertionPoint(), codeOriginCall()); |
31 | 48 |
|
| 49 | + return Status.INSTALLED; |
| 50 | + } |
| 51 | + |
| 52 | + private InsnList codeOriginCall() { |
| 53 | + InsnList insnList = new InsnList(); |
32 | 54 | ldc(insnList, probeIds.get(0).getEncodedId());
|
33 | 55 | invokeStatic(insnList, DEBUGGER_CONTEXT_TYPE, "codeOrigin", Type.VOID_TYPE, STRING_TYPE);
|
34 |
| - methodNode.instructions.insert(findInsertionPoint(), insnList); |
| 56 | + return insnList; |
| 57 | + } |
35 | 58 |
|
36 |
| - return InstrumentationResult.Status.INSTALLED; |
| 59 | + private AbstractInsnNode stripSetup() { |
| 60 | + ListIterator<AbstractInsnNode> iterator = methodNode.instructions.iterator(); |
| 61 | + List<AbstractInsnNode> list = new ArrayList<>(); |
| 62 | + AbstractInsnNode insertionPoint = null; |
| 63 | + while (iterator.hasNext()) { |
| 64 | + AbstractInsnNode next = iterator.next(); |
| 65 | + if (buildDescription(next).equals(CAPTURE)) { |
| 66 | + int argumentCount = Type.getMethodType(((MethodInsnNode) next).desc).getArgumentCount(); |
| 67 | + int count; |
| 68 | + if (argumentCount == 2) { |
| 69 | + count = 10; |
| 70 | + } else if (argumentCount == 1) { |
| 71 | + count = 1; |
| 72 | + } else { |
| 73 | + return null; |
| 74 | + } |
| 75 | + for (int i = 0; i < count; i++) { |
| 76 | + list.remove(list.size() - 1); |
| 77 | + } |
| 78 | + insertionPoint = list.get(list.size() - 1); |
| 79 | + } else { |
| 80 | + list.add(next); |
| 81 | + } |
| 82 | + } |
| 83 | + methodNode.instructions = new InsnList(); |
| 84 | + list.forEach(n -> methodNode.instructions.add(n)); |
| 85 | + return insertionPoint; |
37 | 86 | }
|
38 | 87 |
|
39 | 88 | private AbstractInsnNode findInsertionPoint() {
|
|
0 commit comments