1579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/*
2579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Copyright (C) 2007 The Android Open Source Project
3579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
4579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
5579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * you may not use this file except in compliance with the License.
6579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * You may obtain a copy of the License at
7579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
8579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
9579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
10579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Unless required by applicable law or agreed to in writing, software
11579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
12579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * See the License for the specific language governing permissions and
14579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * limitations under the License.
15579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
16579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
17579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpackage com.android.dx.dex.file;
18579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
19579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.code.DalvCode;
20579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.code.DalvInsnList;
21579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.code.LocalList;
22579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.code.PositionList;
23579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.cst.CstMethodRef;
24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.cst.CstString;
25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.type.Prototype;
26579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.type.StdTypeList;
27579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.type.Type;
28579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.ByteArrayByteInput;
29579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.ByteInput;
30579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.ExceptionWithContext;
31579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
32579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.Leb128Utils;
33579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.io.IOException;
34579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.ArrayList;
35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.List;
36579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
37579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport static com.android.dx.dex.file.DebugInfoConstants.*;
38579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
39579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/**
40579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * A decoder for the dex debug info state machine format.
41579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * This code exists mostly as a reference implementation and test for
42579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * for the {@code DebugInfoEncoder}
43579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
44579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpublic class DebugInfoDecoder {
45579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** encoded debug info */
46579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final byte[] encoded;
47579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
48579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** positions decoded */
49579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final ArrayList<PositionEntry> positions;
50579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
51579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** locals decoded */
52579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final ArrayList<LocalEntry> locals;
53579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
54579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** size of code block in code units */
55579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final int codesize;
56579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
57579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** indexed by register, the last local variable live in a reg */
58579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final LocalEntry[] lastEntryForReg;
59579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
60579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** method descriptor of method this debug info is for */
61579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final Prototype desc;
62579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
63579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** true if method is static */
64579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final boolean isStatic;
65579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
66579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** dex file this debug info will be stored in */
67579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final DexFile file;
68579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
69579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
70579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * register size, in register units, of the register space
71579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * used by this method
72579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
73579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final int regSize;
74579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
75579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** current decoding state: line number */
76579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private int line = 1;
77579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
78579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** current decoding state: bytecode address */
79579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private int address = 0;
80579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
81579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** string index of the string "this" */
82579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final int thisStringIdx;
83579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
84579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
85579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Constructs an instance.
86579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
87579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param encoded encoded debug info
88579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param codesize size of code block in code units
89579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param regSize register size, in register units, of the register space
90579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * used by this method
91579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param isStatic true if method is static
92579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param ref method descriptor of method this debug info is for
93579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param file dex file this debug info will be stored in
94579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
95579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    DebugInfoDecoder(byte[] encoded, int codesize, int regSize,
96579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            boolean isStatic, CstMethodRef ref, DexFile file) {
97579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (encoded == null) {
98579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new NullPointerException("encoded == null");
99579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
100579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
101579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.encoded = encoded;
102579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.isStatic = isStatic;
103579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.desc = ref.getPrototype();
104579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.file = file;
105579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.regSize = regSize;
106579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
107579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        positions = new ArrayList<PositionEntry>();
108579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        locals = new ArrayList<LocalEntry>();
109579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.codesize = codesize;
110579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        lastEntryForReg = new LocalEntry[regSize];
111579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
112579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int idx = -1;
113579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
114579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
115579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            idx = file.getStringIds().indexOf(new CstString("this"));
116579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (IllegalArgumentException ex) {
117579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            /*
118579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * Silently tolerate not finding "this". It just means that
119579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * no method has local variable info that looks like
120579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * a standard instance method.
121579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             */
122579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
123579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
124579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        thisStringIdx = idx;
125579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
126579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
127579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
128579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * An entry in the resulting postions table
129579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
130579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    static private class PositionEntry {
131579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** bytecode address */
132579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public int address;
133579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
134579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** line number */
135579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public int line;
136579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
137579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public PositionEntry(int address, int line) {
138579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.address = address;
139579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.line = line;
140579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
141579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
142579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
143579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
144579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * An entry in the resulting locals table
145579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
146579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    static private class LocalEntry {
147579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** address of event */
148579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public int address;
149579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
150579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@code true} iff it's a local start */
151579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public boolean isStart;
152579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
153579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** register number */
154579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public int reg;
155579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
156579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** index of name in strings table */
157579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public int nameIndex;
158579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
159579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** index of type in types table */
160579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public int typeIndex;
161579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
162579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** index of type signature in strings table */
163579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public int signatureIndex;
164579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
165579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public LocalEntry(int address, boolean isStart, int reg, int nameIndex,
166579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                int typeIndex, int signatureIndex) {
167579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.address        = address;
168579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.isStart        = isStart;
169579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.reg            = reg;
170579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.nameIndex      = nameIndex;
171579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.typeIndex      = typeIndex;
172579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.signatureIndex = signatureIndex;
173579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
174579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
175579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public String toString() {
176579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return String.format("[%x %s v%d %04x %04x %04x]",
177579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    address, isStart ? "start" : "end", reg,
178579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    nameIndex, typeIndex, signatureIndex);
179579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
180579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
181579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
182579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
183579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the decoded positions list.
184579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Valid after calling {@code decode}.
185579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
186579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return positions list in ascending address order.
187579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
188579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public List<PositionEntry> getPositionList() {
189579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return positions;
190579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
191579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
192579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
193579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the decoded locals list, in ascending start-address order.
194579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Valid after calling {@code decode}.
195579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
196579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return locals list in ascending address order.
197579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
198579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public List<LocalEntry> getLocals() {
199579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return locals;
200579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
201579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
202579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
203579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Decodes the debug info sequence.
204579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
205579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void decode() {
206579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
207579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            decode0();
208579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (Exception ex) {
209579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw ExceptionWithContext.withContext(ex,
210579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    "...while decoding debug info");
211579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
212579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
213579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
214579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
215579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Reads a string index. String indicies are offset by 1, and a 0 value
216579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * in the stream (-1 as returned by this method) means "null"
217579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
218579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return index into file's string ids table, -1 means null
219579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @throws IOException
220579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
221579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private int readStringIndex(ByteInput bs) throws IOException {
222579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int offsetIndex = Leb128Utils.readUnsignedLeb128(bs);
223579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
224579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return offsetIndex - 1;
225579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
226579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
227579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
228579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the register that begins the method's parameter range (including
229579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * the 'this' parameter for non-static methods). The range continues until
230579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@code regSize}
231579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
232579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return register as noted above.
233579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
234579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private int getParamBase() {
235579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return regSize
236579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                - desc.getParameterTypes().getWordCount() - (isStatic? 0 : 1);
237579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
238579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
239579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private void decode0() throws IOException {
240579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        ByteInput bs = new ByteArrayByteInput(encoded);
241579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
242579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        line = Leb128Utils.readUnsignedLeb128(bs);
243579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int szParams = Leb128Utils.readUnsignedLeb128(bs);
244579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        StdTypeList params = desc.getParameterTypes();
245579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int curReg = getParamBase();
246579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
247579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (szParams != params.size()) {
248579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new RuntimeException(
249579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    "Mismatch between parameters_size and prototype");
250579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
251579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
252579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (!isStatic) {
253579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            // Start off with implicit 'this' entry
254579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            LocalEntry thisEntry =
255579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                new LocalEntry(0, true, curReg, thisStringIdx, 0, 0);
256579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            locals.add(thisEntry);
257579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            lastEntryForReg[curReg] = thisEntry;
258579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            curReg++;
259579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
260579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
261579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < szParams; i++) {
262579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Type paramType = params.getType(i);
263579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            LocalEntry le;
264579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
265579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int nameIdx = readStringIndex(bs);
266579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
267579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (nameIdx == -1) {
268579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                /*
269579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * Unnamed parameter; often but not always filled in by an
270579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * extended start op after the prologue
271579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 */
272579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                le = new LocalEntry(0, true, curReg, -1, 0, 0);
273579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            } else {
274579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                // TODO: Final 0 should be idx of paramType.getDescriptor().
275579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                le = new LocalEntry(0, true, curReg, nameIdx, 0, 0);
276579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
277579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
278579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            locals.add(le);
279579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            lastEntryForReg[curReg] = le;
280579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            curReg += paramType.getCategory();
281579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
282579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
283579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (;;) {
284579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int opcode = bs.readByte() & 0xff;
285579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
286579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            switch (opcode) {
287579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                case DBG_START_LOCAL: {
288579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    int reg = Leb128Utils.readUnsignedLeb128(bs);
289579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    int nameIdx = readStringIndex(bs);
290579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    int typeIdx = readStringIndex(bs);
291579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    LocalEntry le = new LocalEntry(
292579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            address, true, reg, nameIdx, typeIdx, 0);
293579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
294579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    locals.add(le);
295579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    lastEntryForReg[reg] = le;
296579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
297579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                break;
298579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
299579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                case DBG_START_LOCAL_EXTENDED: {
300579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    int reg = Leb128Utils.readUnsignedLeb128(bs);
301579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    int nameIdx = readStringIndex(bs);
302579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    int typeIdx = readStringIndex(bs);
303579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    int sigIdx = readStringIndex(bs);
304579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    LocalEntry le = new LocalEntry(
305579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            address, true, reg, nameIdx, typeIdx, sigIdx);
306579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
307579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    locals.add(le);
308579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    lastEntryForReg[reg] = le;
309579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
310579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                break;
311579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
312579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                case DBG_RESTART_LOCAL: {
313579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    int reg = Leb128Utils.readUnsignedLeb128(bs);
314579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    LocalEntry prevle;
315579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    LocalEntry le;
316579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
317579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    try {
318579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        prevle = lastEntryForReg[reg];
319579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
320579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        if (prevle.isStart) {
321579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            throw new RuntimeException("nonsensical "
322579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                    + "RESTART_LOCAL on live register v"
323579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                    + reg);
324579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        }
325579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
326579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        le = new LocalEntry(address, true, reg,
327579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                prevle.nameIndex, prevle.typeIndex, 0);
328579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    } catch (NullPointerException ex) {
329579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        throw new RuntimeException(
330579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                "Encountered RESTART_LOCAL on new v" + reg);
331579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    }
332579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
333579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    locals.add(le);
334579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    lastEntryForReg[reg] = le;
335579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
336579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                break;
337579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
338579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                case DBG_END_LOCAL: {
339579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    int reg = Leb128Utils.readUnsignedLeb128(bs);
340579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    LocalEntry prevle;
341579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    LocalEntry le;
342579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
343579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    try {
344579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        prevle = lastEntryForReg[reg];
345579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
346579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        if (!prevle.isStart) {
347579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            throw new RuntimeException("nonsensical "
348579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                    + "END_LOCAL on dead register v" + reg);
349579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        }
350579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
351579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        le = new LocalEntry(address, false, reg,
352579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                prevle.nameIndex, prevle.typeIndex,
353579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                prevle.signatureIndex);
354579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    } catch (NullPointerException ex) {
355579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        throw new RuntimeException(
356579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                "Encountered END_LOCAL on new v" + reg);
357579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    }
358579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
359579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    locals.add(le);
360579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    lastEntryForReg[reg] = le;
361579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
362579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                break;
363579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
364579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                case DBG_END_SEQUENCE:
365579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    // all done
366579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return;
367579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
368579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                case DBG_ADVANCE_PC:
369579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    address += Leb128Utils.readUnsignedLeb128(bs);
370579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                break;
371579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
372579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                case DBG_ADVANCE_LINE:
373579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    line += Leb128Utils.readSignedLeb128(bs);
374579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                break;
375579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
376579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                case DBG_SET_PROLOGUE_END:
377579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    //TODO do something with this.
378579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                break;
379579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
380579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                case DBG_SET_EPILOGUE_BEGIN:
381579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    //TODO do something with this.
382579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                break;
383579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
384579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                case DBG_SET_FILE:
385579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    //TODO do something with this.
386579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                break;
387579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
388579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                default:
389579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    if (opcode < DBG_FIRST_SPECIAL) {
390579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        throw new RuntimeException(
391579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                "Invalid extended opcode encountered "
392579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                        + opcode);
393579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    }
394579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
395579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    int adjopcode = opcode - DBG_FIRST_SPECIAL;
396579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
397579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    address += adjopcode / DBG_LINE_RANGE;
398579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    line += DBG_LINE_BASE + (adjopcode % DBG_LINE_RANGE);
399579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
400579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    positions.add(new PositionEntry(address, line));
401579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                break;
402579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
403579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
404579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
405579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
406579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
407579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
408579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Validates an encoded debug info stream against data used to encode it,
409579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * throwing an exception if they do not match. Used to validate the
410579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * encoder.
411579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
412579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param info encoded debug info
413579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param file {@code non-null;} file to refer to during decoding
414579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param ref {@code non-null;} method whose info is being decoded
415579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param code {@code non-null;} original code object that was encoded
416579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param isStatic whether the method is static
417579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
418579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static void validateEncode(byte[] info, DexFile file,
419579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            CstMethodRef ref, DalvCode code, boolean isStatic) {
420579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        PositionList pl = code.getPositions();
421579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        LocalList ll = code.getLocals();
422579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        DalvInsnList insns = code.getInsns();
423579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int codeSize = insns.codeSize();
424579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int countRegisters = insns.getRegistersSize();
425579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
426579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
427579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            validateEncode0(info, codeSize, countRegisters,
428579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    isStatic, ref, file, pl, ll);
429579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (RuntimeException ex) {
430579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            System.err.println("instructions:");
431579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            insns.debugPrint(System.err, "  ", true);
432579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            System.err.println("local list:");
433579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            ll.debugPrint(System.err, "  ");
434579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw ExceptionWithContext.withContext(ex,
435579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    "while processing " + ref.toHuman());
436579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
437579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
438579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
439579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static void validateEncode0(byte[] info, int codeSize,
440579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int countRegisters, boolean isStatic, CstMethodRef ref,
441579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            DexFile file, PositionList pl, LocalList ll) {
442579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        DebugInfoDecoder decoder
443579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                = new DebugInfoDecoder(info, codeSize, countRegisters,
444579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    isStatic, ref, file);
445579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
446579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        decoder.decode();
447579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
448579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
449579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Go through the decoded position entries, matching up
450579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * with original entries.
451579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
452579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
453579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        List<PositionEntry> decodedEntries = decoder.getPositionList();
454579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
455579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (decodedEntries.size() != pl.size()) {
456579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new RuntimeException(
457579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    "Decoded positions table not same size was "
458579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    + decodedEntries.size() + " expected " + pl.size());
459579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
460579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
461579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (PositionEntry entry : decodedEntries) {
462579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            boolean found = false;
463579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            for (int i = pl.size() - 1; i >= 0; i--) {
464579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                PositionList.Entry ple = pl.get(i);
465579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
466579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (entry.line == ple.getPosition().getLine()
467579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        && entry.address == ple.getAddress()) {
468579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    found = true;
469579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    break;
470579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
471579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
472579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
473579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (!found) {
474579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw new RuntimeException ("Could not match position entry: "
475579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        + entry.address + ", " + entry.line);
476579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
477579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
478579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
479579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
480579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Go through the original local list, in order, matching up
481579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * with decoded entries.
482579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
483579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
484579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        List<LocalEntry> decodedLocals = decoder.getLocals();
485579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int thisStringIdx = decoder.thisStringIdx;
486579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int decodedSz = decodedLocals.size();
487579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int paramBase = decoder.getParamBase();
488579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
489579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
490579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Preflight to fill in any parameters that were skipped in
491579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * the prologue (including an implied "this") but then
492579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * identified by full signature.
493579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
494579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < decodedSz; i++) {
495579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            LocalEntry entry = decodedLocals.get(i);
496579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int idx = entry.nameIndex;
497579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
498579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if ((idx < 0) || (idx == thisStringIdx)) {
499579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                for (int j = i + 1; j < decodedSz; j++) {
500579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    LocalEntry e2 = decodedLocals.get(j);
501579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    if (e2.address != 0) {
502579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        break;
503579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    }
504579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    if ((entry.reg == e2.reg) && e2.isStart) {
505579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        decodedLocals.set(i, e2);
506579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        decodedLocals.remove(j);
507579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        decodedSz--;
508579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        break;
509579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    }
510579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
511579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
512579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
513579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
514579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int origSz = ll.size();
515579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int decodeAt = 0;
516579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        boolean problem = false;
517579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
518579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < origSz; i++) {
519579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            LocalList.Entry origEntry = ll.get(i);
520579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
521579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (origEntry.getDisposition()
522579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    == LocalList.Disposition.END_REPLACED) {
523579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                /*
524579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * The encoded list doesn't represent replacements, so
525579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * ignore them for the sake of comparison.
526579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 */
527579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                continue;
528579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
529579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
530579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            LocalEntry decodedEntry;
531579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
532579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            do {
533579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                decodedEntry = decodedLocals.get(decodeAt);
534579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (decodedEntry.nameIndex >= 0) {
535579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    break;
536579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
537579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                /*
538579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * A negative name index means this is an anonymous
539579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * parameter, and we shouldn't expect to see it in the
540579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * original list. So, skip it.
541579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 */
542579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                decodeAt++;
543579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            } while (decodeAt < decodedSz);
544579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
545579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int decodedAddress = decodedEntry.address;
546579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
547579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (decodedEntry.reg != origEntry.getRegister()) {
548579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                System.err.println("local register mismatch at orig " + i +
549579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        " / decoded " + decodeAt);
550579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                problem = true;
551579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                break;
552579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
553579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
554579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (decodedEntry.isStart != origEntry.isStart()) {
555579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                System.err.println("local start/end mismatch at orig " + i +
556579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        " / decoded " + decodeAt);
557579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                problem = true;
558579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                break;
559579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
560579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
561579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            /*
562579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * The secondary check here accounts for the fact that a
563579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * parameter might not be marked as starting at 0 in the
564579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * original list.
565579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             */
566579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if ((decodedAddress != origEntry.getAddress())
567579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    && !((decodedAddress == 0)
568579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            && (decodedEntry.reg >= paramBase))) {
569579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                System.err.println("local address mismatch at orig " + i +
570579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        " / decoded " + decodeAt);
571579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                problem = true;
572579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                break;
573579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
574579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
575579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            decodeAt++;
576579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
577579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
578579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (problem) {
579579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            System.err.println("decoded locals:");
580579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            for (LocalEntry e : decodedLocals) {
581579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                System.err.println("  " + e);
582579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
583579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new RuntimeException("local table problem");
584579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
585579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
586579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
587