Skip to content

Commit e93f823

Browse files
committed
Host: support character devices on POSIX platforms
Introduce a new `HandleChannel` type that creates a channel from a handle. This allows us to create a channel to a serial port device. Wire this up in main to get a channel to the physical device, enabling serial port support.
1 parent 20c8d96 commit e93f823

File tree

5 files changed

+139
-17
lines changed

5 files changed

+139
-17
lines changed

BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ filegroup(
252252
"Headers/DebugServer2/Target/Windows/Thread.h",
253253
],
254254
("@platforms//os:android", "@platforms//os:freebsd", "@platforms//os:linux", "@platforms//os:macos"): [
255+
"Headers/DebugServer2/Host/POSIX/HandleChannel.h",
255256
"Headers/DebugServer2/Host/POSIX/PTrace.h",
256257
"Headers/DebugServer2/Host/POSIX/ProcessSpawner.h",
257258
"Headers/DebugServer2/Target/POSIX/Process.h",
@@ -402,6 +403,7 @@ filegroup(
402403
],
403404
("@platforms//os:android", "@platforms//os:freebsd", "@platforms//os:linux", "@platforms//os:macos"): [
404405
"Sources/Host/POSIX/File.cpp",
406+
"Sources/Host/POSIX/HandleChannel.cpp",
405407
"Sources/Host/POSIX/Platform.cpp",
406408
"Sources/Host/POSIX/ProcessSpawner.cpp",
407409
"Sources/Host/POSIX/PTrace.cpp",

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ else()
275275
# Assumes that any non-Windows platform is POSIX.
276276
target_sources(ds2 PRIVATE
277277
Sources/Host/POSIX/File.cpp
278+
Sources/Host/POSIX/HandleChannel.cpp
278279
Sources/Host/POSIX/Platform.cpp
279280
Sources/Host/POSIX/ProcessSpawner.cpp
280281
Sources/Host/POSIX/PTrace.cpp
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2022 Saleem Abdulrasool <[email protected]>
2+
3+
#pragma once
4+
5+
#include "DebugServer2/Host/Channel.h"
6+
7+
namespace ds2 {
8+
namespace Host {
9+
10+
class HandleChannel : public Channel {
11+
int fd_;
12+
13+
public:
14+
HandleChannel() : fd_(-1) {}
15+
HandleChannel(int fd);
16+
~HandleChannel() override;
17+
18+
HandleChannel(const HandleChannel &) = delete;
19+
HandleChannel(HandleChannel &&other) : fd_(other.fd_) {
20+
other.fd_ = -1;
21+
}
22+
23+
public:
24+
void close() override;
25+
26+
public:
27+
bool connected() const override { return fd_ >= 0; }
28+
29+
public:
30+
bool wait(int ms = -1) override;
31+
32+
public:
33+
ssize_t send(void const *buffer, size_t length) override;
34+
ssize_t receive(void *buffer, size_t length) override;
35+
};
36+
37+
}
38+
}

Sources/Host/POSIX/HandleChannel.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright 2022 Saleem Abdulrasool <[email protected]>
2+
3+
#include "DebugServer2/Host/POSIX/HandleChannel.h"
4+
5+
#include <fcntl.h>
6+
#include <poll.h>
7+
8+
namespace ds2 {
9+
namespace Host {
10+
11+
HandleChannel::HandleChannel(int fd) : fd_(fd) {
12+
int flags = ::fcntl(fd_, F_GETFL, 0);
13+
::fcntl(fd_, F_SETFL, flags | O_NONBLOCK);
14+
}
15+
16+
HandleChannel::~HandleChannel() {
17+
close();
18+
}
19+
20+
void HandleChannel::close() {
21+
if (fd_ >= 0)
22+
::close(fd_);
23+
fd_ = -1;
24+
}
25+
26+
bool HandleChannel::wait(int ms) {
27+
if (fd_ < 0)
28+
return false;
29+
30+
struct pollfd fds;
31+
fds.fd = fd_;
32+
fds.events = POLLIN;
33+
int nfds = ::poll(&fds, 1, ms);
34+
return nfds == 1 && (fds.revents & POLLIN);
35+
}
36+
37+
ssize_t HandleChannel::send(void const *buffer, size_t length) {
38+
if (fd_ < 0)
39+
return -1;
40+
41+
if (ssize_t nwritten =
42+
::write(fd_, reinterpret_cast<const char *>(buffer), length);
43+
nwritten > 0)
44+
return nwritten;
45+
46+
close();
47+
return -1;
48+
}
49+
50+
ssize_t HandleChannel::receive(void *buffer, size_t length) {
51+
if (fd_ < 0)
52+
return -1;
53+
54+
if (length == 0)
55+
return 0;
56+
57+
ssize_t nread = ::read(fd_, reinterpret_cast<char *>(buffer), length);
58+
if (nread == 0)
59+
close();
60+
return nread > 0 ? nread : 0;
61+
}
62+
}
63+
}

Sources/main.cpp

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
#include "DebugServer2/Host/Platform.h"
1818
#include "DebugServer2/Host/QueueChannel.h"
1919
#include "DebugServer2/Host/Socket.h"
20+
#if defined(OS_POSIX)
21+
#include "DebugServer2/Host/POSIX/HandleChannel.h"
22+
#endif
2023
#include "DebugServer2/Utils/Daemon.h"
2124
#include "DebugServer2/Utils/Log.h"
2225
#include "DebugServer2/Utils/OptParse.h"
@@ -197,10 +200,10 @@ static std::unique_ptr<Socket> CreateSocket(std::string const &arg,
197200
DS2_UNREACHABLE();
198201
}
199202

200-
static int RunDebugServer(Socket *socket, SessionDelegate *impl) {
203+
static int RunDebugServer(ds2::Host::Channel *channel, SessionDelegate *impl) {
201204
Session session(gGDBCompat ? ds2::GDBRemote::kCompatibilityModeGDB
202205
: ds2::GDBRemote::kCompatibilityModeLLDB);
203-
QueueChannel qchannel(socket);
206+
QueueChannel qchannel(channel);
204207
SessionThread thread(&qchannel, &session);
205208

206209
session.setDelegate(impl);
@@ -392,6 +395,9 @@ static int GdbserverMain(int argc, char **argv) {
392395
bool reverse = opts.getBool("reverse-connect");
393396

394397
std::unique_ptr<Socket> socket;
398+
#if defined(OS_POSIX)
399+
std::unique_ptr<ds2::Host::HandleChannel> device;
400+
#endif
395401

396402
switch (connection_type) {
397403
case channel_type::named_pipe:
@@ -419,6 +425,15 @@ static int GdbserverMain(int argc, char **argv) {
419425
}
420426
break;
421427

428+
case channel_type::file_descriptor:
429+
#if defined(OS_POSIX)
430+
socket = CreateFDSocket(fd);
431+
#else
432+
(void)fd;
433+
DS2BUG("connecting with file descriptor is not supported on this platform");
434+
#endif
435+
break;
436+
422437
case channel_type::character_device:
423438
#if defined(OS_POSIX)
424439
if (std::filesystem::exists(address))
@@ -444,24 +459,33 @@ static int GdbserverMain(int argc, char **argv) {
444459
}
445460
#endif
446461

447-
[[fallthrough]];
462+
device = std::make_unique<ds2::Host::HandleChannel>(fd);
463+
break;
448464
#else
449465
DS2BUG("connecting with chardev is not supported on this platform");
450466
#endif
467+
}
468+
469+
if (gDaemonize) {
470+
ds2::Utils::Daemonize();
471+
}
472+
473+
ds2::Host::Channel *channel;
474+
switch (connection_type) {
451475
case channel_type::file_descriptor:
476+
case channel_type::named_pipe:
477+
case channel_type::network:
478+
channel = (fd >= 0 || reverse) ? socket.get() : socket->accept().get();
479+
break;
480+
case channel_type::character_device:
452481
#if defined(OS_POSIX)
453-
socket = CreateFDSocket(fd);
482+
channel = device.get();
454483
#else
455-
(void)fd;
456-
DS2BUG("connecting with file descriptor is not supported on this platform");
484+
DS2BUG("connecting with chardev is not supported on this platform");
457485
#endif
458486
break;
459487
}
460488

461-
if (gDaemonize) {
462-
ds2::Utils::Daemonize();
463-
}
464-
465489
std::unique_ptr<DebugSessionImpl> impl;
466490

467491
if (attachPid > 0)
@@ -471,13 +495,7 @@ static int GdbserverMain(int argc, char **argv) {
471495
else
472496
impl = ds2::make_unique<DebugSessionImpl>();
473497

474-
#if defined(OS_POSIX)
475-
return RunDebugServer(
476-
(fd >= 0 || reverse) ? socket.get() : socket->accept().get(), impl.get());
477-
#else
478-
return RunDebugServer(reverse ? socket.get() : socket->accept().get(),
479-
impl.get());
480-
#endif
498+
return RunDebugServer(channel, impl.get());
481499
}
482500

483501
#if !defined(OS_WIN32)

0 commit comments

Comments
 (0)