MethodDefinition.java revision 6ef13753e78bb7abc7e7683d5e533c3395d4a9b6
1/* 2 * [The "BSD licence"] 3 * Copyright (c) 2009 Ben Gruver 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29package org.jf.baksmali.Adaptors; 30 31import org.jf.dexlib.ClassDataItem; 32import org.jf.dexlib.CodeItem; 33import org.jf.dexlib.MethodIdItem; 34import org.jf.dexlib.code.InstructionField; 35import org.jf.dexlib.code.Instruction; 36import org.jf.dexlib.code.Opcode; 37import org.jf.dexlib.code.Format.*; 38import org.jf.dexlib.util.AccessFlags; 39import org.jf.baksmali.Adaptors.Format.*; 40 41import java.util.*; 42 43public class MethodDefinition { 44 private ClassDataItem.EncodedMethod encodedMethod; 45 private MethodIdItem methodIdItem; 46 private CodeItem codeItem; 47 48 public MethodDefinition(ClassDataItem.EncodedMethod encodedMethod) { 49 this.encodedMethod = encodedMethod; 50 this.methodIdItem = encodedMethod.getMethod(); 51 this.codeItem = encodedMethod.getCodeItem(); 52 } 53 54 private String methodName = null; 55 public String getMethodName() { 56 if (methodName == null) { 57 methodName = methodIdItem.getMethodName(); 58 } 59 return methodName; 60 } 61 62 private List<String> accessFlags = null; 63 public List<String> getAccessFlags() { 64 if (accessFlags == null) { 65 accessFlags = new ArrayList<String>(); 66 67 for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForMethod(encodedMethod.getAccessFlags())) { 68 accessFlags.add(accessFlag.toString()); 69 } 70 } 71 return accessFlags; 72 } 73 74 private String prototype = null; 75 public String getPrototype() { 76 if (prototype == null) { 77 prototype = methodIdItem.getPrototype().getPrototypeString(); 78 } 79 return prototype; 80 } 81 82 private Boolean hasCode = null; 83 public boolean getHasCode() { 84 if (hasCode == null) { 85 hasCode = (codeItem != null); 86 } 87 return hasCode; 88 } 89 90 private String registerCount = null; 91 public String getRegisterCount() { 92 if (registerCount == null) { 93 if (codeItem == null) { 94 registerCount = "0"; 95 } else { 96 registerCount = Integer.toString(codeItem.getRegisterCount()); 97 } 98 } 99 return registerCount; 100 } 101 102 103 private List<MethodItem> methodItems = null; 104 public List<MethodItem> getMethodItems() { 105 if (methodItems == null) { 106 MethodItemList methodItemList = new MethodItemList(); 107 methodItemList.generateMethodItemList(); 108 109 methodItems = new ArrayList<MethodItem>(); 110 111 methodItems.addAll(methodItemList.labels); 112 methodItems.addAll(methodItemList.instructions); 113 methodItems.addAll(methodItemList.blanks); 114 Collections.sort(methodItems); 115 } 116 return methodItems; 117 } 118 119 120 private class MethodItemList { 121 public HashSet<LabelMethodItem> labels = new HashSet<LabelMethodItem>(); 122 public List<InstructionFormatMethodItem> instructions = new ArrayList<InstructionFormatMethodItem>(); 123 public List<BlankMethodItem> blanks = new ArrayList<BlankMethodItem>(); 124 125 private HashMap<Integer, Integer> packedSwitchMap = new HashMap<Integer, Integer>(); 126 private HashMap<Integer, Integer> sparseSwitchMap = new HashMap<Integer, Integer>(); 127 128 129 public void generateMethodItemList() { 130 if (codeItem == null) { 131 return; 132 } 133 134 int offset = 0; 135 for (InstructionField instructionField: codeItem.getInstructions()) { 136 Instruction instruction = instructionField.getInstruction(); 137 if (instruction.getOpcode() == Opcode.PACKED_SWITCH) { 138 packedSwitchMap.put(offset+((Instruction31t)instruction).getOffset(), offset); 139 } else if (instruction.getOpcode() == Opcode.SPARSE_SWITCH) { 140 sparseSwitchMap.put(offset+((Instruction31t)instruction).getOffset(), offset); 141 } 142 143 offset += instructionField.getSize(offset * 2) / 2; 144 } 145 146 offset = 0; 147 for (InstructionField instructionField: codeItem.getInstructions()) { 148 addMethodItemsForInstruction(offset, instructionField); 149 blanks.add(new BlankMethodItem(offset)); 150 offset += instructionField.getSize(offset*2) / 2; 151 } 152 blanks.remove(blanks.size()-1); 153 } 154 155 private void addMethodItemsForInstruction(int offset, InstructionField instructionField) { 156 Instruction instruction = instructionField.getInstruction(); 157 158 switch (instruction.getFormat()) { 159 case Format10t: 160 instructions.add(new Instruction10tMethodItem(offset, (Instruction10t)instruction)); 161 labels.add(new LabelMethodItem(offset + ((Instruction10t)instruction).getOffset(), "goto_")); 162 return; 163 case Format10x: 164 instructions.add(new Instruction10xMethodItem(offset, (Instruction10x)instruction)); 165 return; 166 case Format11n: 167 instructions.add(new Instruction11nMethodItem(offset, (Instruction11n)instruction)); 168 return; 169 case Format11x: 170 instructions.add(new Instruction11xMethodItem(offset, (Instruction11x)instruction)); 171 return; 172 case Format12x: 173 instructions.add(new Instruction12xMethodItem(offset, (Instruction12x)instruction)); 174 return; 175 case Format20t: 176 instructions.add(new Instruction20tMethodItem(offset, (Instruction20t)instruction)); 177 labels.add(new LabelMethodItem(offset + ((Instruction20t)instruction).getOffset(), "goto_")); 178 return; 179 case Format21c: 180 instructions.add(new Instruction21cMethodItem(offset, (Instruction21c)instruction)); 181 return; 182 case Format21h: 183 instructions.add(new Instruction21hMethodItem(offset, (Instruction21h)instruction)); 184 return; 185 case Format21s: 186 instructions.add(new Instruction21sMethodItem(offset, (Instruction21s)instruction)); 187 return; 188 case Format21t: 189 instructions.add(new Instruction21tMethodItem(offset, (Instruction21t)instruction)); 190 labels.add(new LabelMethodItem(offset + ((Instruction21t)instruction).getOffset(), "cond_")); 191 return; 192 case Format22b: 193 instructions.add(new Instruction22bMethodItem(offset, (Instruction22b)instruction)); 194 return; 195 case Format22c: 196 instructions.add(new Instruction22cMethodItem(offset, (Instruction22c)instruction)); 197 return; 198 case Format22s: 199 instructions.add(new Instruction22sMethodItem(offset, (Instruction22s)instruction)); 200 return; 201 case Format22t: 202 instructions.add(new Instruction22tMethodItem(offset, (Instruction22t)instruction)); 203 labels.add(new LabelMethodItem(offset + ((Instruction22t)instruction).getOffset(), "cond_")); 204 return; 205 case Format22x: 206 instructions.add(new Instruction22xMethodItem(offset, (Instruction22x)instruction)); 207 return; 208 case Format23x: 209 instructions.add(new Instruction23xMethodItem(offset, (Instruction23x)instruction)); 210 return; 211 case Format30t: 212 instructions.add(new Instruction30tMethodItem(offset, (Instruction30t)instruction)); 213 labels.add(new LabelMethodItem(offset + ((Instruction30t)instruction).getOffset(), "goto_")); 214 return; 215 case Format31c: 216 instructions.add(new Instruction31cMethodItem(offset, (Instruction31c)instruction)); 217 return; 218 case Format31i: 219 instructions.add(new Instruction31iMethodItem(offset, (Instruction31i)instruction)); 220 return; 221 case Format31t: 222 instructions.add(new Instruction31tMethodItem(offset, (Instruction31t)instruction)); 223 if (instruction.getOpcode() == Opcode.FILL_ARRAY_DATA) { 224 labels.add(new LabelMethodItem(offset + ((Instruction31t)instruction).getOffset(), "array_")); 225 } else if (instruction.getOpcode() == Opcode.PACKED_SWITCH) { 226 labels.add(new LabelMethodItem(offset + ((Instruction31t)instruction).getOffset(), "pswitch_data_")); 227 } else if (instruction.getOpcode() == Opcode.SPARSE_SWITCH) { 228 labels.add(new LabelMethodItem(offset + ((Instruction31t)instruction).getOffset(), "sswitch_data_")); 229 } 230 return; 231 case Format32x: 232 instructions.add(new Instruction32xMethodItem(offset, (Instruction32x)instruction)); 233 return; 234 case Format35c: 235 instructions.add(new Instruction35cMethodItem(offset, (Instruction35c)instruction)); 236 return; 237 case Format3rc: 238 instructions.add(new Instruction3rcMethodItem(offset, (Instruction3rc)instruction)); 239 return; 240 case Format51l: 241 instructions.add(new Instruction51lMethodItem(offset, (Instruction51l)instruction)); 242 return; 243 case ArrayData: 244 instructions.add(new ArrayDataMethodItem(offset, (ArrayDataPseudoInstruction)instruction)); 245 return; 246 case PackedSwitchData: 247 { 248 Integer baseAddress = packedSwitchMap.get(offset); 249 250 if (baseAddress != null) { 251 instructions.add(new PackedSwitchMethodItem(offset, 252 (PackedSwitchDataPseudoInstruction)instruction, baseAddress)); 253 for (int target: ((PackedSwitchDataPseudoInstruction)instruction).getTargets()) { 254 labels.add(new LabelMethodItem(baseAddress + target, "pswitch_")); 255 } 256 } 257 return; 258 } 259 case SparseSwitchData: 260 { 261 Integer baseAddress = sparseSwitchMap.get(offset); 262 if (baseAddress != null) { 263 instructions.add(new SparseSwitchMethodItem(offset, 264 (SparseSwitchDataPseudoInstruction)instruction, baseAddress)); 265 for (int target: ((SparseSwitchDataPseudoInstruction)instruction).getTargets()) { 266 labels.add(new LabelMethodItem(baseAddress + target, "sswitch_")); 267 } 268 } 269 return; 270 } 271 } 272 } 273 } 274} 275