Commit e610fdbb authored by ebruneton's avatar ebruneton

initial import of BytecodeOutline plugin

parents
******************************* Copyright notice *******************************
Copyright (C)2004 by Andrei Loskutov <Loskutov@gmx.de>. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
********************************************************************************
This program uses ASM framework
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000,2002,2003 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
Manifest-Version: 1.0
Bundle-Name: Bytecode Outline Plug-in
Bundle-SymbolicName: de.loskutov.BytecodeOutline;singleton=true
Bundle-Version: 1.3.1
Bundle-ClassPath: BytecodeOutline.jar,externals/asm-1.5.1.jar,externals/asm-attrs-1.5.1.jar,externals/asm-tree-1.5.1.jar,externals/asm-util-1.5.1.jar
Bundle-Activator: de.loskutov.bco.BytecodeOutlinePlugin
Bundle-Vendor: Andrei Loskutov
Bundle-Localization: plugin
Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
org.eclipse.jface.text,
org.eclipse.core.filebuffers,
org.eclipse.jdt.core,
org.eclipse.ui.editors,
org.eclipse.ui.workbench.texteditor,
org.eclipse.jdt.ui,
org.eclipse.core.resources,
org.eclipse.ui.ide,
org.eclipse.jdt,
org.eclipse.compare
Eclipse-AutoStart: true
Bytecode Outline plugin for Eclipse
-----------------------------------------------------------------
Bytecode Outline plugin shows disassembled bytecode of current java editor or
class file, allows bytecode compare for java/class files and shows ASMifier
code for current bytecode.
Have you already asked yourselves what the compiler does with your Java code?
Here is the answer ;)
The main reason for this plugin was my study how Java generates bytecode and my
interest in ASM framework. ASM is a great, fast and small bytecode manipulation
framework, licensed under the BSD License.
Bytecode Outline is free, see copyright. ASM is also free and parts of them are included to Bytecode Outline plugin distribution. Please visit
http://asm.objectweb.org/index.html to obtain latest information about ASM.
Bytecode Outline currently support only Eclipse default Java editor.
Installation
-----------------------------------------------------------------
All what you need to install Bytecode Outline plugin is to unzip the zip file
into you %Eclipse%/plugin directory and restart Eclipse. You don't need to do
anymore to install Bytecode Outline.
Usage
-----------------------------------------------------------------
Window -> Show View -> Other -> Java -> Bytecode to see bytecode of current
Java editor/ Class file view.
If "Link with editor" is on, then any selection in Java editor will be followed
with selection of appropriated bytecode label, and vice - versa.
Note: this bi-directional selection could only works, if your bytecode contains
source lines/local variables information. Check your compiler setings, if you
are not sure that your compiler generates debug information.
If "show raw bytecode" is off, than local variable names will be shown instead
of indexes, full qualified names replaced with simply class names, and
primitive type abbreviations decoded to readable names.
If "show current element only" is on, then only bytecode of current
field/method node will be shown (if cursor is placed inside field/method name
or body).
Note: some methods with generic types in signature are not shown if "show
current element only" is on. This will be fixed later.
Select two *.class/*.java files -> right click -> Compare with -> Each Other
Bytecode
Select one *.class/*.java file -> right click -> Compare with -> Another Class
Bytecode
to compare bytecode of selected class files. Compare works also for *.class
files included in any referenced *.jar library.
plugin.id de.loskutov.ByteCodeOutline
plugin.version 1.3.1
#Home directory of Eclipse (3.x)
eclipse /usr/local/bin/eclipse3.1M2
\ No newline at end of file
bin.includes = LICENSE.txt,\
README.txt,\
META-INF/,\
externals/,\
icons/,\
plugin.xml
<project name="BytecodeOutline" default="plugin">
<property file="build.config"/>
<property name="src" value="${basedir}/src"/>
<property name="externals" value="${basedir}/externals"/>
<property name="out" value="${basedir}/output"/>
<property name="out.build" value="${out}/build"/>
<property name="out.plugin" value="${out}/plugin"/>
<target name="init">
<path id="classpath">
<fileset dir="${externals}">
<include name="**/*.jar"/>
</fileset>
<fileset dir="${eclipse}">
<include name="plugins/**/*.jar"/>
</fileset>
</path>
</target>
<target name="compile" depends="init">
<mkdir dir="${out.build}"/>
<javac destdir="${out.build}" debug="on">
<classpath refid="classpath"/>
<src path="${src}"/>
<include name="**/*.java"/>
</javac>
</target>
<target name="jars" depends="compile">
<mkdir dir="${out.plugin}"/>
<jar jarfile="${out.plugin}/BytecodeOutline.jar" basedir="${out.build}">
<include name="**/*"/>
<manifest>
<attribute name="Implementation-Title" value="BytecodeOutline"/>
<attribute name="Implementation-Version" value="${plugin.version}"/>
</manifest>
</jar>
<zip zipfile="${out.plugin}/BytecodeOutlinesrc.zip" basedir="${src}">
<include name="**/*"/>
</zip>
</target>
<target name="plugin" depends="jars">
<copy todir="${out.plugin}">
<fileset dir=".">
<include name="externals/**/*"/>
<include name="icons/**/*"/>
<include name="METAINF/**/*"/>
<include name="plugin.xml"/>
<include name="*.txt"/>
</fileset>
</copy>
<zip zipfile="${out}/${plugin.id}_${plugin.version}.zip" basedir="${out.plugin}">
<include name="**/*"/>
</zip>
</target>
<target name="clean">
<delete dir="${out}"/>
</target>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>
<plugin>
<extension
point="org.eclipse.ui.views">
<view
name="Bytecode"
icon="icons/bytecodeview.gif"
category="org.eclipse.jdt.ui.java"
class="de.loskutov.bco.views.BytecodeOutlineView"
id="de.loskutov.bco.views.BytecodeOutlineView"/>
</extension>
<extension
point="org.eclipse.ui.popupMenus">
<objectContribution
objectClass="org.eclipse.jdt.core.IOpenable"
id="de.loskutov.bco.CompareBytecodeActionContribution1">
<visibility>
<or>
<objectClass name="org.eclipse.jdt.core.IClassFile"/>
<objectClass name="org.eclipse.jdt.core.ICompilationUnit"/>
</or>
</visibility>
<menu
label="Compare With ..."
path="additions"
id="compareWithMenu">
<separator
name="compareWithGroup">
</separator>
</menu>
<action
enablesFor="1"
label="Another Class Bytecode"
icon="icons/bytecodeview.gif"
class="de.loskutov.bco.ui.actions.OpenAction"
menubarPath="compareWithMenu/compareWithGroup"
id="de.loskutov.bco.CompareBytecodeAction">
</action>
<action
enablesFor="2"
label="Each Other Bytecode"
icon="icons/bytecodeview.gif"
class="de.loskutov.bco.ui.actions.CompareBytecodeAction"
menubarPath="compareWithMenu/compareWithGroup"
id="de.loskutov.bco.OpenAction">
</action>
</objectContribution>
<objectContribution
objectClass="org.eclipse.core.resources.IFile"
nameFilter="*.class"
id="de.loskutov.bco.CompareBytecodeActionContribution2">
<visibility>
<not>
<or>
<objectClass name="org.eclipse.jdt.core.IClassFile"/>
<objectClass name="org.eclipse.jdt.core.ICompilationUnit"/>
</or>
</not>
</visibility>
<menu
label="Compare With ..."
path="additions"
id="compareWithMenu">
<separator
name="compareWithGroup">
</separator>
</menu>
<action
enablesFor="1"
label="Another Class Bytecode"
icon="icons/bytecodeview.gif"
class="de.loskutov.bco.ui.actions.OpenAction"
menubarPath="compareWithMenu/compareWithGroup"
id="de.loskutov.bco.CompareBytecodeAction">
</action>
<action
enablesFor="2"
label="Each Other Bytecode"
icon="icons/bytecodeview.gif"
class="de.loskutov.bco.ui.actions.CompareBytecodeAction"
menubarPath="compareWithMenu/compareWithGroup"
id="de.loskutov.bco.OpenAction">
</action>
</objectContribution>
</extension>
</plugin>
/*****************************************************************************************
* Copyright (c) 2004 Andrei Loskutov. All rights reserved. This program and the
* accompanying materials are made available under the terms of the BSD License which
* accompanies this distribution, and is available at
* http://www.opensource.org/licenses/bsd-license.php Contributor: Andrei Loskutov -
* initial API and implementation
****************************************************************************************/
package de.loskutov.bco;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
/**
* The main plugin class to be used in the desktop.
*/
public class BytecodeOutlinePlugin extends AbstractUIPlugin {
//The shared instance.
private static BytecodeOutlinePlugin plugin;
//Resource bundle.
private ResourceBundle resourceBundle;
/** asm logo */
public static final String IMG_ASM = "icons/asm.gif"; //$NON-NLS-1$
/**
* The constructor.
*/
public BytecodeOutlinePlugin() {
super();
plugin = this;
try {
resourceBundle = ResourceBundle
.getBundle("de.loskutov.bco.BytecodeOutlinePluginResources"); //$NON-NLS-1$
} catch (MissingResourceException x) {
resourceBundle = null;
}
}
/**
* This method is called upon plug-in activation
* @param context
* @throws Exception
*/
public void start(BundleContext context) throws Exception {
super.start(context);
}
/**
* This method is called when the plug-in is stopped
* @param context
* @throws Exception
*/
public void stop(BundleContext context) throws Exception {
super.stop(context);
}
/**
* Returns the shared instance.
* @return plugin
*/
public static BytecodeOutlinePlugin getDefault() {
return plugin;
}
/**
* Returns the string from the plugin's resource bundle, or 'key' if not found.
* @param key
* @return translation
*/
public static String getResourceString(String key) {
ResourceBundle bundle = BytecodeOutlinePlugin.getDefault()
.getResourceBundle();
try {
return (bundle != null)
? bundle.getString(key)
: key;
} catch (MissingResourceException e) {
return key;
}
}
/**
* Returns the plugin's resource bundle,
*/
private ResourceBundle getResourceBundle() {
return resourceBundle;
}
/**
* Returns the workspace instance.
* @return shell object
*/
public static Shell getShell() {
return getDefault().getWorkbench().getActiveWorkbenchWindow()
.getShell();
}
/**
* @param messageID
* @param error
*/
public static void error(String messageID, Throwable error) {
Shell shell = getShell();
String message = getResourceString("BytecodeOutline.Error"); //$NON-NLS-1$
if (messageID != null) {
message = getResourceString(messageID);
}
message = message + " " + error.getMessage();//$NON-NLS-1$
MessageDialog.openError(
shell, getResourceString("BytecodeOutline.Title"), //$NON-NLS-1$
message);
getDefault().getLog().log(
new Status(IStatus.ERROR, "BytecodeOutline", 0, message, error)); //$NON-NLS-1$
}
/**
* @param error
*/
public static void logError(Throwable error) {
String message = error.getMessage();
if(message == null){
message = error.toString();
}
getDefault().getLog()
.log(
new Status(
IStatus.ERROR,
"BytecodeOutline", 0, message, error)); //$NON-NLS-1$
}
}
\ No newline at end of file
/*****************************************************************************************
* Copyright (c) 2004 Andrei Loskutov. All rights reserved. This program and the
* accompanying materials are made available under the terms of the BSD License which
* accompanies this distribution, and is available at
* http://www.opensource.org/licenses/bsd-license.php Contributor: Andrei Loskutov -
* initial API and implementation
****************************************************************************************/
package de.loskutov.bco.asm;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IInitializer;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.internal.core.BinaryMember;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.TreeClassAdapter;
import org.objectweb.asm.util.ASMifierClassVisitor;
import org.objectweb.asm.util.ASMifierCodeVisitor;
import org.objectweb.asm.util.PrintClassVisitor;
import org.objectweb.asm.util.PrintCodeVisitor;
import de.loskutov.bco.BytecodeOutlinePlugin;
import de.loskutov.bco.ui.JdtUtils;
/**
* @author Andrei
*/
public class AsmUtils {
/**
* Decompiles entire given input stream (with class file) to java bytecode
* @param is java .class file
* @param isRawMode true for "not beautified" output, false for better
* readable output without package information but with resolved local
* variables
* @param isASMifierMode true if we should return not bytecode instructions,
* but ASM instructions that generate bytecode
* @return decompiled bytecode as text or ASMfier java code
* @throws IOException
*/
public static DecompileResult getFullBytecode(InputStream is,
boolean isRawMode, boolean isASMifierMode) throws IOException {
ClassReader cr = new ClassReader(is);
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
if(isASMifierMode){
ASMifierClassVisitor acv = new ASMifierClassVisitor(pw);
cr.accept(acv, PrintClassVisitor.getDefaultAttributes(), false);
} else {
CommentedTraceClassVisitor cv = new CommentedTraceClassVisitor(null, pw);
cv.setRawMode(isRawMode);
TreeClassAdapter treeClassAdapter = new TreeClassAdapter(cv);
cv.setTreeClassAdapter(treeClassAdapter);
cr.accept(treeClassAdapter, PrintClassVisitor.getDefaultAttributes(), false);
}
pw.flush();
return new DecompileResult(sw.toString());
}
/**
* Decompiles a part of given input stream (with class file) to java bytecode
* @param is
* @param javaElement java element to decompile
* @param isRawMode true for "not beautified" output, false for better
* readable output without package information but with resolved local
* variables
* @param isASMifierMode true if we should return not bytecode instructions,
* but ASM instructions that generate bytecode
* @return decompiled bytecode as text or ASMfier java code
* @throws IOException
*/
public static DecompileResult getBytecode(InputStream is,
IJavaElement javaElement,
boolean isRawMode, boolean isASMifierMode) throws IOException {
ClassNode cnode = createClassNode(is);
MethodNode methodToVisit = null;
// some fields doesn't included in <cinit>/<init> blocks...
if (javaElement.getElementType() == IJavaElement.FIELD) {
// try to get single field
List fields = cnode.fields;
for (int i = 0; i < fields.size(); i++) {
FieldNode fn = (FieldNode) fields.get(i);
if (javaElement.getElementName().equals(fn.name)) {
if (fn.value != null) {
if(!isASMifierMode) {
return new DecompileResult(NodePrinter.print(
fn, isRawMode));
}
return new DecompileResult(NodePrinter
.printASMifier(fn));
}
methodToVisit = findInitializerNode(
cnode.methods, (IField) javaElement);
// no initializer - print empty field
if (methodToVisit == null) {
if(!isASMifierMode) {
return new DecompileResult(NodePrinter.print(
fn, isRawMode));
}
return new DecompileResult(NodePrinter
.printASMifier(fn));
}
break;
}
}
}
if (methodToVisit == null) {
methodToVisit = getMethodNode(javaElement, cnode.methods);
if (methodToVisit == null) {
return null;
}
}
StringBuffer sb;
String elementName = createBytecodeSignature(methodToVisit, isRawMode);
PrintCodeVisitor cv;
if(!isASMifierMode){
cv = new CommentedTraceCodeVisitor(
null, methodToVisit);
((CommentedTraceCodeVisitor)cv).setRawMode(isRawMode);
} else {
cv = new ASMifierCodeVisitor();
}
NodePrinter.visitMethod(cv, methodToVisit, isRawMode, isASMifierMode);
sb = NodePrinter.createTextFromVisitor(elementName, cv);
return new DecompileResult(sb.toString());
}
/**
* @param javaElement
* @param methods