Skip to content

Commit

Permalink
Merge pull request #2 from aldelaro5/memory-viewer
Browse files Browse the repository at this point in the history
Add and integrate a memory viewer
  • Loading branch information
aldelaro5 authored Sep 10, 2017
2 parents 473d1be + 3e4ed64 commit 1402279
Show file tree
Hide file tree
Showing 16 changed files with 816 additions and 40 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ For binary releases of this program, refer to [the "releases" page](https://gith
## System requirements
Any x86_64 based system should theoretically work, however, please note that Mac OS is currently _not_ supported. Additionally, 32-bit x86 based systems are unsupported as Dolphin does not support them either. (Support for them was dropped a while ago.)

You absolutely need to have Dolphin running ***and*** _have the emulation started_ for this program to be of any use. As such, your system needs to meet Dolphin's [system requirements](https://github.com/dolphin-emu/dolphin#system-requirements). Additionally, have at least 250 MB of memory free; especially when scanning with MEM2 enabled, as it should only take this much when doing that.
You absolutely need to have Dolphin running ***and*** _have the emulation started_ for this program to be of any use. As such, your system needs to meet Dolphin's [system requirements](https://github.com/dolphin-emu/dolphin#system-requirements). Additionally, have at least 250 MB of memory free.

On Linux, you need to install the Qt 5 package of your respective distribution.

Expand Down
2 changes: 1 addition & 1 deletion Roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ This file explains the features that are planned so far in the future of the pro

## Features to be implemented before 1.0:

* Memory viewer with real time updates
* DONE - Memory viewer with real time updates
* If possible, with a little animation showing what bytes updated
* Must also provide in place editing.
* Greatly improve the UI.
Expand Down
2 changes: 2 additions & 0 deletions Source/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ set(SRCS ${DolphinProcessSrc}
GUI/MemWatcher/MemWatchWidget.cpp
GUI/MemScanner/ResultsListModel.cpp
GUI/MemScanner/MemScanWidget.cpp
GUI/MemViewer/MemViewer.cpp
GUI/MemViewer/MemViewerWidget.cpp
GUI/MainWindow.cpp
main.cpp)

Expand Down
6 changes: 4 additions & 2 deletions Source/Common/MemoryCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -463,8 +463,10 @@ std::string formatMemoryToString(const char* memory, const MemType type, const s
std::memcpy(&aByte, memory + i, sizeof(u8));
ss << std::setfill('0') << std::setw(2) << static_cast<int>(aByte) << " ";
}
std::string test = ss.str();
return ss.str();
std::string str = ss.str();
// Remove the space at the end
str.pop_back();
return str;
}
default:
return "";
Expand Down
72 changes: 68 additions & 4 deletions Source/DolphinProcess/DolphinAccessor.cpp
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,19 @@
#include "Windows/WindowsDolphinProcess.h"
#endif

#include <cstring>

#include "../Common/CommonUtils.h"
#include "../Common/MemoryCommon.h"

namespace DolphinComm
{
IDolphinProcess* DolphinAccessor::m_instance = nullptr;
DolphinAccessor::DolphinStatus DolphinAccessor::m_status = DolphinStatus::unHooked;
char* DolphinAccessor::m_updatedRAMCache = nullptr;
bool DolphinAccessor::m_mem2Enabled = false;

void DolphinAccessor::hook()
void DolphinAccessor::init()
{
if (m_instance == nullptr)
{
Expand All @@ -23,7 +27,11 @@ void DolphinAccessor::hook()
m_instance = new WindowsDolphinProcess();
#endif
}
}

void DolphinAccessor::hook()
{
init();
if (!m_instance->findPID())
{
m_status = DolphinStatus::notRunning;
Expand All @@ -35,6 +43,7 @@ void DolphinAccessor::hook()
else
{
m_status = DolphinStatus::hooked;
updateRAMCache();
}
}

Expand Down Expand Up @@ -75,7 +84,10 @@ u64 DolphinAccessor::getEmuRAMAddressStart()

void DolphinAccessor::enableMem2(const bool doEnable)
{
bool old = m_mem2Enabled;
m_mem2Enabled = doEnable;
if (old != m_mem2Enabled)
updateRAMCache();
}

bool DolphinAccessor::isMem2Enabled()
Expand All @@ -94,19 +106,19 @@ void DolphinAccessor::autoDetectMem2()
{
case 'G': // Gamecube disc
case 'P': // Promotional games, guaranteed to be Gamecube
m_mem2Enabled = false;
enableMem2(false);
break;

case 'R': // Wii disc, can be prototypes, but unlikely
case 'S': // Later Wii disc
m_mem2Enabled = true;
enableMem2(true);
break;

// If there's no ID, likely to be a Wiiware, but this isn't guaranteed, could also be D, but
// this one is present on both, so let's just leave MEM2 enabled for these by default, the
// user can be the judge here, these are extremely unlikely cases anyway
default:
m_mem2Enabled = true;
enableMem2(true);
break;
}
}
Expand All @@ -119,11 +131,63 @@ void DolphinAccessor::autoDetectMem2()

bool DolphinAccessor::isValidConsoleAddress(const u32 address)
{
if (getStatus() != DolphinStatus::hooked)
return false;
bool isMem1Address = address >= Common::MEM1_START && address < Common::MEM1_END;
if (m_mem2Enabled)
{
return isMem1Address || (address >= Common::MEM2_START && address < Common::MEM2_END);
}
return isMem1Address;
}

Common::MemOperationReturnCode DolphinAccessor::updateRAMCache()
{
delete[] m_updatedRAMCache;
m_updatedRAMCache = nullptr;

// MEM2, if enabled, is read right after MEM1 in the cache so both regions are contigous
if (m_mem2Enabled)
{
m_updatedRAMCache = new char[Common::MEM1_SIZE + Common::MEM2_SIZE - 1];
// Read Wii extra RAM
if (!DolphinComm::DolphinAccessor::readFromRAM(Common::dolphinAddrToOffset(Common::MEM2_START),
m_updatedRAMCache + Common::MEM1_SIZE,
Common::MEM2_SIZE - 1, false))
return Common::MemOperationReturnCode::operationFailed;
}
else
{
m_updatedRAMCache = new char[Common::MEM1_SIZE - 1];
}
// Read GameCube and Wii basic RAM
if (!DolphinComm::DolphinAccessor::readFromRAM(0, m_updatedRAMCache, Common::MEM1_SIZE - 1,
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)
{
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<u32>(byteCount)) - 1))
{
u32 offset = Common::dolphinAddrToOffset(consoleAddress);
u32 ramIndex = 0;
if (offset >= Common::MEM1_SIZE)
ramIndex = offset - (Common::MEM2_START - Common::MEM1_END);
else
ramIndex = offset;
std::memcpy(dest, m_updatedRAMCache + ramIndex, byteCount);
}
}
}
9 changes: 9 additions & 0 deletions Source/DolphinProcess/DolphinAccessor.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Wrapper around IDolphinProcess
#pragma once

#include "../Common/CommonTypes.h"
#include "../Common/MemoryCommon.h"
#include "IDolphinProcess.h"

namespace DolphinComm
Expand All @@ -16,6 +18,7 @@ class DolphinAccessor
unHooked
};

static void init();
static void hook();
static void unHook();
static bool readFromRAM(const u32 offset, char* buffer, const size_t size, const bool withBSwap);
Expand All @@ -27,11 +30,17 @@ class DolphinAccessor
static void enableMem2(const bool doEnable);
static bool isMem2Enabled();
static void autoDetectMem2();
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 bool isValidConsoleAddress(const u32 address);

private:
static IDolphinProcess* m_instance;
static DolphinStatus m_status;
static bool m_mem2Enabled;
static char* m_updatedRAMCache;
};
}
38 changes: 37 additions & 1 deletion Source/GUI/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,16 @@ MainWindow::MainWindow()
m_mem2StatusWidget = new QWidget();
m_mem2StatusWidget->setLayout(mem2Status_layout);

m_btnOpenMemViewer = new QPushButton("Open memory viewer");
connect(m_btnOpenMemViewer, static_cast<void (QPushButton::*)(bool)>(&QPushButton::clicked), this,
&MainWindow::onOpenMenViewer);

QVBoxLayout* main_layout = new QVBoxLayout;
main_layout->addWidget(m_lblDolphinStatus);
main_layout->addLayout(dolphinHookButtons_layout);
main_layout->addWidget(m_mem2StatusWidget);
main_layout->addWidget(m_scanner);
main_layout->addWidget(m_btnOpenMemViewer);
main_layout->addWidget(m_watcher);

QWidget* main_widget = new QWidget(this);
Expand Down Expand Up @@ -89,6 +94,18 @@ MainWindow::MainWindow()
connect(m_scanner, &MemScanWidget::mustUnhook, this, &MainWindow::onUnhook);
connect(m_watcher, &MemWatchWidget::mustUnhook, this, &MainWindow::onUnhook);

DolphinComm::DolphinAccessor::init();

m_viewer = new MemViewerWidget(this, Common::MEM1_START);
connect(m_viewer, &MemViewerWidget::mustUnhook, this, &MainWindow::onUnhook);
connect(m_watcher,
static_cast<void (MemWatchWidget::*)(u32)>(&MemWatchWidget::goToAddressInViewer), this,
static_cast<void (MainWindow::*)(u32)>(&MainWindow::onOpenMemViewerWithAddress));
m_dlgViewer = new QDialog(this);
QVBoxLayout* layout = new QVBoxLayout;
layout->addWidget(m_viewer);
m_dlgViewer->setLayout(layout);

// First attempt to hook
onHookAttempt();
if (DolphinComm::DolphinAccessor::getStatus() ==
Expand Down Expand Up @@ -126,6 +143,17 @@ void MainWindow::onToggleMem2()
updateMem2Status();
}

void MainWindow::onOpenMenViewer()
{
m_dlgViewer->show();
}

void MainWindow::onOpenMemViewerWithAddress(u32 address)
{
m_viewer->goToAddress(address);
m_dlgViewer->show();
}

void MainWindow::updateMem2Status()
{
if (DolphinComm::DolphinAccessor::isMem2Enabled())
Expand All @@ -145,6 +173,7 @@ void MainWindow::updateDolphinHookingStatus()
QString::number(DolphinComm::DolphinAccessor::getEmuRAMAddressStart(), 16).toUpper());
m_scanner->setEnabled(true);
m_watcher->setEnabled(true);
m_btnOpenMemViewer->setEnabled(true);
m_btnAttempHook->hide();
m_btnUnhook->show();
break;
Expand All @@ -154,6 +183,7 @@ void MainWindow::updateDolphinHookingStatus()
m_lblDolphinStatus->setText("Cannot hook to Dolphin, the process is not running");
m_scanner->setDisabled(true);
m_watcher->setDisabled(true);
m_btnOpenMemViewer->setDisabled(true);
m_btnAttempHook->show();
m_btnUnhook->hide();
break;
Expand All @@ -164,6 +194,7 @@ void MainWindow::updateDolphinHookingStatus()
"Cannot hook to Dolphin, the process is running, but no emulation has been started");
m_scanner->setDisabled(true);
m_watcher->setDisabled(true);
m_btnOpenMemViewer->setDisabled(true);
m_btnAttempHook->show();
m_btnUnhook->hide();
break;
Expand All @@ -173,6 +204,7 @@ void MainWindow::updateDolphinHookingStatus()
m_lblDolphinStatus->setText("Unhooked, press \"Hook\" to hook to Dolphin again");
m_scanner->setDisabled(true);
m_watcher->setDisabled(true);
m_btnOpenMemViewer->setDisabled(true);
m_btnAttempHook->show();
m_btnUnhook->hide();
break;
Expand All @@ -190,6 +222,8 @@ void MainWindow::onHookAttempt()
m_scanner->getUpdateTimer()->start(100);
m_watcher->getUpdateTimer()->start(10);
m_watcher->getFreezeTimer()->start(10);
m_viewer->getUpdateTimer()->start(100);
m_viewer->hookStatusChanged(true);
m_mem2StatusWidget->setEnabled(true);
}
else
Expand All @@ -203,6 +237,8 @@ void MainWindow::onUnhook()
m_scanner->getUpdateTimer()->stop();
m_watcher->getUpdateTimer()->stop();
m_watcher->getFreezeTimer()->stop();
m_viewer->getUpdateTimer()->stop();
m_viewer->hookStatusChanged(false);
m_mem2StatusWidget->setDisabled(true);
DolphinComm::DolphinAccessor::unHook();
updateDolphinHookingStatus();
Expand All @@ -227,7 +263,7 @@ void MainWindow::onSaveAsWatchFile()
void MainWindow::onAbout()
{
QMessageBox::about(this, "About Dolphin memory engine",
"Beta version 0.1.2\n\nA RAM search made to facilitate research and "
"Beta version 0.2\n\nA RAM search made to facilitate research and "
"reverse engineering of GameCube and Wii games using the Dolphin "
"emulator.\n\nThis program is licensed under the MIT license. You "
"should have received a copy of the MIT license along with this program");
Expand Down
6 changes: 6 additions & 0 deletions Source/GUI/MainWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "../Common/CommonTypes.h"
#include "../Common/MemoryCommon.h"
#include "MemScanner/MemScanWidget.h"
#include "MemViewer/MemViewerWidget.h"
#include "MemWatcher/MemWatchWidget.h"

class MainWindow : public QMainWindow
Expand All @@ -24,6 +25,8 @@ class MainWindow : public QMainWindow
void onUnhook();
void onAutoDetectMem2();
void onToggleMem2();
void onOpenMenViewer();
void onOpenMemViewerWithAddress(u32 address);
void updateMem2Status();

void onOpenWatchFile();
Expand All @@ -35,13 +38,16 @@ class MainWindow : public QMainWindow
private:
MemWatchWidget* m_watcher;
MemScanWidget* m_scanner;
MemViewerWidget* m_viewer;

QDialog* m_dlgViewer;
QLabel* m_lblDolphinStatus;
QPushButton* m_btnAttempHook;
QPushButton* m_btnUnhook;
QLabel* m_lblMem2Status;
QPushButton* m_btnToggleMem2;
QPushButton* m_btnMem2AutoDetect;
QPushButton* m_btnOpenMemViewer;
QWidget* m_mem2StatusWidget;

QMenu* m_menuFile;
Expand Down
Loading

0 comments on commit 1402279

Please sign in to comment.