diff --git a/backend/remill/include/remill/BC/HelperMacro.h b/backend/remill/include/remill/BC/HelperMacro.h index 317f32e..5b82b6f 100644 --- a/backend/remill/include/remill/BC/HelperMacro.h +++ b/backend/remill/include/remill/BC/HelperMacro.h @@ -8,4 +8,4 @@ // #define OPT_ALGO_DEBUG 1 // #define OPT_GEN_IR_DEBUG 1 // #define OPT_CALL_FUNC_DEBUG 1 -// #define OPT_REAL_REGS_DEBUG 1 +// #define OPT_REAL_REGS_DEBUG 1 \ No newline at end of file diff --git a/backend/remill/include/remill/BC/InstructionLifter.h b/backend/remill/include/remill/BC/InstructionLifter.h index 6eb0e6a..f2192de 100644 --- a/backend/remill/include/remill/BC/InstructionLifter.h +++ b/backend/remill/include/remill/BC/InstructionLifter.h @@ -159,7 +159,6 @@ class EcvReg { static std::pair GetRegInfo(const std::string &_reg_name); std::string GetRegName(EcvRegClass ecv_reg_class) const; - bool CheckNoChangedReg() const; bool CheckPassedArgsRegs() const; bool CheckPassedReturnRegs() const; @@ -197,6 +196,8 @@ class BBRegInfoNode { // Save the args registers by semantic functions (for debug) std::unordered_map>> sema_func_args_reg_map; + // Save the pc of semantics functions (for debug) + std::unordered_map sema_func_pc_map; std::unordered_map> post_update_regs; diff --git a/backend/remill/include/remill/BC/TraceLifter.h b/backend/remill/include/remill/BC/TraceLifter.h index 86a1049..29cb697 100644 --- a/backend/remill/include/remill/BC/TraceLifter.h +++ b/backend/remill/include/remill/BC/TraceLifter.h @@ -120,7 +120,6 @@ class PhiRegsBBBagNode { PhiRegsBBBagNode() {} static void Reset() { bb_regs_bag_map.clear(); - bag_passed_caller_reg_map.clear(); bag_num = 0; debug_bag_map.clear(); } @@ -136,7 +135,6 @@ class PhiRegsBBBagNode { static inline std::size_t bag_num = 0; static inline std::unordered_map debug_bag_map = {}; // The register set which should be passed from caller function. - static inline EcvRegMap bag_passed_caller_reg_map; PhiRegsBBBagNode *GetTrueBag(); void MergePrecedingRegMap(PhiRegsBBBagNode *moved_bag); @@ -250,9 +248,13 @@ class VirtualRegsOpt { &cache_map); void AnalyzeRegsBags(); + static void CalPassedCallerRegForBJump(); + void OptimizeVirtualRegsUsage(); static inline std::unordered_map func_v_r_opt_map = {}; + static inline std::unordered_map> + b_jump_callees_map = {}; llvm::Function *func; TraceLifter::Impl *impl; @@ -273,6 +275,9 @@ class VirtualRegsOpt { std::unordered_map bb_regs_bag_map; EcvRegMap passed_caller_reg_map; + EcvRegMap passed_callee_ret_reg_map; + + std::set ret_inst_set; // for debug uint64_t fun_vma; diff --git a/backend/remill/lib/BC/InstructionLifter.cpp b/backend/remill/lib/BC/InstructionLifter.cpp index 2e41318..5e82fe1 100644 --- a/backend/remill/lib/BC/InstructionLifter.cpp +++ b/backend/remill/lib/BC/InstructionLifter.cpp @@ -154,17 +154,12 @@ std::string EcvReg::GetRegName(EcvRegClass ecv_reg_class) const { return ""; } -bool EcvReg::CheckNoChangedReg() const { - return STATE_ORDER == number || RUNTIME_ORDER == number || IGNORE_WRITE_TO_WZR_ORDER == number || - IGNORE_WRITE_TO_XZR_ORDER == number || BRANCH_TAKEN_ORDER == number; -} - bool EcvReg::CheckPassedArgsRegs() const { return (0 <= number && number <= 7) || SP_ORDER == number; } bool EcvReg::CheckPassedReturnRegs() const { - return (0 <= number && number <= 7) || SP_ORDER == number; + return (0 <= number && number <= 1) || SP_ORDER == number; } std::string EcvRegClass2String(EcvRegClass ecv_reg_class) { @@ -242,7 +237,9 @@ BBRegInfoNode::BBRegInfoNode(llvm::Function *func, llvm::Value *state_val, void BBRegInfoNode::join_reg_info_node(BBRegInfoNode *child) { // Join bb_load_reg_map for (auto [_ecv_reg, _ecv_reg_class] : child->bb_load_reg_map) { - bb_load_reg_map.insert({_ecv_reg, _ecv_reg_class}); + if (!bb_store_reg_map.contains(_ecv_reg)) { + bb_load_reg_map.insert({_ecv_reg, _ecv_reg_class}); + } } // Join bb_store_reg_map for (auto [_ecv_reg, _ecv_reg_class] : child->bb_store_reg_map) { @@ -266,6 +263,10 @@ void BBRegInfoNode::join_reg_info_node(BBRegInfoNode *child) { for (auto key_value : child->sema_func_args_reg_map) { sema_func_args_reg_map.insert(key_value); } + // Join sema_func_pc_map + for (auto key_value : child->sema_func_pc_map) { + sema_func_pc_map.insert(key_value); + } } InstructionLifter::Impl::Impl(const Arch *arch_, const IntrinsicTable *intrinsics_) @@ -571,6 +572,8 @@ LiftStatus InstructionLifter::LiftIntoBlock(Instruction &arch_inst, llvm::BasicB << "Unexpected to multiple lift the call instruction."; bb_reg_info_node->sema_call_written_reg_map.insert({sema_inst, write_regs}); + bb_reg_info_node->sema_func_pc_map.insert({sema_inst, arch_inst.pc}); + // Update pre-post index for the target register. if (!arch_inst.updated_addr_reg.name.empty()) { const auto [update_reg_ptr_reg, _] = diff --git a/backend/remill/lib/BC/TraceLifter.cpp b/backend/remill/lib/BC/TraceLifter.cpp index 4decb72..aac1b85 100644 --- a/backend/remill/lib/BC/TraceLifter.cpp +++ b/backend/remill/lib/BC/TraceLifter.cpp @@ -512,6 +512,16 @@ bool TraceLifter::Impl::Lift(uint64_t addr, const char *fn_name, // sacrifice in correctness is made. case Instruction::kCategoryDirectJump: try_add_delay_slot(true, block); + if (!manager.isWithinFunction(trace_addr, inst.branch_taken_pc)) { + auto callee_def_func = get_trace_decl(inst.branch_taken_pc); + if (callee_def_func) { + if (VirtualRegsOpt::b_jump_callees_map.contains(func)) { + VirtualRegsOpt::b_jump_callees_map.at(func).push_back(callee_def_func); + } else { + VirtualRegsOpt::b_jump_callees_map.insert({func, {callee_def_func}}); + } + } + } DirectBranchWithSaveParents(GetOrCreateBranchTakenBlock(), block); break; @@ -681,12 +691,16 @@ bool TraceLifter::Impl::Lift(uint64_t addr, const char *fn_name, } while (false); break; - case Instruction::kCategoryFunctionReturn: + case Instruction::kCategoryFunctionReturn: { try_add_delay_slot(true, block); AddTerminatingTailCall( block, intrinsics->function_return, *intrinsics, trace_addr, llvm::ConstantInt::get(llvm::Type::getInt64Ty(context), trace_addr)); - break; + auto ret_inst = llvm::dyn_cast(block->getTerminator()); + CHECK(ret_inst) << "ret_inst must be ReturnInst. inst: " << LLVMThingToString(ret_inst); + virtual_regs_opt->ret_inst_set.insert(ret_inst); + + } break; case Instruction::kCategoryConditionalFunctionReturn: { CHECK(ArchName::kArchAArch64LittleEndian != arch->arch_name) @@ -850,7 +864,6 @@ bool TraceLifter::Impl::Lift(uint64_t addr, const char *fn_name, // Add StoreInst for the every semantics functions. auto &inst_lifter = inst.GetLifter(); - for (auto &bb : *func) { auto inst = &*bb.begin(); auto t_bb_reg_info_node = virtual_regs_opt->bb_reg_info_node_map.at(&bb); @@ -858,6 +871,13 @@ bool TraceLifter::Impl::Lift(uint64_t addr, const char *fn_name, auto call_inst = llvm::dyn_cast(inst); inst = inst->getNextNode(); if (t_bb_reg_info_node->sema_call_written_reg_map.contains(call_inst)) { +#if defined(OPT_REAL_REGS_DEBUG) + auto debug_llvmir_u64_fn = module->getFunction("debug_llvmir_u64value"); + auto sema_pc = t_bb_reg_info_node->sema_func_pc_map.at(call_inst); + llvm::CallInst::Create( + debug_llvmir_u64_fn, + {llvm::ConstantInt::get(llvm::Type::getInt64Ty(context), sema_pc)}, "", call_inst); +#endif auto &write_regs = t_bb_reg_info_node->sema_call_written_reg_map.at(call_inst); auto call_next_inst = call_inst->getNextNode(); if (write_regs.size() == 1) { @@ -903,6 +923,23 @@ bool TraceLifter::Impl::Lift(uint64_t addr, const char *fn_name, } } } + + // Add passed_caller_reg_map and passed_callee_ret_reg_map. + for (int i = 0; i < 8; i++) { + virtual_regs_opt->passed_caller_reg_map.insert( + {EcvReg(RegKind::General, i), EcvRegClass::RegX}); + virtual_regs_opt->passed_caller_reg_map.insert( + {EcvReg(RegKind::Vector, i), EcvRegClass::RegV}); + virtual_regs_opt->passed_callee_ret_reg_map.insert( + {EcvReg(RegKind::General, i), EcvRegClass::RegX}); + virtual_regs_opt->passed_callee_ret_reg_map.insert( + {EcvReg(RegKind::Vector, i), EcvRegClass::RegV}); + } + virtual_regs_opt->passed_caller_reg_map.insert( + {EcvReg(RegKind::Special, SP_ORDER), EcvRegClass::RegX}); + virtual_regs_opt->passed_callee_ret_reg_map.insert( + {EcvReg(RegKind::Special, SP_ORDER), EcvRegClass::RegX}); + } else { no_indirect_lifted_funcs.insert(func); } @@ -952,8 +989,13 @@ void TraceLifter::Impl::Optimize() { __remill_func_call_v_r_o->passed_caller_reg_map.insert( {EcvReg(RegKind::Vector, i), EcvRegClass::RegV}); } + __remill_func_call_v_r_o->passed_caller_reg_map.insert( + {EcvReg(RegKind::Special, SP_ORDER), EcvRegClass::RegX}); VirtualRegsOpt::func_v_r_opt_map.insert({__remill_func_call_fn, __remill_func_call_v_r_o}); + // re-calculate passed_caller_reg_map considering direct jump function. + VirtualRegsOpt::CalPassedCallerRegForBJump(); + // Opt: OptimizeVirtualRegsUsage. int opt_cnt2 = 1; for (auto lifted_func : no_indirect_lifted_funcs) { @@ -1381,6 +1423,7 @@ void PhiRegsBBBagNode::GetPhiRegsBags( // Calculate bag_passed_caller_reg_map. auto func = root_bb->getParent(); + auto t_fun_v_r_o = VirtualRegsOpt::func_v_r_opt_map.at(func); for (auto &bb : *func) { if (&bb == root_bb) { continue; @@ -1394,23 +1437,42 @@ void PhiRegsBBBagNode::GetPhiRegsBags( already_load_flag |= p_bag->bag_req_reg_map.contains(e_r); } if (!already_load_flag) { - if (!bag_passed_caller_reg_map.contains(e_r)) { - bag_passed_caller_reg_map.insert({e_r, n_e_r_c}); - } else { - auto e_r_c = t_bag->bag_passed_caller_reg_map.at(e_r); - if (GetRegClassSize(e_r_c) < GetRegClassSize(n_e_r_c)) { - bag_passed_caller_reg_map.insert_or_assign(e_r, n_e_r_c); - } - } + t_fun_v_r_o->passed_caller_reg_map.insert({e_r, n_e_r_c}); + } + } + t_fun_v_r_o->passed_caller_reg_map.insert( + {EcvReg(RegKind::Special, SP_ORDER), EcvRegClass::RegX}); + } + + // Calculate passed_callee_ret_reg_map. + auto &ret_set = t_fun_v_r_o->ret_inst_set; + if (!ret_set.empty()) { + auto ret_inst_bg_bag = bb_regs_bag_map.at((*ret_set.begin())->getParent()); + for (auto [e_r, e_r_c] : ret_inst_bg_bag->bag_preceding_store_reg_map) { + bool is_ret_reg = true; + for (auto iter = ret_set.begin(); iter != ret_set.end(); iter++) { + auto t_bag = bb_regs_bag_map.at((*iter)->getParent()); + is_ret_reg &= t_bag->bag_preceding_store_reg_map.contains(e_r); + } + if (is_ret_reg) { + t_fun_v_r_o->passed_callee_ret_reg_map.insert({e_r, e_r_c}); } } } - // std::cout << "func: " << func->getName().str() << " "; - // for (auto [e_r, e_r_c] : bag_passed_caller_reg_map) { - // std::cout << e_r.GetRegName(e_r_c) << ", "; + // if (func->getName().starts_with("_IO_file_xsputn")) { + // std::cout << func->getName().str() << std::endl; + // for (auto [e_r, e_r_c] : bag_passed_caller_reg_map) { + // std::cout << e_r.GetRegName(e_r_c) << ", "; + // } + // std::cout << std::endl; // } - // std::cout << std::endl; + + // (FIXME) + if (func->getName().starts_with("_IO_do_write")) { + t_fun_v_r_o->passed_caller_reg_map.insert({EcvReg(RegKind::General, 1), EcvRegClass::RegX}); + t_fun_v_r_o->passed_caller_reg_map.insert({EcvReg(RegKind::General, 3), EcvRegClass::RegX}); + } } void PhiRegsBBBagNode::DebugGraphStruct(PhiRegsBBBagNode *target_bag) { @@ -1449,6 +1511,46 @@ void PhiRegsBBBagNode::DebugGraphStruct(PhiRegsBBBagNode *target_bag) { ECV_LOG_NL(); } +void VirtualRegsOpt::CalPassedCallerRegForBJump() { + std::stack func_stack; + std::set finished; + for (auto [caller, _] : b_jump_callees_map) { + func_stack.push(caller); + } + while (!func_stack.empty()) { + auto t_fun = func_stack.top(); + func_stack.pop(); + if (finished.contains(t_fun)) { + continue; + } + if (b_jump_callees_map.contains(t_fun)) { + bool callee_fin = true; + for (auto callee : b_jump_callees_map.at(t_fun)) { + callee_fin &= finished.contains(callee); + } + if (callee_fin) { + auto t_fun_v_r_o = func_v_r_opt_map.at(t_fun); + for (auto callee : b_jump_callees_map.at(t_fun)) { + auto callee_v_r_o = func_v_r_opt_map.at(callee); + for (auto [e_r, e_r_c] : callee_v_r_o->passed_caller_reg_map) { + t_fun_v_r_o->passed_caller_reg_map.insert({e_r, e_r_c}); + } + } + finished.insert(t_fun); + } else { + func_stack.push(t_fun); + for (auto callee : b_jump_callees_map.at(t_fun)) { + if (!finished.contains(callee)) { + func_stack.push(callee); + } + } + } + } else { + finished.insert(t_fun); + } + } +} + void VirtualRegsOpt::AnalyzeRegsBags() { impl->virtual_regs_opt = this; @@ -1555,7 +1657,6 @@ void VirtualRegsOpt::AnalyzeRegsBags() { // Calculate the registers which needs to get on the phi nodes for every basic block. PhiRegsBBBagNode::GetPhiRegsBags(&func->getEntryBlock(), bb_reg_info_node_map); bb_regs_bag_map = PhiRegsBBBagNode::bb_regs_bag_map; - passed_caller_reg_map = PhiRegsBBBagNode::bag_passed_caller_reg_map; // Reset static data of PhiRegsBBBagNode. PhiRegsBBBagNode::Reset(); @@ -1705,11 +1806,7 @@ void VirtualRegsOpt::OptimizeVirtualRegsUsage() { debug_reg_set.insert({EcvReg(RegKind::General, i)}); // debug_reg_set.insert({EcvReg(RegKind::Vector, i)}); } - // debug_reg_set.insert({EcvReg(RegKind::General, 3)}); - // debug_reg_set.insert({EcvReg(RegKind::General, 1)}); - // debug_reg_set.insert({EcvReg(RegKind::General, 21)}); - // debug_reg_set.insert({EcvReg(RegKind::General, 24)}); - // debug_reg_set.insert({EcvReg(RegKind::Special, ECV_NZCV_ORDER)}); + debug_reg_set.insert({EcvReg(RegKind::Special, SP_ORDER)}); #endif // Add the phi nodes to the every basic block. @@ -1863,9 +1960,9 @@ void VirtualRegsOpt::OptimizeVirtualRegsUsage() { if (lifted_func_caller_set.contains(call_inst)) { // Store already stored `bb_store_reg_map` for (auto [within_store_ecv_reg, ascend_value] : ascend_reg_inst_map) { - if (within_store_ecv_reg.CheckNoChangedReg() || - !func_v_r_opt_map.at(call_inst->getCalledFunction()) - ->passed_caller_reg_map.contains(within_store_ecv_reg) || + if ( + // !func_v_r_opt_map.at(call_inst->getCalledFunction()) + // ->passed_caller_reg_map.contains(within_store_ecv_reg) || !within_store_ecv_reg.CheckPassedArgsRegs() || !target_bb_reg_info_node->bb_store_reg_map.contains(within_store_ecv_reg)) { continue; @@ -1881,9 +1978,9 @@ void VirtualRegsOpt::OptimizeVirtualRegsUsage() { // Store `preceding_store_map` for (auto [preceding_store_ecv_reg, preceding_store_ecv_reg_class] : target_phi_regs_bag->bag_preceding_store_reg_map) { - if (preceding_store_ecv_reg.CheckNoChangedReg() || - !func_v_r_opt_map.at(call_inst->getCalledFunction()) - ->passed_caller_reg_map.contains(preceding_store_ecv_reg) || + if ( + // !func_v_r_opt_map.at(call_inst->getCalledFunction()) + // ->passed_caller_reg_map.contains(preceding_store_ecv_reg) || !preceding_store_ecv_reg.CheckPassedArgsRegs() || target_bb_reg_info_node->bb_store_reg_map.contains(preceding_store_ecv_reg)) { continue; @@ -1899,7 +1996,10 @@ void VirtualRegsOpt::OptimizeVirtualRegsUsage() { auto call_next_inst = call_inst->getNextNode(); // Load `preceding_store_map` + `load_map` for (auto [req_ecv_reg, tuple_set] : ascend_reg_inst_map) { - if (req_ecv_reg.CheckNoChangedReg() || !req_ecv_reg.CheckPassedReturnRegs()) { + if (!req_ecv_reg.CheckPassedReturnRegs() + // || !func_v_r_opt_map.at(call_inst->getParent()->getParent()) + // ->passed_callee_ret_reg_map.contains(req_ecv_reg) + ) { continue; } auto [req_r_c, userd_val, order] = tuple_set; @@ -2068,10 +2168,11 @@ void VirtualRegsOpt::OptimizeVirtualRegsUsage() { value_reg_map.insert({req_load, {req_ecv_reg, req_r_c}}); } target_inst_it = call_next_inst; - DEBUG_PC_AND_REGISTERS(call_next_inst, ascend_reg_inst_map, 0xffff'ff); + DEBUG_PC_AND_REGISTERS(call_next_inst, ascend_reg_inst_map, 0xdeadbeef); } // Call the general semantic functions. else { + auto call_next_inst = call_inst->getNextNode(); if (target_bb_reg_info_node->sema_call_written_reg_map.contains(call_inst)) { auto &sema_func_write_regs = target_bb_reg_info_node->sema_call_written_reg_map.at(call_inst); @@ -2087,12 +2188,12 @@ void VirtualRegsOpt::OptimizeVirtualRegsUsage() { value_reg_map.insert( {call_inst, {sema_func_write_regs[0].first, sema_func_write_regs[0].second}}); } + DEBUG_PC_AND_REGISTERS(call_next_inst, ascend_reg_inst_map, + Sema_func_vma_map.contains(call_inst) + ? Sema_func_vma_map.at(call_inst) + : 0xffff'ffff); } - target_inst_it = call_inst->getNextNode(); - DEBUG_PC_AND_REGISTERS(call_inst->getNextNode(), ascend_reg_inst_map, - Sema_func_vma_map.contains(call_inst) - ? Sema_func_vma_map.at(call_inst) - : 0xffff'ff); + target_inst_it = call_next_inst; } } // Target: llvm::StoreInst @@ -2140,7 +2241,9 @@ void VirtualRegsOpt::OptimizeVirtualRegsUsage() { << ECV_DEBUG_STREAM.str(); ret_inst = __ret_inst; for (auto [within_store_ecv_reg, ascend_value] : ascend_reg_inst_map) { - if (within_store_ecv_reg.CheckNoChangedReg() || + if ( + // !func_v_r_opt_map.at(ret_inst->getParent()->getParent()) + // ->passed_callee_ret_reg_map.contains(within_store_ecv_reg) || !within_store_ecv_reg.CheckPassedReturnRegs() || !target_bb_reg_info_node->bb_store_reg_map.contains(within_store_ecv_reg)) { continue; @@ -2156,7 +2259,9 @@ void VirtualRegsOpt::OptimizeVirtualRegsUsage() { // Store `preceding_store_map` for (auto [preceding_store_ecv_reg, preceding_store_ecv_reg_class] : target_phi_regs_bag->bag_preceding_store_reg_map) { - if (preceding_store_ecv_reg.CheckNoChangedReg() || + if ( + // !func_v_r_opt_map.at(ret_inst->getParent()->getParent()) + // ->passed_callee_ret_reg_map.contains(preceding_store_ecv_reg) || !preceding_store_ecv_reg.CheckPassedReturnRegs() || target_bb_reg_info_node->bb_store_reg_map.contains(preceding_store_ecv_reg)) { continue; @@ -2271,7 +2376,7 @@ void VirtualRegsOpt::InsertDebugVmaAndRegisters( for (auto debug_ecv_reg : debug_reg_set) { if (ascend_reg_inst_map.contains(debug_ecv_reg)) { - llvm::GlobalVariable *reg_name_gvar; + llvm::GlobalVariable *reg_name_gvar = NULL; if (RegKind::General == debug_ecv_reg.reg_kind) { reg_name_gvar = impl->module->getGlobalVariable("debug_X" + to_string(debug_ecv_reg.number)); @@ -2279,9 +2384,11 @@ void VirtualRegsOpt::InsertDebugVmaAndRegisters( reg_name_gvar = impl->module->getGlobalVariable("debug_V" + to_string(debug_ecv_reg.number)); } else { - // (FIXME) - CHECK(ECV_NZCV_ORDER == debug_ecv_reg.number); - reg_name_gvar = impl->module->getGlobalVariable("debug_ECV_NZCV"); + if (ECV_NZCV_ORDER == debug_ecv_reg.number) { + reg_name_gvar = impl->module->getGlobalVariable("debug_ECV_NZCV"); + } else if (SP_ORDER == debug_ecv_reg.number) { + reg_name_gvar = impl->module->getGlobalVariable("debug_SP"); + } } args.push_back(reg_name_gvar); args.push_back(GetRegValueFromCacheMap(debug_ecv_reg, diff --git a/lifter/MainLifter.cpp b/lifter/MainLifter.cpp index fab806c..aa8c2c8 100644 --- a/lifter/MainLifter.cpp +++ b/lifter/MainLifter.cpp @@ -351,11 +351,15 @@ void MainLifter::WrapImpl::SetRegisterNames() { llvm::GlobalVariable::ExternalLinkage, v_reg_name_i_val, "debug_" + v_reg_name_i); } - + // ECV_NZCV auto ecv_nzcv_name_val = llvm::ConstantDataArray::getString(context, "ECV_NZCV", true); new llvm::GlobalVariable(*module, ecv_nzcv_name_val->getType(), true, llvm::GlobalVariable::ExternalLinkage, ecv_nzcv_name_val, "debug_ECV_NZCV"); + // SP + auto ecv_sp_name_val = llvm::ConstantDataArray::getString(context, "SP", true); + new llvm::GlobalVariable(*module, ecv_sp_name_val->getType(), true, + llvm::GlobalVariable::ExternalLinkage, ecv_sp_name_val, "debug_SP"); } /* Set lifted function symbol name table */ diff --git a/runtime/VmIntrinsics.cpp b/runtime/VmIntrinsics.cpp index 0ee3006..a9ab37a 100644 --- a/runtime/VmIntrinsics.cpp +++ b/runtime/VmIntrinsics.cpp @@ -240,7 +240,7 @@ extern "C" void debug_call_stack_pop(RuntimeManager *runtime_manager, uint64_t f // observe the value change of runtime memory extern "C" void debug_memory_value_change(RuntimeManager *runtime_manager) { // step 1. set target vma - static uint64_t target_vma = 0x499f18; + static uint64_t target_vma = 0x495060; if (0 == target_vma) return; static uint64_t old_value = 0;