Initial Commit
This commit is contained in:
parent
0da888414c
commit
3429da6282
21
CMakeLists.txt
Normal file
21
CMakeLists.txt
Normal file
@ -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")
|
58
include/BigEndian.h
Normal file
58
include/BigEndian.h
Normal file
@ -0,0 +1,58 @@
|
||||
#ifndef __JAVA_PARSER_BIG_ENDIAN_H
|
||||
#define __JAVA_PARSER_BIG_ENDIAN_H
|
||||
|
||||
#include <Types.h>
|
||||
#include <cstddef>
|
||||
|
||||
template <typename T>
|
||||
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<char*>(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
|
105
include/ClassFormat.h
Normal file
105
include/ClassFormat.h
Normal file
@ -0,0 +1,105 @@
|
||||
#ifndef __JAVA_PARSER_CLASS_FORMAT_H
|
||||
#define __JAVA_PARSER_CLASS_FORMAT_H
|
||||
|
||||
#include <SpecTypes.h>
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
#include <ConstantPoolTags/Tags.h>
|
||||
|
||||
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<u1> info;
|
||||
} attribute_info;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u2 access_flags;
|
||||
u2 name_index;
|
||||
u2 descriptor_index;
|
||||
u2 attributes_count;
|
||||
std::vector<attribute_info> attributes;
|
||||
} method_info;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u2 access_flags;
|
||||
u2 name_index;
|
||||
u2 descriptor_index;
|
||||
u2 attributes_count;
|
||||
std::vector<attribute_info> attributes;
|
||||
} field_info;
|
||||
|
||||
struct JavaClassFormat
|
||||
{
|
||||
u4 magic;
|
||||
u2 minor;
|
||||
u2 major;
|
||||
u2 constant_pool_count;
|
||||
std::vector<ConstantPoolTags::ConstantPool> constant_pool;
|
||||
u2 access_flags;
|
||||
u2 this_class;
|
||||
u2 super_class;
|
||||
u2 interfaces_count;
|
||||
std::vector<u2> interfaces;
|
||||
u2 fields_count;
|
||||
std::vector<field_info> fields;
|
||||
u2 methods_count;
|
||||
std::vector<method_info> methods;
|
||||
u2 attributes_count;
|
||||
std::vector<attribute_info> attributes;
|
||||
};
|
||||
|
||||
#endif
|
90
include/ConstantPoolTags/Tags.h
Normal file
90
include/ConstantPoolTags/Tags.h
Normal file
@ -0,0 +1,90 @@
|
||||
#ifndef __JAVA_PARSER_CONSTANT_POOL_TAGS_TAGS_H
|
||||
#define __JAVA_PARSER_CONSTANT_POOL_TAGS_TAGS_H
|
||||
|
||||
#include <SpecTypes.h>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
|
||||
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<unsigned char> 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
|
12
include/FieldInfo.h
Normal file
12
include/FieldInfo.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef __JAVA_PARSER_FIELD_INFO_H
|
||||
#define __JAVA_PARSER_FIELD_INFO_H
|
||||
|
||||
#include <ClassFormat.h>
|
||||
|
||||
namespace FieldInfo
|
||||
{
|
||||
|
||||
void FieldInfoParser(field_info &p, JavaClassFormat &jc);
|
||||
}
|
||||
|
||||
#endif
|
17
include/Globals.h
Normal file
17
include/Globals.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef __JAVA_PARSER_GLOBALS_H
|
||||
#define __JAVA_PARSER_GLOBALS_H
|
||||
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
namespace Globals
|
||||
{
|
||||
inline std::vector<uint8_t> &buffer()
|
||||
{
|
||||
static std::vector<uint8_t> BUFFER;
|
||||
return BUFFER;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
11
include/Methods.h
Normal file
11
include/Methods.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef __JAVA_PARSER_METHOD_INFO_H
|
||||
#define __JAVA_PARSER_METHOD_INFO_H
|
||||
|
||||
#include <ClassFormat.h>
|
||||
|
||||
namespace Methods
|
||||
{
|
||||
void MethodParser(method_info &p, JavaClassFormat &jc);
|
||||
}
|
||||
|
||||
#endif
|
11
include/SpecTypes.h
Normal file
11
include/SpecTypes.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef __JAVA_PARSER_SPEC_TYPES_H
|
||||
#define __JAVA_PARSER_SPEC_TYPES_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <BigEndian.h>
|
||||
|
||||
typedef BigEndian<uint32_t> u4;
|
||||
typedef BigEndian<uint16_t> u2;
|
||||
typedef BigEndian<uint8_t> u1;
|
||||
|
||||
#endif
|
6
include/Types.h
Normal file
6
include/Types.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef __JAVA_PARSER_TYPES_H
|
||||
#define __JAVA_PARSER_TYPES_H
|
||||
|
||||
#define ALWAYS_INLINE __attribute__((always_inline)) inline
|
||||
|
||||
#endif
|
138
include/Utils/Utils.h
Normal file
138
include/Utils/Utils.h
Normal file
@ -0,0 +1,138 @@
|
||||
#ifndef __JAVA_PARSER_UTILS_UTILS_H
|
||||
#define __JAVA_PARSER_UTILS_UTILS_H
|
||||
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
#include <SpecTypes.h>
|
||||
|
||||
namespace Utils
|
||||
{
|
||||
|
||||
template <typename T, typename X>
|
||||
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<typename T = unsigned int>
|
||||
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 <typename T>
|
||||
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<char> 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 <typename T>
|
||||
ALWAYS_INLINE std::vector<T> Read(std::vector<T> &vec, int start, int end)
|
||||
{
|
||||
std::vector<T> ret;
|
||||
|
||||
for (int i = start; i < end; i++)
|
||||
{
|
||||
ret.push_back(vec.at(i));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ALWAYS_INLINE std::vector<T> ReadFromStart(std::vector<T> &vec, int end)
|
||||
{
|
||||
std::vector<T> ret = Read(vec, 0, end);
|
||||
for (int i = 0; i < end; i++)
|
||||
vec.erase(vec.begin());
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
template <typename T, typename vec_type=uint8_t>
|
||||
ALWAYS_INLINE T vecToVal(std::vector<vec_type> &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 <typename T, typename vec_type>
|
||||
ALWAYS_INLINE T ReadFromStartIntoVal(std::vector<vec_type> &vec, int end)
|
||||
{
|
||||
std::vector<uint8_t> val = ReadFromStart<vec_type>(vec, end);
|
||||
return vecToVal<T>(val);
|
||||
}
|
||||
|
||||
template <typename T, typename vec_type>
|
||||
ALWAYS_INLINE T ReadFromStartIntoVal(std::vector<vec_type> &vec)
|
||||
{
|
||||
std::vector<uint8_t> val = ReadFromStart<vec_type>(vec, sizeof(T));
|
||||
return vecToVal<T>(val);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
13
samples/Hello.java
Normal file
13
samples/Hello.java
Normal file
@ -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);
|
||||
}
|
||||
}
|
9
src/CMakeLists.txt
Normal file
9
src/CMakeLists.txt
Normal file
@ -0,0 +1,9 @@
|
||||
add_subdirectory(ConstantPoolTags)
|
||||
add_subdirectory(FieldInfo)
|
||||
add_subdirectory(Method)
|
||||
|
||||
set(CONSTANT_POOL_TAG_SRC
|
||||
${CONSTANT_POOL_TAG_SRC}
|
||||
|
||||
PARENT_SCOPE
|
||||
)
|
24
src/ConstantPoolTags/CMakeLists.txt
Normal file
24
src/ConstantPoolTags/CMakeLists.txt
Normal file
@ -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
|
||||
)
|
0
src/ConstantPoolTags/Class.cpp
Normal file
0
src/ConstantPoolTags/Class.cpp
Normal file
0
src/ConstantPoolTags/Double.cpp
Normal file
0
src/ConstantPoolTags/Double.cpp
Normal file
0
src/ConstantPoolTags/Dynamic.cpp
Normal file
0
src/ConstantPoolTags/Dynamic.cpp
Normal file
0
src/ConstantPoolTags/Fieldref.cpp
Normal file
0
src/ConstantPoolTags/Fieldref.cpp
Normal file
0
src/ConstantPoolTags/Float.cpp
Normal file
0
src/ConstantPoolTags/Float.cpp
Normal file
0
src/ConstantPoolTags/Integer.cpp
Normal file
0
src/ConstantPoolTags/Integer.cpp
Normal file
0
src/ConstantPoolTags/InterfaceMethodref.cpp
Normal file
0
src/ConstantPoolTags/InterfaceMethodref.cpp
Normal file
0
src/ConstantPoolTags/InvokeDynamic.cpp
Normal file
0
src/ConstantPoolTags/InvokeDynamic.cpp
Normal file
0
src/ConstantPoolTags/Long.cpp
Normal file
0
src/ConstantPoolTags/Long.cpp
Normal file
0
src/ConstantPoolTags/MethodHandle.cpp
Normal file
0
src/ConstantPoolTags/MethodHandle.cpp
Normal file
0
src/ConstantPoolTags/MethodType.cpp
Normal file
0
src/ConstantPoolTags/MethodType.cpp
Normal file
0
src/ConstantPoolTags/Methodref.cpp
Normal file
0
src/ConstantPoolTags/Methodref.cpp
Normal file
0
src/ConstantPoolTags/Module.cpp
Normal file
0
src/ConstantPoolTags/Module.cpp
Normal file
0
src/ConstantPoolTags/NameAndType.cpp
Normal file
0
src/ConstantPoolTags/NameAndType.cpp
Normal file
0
src/ConstantPoolTags/Package.cpp
Normal file
0
src/ConstantPoolTags/Package.cpp
Normal file
170
src/ConstantPoolTags/PoolParser.cpp
Normal file
170
src/ConstantPoolTags/PoolParser.cpp
Normal file
@ -0,0 +1,170 @@
|
||||
#include <Globals.h>
|
||||
#include <ConstantPoolTags/Tags.h>
|
||||
#include <Utils/Utils.h>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <ClassFormat.h>
|
||||
#include <ostream>
|
||||
|
||||
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<ConstantUtf8Info>(p.info);
|
||||
std::vector<uint8_t> length = Utils::ReadFromStart(Globals::buffer(), 2);
|
||||
ref.tag = p.tag;
|
||||
ref.length = Utils::vecToVal<uint16_t>(length);
|
||||
|
||||
unsigned char x = Utils::ReadFromStartIntoVal<unsigned char>(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<unsigned char>(Globals::buffer(), 1);
|
||||
ref.bytes[i] = ((x & 0x1f) << 6) + (y & 0x3f);
|
||||
}
|
||||
else if ((x & 0x10000) == 0)
|
||||
{
|
||||
unsigned char y = Utils::ReadFromStartIntoVal<unsigned char>(Globals::buffer(), 1);
|
||||
unsigned char z = Utils::ReadFromStartIntoVal<unsigned char>(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<unsigned char>(Globals::buffer(), 1);
|
||||
}
|
||||
|
||||
p.info = static_cast<ConstantPoolInfo>(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<ConstantClassInfo>(p.info);
|
||||
// std::vector<uint8_t> name_index = Utils::ReadFromStart(Globals::buffer(), 2);
|
||||
ref.tag = p.tag;
|
||||
ref.name_index = Utils::ReadFromStartIntoVal<uint16_t>(Globals::buffer(), 2);
|
||||
|
||||
p.info = static_cast<ConstantPoolInfo>(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<ConstantStringInfo>(p.info);
|
||||
ref.tag = p.tag;
|
||||
// std::cout << std::dec << Globals::buffer().size() << std::endl;
|
||||
ref.string_index = Utils::ReadFromStartIntoVal<uint16_t>(Globals::buffer(), 2);
|
||||
|
||||
// std::cout << std::dec << ref.string_index.ToHostFormat() << std::endl;
|
||||
p.info = static_cast<ConstantPoolInfo>(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<ConstantFieldrefInfo>(p.info);
|
||||
ref.tag = p.tag;
|
||||
ref.class_index = Utils::ReadFromStartIntoVal<uint16_t>(Globals::buffer(), 2);
|
||||
ref.name_and_type_index = Utils::ReadFromStartIntoVal<uint16_t>(Globals::buffer(), 2);
|
||||
|
||||
p.info = static_cast<ConstantPoolInfo>(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<ConstantMethodrefInfo*>(p->info);
|
||||
ConstantMethodrefInfo ref = static_cast<ConstantMethodrefInfo>(p.info);
|
||||
|
||||
ref.tag = p.tag;
|
||||
ref.class_index = Utils::ReadFromStartIntoVal<uint16_t>(Globals::buffer(), 2);
|
||||
ref.name_and_type_index = Utils::ReadFromStartIntoVal<uint16_t>(Globals::buffer(), 2);
|
||||
|
||||
p.info = static_cast<ConstantPoolInfo>(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<ConstantNameAndTypeInfo>(p.info);
|
||||
|
||||
ref.tag = p.tag;
|
||||
ref.name_index = Utils::ReadFromStartIntoVal<uint16_t>(Globals::buffer(), 2);
|
||||
ref.descriptor_index = Utils::ReadFromStartIntoVal<uint16_t>(Globals::buffer(), 2);
|
||||
|
||||
p.info = static_cast<ConstantPoolInfo>(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);
|
||||
}
|
||||
}
|
0
src/ConstantPoolTags/String.cpp
Normal file
0
src/ConstantPoolTags/String.cpp
Normal file
0
src/ConstantPoolTags/Utf8.cpp
Normal file
0
src/ConstantPoolTags/Utf8.cpp
Normal file
9
src/FieldInfo/CMakeLists.txt
Normal file
9
src/FieldInfo/CMakeLists.txt
Normal file
@ -0,0 +1,9 @@
|
||||
set(CWD ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
set(CONSTANT_POOL_TAG_SRC
|
||||
${CONSTANT_POOL_TAG_SRC}
|
||||
|
||||
${CWD}/FieldInfoParser.cpp
|
||||
|
||||
PARENT_SCOPE
|
||||
)
|
19
src/FieldInfo/FieldInfoParser.cpp
Normal file
19
src/FieldInfo/FieldInfoParser.cpp
Normal file
@ -0,0 +1,19 @@
|
||||
#include <SpecTypes.h>
|
||||
#include <Utils/Utils.h>
|
||||
#include <Globals.h>
|
||||
#include <FieldInfo.h>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
void FieldInfo::FieldInfoParser(field_info &p, JavaClassFormat &jc)
|
||||
{
|
||||
p.access_flags = Utils::ReadFromStartIntoVal<uint16_t>(Globals::buffer());
|
||||
|
||||
p.name_index = Utils::ReadFromStartIntoVal<uint16_t>(Globals::buffer());
|
||||
p.descriptor_index = Utils::ReadFromStartIntoVal<uint16_t>(Globals::buffer());
|
||||
p.attributes_count = Utils::ReadFromStartIntoVal<uint16_t>(Globals::buffer());
|
||||
|
||||
// FIXME: Implement attributes[]
|
||||
|
||||
jc.fields.push_back(p);
|
||||
}
|
157
src/Main.cpp
Normal file
157
src/Main.cpp
Normal file
@ -0,0 +1,157 @@
|
||||
#include "FieldInfo.h"
|
||||
#include "Methods.h"
|
||||
#include <ConstantPoolTags/Tags.h>
|
||||
#include <SpecTypes.h>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <ClassFormat.h>
|
||||
#include <Utils/Utils.h>
|
||||
#include <iostream>
|
||||
#include <Globals.h>
|
||||
|
||||
#define JVM_STACK_SIZE 4096
|
||||
|
||||
int stack[JVM_STACK_SIZE];
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
std::cerr << "Usage " << argv[0] << " <jar file to run>" << 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<uint8_t> Globals::buffer(std::istreambuf_iterator<char>(f), {});
|
||||
Globals::buffer() = std::vector<uint8_t>(std::istreambuf_iterator<char>(f), {});
|
||||
f.close();
|
||||
|
||||
int size = Globals::buffer().size();
|
||||
|
||||
jc.magic = Utils::ReadFromStartIntoVal<uint32_t>(Globals::buffer(), 4);
|
||||
|
||||
assert(jc.magic.ToHostFormat() == 0xcafebabe);
|
||||
|
||||
jc.minor = Utils::ReadFromStartIntoVal<uint16_t>(Globals::buffer(), 2);
|
||||
|
||||
jc.major = Utils::ReadFromStartIntoVal<uint16_t>(Globals::buffer(), 2);
|
||||
|
||||
jc.constant_pool_count = Utils::ReadFromStartIntoVal<uint16_t>(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<int>(Globals::buffer(), 1);
|
||||
|
||||
ConstantPoolTags::ConstantPoolParser(cp, jc);
|
||||
}
|
||||
jc.access_flags = Utils::ReadFromStartIntoVal<uint16_t>(Globals::buffer(), 2);
|
||||
jc.this_class = Utils::ReadFromStartIntoVal<uint16_t>(Globals::buffer(), 2);
|
||||
jc.super_class = Utils::ReadFromStartIntoVal<uint16_t>(Globals::buffer(), 2);
|
||||
jc.interfaces_count = Utils::ReadFromStartIntoVal<uint16_t>(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<uint16_t>(Globals::buffer(), 2);
|
||||
|
||||
jc.interfaces.push_back(data);
|
||||
}
|
||||
|
||||
jc.fields_count = Utils::ReadFromStartIntoVal<uint16_t>(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<uint16_t>(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;
|
||||
}
|
9
src/Method/CMakeLists.txt
Normal file
9
src/Method/CMakeLists.txt
Normal file
@ -0,0 +1,9 @@
|
||||
set(CWD ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
set(CONSTANT_POOL_TAG_SRC
|
||||
${CONSTANT_POOL_TAG_SRC}
|
||||
|
||||
${CWD}/MethodParser.cpp
|
||||
|
||||
PARENT_SCOPE
|
||||
)
|
45
src/Method/MethodParser.cpp
Normal file
45
src/Method/MethodParser.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
#include "ConstantPoolTags/Tags.h"
|
||||
#include <Globals.h>
|
||||
#include <Utils/Utils.h>
|
||||
#include <ClassFormat.h>
|
||||
#include <SpecTypes.h>
|
||||
#include <Methods.h>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
void Methods::MethodParser(method_info &p, JavaClassFormat &jc)
|
||||
{
|
||||
p.access_flags = Utils::ReadFromStartIntoVal<uint16_t>(Globals::buffer());
|
||||
p.name_index = Utils::ReadFromStartIntoVal<uint16_t>(Globals::buffer());
|
||||
p.descriptor_index = Utils::ReadFromStartIntoVal<uint16_t>(Globals::buffer());
|
||||
p.attributes_count = Utils::ReadFromStartIntoVal<uint16_t>(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<uint16_t>(Globals::buffer());
|
||||
a.attribute_length = Utils::ReadFromStartIntoVal<uint32_t>(Globals::buffer());
|
||||
|
||||
for (int j = 0; j < a.attribute_length.ToHostFormat(); j++)
|
||||
{
|
||||
a.info.push_back(Utils::ReadFromStartIntoVal<uint8_t>(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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user