void test_move() { assert(NULL != sexp_parse("(move/from16 v12,v1234)", &sexp)); /*assert(0 == dalvik_instruction_from_sexp(sexp, &inst, 0, NULL)); assert(inst.opcode == DVM_MOVE); assert(inst.num_operands == 2); assert(inst.operands[0].payload.uint16 == 12); assert(inst.operands[1].payload.uint16 == 1234); assert(inst.operands[0].header.info.size == 0);*/ sexp_free(sexp); assert(NULL != sexp_parse("(move-wide/from16 v12,v1234)", &sexp)); assert(0 == dalvik_instruction_from_sexp(sexp, &inst, 0)); assert(inst.opcode == DVM_MOVE); assert(inst.num_operands == 2); assert(inst.operands[0].payload.uint16 == 12); assert(inst.operands[1].payload.uint16 == 1234); assert(inst.operands[0].header.info.size == 1); assert(inst.operands[1].header.info.size == 1); sexp_free(sexp); assert(NULL != sexp_parse("(move v12,v1234)", &sexp)); assert(0 == dalvik_instruction_from_sexp(sexp, &inst, 0)); assert(inst.opcode == DVM_MOVE); assert(inst.num_operands == 2); assert(inst.operands[0].payload.uint16 == 12); assert(inst.operands[1].payload.uint16 == 1234); assert(inst.operands[0].header.info.size == 0); assert(inst.operands[1].header.info.size == 0); sexp_free(sexp); assert(NULL != sexp_parse("(move-result/wide v1234)", &sexp)); assert(0 == dalvik_instruction_from_sexp(sexp, &inst, 0)); assert(inst.opcode == DVM_MOVE); assert(inst.num_operands == 2); assert(inst.operands[0].payload.uint16 == 1234); assert(inst.operands[0].header.info.size == 1); assert(inst.operands[1].header.info.is_result); sexp_free(sexp); assert(NULL != sexp_parse("(move-result-object v1234)", &sexp)); assert(0 == dalvik_instruction_from_sexp(sexp, &inst, 0)); assert(inst.opcode == DVM_MOVE); assert(inst.num_operands == 2); assert(inst.operands[0].payload.uint16 == 1234); assert(inst.operands[0].header.info.size == 0); assert(inst.operands[0].header.info.type = DVM_OPERAND_TYPE_OBJECT); assert(inst.operands[1].header.info.type = DVM_OPERAND_TYPE_OBJECT); assert(inst.operands[1].header.info.is_result); sexp_free(sexp); }
void test_packed() { assert(NULL != sexp_parse( "(packed-switch v123, 456,\n" " l456, ;case456\n" " l457, ;case457\n" " l458, ;case458\n" " ldefault ;default\n" ")", &sexp)); assert(0 == dalvik_instruction_from_sexp(sexp, &inst, 0)); assert(DVM_SWITCH == inst.opcode); assert(3 == inst.num_operands); assert(123 == inst.operands[0].payload.uint16); assert(0 == inst.operands[0].header.flags); assert(1 == inst.operands[1].header.info.is_const); assert(456 == inst.operands[1].payload.uint16); assert(inst.operands[1].header.info.type == DVM_OPERAND_TYPE_INT); assert(inst.operands[2].header.info.type == DVM_OPERAND_TYPE_LABELVECTOR); assert(inst.operands[2].header.info.is_const == 1); assert(inst.operands[2].payload.branches != NULL); vector_t* v = inst.operands[2].payload.branches; assert(0 == *(int*)vector_get(v, 0)); assert(1 == *(int*)vector_get(v, 1)); assert(2 == *(int*)vector_get(v, 2)); assert(3 == *(int*)vector_get(v, 3)); assert(0 == dalvik_label_get_label_id(stringpool_query("l456"))); assert(1 == dalvik_label_get_label_id(stringpool_query("l457"))); assert(2 == dalvik_label_get_label_id(stringpool_query("l458"))); assert(3 == dalvik_label_get_label_id(stringpool_query("ldefault"))); sexp_free(sexp); dalvik_instruction_free(&inst); }
void test_arrayops() { #if DALVIK_ARRAY_SUPPORT assert(NULL != sexp_parse("(aput v1 v2 v3)", &sexp)); assert(0 == dalvik_instruction_from_sexp(sexp, &inst, 0)); assert(inst.opcode == DVM_ARRAY); assert(inst.flags = DVM_FLAG_ARRAY_PUT); assert(inst.num_operands == 3); assert(inst.operands[0].header.flags == 0); assert(inst.operands[0].payload.uint16 == 1); assert(inst.operands[1].header.info.type == DVM_OPERAND_TYPE_OBJECT); assert(inst.operands[1].payload.uint16 == 2); assert(inst.operands[2].header.info.type == DVM_OPERAND_TYPE_INT); assert(inst.operands[2].payload.uint16 == 3); sexp_free(sexp); dalvik_instruction_free(&inst); assert(NULL != sexp_parse("(aput-object v1 v2 v3)", &sexp)); assert(0 == dalvik_instruction_from_sexp(sexp, &inst, 0)); assert(inst.opcode == DVM_ARRAY); assert(inst.flags = DVM_FLAG_ARRAY_PUT); assert(inst.num_operands == 3); assert(inst.operands[0].header.info.type == DVM_OPERAND_TYPE_OBJECT); assert(inst.operands[0].payload.uint16 == 1); assert(inst.operands[1].header.info.type == DVM_OPERAND_TYPE_OBJECT); assert(inst.operands[1].payload.uint16 == 2); assert(inst.operands[2].header.info.type == DVM_OPERAND_TYPE_INT); assert(inst.operands[2].payload.uint16 == 3); sexp_free(sexp); dalvik_instruction_free(&inst); assert(NULL != sexp_parse("(aget-object v1 v2 v3)", &sexp)); assert(0 == dalvik_instruction_from_sexp(sexp, &inst, 0)); assert(inst.opcode == DVM_ARRAY); assert(inst.flags = DVM_FLAG_ARRAY_GET); assert(inst.num_operands == 3); assert(inst.operands[0].header.info.type == DVM_OPERAND_TYPE_OBJECT); assert(inst.operands[0].payload.uint16 == 1); assert(inst.operands[1].header.info.type == DVM_OPERAND_TYPE_OBJECT); assert(inst.operands[1].payload.uint16 == 2); assert(inst.operands[2].header.info.type == DVM_OPERAND_TYPE_INT); assert(inst.operands[2].payload.uint16 == 3); sexp_free(sexp); dalvik_instruction_free(&inst); #endif }
void test_return() { assert(NULL != sexp_parse("(return-object v1234)", &sexp)); assert(0 == dalvik_instruction_from_sexp(sexp, &inst, 0)); assert(inst.opcode == DVM_RETURN); assert(inst.num_operands == 1); assert(inst.operands[0].payload.uint16 == 1234); assert(inst.operands[0].header.info.size == 0); assert(inst.operands[0].header.info.type = DVM_OPERAND_TYPE_OBJECT); sexp_free(sexp); assert(NULL != sexp_parse("(return-void)", &sexp)); assert(0 == dalvik_instruction_from_sexp(sexp, &inst, 0)); assert(inst.opcode == DVM_RETURN); assert(inst.num_operands == 1); assert(inst.operands[0].header.info.type = DVM_OPERAND_TYPE_VOID); sexp_free(sexp); }
void test_invoke() { assert(NULL != sexp_parse("(invoke-virtual {v1,v2,v3} this/is/a/test (int int int) int)", &sexp)); assert(0 == dalvik_instruction_from_sexp(sexp,&inst, 0)); assert(inst.opcode == DVM_INVOKE); assert(inst.flags == DVM_FLAG_INVOKE_VIRTUAL); assert(inst.num_operands == 7); //TODO: test it }
void test_instanceops() { assert(NULL != sexp_parse("(iput v1 v2 myclass.Property1 [array [object java.lang.String]])", &sexp)); assert(0 == dalvik_instruction_from_sexp(sexp, &inst, 0)); assert(inst.opcode == DVM_INSTANCE); assert(inst.flags = DVM_FLAG_INSTANCE_PUT); assert(inst.num_operands == 5); sexp_free(sexp); dalvik_instruction_free(&inst); }
void test_monitor() { assert(NULL != sexp_parse("(monitor-enter v123)", &sexp)); assert(0 == dalvik_instruction_from_sexp(sexp, &inst, 0)); assert(inst.opcode == DVM_MONITOR); assert(inst.num_operands == 1); assert(inst.operands[0].header.info.type == 0); assert(inst.operands[0].payload.uint16 == 123); assert(inst.operands[0].header.info.is_const == 0); assert(inst.flags == DVM_FLAG_MONITOR_ENT); sexp_free(sexp); assert(NULL != sexp_parse("(monitor-exit v123)", &sexp)); assert(0 == dalvik_instruction_from_sexp(sexp, &inst, 0)); assert(inst.opcode == DVM_MONITOR); assert(inst.num_operands == 1); assert(inst.operands[0].header.info.type == 0); assert(inst.operands[0].payload.uint16 == 123); assert(inst.operands[0].header.info.is_const == 0); assert(inst.flags == DVM_FLAG_MONITOR_EXT); sexp_free(sexp); }
void test_sparse() { assert(NULL != sexp_parse( "(sparse-switch v4 \n" " (9 sp1) \n" " (10 sp2) \n" " (13 sp3) \n" " (65535 sp4)\n" " (default sp5))", &sexp)); assert(0 == dalvik_instruction_from_sexp(sexp, &inst, 0)); assert(inst.opcode == DVM_SWITCH); assert(inst.flags == DVM_FLAG_SWITCH_SPARSE); assert(inst.num_operands == 2); assert(inst.operands[0].header.flags == 0); assert(inst.operands[0].payload.uint16 = 4); assert(inst.operands[1].header.info.is_const == 1); assert(inst.operands[1].header.info.type == DVM_OPERAND_TYPE_SPARSE); assert(inst.operands[1].payload.sparse != NULL); vector_t* v = inst.operands[1].payload.branches; assert(4 ==((dalvik_sparse_switch_branch_t *)vector_get(v, 0))->labelid); assert(5 ==((dalvik_sparse_switch_branch_t *)vector_get(v, 1))->labelid); assert(6 ==((dalvik_sparse_switch_branch_t *)vector_get(v, 2))->labelid); assert(7 ==((dalvik_sparse_switch_branch_t *)vector_get(v, 3))->labelid); assert(8 ==((dalvik_sparse_switch_branch_t *)vector_get(v, 4))->labelid); assert(9 ==((dalvik_sparse_switch_branch_t *)vector_get(v, 0))->cond); assert(10 ==((dalvik_sparse_switch_branch_t *)vector_get(v, 1))->cond); assert(13 ==((dalvik_sparse_switch_branch_t *)vector_get(v, 2))->cond); assert(65535 ==((dalvik_sparse_switch_branch_t *)vector_get(v, 3))->cond); assert(0 ==((dalvik_sparse_switch_branch_t *)vector_get(v, 4))->cond); assert(0 ==((dalvik_sparse_switch_branch_t *)vector_get(v, 0))->is_default); assert(0 ==((dalvik_sparse_switch_branch_t *)vector_get(v, 1))->is_default); assert(0 ==((dalvik_sparse_switch_branch_t *)vector_get(v, 2))->is_default); assert(0 ==((dalvik_sparse_switch_branch_t *)vector_get(v, 3))->is_default); assert(1 ==((dalvik_sparse_switch_branch_t *)vector_get(v, 4))->is_default); assert(5 == vector_size(v)); sexp_free(sexp); dalvik_instruction_free(&inst); }
dalvik_method_t* dalvik_method_from_sexp(const sexpression_t* sexp, const char* class_path,const char* file) { #ifdef PARSER_COUNT dalvik_method_count ++; #endif dalvik_method_t* method = NULL; if(SEXP_NIL == sexp) return NULL; if(NULL == class_path) class_path = "(undefined)"; if(NULL == file) file = "(undefined)"; const char* name; sexpression_t *attrs, *arglist, *ret, *body; /* matches (method (attribute-list) method-name (arg-list) return-type body) */ if(!sexp_match(sexp, "(L=C?L?C?_?A", DALVIK_TOKEN_METHOD, &attrs, &name, &arglist, &ret, &body)) { LOG_ERROR("bad method defination"); return NULL; } /* get attributes */ int attrnum; if((attrnum = dalvik_attrs_from_sexp(attrs)) < 0) { LOG_ERROR("can not parse attributes"); return NULL; } /* get number of arguments */ int num_args; num_args = sexp_length(arglist); /* Now we know the size we have to allocate for this method */ method = (dalvik_method_t*)malloc(sizeof(dalvik_method_t) + sizeof(dalvik_type_t*) * (num_args + 1)); if(NULL == method) { LOG_ERROR("can not allocate memory for method argument list"); return NULL; } memset(method->args_type, 0, sizeof(dalvik_type_t*) * (num_args + 1)); method->num_args = num_args; method->path = class_path; method->file = file; method->name = name; /* Setup the type of argument list */ int i; for(i = 0;arglist != SEXP_NIL && i < num_args; i ++) { sexpression_t *this_arg; if(!sexp_match(arglist, "(_?A", &this_arg, &arglist)) { LOG_ERROR("invalid argument list"); goto ERR; } if(NULL == (method->args_type[i] = dalvik_type_from_sexp(this_arg))) { LOG_ERROR("invalid argument type @ #%d", i); goto ERR; } } /* Setup the return type */ if(NULL == (method->return_type = dalvik_type_from_sexp(ret))) { LOG_ERROR("invalid return type"); goto ERR; } /* Now fetch the body */ //TODO: process other parts of a method int current_line_number = 0; /* Current Line Number */ uint32_t last = DALVIK_INSTRUCTION_INVALID; //int last_label = -1; int label_stack[DALVIK_METHOD_LABEL_STACK_SIZE]; /* how many label can one isntruction assign to */ int label_sp; int from_label[DALVIK_MAX_CATCH_BLOCK]; /* NOTICE: the maximum number of catch block is limited to this constant */ int to_label [DALVIK_MAX_CATCH_BLOCK]; int label_st [DALVIK_MAX_CATCH_BLOCK]; /* 0: haven't seen any label related to the label. * 1: seen from label before * 2: seen from and to label */ label_sp = 0; dalvik_exception_handler_t* excepthandler[DALVIK_MAX_CATCH_BLOCK] = {}; dalvik_exception_handler_set_t* current_ehset = NULL; int number_of_exception_handler = 0; for(;body != SEXP_NIL;) { sexpression_t *this_smt; if(!sexp_match(body, "(C?A", &this_smt, &body)) { LOG_ERROR("invalid method body"); goto ERR; } /* First check if the statement is a psuedo-instruction */ const char* arg; #if LOG_LEVEL >= 6 char buf[40906]; static int counter = 0; #endif LOG_DEBUG("#%d current instruction : %s",(++counter) ,sexp_to_string(this_smt, buf) ); if(sexp_match(this_smt, "(L=L=L?", DALVIK_TOKEN_LIMIT, DALVIK_TOKEN_REGISTERS, &arg)) { /* (limit-registers k) */ method->num_regs = atoi(arg); LOG_DEBUG("uses %d registers", method->num_regs); } else if(sexp_match(this_smt, "(L=L?", DALVIK_TOKEN_LINE, &arg)) { /* (line arg) */ current_line_number = atoi(arg); } else if(sexp_match(this_smt, "(L=L?", DALVIK_TOKEN_LABEL, &arg)) { /* (label arg) */ int lid = dalvik_label_get_label_id(arg); int i; if(lid == -1) { LOG_ERROR("can not create label for %s", arg); goto ERR; } //last_label = lid; if(label_sp < DALVIK_METHOD_LABEL_STACK_SIZE) label_stack[label_sp++] = lid; else LOG_WARNING("label stack overflow, might loss some label here"); int enbaled_count = 0; dalvik_exception_handler_t* exceptionset[DALVIK_MAX_CATCH_BLOCK]; for(i = 0; i < number_of_exception_handler; i ++) { if(lid == from_label[i] && label_st[i] == 0) label_st[i] = 1; else if(lid == to_label[i] && label_st[i] == 1) label_st[i] = 2; else if(lid == from_label[i] && label_st[i] != 0) LOG_WARNING("meet from label twice, it might be a mistake"); else if(lid == to_label[i] && label_st[i] != 1) LOG_WARNING("to label is before from label, it might be a mistake"); if(label_st[i] == 1) exceptionset[enbaled_count++] = excepthandler[i]; } current_ehset = dalvik_exception_new_handler_set(enbaled_count, exceptionset); } else if(sexp_match(this_smt, "(L=A", DALVIK_TOKEN_ANNOTATION, &arg)) { /* Simplely ignore */ LOG_INFO("fixme: ignored psuedo-insturction (annotation)"); } else if(sexp_match(this_smt, "(L=L=A", DALVIK_TOKEN_DATA, DALVIK_TOKEN_ARRAY, &arg)) { /* TODO: what is (data-array ....)statement currently ignored */ LOG_INFO("fixme: (data-array) psuedo-insturction is to be implemented"); } else if(sexp_match(this_smt, "(L=A", DALVIK_TOKEN_CATCH, &arg) || sexp_match(this_smt, "(L=A", DALVIK_TOKEN_CATCHALL, &arg)) { excepthandler[number_of_exception_handler] = dalvik_exception_handler_from_sexp( this_smt, from_label + number_of_exception_handler, to_label + number_of_exception_handler); if(excepthandler[number_of_exception_handler] == NULL) { LOG_WARNING("invalid exception handler %s", sexp_to_string(this_smt, NULL)); continue; } LOG_DEBUG("exception %s is handlered in label #%d", excepthandler[number_of_exception_handler]->exception, excepthandler[number_of_exception_handler]->handler_label); //label_st[number_of_exception_handler] = 0; /* TODO: verify this is a bug */ number_of_exception_handler ++; } else if(sexp_match(this_smt, "(L=A", DALVIK_TOKEN_FILL, &arg)) { //TODO: fill-array-data psuedo-instruction LOG_INFO("fixme: (fill-array-data) is to be implemented"); } else { dalvik_instruction_t* inst = dalvik_instruction_new(); if(NULL == inst) { LOG_ERROR("can not create new instruction"); goto ERR; } if(dalvik_instruction_from_sexp(this_smt, inst, current_line_number) < 0) { LOG_ERROR("can not recognize instuction %s", sexp_to_string(this_smt, NULL)); goto ERR; } if(DALVIK_INSTRUCTION_INVALID == last) method->entry = dalvik_instruction_get_index(inst); else dalvik_instruction_set_next(last, inst); last = dalvik_instruction_get_index(inst); inst->handler_set = current_ehset; if(label_sp > 0) { int i; for(i = 0; i < label_sp; i++) { LOG_DEBUG("assigned instruction@%p to label #%d", inst, label_stack[i]); dalvik_label_jump_table[label_stack[i]] = dalvik_instruction_get_index(inst); } label_sp = 0; } } } return method; ERR: dalvik_method_free(method); return NULL; }
void test_const() { assert(NULL != sexp_parse("(const/high16 v123,1)", &sexp)); assert(0 == dalvik_instruction_from_sexp(sexp, &inst, 0)); assert(inst.opcode == DVM_CONST); assert(inst.num_operands == 2); assert(inst.operands[0].header.flags == 0); assert(inst.operands[0].header.info.type == 0); assert(inst.operands[0].payload.uint16 == 123); assert(inst.operands[1].header.info.is_const == 1); assert(inst.operands[1].payload.uint32 == 0x10000); sexp_free(sexp); assert(NULL != sexp_parse("(const v123,1235)", &sexp)); assert(0 == dalvik_instruction_from_sexp(sexp, &inst, 0)); assert(inst.opcode == DVM_CONST); assert(inst.num_operands == 2); assert(inst.operands[0].header.flags == 0); assert(inst.operands[0].header.info.type == 0); assert(inst.operands[0].payload.uint16 == 123); assert(inst.operands[1].header.info.is_const == 1); assert(inst.operands[1].payload.uint32 == 1235); sexp_free(sexp); assert(NULL != sexp_parse("(const/4 v123,1235)", &sexp)); assert(0 == dalvik_instruction_from_sexp(sexp, &inst, 0)); assert(inst.opcode == DVM_CONST); assert(inst.num_operands == 2); assert(inst.operands[0].header.flags == 0); assert(inst.operands[0].header.info.type == 0); assert(inst.operands[0].payload.uint16 == 123); assert(inst.operands[1].header.info.is_const == 1); assert(inst.operands[1].payload.uint32 == 1235); sexp_free(sexp); assert(NULL != sexp_parse("(const/16 v123,1235)", &sexp)); assert(0 == dalvik_instruction_from_sexp(sexp, &inst, 0)); assert(inst.opcode == DVM_CONST); assert(inst.num_operands == 2); assert(inst.operands[0].header.flags == 0); assert(inst.operands[0].header.info.type == 0); assert(inst.operands[0].payload.uint16 == 123); assert(inst.operands[1].header.info.is_const == 1); assert(inst.operands[1].payload.uint32 == 1235); sexp_free(sexp); assert(NULL != sexp_parse("(const-wide v123,123456789)", &sexp)); assert(0 == dalvik_instruction_from_sexp(sexp, &inst, 0)); assert(inst.opcode == DVM_CONST); assert(inst.num_operands == 2); assert(inst.operands[0].header.info.size == 1); assert(inst.operands[0].header.info.type == 0); assert(inst.operands[0].payload.uint16 == 123); assert(inst.operands[1].header.info.is_const == 1); assert(inst.operands[1].payload.uint64 == 123456789); sexp_free(sexp); assert(NULL != sexp_parse("(const-wide v123,123456789)", &sexp)); assert(0 == dalvik_instruction_from_sexp(sexp, &inst, 0)); assert(inst.opcode == DVM_CONST); assert(inst.num_operands == 2); assert(inst.operands[0].header.info.size == 1); assert(inst.operands[0].header.info.type == 0); assert(inst.operands[0].payload.uint16 == 123); assert(inst.operands[1].header.info.is_const == 1); assert(inst.operands[1].payload.uint64 == 123456789); sexp_free(sexp); assert(NULL != sexp_parse("(const-wide/high16 v123,1)", &sexp)); assert(0 == dalvik_instruction_from_sexp(sexp, &inst, 0)); assert(inst.opcode == DVM_CONST); assert(inst.num_operands == 2); assert(inst.operands[0].header.info.size == 1); assert(inst.operands[0].header.info.type == 0); assert(inst.operands[0].payload.uint16 == 123); assert(inst.operands[1].header.info.is_const == 1); assert(inst.operands[1].payload.uint64 == 0x0001000000000000ull); sexp_free(sexp); assert(NULL != sexp_parse("(const-string v123,\"this is a test case for const-string\")", &sexp)); assert(0 == dalvik_instruction_from_sexp(sexp, &inst, 0)); assert(inst.opcode == DVM_CONST); assert(inst.num_operands == 2); assert(inst.operands[1].header.info.type == DVM_OPERAND_TYPE_STRING); assert(inst.operands[1].payload.string == stringpool_query("this is a test case for const-string")); assert(inst.operands[1].header.info.is_const == 1); sexp_free(sexp); assert(NULL != sexp_parse("(const-class v123,this/is/a/test/class)", &sexp)); assert(0 == dalvik_instruction_from_sexp(sexp, &inst, 0)); assert(inst.opcode == DVM_CONST); assert(inst.num_operands == 2); assert(inst.operands[1].header.info.type == DVM_OPERAND_TYPE_CLASS); assert(inst.operands[1].payload.string == stringpool_query("this/is/a/test/class")); assert(inst.operands[1].header.info.is_const == 1); sexp_free(sexp); }