From 3429da62824cee7d102e9f900102d43ad7606536 Mon Sep 17 00:00:00 2001 From: ComputerKing12 Date: Tue, 13 Aug 2024 08:12:22 -0400 Subject: [PATCH] Initial Commit --- CMakeLists.txt | 21 +++ include/BigEndian.h | 58 +++++++ include/ClassFormat.h | 105 ++++++++++++ include/ConstantPoolTags/Tags.h | 90 +++++++++++ include/FieldInfo.h | 12 ++ include/Globals.h | 17 ++ include/Methods.h | 11 ++ include/SpecTypes.h | 11 ++ include/Types.h | 6 + include/Utils/Utils.h | 138 ++++++++++++++++ samples/Hello.java | 13 ++ src/CMakeLists.txt | 9 ++ src/ConstantPoolTags/CMakeLists.txt | 24 +++ src/ConstantPoolTags/Class.cpp | 0 src/ConstantPoolTags/Double.cpp | 0 src/ConstantPoolTags/Dynamic.cpp | 0 src/ConstantPoolTags/Fieldref.cpp | 0 src/ConstantPoolTags/Float.cpp | 0 src/ConstantPoolTags/Integer.cpp | 0 src/ConstantPoolTags/InterfaceMethodref.cpp | 0 src/ConstantPoolTags/InvokeDynamic.cpp | 0 src/ConstantPoolTags/Long.cpp | 0 src/ConstantPoolTags/MethodHandle.cpp | 0 src/ConstantPoolTags/MethodType.cpp | 0 src/ConstantPoolTags/Methodref.cpp | 0 src/ConstantPoolTags/Module.cpp | 0 src/ConstantPoolTags/NameAndType.cpp | 0 src/ConstantPoolTags/Package.cpp | 0 src/ConstantPoolTags/PoolParser.cpp | 170 ++++++++++++++++++++ src/ConstantPoolTags/String.cpp | 0 src/ConstantPoolTags/Utf8.cpp | 0 src/FieldInfo/CMakeLists.txt | 9 ++ src/FieldInfo/FieldInfoParser.cpp | 19 +++ src/Main.cpp | 157 ++++++++++++++++++ src/Method/CMakeLists.txt | 9 ++ src/Method/MethodParser.cpp | 45 ++++++ 36 files changed, 924 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 include/BigEndian.h create mode 100644 include/ClassFormat.h create mode 100644 include/ConstantPoolTags/Tags.h create mode 100644 include/FieldInfo.h create mode 100644 include/Globals.h create mode 100644 include/Methods.h create mode 100644 include/SpecTypes.h create mode 100644 include/Types.h create mode 100644 include/Utils/Utils.h create mode 100644 samples/Hello.java create mode 100644 src/CMakeLists.txt create mode 100644 src/ConstantPoolTags/CMakeLists.txt create mode 100644 src/ConstantPoolTags/Class.cpp create mode 100644 src/ConstantPoolTags/Double.cpp create mode 100644 src/ConstantPoolTags/Dynamic.cpp create mode 100644 src/ConstantPoolTags/Fieldref.cpp create mode 100644 src/ConstantPoolTags/Float.cpp create mode 100644 src/ConstantPoolTags/Integer.cpp create mode 100644 src/ConstantPoolTags/InterfaceMethodref.cpp create mode 100644 src/ConstantPoolTags/InvokeDynamic.cpp create mode 100644 src/ConstantPoolTags/Long.cpp create mode 100644 src/ConstantPoolTags/MethodHandle.cpp create mode 100644 src/ConstantPoolTags/MethodType.cpp create mode 100644 src/ConstantPoolTags/Methodref.cpp create mode 100644 src/ConstantPoolTags/Module.cpp create mode 100644 src/ConstantPoolTags/NameAndType.cpp create mode 100644 src/ConstantPoolTags/Package.cpp create mode 100644 src/ConstantPoolTags/PoolParser.cpp create mode 100644 src/ConstantPoolTags/String.cpp create mode 100644 src/ConstantPoolTags/Utf8.cpp create mode 100644 src/FieldInfo/CMakeLists.txt create mode 100644 src/FieldInfo/FieldInfoParser.cpp create mode 100644 src/Main.cpp create mode 100644 src/Method/CMakeLists.txt create mode 100644 src/Method/MethodParser.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..540d03b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.25) + +project(JavaBytecodeParser) + +include_directories(include) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CXX_STANDARD 23) + +add_subdirectory(src) + +set(CONSTANT_POOL_TAG_SRC ${CONSTANT_POOL_TAG_SRC}) + +message("src " ${CONSTANT_POOL_TAG_SRC}) + +add_executable(parser + src/Main.cpp + + ${CONSTANT_POOL_TAG_SRC} +) +set(CMAKE_CXX_FLAGS "-std=c++${CXX_STANDARD} -O0 -g -Wpedantic") \ No newline at end of file diff --git a/include/BigEndian.h b/include/BigEndian.h new file mode 100644 index 0000000..446c32b --- /dev/null +++ b/include/BigEndian.h @@ -0,0 +1,58 @@ +#ifndef __JAVA_PARSER_BIG_ENDIAN_H +#define __JAVA_PARSER_BIG_ENDIAN_H + +#include +#include + +template +class BigEndian +{ + public: + ALWAYS_INLINE BigEndian(T val) + { + _val = val; + } + ALWAYS_INLINE BigEndian() + { + } + + ALWAYS_INLINE T ToHostFormat() + { + return ToHostFormat(_val); + } + + ALWAYS_INLINE T ToHostFormat(T val) + { + switch (sizeof(T)) + { + case 1: + return val; + case 2: + return __builtin_bswap16(val); + case 4: + return __builtin_bswap32(val); + case 8: + return __builtin_bswap64(val); + // Clang doesn't support __builtin_bswap128, so we fall back to a generic byte-order swap implementation + #ifndef __clang__ + case 16: + return __builtin_bswap128(val); + #endif + default: + char *p = reinterpret_cast(val); + size_t lo, hi; + for(lo = 0, hi = sizeof(T) - 1; hi > lo; lo++, hi--) + { + char tmp = p[lo]; + p[lo] = p[hi]; + p[hi] = tmp; + } + + return (T)(*p); + } + } + private: + T _val; +}; + +#endif \ No newline at end of file diff --git a/include/ClassFormat.h b/include/ClassFormat.h new file mode 100644 index 0000000..bf2968b --- /dev/null +++ b/include/ClassFormat.h @@ -0,0 +1,105 @@ +#ifndef __JAVA_PARSER_CLASS_FORMAT_H +#define __JAVA_PARSER_CLASS_FORMAT_H + +#include +#include +#include +#include + +namespace FieldInfo +{ +enum class ACCESS_FLAGS +{ + ACC_PUBLIC = 0x0001, + ACC_PRIVATE, + ACC_PROTECTED = 0x0004, + ACC_STATIC = 0x0008, + ACC_FINAL = 0x0010, + ACC_VOLATILE = 0x0040, + ACC_TRANSIENT = 0x0080, + ACC_SYNTHETIC = 0x1000, + ACC_ENUM = 0x4000 +}; +} // namespace FieldInfo + +namespace JavaClass +{ +enum class ACCESS_FLAGS +{ + ACC_PUBLIC = 0x0001, + ACC_FINAL = 0x0010, + ACC_SUPER = 0x0020, + ACC_INTERFACE = 0x0200, + ACC_ABSTRACT = 0x0400, + ACC_SYNTHETIC = 0x1000, + ACC_ANNOTATION = 0x2000, + ACC_ENUM = 0x4000, + ACC_MODULE = 0x8000 +}; +} // namespace JavaClass + +namespace Method +{ +enum class ACCESS_FLAGS +{ + ACC_PUBLIC = 0x0001, // Declared public; may be accessed from outside its package. + ACC_PRIVATE = 0x0002, // Declared private; accessible only within the defining class and other classes belonging to the same nest (§5.4.4). + ACC_PROTECTED = 0x0004, // Declared protected; may be accessed within subclasses. + ACC_STATIC = 0x0008, // Declared static. + ACC_FINAL = 0x0010, // Declared final; must not be overridden (§5.4.5). + ACC_SYNCHRONIZED = 0x0020, // Declared synchronized; invocation is wrapped by a monitor use. + ACC_BRIDGE = 0x0040, // A bridge method, generated by the compiler. + ACC_VARARGS = 0x0080, // Declared with variable number of arguments. + ACC_NATIVE = 0x0100, // Declared native; implemented in a language other than the Java programming language. + ACC_ABSTRACT = 0x0400, // Declared abstract; no implementation is provided. + ACC_STRICT = 0x0800, // In a class file whose major version number is at least 46 and at most 60: Declared strictfp. + ACC_SYNTHETIC = 0x1000 // Declared synthetic; not present in the source code. +}; +} // namespace Method + +typedef struct +{ + u2 attribute_name_index; + u4 attribute_length; + std::vector info; +} attribute_info; + +typedef struct +{ + u2 access_flags; + u2 name_index; + u2 descriptor_index; + u2 attributes_count; + std::vector attributes; +} method_info; + +typedef struct +{ + u2 access_flags; + u2 name_index; + u2 descriptor_index; + u2 attributes_count; + std::vector attributes; +} field_info; + +struct JavaClassFormat +{ + u4 magic; + u2 minor; + u2 major; + u2 constant_pool_count; + std::vector constant_pool; + u2 access_flags; + u2 this_class; + u2 super_class; + u2 interfaces_count; + std::vector interfaces; + u2 fields_count; + std::vector fields; + u2 methods_count; + std::vector methods; + u2 attributes_count; + std::vector attributes; +}; + +#endif \ No newline at end of file diff --git a/include/ConstantPoolTags/Tags.h b/include/ConstantPoolTags/Tags.h new file mode 100644 index 0000000..b20ddf5 --- /dev/null +++ b/include/ConstantPoolTags/Tags.h @@ -0,0 +1,90 @@ +#ifndef __JAVA_PARSER_CONSTANT_POOL_TAGS_TAGS_H +#define __JAVA_PARSER_CONSTANT_POOL_TAGS_TAGS_H + +#include +#include +#include + + +struct JavaClassFormat; + +namespace ConstantPoolTags +{ +enum class Tags : uint8_t +{ + Utf8 = 1, + Integer = 3, + Float, + Long, + Double, + Class, + String, + Fieldref, + Methodref, + InterfaceMethodref, + NameAndType, + MethodHandle = 15, + MethodType, + Dynamic, + InvokeDynamic, + Module, + Package +}; + + +struct ConstantPoolInfo +{ + ConstantPoolTags::Tags tag; +}; + +struct ConstantPool +{ + ConstantPoolTags::Tags tag; + ConstantPoolInfo info; +}; + +struct ConstantUtf8Info : ConstantPoolInfo +{ + ConstantPoolTags::Tags tag; + u2 length; + unsigned char* bytes; + // std::vector bytes; +}; + +struct ConstantClassInfo : ConstantPoolInfo +{ + ConstantPoolTags::Tags tag; + u2 name_index; +}; + +struct ConstantStringInfo : ConstantPoolInfo +{ + ConstantPoolTags::Tags tag; + u2 string_index; +}; + +struct ConstantFieldrefInfo : ConstantPoolInfo +{ + ConstantPoolTags::Tags tag; + u2 class_index; + u2 name_and_type_index; +}; + +struct ConstantMethodrefInfo : ConstantPoolInfo +{ + ConstantPoolTags::Tags tag; + u2 class_index; + u2 name_and_type_index; +}; + +struct ConstantNameAndTypeInfo : ConstantPoolInfo +{ + ConstantPoolTags::Tags tag; + u2 name_index; + u2 descriptor_index; +}; + +void ConstantPoolParser(ConstantPool &p, JavaClassFormat &jc); +} + +#endif \ No newline at end of file diff --git a/include/FieldInfo.h b/include/FieldInfo.h new file mode 100644 index 0000000..0d63532 --- /dev/null +++ b/include/FieldInfo.h @@ -0,0 +1,12 @@ +#ifndef __JAVA_PARSER_FIELD_INFO_H +#define __JAVA_PARSER_FIELD_INFO_H + +#include + +namespace FieldInfo +{ + +void FieldInfoParser(field_info &p, JavaClassFormat &jc); +} + +#endif \ No newline at end of file diff --git a/include/Globals.h b/include/Globals.h new file mode 100644 index 0000000..5c94bae --- /dev/null +++ b/include/Globals.h @@ -0,0 +1,17 @@ +#ifndef __JAVA_PARSER_GLOBALS_H +#define __JAVA_PARSER_GLOBALS_H + +#include +#include + +namespace Globals +{ +inline std::vector &buffer() +{ + static std::vector BUFFER; + return BUFFER; +} +} + +#endif + diff --git a/include/Methods.h b/include/Methods.h new file mode 100644 index 0000000..ef15fab --- /dev/null +++ b/include/Methods.h @@ -0,0 +1,11 @@ +#ifndef __JAVA_PARSER_METHOD_INFO_H +#define __JAVA_PARSER_METHOD_INFO_H + +#include + +namespace Methods +{ +void MethodParser(method_info &p, JavaClassFormat &jc); +} + +#endif \ No newline at end of file diff --git a/include/SpecTypes.h b/include/SpecTypes.h new file mode 100644 index 0000000..c2379b0 --- /dev/null +++ b/include/SpecTypes.h @@ -0,0 +1,11 @@ +#ifndef __JAVA_PARSER_SPEC_TYPES_H +#define __JAVA_PARSER_SPEC_TYPES_H + +#include +#include + +typedef BigEndian u4; +typedef BigEndian u2; +typedef BigEndian u1; + +#endif \ No newline at end of file diff --git a/include/Types.h b/include/Types.h new file mode 100644 index 0000000..a83214a --- /dev/null +++ b/include/Types.h @@ -0,0 +1,6 @@ +#ifndef __JAVA_PARSER_TYPES_H +#define __JAVA_PARSER_TYPES_H + +#define ALWAYS_INLINE __attribute__((always_inline)) inline + +#endif \ No newline at end of file diff --git a/include/Utils/Utils.h b/include/Utils/Utils.h new file mode 100644 index 0000000..2ceddba --- /dev/null +++ b/include/Utils/Utils.h @@ -0,0 +1,138 @@ +#ifndef __JAVA_PARSER_UTILS_UTILS_H +#define __JAVA_PARSER_UTILS_UTILS_H + +#include +#include +#include +#include + +namespace Utils +{ + +template +ALWAYS_INLINE T M_POW(T x, X power) +{ + T ret = 1; + + if (power == 0) + return 1; + + + + for (int i = 0; i < power; i++) + { + ret *= x; + } + + if (power < 0) + { + for (int i = (int)power; i > 0; i++) + { + ret *= 1 / x; + } + } + + return ret; +} + +template +ALWAYS_INLINE T Hex2Int(T x) +{ + T ret = 0; + int digits = 0; + + while (x != 0) + { + T a = x % 10; + ret += a * M_POW(16, digits); + x = (int)(x / 10); + digits += 1; + } + + return ret; +} + +template +ALWAYS_INLINE const char* Int2Hex(T x) +{ + constexpr const char *digits[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"}; + + std::vector ret; + + while (x != 0) + { + T rem = x % 16; + x = (int)(x / 16); + + ret.push_back(digits[rem]); + } + + for (int i = 0; i < ret.size() / 2; i++) + { + char tmp = ret[i]; + ret[i] = ret[ret.size() - i]; + ret[ret.size() - i] = tmp; + } + + const char *data = ret.data(); + + return data; +} + +template +ALWAYS_INLINE std::vector Read(std::vector &vec, int start, int end) +{ + std::vector ret; + + for (int i = start; i < end; i++) + { + ret.push_back(vec.at(i)); + } + + return ret; +} + +template +ALWAYS_INLINE std::vector ReadFromStart(std::vector &vec, int end) +{ + std::vector ret = Read(vec, 0, end); + for (int i = 0; i < end; i++) + vec.erase(vec.begin()); + return ret; +} + + +template +ALWAYS_INLINE T vecToVal(std::vector &vec) +{ + if (vec.size() > sizeof(T)) + { + throw std::out_of_range("Provided vector larger than type to convert to."); + } + + T ret = 0; + + for (int i = vec.size() - 1; i >= 0; i--) + { + ret |= vec.at(i) << (i * 8); + } + + return ret; +} + +template +ALWAYS_INLINE T ReadFromStartIntoVal(std::vector &vec, int end) +{ + std::vector val = ReadFromStart(vec, end); + return vecToVal(val); +} + +template +ALWAYS_INLINE T ReadFromStartIntoVal(std::vector &vec) +{ + std::vector val = ReadFromStart(vec, sizeof(T)); + return vecToVal(val); +} +} + +#endif \ No newline at end of file diff --git a/samples/Hello.java b/samples/Hello.java new file mode 100644 index 0000000..c1886a3 --- /dev/null +++ b/samples/Hello.java @@ -0,0 +1,13 @@ +public class Hello +{ + public static void main(String[] args) + { + final int i = 0; + final double j = 1.0; + final String k = "Hello World1"; + System.out.println("Hello World"); + System.out.println(i); + System.out.println(j); + System.out.println(k); + } +} \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..4cca843 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,9 @@ +add_subdirectory(ConstantPoolTags) +add_subdirectory(FieldInfo) +add_subdirectory(Method) + +set(CONSTANT_POOL_TAG_SRC + ${CONSTANT_POOL_TAG_SRC} + + PARENT_SCOPE +) \ No newline at end of file diff --git a/src/ConstantPoolTags/CMakeLists.txt b/src/ConstantPoolTags/CMakeLists.txt new file mode 100644 index 0000000..a50e2e8 --- /dev/null +++ b/src/ConstantPoolTags/CMakeLists.txt @@ -0,0 +1,24 @@ +set(CWD ${CMAKE_CURRENT_LIST_DIR}) + +set(CONSTANT_POOL_TAG_SRC + ${CWD}/Class.cpp + ${CWD}/Double.cpp + ${CWD}/Dynamic.cpp + ${CWD}/Fieldref.cpp + ${CWD}/Float.cpp + ${CWD}/Integer.cpp + ${CWD}/InterfaceMethodref.cpp + ${CWD}/InvokeDynamic.cpp + ${CWD}/Long.cpp + ${CWD}/MethodHandle.cpp + ${CWD}/MethodType.cpp + ${CWD}/Methodref.cpp + ${CWD}/Module.cpp + ${CWD}/NameAndType.cpp + ${CWD}/Package.cpp + ${CWD}/String.cpp + ${CWD}/Utf8.cpp + ${CWD}/PoolParser.cpp + + PARENT_SCOPE +) \ No newline at end of file diff --git a/src/ConstantPoolTags/Class.cpp b/src/ConstantPoolTags/Class.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/ConstantPoolTags/Double.cpp b/src/ConstantPoolTags/Double.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/ConstantPoolTags/Dynamic.cpp b/src/ConstantPoolTags/Dynamic.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/ConstantPoolTags/Fieldref.cpp b/src/ConstantPoolTags/Fieldref.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/ConstantPoolTags/Float.cpp b/src/ConstantPoolTags/Float.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/ConstantPoolTags/Integer.cpp b/src/ConstantPoolTags/Integer.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/ConstantPoolTags/InterfaceMethodref.cpp b/src/ConstantPoolTags/InterfaceMethodref.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/ConstantPoolTags/InvokeDynamic.cpp b/src/ConstantPoolTags/InvokeDynamic.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/ConstantPoolTags/Long.cpp b/src/ConstantPoolTags/Long.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/ConstantPoolTags/MethodHandle.cpp b/src/ConstantPoolTags/MethodHandle.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/ConstantPoolTags/MethodType.cpp b/src/ConstantPoolTags/MethodType.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/ConstantPoolTags/Methodref.cpp b/src/ConstantPoolTags/Methodref.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/ConstantPoolTags/Module.cpp b/src/ConstantPoolTags/Module.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/ConstantPoolTags/NameAndType.cpp b/src/ConstantPoolTags/NameAndType.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/ConstantPoolTags/Package.cpp b/src/ConstantPoolTags/Package.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/ConstantPoolTags/PoolParser.cpp b/src/ConstantPoolTags/PoolParser.cpp new file mode 100644 index 0000000..411dddc --- /dev/null +++ b/src/ConstantPoolTags/PoolParser.cpp @@ -0,0 +1,170 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +void ConstantPoolTags::ConstantPoolParser(ConstantPool &p, JavaClassFormat &jc) +{ + switch (p.tag) + { + case Tags::Utf8: { + // std::cout << "FIXME: Implement Utf8 Constant Pool Tag" << std::endl; + ConstantUtf8Info ref = static_cast(p.info); + std::vector length = Utils::ReadFromStart(Globals::buffer(), 2); + ref.tag = p.tag; + ref.length = Utils::vecToVal(length); + + unsigned char x = Utils::ReadFromStartIntoVal(Globals::buffer(), 1); + bool valid = true; + + ref.bytes = new unsigned char[ref.length.ToHostFormat()]; + + for (int i = 0; i < ref.length.ToHostFormat(); i++) + { + if ((x & 0x80) == 0) + { + ref.bytes[i] = x; + } + else if ((x & 0x800) == 0) + { + unsigned char y = Utils::ReadFromStartIntoVal(Globals::buffer(), 1); + ref.bytes[i] = ((x & 0x1f) << 6) + (y & 0x3f); + } + else if ((x & 0x10000) == 0) + { + unsigned char y = Utils::ReadFromStartIntoVal(Globals::buffer(), 1); + unsigned char z = Utils::ReadFromStartIntoVal(Globals::buffer(), 1); + ref.bytes[i] = ((x & 0xf) << 12) + ((y & 0x3f) << 6) + (z & 0x3f); + } + else + { + std::cerr << "Invalid character: " << x << std::endl; + exit(1); + } + + if (i != ref.length.ToHostFormat() - 1) + x = Utils::ReadFromStartIntoVal(Globals::buffer(), 1); + } + + p.info = static_cast(ref); + jc.constant_pool.push_back(p); + + break; + } + case Tags::Integer: + std::cout << "FIXME: Implement Integer Constant Pool Tag" << std::endl; + exit(EXIT_SUCCESS); + case Tags::Float: + std::cout << "FIXME: Implement Float Constant Pool Tag" << std::endl; + exit(EXIT_SUCCESS); + case Tags::Long: + std::cout << "FIXME: Implement Long Constant Pool Tag" << std::endl; + exit(EXIT_SUCCESS); + case Tags::Double: + std::cout << "FIXME: Implement Double Constant Pool Tag" << std::endl; + exit(EXIT_SUCCESS); + case Tags::Class: { + // std::cout << "FIXME: Implement Class Constant Pool Tag" << std::endl; + ConstantClassInfo ref = static_cast(p.info); + // std::vector name_index = Utils::ReadFromStart(Globals::buffer(), 2); + ref.tag = p.tag; + ref.name_index = Utils::ReadFromStartIntoVal(Globals::buffer(), 2); + + p.info = static_cast(ref); + jc.constant_pool.push_back(p); + + // exit(EXIT_SUCCESS); + break; + } + case Tags::String: { + // std::cout << "FIXME: Implement String Constant Pool Tag" << std::endl; + ConstantStringInfo ref = static_cast(p.info); + ref.tag = p.tag; + // std::cout << std::dec << Globals::buffer().size() << std::endl; + ref.string_index = Utils::ReadFromStartIntoVal(Globals::buffer(), 2); + + // std::cout << std::dec << ref.string_index.ToHostFormat() << std::endl; + p.info = static_cast(ref); + + // std::cout << Globals::buffer().size() << std::endl; + + jc.constant_pool.push_back(p); + + // exit(EXIT_SUCCESS); + break; + } + case Tags::Fieldref: { + // std::cout << "FIXME: Implement Fieldref Constant Pool Tag" << std::endl; + ConstantFieldrefInfo ref = static_cast(p.info); + ref.tag = p.tag; + ref.class_index = Utils::ReadFromStartIntoVal(Globals::buffer(), 2); + ref.name_and_type_index = Utils::ReadFromStartIntoVal(Globals::buffer(), 2); + + p.info = static_cast(ref); + + jc.constant_pool.push_back(p); + + // exit(EXIT_SUCCESS); + break; + } + case Tags::Methodref: + { + // std::cout << "FIXME: Implement Methodref Constant Pool Tag" << std::endl; + // ConstantMethodrefInfo ref = *reinterpret_cast(p->info); + ConstantMethodrefInfo ref = static_cast(p.info); + + ref.tag = p.tag; + ref.class_index = Utils::ReadFromStartIntoVal(Globals::buffer(), 2); + ref.name_and_type_index = Utils::ReadFromStartIntoVal(Globals::buffer(), 2); + + p.info = static_cast(ref); + + jc.constant_pool.push_back(p); + + // exit(EXIT_SUCCESS); + break; + } + case Tags::InterfaceMethodref: + std::cout << "FIXME: Implement InterfaceMethodref Constant Pool Tag" << std::endl; + exit(EXIT_SUCCESS); + case Tags::NameAndType: { + // std::cout << "FIXME: Implement NameAndType Constant Pool Tag" << std::endl; + ConstantNameAndTypeInfo ref = static_cast(p.info); + + ref.tag = p.tag; + ref.name_index = Utils::ReadFromStartIntoVal(Globals::buffer(), 2); + ref.descriptor_index = Utils::ReadFromStartIntoVal(Globals::buffer(), 2); + + p.info = static_cast(ref); + jc.constant_pool.push_back(p); + + // exit(EXIT_SUCCESS); + break; + } + case Tags::MethodHandle: + std::cout << "FIXME: Implement MethodHandle Constant Pool Tag" << std::endl; + exit(EXIT_SUCCESS); + case Tags::MethodType: + std::cout << "FIXME: Implement MethodType Constant Pool Tag" << std::endl; + exit(EXIT_SUCCESS); + case Tags::Dynamic: + std::cout << "FIXME: Implement Dynamic Constant Pool Tag" << std::endl; + exit(EXIT_SUCCESS); + case Tags::InvokeDynamic: + std::cout << "FIXME: Implement InvokeDynamic Constant Pool Tag" << std::endl; + exit(EXIT_SUCCESS); + case Tags::Module: + std::cout << "FIXME: Implement Module Constant Pool Tag" << std::endl; + exit(EXIT_SUCCESS); + case Tags::Package: + std::cout << "FIXME: Implement Package Constant Pool Tag" << std::endl; + exit(EXIT_SUCCESS); + default: + std::cerr << "Unknown tag: " << std::hex << (int)p.tag << " @ byte " << std::dec << Globals::buffer().size() << " from end of class file" << std::endl; + exit(EXIT_FAILURE); + } +} \ No newline at end of file diff --git a/src/ConstantPoolTags/String.cpp b/src/ConstantPoolTags/String.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/ConstantPoolTags/Utf8.cpp b/src/ConstantPoolTags/Utf8.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/FieldInfo/CMakeLists.txt b/src/FieldInfo/CMakeLists.txt new file mode 100644 index 0000000..cd4038b --- /dev/null +++ b/src/FieldInfo/CMakeLists.txt @@ -0,0 +1,9 @@ +set(CWD ${CMAKE_CURRENT_LIST_DIR}) + +set(CONSTANT_POOL_TAG_SRC + ${CONSTANT_POOL_TAG_SRC} + + ${CWD}/FieldInfoParser.cpp + + PARENT_SCOPE +) \ No newline at end of file diff --git a/src/FieldInfo/FieldInfoParser.cpp b/src/FieldInfo/FieldInfoParser.cpp new file mode 100644 index 0000000..312a995 --- /dev/null +++ b/src/FieldInfo/FieldInfoParser.cpp @@ -0,0 +1,19 @@ +#include +#include +#include +#include +#include +#include + +void FieldInfo::FieldInfoParser(field_info &p, JavaClassFormat &jc) +{ + p.access_flags = Utils::ReadFromStartIntoVal(Globals::buffer()); + + p.name_index = Utils::ReadFromStartIntoVal(Globals::buffer()); + p.descriptor_index = Utils::ReadFromStartIntoVal(Globals::buffer()); + p.attributes_count = Utils::ReadFromStartIntoVal(Globals::buffer()); + + // FIXME: Implement attributes[] + + jc.fields.push_back(p); +} \ No newline at end of file diff --git a/src/Main.cpp b/src/Main.cpp new file mode 100644 index 0000000..34b6dba --- /dev/null +++ b/src/Main.cpp @@ -0,0 +1,157 @@ +#include "FieldInfo.h" +#include "Methods.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define JVM_STACK_SIZE 4096 + +int stack[JVM_STACK_SIZE]; + +int main(int argc, char **argv) +{ + if (argc < 2) + { + std::cerr << "Usage " << argv[0] << " " << std::endl; + return 1; + } + + for (int i = 0; i < JVM_STACK_SIZE; i++) + { + stack[i] = 0; + } + std::ifstream f; + JavaClassFormat jc; + f.open(argv[1], std::ios::binary); + + ConstantPoolTags::ConstantPool cp; + + if (!f.is_open()) + { + std::cerr << "Failed to open " << argv[1] << std::endl; + return 1; + } + + // std::vector Globals::buffer(std::istreambuf_iterator(f), {}); + Globals::buffer() = std::vector(std::istreambuf_iterator(f), {}); + f.close(); + + int size = Globals::buffer().size(); + + jc.magic = Utils::ReadFromStartIntoVal(Globals::buffer(), 4); + + assert(jc.magic.ToHostFormat() == 0xcafebabe); + + jc.minor = Utils::ReadFromStartIntoVal(Globals::buffer(), 2); + + jc.major = Utils::ReadFromStartIntoVal(Globals::buffer(), 2); + + jc.constant_pool_count = Utils::ReadFromStartIntoVal(Globals::buffer(), 2); + + std::cout << "Magic: 0x" << std::hex << jc.magic.ToHostFormat() << std::endl; + std::cout << "Minor: " << Utils::Hex2Int(jc.minor.ToHostFormat()) << std::endl; + std::cout << "Major: " << Utils::Hex2Int(jc.major.ToHostFormat()) << std::endl; + std::cout << "Constant Pool Count: " + << Utils::Hex2Int(jc.constant_pool_count.ToHostFormat()) << std::endl; + + for (int i = 0; i < jc.constant_pool_count.ToHostFormat() - 1; i++) + { + ConstantPoolTags::ConstantPool cp; + cp.tag = (ConstantPoolTags::Tags)Utils::ReadFromStartIntoVal(Globals::buffer(), 1); + + ConstantPoolTags::ConstantPoolParser(cp, jc); + } + jc.access_flags = Utils::ReadFromStartIntoVal(Globals::buffer(), 2); + jc.this_class = Utils::ReadFromStartIntoVal(Globals::buffer(), 2); + jc.super_class = Utils::ReadFromStartIntoVal(Globals::buffer(), 2); + jc.interfaces_count = Utils::ReadFromStartIntoVal(Globals::buffer(), 2); + + assert(jc.this_class.ToHostFormat() >= 0); + assert(jc.super_class.ToHostFormat() >= 0); + + assert(jc.constant_pool.size() > jc.this_class.ToHostFormat()); + assert(jc.constant_pool[jc.this_class.ToHostFormat() - 1].tag == ConstantPoolTags::Tags::Class); + + if (jc.super_class.ToHostFormat() != 0) + { + // For a class, the value of the super_class item either must be zero or + // must be a valid index into the constant_pool table. If the value of + // the super_class item is nonzero, the constant_pool entry at that index + // must be a CONSTANT_Class_info structure representing the direct superclass + // of the class defined by this class file. Neither the direct superclass nor + // any of its superclasses may have the ACC_FINAL flag set in the access_flags + // item of its ClassFile structure. + + // FIXME: Finish implementing the above comment. + assert(jc.constant_pool.size() > jc.super_class.ToHostFormat()); + assert(jc.constant_pool[jc.super_class.ToHostFormat() - 1].tag == ConstantPoolTags::Tags::Class); + } + else + { + // FIXME: Implement zero super_class checks + } + + std::cout << "Access Flags: " << jc.access_flags.ToHostFormat() << std::endl; + std::cout << "This Class: " << std::dec << jc.this_class.ToHostFormat() << std::endl; + std::cout << "Super Class: " << jc.super_class.ToHostFormat() << std::endl; + std::cout << "Interfaces Count: " << std::dec << jc.interfaces_count.ToHostFormat() << std::endl; + + if (jc.access_flags.ToHostFormat() >= (int)JavaClass::ACCESS_FLAGS::ACC_MODULE) + { + assert(jc.access_flags.ToHostFormat() == (int)JavaClass::ACCESS_FLAGS::ACC_MODULE); + // Conditions for when jc.access_flags == JavaClass::ACCESS_FLAGS::ACC_MODULE + // major_version, minor_version: ≥ 53.0 (i.e., Java SE 9 and above) + assert(jc.major.ToHostFormat() >= 53); + assert(jc.minor.ToHostFormat() >= 0); + + } + // std::cout << std::dec << (int)(jc.constant_pool[jc.this_class.ToHostFormat()].info.tag) << std::endl; + + // std::cout << "" << std::hex << size - Globals::buffer().size() << std::endl; + + for (int i = 0; i < jc.interfaces_count.ToHostFormat(); i++) + { + uint16_t data = Utils::ReadFromStartIntoVal(Globals::buffer(), 2); + + jc.interfaces.push_back(data); + } + + jc.fields_count = Utils::ReadFromStartIntoVal(Globals::buffer(), 2); + + std::cout << "Fields Count: " << jc.fields_count.ToHostFormat() << std::endl; + + for (int i = 0; i < jc.fields_count.ToHostFormat(); i++) + { + field_info f; + FieldInfo::FieldInfoParser(f, jc); + } + + jc.methods_count = Utils::ReadFromStartIntoVal(Globals::buffer()); + + for (int i = 0; i < jc.methods_count.ToHostFormat(); i++) + { + method_info m; + Methods::MethodParser(m, jc); + + // std::cout << std::hex << size - Globals::buffer().size() << std::endl; + } + + for (int i = 0; i < jc.constant_pool_count.ToHostFormat() - 1; i++) + { + std::cout << "(" << i << ") " << (int)jc.constant_pool[i].tag << std::endl; + } + + std::cout << &jc.constant_pool[30].info << std::endl; + // delete[] ((ConstantPoolTags::ConstantUtf8Info*)(&jc.constant_pool[30].info))->bytes; + + // std::cout << jc.methods_count.ToHostFormat() << std::endl; + + return 0; +} \ No newline at end of file diff --git a/src/Method/CMakeLists.txt b/src/Method/CMakeLists.txt new file mode 100644 index 0000000..a0d2a55 --- /dev/null +++ b/src/Method/CMakeLists.txt @@ -0,0 +1,9 @@ +set(CWD ${CMAKE_CURRENT_LIST_DIR}) + +set(CONSTANT_POOL_TAG_SRC + ${CONSTANT_POOL_TAG_SRC} + + ${CWD}/MethodParser.cpp + + PARENT_SCOPE +) \ No newline at end of file diff --git a/src/Method/MethodParser.cpp b/src/Method/MethodParser.cpp new file mode 100644 index 0000000..93c21f9 --- /dev/null +++ b/src/Method/MethodParser.cpp @@ -0,0 +1,45 @@ +#include "ConstantPoolTags/Tags.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void Methods::MethodParser(method_info &p, JavaClassFormat &jc) +{ + p.access_flags = Utils::ReadFromStartIntoVal(Globals::buffer()); + p.name_index = Utils::ReadFromStartIntoVal(Globals::buffer()); + p.descriptor_index = Utils::ReadFromStartIntoVal(Globals::buffer()); + p.attributes_count = Utils::ReadFromStartIntoVal(Globals::buffer()); + + // std::cout << p.attributes_count.ToHostFormat() << std::endl; + + // FIXME: Implement attributes[] + + for (int i = 0; i < p.attributes_count.ToHostFormat(); i++) + { + attribute_info a; + a.attribute_name_index = Utils::ReadFromStartIntoVal(Globals::buffer()); + a.attribute_length = Utils::ReadFromStartIntoVal(Globals::buffer()); + + for (int j = 0; j < a.attribute_length.ToHostFormat(); j++) + { + a.info.push_back(Utils::ReadFromStartIntoVal(Globals::buffer())); + } + + std::cout << a.attribute_name_index.ToHostFormat() << std::endl; + // std::cout << a.info.size() << std::endl; + } + + // if ((p.access_flags.ToHostFormat() & (int)Method::ACCESS_FLAGS::ACC_NATIVE) == 0 && + // (p.access_flags.ToHostFormat() & (int)Method::ACCESS_FLAGS::ACC_ABSTRACT) == 0) + // { + // std::cout << "Not Set" << std::endl; + // } + + jc.methods.push_back(p); +} \ No newline at end of file