diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/gdbstub/gdbstub.cpp | 123 |
1 files changed, 86 insertions, 37 deletions
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index bdcc889e0..687dea409 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp | |||
| @@ -71,10 +71,6 @@ constexpr u32 PSTATE_REGISTER = 33; | |||
| 71 | constexpr u32 UC_ARM64_REG_Q0 = 34; | 71 | constexpr u32 UC_ARM64_REG_Q0 = 34; |
| 72 | constexpr u32 FPCR_REGISTER = 66; | 72 | constexpr u32 FPCR_REGISTER = 66; |
| 73 | 73 | ||
| 74 | // TODO/WiP - Used while working on support for FPU | ||
| 75 | constexpr u32 TODO_DUMMY_REG_997 = 997; | ||
| 76 | constexpr u32 TODO_DUMMY_REG_998 = 998; | ||
| 77 | |||
| 78 | // For sample XML files see the GDB source /gdb/features | 74 | // For sample XML files see the GDB source /gdb/features |
| 79 | // GDB also wants the l character at the start | 75 | // GDB also wants the l character at the start |
| 80 | // This XML defines what the registers are for this specific ARM device | 76 | // This XML defines what the registers are for this specific ARM device |
| @@ -260,6 +256,36 @@ static void RegWrite(std::size_t id, u64 val, Kernel::Thread* thread = nullptr) | |||
| 260 | } | 256 | } |
| 261 | } | 257 | } |
| 262 | 258 | ||
| 259 | static u128 FpuRead(std::size_t id, Kernel::Thread* thread = nullptr) { | ||
| 260 | if (!thread) { | ||
| 261 | return u128{0}; | ||
| 262 | } | ||
| 263 | |||
| 264 | auto& thread_context = thread->GetContext(); | ||
| 265 | |||
| 266 | if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { | ||
| 267 | return thread_context.vector_registers[id - UC_ARM64_REG_Q0]; | ||
| 268 | } else if (id == FPCR_REGISTER) { | ||
| 269 | return u128{thread_context.fpcr, 0}; | ||
| 270 | } else { | ||
| 271 | return u128{0}; | ||
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 275 | static void FpuWrite(std::size_t id, u128 val, Kernel::Thread* thread = nullptr) { | ||
| 276 | if (!thread) { | ||
| 277 | return; | ||
| 278 | } | ||
| 279 | |||
| 280 | auto& thread_context = thread->GetContext(); | ||
| 281 | |||
| 282 | if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { | ||
| 283 | thread_context.vector_registers[id - UC_ARM64_REG_Q0] = val; | ||
| 284 | } else if (id == FPCR_REGISTER) { | ||
| 285 | thread_context.fpcr = val[0]; | ||
| 286 | } | ||
| 287 | } | ||
| 288 | |||
| 263 | /** | 289 | /** |
| 264 | * Turns hex string character into the equivalent byte. | 290 | * Turns hex string character into the equivalent byte. |
| 265 | * | 291 | * |
| @@ -409,6 +435,27 @@ static u64 GdbHexToLong(const u8* src) { | |||
| 409 | return output; | 435 | return output; |
| 410 | } | 436 | } |
| 411 | 437 | ||
| 438 | /** | ||
| 439 | * Convert a gdb-formatted hex string into a u128. | ||
| 440 | * | ||
| 441 | * @param src Pointer to hex string. | ||
| 442 | */ | ||
| 443 | static u128 GdbHexToU128(const u8* src) { | ||
| 444 | u128 output; | ||
| 445 | |||
| 446 | for (int i = 0; i < 16; i += 2) { | ||
| 447 | output[0] = (output[0] << 4) | HexCharToValue(src[15 - i - 1]); | ||
| 448 | output[0] = (output[0] << 4) | HexCharToValue(src[15 - i]); | ||
| 449 | } | ||
| 450 | |||
| 451 | for (int i = 0; i < 16; i += 2) { | ||
| 452 | output[1] = (output[1] << 4) | HexCharToValue(src[16 + 15 - i - 1]); | ||
| 453 | output[1] = (output[1] << 4) | HexCharToValue(src[16 + 15 - i]); | ||
| 454 | } | ||
| 455 | |||
| 456 | return output; | ||
| 457 | } | ||
| 458 | |||
| 412 | /// Read a byte from the gdb client. | 459 | /// Read a byte from the gdb client. |
| 413 | static u8 ReadByte() { | 460 | static u8 ReadByte() { |
| 414 | u8 c; | 461 | u8 c; |
| @@ -599,8 +646,7 @@ static void HandleQuery() { | |||
| 599 | for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { | 646 | for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { |
| 600 | const auto& threads = Core::System::GetInstance().Scheduler(core).GetThreadList(); | 647 | const auto& threads = Core::System::GetInstance().Scheduler(core).GetThreadList(); |
| 601 | for (const auto& thread : threads) { | 648 | for (const auto& thread : threads) { |
| 602 | val += fmt::format("{:x}", thread->GetThreadID()); | 649 | val += fmt::format("{:x},", thread->GetThreadID()); |
| 603 | val += ","; | ||
| 604 | } | 650 | } |
| 605 | } | 651 | } |
| 606 | val.pop_back(); | 652 | val.pop_back(); |
| @@ -791,11 +837,15 @@ static void ReadRegister() { | |||
| 791 | } else if (id == PSTATE_REGISTER) { | 837 | } else if (id == PSTATE_REGISTER) { |
| 792 | IntToGdbHex(reply, static_cast<u32>(RegRead(id, current_thread))); | 838 | IntToGdbHex(reply, static_cast<u32>(RegRead(id, current_thread))); |
| 793 | } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { | 839 | } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { |
| 794 | LongToGdbHex(reply, RegRead(id, current_thread)); | 840 | u128 r = FpuRead(id, current_thread); |
| 841 | LongToGdbHex(reply, r[0]); | ||
| 842 | LongToGdbHex(reply + 16, r[1]); | ||
| 795 | } else if (id == FPCR_REGISTER) { | 843 | } else if (id == FPCR_REGISTER) { |
| 796 | LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_998, current_thread)); | 844 | u128 r = FpuRead(id, current_thread); |
| 797 | } else { | 845 | IntToGdbHex(reply, static_cast<u32>(r[0])); |
| 798 | LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_997, current_thread)); | 846 | } else if (id == FPCR_REGISTER + 1) { |
| 847 | u128 r = FpuRead(id, current_thread); | ||
| 848 | IntToGdbHex(reply, static_cast<u32>(r[0] >> 32)); | ||
| 799 | } | 849 | } |
| 800 | 850 | ||
| 801 | SendReply(reinterpret_cast<char*>(reply)); | 851 | SendReply(reinterpret_cast<char*>(reply)); |
| @@ -822,13 +872,18 @@ static void ReadRegisters() { | |||
| 822 | 872 | ||
| 823 | bufptr += 8; | 873 | bufptr += 8; |
| 824 | 874 | ||
| 825 | for (u32 reg = UC_ARM64_REG_Q0; reg <= UC_ARM64_REG_Q0 + 31; reg++) { | 875 | u128 r; |
| 826 | LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread)); | 876 | |
| 877 | for (u32 reg = UC_ARM64_REG_Q0; reg < FPCR_REGISTER; reg++) { | ||
| 878 | r = FpuRead(reg, current_thread); | ||
| 879 | LongToGdbHex(bufptr + reg * 32, r[0]); | ||
| 880 | LongToGdbHex(bufptr + reg * 32 + 16, r[1]); | ||
| 827 | } | 881 | } |
| 828 | 882 | ||
| 829 | bufptr += 32 * 32; | 883 | bufptr += 32 * 32; |
| 830 | 884 | ||
| 831 | LongToGdbHex(bufptr, RegRead(TODO_DUMMY_REG_998, current_thread)); | 885 | r = FpuRead(FPCR_REGISTER, current_thread); |
| 886 | IntToGdbHex(bufptr, static_cast<u32>(r[0])); | ||
| 832 | 887 | ||
| 833 | bufptr += 8; | 888 | bufptr += 8; |
| 834 | 889 | ||
| @@ -853,14 +908,12 @@ static void WriteRegister() { | |||
| 853 | } else if (id == PSTATE_REGISTER) { | 908 | } else if (id == PSTATE_REGISTER) { |
| 854 | RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); | 909 | RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); |
| 855 | } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { | 910 | } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { |
| 856 | RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); | 911 | FpuWrite(id, GdbHexToU128(buffer_ptr), current_thread); |
| 857 | } else if (id == FPCR_REGISTER) { | 912 | } else if (id == FPCR_REGISTER) { |
| 858 | RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr), current_thread); | 913 | } else if (id == FPCR_REGISTER + 1) { |
| 859 | } else { | ||
| 860 | RegWrite(TODO_DUMMY_REG_997, GdbHexToLong(buffer_ptr), current_thread); | ||
| 861 | } | 914 | } |
| 862 | 915 | ||
| 863 | // Update Unicorn context skipping scheduler, no running threads at this point | 916 | // Update ARM context, skipping scheduler - no running threads at this point |
| 864 | Core::System::GetInstance() | 917 | Core::System::GetInstance() |
| 865 | .ArmInterface(current_core) | 918 | .ArmInterface(current_core) |
| 866 | .LoadContext(current_thread->GetContext()); | 919 | .LoadContext(current_thread->GetContext()); |
| @@ -885,13 +938,13 @@ static void WriteRegisters() { | |||
| 885 | } else if (reg >= UC_ARM64_REG_Q0 && reg < FPCR_REGISTER) { | 938 | } else if (reg >= UC_ARM64_REG_Q0 && reg < FPCR_REGISTER) { |
| 886 | RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); | 939 | RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); |
| 887 | } else if (reg == FPCR_REGISTER) { | 940 | } else if (reg == FPCR_REGISTER) { |
| 888 | RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr + i * 16), current_thread); | 941 | RegWrite(FPCR_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); |
| 889 | } else { | 942 | } else if (reg == FPCR_REGISTER + 1) { |
| 890 | UNIMPLEMENTED(); | 943 | RegWrite(FPCR_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); |
| 891 | } | 944 | } |
| 892 | } | 945 | } |
| 893 | 946 | ||
| 894 | // Update Unicorn context skipping scheduler, no running threads at this point | 947 | // Update ARM context, skipping scheduler - no running threads at this point |
| 895 | Core::System::GetInstance() | 948 | Core::System::GetInstance() |
| 896 | .ArmInterface(current_core) | 949 | .ArmInterface(current_core) |
| 897 | .LoadContext(current_thread->GetContext()); | 950 | .LoadContext(current_thread->GetContext()); |
| @@ -917,12 +970,6 @@ static void ReadMemory() { | |||
| 917 | SendReply("E01"); | 970 | SendReply("E01"); |
| 918 | } | 971 | } |
| 919 | 972 | ||
| 920 | const auto& vm_manager = Core::CurrentProcess()->VMManager(); | ||
| 921 | if (addr < vm_manager.GetCodeRegionBaseAddress() || | ||
| 922 | addr >= vm_manager.GetMapRegionEndAddress()) { | ||
| 923 | return SendReply("E00"); | ||
| 924 | } | ||
| 925 | |||
| 926 | if (!Memory::IsValidVirtualAddress(addr)) { | 973 | if (!Memory::IsValidVirtualAddress(addr)) { |
| 927 | return SendReply("E00"); | 974 | return SendReply("E00"); |
| 928 | } | 975 | } |
| @@ -967,7 +1014,7 @@ void Break(bool is_memory_break) { | |||
| 967 | static void Step() { | 1014 | static void Step() { |
| 968 | if (command_length > 1) { | 1015 | if (command_length > 1) { |
| 969 | RegWrite(PC_REGISTER, GdbHexToLong(command_buffer + 1), current_thread); | 1016 | RegWrite(PC_REGISTER, GdbHexToLong(command_buffer + 1), current_thread); |
| 970 | // Update Unicorn context skipping scheduler, no running threads at this point | 1017 | // Update ARM context, skipping scheduler - no running threads at this point |
| 971 | Core::System::GetInstance() | 1018 | Core::System::GetInstance() |
| 972 | .ArmInterface(current_core) | 1019 | .ArmInterface(current_core) |
| 973 | .LoadContext(current_thread->GetContext()); | 1020 | .LoadContext(current_thread->GetContext()); |
| @@ -1010,7 +1057,7 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) { | |||
| 1010 | breakpoint.addr = addr; | 1057 | breakpoint.addr = addr; |
| 1011 | breakpoint.len = len; | 1058 | breakpoint.len = len; |
| 1012 | Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size()); | 1059 | Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size()); |
| 1013 | static constexpr std::array<u8, 4> btrap{{0x00, 0x7d, 0x20, 0xd4}}; | 1060 | static constexpr std::array<u8, 4> btrap{0x00, 0x7d, 0x20, 0xd4}; |
| 1014 | Memory::WriteBlock(addr, btrap.data(), btrap.size()); | 1061 | Memory::WriteBlock(addr, btrap.data(), btrap.size()); |
| 1015 | Core::System::GetInstance().InvalidateCpuInstructionCaches(); | 1062 | Core::System::GetInstance().InvalidateCpuInstructionCaches(); |
| 1016 | p.insert({addr, breakpoint}); | 1063 | p.insert({addr, breakpoint}); |
| @@ -1321,13 +1368,15 @@ void SetCpuStepFlag(bool is_step) { | |||
| 1321 | } | 1368 | } |
| 1322 | 1369 | ||
| 1323 | void SendTrap(Kernel::Thread* thread, int trap) { | 1370 | void SendTrap(Kernel::Thread* thread, int trap) { |
| 1324 | if (send_trap) { | 1371 | if (!send_trap) { |
| 1325 | if (!halt_loop || current_thread == thread) { | 1372 | return; |
| 1326 | current_thread = thread; | ||
| 1327 | SendSignal(thread, trap); | ||
| 1328 | } | ||
| 1329 | halt_loop = true; | ||
| 1330 | send_trap = false; | ||
| 1331 | } | 1373 | } |
| 1374 | |||
| 1375 | if (!halt_loop || current_thread == thread) { | ||
| 1376 | current_thread = thread; | ||
| 1377 | SendSignal(thread, trap); | ||
| 1378 | } | ||
| 1379 | halt_loop = true; | ||
| 1380 | send_trap = false; | ||
| 1332 | } | 1381 | } |
| 1333 | }; // namespace GDBStub | 1382 | }; // namespace GDBStub |