| // Copyright 2026 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| // This file contains a GDB server that can be used to with MPACT-Sim based |
| // simulators. It requires that the debugger (gdb, lldb, etc.) already |
| // supports your architecture. |
| |
| #ifndef MPACT_SIM_UTIL_GDBSERVER_GDBSERVER_H_ |
| #define MPACT_SIM_UTIL_GDBSERVER_GDBSERVER_H_ |
| |
| #include <cstdint> |
| #include <istream> |
| #include <ostream> |
| #include <string> |
| #include <string_view> |
| #include <vector> |
| |
| #include "absl/container/flat_hash_map.h" |
| #include "absl/types/span.h" |
| #include "mpact/sim/generic/core_debug_interface.h" |
| #include "mpact/sim/generic/debug_info.h" |
| #include "mpact/sim/util/renode/socket_streambuf.h" |
| |
| namespace mpact::sim::util::gdbserver { |
| |
| using ::mpact::sim::generic::DebugInfo; |
| using ::mpact::sim::util::renode::SocketStreambuf; |
| |
| class GdbServer { |
| public: |
| // The constructor takes a span of core debug interfaces (usually the sim |
| // top objects), and a debug info object to provide information about the |
| // registers. Programs should already be loaded onto the core debug |
| // interfaces before the Gdb server is connected. |
| |
| // For now, only one core is supported (core 0) - the others are ignored. |
| // Multiple cores will be supported in the future, but that requires that |
| // the cores can be set to operate in stop mode. Then, after that we can |
| // add support for non-stop mode with multiple cores. |
| |
| explicit GdbServer( |
| absl::Span<generic::CoreDebugInterface*> core_debug_interfaces, |
| const DebugInfo& debug_info); |
| ~GdbServer(); |
| |
| // Open the GDB server on the given port, wait for a connection, and process |
| // the GDB commands. |
| bool Connect(int port); |
| |
| private: |
| // Terminate the connection to the GDB client. |
| void Terminate(); |
| // Sends the given response to the GDB client. Wrapping it in the proper |
| // packet format and adding the checksum. |
| void Respond(std::string_view response); |
| // Sends the given error message to the GDB client in an error packet. |
| void SendError(std::string_view error); |
| |
| // Takes a GDB command string, verifies the checksum, and if it is valid, |
| // then submits the command to be parsed. |
| void AcceptGdbCommand(std::string_view command); |
| // Parses the given GDB command and calls the appropriate command handler. |
| void ParseGdbCommand(std::string_view command); |
| |
| std::string HexEncodeNumberInTargetEndianness(uint64_t number); |
| // GDB command handlers. |
| |
| // Halt the simulator. |
| void GdbHalt(); |
| // Return the halt reason. |
| std::string GetHaltReason(int thread_id); |
| void GdbHaltReason(); |
| // Continue the simulation. |
| void GdbContinue(std::string_view command); |
| void ContinueThread(int thread_id); |
| void GdbVContinue(std::string_view command); |
| // Detach from the simulator. |
| void GdbDetach(); |
| // Select the thread to operate on. |
| void GdbSelectThread(std::string_view command); |
| // Return the thread info. |
| void GdbThreadInfo(); |
| // Read memory from the simulator. |
| void GdbReadMemory(std::string_view address, std::string_view length); |
| // Write memory to the simulator. |
| void GdbWriteMemory(std::string_view address, std::string_view length, |
| std::string_view data); |
| // Read GPR registers from the simulator. |
| void GdbReadGprRegisters(); |
| // Write GPR registers to the simulator. |
| void GdbWriteGprRegisters(std::string_view data); |
| // Read a register from the simulator. |
| void GdbReadRegister(std::string_view register_number_str); |
| // Write a register to the simulator. |
| void GdbWriteRegister(std::string_view register_number_str, |
| std::string_view register_value_str); |
| // Query gdbserver features. |
| void GdbQuery(std::string_view command); |
| // Set gdbserver features. |
| void GdbSet(std::string_view command); |
| // Step the simulator. |
| void GdbStep(std::string_view command); |
| void StepThread(int thread_id); |
| // Add a breakpoint to the simulator. |
| void GdbAddBreakpoint(char type, std::string_view address_str, |
| std::string_view kind_str); |
| // Remove a breakpoint from the simulator. |
| void GdbRemoveBreakpoint(char type, std::string_view address_str, |
| std::string_view kind_str); |
| // Respond with the supported GDB features. |
| void GdbSupported(std::string_view command); |
| // Get the executable file name and program arguments. |
| void GdbExecAndArgs(std::string_view command); |
| // Get the host info. |
| void GdbHostInfo(); |
| |
| SocketStreambuf* out_buf_ = nullptr; |
| SocketStreambuf* in_buf_ = nullptr; |
| std::ostream* os_ = nullptr; |
| std::istream* is_ = nullptr; |
| |
| bool no_ack_mode_ = false; |
| bool no_ack_mode_latch_ = false; |
| bool error_message_supported_ = false; |
| uint8_t buffer_[16 * 1024]; |
| bool good_ = false; |
| int server_socket_ = -1; |
| int cli_fd_ = -1; |
| int current_thread_id_ = 0; |
| absl::flat_hash_map<char, int> thread_select_; |
| absl::Span<generic::CoreDebugInterface*> core_debug_interfaces_; |
| std::vector<int> halt_reasons_; |
| const DebugInfo& debug_info_; |
| }; |
| |
| } // namespace mpact::sim::util::gdbserver |
| |
| #endif // MPACT_SIM_UTIL_GDBSERVER_GDBSERVER_H_ |