DEADSOFTWARE

Patched for Linux
[mp3cc.git] / MPC.3.5.LINUX / preverifier / classloader.c
1 /*
2 * @(#)classloader.c 1.37 02/09/27
3 *
4 * Copyright 1995-1999 by Sun Microsystems, Inc.,
5 * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
6 * All rights reserved.
7 *
8 * This software is the confidential and proprietary information
9 * of Sun Microsystems, Inc. ("Confidential Information"). You
10 * shall not disclose such Confidential Information and shall use
11 * it only in accordance with the terms of the license agreement
12 * you entered into with Sun.
13 * Use is subject to license terms.
14 */
16 /*=========================================================================
17 * SYSTEM: Verifier
18 * SUBSYSTEM: class loader.
19 * FILE: classloader.c
20 * OVERVIEW: Routines for loading and resolving class definitions.
21 * These routines should not be depending upon the interpreter
22 * or the garbage collector.
23 * AUTHOR: Sheng Liang, Sun Microsystems, Inc.
24 * Modifications for JAR support and comments,
25 * Tasneem Sayeed, Sun Microsystems
26 *=======================================================================*/
28 /*=========================================================================
29 * Include files
30 *=======================================================================*/
32 #include <string.h>
33 #include <stdio.h>
34 #include <sys/types.h>
35 #include <stddef.h>
36 #include <fcntl.h>
37 #include <sys/stat.h>
38 #include <stdlib.h>
39 #include <setjmp.h>
41 #include "jar.h"
42 #include "oobj.h"
43 #include "path.h"
44 #include "tree.h"
45 #include "signature.h"
46 #include "convert_md.h"
48 #include "sys_api.h"
50 #ifdef UNIX
51 #include <unistd.h>
52 #endif
55 /*=========================================================================
56 * Globals and extern declarations
57 *=======================================================================*/
59 char *stat_source(ClassClass *cb, struct stat *s, char *pathbuf, int maxlen);
61 extern ClassClass *allocClassClass();
63 extern bool_t JARfile;
65 extern char * zipFileName;
67 extern zip_t * getZipEntry(char *zipFile, int len);
69 extern bool_t findJARDirectories(zip_t *entry, struct stat *statbuf);
71 extern JAR_DataStreamPtr loadJARfile(zip_t *entry, const char* filename);
74 /*=========================================================================
75 * FUNCTION: AddBinClass
76 * OVERVIEW: Used by createInternalClass1() and createFakeArrayClass()
77 * to add a class in the class table.
78 * INTERFACE:
79 * parameters: ClassClass: cb
80 *
81 * returns: nothing
82 *=======================================================================*/
83 void
84 AddBinClass(ClassClass * cb)
85 {
86 register int left, right, middle, result, i;
87 char *name = cbName(cb);
88 struct Hjava_lang_ClassLoader *loader = cbLoader(cb);
90 BINCLASS_LOCK();
91 left = 0;
92 right = nbinclasses - 1;
93 result = 1;
94 while (left <= right) {
95 ClassClass *cb1;
96 middle = (left+right)/2;
97 cb1 = binclasses[middle];
98 result = strcmp(name, cbName(cb1));
99 if (result == 0) {
100 if (loader < cbLoader(cb1)) {
101 result = -1;
102 } else if (loader > cbLoader(cb1)) {
103 result = 1;
104 } else {
105 result = 0;
108 if (result < 0) {
109 right = middle-1;
110 } else if (result > 0) {
111 left = middle+1;
112 } else {
113 break;
116 if (result != 0) {
117 if (nbinclasses >= sizebinclasses) {
118 if (binclasses == 0)
119 binclasses = (ClassClass **)
120 sysMalloc(sizeof(ClassClass *) * (sizebinclasses = 50));
121 else
122 binclasses = (ClassClass **)
123 sysRealloc(binclasses, sizeof(ClassClass *)
124 * (sizebinclasses = nbinclasses * 2));
126 if (binclasses == 0)
127 goto unlock;
128 right++;
129 for (i = nbinclasses; i > right; i--) {
130 binclasses[i] = binclasses[i-1];
132 binclasses[right] = cb;
133 nbinclasses++;
136 unlock:
137 BINCLASS_UNLOCK();
141 /*=========================================================================
142 * FUNCTION: DelBinClass
143 * OVERVIEW: Intended for allowing deletion of classes from the class
144 * table.
146 * INTERFACE:
147 * parameters: ClassClass: cb
149 * returns: nothing
150 *=======================================================================*/
151 void
152 DelBinClass(ClassClass * cb)
154 register int i, j;
155 BINCLASS_LOCK();
156 for (i = nbinclasses; --i >= 0; )
157 if (binclasses[i] == cb) {
158 nbinclasses--;
159 for (j = i; j < nbinclasses; j++) {
160 binclasses[j] = binclasses[j+1];
162 break;
164 BINCLASS_UNLOCK();
168 /*=========================================================================
169 * FUNCTION: MakeClassSticky
170 * OVERVIEW: Used to lock certain system classes into memory during
171 * initialization.
173 * INTERFACE:
174 * parameters: ClassClass: cb
176 * returns: nothing
177 *=======================================================================*/
178 void
179 MakeClassSticky(ClassClass *cb)
181 /* monitorEnter(obj_monitor(cb)); */
182 CCSet(cb, Sticky);
183 /* monitorExit(obj_monitor(cb)); */
187 /*=========================================================================
188 * FUNCTION: LoadClassFromFile
189 * OVERVIEW: Loads a .class file normally from disk or a null if it fails.
190 * When the interpreter requests for a file, it is actually
191 * looking for a classblock structure to be created, and the
192 * only way it can get one of those is by loading a compiled
193 * class.
194 * OpenCode() tries to open a .class file first. If it fails
195 * to open the file, it returns a non-zero status. If it
196 * returns a valid file descriptor, this usually means that
197 * this is a valid .class file.
198 * It then invokes createInternalClass() to actually create the
199 * internal representation of the class.
201 * INTERFACE:
202 * parameters: char*: file name
203 * char*: directory
204 * char*: class name
206 * returns: nothing
207 *=======================================================================*/
208 ClassClass *
209 LoadClassFromFile(char *fn, char *dir, char *class_name)
211 extern int OpenCode(char *, char *, char *, struct stat*);
212 struct stat st;
213 ClassClass *cb = 0;
214 int codefd = -1;
215 unsigned char *external_class;
216 char *detail;
218 codefd = OpenCode(fn, NULL, dir, &st);
220 if (codefd < 0) /* open failed */
221 return 0;
223 /* Snarf the file into memory. */
224 external_class = (unsigned char *)sysMalloc(st.st_size);
225 if (external_class == 0)
226 goto failed;
227 if (sysRead(codefd, external_class, st.st_size) != st.st_size)
228 goto failed;
229 sysClose(codefd);
230 codefd = -1;
232 /* Create the internal class */
233 cb = allocClassClass();
234 if (cb == NULL ||
235 !createInternalClass(external_class, external_class + st.st_size,
236 cb, NULL, class_name, &detail)) {
237 sysFree(external_class);
238 goto failed;
240 sysFree(external_class);
242 if (verbose)
243 jio_fprintf(stderr, "[Loaded %s]\n", fn);
245 return cb;
246 failed:
247 if (codefd >= 0)
248 sysClose(codefd);
249 if (cb != 0)
250 FreeClass(cb);
251 return 0;
255 /*=========================================================================
256 * FUNCTION: LoadClassFromZip
257 * TYPE: load class from a JAR or Zip file
258 * OVERVIEW: Called by LoadClassLocally for loading classes from a Zip.
260 * This function loads a .class file normally from a Zip or
261 * JAR file.
262 * It returns the class when it succeeds or NULL if it fails.
264 * INTERFACE:
265 * parameters: zip_t: zip file entry
266 * char*: class file name to search for loading
267 * returns: Pointer to ClassClass when it succeeds, or NULL if it fails.
268 *=======================================================================*/
269 static ClassClass *
270 LoadClassFromZip(zip_t *zipEntry, char *class_name)
272 ClassClass *cb = 0;
273 JAR_DataStreamPtr jdstream = NULL;
274 unsigned char *external_class;
275 int data_length;
276 char *detail;
278 jdstream = loadJARfile (zipEntry, class_name);
280 if (jdstream == NULL)
281 goto failed;
283 external_class = jdstream->data;
284 data_length = jdstream->dataLen;
286 /* Create the internal class */
287 cb = allocClassClass();
288 if (cb == NULL ||
289 !createInternalClass(external_class, external_class + data_length,
290 cb, NULL, class_name, &detail)) {
291 goto failed;
293 if (jdstream != NULL) {
294 freeBytes(jdstream);
297 if (verbose) {
298 jio_fprintf(stderr, "[Loaded %s] from [%s]\n", class_name,
299 zipEntry->name);
301 return cb;
302 failed:
303 if (cb != 0)
304 FreeClass(cb);
305 if (jdstream != NULL) {
306 freeBytes(jdstream);
308 return 0;
312 /*=========================================================================
313 * FUNCTION: LoadClassLocally
314 * OVERVIEW: Find a class file that is somewhere local, and not from a
315 * class loader.
316 * It still needs to be searched using the classpath.
318 * INTERFACE:
319 * parameters: char* : class file name
320 * returns: Pointer to ClassClass when it succeeds, or NULL if it fails.
321 *=======================================================================*/
322 ClassClass *LoadClassLocally(char *name)
324 ClassClass *cb = 0;
325 cpe_t **cpp;
327 if (name[0] == DIR_SEPARATOR || name[0] == SIGNATURE_ARRAY)
328 return 0;
330 for (cpp = sysGetClassPath(); cpp && *cpp != 0; cpp++) {
331 cpe_t *cpe = *cpp;
332 char *path;
334 if (cpe->type == CPE_DIR) {
335 path = (char *)sysMalloc(strlen(cpe->u.dir)
336 + sizeof(LOCAL_DIR_SEPARATOR)
337 + strlen(name)
338 + strlen(JAVAOBJEXT)
339 + 2); /* 2 is for the . and the \0 */
340 if (sprintf(path,
341 "%s%c%s." JAVAOBJEXT, cpe->u.dir,
342 LOCAL_DIR_SEPARATOR, name) == -1) {
343 sysFree(path);
344 return 0;
346 if ((cb = LoadClassFromFile(sysNativePath(path),
347 cpe->u.dir, name))) {
348 sysFree(path);
349 return cb;
351 } else if (cpe->type == CPE_ZIP) {
352 // if (JAR_DEBUG && verbose)
353 // jio_fprintf(stderr, "Loading classes from a ZIP file... \n");
354 if ((cb = LoadClassFromZip(cpe->u.zip, name))) {
355 return cb;
360 return cb;
364 /*=========================================================================
365 * FUNCTION: stat_source
366 * OVERVIEW: Unused by the Verifier, but it is too late to remove it now.
368 * INTERFACE:
369 * parameters: ClassClass *: cb
370 * struct stat*: s
371 * char*: pathbuf
372 * int: maxlen
373 * returns: char *, or NULL if it fails.
374 *=======================================================================*/
375 char *
376 stat_source(ClassClass *cb, struct stat *s, char *pathbuf, int maxlen)
378 #define NAMEBUFLEN 255
379 char nm[NAMEBUFLEN];
380 char *p, *q, *lp;
381 cpe_t **cpp;
383 /* don't bother searching if absolute */
384 /* REMIND: only here for compatibility */
385 if (sysIsAbsolute(cbSourceName(cb))) {
386 if (sysStat(cbSourceName(cb), s) == 0) {
387 if (jio_snprintf(pathbuf, maxlen, "%s", cbSourceName(cb)) == -1) {
388 return 0;
390 return pathbuf;
391 } else {
392 return 0;
396 /* parse the package name */
397 p = cbName(cb);
398 if (strlen(p) > NAMEBUFLEN - 1) {
399 return 0;
401 for (q = lp = nm ; *p ; p++) {
402 if (*p == DIR_SEPARATOR) {
403 *q++ = LOCAL_DIR_SEPARATOR;
404 lp = q;
405 } else {
406 *q++ = *p;
410 /* append the source file name */
411 p = cbSourceName(cb);
412 if (strlen(p) + (lp - nm) > NAMEBUFLEN - 1) {
413 return 0;
415 for (; *p ; p++) {
416 *lp++ = (*p == DIR_SEPARATOR ? LOCAL_DIR_SEPARATOR : *p);
418 *lp = '\0';
420 /* search the class path */
421 for (cpp = sysGetClassPath() ; cpp && *cpp != 0 ; cpp++) {
422 cpe_t *cpe = *cpp;
423 if (cpe->type == CPE_DIR) {
424 if (jio_snprintf(pathbuf, maxlen, "%s%c%s",
425 cpe->u.dir, LOCAL_DIR_SEPARATOR, nm) == -1) {
426 return 0;
428 if (sysStat(pathbuf, s) == 0) {
429 return pathbuf;
433 return 0;
437 /*=========================================================================
438 * Globals and externs for Internal Class representation
439 *=======================================================================*/
440 struct CICmallocs {
441 struct CICmallocs *next;
442 void * alignment_padding;
444 /* Whatever follows will be 8-byte aligned, if the structure itself is
445 8-byte aligned. */
446 };
448 typedef struct CICmallocs CICmallocs;
450 struct CICcontext {
451 unsigned char *ptr;
452 unsigned char *end_ptr;
453 ClassClass *cb;
454 jmp_buf jump_buffer;
455 char **detail;
457 int pass; /* two passes, 1 or 2 */
458 int malloc_size; /* space needed for everything other than <clinit> */
459 int clinit_size; /* space needed for the <clinit> method */
460 int in_clinit; /* indicates whether we are loading <clinit> method */
462 struct {
463 CICmallocs *mallocs; /* list of memory blocks used in the first pass */
465 void * alignment_padding;
466 /* Whatever follows will be 8-byte aligned */
467 } pass1;
469 struct {
470 char *malloc_buffer; /* used to hold everything other than <clinit> */
471 char *malloc_ptr; /* current point of allocation */
473 char *clinit_buffer; /* used to hold the <clinit> method */
474 char *clinit_ptr; /* current point of allocation */
475 } pass2;
477 };
479 typedef struct CICcontext CICcontext;
481 static char *getAsciz(CICcontext *, bool_t);
482 static char *getAscizFromClass(CICcontext *, int i);
484 static unsigned char get1byte(CICcontext *);
485 static unsigned short get2bytes(CICcontext *);
486 static unsigned long get4bytes(CICcontext *);
487 static void getNbytes(CICcontext *, int count, char *buffer);
488 static void *allocNBytes(CICcontext *, int size);
489 static void freeBuffers(CICcontext *);
491 static void LoadConstantPool(CICcontext *);
492 static void ReadInCode(CICcontext *, struct methodblock *);
493 static void ReadLineTable(CICcontext *, struct methodblock *mb);
494 static void ReadExceptions(CICcontext *, struct methodblock *);
495 static void ReadLocalVars(CICcontext *, struct methodblock *mb);
497 static void
498 createInternalClass0(CICcontext *context, ClassClass *cb,
499 struct Hjava_lang_ClassLoader *loader, char *name);
501 bool_t
502 createInternalClass1(unsigned char *ptr, unsigned char *end_ptr,
503 ClassClass *cb, struct Hjava_lang_ClassLoader *loader,
504 char *name, char **detail);
507 /*=========================================================================
508 * FUNCTION: createInternalClass
509 * OVERVIEW: Invoked by LoadClassFromFile() or LoadClassFromZip() to
510 * create an internal class. See createInternalClass1() for
511 * details.
513 * INTERFACE:
514 * parameters: unsigned char *: ptr
515 * unsigned char *: end_ptr
516 * ClassClass *: cb
517 * struct Hjava_lang_ClassLoader *: loader
518 * char *: name
519 * char **: detail
521 * returns: bool_t
522 *=======================================================================*/
523 bool_t
524 createInternalClass(unsigned char *ptr, unsigned char *end_ptr,
525 ClassClass *cb, struct Hjava_lang_ClassLoader *loader,
526 char *name, char **detail)
528 bool_t res;
529 res = createInternalClass1(ptr, end_ptr, cb, loader, name, detail);
531 return res;
535 /*=========================================================================
536 * FUNCTION: JAVA_ERROR
537 * OVERVIEW: Verifier error processing function.
539 * INTERFACE:
540 * parameters: CICcontext *: context
541 * char * : name
543 * returns: nothing
544 *=======================================================================*/
545 void JAVA_ERROR(CICcontext *context, char *name) {
546 printCurrentClassName();
547 *(context->detail) = name;
548 EE()->class_loading_msg = name;
549 fprintf(stderr, "Class loading error: %s\n", name);
550 exit(1);
554 /*=========================================================================
555 * FUNCTION: createInternalClass1
556 * OVERVIEW: Auxiliary function for creating an internal class.
557 * Invoked by createInternalClass().
559 * Creates an internal class file from the indicated data.
560 * It should be in a buffer for which the first byte is at
561 * *ptr and the last byte is just before *end_ptr.
562 * The class's classloader is indicated by the classloader
563 * argument.
565 * We go through the buffer twice. In the first pass, we
566 * determine the amount of storage needed by the class.
567 * We then allocate a single chunk of memory, free the
568 * temporary storage, and load from the buffer for the second
569 * time.
571 * Since all storage needed by the class initialization method
572 * <clinit> can be freed after the class is loaded, we count
573 * the <clinit> space needs separately and store the <clinit>
574 * method in a separate chunk of memory.
576 * INTERFACE:
577 * parameters: unsigned char *: ptr
578 * unsigned char *: end_ptr
579 * ClassClass *: cb
580 * struct Hjava_lang_ClassLoader *: loader
581 * char *: name
582 * char **: detail
584 * returns: bool_t
585 *=======================================================================*/
586 bool_t
587 createInternalClass1(unsigned char *ptr, unsigned char *end_ptr,
588 ClassClass *cb, struct Hjava_lang_ClassLoader *loader,
589 char *name, char **detail)
591 struct CICcontext context_block;
592 struct CICcontext *context = &context_block;
594 /* Set up the context */
595 context->ptr = ptr;
596 context->end_ptr = end_ptr;
597 context->cb = cb;
598 context->detail = detail;
600 /* initialize the remaining fields of the context block */
601 context->pass = 0;
602 context->malloc_size = 0;
603 context->clinit_size = 0;
604 context->in_clinit = 0;
605 context->pass1.mallocs = 0;
607 context->pass2.malloc_buffer = NULL;
608 context->pass2.malloc_ptr = NULL;
609 context->pass2.clinit_buffer = NULL;
610 context->pass2.clinit_ptr = NULL;
613 if (setjmp(context->jump_buffer)) {
615 /* We've gotten an error of some sort
616 * See comments below about zeroing these
617 * two fields before freeing the temporary
618 * buffer.
619 */
621 cbConstantPool(cb) = NULL;
622 cbFields(cb) = NULL;
624 /* Zero out the method so that freeClass will
625 * not try to free the clinit method.
626 */
628 cbMethodsCount(cb) = 0;
629 freeBuffers(context);
630 return FALSE;
633 /* The first pass allows us to uncover any class format
634 * errors and find out the size of the buffer needed.
635 */
637 context->pass = 1;
638 createInternalClass0(context, cb, loader, name);
640 /* We must set the following two fields to zero before we free
641 * the temporary buffers, because markClassClass may scan a
642 * partially constructed class block in the second pass.
643 * If these two fields are set to zero, markClassClass will
644 * not scan the constant pool and field blocks, which may
645 * point to freed memory.
646 */
648 cbConstantPool(cb) = NULL;
649 cbFields(cb) = NULL;
651 /* Zero out the method so that freeClass will not try
652 * to free the clinit method.
653 */
655 cbMethodsCount(cb) = 0;
656 freeBuffers(context);
658 context->ptr = ptr; /* rewind the raw class data */
660 if (context->malloc_size > 0) {
661 context->pass2.malloc_buffer =
662 (char *)sysCalloc(1, context->malloc_size);
664 if (context->pass2.malloc_buffer == 0)
665 JAVA_ERROR(context, "out of memory");
668 if (context->clinit_size > 0) {
669 context->pass2.clinit_buffer =
670 (char *)sysCalloc(1, context->clinit_size * sizeof(char));
672 if (context->pass2.clinit_buffer == 0) {
673 sysFree(context->pass2.malloc_buffer);
674 JAVA_ERROR(context, "out of memory");
678 context->pass2.malloc_ptr = context->pass2.malloc_buffer;
679 context->pass2.clinit_ptr = context->pass2.clinit_buffer;
681 /* The second pass accomplishes the real task. */
683 context->pass = 2;
684 createInternalClass0(context, cb, loader, name);
686 /* Valid class - let's put it in the class table. */
687 AddBinClass(cb);
689 return TRUE;
693 /*=========================================================================
694 * FUNCTION: createInternalClass0
695 * OVERVIEW: Auxiliary function invoked by createInternalClass1() during
696 * the second pass to actually load the internal class file
697 * structures such as the constant pool, method blocks, field
698 * blocks and so on.
700 * INTERFACE:
701 * parameters: CICcontext *: ptr
702 * ClassClass *: cb
703 * struct Hjava_lang_ClassLoader *: loader
704 * char *: name
706 * returns: nothing
707 *=======================================================================*/
708 static void
709 createInternalClass0(CICcontext *context, ClassClass *cb,
710 struct Hjava_lang_ClassLoader *loader, char *name)
712 int i, j, len;
713 char buff[BUFSIZ];
714 char *UTFname = &buff[0];
715 union cp_item_type *constant_pool;
716 unsigned char *type_table;
717 int attribute_count;
718 unsigned fields_count;
719 struct methodblock *mb;
720 struct fieldblock *fb;
721 struct Classjava_lang_Class *ucb = unhand(cb);
723 int32_t tmp = get4bytes(context);
724 if (tmp != JAVA_CLASSFILE_MAGIC)
725 JAVA_ERROR(context, "Bad magic number");
727 ucb->minor_version = get2bytes(context);
728 ucb->major_version = get2bytes(context);
729 ucb->loader = loader;
731 /* Ignore version # so that the preverifier can work with JDK 1.4 onwards */
732 /*
733 if (ucb->major_version != JAVA_VERSION)
734 JAVA_ERROR(context, "Bad major version number");
735 */
737 LoadConstantPool(context);
738 constant_pool = ucb->constantpool;
739 type_table = constant_pool[CONSTANT_POOL_TYPE_TABLE_INDEX].type;
741 ucb->access = get2bytes(context) & ACC_WRITTEN_FLAGS;
743 /* Get the name of the class */
744 i = get2bytes(context); /* index in constant pool of class */
745 ucb->name = getAscizFromClass(context, i);
747 /* Conversion for Japanese filenames */
748 len = native2utf8(name, UTFname, BUFSIZ);
750 if (name != NULL && strcmp(ucb->name, UTFname) != 0)
751 JAVA_ERROR(context, "Wrong name");
752 constant_pool[i].clazz = cb;
753 CONSTANT_POOL_TYPE_TABLE_SET_RESOLVED(type_table, i);
755 if (loader) {
756 /* We don't trust a classloader to do the right thing. . . */
757 ClassClass **pcb, **end_pcb;
758 char *name = ucb->name;
759 // if (name == NULL || !IsLegalClassname(name, FALSE)) {
760 // JAVA_ERROR(context, "Bad name");
761 // }
762 BINCLASS_LOCK();
763 for (pcb = binclasses, end_pcb = pcb + nbinclasses;
764 pcb < end_pcb; pcb++) {
765 ClassClass *cb = *pcb;
766 if ((cbLoader(cb) == loader) && (strcmp(name, cbName(cb)) == 0))
767 break;
769 BINCLASS_UNLOCK();
770 if (pcb < end_pcb)
771 /* There's already a class with the same name and loader */
772 JAVA_ERROR(context, "Duplicate name");
775 /* Get the super class name. */
776 i = get2bytes(context); /* index in constant pool of class */
777 if (i > 0) {
778 ucb->super_name = getAscizFromClass(context, i);
779 ucb->superclass_idx = i;
780 // if (!IsLegalClassname(ucb->super_name, FALSE)) {
781 // JAVA_ERROR(context, "Bad superclass name");
782 // }
785 i = ucb->implements_count = get2bytes(context);
786 if (i > 0) {
787 int j;
788 ucb->implements = allocNBytes(context, i * sizeof(short));
789 for (j = 0; j < i; j++) {
790 ucb->implements[j] = get2bytes(context);
794 fields_count = ucb->fields_count = get2bytes(context);
795 if (fields_count > 0)
796 ucb->fields = (struct fieldblock *)
797 allocNBytes(context, ucb->fields_count * sizeof(struct fieldblock));
798 for (i = fields_count, fb = ucb->fields; --i >= 0; fb++) {
799 fieldclass(fb) = cb;
800 fb->access = get2bytes(context) & ACC_WRITTEN_FLAGS;
801 fb->name = getAsciz(context, FALSE);
802 fb->signature = getAsciz(context, FALSE);
803 attribute_count = get2bytes(context);
804 for (j = 0; j < (int)attribute_count; j++) {
805 char *attr_name = getAsciz(context, FALSE);
806 int length = get4bytes(context);
807 if (strcmp(attr_name, "ConstantValue") == 0) {
808 if (fb->access & ACC_STATIC) {
809 if (length != 2) {
810 JAVA_ERROR(context, "Wrong size for VALUE attribute");
812 fb->access |= ACC_VALKNOWN;
813 /* we'll change this below */
814 fb->u.offset = get2bytes(context);
815 } else {
816 getNbytes(context, length, NULL);
818 } else if (strcmp(attr_name, "Deprecated") == 0) {
819 if (length > 0) {
820 JAVA_ERROR(context, "Bad deprecated size");
822 fb->deprecated = TRUE;
823 } else if (strcmp(attr_name, "Synthetic") == 0) {
824 if (length > 0) {
825 JAVA_ERROR(context, "Bad synthetic attribute size");
827 fb->synthetic = TRUE;
828 } else {
829 getNbytes(context, length, NULL);
832 /*
833 if (fb->access & ACC_STATIC) {
834 InitializeStaticVar(fb, context);
836 */
839 if ((ucb->methods_count = get2bytes(context)) > 0)
840 ucb->methods = (struct methodblock *)
841 allocNBytes(context, ucb->methods_count * sizeof(struct methodblock));
843 for (i = cbMethodsCount(cb), mb = cbMethods(cb); --i >= 0; mb++) {
844 fieldclass(&mb->fb) = cb;
845 mb->fb.access = get2bytes(context) & ACC_WRITTEN_FLAGS;
846 mb->fb.name = getAsciz(context, FALSE);
847 mb->fb.signature = getAsciz(context, FALSE);
849 if (strcmp(mb->fb.name, "<clinit>") == 0 &&
850 strcmp(mb->fb.signature, "()V") == 0)
851 context->in_clinit = TRUE;
853 mb->args_size = Signature2ArgsSize(mb->fb.signature)
854 + ((mb->fb.access & ACC_STATIC) ? 0 : 1);
855 if (mb->args_size > 255)
856 JAVA_ERROR(context, "Too many arguments");
858 attribute_count = get2bytes(context);
859 for (j = 0; j < attribute_count; j++) {
860 char *attr_name = getAsciz(context, FALSE);
861 if ((strcmp(attr_name, "Code") == 0)
862 && ((mb->fb.access & (ACC_NATIVE | ACC_ABSTRACT))==0)) {
863 ReadInCode(context, mb);
864 } else if (strcmp(attr_name, "Exceptions") == 0) {
865 ReadExceptions(context, mb);
866 } else {
867 int length = get4bytes(context);
868 if (strcmp(attr_name, "Deprecated") == 0) {
869 if (length > 0) {
870 JAVA_ERROR(context, "Bad deprecated size");
872 mb->fb.deprecated = TRUE;
873 } else if (strcmp(attr_name, "Synthetic") == 0) {
874 if (length > 0) {
875 JAVA_ERROR(context, "Bad synthetic attribute size");
877 mb->fb.synthetic = TRUE;
878 } else {
879 getNbytes(context, length, NULL);
883 context->in_clinit = FALSE;
886 /* See if there are class attributes */
887 attribute_count = get2bytes(context);
888 for (j = 0; j < attribute_count; j++) {
889 char *attr_name = getAsciz(context, FALSE);
890 int length = get4bytes(context);
891 if (strcmp(attr_name, "SourceFile") == 0) {
892 if (length != 2) {
893 JAVA_ERROR(context, "Wrong size for VALUE attribute");
895 ucb->source_name = getAsciz(context, FALSE);
896 } else if (strcmp(attr_name, "AbsoluteSourcePath") == 0) {
897 if (length == 2) {
898 ucb->absolute_source_name = getAsciz(context, FALSE);
899 } else
900 getNbytes(context, length, NULL);
901 } else if (strcmp(attr_name, "TimeStamp") == 0) {
902 if (length == 8) {
903 ucb->hasTimeStamp = TRUE;
904 ucb->timestamp.high = get4bytes(context);
905 ucb->timestamp.low = get4bytes(context);
906 } else {
907 getNbytes(context, length, NULL);
909 } else if (strcmp(attr_name, "Deprecated") == 0) {
910 if (length > 0) {
911 JAVA_ERROR(context, "Bad deprecated size");
913 ucb->deprecated = TRUE;
914 } else if (strcmp(attr_name, "Synthetic") == 0) {
915 if (length > 0) {
916 JAVA_ERROR(context, "Bad synthetic attribute size");
918 ucb->synthetic = TRUE;
919 } else if (strcmp(attr_name, "InnerClasses") == 0) {
920 int count = get2bytes(context);
921 struct innerClasses *thisInnerClass = (struct innerClasses *)
922 allocNBytes(context, count * sizeof(struct innerClasses));
923 struct innerClasses *lastInnerClass = thisInnerClass + count;
925 if (count * 8 + 2 != length) {
926 JAVA_ERROR(context, "Bad length of InnerClasses attribute");
929 ucb->inner_classes_count = count;
930 ucb->inner_classes = thisInnerClass;
932 for ( ; thisInnerClass < lastInnerClass; thisInnerClass++) {
933 thisInnerClass->inner_class = get2bytes(context);
934 thisInnerClass->outer_class = get2bytes(context);
935 thisInnerClass->inner_name = getAsciz(context, TRUE);
936 thisInnerClass->access = get2bytes(context);
937 if (thisInnerClass->inner_class != 0) {
938 /* Make sure that inner_class really belongs to a CLASS */
939 getAscizFromClass(context, thisInnerClass->inner_class);
941 if (thisInnerClass->outer_class != 0) {
942 /* Make sure that outer_class really belongs to a CLASS */
943 getAscizFromClass(context, thisInnerClass->outer_class);
946 } else {
947 getNbytes(context, length, NULL);
953 /*=========================================================================
954 * FUNCTION: createFakeArrayClass
955 * OVERVIEW: Invoked by Locked_FindArrayClassFromClass() for creating
956 * a fake array class that has the specified fields.
958 * INTERFACE:
959 * parameters: char *: name
960 * int : base type
961 * int : depth (array dimension)
962 * ClassClass * : base type if T_CLASS
963 * struct Hjava_lang_ClassLoader *: class loader
965 * returns: ClassClass *
966 *=======================================================================*/
967 ClassClass *
968 createFakeArrayClass(char *name, /* name */
969 int base_type, /* base_type */
970 int depth, /* array dimension */
971 ClassClass *inner_cb, /* base type if T_CLASS */
972 struct Hjava_lang_ClassLoader *loader)
974 ClassClass *cb = allocClassClass();
975 Classjava_lang_Class *ucb = unhand(cb);
976 cp_item_type *constant_pool =
977 sysCalloc(CONSTANT_POOL_ARRAY_LENGTH,
978 (sizeof(cp_item_type) + sizeof(unsigned char)));
979 unsigned char *type_table = (unsigned char *)
980 (constant_pool + CONSTANT_POOL_ARRAY_LENGTH);
981 sysAssert(name[0] == SIGNATURE_ARRAY);
982 ucb->major_version = JAVA_VERSION;
983 ucb->minor_version = JAVA_MINOR_VERSION;
984 ucb->name = strdup(name);
985 ucb->super_name = JAVAPKG "Object";
986 ucb->constantpool = constant_pool;
987 ucb->constantpool_count = CONSTANT_POOL_ARRAY_LENGTH;
988 ucb->loader = loader;
990 constant_pool[CONSTANT_POOL_TYPE_TABLE_INDEX].type = type_table;
991 constant_pool[CONSTANT_POOL_ARRAY_DEPTH_INDEX].i = depth;
992 constant_pool[CONSTANT_POOL_ARRAY_TYPE_INDEX].i = base_type;
993 type_table[CONSTANT_POOL_ARRAY_DEPTH_INDEX] =
994 CONSTANT_Integer | CONSTANT_POOL_ENTRY_RESOLVED;
995 type_table[CONSTANT_POOL_ARRAY_TYPE_INDEX] =
996 CONSTANT_Integer | CONSTANT_POOL_ENTRY_RESOLVED;
998 if (base_type == T_CLASS) {
999 /* Initialize the appropriate fields of the constant pool */
1000 constant_pool[CONSTANT_POOL_ARRAY_CLASS_INDEX].clazz = inner_cb;
1001 type_table[CONSTANT_POOL_ARRAY_CLASS_INDEX] =
1002 CONSTANT_Class | CONSTANT_POOL_ENTRY_RESOLVED;
1003 /* The class is public iff its base class is public */
1004 ucb->access = ACC_FINAL | ACC_ABSTRACT |
1005 (cbAccess(inner_cb) & ACC_PUBLIC);
1006 } else {
1007 /* Set the class field to something innocuous */
1008 type_table[CONSTANT_POOL_ARRAY_CLASS_INDEX] =
1009 CONSTANT_Integer | CONSTANT_POOL_ENTRY_RESOLVED;
1010 ucb->access = ACC_FINAL | ACC_ABSTRACT | ACC_PUBLIC;
1012 AddBinClass(cb);
1013 return cb;
1017 /*=========================================================================
1018 * FUNCTION: createPrimitiveClass
1019 * OVERVIEW: Creates a class block to represent a primitive type.
1020 * NOTE: this is not added to the built-in class table, so
1021 * it should only be called once per primitive type.
1022 * See FindPrimitiveClass().
1024 * INTERFACE:
1025 * parameters: char *: name
1026 * char : sig
1027 * unsigned char: typecode
1028 * unsigned char: slotsize
1029 * unsigned char: elementsize
1031 * returns: ClassClass *
1032 *=======================================================================*/
1033 ClassClass *
1034 createPrimitiveClass(char *name, char sig, unsigned char typecode,
1035 unsigned char slotsize, unsigned char elementsize)
1037 ClassClass *cb = allocClassClass();
1038 Classjava_lang_Class *ucb = unhand(cb);
1040 ucb->major_version = JAVA_VERSION;
1041 ucb->minor_version = JAVA_MINOR_VERSION;
1042 ucb->name = strdup(name);
1043 ucb->super_name = JAVAPKG "Object";
1044 ucb->constantpool = NULL;
1045 ucb->constantpool_count = 0;
1046 ucb->loader = NULL;
1047 ucb->access = ACC_FINAL | ACC_ABSTRACT | ACC_PUBLIC;
1049 CCSet(cb, Primitive);
1050 cbTypeSig(cb) = sig;
1051 cbTypeCode(cb) = typecode;
1052 cbSlotSize(cb) = slotsize;
1053 cbElementSize(cb) = elementsize;
1054 MakeClassSticky(cb);
1056 return cb;
1060 /*=========================================================================
1061 * FUNCTION: LoadConstantPool
1062 * OVERVIEW: Loads the constant pool given a pointer to the internal
1063 * class file.
1065 * INTERFACE:
1066 * parameters: CICcontext *: ptr
1068 * returns: nothing
1069 *=======================================================================*/
1070 static void LoadConstantPool(CICcontext *context)
1072 ClassClass *cb = context->cb;
1073 int nconstants = get2bytes(context);
1074 cp_item_type *constant_pool;
1075 unsigned char *type_table;
1076 int i;
1077 Java8 t1;
1079 if (nconstants > 16384) {
1080 JAVA_ERROR(context, "Preverifier only "
1081 "handles constant pool size up to 16K");
1084 t1.x[0] = 0; /* shut off warning */
1085 if (nconstants < CONSTANT_POOL_UNUSED_INDEX) {
1086 JAVA_ERROR(context, "Illegal constant pool size");
1089 constant_pool = (cp_item_type *)
1090 allocNBytes(context, nconstants * sizeof(cp_item_type));
1091 type_table = allocNBytes(context, nconstants * sizeof(char));
1093 for (i = CONSTANT_POOL_UNUSED_INDEX; i < nconstants; i++) {
1094 int type = get1byte(context);
1095 CONSTANT_POOL_TYPE_TABLE_PUT(type_table, i, type);
1096 switch (type) {
1097 case CONSTANT_Utf8: {
1098 int length = get2bytes(context);
1099 char *result = allocNBytes(context, length + 1);
1100 getNbytes(context, length, result);
1101 result[length] = '\0';
1102 constant_pool[i].cp = result;
1103 CONSTANT_POOL_TYPE_TABLE_SET_RESOLVED(type_table, i);
1104 break;
1107 case CONSTANT_Class:
1108 case CONSTANT_String:
1109 constant_pool[i].i = get2bytes(context);
1110 break;
1112 case CONSTANT_Fieldref:
1113 case CONSTANT_Methodref:
1114 case CONSTANT_InterfaceMethodref:
1115 case CONSTANT_NameAndType:
1116 constant_pool[i].i = get4bytes(context);
1117 break;
1119 case CONSTANT_Float:
1120 if (no_floating_point) {
1121 panic("floating-point constants should not appear");
1124 case CONSTANT_Integer:
1125 constant_pool[i].i = get4bytes(context);
1126 CONSTANT_POOL_TYPE_TABLE_SET_RESOLVED(type_table, i);
1127 break;
1129 case CONSTANT_Double:
1130 if (no_floating_point) {
1131 panic("floating-point constants should not appear");
1133 case CONSTANT_Long: {
1134 /* We ignore endian problems, and just load the two
1135 * values. The verifier never actually cares what
1136 * the actual value is.
1137 */
1138 constant_pool[i].i = get4bytes(context);
1139 CONSTANT_POOL_TYPE_TABLE_SET_RESOLVED(type_table, i);
1140 i++;
1141 if (i >= nconstants) {
1142 JAVA_ERROR(context, "illegal constant pool entry");
1144 /* Indicate that the next object in the constant pool cannot
1145 * be accessed independently.
1146 */
1147 constant_pool[i].i = get4bytes(context);
1148 CONSTANT_POOL_TYPE_TABLE_PUT(type_table, i, 0);
1149 CONSTANT_POOL_TYPE_TABLE_SET_RESOLVED(type_table, i);
1150 break;
1153 default:
1154 JAVA_ERROR(context, "Illegal constant pool type");
1157 /* It is important to only set these after everything is setup,
1158 so that the GC sees a consistent state.*/
1159 cbConstantPool(cb) = constant_pool;
1160 cbConstantPoolCount(cb) = nconstants;
1161 constant_pool[CONSTANT_POOL_TYPE_TABLE_INDEX].type = type_table;
1165 /*=========================================================================
1166 * FUNCTION: ReadInCode
1167 * OVERVIEW: Reads the code attributes given a pointer to the internal
1168 * class file and a pointer to the method block structure.
1169 * This includes line number and local variable tables.
1171 * INTERFACE:
1172 * parameters: CICcontext *: ptr
1173 * struct methodblock *: mb
1175 * returns: nothing
1176 *=======================================================================*/
1177 static void ReadInCode(CICcontext *context, struct methodblock *mb)
1179 int attribute_length = get4bytes(context);
1180 unsigned char *end_ptr = context->ptr + attribute_length;
1181 int attribute_count;
1182 int code_length;
1183 int i;
1185 if (cbMinorVersion(context->cb) == JAVA_VERSION &&
1186 cbMinorVersion(context->cb) <= 2) {
1187 mb->maxstack = get1byte(context);
1188 mb->nlocals = get1byte(context);
1189 code_length = mb->code_length = get2bytes(context);
1190 } else {
1191 mb->maxstack = get2bytes(context);
1192 mb->nlocals = get2bytes(context);
1193 code_length = mb->code_length = get4bytes(context);
1195 if (mb->nlocals < mb->args_size)
1196 JAVA_ERROR(context, "Arguments can't fit into locals");
1198 if (code_length > 65535) {
1199 JAVA_ERROR(context, "Byte code size exceeds 65535 bytes");
1202 mb->code = allocNBytes(context, code_length);
1204 getNbytes(context, code_length, (char *)mb->code);
1205 if ((mb->exception_table_length = get2bytes(context)) > 0) {
1206 unsigned exception_table_size = mb->exception_table_length
1207 * sizeof(struct CatchFrame);
1208 mb->exception_table = allocNBytes(context, exception_table_size);
1209 for (i = 0; i < (int)mb->exception_table_length; i++) {
1210 mb->exception_table[i].start_pc = get2bytes(context);
1211 mb->exception_table[i].end_pc = get2bytes(context);
1212 mb->exception_table[i].handler_pc = get2bytes(context);
1213 mb->exception_table[i].catchType = get2bytes(context);
1214 mb->exception_table[i].compiled_CatchFrame = NULL;
1217 attribute_count = get2bytes(context);
1218 for (i = 0; i < attribute_count; i++) {
1219 char *name = getAsciz(context, FALSE);
1220 if (strcmp(name, "LineNumberTable") == 0) {
1221 ReadLineTable(context, mb);
1222 } else if (strcmp(name, "LocalVariableTable") == 0) {
1223 ReadLocalVars(context, mb);
1224 } else {
1225 int length = get4bytes(context);
1226 getNbytes(context, length, NULL);
1229 if (context->ptr != end_ptr)
1230 JAVA_ERROR(context, "Code segment was wrong length");
1234 /*=========================================================================
1235 * FUNCTION: ReadLineTable
1236 * OVERVIEW: Reads the line number table given a pointer to the internal
1237 * class file and a pointer to the method block structure.
1239 * INTERFACE:
1240 * parameters: CICcontext *: ptr
1241 * struct methodblock *: mb
1243 * returns: nothing
1244 *=======================================================================*/
1245 static void ReadLineTable(CICcontext *context, struct methodblock *mb)
1247 int attribute_length = get4bytes(context);
1248 unsigned char *end_ptr = context->ptr + attribute_length;
1249 int i;
1250 if ((mb->line_number_table_length = get2bytes(context)) > 0) {
1251 struct lineno *ln =
1252 allocNBytes(context, mb->line_number_table_length *
1253 sizeof(struct lineno));
1254 mb->line_number_table = ln;
1255 for (i = mb->line_number_table_length; --i >= 0; ln++) {
1256 ln->pc = get2bytes(context);
1257 ln->line_number = get2bytes(context);
1260 if (context->ptr != end_ptr)
1261 JAVA_ERROR(context, "Line number table was wrong length?");
1266 /*=========================================================================
1267 * FUNCTION: ReadLocalVars
1268 * OVERVIEW: Reads the localvar table given a pointer to the internal
1269 * class file and a pointer to the method block structure.
1271 * INTERFACE:
1272 * parameters: CICcontext *: ptr
1273 * struct methodblock *: mb
1275 * returns: nothing
1276 *=======================================================================*/
1277 static void ReadLocalVars(CICcontext *context, struct methodblock *mb)
1279 int attribute_length = get4bytes(context);
1280 unsigned char *end_ptr = context->ptr + attribute_length;
1281 int i;
1282 if ((mb->localvar_table_length = get2bytes(context)) > 0) {
1283 struct localvar *lv =
1284 allocNBytes(context, mb->localvar_table_length *
1285 sizeof(struct localvar));
1286 mb->localvar_table = lv;
1287 for (i = mb->localvar_table_length; --i >= 0; lv++) {
1288 lv->pc0 = get2bytes(context);
1289 lv->length = get2bytes(context);
1290 lv->name = getAsciz(context, FALSE);
1291 lv->signature = getAsciz(context, FALSE);
1292 lv->slot = get2bytes(context);
1295 if (context->ptr != end_ptr)
1296 JAVA_ERROR(context, "Local variables table was wrong length?");
1300 /*=========================================================================
1301 * FUNCTION: ReadExceptions
1302 * OVERVIEW: Reads the Exception attribute given a pointer to the internal
1303 * class file and a pointer to the method block structure.
1305 * INTERFACE:
1306 * parameters: CICcontext *: ptr
1307 * struct methodblock *: mb
1309 * returns: nothing
1310 *=======================================================================*/
1311 static void
1312 ReadExceptions(CICcontext *context, struct methodblock *mb)
1314 int attribute_length = get4bytes(context);
1315 unsigned char *end_ptr = context->ptr + attribute_length;
1316 unsigned short nexceptions = get2bytes(context);
1318 if ((mb->nexceptions = nexceptions) > 0) {
1319 unsigned short *ep, *exceptions =
1320 allocNBytes(context, nexceptions * sizeof (unsigned short));
1321 mb->exceptions = ep = exceptions;
1322 while (nexceptions-- > 0) {
1323 *ep++ = get2bytes(context);
1326 if (context->ptr != end_ptr)
1327 JAVA_ERROR(context, "Exceptions attribute has wrong length");
1331 /*=========================================================================
1332 * FUNCTION: Signature2ArgsSize
1333 * OVERVIEW: Returns the size of arguments given a pointer to a method
1334 * signature.
1336 * INTERFACE:
1337 * parameters: char*: method_signature
1339 * returns: unsigned
1340 *=======================================================================*/
1341 unsigned Signature2ArgsSize(char *method_signature)
1343 char *p;
1344 int args_size = 0;
1345 for (p = method_signature; *p != SIGNATURE_ENDFUNC; p++) {
1346 switch (*p) {
1347 case SIGNATURE_FLOAT:
1348 if (no_floating_point) {
1349 panic("floating-point arguments should not appear");
1352 case SIGNATURE_BOOLEAN:
1353 case SIGNATURE_BYTE:
1354 case SIGNATURE_CHAR:
1355 case SIGNATURE_SHORT:
1356 case SIGNATURE_INT:
1357 args_size += 1;
1358 break;
1360 case SIGNATURE_CLASS:
1361 args_size += 1;
1362 while (*p != SIGNATURE_ENDCLASS) p++;
1363 break;
1365 case SIGNATURE_ARRAY:
1366 args_size += 1;
1367 while ((*p == SIGNATURE_ARRAY)) p++;
1368 /* If an array of classes, skip over class name, too. */
1369 if (*p == SIGNATURE_CLASS) {
1370 while (*p != SIGNATURE_ENDCLASS)
1371 p++;
1373 break;
1375 case SIGNATURE_DOUBLE:
1376 if (no_floating_point) {
1377 panic("floating-point arguments should not appear");
1380 case SIGNATURE_LONG:
1381 args_size += 2;
1382 break;
1384 case SIGNATURE_FUNC: /* ignore initial (, if given */
1385 break;
1387 default: /* Indicates an error. */
1388 return 0;
1391 return args_size;
1395 /*=========================================================================
1396 * FUNCTION: free_clinit_memory
1397 * OVERVIEW: Frees clinit memory.
1399 * INTERFACE:
1400 * parameters: struct methodblock *: mb
1402 * returns: nothing
1403 *=======================================================================*/
1404 void free_clinit_memory(struct methodblock *mb)
1406 /* This function is somewhat a hack. It fixes the problem in 1.1.3
1407 * and before. sysFree may be called on the wrong memory block if
1408 * the exception attribute comes before the code attribute.
1409 */
1410 /* If there is no exceptions attribute, or if both have already
1411 * been freed.
1412 */
1413 if (mb->exceptions == NULL) {
1414 if (mb->code) {
1415 sysFree(mb->code);
1416 mb->code = NULL;
1418 return;
1421 /* If both attributes exist, free the one at the lower address */
1422 if ((char *)mb->code < (char *)mb->exceptions)
1423 sysFree(mb->code);
1424 else
1425 sysFree(mb->exceptions);
1427 mb->code = NULL;
1428 mb->exceptions = NULL;
1432 /*=========================================================================
1433 * FUNCTION: FreeClass
1434 * OVERVIEW: Frees class.
1436 * INTERFACE:
1437 * parameters: ClassClass *: cb
1439 * returns: nothing
1440 *=======================================================================*/
1441 void FreeClass(ClassClass *cb)
1443 int i;
1444 struct methodblock *mb;
1446 for (i = cbMethodsCount(cb), mb = cbMethods(cb); --i >= 0; mb++) {
1447 if (strcmp(mb->fb.name, "<clinit>") == 0 &&
1448 strcmp(mb->fb.signature, "()V") == 0 &&
1449 mb->code_length /* not external */ )
1450 free_clinit_memory(mb);
1453 sysFree(cbConstantPool(cb));
1455 sysFree(cbMethodTableMem(cb));
1456 sysFree(cbSlotTable(cb));
1458 /* Interface method tables can be shared between child and
1459 * super classes.
1460 */
1461 if (cbImplementsCount(cb) != 0 || cbIsInterface(cb))
1462 sysFree(cbIntfMethodTable(cb));
1466 /*=========================================================================
1467 * FUNCTION: get1byte
1468 * OVERVIEW: Gets one byte from the class file.
1470 * INTERFACE:
1471 * parameters: CICcontext *: context
1473 * returns: value read or 0 if an error occurred.
1474 *=======================================================================*/
1475 static unsigned char get1byte(CICcontext *context)
1477 unsigned char *ptr = context->ptr;
1478 if (context->end_ptr - ptr < 1) {
1479 JAVA_ERROR(context, "Truncated class file");
1480 return 0;
1481 } else {
1482 unsigned char *ptr = context->ptr;
1483 unsigned char value = ptr[0];
1484 (context->ptr) += 1;
1485 return value;
1490 /*=========================================================================
1491 * FUNCTION: get2bytes
1492 * OVERVIEW: Gets two bytes from the class file.
1494 * INTERFACE:
1495 * parameters: CICcontext *: context
1497 * returns: value read or 0 if an error occurred.
1498 *=======================================================================*/
1499 static unsigned short get2bytes(CICcontext *context)
1501 unsigned char *ptr = context->ptr;
1502 if (context->end_ptr - ptr < 2) {
1503 JAVA_ERROR(context, "Truncated class file");
1504 return 0;
1505 } else {
1506 unsigned short value = (ptr[0] << 8) + ptr[1];
1507 (context->ptr) += 2;
1508 return value;
1513 /*=========================================================================
1514 * FUNCTION: get4bytes
1515 * OVERVIEW: Gets four bytes from the class file.
1517 * INTERFACE:
1518 * parameters: CICcontext *: context
1520 * returns: value read or 0 if an error occurred.
1521 *=======================================================================*/
1522 static unsigned long get4bytes(CICcontext *context)
1524 unsigned char *ptr = context->ptr;
1525 if (context->end_ptr - ptr < 4) {
1526 JAVA_ERROR(context, "Truncated class file");
1527 return 0;
1528 } else {
1529 unsigned long value = (ptr[0] << 24) + (ptr[1] << 16) +
1530 (ptr[2] << 8) + ptr[3];
1531 (context->ptr) += 4;
1532 return value;
1537 /*=========================================================================
1538 * FUNCTION: getNbytes
1539 * OVERVIEW: Gets N bytes from the class file specified by the count
1540 * parameter. If buffer is not null, it will also copy the
1541 * count number of bytes read into the buffer as well.
1542 * Note that this function seems to be always invoked with
1543 * a NULL argument for the buffer, except when it loads the
1544 * UTF8 entry from the constant pool and when the code
1545 * attribute is loaded.
1547 * INTERFACE:
1548 * parameters: CICcontext *: context
1549 * int: count
1550 * char *: buffer
1552 * returns: nothing
1553 *=======================================================================*/
1554 static void getNbytes(CICcontext *context, int count, char *buffer)
1556 unsigned char *ptr = context->ptr;
1557 if (context->end_ptr - ptr < count)
1558 JAVA_ERROR(context, "Truncated class file");
1559 if (buffer != NULL)
1560 memcpy(buffer, ptr, count);
1561 (context->ptr) += count;
1565 /*=========================================================================
1566 * FUNCTION: getAsciz
1567 * OVERVIEW: Reads the next two bytes and uses this value to look up for
1568 * the corresponding constant pool entry.
1569 * Returns null if the value is 0 and zeroOkay flag is set.
1571 * INTERFACE:
1572 * parameters: CICcontext *: context
1573 * bool_t : zeroOkay
1575 * returns: char * or NULL
1576 *=======================================================================*/
1577 static char *getAsciz(CICcontext *context, bool_t zeroOkay)
1579 ClassClass *cb = context->cb;
1580 union cp_item_type *constant_pool = cbConstantPool(cb);
1581 int nconstants = cbConstantPoolCount(cb);
1582 unsigned char *type_table =
1583 constant_pool[CONSTANT_POOL_TYPE_TABLE_INDEX].type;
1585 int value = get2bytes(context);
1586 if (value == 0 && zeroOkay) {
1587 return NULL;
1588 } else if ((value == 0) || (value >= nconstants) ||
1589 type_table[value] != (CONSTANT_Utf8 | CONSTANT_POOL_ENTRY_RESOLVED))
1590 JAVA_ERROR(context, "Illegal constant pool index");
1591 return constant_pool[value].cp;
1595 /*=========================================================================
1596 * FUNCTION: getAscizFromClass
1597 * OVERVIEW: Given the constant pool index, returns the name of the class
1598 * which corresponds to this constant pool entry.
1600 * INTERFACE:
1601 * parameters: CICcontext *: context
1602 * int: value
1604 * returns: char * or NULL
1605 *=======================================================================*/
1606 static char *getAscizFromClass(CICcontext *context, int value)
1608 ClassClass *cb = context->cb;
1609 union cp_item_type *constant_pool = cbConstantPool(cb);
1610 int nconstants = cbConstantPoolCount(cb);
1611 unsigned char *type_table =
1612 constant_pool[CONSTANT_POOL_TYPE_TABLE_INDEX].type;
1613 if ((value > 0) && (value < nconstants)) {
1614 if (type_table[value] == CONSTANT_Class) {
1615 value = constant_pool[value].i;
1616 if ((value <= 0) || (value >= nconstants) ||
1617 (type_table[value] != (CONSTANT_Utf8 |
1618 CONSTANT_POOL_ENTRY_RESOLVED)))
1619 JAVA_ERROR(context, "Illegal constant pool index");
1620 return constant_pool[value].cp;
1621 } else if (type_table[value] == (CONSTANT_Class |
1622 CONSTANT_POOL_ENTRY_RESOLVED)) {
1623 ClassClass *cb = constant_pool[value].clazz;
1624 return cbName(cb);
1625 } else {
1626 JAVA_ERROR(context, "Illegal constant pool index");
1628 } else {
1629 JAVA_ERROR(context, "Illegal constant pool index");
1631 return NULL; /* not reached */
1634 /* In order to avoid possible alignment errors, round up all sizes to
1635 * multiples of eight.
1636 */
1637 #define ROUNDUP_SIZE(s) while ((s) % 8 != 0) (s)++
1640 /*=========================================================================
1641 * FUNCTION: allocNBytes
1642 * OVERVIEW: Memory allocation function for internal class file
1643 * structures.
1644 * It calculates the number of allocations needed for the
1645 * two passes, and the allocations required for the clinit
1646 * method.
1648 * INTERFACE:
1649 * parameters: CICcontext *: context
1650 * int : size
1652 * returns: void *
1653 *=======================================================================*/
1654 static void *allocNBytes(CICcontext *context, int size)
1656 void *result;
1657 if (context->pass == 1) {
1658 /* The first pass
1659 * A more sophisticated scheme could reduce the number of mallocs.
1660 */
1661 CICmallocs *mallocs =
1662 (CICmallocs *)sysCalloc(1, sizeof(CICmallocs) + size);
1663 if (mallocs == 0)
1664 JAVA_ERROR(context, "out of memory");
1665 result = (void *)(mallocs + 1);
1666 mallocs->next = context->pass1.mallocs;
1667 ROUNDUP_SIZE(size);
1668 if (context->in_clinit)
1669 context->clinit_size += size;
1670 else
1671 context->malloc_size += size;
1672 context->pass1.mallocs = mallocs;
1673 } else {
1674 /* The second pass */
1676 ROUNDUP_SIZE(size);
1678 #define ALLOC_BLOCK(ptr,buf,sizelimit) \
1679 result = (ptr); \
1680 (ptr) += (size); \
1681 sysAssert((ptr) <= (buf) + (sizelimit))
1683 if (context->in_clinit) {
1684 /* Make sure that this clinit pointer is not null */
1685 sysAssert(context->pass2.clinit_ptr != NULL);
1687 ALLOC_BLOCK(context->pass2.clinit_ptr,
1688 context->pass2.clinit_buffer,
1689 context->clinit_size*sizeof(char));
1691 } else {
1693 /* Make sure that this malloc pointer is not null */
1694 sysAssert(context->pass2.malloc_ptr != NULL);
1696 ALLOC_BLOCK(context->pass2.malloc_ptr,
1697 context->pass2.malloc_buffer,
1698 context->malloc_size);
1701 return result;
1705 /*=========================================================================
1706 * FUNCTION: freeBuffers
1707 * OVERVIEW: Frees buffers allocated by allocNBytes().
1709 * INTERFACE:
1710 * parameters: CICcontext *: context
1712 * returns: nothing
1713 *=======================================================================*/
1714 static void freeBuffers(CICcontext * context)
1716 if (context->pass == 1) {
1717 CICmallocs *mallocs = context->pass1.mallocs;
1719 while (mallocs) {
1720 CICmallocs *tmp = mallocs;
1721 mallocs = mallocs->next;
1722 if (tmp != NULL) {
1723 sysFree(tmp);
1726 context->pass1.mallocs = 0;
1727 } else { /* context->pass = 2 */
1729 /* Note: this code is here just for historical reasons. Actually, these
1730 * buffers cannot really be freed here since the data in them is still
1731 * pointed to by the class buffer (cb) and we are not yet done loading
1732 * the class. If the class loading fails, FreeClass() will free the method
1733 * blocks and the clinit memory.
1734 */
1735 if (context->pass2.malloc_buffer != NULL) {
1736 sysFree(context->pass2.malloc_buffer);
1737 /* Reset only if buffer was freed */
1738 context->pass2.malloc_buffer = 0;
1741 if (context->pass2.clinit_buffer != NULL) {
1742 sysFree(context->pass2.clinit_buffer);
1743 /* Initialize only if buffer was freed */
1744 context->pass2.clinit_buffer = 0;
1750 /*=========================================================================
1751 * FUNCTION: GetClassConstantClassName
1752 * OVERVIEW: Returns class name corresponding to the constant pool entry
1753 * for the given cpIndex. This is desirable in cases when we
1754 * may simply be interested in the name of the class, but may
1755 * not necessarily want to resolve the class reference if it
1756 * isn't already.
1758 * INTERFACE:
1759 * parameters: cp_item_type *: constant pool
1760 * int : index
1762 * returns: char *: class name
1763 *=======================================================================*/
1764 char *GetClassConstantClassName(cp_item_type *constant_pool, int index)
1766 unsigned char *type_table =
1767 constant_pool[CONSTANT_POOL_TYPE_TABLE_INDEX].type;
1768 switch(type_table[index]) {
1769 case CONSTANT_Class | CONSTANT_POOL_ENTRY_RESOLVED: {
1770 ClassClass *cb = constant_pool[index].clazz;
1771 return cbName(cb);
1774 case CONSTANT_Class: {
1775 int name_index = constant_pool[index].i;
1776 return constant_pool[name_index].cp;
1779 default:
1780 return (char *)0;