GDB stub progress

This commit is contained in:
momo5502
2025-01-12 16:03:41 +01:00
parent 8adc73de71
commit 9e268ea4dc
9 changed files with 159 additions and 50 deletions

View File

@@ -48,6 +48,14 @@ namespace network
address(const sockaddr_in6& addr);
address(const sockaddr* addr, socklen_t length);
address(const address&) = default;
address(address&&) noexcept = default;
address& operator=(const address&) = default;
address& operator=(address&&) noexcept = default;
~address() = default;
void set_ipv4(uint32_t ip);
void set_ipv4(const in_addr& addr);
void set_ipv6(const in6_addr& addr);

View File

@@ -31,7 +31,7 @@ namespace network
socket::~socket()
{
this->release();
this->close();
}
socket::socket(socket&& obj) noexcept
@@ -43,7 +43,7 @@ namespace network
{
if (this != &obj)
{
this->release();
this->close();
this->socket_ = obj.socket_;
obj.socket_ = INVALID_SOCKET;
@@ -53,15 +53,20 @@ namespace network
}
socket::operator bool() const
{
return this->is_valid();
}
bool socket::is_valid() const
{
return this->socket_ != INVALID_SOCKET;
}
void socket::release()
void socket::close()
{
if (this->socket_ != INVALID_SOCKET)
{
closesocket(this->socket_);
::closesocket(this->socket_);
this->socket_ = INVALID_SOCKET;
}
}
@@ -90,7 +95,7 @@ namespace network
#endif
}
bool socket::sleep(const std::chrono::milliseconds timeout) const
bool socket::sleep(const std::chrono::milliseconds timeout, const bool in_poll) const
{
/*fd_set fdr;
FD_ZERO(&fdr);
@@ -119,13 +124,13 @@ namespace network
std::vector<const socket*> sockets{};
sockets.push_back(this);
return sleep_sockets(sockets, timeout);
return sleep_sockets(sockets, timeout, in_poll);
}
bool socket::sleep_until(const std::chrono::high_resolution_clock::time_point time_point) const
bool socket::sleep_until(const std::chrono::high_resolution_clock::time_point time_point, const bool in_poll) const
{
const auto duration = time_point - std::chrono::high_resolution_clock::now();
return this->sleep(std::chrono::duration_cast<std::chrono::milliseconds>(duration));
return this->sleep(std::chrono::duration_cast<std::chrono::milliseconds>(duration), in_poll);
}
SOCKET socket::get_socket() const
@@ -167,7 +172,13 @@ namespace network
return address->get_addr().sa_family;
}
bool socket::sleep_sockets(const std::span<const socket*>& sockets, const std::chrono::milliseconds timeout)
bool socket::is_ready(const bool in_poll) const
{
return this->is_valid() && is_socket_ready(this->socket_, in_poll);
}
bool socket::sleep_sockets(const std::span<const socket*>& sockets, const std::chrono::milliseconds timeout,
const bool in_poll)
{
std::vector<pollfd> pfds{};
pfds.resize(sockets.size());
@@ -178,7 +189,7 @@ namespace network
const auto& socket = sockets[i];
pfd.fd = socket->get_socket();
pfd.events = POLLIN;
pfd.events = in_poll ? POLLIN : POLLOUT;
pfd.revents = 0;
}
@@ -223,9 +234,10 @@ namespace network
}
bool socket::sleep_sockets_until(const std::span<const socket*>& sockets,
const std::chrono::high_resolution_clock::time_point time_point)
const std::chrono::high_resolution_clock::time_point time_point,
const bool in_poll)
{
const auto duration = time_point - std::chrono::high_resolution_clock::now();
return sleep_sockets(sockets, std::chrono::duration_cast<std::chrono::milliseconds>(duration));
return sleep_sockets(sockets, std::chrono::duration_cast<std::chrono::milliseconds>(duration), in_poll);
}
}

View File

@@ -10,7 +10,7 @@
using send_size = int;
#define GET_SOCKET_ERROR() (WSAGetLastError())
#define poll WSAPoll
#define SOCK_WOULDBLOCK WSAEWOULDBLOCK
#define SERR(x) (WSA##x)
#define SHUT_RDWR SD_BOTH
#else
using SOCKET = int;
@@ -19,7 +19,7 @@ using send_size = size_t;
#define SOCKET_ERROR (-1)
#define GET_SOCKET_ERROR() (errno)
#define closesocket close
#define SOCK_WOULDBLOCK EWOULDBLOCK
#define SERR(x) (x)
#endif
namespace network
@@ -42,14 +42,16 @@ namespace network
operator bool() const;
bool is_valid() const;
bool bind(const address& target);
bool set_blocking(bool blocking);
static bool set_blocking(SOCKET s, bool blocking);
static constexpr bool socket_is_ready = true;
bool sleep(std::chrono::milliseconds timeout) const;
bool sleep_until(std::chrono::high_resolution_clock::time_point time_point) const;
bool sleep(std::chrono::milliseconds timeout, bool in_poll = true) const;
bool sleep_until(std::chrono::high_resolution_clock::time_point time_point, bool in_poll = true) const;
SOCKET get_socket() const;
uint16_t get_port() const;
@@ -57,15 +59,18 @@ namespace network
int get_address_family() const;
static bool sleep_sockets(const std::span<const socket*>& sockets, std::chrono::milliseconds timeout);
bool is_ready(bool in_poll) const;
static bool sleep_sockets(const std::span<const socket*>& sockets, std::chrono::milliseconds timeout,
bool in_poll);
static bool sleep_sockets_until(const std::span<const socket*>& sockets,
std::chrono::high_resolution_clock::time_point time_point);
std::chrono::high_resolution_clock::time_point time_point, bool in_poll);
static bool is_socket_ready(SOCKET s, bool in_poll);
void close();
private:
SOCKET socket_ = INVALID_SOCKET;
void release();
};
}

View File

@@ -26,27 +26,52 @@ namespace network
bool tcp_client_socket::send(const void* data, const size_t size) const
{
const auto res = ::send(this->get_socket(), static_cast<const char*>(data), static_cast<send_size>(size), 0);
return static_cast<size_t>(res) == size;
return this->send(std::string_view(static_cast<const char*>(data), size));
}
bool tcp_client_socket::send(const std::string_view data) const
bool tcp_client_socket::send(std::string_view data) const
{
return this->send(data.data(), data.size());
while (!data.empty())
{
const auto res = ::send(this->get_socket(), data.data(), static_cast<send_size>(data.size()), 0);
if (res < 0)
{
if (GET_SOCKET_ERROR() != SERR(EWOULDBLOCK))
{
break;
}
this->sleep(std::chrono::milliseconds(10), true);
continue;
}
if (static_cast<size_t>(res) > data.size())
{
break;
}
data = data.substr(res);
}
return data.empty();
}
bool tcp_client_socket::receive(std::string& data) const
std::optional<std::string> tcp_client_socket::receive()
{
char buffer[0x2000];
const auto result = recv(this->get_socket(), buffer, static_cast<int>(sizeof(buffer)), 0);
if (result == SOCKET_ERROR)
if (result > 0)
{
return false;
return std::string(buffer, result);
}
data.assign(buffer, buffer + result);
return true;
if (result == 0 || (result < 0 && GET_SOCKET_ERROR() == SERR(ECONNRESET)))
{
this->close();
}
return std::nullopt;
}
std::optional<address> tcp_client_socket::get_target() const
@@ -69,6 +94,6 @@ namespace network
}
const auto error = GET_SOCKET_ERROR();
return error == SOCK_WOULDBLOCK;
return error == SERR(EWOULDBLOCK);
}
}

View File

@@ -21,7 +21,7 @@ namespace network
[[maybe_unused]] bool send(const void* data, size_t size) const;
[[maybe_unused]] bool send(std::string_view data) const;
bool receive(std::string& data) const;
std::optional<std::string> receive();
std::optional<address> get_target() const;

View File

@@ -9,29 +9,39 @@ namespace network
bool udp_socket::send(const address& target, const void* data, const size_t size) const
{
const auto res = sendto(this->get_socket(), static_cast<const char*>(data), static_cast<send_size>(size), 0,
&target.get_addr(), target.get_size());
return static_cast<size_t>(res) == size;
return this->send(target, std::string_view(static_cast<const char*>(data), size));
}
bool udp_socket::send(const address& target, const std::string_view data) const
{
return this->send(target, data.data(), data.size());
while (true)
{
const auto res = sendto(this->get_socket(), data.data(), static_cast<send_size>(data.size()), 0,
&target.get_addr(), target.get_size());
if (res < 0 && GET_SOCKET_ERROR() == SERR(EWOULDBLOCK))
{
this->sleep(std::chrono::milliseconds(10), true);
continue;
}
return static_cast<size_t>(res) == data.size();
}
}
bool udp_socket::receive(address& source, std::string& data) const
std::optional<std::pair<address, std::string>> udp_socket::receive() const
{
char buffer[0x2000];
address source{};
auto len = source.get_max_size();
const auto result =
recvfrom(this->get_socket(), buffer, static_cast<int>(sizeof(buffer)), 0, &source.get_addr(), &len);
if (result == SOCKET_ERROR)
{
return false;
return std::nullopt;
}
data.assign(buffer, buffer + result);
return true;
return {{source, std::string(buffer, result)}};
}
}

View File

@@ -17,6 +17,6 @@ namespace network
[[maybe_unused]] bool send(const address& target, const void* data, size_t size) const;
[[maybe_unused]] bool send(const address& target, std::string_view data) const;
bool receive(address& source, std::string& data) const;
std::optional<std::pair<address, std::string>> receive() const;
};
}

View File

@@ -21,6 +21,21 @@ namespace gdb_stub
return csum;
}
std::string compute_checksum_string(const std::string_view data)
{
const auto checksum = compute_checksum(data);
std::stringstream stream{};
stream << std::hex << checksum;
return stream.str();
}
bool send_packet_reply(const network::tcp_client_socket& socket, const std::string_view data)
{
const auto checksum = compute_checksum_string(data);
return socket.send("$" + std::string(data) + "#" + checksum);
}
network::tcp_client_socket accept_client(const network::address& bind_address)
{
network::tcp_server_socket server{bind_address.get_family()};
@@ -102,27 +117,61 @@ namespace gdb_stub
}
}
};
void read_from_socket(packet_queue& queue, network::tcp_client_socket& client)
{
while (client.is_ready(true))
{
auto packet = client.receive();
if (packet)
{
queue.enqueue(std::move(*packet));
}
}
}
void handle_command(const uint8_t command, const std::string_view data)
{
switch (command)
{
case 'q':
break;
}
}
void process_packet(const std::string_view packet)
{
if (packet.empty())
{
return;
}
const auto command = packet.front();
handle_command(command, packet.substr(1));
}
}
bool run_gdb_stub(const network::address& bind_address)
{
const auto client = accept_client(bind_address);
packet_queue queue{};
auto client = accept_client(bind_address);
if (!client)
{
return false;
}
packet_queue queue{};
client.set_blocking(false);
while (true)
{
std::string packet{};
if (!client.receive(packet))
{
break;
}
read_from_socket(queue, client);
queue.enqueue(packet);
while (!queue.packets.empty())
{
process_packet(queue.packets.front());
queue.packets.pop();
}
}
return true;

View File

@@ -457,7 +457,7 @@ namespace
if (recevied_data < 0)
{
const auto error = GET_SOCKET_ERROR();
if (error == SOCK_WOULDBLOCK)
if (error == SERR(EWOULDBLOCK))
{
this->delay_ioctrl(c, {}, true);
return STATUS_PENDING;
@@ -512,7 +512,7 @@ namespace
if (sent_data < 0)
{
const auto error = GET_SOCKET_ERROR();
if (error == SOCK_WOULDBLOCK)
if (error == SERR(EWOULDBLOCK))
{
this->delay_ioctrl(c, {}, false);
return STATUS_PENDING;