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