int main() { adam_init(); sexpression_t* svoid; assert(NULL != sexp_parse("void", &svoid)); tvoid = dalvik_type_from_sexp(svoid); sexp_free(svoid); assert(NULL != tvoid); /* load package */ dalvik_loader_from_directory("test/cases/block_analyzer"); /* run test cases */ case1(); case2(); case3(); dalvik_type_free(tvoid); /* finalize */ adam_finalize(); return 0; }
dalvik_field_t* dalvik_field_from_sexp(const sexpression_t* sexp, const char* class_path, const char* file_name) { #ifdef PARSER_COUNT dalvik_field_count ++; #endif dalvik_field_t* ret = NULL; if(SEXP_NIL == sexp) goto ERR; if(NULL == class_path) class_path = "(undefined)"; if(NULL== file_name) file_name = "(undefined)"; const char* name; sexpression_t *attr_list , *type_sexp; if(!sexp_match(sexp, "(L=C?L?_?A", DALVIK_TOKEN_FIELD, &attr_list, &name, &type_sexp, &sexp)) { LOG_ERROR("bad field definition"); goto ERR; } ret = (dalvik_field_t*)malloc(sizeof(dalvik_field_t)); ret->name = name; ret->path = class_path; ret->file = file_name; if(NULL == (ret->type = dalvik_type_from_sexp(type_sexp))) { LOG_ERROR("can't parse type"); LOG_DEBUG("type is %s", sexp_to_string(type_sexp,NULL)); goto ERR; } if(-1 == (ret->attrs = dalvik_attrs_from_sexp(attr_list))) { LOG_ERROR("can't parse attribute"); goto ERR; } if(SEXP_NIL != sexp) { /* it has a defualt value */ if(!sexp_match(sexp, "(A", &ret->defualt_value)) { LOG_ERROR("can't parse default value"); goto ERR; } LOG_NOTICE("fixme: parse default value of a field"); } return ret; ERR: dalvik_field_free(ret); return NULL; }
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; }
int main() { adam_init(); /* Runnability test */ assert(dalvik_loader_from_directory("test/data/AndroidAntlr") >= 0); sexpression_t* sexp; sexp_parse("[object java/lang/String]", &sexp); dalvik_type_t *type = dalvik_type_from_sexp(sexp); sexp_free(sexp); const char* classname = stringpool_query("antlr/ANTLRParser"); const char* methodname = stringpool_query("treeParserSpec"); dalvik_type_t* arglist[] = {NULL ,NULL}; arglist[0] = type; sexpression_t* svoid; assert(NULL != sexp_parse("void", &svoid)); dalvik_type_t* tvoid = dalvik_type_from_sexp(svoid); sexp_free(svoid); dalvik_block_t* block = dalvik_block_from_method(classname, methodname, (const dalvik_type_t**)arglist, tvoid); dalvik_type_free(type); assert(NULL != block); /* setup function test */ assert(dalvik_loader_from_directory("test/cases/dalvik_block") >= 0); arglist[0] = NULL; classname = stringpool_query("TestClass"); /* Case 1 */ methodname = stringpool_query("case1"); block = dalvik_block_from_method(classname, methodname, (const dalvik_type_t**)arglist, tvoid); const dalvik_method_t* method = dalvik_memberdict_get_method(classname, methodname, (const dalvik_type_t**)arglist, tvoid); assert(NULL != method); assert(NULL != block); assert(block->begin == method->entry); assert(block->end == method->entry + 3); assert(block->nbranches == 1); assert(block->branches[0].conditional == 0); assert(DALVIK_BLOCK_BRANCH_UNCOND_TYPE_IS_JUMP(block->branches[0])); dalvik_block_t* retblk = block->branches[0].block; assert(NULL != retblk); assert(1 == retblk->nbranches); assert(DALVIK_BLOCK_BRANCH_UNCOND_TYPE_IS_RETURN(retblk->branches[0])); /* Case 2 */ methodname = stringpool_query("case2"); block = dalvik_block_from_method(classname, methodname, (const dalvik_type_t**)arglist, tvoid); method = dalvik_memberdict_get_method(classname, methodname, (const dalvik_type_t**)arglist, tvoid); assert(NULL != block); assert(NULL != method); /* verify block0 */ assert(block->begin == method->entry); assert(block->end == method->entry + 2); assert(block->nbranches == 2); assert(block->branches[0].disabled == 0); assert(block->branches[0].linked == 1); assert(block->branches[0].conditional == 1); assert(block->branches[0].eq == 1); assert(block->branches[0].lt == 0); assert(block->branches[0].gt == 0); assert(block->branches[0].left_inst == 0); assert(block->branches[0].left->header.flags == 0); assert(block->branches[0].left->payload.uint16 == 1); assert(block->branches[0].right->header.flags == 0); assert(block->branches[0].right->payload.uint16 == 2); assert(block->branches[0].block != NULL); assert(block->branches[1].disabled == 0); assert(block->branches[1].linked == 1); assert(block->branches[1].conditional == 0); assert(block->branches[1].block != NULL); /* verify block2 */ dalvik_block_t* block2 = block->branches[0].block; assert(block2->begin == method->entry + 5); assert(block2->end == method->entry + 6); assert(block2->nbranches == 1); assert(block2->branches[0].disabled == 0); assert(block2->branches[0].linked == 1); assert(block2->branches[0].conditional == 0); assert(block2->branches[0].block != NULL); /* verify block1 */ dalvik_block_t* block1 = block->branches[1].block; assert(block1->begin == method->entry + 3); assert(block1->end == method->entry + 4); assert(block1->nbranches == 1); assert(block1->branches[0].disabled == 0); assert(block1->branches[0].linked == 1); assert(block1->branches[0].conditional == 0); assert(block1->branches[0].block != NULL); assert(block1->branches[0].block == block2->branches[0].block); /* verify block3 */ dalvik_block_t* block3 = block1->branches[0].block; assert(block3->begin == method->entry + 6); assert(block3->end == method->entry + 6); assert(block3->nbranches == 1); assert(DALVIK_BLOCK_BRANCH_UNCOND_TYPE_IS_RETURN(block3->branches[0])); assert(block3->branches[0].block == NULL); assert(block3->branches[0].left->payload.uint16 == 1); assert(block3->branches[0].block == NULL); /* Case 3 */ methodname = stringpool_query("case3"); block = dalvik_block_from_method(classname, methodname, (const dalvik_type_t**)arglist, tvoid); method = dalvik_memberdict_get_method(classname, methodname, (const dalvik_type_t**)arglist, tvoid); assert(NULL != block); assert(NULL != method); /* verify block 1 */ assert(block->begin == method->entry + 0); assert(block->end == method->entry + 2); assert(block->nbranches == 1); assert(block->branches[0].linked == 1); assert(block->branches[0].disabled == 0); assert(block->branches[0].conditional == 0); assert(block->branches[0].block != NULL); /* verify block 3*/ block3 = block->branches[0].block; assert(block3->begin == method->entry + 6); assert(block3->end == method->entry + 7); assert(block3->nbranches == 1); assert(block3->branches[0].linked == 1); assert(block3->branches[0].disabled == 0); assert(DALVIK_BLOCK_BRANCH_UNCOND_TYPE_IS_JUMP(block3->branches[0])); /*verify block 4 */ dalvik_block_t* block4 = block3->branches[0].block; assert(block4->begin == method->entry + 7); assert(block4->end == method->entry + 7); assert(block4->nbranches == 1); assert(DALVIK_BLOCK_BRANCH_UNCOND_TYPE_IS_RETURN(block4->branches[0])); assert(block4->branches[0].left->payload.uint16 == 9); assert(block4->branches[0].block == NULL); /* Case 4 */ methodname = stringpool_query("case4"); block = dalvik_block_from_method(classname, methodname, (const dalvik_type_t**) arglist, tvoid); method = dalvik_memberdict_get_method(classname, methodname, (const dalvik_type_t**) arglist, tvoid); assert(NULL != block); assert(NULL != method); /* verify block 1 */ assert(block->begin == method->entry + 0); assert(block->end == method->entry + 1); assert(block->nbranches == 1); assert(block->branches[0].linked == 1); assert(block->branches[0].disabled == 0); assert(block->branches[0].conditional == 0); assert(block->branches[0].block != NULL); /* verify block 2 */ block2 = block->branches[0].block; assert(block2->begin == method->entry + 1); assert(block2->end == method->entry + 2); assert(block2->nbranches == 1); assert(block2->branches[0].linked == 1); assert(block2->branches[0].conditional == 0); assert(block2->branches[0].disabled == 0); assert(block2->branches[0].block != NULL); /* verify block3 */ block3 = block2->branches[0].block; assert(block3->begin == method->entry + 2); assert(block3->end == method->entry + 3); assert(block3->nbranches == 1); assert(block3->branches[0].linked == 1); assert(block3->branches[0].conditional == 0); assert(block3->branches[0].disabled == 0); block4 = block3->branches[0].block; assert(NULL != block4); assert(DALVIK_BLOCK_BRANCH_UNCOND_TYPE_IS_RETURN(block4->branches[0])); assert(block4->branches[0].block == NULL); /* Case 5 */ methodname = stringpool_query("case5"); block = dalvik_block_from_method(classname, methodname, (const dalvik_type_t**) arglist, tvoid); method = dalvik_memberdict_get_method(classname, methodname, (const dalvik_type_t**) arglist, tvoid); assert(NULL != block); assert(NULL != method); adam_finalize(); return 0; }