summaryrefslogtreecommitdiff
path: root/src/core/debugger/gdbstub_arch.cpp
diff options
context:
space:
mode:
authorGravatar Mai M2022-06-01 00:19:49 -0400
committerGravatar GitHub2022-06-01 00:19:49 -0400
commitde2f2e5140eb85311e0fd844c580d6726adf7e03 (patch)
tree10f0e96a0689b2edb823f5833ff388ac9c645229 /src/core/debugger/gdbstub_arch.cpp
parentMerge pull request #8401 from zhaobot/tx-update-20220601034505 (diff)
parentcore/debugger: Implement new GDB stub debugger (diff)
downloadyuzu-de2f2e5140eb85311e0fd844c580d6726adf7e03.tar.gz
yuzu-de2f2e5140eb85311e0fd844c580d6726adf7e03.tar.xz
yuzu-de2f2e5140eb85311e0fd844c580d6726adf7e03.zip
Merge pull request #8394 from liamwhite/debugger
core/debugger: Implement new GDB stub debugger
Diffstat (limited to 'src/core/debugger/gdbstub_arch.cpp')
-rw-r--r--src/core/debugger/gdbstub_arch.cpp406
1 files changed, 406 insertions, 0 deletions
diff --git a/src/core/debugger/gdbstub_arch.cpp b/src/core/debugger/gdbstub_arch.cpp
new file mode 100644
index 000000000..99e3893a9
--- /dev/null
+++ b/src/core/debugger/gdbstub_arch.cpp
@@ -0,0 +1,406 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/hex_util.h"
5#include "core/debugger/gdbstub_arch.h"
6#include "core/hle/kernel/k_thread.h"
7
8namespace Core {
9
10template <typename T>
11static T HexToValue(std::string_view hex) {
12 static_assert(std::is_trivially_copyable_v<T>);
13 T value{};
14 const auto mem{Common::HexStringToVector(hex, false)};
15 std::memcpy(&value, mem.data(), std::min(mem.size(), sizeof(T)));
16 return value;
17}
18
19template <typename T>
20static std::string ValueToHex(const T value) {
21 static_assert(std::is_trivially_copyable_v<T>);
22 std::array<u8, sizeof(T)> mem{};
23 std::memcpy(mem.data(), &value, sizeof(T));
24 return Common::HexToString(mem);
25}
26
27template <typename T>
28static T GetSIMDRegister(const std::array<u32, 64>& simd_regs, size_t offset) {
29 static_assert(std::is_trivially_copyable_v<T>);
30 T value{};
31 std::memcpy(&value, reinterpret_cast<const u8*>(simd_regs.data()) + sizeof(T) * offset,
32 sizeof(T));
33 return value;
34}
35
36template <typename T>
37static void PutSIMDRegister(std::array<u32, 64>& simd_regs, size_t offset, const T value) {
38 static_assert(std::is_trivially_copyable_v<T>);
39 std::memcpy(reinterpret_cast<u8*>(simd_regs.data()) + sizeof(T) * offset, &value, sizeof(T));
40}
41
42// For sample XML files see the GDB source /gdb/features
43// This XML defines what the registers are for this specific ARM device
44std::string GDBStubA64::GetTargetXML() const {
45 constexpr const char* target_xml =
46 R"(<?xml version="1.0"?>
47<!DOCTYPE target SYSTEM "gdb-target.dtd">
48<target version="1.0">
49 <feature name="org.gnu.gdb.aarch64.core">
50 <reg name="x0" bitsize="64"/>
51 <reg name="x1" bitsize="64"/>
52 <reg name="x2" bitsize="64"/>
53 <reg name="x3" bitsize="64"/>
54 <reg name="x4" bitsize="64"/>
55 <reg name="x5" bitsize="64"/>
56 <reg name="x6" bitsize="64"/>
57 <reg name="x7" bitsize="64"/>
58 <reg name="x8" bitsize="64"/>
59 <reg name="x9" bitsize="64"/>
60 <reg name="x10" bitsize="64"/>
61 <reg name="x11" bitsize="64"/>
62 <reg name="x12" bitsize="64"/>
63 <reg name="x13" bitsize="64"/>
64 <reg name="x14" bitsize="64"/>
65 <reg name="x15" bitsize="64"/>
66 <reg name="x16" bitsize="64"/>
67 <reg name="x17" bitsize="64"/>
68 <reg name="x18" bitsize="64"/>
69 <reg name="x19" bitsize="64"/>
70 <reg name="x20" bitsize="64"/>
71 <reg name="x21" bitsize="64"/>
72 <reg name="x22" bitsize="64"/>
73 <reg name="x23" bitsize="64"/>
74 <reg name="x24" bitsize="64"/>
75 <reg name="x25" bitsize="64"/>
76 <reg name="x26" bitsize="64"/>
77 <reg name="x27" bitsize="64"/>
78 <reg name="x28" bitsize="64"/>
79 <reg name="x29" bitsize="64"/>
80 <reg name="x30" bitsize="64"/>
81 <reg name="sp" bitsize="64" type="data_ptr"/>
82 <reg name="pc" bitsize="64" type="code_ptr"/>
83 <flags id="pstate_flags" size="4">
84 <field name="SP" start="0" end="0"/>
85 <field name="" start="1" end="1"/>
86 <field name="EL" start="2" end="3"/>
87 <field name="nRW" start="4" end="4"/>
88 <field name="" start="5" end="5"/>
89 <field name="F" start="6" end="6"/>
90 <field name="I" start="7" end="7"/>
91 <field name="A" start="8" end="8"/>
92 <field name="D" start="9" end="9"/>
93 <field name="IL" start="20" end="20"/>
94 <field name="SS" start="21" end="21"/>
95 <field name="V" start="28" end="28"/>
96 <field name="C" start="29" end="29"/>
97 <field name="Z" start="30" end="30"/>
98 <field name="N" start="31" end="31"/>
99 </flags>
100 <reg name="pstate" bitsize="32" type="pstate_flags"/>
101 </feature>
102 <feature name="org.gnu.gdb.aarch64.fpu">
103 </feature>
104</target>)";
105
106 return target_xml;
107}
108
109std::string GDBStubA64::RegRead(const Kernel::KThread* thread, size_t id) const {
110 if (!thread) {
111 return "";
112 }
113
114 const auto& context{thread->GetContext64()};
115 const auto& gprs{context.cpu_registers};
116 const auto& fprs{context.vector_registers};
117
118 if (id <= SP_REGISTER) {
119 return ValueToHex(gprs[id]);
120 } else if (id == PC_REGISTER) {
121 return ValueToHex(context.pc);
122 } else if (id == PSTATE_REGISTER) {
123 return ValueToHex(context.pstate);
124 } else if (id >= Q0_REGISTER && id < FPCR_REGISTER) {
125 return ValueToHex(fprs[id - Q0_REGISTER]);
126 } else if (id == FPCR_REGISTER) {
127 return ValueToHex(context.fpcr);
128 } else if (id == FPSR_REGISTER) {
129 return ValueToHex(context.fpsr);
130 } else {
131 return "";
132 }
133}
134
135void GDBStubA64::RegWrite(Kernel::KThread* thread, size_t id, std::string_view value) const {
136 if (!thread) {
137 return;
138 }
139
140 auto& context{thread->GetContext64()};
141
142 if (id <= SP_REGISTER) {
143 context.cpu_registers[id] = HexToValue<u64>(value);
144 } else if (id == PC_REGISTER) {
145 context.pc = HexToValue<u64>(value);
146 } else if (id == PSTATE_REGISTER) {
147 context.pstate = HexToValue<u32>(value);
148 } else if (id >= Q0_REGISTER && id < FPCR_REGISTER) {
149 context.vector_registers[id - Q0_REGISTER] = HexToValue<u128>(value);
150 } else if (id == FPCR_REGISTER) {
151 context.fpcr = HexToValue<u32>(value);
152 } else if (id == FPSR_REGISTER) {
153 context.fpsr = HexToValue<u32>(value);
154 }
155}
156
157std::string GDBStubA64::ReadRegisters(const Kernel::KThread* thread) const {
158 std::string output;
159
160 for (size_t reg = 0; reg <= FPCR_REGISTER; reg++) {
161 output += RegRead(thread, reg);
162 }
163
164 return output;
165}
166
167void GDBStubA64::WriteRegisters(Kernel::KThread* thread, std::string_view register_data) const {
168 for (size_t i = 0, reg = 0; reg <= FPCR_REGISTER; reg++) {
169 if (reg <= SP_REGISTER || reg == PC_REGISTER) {
170 RegWrite(thread, reg, register_data.substr(i, 16));
171 i += 16;
172 } else if (reg == PSTATE_REGISTER || reg == FPCR_REGISTER || reg == FPSR_REGISTER) {
173 RegWrite(thread, reg, register_data.substr(i, 8));
174 i += 8;
175 } else if (reg >= Q0_REGISTER && reg < FPCR_REGISTER) {
176 RegWrite(thread, reg, register_data.substr(i, 32));
177 i += 32;
178 }
179 }
180}
181
182std::string GDBStubA64::ThreadStatus(const Kernel::KThread* thread, u8 signal) const {
183 return fmt::format("T{:02x}{:02x}:{};{:02x}:{};{:02x}:{};thread:{:x};", signal, PC_REGISTER,
184 RegRead(thread, PC_REGISTER), SP_REGISTER, RegRead(thread, SP_REGISTER),
185 LR_REGISTER, RegRead(thread, LR_REGISTER), thread->GetThreadID());
186}
187
188u32 GDBStubA64::BreakpointInstruction() const {
189 // A64: brk #0
190 return 0xd4200000;
191}
192
193std::string GDBStubA32::GetTargetXML() const {
194 constexpr const char* target_xml =
195 R"(<?xml version="1.0"?>
196<!DOCTYPE target SYSTEM "gdb-target.dtd">
197<target version="1.0">
198 <feature name="org.gnu.gdb.arm.core">
199 <reg name="r0" bitsize="32" type="uint32"/>
200 <reg name="r1" bitsize="32" type="uint32"/>
201 <reg name="r2" bitsize="32" type="uint32"/>
202 <reg name="r3" bitsize="32" type="uint32"/>
203 <reg name="r4" bitsize="32" type="uint32"/>
204 <reg name="r5" bitsize="32" type="uint32"/>
205 <reg name="r6" bitsize="32" type="uint32"/>
206 <reg name="r7" bitsize="32" type="uint32"/>
207 <reg name="r8" bitsize="32" type="uint32"/>
208 <reg name="r9" bitsize="32" type="uint32"/>
209 <reg name="r10" bitsize="32" type="uint32"/>
210 <reg name="r11" bitsize="32" type="uint32"/>
211 <reg name="r12" bitsize="32" type="uint32"/>
212 <reg name="sp" bitsize="32" type="data_ptr"/>
213 <reg name="lr" bitsize="32" type="code_ptr"/>
214 <reg name="pc" bitsize="32" type="code_ptr"/>
215 <!-- The CPSR is register 25, rather than register 16, because
216 the FPA registers historically were placed between the PC
217 and the CPSR in the "g" packet. -->
218 <reg name="cpsr" bitsize="32" regnum="25"/>
219 </feature>
220 <feature name="org.gnu.gdb.arm.vfp">
221 <vector id="neon_uint8x8" type="uint8" count="8"/>
222 <vector id="neon_uint16x4" type="uint16" count="4"/>
223 <vector id="neon_uint32x2" type="uint32" count="2"/>
224 <vector id="neon_float32x2" type="ieee_single" count="2"/>
225 <union id="neon_d">
226 <field name="u8" type="neon_uint8x8"/>
227 <field name="u16" type="neon_uint16x4"/>
228 <field name="u32" type="neon_uint32x2"/>
229 <field name="u64" type="uint64"/>
230 <field name="f32" type="neon_float32x2"/>
231 <field name="f64" type="ieee_double"/>
232 </union>
233 <vector id="neon_uint8x16" type="uint8" count="16"/>
234 <vector id="neon_uint16x8" type="uint16" count="8"/>
235 <vector id="neon_uint32x4" type="uint32" count="4"/>
236 <vector id="neon_uint64x2" type="uint64" count="2"/>
237 <vector id="neon_float32x4" type="ieee_single" count="4"/>
238 <vector id="neon_float64x2" type="ieee_double" count="2"/>
239 <union id="neon_q">
240 <field name="u8" type="neon_uint8x16"/>
241 <field name="u16" type="neon_uint16x8"/>
242 <field name="u32" type="neon_uint32x4"/>
243 <field name="u64" type="neon_uint64x2"/>
244 <field name="f32" type="neon_float32x4"/>
245 <field name="f64" type="neon_float64x2"/>
246 </union>
247 <reg name="d0" bitsize="64" type="neon_d" regnum="32"/>
248 <reg name="d1" bitsize="64" type="neon_d"/>
249 <reg name="d2" bitsize="64" type="neon_d"/>
250 <reg name="d3" bitsize="64" type="neon_d"/>
251 <reg name="d4" bitsize="64" type="neon_d"/>
252 <reg name="d5" bitsize="64" type="neon_d"/>
253 <reg name="d6" bitsize="64" type="neon_d"/>
254 <reg name="d7" bitsize="64" type="neon_d"/>
255 <reg name="d8" bitsize="64" type="neon_d"/>
256 <reg name="d9" bitsize="64" type="neon_d"/>
257 <reg name="d10" bitsize="64" type="neon_d"/>
258 <reg name="d11" bitsize="64" type="neon_d"/>
259 <reg name="d12" bitsize="64" type="neon_d"/>
260 <reg name="d13" bitsize="64" type="neon_d"/>
261 <reg name="d14" bitsize="64" type="neon_d"/>
262 <reg name="d15" bitsize="64" type="neon_d"/>
263 <reg name="d16" bitsize="64" type="neon_d"/>
264 <reg name="d17" bitsize="64" type="neon_d"/>
265 <reg name="d18" bitsize="64" type="neon_d"/>
266 <reg name="d19" bitsize="64" type="neon_d"/>
267 <reg name="d20" bitsize="64" type="neon_d"/>
268 <reg name="d21" bitsize="64" type="neon_d"/>
269 <reg name="d22" bitsize="64" type="neon_d"/>
270 <reg name="d23" bitsize="64" type="neon_d"/>
271 <reg name="d24" bitsize="64" type="neon_d"/>
272 <reg name="d25" bitsize="64" type="neon_d"/>
273 <reg name="d26" bitsize="64" type="neon_d"/>
274 <reg name="d27" bitsize="64" type="neon_d"/>
275 <reg name="d28" bitsize="64" type="neon_d"/>
276 <reg name="d29" bitsize="64" type="neon_d"/>
277 <reg name="d30" bitsize="64" type="neon_d"/>
278 <reg name="d31" bitsize="64" type="neon_d"/>
279
280 <reg name="q0" bitsize="128" type="neon_q" regnum="64"/>
281 <reg name="q1" bitsize="128" type="neon_q"/>
282 <reg name="q2" bitsize="128" type="neon_q"/>
283 <reg name="q3" bitsize="128" type="neon_q"/>
284 <reg name="q4" bitsize="128" type="neon_q"/>
285 <reg name="q5" bitsize="128" type="neon_q"/>
286 <reg name="q6" bitsize="128" type="neon_q"/>
287 <reg name="q7" bitsize="128" type="neon_q"/>
288 <reg name="q8" bitsize="128" type="neon_q"/>
289 <reg name="q9" bitsize="128" type="neon_q"/>
290 <reg name="q10" bitsize="128" type="neon_q"/>
291 <reg name="q10" bitsize="128" type="neon_q"/>
292 <reg name="q12" bitsize="128" type="neon_q"/>
293 <reg name="q13" bitsize="128" type="neon_q"/>
294 <reg name="q14" bitsize="128" type="neon_q"/>
295 <reg name="q15" bitsize="128" type="neon_q"/>
296
297 <reg name="fpscr" bitsize="32" type="int" group="float" regnum="80"/>
298 </feature>
299</target>)";
300
301 return target_xml;
302}
303
304std::string GDBStubA32::RegRead(const Kernel::KThread* thread, size_t id) const {
305 if (!thread) {
306 return "";
307 }
308
309 const auto& context{thread->GetContext32()};
310 const auto& gprs{context.cpu_registers};
311 const auto& fprs{context.extension_registers};
312
313 if (id <= PC_REGISTER) {
314 return ValueToHex(gprs[id]);
315 } else if (id == CPSR_REGISTER) {
316 return ValueToHex(context.cpsr);
317 } else if (id >= D0_REGISTER && id < Q0_REGISTER) {
318 const u64 dN{GetSIMDRegister<u64>(fprs, id - D0_REGISTER)};
319 return ValueToHex(dN);
320 } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) {
321 const u128 qN{GetSIMDRegister<u128>(fprs, id - Q0_REGISTER)};
322 return ValueToHex(qN);
323 } else if (id == FPSCR_REGISTER) {
324 return ValueToHex(context.fpscr);
325 } else {
326 return "";
327 }
328}
329
330void GDBStubA32::RegWrite(Kernel::KThread* thread, size_t id, std::string_view value) const {
331 if (!thread) {
332 return;
333 }
334
335 auto& context{thread->GetContext32()};
336 auto& fprs{context.extension_registers};
337
338 if (id <= PC_REGISTER) {
339 context.cpu_registers[id] = HexToValue<u32>(value);
340 } else if (id == CPSR_REGISTER) {
341 context.cpsr = HexToValue<u32>(value);
342 } else if (id >= D0_REGISTER && id < Q0_REGISTER) {
343 PutSIMDRegister(fprs, id - D0_REGISTER, HexToValue<u64>(value));
344 } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) {
345 PutSIMDRegister(fprs, id - Q0_REGISTER, HexToValue<u128>(value));
346 } else if (id == FPSCR_REGISTER) {
347 context.fpscr = HexToValue<u32>(value);
348 }
349}
350
351std::string GDBStubA32::ReadRegisters(const Kernel::KThread* thread) const {
352 std::string output;
353
354 for (size_t reg = 0; reg <= FPSCR_REGISTER; reg++) {
355 const bool gpr{reg <= PC_REGISTER};
356 const bool dfpr{reg >= D0_REGISTER && reg < Q0_REGISTER};
357 const bool qfpr{reg >= Q0_REGISTER && reg < FPSCR_REGISTER};
358
359 if (!(gpr || dfpr || qfpr || reg == CPSR_REGISTER || reg == FPSCR_REGISTER)) {
360 continue;
361 }
362
363 output += RegRead(thread, reg);
364 }
365
366 return output;
367}
368
369void GDBStubA32::WriteRegisters(Kernel::KThread* thread, std::string_view register_data) const {
370 for (size_t i = 0, reg = 0; reg <= FPSCR_REGISTER; reg++) {
371 const bool gpr{reg <= PC_REGISTER};
372 const bool dfpr{reg >= D0_REGISTER && reg < Q0_REGISTER};
373 const bool qfpr{reg >= Q0_REGISTER && reg < FPSCR_REGISTER};
374
375 if (gpr || reg == CPSR_REGISTER || reg == FPSCR_REGISTER) {
376 RegWrite(thread, reg, register_data.substr(i, 8));
377 i += 8;
378 } else if (dfpr) {
379 RegWrite(thread, reg, register_data.substr(i, 16));
380 i += 16;
381 } else if (qfpr) {
382 RegWrite(thread, reg, register_data.substr(i, 32));
383 i += 32;
384 }
385
386 if (reg == PC_REGISTER) {
387 reg = CPSR_REGISTER - 1;
388 } else if (reg == CPSR_REGISTER) {
389 reg = D0_REGISTER - 1;
390 }
391 }
392}
393
394std::string GDBStubA32::ThreadStatus(const Kernel::KThread* thread, u8 signal) const {
395 return fmt::format("T{:02x}{:02x}:{};{:02x}:{};{:02x}:{};thread:{:x};", signal, PC_REGISTER,
396 RegRead(thread, PC_REGISTER), SP_REGISTER, RegRead(thread, SP_REGISTER),
397 LR_REGISTER, RegRead(thread, LR_REGISTER), thread->GetThreadID());
398}
399
400u32 GDBStubA32::BreakpointInstruction() const {
401 // A32: trap
402 // T32: trap + b #4
403 return 0xe7ffdefe;
404}
405
406} // namespace Core