MethodDefinition.java revision 311ee79fab06269ea6d9bd31ec1854a6ad036b23
1e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard/* 2e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * [The "BSD licence"] 3e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * Copyright (c) 2009 Ben Gruver 4e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * All rights reserved. 5e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * 6e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * Redistribution and use in source and binary forms, with or without 7e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * modification, are permitted provided that the following conditions 8e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * are met: 9e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * 1. Redistributions of source code must retain the above copyright 10e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * notice, this list of conditions and the following disclaimer. 11e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * 2. Redistributions in binary form must reproduce the above copyright 12e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * notice, this list of conditions and the following disclaimer in the 13e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * documentation and/or other materials provided with the distribution. 14e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * 3. The name of the author may not be used to endorse or promote products 15e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * derived from this software without specific prior written permission. 16e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * 17e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 262857b47a2731579772c76d46285660972c0ba23dBen Cheng * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard */ 28e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard 29e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgardpackage org.jf.baksmali.Adaptors; 302857b47a2731579772c76d46285660972c0ba23dBen Cheng 312857b47a2731579772c76d46285660972c0ba23dBen Chengimport org.jf.baksmali.Adaptors.Format.*; 322857b47a2731579772c76d46285660972c0ba23dBen Chengimport org.jf.baksmali.baksmali; 33e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgardimport org.jf.dexlib.*; 34e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgardimport org.jf.dexlib.Debug.DebugInstructionIterator; 35e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgardimport org.jf.dexlib.Code.Format.*; 36b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgardimport org.jf.dexlib.Code.Instruction; 37b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgardimport org.jf.dexlib.Code.Opcode; 38e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgardimport org.jf.dexlib.Code.InstructionIterator; 39b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgardimport org.jf.dexlib.Code.OffsetInstruction; 40e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgardimport org.jf.dexlib.Util.AccessFlags; 41e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgardimport org.antlr.stringtemplate.StringTemplateGroup; 42e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgardimport org.antlr.stringtemplate.StringTemplate; 43b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard 44e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgardimport java.util.*; 45b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard 46b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgardpublic class MethodDefinition { 47e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard public static StringTemplate makeTemplate(StringTemplateGroup stg, ClassDataItem.EncodedMethod encodedMethod, 48b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard AnnotationSetItem annotationSet, 49b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard AnnotationSetRefList parameterAnnotations) { 50e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard 51e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard CodeItem codeItem = encodedMethod.codeItem; 52e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard 53b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard StringTemplate template = stg.getInstanceOf("method"); 54e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard 55e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard template.setAttribute("AccessFlags", getAccessFlags(encodedMethod)); 56b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard template.setAttribute("MethodName", encodedMethod.method.getMethodName().getStringValue()); 57e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard template.setAttribute("Prototype", encodedMethod.method.getPrototype().getPrototypeString()); 58b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard template.setAttribute("HasCode", codeItem != null); 59e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard template.setAttribute("RegistersDirective", baksmali.useLocalsDirective?".locals":".registers"); 60b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard template.setAttribute("RegisterCount", codeItem==null?"0":Integer.toString(getRegisterCount(encodedMethod))); 61b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard template.setAttribute("Parameters", getParameters(stg, codeItem, parameterAnnotations)); 62b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard template.setAttribute("Annotations", getAnnotations(stg, annotationSet)); 63e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard template.setAttribute("MethodItems", getMethodItems(encodedMethod.method.getDexFile(), stg, codeItem)); 64e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard 65b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard return template; 66e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard } 67b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard 68b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard private static int getRegisterCount(ClassDataItem.EncodedMethod encodedMethod) 69e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard { 70e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard int totalRegisters = encodedMethod.codeItem.getRegisterCount(); 71e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard if (baksmali.useLocalsDirective) { 72e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard int parameterRegisters = encodedMethod.method.getPrototype().getParameterRegisterCount(); 73e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard if ((encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) == 0) { 74e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard parameterRegisters++; 75b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard } 76e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard return totalRegisters - parameterRegisters; 77b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard } 78e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard return totalRegisters; 79b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard } 80e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard 81e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard private static List<String> getAccessFlags(ClassDataItem.EncodedMethod encodedMethod) { 82b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard List<String> accessFlags = new ArrayList<String>(); 83e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard 84e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForMethod(encodedMethod.accessFlags)) { 85b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard accessFlags.add(accessFlag.toString()); 86e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard } 87b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard 88e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard return accessFlags; 89e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard } 90e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard 91b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard private static List<StringTemplate> getParameters(StringTemplateGroup stg, CodeItem codeItem, 92b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard AnnotationSetRefList parameterAnnotations) { 93e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard DebugInfoItem debugInfoItem = null; 94e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard if (codeItem != null) { 95e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard debugInfoItem = codeItem.getDebugInfo(); 96e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard } 97e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard 98b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard int parameterCount = 0; 99e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard 100e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard List<AnnotationSetItem> annotations = new ArrayList<AnnotationSetItem>(); 101e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard if (parameterAnnotations != null) { 102b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard AnnotationSetItem[] _annotations = parameterAnnotations.getAnnotationSets(); 103b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard if (_annotations != null) { 104b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard annotations.addAll(Arrays.asList(_annotations)); 105e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard } 106b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard 107e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard parameterCount = annotations.size(); 108b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard } 109e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard 1102857b47a2731579772c76d46285660972c0ba23dBen Cheng List<String> parameterNames = new ArrayList<String>(); 111b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard if (debugInfoItem != null) { 112e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard StringIdItem[] _parameterNames = debugInfoItem.getParameterNames(); 113e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard if (_parameterNames != null) { 114b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard for (StringIdItem parameterName: _parameterNames) { 115e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard parameterNames.add(parameterName==null?null:parameterName.getStringValue()); 1162857b47a2731579772c76d46285660972c0ba23dBen Cheng } 117b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard } 118e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard 119e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard if (parameterCount < parameterNames.size()) { 1202857b47a2731579772c76d46285660972c0ba23dBen Cheng parameterCount = parameterNames.size(); 121e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard } 122e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard } 123e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard 1242857b47a2731579772c76d46285660972c0ba23dBen Cheng List<StringTemplate> parameters = new ArrayList<StringTemplate>(); 1252857b47a2731579772c76d46285660972c0ba23dBen Cheng for (int i=0; i<parameterCount; i++) { 1262857b47a2731579772c76d46285660972c0ba23dBen Cheng AnnotationSetItem annotationSet = null; 127e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard if (i < annotations.size()) { 128e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard annotationSet = annotations.get(i); 129e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard } 130b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard 131e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard String parameterName = null; 132b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard if (i < parameterNames.size()) { 133b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard parameterName = parameterNames.get(i); 134b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard } 135e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard 136e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard parameters.add(ParameterAdaptor.makeTemplate(stg, parameterName, annotationSet)); 137e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard } 138b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard 139b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard return parameters; 140b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard } 141e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard 142e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard private static List<StringTemplate> getAnnotations(StringTemplateGroup stg, AnnotationSetItem annotationSet) { 143b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard if (annotationSet == null) { 144e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard return null; 145e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard } 146b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard 147e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard List<StringTemplate> annotationAdaptors = new ArrayList<StringTemplate>(); 148e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard 149e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard for (AnnotationItem annotationItem: annotationSet.getAnnotations()) { 150e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard annotationAdaptors.add(AnnotationAdaptor.makeTemplate(stg, annotationItem)); 151b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard } 152e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard return annotationAdaptors; 1532857b47a2731579772c76d46285660972c0ba23dBen Cheng } 154e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard 155e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard private static List<MethodItem> getMethodItems(DexFile dexFile, StringTemplateGroup stg, CodeItem codeItem) { 156e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard List<MethodItem> methodItems = new ArrayList<MethodItem>(); 1572857b47a2731579772c76d46285660972c0ba23dBen Cheng 158 MethodItemList methodItemList = new MethodItemList(dexFile, stg, codeItem); 159 methodItemList.generateMethodItemList(); 160 161 for (LabelMethodItem labelMethodItem: methodItemList.labels.getLabels()) { 162 if (labelMethodItem.isCommentedOut()) { 163 methodItems.add(new CommentedOutMethodItem(stg, labelMethodItem)); 164 } else { 165 methodItems.add(labelMethodItem); 166 } 167 } 168 169 methodItems.addAll(methodItemList.instructions); 170 methodItems.addAll(methodItemList.blanks); 171 methodItems.addAll(methodItemList.catches); 172 methodItems.addAll(methodItemList.debugItems); 173 Collections.sort(methodItems); 174 175 return methodItems; 176 } 177 178 179 private static class MethodItemList { 180 private final DexFile dexFile; 181 private final StringTemplateGroup stg; 182 private final CodeItem codeItem; 183 184 public LabelCache labels = new LabelCache(); 185 186 public List<MethodItem> instructions = new ArrayList<MethodItem>(); 187 public List<BlankMethodItem> blanks = new ArrayList<BlankMethodItem>(); 188 public List<CatchMethodItem> catches = new ArrayList<CatchMethodItem>(); 189 public List<MethodItem> debugItems = new ArrayList<MethodItem>(); 190 191 private HashMap<Integer, Integer> packedSwitchMap = new HashMap<Integer, Integer>(); 192 private HashMap<Integer, Integer> sparseSwitchMap = new HashMap<Integer, Integer>(); 193 194 public MethodItemList(DexFile dexFile, StringTemplateGroup stg, CodeItem codeItem) { 195 this.dexFile = dexFile; 196 this.stg = stg; 197 this.codeItem = codeItem; 198 } 199 200 public void generateMethodItemList() { 201 if (codeItem == null) { 202 return; 203 } 204 205 if (baksmali.deodexUtil != null && dexFile.isOdex()) { 206 List<Instruction> instructions = baksmali.deodexUtil.deodexerizeCode(codeItem); 207 208 int offset = 0; 209 for (Instruction instruction: instructions) { 210 if (instruction.opcode == Opcode.PACKED_SWITCH) { 211 Instruction31t ins = (Instruction31t)instruction; 212 packedSwitchMap.put(offset + ins.getOffset(), offset); 213 } else if (instruction.opcode == Opcode.SPARSE_SWITCH) { 214 Instruction31t ins = (Instruction31t)instruction; 215 sparseSwitchMap.put(offset + ins.getOffset(), offset); 216 } 217 218 offset += instruction.getSize(offset*2)/2; 219 } 220 221 offset = 0; 222 for (Instruction instruction: instructions) { 223 addMethodItemsForInstruction(offset, instruction, false); 224 blanks.add(new BlankMethodItem(stg, offset)); 225 226 offset += instruction.getSize(offset*2)/2; 227 } 228 229 /* 230 * Look for the last uncommented instruction. If it is an UnresolvedNullReference, 231 * then set IsLastInstruction, so a goto will be added after it, to avoid validation 232 * issues 233 */ 234 for (int i=this.instructions.size()-1; i>=0; i--) { 235 MethodItem ins = this.instructions.get(i); 236 if (ins instanceof UnresolvedNullReferenceMethodItem) { 237 ((UnresolvedNullReferenceMethodItem)ins).setIsLastInstruction(true); 238 break; 239 } 240 241 if (!(ins instanceof CommentedOutMethodItem)) { 242 break; 243 } 244 } 245 } else { 246 int currentCodeOffset = 0; 247 for (Instruction instruction: codeItem.getInstructions()) { 248 if (instruction.opcode == Opcode.PACKED_SWITCH) { 249 OffsetInstruction offsetInstruction = (OffsetInstruction)instruction; 250 packedSwitchMap.put(currentCodeOffset/2 + offsetInstruction.getOffset(), currentCodeOffset/2); 251 } else if (instruction.opcode == Opcode.SPARSE_SWITCH) { 252 OffsetInstruction offsetInstruction = (OffsetInstruction)instruction; 253 sparseSwitchMap.put(currentCodeOffset/2 + offsetInstruction.getOffset(), currentCodeOffset/2); 254 } 255 256 currentCodeOffset += instruction.getSize(currentCodeOffset); 257 } 258 259 currentCodeOffset = 0; 260 for (Instruction instruction: codeItem.getInstructions()) { 261 int offset = currentCodeOffset/2; 262 addMethodItemsForInstruction(offset, instruction, false); 263 blanks.add(new BlankMethodItem(stg, offset)); 264 currentCodeOffset += instruction.getSize(currentCodeOffset); 265 } 266 267 } 268 269 blanks.remove(blanks.size()-1); 270 271 addTries(); 272 273 addDebugInfo(); 274 275 if (baksmali.useIndexedLabels) { 276 setLabelIndexes(); 277 } 278 } 279 280 private void addOffsetInstructionMethodItem(OffsetInstructionFormatMethodItem methodItem, 281 boolean commentedOut) { 282 if (commentedOut) { 283 instructions.add(new CommentedOutMethodItem(stg, methodItem)); 284 } else { 285 instructions.add(methodItem); 286 LabelMethodItem label = methodItem.getLabel(); 287 label.setUncommented(); 288 } 289 } 290 291 292 private void addInstructionMethodItem(InstructionFormatMethodItem methodItem, boolean commentedOut) { 293 if (commentedOut) { 294 instructions.add(new CommentedOutMethodItem(stg, methodItem)); 295 } else { 296 instructions.add(methodItem); 297 } 298 } 299 300 private void addMethodItemsForInstruction(int offset, Instruction instruction, boolean commentedOut) { 301 switch (instruction.getFormat()) { 302 case Format10t: 303 addOffsetInstructionMethodItem( 304 new Instruction10tMethodItem(labels, codeItem, offset, stg,(Instruction10t)instruction), 305 commentedOut); 306 return; 307 case Format10x: 308 addInstructionMethodItem( 309 new Instruction10xMethodItem(codeItem, offset, stg, (Instruction10x)instruction), 310 commentedOut); 311 return; 312 case Format11n: 313 addInstructionMethodItem( 314 new Instruction11nMethodItem(codeItem, offset, stg, (Instruction11n)instruction), 315 commentedOut); 316 return; 317 case Format11x: 318 addInstructionMethodItem( 319 new Instruction11xMethodItem(codeItem, offset, stg, (Instruction11x)instruction), 320 commentedOut); 321 return; 322 case Format12x: 323 addInstructionMethodItem( 324 new Instruction12xMethodItem(codeItem, offset, stg, (Instruction12x)instruction), 325 commentedOut); 326 return; 327 case Format20t: 328 addOffsetInstructionMethodItem( 329 new Instruction20tMethodItem(labels, codeItem, offset, stg, (Instruction20t)instruction), 330 commentedOut); 331 return; 332 case Format21c: 333 addInstructionMethodItem( 334 new Instruction21cMethodItem(codeItem, offset, stg, (Instruction21c)instruction), 335 commentedOut); 336 return; 337 case Format21h: 338 addInstructionMethodItem( 339 new Instruction21hMethodItem(codeItem, offset, stg, (Instruction21h)instruction), 340 commentedOut); 341 return; 342 case Format21s: 343 addInstructionMethodItem( 344 new Instruction21sMethodItem(codeItem, offset, stg, (Instruction21s)instruction), 345 commentedOut); 346 return; 347 case Format21t: 348 addOffsetInstructionMethodItem( 349 new Instruction21tMethodItem(labels, codeItem, offset, stg, (Instruction21t)instruction), 350 commentedOut); 351 return; 352 case Format22b: 353 addInstructionMethodItem( 354 new Instruction22bMethodItem(codeItem, offset, stg, (Instruction22b)instruction), 355 commentedOut); 356 return; 357 case Format22c: 358 addInstructionMethodItem( 359 new Instruction22cMethodItem(codeItem, offset, stg, (Instruction22c)instruction), 360 commentedOut); 361 return; 362 case Format22cs: 363 addInstructionMethodItem( 364 new Instruction22csMethodItem(codeItem, offset, stg, (Instruction22cs)instruction), 365 commentedOut); 366 return; 367 case Format22csf: 368 addInstructionMethodItem( 369 new Instruction22csfMethodItem(codeItem, offset, stg, (Instruction22csf)instruction), 370 commentedOut); 371 return; 372 case Format22s: 373 addInstructionMethodItem( 374 new Instruction22sMethodItem(codeItem, offset, stg, (Instruction22s)instruction), 375 commentedOut); 376 return; 377 case Format22t: 378 addOffsetInstructionMethodItem( 379 new Instruction22tMethodItem(labels, codeItem, offset, stg, (Instruction22t)instruction), 380 commentedOut); 381 return; 382 case Format22x: 383 addInstructionMethodItem( 384 new Instruction22xMethodItem(codeItem, offset, stg, (Instruction22x)instruction), 385 commentedOut); 386 return; 387 case Format23x: 388 addInstructionMethodItem( 389 new Instruction23xMethodItem(codeItem, offset, stg, (Instruction23x)instruction), 390 commentedOut); 391 return; 392 case Format30t: 393 addOffsetInstructionMethodItem( 394 new Instruction30tMethodItem(labels, codeItem, offset, stg, (Instruction30t)instruction), 395 commentedOut); 396 return; 397 case Format31c: 398 addInstructionMethodItem( 399 new Instruction31cMethodItem(codeItem, offset, stg, (Instruction31c)instruction), 400 commentedOut); 401 return; 402 case Format31i: 403 addInstructionMethodItem( 404 new Instruction31iMethodItem(codeItem, offset, stg, (Instruction31i)instruction), 405 commentedOut); 406 return; 407 case Format31t: 408 addOffsetInstructionMethodItem( 409 new Instruction31tMethodItem(labels, codeItem, offset, stg, (Instruction31t)instruction), 410 commentedOut); 411 return; 412 case Format32x: 413 addInstructionMethodItem( 414 new Instruction32xMethodItem(codeItem, offset, stg, (Instruction32x)instruction), 415 commentedOut); 416 return; 417 case Format35c: 418 addInstructionMethodItem( 419 new Instruction35cMethodItem(codeItem, offset, stg, (Instruction35c)instruction), 420 commentedOut); 421 return; 422 case Format35s: 423 addInstructionMethodItem( 424 new Instruction35sMethodItem(codeItem, offset, stg, (Instruction35s)instruction), 425 commentedOut); 426 return; 427 case Format35sf: 428 addInstructionMethodItem( 429 new Instruction35sfMethodItem(codeItem, offset, stg, (Instruction35sf)instruction), 430 commentedOut); 431 return; 432 case Format35ms: 433 addInstructionMethodItem( 434 new Instruction35msMethodItem(codeItem, offset, stg, (Instruction35ms)instruction), 435 commentedOut); 436 return; 437 case Format35msf: 438 addInstructionMethodItem( 439 new Instruction35msfMethodItem(codeItem, offset, stg, (Instruction35msf)instruction), 440 commentedOut); 441 return; 442 case Format3rc: 443 addInstructionMethodItem( 444 new Instruction3rcMethodItem(codeItem, offset, stg, (Instruction3rc)instruction), 445 commentedOut); 446 return; 447 case Format3rms: 448 addInstructionMethodItem( 449 new Instruction3rmsMethodItem(codeItem, offset, stg, (Instruction3rms)instruction), 450 commentedOut); 451 return; 452 case Format3rmsf: 453 addInstructionMethodItem( 454 new Instruction3rmsfMethodItem(codeItem, offset, stg, (Instruction3rmsf)instruction), 455 commentedOut); 456 return; 457 case Format51l: 458 addInstructionMethodItem( 459 new Instruction51lMethodItem(codeItem, offset, stg, (Instruction51l)instruction), 460 commentedOut); 461 return; 462 case ArrayData: 463 addInstructionMethodItem( 464 new ArrayDataMethodItem(codeItem, offset, stg, (ArrayDataPseudoInstruction)instruction), 465 commentedOut); 466 return; 467 case PackedSwitchData: 468 { 469 final Integer baseAddress = packedSwitchMap.get(offset); 470 471 if (baseAddress != null) { 472 PackedSwitchDataPseudoInstruction packedSwitchInstruction = 473 (PackedSwitchDataPseudoInstruction)instruction; 474 475 PackedSwitchMethodItem packedSwitch = new PackedSwitchMethodItem(labels, codeItem, offset, stg, 476 packedSwitchInstruction, baseAddress); 477 addInstructionMethodItem(packedSwitch, commentedOut); 478 479 if (!commentedOut) { 480 for (LabelMethodItem label: packedSwitch) { 481 label.setUncommented(); 482 } 483 } 484 } 485 return; 486 } 487 case SparseSwitchData: 488 { 489 final Integer baseAddress = sparseSwitchMap.get(offset); 490 491 if (baseAddress != null) { 492 SparseSwitchDataPseudoInstruction sparseSwitchInstruction = 493 (SparseSwitchDataPseudoInstruction)instruction; 494 495 SparseSwitchMethodItem sparseSwitch = new SparseSwitchMethodItem(labels, codeItem, offset, stg, 496 sparseSwitchInstruction, baseAddress); 497 addInstructionMethodItem(sparseSwitch, commentedOut); 498 499 if (!commentedOut) { 500 for (LabelMethodItem label: sparseSwitch) { 501 label.setUncommented(); 502 } 503 } 504 } 505 return; 506 } 507 case UnresolvedNullReference: 508 { 509 addInstructionMethodItem(new UnresolvedNullReferenceMethodItem(codeItem, offset, stg, 510 (UnresolvedNullReference)instruction), commentedOut); 511 addMethodItemsForInstruction(offset, ((UnresolvedNullReference)instruction).OriginalInstruction, 512 true); 513 return; 514 } 515 case DeadInstruction: 516 { 517 //TODO: what about try/catch blocks inside the dead code? those will need to be commented out too. ugh. 518 addMethodItemsForInstruction(offset, ((DeadInstruction)instruction).OriginalInstruction, true); 519 return; 520 } 521 } 522 } 523 524 private void addTries() { 525 if (codeItem.getTries() == null) { 526 return; 527 } 528 for (CodeItem.TryItem tryItem: codeItem.getTries()) { 529 int startAddress = tryItem.getStartAddress(); 530 int endAddress = tryItem.getStartAddress() + tryItem.getInstructionCount(); 531 532 /** 533 * The end address points to the address immediately after the end of the last 534 * instruction that the try block covers. We want the .catch directive and end_try 535 * label to be associated with the last covered instruction, so we need to get 536 * the offset for that instruction 537 */ 538 int index = Collections.binarySearch(instructions, new BlankMethodItem(stg, endAddress)); 539 if (index < 0) { 540 index = (index * -1) - 1; 541 } 542 //index should never be 0, so this should be safe 543 if (index == instructions.size()) { 544 //if the end address is the same as the address of the last instruction, then 545 //this try item ends at the next to last instruction. 546 //otherwise, if the end address is past the address of the last instruction, 547 //thin this try item ends at the last instruction 548 if (instructions.get(instructions.size() - 1).getOffset() == endAddress) { 549 //get the address for the next to last instruction 550 index -= 2; 551 } else { 552 //get the address for the last instruction 553 index--; 554 } 555 } else { 556 index -= 2; 557 } 558 559 int lastInstructionOffset = instructions.get(index).getOffset(); 560 561 //add the catch all handler if it exists 562 int catchAllAddress = tryItem.encodedCatchHandler.getCatchAllHandlerAddress(); 563 if (catchAllAddress != -1) { 564 CatchMethodItem catchMethodItem = new CatchMethodItem(labels, lastInstructionOffset, stg, null, 565 startAddress, endAddress, catchAllAddress); 566 catches.add(catchMethodItem); 567 } 568 569 //add the rest of the handlers 570 for (CodeItem.EncodedTypeAddrPair handler: tryItem.encodedCatchHandler.handlers) { 571 //use the offset from the last covered instruction 572 CatchMethodItem catchMethodItem = new CatchMethodItem(labels, lastInstructionOffset, stg, 573 handler.exceptionType, startAddress, endAddress, handler.getHandlerAddress()); 574 catches.add(catchMethodItem); 575 } 576 } 577 } 578 579 private void addDebugInfo() { 580 DebugInfoItem debugInfoItem = codeItem.getDebugInfo(); 581 if (debugInfoItem == null) { 582 return; 583 } 584 585 DebugInstructionIterator.DecodeInstructions(debugInfoItem, codeItem.getRegisterCount(), 586 new DebugInstructionIterator.ProcessDecodedDebugInstructionDelegate() { 587 @Override 588 public void ProcessStartLocal(int codeAddress, int length, int registerNum, StringIdItem name, 589 TypeIdItem type) { 590 debugItems.add(new LocalDebugMethodItem(codeItem, codeAddress, stg, "StartLocal", -1, 591 registerNum, name, type, null)); 592 } 593 594 @Override 595 public void ProcessStartLocalExtended(int codeAddress, int length, int registerNum, 596 StringIdItem name, TypeIdItem type, 597 StringIdItem signature) { 598 debugItems.add(new LocalDebugMethodItem(codeItem, codeAddress, stg, "StartLocal", -1, 599 registerNum, name, type, signature)); 600 } 601 602 @Override 603 public void ProcessEndLocal(int codeAddress, int length, int registerNum, StringIdItem name, 604 TypeIdItem type, StringIdItem signature) { 605 debugItems.add(new LocalDebugMethodItem(codeItem, codeAddress, stg, "EndLocal", -1, 606 registerNum, name, type, signature)); 607 } 608 609 @Override 610 public void ProcessRestartLocal(int codeAddress, int length, int registerNum, StringIdItem name, 611 TypeIdItem type, StringIdItem signature) { 612 debugItems.add(new LocalDebugMethodItem(codeItem, codeAddress, stg, "RestartLocal", -1, 613 registerNum, name, type, signature)); 614 } 615 616 @Override 617 public void ProcessSetPrologueEnd(int codeAddress) { 618 debugItems.add(new DebugMethodItem(codeAddress, stg, "EndPrologue", -4)); 619 } 620 621 @Override 622 public void ProcessSetEpilogueBegin(int codeAddress) { 623 debugItems.add(new DebugMethodItem(codeAddress, stg, "StartEpilogue", -4)); 624 } 625 626 @Override 627 public void ProcessSetFile(int codeAddress, int length, final StringIdItem name) { 628 debugItems.add(new DebugMethodItem(codeAddress, stg, "SetFile", -3) { 629 @Override 630 protected void setAttributes(StringTemplate template) { 631 template.setAttribute("FileName", name.getStringValue()); 632 } 633 }); 634 } 635 636 @Override 637 public void ProcessLineEmit(int codeAddress, final int line) { 638 debugItems.add(new DebugMethodItem(codeAddress, stg, "Line", -2) { 639 @Override 640 protected void setAttributes(StringTemplate template) { 641 template.setAttribute("Line", line); 642 } 643 }); 644 } 645 }); 646 } 647 648 private void setLabelIndexes() { 649 HashMap<String, Integer> nextLabelIndexByType = new HashMap<String, Integer>(); 650 ArrayList<LabelMethodItem> sortedLabels = new ArrayList<LabelMethodItem>(labels.getLabels()); 651 652 //sort the labels by their location in the method 653 Collections.sort(sortedLabels); 654 655 for (LabelMethodItem labelMethodItem: sortedLabels) { 656 Integer labelIndex = nextLabelIndexByType.get(labelMethodItem.getLabelPrefix()); 657 if (labelIndex == null) { 658 labelIndex = 0; 659 } 660 labelMethodItem.setLabelIndex(labelIndex); 661 nextLabelIndexByType.put(labelMethodItem.getLabelPrefix(), labelIndex + 1); 662 } 663 } 664 } 665 666 public static class LabelCache { 667 protected HashMap<LabelMethodItem, LabelMethodItem> labels = new HashMap<LabelMethodItem, LabelMethodItem>(); 668 669 public LabelCache() { 670 } 671 672 public LabelMethodItem internLabel(LabelMethodItem labelMethodItem) { 673 LabelMethodItem internedLabelMethodItem = labels.get(labelMethodItem); 674 if (internedLabelMethodItem != null) { 675 if (!labelMethodItem.isCommentedOut()) { 676 internedLabelMethodItem.setUncommented(); 677 } 678 return internedLabelMethodItem; 679 } 680 labels.put(labelMethodItem, labelMethodItem); 681 return labelMethodItem; 682 } 683 684 685 public Collection<LabelMethodItem> getLabels() { 686 return labels.values(); 687 } 688 } 689} 690