10f0462caSWalter Erquinigo //===-- RunInTerminal.cpp ---------------------------------------*- C++ -*-===//
20f0462caSWalter Erquinigo //
30f0462caSWalter Erquinigo // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40f0462caSWalter Erquinigo // See https://llvm.org/LICENSE.txt for license information.
50f0462caSWalter Erquinigo // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60f0462caSWalter Erquinigo //
70f0462caSWalter Erquinigo //===----------------------------------------------------------------------===//
80f0462caSWalter Erquinigo
90bca9a7cSWalter Erquinigo #include "RunInTerminal.h"
100bca9a7cSWalter Erquinigo
11*36496cc2SWalter Erquinigo #if !defined(_WIN32)
120f0462caSWalter Erquinigo #include <sys/stat.h>
130f0462caSWalter Erquinigo #include <sys/types.h>
140f0462caSWalter Erquinigo #include <unistd.h>
150f0462caSWalter Erquinigo #endif
160f0462caSWalter Erquinigo
170f0462caSWalter Erquinigo #include <chrono>
180f0462caSWalter Erquinigo #include <fstream>
190f0462caSWalter Erquinigo #include <future>
200f0462caSWalter Erquinigo #include <thread>
210f0462caSWalter Erquinigo
220f0462caSWalter Erquinigo #include "llvm/Support/FileSystem.h"
230f0462caSWalter Erquinigo
240f0462caSWalter Erquinigo #include "lldb/lldb-defines.h"
250f0462caSWalter Erquinigo
260f0462caSWalter Erquinigo using namespace llvm;
270f0462caSWalter Erquinigo
280f0462caSWalter Erquinigo namespace lldb_vscode {
290f0462caSWalter Erquinigo
GetAsPidMessage() const300f0462caSWalter Erquinigo const RunInTerminalMessagePid *RunInTerminalMessage::GetAsPidMessage() const {
310f0462caSWalter Erquinigo return static_cast<const RunInTerminalMessagePid *>(this);
320f0462caSWalter Erquinigo }
330f0462caSWalter Erquinigo
340f0462caSWalter Erquinigo const RunInTerminalMessageError *
GetAsErrorMessage() const350f0462caSWalter Erquinigo RunInTerminalMessage::GetAsErrorMessage() const {
360f0462caSWalter Erquinigo return static_cast<const RunInTerminalMessageError *>(this);
370f0462caSWalter Erquinigo }
380f0462caSWalter Erquinigo
RunInTerminalMessage(RunInTerminalMessageKind kind)390f0462caSWalter Erquinigo RunInTerminalMessage::RunInTerminalMessage(RunInTerminalMessageKind kind)
400f0462caSWalter Erquinigo : kind(kind) {}
410f0462caSWalter Erquinigo
RunInTerminalMessagePid(lldb::pid_t pid)420f0462caSWalter Erquinigo RunInTerminalMessagePid::RunInTerminalMessagePid(lldb::pid_t pid)
430f0462caSWalter Erquinigo : RunInTerminalMessage(eRunInTerminalMessageKindPID), pid(pid) {}
440f0462caSWalter Erquinigo
ToJSON() const450f0462caSWalter Erquinigo json::Value RunInTerminalMessagePid::ToJSON() const {
460f0462caSWalter Erquinigo return json::Object{{"kind", "pid"}, {"pid", static_cast<int64_t>(pid)}};
470f0462caSWalter Erquinigo }
480f0462caSWalter Erquinigo
RunInTerminalMessageError(StringRef error)490f0462caSWalter Erquinigo RunInTerminalMessageError::RunInTerminalMessageError(StringRef error)
500f0462caSWalter Erquinigo : RunInTerminalMessage(eRunInTerminalMessageKindError), error(error) {}
510f0462caSWalter Erquinigo
ToJSON() const520f0462caSWalter Erquinigo json::Value RunInTerminalMessageError::ToJSON() const {
530f0462caSWalter Erquinigo return json::Object{{"kind", "error"}, {"value", error}};
540f0462caSWalter Erquinigo }
550f0462caSWalter Erquinigo
RunInTerminalMessageDidAttach()560f0462caSWalter Erquinigo RunInTerminalMessageDidAttach::RunInTerminalMessageDidAttach()
570f0462caSWalter Erquinigo : RunInTerminalMessage(eRunInTerminalMessageKindDidAttach) {}
580f0462caSWalter Erquinigo
ToJSON() const590f0462caSWalter Erquinigo json::Value RunInTerminalMessageDidAttach::ToJSON() const {
600f0462caSWalter Erquinigo return json::Object{{"kind", "didAttach"}};
610f0462caSWalter Erquinigo }
620f0462caSWalter Erquinigo
630f0462caSWalter Erquinigo static Expected<RunInTerminalMessageUP>
ParseJSONMessage(const json::Value & json)640f0462caSWalter Erquinigo ParseJSONMessage(const json::Value &json) {
650f0462caSWalter Erquinigo if (const json::Object *obj = json.getAsObject()) {
660f0462caSWalter Erquinigo if (Optional<StringRef> kind = obj->getString("kind")) {
670f0462caSWalter Erquinigo if (*kind == "pid") {
680f0462caSWalter Erquinigo if (Optional<int64_t> pid = obj->getInteger("pid"))
690f0462caSWalter Erquinigo return std::make_unique<RunInTerminalMessagePid>(
700f0462caSWalter Erquinigo static_cast<lldb::pid_t>(*pid));
710f0462caSWalter Erquinigo } else if (*kind == "error") {
720f0462caSWalter Erquinigo if (Optional<StringRef> error = obj->getString("error"))
730f0462caSWalter Erquinigo return std::make_unique<RunInTerminalMessageError>(*error);
740f0462caSWalter Erquinigo } else if (*kind == "didAttach") {
750f0462caSWalter Erquinigo return std::make_unique<RunInTerminalMessageDidAttach>();
760f0462caSWalter Erquinigo }
770f0462caSWalter Erquinigo }
780f0462caSWalter Erquinigo }
790f0462caSWalter Erquinigo
800f0462caSWalter Erquinigo return createStringError(inconvertibleErrorCode(),
810f0462caSWalter Erquinigo "Incorrect JSON message: " + JSONToString(json));
820f0462caSWalter Erquinigo }
830f0462caSWalter Erquinigo
840f0462caSWalter Erquinigo static Expected<RunInTerminalMessageUP>
GetNextMessage(FifoFileIO & io,std::chrono::milliseconds timeout)850f0462caSWalter Erquinigo GetNextMessage(FifoFileIO &io, std::chrono::milliseconds timeout) {
860f0462caSWalter Erquinigo if (Expected<json::Value> json = io.ReadJSON(timeout))
870f0462caSWalter Erquinigo return ParseJSONMessage(*json);
880f0462caSWalter Erquinigo else
890f0462caSWalter Erquinigo return json.takeError();
900f0462caSWalter Erquinigo }
910f0462caSWalter Erquinigo
ToError(const RunInTerminalMessage & message)920f0462caSWalter Erquinigo static Error ToError(const RunInTerminalMessage &message) {
930f0462caSWalter Erquinigo if (message.kind == eRunInTerminalMessageKindError)
940f0462caSWalter Erquinigo return createStringError(inconvertibleErrorCode(),
950f0462caSWalter Erquinigo message.GetAsErrorMessage()->error);
960f0462caSWalter Erquinigo return createStringError(inconvertibleErrorCode(),
970f0462caSWalter Erquinigo "Unexpected JSON message: " +
980f0462caSWalter Erquinigo JSONToString(message.ToJSON()));
990f0462caSWalter Erquinigo }
1000f0462caSWalter Erquinigo
RunInTerminalLauncherCommChannel(StringRef comm_file)1010f0462caSWalter Erquinigo RunInTerminalLauncherCommChannel::RunInTerminalLauncherCommChannel(
1020f0462caSWalter Erquinigo StringRef comm_file)
1030f0462caSWalter Erquinigo : m_io(comm_file, "debug adaptor") {}
1040f0462caSWalter Erquinigo
WaitUntilDebugAdaptorAttaches(std::chrono::milliseconds timeout)1050f0462caSWalter Erquinigo Error RunInTerminalLauncherCommChannel::WaitUntilDebugAdaptorAttaches(
1060f0462caSWalter Erquinigo std::chrono::milliseconds timeout) {
1070f0462caSWalter Erquinigo if (Expected<RunInTerminalMessageUP> message =
1080f0462caSWalter Erquinigo GetNextMessage(m_io, timeout)) {
1090f0462caSWalter Erquinigo if (message.get()->kind == eRunInTerminalMessageKindDidAttach)
1100f0462caSWalter Erquinigo return Error::success();
1110f0462caSWalter Erquinigo else
1120f0462caSWalter Erquinigo return ToError(*message.get());
1130f0462caSWalter Erquinigo } else
1140f0462caSWalter Erquinigo return message.takeError();
1150f0462caSWalter Erquinigo }
1160f0462caSWalter Erquinigo
NotifyPid()1170f0462caSWalter Erquinigo Error RunInTerminalLauncherCommChannel::NotifyPid() {
1180f0462caSWalter Erquinigo return m_io.SendJSON(RunInTerminalMessagePid(getpid()).ToJSON());
1190f0462caSWalter Erquinigo }
1200f0462caSWalter Erquinigo
NotifyError(StringRef error)1210f0462caSWalter Erquinigo void RunInTerminalLauncherCommChannel::NotifyError(StringRef error) {
1220f0462caSWalter Erquinigo if (Error err = m_io.SendJSON(RunInTerminalMessageError(error).ToJSON(),
1230f0462caSWalter Erquinigo std::chrono::seconds(2)))
1240f0462caSWalter Erquinigo llvm::errs() << llvm::toString(std::move(err)) << "\n";
1250f0462caSWalter Erquinigo }
1260f0462caSWalter Erquinigo
RunInTerminalDebugAdapterCommChannel(StringRef comm_file)1270f0462caSWalter Erquinigo RunInTerminalDebugAdapterCommChannel::RunInTerminalDebugAdapterCommChannel(
1280f0462caSWalter Erquinigo StringRef comm_file)
1290f0462caSWalter Erquinigo : m_io(comm_file, "runInTerminal launcher") {}
1300f0462caSWalter Erquinigo
1311ac36b34SWalter Erquinigo // Can't use \a std::future<llvm::Error> because it doesn't compile on Windows
1321ac36b34SWalter Erquinigo std::future<lldb::SBError>
NotifyDidAttach()1331ac36b34SWalter Erquinigo RunInTerminalDebugAdapterCommChannel::NotifyDidAttach() {
1340f0462caSWalter Erquinigo return std::async(std::launch::async, [&]() {
1351ac36b34SWalter Erquinigo lldb::SBError error;
1361ac36b34SWalter Erquinigo if (llvm::Error err =
1371ac36b34SWalter Erquinigo m_io.SendJSON(RunInTerminalMessageDidAttach().ToJSON()))
1381ac36b34SWalter Erquinigo error.SetErrorString(llvm::toString(std::move(err)).c_str());
1391ac36b34SWalter Erquinigo return error;
1400f0462caSWalter Erquinigo });
1410f0462caSWalter Erquinigo }
1420f0462caSWalter Erquinigo
GetLauncherPid()1430f0462caSWalter Erquinigo Expected<lldb::pid_t> RunInTerminalDebugAdapterCommChannel::GetLauncherPid() {
1440f0462caSWalter Erquinigo if (Expected<RunInTerminalMessageUP> message =
1450f0462caSWalter Erquinigo GetNextMessage(m_io, std::chrono::seconds(20))) {
1460f0462caSWalter Erquinigo if (message.get()->kind == eRunInTerminalMessageKindPID)
1470f0462caSWalter Erquinigo return message.get()->GetAsPidMessage()->pid;
1480f0462caSWalter Erquinigo return ToError(*message.get());
1490f0462caSWalter Erquinigo } else {
1500f0462caSWalter Erquinigo return message.takeError();
1510f0462caSWalter Erquinigo }
1520f0462caSWalter Erquinigo }
1530f0462caSWalter Erquinigo
GetLauncherError()1540f0462caSWalter Erquinigo std::string RunInTerminalDebugAdapterCommChannel::GetLauncherError() {
1550f0462caSWalter Erquinigo // We know there's been an error, so a small timeout is enough.
1560f0462caSWalter Erquinigo if (Expected<RunInTerminalMessageUP> message =
1570f0462caSWalter Erquinigo GetNextMessage(m_io, std::chrono::seconds(1)))
1580f0462caSWalter Erquinigo return toString(ToError(*message.get()));
1590f0462caSWalter Erquinigo else
1600f0462caSWalter Erquinigo return toString(message.takeError());
1610f0462caSWalter Erquinigo }
1620f0462caSWalter Erquinigo
CreateRunInTerminalCommFile()1630f0462caSWalter Erquinigo Expected<std::shared_ptr<FifoFile>> CreateRunInTerminalCommFile() {
1640f0462caSWalter Erquinigo SmallString<256> comm_file;
1650f0462caSWalter Erquinigo if (std::error_code EC = sys::fs::getPotentiallyUniqueTempFileName(
1660f0462caSWalter Erquinigo "lldb-vscode-run-in-terminal-comm", "", comm_file))
1670f0462caSWalter Erquinigo return createStringError(EC, "Error making unique file name for "
1680f0462caSWalter Erquinigo "runInTerminal communication files");
1690f0462caSWalter Erquinigo
1700f0462caSWalter Erquinigo return CreateFifoFile(comm_file.str());
1710f0462caSWalter Erquinigo }
1720f0462caSWalter Erquinigo
1730f0462caSWalter Erquinigo } // namespace lldb_vscode
174