summaryrefslogtreecommitdiff
path: root/src/core/debugger
diff options
context:
space:
mode:
authorGravatar Fernando S2023-12-06 14:19:17 +0100
committerGravatar GitHub2023-12-06 14:19:17 +0100
commit8a79dd2d6c6445bff63ea1f2f5f1611a6afcd97a (patch)
tree265bf3c7970a570479c6a3ac1250549995f0329c /src/core/debugger
parentMerge pull request #12271 from liamwhite/pretext-fix (diff)
parentarm: fix context save of vector regs (diff)
downloadyuzu-8a79dd2d6c6445bff63ea1f2f5f1611a6afcd97a.tar.gz
yuzu-8a79dd2d6c6445bff63ea1f2f5f1611a6afcd97a.tar.xz
yuzu-8a79dd2d6c6445bff63ea1f2f5f1611a6afcd97a.zip
Merge pull request #12236 from liamwhite/cpu-refactor
core: refactor emulated cpu core activation
Diffstat (limited to 'src/core/debugger')
-rw-r--r--src/core/debugger/gdbstub.cpp243
-rw-r--r--src/core/debugger/gdbstub_arch.cpp72
-rw-r--r--src/core/debugger/gdbstub_arch.h1
3 files changed, 44 insertions, 272 deletions
diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp
index 148dd3e39..66e46c4ba 100644
--- a/src/core/debugger/gdbstub.cpp
+++ b/src/core/debugger/gdbstub.cpp
@@ -16,6 +16,7 @@
16#include "common/settings.h" 16#include "common/settings.h"
17#include "common/string_util.h" 17#include "common/string_util.h"
18#include "core/arm/arm_interface.h" 18#include "core/arm/arm_interface.h"
19#include "core/arm/debug.h"
19#include "core/core.h" 20#include "core/core.h"
20#include "core/debugger/gdbstub.h" 21#include "core/debugger/gdbstub.h"
21#include "core/debugger/gdbstub_arch.h" 22#include "core/debugger/gdbstub_arch.h"
@@ -310,7 +311,7 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction
310 const auto mem{Common::HexStringToVector(mem_substr, false)}; 311 const auto mem{Common::HexStringToVector(mem_substr, false)};
311 312
312 if (system.ApplicationMemory().WriteBlock(addr, mem.data(), size)) { 313 if (system.ApplicationMemory().WriteBlock(addr, mem.data(), size)) {
313 system.InvalidateCpuInstructionCacheRange(addr, size); 314 Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), addr, size);
314 SendReply(GDB_STUB_REPLY_OK); 315 SendReply(GDB_STUB_REPLY_OK);
315 } else { 316 } else {
316 SendReply(GDB_STUB_REPLY_ERR); 317 SendReply(GDB_STUB_REPLY_ERR);
@@ -363,7 +364,7 @@ void GDBStub::HandleBreakpointInsert(std::string_view command) {
363 case BreakpointType::Software: 364 case BreakpointType::Software:
364 replaced_instructions[addr] = system.ApplicationMemory().Read32(addr); 365 replaced_instructions[addr] = system.ApplicationMemory().Read32(addr);
365 system.ApplicationMemory().Write32(addr, arch->BreakpointInstruction()); 366 system.ApplicationMemory().Write32(addr, arch->BreakpointInstruction());
366 system.InvalidateCpuInstructionCacheRange(addr, sizeof(u32)); 367 Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), addr, sizeof(u32));
367 success = true; 368 success = true;
368 break; 369 break;
369 case BreakpointType::WriteWatch: 370 case BreakpointType::WriteWatch:
@@ -411,7 +412,7 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) {
411 const auto orig_insn{replaced_instructions.find(addr)}; 412 const auto orig_insn{replaced_instructions.find(addr)};
412 if (orig_insn != replaced_instructions.end()) { 413 if (orig_insn != replaced_instructions.end()) {
413 system.ApplicationMemory().Write32(addr, orig_insn->second); 414 system.ApplicationMemory().Write32(addr, orig_insn->second);
414 system.InvalidateCpuInstructionCacheRange(addr, sizeof(u32)); 415 Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), addr, sizeof(u32));
415 replaced_instructions.erase(addr); 416 replaced_instructions.erase(addr);
416 success = true; 417 success = true;
417 } 418 }
@@ -442,114 +443,6 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) {
442 } 443 }
443} 444}
444 445
445// Structure offsets are from Atmosphere
446// See osdbg_thread_local_region.os.horizon.hpp and osdbg_thread_type.os.horizon.hpp
447
448static std::optional<std::string> GetNameFromThreadType32(Core::Memory::Memory& memory,
449 const Kernel::KThread& thread) {
450 // Read thread type from TLS
451 const VAddr tls_thread_type{memory.Read32(thread.GetTlsAddress() + 0x1fc)};
452 const VAddr argument_thread_type{thread.GetArgument()};
453
454 if (argument_thread_type && tls_thread_type != argument_thread_type) {
455 // Probably not created by nnsdk, no name available.
456 return std::nullopt;
457 }
458
459 if (!tls_thread_type) {
460 return std::nullopt;
461 }
462
463 const u16 version{memory.Read16(tls_thread_type + 0x26)};
464 VAddr name_pointer{};
465 if (version == 1) {
466 name_pointer = memory.Read32(tls_thread_type + 0xe4);
467 } else {
468 name_pointer = memory.Read32(tls_thread_type + 0xe8);
469 }
470
471 if (!name_pointer) {
472 // No name provided.
473 return std::nullopt;
474 }
475
476 return memory.ReadCString(name_pointer, 256);
477}
478
479static std::optional<std::string> GetNameFromThreadType64(Core::Memory::Memory& memory,
480 const Kernel::KThread& thread) {
481 // Read thread type from TLS
482 const VAddr tls_thread_type{memory.Read64(thread.GetTlsAddress() + 0x1f8)};
483 const VAddr argument_thread_type{thread.GetArgument()};
484
485 if (argument_thread_type && tls_thread_type != argument_thread_type) {
486 // Probably not created by nnsdk, no name available.
487 return std::nullopt;
488 }
489
490 if (!tls_thread_type) {
491 return std::nullopt;
492 }
493
494 const u16 version{memory.Read16(tls_thread_type + 0x46)};
495 VAddr name_pointer{};
496 if (version == 1) {
497 name_pointer = memory.Read64(tls_thread_type + 0x1a0);
498 } else {
499 name_pointer = memory.Read64(tls_thread_type + 0x1a8);
500 }
501
502 if (!name_pointer) {
503 // No name provided.
504 return std::nullopt;
505 }
506
507 return memory.ReadCString(name_pointer, 256);
508}
509
510static std::optional<std::string> GetThreadName(Core::System& system,
511 const Kernel::KThread& thread) {
512 if (system.ApplicationProcess()->Is64Bit()) {
513 return GetNameFromThreadType64(system.ApplicationMemory(), thread);
514 } else {
515 return GetNameFromThreadType32(system.ApplicationMemory(), thread);
516 }
517}
518
519static std::string_view GetThreadWaitReason(const Kernel::KThread& thread) {
520 switch (thread.GetWaitReasonForDebugging()) {
521 case Kernel::ThreadWaitReasonForDebugging::Sleep:
522 return "Sleep";
523 case Kernel::ThreadWaitReasonForDebugging::IPC:
524 return "IPC";
525 case Kernel::ThreadWaitReasonForDebugging::Synchronization:
526 return "Synchronization";
527 case Kernel::ThreadWaitReasonForDebugging::ConditionVar:
528 return "ConditionVar";
529 case Kernel::ThreadWaitReasonForDebugging::Arbitration:
530 return "Arbitration";
531 case Kernel::ThreadWaitReasonForDebugging::Suspended:
532 return "Suspended";
533 default:
534 return "Unknown";
535 }
536}
537
538static std::string GetThreadState(const Kernel::KThread& thread) {
539 switch (thread.GetState()) {
540 case Kernel::ThreadState::Initialized:
541 return "Initialized";
542 case Kernel::ThreadState::Waiting:
543 return fmt::format("Waiting ({})", GetThreadWaitReason(thread));
544 case Kernel::ThreadState::Runnable:
545 return "Runnable";
546 case Kernel::ThreadState::Terminated:
547 return "Terminated";
548 default:
549 return "Unknown";
550 }
551}
552
553static std::string PaginateBuffer(std::string_view buffer, std::string_view request) { 446static std::string PaginateBuffer(std::string_view buffer, std::string_view request) {
554 const auto amount{request.substr(request.find(',') + 1)}; 447 const auto amount{request.substr(request.find(',') + 1)};
555 const auto offset_val{static_cast<u64>(strtoll(request.data(), nullptr, 16))}; 448 const auto offset_val{static_cast<u64>(strtoll(request.data(), nullptr, 16))};
@@ -562,120 +455,6 @@ static std::string PaginateBuffer(std::string_view buffer, std::string_view requ
562 } 455 }
563} 456}
564 457
565static VAddr GetModuleEnd(Kernel::KProcessPageTable& page_table, VAddr base) {
566 Kernel::KMemoryInfo mem_info;
567 Kernel::Svc::MemoryInfo svc_mem_info;
568 Kernel::Svc::PageInfo page_info;
569 VAddr cur_addr{base};
570
571 // Expect: r-x Code (.text)
572 R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr));
573 svc_mem_info = mem_info.GetSvcMemoryInfo();
574 cur_addr = svc_mem_info.base_address + svc_mem_info.size;
575 if (svc_mem_info.state != Kernel::Svc::MemoryState::Code ||
576 svc_mem_info.permission != Kernel::Svc::MemoryPermission::ReadExecute) {
577 return cur_addr - 1;
578 }
579
580 // Expect: r-- Code (.rodata)
581 R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr));
582 svc_mem_info = mem_info.GetSvcMemoryInfo();
583 cur_addr = svc_mem_info.base_address + svc_mem_info.size;
584 if (svc_mem_info.state != Kernel::Svc::MemoryState::Code ||
585 svc_mem_info.permission != Kernel::Svc::MemoryPermission::Read) {
586 return cur_addr - 1;
587 }
588
589 // Expect: rw- CodeData (.data)
590 R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr));
591 svc_mem_info = mem_info.GetSvcMemoryInfo();
592 cur_addr = svc_mem_info.base_address + svc_mem_info.size;
593 return cur_addr - 1;
594}
595
596static Loader::AppLoader::Modules FindModules(Core::System& system) {
597 Loader::AppLoader::Modules modules;
598
599 auto& page_table = system.ApplicationProcess()->GetPageTable();
600 auto& memory = system.ApplicationMemory();
601 VAddr cur_addr = 0;
602
603 // Look for executable sections in Code or AliasCode regions.
604 while (true) {
605 Kernel::KMemoryInfo mem_info{};
606 Kernel::Svc::PageInfo page_info{};
607 R_ASSERT(
608 page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr));
609 auto svc_mem_info = mem_info.GetSvcMemoryInfo();
610
611 if (svc_mem_info.permission == Kernel::Svc::MemoryPermission::ReadExecute &&
612 (svc_mem_info.state == Kernel::Svc::MemoryState::Code ||
613 svc_mem_info.state == Kernel::Svc::MemoryState::AliasCode)) {
614 // Try to read the module name from its path.
615 constexpr s32 PathLengthMax = 0x200;
616 struct {
617 u32 zero;
618 s32 path_length;
619 std::array<char, PathLengthMax> path;
620 } module_path;
621
622 if (memory.ReadBlock(svc_mem_info.base_address + svc_mem_info.size, &module_path,
623 sizeof(module_path))) {
624 if (module_path.zero == 0 && module_path.path_length > 0) {
625 // Truncate module name.
626 module_path.path[PathLengthMax - 1] = '\0';
627
628 // Ignore leading directories.
629 char* path_pointer = module_path.path.data();
630
631 for (s32 i = 0; i < std::min(PathLengthMax, module_path.path_length) &&
632 module_path.path[i] != '\0';
633 i++) {
634 if (module_path.path[i] == '/' || module_path.path[i] == '\\') {
635 path_pointer = module_path.path.data() + i + 1;
636 }
637 }
638
639 // Insert output.
640 modules.emplace(svc_mem_info.base_address, path_pointer);
641 }
642 }
643 }
644
645 // Check if we're done.
646 const uintptr_t next_address = svc_mem_info.base_address + svc_mem_info.size;
647 if (next_address <= cur_addr) {
648 break;
649 }
650
651 cur_addr = next_address;
652 }
653
654 return modules;
655}
656
657static VAddr FindMainModuleEntrypoint(Core::System& system) {
658 Loader::AppLoader::Modules modules;
659 system.GetAppLoader().ReadNSOModules(modules);
660
661 // Do we have a module named main?
662 const auto main = std::find_if(modules.begin(), modules.end(),
663 [](const auto& key) { return key.second == "main"; });
664
665 if (main != modules.end()) {
666 return main->first;
667 }
668
669 // Do we have any loaded executable sections?
670 modules = FindModules(system);
671 if (!modules.empty()) {
672 return modules.begin()->first;
673 }
674
675 // As a last resort, use the start of the code region.
676 return GetInteger(system.ApplicationProcess()->GetPageTable().GetCodeRegionStart());
677}
678
679void GDBStub::HandleQuery(std::string_view command) { 458void GDBStub::HandleQuery(std::string_view command) {
680 if (command.starts_with("TStatus")) { 459 if (command.starts_with("TStatus")) {
681 // no tracepoint support 460 // no tracepoint support
@@ -687,10 +466,10 @@ void GDBStub::HandleQuery(std::string_view command) {
687 const auto target_xml{arch->GetTargetXML()}; 466 const auto target_xml{arch->GetTargetXML()};
688 SendReply(PaginateBuffer(target_xml, command.substr(30))); 467 SendReply(PaginateBuffer(target_xml, command.substr(30)));
689 } else if (command.starts_with("Offsets")) { 468 } else if (command.starts_with("Offsets")) {
690 const auto main_offset = FindMainModuleEntrypoint(system); 469 const auto main_offset = Core::FindMainModuleEntrypoint(system.ApplicationProcess());
691 SendReply(fmt::format("TextSeg={:x}", main_offset)); 470 SendReply(fmt::format("TextSeg={:x}", GetInteger(main_offset)));
692 } else if (command.starts_with("Xfer:libraries:read::")) { 471 } else if (command.starts_with("Xfer:libraries:read::")) {
693 auto modules = FindModules(system); 472 auto modules = Core::FindModules(system.ApplicationProcess());
694 473
695 std::string buffer; 474 std::string buffer;
696 buffer += R"(<?xml version="1.0"?>)"; 475 buffer += R"(<?xml version="1.0"?>)";
@@ -720,14 +499,14 @@ void GDBStub::HandleQuery(std::string_view command) {
720 499
721 const auto& threads = system.ApplicationProcess()->GetThreadList(); 500 const auto& threads = system.ApplicationProcess()->GetThreadList();
722 for (const auto& thread : threads) { 501 for (const auto& thread : threads) {
723 auto thread_name{GetThreadName(system, thread)}; 502 auto thread_name{Core::GetThreadName(&thread)};
724 if (!thread_name) { 503 if (!thread_name) {
725 thread_name = fmt::format("Thread {:d}", thread.GetThreadId()); 504 thread_name = fmt::format("Thread {:d}", thread.GetThreadId());
726 } 505 }
727 506
728 buffer += fmt::format(R"(<thread id="{:x}" core="{:d}" name="{}">{}</thread>)", 507 buffer += fmt::format(R"(<thread id="{:x}" core="{:d}" name="{}">{}</thread>)",
729 thread.GetThreadId(), thread.GetActiveCore(), 508 thread.GetThreadId(), thread.GetActiveCore(),
730 EscapeXML(*thread_name), GetThreadState(thread)); 509 EscapeXML(*thread_name), GetThreadState(&thread));
731 } 510 }
732 511
733 buffer += "</threads>"; 512 buffer += "</threads>";
@@ -856,7 +635,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
856 reply = "Fastmem is not enabled.\n"; 635 reply = "Fastmem is not enabled.\n";
857 } 636 }
858 } else if (command_str == "get info") { 637 } else if (command_str == "get info") {
859 auto modules = FindModules(system); 638 auto modules = Core::FindModules(process);
860 639
861 reply = fmt::format("Process: {:#x} ({})\n" 640 reply = fmt::format("Process: {:#x} ({})\n"
862 "Program Id: {:#018x}\n", 641 "Program Id: {:#018x}\n",
@@ -880,7 +659,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
880 659
881 for (const auto& [vaddr, name] : modules) { 660 for (const auto& [vaddr, name] : modules) {
882 reply += fmt::format(" {:#012x} - {:#012x} {}\n", vaddr, 661 reply += fmt::format(" {:#012x} - {:#012x} {}\n", vaddr,
883 GetModuleEnd(page_table, vaddr), name); 662 GetInteger(Core::GetModuleEnd(process, vaddr)), name);
884 } 663 }
885 } else if (command_str == "get mappings") { 664 } else if (command_str == "get mappings") {
886 reply = "Mappings:\n"; 665 reply = "Mappings:\n";
diff --git a/src/core/debugger/gdbstub_arch.cpp b/src/core/debugger/gdbstub_arch.cpp
index 75c94a91a..f2a407dc8 100644
--- a/src/core/debugger/gdbstub_arch.cpp
+++ b/src/core/debugger/gdbstub_arch.cpp
@@ -24,21 +24,6 @@ static std::string ValueToHex(const T value) {
24 return Common::HexToString(mem); 24 return Common::HexToString(mem);
25} 25}
26 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 27// For sample XML files see the GDB source /gdb/features
43// This XML defines what the registers are for this specific ARM device 28// This XML defines what the registers are for this specific ARM device
44std::string_view GDBStubA64::GetTargetXML() const { 29std::string_view GDBStubA64::GetTargetXML() const {
@@ -184,12 +169,16 @@ std::string GDBStubA64::RegRead(const Kernel::KThread* thread, size_t id) const
184 return ""; 169 return "";
185 } 170 }
186 171
187 const auto& context{thread->GetContext64()}; 172 const auto& context{thread->GetContext()};
188 const auto& gprs{context.cpu_registers}; 173 const auto& gprs{context.r};
189 const auto& fprs{context.vector_registers}; 174 const auto& fprs{context.v};
190 175
191 if (id < SP_REGISTER) { 176 if (id < FP_REGISTER) {
192 return ValueToHex(gprs[id]); 177 return ValueToHex(gprs[id]);
178 } else if (id == FP_REGISTER) {
179 return ValueToHex(context.fp);
180 } else if (id == LR_REGISTER) {
181 return ValueToHex(context.lr);
193 } else if (id == SP_REGISTER) { 182 } else if (id == SP_REGISTER) {
194 return ValueToHex(context.sp); 183 return ValueToHex(context.sp);
195 } else if (id == PC_REGISTER) { 184 } else if (id == PC_REGISTER) {
@@ -212,10 +201,14 @@ void GDBStubA64::RegWrite(Kernel::KThread* thread, size_t id, std::string_view v
212 return; 201 return;
213 } 202 }
214 203
215 auto& context{thread->GetContext64()}; 204 auto& context{thread->GetContext()};
216 205
217 if (id < SP_REGISTER) { 206 if (id < FP_REGISTER) {
218 context.cpu_registers[id] = HexToValue<u64>(value); 207 context.r[id] = HexToValue<u64>(value);
208 } else if (id == FP_REGISTER) {
209 context.fp = HexToValue<u64>(value);
210 } else if (id == LR_REGISTER) {
211 context.lr = HexToValue<u64>(value);
219 } else if (id == SP_REGISTER) { 212 } else if (id == SP_REGISTER) {
220 context.sp = HexToValue<u64>(value); 213 context.sp = HexToValue<u64>(value);
221 } else if (id == PC_REGISTER) { 214 } else if (id == PC_REGISTER) {
@@ -223,7 +216,7 @@ void GDBStubA64::RegWrite(Kernel::KThread* thread, size_t id, std::string_view v
223 } else if (id == PSTATE_REGISTER) { 216 } else if (id == PSTATE_REGISTER) {
224 context.pstate = HexToValue<u32>(value); 217 context.pstate = HexToValue<u32>(value);
225 } else if (id >= Q0_REGISTER && id < FPSR_REGISTER) { 218 } else if (id >= Q0_REGISTER && id < FPSR_REGISTER) {
226 context.vector_registers[id - Q0_REGISTER] = HexToValue<u128>(value); 219 context.v[id - Q0_REGISTER] = HexToValue<u128>(value);
227 } else if (id == FPSR_REGISTER) { 220 } else if (id == FPSR_REGISTER) {
228 context.fpsr = HexToValue<u32>(value); 221 context.fpsr = HexToValue<u32>(value);
229 } else if (id == FPCR_REGISTER) { 222 } else if (id == FPCR_REGISTER) {
@@ -381,22 +374,20 @@ std::string GDBStubA32::RegRead(const Kernel::KThread* thread, size_t id) const
381 return ""; 374 return "";
382 } 375 }
383 376
384 const auto& context{thread->GetContext32()}; 377 const auto& context{thread->GetContext()};
385 const auto& gprs{context.cpu_registers}; 378 const auto& gprs{context.r};
386 const auto& fprs{context.extension_registers}; 379 const auto& fprs{context.v};
387 380
388 if (id <= PC_REGISTER) { 381 if (id <= PC_REGISTER) {
389 return ValueToHex(gprs[id]); 382 return ValueToHex(static_cast<u32>(gprs[id]));
390 } else if (id == CPSR_REGISTER) { 383 } else if (id == CPSR_REGISTER) {
391 return ValueToHex(context.cpsr); 384 return ValueToHex(context.pstate);
392 } else if (id >= D0_REGISTER && id < Q0_REGISTER) { 385 } else if (id >= D0_REGISTER && id < Q0_REGISTER) {
393 const u64 dN{GetSIMDRegister<u64>(fprs, id - D0_REGISTER)}; 386 return ValueToHex(fprs[id - D0_REGISTER][0]);
394 return ValueToHex(dN);
395 } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) { 387 } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) {
396 const u128 qN{GetSIMDRegister<u128>(fprs, id - Q0_REGISTER)}; 388 return ValueToHex(fprs[id - Q0_REGISTER]);
397 return ValueToHex(qN);
398 } else if (id == FPSCR_REGISTER) { 389 } else if (id == FPSCR_REGISTER) {
399 return ValueToHex(context.fpscr); 390 return ValueToHex(context.fpcr | context.fpsr);
400 } else { 391 } else {
401 return ""; 392 return "";
402 } 393 }
@@ -407,19 +398,20 @@ void GDBStubA32::RegWrite(Kernel::KThread* thread, size_t id, std::string_view v
407 return; 398 return;
408 } 399 }
409 400
410 auto& context{thread->GetContext32()}; 401 auto& context{thread->GetContext()};
411 auto& fprs{context.extension_registers}; 402 auto& fprs{context.v};
412 403
413 if (id <= PC_REGISTER) { 404 if (id <= PC_REGISTER) {
414 context.cpu_registers[id] = HexToValue<u32>(value); 405 context.r[id] = HexToValue<u32>(value);
415 } else if (id == CPSR_REGISTER) { 406 } else if (id == CPSR_REGISTER) {
416 context.cpsr = HexToValue<u32>(value); 407 context.pstate = HexToValue<u32>(value);
417 } else if (id >= D0_REGISTER && id < Q0_REGISTER) { 408 } else if (id >= D0_REGISTER && id < Q0_REGISTER) {
418 PutSIMDRegister(fprs, id - D0_REGISTER, HexToValue<u64>(value)); 409 fprs[id - D0_REGISTER] = {HexToValue<u64>(value), 0};
419 } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) { 410 } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) {
420 PutSIMDRegister(fprs, id - Q0_REGISTER, HexToValue<u128>(value)); 411 fprs[id - Q0_REGISTER] = HexToValue<u128>(value);
421 } else if (id == FPSCR_REGISTER) { 412 } else if (id == FPSCR_REGISTER) {
422 context.fpscr = HexToValue<u32>(value); 413 context.fpcr = HexToValue<u32>(value);
414 context.fpsr = HexToValue<u32>(value);
423 } 415 }
424} 416}
425 417
diff --git a/src/core/debugger/gdbstub_arch.h b/src/core/debugger/gdbstub_arch.h
index 34530c788..d53714d69 100644
--- a/src/core/debugger/gdbstub_arch.h
+++ b/src/core/debugger/gdbstub_arch.h
@@ -36,6 +36,7 @@ public:
36 u32 BreakpointInstruction() const override; 36 u32 BreakpointInstruction() const override;
37 37
38private: 38private:
39 static constexpr u32 FP_REGISTER = 29;
39 static constexpr u32 LR_REGISTER = 30; 40 static constexpr u32 LR_REGISTER = 30;
40 static constexpr u32 SP_REGISTER = 31; 41 static constexpr u32 SP_REGISTER = 31;
41 static constexpr u32 PC_REGISTER = 32; 42 static constexpr u32 PC_REGISTER = 32;