mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-04 13:07:52 +00:00
2822 lines
62 KiB
C++
2822 lines
62 KiB
C++
/* -*- 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 <stdio.h>
|
|
|
|
#ifndef NO_NSPR
|
|
#include "plstr.h"
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
#include "DebugUtils.h"
|
|
#include "JavaBytecodes.h"
|
|
#include <stdarg.h>
|
|
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<AttributeInfoItem>::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<AttributeInfoItem>::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<AttributeInfoItem>::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<AttributeInfoItem> &list = fieldInfo[i]->getAttributes();
|
|
for (DoublyLinkedList<AttributeInfoItem>::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<AttributeConstantValue *>(&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<AttributeInfoItem> &list = methodInfo[i]->getAttributes();
|
|
int currentCount = 0;
|
|
for (DoublyLinkedList<AttributeInfoItem>::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<AttributeCode *>(&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<AttributeExceptions *>(&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;
|
|
}
|
|
|
|
|