blob: 219cf657be161a032e2b427d78f7ad581a299189 [file] [log] [blame]
/* This file read a Java(TM) .class file.
It is not stand-alone: It depends on tons of macros, and the
intent is you #include this file after you've defined the macros.
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005
Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to
the Free Software Foundation, 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
Java and all Java-based marks are trademarks or registered trademarks
of Sun Microsystems, Inc. in the United States and other countries.
The Free Software Foundation is independent of Sun Microsystems, Inc. */
#include "jcf.h"
#include "zipfile.h"
static int get_attribute (JCF *);
static int jcf_parse_preamble (JCF *);
static int jcf_parse_constant_pool (JCF *);
static void jcf_parse_class (JCF *);
static int jcf_parse_fields (JCF *);
static int jcf_parse_one_method (JCF *);
static int jcf_parse_methods (JCF *);
static int jcf_parse_final_attributes (JCF *);
#ifdef NEED_PEEK_ATTRIBUTE
static int peek_attribute (JCF *, int, const char *, int);
#endif
#ifdef NEED_SKIP_ATTRIBUTE
static void skip_attribute (JCF *, int);
#endif
/* Go through all available attribute (ATTRIBUTE_NUMER) and try to
identify PEEKED_NAME. Return 1 if PEEKED_NAME was found, 0
otherwise. JCF is restored to its initial position before
returning. */
#ifdef NEED_PEEK_ATTRIBUTE /* Not everyone uses this function */
static int
peek_attribute (JCF *jcf, int attribute_number, const char *peeked_name,
int peeked_name_length)
{
int to_return = 0;
long absolute_offset = (long)JCF_TELL (jcf);
int i;
for (i = 0; !to_return && i < attribute_number; i++)
{
uint16 attribute_name = (JCF_FILL (jcf, 6), JCF_readu2 (jcf));
uint32 attribute_length = JCF_readu4 (jcf);
int name_length;
const unsigned char *name_data;
JCF_FILL (jcf, (long) attribute_length);
if (attribute_name <= 0 || attribute_name >= JPOOL_SIZE(jcf)
|| JPOOL_TAG (jcf, attribute_name) != CONSTANT_Utf8)
continue;
name_length = JPOOL_UTF_LENGTH (jcf, attribute_name);
name_data = JPOOL_UTF_DATA (jcf, attribute_name);
if (name_length == peeked_name_length
&& ! memcmp (name_data, peeked_name, peeked_name_length))
{
to_return = 1;
break;
}
JCF_SKIP (jcf, attribute_length);
}
JCF_SEEK (jcf, absolute_offset);
return to_return;
}
#endif
#ifdef NEED_SKIP_ATTRIBUTE /* Not everyone uses this function */
static void
skip_attribute (JCF *jcf, int number_of_attribute)
{
while (number_of_attribute--)
{
JCF_u4 N;
JCF_FILL (jcf, 6);
(void) JCF_readu2 (jcf);
N = JCF_readu4 (jcf);
JCF_SKIP (jcf, N);
}
}
#endif
static int
get_attribute (JCF *jcf)
{
uint16 attribute_name = (JCF_FILL (jcf, 6), JCF_readu2 (jcf));
uint32 attribute_length = JCF_readu4 (jcf);
uint32 start_pos = JCF_TELL(jcf);
int name_length;
const unsigned char *name_data;
JCF_FILL (jcf, (long) attribute_length);
if (attribute_name <= 0 || attribute_name >= JPOOL_SIZE(jcf))
return -2;
if (JPOOL_TAG (jcf, attribute_name) != CONSTANT_Utf8)
return -2;
name_length = JPOOL_UTF_LENGTH (jcf, attribute_name);
name_data = JPOOL_UTF_DATA (jcf, attribute_name);
#define MATCH_ATTRIBUTE(S) \
(name_length == sizeof (S)-1 && memcmp (name_data, S, sizeof (S)-1) == 0)
#ifdef IGNORE_ATTRIBUTE
if (IGNORE_ATTRIBUTE (jcf, attribute_name, attribute_length))
{
JCF_SKIP (jcf, attribute_length);
}
else
#endif
#ifdef HANDLE_SOURCEFILE
if (MATCH_ATTRIBUTE ("SourceFile"))
{
uint16 sourcefile_index = JCF_readu2 (jcf);
HANDLE_SOURCEFILE(sourcefile_index);
}
else
#endif
#ifdef HANDLE_CONSTANTVALUE
if (MATCH_ATTRIBUTE ("ConstantValue"))
{
uint16 constantvalue_index = JCF_readu2 (jcf);
if (constantvalue_index <= 0 || constantvalue_index >= JPOOL_SIZE(jcf))
return -2;
HANDLE_CONSTANTVALUE(constantvalue_index);
}
else
#endif
#ifdef HANDLE_CODE_ATTRIBUTE
if (MATCH_ATTRIBUTE ("Code"))
{
uint16 j;
uint16 max_stack ATTRIBUTE_UNUSED = JCF_readu2 (jcf);
uint16 max_locals ATTRIBUTE_UNUSED = JCF_readu2 (jcf);
uint32 code_length = JCF_readu4 (jcf);
uint16 exception_table_length, attributes_count;
if (code_length + 12 > attribute_length)
return -1;
HANDLE_CODE_ATTRIBUTE(max_stack, max_locals, code_length);
JCF_SKIP (jcf, code_length);
exception_table_length = JCF_readu2 (jcf);
if (code_length + 8 * exception_table_length + 12 > attribute_length)
return -1;
#ifdef HANDLE_EXCEPTION_TABLE
HANDLE_EXCEPTION_TABLE (jcf->read_ptr, exception_table_length);
#endif
JCF_SKIP (jcf, 2 * 4 * exception_table_length);
attributes_count = JCF_readu2 (jcf);
for (j = 0; j < attributes_count; j++)
{
int code = get_attribute (jcf);
if (code != 0)
return code;
}
}
else
#endif /* HANDLE_CODE_ATTRIBUTE */
#ifdef HANDLE_EXCEPTIONS_ATTRIBUTE
if (MATCH_ATTRIBUTE ("Exceptions"))
{
uint16 count = JCF_readu2 (jcf);
HANDLE_EXCEPTIONS_ATTRIBUTE (count);
}
else
#endif
#ifdef HANDLE_LINENUMBERTABLE_ATTRIBUTE
if (MATCH_ATTRIBUTE ("LineNumberTable"))
{
uint16 count = JCF_readu2 (jcf);
HANDLE_LINENUMBERTABLE_ATTRIBUTE (count);
}
else
#endif
#ifdef HANDLE_LOCALVARIABLETABLE_ATTRIBUTE
if (MATCH_ATTRIBUTE ("LocalVariableTable"))
{
uint16 count = JCF_readu2 (jcf);
HANDLE_LOCALVARIABLETABLE_ATTRIBUTE (count);
}
else
#endif
#ifdef HANDLE_INNERCLASSES_ATTRIBUTE
if (MATCH_ATTRIBUTE ("InnerClasses"))
{
uint16 count = JCF_readu2 (jcf);
HANDLE_INNERCLASSES_ATTRIBUTE (count);
}
else
#endif
#ifdef HANDLE_SYNTHETIC_ATTRIBUTE
if (MATCH_ATTRIBUTE ("Synthetic"))
{
HANDLE_SYNTHETIC_ATTRIBUTE ();
}
else
#endif
#ifdef HANDLE_GCJCOMPILED_ATTRIBUTE
if (MATCH_ATTRIBUTE ("gnu.gcj.gcj-compiled"))
{
HANDLE_GCJCOMPILED_ATTRIBUTE ();
}
else
#endif
#ifdef HANDLE_DEPRECATED_ATTRIBUTE
if (MATCH_ATTRIBUTE ("Deprecated"))
{
HANDLE_DEPRECATED_ATTRIBUTE ();
}
else
#endif
#ifdef HANDLE_SOURCEDEBUGEXTENSION_ATTRIBUTE
if (MATCH_ATTRIBUTE ("SourceDebugExtension")) /* JSR 45 */
{
HANDLE_SOURCEDEBUGEXTENSION_ATTRIBUTE (attribute_length);
}
else
#endif
{
#ifdef PROCESS_OTHER_ATTRIBUTE
PROCESS_OTHER_ATTRIBUTE(jcf, attribute_name, attribute_length);
#else
JCF_SKIP (jcf, attribute_length);
#endif
}
if ((long) (start_pos + attribute_length) != JCF_TELL(jcf))
return -1;
return 0;
}
/* Read and handle the pre-amble. */
static int
jcf_parse_preamble (JCF* jcf)
{
uint32 magic = (JCF_FILL (jcf, 8), JCF_readu4 (jcf));
uint16 minor_version ATTRIBUTE_UNUSED = JCF_readu2 (jcf);
uint16 major_version ATTRIBUTE_UNUSED = JCF_readu2 (jcf);
#ifdef HANDLE_MAGIC
HANDLE_MAGIC (magic, minor_version, major_version);
#endif
if (magic != 0xcafebabe)
return -1;
else
return 0;
}
/* Read and handle the constant pool.
Return 0 if OK.
Return -2 if a bad cross-reference (index of other constant) was seen.
*/
static int
jcf_parse_constant_pool (JCF* jcf)
{
int i, n;
JPOOL_SIZE (jcf) = (JCF_FILL (jcf, 2), JCF_readu2 (jcf));
jcf->cpool.tags = ggc_alloc (JPOOL_SIZE (jcf));
jcf->cpool.data = ggc_alloc (sizeof (jword) * JPOOL_SIZE (jcf));
jcf->cpool.tags[0] = 0;
#ifdef HANDLE_START_CONSTANT_POOL
HANDLE_START_CONSTANT_POOL (JPOOL_SIZE (jcf));
#endif
for (i = 1; i < (int) JPOOL_SIZE (jcf); i++)
{
int constant_kind;
/* Make sure at least 9 bytes are available. This is enough
for all fixed-sized constant pool entries (so we don't need many
more JCF_FILL calls below), but is is small enough that
we are guaranteed to not hit EOF (in a valid .class file). */
JCF_FILL (jcf, 9);
constant_kind = JCF_readu (jcf);
jcf->cpool.tags[i] = constant_kind;
switch (constant_kind)
{
case CONSTANT_String:
case CONSTANT_Class:
jcf->cpool.data[i].w = JCF_readu2 (jcf);
break;
case CONSTANT_Fieldref:
case CONSTANT_Methodref:
case CONSTANT_InterfaceMethodref:
case CONSTANT_NameAndType:
jcf->cpool.data[i].w = JCF_readu2 (jcf);
jcf->cpool.data[i].w |= JCF_readu2 (jcf) << 16;
break;
case CONSTANT_Integer:
case CONSTANT_Float:
jcf->cpool.data[i].w = JCF_readu4 (jcf);
break;
case CONSTANT_Long:
case CONSTANT_Double:
jcf->cpool.data[i].w = JCF_readu4 (jcf);
i++; /* These take up two spots in the constant pool */
jcf->cpool.tags[i] = 0;
jcf->cpool.data[i].w = JCF_readu4 (jcf);
break;
case CONSTANT_Utf8:
n = JCF_readu2 (jcf);
JCF_FILL (jcf, n);
#ifdef HANDLE_CONSTANT_Utf8
HANDLE_CONSTANT_Utf8(jcf, i, n);
#else
jcf->cpool.data[i].w = JCF_TELL(jcf) - 2;
JCF_SKIP (jcf, n);
#endif
break;
default:
return i;
}
}
return 0;
}
/* Read various class flags and numbers. */
static void
jcf_parse_class (JCF* jcf)
{
int i;
uint16 interfaces_count;
JCF_FILL (jcf, 8);
jcf->access_flags = JCF_readu2 (jcf);
jcf->this_class = JCF_readu2 (jcf);
jcf->super_class = JCF_readu2 (jcf);
interfaces_count = JCF_readu2 (jcf);
#ifdef HANDLE_CLASS_INFO
HANDLE_CLASS_INFO(jcf->access_flags, jcf->this_class, jcf->super_class, interfaces_count);
#endif
JCF_FILL (jcf, 2 * interfaces_count);
/* Read interfaces. */
for (i = 0; i < interfaces_count; i++)
{
uint16 index ATTRIBUTE_UNUSED = JCF_readu2 (jcf);
#ifdef HANDLE_CLASS_INTERFACE
HANDLE_CLASS_INTERFACE (index);
#endif
}
}
/* Read fields. */
static int
jcf_parse_fields (JCF* jcf)
{
int i, j;
uint16 fields_count;
JCF_FILL (jcf, 2);
fields_count = JCF_readu2 (jcf);
#ifdef HANDLE_START_FIELDS
HANDLE_START_FIELDS (fields_count);
#endif
for (i = 0; i < fields_count; i++)
{
uint16 access_flags = (JCF_FILL (jcf, 8), JCF_readu2 (jcf));
uint16 name_index = JCF_readu2 (jcf);
uint16 signature_index = JCF_readu2 (jcf);
uint16 attribute_count = JCF_readu2 (jcf);
#ifdef HANDLE_START_FIELD
HANDLE_START_FIELD (access_flags, name_index, signature_index,
attribute_count);
#endif
for (j = 0; j < attribute_count; j++)
{
int code = get_attribute (jcf);
if (code != 0)
return code;
}
#ifdef HANDLE_END_FIELD
HANDLE_END_FIELD ();
#endif
}
#ifdef HANDLE_END_FIELDS
HANDLE_END_FIELDS ();
#endif
return 0;
}
/* Read methods. */
static int
jcf_parse_one_method (JCF* jcf)
{
int i;
uint16 access_flags = (JCF_FILL (jcf, 8), JCF_readu2 (jcf));
uint16 name_index = JCF_readu2 (jcf);
uint16 signature_index = JCF_readu2 (jcf);
uint16 attribute_count = JCF_readu2 (jcf);
#ifdef HANDLE_METHOD
HANDLE_METHOD(access_flags, name_index, signature_index, attribute_count);
#endif
for (i = 0; i < attribute_count; i++)
{
int code = get_attribute (jcf);
if (code != 0)
return code;
}
#ifdef HANDLE_END_METHOD
HANDLE_END_METHOD ();
#endif
return 0;
}
static int
jcf_parse_methods (JCF* jcf)
{
int i;
uint16 methods_count;
JCF_FILL (jcf, 2);
methods_count = JCF_readu2 (jcf);
#ifdef HANDLE_START_METHODS
HANDLE_START_METHODS (methods_count);
#endif
for (i = 0; i < methods_count; i++)
{
int code = jcf_parse_one_method (jcf);
if (code != 0)
return code;
}
#ifdef HANDLE_END_METHODS
HANDLE_END_METHODS ();
#endif
return 0;
}
/* Read attributes. */
static int
jcf_parse_final_attributes (JCF *jcf)
{
int i;
uint16 attributes_count = (JCF_FILL (jcf, 2), JCF_readu2 (jcf));
#ifdef START_FINAL_ATTRIBUTES
START_FINAL_ATTRIBUTES (attributes_count)
#endif
for (i = 0; i < attributes_count; i++)
{
int code = get_attribute (jcf);
if (code != 0)
return code;
}
return 0;
}