if (kInterpreterImplKind == kMterpImplKind) { if (transaction_active) { // No Mterp variant - just use the switch interpreter. return ExecuteSwitchImpl<false, true>(self, code_item, shadow_frame, result_register, false); } elseif (UNLIKELY(!Runtime::Current()->IsStarted())) { return ExecuteSwitchImpl<false, false>(self, code_item, shadow_frame, result_register, false); } else { while (true) { // Mterp does not support all instrumentation/debugging. if (MterpShouldSwitchInterpreters() != 0) { return ExecuteSwitchImpl<false, false>(self, code_item, shadow_frame, result_register, false); } bool returned = ExecuteMterpImpl(self, code_item, &shadow_frame, &result_register); if (returned) { return result_register; } else { // Mterp didn't like that instruction. Single-step it with the reference interpreter. result_register = ExecuteSwitchImpl<false, false>(self, code_item, shadow_frame, result_register, true); if (shadow_frame.GetDexPC() == DexFile::kDexNoIndex) { // Single-stepped a return or an exception not handled locally. Return to caller. return result_register; } } } } }
/* Remember the return register */ str x3, [x2, #SHADOWFRAME_RESULT_REGISTER_OFFSET]
/* Remember the code_item */ str x1, [x2, #SHADOWFRAME_CODE_ITEM_OFFSET]
/* set up "named" registers */ mov xSELF, x0 ldr w0, [x2, #SHADOWFRAME_NUMBER_OF_VREGS_OFFSET] add xFP, x2, #SHADOWFRAME_VREGS_OFFSET // point to vregs. add xREFS, xFP, w0, lsl #2 // point to reference array in shadow frame ldr w0, [x2, #SHADOWFRAME_DEX_PC_OFFSET] // Get starting dex_pc. add xPC, x1, #CODEITEM_INSNS_OFFSET // Point to base of insns[] add xPC, xPC, w0, lsl #1 // Create direct pointer to 1st dex opcode EXPORT_PC
/* Set up for backwards branches & osr profiling */ ldr x0, [xFP, #OFF_FP_METHOD] add x1, xFP, #OFF_FP_SHADOWFRAME bl MterpSetUpHotnessCountdown mov wPROFILE, w0 // Starting hotness countdown to xPROFILE
/* start executing the instruction at rPC */ FETCH_INST // load wINST from rPC GET_INST_OPCODE ip // extract opcode from wINST GOTO_OPCODE ip // jump to next instruction /* NOTE: no fallthrough */
functioncallPrettyMethod(artmethod){ var prettyMethodPtr=Module.getExportByName("libart.so","_ZN3art9ArtMethod12PrettyMethodEb"); var result=Memory.alloc(0x100); var prettyMethod=new NativeFunction(prettyMethodPtr,'pointer',['pointer','pointer','bool']); prettyMethod(ptr(result),ptr(artmethod),1); var methodName=result.add(0x8).readPointer().readCString() return methodName; }
functionhook_interpreter(){ varmodule=Process.getModuleByName("libart.so"); module.enumerateSymbols().forEach(function(symbol){ if(symbol.name.indexOf("ExecuteSwitchImpl")!=-1){ console.log(symbol.name,symbol.address); Interceptor.attach(symbol.address,{ onEnter:function(args){ var shadow=args[3]; var artmethod=ptr(shadow).add(Process.pointerSize).readPointer(); var methodName= callPrettyMethod(artmethod); console.log("ExecuteSwitchImpl methodName:",methodName); }, onLeave:function(retval){
}, }) } if(symbol.name.indexOf("ExecuteMterpImpl")!=-1){ console.log(symbol.name,symbol.address); Interceptor.attach(symbol.address,{ onEnter:function(args){ var shadow=args[2]; var artmethod=ptr(shadow).add(Process.pointerSize).readPointer(); var methodName= callPrettyMethod(artmethod); console.log("ExecuteMterpImpl methodName:",methodName); }, onLeave:function(retval){