Skip to content

Commit e55850b

Browse files
committed
[lldb-server] Add unnamed pipe support to PipeWindows
Summary: This adds unnamed pipe support in PipeWindows to support communication between a debug server and child process. Modify PipeWindows::CreateNew to support the creation of an unnamed pipe. Rename the previous method that created a named pipe to PipeWindows::CreateNewNamed. Reviewers: zturner, llvm-commits Reviewed By: zturner Subscribers: Hui, labath, lldb-commits Differential Revision: https://reviews.llvm.org/D56234 llvm-svn: 350784
1 parent b236d7e commit e55850b

File tree

9 files changed

+107
-42
lines changed

9 files changed

+107
-42
lines changed

lldb/include/lldb/Host/PipeBase.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ class PipeBase {
4141
virtual bool CanRead() const = 0;
4242
virtual bool CanWrite() const = 0;
4343

44+
virtual lldb::pipe_t GetReadPipe() const = 0;
45+
virtual lldb::pipe_t GetWritePipe() const = 0;
46+
4447
virtual int GetReadFileDescriptor() const = 0;
4548
virtual int GetWriteFileDescriptor() const = 0;
4649
virtual int ReleaseReadFileDescriptor() = 0;

lldb/include/lldb/Host/posix/PipePosix.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class PipePosix : public PipeBase {
2727
static int kInvalidDescriptor;
2828

2929
PipePosix();
30-
PipePosix(int read_fd, int write_fd);
30+
PipePosix(lldb::pipe_t read, lldb::pipe_t write);
3131
PipePosix(const PipePosix &) = delete;
3232
PipePosix(PipePosix &&pipe_posix);
3333
PipePosix &operator=(const PipePosix &) = delete;
@@ -49,6 +49,13 @@ class PipePosix : public PipeBase {
4949
bool CanRead() const override;
5050
bool CanWrite() const override;
5151

52+
lldb::pipe_t GetReadPipe() const override {
53+
return lldb::pipe_t(GetReadFileDescriptor());
54+
}
55+
lldb::pipe_t GetWritePipe() const override {
56+
return lldb::pipe_t(GetWriteFileDescriptor());
57+
}
58+
5259
int GetReadFileDescriptor() const override;
5360
int GetWriteFileDescriptor() const override;
5461
int ReleaseReadFileDescriptor() override;

lldb/include/lldb/Host/windows/PipeWindows.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,19 @@ namespace lldb_private {
2323
/// A class that abstracts the LLDB core from host pipe functionality.
2424
//----------------------------------------------------------------------
2525
class PipeWindows : public PipeBase {
26+
public:
27+
static const int kInvalidDescriptor = -1;
28+
2629
public:
2730
PipeWindows();
31+
PipeWindows(lldb::pipe_t read, lldb::pipe_t write);
2832
~PipeWindows() override;
2933

34+
// Create an unnamed pipe.
3035
Status CreateNew(bool child_process_inherit) override;
36+
37+
// Create a named pipe.
38+
Status CreateNewNamed(bool child_process_inherit);
3139
Status CreateNew(llvm::StringRef name, bool child_process_inherit) override;
3240
Status CreateWithUniqueName(llvm::StringRef prefix,
3341
bool child_process_inherit,
@@ -41,6 +49,9 @@ class PipeWindows : public PipeBase {
4149
bool CanRead() const override;
4250
bool CanWrite() const override;
4351

52+
lldb::pipe_t GetReadPipe() const { return lldb::pipe_t(m_read); }
53+
lldb::pipe_t GetWritePipe() const { return lldb::pipe_t(m_write); }
54+
4455
int GetReadFileDescriptor() const override;
4556
int GetWriteFileDescriptor() const override;
4657
int ReleaseReadFileDescriptor() override;

lldb/include/lldb/lldb-types.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ typedef unsigned int __w64 socket_t; // Host socket type
4747
typedef void *thread_arg_t; // Host thread argument type
4848
typedef unsigned thread_result_t; // Host thread result type
4949
typedef thread_result_t (*thread_func_t)(void *); // Host thread function type
50-
}
50+
typedef void *pipe_t; // Host pipe type is HANDLE
51+
} // namespace lldb
5152

5253
#else
5354

@@ -65,6 +66,7 @@ typedef int socket_t; // Host socket type
6566
typedef void *thread_arg_t; // Host thread argument type
6667
typedef void *thread_result_t; // Host thread result type
6768
typedef void *(*thread_func_t)(void *); // Host thread function type
69+
typedef int pipe_t; // Host pipe type
6870
} // namespace lldb
6971

7072
#endif
@@ -76,10 +78,11 @@ typedef bool (*CommandOverrideCallbackWithResult)(
7678
void *baton, const char **argv, lldb_private::CommandReturnObject &result);
7779
typedef bool (*ExpressionCancelCallback)(ExpressionEvaluationPhase phase,
7880
void *baton);
79-
}
81+
} // namespace lldb
8082

8183
#define LLDB_INVALID_PROCESS ((lldb::process_t)-1)
8284
#define LLDB_INVALID_HOST_THREAD ((lldb::thread_t)NULL)
85+
#define LLDB_INVALID_PIPE ((lldb::pipe_t)-1)
8386

8487
namespace lldb {
8588
typedef uint64_t addr_t;
@@ -91,6 +94,6 @@ typedef int32_t break_id_t;
9194
typedef int32_t watch_id_t;
9295
typedef void *opaque_compiler_type_t;
9396
typedef uint64_t queue_id_t;
94-
}
97+
} // namespace lldb
9598

9699
#endif // LLDB_lldb_types_h_

lldb/source/Host/posix/PipePosix.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,13 @@ bool SetCloexecFlag(int fd) {
6161
std::chrono::time_point<std::chrono::steady_clock> Now() {
6262
return std::chrono::steady_clock::now();
6363
}
64-
}
64+
} // namespace
6565

6666
PipePosix::PipePosix()
6767
: m_fds{PipePosix::kInvalidDescriptor, PipePosix::kInvalidDescriptor} {}
6868

69-
PipePosix::PipePosix(int read_fd, int write_fd) : m_fds{read_fd, write_fd} {}
69+
PipePosix::PipePosix(lldb::pipe_t read, lldb::pipe_t write)
70+
: m_fds{read, write} {}
7071

7172
PipePosix::PipePosix(PipePosix &&pipe_posix)
7273
: PipeBase{std::move(pipe_posix)},

lldb/source/Host/windows/PipeWindows.cpp

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,66 @@ using namespace lldb_private;
2525

2626
namespace {
2727
std::atomic<uint32_t> g_pipe_serial(0);
28+
constexpr llvm::StringLiteral g_pipe_name_prefix = "\\\\.\\Pipe\\";
29+
} // namespace
30+
31+
PipeWindows::PipeWindows()
32+
: m_read(INVALID_HANDLE_VALUE), m_write(INVALID_HANDLE_VALUE),
33+
m_read_fd(PipeWindows::kInvalidDescriptor),
34+
m_write_fd(PipeWindows::kInvalidDescriptor) {
35+
ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));
36+
ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));
2837
}
2938

30-
PipeWindows::PipeWindows() {
31-
m_read = INVALID_HANDLE_VALUE;
32-
m_write = INVALID_HANDLE_VALUE;
39+
PipeWindows::PipeWindows(pipe_t read, pipe_t write)
40+
: m_read((HANDLE)read), m_write((HANDLE)write),
41+
m_read_fd(PipeWindows::kInvalidDescriptor),
42+
m_write_fd(PipeWindows::kInvalidDescriptor) {
43+
assert(read != LLDB_INVALID_PIPE || write != LLDB_INVALID_PIPE);
44+
45+
// Don't risk in passing file descriptors and getting handles from them by
46+
// _get_osfhandle since the retrieved handles are highly likely unrecognized
47+
// in the current process and usually crashes the program. Pass handles
48+
// instead since the handle can be inherited.
49+
50+
if (read != LLDB_INVALID_PIPE) {
51+
m_read_fd = _open_osfhandle((intptr_t)read, _O_RDONLY);
52+
// Make sure the fd and native handle are consistent.
53+
if (m_read_fd < 0)
54+
m_read = INVALID_HANDLE_VALUE;
55+
}
56+
57+
if (write != LLDB_INVALID_PIPE) {
58+
m_write_fd = _open_osfhandle((intptr_t)write, _O_WRONLY);
59+
if (m_write_fd < 0)
60+
m_write = INVALID_HANDLE_VALUE;
61+
}
3362

34-
m_read_fd = -1;
35-
m_write_fd = -1;
3663
ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));
3764
ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));
3865
}
3966

4067
PipeWindows::~PipeWindows() { Close(); }
4168

4269
Status PipeWindows::CreateNew(bool child_process_inherit) {
70+
// Create an anonymous pipe with the specified inheritance.
71+
SECURITY_ATTRIBUTES sa{sizeof(SECURITY_ATTRIBUTES), 0,
72+
child_process_inherit ? TRUE : FALSE};
73+
BOOL result = ::CreatePipe(&m_read, &m_write, &sa, 1024);
74+
if (result == FALSE)
75+
return Status(::GetLastError(), eErrorTypeWin32);
76+
77+
m_read_fd = _open_osfhandle((intptr_t)m_read, _O_RDONLY);
78+
ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));
79+
m_read_overlapped.hEvent = ::CreateEventA(nullptr, TRUE, FALSE, nullptr);
80+
81+
m_write_fd = _open_osfhandle((intptr_t)m_write, _O_WRONLY);
82+
ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));
83+
84+
return Status();
85+
}
86+
87+
Status PipeWindows::CreateNewNamed(bool child_process_inherit) {
4388
// Even for anonymous pipes, we open a named pipe. This is because you
4489
// cannot get overlapped i/o on Windows without using a named pipe. So we
4590
// synthesize a unique name.
@@ -60,7 +105,7 @@ Status PipeWindows::CreateNew(llvm::StringRef name,
60105
if (CanRead() || CanWrite())
61106
return Status(ERROR_ALREADY_EXISTS, eErrorTypeWin32);
62107

63-
std::string pipe_path = "\\\\.\\Pipe\\";
108+
std::string pipe_path = g_pipe_name_prefix;
64109
pipe_path.append(name);
65110

66111
// Always open for overlapped i/o. We implement blocking manually in Read
@@ -75,7 +120,8 @@ Status PipeWindows::CreateNew(llvm::StringRef name,
75120
ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));
76121
m_read_overlapped.hEvent = ::CreateEvent(nullptr, TRUE, FALSE, nullptr);
77122

78-
// Open the write end of the pipe.
123+
// Open the write end of the pipe. Note that closing either the read or
124+
// write end of the pipe could directly close the pipe itself.
79125
Status result = OpenNamedPipe(name, child_process_inherit, false);
80126
if (!result.Success()) {
81127
CloseReadFileDescriptor();
@@ -111,7 +157,7 @@ Status PipeWindows::CreateWithUniqueName(llvm::StringRef prefix,
111157

112158
Status PipeWindows::OpenAsReader(llvm::StringRef name,
113159
bool child_process_inherit) {
114-
if (CanRead() || CanWrite())
160+
if (CanRead())
115161
return Status(ERROR_ALREADY_EXISTS, eErrorTypeWin32);
116162

117163
return OpenNamedPipe(name, child_process_inherit, true);
@@ -121,7 +167,7 @@ Status
121167
PipeWindows::OpenAsWriterWithTimeout(llvm::StringRef name,
122168
bool child_process_inherit,
123169
const std::chrono::microseconds &timeout) {
124-
if (CanRead() || CanWrite())
170+
if (CanWrite())
125171
return Status(ERROR_ALREADY_EXISTS, eErrorTypeWin32);
126172

127173
return OpenNamedPipe(name, child_process_inherit, false);
@@ -137,7 +183,7 @@ Status PipeWindows::OpenNamedPipe(llvm::StringRef name,
137183
SECURITY_ATTRIBUTES attributes = {};
138184
attributes.bInheritHandle = child_process_inherit;
139185

140-
std::string pipe_path = "\\\\.\\Pipe\\";
186+
std::string pipe_path = g_pipe_name_prefix;
141187
pipe_path.append(name);
142188

143189
if (is_read) {
@@ -170,9 +216,9 @@ int PipeWindows::GetWriteFileDescriptor() const { return m_write_fd; }
170216

171217
int PipeWindows::ReleaseReadFileDescriptor() {
172218
if (!CanRead())
173-
return -1;
219+
return PipeWindows::kInvalidDescriptor;
174220
int result = m_read_fd;
175-
m_read_fd = -1;
221+
m_read_fd = PipeWindows::kInvalidDescriptor;
176222
if (m_read_overlapped.hEvent)
177223
::CloseHandle(m_read_overlapped.hEvent);
178224
m_read = INVALID_HANDLE_VALUE;
@@ -182,9 +228,9 @@ int PipeWindows::ReleaseReadFileDescriptor() {
182228

183229
int PipeWindows::ReleaseWriteFileDescriptor() {
184230
if (!CanWrite())
185-
return -1;
231+
return PipeWindows::kInvalidDescriptor;
186232
int result = m_write_fd;
187-
m_write_fd = -1;
233+
m_write_fd = PipeWindows::kInvalidDescriptor;
188234
m_write = INVALID_HANDLE_VALUE;
189235
ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));
190236
return result;
@@ -196,9 +242,10 @@ void PipeWindows::CloseReadFileDescriptor() {
196242

197243
if (m_read_overlapped.hEvent)
198244
::CloseHandle(m_read_overlapped.hEvent);
245+
199246
_close(m_read_fd);
200247
m_read = INVALID_HANDLE_VALUE;
201-
m_read_fd = -1;
248+
m_read_fd = PipeWindows::kInvalidDescriptor;
202249
ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped));
203250
}
204251

@@ -208,7 +255,7 @@ void PipeWindows::CloseWriteFileDescriptor() {
208255

209256
_close(m_write_fd);
210257
m_write = INVALID_HANDLE_VALUE;
211-
m_write_fd = -1;
258+
m_write_fd = PipeWindows::kInvalidDescriptor;
212259
ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped));
213260
}
214261

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,9 +1074,9 @@ Status GDBRemoteCommunication::StartDebugserverProcess(
10741074
__FUNCTION__, error.AsCString());
10751075
return error;
10761076
}
1077-
int write_fd = socket_pipe.GetWriteFileDescriptor();
1077+
pipe_t write = socket_pipe.GetWritePipe();
10781078
debugserver_args.AppendArgument(llvm::StringRef("--pipe"));
1079-
debugserver_args.AppendArgument(llvm::to_string(write_fd));
1079+
debugserver_args.AppendArgument(llvm::to_string(write));
10801080
launch_info.AppendCloseFileAction(socket_pipe.GetReadFileDescriptor());
10811081
#endif
10821082
} else {

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -164,9 +164,6 @@ Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer(
164164
GDBRemoteCommunication::PacketResult
165165
GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer(
166166
StringExtractorGDBRemote &packet) {
167-
#ifdef _WIN32
168-
return SendErrorResponse(9);
169-
#else
170167
// Spawn a local debugserver as a platform so we can then attach or launch a
171168
// process...
172169

@@ -217,10 +214,9 @@ GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer(
217214
PacketResult packet_result = SendPacketNoLock(response.GetString());
218215
if (packet_result != PacketResult::Success) {
219216
if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
220-
::kill(debugserver_pid, SIGINT);
217+
Host::Kill(debugserver_pid, SIGINT);
221218
}
222219
return packet_result;
223-
#endif
224220
}
225221

226222
GDBRemoteCommunication::PacketResult

lldb/tools/lldb-server/lldb-gdbserver.cpp

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -218,20 +218,17 @@ Status writeSocketIdToPipe(const char *const named_pipe_path,
218218
return writeSocketIdToPipe(port_name_pipe, socket_id);
219219
}
220220

221-
Status writeSocketIdToPipe(int unnamed_pipe_fd, const std::string &socket_id) {
222-
#if defined(_WIN32)
223-
return Status("Unnamed pipes are not supported on Windows.");
224-
#else
225-
Pipe port_pipe{Pipe::kInvalidDescriptor, unnamed_pipe_fd};
221+
Status writeSocketIdToPipe(lldb::pipe_t unnamed_pipe,
222+
const std::string &socket_id) {
223+
Pipe port_pipe{LLDB_INVALID_PIPE, unnamed_pipe};
226224
return writeSocketIdToPipe(port_pipe, socket_id);
227-
#endif
228225
}
229226

230227
void ConnectToRemote(MainLoop &mainloop,
231228
GDBRemoteCommunicationServerLLGS &gdb_server,
232229
bool reverse_connect, const char *const host_and_port,
233230
const char *const progname, const char *const subcommand,
234-
const char *const named_pipe_path, int unnamed_pipe_fd,
231+
const char *const named_pipe_path, pipe_t unnamed_pipe,
235232
int connection_fd) {
236233
Status error;
237234

@@ -331,8 +328,8 @@ void ConnectToRemote(MainLoop &mainloop,
331328
}
332329
// If we have an unnamed pipe to write the socket id back to, do that
333330
// now.
334-
else if (unnamed_pipe_fd >= 0) {
335-
error = writeSocketIdToPipe(unnamed_pipe_fd, socket_id);
331+
else if (unnamed_pipe != LLDB_INVALID_PIPE) {
332+
error = writeSocketIdToPipe(unnamed_pipe, socket_id);
336333
if (error.Fail())
337334
fprintf(stderr, "failed to write to the unnamed pipe: %s\n",
338335
error.AsCString());
@@ -384,7 +381,7 @@ int main_gdbserver(int argc, char *argv[]) {
384381
std::string log_file;
385382
StringRef
386383
log_channels; // e.g. "lldb process threads:gdb-remote default:linux all"
387-
int unnamed_pipe_fd = -1;
384+
lldb::pipe_t unnamed_pipe = LLDB_INVALID_PIPE;
388385
bool reverse_connect = false;
389386
int connection_fd = -1;
390387

@@ -425,7 +422,7 @@ int main_gdbserver(int argc, char *argv[]) {
425422

426423
case 'U': // unnamed pipe
427424
if (optarg && optarg[0])
428-
unnamed_pipe_fd = StringConvert::ToUInt32(optarg, -1);
425+
unnamed_pipe = (pipe_t)StringConvert::ToUInt64(optarg, -1);
429426
break;
430427

431428
case 'r':
@@ -528,8 +525,8 @@ int main_gdbserver(int argc, char *argv[]) {
528525
printf("%s-%s", LLGS_PROGRAM_NAME, LLGS_VERSION_STR);
529526

530527
ConnectToRemote(mainloop, gdb_server, reverse_connect, host_and_port,
531-
progname, subcommand, named_pipe_path.c_str(),
532-
unnamed_pipe_fd, connection_fd);
528+
progname, subcommand, named_pipe_path.c_str(),
529+
unnamed_pipe, connection_fd);
533530

534531
if (!gdb_server.IsConnected()) {
535532
fprintf(stderr, "no connection information provided, unable to run\n");

0 commit comments

Comments
 (0)