222 lines
8.0 KiB
C
222 lines
8.0 KiB
C
#ifndef CLASSFILE_H
|
|
#define CLASSFILE_H
|
|
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
|
|
// https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.htmls table 4.3
|
|
#define CP_UTF8 1
|
|
#define CP_INTEGER 3
|
|
#define CP_FLOAT 4
|
|
#define CP_LONG 5
|
|
#define CP_DOUBLE 6
|
|
#define CP_CLASS 7
|
|
#define CP_STRING 8
|
|
#define CP_FIELDREF 9
|
|
#define CP_METHODREF 10
|
|
#define CP_IFACE_METHODREF 11
|
|
#define CP_NAME_AND_TYPE 12
|
|
|
|
// https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html table 4.1
|
|
#define ACC_PUBLIC 0x0001
|
|
#define ACC_PRIVATE 0x0002
|
|
#define ACC_PROTECTED 0x0004
|
|
#define ACC_STATIC 0x0008
|
|
#define ACC_FINAL 0x0010
|
|
#define ACC_SYNCHRONIZED 0x0020
|
|
#define ACC_NATIVE 0x0100
|
|
#define ACC_ABSTRACT 0x0400
|
|
|
|
/* ── opcodes we handle ──────────────────────────────────────────────────── */
|
|
#define OP_NOP 0x00
|
|
#define OP_ACONST_NULL 0x01
|
|
#define OP_ICONST_M1 0x02
|
|
#define OP_ICONST_0 0x03
|
|
#define OP_ICONST_1 0x04
|
|
#define OP_ICONST_2 0x05
|
|
#define OP_ICONST_3 0x06
|
|
#define OP_ICONST_4 0x07
|
|
#define OP_ICONST_5 0x08
|
|
#define OP_LCONST_0 0x09
|
|
#define OP_LCONST_1 0x0A
|
|
#define OP_BIPUSH 0x10
|
|
#define OP_SIPUSH 0x11
|
|
#define OP_LDC 0x12
|
|
#define OP_LDC_W 0x13
|
|
#define OP_LDC2_W 0x14
|
|
#define OP_ILOAD 0x15
|
|
#define OP_ALOAD 0x19
|
|
#define OP_ILOAD_0 0x1A
|
|
#define OP_ILOAD_1 0x1B
|
|
#define OP_ILOAD_2 0x1C
|
|
#define OP_ILOAD_3 0x1D
|
|
#define OP_ALOAD_0 0x2A
|
|
#define OP_ALOAD_1 0x2B
|
|
#define OP_ALOAD_2 0x2C
|
|
#define OP_ALOAD_3 0x2D
|
|
#define OP_IALOAD 0x2E
|
|
#define OP_ISTORE 0x36
|
|
#define OP_ASTORE 0x3A
|
|
#define OP_ISTORE_0 0x3B
|
|
#define OP_ISTORE_1 0x3C
|
|
#define OP_ISTORE_2 0x3D
|
|
#define OP_ISTORE_3 0x3E
|
|
#define OP_ASTORE_0 0x4B
|
|
#define OP_ASTORE_1 0x4C
|
|
#define OP_ASTORE_2 0x4D
|
|
#define OP_ASTORE_3 0x4E
|
|
#define OP_IASTORE 0x4F
|
|
#define OP_POP 0x57
|
|
#define OP_POP2 0x58
|
|
#define OP_DUP 0x59
|
|
#define OP_DUP_X1 0x5A
|
|
#define OP_SWAP 0x5F
|
|
#define OP_IADD 0x60
|
|
#define OP_LADD 0x61
|
|
#define OP_ISUB 0x64
|
|
#define OP_IMUL 0x68
|
|
#define OP_IDIV 0x6C
|
|
#define OP_IREM 0x70
|
|
#define OP_INEG 0x74
|
|
#define OP_ISHL 0x78
|
|
#define OP_ISHR 0x7A
|
|
#define OP_IUSHR 0x7C
|
|
#define OP_IAND 0x7E
|
|
#define OP_IOR 0x80
|
|
#define OP_IXOR 0x82
|
|
#define OP_IINC 0x84
|
|
#define OP_I2L 0x85
|
|
#define OP_I2C 0x92
|
|
#define OP_LCMP 0x94
|
|
#define OP_IFEQ 0x99
|
|
#define OP_IFNE 0x9A
|
|
#define OP_IFLT 0x9B
|
|
#define OP_IFGE 0x9C
|
|
#define OP_IFGT 0x9D
|
|
#define OP_IFLE 0x9E
|
|
#define OP_IF_ICMPEQ 0x9F
|
|
#define OP_IF_ICMPNE 0xA0
|
|
#define OP_IF_ICMPLT 0xA1
|
|
#define OP_IF_ICMPGE 0xA2
|
|
#define OP_IF_ICMPGT 0xA3
|
|
#define OP_IF_ICMPLE 0xA4
|
|
#define OP_IF_ACMPEQ 0xA5
|
|
#define OP_IF_ACMPNE 0xA6
|
|
#define OP_GOTO 0xA7
|
|
#define OP_IRETURN 0xAC
|
|
#define OP_LRETURN 0xAD
|
|
#define OP_ARETURN 0xB0
|
|
#define OP_RETURN 0xB1
|
|
#define OP_GETSTATIC 0xB2
|
|
#define OP_PUTSTATIC 0xB3
|
|
#define OP_GETFIELD 0xB4
|
|
#define OP_PUTFIELD 0xB5
|
|
#define OP_INVOKEVIRTUAL 0xB6
|
|
#define OP_INVOKESPECIAL 0xB7
|
|
#define OP_INVOKESTATIC 0xB8
|
|
#define OP_NEW 0xBB
|
|
#define OP_NEWARRAY 0xBC
|
|
#define OP_ANEWARRAY 0xBD
|
|
#define OP_ARRAYLENGTH 0xBE
|
|
#define OP_ATHROW 0xBF
|
|
#define OP_CHECKCAST 0xC0
|
|
#define OP_INSTANCEOF 0xC1
|
|
#define OP_IFNULL 0xC6
|
|
#define OP_IFNONNULL 0xC7
|
|
|
|
|
|
|
|
/* ── constant pool entry ────────────────────────────────────────────────── */
|
|
typedef struct {
|
|
uint8_t tag;
|
|
union {
|
|
/* CP_UTF8 */
|
|
struct { uint16_t len; char *bytes; } utf8;
|
|
/* CP_INTEGER */
|
|
struct { int32_t value; } integer;
|
|
/* CP_FLOAT */
|
|
struct { float value; } flt;
|
|
/* CP_LONG */
|
|
struct { int64_t value; } lng;
|
|
/* CP_DOUBLE */
|
|
struct { double value; } dbl;
|
|
/* CP_CLASS, CP_STRING */
|
|
struct { uint16_t index; } cls_or_str;
|
|
/* CP_FIELDREF, CP_METHODREF, CP_IFACE_METHODREF */
|
|
struct { uint16_t class_index; uint16_t name_and_type_index; } ref;
|
|
/* CP_NAME_AND_TYPE */
|
|
struct { uint16_t name_index; uint16_t descriptor_index; } nat;
|
|
};
|
|
} CPEntry;
|
|
|
|
/* ── exception handler table entry ─────────────────────────────────────── */
|
|
typedef struct {
|
|
uint16_t start_pc;
|
|
uint16_t end_pc;
|
|
uint16_t handler_pc;
|
|
uint16_t catch_type; /* CP index to Class, or 0 = catch all */
|
|
} ExceptionHandler;
|
|
|
|
/* ── Code attribute (lives inside a Method) ─────────────────────────────── */
|
|
typedef struct {
|
|
uint16_t max_stack;
|
|
uint16_t max_locals;
|
|
uint32_t code_len;
|
|
uint8_t *code;
|
|
uint16_t exception_table_len;
|
|
ExceptionHandler *exception_table;
|
|
} CodeAttr;
|
|
|
|
/* ── field ──────────────────────────────────────────────────────────────── */
|
|
typedef struct {
|
|
uint16_t access_flags;
|
|
uint16_t name_index; /* → CP_UTF8 */
|
|
uint16_t descriptor_index; /* → CP_UTF8 */
|
|
} Field;
|
|
|
|
/* ── method ─────────────────────────────────────────────────────────────── */
|
|
typedef struct {
|
|
uint16_t access_flags;
|
|
uint16_t name_index; /* → CP_UTF8 */
|
|
uint16_t descriptor_index; /* → CP_UTF8 */
|
|
CodeAttr code; /* zeroed if native/abstract */
|
|
int has_code;
|
|
} Method;
|
|
|
|
/* ── top-level class file ───────────────────────────────────────────────── */
|
|
typedef struct {
|
|
uint16_t minor_version;
|
|
uint16_t major_version; /* 46 = Java 1.2 … 50 = Java 6 */
|
|
|
|
uint16_t cp_count; /* constant_pool_count from spec (1-indexed) */
|
|
CPEntry *cp; /* cp[1..cp_count-1], cp[0] unused */
|
|
|
|
uint16_t access_flags;
|
|
uint16_t this_class; /* CP index */
|
|
uint16_t super_class; /* CP index (0 = java/lang/Object) */
|
|
|
|
uint16_t interfaces_count;
|
|
uint16_t *interfaces; /* array of CP indices */
|
|
|
|
uint16_t fields_count;
|
|
Field *fields;
|
|
|
|
uint16_t methods_count;
|
|
Method *methods;
|
|
} ClassFile;
|
|
|
|
/* ── helper: resolve UTF8 string from CP ───────────────────────────────── */
|
|
static inline const char *cp_utf8(const ClassFile *cf, uint16_t idx) {
|
|
if (idx == 0 || idx >= cf->cp_count) return "";
|
|
if (cf->cp[idx].tag != CP_UTF8) return "";
|
|
return cf->cp[idx].utf8.bytes;
|
|
}
|
|
|
|
/* ── function declarations ──────────────────────────────────────────────── */
|
|
ClassFile *classfile_load(const char *path);
|
|
void classfile_free(ClassFile *cf);
|
|
Method *classfile_find_method(ClassFile *cf, const char *name, const char *descriptor);
|
|
void classfile_dump(const ClassFile *cf); /* debug print */
|
|
|
|
#endif /* CLASSFILE_H */ |