diff --git a/CMakeLists.txt b/CMakeLists.txt
index d43cb98324..8d4157062c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1482,6 +1482,8 @@ add_library(${CoreLibName} ${CoreLinkType}
Core/Debugger/WebSocket/HLESubscriber.h
Core/Debugger/WebSocket/LogBroadcaster.cpp
Core/Debugger/WebSocket/LogBroadcaster.h
+ Core/Debugger/WebSocket/MemorySubscriber.cpp
+ Core/Debugger/WebSocket/MemorySubscriber.h
Core/Debugger/WebSocket/SteppingBroadcaster.cpp
Core/Debugger/WebSocket/SteppingBroadcaster.h
Core/Debugger/WebSocket/SteppingSubscriber.cpp
diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index 91f0fd5830..baf1d89505 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -378,6 +378,7 @@
+
@@ -909,6 +910,7 @@
+
diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters
index f3e5bea144..a5460b6d4f 100644
--- a/Core/Core.vcxproj.filters
+++ b/Core/Core.vcxproj.filters
@@ -713,6 +713,9 @@
Debugger\WebSocket
+
+ Debugger\WebSocket
+
Debugger\WebSocket
@@ -1352,6 +1355,9 @@
Debugger\WebSocket
+
+ Debugger\WebSocket
+
Debugger\WebSocket
diff --git a/Core/Debugger/WebSocket.cpp b/Core/Debugger/WebSocket.cpp
index 6175279363..62d1879cda 100644
--- a/Core/Debugger/WebSocket.cpp
+++ b/Core/Debugger/WebSocket.cpp
@@ -55,6 +55,7 @@
#include "Core/Debugger/WebSocket/GPUBufferSubscriber.h"
#include "Core/Debugger/WebSocket/GPURecordSubscriber.h"
#include "Core/Debugger/WebSocket/HLESubscriber.h"
+#include "Core/Debugger/WebSocket/MemorySubscriber.h"
#include "Core/Debugger/WebSocket/SteppingSubscriber.h"
typedef DebuggerSubscriber *(*SubscriberInit)(DebuggerEventHandlerMap &map);
@@ -66,6 +67,7 @@ static const std::vector subscribers({
&WebSocketGPUBufferInit,
&WebSocketGPURecordInit,
&WebSocketHLEInit,
+ &WebSocketMemoryInit,
&WebSocketSteppingInit,
});
diff --git a/Core/Debugger/WebSocket/MemorySubscriber.cpp b/Core/Debugger/WebSocket/MemorySubscriber.cpp
new file mode 100644
index 0000000000..6710b7492c
--- /dev/null
+++ b/Core/Debugger/WebSocket/MemorySubscriber.cpp
@@ -0,0 +1,205 @@
+// Copyright (c) 2018- PPSSPP Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0 or later versions.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+
+#include "Common/StringUtils.h"
+#include "Core/MemMap.h"
+#include "Core/System.h"
+#include "Core/Debugger/WebSocket/MemorySubscriber.h"
+#include "Core/Debugger/WebSocket/WebSocketUtils.h"
+
+DebuggerSubscriber *WebSocketMemoryInit(DebuggerEventHandlerMap &map) {
+ // No need to bind or alloc state, these are all global.
+ map["memory.read_u8"] = &WebSocketMemoryReadU8;
+ map["memory.read_u16"] = &WebSocketMemoryReadU16;
+ map["memory.read_u32"] = &WebSocketMemoryReadU32;
+ map["memory.write_u8"] = &WebSocketMemoryWriteU8;
+ map["memory.write_u16"] = &WebSocketMemoryWriteU16;
+ map["memory.write_u32"] = &WebSocketMemoryWriteU32;
+
+ return nullptr;
+}
+
+// Read a byte from memory (memory.read_u8)
+//
+// Parameters:
+// - address: unsigned integer
+//
+// Response (same event name):
+// - value: unsigned integer
+void WebSocketMemoryReadU8(DebuggerRequest &req) {
+ auto memLock = Memory::Lock();
+ uint32_t addr;
+
+ if (!req.ParamU32("address", &addr, false)) {
+ req.Fail("No address given");
+ return;
+ }
+
+ if (!Memory::IsValidAddress(addr)) {
+ req.Fail("Invalid address");
+ return;
+ }
+
+ JsonWriter &json = req.Respond();
+ json.writeUint("value", Memory::Read_U8(addr));
+}
+
+// Read two bytes from memory (memory.read_u16)
+//
+// Parameters:
+// - address: unsigned integer
+//
+// Response (same event name):
+// - value: unsigned integer
+void WebSocketMemoryReadU16(DebuggerRequest &req) {
+ auto memLock = Memory::Lock();
+ uint32_t addr;
+
+ if (!req.ParamU32("address", &addr, false)) {
+ req.Fail("No address given");
+ return;
+ }
+
+ if (!Memory::IsValidAddress(addr)) {
+ req.Fail("Invalid address");
+ return;
+ }
+
+ JsonWriter &json = req.Respond();
+ json.writeUint("value", Memory::Read_U16(addr));
+}
+
+// Read four bytes from memory (memory.read_u32)
+//
+// Parameters:
+// - address: unsigned integer
+//
+// Response (same event name):
+// - value: unsigned integer
+void WebSocketMemoryReadU32(DebuggerRequest &req) {
+ auto memLock = Memory::Lock();
+ uint32_t addr;
+
+ if (!req.ParamU32("address", &addr, false)) {
+ req.Fail("No address given");
+ return;
+ }
+
+ if (!Memory::IsValidAddress(addr)) {
+ req.Fail("Invalid address");
+ return;
+ }
+
+ JsonWriter &json = req.Respond();
+ json.writeUint("value", Memory::Read_U32(addr));
+}
+
+// Write a byte to memory (memory.write_u8)
+//
+// Parameters:
+// - address: unsigned integer
+// - value: unsigned integer
+//
+// Response (same event name):
+// - value: new value, unsigned integer
+void WebSocketMemoryWriteU8(DebuggerRequest &req) {
+ auto memLock = Memory::Lock();
+ uint32_t addr, val;
+
+ if (!req.ParamU32("address", &addr, false)) {
+ req.Fail("No address given");
+ return;
+ }
+
+ if (!req.ParamU32("value", &val, false)) {
+ req.Fail("No value given");
+ return;
+ }
+
+ if (!Memory::IsValidAddress(addr)) {
+ req.Fail("Invalid address");
+ return;
+ }
+ Memory::Write_U8(val, addr);
+
+ JsonWriter &json = req.Respond();
+ json.writeUint("value", Memory::Read_U8(addr));
+}
+
+// Write two bytes to memory (memory.write_u16)
+//
+// Parameters:
+// - address: unsigned integer
+// - value: unsigned integer
+//
+// Response (same event name):
+// - value: new value, unsigned integer
+void WebSocketMemoryWriteU16(DebuggerRequest &req) {
+ auto memLock = Memory::Lock();
+ uint32_t addr, val;
+
+ if (!req.ParamU32("address", &addr, false)) {
+ req.Fail("No address given");
+ return;
+ }
+
+ if (!req.ParamU32("value", &val, false)) {
+ req.Fail("No value given");
+ return;
+ }
+
+ if (!Memory::IsValidAddress(addr)) {
+ req.Fail("Invalid address");
+ return;
+ }
+ Memory::Write_U16(val, addr);
+
+ JsonWriter &json = req.Respond();
+ json.writeUint("value", Memory::Read_U16(addr));
+}
+
+// Write four bytes to memory (memory.write_u32)
+//
+// Parameters:
+// - address: unsigned integer
+// - value: unsigned integer
+//
+// Response (same event name):
+// - value: new value, unsigned integer
+void WebSocketMemoryWriteU32(DebuggerRequest &req) {
+ auto memLock = Memory::Lock();
+ uint32_t addr, val;
+
+ if (!req.ParamU32("address", &addr, false)) {
+ req.Fail("No address given");
+ return;
+ }
+
+ if (!req.ParamU32("value", &val, false)) {
+ req.Fail("No value given");
+ return;
+ }
+
+ if (!Memory::IsValidAddress(addr)) {
+ req.Fail("Invalid address");
+ return;
+ }
+ Memory::Write_U32(val, addr);
+
+ JsonWriter &json = req.Respond();
+ json.writeUint("value", Memory::Read_U32(addr));
+}
diff --git a/Core/Debugger/WebSocket/MemorySubscriber.h b/Core/Debugger/WebSocket/MemorySubscriber.h
new file mode 100644
index 0000000000..32e8e898c0
--- /dev/null
+++ b/Core/Debugger/WebSocket/MemorySubscriber.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2018- PPSSPP Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0 or later versions.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+
+#pragma once
+
+#include "Core/Debugger/WebSocket/WebSocketUtils.h"
+
+DebuggerSubscriber *WebSocketMemoryInit(DebuggerEventHandlerMap &map);
+
+void WebSocketMemoryReadU8(DebuggerRequest &req);
+void WebSocketMemoryReadU16(DebuggerRequest &req);
+void WebSocketMemoryReadU32(DebuggerRequest &req);
+void WebSocketMemoryWriteU8(DebuggerRequest &req);
+void WebSocketMemoryWriteU16(DebuggerRequest &req);
+void WebSocketMemoryWriteU32(DebuggerRequest &req);
diff --git a/UWP/CoreUWP/CoreUWP.vcxproj b/UWP/CoreUWP/CoreUWP.vcxproj
index 8d706d5566..4f9545c490 100644
--- a/UWP/CoreUWP/CoreUWP.vcxproj
+++ b/UWP/CoreUWP/CoreUWP.vcxproj
@@ -400,6 +400,7 @@
+
@@ -618,6 +619,7 @@
+
diff --git a/UWP/CoreUWP/CoreUWP.vcxproj.filters b/UWP/CoreUWP/CoreUWP.vcxproj.filters
index b4eaac21a4..781833645f 100644
--- a/UWP/CoreUWP/CoreUWP.vcxproj.filters
+++ b/UWP/CoreUWP/CoreUWP.vcxproj.filters
@@ -666,6 +666,9 @@
Debugger\WebSocket
+
+ Debugger\WebSocket
+
Debugger\WebSocket
@@ -1289,6 +1292,9 @@
Debugger\WebSocket
+
+ Debugger\WebSocket
+
Debugger\WebSocket
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
index f8651f3146..510c6a0a1d 100644
--- a/android/jni/Android.mk
+++ b/android/jni/Android.mk
@@ -324,6 +324,7 @@ EXEC_AND_LIB_FILES := \
$(SRC)/Core/Debugger/WebSocket/GPURecordSubscriber.cpp \
$(SRC)/Core/Debugger/WebSocket/HLESubscriber.cpp \
$(SRC)/Core/Debugger/WebSocket/LogBroadcaster.cpp \
+ $(SRC)/Core/Debugger/WebSocket/MemorySubscriber.cpp \
$(SRC)/Core/Debugger/WebSocket/SteppingBroadcaster.cpp \
$(SRC)/Core/Debugger/WebSocket/SteppingSubscriber.cpp \
$(SRC)/Core/Debugger/WebSocket/WebSocketUtils.cpp \