From 7d41c1f52390abb47e67d3fc43310e9d87fbd862 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 30 May 2019 19:35:03 -0400 Subject: cheat_engine: Move to memory and strip VM This is to go with the Atmosphere VM port, now it just contains the callbacks needed for the interface between DmntCheatVm and yuzu, along with the cheat parsers. --- src/core/file_sys/cheat_engine.cpp | 492 ------------------------------------- src/core/file_sys/cheat_engine.h | 234 ------------------ 2 files changed, 726 deletions(-) delete mode 100644 src/core/file_sys/cheat_engine.cpp delete mode 100644 src/core/file_sys/cheat_engine.h (limited to 'src/core/file_sys') diff --git a/src/core/file_sys/cheat_engine.cpp b/src/core/file_sys/cheat_engine.cpp deleted file mode 100644 index b06c2f20a..000000000 --- a/src/core/file_sys/cheat_engine.cpp +++ /dev/null @@ -1,492 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include "common/hex_util.h" -#include "common/microprofile.h" -#include "common/swap.h" -#include "core/core.h" -#include "core/core_timing.h" -#include "core/core_timing_util.h" -#include "core/file_sys/cheat_engine.h" -#include "core/hle/kernel/process.h" -#include "core/hle/service/hid/controllers/npad.h" -#include "core/hle/service/hid/hid.h" -#include "core/hle/service/sm/sm.h" - -namespace FileSys { - -constexpr s64 CHEAT_ENGINE_TICKS = static_cast(Core::Timing::BASE_CLOCK_RATE / 60); -constexpr u32 KEYPAD_BITMASK = 0x3FFFFFF; - -u64 Cheat::Address() const { - u64 out; - std::memcpy(&out, raw.data(), sizeof(u64)); - return Common::swap64(out) & 0xFFFFFFFFFF; -} - -u64 Cheat::ValueWidth(u64 offset) const { - return Value(offset, width); -} - -u64 Cheat::Value(u64 offset, u64 width) const { - u64 out; - std::memcpy(&out, raw.data() + offset, sizeof(u64)); - out = Common::swap64(out); - if (width == 8) - return out; - return out & ((1ull << (width * CHAR_BIT)) - 1); -} - -u32 Cheat::KeypadValue() const { - u32 out; - std::memcpy(&out, raw.data(), sizeof(u32)); - return Common::swap32(out) & 0x0FFFFFFF; -} - -void CheatList::SetMemoryParameters(VAddr main_begin, VAddr heap_begin, VAddr main_end, - VAddr heap_end, MemoryWriter writer, MemoryReader reader) { - this->main_region_begin = main_begin; - this->main_region_end = main_end; - this->heap_region_begin = heap_begin; - this->heap_region_end = heap_end; - this->writer = writer; - this->reader = reader; -} - -MICROPROFILE_DEFINE(Cheat_Engine, "Add-Ons", "Cheat Engine", MP_RGB(70, 200, 70)); - -void CheatList::Execute() { - MICROPROFILE_SCOPE(Cheat_Engine); - - std::fill(scratch.begin(), scratch.end(), 0); - in_standard = false; - for (std::size_t i = 0; i < master_list.size(); ++i) { - LOG_DEBUG(Common_Filesystem, "Executing block #{:08X} ({})", i, master_list[i].first); - current_block = i; - ExecuteBlock(master_list[i].second); - } - - in_standard = true; - for (std::size_t i = 0; i < standard_list.size(); ++i) { - LOG_DEBUG(Common_Filesystem, "Executing block #{:08X} ({})", i, standard_list[i].first); - current_block = i; - ExecuteBlock(standard_list[i].second); - } -} - -CheatList::CheatList(const Core::System& system_, ProgramSegment master, ProgramSegment standard) - : master_list{std::move(master)}, standard_list{std::move(standard)}, system{&system_} {} - -bool CheatList::EvaluateConditional(const Cheat& cheat) const { - using ComparisonFunction = bool (*)(u64, u64); - constexpr std::array comparison_functions{ - [](u64 a, u64 b) { return a > b; }, [](u64 a, u64 b) { return a >= b; }, - [](u64 a, u64 b) { return a < b; }, [](u64 a, u64 b) { return a <= b; }, - [](u64 a, u64 b) { return a == b; }, [](u64 a, u64 b) { return a != b; }, - }; - - if (cheat.type == CodeType::ConditionalInput) { - const auto applet_resource = - system->ServiceManager().GetService("hid")->GetAppletResource(); - if (applet_resource == nullptr) { - LOG_WARNING( - Common_Filesystem, - "Attempted to evaluate input conditional, but applet resource is not initialized!"); - return false; - } - - const auto press_state = - applet_resource - ->GetController(Service::HID::HidController::NPad) - .GetAndResetPressState(); - return ((press_state & cheat.KeypadValue()) & KEYPAD_BITMASK) != 0; - } - - ASSERT(cheat.type == CodeType::Conditional); - - const auto offset = - cheat.memory_type == MemoryType::MainNSO ? main_region_begin : heap_region_begin; - ASSERT(static_cast(cheat.comparison_op.Value()) < 6); - auto* function = comparison_functions[static_cast(cheat.comparison_op.Value())]; - const auto addr = cheat.Address() + offset; - - return function(reader(cheat.width, SanitizeAddress(addr)), cheat.ValueWidth(8)); -} - -void CheatList::ProcessBlockPairs(const Block& block) { - block_pairs.clear(); - - u64 scope = 0; - std::map pairs; - - for (std::size_t i = 0; i < block.size(); ++i) { - const auto& cheat = block[i]; - - switch (cheat.type) { - case CodeType::Conditional: - case CodeType::ConditionalInput: - pairs.insert_or_assign(scope, i); - ++scope; - break; - case CodeType::EndConditional: { - --scope; - const auto idx = pairs.at(scope); - block_pairs.insert_or_assign(idx, i); - break; - } - case CodeType::Loop: { - if (cheat.end_of_loop) { - --scope; - const auto idx = pairs.at(scope); - block_pairs.insert_or_assign(idx, i); - } else { - pairs.insert_or_assign(scope, i); - ++scope; - } - break; - } - } - } -} - -void CheatList::WriteImmediate(const Cheat& cheat) { - const auto offset = - cheat.memory_type == MemoryType::MainNSO ? main_region_begin : heap_region_begin; - const auto& register_3 = scratch.at(cheat.register_3); - - const auto addr = cheat.Address() + offset + register_3; - LOG_DEBUG(Common_Filesystem, "writing value={:016X} to addr={:016X}", addr, - cheat.Value(8, cheat.width)); - writer(cheat.width, SanitizeAddress(addr), cheat.ValueWidth(8)); -} - -void CheatList::BeginConditional(const Cheat& cheat) { - if (EvaluateConditional(cheat)) { - return; - } - - const auto iter = block_pairs.find(current_index); - ASSERT(iter != block_pairs.end()); - current_index = iter->second - 1; -} - -void CheatList::EndConditional(const Cheat& cheat) { - LOG_DEBUG(Common_Filesystem, "Ending conditional block."); -} - -void CheatList::Loop(const Cheat& cheat) { - if (cheat.end_of_loop.Value()) - ASSERT(!cheat.end_of_loop.Value()); - - auto& register_3 = scratch.at(cheat.register_3); - const auto iter = block_pairs.find(current_index); - ASSERT(iter != block_pairs.end()); - ASSERT(iter->first < iter->second); - - const s32 initial_value = static_cast(cheat.Value(4, sizeof(s32))); - for (s32 i = initial_value; i >= 0; --i) { - register_3 = static_cast(i); - for (std::size_t c = iter->first + 1; c < iter->second; ++c) { - current_index = c; - ExecuteSingleCheat( - (in_standard ? standard_list : master_list)[current_block].second[c]); - } - } - - current_index = iter->second; -} - -void CheatList::LoadImmediate(const Cheat& cheat) { - auto& register_3 = scratch.at(cheat.register_3); - - LOG_DEBUG(Common_Filesystem, "setting register={:01X} equal to value={:016X}", cheat.register_3, - cheat.Value(4, 8)); - register_3 = cheat.Value(4, 8); -} - -void CheatList::LoadIndexed(const Cheat& cheat) { - const auto offset = - cheat.memory_type == MemoryType::MainNSO ? main_region_begin : heap_region_begin; - auto& register_3 = scratch.at(cheat.register_3); - - const auto addr = (cheat.load_from_register.Value() ? register_3 : offset) + cheat.Address(); - LOG_DEBUG(Common_Filesystem, "writing indexed value to register={:01X}, addr={:016X}", - cheat.register_3, addr); - register_3 = reader(cheat.width, SanitizeAddress(addr)); -} - -void CheatList::StoreIndexed(const Cheat& cheat) { - const auto& register_3 = scratch.at(cheat.register_3); - - const auto addr = - register_3 + (cheat.add_additional_register.Value() ? scratch.at(cheat.register_6) : 0); - LOG_DEBUG(Common_Filesystem, "writing value={:016X} to addr={:016X}", - cheat.Value(4, cheat.width), addr); - writer(cheat.width, SanitizeAddress(addr), cheat.ValueWidth(4)); -} - -void CheatList::RegisterArithmetic(const Cheat& cheat) { - using ArithmeticFunction = u64 (*)(u64, u64); - constexpr std::array arithmetic_functions{ - [](u64 a, u64 b) { return a + b; }, [](u64 a, u64 b) { return a - b; }, - [](u64 a, u64 b) { return a * b; }, [](u64 a, u64 b) { return a << b; }, - [](u64 a, u64 b) { return a >> b; }, - }; - - using ArithmeticOverflowCheck = bool (*)(u64, u64); - constexpr std::array arithmetic_overflow_checks{ - [](u64 a, u64 b) { return a > (std::numeric_limits::max() - b); }, // a + b - [](u64 a, u64 b) { return a > (std::numeric_limits::max() + b); }, // a - b - [](u64 a, u64 b) { return a > (std::numeric_limits::max() / b); }, // a * b - [](u64 a, u64 b) { return b >= 64 || (a & ~((1ull << (64 - b)) - 1)) != 0; }, // a << b - [](u64 a, u64 b) { return b >= 64 || (a & ((1ull << b) - 1)) != 0; }, // a >> b - }; - - static_assert(sizeof(arithmetic_functions) == sizeof(arithmetic_overflow_checks), - "Missing or have extra arithmetic overflow checks compared to functions!"); - - auto& register_3 = scratch.at(cheat.register_3); - - ASSERT(static_cast(cheat.arithmetic_op.Value()) < 5); - auto* function = arithmetic_functions[static_cast(cheat.arithmetic_op.Value())]; - auto* overflow_function = - arithmetic_overflow_checks[static_cast(cheat.arithmetic_op.Value())]; - LOG_DEBUG(Common_Filesystem, "performing arithmetic with register={:01X}, value={:016X}", - cheat.register_3, cheat.ValueWidth(4)); - - if (overflow_function(register_3, cheat.ValueWidth(4))) { - LOG_WARNING(Common_Filesystem, - "overflow will occur when performing arithmetic operation={:02X} with operands " - "a={:016X}, b={:016X}!", - static_cast(cheat.arithmetic_op.Value()), register_3, cheat.ValueWidth(4)); - } - - register_3 = function(register_3, cheat.ValueWidth(4)); -} - -void CheatList::BeginConditionalInput(const Cheat& cheat) { - if (EvaluateConditional(cheat)) - return; - - const auto iter = block_pairs.find(current_index); - ASSERT(iter != block_pairs.end()); - current_index = iter->second - 1; -} - -VAddr CheatList::SanitizeAddress(VAddr in) const { - if ((in < main_region_begin || in >= main_region_end) && - (in < heap_region_begin || in >= heap_region_end)) { - LOG_ERROR(Common_Filesystem, - "Cheat attempting to access memory at invalid address={:016X}, if this persists, " - "the cheat may be incorrect. However, this may be normal early in execution if " - "the game has not properly set up yet.", - in); - return 0; ///< Invalid addresses will hard crash - } - - return in; -} - -void CheatList::ExecuteSingleCheat(const Cheat& cheat) { - using CheatOperationFunction = void (CheatList::*)(const Cheat&); - constexpr std::array cheat_operation_functions{ - &CheatList::WriteImmediate, &CheatList::BeginConditional, - &CheatList::EndConditional, &CheatList::Loop, - &CheatList::LoadImmediate, &CheatList::LoadIndexed, - &CheatList::StoreIndexed, &CheatList::RegisterArithmetic, - &CheatList::BeginConditionalInput, - }; - - const auto index = static_cast(cheat.type.Value()); - ASSERT(index < sizeof(cheat_operation_functions)); - const auto op = cheat_operation_functions[index]; - (this->*op)(cheat); -} - -void CheatList::ExecuteBlock(const Block& block) { - encountered_loops.clear(); - - ProcessBlockPairs(block); - for (std::size_t i = 0; i < block.size(); ++i) { - current_index = i; - ExecuteSingleCheat(block[i]); - i = current_index; - } -} - -CheatParser::~CheatParser() = default; - -CheatList CheatParser::MakeCheatList(const Core::System& system, CheatList::ProgramSegment master, - CheatList::ProgramSegment standard) const { - return {system, std::move(master), std::move(standard)}; -} - -TextCheatParser::~TextCheatParser() = default; - -CheatList TextCheatParser::Parse(const Core::System& system, const std::vector& data) const { - std::stringstream ss; - ss.write(reinterpret_cast(data.data()), data.size()); - - std::vector lines; - std::string stream_line; - while (std::getline(ss, stream_line)) { - // Remove a trailing \r - if (!stream_line.empty() && stream_line.back() == '\r') - stream_line.pop_back(); - lines.push_back(std::move(stream_line)); - } - - CheatList::ProgramSegment master_list; - CheatList::ProgramSegment standard_list; - - for (std::size_t i = 0; i < lines.size(); ++i) { - auto line = lines[i]; - - if (!line.empty() && (line[0] == '[' || line[0] == '{')) { - const auto master = line[0] == '{'; - const auto begin = master ? line.find('{') : line.find('['); - const auto end = master ? line.rfind('}') : line.rfind(']'); - - ASSERT(begin != std::string::npos && end != std::string::npos); - - const std::string patch_name{line.begin() + begin + 1, line.begin() + end}; - CheatList::Block block{}; - - while (i < lines.size() - 1) { - line = lines[++i]; - if (!line.empty() && (line[0] == '[' || line[0] == '{')) { - --i; - break; - } - - if (line.size() < 8) - continue; - - Cheat out{}; - out.raw = ParseSingleLineCheat(line); - block.push_back(out); - } - - (master ? master_list : standard_list).emplace_back(patch_name, block); - } - } - - return MakeCheatList(system, master_list, standard_list); -} - -std::array TextCheatParser::ParseSingleLineCheat(const std::string& line) const { - std::array out{}; - - if (line.size() < 8) - return out; - - const auto word1 = Common::HexStringToArray(std::string_view{line.data(), 8}); - std::memcpy(out.data(), word1.data(), sizeof(u32)); - - if (line.size() < 17 || line[8] != ' ') - return out; - - const auto word2 = Common::HexStringToArray(std::string_view{line.data() + 9, 8}); - std::memcpy(out.data() + sizeof(u32), word2.data(), sizeof(u32)); - - if (line.size() < 26 || line[17] != ' ') { - // Perform shifting in case value is truncated early. - const auto type = static_cast((out[0] & 0xF0) >> 4); - if (type == CodeType::Loop || type == CodeType::LoadImmediate || - type == CodeType::StoreIndexed || type == CodeType::RegisterArithmetic) { - std::memcpy(out.data() + 8, out.data() + 4, sizeof(u32)); - std::memset(out.data() + 4, 0, sizeof(u32)); - } - - return out; - } - - const auto word3 = Common::HexStringToArray(std::string_view{line.data() + 18, 8}); - std::memcpy(out.data() + 2 * sizeof(u32), word3.data(), sizeof(u32)); - - if (line.size() < 35 || line[26] != ' ') { - // Perform shifting in case value is truncated early. - const auto type = static_cast((out[0] & 0xF0) >> 4); - if (type == CodeType::WriteImmediate || type == CodeType::Conditional) { - std::memcpy(out.data() + 12, out.data() + 8, sizeof(u32)); - std::memset(out.data() + 8, 0, sizeof(u32)); - } - - return out; - } - - const auto word4 = Common::HexStringToArray(std::string_view{line.data() + 27, 8}); - std::memcpy(out.data() + 3 * sizeof(u32), word4.data(), sizeof(u32)); - - return out; -} - -namespace { -u64 MemoryReadImpl(u32 width, VAddr addr) { - switch (width) { - case 1: - return Memory::Read8(addr); - case 2: - return Memory::Read16(addr); - case 4: - return Memory::Read32(addr); - case 8: - return Memory::Read64(addr); - default: - UNREACHABLE(); - return 0; - } -} - -void MemoryWriteImpl(u32 width, VAddr addr, u64 value) { - switch (width) { - case 1: - Memory::Write8(addr, static_cast(value)); - break; - case 2: - Memory::Write16(addr, static_cast(value)); - break; - case 4: - Memory::Write32(addr, static_cast(value)); - break; - case 8: - Memory::Write64(addr, value); - break; - default: - UNREACHABLE(); - } -} -} // Anonymous namespace - -CheatEngine::CheatEngine(Core::System& system, std::vector cheats_, - const std::string& build_id, VAddr code_region_start, - VAddr code_region_end) - : cheats{std::move(cheats_)}, core_timing{system.CoreTiming()} { - event = core_timing.RegisterEvent( - "CheatEngine::FrameCallback::" + build_id, - [this](u64 userdata, s64 cycles_late) { FrameCallback(userdata, cycles_late); }); - core_timing.ScheduleEvent(CHEAT_ENGINE_TICKS, event); - - const auto& vm_manager = system.CurrentProcess()->VMManager(); - for (auto& list : this->cheats) { - list.SetMemoryParameters(code_region_start, vm_manager.GetHeapRegionBaseAddress(), - code_region_end, vm_manager.GetHeapRegionEndAddress(), - &MemoryWriteImpl, &MemoryReadImpl); - } -} - -CheatEngine::~CheatEngine() { - core_timing.UnscheduleEvent(event, 0); -} - -void CheatEngine::FrameCallback(u64 userdata, s64 cycles_late) { - for (auto& list : cheats) { - list.Execute(); - } - - core_timing.ScheduleEvent(CHEAT_ENGINE_TICKS - cycles_late, event); -} - -} // namespace FileSys diff --git a/src/core/file_sys/cheat_engine.h b/src/core/file_sys/cheat_engine.h deleted file mode 100644 index ac22a82cb..000000000 --- a/src/core/file_sys/cheat_engine.h +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include -#include "common/bit_field.h" -#include "common/common_types.h" - -namespace Core { -class System; -} - -namespace Core::Timing { -class CoreTiming; -struct EventType; -} // namespace Core::Timing - -namespace FileSys { - -enum class CodeType : u32 { - // 0TMR00AA AAAAAAAA YYYYYYYY YYYYYYYY - // Writes a T sized value Y to the address A added to the value of register R in memory domain M - WriteImmediate = 0, - - // 1TMC00AA AAAAAAAA YYYYYYYY YYYYYYYY - // Compares the T sized value Y to the value at address A in memory domain M using the - // conditional function C. If success, continues execution. If failure, jumps to the matching - // EndConditional statement. - Conditional = 1, - - // 20000000 - // Terminates a Conditional or ConditionalInput block. - EndConditional = 2, - - // 300R0000 VVVVVVVV - // Starts looping V times, storing the current count in register R. - // Loop block is terminated with a matching 310R0000. - Loop = 3, - - // 400R0000 VVVVVVVV VVVVVVVV - // Sets the value of register R to the value V. - LoadImmediate = 4, - - // 5TMRI0AA AAAAAAAA - // Sets the value of register R to the value of width T at address A in memory domain M, with - // the current value of R added to the address if I == 1. - LoadIndexed = 5, - - // 6T0RIFG0 VVVVVVVV VVVVVVVV - // Writes the value V of width T to the memory address stored in register R. Adds the value of - // register G to the final calculation if F is nonzero. Increments the value of register R by T - // after operation if I is nonzero. - StoreIndexed = 6, - - // 7T0RA000 VVVVVVVV - // Performs the arithmetic operation A on the value in register R and the value V of width T, - // storing the result in register R. - RegisterArithmetic = 7, - - // 8KKKKKKK - // Checks to see if any of the buttons defined by the bitmask K are pressed. If any are, - // execution continues. If none are, execution skips to the next EndConditional command. - ConditionalInput = 8, -}; - -enum class MemoryType : u32 { - // Addressed relative to start of main NSO - MainNSO = 0, - - // Addressed relative to start of heap - Heap = 1, -}; - -enum class ArithmeticOp : u32 { - Add = 0, - Sub = 1, - Mult = 2, - LShift = 3, - RShift = 4, -}; - -enum class ComparisonOp : u32 { - GreaterThan = 1, - GreaterThanEqual = 2, - LessThan = 3, - LessThanEqual = 4, - Equal = 5, - Inequal = 6, -}; - -union Cheat { - std::array raw; - - BitField<4, 4, CodeType> type; - BitField<0, 4, u32> width; // Can be 1, 2, 4, or 8. Measured in bytes. - BitField<0, 4, u32> end_of_loop; - BitField<12, 4, MemoryType> memory_type; - BitField<8, 4, u32> register_3; - BitField<8, 4, ComparisonOp> comparison_op; - BitField<20, 4, u32> load_from_register; - BitField<20, 4, u32> increment_register; - BitField<20, 4, ArithmeticOp> arithmetic_op; - BitField<16, 4, u32> add_additional_register; - BitField<28, 4, u32> register_6; - - u64 Address() const; - u64 ValueWidth(u64 offset) const; - u64 Value(u64 offset, u64 width) const; - u32 KeypadValue() const; -}; - -class CheatParser; - -// Represents a full collection of cheats for a game. The Execute function should be called every -// interval that all cheats should be executed. Clients should not directly instantiate this class -// (hence private constructor), they should instead receive an instance from CheatParser, which -// guarantees the list is always in an acceptable state. -class CheatList { -public: - friend class CheatParser; - - using Block = std::vector; - using ProgramSegment = std::vector>; - - // (width in bytes, address, value) - using MemoryWriter = void (*)(u32, VAddr, u64); - // (width in bytes, address) -> value - using MemoryReader = u64 (*)(u32, VAddr); - - void SetMemoryParameters(VAddr main_begin, VAddr heap_begin, VAddr main_end, VAddr heap_end, - MemoryWriter writer, MemoryReader reader); - - void Execute(); - -private: - CheatList(const Core::System& system_, ProgramSegment master, ProgramSegment standard); - - void ProcessBlockPairs(const Block& block); - void ExecuteSingleCheat(const Cheat& cheat); - - void ExecuteBlock(const Block& block); - - bool EvaluateConditional(const Cheat& cheat) const; - - // Individual cheat operations - void WriteImmediate(const Cheat& cheat); - void BeginConditional(const Cheat& cheat); - void EndConditional(const Cheat& cheat); - void Loop(const Cheat& cheat); - void LoadImmediate(const Cheat& cheat); - void LoadIndexed(const Cheat& cheat); - void StoreIndexed(const Cheat& cheat); - void RegisterArithmetic(const Cheat& cheat); - void BeginConditionalInput(const Cheat& cheat); - - VAddr SanitizeAddress(VAddr in) const; - - // Master Codes are defined as codes that cannot be disabled and are run prior to all - // others. - ProgramSegment master_list; - // All other codes - ProgramSegment standard_list; - - bool in_standard = false; - - // 16 (0x0-0xF) scratch registers that can be used by cheats - std::array scratch{}; - - MemoryWriter writer = nullptr; - MemoryReader reader = nullptr; - - u64 main_region_begin{}; - u64 heap_region_begin{}; - u64 main_region_end{}; - u64 heap_region_end{}; - - u64 current_block{}; - // The current index of the cheat within the current Block - u64 current_index{}; - - // The 'stack' of the program. When a conditional or loop statement is encountered, its index is - // pushed onto this queue. When a end block is encountered, the condition is checked. - std::map block_pairs; - - std::set encountered_loops; - - const Core::System* system; -}; - -// Intermediary class that parses a text file or other disk format for storing cheats into a -// CheatList object, that can be used for execution. -class CheatParser { -public: - virtual ~CheatParser(); - - virtual CheatList Parse(const Core::System& system, const std::vector& data) const = 0; - -protected: - CheatList MakeCheatList(const Core::System& system_, CheatList::ProgramSegment master, - CheatList::ProgramSegment standard) const; -}; - -// CheatParser implementation that parses text files -class TextCheatParser final : public CheatParser { -public: - ~TextCheatParser() override; - - CheatList Parse(const Core::System& system, const std::vector& data) const override; - -private: - std::array ParseSingleLineCheat(const std::string& line) const; -}; - -// Class that encapsulates a CheatList and manages its interaction with memory and CoreTiming -class CheatEngine final { -public: - CheatEngine(Core::System& system_, std::vector cheats_, const std::string& build_id, - VAddr code_region_start, VAddr code_region_end); - ~CheatEngine(); - -private: - void FrameCallback(u64 userdata, s64 cycles_late); - - std::vector cheats; - - Core::Timing::EventType* event; - Core::Timing::CoreTiming& core_timing; -}; - -} // namespace FileSys -- cgit v1.2.3 From a0055192fed8748e6ef3f001adc36f771909de31 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 30 May 2019 19:35:52 -0400 Subject: patch_manager: Update cheat parsing for new VM --- src/core/file_sys/patch_manager.cpp | 29 +++++++++++++++++------------ src/core/file_sys/patch_manager.h | 6 +++--- 2 files changed, 20 insertions(+), 15 deletions(-) (limited to 'src/core/file_sys') diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index c1dd0c6d7..90b537834 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp @@ -22,6 +22,7 @@ #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/loader.h" #include "core/loader/nso.h" +#include "core/memory/cheat_engine.h" #include "core/settings.h" namespace FileSys { @@ -247,9 +248,10 @@ bool PatchManager::HasNSOPatch(const std::array& build_id_) const { return !CollectPatches(patch_dirs, build_id).empty(); } -static std::optional ReadCheatFileFromFolder(const Core::System& system, u64 title_id, - const std::array& build_id_, - const VirtualDir& base_path, bool upper) { +namespace { +std::optional> ReadCheatFileFromFolder( + const Core::System& system, u64 title_id, const std::array& build_id_, + const VirtualDir& base_path, bool upper) { const auto build_id_raw = Common::HexToString(build_id_, upper); const auto build_id = build_id_raw.substr(0, sizeof(u64) * 2); const auto file = base_path->GetFile(fmt::format("{}.txt", build_id)); @@ -267,12 +269,15 @@ static std::optional ReadCheatFileFromFolder(const Core::System& syst return std::nullopt; } - TextCheatParser parser; - return parser.Parse(system, data); + Memory::TextCheatParser parser; + return parser.Parse( + system, std::string_view(reinterpret_cast(data.data()), data.size())); } -std::vector PatchManager::CreateCheatList(const Core::System& system, - const std::array& build_id_) const { +} // Anonymous namespace + +std::vector PatchManager::CreateCheatList( + const Core::System& system, const std::array& build_id_) const { const auto load_dir = Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id); if (load_dir == nullptr) { @@ -284,20 +289,20 @@ std::vector PatchManager::CreateCheatList(const Core::System& system, std::sort(patch_dirs.begin(), patch_dirs.end(), [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); }); - std::vector out; - out.reserve(patch_dirs.size()); + std::vector out; for (const auto& subdir : patch_dirs) { auto cheats_dir = subdir->GetSubdirectory("cheats"); if (cheats_dir != nullptr) { auto res = ReadCheatFileFromFolder(system, title_id, build_id_, cheats_dir, true); if (res.has_value()) { - out.push_back(std::move(*res)); + std::copy(res->begin(), res->end(), std::back_inserter(out)); continue; } res = ReadCheatFileFromFolder(system, title_id, build_id_, cheats_dir, false); - if (res.has_value()) - out.push_back(std::move(*res)); + if (res.has_value()) { + std::copy(res->begin(), res->end(), std::back_inserter(out)); + } } } diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h index a363c6577..e857e6e82 100644 --- a/src/core/file_sys/patch_manager.h +++ b/src/core/file_sys/patch_manager.h @@ -8,9 +8,9 @@ #include #include #include "common/common_types.h" -#include "core/file_sys/cheat_engine.h" #include "core/file_sys/nca_metadata.h" #include "core/file_sys/vfs.h" +#include "core/memory/dmnt_cheat_types.h" namespace Core { class System; @@ -51,8 +51,8 @@ public: bool HasNSOPatch(const std::array& build_id) const; // Creates a CheatList object with all - std::vector CreateCheatList(const Core::System& system, - const std::array& build_id) const; + std::vector CreateCheatList(const Core::System& system, + const std::array& build_id) const; // Currently tracked RomFS patches: // - Game Updates -- cgit v1.2.3 From 2bddc0346815bf5e893ad9611d89dbb0d511e32f Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sat, 21 Sep 2019 22:43:49 -0400 Subject: dmnt_cheat_vm: Default initialize structure values --- src/core/file_sys/patch_manager.cpp | 3 +- src/core/memory/dmnt_cheat_types.h | 30 ++++---- src/core/memory/dmnt_cheat_vm.h | 144 ++++++++++++++++++------------------ 3 files changed, 88 insertions(+), 89 deletions(-) (limited to 'src/core/file_sys') diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index 90b537834..df0ecb15c 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp @@ -278,8 +278,7 @@ std::optional> ReadCheatFileFromFolder( std::vector PatchManager::CreateCheatList( const Core::System& system, const std::array& build_id_) const { - const auto load_dir = - Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id); + const auto load_dir = system.GetFileSystemController().GetModificationLoadRoot(title_id); if (load_dir == nullptr) { LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id); return {}; diff --git a/src/core/memory/dmnt_cheat_types.h b/src/core/memory/dmnt_cheat_types.h index aa1264c32..bf68fa0fe 100644 --- a/src/core/memory/dmnt_cheat_types.h +++ b/src/core/memory/dmnt_cheat_types.h @@ -29,30 +29,30 @@ namespace Memory { struct MemoryRegionExtents { - u64 base; - u64 size; + u64 base{}; + u64 size{}; }; struct CheatProcessMetadata { - u64 process_id; - u64 title_id; - MemoryRegionExtents main_nso_extents; - MemoryRegionExtents heap_extents; - MemoryRegionExtents alias_extents; - MemoryRegionExtents address_space_extents; - std::array main_nso_build_id; + u64 process_id{}; + u64 title_id{}; + MemoryRegionExtents main_nso_extents{}; + MemoryRegionExtents heap_extents{}; + MemoryRegionExtents alias_extents{}; + MemoryRegionExtents address_space_extents{}; + std::array main_nso_build_id{}; }; struct CheatDefinition { - std::array readable_name; - u32 num_opcodes; - std::array opcodes; + std::array readable_name{}; + u32 num_opcodes{}; + std::array opcodes{}; }; struct CheatEntry { - bool enabled; - u32 cheat_id; - CheatDefinition definition; + bool enabled{}; + u32 cheat_id{}; + CheatDefinition definition{}; }; } // namespace Memory diff --git a/src/core/memory/dmnt_cheat_vm.h b/src/core/memory/dmnt_cheat_vm.h index d1580d7f6..c36212cf1 100644 --- a/src/core/memory/dmnt_cheat_vm.h +++ b/src/core/memory/dmnt_cheat_vm.h @@ -136,131 +136,131 @@ union VmInt { }; struct StoreStaticOpcode { - u32 bit_width; - MemoryAccessType mem_type; - u32 offset_register; - u64 rel_address; - VmInt value; + u32 bit_width{}; + MemoryAccessType mem_type{}; + u32 offset_register{}; + u64 rel_address{}; + VmInt value{}; }; struct BeginConditionalOpcode { - u32 bit_width; - MemoryAccessType mem_type; - ConditionalComparisonType cond_type; - u64 rel_address; - VmInt value; + u32 bit_width{}; + MemoryAccessType mem_type{}; + ConditionalComparisonType cond_type{}; + u64 rel_address{}; + VmInt value{}; }; struct EndConditionalOpcode {}; struct ControlLoopOpcode { - bool start_loop; - u32 reg_index; - u32 num_iters; + bool start_loop{}; + u32 reg_index{}; + u32 num_iters{}; }; struct LoadRegisterStaticOpcode { - u32 reg_index; - u64 value; + u32 reg_index{}; + u64 value{}; }; struct LoadRegisterMemoryOpcode { - u32 bit_width; - MemoryAccessType mem_type; - u32 reg_index; - bool load_from_reg; - u64 rel_address; + u32 bit_width{}; + MemoryAccessType mem_type{}; + u32 reg_index{}; + bool load_from_reg{}; + u64 rel_address{}; }; struct StoreStaticToAddressOpcode { - u32 bit_width; - u32 reg_index; - bool increment_reg; - bool add_offset_reg; - u32 offset_reg_index; - u64 value; + u32 bit_width{}; + u32 reg_index{}; + bool increment_reg{}; + bool add_offset_reg{}; + u32 offset_reg_index{}; + u64 value{}; }; struct PerformArithmeticStaticOpcode { - u32 bit_width; - u32 reg_index; - RegisterArithmeticType math_type; - u32 value; + u32 bit_width{}; + u32 reg_index{}; + RegisterArithmeticType math_type{}; + u32 value{}; }; struct BeginKeypressConditionalOpcode { - u32 key_mask; + u32 key_mask{}; }; struct PerformArithmeticRegisterOpcode { - u32 bit_width; - RegisterArithmeticType math_type; - u32 dst_reg_index; - u32 src_reg_1_index; - u32 src_reg_2_index; - bool has_immediate; - VmInt value; + u32 bit_width{}; + RegisterArithmeticType math_type{}; + u32 dst_reg_index{}; + u32 src_reg_1_index{}; + u32 src_reg_2_index{}; + bool has_immediate{}; + VmInt value{}; }; struct StoreRegisterToAddressOpcode { - u32 bit_width; - u32 str_reg_index; - u32 addr_reg_index; - bool increment_reg; - StoreRegisterOffsetType ofs_type; - MemoryAccessType mem_type; - u32 ofs_reg_index; - u64 rel_address; + u32 bit_width{}; + u32 str_reg_index{}; + u32 addr_reg_index{}; + bool increment_reg{}; + StoreRegisterOffsetType ofs_type{}; + MemoryAccessType mem_type{}; + u32 ofs_reg_index{}; + u64 rel_address{}; }; struct BeginRegisterConditionalOpcode { - u32 bit_width; - ConditionalComparisonType cond_type; - u32 val_reg_index; - CompareRegisterValueType comp_type; - MemoryAccessType mem_type; - u32 addr_reg_index; - u32 other_reg_index; - u32 ofs_reg_index; - u64 rel_address; - VmInt value; + u32 bit_width{}; + ConditionalComparisonType cond_type{}; + u32 val_reg_index{}; + CompareRegisterValueType comp_type{}; + MemoryAccessType mem_type{}; + u32 addr_reg_index{}; + u32 other_reg_index{}; + u32 ofs_reg_index{}; + u64 rel_address{}; + VmInt value{}; }; struct SaveRestoreRegisterOpcode { - u32 dst_index; - u32 src_index; - SaveRestoreRegisterOpType op_type; + u32 dst_index{}; + u32 src_index{}; + SaveRestoreRegisterOpType op_type{}; }; struct SaveRestoreRegisterMaskOpcode { - SaveRestoreRegisterOpType op_type; - std::array should_operate; + SaveRestoreRegisterOpType op_type{}; + std::array should_operate{}; }; struct DebugLogOpcode { - u32 bit_width; - u32 log_id; - DebugLogValueType val_type; - MemoryAccessType mem_type; - u32 addr_reg_index; - u32 val_reg_index; - u32 ofs_reg_index; - u64 rel_address; + u32 bit_width{}; + u32 log_id{}; + DebugLogValueType val_type{}; + MemoryAccessType mem_type{}; + u32 addr_reg_index{}; + u32 val_reg_index{}; + u32 ofs_reg_index{}; + u64 rel_address{}; }; struct UnrecognizedInstruction { - CheatVmOpcodeType opcode; + CheatVmOpcodeType opcode{}; }; struct CheatVmOpcode { - bool begin_conditional_block; + bool begin_conditional_block{}; std::variant - opcode; + opcode{}; }; class DmntCheatVm { -- cgit v1.2.3