blob: aea988de66e607004eceb2a0ccf1cb5db7e73bd3 [file]
// 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_