1e2ae97f2SGreg Clayton //===-- SBStream.cpp ----------------------------------------*- C++ -*-===// 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" 12e2ae97f2SGreg Clayton #include "lldb/Core/StreamFile.h" 1350bc1ed2SJonas Devlieghere #include "lldb/Host/FileSystem.h" 1497206d57SZachary Turner #include "lldb/Utility/Status.h" 15bf9a7730SZachary Turner #include "lldb/Utility/Stream.h" 16bf9a7730SZachary Turner #include "lldb/Utility/StreamString.h" 17e2ae97f2SGreg Clayton 18e2ae97f2SGreg Clayton using namespace lldb; 19e2ae97f2SGreg Clayton using namespace lldb_private; 20e2ae97f2SGreg Clayton 21baf5664fSJonas Devlieghere SBStream::SBStream() : m_opaque_up(new StreamString()), m_is_file(false) { 22baf5664fSJonas Devlieghere LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBStream); 23baf5664fSJonas Devlieghere } 24e2ae97f2SGreg Clayton 25b9c1b51eSKate Stone SBStream::SBStream(SBStream &&rhs) 26d5b44036SJonas Devlieghere : m_opaque_up(std::move(rhs.m_opaque_up)), m_is_file(rhs.m_is_file) {} 270817da88SGreg Clayton 28b9c1b51eSKate Stone SBStream::~SBStream() {} 290817da88SGreg Clayton 30baf5664fSJonas Devlieghere bool SBStream::IsValid() const { 31baf5664fSJonas Devlieghere LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBStream, IsValid); 327f5237bcSPavel Labath return this->operator bool(); 337f5237bcSPavel Labath } 347f5237bcSPavel Labath SBStream::operator bool() const { 357f5237bcSPavel Labath LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBStream, operator bool); 36baf5664fSJonas Devlieghere 37baf5664fSJonas Devlieghere return (m_opaque_up != NULL); 38baf5664fSJonas Devlieghere } 39e2ae97f2SGreg Clayton 4005097246SAdrian Prantl // If this stream is not redirected to a file, it will maintain a local cache 4105097246SAdrian Prantl // for the stream data which can be accessed using this accessor. 42b9c1b51eSKate Stone const char *SBStream::GetData() { 43baf5664fSJonas Devlieghere LLDB_RECORD_METHOD_NO_ARGS(const char *, SBStream, GetData); 44baf5664fSJonas Devlieghere 45d5b44036SJonas Devlieghere if (m_is_file || m_opaque_up == NULL) 46e2ae97f2SGreg Clayton return NULL; 47e2ae97f2SGreg Clayton 48d5b44036SJonas Devlieghere return static_cast<StreamString *>(m_opaque_up.get())->GetData(); 49e2ae97f2SGreg Clayton } 50e2ae97f2SGreg Clayton 5105097246SAdrian Prantl // If this stream is not redirected to a file, it will maintain a local cache 5205097246SAdrian Prantl // for the stream output whose length can be accessed using this accessor. 53b9c1b51eSKate Stone size_t SBStream::GetSize() { 54baf5664fSJonas Devlieghere LLDB_RECORD_METHOD_NO_ARGS(size_t, SBStream, GetSize); 55baf5664fSJonas Devlieghere 56d5b44036SJonas Devlieghere if (m_is_file || m_opaque_up == NULL) 5760fd91ffSBill Wendling return 0; 58e2ae97f2SGreg Clayton 59d5b44036SJonas Devlieghere return static_cast<StreamString *>(m_opaque_up.get())->GetSize(); 60e2ae97f2SGreg Clayton } 61e2ae97f2SGreg Clayton 62b9c1b51eSKate Stone void SBStream::Printf(const char *format, ...) { 634f8189bcSJohnny Chen if (!format) 644f8189bcSJohnny Chen return; 65e2ae97f2SGreg Clayton va_list args; 66e2ae97f2SGreg Clayton va_start(args, format); 67e2ae97f2SGreg Clayton ref().PrintfVarArg(format, args); 68e2ae97f2SGreg Clayton va_end(args); 69e2ae97f2SGreg Clayton } 70e2ae97f2SGreg Clayton 71b9c1b51eSKate Stone void SBStream::RedirectToFile(const char *path, bool append) { 72baf5664fSJonas Devlieghere LLDB_RECORD_METHOD(void, SBStream, RedirectToFile, (const char *, bool), path, 73baf5664fSJonas Devlieghere append); 74baf5664fSJonas Devlieghere 75e2dcbd00SZachary Turner if (path == nullptr) 76e2dcbd00SZachary Turner return; 77e2dcbd00SZachary Turner 78e2ae97f2SGreg Clayton std::string local_data; 79d5b44036SJonas Devlieghere if (m_opaque_up) { 80e2ae97f2SGreg Clayton // See if we have any locally backed data. If so, copy it so we can then 81e2ae97f2SGreg Clayton // redirect it to the file so we don't lose the data 82e2ae97f2SGreg Clayton if (!m_is_file) 83d5b44036SJonas Devlieghere local_data = static_cast<StreamString *>(m_opaque_up.get())->GetString(); 84e2ae97f2SGreg Clayton } 8551b1e2d2SGreg Clayton StreamFile *stream_file = new StreamFile; 8651b1e2d2SGreg Clayton uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate; 8751b1e2d2SGreg Clayton if (append) 8851b1e2d2SGreg Clayton open_options |= File::eOpenOptionAppend; 8906357c93SGreg Clayton else 9006357c93SGreg Clayton open_options |= File::eOpenOptionTruncate; 9151b1e2d2SGreg Clayton 9250bc1ed2SJonas Devlieghere FileSystem::Instance().Open(stream_file->GetFile(), FileSpec(path), 9350bc1ed2SJonas Devlieghere open_options); 94d5b44036SJonas Devlieghere m_opaque_up.reset(stream_file); 95e2ae97f2SGreg Clayton 96d5b44036SJonas Devlieghere if (m_opaque_up) { 97e2ae97f2SGreg Clayton m_is_file = true; 98e2ae97f2SGreg Clayton 99e2ae97f2SGreg Clayton // If we had any data locally in our StreamString, then pass that along to 100e2ae97f2SGreg Clayton // the to new file we are redirecting to. 101e2ae97f2SGreg Clayton if (!local_data.empty()) 102d5b44036SJonas Devlieghere m_opaque_up->Write(&local_data[0], local_data.size()); 103b9c1b51eSKate Stone } else 104e2ae97f2SGreg Clayton m_is_file = false; 105e2ae97f2SGreg Clayton } 106e2ae97f2SGreg Clayton 107b9c1b51eSKate Stone void SBStream::RedirectToFileHandle(FILE *fh, bool transfer_fh_ownership) { 108baf5664fSJonas Devlieghere LLDB_RECORD_METHOD(void, SBStream, RedirectToFileHandle, (FILE *, bool), fh, 109baf5664fSJonas Devlieghere transfer_fh_ownership); 110baf5664fSJonas Devlieghere 111e2dcbd00SZachary Turner if (fh == nullptr) 112e2dcbd00SZachary Turner return; 113e2dcbd00SZachary Turner 114e2ae97f2SGreg Clayton std::string local_data; 115d5b44036SJonas Devlieghere if (m_opaque_up) { 116e2ae97f2SGreg Clayton // See if we have any locally backed data. If so, copy it so we can then 117e2ae97f2SGreg Clayton // redirect it to the file so we don't lose the data 118e2ae97f2SGreg Clayton if (!m_is_file) 119d5b44036SJonas Devlieghere local_data = static_cast<StreamString *>(m_opaque_up.get())->GetString(); 120e2ae97f2SGreg Clayton } 121d5b44036SJonas Devlieghere m_opaque_up.reset(new StreamFile(fh, transfer_fh_ownership)); 122e2ae97f2SGreg Clayton 123d5b44036SJonas Devlieghere if (m_opaque_up) { 124e2ae97f2SGreg Clayton m_is_file = true; 125e2ae97f2SGreg Clayton 126e2ae97f2SGreg Clayton // If we had any data locally in our StreamString, then pass that along to 127e2ae97f2SGreg Clayton // the to new file we are redirecting to. 128e2ae97f2SGreg Clayton if (!local_data.empty()) 129d5b44036SJonas Devlieghere m_opaque_up->Write(&local_data[0], local_data.size()); 130b9c1b51eSKate Stone } else 131e2ae97f2SGreg Clayton m_is_file = false; 132e2ae97f2SGreg Clayton } 133e2ae97f2SGreg Clayton 134b9c1b51eSKate Stone void SBStream::RedirectToFileDescriptor(int fd, bool transfer_fh_ownership) { 135baf5664fSJonas Devlieghere LLDB_RECORD_METHOD(void, SBStream, RedirectToFileDescriptor, (int, bool), fd, 136baf5664fSJonas Devlieghere transfer_fh_ownership); 137baf5664fSJonas Devlieghere 138e2ae97f2SGreg Clayton std::string local_data; 139d5b44036SJonas Devlieghere if (m_opaque_up) { 140e2ae97f2SGreg Clayton // See if we have any locally backed data. If so, copy it so we can then 141e2ae97f2SGreg Clayton // redirect it to the file so we don't lose the data 142e2ae97f2SGreg Clayton if (!m_is_file) 143d5b44036SJonas Devlieghere local_data = static_cast<StreamString *>(m_opaque_up.get())->GetString(); 144e2ae97f2SGreg Clayton } 145e2ae97f2SGreg Clayton 146d5b44036SJonas Devlieghere m_opaque_up.reset(new StreamFile(::fdopen(fd, "w"), transfer_fh_ownership)); 147d5b44036SJonas Devlieghere if (m_opaque_up) { 148e2ae97f2SGreg Clayton m_is_file = true; 149e2ae97f2SGreg Clayton 150e2ae97f2SGreg Clayton // If we had any data locally in our StreamString, then pass that along to 151e2ae97f2SGreg Clayton // the to new file we are redirecting to. 152e2ae97f2SGreg Clayton if (!local_data.empty()) 153d5b44036SJonas Devlieghere m_opaque_up->Write(&local_data[0], local_data.size()); 154b9c1b51eSKate Stone } else 155e2ae97f2SGreg Clayton m_is_file = false; 156e2ae97f2SGreg Clayton } 157e2ae97f2SGreg Clayton 158d5b44036SJonas Devlieghere lldb_private::Stream *SBStream::operator->() { return m_opaque_up.get(); } 159e2ae97f2SGreg Clayton 160d5b44036SJonas Devlieghere lldb_private::Stream *SBStream::get() { return m_opaque_up.get(); } 161e2ae97f2SGreg Clayton 162b9c1b51eSKate Stone lldb_private::Stream &SBStream::ref() { 163d5b44036SJonas Devlieghere if (m_opaque_up == NULL) 164d5b44036SJonas Devlieghere m_opaque_up.reset(new StreamString()); 165d5b44036SJonas Devlieghere return *m_opaque_up; 166e2ae97f2SGreg Clayton } 167e2ae97f2SGreg Clayton 168b9c1b51eSKate Stone void SBStream::Clear() { 169baf5664fSJonas Devlieghere LLDB_RECORD_METHOD_NO_ARGS(void, SBStream, Clear); 170baf5664fSJonas Devlieghere 171d5b44036SJonas Devlieghere if (m_opaque_up) { 172e2ae97f2SGreg Clayton // See if we have any locally backed data. If so, copy it so we can then 173e2ae97f2SGreg Clayton // redirect it to the file so we don't lose the data 174e2ae97f2SGreg Clayton if (m_is_file) 175d5b44036SJonas Devlieghere m_opaque_up.reset(); 176e2ae97f2SGreg Clayton else 177d5b44036SJonas Devlieghere static_cast<StreamString *>(m_opaque_up.get())->Clear(); 178e2ae97f2SGreg Clayton } 179e2ae97f2SGreg Clayton } 180*ae211eceSMichal Gorny 181*ae211eceSMichal Gorny namespace lldb_private { 182*ae211eceSMichal Gorny namespace repro { 183*ae211eceSMichal Gorny 184*ae211eceSMichal Gorny template <> 185*ae211eceSMichal Gorny void RegisterMethods<SBStream>(Registry &R) { 186*ae211eceSMichal Gorny LLDB_REGISTER_CONSTRUCTOR(SBStream, ()); 187*ae211eceSMichal Gorny LLDB_REGISTER_METHOD_CONST(bool, SBStream, IsValid, ()); 188*ae211eceSMichal Gorny LLDB_REGISTER_METHOD_CONST(bool, SBStream, operator bool, ()); 189*ae211eceSMichal Gorny LLDB_REGISTER_METHOD(const char *, SBStream, GetData, ()); 190*ae211eceSMichal Gorny LLDB_REGISTER_METHOD(size_t, SBStream, GetSize, ()); 191*ae211eceSMichal Gorny LLDB_REGISTER_METHOD(void, SBStream, RedirectToFile, (const char *, bool)); 192*ae211eceSMichal Gorny LLDB_REGISTER_METHOD(void, SBStream, RedirectToFileHandle, (FILE *, bool)); 193*ae211eceSMichal Gorny LLDB_REGISTER_METHOD(void, SBStream, RedirectToFileDescriptor, (int, bool)); 194*ae211eceSMichal Gorny LLDB_REGISTER_METHOD(void, SBStream, Clear, ()); 195*ae211eceSMichal Gorny } 196*ae211eceSMichal Gorny 197*ae211eceSMichal Gorny } 198*ae211eceSMichal Gorny } 199