[lldb-vscode] Implement stderr/stdout on win32 and redirect lldb log to VSCode

This patch implements stderr/stdout forwarding on windows.
This was previously not implemented in D99974.
I added separate callbacks so the output can be sent to the different channels VSCode provides (OutputType::Stdout, OutputType::Stderr, OutputType::Console).

This patch also passes a log callback handler to SBDebugger::Create to be able to see logging output when it is enabled.

Since the output is now redirect on early startup I removed the calls to SetOutputFileHandle/SetErrorFileHandle, which set them to /dev/null.

I send the output of stderr/stdout/lldb log to OutputType::Console

Reviewed By: wallace

Differential Revision: https://reviews.llvm.org/D123025
This commit is contained in:
Walter Erquinigo 2022-04-05 11:21:22 -07:00
parent 5561ab3495
commit 9bcaf6ddfe
2 changed files with 33 additions and 35 deletions

View File

@ -6,20 +6,27 @@
//
//===----------------------------------------------------------------------===/
#if !defined(_WIN32)
#if defined(_WIN32)
#include <fcntl.h>
#include <io.h>
#else
#include <unistd.h>
#endif
#include "OutputRedirector.h"
#include "llvm/ADT/StringRef.h"
using namespace llvm;
namespace lldb_vscode {
Error RedirectFd(int fd, std::function<void(llvm::StringRef)> callback) {
#if !defined(_WIN32)
int new_fd[2];
#if defined(_WIN32)
if (_pipe(new_fd, 4096, O_TEXT) == -1) {
#else
if (pipe(new_fd) == -1) {
#endif
int error = errno;
return createStringError(inconvertibleErrorCode(),
"Couldn't create new pipe for fd %d. %s", fd,
@ -45,11 +52,10 @@ Error RedirectFd(int fd, std::function<void(llvm::StringRef)> callback) {
continue;
break;
}
callback(StringRef(buffer, bytes_count).str());
callback(StringRef(buffer, bytes_count));
}
});
t.detach();
#endif
return Error::success();
}

View File

@ -65,11 +65,6 @@
#define PATH_MAX MAX_PATH
#endif
typedef int socklen_t;
constexpr const char *dev_null_path = "nul";
#else
constexpr const char *dev_null_path = "/dev/null";
#endif
using namespace lldb_vscode;
@ -1446,23 +1441,13 @@ void request_modules(const llvm::json::Object &request) {
// }]
// }
void request_initialize(const llvm::json::Object &request) {
g_vsc.debugger = lldb::SBDebugger::Create(true /*source_init_files*/);
auto log_cb = [](const char *buf, void *baton) -> void {
g_vsc.SendOutput(OutputType::Console, llvm::StringRef{buf});
};
g_vsc.debugger =
lldb::SBDebugger::Create(true /*source_init_files*/, log_cb, nullptr);
g_vsc.progress_event_thread = std::thread(ProgressEventThreadFunction);
// Create an empty target right away since we might get breakpoint requests
// before we are given an executable to launch in a "launch" request, or a
// executable when attaching to a process by process ID in a "attach"
// request.
FILE *out = llvm::sys::RetryAfterSignal(nullptr, fopen, dev_null_path, "w");
if (out) {
// Set the output and error file handles to redirect into nothing otherwise
// if any code in LLDB prints to the debugger file handles, the output and
// error file handles are initialized to STDOUT and STDERR and any output
// will kill our debug session.
g_vsc.debugger.SetOutputFileHandle(out, true);
g_vsc.debugger.SetErrorFileHandle(out, false);
}
// Start our event thread so we can receive events from the debugger, target,
// process and more.
g_vsc.event_thread = std::thread(EventThreadFunction);
@ -3147,18 +3132,25 @@ void redirection_test() {
/// \return
/// A fd pointing to the original stdout.
int SetupStdoutStderrRedirection() {
int new_stdout_fd = dup(fileno(stdout));
auto stdout_err_redirector_callback = [&](llvm::StringRef data) {
g_vsc.SendOutput(OutputType::Console, data);
int stdoutfd = fileno(stdout);
int new_stdout_fd = dup(stdoutfd);
auto output_callback_stderr = [](llvm::StringRef data) {
g_vsc.SendOutput(OutputType::Stderr, data);
};
for (int fd : {fileno(stdout), fileno(stderr)}) {
if (llvm::Error err = RedirectFd(fd, stdout_err_redirector_callback)) {
std::string error_message = llvm::toString(std::move(err));
if (g_vsc.log)
*g_vsc.log << error_message << std::endl;
stdout_err_redirector_callback(error_message);
}
auto output_callback_stdout = [](llvm::StringRef data) {
g_vsc.SendOutput(OutputType::Stdout, data);
};
if (llvm::Error err = RedirectFd(stdoutfd, output_callback_stdout)) {
std::string error_message = llvm::toString(std::move(err));
if (g_vsc.log)
*g_vsc.log << error_message << std::endl;
output_callback_stderr(error_message);
}
if (llvm::Error err = RedirectFd(fileno(stderr), output_callback_stderr)) {
std::string error_message = llvm::toString(std::move(err));
if (g_vsc.log)
*g_vsc.log << error_message << std::endl;
output_callback_stderr(error_message);
}
/// used only by TestVSCode_redirection_to_console.py