blob: 42bf4383bbc99bb599831b2f6190209fb3ff1856 [file] [log] [blame]
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_DEBUG_WASM_GDB_SERVER_TRANSPORT_H_
#define V8_DEBUG_WASM_GDB_SERVER_TRANSPORT_H_
#include <sstream>
#include <vector>
#include "src/base/macros.h"
#include "src/debug/wasm/gdb-server/gdb-remote-util.h"
#if _WIN32
#include <windows.h>
#include <winsock2.h>
typedef SOCKET SocketHandle;
#define CloseSocket closesocket
#define InvalidSocket INVALID_SOCKET
#define SocketGetLastError() WSAGetLastError()
static const int kErrInterrupt = WSAEINTR;
typedef int ssize_t;
typedef int socklen_t;
#else // _WIN32
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string>
typedef int SocketHandle;
#define CloseSocket close
#define InvalidSocket (-1)
#define SocketGetLastError() errno
static const int kErrInterrupt = EINTR;
#endif // _WIN32
namespace v8 {
namespace internal {
namespace wasm {
namespace gdb_server {
class SocketTransport;
// Acts as a factory for Transport objects bound to a specified TCP port.
class SocketBinding {
public:
// Wrap existing socket handle.
explicit SocketBinding(SocketHandle socket_handle);
// Bind to the specified TCP port.
static SocketBinding Bind(uint16_t tcp_port);
bool IsValid() const { return socket_handle_ != InvalidSocket; }
// Create a transport object from this socket binding
std::unique_ptr<SocketTransport> CreateTransport();
// Get port the socket is bound to.
uint16_t GetBoundPort();
private:
SocketHandle socket_handle_;
};
class V8_EXPORT_PRIVATE TransportBase {
public:
virtual ~TransportBase() {}
// Waits for an incoming connection on the bound port.
virtual bool AcceptConnection() = 0;
// Read {len} bytes from this transport, possibly blocking until enough data
// is available.
// {dst} must point to a buffer large enough to contain {len} bytes.
// Returns true on success.
// Returns false if the connection is closed; in that case the {dst} may have
// been partially overwritten.
virtual bool Read(char* dst, int32_t len) = 0;
// Write {len} bytes to this transport.
// Return true on success, false if the connection is closed.
virtual bool Write(const char* src, int32_t len) = 0;
// Return true if there is data to read.
virtual bool IsDataAvailable() const = 0;
// If we are connected to a debugger, gracefully closes the connection.
// This should be called when a debugging session gets closed.
virtual void Disconnect() = 0;
// Shuts down this transport, gracefully closing the existing connection and
// also closing the listening socket. This should be called when the GDB stub
// shuts down, when the program terminates.
virtual void Close() = 0;
// Blocks waiting for one of these two events to occur:
// - A network event (a new packet arrives, or the connection is dropped),
// - A thread event is signaled (the execution stopped because of a trap or
// breakpoint).
virtual void WaitForDebugStubEvent() = 0;
// Signal that this transport should leave an alertable wait state because
// the execution of the debuggee was stopped because of a trap or breakpoint.
virtual bool SignalThreadEvent() = 0;
};
class Transport : public TransportBase {
public:
explicit Transport(SocketHandle s);
~Transport() override;
// TransportBase
bool Read(char* dst, int32_t len) override;
bool Write(const char* src, int32_t len) override;
bool IsDataAvailable() const override;
void Disconnect() override;
void Close() override;
static const int kBufSize = 4096;
protected:
// Copy buffered data to *dst up to len bytes and update dst and len.
void CopyFromBuffer(char** dst, int32_t* len);
// Read available data from the socket. Return false on EOF or error.
virtual bool ReadSomeData() = 0;
std::unique_ptr<char[]> buf_;
int32_t pos_;
int32_t size_;
SocketHandle handle_bind_;
SocketHandle handle_accept_;
};
#if _WIN32
class SocketTransport : public Transport {
public:
explicit SocketTransport(SocketHandle s);
~SocketTransport() override;
// TransportBase
bool AcceptConnection() override;
void Disconnect() override;
void WaitForDebugStubEvent() override;
bool SignalThreadEvent() override;
private:
bool ReadSomeData() override;
HANDLE socket_event_;
HANDLE faulted_thread_event_;
DISALLOW_COPY_AND_ASSIGN(SocketTransport);
};
#else // _WIN32
class SocketTransport : public Transport {
public:
explicit SocketTransport(SocketHandle s);
~SocketTransport() override;
// TransportBase
bool AcceptConnection() override;
void WaitForDebugStubEvent() override;
bool SignalThreadEvent() override;
private:
bool ReadSomeData() override;
int faulted_thread_fd_read_;
int faulted_thread_fd_write_;
DISALLOW_COPY_AND_ASSIGN(SocketTransport);
};
#endif // _WIN32
} // namespace gdb_server
} // namespace wasm
} // namespace internal
} // namespace v8
#endif // V8_DEBUG_WASM_GDB_SERVER_TRANSPORT_H_