void mterpBBCallback(DECAF_Callback_Params* params) { if ( (mterpMap == NULL) || (params == NULL) ) { return; } CPUState* env = params->bb.env; TranslationBlock* tb = params->bb.tb; Dalvik_Callback_Params dalvikparams; DEFENSIVE_CHECK0((env == NULL) || (tb == NULL)); MterpInfo* pInfo = NULL; if (OpaqueHashmap_getVal(mterpMap, getCurrentPID(), (void**)&pInfo) != 0) { return; } //check to make sure that the BB is for the right iBaseRange first uint32_t opcode = mterpAddrToOpcode(pInfo->iBase, tb->pc); if (opcode != INV_ADDR) { if (RangeList_exist(pInfo->ranges, getDalvikPC(env))) { dalvikparams.ib.env = env; dalvikparams.ib.dalvik_pc = getDalvikPC(env); dalvikparams.ib.opcode = opcode; SimpleCallback_dispatch(&DS_Mterp_callbacks[DS_DALVIK_INSN_BEGIN_CB], &dalvikparams); } } }
void disableJitBBCallback(DECAF_Callback_Params* params) { if ( (disableJitMap == NULL) || (params == NULL) ) { return; } CPUState* env = params->bb.env; TranslationBlock* tb = params->bb.tb; Dalvik_Callback_Params dalvikparams; DEFENSIVE_CHECK0((env == NULL) || (tb == NULL)); DisableJitInfo* pInfo = NULL; if (OpaqueHashmap_getVal(disableJitMap, getCurrentPID(), (void**)&pInfo) != 0) { return; } if (tb->pc == pInfo->getCodeAddr) { if (pInfo->retHandle != DECAF_NULL_HANDLE) { return; } if (RangeList_exist(pInfo->ranges, DECAF_getFirstParam(env))) { pInfo->retAddr = lp_strip(DECAF_getReturnAddr(env)); pInfo->retHandle = DECAF_registerOptimizedBlockBeginCallback(&disableJitBBCallback, pInfo->retAddr, OCB_CONST); } /** TESTING SETTING THE TARGET ADDRESS TO 0 -- RESULTS: It doesn't make sense why the performance is so much lower than the original method of replacing the return value with 0. This is particularly true for the string tests in com.android.cm3 since most of the work is being done outside of the library. Also setting it to 0 makes gives in consistent results in the . and + in terms of the calls and returns. Before I made this change there seems to be two .s per + in linpack (which is weird in itself) but after this change there seems to be many .s per + like thousands more - it is just one single line change - perhaps it has something to do with the code itself where changing the address to 0 is NOT forcing a NULL to be returned**/ //printf("%x\n", env->regs[0]); //env->regs[0] = 0; /** END TEST **/ } else if ( (pInfo->retHandle != DECAF_NULL_HANDLE) && (lp_strip(tb->pc) == pInfo->retAddr) ) { #ifdef TARGET_ARM env->regs[0] = 0; #elif defined(TARGET_I386) env->regs[R_EAX] = 0; #endif DECAF_unregisterOptimizedBlockBeginCallback(pInfo->retHandle); pInfo->retHandle = DECAF_NULL_HANDLE; pInfo->retAddr = INV_ADDR; //printf("+"); } }
//reg 0 is c2_base0 and 1 is c2_base1 void Context_PGDWriteCallback(DECAF_Callback_Params* params) { struct timeval t; gettimeofday(&t, NULL); DEFENSIVE_CHECK0(params == NULL); //TODO: Keep a record of what the current PGD is and the new PGD is // so that we don't do unnecessary updates - this applies to the // skipupdates flag that is set when system calls are made as well if (!bSkipNextPGDUpdate) { updateProcessList(params->pgd.env, params->pgd.newPGD, UPDATE_PROCESSES | UPDATE_THREADS); } //reset this flag bSkipNextPGDUpdate = 0; }
//LOK: My tests have shown that do_fork -> then update on a PGD write is a perfect choice. Should change the logic to do that. // it seems to cover many more cases than do_fork and schedule() //TODO: have to fix the potential problem where this is called twice before the return is processed // in which case the process name will not be updated properly void contextBBCallback(DECAF_Callback_Params* params) { static gva_t taskAddr = INV_ADDR; static int updateMask = 0; gpid_t pid = -1; TranslationBlock* tb = NULL; CPUState* env = NULL; DEFENSIVE_CHECK0(params == NULL); env = params->bb.env; tb = params->bb.tb; if (NULL == tb) { return; } if ( (tb->pc == SET_TASK_COMM_ADDR) || (tb->pc == DO_PRCTL_ADDR) )//set_task_comm { //In this case, we just update the name when the function returns //TODO: Fix i386 support //TODO: Make sure this taskAddr is NOT the thread's task #ifdef TARGET_ARM taskAddr = env->regs[0]; Context_retAddr = env->regs[14]; #elif TARGET_I386 taskAddr = env->regs[R_EAX]; DECAF_read_mem(env, env->regs[R_ESP], &Context_retAddr, sizeof(Context_retAddr)); #endif } else if ( (tb->pc == DO_EXECVE_ADDR) || (tb->pc == DO_CLONE_ADDR) )//do_execve { //we OR the update mask since its possible for the system call // to call another test - e.g. do_fork - and without declaring // the updateMask as static and using |= the flags will be // overwritten //TODO: Implement a STACK for the return addresses!!! //in this case we update the process, threads and module lists updateMask |= UPDATE_PROCESSES | UPDATE_THREADS | UPDATE_MODULES; #ifdef TARGET_ARM Context_retAddr = env->regs[14]; #endif } else if (tb->pc == DO_FORK_ADDR) //do_fork { //In this case we just update the process and threads lists updateMask |= UPDATE_PROCESSES | UPDATE_THREADS; #ifdef TARGET_ARM Context_retAddr = env->regs[14]; #endif } if (tb->pc == Context_retAddr) { if (taskAddr != INV_ADDR) //if we need to update the names only { pid = DECAF_get_pid(env, taskAddr); if (pid != -1) { //if we found the PID then just read the names and update updateProcessListByTask(env, taskAddr, UPDATE_PROCESSES | UPDATE_THREADS | UPDATE_MODULES, 0); } taskAddr = INV_ADDR; } else { updateProcessList(env, getCurrentPGD(), updateMask); } //since we updated the list already - lets skip the next PGD //write update bSkipNextPGDUpdate = 1; Context_retAddr = 0; DECAF_flushTranslationBlock_env(env, Context_retAddr); } if (Context_retAddr != 0) { //instead of registering for a new callback - we will just update our //conditions list and flush the entry for retAddr DECAF_flushTranslationBlock_env(env, Context_retAddr); } return; }
/** * Instruction Begin callback. */ void nd_instruction_begin_callback(DECAF_Callback_Params* params){ DEFENSIVE_CHECK0(params == NULL); DEFENSIVE_CHECK0(getCurrentPID() != ND_GLOBAL_TRACING_PID); CPUState* env = params->ib.env; gva_t cur_pc = params->ib.cur_pc; //since for thumb instruction, the last bit is '1' gva_t cur_pc_even = cur_pc & 0xfffffffe; if(!nd_in_blacklist(cur_pc_even)){ return; } //ARM Instruction union _tmpARMInsn{ target_ulong insn; char chars[4]; } tmpARMInsn; //Thumb Instruction union _tmpThumbInsn{ unsigned short insn; char chars[2]; } tmpThumbInsn; //Thumb2 Instruction union _tmpThumb2Insn{ target_ulong insn; char chars[4]; } tmpThumb2Insn; //undefined instruction if(cur_pc == -1){ return; } //the first instruction of target native method SourcePolicy* sourcePolicy = findSourcePolicy(cur_pc_even); if(sourcePolicy != NULL){ DECAF_printf("Step into Native\n"); sourcePolicy->handler(sourcePolicy, env); } //DECAF_printf("%x %x\n", cur_pc_even, lastCallSysLibAddrRet); //return from JNI API calls/system library calls if(cur_pc_even == lastCallJNIAddrRet){ if(lastJniHandler != NULL){ lastJniHandler(env, 0); lastJniHandler = NULL; lastCallJNIAddrRet = -1; } } if(cur_pc_even == lastCallSysLibAddrRet){ if(lastSysLibHandler != NULL){ lastSysLibHandler(env, 0); lastSysLibHandler = NULL; lastCallSysLibAddrRet = -1; } } //Thumb instruction if(env->thumb == 1){ if(DECAF_read_mem(env, cur_pc_even, tmpThumbInsn.chars, 2) != -1){ darm_t d; //darm_str_t str; // magic table constructed based on section A6.1 of the ARM manual static uint8_t is_thumb2[0x20] = { [0x01d] = 1, [0x01e] = 1, [0x01f] = 1, }; if(is_thumb2[tmpThumbInsn.insn >> 11]){ //Thumb2 instruction if(DECAF_read_mem(env, cur_pc_even, tmpThumb2Insn.chars, 4) != -1){ if(darm_thumb2_disasm(&d, tmpThumb2Insn.insn & 0x0000ffff, tmpThumb2Insn.insn >> 16, env) == 0){ //if(darm_str(&d, &str, env) == 0){ //DECAF_printf("T2 %x: %s\n", cur_pc, str.total); //} } } }else{ //Thumb instruction if(darm_thumb_disasm(&d, tmpThumbInsn.insn, env) == 0){ //if(darm_str(&d, &str, env) == 0){ //DECAF_printf("T %x: %s\n", cur_pc, str.total); //} } } }
/** * Instruction Begin callback. */ void nd_instruction_begin_callback(DECAF_Callback_Params* params){ DEFENSIVE_CHECK0(params == NULL); DEFENSIVE_CHECK0(getCurrentPID() != ND_GLOBAL_TRACING_PID); CPUState* env = params->ib.env; gva_t cur_pc = params->ib.cur_pc; //since for thumb instruction, the last bit is '1' gva_t cur_pc_even = cur_pc & 0xfffffffe; //ARM Instruction union _tmpARMInsn{ target_ulong insn; char chars[4]; } tmpARMInsn; //Thumb Instruction union _tmpThumbInsn{ unsigned short insn; char chars[2]; } tmpThumbInsn; //Thumb2 Instruction union _tmpThumb2Insn{ target_ulong insn; char chars[4]; } tmpThumb2Insn; //undefined instruction if(cur_pc == -1){ return; } //the first instruction of target native method SourcePolicy* sourcePolicy = findSourcePolicy(cur_pc_even); if(sourcePolicy != NULL){ sourcePolicy->handler(sourcePolicy, env); } //Thumb instruction if(env->thumb == 1){ if(DECAF_read_mem(env, cur_pc_even, tmpThumbInsn.chars, 2) != -1){ darm_t d; darm_str_t str; // magic table constructed based on section A6.1 of the ARM manual static uint8_t is_thumb2[0x20] = { [0x01d] = 1, [0x01e] = 1, [0x01f] = 1, }; if(is_thumb2[tmpThumbInsn.insn >> 11]){ //Thumb2 instruction if(DECAF_read_mem(env, cur_pc_even, tmpThumb2Insn.chars, 4) != -1){ if(darm_thumb2_disasm(&d, tmpThumb2Insn.insn >> 16, tmpThumb2Insn.insn & 0x0000ffff) == 0){ if(darm_str(&d, &str) == 0){ //DECAF_printf("T2 %x: %s\n", cur_pc, str.total); } } } }else{ //Thumb instruction if(darm_thumb_disasm(&d, tmpThumbInsn.insn) == 0){ if(darm_str(&d, &str) == 0){ //DECAF_printf("T %x: %s\n", cur_pc, str.total); } } } }