1917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul/*
2917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Copyright (C) 2007 The Android Open Source Project
3917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
4917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Licensed under the Apache License, Version 2.0 (the "License");
5917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * you may not use this file except in compliance with the License.
6917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * You may obtain a copy of the License at
7917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
8917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *      http://www.apache.org/licenses/LICENSE-2.0
9917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
10917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Unless required by applicable law or agreed to in writing, software
11917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * distributed under the License is distributed on an "AS IS" BASIS,
12917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * See the License for the specific language governing permissions and
14917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * limitations under the License.
15917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */
16917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
17917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulpackage com.android.dexgen.dex.file;
18917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
19917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.dex.code.DalvCode;
20917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.dex.code.DalvInsnList;
21917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.dex.code.LocalList;
22917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.dex.code.PositionList;
23917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.CstMethodRef;
24917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.CstUtf8;
25917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.type.Prototype;
26917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.type.StdTypeList;
27917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.type.Type;
28917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.util.ExceptionWithContext;
29917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
30917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.io.ByteArrayInputStream;
31917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.io.IOException;
32917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.io.InputStream;
33917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.ArrayList;
34917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.List;
35917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
36917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport static com.android.dexgen.dex.file.DebugInfoConstants.*;
37917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
38917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul/**
39917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * A decoder for the dex debug info state machine format.
40917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * This code exists mostly as a reference implementation and test for
41917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * for the {@code DebugInfoEncoder}
42917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */
43917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulpublic class DebugInfoDecoder {
44917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** encoded debug info */
45917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final byte[] encoded;
46917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
47917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** positions decoded */
48917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final ArrayList<PositionEntry> positions;
49917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
50917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** locals decoded */
51917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final ArrayList<LocalEntry> locals;
52917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
53917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** size of code block in code units */
54917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final int codesize;
55917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
56917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** indexed by register, the last local variable live in a reg */
57917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final LocalEntry[] lastEntryForReg;
58917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
59917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** method descriptor of method this debug info is for */
60917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final Prototype desc;
61917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
62917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** true if method is static */
63917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final boolean isStatic;
64917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
65917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** dex file this debug info will be stored in */
66917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final DexFile file;
67917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
68917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
69917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * register size, in register units, of the register space
70917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * used by this method
71917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
72917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final int regSize;
73917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
74917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** current decoding state: line number */
75917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private int line = 1;
76917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
77917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** current decoding state: bytecode address */
78917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private int address = 0;
79917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
80917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** string index of the string "this" */
81917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final int thisStringIdx;
82917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
83917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
84917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Constructs an instance.
85917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
86917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param encoded encoded debug info
87917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param codesize size of code block in code units
88917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param regSize register size, in register units, of the register space
89917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * used by this method
90917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param isStatic true if method is static
91917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param ref method descriptor of method this debug info is for
92917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param file dex file this debug info will be stored in
93917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
94917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    DebugInfoDecoder(byte[] encoded, int codesize, int regSize,
95917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            boolean isStatic, CstMethodRef ref, DexFile file) {
96917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (encoded == null) {
97917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new NullPointerException("encoded == null");
98917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
99917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
100917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.encoded = encoded;
101917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.isStatic = isStatic;
102917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.desc = ref.getPrototype();
103917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.file = file;
104917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.regSize = regSize;
105917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
106917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        positions = new ArrayList<PositionEntry>();
107917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        locals = new ArrayList<LocalEntry>();
108917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.codesize = codesize;
109917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        lastEntryForReg = new LocalEntry[regSize];
110917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
111917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int idx = -1;
112917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
113917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        try {
114917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            idx = file.getStringIds().indexOf(new CstUtf8("this"));
115917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        } catch (IllegalArgumentException ex) {
116917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            /*
117917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * Silently tolerate not finding "this". It just means that
118917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * no method has local variable info that looks like
119917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * a standard instance method.
120917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             */
121917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
122917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
123917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        thisStringIdx = idx;
124917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
125917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
126917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
127917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * An entry in the resulting postions table
128917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
129917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    static private class PositionEntry {
130917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** bytecode address */
131917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public int address;
132917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
133917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** line number */
134917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public int line;
135917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
136917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public PositionEntry(int address, int line) {
137917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            this.address = address;
138917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            this.line = line;
139917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
140917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
141917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
142917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
143917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * An entry in the resulting locals table
144917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
145917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    static private class LocalEntry {
146917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** address of event */
147917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public int address;
148917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
149917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** {@code true} iff it's a local start */
150917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public boolean isStart;
151917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
152917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** register number */
153917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public int reg;
154917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
155917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** index of name in strings table */
156917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public int nameIndex;
157917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
158917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** index of type in types table */
159917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public int typeIndex;
160917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
161917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** index of type signature in strings table */
162917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public int signatureIndex;
163917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
164917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public LocalEntry(int address, boolean isStart, int reg, int nameIndex,
165917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                int typeIndex, int signatureIndex) {
166917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            this.address        = address;
167917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            this.isStart        = isStart;
168917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            this.reg            = reg;
169917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            this.nameIndex      = nameIndex;
170917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            this.typeIndex      = typeIndex;
171917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            this.signatureIndex = signatureIndex;
172917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
173917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
174917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public String toString() {
175917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return String.format("[%x %s v%d %04x %04x %04x]",
176917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    address, isStart ? "start" : "end", reg,
177917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    nameIndex, typeIndex, signatureIndex);
178917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
179917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
180917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
181917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
182917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets the decoded positions list.
183917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Valid after calling {@code decode}.
184917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
185917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return positions list in ascending address order.
186917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
187917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public List<PositionEntry> getPositionList() {
188917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return positions;
189917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
190917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
191917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
192917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets the decoded locals list, in ascending start-address order.
193917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Valid after calling {@code decode}.
194917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
195917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return locals list in ascending address order.
196917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
197917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public List<LocalEntry> getLocals() {
198917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return locals;
199917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
200917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
201917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
202917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Decodes the debug info sequence.
203917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
204917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public void decode() {
205917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        try {
206917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            decode0();
207917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        } catch (Exception ex) {
208917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw ExceptionWithContext.withContext(ex,
209917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    "...while decoding debug info");
210917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
211917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
212917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
213917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
214917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Reads a string index. String indicies are offset by 1, and a 0 value
215917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * in the stream (-1 as returned by this method) means "null"
216917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
217917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param bs
218917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return index into file's string ids table, -1 means null
219917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @throws IOException
220917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
221917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private int readStringIndex(InputStream bs) throws IOException {
222917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int offsetIndex = readUnsignedLeb128(bs);
223917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
224917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return offsetIndex - 1;
225917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
226917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
227917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
228917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets the register that begins the method's parameter range (including
229917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * the 'this' parameter for non-static methods). The range continues until
230917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@code regSize}
231917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
232917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return register as noted above.
233917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
234917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private int getParamBase() {
235917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return regSize
236917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                - desc.getParameterTypes().getWordCount() - (isStatic? 0 : 1);
237917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
238917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
239917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private void decode0() throws IOException {
240917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        ByteArrayInputStream bs = new ByteArrayInputStream(encoded);
241917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
242917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        line = readUnsignedLeb128(bs);
243917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int szParams = readUnsignedLeb128(bs);
244917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        StdTypeList params = desc.getParameterTypes();
245917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int curReg = getParamBase();
246917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
247917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (szParams != params.size()) {
248917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new RuntimeException(
249917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    "Mismatch between parameters_size and prototype");
250917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
251917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
252917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (!isStatic) {
253917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            // Start off with implicit 'this' entry
254917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            LocalEntry thisEntry =
255917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                new LocalEntry(0, true, curReg, thisStringIdx, 0, 0);
256917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            locals.add(thisEntry);
257917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            lastEntryForReg[curReg] = thisEntry;
258917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            curReg++;
259917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
260917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
261917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < szParams; i++) {
262917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Type paramType = params.getType(i);
263917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            LocalEntry le;
264917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
265917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int nameIdx = readStringIndex(bs);
266917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
267917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (nameIdx == -1) {
268917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                /*
269917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * Unnamed parameter; often but not always filled in by an
270917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * extended start op after the prologue
271917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 */
272917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                le = new LocalEntry(0, true, curReg, -1, 0, 0);
273917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            } else {
274917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                // TODO: Final 0 should be idx of paramType.getDescriptor().
275917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                le = new LocalEntry(0, true, curReg, nameIdx, 0, 0);
276917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
277917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
278917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            locals.add(le);
279917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            lastEntryForReg[curReg] = le;
280917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            curReg += paramType.getCategory();
281917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
282917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
283917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (;;) {
284917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int opcode = bs.read();
285917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
286917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (opcode < 0) {
287917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                throw new RuntimeException
288917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        ("Reached end of debug stream without "
289917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                + "encountering end marker");
290917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
291917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
292917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            switch (opcode) {
293917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                case DBG_START_LOCAL: {
294917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    int reg = readUnsignedLeb128(bs);
295917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    int nameIdx = readStringIndex(bs);
296917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    int typeIdx = readStringIndex(bs);
297917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    LocalEntry le = new LocalEntry(
298917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            address, true, reg, nameIdx, typeIdx, 0);
299917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
300917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    locals.add(le);
301917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    lastEntryForReg[reg] = le;
302917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
303917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                break;
304917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
305917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                case DBG_START_LOCAL_EXTENDED: {
306917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    int reg = readUnsignedLeb128(bs);
307917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    int nameIdx = readStringIndex(bs);
308917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    int typeIdx = readStringIndex(bs);
309917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    int sigIdx = readStringIndex(bs);
310917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    LocalEntry le = new LocalEntry(
311917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            address, true, reg, nameIdx, typeIdx, sigIdx);
312917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
313917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    locals.add(le);
314917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    lastEntryForReg[reg] = le;
315917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
316917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                break;
317917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
318917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                case DBG_RESTART_LOCAL: {
319917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    int reg = readUnsignedLeb128(bs);
320917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    LocalEntry prevle;
321917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    LocalEntry le;
322917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
323917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    try {
324917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        prevle = lastEntryForReg[reg];
325917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
326917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        if (prevle.isStart) {
327917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            throw new RuntimeException("nonsensical "
328917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                    + "RESTART_LOCAL on live register v"
329917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                    + reg);
330917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        }
331917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
332917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        le = new LocalEntry(address, true, reg,
333917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                prevle.nameIndex, prevle.typeIndex, 0);
334917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    } catch (NullPointerException ex) {
335917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        throw new RuntimeException(
336917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                "Encountered RESTART_LOCAL on new v" + reg);
337917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    }
338917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
339917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    locals.add(le);
340917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    lastEntryForReg[reg] = le;
341917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
342917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                break;
343917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
344917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                case DBG_END_LOCAL: {
345917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    int reg = readUnsignedLeb128(bs);
346917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    LocalEntry prevle;
347917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    LocalEntry le;
348917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
349917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    try {
350917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        prevle = lastEntryForReg[reg];
351917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
352917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        if (!prevle.isStart) {
353917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            throw new RuntimeException("nonsensical "
354917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                    + "END_LOCAL on dead register v" + reg);
355917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        }
356917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
357917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        le = new LocalEntry(address, false, reg,
358917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                prevle.nameIndex, prevle.typeIndex,
359917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                prevle.signatureIndex);
360917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    } catch (NullPointerException ex) {
361917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        throw new RuntimeException(
362917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                "Encountered END_LOCAL on new v" + reg);
363917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    }
364917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
365917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    locals.add(le);
366917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    lastEntryForReg[reg] = le;
367917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
368917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                break;
369917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
370917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                case DBG_END_SEQUENCE:
371917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    // all done
372917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                return;
373917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
374917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                case DBG_ADVANCE_PC:
375917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    address += readUnsignedLeb128(bs);
376917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                break;
377917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
378917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                case DBG_ADVANCE_LINE:
379917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    line += readSignedLeb128(bs);
380917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                break;
381917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
382917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                case DBG_SET_PROLOGUE_END:
383917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    //TODO do something with this.
384917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                break;
385917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
386917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                case DBG_SET_EPILOGUE_BEGIN:
387917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    //TODO do something with this.
388917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                break;
389917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
390917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                case DBG_SET_FILE:
391917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    //TODO do something with this.
392917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                break;
393917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
394917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                default:
395917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    if (opcode < DBG_FIRST_SPECIAL) {
396917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        throw new RuntimeException(
397917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                "Invalid extended opcode encountered "
398917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                        + opcode);
399917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    }
400917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
401917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    int adjopcode = opcode - DBG_FIRST_SPECIAL;
402917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
403917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    address += adjopcode / DBG_LINE_RANGE;
404917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    line += DBG_LINE_BASE + (adjopcode % DBG_LINE_RANGE);
405917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
406917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    positions.add(new PositionEntry(address, line));
407917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                break;
408917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
409917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
410917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
411917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
412917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
413917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
414917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Validates an encoded debug info stream against data used to encode it,
415917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * throwing an exception if they do not match. Used to validate the
416917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * encoder.
417917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
418917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param info encoded debug info
419917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param file {@code non-null;} file to refer to during decoding
420917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param ref {@code non-null;} method whose info is being decoded
421917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param code {@code non-null;} original code object that was encoded
422917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param isStatic whether the method is static
423917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
424917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public static void validateEncode(byte[] info, DexFile file,
425917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            CstMethodRef ref, DalvCode code, boolean isStatic) {
426917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        PositionList pl = code.getPositions();
427917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        LocalList ll = code.getLocals();
428917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        DalvInsnList insns = code.getInsns();
429917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int codeSize = insns.codeSize();
430917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int countRegisters = insns.getRegistersSize();
431917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
432917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        try {
433917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            validateEncode0(info, codeSize, countRegisters,
434917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    isStatic, ref, file, pl, ll);
435917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        } catch (RuntimeException ex) {
436917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            System.err.println("instructions:");
437917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            insns.debugPrint(System.err, "  ", true);
438917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            System.err.println("local list:");
439917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            ll.debugPrint(System.err, "  ");
440917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw ExceptionWithContext.withContext(ex,
441917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    "while processing " + ref.toHuman());
442917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
443917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
444917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
445917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private static void validateEncode0(byte[] info, int codeSize,
446917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int countRegisters, boolean isStatic, CstMethodRef ref,
447917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            DexFile file, PositionList pl, LocalList ll) {
448917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        DebugInfoDecoder decoder
449917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                = new DebugInfoDecoder(info, codeSize, countRegisters,
450917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    isStatic, ref, file);
451917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
452917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        decoder.decode();
453917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
454917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /*
455917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Go through the decoded position entries, matching up
456917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * with original entries.
457917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
458917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
459917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        List<PositionEntry> decodedEntries = decoder.getPositionList();
460917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
461917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (decodedEntries.size() != pl.size()) {
462917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new RuntimeException(
463917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    "Decoded positions table not same size was "
464917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    + decodedEntries.size() + " expected " + pl.size());
465917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
466917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
467917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (PositionEntry entry : decodedEntries) {
468917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            boolean found = false;
469917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            for (int i = pl.size() - 1; i >= 0; i--) {
470917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                PositionList.Entry ple = pl.get(i);
471917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
472917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (entry.line == ple.getPosition().getLine()
473917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        && entry.address == ple.getAddress()) {
474917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    found = true;
475917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    break;
476917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
477917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
478917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
479917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (!found) {
480917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                throw new RuntimeException ("Could not match position entry: "
481917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        + entry.address + ", " + entry.line);
482917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
483917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
484917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
485917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /*
486917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Go through the original local list, in order, matching up
487917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * with decoded entries.
488917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
489917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
490917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        List<LocalEntry> decodedLocals = decoder.getLocals();
491917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int thisStringIdx = decoder.thisStringIdx;
492917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int decodedSz = decodedLocals.size();
493917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int paramBase = decoder.getParamBase();
494917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
495917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /*
496917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Preflight to fill in any parameters that were skipped in
497917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * the prologue (including an implied "this") but then
498917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * identified by full signature.
499917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
500917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < decodedSz; i++) {
501917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            LocalEntry entry = decodedLocals.get(i);
502917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int idx = entry.nameIndex;
503917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
504917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if ((idx < 0) || (idx == thisStringIdx)) {
505917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                for (int j = i + 1; j < decodedSz; j++) {
506917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    LocalEntry e2 = decodedLocals.get(j);
507917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    if (e2.address != 0) {
508917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        break;
509917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    }
510917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    if ((entry.reg == e2.reg) && e2.isStart) {
511917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        decodedLocals.set(i, e2);
512917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        decodedLocals.remove(j);
513917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        decodedSz--;
514917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        break;
515917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    }
516917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
517917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
518917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
519917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
520917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int origSz = ll.size();
521917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int decodeAt = 0;
522917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        boolean problem = false;
523917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
524917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < origSz; i++) {
525917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            LocalList.Entry origEntry = ll.get(i);
526917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
527917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (origEntry.getDisposition()
528917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    == LocalList.Disposition.END_REPLACED) {
529917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                /*
530917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * The encoded list doesn't represent replacements, so
531917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * ignore them for the sake of comparison.
532917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 */
533917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                continue;
534917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
535917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
536917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            LocalEntry decodedEntry;
537917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
538917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            do {
539917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                decodedEntry = decodedLocals.get(decodeAt);
540917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (decodedEntry.nameIndex >= 0) {
541917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    break;
542917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
543917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                /*
544917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * A negative name index means this is an anonymous
545917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * parameter, and we shouldn't expect to see it in the
546917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * original list. So, skip it.
547917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 */
548917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                decodeAt++;
549917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            } while (decodeAt < decodedSz);
550917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
551917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int decodedAddress = decodedEntry.address;
552917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
553917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (decodedEntry.reg != origEntry.getRegister()) {
554917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                System.err.println("local register mismatch at orig " + i +
555917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        " / decoded " + decodeAt);
556917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                problem = true;
557917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                break;
558917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
559917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
560917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (decodedEntry.isStart != origEntry.isStart()) {
561917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                System.err.println("local start/end mismatch at orig " + i +
562917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        " / decoded " + decodeAt);
563917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                problem = true;
564917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                break;
565917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
566917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
567917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            /*
568917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * The secondary check here accounts for the fact that a
569917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * parameter might not be marked as starting at 0 in the
570917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * original list.
571917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             */
572917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if ((decodedAddress != origEntry.getAddress())
573917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    && !((decodedAddress == 0)
574917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            && (decodedEntry.reg >= paramBase))) {
575917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                System.err.println("local address mismatch at orig " + i +
576917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        " / decoded " + decodeAt);
577917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                problem = true;
578917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                break;
579917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
580917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
581917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            decodeAt++;
582917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
583917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
584917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (problem) {
585917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            System.err.println("decoded locals:");
586917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            for (LocalEntry e : decodedLocals) {
587917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                System.err.println("  " + e);
588917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
589917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new RuntimeException("local table problem");
590917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
591917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
592917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
593917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
594917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Reads a DWARFv3-style signed LEB128 integer to the specified stream.
595917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * See DWARF v3 section 7.6. An invalid sequence produces an IOException.
596917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
597917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param bs stream to input from
598917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return read value
599917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @throws IOException on invalid sequence in addition to
600917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * those caused by the InputStream
601917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
602917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public static int readSignedLeb128(InputStream bs) throws IOException {
603917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int result = 0;
604917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int cur;
605917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int count = 0;
606917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int signBits = -1;
607917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
608917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        do {
609917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            cur = bs.read();
610917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            result |= (cur & 0x7f) << (count * 7);
611917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            signBits <<= 7;
612917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            count++;
613917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        } while (((cur & 0x80) == 0x80) && count < 5);
614917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
615917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if ((cur & 0x80) == 0x80) {
616917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new IOException ("invalid LEB128 sequence");
617917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
618917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
619917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        // Sign extend if appropriate
620917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (((signBits >> 1) & result) != 0 ) {
621917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            result |= signBits;
622917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
623917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
624917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return result;
625917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
626917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
627917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
628917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Reads a DWARFv3-style unsigned LEB128 integer to the specified stream.
629917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * See DWARF v3 section 7.6. An invalid sequence produces an IOException.
630917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
631917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param bs stream to input from
632917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return read value, which should be treated as an unsigned value.
633917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @throws IOException on invalid sequence in addition to
634917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * those caused by the InputStream
635917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
636917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public static int readUnsignedLeb128(InputStream bs) throws IOException {
637917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int result = 0;
638917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int cur;
639917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int count = 0;
640917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
641917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        do {
642917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            cur = bs.read();
643917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            result |= (cur & 0x7f) << (count * 7);
644917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            count++;
645917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        } while (((cur & 0x80) == 0x80) && count < 5);
646917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
647917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if ((cur & 0x80) == 0x80) {
648917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new IOException ("invalid LEB128 sequence");
649917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
650917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
651917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return result;
652917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
653917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul}
654