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