/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public * License Version 1.1 (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.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): */ #include "ClassReader.h" #include "AttributeHandlers.h" #include #ifndef NO_NSPR #include "plstr.h" #endif #ifdef DEBUG #include "DebugUtils.h" #include "JavaBytecodes.h" #include void indent(int n) { for (; n; n--) printf(" "); } void title(int nIndents, const char *s) { indent(nIndents); printf("%s\n", s); } void print(int nIndents, const char *fmt, ...) { va_list args; static char buffer[2048]; indent(nIndents); va_start(args, fmt); vsprintf(buffer, fmt, args); va_end(args); printf("%s\n", buffer); } #endif /* Functions to parse method and field descriptors */ static bool parseFieldDescriptor(Pool &pool, const char *s, JavaType &type, const char **next) { TypeKind tk; switch (*s) { case 'B': tk = tkByte; break; case 'C': tk = tkChar; break; case 'D': tk = tkDouble; break; case 'F': tk = tkFloat; break; case 'I': tk = tkInt; break; case 'J': tk = tkLong; break; case 'S': tk = tkShort; break; case 'Z': tk = tkBoolean; break; case '[': { JavaType *javaType = new (pool) JavaType; if (!javaType) return false; if (!parseFieldDescriptor(pool, s+1, *javaType, next)) return false; type.set(*javaType); return true; } case 'L': { #ifdef NO_NSPR char *t = strchr(++s, ';'); #else char *t = PL_strchr(++s, ';'); #endif if (!t) return false; int len = t-s+1; char *instanceClass = new (pool) char [len]; if (!instanceClass) return false; #ifdef NO_NSPR strncpy(instanceClass, s, len-1); #else PL_strncpy(instanceClass, s, len-1); #endif instanceClass[len-1] = 0; *next = (char *) t+1; type.set(instanceClass); return true; } default: return false; } type.set(tk); *next = s+1; return true; } inline int getJavaSize(const JavaType *type) { return getTypeKindSize(type->getKind()); } /* Implementation of ConstantUtf8 */ ConstantUtf8::ConstantUtf8(Pool &pool, char *str, int len) : ConstantPoolItem(pool, CR_CONSTANT_UTF8) { data = str; dataLen = len; } #ifdef DEBUG void ConstantUtf8::dump(int nIndents) { title(nIndents, "CONSTANT_UTF8"); print(nIndents, "String: %s", data); } #endif ConstantUtf8::ConstantUtf8(Pool &pool, int len) : ConstantPoolItem(pool, CR_CONSTANT_UTF8) { dataLen = len; } /* Implementation of ConstantClass */ int ConstantClass::resolveAndValidate() { if (pool) utfString = (ConstantUtf8 *) pool[index]; return (utfString && utfString->getType() == CR_CONSTANT_UTF8); } #ifdef DEBUG void ConstantClass::dump(int nIndents) { title(nIndents, "CONSTANT_CLASS"); utfString->dump(nIndents+1); } #endif /* Implementation of ConstantNameAndType */ int ConstantNameAndType::resolveAndValidate() { if (pool) { nameInfo = (ConstantUtf8 *) pool[nameIndex]; descInfo = (ConstantUtf8 *) pool[descIndex]; } return (nameInfo && descInfo && nameInfo->getType() == CR_CONSTANT_UTF8 && descInfo->getType() == CR_CONSTANT_UTF8); } #ifdef DEBUG void ConstantNameAndType::dump(int nIndents) { title(nIndents, "CONSTANT_NAMEANDTYPE (name/desc)"); nameInfo->dump(nIndents+1); descInfo->dump(nIndents+1); } #endif ConstantNameAndType::ConstantNameAndType(Pool &pool, ConstantPoolItem **array, int nindex, int dIndex) : ConstantPoolItem(pool, array, CR_CONSTANT_NAMEANDTYPE) { nameIndex = nindex, descIndex = dIndex; nameInfo = descInfo = 0; } /* Implementation of ConstantRef */ int ConstantRef::resolveAndValidate() { if (pool) { classInfo = (ConstantClass *) pool[classIndex]; typeInfo = (ConstantNameAndType *) pool[typeIndex]; } return (classInfo && typeInfo && classInfo->getType() == CR_CONSTANT_CLASS && typeInfo->getType() == CR_CONSTANT_NAMEANDTYPE); } #ifdef DEBUG void ConstantRef::dump(int nIndents) { print(nIndents+2, "Printing ClassInfo and typeInfo"); classInfo->dump(nIndents+1); typeInfo->dump(nIndents+1); } #endif ConstantRef::ConstantRef(Pool &pool, uint8 _type, ConstantPoolItem **array, int cIndex, int tIndex) : ConstantPoolItem(pool, array, _type) { classIndex = cIndex, typeIndex = tIndex; classInfo = 0; typeInfo = 0; } /* Implementation of ConstantFieldRef */ #ifdef DEBUG void ConstantFieldRef::dump(int nIndents) { title(nIndents, "CONSTANT_FIELD_REF"); ConstantRef::dump(nIndents); } #endif /* Implementation of ConstantMethodRef */ #ifdef DEBUG void ConstantMethodRef::dump(int nIndents) { title(nIndents, "CONSTANT_METHOD_REF"); ConstantRef::dump(nIndents); } #endif /* Implementation of class ConstantInterfaceMethodRef */ #ifdef DEBUG void ConstantInterfaceMethodRef::dump(int nIndents) { title(nIndents, "CONSTANT_INTERFACEMETHOD_REF"); ConstantRef::dump(nIndents); } #endif /* Implementation of ConstantString */ int ConstantString::resolveAndValidate() { if (pool) utfString = (ConstantUtf8 *) pool[index]; return (utfString && utfString->getType() == CR_CONSTANT_UTF8); } #ifdef DEBUG void ConstantString::dump(int nIndents) { title(nIndents, "CONSTANT_STRING"); utfString->dump(nIndents+1); } #endif /* Implementation of ConstantVal */ #ifdef DEBUG void ConstantVal::dump(int nIndents) { switch (vk) { case vkInt: title(nIndents, "CONSTANT_INT"); print(nIndents, "Value: %d", value.i); break; case vkFloat: title(nIndents, "CONSTANT_FLOAT"); print(nIndents, "Value: %f", value.f); break; case vkDouble: title(nIndents, "CONSTANT_DOUBLE"); print(nIndents, "Value: %lf", value.d); break; case vkLong: title(nIndents, "CONSTANT_LONG"); break; default: break; } } #endif /* Implementation of ConstantFloat */ ConstantFloat::ConstantFloat(Pool &pool, uint32 _raw): ConstantVal(pool, CR_CONSTANT_FLOAT, vkFloat), raw(_raw) { if (raw == 0x7f80000) value.setValueContents(floatPositiveInfinity); else if (raw == 0xff800000) value.setValueContents(floatNegativeInfinity); #if 0 else if ((raw >= 0x7f800001 && raw <= 0x7fffffff) || (raw >= 0xff800001 && raw <= 0xffffffff)) #else else if ((raw & 0x7f800001) || (raw & 0xff800001)) #endif value.setValueContents(floatNaN); else { int s = ((raw >> 31) == 0) ? 1 : -1; int e = ((raw >> 23) &0xff); int m = (e == 0) ? (raw & 0x7fffff) << 1: (raw & 0x7fffff) | 0x800000; value.setValueContents((Flt32) s * m * pow(2.0, e-150)); } } /* Implementation of ConstantLong */ ConstantLong::ConstantLong(Pool &pool, uint32 _lo, uint32 _hi) : ConstantVal(pool, CR_CONSTANT_LONG, vkLong), lo(_lo), hi(_hi) { #ifdef HAVE_LONG_LONG int64 lw, llo, lhi; llo = (int64) lo; lhi = (int64) hi; lhi <<= 32; lw = llo | lhi; value.setValueContents(lw); #else value.l.lo = lo; value.l.hi = hi; #endif } /* Implementation of ConstantDouble */ ConstantDouble::ConstantDouble(Pool &pool, char *_data): ConstantVal(pool, CR_CONSTANT_DOUBLE, vkDouble) { union { unsigned char c[8]; Flt64 d; } u; memcpy(data, _data, 8); #ifdef LITTLE_ENDIAN u.c[0] = data[7]; u.c[1] = data[6]; u.c[2] = data[5]; u.c[3] = data[4]; u.c[4] = data[3]; u.c[5] = data[2]; u.c[6] = data[1]; u.c[7] = data[0]; #else u.c[0] = data[0]; u.c[1] = data[1]; u.c[2] = data[2]; u.c[3] = data[3]; u.c[4] = data[4]; u.c[5] = data[5]; u.c[6] = data[6]; u.c[7] = data[7]; #endif value.d = u.d; } /* Implementation of AttributeSourceFile */ #ifdef DEBUG void AttributeSourceFile::dump(int nIndents) { title(nIndents, "SOURCE-FILE"); srcName->dump(nIndents+1); } #endif /* Implementation of AttributeConstantValue */ #ifdef DEBUG void AttributeConstantValue::dump(int nIndents) { title(nIndents, "CONSTANT-VALUE"); value->dump(nIndents+1); } #endif /* Implementation of ExceptionItem */ ExceptionItem::ExceptionItem(uint16 _startPc, uint16 _endPc, uint16 _handlerPc, ConstantClass *_catcher, uint16 _catcherIndex) { startPc = _startPc, endPc = _endPc, handlerPc = _handlerPc, catcher = _catcher; catcherIndex = _catcherIndex; } #ifdef DEBUG void ExceptionItem::dump(int nIndents) { title(nIndents, "ExceptionItem"); print(nIndents+1, "Start %u End %u Handler %u", startPc, endPc, handlerPc); if (catcher) { print(nIndents+1, "CATCHER:"); catcher->dump(nIndents+2); } } #endif /* Implementation of AttributeCode */ AttributeCode::AttributeCode(Pool &pool, uint16 _length, uint16 _maxStack, uint16 _maxLocals, uint32 _codeLength, uint16 nindex, CrError *status): AttributeInfoItem(pool, "Code", CR_ATTRIBUTE_CODE, _length, nindex) { *status = crErrorNone; maxStack = _maxStack, maxLocals = _maxLocals, codeLength = _codeLength; numExceptions = 0; exceptions = 0; numAttributes = 0; attributes = 0; if (codeLength > 0) code = new (p) char[codeLength]; else code = 0; } int AttributeCode::setNumExceptions(int _numExceptions) { exceptions = new (p) ExceptionItem *[_numExceptions]; numExceptions = _numExceptions; return true; } int AttributeCode::setNumAttributes(int _numAttributes) { attributes = new (p) AttributeInfoItem *[_numAttributes]; numAttributes = _numAttributes; return true; } #ifdef DEBUG void AttributeCode::dump(int nIndents) { int32 i; title(nIndents, "CODE"); print(nIndents, "maxStack %u maxLocals %u codeLength %u numExceptions %u", maxStack, maxLocals, codeLength, numExceptions); if (numExceptions > 0) { title(nIndents, "Exceptions"); for (i = 0; i < (int32) numExceptions; i++) exceptions[i]->dump(nIndents+1); } if (numAttributes > 0) { title(nIndents, "Attributes"); for (i = 0; i < numAttributes; i++) attributes[i]->dump(nIndents+1); } } #endif /* Implementation of AttributeExceptions */ int AttributeExceptions::setNumExceptions(uint16 n) { exceptions = new (p) ConstantClass *[n]; excIndices = new (p) uint16[n]; numExceptions = n; return true; } #ifdef DEBUG void AttributeExceptions::dump(int nIndents) { int i; title(nIndents, "EXCEPTIONS"); print(nIndents, "numExceptions %d", numExceptions); if (numExceptions > 0) { title(nIndents, "Exceptions"); for (i = 0; i < numExceptions; i++) exceptions[i]->dump(nIndents+1); } } #endif /* Implementation of AttributeLineNumberTable */ int AttributeLineNumberTable::setNumEntries(uint16 n) { entries = new (p) LineNumberEntry[n]; numEntries = n; return true; } int AttributeLineNumberTable::getPc(uint16 lineNumber) { int i; /* The line numbers are not guaranteed to be in order */ for (i = 0; i < numEntries; i++) if (entries[i].lineNumber == lineNumber) return entries[i].startPc; return -1; } #ifdef DEBUG void AttributeLineNumberTable::dump(int nIndents) { title(nIndents, "LINE-NUMBER-ENTRY"); for (int i = 0; i < numEntries; i++) entries[i].dump(nIndents+1); } #endif /* Implementation of AttributeLocalVariableTable */ int AttributeLocalVariableTable::setNumEntries(uint16 n) { entries = new (p) LocalVariableEntry[n]; numEntries = n; return true; } #ifdef DEBUG void AttributeLocalVariableTable::dump(int nIndents) { title(nIndents, "LOCAL-VARIABLE-TABLE"); for (int i = 0; i < numEntries; i++) entries[i].dump(nIndents+1); } #endif /* Implementation of InfoItem */ InfoItem::InfoItem(Pool &pool, uint16 aflags, ConstantUtf8 *classInfo, ConstantUtf8 *nameInfo, ConstantUtf8 *descInfo, uint16 nIndex, uint16 dIndex) : p(pool), nameIndex(nIndex), descIndex(dIndex) { accessFlags = aflags; name = nameInfo; descriptor = descInfo; className = classInfo; attrCount = 0; } int InfoItem::addAttribute(AttributeInfoItem &attribute) { attributes.addLast(attribute); attrCount++; return true; } AttributeInfoItem *InfoItem::getAttribute(const char *_name) const { for (DoublyLinkedList::iterator i = attributes.begin(); !attributes.done(i); i = attributes.advance(i)) { AttributeInfoItem &attribute = attributes.get(i); #ifdef NO_NSPR if (!(strncmp(_name, attribute.getName(), attribute.getLength()))) #else if (!(PL_strncmp(_name, attribute.getName(), attribute.getLength()))) #endif return &attribute; } return 0; } AttributeInfoItem *InfoItem::getAttribute(const uint32 code) const { for (DoublyLinkedList::iterator i = attributes.begin(); !attributes.done(i); i = attributes.advance(i)) { AttributeInfoItem &attribute = attributes.get(i); if (attribute.getCode() == code) return &attribute; } return 0; } #ifdef DEBUG void InfoItem::dump(int nIndents) { print(nIndents, "%s() descriptor:%s", name->getUtfString(), descriptor->getUtfString()); print(nIndents, "AccessFlags %x attrCount %d", accessFlags, attrCount); if (attrCount > 0) { print(nIndents, "-> Attributes (%d):", attrCount); for (DoublyLinkedList::iterator i = attributes.begin(); !attributes.done(i); i = attributes.advance(i)) attributes.get(i).dump(nIndents+1); } } #endif /* Implementation of FieldInfo */ FieldInfo::FieldInfo(Pool &pool, uint16 aflags, ConstantUtf8 *classInfo, ConstantUtf8 *nameInfo, ConstantUtf8 *descInfo, uint16 nameindex, uint16 descindex) : InfoItem(pool, aflags, classInfo, nameInfo, descInfo, nameindex, descindex) { type = new (pool) JavaType; } void FieldInfo::getInfo(JavaType *&typeRet, bool &isVolatile, bool &isConstant, uint32 &offsetRet) const { typeRet = type; offsetRet = pos.offset; isVolatile = (getAccessFlags() & CR_FIELD_VOLATILE); isConstant = false; } void FieldInfo::getInfo(JavaType *&typeRet, bool &isVolatile, bool &isConstant, addr &addrRet) const { typeRet = type; addrRet = pos.a; isVolatile = (getAccessFlags() & CR_FIELD_VOLATILE); isConstant = false; } #ifdef DEBUG void FieldInfo::dump(int nIndents) { InfoItem::dump(nIndents); if (getAccessFlags() & CR_FIELD_STATIC) print(nIndents, "Address: %x", pos.a); else print(nIndents, "Offset: %d", pos.offset); } #endif /* Implementation of MethodInfo */ MethodInfo::MethodInfo(Pool &pool, uint16 aflags, ConstantUtf8 *classInfo, ConstantUtf8 *nameInfo, ConstantUtf8 *descInfo, uint16 nIndex, uint16 dIndex) : InfoItem(pool, aflags, classInfo, nameInfo, descInfo, nIndex, dIndex) { paramSize = 10; params = new (pool) JavaType[paramSize]; } const JavaType &MethodInfo::getSignature(int &nParams, const JavaType *¶mTypes, bool &isStatic, bool &isNative, bool &isAbstract) const { nParams = numParams; paramTypes = params; uint16 aFlags = getAccessFlags(); isStatic = (aFlags & CR_METHOD_STATIC) != 0; isNative = (aFlags & CR_METHOD_NATIVE) != 0; isAbstract = (aFlags & CR_METHOD_ABSTRACT) != 0; return ret; } #if DEBUG_LAURENT static inline JavaType *newJavaType(Pool& p, uint32 size) {return new(p) JavaType[size];} #endif bool MethodInfo::parseMethodDescriptor(const char *s) { char *paramstr; const char *t; numParams = 0; if (!(getAccessFlags() & CR_METHOD_STATIC)) { /* We need a copy since ~JavaType() deletes the string * passed to it */ const char *t = getClassName()->getUtfString(); #ifdef NO_NSPR int len = strlen(t); #else int len = PL_strlen(t); #endif char *s = new (p) char [len+1]; #ifdef NO_NSPR strncpy(s, t, len); #else PL_strncpy(s, t, len); #endif s[len] = 0; params[0].set(s); numParams = 1; } if (*s++ != '(') return false; /* Get everything between this and ')' */ #ifdef NO_NSPR if (!(t = strchr(s, ')'))) #else if (!(t = PL_strchr(s, ')'))) #endif return false; int len = t-s+1; if (len != 1) { /* This is a very temporary allocation, so we don't use the pool * to allocate this. Also see the delete paramstr, below */ if (!(paramstr = new char[len])) return false; #ifdef NO_NSPR strncpy((char *) paramstr, s, len-1); #else PL_strncpy((char *) paramstr, s, len-1); #endif paramstr[len-1] = 0; const char *next = paramstr; while (*next) { if (numParams+1 > paramSize) { JavaType *oldParams = params; #if DEBUG_LAURENT // This will avoid an internal compile error (gcc) params = newJavaType(p, paramSize); #else params = new (p) JavaType[paramSize]; #endif for (int i = 0; i < numParams; i++) params[i].move(oldParams[i]); /* We don't do this since we're using a pool to allocate, but * this is a potential source of runaway memory usage */ /* delete [] oldParams;*/ } if (!parseFieldDescriptor(p, next, params[numParams], &next)) return false; numParams++; } delete [] paramstr; } s += len; /* Parse the return descriptor */ if (*s == 'V') { ret.set(tkVoid); return true; } else { const char *next; return parseFieldDescriptor(p, s, ret, &next) && !*next; } } /* Implementation of ClassFileReader */ bool ClassFileReader::lookupConstant(uint16 index, ValueKind &vk, Value &value) const { if (index < 1 || index >= constantPoolCount) return false; /* Are we dealing with a constant that returns a value? */ int type = constantPool[index]->getType(); /* index must point to a long, float, double, or integer */ if (!((type > 2 && type < 7))) return false; ConstantVal *val = (ConstantVal *) constantPool[index]; vk = val->getValueKind(); value = val->getValue(); return true; } /* Index is an index into the field array */ bool ClassFileReader::lookupStaticField(uint16 index, JavaType *&type, addr &a, bool &isVolatile, bool &isConstant) { FieldInfo *fInfo; if (index >= fieldCount) return false; isConstant = false; fInfo = fieldInfo[index]; uint16 aFlags = fInfo->getAccessFlags(); if (!(aFlags & CR_FIELD_STATIC)) return false; isVolatile = (aFlags & CR_FIELD_VOLATILE) != 0; fInfo->getType(type); a = fInfo->pos.a; return true; } /* Index is an index into the field array */ bool ClassFileReader::lookupInstanceField(uint16 index, JavaType *&type, uint32 &offset, bool &isVolatile, bool &isConstant) { FieldInfo *fInfo; if (index >= fieldCount) return false; isConstant = false; fInfo = fieldInfo[index]; uint16 aFlags = fInfo->getAccessFlags(); if (aFlags & CR_FIELD_STATIC) return false; isVolatile = (aFlags & CR_FIELD_VOLATILE) != 0; fInfo->getType(type); offset = fInfo->pos.offset; return true; } /* Index is an index into the method array */ bool ClassFileReader::lookupMethod(uint16 index, const JavaType *&ret, int &nParams, const JavaType *¶mTypes, bool &isStatic, bool &isNative, bool &isAbstract) { if (index >= methodCount) return false; ret = &methodInfo[index]->getSignature(nParams, paramTypes, isStatic, isNative, isAbstract); return true; } #ifdef DEBUG void ClassFileReader::dump() { int i; print(0, "AccessFlags %x", accessFlags); print(0, "Major Version %d, Minor Version %d", majorVersion, minorVersion); print(0, "\nThis Class:"); constantPool[thisClassIndex]->dump(0); if (superClassIndex > 0) { print(0, "\nSuper Class:"); constantPool[superClassIndex]->dump(0); } print(0, "\nConstant Pool Count: %d", constantPoolCount); for (i = 1; i < constantPoolCount; i++) { print(0, "%d.", i); if (constantPool[i]) constantPool[i]->dump(0); else print(0, "NULL Constant-pool entry, probably result of a previous\n" "DOUBLE or LONG"); } print(0, "\nField Count: %d", fieldCount); for (i = 0; i < fieldCount; i++) { print(0, "%d.", i+1); fieldInfo[i]->dump(0); } print(0, "\nInterface Count: %d", interfaceCount); for (i = 0; i < interfaceCount; i++) { print(0, "%d.", i+1); interfaceInfo[i].item->dump(0); } print(0, "\nMethod Count: %d", methodCount); for (i = 0; i < methodCount; i++) { print(0, "%d.", i+1); methodInfo[i]->dump(0); } print(0, "\nAttribute Count: %d", attributeCount); for (i = 0; i < attributeCount; i++) { print(0, "%d.", i+1); attributeInfo[i]->dump(0); } } void ClassFileReader::dumpClass(char *dumpfile) { /* Create file. */ FILE *fp; fp = fopen(dumpfile,"w"); /* Begin file */ fprintf(fp,"#begin_class_file\n"); fprintf(fp,"\n"); /* Magic */ uint32 magic = 0xCAFEBABE; fprintf(fp,"#magic\n"); fprintf(fp,"0x%x\n",magic); fprintf(fp,"\n"); /* Minor version */ fprintf(fp,"#minor_version\n"); fprintf(fp,"%i\n",minorVersion); fprintf(fp,"\n"); /* Major version */ fprintf(fp,"#major_version\n"); fprintf(fp,"%i\n",majorVersion); fprintf(fp,"\n"); /* Output to stdout. */ if (true) { /* Magic */ printf("#magic\n"); printf("0x%x\n",magic); printf("\n"); /* Minor version */ printf("#minor_version\n"); printf("%i\n",minorVersion); printf("\n"); /* Major version */ printf("#major_version\n"); printf("%i\n",majorVersion); printf("\n"); } /* Constant Pool */ dumpConstantPool(fp); fprintf(fp,"\n"); /* Access flags */ fprintf(fp,"#access_flags\n"); fprintf(fp,"0x%x\n",accessFlags); fprintf(fp,"\n"); /* This class */ fprintf(fp,"#this_class\n"); fprintf(fp,"%i\n",thisClassIndex); fprintf(fp,"\n"); /* Super class */ fprintf(fp,"#super_class\n"); fprintf(fp,"%i\n",superClassIndex); fprintf(fp,"\n"); /* Output to stdout. */ if (true) { printf("\n"); /* Access flags */ printf("#access_flags\n"); printf("0x%x\n",(char)accessFlags); printf("\n"); /* This class */ printf("#this_class\n"); printf("%i\n",thisClassIndex); printf("\n"); /* Super class */ printf("#super_class\n"); printf("%i\n",superClassIndex); printf("\n"); } /* Interfaces */ dumpInterfaces(fp); fprintf(fp,"\n"); /* Output to stdout. */ if (true) printf("\n"); /* Fields */ dumpFields(fp); fprintf(fp,"\n"); /* Output to stdout. */ if (true) printf("\n"); /* Methods */ dumpMethods(fp); fprintf(fp,"\n"); /* Output to stdout. */ if (true) printf("\n"); /* Attributes */ dumpAttributes(fp); /* End class file */ fprintf(fp,"\n"); fprintf(fp,"#end_class_file"); fclose(fp); } void ClassFileReader::dumpConstantPool(FILE *fp) { fprintf(fp,"#constant_pool_count\n"); fprintf(fp,"%i\n",constantPoolCount); fprintf(fp,"#begin_constant_pool\n"); /* Entry 0 is reserved. */ fprintf(fp,"\t#0 Reserved\n"); /* Output to stdout. */ if (true) { printf("#constant_pool_count\n"); printf("%i\n",constantPoolCount); printf("#begin_constant_pool\n"); /* Entry 0 is reserved. */ printf("\t#0 Reserved\n"); } for (int i = 1; i < constantPoolCount; i++) { if (constantPool[i]) { switch(constantPool[i]->getType()) { case CR_CONSTANT_UTF8: { ConstantUtf8 *tempUtf8 = (ConstantUtf8 *)constantPool[i]; fprintf(fp, "\t#%i Utf8\n",i); fprintf(fp, "\t%s\n",tempUtf8->data); /* Output to stdout. */ if (true) { printf("\t#%i Utf8\n",i); printf("\t%s\n",tempUtf8->data); } break; } case CR_CONSTANT_INTEGER: { ConstantInt *tempInt = (ConstantInt *)constantPool[i]; fprintf(fp, "\t#%i Integer\n", i); fprintf(fp, "\tvalue %i\n",tempInt->getValue()); /* Output to stdout. */ if (true) { printf("\t#%i Integer\n",i); printf("\t#value %i\n",tempInt->getValue()); } break; } case CR_CONSTANT_FLOAT: { int s,e,m; uint32 raw; ConstantFloat *tempFloat = (ConstantFloat *)constantPool[i]; raw = (uint32)tempFloat->getRaw(); /*Use raw to compute for s, e, and m.*/ /*This doesn't check for +/- Infinity and Nan yet.*/ s = ((raw >> 31) == 0) ? 1 : -1; e = ((raw >> 23) &0xff); m = (e == 0) ? (raw & 0x7fffff) << 1 : (raw & 0x7fffff) | 0x800000; fprintf(fp, "\t#%i Float\n",i); fprintf(fp, "\tvalue sign %i exponent %i mantissa %i\n",s,e,m); /* Output to stdout. */ if (true) { printf("\t#%i Float\n",i); printf("\tvalue sign %i exponent %i mantissa %i\n",s,e,m); } break; } case CR_CONSTANT_LONG: { uint32 hi,lo; ConstantLong *tempLong = (ConstantLong *)constantPool[i]; tempLong->getBits(lo,hi); fprintf(fp, "\t#%i Long\n",i); fprintf(fp, "\tvalue hi %i lo %i\n",hi,lo); /* Output to stdout. */ if (true) { printf("\t#%i Long\n",i); printf("\tvalue hi %i lo %i\n",hi,lo); } //Increase count. This is specified in the spec. i++; break; } case CR_CONSTANT_DOUBLE: { char* data; ConstantDouble *tempDouble = (ConstantDouble *)constantPool[i]; data = tempDouble->getData(); fprintf(fp, "\t#%i Double\n",i); fprintf(fp, "\tvalue "); /* The following will need to be fixed once we know how to handle Doubles. */ int j; for (j = 0; j < 8; j++) { fprintf(fp,"%x ",data[j]); } fprintf(fp, "\n"); /* Output to stdout. */ if (true) { printf("\t#%i Double\n",i); printf("\tvalue "); for(j = 0; j < 8 ; j++) printf("%x ",data[j]); printf("\n"); } //Increase count. This is specified in the spec. i++; break; } case CR_CONSTANT_CLASS: { ConstantClass *tempClass = (ConstantClass *)constantPool[i]; fprintf(fp, "\t#%i Class\n",i); fprintf(fp, "\tindex %i\n",tempClass->index); /* Output to stdout. */ if (true) { printf("\t#%i Class\n",i); printf("\tindex %i\n",tempClass->index); } break; } case CR_CONSTANT_STRING: { ConstantString *tempString = (ConstantString *)constantPool[i]; fprintf(fp, "\t#%i String\n",i); fprintf(fp, "\tindex %i\n",tempString->index); /* Output to stdout. */ if (true) { printf("\t#%i String\n",i); printf("\tindex %i\n",tempString->index); } break; } case CR_CONSTANT_FIELDREF: { ConstantFieldRef *tempFieldRef = (ConstantFieldRef *)constantPool[i]; ConstantRef *tempRef = (ConstantRef *)tempFieldRef; fprintf(fp, "\t#%i FieldRef\n",i); fprintf(fp, "\tclassIndex %i typeIndex %i\n",tempRef->classIndex,tempRef->typeIndex); /* Output to stdout. */ if (true) { printf("\t#%i FieldRef\n",i); printf("\tclassIndex %i typeIndex %i\n",tempRef->classIndex,tempRef->typeIndex); } break; } case CR_CONSTANT_METHODREF: { ConstantMethodRef *tempMethodRef = (ConstantMethodRef *)constantPool[i]; ConstantRef *tempRef = (ConstantRef *)tempMethodRef; fprintf(fp, "\t#%i MethodRef\n",i); fprintf(fp, "\tclassIndex %i typeIndex %i\n",tempRef->classIndex,tempRef->typeIndex); /* Output to stdout. */ if (true) { printf("\t#%i MethodRef\n",i); printf("\tclassIndex %i typeIndex %i\n",tempRef->classIndex,tempRef->typeIndex); } break; } case CR_CONSTANT_INTERFACEMETHODREF: { ConstantInterfaceMethodRef *tempInterfaceMethodRef = (ConstantInterfaceMethodRef *)constantPool[i]; ConstantRef *tempRef = (ConstantRef *)tempInterfaceMethodRef; fprintf(fp, "\t#%i InterfaceMethodRef\n",i); fprintf(fp, "\tclassIndex %i typeIndex %i\n",tempRef->classIndex,tempRef->typeIndex); /* Output to stdout. */ if (true) { printf("\t#%i InterfaceMethodRef\n",i); printf("\tclassIndex %i typeIndex %i\n",tempRef->classIndex,tempRef->typeIndex); } break; } case CR_CONSTANT_NAMEANDTYPE: { ConstantNameAndType *tempNameAndType = (ConstantNameAndType *)constantPool[i]; fprintf(fp, "\t#%i NameAndType\n",i); fprintf(fp, "\tnameIndex %i descIndex %i\n",tempNameAndType->nameIndex,tempNameAndType->descIndex); /* Output to stdout. */ if (true) { printf("\t#%i NameAndType\n",i); printf("\tnameIndex %i descIndex %i\n",tempNameAndType->nameIndex,tempNameAndType->descIndex); } break; } default: { printf("Error in constant pool\n"); return; } } } else print(0, "NULL Constant-pool entry, probably result of a previous\n" "DOUBLE or LONG\n"); } fprintf(fp,"#end_constant_pool\n"); /* Output to stdout. */ if (true) { printf("#end_constant_pool\n"); } } void ClassFileReader::dumpInterfaces(FILE *fp) { fprintf(fp,"#interfaces_count\n"); fprintf(fp,"%i\n",interfaceCount); /* Output to stdout. */ if (true) { printf("#interfaces_count\n"); printf("%i\n",interfaceCount); } if (interfaceCount > 0) { fprintf(fp,"#begin_interfaces\n"); /* Output to stdout. */ if (true) printf("#begin_interfaces\n"); for (uint16 i = 0; i < interfaceCount; i++ ) { fprintf(fp,"\t#%i\n",i); fprintf(fp,"\tindex %i\n",interfaceInfo[i].index); /* Output to stdout. */ if (true) { printf("\t#%i\n",i); printf("\tindex %i\n",interfaceInfo[i].index); } } fprintf(fp,"#end_interfaces\n"); /* Output to stdout. */ if (true) printf("#end_interfaces\n"); } } void ClassFileReader::dumpFields(FILE *fp) { fprintf(fp,"#fields_count\n"); fprintf(fp,"%i\n",fieldCount); /* Output to stdout. */ if (true) { printf("#fields_count\n"); printf("%i\n",fieldCount); } if (fieldCount > 0) { fprintf(fp,"#begin_fields\n"); /* Output to stdout. */ if (true) printf("#begin_fields\n"); for (uint16 i = 0; i < fieldCount; i++ ) { fprintf(fp,"\t#%i\n",i); /* Access flags */ fprintf(fp,"\taccess_flags 0x%x\n",fieldInfo[i]->getAccessFlags()); /* Name index */ fprintf(fp,"\tnameIndex %i descIndex %i\n",fieldInfo[i]->getNameIndex(),fieldInfo[i]->getDescIndex()); /* Attributes count */ fprintf(fp,"\tattributes_count %i\n",fieldInfo[i]->getAttributeCount()); /* Output to stdout. */ if (true) { printf("\t#%i\n",i); /* Access flags */ printf("\taccess_flags 0x%x\n",fieldInfo[i]->getAccessFlags()); /* Name index */ printf("\tnameIndex %i descIndex %i\n",fieldInfo[i]->getNameIndex(),fieldInfo[i]->getDescIndex()); /* Attributes count */ printf("\tattributes_count %i\n",fieldInfo[i]->getAttributeCount()); } /* * The following attribute_info loop needs to be tested. */ if (fieldInfo[i]->getAttributeCount() > 0) { fprintf(fp,"\t#begin_attributes\n"); /* Output to stdout. */ if (true) printf("\t#being_attributes\n"); int currentCount = 0; const DoublyLinkedList &list = fieldInfo[i]->getAttributes(); for (DoublyLinkedList::iterator j = list.begin(); !list.done(j); j = list.advance(j)) { AttributeInfoItem &item = list.get(j); fprintf(fp,"\t\t#%i %s\n",currentCount,item.getName()); /* Attribute name index */ fprintf(fp,"\t\tnameIndex %i\n",item.getNameIndex()); /* Attribute length */ fprintf(fp,"\t\tlength %i\n",item.getLength()); /* Output to stdout. */ if (true) { printf("\t\t#%i %s\n",currentCount,item.getName()); /* Attribute name index */ printf("\t\tnameIndex %i\n",item.getNameIndex()); /* Attribute length */ printf("\t\tlength %i\n",item.getLength()); } /* Find the correct attribute and generate the corresponding info. */ switch (item.getCode()) { case CR_ATTRIBUTE_CONSTANTVALUE: { /* ConstantValue Attribute */ AttributeConstantValue *constVal = static_cast(&item); fprintf(fp,"\t\tindex: %i\n",constVal->getIndex()); /* Output to stdout. */ if (true) printf("\t\tindex: %i\n",constVal->getIndex()); break; } default: { /* Ignore everything else. */ break; } } currentCount++; } fprintf(fp,"\t#end_attribute_info\n"); /* Output to stdout. */ if (true) printf("\t#end_attribute_info\n"); } } fprintf(fp,"#end_fields\n"); /* Output to stdout. */ if (true) printf("#end_fields\n"); } } void ClassFileReader::dumpMethods(FILE *fp) { /* Total number of bytecodes. */ int totalBytecodes = 0; fprintf(fp,"#methods_count\n"); fprintf(fp,"%i\n",methodCount); /* Output to stdout. */ if (true) { printf("#methods_count\n"); printf("%i\n",methodCount); } if (methodCount > 0) { fprintf(fp,"#begin_methods\n"); /* Output to stdout. */ if (true) printf("#begin_methods\n"); for (uint i = 0; i < methodCount; i++) { ConstantUtf8 *method = methodInfo[i]->getName(); fprintf(fp,"\t#%i %s\n",i,method->getUtfString()); fprintf(fp,"\taccess_flags %i\n",methodInfo[i]->getAccessFlags()); fprintf(fp,"\tnameIndex %i descIndex %i\n",methodInfo[i]->getNameIndex(),methodInfo[i]->getDescIndex()); fprintf(fp,"\tattributes_count %i\n",methodInfo[i]->getAttributeCount()); /* Output to stdout. */ if (true) { printf("\t#%i %s\n",i,method->getUtfString()); printf("\taccess_flags %i\n",methodInfo[i]->getAccessFlags()); printf("\tnameIndex %i descIndex %i\n",methodInfo[i]->getNameIndex(),methodInfo[i]->getDescIndex()); printf("\tattributes_count %i\n",methodInfo[i]->getAttributeCount()); } if (methodInfo[i]->getAttributeCount() > 0) { fprintf(fp,"\t#begin_attributes\n"); /* Output to stdout. */ printf("\t#begin_attributes\n"); const DoublyLinkedList &list = methodInfo[i]->getAttributes(); int currentCount = 0; for (DoublyLinkedList::iterator j = list.begin(); !list.done(j); j = list.advance(j)) { AttributeInfoItem &item = list.get(j); fprintf(fp,"\t\t#%i %s\n",currentCount,item.getName()); /* Attribute name index */ fprintf(fp,"\t\tnameIndex %i\n",item.getNameIndex()); /* Attribute length */ fprintf(fp,"\t\tlength %i\n",item.getLength()); /* Output to stdout. */ if (true) { printf("\t\t#%i %s\n",currentCount,item.getName()); /* Attribute name index */ printf("\t\tnameIndex %i\n",item.getNameIndex()); /* Attribute length */ printf("\t\tlength %i\n",item.getLength()); } /* Get the correct code and generate the corresponding info. */ switch(item.getCode()) { case CR_ATTRIBUTE_CODE: { /* Code Attribute */ AttributeCode *code = static_cast(&item); /* Max stacks */ fprintf(fp,"\t\tmax_stack %i\n",code->getMaxStack()); /* Max locals */ fprintf(fp,"\t\tmax_locals %i\n",code->getMaxLocals()); /* Code length */ fprintf(fp,"\t\tcode_length %i\n",code->getCodeLength()); /* Add to total number of bytecodes. */ totalBytecodes = totalBytecodes + code->getCodeLength(); /* Bytecode */ const unsigned char *bytecode = (const unsigned char *)code->getCode(); /* Temp way for handling bytecodes. */ int k; uint32 codeLength = code->getCodeLength(); fprintf(fp,"\t\t#bytecodes "); for ( k = 0; k < (int)codeLength; k++) { fprintf(fp,"%x ",bytecode[k]); } fprintf(fp,"\n"); fprintf(fp,"\t\t#begin_bytecodes\n"); disassembleBytecodes(fp,bytecode,bytecode+code->getCodeLength(),bytecode,24); fprintf(fp,"\t\t#end_bytecodes\n"); /* Exception table length */ fprintf(fp,"\t\texception_table_length %i\n",code->getNumExceptions()); /* Output to stdout. */ if (true) { /* Max stacks */ printf("\t\tmax_stack %i\n",code->getMaxStack()); /* Max locals */ printf("\t\tmax_locals %i\n",code->getMaxLocals()); /* Code length */ printf("\t\tcode_length %i\n",code->getCodeLength()); /* Temp way for handling bytecodes. */ printf("\t\t#bytecodes "); for ( k = 0; k < (int)codeLength; k++) { printf("%x ",bytecode[k]); } printf("\n"); /* Bytecode */ printf("\t\t#begin_bytecodes\n"); disassembleBytecodes(stdout,bytecode,bytecode+code->getCodeLength(),bytecode,24); printf("\t\t#end_bytecodes\n"); /* Exception table length */ printf("\t\texception_table_length %i\n",code->getNumExceptions()); } /* * The following Exception_Table loop needs to be tested. */ if (code->getNumExceptions() > 0) { ExceptionItem **exceptionItem = code->getExceptions(); fprintf(fp,"\t\t#begin_exception_table\n"); /* Output to stdout. */ if (true) printf("\t\t#begin_exception_table\n"); for ( k = 0; k < (int)code->getNumExceptions(); k++) { fprintf(fp,"\t\t\t#%i\n", k); /* Start/End pc */ fprintf(fp,"\t\t\tstart_pc %i end_pc %i\n",exceptionItem[k]->getStartPc(),exceptionItem[k]->getEndPc); /* Handler pc */ fprintf(fp,"\t\t\thandler_pc %i\n",exceptionItem[k]->getHandlerPc()); /* Catcher type */ fprintf(fp,"\t\t\tcatch_type %i\n",exceptionItem[k]->getCatcherIndex()); /* Output to stdout. */ if (true) { printf("\t\t\t#%i\n",k); /* Start/End pc */ printf("\t\t\tstart_pc %i end_pc %i\n",exceptionItem[k]->getStartPc(),exceptionItem[k]->getEndPc); /* Handler pc */ printf("\t\t\thandler_pc %i\n",exceptionItem[k]->getHandlerPc()); /* Catcher type */ printf("\t\t\tcatch_type %i\n",exceptionItem[k]->getCatcherIndex()); } } fprintf(fp,"\t\t#end_excpetion_table\n"); /* Output to stdout. */ if (true) printf("\t\t#end_exception_table\n"); } /* Attributes count */ fprintf(fp,"\t\tattributes_count %i\n",code->getNumAttributes()); /* Output to stdout. */ if (true) printf("\t\tattributes_count %i\n",code->getNumAttributes()); if (code->getNumAttributes() > 0) { fprintf(fp,"\t\t#begin_attributes\n"); /* Output to stdout. */ if (true) printf("\t\t#begin_attributes\n"); AttributeInfoItem **attributes = code->getAttributes(); for (uint16 l = 0; l < code->getNumAttributes(); l++) { fprintf(fp,"\t\t\t#%i %s\n",l,attributes[l]->getName()); /* Attribute name index */ fprintf(fp,"\t\t\tnameIndex %i\n",attributes[l]->getNameIndex()); /* Attribute length */ fprintf(fp,"\t\t\tlength %i\n",attributes[l]->getLength()); /* Output to stdout. */ if (true) { printf("\t\t\t#%i %s\n",l,attributes[l]->getName()); /* Attribute name index */ printf("\t\t\tnameIndex %i\n",attributes[l]->getNameIndex()); /* Attribute length */ printf("\t\t\tlength %i\n",attributes[l]->getLength()); } /* Get the correct code and generate the corresponding attribute. */ switch(attributes[l]->getCode()) { case CR_ATTRIBUTE_LINENUMBERTABLE: { /* LineNumberTable Attribute */ AttributeLineNumberTable *lineNoTable = (AttributeLineNumberTable*)attributes[l]; /* Line number table length */ fprintf(fp,"\t\t\ttable_length %i\n",lineNoTable->getNumEntries()); /* Output to stdout. */ if (true) { /* Line number table length */ printf("\t\t\ttable_length %i\n",lineNoTable->getNumEntries()); } if (lineNoTable->getNumEntries() > 0) { LineNumberEntry *lineNoEntry = lineNoTable->getEntries(); fprintf(fp,"\t\t\t#begin_line_number_table\n"); /* Output to stdout. */ if (true) printf("\t\t\t#begin_line_number_table\n"); for(uint16 m = 0; m < lineNoTable->getNumEntries(); m++) { fprintf(fp,"\t\t\t\t#%i\n",m); /* Start pc */ fprintf(fp,"\t\t\t\tstart_pc %i\n",lineNoEntry[m].startPc); /* Line number */ fprintf(fp,"\t\t\t\tline_number %i\n",lineNoEntry[m].lineNumber); /* Output to stdout. */ if (true) { printf("\t\t\t\t#%i\n",m); /* Start pc */ printf("\t\t\t\tstart_pc %i\n",lineNoEntry[m].startPc); /* Line number */ printf("\t\t\t\tline_number %i\n",lineNoEntry[m].lineNumber); } } fprintf(fp,"\t\t\t#end_line_number_table\n"); /* Output to stdout. */ if (true) printf("\t\t\t#end_line_number_table\n"); } break; } /* * The LocalVariableTable case needs to be tested. */ case CR_ATTRIBUTE_LOCALVARIABLETABLE: { /* LocalVariableTable */ AttributeLocalVariableTable *localVariableTable = (AttributeLocalVariableTable*)attributes[l]; /* Local variable table length */ fprintf(fp,"\t\t\ttable_length %i\n",localVariableTable->getNumEntries()); /* Output to stdout. */ if (true) { /* Local variable table length */ printf("\t\t\ttable_length %i\n",localVariableTable->getNumEntries()); } if(localVariableTable->getNumEntries() > 0) { fprintf(fp,"\t\t\t#begin_local_variable_table\n"); /* Output to stdout. */ if (true) printf("\t\t\t#begin_local_variable_table\n"); LocalVariableEntry *localVarEntry = localVariableTable->getEntries(); for (uint16 m = 0; m < localVariableTable->getNumEntries(); m++) { fprintf(fp,"\t\t\t\t#%i\n",m); /* Start pc */ fprintf(fp,"\t\t\t\tstart_pc %i\n",localVarEntry[m].startPc); /* Length */ fprintf(fp,"\t\t\t\tlength %i\n",localVarEntry[m].length); /* Name index */ fprintf(fp,"\t\t\t\tnameIndex %i\n",localVarEntry[m].nameIndex); /* Description index */ fprintf(fp,"\t\t\t\tdescIndex %i\n",localVarEntry[m].descIndex); /* Index */ fprintf(fp,"\t\t\t\tindex %i\n",localVarEntry[m].index); /* Output to stdout. */ if (true) { printf("\t\t\t\t#%i\n",m); /* Start pc */ printf("\t\t\t\tstartPc %i\n",localVarEntry[m].startPc); /* Length */ printf("\t\t\t\tlength %i\n",localVarEntry[m].length); /* Name index */ printf("\t\t\t\tnameIndex %i\n",localVarEntry[m].nameIndex); /* Description index */ printf("\t\t\t\tdescIndex %i\n",localVarEntry[m].descIndex); /* Index */ printf("\t\t\t\tindex %i\n",localVarEntry[m].index); } } fprintf(fp,"\t\t\t#end_local_variable_table\n"); /* Output to stdout. */ if (true) printf("\t\t\t#end_local_variable_table\n"); } } default: { /* Ignore everything else. */ break; } } } fprintf(fp,"\t\t#end_attributes\n"); /* Output to stdout. */ if (true) printf("\t\t#end_attributes\n"); } break; } /* * The following Exceptions case needs to be tested. */ case CR_ATTRIBUTE_EXCEPTIONS: { /* Exceptions Attribute */ AttributeExceptions *exceptions = static_cast(&item); /* Number of exceptions */ fprintf(fp,"\t\texceptions_count %i\n",exceptions->getNumExceptions()); /* Output to stdout. */ if (true) { /* Number of exceptions */ fprintf(fp,"\t\texceptions_count %i\n",exceptions->getNumExceptions()); } if (exceptions->getNumExceptions() > 0) { fprintf(fp,"\t\t#begin_exception_index_table\n"); /* Output to stdout. */ if (true) printf("\t\t#begin_exception_index_table\n"); uint16 *indices = exceptions->getExcIndices(); for (uint16 k = 0; k < exceptions->getNumExceptions(); k++) { fprintf(fp,"\t\t\t#%i\n",k); /* Index */ fprintf(fp,"\t\t\tindex %i\n",indices[k]); /* Output to stdout. */ if (true) { fprintf(fp,"\t\t\t#%i\n",k); /* Index */ fprintf(fp,"\t\t\tindex %i\n",indices[k]); } } fprintf(fp,"\t\t#end_exception_index_table\n"); /* Output to stdout. */ if (true) printf("\t\t#end_exception_index_table\n"); } break; } default: { /* Ignore everything else. */ break; } } currentCount++; } fprintf(fp,"\t#end_attributes\n"); /* Output to stdout. */ printf("\t#end_attributes\n"); } } fprintf(fp,"#end_methods\n"); /* Output to stdout. */ if (true) printf("#end_methods\n"); } printf("TOTAL NUMBER OF BYTECODES: %i", totalBytecodes); } void ClassFileReader::dumpAttributes(FILE *fp) { fprintf(fp,"#attributes_count\n"); fprintf(fp,"%i\n",attributeCount); /* Output to stdout. */ if (true) { printf("#attributes_count\n"); printf("%i\n",attributeCount); } if (attributeCount > 0) { fprintf(fp,"#begin_attributes\n"); /* Output to stdout. */ if (true) printf("#begin_attributes\n"); for(uint i = 0; i < attributeCount; i++ ) { fprintf(fp,"\t#%i %s\n",i,attributeInfo[i]->getName()); /* Attribute name index */ fprintf(fp,"\tnameIndex %i\n",attributeInfo[i]->getNameIndex()); /* Attribute length */ fprintf(fp,"\tlength %i\n",attributeInfo[i]->getLength()); /* Output to stdout. */ if (true) { printf("\t#%i %s\n",i,attributeInfo[i]->getName()); /* Attribute name index */ printf("\tnameIndex %i\n",attributeInfo[i]->getNameIndex()); /* Attribute length */ printf("\tlength %i\n",attributeInfo[i]->getLength()); } /* Get the correct code and generate the corresponding attribute. */ switch(attributeInfo[i]->getCode()) { case CR_ATTRIBUTE_SOURCEFILE: { /* SourceFile Attribute */ AttributeSourceFile *srcFile = (AttributeSourceFile*)attributeInfo[i]; fprintf(fp,"\tindex %i\n",srcFile->getIndex()); /* Output to stdout. */ printf("\tindex %i\n",srcFile->getIndex()); break; } default: { /* Ignore everything else. */ break; } } } fprintf(fp,"#end_attributes\n"); /* Output to stdout. */ if (true) printf("#end_attributes\n"); } } #endif #define CR_BUFFER_SIZE 16184 #define JAVA_MAGIC 0xCAFEBABE CrError ClassFileReader::readConstantPool() { uint16 cIndex, tIndex; uint16 index; uint32 low, high; int i; constantPool[0] = 0; for (i = 1; i < constantPoolCount; i++) { char tag; if (!fr->readU1(&tag, 1)) { return crErrorIO; } switch (tag) { case CR_CONSTANT_UTF8: { uint16 len; if (!fr->readU2(&len, 1)) { return crErrorIO; } ConstantUtf8 *utf = new (p) ConstantUtf8(p, len); char *buf = new char[len+1]; fr->readU1(buf, len); buf[len] = 0; /* Do we intern all strings that we get, or just class names? */ utf->data = sp.intern(buf); delete buf; constantPool[i] = utf; break; } case CR_CONSTANT_INTEGER: { int32 val; if (!fr->readU4((uint32 *) &val, 1)) { return crErrorIO; } constantPool[i] = new (p) ConstantInt(p, val); break; } case CR_CONSTANT_FLOAT: { uint32 raw; if (!fr->readU4(&raw, 1)) { return crErrorIO; } constantPool[i] = new (p) ConstantFloat(p, raw); break; } case CR_CONSTANT_LONG: if (!fr->readU4(&high, 1)) { return crErrorIO; } if (!fr->readU4(&low, 1)) { return crErrorIO; } constantPool[i] = new (p) ConstantLong(p, low, high); constantPool[i+1] = 0; /* Longs and doubles take up two constant-pool entries */ i++; break; case CR_CONSTANT_DOUBLE: { char buf[8]; if (!fr->readU1(buf, 8)) { return crErrorIO; } constantPool[i] = new (p) ConstantDouble(p, buf); constantPool[i+1] = 0; /* Longs and doubles take up two constant-pool entries */ i++; break; } case CR_CONSTANT_CLASS: if (!fr->readU2(&index, 1)) { #ifdef DEBUG print(0, "CR_CONSTANT_CLASS: Cannot read index\n"); #endif return crErrorIO; } if (invalidIndex(index)) { #ifdef DEBUG print(0, "CR_CONSTANT_CLASS: Invalid index %d\n", index); #endif return crErrorInvalidConstant; } constantPool[i] = new (p) ConstantClass(p, constantPool, index); break; case CR_CONSTANT_STRING: if (!fr->readU2(&index, 1)) { return crErrorIO; } if (invalidIndex(index)) { #ifdef DEBUG print(0, "CR_CONSTANT_STRING: Invalid index %d\n", index); #endif return crErrorInvalidConstant; } constantPool[i] = new (p) ConstantString(p, constantPool, index); break; case CR_CONSTANT_FIELDREF: if (!fr->readU2(&cIndex, 1)) { return crErrorIO; } if (!fr->readU2(&tIndex, 1)) { return crErrorIO; } if (invalidIndex(cIndex) || invalidIndex(tIndex)) { #ifdef DEBUG print(0, "CR_CONSTANT_FIELDREF: Invalid indices %d %d\n", cIndex, tIndex); #endif return crErrorInvalidConstant; } constantPool[i] = new (p) ConstantFieldRef(p, constantPool, cIndex, tIndex); break; case CR_CONSTANT_METHODREF: if (!fr->readU2(&cIndex, 1)) { return crErrorIO; } if (!fr->readU2(&tIndex, 1)) { return crErrorIO; } if (invalidIndex(cIndex) || invalidIndex(tIndex)) { #ifdef DEBUG print(0, "CR_CONSTANT_METHODREF: Invalid indices %d %d\n", cIndex, tIndex); #endif return crErrorInvalidConstant; } constantPool[i] = new (p) ConstantMethodRef(p, constantPool, cIndex, tIndex); break; case CR_CONSTANT_INTERFACEMETHODREF: if (!fr->readU2(&cIndex, 1)) { return crErrorIO; } if (!fr->readU2(&tIndex, 1)) { return crErrorIO; } if (invalidIndex(cIndex) || invalidIndex(tIndex)) { #ifdef DEBUG print(0, "CR_CONSTANT_INTERFACEMETHODREF: Invalid indices %d %d\n", cIndex, tIndex); #endif return crErrorInvalidConstant; } constantPool[i] = new (p) ConstantInterfaceMethodRef(p, constantPool, cIndex, tIndex); break; case CR_CONSTANT_NAMEANDTYPE: { uint16 nIndex, dIndex; if (!fr->readU2(&nIndex, 1)) { return crErrorIO; } if (!fr->readU2(&dIndex, 1)) { return crErrorIO; } if (invalidIndex(nIndex) || invalidIndex(dIndex)) { #ifdef DEBUG print(0, "CR_CONSTANT_NAMEANDTYPE: Invalid indices %d %d\n", nIndex, dIndex); #endif return crErrorInvalidConstant; } constantPool[i] = new (p) ConstantNameAndType(p, constantPool, nIndex, dIndex); break; } default: #ifdef DEBUG print(0, "UNKNOWN constant type %d\n", tag); #endif return crErrorUnknownConstantType; } } for (i = 1; i < constantPoolCount; i++) if (constantPool[i] && !constantPool[i]->resolveAndValidate()) { #ifdef DEBUG print(0, "Cannot resolveAndValidate entry #%d\n", i); #endif return crErrorInvalidConstant; } return crErrorNone; } CrError ClassFileReader::readInterfaces() { for (int i = 0; i < interfaceCount; i++) { uint16 index; if (!fr->readU2(&index, 1)) return crErrorIO; if (invalidIndex(index)) return crErrorInvalidInterface; interfaceInfo[i].item = constantPool[index]; interfaceInfo[i].index = index; } return crErrorNone; } AttributeInfoItem *ClassFileReader::readAttribute(CrError *status) { uint16 nameIndex; AttributeInfoItem *item; ConstantUtf8 *utf8; *status = crErrorNone; if (!fr->readU2(&nameIndex, 1)) { *status = crErrorIO; return 0; } /* Do we want to read the rest here to recover? */ if (invalidIndex(nameIndex)) { #ifdef DEBUG print(0, "ClassFileReader::readAttribute(): Invalid Name Index (%d)\n", nameIndex); #endif *status = crErrorInvalidConstant; return 0; } if (constantPool[nameIndex]->getType() != CR_CONSTANT_UTF8) { #ifdef DEBUG print(0, "ClassFileReader::readAttribute(): Invalid Type(%d, %d)\n", nameIndex, constantPool[nameIndex]->getType()); #endif *status = crErrorInvalidConstant; return 0; } utf8 = (ConstantUtf8 *) constantPool[nameIndex]; for (int i = 0; i < numAttrHandlers; i++) if ((item = attrHandlers[i]->handle(utf8->getUtfString(), nameIndex, status)) != 0 && *status == crErrorNone) return item; else if (*status != crErrorNone) { #ifdef DEBUG print(0, "Error trying to read attribute (%s); Current handler (%s)\n", utf8->getUtfString(), attrHandlers[i]->getName()); #endif return 0; } #ifdef DEBUG print(0, "Cannot find a handler for attribute (%s)\n", utf8->getUtfString()); #endif *status = crErrorInvalidAttribute; return 0; } #define ALIGN(size,mod) ((size)+(((size)%(mod)) ? ((mod)-((size)%(mod))) : 0)) CrError ClassFileReader::readInfoItems(int count, InfoItem **info, int field) { uint32 offset = 4; /* Offset of first field is 4 */ CrError def = (field) ? crErrorInvalidField : crErrorInvalidMethod; for (int i = 0; i < count; i++) { uint16 aFlags, nameIndex, descIndex, attrCount; if (!fr->readU2(&aFlags, 1)) return crErrorIO; if (!fr->readU2(&nameIndex, 1)) return crErrorIO; if (invalidIndex(nameIndex)) { #ifdef DEBUG print(0, "(%d): Invalid name index %d\n", i, nameIndex); #endif return def; } if (!fr->readU2(&descIndex, 1)) return crErrorIO; if (invalidIndex(descIndex)) { #ifdef DEBUG print(0, "(%d): Invalid desc index %d\n", i, descIndex); #endif return def; } if (!fr->readU2(&attrCount, 1)) return crErrorIO; if (constantPool[nameIndex]->getType() != CR_CONSTANT_UTF8 || constantPool[descIndex]->getType() != CR_CONSTANT_UTF8) { #ifdef DEBUG print(0, "Invalid type for indices name (%d, %d) or desc (%d, %d)\n", nameIndex, constantPool[nameIndex]->getType(), descIndex, constantPool[descIndex]->getType()); #endif return def; } if (field) { FieldInfo *fInfo; ConstantUtf8 *desc = (ConstantUtf8 *) constantPool[descIndex]; fInfo = new (p) FieldInfo(p, aFlags, (ConstantUtf8 *) constantPool[thisClassIndex], (ConstantUtf8 *) constantPool[nameIndex], desc, nameIndex, descIndex); JavaType *type; fInfo->getType(type); const char *next; if (!parseFieldDescriptor(p, desc->getUtfString(), *type, &next) || *next) { #ifdef DEBUG print(0, "Cannot parse field descriptor for field %s\n", ((ConstantUtf8 *) constantPool[nameIndex])->getUtfString()); #endif return crErrorInvalidField; } if (!(aFlags & CR_FIELD_STATIC)) { fInfo->pos.offset = offset; offset += getJavaSize(type); offset = ALIGN(offset, CR_ALIGNMENT); } else { int size = getJavaSize(type); fInfo->pos.a = objectAddress((obj)(new(p) char[size])); } info[i] = (InfoItem *) fInfo; } else { MethodInfo *mInfo; ConstantUtf8 *desc = (ConstantUtf8 *) constantPool[descIndex]; mInfo = new (p) MethodInfo(p, aFlags, ((ConstantClass *) constantPool[thisClassIndex])->getUtf(), (ConstantUtf8 *) constantPool[nameIndex], (ConstantUtf8 *) constantPool[descIndex], nameIndex, descIndex); #if 0 printf("Method %s\n", ((ConstantUtf8 *) constantPool[nameIndex])->getUtfString()); #endif if (!mInfo->parseMethodDescriptor(desc->getUtfString())) { #ifdef DEBUG print(0, "Cannot parse method descriptor for field %s\n", ((ConstantUtf8 *) constantPool[nameIndex])->getUtfString()); #endif return crErrorInvalidMethod; } info[i] = mInfo; } for (int j = 0; j < attrCount; j++) { CrError status; AttributeInfoItem *attr = readAttribute(&status); if (attr) info[i]->addAttribute(*attr); else { #ifdef DEBUG print(0, "Cannot add attribute to InfoItem (%d)\n", i); #endif info[i] = 0; return crErrorIO; } } } if (field) objSize = offset; return crErrorNone; } CrError ClassFileReader::readMethods() { return readInfoItems(methodCount, (InfoItem **) methodInfo, false); } CrError ClassFileReader::readFields() { return readInfoItems(fieldCount, (InfoItem **) fieldInfo, true); } CrError ClassFileReader::readAttributes(AttributeInfoItem **attrInfo, int attrCount) { CrError status; for (int i = 0; i < attrCount; i++) if (!(attrInfo[i] = readAttribute(&status))) return status; return crErrorNone; } ClassFileReader::ClassFileReader(Pool &pool, StringPool &strPool, const char *fileName, CrError *status) : p(pool), sp(strPool) { if (!fileName) { *status = crErrorNone; return; } int st; fr = new (p) FileReader(p, fileName, &st); if (st != 0) { *status = crErrorFileNotFound; return; } uint32 magic; objSize = 0; methodInfo = 0; methodCount = 0; constantPool = 0, interfaceInfo = 0, fieldInfo = 0, attributeInfo = 0; constantPoolCount = 0, interfaceCount = 0, fieldCount = 0, attributeCount = 0; numAttrHandlers = 0; attrSize = 10; attrHandlers = new (p) AttributeHandler *[attrSize]; if (!fr) { *status = crErrorNoMem; return; } if (!fr->readU4(&magic, 1)) { *status = crErrorIO; return; } if (magic != JAVA_MAGIC) { *status = crErrorInvalidFileType; return; } /* get the version numbers */ if (!fr->readU2(&minorVersion, 1) || !fr->readU2(&majorVersion, 1)) { *status = crErrorIO; return; } /* Constant pool count */ if (!fr->readU2(&constantPoolCount, 1)) { *status = crErrorIO; return; } constantPool = new (p) ConstantPoolItem *[constantPoolCount]; /* Parse the constant pool */ if ((*status = readConstantPool()) != 0) return; /* Register attribute handlers for all attributes that we can * handle */ addAttrHandler(new (p) AttributeHandlerSourceFile(p, fr, this)); addAttrHandler(new (p) AttributeHandlerConstantValue(p, fr, this)); addAttrHandler(new (p) AttributeHandlerCode(p, fr, this)); addAttrHandler(new (p) AttributeHandlerExceptions(p, fr, this)); addAttrHandler(new (p) AttributeHandlerLineNumberTable(p, fr, this)); addAttrHandler(new (p) AttributeHandlerLocalVariableTable(p, fr, this)); /* This must always be added after everything else, since it handles * all attributes that we know nothing about */ addAttrHandler(new (p) AttributeHandlerDummy(p, fr, this)); /* Access Flags */ if (!fr->readU2(&accessFlags, 1)) { *status = crErrorIO; return; } /* This Class, super Class */ if (!fr->readU2(&thisClassIndex, 1)) { *status = crErrorIO; return; } if (!fr->readU2(&superClassIndex, 1)) { *status = crErrorIO; return; } if (invalidIndex(thisClassIndex)) { *status = crErrorNoClass; return; } if (superClassIndex > 0 && invalidIndex(superClassIndex)) { *status = crErrorNoSuperClass; return; } if (constantPool[thisClassIndex]->getType() != CR_CONSTANT_CLASS) { *status = crErrorNoClass; return; } /* If we don't have a super-class, we must be java/lang/Object */ if (superClassIndex < 1) { #ifdef NO_NSPR if (strcmp(((ConstantClass *)constantPool[thisClassIndex])->getUtf()->getUtfString(), "java/lang/Object") != 0) { #else if (PL_strcmp(((ConstantClass *)constantPool[thisClassIndex])->getUtf()->getUtfString(), "java/lang/Object") != 0) { #endif *status = crErrorNoSuperClass; return; } } else { if (constantPool[superClassIndex]->getType() != CR_CONSTANT_CLASS) { *status = crErrorNoClass; return; } } /* Interfaces */ if (!fr->readU2(&interfaceCount, 1)) { *status = crErrorIO; return; } if (interfaceCount > 0) { interfaceInfo = new (p) InterfaceInfo[interfaceCount]; if ((*status = readInterfaces()) != 0) return; } else interfaceInfo = 0; /* Fields */ if (!fr->readU2(&fieldCount, 1)) { *status = crErrorIO; return; } if (fieldCount > 0) { fieldInfo = new (p) FieldInfo *[fieldCount]; if ((*status = readFields()) != 0) return; } else { fieldInfo = 0; objSize = 4; } /* Methods */ if (!fr->readU2(&methodCount, 1)) { *status = crErrorIO; return; } if (methodCount > 0) { methodInfo = new (p) MethodInfo *[methodCount]; memset(methodInfo, 0, sizeof(MethodInfo *)*methodCount); if ((*status = readMethods()) != 0) return; } else methodInfo = 0; /* Attributes */ if (!fr->readU2(&attributeCount, 1)) { attributeCount = 0; *status = crErrorIO; return; } if (attributeCount > 0) { attributeInfo = new (p) AttributeInfoItem *[attributeCount]; if ((*status = readAttributes(attributeInfo, attributeCount)) != 0) return; } else attributeInfo = 0; /* At this point, we must be at the end of the file....*/ #if 1 char dummy; if (fr->readU1(&dummy, 1)) *status = crErrorSpuriousBytes; else { /* Success... */ *status = crErrorNone; } #else *status = crErrorNone; #endif } void ClassFileReader::addAttrHandler(AttributeHandler *handler) { if (numAttrHandlers+1 > attrSize) { AttributeHandler **oldAttrHandlers = attrHandlers; attrSize += 5; attrHandlers = new (p) AttributeHandler *[attrSize]; for (int i = 0; i < numAttrHandlers; i++) attrHandlers[i] = oldAttrHandlers[i]; } attrHandlers[numAttrHandlers++] = handler; } bool ClassFileReader::lookupConstant(const char *name, const char *typeStr, uint8 type, uint16 &index) const { /* Get interned versions of the name and type string */ const char *namei = sp.get(name); const char *typeStri = sp.get(typeStr); for (int i = 1; i < constantPoolCount; i++) { if (constantPool[i] && constantPool[i]->getType() == type) { switch (type) { case CR_CONSTANT_METHODREF: case CR_CONSTANT_INTERFACEMETHODREF: case CR_CONSTANT_FIELDREF: { ConstantNameAndType *ninfo = ((ConstantRef *) constantPool[i])->getTypeInfo(); ConstantUtf8 *nameUtf = ninfo->getName(); ConstantUtf8 *typeUtf = ninfo->getDesc(); if (nameUtf->getUtfString() == namei && typeUtf->getUtfString() == typeStri) { index = i; return true; } break; } default: /* If we're here, we don't yet support "type" */ return false; } } } return false; }