/* javaclfl.c: Copyright (C) Codemist Ltd., 1996. */ #include <stdio.h> #include <string.h> #include "machine.h" #include "tags.h" #include "cslerror.h" #include "externs.h" #include "read.h" #include "stream.h" #include "arith.h" #include "entries.h" #include "javahost.h" #include "javaglb.h" /* #include "javatype.h" */ #define D_CLASSFILE 1 #define D_CLASSFILEIO 2 #define D_CLASSFILECODE 4 static int depth; static unsigned32 rd1(FILE *f) { unsigned32 x = getc(f); if (debugging & D_CLASSFILEIO) jdebug("rd1 %d", x); return x; } static unsigned32 rd2(FILE *f) { unsigned32 x = getc(f); x = x<<8 | getc(f); if (debugging & D_CLASSFILEIO) jdebug("rd2 0x%.4x", x); return x; } static unsigned32 rd4(FILE *f) { unsigned32 x = getc(f); x = x<<8 | getc(f); x = x<<8 | getc(f); x = x<<8 | getc(f); if (debugging & D_CLASSFILEIO) jdebug("rd4 0x%.8x", x); return x; } static char *rd1string(FILE *f, unsigned32 n) { int i; unsigned8 *p = (unsigned8 *)jmalloc((n+1) * sizeof(*p)); for (i=0; i<n; i++) p[i] = rd1(f); p[n] = 0; /* @@@ ease C access for debugging (temp?) */ return (char *)p; } static char *rd2string(FILE *f, unsigned32 n) { int i; unsigned16 *p = (unsigned16 *)jmalloc(n * sizeof(*p)); for (i=0; i<n; i++) p[i] = rd2(f); return (char *)p; } static char *cpname(unsigned32 cpx, ClassFile *cf) { if (cpx < cf->constant_pool_count) { Cp_Info *cpitem = &cf->constant_pool[cpx]; if (cpitem->tag == CONSTANT_Utf8) return cpitem->u.utf8; return "<non-utf8 const pool index>"; } return "<bad const pool index>"; } static Attribute_Sort lookup_attribute_sort(char *utf8, unsigned32 len) { /* Should use 'len' not rely on rd1string() zero padding. */ if (strcmp(utf8,"SourceFile") == 0) return ATT_SourceFile; if (strcmp(utf8,"ConstantValue") == 0) return ATT_ConstantValue; if (strcmp(utf8,"Code") == 0) return ATT_Code; if (strcmp(utf8,"Exceptions") == 0) return ATT_Exceptions; if (strcmp(utf8,"LineNumberTable") == 0) return ATT_LineNumberTable; if (strcmp(utf8,"LocalVariableTable") == 0) return ATT_LocalVariableTable; return ATT_unknown; } static int rdAttribute_Info(FILE *f, ClassFile *cf, unsigned32 n, Attribute_Info **res); static int rdSourceFile_Attribute(FILE *f, ClassFile *cf, SourceFile_Attribute **res) { SourceFile_Attribute *p = (SourceFile_Attribute *)jmalloc(sizeof(*p)); depth++; p->sourcefile_index = rd2(f); if (debugging & D_CLASSFILE) jdebug("%*sAttribute Sourcefile '%s'", depth*2, "", cpname(p->sourcefile_index, cf)); *res = p; return (depth--, 0); } static int rdConstantValue_Attribute(FILE *f, ClassFile *cf, ConstantValue_Attribute **res) { ConstantValue_Attribute *p = (ConstantValue_Attribute *)jmalloc(sizeof(*p)); depth++; p->constantvalue_index = rd2(f); if (debugging & D_CLASSFILE) jdebug("%*sAttribute ConstantValue [%d]", depth*2, "", p->constantvalue_index); *res = p; return (depth--, 0); } static int rdCode_Attribute(FILE *f, ClassFile *cf, Code_Attribute **res) { Code_Attribute *p = (Code_Attribute *)jmalloc(sizeof(*p)); unsigned32 i,n; depth++; p->max_stack = rd2(f); p->max_locals = rd2(f); p->code_length = n = rd4(f); p->code = (unsigned8 *)jmalloc(n * sizeof(*p->code)); for (i=0; i<n; i++) p->code[i] = rd1(f); p->exception_table_length = n = rd2(f); p->exception_table = (Exception_Info *)jmalloc(n * sizeof(*p->exception_table)); for (i=0; i<n; i++) { Exception_Info *q = &p->exception_table[i]; q->start_pc = rd2(f); q->end_pc = rd2(f); q->handler_pc = rd2(f); q->catch_type = rd2(f); } p->attributes_count = n = rd2(f); if (debugging & D_CLASSFILE) jdebug("%*sAttribute Code \ (stack %d, locals %d, bytes %d, exceptions %d)", depth*2, "", p->max_stack, p->max_locals, p->code_length, p->exception_table_length); if (debugging & D_CLASSFILECODE) javadecode(p->code, p->code_length, cf->constant_pool, cf->constant_pool_count); if (rdAttribute_Info(f, cf, n, &p[i].attributes)) return 5; *res = p; return (depth--, 0); } static int rdExceptions_Attribute(FILE *f, ClassFile *cf, Exceptions_Attribute **res) { Exceptions_Attribute *p = (Exceptions_Attribute *)jmalloc(sizeof(*p)); unsigned32 i,n; depth++; p->number_of_exceptions = n = rd2(f); p->exception_index_table = (unsigned16 *)jmalloc(n * sizeof(*p->exception_index_table)); for (i=0; i<n; i++) p->exception_index_table[i] = rd2(f); if (debugging & D_CLASSFILE) jdebug("%*sAttribute Exceptions (entries %d)", depth*2, "", p->number_of_exceptions); *res = p; return (depth--, 0); } static int rdLineNumberTable_Attribute(FILE *f, ClassFile *cf, LineNumberTable_Attribute **res) { LineNumberTable_Attribute *p = (LineNumberTable_Attribute *)jmalloc(sizeof(*p)); unsigned32 i,n; depth++; p->line_number_table_length = n = rd2(f); p->line_number_table = (LineNumber_Info *)jmalloc(n * sizeof(*p->line_number_table)); for (i=0; i<n; i++) { LineNumber_Info *q = &p->line_number_table[i]; q->start_pc = rd2(f); q->line_number = rd2(f); } if (debugging & D_CLASSFILE) jdebug("%*sAttribute LineNumberTable (entries %d)", depth*2, "", p->line_number_table_length); *res = p; return (depth--, 0); } static int rdLocalVariableTable_Attribute(FILE *f, ClassFile *cf, LocalVariableTable_Attribute **res) { LocalVariableTable_Attribute *p = (LocalVariableTable_Attribute *)jmalloc(sizeof(*p)); unsigned32 i,n; depth++; p->local_variable_table_length = n = rd2(f); p->local_variable_table = (LocalVariable_Info *)jmalloc(n * sizeof(*p->local_variable_table)); for (i=0; i<n; i++) { LocalVariable_Info *q = &p->local_variable_table[i]; q->start_pc = rd2(f); q->length = rd2(f); q->name_index = rd2(f); q->signature_index = rd2(f); q->slot = rd2(f); } if (debugging & D_CLASSFILE) jdebug("%*sAttribute LocalVariableTable (entries %d)", depth*2, "", p->local_variable_table_length); *res = p; return (depth--, 0); } /* 'Attributes' occur more than once in a Classfile, hence they are */ /* stored in *res (OK/NOK is return value), but reading Attributes */ /* also requires cf to access the previously read Cp_Info. */ static int rdAttribute_Info(FILE *f, ClassFile *cf, unsigned32 n, Attribute_Info **res) { Attribute_Info *p; unsigned32 i; if (n > 0xffff) return 1; p = (Attribute_Info *)jmalloc(n * sizeof(*p)); if (debugging & D_CLASSFILE) jdebug("%*sAttributes_Info %d", depth*2, "", n); for (i=0; i<n; i++) { unsigned32 cpx = rd2(f); unsigned32 len = rd4(f); Cp_Info *cpitem = &cf->constant_pool[cpx]; if (cpitem->tag != CONSTANT_Utf8) return 3; switch (p[i].sort = lookup_attribute_sort(cpitem->u.utf8, cpitem->len)) { case ATT_Code: if (rdCode_Attribute(f, cf, &p[i].uattr.code)) return 6; break; case ATT_SourceFile: if (rdSourceFile_Attribute(f, cf, &p[i].uattr.sourcefile)) return 6; break; case ATT_ConstantValue: if (rdConstantValue_Attribute(f, cf, &p[i].uattr.constantvalue)) return 6; break; case ATT_Exceptions: if (rdExceptions_Attribute(f, cf, &p[i].uattr.exceptions)) return 6; break; case ATT_LineNumberTable: if (rdLineNumberTable_Attribute(f, cf, &p[i].uattr.linenumbertable)) return 6; break; case ATT_LocalVariableTable: if (rdLocalVariableTable_Attribute(f, cf, &p[i].uattr.localvariabletable)) return 6; break; default: /* currently ignore other attributes */ if (debugging & D_CLASSFILE) jdebug("%*sAttribute '%s' unknown", (depth+1)*2, "", cpitem->u.utf8); while (len) rd1(f), len--; } } *res = p; return 0; } static int rdCp_Info(FILE *f, ClassFile *cf, unsigned32 n) { Cp_Info *p; unsigned32 i, nn; depth++; if (n > 0xffff) return 1; if (debugging & D_CLASSFILE) jdebug("Cp_Info %d", n); p = (Cp_Info *)jmalloc(n * sizeof(*p)); /* Yes, the next line really is '1'! */ for (i=1; i<n; i++) switch (p[i].tag = rd1(f)) { default: jsyserr("tag %d", p[i].tag); return 2; case CONSTANT_Class: p[i].u.val = rd2(f); break; case CONSTANT_FieldRef: case CONSTANT_MethodRef: case CONSTANT_InterfaceMethodRef: /* stuff name_and_type_index into len */ p[i].u.val = rd2(f); p[i].len = rd2(f); break; case CONSTANT_String: p[i].u.val = rd2(f); break; case CONSTANT_Integer: case CONSTANT_Float: p[i].u.val = rd4(f); break; case CONSTANT_Long: case CONSTANT_Double: p[i].u.val = rd4(f); i++; p[i].tag = CONSTANT_Xhalf; p[i].u.val = rd4(f); break; case CONSTANT_Utf8: if ((nn = rd2(f)) > 0xffff) nn = 0; /* EOF */ p[i].len = nn; p[i].u.utf8 = rd1string(f, nn); break; case CONSTANT_Unicode: if ((nn = rd2(f)) > 0xffff) nn = 0; /* EOF */ p[i].len = nn; p[i].u.utf8 = rd2string(f, nn); break; case CONSTANT_NameAndType: /* stuff signature_index into len */ p[i].u.val = rd2(f); p[i].len = rd2(f); break; } cf->constant_pool = p; return (depth--, 0); } static int rdInterface_Info(FILE *f, ClassFile *cf, unsigned32 n) { unsigned16 *p; unsigned32 i; depth++; if (n > 0xffff) return 1; if (debugging & D_CLASSFILE) jdebug("Interface_Info %d", n); p = (unsigned16 *)jmalloc(n * sizeof(*p)); for (i=0; i<n; i++) p[i] = rd2(f); cf->interfaces = p; return (depth--, 0); } static int rdField_Info(FILE *f, ClassFile *cf, unsigned32 n) { Field_Info *p; unsigned32 i; depth++; if (n > 0xffff) return 1; if (debugging & D_CLASSFILE) jdebug("Field_Info %d", n); p = (Field_Info *)jmalloc(n * sizeof(*p)); for (i=0; i<n; i++) { unsigned32 nn; p[i].access_flags = rd2(f); p[i].name_index = rd2(f); p[i].signature_index = rd2(f); p[i].attributes_count = nn = rd2(f); if (debugging & D_CLASSFILE) jdebug(" Field '%s' signature '%s' flags 0x%x", cpname(p[i].name_index, cf), cpname(p[i].signature_index, cf), p[i].access_flags); if (rdAttribute_Info(f, cf, nn, &p[i].attributes)) return 4; } cf->fields = p; return (depth--, 0); } static int rdMethod_Info(FILE *f, ClassFile *cf, unsigned32 n) { Method_Info *p; unsigned32 i; depth++; if (n > 0xffff) return 1; if (debugging & D_CLASSFILE) jdebug("Method_Info %d", n); p = (Method_Info *)jmalloc(n * sizeof(*p)); for (i=0; i<n; i++) { unsigned32 nn; p[i].access_flags = rd2(f); p[i].name_index = rd2(f); p[i].signature_index = rd2(f); p[i].attributes_count = nn = rd2(f); if (debugging & D_CLASSFILE) jdebug(" Method '%s' signature '%s' flags 0x%x", cpname(p[i].name_index, cf), cpname(p[i].signature_index, cf), p[i].access_flags); if (rdAttribute_Info(f, cf, nn, &p[i].attributes)) return 4; } cf->methods = p; return (depth--, 0); } ClassFile *rdClassFile(char *name) { FILE *f = fopen(name, "rb"); ClassFile *cf = rdClassFILE1(f, name); fclose(f); return cf; } ClassFile *rdClassFILE1(FILE *f, char *name) { ClassFile *cf; unsigned32 n; depth = 0; if (f == 0) { jsyserr("cannot read '%s'", name); return 0; } if (rd4(f) != JAVA_MAGIC) { jsyserr("not class file '%s'", name); return 0; } if ((n = rd2(f)) > JAVA_THIS_MIN) jdebug("ClassFile '%s' wrong minor vsn %d", name, n); if ((n = rd2(f)) != JAVA_THIS_MAJ) jdebug("ClassFile '%s' wrong major vsn %d", name, n); cf = (ClassFile *)jmalloc(sizeof(ClassFile)); cf->constant_pool_count = n = rd2(f); if (rdCp_Info(f, cf, n)) goto corrupt; cf->access_flags = rd2(f); cf->this_class = rd2(f); cf->super_class = rd2(f); cf->interfaces_count = n = rd2(f); if (rdInterface_Info(f, cf, n)) goto corrupt; cf->fields_count = n = rd2(f); if (rdField_Info(f, cf, n)) goto corrupt; cf->methods_count = n = rd2(f); if (rdMethod_Info(f, cf, n)) goto corrupt; cf->attributes_count = n = rd2(f); if (rdAttribute_Info(f, cf, n, &cf->attributes)) goto corrupt; if (rd1(f) != EOF) jdebug("junk at end of ClassFile '%s'", name); return cf; corrupt: jsyserr("ClassFile '%s' corrupted", name); return 0; }