CodeItem.java revision c604ed6c1a306ae963500fc63177bc9b6ae5569a
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; 30 31import org.jf.dexlib.Code.InstructionReader; 32import org.jf.dexlib.Code.InstructionIterator; 33import org.jf.dexlib.Code.Opcode; 34import org.jf.dexlib.Code.InstructionWriter; 35import org.jf.dexlib.Util.AnnotatedOutput; 36import org.jf.dexlib.Util.Input; 37import org.jf.dexlib.Util.SparseArray; 38import org.jf.dexlib.Util.Leb128Utils; 39 40import java.util.List; 41 42public class CodeItem extends Item<CodeItem> { 43 private int registerCount; 44 private int inWords; 45 private int outWords; 46 private DebugInfoItem debugInfo; 47 private byte[] encodedInstructions; 48 private Item[] referencedItems; 49 private TryItem[] tries; 50 private EncodedCatchHandler[] encodedCatchHandlers; 51 52 private ClassDataItem.EncodedMethod parent; 53 54 /** 55 * Creates a new uninitialized <code>CodeItem</code> 56 * @param dexFile The <code>DexFile</code> that this item belongs to 57 */ 58 public CodeItem(DexFile dexFile) { 59 super(dexFile); 60 } 61 62 /** 63 * Creates a new <code>CodeItem</code> with the given values. 64 * @param dexFile The <code>DexFile</code> that this item belongs to 65 * @param registerCount the number of registers that the method containing this code uses 66 * @param inWords the number of 2-byte words that the parameters to the method containing this code take 67 * @param outWords the maximum number of 2-byte words for the arguments of any method call in this code 68 * @param debugInfo the debug information for this code/method 69 * @param encodedInstructions the instructions, encoded as a byte array 70 * @param referencedItems an array of the items referenced by instructions, in order of occurance in the code 71 * @param tries an array of the tries defined for this code/method 72 * @param encodedCatchHandlers an array of the exception handlers defined for this code/method 73 */ 74 private CodeItem(DexFile dexFile, 75 int registerCount, 76 int inWords, 77 int outWords, 78 DebugInfoItem debugInfo, 79 byte[] encodedInstructions, 80 Item[] referencedItems, 81 TryItem[] tries, 82 EncodedCatchHandler[] encodedCatchHandlers) { 83 super(dexFile); 84 85 this.registerCount = registerCount; 86 this.inWords = inWords; 87 this.outWords = outWords; 88 this.debugInfo = debugInfo; 89 if (debugInfo != null) { 90 debugInfo.setParent(this); 91 } 92 this.encodedInstructions = encodedInstructions; 93 this.referencedItems = referencedItems; 94 this.tries = tries; 95 this.encodedCatchHandlers = encodedCatchHandlers; 96 } 97 98 /** 99 * Returns a new <code>CodeItem</code> with the given values. 100 * @param dexFile The <code>DexFile</code> that this item belongs to 101 * @param registerCount the number of registers that the method containing this code uses 102 * @param inWords the number of 2-byte words that the parameters to the method containing this code take 103 * @param outWords the maximum number of 2-byte words for the arguments of any method call in this code 104 * @param debugInfo the debug information for this code/method 105 * @param encodedInstructions the instructions, encoded as a byte array 106 * @param referencedItems a list of the items referenced by instructions, in order of occurance in the code, 107 * or null if none 108 * @param tries a list of the tries defined for this code/method or null if none 109 * @param encodedCatchHandlers a list of the exception handlers defined for this code/method or null if none 110 * @return a new <code>CodeItem</code> with the given values. 111 */ 112 public static CodeItem getInternedCodeItem(DexFile dexFile, 113 int registerCount, 114 int inWords, 115 int outWords, 116 DebugInfoItem debugInfo, 117 byte[] encodedInstructions, 118 List<Item> referencedItems, 119 List<TryItem> tries, 120 List<EncodedCatchHandler> encodedCatchHandlers) { 121 Item[] referencedItemsArray = null; 122 TryItem[] triesArray = null; 123 EncodedCatchHandler[] encodedCatchHandlersArray = null; 124 125 if (referencedItems != null && referencedItems.size() > 0) { 126 referencedItemsArray = new Item[referencedItems.size()]; 127 referencedItems.toArray(referencedItemsArray); 128 } 129 130 if (tries != null && tries.size() > 0) { 131 triesArray = new TryItem[tries.size()]; 132 tries.toArray(triesArray); 133 } 134 135 if (encodedCatchHandlers != null && encodedCatchHandlers.size() > 0) { 136 encodedCatchHandlersArray = new EncodedCatchHandler[encodedCatchHandlers.size()]; 137 encodedCatchHandlers.toArray(encodedCatchHandlersArray); 138 } 139 140 CodeItem codeItem = new CodeItem(dexFile, registerCount, inWords, outWords, debugInfo, encodedInstructions, 141 referencedItemsArray, triesArray, encodedCatchHandlersArray); 142 return dexFile.CodeItemsSection.intern(codeItem); 143 } 144 145 /** {@inheritDoc} */ 146 protected void readItem(Input in, ReadContext readContext) { 147 this.registerCount = in.readShort(); 148 this.inWords = in.readShort(); 149 this.outWords = in.readShort(); 150 int triesCount = in.readShort(); 151 this.debugInfo = (DebugInfoItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_DEBUG_INFO_ITEM, 152 in.readInt()); 153 if (this.debugInfo != null) { 154 this.debugInfo.setParent(this); 155 } 156 int instructionCount = in.readInt(); 157 this.encodedInstructions = in.readBytes(instructionCount * 2); 158 this.referencedItems = InstructionReader.getReferencedItems(encodedInstructions, dexFile); 159 if (triesCount > 0) { 160 in.alignTo(4); 161 162 //we need to read in the catch handlers first, so save the offset to the try items for future reference 163 int triesOffset = in.getCursor(); 164 in.setCursor(triesOffset + 8 * triesCount); 165 166 //read in the encoded catch handlers 167 int encodedHandlerStart = in.getCursor(); 168 int handlerCount = in.readUnsignedLeb128(); 169 SparseArray<EncodedCatchHandler> handlerMap = new SparseArray<EncodedCatchHandler>(handlerCount); 170 encodedCatchHandlers = new EncodedCatchHandler[handlerCount]; 171 for (int i=0; i<handlerCount; i++) { 172 int position = in.getCursor() - encodedHandlerStart; 173 encodedCatchHandlers[i] = new EncodedCatchHandler(dexFile, in); 174 handlerMap.append(position, encodedCatchHandlers[i]); 175 } 176 int codeItemEnd = in.getCursor(); 177 178 //now go back and read the tries 179 in.setCursor(triesOffset); 180 tries = new TryItem[triesCount]; 181 for (int i=0; i<triesCount; i++) { 182 tries[i] = new TryItem(in, handlerMap); 183 } 184 185 //and now back to the end of the code item 186 in.setCursor(codeItemEnd); 187 } 188 } 189 190 /** {@inheritDoc} */ 191 protected int placeItem(int offset) { 192 offset += 16 + encodedInstructions.length; 193 if (tries != null && tries.length > 0) { 194 if (encodedInstructions.length % 4 != 0) { 195 offset+=2; 196 } 197 198 offset += tries.length * 8; 199 int encodedCatchHandlerBaseOffset = offset; 200 offset += Leb128Utils.unsignedLeb128Size(encodedCatchHandlers.length); 201 for (EncodedCatchHandler encodedCatchHandler: encodedCatchHandlers) { 202 offset = encodedCatchHandler.place(offset, encodedCatchHandlerBaseOffset); 203 } 204 } 205 return offset; 206 } 207 208 /** {@inheritDoc} */ 209 protected void writeItem(final AnnotatedOutput out) { 210 if (out.annotates()) { 211 out.annotate(0, parent.method.getMethodString()); 212 out.annotate(2, "registers_size: 0x" + Integer.toHexString(registerCount) + " (" + registerCount + ")"); 213 out.annotate(2, "ins_size: 0x" + Integer.toHexString(inWords) + " (" + inWords + ")"); 214 out.annotate(2, "outs_size: 0x" + Integer.toHexString(outWords) + " (" + outWords + ")"); 215 int triesLength = tries==null?0:tries.length; 216 out.annotate(2, "tries_size: 0x" + Integer.toHexString(triesLength) + " (" + triesLength + ")"); 217 if (debugInfo == null) { 218 out.annotate(4, "debug_info_off:"); 219 } else { 220 out.annotate(4, "debug_info_off: 0x" + debugInfo.getOffset()); 221 } 222 out.annotate(4, "insns_size: 0x" + Integer.toHexString(encodedInstructions.length / 2) + " (" + 223 (encodedInstructions.length / 2) + ")"); 224 InstructionIterator.IterateInstructions(encodedInstructions, 225 new InstructionIterator.ProcessRawInstructionDelegate() { 226 227 public void ProcessNormalInstruction(Opcode opcode, int index) { 228 out.annotate(opcode.format.size, "[0x" + Integer.toHexString(index/2) + "] " + opcode.name + 229 " instruction"); 230 } 231 232 public void ProcessReferenceInstruction(Opcode opcode, int index) { 233 out.annotate(opcode.format.size, "[0x" + Integer.toHexString(index/2) + "] " + opcode.name + 234 " instruction"); 235 } 236 237 public void ProcessPackedSwitchInstruction(int index, int targetCount, int instructionLength) { 238 out.annotate(instructionLength, "[0x" + Integer.toHexString(index/2) + "] " + 239 "packed_switch instruction"); 240 } 241 242 public void ProcessSparseSwitchInstruction(int index, int targetCount, int instructionLength) { 243 out.annotate(instructionLength, "[0x" + Integer.toHexString(index/2) + "] " + 244 "sparse_switch instruction"); 245 } 246 247 public void ProcessFillArrayDataInstruction(int index, int elementWidth, int elementCount, 248 int instructionLength) { 249 out.annotate(instructionLength, "[0x" + Integer.toHexString(index/2) + "] " + 250 "fill_array_data instruction"); 251 } 252 }); 253 } 254 255 out.writeShort(registerCount); 256 out.writeShort(inWords); 257 out.writeShort(outWords); 258 if (tries == null) { 259 out.writeShort(0); 260 } else { 261 out.writeShort(tries.length); 262 } 263 if (debugInfo == null) { 264 out.writeInt(0); 265 } else { 266 out.writeInt(debugInfo.getOffset()); 267 } 268 out.writeInt(encodedInstructions.length / 2); 269 InstructionWriter.writeInstructions(encodedInstructions, referencedItems, out); 270 271 if (tries != null && tries.length > 0) { 272 if (out.annotates()) { 273 if ((encodedInstructions.length % 4) != 0) { 274 out.annotate("padding"); 275 out.writeShort(0); 276 } 277 278 int index = 0; 279 for (TryItem tryItem: tries) { 280 out.annotate(0, "[0x" + Integer.toHexString(index++) + "] try_item"); 281 out.indent(); 282 tryItem.writeTo(out); 283 out.deindent(); 284 } 285 286 out.annotate("handler_count: 0x" + Integer.toHexString(encodedCatchHandlers.length) + "(" + 287 encodedCatchHandlers.length + ")"); 288 out.writeUnsignedLeb128(encodedCatchHandlers.length); 289 290 index = 0; 291 for (EncodedCatchHandler encodedCatchHandler: encodedCatchHandlers) { 292 out.annotate(0, "[" + Integer.toHexString(index++) + "] encoded_catch_handler"); 293 out.indent(); 294 encodedCatchHandler.writeTo(out); 295 out.deindent(); 296 } 297 } else { 298 if ((encodedInstructions.length % 4) != 0) { 299 out.writeShort(0); 300 } 301 302 for (TryItem tryItem: tries) { 303 tryItem.writeTo(out); 304 } 305 306 out.writeUnsignedLeb128(encodedCatchHandlers.length); 307 308 for (EncodedCatchHandler encodedCatchHandler: encodedCatchHandlers) { 309 encodedCatchHandler.writeTo(out); 310 } 311 } 312 } 313 } 314 315 /** {@inheritDoc} */ 316 public ItemType getItemType() { 317 return ItemType.TYPE_CODE_ITEM; 318 } 319 320 /** {@inheritDoc} */ 321 public String getConciseIdentity() { 322 //TODO: should mention the method name here 323 return "code_item @0x" + Integer.toHexString(getOffset()); 324 } 325 326 /** {@inheritDoc} */ 327 public int compareTo(CodeItem other) { 328 if (parent == null) { 329 if (other.parent == null) { 330 return 0; 331 } 332 return -1; 333 } 334 if (other.parent == null) { 335 return 1; 336 } 337 return parent.method.compareTo(other.parent.method); 338 } 339 340 /** 341 * @return the register count 342 */ 343 public int getRegisterCount() { 344 return registerCount; 345 } 346 347 /** 348 * @return a byte array containing the encoded instructions 349 */ 350 public byte[] getEncodedInstructions() { 351 return encodedInstructions; 352 } 353 354 /** 355 * @return an array of the <code>TryItem</code> objects in this <code>CodeItem</code> 356 */ 357 public TryItem[] getTries() { 358 return tries; 359 } 360 361 /** 362 * @return the <code>DebugInfoItem</code> associated with this <code>CodeItem</code> 363 */ 364 public DebugInfoItem getDebugInfo() { 365 return debugInfo; 366 } 367 368 /** 369 * Sets the <code>MethodIdItem</code> of the method that this <code>CodeItem</code> is associated with 370 * @param encodedMethod the <code>EncodedMethod</code> of the method that this <code>CodeItem</code> is associated 371 * with 372 */ 373 protected void setParent(ClassDataItem.EncodedMethod encodedMethod) { 374 this.parent = encodedMethod; 375 } 376 377 /** 378 * @return the MethodIdItem of the method that this CodeItem belongs to 379 */ 380 public ClassDataItem.EncodedMethod getParent() { 381 return parent; 382 } 383 384 public static class TryItem { 385 /** 386 * The address (in 2-byte words) within the code where the try block starts 387 */ 388 public final int startAddress; 389 390 /** 391 * The number of 2-byte words that the try block covers 392 */ 393 public final int instructionCount; 394 395 /** 396 * The associated exception handler 397 */ 398 public final EncodedCatchHandler encodedCatchHandler; 399 400 /** 401 * Construct a new <code>TryItem</code> with the given values 402 * @param startAddress the address (in 2-byte words) within the code where the try block starts 403 * @param instructionCount the number of 2-byte words that the try block covers 404 * @param encodedCatchHandler the associated exception handler 405 */ 406 public TryItem(int startAddress, int instructionCount, EncodedCatchHandler encodedCatchHandler) { 407 this.startAddress = startAddress; 408 this.instructionCount = instructionCount; 409 this.encodedCatchHandler = encodedCatchHandler; 410 } 411 412 /** 413 * This is used internally to construct a new <code>TryItem</code> while reading in a <code>DexFile</code> 414 * @param in the Input object to read the <code>TryItem</code> from 415 * @param encodedCatchHandlers a SparseArray of the EncodedCatchHandlers for this <code>CodeItem</code>. The 416 * key should be the offset of the EncodedCatchHandler from the beginning of the encoded_catch_handler_list 417 * structure. 418 */ 419 private TryItem(Input in, SparseArray<EncodedCatchHandler> encodedCatchHandlers) { 420 startAddress = in.readInt(); 421 instructionCount = in.readShort(); 422 423 encodedCatchHandler = encodedCatchHandlers.get(in.readShort()); 424 if (encodedCatchHandler == null) { 425 throw new RuntimeException("Could not find the EncodedCatchHandler referenced by this TryItem"); 426 } 427 } 428 429 /** 430 * Writes the <code>TryItem</code> to the given <code>AnnotatedOutput</code> object 431 * @param out the <code>AnnotatedOutput</code> object to write to 432 */ 433 private void writeTo(AnnotatedOutput out) { 434 if (out.annotates()) { 435 out.annotate(4, "start_addr: 0x" + Integer.toHexString(startAddress)); 436 out.annotate(2, "insn_count: 0x" + Integer.toHexString(instructionCount) + " (" + instructionCount + 437 ")"); 438 out.annotate(2, "handler_off: 0x" + Integer.toHexString(encodedCatchHandler.getOffsetInList())); 439 } 440 441 out.writeInt(startAddress); 442 out.writeShort(instructionCount); 443 out.writeShort(encodedCatchHandler.getOffsetInList()); 444 } 445 } 446 447 public static class EncodedCatchHandler { 448 /** 449 * An array of the individual exception handlers 450 */ 451 public final EncodedTypeAddrPair[] handlers; 452 453 /** 454 * The address within the code (in 2-byte words) for the catch all handler, or -1 if there is no catch all 455 * handler 456 */ 457 public final int catchAllHandlerAddress; 458 459 //TODO: would it be possible to get away without having these? and generate/create these values while writing? 460 private int baseOffset; 461 private int offset; 462 463 /** 464 * Constructs a new <code>EncodedCatchHandler</code> with the given values 465 * @param handlers an array of the individual exception handlers 466 * @param catchAllHandlerAddress The address within the code (in 2-byte words) for the catch all handler, or -1 467 * if there is no catch all handler 468 */ 469 public EncodedCatchHandler(EncodedTypeAddrPair[] handlers, int catchAllHandlerAddress) { 470 this.handlers = handlers; 471 this.catchAllHandlerAddress = catchAllHandlerAddress; 472 } 473 474 /** 475 * This is used internally to construct a new <code>EncodedCatchHandler</code> while reading in a 476 * <code>DexFile</code> 477 * @param dexFile the <code>DexFile</code> that is being read in 478 * @param in the Input object to read the <code>EncodedCatchHandler</code> from 479 */ 480 private EncodedCatchHandler(DexFile dexFile, Input in) { 481 int handlerCount = in.readSignedLeb128(); 482 483 if (handlerCount < 0) { 484 handlers = new EncodedTypeAddrPair[-1 * handlerCount]; 485 } else { 486 handlers = new EncodedTypeAddrPair[handlerCount]; 487 } 488 489 for (int i=0; i<handlers.length; i++) { 490 handlers[i] = new EncodedTypeAddrPair(dexFile, in); 491 } 492 493 if (handlerCount <= 0) { 494 catchAllHandlerAddress = in.readUnsignedLeb128(); 495 } else { 496 catchAllHandlerAddress = -1; 497 } 498 } 499 500 /** 501 * @return the offset of this <code>EncodedCatchHandler</code> from the beginning of the 502 * encoded_catch_handler_list structure 503 */ 504 private int getOffsetInList() { 505 return offset-baseOffset; 506 } 507 508 /** 509 * Places the <code>EncodedCatchHandler</code>, storing the offset and baseOffset, and returning the offset 510 * immediately following this <code>EncodedCatchHandler</code> 511 * @param offset the offset of this <code>EncodedCatchHandler</code> in the <code>DexFile</code> 512 * @param baseOffset the offset of the beginning of the encoded_catch_handler_list structure in the 513 * <code>DexFile</code> 514 * @return the offset immediately following this <code>EncodedCatchHandler</code> 515 */ 516 private int place(int offset, int baseOffset) { 517 this.offset = offset; 518 this.baseOffset = baseOffset; 519 520 int size = handlers.length; 521 if (catchAllHandlerAddress > -1) { 522 size *= -1; 523 offset += Leb128Utils.unsignedLeb128Size(catchAllHandlerAddress); 524 } 525 offset += Leb128Utils.signedLeb128Size(size); 526 527 for (EncodedTypeAddrPair handler: handlers) { 528 offset += handler.getSize(); 529 } 530 return offset; 531 } 532 533 /** 534 * Writes the <code>EncodedCatchHandler</code> to the given <code>AnnotatedOutput</code> object 535 * @param out the <code>AnnotatedOutput</code> object to write to 536 */ 537 private void writeTo(AnnotatedOutput out) { 538 if (out.annotates()) { 539 out.annotate("size: 0x" + Integer.toHexString(handlers.length) + " (" + handlers.length + ")"); 540 541 int size = handlers.length; 542 if (catchAllHandlerAddress > -1) { 543 size = size * -1; 544 } 545 out.writeSignedLeb128(size); 546 547 int index = 0; 548 for (EncodedTypeAddrPair handler: handlers) { 549 out.annotate(0, "[" + index++ + "] encoded_type_addr_pair"); 550 out.indent(); 551 handler.writeTo(out); 552 out.deindent(); 553 } 554 555 if (catchAllHandlerAddress > -1) { 556 out.annotate("catch_all_addr: 0x" + Integer.toHexString(catchAllHandlerAddress)); 557 out.writeUnsignedLeb128(catchAllHandlerAddress); 558 } 559 } else { 560 int size = handlers.length; 561 if (catchAllHandlerAddress > -1) { 562 size = size * -1; 563 } 564 out.writeSignedLeb128(size); 565 566 for (EncodedTypeAddrPair handler: handlers) { 567 handler.writeTo(out); 568 } 569 570 if (catchAllHandlerAddress > -1) { 571 out.writeUnsignedLeb128(catchAllHandlerAddress); 572 } 573 } 574 } 575 576 @Override 577 public int hashCode() { 578 int hash = 0; 579 for (EncodedTypeAddrPair handler: handlers) { 580 hash = hash * 31 + handler.hashCode(); 581 } 582 hash = hash * 31 + catchAllHandlerAddress; 583 return hash; 584 } 585 586 @Override 587 public boolean equals(Object o) { 588 if (this==o) { 589 return true; 590 } 591 if (o==null || !this.getClass().equals(o.getClass())) { 592 return false; 593 } 594 595 EncodedCatchHandler other = (EncodedCatchHandler)o; 596 if (handlers.length != other.handlers.length || catchAllHandlerAddress != other.catchAllHandlerAddress) { 597 return false; 598 } 599 600 for (int i=0; i<handlers.length; i++) { 601 if (!handlers[i].equals(other.handlers[i])) { 602 return false; 603 } 604 } 605 606 return true; 607 } 608 } 609 610 public static class EncodedTypeAddrPair { 611 /** 612 * The type of the <code>Exception</code> that this handler handles 613 */ 614 public final TypeIdItem exceptionType; 615 616 /** 617 * The address (in 2-byte words) in the code of the handler 618 */ 619 public final int handlerAddress; 620 621 /** 622 * Constructs a new <code>EncodedTypeAddrPair</code> with the given values 623 * @param exceptionType the type of the <code>Exception</code> that this handler handles 624 * @param handlerAddress the address (in 2-byte words) in the code of the handler 625 */ 626 public EncodedTypeAddrPair(TypeIdItem exceptionType, int handlerAddress) { 627 this.exceptionType = exceptionType; 628 this.handlerAddress = handlerAddress; 629 } 630 631 /** 632 * This is used internally to construct a new <code>EncodedTypeAddrPair</code> while reading in a 633 * <code>DexFile</code> 634 * @param dexFile the <code>DexFile</code> that is being read in 635 * @param in the Input object to read the <code>EncodedCatchHandler</code> from 636 */ 637 private EncodedTypeAddrPair(DexFile dexFile, Input in) { 638 exceptionType = dexFile.TypeIdsSection.getItemByIndex(in.readUnsignedLeb128()); 639 handlerAddress = in.readUnsignedLeb128(); 640 } 641 642 /** 643 * @return the size of this <code>EncodedTypeAddrPair</code> 644 */ 645 private int getSize() { 646 return Leb128Utils.unsignedLeb128Size(exceptionType.getIndex()) + 647 Leb128Utils.unsignedLeb128Size(handlerAddress); 648 } 649 650 /** 651 * Writes the <code>EncodedTypeAddrPair</code> to the given <code>AnnotatedOutput</code> object 652 * @param out the <code>AnnotatedOutput</code> object to write to 653 */ 654 private void writeTo(AnnotatedOutput out) { 655 if (out.annotates()) { 656 out.annotate("exception_type: " + exceptionType.getTypeDescriptor()); 657 out.writeUnsignedLeb128(exceptionType.getIndex()); 658 659 out.annotate("handler_addr: 0x" + Integer.toHexString(handlerAddress)); 660 out.writeUnsignedLeb128(handlerAddress); 661 } else { 662 out.writeUnsignedLeb128(exceptionType.getIndex()); 663 out.writeUnsignedLeb128(handlerAddress); 664 } 665 } 666 667 @Override 668 public int hashCode() { 669 return exceptionType.hashCode() * 31 + handlerAddress; 670 } 671 672 @Override 673 public boolean equals(Object o) { 674 if (this==o) { 675 return true; 676 } 677 if (o==null || !this.getClass().equals(o.getClass())) { 678 return false; 679 } 680 681 EncodedTypeAddrPair other = (EncodedTypeAddrPair)o; 682 return exceptionType == other.exceptionType && handlerAddress == other.handlerAddress; 683 } 684 } 685} 686