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