mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-07-11 01:34:17 +02:00
Debugger: Allow strings to be edited from the symbol trees
This commit is contained in:
committed by
lightningterror
parent
6834086c37
commit
1ae2a96747
@@ -34,6 +34,34 @@ Value MemoryInterface::Read(u32 address, bool* valid)
|
||||
return Value(0);
|
||||
}
|
||||
|
||||
std::optional<std::string> MemoryInterface::ReadString(u32 address, u32 max_size, ReadStringFlags flags)
|
||||
{
|
||||
std::string string;
|
||||
|
||||
for (u32 i = 0; i < max_size; i++)
|
||||
{
|
||||
bool valid;
|
||||
char c = Read8(address + i, &valid);
|
||||
if (!valid)
|
||||
return std::nullopt;
|
||||
|
||||
if (c == '\0')
|
||||
return string;
|
||||
else if (!(flags & ALLOW_NON_PRINTABLE_CHARACTERS) && (c < ' ' || c > '~'))
|
||||
return std::nullopt;
|
||||
|
||||
string += c;
|
||||
}
|
||||
|
||||
if (flags & ALLOW_LONG_STRINGS)
|
||||
{
|
||||
string += '~';
|
||||
return string;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template <MemoryAccessType Value>
|
||||
bool MemoryInterface::Write(u32 address, Value value)
|
||||
{
|
||||
@@ -62,6 +90,17 @@ bool MemoryInterface::Write(u32 address, Value value)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MemoryInterface::WriteString(u32 address, std::string_view string)
|
||||
{
|
||||
if (!WriteBytes(address, string.data(), static_cast<u32>(string.size())))
|
||||
return false;
|
||||
|
||||
if (!Write8(address + static_cast<u32>(string.size()), '\0'))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MemoryInterface::IdempotentWrite8(u32 address, u8 value)
|
||||
{
|
||||
bool valid;
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
|
||||
#include "Pcsx2Types.h"
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
template <typename Value>
|
||||
@@ -31,16 +34,27 @@ public:
|
||||
template <MemoryAccessType Value>
|
||||
Value Read(u32 address, bool* valid = nullptr);
|
||||
|
||||
enum ReadStringFlags
|
||||
{
|
||||
NO_FLAGS = 0,
|
||||
ALLOW_LONG_STRINGS = 1 << 0,
|
||||
ALLOW_NON_PRINTABLE_CHARACTERS = 1 << 1
|
||||
};
|
||||
|
||||
std::optional<std::string> ReadString(u32 address, u32 max_size = 256, ReadStringFlags flags = NO_FLAGS);
|
||||
|
||||
virtual bool Write8(u32 address, u8 value) = 0;
|
||||
virtual bool Write16(u32 address, u16 value) = 0;
|
||||
virtual bool Write32(u32 address, u32 value) = 0;
|
||||
virtual bool Write64(u32 address, u64 value) = 0;
|
||||
virtual bool Write128(u32 address, u128 value) = 0;
|
||||
virtual bool WriteBytes(u32 address, void* src, u32 size) = 0;
|
||||
virtual bool WriteBytes(u32 address, const void* src, u32 size) = 0;
|
||||
|
||||
template <MemoryAccessType Value>
|
||||
bool Write(u32 address, Value value);
|
||||
|
||||
bool WriteString(u32 address, std::string_view string);
|
||||
|
||||
bool IdempotentWrite8(u32 address, u8 value);
|
||||
bool IdempotentWrite16(u32 address, u16 value);
|
||||
bool IdempotentWrite32(u32 address, u32 value);
|
||||
@@ -51,5 +65,5 @@ public:
|
||||
template <MemoryAccessType Value>
|
||||
bool IdempotentWrite(u32 address, Value value);
|
||||
|
||||
virtual bool CompareBytes(u32 address, void* src, u32 size) = 0;
|
||||
virtual bool CompareBytes(u32 address, const void* src, u32 size) = 0;
|
||||
};
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include "Debugger/SymbolTree/SymbolTreeModel.h"
|
||||
#include "Debugger/SymbolTree/TypeString.h"
|
||||
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
#include <QtWidgets/QCheckBox>
|
||||
#include <QtWidgets/QComboBox>
|
||||
#include <QtWidgets/QDoubleSpinBox>
|
||||
@@ -44,12 +46,28 @@ QWidget* SymbolTreeValueDelegate::createEditor(QWidget* parent, const QStyleOpti
|
||||
const ccc::ast::Node& physical_type = *logical_type->physical_type(database).first;
|
||||
QVariant value = node->readValueAsVariant(physical_type, m_cpu, database);
|
||||
|
||||
const ccc::ast::Node& type = *logical_type->physical_type(database).first;
|
||||
switch (type.descriptor)
|
||||
switch (physical_type.descriptor)
|
||||
{
|
||||
case ccc::ast::ARRAY:
|
||||
{
|
||||
const ccc::ast::Array& array = physical_type.as<ccc::ast::Array>();
|
||||
const ccc::ast::Node& element_type = *array.element_type->physical_type(database).first;;
|
||||
|
||||
if (array.element_count > 0 &&
|
||||
element_type.name == "char" &&
|
||||
node->location.type == SymbolTreeLocation::MEMORY &&
|
||||
!value.isNull())
|
||||
{
|
||||
QLineEdit* editor = new QLineEdit(parent);
|
||||
editor->setText(value.toString());
|
||||
result = editor;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case ccc::ast::BUILTIN:
|
||||
{
|
||||
const ccc::ast::BuiltIn& builtin = type.as<ccc::ast::BuiltIn>();
|
||||
const ccc::ast::BuiltIn& builtin = physical_type.as<ccc::ast::BuiltIn>();
|
||||
|
||||
switch (builtin.bclass)
|
||||
{
|
||||
@@ -111,7 +129,7 @@ QWidget* SymbolTreeValueDelegate::createEditor(QWidget* parent, const QStyleOpti
|
||||
}
|
||||
case ccc::ast::ENUM:
|
||||
{
|
||||
const ccc::ast::Enum& enumeration = type.as<ccc::ast::Enum>();
|
||||
const ccc::ast::Enum& enumeration = physical_type.as<ccc::ast::Enum>();
|
||||
|
||||
QComboBox* combo_box = new QComboBox(parent);
|
||||
bool named = false;
|
||||
@@ -186,12 +204,30 @@ void SymbolTreeValueDelegate::setModelData(QWidget* editor, QAbstractItemModel*
|
||||
if (!logical_type)
|
||||
return;
|
||||
|
||||
const ccc::ast::Node& type = *logical_type->physical_type(database).first;
|
||||
switch (type.descriptor)
|
||||
const ccc::ast::Node& physical_type = *logical_type->physical_type(database).first;
|
||||
|
||||
switch (physical_type.descriptor)
|
||||
{
|
||||
case ccc::ast::ARRAY:
|
||||
{
|
||||
const ccc::ast::Array& array = physical_type.as<ccc::ast::Array>();
|
||||
const ccc::ast::Node& element_type = *array.element_type->physical_type(database).first;
|
||||
|
||||
QLineEdit* line_edit = qobject_cast<QLineEdit*>(editor);
|
||||
|
||||
if (array.element_count > 0 &&
|
||||
element_type.name == "char" &&
|
||||
node->location.type == SymbolTreeLocation::MEMORY &&
|
||||
line_edit)
|
||||
{
|
||||
value = line_edit->text();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case ccc::ast::BUILTIN:
|
||||
{
|
||||
const ccc::ast::BuiltIn& builtin = type.as<ccc::ast::BuiltIn>();
|
||||
const ccc::ast::BuiltIn& builtin = physical_type.as<ccc::ast::BuiltIn>();
|
||||
|
||||
switch (builtin.bclass)
|
||||
{
|
||||
|
||||
@@ -67,7 +67,7 @@ bool SymbolTreeNode::writeToVM(
|
||||
if (logical_type)
|
||||
{
|
||||
const ccc::ast::Node& physical_type = *logical_type->physical_type(database).first;
|
||||
writeValueFromVariant(m_value, physical_type, cpu);
|
||||
writeValueFromVariant(m_value, physical_type, cpu, database);
|
||||
}
|
||||
|
||||
data_changed |= updateDisplayString(cpu, database, display_options);
|
||||
@@ -76,10 +76,29 @@ bool SymbolTreeNode::writeToVM(
|
||||
return data_changed;
|
||||
}
|
||||
|
||||
QVariant SymbolTreeNode::readValueAsVariant(const ccc::ast::Node& physical_type, DebugInterface& cpu, const ccc::SymbolDatabase& database) const
|
||||
QVariant SymbolTreeNode::readValueAsVariant(
|
||||
const ccc::ast::Node& physical_type,
|
||||
DebugInterface& cpu,
|
||||
const ccc::SymbolDatabase& database) const
|
||||
{
|
||||
switch (physical_type.descriptor)
|
||||
{
|
||||
case ccc::ast::ARRAY:
|
||||
{
|
||||
const ccc::ast::Array& array = physical_type.as<ccc::ast::Array>();
|
||||
const ccc::ast::Node& element_type = *array.element_type->physical_type(database).first;
|
||||
|
||||
if (array.element_count > 0 &&
|
||||
element_type.name == "char" &&
|
||||
location.type == SymbolTreeLocation::MEMORY)
|
||||
{
|
||||
std::optional<std::string> string = cpu.ReadString(location.address, 256);
|
||||
if (string.has_value())
|
||||
return QString::fromStdString(*string);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case ccc::ast::BUILTIN:
|
||||
{
|
||||
const ccc::ast::BuiltIn& builtIn = physical_type.as<ccc::ast::BuiltIn>();
|
||||
@@ -134,10 +153,36 @@ QVariant SymbolTreeNode::readValueAsVariant(const ccc::ast::Node& physical_type,
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool SymbolTreeNode::writeValueFromVariant(QVariant value, const ccc::ast::Node& physical_type, DebugInterface& cpu) const
|
||||
bool SymbolTreeNode::writeValueFromVariant(
|
||||
QVariant value,
|
||||
const ccc::ast::Node& physical_type,
|
||||
DebugInterface& cpu,
|
||||
const ccc::SymbolDatabase& database) const
|
||||
{
|
||||
if (value.isNull())
|
||||
return false;
|
||||
|
||||
switch (physical_type.descriptor)
|
||||
{
|
||||
case ccc::ast::ARRAY:
|
||||
{
|
||||
const ccc::ast::Array& array = physical_type.as<ccc::ast::Array>();
|
||||
const ccc::ast::Node& element_type = *array.element_type->physical_type(database).first;
|
||||
|
||||
if (array.element_count > 0 &&
|
||||
element_type.name == "char" &&
|
||||
location.type == SymbolTreeLocation::MEMORY)
|
||||
{
|
||||
QByteArray byte_array = value.toString().toLatin1();
|
||||
std::string_view view(
|
||||
byte_array.data(),
|
||||
std::min(static_cast<s32>(byte_array.size()), array.element_count - 1));
|
||||
cpu.WriteString(location.address, view);
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
case ccc::ast::BUILTIN:
|
||||
{
|
||||
const ccc::ast::BuiltIn& built_in = physical_type.as<ccc::ast::BuiltIn>();
|
||||
@@ -191,6 +236,7 @@ bool SymbolTreeNode::writeValueFromVariant(QVariant value, const ccc::ast::Node&
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case ccc::ast::ENUM:
|
||||
@@ -266,11 +312,14 @@ QString SymbolTreeNode::generateDisplayString(
|
||||
const ccc::ast::Array& array = physical_type.as<ccc::ast::Array>();
|
||||
const ccc::ast::Node& element_type = *array.element_type->physical_type(database).first;
|
||||
|
||||
if (element_type.name == "char" && location.type == SymbolTreeLocation::MEMORY)
|
||||
if (array.element_count > 0 &&
|
||||
element_type.name == "char" &&
|
||||
location.type == SymbolTreeLocation::MEMORY)
|
||||
{
|
||||
char* string = cpu.stringFromPointer(location.address);
|
||||
if (string)
|
||||
return QString("\"%1\"").arg(string);
|
||||
std::optional<std::string> string = cpu.ReadString(
|
||||
location.address, 256, MemoryInterface::ALLOW_LONG_STRINGS);
|
||||
if (string.has_value())
|
||||
return QString("\"%1\"").arg(*string);
|
||||
}
|
||||
|
||||
QString result;
|
||||
@@ -412,9 +461,10 @@ QString SymbolTreeNode::generateDisplayString(
|
||||
|
||||
if (pointer_or_reference.is_pointer && value_type.name == "char")
|
||||
{
|
||||
const char* string = cpu.stringFromPointer(address);
|
||||
if (string)
|
||||
result += QString(" \"%1\"").arg(string);
|
||||
std::optional<std::string> string = cpu.ReadString(
|
||||
address, 256, MemoryInterface::ALLOW_LONG_STRINGS);
|
||||
if (string.has_value())
|
||||
result += QString(" \"%1\"").arg(*string);
|
||||
}
|
||||
else if (depth == 0)
|
||||
{
|
||||
|
||||
@@ -62,11 +62,20 @@ public:
|
||||
const ccc::SymbolDatabase& database,
|
||||
const SymbolTreeDisplayOptions& display_options);
|
||||
|
||||
QVariant readValueAsVariant(const ccc::ast::Node& physical_type, DebugInterface& cpu, const ccc::SymbolDatabase& database) const;
|
||||
bool writeValueFromVariant(QVariant value, const ccc::ast::Node& physical_type, DebugInterface& cpu) const;
|
||||
QVariant readValueAsVariant(
|
||||
const ccc::ast::Node& physical_type,
|
||||
DebugInterface& cpu,
|
||||
const ccc::SymbolDatabase& database) const;
|
||||
|
||||
bool writeValueFromVariant(
|
||||
QVariant value,
|
||||
const ccc::ast::Node& physical_type,
|
||||
DebugInterface& cpu,
|
||||
const ccc::SymbolDatabase& database) const;
|
||||
|
||||
bool updateDisplayString(
|
||||
DebugInterface& cpu, const ccc::SymbolDatabase& database, const SymbolTreeDisplayOptions& display);
|
||||
|
||||
QString generateDisplayString(
|
||||
const ccc::ast::Node& physical_type,
|
||||
DebugInterface& cpu,
|
||||
|
||||
@@ -63,37 +63,6 @@ void DebugInterface::resumeCpu()
|
||||
VMManager::SetPaused(false);
|
||||
}
|
||||
|
||||
char* DebugInterface::stringFromPointer(u32 p)
|
||||
{
|
||||
const int BUFFER_LEN = 64;
|
||||
static char buf[BUFFER_LEN] = {0};
|
||||
|
||||
if (!isValidAddress(p))
|
||||
return NULL;
|
||||
|
||||
// This is going to blow up if it hits a TLB miss..
|
||||
// Hopefully the checks in isValidAddress() are sufficient.
|
||||
for (u32 i = 0; i < BUFFER_LEN; i++)
|
||||
{
|
||||
char c = Read8(p + i);
|
||||
buf[i] = c;
|
||||
|
||||
if (c == 0)
|
||||
{
|
||||
return i > 0 ? buf : NULL;
|
||||
}
|
||||
else if (c < 0x20 || c >= 0x7f)
|
||||
{
|
||||
// non printable character
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
buf[BUFFER_LEN - 1] = 0;
|
||||
buf[BUFFER_LEN - 2] = '~';
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::optional<u32> DebugInterface::getCallerStackPointer(const ccc::Function& currentFunction)
|
||||
{
|
||||
u32 sp = getRegister(EECAT_GPR, 29);
|
||||
@@ -336,12 +305,12 @@ bool R5900DebugInterface::Write128(u32 address, u128 value)
|
||||
return isValidAddress(address) && vtlb_memSafeWriteBytes(address, &value, sizeof(value));
|
||||
}
|
||||
|
||||
bool R5900DebugInterface::WriteBytes(u32 address, void* src, u32 size)
|
||||
bool R5900DebugInterface::WriteBytes(u32 address, const void* src, u32 size)
|
||||
{
|
||||
return vtlb_memSafeWriteBytes(address, src, size);
|
||||
}
|
||||
|
||||
bool R5900DebugInterface::CompareBytes(u32 address, void* src, u32 size)
|
||||
bool R5900DebugInterface::CompareBytes(u32 address, const void* src, u32 size)
|
||||
{
|
||||
return vtlb_memSafeCmpBytes(address, src, size) == 0;
|
||||
}
|
||||
@@ -839,12 +808,12 @@ bool R3000DebugInterface::Write128(u32 address, u128 value)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool R3000DebugInterface::WriteBytes(u32 address, void* src, u32 size)
|
||||
bool R3000DebugInterface::WriteBytes(u32 address, const void* src, u32 size)
|
||||
{
|
||||
return iopMemSafeWriteBytes(address, src, size);
|
||||
}
|
||||
|
||||
bool R3000DebugInterface::CompareBytes(u32 address, void* src, u32 size)
|
||||
bool R3000DebugInterface::CompareBytes(u32 address, const void* src, u32 size)
|
||||
{
|
||||
return iopMemSafeCmpBytes(address, src, size) == 0;
|
||||
}
|
||||
@@ -1185,12 +1154,12 @@ bool ElfMemoryReader::Write128(u32 address, u128 value)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ElfMemoryReader::WriteBytes(u32 address, void* src, u32 size)
|
||||
bool ElfMemoryReader::WriteBytes(u32 address, const void* src, u32 size)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ElfMemoryReader::CompareBytes(u32 address, void* src, u32 size)
|
||||
bool ElfMemoryReader::CompareBytes(u32 address, const void* src, u32 size)
|
||||
{
|
||||
std::optional<std::span<const u8>> bytes = m_elf.get_virtual(address, size);
|
||||
if (!bytes.has_value())
|
||||
|
||||
@@ -80,7 +80,6 @@ public:
|
||||
bool isCpuPaused();
|
||||
void pauseCpu();
|
||||
void resumeCpu();
|
||||
char* stringFromPointer(u32 p);
|
||||
|
||||
std::optional<u32> getCallerStackPointer(const ccc::Function& currentFunction);
|
||||
std::optional<u32> getStackFrameSize(const ccc::Function& currentFunction);
|
||||
@@ -115,9 +114,9 @@ public:
|
||||
bool Write32(u32 address, u32 value) override;
|
||||
bool Write64(u32 address, u64 value) override;
|
||||
bool Write128(u32 address, u128 value) override;
|
||||
bool WriteBytes(u32 address, void* src, u32 size) override;
|
||||
bool WriteBytes(u32 address, const void* src, u32 size) override;
|
||||
|
||||
bool CompareBytes(u32 address, void* src, u32 size) override;
|
||||
bool CompareBytes(u32 address, const void* src, u32 size) override;
|
||||
|
||||
// register stuff
|
||||
int getRegisterCategoryCount() override;
|
||||
@@ -161,9 +160,9 @@ public:
|
||||
bool Write32(u32 address, u32 value) override;
|
||||
bool Write64(u32 address, u64 value) override;
|
||||
bool Write128(u32 address, u128 value) override;
|
||||
bool WriteBytes(u32 address, void* src, u32 size) override;
|
||||
bool WriteBytes(u32 address, const void* src, u32 size) override;
|
||||
|
||||
bool CompareBytes(u32 address, void* src, u32 size) override;
|
||||
bool CompareBytes(u32 address, const void* src, u32 size) override;
|
||||
|
||||
// register stuff
|
||||
int getRegisterCategoryCount() override;
|
||||
@@ -210,9 +209,9 @@ public:
|
||||
bool Write32(u32 address, u32 value) override;
|
||||
bool Write64(u32 address, u64 value) override;
|
||||
bool Write128(u32 address, u128 value) override;
|
||||
bool WriteBytes(u32 address, void* src, u32 size) override;
|
||||
bool WriteBytes(u32 address, const void* src, u32 size) override;
|
||||
|
||||
bool CompareBytes(u32 address, void* src, u32 size) override;
|
||||
bool CompareBytes(u32 address, const void* src, u32 size) override;
|
||||
|
||||
protected:
|
||||
const ccc::ElfFile& m_elf;
|
||||
|
||||
+2
-2
@@ -607,12 +607,12 @@ bool IOPMemoryInterface::Write128(u32 address, u128 value)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IOPMemoryInterface::WriteBytes(u32 address, void* src, u32 size)
|
||||
bool IOPMemoryInterface::WriteBytes(u32 address, const void* src, u32 size)
|
||||
{
|
||||
return iopMemSafeWriteBytes(address, src, size);
|
||||
}
|
||||
|
||||
bool IOPMemoryInterface::CompareBytes(u32 address, void* src, u32 size)
|
||||
bool IOPMemoryInterface::CompareBytes(u32 address, const void* src, u32 size)
|
||||
{
|
||||
return iopMemSafeCmpBytes(address, src, size) == 0;
|
||||
}
|
||||
|
||||
+2
-2
@@ -136,7 +136,7 @@ public:
|
||||
bool Write32(u32 address, u32 value) override;
|
||||
bool Write64(u32 address, u64 value) override;
|
||||
bool Write128(u32 address, u128 value) override;
|
||||
bool WriteBytes(u32 address, void* src, u32 size) override;
|
||||
bool WriteBytes(u32 address, const void* src, u32 size) override;
|
||||
|
||||
bool CompareBytes(u32 address, void* src, u32 size) override;
|
||||
bool CompareBytes(u32 address, const void* src, u32 size) override;
|
||||
};
|
||||
|
||||
+2
-2
@@ -1257,12 +1257,12 @@ bool EEMemoryInterface::Write128(u32 address, u128 value)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EEMemoryInterface::WriteBytes(u32 address, void* src, u32 size)
|
||||
bool EEMemoryInterface::WriteBytes(u32 address, const void* src, u32 size)
|
||||
{
|
||||
return vtlb_memSafeWriteBytes(address, src, size);
|
||||
}
|
||||
|
||||
bool EEMemoryInterface::CompareBytes(u32 address, void* src, u32 size)
|
||||
bool EEMemoryInterface::CompareBytes(u32 address, const void* src, u32 size)
|
||||
{
|
||||
return vtlb_memSafeCmpBytes(address, src, size) == 0;
|
||||
}
|
||||
|
||||
+2
-2
@@ -206,7 +206,7 @@ public:
|
||||
bool Write32(u32 address, u32 value) override;
|
||||
bool Write64(u32 address, u64 value) override;
|
||||
bool Write128(u32 address, u128 value) override;
|
||||
bool WriteBytes(u32 address, void* src, u32 size) override;
|
||||
bool WriteBytes(u32 address, const void* src, u32 size) override;
|
||||
|
||||
bool CompareBytes(u32 address, void* src, u32 size) override;
|
||||
bool CompareBytes(u32 address, const void* src, u32 size) override;
|
||||
};
|
||||
|
||||
@@ -21,9 +21,9 @@ public:
|
||||
MOCK_METHOD(bool, Write32, (u32 address, u32 value), (override));
|
||||
MOCK_METHOD(bool, Write64, (u32 address, u64 value), (override));
|
||||
MOCK_METHOD(bool, Write128, (u32 address, u128 value), (override));
|
||||
MOCK_METHOD(bool, WriteBytes, (u32 address, void* src, u32 size), (override));
|
||||
MOCK_METHOD(bool, WriteBytes, (u32 address, const void* src, u32 size), (override));
|
||||
|
||||
MOCK_METHOD(bool, CompareBytes, (u32 address, void* src, u32 size), (override));
|
||||
MOCK_METHOD(bool, CompareBytes, (u32 address, const void* src, u32 size), (override));
|
||||
|
||||
struct SetValidOutParameterAction
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user