6
6
//
7
7
// ===----------------------------------------------------------------------===//
8
8
9
- #include < chrono>
10
- #include < cstdarg>
11
- #include < fstream>
12
- #include < mutex>
13
-
14
9
#include " DAP.h"
15
10
#include " JSONUtils.h"
16
11
#include " LLDBUtils.h"
12
+ #include " lldb/API/SBBreakpoint.h"
17
13
#include " lldb/API/SBCommandInterpreter.h"
18
14
#include " lldb/API/SBLanguageRuntime.h"
19
15
#include " lldb/API/SBListener.h"
20
16
#include " lldb/API/SBStream.h"
17
+ #include " lldb/Host/FileSystem.h"
18
+ #include " lldb/API/SBCommandReturnObject.h"
19
+ #include " lldb/API/SBProcess.h"
20
+ #include " lldb/Utility/Status.h"
21
+ #include " lldb/lldb-defines.h"
22
+ #include " lldb/lldb-enumerations.h"
23
+ #include " llvm/ADT/ArrayRef.h"
24
+ #include " llvm/ADT/Twine.h"
21
25
#include " llvm/ADT/StringExtras.h"
26
+ #include " llvm/Support/Error.h"
22
27
#include " llvm/Support/FormatVariadic.h"
28
+ #include " llvm/Support/ErrorHandling.h"
29
+ #include " llvm/Support/raw_ostream.h"
30
+ #include < algorithm>
31
+ #include < cassert>
32
+ #include < chrono>
33
+ #include < cstdarg>
34
+ #include < cstdio>
35
+ #include < fstream>
36
+ #include < mutex>
37
+ #include < utility>
23
38
24
39
#if defined(_WIN32)
25
40
#define NOMINMAX
26
41
#include < fcntl.h>
27
42
#include < io.h>
28
43
#include < windows.h>
44
+ #else
45
+ #include < unistd.h>
29
46
#endif
30
47
31
48
using namespace lldb_dap ;
32
49
33
50
namespace lldb_dap {
34
51
35
- DAP::DAP (llvm::StringRef path, ReplMode repl_mode)
36
- : debug_adaptor_path(path), broadcaster(" lldb-dap" ),
52
+ DAP::DAP (llvm::StringRef path, std::optional<std::ofstream> &log,
53
+ ReplMode repl_mode, StreamDescriptor input, StreamDescriptor output)
54
+ : debug_adaptor_path(path), log(log), input(std::move(input)),
55
+ output (std::move(output)), broadcaster(" lldb-dap" ),
37
56
exception_breakpoints(), focus_tid(LLDB_INVALID_THREAD_ID),
38
57
stop_at_entry(false ), is_attach(false ),
39
58
enable_auto_variable_summaries(false ),
@@ -43,21 +62,7 @@ DAP::DAP(llvm::StringRef path, ReplMode repl_mode)
43
62
configuration_done_sent(false ), waiting_for_run_in_terminal(false ),
44
63
progress_event_reporter(
45
64
[&](const ProgressEvent &event) { SendJSON (event.ToJSON ()); }),
46
- reverse_request_seq (0 ), repl_mode(repl_mode) {
47
- const char *log_file_path = getenv (" LLDBDAP_LOG" );
48
- #if defined(_WIN32)
49
- // Windows opens stdout and stdin in text mode which converts \n to 13,10
50
- // while the value is just 10 on Darwin/Linux. Setting the file mode to binary
51
- // fixes this.
52
- int result = _setmode (fileno (stdout), _O_BINARY);
53
- assert (result);
54
- result = _setmode (fileno (stdin), _O_BINARY);
55
- UNUSED_IF_ASSERT_DISABLED (result);
56
- assert (result);
57
- #endif
58
- if (log_file_path)
59
- log.reset (new std::ofstream (log_file_path));
60
- }
65
+ reverse_request_seq (0 ), repl_mode(repl_mode) {}
61
66
62
67
DAP::~DAP () = default ;
63
68
@@ -173,6 +178,63 @@ ExceptionBreakpoint *DAP::GetExceptionBreakpoint(const lldb::break_id_t bp_id) {
173
178
return nullptr ;
174
179
}
175
180
181
+ llvm::Error DAP::ConfigureIO (std::optional<std::FILE *> overrideOut,
182
+ std::optional<std::FILE *> overrideErr) {
183
+ auto *inull = lldb_private::FileSystem::Instance ().Fopen (
184
+ lldb_private::FileSystem::DEV_NULL, " w" );
185
+ in = lldb::SBFile (inull, true );
186
+
187
+ lldb_private::Status status;
188
+ status = pout.CreateNew (/* child_process_inherit=*/ false );
189
+ if (status.Fail ())
190
+ return status.takeError ();
191
+ status = perr.CreateNew (/* child_process_inherit=*/ false );
192
+ if (status.Fail ())
193
+ return status.takeError ();
194
+
195
+ if (overrideOut) {
196
+ if (dup2 (pout.GetWriteFileDescriptor (), fileno (*overrideOut)) == -1 ) {
197
+ return llvm::make_error<llvm::StringError>(
198
+ llvm::errnoAsErrorCode (),
199
+ llvm::formatv (" override fd=%d failed" , fileno (*overrideOut))
200
+ .str ()
201
+ .c_str ());
202
+ }
203
+ }
204
+
205
+ if (overrideErr) {
206
+ if (dup2 (perr.GetWriteFileDescriptor (), fileno (*overrideErr)) == -1 ) {
207
+ return llvm::make_error<llvm::StringError>(
208
+ llvm::errnoAsErrorCode (),
209
+ llvm::formatv (" override fd=%d failed" , fileno (*overrideErr))
210
+ .str ()
211
+ .c_str ());
212
+ }
213
+ }
214
+
215
+ auto forwarder = [&](lldb_private::Pipe &pipe, OutputType outputType) {
216
+ char buffer[4098 ];
217
+ size_t bytes_read;
218
+ while (pipe.CanRead ()) {
219
+ lldb_private::Status error = pipe.ReadWithTimeout (
220
+ &buffer, sizeof (buffer), std::chrono::seconds (1 ), bytes_read);
221
+ if (error.Success ()) {
222
+ // zero bytes returned on EOF.
223
+ if (bytes_read == 0 )
224
+ break ;
225
+ SendOutput (outputType, llvm::StringRef (buffer, bytes_read));
226
+ }
227
+ }
228
+ };
229
+
230
+ stdout_forward_thread =
231
+ std::thread (forwarder, std::ref (pout), OutputType::Stdout);
232
+ stderr_forward_thread =
233
+ std::thread (forwarder, std::ref (perr), OutputType::Stderr);
234
+
235
+ return llvm::Error::success ();
236
+ }
237
+
176
238
// Send the JSON in "json_str" to the "out" stream. Correctly send the
177
239
// "Content-Length:" field followed by the length, followed by the raw
178
240
// JSON bytes.
@@ -208,19 +270,19 @@ std::string DAP::ReadJSON() {
208
270
std::string json_str;
209
271
int length;
210
272
211
- if (!input.read_expected (log. get () , " Content-Length: " ))
273
+ if (!input.read_expected (log, " Content-Length: " ))
212
274
return json_str;
213
275
214
- if (!input.read_line (log. get () , length_str))
276
+ if (!input.read_line (log, length_str))
215
277
return json_str;
216
278
217
279
if (!llvm::to_integer (length_str, length))
218
280
return json_str;
219
281
220
- if (!input.read_expected (log. get () , " \r\n " ))
282
+ if (!input.read_expected (log, " \r\n " ))
221
283
return json_str;
222
284
223
- if (!input.read_full (log. get () , length, json_str))
285
+ if (!input.read_full (log, length, json_str))
224
286
return json_str;
225
287
226
288
if (log) {
0 commit comments