1 /* 2 * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.openjdk.asmtools.jdec; 24 25 import org.openjdk.asmtools.common.Module; 26 import org.openjdk.asmtools.asmutils.StringUtils; 27 import org.openjdk.asmtools.jasm.Modifiers; 28 import org.openjdk.asmtools.jcoder.JcodTokens; 29 import org.openjdk.asmtools.util.I18NResourceBundle; 30 31 import java.awt.event.KeyEvent; 32 import java.io.DataInputStream; 33 import java.io.EOFException; 34 import java.io.IOException; 35 import java.io.PrintWriter; 36 37 import static java.lang.String.format; 38 import static org.openjdk.asmtools.jasm.Tables.*; 39 import static org.openjdk.asmtools.jasm.Tables.AnnotElemType.AE_UNKNOWN; 40 import static org.openjdk.asmtools.jasm.TypeAnnotationTypes.*; 41 42 /** 43 * Class data of the Java Decoder 44 */ 45 class ClassData { 46 47 private byte[] types; 48 private Object[] cpool; 49 private int CPlen; 50 private NestedByteArrayInputStream countedin; 51 private DataInputStream in; 52 private PrintWriter out; 53 private int[] cpe_pos; 54 private boolean printDetails; 55 private String entityType = ""; 56 private String entityName = ""; 57 58 public static I18NResourceBundle i18n 59 = I18NResourceBundle.getBundleForClass(Main.class); 60 61 ClassData(DataInputStream dis, int printFlags, PrintWriter out) throws IOException { 62 byte[] buf = new byte[dis.available()]; 63 try { 64 if (dis.read(buf) <= 0) 65 throw new IOException("The file is empty"); 66 } finally { 67 dis.close(); 68 } 69 countedin = new NestedByteArrayInputStream(buf); 70 in = new DataInputStream(countedin); 71 this.out = out; 72 printDetails = ((printFlags & 1) == 1); 73 } 74 75 /*========================================================*/ 76 private static final char[] hexTable = { 77 '0', '1', '2', '3', '4', '5', '6', '7', 78 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' 79 }; 80 81 private String toHex(long val, int width) { 82 StringBuilder s = new StringBuilder(); 83 for (int i = width * 2 - 1; i >= 0; i--) { 84 s.append(hexTable[((int) (val >> (4 * i))) & 0xF]); 85 } 86 return "0x" + s.toString(); 87 } 88 89 private String toHex(long val) { 90 int width; 91 for (width = 8; width > 0; width--) { 92 if ((val >> (width - 1) * 8) != 0) { 93 break; 94 } 95 } 96 return toHex(val, width); 97 } 98 99 private void printByteHex(PrintWriter out, int b) { 100 out.print(hexTable[(b >> 4) & 0xF]); 101 out.print(hexTable[b & 0xF]); 102 } 103 104 private void printBytes(PrintWriter out, DataInputStream in, int len) 105 throws IOException { 106 try { 107 for (int i = 0; i < len; i++) { 108 if (i % 8 == 0) { 109 out_print("0x"); 110 } 111 printByteHex(out, in.readByte()); 112 if (i % 8 == 7) { 113 out.println(";"); 114 } 115 } 116 } finally { 117 if (len % 8 != 0) { 118 out.println(";"); 119 } 120 } 121 } 122 123 private void printRestOfBytes() { 124 for (int i = 0; ; i++) { 125 try { 126 byte b = in.readByte(); 127 if (i % 8 == 0) { 128 out_print("0x"); 129 } 130 printByteHex(out, b); 131 if (i % 8 == 7) { 132 out.print(";\n"); 133 } 134 } catch (IOException e) { 135 return; 136 } 137 } 138 } 139 140 private void printUtf8InfoIndex(int index, String indexName) { 141 String name = (String) cpool[index]; 142 out_print("#" + index + "; // "); 143 if (printDetails) { 144 out.println(String.format("%-16s",indexName) + " : " + name); 145 } else { 146 out.println(indexName); 147 } 148 } 149 150 /*========================================================*/ 151 private int shift = 0; 152 153 private void out_begin(String s) { 154 for (int i = 0; i < shift; i++) { 155 out.print(" "); 156 } 157 out.println(s); 158 shift++; 159 } 160 161 private void out_print(String s) { 162 for (int i = 0; i < shift; i++) { 163 out.print(" "); 164 } 165 out.print(s); 166 } 167 168 private void out_println(String s) { 169 for (int i = 0; i < shift; i++) { 170 out.print(" "); 171 } 172 out.println(s); 173 } 174 175 private void out_end(String s) { 176 shift--; 177 for (int i = 0; i < shift; i++) { 178 out.print(" "); 179 } 180 out.println(s); 181 } 182 183 private String startArray(int length) { 184 return "[" + (printDetails ? Integer.toString(length) : "") + "]"; 185 } 186 187 private void startArrayCmt(int length, String comment) { 188 out_begin(startArray(length) + format(" {%s", comment == null ? "" : " // " + comment)); 189 } 190 191 private void startArrayCmtB(int length, String comment) { 192 out_begin(startArray(length) + format("b {%s", comment == null ? "" : " // " + comment)); 193 } 194 195 /*========================================================*/ 196 private void readCP(DataInputStream in) throws IOException { 197 int length = in.readUnsignedShort(); 198 CPlen = length; 199 traceln(i18n.getString("jdec.trace.CP_len", length)); 200 types = new byte[length]; 201 cpool = new Object[length]; 202 cpe_pos = new int[length]; 203 for (int i = 1; i < length; i++) { 204 byte btag; 205 int v1; 206 long lv; 207 cpe_pos[i] = countedin.getPos(); 208 btag = in.readByte(); 209 traceln(i18n.getString("jdec.trace.CP_entry", i, btag)); 210 types[i] = btag; 211 ConstType tg = tag(btag); 212 switch (tg) { 213 case CONSTANT_UTF8: 214 cpool[i] = in.readUTF(); 215 break; 216 case CONSTANT_INTEGER: 217 v1 = in.readInt(); 218 cpool[i] = v1; 219 break; 220 case CONSTANT_FLOAT: 221 v1 = Float.floatToIntBits(in.readFloat()); 222 cpool[i] = v1; 223 break; 224 case CONSTANT_LONG: 225 lv = in.readLong(); 226 cpool[i] = lv; 227 i++; 228 break; 229 case CONSTANT_DOUBLE: 230 lv = Double.doubleToLongBits(in.readDouble()); 231 cpool[i] = lv; 232 i++; 233 break; 234 case CONSTANT_CLASS: 235 case CONSTANT_STRING: 236 case CONSTANT_MODULE: 237 case CONSTANT_PACKAGE: 238 v1 = in.readUnsignedShort(); 239 cpool[i] = v1; 240 break; 241 case CONSTANT_INTERFACEMETHOD: 242 case CONSTANT_FIELD: 243 case CONSTANT_METHOD: 244 case CONSTANT_NAMEANDTYPE: 245 cpool[i] = "#" + in.readUnsignedShort() + " #" + in.readUnsignedShort(); 246 break; 247 case CONSTANT_DYNAMIC: 248 case CONSTANT_INVOKEDYNAMIC: 249 cpool[i] = in.readUnsignedShort() + "s #" + in.readUnsignedShort(); 250 break; 251 case CONSTANT_METHODHANDLE: 252 cpool[i] = in.readUnsignedByte() + "b #" + in.readUnsignedShort(); 253 break; 254 case CONSTANT_METHODTYPE: 255 cpool[i] = "#" + in.readUnsignedShort(); 256 break; 257 default: 258 CPlen = i; 259 printCP(out); 260 out_println(toHex(btag, 1) + "; // invalid constant type: " + (int) btag + " for element " + i); 261 throw new ClassFormatError(); 262 } 263 } 264 } 265 266 private void printCP(PrintWriter out) { 267 int length = CPlen; 268 startArrayCmt(length, "Constant Pool"); 269 out_println("; // first element is empty"); 270 try { 271 int size; 272 for (int i = 1; i < length; i = i + size) { 273 size = 1; 274 byte btag = types[i]; 275 ConstType tg = tag(btag); 276 int pos = cpe_pos[i]; 277 String tagstr; 278 String valstr; 279 int v1; 280 long lv; 281 if (tg != null) { 282 tagstr = tg.parseKey(); 283 } else { 284 throw new Error("Can't get a tg representing the type of Constant in the Constant Pool at: " + i); 285 } 286 switch (tg) { 287 case CONSTANT_UTF8: { 288 tagstr = "Utf8"; 289 valstr = StringUtils.Utf8ToString((String) cpool[i]); 290 } 291 break; 292 case CONSTANT_FLOAT: 293 case CONSTANT_INTEGER: 294 v1 = (Integer) cpool[i]; 295 valstr = toHex(v1, 4); 296 break; 297 case CONSTANT_DOUBLE: 298 case CONSTANT_LONG: 299 lv = (Long) cpool[i]; 300 valstr = toHex(lv, 8) + ";"; 301 size = 2; 302 break; 303 case CONSTANT_CLASS: 304 case CONSTANT_MODULE: 305 case CONSTANT_PACKAGE: 306 case CONSTANT_STRING: 307 v1 = (Integer) cpool[i]; 308 valstr = "#" + v1; 309 break; 310 case CONSTANT_INTERFACEMETHOD: 311 case CONSTANT_FIELD: 312 case CONSTANT_METHOD: 313 case CONSTANT_NAMEANDTYPE: 314 case CONSTANT_METHODHANDLE: 315 case CONSTANT_METHODTYPE: 316 case CONSTANT_DYNAMIC: 317 case CONSTANT_INVOKEDYNAMIC: 318 valstr = (String) cpool[i]; 319 break; 320 default: 321 throw new Error("invalid constant type: " + (int) btag); 322 } 323 out_print(tagstr + " " + valstr + "; // #" + i); 324 if (printDetails) { 325 out_println(" at " + toHex(pos)); 326 } else { 327 out.println(); 328 } 329 } 330 } finally { 331 out_end("} // Constant Pool"); 332 out.println(); 333 } 334 } 335 336 private String getStringPos() { 337 return " at " + toHex(countedin.getPos()); 338 } 339 340 private String getCommentPosCond() { 341 if (printDetails) { 342 return " // " + getStringPos(); 343 } else { 344 return ""; 345 } 346 } 347 348 private void decodeCPXAttr(DataInputStream in, int len, String attrname, PrintWriter out) throws IOException { 349 decodeCPXAttrM(in, len, attrname, out, 1); 350 } 351 352 private void decodeCPXAttrM(DataInputStream in, int len, String attrname, PrintWriter out, int expectedIndices) throws IOException { 353 if (len != expectedIndices * 2) { 354 out_println("// invalid length of " + attrname + " attr: " + len + " (should be " + (expectedIndices * 2) + ") > "); 355 printBytes(out, in, len); 356 } else { 357 StringBuilder outputString = new StringBuilder(); 358 for (int k = 1; k <= expectedIndices; k++) { 359 outputString.append("#").append(in.readUnsignedShort()).append("; "); 360 if (k % 16 == 0) { 361 out_println(outputString.toString().replaceAll("\\s+$","")); 362 outputString = new StringBuilder(); 363 } 364 } 365 if (outputString.length() > 0) { 366 out_println(outputString.toString().replaceAll("\\s+$","")); 367 } 368 } 369 } 370 371 private void printStackMap(DataInputStream in, int elementsNum) throws IOException { 372 int num; 373 if (elementsNum > 0) { 374 num = elementsNum; 375 } else { 376 num = in.readUnsignedShort(); 377 } 378 out.print(startArray(num) + (elementsNum > 0 ? "z" : "") + "{"); 379 try { 380 for (int k = 0; k < num; k++) { 381 int maptype = in.readUnsignedByte(); 382 StackMapType mptyp = stackMapType(maptype, out); 383 String maptypeImg; 384 if (printDetails) { 385 maptypeImg = maptype + "b"; 386 } else { 387 try { 388 maptypeImg = mptyp.parsekey(); 389 } catch (ArrayIndexOutOfBoundsException e) { 390 maptypeImg = "/* BAD TYPE: */ " + maptype + "b"; 391 } 392 } 393 switch (mptyp) { 394 case ITEM_Object: 395 case ITEM_NewObject: 396 maptypeImg = maptypeImg + "," + in.readUnsignedShort(); 397 break; 398 case ITEM_UNKNOWN: 399 maptypeImg = maptype + "b"; 400 break; 401 default: 402 } 403 out.print(maptypeImg); 404 if (k < num - 1) { 405 out.print("; "); 406 } 407 } 408 } finally { 409 out.print("}"); 410 } 411 } 412 413 /** 414 * Processes 4.7.20 The RuntimeVisibleTypeAnnotations Attribute, 4.7.21 The RuntimeInvisibleTypeAnnotations Attribute 415 * <code>type_annotation</code> structure. 416 */ 417 private void decodeTargetTypeAndRefInfo(DataInputStream in) throws IOException { 418 int tt = in.readUnsignedByte(); // [4.7.20] annotations[], type_annotation { u1 target_type; ...} 419 ETargetType targetType = ETargetType.getTargetType(tt); 420 if( targetType == null ) { 421 throw new Error("Type annotation: invalid target_type(u1) " + tt); 422 } 423 ETargetInfo targetInfo = targetType.targetInfo(); 424 out_println(toHex(tt, 1) + "; // target_type: " + targetType.parseKey()); 425 switch (targetInfo) { 426 case TYPEPARAM: //[3.3.1] meth_type_param, class_type_param: 427 out_println(toHex(in.readUnsignedByte(), 1) + "; // param_index"); 428 break; 429 case SUPERTYPE: //[3.3.2] class_exts_impls 430 out_println(toHex(in.readUnsignedShort(), 2) + "; // type_index"); 431 break; 432 case TYPEPARAM_BOUND: //[3.3.3] class_type_param_bnds, meth_type_param_bnds 433 out_println(toHex(in.readUnsignedByte(), 1) + "; // param_index"); 434 out_println(toHex(in.readUnsignedByte(), 1) + "; // bound_index"); 435 break; 436 case EMPTY: //[3.3.4] meth_receiver, meth_ret_type, field 437 // NOTE: reference_info is empty for this annotation's target 438 break; 439 case METHODPARAM: //[3.3.5] meth_formal_param: 440 out_println(toHex(in.readUnsignedByte(), 1) + "; // parameter_index"); 441 break; 442 case EXCEPTION: //[3.3.61] throws_type 443 //KTL: Updated index to UShort for JSR308 change 444 out_println(in.readUnsignedShort() + "; // type_index"); 445 break; 446 case LOCALVAR: //[3.3.7] local_var, resource_var 447 { 448 int lv_num = in.readUnsignedShort(); 449 startArrayCmt(lv_num, "local_variables"); 450 try { 451 for (int i = 0; i < lv_num; i++) { 452 out_println(in.readUnsignedShort() + " " + in.readUnsignedShort() 453 + " " + in.readUnsignedShort() + ";" + getCommentPosCond()); 454 } 455 } finally { 456 out_end("}"); 457 } 458 } 459 break; 460 case CATCH: //[3.3.8] exception_param 461 out_println(in.readUnsignedShort() + "; // exception_table_index"); 462 break; 463 case OFFSET: //[3.3.9] type_test (instanceof), obj_creat (new) 464 // constr_ref_receiver, meth_ref_receiver 465 out_println(in.readUnsignedShort() + "; // offset"); 466 break; 467 case TYPEARG: //[3.3.10] cast, constr_ref_typearg, meth_invoc_typearg 468 // constr_invoc_typearg, meth_ref_typearg 469 out_println(in.readUnsignedShort() + "; // offset"); 470 out_println(toHex(in.readUnsignedByte(), 1) + "; // type_index"); 471 break; 472 default: // should never happen 473 out_println(toHex(tt, 1) + "; // invalid target_info: " + tt); 474 throw new ClassFormatError(); 475 } 476 // [4.7.20.2] 477 int path_length = in.readUnsignedByte(); // type_path { u1 path_length; ...} 478 startArrayCmtB(path_length, "type_paths"); 479 try { 480 for (int i = 0; i < path_length; i++) { 481 // print the type_path elements 482 out_println("{ " + toHex(in.readUnsignedByte(), 1) // { u1 type_path_kind; 483 + "; " + toHex(in.readUnsignedByte(), 1) // u1 type_argument_index; } 484 + "; } // type_path[" + i + "]"); // path[i] 485 } 486 } finally { 487 out_end("}"); 488 } 489 } 490 491 private void decodeElementValue(DataInputStream in, PrintWriter out) throws IOException { 492 out_begin("{ // element_value"); 493 try { 494 char tg = (char) in.readByte(); 495 AnnotElemType tag = annotElemType(tg); 496 if (tag != AE_UNKNOWN) { 497 out_println("'" + tg + "';"); 498 } 499 switch (tag) { 500 case AE_BYTE: 501 case AE_CHAR: 502 case AE_DOUBLE: 503 case AE_FLOAT: 504 case AE_INT: 505 case AE_LONG: 506 case AE_SHORT: 507 case AE_BOOLEAN: 508 case AE_STRING: 509 decodeCPXAttr(in, 2, "const_value_index", out); 510 break; 511 case AE_ENUM: 512 out_begin("{ // enum_const_value"); 513 decodeCPXAttr(in, 2, "type_name_index", out); 514 decodeCPXAttr(in, 2, "const_name_index", out); 515 out_end("} // enum_const_value"); 516 break; 517 case AE_CLASS: 518 decodeCPXAttr(in, 2, "class_info_index", out); 519 break; 520 case AE_ANNOTATION: 521 decodeAnnotation(in, out); 522 break; 523 case AE_ARRAY: 524 int ev_num = in.readUnsignedShort(); 525 startArrayCmt(ev_num, "array_value"); 526 try { 527 for (int i = 0; i < ev_num; i++) { 528 decodeElementValue(in, out); 529 if (i < ev_num - 1) { 530 out_println(";"); 531 } 532 } 533 } finally { 534 out_end("} // array_value"); 535 } 536 break; 537 case AE_UNKNOWN: 538 default: 539 String msg = "invalid element_value" + (isPrintableChar(tg) ? " tag type : " + tg : ""); 540 out_println(toHex(tg, 1) + "; // " + msg); 541 throw new ClassFormatError(msg); 542 } 543 } finally { 544 out_end("} // element_value"); 545 } 546 } 547 548 public boolean isPrintableChar(char c) { 549 Character.UnicodeBlock block = Character.UnicodeBlock.of(c); 550 return (!Character.isISOControl(c)) && 551 c != KeyEvent.CHAR_UNDEFINED && 552 block != null && 553 block != Character.UnicodeBlock.SPECIALS; 554 } 555 556 private void decodeAnnotation(DataInputStream in, PrintWriter out) throws IOException { 557 out_begin("{ // annotation"); 558 try { 559 decodeCPXAttr(in, 2, "field descriptor", out); 560 int evp_num = in.readUnsignedShort(); 561 decodeElementValuePairs(evp_num, in, out); 562 } finally { 563 out_end("} // annotation"); 564 } 565 } 566 567 private void decodeElementValuePairs(int count, DataInputStream in, PrintWriter out) throws IOException { 568 startArrayCmt(count, "element_value_pairs"); 569 try { 570 for (int i = 0; i < count; i++) { 571 out_begin("{ // element value pair"); 572 try { 573 decodeCPXAttr(in, 2, "name of the annotation type element", out); 574 decodeElementValue(in, out); 575 } finally { 576 out_end("} // element value pair"); 577 if (i < count - 1) { 578 out_println(";"); 579 } 580 } 581 } 582 } finally { 583 out_end("} // element_value_pairs"); 584 } 585 } 586 587 /** 588 * component_info { JEP 359 Record(Preview): class file 58.65535 589 * u2 name_index; 590 * u2 descriptor_index; 591 * u2 attributes_count; 592 * attribute_info attributes[attributes_count]; 593 * } 594 * 595 * or 596 * field_info { 597 * u2 access_flags; 598 * u2 name_index; 599 * u2 descriptor_index; 600 * u2 attributes_count; 601 * attribute_info attributes[attributes_count]; 602 * } 603 * or 604 * method_info { 605 * u2 access_flags; 606 * u2 name_index; 607 * u2 descriptor_index; 608 * u2 attributes_count; 609 * attribute_info attributes[attributes_count]; 610 * } 611 * 612 */ 613 private void decodeInfo(DataInputStream in, PrintWriter out, String elementName, boolean hasAccessFlag) throws IOException { 614 out_begin("{ // " + elementName + (printDetails ? getStringPos() : "")); 615 try { 616 if(hasAccessFlag) { 617 // u2 access_flags; 618 out_println(toHex(in.readShort(), 2) + "; // access"); 619 } 620 // u2 name_index 621 printUtf8InfoIndex(in.readUnsignedShort(), "name_index"); 622 // u2 descriptor_index 623 printUtf8InfoIndex(in.readUnsignedShort(), "descriptor_index"); 624 // u2 attributes_count; 625 // attribute_info attributes[attributes_count] 626 decodeAttrs(in, out); 627 } finally { 628 out_end("}"); 629 } 630 } 631 632 private void decodeTypeAnnotation(DataInputStream in, PrintWriter out) throws IOException { 633 out_begin("{ // type_annotation"); 634 try { 635 decodeTargetTypeAndRefInfo(in); 636 decodeCPXAttr(in, 2, "field descriptor", out); 637 int evp_num = in.readUnsignedShort(); 638 decodeElementValuePairs(evp_num, in, out); 639 } finally { 640 out_end("} // type_annotation"); 641 } 642 } 643 644 private void decodeBootstrapMethod(DataInputStream in) throws IOException { 645 out_begin("{ // bootstrap_method"); 646 try { 647 out_println("#" + in.readUnsignedShort() + "; // bootstrap_method_ref"); 648 int bm_args_cnt = in.readUnsignedShort(); 649 startArrayCmt(bm_args_cnt, "bootstrap_arguments"); 650 try { 651 for (int i = 0; i < bm_args_cnt; i++) { 652 out_println("#" + in.readUnsignedShort() + ";" + getCommentPosCond()); 653 } 654 } finally { 655 out_end("} // bootstrap_arguments"); 656 } 657 } finally { 658 out_end("} // bootstrap_method"); 659 } 660 } 661 662 private void decodeAttr(DataInputStream in, PrintWriter out) throws IOException { 663 // Read one attribute 664 String posComment = getStringPos(); 665 int name_cpx = in.readUnsignedShort(), btag, len; 666 667 String AttrName = ""; 668 try { 669 btag = types[name_cpx]; 670 ConstType tag = tag(btag); 671 672 if (tag == ConstType.CONSTANT_UTF8) { 673 AttrName = (String) cpool[name_cpx]; 674 } 675 } catch (ArrayIndexOutOfBoundsException ignored) { 676 } 677 AttrTag tg = attrtag(AttrName); 678 String endingComment = AttrName; 679 len = in.readInt(); 680 countedin.enter(len); 681 try { 682 if (printDetails) { 683 out_begin("Attr(#" + name_cpx + ", " + len + ") { // " + AttrName + posComment); 684 } else { 685 out_begin("Attr(#" + name_cpx + ") { // " + AttrName); 686 } 687 688 switch (tg) { 689 case ATT_Code: 690 out_println(in.readUnsignedShort() + "; // max_stack"); 691 out_println(in.readUnsignedShort() + "; // max_locals"); 692 int code_len = in.readInt(); 693 out_begin("Bytes" + startArray(code_len) + "{"); 694 try { 695 printBytes(out, in, code_len); 696 } finally { 697 out_end("}"); 698 } 699 int trap_num = in.readUnsignedShort(); 700 startArrayCmt(trap_num, "Traps"); 701 try { 702 for (int i = 0; i < trap_num; i++) { 703 out_println(in.readUnsignedShort() + " " + 704 in.readUnsignedShort() + " " + 705 in.readUnsignedShort() + " " + 706 in.readUnsignedShort() + ";" + 707 getCommentPosCond()); 708 } 709 } finally { 710 out_end("} // end Traps"); 711 } 712 // Read the attributes 713 decodeAttrs(in, out); 714 break; 715 716 case ATT_Exceptions: 717 int count = in.readUnsignedShort(); 718 startArrayCmt(count, AttrName); 719 try { 720 for (int i = 0; i < count; i++) { 721 out_println("#" + in.readUnsignedShort() + ";" + 722 getCommentPosCond()); 723 } 724 } finally { 725 out_end("}"); 726 } 727 break; 728 case ATT_LineNumberTable: 729 int ll_num = in.readUnsignedShort(); 730 startArrayCmt(ll_num, "line_number_table"); 731 try { 732 for (int i = 0; i < ll_num; i++) { 733 out_println(in.readUnsignedShort() + " " + 734 in.readUnsignedShort() + ";" + 735 getCommentPosCond()); 736 } 737 } finally { 738 out_end("}"); 739 } 740 break; 741 case ATT_LocalVariableTable: 742 case ATT_LocalVariableTypeTable: 743 int lvt_num = in.readUnsignedShort(); 744 startArrayCmt(lvt_num, AttrName); 745 try { 746 for (int i = 0; i < lvt_num; i++) { 747 out_println(in.readUnsignedShort() + " " + 748 in.readUnsignedShort() + " " + 749 in.readUnsignedShort() + " " + 750 in.readUnsignedShort() + " " + 751 in.readUnsignedShort() + ";" + 752 getCommentPosCond()); 753 } 754 } finally { 755 out_end("}"); 756 } 757 break; 758 case ATT_InnerClasses: 759 int ic_num = in.readUnsignedShort(); 760 startArrayCmt(ic_num, "classes"); 761 try { 762 for (int i = 0; i < ic_num; i++) { 763 out_println("#" + in.readUnsignedShort() + " #" + 764 in.readUnsignedShort() + " #" + 765 in.readUnsignedShort() + " " + 766 in.readUnsignedShort() + ";" + getCommentPosCond()); 767 } 768 } finally { 769 out_end("}"); 770 } 771 break; 772 case ATT_StackMap: 773 int e_num = in.readUnsignedShort(); 774 startArrayCmt(e_num, ""); 775 try { 776 for (int k = 0; k < e_num; k++) { 777 int start_pc = in.readUnsignedShort(); 778 out_print("" + start_pc + ", "); 779 printStackMap(in, 0); 780 out.print(", "); 781 printStackMap(in, 0); 782 out.println(";"); 783 } 784 } finally { 785 out_end("}"); 786 } 787 break; 788 case ATT_StackMapTable: 789 int et_num = in.readUnsignedShort(); 790 startArrayCmt(et_num, ""); 791 try { 792 for (int k = 0; k < et_num; k++) { 793 int frame_type = in.readUnsignedByte(); 794 StackMapFrameType ftype = stackMapFrameType(frame_type); 795 switch (ftype) { 796 case SAME_FRAME: 797 // type is same_frame; 798 out_print("" + frame_type + "b"); 799 out.println("; // same_frame"); 800 break; 801 case SAME_LOCALS_1_STACK_ITEM_FRAME: 802 // type is same_locals_1_stack_item_frame 803 out_print("" + frame_type + "b, "); 804 // read additional single stack element 805 printStackMap(in, 1); 806 out.println("; // same_locals_1_stack_item_frame"); 807 break; 808 case SAME_LOCALS_1_STACK_ITEM_EXTENDED_FRAME: 809 // type is same_locals_1_stack_item_frame_extended 810 int noffset = in.readUnsignedShort(); 811 out_print("" + frame_type + "b, " + noffset + ", "); 812 // read additional single stack element 813 printStackMap(in, 1); 814 out.println("; // same_locals_1_stack_item_frame_extended"); 815 break; 816 case CHOP_1_FRAME: 817 case CHOP_2_FRAME: 818 case CHOP_3_FRAME: 819 // type is chop_frame 820 int coffset = in.readUnsignedShort(); 821 out_print("" + frame_type + "b, " + coffset); 822 out.println("; // chop_frame " + (251 - frame_type)); 823 break; 824 case SAME_FRAME_EX: 825 // type is same_frame_extended; 826 int xoffset = in.readUnsignedShort(); 827 out_print("" + frame_type + "b, " + xoffset); 828 out.println("; // same_frame_extended"); 829 break; 830 case APPEND_FRAME: 831 // type is append_frame 832 int aoffset = in.readUnsignedShort(); 833 out_print("" + frame_type + "b, " + aoffset + ", "); 834 // read additional locals 835 printStackMap(in, frame_type - 251); 836 out.println("; // append_frame " + (frame_type - 251)); 837 break; 838 case FULL_FRAME: 839 // type is full_frame 840 int foffset = in.readUnsignedShort(); 841 out_print("" + frame_type + "b, " + foffset + ", "); 842 printStackMap(in, 0); 843 out.print(", "); 844 printStackMap(in, 0); 845 out.println("; // full_frame"); 846 break; 847 } 848 } 849 } finally { 850 out_end("}"); 851 } 852 break; 853 case ATT_EnclosingMethod: 854 decodeCPXAttrM(in, len, AttrName, out, 2); 855 break; 856 case ATT_AnnotationDefault: 857 decodeElementValue(in, out); 858 break; 859 case ATT_RuntimeInvisibleAnnotations: 860 case ATT_RuntimeVisibleAnnotations: 861 int an_num = in.readUnsignedShort(); 862 startArrayCmt(an_num, "annotations"); 863 try { 864 for (int i = 0; i < an_num; i++) { 865 decodeAnnotation(in, out); 866 if (i < an_num - 1) { 867 out_println(";"); 868 } 869 } 870 } finally { 871 out_end("}"); 872 } 873 break; 874 // 4.7.20 The RuntimeVisibleTypeAnnotations Attribute 875 // 4.7.21 The RuntimeInvisibleTypeAnnotations Attribute 876 case ATT_RuntimeInvisibleTypeAnnotations: 877 case ATT_RuntimeVisibleTypeAnnotations: 878 int ant_num = in.readUnsignedShort(); 879 startArrayCmt(ant_num, "annotations"); 880 try { 881 for (int i = 0; i < ant_num; i++) { 882 decodeTypeAnnotation(in, out); 883 if (i < ant_num - 1) { 884 out_println(";"); 885 } 886 } 887 } finally { 888 out_end("}"); 889 } 890 break; 891 case ATT_RuntimeInvisibleParameterAnnotations: 892 case ATT_RuntimeVisibleParameterAnnotations: 893 int pm_num = in.readUnsignedByte(); 894 startArrayCmtB(pm_num, "parameters"); 895 try { 896 for (int k = 0; k < pm_num; k++) { 897 int anp_num = in.readUnsignedShort(); 898 startArrayCmt(anp_num, "annotations"); 899 try { 900 for (int i = 0; i < anp_num; i++) { 901 decodeAnnotation(in, out); 902 if (k < anp_num - 1) { 903 out_println(";"); 904 } 905 } 906 } finally { 907 out_end("}"); 908 } 909 if (k < pm_num - 1) { 910 out_println(";"); 911 } 912 } 913 } finally { 914 out_end("}"); 915 } 916 break; 917 case ATT_BootstrapMethods: 918 int bm_num = in.readUnsignedShort(); 919 startArrayCmt(bm_num, "bootstrap_methods"); 920 try { 921 for (int i = 0; i < bm_num; i++) { 922 decodeBootstrapMethod(in); 923 if (i < bm_num - 1) { 924 out_println(";"); 925 } 926 } 927 } finally { 928 out_end("}"); 929 } 930 break; 931 case ATT_Module: 932 decodeModule(in); 933 break; 934 case ATT_TargetPlatform: 935 decodeCPXAttrM(in, len, AttrName, out, 3); 936 break; 937 case ATT_ModulePackages: 938 int p_num = in.readUnsignedShort(); 939 startArrayCmt(p_num, null); 940 try { 941 decodeCPXAttrM(in, len - 2, AttrName, out, p_num); 942 } finally { 943 out_end("}"); 944 } 945 break; 946 // MethodParameters_attribute { 947 // u2 attribute_name_index; 948 // u4 attribute_length; 949 // u1 parameters_count; 950 // { u2 name_index; 951 // u2 access_flags; 952 // } parameters[parameters_count]; 953 // } 954 case ATT_MethodParameters: 955 int pcount = in.readUnsignedByte(); 956 startArrayCmtB(pcount, AttrName); 957 try { 958 for (int i = 0; i < pcount; i++) { 959 out_println("#" + in.readUnsignedShort() + " " + 960 toHex(in.readUnsignedShort(), 2) + ";" + 961 getCommentPosCond()); 962 } 963 } finally { 964 out_end("}"); 965 } 966 break; 967 // JEP 359 Record(Preview): class file 58.65535 968 // Record_attribute { 969 // u2 attribute_name_index; 970 // u4 attribute_length; 971 // u2 components_count; 972 // component_info components[components_count]; 973 // } 974 case ATT_Record: 975 int ncomps = in.readUnsignedShort(); 976 startArrayCmt(ncomps, "components"); 977 try { 978 for (int i = 0; i < ncomps; i++) { 979 decodeInfo(in,out,"component",false); 980 if (i < ncomps - 1) { 981 out_println(";"); 982 } 983 } 984 } finally { 985 out_end("}"); 986 } 987 break; 988 case ATT_ConstantValue: 989 case ATT_Signature: 990 case ATT_SourceFile: 991 decodeCPXAttr(in, len, AttrName, out); 992 break; 993 // JEP 181 (Nest-based Access Control): class file 55.0 994 // NestHost_attribute { 995 // u2 attribute_name_index; 996 // u4 attribute_length; 997 // u2 host_class_index; 998 // } 999 case ATT_NestHost: 1000 decodeTypes(in, out, 1); 1001 break; 1002 // JEP 181 (Nest-based Access Control): class file 55.0 1003 // NestMembers_attribute { 1004 // u2 attribute_name_index; 1005 // u4 attribute_length; 1006 // u2 number_of_classes; 1007 // u2 classes[number_of_classes]; 1008 // } 1009 case ATT_NestMembers: 1010 // JEP 360 (Sealed types): class file 59.65535 1011 // PermittedSubclasses_attribute { 1012 // u2 attribute_name_index; 1013 // u4 attribute_length; 1014 // u2 number_of_classes; 1015 // u2 classes[number_of_classes]; 1016 // } 1017 case ATT_PermittedSubclasses: 1018 // Preload attribute has same format 1019 case ATT_Preload: 1020 int nsubtypes = in.readUnsignedShort(); 1021 startArrayCmt(nsubtypes, "classes"); 1022 try { 1023 decodeTypes(in, out, nsubtypes); 1024 } finally { 1025 out_end("}"); 1026 } 1027 break; 1028 default: 1029 printBytes(out, in, len); 1030 if (AttrName == null) { 1031 endingComment = "Attr(#" + name_cpx + ")"; 1032 } 1033 } 1034 1035 } catch (EOFException e) { 1036 out.println("// ======== unexpected end of attribute array"); 1037 } finally { 1038 int rest = countedin.available(); 1039 if (rest > 0) { 1040 out.println("// ======== attribute array started " + posComment + " has " + rest + " bytes more:"); 1041 printBytes(out, in, rest); 1042 } 1043 out_end("} // end " + endingComment); 1044 countedin.leave(); 1045 } 1046 } 1047 1048 private void decodeModuleStatement(String statementName, DataInputStream in) throws IOException { 1049 // u2 {exports|opens}_count 1050 int count = in.readUnsignedShort(); 1051 startArrayCmt(count, statementName); 1052 try { 1053 for (int i = 0; i < count; i++) { 1054 // u2 {exports|opens}_index; u2 {exports|opens}_flags 1055 int index = in.readUnsignedShort(); 1056 int nFlags = in.readUnsignedShort(); 1057 String sFlags = printDetails ? Module.Modifier.getStatementFlags(nFlags) : ""; 1058 out_println("#" + index + " " + toHex(nFlags, 2) + (sFlags.isEmpty() ? "" : " // [ " + sFlags + " ]")); 1059 int exports_to_count = in.readUnsignedShort(); 1060 startArrayCmt(exports_to_count, null); 1061 try { 1062 for (int j = 0; j < exports_to_count; j++) { 1063 out_println("#" + in.readUnsignedShort() + ";"); 1064 } 1065 } finally { 1066 out_end("};"); 1067 } 1068 } 1069 } finally { 1070 out_end("} // " + statementName + "\n"); 1071 } 1072 } 1073 1074 private void decodeModule(DataInputStream in) throws IOException { 1075 //u2 module_name_index 1076 int index = in.readUnsignedShort(); 1077 entityName = (String) cpool[(Integer) cpool[index]]; 1078 out_print("#" + index + "; // "); 1079 if (printDetails) { 1080 out.println(String.format("%-16s","name_index") + " : " + entityName); 1081 } else { 1082 out.println("name_index"); 1083 } 1084 1085 // u2 module_flags 1086 int moduleFlags = in.readUnsignedShort(); 1087 out_print(toHex(moduleFlags, 2) + "; // flags"); 1088 if (printDetails) { 1089 out_print(" " + Module.Modifier.getModuleFlags(moduleFlags)); 1090 } 1091 out.println(); 1092 1093 //u2 module_version 1094 int versionIndex = in.readUnsignedShort(); 1095 out_println("#" + versionIndex + "; // version"); 1096 1097 // u2 requires_count 1098 int count = in.readUnsignedShort(); 1099 startArrayCmt(count, "requires"); 1100 try { 1101 for (int i = 0; i < count; i++) { 1102 // u2 requires_index; u2 requires_flags; u2 requires_version_index 1103 index = in.readUnsignedShort(); 1104 int nFlags = in.readUnsignedShort(); 1105 versionIndex = in.readUnsignedShort(); 1106 String sFlags = printDetails ? Module.Modifier.getStatementFlags(nFlags) : ""; 1107 out_println("#" + index + " " + toHex(nFlags, 2) + " #" + versionIndex + ";" + (sFlags.isEmpty() ? "" : " // " + sFlags)); 1108 } 1109 } finally { 1110 out_end("} // requires\n"); 1111 } 1112 1113 decodeModuleStatement("exports", in); 1114 1115 decodeModuleStatement("opens", in); 1116 // u2 uses_count 1117 count = in.readUnsignedShort(); 1118 startArrayCmt(count, "uses"); 1119 try { 1120 for (int i = 0; i < count; i++) { 1121 // u2 uses_index 1122 out_println("#" + in.readUnsignedShort() + ";"); 1123 } 1124 } finally { 1125 out_end("} // uses\n"); 1126 } 1127 count = in.readUnsignedShort(); // u2 provides_count 1128 startArrayCmt(count, "provides"); 1129 try { 1130 for (int i = 0; i < count; i++) { 1131 // u2 provides_index 1132 out_println("#" + in.readUnsignedShort()); 1133 int provides_with_count = in.readUnsignedShort(); 1134 // u2 provides_with_count 1135 startArrayCmt(provides_with_count, null); 1136 try { 1137 for (int j = 0; j < provides_with_count; j++) { 1138 // u2 provides_with_index; 1139 out_println("#" + in.readUnsignedShort() + ";"); 1140 } 1141 } finally { 1142 out_end("};"); 1143 } 1144 } 1145 } finally { 1146 out_end("} // provides\n"); 1147 } 1148 } 1149 1150 private void decodeAttrs(DataInputStream in, PrintWriter out) throws IOException { 1151 // Read the attributes 1152 int attr_num = in.readUnsignedShort(); 1153 startArrayCmt(attr_num, "Attributes"); 1154 try { 1155 for (int i = 0; i < attr_num; i++) { 1156 decodeAttr(in, out); 1157 if (i + 1 < attr_num) { 1158 out_println(";"); 1159 } 1160 } 1161 } finally { 1162 out_end("} // Attributes"); 1163 } 1164 } 1165 1166 private void decodeMembers(DataInputStream in, PrintWriter out, String groupName, String elementName) throws IOException { 1167 int count = in.readUnsignedShort(); 1168 traceln(groupName + "=" + count); 1169 startArrayCmt(count, groupName); 1170 try { 1171 for (int i = 0; i < count; i++) { 1172 decodeInfo(in,out,elementName,true); 1173 if (i + 1 < count) { 1174 out_println(";"); 1175 } 1176 } 1177 } finally { 1178 out_end("} // " + groupName); 1179 out.println(); 1180 } 1181 } 1182 1183 void decodeClass(String fileName) throws IOException { 1184 // Read the header 1185 try { 1186 int magic = in.readInt(); 1187 int min_version = in.readUnsignedShort(); 1188 int version = in.readUnsignedShort(); 1189 1190 // Read the constant pool 1191 readCP(in); 1192 short access = in.readShort(); // don't care about sign 1193 int this_cpx = in.readUnsignedShort(); 1194 1195 try { 1196 entityName = (String) cpool[(Integer) cpool[this_cpx]]; 1197 if (entityName.equals("module-info")) { 1198 entityType = "module"; 1199 entityName = ""; 1200 } else { 1201 entityType = "class"; 1202 } 1203 if (!entityName.isEmpty() && (JcodTokens.keyword_token_ident(entityName) != JcodTokens.Token.IDENT || JcodTokens.constValue(entityName) != -1)) { 1204 // JCod can't parse a entityName matching a keyword or a constant value, 1205 // then use the filename instead: 1206 out_begin(String.format("file \"%s.class\" {", entityName)); 1207 } else { 1208 out_begin(format("%s %s {", entityType, entityName)); 1209 } 1210 } catch (Exception e) { 1211 entityName = fileName; 1212 out.println("// " + e.getMessage() + " while accessing entityName"); 1213 out_begin(format("%s %s { // source file name", entityType, entityName)); 1214 } 1215 1216 out_print(toHex(magic, 4) + ";"); 1217 if (magic != JAVA_MAGIC) { 1218 out.print(" // wrong magic: 0x" + Integer.toString(JAVA_MAGIC, 16) + " expected"); 1219 } 1220 out.println(); 1221 out_println(min_version + "; // minor version"); 1222 out_println(version + "; // version"); 1223 1224 // Print the constant pool 1225 printCP(out); 1226 out_println(toHex(access, 2) + "; // access" + 1227 (printDetails ? " [" + (" " + Modifiers.accessString(access, CF_Context.CTX_CLASS).toUpperCase()).replaceAll(" (\\S)", " ACC_$1") + "]" : "")); 1228 out_println("#" + this_cpx + ";// this_cpx"); 1229 int super_cpx = in.readUnsignedShort(); 1230 out_println("#" + super_cpx + ";// super_cpx"); 1231 traceln(i18n.getString("jdec.trace.access_thisCpx_superCpx", access, this_cpx, super_cpx)); 1232 out.println(); 1233 1234 // Read the interfaces 1235 int numinterfaces = in.readUnsignedShort(); 1236 traceln(i18n.getString("jdec.trace.numinterfaces", numinterfaces)); 1237 startArrayCmt(numinterfaces, "Interfaces"); 1238 try { 1239 decodeTypes(in, out, numinterfaces); 1240 } finally { 1241 out_end("} // Interfaces\n"); 1242 } 1243 // Read the fields 1244 decodeMembers(in, out, "Fields", "field"); 1245 1246 // Read the methods 1247 decodeMembers(in, out, "Methods", "method"); 1248 1249 // Read the attributes 1250 decodeAttrs(in, out); 1251 } catch (EOFException ignored) { 1252 } catch (ClassFormatError err) { 1253 String msg = err.getMessage(); 1254 out.println("//------- ClassFormatError" + 1255 (msg == null || msg.isEmpty() ? "" : ": " + msg)); 1256 printRestOfBytes(); 1257 } finally { 1258 out_end(format("} // end %s %s", entityType, entityName)); 1259 } 1260 } // end decodeClass() 1261 1262 private void decodeTypes(DataInputStream in, PrintWriter out, int count) throws IOException { 1263 for (int i = 0; i < count; i++) { 1264 int type_cpx = in.readUnsignedShort(); 1265 traceln(i18n.getString("jdec.trace.type", i, type_cpx)); 1266 out_print("#" + type_cpx + ";"); 1267 if (printDetails) { 1268 String name = (String) cpool[(int)cpool[type_cpx]]; 1269 out.println(" // " + name + getStringPos()); 1270 } else { 1271 out.println(); 1272 } 1273 } 1274 } 1275 1276 /* ====================================================== */ 1277 boolean DebugFlag = false; 1278 1279 public void trace(String s) { 1280 if (!DebugFlag) { 1281 return; 1282 } 1283 System.out.print(s); 1284 } 1285 1286 public void traceln(String s) { 1287 if (!DebugFlag) { 1288 return; 1289 } 1290 System.out.println(s); 1291 } 1292 }// end class ClassData