Search in sources :

Example 1 with PackageWeaveResult

use of com.newrelic.weave.weavepackage.PackageWeaveResult in project newrelic-java-agent by newrelic.

the class InstrumentingClassLoader method transform.

@Override
protected byte[] transform(String className) throws Exception {
    byte[] classBytes = WeaveUtils.getClassBytesFromClassLoaderResource(className, this);
    if (classBytes == null) {
        return null;
    }
    final InstrumentationContext context = new InstrumentationContext(classBytes, null, null);
    new ClassReader(classBytes).accept(new ScalaTraitMatcher().newClassMatchVisitor(null, null, null, null, context), ClassReader.SKIP_FRAMES);
    // weave
    byte[] weaved = weave(className, classBytes, context.getSkipMethods(), new ClassWeavedListener() {

        @Override
        public void classWeaved(PackageWeaveResult weaveResult, ClassLoader classloader, ClassCache cache) {
            if (weaveResult.weavedClass()) {
                final String packageName = weaveResult.getValidationResult().getWeavePackage().getName();
                for (String originalName : weaveResult.getWeavedMethods().keySet()) {
                    for (Method method : weaveResult.getWeavedMethods().get(originalName)) {
                        context.addWeavedMethod(method, packageName);
                    }
                    ClassWeaverService.addTraceInformation(InstrumentingClassLoader.this.tracedWeaveInstrumentationDetails, packageName, context, weaveResult.getComposite(), originalName);
                }
                try {
                    Map<String, byte[]> annotationProxyClasses = weaveResult.getAnnotationProxyClasses();
                    if (!annotationProxyClasses.isEmpty()) {
                        // Special case for annotation weaving in order to support dynamic annotation proxies. We
                        // need to add the dynamic proxy classes that we created to the current classloader here
                        NewClassAppender.appendClasses(classloader, annotationProxyClasses);
                    }
                } catch (Exception e) {
                    Agent.LOG.log(Level.FINE, e, "Unable to add annotation proxy classes");
                }
            }
        }
    });
    // trace
    if (weaved != null) {
        classBytes = weaved;
    }
    ClassReader reader = new ClassReader(classBytes);
    if (weaved == null) {
        // process trace annotations for non-weaved code
        reader.accept(new SimpleTraceMatchVisitor(null, context), ClassReader.EXPAND_FRAMES);
    }
    if (!context.isTracerMatch()) {
        if (weaved != null) {
            // printClass(className, weaved);
            return weaved;
        }
        return null;
    }
    NoticeSqlVisitor noticeSqlVisitor = new NoticeSqlVisitor(WeaveUtils.ASM_API_LEVEL);
    // find the noticeSql calls
    reader.accept(noticeSqlVisitor, ClassReader.SKIP_FRAMES);
    String internalClassName = className.replace('.', '/');
    ClassWriter writer = new PatchedClassWriter(ClassWriter.COMPUTE_FRAMES, context.getClassResolver(this));
    ClassVisitor cv = writer;
    cv = new TraceClassVisitor(cv, internalClassName, context, noticeSqlVisitor.getNoticeSqlMethods());
    cv = new ClassVisitor(WeaveUtils.ASM_API_LEVEL, cv) {

        @Override
        public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
            if (version < 49 || version > 100) {
                // Some weird Apache classes have really large versions.
                version = WeaveUtils.RUNTIME_MAX_SUPPORTED_CLASS_VERSION;
            }
            super.visit(version, access, name, signature, superName, interfaces);
        }
    };
    reader.accept(cv, ClassReader.EXPAND_FRAMES);
    byte[] result = writer.toByteArray();
    return result;
}
Also used : InstrumentationContext(com.newrelic.agent.instrumentation.context.InstrumentationContext) ClassWeavedListener(com.newrelic.weave.weavepackage.ClassWeavedListener) PackageWeaveResult(com.newrelic.weave.weavepackage.PackageWeaveResult) Method(com.newrelic.agent.deps.org.objectweb.asm.commons.Method) ClassVisitor(com.newrelic.agent.deps.org.objectweb.asm.ClassVisitor) TraceClassVisitor(com.newrelic.agent.instrumentation.tracing.TraceClassVisitor) IOException(java.io.IOException) PatchedClassWriter(com.newrelic.agent.util.asm.PatchedClassWriter) ClassWriter(com.newrelic.agent.deps.org.objectweb.asm.ClassWriter) TraceClassVisitor(com.newrelic.agent.instrumentation.tracing.TraceClassVisitor) NoticeSqlVisitor(com.newrelic.agent.instrumentation.tracing.NoticeSqlVisitor) ScalaTraitMatcher(com.newrelic.agent.instrumentation.classmatchers.ScalaTraitMatcher) PatchedClassWriter(com.newrelic.agent.util.asm.PatchedClassWriter) ClassReader(com.newrelic.agent.deps.org.objectweb.asm.ClassReader) URLClassLoader(java.net.URLClassLoader) ClassCache(com.newrelic.weave.utils.ClassCache) ConcurrentMap(java.util.concurrent.ConcurrentMap) Map(java.util.Map)

Example 2 with PackageWeaveResult

use of com.newrelic.weave.weavepackage.PackageWeaveResult in project newrelic-java-agent by newrelic.

the class ClassWeaverService method transform.

@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer, final InstrumentationContext context, Match match) throws IllegalClassFormatException {
    if (!PointCutClassTransformer.isValidClassName(className)) {
        return null;
    }
    ClassWeavedListener classWeavedCallback = new ClassWeavedListener() {

        @Override
        public void classWeaved(PackageWeaveResult weaveResult, ClassLoader classloader, ClassCache cache) {
            List<WeaveViolation> violations = weaveResult.getValidationResult().getViolations();
            if (!violations.isEmpty()) {
                // This is due to the nature of annotation weaving happening at weave time instead of validation time
                weaveViolationLogger.logWeaveViolations(weaveResult.getValidationResult(), classloader, false);
                return;
            }
            final String packageName = weaveResult.getValidationResult().getWeavePackage().getName();
            if (Agent.LOG.isFinerEnabled()) {
                try {
                    if (Agent.LOG.isFinerEnabled()) {
                        ClassInformation weavedClass = cache.getClassInformation(weaveResult.getClassName());
                        Agent.LOG.log(Level.FINER, "{0} matched {1}", packageName, weavedClass.className);
                        for (String superName : weavedClass.getAllSuperNames(cache)) {
                            Agent.LOG.log(Level.FINER, "\ts: {0}", superName);
                        }
                        for (String interfaceName : weavedClass.getAllInterfaces(cache)) {
                            Agent.LOG.log(Level.FINER, "\ti: {0}", interfaceName);
                        }
                    }
                } catch (IOException ioe) {
                    Agent.LOG.log(Level.FINEST, ioe, "exception while getting supertype info");
                }
            }
            if (weaveResult.weavedClass()) {
                try {
                    Map<String, byte[]> annotationProxyClasses = weaveResult.getAnnotationProxyClasses();
                    if (!annotationProxyClasses.isEmpty()) {
                        // the dynamic proxy classes that we created to the current classloader at this point
                        if (BootstrapLoader.PLACEHOLDER == classloader) {
                            NewClassAppender.appendClassesToBootstrapClassLoader(instrumentation, annotationProxyClasses);
                        } else {
                            NewClassAppender.appendClasses(classloader, annotationProxyClasses);
                        }
                    }
                } catch (Exception e) {
                    Agent.LOG.log(Level.FINE, e, "Unable to add annotation proxy classes");
                }
                String weaveClassStat = MessageFormat.format(MetricNames.SUPPORTABILITY_WEAVE_CLASS, packageName, weaveResult.getClassName());
                ServiceFactory.getStatsService().doStatsWork(StatsWorks.getRecordMetricWork(weaveClassStat, 1), weaveClassStat);
                for (String originalName : weaveResult.getWeavedMethods().keySet()) {
                    Agent.LOG.log(Level.FINE, "{0}: weaved target {1}-{2}", packageName, classloader, weaveResult.getClassName());
                    for (Method method : weaveResult.getWeavedMethods().get(originalName)) {
                        Agent.LOG.log(Level.FINE, "\t{0}.{1}:{2}", originalName, method.getName(), method.getDescriptor());
                        context.addWeavedMethod(method, packageName);
                    }
                    addTraceInformation(ClassWeaverService.this.tracedWeaveInstrumentationDetails, packageName, context, weaveResult.getComposite(), originalName);
                }
            } else {
                Agent.LOG.log(Level.FINER, "{0} matched class {1} but no methods were weaved.", packageName, weaveResult.getClassName());
            }
        }
    };
    try {
        return weavePackageManager.weave(loader, getClassCache(loader), className, classfileBuffer, context.getSkipMethods(), classWeavedCallback);
    } catch (IOException ioe) {
        throw new RuntimeException(ioe);
    }
}
Also used : ClassWeavedListener(com.newrelic.weave.weavepackage.ClassWeavedListener) ClassInformation(com.newrelic.weave.utils.ClassInformation) PackageWeaveResult(com.newrelic.weave.weavepackage.PackageWeaveResult) WeaveViolation(com.newrelic.weave.violation.WeaveViolation) IOException(java.io.IOException) Method(org.objectweb.asm.commons.Method) IllegalClassFormatException(java.lang.instrument.IllegalClassFormatException) IOException(java.io.IOException) ClassCache(com.newrelic.weave.utils.ClassCache)

Example 3 with PackageWeaveResult

use of com.newrelic.weave.weavepackage.PackageWeaveResult in project newrelic-java-agent by newrelic.

the class ClassLoaderClassTransformer method transform.

@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer, final InstrumentationContext context, Match match) throws IllegalClassFormatException {
    if (classloadersToSkip.contains(className)) {
        Agent.LOG.log(Level.FINEST, "ClassLoaderClassTransformer: classloadersToSkip contains {0}", className);
        return null;
    }
    // For any new ClassLoaders that we encounter, we should add them to the map
    if (!observedClassLoaders.containsKey(className)) {
        observedClassLoaders.put(className, classfileBuffer);
    }
    try {
        if (loader == null) {
            loader = BootstrapLoader.PLACEHOLDER;
        }
        Agent.LOG.log(Level.FINER, "ClassLoaderClassTransformer transforming: {0} -- {1}", loader, className);
        // This ClassCache will only consult the map of the observedClassLoaders that we pass in, so
        // we don't need to worry about it possibly using findResource() when we call validate(cache).
        ClassCache cache = new ClassCache(new ClassLoaderClassFinder(observedClassLoaders));
        PackageValidationResult result;
        if (className.equals("java/lang/ClassLoader")) {
            // For "java.lang.ClassLoader" we only want to instrument one of the loadClass() methods
            result = classloaderPackage.validate(cache);
        } else {
            // For every other ClassLoader that extends "java.lang.ClassLoader" we want to instrument both loadClass() methods
            result = classloaderBasePackage.validate(cache);
        }
        if (result.succeeded()) {
            Map<String, byte[]> utilityClassBytes = result.computeUtilityClassBytes(cache);
            if (utilityClassBytes != null && !utilityClassBytes.isEmpty()) {
                // Note: This is a duplication of code from the WeavePackageManager. This is duplicated here because we are
                // not using WeavePackageManager directly.
                NewClassAppender.appendClassesToBootstrapClassLoader(instrumentation, utilityClassBytes);
            }
            // Since we know that this class validated we are assured that this class extends
            // "java.lang.ClassLoader" so we can manually set the super class name to "java/lang/ClassLoader" or
            // to empty if it's the java.lang.ClassLoader instance itself.
            final String[] superNames;
            if (className.equals("java/lang/ClassLoader")) {
                superNames = new String[0];
            } else {
                superNames = new String[] { "java/lang/ClassLoader" };
            }
            Map<Method, Collection<String>> skipMethods = (context != null) ? context.getSkipMethods() : Collections.emptyMap();
            // This applies the "checkPackageAccess" weaved code only if it should be enabled from the constructor above
            byte[] newBytes = classfileBuffer;
            if (checkPackageAccessPackage != null && newBytes != null && className.equals("java/lang/ClassLoader")) {
                PackageValidationResult checkPackageAccessResult = checkPackageAccessPackage.validate(cache);
                if (checkPackageAccessResult.succeeded()) {
                    newBytes = checkPackageAccessResult.weave(className, superNames, new String[0], newBytes, cache, skipMethods).getCompositeBytes(cache);
                } else {
                    logClassLoaderWeaveViolations(checkPackageAccessResult, className);
                }
                if (newBytes == null) {
                    newBytes = classfileBuffer;
                }
            }
            PackageWeaveResult packageWeaveResult = result.weave(className, superNames, new String[0], newBytes, cache, skipMethods);
            // Do the weaving and use our "non-findResource" cache from above
            newBytes = packageWeaveResult.getCompositeBytes(cache);
            if (newBytes != null) {
                Agent.LOG.log(Level.FINE, "ClassLoaderClassTransformer patched {0} -- {1}", loader, className);
                return newBytes;
            }
        } else {
            logClassLoaderWeaveViolations(result, className);
        }
    } catch (Throwable t) {
        Agent.LOG.log(Level.FINE, t, "ClassLoaderClassTransformer unable to instrument classloader {0} -- {1}", loader, className);
    }
    Agent.LOG.log(Level.FINE, "ClassLoaderClassTransformer skipped transformation: {0} -- {1}", loader, className);
    return null;
}
Also used : ClassLoaderClassFinder(com.newrelic.agent.instrumentation.ClassLoaderClassFinder) PackageWeaveResult(com.newrelic.weave.weavepackage.PackageWeaveResult) Collection(java.util.Collection) ClassCache(com.newrelic.weave.utils.ClassCache) PackageValidationResult(com.newrelic.weave.weavepackage.PackageValidationResult) Method(org.objectweb.asm.commons.Method)

Aggregations

ClassCache (com.newrelic.weave.utils.ClassCache)3 PackageWeaveResult (com.newrelic.weave.weavepackage.PackageWeaveResult)3 ClassWeavedListener (com.newrelic.weave.weavepackage.ClassWeavedListener)2 IOException (java.io.IOException)2 Method (org.objectweb.asm.commons.Method)2 ClassReader (com.newrelic.agent.deps.org.objectweb.asm.ClassReader)1 ClassVisitor (com.newrelic.agent.deps.org.objectweb.asm.ClassVisitor)1 ClassWriter (com.newrelic.agent.deps.org.objectweb.asm.ClassWriter)1 Method (com.newrelic.agent.deps.org.objectweb.asm.commons.Method)1 ClassLoaderClassFinder (com.newrelic.agent.instrumentation.ClassLoaderClassFinder)1 ScalaTraitMatcher (com.newrelic.agent.instrumentation.classmatchers.ScalaTraitMatcher)1 InstrumentationContext (com.newrelic.agent.instrumentation.context.InstrumentationContext)1 NoticeSqlVisitor (com.newrelic.agent.instrumentation.tracing.NoticeSqlVisitor)1 TraceClassVisitor (com.newrelic.agent.instrumentation.tracing.TraceClassVisitor)1 PatchedClassWriter (com.newrelic.agent.util.asm.PatchedClassWriter)1 ClassInformation (com.newrelic.weave.utils.ClassInformation)1 WeaveViolation (com.newrelic.weave.violation.WeaveViolation)1 PackageValidationResult (com.newrelic.weave.weavepackage.PackageValidationResult)1 IllegalClassFormatException (java.lang.instrument.IllegalClassFormatException)1 URLClassLoader (java.net.URLClassLoader)1