1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.dx.cf.direct; 18 19 import com.android.dx.cf.attrib.AttAnnotationDefault; 20 import com.android.dx.cf.attrib.AttBootstrapMethods; 21 import com.android.dx.cf.attrib.AttCode; 22 import com.android.dx.cf.attrib.AttConstantValue; 23 import com.android.dx.cf.attrib.AttDeprecated; 24 import com.android.dx.cf.attrib.AttEnclosingMethod; 25 import com.android.dx.cf.attrib.AttExceptions; 26 import com.android.dx.cf.attrib.AttInnerClasses; 27 import com.android.dx.cf.attrib.AttLineNumberTable; 28 import com.android.dx.cf.attrib.AttLocalVariableTable; 29 import com.android.dx.cf.attrib.AttLocalVariableTypeTable; 30 import com.android.dx.cf.attrib.AttRuntimeInvisibleAnnotations; 31 import com.android.dx.cf.attrib.AttRuntimeInvisibleParameterAnnotations; 32 import com.android.dx.cf.attrib.AttRuntimeVisibleAnnotations; 33 import com.android.dx.cf.attrib.AttRuntimeVisibleParameterAnnotations; 34 import com.android.dx.cf.attrib.AttSignature; 35 import com.android.dx.cf.attrib.AttSourceDebugExtension; 36 import com.android.dx.cf.attrib.AttSourceFile; 37 import com.android.dx.cf.attrib.AttSynthetic; 38 import com.android.dx.cf.attrib.InnerClassList; 39 import com.android.dx.cf.code.BootstrapMethodArgumentsList; 40 import com.android.dx.cf.code.BootstrapMethodsList; 41 import com.android.dx.cf.code.ByteCatchList; 42 import com.android.dx.cf.code.BytecodeArray; 43 import com.android.dx.cf.code.LineNumberList; 44 import com.android.dx.cf.code.LocalVariableList; 45 import com.android.dx.cf.iface.Attribute; 46 import com.android.dx.cf.iface.ParseException; 47 import com.android.dx.cf.iface.ParseObserver; 48 import com.android.dx.cf.iface.StdAttributeList; 49 import com.android.dx.rop.annotation.AnnotationVisibility; 50 import com.android.dx.rop.annotation.Annotations; 51 import com.android.dx.rop.annotation.AnnotationsList; 52 import com.android.dx.rop.code.AccessFlags; 53 import com.android.dx.rop.cst.Constant; 54 import com.android.dx.rop.cst.ConstantPool; 55 import com.android.dx.rop.cst.CstMethodHandle; 56 import com.android.dx.rop.cst.CstNat; 57 import com.android.dx.rop.cst.CstString; 58 import com.android.dx.rop.cst.CstType; 59 import com.android.dx.rop.cst.TypedConstant; 60 import com.android.dx.rop.type.TypeList; 61 import com.android.dx.util.ByteArray; 62 import com.android.dx.util.Hex; 63 import java.io.IOException; 64 65 /** 66 * Standard subclass of {@link AttributeFactory}, which knows how to parse 67 * all the standard attribute types. 68 */ 69 public class StdAttributeFactory 70 extends AttributeFactory { 71 /** {@code non-null;} shared instance of this class */ 72 public static final StdAttributeFactory THE_ONE = 73 new StdAttributeFactory(); 74 75 /** 76 * Constructs an instance. 77 */ StdAttributeFactory()78 public StdAttributeFactory() { 79 // This space intentionally left blank. 80 } 81 82 /** {@inheritDoc} */ 83 @Override parse0(DirectClassFile cf, int context, String name, int offset, int length, ParseObserver observer)84 protected Attribute parse0(DirectClassFile cf, int context, String name, 85 int offset, int length, ParseObserver observer) { 86 switch (context) { 87 case CTX_CLASS: { 88 if (name == AttBootstrapMethods.ATTRIBUTE_NAME) { 89 return bootstrapMethods(cf, offset, length, observer); 90 } 91 if (name == AttDeprecated.ATTRIBUTE_NAME) { 92 return deprecated(cf, offset, length, observer); 93 } 94 if (name == AttEnclosingMethod.ATTRIBUTE_NAME) { 95 return enclosingMethod(cf, offset, length, observer); 96 } 97 if (name == AttInnerClasses.ATTRIBUTE_NAME) { 98 return innerClasses(cf, offset, length, observer); 99 } 100 if (name == AttRuntimeInvisibleAnnotations.ATTRIBUTE_NAME) { 101 return runtimeInvisibleAnnotations(cf, offset, length, 102 observer); 103 } 104 if (name == AttRuntimeVisibleAnnotations.ATTRIBUTE_NAME) { 105 return runtimeVisibleAnnotations(cf, offset, length, 106 observer); 107 } 108 if (name == AttSynthetic.ATTRIBUTE_NAME) { 109 return synthetic(cf, offset, length, observer); 110 } 111 if (name == AttSignature.ATTRIBUTE_NAME) { 112 return signature(cf, offset, length, observer); 113 } 114 if (name == AttSourceDebugExtension.ATTRIBUTE_NAME) { 115 return sourceDebugExtension(cf, offset, length, observer); 116 } 117 if (name == AttSourceFile.ATTRIBUTE_NAME) { 118 return sourceFile(cf, offset, length, observer); 119 } 120 break; 121 } 122 case CTX_FIELD: { 123 if (name == AttConstantValue.ATTRIBUTE_NAME) { 124 return constantValue(cf, offset, length, observer); 125 } 126 if (name == AttDeprecated.ATTRIBUTE_NAME) { 127 return deprecated(cf, offset, length, observer); 128 } 129 if (name == AttRuntimeInvisibleAnnotations.ATTRIBUTE_NAME) { 130 return runtimeInvisibleAnnotations(cf, offset, length, 131 observer); 132 } 133 if (name == AttRuntimeVisibleAnnotations.ATTRIBUTE_NAME) { 134 return runtimeVisibleAnnotations(cf, offset, length, 135 observer); 136 } 137 if (name == AttSignature.ATTRIBUTE_NAME) { 138 return signature(cf, offset, length, observer); 139 } 140 if (name == AttSynthetic.ATTRIBUTE_NAME) { 141 return synthetic(cf, offset, length, observer); 142 } 143 break; 144 } 145 case CTX_METHOD: { 146 if (name == AttAnnotationDefault.ATTRIBUTE_NAME) { 147 return annotationDefault(cf, offset, length, observer); 148 } 149 if (name == AttCode.ATTRIBUTE_NAME) { 150 return code(cf, offset, length, observer); 151 } 152 if (name == AttDeprecated.ATTRIBUTE_NAME) { 153 return deprecated(cf, offset, length, observer); 154 } 155 if (name == AttExceptions.ATTRIBUTE_NAME) { 156 return exceptions(cf, offset, length, observer); 157 } 158 if (name == AttRuntimeInvisibleAnnotations.ATTRIBUTE_NAME) { 159 return runtimeInvisibleAnnotations(cf, offset, length, 160 observer); 161 } 162 if (name == AttRuntimeVisibleAnnotations.ATTRIBUTE_NAME) { 163 return runtimeVisibleAnnotations(cf, offset, length, 164 observer); 165 } 166 if (name == AttRuntimeInvisibleParameterAnnotations. 167 ATTRIBUTE_NAME) { 168 return runtimeInvisibleParameterAnnotations( 169 cf, offset, length, observer); 170 } 171 if (name == AttRuntimeVisibleParameterAnnotations. 172 ATTRIBUTE_NAME) { 173 return runtimeVisibleParameterAnnotations( 174 cf, offset, length, observer); 175 } 176 if (name == AttSignature.ATTRIBUTE_NAME) { 177 return signature(cf, offset, length, observer); 178 } 179 if (name == AttSynthetic.ATTRIBUTE_NAME) { 180 return synthetic(cf, offset, length, observer); 181 } 182 break; 183 } 184 case CTX_CODE: { 185 if (name == AttLineNumberTable.ATTRIBUTE_NAME) { 186 return lineNumberTable(cf, offset, length, observer); 187 } 188 if (name == AttLocalVariableTable.ATTRIBUTE_NAME) { 189 return localVariableTable(cf, offset, length, observer); 190 } 191 if (name == AttLocalVariableTypeTable.ATTRIBUTE_NAME) { 192 return localVariableTypeTable(cf, offset, length, 193 observer); 194 } 195 break; 196 } 197 } 198 199 return super.parse0(cf, context, name, offset, length, observer); 200 } 201 202 /** 203 * Parses an {@code AnnotationDefault} attribute. 204 */ annotationDefault(DirectClassFile cf, int offset, int length, ParseObserver observer)205 private Attribute annotationDefault(DirectClassFile cf, 206 int offset, int length, ParseObserver observer) { 207 if (length < 2) { 208 throwSeverelyTruncated(); 209 } 210 211 AnnotationParser ap = 212 new AnnotationParser(cf, offset, length, observer); 213 Constant cst = ap.parseValueAttribute(); 214 215 return new AttAnnotationDefault(cst, length); 216 } 217 218 /** 219 * Parses a {@code BootstrapMethods} attribute. 220 */ bootstrapMethods(DirectClassFile cf, int offset, int length, ParseObserver observer)221 private Attribute bootstrapMethods(DirectClassFile cf, int offset, int length, 222 ParseObserver observer) { 223 if (length < 2) { 224 return throwSeverelyTruncated(); 225 } 226 227 ByteArray bytes = cf.getBytes(); 228 int numMethods = bytes.getUnsignedShort(offset); 229 if (observer != null) { 230 observer.parsed(bytes, offset, 2, 231 "num_boostrap_methods: " + Hex.u2(numMethods)); 232 } 233 234 offset += 2; 235 length -= 2; 236 237 BootstrapMethodsList methods = parseBootstrapMethods(bytes, cf.getConstantPool(), 238 cf.getThisClass(), numMethods, 239 offset, length, observer); 240 return new AttBootstrapMethods(methods); 241 } 242 243 /** 244 * Parses a {@code Code} attribute. 245 */ code(DirectClassFile cf, int offset, int length, ParseObserver observer)246 private Attribute code(DirectClassFile cf, int offset, int length, 247 ParseObserver observer) { 248 if (length < 12) { 249 return throwSeverelyTruncated(); 250 } 251 252 ByteArray bytes = cf.getBytes(); 253 ConstantPool pool = cf.getConstantPool(); 254 int maxStack = bytes.getUnsignedShort(offset); // u2 max_stack 255 int maxLocals = bytes.getUnsignedShort(offset + 2); // u2 max_locals 256 int codeLength = bytes.getInt(offset + 4); // u4 code_length 257 int origOffset = offset; 258 259 if (observer != null) { 260 observer.parsed(bytes, offset, 2, 261 "max_stack: " + Hex.u2(maxStack)); 262 observer.parsed(bytes, offset + 2, 2, 263 "max_locals: " + Hex.u2(maxLocals)); 264 observer.parsed(bytes, offset + 4, 4, 265 "code_length: " + Hex.u4(codeLength)); 266 } 267 268 offset += 8; 269 length -= 8; 270 271 if (length < (codeLength + 4)) { 272 return throwTruncated(); 273 } 274 275 int codeOffset = offset; 276 offset += codeLength; 277 length -= codeLength; 278 BytecodeArray code = 279 new BytecodeArray(bytes.slice(codeOffset, codeOffset + codeLength), 280 pool); 281 if (observer != null) { 282 code.forEach(new CodeObserver(code.getBytes(), observer)); 283 } 284 285 // u2 exception_table_length 286 int exceptionTableLength = bytes.getUnsignedShort(offset); 287 ByteCatchList catches = (exceptionTableLength == 0) ? 288 ByteCatchList.EMPTY : 289 new ByteCatchList(exceptionTableLength); 290 291 if (observer != null) { 292 observer.parsed(bytes, offset, 2, 293 "exception_table_length: " + 294 Hex.u2(exceptionTableLength)); 295 } 296 297 offset += 2; 298 length -= 2; 299 300 if (length < (exceptionTableLength * 8 + 2)) { 301 return throwTruncated(); 302 } 303 304 for (int i = 0; i < exceptionTableLength; i++) { 305 if (observer != null) { 306 observer.changeIndent(1); 307 } 308 309 int startPc = bytes.getUnsignedShort(offset); 310 int endPc = bytes.getUnsignedShort(offset + 2); 311 int handlerPc = bytes.getUnsignedShort(offset + 4); 312 int catchTypeIdx = bytes.getUnsignedShort(offset + 6); 313 CstType catchType = (CstType) pool.get0Ok(catchTypeIdx); 314 catches.set(i, startPc, endPc, handlerPc, catchType); 315 if (observer != null) { 316 observer.parsed(bytes, offset, 8, 317 Hex.u2(startPc) + ".." + Hex.u2(endPc) + 318 " -> " + Hex.u2(handlerPc) + " " + 319 ((catchType == null) ? "<any>" : 320 catchType.toHuman())); 321 } 322 offset += 8; 323 length -= 8; 324 325 if (observer != null) { 326 observer.changeIndent(-1); 327 } 328 } 329 330 catches.setImmutable(); 331 332 AttributeListParser parser = 333 new AttributeListParser(cf, CTX_CODE, offset, this); 334 parser.setObserver(observer); 335 336 StdAttributeList attributes = parser.getList(); 337 attributes.setImmutable(); 338 339 int attributeByteCount = parser.getEndOffset() - offset; 340 if (attributeByteCount != length) { 341 return throwBadLength(attributeByteCount + (offset - origOffset)); 342 } 343 344 return new AttCode(maxStack, maxLocals, code, catches, attributes); 345 } 346 347 /** 348 * Parses a {@code ConstantValue} attribute. 349 */ constantValue(DirectClassFile cf, int offset, int length, ParseObserver observer)350 private Attribute constantValue(DirectClassFile cf, int offset, int length, 351 ParseObserver observer) { 352 if (length != 2) { 353 return throwBadLength(2); 354 } 355 356 ByteArray bytes = cf.getBytes(); 357 ConstantPool pool = cf.getConstantPool(); 358 int idx = bytes.getUnsignedShort(offset); 359 TypedConstant cst = (TypedConstant) pool.get(idx); 360 Attribute result = new AttConstantValue(cst); 361 362 if (observer != null) { 363 observer.parsed(bytes, offset, 2, "value: " + cst); 364 } 365 366 return result; 367 } 368 369 /** 370 * Parses a {@code Deprecated} attribute. 371 */ deprecated(DirectClassFile cf, int offset, int length, ParseObserver observer)372 private Attribute deprecated(DirectClassFile cf, int offset, int length, 373 ParseObserver observer) { 374 if (length != 0) { 375 return throwBadLength(0); 376 } 377 378 return new AttDeprecated(); 379 } 380 381 /** 382 * Parses an {@code EnclosingMethod} attribute. 383 */ enclosingMethod(DirectClassFile cf, int offset, int length, ParseObserver observer)384 private Attribute enclosingMethod(DirectClassFile cf, int offset, 385 int length, ParseObserver observer) { 386 if (length != 4) { 387 throwBadLength(4); 388 } 389 390 ByteArray bytes = cf.getBytes(); 391 ConstantPool pool = cf.getConstantPool(); 392 393 int idx = bytes.getUnsignedShort(offset); 394 CstType type = (CstType) pool.get(idx); 395 396 idx = bytes.getUnsignedShort(offset + 2); 397 CstNat method = (CstNat) pool.get0Ok(idx); 398 399 Attribute result = new AttEnclosingMethod(type, method); 400 401 if (observer != null) { 402 observer.parsed(bytes, offset, 2, "class: " + type); 403 observer.parsed(bytes, offset + 2, 2, "method: " + 404 DirectClassFile.stringOrNone(method)); 405 } 406 407 return result; 408 } 409 410 /** 411 * Parses an {@code Exceptions} attribute. 412 */ exceptions(DirectClassFile cf, int offset, int length, ParseObserver observer)413 private Attribute exceptions(DirectClassFile cf, int offset, int length, 414 ParseObserver observer) { 415 if (length < 2) { 416 return throwSeverelyTruncated(); 417 } 418 419 ByteArray bytes = cf.getBytes(); 420 int count = bytes.getUnsignedShort(offset); // number_of_exceptions 421 422 if (observer != null) { 423 observer.parsed(bytes, offset, 2, 424 "number_of_exceptions: " + Hex.u2(count)); 425 } 426 427 offset += 2; 428 length -= 2; 429 430 if (length != (count * 2)) { 431 throwBadLength((count * 2) + 2); 432 } 433 434 TypeList list = cf.makeTypeList(offset, count); 435 return new AttExceptions(list); 436 } 437 438 /** 439 * Parses an {@code InnerClasses} attribute. 440 */ innerClasses(DirectClassFile cf, int offset, int length, ParseObserver observer)441 private Attribute innerClasses(DirectClassFile cf, int offset, int length, 442 ParseObserver observer) { 443 if (length < 2) { 444 return throwSeverelyTruncated(); 445 } 446 447 ByteArray bytes = cf.getBytes(); 448 ConstantPool pool = cf.getConstantPool(); 449 int count = bytes.getUnsignedShort(offset); // number_of_classes 450 451 if (observer != null) { 452 observer.parsed(bytes, offset, 2, 453 "number_of_classes: " + Hex.u2(count)); 454 } 455 456 offset += 2; 457 length -= 2; 458 459 if (length != (count * 8)) { 460 throwBadLength((count * 8) + 2); 461 } 462 463 InnerClassList list = new InnerClassList(count); 464 465 for (int i = 0; i < count; i++) { 466 int innerClassIdx = bytes.getUnsignedShort(offset); 467 int outerClassIdx = bytes.getUnsignedShort(offset + 2); 468 int nameIdx = bytes.getUnsignedShort(offset + 4); 469 int accessFlags = bytes.getUnsignedShort(offset + 6); 470 CstType innerClass = (CstType) pool.get(innerClassIdx); 471 CstType outerClass = (CstType) pool.get0Ok(outerClassIdx); 472 CstString name = (CstString) pool.get0Ok(nameIdx); 473 list.set(i, innerClass, outerClass, name, accessFlags); 474 if (observer != null) { 475 observer.parsed(bytes, offset, 2, 476 "inner_class: " + 477 DirectClassFile.stringOrNone(innerClass)); 478 observer.parsed(bytes, offset + 2, 2, 479 " outer_class: " + 480 DirectClassFile.stringOrNone(outerClass)); 481 observer.parsed(bytes, offset + 4, 2, 482 " name: " + 483 DirectClassFile.stringOrNone(name)); 484 observer.parsed(bytes, offset + 6, 2, 485 " access_flags: " + 486 AccessFlags.innerClassString(accessFlags)); 487 } 488 offset += 8; 489 } 490 491 list.setImmutable(); 492 return new AttInnerClasses(list); 493 } 494 495 /** 496 * Parses a {@code LineNumberTable} attribute. 497 */ lineNumberTable(DirectClassFile cf, int offset, int length, ParseObserver observer)498 private Attribute lineNumberTable(DirectClassFile cf, int offset, 499 int length, ParseObserver observer) { 500 if (length < 2) { 501 return throwSeverelyTruncated(); 502 } 503 504 ByteArray bytes = cf.getBytes(); 505 int count = bytes.getUnsignedShort(offset); // line_number_table_length 506 507 if (observer != null) { 508 observer.parsed(bytes, offset, 2, 509 "line_number_table_length: " + Hex.u2(count)); 510 } 511 512 offset += 2; 513 length -= 2; 514 515 if (length != (count * 4)) { 516 throwBadLength((count * 4) + 2); 517 } 518 519 LineNumberList list = new LineNumberList(count); 520 521 for (int i = 0; i < count; i++) { 522 int startPc = bytes.getUnsignedShort(offset); 523 int lineNumber = bytes.getUnsignedShort(offset + 2); 524 list.set(i, startPc, lineNumber); 525 if (observer != null) { 526 observer.parsed(bytes, offset, 4, 527 Hex.u2(startPc) + " " + lineNumber); 528 } 529 offset += 4; 530 } 531 532 list.setImmutable(); 533 return new AttLineNumberTable(list); 534 } 535 536 /** 537 * Parses a {@code LocalVariableTable} attribute. 538 */ localVariableTable(DirectClassFile cf, int offset, int length, ParseObserver observer)539 private Attribute localVariableTable(DirectClassFile cf, int offset, 540 int length, ParseObserver observer) { 541 if (length < 2) { 542 return throwSeverelyTruncated(); 543 } 544 545 ByteArray bytes = cf.getBytes(); 546 int count = bytes.getUnsignedShort(offset); 547 548 if (observer != null) { 549 observer.parsed(bytes, offset, 2, 550 "local_variable_table_length: " + Hex.u2(count)); 551 } 552 553 LocalVariableList list = parseLocalVariables( 554 bytes.slice(offset + 2, offset + length), cf.getConstantPool(), 555 observer, count, false); 556 return new AttLocalVariableTable(list); 557 } 558 559 /** 560 * Parses a {@code LocalVariableTypeTable} attribute. 561 */ localVariableTypeTable(DirectClassFile cf, int offset, int length, ParseObserver observer)562 private Attribute localVariableTypeTable(DirectClassFile cf, int offset, 563 int length, ParseObserver observer) { 564 if (length < 2) { 565 return throwSeverelyTruncated(); 566 } 567 568 ByteArray bytes = cf.getBytes(); 569 int count = bytes.getUnsignedShort(offset); 570 571 if (observer != null) { 572 observer.parsed(bytes, offset, 2, 573 "local_variable_type_table_length: " + Hex.u2(count)); 574 } 575 576 LocalVariableList list = parseLocalVariables( 577 bytes.slice(offset + 2, offset + length), cf.getConstantPool(), 578 observer, count, true); 579 return new AttLocalVariableTypeTable(list); 580 } 581 582 /** 583 * Parse the table part of either a {@code LocalVariableTable} 584 * or a {@code LocalVariableTypeTable}. 585 * 586 * @param bytes {@code non-null;} bytes to parse, which should <i>only</i> 587 * contain the table data (no header) 588 * @param pool {@code non-null;} constant pool to use 589 * @param count {@code >= 0;} the number of entries 590 * @param typeTable {@code true} iff this is for a type table 591 * @return {@code non-null;} the constructed list 592 */ parseLocalVariables(ByteArray bytes, ConstantPool pool, ParseObserver observer, int count, boolean typeTable)593 private LocalVariableList parseLocalVariables(ByteArray bytes, 594 ConstantPool pool, ParseObserver observer, int count, 595 boolean typeTable) { 596 if (bytes.size() != (count * 10)) { 597 // "+ 2" is for the count. 598 throwBadLength((count * 10) + 2); 599 } 600 601 ByteArray.MyDataInputStream in = bytes.makeDataInputStream(); 602 LocalVariableList list = new LocalVariableList(count); 603 604 try { 605 for (int i = 0; i < count; i++) { 606 int startPc = in.readUnsignedShort(); 607 int length = in.readUnsignedShort(); 608 int nameIdx = in.readUnsignedShort(); 609 int typeIdx = in.readUnsignedShort(); 610 int index = in.readUnsignedShort(); 611 CstString name = (CstString) pool.get(nameIdx); 612 CstString type = (CstString) pool.get(typeIdx); 613 CstString descriptor = null; 614 CstString signature = null; 615 616 if (typeTable) { 617 signature = type; 618 } else { 619 descriptor = type; 620 } 621 622 list.set(i, startPc, length, name, 623 descriptor, signature, index); 624 625 if (observer != null) { 626 observer.parsed(bytes, i * 10, 10, Hex.u2(startPc) + 627 ".." + Hex.u2(startPc + length) + " " + 628 Hex.u2(index) + " " + name.toHuman() + " " + 629 type.toHuman()); 630 } 631 } 632 } catch (IOException ex) { 633 throw new RuntimeException("shouldn't happen", ex); 634 } 635 636 list.setImmutable(); 637 return list; 638 } 639 640 /** 641 * Parses a {@code RuntimeInvisibleAnnotations} attribute. 642 */ runtimeInvisibleAnnotations(DirectClassFile cf, int offset, int length, ParseObserver observer)643 private Attribute runtimeInvisibleAnnotations(DirectClassFile cf, 644 int offset, int length, ParseObserver observer) { 645 if (length < 2) { 646 throwSeverelyTruncated(); 647 } 648 649 AnnotationParser ap = 650 new AnnotationParser(cf, offset, length, observer); 651 Annotations annotations = 652 ap.parseAnnotationAttribute(AnnotationVisibility.BUILD); 653 654 return new AttRuntimeInvisibleAnnotations(annotations, length); 655 } 656 657 /** 658 * Parses a {@code RuntimeVisibleAnnotations} attribute. 659 */ runtimeVisibleAnnotations(DirectClassFile cf, int offset, int length, ParseObserver observer)660 private Attribute runtimeVisibleAnnotations(DirectClassFile cf, 661 int offset, int length, ParseObserver observer) { 662 if (length < 2) { 663 throwSeverelyTruncated(); 664 } 665 666 AnnotationParser ap = 667 new AnnotationParser(cf, offset, length, observer); 668 Annotations annotations = 669 ap.parseAnnotationAttribute(AnnotationVisibility.RUNTIME); 670 671 return new AttRuntimeVisibleAnnotations(annotations, length); 672 } 673 674 /** 675 * Parses a {@code RuntimeInvisibleParameterAnnotations} attribute. 676 */ runtimeInvisibleParameterAnnotations(DirectClassFile cf, int offset, int length, ParseObserver observer)677 private Attribute runtimeInvisibleParameterAnnotations(DirectClassFile cf, 678 int offset, int length, ParseObserver observer) { 679 if (length < 2) { 680 throwSeverelyTruncated(); 681 } 682 683 AnnotationParser ap = 684 new AnnotationParser(cf, offset, length, observer); 685 AnnotationsList list = 686 ap.parseParameterAttribute(AnnotationVisibility.BUILD); 687 688 return new AttRuntimeInvisibleParameterAnnotations(list, length); 689 } 690 691 /** 692 * Parses a {@code RuntimeVisibleParameterAnnotations} attribute. 693 */ runtimeVisibleParameterAnnotations(DirectClassFile cf, int offset, int length, ParseObserver observer)694 private Attribute runtimeVisibleParameterAnnotations(DirectClassFile cf, 695 int offset, int length, ParseObserver observer) { 696 if (length < 2) { 697 throwSeverelyTruncated(); 698 } 699 700 AnnotationParser ap = 701 new AnnotationParser(cf, offset, length, observer); 702 AnnotationsList list = 703 ap.parseParameterAttribute(AnnotationVisibility.RUNTIME); 704 705 return new AttRuntimeVisibleParameterAnnotations(list, length); 706 } 707 708 /** 709 * Parses a {@code Signature} attribute. 710 */ signature(DirectClassFile cf, int offset, int length, ParseObserver observer)711 private Attribute signature(DirectClassFile cf, int offset, int length, 712 ParseObserver observer) { 713 if (length != 2) { 714 throwBadLength(2); 715 } 716 717 ByteArray bytes = cf.getBytes(); 718 ConstantPool pool = cf.getConstantPool(); 719 int idx = bytes.getUnsignedShort(offset); 720 CstString cst = (CstString) pool.get(idx); 721 Attribute result = new AttSignature(cst); 722 723 if (observer != null) { 724 observer.parsed(bytes, offset, 2, "signature: " + cst); 725 } 726 727 return result; 728 } 729 730 /** 731 * Parses a {@code SourceDebugExtesion} attribute. 732 */ sourceDebugExtension(DirectClassFile cf, int offset, int length, ParseObserver observer)733 private Attribute sourceDebugExtension(DirectClassFile cf, int offset, int length, 734 ParseObserver observer) { 735 ByteArray bytes = cf.getBytes().slice(offset, offset + length); 736 CstString smapString = new CstString(bytes); 737 Attribute result = new AttSourceDebugExtension(smapString); 738 739 if (observer != null) { 740 String decoded = smapString.getString(); 741 observer.parsed(bytes, offset, length, "sourceDebugExtension: " + decoded); 742 } 743 744 return result; 745 } 746 747 /** 748 * Parses a {@code SourceFile} attribute. 749 */ sourceFile(DirectClassFile cf, int offset, int length, ParseObserver observer)750 private Attribute sourceFile(DirectClassFile cf, int offset, int length, 751 ParseObserver observer) { 752 if (length != 2) { 753 throwBadLength(2); 754 } 755 756 ByteArray bytes = cf.getBytes(); 757 ConstantPool pool = cf.getConstantPool(); 758 int idx = bytes.getUnsignedShort(offset); 759 CstString cst = (CstString) pool.get(idx); 760 Attribute result = new AttSourceFile(cst); 761 762 if (observer != null) { 763 observer.parsed(bytes, offset, 2, "source: " + cst); 764 } 765 766 return result; 767 } 768 769 /** 770 * Parses a {@code Synthetic} attribute. 771 */ synthetic(DirectClassFile cf, int offset, int length, ParseObserver observer)772 private Attribute synthetic(DirectClassFile cf, int offset, int length, 773 ParseObserver observer) { 774 if (length != 0) { 775 return throwBadLength(0); 776 } 777 778 return new AttSynthetic(); 779 } 780 781 /** 782 * Throws the right exception when a known attribute has a way too short 783 * length. 784 * 785 * @return never 786 * @throws ParseException always thrown 787 */ throwSeverelyTruncated()788 private static Attribute throwSeverelyTruncated() { 789 throw new ParseException("severely truncated attribute"); 790 } 791 792 /** 793 * Throws the right exception when a known attribute has a too short 794 * length. 795 * 796 * @return never 797 * @throws ParseException always thrown 798 */ throwTruncated()799 private static Attribute throwTruncated() { 800 throw new ParseException("truncated attribute"); 801 } 802 803 /** 804 * Throws the right exception when an attribute has an unexpected length 805 * (given its contents). 806 * 807 * @param expected expected length 808 * @return never 809 * @throws ParseException always thrown 810 */ throwBadLength(int expected)811 private static Attribute throwBadLength(int expected) { 812 throw new ParseException("bad attribute length; expected length " + 813 Hex.u4(expected)); 814 } 815 parseBootstrapMethods(ByteArray bytes, ConstantPool constantPool, CstType declaringClass, int numMethods, int offset, int length, ParseObserver observer)816 private BootstrapMethodsList parseBootstrapMethods(ByteArray bytes, ConstantPool constantPool, 817 CstType declaringClass, int numMethods, int offset, int length, ParseObserver observer) 818 throws ParseException { 819 BootstrapMethodsList methods = new BootstrapMethodsList(numMethods); 820 for (int methodIndex = 0; methodIndex < numMethods; ++methodIndex) { 821 if (length < 4) { 822 throwTruncated(); 823 } 824 825 int methodRef = bytes.getUnsignedShort(offset); 826 int numArguments = bytes.getUnsignedShort(offset + 2); 827 828 if (observer != null) { 829 observer.parsed(bytes, offset, 2, "bootstrap_method_ref: " + Hex.u2(methodRef)); 830 observer.parsed(bytes, offset + 2, 2, 831 "num_bootstrap_arguments: " + Hex.u2(numArguments)); 832 } 833 834 offset += 4; 835 length -= 4; 836 if (length < numArguments * 2) { 837 throwTruncated(); 838 } 839 840 BootstrapMethodArgumentsList arguments = new BootstrapMethodArgumentsList(numArguments); 841 for (int argIndex = 0; argIndex < numArguments; ++argIndex, offset += 2, length -= 2) { 842 int argumentRef = bytes.getUnsignedShort(offset); 843 if (observer != null) { 844 observer.parsed(bytes, offset, 2, 845 "bootstrap_arguments[" + argIndex + "]" + Hex.u2(argumentRef)); 846 } 847 arguments.set(argIndex, constantPool.get(argumentRef)); 848 } 849 arguments.setImmutable(); 850 Constant cstMethodRef = constantPool.get(methodRef); 851 methods.set(methodIndex, declaringClass, (CstMethodHandle) cstMethodRef, arguments); 852 } 853 methods.setImmutable(); 854 855 if (length != 0) { 856 throwBadLength(length); 857 } 858 859 return methods; 860 } 861 } 862