| /* |
| * [The "BSD licence"] |
| * Copyright (c) 2011 Ben Gruver |
| * 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. The name of the author may not be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. |
| */ |
| |
| package org.jf.dexlib.Code.Analysis; |
| |
| import org.jf.dexlib.*; |
| import org.jf.dexlib.Code.Format.Instruction22c; |
| import org.jf.dexlib.Code.Instruction; |
| import org.jf.dexlib.Code.InstructionWithReference; |
| import org.jf.dexlib.Util.AccessFlags; |
| |
| import java.util.HashMap; |
| |
| public class SyntheticAccessorResolver { |
| public static final int METHOD = 0; |
| public static final int GETTER = 1; |
| public static final int SETTER = 2; |
| |
| private final DexFileClassMap classMap; |
| private final HashMap<MethodIdItem, AccessedMember> resolvedAccessors = new HashMap<MethodIdItem, AccessedMember>(); |
| |
| public SyntheticAccessorResolver(DexFile dexFile) { |
| classMap = new DexFileClassMap(dexFile); |
| } |
| |
| public static boolean looksLikeSyntheticAccessor(MethodIdItem methodIdItem) { |
| return methodIdItem.getMethodName().getStringValue().startsWith("access$"); |
| } |
| |
| public AccessedMember getAccessedMember(MethodIdItem methodIdItem) { |
| AccessedMember accessedMember = resolvedAccessors.get(methodIdItem); |
| if (accessedMember != null) { |
| return accessedMember; |
| } |
| |
| ClassDefItem classDefItem = classMap.getClassDefByType(methodIdItem.getContainingClass()); |
| if (classDefItem == null) { |
| return null; |
| } |
| |
| ClassDataItem classDataItem = classDefItem.getClassData(); |
| if (classDataItem == null) { |
| return null; |
| } |
| |
| ClassDataItem.EncodedMethod encodedMethod = classDataItem.findDirectMethodByMethodId(methodIdItem); |
| if (encodedMethod == null) { |
| return null; |
| } |
| |
| //A synthetic accessor will be marked synthetic |
| if ((encodedMethod.accessFlags & AccessFlags.SYNTHETIC.getValue()) == 0) { |
| return null; |
| } |
| |
| Instruction[] instructions = encodedMethod.codeItem.getInstructions(); |
| |
| //TODO: add support for odexed formats |
| switch (instructions[0].opcode.format) { |
| case Format35c: |
| case Format3rc: { |
| //a synthetic method access should be either 2 or 3 instructions, depending on if the method returns |
| //anything or not |
| if (instructions.length < 2 || instructions.length > 3) { |
| return null; |
| } |
| InstructionWithReference instruction = (InstructionWithReference)instructions[0]; |
| Item referencedItem = instruction.getReferencedItem(); |
| if (!(referencedItem instanceof MethodIdItem)) { |
| return null; |
| } |
| MethodIdItem referencedMethodIdItem = (MethodIdItem)referencedItem; |
| |
| accessedMember = new AccessedMember(METHOD, referencedMethodIdItem); |
| resolvedAccessors.put(methodIdItem, accessedMember); |
| return accessedMember; |
| } |
| case Format22c: { |
| //a synthetic field access should be exactly 2 instructions. The set/put, and then the return |
| if (instructions.length != 2) { |
| return null; |
| } |
| Instruction22c instruction = (Instruction22c)instructions[0]; |
| Item referencedItem = instruction.getReferencedItem(); |
| if (!(referencedItem instanceof FieldIdItem)) { |
| return null; |
| } |
| FieldIdItem referencedFieldIdItem = (FieldIdItem)referencedItem; |
| |
| if (instruction.opcode.setsRegister() || instruction.opcode.setsWideRegister()) { |
| //If the instruction sets a register, that means it is a getter - it gets the field value and |
| //stores it in the register |
| accessedMember = new AccessedMember(GETTER, referencedFieldIdItem); |
| } else { |
| accessedMember = new AccessedMember(SETTER, referencedFieldIdItem); |
| } |
| |
| resolvedAccessors.put(methodIdItem, accessedMember); |
| return accessedMember; |
| } |
| default: |
| return null; |
| } |
| } |
| |
| public static class AccessedMember { |
| public final int accessedMemberType; |
| public final Item accessedMember; |
| |
| public AccessedMember(int accessedMemberType, Item accessedMember) { |
| this.accessedMemberType = accessedMemberType; |
| this.accessedMember = accessedMember; |
| } |
| } |
| } |