diff --git a/Source/.clang-format b/Source/.clang-format index a914852..b4ec493 100755 --- a/Source/.clang-format +++ b/Source/.clang-format @@ -1,17 +1,84 @@ ---- -AlignAfterOpenBracket: 'true' -AllowAllParametersOfDeclarationOnNextLine: 'true' -AllowShortFunctionsOnASingleLine: None -AlwaysBreakBeforeMultilineStrings: 'true' -AlwaysBreakTemplateDeclarations: 'true' -BreakBeforeBraces: Allman -BreakStringLiterals: 'true' -FixNamespaceComments: 'true' -ColumnLimit: '100' -Cpp11BracedListStyle: 'true' -Language: Cpp +--- +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: false +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: InlineOnly +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: true +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: false +BreakConstructorInitializersBeforeComma: false +ColumnLimit: 100 +CommentPragmas: '^ (IWYU pragma:|NOLINT)' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ForEachMacros: [] +IncludeCategories: + - Regex: '^<[Ww]indows\.h>$' + Priority: 1 + - Regex: '^<' + Priority: 2 + - Regex: '^"' + Priority: 3 +IndentCaseLabels: false +IndentWidth: 2 +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 PointerAlignment: Left -Standard: Cpp11 -UseTab: Never +ReflowComments: true +SortIncludes: true +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Latest +TabWidth: 2 +UseTab: Never ... diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index efbc79b..d200d48 100755 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -1,22 +1,30 @@ -cmake_minimum_required(VERSION 3.5.0) -project(Dolphin-memory-engine CXX) - -if(WIN32) - set(DolphinProcessSrc DolphinProcess/Windows/WindowsDolphinProcess.cpp) -elseif(UNIX) - set(DolphinProcessSrc DolphinProcess/Linux/LinuxDolphinProcess.cpp) -else() - set(DolphinProcessSrc DolphinProcess/Dummy/DummyDolphinProcess.cpp) -endif() - -set(SRCS ${DolphinProcessSrc} - DolphinProcess/DolphinAccessor.cpp - Common/MemoryCommon.cpp - MemoryWatch/MemWatchEntry.cpp - ) - -set(CMAKE_INCLUE_CURRENT_DIR ON) -set(CMAKE_CXX_STANDARD_REQUIRED YES) -set(CMAKE_CXX_STANDARD 14) - -add_library(dolphin-memory-engine ${SRCS}) +cmake_minimum_required(VERSION 3.13) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(GCC_min_version 10) +project(dolphin-memory-engine) + +if(WIN32) + set(DolphinProcessSrc DolphinProcess/Windows/WindowsDolphinProcess.cpp) +endif(WIN32) + +if(UNIX AND NOT APPLE) + set(DolphinProcessSrc DolphinProcess/Linux/LinuxDolphinProcess.cpp) +endif(UNIX AND NOT APPLE) + +if(APPLE) + set(DolphinProcessSrc DolphinProcess/Mac/MacDolphinProcess.cpp) +endif(APPLE) + +set(SRCS ${DolphinProcessSrc} + DolphinProcess/DolphinAccessor.cpp + Common/MemoryCommon.cpp + MemoryWatch/MemWatchEntry.cpp + MemoryScanner/MemoryScanner.cpp) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +add_library(dolphin-memory-engine ${SRCS}) diff --git a/Source/Common/CommonUtils.h b/Source/Common/CommonUtils.h old mode 100755 new mode 100644 index 97eb1b1..36802cf --- a/Source/Common/CommonUtils.h +++ b/Source/Common/CommonUtils.h @@ -4,8 +4,16 @@ #include #elif _WIN32 #include -#elif defined(__APPLE__) -#include +#elif __APPLE__ +#define bswap_16(value) ((((value)&0xff) << 8) | ((value) >> 8)) + +#define bswap_32(value) \ + (((uint32_t)bswap_16((uint16_t)((value)&0xffff)) << 16) | \ + (uint32_t)bswap_16((uint16_t)((value) >> 16))) + +#define bswap_64(value) \ + (((uint64_t)bswap_32((uint32_t)((value)&0xffffffff)) << 32) | \ + (uint64_t)bswap_32((uint32_t)((value) >> 32))) #endif #include "CommonTypes.h" @@ -27,7 +35,7 @@ inline u64 bSwap64(u64 data) return _byteswap_uint64(data); } -#elif __linux__ +#else inline u16 bSwap16(u16 data) { return bswap_16(data); @@ -40,21 +48,21 @@ inline u64 bSwap64(u64 data) { return bswap_64(data); } -#elif defined(__APPLE__) -inline u16 bSwap16(u16 data) -{ - return OSSwapInt16(data); -} -inline u32 bSwap32(u32 data) -{ - return OSSwapInt32(data); -} -inline u64 bSwap64(u64 data) -{ - return OSSwapInt64(data); -} #endif +constexpr u32 NextPowerOf2(u32 value) +{ + --value; + value |= value >> 1; + value |= value >> 2; + value |= value >> 4; + value |= value >> 8; + value |= value >> 16; + ++value; + + return value; +}; + inline u32 dolphinAddrToOffset(u32 addr, bool considerAram) { // ARAM address @@ -63,14 +71,14 @@ inline u32 dolphinAddrToOffset(u32 addr, bool considerAram) addr -= ARAM_START; } // MEM1 address - else if (addr >= MEM1_START && addr < MEM1_END) + else if (addr >= MEM1_START && addr < GetMEM1End()) { addr -= MEM1_START; if (considerAram) addr += ARAM_FAKESIZE; } // MEM2 address - else if (addr >= MEM2_START && addr < MEM2_END) + else if (addr >= MEM2_START && addr < GetMEM2End()) { addr -= MEM2_START; addr += (MEM2_START - MEM1_START); @@ -86,7 +94,7 @@ inline u32 offsetToDolphinAddr(u32 offset, bool considerAram) { offset += ARAM_START; } - else if (offset >= ARAM_FAKESIZE && offset < ARAM_FAKESIZE + MEM1_SIZE) + else if (offset >= ARAM_FAKESIZE && offset < ARAM_FAKESIZE + GetMEM1SizeReal()) { offset += MEM1_START; offset -= ARAM_FAKESIZE; @@ -94,11 +102,12 @@ inline u32 offsetToDolphinAddr(u32 offset, bool considerAram) } else { - if (offset < MEM1_SIZE) + if (offset < GetMEM1SizeReal()) { offset += MEM1_START; } - else if (offset >= MEM2_START - MEM1_START && offset < MEM2_START - MEM1_START + MEM2_SIZE) + else if (offset >= MEM2_START - MEM1_START && + offset < MEM2_START - MEM1_START + GetMEM2SizeReal()) { offset += MEM2_START; offset -= (MEM2_START - MEM1_START); @@ -111,16 +120,16 @@ inline u32 offsetToCacheIndex(u32 offset, bool considerAram) { if (considerAram) { - if (offset >= ARAM_FAKESIZE && offset < MEM1_SIZE + ARAM_FAKESIZE) + if (offset >= ARAM_FAKESIZE && offset < GetMEM1SizeReal() + ARAM_FAKESIZE) { offset -= (ARAM_FAKESIZE - ARAM_SIZE); } } else { - if (offset >= MEM2_START - MEM1_START && offset < MEM2_START - MEM1_START + MEM2_SIZE) + if (offset >= MEM2_START - MEM1_START && offset < MEM2_START - MEM1_START + GetMEM2SizeReal()) { - offset -= (MEM2_START - MEM1_END); + offset -= (MEM2_START - GetMEM1End()); } } return offset; @@ -130,18 +139,18 @@ inline u32 cacheIndexToOffset(u32 cacheIndex, bool considerAram) { if (considerAram) { - if (cacheIndex >= ARAM_SIZE && cacheIndex < MEM1_SIZE + ARAM_SIZE) + if (cacheIndex >= ARAM_SIZE && cacheIndex < GetMEM1SizeReal() + ARAM_SIZE) { cacheIndex += (ARAM_FAKESIZE - ARAM_SIZE); } } else { - if (cacheIndex >= MEM1_SIZE && cacheIndex < MEM1_SIZE + MEM2_SIZE) + if (cacheIndex >= GetMEM1SizeReal() && cacheIndex < GetMEM1SizeReal() + GetMEM2SizeReal()) { - cacheIndex += (MEM2_START - MEM1_END); + cacheIndex += (MEM2_START - GetMEM1End()); } } return cacheIndex; } -} // namespace Common +} // namespace Common diff --git a/Source/Common/MemoryCommon.cpp b/Source/Common/MemoryCommon.cpp index 987fe81..5fd1be0 100644 --- a/Source/Common/MemoryCommon.cpp +++ b/Source/Common/MemoryCommon.cpp @@ -11,6 +11,48 @@ namespace Common { +static u32 s_mem1_size_real; +static u32 s_mem2_size_real; +static u32 s_mem1_size; +static u32 s_mem2_size; +static u32 s_mem1_end; +static u32 s_mem2_end; + +u32 GetMEM1SizeReal() +{ + return s_mem1_size_real; +} +u32 GetMEM2SizeReal() +{ + return s_mem2_size_real; +} +u32 GetMEM1Size() +{ + return s_mem1_size; +} +u32 GetMEM2Size() +{ + return s_mem2_size; +} +u32 GetMEM1End() +{ + return s_mem1_end; +} +u32 GetMEM2End() +{ + return s_mem2_end; +} + +void UpdateMemoryValues() +{ + s_mem1_size_real = 24u * 1024 * 1024; + s_mem2_size_real = 64u * 1024 * 1024; + s_mem1_size = NextPowerOf2(GetMEM1SizeReal()); + s_mem2_size = NextPowerOf2(GetMEM2SizeReal()); + s_mem1_end = MEM1_START + GetMEM1SizeReal(); + s_mem2_end = MEM2_START + GetMEM2SizeReal(); +} + size_t getSizeForType(const MemType type, const size_t length) { switch (type) @@ -57,7 +99,7 @@ bool shouldBeBSwappedForType(const MemType type) } } -int getNbrBytesAlignementForType(const MemType type) +int getNbrBytesAlignmentForType(const MemType type) { switch (type) { @@ -505,4 +547,4 @@ std::string formatMemoryToString(const char* memory, const MemType type, const s break; } } -} // namespace Common +} // namespace Common diff --git a/Source/Common/MemoryCommon.h b/Source/Common/MemoryCommon.h index 6047d17..0d0bd38 100644 --- a/Source/Common/MemoryCommon.h +++ b/Source/Common/MemoryCommon.h @@ -7,20 +7,22 @@ namespace Common { -const u32 MEM1_SIZE = 0x1800000; -const u32 MEM1_START = 0x80000000; -const u32 MEM1_END = 0x81800000; - -const u32 ARAM_SIZE = 0x1000000; +u32 GetMEM1SizeReal(); +u32 GetMEM2SizeReal(); +u32 GetMEM1Size(); +u32 GetMEM2Size(); +u32 GetMEM1End(); +u32 GetMEM2End(); +constexpr u32 MEM1_START = 0x80000000; +constexpr u32 MEM2_START = 0x90000000; +constexpr u32 ARAM_SIZE = 0x1000000; // Dolphin maps 32 mb for the fakeVMem which is what ends up being the speedhack, but in reality // the ARAM is actually 16 mb. We need the fake size to do process address calculation -const u32 ARAM_FAKESIZE = 0x2000000; -const u32 ARAM_START = 0x7E000000; -const u32 ARAM_END = 0x7F000000; +constexpr u32 ARAM_FAKESIZE = 0x2000000; +constexpr u32 ARAM_START = 0x7E000000; +constexpr u32 ARAM_END = 0x7F000000; -const u32 MEM2_SIZE = 0x4000000; -const u32 MEM2_START = 0x90000000; -const u32 MEM2_END = 0x94000000; +void UpdateMemoryValues(); enum class MemType { @@ -40,7 +42,7 @@ enum class MemBase base_hexadecimal, base_octal, base_binary, - base_none // Placeholder when the base doesn't matter (ie. string) + base_none // Placeholder when the base doesn't matter (ie. string) }; enum class MemOperationReturnCode @@ -54,11 +56,11 @@ enum class MemOperationReturnCode size_t getSizeForType(const MemType type, const size_t length); bool shouldBeBSwappedForType(const MemType type); -int getNbrBytesAlignementForType(const MemType type); +int getNbrBytesAlignmentForType(const MemType type); char* formatStringToMemory(MemOperationReturnCode& returnCode, size_t& actualLength, const std::string inputString, const MemBase base, const MemType type, const size_t length); std::string formatMemoryToString(const char* memory, const MemType type, const size_t length, const MemBase base, const bool isUnsigned, const bool withBSwap = false); -} // namespace Common +} // namespace Common diff --git a/Source/DolphinProcess/DolphinAccessor.cpp b/Source/DolphinProcess/DolphinAccessor.cpp index 92b55f4..4438913 100644 --- a/Source/DolphinProcess/DolphinAccessor.cpp +++ b/Source/DolphinProcess/DolphinAccessor.cpp @@ -1,11 +1,14 @@ #include "DolphinAccessor.h" -#ifdef linux +#ifdef __linux__ #include "Linux/LinuxDolphinProcess.h" #elif _WIN32 #include "Windows/WindowsDolphinProcess.h" +#elif __APPLE__ +#include "Mac/MacDolphinProcess.h" #endif #include +#include #include "../Common/CommonUtils.h" #include "../Common/MemoryCommon.h" @@ -13,17 +16,19 @@ namespace DolphinComm { IDolphinProcess* DolphinAccessor::m_instance = nullptr; -DolphinStatus DolphinAccessor::m_status = DolphinStatus::unHooked; -char* DolphinAccessor::m_updatedRAMCache = nullptr; +DolphinAccessor::DolphinStatus DolphinAccessor::m_status = DolphinStatus::unHooked; void DolphinAccessor::init() { + Common::UpdateMemoryValues(); if (m_instance == nullptr) { #ifdef __linux__ m_instance = new LinuxDolphinProcess(); #elif _WIN32 m_instance = new WindowsDolphinProcess(); +#elif __APPLE__ + m_instance = new MacDolphinProcess(); #endif } } @@ -31,13 +36,11 @@ void DolphinAccessor::init() void DolphinAccessor::free() { delete m_instance; - delete[] m_updatedRAMCache; } void DolphinAccessor::hook() { init(); - if (m_instance == nullptr) { return; } if (!m_instance->findPID()) { m_status = DolphinStatus::notRunning; @@ -49,7 +52,6 @@ void DolphinAccessor::hook() else { m_status = DolphinStatus::hooked; - updateRAMCache(); } } @@ -60,7 +62,7 @@ void DolphinAccessor::unHook() m_status = DolphinStatus::unHooked; } -DolphinStatus DolphinAccessor::getStatus() +DolphinAccessor::DolphinStatus DolphinAccessor::getStatus() { return m_status; } @@ -68,38 +70,38 @@ DolphinStatus DolphinAccessor::getStatus() bool DolphinAccessor::readFromRAM(const u32 offset, char* buffer, const size_t size, const bool withBSwap) { - return m_instance->readFromRAM(offset, buffer, size, withBSwap); + return m_instance ? m_instance->readFromRAM(offset, buffer, size, withBSwap) : false; } bool DolphinAccessor::writeToRAM(const u32 offset, const char* buffer, const size_t size, const bool withBSwap) { - return m_instance->writeToRAM(offset, buffer, size, withBSwap); + return m_instance ? m_instance->writeToRAM(offset, buffer, size, withBSwap) : false; } int DolphinAccessor::getPID() { - return m_instance->getPID(); + return m_instance ? m_instance->getPID() : -1; } u64 DolphinAccessor::getEmuRAMAddressStart() { - return m_instance->getEmuRAMAddressStart(); + return m_instance ? m_instance->getEmuRAMAddressStart() : 0; } bool DolphinAccessor::isARAMAccessible() { - return m_instance->isARAMAccessible(); + return m_instance ? m_instance->isARAMAccessible() : false; } u64 DolphinAccessor::getARAMAddressStart() { - return m_instance->getARAMAddressStart(); + return m_instance ? m_instance->getARAMAddressStart() : 0; } bool DolphinAccessor::isMEM2Present() { - return m_instance->isMEM2Present(); + return m_instance ? m_instance->isMEM2Present() : false; } bool DolphinAccessor::isValidConsoleAddress(const u32 address) @@ -107,105 +109,83 @@ bool DolphinAccessor::isValidConsoleAddress(const u32 address) if (getStatus() != DolphinStatus::hooked) return false; - if (address >= Common::MEM1_START && address < Common::MEM1_END) + if (address >= Common::MEM1_START && address < Common::GetMEM1End()) return true; - if (isMEM2Present() && (address >= Common::MEM2_START && address < Common::MEM2_END)) + if (isMEM2Present() && (address >= Common::MEM2_START && address < Common::GetMEM2End())) return true; - if (isARAMAccessible && (address >= Common::ARAM_START && address < Common::ARAM_END)) + if (isARAMAccessible() && (address >= Common::ARAM_START && address < Common::ARAM_END)) return true; return false; } -char* DolphinAccessor::getRAMCache() -{ - return m_updatedRAMCache; -} - -size_t DolphinAccessor::getRAMCacheSize() +size_t DolphinAccessor::getRAMTotalSize() { if (isMEM2Present()) { - return Common::MEM1_SIZE + Common::MEM2_SIZE; + return Common::GetMEM1SizeReal() + Common::GetMEM2SizeReal(); } else if (isARAMAccessible()) { - return Common::MEM1_SIZE + Common::ARAM_SIZE; + return Common::GetMEM1SizeReal() + Common::ARAM_SIZE; } else { - return Common::MEM1_SIZE; + return Common::GetMEM1SizeReal(); } } -Common::MemOperationReturnCode DolphinAccessor::updateRAMCache() +Common::MemOperationReturnCode DolphinAccessor::readEntireRAM(char* buffer) { - delete[] m_updatedRAMCache; - m_updatedRAMCache = nullptr; - - // MEM2, if enabled, is read right after MEM1 in the cache so both regions are contigous + // MEM2, if enabled, is read right after MEM1 in the buffer so both regions are contigous if (isMEM2Present()) { - m_updatedRAMCache = new char[Common::MEM1_SIZE + Common::MEM2_SIZE]; - if (!DolphinComm::DolphinAccessor::readFromRAM( - Common::dolphinAddrToOffset(Common::MEM1_START, false), m_updatedRAMCache, - Common::MEM1_SIZE, false)) + Common::dolphinAddrToOffset(Common::MEM1_START, false), buffer, + Common::GetMEM1SizeReal(), false)) return Common::MemOperationReturnCode::operationFailed; // Read Wii extra RAM if (!DolphinComm::DolphinAccessor::readFromRAM( Common::dolphinAddrToOffset(Common::MEM2_START, false), - m_updatedRAMCache + Common::MEM1_SIZE, Common::MEM2_SIZE, false)) + buffer + Common::GetMEM1SizeReal(), Common::GetMEM2SizeReal(), false)) return Common::MemOperationReturnCode::operationFailed; } else if (isARAMAccessible()) { - m_updatedRAMCache = new char[Common::ARAM_SIZE + Common::MEM1_SIZE]; // read ARAM if (!DolphinComm::DolphinAccessor::readFromRAM( - Common::dolphinAddrToOffset(Common::ARAM_START, true), m_updatedRAMCache, - Common::ARAM_SIZE, false)) + Common::dolphinAddrToOffset(Common::ARAM_START, true), buffer, Common::ARAM_SIZE, + false)) return Common::MemOperationReturnCode::operationFailed; // Read GameCube and Wii basic RAM if (!DolphinComm::DolphinAccessor::readFromRAM( - Common::dolphinAddrToOffset(Common::MEM1_START, true), - m_updatedRAMCache + Common::ARAM_SIZE, Common::MEM1_SIZE, false)) + Common::dolphinAddrToOffset(Common::MEM1_START, true), buffer + Common::ARAM_SIZE, + Common::GetMEM1SizeReal(), false)) return Common::MemOperationReturnCode::operationFailed; } else { - m_updatedRAMCache = new char[Common::MEM1_SIZE]; if (!DolphinComm::DolphinAccessor::readFromRAM( - Common::dolphinAddrToOffset(Common::MEM1_START, false), m_updatedRAMCache, - Common::MEM1_SIZE, false)) + Common::dolphinAddrToOffset(Common::MEM1_START, false), buffer, + Common::GetMEM1SizeReal(), false)) return Common::MemOperationReturnCode::operationFailed; } return Common::MemOperationReturnCode::OK; } -std::string DolphinAccessor::getFormattedValueFromCache(const u32 ramIndex, Common::MemType memType, - size_t memSize, Common::MemBase memBase, - bool memIsUnsigned) +std::string DolphinAccessor::getFormattedValueFromMemory(const u32 ramIndex, + Common::MemType memType, size_t memSize, + Common::MemBase memBase, + bool memIsUnsigned) { - return Common::formatMemoryToString(&m_updatedRAMCache[ramIndex], memType, memSize, memBase, - memIsUnsigned, Common::shouldBeBSwappedForType(memType)); -} - -void DolphinAccessor::copyRawMemoryFromCache(char* dest, const u32 consoleAddress, - const size_t byteCount) -{ - if (isValidConsoleAddress(consoleAddress) && - isValidConsoleAddress((consoleAddress + static_cast(byteCount)) - 1)) - { - bool aramAccessible = isARAMAccessible(); - u32 offset = Common::dolphinAddrToOffset(consoleAddress, isARAMAccessible()); - u32 cacheIndex = Common::offsetToCacheIndex(offset, aramAccessible); - std::memcpy(dest, m_updatedRAMCache + cacheIndex, byteCount); - } + std::unique_ptr buffer(new char[memSize]); + readFromRAM(ramIndex, buffer.get(), memSize, false); + return Common::formatMemoryToString(buffer.get(), memType, memSize, memBase, memIsUnsigned, + Common::shouldBeBSwappedForType(memType)); } -} // namespace DolphinComm +} // namespace DolphinComm diff --git a/Source/DolphinProcess/DolphinAccessor.h b/Source/DolphinProcess/DolphinAccessor.h index a027973..e3159e8 100644 --- a/Source/DolphinProcess/DolphinAccessor.h +++ b/Source/DolphinProcess/DolphinAccessor.h @@ -7,17 +7,17 @@ namespace DolphinComm { -enum class DolphinStatus -{ - hooked, - notRunning, - noEmu, - unHooked -}; - class DolphinAccessor { public: + enum class DolphinStatus + { + hooked, + notRunning, + noEmu, + unHooked + }; + static void init(); static void free(); static void hook(); @@ -31,18 +31,15 @@ class DolphinAccessor static bool isARAMAccessible(); static u64 getARAMAddressStart(); static bool isMEM2Present(); - static char* getRAMCache(); - static size_t getRAMCacheSize(); - static Common::MemOperationReturnCode updateRAMCache(); - static std::string getFormattedValueFromCache(const u32 ramIndex, Common::MemType memType, - size_t memSize, Common::MemBase memBase, - bool memIsUnsigned); - static void copyRawMemoryFromCache(char* dest, const u32 consoleAddress, const size_t byteCount); + static size_t getRAMTotalSize(); + static Common::MemOperationReturnCode readEntireRAM(char* buffer); + static std::string getFormattedValueFromMemory(const u32 ramIndex, Common::MemType memType, + size_t memSize, Common::MemBase memBase, + bool memIsUnsigned); static bool isValidConsoleAddress(const u32 address); private: static IDolphinProcess* m_instance; static DolphinStatus m_status; - static char* m_updatedRAMCache; }; -} // namespace DolphinComm +} // namespace DolphinComm diff --git a/Source/DolphinProcess/Dummy/DummyDolphinProcess.cpp b/Source/DolphinProcess/Dummy/DummyDolphinProcess.cpp deleted file mode 100644 index eb79259..0000000 --- a/Source/DolphinProcess/Dummy/DummyDolphinProcess.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "DummyDolphinProcess.h" -#include "../../Common/CommonUtils.h" - -namespace DolphinComm -{ -bool DummyDolphinProcess::obtainEmuRAMInformations() -{ - return false; -} - -bool DummyDolphinProcess::findPID() -{ - return false; -} - -bool DummyDolphinProcess::readFromRAM(const u32 offset, char* buffer, const size_t size, - const bool withBSwap) -{ - return false; -} - -bool DummyDolphinProcess::writeToRAM(const u32 offset, const char* buffer, const size_t size, - const bool withBSwap) -{ - return false; -} -} // namespace DolphinComm diff --git a/Source/DolphinProcess/IDolphinProcess.h b/Source/DolphinProcess/IDolphinProcess.h index 6c2d9ba..2609c02 100644 --- a/Source/DolphinProcess/IDolphinProcess.h +++ b/Source/DolphinProcess/IDolphinProcess.h @@ -10,9 +10,7 @@ namespace DolphinComm class IDolphinProcess { public: - virtual ~IDolphinProcess() - { - } + virtual ~IDolphinProcess() {} virtual bool findPID() = 0; virtual bool obtainEmuRAMInformations() = 0; virtual bool readFromRAM(const u32 offset, char* buffer, const size_t size, @@ -20,31 +18,13 @@ class IDolphinProcess virtual bool writeToRAM(const u32 offset, const char* buffer, const size_t size, const bool withBSwap) = 0; - int getPID() const - { - return m_PID; - }; - u64 getEmuRAMAddressStart() const - { - return m_emuRAMAddressStart; - }; - bool isMEM2Present() const - { - return m_MEM2Present; - }; - bool isARAMAccessible() const - { - return m_ARAMAccessible; - }; - u64 getARAMAddressStart() const - { - return m_emuARAMAdressStart; - }; - u64 getMEM2AddressStart() const - { - return m_MEM2AddressStart; - }; - u32 getMEM1ToMEM2Distance() const + int getPID() const { return m_PID; }; + u64 getEmuRAMAddressStart() const { return m_emuRAMAddressStart; }; + bool isMEM2Present() const { return m_MEM2Present; }; + bool isARAMAccessible() const { return m_ARAMAccessible; }; + u64 getARAMAddressStart() const { return m_emuARAMAdressStart; }; + u64 getMEM2AddressStart() const { return m_MEM2AddressStart; }; + u64 getMEM1ToMEM2Distance() const { if (!m_MEM2Present) return 0; @@ -59,4 +39,4 @@ class IDolphinProcess bool m_ARAMAccessible = false; bool m_MEM2Present = false; }; -} // namespace DolphinComm +} // namespace DolphinComm diff --git a/Source/DolphinProcess/Linux/LinuxDolphinProcess.cpp b/Source/DolphinProcess/Linux/LinuxDolphinProcess.cpp index ce75940..bae5a6d 100644 --- a/Source/DolphinProcess/Linux/LinuxDolphinProcess.cpp +++ b/Source/DolphinProcess/Linux/LinuxDolphinProcess.cpp @@ -2,14 +2,15 @@ #include "LinuxDolphinProcess.h" #include "../../Common/CommonUtils.h" +#include "../../Common/MemoryCommon.h" +#include #include #include #include #include #include #include - #include #include @@ -50,7 +51,7 @@ bool LinuxDolphinProcess::obtainEmuRAMInformations() u32 offset = 0; std::string offsetStr("0x" + lineData[2]); offset = std::stoul(offsetStr, nullptr, 16); - if (offset != 0 && offset != 0x2040000) + if (offset != 0 && offset != Common::GetMEM1Size() + 0x40000) continue; u64 firstAddress = 0; @@ -62,7 +63,8 @@ bool LinuxDolphinProcess::obtainEmuRAMInformations() firstAddress = std::stoul(firstAddressStr, nullptr, 16); SecondAddress = std::stoul(secondAddressStr, nullptr, 16); - if (SecondAddress - firstAddress == 0x4000000 && offset == 0x2040000) + if (SecondAddress - firstAddress == Common::GetMEM2Size() && + offset == Common::GetMEM1Size() + 0x40000) { m_MEM2AddressStart = firstAddress; m_MEM2Present = true; @@ -70,14 +72,14 @@ bool LinuxDolphinProcess::obtainEmuRAMInformations() break; } - if (SecondAddress - firstAddress == 0x2000000) + if (SecondAddress - firstAddress == Common::GetMEM1Size()) { if (offset == 0x0) { m_emuRAMAddressStart = firstAddress; MEM1Found = true; } - else if (offset == 0x2040000) + else if (offset == Common::GetMEM1Size() + 0x40000) { m_emuARAMAdressStart = firstAddress; m_ARAMAccessible = true; @@ -105,6 +107,9 @@ bool LinuxDolphinProcess::findPID() if (directoryPointer == nullptr) return false; + static const char* const s_dolphinProcessName{std::getenv("DME_DOLPHIN_PROCESS_NAME")}; + + m_PID = -1; struct dirent* directoryEntry = nullptr; while (m_PID == -1 && (directoryEntry = readdir(directoryPointer))) { @@ -116,7 +121,11 @@ bool LinuxDolphinProcess::findPID() std::string line; aCmdLineFile.open("/proc/" + std::string(directoryEntry->d_name) + "/comm"); getline(aCmdLineFile, line); - if (line == "dolphin-emu" || line == "dolphin-emu-qt2" || line == "dolphin-emu-wx") + + const bool match{s_dolphinProcessName ? line == s_dolphinProcessName : + (line == "dolphin-emu" || line == "dolphin-emu-qt2" || + line == "dolphin-emu-wx")}; + if (match) m_PID = aPID; aCmdLineFile.close(); @@ -264,5 +273,5 @@ bool LinuxDolphinProcess::writeToRAM(const u32 offset, const char* buffer, const return true; } -} // namespace DolphinComm +} // namespace DolphinComm #endif diff --git a/Source/DolphinProcess/Linux/LinuxDolphinProcess.h b/Source/DolphinProcess/Linux/LinuxDolphinProcess.h index 20b8e4d..58026f6 100644 --- a/Source/DolphinProcess/Linux/LinuxDolphinProcess.h +++ b/Source/DolphinProcess/Linux/LinuxDolphinProcess.h @@ -13,14 +13,12 @@ namespace DolphinComm class LinuxDolphinProcess : public IDolphinProcess { public: - LinuxDolphinProcess() - { - } + LinuxDolphinProcess() {} bool findPID() override; bool obtainEmuRAMInformations() override; bool readFromRAM(const u32 offset, char* buffer, size_t size, const bool withBSwap) override; bool writeToRAM(const u32 offset, const char* buffer, const size_t size, const bool withBSwap) override; }; -} // namespace DolphinComm +} // namespace DolphinComm #endif diff --git a/Source/DolphinProcess/Mac/MacDolphinProcess.cpp b/Source/DolphinProcess/Mac/MacDolphinProcess.cpp new file mode 100644 index 0000000..d5f7382 --- /dev/null +++ b/Source/DolphinProcess/Mac/MacDolphinProcess.cpp @@ -0,0 +1,243 @@ +#ifdef __APPLE__ + +#include "MacDolphinProcess.h" +#include "../../Common/CommonUtils.h" +#include "../../Common/MemoryCommon.h" + +#include +#include +#include +#include +#include + +namespace DolphinComm +{ +bool MacDolphinProcess::findPID() +{ + static const int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0}; + + size_t procSize = 0; + if (sysctl((int*)mib, 4, NULL, &procSize, NULL, 0) == -1) + return false; + + auto procs = std::make_unique(procSize / sizeof(kinfo_proc)); + if (sysctl((int*)mib, 4, procs.get(), &procSize, NULL, 0) == -1) + return false; + + static const char* const s_dolphinProcessName{std::getenv("DME_DOLPHIN_PROCESS_NAME")}; + + m_PID = -1; + for (int i = 0; i < procSize / sizeof(kinfo_proc); i++) + { + const std::string_view name{procs[i].kp_proc.p_comm}; + const bool match{s_dolphinProcessName ? name == s_dolphinProcessName : + (name == "Dolphin" || name == "dolphin-emu")}; + if (match) + { + m_PID = procs[i].kp_proc.p_pid; + } + } + + if (m_PID == -1) + return false; + return true; +} + +bool MacDolphinProcess::obtainEmuRAMInformations() +{ + m_currentTask = current_task(); + kern_return_t error = task_for_pid(m_currentTask, m_PID, &m_task); + if (error != KERN_SUCCESS) + return false; + + mach_vm_address_t regionAddr = 0; + mach_vm_size_t size = 0; + vm_region_extended_info_data_t regInfo; + vm_region_basic_info_data_64_t basInfo; + vm_region_top_info_data_t topInfo; + mach_msg_type_number_t cnt = VM_REGION_EXTENDED_INFO_COUNT; + mach_port_t obj; + bool MEM1Found = false; + unsigned int MEM1Obj = 0; + while (mach_vm_region(m_task, ®ionAddr, &size, VM_REGION_EXTENDED_INFO, (int*)®Info, &cnt, + &obj) == KERN_SUCCESS) + { + cnt = VM_REGION_BASIC_INFO_COUNT_64; + if (mach_vm_region(m_task, ®ionAddr, &size, VM_REGION_BASIC_INFO_64, (int*)&basInfo, &cnt, + &obj) != KERN_SUCCESS) + break; + cnt = VM_REGION_TOP_INFO_COUNT; + if (mach_vm_region(m_task, ®ionAddr, &size, VM_REGION_TOP_INFO, (int*)&topInfo, &cnt, + &obj) != 0) + break; + + if (!m_MEM2Present && size == Common::GetMEM2Size() && + basInfo.offset == Common::GetMEM1Size() + 0x40000) + { + m_MEM2Present = true; + m_MEM2AddressStart = regionAddr; + } + + // if these are true, then it is very likely the correct region, but we cannot guarantee + if ((!MEM1Found || (MEM1Found && MEM1Obj == topInfo.obj_id)) && size == Common::GetMEM1Size() && + regInfo.share_mode == SM_TRUESHARED && + basInfo.max_protection == (VM_PROT_READ | VM_PROT_WRITE)) + { + if (basInfo.offset == 0x0) + { + m_emuRAMAddressStart = regionAddr; + MEM1Found = true; + } + else if (basInfo.offset == Common::GetMEM1Size() + 0x40000) + { + m_emuARAMAdressStart = regionAddr; + m_ARAMAccessible = true; + } + + MEM1Found = true; + MEM1Obj = topInfo.obj_id; + } + + regionAddr += size; + cnt = VM_REGION_EXTENDED_INFO_COUNT; + } + + if (m_MEM2Present) + { + m_emuARAMAdressStart = 0; + m_ARAMAccessible = false; + } + + if (m_emuRAMAddressStart != 0) + return true; + + // Here, Dolphin appears to be running, but the emulator isn't started + return false; +} + +bool MacDolphinProcess::readFromRAM(const u32 offset, char* buffer, size_t size, + const bool withBSwap) +{ + vm_size_t nread; + u64 RAMAddress = 0; + if (m_ARAMAccessible) + { + if (offset >= Common::ARAM_FAKESIZE) + RAMAddress = m_emuRAMAddressStart + offset - Common::ARAM_FAKESIZE; + else + RAMAddress = m_emuARAMAdressStart + offset; + } + else if (offset >= (Common::MEM2_START - Common::MEM1_START)) + { + RAMAddress = m_MEM2AddressStart + offset - (Common::MEM2_START - Common::MEM1_START); + } + else + { + RAMAddress = m_emuRAMAddressStart + offset; + } + + if (vm_read_overwrite(m_task, RAMAddress, size, reinterpret_cast(buffer), &nread) != + KERN_SUCCESS) + return false; + if (nread != size) + return false; + + if (withBSwap) + { + switch (size) + { + case 2: + { + u16 halfword = 0; + std::memcpy(&halfword, buffer, sizeof(u16)); + halfword = Common::bSwap16(halfword); + std::memcpy(buffer, &halfword, sizeof(u16)); + break; + } + case 4: + { + u32 word = 0; + std::memcpy(&word, buffer, sizeof(u32)); + word = Common::bSwap32(word); + std::memcpy(buffer, &word, sizeof(u32)); + break; + } + case 8: + { + u64 doubleword = 0; + std::memcpy(&doubleword, buffer, sizeof(u64)); + doubleword = Common::bSwap64(doubleword); + std::memcpy(buffer, &doubleword, sizeof(u64)); + break; + } + } + } + + return true; +} + +bool MacDolphinProcess::writeToRAM(const u32 offset, const char* buffer, const size_t size, + const bool withBSwap) +{ + u64 RAMAddress = 0; + if (m_ARAMAccessible) + { + if (offset >= Common::ARAM_FAKESIZE) + RAMAddress = m_emuRAMAddressStart + offset - Common::ARAM_FAKESIZE; + else + RAMAddress = m_emuARAMAdressStart + offset; + } + else if (offset >= (Common::MEM2_START - Common::MEM1_START)) + { + RAMAddress = m_MEM2AddressStart + offset - (Common::MEM2_START - Common::MEM1_START); + } + else + { + RAMAddress = m_emuRAMAddressStart + offset; + } + + char* bufferCopy = new char[size]; + std::memcpy(bufferCopy, buffer, size); + + if (withBSwap) + { + switch (size) + { + case 2: + { + u16 halfword = 0; + std::memcpy(&halfword, bufferCopy, sizeof(u16)); + halfword = Common::bSwap16(halfword); + std::memcpy(bufferCopy, &halfword, sizeof(u16)); + break; + } + case 4: + { + u32 word = 0; + std::memcpy(&word, bufferCopy, sizeof(u32)); + word = Common::bSwap32(word); + std::memcpy(bufferCopy, &word, sizeof(u32)); + break; + } + case 8: + { + u64 doubleword = 0; + std::memcpy(&doubleword, bufferCopy, sizeof(u64)); + doubleword = Common::bSwap64(doubleword); + std::memcpy(bufferCopy, &doubleword, sizeof(u64)); + break; + } + } + } + + if (vm_write(m_task, RAMAddress, reinterpret_cast(bufferCopy), size) != KERN_SUCCESS) + { + delete[] bufferCopy; + return false; + } + + delete[] bufferCopy; + return true; +} +} // namespace DolphinComm +#endif diff --git a/Source/DolphinProcess/Dummy/DummyDolphinProcess.h b/Source/DolphinProcess/Mac/MacDolphinProcess.h similarity index 65% rename from Source/DolphinProcess/Dummy/DummyDolphinProcess.h rename to Source/DolphinProcess/Mac/MacDolphinProcess.h index da39c5a..4b23525 100644 --- a/Source/DolphinProcess/Dummy/DummyDolphinProcess.h +++ b/Source/DolphinProcess/Mac/MacDolphinProcess.h @@ -1,19 +1,25 @@ +#ifdef __APPLE__ + #pragma once +#include #include "../IDolphinProcess.h" namespace DolphinComm { -class DummyDolphinProcess : public IDolphinProcess +class MacDolphinProcess : public IDolphinProcess { public: - DummyDolphinProcess() - { - } + MacDolphinProcess() {} bool findPID() override; bool obtainEmuRAMInformations() override; bool readFromRAM(const u32 offset, char* buffer, size_t size, const bool withBSwap) override; bool writeToRAM(const u32 offset, const char* buffer, const size_t size, const bool withBSwap) override; + +private: + task_t m_task; + task_t m_currentTask; }; -} // namespace DolphinComm +} // namespace DolphinComm +#endif diff --git a/Source/DolphinProcess/Windows/WindowsDolphinProcess.cpp b/Source/DolphinProcess/Windows/WindowsDolphinProcess.cpp old mode 100755 new mode 100644 index f00ca1d..1e640d9 --- a/Source/DolphinProcess/Windows/WindowsDolphinProcess.cpp +++ b/Source/DolphinProcess/Windows/WindowsDolphinProcess.cpp @@ -1,242 +1,273 @@ -#ifdef _WIN32 - -#include "WindowsDolphinProcess.h" -#include "../../Common/CommonUtils.h" - -#include -#include -#include - -namespace DolphinComm -{ - -bool WindowsDolphinProcess::findPID() -{ - PROCESSENTRY32 entry; - entry.dwSize = sizeof(PROCESSENTRY32); - - HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); - - if (Process32First(snapshot, &entry) == TRUE) - { - do - { - if (std::string(entry.szExeFile) == "Dolphin.exe" || - std::string(entry.szExeFile) == "DolphinQt2.exe" || - std::string(entry.szExeFile) == "DolphinWx.exe") - { - m_PID = entry.th32ProcessID; - break; - } - } while (Process32Next(snapshot, &entry) == TRUE); - } - - CloseHandle(snapshot); - if (m_PID == -1) - // Here, Dolphin doesn't appear to be running on the system - return false; - - // Get the handle if Dolphin is running since it's required on Windows to read or write into the - // RAM of the process and to query the RAM mapping information - m_hDolphin = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_READ | - PROCESS_VM_WRITE, - FALSE, m_PID); - return true; -} - -bool WindowsDolphinProcess::obtainEmuRAMInformations() -{ - MEMORY_BASIC_INFORMATION info; - bool MEM1Found = false; - for (unsigned char* p = nullptr; - VirtualQueryEx(m_hDolphin, p, &info, sizeof(info)) == sizeof(info); p += info.RegionSize) - { - // Check region size so that we know it's MEM2 - if (!m_MEM2Present && info.RegionSize == 0x4000000) - { - u64 regionBaseAddress = 0; - std::memcpy(®ionBaseAddress, &(info.BaseAddress), sizeof(info.BaseAddress)); - if (MEM1Found && regionBaseAddress > m_emuRAMAddressStart + 0x10000000) - { - // In some cases MEM2 could actually be before MEM1. Once we find MEM1, ignore regions of - // this size that are too far away. There apparently are other non-MEM2 regions of size - // 0x4000000. - break; - } - // View the comment for MEM1. - PSAPI_WORKING_SET_EX_INFORMATION wsInfo; - wsInfo.VirtualAddress = info.BaseAddress; - if (QueryWorkingSetEx(m_hDolphin, &wsInfo, sizeof(PSAPI_WORKING_SET_EX_INFORMATION))) - { - if (wsInfo.VirtualAttributes.Valid) - { - std::memcpy(&m_MEM2AddressStart, &(regionBaseAddress), sizeof(regionBaseAddress)); - m_MEM2Present = true; - } - } - } - else if (info.RegionSize == 0x2000000 && info.Type == MEM_MAPPED) - { - // Here, it's likely the right page, but it can happen that multiple pages with these criteria - // exists and have nothing to do with the emulated memory. Only the right page has valid - // working set information so an additional check is required that it is backed by physical - // memory. - PSAPI_WORKING_SET_EX_INFORMATION wsInfo; - wsInfo.VirtualAddress = info.BaseAddress; - if (QueryWorkingSetEx(m_hDolphin, &wsInfo, sizeof(PSAPI_WORKING_SET_EX_INFORMATION))) - { - if (wsInfo.VirtualAttributes.Valid) - { - if (!MEM1Found) - { - std::memcpy(&m_emuRAMAddressStart, &(info.BaseAddress), sizeof(info.BaseAddress)); - MEM1Found = true; - } - else - { - u64 aramCandidate = 0; - std::memcpy(&aramCandidate, &(info.BaseAddress), sizeof(info.BaseAddress)); - if (aramCandidate == m_emuRAMAddressStart + 0x2000000) - { - m_emuARAMAdressStart = aramCandidate; - m_ARAMAccessible = true; - } - } - } - } - } - } - - if (m_MEM2Present) - { - m_emuARAMAdressStart = 0; - m_ARAMAccessible = false; - } - - if (m_emuRAMAddressStart == 0) - { - // Here, Dolphin is running, but the emulation hasn't started - return false; - } - return true; -} - -bool WindowsDolphinProcess::readFromRAM(const u32 offset, char* buffer, const size_t size, - const bool withBSwap) -{ - u64 RAMAddress = 0; - if (m_ARAMAccessible) - { - if (offset >= Common::ARAM_FAKESIZE) - RAMAddress = m_emuRAMAddressStart + offset - Common::ARAM_FAKESIZE; - else - RAMAddress = m_emuARAMAdressStart + offset; - } - else if (offset >= (Common::MEM2_START - Common::MEM1_START)) - { - RAMAddress = m_MEM2AddressStart + offset - (Common::MEM2_START - Common::MEM1_START); - } - else - { - RAMAddress = m_emuRAMAddressStart + offset; - } - - SIZE_T nread = 0; - bool bResult = ReadProcessMemory(m_hDolphin, (void*)RAMAddress, buffer, size, &nread); - if (bResult && nread == size) - { - if (withBSwap) - { - switch (size) - { - case 2: - { - u16 halfword = 0; - std::memcpy(&halfword, buffer, sizeof(u16)); - halfword = Common::bSwap16(halfword); - std::memcpy(buffer, &halfword, sizeof(u16)); - break; - } - case 4: - { - u32 word = 0; - std::memcpy(&word, buffer, sizeof(u32)); - word = Common::bSwap32(word); - std::memcpy(buffer, &word, sizeof(u32)); - break; - } - case 8: - { - u64 doubleword = 0; - std::memcpy(&doubleword, buffer, sizeof(u64)); - doubleword = Common::bSwap64(doubleword); - std::memcpy(buffer, &doubleword, sizeof(u64)); - break; - } - } - } - return true; - } - return false; -} - -bool WindowsDolphinProcess::writeToRAM(const u32 offset, const char* buffer, const size_t size, - const bool withBSwap) -{ - u64 RAMAddress = 0; - if (m_ARAMAccessible) - { - if (offset >= Common::ARAM_FAKESIZE) - RAMAddress = m_emuRAMAddressStart + offset - Common::ARAM_FAKESIZE; - else - RAMAddress = m_emuARAMAdressStart + offset; - } - else if (offset >= (Common::MEM2_START - Common::MEM1_START)) - { - RAMAddress = m_MEM2AddressStart + offset - (Common::MEM2_START - Common::MEM1_START); - } - else - { - RAMAddress = m_emuRAMAddressStart + offset; - } - - SIZE_T nread = 0; - char* bufferCopy = new char[size]; - std::memcpy(bufferCopy, buffer, size); - if (withBSwap) - { - switch (size) - { - case 2: - { - u16 halfword = 0; - std::memcpy(&halfword, bufferCopy, sizeof(u16)); - halfword = Common::bSwap16(halfword); - std::memcpy(bufferCopy, &halfword, sizeof(u16)); - break; - } - case 4: - { - u32 word = 0; - std::memcpy(&word, bufferCopy, sizeof(u32)); - word = Common::bSwap32(word); - std::memcpy(bufferCopy, &word, sizeof(u32)); - break; - } - case 8: - { - u64 doubleword = 0; - std::memcpy(&doubleword, bufferCopy, sizeof(u64)); - doubleword = Common::bSwap64(doubleword); - std::memcpy(bufferCopy, &doubleword, sizeof(u64)); - break; - } - } - } - - bool bResult = WriteProcessMemory(m_hDolphin, (void*)RAMAddress, bufferCopy, size, &nread); - delete[] bufferCopy; - return (bResult && nread == size); -} -} // namespace DolphinComm -#endif +#ifdef _WIN32 + +#include "WindowsDolphinProcess.h" +#include "../../Common/CommonUtils.h" +#include "../../Common/MemoryCommon.h" + +#include +#ifdef UNICODE +#include +#endif +#include +#include +#include + +namespace +{ +#ifdef UNICODE +std::wstring utf8_to_wstring(const std::string& str) +{ + std::wstring_convert> myconv; + return myconv.from_bytes(str); +} +#endif +} // namespace + +namespace DolphinComm +{ + +bool WindowsDolphinProcess::findPID() +{ + PROCESSENTRY32 entry; + entry.dwSize = sizeof(PROCESSENTRY32); + + static const char* const s_dolphinProcessName{std::getenv("DME_DOLPHIN_PROCESS_NAME")}; + + HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); + + m_PID = -1; + if (Process32First(snapshot, &entry) == TRUE) + { + do + { +#ifdef UNICODE + const std::wstring exeFile{entry.szExeFile}; + const bool match{s_dolphinProcessName ? + (exeFile == utf8_to_wstring(s_dolphinProcessName) || + exeFile == utf8_to_wstring(s_dolphinProcessName) + L".exe") : + (exeFile == L"Dolphin.exe" || exeFile == L"DolphinQt2.exe" || + exeFile == L"DolphinWx.exe")}; +#else + const std::string exeFile{entry.szExeFile}; + const bool match{s_dolphinProcessName ? + (exeFile == s_dolphinProcessName || + exeFile == std::string(s_dolphinProcessName) + ".exe") : + (exeFile == "Dolphin.exe" || exeFile == "DolphinQt2.exe" || + exeFile == "DolphinWx.exe")}; +#endif + if (match) + { + m_PID = entry.th32ProcessID; + break; + } + } while (Process32Next(snapshot, &entry) == TRUE); + } + + CloseHandle(snapshot); + if (m_PID == -1) + // Here, Dolphin doesn't appear to be running on the system + return false; + + // Get the handle if Dolphin is running since it's required on Windows to read or write into the + // RAM of the process and to query the RAM mapping information + m_hDolphin = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_READ | + PROCESS_VM_WRITE, + FALSE, m_PID); + return true; +} + +bool WindowsDolphinProcess::obtainEmuRAMInformations() +{ + MEMORY_BASIC_INFORMATION info; + bool MEM1Found = false; + for (unsigned char* p = nullptr; + VirtualQueryEx(m_hDolphin, p, &info, sizeof(info)) == sizeof(info); p += info.RegionSize) + { + // Check region size so that we know it's MEM2 + if (!m_MEM2Present && info.RegionSize == Common::GetMEM2Size()) + { + u64 regionBaseAddress = 0; + std::memcpy(®ionBaseAddress, &(info.BaseAddress), sizeof(info.BaseAddress)); + if (MEM1Found && regionBaseAddress > m_emuRAMAddressStart + 0x10000000) + { + // In some cases MEM2 could actually be before MEM1. Once we find MEM1, ignore regions of + // this size that are too far away. There apparently are other non-MEM2 regions of 64 MiB. + break; + } + // View the comment for MEM1. + PSAPI_WORKING_SET_EX_INFORMATION wsInfo; + wsInfo.VirtualAddress = info.BaseAddress; + if (QueryWorkingSetEx(m_hDolphin, &wsInfo, sizeof(PSAPI_WORKING_SET_EX_INFORMATION))) + { + if (wsInfo.VirtualAttributes.Valid) + { + std::memcpy(&m_MEM2AddressStart, &(regionBaseAddress), sizeof(regionBaseAddress)); + m_MEM2Present = true; + } + } + } + else if (info.RegionSize == Common::GetMEM1Size() && info.Type == MEM_MAPPED) + { + // Here, it's likely the right page, but it can happen that multiple pages with these criteria + // exists and have nothing to do with the emulated memory. Only the right page has valid + // working set information so an additional check is required that it is backed by physical + // memory. + PSAPI_WORKING_SET_EX_INFORMATION wsInfo; + wsInfo.VirtualAddress = info.BaseAddress; + if (QueryWorkingSetEx(m_hDolphin, &wsInfo, sizeof(PSAPI_WORKING_SET_EX_INFORMATION))) + { + if (wsInfo.VirtualAttributes.Valid) + { + if (!MEM1Found) + { + std::memcpy(&m_emuRAMAddressStart, &(info.BaseAddress), sizeof(info.BaseAddress)); + MEM1Found = true; + } + else + { + u64 aramCandidate = 0; + std::memcpy(&aramCandidate, &(info.BaseAddress), sizeof(info.BaseAddress)); + if (aramCandidate == m_emuRAMAddressStart + Common::GetMEM1Size()) + { + m_emuARAMAdressStart = aramCandidate; + m_ARAMAccessible = true; + } + } + } + } + } + } + + if (m_MEM2Present) + { + m_emuARAMAdressStart = 0; + m_ARAMAccessible = false; + } + + if (m_emuRAMAddressStart == 0) + { + // Here, Dolphin is running, but the emulation hasn't started + return false; + } + return true; +} + +bool WindowsDolphinProcess::readFromRAM(const u32 offset, char* buffer, const size_t size, + const bool withBSwap) +{ + u64 RAMAddress = 0; + if (m_ARAMAccessible) + { + if (offset >= Common::ARAM_FAKESIZE) + RAMAddress = m_emuRAMAddressStart + offset - Common::ARAM_FAKESIZE; + else + RAMAddress = m_emuARAMAdressStart + offset; + } + else if (offset >= (Common::MEM2_START - Common::MEM1_START)) + { + RAMAddress = m_MEM2AddressStart + offset - (Common::MEM2_START - Common::MEM1_START); + } + else + { + RAMAddress = m_emuRAMAddressStart + offset; + } + + SIZE_T nread = 0; + bool bResult = ReadProcessMemory(m_hDolphin, (void*)RAMAddress, buffer, size, &nread); + if (bResult && nread == size) + { + if (withBSwap) + { + switch (size) + { + case 2: + { + u16 halfword = 0; + std::memcpy(&halfword, buffer, sizeof(u16)); + halfword = Common::bSwap16(halfword); + std::memcpy(buffer, &halfword, sizeof(u16)); + break; + } + case 4: + { + u32 word = 0; + std::memcpy(&word, buffer, sizeof(u32)); + word = Common::bSwap32(word); + std::memcpy(buffer, &word, sizeof(u32)); + break; + } + case 8: + { + u64 doubleword = 0; + std::memcpy(&doubleword, buffer, sizeof(u64)); + doubleword = Common::bSwap64(doubleword); + std::memcpy(buffer, &doubleword, sizeof(u64)); + break; + } + } + } + return true; + } + return false; +} + +bool WindowsDolphinProcess::writeToRAM(const u32 offset, const char* buffer, const size_t size, + const bool withBSwap) +{ + u64 RAMAddress = 0; + if (m_ARAMAccessible) + { + if (offset >= Common::ARAM_FAKESIZE) + RAMAddress = m_emuRAMAddressStart + offset - Common::ARAM_FAKESIZE; + else + RAMAddress = m_emuARAMAdressStart + offset; + } + else if (offset >= (Common::MEM2_START - Common::MEM1_START)) + { + RAMAddress = m_MEM2AddressStart + offset - (Common::MEM2_START - Common::MEM1_START); + } + else + { + RAMAddress = m_emuRAMAddressStart + offset; + } + + SIZE_T nread = 0; + char* bufferCopy = new char[size]; + std::memcpy(bufferCopy, buffer, size); + if (withBSwap) + { + switch (size) + { + case 2: + { + u16 halfword = 0; + std::memcpy(&halfword, bufferCopy, sizeof(u16)); + halfword = Common::bSwap16(halfword); + std::memcpy(bufferCopy, &halfword, sizeof(u16)); + break; + } + case 4: + { + u32 word = 0; + std::memcpy(&word, bufferCopy, sizeof(u32)); + word = Common::bSwap32(word); + std::memcpy(bufferCopy, &word, sizeof(u32)); + break; + } + case 8: + { + u64 doubleword = 0; + std::memcpy(&doubleword, bufferCopy, sizeof(u64)); + doubleword = Common::bSwap64(doubleword); + std::memcpy(bufferCopy, &doubleword, sizeof(u64)); + break; + } + } + } + + bool bResult = WriteProcessMemory(m_hDolphin, (void*)RAMAddress, bufferCopy, size, &nread); + delete[] bufferCopy; + return (bResult && nread == size); +} +} // namespace DolphinComm +#endif diff --git a/Source/DolphinProcess/Windows/WindowsDolphinProcess.h b/Source/DolphinProcess/Windows/WindowsDolphinProcess.h index 759a960..b12705a 100644 --- a/Source/DolphinProcess/Windows/WindowsDolphinProcess.h +++ b/Source/DolphinProcess/Windows/WindowsDolphinProcess.h @@ -11,9 +11,7 @@ namespace DolphinComm class WindowsDolphinProcess : public IDolphinProcess { public: - WindowsDolphinProcess() - { - } + WindowsDolphinProcess() {} bool findPID() override; bool obtainEmuRAMInformations() override; bool readFromRAM(const u32 offset, char* buffer, const size_t size, @@ -24,5 +22,5 @@ class WindowsDolphinProcess : public IDolphinProcess private: HANDLE m_hDolphin; }; -} // namespace DolphinComm +} // namespace DolphinComm #endif diff --git a/Source/MemoryScanner/MemoryScanner.cpp b/Source/MemoryScanner/MemoryScanner.cpp index ea3358e..c7816ca 100644 --- a/Source/MemoryScanner/MemoryScanner.cpp +++ b/Source/MemoryScanner/MemoryScanner.cpp @@ -17,23 +17,51 @@ Common::MemOperationReturnCode MemScanner::firstScan(const MemScanner::ScanFiter const std::string& searchTerm2) { m_scanRAMCache = nullptr; - if (DolphinComm::DolphinAccessor::updateRAMCache() != Common::MemOperationReturnCode::OK) + u32 ramSize = static_cast(DolphinComm::DolphinAccessor::getRAMTotalSize()); + m_scanRAMCache = new char[ramSize]; + DolphinComm::DolphinAccessor::readEntireRAM(m_scanRAMCache); + + u32 beginA = m_searchInRangeBegin ? m_beginSearchRange : 0; + u32 endA = m_searchInRangeEnd ? m_endSearchRange : ramSize; + + if (m_searchInRangeBegin || m_searchInRangeEnd) { - return Common::MemOperationReturnCode::operationFailed; + ramSize = endA - beginA; } - u32 ramSize = DolphinComm::DolphinAccessor::getRAMCacheSize(); - m_scanRAMCache = new char[ramSize]; - std::memcpy(m_scanRAMCache, DolphinComm::DolphinAccessor::getRAMCache(), ramSize); if (filter == ScanFiter::unknownInitial) { - int alignementDivision = - m_enforceMemAlignement ? Common::getNbrBytesAlignementForType(m_memType) : 1; - m_resultCount = ((ramSize / alignementDivision) - - Common::getSizeForType(m_memType, static_cast(1))); - m_wasUnknownInitialValue = true; - m_memSize = 1; - m_scanStarted = true; + if (m_searchInRangeBegin || m_searchInRangeEnd) + { + int alignmentDivision = + m_enforceMemAlignment ? Common::getNbrBytesAlignmentForType(m_memType) : 1; + m_wasUnknownInitialValue = false; + m_memSize = Common::getSizeForType(m_memType, static_cast(1)); + m_scanStarted = true; + + bool aram = DolphinComm::DolphinAccessor::isARAMAccessible(); + + u32 alignedBeginA = + beginA + ((alignmentDivision - (beginA % alignmentDivision)) % alignmentDivision); + + for (u32 i = alignedBeginA; i < endA - m_memSize; i += alignmentDivision) + { + m_resultsConsoleAddr.push_back(Common::offsetToDolphinAddr(i, aram)); + } + + m_resultCount = m_resultsConsoleAddr.size(); + } + else + { + int alignementDivision = + m_enforceMemAlignment ? Common::getNbrBytesAlignmentForType(m_memType) : 1; + m_resultCount = ((ramSize / alignementDivision) - + Common::getSizeForType(m_memType, static_cast(1))); + m_wasUnknownInitialValue = true; + m_memSize = 1; + m_scanStarted = true; + } + return Common::MemOperationReturnCode::OK; } @@ -87,8 +115,12 @@ Common::MemOperationReturnCode MemScanner::firstScan(const MemScanner::ScanFiter char* noOffset = new char[m_memSize]; std::memset(noOffset, 0, m_memSize); - int increment = m_enforceMemAlignement ? Common::getNbrBytesAlignementForType(m_memType) : 1; - for (u32 i = 0; i < (ramSize - m_memSize); i += increment) + int increment = m_enforceMemAlignment ? Common::getNbrBytesAlignmentForType(m_memType) : 1; + + u32 beginSearch = beginA; + u32 endSearch = endA - static_cast(m_memSize); + + for (u32 i = beginSearch; i < endSearch; i += increment) { char* memoryCandidate = &m_scanRAMCache[i]; bool isResult = false; @@ -149,13 +181,9 @@ Common::MemOperationReturnCode MemScanner::nextScan(const MemScanner::ScanFiter const std::string& searchTerm2) { char* newerRAMCache = nullptr; - if (DolphinComm::DolphinAccessor::updateRAMCache() != Common::MemOperationReturnCode::OK) - { - return Common::MemOperationReturnCode::operationFailed; - } - u32 ramSize = DolphinComm::DolphinAccessor::getRAMCacheSize(); + u32 ramSize = static_cast(DolphinComm::DolphinAccessor::getRAMTotalSize()); newerRAMCache = new char[ramSize]; - std::memcpy(newerRAMCache, DolphinComm::DolphinAccessor::getRAMCache(), ramSize); + DolphinComm::DolphinAccessor::readEntireRAM(newerRAMCache); Common::MemOperationReturnCode scanReturn = Common::MemOperationReturnCode::OK; size_t termActualLength = 0; @@ -203,11 +231,13 @@ Common::MemOperationReturnCode MemScanner::nextScan(const MemScanner::ScanFiter std::vector newerResults = std::vector(); bool aramAccessible = DolphinComm::DolphinAccessor::isARAMAccessible(); + bool wasUninitialized = m_wasUnknownInitialValue; + if (m_wasUnknownInitialValue) { m_wasUnknownInitialValue = false; - int increment = m_enforceMemAlignement ? Common::getNbrBytesAlignementForType(m_memType) : 1; + int increment = m_enforceMemAlignment ? Common::getNbrBytesAlignmentForType(m_memType) : 1; for (u32 i = 0; i < (ramSize - m_memSize); i += increment) { if (isHitNextScan(filter, memoryToCompare1, memoryToCompare2, noOffset, newerRAMCache, @@ -233,8 +263,13 @@ Common::MemOperationReturnCode MemScanner::nextScan(const MemScanner::ScanFiter } delete[] noOffset; + + m_UndoStack.push({m_resultsConsoleAddr, wasUninitialized}); + m_undoCount = m_UndoStack.size(); + m_resultsConsoleAddr.clear(); std::swap(m_resultsConsoleAddr, newerResults); + delete[] m_scanRAMCache; m_scanRAMCache = nullptr; m_scanRAMCache = newerRAMCache; @@ -250,6 +285,11 @@ void MemScanner::reset() m_scanRAMCache = nullptr; m_resultCount = 0; m_scanStarted = false; + while (!m_UndoStack.empty()) + { + m_UndoStack.pop(); + } + m_undoCount = 0; } inline bool MemScanner::isHitNextScan(const MemScanner::ScanFiter filter, @@ -367,9 +407,9 @@ void MemScanner::setBase(const Common::MemBase base) m_memBase = base; } -void MemScanner::setEnforceMemAlignement(const bool enforceAlignement) +void MemScanner::setEnforceMemAlignment(const bool enforceAlignment) { - m_enforceMemAlignement = enforceAlignement; + m_enforceMemAlignment = enforceAlignment; } void MemScanner::setIsSigned(const bool isSigned) @@ -377,6 +417,62 @@ void MemScanner::setIsSigned(const bool isSigned) m_memIsSigned = isSigned; } +void MemScanner::resetSearchRange() +{ + m_searchInRangeBegin = false; + m_searchInRangeEnd = false; + m_beginSearchRange = 0; + m_endSearchRange = 0; +} + +bool MemScanner::setSearchRange(u32 beginRange, u32 endRange) +{ + if (!DolphinComm::DolphinAccessor::isValidConsoleAddress(beginRange) || + !DolphinComm::DolphinAccessor::isValidConsoleAddress(endRange)) + { + return false; + } + + m_searchInRangeBegin = true; + m_searchInRangeEnd = true; + bool aram = DolphinComm::DolphinAccessor::isARAMAccessible(); + m_beginSearchRange = + Common::offsetToCacheIndex(Common::dolphinAddrToOffset(beginRange, aram), aram); + m_endSearchRange = Common::offsetToCacheIndex(Common::dolphinAddrToOffset(endRange, aram), aram); + + return true; +} + +bool MemScanner::setSearchRangeBegin(u32 beginRange) +{ + if (!DolphinComm::DolphinAccessor::isValidConsoleAddress(beginRange)) + { + return false; + } + + m_searchInRangeBegin = true; + bool aram = DolphinComm::DolphinAccessor::isARAMAccessible(); + m_beginSearchRange = + Common::offsetToCacheIndex(Common::dolphinAddrToOffset(beginRange, aram), aram); + + return true; +} + +bool MemScanner::setSearchRangeEnd(u32 endRange) +{ + if (!DolphinComm::DolphinAccessor::isValidConsoleAddress(endRange)) + { + return false; + } + + m_searchInRangeEnd = true; + bool aram = DolphinComm::DolphinAccessor::isARAMAccessible(); + m_endSearchRange = + Common::offsetToCacheIndex(Common::dolphinAddrToOffset(endRange, aram), aram) + 1; + + return true; +} + int MemScanner::getTermsNumForFilter(const MemScanner::ScanFiter filter) const { if (filter == MemScanner::ScanFiter::between) @@ -409,20 +505,14 @@ std::string MemScanner::getFormattedScannedValueAt(const int index) const !m_memIsSigned, Common::shouldBeBSwappedForType(m_memType)); } -Common::MemOperationReturnCode MemScanner::updateCurrentRAMCache() -{ - return DolphinComm::DolphinAccessor::updateRAMCache(); -} - std::string MemScanner::getFormattedCurrentValueAt(const int index) const { if (DolphinComm::DolphinAccessor::isValidConsoleAddress(m_resultsConsoleAddr.at(index))) { bool aramAccessible = DolphinComm::DolphinAccessor::isARAMAccessible(); u32 offset = Common::dolphinAddrToOffset(m_resultsConsoleAddr.at(index), aramAccessible); - u32 ramIndex = Common::offsetToCacheIndex(offset, aramAccessible); - return DolphinComm::DolphinAccessor::getFormattedValueFromCache(ramIndex, m_memType, m_memSize, - m_memBase, !m_memIsSigned); + return DolphinComm::DolphinAccessor::getFormattedValueFromMemory(offset, m_memType, m_memSize, + m_memBase, !m_memIsSigned); } return ""; } @@ -452,11 +542,48 @@ std::string MemScanner::addSpacesToBytesArrays(const std::string& bytesArray) co return result; } +bool MemScanner::undoScan() +{ + if (m_undoCount > 0) + { + m_resultsConsoleAddr = m_UndoStack.top().data; + m_resultCount = m_resultsConsoleAddr.size(); + bool wasUninitialzed = m_UndoStack.top().wasUnknownInitialState; + + m_UndoStack.pop(); + m_undoCount = m_UndoStack.size(); + + if (wasUninitialzed) + { + u32 ramSize = static_cast(DolphinComm::DolphinAccessor::getRAMTotalSize()); + int alignementDivision = + m_enforceMemAlignment ? Common::getNbrBytesAlignmentForType(m_memType) : 1; + m_resultCount = ((ramSize / alignementDivision) - + Common::getSizeForType(m_memType, static_cast(1))); + m_wasUnknownInitialValue = true; + m_memSize = 1; + } + + return true; + } + return false; +} + size_t MemScanner::getResultCount() const { return m_resultCount; } +bool MemScanner::hasUndo() const +{ + return m_undoCount > 0; +} + +size_t MemScanner::getUndoCount() const +{ + return m_undoCount; +} + bool MemScanner::hasScanStarted() const { return m_scanStarted; diff --git a/Source/MemoryScanner/MemoryScanner.h b/Source/MemoryScanner/MemoryScanner.h index 79b0552..dbc5080 100644 --- a/Source/MemoryScanner/MemoryScanner.h +++ b/Source/MemoryScanner/MemoryScanner.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -40,6 +41,7 @@ class MemScanner const std::string& searchTerm2); Common::MemOperationReturnCode nextScan(const ScanFiter filter, const std::string& searchTerm1, const std::string& searchTerm2); + bool undoScan(); void reset(); inline CompareResult compareMemoryAsNumbers(const char* first, const char* second, const char* offset, bool offsetInvert, @@ -124,18 +126,23 @@ class MemScanner void setType(const Common::MemType type); void setBase(const Common::MemBase base); - void setEnforceMemAlignement(const bool enforceAlignement); + void setEnforceMemAlignment(const bool enforceAlignment); void setIsSigned(const bool isSigned); + void resetSearchRange(); + bool setSearchRangeBegin(u32 beginIndex); + bool setSearchRangeEnd(u32 endIndex); + bool setSearchRange(u32 beginIndex, u32 endIndex); std::vector getResultsConsoleAddr() const; size_t getResultCount() const; + bool hasUndo() const; + size_t getUndoCount() const; int getTermsNumForFilter(const ScanFiter filter) const; Common::MemType getType() const; Common::MemBase getBase() const; size_t getLength() const; bool getIsUnsigned() const; std::string getFormattedScannedValueAt(const int index) const; - Common::MemOperationReturnCode updateCurrentRAMCache(); std::string getFormattedCurrentValueAt(int index) const; void removeResultAt(int index); bool typeSupportsAdditionalOptions(const Common::MemType type) const; @@ -148,14 +155,28 @@ class MemScanner const u32 consoleOffset) const; std::string addSpacesToBytesArrays(const std::string& bytesArray) const; + bool m_searchInRangeBegin = false; + bool m_searchInRangeEnd = false; + u32 m_beginSearchRange = 0; + u32 m_endSearchRange = 0; + Common::MemType m_memType = Common::MemType::type_byte; Common::MemBase m_memBase = Common::MemBase::base_decimal; size_t m_memSize; - bool m_enforceMemAlignement = true; + bool m_enforceMemAlignment = true; bool m_memIsSigned = false; - std::vector m_resultsConsoleAddr; - bool m_wasUnknownInitialValue = false; + size_t m_resultCount = 0; + size_t m_undoCount = 0; + bool m_wasUnknownInitialValue = false; char* m_scanRAMCache = nullptr; bool m_scanStarted = false; + + struct MemScannerUndoAction + { + std::vector data; + bool wasUnknownInitialState = false; + }; + std::stack m_UndoStack; + std::vector m_resultsConsoleAddr; }; diff --git a/Source/MemoryWatch/MemWatchEntry.cpp b/Source/MemoryWatch/MemWatchEntry.cpp index 2c04d07..5dd12ab 100644 --- a/Source/MemoryWatch/MemWatchEntry.cpp +++ b/Source/MemoryWatch/MemWatchEntry.cpp @@ -261,6 +261,9 @@ Common::MemOperationReturnCode MemWatchEntry::readMemoryFromRAM() m_isValidPointer = true; } + if (!DolphinComm::DolphinAccessor::isValidConsoleAddress(realConsoleAddress)) + return Common::MemOperationReturnCode::OK; + if (DolphinComm::DolphinAccessor::readFromRAM( Common::dolphinAddrToOffset(realConsoleAddress, DolphinComm::DolphinAccessor::isARAMAccessible()), @@ -303,6 +306,9 @@ Common::MemOperationReturnCode MemWatchEntry::writeMemoryToRAM(const char* memor m_isValidPointer = true; } + if (!DolphinComm::DolphinAccessor::isValidConsoleAddress(realConsoleAddress)) + return Common::MemOperationReturnCode::OK; + if (DolphinComm::DolphinAccessor::writeToRAM( Common::dolphinAddrToOffset(realConsoleAddress, DolphinComm::DolphinAccessor::isARAMAccessible()), @@ -313,7 +319,8 @@ Common::MemOperationReturnCode MemWatchEntry::writeMemoryToRAM(const char* memor std::string MemWatchEntry::getStringFromMemory() const { - if (m_boundToPointer && !m_isValidPointer) + if ((m_boundToPointer && !m_isValidPointer) || + !DolphinComm::DolphinAccessor::isValidConsoleAddress(m_consoleAddress)) return "???"; return Common::formatMemoryToString(m_memory, m_type, m_length, m_base, m_isUnsigned); } diff --git a/_dolphin_memory_engine.pyx b/_dolphin_memory_engine.pyx index 64cb176..f0073d1 100644 --- a/_dolphin_memory_engine.pyx +++ b/_dolphin_memory_engine.pyx @@ -28,7 +28,7 @@ cdef extern from "Common/CommonUtils.h" namespace "Common": uint32_t offsetToDolphinAddr(uint32_t, c_bool) -cdef extern from "DolphinProcess/DolphinAccessor.h" namespace "DolphinComm": +cdef extern from "DolphinProcess/DolphinAccessor.h" namespace "DolphinComm::DolphinAccessor": cpdef enum class DolphinStatus: hooked notRunning