DebugInstructionIterator.java revision 83b80f81d311b233188c281059aad4a9f5e8b4e6
1/* 2 * [The "BSD licence"] 3 * Copyright (c) 2009 Ben Gruver 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29package org.jf.dexlib.Debug; 30 31import org.jf.dexlib.Util.Input; 32import org.jf.dexlib.Util.ByteArrayInput; 33import org.jf.dexlib.TypeIdItem; 34import org.jf.dexlib.StringIdItem; 35import org.jf.dexlib.DexFile; 36import org.jf.dexlib.DebugInfoItem; 37 38public class DebugInstructionIterator { 39 /** 40 * This method decodes the debug instructions in the given byte array and iterates over them, calling 41 * the ProcessDebugInstructionDelegate.ProcessDebugInstruction method for each instruction 42 * @param in an Input object that the debug instructions can be read from 43 * @param processDebugInstruction a <code>ProcessDebugInstructionDelegate</code> object that gets called 44 * for each instruction that is encountered 45 */ 46 public static void IterateInstructions(Input in, ProcessRawDebugInstructionDelegate processDebugInstruction) { 47 int startOffset; 48 49 while(true) 50 { 51 startOffset = in.getCursor(); 52 byte debugOpcode = in.readByte(); 53 54 switch (debugOpcode) { 55 case 0x00: 56 { 57 processDebugInstruction.ProcessEndSequence(startOffset); 58 return; 59 } 60 case 0x01: 61 { 62 int addressDiff = in.readUnsignedLeb128(); 63 processDebugInstruction.ProcessAdvancePC(startOffset, in.getCursor() - startOffset, addressDiff); 64 break; 65 } 66 case 0x02: 67 { 68 int lineDiff = in.readSignedLeb128(); 69 processDebugInstruction.ProcessAdvanceLine(startOffset, in.getCursor() - startOffset, lineDiff); 70 break; 71 } 72 case 0x03: 73 { 74 int registerNum = in.readUnsignedLeb128(); 75 int nameIndex = in.readUnsignedLeb128() - 1; 76 int typeIndex = in.readUnsignedLeb128() - 1; 77 processDebugInstruction.ProcessStartLocal(startOffset, in.getCursor() - startOffset, registerNum, 78 nameIndex, typeIndex); 79 break; 80 } 81 case 0x04: 82 { 83 int registerNum = in.readUnsignedLeb128(); 84 int nameIndex = in.readUnsignedLeb128() - 1; 85 int typeIndex = in.readUnsignedLeb128() - 1; 86 int signatureIndex = in.readUnsignedLeb128() - 1; 87 processDebugInstruction.ProcessStartLocalExtended(startOffset, in.getCursor() - startOffset, 88 registerNum, nameIndex, typeIndex, signatureIndex); 89 break; 90 } 91 case 0x05: 92 { 93 int registerNum = in.readUnsignedLeb128(); 94 processDebugInstruction.ProcessEndLocal(startOffset, in.getCursor() - startOffset, registerNum); 95 break; 96 } 97 case 0x06: 98 { 99 int registerNum = in.readUnsignedLeb128(); 100 processDebugInstruction.ProcessRestartLocal(startOffset, in.getCursor() - startOffset, registerNum); 101 break; 102 } 103 case 0x07: 104 { 105 processDebugInstruction.ProcessSetPrologueEnd(startOffset); 106 break; 107 } 108 case 0x08: 109 { 110 processDebugInstruction.ProcessSetEpilogueBegin(startOffset); 111 break; 112 } 113 case 0x09: 114 { 115 int nameIndex = in.readUnsignedLeb128(); 116 processDebugInstruction.ProcessSetFile(startOffset, in.getCursor() - startOffset, nameIndex); 117 break; 118 } 119 default: 120 { 121 byte base = (byte)((debugOpcode & 0xFF) - 0x0A); 122 processDebugInstruction.ProcessSpecialOpcode(startOffset, debugOpcode, (base % 15) - 4, base / 15); 123 } 124 } 125 } 126 } 127 128 /** 129 * This method decodes the debug instructions in the given byte array and iterates over them, calling 130 * the ProcessDebugInstructionDelegate.ProcessDebugInstruction method for each instruction 131 * @param debugInfoItem the <code>DebugInfoItem</code> to iterate over 132 * @param registerCount the number of registers in the method that the given debug info is for 133 * @param processDecodedDebugInstruction a <code>ProcessDebugInstructionDelegate</code> object that gets called 134 * for each instruction that is encountered 135 */ 136 public static void DecodeInstructions(DebugInfoItem debugInfoItem, int registerCount, 137 ProcessDecodedDebugInstructionDelegate processDecodedDebugInstruction) { 138 int startOffset; 139 int address = 0; 140 int line = debugInfoItem.getLineStart(); 141 Input in = new ByteArrayInput(debugInfoItem.getEncodedDebugInfo()); 142 DexFile dexFile = debugInfoItem.getDexFile(); 143 144 Local[] locals = new Local[registerCount]; 145 146 while(true) 147 { 148 startOffset = in.getCursor(); 149 byte debugOpcode = in.readByte(); 150 151 switch (debugOpcode) { 152 case 0x00: 153 { 154 return; 155 } 156 case 0x01: 157 { 158 int addressDiff = in.readUnsignedLeb128(); 159 address += addressDiff; 160 break; 161 } 162 case 0x02: 163 { 164 int lineDiff = in.readSignedLeb128(); 165 line += lineDiff; 166 break; 167 } 168 case 0x03: 169 { 170 int registerNum = in.readUnsignedLeb128(); 171 StringIdItem name = dexFile.StringIdsSection.getItemByIndex(in.readUnsignedLeb128() - 1); 172 TypeIdItem type = dexFile.TypeIdsSection.getItemByIndex(in.readUnsignedLeb128() - 1); 173 locals[registerNum] = new Local(registerNum, name, type, null); 174 processDecodedDebugInstruction.ProcessStartLocal(startOffset, in.getCursor() - startOffset, registerNum, 175 name, type); 176 break; 177 } 178 case 0x04: 179 { 180 int registerNum = in.readUnsignedLeb128(); 181 StringIdItem name = dexFile.StringIdsSection.getItemByIndex(in.readUnsignedLeb128() - 1); 182 TypeIdItem type = dexFile.TypeIdsSection.getItemByIndex(in.readUnsignedLeb128() - 1); 183 StringIdItem signature = dexFile.StringIdsSection.getItemByIndex(in.readUnsignedLeb128() - 1); 184 locals[registerNum] = new Local(registerNum, name, type, signature); 185 processDecodedDebugInstruction.ProcessStartLocalExtended(startOffset, in.getCursor() - startOffset, 186 registerNum, name, type, signature); 187 break; 188 } 189 case 0x05: 190 { 191 int registerNum = in.readUnsignedLeb128(); 192 Local local = locals[registerNum]; 193 if (local == null) { 194 processDecodedDebugInstruction.ProcessEndLocal(startOffset, in.getCursor() - startOffset, registerNum, 195 null, null, null); 196 } else { 197 processDecodedDebugInstruction.ProcessEndLocal(startOffset, in.getCursor() - startOffset, registerNum, 198 local.name, local.type, local.signature); 199 } 200 break; 201 } 202 case 0x06: 203 { 204 int registerNum = in.readUnsignedLeb128(); 205 Local local = locals[registerNum]; 206 if (local == null) { 207 processDecodedDebugInstruction.ProcessRestartLocal(startOffset, in.getCursor() - startOffset, 208 registerNum, null, null, null); 209 } else { 210 processDecodedDebugInstruction.ProcessRestartLocal(startOffset, in.getCursor() - startOffset, 211 registerNum, local.name, local.type, local.signature); 212 } 213 214 break; 215 } 216 case 0x07: 217 { 218 processDecodedDebugInstruction.ProcessSetPrologueEnd(startOffset); 219 break; 220 } 221 case 0x08: 222 { 223 processDecodedDebugInstruction.ProcessSetEpilogueBegin(startOffset); 224 break; 225 } 226 case 0x09: 227 { 228 StringIdItem name = dexFile.StringIdsSection.getItemByIndex(in.readUnsignedLeb128() - 1); 229 processDecodedDebugInstruction.ProcessSetFile(startOffset, in.getCursor() - startOffset, name); 230 break; 231 } 232 default: 233 { 234 byte base = (byte)((debugOpcode & 0xFF) - 0x0A); 235 address += base / 15; 236 line += (base % 15) - 4; 237 processDecodedDebugInstruction.ProcessLineEmit(address, line); 238 } 239 } 240 } 241 } 242 243 public static class ProcessRawDebugInstructionDelegate 244 { 245 //TODO: add javadocs 246 public void ProcessEndSequence(int startOffset) { 247 ProcessStaticOpcode(startOffset, 1); 248 } 249 250 public void ProcessAdvancePC(int startOffset, int length, int addressDiff) { 251 ProcessStaticOpcode(startOffset, length); 252 } 253 254 public void ProcessAdvanceLine(int startOffset, int length, int lineDiff) { 255 ProcessStaticOpcode(startOffset, length); 256 } 257 258 public void ProcessStartLocal(int startOffset, int length, int registerNum, int nameIndex, int typeIndex) { 259 } 260 261 public void ProcessStartLocalExtended(int startOffset, int length, int registerNum, int nameIndex, 262 int typeIndex,int signatureIndex) { 263 } 264 265 public void ProcessEndLocal(int startOffset, int length, int registerNum) { 266 ProcessStaticOpcode(startOffset, length); 267 } 268 269 public void ProcessRestartLocal(int startOffset, int length, int registerNum) { 270 ProcessStaticOpcode(startOffset, length); 271 } 272 273 public void ProcessSetPrologueEnd(int startOffset) { 274 ProcessStaticOpcode(startOffset, 1); 275 } 276 277 public void ProcessSetEpilogueBegin(int startOffset) { 278 ProcessStaticOpcode(startOffset, 1); 279 } 280 281 public void ProcessSetFile(int startOffset, int length, int nameIndex) { 282 } 283 284 public void ProcessSpecialOpcode(int startOffset, int debugOpcode, int lineDiff, int addressDiff) { 285 ProcessStaticOpcode(startOffset, 1); 286 } 287 288 public void ProcessStaticOpcode(int startOffset, int length) { 289 } 290 } 291 292 public static class ProcessDecodedDebugInstructionDelegate 293 { 294 public void ProcessStartLocal(int codeAddress, int length, int registerNum, StringIdItem name, 295 TypeIdItem type) { 296 } 297 298 public void ProcessStartLocalExtended(int codeAddress, int length, int registerNum, StringIdItem name, 299 TypeIdItem type, StringIdItem signature) { 300 } 301 302 public void ProcessEndLocal(int codeAddress, int length, int registerNum, StringIdItem name, TypeIdItem type, 303 StringIdItem signature) { 304 } 305 306 public void ProcessRestartLocal(int codeAddress, int length, int registerNum, StringIdItem name, 307 TypeIdItem type, StringIdItem signature) { 308 } 309 310 public void ProcessSetPrologueEnd(int codeAddress) { 311 } 312 313 public void ProcessSetEpilogueBegin(int codeAddress) { 314 } 315 316 public void ProcessSetFile(int codeAddress, int length, StringIdItem name) { 317 } 318 319 public void ProcessLineEmit(int codeAddress, int line) { 320 } 321 } 322 323 private static class Local { 324 public final int register; 325 public final StringIdItem name; 326 public final TypeIdItem type; 327 public final StringIdItem signature; 328 public Local(int register, StringIdItem name, TypeIdItem type, StringIdItem signature) { 329 this.register = register; 330 this.name = name; 331 this.type = type; 332 this.signature = signature; 333 } 334 335 } 336} 337