/* * 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.bytecodemod; import java.awt.event.ActionEvent; import java.util.Vector; import javax.swing.Icon; import javax.swing.JViewport; import analyser.gui.ClassTree; import analyser.gui.FieldDialog; import analyser.gui.LineBuilderFormatter; import analyser.gui.MainFrame; import analyser.gui.Selection; import analyser.gui.TextBuilder; import analyser.logic.BytecodeModificationMediator; import analyser.logic.Reference; import jerl.bcm.inj.Injection; import jerl.bcm.inj.InjectionMethodOffset; import jerl.bcm.inj.impl.MethodOffsetFieldArrayOut; import jerl.bcm.inj.impl.MethodOffsetFieldOut; import mereflect.MEField; import mereflect.MEMethod; import mereflect.Type; import mereflect.bytecode.Bytecode; import mereflect.io.DescriptorParser; import mereflect.primitives.MEArray; public class FieldAction extends AbstractTreeBytecodeModAction { private static final long serialVersionUID = -7338862962364584726L; protected static FieldAction m_inst = null; public static FieldAction getInstance(MainFrame mainFrame) { if (m_inst == null) { m_inst = new FieldAction("Print a local variable", null); m_inst.setMainFrame(mainFrame); } return m_inst; } protected FieldAction(String arg0, Icon arg1) { super(arg0, arg1); } @Override public void run(ActionEvent e) throws Throwable { ClassTree tree = ((MainFrame) getMainFrame()).getSelectedTree(); if (!(Selection.getSelectedView() instanceof TextBuilder)) { return; } TextBuilder text = (TextBuilder) Selection.getSelectedView(); Object ref = text.getLineBuilder().getReference(text.getCurrentLine()); MainFrame mainFrame = (MainFrame) getMainFrame(); if (ref != null && LineBuilderFormatter.BytecodeOffset.class.isAssignableFrom(ref.getClass())) { int bytecodeOffset = ((LineBuilderFormatter.BytecodeOffset) ref).pc; MEMethod method = (MEMethod) text.getOwnerData(); MEField[] meFields = method.getMEClass().getFields(); if (meFields != null && meFields.length > 0) { Vector<MEField> fields = new Vector<MEField>(); for (int i = 0; i < meFields.length; i++) { fields.add(meFields[i]); } FieldDialog fd = new FieldDialog( mainFrame, method.getMEClass(), "Select field", method.getMEClass().getName() + ":" + method.getName() + "@" + Integer.toHexString(((LineBuilderFormatter.BytecodeOffset) ref).pc), fields, this); fd.setSize(700, 500); int x = mainFrame.getLocationOnScreen().x + (mainFrame.getWidth() - fd.getWidth()) / 2; int y = mainFrame.getLocationOnScreen().y + (mainFrame.getHeight() - fd.getHeight()) / 2; fd.setLocation(Math.max(0, x), Math.max(0, y)); fd.setVisible(true); fd.setModal(false); fd.awaitAcknowledge(); String output = fd.getOutput(); MEField field = fd.getChosenField(); InjectionMethodOffset[] injections = null; if (output != null && output.trim().length() > 0 && field != null && isRunning()) { if (output.endsWith("=")) { output = output.substring(0, output.length() - 1); } StringBuffer fieldType = new StringBuffer(); if (field.getType().isArray() && fd.getArraySpecification() != FieldDialog.INSTANCE) { Type arrayType = ((MEArray) field.getType()).getArrayType(); DescriptorParser.processType(field.getType(), fieldType); StringBuffer fieldPrintType = new StringBuffer(); DescriptorParser.processType(arrayType, fieldPrintType); if (fd.getArraySpecification() == FieldDialog.ELEMENTS) { int[] ixs = fd.getArrayIndicesSpecification(); injections = new InjectionMethodOffset[ixs.length]; for (int i = 0; i < ixs.length; i++) { injections[i] = new MethodOffsetFieldArrayOut(method.getName() + method.getDescriptor(), Bytecode.getBytecodeIndexForOffset(method, bytecodeOffset), method.getMEClass().getRawName(), field.getName(), fieldType.toString(), arrayType.isPrimitive() ? fieldPrintType.toString() : "Ljava/lang/Object;", output + "[" + ixs[i] + "]=", field.isStatic(), ixs[i]); } } else if (fd.getArraySpecification() == FieldDialog.ALL_ELEMENTS) { // TODO implement } } else { DescriptorParser.processType(field.getType(), fieldType); injections = new InjectionMethodOffset[1]; injections[0] = new MethodOffsetFieldOut(method.getName() + method.getDescriptor(), Bytecode.getBytecodeIndexForOffset(method, bytecodeOffset), method.getMEClass().getRawName(), field.getName(), fieldType.toString(), field.getType().isPrimitive() ? fieldType.toString() : "Ljava/lang/Object;", output + "=", field.isStatic()); } for (int i = 0; injections != null && i < injections.length; i++) { BytecodeModificationMediator.getInstance().registerModification( method.getMEClass().getResource().getContext(), method.getMEClass(), injections[i], method); } if (isRunning()) { mainFrame.actionFinished(this); } if (injections != null && isRunning()) { boolean arrayElements = field.getType().isArray() && fd.getArraySpecification() != FieldDialog.INSTANCE && fd.getArraySpecification() == FieldDialog.ELEMENTS; tree.findAndMarkNode(method, Reference.MODIFIED); tree.repaint(); int pos = text.getCaretPosition(); JViewport view = text.getScrollPane().getViewport(); int[] ixs = fd.getArrayIndicesSpecification(); for (int i = 0; i < injections.length; i++) { text.getLineBuilder().insertLineBefore(text.getCurrentLine() + i); text.getLineBuilder().append(" >>> ", 0xbb0000); text.getLineBuilder().append("PRINT(", 0x000000); text.getLineBuilder().append("\"" + output + "=\"", 0x0000bb); text.getLineBuilder().append(" + ", 0x000000); text.getLineBuilder().append(field.getName(), 0x000000); if (arrayElements) { text.getLineBuilder().append("[" + ixs[i] + "]", 0xbb0000); } text.getLineBuilder().append(")", 0x000000); text.getLineBuilder().setReferenceToCurrent(injections[i]); } text.updateDocument(); text.setCaretPosition(pos); text.getScrollPane().setViewport(view); } } } else { mainFrame.getSelectedTree().repaint(); } } } @Override protected Injection getInjection(String className, String methodSignature) { // not used return null; } }