SBStream.cpp revision 360784
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/API/SBFile.h" 13#include "lldb/Core/StreamFile.h" 14#include "lldb/Host/FileSystem.h" 15#include "lldb/Utility/Status.h" 16#include "lldb/Utility/Stream.h" 17#include "lldb/Utility/StreamString.h" 18 19using namespace lldb; 20using namespace lldb_private; 21 22SBStream::SBStream() : m_opaque_up(new StreamString()), m_is_file(false) { 23 LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBStream); 24} 25 26SBStream::SBStream(SBStream &&rhs) 27 : m_opaque_up(std::move(rhs.m_opaque_up)), m_is_file(rhs.m_is_file) {} 28 29SBStream::~SBStream() {} 30 31bool SBStream::IsValid() const { 32 LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBStream, IsValid); 33 return this->operator bool(); 34} 35SBStream::operator bool() const { 36 LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBStream, operator bool); 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. 43const char *SBStream::GetData() { 44 LLDB_RECORD_METHOD_NO_ARGS(const char *, SBStream, GetData); 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. 54size_t SBStream::GetSize() { 55 LLDB_RECORD_METHOD_NO_ARGS(size_t, SBStream, GetSize); 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 63void SBStream::Printf(const char *format, ...) { 64 if (!format) 65 return; 66 va_list args; 67 va_start(args, format); 68 ref().PrintfVarArg(format, args); 69 va_end(args); 70} 71 72void SBStream::RedirectToFile(const char *path, bool append) { 73 LLDB_RECORD_METHOD(void, SBStream, RedirectToFile, (const char *, bool), path, 74 append); 75 76 if (path == nullptr) 77 return; 78 79 std::string local_data; 80 if (m_opaque_up) { 81 // See if we have any locally backed data. If so, copy it so we can then 82 // redirect it to the file so we don't lose the data 83 if (!m_is_file) 84 local_data = static_cast<StreamString *>(m_opaque_up.get())->GetString(); 85 } 86 auto open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate; 87 if (append) 88 open_options |= File::eOpenOptionAppend; 89 else 90 open_options |= File::eOpenOptionTruncate; 91 92 llvm::Expected<FileUP> file = 93 FileSystem::Instance().Open(FileSpec(path), open_options); 94 if (!file) { 95 LLDB_LOG_ERROR(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), file.takeError(), 96 "Cannot open {1}: {0}", path); 97 return; 98 } 99 100 m_opaque_up = std::make_unique<StreamFile>(std::move(file.get())); 101 m_is_file = true; 102 103 // If we had any data locally in our StreamString, then pass that along to 104 // the to new file we are redirecting to. 105 if (!local_data.empty()) 106 m_opaque_up->Write(&local_data[0], local_data.size()); 107} 108 109void SBStream::RedirectToFileHandle(FILE *fh, bool transfer_fh_ownership) { 110 LLDB_RECORD_METHOD(void, SBStream, RedirectToFileHandle, (FILE *, bool), fh, 111 transfer_fh_ownership); 112 FileSP file = std::make_unique<NativeFile>(fh, transfer_fh_ownership); 113 return RedirectToFile(file); 114} 115 116void SBStream::RedirectToFile(SBFile file) { 117 LLDB_RECORD_METHOD(void, SBStream, RedirectToFile, (SBFile), file) 118 RedirectToFile(file.GetFile()); 119} 120 121void SBStream::RedirectToFile(FileSP file_sp) { 122 LLDB_RECORD_METHOD(void, SBStream, RedirectToFile, (FileSP), file_sp); 123 124 if (!file_sp || !file_sp->IsValid()) 125 return; 126 127 std::string local_data; 128 if (m_opaque_up) { 129 // See if we have any locally backed data. If so, copy it so we can then 130 // redirect it to the file so we don't lose the data 131 if (!m_is_file) 132 local_data = static_cast<StreamString *>(m_opaque_up.get())->GetString(); 133 } 134 135 m_opaque_up = std::make_unique<StreamFile>(file_sp); 136 m_is_file = true; 137 138 // If we had any data locally in our StreamString, then pass that along to 139 // the to new file we are redirecting to. 140 if (!local_data.empty()) 141 m_opaque_up->Write(&local_data[0], local_data.size()); 142} 143 144void SBStream::RedirectToFileDescriptor(int fd, bool transfer_fh_ownership) { 145 LLDB_RECORD_METHOD(void, SBStream, RedirectToFileDescriptor, (int, bool), fd, 146 transfer_fh_ownership); 147 148 std::string local_data; 149 if (m_opaque_up) { 150 // See if we have any locally backed data. If so, copy it so we can then 151 // redirect it to the file so we don't lose the data 152 if (!m_is_file) 153 local_data = static_cast<StreamString *>(m_opaque_up.get())->GetString(); 154 } 155 156 m_opaque_up = std::make_unique<StreamFile>(fd, transfer_fh_ownership); 157 m_is_file = true; 158 159 // If we had any data locally in our StreamString, then pass that along to 160 // the to new file we are redirecting to. 161 if (!local_data.empty()) 162 m_opaque_up->Write(&local_data[0], local_data.size()); 163} 164 165lldb_private::Stream *SBStream::operator->() { return m_opaque_up.get(); } 166 167lldb_private::Stream *SBStream::get() { return m_opaque_up.get(); } 168 169lldb_private::Stream &SBStream::ref() { 170 if (m_opaque_up == nullptr) 171 m_opaque_up.reset(new StreamString()); 172 return *m_opaque_up; 173} 174 175void SBStream::Clear() { 176 LLDB_RECORD_METHOD_NO_ARGS(void, SBStream, Clear); 177 178 if (m_opaque_up) { 179 // See if we have any locally backed data. If so, copy it so we can then 180 // redirect it to the file so we don't lose the data 181 if (m_is_file) 182 m_opaque_up.reset(); 183 else 184 static_cast<StreamString *>(m_opaque_up.get())->Clear(); 185 } 186} 187 188namespace lldb_private { 189namespace repro { 190 191template <> 192void RegisterMethods<SBStream>(Registry &R) { 193 LLDB_REGISTER_CONSTRUCTOR(SBStream, ()); 194 LLDB_REGISTER_METHOD_CONST(bool, SBStream, IsValid, ()); 195 LLDB_REGISTER_METHOD_CONST(bool, SBStream, operator bool, ()); 196 LLDB_REGISTER_METHOD(const char *, SBStream, GetData, ()); 197 LLDB_REGISTER_METHOD(size_t, SBStream, GetSize, ()); 198 LLDB_REGISTER_METHOD(void, SBStream, RedirectToFile, (const char *, bool)); 199 LLDB_REGISTER_METHOD(void, SBStream, RedirectToFile, (FileSP)); 200 LLDB_REGISTER_METHOD(void, SBStream, RedirectToFile, (SBFile)); 201 LLDB_REGISTER_METHOD(void, SBStream, RedirectToFileHandle, (FILE *, bool)); 202 LLDB_REGISTER_METHOD(void, SBStream, RedirectToFileDescriptor, (int, bool)); 203 LLDB_REGISTER_METHOD(void, SBStream, Clear, ()); 204} 205 206} 207} 208