├── .gitignore ├── LICENSE ├── Makefile ├── simple_dvm ├── Makefile ├── bytecodes.c ├── class_def_parser.c ├── dex_parser.c ├── java_lib.c ├── java_lib.h ├── leb128.c ├── main.c ├── map_list_parser.c ├── method_ids_parser.c ├── simple_dvm.h ├── string_ids_parser.c ├── type_ids_parser.c └── utils.c ├── simple_jvm ├── Makefile ├── bytecodes.c ├── class_parser.c ├── constant_pool_parser.c ├── field_pool_parser.c ├── free_pool.c ├── interface_pool_parser.c ├── java_lib.c ├── java_lib.h ├── main.c ├── method_pool_parser.c ├── simple_jvm.h └── stack.c └── tests ├── Foo1.class ├── Foo1.dex └── Foo1.java /.gitignore: -------------------------------------------------------------------------------- 1 | # compiling output 2 | *.dat 3 | *.la 4 | *.lo 5 | *.o 6 | .deps 7 | .libs 8 | *.a 9 | simple_jvm/jvm 10 | simple_dvm/dvm 11 | 12 | # tests 13 | output-jvm 14 | output-dvm 15 | 16 | # gcov output 17 | *.gcda 18 | *.gcno 19 | *.gcov 20 | /coverage.info 21 | /coveragereport 22 | 23 | # cscope output 24 | cscope.* 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Jim Huang 2 | Copyright (C) 2013 Chun-Yu Wang 3 | All rights reserved. 4 | 5 | Permission to use, copy, modify, distribute, and sell this software and its 6 | documentation for any purpose is hereby granted without fee, provided that 7 | the above copyright notice appear in all copies and that both that copyright 8 | notice and this permission notice appear in supporting documentation, and 9 | that the name of the copyright holders not be used in advertising or 10 | publicity pertaining to distribution of the software without specific, 11 | written prior permission. The copyright holders make no representations 12 | about the suitability of this software for any purpose. It is provided "as 13 | is" without express or implied warranty. 14 | 15 | THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16 | INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 17 | EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 18 | CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 19 | DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 20 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 21 | OF THIS SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | VMS = simple_jvm/jvm simple_dvm/dvm 2 | 3 | all: $(VMS) 4 | 5 | simple_jvm/jvm: 6 | $(MAKE) -C simple_jvm 7 | 8 | simple_dvm/dvm: 9 | $(MAKE) -C simple_dvm 10 | 11 | clean: 12 | $(MAKE) -C simple_jvm clean 13 | $(MAKE) -C simple_dvm clean 14 | $(RM) output-jvm output-dvm 15 | 16 | check: $(VMS) 17 | simple_jvm/jvm tests/Foo1.class > output-jvm 18 | simple_dvm/dvm tests/Foo1.dex > output-dvm 19 | @diff -u output-jvm output-dvm || echo "ERROR: different results" 20 | -------------------------------------------------------------------------------- /simple_dvm/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = dvm 2 | 3 | # Toolchain configurations 4 | CROSS_COMPILE ?= 5 | CC = $(CROSS_COMPILE)gcc 6 | 7 | SUFFIX ?= 8 | EXECUTABLE = $(PROJECT)$(SUFFIX) 9 | 10 | # Basic configurations 11 | CFLAGS += -g -std=c99 12 | LDFLAGS = 13 | 14 | # Optimizations 15 | CFLAGS += -Os 16 | 17 | # project starts here 18 | CFLAGS += -I. 19 | OBJS = \ 20 | bytecodes.o \ 21 | java_lib.o \ 22 | map_list_parser.o \ 23 | type_ids_parser.o \ 24 | class_def_parser.o \ 25 | leb128.o \ 26 | method_ids_parser.o \ 27 | utils.o \ 28 | dex_parser.o \ 29 | string_ids_parser.o \ 30 | main.o 31 | 32 | $(EXECUTABLE): $(OBJS) 33 | $(CC) -o $@ $(OBJS) $(LDFLAGS) 34 | 35 | %.o: %.c 36 | $(CC) $(CFLAGS) -c $< -o $@ 37 | 38 | clean: 39 | rm -rf $(EXECUTABLE) 40 | rm -f $(OBJS) 41 | .PHONY: clean 42 | -------------------------------------------------------------------------------- /simple_dvm/bytecodes.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Dalvik Virtual Machine Implementation 3 | * 4 | * Copyright (C) 2014 Jim Huang 5 | * Copyright (C) 2013 Chun-Yu Wang 6 | */ 7 | 8 | #include "simple_dvm.h" 9 | #include "java_lib.h" 10 | 11 | static int find_const_string(DexFileFormat *dex, char *entry) 12 | { 13 | int i = 0; 14 | for (i = 0; i < dex->header.stringIdsSize; i++) { 15 | if (memcmp(dex->string_data_item[i].data, entry, strlen(entry)) == 0) { 16 | if (is_verbose()) 17 | printf("find %s in dex->string_data_item[%d]\n", entry, i); 18 | return i; 19 | } 20 | } 21 | return -1; 22 | } 23 | 24 | static void printRegs(simple_dalvik_vm *vm) 25 | { 26 | int i = 0; 27 | if (is_verbose()) { 28 | printf("pc = %08x\n", vm->pc); 29 | for (i = 0; i < 16 ; i++) { 30 | printf("Reg[%2d] = %4d (%04x) ", 31 | i, vm->regs[i], vm->regs[i]); 32 | if ((i + 1) % 4 == 0) printf("\n"); 33 | } 34 | } 35 | } 36 | 37 | /* 0x0b, move-result-wide 38 | * 39 | * Move the long/double result value of the previous method invocation 40 | * into vx, vx+1. 41 | * 42 | * 0B02 - move-result-wide v2 43 | * Move the long/double result value of the previous method 44 | * invocation into v2,v3. 45 | */ 46 | static int op_move_result_wide(DexFileFormat *dex, simple_dalvik_vm *vm, u1 *ptr, int *pc) 47 | { 48 | int reg_idx_vx = 0; 49 | int reg_idx_vy = 0; 50 | reg_idx_vx = ptr[*pc + 1]; 51 | reg_idx_vy = reg_idx_vx + 1; 52 | if (is_verbose()) 53 | printf("move-result-wide v%d,v%d\n", reg_idx_vx, reg_idx_vy); 54 | move_bottom_half_result_to_reg(vm, reg_idx_vx); 55 | move_top_half_result_to_reg(vm, reg_idx_vy); 56 | *pc = *pc + 2; 57 | return 0; 58 | } 59 | 60 | /* 0x0c, move-result-object vx 61 | * 62 | * Move the result object reference of 63 | * the previous method invocation into vx. 64 | * 65 | * 0C00 - move-result-object v0 66 | */ 67 | static int op_move_result_object(DexFileFormat *dex, simple_dalvik_vm *vm, u1 *ptr, int *pc) 68 | { 69 | int reg_idx_vx = 0; 70 | reg_idx_vx = ptr[*pc + 1]; 71 | if (is_verbose()) 72 | printf("move-result-object v%d\n", reg_idx_vx); 73 | move_bottom_half_result_to_reg(vm, reg_idx_vx); 74 | *pc = *pc + 2; 75 | return 0; 76 | } 77 | 78 | /* 0x0e , return-void 79 | * Return without a return value 80 | * 0E00 - return-void 81 | */ 82 | static int op_return_void(DexFileFormat *dex, simple_dalvik_vm *vm, u1 *ptr, int *pc) 83 | { 84 | if (is_verbose()) 85 | printf("return-void\n"); 86 | *pc = *pc + 2; 87 | return 0; 88 | } 89 | 90 | /* 0x12, const/4 vx,lit4 91 | * Puts the 4 bit constant into vx 92 | * 1221 - const/4 v1, #int2 93 | * Moves literal 2 into v1. 94 | * The destination register is in the lower 4 bit 95 | * in the second byte, the literal 2 is in the higher 4 bit. 96 | */ 97 | static int op_const_4(DexFileFormat *dex, simple_dalvik_vm *vm, u1 *ptr, int *pc) 98 | { 99 | int value = 0; 100 | int reg_idx_vx = 0; 101 | value = ptr[*pc + 1] >> 4; 102 | reg_idx_vx = ptr[*pc + 1] & 0x0F; 103 | if (value & 0x08) { 104 | value = 0x0F - value + 1; 105 | value = -value; 106 | } 107 | store_to_reg(vm, reg_idx_vx, (unsigned char *) &value); 108 | if (is_verbose()) 109 | printf("const/4 v%d, #int%d\n", reg_idx_vx , value); 110 | *pc = *pc + 2; 111 | return 0; 112 | } 113 | 114 | /* 0x13, const/16 vx,lit16 115 | * Puts the 16 bit constant into vx 116 | * 1300 0A00 - const/16 v0, #int 10 117 | * Puts the literal constant of 10 into v0. 118 | */ 119 | static int op_const_16(DexFileFormat *dex, simple_dalvik_vm *vm, u1 *ptr, int *pc) 120 | { 121 | int reg_idx_vx = 0; 122 | int value = 0; 123 | reg_idx_vx = ptr[*pc + 1]; 124 | value = (ptr[*pc + 3] << 8 | ptr[*pc + 2]); 125 | 126 | store_to_reg(vm, reg_idx_vx, (unsigned char *) &value); 127 | if (is_verbose()) 128 | printf("const/16 v%d, #int%d\n", reg_idx_vx, value); 129 | *pc = *pc + 4; 130 | return 0; 131 | } 132 | 133 | /* 0x19, const-wide/high16 vx,lit16 134 | * Puts the 16 bit constant into the highest 16 bit of vx 135 | * and vx+1 registers. 136 | * Used to initialize double values. 137 | * 1900 2440 - const-wide/high16 v0, #double 10.0 // #402400000 138 | * Puts the double constant of 10.0 into v0 register. 139 | */ 140 | static int op_const_wide_high16(DexFileFormat *dex, simple_dalvik_vm *vm, u1 *ptr, int *pc) 141 | { 142 | long long value = 0L; 143 | unsigned char *ptr2 = (unsigned char *) &value; 144 | int reg_idx_vx = 0; 145 | reg_idx_vx = ptr[*pc + 1]; 146 | ptr2[1] = ptr[*pc + 3]; 147 | ptr2[0] = ptr[*pc + 2]; 148 | if (is_verbose()) 149 | printf("const-wide/hight16 v%d, #long %lld\n", reg_idx_vx, value); 150 | store_to_reg(vm, reg_idx_vx, ptr2); 151 | value = 1L; 152 | *pc = *pc + 4; 153 | return 0; 154 | } 155 | 156 | /* 0x1a, const-string vx,string_id 157 | * Puts reference to a string constant identified by string_id into vx. 158 | * 1A08 0000 - const-string v8, "" // string@0000 159 | * Puts reference to string@0000 (entry #0 in the string table) into v8. 160 | */ 161 | static int op_const_string(DexFileFormat *dex, simple_dalvik_vm *vm, u1 *ptr, int *pc) 162 | { 163 | int reg_idx_vx = 0; 164 | int string_id = 0; 165 | reg_idx_vx = ptr[*pc + 1]; 166 | string_id = ((ptr[*pc + 3] << 8) | ptr[*pc + 2]); 167 | 168 | if (is_verbose()) 169 | printf("const-string v%d, string_id 0x%04x\n", 170 | reg_idx_vx , string_id); 171 | store_to_reg(vm, reg_idx_vx, (unsigned char *) &string_id); 172 | *pc = *pc + 4; 173 | return 0; 174 | } 175 | 176 | /* 0x22 new-instance vx,type 177 | * Instantiates an object type and puts 178 | * the reference of the newly created instance into vx 179 | * 2200 1500 - new-instance v0, java.io.FileInputStream // type@0015 180 | * Instantiates type@0015 (entry #15H in the type table) 181 | * and puts its reference into v0. 182 | */ 183 | static int op_new_instance(DexFileFormat *dex, simple_dalvik_vm *vm, u1 *ptr, int *pc) 184 | { 185 | int reg_idx_vx = 0; 186 | int type_id = 0; 187 | type_id_item *type_item = 0; 188 | 189 | reg_idx_vx = ptr[*pc + 1]; 190 | type_id = ((ptr[*pc + 3] << 8) | ptr[*pc + 2]); 191 | 192 | type_item = get_type_item(dex, type_id); 193 | 194 | if (is_verbose()) { 195 | printf("new-instance v%d, type_id 0x%04x", reg_idx_vx, type_id); 196 | if (type_item != 0) { 197 | printf(" %s", get_string_data(dex, type_item->descriptor_idx)); 198 | } 199 | printf("\n"); 200 | } 201 | store_to_reg(vm, reg_idx_vx, (unsigned char*)&type_id); 202 | /* TODO */ 203 | *pc = *pc + 4; 204 | return 0; 205 | } 206 | 207 | /* 35c format 208 | * A|G|op BBBB F|E|D|C 209 | * [A=5] op {vC, vD, vE, vF, vG}, meth@BBBB 210 | * [A=5] op {vC, vD, vE, vF, vG}, type@BBBB 211 | * [A=4] op {vC, vD, vE, vF}, kind@BBBB 212 | * [A=3] op {vC, vD, vE}, kind@BBBB 213 | * [A=2] op {vC, vD}, kind@BBBB 214 | * [A=1] op {vC}, kind@BBBB 215 | * [A=0] op {}, kind@BBBB 216 | * The unusual choice in lettering here reflects a desire to 217 | * make the count and the reference index have the same label as in format 3rc. 218 | */ 219 | static int op_utils_invoke_35c_parse(DexFileFormat *dex, u1 *ptr, int *pc, 220 | invoke_parameters *p) 221 | { 222 | unsigned char tmp = 0; 223 | int i = 0; 224 | if (dex != 0 && ptr != 0 && p != 0) { 225 | memset(p, 0, sizeof(invoke_parameters)); 226 | 227 | tmp = ptr[*pc + 1]; 228 | p->reg_count = tmp >> 4; 229 | p->reg_idx[4] = tmp & 0x0F; 230 | 231 | p->method_id = ptr[*pc + 2]; 232 | p->method_id |= (ptr[*pc + 3] << 4); 233 | 234 | tmp = ptr[*pc + 4]; 235 | p->reg_idx[1] = tmp >> 4; 236 | p->reg_idx[0] = tmp & 0x0F; 237 | 238 | tmp = ptr[*pc + 5]; 239 | p->reg_idx[3] = tmp >> 4; 240 | p->reg_idx[2] = tmp & 0x0F; 241 | } 242 | return 0; 243 | } 244 | 245 | static int op_utils_invoke(char *name, DexFileFormat *dex, simple_dalvik_vm *vm, 246 | invoke_parameters *p) 247 | { 248 | method_id_item *m = 0; 249 | type_id_item *type_class = 0; 250 | proto_id_item *proto_item = 0; 251 | type_list *proto_type_list = 0; 252 | if (p != 0) { 253 | m = get_method_item(dex, p->method_id); 254 | if (m != 0) { 255 | type_class = get_type_item(dex, m->class_idx); 256 | proto_item = get_proto_item(dex, m->proto_idx); 257 | } 258 | switch (p->reg_count) { 259 | case 0: 260 | if (is_verbose()) 261 | printf("%s {} method_id 0x%04x", name, p->method_id); 262 | break; 263 | case 1: 264 | if (is_verbose()) 265 | printf("%s, {v%d} method_id 0x%04x", 266 | name, p->reg_idx[0], p->method_id); 267 | break; 268 | case 2: 269 | if (is_verbose()) 270 | printf("%s {v%d, v%d} method_id 0x%04x", 271 | name, 272 | p->reg_idx[0], p->reg_idx[1], 273 | p->method_id); 274 | break; 275 | case 3: 276 | if (is_verbose()) 277 | printf("%s {v%d, v%d, v%d} method_id 0x%04x", 278 | name, 279 | p->reg_idx[0], p->reg_idx[1], p->reg_idx[2], 280 | p->method_id); 281 | break; 282 | case 4: 283 | if (is_verbose()) 284 | printf("%s {v%d, v%d, v%d, v%d} method_id 0x%04x", 285 | name, 286 | p->reg_idx[0], p->reg_idx[1], 287 | p->reg_idx[2], p->reg_idx[3], 288 | p->method_id); 289 | break; 290 | case 5: 291 | if (is_verbose()) 292 | printf("%s {v%d, v%d, v%d, v%d, v%d} method_id 0x%04x", 293 | name, 294 | p->reg_idx[0], p->reg_idx[1], p->reg_idx[2], 295 | p->reg_idx[3], p->reg_idx[4], 296 | p->method_id); 297 | break; 298 | default: 299 | break; 300 | } 301 | 302 | if (m != 0 && type_class != 0 && p->reg_count <= 5) { 303 | if (proto_item != 0) 304 | proto_type_list = get_proto_type_list(dex, m->proto_idx); 305 | if (proto_type_list != 0 && proto_type_list->size > 0) { 306 | if (is_verbose()) 307 | printf(" %s,%s,(%s)%s \n", 308 | get_string_data(dex, type_class->descriptor_idx), 309 | get_string_data(dex, m->name_idx), 310 | get_type_item_name(dex, 311 | proto_type_list->type_item[0].type_idx), 312 | get_type_item_name(dex, 313 | proto_item->return_type_idx)); 314 | invoke_java_lang_library(dex, vm, 315 | get_string_data(dex, type_class->descriptor_idx), 316 | get_string_data(dex, m->name_idx), 317 | get_type_item_name(dex, proto_type_list->type_item[0].type_idx)); 318 | } else { 319 | if (is_verbose()) 320 | printf(" %s,%s,()%s \n", 321 | get_string_data(dex, type_class->descriptor_idx), 322 | get_string_data(dex, m->name_idx), 323 | get_type_item_name(dex, 324 | proto_item->return_type_idx)); 325 | invoke_java_lang_library(dex, vm, 326 | get_string_data(dex, type_class->descriptor_idx), 327 | get_string_data(dex, m->name_idx), 0); 328 | } 329 | 330 | } else { 331 | if (is_verbose()) 332 | printf("\n"); 333 | } 334 | } 335 | return 0; 336 | } 337 | 338 | 339 | /* invoke-virtual { parameters }, methodtocall */ 340 | /* 341 | * 6E53 0600 0421 - invoke-virtual { v4, v0, v1, v2, v3}, Test2.method5:(IIII)V // method@0006 342 | * 6e20 0200 3200 invoke-virtual {v2, v3}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0002 343 | */ 344 | static int op_invoke_virtual(DexFileFormat *dex, simple_dalvik_vm *vm, u1 *ptr, int *pc) 345 | { 346 | int string_id = 0; 347 | 348 | op_utils_invoke_35c_parse(dex, ptr, pc, &vm->p); 349 | op_utils_invoke("invoke-virtual", dex, vm, &vm->p); 350 | /* TODO */ 351 | *pc = *pc + 6; 352 | return 0; 353 | } 354 | 355 | /* invoke-direct 356 | * 7010 0400 0300 invoke-direct {v3}, Ljava/lang/StringBuilder;.:()V // method@0004 357 | */ 358 | static int op_invoke_direct(DexFileFormat *dex, simple_dalvik_vm *vm, u1 *ptr, int *pc) 359 | { 360 | invoke_parameters p; 361 | int string_id = 0; 362 | 363 | op_utils_invoke_35c_parse(dex, ptr, pc, &vm->p); 364 | op_utils_invoke("invoke-direct", dex, vm, &vm->p); 365 | /* TODO */ 366 | *pc = *pc + 6; 367 | return 0; 368 | } 369 | 370 | /* 0x71 invoke-direct 371 | * 7100 0300 0000 invoke-static {}, Ljava/lang/Math;.random:()D // method@0003 372 | */ 373 | static int op_invoke_static(DexFileFormat *dex, simple_dalvik_vm *vm, u1 *ptr, int *pc) 374 | { 375 | invoke_parameters p; 376 | int string_id = 0; 377 | 378 | op_utils_invoke_35c_parse(dex, ptr, pc, &vm->p); 379 | op_utils_invoke("invoke-static", dex, vm, &vm->p); 380 | /* TODO */ 381 | *pc = *pc + 6; 382 | return 0; 383 | } 384 | 385 | /* 0x62 sget-object vx,field_id 386 | * Reads the object reference field identified by the field_id into vx. 387 | * 6201 0C00 - sget-object v1, Test3.os1:Ljava/lang/Object; // field@000c 388 | * Reads field@000c (entry #CH in the field id table) into v1. 389 | */ 390 | static int op_sget_object(DexFileFormat *dex, simple_dalvik_vm *vm, u1 *ptr, int *pc) 391 | { 392 | int field_id = 0; 393 | int reg_idx_vx = 0; 394 | reg_idx_vx = ptr[*pc + 1]; 395 | field_id = ((ptr[*pc + 3] << 8) | ptr[*pc + 2]); 396 | 397 | if (is_verbose()) { 398 | printf("sget-object v%d, field 0x%04x\n", reg_idx_vx, field_id); 399 | } 400 | store_to_reg(vm, reg_idx_vx, (unsigned char *) &field_id); 401 | /* TODO */ 402 | *pc = *pc + 4; 403 | return 0; 404 | } 405 | 406 | /* 0x90 add-int vx,vy vz 407 | * Calculates vy+vz and puts the result into vx. 408 | * 9000 0203 - add-int v0, v2, v3 409 | * Adds v3 to v2 and puts the result into v0. 410 | */ 411 | static int op_add_int(DexFileFormat *dex, simple_dalvik_vm *vm, u1 *ptr, int *pc) 412 | { 413 | int reg_idx_vx = 0; 414 | int reg_idx_vy = 0; 415 | int reg_idx_vz = 0; 416 | int x = 0, y = 0 , z = 0; 417 | reg_idx_vx = ptr[*pc + 1]; 418 | reg_idx_vy = ptr[*pc + 2]; 419 | reg_idx_vz = ptr[*pc + 3]; 420 | 421 | if (is_verbose()) 422 | printf("add-int v%d, v%d, v%d\n", reg_idx_vx, reg_idx_vy, 423 | reg_idx_vz); 424 | /* x = y + z */ 425 | load_reg_to(vm, reg_idx_vy, (unsigned char *) &y); 426 | load_reg_to(vm, reg_idx_vz, (unsigned char *) &z); 427 | x = y + z; 428 | store_to_reg(vm, reg_idx_vx, (unsigned char *) &x); 429 | *pc = *pc + 4; 430 | return 0; 431 | 432 | } 433 | 434 | /* 0x91 sub-int vx,vy,vz 435 | * Calculates vy-vz and puts the result into vx. 436 | * 9100 0203 - sub-int v0, v2, v3 437 | * Subtracts v3 from v2 and puts the result into v0. 438 | */ 439 | static int op_sub_int(DexFileFormat *dex, simple_dalvik_vm *vm, u1 *ptr, int *pc) 440 | { 441 | int reg_idx_vx = 0; 442 | int reg_idx_vy = 0; 443 | int reg_idx_vz = 0; 444 | int x = 0, y = 0 , z = 0; 445 | reg_idx_vx = ptr[*pc + 1]; 446 | reg_idx_vy = ptr[*pc + 2]; 447 | reg_idx_vz = ptr[*pc + 3]; 448 | 449 | if (is_verbose()) 450 | printf("sub-int v%d, v%d, v%d\n", reg_idx_vx, reg_idx_vz, 451 | reg_idx_vy); 452 | /* x = y + z */ 453 | load_reg_to(vm, reg_idx_vy, (unsigned char *) &y); 454 | load_reg_to(vm, reg_idx_vz, (unsigned char *) &z); 455 | x = y - z; 456 | store_to_reg(vm, reg_idx_vx, (unsigned char *) &x); 457 | *pc = *pc + 4; 458 | return 0; 459 | } 460 | 461 | /* 0x92 mul-int vx, vy, vz 462 | * Multiplies vz with wy and puts the result int vx. 463 | * 9200 0203 - mul-int v0,v2,v3 464 | * Multiplies v2 with w3 and puts the result into v0 465 | */ 466 | static int op_mul_int(DexFileFormat *dex, simple_dalvik_vm *vm, u1 *ptr, int *pc) 467 | { 468 | int reg_idx_vx = 0; 469 | int reg_idx_vy = 0; 470 | int reg_idx_vz = 0; 471 | int x = 0, y = 0 , z = 0; 472 | reg_idx_vx = ptr[*pc + 1]; 473 | reg_idx_vy = ptr[*pc + 2]; 474 | reg_idx_vz = ptr[*pc + 3]; 475 | 476 | if (is_verbose()) 477 | printf("add-int v%d, v%d, v%d\n", reg_idx_vx, reg_idx_vy, reg_idx_vz); 478 | /* x = y + z */ 479 | load_reg_to(vm, reg_idx_vy, (unsigned char *) &y); 480 | load_reg_to(vm, reg_idx_vz, (unsigned char *) &z); 481 | x = y * z; 482 | store_to_reg(vm, reg_idx_vx, (unsigned char *) &x); 483 | *pc = *pc + 4; 484 | return 0; 485 | 486 | } 487 | 488 | /* 0x93 div-int vx,vy,vz 489 | * Divides vy with vz and puts the result into vx. 490 | * 9303 0001 - div-int v3, v0, v1 491 | * Divides v0 with v1 and puts the result into v3. 492 | */ 493 | static int op_div_int(DexFileFormat *dex, simple_dalvik_vm *vm, u1 *ptr, int *pc) 494 | { 495 | int reg_idx_vx = 0; 496 | int reg_idx_vy = 0; 497 | int reg_idx_vz = 0; 498 | int x = 0, y = 0 , z = 0; 499 | reg_idx_vx = ptr[*pc + 1]; 500 | reg_idx_vy = ptr[*pc + 2]; 501 | reg_idx_vz = ptr[*pc + 3]; 502 | 503 | if (is_verbose()) 504 | printf("add-int v%d, v%d, v%d\n", reg_idx_vx, reg_idx_vy, reg_idx_vz); 505 | /* x = y + z */ 506 | load_reg_to(vm, reg_idx_vy, (unsigned char *) &y); 507 | load_reg_to(vm, reg_idx_vz, (unsigned char *) &z); 508 | x = y % z; 509 | x = (y - x) / z; 510 | store_to_reg(vm, reg_idx_vx, (unsigned char *) &x); 511 | *pc = *pc + 4; 512 | return 0; 513 | 514 | } 515 | 516 | /* 0x8A double-to-int vx, vy 517 | * Converts the double value in vy,vy+1 into an integer value in vx. 518 | * 8A40 - double-to-int v0, v4 519 | * Converts the double value in v4,v5 into an integer value in v0. 520 | */ 521 | static int op_double_to_int(DexFileFormat *dex, simple_dalvik_vm *vm, u1 *ptr, int *pc) 522 | { 523 | int reg_idx_vx = 0; 524 | int reg_idx_vy = 0; 525 | int reg_idx_vz = 0; 526 | double d = 0; 527 | unsigned char *ptr_d = (unsigned char *) &d; 528 | int i = 0; 529 | int i2 = 0 ; 530 | reg_idx_vx = ptr[*pc + 1] & 0x0F; 531 | reg_idx_vy = (ptr[*pc + 1] >> 4) & 0x0F; 532 | reg_idx_vz = reg_idx_vy + 1; 533 | 534 | load_reg_to_double(vm, reg_idx_vy , ptr_d + 4); 535 | load_reg_to_double(vm, reg_idx_vz , ptr_d); 536 | 537 | i = (int)d; 538 | if (is_verbose()) { 539 | printf("double-to-int v%d, v%d\n", reg_idx_vx, reg_idx_vy); 540 | printf("(%f) to (%d) \n", d , i); 541 | } 542 | 543 | store_to_reg(vm, reg_idx_vx, (unsigned char *) &i); 544 | *pc = *pc + 2; 545 | return 0; 546 | } 547 | 548 | /* 0xb0 add-int/2addr vx,vy 549 | * Adds vy to vx. 550 | * B010 - add-int/2addr v0,v1 Adds v1 to v0. 551 | */ 552 | static int op_add_int_2addr(DexFileFormat *dex, simple_dalvik_vm *vm, u1 *ptr, int *pc) 553 | { 554 | int reg_idx_vx = 0; 555 | int reg_idx_vy = 0; 556 | int x = 0, y = 0; 557 | reg_idx_vx = ptr[*pc + 1] & 0x0F ; 558 | reg_idx_vy = (ptr[*pc + 1] >> 4) & 0x0F ; 559 | if (is_verbose()) 560 | printf("add-int/2addr v%d, v%d\n", reg_idx_vx, reg_idx_vy); 561 | load_reg_to(vm, reg_idx_vx, (unsigned char *) &x); 562 | load_reg_to(vm, reg_idx_vy, (unsigned char *) &y); 563 | x = x + y; 564 | store_to_reg(vm, reg_idx_vx, (unsigned char *) &x); 565 | 566 | *pc = *pc + 2; 567 | return 0; 568 | } 569 | 570 | /* 0xcb , add-double/2addr 571 | * Adds vy to vx. 572 | * CB70 - add-double/2addr v0, v7 573 | * Adds v7 to v0. 574 | */ 575 | static int op_add_double_2addr(DexFileFormat *dex, simple_dalvik_vm *vm, u1 *ptr, int *pc) 576 | { 577 | int reg_idx_vx = 0; 578 | int reg_idx_vy = 0; 579 | double x = 0.0, y = 0.0; 580 | unsigned char *ptr_x = (unsigned char *) &x; 581 | unsigned char *ptr_y = (unsigned char *) &y; 582 | reg_idx_vx = ptr[*pc + 1] & 0x0F; 583 | reg_idx_vy = (ptr[*pc + 1] >> 4) & 0x0F; 584 | 585 | load_reg_to_double(vm, reg_idx_vx, ptr_x + 4); 586 | load_reg_to_double(vm, reg_idx_vx + 1, ptr_x); 587 | load_reg_to_double(vm, reg_idx_vy, ptr_y + 4); 588 | load_reg_to_double(vm, reg_idx_vy + 1, ptr_y); 589 | 590 | 591 | if (is_verbose()) { 592 | printf("add-double/2addr v%d, v%d\n", reg_idx_vx, reg_idx_vy); 593 | printf("%f(%llx) + %f(%llx) = %f\n", x, x, y, y , y + x); 594 | } 595 | x = x + y; 596 | store_double_to_reg(vm, reg_idx_vx, ptr_x + 4); 597 | store_double_to_reg(vm, reg_idx_vx + 1, ptr_x); 598 | *pc = *pc + 2; 599 | return 0; 600 | } 601 | 602 | /* 0xcd , mul-double/2addr 603 | * Multiplies vx with vy 604 | * CD20 - mul-double/2addr v0, v2 605 | * Multiplies the double value in v0,v1 with the 606 | * double value in v2,v3 and puts the result into v0,v1. 607 | */ 608 | static int op_mul_double_2addr(DexFileFormat *dex, simple_dalvik_vm *vm, u1 *ptr, int *pc) 609 | { 610 | int reg_idx_vx = 0; 611 | int reg_idx_vy = 0; 612 | int reg_idx_vz = 0; 613 | int reg_idx_vw = 0; 614 | double x = 0.0, y = 0.0; 615 | unsigned char *ptr_x = (unsigned char *) &x; 616 | unsigned char *ptr_y = (unsigned char *) &y; 617 | 618 | reg_idx_vx = ptr[*pc + 1] & 0x0F; 619 | reg_idx_vy = reg_idx_vx + 1; 620 | reg_idx_vz = (ptr[*pc + 1] >> 4) & 0x0F; 621 | reg_idx_vw = reg_idx_vz + 1 ; 622 | 623 | load_reg_to_double(vm, reg_idx_vx, ptr_x + 4); 624 | load_reg_to_double(vm, reg_idx_vy, ptr_x); 625 | 626 | load_reg_to_double(vm, reg_idx_vz, ptr_y + 4); 627 | load_reg_to_double(vm, reg_idx_vw, ptr_y); 628 | 629 | if (is_verbose()) { 630 | printf("mul-double/2addr v%d, v%d\n", reg_idx_vx, reg_idx_vz); 631 | printf(" %f * %f = %f\n", x, y, x * y); 632 | } 633 | 634 | x = x * y; 635 | 636 | store_double_to_reg(vm, reg_idx_vx, ptr_x + 4); 637 | store_double_to_reg(vm, reg_idx_vy, ptr_x); 638 | 639 | load_reg_to_double(vm, reg_idx_vx, ptr_y + 4); 640 | load_reg_to_double(vm, reg_idx_vy, ptr_y); 641 | 642 | *pc = *pc + 2; 643 | return 0; 644 | } 645 | 646 | /* 0xdb div-int/lit8 vx,vy,lit8 647 | * Calculates vy/lit8 and stores the result into vx. 648 | * DB00 0203 - div-int/lit8 v0,v2, #int3 649 | * Calculates v2/3 and stores the result into v0. 650 | */ 651 | static int op_div_int_lit8(DexFileFormat *dex, simple_dalvik_vm *vm, u1 *ptr, int *pc) 652 | { 653 | int reg_idx_vx = 0; 654 | int reg_idx_vy = 0; 655 | int x = 0, y = 0 ; 656 | int z = 0; 657 | reg_idx_vx = ptr[*pc + 1]; 658 | reg_idx_vy = ptr[*pc + 2]; 659 | z = ptr[*pc + 3]; 660 | 661 | if (is_verbose()) 662 | printf("add-int v%d, v%d, #int%d\n", reg_idx_vx, reg_idx_vy, z); 663 | /* x = y + z */ 664 | load_reg_to(vm, reg_idx_vy, (unsigned char *) &y); 665 | x = y % z; 666 | x = (y - x) / z; 667 | store_to_reg(vm, reg_idx_vx, (unsigned char *) &x); 668 | 669 | *pc = *pc + 4; 670 | return 0; 671 | } 672 | 673 | static byteCode byteCodes[] = { 674 | { "move-result-wide" , 0x0B, 2, op_move_result_wide }, 675 | { "move-result-object", 0x0C, 2, op_move_result_object }, 676 | { "return-void" , 0x0e, 2, op_return_void }, 677 | { "const/4" , 0x12, 2, op_const_4 }, 678 | { "const/16" , 0x13, 4, op_const_16 }, 679 | { "const-wide/high16" , 0x19, 4, op_const_wide_high16 }, 680 | { "const-string" , 0x1a, 4, op_const_string }, 681 | { "new-instance" , 0x22, 4, op_new_instance }, 682 | { "sget-object" , 0x62, 4, op_sget_object }, 683 | { "invoke-virtual" , 0x6e, 6, op_invoke_virtual }, 684 | { "invoke-direct" , 0x70, 6, op_invoke_direct }, 685 | { "invoke-static" , 0x71, 6, op_invoke_static }, 686 | { "double-to-int" , 0x8a, 2, op_double_to_int}, 687 | { "add-int" , 0x90, 4, op_add_int }, 688 | { "sub-int" , 0x91, 4, op_sub_int }, 689 | { "mul-int" , 0x92, 4, op_mul_int }, 690 | { "div-int" , 0x93, 4, op_div_int }, 691 | { "add-int/2addr" , 0xb0, 2, op_add_int_2addr}, 692 | { "add-double/2addr" , 0xcb, 2, op_add_double_2addr}, 693 | { "mul-double/2addr" , 0xcd, 2, op_mul_double_2addr}, 694 | { "div-int/lit8" , 0xdb, 4, op_div_int_lit8 } 695 | }; 696 | static byteCode_size = sizeof(byteCodes) / sizeof(byteCode); 697 | 698 | static opCodeFunc findOpCodeFunc(unsigned char op) 699 | { 700 | int i = 0; 701 | for (i = 0; i < byteCode_size; i++) 702 | if (op == byteCodes[i].opCode) 703 | return byteCodes[i].func; 704 | return 0; 705 | } 706 | 707 | void runMethod(DexFileFormat *dex, simple_dalvik_vm *vm, encoded_method *m) 708 | { 709 | u1 *ptr = (u1 *) m->code_item.insns; 710 | unsigned char opCode = 0; 711 | opCodeFunc func = 0; 712 | 713 | vm->pc = 0; 714 | while (1) { 715 | if (vm->pc >= m->code_item.insns_size * sizeof(ushort)) 716 | break; 717 | opCode = ptr[vm->pc]; 718 | func = findOpCodeFunc(opCode); 719 | if (func != 0) { 720 | func(dex, vm, ptr, &vm->pc); 721 | } else { 722 | printRegs(vm); 723 | printf("Unknow OpCode =%02x \n", opCode); 724 | break; 725 | } 726 | } 727 | } 728 | 729 | void simple_dvm_startup(DexFileFormat *dex, simple_dalvik_vm *vm, char *entry) 730 | { 731 | int i = 0; 732 | int method_name_idx = -1; 733 | int method_idx = -1; 734 | int class_idx = -1; 735 | 736 | method_name_idx = find_const_string(dex, entry); 737 | 738 | if (method_name_idx < 0) { 739 | printf("no method %s in dex\n", entry); 740 | return; 741 | } 742 | for (i = 0 ; i < dex->header.methodIdsSize; i++) 743 | if (dex->method_id_item[i].name_idx == method_name_idx) { 744 | if (is_verbose() > 2) 745 | printf("find %s in class_idx[%d], method_id = %d\n", 746 | entry, i - 1, i); 747 | class_idx = i - 1; 748 | method_idx = i; 749 | break; 750 | } 751 | if (class_idx < 0 || method_idx < 0) { 752 | printf("no method %s in dex\n", entry); 753 | return; 754 | } 755 | 756 | encoded_method *m = 757 | &dex->class_data_item[class_idx].direct_methods[method_idx]; 758 | 759 | if (is_verbose() > 2) 760 | printf("encoded_method method_id = %d, insns_size = %d\n", 761 | m->method_idx_diff, m->code_item.insns_size); 762 | 763 | memset(vm , 0, sizeof(simple_dalvik_vm)); 764 | runMethod(dex, vm, m); 765 | } 766 | -------------------------------------------------------------------------------- /simple_dvm/class_def_parser.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Dalvik Virtual Machine Implementation 3 | * 4 | * Copyright (C) 2013 Chun-Yu Wang 5 | */ 6 | 7 | #include "simple_dvm.h" 8 | 9 | static void parse_encoded_method(DexFileFormat *dex, 10 | unsigned char *buf, encoded_method *method) 11 | { 12 | int i = 0; 13 | int offset = 0; 14 | 15 | if (is_verbose() > 3) 16 | printf("parse encoded method\n"); 17 | offset = method->code_off - sizeof(DexHeader); 18 | 19 | memcpy(&method->code_item.registers_size, buf + offset, sizeof(ushort)); 20 | offset += sizeof(ushort); 21 | memcpy(&method->code_item.ins_size, buf + offset, sizeof(ushort)); 22 | offset += sizeof(ushort); 23 | memcpy(&method->code_item.outs_size, buf + offset, sizeof(ushort)); 24 | offset += sizeof(ushort); 25 | memcpy(&method->code_item.tries_size, buf + offset, sizeof(ushort)); 26 | offset += sizeof(ushort); 27 | memcpy(&method->code_item.debug_info_off, buf + offset, sizeof(uint)); 28 | offset += sizeof(uint); 29 | memcpy(&method->code_item.insns_size, buf + offset, sizeof(uint)); 30 | offset += sizeof(uint); 31 | 32 | if (is_verbose() > 3) { 33 | printf("registers_size = %d\n", method->code_item.registers_size); 34 | printf("insns_size = %d\n", method->code_item.insns_size); 35 | } 36 | method->code_item.insns = malloc(sizeof(ushort) * method->code_item.insns_size); 37 | memcpy(method->code_item.insns, buf + offset, 38 | sizeof(ushort) * method->code_item.insns_size); 39 | offset += sizeof(ushort) * method->code_item.insns_size; 40 | } 41 | 42 | static void parse_class_data_item(DexFileFormat *dex, 43 | unsigned char *buf, int offset, int index) 44 | { 45 | int i = 0; 46 | int j = 0; 47 | int size = 0; 48 | int len = 0; 49 | i = offset; 50 | 51 | dex->class_data_item[index].static_fields_size = 52 | get_uleb128_len(buf, i, &size); 53 | i += size; 54 | 55 | dex->class_data_item[index].instance_fields_size = 56 | get_uleb128_len(buf, i, &size); 57 | i += size; 58 | 59 | dex->class_data_item[index].direct_methods_size = 60 | get_uleb128_len(buf, i, &size); 61 | i += size; 62 | 63 | dex->class_data_item[index].virtual_methods_size = 64 | get_uleb128_len(buf, i, &size); 65 | i += size; 66 | 67 | if (is_verbose() > 3) { 68 | printf(" class_data_item[%d]", index); 69 | printf(" , static_fields_size = %d\n", 70 | dex->class_data_item[index].static_fields_size); 71 | printf(" , instance_fields_size = %d\n", 72 | dex->class_data_item[index].instance_fields_size); 73 | printf(" , direct_method_size = %d\n", 74 | dex->class_data_item[index].direct_methods_size); 75 | printf(" , direct_method_size = %d\n", 76 | dex->class_data_item[index].virtual_methods_size); 77 | printf("i = %d\n", i); 78 | } 79 | if (dex->class_data_item[index].static_fields_size > 0) { 80 | } 81 | if (dex->class_data_item[index].instance_fields_size > 0) { 82 | } 83 | if (dex->class_data_item[index].direct_methods_size > 0) { 84 | dex->class_data_item[index].direct_methods = (encoded_method *) 85 | malloc(sizeof(encoded_method) * 86 | dex->class_data_item[index].direct_methods_size); 87 | for (j = 0; j < dex->class_data_item[index].direct_methods_size; j++) { 88 | if (is_verbose() > 3) 89 | printf("offset = %04x ", i + sizeof(DexHeader)); 90 | dex->class_data_item[index].direct_methods[j].method_idx_diff = 91 | get_uleb128_len(buf, i, &size); 92 | i += size; 93 | dex->class_data_item[index].direct_methods[j].access_flags = 94 | get_uleb128_len(buf, i, &size); 95 | i += size; 96 | dex->class_data_item[index].direct_methods[j].code_off = 97 | get_uleb128_len(buf, i, &size); 98 | i += size; 99 | 100 | if (is_verbose() > 3) 101 | printf("ecoded_method, method_id = %d, access_flag = %04x, code_off = %04x\n", 102 | dex->class_data_item[index].direct_methods[j].method_idx_diff, 103 | dex->class_data_item[index].direct_methods[j].access_flags, 104 | dex->class_data_item[index].direct_methods[j].code_off); 105 | 106 | parse_encoded_method(dex, buf, 107 | &dex->class_data_item[index].direct_methods[j]); 108 | } 109 | 110 | } 111 | if (dex->class_data_item[index].virtual_methods_size > 0) { 112 | } 113 | } 114 | 115 | void parse_class_defs(DexFileFormat *dex, unsigned char *buf, int offset) 116 | { 117 | int i = 0; 118 | if (is_verbose() > 3) 119 | printf("parse class defs offset = %04x\n", offset + sizeof(DexHeader)); 120 | if (dex->header.classDefsSize <= 0) 121 | return; 122 | dex->class_def_item = malloc( 123 | sizeof(class_def_item) * dex->header.classDefsSize); 124 | dex->class_data_item = malloc( 125 | sizeof(class_data_item) * dex->header.classDefsSize); 126 | 127 | for (i = 0 ; i < dex->header.classDefsSize; i++) { 128 | memcpy(&dex->class_def_item[i], 129 | buf + i * sizeof(class_def_item) + offset, 130 | sizeof(class_def_item)); 131 | if (is_verbose() > 3) { 132 | printf(" class_defs[%d], cls_id = %d, data_off = 0x%04x, source_file_idx = %d\n", 133 | i, 134 | dex->class_def_item[i].class_idx, 135 | dex->class_def_item[i].class_data_off, 136 | dex->class_def_item[i].source_file_idx); 137 | } 138 | parse_class_data_item(dex, buf, 139 | dex->class_def_item[i].class_data_off - sizeof(DexHeader), i); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /simple_dvm/dex_parser.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Dalvik Virtual Machine Implementation 3 | * 4 | * Copyright (C) 2013 Chun-Yu Wang 5 | */ 6 | 7 | #include "simple_dvm.h" 8 | 9 | /* Print Dex File Format */ 10 | static void printDexHeader(DexHeader *dex) 11 | { 12 | int i = 0; 13 | printf("Magic Number = "); 14 | for (i = 0 ; i < 8 ; i++) 15 | printf("0x%02x ", dex->magic[i]); 16 | printf("( "); 17 | for (i = 0 ; i < 8 ; i++) 18 | if (dex->magic[i] != '\n') { 19 | printf("%c", dex->magic[i]); 20 | } else { 21 | printf("\\n"); 22 | } 23 | printf(" )\n"); 24 | 25 | printf("Checksum = "); 26 | for (i = 3 ; i >= 0 ; i--) 27 | printf("%02x ", dex->checksum[i]); 28 | printf("\n"); 29 | 30 | printf("FileSize = %4d (0x%04x)\n", dex->fileSize, dex->fileSize); 31 | printf("headerSize = %4d (0x%04x)\n", dex->headerSize, dex->headerSize); 32 | printf("endianTag = %4d (0x%04x)\n", dex->endianTag, dex->endianTag); 33 | printf("linkSize = %4d (0x%04x)\n", dex->linkSize, dex->linkSize); 34 | printf("mapOff = %4d (0x%04x)\n", dex->mapOff, dex->mapOff); 35 | printf("stringIdsSize = %4d (0x%04x)\n", dex->stringIdsSize, dex->stringIdsSize); 36 | printf("stringIdsOff = %4d (0x%04x)\n", dex->stringIdsOff, dex->stringIdsOff); 37 | printf("typeIdsSize = %4d (0x%04x)\n", dex->typeIdsSize, dex->typeIdsSize); 38 | printf("typeIdsOff = %4d (0x%04x)\n", dex->typeIdsOff, dex->typeIdsOff); 39 | printf("protoIdsSize = %4d (0x%04x)\n", dex->protoIdsSize, dex->protoIdsSize); 40 | printf("protoIdsOff = %4d (0x%04x)\n", dex->protoIdsOff, dex->protoIdsOff); 41 | printf("fieldIdsSize = %4d (0x%04x)\n", dex->fieldIdsSize, dex->fieldIdsSize); 42 | printf("fieldIdsOff = %4d (0x%04x)\n", dex->fieldIdsOff, dex->fieldIdsOff); 43 | printf("methodIdsSize = %4d (0x%04x)\n", dex->methodIdsSize, dex->methodIdsSize); 44 | printf("methodIdsOff = %4d (0x%04x)\n", dex->methodIdsOff, dex->methodIdsOff); 45 | printf("classDefsSize = %4d (0x%04x)\n", dex->classDefsSize, dex->classDefsSize); 46 | printf("classDefsOff = %4d (0x%04x)\n", dex->classDefsOff, dex->classDefsOff); 47 | printf("dataSize = %4d (0x%04x)\n", dex->dataSize, dex->dataSize); 48 | printf("dataOff = %4d (0x%04x)\n", dex->dataOff, dex->dataOff); 49 | } 50 | 51 | void printDexFile(DexFileFormat *dex) 52 | { 53 | printDexHeader(&dex->header); 54 | } 55 | 56 | /* Parse Dex File */ 57 | int parseDexFile(char *file, DexFileFormat *dex) 58 | { 59 | FILE *fp = 0; 60 | unsigned char *buf = 0; 61 | 62 | fp = fopen(file, "rb"); 63 | if (fp == 0) { 64 | printf("Open file %s failed\n", file); 65 | return -1; 66 | } 67 | memset(dex, 0, sizeof(dex)); 68 | fread(&dex->header, sizeof(DexHeader), 1, fp); 69 | buf = (unsigned char *) malloc( 70 | sizeof(u1) * (dex->header.fileSize - sizeof(DexHeader))); 71 | 72 | /* read all value into buf */ 73 | fread(buf, (dex->header.fileSize - sizeof(DexHeader)), 1, fp); 74 | fclose(fp); 75 | 76 | parse_map_list(dex, buf, dex->header.mapOff - sizeof(DexHeader)); 77 | parse_string_ids(dex, buf, dex->header.stringIdsOff - sizeof(DexHeader)); 78 | parse_type_ids(dex, buf, dex->header.typeIdsOff - sizeof(DexHeader)); 79 | parse_proto_ids(dex, buf, dex->header.protoIdsOff - sizeof(DexHeader)); 80 | parse_field_ids(dex, buf, dex->header.fieldIdsOff - sizeof(DexHeader)); 81 | parse_method_ids(dex, buf, dex->header.methodIdsOff - sizeof(DexHeader)); 82 | parse_class_defs(dex, buf, dex->header.classDefsOff - sizeof(DexHeader)); 83 | 84 | if (dex->header.dataSize > 0) { 85 | dex->data = malloc(sizeof(u1) * dex->header.dataSize); 86 | memcpy(dex->data, buf, dex->header.dataOff - sizeof(DexHeader)); 87 | } 88 | 89 | free(buf); 90 | return 0; 91 | } 92 | -------------------------------------------------------------------------------- /simple_dvm/java_lib.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Dalvik Virtual Machine Implementation 3 | * 4 | * Copyright (C) 2013 Chun-Yu Wang 5 | */ 6 | 7 | #include "java_lib.h" 8 | 9 | int java_lang_math_random(DexFileFormat *dex, simple_dalvik_vm *vm, char *type) 10 | { 11 | double r = 0.0f; 12 | double test = 0.0f; 13 | int i = 0; 14 | int times = 0; 15 | srand(time(0)); 16 | times = rand() % 100; 17 | for (i = 0; i < times; i++) 18 | r = ((double) rand() / (double) RAND_MAX); 19 | 20 | if (is_verbose() > 3) printf("get random number = %f \n", r); 21 | store_double_to_result(vm, (unsigned char *) &r); 22 | load_result_to_double(vm, (unsigned char *) &test); 23 | 24 | return 0; 25 | } 26 | 27 | /* java.io.PrintStream.println */ 28 | static char buf[1024]; 29 | static int buf_ptr = 0; 30 | static int use_buf = 0; 31 | int java_io_print_stream_println(DexFileFormat *dex, simple_dalvik_vm *vm, char *type) 32 | { 33 | invoke_parameters *p = &vm->p; 34 | int i = 0; 35 | int string_id = 0; 36 | if (is_verbose()) 37 | printf("call java.io.PrintStream.println\n"); 38 | 39 | load_reg_to(vm, p->reg_idx[1], (unsigned char *) &string_id); 40 | if (use_buf == 1) { 41 | printf("%s\n", buf); 42 | use_buf = 0; 43 | memset(buf, 0, 1024); 44 | buf_ptr = 0; 45 | } else { 46 | printf("%s\n", get_string_data(dex, string_id)); 47 | } 48 | return 0; 49 | } 50 | 51 | /* java.lang.StringBuilder. */ 52 | int java_lang_string_builder_init(DexFileFormat *dex, simple_dalvik_vm *vm, char *type) 53 | { 54 | invoke_parameters *p = &vm->p; 55 | if (is_verbose()) 56 | printf("call java.lang.StringBuilder.\n"); 57 | memset(buf, 0, 1024); 58 | buf_ptr = 0; 59 | return 0; 60 | } 61 | 62 | int java_lang_string_builder_append(DexFileFormat *dex, simple_dalvik_vm *vm, char *type) 63 | { 64 | invoke_parameters *p = &vm->p; 65 | int string_id = 0; 66 | if (is_verbose()) 67 | printf("call java.lang.StringBuilder.append\n"); 68 | load_reg_to(vm, p->reg_idx[1], (unsigned char *) &string_id); 69 | if (type != 0) { 70 | if (strcmp(type, "Ljava/lang/String;") == 0) { 71 | buf_ptr += snprintf(buf + buf_ptr, 1024, "%s", get_string_data(dex, string_id)); 72 | } else if (strcmp(type, "I") == 0) { 73 | buf_ptr += snprintf(buf + buf_ptr, 1024, "%d", string_id); 74 | } 75 | } 76 | return 0; 77 | } 78 | 79 | int java_lang_string_builder_to_string(DexFileFormat *dex, simple_dalvik_vm *vm, char *type) 80 | { 81 | invoke_parameters *p = &vm->p; 82 | if (is_verbose()) 83 | printf("call java.lang.StringBuilder.toString\n"); 84 | use_buf = 1; 85 | return 0; 86 | } 87 | 88 | static java_lang_method method_table[] = { 89 | {"Ljava/lang/Math;", "random", java_lang_math_random}, 90 | {"Ljava/io/PrintStream;", "println", java_io_print_stream_println}, 91 | {"Ljava/lang/StringBuilder;", "", java_lang_string_builder_init}, 92 | {"Ljava/lang/StringBuilder;", "append", java_lang_string_builder_append}, 93 | {"Ljava/lang/StringBuilder;", "toString", java_lang_string_builder_to_string} 94 | }; 95 | 96 | static int java_lang_method_size = sizeof(method_table) / sizeof(java_lang_method); 97 | 98 | java_lang_method *find_java_lang_method(char *cls_name, char *method_name) 99 | { 100 | int i = 0; 101 | for (i = 0; i < java_lang_method_size; i++) 102 | if (strcmp(cls_name, method_table[i].clzname) == 0 && 103 | strcmp(method_name, method_table[i].methodname) == 0) 104 | return &method_table[i]; 105 | return 0; 106 | } 107 | 108 | int invoke_java_lang_library(DexFileFormat *dex, simple_dalvik_vm *vm, 109 | char *cls_name, char *method_name, char *type) 110 | { 111 | java_lang_method *method = find_java_lang_method(cls_name, method_name); 112 | if (method != 0) { 113 | if (is_verbose()) 114 | printf("invoke %s/%s %s\n", method->clzname, method->methodname, type); 115 | method->method_runtime(dex, vm, type); 116 | return 1; 117 | } 118 | return 0; 119 | } 120 | -------------------------------------------------------------------------------- /simple_dvm/java_lib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Dalvik Virtual Machine Implementation 3 | * 4 | * Copyright (C) 2013 Chun-Yu Wang 5 | */ 6 | 7 | #ifndef SIMPLE_DVM_JAVA_LIBRARY_H 8 | #define SIMPLE_DVM_JAVA_LIBRARY_H 9 | 10 | #include "simple_dvm.h" 11 | 12 | typedef int (*java_lang_lib)(DexFileFormat *dex, simple_dalvik_vm *vm, char*type); 13 | 14 | typedef struct _java_lang_method { 15 | char *clzname; 16 | char *methodname; 17 | java_lang_lib method_runtime; 18 | } java_lang_method; 19 | 20 | int invoke_java_lang_library(DexFileFormat *dex, simple_dalvik_vm *vm, 21 | char *cls_name, char *method_name, char *type); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /simple_dvm/leb128.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Dalvik Virtual Machine Implementation 3 | * 4 | * Copyright (C) 2013 Chun-Yu Wang 5 | */ 6 | 7 | #include "simple_dvm.h" 8 | 9 | /* get string ids 10 | * little endian 11 | * 0b0xxxxxxx 12 | * 0b1xxxxxxx 13 | */ 14 | int get_uleb128_len(unsigned char *buf, int offset, int *size) 15 | { 16 | int len = 0; 17 | int i = offset; 18 | unsigned char value = 0; 19 | int j = 0; 20 | do { 21 | value = buf[i]; 22 | i++; 23 | if ((value & 0x80) != 0) { 24 | len = (len | (value ^ 0x80) << (j * 7)); 25 | } else { 26 | len = (len | value << j * 7); 27 | break; 28 | } 29 | j++; 30 | } while (1); 31 | *size = i - offset; 32 | return len; 33 | } 34 | -------------------------------------------------------------------------------- /simple_dvm/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Dalvik Virtual Machine Implementation 3 | * 4 | * Copyright (C) 2013 Chun-Yu Wang 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include "simple_dvm.h" 11 | 12 | int main(int argc, char *argv[]) 13 | { 14 | DexFileFormat dex; 15 | simple_dalvik_vm vm; 16 | int x = 0; 17 | 18 | memset(&dex, 0, sizeof(DexFileFormat)); 19 | if (argc < 2) { 20 | printf("%s [dex_file] \n", argv[0]); 21 | return 0; 22 | } 23 | if (argc >= 3) 24 | set_verbose(atoi(argv[2])); 25 | parseDexFile(argv[1], &dex); 26 | if (is_verbose() > 3) printDexFile(&dex); 27 | simple_dvm_startup(&dex, &vm, "main"); 28 | 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /simple_dvm/map_list_parser.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Dalvik Virtual Machine Implementation 3 | * 4 | * Copyright (C) 2013 Chun-Yu Wang 5 | */ 6 | 7 | #include "simple_dvm.h" 8 | 9 | static char *map_item_type_name_00[7] = { 10 | "TYPE_HEADER_ITEM", 11 | "TYPE_STRING_ID_ITEM", 12 | "TYPE_TYPE_ID_ITEM", 13 | "TYPE_PROTO_ID_ITEM", 14 | "TYPE_FIELD_ID_ITEM", 15 | "TYPE_METHOD_ID_ITEM", 16 | "TYPE_CLASS_DEF_ITEM" 17 | }; 18 | 19 | static char *map_item_type_name_10[4] = { 20 | "TYPE_MAP_LIST", 21 | "TYPE_TYPE_LIST", 22 | "TYPE_ANNOTATION_SET_REF_LIST", 23 | "TYPE_ANNOTATION_SET_ITEM" 24 | }; 25 | 26 | static char *map_item_type_name_20[7] = { 27 | "TYPE_CLASS_DATA_ITEM", 28 | "TYPE_CODE_ITEM", 29 | "TYPE_STRING_DATA_ITEM", 30 | "TYPE_DEBUG_INFO_ITEM", 31 | "TYPE_ANNOTATION_ITEM", 32 | "TYPE_ENCODED_ARRAY_ITEM", 33 | "TYPE_ANNOTATIONS_DIRECTORY_ITEM" 34 | }; 35 | 36 | static char *get_map_item_type_name(int type_id) 37 | { 38 | int table = 0; 39 | int value = 0; 40 | 41 | table = (type_id >> 8) & 0xFF; 42 | value = type_id & 0xFF; 43 | if (table == 0x00 && value >= 0 && value <= 6) { 44 | return map_item_type_name_00[value]; 45 | } else if (table == 0x10 && value >= 0 && value <= 3) { 46 | return map_item_type_name_10[value]; 47 | } else if (table == 0x20 && value >= 0 && value <= 6) { 48 | return map_item_type_name_20[value]; 49 | } 50 | return 0; 51 | } 52 | 53 | /* Parse type list */ 54 | static void parse_type_list(DexFileFormat *dex, 55 | unsigned char *buf, int offset) 56 | { 57 | int i = 0; 58 | if (is_verbose() > 3) 59 | printf("parse type_list offset = %04x\n", offset + sizeof(DexHeader)); 60 | memcpy(&dex->type_list.size , buf + offset, 4); 61 | if (is_verbose() > 3) 62 | printf("type_list size = %d\n", dex->type_list.size); 63 | if (dex->type_list.size > 0) { 64 | dex->type_list.type_item = malloc(sizeof(type_item) * dex->type_list.size); 65 | for (i = 0 ; i < dex->type_list.size; i++) { 66 | memcpy(&dex->type_list.type_item[i], 67 | buf + offset + 4 + (sizeof(type_item) * i), 68 | sizeof(type_item)); 69 | if (is_verbose() > 3) 70 | printf("type_list[%d], type_idx = %d\n", i, 71 | dex->type_list.type_item[i].type_idx); 72 | } 73 | } 74 | } 75 | 76 | /* Parse Map Item */ 77 | static void parse_map_item(DexFileFormat *dex, 78 | unsigned char *buf, int offset, int index) 79 | { 80 | int size_in_bytes = 0; 81 | memcpy(&dex->map_list.map_item[index], buf + offset, sizeof(map_item)); 82 | size_in_bytes = 4 + (dex->map_list.map_item[index].size * 2); 83 | if (is_verbose() > 3) { 84 | printf("offset = %04x ", offset + sizeof(DexHeader)); 85 | printf("map_item[%d] : type = %04x(%s), size = %04x, " 86 | "offset = 0x%04x, item_size_in_byte = %d\n", 87 | index, 88 | dex->map_list.map_item[index].type, 89 | get_map_item_type_name(dex->map_list.map_item[index].type), 90 | dex->map_list.map_item[index].size, 91 | dex->map_list.map_item[index].offset, 92 | size_in_bytes); 93 | } 94 | if (dex->map_list.map_item[index].type == 0x1001) /* TYPE_TYPE_LIST */ 95 | parse_type_list(dex, buf, 96 | dex->map_list.map_item[index].offset - sizeof(DexHeader)); 97 | } 98 | 99 | /* Parse Map list */ 100 | void parse_map_list(DexFileFormat *dex, unsigned char *buf, int offset) 101 | { 102 | int i = 0; 103 | if (is_verbose() > 3) 104 | printf("parse map_list offset = %04x\n", offset + sizeof(DexHeader)); 105 | memcpy(&dex->map_list.size , buf + offset, 4); 106 | if (is_verbose() > 3) 107 | printf("map_list size = %d\n", dex->map_list.size); 108 | if (dex->map_list.size > 0) { 109 | dex->map_list.map_item = malloc(sizeof(map_item) * dex->map_list.size); 110 | for (i = 0 ; i < dex->map_list.size; i++) 111 | parse_map_item(dex, buf, offset + 4 + (sizeof(map_item) * i), i); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /simple_dvm/method_ids_parser.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Dalvik Virtual Machine Implementation 3 | * 4 | * Copyright (C) 2013 Chun-Yu Wang 5 | */ 6 | 7 | #include "simple_dvm.h" 8 | 9 | void parse_method_ids(DexFileFormat *dex, unsigned char *buf, int offset) 10 | { 11 | int i = 0; 12 | if (is_verbose() > 3) 13 | printf("parse method ids offset = %04x\n", offset + sizeof(DexHeader)); 14 | dex->method_id_item = malloc( 15 | sizeof(method_id_item) * dex->header.methodIdsSize); 16 | 17 | for (i = 0 ; i < dex->header.methodIdsSize ; i++) { 18 | memcpy(&dex->method_id_item[i], 19 | buf + i * sizeof(method_id_item) + offset, 20 | sizeof(method_id_item)); 21 | 22 | if (is_verbose() > 3) 23 | printf(" method[%d], cls_id = %d, proto_id = %d, name_id = %d, %s\n", 24 | i, 25 | dex->method_id_item[i].class_idx, 26 | dex->method_id_item[i].proto_idx, 27 | dex->method_id_item[i].name_idx, 28 | dex->string_data_item[dex->method_id_item[i].name_idx].data); 29 | } 30 | } 31 | 32 | method_id_item *get_method_item(DexFileFormat *dex, int method_id) 33 | { 34 | if (method_id >= 0 && method_id < dex->header.methodIdsSize) 35 | return &dex->method_id_item[method_id]; 36 | return 0; 37 | } 38 | 39 | int get_method_name(DexFileFormat *dex, int method_id, char *name) 40 | { 41 | method_id_item *m = get_method_item(dex, method_id); 42 | type_id_item *type_class = 0; 43 | proto_id_item *proto_item = 0; 44 | char *method_name = 0; 45 | char *class_name = 0; 46 | if (m != 0) { 47 | method_name = get_string_data(dex, m->name_idx); 48 | type_class = get_type_item(dex, m->class_idx); 49 | if (type_class != 0) 50 | class_name = get_string_data(dex, type_class->descriptor_idx); 51 | proto_item = get_proto_item(dex, m->proto_idx); 52 | } 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /simple_dvm/simple_dvm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Dalvik Virtual Machine Implementation 3 | * 4 | * Copyright (C) 2013 Chun-Yu Wang 5 | */ 6 | 7 | #ifndef SIMPLE_DVM_H 8 | #define SIMPLE_DVM_H 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | typedef short u2; 15 | typedef unsigned int u4; 16 | typedef unsigned int uint; 17 | typedef unsigned char u1; 18 | typedef unsigned short ushort; 19 | typedef unsigned char byte; 20 | 21 | /* map_list */ 22 | typedef struct _map_item { 23 | ushort type; 24 | ushort unused; 25 | uint size; 26 | uint offset; 27 | } map_item; 28 | typedef struct _map_list { 29 | uint size ; 30 | map_item *map_item; 31 | } map_list; 32 | 33 | typedef struct _type_item { 34 | ushort type_idx; 35 | } type_item; 36 | typedef struct _type_list { 37 | uint size ; 38 | type_item *type_item; 39 | } type_list; 40 | 41 | /* string_ids */ 42 | typedef struct _string_data_item { 43 | int index; 44 | int uleb128_len; 45 | u1 data[255]; 46 | } string_data_item; 47 | 48 | typedef struct _string_ids { 49 | u4 string_data_off; 50 | } string_ids; 51 | 52 | /* type_ids */ 53 | typedef struct _type_id_item { 54 | uint descriptor_idx; 55 | } type_id_item; 56 | 57 | /* proto_ids */ 58 | typedef struct _proto_id_item { 59 | uint shorty_idx; /* pointer to string_data_item */ 60 | uint return_type_idx; /* pointer to type_ids */ 61 | uint parameters_off; 62 | } proto_id_item; 63 | 64 | /* field_ids */ 65 | typedef struct _field_id_item { 66 | ushort class_idx; /* index into the type_ids list for the definer of this field */ 67 | ushort type_idx; 68 | uint name_idx; 69 | } field_id_item; 70 | 71 | /* method_ids */ 72 | typedef struct _method_id_tiem { 73 | ushort class_idx; /* index into the type_ids list for the definer of this method */ 74 | ushort proto_idx; /* index into the proto_ids list for the prototype of this method */ 75 | uint name_idx; 76 | } method_id_item; 77 | 78 | /* class defs */ 79 | typedef struct _code_item { 80 | ushort registers_size; 81 | ushort ins_size; 82 | ushort outs_size; 83 | ushort tries_size; 84 | uint debug_info_off; 85 | uint insns_size; 86 | ushort *insns; 87 | /* 88 | ushort padding; 89 | try_item 90 | handlers 91 | */ 92 | } code_item; 93 | 94 | typedef struct _encoded_method { 95 | uint method_idx_diff; 96 | uint access_flags; 97 | uint code_off; 98 | code_item code_item; 99 | } encoded_method; 100 | 101 | typedef struct _class_def_item { 102 | uint class_idx; 103 | uint access_flags; 104 | uint superclass_idx; /* index into typeIds for superclass */ 105 | uint interfaces_off; /* file offset to DexTypeList */ 106 | uint source_file_idx; /* index into stringIds for source file name */ 107 | uint annotations_off; /* file offset to annotations_directory_item */ 108 | uint class_data_off; /* file offset to class_data_item */ 109 | uint static_values_off; /* file offset to DexEncodedArray */ 110 | } class_def_item; 111 | 112 | typedef struct _class_data_item { 113 | uint static_fields_size; 114 | uint instance_fields_size; 115 | uint direct_methods_size; 116 | uint virtual_methods_size; 117 | 118 | encoded_method *direct_methods; 119 | encoded_method *virtual_methods; 120 | } class_data_item; 121 | 122 | typedef struct _DexHeader { 123 | u1 magic[8]; /* includes version number */ 124 | u1 checksum[4]; /* adler32 checksum */ 125 | u1 signature[20]; /* SHA-1 hash */ 126 | u4 fileSize; /* length of entire file */ 127 | u4 headerSize; /* offset to start of next section */ 128 | u4 endianTag; 129 | u4 linkSize; 130 | u4 linkOff; 131 | u4 mapOff; 132 | u4 stringIdsSize; 133 | u4 stringIdsOff; 134 | u4 typeIdsSize; 135 | u4 typeIdsOff; 136 | u4 protoIdsSize; 137 | u4 protoIdsOff; 138 | u4 fieldIdsSize; 139 | u4 fieldIdsOff; 140 | u4 methodIdsSize; 141 | u4 methodIdsOff; 142 | u4 classDefsSize; 143 | u4 classDefsOff; 144 | u4 dataSize; 145 | u4 dataOff; 146 | } DexHeader; 147 | 148 | typedef struct DexFileFormat { 149 | DexHeader header; 150 | string_ids *string_ids; 151 | string_data_item *string_data_item; 152 | type_id_item *type_id_item; 153 | proto_id_item *proto_id_item; 154 | type_list *proto_type_list; 155 | field_id_item *field_id_item; 156 | method_id_item *method_id_item; 157 | class_def_item *class_def_item; 158 | class_data_item *class_data_item; 159 | map_list map_list; 160 | type_list type_list; 161 | u1 *data; 162 | } DexFileFormat; 163 | 164 | /* Dex File Parser */ 165 | int parseDexFile(char *file, DexFileFormat *dex); 166 | void printDexFile(DexFileFormat *dex); 167 | 168 | /* map list parser */ 169 | void parse_map_list(DexFileFormat *dex, unsigned char *buf, int offset); 170 | 171 | /* String ids parser */ 172 | void parse_string_ids(DexFileFormat *dex, unsigned char *buf, int offset); 173 | char *get_string_data(DexFileFormat *dex, int string_id); 174 | 175 | /* type_ids parser */ 176 | void parse_type_ids(DexFileFormat *dex, unsigned char *buf, int offset); 177 | type_id_item *get_type_item(DexFileFormat *dex, int type_id); 178 | char *get_type_item_name(DexFileFormat *dex, int type_id); 179 | 180 | /* proto_ids parser */ 181 | void parse_proto_ids(DexFileFormat *dex, unsigned char *buf, int offset); 182 | proto_id_item *get_proto_item(DexFileFormat *dex, int proto_id); 183 | type_list *get_proto_type_list(DexFileFormat *dex, int proto_id); 184 | 185 | /* field_ids parser */ 186 | void parse_field_ids(DexFileFormat *dex, unsigned char *buf, int offset); 187 | field_id_item *get_field_item(DexFileFormat *dex, int field_id); 188 | 189 | /* method ids parser */ 190 | void parse_method_ids(DexFileFormat *dex, unsigned char *buf, int offset); 191 | method_id_item *get_method_item(DexFileFormat *dex, int method_id); 192 | 193 | /* class defs parser */ 194 | void parse_class_defs(DexFileFormat *dex, unsigned char *buf, int offset); 195 | 196 | int get_uleb128_len(unsigned char *buf, int offset, int *size); 197 | 198 | /* generic parameter parser for 35c */ 199 | typedef struct _invoke_parameters { 200 | int method_id; 201 | int reg_count; 202 | int reg_idx[5]; // 0-5 map C-G 203 | } invoke_parameters; 204 | 205 | /* Dalvik VM Register Bank */ 206 | typedef struct _simple_dvm_register { 207 | u1 data[4]; 208 | } simple_dvm_register; 209 | 210 | typedef struct _simple_dalvik_vm { 211 | u1 heap[8192]; 212 | u1 object_ref[4]; 213 | simple_dvm_register regs[32]; 214 | invoke_parameters p; 215 | u1 result[8]; 216 | uint pc; 217 | } simple_dalvik_vm; 218 | 219 | /* convert to int ok */ 220 | void load_reg_to(simple_dalvik_vm *vm, int id, unsigned char *ptr); 221 | void load_reg_to_double(simple_dalvik_vm *vm, int id, unsigned char *ptr); 222 | void load_result_to_double(simple_dalvik_vm *vm, unsigned char *ptr); 223 | 224 | void store_to_reg(simple_dalvik_vm *vm, int id, unsigned char *ptr); 225 | void store_double_to_reg(simple_dalvik_vm *vm, int id, unsigned char *ptr); 226 | void store_double_to_result(simple_dalvik_vm *vm, unsigned char *ptr); 227 | 228 | void move_top_half_result_to_reg(simple_dalvik_vm *vm, int id); 229 | void move_bottom_half_result_to_reg(simple_dalvik_vm *vm, int id); 230 | 231 | void simple_dvm_startup(DexFileFormat *dex, simple_dalvik_vm *vm, char *entry); 232 | void runMethod(DexFileFormat *dex, simple_dalvik_vm *vm, encoded_method *m); 233 | 234 | typedef int (*opCodeFunc)(DexFileFormat *dex, simple_dalvik_vm *vm, u1 *ptr, int *pc); 235 | 236 | typedef struct _byteCode { 237 | char *name; 238 | unsigned char opCode; 239 | int offset; 240 | opCodeFunc func; 241 | } byteCode; 242 | 243 | int is_verbose(); 244 | int enable_verbose(); 245 | int disable_verbose(); 246 | int set_verbose(int l); 247 | 248 | #endif 249 | -------------------------------------------------------------------------------- /simple_dvm/string_ids_parser.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Dalvik Virtual Machine Implementation 3 | * 4 | * Copyright (C) 2013 Chun-Yu Wang 5 | */ 6 | 7 | #include "simple_dvm.h" 8 | 9 | static void parse_string_data_item(DexFileFormat *dex, 10 | unsigned char *buf, int offset, int index) 11 | { 12 | int i = 0; 13 | int size = 0; 14 | int len = 0; 15 | if (is_verbose() > 3) 16 | printf("parse string data item offset = %04x ", 17 | offset + sizeof(DexHeader)); 18 | memset(&dex->string_data_item[index], 0, sizeof(string_data_item)); 19 | dex->string_data_item[index].index = index; 20 | dex->string_data_item[index].uleb128_len = 21 | get_uleb128_len(buf, offset , &size) ; 22 | 23 | strncpy(dex->string_data_item[index].data, 24 | buf + offset + size, 25 | dex->string_data_item[index].uleb128_len); 26 | if (is_verbose() > 3) { 27 | printf("str[%2d], len = %4d, ", 28 | dex->string_data_item[index].index, 29 | dex->string_data_item[index].uleb128_len 30 | ); 31 | printf("data = "); 32 | for (i = 0; i < dex->string_data_item[index].uleb128_len; i++) 33 | printf("%c", dex->string_data_item[index].data[i]); 34 | printf("\n"); 35 | } 36 | } 37 | 38 | void parse_string_ids(DexFileFormat *dex, unsigned char *buf, int offset) 39 | { 40 | int i = 0; 41 | if (is_verbose() > 3) 42 | printf("parse string ids offset = %04x\n", offset + sizeof(DexHeader)); 43 | dex->string_ids = malloc( 44 | sizeof(string_ids) * dex->header.stringIdsSize); 45 | dex->string_data_item = malloc( 46 | sizeof(string_data_item) * dex->header.stringIdsSize); 47 | for (i = 0 ; i < dex->header.stringIdsSize ; i++) { 48 | memcpy(&dex->string_ids[i].string_data_off, 49 | buf + i * 4 + offset, 4); 50 | parse_string_data_item(dex, buf, 51 | dex->string_ids[i].string_data_off - sizeof(dex->header), 52 | i); 53 | } 54 | } 55 | 56 | static string_data_item *get_string_data_item(DexFileFormat *dex, int string_id) 57 | { 58 | if (string_id >= 0 && string_id < dex->header.stringIdsSize) 59 | return &dex->string_data_item[string_id]; 60 | return 0; 61 | } 62 | 63 | char *get_string_data(DexFileFormat *dex, int string_id) 64 | { 65 | string_data_item *s = get_string_data_item(dex, string_id); 66 | if (s != 0) 67 | return s->data; 68 | return 0; 69 | } 70 | -------------------------------------------------------------------------------- /simple_dvm/type_ids_parser.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Dalvik Virtual Machine Implementation 3 | * 4 | * Copyright (C) 2013 Chun-Yu Wang 5 | */ 6 | 7 | #include "simple_dvm.h" 8 | 9 | void parse_type_ids(DexFileFormat *dex, unsigned char *buf, int offset) 10 | { 11 | int i = 0; 12 | if (is_verbose() > 3) 13 | printf("parse type ids offset = %04x\n", offset + sizeof(DexHeader)); 14 | dex->type_id_item = malloc( 15 | sizeof(type_id_item) * dex->header.typeIdsSize); 16 | 17 | for (i = 0; i < dex->header.typeIdsSize; i++) { 18 | memcpy(&dex->type_id_item[i], 19 | buf + i * sizeof(type_id_item) + offset, 20 | sizeof(type_id_item)); 21 | 22 | if (is_verbose() > 3) 23 | printf(" type_ids [%d], = %s\n", i, 24 | dex->string_data_item[ 25 | dex->type_id_item[i].descriptor_idx].data); 26 | } 27 | } 28 | 29 | type_id_item *get_type_item(DexFileFormat *dex, int type_id) 30 | { 31 | if (type_id >= 0 && type_id < dex->header.typeIdsSize) 32 | return &dex->type_id_item[type_id]; 33 | return 0; 34 | } 35 | 36 | char *get_type_item_name(DexFileFormat *dex, int type_id) 37 | { 38 | type_id_item *type_item = get_type_item(dex, type_id); 39 | if (type_item != 0) 40 | return get_string_data(dex, type_item->descriptor_idx); 41 | return 0; 42 | } 43 | 44 | void parse_proto_ids(DexFileFormat *dex, unsigned char *buf, int offset) 45 | { 46 | volatile int i = 0, j = 0; 47 | int idx = 0; 48 | if (is_verbose() > 3) 49 | printf("parse proto ids offset = %04x\n", offset + sizeof(DexHeader)); 50 | dex->proto_id_item = malloc( 51 | sizeof(proto_id_item) * dex->header.protoIdsSize); 52 | 53 | dex->proto_type_list = malloc( 54 | sizeof(type_list) * dex->header.protoIdsSize); 55 | for (i = 0 ; i < dex->header.protoIdsSize; i++) { 56 | memcpy(&dex->proto_id_item[i], 57 | buf + i * sizeof(proto_id_item) + offset, 58 | sizeof(proto_id_item)); 59 | memset(&dex->proto_type_list[i], 0, sizeof(type_list)); 60 | idx = dex->proto_id_item[i].return_type_idx; 61 | if (is_verbose() > 3) 62 | printf(" proto_id_item [%d], %s, type_id = %d %s, parameters_off = %08x\n", i, 63 | dex->string_data_item[dex->proto_id_item[i].shorty_idx].data, 64 | idx, get_type_item_name(dex, idx), 65 | dex->proto_id_item[i].parameters_off); 66 | if (dex->proto_id_item[i].parameters_off == 0) 67 | continue; 68 | if (is_verbose() > 3) 69 | printf(" proto_typ_list[%d] offset %p ", i, 70 | buf + dex->proto_id_item[i].parameters_off - sizeof(DexHeader)); 71 | memcpy(&dex->proto_type_list[i].size, 72 | buf + dex->proto_id_item[i].parameters_off - sizeof(DexHeader), 73 | sizeof(int)); 74 | 75 | if (is_verbose() > 3) 76 | printf("proto_type_list[%d].size = %d\n", i, 77 | dex->proto_type_list[i].size); 78 | if (dex->proto_type_list[i].size > 0) { 79 | dex->proto_type_list[i].type_item = (type_item *) 80 | malloc(sizeof(type_item) * dex->proto_type_list[i].size); 81 | 82 | for (j = 0 ; j < dex->proto_type_list[i].size ; j++) { 83 | memset(&dex->proto_type_list[i].type_item[j], 0, sizeof(type_item)); 84 | type_item *item = &dex->proto_type_list[i].type_item[j]; 85 | memcpy(item, 86 | buf 87 | + dex->proto_id_item[i].parameters_off 88 | - sizeof(DexHeader) 89 | + 4 90 | + (sizeof(type_item) * j), 91 | sizeof(type_item)); 92 | 93 | if (is_verbose() > 3) 94 | printf("item[%d], type_idx = %d, type = %s\n", 95 | j, item->type_idx, 96 | get_type_item_name(dex, item->type_idx)); 97 | } 98 | } 99 | } 100 | } 101 | 102 | proto_id_item *get_proto_item(DexFileFormat *dex, int proto_id) 103 | { 104 | if (proto_id >= 0 && proto_id < dex->header.protoIdsSize) 105 | return &dex->proto_id_item[proto_id]; 106 | return 0; 107 | } 108 | 109 | type_list *get_proto_type_list(DexFileFormat *dex, int proto_id) 110 | { 111 | if (proto_id >= 0 && proto_id < dex->header.protoIdsSize) 112 | return &dex->proto_type_list[proto_id]; 113 | return 0; 114 | } 115 | 116 | void parse_field_ids(DexFileFormat *dex, unsigned char *buf, int offset) 117 | { 118 | int i; 119 | if (is_verbose() > 3) 120 | printf("parse feild ids offset = %04x\n", offset + sizeof(DexHeader)); 121 | dex->field_id_item = malloc(sizeof(field_id_item) * dex->header.fieldIdsSize); 122 | 123 | if (is_verbose() > 3) 124 | printf("dex->header.fieldIdsSize = %d\n", dex->header.fieldIdsSize); 125 | for (i = 0; i < dex->header.fieldIdsSize; i++) { 126 | memcpy(&dex->field_id_item[i], 127 | buf + i * sizeof(field_id_item) + offset, 128 | sizeof(field_id_item)); 129 | 130 | if (is_verbose() > 3) { 131 | printf(" field_id_item [%d], class_id = %d %s, type_id = %d %s, name_idx=%d %s\n", 132 | i, dex->field_id_item[i].class_idx, 133 | dex->string_data_item[ 134 | dex->type_id_item[ 135 | dex->field_id_item[i].class_idx].descriptor_idx].data, 136 | 137 | dex->field_id_item[i].type_idx, 138 | dex->string_data_item[ 139 | dex->type_id_item[ 140 | dex->field_id_item[i].type_idx].descriptor_idx].data, 141 | dex->field_id_item[i].name_idx, 142 | dex->string_data_item[dex->field_id_item[i].name_idx].data); 143 | } 144 | } 145 | } 146 | 147 | field_id_item *get_field_item(DexFileFormat *dex, int field_id) 148 | { 149 | if (field_id >= 0 && field_id < dex->header.fieldIdsSize) 150 | return &dex->field_id_item[field_id]; 151 | return 0; 152 | } 153 | -------------------------------------------------------------------------------- /simple_dvm/utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Dalvik Virtual Machine Implementation 3 | * 4 | * Copyright (C) 2013 Chun-Yu Wang 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include "simple_dvm.h" 11 | 12 | static int verbose_flag = 0; 13 | 14 | int is_verbose() 15 | { 16 | return verbose_flag; 17 | } 18 | 19 | int enable_verbose() 20 | { 21 | verbose_flag = 1; 22 | return 0; 23 | } 24 | 25 | int disable_verbose() 26 | { 27 | verbose_flag = 0; 28 | return 0; 29 | } 30 | 31 | int set_verbose(int l) 32 | { 33 | verbose_flag = l; 34 | return 0; 35 | } 36 | 37 | void load_reg_to(simple_dalvik_vm *vm, int id, unsigned char *ptr) 38 | { 39 | simple_dvm_register *r = &vm->regs[id]; 40 | ptr[0] = r->data[0]; 41 | ptr[1] = r->data[1]; 42 | ptr[2] = r->data[2]; 43 | ptr[3] = r->data[3]; 44 | } 45 | 46 | void load_reg_to_double(simple_dalvik_vm *vm, int id, unsigned char *ptr) 47 | { 48 | simple_dvm_register *r = &vm->regs[id]; 49 | ptr[0] = r->data[2]; 50 | ptr[1] = r->data[3]; 51 | ptr[2] = r->data[0]; 52 | ptr[3] = r->data[1]; 53 | } 54 | void load_result_to_double(simple_dalvik_vm *vm, unsigned char *ptr) 55 | { 56 | ptr[0] = vm->result[2]; 57 | ptr[1] = vm->result[3]; 58 | ptr[2] = vm->result[0]; 59 | ptr[3] = vm->result[1]; 60 | ptr[4] = vm->result[6]; 61 | ptr[5] = vm->result[7]; 62 | ptr[6] = vm->result[4]; 63 | ptr[7] = vm->result[5]; 64 | } 65 | 66 | void store_double_to_result(simple_dalvik_vm *vm, unsigned char *ptr) 67 | { 68 | vm->result[0] = ptr[2]; 69 | vm->result[1] = ptr[3]; 70 | vm->result[2] = ptr[0]; 71 | vm->result[3] = ptr[1]; 72 | vm->result[4] = ptr[6]; 73 | vm->result[5] = ptr[7]; 74 | vm->result[6] = ptr[4]; 75 | vm->result[7] = ptr[5]; 76 | } 77 | 78 | void store_double_to_reg(simple_dalvik_vm *vm, int id, unsigned char *ptr) 79 | { 80 | simple_dvm_register *r = &vm->regs[id]; 81 | r->data[0] = ptr[2]; 82 | r->data[1] = ptr[3]; 83 | r->data[2] = ptr[0]; 84 | r->data[3] = ptr[1]; 85 | } 86 | 87 | void store_to_reg(simple_dalvik_vm *vm, int id, unsigned char *ptr) 88 | { 89 | simple_dvm_register *r = &vm->regs[id]; 90 | r->data[0] = ptr[0]; 91 | r->data[1] = ptr[1]; 92 | r->data[2] = ptr[2]; 93 | r->data[3] = ptr[3]; 94 | } 95 | 96 | void move_top_half_result_to_reg(simple_dalvik_vm *vm, int id) 97 | { 98 | simple_dvm_register *r = &vm->regs[id]; 99 | r->data[0] = vm->result[0]; 100 | r->data[1] = vm->result[1]; 101 | r->data[2] = vm->result[2]; 102 | r->data[3] = vm->result[3]; 103 | } 104 | 105 | void move_bottom_half_result_to_reg(simple_dalvik_vm *vm, int id) 106 | { 107 | simple_dvm_register *r = &vm->regs[id]; 108 | r->data[0] = vm->result[4]; 109 | r->data[1] = vm->result[5]; 110 | r->data[2] = vm->result[6]; 111 | r->data[3] = vm->result[7]; 112 | } 113 | -------------------------------------------------------------------------------- /simple_jvm/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = jvm 2 | 3 | # Toolchain configurations 4 | CROSS_COMPILE ?= 5 | CC = $(CROSS_COMPILE)gcc 6 | 7 | SUFFIX ?= 8 | EXECUTABLE = $(PROJECT)$(SUFFIX) 9 | 10 | # Basic configurations 11 | CFLAGS += -g -std=c99 12 | LDFLAGS = 13 | 14 | # Optimizations 15 | CFLAGS += -Os 16 | 17 | # project starts here 18 | CFLAGS += -I. 19 | OBJS = \ 20 | bytecodes.o \ 21 | field_pool_parser.o \ 22 | java_lib.o \ 23 | stack.o \ 24 | class_parser.o \ 25 | free_pool.o \ 26 | main.o \ 27 | constant_pool_parser.o \ 28 | interface_pool_parser.o \ 29 | method_pool_parser.o 30 | 31 | $(EXECUTABLE): $(OBJS) 32 | $(CC) -o $@ $(OBJS) $(LDFLAGS) 33 | 34 | %.o: %.c 35 | $(CC) $(CFLAGS) -c $< -o $@ 36 | 37 | clean: 38 | rm -rf $(EXECUTABLE) 39 | rm -f $(OBJS) 40 | .PHONY: clean 41 | -------------------------------------------------------------------------------- /simple_jvm/bytecodes.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Java Virtual Machine Implementation 3 | * 4 | * Copyright (C) 2014 Jim Huang 5 | * Copyright (C) 2013 Chun-Yu Wang 6 | */ 7 | 8 | #include "simple_jvm.h" 9 | #include "java_lib.h" 10 | 11 | extern SimpleInterfacePool simpleInterfacePool; 12 | extern SimpleFieldPool simpleFieldPool; 13 | extern SimpleConstantPool simpleConstantPool; 14 | extern SimpleMethodPool simpleMethodPool; 15 | extern StackFrame stackFrame; 16 | extern LocalVariables localVariables; 17 | 18 | static int run = 1; 19 | static int get_integer_parameter(StackFrame *stack, SimpleConstantPool *p) 20 | { 21 | int value = 0; 22 | if (is_ref_entry(stack)) { 23 | int index = popInt(stack); 24 | value = get_integer_from_constant_pool(p, index); 25 | } else { 26 | value = popInt(stack); 27 | } 28 | return value; 29 | } 30 | 31 | static long long get_long_parameter(StackFrame *stack, SimpleConstantPool *p) 32 | { 33 | long long value = 0; 34 | if (is_ref_entry(stack)) { 35 | int index = popInt(stack); 36 | value = get_long_from_constant_pool(p, index); 37 | } else { 38 | value = popLong(stack); 39 | } 40 | return value; 41 | } 42 | 43 | static float get_float_parameter(StackFrame *stack, SimpleConstantPool *p) 44 | { 45 | float value = 0; 46 | if (is_ref_entry(stack)) { 47 | int index = popInt(stack); 48 | value = get_float_from_constant_pool(p, index); 49 | } else { 50 | value = popFloat(stack); 51 | } 52 | return value; 53 | } 54 | 55 | static double get_double_parameter(StackFrame *stack, SimpleConstantPool *p) 56 | { 57 | double value = 0.0f; 58 | if (is_ref_entry(stack)) { 59 | int index = popInt(stack); 60 | value = get_double_from_constant_pool(p, index); 61 | #if SIMPLE_JVM_DEBUG 62 | printf("index %d\n", index); 63 | printf("get value from constant pool = %f\n", value); 64 | #endif 65 | } else { 66 | value = popDouble(stack); 67 | #if SIMPLE_JVM_DEBUG 68 | printf("get value from stack = %f\n", value); 69 | #endif 70 | } 71 | return value; 72 | } 73 | 74 | /* opcode implementation */ 75 | 76 | /* aload_0 */ 77 | static int op_aload_0(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 78 | { 79 | pushInt(stack, 0); 80 | #if SIMPLE_JVM_DEBUG 81 | printf("push 0 into stack\n"); 82 | #endif 83 | *opCode = *opCode + 1; 84 | return 0; 85 | } 86 | 87 | /* bipush */ 88 | static int op_bipush(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 89 | { 90 | int value = opCode[0][1]; 91 | pushInt(stack, value); 92 | #if SIMPLE_JVM_DEBUG 93 | printf("push a byte %d onto the stack \n", value); 94 | #endif 95 | *opCode = *opCode + 2; 96 | return 0; 97 | } 98 | 99 | /* dup */ 100 | static int op_dup(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 101 | { 102 | StackEntry *entry = popEntry(stack); 103 | int value = 0; 104 | value = EntryToInt(entry); 105 | if (entry->type == STACK_ENTRY_INT) { 106 | 107 | pushInt(stack, value); 108 | pushInt(stack, value); 109 | } else { 110 | pushRef(stack, value); 111 | pushRef(stack, value); 112 | } 113 | #if SIMPLE_JVM_DEBUG 114 | printf("dup\n"); 115 | #endif 116 | *opCode = *opCode + 1; 117 | return 0; 118 | } 119 | 120 | /* getstatic */ 121 | static int op_getstatic(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 122 | { 123 | u2 field_index ; 124 | unsigned char tmp[2]; 125 | tmp[0] = opCode[0][1]; 126 | tmp[1] = opCode[0][2]; 127 | field_index = tmp[0] << 8 | tmp[1]; 128 | #if SIMPLE_JVM_DEBUG 129 | printf("getstatic %d\n", field_index); 130 | #endif 131 | pushRef(stack, field_index); 132 | *opCode = *opCode + 3; 133 | return 0; 134 | } 135 | 136 | /* iadd */ 137 | static int op_iadd(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 138 | { 139 | int value1 = popInt(stack); 140 | int value2 = popInt(stack); 141 | int result = 0; 142 | result = value1 + value2; 143 | #if SIMPLE_JVM_DEBUG 144 | printf("iadd: %d + %d = %d\n", value1, value2, result); 145 | #endif 146 | pushInt(stack, result); 147 | *opCode = *opCode + 1; 148 | return 0; 149 | } 150 | 151 | /* iconst_0 */ 152 | static int op_iconst_0(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 153 | { 154 | pushInt(stack, 0); 155 | #if SIMPLE_JVM_DEBUG 156 | printf("iconst_0: push 0 into stack\n"); 157 | #endif 158 | *opCode = *opCode + 1; 159 | return 0; 160 | } 161 | 162 | /* iconst_1 */ 163 | static int op_iconst_1(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 164 | { 165 | pushInt(stack, 1); 166 | #if SIMPLE_JVM_DEBUG 167 | printf("iconst_1: push 1 into stack\n"); 168 | #endif 169 | *opCode = *opCode + 1; 170 | return 0; 171 | } 172 | 173 | /* iconst_2 */ 174 | static int op_iconst_2(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 175 | { 176 | pushInt(stack, 2); 177 | #if SIMPLE_JVM_DEBUG 178 | printf("iconst_2: push 1 into stack\n"); 179 | #endif 180 | *opCode = *opCode + 1; 181 | return 0; 182 | } 183 | 184 | /* iconst_3 */ 185 | static int op_iconst_3(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 186 | { 187 | pushInt(stack, 3); 188 | #if SIMPLE_JVM_DEBUG 189 | printf("iconst_3: push 1 into stack\n"); 190 | #endif 191 | *opCode = *opCode + 1; 192 | return 0; 193 | } 194 | 195 | /* iconst_4 */ 196 | static int op_iconst_4(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 197 | { 198 | pushInt(stack, 4); 199 | #if SIMPLE_JVM_DEBUG 200 | printf("iconst_4: push 1 into stack\n"); 201 | #endif 202 | *opCode = *opCode + 1; 203 | return 0; 204 | } 205 | 206 | /* iconst_5 */ 207 | static int op_iconst_5(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 208 | { 209 | pushInt(stack, 5); 210 | #if SIMPLE_JVM_DEBUG 211 | printf("iconst_5: push 5 into stack\n"); 212 | #endif 213 | *opCode = *opCode + 1; 214 | return 0; 215 | } 216 | 217 | /* 0x0F dconst_1 */ 218 | static int op_dconst_1(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 219 | { 220 | pushDouble(stack, 1.0f); 221 | #if SIMPLE_JVM_DEBUG 222 | printf("iconst_5: push 1.0f into stack\n"); 223 | #endif 224 | *opCode = *opCode + 1; 225 | return 0; 226 | } 227 | 228 | /* idiv */ 229 | static int op_idiv(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 230 | { 231 | int value2 = popInt(stack); 232 | int value1 = popInt(stack); 233 | int result = 0; 234 | result = value1 / value2; 235 | #if SIMPLE_JVM_DEBUG 236 | printf("idiv: %d / %d = %d\n", value1, value2, result); 237 | #endif 238 | pushInt(stack, result); 239 | *opCode = *opCode + 1; 240 | return 0; 241 | } 242 | 243 | /* iload */ 244 | static int op_iload(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 245 | { 246 | int index = opCode[0][1]; 247 | int value = localVariables.integer[index]; 248 | #if SIMPLE_JVM_DEBUG 249 | printf("iload: load value from local variable %d(%d)\n", index, localVariables.integer[index]); 250 | #endif 251 | pushInt(stack, value); 252 | *opCode = *opCode + 2; 253 | return 0; 254 | } 255 | 256 | /* iload_1 */ 257 | static int op_iload_1(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 258 | { 259 | int value = localVariables.integer[1]; 260 | #if SIMPLE_JVM_DEBUG 261 | printf("iload_1: load value from local variable 1(%d)\n", localVariables.integer[1]); 262 | #endif 263 | pushInt(stack, value); 264 | *opCode = *opCode + 1; 265 | return 0; 266 | } 267 | 268 | /* iload_2 */ 269 | static int op_iload_2(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 270 | { 271 | int value = localVariables.integer[2]; 272 | #if SIMPLE_JVM_DEBUG 273 | printf("iload_2: load value from local variable 2(%d)\n", localVariables.integer[2]); 274 | #endif 275 | pushInt(stack, value); 276 | *opCode = *opCode + 1; 277 | return 0; 278 | } 279 | 280 | /* iload_3 */ 281 | static int op_iload_3(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 282 | { 283 | int value = localVariables.integer[3]; 284 | #if SIMPLE_JVM_DEBUG 285 | printf("iload_3: load value from local variable 3(%d)\n", localVariables.integer[3]); 286 | #endif 287 | pushInt(stack, value); 288 | *opCode = *opCode + 1; 289 | return 0; 290 | } 291 | 292 | /* imul */ 293 | static int op_imul(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 294 | { 295 | int value1 = popInt(stack); 296 | int value2 = popInt(stack); 297 | int result = 0; 298 | result = value1 * value2; 299 | #if SIMPLE_JVM_DEBUG 300 | printf("imul: %d * %d = %d\n", value1, value2, result); 301 | #endif 302 | pushInt(stack, result); 303 | *opCode = *opCode + 1; 304 | return 0; 305 | } 306 | 307 | /* 0x63 dadd */ 308 | static int op_dadd(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 309 | { 310 | double value1 = get_double_parameter(stack, p); 311 | double value2 = get_double_parameter(stack, p); 312 | double result = 0; 313 | result = value1 + value2; 314 | #if SIMPLE_JVM_DEBUG 315 | printf("dadd: %f + %f = %f\n", value1, value2, result); 316 | #endif 317 | pushDouble(stack, result); 318 | *opCode = *opCode + 1; 319 | return 0; 320 | } 321 | 322 | /* 0x6B dmul */ 323 | static int op_dmul(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 324 | { 325 | double value1 = get_double_parameter(stack, p); 326 | double value2 = get_double_parameter(stack, p); 327 | double result = 0; 328 | result = value1 * value2; 329 | #if SIMPLE_JVM_DEBUG 330 | printf("dmul: %f * %f = %f\n", value1, value2, result); 331 | #endif 332 | pushDouble(stack, result); 333 | *opCode = *opCode + 1; 334 | return 0; 335 | } 336 | 337 | /* 0x8e d2i */ 338 | static int op_d2i(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 339 | { 340 | double value1 = popDouble(stack); 341 | int result = 0; 342 | result = (int)value1; 343 | #if SIMPLE_JVM_DEBUG 344 | printf("d2i: %d <-- %f\n", result, value1); 345 | #endif 346 | pushInt(stack, result); 347 | *opCode = *opCode + 1; 348 | return 0; 349 | } 350 | 351 | /* irem */ 352 | static int op_irem(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 353 | { 354 | int value1 = popInt(stack); 355 | int value2 = popInt(stack); 356 | int result = 0; 357 | result = value2 % value1; 358 | #if SIMPLE_JVM_DEBUG 359 | printf("irem: %d % %d = %d\n", value2, value1, result); 360 | #endif 361 | pushInt(stack, result); 362 | *opCode = *opCode + 1; 363 | return 0; 364 | } 365 | 366 | /* istore */ 367 | static int op_istore(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 368 | { 369 | int value = popInt(stack); 370 | int index = opCode[0][1]; 371 | #if SIMPLE_JVM_DEBUG 372 | printf("istore: store value into local variable %d(%d)\n", index, value); 373 | #endif 374 | localVariables.integer[index] = value; 375 | *opCode = *opCode + 2; 376 | return 0; 377 | } 378 | 379 | /* istore_1 */ 380 | static int op_istore_1(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 381 | { 382 | int value = popInt(stack); 383 | #if SIMPLE_JVM_DEBUG 384 | printf("istore_1: store value into local variable 1(%d)\n", value); 385 | #endif 386 | localVariables.integer[1] = value; 387 | *opCode = *opCode + 1; 388 | return 0; 389 | } 390 | 391 | /* istore_2 */ 392 | static int op_istore_2(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 393 | { 394 | int value = popInt(stack); 395 | #if SIMPLE_JVM_DEBUG 396 | printf("istore_2: store value into local variable 2(%d)\n", value); 397 | #endif 398 | localVariables.integer[2] = value; 399 | *opCode = *opCode + 1; 400 | return 0; 401 | } 402 | 403 | /* istore_3 */ 404 | static int op_istore_3(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 405 | { 406 | int value = popInt(stack); 407 | #if SIMPLE_JVM_DEBUG 408 | printf("istore_3: store value into local variable 3(%d)\n", value); 409 | #endif 410 | localVariables.integer[3] = value; 411 | *opCode = *opCode + 1; 412 | return 0; 413 | } 414 | 415 | /* isub */ 416 | static int op_isub(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 417 | { 418 | int value2 = popInt(stack); 419 | int value1 = popInt(stack); 420 | int result = 0; 421 | result = value1 - value2; 422 | #if SIMPLE_JVM_DEBUG 423 | printf("isub : %d - %d = %d\n", value1, value2, result); 424 | #endif 425 | pushInt(stack, result); 426 | *opCode = *opCode + 1; 427 | return 0; 428 | } 429 | 430 | /* invokespecial */ 431 | static int op_invokespecial(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 432 | { 433 | u2 method_index; 434 | unsigned char tmp[2]; 435 | tmp[0] = opCode[0][1]; 436 | tmp[1] = opCode[0][2]; 437 | method_index = tmp[0] << 8 | tmp[1]; 438 | #if SIMPLE_JVM_DEBUG 439 | printf("call method_index %d\n", method_index); 440 | #endif 441 | *opCode = *opCode + 3; 442 | if (method_index < simpleMethodPool.method_used) { 443 | MethodInfo *method = &simpleMethodPool.method[method_index]; 444 | executeMethod(method, &stackFrame, &simpleConstantPool); 445 | } 446 | return 0; 447 | } 448 | 449 | static char *clzNamePrint = "java/io/PrintStream"; 450 | static char *clzNameStrBuilder = "java/lang/StringBuilder"; 451 | static char stringBuilderBuffer[1024]; 452 | static int stringBuilderUsed = 0; 453 | 454 | /* 0xb8 invokestatic */ 455 | static int op_invokestatic(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 456 | { 457 | u2 method_index ; 458 | unsigned char tmp[2]; 459 | char method_name[255]; 460 | char clsName[255]; 461 | char method_type[255]; 462 | tmp[0] = opCode[0][1]; 463 | tmp[1] = opCode[0][2]; 464 | method_index = tmp[0] << 8 | tmp[1]; 465 | #if SIMPLE_JVM_DEBUG 466 | printf("invokestatic method_index %d\n", method_index); 467 | printf("simpleMethodPool.method_used = %d\n", simpleMethodPool.method_used); 468 | #endif 469 | *opCode = *opCode + 3; 470 | if (method_index < simpleMethodPool.method_used) { 471 | MethodInfo *method = &simpleMethodPool.method[method_index]; 472 | memset(method_name, 0, 255); 473 | getUTF8String(p, method->name_index, 255, method_name); 474 | #if SIMPLE_JVM_DEBUG 475 | printf(" method name = %s\n", method_name); 476 | #endif 477 | } else { 478 | ConstantMethodRef *mRef = findMethodRef(p, method_index); 479 | if (mRef != 0) { 480 | ConstantClassRef *clasz = findClassRef(p, mRef->classIndex); 481 | ConstantNameAndType *nat = findNameAndType(p, mRef->nameAndTypeIndex); 482 | if (clasz == 0 || nat == 0) return -1; 483 | getUTF8String(p, clasz->stringIndex, 255, clsName); 484 | getUTF8String(p, nat->nameIndex, 255, method_name); 485 | getUTF8String(p, nat->typeIndex, 255, method_type); 486 | 487 | #if SIMPLE_JVM_DEBUG 488 | printf("call class %s\n", clsName); 489 | printf("call method %s\n", method_name); 490 | printf("call method type %s\n", method_type); 491 | #endif 492 | int ret = invoke_java_lang_library(stack, p, 493 | clsName, method_name, method_type); 494 | #if SIMPLE_JVM_DEBUG 495 | if (ret) { 496 | printf("invoke java lang library successful\n"); 497 | } 498 | #endif 499 | } 500 | } 501 | 502 | return 0; 503 | } 504 | 505 | /* invokevirtual */ 506 | static int op_invokevirtual(unsigned char **opCode, StackFrame *stack, 507 | SimpleConstantPool *p) 508 | { 509 | u2 object_ref; 510 | unsigned char tmp[2]; 511 | char clsName[255]; 512 | char utf8[255]; 513 | int len = 0; 514 | tmp[0] = opCode[0][1]; 515 | tmp[1] = opCode[0][2]; 516 | object_ref = tmp[0] << 8 | tmp[1]; 517 | #if SIMPLE_JVM_DEBUG 518 | printf("call object_ref %d\n", object_ref); 519 | #endif 520 | *opCode = *opCode + 3; 521 | ConstantMethodRef *mRef = findMethodRef(p, object_ref); 522 | if (mRef != 0) { 523 | ConstantClassRef *clasz = findClassRef(p, mRef->classIndex); 524 | ConstantNameAndType *nat = findNameAndType(p, mRef->nameAndTypeIndex); 525 | if (clasz == 0 || nat == 0) return -1; 526 | getUTF8String(p, clasz->stringIndex, 255, clsName); 527 | #if SIMPLE_JVM_DEBUG 528 | printf("call object ref class %s\n", clsName); 529 | #endif 530 | if (strcmp(clzNamePrint, clsName) == 0) { 531 | StackEntry *entry = popEntry(stack); 532 | int index = EntryToInt(entry); 533 | #if SIMPLE_JVM_DEBUG 534 | printf("call Println with index = %d\n", index); 535 | #endif 536 | if (entry->type == STACK_ENTRY_REF) { 537 | ConstantStringRef *strRef = findStringRef(p, index); 538 | if (strRef != 0) { 539 | getUTF8String(p, strRef->stringIndex, 255, utf8); 540 | len = strlen(utf8); 541 | memcpy(stringBuilderBuffer + stringBuilderUsed, utf8, len); 542 | stringBuilderUsed += len; 543 | stringBuilderBuffer[stringBuilderUsed] = 0; 544 | } 545 | } else if (entry->type == STACK_ENTRY_INT) { 546 | sprintf(utf8, "%d", index); 547 | len = strlen(utf8); 548 | memcpy(stringBuilderBuffer + stringBuilderUsed, utf8, len); 549 | stringBuilderUsed += len; 550 | stringBuilderBuffer[stringBuilderUsed] = 0; 551 | } 552 | // printf out the result 553 | printf("%s\n", stringBuilderBuffer); 554 | memset(stringBuilderBuffer, 0, 1024); 555 | stringBuilderUsed = 0; 556 | } else if (strcmp(clzNameStrBuilder, clsName) == 0) { 557 | StackEntry *entry = popEntry(stack); 558 | int index = EntryToInt(entry); 559 | #if SIMPLE_JVM_DEBUG 560 | printf("call StringBuilder with index = %d\n", index); 561 | #endif 562 | if (entry->type == STACK_ENTRY_REF) { 563 | ConstantStringRef *strRef = findStringRef(p, index); 564 | if (strRef != 0) { 565 | getUTF8String(p, strRef->stringIndex, 255, utf8); 566 | len = strlen(utf8); 567 | memcpy(stringBuilderBuffer + stringBuilderUsed, utf8, len); 568 | stringBuilderUsed += len; 569 | } 570 | } else if (entry->type == STACK_ENTRY_INT) { 571 | sprintf(utf8, "%d", index); 572 | len = strlen(utf8); 573 | memcpy(stringBuilderBuffer + stringBuilderUsed, utf8, len); 574 | stringBuilderUsed += len; 575 | #if SIMPLE_JVM_DEBUG 576 | printf("%s\n", stringBuilderBuffer); 577 | #endif 578 | } 579 | 580 | } 581 | } 582 | return 0; 583 | } 584 | 585 | /* ldc */ 586 | static int op_ldc(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 587 | { 588 | int value = opCode[0][1]; 589 | pushRef(stack, value); 590 | #if SIMPLE_JVM_DEBUG 591 | printf("ldc: push a constant index %d onto the stack \n", value); 592 | #endif 593 | *opCode = *opCode + 2; 594 | return 0; 595 | } 596 | 597 | /* 0x14 ldc2_w */ 598 | static int op_ldc2_w(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 599 | { 600 | unsigned char index1 = opCode[0][1]; 601 | unsigned char index2 = opCode[0][2]; 602 | int index = (index1 << 8) | index2; 603 | pushRef(stack, index); 604 | #if SIMPLE_JVM_DEBUG 605 | printf("ldc2_w: push a constant index %d onto the stack \n", index); 606 | #endif 607 | *opCode = *opCode + 3; 608 | return 0; 609 | } 610 | 611 | /* 0x11 op_sipush */ 612 | static int op_sipush(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 613 | { 614 | short value; 615 | unsigned char tmp[2]; 616 | tmp[0] = opCode[0][1]; 617 | tmp[1] = opCode[0][2]; 618 | value = tmp[0] << 8 | tmp[1]; 619 | #if SIMPLE_JVM_DEBUG 620 | printf("sipush value %d\n", value); 621 | #endif 622 | pushInt(stack, value); 623 | *opCode = *opCode + 3; 624 | return 0; 625 | } 626 | 627 | /* op_new */ 628 | static int op_new(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 629 | { 630 | u2 object_ref; 631 | unsigned char tmp[2]; 632 | tmp[0] = opCode[0][1]; 633 | tmp[1] = opCode[0][2]; 634 | object_ref = tmp[0] << 8 | tmp[1]; 635 | #if SIMPLE_JVM_DEBUG 636 | printf("new: new object_ref %d\n", object_ref); 637 | #endif 638 | *opCode = *opCode + 3; 639 | return 0; 640 | } 641 | 642 | /* return */ 643 | static int op_return(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p) 644 | { 645 | #if SIMPLE_JVM_DEBUG 646 | printf("return: \n"); 647 | #endif 648 | *opCode = *opCode + 1; 649 | return -1; 650 | } 651 | 652 | static byteCode byteCodes[] = { 653 | { "aload_0" , 0x2A, 1, op_aload_0 }, 654 | { "bipush" , 0x10, 2, op_bipush }, 655 | { "dup" , 0x59, 1, op_dup }, 656 | { "getstatic" , 0xB2, 3, op_getstatic }, 657 | { "iadd" , 0x60, 1, op_iadd }, 658 | { "iconst_0" , 0x03, 1, op_iconst_0 }, 659 | { "iconst_1" , 0x04, 1, op_iconst_1 }, 660 | { "iconst_2" , 0x05, 1, op_iconst_2 }, 661 | { "iconst_3" , 0x06, 1, op_iconst_3 }, 662 | { "iconst_4" , 0x07, 1, op_iconst_4 }, 663 | { "iconst_5" , 0x08, 1, op_iconst_5 }, 664 | { "dconst_1" , 0x0F, 1, op_dconst_1 }, 665 | { "idiv" , 0x6C, 1, op_idiv }, 666 | { "imul" , 0x68, 1, op_imul }, 667 | { "dadd" , 0x63, 1, op_dadd }, 668 | { "dmul" , 0x6B, 1, op_dmul }, 669 | { "d2i" , 0x8e, 1, op_d2i }, 670 | { "invokespecial" , 0xB7, 3, op_invokespecial }, 671 | { "invokevirtual" , 0xB6, 3, op_invokevirtual }, 672 | { "invokestatic" , 0xB8, 3, op_invokestatic }, 673 | { "iload" , 0x15, 2, op_iload }, 674 | { "iload_1" , 0x1B, 1, op_iload_1 }, 675 | { "iload_2" , 0x1C, 1, op_iload_2 }, 676 | { "iload_3" , 0x1D, 1, op_iload_3 }, 677 | { "istore" , 0x36, 2, op_istore }, 678 | { "istore_1" , 0x3C, 1, op_istore_1 }, 679 | { "istore_2" , 0x3D, 1, op_istore_2 }, 680 | { "istore_3" , 0x3E, 1, op_istore_3 }, 681 | { "isub" , 0x64, 1, op_isub }, 682 | { "ldc" , 0x12, 2, op_ldc }, 683 | { "ldc2_w" , 0x14, 3, op_ldc2_w }, 684 | { "new" , 0xBB, 3, op_new }, 685 | { "irem" , 0x70, 1, op_irem }, 686 | { "sipush" , 0x11, 3, op_sipush }, 687 | { "return" , 0xB1, 1, op_return } 688 | }; 689 | static size_t byteCode_size = sizeof(byteCodes) / sizeof(byteCode); 690 | 691 | static char *findOpCode(unsigned char op) 692 | { 693 | int i; 694 | for (i = 0; i < byteCode_size ; i++) 695 | if (op == byteCodes[i].opCode) 696 | return byteCodes[i].name; 697 | return 0; 698 | } 699 | 700 | static opCodeFunc findOpCodeFunc(unsigned char op) 701 | { 702 | int i; 703 | for (i = 0; i < byteCode_size ; i++) 704 | if (op == byteCodes[i].opCode) 705 | return byteCodes[i].func; 706 | return 0; 707 | } 708 | 709 | static int findOpCodeOffset(unsigned char op) 710 | { 711 | int i; 712 | for (i = 0; i < byteCode_size ; i++) 713 | if (op == byteCodes[i].opCode) 714 | return byteCodes[i].offset; 715 | return 0; 716 | } 717 | 718 | static int convertToCodeAttribute(CodeAttribute *ca, AttributeInfo *attr) 719 | { 720 | int info_p = 0; 721 | unsigned char tmp[4]; 722 | ca->attribute_name_index = attr->attribute_name_index; 723 | ca->attribute_length = attr->attribute_length; 724 | tmp[0] = attr->info[info_p++]; 725 | tmp[1] = attr->info[info_p++]; 726 | ca->max_stack = tmp[0] << 8 | tmp[1]; 727 | tmp[0] = attr->info[info_p++]; 728 | tmp[1] = attr->info[info_p++]; 729 | ca->max_locals = tmp[0] << 8 | tmp[1]; 730 | tmp[0] = attr->info[info_p++]; 731 | tmp[1] = attr->info[info_p++]; 732 | tmp[2] = attr->info[info_p++]; 733 | tmp[3] = attr->info[info_p++]; 734 | ca->code_length = tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3]; 735 | ca->code = (unsigned char *) malloc(sizeof(unsigned char) * ca->code_length); 736 | memcpy(ca->code, attr->info + info_p, ca->code_length); 737 | } 738 | 739 | int executeMethod(MethodInfo *startup, StackFrame *stack, SimpleConstantPool *p) 740 | { 741 | int i = 0; 742 | int j = 0; 743 | int tmp = 0; 744 | char name[255]; 745 | CodeAttribute ca; 746 | memset(&ca, 0 , sizeof(CodeAttribute)); 747 | for (j = 0 ; j < startup->attributes_count ; j++) { 748 | convertToCodeAttribute(&ca, &startup->attributes[j]); 749 | getUTF8String(p, ca.attribute_name_index, 255, name); 750 | if (memcmp(name, "Code", 4) != 0) continue; 751 | #if SIMPLE_JVM_DEBUG 752 | printf("----------------------------------------\n"); 753 | printf("code dump\n"); 754 | printCodeAttribute(&ca, p); 755 | printf("----------------------------------------\n"); 756 | #endif 757 | unsigned char *pc = ca.code; 758 | if (run == 0) 759 | exit(1); 760 | do { 761 | #if 1 762 | opCodeFunc func = findOpCodeFunc(pc[0]); 763 | if (func != 0) { 764 | i = func(&pc , &stackFrame, p); 765 | } 766 | if (i < 0) break; 767 | #endif 768 | } while (1); 769 | } 770 | return 0; 771 | } 772 | 773 | static void printCodeAttribute(CodeAttribute *ca, SimpleConstantPool *p) 774 | { 775 | int i = 0; 776 | int tmp = 0; 777 | char name[255]; 778 | unsigned char opCode = 0; 779 | getUTF8String(p, ca->attribute_name_index, 255, name); 780 | printf("attribute name : %s\n", name); 781 | printf("attribute length: %d\n", ca->attribute_length); 782 | 783 | printf("max_stack: %d\n", ca->max_stack); 784 | printf("max_locals: %d\n", ca->max_locals); 785 | printf("code_length: %d\n", ca->code_length); 786 | unsigned char *pc = ca->code; 787 | i = 0; 788 | do { 789 | char *opName = findOpCode(pc[0]); 790 | if (opName == 0) { 791 | printf("Unknow OpCode %02X\n", pc[0]); 792 | exit(1); 793 | } 794 | printf("%s \n", opName); 795 | tmp = findOpCodeOffset(pc[0]); 796 | pc += tmp; 797 | i += tmp; 798 | } while (i < ca->code_length); 799 | } 800 | -------------------------------------------------------------------------------- /simple_jvm/class_parser.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Java Virtual Machine Implementation 3 | * 4 | * Copyright (C) 2013 Chun-Yu Wang 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include "simple_jvm.h" 11 | 12 | extern SimpleInterfacePool simpleInterfacePool; 13 | extern SimpleFieldPool simpleFieldPool; 14 | extern SimpleConstantPool simpleConstantPool; 15 | extern SimpleMethodPool simpleMethodPool; 16 | 17 | /* Get Major Version String */ 18 | static char *getMajorVersionString(u2 major_number) 19 | { 20 | if (major_number == 0x33) 21 | return "J2SE 7"; 22 | if (major_number == 0x32) 23 | return "J2SE 6.0"; 24 | return "NONE"; 25 | } 26 | 27 | /* Print Class File Format */ 28 | void printClassFileFormat(ClassFileFormat *cff) 29 | { 30 | int i; 31 | printf("Magic Number = "); 32 | for (i = 0; i < 4 ; i++) 33 | printf("0x%02X ", cff->magic_number[i]); 34 | printf("\n"); 35 | printf("Minor Number = 0x(%02X) %d \n", 36 | cff->minor_version, cff->minor_version); 37 | printf("Major Number(%s) = 0x(%02X) %d \n", 38 | getMajorVersionString(cff->major_version), 39 | cff->major_version, cff->major_version); 40 | printf("Constant Pool Count = 0x(%02X) %d \n", 41 | cff->constant_pool_count, cff->constant_pool_count); 42 | printf("access flag = 0x(%02X) %d \n", cff->access_flags, cff->access_flags); 43 | printf("this class = 0x(%02X) %d \n", 44 | cff->this_class, cff->this_class); 45 | printf("super class = 0x(%02X) %d \n", 46 | cff->super_class, cff->super_class); 47 | printf("interface count = 0x(%02X) %d \n", 48 | cff->interface_count, cff->interface_count); 49 | printf("field count = 0x(%02X) %d \n", 50 | cff->fields_count, cff->fields_count); 51 | printf("method count = 0x(%02X) %d \n", 52 | cff->methods_count, cff->methods_count); 53 | } 54 | 55 | /* Parse Class File */ 56 | int parseJavaClassFile(char *file, ClassFileFormat *cff) 57 | { 58 | FILE *fp = 0; 59 | unsigned char short_tmp[2]; 60 | fp = fopen(file, "rb"); 61 | if (fp == 0) { 62 | printf("Open file %s failed\n", file); 63 | return -1; 64 | } 65 | /* magic number */ 66 | fread(cff->magic_number, 4, 1, fp); 67 | 68 | /* minor_version */ 69 | fread(short_tmp, 2, 1, fp); 70 | cff->minor_version = short_tmp[0] << 8 | short_tmp[1]; 71 | 72 | /* major_version */ 73 | fread(short_tmp, 2, 1, fp); 74 | cff->major_version = short_tmp[0] << 8 | short_tmp[1]; 75 | 76 | /* constant pool */ 77 | fread(short_tmp, 2, 1, fp); 78 | cff->constant_pool_count = short_tmp[0] << 8 | short_tmp[1]; 79 | 80 | /* constant pool table */ 81 | parseConstantPool(fp, cff->constant_pool_count); 82 | 83 | /* access flag */ 84 | fread(short_tmp, 2, 1, fp); 85 | cff->access_flags = short_tmp[0] << 8 | short_tmp[1]; 86 | 87 | /* this class */ 88 | fread(short_tmp, 2, 1, fp); 89 | cff->this_class = short_tmp[0] << 8 | short_tmp[1]; 90 | 91 | /* super class */ 92 | fread(short_tmp, 2, 1, fp); 93 | cff->super_class = short_tmp[0] << 8 | short_tmp[1]; 94 | 95 | /* interface count */ 96 | fread(short_tmp, 2, 1, fp); 97 | cff->interface_count = short_tmp[0] << 8 | short_tmp[1]; 98 | 99 | /* interface pool table */ 100 | parseInterfacePool(fp, cff->interface_count); 101 | 102 | /* field count */ 103 | fread(short_tmp, 2, 1, fp); 104 | cff->fields_count = short_tmp[0] << 8 | short_tmp[1]; 105 | 106 | /* field pool table */ 107 | parseFieldPool(fp , cff->fields_count); 108 | 109 | /* method count */ 110 | fread(short_tmp, 2, 1, fp); 111 | cff->methods_count = short_tmp[0] << 8 | short_tmp[1]; 112 | 113 | /* method pool table */ 114 | parseMethodPool(fp, cff->methods_count); 115 | 116 | fclose(fp); 117 | return 0; 118 | } 119 | -------------------------------------------------------------------------------- /simple_jvm/constant_pool_parser.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Java Virtual Machine Implementation 3 | * 4 | * Copyright (C) 2013 Chun-Yu Wang 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include "simple_jvm.h" 11 | 12 | extern SimpleConstantPool simpleConstantPool; 13 | static const int tag_additional_byte_size[13] = { 14 | 0, 2, 0, 4, 4, 15 | 8, 8, 2, 2, 4, 16 | 4, 4, 4 17 | }; 18 | 19 | /* parse UTF-8 String */ 20 | static int parseCPString(FILE *fp, int index) 21 | { 22 | unsigned char short_tmp[2]; 23 | ConstantUTF8 *ptr = &simpleConstantPool.utf8CP[simpleConstantPool.utf8_used]; 24 | 25 | ptr->tag = CONSTANT_UTF8; 26 | ptr->index = index; 27 | 28 | fread(short_tmp, 2, 1, fp); 29 | ptr->string_size = short_tmp[0] << 8 | short_tmp[1]; 30 | ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_UTF8] + ptr->string_size; 31 | 32 | ptr->ptr = (unsigned char *) malloc(sizeof(unsigned char) * ptr->string_size + 1); 33 | memset(ptr->ptr, 0, ptr->string_size); 34 | fread(ptr->ptr , ptr->string_size , 1, fp); 35 | ptr->ptr[ptr->string_size] = '\0'; 36 | simpleConstantPool.utf8_used++; 37 | } 38 | 39 | /* parse Integer */ 40 | static int parseCPInteger(FILE *fp, int index) 41 | { 42 | unsigned char tmp[4]; 43 | ConstantInteger *ptr = &simpleConstantPool.integerCP[ simpleConstantPool.integer_used]; 44 | 45 | ptr->tag = CONSTANT_INTEGER; 46 | ptr->index = index; 47 | ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_INTEGER]; 48 | 49 | fread(tmp, 4, 1, fp); 50 | ptr->value = (tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3]); 51 | 52 | simpleConstantPool.integer_used++; 53 | } 54 | 55 | /* parse Float */ 56 | static int parseCPFloat(FILE *fp, int index) 57 | { 58 | unsigned char tmp[4]; 59 | ConstantFloat *ptr = &simpleConstantPool.floatCP[ simpleConstantPool.float_used]; 60 | 61 | ptr->tag = CONSTANT_FLOAT; 62 | ptr->index = index; 63 | ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_FLOAT]; 64 | 65 | fread(tmp, 4, 1, fp); 66 | ptr->value = (tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3]); 67 | 68 | simpleConstantPool.float_used++; 69 | } 70 | 71 | /* parse LONG */ 72 | static int parseCPLong(FILE *fp, int index) 73 | { 74 | unsigned char tmp[8]; 75 | ConstantLong *ptr = &simpleConstantPool.longCP[ simpleConstantPool.long_used]; 76 | 77 | ptr->tag = CONSTANT_LONG; 78 | ptr->index = index; 79 | ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_LONG]; 80 | 81 | fread(tmp, 8, 1, fp); 82 | memcpy(&ptr->value, tmp, 8); 83 | 84 | simpleConstantPool.long_used++; 85 | } 86 | 87 | /* parse Double */ 88 | static int parseCPDouble(FILE *fp, int index) 89 | { 90 | unsigned char tmp[8]; 91 | unsigned char tmp2[8]; 92 | int i, j; 93 | ConstantDouble *ptr = &simpleConstantPool.doubleCP[ simpleConstantPool.double_used]; 94 | 95 | ptr->tag = CONSTANT_DOUBLE; 96 | ptr->index = index; 97 | ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_DOUBLE]; 98 | 99 | fread(tmp, 8, 1, fp); 100 | for (i = 0, j = 7 ; i < 8 ; i++, j--) 101 | tmp2[j] = tmp[i]; 102 | memcpy(&ptr->value, tmp2, 8); 103 | 104 | simpleConstantPool.double_used++; 105 | } 106 | 107 | /* parse Constant Pool Class */ 108 | static int parseCPClass(FILE *fp, int index) 109 | { 110 | unsigned char short_tmp[2]; 111 | ConstantClassRef *ptr = &simpleConstantPool.clasz[simpleConstantPool.clasz_used]; 112 | 113 | ptr->tag = CONSTANT_CLASS; 114 | ptr->index = index; 115 | ptr->additional_byte_size = tag_additional_byte_size [CONSTANT_CLASS]; 116 | 117 | fread(short_tmp, 2, 1, fp); 118 | ptr->stringIndex = short_tmp[0] << 8 | short_tmp[1]; 119 | 120 | simpleConstantPool.clasz_used++; 121 | } 122 | 123 | /* parse Constant Pool String Ref */ 124 | static int parseCPStringRef(FILE *fp, int index) 125 | { 126 | unsigned char short_tmp[2]; 127 | ConstantStringRef *ptr = &simpleConstantPool.stringRef[simpleConstantPool.stringRef_used]; 128 | 129 | ptr->tag = CONSTANT_STRING_REF; 130 | ptr->index = index; 131 | ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_STRING_REF]; 132 | 133 | fread(short_tmp, 2, 1, fp); 134 | ptr->stringIndex = short_tmp[0] << 8 | short_tmp[1]; 135 | 136 | simpleConstantPool.stringRef_used++; 137 | } 138 | 139 | /* parse Constant Pool Field */ 140 | static int parseCPField(FILE *fp, int index) 141 | { 142 | unsigned char short_tmp[2]; 143 | ConstantFieldRef *ptr = &simpleConstantPool.field[simpleConstantPool.field_used]; 144 | 145 | ptr->tag = CONSTANT_FIELD_REF; 146 | ptr->index = index; 147 | ptr->additional_byte_size = tag_additional_byte_size [CONSTANT_FIELD_REF]; 148 | 149 | fread(short_tmp, 2, 1, fp); 150 | ptr->classIndex = short_tmp[0] << 8 | short_tmp[1]; 151 | 152 | fread(short_tmp, 2, 1, fp); 153 | ptr->nameAndTypeIndex = short_tmp[0] << 8 | short_tmp[1]; 154 | 155 | simpleConstantPool.field_used++; 156 | } 157 | 158 | /* parse Constant Pool Method */ 159 | static int parseCPMethod(FILE *fp, int index) 160 | { 161 | unsigned char short_tmp[2]; 162 | ConstantMethodRef *ptr = &simpleConstantPool.method[simpleConstantPool.method_used]; 163 | 164 | ptr->tag = CONSTANT_METHOD_REF; 165 | ptr->index = index; 166 | ptr->additional_byte_size = tag_additional_byte_size [CONSTANT_METHOD_REF]; 167 | 168 | fread(short_tmp, 2, 1, fp); 169 | ptr->classIndex = short_tmp[0] << 8 | short_tmp[1]; 170 | 171 | fread(short_tmp, 2, 1, fp); 172 | ptr->nameAndTypeIndex = short_tmp[0] << 8 | short_tmp[1]; 173 | 174 | simpleConstantPool.method_used++; 175 | } 176 | 177 | /* parse Constant Pool Interface */ 178 | static int parseCPInterface(FILE *fp, int index) 179 | { 180 | unsigned char short_tmp[2]; 181 | ConstantInterfaceRef *ptr = &simpleConstantPool.interface[simpleConstantPool.interface_used]; 182 | 183 | ptr->tag = CONSTANT_INTERFACE_REF; 184 | ptr->index = index; 185 | ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_INTERFACE_REF]; 186 | 187 | fread(short_tmp, 2, 1, fp); 188 | ptr->classIndex = short_tmp[0] << 8 | short_tmp[1]; 189 | 190 | fread(short_tmp, 2, 1, fp); 191 | ptr->nameAndTypeIndex = short_tmp[0] << 8 | short_tmp[1]; 192 | 193 | simpleConstantPool.interface_used++; 194 | } 195 | 196 | /* parse Constant Pool Interface */ 197 | static int parseCPNameAndType(FILE *fp, int index) 198 | { 199 | unsigned char short_tmp[2]; 200 | ConstantNameAndType *ptr = &simpleConstantPool.name_and_type[simpleConstantPool.name_and_type_used]; 201 | 202 | ptr->tag = CONSTANT_NAME_AND_TYPE; 203 | ptr->index = index; 204 | ptr->additional_byte_size = tag_additional_byte_size[CONSTANT_NAME_AND_TYPE]; 205 | 206 | fread(short_tmp, 2, 1, fp); 207 | ptr->nameIndex = short_tmp[0] << 8 | short_tmp[1]; 208 | 209 | fread(short_tmp, 2, 1, fp); 210 | ptr->typeIndex = short_tmp[0] << 8 | short_tmp[1]; 211 | 212 | simpleConstantPool.name_and_type_used++; 213 | } 214 | 215 | int parseConstantPool(FILE *fp, int count) 216 | { 217 | unsigned char tag = 0; 218 | int i = 0 ; 219 | int offset_start = 0; 220 | int offset_end = 0; 221 | for (i = 1 ; i < count ; i++) { 222 | fread(&tag, 1, 1, fp); 223 | offset_start = ftell(fp); 224 | switch (tag) { 225 | case CONSTANT_UTF8: 226 | parseCPString(fp, i); 227 | break; 228 | case CONSTANT_INTEGER: 229 | parseCPInteger(fp, i); 230 | break; 231 | case CONSTANT_FLOAT: 232 | parseCPFloat(fp, i); 233 | break; 234 | case CONSTANT_LONG: 235 | parseCPLong(fp, i); 236 | i++; 237 | break; 238 | case CONSTANT_DOUBLE: 239 | parseCPDouble(fp, i); 240 | i++; 241 | break; 242 | case CONSTANT_STRING_REF: 243 | parseCPStringRef(fp, i); 244 | break; 245 | case CONSTANT_CLASS: 246 | parseCPClass(fp, i); 247 | break; 248 | case CONSTANT_FIELD_REF: 249 | parseCPField(fp, i); 250 | break; 251 | case CONSTANT_METHOD_REF: 252 | parseCPMethod(fp, i); 253 | break; 254 | case CONSTANT_INTERFACE_REF: 255 | parseCPInterface(fp, i); 256 | break; 257 | case CONSTANT_NAME_AND_TYPE: 258 | parseCPNameAndType(fp, i); 259 | break; 260 | default: 261 | printf("\n!!!unknow tag = %02x!!!\n\n", tag); 262 | fseek(fp, -1, SEEK_CUR); 263 | break; 264 | }; 265 | offset_end = ftell(fp); 266 | } 267 | return 0; 268 | } 269 | 270 | /* find UTF8 */ 271 | ConstantUTF8 *findUTF8(SimpleConstantPool *p, int index) 272 | { 273 | int i; 274 | for (i = 0; i < p->utf8_used; i++) 275 | if (p->utf8CP[i].index == (index)) 276 | return &p->utf8CP[i]; 277 | return 0; 278 | } 279 | 280 | /* Find Class Reference */ 281 | ConstantStringRef *findStringRef(SimpleConstantPool *p, int index) 282 | { 283 | int i; 284 | for (i = 0; i < p->stringRef_used; i++) 285 | if (p->stringRef[i].index == (index)) 286 | return &p->stringRef[i]; 287 | return 0; 288 | } 289 | 290 | /* get UTF8String */ 291 | int getUTF8String(SimpleConstantPool *p, int index, int size, char *out) 292 | { 293 | int copy_size = 0; 294 | ConstantUTF8 *utf8 = findUTF8(p, index); 295 | memset(out, 0, size); 296 | if (utf8 != 0) { 297 | copy_size = utf8->string_size < size ? utf8->string_size : size; 298 | memcpy(out, utf8->ptr, copy_size); 299 | return copy_size; 300 | } 301 | return 0; 302 | } 303 | 304 | /* Find Class Reference */ 305 | ConstantClassRef *findClassRef(SimpleConstantPool *p, int index) 306 | { 307 | int i; 308 | for (i = 0; i < p->clasz_used; i++) 309 | if (p->clasz[i].index == (index)) 310 | return &p->clasz[i]; 311 | return 0; 312 | } 313 | 314 | /* Find Method Reference */ 315 | ConstantMethodRef *findMethodRef(SimpleConstantPool *p, int index) 316 | { 317 | int i; 318 | for (i = 0; i < p->method_used; i++) 319 | if (p->method[i].index == (index)) 320 | return &p->method[i]; 321 | return 0; 322 | } 323 | 324 | /* Find Name and Type Reference */ 325 | ConstantNameAndType *findNameAndType(SimpleConstantPool *p, int index) 326 | { 327 | int i; 328 | for (i = 0; i < p->name_and_type_used; i++) 329 | if (p->name_and_type[i].index == (index)) 330 | return &p->name_and_type[i]; 331 | return 0; 332 | } 333 | 334 | /* get integer from constant pool */ 335 | int get_integer_from_constant_pool(SimpleConstantPool *p, int index) 336 | { 337 | int i; 338 | for (i = 0; i < p->integer_used; i++) 339 | if (p->integerCP[i].index == (index)) 340 | return p->integerCP[i].value; 341 | return 0; 342 | } 343 | 344 | /* get long from constant pool */ 345 | long long get_long_from_constant_pool(SimpleConstantPool *p, int index) 346 | { 347 | int i; 348 | for (i = 0; i < p->long_used; i++) 349 | if (p->longCP[i].index == (index)) 350 | return p->longCP[i].value; 351 | return 0; 352 | } 353 | 354 | /* get float from constant pool */ 355 | float get_float_from_constant_pool(SimpleConstantPool *p, int index) 356 | { 357 | int i; 358 | for (i = 0; i < p->float_used; i++) 359 | if (p->floatCP[i].index == (index)) 360 | return p->floatCP[i].value; 361 | return 0.0f; 362 | } 363 | 364 | /* get double from constant pool */ 365 | double get_double_from_constant_pool(SimpleConstantPool *p, int index) 366 | { 367 | int i; 368 | for (i = 0; i < p->double_used; i++) 369 | if (p->doubleCP[i].index == (index)) 370 | return p->doubleCP[i].value; 371 | return 0.0f; 372 | } 373 | 374 | /* print constant pool table */ 375 | void printConstantPool(SimpleConstantPool *p) 376 | { 377 | int i, j; 378 | printf("ConstantUTF8 = \n"); 379 | for (i = 0; i < p->utf8_used ; i++) { 380 | printf("cp_index[%d], utf8[%d], tag = %d, size = %d, ", 381 | p->utf8CP[i].index, i, p->utf8CP[i].tag, 382 | p->utf8CP[i].string_size); 383 | for (j = 0 ; j < p->utf8CP[i].string_size ; j++) 384 | printf("%c", p->utf8CP[i].ptr[j]); 385 | printf("\n"); 386 | } 387 | printf("p->integer_used = %d\n", p->integer_used); 388 | if (p->integer_used > 0) { 389 | printf("Constant Integer= \n"); 390 | for (i = 0; i < p->integer_used ; i++) 391 | printf(" cp_index[%d], integer[%d], tag = %d, size = %d, %d\n", 392 | p->integerCP[i].index, i, p->integerCP[i].tag, 393 | p->integerCP[i].additional_byte_size, 394 | p->integerCP[i].value); 395 | } 396 | printf("p->float_used = %d\n", p->float_used); 397 | if (p->float_used > 0) { 398 | printf("Constant Float= \n"); 399 | for (i = 0; i < p->float_used ; i++) 400 | printf(" cp_index[%d], float[%d], tag = %d, size = %d, %.4f\n", 401 | p->floatCP[i].index, i, p->floatCP[i].tag, 402 | p->floatCP[i].additional_byte_size, 403 | p->floatCP[i].value); 404 | } 405 | printf("p->double_used = %d\n", p->double_used); 406 | if (p->double_used > 0) { 407 | printf("Constant Double= \n"); 408 | for (i = 0; i < p->double_used ; i++) 409 | printf(" cp_index[%d], double[%d], tag = %d, size = %d, %.5f\n", 410 | p->doubleCP[i].index, i, p->doubleCP[i].tag, 411 | p->doubleCP[i].additional_byte_size, 412 | p->doubleCP[i].value); 413 | } 414 | 415 | printf("p->clasz_used = %d\n", p->clasz_used); 416 | if (p->clasz_used > 0) { 417 | printf("Constant Class Pool= \n"); 418 | for (i = 0; i < p->clasz_used ; i++) { 419 | ConstantUTF8 *ptr = findUTF8(p, p->clasz[i].stringIndex); 420 | printf(" cp_index[%d], class[%d], tag = %d, size = %d, %d", 421 | p->clasz[i].index, i, p->clasz[i].tag, 422 | p->clasz[i].additional_byte_size, 423 | p->clasz[i].stringIndex 424 | ); 425 | if (ptr != 0) { 426 | printf(" "); 427 | for (j = 0 ; j < ptr->string_size ; j++) 428 | printf("%c", ptr->ptr[j]); 429 | printf(" \n"); 430 | } else { 431 | printf("\n"); 432 | } 433 | } 434 | } 435 | 436 | printf("p->stringRef_used = %d\n", p->stringRef_used); 437 | if (p->stringRef_used > 0) { 438 | printf("Constant String Reference= \n"); 439 | for (i = 0; i < p->stringRef_used; i++) { 440 | ConstantUTF8 *ptr = findUTF8(p, p->stringRef[i].stringIndex); 441 | printf(" cp_index[%d], strRef[%d], tag = %d, size = %d, %d", 442 | p->stringRef[i].index, i, p->stringRef[i].tag, 443 | p->stringRef[i].additional_byte_size, 444 | p->stringRef[i].stringIndex); 445 | if (ptr != 0) { 446 | printf(" "); 447 | for (j = 0 ; j < ptr->string_size ; j++) 448 | printf("%c", ptr->ptr[j]); 449 | printf(" \n"); 450 | } else { 451 | printf("\n"); 452 | } 453 | } 454 | } 455 | printf("p->field_used = %d\n", p->field_used); 456 | if (p->field_used > 0) { 457 | printf("Constant Field = \n"); 458 | for (i = 0; i < p->field_used; i++) { 459 | ConstantClassRef *ptr = findClassRef(p, p->field[i].classIndex); 460 | ConstantNameAndType *ptr2 = findNameAndType(p, p->field[i].nameAndTypeIndex); 461 | 462 | printf(" cp_index[%d], field[%d], tag = %d, size = %d, cls %d, nat= %d", 463 | p->field[i].index, i, p->field[i].tag, 464 | p->field[i].additional_byte_size, 465 | p->field[i].classIndex, 466 | p->field[i].nameAndTypeIndex); 467 | if (ptr != 0) { 468 | ConstantUTF8 *name = findUTF8(p, ptr->stringIndex); 469 | if (name != 0) { 470 | printf(" "); 471 | for (j = 0 ; j < name->string_size ; j++) 472 | printf("%c", name->ptr[j]); 473 | printf(" \n"); 474 | } 475 | } else { 476 | printf("\n"); 477 | } 478 | if (ptr2 != 0) { 479 | ConstantUTF8 *name = findUTF8(p, ptr2->nameIndex); 480 | ConstantUTF8 *type = findUTF8(p, ptr2->typeIndex); 481 | if (name != 0) { 482 | printf(" "); 483 | for (j = 0 ; j < name->string_size ; j++) 484 | printf("%c", name->ptr[j]); 485 | printf(" \n"); 486 | } 487 | if (type != 0) { 488 | printf(" "); 489 | for (j = 0 ; j < type->string_size ; j++) 490 | printf("%c", type->ptr[j]); 491 | printf(" \n"); 492 | } 493 | } 494 | } 495 | } 496 | printf("p->method_used= %d\n", p->method_used); 497 | if (p->method_used > 0) { 498 | printf("Constant Method= \n"); 499 | for (i = 0; i < p->method_used; i++) { 500 | ConstantClassRef *ptr = findClassRef(p, p->method[i].classIndex); 501 | ConstantNameAndType *ptr2 = findNameAndType(p, p->method[i].nameAndTypeIndex); 502 | 503 | printf(" cp_index[%d], method[%d], tag = %d, size = %d, cls %d, nat= %d", 504 | p->method[i].index, i, p->method[i].tag, 505 | p->method[i].additional_byte_size, 506 | p->method[i].classIndex, 507 | p->method[i].nameAndTypeIndex); 508 | if (ptr != 0) { 509 | ConstantUTF8 *name = findUTF8(p, ptr->stringIndex); 510 | if (name != 0) { 511 | printf(" "); 512 | for (j = 0 ; j < name->string_size ; j++) 513 | printf("%c", name->ptr[j]); 514 | printf(" \n"); 515 | } 516 | } else { 517 | printf("\n"); 518 | } 519 | if (ptr2 != 0) { 520 | ConstantUTF8 *name = findUTF8(p, ptr2->nameIndex); 521 | ConstantUTF8 *type = findUTF8(p, ptr2->typeIndex); 522 | if (name != 0) { 523 | printf(" "); 524 | for (j = 0 ; j < name->string_size ; j++) 525 | printf("%c", name->ptr[j]); 526 | printf(" \n"); 527 | } 528 | if (type != 0) { 529 | printf(" "); 530 | for (j = 0 ; j < type->string_size ; j++) 531 | printf("%c", type->ptr[j]); 532 | printf(" \n"); 533 | } 534 | } 535 | } 536 | } 537 | } 538 | -------------------------------------------------------------------------------- /simple_jvm/field_pool_parser.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Java Virtual Machine Implementation 3 | * 4 | * Copyright (C) 2013 Chun-Yu Wang 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include "simple_jvm.h" 11 | 12 | extern SimpleInterfacePool simpleInterfacePool; 13 | extern SimpleFieldPool simpleFieldPool; 14 | extern SimpleConstantPool simpleConstantPool; 15 | 16 | static int parseAttr(FieldInfo *ptr, FILE *fp) 17 | { 18 | int i; 19 | AttributeInfo *tmp = 0; 20 | unsigned char short_tmp[2]; 21 | unsigned char integer_tmp[4]; 22 | 23 | printf("field attributes_count = %d\n", ptr->attributes_count); 24 | for (i = 0; i < ptr->attributes_count ; i ++) { 25 | tmp = &ptr->attributes[i]; 26 | fread(short_tmp, 2, 1, fp); 27 | tmp->attribute_name_index = short_tmp[0] << 8 | short_tmp[1]; 28 | 29 | fread(integer_tmp, 4, 1, fp); 30 | tmp->attribute_length = integer_tmp[0] << 24 | integer_tmp[1] << 16 | 31 | integer_tmp[2] << 8 | integer_tmp[0] ; 32 | 33 | printf("field tmp->attribute_length = %d\n", tmp->attribute_length); 34 | 35 | tmp->info = (unsigned char *) malloc(sizeof(unsigned char) * tmp->attribute_length); 36 | fread(tmp->info, tmp->attribute_length, 1, fp); 37 | } 38 | } 39 | 40 | /* parse Field Pool */ 41 | static int parseFP(FILE *fp) 42 | { 43 | int i = 0; 44 | unsigned char short_tmp[2]; 45 | FieldInfo *ptr = &simpleFieldPool.field[simpleFieldPool.field_used]; 46 | 47 | /* access flag */ 48 | fread(short_tmp, 2, 1, fp); 49 | ptr->access_flags = short_tmp[0] << 8 | short_tmp[1]; 50 | 51 | /* name index */ 52 | fread(short_tmp, 2, 1, fp); 53 | ptr->name_index = short_tmp[0] << 8 | short_tmp[1]; 54 | 55 | /* descriptor index */ 56 | fread(short_tmp, 2, 1, fp); 57 | ptr->descriptor_index = short_tmp[0] << 8 | short_tmp[1]; 58 | 59 | /* attributes count */ 60 | fread(short_tmp, 2, 1, fp); 61 | ptr->attributes_count = short_tmp[0] << 8 | short_tmp[1]; 62 | 63 | ptr->attributes = (AttributeInfo *) malloc(sizeof(AttributeInfo) * ptr->attributes_count); 64 | memset(ptr->attributes, 0, sizeof(AttributeInfo) * ptr->attributes_count); 65 | 66 | /* parse attributes */ 67 | parseAttr(ptr, fp); 68 | simpleFieldPool.field_used++; 69 | return 0; 70 | } 71 | 72 | void printFieldPool(SimpleConstantPool *p, SimpleFieldPool *fp) 73 | { 74 | int i, j; 75 | 76 | if (fp->field_used > 0) { 77 | printf("Field Pool= \n"); 78 | for (i = 0; i < fp->field_used ; i++) { 79 | ConstantUTF8 *ptr = findUTF8(p, fp->field[i].name_index); 80 | printf("field[%d], attr_count = %d, %d", 81 | i, fp->field[i].attributes_count, 82 | fp->field[i].name_index); 83 | if (ptr != 0) { 84 | printf(" "); 85 | for (j = 0 ; j < ptr->string_size ; j++) 86 | printf("%c", ptr->ptr[j]); 87 | printf(" \n"); 88 | } else { 89 | printf("\n"); 90 | } 91 | } 92 | } 93 | } 94 | 95 | int parseFieldPool(FILE *fp, int count) 96 | { 97 | int i; 98 | for (i = 0; i < count ; i ++) 99 | parseFP(fp); 100 | return 0; 101 | } 102 | -------------------------------------------------------------------------------- /simple_jvm/free_pool.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Java Virtual Machine Implementation 3 | * 4 | * Copyright (C) 2013 Chun-Yu Wang 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include "simple_jvm.h" 11 | 12 | extern SimpleInterfacePool simpleInterfacePool; 13 | extern SimpleFieldPool simpleFieldPool; 14 | extern SimpleConstantPool simpleConstantPool; 15 | extern SimpleMethodPool simpleMethodPool; 16 | 17 | void free_pools() 18 | { 19 | int i, j; 20 | MethodInfo *method = 0; 21 | AttributeInfo *attr = 0; 22 | for (i = 0; i < simpleMethodPool.method_used; i++) { 23 | method = &simpleMethodPool.method[i]; 24 | for (j = 0; j < method->attributes_count ; j++) { 25 | attr = &method->attributes[j]; 26 | free(attr->info); 27 | memset(attr, 0, sizeof(AttributeInfo)); 28 | } 29 | free(method->attributes); 30 | memset(method, 0, sizeof(MethodInfo)); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /simple_jvm/interface_pool_parser.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Java Virtual Machine Implementation 3 | * 4 | * Copyright (C) 2013 Chun-Yu Wang 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include "simple_jvm.h" 11 | 12 | extern SimpleInterfacePool simpleInterfacePool; 13 | extern SimpleConstantPool simpleConstantPool; 14 | 15 | /* parse Interface Pool Class */ 16 | static int parseIPClass(FILE *fp, int index) 17 | { 18 | unsigned char short_tmp[2]; 19 | ConstantClassRef *ptr = &simpleInterfacePool.clasz[simpleInterfacePool.clasz_used]; 20 | 21 | ptr->tag = CONSTANT_CLASS; 22 | ptr->index = index; 23 | ptr->additional_byte_size = 2; 24 | 25 | fread(short_tmp, 2, 1, fp); 26 | ptr->stringIndex = short_tmp[0] << 8 | short_tmp[1]; 27 | 28 | simpleInterfacePool.clasz_used++; 29 | } 30 | 31 | void printInterfacePool(SimpleConstantPool *p, SimpleInterfacePool *ip) 32 | { 33 | int i, j; 34 | 35 | if (ip->clasz_used > 0) { 36 | printf("Interface Class Pool= \n"); 37 | for (i = 0; i < ip->clasz_used; i++) { 38 | ConstantUTF8 *ptr = findUTF8(p, ip->clasz[i].stringIndex); 39 | printf(" ip_index[%d], class[%d], tag = %d, size = %d, %d", 40 | ip->clasz[i].index, i, ip->clasz[i].tag, 41 | ip->clasz[i].additional_byte_size, 42 | ip->clasz[i].stringIndex); 43 | if (ptr != 0) { 44 | printf(" "); 45 | for (j = 0 ; j < ptr->string_size ; j++) 46 | printf("%c", ptr->ptr[j]); 47 | printf(" \n"); 48 | } else { 49 | printf("\n"); 50 | } 51 | } 52 | } 53 | } 54 | 55 | int parseInterfacePool(FILE *fp, int count) 56 | { 57 | int i; 58 | for (i = 1; i < count; i++) 59 | parseIPClass(fp, 1); 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /simple_jvm/java_lib.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Java Virtual Machine Implementation 3 | * 4 | * Copyright (C) 2013 Chun-Yu Wang 5 | */ 6 | 7 | #include "java_lib.h" 8 | 9 | int java_lang_math_random(StackFrame *stack, SimpleConstantPool *p, char *type) 10 | { 11 | double r = 0.0f; 12 | int i; 13 | int times = 0; 14 | srand(time(0)); 15 | times = rand() % 100; 16 | for (i = 0; i < times; i++) 17 | r = ((double) rand() / (double) RAND_MAX); 18 | #if SIMPLE_JVM_DEBUG 19 | printf("rand r = %f\n", r); 20 | #endif 21 | pushDouble(stack, r); 22 | return 0; 23 | } 24 | static java_lang_method method_table[] = { 25 | {"java/lang/Math", "random", java_lang_math_random} 26 | }; 27 | 28 | static int java_lang_method_size = sizeof(method_table) / sizeof(java_lang_method); 29 | 30 | java_lang_method *find_java_lang_method(char *cls_name, char *method_name) 31 | { 32 | int i; 33 | for (i = 0; i < java_lang_method_size; i++) 34 | if (strcmp(cls_name, method_table[i].clzname) == 0 && 35 | strcmp(method_name, method_table[i].methodname) == 0) 36 | return &method_table[i]; 37 | return 0; 38 | } 39 | 40 | int invoke_java_lang_library(StackFrame *stack, SimpleConstantPool *p, 41 | char *cls_name, char *method_name, char *type) 42 | { 43 | java_lang_method *method = find_java_lang_method(cls_name, method_name); 44 | if (method != 0) { 45 | #if SIMPLE_JVM_DEBUG 46 | printf("invoke %s/%s %s\n", method->clzname, method->methodname, type); 47 | #endif 48 | method->method_runtime(stack, p, type); 49 | return 1; 50 | } 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /simple_jvm/java_lib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Java Virtual Machine Implementation 3 | * 4 | * Copyright (C) 2013 Chun-Yu Wang 5 | */ 6 | 7 | #ifndef SIMPLE_JVM_JAVA_LIBRARY_H 8 | #define SIMPLE_JVM_JAVA_LIBRARY_H 9 | #include "simple_jvm.h" 10 | typedef int (*java_lang_lib) ( StackFrame *stack, SimpleConstantPool *p, char *type); 11 | 12 | typedef struct _java_lang_method { 13 | char *clzname; 14 | char *methodname; 15 | java_lang_lib method_runtime; 16 | } java_lang_method; 17 | 18 | int invoke_java_lang_library(StackFrame *stack, SimpleConstantPool *p, 19 | char *cls_name, char *method_name, char *type); 20 | #endif 21 | -------------------------------------------------------------------------------- /simple_jvm/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Java Virtual Machine Implementation 3 | * 4 | * Copyright (C) 2013 Chun-Yu Wang 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include "simple_jvm.h" 11 | 12 | /* 13 | * Simple JVM stores integer-only intrinsically, 14 | * and parses one class file called Foo.class in the same directory. 15 | * 16 | * We limit its capability for quick implementation. 17 | */ 18 | SimpleConstantPool simpleConstantPool; 19 | SimpleInterfacePool simpleInterfacePool; 20 | SimpleFieldPool simpleFieldPool; 21 | SimpleMethodPool simpleMethodPool; 22 | StackFrame stackFrame; 23 | LocalVariables localVariables; 24 | 25 | int main(int argc, char *argv[]) 26 | { 27 | ClassFileFormat cff; 28 | 29 | /* Initialize All Pools */ 30 | memset(&cff, 0, sizeof(ClassFileFormat)); 31 | memset(&simpleConstantPool, 0, sizeof(SimpleConstantPool)); 32 | memset(&simpleInterfacePool, 0, sizeof(SimpleInterfacePool)); 33 | memset(&simpleFieldPool, 0, sizeof(SimpleFieldPool)); 34 | memset(&simpleMethodPool, 0, sizeof(SimpleMethodPool)); 35 | memset(&localVariables, 0, sizeof(LocalVariables)); 36 | 37 | if (argc < 2) { 38 | printf("%s [class] \n", argv[0]); 39 | return 0; 40 | } 41 | parseJavaClassFile(argv[1], &cff); 42 | 43 | #if SIMPLE_JVM_DEBUG 44 | printConstantPool(&simpleConstantPool); 45 | printMethodPool(&simpleConstantPool, &simpleMethodPool); 46 | printClassFileFormat(&cff); 47 | #endif 48 | 49 | MethodInfo *init = findMethodInPool(&simpleConstantPool, 50 | &simpleMethodPool, 51 | "", 6); 52 | if (init != 0) { 53 | #if SIMPLE_JVM_DEBUG 54 | printMethodAttributes(&simpleConstantPool, init); 55 | #endif 56 | stackInit(&stackFrame, 500); 57 | executeMethod(init, &stackFrame, &simpleConstantPool); 58 | } 59 | free_pools(); 60 | 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /simple_jvm/method_pool_parser.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Java Virtual Machine Implementation 3 | * 4 | * Copyright (C) 2013 Chun-Yu Wang 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include "simple_jvm.h" 11 | 12 | extern SimpleInterfacePool simpleInterfacePool; 13 | extern SimpleFieldPool simpleFieldPool; 14 | extern SimpleMethodPool simpleMethodPool; 15 | extern SimpleConstantPool simpleConstantPool; 16 | 17 | static int parseMethodAttr(MethodInfo *ptr, FILE *fp) 18 | { 19 | int i; 20 | AttributeInfo *tmp = 0; 21 | unsigned char short_tmp[2]; 22 | unsigned char integer_tmp[4]; 23 | for (i = 0; i < ptr->attributes_count; i++) { 24 | tmp = &ptr->attributes[i]; 25 | fread(short_tmp, 2, 1, fp); 26 | tmp->attribute_name_index = short_tmp[0] << 8 | short_tmp[1]; 27 | fread(integer_tmp, 4, 1, fp); 28 | tmp->attribute_length = integer_tmp[0] << 24 | integer_tmp[1] << 16 | 29 | integer_tmp[2] << 8 | integer_tmp[3]; 30 | 31 | tmp->info = (unsigned char *) malloc(sizeof(unsigned char) * tmp->attribute_length); 32 | fread(tmp->info, tmp->attribute_length, 1, fp); 33 | } 34 | } 35 | 36 | /* parse Method Pool */ 37 | static int parseMP(FILE *fp) 38 | { 39 | int i = 0; 40 | unsigned char short_tmp[2]; 41 | MethodInfo *ptr = &simpleMethodPool.method[simpleMethodPool.method_used]; 42 | 43 | /* access flag */ 44 | fread(short_tmp, 2, 1, fp); 45 | ptr->access_flags = short_tmp[0] << 8 | short_tmp[1]; 46 | 47 | /* name index */ 48 | fread(short_tmp, 2, 1, fp); 49 | ptr->name_index = short_tmp[0] << 8 | short_tmp[1]; 50 | 51 | /* descriptor index */ 52 | fread(short_tmp, 2, 1, fp); 53 | ptr->descriptor_index = short_tmp[0] << 8 | short_tmp[1]; 54 | 55 | /* attributes count */ 56 | fread(short_tmp, 2, 1, fp); 57 | ptr->attributes_count = short_tmp[0] << 8 | short_tmp[1]; 58 | 59 | ptr->attributes = (AttributeInfo *) malloc(sizeof(AttributeInfo) * ptr->attributes_count); 60 | memset(ptr->attributes, 0, sizeof(AttributeInfo) * ptr->attributes_count); 61 | /* parse method attributes */ 62 | parseMethodAttr(ptr, fp); 63 | simpleMethodPool.method_used++; 64 | return 0; 65 | } 66 | 67 | /* Find Method from Pool */ 68 | MethodInfo *findMethodInPool(SimpleConstantPool *p, 69 | SimpleMethodPool *mp, 70 | char *method_name, int size) 71 | { 72 | int i; 73 | int cmp_size = 0; 74 | if (mp->method_used > 0) { 75 | for (i = 0; i < mp->method_used; i++) { 76 | ConstantUTF8 *name = findUTF8(p, mp->method[i].name_index); 77 | if (size == name->string_size && 78 | strncmp(method_name, name->ptr, size) == 0) 79 | return &mp->method[i]; 80 | } 81 | } 82 | return 0; 83 | } 84 | 85 | /* Print Method Attributes */ 86 | void printMethodAttributes(SimpleConstantPool *p, 87 | MethodInfo *method) 88 | { 89 | int i; 90 | char name[255]; 91 | AttributeInfo *attr = 0; 92 | 93 | for (i = 0; i < method->attributes_count; i++) { 94 | attr = &method->attributes[i]; 95 | getUTF8String(p, attr->attribute_name_index, 255, name); 96 | printf("attribute name = %s\n", name); 97 | } 98 | } 99 | 100 | /* Print Method Pool */ 101 | void printMethodPool(SimpleConstantPool *p, SimpleMethodPool *mp) 102 | { 103 | int i, j; 104 | if (mp->method_used > 0) { 105 | printf("Method Pool= \n"); 106 | for (i = 0; i < mp->method_used; i++) { 107 | ConstantUTF8 *ptr = findUTF8(p, mp->method[i].name_index); 108 | ConstantUTF8 *ptr2 = findUTF8(p, mp->method[i].descriptor_index); 109 | ConstantMethodRef *mRefPtr = findMethodRef(p, mp->method[i].name_index); 110 | printf("method[%d], attr_count = %d, %d", 111 | i, mp->method[i].attributes_count, 112 | mp->method[i].name_index); 113 | if (ptr != 0) { 114 | printf(" "); 115 | for (j = 0 ; j < ptr->string_size ; j++) 116 | printf("%c", ptr->ptr[j]); 117 | printf(" \n"); 118 | } 119 | #if 0 120 | else if (mRefPtr != 0) { 121 | ConstantClassRef *clazz = findClassRef(p, mRefPtr->classIndex); 122 | if (clazz != 0) { 123 | ConstantUTF8 *name = findUTF8(p, clazz->stringIndex); 124 | if (name != 0) { 125 | printf(" "); 126 | for (j = 0 ; j < name->string_size ; j++) 127 | printf("%c", name->ptr[j]); 128 | printf(" "); 129 | 130 | } 131 | } 132 | ConstantNameAndType *nameAndType = findNameAndType(p, mRefPtr->nameAndTypeIndex); 133 | if (nameAndType != 0) { 134 | ConstantUTF8 *name = findUTF8(p, nameAndType->nameIndex); 135 | ConstantUTF8 *type = findUTF8(p, nameAndType->typeIndex); 136 | 137 | if (name != 0) { 138 | printf(" "); 139 | for (j = 0 ; j < name->string_size ; j++) 140 | printf("%c", name->ptr[j]); 141 | printf(" "); 142 | } 143 | if (type != 0) { 144 | printf(" "); 145 | for (j = 0 ; j < type->string_size ; j++) 146 | printf("%c", type->ptr[j]); 147 | printf(" "); 148 | } 149 | } 150 | printf("\n"); 151 | } 152 | #endif 153 | else { 154 | printf("\n"); 155 | continue; 156 | } 157 | if (ptr2 != 0) { 158 | printf("Descriptor "); 159 | for (j = 0 ; j < ptr2->string_size ; j++) 160 | printf("%c", ptr2->ptr[j]); 161 | printf(" \n"); 162 | } 163 | printMethodAttributes(p, &mp->method[i]); 164 | } 165 | } 166 | } 167 | 168 | int parseMethodPool(FILE *fp, int count) 169 | { 170 | int i; 171 | for (i = 0; i < count; i ++) 172 | parseMP(fp); 173 | return 0; 174 | } 175 | -------------------------------------------------------------------------------- /simple_jvm/simple_jvm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Java Virtual Machine Implementation 3 | * 4 | * Copyright (C) 2013 Chun-Yu Wang 5 | */ 6 | 7 | #ifndef SIMPLE_JVM_H 8 | #define SIMPLE_JVM_H 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | typedef unsigned short u2; 15 | typedef unsigned char byte; 16 | 17 | /* Java Class File */ 18 | typedef struct _ClassFileFormat { 19 | byte magic_number[4]; 20 | u2 minor_version; 21 | u2 major_version; 22 | u2 constant_pool_count; 23 | /* constant pool */ 24 | u2 access_flags; 25 | u2 this_class; 26 | u2 super_class; 27 | 28 | u2 interface_count; 29 | /* interface pool */ 30 | u2 fields_count; 31 | /* fields pool */ 32 | u2 methods_count; 33 | /* method pool */ 34 | u2 attributes_count; 35 | /* attributes pool */ 36 | } ClassFileFormat; 37 | 38 | /* 39 | * TAG 40 | * 1 UTF-8 String 41 | * 3 Integer 42 | * 4 Float 43 | * 5 Long 44 | * 6 Double 45 | * 7 Class reference 46 | * 8 String reference 47 | * 9 Field reference 48 | * 10 Method reference 49 | * 11 Interface method reference 50 | * 12 Name and type descriptor 51 | * */ 52 | #define CONSTANT_UTF8 1 53 | #define CONSTANT_INTEGER 3 54 | #define CONSTANT_FLOAT 4 55 | #define CONSTANT_LONG 5 56 | #define CONSTANT_DOUBLE 6 57 | 58 | #define CONSTANT_CLASS 7 59 | #define CONSTANT_STRING_REF 8 60 | #define CONSTANT_FIELD_REF 9 61 | #define CONSTANT_METHOD_REF 10 62 | #define CONSTANT_INTERFACE_REF 11 63 | #define CONSTANT_NAME_AND_TYPE 12 64 | 65 | typedef struct _ConstantUTF8 { 66 | int index; 67 | unsigned char tag; 68 | int additional_byte_size; 69 | u2 string_size; 70 | unsigned char *ptr; 71 | } ConstantUTF8; 72 | 73 | typedef struct _ConstantInteger { 74 | int index; 75 | unsigned char tag; 76 | int additional_byte_size; 77 | int value; 78 | } ConstantInteger; 79 | 80 | typedef struct _ConstantFloat { 81 | int index; 82 | unsigned char tag; 83 | int additional_byte_size; 84 | float value; 85 | } ConstantFloat; 86 | 87 | typedef struct _ConstantLong { 88 | int index; 89 | unsigned char tag; 90 | int additional_byte_size; 91 | long long value; 92 | } ConstantLong; 93 | 94 | typedef struct _ConstantDouble { 95 | int index; 96 | unsigned char tag; 97 | int additional_byte_size; 98 | double value; 99 | } ConstantDouble; 100 | 101 | typedef struct _ConstantClassRef { 102 | int index; 103 | unsigned char tag; 104 | int additional_byte_size; 105 | u2 stringIndex; 106 | } ConstantClassRef; 107 | 108 | typedef struct _ConstantStringRef { 109 | int index; 110 | unsigned char tag; 111 | int additional_byte_size; 112 | u2 stringIndex; 113 | } ConstantStringRef; 114 | 115 | typedef struct _ConstantFieldRef { 116 | int index; 117 | unsigned char tag; 118 | int additional_byte_size; 119 | u2 classIndex; 120 | u2 nameAndTypeIndex; 121 | } ConstantFieldRef; 122 | 123 | typedef struct _ConstantMethodRef { 124 | int index; 125 | unsigned char tag; 126 | int additional_byte_size; 127 | u2 classIndex; 128 | u2 nameAndTypeIndex; 129 | } ConstantMethodRef; 130 | 131 | typedef struct _ConstantInterfaceRef { 132 | int index; 133 | unsigned char tag; 134 | int additional_byte_size; 135 | u2 classIndex; 136 | u2 nameAndTypeIndex; 137 | } ConstantInterfaceRef; 138 | 139 | typedef struct _ConstantNameAndType { 140 | int index; 141 | unsigned char tag; 142 | int additional_byte_size; 143 | u2 nameIndex; 144 | u2 typeIndex; 145 | } ConstantNameAndType; 146 | 147 | typedef struct _SimpleConstantPool { 148 | /* UTF-8 String */ 149 | ConstantUTF8 utf8CP[200]; 150 | int utf8_used; 151 | 152 | /* Integer */ 153 | ConstantInteger integerCP[100]; 154 | int integer_used; 155 | 156 | /* Float */ 157 | ConstantFloat floatCP[100]; 158 | int float_used; 159 | 160 | /* Long */ 161 | ConstantLong longCP[100]; 162 | int long_used; 163 | 164 | /* Double */ 165 | ConstantDouble doubleCP[100]; 166 | int double_used; 167 | 168 | /* Class Reference */ 169 | ConstantClassRef clasz[100]; 170 | int clasz_used; 171 | 172 | /* String Reference */ 173 | ConstantStringRef stringRef[100]; 174 | int stringRef_used; 175 | 176 | /* Field Reference */ 177 | ConstantFieldRef field[100]; 178 | int field_used; 179 | 180 | /* Method Reference */ 181 | ConstantMethodRef method[100]; 182 | int method_used; 183 | 184 | /* Interface Reference */ 185 | ConstantInterfaceRef interface[100]; 186 | int interface_used; 187 | 188 | /* Name And Type Reference */ 189 | ConstantNameAndType name_and_type[100]; 190 | int name_and_type_used; 191 | } SimpleConstantPool; 192 | 193 | typedef struct _SimpleInterfacePool { 194 | /* Class Reference */ 195 | ConstantClassRef clasz[100]; 196 | int clasz_used; 197 | } SimpleInterfacePool; 198 | 199 | /* Attribute Info */ 200 | typedef struct _AttributeInfo { 201 | u2 attribute_name_index; 202 | int attribute_length; 203 | unsigned char *info; 204 | } AttributeInfo; 205 | 206 | /* Code Attributes */ 207 | typedef struct _CodeAttribute { 208 | u2 attribute_name_index; 209 | int attribute_length; 210 | u2 max_stack; 211 | u2 max_locals; 212 | int code_length; 213 | unsigned char *code; // [code_length]; 214 | #if 0 215 | u2 exception_table_length; 216 | Exception_table* exception_table; //[exception_table_length]; 217 | u2 attributes_count; 218 | attribute_info* attributes; //[attributes_count]; 219 | #endif 220 | } CodeAttribute; 221 | 222 | /* Field Info */ 223 | typedef struct _FieldInfo { 224 | u2 access_flags; 225 | u2 name_index; 226 | u2 descriptor_index; 227 | u2 attributes_count; 228 | AttributeInfo *attributes; 229 | } FieldInfo; 230 | 231 | /* Simple Field Pool */ 232 | typedef struct _SimpleFieldPool { 233 | FieldInfo field[100]; 234 | int field_used; 235 | } SimpleFieldPool; 236 | 237 | /* Method Info */ 238 | typedef struct _MethodInfo { 239 | u2 access_flags; 240 | u2 name_index; 241 | u2 descriptor_index; 242 | u2 attributes_count; 243 | AttributeInfo *attributes; 244 | } MethodInfo; 245 | 246 | /* Simple Method Pool */ 247 | typedef struct _SimpleMethodPool { 248 | MethodInfo method[100]; 249 | int method_used; 250 | } SimpleMethodPool; 251 | 252 | /* constant pool parser */ 253 | int parseConstantPool(FILE *fp, int count); 254 | void printConstantPool(SimpleConstantPool *p); 255 | ConstantUTF8 *findUTF8(SimpleConstantPool *p, int index); 256 | ConstantStringRef *findStringRef(SimpleConstantPool *p, int index); 257 | int getUTF8String(SimpleConstantPool *p, int index, int size, char *out); 258 | ConstantClassRef *findClassRef(SimpleConstantPool *p , int index); 259 | ConstantMethodRef *findMethodRef(SimpleConstantPool *p , int index); 260 | ConstantNameAndType *findNameAndType(SimpleConstantPool *p , int index); 261 | 262 | int get_integer_from_constant_pool(SimpleConstantPool *p, int index); 263 | long long get_long_from_constant_pool(SimpleConstantPool *p, int index); 264 | float get_float_from_constant_pool(SimpleConstantPool *p, int index); 265 | double get_double_from_constant_pool(SimpleConstantPool *p, int index); 266 | 267 | /* Interface Pool Parser */ 268 | int parseInterfacePool(FILE *fp, int count); 269 | void printInterfacePool( SimpleConstantPool *p, SimpleInterfacePool *ip); 270 | 271 | /* Field Pool Parser */ 272 | int parseFieldPool(FILE *fp, int count); 273 | void printFieldPool( SimpleConstantPool *p, SimpleFieldPool *fp); 274 | 275 | /* Method Pool Parser */ 276 | int parseMethodPool(FILE *fp, int count); 277 | void printMethodPool( SimpleConstantPool *p, SimpleMethodPool *fp); 278 | MethodInfo *findMethodInPool(SimpleConstantPool *p, 279 | SimpleMethodPool *mp, 280 | char *method_name, int size); 281 | void printMethodAttributes(SimpleConstantPool *p, 282 | MethodInfo *method); 283 | 284 | /* Java Class File Parser */ 285 | int parseJavaClassFile(char *file, ClassFileFormat *cff); 286 | void printClassFileFormat(ClassFileFormat *cff); 287 | 288 | /* Free Pools */ 289 | void free_pools(); 290 | 291 | /* Stack Frame */ 292 | #define STACK_ENTRY_NONE 0 293 | #define STACK_ENTRY_INT 1 294 | #define STACK_ENTRY_REF 2 295 | #define STACK_ENTRY_LONG 3 296 | #define STACK_ENTRY_DOUBLE 4 297 | #define STACK_ENTRY_FLOAT 5 298 | 299 | typedef struct _StackEntry { 300 | unsigned char entry[8]; 301 | int type; 302 | } StackEntry; 303 | 304 | typedef struct _StackFrame { 305 | int max_size; 306 | int size; 307 | StackEntry *store; 308 | } StackFrame; 309 | void stackInit(StackFrame *stack, int entry_size); 310 | 311 | void pushInt (StackFrame *stack, int value); 312 | void pushLong (StackFrame *stack, long long value); 313 | void pushDouble (StackFrame *stack, double value); 314 | void pushFloat (StackFrame *stack, float value); 315 | void pushRef (StackFrame *stack, int value); 316 | 317 | int popInt (StackFrame *stack); 318 | long long popLong (StackFrame *stack); 319 | double popDouble (StackFrame *stack); 320 | float popFloat (StackFrame *stack); 321 | StackEntry *popEntry (StackFrame *stack); 322 | 323 | int EntryToInt(StackEntry *entry ); 324 | double EntryToDouble(StackEntry *entry); 325 | int is_ref_entry(StackFrame *stack); 326 | 327 | /* local variable */ 328 | typedef struct _LocalVariables { 329 | int integer[10]; 330 | } LocalVariables; 331 | 332 | /* byte Codes */ 333 | typedef int (*opCodeFunc)(unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p); 334 | 335 | typedef struct _byteCode { 336 | char *name; 337 | unsigned char opCode; 338 | int offset; 339 | opCodeFunc func; 340 | } byteCode; 341 | int executeMethod(MethodInfo *startup, StackFrame *stack, SimpleConstantPool *p); 342 | 343 | #endif 344 | -------------------------------------------------------------------------------- /simple_jvm/stack.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple Java Virtual Machine Implementation 3 | * 4 | * Copyright (C) 2013 Chun-Yu Wang 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include "simple_jvm.h" 11 | 12 | extern SimpleInterfacePool simpleInterfacePool; 13 | extern SimpleFieldPool simpleFieldPool; 14 | extern SimpleConstantPool simpleConstantPool; 15 | extern SimpleMethodPool simpleMethodPool; 16 | 17 | /* Stack Initialization */ 18 | void stackInit(StackFrame *stack, int entry_size) 19 | { 20 | int i; 21 | memset(stack, 0, sizeof(StackFrame)); 22 | stack->store = (StackEntry *) malloc(sizeof(StackEntry) * entry_size); 23 | for (i = 0; i < entry_size ; i++) 24 | memset(&stack->store[i], 0, sizeof(StackEntry)); 25 | stack->size = 0; 26 | } 27 | /* push Integer */ 28 | void pushInt(StackFrame *stack, int value) 29 | { 30 | memset(&stack->store[stack->size], 0, sizeof(StackEntry)); 31 | unsigned char *tmp = stack->store[stack->size].entry; 32 | memcpy(tmp, &value, sizeof(int)); 33 | stack->store[stack->size].type = STACK_ENTRY_INT; 34 | stack->size++; 35 | } 36 | 37 | /* push Long */ 38 | void pushLong(StackFrame *stack, long long value) 39 | { 40 | memset(&stack->store[stack->size], 0, sizeof(StackEntry)); 41 | unsigned char *tmp = stack->store[stack->size].entry; 42 | memcpy(tmp, &value, sizeof(long long)); 43 | stack->store[stack->size].type = STACK_ENTRY_LONG; 44 | stack->size++; 45 | } 46 | 47 | /* push Double */ 48 | void pushDouble(StackFrame *stack, double value) 49 | { 50 | memset(&stack->store[stack->size], 0, sizeof(StackEntry)); 51 | unsigned char *tmp = stack->store[stack->size].entry; 52 | memcpy(tmp, &value, sizeof(double)); 53 | stack->store[stack->size].type = STACK_ENTRY_DOUBLE; 54 | stack->size++; 55 | } 56 | 57 | /* push Float */ 58 | void pushFloat(StackFrame *stack, float value) 59 | { 60 | memset(&stack->store[stack->size], 0, sizeof(StackEntry)); 61 | unsigned char *tmp = stack->store[stack->size].entry; 62 | memcpy(tmp, &value, sizeof(float)); 63 | stack->store[stack->size].type = STACK_ENTRY_FLOAT; 64 | stack->size++; 65 | } 66 | 67 | /* push Ref */ 68 | void pushRef(StackFrame *stack, int value) 69 | { 70 | memset(&stack->store[stack->size], 0, sizeof(StackEntry)); 71 | unsigned char *tmp = stack->store[stack->size].entry; 72 | memcpy(tmp, &value, sizeof(int)); 73 | stack->store[stack->size].type = STACK_ENTRY_REF; 74 | stack->size++; 75 | } 76 | 77 | /* pop Integer */ 78 | int popInt(StackFrame *stack) 79 | { 80 | stack->size--; 81 | unsigned char *tmp = stack->store[stack->size].entry; 82 | int value = 0; 83 | memcpy(&value, tmp, sizeof(int)); 84 | memset(&stack->store[stack->size], 0, sizeof(StackEntry)); 85 | return value; 86 | } 87 | 88 | /* pop Long */ 89 | long long popLong(StackFrame *stack) 90 | { 91 | stack->size--; 92 | long long value = 0; 93 | unsigned char *tmp = stack->store[stack->size].entry; 94 | memcpy(&value, tmp, sizeof(long long)); 95 | memset(&stack->store[stack->size], 0, sizeof(StackEntry)); 96 | return value; 97 | } 98 | 99 | /* pop Double */ 100 | double popDouble(StackFrame *stack) 101 | { 102 | stack->size--; 103 | double value = 0; 104 | unsigned char *tmp = stack->store[stack->size].entry; 105 | memcpy(&value, tmp, sizeof(double)); 106 | memset(&stack->store[stack->size], 0, sizeof(StackEntry)); 107 | return value; 108 | } 109 | 110 | /* pop Float */ 111 | float popFloat(StackFrame *stack) 112 | { 113 | stack->size--; 114 | float value = 0; 115 | unsigned char *tmp = stack->store[stack->size].entry; 116 | memcpy(&value, tmp, sizeof(float)); 117 | memset(&stack->store[stack->size], 0, sizeof(StackEntry)); 118 | return value; 119 | } 120 | 121 | /* Pop Stack Entry */ 122 | StackEntry *popEntry(StackFrame *stack) 123 | { 124 | stack->size--; 125 | return &stack->store[stack->size]; 126 | } 127 | 128 | /* Entry to Int */ 129 | int EntryToInt(StackEntry *entry) 130 | { 131 | int value = 0; 132 | memcpy(&value, entry->entry, sizeof(int)); 133 | return value; 134 | } 135 | 136 | double EntryToDouble(StackEntry *entry) 137 | { 138 | double value = 0; 139 | memcpy(&value, entry->entry, sizeof(double)); 140 | return value; 141 | } 142 | 143 | int is_ref_entry(StackFrame *stack) 144 | { 145 | if (stack->store[stack->size - 1].type == STACK_ENTRY_REF) 146 | return 1; 147 | return 0; 148 | } 149 | -------------------------------------------------------------------------------- /tests/Foo1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntu-android/simple_vm/31f01d2ca02fae5143fff11f13175eaad9e5c6aa/tests/Foo1.class -------------------------------------------------------------------------------- /tests/Foo1.dex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntu-android/simple_vm/31f01d2ca02fae5143fff11f13175eaad9e5c6aa/tests/Foo1.dex -------------------------------------------------------------------------------- /tests/Foo1.java: -------------------------------------------------------------------------------- 1 | class Foo1 { 2 | public static void main(String args[]) { 3 | int x = (int)(Math.random() * 42 + 1); 4 | int y = 6345; 5 | int c = 0; 6 | int d = 23456; 7 | int f = 0; 8 | System.out.println("HelloWorld"); 9 | System.out.println("--------------------" ); 10 | System.out.println("initial value "); 11 | System.out.println("random number x : " + x); 12 | System.out.println("x = " + x ); 13 | System.out.println("y = " + y ); 14 | System.out.println("c = " + c ); 15 | System.out.println("d = " + d ); 16 | System.out.println("f = " + f ); 17 | System.out.println("--------------------" ); 18 | 19 | c = x + y; 20 | d += c; 21 | System.out.println("c = x + y = " +x+ " + " + y + " = " + c); 22 | System.out.println("d = d + c = " + d ); 23 | x = c / 2; 24 | System.out.println("x = c/2 = " + x ); 25 | 26 | c = x * y; 27 | d +=c; 28 | System.out.println("c = x * y = " +x+ " * " + y + " = " + c); 29 | System.out.println("d = d + c = " + d ); 30 | x = c/2; 31 | System.out.println("x = c/2 = " + x ); 32 | 33 | c = x-y; 34 | d +=c ; 35 | System.out.println("c = x - y = " +x+ " - " + y + " = " + c); 36 | System.out.println("d = d + c = " + d ); 37 | x = c/2; 38 | System.out.println("x = c/2 = " + x ); 39 | 40 | c = x/y; 41 | d +=c ; 42 | System.out.println("c = x / y = " +x+ " / " + y + " = " + c); 43 | System.out.println("d = d + c = " + d ); 44 | 45 | f = d + x + y + c ; 46 | System.out.println("f = " + (d) + " + " + (x) + " + " + (y) + " + " + (c) + " = " + f ); 47 | System.out.println("Foo Test By WJY"); 48 | } 49 | } 50 | --------------------------------------------------------------------------------