ASM: A Bytecode Manipulation Tool – A brief Overview Course : CSE 6329 Spring 2011 University of Texas at Arlington • Presented by • Sarker Tanveer Ahmed Rumee Acknowledgement • All the tables and figures of this presentation was copied from the publicly available ASM- Guide from the ASM website. http://asm.ow2.org/ • Some contents were also copied from the ASM 2.0 tutorial. http://asm.ow2.org/doc/tutorial-asm-2.0.html What is ASM? • ASM is an all purpose Java Bytecode manipulation and analysis framework. • It can be used to modify existing classes or dynamically generate classes, directly in binary form. Where to find? • The ASM Home Page – http://asm.ow2.org/ – It contains the ASM library for download – Also has links to documents and other resources – To download the current stable version of ASM library go to the following link: • http://forge.ow2.org/project/showfiles.php?group_id= 23&release_id=4412 Online Documentation and Resources • ASM Guide [API Reference and Detail Discussion about the use of ASM]. – http://download.forge.objectweb.org/asm/asmguide.pdf • API Reference – http://asm.ow2.org/asm33/javadoc/user/index.ht ml Bytecode Outline Plugin • Start Eclipse • Go to: Help->Install new software • In the Location bar enter the following address: – http://download.forge.objectweb.org/eclipseupdate/ – It will show available updates – Select the Bytecode Outline and rest of the steps are trivial A Very short Overview of JAVA Class File Format Structure of Compiled Java Class Few Facts • Compiled class describes only one class where a source file may contain several classes • Compiled class does not contain comments • A compiled class does not contain package and import section, so all type names must be fully qualified. For example: – Fully Qualified name of String is java/lang/String • NB: In this form Dots (.) are replaced by Slash (/) Few Facts (Contd..) • Internal names are used for class and interface types. Internal name is nothing but the fully qualified name of the class/interface. • In all other situations java types are represented in compiled classes with type descriptors. Type Descriptors Method Descriptors ASM Framework • The ASM bytecode manipulation framework is written in Java and uses a visitor-based approach. • Allows developers to avoid dealing directly with a class constant pool and offsets within method byte code. • Provides better performance, compared to other tools such as BCEL, SERP, orJavassist. ASM package structure • ASM is divided into several packages. The package structure is : ASM package structure (Contd..) • The Core package provides an API to read, write, and transform Java bytecode and defines a foundation for the other packages. This package is sufficient to generate Java bytecode and to implement the majority of bytecode transformations. • The Tree package provides in-memory representation of Java bytecode. • The Analysis package provides basic data-flow analyses and type-checking algorithms for Java method bytecode stored in structures from the tree package. • The Commons package (added in ASM 2.0) provides several commonly used bytecode transformations and adapters to simplify bytecode generation. • The Util package contains several helper classes and simple bytecode verifiers that can help in development or testing. • The XML package provides an adapter to convert bytecode structures to and from XML CORE PAKCAGE The Core Package • The Core package uses a push approach (similar to the "Visitor" design pattern) to walk trough complex bytecode structures. • ASM defines several interfaces, such as ClassVisitor , FieldVisitor , MethodVisitor and AnnotationVisitor. • These interfaces interact with each other to implement bytecode transformations and/or capture information from the bytecode. Core package [cont..] • The Core package can be logically divided into two major parts: – Bytecode producers, such as a ClassReader or a custom class that can fire the proper sequence of calls to the methods of the above visitor classes. – Bytecode consumers, such as writers (ClassWriter, FieldWriter, MethodWriter, and AnnotationWriter), adapters (ClassAdapter and MethodAdapter), or any other classes implementing the above visitor interfaces. Visitor Design Pattern • ASM follows the Visitor Design Pattern for its operation. • To understand how it works we need to investigate how the Visitor Design Pattern fits in Object Oriented Programming. Visitor Design Pattern • In object-oriented programming and software engineering, the visitor design pattern is a way of separating an algorithm from an object structure it operates on. • A practical result of this separation is the ability to add new operations to existing object structures without modifying those structures. The participating classes Visitor - This is an interface used to declare the visit operations for all the types of visitable classes. Usually the name of the operation is the same and the operations are differentiated by the method signature. ConcreteVisitor - An implementation of Visitor that implements all the visit method Visitable - is an abstraction which declares the accept operation. This is the entry point which enables an object to be "visited" by the visitor object. ConcreteVisitable - Those classes implementing the Visitable interface or a class and defines the accept operation. Visitor Design Pattern [cont..] • We want to add “print” method for each of the following classes representing different parts of a Car – Wheel, Engine, and Body – Instead of creating "print" methods for each subclass (Wheel, Engine, Body), a single class (CarElementPrintVisitor) will be used to perform the required printing action Example interface CarElementVisitor { void visit(Wheel wheel); void visit(Engine engine); void visit(Body body); } Visitor Visitable interface CarElement { void accept(CarElementVisitor visitor); // CarElements have to provide accept(). } class Wheel implements CarElement { public void accept(CarElementVisitor visitor) { visitor.visit(this); } } Concrete Visitables class Engine implements CarElement { public void accept(CarElementVisitor visitor) { visitor.visit(this); } } class Body implements CarElement { accept(..) {} } class CarElementPrintVisitor implements CarElementVisitor { public void visit(Wheel wheel) { System.out.println("Visiting wheel"); } Concrete Visitor public void visit(Engine engine) { System.out.println("Visiting engine"); } public void visit(Body body) { System.out.println("Visiting body"); } } public class VisitorDemo { static public void main(String[] args){ Wheel ob1 = new Wheel(); Body ob2 = new Body(); Engine ob3 = new Engine(); ob1.accept(new CarElementVisitor()); ob2.accept(new CarElementVisitor()); ob3.accept(new CarElementVisitor()); } } Using ASM API to write Code • ASM API for generating and transforming compiled classes is based on ClassVisitor interface. • Each method of this interface correspond to the class file structure described earlier • The ClassVisitor interface is depicted in the next slide. ClassVisitor Interface ClassVisitor (cont..) • Simple sections of a class are visited by a single method call and it returns void • Sections whose content can be of arbitrary length are visited with a initial method call that returns an auxiliary interface. This happens for visitAnnotation, visitField and visitMethod. • The auxiliary visitor interfaces will be described later. How it works • A client application creates ClassReader and calls the accept() method, passing a concrete ClassVisitor instance as a parameter. • Then ClassReader parses the class and fires "visit" events to ClassVisitor for each bytecode fragment • For repeated contexts, such as fields, methods, or annotations, a ClassVisitor may create child visitors derived from the corresponding interface (FieldVisitor,MethodVisitor, or AnnotationVisitor) and return them to the producer. • The methods of the ClassVisitor interface must be called in the following order: visit visitSource? visitOuterClass? (visitAnnotation | visitAttribute) * (visitInnerClass | visitField | visit Method )* visitEnd Three Core Components • ASM provides three core components based on ClassVisitor interface in order to generate and transform classes. These are: – ClassReader – ClassWriter – ClassAdapter Three Main tasks of ASM Tool • Parse a class • Generate a class • Transform a class – We discuss these three tasks in light of the three core components depicted in the previous class. Parsing Classes • Only required component to parse and existing class is the ClassReader • It does so by calling the corresponding visitXxx methods on ClassVisitor instance passed as an argument to its accept method. • Let’s see an example how it works. Parsing a Class using ClassReader • Example: Generating Classes • The only required component – ClassWriter • It is an implementation of the ClassVisitor interface that builds compiled classes directly in binary form. • It produce as output a byte array that contains the compiled class • Lets’ see and example: Generating Classes (cont..) • Consider the following interface Generating Classes (cont..) • The Above interface can be generated with 6 method calls to a ClassVisitor • Lets’ see the example.. Transforming classes • So far we have used ClassReader and ClassWriter separately. • The events were produced by “hand ” and consumed directly by a ClassWriter or, Symmetrically, or Events were produced by ClassReader and consumed by “hand”. i.e, by a custom ClassVisitor implementation. Transforming Classes (cont..) • Now we want to use both ClassReader and ClassWriter together. • The first step would be to direct the events produced by a ClassReader to a ClassWriter, the result is that the class parsed by the ClassReader is reconstructed by the ClassWriter Transforming Classes (cont..) • So the corresponding code fragment will be: Introduction of ClassAdapter • Now we introduce a middle entity named ClassAdapter. The idea will be: ClassAdapter (cont..) ClassAdapter (cont..) • According to the code fragment depicted above the outcome does not change, because the ClassAdapter does not filter anything • But now we can easily filter some events using the ClassAdapter to Transform a class. Example on Class Transformation Conclusion • We have discussed so far three basic operations that can be done by ASM • But ASM library has a large collection of useful API to help analysis Compiled java classes in great detail. • The ASM –GUIDE is very good resource in this regard. Questions??