├── LICENSE ├── Makefile ├── README ├── class.c ├── class.h ├── file.c ├── file.h ├── java.1 ├── java.c ├── javap.1 ├── javap.c ├── memory.c ├── memory.h ├── native.c ├── native.h ├── tests ├── Double.java ├── Echo.java ├── HelloWorld.java ├── Int.java ├── Multi.java ├── StringTest.java ├── TableSwitch.java ├── Vector1.java └── Vector2.java ├── util.c └── util.h /LICENSE: -------------------------------------------------------------------------------- 1 | MIT/X Consortium License 2 | 3 | © 2021 phillbush 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a 6 | copy of this software and associated documentation files (the "Software"), 7 | to deal in the Software without restriction, including without limitation 8 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | and/or sell copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 | DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | JAVAOBJS := java.o util.o class.o file.o memory.o native.o 2 | JAVAPOBJS := javap.o util.o class.o file.o 3 | OBJS := java.o javap.o util.o class.o file.o memory.o native.o 4 | SRCS := ${OBJS:.o=.c} 5 | 6 | JAVAP := javap 7 | JAVA := java 8 | 9 | CLASSES := tests/HelloWorld.class \ 10 | tests/Double.class \ 11 | tests/Echo.class \ 12 | tests/Int.class \ 13 | tests/Multi.class \ 14 | tests/StringTest.class \ 15 | tests/TableSwitch.class \ 16 | tests/Vector1.class \ 17 | tests/Vector2.class 18 | TESTP := ${CLASSES:.class=.p} 19 | TESTJ := ${CLASSES:.class=.j} 20 | 21 | LIBS = -lm 22 | INCS = 23 | CPPFLAGS = -D_POSIX_C_SOURCE=200809L 24 | CFLAGS = -g -O0 -std=c99 -Wall -Wextra ${INCS} ${CPPFLAGS} 25 | LDFLAGS = ${LIBS} 26 | LINT = splint 27 | LINTFLAGS = -nullret -predboolint 28 | JAVAPFLAGS = -vp 29 | 30 | # .p and .j are dummy suffixes we use for testing 31 | .SUFFIXES: .p .j .java .class 32 | 33 | # main targets 34 | all: ${JAVA} ${JAVAP} 35 | 36 | classes: ${CLASSES} 37 | 38 | testp: ${TESTP} 39 | testj: ${TESTJ} 40 | 41 | lint: 42 | -${LINT} ${CPPFLAGS} ${LINTFLAGS} ${SRCS} 43 | 44 | ${JAVA}: ${JAVAOBJS} 45 | ${CC} -o $@ ${JAVAOBJS} ${LDFLAGS} 46 | 47 | ${JAVAP}: ${JAVAPOBJS} 48 | ${CC} -o $@ ${JAVAPOBJS} ${LDFLAGS} 49 | 50 | java.o: class.h util.h file.h memory.h native.h 51 | javap.o: class.h util.h file.h 52 | file.o: class.h util.h 53 | native.o: class.h memory.h native.h 54 | memory.o: class.h memory.h 55 | class.o: class.h util.h 56 | 57 | .c.o: 58 | ${CC} ${CFLAGS} -c $< 59 | 60 | ${TESTP}: javap 61 | ${TESTJ}: java 62 | 63 | # test the disassembler (javap) on the test classes 64 | .class.p: 65 | @echo 66 | @echo "========== Disassembling $<" 67 | @./${JAVAP} ${JAVAPFLAGS} $< 68 | 69 | # test the jvm (java) on the test classes 70 | .class.j: 71 | @echo 72 | @echo "========== Running $<" 73 | @./${JAVA} -cp "$$(echo $< | sed 's,/[^/]*,,')" ${JAVAFLAGS} "$$(echo $< | sed 's,.*/,,; s,.class,,')" 74 | 75 | # compile the test classes 76 | .java.class: 77 | javac $< 78 | 79 | clean: 80 | -rm ${JAVA} ${JAVAP} ${OBJS} ${CLASSES} 2>/dev/null 81 | 82 | .PHONY: all clean lint testp testj ${TESTP} ${TESTJ} 83 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | jvm 2 | 3 | This is the implementation of a simple Java Virtual Machine. This is 4 | the final project of the first semester of 2021 of the System Software 5 | course of the Computer Science department of the University of Brasilia. 6 | 7 | The following tools are implemented: 8 | • javap(1): Disassembles one or more class files. 9 | • java(1): Launches a Java application. 10 | 11 | 12 | § Files 13 | 14 | • util.[ch]: miscellaneous routines 15 | • class.[ch]: routines and definitions related to class structure 16 | • native.[ch]: routines and definitions related to native code 17 | • memory.[ch]: routines and definitions related to JRE memory 18 | • file.[ch]: routines to read and free .class files 19 | • javap.c: .class file disassembler 20 | • java.c: .class file interpreter 21 | • tests/*: collection of simple .java files for testing the jvm 22 | 23 | 24 | § Running 25 | 26 | To build the jvm, run the following command. This will create the 27 | executable file ./java for the jvm. 28 | 29 | make java 30 | 31 | To build the disassembler, run the following command. This will create 32 | the executable file ./javap for the disassembler. 33 | 34 | make javap 35 | 36 | To test the disassembler, run make on one of the test files with its 37 | suffix replaced with "p". For example, to test the disassembler on 38 | the test class tests/HelloWorld.class, run the following command. 39 | 40 | make tests/HelloWorld.p 41 | 42 | To test the disassembler on all test classes, run the following command. 43 | 44 | make testp 45 | 46 | To test the jvm, run make on one of the test files with its suffix 47 | replaced with "j". For example, to test the jvm on the test class 48 | tests/HelloWorld.class, run the following command. 49 | 50 | make tests/HelloWorld.j 51 | 52 | To test the jvm on all test classes, run the following command. 53 | 54 | make testj 55 | 56 | 57 | § See Also 58 | 59 | The Java® Virtual Machine Specification: Java SE 8Edition, 60 | by Tim Lindholm, Frank Yellin, Gilad Bracha, Alex Buckley, 61 | Addison-Wesley, 2014. 62 | ISBN: 978-0-13-390590-8. 63 | https://docs.oracle.com/javase/specs/jvms/se8/html/ 64 | -------------------------------------------------------------------------------- /class.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "util.h" 5 | #include "class.h" 6 | 7 | static int noperands[] = { 8 | [NOP] = 0, 9 | [ACONST_NULL] = 0, 10 | [ICONST_M1] = 0, 11 | [ICONST_0] = 0, 12 | [ICONST_1] = 0, 13 | [ICONST_2] = 0, 14 | [ICONST_3] = 0, 15 | [ICONST_4] = 0, 16 | [ICONST_5] = 0, 17 | [LCONST_0] = 0, 18 | [LCONST_1] = 0, 19 | [FCONST_0] = 0, 20 | [FCONST_1] = 0, 21 | [FCONST_2] = 0, 22 | [DCONST_0] = 0, 23 | [DCONST_1] = 0, 24 | [BIPUSH] = 1, 25 | [SIPUSH] = 2, 26 | [LDC] = 1, 27 | [LDC_W] = 2, 28 | [LDC2_W] = 2, 29 | [ILOAD] = 1, 30 | [LLOAD] = 1, 31 | [FLOAD] = 1, 32 | [DLOAD] = 1, 33 | [ALOAD] = 1, 34 | [ILOAD_0] = 0, 35 | [ILOAD_1] = 0, 36 | [ILOAD_2] = 0, 37 | [ILOAD_3] = 0, 38 | [LLOAD_0] = 0, 39 | [LLOAD_1] = 0, 40 | [LLOAD_2] = 0, 41 | [LLOAD_3] = 0, 42 | [FLOAD_0] = 0, 43 | [FLOAD_1] = 0, 44 | [FLOAD_2] = 0, 45 | [FLOAD_3] = 0, 46 | [DLOAD_0] = 0, 47 | [DLOAD_1] = 0, 48 | [DLOAD_2] = 0, 49 | [DLOAD_3] = 0, 50 | [ALOAD_0] = 0, 51 | [ALOAD_1] = 0, 52 | [ALOAD_2] = 0, 53 | [ALOAD_3] = 0, 54 | [IALOAD] = 0, 55 | [LALOAD] = 0, 56 | [FALOAD] = 0, 57 | [DALOAD] = 0, 58 | [AALOAD] = 0, 59 | [BALOAD] = 0, 60 | [CALOAD] = 0, 61 | [SALOAD] = 0, 62 | [ISTORE] = 1, 63 | [LSTORE] = 1, 64 | [FSTORE] = 1, 65 | [DSTORE] = 1, 66 | [ASTORE] = 1, 67 | [ISTORE_0] = 0, 68 | [ISTORE_1] = 0, 69 | [ISTORE_2] = 0, 70 | [ISTORE_3] = 0, 71 | [LSTORE_0] = 0, 72 | [LSTORE_1] = 0, 73 | [LSTORE_2] = 0, 74 | [LSTORE_3] = 0, 75 | [FSTORE_0] = 0, 76 | [FSTORE_1] = 0, 77 | [FSTORE_2] = 0, 78 | [FSTORE_3] = 0, 79 | [DSTORE_0] = 0, 80 | [DSTORE_1] = 0, 81 | [DSTORE_2] = 0, 82 | [DSTORE_3] = 0, 83 | [ASTORE_0] = 0, 84 | [ASTORE_1] = 0, 85 | [ASTORE_2] = 0, 86 | [ASTORE_3] = 0, 87 | [IASTORE] = 0, 88 | [LASTORE] = 0, 89 | [FASTORE] = 0, 90 | [DASTORE] = 0, 91 | [AASTORE] = 0, 92 | [BASTORE] = 0, 93 | [CASTORE] = 0, 94 | [SASTORE] = 0, 95 | [POP] = 0, 96 | [POP2] = 0, 97 | [DUP] = 0, 98 | [DUP_X1] = 0, 99 | [DUP_X2] = 0, 100 | [DUP2] = 0, 101 | [DUP2_X1] = 0, 102 | [DUP2_X2] = 0, 103 | [SWAP] = 0, 104 | [IADD] = 0, 105 | [LADD] = 0, 106 | [FADD] = 0, 107 | [DADD] = 0, 108 | [ISUB] = 0, 109 | [LSUB] = 0, 110 | [FSUB] = 0, 111 | [DSUB] = 0, 112 | [IMUL] = 0, 113 | [LMUL] = 0, 114 | [FMUL] = 0, 115 | [DMUL] = 0, 116 | [IDIV] = 0, 117 | [LDIV] = 0, 118 | [FDIV] = 0, 119 | [DDIV] = 0, 120 | [IREM] = 0, 121 | [LREM] = 0, 122 | [FREM] = 0, 123 | [DREM] = 0, 124 | [INEG] = 0, 125 | [LNEG] = 0, 126 | [FNEG] = 0, 127 | [DNEG] = 0, 128 | [ISHL] = 0, 129 | [LSHL] = 0, 130 | [ISHR] = 0, 131 | [LSHR] = 0, 132 | [IUSHR] = 0, 133 | [LUSHR] = 0, 134 | [IAND] = 0, 135 | [LAND] = 0, 136 | [IOR] = 0, 137 | [LOR] = 0, 138 | [IXOR] = 0, 139 | [LXOR] = 0, 140 | [IINC] = 2, 141 | [I2L] = 0, 142 | [I2F] = 0, 143 | [I2D] = 0, 144 | [L2I] = 0, 145 | [L2F] = 0, 146 | [L2D] = 0, 147 | [F2I] = 0, 148 | [F2L] = 0, 149 | [F2D] = 0, 150 | [D2I] = 0, 151 | [D2L] = 0, 152 | [D2F] = 0, 153 | [I2B] = 0, 154 | [I2C] = 0, 155 | [I2S] = 0, 156 | [LCMP] = 0, 157 | [FCMPL] = 0, 158 | [FCMPG] = 0, 159 | [DCMPL] = 0, 160 | [DCMPG] = 0, 161 | [IFEQ] = 2, 162 | [IFNE] = 2, 163 | [IFLT] = 2, 164 | [IFGE] = 2, 165 | [IFGT] = 2, 166 | [IFLE] = 2, 167 | [IF_ICMPEQ] = 2, 168 | [IF_ICMPNE] = 2, 169 | [IF_ICMPLT] = 2, 170 | [IF_ICMPGE] = 2, 171 | [IF_ICMPGT] = 2, 172 | [IF_ICMPLE] = 2, 173 | [IF_ACMPEQ] = 2, 174 | [IF_ACMPNE] = 2, 175 | [GOTO] = 2, 176 | [JSR] = 2, 177 | [RET] = 1, 178 | [TABLESWITCH] = OP_TABLESWITCH, 179 | [LOOKUPSWITCH] = OP_LOOKUPSWITCH, 180 | [IRETURN] = 0, 181 | [LRETURN] = 0, 182 | [FRETURN] = 0, 183 | [DRETURN] = 0, 184 | [ARETURN] = 0, 185 | [RETURN] = 0, 186 | [GETSTATIC] = 2, 187 | [PUTSTATIC] = 2, 188 | [GETFIELD] = 2, 189 | [PUTFIELD] = 2, 190 | [INVOKEVIRTUAL] = 2, 191 | [INVOKESPECIAL] = 2, 192 | [INVOKESTATIC] = 2, 193 | [INVOKEINTERFACE] = 4, 194 | [INVOKEDYNAMIC] = 4, 195 | [NEW] = 2, 196 | [NEWARRAY] = 1, 197 | [ANEWARRAY] = 2, 198 | [ARRAYLENGTH] = 0, 199 | [ATHROW] = 0, 200 | [CHECKCAST] = 2, 201 | [INSTANCEOF] = 2, 202 | [MONITORENTER] = 0, 203 | [MONITOREXIT] = 0, 204 | [WIDE] = OP_WIDE, 205 | [MULTIANEWARRAY] = 3, 206 | [IFNULL] = 2, 207 | [IFNONNULL] = 2, 208 | [GOTO_W] = 4, 209 | [JSR_W] = 4, 210 | }; 211 | 212 | /* get number of operands of a given instruction */ 213 | int 214 | class_getnoperands(U1 instruction) 215 | { 216 | return noperands[instruction]; 217 | } 218 | 219 | /* get attribute with given tag in list of attributes */ 220 | Attribute * 221 | class_getattr(Attribute **attrs, U2 count, AttributeTag tag) 222 | { 223 | U2 i; 224 | 225 | for (i = 0; i < count; i++) 226 | if (attrs[i]->tag == tag) 227 | return attrs[i]; 228 | return NULL; 229 | } 230 | 231 | /* get string from constant pool */ 232 | char * 233 | class_getutf8(ClassFile *class, U2 index) 234 | { 235 | return class->constant_pool[index]->info.utf8_info.bytes; 236 | } 237 | 238 | /* get string from constant pool */ 239 | char * 240 | class_getclassname(ClassFile *class, U2 index) 241 | { 242 | return class_getutf8(class, class->constant_pool[index]->info.class_info.name_index); 243 | } 244 | 245 | /* get string from string reference */ 246 | char * 247 | class_getstring(ClassFile *class, U2 index) 248 | { 249 | return class_getutf8(class, class->constant_pool[index]->info.string_info.string_index); 250 | } 251 | 252 | /* get int32_t from integer reference */ 253 | int32_t 254 | class_getinteger(ClassFile *class, U2 index) 255 | { 256 | return getint(class->constant_pool[index]->info.integer_info.bytes); 257 | } 258 | 259 | /* get float from float reference */ 260 | float 261 | class_getfloat(ClassFile *class, U2 index) 262 | { 263 | return getfloat(class->constant_pool[index]->info.integer_info.bytes); 264 | } 265 | 266 | /* get int64_t from long reference */ 267 | int64_t 268 | class_getlong(ClassFile *class, U2 index) 269 | { 270 | return getlong(class->constant_pool[index]->info.long_info.high_bytes, 271 | class->constant_pool[index]->info.long_info.low_bytes); 272 | } 273 | 274 | /* get double from double reference */ 275 | double 276 | class_getdouble(ClassFile *class, U2 index) 277 | { 278 | return getdouble(class->constant_pool[index]->info.long_info.high_bytes, 279 | class->constant_pool[index]->info.long_info.low_bytes); 280 | } 281 | 282 | /* get name and type of field or method */ 283 | void 284 | class_getnameandtype(ClassFile *class, U2 index, char **name, char **type) 285 | { 286 | *name = class_getutf8(class, class->constant_pool[index]->info.nameandtype_info.name_index); 287 | *type = class_getutf8(class, class->constant_pool[index]->info.nameandtype_info.descriptor_index); 288 | } 289 | 290 | /* get method matching name and descriptor from class */ 291 | Method * 292 | class_getmethod(ClassFile *class, char *name, char *descr) 293 | { 294 | U2 i; 295 | 296 | for (i = 0; i < class->methods_count; i++) 297 | if (strcmp(name, class_getutf8(class, class->methods[i]->name_index)) == 0 && 298 | strcmp(descr, class_getutf8(class, class->methods[i]->descriptor_index)) == 0) 299 | return class->methods[i]; 300 | return NULL; 301 | } 302 | 303 | /* get field matching name and descriptor from class */ 304 | Field * 305 | class_getfield(ClassFile *class, char *name, char *descr) 306 | { 307 | U2 i; 308 | 309 | for (i = 0; i < class->fields_count; i++) 310 | if (strcmp(name, class_getutf8(class, class->fields[i]->name_index)) == 0 && 311 | strcmp(descr, class_getutf8(class, class->fields[i]->descriptor_index)) == 0) 312 | return class->fields[i]; 313 | return NULL; 314 | } 315 | 316 | /* check if super class is java.lang.Object */ 317 | int 318 | class_istopclass(ClassFile *class) 319 | { 320 | return strcmp(class_getclassname(class, class->super_class), "java/lang/Object") == 0; 321 | } 322 | -------------------------------------------------------------------------------- /class.h: -------------------------------------------------------------------------------- 1 | #define OP_WIDE -1 2 | #define OP_TABLESWITCH -2 3 | #define OP_LOOKUPSWITCH -3 4 | 5 | typedef uint8_t U1; 6 | typedef uint16_t U2; 7 | typedef uint32_t U4; 8 | typedef uint64_t U8; 9 | 10 | typedef int8_t I1; 11 | typedef int16_t I2; 12 | typedef int32_t I4; 13 | typedef int64_t I8; 14 | 15 | /* heap object structure */ 16 | typedef struct Heap { 17 | struct Heap *prev, *next; 18 | void *obj; 19 | int32_t nmemb; 20 | size_t count; 21 | } Heap; 22 | 23 | /* local variable or operand structure */ 24 | typedef union Value { 25 | int32_t i; 26 | int64_t l; 27 | float f; 28 | double d; 29 | Heap *v; 30 | } Value; 31 | 32 | typedef enum TypeCode { 33 | T_BOOLEAN = 4, 34 | T_CHAR = 5, 35 | T_FLOAT = 6, 36 | T_DOUBLE = 7, 37 | T_BYTE = 8, 38 | T_SHORT = 9, 39 | T_INT = 10, 40 | T_LONG = 11, 41 | T_LAST 42 | } TypeCode; 43 | 44 | typedef enum Instruction { 45 | /* constants */ 46 | NOP = 0x00, 47 | ACONST_NULL = 0x01, 48 | ICONST_M1 = 0x02, 49 | ICONST_0 = 0x03, 50 | ICONST_1 = 0x04, 51 | ICONST_2 = 0x05, 52 | ICONST_3 = 0x06, 53 | ICONST_4 = 0x07, 54 | ICONST_5 = 0x08, 55 | LCONST_0 = 0x09, 56 | LCONST_1 = 0x0A, 57 | FCONST_0 = 0x0B, 58 | FCONST_1 = 0x0C, 59 | FCONST_2 = 0x0D, 60 | DCONST_0 = 0x0E, 61 | DCONST_1 = 0x0F, 62 | BIPUSH = 0x10, 63 | SIPUSH = 0x11, 64 | LDC = 0x12, 65 | LDC_W = 0x13, 66 | LDC2_W = 0x14, 67 | 68 | /* loads */ 69 | ILOAD = 0x15, 70 | LLOAD = 0x16, 71 | FLOAD = 0x17, 72 | DLOAD = 0x18, 73 | ALOAD = 0x19, 74 | ILOAD_0 = 0x1A, 75 | ILOAD_1 = 0x1B, 76 | ILOAD_2 = 0x1C, 77 | ILOAD_3 = 0x1D, 78 | LLOAD_0 = 0x1E, 79 | LLOAD_1 = 0x1F, 80 | LLOAD_2 = 0x20, 81 | LLOAD_3 = 0x21, 82 | FLOAD_0 = 0x22, 83 | FLOAD_1 = 0x23, 84 | FLOAD_2 = 0x24, 85 | FLOAD_3 = 0x25, 86 | DLOAD_0 = 0x26, 87 | DLOAD_1 = 0x27, 88 | DLOAD_2 = 0x28, 89 | DLOAD_3 = 0x29, 90 | ALOAD_0 = 0x2A, 91 | ALOAD_1 = 0x2B, 92 | ALOAD_2 = 0x2C, 93 | ALOAD_3 = 0x2D, 94 | IALOAD = 0x2E, 95 | LALOAD = 0x2F, 96 | FALOAD = 0x30, 97 | DALOAD = 0x31, 98 | AALOAD = 0x32, 99 | BALOAD = 0x33, 100 | CALOAD = 0x34, 101 | SALOAD = 0x35, 102 | 103 | /* stores */ 104 | ISTORE = 0x36, 105 | LSTORE = 0x37, 106 | FSTORE = 0x38, 107 | DSTORE = 0x39, 108 | ASTORE = 0x3A, 109 | ISTORE_0 = 0x3B, 110 | ISTORE_1 = 0x3C, 111 | ISTORE_2 = 0x3D, 112 | ISTORE_3 = 0x3E, 113 | LSTORE_0 = 0x3F, 114 | LSTORE_1 = 0x40, 115 | LSTORE_2 = 0x41, 116 | LSTORE_3 = 0x42, 117 | FSTORE_0 = 0x43, 118 | FSTORE_1 = 0x44, 119 | FSTORE_2 = 0x45, 120 | FSTORE_3 = 0x46, 121 | DSTORE_0 = 0x47, 122 | DSTORE_1 = 0x48, 123 | DSTORE_2 = 0x49, 124 | DSTORE_3 = 0x4A, 125 | ASTORE_0 = 0x4B, 126 | ASTORE_1 = 0x4C, 127 | ASTORE_2 = 0x4D, 128 | ASTORE_3 = 0x4E, 129 | IASTORE = 0x4F, 130 | LASTORE = 0x50, 131 | FASTORE = 0x51, 132 | DASTORE = 0x52, 133 | AASTORE = 0x53, 134 | BASTORE = 0x54, 135 | CASTORE = 0x55, 136 | SASTORE = 0x56, 137 | 138 | /* stack */ 139 | POP = 0x57, 140 | POP2 = 0x58, 141 | DUP = 0x59, 142 | DUP_X1 = 0x5A, 143 | DUP_X2 = 0x5B, 144 | DUP2 = 0x5C, 145 | DUP2_X1 = 0x5D, 146 | DUP2_X2 = 0x5E, 147 | SWAP = 0x5F, 148 | 149 | /* math */ 150 | IADD = 0x60, 151 | LADD = 0x61, 152 | FADD = 0x62, 153 | DADD = 0x63, 154 | ISUB = 0x64, 155 | LSUB = 0x65, 156 | FSUB = 0x66, 157 | DSUB = 0x67, 158 | IMUL = 0x68, 159 | LMUL = 0x69, 160 | FMUL = 0x6A, 161 | DMUL = 0x6B, 162 | IDIV = 0x6C, 163 | LDIV = 0x6D, 164 | FDIV = 0x6E, 165 | DDIV = 0x6F, 166 | IREM = 0x70, 167 | LREM = 0x71, 168 | FREM = 0x72, 169 | DREM = 0x73, 170 | INEG = 0x74, 171 | LNEG = 0x75, 172 | FNEG = 0x76, 173 | DNEG = 0x77, 174 | ISHL = 0x78, 175 | LSHL = 0x79, 176 | ISHR = 0x7A, 177 | LSHR = 0x7B, 178 | IUSHR = 0x7C, 179 | LUSHR = 0x7D, 180 | IAND = 0x7E, 181 | LAND = 0x7F, 182 | IOR = 0x80, 183 | LOR = 0x81, 184 | IXOR = 0x82, 185 | LXOR = 0x83, 186 | IINC = 0x84, 187 | 188 | /* conversions */ 189 | I2L = 0x85, 190 | I2F = 0x86, 191 | I2D = 0x87, 192 | L2I = 0x88, 193 | L2F = 0x89, 194 | L2D = 0x8A, 195 | F2I = 0x8B, 196 | F2L = 0x8C, 197 | F2D = 0x8D, 198 | D2I = 0x8E, 199 | D2L = 0x8F, 200 | D2F = 0x90, 201 | I2B = 0x91, 202 | I2C = 0x92, 203 | I2S = 0x93, 204 | 205 | /* comparisons */ 206 | LCMP = 0x94, 207 | FCMPL = 0x95, 208 | FCMPG = 0x96, 209 | DCMPL = 0x97, 210 | DCMPG = 0x98, 211 | IFEQ = 0x99, 212 | IFNE = 0x9A, 213 | IFLT = 0x9B, 214 | IFGE = 0x9C, 215 | IFGT = 0x9D, 216 | IFLE = 0x9E, 217 | IF_ICMPEQ = 0x9F, 218 | IF_ICMPNE = 0xA0, 219 | IF_ICMPLT = 0xA1, 220 | IF_ICMPGE = 0xA2, 221 | IF_ICMPGT = 0xA3, 222 | IF_ICMPLE = 0xA4, 223 | IF_ACMPEQ = 0xA5, 224 | IF_ACMPNE = 0xA6, 225 | 226 | /* control */ 227 | GOTO = 0xA7, 228 | JSR = 0xA8, 229 | RET = 0xA9, 230 | TABLESWITCH = 0xAA, 231 | LOOKUPSWITCH = 0xAB, 232 | IRETURN = 0xAC, 233 | LRETURN = 0xAD, 234 | FRETURN = 0xAE, 235 | DRETURN = 0xAF, 236 | ARETURN = 0xB0, 237 | RETURN = 0xB1, 238 | 239 | /* references */ 240 | GETSTATIC = 0xB2, 241 | PUTSTATIC = 0xB3, 242 | GETFIELD = 0xB4, 243 | PUTFIELD = 0xB5, 244 | INVOKEVIRTUAL = 0xB6, 245 | INVOKESPECIAL = 0xB7, 246 | INVOKESTATIC = 0xB8, 247 | INVOKEINTERFACE = 0xB9, 248 | INVOKEDYNAMIC = 0xBA, 249 | NEW = 0xBB, 250 | NEWARRAY = 0xBC, 251 | ANEWARRAY = 0xBD, 252 | ARRAYLENGTH = 0xBE, 253 | ATHROW = 0xBF, 254 | CHECKCAST = 0xC0, 255 | INSTANCEOF = 0xC1, 256 | MONITORENTER = 0xC2, 257 | MONITOREXIT = 0xC3, 258 | 259 | /* extended */ 260 | WIDE = 0xC4, 261 | MULTIANEWARRAY = 0xC5, 262 | IFNULL = 0xC6, 263 | IFNONNULL = 0xC7, 264 | GOTO_W = 0xC8, 265 | JSR_W = 0xC9, 266 | 267 | /* reserved */ 268 | CODE_LAST = 0xCA, 269 | BREAKPOINT = 0xCA, 270 | IMPDEP1 = 0xFE, 271 | IMPDEP2 = 0xFF 272 | } Instruction; 273 | 274 | typedef enum ConstantTag { 275 | CONSTANT_Untagged = 0, 276 | CONSTANT_Utf8 = 1, 277 | CONSTANT_Integer = 3, 278 | CONSTANT_Float = 4, 279 | CONSTANT_Long = 5, 280 | CONSTANT_Double = 6, 281 | CONSTANT_Class = 7, 282 | CONSTANT_String = 8, 283 | CONSTANT_Fieldref = 9, 284 | CONSTANT_Methodref = 10, 285 | CONSTANT_InterfaceMethodref = 11, 286 | CONSTANT_NameAndType = 12, 287 | CONSTANT_MethodHandle = 15, 288 | CONSTANT_MethodType = 16, 289 | CONSTANT_InvokeDynamic = 18, 290 | CONSTANT_Constant = 20, /* used to tag integers, longs, doubles, floats and strings */ 291 | CONSTANT_U1 = 21, /* used to tag integers, floats and strings */ 292 | CONSTANT_U2 = 22 /* used to tag longs and doubles */ 293 | } ConstantTag; 294 | 295 | typedef enum FlagType { 296 | TYPE_CLASS = 0x01, 297 | TYPE_FIELD = 0x02, 298 | TYPE_METHOD = 0x04, 299 | TYPE_INNER = 0x08 300 | } FlagType; 301 | 302 | typedef enum AccessFlags { 303 | ACC_NONE = 0x0000, 304 | ACC_PUBLIC = 0x0001, 305 | ACC_PRIVATE = 0x0002, 306 | ACC_PROTECTED = 0x0004, 307 | ACC_STATIC = 0x0008, 308 | ACC_FINAL = 0x0010, 309 | ACC_SUPER = 0x0020, 310 | ACC_SYNCHRONIZED = 0x0020, 311 | ACC_VOLATILE = 0x0040, 312 | ACC_BRIDGE = 0x0040, 313 | ACC_TRANSIENT = 0x0080, 314 | ACC_VARARGS = 0x0080, 315 | ACC_NATIVE = 0x0100, 316 | ACC_INTERFACE = 0x0200, 317 | ACC_ABSTRACT = 0x0400, 318 | ACC_STRICT = 0x0800, 319 | ACC_SYNTHETIC = 0x1000, 320 | ACC_ANNOTATION = 0x2000, 321 | ACC_ENUM = 0x4000 322 | } AccessFlags; 323 | 324 | typedef enum AttributeTag { 325 | UnknownAttribute, 326 | ConstantValue, 327 | Code, 328 | Deprecated, 329 | Exceptions, 330 | InnerClasses, 331 | SourceFile, 332 | Synthetic, 333 | LineNumberTable, 334 | LocalVariableTable 335 | } AttributeTag; 336 | 337 | typedef enum ReferenceKind { 338 | REF_none = 0, 339 | REF_getField = 1, 340 | REF_getStatic = 2, 341 | REF_putField = 3, 342 | REF_putStatic = 4, 343 | REF_invokeVirtual = 5, 344 | REF_invokeStatic = 6, 345 | REF_invokeSpecial = 7, 346 | REF_newInvokeSpecial = 8, 347 | REF_invokeInterface = 9, 348 | REF_last = 10, 349 | } ReferenceKind; 350 | 351 | typedef enum FieldType { 352 | TYPE_BYTE = 'B', 353 | TYPE_CHAR = 'C', 354 | TYPE_DOUBLE = 'D', 355 | TYPE_FLOAT = 'F', 356 | TYPE_INT = 'I', 357 | TYPE_LONG = 'J', 358 | TYPE_REFERENCE = 'L', 359 | TYPE_SHORT = 'S', 360 | TYPE_VOID = 'V', 361 | TYPE_BOOLEAN = 'Z', 362 | TYPE_ARRAY = '[', 363 | TYPE_TERMINAL = ';', 364 | TYPE_SEPARATOR = '/', 365 | } FieldType; 366 | 367 | typedef struct CONSTANT_Utf8_info { 368 | U2 length; 369 | char *bytes; 370 | } CONSTANT_Utf8_info; 371 | 372 | typedef struct CONSTANT_Integer_info { 373 | U4 bytes; 374 | } CONSTANT_Integer_info; 375 | 376 | typedef struct CONSTANT_Float_info { 377 | U4 bytes; 378 | } CONSTANT_Float_info; 379 | 380 | typedef struct CONSTANT_Long_info { 381 | U4 high_bytes; 382 | U4 low_bytes; 383 | } CONSTANT_Long_info; 384 | 385 | typedef struct CONSTANT_Double_info { 386 | U4 high_bytes; 387 | U4 low_bytes; 388 | } CONSTANT_Double_info; 389 | 390 | typedef struct CONSTANT_Class_info { 391 | U2 name_index; 392 | } CONSTANT_Class_info; 393 | 394 | typedef struct CONSTANT_String_info { 395 | U2 string_index; 396 | char *string; 397 | } CONSTANT_String_info; 398 | 399 | typedef struct CONSTANT_Fieldref_info { 400 | U2 class_index; 401 | U2 name_and_type_index; 402 | } CONSTANT_Fieldref_info; 403 | 404 | typedef struct CONSTANT_Methodref_info { 405 | U2 class_index; 406 | U2 name_and_type_index; 407 | } CONSTANT_Methodref_info; 408 | 409 | typedef struct CONSTANT_InterfaceMethodref_info { 410 | U2 class_index; 411 | U2 name_and_type_index; 412 | } CONSTANT_InterfaceMethodref_info; 413 | 414 | typedef struct CONSTANT_NameAndType_info { 415 | U2 name_index; 416 | U2 descriptor_index; 417 | } CONSTANT_NameAndType_info; 418 | 419 | typedef struct CONSTANT_MethodHandle_info { 420 | U1 reference_kind; 421 | U2 reference_index; 422 | } CONSTANT_MethodHandle_info; 423 | 424 | typedef struct CONSTANT_MethodType_info { 425 | U2 descriptor_index; 426 | } CONSTANT_MethodType_info; 427 | 428 | typedef struct CONSTANT_InvokeDynamic_info { 429 | U2 bootstrap_method_attr_index; 430 | U2 name_and_type_index; 431 | } CONSTANT_InvokeDynamic_info; 432 | 433 | typedef struct ConstantValue_attribute { 434 | U2 constantvalue_index; 435 | } ConstantValue_attribute; 436 | 437 | typedef struct Code_attribute { 438 | U2 max_stack; 439 | U2 max_locals; 440 | U4 code_length; 441 | U1 *code; 442 | U2 exception_table_length; 443 | struct Exception **exception_table; 444 | U2 attributes_count; 445 | struct Attribute **attributes; 446 | } Code_attribute; 447 | 448 | typedef struct Exceptions_attribute { 449 | U2 number_of_exceptions; 450 | U2 *exception_index_table; 451 | } Exceptions_attribute; 452 | 453 | typedef struct InnerClasses_attribute { 454 | U2 number_of_classes; 455 | struct InnerClass **classes; 456 | } InnerClasses_attribute; 457 | 458 | typedef struct SourceFile_attribute { 459 | U2 sourcefile_index; 460 | } SourceFile_attribute; 461 | 462 | typedef struct LineNumberTable_attribute { 463 | U2 line_number_table_length; 464 | struct LineNumber **line_number_table; 465 | } LineNumberTable_attribute; 466 | 467 | typedef struct LocalVariableTable_attribute { 468 | U2 local_variable_table_length; 469 | struct LocalVariable **local_variable_table; 470 | } LocalVariableTable_attribute; 471 | 472 | typedef struct CP { 473 | U1 tag; 474 | union { 475 | struct CONSTANT_Utf8_info utf8_info; 476 | struct CONSTANT_Integer_info integer_info; 477 | struct CONSTANT_Float_info float_info; 478 | struct CONSTANT_Long_info long_info; 479 | struct CONSTANT_Double_info double_info; 480 | struct CONSTANT_Class_info class_info; 481 | struct CONSTANT_String_info string_info; 482 | struct CONSTANT_Fieldref_info fieldref_info; 483 | struct CONSTANT_Methodref_info methodref_info; 484 | struct CONSTANT_InterfaceMethodref_info interfacemethodref_info; 485 | struct CONSTANT_NameAndType_info nameandtype_info; 486 | struct CONSTANT_MethodHandle_info methodhandle_info; 487 | struct CONSTANT_MethodType_info methodtype_info; 488 | struct CONSTANT_InvokeDynamic_info invokedynamic_info; 489 | } info; 490 | } CP; 491 | 492 | typedef struct Attribute { 493 | enum AttributeTag tag; 494 | union { 495 | struct ConstantValue_attribute constantvalue; 496 | struct Code_attribute code; 497 | struct Exceptions_attribute exceptions; 498 | struct InnerClasses_attribute innerclasses; 499 | struct SourceFile_attribute sourcefile; 500 | struct LineNumberTable_attribute linenumbertable; 501 | struct LocalVariableTable_attribute localvariabletable; 502 | } info; 503 | } Attribute; 504 | 505 | typedef struct Field { 506 | U2 access_flags; 507 | U2 name_index; 508 | U2 descriptor_index; 509 | U2 attributes_count; 510 | struct Attribute **attributes; 511 | } Field; 512 | 513 | typedef struct Method { 514 | U2 access_flags; 515 | U2 name_index; 516 | U2 descriptor_index; 517 | U2 attributes_count; 518 | struct Attribute **attributes; 519 | } Method; 520 | 521 | typedef struct Exception { 522 | U2 start_pc; 523 | U2 end_pc; 524 | U2 handler_pc; 525 | U2 catch_type; 526 | } Exception; 527 | 528 | typedef struct InnerClass { 529 | U2 inner_class_info_index; 530 | U2 outer_class_info_index; 531 | U2 inner_name_index; 532 | U2 inner_class_access_flags; 533 | } InnerClass; 534 | 535 | typedef struct LineNumber { 536 | U2 start_pc; 537 | U2 line_number; 538 | } LineNumber; 539 | 540 | typedef struct LocalVariable { 541 | U2 start_pc; 542 | U2 length; 543 | U2 name_index; 544 | U2 descriptor_index; 545 | U2 index; 546 | } LocalVariable; 547 | 548 | typedef struct ClassFile { 549 | int init; 550 | struct ClassFile *next, *super; 551 | U2 minor_version; 552 | U2 major_version; 553 | U2 constant_pool_count; 554 | struct CP **constant_pool; 555 | U2 access_flags; 556 | U2 this_class; 557 | U2 super_class; 558 | U2 interfaces_count; 559 | U2 *interfaces; 560 | U2 fields_count; 561 | struct Field **fields; 562 | U2 methods_count; 563 | struct Method **methods; 564 | U2 attributes_count; 565 | struct Attribute **attributes; 566 | } ClassFile; 567 | 568 | int class_getnoperands(U1 instruction); 569 | Attribute *class_getattr(Attribute **attrs, U2 count, AttributeTag tag); 570 | char *class_getutf8(ClassFile *class, U2 index); 571 | char *class_getclassname(ClassFile *class, U2 index); 572 | char *class_getstring(ClassFile *class, U2 index); 573 | int32_t class_getinteger(ClassFile *class, U2 index); 574 | float class_getfloat(ClassFile *class, U2 index); 575 | int64_t class_getlong(ClassFile *class, U2 index); 576 | double class_getdouble(ClassFile *class, U2 index); 577 | void class_getnameandtype(ClassFile *class, U2 index, char **name, char **type); 578 | Method *class_getmethod(ClassFile *class, char *name, char *descr); 579 | Field *class_getfield(ClassFile *class, char *name, char *descr); 580 | int class_istopclass(ClassFile *class); 581 | -------------------------------------------------------------------------------- /file.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "util.h" 8 | #include "class.h" 9 | #include "file.h" 10 | 11 | #define MAGIC 0xCAFEBABE 12 | 13 | #define TRY(expr) \ 14 | do { \ 15 | if ((expr) == -1) { \ 16 | goto error; \ 17 | } \ 18 | } while(0) 19 | 20 | /* error tags */ 21 | enum { 22 | ERR_NONE = 0, 23 | ERR_READ, 24 | ERR_ALLOC, 25 | ERR_CODE, 26 | ERR_CONSTANT, 27 | ERR_DESCRIPTOR, 28 | ERR_EOF, 29 | ERR_INDEX, 30 | ERR_KIND, 31 | ERR_MAGIC, 32 | ERR_TAG, 33 | ERR_METHOD, 34 | }; 35 | 36 | /* error variables */ 37 | static int errtag = ERR_NONE; 38 | static char *errstr[] = { 39 | [ERR_NONE] = NULL, 40 | [ERR_READ] = "could not read file", 41 | [ERR_ALLOC] = "could not allocate memory", 42 | [ERR_CODE] = "code does not follow jvm code constraints", 43 | [ERR_CONSTANT] = "reference to entry of wrong type on constant pool", 44 | [ERR_DESCRIPTOR] = "invalid descriptor string", 45 | [ERR_EOF] = "unexpected end of file", 46 | [ERR_INDEX] = "index to constant pool out of bounds", 47 | [ERR_KIND] = "invalid method handle reference kind", 48 | [ERR_MAGIC] = "invalid magic number", 49 | [ERR_METHOD] = "invalid method name", 50 | [ERR_TAG] = "unknown constant pool tag", 51 | }; 52 | 53 | /* call malloc; return -1 on error */ 54 | static int 55 | fmalloc(void **p, size_t size) 56 | { 57 | if ((*p = malloc(size)) == NULL) { 58 | errtag = ERR_ALLOC; 59 | return -1; 60 | } 61 | return 0; 62 | } 63 | 64 | /* call calloc; return -1 on error */ 65 | static int 66 | fcalloc(void **p, size_t nmemb, size_t size) 67 | { 68 | if ((*p = calloc(nmemb, size)) == NULL) { 69 | errtag = ERR_ALLOC; 70 | return -1; 71 | } 72 | return 0; 73 | } 74 | 75 | /* get attribute tag from string */ 76 | static AttributeTag 77 | getattributetag(char *tagstr) 78 | { 79 | static struct { 80 | AttributeTag t; 81 | char *s; 82 | } tags[] = { 83 | {ConstantValue, "ConstantValue"}, 84 | {Code, "Code"}, 85 | {Deprecated, "Deprecated"}, 86 | {Exceptions, "Exceptions"}, 87 | {InnerClasses, "InnerClasses"}, 88 | {SourceFile, "SourceFile"}, 89 | {Synthetic, "Synthetic"}, 90 | {LineNumberTable, "LineNumberTable"}, 91 | {LocalVariableTable, "LocalVariableTable"}, 92 | {UnknownAttribute, NULL}, 93 | }; 94 | int i; 95 | 96 | for (i = 0; tags[i].s; i++) 97 | if (strcmp(tagstr, tags[i].s) == 0) 98 | break; 99 | return tags[i].t; 100 | } 101 | 102 | /* check if string is valid field type, return pointer to next character */ 103 | static int 104 | isdescriptor(char *s) 105 | { 106 | if (*s == '(') { 107 | s++; 108 | while (*s && *s != ')') { 109 | if (*s == 'L') { 110 | while (*s != '\0' && *s != ';') 111 | s++; 112 | if (*s == '\0') 113 | return 0; 114 | } else if (!strchr("BCDFIJSZ[", *s)) { 115 | return 0; 116 | } 117 | s++; 118 | } 119 | if (*s != ')') 120 | return 0; 121 | s++; 122 | } 123 | do { 124 | if (*s == 'L') { 125 | while (*s != '\0' && *s != ';') 126 | s++; 127 | if (*s == '\0') 128 | return 0; 129 | } else if (!strchr("BCDFIJSVZ[", *s)) { 130 | return 0; 131 | } 132 | } while (*s++ == '['); 133 | return 1; 134 | } 135 | 136 | /* check if kind of method handle is valid */ 137 | static int 138 | checkkind(U1 kind) 139 | { 140 | if (kind <= REF_none || kind >= REF_last) { 141 | errtag = ERR_KIND; 142 | return -1; 143 | } 144 | return 0; 145 | } 146 | 147 | /* check if index is valid and points to a given tag in the constant pool */ 148 | static int 149 | checkindex(CP **cp, U2 count, ConstantTag tag, U2 index) 150 | { 151 | if (index < 1 || index >= count) { 152 | errtag = ERR_INDEX; 153 | return -1; 154 | } 155 | switch (tag) { 156 | case CONSTANT_Untagged: 157 | break; 158 | case CONSTANT_Constant: 159 | if (cp[index]->tag != CONSTANT_Integer && 160 | cp[index]->tag != CONSTANT_Float && 161 | cp[index]->tag != CONSTANT_Long && 162 | cp[index]->tag != CONSTANT_Double && 163 | cp[index]->tag != CONSTANT_String) 164 | goto error; 165 | break; 166 | case CONSTANT_U1: 167 | if (cp[index]->tag != CONSTANT_Integer && 168 | cp[index]->tag != CONSTANT_Float && 169 | cp[index]->tag != CONSTANT_String) 170 | goto error; 171 | break; 172 | case CONSTANT_U2: 173 | if (cp[index]->tag != CONSTANT_Long && 174 | cp[index]->tag != CONSTANT_Double) 175 | goto error; 176 | break; 177 | default: 178 | if (cp[index]->tag != tag) 179 | goto error; 180 | break; 181 | } 182 | return 0; 183 | error: 184 | errtag = ERR_CONSTANT; 185 | return -1; 186 | } 187 | 188 | /* check if index is points to a valid descriptor in the constant pool */ 189 | static int 190 | checkdescriptor(CP **cp, U2 count, U2 index) 191 | { 192 | if (index < 1 || index >= count) { 193 | errtag = ERR_INDEX; 194 | return -1; 195 | } 196 | if (cp[index]->tag != CONSTANT_Utf8) { 197 | errtag = ERR_CONSTANT; 198 | return -1; 199 | } 200 | if (!isdescriptor(cp[index]->info.utf8_info.bytes)) { 201 | errtag = ERR_DESCRIPTOR; 202 | return -1; 203 | } 204 | return 0; 205 | } 206 | 207 | /* check if method is not special ( or ) */ 208 | static int 209 | checkmethod(ClassFile *class, U2 index) 210 | { 211 | CONSTANT_Methodref_info *methodref; 212 | char *name, *type; 213 | 214 | methodref = &class->constant_pool[index]->info.methodref_info; 215 | class_getnameandtype(class, methodref->name_and_type_index, &name, &type); 216 | if (strcmp(name, "") == 0 || strcmp(name, "") == 0) { 217 | errtag = ERR_METHOD; 218 | return -1; 219 | } 220 | return 0; 221 | } 222 | 223 | /* read count bytes into buf */ 224 | static int 225 | readb(FILE *fp, void *buf, U4 count) 226 | { 227 | if (fread(buf, 1, count, fp) != count) 228 | return -1; 229 | return 0; 230 | } 231 | 232 | /* read unsigned integer of size count into *u */ 233 | static int 234 | readu(FILE *fp, void *u, U2 count) 235 | { 236 | U1 b[4]; 237 | 238 | TRY(readb(fp, b, count)); 239 | switch (count) { 240 | case 4: 241 | *(U4 *)u = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; 242 | break; 243 | case 2: 244 | *(U2 *)u = (b[0] << 8) | b[1]; 245 | break; 246 | default: 247 | *(U1 *)u = b[0]; 248 | break; 249 | } 250 | return 0; 251 | error: 252 | return -1; 253 | } 254 | 255 | /* read string of length count into buf; insert a nul at the end of it */ 256 | static int 257 | reads(FILE *fp, char **s, U2 count) 258 | { 259 | TRY(fmalloc((void **)s, count + 1)); 260 | TRY(readb(fp, (*s), count)); 261 | (*s)[count] = '\0'; 262 | return 0; 263 | error: 264 | return -1; 265 | } 266 | 267 | /* read index to constant pool and check whether it is a valid index to a given tag */ 268 | static int 269 | readindex(FILE *fp, U2 *u, int canbezero, ClassFile *class, ConstantTag tag) 270 | { 271 | U1 b[2]; 272 | 273 | TRY(readb(fp, b, 2)); 274 | *u = (b[0] << 8) | b[1]; 275 | if (!canbezero || *u) 276 | TRY(checkindex(class->constant_pool, class->constant_pool_count, tag, *u)); 277 | return 0; 278 | error: 279 | return -1; 280 | } 281 | 282 | /* read descriptor index to constant pool and check whether it is a valid */ 283 | static int 284 | readdescriptor(FILE *fp, U2 *u, ClassFile *class) 285 | { 286 | U1 b[2]; 287 | 288 | TRY(readb(fp, b, 2)); 289 | *u = (b[0] << 8) | b[1]; 290 | TRY(checkdescriptor(class->constant_pool, class->constant_pool_count, *u)); 291 | return 0; 292 | error: 293 | return -1; 294 | } 295 | 296 | /* read constant pool into *cp */ 297 | static int 298 | readcp(FILE *fp, CP ***cp, U2 count) 299 | { 300 | U2 i; 301 | 302 | if (count == 0) { 303 | *cp = NULL; 304 | return 0; 305 | } 306 | TRY(fcalloc((void **)cp, count, sizeof(**cp))); 307 | for (i = 1; i < count; i++) { 308 | TRY(fcalloc((void **)&(*cp)[i], 1, sizeof(*(*cp)[i]))); 309 | TRY(readu(fp, &(*cp)[i]->tag, 1)); 310 | switch ((*cp)[i]->tag) { 311 | case CONSTANT_Utf8: 312 | TRY(readu(fp, &(*cp)[i]->info.utf8_info.length, 2)); 313 | TRY(reads(fp, &(*cp)[i]->info.utf8_info.bytes, (*cp)[i]->info.utf8_info.length)); 314 | break; 315 | case CONSTANT_Integer: 316 | TRY(readu(fp, &(*cp)[i]->info.integer_info.bytes, 4)); 317 | break; 318 | case CONSTANT_Float: 319 | TRY(readu(fp, &(*cp)[i]->info.float_info.bytes, 4)); 320 | break; 321 | case CONSTANT_Long: 322 | TRY(readu(fp, &(*cp)[i]->info.long_info.high_bytes, 4)); 323 | TRY(readu(fp, &(*cp)[i]->info.long_info.low_bytes, 4)); 324 | i++; 325 | break; 326 | case CONSTANT_Double: 327 | TRY(readu(fp, &(*cp)[i]->info.double_info.high_bytes, 4)); 328 | TRY(readu(fp, &(*cp)[i]->info.double_info.low_bytes, 4)); 329 | i++; 330 | break; 331 | case CONSTANT_Class: 332 | TRY(readu(fp, &(*cp)[i]->info.class_info.name_index, 2)); 333 | break; 334 | case CONSTANT_String: 335 | TRY(readu(fp, &(*cp)[i]->info.string_info.string_index, 2)); 336 | break; 337 | case CONSTANT_Fieldref: 338 | TRY(readu(fp, &(*cp)[i]->info.fieldref_info.class_index, 2)); 339 | TRY(readu(fp, &(*cp)[i]->info.fieldref_info.name_and_type_index, 2)); 340 | break; 341 | case CONSTANT_Methodref: 342 | TRY(readu(fp, &(*cp)[i]->info.methodref_info.class_index, 2)); 343 | TRY(readu(fp, &(*cp)[i]->info.methodref_info.name_and_type_index, 2)); 344 | break; 345 | case CONSTANT_InterfaceMethodref: 346 | TRY(readu(fp, &(*cp)[i]->info.interfacemethodref_info.class_index, 2)); 347 | TRY(readu(fp, &(*cp)[i]->info.interfacemethodref_info.name_and_type_index, 2)); 348 | break; 349 | case CONSTANT_NameAndType: 350 | TRY(readu(fp, &(*cp)[i]->info.nameandtype_info.name_index, 2)); 351 | TRY(readu(fp, &(*cp)[i]->info.nameandtype_info.descriptor_index, 2)); 352 | break; 353 | case CONSTANT_MethodHandle: 354 | TRY(readu(fp, &(*cp)[i]->info.methodhandle_info.reference_kind, 1)); 355 | TRY(readu(fp, &(*cp)[i]->info.methodhandle_info.reference_index, 2)); 356 | break; 357 | case CONSTANT_MethodType: 358 | TRY(readu(fp, &(*cp)[i]->info.methodtype_info.descriptor_index, 2)); 359 | break; 360 | case CONSTANT_InvokeDynamic: 361 | TRY(readu(fp, &(*cp)[i]->info.invokedynamic_info.bootstrap_method_attr_index, 2)); 362 | TRY(readu(fp, &(*cp)[i]->info.invokedynamic_info.name_and_type_index, 2)); 363 | break; 364 | default: 365 | errtag = ERR_TAG; 366 | goto error; 367 | } 368 | } 369 | for (i = 1; i < count; i++) { 370 | switch ((*cp)[i]->tag) { 371 | case CONSTANT_Utf8: 372 | case CONSTANT_Integer: 373 | case CONSTANT_Float: 374 | break; 375 | case CONSTANT_Long: 376 | case CONSTANT_Double: 377 | i++; 378 | break; 379 | case CONSTANT_Class: 380 | break; 381 | case CONSTANT_String: 382 | TRY(checkindex((*cp), count, CONSTANT_Utf8, (*cp)[i]->info.string_info.string_index)); 383 | (*cp)[i]->info.string_info.string = (*cp)[(*cp)[i]->info.string_info.string_index]->info.utf8_info.bytes; 384 | break; 385 | case CONSTANT_Fieldref: 386 | TRY(checkindex((*cp), count, CONSTANT_Class, (*cp)[i]->info.fieldref_info.class_index)); 387 | TRY(checkindex((*cp), count, CONSTANT_NameAndType, (*cp)[i]->info.fieldref_info.name_and_type_index)); 388 | break; 389 | case CONSTANT_Methodref: 390 | TRY(checkindex((*cp), count, CONSTANT_Class, (*cp)[i]->info.methodref_info.class_index)); 391 | TRY(checkindex((*cp), count, CONSTANT_NameAndType, (*cp)[i]->info.methodref_info.name_and_type_index)); 392 | break; 393 | case CONSTANT_InterfaceMethodref: 394 | TRY(checkindex((*cp), count, CONSTANT_Class, (*cp)[i]->info.interfacemethodref_info.class_index)); 395 | TRY(checkindex((*cp), count, CONSTANT_NameAndType, (*cp)[i]->info.interfacemethodref_info.name_and_type_index)); 396 | break; 397 | case CONSTANT_NameAndType: 398 | TRY(checkindex((*cp), count, CONSTANT_Utf8, (*cp)[i]->info.nameandtype_info.name_index)); 399 | TRY(checkdescriptor((*cp), count, (*cp)[i]->info.nameandtype_info.descriptor_index)); 400 | break; 401 | case CONSTANT_MethodHandle: 402 | TRY(checkkind((*cp)[i]->info.methodhandle_info.reference_kind)); 403 | switch ((*cp)[i]->info.methodhandle_info.reference_kind) { 404 | case REF_getField: 405 | case REF_getStatic: 406 | case REF_putField: 407 | case REF_putStatic: 408 | TRY(checkindex((*cp), count, CONSTANT_Fieldref, (*cp)[i]->info.methodhandle_info.reference_index)); 409 | break; 410 | case REF_invokeVirtual: 411 | case REF_newInvokeSpecial: 412 | TRY(checkindex((*cp), count, CONSTANT_Methodref, (*cp)[i]->info.methodhandle_info.reference_index)); 413 | break; 414 | case REF_invokeStatic: 415 | case REF_invokeSpecial: 416 | /* TODO check based on ClassFile version */ 417 | break; 418 | case REF_invokeInterface: 419 | TRY(checkindex((*cp), count, CONSTANT_InterfaceMethodref, (*cp)[i]->info.methodhandle_info.reference_index)); 420 | break; 421 | } 422 | break; 423 | case CONSTANT_MethodType: 424 | TRY(checkdescriptor((*cp), count, (*cp)[i]->info.methodtype_info.descriptor_index)); 425 | break; 426 | case CONSTANT_InvokeDynamic: 427 | TRY(checkindex((*cp), count, CONSTANT_NameAndType, (*cp)[i]->info.invokedynamic_info.name_and_type_index)); 428 | break; 429 | default: 430 | break; 431 | } 432 | } 433 | return 0; 434 | error: 435 | return -1; 436 | } 437 | 438 | /* read interface indices into *p */ 439 | static int 440 | readinterfaces(FILE *fp, U2 **p, U2 count) 441 | { 442 | U2 i; 443 | 444 | if (count == 0) { 445 | *p = NULL; 446 | return 0; 447 | } 448 | TRY(fcalloc((void **)p, count, sizeof(**p))); 449 | for (i = 0; i < count; i++) 450 | TRY(readu(fp, &(*p)[i], 2)); 451 | return 0; 452 | error: 453 | return -1; 454 | } 455 | 456 | /* read code instructions into *code */ 457 | static int 458 | readcode(FILE *fp, U1 **code, ClassFile *class, U4 count) 459 | { 460 | int32_t j, npairs, off, high, low; 461 | I8 base, i; 462 | U2 u; 463 | 464 | if (count == 0) { 465 | *code = NULL; 466 | return 0; 467 | } 468 | TRY(fmalloc((void **)code, count)); 469 | for (i = 0; i < count; i++) { 470 | TRY(readu(fp, &(*code)[i], 1)); 471 | if ((*code)[i] >= CODE_LAST) 472 | goto error; 473 | switch ((*code)[i]) { 474 | case WIDE: 475 | TRY(readu(fp, &(*code)[++i], 1)); 476 | switch ((*code)[i]) { 477 | case IINC: 478 | TRY(readu(fp, &(*code)[++i], 1)); 479 | TRY(readu(fp, &(*code)[++i], 1)); 480 | /* FALLTHROUGH */ 481 | case ILOAD: 482 | case FLOAD: 483 | case ALOAD: 484 | case LLOAD: 485 | case DLOAD: 486 | case ISTORE: 487 | case FSTORE: 488 | case ASTORE: 489 | case LSTORE: 490 | case DSTORE: 491 | case RET: 492 | TRY(readu(fp, &(*code)[++i], 1)); 493 | TRY(readu(fp, &(*code)[++i], 1)); 494 | break; 495 | default: 496 | goto error; 497 | break; 498 | } 499 | break; 500 | case LOOKUPSWITCH: 501 | while ((3 - (i % 4)) > 0) 502 | TRY(readu(fp, &(*code)[++i], 1)); 503 | for (j = 0; j < 8; j++) 504 | TRY(readu(fp, &(*code)[++i], 1)); 505 | npairs = ((*code)[i-3] << 24) | ((*code)[i-2] << 16) | ((*code)[i-1] << 8) | (*code)[i]; 506 | if (npairs < 0) 507 | goto error; 508 | for (j = 8 * npairs; j > 0; j--) 509 | TRY(readu(fp, &(*code)[++i], 1)); 510 | break; 511 | case TABLESWITCH: 512 | base = i; 513 | while ((3 - (i % 4)) > 0) 514 | TRY(readu(fp, &(*code)[++i], 1)); 515 | for (j = 0; j < 12; j++) 516 | TRY(readu(fp, &(*code)[++i], 1)); 517 | off = ((*code)[i-11] << 24) | ((*code)[i-10] << 16) | ((*code)[i-9] << 8) | (*code)[i-8]; 518 | low = ((*code)[i-7] << 24) | ((*code)[i-6] << 16) | ((*code)[i-5] << 8) | (*code)[i-4]; 519 | high = ((*code)[i-3] << 24) | ((*code)[i-2] << 16) | ((*code)[i-1] << 8) | (*code)[i]; 520 | if (base + off < 0 || base + off >= count) 521 | goto error; 522 | if (low > high) 523 | goto error; 524 | for (j = low; j <= high; j++) { 525 | TRY(readu(fp, &(*code)[++i], 1)); 526 | TRY(readu(fp, &(*code)[++i], 1)); 527 | TRY(readu(fp, &(*code)[++i], 1)); 528 | TRY(readu(fp, &(*code)[++i], 1)); 529 | off = ((*code)[i-3] << 24) | ((*code)[i-2] << 16) | ((*code)[i-1] << 8) | (*code)[i]; 530 | if (base + off < 0 || base + off >= count) { 531 | goto error; 532 | } 533 | } 534 | break; 535 | case LDC: 536 | TRY(readu(fp, &(*code)[++i], 1)); 537 | TRY(checkindex(class->constant_pool, class->constant_pool_count, CONSTANT_U1, (*code)[i])); 538 | break; 539 | case LDC_W: 540 | TRY(readu(fp, &(*code)[++i], 1)); 541 | TRY(readu(fp, &(*code)[++i], 1)); 542 | TRY(checkindex(class->constant_pool, class->constant_pool_count, CONSTANT_U1, (*code)[i - 1] << 8 | (*code)[i])); 543 | break; 544 | case LDC2_W: 545 | TRY(readu(fp, &(*code)[++i], 1)); 546 | TRY(readu(fp, &(*code)[++i], 1)); 547 | TRY(checkindex(class->constant_pool, class->constant_pool_count, CONSTANT_U2, (*code)[i - 1] << 8 | (*code)[i])); 548 | break; 549 | case GETSTATIC: case PUTSTATIC: case GETFIELD: case PUTFIELD: 550 | TRY(readu(fp, &(*code)[++i], 1)); 551 | TRY(readu(fp, &(*code)[++i], 1)); 552 | TRY(checkindex(class->constant_pool, class->constant_pool_count, CONSTANT_Fieldref, (*code)[i - 1] << 8 | (*code)[i])); 553 | break; 554 | case INVOKESTATIC: 555 | TRY(readu(fp, &(*code)[++i], 1)); 556 | TRY(readu(fp, &(*code)[++i], 1)); 557 | u = (*code)[i - 1] << 8 | (*code)[i]; 558 | TRY(checkindex(class->constant_pool, class->constant_pool_count, CONSTANT_Methodref, u)); 559 | TRY(checkmethod(class, u)); 560 | break; 561 | case MULTIANEWARRAY: 562 | TRY(readu(fp, &(*code)[++i], 1)); 563 | TRY(readu(fp, &(*code)[++i], 1)); 564 | u = (*code)[i - 1] << 8 | (*code)[i]; 565 | TRY(checkindex(class->constant_pool, class->constant_pool_count, CONSTANT_Class, u)); 566 | TRY(readu(fp, &(*code)[++i], 1)); 567 | if ((*code)[i] < 1) 568 | goto error; 569 | break; 570 | default: 571 | for (j = class_getnoperands((*code)[i]); j > 0; j--) 572 | TRY(readu(fp, &(*code)[++i], 1)); 573 | break; 574 | } 575 | } 576 | if (i != count) 577 | goto error; 578 | return 0; 579 | error: 580 | return -1; 581 | } 582 | 583 | /* read indices to constant pool into *p */ 584 | static int 585 | readindices(FILE *fp, U2 **indices, U2 count) 586 | { 587 | U2 i; 588 | 589 | if (count == 0) { 590 | *indices = NULL; 591 | return 0; 592 | } 593 | TRY(fcalloc((void **)indices, count, sizeof(**indices))); 594 | for (i = 0; i < count; i++) 595 | TRY(readu(fp, &(*indices)[i], 2)); 596 | return 0; 597 | error: 598 | return -1; 599 | } 600 | 601 | /* read exception table into *p */ 602 | static int 603 | readexceptions(FILE *fp, Exception ***p, U2 count) 604 | { 605 | U2 i; 606 | 607 | if (count == 0) { 608 | *p = NULL; 609 | return 0; 610 | } 611 | TRY(fcalloc((void **)p, count, sizeof(*(*p)))); 612 | for (i = 0; i < count; i++) { 613 | TRY(fcalloc((void **)&(*p)[i], 1, sizeof(*(*p)[i]))); 614 | TRY(readu(fp, &(*p)[i]->start_pc, 2)); 615 | TRY(readu(fp, &(*p)[i]->end_pc, 2)); 616 | TRY(readu(fp, &(*p)[i]->handler_pc, 2)); 617 | TRY(readu(fp, &(*p)[i]->catch_type, 2)); 618 | } 619 | return 0; 620 | error: 621 | return -1; 622 | } 623 | 624 | /* read inner class table into *p */ 625 | static int 626 | readclasses(FILE *fp, InnerClass ***p, ClassFile *class, U2 count) 627 | { 628 | U2 i; 629 | 630 | if (count == 0) { 631 | *p = NULL; 632 | return 0; 633 | } 634 | TRY(fcalloc((void **)p, count, sizeof(*(*p)))); 635 | for (i = 0; i < count; i++) { 636 | TRY(fcalloc((void **)&(*p)[i], 1, sizeof(*(*p)[i]))); 637 | TRY(readindex(fp, &(*p)[i]->inner_class_info_index, 0, class, CONSTANT_Class)); 638 | TRY(readindex(fp, &(*p)[i]->outer_class_info_index, 1, class, CONSTANT_Class)); 639 | TRY(readindex(fp, &(*p)[i]->inner_name_index, 1, class, CONSTANT_Utf8)); 640 | TRY(readu(fp, &(*p)[i]->inner_class_access_flags, 2)); 641 | } 642 | return 0; 643 | error: 644 | return -1; 645 | } 646 | 647 | /* read line number table into *p */ 648 | static int 649 | readlinenumber(FILE *fp, LineNumber ***p, U2 count) 650 | { 651 | U2 i; 652 | 653 | if (count == 0) { 654 | *p = NULL; 655 | return 0; 656 | } 657 | TRY(fcalloc((void **)p, count, sizeof(*(*p)))); 658 | for (i = 0; i < count; i++) { 659 | TRY(fcalloc((void **)&(*p)[i], 1, sizeof(*(*p)[i]))); 660 | TRY(readu(fp, &(*p)[i]->start_pc, 2)); 661 | TRY(readu(fp, &(*p)[i]->line_number, 2)); 662 | } 663 | return 0; 664 | error: 665 | return -1; 666 | } 667 | 668 | /* read local variable table into *p */ 669 | static int 670 | readlocalvariable(FILE *fp, LocalVariable ***p, ClassFile *class, U2 count) 671 | { 672 | U2 i; 673 | 674 | if (count == 0) { 675 | *p = NULL; 676 | return 0; 677 | } 678 | TRY(fcalloc((void **)p, count, sizeof *(*p))); 679 | for (i = 0; i < count; i++) { 680 | TRY(fcalloc((void **)&(*p)[i], 1, sizeof *(*p)[i])); 681 | TRY(readu(fp, &(*p)[i]->start_pc, 2)); 682 | TRY(readu(fp, &(*p)[i]->length, 2)); 683 | TRY(readindex(fp, &(*p)[i]->name_index, 0, class, CONSTANT_Utf8)); 684 | TRY(readdescriptor(fp, &(*p)[i]->descriptor_index, class)); 685 | TRY(readu(fp, &(*p)[i]->index, 2)); 686 | } 687 | return 0; 688 | error: 689 | return -1; 690 | } 691 | 692 | /* read attribute list into *p */ 693 | static int 694 | readattributes(FILE *fp, Attribute ***p, ClassFile *class, U2 count) 695 | { 696 | U4 length; 697 | U2 index; 698 | U2 i; 699 | U1 b; 700 | 701 | if (count == 0) { 702 | *p = NULL; 703 | return 0; 704 | } 705 | TRY(fcalloc((void **)p, count, sizeof(**p))); 706 | for (i = 0; i < count; i++) { 707 | TRY(fcalloc((void **)&(*p)[i], 1, sizeof(*(*p)[i]))); 708 | TRY(readindex(fp, &index, 0, class, CONSTANT_Utf8)); 709 | TRY(readu(fp, &length, 4)); 710 | (*p)[i]->tag = getattributetag(class->constant_pool[index]->info.utf8_info.bytes); 711 | switch ((*p)[i]->tag) { 712 | case ConstantValue: 713 | TRY(readindex(fp, &(*p)[i]->info.constantvalue.constantvalue_index, 0, class, CONSTANT_Constant)); 714 | break; 715 | case Code: 716 | TRY(readu(fp, &(*p)[i]->info.code.max_stack, 2)); 717 | TRY(readu(fp, &(*p)[i]->info.code.max_locals, 2)); 718 | TRY(readu(fp, &(*p)[i]->info.code.code_length, 4)); 719 | TRY(readcode(fp, &(*p)[i]->info.code.code, class, (*p)[i]->info.code.code_length)); 720 | TRY(readu(fp, &(*p)[i]->info.code.exception_table_length, 2)); 721 | TRY(readexceptions(fp, &(*p)[i]->info.code.exception_table, (*p)[i]->info.code.exception_table_length)); 722 | TRY(readu(fp, &(*p)[i]->info.code.attributes_count, 2)); 723 | TRY(readattributes(fp, &(*p)[i]->info.code.attributes, class, (*p)[i]->info.code.attributes_count)); 724 | break; 725 | case Deprecated: 726 | break; 727 | case Exceptions: 728 | TRY(readu(fp, &(*p)[i]->info.exceptions.number_of_exceptions, 2)); 729 | TRY(readindices(fp, &(*p)[i]->info.exceptions.exception_index_table, (*p)[i]->info.exceptions.number_of_exceptions)); 730 | break; 731 | case InnerClasses: 732 | TRY(readu(fp, &(*p)[i]->info.innerclasses.number_of_classes, 2)); 733 | TRY(readclasses(fp, &(*p)[i]->info.innerclasses.classes, class, (*p)[i]->info.innerclasses.number_of_classes)); 734 | break; 735 | case SourceFile: 736 | TRY(readindex(fp, &(*p)[i]->info.sourcefile.sourcefile_index, 0, class, CONSTANT_Utf8)); 737 | break; 738 | case Synthetic: 739 | break; 740 | case LineNumberTable: 741 | TRY(readu(fp, &(*p)[i]->info.linenumbertable.line_number_table_length, 2)); 742 | TRY(readlinenumber(fp, &(*p)[i]->info.linenumbertable.line_number_table, (*p)[i]->info.linenumbertable.line_number_table_length)); 743 | break; 744 | case LocalVariableTable: 745 | TRY(readu(fp, &(*p)[i]->info.localvariabletable.local_variable_table_length, 2)); 746 | TRY(readlocalvariable(fp, &(*p)[i]->info.localvariabletable.local_variable_table, class, (*p)[i]->info.localvariabletable.local_variable_table_length)); 747 | break; 748 | case UnknownAttribute: 749 | while (length-- > 0) 750 | TRY(readb(fp, &b, 1)); 751 | break; 752 | } 753 | } 754 | return 0; 755 | error: 756 | return -1; 757 | } 758 | 759 | /* read fields into *p */ 760 | static int 761 | readfields(FILE *fp, Field ***p, ClassFile *class, U2 count) 762 | { 763 | U2 i; 764 | 765 | if (count == 0) { 766 | *p = NULL; 767 | return 0; 768 | } 769 | TRY(fcalloc((void **)p, count, sizeof(**p))); 770 | for (i = 0; i < count; i++) { 771 | TRY(fcalloc((void **)&(*p)[i], 1, sizeof(*(*p)[i]))); 772 | TRY(readu(fp, &(*p)[i]->access_flags, 2)); 773 | TRY(readindex(fp, &(*p)[i]->name_index, 0, class, CONSTANT_Utf8)); 774 | TRY(readdescriptor(fp, &(*p)[i]->descriptor_index, class)); 775 | TRY(readu(fp, &(*p)[i]->attributes_count, 2)); 776 | TRY(readattributes(fp, &(*p)[i]->attributes, class, (*p)[i]->attributes_count)); 777 | } 778 | return 0; 779 | error: 780 | return -1; 781 | } 782 | 783 | /* read methods into *p */ 784 | static int 785 | readmethods(FILE *fp, Method ***p, ClassFile *class, U2 count) 786 | { 787 | U2 i; 788 | 789 | if (count == 0) { 790 | *p = NULL; 791 | return 0; 792 | } 793 | TRY(fcalloc((void **)p, count, sizeof(**p))); 794 | for (i = 0; i < count; i++) { 795 | TRY(fcalloc((void **)&(*p)[i], 1, sizeof(*(*p)[i]))); 796 | TRY(readu(fp, &(*p)[i]->access_flags, 2)); 797 | TRY(readindex(fp, &(*p)[i]->name_index, 0, class, CONSTANT_Utf8)); 798 | TRY(readdescriptor(fp, &(*p)[i]->descriptor_index, class)); 799 | TRY(readu(fp, &(*p)[i]->attributes_count, 2)); 800 | TRY(readattributes(fp, &(*p)[i]->attributes, class, (*p)[i]->attributes_count)); 801 | } 802 | return 0; 803 | error: 804 | return -1; 805 | } 806 | 807 | /* free attribute */ 808 | static void 809 | attributefree(Attribute **attr, U2 count) 810 | { 811 | U2 i, j; 812 | 813 | if (attr == NULL) 814 | return; 815 | for (i = 0; i < count; i++) { 816 | switch (attr[i]->tag) { 817 | case UnknownAttribute: 818 | case ConstantValue: 819 | case Deprecated: 820 | case SourceFile: 821 | case Synthetic: 822 | break; 823 | case Code: 824 | free(attr[i]->info.code.code); 825 | free(attr[i]->info.code.exception_table); 826 | attributefree(attr[i]->info.code.attributes, attr[i]->info.code.attributes_count); 827 | break; 828 | case Exceptions: 829 | free(attr[i]->info.exceptions.exception_index_table); 830 | break; 831 | case InnerClasses: 832 | if (attr[i]->info.innerclasses.classes != NULL) 833 | for (j = 0; j < attr[i]->info.innerclasses.number_of_classes; j++) 834 | free(attr[i]->info.innerclasses.classes[j]); 835 | free(attr[i]->info.innerclasses.classes); 836 | break; 837 | case LineNumberTable: 838 | if (attr[i]->info.linenumbertable.line_number_table != 0) 839 | for (j = 0; j < attr[i]->info.linenumbertable.line_number_table_length; j++) 840 | free(attr[i]->info.linenumbertable.line_number_table[j]); 841 | free(attr[i]->info.linenumbertable.line_number_table); 842 | break; 843 | case LocalVariableTable: 844 | if (attr[i]->info.localvariabletable.local_variable_table != 0) 845 | for (j = 0; j < attr[i]->info.localvariabletable.local_variable_table_length; j++) 846 | free(attr[i]->info.localvariabletable.local_variable_table[j]); 847 | free(attr[i]->info.localvariabletable.local_variable_table); 848 | break; 849 | } 850 | } 851 | free(attr); 852 | } 853 | 854 | /* free class structure */ 855 | void 856 | file_free(ClassFile *class) 857 | { 858 | U2 i; 859 | 860 | if (class == NULL) 861 | return; 862 | if (class->constant_pool) { 863 | for (i = 1; i < class->constant_pool_count; i++) { 864 | switch (class->constant_pool[i]->tag) { 865 | case CONSTANT_Utf8: 866 | free(class->constant_pool[i]->info.utf8_info.bytes); 867 | break; 868 | case CONSTANT_Double: 869 | case CONSTANT_Long: 870 | i++; 871 | break; 872 | default: 873 | break; 874 | } 875 | } 876 | } 877 | free(class->constant_pool); 878 | free(class->interfaces); 879 | if (class->fields) 880 | for (i = 0; i < class->fields_count; i++) 881 | attributefree(class->fields[i]->attributes, class->fields[i]->attributes_count); 882 | free(class->fields); 883 | if (class->methods) 884 | for (i = 0; i < class->methods_count; i++) 885 | attributefree(class->methods[i]->attributes, class->methods[i]->attributes_count); 886 | free(class->methods); 887 | attributefree(class->attributes, class->attributes_count); 888 | } 889 | 890 | /* read class file */ 891 | int 892 | file_read(FILE *fp, ClassFile *class) 893 | { 894 | U4 magic; 895 | 896 | TRY(readu(fp, &magic, 4)); 897 | if (magic != MAGIC) { 898 | errtag = ERR_MAGIC; 899 | goto error; 900 | } 901 | class->init = 0; 902 | class->next = NULL; 903 | class->super = NULL; 904 | TRY(readu(fp, &class->minor_version, 2)); 905 | TRY(readu(fp, &class->major_version, 2)); 906 | TRY(readu(fp, &class->constant_pool_count, 2)); 907 | TRY(readcp(fp, &class->constant_pool, class->constant_pool_count)); 908 | TRY(readu(fp, &class->access_flags, 2)); 909 | TRY(readu(fp, &class->this_class, 2)); 910 | TRY(readu(fp, &class->super_class, 2)); 911 | TRY(readu(fp, &class->interfaces_count, 2)); 912 | TRY(readinterfaces(fp, &class->interfaces, class->interfaces_count)); 913 | TRY(readu(fp, &class->fields_count, 2)); 914 | TRY(readfields(fp, &class->fields, class, class->fields_count)); 915 | TRY(readu(fp, &class->methods_count, 2)); 916 | TRY(readmethods(fp, &class->methods, class, class->methods_count)); 917 | TRY(readu(fp, &class->attributes_count, 2)); 918 | TRY(readattributes(fp, &class->attributes, class, class->attributes_count)); 919 | return ERR_NONE; 920 | error: 921 | file_free(class); 922 | return errtag; 923 | } 924 | 925 | /* return string describing error tag */ 926 | char * 927 | file_errstr(int i) 928 | { 929 | return errstr[i]; 930 | } 931 | -------------------------------------------------------------------------------- /file.h: -------------------------------------------------------------------------------- 1 | void file_free(ClassFile *class); 2 | int file_read(FILE *fp, ClassFile *class); 3 | char *file_errstr(int i); 4 | -------------------------------------------------------------------------------- /java.1: -------------------------------------------------------------------------------- 1 | .TH JAVA 1 2 | .SH NAME 3 | java \- launch a java application 4 | .SH SYNOPSIS 5 | .B java 6 | .RB [ \-cp 7 | .IR pathlist ] 8 | .I classname 9 | .RI [ args ...] 10 | .SH DESCRIPTION 11 | .B java 12 | starts a Java application. 13 | It does this by starting the Java Runtime Environment, 14 | loading the specified class, and calling that class's 15 | .B main() 16 | method. 17 | The method must be declared 18 | .I public 19 | and 20 | .IR static , 21 | it must not return any value, and it must accept a 22 | .B String 23 | array as a parameter. 24 | The method declaration has the following form: 25 | .IP 26 | .EX 27 | public static void main(String[] args); 28 | .EE 29 | .PP 30 | The JRE searches for the startup class (and other classes used by the application) 31 | in the class path. 32 | The class path is, by default, the current working directory. 33 | The class path can be specified by the environment variable 34 | .B CLASSPATH , 35 | or by the the command line option 36 | .B -cp 37 | (the command line option overrides the environment variable). 38 | .PP 39 | The options are as follows: 40 | .TP 41 | .BI "\-cp " pathlist 42 | Specify a colon-delimited list of directories as the class path. 43 | .SH ENVIRONMENT 44 | The following environment variables affect the execution of 45 | .B java 46 | .TP 47 | .B CLASSPATH 48 | Colon-delimited list of directories as the class path. 49 | .SH EXIT STATUS 50 | .TP 51 | .B 0 52 | Success. 53 | .TP 54 | .B >0 55 | Error occurred. 56 | .EE 57 | .SH SEE ALSO 58 | .IR javac (1), 59 | .IR javap (1) 60 | .PP 61 | Tim Lindholm, Frank Yellin, Gilad Bracha, Alex Buckley, 62 | .I The Java® Virtual Machine Specification: Java SE 8Edition, 63 | Addison-Wesley, 64 | 2014. 65 | ISBN 978-0-13-390590-8. 66 | -------------------------------------------------------------------------------- /java.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #ifdef _WIN32 7 | #include 8 | #else 9 | #include 10 | #endif 11 | #include "util.h" 12 | #include "class.h" 13 | #include "file.h" 14 | #include "memory.h" 15 | #include "native.h" 16 | 17 | /* path separator */ 18 | #ifdef _WIN32 19 | #define PATHSEP ';' 20 | #define DIRSEP '\\' 21 | #else 22 | #define PATHSEP ':' 23 | #define DIRSEP '/' 24 | #endif 25 | 26 | enum { 27 | NO_RETURN = 0, 28 | RETURN_VOID = 1, 29 | RETURN_OPERAND = 2, 30 | RETURN_ERROR = 3 31 | }; 32 | 33 | int methodcall(ClassFile *class, Frame *frame, char *name, char *descr, U2 flags); 34 | 35 | static char **classpath = NULL; /* NULL-terminated array of path strings */ 36 | static ClassFile *classes = NULL; /* list of loaded classes */ 37 | 38 | /* show usage */ 39 | static void 40 | usage(void) 41 | { 42 | (void)fprintf(stderr, "usage: java [-cp classpath] class\n"); 43 | exit(EXIT_FAILURE); 44 | } 45 | 46 | /* check if a class with the given name is loaded */ 47 | static ClassFile * 48 | getclass(char *classname) 49 | { 50 | ClassFile *class; 51 | 52 | for (class = classes; class; class = class->next) 53 | if (strcmp(classname, class_getclassname(class, class->this_class)) == 0) 54 | return class; 55 | return NULL; 56 | } 57 | 58 | /* break cpath into paths and set classpath global variable */ 59 | static void 60 | setclasspath(char *cpath) 61 | { 62 | char *s; 63 | size_t i, n; 64 | 65 | for (n = 1, s = cpath; *s; s++) { 66 | if (*s == PATHSEP) { 67 | *s = '\0'; 68 | n++; 69 | } 70 | } 71 | classpath = ecalloc(n + 1, sizeof *classpath); 72 | classpath[0] = cpath; 73 | classpath[n] = NULL; 74 | for (i = 1; i < n; i++) { 75 | while (*cpath++) 76 | ; 77 | classpath[i] = cpath; 78 | } 79 | } 80 | 81 | /* free all the classes in the list of loaded classes */ 82 | static void 83 | classfree(void) 84 | { 85 | ClassFile *tmp; 86 | 87 | while (classes) { 88 | tmp = classes; 89 | classes = classes->next; 90 | file_free(tmp); 91 | free(tmp); 92 | } 93 | } 94 | 95 | /* initialize class */ 96 | static void 97 | classinit(ClassFile *class) 98 | { 99 | Method *method; 100 | 101 | if (class->init) 102 | return; 103 | class->init = 1; 104 | if (class->super) 105 | classinit(class->super); 106 | if ((method = class_getmethod(class, "", "()V")) != NULL) 107 | (void)methodcall(class, NULL, "", "()V", (class->major_version >= 51 ? ACC_STATIC : ACC_NONE)); 108 | } 109 | 110 | /* recursivelly load class and its superclasses from file matching class name */ 111 | static ClassFile * 112 | classload(char *classname) 113 | { 114 | ClassFile *class, *tmp; 115 | FILE *fp = NULL; 116 | size_t cplen, len, i; 117 | char *basename, *filename; 118 | 119 | if ((class = getclass(classname)) != NULL) 120 | return class; 121 | len = strlen(classname); 122 | basename = emalloc(len + 7); /* 7 == strlen(".class") + 1 */ 123 | memcpy(basename, classname, len); 124 | memcpy(basename + len, ".class", 6); 125 | basename[len + 6] = '\0'; 126 | filename = 0; 127 | for (i = 0; classpath[i] != NULL; i++) { 128 | cplen = strlen(classpath[i]); 129 | filename = emalloc(cplen + len + 8); 130 | strncpy(filename, classpath[i], cplen); 131 | filename[cplen] = DIRSEP; 132 | strncpy(filename + cplen + 1, basename, len + 6); 133 | filename[cplen + len + 7] = '\0'; 134 | if ((fp = fopen(filename, "rb")) != NULL) { 135 | free(filename); 136 | break; 137 | } 138 | free(filename); 139 | } 140 | free(basename); 141 | if (fp == NULL) 142 | errx(EXIT_FAILURE, "could not find class %s", classname); 143 | class = emalloc(sizeof *class); 144 | if (file_read(fp, class) != 0) { 145 | fclose(fp); 146 | free(class); 147 | errx(EXIT_FAILURE, "could not load class %s", classname); 148 | } 149 | fclose(fp); 150 | if (strcmp(class_getclassname(class, class->this_class), classname) != 0) { 151 | free(class); 152 | errx(EXIT_FAILURE, "could not find class %s", classname); 153 | } 154 | class->next = classes; 155 | class->super = NULL; 156 | classes = class; 157 | if (!class_istopclass(class)) { 158 | class->super = classload(class_getclassname(class, class->super_class)); 159 | for (tmp = class->super; tmp; tmp = tmp->super) { 160 | if (strcmp(class_getclassname(class, class->this_class), 161 | class_getclassname(tmp, tmp->this_class)) == 0) { 162 | errx(EXIT_FAILURE, "class circularity error"); 163 | } 164 | } 165 | } 166 | classinit(class); 167 | return class; 168 | } 169 | 170 | /* resolve constant reference */ 171 | static Value 172 | resolveconstant(ClassFile *class, U2 index) 173 | { 174 | Value v; 175 | char *s; 176 | 177 | v.i = 0; 178 | switch (class->constant_pool[index]->tag) { 179 | case CONSTANT_Integer: 180 | v.i = class_getinteger(class, index); 181 | break; 182 | case CONSTANT_Float: 183 | v.f = class_getfloat(class, index); 184 | break; 185 | case CONSTANT_Long: 186 | v.l = class_getlong(class, index); 187 | break; 188 | case CONSTANT_Double: 189 | v.d = class_getdouble(class, index); 190 | break; 191 | case CONSTANT_String: 192 | s = class_getstring(class, index); 193 | v.v = heap_alloc(0, 0); 194 | v.v->obj = s; 195 | break; 196 | } 197 | return v; 198 | } 199 | 200 | /* resolve field reference */ 201 | static CP * 202 | resolvefield(ClassFile *class, CONSTANT_Fieldref_info *fieldref, Heap **p) 203 | { 204 | Field *field; 205 | enum JavaClass jclass; 206 | U2 index, i; 207 | char *classname, *name, *type; 208 | 209 | if (p != NULL) 210 | *p = NULL; 211 | classname = class_getclassname(class, fieldref->class_index); 212 | class_getnameandtype(class, fieldref->name_and_type_index, &name, &type); 213 | if ((jclass = native_javaclass(classname)) != NONE_CLASS) { 214 | if (p != NULL) { 215 | (*p) = heap_alloc(0, 0); 216 | ((Heap *)*p)->obj = native_javaobj(jclass, name, type); 217 | } 218 | return NULL; 219 | } else if ((class = classload(classname)) && 220 | (field = class_getfield(class, name, type))) { 221 | index = 0; 222 | for (i = 0; i < field->attributes_count; i++) { 223 | if (field->attributes[i]->tag == ConstantValue) { 224 | index = field->attributes[i]->info.constantvalue.constantvalue_index; 225 | break; 226 | } 227 | } 228 | if (index != 0) { 229 | return class->constant_pool[index]; 230 | } 231 | } 232 | errx(EXIT_FAILURE, "could not resolve field"); 233 | return NULL; 234 | } 235 | 236 | /* aconst_null: push null */ 237 | static int 238 | opaconst_null(Frame *frame) 239 | { 240 | Value v; 241 | 242 | v.v = heap_alloc(0, 0); 243 | v.v->obj = NULL; 244 | frame_stackpush(frame, v); 245 | return NO_RETURN; 246 | } 247 | 248 | /* aaload: load reference from array */ 249 | static int 250 | opaaload(Frame *frame) 251 | { 252 | Value va, vi, v; 253 | 254 | vi = frame_stackpop(frame); 255 | va = frame_stackpop(frame); 256 | if (va.v->obj == NULL) { 257 | // TODO: throw NullPointerException 258 | } 259 | if (vi.i < 0 || vi.i >= va.v->nmemb) { 260 | // TODO: throw ArrayIndexOutOfBoundsException 261 | } 262 | v.v = ((void **)va.v->obj)[vi.i]; 263 | frame_stackpush(frame, v); 264 | return NO_RETURN; 265 | } 266 | 267 | /* aastore: store into reference array */ 268 | static int 269 | opaastore(Frame *frame) 270 | { 271 | Value va, vi, vv; 272 | 273 | vv = frame_stackpop(frame); 274 | vi = frame_stackpop(frame); 275 | va = frame_stackpop(frame); 276 | if (va.v->obj == NULL) { 277 | // TODO: throw NullPointerException 278 | } 279 | if (vi.i < 0 || vi.i >= va.v->nmemb) { 280 | // TODO: throw ArrayIndexOutOfBoundsException 281 | } 282 | ((void **)va.v->obj)[vi.i] = vv.v; 283 | return NO_RETURN; 284 | } 285 | 286 | /* arraylength: get length of array */ 287 | static int 288 | oparraylength(Frame *frame) 289 | { 290 | Value v; 291 | 292 | v = frame_stackpop(frame); 293 | v.i = v.v->nmemb; 294 | frame_stackpush(frame, v); 295 | return NO_RETURN; 296 | } 297 | 298 | /* bipush: push byte */ 299 | static int 300 | opbipush(Frame *frame) 301 | { 302 | Value v; 303 | 304 | v.i = (int8_t)frame->code->code[frame->pc++]; 305 | frame_stackpush(frame, v); 306 | return NO_RETURN; 307 | } 308 | 309 | /* d2f: convert double to float */ 310 | static int 311 | opd2f(Frame *frame) 312 | { 313 | Value v; 314 | 315 | v = frame_stackpop(frame); 316 | v.f = v.d; 317 | frame_stackpush(frame, v); 318 | return NO_RETURN; 319 | } 320 | 321 | /* d2i: convert double to int */ 322 | static int 323 | opd2i(Frame *frame) 324 | { 325 | Value v; 326 | 327 | v = frame_stackpop(frame); 328 | v.i = v.d; 329 | frame_stackpush(frame, v); 330 | return NO_RETURN; 331 | } 332 | 333 | /* d2l: convert double to long */ 334 | static int 335 | opd2l(Frame *frame) 336 | { 337 | Value v; 338 | 339 | v = frame_stackpop(frame); 340 | v.l = v.d; 341 | frame_stackpush(frame, v); 342 | return NO_RETURN; 343 | } 344 | 345 | /* dadd: add double */ 346 | static int 347 | opdadd(Frame *frame) 348 | { 349 | Value v1, v2; 350 | 351 | v2 = frame_stackpop(frame); 352 | v1 = frame_stackpop(frame); 353 | v1.d += v2.d; 354 | frame_stackpush(frame, v1); 355 | return NO_RETURN; 356 | } 357 | 358 | /* daload: load double from array */ 359 | static int 360 | opdaload(Frame *frame) 361 | { 362 | Value va, vi, v; 363 | 364 | vi = frame_stackpop(frame); 365 | va = frame_stackpop(frame); 366 | if (va.v->obj == NULL) { 367 | // TODO: throw NullPointerException 368 | } 369 | if (vi.i < 0 || vi.i >= va.v->nmemb) { 370 | // TODO: throw ArrayIndexOutOfBoundsException 371 | } 372 | v.d = ((double *)va.v->obj)[vi.i]; 373 | frame_stackpush(frame, v); 374 | return NO_RETURN; 375 | } 376 | 377 | /* dastore: store into double array */ 378 | static int 379 | opdastore(Frame *frame) 380 | { 381 | Value va, vi, vv; 382 | 383 | vv = frame_stackpop(frame); 384 | vi = frame_stackpop(frame); 385 | va = frame_stackpop(frame); 386 | if (va.v->obj == NULL) { 387 | // TODO: throw NullPointerException 388 | } 389 | if (vi.i < 0 || vi.i >= va.v->nmemb) { 390 | // TODO: throw ArrayIndexOutOfBoundsException 391 | } 392 | ((double *)va.v->obj)[vi.i] = vv.d; 393 | return NO_RETURN; 394 | } 395 | 396 | /* dcmpg: compare double */ 397 | static int 398 | opdcmpg(Frame *frame) 399 | { 400 | Value v1, v2, v; 401 | 402 | v2 = frame_stackpop(frame); 403 | v1 = frame_stackpop(frame); 404 | if (v1.d > v2.d) 405 | v.i = 1; 406 | else if (v1.d == v2.d) 407 | v.i = 0; 408 | else if (v1.d < v2.d) 409 | v.i = -1; 410 | else 411 | v.i = 1; 412 | frame_stackpush(frame, v); 413 | return NO_RETURN; 414 | } 415 | 416 | /* dcmpl: compare double */ 417 | static int 418 | opdcmpl(Frame *frame) 419 | { 420 | Value v1, v2, v; 421 | 422 | v2 = frame_stackpop(frame); 423 | v1 = frame_stackpop(frame); 424 | if (v1.d > v2.d) 425 | v.i = 1; 426 | else if (v1.d == v2.d) 427 | v.i = 0; 428 | else if (v1.d < v2.d) 429 | v.i = -1; 430 | else 431 | v.i = -1; 432 | frame_stackpush(frame, v); 433 | return NO_RETURN; 434 | } 435 | 436 | /* dconst_0: push double 0 into stack */ 437 | static int 438 | opdconst_0(Frame *frame) 439 | { 440 | Value v; 441 | 442 | v.d = 0.0; 443 | frame_stackpush(frame, v); 444 | return NO_RETURN; 445 | } 446 | 447 | /* dconst_1: push double 1 into stack */ 448 | static int 449 | opdconst_1(Frame *frame) 450 | { 451 | Value v; 452 | 453 | v.d = 1.0; 454 | frame_stackpush(frame, v); 455 | return NO_RETURN; 456 | } 457 | 458 | /* ddiv: divide double */ 459 | static int 460 | opddiv(Frame *frame) 461 | { 462 | Value v1, v2; 463 | 464 | v2 = frame_stackpop(frame); 465 | v1 = frame_stackpop(frame); 466 | v1.d /= v2.d; 467 | frame_stackpush(frame, v1); 468 | return NO_RETURN; 469 | } 470 | 471 | /* dmul: multiply double */ 472 | static int 473 | opdmul(Frame *frame) 474 | { 475 | Value v1, v2; 476 | 477 | v2 = frame_stackpop(frame); 478 | v1 = frame_stackpop(frame); 479 | v1.d *= v2.d; 480 | frame_stackpush(frame, v1); 481 | return NO_RETURN; 482 | } 483 | 484 | /* dneg: negate double */ 485 | static int 486 | opdneg(Frame *frame) 487 | { 488 | Value v; 489 | 490 | v = frame_stackpop(frame); 491 | v.d = -v.d; 492 | frame_stackpush(frame, v); 493 | return NO_RETURN; 494 | } 495 | 496 | /* drem: remainder double */ 497 | static int 498 | opdrem(Frame *frame) 499 | { 500 | Value v1, v2; 501 | 502 | v2 = frame_stackpop(frame); 503 | v1 = frame_stackpop(frame); 504 | v1.d = fmod(v1.d, v2.d); 505 | frame_stackpush(frame, v1); 506 | return NO_RETURN; 507 | } 508 | 509 | /* dsub: subtract double */ 510 | static int 511 | opdsub(Frame *frame) 512 | { 513 | Value v1, v2; 514 | 515 | v2 = frame_stackpop(frame); 516 | v1 = frame_stackpop(frame); 517 | v1.d -= v2.d; 518 | frame_stackpush(frame, v1); 519 | return NO_RETURN; 520 | } 521 | 522 | /* dup: duplicate the top operand stack value */ 523 | static int 524 | opdup(Frame *frame) 525 | { 526 | Value v; 527 | 528 | v = frame_stackpop(frame); 529 | frame_stackpush(frame, v); 530 | frame_stackpush(frame, v); 531 | return NO_RETURN; 532 | } 533 | 534 | /* dup2: duplicate the top one or two operand stack values */ 535 | static int 536 | opdup2(Frame *frame) 537 | { 538 | Value v1, v2; 539 | 540 | v1 = frame_stackpop(frame); 541 | v2 = frame_stackpop(frame); 542 | frame_stackpush(frame, v2); 543 | frame_stackpush(frame, v1); 544 | frame_stackpush(frame, v2); 545 | frame_stackpush(frame, v1); 546 | return NO_RETURN; 547 | } 548 | 549 | /* dup2_x1: duplicate the top one or two operand stack values and insert two or three values down */ 550 | static int 551 | opdup2_x1(Frame *frame) 552 | { 553 | Value v1, v2, v3; 554 | 555 | v1 = frame_stackpop(frame); 556 | v2 = frame_stackpop(frame); 557 | v3 = frame_stackpop(frame); 558 | frame_stackpush(frame, v2); 559 | frame_stackpush(frame, v1); 560 | frame_stackpush(frame, v3); 561 | frame_stackpush(frame, v2); 562 | frame_stackpush(frame, v1); 563 | return NO_RETURN; 564 | } 565 | 566 | /* dup2_x2: duplicate the top one or two operand stack values and insert two, three or four values down */ 567 | static int 568 | opdup2_x2(Frame *frame) 569 | { 570 | Value v1, v2, v3, v4; 571 | 572 | v1 = frame_stackpop(frame); 573 | v2 = frame_stackpop(frame); 574 | v3 = frame_stackpop(frame); 575 | v4 = frame_stackpop(frame); 576 | frame_stackpush(frame, v2); 577 | frame_stackpush(frame, v1); 578 | frame_stackpush(frame, v4); 579 | frame_stackpush(frame, v3); 580 | frame_stackpush(frame, v2); 581 | frame_stackpush(frame, v1); 582 | return NO_RETURN; 583 | } 584 | 585 | /* dup_x1: duplicate the top operand stack value and insert two values down */ 586 | static int 587 | opdup_x1(Frame *frame) 588 | { 589 | Value v1, v2; 590 | 591 | v1 = frame_stackpop(frame); 592 | v2 = frame_stackpop(frame); 593 | frame_stackpush(frame, v1); 594 | frame_stackpush(frame, v2); 595 | frame_stackpush(frame, v1); 596 | return NO_RETURN; 597 | } 598 | 599 | /* dup_x2: duplicate the top operand stack value and insert two or three values down */ 600 | static int 601 | opdup_x2(Frame *frame) 602 | { 603 | Value v1, v2, v3; 604 | 605 | v1 = frame_stackpop(frame); 606 | v2 = frame_stackpop(frame); 607 | v3 = frame_stackpop(frame); 608 | frame_stackpush(frame, v1); 609 | frame_stackpush(frame, v3); 610 | frame_stackpush(frame, v2); 611 | frame_stackpush(frame, v1); 612 | return NO_RETURN; 613 | } 614 | 615 | /* swap: swap the top two operand stack values */ 616 | static int 617 | opswap(Frame *frame) 618 | { 619 | Value v1, v2; 620 | 621 | v1 = frame_stackpop(frame); 622 | v2 = frame_stackpop(frame); 623 | frame_stackpush(frame, v1); 624 | frame_stackpush(frame, v2); 625 | return NO_RETURN; 626 | } 627 | 628 | /* ishl: shift left int */ 629 | static int 630 | opishl(Frame *frame) 631 | { 632 | Value v1, v2; 633 | 634 | v2 = frame_stackpop(frame); 635 | v1 = frame_stackpop(frame); 636 | v1.i <<= v2.i; 637 | frame_stackpush(frame, v1); 638 | return NO_RETURN; 639 | } 640 | 641 | /* lshl: shift left long */ 642 | static int 643 | oplshl(Frame *frame) 644 | { 645 | Value v1, v2; 646 | 647 | v2 = frame_stackpop(frame); 648 | v1 = frame_stackpop(frame); 649 | v1.l <<= v2.l; 650 | frame_stackpush(frame, v1); 651 | return NO_RETURN; 652 | } 653 | 654 | /* ishr: arithmetic shift right int */ 655 | static int 656 | opishr(Frame *frame) 657 | { 658 | Value v1, v2; 659 | 660 | v2 = frame_stackpop(frame); 661 | v1 = frame_stackpop(frame); 662 | v1.i >>= v2.i; 663 | frame_stackpush(frame, v1); 664 | return NO_RETURN; 665 | } 666 | 667 | /* lshr: arithmetic shift right long */ 668 | static int 669 | oplshr(Frame *frame) 670 | { 671 | Value v1, v2; 672 | 673 | v2 = frame_stackpop(frame); 674 | v1 = frame_stackpop(frame); 675 | v1.l >>= v2.l; 676 | frame_stackpush(frame, v1); 677 | return NO_RETURN; 678 | } 679 | 680 | /* iushr: logical shift right int */ 681 | static int 682 | opiushr(Frame *frame) 683 | { 684 | Value v1, v2; 685 | 686 | v2 = frame_stackpop(frame); 687 | v1 = frame_stackpop(frame); 688 | v1.i = (unsigned)v1.i >> v2.i; 689 | frame_stackpush(frame, v1); 690 | return NO_RETURN; 691 | } 692 | 693 | /* lushr: logical shift right long */ 694 | static int 695 | oplushr(Frame *frame) 696 | { 697 | Value v1, v2; 698 | 699 | v2 = frame_stackpop(frame); 700 | v1 = frame_stackpop(frame); 701 | v1.l = (unsigned)v1.l >> v2.l; 702 | frame_stackpush(frame, v1); 703 | return NO_RETURN; 704 | } 705 | 706 | /* iand: boolean AND int */ 707 | static int 708 | opiand(Frame *frame) 709 | { 710 | Value v1, v2; 711 | 712 | v2 = frame_stackpop(frame); 713 | v1 = frame_stackpop(frame); 714 | v1.i &= v2.i; 715 | frame_stackpush(frame, v1); 716 | return NO_RETURN; 717 | } 718 | 719 | /* ior: boolean OR int */ 720 | static int 721 | opior(Frame *frame) 722 | { 723 | Value v1, v2; 724 | 725 | v2 = frame_stackpop(frame); 726 | v1 = frame_stackpop(frame); 727 | v1.i |= v2.i; 728 | frame_stackpush(frame, v1); 729 | return NO_RETURN; 730 | } 731 | 732 | /* ixor: boolean XOR int */ 733 | static int 734 | opixor(Frame *frame) 735 | { 736 | Value v1, v2; 737 | 738 | v2 = frame_stackpop(frame); 739 | v1 = frame_stackpop(frame); 740 | v1.i ^= v2.i; 741 | frame_stackpush(frame, v1); 742 | return NO_RETURN; 743 | } 744 | 745 | /* f2d: convert float to double */ 746 | static int 747 | opf2d(Frame *frame) 748 | { 749 | Value v; 750 | 751 | v = frame_stackpop(frame); 752 | v.d = v.f; 753 | frame_stackpush(frame, v); 754 | return NO_RETURN; 755 | } 756 | 757 | /* f2i: convert float to int */ 758 | static int 759 | opf2i(Frame *frame) 760 | { 761 | Value v; 762 | 763 | v = frame_stackpop(frame); 764 | v.i = v.f; 765 | frame_stackpush(frame, v); 766 | return NO_RETURN; 767 | } 768 | 769 | /* f2l: convert float to long */ 770 | static int 771 | opf2l(Frame *frame) 772 | { 773 | Value v; 774 | 775 | v = frame_stackpop(frame); 776 | v.l = v.f; 777 | frame_stackpush(frame, v); 778 | return NO_RETURN; 779 | } 780 | 781 | /* fadd: add float */ 782 | static int 783 | opfadd(Frame *frame) 784 | { 785 | Value v1, v2; 786 | 787 | v2 = frame_stackpop(frame); 788 | v1 = frame_stackpop(frame); 789 | v1.f += v2.f; 790 | frame_stackpush(frame, v1); 791 | return NO_RETURN; 792 | } 793 | 794 | /* faload: load float from array */ 795 | static int 796 | opfaload(Frame *frame) 797 | { 798 | Value va, vi, v; 799 | 800 | vi = frame_stackpop(frame); 801 | va = frame_stackpop(frame); 802 | if (va.v->obj == NULL) { 803 | // TODO: throw NullPointerException 804 | } 805 | if (vi.i < 0 || vi.i >= va.v->nmemb) { 806 | // TODO: throw ArrayIndexOutOfBoundsException 807 | } 808 | v.f = ((float *)va.v->obj)[vi.i]; 809 | frame_stackpush(frame, v); 810 | return NO_RETURN; 811 | } 812 | 813 | /* fastore: store into float array */ 814 | static int 815 | opfastore(Frame *frame) 816 | { 817 | Value va, vi, vv; 818 | 819 | vv = frame_stackpop(frame); 820 | vi = frame_stackpop(frame); 821 | va = frame_stackpop(frame); 822 | if (va.v->obj == NULL) { 823 | // TODO: throw NullPointerException 824 | } 825 | if (vi.i < 0 || vi.i >= va.v->nmemb) { 826 | // TODO: throw ArrayIndexOutOfBoundsException 827 | } 828 | ((float *)va.v->obj)[vi.i] = vv.f; 829 | return NO_RETURN; 830 | } 831 | 832 | /* fcmpg: compare float */ 833 | static int 834 | opfcmpg(Frame *frame) 835 | { 836 | Value v1, v2, v; 837 | 838 | v2 = frame_stackpop(frame); 839 | v1 = frame_stackpop(frame); 840 | if (v1.f > v2.f) 841 | v.i = 1; 842 | else if (v1.f == v2.f) 843 | v.i = 0; 844 | else if (v1.f < v2.f) 845 | v.i = -1; 846 | else 847 | v.i = 1; 848 | frame_stackpush(frame, v); 849 | return NO_RETURN; 850 | } 851 | 852 | /* fcmpl: compare float */ 853 | static int 854 | opfcmpl(Frame *frame) 855 | { 856 | Value v1, v2, v; 857 | 858 | v2 = frame_stackpop(frame); 859 | v1 = frame_stackpop(frame); 860 | if (v1.f > v2.f) 861 | v.i = 1; 862 | else if (v1.f == v2.f) 863 | v.i = 0; 864 | else if (v1.f < v2.f) 865 | v.i = -1; 866 | else 867 | v.i = -1; 868 | frame_stackpush(frame, v); 869 | return NO_RETURN; 870 | } 871 | 872 | /* fconst_0: push float 0 into stack */ 873 | static int 874 | opfconst_0(Frame *frame) 875 | { 876 | Value v; 877 | 878 | v.f = 0.0; 879 | frame_stackpush(frame, v); 880 | return NO_RETURN; 881 | } 882 | 883 | /* fconst_1: push float 1 into stack */ 884 | static int 885 | opfconst_1(Frame *frame) 886 | { 887 | Value v; 888 | 889 | v.f = 1.0; 890 | frame_stackpush(frame, v); 891 | return NO_RETURN; 892 | } 893 | 894 | /* fconst_2: push float 2 into stack */ 895 | static int 896 | opfconst_2(Frame *frame) 897 | { 898 | Value v; 899 | 900 | v.f = 2.0; 901 | frame_stackpush(frame, v); 902 | return NO_RETURN; 903 | } 904 | 905 | /* fdiv: divide float */ 906 | static int 907 | opfdiv(Frame *frame) 908 | { 909 | Value v1, v2; 910 | 911 | v2 = frame_stackpop(frame); 912 | v1 = frame_stackpop(frame); 913 | v1.f /= v2.f; 914 | frame_stackpush(frame, v1); 915 | return NO_RETURN; 916 | } 917 | 918 | /* fmul: multiply float */ 919 | static int 920 | opfmul(Frame *frame) 921 | { 922 | Value v1, v2; 923 | 924 | v2 = frame_stackpop(frame); 925 | v1 = frame_stackpop(frame); 926 | v1.f *= v2.f; 927 | frame_stackpush(frame, v1); 928 | return NO_RETURN; 929 | } 930 | 931 | /* fneg: negate float */ 932 | static int 933 | opfneg(Frame *frame) 934 | { 935 | Value v; 936 | 937 | v = frame_stackpop(frame); 938 | v.f = -v.f; 939 | frame_stackpush(frame, v); 940 | return NO_RETURN; 941 | } 942 | 943 | /* frem: remainder float */ 944 | static int 945 | opfrem(Frame *frame) 946 | { 947 | Value v1, v2; 948 | 949 | v2 = frame_stackpop(frame); 950 | v1 = frame_stackpop(frame); 951 | v1.f = fmodf(v1.f, v2.f); 952 | frame_stackpush(frame, v1); 953 | return NO_RETURN; 954 | } 955 | 956 | /* fsub: subtract float */ 957 | static int 958 | opfsub(Frame *frame) 959 | { 960 | Value v1, v2; 961 | 962 | v2 = frame_stackpop(frame); 963 | v1 = frame_stackpop(frame); 964 | v1.f -= v2.f; 965 | frame_stackpush(frame, v1); 966 | return NO_RETURN; 967 | } 968 | 969 | /* getstatic: get static field from class */ 970 | static int 971 | opgetstatic(Frame *frame) 972 | { 973 | CONSTANT_Fieldref_info *fieldref; 974 | CP *cp; 975 | Value v; 976 | U2 i; 977 | 978 | i = frame->code->code[frame->pc++] << 8; 979 | i |= frame->code->code[frame->pc++]; 980 | fieldref = &frame->class->constant_pool[i]->info.fieldref_info; 981 | cp = resolvefield(frame->class, fieldref, &v.v); 982 | if (cp != NULL) { 983 | switch (cp->tag) { 984 | case CONSTANT_Integer: 985 | v.i = getint(cp->info.integer_info.bytes); 986 | break; 987 | case CONSTANT_Long: 988 | v.l = getlong(cp->info.long_info.high_bytes, cp->info.long_info.low_bytes); 989 | break; 990 | case CONSTANT_Float: 991 | v.f = getfloat(cp->info.float_info.bytes); 992 | break; 993 | case CONSTANT_Double: 994 | v.d = getdouble(cp->info.double_info.high_bytes, cp->info.double_info.low_bytes); 995 | break; 996 | case CONSTANT_String: 997 | v.v = heap_alloc(0, 0); 998 | v.v->obj = cp->info.string_info.string; 999 | break; 1000 | } 1001 | } 1002 | frame_stackpush(frame, v); 1003 | return NO_RETURN; 1004 | } 1005 | 1006 | /* goto: branch always */ 1007 | static int 1008 | opgoto(Frame *frame) 1009 | { 1010 | int16_t off = 0; 1011 | U2 base, i; 1012 | 1013 | base = frame->pc - 1; 1014 | i = frame->code->code[frame->pc++] << 8; 1015 | i |= frame->code->code[frame->pc++]; 1016 | memcpy(&off, &i, sizeof(off)); 1017 | frame->pc = base + off; 1018 | return NO_RETURN; 1019 | } 1020 | 1021 | /* goto: branch always (wide intex) */ 1022 | static int 1023 | opgoto_w(Frame *frame) 1024 | { 1025 | int16_t off = 0; 1026 | U4 base, i; 1027 | 1028 | base = frame->pc - 1; 1029 | i = frame->code->code[frame->pc++] << 24; 1030 | i |= frame->code->code[frame->pc++] << 16; 1031 | i |= frame->code->code[frame->pc++] << 8; 1032 | i |= frame->code->code[frame->pc++]; 1033 | memcpy(&off, &i, sizeof(off)); 1034 | frame->pc = base + off; 1035 | return NO_RETURN; 1036 | } 1037 | 1038 | /* i2b: convert int to byte */ 1039 | static int 1040 | opi2b(Frame *frame) 1041 | { 1042 | Value v; 1043 | 1044 | v = frame_stackpop(frame); 1045 | v.i = v.i & UINT8_MAX; 1046 | frame_stackpush(frame, v); 1047 | return NO_RETURN; 1048 | } 1049 | 1050 | /* i2s: convert int to short */ 1051 | static int 1052 | opi2s(Frame *frame) 1053 | { 1054 | Value v; 1055 | 1056 | v = frame_stackpop(frame); 1057 | v.i = v.i & UINT16_MAX; 1058 | frame_stackpush(frame, v); 1059 | return NO_RETURN; 1060 | } 1061 | 1062 | /* i2l: convert int to long */ 1063 | static int 1064 | opi2l(Frame *frame) 1065 | { 1066 | Value v; 1067 | 1068 | v = frame_stackpop(frame); 1069 | v.l = v.i; 1070 | frame_stackpush(frame, v); 1071 | return NO_RETURN; 1072 | } 1073 | 1074 | /* i2f: convert int to float */ 1075 | static int 1076 | opi2f(Frame *frame) 1077 | { 1078 | Value v; 1079 | 1080 | v = frame_stackpop(frame); 1081 | v.f = v.i; 1082 | frame_stackpush(frame, v); 1083 | return NO_RETURN; 1084 | } 1085 | 1086 | /* i2c: convert int to char */ 1087 | static int 1088 | opi2c(Frame *frame) 1089 | { 1090 | Value v; 1091 | 1092 | v = frame_stackpop(frame); 1093 | v.i = v.i & UINT8_MAX; 1094 | frame_stackpush(frame, v); 1095 | return NO_RETURN; 1096 | } 1097 | 1098 | /* i2d: convert int to double */ 1099 | static int 1100 | opi2d(Frame *frame) 1101 | { 1102 | Value v; 1103 | 1104 | v = frame_stackpop(frame); 1105 | v.d = v.i; 1106 | frame_stackpush(frame, v); 1107 | return NO_RETURN; 1108 | } 1109 | 1110 | /* iadd: add int */ 1111 | static int 1112 | opiadd(Frame *frame) 1113 | { 1114 | Value v1, v2; 1115 | 1116 | v2 = frame_stackpop(frame); 1117 | v1 = frame_stackpop(frame); 1118 | v1.i += v2.i; 1119 | frame_stackpush(frame, v1); 1120 | return NO_RETURN; 1121 | } 1122 | 1123 | /* iaload: load int from array */ 1124 | static int 1125 | opiaload(Frame *frame) 1126 | { 1127 | Value va, vi, v; 1128 | 1129 | vi = frame_stackpop(frame); 1130 | va = frame_stackpop(frame); 1131 | if (va.v->obj == NULL) { 1132 | // TODO: throw NullPointerException 1133 | } 1134 | if (vi.i < 0 || vi.i >= va.v->nmemb) { 1135 | // TODO: throw ArrayIndexOutOfBoundsException 1136 | } 1137 | v.i = ((int *)va.v->obj)[vi.i]; 1138 | frame_stackpush(frame, v); 1139 | return NO_RETURN; 1140 | } 1141 | 1142 | /* iastore: store into int array */ 1143 | static int 1144 | opiastore(Frame *frame) 1145 | { 1146 | Value va, vi, vv; 1147 | 1148 | vv = frame_stackpop(frame); 1149 | vi = frame_stackpop(frame); 1150 | va = frame_stackpop(frame); 1151 | if (va.v->obj == NULL) { 1152 | // TODO: throw NullPointerException 1153 | } 1154 | if (vi.i < 0 || vi.i >= va.v->nmemb) { 1155 | // TODO: throw ArrayIndexOutOfBoundsException 1156 | } 1157 | ((int *)va.v->obj)[vi.i] = vv.i; 1158 | return NO_RETURN; 1159 | } 1160 | 1161 | /* iconst_0: push int 0 into stack */ 1162 | static int 1163 | opiconst_0(Frame *frame) 1164 | { 1165 | Value v; 1166 | 1167 | v.i = 0; 1168 | frame_stackpush(frame, v); 1169 | return NO_RETURN; 1170 | } 1171 | 1172 | /* iconst_1: push int 1 into stack */ 1173 | static int 1174 | opiconst_1(Frame *frame) 1175 | { 1176 | Value v; 1177 | 1178 | v.i = 1; 1179 | frame_stackpush(frame, v); 1180 | return NO_RETURN; 1181 | } 1182 | 1183 | /* iconst_2: push int 2 into stack */ 1184 | static int 1185 | opiconst_2(Frame *frame) 1186 | { 1187 | Value v; 1188 | 1189 | v.i = 2; 1190 | frame_stackpush(frame, v); 1191 | return NO_RETURN; 1192 | } 1193 | 1194 | /* iconst_3: push int 3 into stack */ 1195 | static int 1196 | opiconst_3(Frame *frame) 1197 | { 1198 | Value v; 1199 | 1200 | v.i = 3; 1201 | frame_stackpush(frame, v); 1202 | return NO_RETURN; 1203 | } 1204 | 1205 | /* iconst_4: push int 4 into stack */ 1206 | static int 1207 | opiconst_4(Frame *frame) 1208 | { 1209 | Value v; 1210 | 1211 | v.i = 4; 1212 | frame_stackpush(frame, v); 1213 | return NO_RETURN; 1214 | } 1215 | 1216 | /* iconst_5: push int 5 into stack */ 1217 | static int 1218 | opiconst_5(Frame *frame) 1219 | { 1220 | Value v; 1221 | 1222 | v.i = 5; 1223 | frame_stackpush(frame, v); 1224 | return NO_RETURN; 1225 | } 1226 | 1227 | /* iconst_m1: push int -1 into stack */ 1228 | static int 1229 | opiconst_m1(Frame *frame) 1230 | { 1231 | Value v; 1232 | 1233 | v.i = -1; 1234 | frame_stackpush(frame, v); 1235 | return NO_RETURN; 1236 | } 1237 | 1238 | /* idiv: divide int */ 1239 | static int 1240 | opidiv(Frame *frame) 1241 | { 1242 | Value v1, v2; 1243 | 1244 | v2 = frame_stackpop(frame); 1245 | v1 = frame_stackpop(frame); 1246 | v1.i /= v2.i; 1247 | frame_stackpush(frame, v1); 1248 | return NO_RETURN; 1249 | } 1250 | 1251 | /* if_acmpeq: branch if reference comparison succeeds */ 1252 | static int 1253 | opif_acmpeq(Frame *frame) 1254 | { 1255 | Value v1, v2; 1256 | int16_t off = 0; 1257 | U2 base, i; 1258 | 1259 | base = frame->pc - 1; 1260 | i = frame->code->code[frame->pc++] << 8; 1261 | i |= frame->code->code[frame->pc++]; 1262 | v2 = frame_stackpop(frame); 1263 | v1 = frame_stackpop(frame); 1264 | if (v1.v == v2.v) { 1265 | memcpy(&off, &i, sizeof off); 1266 | frame->pc = base + off; 1267 | } 1268 | return NO_RETURN; 1269 | } 1270 | 1271 | /* if_acmpne: branch if reference comparison succeeds */ 1272 | static int 1273 | opif_acmpne(Frame *frame) 1274 | { 1275 | Value v1, v2; 1276 | int16_t off = 0; 1277 | U2 base, i; 1278 | 1279 | base = frame->pc - 1; 1280 | i = frame->code->code[frame->pc++] << 8; 1281 | i |= frame->code->code[frame->pc++]; 1282 | v2 = frame_stackpop(frame); 1283 | v1 = frame_stackpop(frame); 1284 | if (v1.v != v2.v) { 1285 | memcpy(&off, &i, sizeof off); 1286 | frame->pc = base + off; 1287 | } 1288 | return NO_RETURN; 1289 | } 1290 | 1291 | /* if_icmpeq: branch if int comparison succeeds */ 1292 | static int 1293 | opif_icmpeq(Frame *frame) 1294 | { 1295 | Value v1, v2; 1296 | int16_t off = 0; 1297 | U2 base, i; 1298 | 1299 | base = frame->pc - 1; 1300 | i = frame->code->code[frame->pc++] << 8; 1301 | i |= frame->code->code[frame->pc++]; 1302 | v2 = frame_stackpop(frame); 1303 | v1 = frame_stackpop(frame); 1304 | if (v1.i == v2.i) { 1305 | memcpy(&off, &i, sizeof off); 1306 | frame->pc = base + off; 1307 | } 1308 | return NO_RETURN; 1309 | } 1310 | 1311 | /* if_icmpge: branch if int comparison succeeds */ 1312 | static int 1313 | opif_icmpge(Frame *frame) 1314 | { 1315 | Value v1, v2; 1316 | int16_t off = 0; 1317 | U2 base, i; 1318 | 1319 | base = frame->pc - 1; 1320 | i = frame->code->code[frame->pc++] << 8; 1321 | i |= frame->code->code[frame->pc++]; 1322 | v2 = frame_stackpop(frame); 1323 | v1 = frame_stackpop(frame); 1324 | if (v1.i >= v2.i) { 1325 | memcpy(&off, &i, sizeof off); 1326 | frame->pc = base + off; 1327 | } 1328 | return NO_RETURN; 1329 | } 1330 | 1331 | /* if_icmpgt: branch if int comparison succeeds */ 1332 | static int 1333 | opif_icmpgt(Frame *frame) 1334 | { 1335 | Value v1, v2; 1336 | int16_t off = 0; 1337 | U2 base, i; 1338 | 1339 | base = frame->pc - 1; 1340 | i = frame->code->code[frame->pc++] << 8; 1341 | i |= frame->code->code[frame->pc++]; 1342 | v2 = frame_stackpop(frame); 1343 | v1 = frame_stackpop(frame); 1344 | if (v1.i > v2.i) { 1345 | memcpy(&off, &i, sizeof off); 1346 | frame->pc = base + off; 1347 | } 1348 | return NO_RETURN; 1349 | } 1350 | 1351 | /* if_icmple: branch if int comparison succeeds */ 1352 | static int 1353 | opif_icmple(Frame *frame) 1354 | { 1355 | Value v1, v2; 1356 | int16_t off = 0; 1357 | U2 base, i; 1358 | 1359 | base = frame->pc - 1; 1360 | i = frame->code->code[frame->pc++] << 8; 1361 | i |= frame->code->code[frame->pc++]; 1362 | v2 = frame_stackpop(frame); 1363 | v1 = frame_stackpop(frame); 1364 | if (v1.i <= v2.i) { 1365 | memcpy(&off, &i, sizeof off); 1366 | frame->pc = base + off; 1367 | } 1368 | return NO_RETURN; 1369 | } 1370 | 1371 | /* if_icmplt: branch if int comparison succeeds */ 1372 | static int 1373 | opif_icmplt(Frame *frame) 1374 | { 1375 | Value v1, v2; 1376 | int16_t off = 0; 1377 | U2 base, i; 1378 | 1379 | base = frame->pc - 1; 1380 | i = frame->code->code[frame->pc++] << 8; 1381 | i |= frame->code->code[frame->pc++]; 1382 | v2 = frame_stackpop(frame); 1383 | v1 = frame_stackpop(frame); 1384 | if (v1.i < v2.i) { 1385 | memcpy(&off, &i, sizeof off); 1386 | frame->pc = base + off; 1387 | } 1388 | return NO_RETURN; 1389 | } 1390 | 1391 | /* if_icmpne: branch if int comparison succeeds */ 1392 | static int 1393 | opif_icmpne(Frame *frame) 1394 | { 1395 | Value v1, v2; 1396 | int16_t off = 0; 1397 | U2 base, i; 1398 | 1399 | base = frame->pc - 1; 1400 | i = frame->code->code[frame->pc++] << 8; 1401 | i |= frame->code->code[frame->pc++]; 1402 | v2 = frame_stackpop(frame); 1403 | v1 = frame_stackpop(frame); 1404 | if (v1.i != v2.i) { 1405 | memcpy(&off, &i, sizeof off); 1406 | frame->pc = base + off; 1407 | } 1408 | return NO_RETURN; 1409 | } 1410 | 1411 | /* ifeq: branch if int comparison with zero succeeds */ 1412 | static int 1413 | opifeq(Frame *frame) 1414 | { 1415 | Value v; 1416 | int16_t off = 0; 1417 | U2 base, i; 1418 | 1419 | base = frame->pc - 1; 1420 | i = frame->code->code[frame->pc++] << 8; 1421 | i |= frame->code->code[frame->pc++]; 1422 | v = frame_stackpop(frame); 1423 | if (v.i == 0) { 1424 | memcpy(&off, &i, sizeof off); 1425 | frame->pc = base + off; 1426 | } 1427 | return NO_RETURN; 1428 | } 1429 | 1430 | /* ifne: branch if int comparison with zero succeeds */ 1431 | static int 1432 | opifne(Frame *frame) 1433 | { 1434 | Value v; 1435 | int16_t off = 0; 1436 | U2 base, i; 1437 | 1438 | base = frame->pc - 1; 1439 | i = frame->code->code[frame->pc++] << 8; 1440 | i |= frame->code->code[frame->pc++]; 1441 | v = frame_stackpop(frame); 1442 | if (v.i != 0) { 1443 | memcpy(&off, &i, sizeof off); 1444 | frame->pc = base + off; 1445 | } 1446 | return NO_RETURN; 1447 | } 1448 | 1449 | /* ifge: branch if int comparison with zero succeeds */ 1450 | static int 1451 | opifge(Frame *frame) 1452 | { 1453 | Value v; 1454 | int16_t off = 0; 1455 | U2 base, i; 1456 | 1457 | base = frame->pc - 1; 1458 | i = frame->code->code[frame->pc++] << 8; 1459 | i |= frame->code->code[frame->pc++]; 1460 | v = frame_stackpop(frame); 1461 | if (v.i >= 0) { 1462 | memcpy(&off, &i, sizeof off); 1463 | frame->pc = base + off; 1464 | } 1465 | return NO_RETURN; 1466 | } 1467 | 1468 | /* ifgt: branch if int comparison with zero succeeds */ 1469 | static int 1470 | opifgt(Frame *frame) 1471 | { 1472 | Value v; 1473 | int16_t off = 0; 1474 | U2 base, i; 1475 | 1476 | base = frame->pc - 1; 1477 | i = frame->code->code[frame->pc++] << 8; 1478 | i |= frame->code->code[frame->pc++]; 1479 | v = frame_stackpop(frame); 1480 | if (v.i > 0) { 1481 | memcpy(&off, &i, sizeof off); 1482 | frame->pc = base + off; 1483 | } 1484 | return NO_RETURN; 1485 | } 1486 | 1487 | /* ifle: branch if int comparison with zero succeeds */ 1488 | static int 1489 | opifle(Frame *frame) 1490 | { 1491 | Value v; 1492 | int16_t off = 0; 1493 | U2 base, i; 1494 | 1495 | base = frame->pc - 1; 1496 | i = frame->code->code[frame->pc++] << 8; 1497 | i |= frame->code->code[frame->pc++]; 1498 | v = frame_stackpop(frame); 1499 | if (v.i <= 0) { 1500 | memcpy(&off, &i, sizeof off); 1501 | frame->pc = base + off; 1502 | } 1503 | return NO_RETURN; 1504 | } 1505 | 1506 | /* iflt: branch if int comparison with zero succeeds */ 1507 | static int 1508 | opiflt(Frame *frame) 1509 | { 1510 | Value v; 1511 | int16_t off = 0; 1512 | U2 base, i; 1513 | 1514 | base = frame->pc - 1; 1515 | i = frame->code->code[frame->pc++] << 8; 1516 | i |= frame->code->code[frame->pc++]; 1517 | v = frame_stackpop(frame); 1518 | if (v.i < 0) { 1519 | memcpy(&off, &i, sizeof off); 1520 | frame->pc = base + off; 1521 | } 1522 | return NO_RETURN; 1523 | } 1524 | 1525 | /* iinc: increment local variable by constant */ 1526 | static int 1527 | opiinc(Frame *frame) 1528 | { 1529 | Value v; 1530 | U1 i; 1531 | int8_t c; 1532 | 1533 | i = frame->code->code[frame->pc++]; 1534 | c = (int8_t)frame->code->code[frame->pc++]; 1535 | v = frame_localload(frame, i); 1536 | v.i += c; 1537 | frame_localstore(frame, i, v); 1538 | return NO_RETURN; 1539 | } 1540 | 1541 | /* iload: load int from local variable */ 1542 | static int 1543 | opiload(Frame *frame) 1544 | { 1545 | Value v; 1546 | U2 i; 1547 | 1548 | i = frame->code->code[frame->pc++]; 1549 | v = frame_localload(frame, i); 1550 | frame_stackpush(frame, v); 1551 | return NO_RETURN; 1552 | } 1553 | 1554 | /* iload_0: load int from local variable */ 1555 | static int 1556 | opiload_0(Frame *frame) 1557 | { 1558 | Value v; 1559 | 1560 | v = frame_localload(frame, 0); 1561 | frame_stackpush(frame, v); 1562 | return NO_RETURN; 1563 | } 1564 | 1565 | /* iload_1: load int from local variable */ 1566 | static int 1567 | opiload_1(Frame *frame) 1568 | { 1569 | Value v; 1570 | 1571 | v = frame_localload(frame, 1); 1572 | frame_stackpush(frame, v); 1573 | return NO_RETURN; 1574 | } 1575 | 1576 | /* iload_2: load int from local variable */ 1577 | static int 1578 | opiload_2(Frame *frame) 1579 | { 1580 | Value v; 1581 | 1582 | v = frame_localload(frame, 2); 1583 | frame_stackpush(frame, v); 1584 | return NO_RETURN; 1585 | } 1586 | 1587 | /* iload_3: load int from local variable */ 1588 | static int 1589 | opiload_3(Frame *frame) 1590 | { 1591 | Value v; 1592 | 1593 | v = frame_localload(frame, 3); 1594 | frame_stackpush(frame, v); 1595 | return NO_RETURN; 1596 | } 1597 | 1598 | /* imul: multiply int */ 1599 | static int 1600 | opimul(Frame *frame) 1601 | { 1602 | Value v1, v2; 1603 | 1604 | v2 = frame_stackpop(frame); 1605 | v1 = frame_stackpop(frame); 1606 | v1.i *= v2.i; 1607 | frame_stackpush(frame, v1); 1608 | return NO_RETURN; 1609 | } 1610 | 1611 | /* ineg: negate int */ 1612 | static int 1613 | opineg(Frame *frame) 1614 | { 1615 | Value v; 1616 | 1617 | v = frame_stackpop(frame); 1618 | v.i = -v.i; 1619 | frame_stackpush(frame, v); 1620 | return NO_RETURN; 1621 | } 1622 | 1623 | /* ifnonnull: branch if reference is not null */ 1624 | static int 1625 | opifnonnull(Frame *frame) 1626 | { 1627 | Value v; 1628 | int16_t off = 0; 1629 | U2 base, i; 1630 | 1631 | base = frame->pc - 1; 1632 | i = frame->code->code[frame->pc++] << 8; 1633 | i |= frame->code->code[frame->pc++]; 1634 | v = frame_stackpop(frame); 1635 | if (v.v != NULL) { 1636 | memcpy(&off, &i, sizeof off); 1637 | frame->pc = base + off; 1638 | } 1639 | return NO_RETURN; 1640 | } 1641 | 1642 | /* ifnull: branch if reference is null */ 1643 | static int 1644 | opifnull(Frame *frame) 1645 | { 1646 | Value v; 1647 | int16_t off = 0; 1648 | U2 base, i; 1649 | 1650 | base = frame->pc - 1; 1651 | i = frame->code->code[frame->pc++] << 8; 1652 | i |= frame->code->code[frame->pc++]; 1653 | v = frame_stackpop(frame); 1654 | if (v.v == NULL) { 1655 | memcpy(&off, &i, sizeof off); 1656 | frame->pc = base + off; 1657 | } 1658 | return NO_RETURN; 1659 | } 1660 | 1661 | /* invokestatic: invoke a class (static) method */ 1662 | static int 1663 | opinvokestatic(Frame *frame) 1664 | { 1665 | CONSTANT_Methodref_info *methodref; 1666 | ClassFile *class; 1667 | enum JavaClass jclass; 1668 | char *classname, *name, *type; 1669 | U2 i; 1670 | 1671 | // TODO: method must not be an instance initialization method, 1672 | // or the class or interface initialization method. 1673 | i = frame->code->code[frame->pc++] << 8; 1674 | i |= frame->code->code[frame->pc++]; 1675 | methodref = &frame->class->constant_pool[i]->info.methodref_info; 1676 | classname = class_getclassname(frame->class, methodref->class_index); 1677 | class_getnameandtype(frame->class, methodref->name_and_type_index, &name, &type); 1678 | if ((jclass = native_javaclass(classname)) != NONE_CLASS) { 1679 | native_javamethod(frame, jclass, name, type); 1680 | } else if ((class = classload(classname)) != NULL) { 1681 | if (methodcall(class, frame, name, type, ACC_STATIC) == -1) { 1682 | errx(EXIT_FAILURE, "could not find method %s", name); 1683 | } 1684 | } else { 1685 | errx(EXIT_FAILURE, "could not load class %s", classname); 1686 | } 1687 | return NO_RETURN; 1688 | } 1689 | 1690 | /* invokevirtual: invoke instance method; dispatch based on class */ 1691 | static int 1692 | opinvokevirtual(Frame *frame) 1693 | { 1694 | CONSTANT_Methodref_info *methodref; 1695 | ClassFile *class; 1696 | enum JavaClass jclass; 1697 | char *classname, *name, *type; 1698 | U2 i; 1699 | 1700 | i = frame->code->code[frame->pc++] << 8; 1701 | i |= frame->code->code[frame->pc++]; 1702 | methodref = &frame->class->constant_pool[i]->info.methodref_info; 1703 | classname = class_getclassname(frame->class, methodref->class_index); 1704 | class_getnameandtype(frame->class, methodref->name_and_type_index, &name, &type); 1705 | if ((jclass = native_javaclass(classname)) != NONE_CLASS) { 1706 | if (native_javamethod(frame, jclass, name, type) == -1) { 1707 | errx(EXIT_FAILURE, "error invoking native method %s", name); 1708 | } 1709 | } else if ((class = classload(classname)) != NULL) { 1710 | if (methodcall(class, NULL, name, type, ACC_STATIC) == -1) { 1711 | errx(EXIT_FAILURE, "could not find method %s", name); 1712 | } 1713 | } else { 1714 | errx(EXIT_FAILURE, "could not load class %s", classname); 1715 | } 1716 | return NO_RETURN; 1717 | } 1718 | 1719 | /* irem: remainder int */ 1720 | static int 1721 | opirem(Frame *frame) 1722 | { 1723 | Value v1, v2; 1724 | 1725 | v2 = frame_stackpop(frame); 1726 | v1 = frame_stackpop(frame); 1727 | v1.i = v1.i - (v1.i / v2.i) * v2.i; 1728 | frame_stackpush(frame, v1); 1729 | return NO_RETURN; 1730 | } 1731 | 1732 | /* ireturn: return something from method */ 1733 | static int 1734 | opireturn(Frame *frame) 1735 | { 1736 | (void)frame; 1737 | return RETURN_OPERAND; 1738 | } 1739 | 1740 | /* store: store into local variable */ 1741 | static int 1742 | opistore(Frame *frame) 1743 | { 1744 | Value v; 1745 | U2 i; 1746 | 1747 | i = frame->code->code[frame->pc++]; 1748 | v = frame_stackpop(frame); 1749 | frame_localstore(frame, i, v); 1750 | return NO_RETURN; 1751 | } 1752 | 1753 | /* istore_0: store int into local variable */ 1754 | static int 1755 | opistore_0(Frame *frame) 1756 | { 1757 | Value v; 1758 | 1759 | v = frame_stackpop(frame); 1760 | frame_localstore(frame, 0, v); 1761 | return NO_RETURN; 1762 | } 1763 | 1764 | /* istore_1: store int into local variable */ 1765 | static int 1766 | opistore_1(Frame *frame) 1767 | { 1768 | Value v; 1769 | 1770 | v = frame_stackpop(frame); 1771 | frame_localstore(frame, 1, v); 1772 | return NO_RETURN; 1773 | } 1774 | 1775 | /* istore_2: store int into local variable */ 1776 | static int 1777 | opistore_2(Frame *frame) 1778 | { 1779 | Value v; 1780 | 1781 | v = frame_stackpop(frame); 1782 | frame_localstore(frame, 2, v); 1783 | return NO_RETURN; 1784 | } 1785 | 1786 | /* istore_3: store int into local variable */ 1787 | static int 1788 | opistore_3(Frame *frame) 1789 | { 1790 | Value v; 1791 | 1792 | v = frame_stackpop(frame); 1793 | frame_localstore(frame, 3, v); 1794 | return NO_RETURN; 1795 | } 1796 | 1797 | /* isub: subtract int */ 1798 | static int 1799 | opisub(Frame *frame) 1800 | { 1801 | Value v1, v2; 1802 | 1803 | v2 = frame_stackpop(frame); 1804 | v1 = frame_stackpop(frame); 1805 | v1.i -= v2.i; 1806 | frame_stackpush(frame, v1); 1807 | return NO_RETURN; 1808 | } 1809 | 1810 | /* jsr: jump subroutine */ 1811 | static int 1812 | opjsr(Frame *frame) 1813 | { 1814 | Value v; 1815 | int16_t off = 0; 1816 | U2 base, i; 1817 | 1818 | base = frame->pc - 1; 1819 | i = frame->code->code[frame->pc++] << 8; 1820 | i |= frame->code->code[frame->pc++]; 1821 | memcpy(&off, &i, sizeof off); 1822 | frame->pc = base + off; 1823 | v.i = base + 2; 1824 | frame_stackpush(frame, v); 1825 | return NO_RETURN; 1826 | } 1827 | 1828 | /* jsr: jump subroutine (wide index) */ 1829 | static int 1830 | opjsr_w(Frame *frame) 1831 | { 1832 | Value v; 1833 | int16_t off = 0; 1834 | U4 base, i; 1835 | 1836 | base = frame->pc - 1; 1837 | i = frame->code->code[frame->pc++] << 24; 1838 | i |= frame->code->code[frame->pc++] << 16; 1839 | i |= frame->code->code[frame->pc++] << 8; 1840 | i |= frame->code->code[frame->pc++]; 1841 | memcpy(&off, &i, sizeof off); 1842 | frame->pc = base + off; 1843 | v.i = base + 4; 1844 | frame_stackpush(frame, v); 1845 | return NO_RETURN; 1846 | } 1847 | 1848 | /* l2d: convert long to double */ 1849 | static int 1850 | opl2d(Frame *frame) 1851 | { 1852 | Value v; 1853 | 1854 | v = frame_stackpop(frame); 1855 | v.d = v.l; 1856 | frame_stackpush(frame, v); 1857 | return NO_RETURN; 1858 | } 1859 | 1860 | /* l2f: convert long to float */ 1861 | static int 1862 | opl2f(Frame *frame) 1863 | { 1864 | Value v; 1865 | 1866 | v = frame_stackpop(frame); 1867 | v.f = v.l; 1868 | frame_stackpush(frame, v); 1869 | return NO_RETURN; 1870 | } 1871 | 1872 | /* l2i: convert long to int */ 1873 | static int 1874 | opl2i(Frame *frame) 1875 | { 1876 | Value v; 1877 | 1878 | v = frame_stackpop(frame); 1879 | v.i = v.l; 1880 | frame_stackpush(frame, v); 1881 | return NO_RETURN; 1882 | } 1883 | 1884 | /* ladd: add long */ 1885 | static int 1886 | opladd(Frame *frame) 1887 | { 1888 | Value v1, v2; 1889 | 1890 | v2 = frame_stackpop(frame); 1891 | v1 = frame_stackpop(frame); 1892 | v1.l += v2.l; 1893 | frame_stackpush(frame, v1); 1894 | return NO_RETURN; 1895 | } 1896 | 1897 | /* laload: load long from array */ 1898 | static int 1899 | oplaload(Frame *frame) 1900 | { 1901 | Value va, vi, v; 1902 | 1903 | vi = frame_stackpop(frame); 1904 | va = frame_stackpop(frame); 1905 | if (va.v->obj == NULL) { 1906 | // TODO: throw NullPointerException 1907 | } 1908 | if (vi.i < 0 || vi.i >= va.v->nmemb) { 1909 | // TODO: throw ArrayIndexOutOfBoundsException 1910 | } 1911 | v.l = ((long *)va.v->obj)[vi.i]; 1912 | frame_stackpush(frame, v); 1913 | return NO_RETURN; 1914 | } 1915 | 1916 | /* land: boolean AND long */ 1917 | static int 1918 | opland(Frame *frame) 1919 | { 1920 | Value v1, v2; 1921 | 1922 | v2 = frame_stackpop(frame); 1923 | v1 = frame_stackpop(frame); 1924 | v1.l &= v2.l; 1925 | frame_stackpush(frame, v1); 1926 | return NO_RETURN; 1927 | } 1928 | 1929 | /* lastore: store into long array */ 1930 | static int 1931 | oplastore(Frame *frame) 1932 | { 1933 | Value va, vi, vv; 1934 | 1935 | vv = frame_stackpop(frame); 1936 | vi = frame_stackpop(frame); 1937 | va = frame_stackpop(frame); 1938 | if (va.v->obj == NULL) { 1939 | // TODO: throw NullPointerException 1940 | } 1941 | if (vi.i < 0 || vi.i >= va.v->nmemb) { 1942 | // TODO: throw ArrayIndexOutOfBoundsException 1943 | } 1944 | ((long *)va.v->obj)[vi.i] = vv.l; 1945 | return NO_RETURN; 1946 | } 1947 | 1948 | /* lcmp: compare long */ 1949 | static int 1950 | oplcmp(Frame *frame) 1951 | { 1952 | Value v1, v2, v; 1953 | 1954 | v2 = frame_stackpop(frame); 1955 | v1 = frame_stackpop(frame); 1956 | if (v1.l > v2.l) 1957 | v.i = 1; 1958 | else if (v1.l < v2.l) 1959 | v.i = -1; 1960 | else 1961 | v.i = 0; 1962 | frame_stackpush(frame, v); 1963 | return NO_RETURN; 1964 | } 1965 | 1966 | /* lconst_0: push long 0 into stack */ 1967 | static int 1968 | oplconst_0(Frame *frame) 1969 | { 1970 | Value v; 1971 | 1972 | v.l = 0; 1973 | frame_stackpush(frame, v); 1974 | return NO_RETURN; 1975 | } 1976 | 1977 | /* lconst_1: push long 1 into stack */ 1978 | static int 1979 | oplconst_1(Frame *frame) 1980 | { 1981 | Value v; 1982 | 1983 | v.l = 1; 1984 | frame_stackpush(frame, v); 1985 | return NO_RETURN; 1986 | } 1987 | 1988 | /* ldc: push item from run-time constant pool */ 1989 | static int 1990 | opldc(Frame *frame) 1991 | { 1992 | Value v; 1993 | U2 i; 1994 | 1995 | i = frame->code->code[frame->pc++]; 1996 | v = resolveconstant(frame->class, i); 1997 | frame_stackpush(frame, v); 1998 | return NO_RETURN; 1999 | } 2000 | 2001 | /* ldc2_w: push long or double from run-time constant pool (wide index) */ 2002 | static int 2003 | opldc2_w(Frame *frame) 2004 | { 2005 | Value v; 2006 | U2 i; 2007 | 2008 | i = frame->code->code[frame->pc++] << 8; 2009 | i |= frame->code->code[frame->pc++]; 2010 | v = resolveconstant(frame->class, i); 2011 | frame_stackpush(frame, v); 2012 | return NO_RETURN; 2013 | } 2014 | 2015 | /* ldc_w: push item from run-time constant pool (wide index) */ 2016 | static int 2017 | opldc_w(Frame *frame) 2018 | { 2019 | Value v; 2020 | U2 i; 2021 | 2022 | i = frame->code->code[frame->pc++] << 8; 2023 | i |= frame->code->code[frame->pc++]; 2024 | v = resolveconstant(frame->class, i); 2025 | frame_stackpush(frame, v); 2026 | return NO_RETURN; 2027 | } 2028 | 2029 | /* ldiv: divide long */ 2030 | static int 2031 | opldiv(Frame *frame) 2032 | { 2033 | Value v1, v2; 2034 | 2035 | v2 = frame_stackpop(frame); 2036 | v1 = frame_stackpop(frame); 2037 | v1.l /= v2.l; 2038 | frame_stackpush(frame, v1); 2039 | return NO_RETURN; 2040 | } 2041 | 2042 | /* lload: load long from local variable */ 2043 | static int 2044 | oplload(Frame *frame) 2045 | { 2046 | Value v; 2047 | U2 i; 2048 | 2049 | i = frame->code->code[frame->pc++]; 2050 | v = frame_localload(frame, i); 2051 | frame_stackpush(frame, v); 2052 | return NO_RETURN; 2053 | } 2054 | 2055 | /* lload_0: load long from local variable */ 2056 | static int 2057 | oplload_0(Frame *frame) 2058 | { 2059 | Value v; 2060 | 2061 | v = frame_localload(frame, 0); 2062 | frame_stackpush(frame, v); 2063 | return NO_RETURN; 2064 | } 2065 | 2066 | /* lload_1: load long from local variable */ 2067 | static int 2068 | oplload_1(Frame *frame) 2069 | { 2070 | Value v; 2071 | 2072 | v = frame_localload(frame, 1); 2073 | frame_stackpush(frame, v); 2074 | return NO_RETURN; 2075 | } 2076 | 2077 | /* lload_2: load long from local variable */ 2078 | static int 2079 | oplload_2(Frame *frame) 2080 | { 2081 | Value v; 2082 | 2083 | v = frame_localload(frame, 2); 2084 | frame_stackpush(frame, v); 2085 | return NO_RETURN; 2086 | } 2087 | 2088 | /* lload_3: load long from local variable */ 2089 | static int 2090 | oplload_3(Frame *frame) 2091 | { 2092 | Value v; 2093 | 2094 | v = frame_localload(frame, 3); 2095 | frame_stackpush(frame, v); 2096 | return NO_RETURN; 2097 | } 2098 | 2099 | /* lmul: multiply long */ 2100 | static int 2101 | oplmul(Frame *frame) 2102 | { 2103 | Value v1, v2; 2104 | 2105 | v2 = frame_stackpop(frame); 2106 | v1 = frame_stackpop(frame); 2107 | v1.l *= v2.l; 2108 | frame_stackpush(frame, v1); 2109 | return NO_RETURN; 2110 | } 2111 | 2112 | /* lneg: negate long */ 2113 | static int 2114 | oplneg(Frame *frame) 2115 | { 2116 | Value v; 2117 | 2118 | v = frame_stackpop(frame); 2119 | v.l = -v.l; 2120 | frame_stackpush(frame, v); 2121 | return NO_RETURN; 2122 | } 2123 | 2124 | /* lookupswitch: access jump table by key match and jump */ 2125 | static int 2126 | oplookupswitch(Frame *frame) 2127 | { 2128 | int32_t def, npairs, match, offset, j; 2129 | U4 a, b, c, d, baseaddr, targetaddr; 2130 | Value v; 2131 | 2132 | baseaddr = frame->pc - 1; 2133 | while (frame->pc % 4) 2134 | frame->pc++; 2135 | v = frame_stackpop(frame); 2136 | a = frame->code->code[frame->pc++]; 2137 | b = frame->code->code[frame->pc++]; 2138 | c = frame->code->code[frame->pc++]; 2139 | d = frame->code->code[frame->pc++]; 2140 | def = (a << 24) | (b << 16) | (c << 8) | d; 2141 | a = frame->code->code[frame->pc++]; 2142 | b = frame->code->code[frame->pc++]; 2143 | c = frame->code->code[frame->pc++]; 2144 | d = frame->code->code[frame->pc++]; 2145 | npairs = (a << 24) | (b << 16) | (c << 8) | d; 2146 | targetaddr = baseaddr + def; 2147 | for (j = 0; j <= npairs; j++) { 2148 | a = frame->code->code[frame->pc++]; 2149 | b = frame->code->code[frame->pc++]; 2150 | c = frame->code->code[frame->pc++]; 2151 | d = frame->code->code[frame->pc++]; 2152 | match = (a << 24) | (b << 16) | (c << 8) | d; 2153 | a = frame->code->code[frame->pc++]; 2154 | b = frame->code->code[frame->pc++]; 2155 | c = frame->code->code[frame->pc++]; 2156 | d = frame->code->code[frame->pc++]; 2157 | offset = (a << 24) | (b << 16) | (c << 8) | d; 2158 | if (v.i == match) { 2159 | targetaddr = baseaddr + offset; 2160 | break; 2161 | } 2162 | } 2163 | frame->pc = targetaddr; 2164 | return NO_RETURN; 2165 | } 2166 | 2167 | /* lor: boolean OR long */ 2168 | static int 2169 | oplor(Frame *frame) 2170 | { 2171 | Value v1, v2; 2172 | 2173 | v2 = frame_stackpop(frame); 2174 | v1 = frame_stackpop(frame); 2175 | v1.l |= v2.l; 2176 | frame_stackpush(frame, v1); 2177 | return NO_RETURN; 2178 | } 2179 | 2180 | /* lrem: remainder long */ 2181 | static int 2182 | oplrem(Frame *frame) 2183 | { 2184 | Value v1, v2; 2185 | 2186 | v2 = frame_stackpop(frame); 2187 | v1 = frame_stackpop(frame); 2188 | v1.l = v1.l - (v1.l / v2.l) * v2.l; 2189 | frame_stackpush(frame, v1); 2190 | return NO_RETURN; 2191 | } 2192 | 2193 | /* lstore: store long into local variable */ 2194 | static int 2195 | oplstore(Frame *frame) 2196 | { 2197 | Value v; 2198 | U2 i; 2199 | 2200 | i = frame->code->code[frame->pc++]; 2201 | v = frame_stackpop(frame); 2202 | frame_localstore(frame, i, v); 2203 | frame_localstore(frame, i + 1, v); 2204 | return NO_RETURN; 2205 | } 2206 | 2207 | /* lstore_0: store long into local variable */ 2208 | static int 2209 | oplstore_0(Frame *frame) 2210 | { 2211 | Value v; 2212 | 2213 | v = frame_stackpop(frame); 2214 | frame_localstore(frame, 0, v); 2215 | frame_localstore(frame, 1, v); 2216 | return NO_RETURN; 2217 | } 2218 | 2219 | /* lstore_1: store long into local variable */ 2220 | static int 2221 | oplstore_1(Frame *frame) 2222 | { 2223 | Value v; 2224 | 2225 | v = frame_stackpop(frame); 2226 | frame_localstore(frame, 1, v); 2227 | frame_localstore(frame, 2, v); 2228 | return NO_RETURN; 2229 | } 2230 | 2231 | /* lstore_2: store long into local variable */ 2232 | static int 2233 | oplstore_2(Frame *frame) 2234 | { 2235 | Value v; 2236 | 2237 | v = frame_stackpop(frame); 2238 | frame_localstore(frame, 2, v); 2239 | frame_localstore(frame, 3, v); 2240 | return NO_RETURN; 2241 | } 2242 | 2243 | /* lstore_3: store long into local variable */ 2244 | static int 2245 | oplstore_3(Frame *frame) 2246 | { 2247 | Value v; 2248 | 2249 | v = frame_stackpop(frame); 2250 | frame_localstore(frame, 3, v); 2251 | frame_localstore(frame, 4, v); 2252 | return NO_RETURN; 2253 | } 2254 | 2255 | /* lsub: subtract long */ 2256 | static int 2257 | oplsub(Frame *frame) 2258 | { 2259 | Value v1, v2; 2260 | 2261 | v2 = frame_stackpop(frame); 2262 | v1 = frame_stackpop(frame); 2263 | v1.l -= v2.l; 2264 | frame_stackpush(frame, v1); 2265 | return NO_RETURN; 2266 | } 2267 | 2268 | /* lxor: boolean XOR long */ 2269 | static int 2270 | oplxor(Frame *frame) 2271 | { 2272 | Value v1, v2; 2273 | 2274 | v2 = frame_stackpop(frame); 2275 | v1 = frame_stackpop(frame); 2276 | v1.l ^= v2.l; 2277 | frame_stackpush(frame, v1); 2278 | return NO_RETURN; 2279 | } 2280 | 2281 | /* multianewarray: create new multidimensional array */ 2282 | static int 2283 | opmultianewarray(Frame *frame) 2284 | { 2285 | Value v; 2286 | Heap *h; 2287 | char *type; 2288 | int32_t *sizes; 2289 | U1 i, dimension; 2290 | U2 index; 2291 | size_t s; 2292 | 2293 | index = frame->code->code[frame->pc++] << 8; 2294 | index = frame->code->code[frame->pc++]; 2295 | dimension = frame->code->code[frame->pc++]; 2296 | sizes = ecalloc(dimension, sizeof *sizes); 2297 | type = class_getclassname(frame->class, index); 2298 | switch (*type) { 2299 | case TYPE_REFERENCE: 2300 | case TYPE_ARRAY: 2301 | s = sizeof (void *); 2302 | break; 2303 | case TYPE_DOUBLE: 2304 | case TYPE_LONG: 2305 | s = sizeof (int64_t); 2306 | break; 2307 | default: 2308 | s = sizeof (int32_t); 2309 | break; 2310 | } 2311 | for (i = 0; i < dimension; i++) { 2312 | v = frame_stackpop(frame); 2313 | if (v.i < 0) { 2314 | // TODO: throw NegativeArraySizeException 2315 | } 2316 | if (v.i == 0) { 2317 | // TODO: handle zero size 2318 | } 2319 | sizes[dimension - i - 1] = v.i; 2320 | } 2321 | h = array_new(sizes, dimension, s); 2322 | if (h == NULL) { 2323 | // TODO: throw error 2324 | } 2325 | v.v = h; 2326 | frame_stackpush(frame, v); 2327 | return NO_RETURN; 2328 | } 2329 | 2330 | /* newarray: create new array */ 2331 | static int 2332 | opnewarray(Frame *frame) 2333 | { 2334 | Value v; 2335 | U1 type; 2336 | Heap *h; 2337 | size_t s; 2338 | 2339 | type = frame->code->code[frame->pc++]; 2340 | v = frame_stackpop(frame); 2341 | switch (type) { 2342 | case T_LONG: 2343 | s = sizeof (int64_t); 2344 | break; 2345 | case T_DOUBLE: 2346 | s = sizeof (double); 2347 | break; 2348 | case T_FLOAT: 2349 | s = sizeof (float); 2350 | break; 2351 | default: 2352 | s = sizeof (int32_t); 2353 | break; 2354 | } 2355 | if (v.i < 0) { 2356 | // TODO: throw NegativeArraySizeException 2357 | } 2358 | if (v.i == 0) { 2359 | // TODO: handle zero size 2360 | } 2361 | h = array_new(&v.i, 1, s); 2362 | v.v = h; 2363 | frame_stackpush(frame, v); 2364 | return NO_RETURN; 2365 | } 2366 | 2367 | /* nop: do nothing */ 2368 | static int 2369 | opnop(Frame *frame) 2370 | { 2371 | (void)frame; 2372 | errx(EXIT_FAILURE, "instruction %02x not implemented (yet)", frame->code->code[frame->pc - 1]); 2373 | return NO_RETURN; 2374 | } 2375 | 2376 | /* pop: pop the top operand stack value */ 2377 | static int 2378 | oppop(Frame *frame) 2379 | { 2380 | frame_stackpop(frame); 2381 | return NO_RETURN; 2382 | } 2383 | 2384 | /* pop: pop the top one or two operand stack values */ 2385 | static int 2386 | oppop2(Frame *frame) 2387 | { 2388 | frame_stackpop(frame); 2389 | frame_stackpop(frame); 2390 | return NO_RETURN; 2391 | } 2392 | 2393 | /* putstatic: set static field in class */ 2394 | static int 2395 | opputstatic(Frame *frame) 2396 | { 2397 | CONSTANT_Fieldref_info *fieldref; 2398 | CP *cp; 2399 | Value v; 2400 | U2 i; 2401 | 2402 | v = frame_stackpop(frame); 2403 | i = frame->code->code[frame->pc++] << 8; 2404 | i |= frame->code->code[frame->pc++]; 2405 | fieldref = &frame->class->constant_pool[i]->info.fieldref_info; 2406 | cp = resolvefield(frame->class, fieldref, NULL); 2407 | if (cp != NULL) { 2408 | switch (cp->tag) { 2409 | case CONSTANT_Integer: 2410 | memcpy(&cp->info.integer_info.bytes, &v.i, 4); 2411 | break; 2412 | case CONSTANT_Long: 2413 | memcpy(&cp->info.long_info.high_bytes, (&v.l) + 0, 4); 2414 | memcpy(&cp->info.long_info.low_bytes, (&v.l) + 4, 4); 2415 | break; 2416 | case CONSTANT_Float: 2417 | memcpy(&cp->info.float_info.bytes, &v.f, 4); 2418 | break; 2419 | case CONSTANT_Double: 2420 | memcpy(&cp->info.double_info.high_bytes, (&v.d) + 0, 4); 2421 | memcpy(&cp->info.double_info.low_bytes, (&v.d) + 4, 4); 2422 | break; 2423 | } 2424 | } 2425 | return NO_RETURN; 2426 | } 2427 | 2428 | /* ret: return from subroutine */ 2429 | static int 2430 | opret(Frame *frame) 2431 | { 2432 | Value v; 2433 | U2 i; 2434 | 2435 | i = frame->code->code[frame->pc++]; 2436 | v = frame_localload(frame, i); 2437 | frame->pc = v.i; 2438 | return RETURN_VOID; 2439 | } 2440 | 2441 | /* return: return void from method */ 2442 | static int 2443 | opreturn(Frame *frame) 2444 | { 2445 | (void)frame; 2446 | return RETURN_VOID; 2447 | } 2448 | 2449 | /* sipush: push short */ 2450 | static int 2451 | opsipush(Frame *frame) 2452 | { 2453 | Value v; 2454 | U2 u; 2455 | 2456 | u = frame->code->code[frame->pc++] << 8; 2457 | u |= frame->code->code[frame->pc++]; 2458 | v.i = (int16_t)u; 2459 | frame_stackpush(frame, v); 2460 | return NO_RETURN; 2461 | } 2462 | 2463 | /* access jump table by index and jump */ 2464 | static int 2465 | optableswitch(Frame *frame) 2466 | { 2467 | int32_t def, high, low, j, n; 2468 | U4 a, b, c, d, baseaddr, targetaddr; 2469 | Value v; 2470 | 2471 | baseaddr = frame->pc - 1; 2472 | while (frame->pc % 4) 2473 | frame->pc++; 2474 | v = frame_stackpop(frame); 2475 | a = frame->code->code[frame->pc++]; 2476 | b = frame->code->code[frame->pc++]; 2477 | c = frame->code->code[frame->pc++]; 2478 | d = frame->code->code[frame->pc++]; 2479 | def = (a << 24) | (b << 16) | (c << 8) | d; 2480 | a = frame->code->code[frame->pc++]; 2481 | b = frame->code->code[frame->pc++]; 2482 | c = frame->code->code[frame->pc++]; 2483 | d = frame->code->code[frame->pc++]; 2484 | low = (a << 24) | (b << 16) | (c << 8) | d; 2485 | a = frame->code->code[frame->pc++]; 2486 | b = frame->code->code[frame->pc++]; 2487 | c = frame->code->code[frame->pc++]; 2488 | d = frame->code->code[frame->pc++]; 2489 | high = (a << 24) | (b << 16) | (c << 8) | d; 2490 | targetaddr = baseaddr + def; 2491 | for (j = low; j <= high; j++) { 2492 | a = frame->code->code[frame->pc++]; 2493 | b = frame->code->code[frame->pc++]; 2494 | c = frame->code->code[frame->pc++]; 2495 | d = frame->code->code[frame->pc++]; 2496 | n = (a << 24) | (b << 16) | (c << 8) | d; 2497 | if (v.i == j) { 2498 | targetaddr = baseaddr + n; 2499 | break; 2500 | } 2501 | } 2502 | frame->pc = targetaddr; 2503 | return NO_RETURN; 2504 | } 2505 | 2506 | /* call method */ 2507 | int 2508 | methodcall(ClassFile *class, Frame *frame, char *name, char *descriptor, U2 flags) 2509 | { 2510 | static int(*instrtab[])(Frame *) = { 2511 | /* 2512 | * some functions are used in more than one instructions, 2513 | * for example, there is no opareturn, opdreturn or oplreturn, 2514 | * there is only opireturn, that implements all function that 2515 | * return something. 2516 | */ 2517 | [NOP] = opnop, 2518 | [ACONST_NULL] = opaconst_null, 2519 | [ICONST_M1] = opiconst_m1, 2520 | [ICONST_0] = opiconst_0, 2521 | [ICONST_1] = opiconst_1, 2522 | [ICONST_2] = opiconst_2, 2523 | [ICONST_3] = opiconst_3, 2524 | [ICONST_4] = opiconst_4, 2525 | [ICONST_5] = opiconst_5, 2526 | [LCONST_0] = oplconst_0, 2527 | [LCONST_1] = oplconst_1, 2528 | [FCONST_0] = opfconst_0, 2529 | [FCONST_1] = opfconst_1, 2530 | [FCONST_2] = opfconst_2, 2531 | [DCONST_0] = opdconst_0, 2532 | [DCONST_1] = opdconst_1, 2533 | [BIPUSH] = opbipush, 2534 | [SIPUSH] = opsipush, 2535 | [LDC] = opldc, 2536 | [LDC_W] = opldc_w, 2537 | [LDC2_W] = opldc2_w, 2538 | [ILOAD] = opiload, 2539 | [LLOAD] = oplload, 2540 | [FLOAD] = opiload, 2541 | [DLOAD] = oplload, 2542 | [ALOAD] = opiload, 2543 | [ILOAD_0] = opiload_0, 2544 | [ILOAD_1] = opiload_1, 2545 | [ILOAD_2] = opiload_2, 2546 | [ILOAD_3] = opiload_3, 2547 | [LLOAD_0] = oplload_0, 2548 | [LLOAD_1] = oplload_1, 2549 | [LLOAD_2] = oplload_2, 2550 | [LLOAD_3] = oplload_3, 2551 | [FLOAD_0] = opiload_0, 2552 | [FLOAD_1] = opiload_1, 2553 | [FLOAD_2] = opiload_2, 2554 | [FLOAD_3] = opiload_3, 2555 | [DLOAD_0] = oplload_0, 2556 | [DLOAD_1] = oplload_1, 2557 | [DLOAD_2] = oplload_2, 2558 | [DLOAD_3] = oplload_3, 2559 | [ALOAD_0] = opiload_0, 2560 | [ALOAD_1] = opiload_1, 2561 | [ALOAD_2] = opiload_2, 2562 | [ALOAD_3] = opiload_3, 2563 | [IALOAD] = opiaload, 2564 | [LALOAD] = oplaload, 2565 | [FALOAD] = opfaload, 2566 | [DALOAD] = opdaload, 2567 | [AALOAD] = opaaload, 2568 | [BALOAD] = opiaload, 2569 | [CALOAD] = opiaload, 2570 | [SALOAD] = opiaload, 2571 | [ISTORE] = opistore, 2572 | [LSTORE] = oplstore, 2573 | [FSTORE] = opistore, 2574 | [DSTORE] = oplstore, 2575 | [ASTORE] = opistore, 2576 | [ISTORE_0] = opistore_0, 2577 | [ISTORE_1] = opistore_1, 2578 | [ISTORE_2] = opistore_2, 2579 | [ISTORE_3] = opistore_3, 2580 | [LSTORE_0] = oplstore_0, 2581 | [LSTORE_1] = oplstore_1, 2582 | [LSTORE_2] = oplstore_2, 2583 | [LSTORE_3] = oplstore_3, 2584 | [FSTORE_0] = opistore_0, 2585 | [FSTORE_1] = opistore_1, 2586 | [FSTORE_2] = opistore_2, 2587 | [FSTORE_3] = opistore_3, 2588 | [DSTORE_0] = oplstore_0, 2589 | [DSTORE_1] = oplstore_1, 2590 | [DSTORE_2] = oplstore_2, 2591 | [DSTORE_3] = oplstore_3, 2592 | [ASTORE_0] = opistore_0, 2593 | [ASTORE_1] = opistore_1, 2594 | [ASTORE_2] = opistore_2, 2595 | [ASTORE_3] = opistore_3, 2596 | [IASTORE] = opiastore, 2597 | [LASTORE] = oplastore, 2598 | [FASTORE] = opfastore, 2599 | [DASTORE] = opdastore, 2600 | [AASTORE] = opaastore, 2601 | [BASTORE] = opiastore, 2602 | [CASTORE] = opiastore, 2603 | [SASTORE] = opiastore, 2604 | [POP] = oppop, 2605 | [POP2] = oppop2, 2606 | [DUP] = opdup, 2607 | [DUP_X1] = opdup_x1, 2608 | [DUP_X2] = opdup_x2, 2609 | [DUP2] = opdup2, 2610 | [DUP2_X1] = opdup2_x1, 2611 | [DUP2_X2] = opdup2_x2, 2612 | [SWAP] = opswap, 2613 | [IADD] = opiadd, 2614 | [LADD] = opladd, 2615 | [FADD] = opfadd, 2616 | [DADD] = opdadd, 2617 | [ISUB] = opisub, 2618 | [LSUB] = oplsub, 2619 | [FSUB] = opfsub, 2620 | [DSUB] = opdsub, 2621 | [IMUL] = opimul, 2622 | [LMUL] = oplmul, 2623 | [FMUL] = opfmul, 2624 | [DMUL] = opdmul, 2625 | [IDIV] = opidiv, 2626 | [LDIV] = opldiv, 2627 | [FDIV] = opfdiv, 2628 | [DDIV] = opddiv, 2629 | [IREM] = opirem, 2630 | [LREM] = oplrem, 2631 | [FREM] = opfrem, 2632 | [DREM] = opdrem, 2633 | [INEG] = opineg, 2634 | [LNEG] = oplneg, 2635 | [FNEG] = opfneg, 2636 | [DNEG] = opdneg, 2637 | [ISHL] = opishl, 2638 | [LSHL] = oplshl, 2639 | [ISHR] = opishr, 2640 | [LSHR] = oplshr, 2641 | [IUSHR] = opiushr, 2642 | [LUSHR] = oplushr, 2643 | [IAND] = opiand, 2644 | [LAND] = opland, 2645 | [IOR] = opior, 2646 | [LOR] = oplor, 2647 | [IXOR] = opixor, 2648 | [LXOR] = oplxor, 2649 | [IINC] = opiinc, 2650 | [I2L] = opi2l, 2651 | [I2F] = opi2f, 2652 | [I2D] = opi2d, 2653 | [L2I] = opl2i, 2654 | [L2F] = opl2f, 2655 | [L2D] = opl2d, 2656 | [F2I] = opf2i, 2657 | [F2L] = opf2l, 2658 | [F2D] = opf2d, 2659 | [D2I] = opd2i, 2660 | [D2L] = opd2l, 2661 | [D2F] = opd2f, 2662 | [I2B] = opi2b, 2663 | [I2C] = opi2c, 2664 | [I2S] = opi2s, 2665 | [LCMP] = oplcmp, 2666 | [FCMPL] = opfcmpl, 2667 | [FCMPG] = opfcmpg, 2668 | [DCMPL] = opdcmpl, 2669 | [DCMPG] = opdcmpg, 2670 | [IFEQ] = opifeq, 2671 | [IFNE] = opifne, 2672 | [IFLT] = opiflt, 2673 | [IFGE] = opifge, 2674 | [IFGT] = opifgt, 2675 | [IFLE] = opifle, 2676 | [IF_ICMPEQ] = opif_icmpeq, 2677 | [IF_ICMPNE] = opif_icmpne, 2678 | [IF_ICMPLT] = opif_icmplt, 2679 | [IF_ICMPGE] = opif_icmpge, 2680 | [IF_ICMPGT] = opif_icmpgt, 2681 | [IF_ICMPLE] = opif_icmple, 2682 | [IF_ACMPEQ] = opif_acmpeq, 2683 | [IF_ACMPNE] = opif_acmpne, 2684 | [GOTO] = opgoto, 2685 | [JSR] = opjsr, 2686 | [RET] = opret, 2687 | [TABLESWITCH] = optableswitch, 2688 | [LOOKUPSWITCH] = oplookupswitch, 2689 | [IRETURN] = opireturn, 2690 | [LRETURN] = opireturn, 2691 | [FRETURN] = opireturn, 2692 | [DRETURN] = opireturn, 2693 | [ARETURN] = opireturn, 2694 | [RETURN] = opreturn, 2695 | [GETSTATIC] = opgetstatic, 2696 | [PUTSTATIC] = opputstatic, 2697 | [GETFIELD] = opnop, 2698 | [PUTFIELD] = opnop, 2699 | [INVOKEVIRTUAL] = opinvokevirtual, 2700 | [INVOKESPECIAL] = opnop, 2701 | [INVOKESTATIC] = opinvokestatic, 2702 | [INVOKEINTERFACE] = opnop, 2703 | [INVOKEDYNAMIC] = opnop, 2704 | [NEW] = opnop, 2705 | [NEWARRAY] = opnewarray, 2706 | [ANEWARRAY] = opnop, 2707 | [ARRAYLENGTH] = oparraylength, 2708 | [ATHROW] = opnop, 2709 | [CHECKCAST] = opnop, 2710 | [INSTANCEOF] = opnop, 2711 | [MONITORENTER] = opnop, 2712 | [MONITOREXIT] = opnop, 2713 | [WIDE] = opnop, 2714 | [MULTIANEWARRAY] = opmultianewarray, 2715 | [IFNULL] = opifnull, 2716 | [IFNONNULL] = opifnonnull, 2717 | [GOTO_W] = opgoto_w, 2718 | [JSR_W] = opjsr_w, 2719 | }; 2720 | Attribute *cattr; /* Code_attribute */ 2721 | Code_attribute *code; 2722 | Frame *newframe; 2723 | Method *method; 2724 | Value v; 2725 | char *s; 2726 | U2 i; 2727 | int ret = NO_RETURN; 2728 | 2729 | if ((method = class_getmethod(class, name, descriptor)) == NULL) 2730 | return -1; 2731 | if ((flags != ACC_NONE) && !(method->access_flags & flags)) 2732 | return -1; 2733 | if ((cattr = class_getattr(method->attributes, method->attributes_count, Code)) == NULL) 2734 | err(EXIT_FAILURE, "could not find code for method %s", name); 2735 | code = &cattr->info.code; 2736 | if ((newframe = frame_push(code, class, code->max_locals, code->max_stack)) == NULL) 2737 | err(EXIT_FAILURE, "out of memory"); 2738 | if (frame) { 2739 | s = descriptor; 2740 | i = 0; 2741 | while (*s && *s != ')') { 2742 | v = frame_stackpop(frame); 2743 | frame_localstore(newframe, i++, v); 2744 | switch (*(++s)) { 2745 | case TYPE_REFERENCE: 2746 | while (*s && *s != TYPE_TERMINAL) { 2747 | s++; 2748 | } 2749 | if (*s == TYPE_TERMINAL) { 2750 | s++; 2751 | } 2752 | break; 2753 | case TYPE_ARRAY: 2754 | while (*s == TYPE_ARRAY) { 2755 | s++; 2756 | } 2757 | if (*s == TYPE_REFERENCE) { 2758 | while (*s && *s != TYPE_TERMINAL) { 2759 | s++; 2760 | } 2761 | if (*s == TYPE_TERMINAL) { 2762 | s++; 2763 | } 2764 | } else { 2765 | s++; 2766 | } 2767 | break; 2768 | case TYPE_DOUBLE: 2769 | case TYPE_LONG: 2770 | frame_localstore(newframe, i++, v); 2771 | /* FALLTHROUGH */ 2772 | default: 2773 | s++; 2774 | break; 2775 | } 2776 | } 2777 | } 2778 | while (newframe->pc < code->code_length) { 2779 | if ((ret = (*instrtab[code->code[newframe->pc++]])(newframe)) != NO_RETURN) { 2780 | break; 2781 | } 2782 | } 2783 | if (ret == RETURN_OPERAND) { 2784 | v = frame_stackpop(newframe); 2785 | frame_stackpush(frame, v); 2786 | } 2787 | frame_pop(); 2788 | return 0; 2789 | } 2790 | 2791 | /* load and initialize main class, then call main method */ 2792 | static void 2793 | java(int argc, char *argv[]) 2794 | { 2795 | ClassFile *class; 2796 | Frame *frame; 2797 | Heap *h; 2798 | Value v; 2799 | int i; 2800 | 2801 | class = classload(argv[0]); 2802 | argc--; 2803 | argv++; 2804 | frame = frame_push(NULL, NULL, 0, 1); 2805 | v.v = array_new(&argc, 1, sizeof (void *)); 2806 | for (i = 0; i < argc; i++) { 2807 | h = array_new((int32_t[]){0}, 1, 0); 2808 | h->obj = argv[i]; 2809 | ((void **)v.v->obj)[i] = h; 2810 | } 2811 | frame_stackpush(frame, v); 2812 | if (methodcall(class, frame, "main", "([Ljava/lang/String;)V", (ACC_PUBLIC | ACC_STATIC)) == -1) 2813 | errx(EXIT_FAILURE, "could not find main method"); 2814 | // TODO: free heap 2815 | } 2816 | 2817 | /* java: launches a java application */ 2818 | int 2819 | main(int argc, char *argv[]) 2820 | { 2821 | char *cpath = NULL; 2822 | int i; 2823 | 2824 | setprogname(argv[0]); 2825 | cpath = getenv("CLASSPATH"); 2826 | for (i = 1; i < argc && argv[i][0] == '-'; i++) { 2827 | if (strcmp(argv[i], "-cp") == 0) { 2828 | if (++i >= argc) 2829 | usage(); 2830 | cpath = argv[i]; 2831 | } else { 2832 | usage(); 2833 | } 2834 | } 2835 | if (i >= argc) 2836 | usage(); 2837 | argc -= i; 2838 | argv += i; 2839 | if (cpath == NULL) 2840 | cpath = "."; 2841 | setclasspath(cpath); 2842 | atexit(classfree); 2843 | java(argc, argv); 2844 | return 0; 2845 | } 2846 | -------------------------------------------------------------------------------- /javap.1: -------------------------------------------------------------------------------- 1 | .TH JAVAP 1 2 | .SH NAME 3 | javap \- disassemble class files 4 | .SH SYNOPSIS 5 | .B javap 6 | .RB [ \-clpsv ] 7 | .IR classfile ... 8 | .SH DESCRIPTION 9 | .B javap 10 | disassembles each classfile sequentially. 11 | .B javap 12 | prints information about non-private 13 | (package, protected, and public) 14 | fields and methods of the classes on each class file. 15 | .PP 16 | The options are as follows: 17 | .TP 18 | .B \-c 19 | Print disassembled code for each of the methods in the class. 20 | .TP 21 | .B \-l 22 | Print line and local variable tables for each of the methods in the class. 23 | .TP 24 | .B \-p 25 | Include private fields and methods. 26 | .TP 27 | .B \-s 28 | Print internal type signatures for each of the fields and methods in the class. 29 | .TP 30 | .B \-v 31 | Verbose mode. 32 | Print metadata about the class file. 33 | Print stack size, number of locals and arguments for each of the methods in the class. 34 | This option also enables options 35 | .BR \-c , 36 | .BR \-l , 37 | and 38 | .BR \-s . 39 | It does not enable the 40 | .B \-p 41 | option, though. 42 | .SH EXIT STATUS 43 | .TP 44 | .B 0 45 | Success. 46 | .TP 47 | .B >0 48 | Error occurred. 49 | .SH EXAMPLES 50 | Compile the following 51 | .B ClassSample 52 | class: 53 | .IP 54 | .EX 55 | public class ClassSample { 56 | public static final int num = 42; 57 | private String name; 58 | private double value; 59 | 60 | public void init(String name, double value) { 61 | this.name = name; 62 | this.value = value; 63 | } 64 | 65 | public String getName() { 66 | return this.name; 67 | } 68 | 69 | public double getValue() { 70 | return this.value; 71 | } 72 | } 73 | .EE 74 | .PP 75 | Running 76 | .B javap 77 | on 78 | .B ClassSample.class 79 | without any option outputs the following: 80 | .IP 81 | .EX 82 | Compiled from "ClassSample.java" 83 | public class ClassSample { 84 | public static final int num; 85 | public ClassSample(); 86 | public void init(java.lang.String, double); 87 | public java.lang.String getName(); 88 | public double getValue(); 89 | } 90 | .EE 91 | .PP 92 | Running 93 | .B javap 94 | on 95 | .B ClassSample.class 96 | with the \-p option outputs the following: 97 | .IP 98 | .EX 99 | Compiled from "ClassSample.java" 100 | public class ClassSample { 101 | public static final int num; 102 | private java.lang.String name; 103 | private double value; 104 | public ClassSample(); 105 | public void init(java.lang.String, double); 106 | public java.lang.String getName(); 107 | public double getValue(); 108 | } 109 | .EE 110 | .PP 111 | Running 112 | .B javap 113 | on 114 | .B ClassSample.class 115 | with the \-v option outputs the following: 116 | .IP 117 | .EX 118 | Compiled from "HelloWorld.java" 119 | public class HelloWorld 120 | minor version: 0 121 | major version: 55 122 | flags: (0x0021) ACC_PUBLIC, ACC_SUPER 123 | this class: #4 // HelloWorld 124 | super class: #5 // java.lang.Object 125 | interfaces: 0, fields: 3, methods: 4, attributes: 1 126 | Constant pool: 127 | #1 = Methodref #5.#26 128 | #2 = Fieldref #4.#27 129 | #3 = Fieldref #4.#28 130 | #4 = Class #29 // HelloWorld 131 | #5 = Class #30 // java/lang/Object 132 | #6 = Utf8 num 133 | #7 = Utf8 I 134 | #8 = Utf8 ConstantValue 135 | #9 = Integer 42 136 | #10 = Utf8 name 137 | #11 = Utf8 Ljava/lang/String; 138 | #12 = Utf8 value 139 | #13 = Utf8 D 140 | #14 = Utf8 141 | #15 = Utf8 ()V 142 | #16 = Utf8 Code 143 | #17 = Utf8 LineNumberTable 144 | #18 = Utf8 init 145 | #19 = Utf8 (Ljava/lang/String;D)V 146 | #20 = Utf8 getName 147 | #21 = Utf8 ()Ljava/lang/String; 148 | #22 = Utf8 getValue 149 | #23 = Utf8 ()D 150 | #24 = Utf8 SourceFile 151 | #25 = Utf8 HelloWorld.java 152 | #26 = NameAndType #14:#15 153 | #27 = NameAndType #10:#11 154 | #28 = NameAndType #12:#13 155 | #29 = Utf8 HelloWorld 156 | #30 = Utf8 java/lang/Object 157 | { 158 | public static final int num; 159 | descriptor: I 160 | flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL 161 | ConstantValue: int 42 162 | 163 | public HelloWorld(); 164 | descriptor: ()V 165 | flags: (0x0001) ACC_PUBLIC 166 | Code: 167 | stack=1, locals=1, args_size=1 168 | 0: aload_0 169 | 1: invokespecial 170 | 4: return 171 | LineNumberTable: 172 | line 1: 0 173 | 174 | public void init(java.lang.String, double); 175 | descriptor: (Ljava/lang/String;D)V 176 | flags: (0x0001) ACC_PUBLIC 177 | Code: 178 | stack=3, locals=4, args_size=3 179 | 0: aload_0 180 | 1: aload_1 181 | 2: putfield 182 | 5: aload_0 183 | 6: dload_2 184 | 7: putfield 185 | 10: return 186 | LineNumberTable: 187 | line 7: 0 188 | line 8: 5 189 | line 9: 10 190 | 191 | public java.lang.String getName(); 192 | descriptor: ()Ljava/lang/String; 193 | flags: (0x0001) ACC_PUBLIC 194 | Code: 195 | stack=1, locals=1, args_size=1 196 | 0: aload_0 197 | 1: getfield 198 | 4: areturn 199 | LineNumberTable: 200 | line 12: 0 201 | 202 | public double getValue(); 203 | descriptor: ()D 204 | flags: (0x0001) ACC_PUBLIC 205 | Code: 206 | stack=2, locals=1, args_size=1 207 | 0: aload_0 208 | 1: getfield 209 | 4: dreturn 210 | LineNumberTable: 211 | line 16: 0 212 | } 213 | .EE 214 | .SH SEE ALSO 215 | .IR java (1), 216 | .IR javac (1) 217 | .PP 218 | Tim Lindholm, Frank Yellin, Gilad Bracha, Alex Buckley, 219 | .I The Java® Virtual Machine Specification: Java SE 8Edition, 220 | Addison-Wesley, 221 | 2014. 222 | ISBN 978-0-13-390590-8. 223 | -------------------------------------------------------------------------------- /javap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "util.h" 6 | #include "class.h" 7 | #include "file.h" 8 | 9 | #define CPINDEX 26 /* columns before index in the constant_pool section */ 10 | #define CPCOMMENT 43 /* columns before comments in the constant_pool section */ 11 | #define CODEINDEX 25 /* columns before index in the code section */ 12 | #define CODECOMMENT 45 /* columns before comments in the code section */ 13 | 14 | /* names */ 15 | static char *cptags[] = { 16 | [CONSTANT_Untagged] = "", 17 | [CONSTANT_Utf8] = "Utf8", 18 | [CONSTANT_Integer] = "Integer", 19 | [CONSTANT_Float] = "Float", 20 | [CONSTANT_Long] = "Long", 21 | [CONSTANT_Double] = "Double", 22 | [CONSTANT_Class] = "Class", 23 | [CONSTANT_String] = "String", 24 | [CONSTANT_Fieldref] = "Fieldref", 25 | [CONSTANT_Methodref] = "Methodref", 26 | [CONSTANT_InterfaceMethodref] = "InterfaceMethodref", 27 | [CONSTANT_NameAndType] = "NameAndType", 28 | [CONSTANT_MethodHandle] = "MethodHandle", 29 | [CONSTANT_MethodType] = "MethodType", 30 | [CONSTANT_InvokeDynamic] = "InvokeDynamic", 31 | }; 32 | static char *instrnames[CODE_LAST] = { 33 | [NOP] = "nop", 34 | [ACONST_NULL] = "aconst_null", 35 | [ICONST_M1] = "iconst_m1", 36 | [ICONST_0] = "iconst_0", 37 | [ICONST_1] = "iconst_1", 38 | [ICONST_2] = "iconst_2", 39 | [ICONST_3] = "iconst_3", 40 | [ICONST_4] = "iconst_4", 41 | [ICONST_5] = "iconst_5", 42 | [LCONST_0] = "lconst_0", 43 | [LCONST_1] = "lconst_1", 44 | [FCONST_0] = "fconst_0", 45 | [FCONST_1] = "fconst_1", 46 | [FCONST_2] = "fconst_2", 47 | [DCONST_0] = "dconst_0", 48 | [DCONST_1] = "dconst_1", 49 | [BIPUSH] = "bipush", 50 | [SIPUSH] = "sipush", 51 | [LDC] = "ldc", 52 | [LDC_W] = "ldc_w", 53 | [LDC2_W] = "ldc2_w", 54 | [ILOAD] = "iload", 55 | [LLOAD] = "lload", 56 | [FLOAD] = "fload", 57 | [DLOAD] = "dload", 58 | [ALOAD] = "aload", 59 | [ILOAD_0] = "iload_0", 60 | [ILOAD_1] = "iload_1", 61 | [ILOAD_2] = "iload_2", 62 | [ILOAD_3] = "iload_3", 63 | [LLOAD_0] = "lload_0", 64 | [LLOAD_1] = "lload_1", 65 | [LLOAD_2] = "lload_2", 66 | [LLOAD_3] = "lload_3", 67 | [FLOAD_0] = "fload_0", 68 | [FLOAD_1] = "fload_1", 69 | [FLOAD_2] = "fload_2", 70 | [FLOAD_3] = "fload_3", 71 | [DLOAD_0] = "dload_0", 72 | [DLOAD_1] = "dload_1", 73 | [DLOAD_2] = "dload_2", 74 | [DLOAD_3] = "dload_3", 75 | [ALOAD_0] = "aload_0", 76 | [ALOAD_1] = "aload_1", 77 | [ALOAD_2] = "aload_2", 78 | [ALOAD_3] = "aload_3", 79 | [IALOAD] = "iaload", 80 | [LALOAD] = "laload", 81 | [FALOAD] = "faload", 82 | [DALOAD] = "daload", 83 | [AALOAD] = "aaload", 84 | [BALOAD] = "baload", 85 | [CALOAD] = "caload", 86 | [SALOAD] = "saload", 87 | [ISTORE] = "istore", 88 | [LSTORE] = "lstore", 89 | [FSTORE] = "fstore", 90 | [DSTORE] = "dstore", 91 | [ASTORE] = "astore", 92 | [ISTORE_0] = "istore_0", 93 | [ISTORE_1] = "istore_1", 94 | [ISTORE_2] = "istore_2", 95 | [ISTORE_3] = "istore_3", 96 | [LSTORE_0] = "lstore_0", 97 | [LSTORE_1] = "lstore_1", 98 | [LSTORE_2] = "lstore_2", 99 | [LSTORE_3] = "lstore_3", 100 | [FSTORE_0] = "fstore_0", 101 | [FSTORE_1] = "fstore_1", 102 | [FSTORE_2] = "fstore_2", 103 | [FSTORE_3] = "fstore_3", 104 | [DSTORE_0] = "dstore_0", 105 | [DSTORE_1] = "dstore_1", 106 | [DSTORE_2] = "dstore_2", 107 | [DSTORE_3] = "dstore_3", 108 | [ASTORE_0] = "astore_0", 109 | [ASTORE_1] = "astore_1", 110 | [ASTORE_2] = "astore_2", 111 | [ASTORE_3] = "astore_3", 112 | [IASTORE] = "iastore", 113 | [LASTORE] = "lastore", 114 | [FASTORE] = "fastore", 115 | [DASTORE] = "dastore", 116 | [AASTORE] = "aastore", 117 | [BASTORE] = "bastore", 118 | [CASTORE] = "castore", 119 | [SASTORE] = "sastore", 120 | [POP] = "pop", 121 | [POP2] = "pop2", 122 | [DUP] = "dup", 123 | [DUP_X1] = "dup_x1", 124 | [DUP_X2] = "dup_x2", 125 | [DUP2] = "dup2", 126 | [DUP2_X1] = "dup2_x1", 127 | [DUP2_X2] = "dup2_x2", 128 | [SWAP] = "swap", 129 | [IADD] = "iadd", 130 | [LADD] = "ladd", 131 | [FADD] = "fadd", 132 | [DADD] = "dadd", 133 | [ISUB] = "isub", 134 | [LSUB] = "lsub", 135 | [FSUB] = "fsub", 136 | [DSUB] = "dsub", 137 | [IMUL] = "imul", 138 | [LMUL] = "lmul", 139 | [FMUL] = "fmul", 140 | [DMUL] = "dmul", 141 | [IDIV] = "idiv", 142 | [LDIV] = "ldiv", 143 | [FDIV] = "fdiv", 144 | [DDIV] = "ddiv", 145 | [IREM] = "irem", 146 | [LREM] = "lrem", 147 | [FREM] = "frem", 148 | [DREM] = "drem", 149 | [INEG] = "ineg", 150 | [LNEG] = "lneg", 151 | [FNEG] = "fneg", 152 | [DNEG] = "dneg", 153 | [ISHL] = "ishl", 154 | [LSHL] = "lshl", 155 | [ISHR] = "ishr", 156 | [LSHR] = "lshr", 157 | [IUSHR] = "iushr", 158 | [LUSHR] = "lushr", 159 | [IAND] = "iand", 160 | [LAND] = "land", 161 | [IOR] = "ior", 162 | [LOR] = "lor", 163 | [IXOR] = "ixor", 164 | [LXOR] = "lxor", 165 | [IINC] = "iinc", 166 | [I2L] = "i2l", 167 | [I2F] = "i2f", 168 | [I2D] = "i2d", 169 | [L2I] = "l2i", 170 | [L2F] = "l2f", 171 | [L2D] = "l2d", 172 | [F2I] = "f2i", 173 | [F2L] = "f2l", 174 | [F2D] = "f2d", 175 | [D2I] = "d2i", 176 | [D2L] = "d2l", 177 | [D2F] = "d2f", 178 | [I2B] = "i2b", 179 | [I2C] = "i2c", 180 | [I2S] = "i2s", 181 | [LCMP] = "lcmp", 182 | [FCMPL] = "fcmpl", 183 | [FCMPG] = "fcmpg", 184 | [DCMPL] = "dcmpl", 185 | [DCMPG] = "dcmpg", 186 | [IFEQ] = "ifeq", 187 | [IFNE] = "ifne", 188 | [IFLT] = "iflt", 189 | [IFGE] = "ifge", 190 | [IFGT] = "ifgt", 191 | [IFLE] = "ifle", 192 | [IF_ICMPEQ] = "if_icmpeq", 193 | [IF_ICMPNE] = "if_icmpne", 194 | [IF_ICMPLT] = "if_icmplt", 195 | [IF_ICMPGE] = "if_icmpge", 196 | [IF_ICMPGT] = "if_icmpgt", 197 | [IF_ICMPLE] = "if_icmple", 198 | [IF_ACMPEQ] = "if_acmpeq", 199 | [IF_ACMPNE] = "if_acmpne", 200 | [GOTO] = "goto", 201 | [JSR] = "jsr", 202 | [RET] = "ret", 203 | [TABLESWITCH] = "tableswitch", 204 | [LOOKUPSWITCH] = "lookupswitch", 205 | [IRETURN] = "ireturn", 206 | [LRETURN] = "lreturn", 207 | [FRETURN] = "freturn", 208 | [DRETURN] = "dreturn", 209 | [ARETURN] = "areturn", 210 | [RETURN] = "return", 211 | [GETSTATIC] = "getstatic", 212 | [PUTSTATIC] = "putstatic", 213 | [GETFIELD] = "getfield", 214 | [PUTFIELD] = "putfield", 215 | [INVOKEVIRTUAL] = "invokevirtual", 216 | [INVOKESPECIAL] = "invokespecial", 217 | [INVOKESTATIC] = "invokestatic", 218 | [INVOKEINTERFACE] = "invokeinterface", 219 | [INVOKEDYNAMIC] = "invokedynamic", 220 | [NEW] = "new", 221 | [NEWARRAY] = "newarray", 222 | [ANEWARRAY] = "anewarray", 223 | [ARRAYLENGTH] = "arraylength", 224 | [ATHROW] = "athrow", 225 | [CHECKCAST] = "checkcast", 226 | [INSTANCEOF] = "instanceof", 227 | [MONITORENTER] = "monitorenter", 228 | [MONITOREXIT] = "monitorexit", 229 | [WIDE] = "wide", 230 | [MULTIANEWARRAY] = "multianewarray", 231 | [IFNULL] = "ifnull", 232 | [IFNONNULL] = "ifnonnull", 233 | [GOTO_W] = "goto_w", 234 | [JSR_W] = "jsr_w", 235 | }; 236 | static char *typenames[T_LAST] = { 237 | [T_BOOLEAN] = "boolean", 238 | [T_CHAR] = "char", 239 | [T_FLOAT] = "float", 240 | [T_DOUBLE] = "double", 241 | [T_BYTE] = "byte", 242 | [T_SHORT] = "short", 243 | [T_INT] = "int", 244 | [T_LONG] = "long", 245 | }; 246 | 247 | /* flags */ 248 | static int cflag = 0; 249 | static int lflag = 0; 250 | static int pflag = 0; 251 | static int sflag = 0; 252 | static int verbose = 0; 253 | 254 | /* show usage */ 255 | static void 256 | usage(void) 257 | { 258 | (void)fprintf(stderr, "usage: javap [-clpsv] classfile...\n"); 259 | exit(EXIT_FAILURE); 260 | } 261 | 262 | /* get number of columns to align index or comment text */ 263 | static int 264 | getcol(int max, int n) 265 | { 266 | return (n > 0 && n < max) ? max - n - 1 : 1; 267 | } 268 | 269 | /* quote method name if it is */ 270 | static char * 271 | quotename(char *s) 272 | { 273 | if (strcmp(s, "") == 0) 274 | return "\"\""; 275 | return s; 276 | } 277 | 278 | /* print access flags */ 279 | static void 280 | printflags(U2 flags, int type) 281 | { 282 | static struct { 283 | char *s; 284 | U2 flag; 285 | int type; 286 | } flagstab[] = { 287 | {"ACC_PUBLIC", 0x0001, TYPE_CLASS | TYPE_FIELD | TYPE_METHOD | TYPE_INNER }, 288 | {"ACC_PRIVATE", 0x0002, TYPE_FIELD | TYPE_METHOD | TYPE_INNER }, 289 | {"ACC_PROTECTED", 0x0004, TYPE_FIELD | TYPE_METHOD | TYPE_INNER }, 290 | {"ACC_STATIC", 0x0008, TYPE_FIELD | TYPE_METHOD | TYPE_INNER }, 291 | {"ACC_FINAL", 0x0010, TYPE_CLASS | TYPE_FIELD | TYPE_METHOD | TYPE_INNER }, 292 | {"ACC_SUPER", 0x0020, TYPE_CLASS }, 293 | {"ACC_SYNCHRONIZED", 0x0020, TYPE_METHOD }, 294 | {"ACC_VOLATILE", 0x0040, TYPE_FIELD }, 295 | {"ACC_BRIDGE", 0x0040, TYPE_METHOD }, 296 | {"ACC_TRANSIENT", 0x0080, TYPE_FIELD }, 297 | {"ACC_VARARGS", 0x0080, TYPE_METHOD }, 298 | {"ACC_NATIVE", 0x0100, TYPE_METHOD }, 299 | {"ACC_INTERFACE", 0x0200, TYPE_CLASS | TYPE_INNER }, 300 | {"ACC_ABSTRACT", 0x0400, TYPE_CLASS | TYPE_METHOD | TYPE_INNER }, 301 | {"ACC_STRICT", 0x0800, TYPE_METHOD }, 302 | {"ACC_SYNTHETIC", 0x1000, TYPE_CLASS | TYPE_FIELD | TYPE_METHOD | TYPE_INNER }, 303 | {"ACC_ANNOTATION", 0x2000, TYPE_CLASS | TYPE_INNER }, 304 | {"ACC_ENUM", 0x4000, TYPE_CLASS | TYPE_FIELD | TYPE_INNER } 305 | }; 306 | int p = 0; /* whether a flag was printed */ 307 | size_t i; 308 | 309 | printf("flags: (0x%04X) ", flags); 310 | for (i = 0; i < LEN(flagstab); i++) { 311 | if (flags & flagstab[i].flag && flagstab[i].type & type) { 312 | if (p) 313 | printf(", "); 314 | printf("%s", flagstab[i].s); 315 | p = 1; 316 | } 317 | } 318 | putchar('\n'); 319 | } 320 | 321 | /* print content of constant pool */ 322 | static void 323 | printcp(ClassFile *class) 324 | { 325 | CP **cp; 326 | U2 count, i; 327 | char *name, *type; 328 | int d, n; 329 | 330 | printf("Constant pool:\n"); 331 | count = class->constant_pool_count; 332 | cp = class->constant_pool; 333 | for (i = 1; i < count; i++) { 334 | d = 0; 335 | n = i; 336 | do { 337 | d++; 338 | } while (n /= 10); 339 | d = (d < 4) ? 4 - d : 0; 340 | n = d; 341 | while (n--) 342 | putchar(' '); 343 | n = printf("#%d = %s", i, cptags[cp[i]->tag]); 344 | n = (n > 0) ? CPINDEX - (n + d) : 0; 345 | do { 346 | putchar(' '); 347 | } while (n-- > 0); 348 | switch (cp[i]->tag) { 349 | case CONSTANT_Utf8: 350 | printf("%s", cp[i]->info.utf8_info.bytes); 351 | break; 352 | case CONSTANT_Integer: 353 | printf("%ld", (long int)getint(cp[i]->info.integer_info.bytes)); 354 | break; 355 | case CONSTANT_Float: 356 | printf("%gd", getfloat(cp[i]->info.integer_info.bytes)); 357 | break; 358 | case CONSTANT_Long: 359 | printf("%lld", (long long int)getlong(cp[i]->info.long_info.high_bytes, cp[i]->info.long_info.low_bytes)); 360 | i++; 361 | break; 362 | case CONSTANT_Double: 363 | printf("%gd", getdouble(cp[i]->info.long_info.high_bytes, cp[i]->info.long_info.low_bytes)); 364 | i++; 365 | break; 366 | case CONSTANT_Class: 367 | n = printf("#%u", cp[i]->info.class_info.name_index); 368 | n = getcol(16, n); 369 | printf("%*c", n, ' '); 370 | printf("// %s", class_getutf8(class, cp[i]->info.class_info.name_index)); 371 | break; 372 | case CONSTANT_String: 373 | n = printf("#%u", cp[i]->info.string_info.string_index); 374 | n = getcol(16, n); 375 | printf("%*c", n, ' '); 376 | printf("// %s", class_getutf8(class, cp[i]->info.string_info.string_index)); 377 | break; 378 | case CONSTANT_Fieldref: 379 | n = printf("#%u.#%u", cp[i]->info.fieldref_info.class_index, 380 | cp[i]->info.fieldref_info.name_and_type_index); 381 | n = getcol(16, n); 382 | printf("%*c", n, ' '); 383 | class_getnameandtype(class, cp[i]->info.fieldref_info.name_and_type_index, &name, &type); 384 | printf("// %s.%s:%s", class_getclassname(class, cp[i]->info.fieldref_info.class_index), name, type); 385 | break; 386 | case CONSTANT_Methodref: 387 | n = printf("#%u.#%u", cp[i]->info.methodref_info.class_index, 388 | cp[i]->info.methodref_info.name_and_type_index); 389 | n = getcol(16, n); 390 | printf("%*c", n, ' '); 391 | class_getnameandtype(class, cp[i]->info.methodref_info.name_and_type_index, &name, &type); 392 | name = quotename(name); 393 | printf("// %s.%s:%s", class_getclassname(class, cp[i]->info.methodref_info.class_index), name, type); 394 | break; 395 | case CONSTANT_InterfaceMethodref: 396 | printf("#%u", cp[i]->info.interfacemethodref_info.class_index); 397 | printf(".#%u", cp[i]->info.interfacemethodref_info.name_and_type_index); 398 | break; 399 | case CONSTANT_NameAndType: 400 | n = printf("#%u:#%u", cp[i]->info.nameandtype_info.name_index, 401 | cp[i]->info.nameandtype_info.descriptor_index); 402 | n = getcol(16, n); 403 | printf("%*c", n, ' '); 404 | class_getnameandtype(class, i, &name, &type); 405 | name = quotename(name); 406 | printf("// %s:%s", name, type); 407 | break; 408 | case CONSTANT_MethodHandle: 409 | printf("%u", cp[i]->info.methodhandle_info.reference_kind); 410 | printf(":#%u", cp[i]->info.methodhandle_info.reference_index); 411 | break; 412 | case CONSTANT_MethodType: 413 | printf("#%u", cp[i]->info.methodtype_info.descriptor_index); 414 | break; 415 | case CONSTANT_InvokeDynamic: 416 | printf("#%u", cp[i]->info.invokedynamic_info.bootstrap_method_attr_index); 417 | printf(":#%u", cp[i]->info.invokedynamic_info.name_and_type_index); 418 | break; 419 | } 420 | putchar('\n'); 421 | } 422 | } 423 | 424 | /* print class name */ 425 | static void 426 | printclass(ClassFile *class, U2 index) 427 | { 428 | char *s; 429 | 430 | s = class_getclassname(class, index); 431 | while (*s) { 432 | if (*s == TYPE_SEPARATOR) 433 | putchar('.'); 434 | else 435 | putchar(*s); 436 | s++; 437 | } 438 | } 439 | 440 | /* print metadata about class */ 441 | static void 442 | printmeta(ClassFile *class) 443 | { 444 | int n; 445 | 446 | printf(" minor version: %u\n", class->minor_version); 447 | printf(" major version: %u\n", class->major_version); 448 | printf(" Java version: %u.0\n", class->major_version - 44); 449 | printf(" "); 450 | printflags(class->access_flags, TYPE_CLASS); 451 | 452 | n = printf(" this_class: #%u", class->this_class); 453 | n = getcol(CPCOMMENT, n); 454 | printf("%*c// ", n, ' '); 455 | printf("%s", class_getclassname(class, class->this_class)); 456 | printf("\n"); 457 | 458 | n = printf(" super_class: #%u", class->super_class); 459 | n = getcol(CPCOMMENT, n); 460 | printf("%*c// ", n, ' '); 461 | printf("%s", class_getclassname(class, class->super_class)); 462 | printf("\n"); 463 | 464 | printf(" interfaces: %u, fields: %u, methods: %u, attributes: %u\n", 465 | class->interfaces_count, class->fields_count, class->methods_count, class->attributes_count); 466 | } 467 | 468 | /* print source file name */ 469 | static void 470 | printsource(ClassFile *class) 471 | { 472 | Attribute *attr; 473 | 474 | if ((attr = class_getattr(class->attributes, class->attributes_count, SourceFile)) == NULL) 475 | return; 476 | printf("Compiled from \"%s\"\n", class_getutf8(class, attr->info.sourcefile.sourcefile_index)); 477 | } 478 | 479 | /* print class header */ 480 | static void 481 | printheader(ClassFile *class) 482 | { 483 | U2 i; 484 | 485 | if (class->access_flags & ACC_PUBLIC) 486 | printf("public "); 487 | if (class->access_flags & ACC_INTERFACE) { 488 | if (class->access_flags & ACC_STRICT) 489 | printf("strict "); 490 | printf("interface "); 491 | } else if (class->access_flags & ACC_ENUM) { 492 | if (class->access_flags & ACC_STRICT) 493 | printf("strict "); 494 | printf("enum "); 495 | } else { 496 | if (class->access_flags & ACC_ABSTRACT) 497 | printf("abstract "); 498 | else if (class->access_flags & ACC_FINAL) 499 | printf("final "); 500 | if (class->access_flags & ACC_STRICT) 501 | printf("strict "); 502 | printf("class "); 503 | } 504 | printclass(class, class->this_class); 505 | if (class->super_class && !class_istopclass(class)) { 506 | printf(" extends "); 507 | printclass(class, class->super_class); 508 | ; 509 | } 510 | if (class->interfaces_count > 0) 511 | printf(" implements "); 512 | for (i = 0; i < class->interfaces_count; i++) { 513 | if (i > 0) 514 | printf(", "); 515 | printclass(class, class->interfaces[i]); 516 | } 517 | } 518 | 519 | /* print type, return next type in descriptor */ 520 | static char * 521 | printtype(char *type) 522 | { 523 | char *s; 524 | 525 | s = type + 1; 526 | switch (*type) { 527 | case TYPE_BYTE: 528 | printf("byte"); 529 | break; 530 | case TYPE_CHAR: 531 | printf("char"); 532 | break; 533 | case TYPE_DOUBLE: 534 | printf("double"); 535 | break; 536 | case TYPE_FLOAT: 537 | printf("float"); 538 | break; 539 | case TYPE_INT: 540 | printf("int"); 541 | break; 542 | case TYPE_LONG: 543 | printf("long"); 544 | break; 545 | case TYPE_REFERENCE: 546 | while (*s && *s != TYPE_TERMINAL) { 547 | if (*s == TYPE_SEPARATOR) 548 | putchar('.'); 549 | else 550 | putchar(*s); 551 | s++; 552 | } 553 | if (*s == TYPE_TERMINAL) 554 | s++; 555 | break; 556 | case TYPE_SHORT: 557 | printf("short"); 558 | break; 559 | case TYPE_VOID: 560 | printf("void"); 561 | break; 562 | case TYPE_BOOLEAN: 563 | printf("boolean"); 564 | break; 565 | case TYPE_ARRAY: 566 | s = printtype(s); 567 | printf("[]"); 568 | break; 569 | } 570 | return s; 571 | } 572 | 573 | /* print descriptor and name; return number of parameters */ 574 | static U2 575 | printdeclaration(char *descriptor, char *name, int init) 576 | { 577 | U2 nargs = 0; 578 | char *s; 579 | 580 | s = strrchr(descriptor, ')'); 581 | if (s == NULL) { 582 | printtype(descriptor); 583 | printf(" %s", name); 584 | } else { 585 | if (!init) { 586 | printtype(s+1); 587 | putchar(' '); 588 | } 589 | printf("%s(", name); 590 | s = descriptor + 1; 591 | while (*s && *s != ')') { 592 | if (nargs) 593 | printf(", "); 594 | s = printtype(s); 595 | nargs++; 596 | } 597 | putchar(')'); 598 | } 599 | return nargs; 600 | } 601 | 602 | /* print constant value of a field */ 603 | static void 604 | printconstant(ClassFile *class, Field *field) 605 | { 606 | U2 index, i; 607 | 608 | if (!(field->access_flags & ACC_STATIC)) 609 | return; 610 | index = 0; 611 | for (i = 0; i < field->attributes_count; i++) { 612 | if (field->attributes[i]->tag == ConstantValue) { 613 | index = field->attributes[i]->info.constantvalue.constantvalue_index; 614 | break; 615 | } 616 | } 617 | if (index == 0) 618 | return; 619 | printf(" ConstantValue: "); 620 | switch (class->constant_pool[index]->tag) { 621 | case CONSTANT_Integer: 622 | printf("int %ld", (long int)getint(class->constant_pool[index]->info.integer_info.bytes)); 623 | break; 624 | case CONSTANT_Long: 625 | printf("long %lld", (long long int)getlong(class->constant_pool[index]->info.long_info.high_bytes, class->constant_pool[index]->info.long_info.low_bytes)); 626 | break; 627 | case CONSTANT_Float: 628 | printf("float %gf", getfloat(class->constant_pool[index]->info.float_info.bytes)); 629 | break; 630 | case CONSTANT_Double: 631 | printf("double %gd", getdouble(class->constant_pool[index]->info.double_info.high_bytes, 632 | class->constant_pool[index]->info.double_info.low_bytes)); 633 | break; 634 | case CONSTANT_String: 635 | printf("String %s", class_getutf8(class, class->constant_pool[index]->info.string_info.string_index)); 636 | break; 637 | } 638 | putchar('\n'); 639 | } 640 | 641 | /* print field information */ 642 | static void 643 | printfield(ClassFile *class, U2 count) 644 | { 645 | Field *field; 646 | 647 | field = class->fields[count]; 648 | if (!pflag && field->access_flags & ACC_PRIVATE) 649 | return; 650 | printf(" "); 651 | if (field->access_flags & ACC_PRIVATE) 652 | printf("private "); 653 | else if (field->access_flags & ACC_PROTECTED) 654 | printf("protected "); 655 | else if (field->access_flags & ACC_PUBLIC) 656 | printf("public "); 657 | if (field->access_flags & ACC_STATIC) 658 | printf("static "); 659 | if (field->access_flags & ACC_FINAL) 660 | printf("final "); 661 | if (field->access_flags & ACC_TRANSIENT) 662 | printf("transient "); 663 | if (field->access_flags & ACC_VOLATILE) 664 | printf("volatile "); 665 | printdeclaration(class_getutf8(class, field->descriptor_index), class_getutf8(class, field->name_index), 0); 666 | printf(";\n"); 667 | if (sflag) 668 | printf(" descriptor: %s\n", class_getutf8(class, field->descriptor_index)); 669 | if (verbose) { 670 | printf(" "); 671 | printflags(field->access_flags, TYPE_FIELD); 672 | printconstant(class, field); 673 | } 674 | if (lflag || cflag) { 675 | putchar('\n'); 676 | } 677 | } 678 | 679 | /* print line numbers */ 680 | static void 681 | printlinenumbers(LineNumberTable_attribute *lnattr) 682 | { 683 | LineNumber **ln; 684 | U2 count, i; 685 | 686 | printf(" LineNumberTable:\n"); 687 | count = lnattr->line_number_table_length; 688 | ln = lnattr->line_number_table; 689 | for (i = 0; i < count; i++) { 690 | printf(" line %u: %u\n", ln[i]->line_number, ln[i]->start_pc); 691 | } 692 | } 693 | 694 | /* print local variables */ 695 | static void 696 | printlocalvars(ClassFile *class, LocalVariableTable_attribute *lvattr) 697 | { 698 | LocalVariable **lv; 699 | U2 count, i; 700 | 701 | count = lvattr->local_variable_table_length; 702 | lv = lvattr->local_variable_table; 703 | if (count == 0) 704 | return; 705 | printf(" LocalVariableTable:\n"); 706 | printf(" Start Length Slot Name Signature\n"); 707 | for (i = 0; i < count; i++) { 708 | printf(" %7u %7u %5u %5s %s\n", lv[i]->start_pc, lv[i]->length, lv[i]->index, 709 | class_getutf8(class, lv[i]->name_index), class_getutf8(class, lv[i]->descriptor_index)); 710 | } 711 | } 712 | 713 | /* print code of method */ 714 | static void 715 | printcode(ClassFile *class, Code_attribute *codeattr, U2 nargs) 716 | { 717 | int32_t j, npairs, def, high, low; 718 | CP **cp; 719 | U1 *code; 720 | U1 opcode; 721 | U1 byte; 722 | U2 u; 723 | U4 count; 724 | U4 a, b, c, d; 725 | U4 i, base; 726 | int8_t ch; 727 | int16_t off; /* branch offset */ 728 | int32_t offw; /* wide branch offset */ 729 | int n, m; /* number of printed column, to format output */ 730 | char *cname, *name, *type; 731 | 732 | cp = class->constant_pool; 733 | code = codeattr->code; 734 | count = codeattr->code_length; 735 | printf(" Code:\n"); 736 | if (verbose) { 737 | printf(" stack=%u, locals=%u, args_size=%u", codeattr->max_stack, codeattr->max_locals, nargs); 738 | putchar('\n'); 739 | } 740 | for (i = 0; i < count; i++) { 741 | opcode = code[i]; 742 | if (verbose) 743 | printf(" "); 744 | n = printf("%8u: %s", i, instrnames[opcode]); 745 | m = getcol(CODEINDEX, n); 746 | switch (code[i]) { 747 | case WIDE: 748 | switch (code[++i]) { 749 | case ILOAD: 750 | case FLOAD: 751 | case ALOAD: 752 | case LLOAD: 753 | case DLOAD: 754 | case ISTORE: 755 | case FSTORE: 756 | case ASTORE: 757 | case LSTORE: 758 | case DSTORE: 759 | case RET: 760 | i += 2; 761 | break; 762 | case IINC: 763 | i += 4; 764 | break; 765 | } 766 | break; 767 | case BIPUSH: 768 | byte = code[++i]; 769 | memcpy(&ch, &byte, sizeof(ch)); 770 | printf("%*c%d", m, ' ', ch); 771 | break; 772 | case IINC: 773 | byte = code[++i]; 774 | memcpy(&ch, &byte, sizeof(ch)); 775 | printf("%*c%d, ", m, ' ', ch); 776 | byte = code[++i]; 777 | memcpy(&ch, &byte, sizeof(ch)); 778 | printf("%d", ch); 779 | break; 780 | case GOTO: 781 | case IF_ACMPEQ: 782 | case IF_ACMPNE: 783 | case IF_ICMPEQ: 784 | case IF_ICMPNE: 785 | case IF_ICMPLT: 786 | case IF_ICMPGT: 787 | case IF_ICMPLE: 788 | case IF_ICMPGE: 789 | case IFEQ: 790 | case IFNE: 791 | case IFLT: 792 | case IFGT: 793 | case IFLE: 794 | case IFGE: 795 | case JSR: 796 | base = i; 797 | u = 0; 798 | u = code[++i] << 8; 799 | u |= code[++i]; 800 | memcpy(&off, &u, sizeof(off)); 801 | off += base; 802 | printf("%*c%d", m, ' ', off); 803 | break; 804 | case GOTO_W: 805 | case JSR_W: 806 | base = i; 807 | a = 0; 808 | a = code[++i] << 24; 809 | a |= code[++i] << 16; 810 | a |= code[++i] << 8; 811 | a |= code[++i]; 812 | memcpy(&offw, &a, sizeof(offw)); 813 | offw += base; 814 | printf("%*c%d", m, ' ', offw); 815 | break; 816 | case LOOKUPSWITCH: 817 | i++; 818 | while (i % 4) 819 | i++; 820 | printf("->%u\n", i); 821 | i += 4; 822 | a = code[i++]; 823 | b = code[i++]; 824 | c = code[i++]; 825 | d = code[i]; 826 | npairs = (a << 24) | (b << 16) | (c << 8) | d; 827 | i += 8 * npairs; 828 | break; 829 | case TABLESWITCH: 830 | base = i++; 831 | while (i % 4) 832 | i++; 833 | a = code[i++]; 834 | b = code[i++]; 835 | c = code[i++]; 836 | d = code[i++]; 837 | def = (a << 24) | (b << 16) | (c << 8) | d; 838 | a = code[i++]; 839 | b = code[i++]; 840 | c = code[i++]; 841 | d = code[i++]; 842 | low = (a << 24) | (b << 16) | (c << 8) | d; 843 | a = code[i++]; 844 | b = code[i++]; 845 | c = code[i++]; 846 | d = code[i++]; 847 | high = (a << 24) | (b << 16) | (c << 8) | d; 848 | printf(" { // %d to %d\n", low, high); 849 | for (j = low; j <= high; j++) { 850 | a = code[i++]; 851 | b = code[i++]; 852 | c = code[i++]; 853 | d = code[i++]; 854 | printf("%24d: %d\n", j, ((int32_t)(a << 24) | (b << 16) | (c << 8) | d) + base); 855 | } 856 | i--; 857 | printf(" default: %d\n", def + base); 858 | printf(" }"); 859 | break; 860 | case GETSTATIC: 861 | u = code[++i] << 8; 862 | u |= code[++i]; 863 | n += printf("%*c#%u", m, ' ', u); 864 | m = getcol(CODECOMMENT, n); 865 | class_getnameandtype(class, cp[u]->info.fieldref_info.name_and_type_index, &name, &type); 866 | printf("%*c// Field %s.%s:%s", m, ' ', 867 | class_getclassname(class, cp[u]->info.fieldref_info.class_index), 868 | name, 869 | type); 870 | break; 871 | case INVOKEVIRTUAL: 872 | case INVOKESPECIAL: 873 | case INVOKESTATIC: 874 | u = code[++i] << 8; 875 | u |= code[++i]; 876 | n += printf("%*c#%u", m, ' ', u); 877 | m = getcol(CODECOMMENT, n); 878 | class_getnameandtype(class, cp[u]->info.methodref_info.name_and_type_index, &name, &type); 879 | cname = class_getclassname(class, cp[u]->info.methodref_info.class_index); 880 | if (strcmp(cname, class_getclassname(class, class->this_class)) == 0) 881 | cname = ""; 882 | name = quotename(name); 883 | printf("%*c// Method %s%s%s:%s", m, ' ', cname, (*cname == '\0' ? "" : "."), name, type); 884 | break; 885 | case LDC: 886 | case LDC_W: 887 | case LDC2_W: 888 | u = 0; 889 | if (code[i] == LDC_W || code[i] == LDC2_W) 890 | u = code[++i]; 891 | u |= code[++i]; 892 | n += printf("%*c#%u", m, ' ', u); 893 | m = getcol(CODECOMMENT, n); 894 | switch (cp[u]->tag) { 895 | case CONSTANT_String: 896 | printf("%*c// String %s", m, ' ', class_getstring(class, u)); 897 | break; 898 | case CONSTANT_Long: 899 | printf("%*c// Integer %lld", m, ' ', (long long int)class_getlong(class, u)); 900 | break; 901 | case CONSTANT_Double: 902 | printf("%*c// double %gd", m, ' ', (double)class_getdouble(class, u)); 903 | break; 904 | case CONSTANT_Integer: 905 | printf("%*c// Integer %ld", m, ' ', (long int)class_getinteger(class, u)); 906 | break; 907 | case CONSTANT_Float: 908 | printf("%*c// float %gf", m, ' ', (float)class_getfloat(class, u)); 909 | break; 910 | } 911 | break; 912 | case MULTIANEWARRAY: 913 | u = code[++i] << 8; 914 | u |= code[++i]; 915 | n += printf(" #%u, %u", u, code[++i]); 916 | m = getcol(CODECOMMENT, n); 917 | printf("%*c// class \"%s\"", m, ' ', class_getutf8(class, cp[u]->info.class_info.name_index)); 918 | break; 919 | case NEWARRAY: 920 | type = typenames[code[++i]]; 921 | printf("%*c%s", m, ' ', type); 922 | break; 923 | default: 924 | for (j = 0; i < count && j < class_getnoperands(opcode); j++) 925 | i++; 926 | break; 927 | } 928 | printf("\n"); 929 | } 930 | } 931 | 932 | /* print method information */ 933 | static void 934 | printmethod(ClassFile *class, U2 count) 935 | { 936 | char *name; 937 | int init = 0; 938 | U2 nargs; 939 | Attribute *cattr; /* Code_attribute */ 940 | Attribute *lnattr; /* LineNumberTable_attribute */ 941 | Attribute *lvattr; /* LocalVariableTable_attribute */ 942 | Method *method; 943 | 944 | method = class->methods[count]; 945 | if (!pflag && method->access_flags & ACC_PRIVATE) 946 | return; 947 | if (count && (lflag || sflag || cflag)) 948 | putchar('\n'); 949 | name = class_getutf8(class, method->name_index); 950 | if (strcmp(name, "") == 0) { 951 | name = class_getclassname(class, class->this_class); 952 | init = 1; 953 | } 954 | printf(" "); 955 | if (method->access_flags & ACC_PRIVATE) 956 | printf("private "); 957 | else if (method->access_flags & ACC_PROTECTED) 958 | printf("protected "); 959 | else if (method->access_flags & ACC_PUBLIC) 960 | printf("public "); 961 | if (method->access_flags & ACC_ABSTRACT) 962 | printf("abstract "); 963 | if (method->access_flags & ACC_STATIC) 964 | printf("static "); 965 | if (method->access_flags & ACC_FINAL) 966 | printf("final "); 967 | if (method->access_flags & ACC_SYNCHRONIZED) 968 | printf("synchronized "); 969 | if (method->access_flags & ACC_NATIVE) 970 | printf("native "); 971 | if (method->access_flags & ACC_STRICT) 972 | printf("strict "); 973 | nargs = printdeclaration(class_getutf8(class, method->descriptor_index), name, init); 974 | if (!(method->access_flags & ACC_STATIC)) 975 | nargs++; 976 | printf(";\n"); 977 | if (sflag) 978 | printf(" descriptor: %s\n", class_getutf8(class, method->descriptor_index)); 979 | if (verbose) { 980 | printf(" "); 981 | printflags(method->access_flags, TYPE_METHOD); 982 | } 983 | cattr = class_getattr(method->attributes, method->attributes_count, Code); 984 | if (cattr != NULL) { 985 | lnattr = class_getattr(cattr->info.code.attributes, cattr->info.code.attributes_count, LineNumberTable); 986 | lvattr = class_getattr(cattr->info.code.attributes, cattr->info.code.attributes_count, LocalVariableTable); 987 | if (cflag) { 988 | printcode(class, &cattr->info.code, nargs); 989 | } 990 | if (lflag && lnattr != NULL) { 991 | printlinenumbers(&lnattr->info.linenumbertable); 992 | } 993 | if (lflag && lvattr != NULL) { 994 | printlocalvars(class, &lvattr->info.localvariabletable); 995 | } 996 | } 997 | } 998 | 999 | /* print class contents */ 1000 | static void 1001 | javap(ClassFile *class) 1002 | { 1003 | U2 i; 1004 | 1005 | printsource(class); 1006 | printheader(class); 1007 | if (verbose) { 1008 | printf("\n"); 1009 | printmeta(class); 1010 | printcp(class); 1011 | printf("{\n"); 1012 | } else { 1013 | printf(" {\n"); 1014 | } 1015 | for (i = 0; i < class->fields_count; i++) 1016 | printfield(class, i); 1017 | for (i = 0; i < class->methods_count; i++) 1018 | printmethod(class, i); 1019 | printf("}\n"); 1020 | } 1021 | 1022 | /* javap: disassemble jclass files */ 1023 | int 1024 | main(int argc, char *argv[]) 1025 | { 1026 | ClassFile *class; 1027 | FILE *fp; 1028 | int exitval = EXIT_SUCCESS; 1029 | int status; 1030 | int ch; 1031 | 1032 | setprogname(argv[0]); 1033 | while ((ch = getopt(argc, argv, "clpsv")) != -1) { 1034 | switch (ch) { 1035 | case 'c': 1036 | cflag = 1; 1037 | break; 1038 | case 'l': 1039 | lflag = 1; 1040 | break; 1041 | case 'p': 1042 | pflag = 1; 1043 | break; 1044 | case 's': 1045 | sflag = 1; 1046 | break; 1047 | case 'v': 1048 | verbose = 1; 1049 | cflag = 1; 1050 | lflag = 1; 1051 | sflag = 1; 1052 | break; 1053 | default: 1054 | usage(); 1055 | break; 1056 | } 1057 | } 1058 | argc -= optind; 1059 | argv += optind; 1060 | if (argc == 0) 1061 | usage(); 1062 | class = emalloc(sizeof *class); 1063 | for (; argc--; argv++) { 1064 | if ((fp = fopen(*argv, "rb")) == NULL) { 1065 | warn("%s", *argv); 1066 | exitval = EXIT_FAILURE; 1067 | continue; 1068 | } 1069 | if ((status = file_read(fp, class)) != 0) { 1070 | warnx("%s: %s", *argv, file_errstr(status)); 1071 | exitval = EXIT_FAILURE; 1072 | } else { 1073 | javap(class); 1074 | file_free(class); 1075 | } 1076 | fclose(fp); 1077 | } 1078 | return exitval; 1079 | } 1080 | -------------------------------------------------------------------------------- /memory.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "class.h" 4 | #include "memory.h" 5 | #include "util.h" 6 | 7 | static Frame *framestack = NULL; 8 | static Heap *heap = NULL; 9 | 10 | /* allocate frame; push it onto framestack; and return it */ 11 | Frame * 12 | frame_push(Code_attribute *code, ClassFile *class, U2 max_locals, U2 max_stack) 13 | { 14 | Frame *frame = NULL; 15 | Value *local = NULL; 16 | Value *stack = NULL; 17 | 18 | frame = malloc(sizeof *frame); 19 | local = calloc(max_locals, sizeof *local); 20 | stack = calloc(max_stack, sizeof *stack); 21 | if (frame == NULL || (max_locals && local == NULL) || (max_stack && stack == NULL)) { 22 | free(frame); 23 | free(local); 24 | free(stack); 25 | return NULL; 26 | } 27 | frame->pc = 0; 28 | frame->code = code; 29 | frame->class = class; 30 | frame->local = local; 31 | frame->stack = stack; 32 | frame->max_locals = max_locals; 33 | frame->max_stack = max_stack ; 34 | frame->nstack = 0; 35 | frame->next = framestack; 36 | framestack = frame; 37 | return frame; 38 | } 39 | 40 | /* pop and free frame from framestack; return -1 on error */ 41 | int 42 | frame_pop(void) 43 | { 44 | Frame *frame; 45 | 46 | if (framestack == NULL) 47 | return -1; 48 | frame = framestack; 49 | framestack = frame->next; 50 | free(frame->local); 51 | free(frame->stack); 52 | free(frame); 53 | return 0; 54 | } 55 | 56 | /* pop and free all frames from framestack */ 57 | void 58 | frame_del(void) 59 | { 60 | while (framestack) { 61 | frame_pop(); 62 | } 63 | } 64 | 65 | /* push value onto frame's operand stack */ 66 | void 67 | frame_stackpush(Frame *frame, Value value) 68 | { 69 | // TODO: handle error when frame->nstack >= frame->max_stack 70 | frame->stack[frame->nstack++] = value; 71 | } 72 | 73 | /* push value onto frame's operand stack */ 74 | Value 75 | frame_stackpop(Frame *frame) 76 | { 77 | // TODO: handle error when --frame->nstack == 0 78 | if (frame->nstack == 0) 79 | errx(EXIT_FAILURE, "ASDA"); 80 | return frame->stack[--frame->nstack]; 81 | } 82 | 83 | /* store value into local variable array */ 84 | void 85 | frame_localstore(Frame *frame, U2 i, Value v) 86 | { 87 | frame->local[i] = v; 88 | } 89 | 90 | /* get value from local variable array */ 91 | Value 92 | frame_localload(Frame *frame, U2 i) 93 | { 94 | return frame->local[i]; 95 | } 96 | 97 | /* allocate entry in heap */ 98 | Heap * 99 | heap_alloc(int32_t nmemb, size_t size) 100 | { 101 | Heap *entry = NULL; 102 | void *obj = NULL; 103 | 104 | entry = malloc(sizeof *entry); 105 | if (nmemb) { 106 | obj = calloc(nmemb, size); 107 | } 108 | if (entry == NULL || (nmemb && obj == NULL)) { 109 | free(entry); 110 | free(obj); 111 | return NULL; 112 | } 113 | entry->nmemb = nmemb; 114 | entry->count = 0; 115 | entry->obj = obj; 116 | entry->prev = NULL; 117 | entry->next = heap; 118 | if (heap) 119 | heap->prev = entry; 120 | heap = entry; 121 | return heap; 122 | } 123 | 124 | /* use entry in heap */ 125 | void * 126 | heap_use(Heap *entry) 127 | { 128 | if (entry == NULL) 129 | return NULL; 130 | entry->count++; 131 | return entry->obj; 132 | } 133 | 134 | /* free entry in heap */ 135 | int 136 | heap_free(Heap *entry) 137 | { 138 | if (entry == NULL) 139 | return -1; 140 | if (entry->count == 1) { 141 | if (entry->nmemb) { 142 | free(entry->obj); 143 | } 144 | if (entry->next) { 145 | entry->next->prev = entry->prev; 146 | } 147 | if (entry->prev) { 148 | entry->prev->next = entry->next; 149 | } else { 150 | heap = entry->next; 151 | } 152 | free(entry); 153 | } else { 154 | entry->count--; 155 | } 156 | return 0; 157 | } 158 | 159 | /* recursivelly create multidimensional array */ 160 | Heap * 161 | array_new(int32_t *nmemb, U1 dimension, size_t size) 162 | { 163 | Heap *h; 164 | int32_t i; 165 | 166 | if (dimension == 1) { 167 | h = heap_alloc(*nmemb, size); 168 | } else { 169 | h = heap_alloc(*nmemb, sizeof (Heap *)); 170 | for (i = 0; i < *nmemb; i++) { 171 | ((void **)h->obj)[i] = array_new(nmemb + 1, dimension - 1, size); 172 | } 173 | } 174 | return h; 175 | } 176 | -------------------------------------------------------------------------------- /memory.h: -------------------------------------------------------------------------------- 1 | /* virtual machine frame structure */ 2 | typedef struct Frame { 3 | struct Frame *next; 4 | struct ClassFile *class; /* constant pool */ 5 | union Value *local; /* local variable table */ 6 | union Value *stack; /* operand stack */ 7 | size_t max_locals; /* local variable table */ 8 | size_t max_stack; /* operand stack */ 9 | size_t nstack; /* number of values on operand stack */ 10 | struct Code_attribute *code; /* array of instructions */ 11 | U2 pc; /* program counter */ 12 | } Frame; 13 | 14 | Frame *frame_push(Code_attribute *code, ClassFile *class, U2 max_locals, U2 max_stack); 15 | int frame_pop(void); 16 | void frame_del(void); 17 | void frame_stackpush(Frame *frame, Value value); 18 | Value frame_stackpop(Frame *frame); 19 | void frame_localstore(Frame *frame, U2 i, Value v); 20 | Value frame_localload(Frame *frame, U2 i); 21 | Heap *heap_alloc(int32_t nmemb, size_t size); 22 | void *heap_use(Heap *entry); 23 | int heap_free(Heap *heap); 24 | Heap *array_new(int32_t *nmemb, U1 dimension, size_t size); 25 | -------------------------------------------------------------------------------- /native.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "class.h" 6 | #include "memory.h" 7 | #include "native.h" 8 | 9 | static void 10 | natprintln(Frame *frame, char *type) 11 | { 12 | Value vfp, v; 13 | 14 | v = frame_stackpop(frame); 15 | if (strcmp(type, "()V") == 0) { 16 | fprintf((FILE *)v.v->obj, "\n"); 17 | } else { 18 | vfp = frame_stackpop(frame); 19 | if (strcmp(type, "(Ljava/lang/String;)V") == 0) 20 | fprintf((FILE *)vfp.v->obj, "%s\n", (char *)v.v->obj); 21 | else if (strcmp(type, "(B)V") == 0) 22 | fprintf((FILE *)vfp.v->obj, "%d\n", v.i); 23 | else if (strcmp(type, "(C)V") == 0) 24 | fprintf((FILE *)vfp.v->obj, "%c\n", v.i); 25 | else if (strcmp(type, "(D)V") == 0) 26 | fprintf((FILE *)vfp.v->obj, "%.16g\n", v.d); 27 | else if (strcmp(type, "(F)V") == 0) 28 | fprintf((FILE *)vfp.v->obj, "%.16g\n", v.f); 29 | else if (strcmp(type, "(I)V") == 0) 30 | fprintf((FILE *)vfp.v->obj, "%d\n", v.i); 31 | else if (strcmp(type, "(J)V") == 0) 32 | fprintf((FILE *)vfp.v->obj, "%lld\n", (long long int)v.l); 33 | else if (strcmp(type, "(S)V") == 0) 34 | fprintf((FILE *)vfp.v->obj, "%d\n", v.i); 35 | else if (strcmp(type, "(Z)V") == 0) 36 | fprintf((FILE *)vfp.v->obj, "%d\n", v.i); 37 | } 38 | } 39 | 40 | static void 41 | natprint(Frame *frame, char *type) 42 | { 43 | Value vfp, v; 44 | 45 | v = frame_stackpop(frame); 46 | if (strcmp(type, "()V") != 0) { 47 | vfp = frame_stackpop(frame); 48 | if (strcmp(type, "(Ljava/lang/String;)V") == 0) 49 | fprintf((FILE *)vfp.v->obj, "%s", (char *)v.v->obj); 50 | else if (strcmp(type, "(B)V") == 0) 51 | fprintf((FILE *)vfp.v->obj, "%d", v.i); 52 | else if (strcmp(type, "(C)V") == 0) 53 | fprintf((FILE *)vfp.v->obj, "%c", v.i); 54 | else if (strcmp(type, "(D)V") == 0) 55 | fprintf((FILE *)vfp.v->obj, "%.16g", v.d); 56 | else if (strcmp(type, "(F)V") == 0) 57 | fprintf((FILE *)vfp.v->obj, "%.16g", v.f); 58 | else if (strcmp(type, "(I)V") == 0) 59 | fprintf((FILE *)vfp.v->obj, "%d", v.i); 60 | else if (strcmp(type, "(J)V") == 0) 61 | fprintf((FILE *)vfp.v->obj, "%lld", (long long int)v.l); 62 | else if (strcmp(type, "(S)V") == 0) 63 | fprintf((FILE *)vfp.v->obj, "%d", v.i); 64 | else if (strcmp(type, "(Z)V") == 0) 65 | fprintf((FILE *)vfp.v->obj, "%d", v.i); 66 | } 67 | } 68 | 69 | static void 70 | natstringcharat(Frame *frame, char *type) 71 | { 72 | Value index, receiver, result; 73 | const char *str; 74 | 75 | // TODO(max): UTF-16 index 76 | assert(strcmp(type, "(I)C") == 0); 77 | index = frame_stackpop(frame); 78 | receiver = frame_stackpop(frame); 79 | str = (char *)receiver.v->obj; 80 | result.i = str[index.i]; 81 | frame_stackpush(frame, result); 82 | } 83 | 84 | static void 85 | natstringlength(Frame *frame, char *type) 86 | { 87 | Value receiver, result; 88 | const char *str; 89 | 90 | // TODO(max): UTF-16 91 | assert(strcmp(type, "()I") == 0); 92 | receiver = frame_stackpop(frame); 93 | str = (char *)receiver.v->obj; 94 | result.i = strlen(str); 95 | frame_stackpush(frame, result); 96 | } 97 | 98 | static struct { 99 | char *name; 100 | JavaClass jclass; 101 | } jclasstab[] = { 102 | {"java/lang/System", LANG_SYSTEM}, 103 | {"java/lang/String", LANG_STRING}, 104 | {"java/io/PrintStream", IO_PRINTSTREAM}, 105 | {NULL, NONE_CLASS}, 106 | }; 107 | 108 | static struct Native { 109 | const char *name; 110 | void (*method)(Frame *frame, char *type); 111 | } *nativetab[] = { 112 | [IO_PRINTSTREAM] = (struct Native[]){ 113 | {"print", natprint}, 114 | {"println", natprintln}, 115 | {NULL, NULL}, 116 | }, 117 | [LANG_STRING] = (struct Native[]){ 118 | {"charAt", natstringcharat}, 119 | {"length", natstringlength}, 120 | {NULL, NULL}, 121 | }, 122 | [LANG_SYSTEM] = (struct Native[]){ 123 | {NULL, NULL}, 124 | }, 125 | }; 126 | 127 | JavaClass 128 | native_javaclass(char *classname) 129 | { 130 | size_t i; 131 | 132 | for (i = 0; jclasstab[i].name; i++) 133 | if (strcmp(classname, jclasstab[i].name) == 0) 134 | break; 135 | return jclasstab[i].jclass; 136 | } 137 | 138 | void * 139 | native_javaobj(JavaClass jclass, char *objname, char *objtype) 140 | { 141 | switch (jclass) { 142 | default: 143 | break; 144 | case LANG_SYSTEM: 145 | if (strcmp(objtype, "Ljava/io/PrintStream;") == 0) { 146 | if (strcmp(objname, "out") == 0) { 147 | return stdout; 148 | } else if (strcmp(objname, "err") == 0) { 149 | return stderr; 150 | } else if (strcmp(objname, "in") == 0) { 151 | return stdin; 152 | } 153 | } 154 | break; 155 | } 156 | return NULL; 157 | } 158 | 159 | int 160 | native_javamethod(Frame *frame, JavaClass jclass, char *name, char *type) 161 | { 162 | U8 i; 163 | 164 | for (i = 0; nativetab[jclass][i].name != NULL; i++) { 165 | if (strcmp(name, nativetab[jclass][i].name) == 0) { 166 | nativetab[jclass][i].method(frame, type); 167 | return 0; 168 | } 169 | } 170 | return -1; 171 | } 172 | -------------------------------------------------------------------------------- /native.h: -------------------------------------------------------------------------------- 1 | typedef enum JavaClass { 2 | NONE_CLASS = -1, 3 | LANG_SYSTEM = 0, 4 | LANG_STRING = 1, 5 | IO_PRINTSTREAM = 2, 6 | } JavaClass; 7 | 8 | JavaClass native_javaclass(char *classname); 9 | void *native_javaobj(JavaClass jclass, char *objname, char *objtype); 10 | int native_javamethod(Frame *frame, JavaClass jclass, char *name, char *type); 11 | -------------------------------------------------------------------------------- /tests/Double.java: -------------------------------------------------------------------------------- 1 | public class Double { 2 | public static void main(String[] args) { 3 | double d1 = 98.24D; 4 | double d2 = 134.87D; 5 | 6 | System.out.println(d1 + d2); 7 | System.out.println(d1 - d2); 8 | System.out.println(d1 * d2); 9 | System.out.println(d1 / d2); 10 | System.out.println(-d1); 11 | System.out.println(d2 % d1); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/Echo.java: -------------------------------------------------------------------------------- 1 | public class Echo { 2 | public static void main(String[] args) { 3 | for (int i = 0; i < args.length; i++) { 4 | System.out.print(args[i]); 5 | if (i + 1 == args.length) { 6 | System.out.println(); 7 | } else { 8 | System.out.print(' '); 9 | } 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/HelloWorld.java: -------------------------------------------------------------------------------- 1 | public class HelloWorld { 2 | static final String str = "Hello world!"; 3 | public static void main(String[] args) { 4 | System.out.println(str); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /tests/Int.java: -------------------------------------------------------------------------------- 1 | public class Int { 2 | public static void main(String[] args) { 3 | int a, b, c; 4 | a = 90; 5 | b = 42; 6 | c = a + b; 7 | System.out.println(c); 8 | c = a - b; 9 | System.out.println(c); 10 | c = a * b; 11 | System.out.println(c); 12 | c = a / b; 13 | System.out.println(c); 14 | c = a % b; 15 | System.out.println(c); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/Multi.java: -------------------------------------------------------------------------------- 1 | public class Multi { 2 | public static void main(String[] args) { 3 | String[][] arr = new String[10][10]; 4 | 5 | arr[0][0] = "test1"; 6 | arr[0][1] = "test2"; 7 | arr[9][5] = "test3"; 8 | System.out.println(arr[0][0]); 9 | System.out.println(arr[0][1]); 10 | System.out.println(arr[9][5]); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/StringTest.java: -------------------------------------------------------------------------------- 1 | public class StringTest { 2 | static final String str = "Hello world!"; 3 | public static void main(String[] args) { 4 | for (int i = 0; i < str.length(); i++) { 5 | System.out.print(str.charAt(i)); 6 | } 7 | System.out.println(""); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/TableSwitch.java: -------------------------------------------------------------------------------- 1 | public class TableSwitch { 2 | public TableSwitch() { 3 | System.out.println("nop"); 4 | } 5 | 6 | public static int choose(int n) { 7 | switch (n) { 8 | case 0: 9 | return 0; 10 | case 1: 11 | return 1; 12 | case 2: 13 | return 2; 14 | } 15 | return -1; 16 | } 17 | 18 | public static void main(String[] args) { 19 | System.out.println(choose(-1)); 20 | System.out.println(choose(0)); 21 | System.out.println(choose(1)); 22 | System.out.println(choose(2)); 23 | System.out.println(choose(3)); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/Vector1.java: -------------------------------------------------------------------------------- 1 | public class Vector1 { 2 | public static void main(String[] args) { 3 | int[] arrayOfInt = new int[10]; 4 | double[] arrayOfDouble = { 2.0D, 3.0D, -5.0D }; 5 | long[] arrayOfLong = { -5L, 3L, 6426246L, -433242L }; 6 | float[] arrayOfFloat = { 2.0F, 3.0F, -5.0F }; 7 | byte[] arrayOfByte = { -2, 4, 0 }; 8 | char[] arrayOfChar = { 'a', '0', ')' }; 9 | short[] arrayOfShort = { 15, 1000, -2 }; 10 | byte b; 11 | for (b = 0; b < 10; b++) 12 | arrayOfInt[b] = b; 13 | arrayOfInt[0] = arrayOfInt[0] + 100000; 14 | for (b = 0; b < 10; b++) 15 | System.out.println(arrayOfInt[b]); 16 | System.out.println(arrayOfInt.length); 17 | System.out.println(); 18 | for (b = 0; b < 3; b++) 19 | System.out.println(arrayOfDouble[b]); 20 | System.out.println(arrayOfDouble.length); 21 | System.out.println(); 22 | for (b = 0; b < 4; b++) 23 | System.out.println(arrayOfLong[b]); 24 | System.out.println(arrayOfLong.length); 25 | System.out.println(); 26 | for (b = 0; b < 3; b++) 27 | System.out.println(arrayOfFloat[b]); 28 | System.out.println(arrayOfFloat.length); 29 | System.out.println(); 30 | for (b = 0; b < 3; b++) 31 | System.out.println(arrayOfByte[b]); 32 | System.out.println(arrayOfByte.length); 33 | System.out.println(); 34 | for (b = 0; b < 3; b++) 35 | System.out.println(arrayOfChar[b]); 36 | System.out.println(arrayOfChar.length); 37 | System.out.println(); 38 | for (b = 0; b < 3; b++) 39 | System.out.println(arrayOfShort[b]); 40 | System.out.println(arrayOfShort.length); 41 | System.out.println(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/Vector2.java: -------------------------------------------------------------------------------- 1 | public class Vector2 { 2 | public static void main(String[] args) { 3 | int[] arrayOfInt1 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 4 | float[] arrayOfFloat1 = { 2.0F, 3.0F, -5.0F }; 5 | int[] arrayOfInt2 = { -5, 3, 6426246, -433242 }; 6 | float[] arrayOfFloat2 = { 2.0F, 3.0F, -5.0F }; 7 | byte[] arrayOfByte = { -2, 4, 0 }; 8 | char[] arrayOfChar = { 'a', '0', ')' }; 9 | short[] arrayOfShort = { 15, 1000, -2 }; 10 | byte b; 11 | for (b = 0; b < 10; b++) 12 | arrayOfInt1[b] = b; 13 | arrayOfInt1[0] = arrayOfInt1[0] + 100000; 14 | for (b = 0; b < 10; b++) 15 | System.out.println(arrayOfInt1[b]); 16 | System.out.println(arrayOfInt1.length); 17 | System.out.println(); 18 | for (b = 0; b < 3; b++) 19 | System.out.println(arrayOfFloat1[b]); 20 | System.out.println(arrayOfFloat1.length); 21 | System.out.println(); 22 | for (b = 0; b < 4; b++) 23 | System.out.println(arrayOfInt2[b]); 24 | System.out.println(arrayOfInt2.length); 25 | System.out.println(); 26 | for (b = 0; b < 3; b++) 27 | System.out.println(arrayOfFloat2[b]); 28 | System.out.println(arrayOfFloat2.length); 29 | System.out.println(); 30 | for (b = 0; b < 3; b++) 31 | System.out.println(arrayOfByte[b]); 32 | System.out.println(arrayOfByte.length); 33 | System.out.println(); 34 | for (b = 0; b < 3; b++) 35 | System.out.println(arrayOfChar[b]); 36 | System.out.println(arrayOfChar.length); 37 | System.out.println(); 38 | for (b = 0; b < 3; b++) 39 | System.out.println(arrayOfShort[b]); 40 | System.out.println(arrayOfShort.length); 41 | System.out.println(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /util.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | static char *progname; 10 | 11 | int optind = 1; 12 | int optopt; 13 | 14 | /* set program name */ 15 | void 16 | setprogname(char *s) 17 | { 18 | progname = s; 19 | } 20 | 21 | /* get int32_t from uint32_t */ 22 | int32_t 23 | getint(uint32_t bytes) 24 | { 25 | int32_t i; 26 | 27 | memcpy(&i, &bytes, sizeof i); 28 | return i; 29 | } 30 | 31 | /* get float from uint32_t */ 32 | float 33 | getfloat(uint32_t bytes) 34 | { 35 | float f; 36 | 37 | memcpy(&f, &bytes, sizeof f); 38 | return f; 39 | } 40 | 41 | /* get int64_t from uint32_t */ 42 | int64_t 43 | getlong(uint32_t high_bytes, uint32_t low_bytes) 44 | { 45 | uint64_t u; 46 | int64_t l; 47 | 48 | u = ((uint64_t)high_bytes << 32) | (uint64_t)low_bytes; 49 | memcpy(&l, &u, sizeof l); 50 | return l; 51 | } 52 | 53 | /* get double from uint32_t */ 54 | double 55 | getdouble(uint32_t high_bytes, uint32_t low_bytes) 56 | { 57 | uint64_t u; 58 | double d; 59 | 60 | u = ((uint64_t)high_bytes << 32) | (uint64_t)low_bytes; 61 | memcpy(&d, &u, sizeof d); 62 | return d; 63 | } 64 | 65 | /* print format error message with error string and exit */ 66 | void 67 | err(int eval, const char *fmt, ...) 68 | { 69 | va_list ap; 70 | int saverrno; 71 | 72 | saverrno = errno; 73 | if (progname) 74 | (void)fprintf(stderr, "%s: ", progname); 75 | va_start(ap, fmt); 76 | if (fmt) { 77 | (void)vfprintf(stderr, fmt, ap); 78 | (void)fprintf(stderr, ": "); 79 | } 80 | va_end(ap); 81 | (void)fprintf(stderr, "%s\n", strerror(saverrno)); 82 | exit(eval); 83 | } 84 | 85 | /* print format error message and exit */ 86 | void 87 | errx(int eval, const char *fmt, ...) 88 | { 89 | va_list ap; 90 | 91 | if (progname) 92 | (void)fprintf(stderr, "%s: ", progname); 93 | va_start(ap, fmt); 94 | if (fmt) 95 | (void)vfprintf(stderr, fmt, ap); 96 | va_end(ap); 97 | (void)fprintf(stderr, "\n"); 98 | exit(eval); 99 | } 100 | 101 | /* print format error message with error string */ 102 | void 103 | warn(const char *fmt, ...) 104 | { 105 | va_list ap; 106 | int saverrno; 107 | 108 | saverrno = errno; 109 | if (progname) 110 | (void)fprintf(stderr, "%s: ", progname); 111 | va_start(ap, fmt); 112 | if (fmt) { 113 | (void)vfprintf(stderr, fmt, ap); 114 | (void)fprintf(stderr, ": "); 115 | } 116 | va_end(ap); 117 | (void)fprintf(stderr, "%s\n", strerror(saverrno)); 118 | } 119 | 120 | /* print format error message */ 121 | void 122 | warnx(const char *fmt, ...) 123 | { 124 | va_list ap; 125 | 126 | if (progname) 127 | (void)fprintf(stderr, "%s: ", progname); 128 | va_start(ap, fmt); 129 | if (fmt) 130 | (void)vfprintf(stderr, fmt, ap); 131 | va_end(ap); 132 | (void)fprintf(stderr, "\n"); 133 | } 134 | 135 | /* call calloc checking for errors */ 136 | void * 137 | ecalloc(size_t nmemb, size_t size) 138 | { 139 | void *p; 140 | 141 | if ((p = calloc(nmemb, size)) == NULL) 142 | err(EXIT_FAILURE, "calloc"); 143 | return p; 144 | } 145 | 146 | /* call malloc checking for errors */ 147 | void * 148 | emalloc(size_t size) 149 | { 150 | void *p; 151 | 152 | if ((p = malloc(size)) == NULL) 153 | err(EXIT_FAILURE, "calloc"); 154 | return p; 155 | } 156 | 157 | /* get options, we do not support ':' on options */ 158 | int 159 | getopt(int argc, char * const *argv, const char *options) 160 | { 161 | static int optpos = 1; 162 | 163 | if (!optind) { /* reset */ 164 | optind = 1; 165 | optpos = 1; 166 | } 167 | if (optind >= argc || !argv[optind] || argv[optind][0] != '-') { 168 | return -1; 169 | } 170 | if (strcmp(argv[optind], "--") == 0) { 171 | optind++; 172 | return -1; 173 | } 174 | optopt = argv[optind][optpos]; 175 | if (strchr(options, argv[optind][optpos]) == NULL) { 176 | warnx("unknown option -- %c", argv[optind][optpos]); 177 | return '?'; 178 | } 179 | if (!argv[optind][++optpos]) { 180 | optind++; 181 | optpos = 1; 182 | } 183 | return optopt; 184 | } 185 | -------------------------------------------------------------------------------- /util.h: -------------------------------------------------------------------------------- 1 | #define LEN(x) (sizeof (x) / sizeof *(x)) 2 | 3 | void setprogname(char *s); 4 | void *ecalloc(size_t nmemb, size_t size); 5 | void *emalloc(size_t size); 6 | int getopt(int argc, char * const *argv, const char *options); 7 | int32_t getint(uint32_t bytes); 8 | float getfloat(uint32_t bytes); 9 | int64_t getlong(uint32_t high_bytes, uint32_t low_bytes); 10 | double getdouble(uint32_t high_bytes, uint32_t low_bytes); 11 | void err(int eval, const char *fmt, ...); 12 | void errx(int eval, const char *fmt, ...); 13 | void warn(const char *fmt, ...); 14 | void warnx(const char *fmt, ...); 15 | 16 | extern int optind, optopt; 17 | --------------------------------------------------------------------------------