Skip to content

Commit 2af8459

Browse files
authored
ds2: refactor communication channel setup
This refactors the communication channel setup to reduce some recomputation as well as to track that in a state variable. This enables adding a new communication channel, which would enable use of DS2 with a serial port like gdbserver.
1 parent bb9bfe4 commit 2af8459

File tree

1 file changed

+70
-39
lines changed

1 file changed

+70
-39
lines changed

Sources/main.cpp

Lines changed: 70 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <cstdio>
2626
#include <cstdlib>
2727
#include <cstring>
28+
#include <filesystem>
2829
#include <iomanip>
2930
#include <memory>
3031
#include <set>
@@ -293,15 +294,51 @@ static int GdbserverMain(int argc, char **argv) {
293294
opts.addPositional("[host]:port", "the [host]:port to connect to");
294295

295296
int idx = opts.parse(argc, argv);
297+
298+
enum class channel_type {
299+
file_descriptor,
300+
named_pipe,
301+
network,
302+
};
303+
channel_type connection_type = channel_type::network;
304+
int fd = -1;
305+
306+
#if defined(OS_POSIX)
307+
if (const std::string &arg = opts.getString("fd"); !arg.empty()) {
308+
connection_type = channel_type::file_descriptor;
309+
fd = atoi(arg.c_str());
310+
if (fd < 0) {
311+
DS2LOG(Error, "invalid file descriptor %s", arg.c_str());
312+
connection_type = channel_type::network;
313+
}
314+
}
315+
#endif
316+
317+
// This is used for llgs testing. We determine a port number dynamically and
318+
// write it back to the FIFO passed as argument for the test harness to use
319+
// it.
320+
const std::string &pipe = opts.getString("named-pipe");
321+
if (!pipe.empty())
322+
connection_type = channel_type::named_pipe;
323+
324+
const std::string &address = opts.getPositional("[host]:port");
325+
326+
switch (connection_type) {
327+
case channel_type::file_descriptor:
296328
#if defined(OS_POSIX)
297-
int fd =
298-
opts.getString("fd").empty() ? -1 : atoi(opts.getString("fd").c_str());
299-
if (fd >= 0) {
300329
CloseFD(fd);
301-
} else {
330+
break;
331+
#else
332+
(void)fd;
333+
DS2BUG("connecting with file descriptor is not supported on this platform");
334+
#endif
335+
default:
336+
#if defined(OS_POSIX)
302337
CloseFD();
303-
}
304338
#endif
339+
break;
340+
}
341+
305342
HandleSharedOptions(opts);
306343

307344
// Target debug program and arguments.
@@ -345,50 +382,44 @@ static int GdbserverMain(int argc, char **argv) {
345382
opts.usageDie("either a program or target PID is required in gdb mode");
346383
}
347384

348-
// This is used for llgs testing. We determine a port number dynamically and
349-
// write it back to the FIFO passed as argument for the test harness to use
350-
// it.
351-
std::string namedPipePath = opts.getString("named-pipe");
352-
353385
bool reverse = opts.getBool("reverse-connect");
354386

355387
std::unique_ptr<Socket> socket;
356388

389+
switch (connection_type) {
390+
case channel_type::named_pipe:
357391
#if defined(OS_POSIX)
358-
if (fd >= 0) {
359-
socket = CreateFDSocket(fd);
360-
} else {
392+
if (fd >= 0)
393+
DS2LOG(Error, "named pipe should not be used with fd option");
361394
#endif
362-
if (opts.getPositional("[host]:port").empty()) {
363-
// If we have a named pipe, set the port to 0 to indicate that we should
364-
// dynamically allocate it and write it back to the FIFO.
365-
socket = CreateTCPSocket(
366-
gDefaultHost, namedPipePath.empty() ? gDefaultPort : "0", reverse);
367-
} else {
368-
socket = CreateSocket(opts.getPositional("[host]:port"), reverse);
395+
[[fallthrough]];
396+
case channel_type::network:
397+
// If we have a named pipe, set the port to 0 to indicate that we should
398+
// dynamically allocate it and write it back to the FIFO.
399+
socket = address.empty()
400+
? CreateTCPSocket(gDefaultHost,
401+
pipe.empty() ? gDefaultPort : "0", reverse)
402+
: CreateSocket(address, reverse);
403+
if (connection_type == channel_type::named_pipe) {
404+
std::string port = socket->port();
405+
FILE *named_pipe = ::fopen(pipe.c_str(), "a");
406+
if (named_pipe) {
407+
::fwrite(port.c_str(), 1, port.length() + 1, named_pipe);
408+
::fclose(named_pipe);
409+
} else {
410+
DS2LOG(Error, "unable to open %s: %s", pipe.c_str(), strerror(errno));
411+
}
369412
}
370-
#if defined(OS_POSIX)
371-
}
372-
#endif
413+
break;
373414

374-
if (!namedPipePath.empty()) {
415+
case channel_type::file_descriptor:
375416
#if defined(OS_POSIX)
376-
if (fd >= 0) {
377-
DS2LOG(Error, "named pipe should not be used with fd option");
378-
}
417+
socket = CreateFDSocket(fd);
418+
#else
419+
(void)fd;
420+
DS2BUG("connecting with file descriptor is not supported on this platform");
379421
#endif
380-
381-
std::string realPort = socket->port();
382-
FILE *namedPipe = fopen(namedPipePath.c_str(), "a");
383-
if (namedPipe == nullptr) {
384-
DS2LOG(Error, "unable to open %s: %s", namedPipePath.c_str(),
385-
strerror(errno));
386-
} else {
387-
// Write the null terminator to the file. This follows the llgs
388-
// behavior.
389-
fwrite(realPort.c_str(), 1, realPort.length() + 1, namedPipe);
390-
fclose(namedPipe);
391-
}
422+
break;
392423
}
393424

394425
if (gDaemonize) {

0 commit comments

Comments
 (0)