File: | build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp |
Warning: | line 554, column 5 1st function call argument is an uninitialized value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===-- ConnectionFileDescriptorPosix.cpp ---------------------------------===// | |||
2 | // | |||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
4 | // See https://llvm.org/LICENSE.txt for license information. | |||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
6 | // | |||
7 | //===----------------------------------------------------------------------===// | |||
8 | ||||
9 | #if defined(__APPLE__) | |||
10 | // Enable this special support for Apple builds where we can have unlimited | |||
11 | // select bounds. We tried switching to poll() and kqueue and we were panicing | |||
12 | // the kernel, so we have to stick with select for now. | |||
13 | #define _DARWIN_UNLIMITED_SELECT | |||
14 | #endif | |||
15 | ||||
16 | #include "lldb/Host/posix/ConnectionFileDescriptorPosix.h" | |||
17 | #include "lldb/Host/Config.h" | |||
18 | #include "lldb/Host/Socket.h" | |||
19 | #include "lldb/Host/SocketAddress.h" | |||
20 | #include "lldb/Utility/LLDBLog.h" | |||
21 | #include "lldb/Utility/SelectHelper.h" | |||
22 | #include "lldb/Utility/Timeout.h" | |||
23 | ||||
24 | #include <cerrno> | |||
25 | #include <cstdlib> | |||
26 | #include <cstring> | |||
27 | #include <fcntl.h> | |||
28 | #include <sys/types.h> | |||
29 | ||||
30 | #if LLDB_ENABLE_POSIX1 | |||
31 | #include <termios.h> | |||
32 | #include <unistd.h> | |||
33 | #endif | |||
34 | ||||
35 | #include <memory> | |||
36 | #include <sstream> | |||
37 | ||||
38 | #include "llvm/Support/Errno.h" | |||
39 | #include "llvm/Support/ErrorHandling.h" | |||
40 | #if defined(__APPLE__) | |||
41 | #include "llvm/ADT/SmallVector.h" | |||
42 | #endif | |||
43 | #include "lldb/Host/Host.h" | |||
44 | #include "lldb/Host/Socket.h" | |||
45 | #include "lldb/Host/common/TCPSocket.h" | |||
46 | #include "lldb/Host/common/UDPSocket.h" | |||
47 | #include "lldb/Utility/Log.h" | |||
48 | #include "lldb/Utility/StreamString.h" | |||
49 | #include "lldb/Utility/Timer.h" | |||
50 | ||||
51 | using namespace lldb; | |||
52 | using namespace lldb_private; | |||
53 | ||||
54 | ConnectionFileDescriptor::ConnectionFileDescriptor(bool child_processes_inherit) | |||
55 | : Connection(), m_pipe(), m_mutex(), m_shutting_down(false), | |||
56 | ||||
57 | m_child_processes_inherit(child_processes_inherit) { | |||
58 | Log *log(GetLog(LLDBLog::Connection | LLDBLog::Object)); | |||
59 | LLDB_LOGF(log, "%p ConnectionFileDescriptor::ConnectionFileDescriptor ()",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::ConnectionFileDescriptor ()" , static_cast<void *>(this)); } while (0) | |||
60 | static_cast<void *>(this))do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::ConnectionFileDescriptor ()" , static_cast<void *>(this)); } while (0); | |||
61 | } | |||
62 | ||||
63 | ConnectionFileDescriptor::ConnectionFileDescriptor(int fd, bool owns_fd) | |||
64 | : Connection(), m_pipe(), m_mutex(), m_shutting_down(false), | |||
65 | m_child_processes_inherit(false) { | |||
66 | m_io_sp = | |||
67 | std::make_shared<NativeFile>(fd, File::eOpenOptionReadWrite, owns_fd); | |||
68 | ||||
69 | Log *log(GetLog(LLDBLog::Connection | LLDBLog::Object)); | |||
70 | LLDB_LOGF(log,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = " "%i, owns_fd = %i)", static_cast<void *>(this), fd, owns_fd ); } while (0) | |||
71 | "%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = "do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = " "%i, owns_fd = %i)", static_cast<void *>(this), fd, owns_fd ); } while (0) | |||
72 | "%i, owns_fd = %i)",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = " "%i, owns_fd = %i)", static_cast<void *>(this), fd, owns_fd ); } while (0) | |||
73 | static_cast<void *>(this), fd, owns_fd)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = " "%i, owns_fd = %i)", static_cast<void *>(this), fd, owns_fd ); } while (0); | |||
74 | OpenCommandPipe(); | |||
75 | } | |||
76 | ||||
77 | ConnectionFileDescriptor::ConnectionFileDescriptor(Socket *socket) | |||
78 | : Connection(), m_pipe(), m_mutex(), m_shutting_down(false), | |||
79 | m_child_processes_inherit(false) { | |||
80 | InitializeSocket(socket); | |||
81 | } | |||
82 | ||||
83 | ConnectionFileDescriptor::~ConnectionFileDescriptor() { | |||
84 | Log *log(GetLog(LLDBLog::Connection | LLDBLog::Object)); | |||
85 | LLDB_LOGF(log, "%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()" , static_cast<void *>(this)); } while (0) | |||
86 | static_cast<void *>(this))do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()" , static_cast<void *>(this)); } while (0); | |||
87 | Disconnect(nullptr); | |||
88 | CloseCommandPipe(); | |||
89 | } | |||
90 | ||||
91 | void ConnectionFileDescriptor::OpenCommandPipe() { | |||
92 | CloseCommandPipe(); | |||
93 | ||||
94 | Log *log = GetLog(LLDBLog::Connection); | |||
95 | // Make the command file descriptor here: | |||
96 | Status result = m_pipe.CreateNew(m_child_processes_inherit); | |||
97 | if (!result.Success()) { | |||
98 | LLDB_LOGF(log,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::OpenCommandPipe () - could not " "make pipe: %s", static_cast<void *>(this), result.AsCString ()); } while (0) | |||
99 | "%p ConnectionFileDescriptor::OpenCommandPipe () - could not "do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::OpenCommandPipe () - could not " "make pipe: %s", static_cast<void *>(this), result.AsCString ()); } while (0) | |||
100 | "make pipe: %s",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::OpenCommandPipe () - could not " "make pipe: %s", static_cast<void *>(this), result.AsCString ()); } while (0) | |||
101 | static_cast<void *>(this), result.AsCString())do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::OpenCommandPipe () - could not " "make pipe: %s", static_cast<void *>(this), result.AsCString ()); } while (0); | |||
102 | } else { | |||
103 | LLDB_LOGF(log,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::OpenCommandPipe() - success " "readfd=%d writefd=%d", static_cast<void *>(this), m_pipe .GetReadFileDescriptor(), m_pipe.GetWriteFileDescriptor()); } while (0) | |||
104 | "%p ConnectionFileDescriptor::OpenCommandPipe() - success "do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::OpenCommandPipe() - success " "readfd=%d writefd=%d", static_cast<void *>(this), m_pipe .GetReadFileDescriptor(), m_pipe.GetWriteFileDescriptor()); } while (0) | |||
105 | "readfd=%d writefd=%d",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::OpenCommandPipe() - success " "readfd=%d writefd=%d", static_cast<void *>(this), m_pipe .GetReadFileDescriptor(), m_pipe.GetWriteFileDescriptor()); } while (0) | |||
106 | static_cast<void *>(this), m_pipe.GetReadFileDescriptor(),do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::OpenCommandPipe() - success " "readfd=%d writefd=%d", static_cast<void *>(this), m_pipe .GetReadFileDescriptor(), m_pipe.GetWriteFileDescriptor()); } while (0) | |||
107 | m_pipe.GetWriteFileDescriptor())do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::OpenCommandPipe() - success " "readfd=%d writefd=%d", static_cast<void *>(this), m_pipe .GetReadFileDescriptor(), m_pipe.GetWriteFileDescriptor()); } while (0); | |||
108 | } | |||
109 | } | |||
110 | ||||
111 | void ConnectionFileDescriptor::CloseCommandPipe() { | |||
112 | Log *log = GetLog(LLDBLog::Connection); | |||
113 | LLDB_LOGF(log, "%p ConnectionFileDescriptor::CloseCommandPipe()",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::CloseCommandPipe()" , static_cast<void *>(this)); } while (0) | |||
114 | static_cast<void *>(this))do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::CloseCommandPipe()" , static_cast<void *>(this)); } while (0); | |||
115 | ||||
116 | m_pipe.Close(); | |||
117 | } | |||
118 | ||||
119 | bool ConnectionFileDescriptor::IsConnected() const { | |||
120 | return m_io_sp && m_io_sp->IsValid(); | |||
121 | } | |||
122 | ||||
123 | ConnectionStatus ConnectionFileDescriptor::Connect(llvm::StringRef path, | |||
124 | Status *error_ptr) { | |||
125 | return Connect(path, nullptr, error_ptr); | |||
126 | } | |||
127 | ||||
128 | ConnectionStatus | |||
129 | ConnectionFileDescriptor::Connect(llvm::StringRef path, | |||
130 | socket_id_callback_type socket_id_callback, | |||
131 | Status *error_ptr) { | |||
132 | std::lock_guard<std::recursive_mutex> guard(m_mutex); | |||
133 | Log *log = GetLog(LLDBLog::Connection); | |||
134 | LLDB_LOGF(log, "%p ConnectionFileDescriptor::Connect (url = '%s')",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Connect (url = '%s')" , static_cast<void *>(this), path.str().c_str()); } while (0) | |||
135 | static_cast<void *>(this), path.str().c_str())do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Connect (url = '%s')" , static_cast<void *>(this), path.str().c_str()); } while (0); | |||
136 | ||||
137 | OpenCommandPipe(); | |||
138 | ||||
139 | if (path.empty()) { | |||
140 | if (error_ptr) | |||
141 | error_ptr->SetErrorString("invalid connect arguments"); | |||
142 | return eConnectionStatusError; | |||
143 | } | |||
144 | ||||
145 | llvm::StringRef scheme; | |||
146 | std::tie(scheme, path) = path.split("://"); | |||
147 | ||||
148 | if (!path.empty()) { | |||
149 | auto method = | |||
150 | llvm::StringSwitch<ConnectionStatus (ConnectionFileDescriptor::*)( | |||
151 | llvm::StringRef, socket_id_callback_type, Status *)>(scheme) | |||
152 | .Case("listen", &ConnectionFileDescriptor::AcceptTCP) | |||
153 | .Cases("accept", "unix-accept", | |||
154 | &ConnectionFileDescriptor::AcceptNamedSocket) | |||
155 | .Case("unix-abstract-accept", | |||
156 | &ConnectionFileDescriptor::AcceptAbstractSocket) | |||
157 | .Cases("connect", "tcp-connect", | |||
158 | &ConnectionFileDescriptor::ConnectTCP) | |||
159 | .Case("udp", &ConnectionFileDescriptor::ConnectUDP) | |||
160 | .Case("unix-connect", &ConnectionFileDescriptor::ConnectNamedSocket) | |||
161 | .Case("unix-abstract-connect", | |||
162 | &ConnectionFileDescriptor::ConnectAbstractSocket) | |||
163 | #if LLDB_ENABLE_POSIX1 | |||
164 | .Case("fd", &ConnectionFileDescriptor::ConnectFD) | |||
165 | .Case("file", &ConnectionFileDescriptor::ConnectFile) | |||
166 | .Case("serial", &ConnectionFileDescriptor::ConnectSerialPort) | |||
167 | #endif | |||
168 | .Default(nullptr); | |||
169 | ||||
170 | if (method) { | |||
171 | if (error_ptr) | |||
172 | *error_ptr = Status(); | |||
173 | return (this->*method)(path, socket_id_callback, error_ptr); | |||
174 | } | |||
175 | } | |||
176 | ||||
177 | if (error_ptr) | |||
178 | error_ptr->SetErrorStringWithFormat("unsupported connection URL: '%s'", | |||
179 | path.str().c_str()); | |||
180 | return eConnectionStatusError; | |||
181 | } | |||
182 | ||||
183 | bool ConnectionFileDescriptor::InterruptRead() { | |||
184 | size_t bytes_written = 0; | |||
185 | Status result = m_pipe.Write("i", 1, bytes_written); | |||
186 | return result.Success(); | |||
187 | } | |||
188 | ||||
189 | ConnectionStatus ConnectionFileDescriptor::Disconnect(Status *error_ptr) { | |||
190 | Log *log = GetLog(LLDBLog::Connection); | |||
191 | LLDB_LOGF(log, "%p ConnectionFileDescriptor::Disconnect ()",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Disconnect ()" , static_cast<void *>(this)); } while (0) | |||
192 | static_cast<void *>(this))do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Disconnect ()" , static_cast<void *>(this)); } while (0); | |||
193 | ||||
194 | ConnectionStatus status = eConnectionStatusSuccess; | |||
195 | ||||
196 | if (!IsConnected()) { | |||
197 | LLDB_LOGF(do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Disconnect(): Nothing to disconnect" , static_cast<void *>(this)); } while (0) | |||
198 | log, "%p ConnectionFileDescriptor::Disconnect(): Nothing to disconnect",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Disconnect(): Nothing to disconnect" , static_cast<void *>(this)); } while (0) | |||
199 | static_cast<void *>(this))do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Disconnect(): Nothing to disconnect" , static_cast<void *>(this)); } while (0); | |||
200 | return eConnectionStatusSuccess; | |||
201 | } | |||
202 | ||||
203 | if (m_io_sp->GetFdType() == IOObject::eFDTypeSocket) | |||
204 | static_cast<Socket &>(*m_io_sp).PreDisconnect(); | |||
205 | ||||
206 | // Try to get the ConnectionFileDescriptor's mutex. If we fail, that is | |||
207 | // quite likely because somebody is doing a blocking read on our file | |||
208 | // descriptor. If that's the case, then send the "q" char to the command | |||
209 | // file channel so the read will wake up and the connection will then know to | |||
210 | // shut down. | |||
211 | std::unique_lock<std::recursive_mutex> locker(m_mutex, std::defer_lock); | |||
212 | if (!locker.try_lock()) { | |||
213 | if (m_pipe.CanWrite()) { | |||
214 | size_t bytes_written = 0; | |||
215 | Status result = m_pipe.Write("q", 1, bytes_written); | |||
216 | LLDB_LOGF(log,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Disconnect(): Couldn't get " "the lock, sent 'q' to %d, error = '%s'.", static_cast<void *>(this), m_pipe.GetWriteFileDescriptor(), result.AsCString ()); } while (0) | |||
217 | "%p ConnectionFileDescriptor::Disconnect(): Couldn't get "do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Disconnect(): Couldn't get " "the lock, sent 'q' to %d, error = '%s'.", static_cast<void *>(this), m_pipe.GetWriteFileDescriptor(), result.AsCString ()); } while (0) | |||
218 | "the lock, sent 'q' to %d, error = '%s'.",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Disconnect(): Couldn't get " "the lock, sent 'q' to %d, error = '%s'.", static_cast<void *>(this), m_pipe.GetWriteFileDescriptor(), result.AsCString ()); } while (0) | |||
219 | static_cast<void *>(this), m_pipe.GetWriteFileDescriptor(),do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Disconnect(): Couldn't get " "the lock, sent 'q' to %d, error = '%s'.", static_cast<void *>(this), m_pipe.GetWriteFileDescriptor(), result.AsCString ()); } while (0) | |||
220 | result.AsCString())do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Disconnect(): Couldn't get " "the lock, sent 'q' to %d, error = '%s'.", static_cast<void *>(this), m_pipe.GetWriteFileDescriptor(), result.AsCString ()); } while (0); | |||
221 | } else if (log) { | |||
222 | LLDB_LOGF(log,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the " "lock, but no command pipe is available.", static_cast<void *>(this)); } while (0) | |||
223 | "%p ConnectionFileDescriptor::Disconnect(): Couldn't get the "do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the " "lock, but no command pipe is available.", static_cast<void *>(this)); } while (0) | |||
224 | "lock, but no command pipe is available.",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the " "lock, but no command pipe is available.", static_cast<void *>(this)); } while (0) | |||
225 | static_cast<void *>(this))do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the " "lock, but no command pipe is available.", static_cast<void *>(this)); } while (0); | |||
226 | } | |||
227 | locker.lock(); | |||
228 | } | |||
229 | ||||
230 | // Prevents reads and writes during shutdown. | |||
231 | m_shutting_down = true; | |||
232 | ||||
233 | Status error = m_io_sp->Close(); | |||
234 | if (error.Fail()) | |||
235 | status = eConnectionStatusError; | |||
236 | if (error_ptr) | |||
237 | *error_ptr = error; | |||
238 | ||||
239 | // Close any pipes we were using for async interrupts | |||
240 | m_pipe.Close(); | |||
241 | ||||
242 | m_uri.clear(); | |||
243 | m_shutting_down = false; | |||
244 | return status; | |||
245 | } | |||
246 | ||||
247 | size_t ConnectionFileDescriptor::Read(void *dst, size_t dst_len, | |||
248 | const Timeout<std::micro> &timeout, | |||
249 | ConnectionStatus &status, | |||
250 | Status *error_ptr) { | |||
251 | Log *log = GetLog(LLDBLog::Connection); | |||
252 | ||||
253 | std::unique_lock<std::recursive_mutex> locker(m_mutex, std::defer_lock); | |||
254 | if (!locker.try_lock()) { | |||
255 | LLDB_LOGF(log,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Read () failed to get the " "connection lock.", static_cast<void *>(this)); } while (0) | |||
256 | "%p ConnectionFileDescriptor::Read () failed to get the "do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Read () failed to get the " "connection lock.", static_cast<void *>(this)); } while (0) | |||
257 | "connection lock.",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Read () failed to get the " "connection lock.", static_cast<void *>(this)); } while (0) | |||
258 | static_cast<void *>(this))do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Read () failed to get the " "connection lock.", static_cast<void *>(this)); } while (0); | |||
259 | if (error_ptr) | |||
260 | error_ptr->SetErrorString("failed to get the connection lock for read."); | |||
261 | ||||
262 | status = eConnectionStatusTimedOut; | |||
263 | return 0; | |||
264 | } | |||
265 | ||||
266 | if (m_shutting_down) { | |||
267 | if (error_ptr) | |||
268 | error_ptr->SetErrorString("shutting down"); | |||
269 | status = eConnectionStatusError; | |||
270 | return 0; | |||
271 | } | |||
272 | ||||
273 | status = BytesAvailable(timeout, error_ptr); | |||
274 | if (status != eConnectionStatusSuccess) | |||
275 | return 0; | |||
276 | ||||
277 | Status error; | |||
278 | size_t bytes_read = dst_len; | |||
279 | error = m_io_sp->Read(dst, bytes_read); | |||
280 | ||||
281 | if (log) { | |||
282 | LLDB_LOGF(log,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Read() fd = %" "l" "u" ", dst = %p, dst_len = %" "l" "u" ") => %" "l" "u" ", error = %s", static_cast<void *>(this), static_cast <uint64_t>(m_io_sp->GetWaitableHandle()), static_cast <void *>(dst), static_cast<uint64_t>(dst_len), static_cast <uint64_t>(bytes_read), error.AsCString()); } while (0) | |||
283 | "%p ConnectionFileDescriptor::Read() fd = %" PRIu64do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Read() fd = %" "l" "u" ", dst = %p, dst_len = %" "l" "u" ") => %" "l" "u" ", error = %s", static_cast<void *>(this), static_cast <uint64_t>(m_io_sp->GetWaitableHandle()), static_cast <void *>(dst), static_cast<uint64_t>(dst_len), static_cast <uint64_t>(bytes_read), error.AsCString()); } while (0) | |||
284 | ", dst = %p, dst_len = %" PRIu64 ") => %" PRIu64 ", error = %s",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Read() fd = %" "l" "u" ", dst = %p, dst_len = %" "l" "u" ") => %" "l" "u" ", error = %s", static_cast<void *>(this), static_cast <uint64_t>(m_io_sp->GetWaitableHandle()), static_cast <void *>(dst), static_cast<uint64_t>(dst_len), static_cast <uint64_t>(bytes_read), error.AsCString()); } while (0) | |||
285 | static_cast<void *>(this),do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Read() fd = %" "l" "u" ", dst = %p, dst_len = %" "l" "u" ") => %" "l" "u" ", error = %s", static_cast<void *>(this), static_cast <uint64_t>(m_io_sp->GetWaitableHandle()), static_cast <void *>(dst), static_cast<uint64_t>(dst_len), static_cast <uint64_t>(bytes_read), error.AsCString()); } while (0) | |||
286 | static_cast<uint64_t>(m_io_sp->GetWaitableHandle()),do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Read() fd = %" "l" "u" ", dst = %p, dst_len = %" "l" "u" ") => %" "l" "u" ", error = %s", static_cast<void *>(this), static_cast <uint64_t>(m_io_sp->GetWaitableHandle()), static_cast <void *>(dst), static_cast<uint64_t>(dst_len), static_cast <uint64_t>(bytes_read), error.AsCString()); } while (0) | |||
287 | static_cast<void *>(dst), static_cast<uint64_t>(dst_len),do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Read() fd = %" "l" "u" ", dst = %p, dst_len = %" "l" "u" ") => %" "l" "u" ", error = %s", static_cast<void *>(this), static_cast <uint64_t>(m_io_sp->GetWaitableHandle()), static_cast <void *>(dst), static_cast<uint64_t>(dst_len), static_cast <uint64_t>(bytes_read), error.AsCString()); } while (0) | |||
288 | static_cast<uint64_t>(bytes_read), error.AsCString())do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Read() fd = %" "l" "u" ", dst = %p, dst_len = %" "l" "u" ") => %" "l" "u" ", error = %s", static_cast<void *>(this), static_cast <uint64_t>(m_io_sp->GetWaitableHandle()), static_cast <void *>(dst), static_cast<uint64_t>(dst_len), static_cast <uint64_t>(bytes_read), error.AsCString()); } while (0); | |||
289 | } | |||
290 | ||||
291 | if (bytes_read == 0) { | |||
292 | error.Clear(); // End-of-file. Do not automatically close; pass along for | |||
293 | // the end-of-file handlers. | |||
294 | status = eConnectionStatusEndOfFile; | |||
295 | } | |||
296 | ||||
297 | if (error_ptr) | |||
298 | *error_ptr = error; | |||
299 | ||||
300 | if (error.Fail()) { | |||
301 | uint32_t error_value = error.GetError(); | |||
302 | switch (error_value) { | |||
303 | case EAGAIN11: // The file was marked for non-blocking I/O, and no data were | |||
304 | // ready to be read. | |||
305 | if (m_io_sp->GetFdType() == IOObject::eFDTypeSocket) | |||
306 | status = eConnectionStatusTimedOut; | |||
307 | else | |||
308 | status = eConnectionStatusSuccess; | |||
309 | return 0; | |||
310 | ||||
311 | case EFAULT14: // Buf points outside the allocated address space. | |||
312 | case EINTR4: // A read from a slow device was interrupted before any data | |||
313 | // arrived by the delivery of a signal. | |||
314 | case EINVAL22: // The pointer associated with fildes was negative. | |||
315 | case EIO5: // An I/O error occurred while reading from the file system. | |||
316 | // The process group is orphaned. | |||
317 | // The file is a regular file, nbyte is greater than 0, the | |||
318 | // starting position is before the end-of-file, and the | |||
319 | // starting position is greater than or equal to the offset | |||
320 | // maximum established for the open file descriptor | |||
321 | // associated with fildes. | |||
322 | case EISDIR21: // An attempt is made to read a directory. | |||
323 | case ENOBUFS105: // An attempt to allocate a memory buffer fails. | |||
324 | case ENOMEM12: // Insufficient memory is available. | |||
325 | status = eConnectionStatusError; | |||
326 | break; // Break to close.... | |||
327 | ||||
328 | case ENOENT2: // no such file or directory | |||
329 | case EBADF9: // fildes is not a valid file or socket descriptor open for | |||
330 | // reading. | |||
331 | case ENXIO6: // An action is requested of a device that does not exist.. | |||
332 | // A requested action cannot be performed by the device. | |||
333 | case ECONNRESET104: // The connection is closed by the peer during a read | |||
334 | // attempt on a socket. | |||
335 | case ENOTCONN107: // A read is attempted on an unconnected socket. | |||
336 | status = eConnectionStatusLostConnection; | |||
337 | break; // Break to close.... | |||
338 | ||||
339 | case ETIMEDOUT110: // A transmission timeout occurs during a read attempt on a | |||
340 | // socket. | |||
341 | status = eConnectionStatusTimedOut; | |||
342 | return 0; | |||
343 | ||||
344 | default: | |||
345 | LLDB_LOG(log, "this = {0}, unexpected error: {1}", this,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp" , __func__, "this = {0}, unexpected error: {1}", this, llvm:: sys::StrError(error_value)); } while (0) | |||
346 | llvm::sys::StrError(error_value))do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp" , __func__, "this = {0}, unexpected error: {1}", this, llvm:: sys::StrError(error_value)); } while (0); | |||
347 | status = eConnectionStatusError; | |||
348 | break; // Break to close.... | |||
349 | } | |||
350 | ||||
351 | return 0; | |||
352 | } | |||
353 | return bytes_read; | |||
354 | } | |||
355 | ||||
356 | size_t ConnectionFileDescriptor::Write(const void *src, size_t src_len, | |||
357 | ConnectionStatus &status, | |||
358 | Status *error_ptr) { | |||
359 | Log *log = GetLog(LLDBLog::Connection); | |||
360 | LLDB_LOGF(log,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Write (src = %p, src_len = %" "l" "u" ")", static_cast<void *>(this), static_cast< const void *>(src), static_cast<uint64_t>(src_len)); } while (0) | |||
361 | "%p ConnectionFileDescriptor::Write (src = %p, src_len = %" PRIu64do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Write (src = %p, src_len = %" "l" "u" ")", static_cast<void *>(this), static_cast< const void *>(src), static_cast<uint64_t>(src_len)); } while (0) | |||
362 | ")",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Write (src = %p, src_len = %" "l" "u" ")", static_cast<void *>(this), static_cast< const void *>(src), static_cast<uint64_t>(src_len)); } while (0) | |||
363 | static_cast<void *>(this), static_cast<const void *>(src),do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Write (src = %p, src_len = %" "l" "u" ")", static_cast<void *>(this), static_cast< const void *>(src), static_cast<uint64_t>(src_len)); } while (0) | |||
364 | static_cast<uint64_t>(src_len))do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Write (src = %p, src_len = %" "l" "u" ")", static_cast<void *>(this), static_cast< const void *>(src), static_cast<uint64_t>(src_len)); } while (0); | |||
365 | ||||
366 | if (!IsConnected()) { | |||
367 | if (error_ptr) | |||
368 | error_ptr->SetErrorString("not connected"); | |||
369 | status = eConnectionStatusNoConnection; | |||
370 | return 0; | |||
371 | } | |||
372 | ||||
373 | if (m_shutting_down) { | |||
374 | if (error_ptr) | |||
375 | error_ptr->SetErrorString("shutting down"); | |||
376 | status = eConnectionStatusError; | |||
377 | return 0; | |||
378 | } | |||
379 | ||||
380 | Status error; | |||
381 | ||||
382 | size_t bytes_sent = src_len; | |||
383 | error = m_io_sp->Write(src, bytes_sent); | |||
384 | ||||
385 | if (log) { | |||
386 | LLDB_LOGF(log,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Write(fd = %" "l" "u" ", src = %p, src_len = %" "l" "u" ") => %" "l" "u" " (error = %s)", static_cast<void *>(this), static_cast <uint64_t>(m_io_sp->GetWaitableHandle()), static_cast <const void *>(src), static_cast<uint64_t>(src_len ), static_cast<uint64_t>(bytes_sent), error.AsCString() ); } while (0) | |||
387 | "%p ConnectionFileDescriptor::Write(fd = %" PRIu64do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Write(fd = %" "l" "u" ", src = %p, src_len = %" "l" "u" ") => %" "l" "u" " (error = %s)", static_cast<void *>(this), static_cast <uint64_t>(m_io_sp->GetWaitableHandle()), static_cast <const void *>(src), static_cast<uint64_t>(src_len ), static_cast<uint64_t>(bytes_sent), error.AsCString() ); } while (0) | |||
388 | ", src = %p, src_len = %" PRIu64 ") => %" PRIu64 " (error = %s)",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Write(fd = %" "l" "u" ", src = %p, src_len = %" "l" "u" ") => %" "l" "u" " (error = %s)", static_cast<void *>(this), static_cast <uint64_t>(m_io_sp->GetWaitableHandle()), static_cast <const void *>(src), static_cast<uint64_t>(src_len ), static_cast<uint64_t>(bytes_sent), error.AsCString() ); } while (0) | |||
389 | static_cast<void *>(this),do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Write(fd = %" "l" "u" ", src = %p, src_len = %" "l" "u" ") => %" "l" "u" " (error = %s)", static_cast<void *>(this), static_cast <uint64_t>(m_io_sp->GetWaitableHandle()), static_cast <const void *>(src), static_cast<uint64_t>(src_len ), static_cast<uint64_t>(bytes_sent), error.AsCString() ); } while (0) | |||
390 | static_cast<uint64_t>(m_io_sp->GetWaitableHandle()),do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Write(fd = %" "l" "u" ", src = %p, src_len = %" "l" "u" ") => %" "l" "u" " (error = %s)", static_cast<void *>(this), static_cast <uint64_t>(m_io_sp->GetWaitableHandle()), static_cast <const void *>(src), static_cast<uint64_t>(src_len ), static_cast<uint64_t>(bytes_sent), error.AsCString() ); } while (0) | |||
391 | static_cast<const void *>(src), static_cast<uint64_t>(src_len),do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Write(fd = %" "l" "u" ", src = %p, src_len = %" "l" "u" ") => %" "l" "u" " (error = %s)", static_cast<void *>(this), static_cast <uint64_t>(m_io_sp->GetWaitableHandle()), static_cast <const void *>(src), static_cast<uint64_t>(src_len ), static_cast<uint64_t>(bytes_sent), error.AsCString() ); } while (0) | |||
392 | static_cast<uint64_t>(bytes_sent), error.AsCString())do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::Write(fd = %" "l" "u" ", src = %p, src_len = %" "l" "u" ") => %" "l" "u" " (error = %s)", static_cast<void *>(this), static_cast <uint64_t>(m_io_sp->GetWaitableHandle()), static_cast <const void *>(src), static_cast<uint64_t>(src_len ), static_cast<uint64_t>(bytes_sent), error.AsCString() ); } while (0); | |||
393 | } | |||
394 | ||||
395 | if (error_ptr) | |||
396 | *error_ptr = error; | |||
397 | ||||
398 | if (error.Fail()) { | |||
399 | switch (error.GetError()) { | |||
400 | case EAGAIN11: | |||
401 | case EINTR4: | |||
402 | status = eConnectionStatusSuccess; | |||
403 | return 0; | |||
404 | ||||
405 | case ECONNRESET104: // The connection is closed by the peer during a read | |||
406 | // attempt on a socket. | |||
407 | case ENOTCONN107: // A read is attempted on an unconnected socket. | |||
408 | status = eConnectionStatusLostConnection; | |||
409 | break; // Break to close.... | |||
410 | ||||
411 | default: | |||
412 | status = eConnectionStatusError; | |||
413 | break; // Break to close.... | |||
414 | } | |||
415 | ||||
416 | return 0; | |||
417 | } | |||
418 | ||||
419 | status = eConnectionStatusSuccess; | |||
420 | return bytes_sent; | |||
421 | } | |||
422 | ||||
423 | std::string ConnectionFileDescriptor::GetURI() { return m_uri; } | |||
424 | ||||
425 | // This ConnectionFileDescriptor::BytesAvailable() uses select() via | |||
426 | // SelectHelper | |||
427 | // | |||
428 | // PROS: | |||
429 | // - select is consistent across most unix platforms | |||
430 | // - The Apple specific version allows for unlimited fds in the fd_sets by | |||
431 | // setting the _DARWIN_UNLIMITED_SELECT define prior to including the | |||
432 | // required header files. | |||
433 | // CONS: | |||
434 | // - on non-Apple platforms, only supports file descriptors up to FD_SETSIZE. | |||
435 | // This implementation will assert if it runs into that hard limit to let | |||
436 | // users know that another ConnectionFileDescriptor::BytesAvailable() should | |||
437 | // be used or a new version of ConnectionFileDescriptor::BytesAvailable() | |||
438 | // should be written for the system that is running into the limitations. | |||
439 | ||||
440 | ConnectionStatus | |||
441 | ConnectionFileDescriptor::BytesAvailable(const Timeout<std::micro> &timeout, | |||
442 | Status *error_ptr) { | |||
443 | // Don't need to take the mutex here separately since we are only called from | |||
444 | // Read. If we ever get used more generally we will need to lock here as | |||
445 | // well. | |||
446 | ||||
447 | Log *log = GetLog(LLDBLog::Connection); | |||
448 | LLDB_LOG(log, "this = {0}, timeout = {1}", this, timeout)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp" , __func__, "this = {0}, timeout = {1}", this, timeout); } while (0); | |||
449 | ||||
450 | // Make a copy of the file descriptors to make sure we don't have another | |||
451 | // thread change these values out from under us and cause problems in the | |||
452 | // loop below where like in FS_SET() | |||
453 | const IOObject::WaitableHandle handle = m_io_sp->GetWaitableHandle(); | |||
454 | const int pipe_fd = m_pipe.GetReadFileDescriptor(); | |||
455 | ||||
456 | if (handle != IOObject::kInvalidHandleValue) { | |||
457 | SelectHelper select_helper; | |||
458 | if (timeout) | |||
459 | select_helper.SetTimeout(*timeout); | |||
460 | ||||
461 | select_helper.FDSetRead(handle); | |||
462 | #if defined(_WIN32) | |||
463 | // select() won't accept pipes on Windows. The entire Windows codepath | |||
464 | // needs to be converted over to using WaitForMultipleObjects and event | |||
465 | // HANDLEs, but for now at least this will allow ::select() to not return | |||
466 | // an error. | |||
467 | const bool have_pipe_fd = false; | |||
468 | #else | |||
469 | const bool have_pipe_fd = pipe_fd >= 0; | |||
470 | #endif | |||
471 | if (have_pipe_fd) | |||
472 | select_helper.FDSetRead(pipe_fd); | |||
473 | ||||
474 | while (handle == m_io_sp->GetWaitableHandle()) { | |||
475 | ||||
476 | Status error = select_helper.Select(); | |||
477 | ||||
478 | if (error_ptr) | |||
479 | *error_ptr = error; | |||
480 | ||||
481 | if (error.Fail()) { | |||
482 | switch (error.GetError()) { | |||
483 | case EBADF9: // One of the descriptor sets specified an invalid | |||
484 | // descriptor. | |||
485 | return eConnectionStatusLostConnection; | |||
486 | ||||
487 | case EINVAL22: // The specified time limit is invalid. One of its | |||
488 | // components is negative or too large. | |||
489 | default: // Other unknown error | |||
490 | return eConnectionStatusError; | |||
491 | ||||
492 | case ETIMEDOUT110: | |||
493 | return eConnectionStatusTimedOut; | |||
494 | ||||
495 | case EAGAIN11: // The kernel was (perhaps temporarily) unable to | |||
496 | // allocate the requested number of file descriptors, or | |||
497 | // we have non-blocking IO | |||
498 | case EINTR4: // A signal was delivered before the time limit | |||
499 | // expired and before any of the selected events occurred. | |||
500 | break; // Lets keep reading to until we timeout | |||
501 | } | |||
502 | } else { | |||
503 | if (select_helper.FDIsSetRead(handle)) | |||
504 | return eConnectionStatusSuccess; | |||
505 | ||||
506 | if (select_helper.FDIsSetRead(pipe_fd)) { | |||
507 | // There is an interrupt or exit command in the command pipe Read the | |||
508 | // data from that pipe: | |||
509 | char c; | |||
510 | ||||
511 | ssize_t bytes_read = | |||
512 | llvm::sys::RetryAfterSignal(-1, ::read, pipe_fd, &c, 1); | |||
513 | assert(bytes_read == 1)(static_cast <bool> (bytes_read == 1) ? void (0) : __assert_fail ("bytes_read == 1", "lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp" , 513, __extension__ __PRETTY_FUNCTION__)); | |||
514 | (void)bytes_read; | |||
515 | switch (c) { | |||
516 | case 'q': | |||
517 | LLDB_LOGF(log,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::BytesAvailable() " "got data: %c from the command channel.", static_cast<void *>(this), c); } while (0) | |||
518 | "%p ConnectionFileDescriptor::BytesAvailable() "do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::BytesAvailable() " "got data: %c from the command channel.", static_cast<void *>(this), c); } while (0) | |||
519 | "got data: %c from the command channel.",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::BytesAvailable() " "got data: %c from the command channel.", static_cast<void *>(this), c); } while (0) | |||
520 | static_cast<void *>(this), c)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("%p ConnectionFileDescriptor::BytesAvailable() " "got data: %c from the command channel.", static_cast<void *>(this), c); } while (0); | |||
521 | return eConnectionStatusEndOfFile; | |||
522 | case 'i': | |||
523 | // Interrupt the current read | |||
524 | return eConnectionStatusInterrupted; | |||
525 | } | |||
526 | } | |||
527 | } | |||
528 | } | |||
529 | } | |||
530 | ||||
531 | if (error_ptr) | |||
532 | error_ptr->SetErrorString("not connected"); | |||
533 | return eConnectionStatusLostConnection; | |||
534 | } | |||
535 | ||||
536 | lldb::ConnectionStatus ConnectionFileDescriptor::AcceptSocket( | |||
537 | Socket::SocketProtocol socket_protocol, llvm::StringRef socket_name, | |||
538 | llvm::function_ref<void(Socket &)> post_listen_callback, | |||
539 | Status *error_ptr) { | |||
540 | Status error; | |||
541 | std::unique_ptr<Socket> listening_socket = | |||
542 | Socket::Create(socket_protocol, m_child_processes_inherit, error); | |||
543 | Socket *accepted_socket; | |||
544 | ||||
545 | if (!error.Fail()) | |||
546 | error = listening_socket->Listen(socket_name, 5); | |||
547 | ||||
548 | if (!error.Fail()) { | |||
549 | post_listen_callback(*listening_socket); | |||
550 | error = listening_socket->Accept(accepted_socket); | |||
551 | } | |||
552 | ||||
553 | if (!error.Fail()) { | |||
554 | m_io_sp.reset(accepted_socket); | |||
| ||||
555 | m_uri.assign(socket_name.str()); | |||
556 | return eConnectionStatusSuccess; | |||
557 | } | |||
558 | ||||
559 | if (error_ptr) | |||
560 | *error_ptr = error; | |||
561 | return eConnectionStatusError; | |||
562 | } | |||
563 | ||||
564 | lldb::ConnectionStatus | |||
565 | ConnectionFileDescriptor::ConnectSocket(Socket::SocketProtocol socket_protocol, | |||
566 | llvm::StringRef socket_name, | |||
567 | Status *error_ptr) { | |||
568 | Status error; | |||
569 | std::unique_ptr<Socket> socket = | |||
570 | Socket::Create(socket_protocol, m_child_processes_inherit, error); | |||
571 | ||||
572 | if (!error.Fail()) | |||
573 | error = socket->Connect(socket_name); | |||
574 | ||||
575 | if (!error.Fail()) { | |||
576 | m_io_sp = std::move(socket); | |||
577 | m_uri.assign(socket_name.str()); | |||
578 | return eConnectionStatusSuccess; | |||
579 | } | |||
580 | ||||
581 | if (error_ptr) | |||
582 | *error_ptr = error; | |||
583 | return eConnectionStatusError; | |||
584 | } | |||
585 | ||||
586 | ConnectionStatus ConnectionFileDescriptor::AcceptNamedSocket( | |||
587 | llvm::StringRef socket_name, socket_id_callback_type socket_id_callback, | |||
588 | Status *error_ptr) { | |||
589 | return AcceptSocket( | |||
590 | Socket::ProtocolUnixDomain, socket_name, | |||
591 | [socket_id_callback, socket_name](Socket &listening_socket) { | |||
592 | socket_id_callback(socket_name); | |||
593 | }, | |||
594 | error_ptr); | |||
595 | } | |||
596 | ||||
597 | ConnectionStatus ConnectionFileDescriptor::ConnectNamedSocket( | |||
598 | llvm::StringRef socket_name, socket_id_callback_type socket_id_callback, | |||
599 | Status *error_ptr) { | |||
600 | return ConnectSocket(Socket::ProtocolUnixDomain, socket_name, error_ptr); | |||
601 | } | |||
602 | ||||
603 | ConnectionStatus ConnectionFileDescriptor::AcceptAbstractSocket( | |||
604 | llvm::StringRef socket_name, socket_id_callback_type socket_id_callback, | |||
605 | Status *error_ptr) { | |||
606 | return AcceptSocket( | |||
607 | Socket::ProtocolUnixAbstract, socket_name, | |||
608 | [socket_id_callback, socket_name](Socket &listening_socket) { | |||
609 | socket_id_callback(socket_name); | |||
610 | }, | |||
611 | error_ptr); | |||
612 | } | |||
613 | ||||
614 | lldb::ConnectionStatus ConnectionFileDescriptor::ConnectAbstractSocket( | |||
615 | llvm::StringRef socket_name, socket_id_callback_type socket_id_callback, | |||
616 | Status *error_ptr) { | |||
617 | return ConnectSocket(Socket::ProtocolUnixAbstract, socket_name, error_ptr); | |||
618 | } | |||
619 | ||||
620 | ConnectionStatus | |||
621 | ConnectionFileDescriptor::AcceptTCP(llvm::StringRef socket_name, | |||
622 | socket_id_callback_type socket_id_callback, | |||
623 | Status *error_ptr) { | |||
624 | ConnectionStatus ret = AcceptSocket( | |||
| ||||
625 | Socket::ProtocolTcp, socket_name, | |||
626 | [socket_id_callback](Socket &listening_socket) { | |||
627 | uint16_t port = | |||
628 | static_cast<TCPSocket &>(listening_socket).GetLocalPortNumber(); | |||
629 | socket_id_callback(std::to_string(port)); | |||
630 | }, | |||
631 | error_ptr); | |||
632 | if (ret == eConnectionStatusSuccess) | |||
633 | m_uri.assign( | |||
634 | static_cast<TCPSocket *>(m_io_sp.get())->GetRemoteConnectionURI()); | |||
635 | return ret; | |||
636 | } | |||
637 | ||||
638 | ConnectionStatus | |||
639 | ConnectionFileDescriptor::ConnectTCP(llvm::StringRef socket_name, | |||
640 | socket_id_callback_type socket_id_callback, | |||
641 | Status *error_ptr) { | |||
642 | return ConnectSocket(Socket::ProtocolTcp, socket_name, error_ptr); | |||
643 | } | |||
644 | ||||
645 | ConnectionStatus | |||
646 | ConnectionFileDescriptor::ConnectUDP(llvm::StringRef s, | |||
647 | socket_id_callback_type socket_id_callback, | |||
648 | Status *error_ptr) { | |||
649 | if (error_ptr) | |||
650 | *error_ptr = Status(); | |||
651 | llvm::Expected<std::unique_ptr<UDPSocket>> socket = | |||
652 | Socket::UdpConnect(s, m_child_processes_inherit); | |||
653 | if (!socket) { | |||
654 | if (error_ptr) | |||
655 | *error_ptr = socket.takeError(); | |||
656 | else | |||
657 | LLDB_LOG_ERROR(GetLog(LLDBLog::Connection), socket.takeError(),do { ::lldb_private::Log *log_private = (GetLog(LLDBLog::Connection )); ::llvm::Error error_private = (socket.takeError()); if (log_private && error_private) { log_private->FormatError(::std ::move(error_private), "lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp" , __func__, "tcp connect failed: {0}"); } else ::llvm::consumeError (::std::move(error_private)); } while (0) | |||
658 | "tcp connect failed: {0}")do { ::lldb_private::Log *log_private = (GetLog(LLDBLog::Connection )); ::llvm::Error error_private = (socket.takeError()); if (log_private && error_private) { log_private->FormatError(::std ::move(error_private), "lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp" , __func__, "tcp connect failed: {0}"); } else ::llvm::consumeError (::std::move(error_private)); } while (0); | |||
659 | return eConnectionStatusError; | |||
660 | } | |||
661 | m_io_sp = std::move(*socket); | |||
662 | m_uri.assign(std::string(s)); | |||
663 | return eConnectionStatusSuccess; | |||
664 | } | |||
665 | ||||
666 | ConnectionStatus | |||
667 | ConnectionFileDescriptor::ConnectFD(llvm::StringRef s, | |||
668 | socket_id_callback_type socket_id_callback, | |||
669 | Status *error_ptr) { | |||
670 | #if LLDB_ENABLE_POSIX1 | |||
671 | // Just passing a native file descriptor within this current process that | |||
672 | // is already opened (possibly from a service or other source). | |||
673 | int fd = -1; | |||
674 | ||||
675 | if (!s.getAsInteger(0, fd)) { | |||
676 | // We have what looks to be a valid file descriptor, but we should make | |||
677 | // sure it is. We currently are doing this by trying to get the flags | |||
678 | // from the file descriptor and making sure it isn't a bad fd. | |||
679 | errno(*__errno_location ()) = 0; | |||
680 | int flags = ::fcntl(fd, F_GETFL3, 0); | |||
681 | if (flags == -1 || errno(*__errno_location ()) == EBADF9) { | |||
682 | if (error_ptr) | |||
683 | error_ptr->SetErrorStringWithFormat("stale file descriptor: %s", | |||
684 | s.str().c_str()); | |||
685 | m_io_sp.reset(); | |||
686 | return eConnectionStatusError; | |||
687 | } else { | |||
688 | // Don't take ownership of a file descriptor that gets passed to us | |||
689 | // since someone else opened the file descriptor and handed it to us. | |||
690 | // TODO: Since are using a URL to open connection we should | |||
691 | // eventually parse options using the web standard where we have | |||
692 | // "fd://123?opt1=value;opt2=value" and we can have an option be | |||
693 | // "owns=1" or "owns=0" or something like this to allow us to specify | |||
694 | // this. For now, we assume we must assume we don't own it. | |||
695 | ||||
696 | std::unique_ptr<TCPSocket> tcp_socket; | |||
697 | tcp_socket = std::make_unique<TCPSocket>(fd, false, false); | |||
698 | // Try and get a socket option from this file descriptor to see if | |||
699 | // this is a socket and set m_is_socket accordingly. | |||
700 | int resuse; | |||
701 | bool is_socket = | |||
702 | !!tcp_socket->GetOption(SOL_SOCKET1, SO_REUSEADDR2, resuse); | |||
703 | if (is_socket) | |||
704 | m_io_sp = std::move(tcp_socket); | |||
705 | else | |||
706 | m_io_sp = | |||
707 | std::make_shared<NativeFile>(fd, File::eOpenOptionReadWrite, false); | |||
708 | m_uri = s.str(); | |||
709 | return eConnectionStatusSuccess; | |||
710 | } | |||
711 | } | |||
712 | ||||
713 | if (error_ptr) | |||
714 | error_ptr->SetErrorStringWithFormat("invalid file descriptor: \"%s\"", | |||
715 | s.str().c_str()); | |||
716 | m_io_sp.reset(); | |||
717 | return eConnectionStatusError; | |||
718 | #endif // LLDB_ENABLE_POSIX | |||
719 | llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX")::llvm::llvm_unreachable_internal("this function should be only called w/ LLDB_ENABLE_POSIX" , "lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp", 719); | |||
720 | } | |||
721 | ||||
722 | ConnectionStatus ConnectionFileDescriptor::ConnectFile( | |||
723 | llvm::StringRef s, socket_id_callback_type socket_id_callback, | |||
724 | Status *error_ptr) { | |||
725 | #if LLDB_ENABLE_POSIX1 | |||
726 | std::string addr_str = s.str(); | |||
727 | // file:///PATH | |||
728 | int fd = llvm::sys::RetryAfterSignal(-1, ::open, addr_str.c_str(), O_RDWR02); | |||
729 | if (fd == -1) { | |||
730 | if (error_ptr) | |||
731 | error_ptr->SetErrorToErrno(); | |||
732 | return eConnectionStatusError; | |||
733 | } | |||
734 | ||||
735 | if (::isatty(fd)) { | |||
736 | // Set up serial terminal emulation | |||
737 | struct termios options; | |||
738 | ::tcgetattr(fd, &options); | |||
739 | ||||
740 | // Set port speed to maximum | |||
741 | ::cfsetospeed(&options, B1152000010002); | |||
742 | ::cfsetispeed(&options, B1152000010002); | |||
743 | ||||
744 | // Raw input, disable echo and signals | |||
745 | options.c_lflag &= ~(ICANON0000002 | ECHO0000010 | ECHOE0000020 | ISIG0000001); | |||
746 | ||||
747 | // Make sure only one character is needed to return from a read | |||
748 | options.c_cc[VMIN6] = 1; | |||
749 | options.c_cc[VTIME5] = 0; | |||
750 | ||||
751 | llvm::sys::RetryAfterSignal(-1, ::tcsetattr, fd, TCSANOW0, &options); | |||
752 | } | |||
753 | ||||
754 | m_io_sp = std::make_shared<NativeFile>(fd, File::eOpenOptionReadWrite, true); | |||
755 | return eConnectionStatusSuccess; | |||
756 | #endif // LLDB_ENABLE_POSIX | |||
757 | llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX")::llvm::llvm_unreachable_internal("this function should be only called w/ LLDB_ENABLE_POSIX" , "lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp", 757); | |||
758 | } | |||
759 | ||||
760 | ConnectionStatus ConnectionFileDescriptor::ConnectSerialPort( | |||
761 | llvm::StringRef s, socket_id_callback_type socket_id_callback, | |||
762 | Status *error_ptr) { | |||
763 | #if LLDB_ENABLE_POSIX1 | |||
764 | llvm::StringRef path, qs; | |||
765 | // serial:///PATH?k1=v1&k2=v2... | |||
766 | std::tie(path, qs) = s.split('?'); | |||
767 | ||||
768 | llvm::Expected<SerialPort::Options> serial_options = | |||
769 | SerialPort::OptionsFromURL(qs); | |||
770 | if (!serial_options) { | |||
771 | if (error_ptr) | |||
772 | *error_ptr = serial_options.takeError(); | |||
773 | else | |||
774 | llvm::consumeError(serial_options.takeError()); | |||
775 | return eConnectionStatusError; | |||
776 | } | |||
777 | ||||
778 | int fd = llvm::sys::RetryAfterSignal(-1, ::open, path.str().c_str(), O_RDWR02); | |||
779 | if (fd == -1) { | |||
780 | if (error_ptr) | |||
781 | error_ptr->SetErrorToErrno(); | |||
782 | return eConnectionStatusError; | |||
783 | } | |||
784 | ||||
785 | llvm::Expected<std::unique_ptr<SerialPort>> serial_sp = SerialPort::Create( | |||
786 | fd, File::eOpenOptionReadWrite, serial_options.get(), true); | |||
787 | if (!serial_sp) { | |||
788 | if (error_ptr) | |||
789 | *error_ptr = serial_sp.takeError(); | |||
790 | else | |||
791 | llvm::consumeError(serial_sp.takeError()); | |||
792 | return eConnectionStatusError; | |||
793 | } | |||
794 | m_io_sp = std::move(serial_sp.get()); | |||
795 | ||||
796 | return eConnectionStatusSuccess; | |||
797 | #endif // LLDB_ENABLE_POSIX | |||
798 | llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX")::llvm::llvm_unreachable_internal("this function should be only called w/ LLDB_ENABLE_POSIX" , "lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp", 798); | |||
799 | } | |||
800 | ||||
801 | bool ConnectionFileDescriptor::GetChildProcessesInherit() const { | |||
802 | return m_child_processes_inherit; | |||
803 | } | |||
804 | ||||
805 | void ConnectionFileDescriptor::SetChildProcessesInherit( | |||
806 | bool child_processes_inherit) { | |||
807 | m_child_processes_inherit = child_processes_inherit; | |||
808 | } | |||
809 | ||||
810 | void ConnectionFileDescriptor::InitializeSocket(Socket *socket) { | |||
811 | m_io_sp.reset(socket); | |||
812 | m_uri = socket->GetRemoteConnectionURI(); | |||
813 | } |