Skip to content

Commit f55dc08

Browse files
[lldb][windows] use Windows APIs to print to the console (#149493)
This patch uses the Windows APIs to print to the Windows Console, through `llvm::raw_fd_ostream`. This fixes a rendering issue where the characters defined in `DiagnosticsRendering.cpp` (`"╰"` for instance) are not rendered properly on Windows out of the box, because the default codepage is not `utf-8`. This solution is based on [this patch downstream](https://github.com/swiftlang/swift/pull/40632/files#diff-e948e4bd7a601e3ca82d596058ccb39326459a4751470eec4d393adeaf516977R37-R38). rdar://156064500
1 parent 1359f72 commit f55dc08

File tree

2 files changed

+47
-9
lines changed

2 files changed

+47
-9
lines changed

lldb/include/lldb/Host/File.h

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -382,15 +382,11 @@ class NativeFile : public File {
382382
Unowned = false,
383383
};
384384

385-
NativeFile() : m_descriptor(kInvalidDescriptor), m_stream(kInvalidStream) {}
385+
NativeFile();
386386

387-
NativeFile(FILE *fh, bool transfer_ownership)
388-
: m_descriptor(kInvalidDescriptor), m_own_descriptor(false), m_stream(fh),
389-
m_options(), m_own_stream(transfer_ownership) {}
387+
NativeFile(FILE *fh, bool transfer_ownership);
390388

391-
NativeFile(int fd, OpenOptions options, bool transfer_ownership)
392-
: m_descriptor(fd), m_own_descriptor(transfer_ownership),
393-
m_stream(kInvalidStream), m_options(options), m_own_stream(false) {}
389+
NativeFile(int fd, OpenOptions options, bool transfer_ownership);
394390

395391
~NativeFile() override { Close(); }
396392

@@ -444,17 +440,19 @@ class NativeFile : public File {
444440
return ValueGuard(m_stream_mutex, StreamIsValidUnlocked());
445441
}
446442

447-
int m_descriptor;
443+
int m_descriptor = kInvalidDescriptor;
448444
bool m_own_descriptor = false;
449445
mutable std::mutex m_descriptor_mutex;
450446

451-
FILE *m_stream;
447+
FILE *m_stream = kInvalidStream;
452448
mutable std::mutex m_stream_mutex;
453449

454450
OpenOptions m_options{};
455451
bool m_own_stream = false;
456452
std::mutex offset_access_mutex;
457453

454+
bool is_windows_console = false;
455+
458456
private:
459457
NativeFile(const NativeFile &) = delete;
460458
const NativeFile &operator=(const NativeFile &) = delete;

lldb/source/Host/common/File.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "llvm/Support/Errno.h"
3737
#include "llvm/Support/FileSystem.h"
3838
#include "llvm/Support/Process.h"
39+
#include "llvm/Support/raw_ostream.h"
3940

4041
using namespace lldb;
4142
using namespace lldb_private;
@@ -247,6 +248,32 @@ uint32_t File::GetPermissions(Status &error) const {
247248
return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
248249
}
249250

251+
NativeFile::NativeFile() = default;
252+
253+
NativeFile::NativeFile(FILE *fh, bool transfer_ownership)
254+
: m_stream(fh), m_own_stream(transfer_ownership) {
255+
#ifdef _WIN32
256+
// In order to properly display non ASCII characters in Windows, we need to
257+
// use Windows APIs to print to the console. This is only required if the
258+
// stream outputs to a console.
259+
int fd = _fileno(fh);
260+
is_windows_console =
261+
::GetFileType((HANDLE)::_get_osfhandle(fd)) == FILE_TYPE_CHAR;
262+
#endif
263+
}
264+
265+
NativeFile::NativeFile(int fd, OpenOptions options, bool transfer_ownership)
266+
: m_descriptor(fd), m_own_descriptor(transfer_ownership),
267+
m_options(options) {
268+
#ifdef _WIN32
269+
// In order to properly display non ASCII characters in Windows, we need to
270+
// use Windows APIs to print to the console. This is only required if the
271+
// file outputs to a console.
272+
is_windows_console =
273+
::GetFileType((HANDLE)::_get_osfhandle(fd)) == FILE_TYPE_CHAR;
274+
#endif
275+
}
276+
250277
bool NativeFile::IsValid() const {
251278
std::scoped_lock<std::mutex, std::mutex> lock(m_descriptor_mutex, m_stream_mutex);
252279
return DescriptorIsValidUnlocked() || StreamIsValidUnlocked();
@@ -618,6 +645,12 @@ Status NativeFile::Write(const void *buf, size_t &num_bytes) {
618645

619646
ssize_t bytes_written = -1;
620647
if (ValueGuard descriptor_guard = DescriptorIsValid()) {
648+
#ifdef _WIN32
649+
if (is_windows_console) {
650+
llvm::raw_fd_ostream(m_descriptor, false).write((char *)buf, num_bytes);
651+
return error;
652+
}
653+
#endif
621654
bytes_written =
622655
llvm::sys::RetryAfterSignal(-1, ::write, m_descriptor, buf, num_bytes);
623656
if (bytes_written == -1) {
@@ -629,6 +662,13 @@ Status NativeFile::Write(const void *buf, size_t &num_bytes) {
629662
}
630663

631664
if (ValueGuard stream_guard = StreamIsValid()) {
665+
#ifdef _WIN32
666+
if (is_windows_console) {
667+
llvm::raw_fd_ostream(_fileno(m_stream), false)
668+
.write((char *)buf, num_bytes);
669+
return error;
670+
}
671+
#endif
632672
bytes_written = ::fwrite(buf, 1, num_bytes, m_stream);
633673

634674
if (bytes_written == 0) {

0 commit comments

Comments
 (0)