mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	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
This commit is contained in:
		
							parent
							
								
									ce23ae3ede
								
							
						
					
					
						commit
						e066bc75b9
					
				| @ -134,7 +134,7 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _ | |||||||
|     size_t dir_end = full_path.find_last_of("/" |     size_t dir_end = full_path.find_last_of("/" | ||||||
| // windows needs the : included for something like just "C:" to be considered a directory
 | // windows needs the : included for something like just "C:" to be considered a directory
 | ||||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||||
|                                             ":" |                                             "\\:" | ||||||
| #endif | #endif | ||||||
|     ); |     ); | ||||||
|     if (std::string::npos == dir_end) |     if (std::string::npos == dir_end) | ||||||
|  | |||||||
| @ -193,11 +193,11 @@ void ARM_Unicorn::ExecuteInstructions(int num_instructions) { | |||||||
|         } |         } | ||||||
|         Kernel::Thread* thread = Kernel::GetCurrentThread(); |         Kernel::Thread* thread = Kernel::GetCurrentThread(); | ||||||
|         SaveContext(thread->context); |         SaveContext(thread->context); | ||||||
|         if (last_bkpt_hit) { |         if (last_bkpt_hit || (num_instructions == 1)) { | ||||||
|             last_bkpt_hit = false; |             last_bkpt_hit = false; | ||||||
|             GDBStub::Break(); |             GDBStub::Break(); | ||||||
|  |             GDBStub::SendTrap(thread, 5); | ||||||
|         } |         } | ||||||
|         GDBStub::SendTrap(thread, 5); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -61,10 +61,16 @@ const u32 SIGTERM = 15; | |||||||
| const u32 MSG_WAITALL = 8; | const u32 MSG_WAITALL = 8; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| const u32 X30_REGISTER = 30; | const u32 LR_REGISTER = 30; | ||||||
| const u32 SP_REGISTER = 31; | const u32 SP_REGISTER = 31; | ||||||
| const u32 PC_REGISTER = 32; | const u32 PC_REGISTER = 32; | ||||||
| const u32 CPSR_REGISTER = 33; | const u32 CPSR_REGISTER = 33; | ||||||
|  | const u32 UC_ARM64_REG_Q0 = 34; | ||||||
|  | const u32 FPSCR_REGISTER = 66; | ||||||
|  | 
 | ||||||
|  | // TODO/WiP - Used while working on support for FPU
 | ||||||
|  | const u32 TODO_DUMMY_REG_997 = 997; | ||||||
|  | const u32 TODO_DUMMY_REG_998 = 998; | ||||||
| 
 | 
 | ||||||
| // For sample XML files see the GDB source /gdb/features
 | // For sample XML files see the GDB source /gdb/features
 | ||||||
| // GDB also wants the l character at the start
 | // GDB also wants the l character at the start
 | ||||||
| @ -130,6 +136,8 @@ static const char* target_xml = | |||||||
|     </flags> |     </flags> | ||||||
|     <reg name="cpsr" bitsize="32" type="cpsr_flags"/> |     <reg name="cpsr" bitsize="32" type="cpsr_flags"/> | ||||||
|   </feature> |   </feature> | ||||||
|  |   <feature name="org.gnu.gdb.aarch64.fpu"> | ||||||
|  |   </feature> | ||||||
| </target> | </target> | ||||||
| )"; | )"; | ||||||
| 
 | 
 | ||||||
| @ -144,6 +152,7 @@ static u32 latest_signal = 0; | |||||||
| static bool memory_break = false; | static bool memory_break = false; | ||||||
| 
 | 
 | ||||||
| static Kernel::Thread* current_thread = nullptr; | static Kernel::Thread* current_thread = nullptr; | ||||||
|  | static u32 current_core = 0; | ||||||
| 
 | 
 | ||||||
| // Binding to a port within the reserved ports range (0-1023) requires root permissions,
 | // Binding to a port within the reserved ports range (0-1023) requires root permissions,
 | ||||||
| // so default to a port outside of that range.
 | // so default to a port outside of that range.
 | ||||||
| @ -171,13 +180,34 @@ static std::map<u64, Breakpoint> breakpoints_execute; | |||||||
| static std::map<u64, Breakpoint> breakpoints_read; | static std::map<u64, Breakpoint> breakpoints_read; | ||||||
| static std::map<u64, Breakpoint> breakpoints_write; | static std::map<u64, Breakpoint> breakpoints_write; | ||||||
| 
 | 
 | ||||||
|  | struct Module { | ||||||
|  |     std::string name; | ||||||
|  |     PAddr beg; | ||||||
|  |     PAddr end; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static std::vector<Module> modules; | ||||||
|  | 
 | ||||||
|  | void RegisterModule(std::string name, PAddr beg, PAddr end, bool add_elf_ext) { | ||||||
|  |     Module module; | ||||||
|  |     if (add_elf_ext) { | ||||||
|  |         Common::SplitPath(name, nullptr, &module.name, nullptr); | ||||||
|  |         module.name += ".elf"; | ||||||
|  |     } else { | ||||||
|  |         module.name = std::move(name); | ||||||
|  |     } | ||||||
|  |     module.beg = beg; | ||||||
|  |     module.end = end; | ||||||
|  |     modules.push_back(std::move(module)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static Kernel::Thread* FindThreadById(int id) { | static Kernel::Thread* FindThreadById(int id) { | ||||||
|     for (int core = 0; core < Core::NUM_CPU_CORES; core++) { |     for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { | ||||||
|         auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); |         const auto& threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); | ||||||
|         for (auto thread : threads) { |         for (auto& thread : threads) { | ||||||
|             if (thread->GetThreadId() == id) { |             if (thread->GetThreadId() == id) { | ||||||
|                 current_thread = thread.get(); |                 current_core = core; | ||||||
|                 return current_thread; |                 return thread.get(); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -197,6 +227,8 @@ static u64 RegRead(int id, Kernel::Thread* thread = nullptr) { | |||||||
|         return thread->context.pc; |         return thread->context.pc; | ||||||
|     } else if (id == CPSR_REGISTER) { |     } else if (id == CPSR_REGISTER) { | ||||||
|         return thread->context.cpsr; |         return thread->context.cpsr; | ||||||
|  |     } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) { | ||||||
|  |         return thread->context.fpu_registers[id - UC_ARM64_REG_Q0][0]; | ||||||
|     } else { |     } else { | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
| @ -215,6 +247,8 @@ static void RegWrite(int id, u64 val, Kernel::Thread* thread = nullptr) { | |||||||
|         thread->context.pc = val; |         thread->context.pc = val; | ||||||
|     } else if (id == CPSR_REGISTER) { |     } else if (id == CPSR_REGISTER) { | ||||||
|         thread->context.cpsr = val; |         thread->context.cpsr = val; | ||||||
|  |     } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) { | ||||||
|  |         thread->context.fpu_registers[id - (CPSR_REGISTER + 1)][0] = val; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -534,7 +568,11 @@ static void HandleQuery() { | |||||||
|         SendReply("T0"); |         SendReply("T0"); | ||||||
|     } else if (strncmp(query, "Supported", strlen("Supported")) == 0) { |     } else if (strncmp(query, "Supported", strlen("Supported")) == 0) { | ||||||
|         // PacketSize needs to be large enough for target xml
 |         // PacketSize needs to be large enough for target xml
 | ||||||
|         SendReply("PacketSize=2000;qXfer:features:read+"); |         std::string buffer = "PacketSize=2000;qXfer:features:read+;qXfer:threads:read+"; | ||||||
|  |         if (!modules.empty()) { | ||||||
|  |             buffer += ";qXfer:libraries:read+"; | ||||||
|  |         } | ||||||
|  |         SendReply(buffer.c_str()); | ||||||
|     } else if (strncmp(query, "Xfer:features:read:target.xml:", |     } else if (strncmp(query, "Xfer:features:read:target.xml:", | ||||||
|                        strlen("Xfer:features:read:target.xml:")) == 0) { |                        strlen("Xfer:features:read:target.xml:")) == 0) { | ||||||
|         SendReply(target_xml); |         SendReply(target_xml); | ||||||
| @ -543,9 +581,9 @@ static void HandleQuery() { | |||||||
|         SendReply(buffer.c_str()); |         SendReply(buffer.c_str()); | ||||||
|     } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { |     } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { | ||||||
|         std::string val = "m"; |         std::string val = "m"; | ||||||
|         for (int core = 0; core < Core::NUM_CPU_CORES; core++) { |         for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { | ||||||
|             auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); |             const auto& threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); | ||||||
|             for (auto thread : threads) { |             for (const auto& thread : threads) { | ||||||
|                 val += fmt::format("{:x}", thread->GetThreadId()); |                 val += fmt::format("{:x}", thread->GetThreadId()); | ||||||
|                 val += ","; |                 val += ","; | ||||||
|             } |             } | ||||||
| @ -554,6 +592,31 @@ static void HandleQuery() { | |||||||
|         SendReply(val.c_str()); |         SendReply(val.c_str()); | ||||||
|     } else if (strncmp(query, "sThreadInfo", strlen("sThreadInfo")) == 0) { |     } else if (strncmp(query, "sThreadInfo", strlen("sThreadInfo")) == 0) { | ||||||
|         SendReply("l"); |         SendReply("l"); | ||||||
|  |     } else if (strncmp(query, "Xfer:threads:read", strlen("Xfer:threads:read")) == 0) { | ||||||
|  |         std::string buffer; | ||||||
|  |         buffer += "l<?xml version=\"1.0\"?>"; | ||||||
|  |         buffer += "<threads>"; | ||||||
|  |         for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { | ||||||
|  |             const auto& threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); | ||||||
|  |             for (const auto& thread : threads) { | ||||||
|  |                 buffer += | ||||||
|  |                     fmt::format(R"*(<thread id="{:x}" core="{:d}" name="Thread {:x}"></thread>)*", | ||||||
|  |                                 thread->GetThreadId(), core, thread->GetThreadId()); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         buffer += "</threads>"; | ||||||
|  |         SendReply(buffer.c_str()); | ||||||
|  |     } else if (strncmp(query, "Xfer:libraries:read", strlen("Xfer:libraries:read")) == 0) { | ||||||
|  |         std::string buffer; | ||||||
|  |         buffer += "l<?xml version=\"1.0\"?>"; | ||||||
|  |         buffer += "<library-list>"; | ||||||
|  |         for (const auto& module : modules) { | ||||||
|  |             buffer += | ||||||
|  |                 fmt::format(R"*("<library name = "{}"><segment address = "0x{:x}"/></library>)*", | ||||||
|  |                             module.name, module.beg); | ||||||
|  |         } | ||||||
|  |         buffer += "</library-list>"; | ||||||
|  |         SendReply(buffer.c_str()); | ||||||
|     } else { |     } else { | ||||||
|         SendReply(""); |         SendReply(""); | ||||||
|     } |     } | ||||||
| @ -561,33 +624,27 @@ static void HandleQuery() { | |||||||
| 
 | 
 | ||||||
| /// Handle set thread command from gdb client.
 | /// Handle set thread command from gdb client.
 | ||||||
| static void HandleSetThread() { | static void HandleSetThread() { | ||||||
|     if (memcmp(command_buffer, "Hc", 2) == 0 || memcmp(command_buffer, "Hg", 2) == 0) { |     int thread_id = -1; | ||||||
|         int thread_id = -1; |     if (command_buffer[2] != '-') { | ||||||
|         if (command_buffer[2] != '-') { |         thread_id = static_cast<int>(HexToInt(command_buffer + 2, command_length - 2)); | ||||||
|             thread_id = static_cast<int>(HexToInt( |     } | ||||||
|                 command_buffer + 2, |     if (thread_id >= 1) { | ||||||
|                 command_length - 2 /*strlen(reinterpret_cast<char*>(command_buffer) + 2)*/)); |         current_thread = FindThreadById(thread_id); | ||||||
|         } |     } | ||||||
|         if (thread_id >= 1) { |     if (!current_thread) { | ||||||
|             current_thread = FindThreadById(thread_id); |         thread_id = 1; | ||||||
|         } |         current_thread = FindThreadById(thread_id); | ||||||
|         if (!current_thread) { |     } | ||||||
|             thread_id = 1; |     if (current_thread) { | ||||||
|             current_thread = FindThreadById(thread_id); |         SendReply("OK"); | ||||||
|         } |         return; | ||||||
|         if (current_thread) { |  | ||||||
|             SendReply("OK"); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|     SendReply("E01"); |     SendReply("E01"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Handle thread alive command from gdb client.
 | /// Handle thread alive command from gdb client.
 | ||||||
| static void HandleThreadAlive() { | static void HandleThreadAlive() { | ||||||
|     int thread_id = static_cast<int>( |     int thread_id = static_cast<int>(HexToInt(command_buffer + 1, command_length - 1)); | ||||||
|         HexToInt(command_buffer + 1, |  | ||||||
|                  command_length - 1 /*strlen(reinterpret_cast<char*>(command_buffer) + 1)*/)); |  | ||||||
|     if (thread_id == 0) { |     if (thread_id == 0) { | ||||||
|         thread_id = 1; |         thread_id = 1; | ||||||
|     } |     } | ||||||
| @ -610,16 +667,23 @@ static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { | |||||||
| 
 | 
 | ||||||
|     latest_signal = signal; |     latest_signal = signal; | ||||||
| 
 | 
 | ||||||
|     std::string buffer; |     if (!thread) { | ||||||
|     if (full) { |         full = false; | ||||||
|         buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x};", latest_signal, PC_REGISTER, |  | ||||||
|                              Common::swap64(RegRead(PC_REGISTER, thread)), SP_REGISTER, |  | ||||||
|                              Common::swap64(RegRead(SP_REGISTER, thread))); |  | ||||||
|     } else { |  | ||||||
|         buffer = fmt::format("T{:02x};", latest_signal); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     buffer += fmt::format("thread:{:x};", thread->GetThreadId()); |     std::string buffer; | ||||||
|  |     if (full) { | ||||||
|  |         buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x};{:02x}:{:016x}", latest_signal, | ||||||
|  |                              PC_REGISTER, Common::swap64(RegRead(PC_REGISTER, thread)), SP_REGISTER, | ||||||
|  |                              Common::swap64(RegRead(SP_REGISTER, thread)), LR_REGISTER, | ||||||
|  |                              Common::swap64(RegRead(LR_REGISTER, thread))); | ||||||
|  |     } else { | ||||||
|  |         buffer = fmt::format("T{:02x}", latest_signal); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (thread) { | ||||||
|  |         buffer += fmt::format(";thread:{:x};", thread->GetThreadId()); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     SendReply(buffer.c_str()); |     SendReply(buffer.c_str()); | ||||||
| } | } | ||||||
| @ -711,8 +775,12 @@ static void ReadRegister() { | |||||||
|         LongToGdbHex(reply, RegRead(id, current_thread)); |         LongToGdbHex(reply, RegRead(id, current_thread)); | ||||||
|     } else if (id == CPSR_REGISTER) { |     } else if (id == CPSR_REGISTER) { | ||||||
|         IntToGdbHex(reply, (u32)RegRead(id, current_thread)); |         IntToGdbHex(reply, (u32)RegRead(id, current_thread)); | ||||||
|  |     } else if (id >= UC_ARM64_REG_Q0 && id < FPSCR_REGISTER) { | ||||||
|  |         LongToGdbHex(reply, RegRead(id, current_thread)); | ||||||
|  |     } else if (id == FPSCR_REGISTER) { | ||||||
|  |         LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_998, current_thread)); | ||||||
|     } else { |     } else { | ||||||
|         return SendReply("E01"); |         LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_997, current_thread)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     SendReply(reinterpret_cast<char*>(reply)); |     SendReply(reinterpret_cast<char*>(reply)); | ||||||
| @ -729,7 +797,7 @@ static void ReadRegisters() { | |||||||
|         LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread)); |         LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     bufptr += (32 * 16); |     bufptr += 32 * 16; | ||||||
| 
 | 
 | ||||||
|     LongToGdbHex(bufptr, RegRead(PC_REGISTER, current_thread)); |     LongToGdbHex(bufptr, RegRead(PC_REGISTER, current_thread)); | ||||||
| 
 | 
 | ||||||
| @ -739,6 +807,16 @@ static void ReadRegisters() { | |||||||
| 
 | 
 | ||||||
|     bufptr += 8; |     bufptr += 8; | ||||||
| 
 | 
 | ||||||
|  |     for (int reg = UC_ARM64_REG_Q0; reg <= UC_ARM64_REG_Q0 + 31; reg++) { | ||||||
|  |         LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bufptr += 32 * 32; | ||||||
|  | 
 | ||||||
|  |     LongToGdbHex(bufptr, RegRead(TODO_DUMMY_REG_998, current_thread)); | ||||||
|  | 
 | ||||||
|  |     bufptr += 8; | ||||||
|  | 
 | ||||||
|     SendReply(reinterpret_cast<char*>(buffer)); |     SendReply(reinterpret_cast<char*>(buffer)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -759,10 +837,17 @@ static void WriteRegister() { | |||||||
|         RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); |         RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); | ||||||
|     } else if (id == CPSR_REGISTER) { |     } else if (id == CPSR_REGISTER) { | ||||||
|         RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); |         RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); | ||||||
|  |     } else if (id >= UC_ARM64_REG_Q0 && id < FPSCR_REGISTER) { | ||||||
|  |         RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); | ||||||
|  |     } else if (id == FPSCR_REGISTER) { | ||||||
|  |         RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr), current_thread); | ||||||
|     } else { |     } else { | ||||||
|         return SendReply("E01"); |         RegWrite(TODO_DUMMY_REG_997, GdbHexToLong(buffer_ptr), current_thread); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     // Update Unicorn context skipping scheduler, no running threads at this point
 | ||||||
|  |     Core::System::GetInstance().ArmInterface(current_core).LoadContext(current_thread->context); | ||||||
|  | 
 | ||||||
|     SendReply("OK"); |     SendReply("OK"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -773,18 +858,25 @@ static void WriteRegisters() { | |||||||
|     if (command_buffer[0] != 'G') |     if (command_buffer[0] != 'G') | ||||||
|         return SendReply("E01"); |         return SendReply("E01"); | ||||||
| 
 | 
 | ||||||
|     for (int i = 0, reg = 0; reg <= CPSR_REGISTER; i++, reg++) { |     for (int i = 0, reg = 0; reg <= FPSCR_REGISTER; i++, reg++) { | ||||||
|         if (reg <= SP_REGISTER) { |         if (reg <= SP_REGISTER) { | ||||||
|             RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); |             RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); | ||||||
|         } else if (reg == PC_REGISTER) { |         } else if (reg == PC_REGISTER) { | ||||||
|             RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); |             RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); | ||||||
|         } else if (reg == CPSR_REGISTER) { |         } else if (reg == CPSR_REGISTER) { | ||||||
|             RegWrite(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread); |             RegWrite(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread); | ||||||
|  |         } else if (reg >= UC_ARM64_REG_Q0 && reg < FPSCR_REGISTER) { | ||||||
|  |             RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); | ||||||
|  |         } else if (reg == FPSCR_REGISTER) { | ||||||
|  |             RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr + i * 16), current_thread); | ||||||
|         } else { |         } else { | ||||||
|             UNIMPLEMENTED(); |             UNIMPLEMENTED(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     // Update Unicorn context skipping scheduler, no running threads at this point
 | ||||||
|  |     Core::System::GetInstance().ArmInterface(current_core).LoadContext(current_thread->context); | ||||||
|  | 
 | ||||||
|     SendReply("OK"); |     SendReply("OK"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -806,6 +898,10 @@ static void ReadMemory() { | |||||||
|         SendReply("E01"); |         SendReply("E01"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     if (addr < Memory::PROCESS_IMAGE_VADDR || addr >= Memory::MAP_REGION_VADDR_END) { | ||||||
|  |         return SendReply("E00"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     if (!Memory::IsValidVirtualAddress(addr)) { |     if (!Memory::IsValidVirtualAddress(addr)) { | ||||||
|         return SendReply("E00"); |         return SendReply("E00"); | ||||||
|     } |     } | ||||||
| @ -840,16 +936,18 @@ static void WriteMemory() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Break(bool is_memory_break) { | void Break(bool is_memory_break) { | ||||||
|     if (!halt_loop) { |     send_trap = true; | ||||||
|         halt_loop = true; |  | ||||||
|         send_trap = true; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     memory_break = is_memory_break; |     memory_break = is_memory_break; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Tell the CPU that it should perform a single step.
 | /// Tell the CPU that it should perform a single step.
 | ||||||
| static void Step() { | static void Step() { | ||||||
|  |     if (command_length > 1) { | ||||||
|  |         RegWrite(PC_REGISTER, GdbHexToLong(command_buffer + 1), current_thread); | ||||||
|  |         // Update Unicorn context skipping scheduler, no running threads at this point
 | ||||||
|  |         Core::System::GetInstance().ArmInterface(current_core).LoadContext(current_thread->context); | ||||||
|  |     } | ||||||
|     step_loop = true; |     step_loop = true; | ||||||
|     halt_loop = true; |     halt_loop = true; | ||||||
|     send_trap = true; |     send_trap = true; | ||||||
| @ -1090,6 +1188,8 @@ static void Init(u16 port) { | |||||||
|     breakpoints_read.clear(); |     breakpoints_read.clear(); | ||||||
|     breakpoints_write.clear(); |     breakpoints_write.clear(); | ||||||
| 
 | 
 | ||||||
|  |     modules.clear(); | ||||||
|  | 
 | ||||||
|     // Start gdb server
 |     // Start gdb server
 | ||||||
|     LOG_INFO(Debug_GDBStub, "Starting GDB server on port {}...", port); |     LOG_INFO(Debug_GDBStub, "Starting GDB server on port {}...", port); | ||||||
| 
 | 
 | ||||||
| @ -1192,8 +1292,12 @@ void SetCpuStepFlag(bool is_step) { | |||||||
| 
 | 
 | ||||||
| void SendTrap(Kernel::Thread* thread, int trap) { | void SendTrap(Kernel::Thread* thread, int trap) { | ||||||
|     if (send_trap) { |     if (send_trap) { | ||||||
|  |         if (!halt_loop || current_thread == thread) { | ||||||
|  |             current_thread = thread; | ||||||
|  |             SendSignal(thread, trap); | ||||||
|  |         } | ||||||
|  |         halt_loop = true; | ||||||
|         send_trap = false; |         send_trap = false; | ||||||
|         SendSignal(thread, trap); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| }; // namespace GDBStub
 | }; // namespace GDBStub
 | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ | |||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
|  | #include <string> | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| #include "core/hle/kernel/thread.h" | #include "core/hle/kernel/thread.h" | ||||||
| 
 | 
 | ||||||
| @ -51,6 +52,9 @@ bool IsServerEnabled(); | |||||||
| /// Returns true if there is an active socket connection.
 | /// Returns true if there is an active socket connection.
 | ||||||
| bool IsConnected(); | bool IsConnected(); | ||||||
| 
 | 
 | ||||||
|  | /// Register module.
 | ||||||
|  | void RegisterModule(std::string name, PAddr beg, PAddr end, bool add_elf_ext = true); | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Signal to the gdbstub server that it should halt CPU execution. |  * Signal to the gdbstub server that it should halt CPU execution. | ||||||
|  * |  * | ||||||
| @ -80,10 +84,10 @@ BreakpointAddress GetNextBreakpointFromAddress(PAddr addr, GDBStub::BreakpointTy | |||||||
|  */ |  */ | ||||||
| bool CheckBreakpoint(PAddr addr, GDBStub::BreakpointType type); | bool CheckBreakpoint(PAddr addr, GDBStub::BreakpointType type); | ||||||
| 
 | 
 | ||||||
| // If set to true, the CPU will halt at the beginning of the next CPU loop.
 | /// If set to true, the CPU will halt at the beginning of the next CPU loop.
 | ||||||
| bool GetCpuHaltFlag(); | bool GetCpuHaltFlag(); | ||||||
| 
 | 
 | ||||||
| // If set to true and the CPU is halted, the CPU will step one instruction.
 | /// If set to true and the CPU is halted, the CPU will step one instruction.
 | ||||||
| bool GetCpuStepFlag(); | bool GetCpuStepFlag(); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | |||||||
| @ -9,6 +9,7 @@ | |||||||
| #include "common/logging/log.h" | #include "common/logging/log.h" | ||||||
| #include "common/string_util.h" | #include "common/string_util.h" | ||||||
| #include "core/file_sys/romfs_factory.h" | #include "core/file_sys/romfs_factory.h" | ||||||
|  | #include "core/gdbstub/gdbstub.h" | ||||||
| #include "core/hle/kernel/process.h" | #include "core/hle/kernel/process.h" | ||||||
| #include "core/hle/kernel/resource_limit.h" | #include "core/hle/kernel/resource_limit.h" | ||||||
| #include "core/hle/service/filesystem/filesystem.h" | #include "core/hle/service/filesystem/filesystem.h" | ||||||
| @ -133,6 +134,8 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( | |||||||
|         next_load_addr = AppLoader_NSO::LoadModule(path, load_addr); |         next_load_addr = AppLoader_NSO::LoadModule(path, load_addr); | ||||||
|         if (next_load_addr) { |         if (next_load_addr) { | ||||||
|             LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); |             LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); | ||||||
|  |             // Register module with GDBStub
 | ||||||
|  |             GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false); | ||||||
|         } else { |         } else { | ||||||
|             next_load_addr = load_addr; |             next_load_addr = load_addr; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -7,10 +7,12 @@ | |||||||
| #include "common/common_funcs.h" | #include "common/common_funcs.h" | ||||||
| #include "common/file_util.h" | #include "common/file_util.h" | ||||||
| #include "common/logging/log.h" | #include "common/logging/log.h" | ||||||
|  | #include "common/string_util.h" | ||||||
| #include "common/swap.h" | #include "common/swap.h" | ||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
| #include "core/file_sys/program_metadata.h" | #include "core/file_sys/program_metadata.h" | ||||||
| #include "core/file_sys/romfs_factory.h" | #include "core/file_sys/romfs_factory.h" | ||||||
|  | #include "core/gdbstub/gdbstub.h" | ||||||
| #include "core/hle/kernel/process.h" | #include "core/hle/kernel/process.h" | ||||||
| #include "core/hle/kernel/resource_limit.h" | #include "core/hle/kernel/resource_limit.h" | ||||||
| #include "core/hle/service/filesystem/filesystem.h" | #include "core/hle/service/filesystem/filesystem.h" | ||||||
| @ -259,6 +261,8 @@ ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr<Kernel::Process>& process) { | |||||||
|         next_load_addr = AppLoader_NSO::LoadModule(module, nca->GetExeFsFile(module), load_addr); |         next_load_addr = AppLoader_NSO::LoadModule(module, nca->GetExeFsFile(module), load_addr); | ||||||
|         if (next_load_addr) { |         if (next_load_addr) { | ||||||
|             LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); |             LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); | ||||||
|  |             // Register module with GDBStub
 | ||||||
|  |             GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false); | ||||||
|         } else { |         } else { | ||||||
|             next_load_addr = load_addr; |             next_load_addr = load_addr; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -9,6 +9,7 @@ | |||||||
| #include "common/logging/log.h" | #include "common/logging/log.h" | ||||||
| #include "common/swap.h" | #include "common/swap.h" | ||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
|  | #include "core/gdbstub/gdbstub.h" | ||||||
| #include "core/hle/kernel/process.h" | #include "core/hle/kernel/process.h" | ||||||
| #include "core/hle/kernel/resource_limit.h" | #include "core/hle/kernel/resource_limit.h" | ||||||
| #include "core/loader/nro.h" | #include "core/loader/nro.h" | ||||||
| @ -115,6 +116,9 @@ bool AppLoader_NRO::LoadNro(const std::string& path, VAddr load_base) { | |||||||
|     codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); |     codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); | ||||||
|     Core::CurrentProcess()->LoadModule(codeset, load_base); |     Core::CurrentProcess()->LoadModule(codeset, load_base); | ||||||
| 
 | 
 | ||||||
|  |     // Register module with GDBStub
 | ||||||
|  |     GDBStub::RegisterModule(codeset->name, load_base, load_base); | ||||||
|  | 
 | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -10,6 +10,7 @@ | |||||||
| #include "common/logging/log.h" | #include "common/logging/log.h" | ||||||
| #include "common/swap.h" | #include "common/swap.h" | ||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
|  | #include "core/gdbstub/gdbstub.h" | ||||||
| #include "core/hle/kernel/process.h" | #include "core/hle/kernel/process.h" | ||||||
| #include "core/hle/kernel/resource_limit.h" | #include "core/hle/kernel/resource_limit.h" | ||||||
| #include "core/loader/nso.h" | #include "core/loader/nso.h" | ||||||
| @ -147,6 +148,9 @@ VAddr AppLoader_NSO::LoadModule(const std::string& name, const std::vector<u8>& | |||||||
|     codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); |     codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); | ||||||
|     Core::CurrentProcess()->LoadModule(codeset, load_base); |     Core::CurrentProcess()->LoadModule(codeset, load_base); | ||||||
| 
 | 
 | ||||||
|  |     // Register module with GDBStub
 | ||||||
|  |     GDBStub::RegisterModule(codeset->name, load_base, load_base); | ||||||
|  | 
 | ||||||
|     return load_base + image_size; |     return load_base + image_size; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Hedges
						Hedges