1 // Copyright 2020 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4 
5 #pragma once
6 
7 #include <array>
8 #include <string>
9 #include <type_traits>
10 
11 #include "Common/CommonTypes.h"
12 #include "Common/Debug/Threads.h"
13 
14 namespace Common::Debug
15 {
16 template <class C>
17 struct OSQueue
18 {
19   u32 head;
20   u32 tail;
21 };
22 template <class C>
23 struct OSLink
24 {
25   u32 next;
26   u32 prev;
27 };
28 
29 struct OSMutex;
30 struct OSThread;
31 
32 using OSThreadQueue = OSQueue<OSThread>;
33 using OSThreadLink = OSLink<OSThread>;
34 
35 using OSMutexQueue = OSQueue<OSMutex>;
36 using OSMutexLink = OSLink<OSMutex>;
37 
38 struct OSContext
39 {
40   enum class State : u16
41   {
42     HasFPU = 1,
43     HasException = 2,
44   };
45   std::array<u32, 32> gpr;
46   u32 cr;
47   u32 lr;
48   u32 ctr;
49   u32 xer;
50   std::array<double, 32> fpr;
51   u64 fpscr;
52   u32 srr0;
53   u32 srr1;
54   u16 dummy;
55   State state;
56   std::array<u32, 8> gqr;
57   u32 psf_padding;
58   std::array<double, 32> psf;
59 
60   void Read(u32 addr);
61 };
62 
63 static_assert(std::is_trivially_copyable_v<OSContext>);
64 static_assert(std::is_standard_layout_v<OSContext>);
65 static_assert(offsetof(OSContext, cr) == 0x80);
66 static_assert(offsetof(OSContext, fpscr) == 0x190);
67 static_assert(offsetof(OSContext, gqr) == 0x1a4);
68 static_assert(offsetof(OSContext, psf) == 0x1c8);
69 
70 struct OSThread
71 {
72   OSContext context;
73 
74   u16 state;               // Thread state (ready, running, waiting, moribund)
75   u16 is_detached;         // Is thread detached
76   s32 suspend;             // Suspended if greater than zero
77   s32 effective_priority;  // Effective priority
78   s32 base_priority;       // Base priority
79   u32 exit_code_addr;      // Exit value address
80 
81   u32 queue_addr;           // Address of the queue the thread is on
82   OSThreadLink queue_link;  // Used to traverse the thread queue
83   // OSSleepThread uses it to insert the current thread at the end of the thread queue
84 
85   OSThreadQueue join_queue;  // Threads waiting to be joined
86 
87   u32 mutex_addr;            // Mutex waiting
88   OSMutexQueue mutex_queue;  // Mutex owned
89 
90   OSThreadLink thread_link;  // Link containing all active threads
91 
92   // The STACK_MAGIC is written at stack_end
93   u32 stack_addr;
94   u32 stack_end;
95 
96   s32 error;                    // errno value
97   std::array<u32, 2> specific;  // Pointers to data (can be used to store thread names)
98 
99   static constexpr u32 STACK_MAGIC = 0xDEADBABE;
100   void Read(u32 addr);
101   bool IsValid() const;
102 };
103 
104 static_assert(std::is_trivially_copyable_v<OSThread>);
105 static_assert(std::is_standard_layout_v<OSThread>);
106 static_assert(offsetof(OSThread, state) == 0x2c8);
107 static_assert(offsetof(OSThread, mutex_addr) == 0x2f0);
108 static_assert(offsetof(OSThread, stack_addr) == 0x304);
109 static_assert(offsetof(OSThread, specific) == 0x310);
110 
111 struct OSMutex
112 {
113   OSThreadQueue thread_queue;  // Threads waiting to own the mutex
114   u32 owner_addr;              // Thread owning the mutex
115   s32 lock_count;              // Mutex lock count
116   OSMutexLink link;            // Used to traverse the thread's mutex queue
117   // OSLockMutex uses it to insert the acquired mutex at the end of the queue
118 
119   void Read(u32 addr);
120 };
121 
122 static_assert(std::is_trivially_copyable_v<OSMutex>);
123 static_assert(std::is_standard_layout_v<OSMutex>);
124 static_assert(offsetof(OSMutex, owner_addr) == 0x8);
125 static_assert(offsetof(OSMutex, link) == 0x10);
126 
127 class OSThreadView : public Common::Debug::ThreadView
128 {
129 public:
130   explicit OSThreadView(u32 addr);
131   ~OSThreadView() = default;
132 
133   const OSThread& Data() const;
134 
135   PartialContext GetContext() const override;
136   u32 GetAddress() const override;
137   u16 GetState() const override;
138   bool IsSuspended() const override;
139   bool IsDetached() const override;
140   s32 GetBasePriority() const override;
141   s32 GetEffectivePriority() const override;
142   u32 GetStackStart() const override;
143   u32 GetStackEnd() const override;
144   std::size_t GetStackSize() const override;
145   s32 GetErrno() const override;
146   std::string GetSpecific() const override;
147   bool IsValid() const override;
148 
149 private:
150   u32 m_address = 0;
151   OSThread m_thread;
152 };
153 
154 }  // namespace Common::Debug
155