MethodDefinition.java revision c3a3ee3799e354b6718ce8eee2cf20cbac1ca9d9
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);
90754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    packedSwitchMap.append(codeOffset, targetOffset);
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);
95754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    sparseSwitchMap.append(codeOffset, targetOffset);
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
163754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        for (MethodItem methodItem: getMethodItems()) {
164754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            if (methodItem.writeTo(writer)) {
165754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                writer.write('\n');
1666eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com            }
1676eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com        }
168754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.deindent(4);
169754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        writer.write(".end method\n");
1703c9013f9c08fa8effc9f6d4dc58212c68eb21742JesusFreke@JesusFreke.com    }
1713c9013f9c08fa8effc9f6d4dc58212c68eb21742JesusFreke@JesusFreke.com
172754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    private int findSwitchPayload(int targetOffset, Opcode type) {
173754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        int targetIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(targetOffset);
174754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver
175754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        //TODO: does dalvik let you pad with multiple nops?
176754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        //TODO: does dalvik let a switch instruction point to a non-payload instruction?
177754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver
178754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        List<? extends Instruction> instructions = methodImpl.getInstructions();
179754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        Instruction instruction = instructions.get(targetIndex);
180754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        if (instruction.getOpcode() != type) {
181754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            // maybe it's pointing to a NOP padding instruction. Look at the next instruction
182754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            if (instruction.getOpcode() == Opcode.NOP) {
183754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                targetIndex += 1;
184754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                if (targetIndex < instructions.size()) {
185754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    instruction = instructions.get(targetIndex);
186754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    if (instruction.getOpcode() == type) {
187754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                        return instructionOffsetMap.getInstructionCodeOffset(targetIndex);
188754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    }
189754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                }
190754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            }
191754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            throw new ExceptionWithContext("No switch payload at offset 0x%x", targetOffset);
192754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        } else {
193754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            return targetOffset;
194c9be5e13034da9827b5598a6257376164745b827JesusFreke@JesusFreke.com        }
195c9be5e13034da9827b5598a6257376164745b827JesusFreke@JesusFreke.com    }
196c9be5e13034da9827b5598a6257376164745b827JesusFreke@JesusFreke.com
197754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    private static void writeAccessFlags(IndentingWriter writer, int accessFlags)
198754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            throws IOException {
199754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForMethod(accessFlags)) {
200754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            writer.write(accessFlag.toString());
201754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            writer.write(' ');
202b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        }
203b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com    }
204b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com
205c3a3ee3799e354b6718ce8eee2cf20cbac1ca9d9Ben Gruver    private static void writeParameters(IndentingWriter writer, Method method) throws IOException {
206c3a3ee3799e354b6718ce8eee2cf20cbac1ca9d9Ben Gruver        boolean isStatic = AccessFlags.STATIC.isSet(method.getAccessFlags());
207c3a3ee3799e354b6718ce8eee2cf20cbac1ca9d9Ben Gruver        int registerNumber = isStatic?0:1;
208c3a3ee3799e354b6718ce8eee2cf20cbac1ca9d9Ben Gruver        for (MethodParameter parameter: method.getParameters()) {
209754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            String parameterType = parameter.getType();
210754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            String parameterName = parameter.getName();
211754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            List<? extends Annotation> annotations = parameter.getAnnotations();
212754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            if (parameterName != null || annotations.size() != 0) {
21316f257ee8f12974c62e50643b2f87533513da455Ben Gruver                writer.write(".param p");
214754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                writer.printSignedIntAsDec(registerNumber);
215754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                if (parameterName != null) {
21616f257ee8f12974c62e50643b2f87533513da455Ben Gruver                    writer.write(", ");
217db4316ef6ddeaaae94ca88673b6bac1c2b29eec5Ben Gruver                    // TODO: does dalvik allow non-identifier parameter and/or local names?
218754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    writer.write(parameterName);
219754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                }
220c3a3ee3799e354b6718ce8eee2cf20cbac1ca9d9Ben Gruver                writer.write("    # ");
22116f257ee8f12974c62e50643b2f87533513da455Ben Gruver                writer.write(parameterType);
222754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                if (annotations.size() > 0) {
223754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    writer.indent(4);
224754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    AnnotationFormatter.writeTo(writer, annotations);
225754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    writer.deindent(4);
22616f257ee8f12974c62e50643b2f87533513da455Ben Gruver                    writer.write(".end param\n");
227754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                } else {
228754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    writer.write("\n");
229754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                }
230754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            }
231cb3e0ea38a669633b8daefd538750c8ded46f524Ben Gruver
232754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            registerNumber++;
233754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            if (TypeUtils.isWideType(parameterType)) {
234754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                registerNumber++;
235cb3e0ea38a669633b8daefd538750c8ded46f524Ben Gruver            }
236b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        }
237b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com    }
238b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com
239754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    @Nonnull public LabelCache getLabelCache() {
240754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        return labelCache;
241754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    }
242db26b663aa3b5bb721185b8798b6767710d3c243JesusFreke@JesusFreke.com
243754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    public int getPackedSwitchBaseAddress(int packedSwitchPayloadCodeOffset) {
244754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        return packedSwitchMap.get(packedSwitchPayloadCodeOffset, -1);
245db26b663aa3b5bb721185b8798b6767710d3c243JesusFreke@JesusFreke.com    }
246db26b663aa3b5bb721185b8798b6767710d3c243JesusFreke@JesusFreke.com
247754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    public int getSparseSwitchBaseAddress(int sparseSwitchPayloadCodeOffset) {
248754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        return sparseSwitchMap.get(sparseSwitchPayloadCodeOffset, -1);
249343df2f456f38c305ee7d6742f6601d9bde09715Ben Gruver    }
250343df2f456f38c305ee7d6742f6601d9bde09715Ben Gruver
251b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com    private List<MethodItem> getMethodItems() {
252f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        ArrayList<MethodItem> methodItems = new ArrayList<MethodItem>();
2539bc4978139ca38e422ae89065d3062146534132dJesusFreke@JesusFreke.com
254754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        //TODO: addAnalyzedInstructionMethodItems
255754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        addInstructionMethodItems(methodItems);
256f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
257f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        addTries(methodItems);
2588913c59363230bc1bf787b7e24941cb13209de0cJesusFreke@JesusFreke.com        if (baksmali.outputDebugInfo) {
2598913c59363230bc1bf787b7e24941cb13209de0cJesusFreke@JesusFreke.com            addDebugInfo(methodItems);
2608913c59363230bc1bf787b7e24941cb13209de0cJesusFreke@JesusFreke.com        }
261f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
262f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        if (baksmali.useSequentialLabels) {
263f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com            setLabelSequentialNumbers();
264f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        }
265f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
266f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        for (LabelMethodItem labelMethodItem: labelCache.getLabels()) {
267e01409c11f10de58a47df9bc02c6c715b75c6289JesusFreke@JesusFreke.com            methodItems.add(labelMethodItem);
268f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        }
269f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
270f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        Collections.sort(methodItems);
271f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
272f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        return methodItems;
273f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com    }
274f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
275f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com    private void addInstructionMethodItems(List<MethodItem> methodItems) {
276754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        List<? extends Instruction> instructions = methodImpl.getInstructions();
277f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
278f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        int currentCodeAddress = 0;
279754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        for (int i=0; i<instructions.size(); i++) {
280754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            Instruction instruction = instructions.get(i);
281f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
282f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com            MethodItem methodItem = InstructionMethodItemFactory.makeInstructionFormatMethodItem(this,
283754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    currentCodeAddress, instruction);
284f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
285f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com            methodItems.add(methodItem);
286f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
287754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            if (i != instructions.size() - 1) {
288f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                methodItems.add(new BlankMethodItem(currentCodeAddress));
289f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com            }
290f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
291f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com            if (baksmali.addCodeOffsets) {
292f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                methodItems.add(new MethodItem(currentCodeAddress) {
293f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
294f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                    @Override
295f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                    public double getSortOrder() {
296f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                        return -1000;
297f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                    }
298f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
299f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                    @Override
300f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                    public boolean writeTo(IndentingWriter writer) throws IOException {
301f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                        writer.write("#@");
302754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                        writer.printUnsignedLongAsHex(codeAddress & 0xFFFFFFFFL);
303f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                        return true;
304f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                    }
305f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                });
306f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com            }
307c9be5e13034da9827b5598a6257376164745b827JesusFreke@JesusFreke.com
308754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            //TODO: uncomment
309754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            /*if (!baksmali.noAccessorComments && (instruction instanceof InstructionWithReference)) {
310754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                Opcode opcode = instruction.getOpcode();
311754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                if (opcode == Opcode.INVOKE_STATIC || opcode == Opcode.INVOKE_STATIC_RANGE) {
3122f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com                    MethodIdItem methodIdItem =
3132f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com                            (MethodIdItem)((InstructionWithReference) instruction).getReferencedItem();
3142f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com
3152f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com                    if (SyntheticAccessorResolver.looksLikeSyntheticAccessor(methodIdItem)) {
3162f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com                        SyntheticAccessorResolver.AccessedMember accessedMember =
3172f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com                                baksmali.syntheticAccessorResolver.getAccessedMember(methodIdItem);
3182f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com                        if (accessedMember != null) {
3192f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com                            methodItems.add(new SyntheticAccessCommentMethodItem(accessedMember, currentCodeAddress));
3202f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com                        }
3212f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com                    }
3222f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com                }
323754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            }*/
3242f376953b4c96542f200724727e4dac74dd27425jesusfreke@jesusfreke.com
325754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            currentCodeAddress += instruction.getCodeUnits();
326f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        }
327f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com    }
328f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
329754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    //TODO: uncomment
330754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    /*private void addAnalyzedInstructionMethodItems(List<MethodItem> methodItems) {
3315967598d012839eb25d50d9fa63952ac802e05ddBen Gruver        methodAnalyzer = new MethodAnalyzer(encodedMethod, baksmali.deodex, baksmali.inlineResolver);
332f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
333f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        methodAnalyzer.analyze();
334f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
335f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        ValidationException validationException = methodAnalyzer.getValidationException();
336f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        if (validationException != null) {
337f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com            methodItems.add(new CommentMethodItem(
338f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                    String.format("ValidationException: %s" ,validationException.getMessage()),
339f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com                    validationException.getCodeAddress(), Integer.MIN_VALUE));
340f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com        } else if (baksmali.verify) {
341f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com            methodAnalyzer.verify();
342f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
343f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com            validationException = methodAnalyzer.getValidationException();
344c9be5e13034da9827b5598a6257376164745b827JesusFreke@JesusFreke.com            if (validationException != null) {
3456eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                methodItems.add(new CommentMethodItem(
3461c56c7e7507dc24ae1ed2f693c793d94df814c76JesusFreke@JesusFreke.com                        String.format("ValidationException: %s" ,validationException.getMessage()),
347c9be5e13034da9827b5598a6257376164745b827JesusFreke@JesusFreke.com                        validationException.getCodeAddress(), Integer.MIN_VALUE));
348c9be5e13034da9827b5598a6257376164745b827JesusFreke@JesusFreke.com            }
3497e24a9f010eeeff54f7ca0cb589a75cc251fabddJesusFreke@JesusFreke.com        }
350f7344d33d01953eee129f3cfa2b9655eb65bfe2fJesusFreke@JesusFreke.com
351ef24b31c9872b24f60c88bdae9b2d8c93eb36feeJesusFreke@JesusFreke.com        List<AnalyzedInstruction> instructions = methodAnalyzer.getInstructions();
352ad1085e32a17b342c2418c117c59d9c8305d71fcJesusFreke@JesusFreke.com
353b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        int currentCodeAddress = 0;
354ef24b31c9872b24f60c88bdae9b2d8c93eb36feeJesusFreke@JesusFreke.com        for (int i=0; i<instructions.size(); i++) {
355ef24b31c9872b24f60c88bdae9b2d8c93eb36feeJesusFreke@JesusFreke.com            AnalyzedInstruction instruction = instructions.get(i);
356ad1085e32a17b342c2418c117c59d9c8305d71fcJesusFreke@JesusFreke.com
357e01409c11f10de58a47df9bc02c6c715b75c6289JesusFreke@JesusFreke.com            MethodItem methodItem = InstructionMethodItemFactory.makeInstructionFormatMethodItem(this,
358e01409c11f10de58a47df9bc02c6c715b75c6289JesusFreke@JesusFreke.com                    encodedMethod.codeItem, currentCodeAddress, instruction.getInstruction());
359650725bbd3c5e10b9f29d3bcbab473b20a89d57bJesusFreke@JesusFreke.com
360e01409c11f10de58a47df9bc02c6c715b75c6289JesusFreke@JesusFreke.com            methodItems.add(methodItem);
3610c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com
362e01409c11f10de58a47df9bc02c6c715b75c6289JesusFreke@JesusFreke.com            if (instruction.getInstruction().getFormat() == Format.UnresolvedOdexInstruction) {
3636eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                methodItems.add(new CommentedOutMethodItem(
364e01409c11f10de58a47df9bc02c6c715b75c6289JesusFreke@JesusFreke.com                        InstructionMethodItemFactory.makeInstructionFormatMethodItem(this,
365e01409c11f10de58a47df9bc02c6c715b75c6289JesusFreke@JesusFreke.com                                encodedMethod.codeItem, currentCodeAddress, instruction.getOriginalInstruction())));
3660c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            }
3677ab77bc90be62b0688c97d4476e3bd219eace0daJesusFreke@JesusFreke.com
368ef24b31c9872b24f60c88bdae9b2d8c93eb36feeJesusFreke@JesusFreke.com            if (i != instructions.size() - 1) {
3696eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                methodItems.add(new BlankMethodItem(currentCodeAddress));
370b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com            }
371e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com
3722bdbf739bfd935877e463bc36df0e446b1dfb09fJesusFreke@JesusFreke.com            if (baksmali.addCodeOffsets) {
3736eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                methodItems.add(new MethodItem(currentCodeAddress) {
3742bdbf739bfd935877e463bc36df0e446b1dfb09fJesusFreke@JesusFreke.com
3756eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                    @Override
3766eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                    public double getSortOrder() {
3776eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                        return -1000;
3781c56c7e7507dc24ae1ed2f693c793d94df814c76JesusFreke@JesusFreke.com                    }
3791c56c7e7507dc24ae1ed2f693c793d94df814c76JesusFreke@JesusFreke.com
3806eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                    @Override
3810b2f7d6a57e90424b3ee455c041aab3996c05f2cJesusFreke@JesusFreke.com                    public boolean writeTo(IndentingWriter writer) throws IOException {
3826eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                        writer.write("#@");
38374c14ffcca0ff4f8f3e66e66022894cd7b0b8540Ben Gruver                        writer.printUnsignedLongAsHex(codeAddress & 0xFFFFFFFF);
3846eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                        return true;
3851c56c7e7507dc24ae1ed2f693c793d94df814c76JesusFreke@JesusFreke.com                    }
3866eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                });
3876eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com            }
3881c56c7e7507dc24ae1ed2f693c793d94df814c76JesusFreke@JesusFreke.com
3896eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com            if (baksmali.registerInfo != 0 && !instruction.getInstruction().getFormat().variableSizeFormat) {
3906eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                methodItems.add(
3916eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                        new PreInstructionRegisterInfoMethodItem(instruction, methodAnalyzer, currentCodeAddress));
3921c56c7e7507dc24ae1ed2f693c793d94df814c76JesusFreke@JesusFreke.com
3936eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                methodItems.add(
3946eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com                        new PostInstructionRegisterInfoMethodItem(instruction, methodAnalyzer, currentCodeAddress));
3951c56c7e7507dc24ae1ed2f693c793d94df814c76JesusFreke@JesusFreke.com            }
3967e24a9f010eeeff54f7ca0cb589a75cc251fabddJesusFreke@JesusFreke.com
3970c65e0f4f54ead8fd2832c954d516367b3556ae3JesusFreke@JesusFreke.com            currentCodeAddress += instruction.getInstruction().getSize(currentCodeAddress);
398b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        }
399754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver    }*/
400e24e70f9ad584d45d2a2af911c1d056163f1bc74JesusFreke@JesusFreke.com
401b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com    private void addTries(List<MethodItem> methodItems) {
402754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        List<? extends TryBlock> tryBlocks = methodImpl.getTryBlocks();
403754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        if (tryBlocks.size() == 0) {
404b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com            return;
405b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        }
406e24e70f9ad584d45d2a2af911c1d056163f1bc74JesusFreke@JesusFreke.com
407754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        List<? extends Instruction> instructions = methodImpl.getInstructions();
408754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        int lastInstructionAddress = instructionOffsetMap.getInstructionCodeOffset(instructions.size() - 1);
409754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        int codeSize = lastInstructionAddress + instructions.get(instructions.size() - 1).getCodeUnits();
410b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com
411754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        for (TryBlock tryBlock: tryBlocks) {
412754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            int startAddress = tryBlock.getStartCodeOffset();
413754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            int endAddress = startAddress + tryBlock.getCodeUnitCount();
414b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com
4155934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver            if (startAddress >= codeSize) {
4165934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver                throw new RuntimeException(String.format("Try start offset %d is past the end of the code block.",
4175934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver                        startAddress));
4185934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver            }
4195934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver            // Note: not >=. endAddress == codeSize is valid, when the try covers the last instruction
4205934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver            if (endAddress > codeSize) {
4215934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver                throw new RuntimeException(String.format("Try end offset %d is past the end of the code block.",
4225934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver                        endAddress));
4235934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver            }
4245934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver
425b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com            /**
426b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com             * The end address points to the address immediately after the end of the last
427b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com             * instruction that the try block covers. We want the .catch directive and end_try
428b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com             * label to be associated with the last covered instruction, so we need to get
429b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com             * the address for that instruction
430b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com             */
431b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com
432754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            int lastCoveredIndex = instructionOffsetMap.getInstructionIndexAtCodeOffset(endAddress - 1, false);
433754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            int lastCoveredAddress = instructionOffsetMap.getInstructionCodeOffset(lastCoveredIndex);
434ad1085e32a17b342c2418c117c59d9c8305d71fcJesusFreke@JesusFreke.com
435754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            for (ExceptionHandler handler: tryBlock.getExceptionHandlers()) {
436754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                int handlerOffset = handler.getHandlerCodeOffset();
437754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                if (handlerOffset >= codeSize) {
438754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                    throw new ExceptionWithContext(
439754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                            "Exception handler offset %d is past the end of the code block.", handlerOffset);
4405934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver                }
4415934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver
442b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com                //use the address from the last covered instruction
4435934004fe3c1e9617793aa120e88f5df1b651c14Ben Gruver                CatchMethodItem catchMethodItem = new CatchMethodItem(labelCache, lastCoveredAddress,
444754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver                        handler.getExceptionType(), startAddress, endAddress, handlerOffset);
445b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com                methodItems.add(catchMethodItem);
446c65a8d8b5f2091a6bd835617262840a3f52c5c00JesusFreke@JesusFreke.com            }
447c65a8d8b5f2091a6bd835617262840a3f52c5c00JesusFreke@JesusFreke.com        }
448b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com    }
449c65a8d8b5f2091a6bd835617262840a3f52c5c00JesusFreke@JesusFreke.com
450b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com    private void addDebugInfo(final List<MethodItem> methodItems) {
451754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver        for (DebugItem debugItem: methodImpl.getDebugItems()) {
452754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver            methodItems.add(DebugMethodItem.build(registerFormatter, debugItem));
453c65a8d8b5f2091a6bd835617262840a3f52c5c00JesusFreke@JesusFreke.com        }
454b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com    }
455e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com
456b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com    private void setLabelSequentialNumbers() {
457b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        HashMap<String, Integer> nextLabelSequenceByType = new HashMap<String, Integer>();
458b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        ArrayList<LabelMethodItem> sortedLabels = new ArrayList<LabelMethodItem>(labelCache.getLabels());
459e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com
460b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        //sort the labels by their location in the method
461b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        Collections.sort(sortedLabels);
462e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com
463b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com        for (LabelMethodItem labelMethodItem: sortedLabels) {
464b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com            Integer labelSequence = nextLabelSequenceByType.get(labelMethodItem.getLabelPrefix());
465b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com            if (labelSequence == null) {
466b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com                labelSequence = 0;
467e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com            }
468b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com            labelMethodItem.setLabelSequence(labelSequence);
469b2e1e2067d5179b0ec38c76a5191909f5a7dc1ccJesusFreke@JesusFreke.com            nextLabelSequenceByType.put(labelMethodItem.getLabelPrefix(), labelSequence + 1);
470e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com        }
471e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com    }
472e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com
473e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com    public static class LabelCache {
474e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com        protected HashMap<LabelMethodItem, LabelMethodItem> labels = new HashMap<LabelMethodItem, LabelMethodItem>();
475e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com
476e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com        public LabelCache() {
477e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com        }
478e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com
479e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com        public LabelMethodItem internLabel(LabelMethodItem labelMethodItem) {
480e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com            LabelMethodItem internedLabelMethodItem = labels.get(labelMethodItem);
481e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com            if (internedLabelMethodItem != null) {
482e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com                return internedLabelMethodItem;
483e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com            }
484e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com            labels.put(labelMethodItem, labelMethodItem);
485e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com            return labelMethodItem;
486e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com        }
487e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com
488e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com
489e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com        public Collection<LabelMethodItem> getLabels() {
490e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com            return labels.values();
491e2684fa2191e04f27faba763f2bcc19593513b25JesusFreke@JesusFreke.com        }
49236836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com    }
49336836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com}
494