diff options
Diffstat (limited to '')
| -rw-r--r-- | src/common/string_util.cpp | 2 | ||||
| -rw-r--r-- | src/core/arm/unicorn/arm_unicorn.cpp | 4 | ||||
| -rw-r--r-- | src/core/gdbstub/gdbstub.cpp | 194 | ||||
| -rw-r--r-- | src/core/gdbstub/gdbstub.h | 8 | ||||
| -rw-r--r-- | src/core/loader/deconstructed_rom_directory.cpp | 3 | ||||
| -rw-r--r-- | src/core/loader/nca.cpp | 4 | ||||
| -rw-r--r-- | src/core/loader/nro.cpp | 4 | ||||
| -rw-r--r-- | src/core/loader/nso.cpp | 4 |
8 files changed, 173 insertions, 50 deletions
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index ea9d8f77c..0027888c7 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp | |||
| @@ -134,7 +134,7 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _ | |||
| 134 | size_t dir_end = full_path.find_last_of("/" | 134 | size_t dir_end = full_path.find_last_of("/" |
| 135 | // windows needs the : included for something like just "C:" to be considered a directory | 135 | // windows needs the : included for something like just "C:" to be considered a directory |
| 136 | #ifdef _WIN32 | 136 | #ifdef _WIN32 |
| 137 | ":" | 137 | "\\:" |
| 138 | #endif | 138 | #endif |
| 139 | ); | 139 | ); |
| 140 | if (std::string::npos == dir_end) | 140 | if (std::string::npos == dir_end) |
diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index ce6c5616d..f239cf0ea 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp | |||
| @@ -193,11 +193,11 @@ void ARM_Unicorn::ExecuteInstructions(int num_instructions) { | |||
| 193 | } | 193 | } |
| 194 | Kernel::Thread* thread = Kernel::GetCurrentThread(); | 194 | Kernel::Thread* thread = Kernel::GetCurrentThread(); |
| 195 | SaveContext(thread->context); | 195 | SaveContext(thread->context); |
| 196 | if (last_bkpt_hit) { | 196 | if (last_bkpt_hit || (num_instructions == 1)) { |
| 197 | last_bkpt_hit = false; | 197 | last_bkpt_hit = false; |
| 198 | GDBStub::Break(); | 198 | GDBStub::Break(); |
| 199 | GDBStub::SendTrap(thread, 5); | ||
| 199 | } | 200 | } |
| 200 | GDBStub::SendTrap(thread, 5); | ||
| 201 | } | 201 | } |
| 202 | } | 202 | } |
| 203 | 203 | ||
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 |
diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h index f2418c9e4..a6b50c26c 100644 --- a/src/core/gdbstub/gdbstub.h +++ b/src/core/gdbstub/gdbstub.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #pragma once | 7 | #pragma once |
| 8 | 8 | ||
| 9 | #include <string> | ||
| 9 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 10 | #include "core/hle/kernel/thread.h" | 11 | #include "core/hle/kernel/thread.h" |
| 11 | 12 | ||
| @@ -51,6 +52,9 @@ bool IsServerEnabled(); | |||
| 51 | /// Returns true if there is an active socket connection. | 52 | /// Returns true if there is an active socket connection. |
| 52 | bool IsConnected(); | 53 | bool IsConnected(); |
| 53 | 54 | ||
| 55 | /// Register module. | ||
| 56 | void RegisterModule(std::string name, PAddr beg, PAddr end, bool add_elf_ext = true); | ||
| 57 | |||
| 54 | /** | 58 | /** |
| 55 | * Signal to the gdbstub server that it should halt CPU execution. | 59 | * Signal to the gdbstub server that it should halt CPU execution. |
| 56 | * | 60 | * |
| @@ -80,10 +84,10 @@ BreakpointAddress GetNextBreakpointFromAddress(PAddr addr, GDBStub::BreakpointTy | |||
| 80 | */ | 84 | */ |
| 81 | bool CheckBreakpoint(PAddr addr, GDBStub::BreakpointType type); | 85 | bool CheckBreakpoint(PAddr addr, GDBStub::BreakpointType type); |
| 82 | 86 | ||
| 83 | // If set to true, the CPU will halt at the beginning of the next CPU loop. | 87 | /// If set to true, the CPU will halt at the beginning of the next CPU loop. |
| 84 | bool GetCpuHaltFlag(); | 88 | bool GetCpuHaltFlag(); |
| 85 | 89 | ||
| 86 | // If set to true and the CPU is halted, the CPU will step one instruction. | 90 | /// If set to true and the CPU is halted, the CPU will step one instruction. |
| 87 | bool GetCpuStepFlag(); | 91 | bool GetCpuStepFlag(); |
| 88 | 92 | ||
| 89 | /** | 93 | /** |
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index eb7feb617..5fdb1d289 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "common/string_util.h" | 10 | #include "common/string_util.h" |
| 11 | #include "core/file_sys/romfs_factory.h" | 11 | #include "core/file_sys/romfs_factory.h" |
| 12 | #include "core/gdbstub/gdbstub.h" | ||
| 12 | #include "core/hle/kernel/process.h" | 13 | #include "core/hle/kernel/process.h" |
| 13 | #include "core/hle/kernel/resource_limit.h" | 14 | #include "core/hle/kernel/resource_limit.h" |
| 14 | #include "core/hle/service/filesystem/filesystem.h" | 15 | #include "core/hle/service/filesystem/filesystem.h" |
| @@ -133,6 +134,8 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( | |||
| 133 | next_load_addr = AppLoader_NSO::LoadModule(path, load_addr); | 134 | next_load_addr = AppLoader_NSO::LoadModule(path, load_addr); |
| 134 | if (next_load_addr) { | 135 | if (next_load_addr) { |
| 135 | LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); | 136 | LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); |
| 137 | // Register module with GDBStub | ||
| 138 | GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false); | ||
| 136 | } else { | 139 | } else { |
| 137 | next_load_addr = load_addr; | 140 | next_load_addr = load_addr; |
| 138 | } | 141 | } |
diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp index da064f8e3..0fd930ae2 100644 --- a/src/core/loader/nca.cpp +++ b/src/core/loader/nca.cpp | |||
| @@ -7,10 +7,12 @@ | |||
| 7 | #include "common/common_funcs.h" | 7 | #include "common/common_funcs.h" |
| 8 | #include "common/file_util.h" | 8 | #include "common/file_util.h" |
| 9 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "common/string_util.h" | ||
| 10 | #include "common/swap.h" | 11 | #include "common/swap.h" |
| 11 | #include "core/core.h" | 12 | #include "core/core.h" |
| 12 | #include "core/file_sys/program_metadata.h" | 13 | #include "core/file_sys/program_metadata.h" |
| 13 | #include "core/file_sys/romfs_factory.h" | 14 | #include "core/file_sys/romfs_factory.h" |
| 15 | #include "core/gdbstub/gdbstub.h" | ||
| 14 | #include "core/hle/kernel/process.h" | 16 | #include "core/hle/kernel/process.h" |
| 15 | #include "core/hle/kernel/resource_limit.h" | 17 | #include "core/hle/kernel/resource_limit.h" |
| 16 | #include "core/hle/service/filesystem/filesystem.h" | 18 | #include "core/hle/service/filesystem/filesystem.h" |
| @@ -259,6 +261,8 @@ ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr<Kernel::Process>& process) { | |||
| 259 | next_load_addr = AppLoader_NSO::LoadModule(module, nca->GetExeFsFile(module), load_addr); | 261 | next_load_addr = AppLoader_NSO::LoadModule(module, nca->GetExeFsFile(module), load_addr); |
| 260 | if (next_load_addr) { | 262 | if (next_load_addr) { |
| 261 | LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); | 263 | LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); |
| 264 | // Register module with GDBStub | ||
| 265 | GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false); | ||
| 262 | } else { | 266 | } else { |
| 263 | next_load_addr = load_addr; | 267 | next_load_addr = load_addr; |
| 264 | } | 268 | } |
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 3853cfa1a..4d7c69a22 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "common/swap.h" | 10 | #include "common/swap.h" |
| 11 | #include "core/core.h" | 11 | #include "core/core.h" |
| 12 | #include "core/gdbstub/gdbstub.h" | ||
| 12 | #include "core/hle/kernel/process.h" | 13 | #include "core/hle/kernel/process.h" |
| 13 | #include "core/hle/kernel/resource_limit.h" | 14 | #include "core/hle/kernel/resource_limit.h" |
| 14 | #include "core/loader/nro.h" | 15 | #include "core/loader/nro.h" |
| @@ -115,6 +116,9 @@ bool AppLoader_NRO::LoadNro(const std::string& path, VAddr load_base) { | |||
| 115 | codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); | 116 | codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); |
| 116 | Core::CurrentProcess()->LoadModule(codeset, load_base); | 117 | Core::CurrentProcess()->LoadModule(codeset, load_base); |
| 117 | 118 | ||
| 119 | // Register module with GDBStub | ||
| 120 | GDBStub::RegisterModule(codeset->name, load_base, load_base); | ||
| 121 | |||
| 118 | return true; | 122 | return true; |
| 119 | } | 123 | } |
| 120 | 124 | ||
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 7f84e4b1b..1c629e21f 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include "common/logging/log.h" | 10 | #include "common/logging/log.h" |
| 11 | #include "common/swap.h" | 11 | #include "common/swap.h" |
| 12 | #include "core/core.h" | 12 | #include "core/core.h" |
| 13 | #include "core/gdbstub/gdbstub.h" | ||
| 13 | #include "core/hle/kernel/process.h" | 14 | #include "core/hle/kernel/process.h" |
| 14 | #include "core/hle/kernel/resource_limit.h" | 15 | #include "core/hle/kernel/resource_limit.h" |
| 15 | #include "core/loader/nso.h" | 16 | #include "core/loader/nso.h" |
| @@ -147,6 +148,9 @@ VAddr AppLoader_NSO::LoadModule(const std::string& name, const std::vector<u8>& | |||
| 147 | codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); | 148 | codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); |
| 148 | Core::CurrentProcess()->LoadModule(codeset, load_base); | 149 | Core::CurrentProcess()->LoadModule(codeset, load_base); |
| 149 | 150 | ||
| 151 | // Register module with GDBStub | ||
| 152 | GDBStub::RegisterModule(codeset->name, load_base, load_base); | ||
| 153 | |||
| 150 | return load_base + image_size; | 154 | return load_base + image_size; |
| 151 | } | 155 | } |
| 152 | 156 | ||