1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License.
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License.
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage com.android.dx.dex.file;
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
199dbd802c8c96c3a66873bc600bc7d1374a1d08e5Orion Hodsonimport com.android.dex.Leb128;
20fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dex.util.ByteArrayByteInput;
21fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dex.util.ByteInput;
22fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dex.util.ExceptionWithContext;
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.code.DalvCode;
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.code.DalvInsnList;
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.code.LocalList;
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.code.PositionList;
27fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport static com.android.dx.dex.file.DebugInfoConstants.DBG_ADVANCE_LINE;
28fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport static com.android.dx.dex.file.DebugInfoConstants.DBG_ADVANCE_PC;
29fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport static com.android.dx.dex.file.DebugInfoConstants.DBG_END_LOCAL;
30fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport static com.android.dx.dex.file.DebugInfoConstants.DBG_END_SEQUENCE;
31fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport static com.android.dx.dex.file.DebugInfoConstants.DBG_FIRST_SPECIAL;
32fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport static com.android.dx.dex.file.DebugInfoConstants.DBG_LINE_BASE;
33fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport static com.android.dx.dex.file.DebugInfoConstants.DBG_LINE_RANGE;
34fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport static com.android.dx.dex.file.DebugInfoConstants.DBG_RESTART_LOCAL;
35fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport static com.android.dx.dex.file.DebugInfoConstants.DBG_SET_EPILOGUE_BEGIN;
36fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport static com.android.dx.dex.file.DebugInfoConstants.DBG_SET_FILE;
37fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport static com.android.dx.dex.file.DebugInfoConstants.DBG_SET_PROLOGUE_END;
38fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport static com.android.dx.dex.file.DebugInfoConstants.DBG_START_LOCAL;
39fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport static com.android.dx.dex.file.DebugInfoConstants.DBG_START_LOCAL_EXTENDED;
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstMethodRef;
41333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilsonimport com.android.dx.rop.cst.CstString;
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.type.Prototype;
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.type.StdTypeList;
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.type.Type;
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.IOException;
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.ArrayList;
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.List;
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * A decoder for the dex debug info state machine format.
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This code exists mostly as a reference implementation and test for
5299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * for the {@code DebugInfoEncoder}
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic class DebugInfoDecoder {
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** encoded debug info */
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final byte[] encoded;
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** positions decoded */
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final ArrayList<PositionEntry> positions;
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** locals decoded */
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final ArrayList<LocalEntry> locals;
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** size of code block in code units */
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final int codesize;
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** indexed by register, the last local variable live in a reg */
68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final LocalEntry[] lastEntryForReg;
69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** method descriptor of method this debug info is for */
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final Prototype desc;
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** true if method is static */
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final boolean isStatic;
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** dex file this debug info will be stored in */
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final DexFile file;
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * register size, in register units, of the register space
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * used by this method
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final int regSize;
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** current decoding state: line number */
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private int line = 1;
87de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** current decoding state: bytecode address */
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private int address = 0;
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** string index of the string "this" */
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final int thisStringIdx;
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Constructs an instance.
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param encoded encoded debug info
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param codesize size of code block in code units
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param regSize register size, in register units, of the register space
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * used by this method
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param isStatic true if method is static
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param ref method descriptor of method this debug info is for
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param file dex file this debug info will be stored in
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    DebugInfoDecoder(byte[] encoded, int codesize, int regSize,
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            boolean isStatic, CstMethodRef ref, DexFile file) {
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (encoded == null) {
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new NullPointerException("encoded == null");
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.encoded = encoded;
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.isStatic = isStatic;
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.desc = ref.getPrototype();
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.file = file;
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.regSize = regSize;
116de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        positions = new ArrayList<PositionEntry>();
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        locals = new ArrayList<LocalEntry>();
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.codesize = codesize;
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        lastEntryForReg = new LocalEntry[regSize];
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int idx = -1;
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
125333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson            idx = file.getStringIds().indexOf(new CstString("this"));
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (IllegalArgumentException ex) {
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * Silently tolerate not finding "this". It just means that
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * no method has local variable info that looks like
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * a standard instance method.
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        thisStringIdx = idx;
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * An entry in the resulting postions table
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    static private class PositionEntry {
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** bytecode address */
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public int address;
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** line number */
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public int line;
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public PositionEntry(int address, int line) {
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.address = address;
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.line = line;
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * An entry in the resulting locals table
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    static private class LocalEntry {
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** address of event */
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public int address;
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** {@code true} iff it's a local start */
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean isStart;
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** register number */
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public int reg;
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** index of name in strings table */
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public int nameIndex;
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** index of type in types table */
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public int typeIndex;
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** index of type signature in strings table */
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public int signatureIndex;
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public LocalEntry(int address, boolean isStart, int reg, int nameIndex,
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                int typeIndex, int signatureIndex) {
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.address        = address;
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.isStart        = isStart;
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.reg            = reg;
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.nameIndex      = nameIndex;
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.typeIndex      = typeIndex;
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.signatureIndex = signatureIndex;
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1859dbd802c8c96c3a66873bc600bc7d1374a1d08e5Orion Hodson        @Override
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public String toString() {
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return String.format("[%x %s v%d %04x %04x %04x]",
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    address, isStart ? "start" : "end", reg,
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    nameIndex, typeIndex, signatureIndex);
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets the decoded positions list.
19599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Valid after calling {@code decode}.
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return positions list in ascending address order.
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public List<PositionEntry> getPositionList() {
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return positions;
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets the decoded locals list, in ascending start-address order.
20599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Valid after calling {@code decode}.
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return locals list in ascending address order.
208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public List<LocalEntry> getLocals() {
210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return locals;
211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Decodes the debug info sequence.
215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void decode() {
217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            decode0();
219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (Exception ex) {
220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw ExceptionWithContext.withContext(ex,
221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    "...while decoding debug info");
222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Reads a string index. String indicies are offset by 1, and a 0 value
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * in the stream (-1 as returned by this method) means "null"
228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return index into file's string ids table, -1 means null
230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @throws IOException
231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
232bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson    private int readStringIndex(ByteInput bs) throws IOException {
233fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilson        int offsetIndex = Leb128.readUnsignedLeb128(bs);
234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return offsetIndex - 1;
236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets the register that begins the method's parameter range (including
240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * the 'this' parameter for non-static methods). The range continues until
24199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code regSize}
242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return register as noted above.
244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private int getParamBase() {
246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return regSize
247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                - desc.getParameterTypes().getWordCount() - (isStatic? 0 : 1);
248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void decode0() throws IOException {
251bd3dba4346223593ac6033a3d2a7d8ec6f20738bJesse Wilson        ByteInput bs = new ByteArrayByteInput(encoded);
252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
253fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilson        line = Leb128.readUnsignedLeb128(bs);
254fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilson        int szParams = Leb128.readUnsignedLeb128(bs);
255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        StdTypeList params = desc.getParameterTypes();
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int curReg = getParamBase();
257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (szParams != params.size()) {
259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new RuntimeException(
260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    "Mismatch between parameters_size and prototype");
261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
262de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro
263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (!isStatic) {
264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // Start off with implicit 'this' entry
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            LocalEntry thisEntry =
266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                new LocalEntry(0, true, curReg, thisStringIdx, 0, 0);
267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            locals.add(thisEntry);
268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            lastEntryForReg[curReg] = thisEntry;
269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            curReg++;
270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < szParams; i++) {
273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Type paramType = params.getType(i);
274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            LocalEntry le;
275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int nameIdx = readStringIndex(bs);
277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (nameIdx == -1) {
279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /*
280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * Unnamed parameter; often but not always filled in by an
281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * extended start op after the prologue
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 */
283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                le = new LocalEntry(0, true, curReg, -1, 0, 0);
284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                // TODO: Final 0 should be idx of paramType.getDescriptor().
286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                le = new LocalEntry(0, true, curReg, nameIdx, 0, 0);
287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            locals.add(le);
290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            lastEntryForReg[curReg] = le;
291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            curReg += paramType.getCategory();
292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (;;) {
295081c7142b29ccd6e1744b26e097b6a4d7c12f2bdJesse Wilson            int opcode = bs.readByte() & 0xff;
296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            switch (opcode) {
298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case DBG_START_LOCAL: {
299fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilson                    int reg = Leb128.readUnsignedLeb128(bs);
300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int nameIdx = readStringIndex(bs);
301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int typeIdx = readStringIndex(bs);
302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    LocalEntry le = new LocalEntry(
303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            address, true, reg, nameIdx, typeIdx, 0);
304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    locals.add(le);
306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    lastEntryForReg[reg] = le;
307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case DBG_START_LOCAL_EXTENDED: {
311fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilson                    int reg = Leb128.readUnsignedLeb128(bs);
312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int nameIdx = readStringIndex(bs);
313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int typeIdx = readStringIndex(bs);
314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int sigIdx = readStringIndex(bs);
315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    LocalEntry le = new LocalEntry(
316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            address, true, reg, nameIdx, typeIdx, sigIdx);
317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    locals.add(le);
319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    lastEntryForReg[reg] = le;
320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
323f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case DBG_RESTART_LOCAL: {
324fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilson                    int reg = Leb128.readUnsignedLeb128(bs);
325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    LocalEntry prevle;
326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    LocalEntry le;
327f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
328f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    try {
329f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        prevle = lastEntryForReg[reg];
330f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
331f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        if (prevle.isStart) {
332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            throw new RuntimeException("nonsensical "
333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                    + "RESTART_LOCAL on live register v"
334f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                    + reg);
335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        }
336f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        le = new LocalEntry(address, true, reg,
338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                prevle.nameIndex, prevle.typeIndex, 0);
339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    } catch (NullPointerException ex) {
340f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        throw new RuntimeException(
341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                "Encountered RESTART_LOCAL on new v" + reg);
342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
344f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    locals.add(le);
345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    lastEntryForReg[reg] = le;
346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case DBG_END_LOCAL: {
350fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilson                    int reg = Leb128.readUnsignedLeb128(bs);
351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    LocalEntry prevle;
352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    LocalEntry le;
353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    try {
355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        prevle = lastEntryForReg[reg];
356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        if (!prevle.isStart) {
358f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            throw new RuntimeException("nonsensical "
359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                    + "END_LOCAL on dead register v" + reg);
360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        }
361de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro
362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        le = new LocalEntry(address, false, reg,
363f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                prevle.nameIndex, prevle.typeIndex,
364f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                prevle.signatureIndex);
365f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    } catch (NullPointerException ex) {
366f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        throw new RuntimeException(
367f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                "Encountered END_LOCAL on new v" + reg);
368f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    locals.add(le);
371f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    lastEntryForReg[reg] = le;
372f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
373f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case DBG_END_SEQUENCE:
376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    // all done
377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return;
378f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case DBG_ADVANCE_PC:
380fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilson                    address += Leb128.readUnsignedLeb128(bs);
381f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
383f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case DBG_ADVANCE_LINE:
384fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilson                    line += Leb128.readSignedLeb128(bs);
385f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
386f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
387f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case DBG_SET_PROLOGUE_END:
388f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    //TODO do something with this.
389f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
390f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
391f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case DBG_SET_EPILOGUE_BEGIN:
392f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    //TODO do something with this.
393f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
394f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
395f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                case DBG_SET_FILE:
396f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    //TODO do something with this.
397f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
398f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
399f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                default:
400f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (opcode < DBG_FIRST_SPECIAL) {
401f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        throw new RuntimeException(
402f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                "Invalid extended opcode encountered "
403f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                        + opcode);
404f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
405f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
406f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int adjopcode = opcode - DBG_FIRST_SPECIAL;
407f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
408f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    address += adjopcode / DBG_LINE_RANGE;
409f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    line += DBG_LINE_BASE + (adjopcode % DBG_LINE_RANGE);
410f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
411f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    positions.add(new PositionEntry(address, line));
412f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
413f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
414f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
415f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
416f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
417f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
418f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
419f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Validates an encoded debug info stream against data used to encode it,
420f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * throwing an exception if they do not match. Used to validate the
421f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * encoder.
422f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
423f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param info encoded debug info
42499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param file {@code non-null;} file to refer to during decoding
42599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param ref {@code non-null;} method whose info is being decoded
42699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param code {@code non-null;} original code object that was encoded
427f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param isStatic whether the method is static
428f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
429f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public static void validateEncode(byte[] info, DexFile file,
430f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            CstMethodRef ref, DalvCode code, boolean isStatic) {
431f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        PositionList pl = code.getPositions();
432f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LocalList ll = code.getLocals();
433f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        DalvInsnList insns = code.getInsns();
434f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int codeSize = insns.codeSize();
435f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int countRegisters = insns.getRegistersSize();
436de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro
437f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
438f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            validateEncode0(info, codeSize, countRegisters,
439f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    isStatic, ref, file, pl, ll);
440f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (RuntimeException ex) {
441f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            System.err.println("instructions:");
442f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            insns.debugPrint(System.err, "  ", true);
443f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            System.err.println("local list:");
444f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ll.debugPrint(System.err, "  ");
445f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw ExceptionWithContext.withContext(ex,
446f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    "while processing " + ref.toHuman());
447f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
448f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
449de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro
450f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static void validateEncode0(byte[] info, int codeSize,
451f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int countRegisters, boolean isStatic, CstMethodRef ref,
452f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            DexFile file, PositionList pl, LocalList ll) {
453f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        DebugInfoDecoder decoder
454f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                = new DebugInfoDecoder(info, codeSize, countRegisters,
455f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    isStatic, ref, file);
456f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
457f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        decoder.decode();
458f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
459f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
460f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Go through the decoded position entries, matching up
461f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * with original entries.
462f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
463f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
464f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        List<PositionEntry> decodedEntries = decoder.getPositionList();
465f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
466f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (decodedEntries.size() != pl.size()) {
467f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new RuntimeException(
468f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    "Decoded positions table not same size was "
469f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    + decodedEntries.size() + " expected " + pl.size());
470f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
471f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
472f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (PositionEntry entry : decodedEntries) {
473f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            boolean found = false;
474f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            for (int i = pl.size() - 1; i >= 0; i--) {
475f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                PositionList.Entry ple = pl.get(i);
476f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
477f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (entry.line == ple.getPosition().getLine()
478f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        && entry.address == ple.getAddress()) {
479f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    found = true;
480f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
481f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
482f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
483f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
484f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (!found) {
485f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                throw new RuntimeException ("Could not match position entry: "
486f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        + entry.address + ", " + entry.line);
487f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
488f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
489f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
490f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
491f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Go through the original local list, in order, matching up
492f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * with decoded entries.
493f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
494f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
495f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        List<LocalEntry> decodedLocals = decoder.getLocals();
496f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int thisStringIdx = decoder.thisStringIdx;
497f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int decodedSz = decodedLocals.size();
498f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int paramBase = decoder.getParamBase();
499f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
500f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
501f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Preflight to fill in any parameters that were skipped in
502f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * the prologue (including an implied "this") but then
503f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * identified by full signature.
504f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
505f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < decodedSz; i++) {
506f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            LocalEntry entry = decodedLocals.get(i);
507f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int idx = entry.nameIndex;
508f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
509f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if ((idx < 0) || (idx == thisStringIdx)) {
510f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                for (int j = i + 1; j < decodedSz; j++) {
511f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    LocalEntry e2 = decodedLocals.get(j);
512f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (e2.address != 0) {
513f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        break;
514f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
515f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if ((entry.reg == e2.reg) && e2.isStart) {
516f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        decodedLocals.set(i, e2);
517f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        decodedLocals.remove(j);
518f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        decodedSz--;
519f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        break;
520f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
521f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
522f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
523f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
524de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro
525f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int origSz = ll.size();
526f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int decodeAt = 0;
527f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean problem = false;
528f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
529f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < origSz; i++) {
530f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            LocalList.Entry origEntry = ll.get(i);
531f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
532f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (origEntry.getDisposition()
533f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    == LocalList.Disposition.END_REPLACED) {
534f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /*
535f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * The encoded list doesn't represent replacements, so
536f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * ignore them for the sake of comparison.
537f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 */
538f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                continue;
539f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
540f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
541f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            LocalEntry decodedEntry;
542f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
543f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            do {
544f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                decodedEntry = decodedLocals.get(decodeAt);
545f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (decodedEntry.nameIndex >= 0) {
546f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
547f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
548f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /*
549f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * A negative name index means this is an anonymous
550f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * parameter, and we shouldn't expect to see it in the
551f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * original list. So, skip it.
552f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 */
553f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                decodeAt++;
554f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } while (decodeAt < decodedSz);
555f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
556f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int decodedAddress = decodedEntry.address;
557f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
558f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (decodedEntry.reg != origEntry.getRegister()) {
559f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                System.err.println("local register mismatch at orig " + i +
560f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        " / decoded " + decodeAt);
561f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                problem = true;
562f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
563f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
564de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro
565f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (decodedEntry.isStart != origEntry.isStart()) {
566f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                System.err.println("local start/end mismatch at orig " + i +
567f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        " / decoded " + decodeAt);
568f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                problem = true;
569f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
570f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
571f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
572f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
573f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * The secondary check here accounts for the fact that a
574f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * parameter might not be marked as starting at 0 in the
575f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * original list.
576f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
577de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro            if ((decodedAddress != origEntry.getAddress())
578f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    && !((decodedAddress == 0)
579f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            && (decodedEntry.reg >= paramBase))) {
580f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                System.err.println("local address mismatch at orig " + i +
581f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        " / decoded " + decodeAt);
582f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                problem = true;
583f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
584f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
585f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
586f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            decodeAt++;
587f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
588f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
589f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (problem) {
590f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            System.err.println("decoded locals:");
591f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            for (LocalEntry e : decodedLocals) {
592f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                System.err.println("  " + e);
593f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
594f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new RuntimeException("local table problem");
595f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
596f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
597f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
598