2 * Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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.
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
27 package sun.tools.javap;
33 * Central data repository of the Java Disassembler.
34 * Stores all the information in java class file.
36 * @author Sucheta Dambalkar (Adopted code from jdis)
38 public class ClassData implements RuntimeConstants {
41 private int minor_version;
42 private int major_version;
43 private int cpool_count;
44 private Object cpool[];
46 private int this_class = 0;;
47 private int super_class;
48 private int interfaces_count;
49 private int[] interfaces = new int[0];;
50 private int fields_count;
51 private FieldData[] fields;
52 private int methods_count;
53 private MethodData[] methods;
54 private InnerClassData[] innerClasses;
55 private int attributes_count;
56 private AttrData[] attrs;
57 private String classname;
58 private String superclassname;
59 private int source_cpx=0;
61 private Hashtable indexHashAscii = new Hashtable();
62 private String pkgPrefix="";
63 private int pkgPrefixLen=0;
66 * Read classfile to disassemble.
68 public ClassData(InputStream infile){
70 this.read(new DataInputStream(infile));
71 }catch (FileNotFoundException ee) {
72 error("cant read file");
76 } catch (Exception ee) {
78 error("fatal exception");
83 * Reads and stores class file information.
85 public void read(DataInputStream in) throws IOException {
88 if (magic != JAVA_MAGIC) {
89 throw new ClassFormatError("wrong magic: " +
90 toHex(magic) + ", expected " +
93 minor_version = in.readShort();
94 major_version = in.readShort();
95 if (major_version != JAVA_VERSION) {
98 // Read the constant pool
100 access = in.readUnsignedShort();
101 this_class = in.readUnsignedShort();
102 super_class = in.readUnsignedShort();
105 interfaces_count = in.readUnsignedShort();
106 if(interfaces_count > 0){
107 interfaces = new int[interfaces_count];
109 for (int i = 0; i < interfaces_count; i++) {
110 interfaces[i]=in.readShort();
119 // Read the attributes
120 attributes_count = in.readUnsignedShort();
121 attrs=new AttrData[attributes_count];
122 for (int k = 0; k < attributes_count; k++) {
123 int name_cpx=in.readUnsignedShort();
124 if (getTag(name_cpx)==CONSTANT_UTF8
125 && getString(name_cpx).equals("SourceFile")
126 ){ if (in.readInt()!=2)
127 throw new ClassFormatError("invalid attr length");
128 source_cpx=in.readUnsignedShort();
129 AttrData attr=new AttrData(this);
133 } else if (getTag(name_cpx)==CONSTANT_UTF8
134 && getString(name_cpx).equals("InnerClasses")
135 ){ int length=in.readInt();
136 int num=in.readUnsignedShort();
137 if (2+num*8 != length)
138 throw new ClassFormatError("invalid attr length");
139 innerClasses=new InnerClassData[num];
140 for (int j = 0; j < num; j++) {
141 InnerClassData innerClass=new InnerClassData(this);
143 innerClasses[j]=innerClass;
145 AttrData attr=new AttrData(this);
149 AttrData attr=new AttrData(this);
150 attr.read(name_cpx, in);
155 } // end ClassData.read()
158 * Reads and stores constant pool info.
160 void readCP(DataInputStream in) throws IOException {
161 cpool_count = in.readUnsignedShort();
162 tags = new byte[cpool_count];
163 cpool = new Object[cpool_count];
164 for (int i = 1; i < cpool_count; i++) {
165 byte tag = in.readByte();
167 switch(tags[i] = tag) {
169 String str=in.readUTF();
170 indexHashAscii.put(cpool[i] = str, new Integer(i));
172 case CONSTANT_INTEGER:
173 cpool[i] = new Integer(in.readInt());
176 cpool[i] = new Float(in.readFloat());
179 cpool[i++] = new Long(in.readLong());
181 case CONSTANT_DOUBLE:
182 cpool[i++] = new Double(in.readDouble());
185 case CONSTANT_STRING:
186 cpool[i] = new CPX(in.readUnsignedShort());
190 case CONSTANT_METHOD:
191 case CONSTANT_INTERFACEMETHOD:
192 case CONSTANT_NAMEANDTYPE:
193 cpool[i] = new CPX2(in.readUnsignedShort(), in.readUnsignedShort());
198 throw new ClassFormatError("invalid constant type: " + (int)tags[i]);
204 * Reads and strores field info.
206 protected void readFields(DataInputStream in) throws IOException {
207 int fields_count = in.readUnsignedShort();
208 fields=new FieldData[fields_count];
209 for (int k = 0; k < fields_count; k++) {
210 FieldData field=new FieldData(this);
217 * Reads and strores Method info.
219 protected void readMethods(DataInputStream in) throws IOException {
220 int methods_count = in.readUnsignedShort();
221 methods=new MethodData[methods_count];
222 for (int k = 0; k < methods_count ; k++) {
223 MethodData method=new MethodData(this);
232 public String getString(int n) {
233 return (n == 0) ? null : (String)cpool[n];
237 * get the type of constant given an index
239 public byte getTag(int n) {
242 } catch (ArrayIndexOutOfBoundsException e) {
247 static final String hexString="0123456789ABCDEF";
249 public static char hexTable[]=hexString.toCharArray();
251 static String toHex(long val, int width) {
252 StringBuffer s = new StringBuffer();
253 for (int i=width-1; i>=0; i--)
254 s.append(hexTable[((int)(val>>(4*i)))&0xF]);
255 return "0x"+s.toString();
258 static String toHex(long val) {
260 for (width=16; width>0; width--) {
261 if ((val>>(width-1)*4)!=0) break;
263 return toHex(val, width);
266 static String toHex(int val) {
268 for (width=8; width>0; width--) {
269 if ((val>>(width-1)*4)!=0) break;
271 return toHex(val, width);
274 public void error(String msg) {
275 System.err.println("ERROR:" +msg);
279 * Returns the name of this class.
281 public String getClassName() {
288 if (tags[this_class]!=CONSTANT_CLASS) {
289 return res; //"<CP["+cpx+"] is not a Class> ";
291 tcpx=((CPX)cpool[this_class]).cpx;
292 } catch (ArrayIndexOutOfBoundsException e) {
293 return res; // "#"+cpx+"// invalid constant pool index";
294 } catch (Throwable e) {
295 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
299 return (String)(cpool[tcpx]);
300 } catch (ArrayIndexOutOfBoundsException e) {
301 return res; // "class #"+scpx+"// invalid constant pool index";
302 } catch (ClassCastException e) {
303 return res; // "class #"+scpx+"// invalid constant pool reference";
304 } catch (Throwable e) {
305 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
311 * Returns the name of class at perticular index.
313 public String getClassName(int cpx) {
320 if (tags[cpx]!=CONSTANT_CLASS) {
321 return res; //"<CP["+cpx+"] is not a Class> ";
323 scpx=((CPX)cpool[cpx]).cpx;
324 } catch (ArrayIndexOutOfBoundsException e) {
325 return res; // "#"+cpx+"// invalid constant pool index";
326 } catch (Throwable e) {
327 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
331 return (String)(cpool[scpx]);
332 } catch (ArrayIndexOutOfBoundsException e) {
333 return res; // "class #"+scpx+"// invalid constant pool index";
334 } catch (ClassCastException e) {
335 return res; // "class #"+scpx+"// invalid constant pool reference";
336 } catch (Throwable e) {
337 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
342 * Returns true if it is a class
344 public boolean isClass() {
345 if((access & ACC_INTERFACE) == 0) return true;
350 * Returns true if it is a interface.
352 public boolean isInterface(){
353 if((access & ACC_INTERFACE) != 0) return true;
358 * Returns true if this member is public, false otherwise.
360 public boolean isPublic(){
361 return (access & ACC_PUBLIC) != 0;
365 * Returns the access of this class or interface.
367 public String[] getAccess(){
368 Vector v = new Vector();
369 if ((access & ACC_PUBLIC) !=0) v.addElement("public");
370 if ((access & ACC_FINAL) !=0) v.addElement("final");
371 if ((access & ACC_ABSTRACT) !=0) v.addElement("abstract");
372 String[] accflags = new String[v.size()];
373 v.copyInto(accflags);
378 * Returns list of innerclasses.
380 public InnerClassData[] getInnerClasses(){
385 * Returns list of attributes.
387 public AttrData[] getAttributes(){
392 * Returns true if superbit is set.
394 public boolean isSuperSet(){
395 if ((access & ACC_SUPER) !=0) return true;
400 * Returns super class name.
402 public String getSuperClassName(){
404 if (super_class==0) {
409 if (tags[super_class]!=CONSTANT_CLASS) {
410 return res; //"<CP["+cpx+"] is not a Class> ";
412 scpx=((CPX)cpool[super_class]).cpx;
413 } catch (ArrayIndexOutOfBoundsException e) {
414 return res; // "#"+cpx+"// invalid constant pool index";
415 } catch (Throwable e) {
416 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
420 return (String)(cpool[scpx]);
421 } catch (ArrayIndexOutOfBoundsException e) {
422 return res; // "class #"+scpx+"// invalid constant pool index";
423 } catch (ClassCastException e) {
424 return res; // "class #"+scpx+"// invalid constant pool reference";
425 } catch (Throwable e) {
426 return res; // "#"+cpx+"// ERROR IN DISASSEMBLER";
431 * Returns list of super interfaces.
433 public String[] getSuperInterfaces(){
434 String interfacenames[] = new String[interfaces.length];
435 int interfacecpx = -1;
436 for(int i = 0; i < interfaces.length; i++){
437 interfacecpx=((CPX)cpool[interfaces[i]]).cpx;
438 interfacenames[i] = (String)(cpool[interfacecpx]);
440 return interfacenames;
444 * Returns string at prticular constant pool index.
446 public String getStringValue(int cpoolx) {
448 return ((String)cpool[cpoolx]);
449 } catch (ArrayIndexOutOfBoundsException e) {
450 return "//invalid constant pool index:"+cpoolx;
451 } catch (ClassCastException e) {
452 return "//invalid constant pool ref:"+cpoolx;
457 * Returns list of field info.
459 public FieldData[] getFields(){
464 * Returns list of method info.
466 public MethodData[] getMethods(){
471 * Returns constant pool entry at that index.
473 public CPX2 getCpoolEntry(int cpx){
474 return ((CPX2)(cpool[cpx]));
477 public Object getCpoolEntryobj(int cpx){
482 * Returns index of this class.
484 public int getthis_cpx(){
488 public String TagString (int tag) {
489 String res=Tables.tagName(tag);
490 if (res==null) return "BOGUS_TAG:"+tag;
495 * Returns string at that index.
497 public String StringValue(int cpx) {
498 if (cpx==0) return "#0";
505 } catch (IndexOutOfBoundsException e) {
506 return "<Incorrect CP index:"+cpx+">";
509 if (x==null) return "<NULL>";
511 case CONSTANT_UTF8: {
512 StringBuffer sb=new StringBuffer();
514 for (int k=0; k<s.length(); k++) {
517 case '\t': sb.append('\\').append('t'); break;
518 case '\n': sb.append('\\').append('n'); break;
519 case '\r': sb.append('\\').append('r'); break;
520 case '\"': sb.append('\\').append('\"'); break;
521 default: sb.append(c);
524 return sb.toString();
526 case CONSTANT_DOUBLE: {
528 String sd=d.toString();
531 case CONSTANT_FLOAT: {
533 String sf=(f).toString();
536 case CONSTANT_LONG: {
538 return ln.toString()+'l';
540 case CONSTANT_INTEGER: {
541 Integer in = (Integer)x;
542 return in.toString();
545 return javaName(getClassName(cpx));
546 case CONSTANT_STRING:
547 return StringValue(((CPX)x).cpx);
549 case CONSTANT_METHOD:
550 case CONSTANT_INTERFACEMETHOD:
551 //return getShortClassName(((CPX2)x).cpx1)+"."+StringValue(((CPX2)x).cpx2);
552 return javaName(getClassName(((CPX2)x).cpx1))+"."+StringValue(((CPX2)x).cpx2);
554 case CONSTANT_NAMEANDTYPE:
555 return getName(((CPX2)x).cpx1)+":"+StringValue(((CPX2)x).cpx2);
557 return "UnknownTag"; //TBD
562 * Returns resolved java type name.
564 public String javaName(String name) {
565 if( name==null) return "null";
566 int len=name.length();
567 if (len==0) return "\"\"";
569 fullname: { // xxx/yyy/zzz
571 for (int k=0; k<len; k += Character.charCount(cp)) {
572 cp=name.codePointAt(k);
574 if (!Character.isJavaIdentifierStart(cp)) break fullname;
575 } else if (cp!='/') {
576 if (!Character.isJavaIdentifierPart(cp)) break fullname;
582 return "\""+name+"\"";
585 public String getName(int cpx) {
588 return javaName((String)cpool[cpx]); //.replace('/','.');
589 } catch (ArrayIndexOutOfBoundsException e) {
590 return "<invalid constant pool index:"+cpx+">";
591 } catch (ClassCastException e) {
592 return "<invalid constant pool ref:"+cpx+">";
597 * Returns unqualified class name.
599 public String getShortClassName(int cpx) {
600 String classname=javaName(getClassName(cpx));
601 pkgPrefixLen=classname.lastIndexOf("/")+1;
602 if (pkgPrefixLen!=0) {
603 pkgPrefix=classname.substring(0,pkgPrefixLen);
604 if (classname.startsWith(pkgPrefix)) {
605 return classname.substring(pkgPrefixLen);
612 * Returns source file name.
614 public String getSourceName(){
615 return getName(source_cpx);
619 * Returns package name.
621 public String getPkgName(){
622 String classname=getClassName(this_class);
623 pkgPrefixLen=classname.lastIndexOf("/")+1;
624 if (pkgPrefixLen!=0) {
625 pkgPrefix=classname.substring(0,pkgPrefixLen);
626 return("package "+pkgPrefix.substring(0,pkgPrefixLen-1)+";\n");
631 * Returns total constant pool entry count.
633 public int getCpoolCount(){
637 public String StringTag(int cpx) {
641 if (cpx==0) throw new IndexOutOfBoundsException();
643 return TagString(tag);
644 } catch (IndexOutOfBoundsException e) {
645 str="Incorrect CP index:"+cpx;
651 * Returns minor version of class file.
653 public int getMinor_version(){
654 return minor_version;
658 * Returns major version of class file.
660 public int getMajor_version(){
661 return major_version;