javap/src/main/java/sun/tools/javap/ClassData.java
author Jaroslav Tulach <jtulach@netbeans.org>
Fri, 09 Nov 2012 21:33:22 +0100
branchjavap
changeset 144 b06660b614db
child 149 32653a09f0db
permissions -rw-r--r--
javap as of revision jdk6-4ab5d66aaf2b
     1 /*
     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.
     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 
    26 
    27 package sun.tools.javap;
    28 
    29 import java.util.*;
    30 import java.io.*;
    31 
    32 /**
    33  * Central data repository of the Java Disassembler.
    34  * Stores all the information in java class file.
    35  *
    36  * @author  Sucheta Dambalkar (Adopted code from jdis)
    37  */
    38 public class ClassData implements RuntimeConstants {
    39 
    40     private int magic;
    41     private int minor_version;
    42     private int major_version;
    43     private int cpool_count;
    44     private Object cpool[];
    45     private int access;
    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;
    60     private byte tags[];
    61     private Hashtable indexHashAscii = new Hashtable();
    62     private String pkgPrefix="";
    63     private int pkgPrefixLen=0;
    64 
    65     /**
    66      * Read classfile to disassemble.
    67      */
    68     public ClassData(InputStream infile){
    69         try{
    70             this.read(new DataInputStream(infile));
    71         }catch (FileNotFoundException ee) {
    72             error("cant read file");
    73         }catch (Error ee) {
    74             ee.printStackTrace();
    75             error("fatal error");
    76         } catch (Exception ee) {
    77             ee.printStackTrace();
    78             error("fatal exception");
    79         }
    80     }
    81 
    82     /**
    83      * Reads and stores class file information.
    84      */
    85     public void read(DataInputStream in) throws IOException {
    86         // Read the header
    87         magic = in.readInt();
    88         if (magic != JAVA_MAGIC) {
    89             throw new ClassFormatError("wrong magic: " +
    90                                        toHex(magic) + ", expected " +
    91                                        toHex(JAVA_MAGIC));
    92         }
    93         minor_version = in.readShort();
    94         major_version = in.readShort();
    95         if (major_version != JAVA_VERSION) {
    96         }
    97 
    98         // Read the constant pool
    99         readCP(in);
   100         access = in.readUnsignedShort();
   101         this_class = in.readUnsignedShort();
   102         super_class = in.readUnsignedShort();
   103 
   104         //Read interfaces.
   105         interfaces_count = in.readUnsignedShort();
   106         if(interfaces_count > 0){
   107             interfaces = new int[interfaces_count];
   108         }
   109         for (int i = 0; i < interfaces_count; i++) {
   110             interfaces[i]=in.readShort();
   111         }
   112 
   113         // Read the fields
   114         readFields(in);
   115 
   116         // Read the methods
   117         readMethods(in);
   118 
   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);
   130                 attr.read(name_cpx);
   131                 attrs[k]=attr;
   132 
   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);
   142                            innerClass.read(in);
   143                            innerClasses[j]=innerClass;
   144                        }
   145                        AttrData attr=new AttrData(this);
   146                        attr.read(name_cpx);
   147                        attrs[k]=attr;
   148             } else {
   149                 AttrData attr=new AttrData(this);
   150                 attr.read(name_cpx, in);
   151                 attrs[k]=attr;
   152             }
   153         }
   154         in.close();
   155     } // end ClassData.read()
   156 
   157     /**
   158      * Reads and stores constant pool info.
   159      */
   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();
   166 
   167             switch(tags[i] = tag) {
   168             case CONSTANT_UTF8:
   169                 String str=in.readUTF();
   170                 indexHashAscii.put(cpool[i] = str, new Integer(i));
   171                 break;
   172             case CONSTANT_INTEGER:
   173                 cpool[i] = new Integer(in.readInt());
   174                 break;
   175             case CONSTANT_FLOAT:
   176                 cpool[i] = new Float(in.readFloat());
   177                 break;
   178             case CONSTANT_LONG:
   179                 cpool[i++] = new Long(in.readLong());
   180                 break;
   181             case CONSTANT_DOUBLE:
   182                 cpool[i++] = new Double(in.readDouble());
   183                 break;
   184             case CONSTANT_CLASS:
   185             case CONSTANT_STRING:
   186                 cpool[i] = new CPX(in.readUnsignedShort());
   187                 break;
   188 
   189             case CONSTANT_FIELD:
   190             case CONSTANT_METHOD:
   191             case CONSTANT_INTERFACEMETHOD:
   192             case CONSTANT_NAMEANDTYPE:
   193                 cpool[i] = new CPX2(in.readUnsignedShort(), in.readUnsignedShort());
   194                 break;
   195 
   196             case 0:
   197             default:
   198                 throw new ClassFormatError("invalid constant type: " + (int)tags[i]);
   199             }
   200         }
   201     }
   202 
   203     /**
   204      * Reads and strores field info.
   205      */
   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);
   211             field.read(in);
   212             fields[k]=field;
   213         }
   214     }
   215 
   216     /**
   217      * Reads and strores Method info.
   218      */
   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);
   224             method.read(in);
   225             methods[k]=method;
   226         }
   227     }
   228 
   229     /**
   230      * get a string
   231      */
   232     public String getString(int n) {
   233         return (n == 0) ? null : (String)cpool[n];
   234     }
   235 
   236     /**
   237      * get the type of constant given an index
   238      */
   239     public byte getTag(int n) {
   240         try{
   241             return tags[n];
   242         } catch (ArrayIndexOutOfBoundsException e) {
   243             return (byte)100;
   244         }
   245     }
   246 
   247     static final String hexString="0123456789ABCDEF";
   248 
   249     public static char hexTable[]=hexString.toCharArray();
   250 
   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();
   256     }
   257 
   258     static String toHex(long val) {
   259         int width;
   260         for (width=16; width>0; width--) {
   261             if ((val>>(width-1)*4)!=0) break;
   262         }
   263         return toHex(val, width);
   264     }
   265 
   266     static String toHex(int val) {
   267         int width;
   268         for (width=8; width>0; width--) {
   269             if ((val>>(width-1)*4)!=0) break;
   270         }
   271         return toHex(val, width);
   272     }
   273 
   274     public void error(String msg) {
   275         System.err.println("ERROR:" +msg);
   276     }
   277 
   278     /**
   279      * Returns the name of this class.
   280      */
   281     public String getClassName() {
   282         String res=null;
   283         if (this_class==0) {
   284             return res;
   285         }
   286         int tcpx;
   287         try {
   288             if (tags[this_class]!=CONSTANT_CLASS) {
   289                 return res; //"<CP["+cpx+"] is not a Class> ";
   290             }
   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";
   296         }
   297 
   298         try {
   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";
   306         }
   307 
   308     }
   309 
   310     /**
   311      * Returns the name of class at perticular index.
   312      */
   313     public String getClassName(int cpx) {
   314         String res="#"+cpx;
   315         if (cpx==0) {
   316             return res;
   317         }
   318         int scpx;
   319         try {
   320             if (tags[cpx]!=CONSTANT_CLASS) {
   321                 return res; //"<CP["+cpx+"] is not a Class> ";
   322             }
   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";
   328         }
   329         res="#"+scpx;
   330         try {
   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";
   338         }
   339     }
   340 
   341     /**
   342      * Returns true if it is a class
   343      */
   344     public boolean isClass() {
   345         if((access & ACC_INTERFACE) == 0) return true;
   346         return false;
   347     }
   348 
   349     /**
   350      * Returns true if it is a interface.
   351      */
   352     public boolean isInterface(){
   353         if((access & ACC_INTERFACE) != 0) return true;
   354         return false;
   355     }
   356 
   357     /**
   358      * Returns true if this member is public, false otherwise.
   359      */
   360     public boolean isPublic(){
   361         return (access & ACC_PUBLIC) != 0;
   362     }
   363 
   364     /**
   365      * Returns the access of this class or interface.
   366      */
   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);
   374         return accflags;
   375     }
   376 
   377     /**
   378      * Returns list of innerclasses.
   379      */
   380     public InnerClassData[] getInnerClasses(){
   381         return innerClasses;
   382     }
   383 
   384     /**
   385      * Returns list of attributes.
   386      */
   387     public AttrData[] getAttributes(){
   388         return attrs;
   389     }
   390 
   391     /**
   392      * Returns true if superbit is set.
   393      */
   394     public boolean isSuperSet(){
   395         if ((access & ACC_SUPER)   !=0) return true;
   396         return false;
   397     }
   398 
   399     /**
   400      * Returns super class name.
   401      */
   402     public String getSuperClassName(){
   403         String res=null;
   404         if (super_class==0) {
   405             return res;
   406         }
   407         int scpx;
   408         try {
   409             if (tags[super_class]!=CONSTANT_CLASS) {
   410                 return res; //"<CP["+cpx+"] is not a Class> ";
   411             }
   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";
   417         }
   418 
   419         try {
   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";
   427         }
   428     }
   429 
   430     /**
   431      * Returns list of super interfaces.
   432      */
   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]);
   439         }
   440         return interfacenames;
   441     }
   442 
   443     /**
   444      * Returns string at prticular constant pool index.
   445      */
   446     public String getStringValue(int cpoolx) {
   447         try {
   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;
   453         }
   454     }
   455 
   456     /**
   457      * Returns list of field info.
   458      */
   459     public  FieldData[] getFields(){
   460         return fields;
   461     }
   462 
   463     /**
   464      * Returns list of method info.
   465      */
   466     public  MethodData[] getMethods(){
   467         return methods;
   468     }
   469 
   470     /**
   471      * Returns constant pool entry at that index.
   472      */
   473     public CPX2 getCpoolEntry(int cpx){
   474         return ((CPX2)(cpool[cpx]));
   475     }
   476 
   477     public Object getCpoolEntryobj(int cpx){
   478         return (cpool[cpx]);
   479     }
   480 
   481     /**
   482      * Returns index of this class.
   483      */
   484     public int getthis_cpx(){
   485         return this_class;
   486     }
   487 
   488     public String TagString (int tag) {
   489         String res=Tables.tagName(tag);
   490         if (res==null)  return "BOGUS_TAG:"+tag;
   491         return res;
   492     }
   493 
   494     /**
   495      * Returns string at that index.
   496      */
   497     public String StringValue(int cpx) {
   498         if (cpx==0) return "#0";
   499         int tag;
   500         Object x;
   501         String suffix="";
   502         try {
   503             tag=tags[cpx];
   504             x=cpool[cpx];
   505         } catch (IndexOutOfBoundsException e) {
   506             return "<Incorrect CP index:"+cpx+">";
   507         }
   508 
   509         if (x==null) return "<NULL>";
   510         switch (tag) {
   511         case CONSTANT_UTF8: {
   512             StringBuffer sb=new StringBuffer();
   513             String s=(String)x;
   514             for (int k=0; k<s.length(); k++) {
   515                 char c=s.charAt(k);
   516                 switch (c) {
   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);
   522                 }
   523             }
   524             return sb.toString();
   525         }
   526         case CONSTANT_DOUBLE: {
   527             Double d=(Double)x;
   528             String sd=d.toString();
   529             return sd+"d";
   530         }
   531         case CONSTANT_FLOAT: {
   532             Float f=(Float)x;
   533             String sf=(f).toString();
   534             return sf+"f";
   535         }
   536         case CONSTANT_LONG: {
   537             Long ln = (Long)x;
   538             return ln.toString()+'l';
   539         }
   540         case CONSTANT_INTEGER: {
   541             Integer in = (Integer)x;
   542             return in.toString();
   543         }
   544         case CONSTANT_CLASS:
   545             return javaName(getClassName(cpx));
   546         case CONSTANT_STRING:
   547             return StringValue(((CPX)x).cpx);
   548         case CONSTANT_FIELD:
   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);
   553 
   554         case CONSTANT_NAMEANDTYPE:
   555             return getName(((CPX2)x).cpx1)+":"+StringValue(((CPX2)x).cpx2);
   556         default:
   557             return "UnknownTag"; //TBD
   558         }
   559     }
   560 
   561     /**
   562      * Returns resolved java type name.
   563      */
   564     public String javaName(String name) {
   565         if( name==null) return "null";
   566         int len=name.length();
   567         if (len==0) return "\"\"";
   568         int cc='/';
   569     fullname: { // xxx/yyy/zzz
   570             int cp;
   571             for (int k=0; k<len; k += Character.charCount(cp)) {
   572                 cp=name.codePointAt(k);
   573                 if (cc=='/') {
   574                     if (!Character.isJavaIdentifierStart(cp)) break fullname;
   575                 } else if (cp!='/') {
   576                     if (!Character.isJavaIdentifierPart(cp)) break fullname;
   577                 }
   578                 cc=cp;
   579             }
   580             return name;
   581         }
   582         return "\""+name+"\"";
   583     }
   584 
   585     public String getName(int cpx) {
   586         String res;
   587         try {
   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+">";
   593         }
   594     }
   595 
   596     /**
   597      * Returns unqualified class name.
   598      */
   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);
   606             }
   607         }
   608         return classname;
   609     }
   610 
   611     /**
   612      * Returns source file name.
   613      */
   614     public String getSourceName(){
   615         return getName(source_cpx);
   616     }
   617 
   618     /**
   619      * Returns package name.
   620      */
   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");
   627         }else return null;
   628     }
   629 
   630     /**
   631      * Returns total constant pool entry count.
   632      */
   633     public int getCpoolCount(){
   634         return cpool_count;
   635     }
   636 
   637     public String StringTag(int cpx) {
   638         byte tag=0;
   639         String str=null;
   640         try {
   641             if (cpx==0) throw new IndexOutOfBoundsException();
   642             tag=tags[cpx];
   643             return      TagString(tag);
   644         } catch (IndexOutOfBoundsException e) {
   645             str="Incorrect CP index:"+cpx;
   646         }
   647         return str;
   648     }
   649 
   650     /**
   651      * Returns minor version of class file.
   652      */
   653     public int getMinor_version(){
   654         return minor_version;
   655     }
   656 
   657     /**
   658      * Returns major version of class file.
   659      */
   660     public int getMajor_version(){
   661         return major_version;
   662     }
   663 }