dolphin/Source/Core/Common/DebugInterface.h
JosJuice 7cecb28bdf DolphinQt: Properly lock CPU before accessing emulated memory
This fixes a problem I was having where using frame advance with the
debugger open would frequently cause panic alerts about invalid addresses
due to the CPU thread changing MSR.DR while the host thread was trying
to access memory.

To aid in tracking down all the places where we weren't properly locking
the CPU, I've created a new type (in Core.h) that you have to pass as a
reference or pointer to functions that require running as the CPU thread.
2023-02-12 11:27:50 +01:00

115 lines
4.4 KiB
C++

// Copyright 2008 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <cstddef>
#include <string>
#include <vector>
#include "Common/CommonTypes.h"
#include "Common/Debug/Threads.h"
namespace Common::Debug
{
struct MemoryPatch;
struct Watch;
} // namespace Common::Debug
namespace Core
{
class CPUThreadGuard;
} // namespace Core
namespace Common
{
class DebugInterface
{
protected:
virtual ~DebugInterface() = default;
public:
// Watches
virtual std::size_t SetWatch(u32 address, std::string name = "") = 0;
virtual const Debug::Watch& GetWatch(std::size_t index) const = 0;
virtual const std::vector<Debug::Watch>& GetWatches() const = 0;
virtual void UnsetWatch(u32 address) = 0;
virtual void UpdateWatch(std::size_t index, u32 address, std::string name) = 0;
virtual void UpdateWatchAddress(std::size_t index, u32 address) = 0;
virtual void UpdateWatchName(std::size_t index, std::string name) = 0;
virtual void UpdateWatchLockedState(std::size_t index, bool locked) = 0;
virtual void EnableWatch(std::size_t index) = 0;
virtual void DisableWatch(std::size_t index) = 0;
virtual bool HasEnabledWatch(u32 address) const = 0;
virtual void RemoveWatch(std::size_t index) = 0;
virtual void LoadWatchesFromStrings(const std::vector<std::string>& watches) = 0;
virtual std::vector<std::string> SaveWatchesToStrings() const = 0;
virtual void ClearWatches() = 0;
// Memory Patches
virtual void SetPatch(const Core::CPUThreadGuard& guard, u32 address, u32 value) = 0;
virtual void SetPatch(const Core::CPUThreadGuard& guard, u32 address, std::vector<u8> value) = 0;
virtual void SetFramePatch(const Core::CPUThreadGuard& guard, u32 address, u32 value) = 0;
virtual void SetFramePatch(const Core::CPUThreadGuard& guard, u32 address,
std::vector<u8> value) = 0;
virtual const std::vector<Debug::MemoryPatch>& GetPatches() const = 0;
virtual void UnsetPatch(const Core::CPUThreadGuard& guard, u32 address) = 0;
virtual void EnablePatch(const Core::CPUThreadGuard& guard, std::size_t index) = 0;
virtual void DisablePatch(const Core::CPUThreadGuard& guard, std::size_t index) = 0;
virtual bool HasEnabledPatch(u32 address) const = 0;
virtual void RemovePatch(const Core::CPUThreadGuard& guard, std::size_t index) = 0;
virtual void ClearPatches(const Core::CPUThreadGuard& guard) = 0;
virtual void ApplyExistingPatch(const Core::CPUThreadGuard& guard, std::size_t index) = 0;
// Threads
virtual Debug::Threads GetThreads(const Core::CPUThreadGuard& guard) const = 0;
virtual std::string Disassemble(const Core::CPUThreadGuard* /*guard*/, u32 /*address*/) const
{
return "NODEBUGGER";
}
virtual std::string GetRawMemoryString(const Core::CPUThreadGuard& /*guard*/, int /*memory*/,
u32 /*address*/) const
{
return "NODEBUGGER";
}
virtual bool IsAlive() const { return true; }
virtual bool IsBreakpoint(u32 /*address*/) const { return false; }
virtual void SetBreakpoint(u32 /*address*/) {}
virtual void ClearBreakpoint(u32 /*address*/) {}
virtual void ClearAllBreakpoints() {}
virtual void ToggleBreakpoint(u32 /*address*/) {}
virtual void ClearAllMemChecks() {}
virtual bool IsMemCheck(u32 /*address*/, size_t /*size*/) const { return false; }
virtual void ToggleMemCheck(u32 /*address*/, bool /*read*/, bool /*write*/, bool /*log*/) {}
virtual u32 ReadMemory(const Core::CPUThreadGuard& /*guard*/, u32 /*address*/) const { return 0; }
virtual void WriteExtraMemory(const Core::CPUThreadGuard& /*guard*/, int /*memory*/,
u32 /*value*/, u32 /*address*/)
{
}
virtual u32 ReadExtraMemory(const Core::CPUThreadGuard& /*guard*/, int /*memory*/,
u32 /*address*/) const
{
return 0;
}
virtual u32 ReadInstruction(const Core::CPUThreadGuard& /*guard*/, u32 /*address*/) const
{
return 0;
}
virtual std::optional<u32>
GetMemoryAddressFromInstruction(const std::string& /*instruction*/) const
{
return std::nullopt;
}
virtual u32 GetPC() const { return 0; }
virtual void SetPC(u32 /*address*/) {}
virtual void Step() {}
virtual void RunToBreakpoint() {}
virtual u32 GetColor(const Core::CPUThreadGuard* /*guard*/, u32 /*address*/) const
{
return 0xFFFFFFFF;
}
virtual std::string GetDescription(u32 /*address*/) const = 0;
virtual void Clear(const Core::CPUThreadGuard& guard) = 0;
};
} // namespace Common