Coverage Report

Created: 2023-09-21 18:56

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/tools/lldb-vscode/RunInTerminal.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- RunInTerminal.cpp ---------------------------------------*- C++ -*-===//
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
#include "RunInTerminal.h"
10
11
#if !defined(_WIN32)
12
#include <sys/stat.h>
13
#include <sys/types.h>
14
#include <unistd.h>
15
#endif
16
17
#include <chrono>
18
#include <fstream>
19
#include <future>
20
#include <thread>
21
22
#include "llvm/Support/FileSystem.h"
23
24
#include "lldb/lldb-defines.h"
25
26
using namespace llvm;
27
28
namespace lldb_vscode {
29
30
0
const RunInTerminalMessagePid *RunInTerminalMessage::GetAsPidMessage() const {
31
0
  return static_cast<const RunInTerminalMessagePid *>(this);
32
0
}
33
34
const RunInTerminalMessageError *
35
0
RunInTerminalMessage::GetAsErrorMessage() const {
36
0
  return static_cast<const RunInTerminalMessageError *>(this);
37
0
}
38
39
RunInTerminalMessage::RunInTerminalMessage(RunInTerminalMessageKind kind)
40
0
    : kind(kind) {}
41
42
RunInTerminalMessagePid::RunInTerminalMessagePid(lldb::pid_t pid)
43
0
    : RunInTerminalMessage(eRunInTerminalMessageKindPID), pid(pid) {}
44
45
0
json::Value RunInTerminalMessagePid::ToJSON() const {
46
0
  return json::Object{{"kind", "pid"}, {"pid", static_cast<int64_t>(pid)}};
47
0
}
48
49
RunInTerminalMessageError::RunInTerminalMessageError(StringRef error)
50
0
    : RunInTerminalMessage(eRunInTerminalMessageKindError), error(error) {}
51
52
0
json::Value RunInTerminalMessageError::ToJSON() const {
53
0
  return json::Object{{"kind", "error"}, {"value", error}};
54
0
}
55
56
RunInTerminalMessageDidAttach::RunInTerminalMessageDidAttach()
57
0
    : RunInTerminalMessage(eRunInTerminalMessageKindDidAttach) {}
58
59
0
json::Value RunInTerminalMessageDidAttach::ToJSON() const {
60
0
  return json::Object{{"kind", "didAttach"}};
61
0
}
62
63
static Expected<RunInTerminalMessageUP>
64
0
ParseJSONMessage(const json::Value &json) {
65
0
  if (const json::Object *obj = json.getAsObject()) {
66
0
    if (std::optional<StringRef> kind = obj->getString("kind")) {
67
0
      if (*kind == "pid") {
68
0
        if (std::optional<int64_t> pid = obj->getInteger("pid"))
69
0
          return std::make_unique<RunInTerminalMessagePid>(
70
0
              static_cast<lldb::pid_t>(*pid));
71
0
      } else if (*kind == "error") {
72
0
        if (std::optional<StringRef> error = obj->getString("error"))
73
0
          return std::make_unique<RunInTerminalMessageError>(*error);
74
0
      } else if (*kind == "didAttach") {
75
0
        return std::make_unique<RunInTerminalMessageDidAttach>();
76
0
      }
77
0
    }
78
0
  }
79
80
0
  return createStringError(inconvertibleErrorCode(),
81
0
                           "Incorrect JSON message: " + JSONToString(json));
82
0
}
83
84
static Expected<RunInTerminalMessageUP>
85
0
GetNextMessage(FifoFileIO &io, std::chrono::milliseconds timeout) {
86
0
  if (Expected<json::Value> json = io.ReadJSON(timeout))
87
0
    return ParseJSONMessage(*json);
88
0
  else
89
0
    return json.takeError();
90
0
}
91
92
0
static Error ToError(const RunInTerminalMessage &message) {
93
0
  if (message.kind == eRunInTerminalMessageKindError)
94
0
    return createStringError(inconvertibleErrorCode(),
95
0
                             message.GetAsErrorMessage()->error);
96
0
  return createStringError(inconvertibleErrorCode(),
97
0
                           "Unexpected JSON message: " +
98
0
                               JSONToString(message.ToJSON()));
99
0
}
100
101
RunInTerminalLauncherCommChannel::RunInTerminalLauncherCommChannel(
102
    StringRef comm_file)
103
0
    : m_io(comm_file, "debug adaptor") {}
104
105
Error RunInTerminalLauncherCommChannel::WaitUntilDebugAdaptorAttaches(
106
0
    std::chrono::milliseconds timeout) {
107
0
  if (Expected<RunInTerminalMessageUP> message =
108
0
          GetNextMessage(m_io, timeout)) {
109
0
    if (message.get()->kind == eRunInTerminalMessageKindDidAttach)
110
0
      return Error::success();
111
0
    else
112
0
      return ToError(*message.get());
113
0
  } else
114
0
    return message.takeError();
115
0
}
116
117
0
Error RunInTerminalLauncherCommChannel::NotifyPid() {
118
0
  return m_io.SendJSON(RunInTerminalMessagePid(getpid()).ToJSON());
119
0
}
120
121
0
void RunInTerminalLauncherCommChannel::NotifyError(StringRef error) {
122
0
  if (Error err = m_io.SendJSON(RunInTerminalMessageError(error).ToJSON(),
123
0
                                std::chrono::seconds(2)))
124
0
    llvm::errs() << llvm::toString(std::move(err)) << "\n";
125
0
}
126
127
RunInTerminalDebugAdapterCommChannel::RunInTerminalDebugAdapterCommChannel(
128
    StringRef comm_file)
129
0
    : m_io(comm_file, "runInTerminal launcher") {}
130
131
// Can't use \a std::future<llvm::Error> because it doesn't compile on Windows
132
std::future<lldb::SBError>
133
0
RunInTerminalDebugAdapterCommChannel::NotifyDidAttach() {
134
0
  return std::async(std::launch::async, [&]() {
135
0
    lldb::SBError error;
136
0
    if (llvm::Error err =
137
0
            m_io.SendJSON(RunInTerminalMessageDidAttach().ToJSON()))
138
0
      error.SetErrorString(llvm::toString(std::move(err)).c_str());
139
0
    return error;
140
0
  });
141
0
}
142
143
0
Expected<lldb::pid_t> RunInTerminalDebugAdapterCommChannel::GetLauncherPid() {
144
0
  if (Expected<RunInTerminalMessageUP> message =
145
0
          GetNextMessage(m_io, std::chrono::seconds(20))) {
146
0
    if (message.get()->kind == eRunInTerminalMessageKindPID)
147
0
      return message.get()->GetAsPidMessage()->pid;
148
0
    return ToError(*message.get());
149
0
  } else {
150
0
    return message.takeError();
151
0
  }
152
0
}
153
154
0
std::string RunInTerminalDebugAdapterCommChannel::GetLauncherError() {
155
  // We know there's been an error, so a small timeout is enough.
156
0
  if (Expected<RunInTerminalMessageUP> message =
157
0
          GetNextMessage(m_io, std::chrono::seconds(1)))
158
0
    return toString(ToError(*message.get()));
159
0
  else
160
0
    return toString(message.takeError());
161
0
}
162
163
0
Expected<std::shared_ptr<FifoFile>> CreateRunInTerminalCommFile() {
164
0
  SmallString<256> comm_file;
165
0
  if (std::error_code EC = sys::fs::getPotentiallyUniqueTempFileName(
166
0
          "lldb-vscode-run-in-terminal-comm", "", comm_file))
167
0
    return createStringError(EC, "Error making unique file name for "
168
0
                                 "runInTerminal communication files");
169
170
0
  return CreateFifoFile(comm_file.str());
171
0
}
172
173
} // namespace lldb_vscode