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