Class Transformer

java.lang.Object
org.jboss.byteman.agent.Transformer
All Implemented Interfaces:
ClassFileTransformer
Direct Known Subclasses:
Retransformer

public class Transformer extends Object implements ClassFileTransformer
byte code transformer used to introduce byteman events into JBoss code
  • Field Details

    • BYTEMAN_PACKAGE_PREFIX

      public static final String BYTEMAN_PACKAGE_PREFIX
      prefix for byteman package
      See Also:
    • BYTEMAN_TEST_PACKAGE_PREFIX

      public static final String BYTEMAN_TEST_PACKAGE_PREFIX
      prefix for byteman test package
      See Also:
    • BYTEMAN_SAMPLE_PACKAGE_PREFIX

      public static final String BYTEMAN_SAMPLE_PACKAGE_PREFIX
      prefix for byteman sample package
      See Also:
    • JAVA_LANG_PACKAGE_PREFIX

      public static final String JAVA_LANG_PACKAGE_PREFIX
      prefix for org.jboss package
      See Also:
    • VERBOSE

      public static final String VERBOSE
      system property set (to any value) in order to switch on dumping of generated bytecode to .class files
      See Also:
    • DUMP_CFG_PARTIAL

      public static final String DUMP_CFG_PARTIAL
      system property set (to any value) in order to switch on dumping of control flow graph for trigger method at each stage of construction
      See Also:
    • DUMP_CFG

      public static final String DUMP_CFG
      system property set (to any value) in order to switch on dumping of control flow graph for triger method after construction
      See Also:
    • DEBUG

      public static final String DEBUG
      system property set (to any value) in order to switch on debug statements in the default Helper
      See Also:
    • AGENT_VERSION

      public static final String AGENT_VERSION
      system property set to record the currently installed Byteman agent's version
      See Also:
    • COMPILE_TO_BYTECODE_COMPATIBILITY

      public static final String COMPILE_TO_BYTECODE_COMPATIBILITY
      retained for compatibility
      See Also:
    • COMPILE_TO_BYTECODE

      public static final String COMPILE_TO_BYTECODE
      system property set (to any value) in order to switch on compilation of rules and left unset if rules are to be interpreted.
      See Also:
    • DUMP_GENERATED_CLASSES

      public static final String DUMP_GENERATED_CLASSES
      system property set (to any value) in order to switch on dumping of generated bytecode to .class files
      See Also:
    • DUMP_GENERATED_CLASSES_INTERMEDIATE

      public static final String DUMP_GENERATED_CLASSES_INTERMEDIATE
      system property set (to any value) in order to switch on dumping of intermediate generated bytecode to .class files
      See Also:
    • DUMP_GENERATED_CLASSES_DIR

      public static final String DUMP_GENERATED_CLASSES_DIR
      system property identifying directory in which to dump generated bytecode .class files
      See Also:
    • TRANSFORM_ALL

      public static final String TRANSFORM_ALL
      system property set to true in order to enable transform of java.lang classes
      See Also:
    • TRANSFORM_ALL_COMPATIBILITY

      public static final String TRANSFORM_ALL_COMPATIBILITY
      retained for compatibility
      See Also:
    • SKIP_OVERRIDE_RULES

      public static final String SKIP_OVERRIDE_RULES
      system property which turns off injection into overriding methods
      See Also:
    • SYSPROPS_STRICT_MODE

      public static final String SYSPROPS_STRICT_MODE
      system property which enables the restriction that only byteman specific system properties will be gettable/settable via a client using the LISTSYSPROPS and SETSYSPROPS commands.
      See Also:
    • VERIFY_TRANSFORMED_BYTES

      public static final String VERIFY_TRANSFORMED_BYTES
      system property which enables the restriction that only byteman specific system properties will be gettable/settable via a client using the LISTSYSPROPS and SETSYSPROPS commands.
      See Also:
    • ALLOW_CONFIG_UPDATE

      public static final String ALLOW_CONFIG_UPDATE
      system property which determines whether or not byteman configuration can be updated at runtime via the byteman agent listener
      See Also:
    • DISALLOW_DOWNCAST

      public static final String DISALLOW_DOWNCAST
      system property which disables downcasts in bindings
      See Also:
    • blacklisted

      private HashSet<String> blacklisted
      hash set naming blacklisted methods we refuse to inject into
    • inst

      protected final Instrumentation inst
      the instrumentation interface to the JVM
    • accessEnabler

      AccessEnabler accessEnabler
      an object we use to enable access to reflective fields where needed
    • isRedefine

      protected boolean isRedefine
      true if the instrumentor allows redefinition
    • scriptRepository

      protected final ScriptRepository scriptRepository
      a mapping from target class names which appear in rules to a script object holding the rule details
    • checkerCache

      protected final CheckerCache checkerCache
    • helperManager

      protected final HelperManager helperManager
      a manager for helper lifecycle events which can be safely handed on to rules
    • verbose

      private static boolean verbose
      switch to control verbose output during rule processing
    • dumpCFGPartial

      private static boolean dumpCFGPartial
      switch to control control flow graph output during rule processing
    • dumpCFG

      private static boolean dumpCFG
      switch to control control flow graph output during rule processing
    • debug

      private static boolean debug
      switch to control debug output during rule processing
    • compileToBytecode

      private static boolean compileToBytecode
      switch to control whether rules are compiled to bytecode or not
    • skipOverrideRules

      private static boolean skipOverrideRules
      switch to control whether rules are injected into overriding methods
    • dumpGeneratedClasses

      private static boolean dumpGeneratedClasses
      switch to control dumping of generated bytecode to .class files
    • dumpGeneratedClassesIntermediate

      private static boolean dumpGeneratedClassesIntermediate
      switch to control dumping of generated bytecode to .class files
    • dumpGeneratedClassesDir

      private static String dumpGeneratedClassesDir
      directory in which to dump generated bytecode .class files (defaults to "."
    • transformAll

      private static boolean transformAll
      switch to control whether transformations will be applied to java.lang.* classes
    • verifyTransformedBytes

      private static boolean verifyTransformedBytes
      switch to control whether we attempt to verify transformed bytecode before returning it by consructing a temporary class from it.
    • disallowDowncast

      private static boolean disallowDowncast
      switch which determines whether downcasts in binding initialisations are disallowed
    • allowConfigUpdate

      private static boolean allowConfigUpdate
      master switch which determines whether or not config values can be updated
    • configLock

      private static Object configLock
      lock object used to control getters and setters when allowConfigUpdate is true
    • isEnabled

      private static ThreadLocal<Integer> isEnabled
      Thread local holding a per thread Boolean which is true if triggering is disabled and false if triggering is enabled
    • DISABLED_USER

      private static final Integer DISABLED_USER
    • DISABLED

      private static final Integer DISABLED
    • ENABLED

      private static final Integer ENABLED
  • Constructor Details

    • Transformer

      public Transformer(Instrumentation inst, ModuleSystem moduleSystem, List<String> scriptPaths, List<String> scriptTexts, boolean isRedefine) throws Exception
      constructor allowing this transformer to be provided with access to the JVM's instrumentation implementation
      Parameters:
      inst - the instrumentation object used to interface to the JVM
      moduleSystem - the module system to use in transformation
      scriptPaths - list of file paths for each input script
      scriptTexts - the text of each input script
      isRedefine - true if class redefinition is allowed false if not
      Throws:
      Exception - if a script is in error
  • Method Details

    • installBootScripts

      public void installBootScripts() throws Exception
      ensure that scripts which apply to classes loaded before registering the transformer are installed by retransforming the relevant classes
      Throws:
      Exception - if the retransform fails
    • installPolicy

      public void installPolicy()
    • transform

      public byte[] transform(ClassLoader originalLoader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException
      The implementation of this method may transform the supplied class file and return a new replacement class file. Once a transformer has been registered with Instrumentation.addTransformer, the transformer will be called for every new class definition and every class redefinition. The request for a new class definition is made with ClassLoader.defineClass. The request for a class redefinition is made with Instrumentation.redefineClasses or its native equivalents. The transformer is called during the processing of the request, before the class file bytes have been verified or applied. If the implementing method determines that no transformations are needed, it should return null. Otherwise, it should create a new byte[] array, copy the input classfileBuffer into it, along with all desired transformations, and return the new array. The input classfileBuffer must not be modified. In the redefine case, the transformer must support the redefinition semantics. If a class that the transformer changed during initial definition is later redefined, the transformer must insure that the second class output class file is a legal redefinition of the first output class file. If the transformer believes the classFileBuffer does not represent a validly formatted class file, it should throw an IllegalClassFormatException. Subsequent transformers will still be called and the load or redefine will still be attempted. Throwing an IllegalClassFormatException thus has the same effect as returning null but facilitates the logging or debugging of format corruptions.
      Specified by:
      transform in interface ClassFileTransformer
      Parameters:
      originalLoader - the defining loader of the class to be transformed, may be null if the bootstrap loader
      className - the name of the class in the internal form of fully qualified class and interface names as defined in The Java Virtual Machine Specification. For example, "java/util/List".
      classBeingRedefined - if this is a redefine, the class being redefined, otherwise null
      protectionDomain - the protection domain of the class being defined or redefined
      classfileBuffer - the input byte buffer in class file format - must not be modified
      Returns:
      a well-formed class file buffer (the result of the transform), or null if no transform is performed.
      Throws:
      IllegalClassFormatException - if the input does not represent a well-formed class file
      See Also:
    • disableTriggers

      public static boolean disableTriggers(boolean isUser)
      disable triggering of rules inside the current thread
      Parameters:
      isUser - true if this was called by rule code false if called internally by Byteman
      Returns:
      true if triggering was previously enabled and false if it was already disabled
    • enableTriggers

      public static boolean enableTriggers(boolean isReset)
      enable triggering of rules inside the current thread
      Parameters:
      isReset - true if this was called by rule code and hence should reset a setting enabled by rule code false if called internally by Byteman and hence should nto reset a setting enabled by rule code
      Returns:
      true if triggering was previously enabled and false if it was already disabled
    • isTriggeringEnabled

      public static boolean isTriggeringEnabled()
      check if triggering of rules is enabled inside the current thread
      Returns:
      true if triggering is enabled and false if it is disabled
    • isVerbose

      public static boolean isVerbose()
      check whether verbose mode for rule processing is enabled or disabled
      Returns:
      true if verbose mode is enabled etherwise false
    • isDumpCFG

      public static boolean isDumpCFG()
      check whether dumping of the control flow graph for the trigger class is enabled
      Returns:
      true if dumping is enabled etherwise false
    • isDumpCFGPartial

      public static boolean isDumpCFGPartial()
      check whether dumping of the control flow graph for the trigger class during construction is enabled
      Returns:
      true if dumping is enabled etherwise false
    • isDumpGeneratedClasses

      protected static boolean isDumpGeneratedClasses()
    • getDumpGeneratedClassesDir

      protected static String getDumpGeneratedClassesDir()
    • isDumpGeneratedClassesIntermediate

      protected static boolean isDumpGeneratedClassesIntermediate()
    • isDebug

      public static boolean isDebug()
      check whether debug mode for rule processing is enabled or disabled
      Returns:
      true if debug mode is enabled or verbose mode is enabled otherwise false
    • isCompileToBytecode

      public static boolean isCompileToBytecode()
      check whether compilation of rules is enabled or disabled
      Returns:
      true if compilation of rules is enabled etherwise false
    • disallowDowncast

      public static boolean disallowDowncast()
      check whether downcasts in bindings are disallowed.
      Returns:
      true if downcasts in bindings are disallowed otherwise false
    • skipOverrideRules

      public boolean skipOverrideRules()
      check whether compilation of rules is enabled or disabled
      Returns:
      true if compilation of rules is enabled otherwise false
    • allowConfigUpdate

      public static boolean allowConfigUpdate()
      check whether changes to org.jboss.byteman.* system properties will affect the agent configuration.
      Returns:
      true if changes will affect the agent configuration otherwise false
    • updateConfiguration

      public void updateConfiguration(String property)
      notify a change to an org.jboss.byteman.* system property so that the agent can choose to update its configuration. n.b. this method is not synchronized because there is an implicit assumption that it is called from the the listener thread immediately after it has updated the property and that no other thread will modify org.jboss.byteman.* properties
      Parameters:
      property - an org.jboss.byteman.* system property which has been updated.
    • isTransformable

      protected boolean isTransformable(String className)
      test whether a class with a given name is a potential candidate for insertion of event notifications
      Parameters:
      className - name of the class to test
      Returns:
      true if a class is a potential candidate for insertion of event notifications otherwise return false
    • maybeDumpClassIntermediate

      public static void maybeDumpClassIntermediate(String fullName, byte[] bytes)
    • maybeDumpClass

      public static void maybeDumpClass(String fullName, byte[] bytes)
    • transform

      public byte[] transform(RuleScript ruleScript, ClassLoader loader, String className, byte[] targetClassBytes)
      The routine which actually does the real bytecode transformation. this is public because it needs to be callable from the type checker script. In normal running the javaagent is the only class which has a handle on the registered transformer so it is the only one which can reach this point.
      Parameters:
      ruleScript - the script
      loader - the loader of the class being injected into
      className - the name of the class being injected into
      targetClassBytes - the current class bytecode
      Returns:
      the transformed bytecode or NULL if no transform was applied
    • isSkipClass

      protected boolean isSkipClass(Class<?> clazz)
      check whether a class should not be considered for transformation
      Parameters:
      clazz - the class to check
      Returns:
      true if clazz should not be considered for transformation otherwise false
    • tryTransform

      private byte[] tryTransform(byte[] buffer, String name, ClassLoader loader, String key, boolean isInterface)
    • tryTransform

      private byte[] tryTransform(byte[] buffer, String name, ClassLoader loader, String key, boolean isInterface, boolean isOverride)
    • dumpScript

      protected void dumpScript(RuleScript ruleScript)
    • isTransformed

      private boolean isTransformed(Class clazz, String name, boolean isInterface)
    • getClassChecker

      private ClassChecker getClassChecker(byte[] bytecode)
      return a checker object which can be used to retrieve the super and interfaces of a class from its defining bytecode
      Parameters:
      bytecode -
      Returns:
      a checker
    • getClassChecker

      public ClassChecker getClassChecker(String name, ClassLoader baseLoader)
      return a checker object which can be used to retrieve the super and interfaces of a class from its name and classloader without forcing a load of the class.
      Parameters:
      name - the name of the superclass being checked
      baseLoader - the class loader of the subclass's bytecode
      Returns:
      the requisite checker or null if the class does not need to be checked or cannot be loaded
    • initBlackList

      private HashSet<String> initBlackList()
      init method to create hash set naming blacklisted methods we refuse to inject into
      Returns:
      the hash set
    • isBlacklisted

      public boolean isBlacklisted(String triggerClassName, String targetMethodName, String targetDescriptor)
      check whether we are unwilling to inject into a given target method
      Parameters:
      triggerClassName - the name of the target class
      targetMethodName - the name of the target method
      targetDescriptor - the descriptor of the target method ignored at present
      Returns:
      true if we are unwilling to inject into the target method
    • maybeVerifyTransformedBytes

      private byte[] maybeVerifyTransformedBytes(ClassLoader loader, String classname, ProtectionDomain protectionDomain, byte[] bytes)
      return the result from calling verifyTransformedBytes if verification is enabled otherwise just return the supplied bytecode
      Parameters:
      loader -
      classname -
      protectionDomain -
      bytes -
      Returns:
      the verified bytecode or the original
    • verifyTransformedBytes

      private byte[] verifyTransformedBytes(ClassLoader loader, String classname, ProtectionDomain protectionDomain, byte[] bytes)
      verify the supplied bytecode by converting it to a class and calling newInstance with no args to instantiate. since not all transformed classes have an empty constructor this should only be enabled for testing of Byteman itself in cases where a transformed class is known to have an empty constructor.
      Parameters:
      loader -
      classname -
      protectionDomain -
      bytes -
      Returns:
      the supplied bytecode if verification succeeds or null if it fails
    • isBytemanClass

      public static boolean isBytemanClass(String className)
      test whether a class with a given name is located in the byteman package
      Parameters:
      className - the name to be checked
      Returns:
      true if a class is located in the byteman package otherwise return false
    • computeVerbose

      private static boolean computeVerbose()
    • computeDumpCFGPartial

      private static boolean computeDumpCFGPartial()
    • computeDumpCFG

      private static boolean computeDumpCFG()
    • computeDebug

      private static boolean computeDebug()
    • computeCompileToBytecode

      private static boolean computeCompileToBytecode()
    • computeSkipOverrideRules

      private static boolean computeSkipOverrideRules()
    • computeDumpGeneratedClasses

      public static boolean computeDumpGeneratedClasses()
    • computeDumpGeneratedClassesIntermediate

      public static boolean computeDumpGeneratedClassesIntermediate()
    • computeDumpGeneratedClassesDir

      public static String computeDumpGeneratedClassesDir()
    • computeTransformAll

      private static boolean computeTransformAll()
    • computeVerifyTransformedBytes

      private static boolean computeVerifyTransformedBytes()
    • computeDisallowDowncast

      private static boolean computeDisallowDowncast()
    • checkConfiguration

      private void checkConfiguration(String property)
    • dumpClass

      private static void dumpClass(String fullName, byte[] bytes)
    • dumpClass

      private static void dumpClass(String fullName, byte[] bytes, boolean intermediate)
    • ensureDumpDirectory

      private static boolean ensureDumpDirectory(String fileName)
    • setAgentVersion

      private void setAgentVersion() throws Exception
      Throws:
      Exception