1 /* 2 * Copyright (c) 2010, 2017, 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 visitDynamicConstant(ConstantPool.CONSTANT_Dynamic_info c, Integer p) { 809 String value = slist.get(p); 810 if (value == null) { 811 try { 812 value = bsmlist.get(c.bootstrap_method_attr_index) + " " 813 + visit(cfpool.get(c.name_and_type_index), c.name_and_type_index); 814 slist.set(p, value); 815 xpool.add(new Element("CONSTANT_Dynamic", 816 new String[]{"id", p.toString()}, 817 value)); 818 819 } catch (ConstantPoolException ex) { 820 ex.printStackTrace(); 821 } 822 } 823 return value; 824 } 825 826 @Override 827 public String visitLong(CONSTANT_Long_info c, Integer p) { 828 String value = slist.get(p); 829 if (value == null) { 830 value = Long.toString(c.value); 831 slist.set(p, value); 832 xpool.add(new Element("CONSTANT_Long", 833 new String[]{"id", p.toString()}, 834 value)); 835 } 836 return value; 837 } 838 839 @Override 840 public String visitNameAndType(CONSTANT_NameAndType_info c, Integer p) { 841 String value = slist.get(p); 842 if (value == null) { 843 try { 844 value = visit(cfpool.get(c.name_index), c.name_index); 845 value = value.concat(" " + 846 visit(cfpool.get(c.type_index), c.type_index)); 847 slist.set(p, value); 848 xpool.add(new Element("CONSTANT_NameAndType", 849 new String[]{"id", p.toString()}, 850 value)); 851 } catch (InvalidIndex ex) { 852 ex.printStackTrace(); 853 } 854 } 855 return value; 856 } 857 858 @Override 859 public String visitMethodref(CONSTANT_Methodref_info c, Integer p) { 860 String value = slist.get(p); 861 if (value == null) { 862 try { 863 value = visit(cfpool.get(c.class_index), c.class_index); 864 value = value.concat(" " + 865 visit(cfpool.get(c.name_and_type_index), 866 c.name_and_type_index)); 867 slist.set(p, value); 868 xpool.add(new Element("CONSTANT_Methodref", 869 new String[]{"id", p.toString()}, 870 value)); 871 872 } catch (ConstantPoolException ex) { 873 ex.printStackTrace(); 874 } 875 } 876 return value; 877 } 878 879 @Override 880 public String visitMethodHandle(CONSTANT_MethodHandle_info c, Integer p) { 881 String value = slist.get(p); 882 if (value == null) { 883 try { 884 value = c.reference_kind.name(); 885 value = value.concat(" " 886 + visit(cfpool.get(c.reference_index), c.reference_index)); 887 slist.set(p, value); 888 xpool.add(new Element("CONSTANT_MethodHandle", 889 new String[]{"id", p.toString()}, 890 value)); 891 892 } catch (ConstantPoolException ex) { 893 ex.printStackTrace(); 894 } 895 } 896 return value; 897 } 898 899 @Override 900 public String visitMethodType(CONSTANT_MethodType_info c, Integer p) { 901 String value = slist.get(p); 902 if (value == null) { 903 try { 904 value = visit(cfpool.get(c.descriptor_index), c.descriptor_index); 905 slist.set(p, value); 906 xpool.add(new Element("CONSTANT_MethodType", 907 new String[]{"id", p.toString()}, 908 value)); 909 } catch (ConstantPoolException ex) { 910 ex.printStackTrace(); 911 } 912 } 913 return value; 914 } 915 916 @Override 917 public String visitString(CONSTANT_String_info c, Integer p) { 918 try { 919 920 String value = slist.get(p); 921 if (value == null) { 922 value = c.getString(); 923 slist.set(p, value); 924 xpool.add(new Element("CONSTANT_String", 925 new String[]{"id", p.toString()}, 926 value)); 927 } 928 return value; 929 } catch (ConstantPoolException ex) { 930 throw new RuntimeException("Fatal error", ex); 931 } 932 } 933 934 @Override 935 public String visitUtf8(CONSTANT_Utf8_info cnstnt, Integer p) { 936 String value = slist.get(p); 937 if (value == null) { 938 value = cnstnt.value; 939 slist.set(p, value); 940 xpool.add(new Element("CONSTANT_Utf8", 941 new String[]{"id", p.toString()}, 942 value)); 943 } 944 return value; 945 946 } 947 } 948 949 class AttributeVisitor implements Attribute.Visitor<Element, Element> { 950 final ClassFile cf; 951 final ClassReader x; 952 final AnnotationsElementVisitor aev; 953 final InstructionVisitor iv; 954 955 public AttributeVisitor(ClassReader x, ClassFile cf) { 956 this.x = x; 957 this.cf = cf; 958 iv = new InstructionVisitor(x, cf); 959 aev = new AnnotationsElementVisitor(x, cf); 960 } 961 962 public void visit(Attribute a, Element parent) { 963 a.accept(this, parent); 964 } 965 966 @Override 967 public Element visitBootstrapMethods(BootstrapMethods_attribute bm, Element p) { 968 Element e = new Element(x.getCpString(bm.attribute_name_index)); 969 for (BootstrapMethods_attribute.BootstrapMethodSpecifier bsm : bm.bootstrap_method_specifiers) { 970 Element be = new Element("BootstrapMethodSpecifier"); 971 be.setAttr("ref", x.getCpString(bsm.bootstrap_method_ref)); 972 if (bsm.bootstrap_arguments.length > 0) { 973 Element bme = new Element("MethodArguments"); 974 for (int index : bsm.bootstrap_arguments) { 975 bme.add(x.getCpString(index)); 976 } 977 bme.trimToSize(); 978 be.add(bme); 979 } 980 be.trimToSize(); 981 e.add(be); 982 } 983 e.trimToSize(); 984 if (!x.keepOrder) { 985 e.sort(); 986 } 987 p.add(e); 988 return null; 989 } 990 991 @Override 992 public Element visitDefault(DefaultAttribute da, Element p) { 993 Element e = new Element(x.getCpString(da.attribute_name_index)); 994 StringBuilder sb = new StringBuilder(); 995 for (byte x : da.info) { 996 sb.append("0x").append(Integer.toHexString(x)).append(" "); 997 } 998 e.setAttr("bytes", sb.toString().trim()); 999 e.trimToSize(); 1000 p.add(e); 1001 return null; 1002 } 1003 1004 @Override 1005 public Element visitAnnotationDefault(AnnotationDefault_attribute ad, Element p) { 1006 Element e = new Element(x.getCpString(ad.attribute_name_index)); 1007 e.setAttr("tag", "" + ad.default_value.tag); 1008 Element child = aev.visit(ad.default_value, e); 1009 if (child != null) { 1010 e.add(child); 1011 } 1012 e.trimToSize(); 1013 p.add(e); 1014 return null; 1015 } 1016 1017 @Override 1018 public Element visitCharacterRangeTable(CharacterRangeTable_attribute crt, 1019 Element p) { 1020 Element e = new Element(x.getCpString(crt.attribute_name_index)); 1021 for (CharacterRangeTable_attribute.Entry ce : crt.character_range_table) { 1022 e.setAttr("start_pc", "" + ce.start_pc); 1023 e.setAttr("end_pc", "" + ce.end_pc); 1024 e.setAttr("range_start", "" + ce.character_range_start); 1025 e.setAttr("range_end", "" + ce.character_range_end); 1026 e.setAttr("flags", x.flagString(ce.flags, "Method")); 1027 } 1028 e.trimToSize(); 1029 p.add(e); 1030 return null; 1031 } 1032 1033 private Element instructions(Element code, Code_attribute c) { 1034 Element ielement = new Element("Instructions"); 1035 for (Instruction ins : c.getInstructions()) { 1036 ielement.add(iv.visit(ins)); 1037 } 1038 ielement.trimToSize(); 1039 return ielement; 1040 } 1041 1042 @Override 1043 public Element visitCode(Code_attribute c, Element p) { 1044 Element e = null; 1045 1046 e = new Element(x.getCpString(c.attribute_name_index), 1047 "stack", "" + c.max_stack, 1048 "local", "" + c.max_locals); 1049 1050 e.add(instructions(e, c)); 1051 1052 for (Code_attribute.Exception_data edata : c.exception_table) { 1053 e.add(new Element("Handler", 1054 "start", "" + edata.start_pc, 1055 "end", "" + edata.end_pc, 1056 "catch", "" + edata.handler_pc, 1057 "class", x.getCpString(edata.catch_type))); 1058 1059 } 1060 this.x.readAttributesFor(cf, c.attributes, e); 1061 e.trimToSize(); 1062 p.add(e); 1063 return null; 1064 } 1065 1066 @Override 1067 public Element visitCompilationID(CompilationID_attribute cid, Element p) { 1068 Element e = new Element(x.getCpString(cid.attribute_name_index), 1069 x.getCpString(cid.compilationID_index)); 1070 p.add(e); 1071 return null; 1072 } 1073 1074 @Override 1075 public Element visitModulePackages(ModulePackages_attribute attr, Element p) { 1076 Element e = new Element(x.getCpString(attr.attribute_name_index)); 1077 for (int i : attr.packages_index) { 1078 Element ee = new Element("Package"); 1079 String pkg = x.getCpString(i); 1080 ee.setAttr("package", pkg); 1081 e.add(ee); 1082 } 1083 e.trimToSize(); 1084 e.sort(); 1085 p.add(e); 1086 return null; 1087 } 1088 1089 @Override 1090 public Element visitConstantValue(ConstantValue_attribute cv, Element p) { 1091 Element e = new Element(x.getCpString(cv.attribute_name_index)); 1092 e.add(x.getCpString(cv.constantvalue_index)); 1093 p.add(e); 1094 return null; 1095 } 1096 1097 @Override 1098 public Element visitDeprecated(Deprecated_attribute d, Element p) { 1099 Element e = new Element(x.getCpString(d.attribute_name_index)); 1100 p.add(e); 1101 return null; 1102 } 1103 1104 @Override 1105 public Element visitEnclosingMethod(EnclosingMethod_attribute em, Element p) { 1106 Element e = new Element(x.getCpString(em.attribute_name_index)); 1107 e.setAttr("class", x.getCpString(em.class_index)); 1108 e.setAttr("desc", x.getCpString(em.method_index)); 1109 e.trimToSize(); 1110 p.add(e); 1111 return null; 1112 } 1113 1114 @Override 1115 public Element visitExceptions(Exceptions_attribute e, Element p) { 1116 Element ee = new Element(x.getCpString(e.attribute_name_index)); 1117 for (int idx : e.exception_index_table) { 1118 Element n = new Element("Item"); 1119 n.setAttr("class", x.getCpString(idx)); 1120 ee.add(n); 1121 } 1122 ee.trimToSize(); 1123 p.add(ee); 1124 return null; 1125 } 1126 1127 @Override 1128 public Element visitInnerClasses(InnerClasses_attribute ic, Element p) { 1129 for (Info info : ic.classes) { 1130 Element e = new Element(x.getCpString(ic.attribute_name_index)); 1131 e.setAttr("class", x.getCpString(info.inner_class_info_index)); 1132 e.setAttr("outer", x.getCpString(info.outer_class_info_index)); 1133 e.setAttr("name", x.getCpString(info.inner_name_index)); 1134 e.setAttr("flags", x.flagString(info.inner_class_access_flags, 1135 "InnerClass")); 1136 e.trimToSize(); 1137 p.add(e); 1138 } 1139 return null; 1140 } 1141 1142 @Override 1143 public Element visitLineNumberTable(LineNumberTable_attribute lnt, Element p) { 1144 String name = x.getCpString(lnt.attribute_name_index); 1145 for (LineNumberTable_attribute.Entry e : lnt.line_number_table) { 1146 Element l = new Element(name); 1147 l.setAttr("bci", "" + e.start_pc); 1148 l.setAttr("line", "" + e.line_number); 1149 l.trimToSize(); 1150 p.add(l); 1151 } 1152 return null; // already added to parent 1153 } 1154 1155 @Override 1156 public Element visitLocalVariableTable(LocalVariableTable_attribute lvt, 1157 Element p) { 1158 String name = x.getCpString(lvt.attribute_name_index); 1159 for (LocalVariableTable_attribute.Entry e : lvt.local_variable_table) { 1160 Element l = new Element(name); 1161 l.setAttr("bci", "" + e.start_pc); 1162 l.setAttr("span", "" + e.length); 1163 l.setAttr("name", x.getCpString(e.name_index)); 1164 l.setAttr("type", x.getCpString(e.descriptor_index)); 1165 l.setAttr("slot", "" + e.index); 1166 l.trimToSize(); 1167 p.add(l); 1168 } 1169 return null; // already added to parent 1170 } 1171 1172 private void parseModuleRequires(RequiresEntry[] res, Element p) { 1173 for (RequiresEntry re : res) { 1174 Element er = new Element("Requires"); 1175 er.setAttr("module", x.getCpString(re.requires_index)); 1176 er.setAttr("flags", Integer.toString(re.requires_flags)); 1177 p.add(er); 1178 } 1179 } 1180 1181 private void parseModuleExports(ExportsEntry[] exports, Element p) { 1182 Element ex = new Element("Exports"); 1183 for (ExportsEntry export : exports) { 1184 Element exto = new Element("exports"); 1185 exto.setAttr("package", x.getCpString(export.exports_index)); 1186 for (int idx : export.exports_to_index) { 1187 exto.setAttr("module", x.getCpString(idx)); 1188 } 1189 ex.add(exto); 1190 } 1191 p.add(ex); 1192 } 1193 1194 private void parseModuleProvides(ProvidesEntry[] provides, Element p) { 1195 Element ex = new Element("Provides"); 1196 for (ProvidesEntry provide : provides) { 1197 ex.setAttr("provides", x.getCpString(provide.provides_index)); 1198 for (int idx : provide.with_index) { 1199 ex.setAttr("with", x.getCpString(idx)); 1200 } 1201 } 1202 p.add(ex); 1203 } 1204 1205 @Override 1206 public Element visitModule(Module_attribute m, Element p) { 1207 Element e = new Element(x.getCpString(m.attribute_name_index)); 1208 parseModuleRequires(m.requires, e); 1209 parseModuleExports(m.exports, e); 1210 for (int idx : m.uses_index) { 1211 Element ei = new Element("Uses"); 1212 ei.setAttr("used_class", x.getCpString(idx)); 1213 e.add(ei); 1214 } 1215 parseModuleProvides(m.provides, e); 1216 p.add(e); 1217 return null; 1218 } 1219 1220 @Override 1221 public Element visitLocalVariableTypeTable(LocalVariableTypeTable_attribute lvtt, 1222 Element p) { 1223 String name = x.getCpString(lvtt.attribute_name_index); 1224 for (LocalVariableTypeTable_attribute.Entry e : lvtt.local_variable_table) { 1225 Element l = new Element(name); 1226 l.setAttr("bci", "" + e.start_pc); 1227 l.setAttr("span", "" + e.length); 1228 l.setAttr("name", x.getCpString(e.name_index)); 1229 l.setAttr("type", x.getCpString(e.signature_index)); 1230 l.setAttr("slot", "" + e.index); 1231 l.trimToSize(); 1232 p.add(l); 1233 } 1234 return null; // already added to parent 1235 } 1236 1237 @Override 1238 public Element visitMethodParameters(MethodParameters_attribute mp, Element p) { 1239 String name = x.getCpString(mp.attribute_name_index); 1240 for (MethodParameters_attribute.Entry e : mp.method_parameter_table) { 1241 Element l = new Element(name); 1242 l.setAttr("name", x.getCpString(e.name_index)); 1243 l.setAttr("flag", "" + e.flags); 1244 l.trimToSize(); 1245 p.add(l); 1246 } 1247 return null; // already added to parent 1248 } 1249 private void parseAnnotation(Annotation anno, Element p) { 1250 Element ea = new Element("Annotation"); 1251 ea.setAttr("name", "" + x.getCpString(anno.type_index)); 1252 for (Annotation.element_value_pair evp : anno.element_value_pairs) { 1253 Element evpe = new Element("Element"); 1254 evpe.setAttr("tag", "" + evp.value.tag); 1255 evpe.setAttr("value", x.getCpString(evp.element_name_index)); 1256 Element child = aev.visit(evp.value, evpe); 1257 if (child != null) { 1258 evpe.add(child); 1259 } 1260 ea.add(evpe); 1261 } 1262 ea.trimToSize(); 1263 p.add(ea); 1264 } 1265 1266 private void parseAnnotations(Annotation[] ra, Element p) { 1267 for (Annotation anno : ra) { 1268 parseAnnotation(anno, p); 1269 } 1270 } 1271 1272 @Override 1273 public Element visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute rva, 1274 Element p) { 1275 Element e = new Element(x.getCpString(rva.attribute_name_index)); 1276 parseAnnotations(rva.annotations, e); 1277 e.trimToSize(); 1278 p.add(e); 1279 return null; 1280 } 1281 1282 @Override 1283 public Element visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute ria, 1284 Element p) { 1285 Element e = new Element(x.getCpString(ria.attribute_name_index)); 1286 parseAnnotations(ria.annotations, e); 1287 e.trimToSize(); 1288 p.add(e); 1289 return null; 1290 } 1291 1292 @Override 1293 public Element visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute rvpa, 1294 Element p) { 1295 Element e = new Element(x.getCpString(rvpa.attribute_name_index)); 1296 for (Annotation[] pa : rvpa.parameter_annotations) { 1297 parseAnnotations(pa, e); 1298 } 1299 p.add(e); 1300 return null; 1301 } 1302 1303 @Override 1304 public Element visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute ripa, 1305 Element p) { 1306 Element e = new Element(x.getCpString(ripa.attribute_name_index)); 1307 for (Annotation[] pa : ripa.parameter_annotations) { 1308 parseAnnotations(pa, e); 1309 } 1310 p.add(e); 1311 return null; 1312 } 1313 1314 private void parsePosition(Position ap, Element p) { 1315 Element te = new Element(); 1316 switch (ap.type) { 1317 case CLASS_TYPE_PARAMETER: // 0x00 1318 te.setName("CLASS_TYPE_PARAMETER"); 1319 te.setAttr("idx", "" + ap.parameter_index); 1320 break; 1321 case METHOD_TYPE_PARAMETER: // 0x01 1322 te.setName("METHOD_TYPE_PARAMETER"); 1323 te.setAttr("idx", "" + ap.parameter_index); 1324 break; 1325 case CLASS_EXTENDS: // 0x10 1326 te.setName("CLASS_EXTENDS"); 1327 te.setAttr("idx", "" + ap.type_index); 1328 break; 1329 case CLASS_TYPE_PARAMETER_BOUND: // 0x11 1330 te.setName("CLASS_TYPE_PARAMETER_BOUND"); 1331 te.setAttr("idx1", "" + ap.parameter_index); 1332 te.setAttr("idx2", "" + ap.bound_index); 1333 break; 1334 case METHOD_TYPE_PARAMETER_BOUND: // 0x12 1335 te.setName("METHOD_TYPE_PARAMETER_BOUND"); 1336 te.setAttr("idx1", "" + ap.parameter_index); 1337 te.setAttr("idx2", "" + ap.bound_index); 1338 break; 1339 case FIELD: // 0x13 1340 te.setName("FIELD"); 1341 break; 1342 case METHOD_RETURN: // 0x14 1343 te.setName("METHOD_RETURN"); 1344 break; 1345 case METHOD_RECEIVER: // 0x15 1346 te.setName("METHOD_RECEIVER"); 1347 break; 1348 case METHOD_FORMAL_PARAMETER: // 0x16 1349 te.setName("METHOD_FORMAL_PARAMETER"); 1350 te.setAttr("idx", "" + ap.parameter_index); 1351 break; 1352 case THROWS: // 0x17 1353 te.setName("THROWS"); 1354 te.setAttr("idx", "" + ap.type_index); 1355 break; 1356 case LOCAL_VARIABLE: // 0x40 1357 te.setName("LOCAL_VARIABLE"); 1358 for (int i = 0; i < ap.lvarIndex.length; i++) { 1359 te.setAttr("lvar_idx_" + i, "" + ap.lvarIndex[i]); 1360 te.setAttr("lvar_len_" + i, "" + ap.lvarLength[i]); 1361 te.setAttr("lvar_off_" + i, "" + ap.lvarOffset[i]); 1362 } 1363 break; 1364 case RESOURCE_VARIABLE: // 0x41 1365 te.setName("RESOURCE_VARIABLE"); 1366 for (int i = 0; i < ap.lvarIndex.length ; i++) { 1367 te.setAttr("lvar_idx_" + i, "" + ap.lvarIndex[i]); 1368 te.setAttr("lvar_len_" + i, "" + ap.lvarLength[i]); 1369 te.setAttr("lvar_off_" + i, "" + ap.lvarOffset[i]); 1370 } 1371 break; 1372 case EXCEPTION_PARAMETER: // 0x42 1373 te.setName("EXCEPTION_PARAMETER"); 1374 te.setAttr("idx", "" + ap.exception_index); 1375 break; 1376 case INSTANCEOF: // 0x43 1377 te.setName("INSTANCE_OF"); 1378 te.setAttr("off", "" + ap.offset); 1379 break; 1380 case NEW: // 0x44 1381 te.setName("NEW"); 1382 te.setAttr("off", "" + ap.offset); 1383 break; 1384 case CONSTRUCTOR_REFERENCE: // 0x45 1385 te.setName("CONSTRUCTOR_REFERENCE_RECEIVER"); 1386 te.setAttr("off", "" + ap.offset); 1387 break; 1388 case METHOD_REFERENCE: // 0x46 1389 te.setName("METHOD_REFERENCE_RECEIVER"); 1390 te.setAttr("off", "" + ap.offset); 1391 break; 1392 case CAST: // 0x47 1393 te.setName("CAST"); 1394 te.setAttr("off", "" + ap.offset); 1395 te.setAttr("idx", "" + ap.type_index); 1396 break; 1397 case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: // 0x48 1398 te.setName("CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT"); 1399 te.setAttr("off", "" + ap.offset); 1400 te.setAttr("idx", "" + ap.type_index); 1401 break; 1402 case METHOD_INVOCATION_TYPE_ARGUMENT: // 0x49 1403 te.setName("METHOD_INVOCATION_TYPE_ARGUMENT"); 1404 te.setAttr("off", "" + ap.offset); 1405 te.setAttr("idx", "" + ap.type_index); 1406 break; 1407 case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: // 0x4A 1408 te.setName("CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT"); 1409 te.setAttr("off", "" + ap.offset); 1410 te.setAttr("idx", "" + ap.type_index); 1411 break; 1412 case METHOD_REFERENCE_TYPE_ARGUMENT: // 0x4B 1413 te.setName("METHOD_REFERENCE_TYPE_ARGUMENT"); 1414 te.setAttr("off", "" + ap.offset); 1415 te.setAttr("idx", "" + ap.type_index); 1416 break; 1417 default: 1418 throw new RuntimeException("not implemented"); 1419 } 1420 te.trimToSize(); 1421 p.add(te); 1422 } 1423 private void parseTypeAnnotations(TypeAnnotation pa, Element p) { 1424 Element pta = new Element("RuntimeVisibleTypeAnnotation"); 1425 p.add(pta); 1426 Position pos = pa.position; 1427 parsePosition(pos, pta); 1428 parseAnnotation(pa.annotation, pta); 1429 } 1430 1431 @Override 1432 public Element visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute rvta, Element p) { 1433 Element e = new Element(x.getCpString(rvta.attribute_name_index)); 1434 for (TypeAnnotation pa : rvta.annotations) { 1435 parseTypeAnnotations(pa, e); 1436 } 1437 e.sort(); 1438 p.add(e); 1439 return null; 1440 } 1441 1442 @Override 1443 public Element visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute rita, Element p) { 1444 Element e = new Element(x.getCpString(rita.attribute_name_index)); 1445 for (TypeAnnotation pa : rita.annotations) { 1446 parseTypeAnnotations(pa, e); 1447 } 1448 e.sort(); 1449 p.add(e); 1450 return null; 1451 } 1452 1453 @Override 1454 public Element visitSignature(Signature_attribute s, Element p) { 1455 String aname = x.getCpString(s.attribute_name_index); 1456 String sname = x.getCpString(s.signature_index); 1457 Element se = new Element(aname); 1458 se.add(sname); 1459 se.trimToSize(); 1460 p.add(se); 1461 return null; 1462 } 1463 1464 @Override 1465 public Element visitSourceDebugExtension(SourceDebugExtension_attribute sde, 1466 Element p) { 1467 String aname = x.getCpString(sde.attribute_name_index); 1468 Element se = new Element(aname); 1469 se.setAttr("val", sde.getValue()); 1470 se.trimToSize(); 1471 p.add(se); 1472 return null; 1473 } 1474 1475 @Override 1476 public Element visitSourceFile(SourceFile_attribute sf, Element p) { 1477 String aname = x.getCpString(sf.attribute_name_index); 1478 String sname = x.getCpString(sf.sourcefile_index); 1479 Element se = new Element(aname); 1480 se.add(sname); 1481 se.trimToSize(); 1482 p.add(se); 1483 return null; 1484 } 1485 1486 @Override 1487 public Element visitSourceID(SourceID_attribute sid, Element p) { 1488 Element e = new Element(x.getCpString(sid.attribute_name_index)); 1489 e.add(x.getCpString(sid.sourceID_index)); 1490 e.trimToSize(); 1491 p.add(e); 1492 return null; 1493 } 1494 1495 @Override 1496 public Element visitStackMap(StackMap_attribute sm, Element p) { 1497 throw new UnsupportedOperationException("Not supported yet."); 1498 } 1499 1500 @Override 1501 public Element visitStackMapTable(StackMapTable_attribute smt, Element p) { 1502 Element stackmap = new Element(x.getCpString(smt.attribute_name_index)); 1503 for (StackMapTable_attribute.stack_map_frame f : smt.entries) { 1504 StackMapVisitor smv = new StackMapVisitor(x, cf, stackmap); 1505 stackmap.add(smv.visit(f)); 1506 } 1507 stackmap.trimToSize(); 1508 p.add(stackmap); 1509 return null; 1510 } 1511 1512 @Override 1513 public Element visitSynthetic(Synthetic_attribute s, Element p) { 1514 Element e = new Element(x.getCpString(s.attribute_name_index)); 1515 e.trimToSize(); 1516 p.add(e); 1517 return null; 1518 } 1519 1520 @Override 1521 public Element visitModuleHashes(ModuleHashes_attribute attr, Element p) { 1522 Element e = new Element(x.getCpString(attr.attribute_name_index)); 1523 e.setAttr("Algorithm", x.getCpString(attr.algorithm_index)); 1524 for (Entry entry : attr.hashes_table) { 1525 Element ee = new Element("Entry"); 1526 String mn = x.getCpString(entry.module_name_index); 1527 ee.setAttr("module_name", mn); 1528 ee.setAttr("hash_length", "" + entry.hash.length); 1529 StringBuilder sb = new StringBuilder(); 1530 for (byte b: entry.hash) { 1531 sb.append(String.format("%02x", b & 0xff)); 1532 } 1533 ee.setAttr("hash", sb.toString()); 1534 ee.trimToSize(); 1535 e.add(ee); 1536 } 1537 e.trimToSize(); 1538 e.sort(); 1539 p.add(e); 1540 return null; 1541 } 1542 1543 @Override 1544 public Element visitModuleMainClass(ModuleMainClass_attribute attr, Element p) { 1545 Element e = new Element(x.getCpString(attr.attribute_name_index)); 1546 e.add(x.getCpString(attr.main_class_index)); 1547 e.trimToSize(); 1548 p.add(e); 1549 return null; 1550 } 1551 1552 @Override 1553 public Element visitModuleResolution(ModuleResolution_attribute attr, Element p) { 1554 Element e = new Element("ModuleResolution"); 1555 e.setAttr("flags", Integer.toString(attr.resolution_flags)); 1556 e.trimToSize(); 1557 p.add(e); 1558 return null; 1559 } 1560 1561 @Override 1562 public Element visitModuleTarget(ModuleTarget_attribute attr, Element p) { 1563 Element e = new Element(x.getCpString(attr.attribute_name_index)); 1564 e.add(x.getCpString(attr.target_platform_index)); 1565 e.trimToSize(); 1566 p.add(e); 1567 return null; 1568 } 1569 } 1570 1571 class StackMapVisitor implements StackMapTable_attribute.stack_map_frame.Visitor<Element, Void> { 1572 1573 final ClassFile cf; 1574 final ClassReader x; 1575 final Element parent; 1576 1577 public StackMapVisitor(ClassReader x, ClassFile cf, Element parent) { 1578 this.x = x; 1579 this.cf = cf; 1580 this.parent = parent; 1581 } 1582 1583 public Element visit(StackMapTable_attribute.stack_map_frame frame) { 1584 return frame.accept(this, null); 1585 } 1586 1587 @Override 1588 public Element visit_same_frame(same_frame sm_frm, Void p) { 1589 Element e = new Element("SameFrame"); 1590 e.setAttr("tag", "" + sm_frm.frame_type); 1591 return e; 1592 } 1593 1594 @Override 1595 public Element visit_same_locals_1_stack_item_frame(same_locals_1_stack_item_frame s, Void p) { 1596 Element e = new Element("SameLocals1StackItemFrame"); 1597 e.setAttr("tag", "" + s.frame_type); 1598 e.addAll(getVerificationTypeInfo("Stack", s.stack)); 1599 e.trimToSize(); 1600 return e; 1601 } 1602 1603 @Override 1604 public Element visit_same_locals_1_stack_item_frame_extended(same_locals_1_stack_item_frame_extended s, Void p) { 1605 Element e = new Element("SameLocals1StackItemFrameExtended"); 1606 e.setAttr("tag", "" + s.frame_type); 1607 e.addAll(getVerificationTypeInfo("Stack", s.stack)); 1608 e.trimToSize(); 1609 return e; 1610 } 1611 1612 @Override 1613 public Element visit_chop_frame(chop_frame c, Void p) { 1614 Element e = new Element("Chop" + (251 - c.frame_type)); 1615 e.setAttr("tag", "" + c.frame_type); 1616 e.setAttr("offset", "" + c.offset_delta); 1617 return e; 1618 } 1619 1620 @Override 1621 public Element visit_same_frame_extended(same_frame_extended s, Void p) { 1622 Element e = new Element("SameFrameExtended"); 1623 e.setAttr("tag", "" + s.frame_type); 1624 e.setAttr("offset", "" + s.offset_delta); 1625 return e; 1626 } 1627 1628 @Override 1629 public Element visit_append_frame(append_frame a, Void p) { 1630 Element e = new Element("AppendFrame" + (a.frame_type - 251)); 1631 e.setAttr("tag", "" + a.frame_type); 1632 e.addAll(getVerificationTypeInfo("Local", a.locals)); 1633 e.trimToSize(); 1634 return e; 1635 } 1636 1637 @Override 1638 public Element visit_full_frame(full_frame fl_frm, Void p) { 1639 Element e = new Element("FullFrame"); 1640 e.setAttr("tag", "" + fl_frm.frame_type); 1641 e.addAll(getVerificationTypeInfo("Local", fl_frm.locals)); 1642 e.trimToSize(); 1643 return e; 1644 } 1645 1646 private Element getVerificationTypeInfo(String kind, 1647 StackMapTable_attribute.verification_type_info velems[]) { 1648 Element container = new Element(velems.length); 1649 for (StackMapTable_attribute.verification_type_info v : velems) { 1650 Element ve = null; 1651 int offset = 0; 1652 int index = 0; 1653 switch (v.tag) { 1654 case StackMapTable_attribute.verification_type_info.ITEM_Top: 1655 ve = new Element("ITEM_Top"); 1656 break; 1657 case StackMapTable_attribute.verification_type_info.ITEM_Integer: 1658 ve = new Element("ITEM_Integer"); 1659 break; 1660 case StackMapTable_attribute.verification_type_info.ITEM_Float: 1661 ve = new Element("ITEM_Float"); 1662 break; 1663 case StackMapTable_attribute.verification_type_info.ITEM_Long: 1664 ve = new Element("ITEM_Long"); 1665 break; 1666 case StackMapTable_attribute.verification_type_info.ITEM_Double: 1667 ve = new Element("ITEM_Double"); 1668 break; 1669 case StackMapTable_attribute.verification_type_info.ITEM_Null: 1670 ve = new Element("ITEM_Null"); 1671 break; 1672 case StackMapTable_attribute.verification_type_info.ITEM_Uninitialized: 1673 ve = new Element("ITEM_Uninitialized"); 1674 offset = ((StackMapTable_attribute.Uninitialized_variable_info) v).offset; 1675 ve.setAttr("offset", "" + offset); 1676 break; 1677 case StackMapTable_attribute.verification_type_info.ITEM_UninitializedThis: 1678 ve = new Element("ITEM_UnitializedtThis"); 1679 break; 1680 case StackMapTable_attribute.verification_type_info.ITEM_Object: 1681 ve = new Element("ITEM_Object"); 1682 index = ((StackMapTable_attribute.Object_variable_info) v).cpool_index; 1683 ve.setAttr("class", x.getCpString(index)); 1684 break; 1685 default: 1686 ve = new Element("Unknown"); 1687 } 1688 Element kindE = new Element(kind); 1689 kindE.setAttr("tag", "" + v.tag); 1690 container.add(kindE); 1691 kindE.add(ve); 1692 } 1693 container.trimToSize(); 1694 return container; 1695 } 1696 } 1697 1698 class InstructionVisitor implements Instruction.KindVisitor<Element, Void> { 1699 1700 final ClassReader x; 1701 final ClassFile cf; 1702 1703 public InstructionVisitor(ClassReader x, ClassFile cf) { 1704 this.x = x; 1705 this.cf = cf; 1706 } 1707 1708 public Element visit(Instruction i) { 1709 Element ie = i.accept(this, null); 1710 ie.trimToSize(); 1711 return ie; 1712 } 1713 1714 @Override 1715 public Element visitNoOperands(Instruction i, Void p) { 1716 Opcode o = i.getOpcode(); 1717 Element e = new Element(i.getMnemonic()); 1718 if (o.opcode > 0xab && o.opcode <= 0xb1) { 1719 e.setAttr("pc", "" + i.getPC()); 1720 } 1721 return e; 1722 } 1723 1724 @Override 1725 public Element visitArrayType(Instruction i, TypeKind tk, Void p) { 1726 Element ie = new Element(i.getMnemonic()); 1727 ie.setAttr("num", "" + tk.value); 1728 ie.setAttr("val", tk.name); 1729 return ie; 1730 } 1731 1732 @Override 1733 public Element visitBranch(Instruction i, int i1, Void p) { 1734 Element ie = new Element(i.getMnemonic()); 1735 ie.setAttr("lab", "" + (i.getPC() + i1)); 1736 return ie; 1737 } 1738 1739 @Override 1740 public Element visitConstantPoolRef(Instruction i, int i1, Void p) { 1741 Element ie = new Element(i.getMnemonic()); 1742 ie.setAttr("ref", x.getCpString(i1)); 1743 return ie; 1744 } 1745 1746 @Override 1747 public Element visitConstantPoolRefAndValue(Instruction i, int i1, int i2, Void p) { 1748 // workaround for a potential bug in classfile 1749 Element ie = new Element(i.getMnemonic()); 1750 if (i.getOpcode().equals(Opcode.IINC_W)) { 1751 ie.setAttr("loc", "" + i1); 1752 ie.setAttr("num", "" + i2); 1753 } else { 1754 ie.setAttr("ref", x.getCpString(i1)); 1755 ie.setAttr("val", "" + i2); 1756 } 1757 return ie; 1758 } 1759 1760 @Override 1761 public Element visitLocal(Instruction i, int i1, Void p) { 1762 Element ie = new Element(i.getMnemonic()); 1763 ie.setAttr("loc", "" + i1); 1764 return ie; 1765 } 1766 1767 @Override 1768 public Element visitLocalAndValue(Instruction i, int i1, int i2, Void p) { 1769 Element ie = new Element(i.getMnemonic()); 1770 ie.setAttr("loc", "" + i1); 1771 ie.setAttr("num", "" + i2); 1772 return ie; 1773 } 1774 1775 @Override 1776 public Element visitLookupSwitch(Instruction i, int i1, int i2, int[] ints, 1777 int[] ints1, Void p) { 1778 Element ie = new Element(i.getMnemonic()); 1779 int pc = i.getPC(); 1780 ie.setAttr("lab", "" + (pc + i1)); 1781 for (int k = 0 ; k < i2 ; k++) { 1782 Element c = new Element("Case"); 1783 c.setAttr("num", "" + (ints[k])); 1784 c.setAttr("lab", "" + (pc + ints1[k])); 1785 c.trimToSize(); 1786 ie.add(c); 1787 } 1788 return ie; 1789 } 1790 1791 @Override 1792 public Element visitTableSwitch(Instruction i, int i1, int i2, int i3, 1793 int[] ints, Void p) { 1794 Element ie = new Element(i.getMnemonic()); 1795 int pc = i.getPC(); 1796 ie.setAttr("lab", "" + (pc + i1)); 1797 for (int k : ints) { 1798 Element c = new Element("Case"); 1799 c.setAttr("num", "" + (k + i2)); 1800 c.setAttr("lab", "" + (pc + k)); 1801 c.trimToSize(); 1802 ie.add(c); 1803 } 1804 return ie; 1805 } 1806 1807 @Override 1808 public Element visitValue(Instruction i, int i1, Void p) { 1809 Element ie = new Element(i.getMnemonic()); 1810 ie.setAttr("num", "" + i1); 1811 return ie; 1812 } 1813 1814 @Override 1815 public Element visitUnknown(Instruction i, Void p) { 1816 Element e = new Element(i.getMnemonic()); 1817 e.setAttr("pc", "" + i.getPC()); 1818 e.setAttr("opcode", "" + i.getOpcode().opcode); 1819 return e; 1820 } 1821 } 1822 1823 class AnnotationsElementVisitor implements Annotation.element_value.Visitor<Element, Element> { 1824 final ClassReader x; 1825 final ClassFile cf; 1826 1827 public AnnotationsElementVisitor(ClassReader x, ClassFile cf) { 1828 this.x = x; 1829 this.cf = cf; 1830 } 1831 1832 public Element visit(Annotation.element_value v, Element p) { 1833 return v.accept(this, p); 1834 } 1835 1836 @Override 1837 public Element visitPrimitive(Primitive_element_value e, Element p) { 1838 Element el = new Element("String"); 1839 el.setAttr("val", x.getCpString(e.const_value_index)); 1840 el.trimToSize(); 1841 return el; 1842 } 1843 1844 @Override 1845 public Element visitEnum(Enum_element_value e, Element p) { 1846 Element el = new Element("Enum"); 1847 el.setAttr("name", x.getCpString(e.const_name_index)); 1848 el.setAttr("type", x.getCpString(e.type_name_index)); 1849 el.trimToSize(); 1850 return el; 1851 } 1852 1853 @Override 1854 public Element visitClass(Class_element_value c, Element p) { 1855 Element el = new Element("Class"); 1856 el.setAttr("name", x.getCpString(c.class_info_index)); 1857 el.trimToSize(); 1858 return el; 1859 } 1860 1861 @Override 1862 public Element visitAnnotation(Annotation_element_value a, Element p) { 1863 Element el = new Element("Annotation"); 1864 Annotation anno = a.annotation_value; 1865 for (Annotation.element_value_pair evp : anno.element_value_pairs) { 1866 Element child = visit(evp.value, el); 1867 if (child != null) { 1868 el.add(child); 1869 } 1870 } 1871 el.trimToSize(); 1872 return el; 1873 } 1874 1875 @Override 1876 public Element visitArray(Array_element_value a, Element p) { 1877 Element el = new Element("Array"); 1878 for (Annotation.element_value v : a.values) { 1879 Element child = visit(v, el); 1880 if (child != null) { 1881 el.add(child); 1882 } 1883 } 1884 el.trimToSize(); 1885 return el; 1886 } 1887 }