Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #8686 from sepalani/thread-tab
Debugger: Add a Thread widget
  • Loading branch information
leoetlino committed May 3, 2020
2 parents 947d673 + 39d34e1 commit c53ecdd
Show file tree
Hide file tree
Showing 24 changed files with 1,090 additions and 12 deletions.
3 changes: 3 additions & 0 deletions Source/Core/Common/CMakeLists.txt
Expand Up @@ -35,6 +35,9 @@ add_library(common
Crypto/ec.h
Debug/MemoryPatches.cpp
Debug/MemoryPatches.h
Debug/OSThread.cpp
Debug/OSThread.h
Debug/Threads.h
Debug/Watches.cpp
Debug/Watches.h
DebugInterface.h
Expand Down
5 changes: 4 additions & 1 deletion Source/Core/Common/Common.vcxproj
Expand Up @@ -76,6 +76,8 @@
<ClInclude Include="CPUDetect.h" />
<ClInclude Include="DebugInterface.h" />
<ClInclude Include="Debug\MemoryPatches.h" />
<ClInclude Include="Debug\OSThread.h" />
<ClInclude Include="Debug\Threads.h" />
<ClInclude Include="Debug\Watches.h" />
<ClInclude Include="DynamicLibrary.h" />
<ClInclude Include="ENetUtil.h" />
Expand Down Expand Up @@ -217,6 +219,7 @@
<ClCompile Include="Config\ConfigInfo.cpp" />
<ClCompile Include="Config\Layer.cpp" />
<ClCompile Include="Debug\MemoryPatches.cpp" />
<ClCompile Include="Debug\OSThread.cpp" />
<ClCompile Include="Debug\Watches.cpp" />
<ClCompile Include="DynamicLibrary.cpp" />
<ClCompile Include="ENetUtil.cpp" />
Expand Down Expand Up @@ -310,4 +313,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
9 changes: 9 additions & 0 deletions Source/Core/Common/Common.vcxproj.filters
Expand Up @@ -274,6 +274,12 @@
<ClInclude Include="Debug\MemoryPatches.h">
<Filter>Debug</Filter>
</ClInclude>
<ClInclude Include="Debug\OSThread.h">
<Filter>Debug</Filter>
</ClInclude>
<ClInclude Include="Debug\Threads.h">
<Filter>Debug</Filter>
</ClInclude>
<ClInclude Include="GL\GLContext.h">
<Filter>GL\GLInterface</Filter>
</ClInclude>
Expand Down Expand Up @@ -359,6 +365,9 @@
<ClCompile Include="Debug\MemoryPatches.cpp">
<Filter>Debug</Filter>
</ClCompile>
<ClCompile Include="Debug\OSThread.cpp">
<Filter>Debug</Filter>
</ClCompile>
<ClCompile Include="GL\GLContext.cpp">
<Filter>GL\GLInterface</Filter>
</ClCompile>
Expand Down
204 changes: 204 additions & 0 deletions Source/Core/Common/Debug/OSThread.cpp
@@ -0,0 +1,204 @@
// Copyright 2020 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#include "Common/Debug/OSThread.h"

#include <algorithm>
#include <fmt/format.h>

#include "Core/PowerPC/MMU.h"

// Context offsets based on the following functions:
// - OSSaveContext
// - OSSaveFPUContext
// - OSDumpContext
// - OSClearContext
// - OSExceptionVector
void Common::Debug::OSContext::Read(u32 addr)
{
for (std::size_t i = 0; i < gpr.size(); i++)
gpr[i] = PowerPC::HostRead_U32(addr + u32(i * sizeof(int)));
cr = PowerPC::HostRead_U32(addr + 0x80);
lr = PowerPC::HostRead_U32(addr + 0x84);
ctr = PowerPC::HostRead_U32(addr + 0x88);
xer = PowerPC::HostRead_U32(addr + 0x8C);
for (std::size_t i = 0; i < fpr.size(); i++)
fpr[i] = PowerPC::HostRead_F64(addr + 0x90 + u32(i * sizeof(double)));
fpscr = PowerPC::HostRead_U64(addr + 0x190);
srr0 = PowerPC::HostRead_U32(addr + 0x198);
srr1 = PowerPC::HostRead_U32(addr + 0x19c);
dummy = PowerPC::HostRead_U16(addr + 0x1a0);
state = static_cast<OSContext::State>(PowerPC::HostRead_U16(addr + 0x1a2));
for (std::size_t i = 0; i < gqr.size(); i++)
gqr[i] = PowerPC::HostRead_U32(addr + 0x1a4 + u32(i * sizeof(int)));
psf_padding = 0;
for (std::size_t i = 0; i < psf.size(); i++)
psf[i] = PowerPC::HostRead_F64(addr + 0x1c8 + u32(i * sizeof(double)));
}

// Mutex offsets based on the following functions:
// - OSInitMutex
// - OSLockMutex
// - __OSUnlockAllMutex
void Common::Debug::OSMutex::Read(u32 addr)
{
thread_queue.head = PowerPC::HostRead_U32(addr);
thread_queue.tail = PowerPC::HostRead_U32(addr + 0x4);
owner_addr = PowerPC::HostRead_U32(addr + 0x8);
lock_count = PowerPC::HostRead_U32(addr + 0xc);
link.next = PowerPC::HostRead_U32(addr + 0x10);
link.prev = PowerPC::HostRead_U32(addr + 0x14);
}

// Thread offsets based on the following functions:
// - OSCreateThread
// - OSIsThreadTerminated
// - OSJoinThread
// - OSSuspendThread
// - OSSetPriority
// - OSExitThread
// - OSLockMutex
// - __OSUnlockAllMutex
// - __OSThreadInit
// - OSSetThreadSpecific
// - SOInit (for errno)
void Common::Debug::OSThread::Read(u32 addr)
{
context.Read(addr);
state = PowerPC::HostRead_U16(addr + 0x2c8);
is_detached = PowerPC::HostRead_U16(addr + 0x2ca);
suspend = PowerPC::HostRead_U32(addr + 0x2cc);
effective_priority = PowerPC::HostRead_U32(addr + 0x2d0);
base_priority = PowerPC::HostRead_U32(addr + 0x2d4);
exit_code_addr = PowerPC::HostRead_U32(addr + 0x2d8);

queue_addr = PowerPC::HostRead_U32(addr + 0x2dc);
queue_link.next = PowerPC::HostRead_U32(addr + 0x2e0);
queue_link.prev = PowerPC::HostRead_U32(addr + 0x2e4);

join_queue.head = PowerPC::HostRead_U32(addr + 0x2e8);
join_queue.tail = PowerPC::HostRead_U32(addr + 0x2ec);

mutex_addr = PowerPC::HostRead_U32(addr + 0x2f0);
mutex_queue.head = PowerPC::HostRead_U32(addr + 0x2f4);
mutex_queue.tail = PowerPC::HostRead_U32(addr + 0x2f8);

thread_link.next = PowerPC::HostRead_U32(addr + 0x2fc);
thread_link.prev = PowerPC::HostRead_U32(addr + 0x300);

stack_addr = PowerPC::HostRead_U32(addr + 0x304);
stack_end = PowerPC::HostRead_U32(addr + 0x308);
error = PowerPC::HostRead_U32(addr + 0x30c);
specific[0] = PowerPC::HostRead_U32(addr + 0x310);
specific[1] = PowerPC::HostRead_U32(addr + 0x314);
}

bool Common::Debug::OSThread::IsValid() const
{
return PowerPC::HostIsRAMAddress(stack_end) && PowerPC::HostRead_U32(stack_end) == STACK_MAGIC;
}

Common::Debug::OSThreadView::OSThreadView(u32 addr)
{
m_address = addr;
m_thread.Read(addr);
}

const Common::Debug::OSThread& Common::Debug::OSThreadView::Data() const
{
return m_thread;
}

Common::Debug::PartialContext Common::Debug::OSThreadView::GetContext() const
{
PartialContext context;

if (!IsValid())
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 Common::Debug::OSThreadView::GetAddress() const
{
return m_address;
}

u16 Common::Debug::OSThreadView::GetState() const
{
return m_thread.state;
}

bool Common::Debug::OSThreadView::IsSuspended() const
{
return m_thread.suspend > 0;
}

bool Common::Debug::OSThreadView::IsDetached() const
{
return m_thread.is_detached != 0;
}

s32 Common::Debug::OSThreadView::GetBasePriority() const
{
return m_thread.base_priority;
}

s32 Common::Debug::OSThreadView::GetEffectivePriority() const
{
return m_thread.effective_priority;
}

u32 Common::Debug::OSThreadView::GetStackStart() const
{
return m_thread.stack_addr;
}

u32 Common::Debug::OSThreadView::GetStackEnd() const
{
return m_thread.stack_end;
}

std::size_t Common::Debug::OSThreadView::GetStackSize() const
{
return GetStackStart() - GetStackEnd();
}

s32 Common::Debug::OSThreadView::GetErrno() const
{
return m_thread.error;
}

std::string Common::Debug::OSThreadView::GetSpecific() const
{
std::string specific;

for (u32 addr : m_thread.specific)
{
if (!PowerPC::HostIsRAMAddress(addr))
break;
specific += fmt::format("{:08x} \"{}\"\n", addr, PowerPC::HostGetString(addr));
}

return specific;
}

bool Common::Debug::OSThreadView::IsValid() const
{
return m_thread.IsValid();
}

0 comments on commit c53ecdd

Please sign in to comment.