MethodDefinition.java revision db49fd7714893b35ba7de51fae8d8e386f3dc335
136836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com/*
236836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * [The "BSD licence"]
300fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * Copyright (c) 2010 Ben Gruver (JesusFreke)
436836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * All rights reserved.
536836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com *
636836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * Redistribution and use in source and binary forms, with or without
736836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * modification, are permitted provided that the following conditions
836836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * are met:
936836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * 1. Redistributions of source code must retain the above copyright
1036836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com *    notice, this list of conditions and the following disclaimer.
1136836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * 2. Redistributions in binary form must reproduce the above copyright
1236836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com *    notice, this list of conditions and the following disclaimer in the
1336836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com *    documentation and/or other materials provided with the distribution.
1436836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * 3. The name of the author may not be used to endorse or promote products
1536836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com *    derived from this software without specific prior written permission.
1636836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com *
1736836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1836836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1936836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2036836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2136836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2236836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2336836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2436836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2536836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2636836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2736836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com */
2836836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com
296ef13753e78bb7abc7e7683d5e533c3395d4a9b6JesusFreke@JesusFreke.compackage org.jf.baksmali.Adaptors;
3036836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com
31754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruverimport org.jf.baksmali.Adaptors.Debug.DebugMethodItem;
32fbea4e751fa6f1748ded4379a4b64601cb53ba7bJesusFreke@JesusFreke.comimport org.jf.baksmali.Adaptors.Format.InstructionMethodItemFactory;
33754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruverimport org.jf.dexlib2.AccessFlags;
34754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruverimport org.jf.dexlib2.Opcode;
35754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruverimport org.jf.dexlib2.iface.*;
36754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruverimport org.jf.dexlib2.iface.debug.DebugItem;
37754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruverimport org.jf.dexlib2.iface.instruction.Instruction;
38754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruverimport org.jf.dexlib2.iface.instruction.OffsetInstruction;
39754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruverimport org.jf.dexlib2.util.InstructionOffsetMap;
40754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruverimport org.jf.dexlib2.util.MethodUtil;
41754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruverimport org.jf.dexlib2.util.TypeUtils;
424b72225e9d81201838f387171a68a832486903f9JesusFreke@JesusFreke.comimport org.jf.util.IndentingWriter;
435b89857df3124851183c75a134f10b6ba41512a9JesusFreke@JesusFreke.comimport org.jf.baksmali.baksmali;
44bf95959ae43ddd003936a01dfaecc612a438d4b5Ben Gruverimport org.jf.util.ExceptionWithContext;
45b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.comimport org.jf.dexlib.Util.SparseIntArray;
4636836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com
47754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruverimport javax.annotation.Nonnull;
486eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.comimport java.io.IOException;
499bc4978139ca38e422ae89065d3062146534132dJesusFreke@JesusFreke.comimport java.util.*;
500b2f7d6a57e90424b3ee455c041aab3996c05f2cJesusFreke@JesusFreke.com
5136836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.compublic class MethodDefinition {
52754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    @Nonnull public final ClassDefinition classDef;
53754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    @Nonnull public final Method method;
54754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    @Nonnull public final MethodImplementation methodImpl;
55754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    public RegisterFormatter registerFormatter;
56b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com
57754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    @Nonnull private final String methodString;
58b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com
59754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    @Nonnull private final LabelCache labelCache = new LabelCache();
60b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com
61754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    @Nonnull private final SparseIntArray packedSwitchMap;
62754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    @Nonnull private final SparseIntArray sparseSwitchMap;
63754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    @Nonnull private final InstructionOffsetMap instructionOffsetMap;
6410a95181115741071ae23911413a3f731047621cJesusFreke@JesusFreke.com
65754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    public MethodDefinition(@Nonnull ClassDefinition classDef, @Nonnull Method method,
66754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                            @Nonnull MethodImplementation methodImpl) {
67754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        this.classDef = classDef;
68754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        this.method = method;
69754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        this.methodImpl = methodImpl;
7010a95181115741071ae23911413a3f731047621cJesusFreke@JesusFreke.com
71754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        this.methodString = MethodUtil.buildFullMethodString(classDef.classDef, method);
7210a95181115741071ae23911413a3f731047621cJesusFreke@JesusFreke.com
73754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        try {
7410a95181115741071ae23911413a3f731047621cJesusFreke@JesusFreke.com            //TODO: what about try/catch blocks inside the dead code? those will need to be commented out too. ugh.
7510a95181115741071ae23911413a3f731047621cJesusFreke@JesusFreke.com
76754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            List<? extends Instruction> instructions = methodImpl.getInstructions();
77754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver
78754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            packedSwitchMap = new SparseIntArray(0);
79754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            sparseSwitchMap = new SparseIntArray(0);
80754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            instructionOffsetMap = new InstructionOffsetMap(methodImpl);
81754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver
82754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            for (int i=0; i<instructions.size(); i++) {
83754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                Instruction instruction = instructions.get(i);
84754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver
85754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                Opcode opcode = instruction.getOpcode();
86754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                if (opcode == Opcode.PACKED_SWITCH) {
87754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i);
88754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset();
89754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    targetOffset = findSwitchPayload(targetOffset, Opcode.PACKED_SWITCH_PAYLOAD);
90d3dd617d250771840c801009e4f71d971c4d4061Ben Gruver                    packedSwitchMap.append(targetOffset, codeOffset);
91754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                } else if (opcode == Opcode.SPARSE_SWITCH) {
92754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    int codeOffset = instructionOffsetMap.getInstructionCodeOffset(i);
93754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    int targetOffset = codeOffset + ((OffsetInstruction)instruction).getCodeOffset();
94754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    targetOffset = findSwitchPayload(targetOffset, Opcode.SPARSE_SWITCH_PAYLOAD);
95d3dd617d250771840c801009e4f71d971c4d4061Ben Gruver                    sparseSwitchMap.append(targetOffset, codeOffset);
96b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com                }
97b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com            }
9810a95181115741071ae23911413a3f731047621cJesusFreke@JesusFreke.com        }catch (Exception ex) {
99754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            throw ExceptionWithContext.withContext(ex, "Error while processing method %s", methodString);
100b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        }
101b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com    }
102b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com
103754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    public static void writeEmptyMethodTo(IndentingWriter writer, Method method) throws IOException {
1046eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com        writer.write(".method ");
105754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writeAccessFlags(writer, method.getAccessFlags());
106754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.write(method.getName());
107754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.write("(");
108754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        for (MethodParameter parameter: method.getParameters()) {
109754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            writer.write(parameter.getType());
110754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        }
111754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.write(")");
112754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.write(method.getReturnType());
1130b2f7d6a57e90424b3ee455c041aab3996c05f2cJesusFreke@JesusFreke.com        writer.write('\n');
11436836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com
1156eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com        writer.indent(4);
116c3a3ee3799e354b6718ce8eee2cf20cbac1ca9d9Ben Gruver        writeParameters(writer, method);
117754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        AnnotationFormatter.writeTo(writer, method.getAnnotations());
1186eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com        writer.deindent(4);
1190b2f7d6a57e90424b3ee455c041aab3996c05f2cJesusFreke@JesusFreke.com        writer.write(".end method\n");
12036836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com    }
12136836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com
122754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    public void writeTo(IndentingWriter writer) throws IOException {
123754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        int parameterRegisterCount = 0;
124754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        if (!AccessFlags.STATIC.isSet(method.getAccessFlags())) {
125754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            parameterRegisterCount++;
12636836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com        }
127fa07a1972e3cff56d5615c18a8797ff58fc9f739JesusFreke@JesusFreke.com
128754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.write(".method ");
129754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writeAccessFlags(writer, method.getAccessFlags());
130754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.write(method.getName());
131754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.write("(");
132754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        for (MethodParameter parameter: method.getParameters()) {
133754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            String type = parameter.getType();
134754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            writer.write(type);
135754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            parameterRegisterCount++;
136754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            if (TypeUtils.isWideType(type)) {
137754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                parameterRegisterCount++;
138754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            }
1393c9013f9c08fa8effc9f6d4dc58212c68eb21742JesusFreke@JesusFreke.com        }
140754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.write(")");
141754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.write(method.getReturnType());
142754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.write('\n');
1433c9013f9c08fa8effc9f6d4dc58212c68eb21742JesusFreke@JesusFreke.com
144754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.indent(4);
145754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        if (baksmali.useLocalsDirective) {
146754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            writer.write(".locals ");
147754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            writer.printSignedIntAsDec(methodImpl.getRegisterCount() - parameterRegisterCount);
1486eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com        } else {
149754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            writer.write(".registers ");
150754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            writer.printSignedIntAsDec(methodImpl.getRegisterCount());
1516eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com        }
152754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.write('\n');
153c3a3ee3799e354b6718ce8eee2cf20cbac1ca9d9Ben Gruver        writeParameters(writer, method);
1543c9013f9c08fa8effc9f6d4dc58212c68eb21742JesusFreke@JesusFreke.com
155754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        if (registerFormatter == null) {
156754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            registerFormatter = new RegisterFormatter(methodImpl.getRegisterCount(), parameterRegisterCount);
1573c9013f9c08fa8effc9f6d4dc58212c68eb21742JesusFreke@JesusFreke.com        }
1583c9013f9c08fa8effc9f6d4dc58212c68eb21742JesusFreke@JesusFreke.com
159754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        AnnotationFormatter.writeTo(writer, method.getAnnotations());
1603c9013f9c08fa8effc9f6d4dc58212c68eb21742JesusFreke@JesusFreke.com
161754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.write('\n');
1626eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com
163db49fd7714893b35ba7de51fae8d8e386f3dc335Ben Gruver        List<MethodItem> methodItems = getMethodItems();
164db49fd7714893b35ba7de51fae8d8e386f3dc335Ben Gruver        int size = methodItems.size();
165db49fd7714893b35ba7de51fae8d8e386f3dc335Ben Gruver        for (int i=0; i<size; i++) {
166db49fd7714893b35ba7de51fae8d8e386f3dc335Ben Gruver            MethodItem methodItem = methodItems.get(i);
167754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            if (methodItem.writeTo(writer)) {
168754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                writer.write('\n');
1696eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com            }
1706eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com        }
171754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.deindent(4);
172754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.write(".end method\n");
1733c9013f9c08fa8effc9f6d4dc58212c68eb21742JesusFreke@JesusFreke.com    }
1743c9013f9c08fa8effc9f6d4dc58212c68eb21742JesusFreke@JesusFreke.com
175754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    private int findSwitchPayload(int targetOffset, Opcode type) {
176754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        int targetIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(targetOffset);
177754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver
178754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        //TODO: does dalvik let you pad with multiple nops?
179754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        //TODO: does dalvik let a switch instruction point to a non-payload instruction?
180754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver
181754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        List<? extends Instruction> instructions = methodImpl.getInstructions();
182754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        Instruction instruction = instructions.get(targetIndex);
183754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        if (instruction.getOpcode() != type) {
184754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            // maybe it's pointing to a NOP padding instruction. Look at the next instruction
185754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            if (instruction.getOpcode() == Opcode.NOP) {
186754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                targetIndex += 1;
187754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                if (targetIndex < instructions.size()) {
188754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    instruction = instructions.get(targetIndex);
189754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    if (instruction.getOpcode() == type) {
190754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                        return instructionOffsetMap.getInstructionCodeOffset(targetIndex);
191754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    }
192754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                }
193754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            }
194754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            throw new ExceptionWithContext("No switch payload at offset 0x%x", targetOffset);
195754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        } else {
196754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            return targetOffset;
197c9be5e13034da9827b5598a6257376164745b827JesusFreke@JesusFreke.com        }
198c9be5e13034da9827b5598a6257376164745b827JesusFreke@JesusFreke.com    }
199c9be5e13034da9827b5598a6257376164745b827JesusFreke@JesusFreke.com
200754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    private static void writeAccessFlags(IndentingWriter writer, int accessFlags)
201754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            throws IOException {
202754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForMethod(accessFlags)) {
203754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            writer.write(accessFlag.toString());
204754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            writer.write(' ');
205b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        }
206b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com    }
207b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com
208c3a3ee3799e354b6718ce8eee2cf20cbac1ca9d9Ben Gruver    private static void writeParameters(IndentingWriter writer, Method method) throws IOException {
209c3a3ee3799e354b6718ce8eee2cf20cbac1ca9d9Ben Gruver        boolean isStatic = AccessFlags.STATIC.isSet(method.getAccessFlags());
210c3a3ee3799e354b6718ce8eee2cf20cbac1ca9d9Ben Gruver        int registerNumber = isStatic?0:1;
211c3a3ee3799e354b6718ce8eee2cf20cbac1ca9d9Ben Gruver        for (MethodParameter parameter: method.getParameters()) {
212754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            String parameterType = parameter.getType();
213754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            String parameterName = parameter.getName();
214754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            List<? extends Annotation> annotations = parameter.getAnnotations();
215754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            if (parameterName != null || annotations.size() != 0) {
21616f257ee8f12974c62e50643b2f87533513da455Ben Gruver                writer.write(".param p");
217754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                writer.printSignedIntAsDec(registerNumber);
218754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                if (parameterName != null) {
21916f257ee8f12974c62e50643b2f87533513da455Ben Gruver                    writer.write(", ");
220db4316ef6ddeaaae94ca88673b6bac1c2b29eec5Ben Gruver                    // TODO: does dalvik allow non-identifier parameter and/or local names?
221754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    writer.write(parameterName);
222754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                }
223c3a3ee3799e354b6718ce8eee2cf20cbac1ca9d9Ben Gruver                writer.write("    # ");
22416f257ee8f12974c62e50643b2f87533513da455Ben Gruver                writer.write(parameterType);
225754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                if (annotations.size() > 0) {
226754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    writer.indent(4);
227754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    AnnotationFormatter.writeTo(writer, annotations);
228754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    writer.deindent(4);
22916f257ee8f12974c62e50643b2f87533513da455Ben Gruver                    writer.write(".end param\n");
230754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                } else {
231754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    writer.write("\n");
232754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                }
233754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            }
234cb3e0ea38a669633b8daefd538750c8ded46f524Ben Gruver
235754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            registerNumber++;
236754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            if (TypeUtils.isWideType(parameterType)) {
237754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                registerNumber++;
238cb3e0ea38a669633b8daefd538750c8ded46f524Ben Gruver            }
239b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        }
240b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com    }
241b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com
242754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    @Nonnull public LabelCache getLabelCache() {
243754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        return labelCache;
244754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    }
245db26b663aa3b5bb721185b8798b6767710d3c243JesusFreke@JesusFreke.com
246754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    public int getPackedSwitchBaseAddress(int packedSwitchPayloadCodeOffset) {
247754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        return packedSwitchMap.get(packedSwitchPayloadCodeOffset, -1);
248db26b663aa3b5bb721185b8798b6767710d3c243JesusFreke@JesusFreke.com    }
249db26b663aa3b5bb721185b8798b6767710d3c243JesusFreke@JesusFreke.com
250754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    public int getSparseSwitchBaseAddress(int sparseSwitchPayloadCodeOffset) {
251754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        return sparseSwitchMap.get(sparseSwitchPayloadCodeOffset, -1);
252343df2f456f38c305ee7d6742f6601d9bde09715Ben Gruver    }
253343df2f456f38c305ee7d6742f6601d9bde09715Ben Gruver
254b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com    private List<MethodItem> getMethodItems() {
255f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        ArrayList<MethodItem> methodItems = new ArrayList<MethodItem>();
2569bc4978139ca38e422ae89065d3062146534132dJesusFreke@JesusFreke.com
257754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        //TODO: addAnalyzedInstructionMethodItems
258754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        addInstructionMethodItems(methodItems);
259f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
260f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        addTries(methodItems);
2618913c59363230bc1bf787b7e24941cb13209de0cJesusFreke@JesusFreke.com        if (baksmali.outputDebugInfo) {
2628913c59363230bc1bf787b7e24941cb13209de0cJesusFreke@JesusFreke.com            addDebugInfo(methodItems);
2638913c59363230bc1bf787b7e24941cb13209de0cJesusFreke@JesusFreke.com        }
264f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
265f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        if (baksmali.useSequentialLabels) {
266f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com            setLabelSequentialNumbers();
267f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        }
268f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
269f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        for (LabelMethodItem labelMethodItem: labelCache.getLabels()) {
270e01409c11f10de58a47df9bc02c6c715b75c6289JesusFreke@JesusFreke.com            methodItems.add(labelMethodItem);
271f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        }
272f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
273f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        Collections.sort(methodItems);
274f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
275f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        return methodItems;
276f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com    }
277f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
278f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com    private void addInstructionMethodItems(List<MethodItem> methodItems) {
279754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        List<? extends Instruction> instructions = methodImpl.getInstructions();
280f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
281f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        int currentCodeAddress = 0;
282754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        for (int i=0; i<instructions.size(); i++) {
283754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            Instruction instruction = instructions.get(i);
284f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
285f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com            MethodItem methodItem = InstructionMethodItemFactory.makeInstructionFormatMethodItem(this,
286754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    currentCodeAddress, instruction);
287f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
288f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com            methodItems.add(methodItem);
289f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
290754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            if (i != instructions.size() - 1) {
291f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                methodItems.add(new BlankMethodItem(currentCodeAddress));
292f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com            }
293f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
294f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com            if (baksmali.addCodeOffsets) {
295f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                methodItems.add(new MethodItem(currentCodeAddress) {
296f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
297f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                    @Override
298f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                    public double getSortOrder() {
299f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                        return -1000;
300f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                    }
301f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
302f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                    @Override
303f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                    public boolean writeTo(IndentingWriter writer) throws IOException {
304f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                        writer.write("#@");
305754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                        writer.printUnsignedLongAsHex(codeAddress & 0xFFFFFFFFL);
306f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                        return true;
307f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                    }
308f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                });
309f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com            }
310c9be5e13034da9827b5598a6257376164745b827JesusFreke@JesusFreke.com
311754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            //TODO: uncomment
312754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            /*if (!baksmali.noAccessorComments && (instruction instanceof InstructionWithReference)) {
313754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                Opcode opcode = instruction.getOpcode();
314754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                if (opcode == Opcode.INVOKE_STATIC || opcode == Opcode.INVOKE_STATIC_RANGE) {
3152f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com                    MethodIdItem methodIdItem =
3162f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com                            (MethodIdItem)((InstructionWithReference) instruction).getReferencedItem();
3172f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com
3182f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com                    if (SyntheticAccessorResolver.looksLikeSyntheticAccessor(methodIdItem)) {
3192f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com                        SyntheticAccessorResolver.AccessedMember accessedMember =
3202f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com                                baksmali.syntheticAccessorResolver.getAccessedMember(methodIdItem);
3212f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com                        if (accessedMember != null) {
3222f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com                            methodItems.add(new SyntheticAccessCommentMethodItem(accessedMember, currentCodeAddress));
3232f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com                        }
3242f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com                    }
3252f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com                }
326754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            }*/
3272f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com
328754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            currentCodeAddress += instruction.getCodeUnits();
329f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        }
330f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com    }
331f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
332754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    //TODO: uncomment
333754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    /*private void addAnalyzedInstructionMethodItems(List<MethodItem> methodItems) {
3345967598d012839eb25d50d9fa63952ac802e05ddBen Gruver        methodAnalyzer = new MethodAnalyzer(encodedMethod, baksmali.deodex, baksmali.inlineResolver);
335f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
336f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        methodAnalyzer.analyze();
337f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
338f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        ValidationException validationException = methodAnalyzer.getValidationException();
339f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        if (validationException != null) {
340f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com            methodItems.add(new CommentMethodItem(
341f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                    String.format("ValidationException: %s" ,validationException.getMessage()),
342f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                    validationException.getCodeAddress(), Integer.MIN_VALUE));
343f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        } else if (baksmali.verify) {
344f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com            methodAnalyzer.verify();
345f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
346f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com            validationException = methodAnalyzer.getValidationException();
347c9be5e13034da9827b5598a6257376164745b827JesusFreke@JesusFreke.com            if (validationException != null) {
3486eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                methodItems.add(new CommentMethodItem(
3491c56c7e7507dc24ae1ed2f693c793d94df814c76JesusFreke@JesusFreke.com                        String.format("ValidationException: %s" ,validationException.getMessage()),
350c9be5e13034da9827b5598a6257376164745b827JesusFreke@JesusFreke.com                        validationException.getCodeAddress(), Integer.MIN_VALUE));
351c9be5e13034da9827b5598a6257376164745b827JesusFreke@JesusFreke.com            }
3527e24a9f010eeeff54f7ca0cb589a75cc251fabddJesusFreke@JesusFreke.com        }
353f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
354ef24b31c9872b24f60c88bdae9b2d8c93eb36feeJesusFreke@JesusFreke.com        List<AnalyzedInstruction> instructions = methodAnalyzer.getInstructions();
355ad1085e32a17b342c2418c117c59d9c8305d71fcJesusFreke@JesusFreke.com
356b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        int currentCodeAddress = 0;
357ef24b31c9872b24f60c88bdae9b2d8c93eb36feeJesusFreke@JesusFreke.com        for (int i=0; i<instructions.size(); i++) {
358ef24b31c9872b24f60c88bdae9b2d8c93eb36feeJesusFreke@JesusFreke.com            AnalyzedInstruction instruction = instructions.get(i);
359ad1085e32a17b342c2418c117c59d9c8305d71fcJesusFreke@JesusFreke.com
360e01409c11f10de58a47df9bc02c6c715b75c6289JesusFreke@JesusFreke.com            MethodItem methodItem = InstructionMethodItemFactory.makeInstructionFormatMethodItem(this,
361e01409c11f10de58a47df9bc02c6c715b75c6289JesusFreke@JesusFreke.com                    encodedMethod.codeItem, currentCodeAddress, instruction.getInstruction());
362650725bbd3c5e10b9f29d3bcbab473b20a89d57bJesusFreke@JesusFreke.com
363e01409c11f10de58a47df9bc02c6c715b75c6289JesusFreke@JesusFreke.com            methodItems.add(methodItem);
3640c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
365e01409c11f10de58a47df9bc02c6c715b75c6289JesusFreke@JesusFreke.com            if (instruction.getInstruction().getFormat() == Format.UnresolvedOdexInstruction) {
3666eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                methodItems.add(new CommentedOutMethodItem(
367e01409c11f10de58a47df9bc02c6c715b75c6289JesusFreke@JesusFreke.com                        InstructionMethodItemFactory.makeInstructionFormatMethodItem(this,
368e01409c11f10de58a47df9bc02c6c715b75c6289JesusFreke@JesusFreke.com                                encodedMethod.codeItem, currentCodeAddress, instruction.getOriginalInstruction())));
3690c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            }
3707ab77bc90be62b0688c97d4476e3bd219eace0daJesusFreke@JesusFreke.com
371ef24b31c9872b24f60c88bdae9b2d8c93eb36feeJesusFreke@JesusFreke.com            if (i != instructions.size() - 1) {
3726eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                methodItems.add(new BlankMethodItem(currentCodeAddress));
373b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com            }
374e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com
3752bdbf739bfd935877e463bc36df0e446b1dfb09fJesusFreke@JesusFreke.com            if (baksmali.addCodeOffsets) {
3766eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                methodItems.add(new MethodItem(currentCodeAddress) {
3772bdbf739bfd935877e463bc36df0e446b1dfb09fJesusFreke@JesusFreke.com
3786eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                    @Override
3796eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                    public double getSortOrder() {
3806eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                        return -1000;
3811c56c7e7507dc24ae1ed2f693c793d94df814c76JesusFreke@JesusFreke.com                    }
3821c56c7e7507dc24ae1ed2f693c793d94df814c76JesusFreke@JesusFreke.com
3836eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                    @Override
3840b2f7d6a57e90424b3ee455c041aab3996c05f2cJesusFreke@JesusFreke.com                    public boolean writeTo(IndentingWriter writer) throws IOException {
3856eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                        writer.write("#@");
38674c14ffcca0ff4f8f3e66e66022894cd7b0b8540Ben Gruver                        writer.printUnsignedLongAsHex(codeAddress & 0xFFFFFFFF);
3876eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                        return true;
3881c56c7e7507dc24ae1ed2f693c793d94df814c76JesusFreke@JesusFreke.com                    }
3896eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                });
3906eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com            }
3911c56c7e7507dc24ae1ed2f693c793d94df814c76JesusFreke@JesusFreke.com
3926eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com            if (baksmali.registerInfo != 0 && !instruction.getInstruction().getFormat().variableSizeFormat) {
3936eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                methodItems.add(
3946eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                        new PreInstructionRegisterInfoMethodItem(instruction, methodAnalyzer, currentCodeAddress));
3951c56c7e7507dc24ae1ed2f693c793d94df814c76JesusFreke@JesusFreke.com
3966eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                methodItems.add(
3976eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                        new PostInstructionRegisterInfoMethodItem(instruction, methodAnalyzer, currentCodeAddress));
3981c56c7e7507dc24ae1ed2f693c793d94df814c76JesusFreke@JesusFreke.com            }
3997e24a9f010eeeff54f7ca0cb589a75cc251fabddJesusFreke@JesusFreke.com
4000c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            currentCodeAddress += instruction.getInstruction().getSize(currentCodeAddress);
401b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        }
402754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    }*/
403e24e70f9ad584d45d2a2af911c1d056163f1bc74JesusFreke@JesusFreke.com
404b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com    private void addTries(List<MethodItem> methodItems) {
405754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        List<? extends TryBlock> tryBlocks = methodImpl.getTryBlocks();
406754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        if (tryBlocks.size() == 0) {
407b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com            return;
408b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        }
409e24e70f9ad584d45d2a2af911c1d056163f1bc74JesusFreke@JesusFreke.com
410754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        List<? extends Instruction> instructions = methodImpl.getInstructions();
411754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        int lastInstructionAddress = instructionOffsetMap.getInstructionCodeOffset(instructions.size() - 1);
412754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        int codeSize = lastInstructionAddress + instructions.get(instructions.size() - 1).getCodeUnits();
413b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com
414754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        for (TryBlock tryBlock: tryBlocks) {
415754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            int startAddress = tryBlock.getStartCodeOffset();
416754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            int endAddress = startAddress + tryBlock.getCodeUnitCount();
417b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com
4185934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver            if (startAddress >= codeSize) {
4195934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver                throw new RuntimeException(String.format("Try start offset %d is past the end of the code block.",
4205934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver                        startAddress));
4215934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver            }
4225934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver            // Note: not >=. endAddress == codeSize is valid, when the try covers the last instruction
4235934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver            if (endAddress > codeSize) {
4245934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver                throw new RuntimeException(String.format("Try end offset %d is past the end of the code block.",
4255934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver                        endAddress));
4265934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver            }
4275934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver
428b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com            /**
429b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com             * The end address points to the address immediately after the end of the last
430b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com             * instruction that the try block covers. We want the .catch directive and end_try
431b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com             * label to be associated with the last covered instruction, so we need to get
432b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com             * the address for that instruction
433b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com             */
434b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com
435754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            int lastCoveredIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(endAddress - 1, false);
436754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            int lastCoveredAddress = instructionOffsetMap.getInstructionCodeOffset(lastCoveredIndex);
437ad1085e32a17b342c2418c117c59d9c8305d71fcJesusFreke@JesusFreke.com
438754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            for (ExceptionHandler handler: tryBlock.getExceptionHandlers()) {
439754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                int handlerOffset = handler.getHandlerCodeOffset();
440754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                if (handlerOffset >= codeSize) {
441754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    throw new ExceptionWithContext(
442754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                            "Exception handler offset %d is past the end of the code block.", handlerOffset);
4435934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver                }
4445934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver
445b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com                //use the address from the last covered instruction
4465934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver                CatchMethodItem catchMethodItem = new CatchMethodItem(labelCache, lastCoveredAddress,
447754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                        handler.getExceptionType(), startAddress, endAddress, handlerOffset);
448b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com                methodItems.add(catchMethodItem);
449c65a8d8b5f2091a6bd835617262840a3f52c5c00JesusFreke@JesusFreke.com            }
450c65a8d8b5f2091a6bd835617262840a3f52c5c00JesusFreke@JesusFreke.com        }
451b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com    }
452c65a8d8b5f2091a6bd835617262840a3f52c5c00JesusFreke@JesusFreke.com
453b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com    private void addDebugInfo(final List<MethodItem> methodItems) {
454754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        for (DebugItem debugItem: methodImpl.getDebugItems()) {
455754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            methodItems.add(DebugMethodItem.build(registerFormatter, debugItem));
456c65a8d8b5f2091a6bd835617262840a3f52c5c00JesusFreke@JesusFreke.com        }
457b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com    }
458e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com
459b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com    private void setLabelSequentialNumbers() {
460b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        HashMap<String, Integer> nextLabelSequenceByType = new HashMap<String, Integer>();
461b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        ArrayList<LabelMethodItem> sortedLabels = new ArrayList<LabelMethodItem>(labelCache.getLabels());
462e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com
463b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        //sort the labels by their location in the method
464b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        Collections.sort(sortedLabels);
465e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com
466b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        for (LabelMethodItem labelMethodItem: sortedLabels) {
467b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com            Integer labelSequence = nextLabelSequenceByType.get(labelMethodItem.getLabelPrefix());
468b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com            if (labelSequence == null) {
469b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com                labelSequence = 0;
470e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com            }
471b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com            labelMethodItem.setLabelSequence(labelSequence);
472b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com            nextLabelSequenceByType.put(labelMethodItem.getLabelPrefix(), labelSequence + 1);
473e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com        }
474e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com    }
475e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com
476e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com    public static class LabelCache {
477e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com        protected HashMap<LabelMethodItem, LabelMethodItem> labels = new HashMap<LabelMethodItem, LabelMethodItem>();
478e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com
479e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com        public LabelCache() {
480e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com        }
481e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com
482e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com        public LabelMethodItem internLabel(LabelMethodItem labelMethodItem) {
483e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com            LabelMethodItem internedLabelMethodItem = labels.get(labelMethodItem);
484e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com            if (internedLabelMethodItem != null) {
485e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com                return internedLabelMethodItem;
486e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com            }
487e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com            labels.put(labelMethodItem, labelMethodItem);
488e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com            return labelMethodItem;
489e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com        }
490e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com
491e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com
492e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com        public Collection<LabelMethodItem> getLabels() {
493e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com            return labels.values();
494e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com        }
49536836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com    }
49636836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com}
497