180814287SRaphael Isemann //===-- SBStream.cpp ------------------------------------------------------===// 2e2ae97f2SGreg Clayton // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e2ae97f2SGreg Clayton // 7e2ae97f2SGreg Clayton //===----------------------------------------------------------------------===// 8e2ae97f2SGreg Clayton 9e2ae97f2SGreg Clayton #include "lldb/API/SBStream.h" 10e2ae97f2SGreg Clayton 11baf5664fSJonas Devlieghere #include "SBReproducerPrivate.h" 1230cf6095SLawrence D'Anna #include "lldb/API/SBFile.h" 13e2ae97f2SGreg Clayton #include "lldb/Core/StreamFile.h" 1450bc1ed2SJonas Devlieghere #include "lldb/Host/FileSystem.h" 1597206d57SZachary Turner #include "lldb/Utility/Status.h" 16bf9a7730SZachary Turner #include "lldb/Utility/Stream.h" 17bf9a7730SZachary Turner #include "lldb/Utility/StreamString.h" 18e2ae97f2SGreg Clayton 19e2ae97f2SGreg Clayton using namespace lldb; 20e2ae97f2SGreg Clayton using namespace lldb_private; 21e2ae97f2SGreg Clayton 22baf5664fSJonas Devlieghere SBStream::SBStream() : m_opaque_up(new StreamString()), m_is_file(false) { 23baf5664fSJonas Devlieghere LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBStream); 24baf5664fSJonas Devlieghere } 25e2ae97f2SGreg Clayton 26b9c1b51eSKate Stone SBStream::SBStream(SBStream &&rhs) 27d5b44036SJonas Devlieghere : m_opaque_up(std::move(rhs.m_opaque_up)), m_is_file(rhs.m_is_file) {} 280817da88SGreg Clayton 29b9c1b51eSKate Stone SBStream::~SBStream() {} 300817da88SGreg Clayton 31baf5664fSJonas Devlieghere bool SBStream::IsValid() const { 32baf5664fSJonas Devlieghere LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBStream, IsValid); 337f5237bcSPavel Labath return this->operator bool(); 347f5237bcSPavel Labath } 357f5237bcSPavel Labath SBStream::operator bool() const { 367f5237bcSPavel Labath LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBStream, operator bool); 37baf5664fSJonas Devlieghere 38248a1305SKonrad Kleine return (m_opaque_up != nullptr); 39baf5664fSJonas Devlieghere } 40e2ae97f2SGreg Clayton 4105097246SAdrian Prantl // If this stream is not redirected to a file, it will maintain a local cache 4205097246SAdrian Prantl // for the stream data which can be accessed using this accessor. 43b9c1b51eSKate Stone const char *SBStream::GetData() { 44baf5664fSJonas Devlieghere LLDB_RECORD_METHOD_NO_ARGS(const char *, SBStream, GetData); 45baf5664fSJonas Devlieghere 46248a1305SKonrad Kleine if (m_is_file || m_opaque_up == nullptr) 47248a1305SKonrad Kleine return nullptr; 48e2ae97f2SGreg Clayton 49d5b44036SJonas Devlieghere return static_cast<StreamString *>(m_opaque_up.get())->GetData(); 50e2ae97f2SGreg Clayton } 51e2ae97f2SGreg Clayton 5205097246SAdrian Prantl // If this stream is not redirected to a file, it will maintain a local cache 5305097246SAdrian Prantl // for the stream output whose length can be accessed using this accessor. 54b9c1b51eSKate Stone size_t SBStream::GetSize() { 55baf5664fSJonas Devlieghere LLDB_RECORD_METHOD_NO_ARGS(size_t, SBStream, GetSize); 56baf5664fSJonas Devlieghere 57248a1305SKonrad Kleine if (m_is_file || m_opaque_up == nullptr) 5860fd91ffSBill Wendling return 0; 59e2ae97f2SGreg Clayton 60d5b44036SJonas Devlieghere return static_cast<StreamString *>(m_opaque_up.get())->GetSize(); 61e2ae97f2SGreg Clayton } 62e2ae97f2SGreg Clayton 63b9c1b51eSKate Stone void SBStream::Printf(const char *format, ...) { 644f8189bcSJohnny Chen if (!format) 654f8189bcSJohnny Chen return; 66e2ae97f2SGreg Clayton va_list args; 67e2ae97f2SGreg Clayton va_start(args, format); 68e2ae97f2SGreg Clayton ref().PrintfVarArg(format, args); 69e2ae97f2SGreg Clayton va_end(args); 70e2ae97f2SGreg Clayton } 71e2ae97f2SGreg Clayton 72b9c1b51eSKate Stone void SBStream::RedirectToFile(const char *path, bool append) { 73baf5664fSJonas Devlieghere LLDB_RECORD_METHOD(void, SBStream, RedirectToFile, (const char *, bool), path, 74baf5664fSJonas Devlieghere append); 75baf5664fSJonas Devlieghere 76e2dcbd00SZachary Turner if (path == nullptr) 77e2dcbd00SZachary Turner return; 78e2dcbd00SZachary Turner 79e2ae97f2SGreg Clayton std::string local_data; 80d5b44036SJonas Devlieghere if (m_opaque_up) { 81e2ae97f2SGreg Clayton // See if we have any locally backed data. If so, copy it so we can then 82e2ae97f2SGreg Clayton // redirect it to the file so we don't lose the data 83e2ae97f2SGreg Clayton if (!m_is_file) 84*adcd0268SBenjamin Kramer local_data = std::string( 85*adcd0268SBenjamin Kramer static_cast<StreamString *>(m_opaque_up.get())->GetString()); 86e2ae97f2SGreg Clayton } 8762c9fe42SLawrence D'Anna auto open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate; 8851b1e2d2SGreg Clayton if (append) 8951b1e2d2SGreg Clayton open_options |= File::eOpenOptionAppend; 9006357c93SGreg Clayton else 9106357c93SGreg Clayton open_options |= File::eOpenOptionTruncate; 9251b1e2d2SGreg Clayton 932fce1137SLawrence D'Anna llvm::Expected<FileUP> file = 942fce1137SLawrence D'Anna FileSystem::Instance().Open(FileSpec(path), open_options); 952fce1137SLawrence D'Anna if (!file) { 962fce1137SLawrence D'Anna LLDB_LOG_ERROR(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), file.takeError(), 972fce1137SLawrence D'Anna "Cannot open {1}: {0}", path); 982fce1137SLawrence D'Anna return; 992fce1137SLawrence D'Anna } 100e2ae97f2SGreg Clayton 1012fce1137SLawrence D'Anna m_opaque_up = std::make_unique<StreamFile>(std::move(file.get())); 102e2ae97f2SGreg Clayton m_is_file = true; 103e2ae97f2SGreg Clayton 104e2ae97f2SGreg Clayton // If we had any data locally in our StreamString, then pass that along to 105e2ae97f2SGreg Clayton // the to new file we are redirecting to. 106e2ae97f2SGreg Clayton if (!local_data.empty()) 107d5b44036SJonas Devlieghere m_opaque_up->Write(&local_data[0], local_data.size()); 108e2ae97f2SGreg Clayton } 109e2ae97f2SGreg Clayton 110b9c1b51eSKate Stone void SBStream::RedirectToFileHandle(FILE *fh, bool transfer_fh_ownership) { 111baf5664fSJonas Devlieghere LLDB_RECORD_METHOD(void, SBStream, RedirectToFileHandle, (FILE *, bool), fh, 112baf5664fSJonas Devlieghere transfer_fh_ownership); 11330cf6095SLawrence D'Anna FileSP file = std::make_unique<NativeFile>(fh, transfer_fh_ownership); 11430cf6095SLawrence D'Anna return RedirectToFile(file); 11530cf6095SLawrence D'Anna } 116baf5664fSJonas Devlieghere 11730cf6095SLawrence D'Anna void SBStream::RedirectToFile(SBFile file) { 11830cf6095SLawrence D'Anna LLDB_RECORD_METHOD(void, SBStream, RedirectToFile, (SBFile), file) 11930cf6095SLawrence D'Anna RedirectToFile(file.GetFile()); 12030cf6095SLawrence D'Anna } 12130cf6095SLawrence D'Anna 12230cf6095SLawrence D'Anna void SBStream::RedirectToFile(FileSP file_sp) { 12330cf6095SLawrence D'Anna LLDB_RECORD_METHOD(void, SBStream, RedirectToFile, (FileSP), file_sp); 12430cf6095SLawrence D'Anna 12530cf6095SLawrence D'Anna if (!file_sp || !file_sp->IsValid()) 126e2dcbd00SZachary Turner return; 127e2dcbd00SZachary Turner 128e2ae97f2SGreg Clayton std::string local_data; 129d5b44036SJonas Devlieghere if (m_opaque_up) { 130e2ae97f2SGreg Clayton // See if we have any locally backed data. If so, copy it so we can then 131e2ae97f2SGreg Clayton // redirect it to the file so we don't lose the data 132e2ae97f2SGreg Clayton if (!m_is_file) 133*adcd0268SBenjamin Kramer local_data = std::string( 134*adcd0268SBenjamin Kramer static_cast<StreamString *>(m_opaque_up.get())->GetString()); 135e2ae97f2SGreg Clayton } 136e2ae97f2SGreg Clayton 13730cf6095SLawrence D'Anna m_opaque_up = std::make_unique<StreamFile>(file_sp); 138e2ae97f2SGreg Clayton m_is_file = true; 139e2ae97f2SGreg Clayton 140e2ae97f2SGreg Clayton // If we had any data locally in our StreamString, then pass that along to 141e2ae97f2SGreg Clayton // the to new file we are redirecting to. 142e2ae97f2SGreg Clayton if (!local_data.empty()) 143d5b44036SJonas Devlieghere m_opaque_up->Write(&local_data[0], local_data.size()); 144e2ae97f2SGreg Clayton } 145e2ae97f2SGreg Clayton 146b9c1b51eSKate Stone void SBStream::RedirectToFileDescriptor(int fd, bool transfer_fh_ownership) { 147baf5664fSJonas Devlieghere LLDB_RECORD_METHOD(void, SBStream, RedirectToFileDescriptor, (int, bool), fd, 148baf5664fSJonas Devlieghere transfer_fh_ownership); 149baf5664fSJonas Devlieghere 150e2ae97f2SGreg Clayton std::string local_data; 151d5b44036SJonas Devlieghere if (m_opaque_up) { 152e2ae97f2SGreg Clayton // See if we have any locally backed data. If so, copy it so we can then 153e2ae97f2SGreg Clayton // redirect it to the file so we don't lose the data 154e2ae97f2SGreg Clayton if (!m_is_file) 155*adcd0268SBenjamin Kramer local_data = std::string( 156*adcd0268SBenjamin Kramer static_cast<StreamString *>(m_opaque_up.get())->GetString()); 157e2ae97f2SGreg Clayton } 158e2ae97f2SGreg Clayton 1592fce1137SLawrence D'Anna m_opaque_up = std::make_unique<StreamFile>(fd, transfer_fh_ownership); 160e2ae97f2SGreg Clayton m_is_file = true; 161e2ae97f2SGreg Clayton 162e2ae97f2SGreg Clayton // If we had any data locally in our StreamString, then pass that along to 163e2ae97f2SGreg Clayton // the to new file we are redirecting to. 164e2ae97f2SGreg Clayton if (!local_data.empty()) 165d5b44036SJonas Devlieghere m_opaque_up->Write(&local_data[0], local_data.size()); 166e2ae97f2SGreg Clayton } 167e2ae97f2SGreg Clayton 168d5b44036SJonas Devlieghere lldb_private::Stream *SBStream::operator->() { return m_opaque_up.get(); } 169e2ae97f2SGreg Clayton 170d5b44036SJonas Devlieghere lldb_private::Stream *SBStream::get() { return m_opaque_up.get(); } 171e2ae97f2SGreg Clayton 172b9c1b51eSKate Stone lldb_private::Stream &SBStream::ref() { 173248a1305SKonrad Kleine if (m_opaque_up == nullptr) 174d5b44036SJonas Devlieghere m_opaque_up.reset(new StreamString()); 175d5b44036SJonas Devlieghere return *m_opaque_up; 176e2ae97f2SGreg Clayton } 177e2ae97f2SGreg Clayton 178b9c1b51eSKate Stone void SBStream::Clear() { 179baf5664fSJonas Devlieghere LLDB_RECORD_METHOD_NO_ARGS(void, SBStream, Clear); 180baf5664fSJonas Devlieghere 181d5b44036SJonas Devlieghere if (m_opaque_up) { 182e2ae97f2SGreg Clayton // See if we have any locally backed data. If so, copy it so we can then 183e2ae97f2SGreg Clayton // redirect it to the file so we don't lose the data 184e2ae97f2SGreg Clayton if (m_is_file) 185d5b44036SJonas Devlieghere m_opaque_up.reset(); 186e2ae97f2SGreg Clayton else 187d5b44036SJonas Devlieghere static_cast<StreamString *>(m_opaque_up.get())->Clear(); 188e2ae97f2SGreg Clayton } 189e2ae97f2SGreg Clayton } 190ae211eceSMichal Gorny 191ae211eceSMichal Gorny namespace lldb_private { 192ae211eceSMichal Gorny namespace repro { 193ae211eceSMichal Gorny 194ae211eceSMichal Gorny template <> 195ae211eceSMichal Gorny void RegisterMethods<SBStream>(Registry &R) { 196ae211eceSMichal Gorny LLDB_REGISTER_CONSTRUCTOR(SBStream, ()); 197ae211eceSMichal Gorny LLDB_REGISTER_METHOD_CONST(bool, SBStream, IsValid, ()); 198ae211eceSMichal Gorny LLDB_REGISTER_METHOD_CONST(bool, SBStream, operator bool, ()); 199ae211eceSMichal Gorny LLDB_REGISTER_METHOD(const char *, SBStream, GetData, ()); 200ae211eceSMichal Gorny LLDB_REGISTER_METHOD(size_t, SBStream, GetSize, ()); 201ae211eceSMichal Gorny LLDB_REGISTER_METHOD(void, SBStream, RedirectToFile, (const char *, bool)); 20230cf6095SLawrence D'Anna LLDB_REGISTER_METHOD(void, SBStream, RedirectToFile, (FileSP)); 20330cf6095SLawrence D'Anna LLDB_REGISTER_METHOD(void, SBStream, RedirectToFile, (SBFile)); 204ae211eceSMichal Gorny LLDB_REGISTER_METHOD(void, SBStream, RedirectToFileHandle, (FILE *, bool)); 205ae211eceSMichal Gorny LLDB_REGISTER_METHOD(void, SBStream, RedirectToFileDescriptor, (int, bool)); 206ae211eceSMichal Gorny LLDB_REGISTER_METHOD(void, SBStream, Clear, ()); 207ae211eceSMichal Gorny } 208ae211eceSMichal Gorny 209ae211eceSMichal Gorny } 210ae211eceSMichal Gorny } 211