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
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*****************************************************************************************
* 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.util.regex.Matcher;
import java.util.regex.Pattern;
import de.loskutov.bco.BytecodeOutlinePlugin;
/**
* Container for decompiled bytecode
* @author Andrei
*/
public class DecompileResult {
/**
* start of source line marker
*/
public static final String SOURCE_LINE_PREFIX = " ("; //$NON-NLS-1$
/**
* stop of source line marker
*/
public static final String SOURCE_LINE_SUFFIX = ")\n"; //$NON-NLS-1$
/**
* " (345)\n" is a valid example for this pattern, 345 is stored as content of
* matching group #1
*/
private static final Pattern sourceLinePattern = Pattern
.compile(" \\((\\d+)\\)\\n"); //$NON-NLS-1$
private String decompiledCode;
/**
* @param decompiledCode full decompiled bytecode as string
*/
public DecompileResult(String decompiledCode) {
setDecompiledCode(decompiledCode);
}
/**
* Returns source line from corresponding source code.
* Based on text pattern search in decompiled bytecode - used pattern is
* currently (\d) just before line end
* @param byteCodeTextOffset text offset from decompiled code
* @return -1 if source line is not found
*/
public int getSourceLine(int byteCodeTextOffset) {
int startLine = -1;
// last character in the currrent line
int stopSearch = decompiledCode.indexOf("\n", byteCodeTextOffset) + 1; //$NON-NLS-1$
String subSequence = decompiledCode.substring(0, stopSearch);
int startSearch = subSequence.lastIndexOf("//") + 1; //$NON-NLS-1$
String lineNbrStr = getLastMatch(
startSearch, subSequence.length(), decompiledCode);
if (lineNbrStr == null) {
return startLine;
}
try {
startLine = Integer.parseInt(lineNbrStr);
} catch (NumberFormatException e) {
BytecodeOutlinePlugin.error(null, e);
}
return startLine;
}
private static final String getLastMatch(int startSearch, int stopSearch,
String code) {
Matcher matcher = sourceLinePattern.matcher(code.subSequence(
startSearch, stopSearch));
String lastGroup = null;
while (matcher.find()) {
lastGroup = matcher.group(1);
}
return lastGroup;
}
/**
* @param decompiledCode The decompiledCode to set.
*/
public void setDecompiledCode(String decompiledCode) {
this.decompiledCode = decompiledCode;
}
/**
* @return Returns the decompiledCode.
*/
public String getDecompiledCode() {
return decompiledCode;
}
}
\ No newline at end of file
This diff is collapsed.
/*****************************************************************************************
* 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.compare;
import org.eclipse.compare.CompareConfiguration;
import org.eclipse.compare.CompareEditorInput;
import org.eclipse.compare.CompareUI;
import org.eclipse.compare.CompareViewerPane;
import org.eclipse.compare.CompareViewerSwitchingPane;
import org.eclipse.compare.structuremergeviewer.Differencer;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.IReusableEditor;
import de.loskutov.bco.compare.actions.ToggleASMifierModeAction;
/**
*/
public class BytecodeCompare extends CompareEditorInput {
/** Stores reference to the element displayed on the left side of the viewer. */
protected TypedElement left;
/** Stores reference to the element displayed on the right side of the viewer. */
protected TypedElement right;
protected Action toggleModeAction;
protected IReusableEditor myEditor;
/**
* Constructor for PerforceCompareEditorInput.
* @param left element displayed on the left.
* @param right element displayed on the right.
*/
public BytecodeCompare(TypedElement left, TypedElement right) {
super(new CompareConfiguration());
this.left = left;
this.right = right;
toggleModeAction = new ToggleASMifierModeAction();
toggleModeAction.addPropertyChangeListener(new IPropertyChangeListener(){
public void propertyChange(PropertyChangeEvent event) {
if(IAction.CHECKED.equals(event.getProperty())){
toggleASMifierMode(Boolean.TRUE == event.getNewValue());
}
}
});
}
/** @see CompareEditorInput#prepareInput(IProgressMonitor) */
protected Object prepareInput(IProgressMonitor monitor)
throws InterruptedException {
if (right == null || left == null) {
return null;
}
try {
initLabels();
Differencer differencer = new Differencer();
monitor.beginTask("Bytecode Outline: comparing...", 30); //$NON-NLS-1$
IProgressMonitor sub = new SubProgressMonitor(monitor, 10);
try {
sub.beginTask("Bytecode Outline: comparing...", 100); //$NON-NLS-1$
return differencer.findDifferences(
false, sub, null, null, left, right);
} finally {
sub.done();
}
} catch (OperationCanceledException e) {
throw new InterruptedException(e.getMessage());
} finally {
monitor.done();
}
}
/**
* Sets up the title and pane labels for the comparison view.
*/
private void initLabels() {
CompareConfiguration cc = getCompareConfiguration();
cc.setLeftLabel(left.getName());
cc.setLeftImage(left.getImage());
cc.setRightLabel(right.getName());
cc.setRightImage(right.getImage());
setTitle("Bytecode compare " //$NON-NLS-1$
+ left.getElementName() + " - " + right.getElementName()); //$NON-NLS-1$
}
/**
* @see org.eclipse.compare.CompareEditorInput#createContents(org.eclipse.swt.widgets.Composite)
*/
public Control createContents(Composite parent) {
Object obj = parent.getData();
// dirty hook on this place to get reference to editor
// CompareEditor extends EditorPart implements IReusableEditor
if(obj instanceof IReusableEditor){
myEditor = (IReusableEditor)obj;
}
Control control = super.createContents(parent);
// dirty hook on this place to get reference to CompareViewerPane
// from CompareEditorInput: see field
// private CompareViewerSwitchingPane fContentInputPane;
// see also CompareEditorInput.createContents:
// fComposite.setData("Nav", //$NON-NLS-1$
Object obj2 = control.getData("Nav"); //$NON-NLS-1$
if (obj2 instanceof CompareViewerSwitchingPane[]) {
// there are 4 panels, last one is the input pane that we search for
CompareViewerSwitchingPane[] panels = (CompareViewerSwitchingPane[])obj2;
if(panels.length > 0){
Composite comparePane = panels[panels.length-1];
ToolBarManager toolBarManager2 = CompareViewerPane
.getToolBarManager(comparePane);
if (toolBarManager2.find(toggleModeAction.getId()) == null) {
toolBarManager2.insert(0, new Separator("bco")); //$NON-NLS-1$
toolBarManager2.insertBefore("bco", toggleModeAction); //$NON-NLS-1$
toolBarManager2.update(true);
}
}
}
return control;
}
protected void toggleASMifierMode(boolean isASMifierMode) {
String contentType = isASMifierMode
? TypedElement.TYPE_ASM_IFIER
: TypedElement.TYPE_BYTECODE;
left.setASMifierMode(isASMifierMode);
left.setType(contentType);
right.setASMifierMode(isASMifierMode);
right.setType(contentType);
CompareUI.reuseCompareEditor(this, myEditor);
}
}
\ 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 -