Files
dolphin/Source/Core/Core/Debugger/OSThread.cpp
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

209 lines
5.9 KiB
C++

// Copyright 2020 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "Core/Debugger/OSThread.h"
#include <algorithm>
#include <fmt/format.h>
#include "Core/PowerPC/MMU.h"
namespace Core::Debug
{
// Context offsets based on the following functions:
// - OSSaveContext
// - OSSaveFPUContext
// - OSDumpContext
// - OSClearContext
// - OSExceptionVector
void OSContext::Read(const Core::CPUThreadGuard& guard, u32 addr)
{
for (std::size_t i = 0; i < gpr.size(); i++)
gpr[i] = PowerPC::HostRead_U32(guard, addr + u32(i * sizeof(int)));
cr = PowerPC::HostRead_U32(guard, addr + 0x80);
lr = PowerPC::HostRead_U32(guard, addr + 0x84);
ctr = PowerPC::HostRead_U32(guard, addr + 0x88);
xer = PowerPC::HostRead_U32(guard, addr + 0x8C);
for (std::size_t i = 0; i < fpr.size(); i++)
fpr[i] = PowerPC::HostRead_F64(guard, addr + 0x90 + u32(i * sizeof(double)));
fpscr = PowerPC::HostRead_U64(guard, addr + 0x190);
srr0 = PowerPC::HostRead_U32(guard, addr + 0x198);
srr1 = PowerPC::HostRead_U32(guard, addr + 0x19c);
dummy = PowerPC::HostRead_U16(guard, addr + 0x1a0);
state = static_cast<OSContext::State>(PowerPC::HostRead_U16(guard, addr + 0x1a2));
for (std::size_t i = 0; i < gqr.size(); i++)
gqr[i] = PowerPC::HostRead_U32(guard, addr + 0x1a4 + u32(i * sizeof(int)));
psf_padding = 0;
for (std::size_t i = 0; i < psf.size(); i++)
psf[i] = PowerPC::HostRead_F64(guard, addr + 0x1c8 + u32(i * sizeof(double)));
}
// Mutex offsets based on the following functions:
// - OSInitMutex
// - OSLockMutex
// - __OSUnlockAllMutex
void OSMutex::Read(const Core::CPUThreadGuard& guard, u32 addr)
{
thread_queue.head = PowerPC::HostRead_U32(guard, addr);
thread_queue.tail = PowerPC::HostRead_U32(guard, addr + 0x4);
owner_addr = PowerPC::HostRead_U32(guard, addr + 0x8);
lock_count = PowerPC::HostRead_U32(guard, addr + 0xc);
link.next = PowerPC::HostRead_U32(guard, addr + 0x10);
link.prev = PowerPC::HostRead_U32(guard, addr + 0x14);
}
// Thread offsets based on the following functions:
// - OSCreateThread
// - OSIsThreadTerminated
// - OSJoinThread
// - OSSuspendThread
// - OSSetPriority
// - OSExitThread
// - OSLockMutex
// - __OSUnlockAllMutex
// - __OSThreadInit
// - OSSetThreadSpecific
// - SOInit (for errno)
void OSThread::Read(const Core::CPUThreadGuard& guard, u32 addr)
{
context.Read(guard, addr);
state = PowerPC::HostRead_U16(guard, addr + 0x2c8);
is_detached = PowerPC::HostRead_U16(guard, addr + 0x2ca);
suspend = PowerPC::HostRead_U32(guard, addr + 0x2cc);
effective_priority = PowerPC::HostRead_U32(guard, addr + 0x2d0);
base_priority = PowerPC::HostRead_U32(guard, addr + 0x2d4);
exit_code_addr = PowerPC::HostRead_U32(guard, addr + 0x2d8);
queue_addr = PowerPC::HostRead_U32(guard, addr + 0x2dc);
queue_link.next = PowerPC::HostRead_U32(guard, addr + 0x2e0);
queue_link.prev = PowerPC::HostRead_U32(guard, addr + 0x2e4);
join_queue.head = PowerPC::HostRead_U32(guard, addr + 0x2e8);
join_queue.tail = PowerPC::HostRead_U32(guard, addr + 0x2ec);
mutex_addr = PowerPC::HostRead_U32(guard, addr + 0x2f0);
mutex_queue.head = PowerPC::HostRead_U32(guard, addr + 0x2f4);
mutex_queue.tail = PowerPC::HostRead_U32(guard, addr + 0x2f8);
thread_link.next = PowerPC::HostRead_U32(guard, addr + 0x2fc);
thread_link.prev = PowerPC::HostRead_U32(guard, addr + 0x300);
stack_addr = PowerPC::HostRead_U32(guard, addr + 0x304);
stack_end = PowerPC::HostRead_U32(guard, addr + 0x308);
error = PowerPC::HostRead_U32(guard, addr + 0x30c);
specific[0] = PowerPC::HostRead_U32(guard, addr + 0x310);
specific[1] = PowerPC::HostRead_U32(guard, addr + 0x314);
}
bool OSThread::IsValid(const Core::CPUThreadGuard& guard) const
{
return PowerPC::HostIsRAMAddress(guard, stack_end) &&
PowerPC::HostRead_U32(guard, stack_end) == STACK_MAGIC;
}
OSThreadView::OSThreadView(const Core::CPUThreadGuard& guard, u32 addr)
{
m_address = addr;
m_thread.Read(guard, addr);
}
const OSThread& OSThreadView::Data() const
{
return m_thread;
}
Common::Debug::PartialContext OSThreadView::GetContext(const Core::CPUThreadGuard& guard) const
{
Common::Debug::PartialContext context;
if (!IsValid(guard))
return context;
context.gpr = m_thread.context.gpr;
context.cr = m_thread.context.cr;
context.lr = m_thread.context.lr;
context.ctr = m_thread.context.ctr;
context.xer = m_thread.context.xer;
context.fpr = m_thread.context.fpr;
context.fpscr = m_thread.context.fpscr;
context.srr0 = m_thread.context.srr0;
context.srr1 = m_thread.context.srr1;
context.dummy = m_thread.context.dummy;
context.state = static_cast<u16>(m_thread.context.state);
context.gqr = m_thread.context.gqr;
context.psf = m_thread.context.psf;
return context;
}
u32 OSThreadView::GetAddress() const
{
return m_address;
}
u16 OSThreadView::GetState() const
{
return m_thread.state;
}
bool OSThreadView::IsSuspended() const
{
return m_thread.suspend > 0;
}
bool OSThreadView::IsDetached() const
{
return m_thread.is_detached != 0;
}
s32 OSThreadView::GetBasePriority() const
{
return m_thread.base_priority;
}
s32 OSThreadView::GetEffectivePriority() const
{
return m_thread.effective_priority;
}
u32 OSThreadView::GetStackStart() const
{
return m_thread.stack_addr;
}
u32 OSThreadView::GetStackEnd() const
{
return m_thread.stack_end;
}
std::size_t OSThreadView::GetStackSize() const
{
return GetStackStart() - GetStackEnd();
}
s32 OSThreadView::GetErrno() const
{
return m_thread.error;
}
std::string OSThreadView::GetSpecific(const Core::CPUThreadGuard& guard) const
{
std::string specific;
for (u32 addr : m_thread.specific)
{
if (!PowerPC::HostIsRAMAddress(guard, addr))
break;
specific += fmt::format("{:08x} \"{}\"\n", addr, PowerPC::HostGetString(guard, addr));
}
return specific;
}
bool OSThreadView::IsValid(const Core::CPUThreadGuard& guard) const
{
return m_thread.IsValid(guard);
}
} // namespace Core::Debug