1 /* 2 * Copyright (c) 2010, 2016, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package xmlkit; // -*- mode: java; indent-tabs-mode: nil -*- 26 27 import com.sun.tools.classfile.AccessFlags; 28 import com.sun.tools.classfile.Annotation; 29 import com.sun.tools.classfile.Annotation.Annotation_element_value; 30 import com.sun.tools.classfile.Annotation.Array_element_value; 31 import com.sun.tools.classfile.Annotation.Class_element_value; 32 import com.sun.tools.classfile.Annotation.Enum_element_value; 33 import com.sun.tools.classfile.Annotation.Primitive_element_value; 34 import com.sun.tools.classfile.AnnotationDefault_attribute; 35 import com.sun.tools.classfile.Attribute; 36 import com.sun.tools.classfile.Attributes; 37 import com.sun.tools.classfile.BootstrapMethods_attribute; 38 import com.sun.tools.classfile.CharacterRangeTable_attribute; 39 import com.sun.tools.classfile.ClassFile; 40 import com.sun.tools.classfile.Code_attribute; 41 import com.sun.tools.classfile.CompilationID_attribute; 42 import com.sun.tools.classfile.ConstantPool; 43 import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info; 44 import com.sun.tools.classfile.ConstantPool.CONSTANT_Module_info; 45 import com.sun.tools.classfile.ConstantPool.CONSTANT_Package_info; 46 import com.sun.tools.classfile.ConstantPool.CONSTANT_Double_info; 47 import com.sun.tools.classfile.ConstantPool.CONSTANT_Fieldref_info; 48 import com.sun.tools.classfile.ConstantPool.CONSTANT_Float_info; 49 import com.sun.tools.classfile.ConstantPool.CONSTANT_Integer_info; 50 import com.sun.tools.classfile.ConstantPool.CONSTANT_InterfaceMethodref_info; 51 import com.sun.tools.classfile.ConstantPool.CONSTANT_InvokeDynamic_info; 52 import com.sun.tools.classfile.ConstantPool.CONSTANT_Long_info; 53 import com.sun.tools.classfile.ConstantPool.CONSTANT_MethodHandle_info; 54 import com.sun.tools.classfile.ConstantPool.CONSTANT_MethodType_info; 55 import com.sun.tools.classfile.ConstantPool.CONSTANT_Methodref_info; 56 import com.sun.tools.classfile.ConstantPool.CONSTANT_NameAndType_info; 57 import com.sun.tools.classfile.ConstantPool.CONSTANT_String_info; 58 import com.sun.tools.classfile.ConstantPool.CONSTANT_Utf8_info; 59 import com.sun.tools.classfile.ConstantPool.CPInfo; 60 import com.sun.tools.classfile.ConstantPool.InvalidIndex; 61 import com.sun.tools.classfile.ConstantPoolException; 62 import com.sun.tools.classfile.ConstantValue_attribute; 63 import com.sun.tools.classfile.DefaultAttribute; 64 import com.sun.tools.classfile.Deprecated_attribute; 65 import com.sun.tools.classfile.Descriptor.InvalidDescriptor; 66 import com.sun.tools.classfile.EnclosingMethod_attribute; 67 import com.sun.tools.classfile.Exceptions_attribute; 68 import com.sun.tools.classfile.Field; 69 import com.sun.tools.classfile.InnerClasses_attribute; 70 import com.sun.tools.classfile.InnerClasses_attribute.Info; 71 import com.sun.tools.classfile.Instruction; 72 import com.sun.tools.classfile.Instruction.TypeKind; 73 import com.sun.tools.classfile.LineNumberTable_attribute; 74 import com.sun.tools.classfile.LocalVariableTable_attribute; 75 import com.sun.tools.classfile.LocalVariableTypeTable_attribute; 76 import com.sun.tools.classfile.Method; 77 import com.sun.tools.classfile.MethodParameters_attribute; 78 import com.sun.tools.classfile.Module_attribute; 79 import com.sun.tools.classfile.Module_attribute.ExportsEntry; 80 import com.sun.tools.classfile.Module_attribute.ProvidesEntry; 81 import com.sun.tools.classfile.Module_attribute.RequiresEntry; 82 import com.sun.tools.classfile.ModuleHashes_attribute; 83 import com.sun.tools.classfile.ModuleHashes_attribute.Entry; 84 import com.sun.tools.classfile.ModuleMainClass_attribute; 85 import com.sun.tools.classfile.ModuleResolution_attribute; 86 import com.sun.tools.classfile.ModuleTarget_attribute; 87 import com.sun.tools.classfile.ModulePackages_attribute; 88 import com.sun.tools.classfile.Opcode; 89 import com.sun.tools.classfile.RuntimeInvisibleAnnotations_attribute; 90 import com.sun.tools.classfile.RuntimeInvisibleParameterAnnotations_attribute; 91 import com.sun.tools.classfile.RuntimeInvisibleTypeAnnotations_attribute; 92 import com.sun.tools.classfile.RuntimeVisibleAnnotations_attribute; 93 import com.sun.tools.classfile.RuntimeVisibleParameterAnnotations_attribute; 94 import com.sun.tools.classfile.RuntimeVisibleTypeAnnotations_attribute; 95 import com.sun.tools.classfile.Signature_attribute; 96 import com.sun.tools.classfile.SourceDebugExtension_attribute; 97 import com.sun.tools.classfile.SourceFile_attribute; 98 import com.sun.tools.classfile.SourceID_attribute; 99 import com.sun.tools.classfile.StackMapTable_attribute; 100 import com.sun.tools.classfile.StackMapTable_attribute.append_frame; 101 import com.sun.tools.classfile.StackMapTable_attribute.chop_frame; 102 import com.sun.tools.classfile.StackMapTable_attribute.full_frame; 103 import com.sun.tools.classfile.StackMapTable_attribute.same_frame; 104 import com.sun.tools.classfile.StackMapTable_attribute.same_frame_extended; 105 import com.sun.tools.classfile.StackMapTable_attribute.same_locals_1_stack_item_frame; 106 import com.sun.tools.classfile.StackMapTable_attribute.same_locals_1_stack_item_frame_extended; 107 import com.sun.tools.classfile.StackMap_attribute; 108 import com.sun.tools.classfile.Synthetic_attribute; 109 import com.sun.tools.classfile.TypeAnnotation; 110 import com.sun.tools.classfile.TypeAnnotation.Position; 111 import static com.sun.tools.classfile.TypeAnnotation.TargetType.THROWS; 112 import java.io.*; 113 import java.util.*; 114 import java.util.jar.JarEntry; 115 import java.util.jar.JarFile; 116 import xmlkit.XMLKit.Element; 117 118 /* 119 * @author jrose, ksrini 120 */ 121 public class ClassReader { 122 123 private static final CommandLineParser CLP = new CommandLineParser("" 124 + "-source: +> = \n" 125 + "-dest: +> = \n" 126 + "-encoding: +> = \n" 127 + "-jcov $ \n -nojcov !-jcov \n" 128 + "-verbose $ \n -noverbose !-verbose \n" 129 + "-keepPath $ \n -nokeepPath !-keepPath \n" 130 + "-keepCP $ \n -nokeepCP !-keepCP \n" 131 + "-keepOrder $ \n -nokeepOrder !-keepOrder \n" 132 + "-continue $ \n -nocontinue !-continue \n" 133 + "-@ >-@ . \n" 134 + "- +? \n" 135 + "\n"); 136 137 138 // Protected state for representing the class file. 139 protected Element cfile; // <ClassFile ...> 140 protected Element cpool; // <ConstantPool ...> 141 protected Element klass; // <Class ...> 142 protected List<String> thePool; // stringified flattened Constant Pool 143 144 public static void main(String[] ava) throws IOException { 145 ArrayList<String> av = new ArrayList<>(Arrays.asList(ava)); 146 HashMap<String, String> props = new HashMap<>(); 147 props.put("-encoding:", "UTF8"); // default 148 props.put("-keepOrder", null); // CLI default 149 props.put("-pretty", "1"); // CLI default 150 props.put("-continue", "1"); // CLI default 151 CLP.parse(av, props); 152 //System.out.println(props+" ++ "+av); 153 File source = asFile(props.get("-source:")); 154 File dest = asFile(props.get("-dest:")); 155 String encoding = props.get("-encoding:"); 156 boolean contError = props.containsKey("-continue"); 157 ClassReader options = new ClassReader(); 158 options.copyOptionsFrom(props); 159 /* 160 if (dest == null && av.size() > 1) { 161 dest = File.createTempFile("TestOut", ".dir", new File(".")); 162 dest.delete(); 163 if (!dest.mkdir()) 164 throw new RuntimeException("Cannot create "+dest); 165 System.out.println("Writing results to "+dest); 166 } 167 */ 168 if (av.isEmpty()) { 169 av.add(""); //to enter this loop 170 } 171 boolean readList = false; 172 for (String a : av) { 173 if (readList) { 174 readList = false; 175 InputStream fin; 176 if (a.equals("-")) { 177 fin = System.in; 178 } else { 179 fin = new FileInputStream(a); 180 } 181 182 BufferedReader files = makeReader(fin, encoding); 183 for (String file; (file = files.readLine()) != null;) { 184 doFile(file, source, dest, options, encoding, contError); 185 } 186 if (fin != System.in) { 187 fin.close(); 188 } 189 } else if (a.equals("-@")) { 190 readList = true; 191 } else if (a.startsWith("-")) { 192 throw new RuntimeException("Bad flag argument: " + a); 193 } else if (source.getName().endsWith(".jar")) { 194 doJar(a, source, dest, options, encoding, contError); 195 } else { 196 doFile(a, source, dest, options, encoding, contError); 197 } 198 } 199 } 200 201 private static File asFile(String str) { 202 return (str == null) ? null : new File(str); 203 } 204 205 private static void doFile(String a, 206 File source, File dest, 207 ClassReader options, String encoding, 208 boolean contError) throws IOException { 209 if (!contError) { 210 doFile(a, source, dest, options, encoding); 211 } else { 212 try { 213 doFile(a, source, dest, options, encoding); 214 } catch (Exception ee) { 215 System.out.println("Error processing " + source + ": " + ee); 216 ee.printStackTrace(); 217 } 218 } 219 } 220 221 private static void doJar(String a, File source, File dest, 222 ClassReader options, String encoding, 223 Boolean contError) throws IOException { 224 try { 225 JarFile jf = new JarFile(source); 226 for (JarEntry je : Collections.list(jf.entries())) { 227 String name = je.getName(); 228 if (!name.endsWith(".class")) { 229 continue; 230 } 231 try { 232 doStream(name, jf.getInputStream(je), dest, options, encoding); 233 } catch (Exception e) { 234 if (contError) { 235 System.out.println("Error processing " + source + ": " + e); 236 e.printStackTrace(); 237 continue; 238 } 239 } 240 } 241 } catch (IOException ioe) { 242 throw ioe; 243 } 244 } 245 246 private static void doStream(String a, InputStream in, File dest, 247 ClassReader options, String encoding) throws IOException { 248 249 File f = new File(a); 250 ClassReader cr = new ClassReader(options); 251 Element e; 252 if (options.verbose) { 253 System.out.println("Reading " + f); 254 } 255 e = cr.readFrom(in); 256 257 OutputStream out; 258 if (dest == null) { 259 out = System.out; 260 } else { 261 File outf = new File(dest, f.isAbsolute() ? f.getName() : f.getPath()); 262 String outName = outf.getName(); 263 File outSubdir = outf.getParentFile(); 264 outSubdir.mkdirs(); 265 int extPos = outName.lastIndexOf('.'); 266 if (extPos > 0) { 267 outf = new File(outSubdir, outName.substring(0, extPos) + ".xml"); 268 } 269 out = new FileOutputStream(outf); 270 } 271 272 Writer outw = makeWriter(out, encoding); 273 if (options.pretty || !options.keepOrder) { 274 e.writePrettyTo(outw); 275 } else { 276 e.writeTo(outw); 277 } 278 if (out == System.out) { 279 outw.write("\n"); 280 outw.flush(); 281 } else { 282 outw.close(); 283 } 284 } 285 286 private static void doFile(String a, 287 File source, File dest, 288 ClassReader options, String encoding) throws IOException { 289 File inf = new File(source, a); 290 if (dest != null && options.verbose) { 291 System.out.println("Reading " + inf); 292 } 293 294 BufferedInputStream in = new BufferedInputStream(new FileInputStream(inf)); 295 296 doStream(a, in, dest, options, encoding); 297 298 } 299 300 public static BufferedReader makeReader(InputStream in, 301 String encoding) throws IOException { 302 Reader inw; 303 in = new BufferedInputStream(in); // add buffering 304 if (encoding == null) { 305 inw = new InputStreamReader(in); 306 } else { 307 inw = new InputStreamReader(in, encoding); 308 } 309 return new BufferedReader(inw); // add buffering 310 } 311 312 public static Writer makeWriter(OutputStream out, 313 String encoding) throws IOException { 314 Writer outw; 315 if (encoding == null) { 316 outw = new OutputStreamWriter(out); 317 } else { 318 outw = new OutputStreamWriter(out, encoding); 319 } 320 return new BufferedWriter(outw); // add buffering 321 } 322 323 public Element result() { 324 return cfile; 325 } 326 327 protected InputStream in; 328 protected ByteArrayOutputStream buf = new ByteArrayOutputStream(1024); 329 // input options 330 public boolean pretty = false; 331 public boolean verbose = false; 332 public boolean keepPath = false; 333 public boolean keepCP = false; 334 public boolean keepBytes = false; 335 public boolean parseBytes = true; 336 public boolean resolveRefs = true; 337 public boolean keepOrder = true; 338 public boolean keepSizes = false; 339 340 public ClassReader() { 341 cfile = new Element("ClassFile"); 342 } 343 344 public ClassReader(ClassReader options) { 345 this(); 346 copyOptionsFrom(options); 347 } 348 349 public void copyOptionsFrom(ClassReader options) { 350 pretty = options.pretty; 351 verbose = options.verbose; 352 keepPath = options.keepPath; 353 keepCP = options.keepCP; 354 keepOrder = options.keepOrder; 355 } 356 357 public void copyOptionsFrom(Map<String, String> options) { 358 if (options.containsKey("-pretty")) { 359 pretty = (options.get("-pretty") != null); 360 } 361 if (options.containsKey("-verbose")) { 362 verbose = (options.get("-verbose") != null); 363 } 364 if (options.containsKey("-keepPath")) { 365 keepPath = (options.get("-keepPath") != null); 366 } 367 if (options.containsKey("-keepCP")) { 368 keepCP = (options.get("-keepCP") != null); 369 } 370 if (options.containsKey("-keepOrder")) { 371 keepOrder = (options.get("-keepOrder") != null); 372 } 373 } 374 375 protected String getCpString(int i) { 376 return thePool.get(i); 377 } 378 379 public Element readFrom(InputStream in) throws IOException { 380 try { 381 this.in = in; 382 ClassFile c = ClassFile.read(in); 383 // read the file header 384 if (c.magic != 0xCAFEBABE) { 385 throw new RuntimeException("bad magic number " + 386 Integer.toHexString(c.magic)); 387 } 388 cfile.setAttr("magic", "" + c.magic); 389 int minver = c.minor_version; 390 int majver = c.major_version; 391 cfile.setAttr("minver", "" + minver); 392 cfile.setAttr("majver", "" + majver); 393 readCP(c); 394 readClass(c); 395 return result(); 396 } catch (InvalidDescriptor | ConstantPoolException ex) { 397 throw new IOException("Fatal error", ex); 398 } 399 } 400 401 public Element readFrom(File file) throws IOException { 402 try (InputStream strm = new FileInputStream(file)) { 403 Element e = readFrom(new BufferedInputStream(strm)); 404 if (keepPath) { 405 e.setAttr("path", file.toString()); 406 } 407 return e; 408 } 409 } 410 411 private void readClass(ClassFile c) throws IOException, 412 ConstantPoolException, 413 InvalidDescriptor { 414 klass = new Element("Class"); 415 cfile.add(klass); 416 String thisk = c.getName(); 417 418 klass.setAttr("name", thisk); 419 420 AccessFlags af = new AccessFlags(c.access_flags.flags); 421 klass.setAttr("flags", flagString(af, klass)); 422 if (!"java/lang/Object".equals(thisk)) { 423 if (c.super_class != 0) { 424 klass.setAttr("super", c.getSuperclassName()); 425 } 426 } 427 for (int i : c.interfaces) { 428 klass.add(new Element("Interface", "name", getCpString(i))); 429 } 430 readFields(c, klass); 431 readMethods(c, klass); 432 readAttributesFor(c, c.attributes, klass); 433 klass.trimToSize(); 434 } 435 436 private void readFields(ClassFile c, Element klass) throws IOException { 437 int len = c.fields.length; 438 Element fields = new Element(len); 439 for (Field f : c.fields) { 440 Element field = new Element("Field"); 441 field.setAttr("name", getCpString(f.name_index)); 442 field.setAttr("type", getCpString(f.descriptor.index)); 443 field.setAttr("flags", flagString(f.access_flags.flags, field)); 444 readAttributesFor(c, f.attributes, field); 445 446 field.trimToSize(); 447 fields.add(field); 448 } 449 if (!keepOrder) { 450 fields.sort(); 451 } 452 klass.addAll(fields); 453 } 454 455 456 private void readMethods(ClassFile c, Element klass) throws IOException { 457 int len = c.methods.length; 458 Element methods = new Element(len); 459 for (Method m : c.methods) { 460 Element member = new Element("Method"); 461 member.setAttr("name", getCpString(m.name_index)); 462 member.setAttr("type", getCpString(m.descriptor.index)); 463 member.setAttr("flags", flagString(m.access_flags.flags, member)); 464 readAttributesFor(c, m.attributes, member); 465 466 member.trimToSize(); 467 methods.add(member); 468 } 469 if (!keepOrder) { 470 methods.sort(); 471 } 472 klass.addAll(methods); 473 } 474 475 private AccessFlags.Kind getKind(Element e) { 476 switch(e.getName()) { 477 case "Class": 478 return AccessFlags.Kind.Class; 479 case "InnerClass": 480 return AccessFlags.Kind.InnerClass; 481 case "Field": 482 return AccessFlags.Kind.Field ; 483 case "Method": 484 return AccessFlags.Kind.Method; 485 default: throw new RuntimeException("should not reach here"); 486 } 487 } 488 489 protected String flagString(int flags, Element holder) { 490 return flagString(new AccessFlags(flags), holder); 491 } 492 protected String flagString(AccessFlags af, Element holder) { 493 return flagString(af, holder.getName()); 494 } 495 protected String flagString(int flags, String kind) { 496 return flagString(new AccessFlags(flags), kind); 497 } 498 protected String flagString(AccessFlags af, String kind) { 499 Set<String> mods = null; 500 switch (kind) { 501 case "Class": 502 mods = af.getClassFlags(); 503 break; 504 case "InnerClass": 505 mods = af.getInnerClassFlags(); 506 break; 507 case "Field": 508 mods = af.getFieldFlags(); 509 break; 510 case "Method": 511 mods = af.getMethodFlags(); 512 break; 513 default: 514 throw new RuntimeException("should not reach here"); 515 } 516 StringBuilder sb = new StringBuilder(); 517 for (String x : mods) { 518 sb.append(x.substring(x.indexOf('_') + 1).toLowerCase()).append(" "); 519 } 520 return sb.toString().trim(); 521 } 522 523 524 protected void readAttributesFor(ClassFile c, Attributes attrs, Element x) { 525 Element container = new Element(); 526 AttributeVisitor av = new AttributeVisitor(this, c); 527 for (Attribute a : attrs) { 528 av.visit(a, container); 529 } 530 if (!keepOrder) { 531 container.sort(); 532 } 533 x.addAll(container); 534 } 535 536 private int fileSize = 0; 537 private HashMap<String, int[]> attrSizes = new HashMap<>(); 538 539 private void attachTo(Element x, Object aval0) { 540 if (aval0 == null) { 541 return; 542 } 543 if (!(aval0 instanceof Element)) { 544 x.add(aval0); 545 return; 546 } 547 Element aval = (Element) aval0; 548 if (!aval.isAnonymous()) { 549 x.add(aval); 550 return; 551 } 552 for (int imax = aval.attrSize(), i = 0; i < imax; i++) { 553 //%% 554 attachAttrTo(x, aval.getAttrName(i), aval.getAttr(i)); 555 } 556 x.addAll(aval); 557 } 558 559 private void attachAttrTo(Element x, String aname, String aval) { 560 String aval0 = x.getAttr(aname); 561 if (aval0 != null) { 562 aval = aval0 + " " + aval; 563 } 564 x.setAttr(aname, aval); 565 } 566 567 private void readCP(ClassFile c) throws IOException { 568 cpool = new Element("ConstantPool", c.constant_pool.size()); 569 ConstantPoolVisitor cpv = new ConstantPoolVisitor(cpool, c, 570 c.constant_pool.size()); 571 for (int i = 1 ; i < c.constant_pool.size() ; i++) { 572 try { 573 cpv.visit(c.constant_pool.get(i), i); 574 } catch (InvalidIndex ex) { 575 // can happen periodically when accessing doubles etc. ignore it 576 // ex.printStackTrace(); 577 } 578 } 579 thePool = cpv.getPoolList(); 580 if (verbose) { 581 for (int i = 0; i < thePool.size(); i++) { 582 System.out.println("[" + i + "]: " + thePool.get(i)); 583 } 584 } 585 if (keepCP) { 586 cfile.add(cpool); 587 } 588 } 589 } 590 591 class ConstantPoolVisitor implements ConstantPool.Visitor<String, Integer> { 592 final List<String> slist; 593 final Element xpool; 594 final ClassFile cf; 595 final ConstantPool cfpool; 596 final List<String> bsmlist; 597 598 599 public ConstantPoolVisitor(Element xpool, ClassFile cf, int size) { 600 slist = new ArrayList<>(size); 601 for (int i = 0 ; i < size; i++) { 602 slist.add(null); 603 } 604 this.xpool = xpool; 605 this.cf = cf; 606 this.cfpool = cf.constant_pool; 607 bsmlist = readBSM(); 608 } 609 610 public List<String> getPoolList() { 611 return Collections.unmodifiableList(slist); 612 } 613 614 public List<String> getBSMList() { 615 return Collections.unmodifiableList(bsmlist); 616 } 617 618 public String visit(CPInfo c, int index) { 619 return c.accept(this, index); 620 } 621 622 private List<String> readBSM() { 623 BootstrapMethods_attribute bsmAttr = 624 (BootstrapMethods_attribute) cf.getAttribute(Attribute.BootstrapMethods); 625 if (bsmAttr != null) { 626 List<String> out = 627 new ArrayList<>(bsmAttr.bootstrap_method_specifiers.length); 628 for (BootstrapMethods_attribute.BootstrapMethodSpecifier bsms : 629 bsmAttr.bootstrap_method_specifiers) { 630 int index = bsms.bootstrap_method_ref; 631 try { 632 String value = slist.get(index); 633 String bsmStr = value; 634 if (value == null) { 635 value = visit(cfpool.get(index), index); 636 slist.set(index, value); 637 } 638 bsmStr = value; 639 for (int idx : bsms.bootstrap_arguments) { 640 value = slist.get(idx); 641 if (value == null) { 642 value = visit(cfpool.get(idx), idx); 643 slist.set(idx, value); 644 } 645 bsmStr = bsmStr.concat("," + value); 646 } 647 out.add(bsmStr); 648 } catch (InvalidIndex ex) { 649 ex.printStackTrace(); 650 } 651 } 652 return out; 653 } 654 return new ArrayList<>(0); 655 } 656 657 @Override 658 public String visitClass(CONSTANT_Class_info c, Integer p) { 659 String value = slist.get(p); 660 if (value == null) { 661 try { 662 value = visit(cfpool.get(c.name_index), c.name_index); 663 slist.set(p, value); 664 xpool.add(new Element("CONSTANT_Class", 665 new String[]{"id", p.toString()}, 666 value)); 667 } catch (ConstantPoolException ex) { 668 ex.printStackTrace(); 669 } 670 } 671 return value; 672 } 673 674 @Override 675 public String visitModule(CONSTANT_Module_info info, Integer p) { 676 String value = slist.get(p); 677 if (value == null) { 678 try { 679 value = visit(cfpool.get(info.name_index), info.name_index); 680 slist.set(p, value); 681 xpool.add(new Element("CONSTANT_Module", 682 new String[]{"id", p.toString()}, 683 value)); 684 } catch (ConstantPoolException ex) { 685 ex.printStackTrace(); 686 } 687 } 688 return value; 689 } 690 691 @Override 692 public String visitPackage(CONSTANT_Package_info info, Integer p) { 693 String value = slist.get(p); 694 if (value == null) { 695 try { 696 value = visit(cfpool.get(info.name_index), info.name_index); 697 slist.set(p, value); 698 xpool.add(new Element("CONSTANT_Package", 699 new String[]{"id", p.toString()}, 700 value)); 701 } catch (ConstantPoolException ex) { 702 ex.printStackTrace(); 703 } 704 } 705 return value; 706 } 707 708 @Override 709 public String visitDouble(CONSTANT_Double_info c, Integer p) { 710 String value = slist.get(p); 711 if (value == null) { 712 value = Double.toString(c.value); 713 slist.set(p, value); 714 xpool.add(new Element("CONSTANT_Double", 715 new String[]{"id", p.toString()}, 716 value)); 717 } 718 return value; 719 } 720 721 @Override 722 public String visitFieldref(CONSTANT_Fieldref_info c, Integer p) { 723 String value = slist.get(p); 724 if (value == null) { 725 try { 726 value = visit(cfpool.get(c.class_index), c.class_index); 727 value = value.concat(" " + visit(cfpool.get(c.name_and_type_index), 728 c.name_and_type_index)); 729 slist.set(p, value); 730 xpool.add(new Element("CONSTANT_Fieldref", 731 new String[]{"id", p.toString()}, 732 value)); 733 } catch (ConstantPoolException ex) { 734 ex.printStackTrace(); 735 } 736 } 737 return value; 738 } 739 740 @Override 741 public String visitFloat(CONSTANT_Float_info c, Integer p) { 742 String value = slist.get(p); 743 if (value == null) { 744 value = Float.toString(c.value); 745 slist.set(p, value); 746 xpool.add(new Element("CONSTANT_Float", 747 new String[]{"id", p.toString()}, 748 value)); 749 } 750 return value; 751 } 752 753 @Override 754 public String visitInteger(CONSTANT_Integer_info cnstnt, Integer p) { 755 String value = slist.get(p); 756 if (value == null) { 757 value = Integer.toString(cnstnt.value); 758 slist.set(p, value); 759 xpool.add(new Element("CONSTANT_Integer", 760 new String[]{"id", p.toString()}, 761 value)); 762 } 763 return value; 764 } 765 766 @Override 767 public String visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info c, 768 Integer p) { 769 String value = slist.get(p); 770 if (value == null) { 771 try { 772 value = visit(cfpool.get(c.class_index), c.class_index); 773 value = value.concat(" " + 774 visit(cfpool.get(c.name_and_type_index), 775 c.name_and_type_index)); 776 slist.set(p, value); 777 xpool.add(new Element("CONSTANT_InterfaceMethodref", 778 new String[]{"id", p.toString()}, 779 value)); 780 781 } catch (ConstantPoolException ex) { 782 ex.printStackTrace(); 783 } 784 } 785 return value; 786 } 787 788 @Override 789 public String visitInvokeDynamic(CONSTANT_InvokeDynamic_info c, Integer p) { 790 String value = slist.get(p); 791 if (value == null) { 792 try { 793 value = bsmlist.get(c.bootstrap_method_attr_index) + " " 794 + visit(cfpool.get(c.name_and_type_index), c.name_and_type_index); 795 slist.set(p, value); 796 xpool.add(new Element("CONSTANT_InvokeDynamic", 797 new String[]{"id", p.toString()}, 798 value)); 799 800 } catch (ConstantPoolException ex) { 801 ex.printStackTrace(); 802 } 803 } 804 return value; 805 } 806 807 @Override 808 public String visitLong(CONSTANT_Long_info c, Integer p) { 809 String value = slist.get(p); 810 if (value == null) { 811 value = Long.toString(c.value); 812 slist.set(p, value); 813 xpool.add(new Element("CONSTANT_Long", 814 new String[]{"id", p.toString()}, 815 value)); 816 } 817 return value; 818 } 819 820 @Override 821 public String visitNameAndType(CONSTANT_NameAndType_info c, Integer p) { 822 String value = slist.get(p); 823 if (value == null) { 824 try { 825 value = visit(cfpool.get(c.name_index), c.name_index); 826 value = value.concat(" " + 827 visit(cfpool.get(c.type_index), c.type_index)); 828 slist.set(p, value); 829 xpool.add(new Element("CONSTANT_NameAndType", 830 new String[]{"id", p.toString()}, 831 value)); 832 } catch (InvalidIndex ex) { 833 ex.printStackTrace(); 834 } 835 } 836 return value; 837 } 838 839 @Override 840 public String visitMethodref(CONSTANT_Methodref_info c, Integer p) { 841 String value = slist.get(p); 842 if (value == null) { 843 try { 844 value = visit(cfpool.get(c.class_index), c.class_index); 845 value = value.concat(" " + 846 visit(cfpool.get(c.name_and_type_index), 847 c.name_and_type_index)); 848 slist.set(p, value); 849 xpool.add(new Element("CONSTANT_Methodref", 850 new String[]{"id", p.toString()}, 851 value)); 852 853 } catch (ConstantPoolException ex) { 854 ex.printStackTrace(); 855 } 856 } 857 return value; 858 } 859 860 @Override 861 public String visitMethodHandle(CONSTANT_MethodHandle_info c, Integer p) { 862 String value = slist.get(p); 863 if (value == null) { 864 try { 865 value = c.reference_kind.name(); 866 value = value.concat(" " 867 + visit(cfpool.get(c.reference_index), c.reference_index)); 868 slist.set(p, value); 869 xpool.add(new Element("CONSTANT_MethodHandle", 870 new String[]{"id", p.toString()}, 871 value)); 872 873 } catch (ConstantPoolException ex) { 874 ex.printStackTrace(); 875 } 876 } 877 return value; 878 } 879 880 @Override 881 public String visitMethodType(CONSTANT_MethodType_info c, Integer p) { 882 String value = slist.get(p); 883 if (value == null) { 884 try { 885 value = visit(cfpool.get(c.descriptor_index), c.descriptor_index); 886 slist.set(p, value); 887 xpool.add(new Element("CONSTANT_MethodType", 888 new String[]{"id", p.toString()}, 889 value)); 890 } catch (ConstantPoolException ex) { 891 ex.printStackTrace(); 892 } 893 } 894 return value; 895 } 896 897 @Override 898 public String visitString(CONSTANT_String_info c, Integer p) { 899 try { 900 901 String value = slist.get(p); 902 if (value == null) { 903 value = c.getString(); 904 slist.set(p, value); 905 xpool.add(new Element("CONSTANT_String", 906 new String[]{"id", p.toString()}, 907 value)); 908 } 909 return value; 910 } catch (ConstantPoolException ex) { 911 throw new RuntimeException("Fatal error", ex); 912 } 913 } 914 915 @Override 916 public String visitUtf8(CONSTANT_Utf8_info cnstnt, Integer p) { 917 String value = slist.get(p); 918 if (value == null) { 919 value = cnstnt.value; 920 slist.set(p, value); 921 xpool.add(new Element("CONSTANT_Utf8", 922 new String[]{"id", p.toString()}, 923 value)); 924 } 925 return value; 926 927 } 928 } 929 930 class AttributeVisitor implements Attribute.Visitor<Element, Element> { 931 final ClassFile cf; 932 final ClassReader x; 933 final AnnotationsElementVisitor aev; 934 final InstructionVisitor iv; 935 936 public AttributeVisitor(ClassReader x, ClassFile cf) { 937 this.x = x; 938 this.cf = cf; 939 iv = new InstructionVisitor(x, cf); 940 aev = new AnnotationsElementVisitor(x, cf); 941 } 942 943 public void visit(Attribute a, Element parent) { 944 a.accept(this, parent); 945 } 946 947 @Override 948 public Element visitBootstrapMethods(BootstrapMethods_attribute bm, Element p) { 949 Element e = new Element(x.getCpString(bm.attribute_name_index)); 950 for (BootstrapMethods_attribute.BootstrapMethodSpecifier bsm : bm.bootstrap_method_specifiers) { 951 Element be = new Element("BootstrapMethodSpecifier"); 952 be.setAttr("ref", x.getCpString(bsm.bootstrap_method_ref)); 953 if (bsm.bootstrap_arguments.length > 0) { 954 Element bme = new Element("MethodArguments"); 955 for (int index : bsm.bootstrap_arguments) { 956 bme.add(x.getCpString(index)); 957 } 958 bme.trimToSize(); 959 be.add(bme); 960 } 961 be.trimToSize(); 962 e.add(be); 963 } 964 e.trimToSize(); 965 if (!x.keepOrder) { 966 e.sort(); 967 } 968 p.add(e); 969 return null; 970 } 971 972 @Override 973 public Element visitDefault(DefaultAttribute da, Element p) { 974 Element e = new Element(x.getCpString(da.attribute_name_index)); 975 StringBuilder sb = new StringBuilder(); 976 for (byte x : da.info) { 977 sb.append("0x").append(Integer.toHexString(x)).append(" "); 978 } 979 e.setAttr("bytes", sb.toString().trim()); 980 e.trimToSize(); 981 p.add(e); 982 return null; 983 } 984 985 @Override 986 public Element visitAnnotationDefault(AnnotationDefault_attribute ad, Element p) { 987 Element e = new Element(x.getCpString(ad.attribute_name_index)); 988 e.setAttr("tag", "" + ad.default_value.tag); 989 Element child = aev.visit(ad.default_value, e); 990 if (child != null) { 991 e.add(child); 992 } 993 e.trimToSize(); 994 p.add(e); 995 return null; 996 } 997 998 @Override 999 public Element visitCharacterRangeTable(CharacterRangeTable_attribute crt, 1000 Element p) { 1001 Element e = new Element(x.getCpString(crt.attribute_name_index)); 1002 for (CharacterRangeTable_attribute.Entry ce : crt.character_range_table) { 1003 e.setAttr("start_pc", "" + ce.start_pc); 1004 e.setAttr("end_pc", "" + ce.end_pc); 1005 e.setAttr("range_start", "" + ce.character_range_start); 1006 e.setAttr("range_end", "" + ce.character_range_end); 1007 e.setAttr("flags", x.flagString(ce.flags, "Method")); 1008 } 1009 e.trimToSize(); 1010 p.add(e); 1011 return null; 1012 } 1013 1014 private Element instructions(Element code, Code_attribute c) { 1015 Element ielement = new Element("Instructions"); 1016 for (Instruction ins : c.getInstructions()) { 1017 ielement.add(iv.visit(ins)); 1018 } 1019 ielement.trimToSize(); 1020 return ielement; 1021 } 1022 1023 @Override 1024 public Element visitCode(Code_attribute c, Element p) { 1025 Element e = null; 1026 1027 e = new Element(x.getCpString(c.attribute_name_index), 1028 "stack", "" + c.max_stack, 1029 "local", "" + c.max_locals); 1030 1031 e.add(instructions(e, c)); 1032 1033 for (Code_attribute.Exception_data edata : c.exception_table) { 1034 e.add(new Element("Handler", 1035 "start", "" + edata.start_pc, 1036 "end", "" + edata.end_pc, 1037 "catch", "" + edata.handler_pc, 1038 "class", x.getCpString(edata.catch_type))); 1039 1040 } 1041 this.x.readAttributesFor(cf, c.attributes, e); 1042 e.trimToSize(); 1043 p.add(e); 1044 return null; 1045 } 1046 1047 @Override 1048 public Element visitCompilationID(CompilationID_attribute cid, Element p) { 1049 Element e = new Element(x.getCpString(cid.attribute_name_index), 1050 x.getCpString(cid.compilationID_index)); 1051 p.add(e); 1052 return null; 1053 } 1054 1055 @Override 1056 public Element visitModulePackages(ModulePackages_attribute attr, Element p) { 1057 Element e = new Element(x.getCpString(attr.attribute_name_index)); 1058 for (int i : attr.packages_index) { 1059 Element ee = new Element("Package"); 1060 String pkg = x.getCpString(i); 1061 ee.setAttr("package", pkg); 1062 e.add(ee); 1063 } 1064 e.trimToSize(); 1065 e.sort(); 1066 p.add(e); 1067 return null; 1068 } 1069 1070 @Override 1071 public Element visitConstantValue(ConstantValue_attribute cv, Element p) { 1072 Element e = new Element(x.getCpString(cv.attribute_name_index)); 1073 e.add(x.getCpString(cv.constantvalue_index)); 1074 p.add(e); 1075 return null; 1076 } 1077 1078 @Override 1079 public Element visitDeprecated(Deprecated_attribute d, Element p) { 1080 Element e = new Element(x.getCpString(d.attribute_name_index)); 1081 p.add(e); 1082 return null; 1083 } 1084 1085 @Override 1086 public Element visitEnclosingMethod(EnclosingMethod_attribute em, Element p) { 1087 Element e = new Element(x.getCpString(em.attribute_name_index)); 1088 e.setAttr("class", x.getCpString(em.class_index)); 1089 e.setAttr("desc", x.getCpString(em.method_index)); 1090 e.trimToSize(); 1091 p.add(e); 1092 return null; 1093 } 1094 1095 @Override 1096 public Element visitExceptions(Exceptions_attribute e, Element p) { 1097 Element ee = new Element(x.getCpString(e.attribute_name_index)); 1098 for (int idx : e.exception_index_table) { 1099 Element n = new Element("Item"); 1100 n.setAttr("class", x.getCpString(idx)); 1101 ee.add(n); 1102 } 1103 ee.trimToSize(); 1104 p.add(ee); 1105 return null; 1106 } 1107 1108 @Override 1109 public Element visitInnerClasses(InnerClasses_attribute ic, Element p) { 1110 for (Info info : ic.classes) { 1111 Element e = new Element(x.getCpString(ic.attribute_name_index)); 1112 e.setAttr("class", x.getCpString(info.inner_class_info_index)); 1113 e.setAttr("outer", x.getCpString(info.outer_class_info_index)); 1114 e.setAttr("name", x.getCpString(info.inner_name_index)); 1115 e.setAttr("flags", x.flagString(info.inner_class_access_flags, 1116 "InnerClass")); 1117 e.trimToSize(); 1118 p.add(e); 1119 } 1120 return null; 1121 } 1122 1123 @Override 1124 public Element visitLineNumberTable(LineNumberTable_attribute lnt, Element p) { 1125 String name = x.getCpString(lnt.attribute_name_index); 1126 for (LineNumberTable_attribute.Entry e : lnt.line_number_table) { 1127 Element l = new Element(name); 1128 l.setAttr("bci", "" + e.start_pc); 1129 l.setAttr("line", "" + e.line_number); 1130 l.trimToSize(); 1131 p.add(l); 1132 } 1133 return null; // already added to parent 1134 } 1135 1136 @Override 1137 public Element visitLocalVariableTable(LocalVariableTable_attribute lvt, 1138 Element p) { 1139 String name = x.getCpString(lvt.attribute_name_index); 1140 for (LocalVariableTable_attribute.Entry e : lvt.local_variable_table) { 1141 Element l = new Element(name); 1142 l.setAttr("bci", "" + e.start_pc); 1143 l.setAttr("span", "" + e.length); 1144 l.setAttr("name", x.getCpString(e.name_index)); 1145 l.setAttr("type", x.getCpString(e.descriptor_index)); 1146 l.setAttr("slot", "" + e.index); 1147 l.trimToSize(); 1148 p.add(l); 1149 } 1150 return null; // already added to parent 1151 } 1152 1153 private void parseModuleRequires(RequiresEntry[] res, Element p) { 1154 for (RequiresEntry re : res) { 1155 Element er = new Element("Requires"); 1156 er.setAttr("module", x.getCpString(re.requires_index)); 1157 er.setAttr("flags", Integer.toString(re.requires_flags)); 1158 p.add(er); 1159 } 1160 } 1161 1162 private void parseModuleExports(ExportsEntry[] exports, Element p) { 1163 Element ex = new Element("Exports"); 1164 for (ExportsEntry export : exports) { 1165 Element exto = new Element("exports"); 1166 exto.setAttr("package", x.getCpString(export.exports_index)); 1167 for (int idx : export.exports_to_index) { 1168 exto.setAttr("module", x.getCpString(idx)); 1169 } 1170 ex.add(exto); 1171 } 1172 p.add(ex); 1173 } 1174 1175 private void parseModuleProvides(ProvidesEntry[] provides, Element p) { 1176 Element ex = new Element("Provides"); 1177 for (ProvidesEntry provide : provides) { 1178 ex.setAttr("provides", x.getCpString(provide.provides_index)); 1179 for (int idx : provide.with_index) { 1180 ex.setAttr("with", x.getCpString(idx)); 1181 } 1182 } 1183 p.add(ex); 1184 } 1185 1186 @Override 1187 public Element visitModule(Module_attribute m, Element p) { 1188 Element e = new Element(x.getCpString(m.attribute_name_index)); 1189 parseModuleRequires(m.requires, e); 1190 parseModuleExports(m.exports, e); 1191 for (int idx : m.uses_index) { 1192 Element ei = new Element("Uses"); 1193 ei.setAttr("used_class", x.getCpString(idx)); 1194 e.add(ei); 1195 } 1196 parseModuleProvides(m.provides, e); 1197 p.add(e); 1198 return null; 1199 } 1200 1201 @Override 1202 public Element visitLocalVariableTypeTable(LocalVariableTypeTable_attribute lvtt, 1203 Element p) { 1204 String name = x.getCpString(lvtt.attribute_name_index); 1205 for (LocalVariableTypeTable_attribute.Entry e : lvtt.local_variable_table) { 1206 Element l = new Element(name); 1207 l.setAttr("bci", "" + e.start_pc); 1208 l.setAttr("span", "" + e.length); 1209 l.setAttr("name", x.getCpString(e.name_index)); 1210 l.setAttr("type", x.getCpString(e.signature_index)); 1211 l.setAttr("slot", "" + e.index); 1212 l.trimToSize(); 1213 p.add(l); 1214 } 1215 return null; // already added to parent 1216 } 1217 1218 @Override 1219 public Element visitMethodParameters(MethodParameters_attribute mp, Element p) { 1220 String name = x.getCpString(mp.attribute_name_index); 1221 for (MethodParameters_attribute.Entry e : mp.method_parameter_table) { 1222 Element l = new Element(name); 1223 l.setAttr("name", x.getCpString(e.name_index)); 1224 l.setAttr("flag", "" + e.flags); 1225 l.trimToSize(); 1226 p.add(l); 1227 } 1228 return null; // already added to parent 1229 } 1230 private void parseAnnotation(Annotation anno, Element p) { 1231 Element ea = new Element("Annotation"); 1232 ea.setAttr("name", "" + x.getCpString(anno.type_index)); 1233 for (Annotation.element_value_pair evp : anno.element_value_pairs) { 1234 Element evpe = new Element("Element"); 1235 evpe.setAttr("tag", "" + evp.value.tag); 1236 evpe.setAttr("value", x.getCpString(evp.element_name_index)); 1237 Element child = aev.visit(evp.value, evpe); 1238 if (child != null) { 1239 evpe.add(child); 1240 } 1241 ea.add(evpe); 1242 } 1243 ea.trimToSize(); 1244 p.add(ea); 1245 } 1246 1247 private void parseAnnotations(Annotation[] ra, Element p) { 1248 for (Annotation anno : ra) { 1249 parseAnnotation(anno, p); 1250 } 1251 } 1252 1253 @Override 1254 public Element visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute rva, 1255 Element p) { 1256 Element e = new Element(x.getCpString(rva.attribute_name_index)); 1257 parseAnnotations(rva.annotations, e); 1258 e.trimToSize(); 1259 p.add(e); 1260 return null; 1261 } 1262 1263 @Override 1264 public Element visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute ria, 1265 Element p) { 1266 Element e = new Element(x.getCpString(ria.attribute_name_index)); 1267 parseAnnotations(ria.annotations, e); 1268 e.trimToSize(); 1269 p.add(e); 1270 return null; 1271 } 1272 1273 @Override 1274 public Element visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute rvpa, 1275 Element p) { 1276 Element e = new Element(x.getCpString(rvpa.attribute_name_index)); 1277 for (Annotation[] pa : rvpa.parameter_annotations) { 1278 parseAnnotations(pa, e); 1279 } 1280 p.add(e); 1281 return null; 1282 } 1283 1284 @Override 1285 public Element visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute ripa, 1286 Element p) { 1287 Element e = new Element(x.getCpString(ripa.attribute_name_index)); 1288 for (Annotation[] pa : ripa.parameter_annotations) { 1289 parseAnnotations(pa, e); 1290 } 1291 p.add(e); 1292 return null; 1293 } 1294 1295 private void parsePosition(Position ap, Element p) { 1296 Element te = new Element(); 1297 switch (ap.type) { 1298 case CLASS_TYPE_PARAMETER: // 0x00 1299 te.setName("CLASS_TYPE_PARAMETER"); 1300 te.setAttr("idx", "" + ap.parameter_index); 1301 break; 1302 case METHOD_TYPE_PARAMETER: // 0x01 1303 te.setName("METHOD_TYPE_PARAMETER"); 1304 te.setAttr("idx", "" + ap.parameter_index); 1305 break; 1306 case CLASS_EXTENDS: // 0x10 1307 te.setName("CLASS_EXTENDS"); 1308 te.setAttr("idx", "" + ap.type_index); 1309 break; 1310 case CLASS_TYPE_PARAMETER_BOUND: // 0x11 1311 te.setName("CLASS_TYPE_PARAMETER_BOUND"); 1312 te.setAttr("idx1", "" + ap.parameter_index); 1313 te.setAttr("idx2", "" + ap.bound_index); 1314 break; 1315 case METHOD_TYPE_PARAMETER_BOUND: // 0x12 1316 te.setName("METHOD_TYPE_PARAMETER_BOUND"); 1317 te.setAttr("idx1", "" + ap.parameter_index); 1318 te.setAttr("idx2", "" + ap.bound_index); 1319 break; 1320 case FIELD: // 0x13 1321 te.setName("FIELD"); 1322 break; 1323 case METHOD_RETURN: // 0x14 1324 te.setName("METHOD_RETURN"); 1325 break; 1326 case METHOD_RECEIVER: // 0x15 1327 te.setName("METHOD_RECEIVER"); 1328 break; 1329 case METHOD_FORMAL_PARAMETER: // 0x16 1330 te.setName("METHOD_FORMAL_PARAMETER"); 1331 te.setAttr("idx", "" + ap.parameter_index); 1332 break; 1333 case THROWS: // 0x17 1334 te.setName("THROWS"); 1335 te.setAttr("idx", "" + ap.type_index); 1336 break; 1337 case LOCAL_VARIABLE: // 0x40 1338 te.setName("LOCAL_VARIABLE"); 1339 for (int i = 0; i < ap.lvarIndex.length; i++) { 1340 te.setAttr("lvar_idx_" + i, "" + ap.lvarIndex[i]); 1341 te.setAttr("lvar_len_" + i, "" + ap.lvarLength[i]); 1342 te.setAttr("lvar_off_" + i, "" + ap.lvarOffset[i]); 1343 } 1344 break; 1345 case RESOURCE_VARIABLE: // 0x41 1346 te.setName("RESOURCE_VARIABLE"); 1347 for (int i = 0; i < ap.lvarIndex.length ; i++) { 1348 te.setAttr("lvar_idx_" + i, "" + ap.lvarIndex[i]); 1349 te.setAttr("lvar_len_" + i, "" + ap.lvarLength[i]); 1350 te.setAttr("lvar_off_" + i, "" + ap.lvarOffset[i]); 1351 } 1352 break; 1353 case EXCEPTION_PARAMETER: // 0x42 1354 te.setName("EXCEPTION_PARAMETER"); 1355 te.setAttr("idx", "" + ap.exception_index); 1356 break; 1357 case INSTANCEOF: // 0x43 1358 te.setName("INSTANCE_OF"); 1359 te.setAttr("off", "" + ap.offset); 1360 break; 1361 case NEW: // 0x44 1362 te.setName("NEW"); 1363 te.setAttr("off", "" + ap.offset); 1364 break; 1365 case CONSTRUCTOR_REFERENCE: // 0x45 1366 te.setName("CONSTRUCTOR_REFERENCE_RECEIVER"); 1367 te.setAttr("off", "" + ap.offset); 1368 break; 1369 case METHOD_REFERENCE: // 0x46 1370 te.setName("METHOD_REFERENCE_RECEIVER"); 1371 te.setAttr("off", "" + ap.offset); 1372 break; 1373 case CAST: // 0x47 1374 te.setName("CAST"); 1375 te.setAttr("off", "" + ap.offset); 1376 te.setAttr("idx", "" + ap.type_index); 1377 break; 1378 case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: // 0x48 1379 te.setName("CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT"); 1380 te.setAttr("off", "" + ap.offset); 1381 te.setAttr("idx", "" + ap.type_index); 1382 break; 1383 case METHOD_INVOCATION_TYPE_ARGUMENT: // 0x49 1384 te.setName("METHOD_INVOCATION_TYPE_ARGUMENT"); 1385 te.setAttr("off", "" + ap.offset); 1386 te.setAttr("idx", "" + ap.type_index); 1387 break; 1388 case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: // 0x4A 1389 te.setName("CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT"); 1390 te.setAttr("off", "" + ap.offset); 1391 te.setAttr("idx", "" + ap.type_index); 1392 break; 1393 case METHOD_REFERENCE_TYPE_ARGUMENT: // 0x4B 1394 te.setName("METHOD_REFERENCE_TYPE_ARGUMENT"); 1395 te.setAttr("off", "" + ap.offset); 1396 te.setAttr("idx", "" + ap.type_index); 1397 break; 1398 default: 1399 throw new RuntimeException("not implemented"); 1400 } 1401 te.trimToSize(); 1402 p.add(te); 1403 } 1404 private void parseTypeAnnotations(TypeAnnotation pa, Element p) { 1405 Element pta = new Element("RuntimeVisibleTypeAnnotation"); 1406 p.add(pta); 1407 Position pos = pa.position; 1408 parsePosition(pos, pta); 1409 parseAnnotation(pa.annotation, pta); 1410 } 1411 1412 @Override 1413 public Element visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute rvta, Element p) { 1414 Element e = new Element(x.getCpString(rvta.attribute_name_index)); 1415 for (TypeAnnotation pa : rvta.annotations) { 1416 parseTypeAnnotations(pa, e); 1417 } 1418 e.sort(); 1419 p.add(e); 1420 return null; 1421 } 1422 1423 @Override 1424 public Element visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute rita, Element p) { 1425 Element e = new Element(x.getCpString(rita.attribute_name_index)); 1426 for (TypeAnnotation pa : rita.annotations) { 1427 parseTypeAnnotations(pa, e); 1428 } 1429 e.sort(); 1430 p.add(e); 1431 return null; 1432 } 1433 1434 @Override 1435 public Element visitSignature(Signature_attribute s, Element p) { 1436 String aname = x.getCpString(s.attribute_name_index); 1437 String sname = x.getCpString(s.signature_index); 1438 Element se = new Element(aname); 1439 se.add(sname); 1440 se.trimToSize(); 1441 p.add(se); 1442 return null; 1443 } 1444 1445 @Override 1446 public Element visitSourceDebugExtension(SourceDebugExtension_attribute sde, 1447 Element p) { 1448 String aname = x.getCpString(sde.attribute_name_index); 1449 Element se = new Element(aname); 1450 se.setAttr("val", sde.getValue()); 1451 se.trimToSize(); 1452 p.add(se); 1453 return null; 1454 } 1455 1456 @Override 1457 public Element visitSourceFile(SourceFile_attribute sf, Element p) { 1458 String aname = x.getCpString(sf.attribute_name_index); 1459 String sname = x.getCpString(sf.sourcefile_index); 1460 Element se = new Element(aname); 1461 se.add(sname); 1462 se.trimToSize(); 1463 p.add(se); 1464 return null; 1465 } 1466 1467 @Override 1468 public Element visitSourceID(SourceID_attribute sid, Element p) { 1469 Element e = new Element(x.getCpString(sid.attribute_name_index)); 1470 e.add(x.getCpString(sid.sourceID_index)); 1471 e.trimToSize(); 1472 p.add(e); 1473 return null; 1474 } 1475 1476 @Override 1477 public Element visitStackMap(StackMap_attribute sm, Element p) { 1478 throw new UnsupportedOperationException("Not supported yet."); 1479 } 1480 1481 @Override 1482 public Element visitStackMapTable(StackMapTable_attribute smt, Element p) { 1483 Element stackmap = new Element(x.getCpString(smt.attribute_name_index)); 1484 for (StackMapTable_attribute.stack_map_frame f : smt.entries) { 1485 StackMapVisitor smv = new StackMapVisitor(x, cf, stackmap); 1486 stackmap.add(smv.visit(f)); 1487 } 1488 stackmap.trimToSize(); 1489 p.add(stackmap); 1490 return null; 1491 } 1492 1493 @Override 1494 public Element visitSynthetic(Synthetic_attribute s, Element p) { 1495 Element e = new Element(x.getCpString(s.attribute_name_index)); 1496 e.trimToSize(); 1497 p.add(e); 1498 return null; 1499 } 1500 1501 @Override 1502 public Element visitModuleHashes(ModuleHashes_attribute attr, Element p) { 1503 Element e = new Element(x.getCpString(attr.attribute_name_index)); 1504 e.setAttr("Algorithm", x.getCpString(attr.algorithm_index)); 1505 for (Entry entry : attr.hashes_table) { 1506 Element ee = new Element("Entry"); 1507 String mn = x.getCpString(entry.module_name_index); 1508 ee.setAttr("module_name", mn); 1509 ee.setAttr("hash_length", "" + entry.hash.length); 1510 StringBuilder sb = new StringBuilder(); 1511 for (byte b: entry.hash) { 1512 sb.append(String.format("%02x", b & 0xff)); 1513 } 1514 ee.setAttr("hash", sb.toString()); 1515 ee.trimToSize(); 1516 e.add(ee); 1517 } 1518 e.trimToSize(); 1519 e.sort(); 1520 p.add(e); 1521 return null; 1522 } 1523 1524 @Override 1525 public Element visitModuleMainClass(ModuleMainClass_attribute attr, Element p) { 1526 Element e = new Element(x.getCpString(attr.attribute_name_index)); 1527 e.add(x.getCpString(attr.main_class_index)); 1528 e.trimToSize(); 1529 p.add(e); 1530 return null; 1531 } 1532 1533 @Override 1534 public Element visitModuleResolution(ModuleResolution_attribute attr, Element p) { 1535 Element e = new Element("ModuleResolution"); 1536 e.setAttr("flags", Integer.toString(attr.resolution_flags)); 1537 e.trimToSize(); 1538 p.add(e); 1539 return null; 1540 } 1541 1542 @Override 1543 public Element visitModuleTarget(ModuleTarget_attribute attr, Element p) { 1544 Element e = new Element(x.getCpString(attr.attribute_name_index)); 1545 e.add(x.getCpString(attr.os_name_index)); 1546 e.add(x.getCpString(attr.os_arch_index)); 1547 e.add(x.getCpString(attr.os_version_index)); 1548 e.trimToSize(); 1549 p.add(e); 1550 return null; 1551 } 1552 } 1553 1554 class StackMapVisitor implements StackMapTable_attribute.stack_map_frame.Visitor<Element, Void> { 1555 1556 final ClassFile cf; 1557 final ClassReader x; 1558 final Element parent; 1559 1560 public StackMapVisitor(ClassReader x, ClassFile cf, Element parent) { 1561 this.x = x; 1562 this.cf = cf; 1563 this.parent = parent; 1564 } 1565 1566 public Element visit(StackMapTable_attribute.stack_map_frame frame) { 1567 return frame.accept(this, null); 1568 } 1569 1570 @Override 1571 public Element visit_same_frame(same_frame sm_frm, Void p) { 1572 Element e = new Element("SameFrame"); 1573 e.setAttr("tag", "" + sm_frm.frame_type); 1574 return e; 1575 } 1576 1577 @Override 1578 public Element visit_same_locals_1_stack_item_frame(same_locals_1_stack_item_frame s, Void p) { 1579 Element e = new Element("SameLocals1StackItemFrame"); 1580 e.setAttr("tag", "" + s.frame_type); 1581 e.addAll(getVerificationTypeInfo("Stack", s.stack)); 1582 e.trimToSize(); 1583 return e; 1584 } 1585 1586 @Override 1587 public Element visit_same_locals_1_stack_item_frame_extended(same_locals_1_stack_item_frame_extended s, Void p) { 1588 Element e = new Element("SameLocals1StackItemFrameExtended"); 1589 e.setAttr("tag", "" + s.frame_type); 1590 e.addAll(getVerificationTypeInfo("Stack", s.stack)); 1591 e.trimToSize(); 1592 return e; 1593 } 1594 1595 @Override 1596 public Element visit_chop_frame(chop_frame c, Void p) { 1597 Element e = new Element("Chop" + (251 - c.frame_type)); 1598 e.setAttr("tag", "" + c.frame_type); 1599 e.setAttr("offset", "" + c.offset_delta); 1600 return e; 1601 } 1602 1603 @Override 1604 public Element visit_same_frame_extended(same_frame_extended s, Void p) { 1605 Element e = new Element("SameFrameExtended"); 1606 e.setAttr("tag", "" + s.frame_type); 1607 e.setAttr("offset", "" + s.offset_delta); 1608 return e; 1609 } 1610 1611 @Override 1612 public Element visit_append_frame(append_frame a, Void p) { 1613 Element e = new Element("AppendFrame" + (a.frame_type - 251)); 1614 e.setAttr("tag", "" + a.frame_type); 1615 e.addAll(getVerificationTypeInfo("Local", a.locals)); 1616 e.trimToSize(); 1617 return e; 1618 } 1619 1620 @Override 1621 public Element visit_full_frame(full_frame fl_frm, Void p) { 1622 Element e = new Element("FullFrame"); 1623 e.setAttr("tag", "" + fl_frm.frame_type); 1624 e.addAll(getVerificationTypeInfo("Local", fl_frm.locals)); 1625 e.trimToSize(); 1626 return e; 1627 } 1628 1629 private Element getVerificationTypeInfo(String kind, 1630 StackMapTable_attribute.verification_type_info velems[]) { 1631 Element container = new Element(velems.length); 1632 for (StackMapTable_attribute.verification_type_info v : velems) { 1633 Element ve = null; 1634 int offset = 0; 1635 int index = 0; 1636 switch (v.tag) { 1637 case StackMapTable_attribute.verification_type_info.ITEM_Top: 1638 ve = new Element("ITEM_Top"); 1639 break; 1640 case StackMapTable_attribute.verification_type_info.ITEM_Integer: 1641 ve = new Element("ITEM_Integer"); 1642 break; 1643 case StackMapTable_attribute.verification_type_info.ITEM_Float: 1644 ve = new Element("ITEM_Float"); 1645 break; 1646 case StackMapTable_attribute.verification_type_info.ITEM_Long: 1647 ve = new Element("ITEM_Long"); 1648 break; 1649 case StackMapTable_attribute.verification_type_info.ITEM_Double: 1650 ve = new Element("ITEM_Double"); 1651 break; 1652 case StackMapTable_attribute.verification_type_info.ITEM_Null: 1653 ve = new Element("ITEM_Null"); 1654 break; 1655 case StackMapTable_attribute.verification_type_info.ITEM_Uninitialized: 1656 ve = new Element("ITEM_Uninitialized"); 1657 offset = ((StackMapTable_attribute.Uninitialized_variable_info) v).offset; 1658 ve.setAttr("offset", "" + offset); 1659 break; 1660 case StackMapTable_attribute.verification_type_info.ITEM_UninitializedThis: 1661 ve = new Element("ITEM_UnitializedtThis"); 1662 break; 1663 case StackMapTable_attribute.verification_type_info.ITEM_Object: 1664 ve = new Element("ITEM_Object"); 1665 index = ((StackMapTable_attribute.Object_variable_info) v).cpool_index; 1666 ve.setAttr("class", x.getCpString(index)); 1667 break; 1668 default: 1669 ve = new Element("Unknown"); 1670 } 1671 Element kindE = new Element(kind); 1672 kindE.setAttr("tag", "" + v.tag); 1673 container.add(kindE); 1674 kindE.add(ve); 1675 } 1676 container.trimToSize(); 1677 return container; 1678 } 1679 } 1680 1681 class InstructionVisitor implements Instruction.KindVisitor<Element, Void> { 1682 1683 final ClassReader x; 1684 final ClassFile cf; 1685 1686 public InstructionVisitor(ClassReader x, ClassFile cf) { 1687 this.x = x; 1688 this.cf = cf; 1689 } 1690 1691 public Element visit(Instruction i) { 1692 Element ie = i.accept(this, null); 1693 ie.trimToSize(); 1694 return ie; 1695 } 1696 1697 @Override 1698 public Element visitNoOperands(Instruction i, Void p) { 1699 Opcode o = i.getOpcode(); 1700 Element e = new Element(i.getMnemonic()); 1701 if (o.opcode > 0xab && o.opcode <= 0xb1) { 1702 e.setAttr("pc", "" + i.getPC()); 1703 } 1704 return e; 1705 } 1706 1707 @Override 1708 public Element visitArrayType(Instruction i, TypeKind tk, Void p) { 1709 Element ie = new Element(i.getMnemonic()); 1710 ie.setAttr("num", "" + tk.value); 1711 ie.setAttr("val", tk.name); 1712 return ie; 1713 } 1714 1715 @Override 1716 public Element visitBranch(Instruction i, int i1, Void p) { 1717 Element ie = new Element(i.getMnemonic()); 1718 ie.setAttr("lab", "" + (i.getPC() + i1)); 1719 return ie; 1720 } 1721 1722 @Override 1723 public Element visitConstantPoolRef(Instruction i, int i1, Void p) { 1724 Element ie = new Element(i.getMnemonic()); 1725 ie.setAttr("ref", x.getCpString(i1)); 1726 return ie; 1727 } 1728 1729 @Override 1730 public Element visitConstantPoolRefAndValue(Instruction i, int i1, int i2, Void p) { 1731 // workaround for a potential bug in classfile 1732 Element ie = new Element(i.getMnemonic()); 1733 if (i.getOpcode().equals(Opcode.IINC_W)) { 1734 ie.setAttr("loc", "" + i1); 1735 ie.setAttr("num", "" + i2); 1736 } else { 1737 ie.setAttr("ref", x.getCpString(i1)); 1738 ie.setAttr("val", "" + i2); 1739 } 1740 return ie; 1741 } 1742 1743 @Override 1744 public Element visitLocal(Instruction i, int i1, Void p) { 1745 Element ie = new Element(i.getMnemonic()); 1746 ie.setAttr("loc", "" + i1); 1747 return ie; 1748 } 1749 1750 @Override 1751 public Element visitLocalAndValue(Instruction i, int i1, int i2, Void p) { 1752 Element ie = new Element(i.getMnemonic()); 1753 ie.setAttr("loc", "" + i1); 1754 ie.setAttr("num", "" + i2); 1755 return ie; 1756 } 1757 1758 @Override 1759 public Element visitLookupSwitch(Instruction i, int i1, int i2, int[] ints, 1760 int[] ints1, Void p) { 1761 Element ie = new Element(i.getMnemonic()); 1762 int pc = i.getPC(); 1763 ie.setAttr("lab", "" + (pc + i1)); 1764 for (int k = 0 ; k < i2 ; k++) { 1765 Element c = new Element("Case"); 1766 c.setAttr("num", "" + (ints[k])); 1767 c.setAttr("lab", "" + (pc + ints1[k])); 1768 c.trimToSize(); 1769 ie.add(c); 1770 } 1771 return ie; 1772 } 1773 1774 @Override 1775 public Element visitTableSwitch(Instruction i, int i1, int i2, int i3, 1776 int[] ints, Void p) { 1777 Element ie = new Element(i.getMnemonic()); 1778 int pc = i.getPC(); 1779 ie.setAttr("lab", "" + (pc + i1)); 1780 for (int k : ints) { 1781 Element c = new Element("Case"); 1782 c.setAttr("num", "" + (k + i2)); 1783 c.setAttr("lab", "" + (pc + k)); 1784 c.trimToSize(); 1785 ie.add(c); 1786 } 1787 return ie; 1788 } 1789 1790 @Override 1791 public Element visitValue(Instruction i, int i1, Void p) { 1792 Element ie = new Element(i.getMnemonic()); 1793 ie.setAttr("num", "" + i1); 1794 return ie; 1795 } 1796 1797 @Override 1798 public Element visitUnknown(Instruction i, Void p) { 1799 Element e = new Element(i.getMnemonic()); 1800 e.setAttr("pc", "" + i.getPC()); 1801 e.setAttr("opcode", "" + i.getOpcode().opcode); 1802 return e; 1803 } 1804 } 1805 1806 class AnnotationsElementVisitor implements Annotation.element_value.Visitor<Element, Element> { 1807 final ClassReader x; 1808 final ClassFile cf; 1809 1810 public AnnotationsElementVisitor(ClassReader x, ClassFile cf) { 1811 this.x = x; 1812 this.cf = cf; 1813 } 1814 1815 public Element visit(Annotation.element_value v, Element p) { 1816 return v.accept(this, p); 1817 } 1818 1819 @Override 1820 public Element visitPrimitive(Primitive_element_value e, Element p) { 1821 Element el = new Element("String"); 1822 el.setAttr("val", x.getCpString(e.const_value_index)); 1823 el.trimToSize(); 1824 return el; 1825 } 1826 1827 @Override 1828 public Element visitEnum(Enum_element_value e, Element p) { 1829 Element el = new Element("Enum"); 1830 el.setAttr("name", x.getCpString(e.const_name_index)); 1831 el.setAttr("type", x.getCpString(e.type_name_index)); 1832 el.trimToSize(); 1833 return el; 1834 } 1835 1836 @Override 1837 public Element visitClass(Class_element_value c, Element p) { 1838 Element el = new Element("Class"); 1839 el.setAttr("name", x.getCpString(c.class_info_index)); 1840 el.trimToSize(); 1841 return el; 1842 } 1843 1844 @Override 1845 public Element visitAnnotation(Annotation_element_value a, Element p) { 1846 Element el = new Element("Annotation"); 1847 Annotation anno = a.annotation_value; 1848 for (Annotation.element_value_pair evp : anno.element_value_pairs) { 1849 Element child = visit(evp.value, el); 1850 if (child != null) { 1851 el.add(child); 1852 } 1853 } 1854 el.trimToSize(); 1855 return el; 1856 } 1857 1858 @Override 1859 public Element visitArray(Array_element_value a, Element p) { 1860 Element el = new Element("Array"); 1861 for (Annotation.element_value v : a.values) { 1862 Element child = visit(v, el); 1863 if (child != null) { 1864 el.add(child); 1865 } 1866 } 1867 el.trimToSize(); 1868 return el; 1869 } 1870 }