diff options
Diffstat (limited to 'lldb/source/API/SBStream.cpp')
| -rw-r--r-- | lldb/source/API/SBStream.cpp | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/lldb/source/API/SBStream.cpp b/lldb/source/API/SBStream.cpp new file mode 100644 index 000000000000..d57634d2947c --- /dev/null +++ b/lldb/source/API/SBStream.cpp @@ -0,0 +1,207 @@ +//===-- SBStream.cpp ----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/API/SBStream.h" + +#include "SBReproducerPrivate.h" +#include "lldb/API/SBFile.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/StreamString.h" + +using namespace lldb; +using namespace lldb_private; + +SBStream::SBStream() : m_opaque_up(new StreamString()), m_is_file(false) { + LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBStream); +} + +SBStream::SBStream(SBStream &&rhs) + : m_opaque_up(std::move(rhs.m_opaque_up)), m_is_file(rhs.m_is_file) {} + +SBStream::~SBStream() {} + +bool SBStream::IsValid() const { + LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBStream, IsValid); + return this->operator bool(); +} +SBStream::operator bool() const { + LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBStream, operator bool); + + return (m_opaque_up != nullptr); +} + +// If this stream is not redirected to a file, it will maintain a local cache +// for the stream data which can be accessed using this accessor. +const char *SBStream::GetData() { + LLDB_RECORD_METHOD_NO_ARGS(const char *, SBStream, GetData); + + if (m_is_file || m_opaque_up == nullptr) + return nullptr; + + return static_cast<StreamString *>(m_opaque_up.get())->GetData(); +} + +// If this stream is not redirected to a file, it will maintain a local cache +// for the stream output whose length can be accessed using this accessor. +size_t SBStream::GetSize() { + LLDB_RECORD_METHOD_NO_ARGS(size_t, SBStream, GetSize); + + if (m_is_file || m_opaque_up == nullptr) + return 0; + + return static_cast<StreamString *>(m_opaque_up.get())->GetSize(); +} + +void SBStream::Printf(const char *format, ...) { + if (!format) + return; + va_list args; + va_start(args, format); + ref().PrintfVarArg(format, args); + va_end(args); +} + +void SBStream::RedirectToFile(const char *path, bool append) { + LLDB_RECORD_METHOD(void, SBStream, RedirectToFile, (const char *, bool), path, + append); + + if (path == nullptr) + return; + + std::string local_data; + if (m_opaque_up) { + // See if we have any locally backed data. If so, copy it so we can then + // redirect it to the file so we don't lose the data + if (!m_is_file) + local_data = static_cast<StreamString *>(m_opaque_up.get())->GetString(); + } + auto open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate; + if (append) + open_options |= File::eOpenOptionAppend; + else + open_options |= File::eOpenOptionTruncate; + + llvm::Expected<FileUP> file = + FileSystem::Instance().Open(FileSpec(path), open_options); + if (!file) { + LLDB_LOG_ERROR(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), file.takeError(), + "Cannot open {1}: {0}", path); + return; + } + + m_opaque_up = std::make_unique<StreamFile>(std::move(file.get())); + m_is_file = true; + + // If we had any data locally in our StreamString, then pass that along to + // the to new file we are redirecting to. + if (!local_data.empty()) + m_opaque_up->Write(&local_data[0], local_data.size()); +} + +void SBStream::RedirectToFileHandle(FILE *fh, bool transfer_fh_ownership) { + LLDB_RECORD_METHOD(void, SBStream, RedirectToFileHandle, (FILE *, bool), fh, + transfer_fh_ownership); + FileSP file = std::make_unique<NativeFile>(fh, transfer_fh_ownership); + return RedirectToFile(file); +} + +void SBStream::RedirectToFile(SBFile file) { + LLDB_RECORD_METHOD(void, SBStream, RedirectToFile, (SBFile), file) + RedirectToFile(file.GetFile()); +} + +void SBStream::RedirectToFile(FileSP file_sp) { + LLDB_RECORD_METHOD(void, SBStream, RedirectToFile, (FileSP), file_sp); + + if (!file_sp || !file_sp->IsValid()) + return; + + std::string local_data; + if (m_opaque_up) { + // See if we have any locally backed data. If so, copy it so we can then + // redirect it to the file so we don't lose the data + if (!m_is_file) + local_data = static_cast<StreamString *>(m_opaque_up.get())->GetString(); + } + + m_opaque_up = std::make_unique<StreamFile>(file_sp); + m_is_file = true; + + // If we had any data locally in our StreamString, then pass that along to + // the to new file we are redirecting to. + if (!local_data.empty()) + m_opaque_up->Write(&local_data[0], local_data.size()); +} + +void SBStream::RedirectToFileDescriptor(int fd, bool transfer_fh_ownership) { + LLDB_RECORD_METHOD(void, SBStream, RedirectToFileDescriptor, (int, bool), fd, + transfer_fh_ownership); + + std::string local_data; + if (m_opaque_up) { + // See if we have any locally backed data. If so, copy it so we can then + // redirect it to the file so we don't lose the data + if (!m_is_file) + local_data = static_cast<StreamString *>(m_opaque_up.get())->GetString(); + } + + m_opaque_up = std::make_unique<StreamFile>(fd, transfer_fh_ownership); + m_is_file = true; + + // If we had any data locally in our StreamString, then pass that along to + // the to new file we are redirecting to. + if (!local_data.empty()) + m_opaque_up->Write(&local_data[0], local_data.size()); +} + +lldb_private::Stream *SBStream::operator->() { return m_opaque_up.get(); } + +lldb_private::Stream *SBStream::get() { return m_opaque_up.get(); } + +lldb_private::Stream &SBStream::ref() { + if (m_opaque_up == nullptr) + m_opaque_up.reset(new StreamString()); + return *m_opaque_up; +} + +void SBStream::Clear() { + LLDB_RECORD_METHOD_NO_ARGS(void, SBStream, Clear); + + if (m_opaque_up) { + // See if we have any locally backed data. If so, copy it so we can then + // redirect it to the file so we don't lose the data + if (m_is_file) + m_opaque_up.reset(); + else + static_cast<StreamString *>(m_opaque_up.get())->Clear(); + } +} + +namespace lldb_private { +namespace repro { + +template <> +void RegisterMethods<SBStream>(Registry &R) { + LLDB_REGISTER_CONSTRUCTOR(SBStream, ()); + LLDB_REGISTER_METHOD_CONST(bool, SBStream, IsValid, ()); + LLDB_REGISTER_METHOD_CONST(bool, SBStream, operator bool, ()); + LLDB_REGISTER_METHOD(const char *, SBStream, GetData, ()); + LLDB_REGISTER_METHOD(size_t, SBStream, GetSize, ()); + LLDB_REGISTER_METHOD(void, SBStream, RedirectToFile, (const char *, bool)); + LLDB_REGISTER_METHOD(void, SBStream, RedirectToFile, (FileSP)); + LLDB_REGISTER_METHOD(void, SBStream, RedirectToFile, (SBFile)); + LLDB_REGISTER_METHOD(void, SBStream, RedirectToFileHandle, (FILE *, bool)); + LLDB_REGISTER_METHOD(void, SBStream, RedirectToFileDescriptor, (int, bool)); + LLDB_REGISTER_METHOD(void, SBStream, Clear, ()); +} + +} +} |
