mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-18 19:23:56 +00:00
GDB stub progress
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)}};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user