/*
* Copyright (C) 2012 Sony Mobile Communications AB
*
* This file is part of ApkAnalyser.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package analyser.gui.actions;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Icon;
import mereflect.CorruptBytecodeException;
import mereflect.MEClass;
import mereflect.MEClassContext;
import mereflect.MEMethod;
import mereflect.UnknownMethod;
import org.jf.dexlib.Code.Instruction;
import analyser.gui.LineBuilder;
import analyser.gui.LineBuilderFormatter;
import analyser.gui.MainFrame;
import analyser.gui.Selection;
import analyser.gui.TextDialog;
import analyser.logic.RefMethod;
import andreflect.DexMethod;
import andreflect.gui.linebuilder.DalvikByteCodeLineBuilder;
public class ShowBytecodeAction extends AbstractAction {
private static final long serialVersionUID = -1200143170943192070L;
static final String PREFIX = " ";
protected static ShowBytecodeAction inst = null;
protected MainFrame mainFrame;
protected MEClassContext classContext;
protected MEClass clazz;
protected MEMethod method;
protected RefMethod refMethod;
protected TextDialog textDialog;
public static ShowBytecodeAction getInstance(MainFrame mainFrame) {
if (inst == null) {
inst = new ShowBytecodeAction("View bytecodes", null);
inst.mainFrame = mainFrame;
}
return inst;
}
protected ShowBytecodeAction(String arg0, Icon arg1) {
super(arg0, arg1);
}
@Override
public void actionPerformed(ActionEvent e) {
method = null;
LineBuilder result = null;
int pc = Selection.getPc();
method = Selection.getMEMethod();
Instruction instruction = Selection.getDalvikInstruction();
if (method == null
|| method instanceof UnknownMethod) {
return;
}
clazz = method.getMEClass();
classContext = clazz.getResource().getContext();
LineBuilder classLines = LineBuilderFormatter.makeOutline(clazz);
classLines.blendLines(0xffffff, 50);
int lineNbr = classLines.getLine(method);
try {
LineBuilder codeLines;
if (method instanceof DexMethod) {
codeLines = DalvikByteCodeLineBuilder.getByteCodeAssembler((DexMethod) method, PREFIX);
} else {
codeLines = LineBuilderFormatter.getByteCodeAssembler(method, PREFIX);
}
if (lineNbr >= 0) {
classLines.insertAfter(lineNbr, codeLines);
classLines.insertLineAfter(lineNbr + codeLines.lineCount());
result = classLines;
} else {
result = codeLines;
}
} catch (CorruptBytecodeException cbe) {
mainFrame.showError(method.toString(), "Bytecode is corrupt (index: " + cbe.getPc() + ")");
return;
}
if (result != null) {
textDialog = mainFrame.showText("Examine method [" + method.toString() + "]", result);
if (instruction == null
&& pc < 0
&& method instanceof DexMethod
&& !method.isAbstract()) {
DexMethod dexMethod = (DexMethod) method;
instruction = dexMethod.getInstructionAtCodeAddress(0);
}
if (instruction != null) {
LineBuilder lb = textDialog.getLineBuilder();
for (int i = 0; i < lb.lineCount(); i++) {
Object ref = lb.getReference(i);
if (ref instanceof DalvikByteCodeLineBuilder.DalvikBytecodeOffset
&& ((DalvikByteCodeLineBuilder.DalvikBytecodeOffset) ref).instruction == instruction) {
lb.gotoLine(i);
textDialog.findNext(lb.currentLineString());
}
}
} else if (pc >= 0) {
int line = -1;
LineBuilder lb = textDialog.getLineBuilder();
for (int i = 0; i < lb.lineCount(); i++) {
Object ref = lb.getReference(i);
if (ref instanceof LineBuilderFormatter.BytecodeOffset) {
line = i;
break;
} else if (ref instanceof DalvikByteCodeLineBuilder.DalvikBytecodeOffset) {
line = i;
break;
}
}
if (line >= 0) {
textDialog.findNext(PREFIX + Integer.toHexString(pc) + ' '); // TODO fix up this sordid stuff
}
}
textDialog.setOwnerData(method);
}
}
public MEClass getMEClass() {
return clazz;
}
/**
* @return
*/
public MEClassContext getClassContext() {
return classContext;
}
/**
* @return
*/
public MEMethod getMethod() {
return method;
}
/**
* @return
*/
public TextDialog getTextDialog() {
return textDialog;
}
}