diff options
| author | 2018-07-13 04:22:59 +0100 | |
|---|---|---|
| committer | 2018-07-12 20:22:59 -0700 | |
| commit | e066bc75b9443ffe39adc44a113eca8e899c6e80 (patch) | |
| tree | 78bd4a46cfa69c678ae7518260b0a91cc4227adf /src/core/gdbstub/gdbstub.cpp | |
| parent | Merge pull request #656 from ogniK5377/audren-mem-init (diff) | |
| download | yuzu-e066bc75b9443ffe39adc44a113eca8e899c6e80.tar.gz yuzu-e066bc75b9443ffe39adc44a113eca8e899c6e80.tar.xz yuzu-e066bc75b9443ffe39adc44a113eca8e899c6e80.zip | |
More improvements to GDBStub (#653)
* More improvements to GDBStub
- Debugging of threads should work correctly with source and assembly level stepping and modifying registers and memory, meaning threads and callstacks are fully clickable in VS.
- List of modules is available to the client, with assumption that .nro and .nso are backed up by an .elf with symbols, while deconstructed ROMs keep N names.
- Initial support for floating point registers.
* Tidy up as requested in PR feedback
* Tidy up as requested in PR feedback
Diffstat (limited to 'src/core/gdbstub/gdbstub.cpp')
| -rw-r--r-- | src/core/gdbstub/gdbstub.cpp | 194 |
1 files changed, 149 insertions, 45 deletions
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 938852a1a..6062de13c 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp | |||
| @@ -61,10 +61,16 @@ const u32 SIGTERM = 15; | |||
| 61 | const u32 MSG_WAITALL = 8; | 61 | const u32 MSG_WAITALL = 8; |
| 62 | #endif | 62 | #endif |
| 63 | 63 | ||
| 64 | const u32 X30_REGISTER = 30; | 64 | const u32 LR_REGISTER = 30; |
| 65 | const u32 SP_REGISTER = 31; | 65 | const u32 SP_REGISTER = 31; |
| 66 | const u32 PC_REGISTER = 32; | 66 | const u32 PC_REGISTER = 32; |
| 67 | const u32 CPSR_REGISTER = 33; | 67 | const u32 CPSR_REGISTER = 33; |
| 68 | const u32 UC_ARM64_REG_Q0 = 34; | ||
| 69 | const u32 FPSCR_REGISTER = 66; | ||
| 70 | |||
| 71 | // TODO/WiP - Used while working on support for FPU | ||
| 72 | const u32 TODO_DUMMY_REG_997 = 997; | ||
| 73 | const u32 TODO_DUMMY_REG_998 = 998; | ||
| 68 | 74 | ||
| 69 | // For sample XML files see the GDB source /gdb/features | 75 | // For sample XML files see the GDB source /gdb/features |
| 70 | // GDB also wants the l character at the start | 76 | // GDB also wants the l character at the start |
| @@ -130,6 +136,8 @@ static const char* target_xml = | |||
| 130 | </flags> | 136 | </flags> |
| 131 | <reg name="cpsr" bitsize="32" type="cpsr_flags"/> | 137 | <reg name="cpsr" bitsize="32" type="cpsr_flags"/> |
| 132 | </feature> | 138 | </feature> |
| 139 | <feature name="org.gnu.gdb.aarch64.fpu"> | ||
| 140 | </feature> | ||
| 133 | </target> | 141 | </target> |
| 134 | )"; | 142 | )"; |
| 135 | 143 | ||
| @@ -144,6 +152,7 @@ static u32 latest_signal = 0; | |||
| 144 | static bool memory_break = false; | 152 | static bool memory_break = false; |
| 145 | 153 | ||
| 146 | static Kernel::Thread* current_thread = nullptr; | 154 | static Kernel::Thread* current_thread = nullptr; |
| 155 | static u32 current_core = 0; | ||
| 147 | 156 | ||
| 148 | // Binding to a port within the reserved ports range (0-1023) requires root permissions, | 157 | // Binding to a port within the reserved ports range (0-1023) requires root permissions, |
| 149 | // so default to a port outside of that range. | 158 | // so default to a port outside of that range. |
| @@ -171,13 +180,34 @@ static std::map<u64, Breakpoint> breakpoints_execute; | |||
| 171 | static std::map<u64, Breakpoint> breakpoints_read; | 180 | static std::map<u64, Breakpoint> breakpoints_read; |
| 172 | static std::map<u64, Breakpoint> breakpoints_write; | 181 | static std::map<u64, Breakpoint> breakpoints_write; |
| 173 | 182 | ||
| 183 | struct Module { | ||
| 184 | std::string name; | ||
| 185 | PAddr beg; | ||
| 186 | PAddr end; | ||
| 187 | }; | ||
| 188 | |||
| 189 | static std::vector<Module> modules; | ||
| 190 | |||
| 191 | void RegisterModule(std::string name, PAddr beg, PAddr end, bool add_elf_ext) { | ||
| 192 | Module module; | ||
| 193 | if (add_elf_ext) { | ||
| 194 | Common::SplitPath(name, nullptr, &module.name, nullptr); | ||
| 195 | module.name += ".elf"; | ||
| 196 | } else { | ||
| 197 | module.name = std::move(name); | ||
| 198 | } | ||
| 199 | module.beg = beg; | ||
| 200 | module.end = end; | ||
| 201 | modules.push_back(std::move(module)); | ||
| 202 | } | ||
| 203 | |||
| 174 | static Kernel::Thread* FindThreadById(int id) { | 204 | static Kernel::Thread* FindThreadById(int id) { |
| 175 | for (int core = 0; core < Core::NUM_CPU_CORES; core++) { | 205 | for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { |
| 176 | auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); | 206 | const auto& threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); |
| 177 | for (auto thread : threads) { | 207 | for (auto& thread : threads) { |
| 178 | if (thread->GetThreadId() == id) { | 208 | if (thread->GetThreadId() == id) { |
| 179 | current_thread = thread.get(); | 209 | current_core = core; |
| 180 | return current_thread; | 210 | return thread.get(); |
| 181 | } | 211 | } |
| 182 | } | 212 | } |
| 183 | } | 213 | } |
| @@ -197,6 +227,8 @@ static u64 RegRead(int id, Kernel::Thread* thread = nullptr) { | |||
| 197 | return thread->context.pc; | 227 | return thread->context.pc; |
| 198 | } else if (id == CPSR_REGISTER) { | 228 | } else if (id == CPSR_REGISTER) { |
| 199 | return thread->context.cpsr; | 229 | return thread->context.cpsr; |
| 230 | } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) { | ||
| 231 | return thread->context.fpu_registers[id - UC_ARM64_REG_Q0][0]; | ||
| 200 | } else { | 232 | } else { |
| 201 | return 0; | 233 | return 0; |
| 202 | } | 234 | } |
| @@ -215,6 +247,8 @@ static void RegWrite(int id, u64 val, Kernel::Thread* thread = nullptr) { | |||
| 215 | thread->context.pc = val; | 247 | thread->context.pc = val; |
| 216 | } else if (id == CPSR_REGISTER) { | 248 | } else if (id == CPSR_REGISTER) { |
| 217 | thread->context.cpsr = val; | 249 | thread->context.cpsr = val; |
| 250 | } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) { | ||
| 251 | thread->context.fpu_registers[id - (CPSR_REGISTER + 1)][0] = val; | ||
| 218 | } | 252 | } |
| 219 | } | 253 | } |
| 220 | 254 | ||
| @@ -534,7 +568,11 @@ static void HandleQuery() { | |||
| 534 | SendReply("T0"); | 568 | SendReply("T0"); |
| 535 | } else if (strncmp(query, "Supported", strlen("Supported")) == 0) { | 569 | } else if (strncmp(query, "Supported", strlen("Supported")) == 0) { |
| 536 | // PacketSize needs to be large enough for target xml | 570 | // PacketSize needs to be large enough for target xml |
| 537 | SendReply("PacketSize=2000;qXfer:features:read+"); | 571 | std::string buffer = "PacketSize=2000;qXfer:features:read+;qXfer:threads:read+"; |
| 572 | if (!modules.empty()) { | ||
| 573 | buffer += ";qXfer:libraries:read+"; | ||
| 574 | } | ||
| 575 | SendReply(buffer.c_str()); | ||
| 538 | } else if (strncmp(query, "Xfer:features:read:target.xml:", | 576 | } else if (strncmp(query, "Xfer:features:read:target.xml:", |
| 539 | strlen("Xfer:features:read:target.xml:")) == 0) { | 577 | strlen("Xfer:features:read:target.xml:")) == 0) { |
| 540 | SendReply(target_xml); | 578 | SendReply(target_xml); |
| @@ -543,9 +581,9 @@ static void HandleQuery() { | |||
| 543 | SendReply(buffer.c_str()); | 581 | SendReply(buffer.c_str()); |
| 544 | } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { | 582 | } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { |
| 545 | std::string val = "m"; | 583 | std::string val = "m"; |
| 546 | for (int core = 0; core < Core::NUM_CPU_CORES; core++) { | 584 | for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { |
| 547 | auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); | 585 | const auto& threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); |
| 548 | for (auto thread : threads) { | 586 | for (const auto& thread : threads) { |
| 549 | val += fmt::format("{:x}", thread->GetThreadId()); | 587 | val += fmt::format("{:x}", thread->GetThreadId()); |
| 550 | val += ","; | 588 | val += ","; |
| 551 | } | 589 | } |
| @@ -554,6 +592,31 @@ static void HandleQuery() { | |||
| 554 | SendReply(val.c_str()); | 592 | SendReply(val.c_str()); |
| 555 | } else if (strncmp(query, "sThreadInfo", strlen("sThreadInfo")) == 0) { | 593 | } else if (strncmp(query, "sThreadInfo", strlen("sThreadInfo")) == 0) { |
| 556 | SendReply("l"); | 594 | SendReply("l"); |
| 595 | } else if (strncmp(query, "Xfer:threads:read", strlen("Xfer:threads:read")) == 0) { | ||
| 596 | std::string buffer; | ||
| 597 | buffer += "l<?xml version=\"1.0\"?>"; | ||
| 598 | buffer += "<threads>"; | ||
| 599 | for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { | ||
| 600 | const auto& threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); | ||
| 601 | for (const auto& thread : threads) { | ||
| 602 | buffer += | ||
| 603 | fmt::format(R"*(<thread id="{:x}" core="{:d}" name="Thread {:x}"></thread>)*", | ||
| 604 | thread->GetThreadId(), core, thread->GetThreadId()); | ||
| 605 | } | ||
| 606 | } | ||
| 607 | buffer += "</threads>"; | ||
| 608 | SendReply(buffer.c_str()); | ||
| 609 | } else if (strncmp(query, "Xfer:libraries:read", strlen("Xfer:libraries:read")) == 0) { | ||
| 610 | std::string buffer; | ||
| 611 | buffer += "l<?xml version=\"1.0\"?>"; | ||
| 612 | buffer += "<library-list>"; | ||
| 613 | for (const auto& module : modules) { | ||
| 614 | buffer += | ||
| 615 | fmt::format(R"*("<library name = "{}"><segment address = "0x{:x}"/></library>)*", | ||
| 616 | module.name, module.beg); | ||
| 617 | } | ||
| 618 | buffer += "</library-list>"; | ||
| 619 | SendReply(buffer.c_str()); | ||
| 557 | } else { | 620 | } else { |
| 558 | SendReply(""); | 621 | SendReply(""); |
| 559 | } | 622 | } |
| @@ -561,33 +624,27 @@ static void HandleQuery() { | |||
| 561 | 624 | ||
| 562 | /// Handle set thread command from gdb client. | 625 | /// Handle set thread command from gdb client. |
| 563 | static void HandleSetThread() { | 626 | static void HandleSetThread() { |
| 564 | if (memcmp(command_buffer, "Hc", 2) == 0 || memcmp(command_buffer, "Hg", 2) == 0) { | 627 | int thread_id = -1; |
| 565 | int thread_id = -1; | 628 | if (command_buffer[2] != '-') { |
| 566 | if (command_buffer[2] != '-') { | 629 | thread_id = static_cast<int>(HexToInt(command_buffer + 2, command_length - 2)); |
| 567 | thread_id = static_cast<int>(HexToInt( | 630 | } |
| 568 | command_buffer + 2, | 631 | if (thread_id >= 1) { |
| 569 | command_length - 2 /*strlen(reinterpret_cast<char*>(command_buffer) + 2)*/)); | 632 | current_thread = FindThreadById(thread_id); |
| 570 | } | 633 | } |
| 571 | if (thread_id >= 1) { | 634 | if (!current_thread) { |
| 572 | current_thread = FindThreadById(thread_id); | 635 | thread_id = 1; |
| 573 | } | 636 | current_thread = FindThreadById(thread_id); |
| 574 | if (!current_thread) { | 637 | } |
| 575 | thread_id = 1; | 638 | if (current_thread) { |
| 576 | current_thread = FindThreadById(thread_id); | 639 | SendReply("OK"); |
| 577 | } | 640 | return; |
| 578 | if (current_thread) { | ||
| 579 | SendReply("OK"); | ||
| 580 | return; | ||
| 581 | } | ||
| 582 | } | 641 | } |
| 583 | SendReply("E01"); | 642 | SendReply("E01"); |
| 584 | } | 643 | } |
| 585 | 644 | ||
| 586 | /// Handle thread alive command from gdb client. | 645 | /// Handle thread alive command from gdb client. |
| 587 | static void HandleThreadAlive() { | 646 | static void HandleThreadAlive() { |
| 588 | int thread_id = static_cast<int>( | 647 | int thread_id = static_cast<int>(HexToInt(command_buffer + 1, command_length - 1)); |
| 589 | HexToInt(command_buffer + 1, | ||
| 590 | command_length - 1 /*strlen(reinterpret_cast<char*>(command_buffer) + 1)*/)); | ||
| 591 | if (thread_id == 0) { | 648 | if (thread_id == 0) { |
| 592 | thread_id = 1; | 649 | thread_id = 1; |
| 593 | } | 650 | } |
| @@ -610,16 +667,23 @@ static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { | |||
| 610 | 667 | ||
| 611 | latest_signal = signal; | 668 | latest_signal = signal; |
| 612 | 669 | ||
| 670 | if (!thread) { | ||
| 671 | full = false; | ||
| 672 | } | ||
| 673 | |||
| 613 | std::string buffer; | 674 | std::string buffer; |
| 614 | if (full) { | 675 | if (full) { |
| 615 | buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x};", latest_signal, PC_REGISTER, | 676 | buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x};{:02x}:{:016x}", latest_signal, |
| 616 | Common::swap64(RegRead(PC_REGISTER, thread)), SP_REGISTER, | 677 | PC_REGISTER, Common::swap64(RegRead(PC_REGISTER, thread)), SP_REGISTER, |
| 617 | Common::swap64(RegRead(SP_REGISTER, thread))); | 678 | Common::swap64(RegRead(SP_REGISTER, thread)), LR_REGISTER, |
| 679 | Common::swap64(RegRead(LR_REGISTER, thread))); | ||
| 618 | } else { | 680 | } else { |
| 619 | buffer = fmt::format("T{:02x};", latest_signal); | 681 | buffer = fmt::format("T{:02x}", latest_signal); |
| 620 | } | 682 | } |
| 621 | 683 | ||
| 622 | buffer += fmt::format("thread:{:x};", thread->GetThreadId()); | 684 | if (thread) { |
| 685 | buffer += fmt::format(";thread:{:x};", thread->GetThreadId()); | ||
| 686 | } | ||
| 623 | 687 | ||
| 624 | SendReply(buffer.c_str()); | 688 | SendReply(buffer.c_str()); |
| 625 | } | 689 | } |
| @@ -711,8 +775,12 @@ static void ReadRegister() { | |||
| 711 | LongToGdbHex(reply, RegRead(id, current_thread)); | 775 | LongToGdbHex(reply, RegRead(id, current_thread)); |
| 712 | } else if (id == CPSR_REGISTER) { | 776 | } else if (id == CPSR_REGISTER) { |
| 713 | IntToGdbHex(reply, (u32)RegRead(id, current_thread)); | 777 | IntToGdbHex(reply, (u32)RegRead(id, current_thread)); |
| 778 | } else if (id >= UC_ARM64_REG_Q0 && id < FPSCR_REGISTER) { | ||
| 779 | LongToGdbHex(reply, RegRead(id, current_thread)); | ||
| 780 | } else if (id == FPSCR_REGISTER) { | ||
| 781 | LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_998, current_thread)); | ||
| 714 | } else { | 782 | } else { |
| 715 | return SendReply("E01"); | 783 | LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_997, current_thread)); |
| 716 | } | 784 | } |
| 717 | 785 | ||
| 718 | SendReply(reinterpret_cast<char*>(reply)); | 786 | SendReply(reinterpret_cast<char*>(reply)); |
| @@ -729,7 +797,7 @@ static void ReadRegisters() { | |||
| 729 | LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread)); | 797 | LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread)); |
| 730 | } | 798 | } |
| 731 | 799 | ||
| 732 | bufptr += (32 * 16); | 800 | bufptr += 32 * 16; |
| 733 | 801 | ||
| 734 | LongToGdbHex(bufptr, RegRead(PC_REGISTER, current_thread)); | 802 | LongToGdbHex(bufptr, RegRead(PC_REGISTER, current_thread)); |
| 735 | 803 | ||
| @@ -739,6 +807,16 @@ static void ReadRegisters() { | |||
| 739 | 807 | ||
| 740 | bufptr += 8; | 808 | bufptr += 8; |
| 741 | 809 | ||
| 810 | for (int reg = UC_ARM64_REG_Q0; reg <= UC_ARM64_REG_Q0 + 31; reg++) { | ||
| 811 | LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread)); | ||
| 812 | } | ||
| 813 | |||
| 814 | bufptr += 32 * 32; | ||
| 815 | |||
| 816 | LongToGdbHex(bufptr, RegRead(TODO_DUMMY_REG_998, current_thread)); | ||
| 817 | |||
| 818 | bufptr += 8; | ||
| 819 | |||
| 742 | SendReply(reinterpret_cast<char*>(buffer)); | 820 | SendReply(reinterpret_cast<char*>(buffer)); |
| 743 | } | 821 | } |
| 744 | 822 | ||
| @@ -759,10 +837,17 @@ static void WriteRegister() { | |||
| 759 | RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); | 837 | RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); |
| 760 | } else if (id == CPSR_REGISTER) { | 838 | } else if (id == CPSR_REGISTER) { |
| 761 | RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); | 839 | RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); |
| 840 | } else if (id >= UC_ARM64_REG_Q0 && id < FPSCR_REGISTER) { | ||
| 841 | RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); | ||
| 842 | } else if (id == FPSCR_REGISTER) { | ||
| 843 | RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr), current_thread); | ||
| 762 | } else { | 844 | } else { |
| 763 | return SendReply("E01"); | 845 | RegWrite(TODO_DUMMY_REG_997, GdbHexToLong(buffer_ptr), current_thread); |
| 764 | } | 846 | } |
| 765 | 847 | ||
| 848 | // Update Unicorn context skipping scheduler, no running threads at this point | ||
| 849 | Core::System::GetInstance().ArmInterface(current_core).LoadContext(current_thread->context); | ||
| 850 | |||
| 766 | SendReply("OK"); | 851 | SendReply("OK"); |
| 767 | } | 852 | } |
| 768 | 853 | ||
| @@ -773,18 +858,25 @@ static void WriteRegisters() { | |||
| 773 | if (command_buffer[0] != 'G') | 858 | if (command_buffer[0] != 'G') |
| 774 | return SendReply("E01"); | 859 | return SendReply("E01"); |
| 775 | 860 | ||
| 776 | for (int i = 0, reg = 0; reg <= CPSR_REGISTER; i++, reg++) { | 861 | for (int i = 0, reg = 0; reg <= FPSCR_REGISTER; i++, reg++) { |
| 777 | if (reg <= SP_REGISTER) { | 862 | if (reg <= SP_REGISTER) { |
| 778 | RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); | 863 | RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); |
| 779 | } else if (reg == PC_REGISTER) { | 864 | } else if (reg == PC_REGISTER) { |
| 780 | RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); | 865 | RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); |
| 781 | } else if (reg == CPSR_REGISTER) { | 866 | } else if (reg == CPSR_REGISTER) { |
| 782 | RegWrite(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread); | 867 | RegWrite(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread); |
| 868 | } else if (reg >= UC_ARM64_REG_Q0 && reg < FPSCR_REGISTER) { | ||
| 869 | RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); | ||
| 870 | } else if (reg == FPSCR_REGISTER) { | ||
| 871 | RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr + i * 16), current_thread); | ||
| 783 | } else { | 872 | } else { |
| 784 | UNIMPLEMENTED(); | 873 | UNIMPLEMENTED(); |
| 785 | } | 874 | } |
| 786 | } | 875 | } |
| 787 | 876 | ||
| 877 | // Update Unicorn context skipping scheduler, no running threads at this point | ||
| 878 | Core::System::GetInstance().ArmInterface(current_core).LoadContext(current_thread->context); | ||
| 879 | |||
| 788 | SendReply("OK"); | 880 | SendReply("OK"); |
| 789 | } | 881 | } |
| 790 | 882 | ||
| @@ -806,6 +898,10 @@ static void ReadMemory() { | |||
| 806 | SendReply("E01"); | 898 | SendReply("E01"); |
| 807 | } | 899 | } |
| 808 | 900 | ||
| 901 | if (addr < Memory::PROCESS_IMAGE_VADDR || addr >= Memory::MAP_REGION_VADDR_END) { | ||
| 902 | return SendReply("E00"); | ||
| 903 | } | ||
| 904 | |||
| 809 | if (!Memory::IsValidVirtualAddress(addr)) { | 905 | if (!Memory::IsValidVirtualAddress(addr)) { |
| 810 | return SendReply("E00"); | 906 | return SendReply("E00"); |
| 811 | } | 907 | } |
| @@ -840,16 +936,18 @@ static void WriteMemory() { | |||
| 840 | } | 936 | } |
| 841 | 937 | ||
| 842 | void Break(bool is_memory_break) { | 938 | void Break(bool is_memory_break) { |
| 843 | if (!halt_loop) { | 939 | send_trap = true; |
| 844 | halt_loop = true; | ||
| 845 | send_trap = true; | ||
| 846 | } | ||
| 847 | 940 | ||
| 848 | memory_break = is_memory_break; | 941 | memory_break = is_memory_break; |
| 849 | } | 942 | } |
| 850 | 943 | ||
| 851 | /// Tell the CPU that it should perform a single step. | 944 | /// Tell the CPU that it should perform a single step. |
| 852 | static void Step() { | 945 | static void Step() { |
| 946 | if (command_length > 1) { | ||
| 947 | RegWrite(PC_REGISTER, GdbHexToLong(command_buffer + 1), current_thread); | ||
| 948 | // Update Unicorn context skipping scheduler, no running threads at this point | ||
| 949 | Core::System::GetInstance().ArmInterface(current_core).LoadContext(current_thread->context); | ||
| 950 | } | ||
| 853 | step_loop = true; | 951 | step_loop = true; |
| 854 | halt_loop = true; | 952 | halt_loop = true; |
| 855 | send_trap = true; | 953 | send_trap = true; |
| @@ -1090,6 +1188,8 @@ static void Init(u16 port) { | |||
| 1090 | breakpoints_read.clear(); | 1188 | breakpoints_read.clear(); |
| 1091 | breakpoints_write.clear(); | 1189 | breakpoints_write.clear(); |
| 1092 | 1190 | ||
| 1191 | modules.clear(); | ||
| 1192 | |||
| 1093 | // Start gdb server | 1193 | // Start gdb server |
| 1094 | LOG_INFO(Debug_GDBStub, "Starting GDB server on port {}...", port); | 1194 | LOG_INFO(Debug_GDBStub, "Starting GDB server on port {}...", port); |
| 1095 | 1195 | ||
| @@ -1192,8 +1292,12 @@ void SetCpuStepFlag(bool is_step) { | |||
| 1192 | 1292 | ||
| 1193 | void SendTrap(Kernel::Thread* thread, int trap) { | 1293 | void SendTrap(Kernel::Thread* thread, int trap) { |
| 1194 | if (send_trap) { | 1294 | if (send_trap) { |
| 1295 | if (!halt_loop || current_thread == thread) { | ||
| 1296 | current_thread = thread; | ||
| 1297 | SendSignal(thread, trap); | ||
| 1298 | } | ||
| 1299 | halt_loop = true; | ||
| 1195 | send_trap = false; | 1300 | send_trap = false; |
| 1196 | SendSignal(thread, trap); | ||
| 1197 | } | 1301 | } |
| 1198 | } | 1302 | } |
| 1199 | }; // namespace GDBStub | 1303 | }; // namespace GDBStub |