SmaliCodeFragmentFactory.java revision ff4c85c5e4e380607fe1f89dc72db7339f77db8c
1a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver/* 2a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * Copyright 2014, Google Inc. 3a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * All rights reserved. 4a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * 5a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * Redistribution and use in source and binary forms, with or without 6a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * modification, are permitted provided that the following conditions are 7a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * met: 8a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * 9a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * * Redistributions of source code must retain the above copyright 10a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * notice, this list of conditions and the following disclaimer. 11a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * * Redistributions in binary form must reproduce the above 12a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * copyright notice, this list of conditions and the following disclaimer 13a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * in the documentation and/or other materials provided with the 14a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * distribution. 15a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * * Neither the name of Google Inc. nor the names of its 16a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * contributors may be used to endorse or promote products derived from 17a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * this software without specific prior written permission. 18a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * 19a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver */ 31a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver 32a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruverpackage org.jf.smalidea.debugging; 33a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver 34aebb205aebd103044de0b62fb9e971631f396057Ben Gruverimport com.google.common.collect.Lists; 35a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruverimport com.google.common.collect.Maps; 36aebb205aebd103044de0b62fb9e971631f396057Ben Gruverimport com.intellij.debugger.SourcePosition; 37a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruverimport com.intellij.debugger.engine.evaluation.*; 38aebb205aebd103044de0b62fb9e971631f396057Ben Gruverimport com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilder; 39aebb205aebd103044de0b62fb9e971631f396057Ben Gruverimport com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator; 40aebb205aebd103044de0b62fb9e971631f396057Ben Gruverimport com.intellij.debugger.engine.jdi.StackFrameProxy; 414a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruverimport com.intellij.openapi.application.ApplicationManager; 42a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruverimport com.intellij.openapi.fileTypes.LanguageFileType; 43a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruverimport com.intellij.openapi.project.Project; 444a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruverimport com.intellij.openapi.util.Computable; 45aebb205aebd103044de0b62fb9e971631f396057Ben Gruverimport com.intellij.openapi.util.Key; 46a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruverimport com.intellij.psi.JavaCodeFragment; 47a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruverimport com.intellij.psi.JavaRecursiveElementVisitor; 48a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruverimport com.intellij.psi.PsiElement; 49a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruverimport com.intellij.psi.PsiLocalVariable; 50f16ea398a1df52e3bb6afbbb274c66e23412ae58Ben Gruverimport com.intellij.psi.util.PsiMatchers; 51a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruverimport com.sun.jdi.*; 52a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruverimport com.sun.tools.jdi.LocalVariableImpl; 53a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruverimport com.sun.tools.jdi.LocationImpl; 54a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruverimport org.jf.dexlib2.analysis.AnalyzedInstruction; 55a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruverimport org.jf.dexlib2.analysis.RegisterType; 56a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruverimport org.jf.smalidea.SmaliFileType; 5793ae7badcd0bf77580b9ccd6f7febe662279b4d0Ben Gruverimport org.jf.smalidea.SmaliLanguage; 58aebb205aebd103044de0b62fb9e971631f396057Ben Gruverimport org.jf.smalidea.debugging.value.LazyValue; 59a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruverimport org.jf.smalidea.psi.impl.SmaliInstruction; 60a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruverimport org.jf.smalidea.psi.impl.SmaliMethod; 61ff4c85c5e4e380607fe1f89dc72db7339f77db8cBen Gruverimport org.jf.smalidea.util.NameUtils; 62f16ea398a1df52e3bb6afbbb274c66e23412ae58Ben Gruverimport org.jf.smalidea.util.PsiUtil; 63a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver 64a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruverimport java.lang.reflect.Constructor; 654a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruverimport java.lang.reflect.InvocationTargetException; 66aebb205aebd103044de0b62fb9e971631f396057Ben Gruverimport java.util.List; 67a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruverimport java.util.Map; 68a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver 69a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruverpublic class SmaliCodeFragmentFactory extends DefaultCodeFragmentFactory { 70aebb205aebd103044de0b62fb9e971631f396057Ben Gruver static final Key<List<LazyValue>> SMALI_LAZY_VALUES_KEY = Key.create("_smali_register_value_key_"); 71aebb205aebd103044de0b62fb9e971631f396057Ben Gruver 72a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver @Override 73a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver public JavaCodeFragment createCodeFragment(TextWithImports item, PsiElement context, Project project) { 74aebb205aebd103044de0b62fb9e971631f396057Ben Gruver context = wrapContext(project, context); 75aebb205aebd103044de0b62fb9e971631f396057Ben Gruver JavaCodeFragment fragment = super.createCodeFragment(item, context, project); 76aebb205aebd103044de0b62fb9e971631f396057Ben Gruver List<LazyValue> lazyValues = context.getUserData(SMALI_LAZY_VALUES_KEY); 77aebb205aebd103044de0b62fb9e971631f396057Ben Gruver if (lazyValues != null) { 78aebb205aebd103044de0b62fb9e971631f396057Ben Gruver fragment.putUserData(SMALI_LAZY_VALUES_KEY, lazyValues); 79aebb205aebd103044de0b62fb9e971631f396057Ben Gruver } 80aebb205aebd103044de0b62fb9e971631f396057Ben Gruver return fragment; 81a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver } 82a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver 83a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver @Override 8493ae7badcd0bf77580b9ccd6f7febe662279b4d0Ben Gruver public boolean isContextAccepted(PsiElement contextElement) { 853f4e6a388a1d79980f6bc02a848873553c7c1c16Ben Gruver if (contextElement == null) { 863f4e6a388a1d79980f6bc02a848873553c7c1c16Ben Gruver return false; 873f4e6a388a1d79980f6bc02a848873553c7c1c16Ben Gruver } 8893ae7badcd0bf77580b9ccd6f7febe662279b4d0Ben Gruver return contextElement.getLanguage() == SmaliLanguage.INSTANCE; 8993ae7badcd0bf77580b9ccd6f7febe662279b4d0Ben Gruver } 9093ae7badcd0bf77580b9ccd6f7febe662279b4d0Ben Gruver 9193ae7badcd0bf77580b9ccd6f7febe662279b4d0Ben Gruver @Override 92a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver public JavaCodeFragment createPresentationCodeFragment(TextWithImports item, PsiElement context, Project project) { 93aebb205aebd103044de0b62fb9e971631f396057Ben Gruver context = wrapContext(project, context); 94aebb205aebd103044de0b62fb9e971631f396057Ben Gruver JavaCodeFragment fragment = super.createPresentationCodeFragment(item, context, project); 95aebb205aebd103044de0b62fb9e971631f396057Ben Gruver List<LazyValue> lazyValues = context.getUserData(SMALI_LAZY_VALUES_KEY); 96aebb205aebd103044de0b62fb9e971631f396057Ben Gruver if (lazyValues != null) { 97aebb205aebd103044de0b62fb9e971631f396057Ben Gruver fragment.putUserData(SMALI_LAZY_VALUES_KEY, lazyValues); 98aebb205aebd103044de0b62fb9e971631f396057Ben Gruver } 99aebb205aebd103044de0b62fb9e971631f396057Ben Gruver return fragment; 100a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver } 101a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver 102a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver @Override public LanguageFileType getFileType() { 103a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver return SmaliFileType.INSTANCE; 104a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver } 105a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver 106aebb205aebd103044de0b62fb9e971631f396057Ben Gruver @Override public EvaluatorBuilder getEvaluatorBuilder() { 107aebb205aebd103044de0b62fb9e971631f396057Ben Gruver final EvaluatorBuilder builder = super.getEvaluatorBuilder(); 108aebb205aebd103044de0b62fb9e971631f396057Ben Gruver return new EvaluatorBuilder() { 109aebb205aebd103044de0b62fb9e971631f396057Ben Gruver 110aebb205aebd103044de0b62fb9e971631f396057Ben Gruver @Override 111aebb205aebd103044de0b62fb9e971631f396057Ben Gruver public ExpressionEvaluator build(PsiElement codeFragment, SourcePosition position) 112aebb205aebd103044de0b62fb9e971631f396057Ben Gruver throws EvaluateException { 113aebb205aebd103044de0b62fb9e971631f396057Ben Gruver return new SmaliExpressionEvaluator(codeFragment, builder.build(codeFragment, position)); 114aebb205aebd103044de0b62fb9e971631f396057Ben Gruver } 115aebb205aebd103044de0b62fb9e971631f396057Ben Gruver }; 116aebb205aebd103044de0b62fb9e971631f396057Ben Gruver } 117aebb205aebd103044de0b62fb9e971631f396057Ben Gruver 118a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver private PsiElement wrapContext(final Project project, final PsiElement originalContext) { 119a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver if (project.isDefault()) return originalContext; 120a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver 121aebb205aebd103044de0b62fb9e971631f396057Ben Gruver final List<LazyValue> lazyValues = Lists.newArrayList(); 122a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver 123f16ea398a1df52e3bb6afbbb274c66e23412ae58Ben Gruver SmaliInstruction currentInstruction = (SmaliInstruction)PsiUtil.searchBackward(originalContext, 124f16ea398a1df52e3bb6afbbb274c66e23412ae58Ben Gruver PsiMatchers.hasClass(SmaliInstruction.class), 125f16ea398a1df52e3bb6afbbb274c66e23412ae58Ben Gruver PsiMatchers.hasClass(SmaliMethod.class)); 126f16ea398a1df52e3bb6afbbb274c66e23412ae58Ben Gruver 127f16ea398a1df52e3bb6afbbb274c66e23412ae58Ben Gruver if (currentInstruction == null) { 128f16ea398a1df52e3bb6afbbb274c66e23412ae58Ben Gruver currentInstruction = (SmaliInstruction)PsiUtil.searchForward(originalContext, 129f16ea398a1df52e3bb6afbbb274c66e23412ae58Ben Gruver PsiMatchers.hasClass(SmaliInstruction.class), 130f16ea398a1df52e3bb6afbbb274c66e23412ae58Ben Gruver PsiMatchers.hasClass(SmaliMethod.class)); 131f16ea398a1df52e3bb6afbbb274c66e23412ae58Ben Gruver if (currentInstruction == null) { 132f16ea398a1df52e3bb6afbbb274c66e23412ae58Ben Gruver return originalContext; 133f16ea398a1df52e3bb6afbbb274c66e23412ae58Ben Gruver } 134f16ea398a1df52e3bb6afbbb274c66e23412ae58Ben Gruver } 135a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver 136a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver final SmaliMethod containingMethod = currentInstruction.getParentMethod(); 137a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver AnalyzedInstruction analyzedInstruction = currentInstruction.getAnalyzedInstruction(); 138ea04d22ffd6dfba6cb4309550e0cbe445e0fef89Ben Gruver if (analyzedInstruction == null) { 139ea04d22ffd6dfba6cb4309550e0cbe445e0fef89Ben Gruver return originalContext; 140ea04d22ffd6dfba6cb4309550e0cbe445e0fef89Ben Gruver } 141a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver 142a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver final int firstParameterRegister = containingMethod.getRegisterCount() - 143a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver containingMethod.getParameterRegisterCount(); 144a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver 145a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver final Map<String, String> registerMap = Maps.newHashMap(); 146a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver StringBuilder variablesText = new StringBuilder(); 147a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver for (int i=0; i<containingMethod.getRegisterCount(); i++) { 148a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver int parameterRegisterNumber = i - firstParameterRegister; 149a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver 150a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(i); 151a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver switch (registerType.category) { 152a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver case RegisterType.UNKNOWN: 153a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver case RegisterType.UNINIT: 154a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver case RegisterType.CONFLICTED: 155a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver case RegisterType.LONG_HI: 156a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver case RegisterType.DOUBLE_HI: 157a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver continue; 158a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver case RegisterType.NULL: 159a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver case RegisterType.ONE: 160a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver case RegisterType.INTEGER: 161a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver variablesText.append("int v").append(i).append(";\n"); 162a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver registerMap.put("v" + i, "I"); 163a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver if (parameterRegisterNumber >= 0) { 164a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver variablesText.append("int p").append(parameterRegisterNumber).append(";\n"); 165a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver registerMap.put("p" + parameterRegisterNumber, "I"); 166a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver } 167a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver break; 168a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver case RegisterType.BOOLEAN: 169a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver variablesText.append("boolean v").append(i).append(";\n"); 170a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver registerMap.put("v" + i, "Z"); 171a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver if (parameterRegisterNumber >= 0) { 172a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver variablesText.append("boolean p").append(parameterRegisterNumber).append(";\n"); 173a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver registerMap.put("p" + parameterRegisterNumber, "Z"); 174a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver } 175a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver break; 176a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver case RegisterType.BYTE: 177a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver case RegisterType.POS_BYTE: 178a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver variablesText.append("byte v").append(i).append(";\n"); 179a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver registerMap.put("v" + i, "B"); 180a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver if (parameterRegisterNumber >= 0) { 181a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver variablesText.append("byte p").append(parameterRegisterNumber).append(";\n"); 182a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver registerMap.put("p" + parameterRegisterNumber, "B"); 183a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver } 184a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver break; 185a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver case RegisterType.SHORT: 186a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver case RegisterType.POS_SHORT: 187a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver variablesText.append("short v").append(i).append(";\n"); 188a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver registerMap.put("v" + i, "S"); 189a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver if (parameterRegisterNumber >= 0) { 190a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver variablesText.append("short p").append(parameterRegisterNumber).append(";\n"); 191a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver registerMap.put("p" + parameterRegisterNumber, "S"); 192a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver } 193a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver break; 194a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver case RegisterType.CHAR: 195a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver variablesText.append("char v").append(i).append(";\n"); 196a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver registerMap.put("v" + i, "C"); 197a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver if (parameterRegisterNumber >= 0) { 198a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver variablesText.append("char p").append(parameterRegisterNumber).append(";\n"); 199a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver registerMap.put("p" + parameterRegisterNumber, "C"); 200a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver } 201a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver break; 202a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver case RegisterType.FLOAT: 203a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver variablesText.append("float v").append(i).append(";\n"); 204a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver registerMap.put("v" + i, "F"); 205a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver if (parameterRegisterNumber >= 0) { 206a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver variablesText.append("float p").append(parameterRegisterNumber).append(";\n"); 207a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver registerMap.put("p" + parameterRegisterNumber, "F"); 208a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver } 209a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver break; 210a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver case RegisterType.LONG_LO: 211a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver variablesText.append("long v").append(i).append(";\n"); 212a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver registerMap.put("v" + i, "J"); 213a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver if (parameterRegisterNumber >= 0) { 214a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver variablesText.append("long p").append(parameterRegisterNumber).append(";\n"); 215a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver registerMap.put("p" + parameterRegisterNumber, "J"); 216a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver } 217a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver break; 218a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver case RegisterType.DOUBLE_LO: 219a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver variablesText.append("double v").append(i).append(";\n"); 220a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver registerMap.put("v" + i, "D"); 221a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver if (parameterRegisterNumber >= 0) { 222a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver variablesText.append("double p").append(parameterRegisterNumber).append(";\n"); 223a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver registerMap.put("p" + parameterRegisterNumber, "D"); 224a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver } 225a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver break; 226a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver case RegisterType.UNINIT_REF: 227a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver case RegisterType.UNINIT_THIS: 228a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver case RegisterType.REFERENCE: 229ff4c85c5e4e380607fe1f89dc72db7339f77db8cBen Gruver String smaliType = registerType.type.getType(); 230ff4c85c5e4e380607fe1f89dc72db7339f77db8cBen Gruver String javaType = NameUtils.smaliToJavaType(smaliType); 231ff4c85c5e4e380607fe1f89dc72db7339f77db8cBen Gruver variablesText.append(javaType).append(" v").append(i).append(";\n"); 232ff4c85c5e4e380607fe1f89dc72db7339f77db8cBen Gruver registerMap.put("v" + i, smaliType); 233a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver if (parameterRegisterNumber >= 0) { 234ff4c85c5e4e380607fe1f89dc72db7339f77db8cBen Gruver variablesText.append(javaType).append(" p").append(parameterRegisterNumber).append(";\n"); 235a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver registerMap.put("p" + parameterRegisterNumber, "Ljava/lang/Object;"); 236a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver } 237a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver break; 238a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver } 239a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver } 240a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver final TextWithImportsImpl textWithImports = new TextWithImportsImpl(CodeFragmentKind.CODE_BLOCK, 241a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver variablesText.toString(), "", getFileType()); 242a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver 243a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver final JavaCodeFragment codeFragment = super.createCodeFragment(textWithImports, originalContext, project); 244a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver 245a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver codeFragment.accept(new JavaRecursiveElementVisitor() { 2464a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver @Override 247a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver public void visitLocalVariable(final PsiLocalVariable variable) { 248a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver final String name = variable.getName(); 249a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver if (registerMap.containsKey(name)) { 250aebb205aebd103044de0b62fb9e971631f396057Ben Gruver int registerNumber = Integer.parseInt(name.substring(1)); 251aebb205aebd103044de0b62fb9e971631f396057Ben Gruver if (name.charAt(0) == 'p') { 252aebb205aebd103044de0b62fb9e971631f396057Ben Gruver registerNumber += ApplicationManager.getApplication().runReadAction(new Computable<Integer>() { 253aebb205aebd103044de0b62fb9e971631f396057Ben Gruver @Override public Integer compute() { 254aebb205aebd103044de0b62fb9e971631f396057Ben Gruver return containingMethod.getRegisterCount() - 255aebb205aebd103044de0b62fb9e971631f396057Ben Gruver containingMethod.getParameterRegisterCount(); 256a5efca6fe61d8fa6a5b7d1430b836635ba455f1eBen Gruver } 257aebb205aebd103044de0b62fb9e971631f396057Ben Gruver }); 258aebb205aebd103044de0b62fb9e971631f396057Ben Gruver } 259aebb205aebd103044de0b62fb9e971631f396057Ben Gruver LazyValue lazyValue = LazyValue.create(containingMethod, project, registerNumber, 260aebb205aebd103044de0b62fb9e971631f396057Ben Gruver registerMap.get(name)); 261aebb205aebd103044de0b62fb9e971631f396057Ben Gruver variable.putUserData(CodeFragmentFactoryContextWrapper.LABEL_VARIABLE_VALUE_KEY, lazyValue); 262aebb205aebd103044de0b62fb9e971631f396057Ben Gruver lazyValues.add(lazyValue); 263a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver } 264a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver } 265a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver }); 266a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver 267a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver int offset = variablesText.length() - 1; 268a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver 269a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver final PsiElement newContext = codeFragment.findElementAt(offset); 270a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver if (newContext != null) { 271aebb205aebd103044de0b62fb9e971631f396057Ben Gruver newContext.putUserData(SMALI_LAZY_VALUES_KEY, lazyValues); 272a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver return newContext; 273a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver } 274a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver return originalContext; 275a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver } 276a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver 277aebb205aebd103044de0b62fb9e971631f396057Ben Gruver public static Value evaluateRegister(EvaluationContext context, final SmaliMethod smaliMethod, 278aebb205aebd103044de0b62fb9e971631f396057Ben Gruver final int registerNum, final String type) throws EvaluateException { 279aebb205aebd103044de0b62fb9e971631f396057Ben Gruver 280aebb205aebd103044de0b62fb9e971631f396057Ben Gruver final StackFrameProxy frameProxy = context.getSuspendContext().getFrameProxy(); 281a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver if (frameProxy == null) { 282a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver return null; 283a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver } 284a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver 285aebb205aebd103044de0b62fb9e971631f396057Ben Gruver VirtualMachine vm = frameProxy.getStackFrame().virtualMachine(); 2864a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver Location currentLocation = frameProxy.location(); 2874a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver if (currentLocation == null) { 2884a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver return null; 2894a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver } 290a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver 2914a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver Method method = currentLocation.method(); 292a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver 2934a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver try { 2944a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver final Constructor<LocalVariableImpl> localVariableConstructor = LocalVariableImpl.class.getDeclaredConstructor( 2954a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver VirtualMachine.class, Method.class, Integer.TYPE, Location.class, Location.class, String.class, 2964a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver String.class, String.class); 2974a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver localVariableConstructor.setAccessible(true); 298a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver 2994a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver Constructor<LocationImpl> locationConstructor = LocationImpl.class.getDeclaredConstructor( 3004a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver VirtualMachine.class, Method.class, Long.TYPE); 3014a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver locationConstructor.setAccessible(true); 302a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver 303aebb205aebd103044de0b62fb9e971631f396057Ben Gruver int methodSize = 0; 304aebb205aebd103044de0b62fb9e971631f396057Ben Gruver for (SmaliInstruction instruction: smaliMethod.getInstructions()) { 305aebb205aebd103044de0b62fb9e971631f396057Ben Gruver methodSize += instruction.getInstructionSize(); 306aebb205aebd103044de0b62fb9e971631f396057Ben Gruver } 307aebb205aebd103044de0b62fb9e971631f396057Ben Gruver Location endLocation = method.locationOfCodeIndex((methodSize/2) - 1); 308a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver 3094a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver LocalVariable localVariable = localVariableConstructor.newInstance(vm, 3104a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver method, 3114a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver mapRegister(frameProxy.getStackFrame().virtualMachine(), smaliMethod, registerNum), 3124a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver method.locationOfCodeIndex(0), 3134a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver endLocation, 3144a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver String.format("v%d", registerNum), type, null); 315a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver 3164a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver return frameProxy.getStackFrame().getValue(localVariable); 3174a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver } catch (NoSuchMethodException e) { 3184a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver return null; 3194a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver } catch (InstantiationException e) { 3204a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver return null; 3214a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver } catch (IllegalAccessException e) { 3224a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver return null; 3234a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver } catch (InvocationTargetException e) { 3244a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver return null; 3254a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver } 3264a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver } 327a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver 3284a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver private static int mapRegister(final VirtualMachine vm, final SmaliMethod smaliMethod, final int register) { 3294a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver if (vm.version().equals("1.5.0")) { 3304a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver return mapRegisterForDalvik(smaliMethod, register); 3314a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver } else { 3324a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver return mapRegisterForArt(smaliMethod, register); 3334a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver } 334a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver } 335a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver 3366649a7553258d7651a1d6c3ee010d380c6f90e7aBen Gruver private static int mapRegisterForArt(final SmaliMethod smaliMethod, final int register) { 3376649a7553258d7651a1d6c3ee010d380c6f90e7aBen Gruver return ApplicationManager.getApplication().runReadAction(new Computable<Integer>() { 3386649a7553258d7651a1d6c3ee010d380c6f90e7aBen Gruver @Override public Integer compute() { 339a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver 3406649a7553258d7651a1d6c3ee010d380c6f90e7aBen Gruver int totalRegisters = smaliMethod.getRegisterCount(); 3416649a7553258d7651a1d6c3ee010d380c6f90e7aBen Gruver int parameterRegisters = smaliMethod.getParameterRegisterCount(); 3426649a7553258d7651a1d6c3ee010d380c6f90e7aBen Gruver 3436649a7553258d7651a1d6c3ee010d380c6f90e7aBen Gruver if (smaliMethod.getModifierList().hasModifierProperty("static")) { 3446649a7553258d7651a1d6c3ee010d380c6f90e7aBen Gruver return register; 3456649a7553258d7651a1d6c3ee010d380c6f90e7aBen Gruver } 3466649a7553258d7651a1d6c3ee010d380c6f90e7aBen Gruver 3476649a7553258d7651a1d6c3ee010d380c6f90e7aBen Gruver // For ART, the parameter registers are rotated to the front 3486649a7553258d7651a1d6c3ee010d380c6f90e7aBen Gruver if (register >= (totalRegisters - parameterRegisters)) { 3496649a7553258d7651a1d6c3ee010d380c6f90e7aBen Gruver return register - (totalRegisters - parameterRegisters); 3506649a7553258d7651a1d6c3ee010d380c6f90e7aBen Gruver } 3516649a7553258d7651a1d6c3ee010d380c6f90e7aBen Gruver return register + parameterRegisters; 3526649a7553258d7651a1d6c3ee010d380c6f90e7aBen Gruver } 3536649a7553258d7651a1d6c3ee010d380c6f90e7aBen Gruver }); 354a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver } 3554a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver 3564a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver private static int mapRegisterForDalvik(final SmaliMethod smaliMethod, final int register) { 3574a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver return ApplicationManager.getApplication().runReadAction(new Computable<Integer>() { 3584a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver @Override public Integer compute() { 3594a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver if (smaliMethod.getModifierList().hasModifierProperty("static")) { 3604a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver return register; 3614a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver } 3624a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver 3634a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver int totalRegisters = smaliMethod.getRegisterCount(); 3644a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver int parameterRegisters = smaliMethod.getParameterRegisterCount(); 3654a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver 3664a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver // For dalvik, p0 is mapped to register 1, and register 0 is mapped to register 1000 3674a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver if (register == (totalRegisters - parameterRegisters)) { 3684a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver return 0; 3694a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver } 3704a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver if (register == 0) { 3714a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver return 1000; 3724a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver } 3734a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver return register; 3744a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver } 3754a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver }); 3764a9e7df53e6c4b4fe047eec058d2220ea4ab959cBen Gruver } 377a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver} 378a28e8f236378cb6c2299a5bc9816702f8fc75bd8Ben Gruver 379