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