diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/debugger/gdbstub_arch.cpp | 4 | ||||
| -rw-r--r-- | src/core/memory/cheat_engine.cpp | 46 | ||||
| -rw-r--r-- | src/core/memory/cheat_engine.h | 8 | ||||
| -rw-r--r-- | src/core/memory/dmnt_cheat_types.h | 2 | ||||
| -rw-r--r-- | src/core/memory/dmnt_cheat_vm.cpp | 74 | ||||
| -rw-r--r-- | src/core/memory/dmnt_cheat_vm.h | 22 |
6 files changed, 105 insertions, 51 deletions
diff --git a/src/core/debugger/gdbstub_arch.cpp b/src/core/debugger/gdbstub_arch.cpp index f2a407dc8..452f565be 100644 --- a/src/core/debugger/gdbstub_arch.cpp +++ b/src/core/debugger/gdbstub_arch.cpp | |||
| @@ -383,7 +383,7 @@ std::string GDBStubA32::RegRead(const Kernel::KThread* thread, size_t id) const | |||
| 383 | } else if (id == CPSR_REGISTER) { | 383 | } else if (id == CPSR_REGISTER) { |
| 384 | return ValueToHex(context.pstate); | 384 | return ValueToHex(context.pstate); |
| 385 | } else if (id >= D0_REGISTER && id < Q0_REGISTER) { | 385 | } else if (id >= D0_REGISTER && id < Q0_REGISTER) { |
| 386 | return ValueToHex(fprs[id - D0_REGISTER][0]); | 386 | return ValueToHex(fprs[(id - D0_REGISTER) / 2][(id - D0_REGISTER) % 2]); |
| 387 | } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) { | 387 | } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) { |
| 388 | return ValueToHex(fprs[id - Q0_REGISTER]); | 388 | return ValueToHex(fprs[id - Q0_REGISTER]); |
| 389 | } else if (id == FPSCR_REGISTER) { | 389 | } else if (id == FPSCR_REGISTER) { |
| @@ -406,7 +406,7 @@ void GDBStubA32::RegWrite(Kernel::KThread* thread, size_t id, std::string_view v | |||
| 406 | } else if (id == CPSR_REGISTER) { | 406 | } else if (id == CPSR_REGISTER) { |
| 407 | context.pstate = HexToValue<u32>(value); | 407 | context.pstate = HexToValue<u32>(value); |
| 408 | } else if (id >= D0_REGISTER && id < Q0_REGISTER) { | 408 | } else if (id >= D0_REGISTER && id < Q0_REGISTER) { |
| 409 | fprs[id - D0_REGISTER] = {HexToValue<u64>(value), 0}; | 409 | fprs[(id - D0_REGISTER) / 2][(id - D0_REGISTER) % 2] = HexToValue<u64>(value); |
| 410 | } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) { | 410 | } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) { |
| 411 | fprs[id - Q0_REGISTER] = HexToValue<u128>(value); | 411 | fprs[id - Q0_REGISTER] = HexToValue<u128>(value); |
| 412 | } else if (id == FPSCR_REGISTER) { | 412 | } else if (id == FPSCR_REGISTER) { |
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp index 96fa7fa3a..14d1a3840 100644 --- a/src/core/memory/cheat_engine.cpp +++ b/src/core/memory/cheat_engine.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "core/core_timing.h" | 9 | #include "core/core_timing.h" |
| 10 | #include "core/hle/kernel/k_page_table.h" | 10 | #include "core/hle/kernel/k_page_table.h" |
| 11 | #include "core/hle/kernel/k_process.h" | 11 | #include "core/hle/kernel/k_process.h" |
| 12 | #include "core/hle/kernel/k_process_page_table.h" | ||
| 12 | #include "core/hle/service/hid/hid_server.h" | 13 | #include "core/hle/service/hid/hid_server.h" |
| 13 | #include "core/hle/service/sm/sm.h" | 14 | #include "core/hle/service/sm/sm.h" |
| 14 | #include "core/memory.h" | 15 | #include "core/memory.h" |
| @@ -46,12 +47,23 @@ StandardVmCallbacks::StandardVmCallbacks(System& system_, const CheatProcessMeta | |||
| 46 | 47 | ||
| 47 | StandardVmCallbacks::~StandardVmCallbacks() = default; | 48 | StandardVmCallbacks::~StandardVmCallbacks() = default; |
| 48 | 49 | ||
| 49 | void StandardVmCallbacks::MemoryRead(VAddr address, void* data, u64 size) { | 50 | void StandardVmCallbacks::MemoryReadUnsafe(VAddr address, void* data, u64 size) { |
| 50 | system.ApplicationMemory().ReadBlock(SanitizeAddress(address), data, size); | 51 | // Return zero on invalid address |
| 52 | if (!IsAddressInRange(address) || !system.ApplicationMemory().IsValidVirtualAddress(address)) { | ||
| 53 | std::memset(data, 0, size); | ||
| 54 | return; | ||
| 55 | } | ||
| 56 | |||
| 57 | system.ApplicationMemory().ReadBlock(address, data, size); | ||
| 51 | } | 58 | } |
| 52 | 59 | ||
| 53 | void StandardVmCallbacks::MemoryWrite(VAddr address, const void* data, u64 size) { | 60 | void StandardVmCallbacks::MemoryWriteUnsafe(VAddr address, const void* data, u64 size) { |
| 54 | system.ApplicationMemory().WriteBlock(SanitizeAddress(address), data, size); | 61 | // Skip invalid memory write address |
| 62 | if (!IsAddressInRange(address) || !system.ApplicationMemory().IsValidVirtualAddress(address)) { | ||
| 63 | return; | ||
| 64 | } | ||
| 65 | |||
| 66 | system.ApplicationMemory().WriteBlock(address, data, size); | ||
| 55 | } | 67 | } |
| 56 | 68 | ||
| 57 | u64 StandardVmCallbacks::HidKeysDown() { | 69 | u64 StandardVmCallbacks::HidKeysDown() { |
| @@ -81,21 +93,25 @@ void StandardVmCallbacks::CommandLog(std::string_view data) { | |||
| 81 | data.back() == '\n' ? data.substr(0, data.size() - 1) : data); | 93 | data.back() == '\n' ? data.substr(0, data.size() - 1) : data); |
| 82 | } | 94 | } |
| 83 | 95 | ||
| 84 | VAddr StandardVmCallbacks::SanitizeAddress(VAddr in) const { | 96 | bool StandardVmCallbacks::IsAddressInRange(VAddr in) const { |
| 85 | if ((in < metadata.main_nso_extents.base || | 97 | if ((in < metadata.main_nso_extents.base || |
| 86 | in >= metadata.main_nso_extents.base + metadata.main_nso_extents.size) && | 98 | in >= metadata.main_nso_extents.base + metadata.main_nso_extents.size) && |
| 87 | (in < metadata.heap_extents.base || | 99 | (in < metadata.heap_extents.base || |
| 88 | in >= metadata.heap_extents.base + metadata.heap_extents.size)) { | 100 | in >= metadata.heap_extents.base + metadata.heap_extents.size) && |
| 89 | LOG_ERROR(CheatEngine, | 101 | (in < metadata.alias_extents.base || |
| 102 | in >= metadata.heap_extents.base + metadata.alias_extents.size) && | ||
| 103 | (in < metadata.aslr_extents.base || | ||
| 104 | in >= metadata.heap_extents.base + metadata.aslr_extents.size)) { | ||
| 105 | LOG_DEBUG(CheatEngine, | ||
| 90 | "Cheat attempting to access memory at invalid address={:016X}, if this " | 106 | "Cheat attempting to access memory at invalid address={:016X}, if this " |
| 91 | "persists, " | 107 | "persists, " |
| 92 | "the cheat may be incorrect. However, this may be normal early in execution if " | 108 | "the cheat may be incorrect. However, this may be normal early in execution if " |
| 93 | "the game has not properly set up yet.", | 109 | "the game has not properly set up yet.", |
| 94 | in); | 110 | in); |
| 95 | return 0; ///< Invalid addresses will hard crash | 111 | return false; ///< Invalid addresses will hard crash |
| 96 | } | 112 | } |
| 97 | 113 | ||
| 98 | return in; | 114 | return true; |
| 99 | } | 115 | } |
| 100 | 116 | ||
| 101 | CheatParser::~CheatParser() = default; | 117 | CheatParser::~CheatParser() = default; |
| @@ -211,16 +227,14 @@ void CheatEngine::Initialize() { | |||
| 211 | .base = GetInteger(page_table.GetHeapRegionStart()), | 227 | .base = GetInteger(page_table.GetHeapRegionStart()), |
| 212 | .size = page_table.GetHeapRegionSize(), | 228 | .size = page_table.GetHeapRegionSize(), |
| 213 | }; | 229 | }; |
| 214 | 230 | metadata.aslr_extents = { | |
| 215 | metadata.address_space_extents = { | ||
| 216 | .base = GetInteger(page_table.GetAddressSpaceStart()), | ||
| 217 | .size = page_table.GetAddressSpaceSize(), | ||
| 218 | }; | ||
| 219 | |||
| 220 | metadata.alias_extents = { | ||
| 221 | .base = GetInteger(page_table.GetAliasCodeRegionStart()), | 231 | .base = GetInteger(page_table.GetAliasCodeRegionStart()), |
| 222 | .size = page_table.GetAliasCodeRegionSize(), | 232 | .size = page_table.GetAliasCodeRegionSize(), |
| 223 | }; | 233 | }; |
| 234 | metadata.alias_extents = { | ||
| 235 | .base = GetInteger(page_table.GetAliasRegionStart()), | ||
| 236 | .size = page_table.GetAliasRegionSize(), | ||
| 237 | }; | ||
| 224 | 238 | ||
| 225 | is_pending_reload.exchange(true); | 239 | is_pending_reload.exchange(true); |
| 226 | } | 240 | } |
diff --git a/src/core/memory/cheat_engine.h b/src/core/memory/cheat_engine.h index ced2168d1..619cabaa2 100644 --- a/src/core/memory/cheat_engine.h +++ b/src/core/memory/cheat_engine.h | |||
| @@ -27,17 +27,17 @@ public: | |||
| 27 | StandardVmCallbacks(System& system_, const CheatProcessMetadata& metadata_); | 27 | StandardVmCallbacks(System& system_, const CheatProcessMetadata& metadata_); |
| 28 | ~StandardVmCallbacks() override; | 28 | ~StandardVmCallbacks() override; |
| 29 | 29 | ||
| 30 | void MemoryRead(VAddr address, void* data, u64 size) override; | 30 | void MemoryReadUnsafe(VAddr address, void* data, u64 size) override; |
| 31 | void MemoryWrite(VAddr address, const void* data, u64 size) override; | 31 | void MemoryWriteUnsafe(VAddr address, const void* data, u64 size) override; |
| 32 | u64 HidKeysDown() override; | 32 | u64 HidKeysDown() override; |
| 33 | void DebugLog(u8 id, u64 value) override; | 33 | void DebugLog(u8 id, u64 value) override; |
| 34 | void CommandLog(std::string_view data) override; | 34 | void CommandLog(std::string_view data) override; |
| 35 | 35 | ||
| 36 | private: | 36 | private: |
| 37 | VAddr SanitizeAddress(VAddr address) const; | 37 | bool IsAddressInRange(VAddr address) const; |
| 38 | 38 | ||
| 39 | const CheatProcessMetadata& metadata; | 39 | const CheatProcessMetadata& metadata; |
| 40 | System& system; | 40 | Core::System& system; |
| 41 | }; | 41 | }; |
| 42 | 42 | ||
| 43 | // Intermediary class that parses a text file or other disk format for storing cheats into a | 43 | // Intermediary class that parses a text file or other disk format for storing cheats into a |
diff --git a/src/core/memory/dmnt_cheat_types.h b/src/core/memory/dmnt_cheat_types.h index c6b40e505..64c072d3d 100644 --- a/src/core/memory/dmnt_cheat_types.h +++ b/src/core/memory/dmnt_cheat_types.h | |||
| @@ -18,7 +18,7 @@ struct CheatProcessMetadata { | |||
| 18 | MemoryRegionExtents main_nso_extents{}; | 18 | MemoryRegionExtents main_nso_extents{}; |
| 19 | MemoryRegionExtents heap_extents{}; | 19 | MemoryRegionExtents heap_extents{}; |
| 20 | MemoryRegionExtents alias_extents{}; | 20 | MemoryRegionExtents alias_extents{}; |
| 21 | MemoryRegionExtents address_space_extents{}; | 21 | MemoryRegionExtents aslr_extents{}; |
| 22 | std::array<u8, 0x20> main_nso_build_id{}; | 22 | std::array<u8, 0x20> main_nso_build_id{}; |
| 23 | }; | 23 | }; |
| 24 | 24 | ||
diff --git a/src/core/memory/dmnt_cheat_vm.cpp b/src/core/memory/dmnt_cheat_vm.cpp index 31ffc4fbb..8bc81e72d 100644 --- a/src/core/memory/dmnt_cheat_vm.cpp +++ b/src/core/memory/dmnt_cheat_vm.cpp | |||
| @@ -322,8 +322,9 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) { | |||
| 322 | } break; | 322 | } break; |
| 323 | case CheatVmOpcodeType::EndConditionalBlock: { | 323 | case CheatVmOpcodeType::EndConditionalBlock: { |
| 324 | // 20000000 | 324 | // 20000000 |
| 325 | // There's actually nothing left to process here! | 325 | opcode.opcode = EndConditionalOpcode{ |
| 326 | opcode.opcode = EndConditionalOpcode{}; | 326 | .is_else = ((first_dword >> 24) & 0xf) == 1, |
| 327 | }; | ||
| 327 | } break; | 328 | } break; |
| 328 | case CheatVmOpcodeType::ControlLoop: { | 329 | case CheatVmOpcodeType::ControlLoop: { |
| 329 | // 300R0000 VVVVVVVV | 330 | // 300R0000 VVVVVVVV |
| @@ -555,6 +556,18 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) { | |||
| 555 | .idx = first_dword & 0xF, | 556 | .idx = first_dword & 0xF, |
| 556 | }; | 557 | }; |
| 557 | } break; | 558 | } break; |
| 559 | case CheatVmOpcodeType::PauseProcess: { | ||
| 560 | /* FF0????? */ | ||
| 561 | /* FF0 = opcode 0xFF0 */ | ||
| 562 | /* Pauses the current process. */ | ||
| 563 | opcode.opcode = PauseProcessOpcode{}; | ||
| 564 | } break; | ||
| 565 | case CheatVmOpcodeType::ResumeProcess: { | ||
| 566 | /* FF0????? */ | ||
| 567 | /* FF0 = opcode 0xFF0 */ | ||
| 568 | /* Pauses the current process. */ | ||
| 569 | opcode.opcode = ResumeProcessOpcode{}; | ||
| 570 | } break; | ||
| 558 | case CheatVmOpcodeType::DebugLog: { | 571 | case CheatVmOpcodeType::DebugLog: { |
| 559 | // FFFTIX## | 572 | // FFFTIX## |
| 560 | // FFFTI0Ma aaaaaaaa | 573 | // FFFTI0Ma aaaaaaaa |
| @@ -621,7 +634,7 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) { | |||
| 621 | return valid; | 634 | return valid; |
| 622 | } | 635 | } |
| 623 | 636 | ||
| 624 | void DmntCheatVm::SkipConditionalBlock() { | 637 | void DmntCheatVm::SkipConditionalBlock(bool is_if) { |
| 625 | if (condition_depth > 0) { | 638 | if (condition_depth > 0) { |
| 626 | // We want to continue until we're out of the current block. | 639 | // We want to continue until we're out of the current block. |
| 627 | const std::size_t desired_depth = condition_depth - 1; | 640 | const std::size_t desired_depth = condition_depth - 1; |
| @@ -637,8 +650,12 @@ void DmntCheatVm::SkipConditionalBlock() { | |||
| 637 | // We also support nesting of conditional blocks, and Gateway does not. | 650 | // We also support nesting of conditional blocks, and Gateway does not. |
| 638 | if (skip_opcode.begin_conditional_block) { | 651 | if (skip_opcode.begin_conditional_block) { |
| 639 | condition_depth++; | 652 | condition_depth++; |
| 640 | } else if (std::holds_alternative<EndConditionalOpcode>(skip_opcode.opcode)) { | 653 | } else if (auto end_cond = std::get_if<EndConditionalOpcode>(&skip_opcode.opcode)) { |
| 641 | condition_depth--; | 654 | if (!end_cond->is_else) { |
| 655 | condition_depth--; | ||
| 656 | } else if (is_if && condition_depth - 1 == desired_depth) { | ||
| 657 | break; | ||
| 658 | } | ||
| 642 | } | 659 | } |
| 643 | } | 660 | } |
| 644 | } else { | 661 | } else { |
| @@ -675,6 +692,10 @@ u64 DmntCheatVm::GetCheatProcessAddress(const CheatProcessMetadata& metadata, | |||
| 675 | return metadata.main_nso_extents.base + rel_address; | 692 | return metadata.main_nso_extents.base + rel_address; |
| 676 | case MemoryAccessType::Heap: | 693 | case MemoryAccessType::Heap: |
| 677 | return metadata.heap_extents.base + rel_address; | 694 | return metadata.heap_extents.base + rel_address; |
| 695 | case MemoryAccessType::Alias: | ||
| 696 | return metadata.alias_extents.base + rel_address; | ||
| 697 | case MemoryAccessType::Aslr: | ||
| 698 | return metadata.aslr_extents.base + rel_address; | ||
| 678 | } | 699 | } |
| 679 | } | 700 | } |
| 680 | 701 | ||
| @@ -682,7 +703,6 @@ void DmntCheatVm::ResetState() { | |||
| 682 | registers.fill(0); | 703 | registers.fill(0); |
| 683 | saved_values.fill(0); | 704 | saved_values.fill(0); |
| 684 | loop_tops.fill(0); | 705 | loop_tops.fill(0); |
| 685 | static_registers.fill(0); | ||
| 686 | instruction_ptr = 0; | 706 | instruction_ptr = 0; |
| 687 | condition_depth = 0; | 707 | condition_depth = 0; |
| 688 | decode_success = true; | 708 | decode_success = true; |
| @@ -753,7 +773,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) { | |||
| 753 | case 2: | 773 | case 2: |
| 754 | case 4: | 774 | case 4: |
| 755 | case 8: | 775 | case 8: |
| 756 | callbacks->MemoryWrite(dst_address, &dst_value, store_static->bit_width); | 776 | callbacks->MemoryWriteUnsafe(dst_address, &dst_value, store_static->bit_width); |
| 757 | break; | 777 | break; |
| 758 | } | 778 | } |
| 759 | } else if (auto begin_cond = std::get_if<BeginConditionalOpcode>(&cur_opcode.opcode)) { | 779 | } else if (auto begin_cond = std::get_if<BeginConditionalOpcode>(&cur_opcode.opcode)) { |
| @@ -766,7 +786,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) { | |||
| 766 | case 2: | 786 | case 2: |
| 767 | case 4: | 787 | case 4: |
| 768 | case 8: | 788 | case 8: |
| 769 | callbacks->MemoryRead(src_address, &src_value, begin_cond->bit_width); | 789 | callbacks->MemoryReadUnsafe(src_address, &src_value, begin_cond->bit_width); |
| 770 | break; | 790 | break; |
| 771 | } | 791 | } |
| 772 | // Check against condition. | 792 | // Check against condition. |
| @@ -794,13 +814,18 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) { | |||
| 794 | } | 814 | } |
| 795 | // Skip conditional block if condition not met. | 815 | // Skip conditional block if condition not met. |
| 796 | if (!cond_met) { | 816 | if (!cond_met) { |
| 797 | SkipConditionalBlock(); | 817 | SkipConditionalBlock(true); |
| 798 | } | 818 | } |
| 799 | } else if (std::holds_alternative<EndConditionalOpcode>(cur_opcode.opcode)) { | 819 | } else if (auto end_cond = std::get_if<EndConditionalOpcode>(&cur_opcode.opcode)) { |
| 800 | // Decrement the condition depth. | 820 | if (end_cond->is_else) { |
| 801 | // We will assume, graciously, that mismatched conditional block ends are a nop. | 821 | /* Skip to the end of the conditional block. */ |
| 802 | if (condition_depth > 0) { | 822 | this->SkipConditionalBlock(false); |
| 803 | condition_depth--; | 823 | } else { |
| 824 | /* Decrement the condition depth. */ | ||
| 825 | /* We will assume, graciously, that mismatched conditional block ends are a nop. */ | ||
| 826 | if (condition_depth > 0) { | ||
| 827 | condition_depth--; | ||
| 828 | } | ||
| 804 | } | 829 | } |
| 805 | } else if (auto ctrl_loop = std::get_if<ControlLoopOpcode>(&cur_opcode.opcode)) { | 830 | } else if (auto ctrl_loop = std::get_if<ControlLoopOpcode>(&cur_opcode.opcode)) { |
| 806 | if (ctrl_loop->start_loop) { | 831 | if (ctrl_loop->start_loop) { |
| @@ -832,8 +857,8 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) { | |||
| 832 | case 2: | 857 | case 2: |
| 833 | case 4: | 858 | case 4: |
| 834 | case 8: | 859 | case 8: |
| 835 | callbacks->MemoryRead(src_address, ®isters[ldr_memory->reg_index], | 860 | callbacks->MemoryReadUnsafe(src_address, ®isters[ldr_memory->reg_index], |
| 836 | ldr_memory->bit_width); | 861 | ldr_memory->bit_width); |
| 837 | break; | 862 | break; |
| 838 | } | 863 | } |
| 839 | } else if (auto str_static = std::get_if<StoreStaticToAddressOpcode>(&cur_opcode.opcode)) { | 864 | } else if (auto str_static = std::get_if<StoreStaticToAddressOpcode>(&cur_opcode.opcode)) { |
| @@ -849,7 +874,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) { | |||
| 849 | case 2: | 874 | case 2: |
| 850 | case 4: | 875 | case 4: |
| 851 | case 8: | 876 | case 8: |
| 852 | callbacks->MemoryWrite(dst_address, &dst_value, str_static->bit_width); | 877 | callbacks->MemoryWriteUnsafe(dst_address, &dst_value, str_static->bit_width); |
| 853 | break; | 878 | break; |
| 854 | } | 879 | } |
| 855 | // Increment register if relevant. | 880 | // Increment register if relevant. |
| @@ -908,7 +933,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) { | |||
| 908 | // Check for keypress. | 933 | // Check for keypress. |
| 909 | if ((begin_keypress_cond->key_mask & kDown) != begin_keypress_cond->key_mask) { | 934 | if ((begin_keypress_cond->key_mask & kDown) != begin_keypress_cond->key_mask) { |
| 910 | // Keys not pressed. Skip conditional block. | 935 | // Keys not pressed. Skip conditional block. |
| 911 | SkipConditionalBlock(); | 936 | SkipConditionalBlock(true); |
| 912 | } | 937 | } |
| 913 | } else if (auto perform_math_reg = | 938 | } else if (auto perform_math_reg = |
| 914 | std::get_if<PerformArithmeticRegisterOpcode>(&cur_opcode.opcode)) { | 939 | std::get_if<PerformArithmeticRegisterOpcode>(&cur_opcode.opcode)) { |
| @@ -1007,7 +1032,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) { | |||
| 1007 | case 2: | 1032 | case 2: |
| 1008 | case 4: | 1033 | case 4: |
| 1009 | case 8: | 1034 | case 8: |
| 1010 | callbacks->MemoryWrite(dst_address, &dst_value, str_register->bit_width); | 1035 | callbacks->MemoryWriteUnsafe(dst_address, &dst_value, str_register->bit_width); |
| 1011 | break; | 1036 | break; |
| 1012 | } | 1037 | } |
| 1013 | 1038 | ||
| @@ -1086,7 +1111,8 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) { | |||
| 1086 | case 2: | 1111 | case 2: |
| 1087 | case 4: | 1112 | case 4: |
| 1088 | case 8: | 1113 | case 8: |
| 1089 | callbacks->MemoryRead(cond_address, &cond_value, begin_reg_cond->bit_width); | 1114 | callbacks->MemoryReadUnsafe(cond_address, &cond_value, |
| 1115 | begin_reg_cond->bit_width); | ||
| 1090 | break; | 1116 | break; |
| 1091 | } | 1117 | } |
| 1092 | } | 1118 | } |
| @@ -1116,7 +1142,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) { | |||
| 1116 | 1142 | ||
| 1117 | // Skip conditional block if condition not met. | 1143 | // Skip conditional block if condition not met. |
| 1118 | if (!cond_met) { | 1144 | if (!cond_met) { |
| 1119 | SkipConditionalBlock(); | 1145 | SkipConditionalBlock(true); |
| 1120 | } | 1146 | } |
| 1121 | } else if (auto save_restore_reg = | 1147 | } else if (auto save_restore_reg = |
| 1122 | std::get_if<SaveRestoreRegisterOpcode>(&cur_opcode.opcode)) { | 1148 | std::get_if<SaveRestoreRegisterOpcode>(&cur_opcode.opcode)) { |
| @@ -1178,6 +1204,10 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) { | |||
| 1178 | // Store a register to a static register. | 1204 | // Store a register to a static register. |
| 1179 | static_registers[rw_static_reg->static_idx] = registers[rw_static_reg->idx]; | 1205 | static_registers[rw_static_reg->static_idx] = registers[rw_static_reg->idx]; |
| 1180 | } | 1206 | } |
| 1207 | } else if (std::holds_alternative<PauseProcessOpcode>(cur_opcode.opcode)) { | ||
| 1208 | // TODO: Pause cheat process | ||
| 1209 | } else if (std::holds_alternative<ResumeProcessOpcode>(cur_opcode.opcode)) { | ||
| 1210 | // TODO: Resume cheat process | ||
| 1181 | } else if (auto debug_log = std::get_if<DebugLogOpcode>(&cur_opcode.opcode)) { | 1211 | } else if (auto debug_log = std::get_if<DebugLogOpcode>(&cur_opcode.opcode)) { |
| 1182 | // Read value from memory. | 1212 | // Read value from memory. |
| 1183 | u64 log_value = 0; | 1213 | u64 log_value = 0; |
| @@ -1224,7 +1254,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) { | |||
| 1224 | case 2: | 1254 | case 2: |
| 1225 | case 4: | 1255 | case 4: |
| 1226 | case 8: | 1256 | case 8: |
| 1227 | callbacks->MemoryRead(val_address, &log_value, debug_log->bit_width); | 1257 | callbacks->MemoryReadUnsafe(val_address, &log_value, debug_log->bit_width); |
| 1228 | break; | 1258 | break; |
| 1229 | } | 1259 | } |
| 1230 | } | 1260 | } |
diff --git a/src/core/memory/dmnt_cheat_vm.h b/src/core/memory/dmnt_cheat_vm.h index 641cb09c4..fed6a24ad 100644 --- a/src/core/memory/dmnt_cheat_vm.h +++ b/src/core/memory/dmnt_cheat_vm.h | |||
| @@ -42,12 +42,16 @@ enum class CheatVmOpcodeType : u32 { | |||
| 42 | DoubleExtendedWidth = 0xF0, | 42 | DoubleExtendedWidth = 0xF0, |
| 43 | 43 | ||
| 44 | // Double-extended width opcodes. | 44 | // Double-extended width opcodes. |
| 45 | PauseProcess = 0xFF0, | ||
| 46 | ResumeProcess = 0xFF1, | ||
| 45 | DebugLog = 0xFFF, | 47 | DebugLog = 0xFFF, |
| 46 | }; | 48 | }; |
| 47 | 49 | ||
| 48 | enum class MemoryAccessType : u32 { | 50 | enum class MemoryAccessType : u32 { |
| 49 | MainNso = 0, | 51 | MainNso = 0, |
| 50 | Heap = 1, | 52 | Heap = 1, |
| 53 | Alias = 2, | ||
| 54 | Aslr = 3, | ||
| 51 | }; | 55 | }; |
| 52 | 56 | ||
| 53 | enum class ConditionalComparisonType : u32 { | 57 | enum class ConditionalComparisonType : u32 { |
| @@ -131,7 +135,9 @@ struct BeginConditionalOpcode { | |||
| 131 | VmInt value{}; | 135 | VmInt value{}; |
| 132 | }; | 136 | }; |
| 133 | 137 | ||
| 134 | struct EndConditionalOpcode {}; | 138 | struct EndConditionalOpcode { |
| 139 | bool is_else; | ||
| 140 | }; | ||
| 135 | 141 | ||
| 136 | struct ControlLoopOpcode { | 142 | struct ControlLoopOpcode { |
| 137 | bool start_loop{}; | 143 | bool start_loop{}; |
| @@ -222,6 +228,10 @@ struct ReadWriteStaticRegisterOpcode { | |||
| 222 | u32 idx{}; | 228 | u32 idx{}; |
| 223 | }; | 229 | }; |
| 224 | 230 | ||
| 231 | struct PauseProcessOpcode {}; | ||
| 232 | |||
| 233 | struct ResumeProcessOpcode {}; | ||
| 234 | |||
| 225 | struct DebugLogOpcode { | 235 | struct DebugLogOpcode { |
| 226 | u32 bit_width{}; | 236 | u32 bit_width{}; |
| 227 | u32 log_id{}; | 237 | u32 log_id{}; |
| @@ -244,8 +254,8 @@ struct CheatVmOpcode { | |||
| 244 | PerformArithmeticStaticOpcode, BeginKeypressConditionalOpcode, | 254 | PerformArithmeticStaticOpcode, BeginKeypressConditionalOpcode, |
| 245 | PerformArithmeticRegisterOpcode, StoreRegisterToAddressOpcode, | 255 | PerformArithmeticRegisterOpcode, StoreRegisterToAddressOpcode, |
| 246 | BeginRegisterConditionalOpcode, SaveRestoreRegisterOpcode, | 256 | BeginRegisterConditionalOpcode, SaveRestoreRegisterOpcode, |
| 247 | SaveRestoreRegisterMaskOpcode, ReadWriteStaticRegisterOpcode, DebugLogOpcode, | 257 | SaveRestoreRegisterMaskOpcode, ReadWriteStaticRegisterOpcode, PauseProcessOpcode, |
| 248 | UnrecognizedInstruction> | 258 | ResumeProcessOpcode, DebugLogOpcode, UnrecognizedInstruction> |
| 249 | opcode{}; | 259 | opcode{}; |
| 250 | }; | 260 | }; |
| 251 | 261 | ||
| @@ -256,8 +266,8 @@ public: | |||
| 256 | public: | 266 | public: |
| 257 | virtual ~Callbacks(); | 267 | virtual ~Callbacks(); |
| 258 | 268 | ||
| 259 | virtual void MemoryRead(VAddr address, void* data, u64 size) = 0; | 269 | virtual void MemoryReadUnsafe(VAddr address, void* data, u64 size) = 0; |
| 260 | virtual void MemoryWrite(VAddr address, const void* data, u64 size) = 0; | 270 | virtual void MemoryWriteUnsafe(VAddr address, const void* data, u64 size) = 0; |
| 261 | 271 | ||
| 262 | virtual u64 HidKeysDown() = 0; | 272 | virtual u64 HidKeysDown() = 0; |
| 263 | 273 | ||
| @@ -296,7 +306,7 @@ private: | |||
| 296 | std::array<std::size_t, NumRegisters> loop_tops{}; | 306 | std::array<std::size_t, NumRegisters> loop_tops{}; |
| 297 | 307 | ||
| 298 | bool DecodeNextOpcode(CheatVmOpcode& out); | 308 | bool DecodeNextOpcode(CheatVmOpcode& out); |
| 299 | void SkipConditionalBlock(); | 309 | void SkipConditionalBlock(bool is_if); |
| 300 | void ResetState(); | 310 | void ResetState(); |
| 301 | 311 | ||
| 302 | // For implementing the DebugLog opcode. | 312 | // For implementing the DebugLog opcode. |