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();
24966892009f5e0037725ab7278e697515ba22d704dBen Gruver                if (name != null && 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