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