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