summaryrefslogtreecommitdiff
path: root/src/core/gdbstub/gdbstub.cpp
diff options
context:
space:
mode:
authorGravatar Hedges2018-06-06 05:20:47 +0100
committerGravatar bunnei2018-06-06 00:20:47 -0400
commit39fb3e362cf71d0542a5807c97039cd474ef3716 (patch)
treee54ad38fba3c7b2b32e5e408e9e7eb8cb6ffe6b0 /src/core/gdbstub/gdbstub.cpp
parentMerge pull request #516 from Subv/f2i_r (diff)
downloadyuzu-39fb3e362cf71d0542a5807c97039cd474ef3716.tar.gz
yuzu-39fb3e362cf71d0542a5807c97039cd474ef3716.tar.xz
yuzu-39fb3e362cf71d0542a5807c97039cd474ef3716.zip
GDB Stub Improvements (#508)
* GDB Stub should work now. * Applied clang-format. * Replaced htonll with swap64. * Tidy up.
Diffstat (limited to 'src/core/gdbstub/gdbstub.cpp')
-rw-r--r--src/core/gdbstub/gdbstub.cpp170
1 files changed, 144 insertions, 26 deletions
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index 6c5a40ba8..2603192fe 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -32,9 +32,13 @@
32 32
33#include "common/logging/log.h" 33#include "common/logging/log.h"
34#include "common/string_util.h" 34#include "common/string_util.h"
35#include "common/swap.h"
35#include "core/arm/arm_interface.h" 36#include "core/arm/arm_interface.h"
36#include "core/core.h" 37#include "core/core.h"
38#include "core/core_cpu.h"
37#include "core/gdbstub/gdbstub.h" 39#include "core/gdbstub/gdbstub.h"
40#include "core/hle/kernel/kernel.h"
41#include "core/hle/kernel/scheduler.h"
38#include "core/loader/loader.h" 42#include "core/loader/loader.h"
39#include "core/memory.h" 43#include "core/memory.h"
40 44
@@ -137,15 +141,17 @@ static u8 command_buffer[GDB_BUFFER_SIZE];
137static u32 command_length; 141static u32 command_length;
138 142
139static u32 latest_signal = 0; 143static u32 latest_signal = 0;
140static bool step_break = false;
141static bool memory_break = false; 144static bool memory_break = false;
142 145
146static Kernel::Thread* current_thread = nullptr;
147
143// Binding to a port within the reserved ports range (0-1023) requires root permissions, 148// Binding to a port within the reserved ports range (0-1023) requires root permissions,
144// so default to a port outside of that range. 149// so default to a port outside of that range.
145static u16 gdbstub_port = 24689; 150static u16 gdbstub_port = 24689;
146 151
147static bool halt_loop = true; 152static bool halt_loop = true;
148static bool step_loop = false; 153static bool step_loop = false;
154static bool send_trap = false;
149 155
150// If set to false, the server will never be started and no 156// If set to false, the server will never be started and no
151// gdbstub-related functions will be executed. 157// gdbstub-related functions will be executed.
@@ -165,6 +171,53 @@ static std::map<u64, Breakpoint> breakpoints_execute;
165static std::map<u64, Breakpoint> breakpoints_read; 171static std::map<u64, Breakpoint> breakpoints_read;
166static std::map<u64, Breakpoint> breakpoints_write; 172static std::map<u64, Breakpoint> breakpoints_write;
167 173
174static Kernel::Thread* FindThreadById(int id) {
175 for (int core = 0; core < Core::NUM_CPU_CORES; core++) {
176 auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList();
177 for (auto thread : threads) {
178 if (thread->GetThreadId() == id) {
179 current_thread = thread.get();
180 return current_thread;
181 }
182 }
183 }
184 return nullptr;
185}
186
187static u64 RegRead(int id, Kernel::Thread* thread = nullptr) {
188 if (!thread) {
189 return 0;
190 }
191
192 if (id < SP_REGISTER) {
193 return thread->context.cpu_registers[id];
194 } else if (id == SP_REGISTER) {
195 return thread->context.sp;
196 } else if (id == PC_REGISTER) {
197 return thread->context.pc;
198 } else if (id == CPSR_REGISTER) {
199 return thread->context.cpsr;
200 } else {
201 return 0;
202 }
203}
204
205static void RegWrite(int id, u64 val, Kernel::Thread* thread = nullptr) {
206 if (!thread) {
207 return;
208 }
209
210 if (id < SP_REGISTER) {
211 thread->context.cpu_registers[id] = val;
212 } else if (id == SP_REGISTER) {
213 thread->context.sp = val;
214 } else if (id == PC_REGISTER) {
215 thread->context.pc = val;
216 } else if (id == CPSR_REGISTER) {
217 thread->context.cpsr = val;
218 }
219}
220
168/** 221/**
169 * Turns hex string character into the equivalent byte. 222 * Turns hex string character into the equivalent byte.
170 * 223 *
@@ -193,7 +246,7 @@ static u8 NibbleToHex(u8 n) {
193 if (n < 0xA) { 246 if (n < 0xA) {
194 return '0' + n; 247 return '0' + n;
195 } else { 248 } else {
196 return 'A' + n - 0xA; 249 return 'a' + n - 0xA;
197 } 250 }
198} 251}
199 252
@@ -439,6 +492,8 @@ static void SendReply(const char* reply) {
439 return; 492 return;
440 } 493 }
441 494
495 NGLOG_DEBUG(Debug_GDBStub, "Reply: {}", reply);
496
442 memset(command_buffer, 0, sizeof(command_buffer)); 497 memset(command_buffer, 0, sizeof(command_buffer));
443 498
444 command_length = static_cast<u32>(strlen(reply)); 499 command_length = static_cast<u32>(strlen(reply));
@@ -483,6 +538,22 @@ static void HandleQuery() {
483 } else if (strncmp(query, "Xfer:features:read:target.xml:", 538 } else if (strncmp(query, "Xfer:features:read:target.xml:",
484 strlen("Xfer:features:read:target.xml:")) == 0) { 539 strlen("Xfer:features:read:target.xml:")) == 0) {
485 SendReply(target_xml); 540 SendReply(target_xml);
541 } else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) {
542 std::string buffer = fmt::format("TextSeg={:0x}", Memory::PROCESS_IMAGE_VADDR);
543 SendReply(buffer.c_str());
544 } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) {
545 std::string val = "m";
546 for (int core = 0; core < Core::NUM_CPU_CORES; core++) {
547 auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList();
548 for (auto thread : threads) {
549 val += fmt::format("{:x}", thread->GetThreadId());
550 val += ",";
551 }
552 }
553 val.pop_back();
554 SendReply(val.c_str());
555 } else if (strncmp(query, "sThreadInfo", strlen("sThreadInfo")) == 0) {
556 SendReply("l");
486 } else { 557 } else {
487 SendReply(""); 558 SendReply("");
488 } 559 }
@@ -490,11 +561,40 @@ static void HandleQuery() {
490 561
491/// Handle set thread command from gdb client. 562/// Handle set thread command from gdb client.
492static void HandleSetThread() { 563static void HandleSetThread() {
493 if (memcmp(command_buffer, "Hg0", 3) == 0 || memcmp(command_buffer, "Hc-1", 4) == 0 || 564 if (memcmp(command_buffer, "Hc", 2) == 0 || memcmp(command_buffer, "Hg", 2) == 0) {
494 memcmp(command_buffer, "Hc0", 4) == 0 || memcmp(command_buffer, "Hc1", 4) == 0) { 565 int thread_id = -1;
495 return SendReply("OK"); 566 if (command_buffer[2] != '-') {
567 thread_id = static_cast<int>(HexToInt(
568 command_buffer + 2,
569 command_length - 2 /*strlen(reinterpret_cast<char*>(command_buffer) + 2)*/));
570 }
571 if (thread_id >= 1) {
572 current_thread = FindThreadById(thread_id);
573 }
574 if (!current_thread) {
575 thread_id = 1;
576 current_thread = FindThreadById(thread_id);
577 }
578 if (current_thread) {
579 SendReply("OK");
580 return;
581 }
496 } 582 }
583 SendReply("E01");
584}
497 585
586/// Handle thread alive command from gdb client.
587static void HandleThreadAlive() {
588 int thread_id = static_cast<int>(
589 HexToInt(command_buffer + 1,
590 command_length - 1 /*strlen(reinterpret_cast<char*>(command_buffer) + 1)*/));
591 if (thread_id == 0) {
592 thread_id = 1;
593 }
594 if (FindThreadById(thread_id)) {
595 SendReply("OK");
596 return;
597 }
498 SendReply("E01"); 598 SendReply("E01");
499} 599}
500 600
@@ -503,15 +603,24 @@ static void HandleSetThread() {
503 * 603 *
504 * @param signal Signal to be sent to client. 604 * @param signal Signal to be sent to client.
505 */ 605 */
506static void SendSignal(u32 signal) { 606static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) {
507 if (gdbserver_socket == -1) { 607 if (gdbserver_socket == -1) {
508 return; 608 return;
509 } 609 }
510 610
511 latest_signal = signal; 611 latest_signal = signal;
512 612
513 std::string buffer = fmt::format("T{:02x}", latest_signal); 613 std::string buffer;
514 NGLOG_DEBUG(Debug_GDBStub, "Response: {}", buffer); 614 if (full) {
615 buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x};", latest_signal, PC_REGISTER,
616 Common::swap64(RegRead(PC_REGISTER, thread)), SP_REGISTER,
617 Common::swap64(RegRead(SP_REGISTER, thread)));
618 } else {
619 buffer = fmt::format("T{:02x};", latest_signal);
620 }
621
622 buffer += fmt::format("thread:{:x};", thread->GetThreadId());
623
515 SendReply(buffer.c_str()); 624 SendReply(buffer.c_str());
516} 625}
517 626
@@ -527,7 +636,7 @@ static void ReadCommand() {
527 } else if (c == 0x03) { 636 } else if (c == 0x03) {
528 NGLOG_INFO(Debug_GDBStub, "gdb: found break command"); 637 NGLOG_INFO(Debug_GDBStub, "gdb: found break command");
529 halt_loop = true; 638 halt_loop = true;
530 SendSignal(SIGTRAP); 639 SendSignal(current_thread, SIGTRAP);
531 return; 640 return;
532 } else if (c != GDB_STUB_START) { 641 } else if (c != GDB_STUB_START) {
533 NGLOG_DEBUG(Debug_GDBStub, "gdb: read invalid byte {:02X}", c); 642 NGLOG_DEBUG(Debug_GDBStub, "gdb: read invalid byte {:02X}", c);
@@ -598,11 +707,11 @@ static void ReadRegister() {
598 } 707 }
599 708
600 if (id <= SP_REGISTER) { 709 if (id <= SP_REGISTER) {
601 LongToGdbHex(reply, Core::CurrentArmInterface().GetReg(static_cast<int>(id))); 710 LongToGdbHex(reply, RegRead(id, current_thread));
602 } else if (id == PC_REGISTER) { 711 } else if (id == PC_REGISTER) {
603 LongToGdbHex(reply, Core::CurrentArmInterface().GetPC()); 712 LongToGdbHex(reply, RegRead(id, current_thread));
604 } else if (id == CPSR_REGISTER) { 713 } else if (id == CPSR_REGISTER) {
605 IntToGdbHex(reply, Core::CurrentArmInterface().GetCPSR()); 714 IntToGdbHex(reply, (u32)RegRead(id, current_thread));
606 } else { 715 } else {
607 return SendReply("E01"); 716 return SendReply("E01");
608 } 717 }
@@ -618,16 +727,16 @@ static void ReadRegisters() {
618 u8* bufptr = buffer; 727 u8* bufptr = buffer;
619 728
620 for (int reg = 0; reg <= SP_REGISTER; reg++) { 729 for (int reg = 0; reg <= SP_REGISTER; reg++) {
621 LongToGdbHex(bufptr + reg * 16, Core::CurrentArmInterface().GetReg(reg)); 730 LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread));
622 } 731 }
623 732
624 bufptr += (32 * 16); 733 bufptr += (32 * 16);
625 734
626 LongToGdbHex(bufptr, Core::CurrentArmInterface().GetPC()); 735 LongToGdbHex(bufptr, RegRead(PC_REGISTER, current_thread));
627 736
628 bufptr += 16; 737 bufptr += 16;
629 738
630 IntToGdbHex(bufptr, Core::CurrentArmInterface().GetCPSR()); 739 IntToGdbHex(bufptr, (u32)RegRead(CPSR_REGISTER, current_thread));
631 740
632 bufptr += 8; 741 bufptr += 8;
633 742
@@ -646,11 +755,11 @@ static void WriteRegister() {
646 } 755 }
647 756
648 if (id <= SP_REGISTER) { 757 if (id <= SP_REGISTER) {
649 Core::CurrentArmInterface().SetReg(id, GdbHexToLong(buffer_ptr)); 758 RegWrite(id, GdbHexToLong(buffer_ptr), current_thread);
650 } else if (id == PC_REGISTER) { 759 } else if (id == PC_REGISTER) {
651 Core::CurrentArmInterface().SetPC(GdbHexToLong(buffer_ptr)); 760 RegWrite(id, GdbHexToLong(buffer_ptr), current_thread);
652 } else if (id == CPSR_REGISTER) { 761 } else if (id == CPSR_REGISTER) {
653 Core::CurrentArmInterface().SetCPSR(GdbHexToInt(buffer_ptr)); 762 RegWrite(id, GdbHexToInt(buffer_ptr), current_thread);
654 } else { 763 } else {
655 return SendReply("E01"); 764 return SendReply("E01");
656 } 765 }
@@ -667,11 +776,11 @@ static void WriteRegisters() {
667 776
668 for (int i = 0, reg = 0; reg <= CPSR_REGISTER; i++, reg++) { 777 for (int i = 0, reg = 0; reg <= CPSR_REGISTER; i++, reg++) {
669 if (reg <= SP_REGISTER) { 778 if (reg <= SP_REGISTER) {
670 Core::CurrentArmInterface().SetReg(reg, GdbHexToLong(buffer_ptr + i * 16)); 779 RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread);
671 } else if (reg == PC_REGISTER) { 780 } else if (reg == PC_REGISTER) {
672 Core::CurrentArmInterface().SetPC(GdbHexToLong(buffer_ptr + i * 16)); 781 RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread);
673 } else if (reg == CPSR_REGISTER) { 782 } else if (reg == CPSR_REGISTER) {
674 Core::CurrentArmInterface().SetCPSR(GdbHexToInt(buffer_ptr + i * 16)); 783 RegWrite(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread);
675 } else { 784 } else {
676 UNIMPLEMENTED(); 785 UNIMPLEMENTED();
677 } 786 }
@@ -734,7 +843,7 @@ static void WriteMemory() {
734void Break(bool is_memory_break) { 843void Break(bool is_memory_break) {
735 if (!halt_loop) { 844 if (!halt_loop) {
736 halt_loop = true; 845 halt_loop = true;
737 SendSignal(SIGTRAP); 846 send_trap = true;
738 } 847 }
739 848
740 memory_break = is_memory_break; 849 memory_break = is_memory_break;
@@ -744,10 +853,10 @@ void Break(bool is_memory_break) {
744static void Step() { 853static void Step() {
745 step_loop = true; 854 step_loop = true;
746 halt_loop = true; 855 halt_loop = true;
747 step_break = true; 856 send_trap = true;
748 SendSignal(SIGTRAP);
749} 857}
750 858
859/// Tell the CPU if we hit a memory breakpoint.
751bool IsMemoryBreak() { 860bool IsMemoryBreak() {
752 if (IsConnected()) { 861 if (IsConnected()) {
753 return false; 862 return false;
@@ -759,7 +868,6 @@ bool IsMemoryBreak() {
759/// Tell the CPU to continue executing. 868/// Tell the CPU to continue executing.
760static void Continue() { 869static void Continue() {
761 memory_break = false; 870 memory_break = false;
762 step_break = false;
763 step_loop = false; 871 step_loop = false;
764 halt_loop = false; 872 halt_loop = false;
765} 873}
@@ -898,7 +1006,7 @@ void HandlePacket() {
898 HandleSetThread(); 1006 HandleSetThread();
899 break; 1007 break;
900 case '?': 1008 case '?':
901 SendSignal(latest_signal); 1009 SendSignal(current_thread, latest_signal);
902 break; 1010 break;
903 case 'k': 1011 case 'k':
904 Shutdown(); 1012 Shutdown();
@@ -935,6 +1043,9 @@ void HandlePacket() {
935 case 'Z': 1043 case 'Z':
936 AddBreakpoint(); 1044 AddBreakpoint();
937 break; 1045 break;
1046 case 'T':
1047 HandleThreadAlive();
1048 break;
938 default: 1049 default:
939 SendReply(""); 1050 SendReply("");
940 break; 1051 break;
@@ -1079,4 +1190,11 @@ bool GetCpuStepFlag() {
1079void SetCpuStepFlag(bool is_step) { 1190void SetCpuStepFlag(bool is_step) {
1080 step_loop = is_step; 1191 step_loop = is_step;
1081} 1192}
1193
1194void SendTrap(Kernel::Thread* thread, int trap) {
1195 if (send_trap) {
1196 send_trap = false;
1197 SendSignal(thread, trap);
1198 }
1199}
1082}; // namespace GDBStub 1200}; // namespace GDBStub