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