From: Robert Pengelly Date: Fri, 26 Sep 2025 19:11:06 +0000 (+0100) Subject: Initial commit X-Git-Url: https://git.candlhat.org/?a=commitdiff_plain;h=bc88c9c62ee3bacf9ae32675cb468791182d45bd;p=lightjvm.git Initial commit --- bc88c9c62ee3bacf9ae32675cb468791182d45bd diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fdddb29 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/Makefile.unix b/Makefile.unix new file mode 100644 index 0000000..36fb29f --- /dev/null +++ b/Makefile.unix @@ -0,0 +1,28 @@ +#****************************************************************************** +# @file Makefile.unix +#****************************************************************************** +SRCDIR ?= $(CURDIR) + +CC := gcc +CFLAGS := -D_FILE_OFFSET_BITS=64 -Wall -Werror -Wextra -std=c90 + +CSRC := $(shell find $(SRCDIR) -type f -name '*.c') + +ifeq ($(OS), Windows_NT) +all: lightjvm.exe + +lightjvm.exe: $(CSRC) + + $(CC) $(CFLAGS) -o $@ $^ +else +all: lightjvm + +lightjvm: $(CSRC) + + $(CC) $(CFLAGS) -o $@ $^ +endif + +clean: + + if [ -f lightjvm.exe ]; then rm -rf lightjvm.exe; fi + if [ -f lightjvm ]; then rm -rf lightjvm; fi diff --git a/Makefile.w32 b/Makefile.w32 new file mode 100644 index 0000000..582d6c8 --- /dev/null +++ b/Makefile.w32 @@ -0,0 +1,19 @@ +#****************************************************************************** +# @file Makefile.w32 +#****************************************************************************** +SRCDIR ?= $(CURDIR) + +CC := gcc +CFLAGS := -D_FILE_OFFSET_BITS=64 -Wall -Werror -Wextra -std=c90 + +CSRC := $(subst \,/,$(shell dir /s /b "$(SRCDIR)\\*.c")) + +all: lightjvm.exe + +clean: + + if exist lightjvm.exe ( del /q lightjvm.exe ) + if exist lightjvm ( del /q lightjvm ) + +lightjvm.exe: $(CSRC) + $(CC) $(CFLAGS) -o $@ $^ diff --git a/README.md b/README.md new file mode 100644 index 0000000..7ffb46d --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +All source code is Public Domain. + +## Obtain the source code + + git clone https://git.candlhat.org/lightjvm.git + +## Building + + BSD: + + Make sure you have gcc and gmake installed then run gmake -f Makefile.unix. + + Linux: + + Make sure you have gcc and make installed then run make -f Makefile.unix. + + macOS: + + Make sure you have xcode command line tools installed then run make -f Makefile.unix. + + Windows: + + Make sure you have mingw installed and the location within your PATH variable then run mingw32-make.exe -f Makefile.w32. diff --git a/class.c b/class.c new file mode 100644 index 0000000..7b2c15a --- /dev/null +++ b/class.c @@ -0,0 +1,352 @@ +/****************************************************************************** + * @file class.c + *****************************************************************************/ +#include +#include +#include + +#include "class.h" +#include "constant.h" +#include "hashtab.h" +#include "jvm.h" +#include "lib.h" +#include "method.h" +#include "report.h" + +static struct hashtab hashtab_class_names = { 0 }; + +struct java_class *parse_java_class (const char *class_name) { + + unsigned long magic; + long i; + + struct java_class *java_class; + struct hashtab_name *key; + + FILE *fp = 0; + + struct class_file_format *cff; + char *path; + + struct vector *method_pool; + void *constant_pool; + + if ((key = hashtab_get_key (&hashtab_class_names, class_name))) { + return hashtab_get (&hashtab_class_names, key); + } + + path = xmalloc (strlen (class_name) + 7); + sprintf (path, "%s.class", class_name); + + if (!(fp = fopen (path, "r+b"))) { + + free (path); + + for (i = 0; i < state->nb_class_paths; i++) { + + path = xmalloc (strlen (state->class_paths[i]) + 1 + strlen (class_name) + 7); +#if defined (unix) || defined (__unix) || defined (__unix__) || defined (__APPLE__) + sprintf (path, "%s/%s.class", state->class_paths[i], class_name); +#elif defined (_WIN32) + sprintf (path, "%s\\%s.class", state->class_paths[i], class_name); +#endif + + if (!(fp = fopen (path, "r+b"))) { + + free (path); + continue; + + } + + break; + + } + + } + + if (!fp) { + + report_at (program_name, 0, REPORT_ERROR, "failed to open class '%s'", class_name); + return 0; + + } + + if (!(java_class = malloc (sizeof (*java_class)))) { + + report_at (program_name, 0, REPORT_ERROR, "not enough memory for the java class"); + + free (path); + fclose (fp); + + return 0; + + } + + cff = &java_class->cff; + + if (fread (cff->magic_number, 1, 4, fp) != 4) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path); + + free (java_class); + free (path); + + fclose (fp); + return 0; + + } + + if (((magic = array_to_integer (cff->magic_number, 4, 1))) != 0xCAFEBABE) { + + report_at (program_name, 0, REPORT_ERROR, "%s is not a valid .class (%04x)", path, magic); + + free (java_class); + free (path); + + fclose (fp); + return 0; + + } + + if (fread (cff->minor_version, 1, 2, fp) != 2) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path); + + free (java_class); + free (path); + + fclose (fp); + return 0; + + } + + if (fread (cff->major_version, 1, 2, fp) != 2) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path); + + free (java_class); + free (path); + + fclose (fp); + return 0; + + } + + if (array_to_integer (cff->major_version, 2, 1) > 52) { + + report_at (program_name, 0, REPORT_ERROR, "currently only up to Java 8 works"); + + free (java_class); + free (path); + + fclose (fp); + return 0; + + } + + if (fread (cff->constant_pool_count, 1, 2, fp) != 2) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path); + + free (java_class); + free (path); + + fclose (fp); + return 0; + + } + + if (!(constant_pool = parse_constant_pool (fp, array_to_integer (cff->constant_pool_count, 2, 1)))) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path); + + free (java_class); + free (path); + + fclose (fp); + return 0; + + } + + if (fread (cff->access_flags, 1, 2, fp) != 2) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path); + + free_constant_pool (constant_pool); + free (constant_pool); + + free (java_class); + free (path); + + fclose (fp); + return 0; + + } + + if (fread (cff->this_class, 1, 2, fp) != 2) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path); + + free_constant_pool (constant_pool); + free (constant_pool); + + free (java_class); + free (path); + + fclose (fp); + return 0; + + } + + if (fread (cff->super_class, 1, 2, fp) != 2) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path); + + free_constant_pool (constant_pool); + free (constant_pool); + + free (java_class); + free (path); + + fclose (fp); + return 0; + + } + + if (fread (cff->interface_count, 1, 2, fp) != 2) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path); + + free_constant_pool (constant_pool); + free (constant_pool); + + free (java_class); + free (path); + + fclose (fp); + return 0; + + } + + if (parse_interface_pool (fp, array_to_integer (cff->interface_count, 2, 1))) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path); + + free_constant_pool (constant_pool); + free (constant_pool); + + free (java_class); + free (path); + + fclose (fp); + return 0; + + } + + if (fread (cff->fields_count, 1, 2, fp) != 2) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path); + + free_constant_pool (constant_pool); + free (constant_pool); + + free (java_class); + free (path); + + fclose (fp); + return 0; + + } + + if (parse_field_pool (fp, array_to_integer (cff->fields_count, 2, 1))) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path); + + free_constant_pool (constant_pool); + free (constant_pool); + + free (java_class); + free (path); + + fclose (fp); + return 0; + + } + + if (fread (cff->methods_count, 1, 2, fp) != 2) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path); + + free_constant_pool (constant_pool); + free (constant_pool); + + free (java_class); + free (path); + + fclose (fp); + return 0; + + } + + if (!(method_pool = parse_method_pool (fp, array_to_integer (cff->methods_count, 2, 1)))) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", path); + + free_constant_pool (constant_pool); + free (constant_pool); + + free (java_class); + free (path); + + fclose (fp); + return 0; + + } + + free (path); + fclose (fp); + + java_class->class_name = xstrdup (class_name); + + java_class->constant_pool = constant_pool; + java_class->method_pool = method_pool; + + if ((key = hashtab_alloc_name (class_name))) { + hashtab_put (&hashtab_class_names, key, java_class); + } + + return java_class; + +} + +void free_classes (void) { + + struct hashtab_entry *entry; + struct java_class *class; + + int i; + + for (i = 0; i < hashtab_class_names.capacity; i++) { + + if ((entry = &hashtab_class_names.entries[i])) { + + if (entry->key && entry->value) { + + class = entry->value; + + free_constant_pool (class->constant_pool); + free (class->constant_pool); + + free_method_pool (class->method_pool); + free (class->method_pool); + + free (class); + hashtab_remove (&hashtab_class_names, entry->key); + + } + + } + + } + +} diff --git a/class.h b/class.h new file mode 100644 index 0000000..14a5010 --- /dev/null +++ b/class.h @@ -0,0 +1,43 @@ +/****************************************************************************** + * @file class.h + *****************************************************************************/ +#ifndef _CLASS_H +#define _CLASS_H + +struct class_file_format { + + unsigned char magic_number[4]; + + unsigned char minor_version[2]; + unsigned char major_version[2]; + + unsigned char constant_pool_count[2]; + unsigned char access_flags[2]; + + unsigned char this_class[2]; + unsigned char super_class[2]; + + unsigned char interface_count[2]; + unsigned char fields_count[2]; + unsigned char methods_count[2]; + unsigned char attributes_count[2]; + +}; + +#include "constant.h" +#include "vector.h" + +struct java_class { + + const char *class_name; + struct class_file_format cff; + + struct constant_pool *constant_pool; + struct vector *method_pool; + +}; + +struct java_class *parse_java_class (const char *class_name); +void free_classes (void); + +#endif /* _CLASS_H */ diff --git a/constant.c b/constant.c new file mode 100644 index 0000000..af574aa --- /dev/null +++ b/constant.c @@ -0,0 +1,795 @@ +/****************************************************************************** + * @file java_constant_pool_parser.c + *****************************************************************************/ +#include +#include +#include + +#include "constant.h" +#include "jvm.h" +#include "lib.h" +#include "report.h" +#include "vector.h" + +#define CONSTANT_UTF8 1 +#define CONSTANT_INTEGER 3 +#define CONSTANT_FLOAT 4 +#define CONSTANT_LONG 5 +#define CONSTANT_DOUBLE 6 +#define CONSTANT_CLASS 7 +#define CONSTANT_STRING_REF 8 +#define CONSTANT_FIELD_REF 9 +#define CONSTANT_METHOD_REF 10 +#define CONSTANT_INTERFACE_REF 11 +#define CONSTANT_NAME_AND_TYPE 12 +#define CONSTANT_METHOD_HANDLER 15 +#define CONSTANT_INVOKE_DYNAMIC 18 + +static const int tag_additional_byte_size[13] = { 0, 2, 0, 4, 4, 8, 8, 2, 2, 4, 4, 4, 4 }; + +/* Parse UTF-8 String. */ +static int parse_string (FILE *fp, struct vector *constant_pool, int index) { + + struct constant_utf8 *ptr; + + if (!(ptr = malloc (sizeof (*ptr)))) { + return -1; + } + + ptr->tag = CONSTANT_UTF8; + ptr->index = index; + + if (fread (ptr->string_size, 1, 2, fp) != 2) { + + free (ptr); + return -1; + + } + + ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_UTF8] + array_to_integer (ptr->string_size, 2, 1); + + if (!(ptr->ptr = malloc (array_to_integer (ptr->string_size, 2, 1) + 1))) { + + free (ptr); + return -1; + + } + + memset (ptr->ptr, 0, array_to_integer (ptr->string_size, 2, 1)); + + if (fread (ptr->ptr, 1, array_to_integer (ptr->string_size, 2, 1), fp) != array_to_integer (ptr->string_size, 2, 1)) { + + free (ptr->ptr); + free (ptr); + + return -1; + + } + + vec_push (constant_pool, ptr); + return 0; + +} + +static int parse_integer (FILE *fp, struct vector *constant_pool, int index) { + + struct constant_integer *ptr; + + if (!(ptr = malloc (sizeof (*ptr)))) { + return -1; + } + + ptr->tag = CONSTANT_INTEGER; + ptr->index = index; + + if (fread (ptr->value, 1, 4, fp) != 4) { + + free (ptr); + return -1; + + } + + ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_INTEGER]; + vec_push (constant_pool, ptr); + + return 0; + +} + +static int parse_float (FILE *fp, struct vector *constant_pool, int index) { + + struct constant_float *ptr; + + if (!(ptr = malloc (sizeof (*ptr)))) { + return -1; + } + + ptr->tag = CONSTANT_FLOAT; + ptr->index = index; + + if (fread (ptr->value, 1, 4, fp) != 4) { + + free (ptr); + return -1; + + } + + ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_FLOAT]; + vec_push (constant_pool, ptr); + + return 0; + +} + +static int parse_long (FILE *fp, struct vector *constant_pool, int index) { + + struct constant_long *ptr; + + if (!(ptr = malloc (sizeof (*ptr)))) { + return -1; + } + + ptr->tag = CONSTANT_LONG; + ptr->index = index; + + if (fread (ptr->value, 1, 8, fp) != 8) { + + free (ptr); + return -1; + + } + + ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_LONG]; + vec_push (constant_pool, ptr); + + return 0; + +} + +static int parse_double (FILE *fp, struct vector *constant_pool, int index) { + + struct constant_double *ptr; + + if (!(ptr = malloc (sizeof (*ptr)))) { + return -1; + } + + ptr->tag = CONSTANT_DOUBLE; + ptr->index = index; + + if (fread (ptr->value, 1, 8, fp) != 8) { + + free (ptr); + return -1; + + } + + ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_DOUBLE]; + vec_push (constant_pool, ptr); + + return 0; + +} + +static int parse_class_ref (FILE *fp, struct vector *constant_pool, int index) { + + struct constant_class_ref *ptr; + + if (!(ptr = malloc (sizeof (*ptr)))) { + return -1; + } + + ptr->tag = CONSTANT_CLASS; + ptr->index = index; + + if (fread (ptr->string_index, 1, 2, fp) != 2) { + + free (ptr); + return -1; + + } + + ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_CLASS]; + vec_push (constant_pool, ptr); + + return 0; + +} + +static int parse_string_ref (FILE *fp, struct vector *constant_pool, int index) { + + struct constant_string_ref *ptr; + + if (!(ptr = malloc (sizeof (*ptr)))) { + return -1; + } + + ptr->tag = CONSTANT_STRING_REF; + ptr->index = index; + + if (fread (ptr->string_index, 1, 2, fp) != 2) { + + free (ptr); + return -1; + + } + + ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_STRING_REF]; + vec_push (constant_pool, ptr); + + return 0; + +} + +static int parse_field_ref (FILE *fp, struct vector *constant_pool, int index) { + + struct constant_field_ref *ptr; + + if (!(ptr = malloc (sizeof (*ptr)))) { + return -1; + } + + ptr->tag = CONSTANT_FIELD_REF; + ptr->index = index; + + if (fread (ptr->class_index, 1, 2, fp) != 2) { + + free (ptr); + return -1; + + } + + ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_FIELD_REF]; + + if (fread (ptr->nat_index, 1, 2, fp) != 2) { + + free (ptr); + return -1; + + } + + vec_push (constant_pool, ptr); + return 0; + +} + +static int parse_method_ref (FILE *fp, struct vector *constant_pool, int index) { + + struct constant_method_ref *ptr; + + if (!(ptr = malloc (sizeof (*ptr)))) { + return -1; + } + + ptr->tag = CONSTANT_METHOD_REF; + ptr->index = index; + + if (fread (ptr->class_index, 1, 2, fp) != 2) { + + free (ptr); + return -1; + + } + + ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_METHOD_REF]; + + if (fread (ptr->nat_index, 1, 2, fp) != 2) { + + free (ptr); + return -1; + + } + + vec_push (constant_pool, ptr); + return 0; + +} + +static int parse_interface_ref (FILE *fp, struct vector *constant_pool, int index) { + + struct constant_interface_ref *ptr; + + if (!(ptr = malloc (sizeof (*ptr)))) { + return -1; + } + + ptr->tag = CONSTANT_INTERFACE_REF; + ptr->index = index; + + if (fread (ptr->class_index, 1, 2, fp) != 2) { + + free (ptr); + return -1; + + } + + ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_INTERFACE_REF]; + + if (fread (ptr->nat_index, 1, 2, fp) != 2) { + + free (ptr); + return -1; + + } + + vec_push (constant_pool, ptr); + return 0; + +} + +static int parse_name_and_type (FILE *fp, struct vector *constant_pool, int index) { + + struct constant_nat *ptr; + + if (!(ptr = malloc (sizeof (*ptr)))) { + return -1; + } + + ptr->tag = CONSTANT_NAME_AND_TYPE; + ptr->index = index; + + if (fread (ptr->name_index, 1, 2, fp) != 2) { + + free (ptr); + return -1; + + } + + ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_NAME_AND_TYPE]; + + if (fread (ptr->type_index, 1, 2, fp) != 2) { + + free (ptr); + return -1; + + } + + vec_push (constant_pool, ptr); + return 0; + +} + +static int parse_method_handler (FILE *fp, struct vector *constant_pool, int index) { + + struct constant_method_handler *ptr; + + if (!(ptr = malloc (sizeof (*ptr)))) { + return -1; + } + + ptr->tag = CONSTANT_METHOD_HANDLER; + ptr->index = index; + + if (fread (&ptr->reference_kind, 1, 1, fp) != 1) { + + free (ptr); + return -1; + + } + + /*ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_INTERFACE_REF];*/ + + if (fread (ptr->reference_index, 1, 2, fp) != 2) { + + free (ptr); + return -1; + + } + + vec_push (constant_pool, ptr); + return 0; + +} + +static int parse_invoke_dynamic (FILE *fp, struct vector *constant_pool, int index) { + + struct constant_invoke_dynamic *ptr; + + if (!(ptr = malloc (sizeof (*ptr)))) { + return -1; + } + + ptr->tag = CONSTANT_INVOKE_DYNAMIC; + ptr->index = index; + + if (fread (ptr->bootstrap_method_attr_index, 1, 2, fp) != 2) { + + free (ptr); + return -1; + + } + + /*ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_INTERFACE_REF];*/ + + if (fread (ptr->nat_index, 1, 2, fp) != 2) { + + free (ptr); + return -1; + + } + + vec_push (constant_pool, ptr); + return 0; + +} + +struct constant_pool *parse_constant_pool (FILE *fp, int count) { + + struct constant_pool *constant_pool; + + unsigned char tag = 0; + int ret, i; + + if (!(constant_pool = malloc (sizeof (*constant_pool)))) { + return 0; + } + + memset (constant_pool, 0, sizeof (*constant_pool)); + + for (i = 1; i < count; i++) { + + fread (&tag, 1, 1, fp); + + switch (tag) { + + case CONSTANT_UTF8: + + ret = parse_string (fp, &constant_pool->vec_strings, i); + break; + + case CONSTANT_INTEGER: + + ret = parse_integer (fp, &constant_pool->vec_integers, i); + break; + + case CONSTANT_FLOAT: + + ret = parse_float (fp, &constant_pool->vec_floats, i); + break; + + case CONSTANT_LONG: + + ret = parse_long (fp, &constant_pool->vec_longs, i); + + i++; + break; + + case CONSTANT_DOUBLE: + + ret = parse_double (fp, &constant_pool->vec_doubles, i); + + i++; + break; + + case CONSTANT_STRING_REF: + + ret = parse_string_ref (fp, &constant_pool->vec_string_refs, i); + break; + + case CONSTANT_CLASS: + + ret = parse_class_ref (fp, &constant_pool->vec_class_refs, i); + break; + + case CONSTANT_FIELD_REF: + + ret = parse_field_ref (fp, &constant_pool->vec_field_refs, i); + break; + + case CONSTANT_METHOD_REF: + + ret = parse_method_ref (fp, &constant_pool->vec_method_refs, i); + break; + + case CONSTANT_INTERFACE_REF: + + ret = parse_interface_ref (fp, &constant_pool->vec_interface_refs, i); + break; + + case CONSTANT_NAME_AND_TYPE: + + ret = parse_name_and_type (fp, &constant_pool->vec_nats, i); + break; + + case CONSTANT_METHOD_HANDLER: + + ret = parse_method_handler (fp, &constant_pool->vec_method_handlers, i); + break; + + case CONSTANT_INVOKE_DYNAMIC: + + ret = parse_invoke_dynamic (fp, &constant_pool->vec_invoke_dynamic, i); + break; + + default: + + report_at (program_name, 0, REPORT_ERROR, "unknown tag = 0x%02x", tag); + + free_constant_pool (constant_pool); + free (constant_pool); + + return 0; + + } + + if (ret) { + + free_constant_pool (constant_pool); + free (constant_pool); + + return 0; + + } + + } + + return constant_pool; + +} + +void free_constant_pool (struct constant_pool *constant_pool) { + + struct constant_utf8 *ptr; + int i; + + for (i = 0; i < constant_pool->vec_strings.length; i++) { + + if ((ptr = constant_pool->vec_strings.data[i])) { + + free (ptr->ptr); + free (ptr); + + } + + } + + for (i = 0; i < constant_pool->vec_integers.length; i++) { + free (constant_pool->vec_integers.data[i]); + } + + for (i = 0; i < constant_pool->vec_floats.length; i++) { + free (constant_pool->vec_floats.data[i]); + } + + for (i = 0; i < constant_pool->vec_longs.length; i++) { + free (constant_pool->vec_longs.data[i]); + } + + for (i = 0; i < constant_pool->vec_doubles.length; i++) { + free (constant_pool->vec_doubles.data[i]); + } + + for (i = 0; i < constant_pool->vec_class_refs.length; i++) { + free (constant_pool->vec_class_refs.data[i]); + } + + for (i = 0; i < constant_pool->vec_string_refs.length; i++) { + free (constant_pool->vec_string_refs.data[i]); + } + + for (i = 0; i < constant_pool->vec_field_refs.length; i++) { + free (constant_pool->vec_field_refs.data[i]); + } + + for (i = 0; i < constant_pool->vec_method_refs.length; i++) { + free (constant_pool->vec_method_refs.data[i]); + } + + for (i = 0; i < constant_pool->vec_interface_refs.length; i++) { + free (constant_pool->vec_interface_refs.data[i]); + } + + for (i = 0; i < constant_pool->vec_nats.length; i++) { + free (constant_pool->vec_nats.data[i]); + } + +} + + +struct constant_utf8 *find_utf8 (struct constant_pool *constant_pool, int index) { + + struct vector *arr = &constant_pool->vec_strings; + + struct constant_utf8 *p; + int i; + + for (i = 0; i < arr->length; i++) { + + if ((p = arr->data[i])) { + + if (p->index == index) { + return p; + } + + } + + } + + return 0; + +} + +struct constant_class_ref *find_class_ref (struct constant_pool *constant_pool, int index) { + + struct vector *arr = &constant_pool->vec_class_refs; + + struct constant_class_ref *p; + int i; + + for (i = 0; i < arr->length; i++) { + + if ((p = arr->data[i])) { + + if (p->index == index) { + return p; + } + + } + + } + + return 0; + +} + +struct constant_string_ref *find_string_ref (struct constant_pool *constant_pool, int index) { + + struct vector *arr = &constant_pool->vec_string_refs; + + struct constant_string_ref *p; + int i; + + for (i = 0; i < arr->length; i++) { + + if ((p = arr->data[i])) { + + if (p->index == index) { + return p; + } + + } + + } + + return 0; + +} + +struct constant_field_ref *find_field_ref (struct constant_pool *constant_pool, int index) { + + struct vector *arr = &constant_pool->vec_field_refs; + + struct constant_field_ref *p; + int i; + + for (i = 0; i < arr->length; i++) { + + if ((p = arr->data[i])) { + + if (p->index == index) { + return p; + } + + } + + } + + return 0; + +} + +struct constant_method_ref *find_method_ref (struct constant_pool *constant_pool, int index) { + + struct vector *arr = &constant_pool->vec_method_refs; + + struct constant_method_ref *p; + int i; + + for (i = 0; i < arr->length; i++) { + + if ((p = arr->data[i])) { + + if (p->index == index) { + return p; + } + + } + + } + + return 0; + +} + +struct constant_nat *find_nat (struct constant_pool *constant_pool, int index) { + + struct vector *arr = &constant_pool->vec_nats; + + struct constant_nat *p; + int i; + + for (i = 0; i < arr->length; i++) { + + if ((p = arr->data[i])) { + + if (p->index == index) { + return p; + } + + } + + } + + return 0; + +} + +struct constant_invoke_dynamic *find_invoke_dynamic (struct constant_pool *constant_pool, int index) { + + struct vector *arr = &constant_pool->vec_invoke_dynamic; + + struct constant_invoke_dynamic *p; + int i; + + for (i = 0; i < arr->length; i++) { + + if ((p = arr->data[i])) { + + if (p->index == index) { + return p; + } + + } + + } + + return 0; + +} + +double get_double_from_constant_pool (struct constant_pool *p, int index) { + + struct constant_double *entry; + unsigned char temp[8]; + + double value = 0; + int i, j, k; + + for (i = 0; i < p->vec_doubles.length; i++) { + + entry = p->vec_doubles.data[i]; + + if (entry->index == (index)) { + + for (j = 0, k = 7; j < 8; j++, k--) { + temp[k] = entry->value[j]; + } + + memcpy (&value, temp, 8); + return value; + + } + + } + + return 0.0f; + +} + +int get_utf8_string (struct constant_pool *p, int index, unsigned long size, char *out) { + + struct constant_utf8 *utf8 = find_utf8 (p, index); + unsigned long copy_size = 0; + + memset (out, 0, size); + + if (utf8 != 0) { + + copy_size = (array_to_integer (utf8->string_size, 2, 1) < size) ? array_to_integer (utf8->string_size, 2, 1) : size; + memcpy (out, utf8->ptr, copy_size); + + } + + return copy_size; + +} diff --git a/constant.h b/constant.h new file mode 100644 index 0000000..d36249b --- /dev/null +++ b/constant.h @@ -0,0 +1,193 @@ +/****************************************************************************** + * @file constant.h + *****************************************************************************/ +#ifndef _CONSTANT_H +#define _CONSTANT_H + +#include "vector.h" +struct constant_pool { + + struct vector vec_strings; + struct vector vec_integers; + struct vector vec_floats; + struct vector vec_longs; + struct vector vec_doubles; + struct vector vec_class_refs; + struct vector vec_string_refs; + struct vector vec_field_refs; + struct vector vec_method_refs; + struct vector vec_interface_refs; + struct vector vec_nats; + struct vector vec_method_handlers; + struct vector vec_invoke_dynamic; + +}; + +void free_constant_pool (struct constant_pool *constant_pool); + +#include +struct constant_pool *parse_constant_pool (FILE *fp, int count); + +struct constant_utf8 { + + unsigned char tag; + + int additional_byte_size; + int index; + + unsigned char string_size[2]; + unsigned char *ptr; + +}; + +struct constant_integer { + + unsigned char tag; + + int additional_byte_size; + int index; + + unsigned char value[4]; + +}; + +struct constant_float { + + unsigned char tag; + + int additional_byte_size; + int index; + + unsigned char value[4]; + +}; + +struct constant_long { + + unsigned char tag; + + int additional_byte_size; + int index; + + unsigned char value[8]; + +}; + +struct constant_double { + + unsigned char tag; + + int additional_byte_size; + int index; + + unsigned char value[8]; + +}; + +struct constant_class_ref { + + unsigned char tag; + + int additional_byte_size; + int index; + + unsigned char string_index[2]; + +}; + +struct constant_string_ref { + + unsigned char tag; + + int additional_byte_size; + int index; + + unsigned char string_index[2]; + +}; + +struct constant_field_ref { + + unsigned char tag; + + int additional_byte_size; + int index; + + unsigned char class_index[2]; + unsigned char nat_index[2]; + +}; + +struct constant_method_ref { + + unsigned char tag; + + int additional_byte_size; + int index; + + unsigned char class_index[2]; + unsigned char nat_index[2]; + +}; + +struct constant_interface_ref { + + unsigned char tag; + + int additional_byte_size; + int index; + + unsigned char class_index[2]; + unsigned char nat_index[2]; + +}; + +struct constant_nat { + + unsigned char tag; + + int additional_byte_size; + int index; + + unsigned char name_index[2]; + unsigned char type_index[2]; + +}; + +struct constant_method_handler { + + unsigned char tag; + + int additional_byte_size; + int index; + + unsigned char reference_kind; + unsigned char reference_index[2]; + +}; + +struct constant_invoke_dynamic { + + unsigned char tag; + + int additional_byte_size; + int index; + + unsigned char bootstrap_method_attr_index[2]; + unsigned char nat_index[2]; + +}; + + +double get_double_from_constant_pool (struct constant_pool *p, int index); +int get_utf8_string (struct constant_pool *p, int index, unsigned long size, char *out); + +struct constant_utf8 *find_utf8 (struct constant_pool *constant_pool, int index); +struct constant_class_ref *find_class_ref (struct constant_pool *constant_pool, int index); +struct constant_string_ref *find_string_ref (struct constant_pool *constant_pool, int index); +struct constant_field_ref *find_field_ref (struct constant_pool *constant_pool, int index); +struct constant_method_ref *find_method_ref (struct constant_pool *constant_pool, int index); +struct constant_nat *find_nat (struct constant_pool *constant_pool, int index); +struct constant_invoke_dynamic *find_invoke_dynamic (struct constant_pool *constant_pool, int index); + +#endif /* _CONSTANT_H */ diff --git a/cstr.c b/cstr.c new file mode 100755 index 0000000..d518f2e --- /dev/null +++ b/cstr.c @@ -0,0 +1,69 @@ +/****************************************************************************** + * @file cstr.c + *****************************************************************************/ +#include +#include + +#include "cstr.h" + +extern void *xrealloc (void *__ptr, unsigned int __size); + +static void cstr_realloc (struct cstring *cstr, int new_size) { + + int size = cstr->size_allocated; + + if (size < 8) { + size = 8; + } + + while (size < new_size) { + size *= 2; + } + + cstr->data = xrealloc (cstr->data, size); + cstr->size_allocated = size; + +} + +void cstr_ccat (struct cstring *cstr, int ch) { + + int size = cstr->size + 1; + + if (size > cstr->size_allocated) { + cstr_realloc (cstr, size); + } + + ((unsigned char *) cstr->data)[size - 1] = ch; + cstr->size = size; + +} + +void cstr_cat (struct cstring *cstr, const char *str, int len) { + + int size; + + if (len <= 0) { + len = strlen (str) + 1 + len; + } + + size = cstr->size + len; + + if (size > cstr->size_allocated) { + cstr_realloc (cstr, size); + } + + memmove (((unsigned char *) cstr->data) + cstr->size, str, len); + cstr->size = size; + +} + +void cstr_new (struct cstring *cstr) { + memset (cstr, 0, sizeof (struct cstring)); +} + +void cstr_free (struct cstring *cstr) { + + free (cstr->data); + cstr_new (cstr); + +} diff --git a/cstr.h b/cstr.h new file mode 100755 index 0000000..2736720 --- /dev/null +++ b/cstr.h @@ -0,0 +1,20 @@ +/****************************************************************************** + * @file cstr.h + *****************************************************************************/ +#ifndef _CSTR_H +#define _CSTR_H + +struct cstring { + + int size, size_allocated; + void *data; + +}; + +void cstr_ccat (struct cstring *cstr, int ch); +void cstr_cat (struct cstring *cstr, const char *str, int len); + +void cstr_new (struct cstring *cstr); +void cstr_free (struct cstring *cstr); + +#endif /* _CSTR_H */ diff --git a/field.c b/field.c new file mode 100644 index 0000000..fdbfa1a --- /dev/null +++ b/field.c @@ -0,0 +1,69 @@ +/****************************************************************************** + * @file java_field_pool_parser.c + *****************************************************************************/ +#include + +#include "lib.h" + +static int parse_attr (FILE *fp, int count) { + + unsigned char temp[4]; + int i; + + for (i = 0; i < count; i++) { + + if (fread (temp, 1, 2, fp) != 2) { + return -1; + } + + if (fread (temp, 1, 4, fp) != 2) { + return -1; + } + + fseek (fp, array_to_integer (temp, 4, 1), SEEK_CUR); + + } + + return 0; + +} + +static int parse (FILE *fp) { + + unsigned char temp[2]; + + if (fread (temp, 1, 2, fp) != 2) { + return -1; + } + + if (fread (temp, 1, 2, fp) != 2) { + return -1; + } + + if (fread (temp, 1, 2, fp) != 2) { + return -1; + } + + if (fread (temp, 1, 2, fp) != 2) { + return -1; + } + + return parse_attr (fp, array_to_integer (temp, 2, 1)); + +} + +int parse_field_pool (FILE *fp, int count) { + + int ret, i; + + for (i = 0; i < count; i++) { + + if ((ret = parse (fp))) { + return ret; + } + + } + + return 0; + +} diff --git a/hashtab.c b/hashtab.c new file mode 100755 index 0000000..328b622 --- /dev/null +++ b/hashtab.c @@ -0,0 +1,217 @@ +/****************************************************************************** + * @file hashtab.c + *****************************************************************************/ +#include +#include +#include + +#include "hashtab.h" + +static struct hashtab_entry *find_entry (struct hashtab_entry *entries, unsigned int capacity, struct hashtab_name *key); + +static int adjust_capacity (struct hashtab *table, unsigned int new_capacity) { + + struct hashtab_entry *new_entries, *old_entries; + unsigned int i, new_count, old_capacity; + + if ((new_entries = malloc (sizeof (*new_entries) * new_capacity)) == NULL) { + return -2; + } + + for (i = 0; i < new_capacity; i++) { + + struct hashtab_entry *entry = &new_entries[i]; + + entry->key = NULL; + entry->value = NULL; + + } + + old_entries = table->entries; + old_capacity = table->capacity; + + new_count = 0; + + for (i = 0; i < old_capacity; i++) { + + struct hashtab_entry *entry = &old_entries[i], *dest; + + if (entry->key == NULL) { + continue; + } + + dest = find_entry (new_entries, new_capacity, entry->key); + + dest->key = entry->key; + dest->value = entry->value; + + new_count++; + + } + + free (old_entries); + + table->capacity = new_capacity; + table->count = new_count; + table->entries = new_entries; + table->used = new_count; + + return 0; + +} + +static struct hashtab_entry *find_entry (struct hashtab_entry *entries, unsigned int capacity, struct hashtab_name *key) { + + struct hashtab_entry *tombstone = NULL; + unsigned int index; + + for (index = key->hash % capacity; ; index = (index + 1) % capacity) { + + struct hashtab_entry *entry = &entries[index]; + + if (entry->key == NULL) { + + if (entry->value == NULL) { + + if (tombstone == NULL) { + return entry; + } + + return tombstone; + + } else if (tombstone == NULL) { + tombstone = entry; + } + + } else if (entry->key->bytes == key->bytes) { + + if (memcmp (entry->key->chars, key->chars, key->bytes) == 0 && entry->key->hash == key->hash) { + return entry; + } + + } + + } + +} + +static unsigned int hash_string (const void *p, unsigned int length) { + + unsigned char *str = (unsigned char *) p; + unsigned int i; + + unsigned int result = 0; + + for (i = 0; i < length; i++) { + result = (((unsigned short) str[i]) << 4) + (result >> 9) + result + (result >> 3) + (((unsigned short) str[i]) << 2) - (result << 12); + } + + return result; + +} + +struct hashtab_name *hashtab_alloc_name (const char *str) { + + unsigned int bytes = strlen (str), hash = hash_string (str, bytes); + struct hashtab_name *name; + + if ((name = malloc (sizeof (*name))) == NULL) { + return NULL; + } + + name->bytes = bytes; + name->chars = str; + name->hash = hash; + + return name; + +} + +struct hashtab_name *hashtab_get_key (struct hashtab *table, const char *name) { + + struct hashtab_name *key; + struct hashtab_entry *entry; + + if (table == NULL || table->count == 0 || !(key = hashtab_alloc_name (name))) { + return 0; + } + + entry = find_entry (table->entries, table->capacity, key); + free (key); + + return entry->key; + +} + +void *hashtab_get (struct hashtab *table, struct hashtab_name *key) { + + struct hashtab_entry *entry; + + if (table == NULL || table->count == 0) { + return NULL; + } + + entry = find_entry (table->entries, table->capacity, key); + + if (entry->key == NULL) { + return NULL; + } + + return entry->value; + +} + +int hashtab_put (struct hashtab *table, struct hashtab_name *key, void *value) { + + const int MIN_CAPACITY = 15; + + struct hashtab_entry *entry; + int ret = 0; + + if (table->used >= table->capacity / 2) { + + int capacity = table->capacity * 2 - 1; + + if (capacity < MIN_CAPACITY) { + capacity = MIN_CAPACITY; + } + + if ((ret = adjust_capacity (table, capacity))) { + return ret; + } + + } + + entry = find_entry (table->entries, table->capacity, key); + + if (entry->key == NULL) { + + table->count++; + + if (entry->value == NULL) { + table->used++; + } + + } + + entry->key = key; + entry->value = value; + + return 0; + +} + +void hashtab_remove (struct hashtab *table, struct hashtab_name *key) { + + struct hashtab_entry *entry; + + if ((entry = find_entry (table->entries, table->capacity, key)) != NULL) { + + entry->key = NULL; + entry->value = NULL; + + --table->count; + + } + +} diff --git a/hashtab.h b/hashtab.h new file mode 100755 index 0000000..ed8e828 --- /dev/null +++ b/hashtab.h @@ -0,0 +1,36 @@ +/****************************************************************************** + * @file hashtab.h + *****************************************************************************/ +#ifndef _HASHTAB_H +#define _HASHTAB_H + +struct hashtab_name { + + const char *chars; + unsigned int bytes, hash; + +}; + +struct hashtab_entry { + + struct hashtab_name *key; + void *value; + +}; + +struct hashtab { + + struct hashtab_entry *entries; + int capacity, count, used; + +}; + +struct hashtab_name *hashtab_alloc_name (const char *str); +struct hashtab_name *hashtab_get_key (struct hashtab *table, const char *name); + +void *hashtab_get (struct hashtab *table, struct hashtab_name *key); + +int hashtab_put (struct hashtab *table, struct hashtab_name *key, void *value); +void hashtab_remove (struct hashtab *table, struct hashtab_name *key); + +#endif /* _HASHTAB_H */ diff --git a/interface.c b/interface.c new file mode 100644 index 0000000..3250e11 --- /dev/null +++ b/interface.c @@ -0,0 +1,32 @@ +/****************************************************************************** + * @file java_interface_pool_parser.c + *****************************************************************************/ +#include + +static int parse (FILE *fp) { + + unsigned char temp[2]; + + if (fread (temp, 1, 2, fp) != 2) { + return -1; + } + + return 0; + +} + +int parse_interface_pool (FILE *fp, int count) { + + int ret, i; + + for (i = 0; i < count; i++) { + + if ((ret = parse (fp))) { + return ret; + } + + } + + return 0; + +} diff --git a/java_lib.c b/java_lib.c new file mode 100644 index 0000000..38f1d05 --- /dev/null +++ b/java_lib.c @@ -0,0 +1,76 @@ +/****************************************************************************** + * @file java_lib.c + *****************************************************************************/ +#include +#include +#include + +#include "constant.h" +#include "stack.h" + +typedef int (*java_lang_lib) (struct constant_pool *p, struct stack_frame *stack); + +struct java_lang_method { + + char *class_name; + char *method_name; + + java_lang_lib runtime; + +}; + +static int java_lang_math_random (struct constant_pool *p, struct stack_frame *stack) { + + double r = 0.0f; + int times = 0, i; + + srand (time (0)); + times = rand () % 100; + + for (i = 0; i < times; i++) { + r = ((double) rand () / (double) RAND_MAX); + } + + push_double (stack, r); + + (void) p; + return 0; + +} + +static struct java_lang_method method_table[] = { + { "java/lang/Math", "random", java_lang_math_random } +}; + +static unsigned long java_lang_method_size = (sizeof (method_table) / sizeof (method_table[0])); + +static struct java_lang_method *find_java_lang_method (char *class_name, char *method_name) { + + struct java_lang_method *entry; + unsigned long i; + + for (i = 0; i < java_lang_method_size; i++) { + + entry = &method_table[i]; + + if (strcmp (entry->class_name, class_name) == 0 && strcmp (entry->method_name, method_name) == 0) { + return entry; + } + + } + + return 0; + +} + +int invoke_java_lang_library (struct constant_pool *p, struct stack_frame *stack, char *class_name, char *method_name) { + + struct java_lang_method *method; + + if ((method = find_java_lang_method (class_name, method_name))) { + return method->runtime (p, stack); + } + + return -1; + +} diff --git a/jvm.c b/jvm.c new file mode 100644 index 0000000..5e33265 --- /dev/null +++ b/jvm.c @@ -0,0 +1,124 @@ +/****************************************************************************** + * @file jvm.c + *****************************************************************************/ +#include +#include +#include + +#include "class.h" +#include "constant.h" +#include "jvm.h" +#include "lib.h" +#include "method.h" +#include "report.h" +#include "stack.h" +#include "vm.h" + +static struct stack_frame *stack_frame = 0; + +/*static FILE *fp = 0; + +static void cleanup (void) { + if (fp) { fclose (fp); } +}*/ + +struct jvm_state *state = 0; +const char *program_name = 0; + +int main (int argc, char **argv) { + + struct java_class *class; + struct method_info *main; + + long i; + + /*atexit (cleanup);*/ + + if (argc && *argv) { + + char *p; + program_name = *argv; + + if ((p = strrchr (program_name, '/')) || (p = strrchr (program_name, '\\'))) { + program_name = (p + 1); + } + + } + + state = xmalloc (sizeof (*state)); + parse_args (argc, argv, 1); + + if (state->nb_files == 0) { + + report_at (program_name, 0, REPORT_ERROR, "no input files provided"); + return EXIT_FAILURE; + + } + + for (i = 0; i < state->nb_files; i++) { + + if (!(class = parse_java_class (state->files[i]))) { + continue; + } + + /*{ + + struct constant_pool *p = class->constant_pool; + int i; + + for (i = 0; i < p->vec_method_refs.length; i++) { + + struct constant_method_ref *method = p->vec_method_refs.data[i]; + + struct constant_utf8 *ptr = find_utf8 (class->constant_pool, array_to_integer (method->, 2, 1)); + printf ("method_ref[%d]\n", method->index); + + } + + }*/ + + if (!(main = find_method_in_pool (class->constant_pool, class->method_pool, ACC_PUBLIC | ACC_STATIC, "main", 4))) { + + report_at (program_name, 0, REPORT_ERROR, "main method not found in class %s", state->files[i]); + continue; + + } + + if (!(stack_frame = stack_init (1024))) { + + report_at (program_name, 0, REPORT_ERROR, "failed to allocate memory for a stack"); + continue; + + } + + execute_method (main, stack_frame, class); + + if (stack_frame) { + + if (stack_frame->store) { + free (stack_frame->store); + } + + free (stack_frame); + + } + + stack_frame = 0; + + } + + free_classes (); + + if (stack_frame) { + + if (stack_frame->store) { + free (stack_frame->store); + } + + free (stack_frame); + + } + + return (get_error_count () > 0 ? EXIT_FAILURE : EXIT_SUCCESS); + +} diff --git a/jvm.h b/jvm.h new file mode 100755 index 0000000..bfbea35 --- /dev/null +++ b/jvm.h @@ -0,0 +1,25 @@ +/****************************************************************************** + * @file jvm.h + *****************************************************************************/ +#ifndef _JVM_H +#define _JVM_H + +struct jvm_state { + + const char **files; + long nb_files; + + const char **class_paths; + long nb_class_paths; + +}; + +extern struct jvm_state *state; +extern const char *program_name; + +#include + +int parse_field_pool (FILE *fp, int count); +int parse_interface_pool (FILE *fp, int count); + +#endif /* _JVM_H */ diff --git a/lib.c b/lib.c new file mode 100755 index 0000000..d6897a7 --- /dev/null +++ b/lib.c @@ -0,0 +1,295 @@ +/****************************************************************************** + * @file lib.c + *****************************************************************************/ +#include +#include +#include +#include + +#include "jvm.h" +#include "lib.h" +#include "report.h" + +#define OPTION_CLASS_PATH 0x0001 +#define OPTION_HELP 0x0002 + +struct option { + + const char *name; + int index, flags; + +}; + +#define OPTION_NO_ARG 0x0001 +#define OPTION_HAS_ARG 0x0002 + +static struct option opts[] = { + + { "--class-path", OPTION_CLASS_PATH, OPTION_HAS_ARG }, + { "-cp", OPTION_CLASS_PATH, OPTION_HAS_ARG }, + + { "--help", OPTION_HELP, OPTION_NO_ARG }, + { 0, 0, 0 } + +}; + +static int strstart (const char *val, const char **str) { + + const char *p = val; + const char *q = *str; + + while (*p != '\0') { + + if (*p != *q) { + return 0; + } + + ++p; + ++q; + + } + + *str = q; + return 1; + +} + +static void print_help (void) { + + if (program_name) { + + fprintf (stderr, "Usage: %s [options] file...\n\n", program_name); + fprintf (stderr, "Options:\n\n"); + + fprintf (stderr, " --help Show this help information then exit.\n"); + + } + + exit (EXIT_SUCCESS); + +} + +static void dynarray_add (void *ptab, long *nb_ptr, void *data) { + + int nb, nb_alloc; + void **pp; + + nb = *nb_ptr; + pp = *(void ***) ptab; + + if ((nb & (nb - 1)) == 0) { + + if (!nb) { + nb_alloc = 1; + } else { + nb_alloc = nb * 2; + } + + pp = xrealloc (pp, nb_alloc * sizeof (void *)); + *(void ***) ptab = pp; + + } + + pp[nb++] = data; + *nb_ptr = nb; + +} + +void parse_args (int argc, char **argv, int optind) { + + struct option *popt; + const char *optarg, *r; + +#if defined (_WIN32) + char *p; + unsigned long length, i; +#endif + + if (argc <= optind) { + print_help (); + } + + while (optind < argc) { + + r = argv[optind++]; + + if (r[0] != '-' || r[1] == '\0') { + + dynarray_add (&state->files, &state->nb_files, xstrdup (r)); + continue; + + } + + for (popt = opts; popt; popt++) { + + const char *p1 = popt->name; + const char *r1 = r; + + if (!p1) { + + report_at (program_name, 0, REPORT_ERROR, "invalid option -- '%s'", r); + exit (EXIT_FAILURE); + + } + + if (!strstart (p1, &r1)) { + continue; + } + + optarg = r1; + + if (popt->flags & OPTION_HAS_ARG) { + + if (*optarg == '\0') { + + if (optind >= argc) { + + report_at (program_name, 0, REPORT_ERROR, "argument to '%s' is missing", r); + exit (EXIT_FAILURE); + + } + + optarg = argv[optind++]; + + } + + } else if (*optarg != '\0') { + continue; + } + + break; + + } + + switch (popt->index) { + + case OPTION_CLASS_PATH: { + +#if defined (_WIN32) + length = strlen (p = (char *) optarg); + + for (i = 0; i < length; i++) { + + if (p[i] == '/') { + p[i] = '\\'; + } + + } +#endif + dynarray_add (&state->class_paths, &state->nb_class_paths, xstrdup (optarg)); + break; + + } + + case OPTION_HELP: { + + print_help (); + break; + + } + + default: { + + report_at (program_name, 0, REPORT_ERROR, "unsupported option '%s'", r); + exit (EXIT_FAILURE); + + } + + } + + } + +} + +unsigned long array_to_integer (unsigned char *arr, int size, int bigendian) { + + unsigned long val = 0, mask = 1; + int i; + + if (bigendian) { + + int j; + + for (i = size, j = 0; i > 0; i--, j++) { + + mask *= (UCHAR_MAX + 1); + val |= arr[j] << (CHAR_BIT * (i - 1)); + + } + + } else { + + for (i = 0; i < size; i++) { + + mask *= (UCHAR_MAX + 1); + val |= arr[i] << (CHAR_BIT * i); + + } + + } + + return val & (mask - 1); + +} + +void write_to_byte_array (unsigned char *arr, unsigned long value, int size, int bigendian) { + + int i; + + if (bigendian) { + + int j; + + for (i = size - 1, j = 0; i >= 0; i--, j++) { + arr[i] = (value >> (CHAR_BIT * j)) & UCHAR_MAX; + } + + } else { + + for (i = 0; i < size; i++) { + arr[i] = (value >> (CHAR_BIT * i)) & UCHAR_MAX; + } + + } + +} + +char *xstrdup (const char *str) { + + char *ptr = xmalloc (strlen (str) + 1); + strcpy (ptr, str); + + return ptr; + +} + +void *xmalloc (unsigned long size) { + + void *ptr = malloc (size); + + if (ptr == NULL && size) { + + report_at (program_name, 0, REPORT_ERROR, "memory full (malloc)"); + exit (EXIT_FAILURE); + + } + + memset (ptr, 0, size); + return ptr; + +} + +void *xrealloc (void *ptr, unsigned long size) { + + void *new_ptr = realloc (ptr, size); + + if (new_ptr == NULL && size) { + + report_at (program_name, 0, REPORT_ERROR, "memory full (realloc)"); + exit (EXIT_FAILURE); + + } + + return new_ptr; + +} diff --git a/lib.h b/lib.h new file mode 100755 index 0000000..ea61df1 --- /dev/null +++ b/lib.h @@ -0,0 +1,17 @@ +/****************************************************************************** + * @file lib.h + *****************************************************************************/ +#ifndef _LIB_H +#define _LIB_H + +unsigned long array_to_integer (unsigned char *arr, int size, int bigendian); +void write_to_byte_array (unsigned char *arr, unsigned long value, int size, int bigendian); + +char *xstrdup (const char *str); + +void *xmalloc (unsigned long size); +void *xrealloc (void *ptr, unsigned long size); + +void parse_args (int argc, char **argv, int optind); + +#endif /* _LIB_H */ diff --git a/method.c b/method.c new file mode 100644 index 0000000..b73a7e9 --- /dev/null +++ b/method.c @@ -0,0 +1,208 @@ +/****************************************************************************** + * @file java_method_pool_parser.c + *****************************************************************************/ +#include +#include +#include + +#include "constant.h" +#include "lib.h" +#include "method.h" +#include "vector.h" + +static int parse_attr (FILE *fp, struct method_attribute_info *attributes, int count) { + + struct method_attribute_info *temp; + int i; + + size_t length; + + for (i = 0; i < count; i++) { + + temp = &attributes[i]; + + if (fread (temp->attribute_name_index, 1, 2, fp) != 2) { + return -1; + } + + if (fread (temp->attribute_length, 1, 4, fp) != 4) { + return -1; + } + + length = array_to_integer (temp->attribute_length, 4, 1); + + if (!(temp->info = malloc (sizeof (unsigned char) * length))) { + return -1; + } + + if (fread (temp->info, 1, length, fp) != length) { + + free (temp->info); + return -1; + + } + + } + + return 0; + +} + +static struct method_info *parse (FILE *fp) { + + struct method_info *method_info; + int count; + + if (!(method_info = malloc (sizeof (*method_info)))) { + return 0; + } + + if (fread (method_info->access_flags, 1, 2, fp) != 2) { + + free (method_info); + return 0; + + } + + if (fread (method_info->name_index, 1, 2, fp) != 2) { + + free (method_info); + return 0; + + } + + if (fread (method_info->descriptor_index, 1, 2, fp) != 2) { + + free (method_info); + return 0; + + } + + if (fread (method_info->attributes_count, 1, 2, fp) != 2) { + + free (method_info); + return 0; + + } + + count = array_to_integer (method_info->attributes_count, 2, 1); + + if (!(method_info->attributes = malloc (sizeof (*method_info->attributes) * count))) { + + free (method_info); + return 0; + + } + + memset (method_info->attributes, 0, sizeof (*method_info->attributes) * count); + + if (parse_attr (fp, method_info->attributes, count)) { + + free (method_info->attributes); + free (method_info); + + return 0; + + } + + return method_info; + +} + +struct vector *parse_method_pool (FILE *fp, int count) { + + struct method_info *method_info; + struct vector *method_pool; + + int i, j; + + if (!(method_pool = malloc (sizeof (*method_pool)))) { + return 0; + } + + memset (method_pool, 0, sizeof (*method_pool)); + + for (i = 0; i < count; i++) { + + if (!(method_info = parse (fp))) { + + for (j = 0; j < method_pool->length; j++) { + + method_info = method_pool->data[j]; + + free (method_info->attributes); + free (method_info); + + } + + free (method_pool); + return 0; + + } + + vec_push (method_pool, method_info); + + } + + return method_pool; + +} + +void free_method_pool (struct vector *method_pool) { + + struct method_info *method_info; + int i; + + for (i = 0; i < method_pool->length; i++) { + + method_info = method_pool->data[i]; + + free (method_info->attributes); + free (method_info); + + } + +} + +struct method_info *find_method_in_pool (struct constant_pool *constant_pool, struct vector *method_pool, int flags, const char *method_name, int length) { + + struct constant_utf8 *name; + struct method_info *method; + + int access_flags, size, i; + + for (i = 0; i < method_pool->length; i++) { + + if ((method = method_pool->data[i])) { + + if (flags) { + + access_flags = array_to_integer (method->access_flags, 2, 1); + + if ((access_flags & flags) != flags) { + continue; + } + + } + + if ((name = find_utf8 (constant_pool, array_to_integer (method->name_index, 2, 1)))) { + + size = array_to_integer (name->string_size, 2, 1); + + if (length == size) { + + if (strncmp (method_name, (char *) name->ptr, size) == 0) { + return method; + } + + } + + } + + } + + } + + return 0; + +} diff --git a/method.h b/method.h new file mode 100644 index 0000000..69b9a41 --- /dev/null +++ b/method.h @@ -0,0 +1,43 @@ +/****************************************************************************** + * @file method.h + *****************************************************************************/ +#ifndef _METHOD_H +#define _METHOD_H + +#include "vector.h" + +struct method_attribute_info { + + unsigned char attribute_name_index[2]; + unsigned char attribute_length[4]; + + unsigned char *info; + +}; + +void free_method_pool (struct vector *method_pool); + +#define ACC_PUBLIC (1 << 0) +#define ACC_PRIVATE (1 << 1) +#define ACC_PROTECTED (1 << 2) + +#define ACC_STATIC (1 << 3) + +struct method_info { + + unsigned char access_flags[2]; + unsigned char name_index[2]; + unsigned char descriptor_index[2]; + unsigned char attributes_count[2]; + + struct method_attribute_info *attributes; + +}; + +#include +struct vector *parse_method_pool (FILE *fp, int count); + +#include "constant.h" +struct method_info *find_method_in_pool (struct constant_pool *constant_pool, struct vector *method_pool, int flags, const char *method_name, int length); + +#endif /* _METHOD_H */ diff --git a/report.c b/report.c new file mode 100644 index 0000000..8e128ef --- /dev/null +++ b/report.c @@ -0,0 +1,150 @@ +/****************************************************************************** + * @file report.c + *****************************************************************************/ +#include +#include +#include + +#include "report.h" + +unsigned long errors = 0; + +#ifndef __PDOS__ +#if defined (_WIN32) +# include +static int OriginalConsoleColor = -1; +#endif + +static void reset_console_color (void) { + +#if defined (_WIN32) + + HANDLE hStdError = GetStdHandle (STD_ERROR_HANDLE); + + if (OriginalConsoleColor == -1) { return; } + + SetConsoleTextAttribute (hStdError, OriginalConsoleColor); + OriginalConsoleColor = -1; + +#else + + fprintf (stderr, "\033[0m"); + +#endif + +} + +static void set_console_color (int color) { + +#if defined (_WIN32) + + HANDLE hStdError = GetStdHandle (STD_ERROR_HANDLE); + WORD wColor; + + if (OriginalConsoleColor == -1) { + + CONSOLE_SCREEN_BUFFER_INFO csbi; + + if (!GetConsoleScreenBufferInfo (hStdError, &csbi)) { + return; + } + + OriginalConsoleColor = csbi.wAttributes; + + } + + wColor = (OriginalConsoleColor & 0xF0) + (color & 0xF); + SetConsoleTextAttribute (hStdError, wColor); + +#else + + fprintf (stderr, "\033[%dm", color); + +#endif + +} +#endif + +static void output_message (const char *filename, unsigned long lineno, unsigned long idx, enum report_type type, const char *fmt, va_list ap) { + + if (filename) { + + if (lineno == 0 && idx == 0) { + fprintf (stderr, "%s: ", filename); + } else { + fprintf (stderr, "%s:", filename); + } + + } + + if (lineno > 0) { + + if (idx == 0) { + fprintf (stderr, "%lu: ", lineno); + } else { + fprintf (stderr, "%lu:", lineno); + } + + } + + if (idx > 0) { + fprintf (stderr, "%lu: ", idx); + } + + if (type == REPORT_ERROR || type == REPORT_FATAL_ERROR) { + +#ifndef __PDOS__ + set_console_color (COLOR_ERROR); +#endif + + if (type == REPORT_ERROR) { + fprintf (stderr, "error:"); + } else { + fprintf (stderr, "fatal error:"); + } + + } else if (type == REPORT_INTERNAL_ERROR) { + +#ifndef __PDOS__ + set_console_color (COLOR_INTERNAL_ERROR); +#endif + + fprintf (stderr, "internal error:"); + + } else if (type == REPORT_WARNING) { + +#ifndef __PDOS__ + set_console_color (COLOR_WARNING); +#endif + + fprintf (stderr, "warning:"); + + } + +#ifndef __PDOS__ + reset_console_color (); +#endif + + fprintf (stderr, " "); + vfprintf (stderr, fmt, ap); + fprintf (stderr, "\n"); + + if (type != REPORT_WARNING) { + ++errors; + } + +} + +unsigned long get_error_count (void) { + return errors; +} + +void report_at (const char *filename, unsigned long lineno, enum report_type type, const char *fmt, ...) { + + va_list ap; + + va_start (ap, fmt); + output_message (filename, lineno, 0, type, fmt, ap); + va_end (ap); + +} diff --git a/report.h b/report.h new file mode 100644 index 0000000..8fc8758 --- /dev/null +++ b/report.h @@ -0,0 +1,29 @@ +/****************************************************************************** + * @file report.h + *****************************************************************************/ +#ifndef _REPORT_H +#define _REPORT_H + +enum report_type { + + REPORT_ERROR = 0, + REPORT_FATAL_ERROR, + REPORT_INTERNAL_ERROR, + REPORT_WARNING + +}; + +#if defined (_WIN32) +# define COLOR_ERROR 12 +# define COLOR_WARNING 13 +# define COLOR_INTERNAL_ERROR 19 +#else +# define COLOR_ERROR 91 +# define COLOR_INTERNAL_ERROR 94 +# define COLOR_WARNING 95 +#endif + +unsigned long get_error_count (void); +void report_at (const char *filename, unsigned long line_number, enum report_type type, const char *fmt, ...); + +#endif /* _REPORT_H */ diff --git a/stack.c b/stack.c new file mode 100644 index 0000000..d3312cb --- /dev/null +++ b/stack.c @@ -0,0 +1,100 @@ +/****************************************************************************** + * @file stack.c + *****************************************************************************/ +#include +#include +#include + +#include "lib.h" +#include "stack.h" + +struct stack_frame *stack_init (int entry_size) { + + struct stack_frame *stack_frame; + int i; + + if (!(stack_frame = malloc (sizeof (*stack_frame)))) { + return 0; + } + + memset (stack_frame, 0, sizeof (*stack_frame)); + + if (!(stack_frame->store = malloc (sizeof (*stack_frame->store) * entry_size))) { + + free (stack_frame); + return 0; + + } + + for (i = 0; i < entry_size; i++) { + memset (&stack_frame->store[i], 0, sizeof (stack_frame->store[i])); + } + + stack_frame->size = entry_size; + stack_frame->max_size = entry_size; + + return stack_frame; + +} + + +void push_double (struct stack_frame *stack, double value) { + + struct stack_entry *entry = &stack->store[--stack->size]; + memset (entry, 0, sizeof (*entry)); + + memcpy (entry->entry, &value, sizeof (double)); + entry->type = STACK_ENTRY_DOUBLE; + +} + +void push_int (struct stack_frame *stack, int value) { + + struct stack_entry *entry = &stack->store[--stack->size]; + memset (entry, 0, sizeof (*entry)); + + write_to_byte_array (entry->entry, value, sizeof (int), 1); + entry->type = STACK_ENTRY_INT; + +} + +void push_ref (struct stack_frame *stack, int value) { + + struct stack_entry *entry = &stack->store[--stack->size]; + memset (entry, 0, sizeof (*entry)); + + write_to_byte_array (entry->entry, value, sizeof (int), 1); + entry->type = STACK_ENTRY_REF; + +} + +double pop_double (struct stack_frame *stack) { + + struct stack_entry *entry = &stack->store[stack->size++]; + + double value = 0; + memcpy (&value, entry->entry, sizeof (double)); + + return value; + +} + +int pop_int (struct stack_frame *stack) { + + struct stack_entry *entry = &stack->store[stack->size++]; + return array_to_integer (entry->entry, 4, 1); + +} + + +struct stack_entry *pop_entry (struct stack_frame *stack) { + return &stack->store[stack->size++]; +} + +int entry_to_int (struct stack_entry *entry) { + return array_to_integer (entry->entry, 4, 1); +} + +int is_ref_entry (struct stack_frame *stack) { + return (stack->store[stack->size].type == STACK_ENTRY_REF); +} diff --git a/stack.h b/stack.h new file mode 100644 index 0000000..4df831d --- /dev/null +++ b/stack.h @@ -0,0 +1,42 @@ +/****************************************************************************** + * @file stack.h + *****************************************************************************/ +#ifndef _STACK_H +#define _STACK_H + +struct stack_entry { + + unsigned char entry[8]; + int type; + +}; + +#define STACK_ENTRY_NONE 0 +#define STACK_ENTRY_INT 1 +#define STACK_ENTRY_REF 2 +#define STACK_ENTRY_LONG 3 +#define STACK_ENTRY_DOUBLE 4 +#define STACK_ENTRY_FLOAT 5 + +struct stack_frame { + + int max_size, size; + struct stack_entry *store; + +}; + +struct stack_frame *stack_init (int entry_size); + +void push_double (struct stack_frame *stack, double value); +void push_int (struct stack_frame *stack, int value); +void push_ref (struct stack_frame *stack, int value); + +double pop_double (struct stack_frame *stack); +int pop_int (struct stack_frame *stack); + +struct stack_entry *pop_entry (struct stack_frame *stack); + +int entry_to_int (struct stack_entry *entry); +int is_ref_entry (struct stack_frame *stack); + +#endif /* _STACK_H */ diff --git a/vector.c b/vector.c new file mode 100755 index 0000000..723993a --- /dev/null +++ b/vector.c @@ -0,0 +1,54 @@ +/****************************************************************************** + * @file vector.c + *****************************************************************************/ +#include +#include + +#include "vector.h" + +extern void *xrealloc (void *__ptr, unsigned int __size); + +int vec_adjust (struct vector *vec, int length) { + + if (vec->capacity <= length) { + + if (vec->capacity == 0) { + vec->capacity = 16; + } else { + vec->capacity <<= 1; + } + + vec->data = xrealloc (vec->data, sizeof (*(vec->data)) * vec->capacity); + + } + + return 0; + +} + +void *vec_pop (struct vector *vec) { + + if (!vec || vec == NULL) { + return NULL; + } + + if (vec->length == 0) { + return NULL; + } + + return vec->data[--vec->length]; + +} + +int vec_push (struct vector *vec, void *elem) { + + int ret; + + if ((ret = vec_adjust (vec, vec->length)) != 0) { + return ret; + } + + vec->data[vec->length++] = elem; + return 0; + +} diff --git a/vector.h b/vector.h new file mode 100755 index 0000000..3da05e1 --- /dev/null +++ b/vector.h @@ -0,0 +1,19 @@ +/****************************************************************************** + * @file vector.h + *****************************************************************************/ +#ifndef _VECTOR_H +#define _VECTOR_H + +struct vector { + + void **data; + int capacity, length; + +}; + +int vec_adjust (struct vector *vec, int length); +int vec_push (struct vector *vec, void *elem); + +void *vec_pop (struct vector *vec); + +#endif /* _VECTOR_H */ diff --git a/vm.c b/vm.c new file mode 100644 index 0000000..95356ae --- /dev/null +++ b/vm.c @@ -0,0 +1,864 @@ +/****************************************************************************** + * @file vm.c + *****************************************************************************/ +#include +#include +#include + +#include "class.h" +#include "cstr.h" +#include "lib.h" +#include "method.h" +#include "stack.h" +#include "vector.h" +#include "vm.h" + +int invoke_java_lang_library (struct constant_pool *p, struct stack_frame *stack, char *class_name, char *method_name); + +static char *java_lib[] = { + + "java/io/PrintStream", + "java/lang/StringBuilder" + +}; + +struct cstring string_builder_buffer = { 0 };; + +struct local_variables { int integer[10]; } local_variables = { 0 }; +struct vector vec_classes = { 0 }; + +static double get_double_parameter (struct stack_frame *stack, struct constant_pool *p) { + + if (is_ref_entry (stack)) { + return get_double_from_constant_pool (p, pop_int (stack)); + } + + return pop_double (stack); + +} + +typedef int (*opcode_func) (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class); + +typedef struct { + + const char *name; + + unsigned char opcode; + int offset; + + opcode_func func; + +} byte_code; + +static int op_aload_0 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + push_int (stack, 0); + (void) java_class; + + *opcode = *opcode + 1; + return 0; + +} + +static int op_bipush (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + push_int (stack, opcode[0][1]); + (void) java_class; + + *opcode = *opcode + 2; + return 0; + +} + +static int op_d2i (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + push_int (stack, (int) pop_double (stack)); + (void) java_class; + + *opcode = *opcode + 1; + return 0; + +} + +static int op_dadd (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + double value1 = get_double_parameter (stack, java_class->constant_pool); + double value2 = get_double_parameter (stack, java_class->constant_pool); + + push_double (stack, value1 + value2); + *opcode = *opcode + 1; + + return 0; + +} + +static int op_dconst_1 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + push_double (stack, 1.0f); + (void) java_class; + + *opcode = *opcode + 1; + return 0; + +} + +static int op_dmul (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + double value1 = get_double_parameter (stack, java_class->constant_pool); + double value2 = get_double_parameter (stack, java_class->constant_pool); + + push_double (stack, value1 * value2); + *opcode = *opcode + 1; + + return 0; + +} + +static int op_dup (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + struct stack_entry *entry = pop_entry (stack); + int value = entry_to_int (entry); + + if (entry->type == STACK_ENTRY_INT) { + + push_int (stack, value); + push_int (stack, value); + + } else { + + push_ref (stack, value); + push_ref (stack, value); + + } + + (void) java_class; + + *opcode = *opcode + 1; + return 0; + +} + +static int op_getstatic (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + unsigned short field_index = (opcode[0][1] << 8) | opcode[0][2]; + + /*struct constant_pool *p = java_class->constant_pool; + struct vector *field_refs = &p->vec_field_refs; + + struct constant_field_ref *ref; + struct constant_nat *nat; + + int i; + + for (i = 0; i < field_refs->length; i++) { + + ref = field_refs->data[i]; + + if ((nat = find_nat (p, array_to_integer (ref->nat_index, 2, 1)))) { + printf ("FUCK YEAHHH\n"); + } + + }*/ + + push_ref (stack, field_index); + (void) java_class; + + *opcode = *opcode + 3; + return 0; + +} + +static int op_iadd (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + int result = pop_int (stack) + pop_int (stack); + + push_int (stack, result); + (void) java_class; + + *opcode = *opcode + 1; + return 0; + +} + +static int op_iconst_0 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + push_int (stack, 0); + (void) java_class; + + *opcode = *opcode + 1; + return 0; + +} + +static int op_iconst_1 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + push_int (stack, 1); + (void) java_class; + + *opcode = *opcode + 1; + return 0; + +} + +static int op_iconst_2 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + push_int (stack, 2); + (void) java_class; + + *opcode = *opcode + 1; + return 0; + +} + +static int op_iconst_3 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + push_int (stack, 3); + (void) java_class; + + *opcode = *opcode + 1; + return 0; + +} + +static int op_iconst_4 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + push_int (stack, 4); + (void) java_class; + + *opcode = *opcode + 1; + return 0; + +} + +static int op_iconst_5 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + push_int (stack, 5); + (void) java_class; + + *opcode = *opcode + 1; + return 0; + +} + +static int op_idiv (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + int value2 = pop_int (stack), value1 = pop_int (stack); + + push_int (stack, value1 / value2); + (void) java_class; + + *opcode = *opcode + 1; + return 0; + +} + +static int op_iload (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + push_int (stack, local_variables.integer[opcode[0][1]]); + (void) java_class; + + *opcode = *opcode + 2; + return 0; + +} + +static int op_iload_1 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + push_int (stack, local_variables.integer[1]); + (void) java_class; + + *opcode = *opcode + 1; + return 0; + +} + +static int op_iload_2 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + push_int (stack, local_variables.integer[2]); + (void) java_class; + + *opcode = *opcode + 1; + return 0; + +} + +static int op_iload_3 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + push_int (stack, local_variables.integer[3]); + (void) java_class; + + *opcode = *opcode + 1; + return 0; + +} + +static int op_imul (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + int result = pop_int (stack) * pop_int (stack); + + push_int (stack, result); + (void) java_class; + + *opcode = *opcode + 1; + return 0; + +} + +/*static int op_invokedynamic (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + struct constant_pool *p = java_class->constant_pool; + unsigned short method_index = (opcode[0][1] << 8) | opcode[0][2]; + + struct vector *methods = &p->vec_invoke_dynamic; + struct constant_invoke_dynamic *method; + + *opcode = *opcode + 5; + + if ((method = find_invoke_dynamic (p, method_index))) { + + struct constant_nat *nat; + char name[255]; + + if ((nat = find_nat (p, array_to_integer (method->nat_index, 2, 1)))) { + + get_utf8_string (p, array_to_integer (nat->name_index, 2, 1), 255, name); + printf ("YAYAY: %s\n", name); + + } + + } + + (void) stack; + + if (method_index < methods->length) { + + if ((method = methods->data[method_index])) { + return execute_method (method, stack, java_class); + } + + } + + if (vec_classes.length > 0) { + + java_class = vec_classes.data[vec_classes.length - 1]; + + p = java_class->constant_pool; + method_refs = java_class->method_pool; + + if (method_index < method_refs->length) { + + if ((method = method_refs->data[method_index])) { + return execute_method (method, stack, java_class); + } + + } + + } + + return 0; + +}*/ + +static int op_invokespecial (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + unsigned short method_index = (opcode[0][1] << 8) | opcode[0][2]; + + struct vector *methods = java_class->method_pool; + struct method_info *method; + + *opcode = *opcode + 3; + + if (method_index < methods->length) { + + if ((method = methods->data[method_index])) { + return execute_method (method, stack, java_class); + } + + } + + /*if (vec_classes.length > 0) { + + java_class = vec_classes.data[vec_classes.length - 1]; + + p = java_class->constant_pool; + method_refs = java_class->method_pool; + + if (method_index < method_refs->length) { + + if ((method = method_refs->data[method_index])) { + return execute_method (method, stack, java_class); + } + + } + + }*/ + + return 0; + +} + +static int op_invokestatic (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + unsigned short method_index = (opcode[0][1] << 8) | opcode[0][2]; + + struct constant_pool *p = java_class->constant_pool; + struct vector *methods = java_class->method_pool; + + char class_name[255]; + char method_name[255]; + char method_type[255]; + + struct method_info *method; + int ret = -1; + + *opcode = *opcode + 3; + + if (method_index < methods->length) { + + method = methods->data[method_index]; + memset(method_name, 0, 255); + + get_utf8_string (p, array_to_integer (method->name_index, 2, 1), 255, method_name); + printf ("method_name: %s\n", method_name); + + } else { + + struct constant_method_ref *method_ref; + struct constant_class_ref *class_ref; + struct constant_nat *nat; + + if ((method_ref = find_method_ref (p, method_index))) { + + if ((class_ref = find_class_ref (p, array_to_integer (method_ref->class_index, 2, 1))) && (nat = find_nat (p, array_to_integer (method_ref->nat_index, 2, 1)))) { + + get_utf8_string (p, array_to_integer (class_ref->string_index, 2, 1), 255, class_name); + get_utf8_string (p, array_to_integer (nat->name_index, 2, 1), 255, method_name); + get_utf8_string (p, array_to_integer (nat->type_index, 2, 1), 255, method_type); + + if ((ret = invoke_java_lang_library (p, stack, class_name, method_name))) { + + struct java_class *class = parse_java_class (class_name); + + if ((method = find_method_in_pool (class->constant_pool, class->method_pool, ACC_STATIC, method_name, strlen (method_name)))) { + ret = execute_method (method, stack, class); + } + + } + + } + + } + + } + + return ret; + +} + +static int op_invokevirtual (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + struct constant_pool *p = java_class->constant_pool; + unsigned short object_ref = (opcode[0][1] << 8) | opcode[0][2]; + + char class_name[255]; + char utf8[255]; + char method_name[255]; + + struct constant_method_ref *method_ref; + *opcode = *opcode + 3; + + if ((method_ref = find_method_ref (p, object_ref))) { + + struct constant_class_ref *class_ref = find_class_ref (p, array_to_integer (method_ref->class_index, 2, 1)); + struct constant_nat *nat = find_nat (p, array_to_integer (method_ref->nat_index, 2, 1)); + + if (class_ref && nat) { + + get_utf8_string (p, array_to_integer (class_ref->string_index, 2, 1), 255, class_name); + + if (strcmp (class_name, "java/io/PrintStream") == 0) { + + struct stack_entry *entry = pop_entry (stack); + struct constant_string_ref *string_ref; + + if (entry->type == STACK_ENTRY_REF) { + + if ((string_ref = find_string_ref (p, entry_to_int (entry)))) { + + get_utf8_string (p, array_to_integer (string_ref->string_index, 2, 1), 255, utf8); + cstr_cat (&string_builder_buffer, utf8, strlen (utf8)); + + } + + } else if (entry->type == STACK_ENTRY_INT) { + + sprintf (utf8, "%d", entry_to_int (entry)); + cstr_cat (&string_builder_buffer, utf8, strlen (utf8)); + + } + + cstr_ccat (&string_builder_buffer, '\0'); + printf ("%s\n", (char *) string_builder_buffer.data); + + cstr_free (&string_builder_buffer); + memset (&string_builder_buffer, 0, sizeof (string_builder_buffer)); + + return 0; + + } else if (strcmp (class_name, "java/lang/StringBuilder") == 0) { + + struct stack_entry *entry = pop_entry (stack); + struct constant_string_ref *string_ref; + + if (entry->type == STACK_ENTRY_REF) { + + if ((string_ref = find_string_ref (p, entry_to_int (entry)))) { + + get_utf8_string (p, array_to_integer (string_ref->string_index, 2, 1), 255, utf8); + cstr_cat (&string_builder_buffer, utf8, strlen (utf8)); + + } + + } else if (entry->type == STACK_ENTRY_INT) { + + sprintf (utf8, "%d", entry_to_int (entry)); + cstr_cat (&string_builder_buffer, utf8, strlen (utf8)); + + } + + cstr_ccat (&string_builder_buffer, '\0'); + string_builder_buffer.size--; + + return 0; + + } else { + + struct stack_entry *entry = pop_entry (stack); + struct method_info *method; + + get_utf8_string (p, array_to_integer (nat->name_index, 2, 1), 255, method_name); + + if (entry->type == STACK_ENTRY_REF) { + + struct java_class *class = parse_java_class (class_name); + + /*struct constant_field_ref *ref; + char temp[255]; + + printf ("index: %d\n", index);*/ + + /*if ((ref = find_field_ref (p, index))) {*/ + + /*printf ("FUCKKKK! %ld\n", array_to_integer (ref->class_index, 2, 1)); + exit (1);*/ + + /*get_utf8_string (p, array_to_integer (ref->string_index, 2, 1), 255, temp);*/ + /*printf ("%s\n", temp);*/ + + if ((method = find_method_in_pool (class->constant_pool, class->method_pool, 0, method_name, strlen (method_name)))) { + return execute_method (method, stack, class); + } + + /*}*/ + + } else if (entry->type == STACK_ENTRY_INT) { + + if (vec_classes.length > 0) { + + struct java_class *class = vec_pop (&vec_classes); + + if (strcmp (class->class_name, class_name) == 0) { + + if ((method = find_method_in_pool (class->constant_pool, class->method_pool, 0, method_name, strlen (method_name)))) { + return execute_method (method, stack, class); + } + + } + + } + + } + + } + + } + + } + + return -1; + +} + +static int op_irem (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + int value1 = pop_int (stack), value2 = pop_int (stack); + + push_int (stack, value2 % value1); + (void) java_class; + + *opcode = *opcode + 1; + return 0; + +} + +static int op_istore (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + local_variables.integer[opcode[0][1]] = pop_int (stack); + (void) java_class; + + *opcode = *opcode + 2; + return 0; + +} + +static int op_istore_1 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + local_variables.integer[1] = pop_int (stack); + (void) java_class; + + *opcode = *opcode + 1; + return 0; + +} + +static int op_istore_2 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + local_variables.integer[2] = pop_int (stack); + (void) java_class; + + *opcode = *opcode + 1; + return 0; + +} + +static int op_istore_3 (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + local_variables.integer[3] = pop_int (stack); + (void) java_class; + + *opcode = *opcode + 1; + return 0; + +} + +static int op_isub (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + int value2 = pop_int (stack), value1 = pop_int (stack); + + push_int (stack, value1 - value2); + (void) java_class; + + *opcode = *opcode + 1; + return 0; + +} + +static int op_ldc (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + push_ref (stack, opcode[0][1]); + *opcode = *opcode + 2; + + (void) java_class; + return 0; + +} + +static int op_ldc2_w (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + int index = (opcode[0][1] << 8) | opcode[0][2]; + + push_ref (stack, index); + *opcode = *opcode + 3; + + (void) java_class; + return 0; + +} + +static int op_new (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + unsigned short object_ref = (opcode[0][1] << 8) | opcode[0][2]; + + struct constant_class_ref *ref; + struct java_class *class; + + char class_name[255]; + int ret = -1; + + unsigned long count = (sizeof (java_lib) / sizeof (java_lib[0])); + unsigned long i; + + *opcode = *opcode + 3; + + if ((ref = find_class_ref (java_class->constant_pool, object_ref))) { + + get_utf8_string (java_class->constant_pool, array_to_integer (ref->string_index, 2, 1), 255, class_name); + + for (i = 0; i < count; i++) { + + if (strcmp (java_lib[i], class_name) == 0) { + return 0; + } + + } + + if ((class = parse_java_class (class_name))) { + ret = vec_push (&vec_classes, class); + } + + } + + (void) stack; + return ret; + +} + +static int op_return (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + *opcode = *opcode + 1; + + (void) stack; + (void) java_class; + + return -1; + +} + +static int op_sipush (unsigned char **opcode, struct stack_frame *stack, struct java_class *java_class) { + + push_int (stack, (opcode[0][1] << 8) | opcode[0][2]); + (void) java_class; + + *opcode = *opcode + 3; + return 0; + +} + +static byte_code opcodes[] = { + + { "aload_0", 0x2A, 1, op_aload_0 }, + { "bipush", 0x10, 2, op_bipush }, + { "dup", 0x59, 1, op_dup }, + { "getstatic", 0xB2, 3, op_getstatic }, + { "iadd", 0x60, 1, op_iadd }, + { "iconst_0", 0x03, 1, op_iconst_0 }, + { "iconst_1", 0x04, 1, op_iconst_1 }, + { "iconst_2", 0x05, 1, op_iconst_2 }, + { "iconst_3", 0x06, 1, op_iconst_3 }, + { "iconst_4", 0x07, 1, op_iconst_4 }, + { "iconst_5", 0x08, 1, op_iconst_5 }, + { "dconst_1", 0x0F, 1, op_dconst_1 }, + { "idiv", 0x6C, 1, op_idiv }, + { "imul", 0x68, 1, op_imul }, + { "dadd", 0x63, 1, op_dadd }, + { "dmul", 0x6B, 1, op_dmul }, + { "d2i", 0x8e, 1, op_d2i }, + { "invokespecial", 0xB7, 3, op_invokespecial }, + { "invokevirtual", 0xB6, 3, op_invokevirtual }, + { "invokestatic", 0xB8, 3, op_invokestatic }, + /*{ "invokedynamic", 0xBA, 3, op_invokedynamic },*/ + { "iload", 0x15, 2, op_iload }, + { "iload_1", 0x1B, 1, op_iload_1 }, + { "iload_2", 0x1C, 1, op_iload_2 }, + { "iload_3", 0x1D, 1, op_iload_3 }, + { "istore", 0x36, 2, op_istore }, + { "istore_1", 0x3C, 1, op_istore_1 }, + { "istore_2", 0x3D, 1, op_istore_2 }, + { "istore_3", 0x3E, 1, op_istore_3 }, + { "isub", 0x64, 1, op_isub }, + { "ldc", 0x12, 2, op_ldc }, + { "ldc2_w", 0x14, 3, op_ldc2_w }, + { "new", 0xBB, 3, op_new }, + { "irem", 0x70, 1, op_irem }, + { "sipush", 0x11, 3, op_sipush }, + { "return", 0xB1, 1, op_return } + +}; + +static unsigned long opcodes_size = (sizeof (opcodes) / sizeof (opcodes[0])); + +static opcode_func find_opcode_func (unsigned char op) { + + unsigned long i; + + for (i = 0; i < opcodes_size; i++) { + + if (opcodes[i].opcode == op) { + return opcodes[i].func; + } + + } + + return 0; + +} + +static int convert_to_code_attribute (struct code_attribute *ca, struct method_attribute_info *attr) { + + unsigned long length; + int info_p = 0; + + memcpy (ca->max_stack, attr->info + info_p, 2); + info_p += 2; + + memcpy (ca->max_locals, attr->info + info_p, 2); + info_p += 2; + + memcpy (ca->code_length, attr->info + info_p, 4); + info_p += 4; + + length = array_to_integer (ca->code_length, 4, 1); + + if (!(ca->code = malloc (sizeof (unsigned char) * length))) { + return -1; + } + + memcpy (ca->code, attr->info + info_p, length); + return 0; + +} + +int execute_method (struct method_info *method, struct stack_frame *stack, struct java_class *java_class) { + + unsigned long count = array_to_integer (method->attributes_count, 2, 1); + unsigned char *pc; + + char name[255]; + unsigned long i; + + struct code_attribute ca; + opcode_func func; + + memset (&ca, 0, sizeof (ca)); + + for (i = 0; i < count; i++) { + + if (convert_to_code_attribute (&ca, &method->attributes[i])) { + break; + } + + get_utf8_string (java_class->constant_pool, array_to_integer (ca.attribute_name_index, 2, 1), 255, name); + + if (memcmp (name, "code", 4) == 0) { + continue; + } + + pc = ca.code; + + for (;;) { + + if (!(func = find_opcode_func (pc[0]))) { + break; + } + + if (func (&pc, stack, java_class)) { + break; + } + + } + + } + + return 0; + +} diff --git a/vm.h b/vm.h new file mode 100644 index 0000000..807c15a --- /dev/null +++ b/vm.h @@ -0,0 +1,26 @@ +/****************************************************************************** + * @file vm.h + *****************************************************************************/ +#ifndef _VM_H +#define _VM_H + +struct code_attribute { + + unsigned char attribute_name_index[2]; + unsigned char attribute_length[4]; + + unsigned char max_stack[2]; + unsigned char max_locals[2]; + + unsigned char code_length[4]; + unsigned char *code; + +}; + +#include "class.h" +#include "method.h" +#include "stack.h" + +int execute_method (struct method_info *method, struct stack_frame *stack, struct java_class *java_class); + +#endif /* _VM_H */