|
20 | 20 | import org.objectweb.asm.ClassReader;
|
21 | 21 | import org.objectweb.asm.ClassVisitor;
|
22 | 22 | import org.objectweb.asm.ClassWriter;
|
| 23 | +import org.objectweb.asm.Label; |
23 | 24 | import org.objectweb.asm.MethodVisitor;
|
24 | 25 | import org.objectweb.asm.Opcodes;
|
25 | 26 | import org.objectweb.asm.Type;
|
@@ -68,6 +69,8 @@ public boolean delayStart() {
|
68 | 69 |
|
69 | 70 | @Override
|
70 | 71 | public void start() {
|
| 72 | + init(); |
| 73 | + |
71 | 74 | EarlyInitAgentConfig earlyConfig = EarlyInitAgentConfig.create();
|
72 | 75 | extensionClassLoader = createExtensionClassLoader(getClass().getClassLoader(), earlyConfig);
|
73 | 76 |
|
@@ -115,6 +118,29 @@ public void start() {
|
115 | 118 | }
|
116 | 119 | }
|
117 | 120 |
|
| 121 | + private void init() { |
| 122 | + instrumentInetAddress(); |
| 123 | + } |
| 124 | + |
| 125 | + private void instrumentInetAddress() { |
| 126 | + InetAddressClassFileTransformer transformer = new InetAddressClassFileTransformer(); |
| 127 | + instrumentation.addTransformer(transformer, true); |
| 128 | + |
| 129 | + try { |
| 130 | + Class<?> clazz = Class.forName("java.net.InetAddress", false, null); |
| 131 | + if (transformer.transformed) { |
| 132 | + // InetAddress was loaded and got transformed |
| 133 | + return; |
| 134 | + } |
| 135 | + // InetAddress was already loaded before we set up transformer |
| 136 | + instrumentation.retransformClasses(clazz); |
| 137 | + } catch (ClassNotFoundException | UnmodifiableClassException ignore) { |
| 138 | + // ignore |
| 139 | + } finally { |
| 140 | + instrumentation.removeTransformer(transformer); |
| 141 | + } |
| 142 | + } |
| 143 | + |
118 | 144 | @SuppressWarnings("SystemOut")
|
119 | 145 | private static void logUnrecognizedLoggerImplWarning(String loggerImplementationName) {
|
120 | 146 | System.err.println(
|
@@ -180,4 +206,117 @@ public void visitCode() {
|
180 | 206 | return hookInserted ? cw.toByteArray() : null;
|
181 | 207 | }
|
182 | 208 | }
|
| 209 | + |
| 210 | + private static class InetAddressClassFileTransformer implements ClassFileTransformer { |
| 211 | + boolean hookInserted = false; |
| 212 | + boolean transformed = false; |
| 213 | + boolean wrapperMethodCreated = false; |
| 214 | + |
| 215 | + private static void createWrapperMethod(ClassWriter cw) { |
| 216 | + /* |
| 217 | + private static boolean isAgentAndVmBooted(); |
| 218 | + Code: |
| 219 | + 0: invokestatic #X // Method io/opentelemetry/javaagent/bootstrap/AgentInitializer/isAgentStarted:()Z |
| 220 | + 3: ifeq 16 |
| 221 | + 6: invokestatic #Y // Method jdk/internal/misc/VM.isBooted:()Z |
| 222 | + 9: ifeq 16 |
| 223 | + 12: iconst_1 |
| 224 | + 13: goto 17 |
| 225 | + 16: iconst_0 |
| 226 | + 17: ireturn |
| 227 | + */ |
| 228 | + |
| 229 | + String descriptor = Type.getMethodDescriptor(Type.BOOLEAN_TYPE); |
| 230 | + Label elseLabel = new Label(); |
| 231 | + Label endLabel = new Label(); |
| 232 | + |
| 233 | + MethodVisitor mv = |
| 234 | + cw.visitMethod( |
| 235 | + Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, |
| 236 | + "isAgentAndVmBooted", |
| 237 | + descriptor, |
| 238 | + null, |
| 239 | + null); |
| 240 | + mv.visitCode(); |
| 241 | + |
| 242 | + mv.visitMethodInsn( |
| 243 | + Opcodes.INVOKESTATIC, |
| 244 | + Type.getInternalName(AgentInitializer.class), |
| 245 | + "isAgentStarted", |
| 246 | + descriptor, |
| 247 | + false); |
| 248 | + mv.visitJumpInsn(Opcodes.IFEQ, elseLabel); |
| 249 | + mv.visitMethodInsn( |
| 250 | + Opcodes.INVOKESTATIC, "jdk/internal/misc/VM", "isBooted", descriptor, false); |
| 251 | + mv.visitJumpInsn(Opcodes.IFEQ, elseLabel); |
| 252 | + mv.visitInsn(Opcodes.ICONST_1); |
| 253 | + mv.visitJumpInsn(Opcodes.GOTO, endLabel); |
| 254 | + mv.visitLabel(elseLabel); |
| 255 | + mv.visitInsn(Opcodes.ICONST_0); |
| 256 | + mv.visitLabel(endLabel); |
| 257 | + mv.visitInsn(Opcodes.IRETURN); |
| 258 | + |
| 259 | + mv.visitMaxs(0, 0); |
| 260 | + mv.visitEnd(); |
| 261 | + } |
| 262 | + |
| 263 | + @Override |
| 264 | + public byte[] transform( |
| 265 | + ClassLoader loader, |
| 266 | + String className, |
| 267 | + Class<?> classBeingRedefined, |
| 268 | + ProtectionDomain protectionDomain, |
| 269 | + byte[] classfileBuffer) { |
| 270 | + if (!"java/net/InetAddress".equals(className)) { |
| 271 | + return null; |
| 272 | + } |
| 273 | + transformed = true; |
| 274 | + ClassReader cr = new ClassReader(classfileBuffer); |
| 275 | + ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS); |
| 276 | + ClassVisitor cv = |
| 277 | + new ClassVisitor(AsmApi.VERSION, cw) { |
| 278 | + @Override |
| 279 | + public MethodVisitor visitMethod( |
| 280 | + int access, String name, String descriptor, String signature, String[] exceptions) { |
| 281 | + MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); |
| 282 | + // We don't want to patch "jdk.internal.misc.VM.isBooted" call in our wrapper |
| 283 | + if ("isAgentAndVmBooted".equals(name)) { |
| 284 | + return mv; |
| 285 | + } |
| 286 | + return new MethodVisitor(api, mv) { |
| 287 | + @Override |
| 288 | + public void visitMethodInsn( |
| 289 | + int opcode, |
| 290 | + String ownerClassName, |
| 291 | + String methodName, |
| 292 | + String descriptor, |
| 293 | + boolean isInterface) { |
| 294 | + if ("jdk/internal/misc/VM".equals(ownerClassName) |
| 295 | + && "isBooted".equals(methodName)) { |
| 296 | + // Create wrapper method only once |
| 297 | + if (!wrapperMethodCreated) { |
| 298 | + createWrapperMethod(cw); |
| 299 | + wrapperMethodCreated = true; |
| 300 | + } |
| 301 | + super.visitMethodInsn( |
| 302 | + Opcodes.INVOKESTATIC, |
| 303 | + "java/net/InetAddress", |
| 304 | + "isAgentAndVmBooted", |
| 305 | + "()Z", |
| 306 | + isInterface); |
| 307 | + hookInserted = true; |
| 308 | + } else { |
| 309 | + super.visitMethodInsn( |
| 310 | + opcode, ownerClassName, methodName, descriptor, isInterface); |
| 311 | + } |
| 312 | + } |
| 313 | + }; |
| 314 | + } |
| 315 | + }; |
| 316 | + |
| 317 | + cr.accept(cv, 0); |
| 318 | + |
| 319 | + return hookInserted ? cw.toByteArray() : null; |
| 320 | + } |
| 321 | + } |
183 | 322 | }
|
0 commit comments