| // 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_ |