/* * Copyright (C) 2014, United States Government, as represented by the * Administrator of the National Aeronautics and Space Administration. * All rights reserved. * * The Java Pathfinder core (jpf-core) platform is licensed under the * Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package gov.nasa.jpf.jvm; import java.io.PrintWriter; import gov.nasa.jpf.util.StructuredPrinter; import gov.nasa.jpf.vm.ClassParseException; /** * simple tool to print contents of a classfile * * <2do> use indentation level variable and formated output */ public class ClassFilePrinter extends StructuredPrinter implements ClassFileReader { public static void main(String[] args){ ClassFilePrinter printer = new ClassFilePrinter(); try { ClassFile cf = new ClassFile(args[0]); cf.parse(printer); } catch (ClassParseException cfx){ cfx.printStackTrace(); } } @Override public void setClass(ClassFile cf, String clsName, String superClsName, int flags, int cpCount) { printSectionHeader( "constpool"); printCp(pw,cf); incIndent(); printSectionHeader( "class"); pw.printf("%sclass=%s\n", indent, clsName); pw.printf("%ssuperclass=%s\n", indent, superClsName); pw.printf("%sflags=0x%X\n", indent, flags); } //--- interfaces @Override public void setInterfaceCount(ClassFile cf, int ifcCount) { pw.printf("%sinterface count=%d\n", indent, ifcCount); incIndent(); } @Override public void setInterface(ClassFile cf, int ifcIndex, String ifcName) { pw.printf("%s[%d]: %s\n", indent, ifcIndex, ifcName); } @Override public void setInterfacesDone(ClassFile cf){ decIndent(); } //--- fields @Override public void setFieldCount(ClassFile cf, int fieldCount) { printSectionHeader( "fields"); pw.printf( "%sfield count=%d\n", indent, fieldCount); } @Override public void setField(ClassFile cf, int fieldIndex, int accessFlags, String name, String descriptor) { pw.printf("%s[%d]: %s, type=%s,flags=0x%X", indent, fieldIndex, name, descriptor, accessFlags); } @Override public void setFieldAttributeCount(ClassFile cf, int fieldIndex, int attrCount) { pw.printf(", attr count=%d\n", attrCount); incIndent(); } @Override public void setFieldAttribute(ClassFile cf, int fieldIndex, int attrIndex, String name, int attrLength) { pw.printf("%s[%d]: %s", indent, attrIndex, name); if (name == ClassFile.CONST_VALUE_ATTR) { cf.parseConstValueAttr(this, null); } else if (name == ClassFile.RUNTIME_VISIBLE_ANNOTATIONS_ATTR){ cf.parseAnnotationsAttr(this, null); } else if (name == ClassFile.RUNTIME_INVISIBLE_ANNOTATIONS_ATTR){ cf.parseAnnotationsAttr(this, null); } else if (name == ClassFile.RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR){ cf.parseTypeAnnotationsAttr(this, null); } else if (name == ClassFile.SIGNATURE_ATTR){ cf.parseSignatureAttr(this, null); } else { pw.printf(" ,length=%d,data=[",attrLength ); printRawData(pw, cf, attrLength, 10); pw.println(']'); } } @Override public void setFieldAttributesDone(ClassFile cf, int fieldIndex){ decIndent(); } @Override public void setFieldDone(ClassFile cf, int fieldIndex){ pw.println(); } @Override public void setFieldsDone(ClassFile cf){ } @Override public void setConstantValue(ClassFile cf, Object tag, Object value) { pw.printf(" value=%s\n", value); } //--- methods @Override public void setMethodCount(ClassFile cf, int methodCount) { printSectionHeader( "methods"); pw.printf( "%smethod count=%d\n", indent, methodCount); } @Override public void setMethod(ClassFile cf, int methodIndex, int accessFlags, String name, String descriptor) { pw.printf("%s[%d]: %s%s, flags=0x%X", indent, methodIndex, name, descriptor, accessFlags); } @Override public void setMethodAttributeCount(ClassFile cf, int methodIndex, int attrCount) { pw.printf(", attr count=%d\n", attrCount); incIndent(); } @Override public void setMethodAttribute(ClassFile cf, int methodIndex, int attrIndex, String name, int attrLength) { pw.printf("%s[%d]: %s", indent, attrIndex, name); if (name == ClassFile.CODE_ATTR) { cf.parseCodeAttr(this, null); } else if (name == ClassFile.EXCEPTIONS_ATTR){ cf.parseExceptionAttr(this, null); } else if (name == ClassFile.RUNTIME_VISIBLE_ANNOTATIONS_ATTR){ cf.parseAnnotationsAttr(this, null); } else if (name == ClassFile.RUNTIME_INVISIBLE_ANNOTATIONS_ATTR){ cf.parseAnnotationsAttr(this, null); } else if (name == ClassFile.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS_ATTR){ cf.parseParameterAnnotationsAttr(this, null); } else if (name == ClassFile.RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR){ cf.parseTypeAnnotationsAttr(this, null); } else if (name == ClassFile.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS_ATTR){ cf.parseParameterAnnotationsAttr(this, null); } else if (name == ClassFile.SIGNATURE_ATTR){ cf.parseSignatureAttr(this, null); } else { pw.printf(" ,length=%d,data=[", attrLength ); printRawData(pw, cf, attrLength, 10); pw.println(']'); } } @Override public void setMethodAttributesDone(ClassFile cf, int methodIndex){ decIndent(); } @Override public void setMethodDone(ClassFile cf, int methodIndex){ pw.println(); } @Override public void setMethodsDone(ClassFile cf){ } @Override public void setExceptionCount(ClassFile cf, Object tag, int exceptionCount){ pw.printf(", count=%d\n", exceptionCount); incIndent(); } @Override public void setException(ClassFile cf, Object tag, int exceptionIndex, String exceptionType){ pw.printf("%s[%d]: %s\n", indent, exceptionIndex, exceptionType); } @Override public void setExceptionsDone(ClassFile cf, Object tag){ decIndent(); } @Override public void setCode(ClassFile cf, Object tag, int maxStack, int maxLocals, int codeLength) { pw.printf(", maxStack=%d,maxLocals=%d,length=%d\n", maxStack, maxLocals,codeLength); incIndent(); JVMByteCodePrinter bcPrinter = new JVMByteCodePrinter(pw, cf, indent); cf.parseBytecode(bcPrinter, tag, codeLength); decIndent(); } @Override public void setExceptionHandlerTableCount(ClassFile cf, Object tag, int exceptionTableCount) { pw.printf("%sexception table count=%d\n", indent, exceptionTableCount); incIndent(); } @Override public void setExceptionHandler(ClassFile cf, Object tag, int exceptionIndex, int startPc, int endPc, int handlerPc, String catchType) { pw.printf("%s[%d]: type=%s, range=[%d..%d], handler=%d\n", indent, exceptionIndex, catchType, startPc, endPc, handlerPc); } @Override public void setExceptionHandlerTableDone(ClassFile cf, Object tag){ decIndent(); } @Override public void setCodeAttributeCount(ClassFile cf, Object tag, int attrCount) { pw.printf("%scode attribute count=%d\n", indent, attrCount); incIndent(); } @Override public void setCodeAttribute(ClassFile cf, Object tag, int attrIndex, String name, int attrLength) { pw.printf("%s[%d]: %s", indent, attrIndex, name); if (name == ClassFile.LINE_NUMBER_TABLE_ATTR) { cf.parseLineNumberTableAttr(this, tag); } else if (name == ClassFile.LOCAL_VAR_TABLE_ATTR) { cf.parseLocalVarTableAttr(this, tag); } else if (name == ClassFile.RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR){ cf.parseTypeAnnotationsAttr(this, tag); } else { // generic pw.printf(" ,length=%d,data=[", attrLength ); printRawData(pw, cf, attrLength, 10); pw.println(']'); } } @Override public void setCodeAttributesDone(ClassFile cf, Object tag){ decIndent(); } @Override public void setLineNumberTableCount(ClassFile cf, Object tag, int lineNumberCount) { pw.printf(", linenumber count=%d\n", lineNumberCount); incIndent(); } @Override public void setLineNumber(ClassFile cf, Object tag, int lineIndex, int lineNumber, int startPc) { pw.printf("%s[%d]: line=%d, pc=%d\n", indent, lineIndex, lineNumber, startPc); } @Override public void setLineNumberTableDone(ClassFile cf, Object tag){ decIndent(); } @Override public void setLocalVarTableCount(ClassFile cf, Object tag, int localVarCount) { pw.printf(", localVar count=%d\n", localVarCount); incIndent(); } @Override public void setLocalVar(ClassFile cf, Object tag, int localVarIndex, String varName, String descriptor, int scopeStartPc, int scopeEndPc, int slotIndex) { pw.printf("%s[%d]: %s, type=%s, scope=[%d..%d], slot=%d\n", indent, localVarIndex, varName, descriptor, scopeStartPc, scopeEndPc, slotIndex); } @Override public void setLocalVarTableDone(ClassFile cf, Object tag){ decIndent(); } //--- class attributes @Override public void setClassAttributeCount(ClassFile cf, int attrCount) { printSectionHeader( "class attributes"); pw.printf("%sclass attribute count=%d\n", indent, attrCount); incIndent(); } @Override public void setClassAttribute(ClassFile cf, int attrIndex, String name, int attrLength) { pw.printf("%s[%d]: %s", indent, attrIndex, name); if (name == ClassFile.SOURCE_FILE_ATTR) { cf.parseSourceFileAttr(this, null); } else if (name == ClassFile.DEPRECATED_ATTR) { } else if (name == ClassFile.INNER_CLASSES_ATTR) { cf.parseInnerClassesAttr(this, null); } else if (name == ClassFile.RUNTIME_VISIBLE_ANNOTATIONS_ATTR){ cf.parseAnnotationsAttr(this, null); } else if (name == ClassFile.RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR){ cf.parseTypeAnnotationsAttr(this, null); } else if (name == ClassFile.RUNTIME_INVISIBLE_ANNOTATIONS_ATTR){ cf.parseAnnotationsAttr(this, null); } else if (name == ClassFile.SIGNATURE_ATTR){ cf.parseSignatureAttr(this, null); } else if (name == ClassFile.ENCLOSING_METHOD_ATTR){ cf.parseEnclosingMethodAttr(this, null); } else if (name == ClassFile.BOOTSTRAP_METHOD_ATTR){ cf.parseBootstrapMethodAttr(this, null); } else { pw.printf(" ,length=%d,data=[", attrLength ); printRawData(pw, cf, attrLength, 10); pw.println(']'); } } @Override public void setClassAttributesDone(ClassFile cf){ decIndent(); } @Override public void setEnclosingMethod(ClassFile cf, Object tag, String enclosingClass, String enclosingMethod, String descriptor) { if (enclosingMethod != null){ pw.printf(", enclosingClass=%s, method=%s%s\n", enclosingClass, enclosingMethod, descriptor); } else { pw.printf(", enclosingClass=%s\n", enclosingClass); } } @Override public void setSourceFile(ClassFile cf, Object tag, String pathName){ pw.printf(", path=%s\n", pathName); } @Override public void setInnerClassCount(ClassFile cf, Object tag, int innerClsCount) { pw.printf( ", inner class count=%d\n", innerClsCount); incIndent(); } @Override public void setInnerClass(ClassFile cf, Object tag, int innerClsIndex, String outerName, String innerName, String innerSimpleName, int accessFlags) { pw.printf("%s[%d]: %s, fullName=%s, outerClass=%s, flags=0x%X\n", indent, innerClsIndex, innerSimpleName, innerName, outerName, accessFlags); } @Override public void setInnerClassesDone(ClassFile cf, Object tag){ decIndent(); } @Override public void setBootstrapMethodCount (ClassFile cf, Object tag, int count) { pw.printf( ", bootstrap method count=%d\n", count); incIndent(); } @Override public void setBootstrapMethod (ClassFile cf, Object tag, int idx, int refKind, String cls, String mth, String descriptor, int[] cpArgs){ String refTypeName = cf.getRefTypeName(refKind); pw.printf("%s[%d]: %s %s.%s%s\n", indent, idx, refTypeName, cls, mth, descriptor); incIndent(); pw.printf("%smethod arg count: %d\n", indent, cpArgs.length); incIndent(); for (int i=0; i<cpArgs.length; i++){ int cpIdx = cpArgs[i]; String arg = getBootstrapMethodArgAsString(cf, cpIdx); pw.printf("%s[%d]: %s\n", indent, i, arg); } decIndent(); decIndent(); } String getBootstrapMethodArgAsString (ClassFile cf, int cpIdx){ StringBuilder sb = new StringBuilder(); Object cpValue = cf.getCpValue(cpIdx); sb.append('@'); sb.append(cpIdx); sb.append(" ("); sb.append( cpValue); sb.append("): "); if (cpValue instanceof ClassFile.CpInfo){ switch ((ClassFile.CpInfo)cpValue){ case MethodType: sb.append( cf.methodTypeDescriptorAt(cpIdx)); break; case MethodHandle: int methodRefIdx = cf.mhMethodRefIndexAt(cpIdx); sb.append( cf.getRefTypeName(cf.mhRefTypeAt(cpIdx))); sb.append(' '); sb.append( cf.methodClassNameAt(methodRefIdx)); sb.append('.'); sb.append( cf.methodNameAt(methodRefIdx)); sb.append( cf.methodDescriptorAt(methodRefIdx)); break; default: sb.append( cpValue.toString()); } } else { sb.append( cpValue.toString()); } return sb.toString(); } @Override public void setBootstrapMethodsDone (ClassFile cf, Object tag) { decIndent(); } @Override public void setAnnotationCount(ClassFile cf, Object tag, int annotationCount){ pw.printf( " count=%d\n", annotationCount); incIndent(); } @Override public void setAnnotation(ClassFile cf, Object tag, int annotationIndex, String annotationType){ pw.printf("%s[%d]: %s", indent, annotationIndex, annotationType); } @Override public void setAnnotationsDone(ClassFile cf, Object tag){ decIndent(); } // Java 8 type annotations @Override public void setTypeAnnotationCount(ClassFile cf, Object tag, int annotationCount){ pw.printf( " count=%d\n", annotationCount); incIndent(); } @Override public void setTypeParameterAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType, int typeIndex, short[] typePath, String annotationType){ pw.printf("%s[%d]: %s (%s, type path=%s, type index=%d)", indent, annotationIndex, annotationType, ClassFile.getTargetTypeName(targetType), ClassFile.getTypePathEncoding(typePath), typeIndex); } @Override public void setSuperTypeAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType, int superTypeIdx, short[] typePath, String annotationType){ pw.printf("%s[%d]: %s (%s, type path=%s, super type index=%d)", indent, annotationIndex, annotationType, ClassFile.getTargetTypeName(targetType), ClassFile.getTypePathEncoding(typePath), superTypeIdx); } @Override public void setTypeParameterBoundAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType, int typeParamIdx, int boundIdx, short[] typePath, String annotationType){ pw.printf("%s[%d]: %s (%s, type path=%s, type index=%d, bound=%d)", indent, annotationIndex, annotationType, ClassFile.getTargetTypeName(targetType), ClassFile.getTypePathEncoding(typePath), typeParamIdx, boundIdx); } @Override public void setTypeAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType, short[] typePath, String annotationType){ pw.printf("%s[%d]: %s (%s, type path=%s)", indent, annotationIndex, annotationType, ClassFile.getTargetTypeName(targetType), ClassFile.getTypePathEncoding(typePath)); } @Override public void setFormalParameterAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType, int formalParamIdx, short[] typePath, String annotationType){ pw.printf("%s[%d]: %s (%s, type path=%s, formal param index=%d)", indent, annotationIndex, annotationType, ClassFile.getTargetTypeName(targetType), ClassFile.getTypePathEncoding(typePath), formalParamIdx); } @Override public void setThrowsAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType, int throwsTypeIdx, short[] typePath, String annotationType){ pw.printf("%s[%d]: %s (%s, type path=%s, throws index=%d)", indent, annotationIndex, annotationType, ClassFile.getTargetTypeName(targetType), ClassFile.getTypePathEncoding(typePath), throwsTypeIdx); } @Override public void setVariableAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType, long[] scopeEntries, short[] typePath, String annotationType){ pw.printf("%s[%d]: %s (%s, type path=%s, scope=%s)", indent, annotationIndex, annotationType, ClassFile.getTargetTypeName(targetType), ClassFile.getTypePathEncoding(typePath), ClassFile.getScopeEncoding(scopeEntries)); // 2do } @Override public void setExceptionParameterAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType, int exceptionIndex, short[] typePath, String annotationType){ pw.printf("%s[%d]: %s (%s, type path=%s, catch type index=%d)", indent, annotationIndex, annotationType, ClassFile.getTargetTypeName(targetType), ClassFile.getTypePathEncoding(typePath), exceptionIndex); } @Override public void setBytecodeAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType, int offset, short[] typePath, String annotationType){ pw.printf("%s[%d]: %s (%s, type path=%s, bytecode offset=%d)", indent, annotationIndex, annotationType, ClassFile.getTargetTypeName(targetType), ClassFile.getTypePathEncoding(typePath), offset); } @Override public void setBytecodeTypeParameterAnnotation(ClassFile cf, Object tag, int annotationIndex, int targetType, int offset, int typeArgIdx, short[] typePath, String annotationType){ pw.printf("%s[%d]: %s (%s, type path=%s, bytecode offset=%d, type arg=%d)", indent, annotationIndex, annotationType, ClassFile.getTargetTypeName(targetType), ClassFile.getTypePathEncoding(typePath), offset, typeArgIdx); } @Override public void setTypeAnnotationsDone(ClassFile cf, Object tag) { decIndent(); } @Override public void setAnnotationValueCount(ClassFile cf, Object tag, int annotationIndex, int nValuePairs){ pw.printf(" valueCount=%d\n", nValuePairs); incIndent(); } @Override public void setPrimitiveAnnotationValue(ClassFile cf, Object tag, int annotationIndex, int valueIndex, String elementName, int arrayIndex, Object val){ if (arrayIndex < 0){ pw.printf("%s[%d]: %s=%s\n", indent, annotationIndex, elementName, val); } else { if (arrayIndex==0) { pw.printf("%s[%d]: %s={", indent, valueIndex, elementName); } else { pw.print(','); } pw.print(val); } } @Override public void setStringAnnotationValue(ClassFile cf, Object tag, int annotationIndex, int valueIndex, String elementName, int arrayIndex, String s){ if (arrayIndex < 0){ pw.printf("%s[%d]: %s=\"%s\"\n", indent, annotationIndex, elementName, s); } else { if (arrayIndex==0) { pw.printf("%s[%d]: %s={", indent, valueIndex, elementName); } else { pw.print(','); } pw.printf("\"%s\"", s); } } @Override public void setClassAnnotationValue(ClassFile cf, Object tag, int annotationIndex, int valueIndex, String elementName, int arrayIndex, String typeName){ if (arrayIndex < 0){ pw.printf("%s[%d]: %s=class %s\n", indent, annotationIndex, elementName, typeName); } else { if (arrayIndex==0) { pw.printf("%s[%d]: %s={", indent, valueIndex, elementName); } else { pw.print(','); } pw.printf("class %s", typeName); } } @Override public void setEnumAnnotationValue(ClassFile cf, Object tag, int annotationIndex, int valueIndex, String elementName, int arrayIndex, String enumType, String enumValue){ if (arrayIndex < 0){ pw.printf("%s[%d]: %s=%s.%s\n", indent, annotationIndex, elementName, enumType, enumValue); } else { if (arrayIndex==0) { pw.printf("%s[%d]: %s={", indent, valueIndex, elementName); } else { pw.print(','); } pw.printf("%s.%s", enumType, enumValue); } } @Override public void setAnnotationValueElementCount(ClassFile cf, Object tag, int annotationIndex, int valueIndex, String elementName, int elementCount){ } @Override public void setAnnotationValueElementsDone(ClassFile cf, Object tag, int annotationIndex, int valueIndex, String elementName){ pw.println("}"); } @Override public void setAnnotationValuesDone(ClassFile cf, Object tag, int annotationIndex){ decIndent(); } @Override public void setParameterCount(ClassFile cf, Object tag, int parameterCount){ pw.printf(" parameterCount=%d\n", parameterCount); incIndent(); } @Override public void setParameterAnnotationCount(ClassFile cf, Object tag, int paramIndex, int annotationCount){ pw.printf("%s[%d] count: %d\n", indent, paramIndex, annotationCount); incIndent(); } @Override public void setParameterAnnotation(ClassFile cf, Object tag, int annotationIndex, String annotationType){ pw.printf("%s[%d]: %s", indent, annotationIndex, annotationType); } @Override public void setParameterAnnotationsDone(ClassFile cf, Object tag, int paramIndex){ decIndent(); } @Override public void setParametersDone(ClassFile cf, Object tag){ decIndent(); } @Override public void setSignature(ClassFile cf, Object tag, String signature){ pw.printf(" %s\n", signature); } //--- internal stuff protected void printCp (PrintWriter pw, ClassFile cf){ int nCpEntries = cf.getNumberOfCpEntries(); for (int i=1; i<nCpEntries; i++){ int j = cf.getDataPosOfCpEntry(i); pw.print(" ["); pw.print(i); pw.print("]: "); if (j < 0) { pw.println("<unused>"); continue; } switch (cf.u1(j)){ case ClassFile.CONSTANT_UTF8: pw.print( "constant_utf8 {\""); pw.print( cf.getCpValue(i)); pw.println("\"}"); break; case ClassFile.CONSTANT_INTEGER: pw.print( "constant_integer {"); pw.print( cf.getCpValue(i)); pw.println("}"); break; case ClassFile.CONSTANT_FLOAT: pw.print( "constant_float {"); pw.print( cf.getCpValue(i)); pw.println("}"); break; case ClassFile.CONSTANT_LONG: pw.print( "constant_long {"); pw.print( cf.getCpValue(i)); pw.println("}"); break; case ClassFile.CONSTANT_DOUBLE: pw.print( "constant_double {"); pw.print( cf.getCpValue(i)); pw.println("}"); break; case ClassFile.CONSTANT_CLASS: pw.print("constant_class {name=#"); pw.print( cf.u2(j+1)); pw.print("(\""); pw.print( cf.classNameAt(i)); pw.println("\")}"); break; case ClassFile.CONSTANT_STRING: pw.print("constant_string {utf8=#"); pw.print( cf.u2(j+1)); pw.print("(\""); pw.print( cf.stringAt(i)); pw.println("\")}"); break; case ClassFile.FIELD_REF: printRef(pw, cf, i, j, "fieldref"); break; case ClassFile.METHOD_REF: printRef(pw, cf, i, j, "methodref"); break; case ClassFile.INTERFACE_METHOD_REF: printRef(pw, cf, i, j, "interface_methodref"); break; case ClassFile.NAME_AND_TYPE: pw.print("name_and_type {name=#"); pw.print( cf.u2(j+1)); pw.print("(\""); pw.print(cf.utf8At(cf.u2(j+1))); pw.print("\"),desciptor=#"); pw.print( cf.u2(j+3)); pw.print("(\""); pw.print(cf.utf8At(cf.u2(j+3))); pw.println("\")}"); break; case ClassFile.METHOD_HANDLE: pw.print("method_handle {"); pw.print("(\""); pw.println("\")}"); break; case ClassFile.METHOD_TYPE: pw.print("method_type {"); pw.print("(\""); pw.println("\")}"); break; case ClassFile.INVOKE_DYNAMIC: pw.print("invoke_dynamic {bootstrap=#"); pw.print(cf.u2(j+1)); pw.print("(\""); pw.println("\")}"); break; default: pw.print("ERROR: illegal tag" + cf.u1(j)); } } pw.println(); } void printRef(PrintWriter pw, ClassFile cf, int cpIdx, int dataPos, String refType){ pw.print(refType); pw.print(" {class=#"); pw.print(cf.u2(dataPos + 1)); pw.print("(\""); pw.print(cf.refClassNameAt(cpIdx)); pw.print("\"),nameType=#"); pw.print(cf.u2(dataPos + 3)); pw.print("(\""); pw.print(cf.refNameAt(cpIdx)); pw.print("\",\""); pw.print(cf.refDescriptorAt(cpIdx)); pw.println("\")}"); } void printRawData(PrintWriter pw, ClassFile cf, int dataLength, int maxBytes){ int max = Math.min(dataLength, maxBytes); int max1 = max-1; for (int i=0; i<max1; i++){ pw.printf("%02x ", cf.readUByte()); } pw.printf("%02x", cf.readUByte()); if (dataLength>maxBytes){ pw.print(".."); } } }