1 //===-- SBStream.cpp ----------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/API/SBStream.h" 10 11 #include "SBReproducerPrivate.h" 12 #include "lldb/Core/StreamFile.h" 13 #include "lldb/Host/FileSystem.h" 14 #include "lldb/Utility/Status.h" 15 #include "lldb/Utility/Stream.h" 16 #include "lldb/Utility/StreamString.h" 17 18 using namespace lldb; 19 using namespace lldb_private; 20 21 SBStream::SBStream() : m_opaque_up(new StreamString()), m_is_file(false) { 22 LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBStream); 23 } 24 25 SBStream::SBStream(SBStream &&rhs) 26 : m_opaque_up(std::move(rhs.m_opaque_up)), m_is_file(rhs.m_is_file) {} 27 28 SBStream::~SBStream() {} 29 30 bool SBStream::IsValid() const { 31 LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBStream, IsValid); 32 return this->operator bool(); 33 } 34 SBStream::operator bool() const { 35 LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBStream, operator bool); 36 37 return (m_opaque_up != nullptr); 38 } 39 40 // If this stream is not redirected to a file, it will maintain a local cache 41 // for the stream data which can be accessed using this accessor. 42 const char *SBStream::GetData() { 43 LLDB_RECORD_METHOD_NO_ARGS(const char *, SBStream, GetData); 44 45 if (m_is_file || m_opaque_up == nullptr) 46 return nullptr; 47 48 return static_cast<StreamString *>(m_opaque_up.get())->GetData(); 49 } 50 51 // If this stream is not redirected to a file, it will maintain a local cache 52 // for the stream output whose length can be accessed using this accessor. 53 size_t SBStream::GetSize() { 54 LLDB_RECORD_METHOD_NO_ARGS(size_t, SBStream, GetSize); 55 56 if (m_is_file || m_opaque_up == nullptr) 57 return 0; 58 59 return static_cast<StreamString *>(m_opaque_up.get())->GetSize(); 60 } 61 62 void SBStream::Printf(const char *format, ...) { 63 if (!format) 64 return; 65 va_list args; 66 va_start(args, format); 67 ref().PrintfVarArg(format, args); 68 va_end(args); 69 } 70 71 void SBStream::RedirectToFile(const char *path, bool append) { 72 LLDB_RECORD_METHOD(void, SBStream, RedirectToFile, (const char *, bool), path, 73 append); 74 75 if (path == nullptr) 76 return; 77 78 std::string local_data; 79 if (m_opaque_up) { 80 // See if we have any locally backed data. If so, copy it so we can then 81 // redirect it to the file so we don't lose the data 82 if (!m_is_file) 83 local_data = static_cast<StreamString *>(m_opaque_up.get())->GetString(); 84 } 85 StreamFile *stream_file = new StreamFile; 86 uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate; 87 if (append) 88 open_options |= File::eOpenOptionAppend; 89 else 90 open_options |= File::eOpenOptionTruncate; 91 92 FileSystem::Instance().Open(stream_file->GetFile(), FileSpec(path), 93 open_options); 94 m_opaque_up.reset(stream_file); 95 96 if (m_opaque_up) { 97 m_is_file = true; 98 99 // If we had any data locally in our StreamString, then pass that along to 100 // the to new file we are redirecting to. 101 if (!local_data.empty()) 102 m_opaque_up->Write(&local_data[0], local_data.size()); 103 } else 104 m_is_file = false; 105 } 106 107 void SBStream::RedirectToFileHandle(FILE *fh, bool transfer_fh_ownership) { 108 LLDB_RECORD_METHOD(void, SBStream, RedirectToFileHandle, (FILE *, bool), fh, 109 transfer_fh_ownership); 110 111 if (fh == nullptr) 112 return; 113 114 std::string local_data; 115 if (m_opaque_up) { 116 // See if we have any locally backed data. If so, copy it so we can then 117 // redirect it to the file so we don't lose the data 118 if (!m_is_file) 119 local_data = static_cast<StreamString *>(m_opaque_up.get())->GetString(); 120 } 121 m_opaque_up.reset(new StreamFile(fh, transfer_fh_ownership)); 122 123 if (m_opaque_up) { 124 m_is_file = true; 125 126 // If we had any data locally in our StreamString, then pass that along to 127 // the to new file we are redirecting to. 128 if (!local_data.empty()) 129 m_opaque_up->Write(&local_data[0], local_data.size()); 130 } else 131 m_is_file = false; 132 } 133 134 void SBStream::RedirectToFileDescriptor(int fd, bool transfer_fh_ownership) { 135 LLDB_RECORD_METHOD(void, SBStream, RedirectToFileDescriptor, (int, bool), fd, 136 transfer_fh_ownership); 137 138 std::string local_data; 139 if (m_opaque_up) { 140 // See if we have any locally backed data. If so, copy it so we can then 141 // redirect it to the file so we don't lose the data 142 if (!m_is_file) 143 local_data = static_cast<StreamString *>(m_opaque_up.get())->GetString(); 144 } 145 146 m_opaque_up.reset(new StreamFile(::fdopen(fd, "w"), transfer_fh_ownership)); 147 if (m_opaque_up) { 148 m_is_file = true; 149 150 // If we had any data locally in our StreamString, then pass that along to 151 // the to new file we are redirecting to. 152 if (!local_data.empty()) 153 m_opaque_up->Write(&local_data[0], local_data.size()); 154 } else 155 m_is_file = false; 156 } 157 158 lldb_private::Stream *SBStream::operator->() { return m_opaque_up.get(); } 159 160 lldb_private::Stream *SBStream::get() { return m_opaque_up.get(); } 161 162 lldb_private::Stream &SBStream::ref() { 163 if (m_opaque_up == nullptr) 164 m_opaque_up.reset(new StreamString()); 165 return *m_opaque_up; 166 } 167 168 void SBStream::Clear() { 169 LLDB_RECORD_METHOD_NO_ARGS(void, SBStream, Clear); 170 171 if (m_opaque_up) { 172 // See if we have any locally backed data. If so, copy it so we can then 173 // redirect it to the file so we don't lose the data 174 if (m_is_file) 175 m_opaque_up.reset(); 176 else 177 static_cast<StreamString *>(m_opaque_up.get())->Clear(); 178 } 179 } 180 181 namespace lldb_private { 182 namespace repro { 183 184 template <> 185 void RegisterMethods<SBStream>(Registry &R) { 186 LLDB_REGISTER_CONSTRUCTOR(SBStream, ()); 187 LLDB_REGISTER_METHOD_CONST(bool, SBStream, IsValid, ()); 188 LLDB_REGISTER_METHOD_CONST(bool, SBStream, operator bool, ()); 189 LLDB_REGISTER_METHOD(const char *, SBStream, GetData, ()); 190 LLDB_REGISTER_METHOD(size_t, SBStream, GetSize, ()); 191 LLDB_REGISTER_METHOD(void, SBStream, RedirectToFile, (const char *, bool)); 192 LLDB_REGISTER_METHOD(void, SBStream, RedirectToFileHandle, (FILE *, bool)); 193 LLDB_REGISTER_METHOD(void, SBStream, RedirectToFileDescriptor, (int, bool)); 194 LLDB_REGISTER_METHOD(void, SBStream, Clear, ()); 195 } 196 197 } 198 } 199