1 // Copyright 2020 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_DEBUG_WASM_GDB_SERVER_TRANSPORT_H_ 6 #define V8_DEBUG_WASM_GDB_SERVER_TRANSPORT_H_ 7 8 #include <sstream> 9 10 #include "src/base/macros.h" 11 #include "src/debug/wasm/gdb-server/gdb-remote-util.h" 12 13 #if _WIN32 14 #include <windows.h> 15 #include <winsock2.h> 16 17 typedef SOCKET SocketHandle; 18 19 #define CloseSocket closesocket 20 #define InvalidSocket INVALID_SOCKET 21 #define SocketGetLastError() WSAGetLastError() 22 static const int kErrInterrupt = WSAEINTR; 23 typedef int ssize_t; 24 typedef int socklen_t; 25 26 #else // _WIN32 27 28 #include <arpa/inet.h> 29 #include <netdb.h> 30 #include <netinet/tcp.h> 31 #include <sys/select.h> 32 #include <sys/socket.h> 33 #include <unistd.h> 34 35 typedef int SocketHandle; 36 37 #define CloseSocket close 38 #define InvalidSocket (-1) 39 #define SocketGetLastError() errno 40 static const int kErrInterrupt = EINTR; 41 42 #endif // _WIN32 43 44 namespace v8 { 45 namespace internal { 46 namespace wasm { 47 namespace gdb_server { 48 49 class SocketTransport; 50 51 // Acts as a factory for Transport objects bound to a specified TCP port. 52 class SocketBinding { 53 public: 54 // Wrap existing socket handle. 55 explicit SocketBinding(SocketHandle socket_handle); 56 57 // Bind to the specified TCP port. 58 static SocketBinding Bind(uint16_t tcp_port); 59 IsValid()60 bool IsValid() const { return socket_handle_ != InvalidSocket; } 61 62 // Create a transport object from this socket binding 63 std::unique_ptr<SocketTransport> CreateTransport(); 64 65 // Get port the socket is bound to. 66 uint16_t GetBoundPort(); 67 68 private: 69 SocketHandle socket_handle_; 70 }; 71 72 class V8_EXPORT_PRIVATE TransportBase { 73 public: ~TransportBase()74 virtual ~TransportBase() {} 75 76 // Waits for an incoming connection on the bound port. 77 virtual bool AcceptConnection() = 0; 78 79 // Read {len} bytes from this transport, possibly blocking until enough data 80 // is available. 81 // {dst} must point to a buffer large enough to contain {len} bytes. 82 // Returns true on success. 83 // Returns false if the connection is closed; in that case the {dst} may have 84 // been partially overwritten. 85 virtual bool Read(char* dst, int32_t len) = 0; 86 87 // Write {len} bytes to this transport. 88 // Return true on success, false if the connection is closed. 89 virtual bool Write(const char* src, int32_t len) = 0; 90 91 // Return true if there is data to read. 92 virtual bool IsDataAvailable() const = 0; 93 94 // If we are connected to a debugger, gracefully closes the connection. 95 // This should be called when a debugging session gets closed. 96 virtual void Disconnect() = 0; 97 98 // Shuts down this transport, gracefully closing the existing connection and 99 // also closing the listening socket. This should be called when the GDB stub 100 // shuts down, when the program terminates. 101 virtual void Close() = 0; 102 103 // Blocks waiting for one of these two events to occur: 104 // - A network event (a new packet arrives, or the connection is dropped), 105 // - A thread event is signaled (the execution stopped because of a trap or 106 // breakpoint). 107 virtual void WaitForDebugStubEvent() = 0; 108 109 // Signal that this transport should leave an alertable wait state because 110 // the execution of the debuggee was stopped because of a trap or breakpoint. 111 virtual bool SignalThreadEvent() = 0; 112 }; 113 114 class Transport : public TransportBase { 115 public: 116 explicit Transport(SocketHandle s); 117 ~Transport() override; 118 119 // TransportBase 120 bool Read(char* dst, int32_t len) override; 121 bool Write(const char* src, int32_t len) override; 122 bool IsDataAvailable() const override; 123 void Disconnect() override; 124 void Close() override; 125 126 static const int kBufSize = 4096; 127 128 protected: 129 // Copy buffered data to *dst up to len bytes and update dst and len. 130 void CopyFromBuffer(char** dst, int32_t* len); 131 132 // Read available data from the socket. Return false on EOF or error. 133 virtual bool ReadSomeData() = 0; 134 135 std::unique_ptr<char[]> buf_; 136 int32_t pos_; 137 int32_t size_; 138 SocketHandle handle_bind_; 139 SocketHandle handle_accept_; 140 }; 141 142 #if _WIN32 143 144 class SocketTransport : public Transport { 145 public: 146 explicit SocketTransport(SocketHandle s); 147 ~SocketTransport() override; 148 SocketTransport(const SocketTransport&) = delete; 149 SocketTransport& operator=(const SocketTransport&) = delete; 150 151 // TransportBase 152 bool AcceptConnection() override; 153 void Disconnect() override; 154 void WaitForDebugStubEvent() override; 155 bool SignalThreadEvent() override; 156 157 private: 158 bool ReadSomeData() override; 159 160 HANDLE socket_event_; 161 HANDLE faulted_thread_event_; 162 }; 163 164 #else // _WIN32 165 166 class SocketTransport : public Transport { 167 public: 168 explicit SocketTransport(SocketHandle s); 169 ~SocketTransport() override; 170 SocketTransport(const SocketTransport&) = delete; 171 SocketTransport& operator=(const SocketTransport&) = delete; 172 173 // TransportBase 174 bool AcceptConnection() override; 175 void WaitForDebugStubEvent() override; 176 bool SignalThreadEvent() override; 177 178 private: 179 bool ReadSomeData() override; 180 181 int faulted_thread_fd_read_; 182 int faulted_thread_fd_write_; 183 }; 184 185 #endif // _WIN32 186 187 } // namespace gdb_server 188 } // namespace wasm 189 } // namespace internal 190 } // namespace v8 191 192 #endif // V8_DEBUG_WASM_GDB_SERVER_TRANSPORT_H_ 193