15ffd83dbSDimitry Andric //===-- SBStream.cpp ------------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "lldb/API/SBStream.h"
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "SBReproducerPrivate.h"
129dba64beSDimitry Andric #include "lldb/API/SBFile.h"
130b57cec5SDimitry Andric #include "lldb/Core/StreamFile.h"
140b57cec5SDimitry Andric #include "lldb/Host/FileSystem.h"
150b57cec5SDimitry Andric #include "lldb/Utility/Status.h"
160b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
170b57cec5SDimitry Andric #include "lldb/Utility/StreamString.h"
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric using namespace lldb;
200b57cec5SDimitry Andric using namespace lldb_private;
210b57cec5SDimitry Andric 
SBStream()22*5f7ddb14SDimitry Andric SBStream::SBStream() : m_opaque_up(new StreamString()) {
230b57cec5SDimitry Andric   LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBStream);
240b57cec5SDimitry Andric }
250b57cec5SDimitry Andric 
SBStream(SBStream && rhs)260b57cec5SDimitry Andric SBStream::SBStream(SBStream &&rhs)
270b57cec5SDimitry Andric     : m_opaque_up(std::move(rhs.m_opaque_up)), m_is_file(rhs.m_is_file) {}
280b57cec5SDimitry Andric 
295ffd83dbSDimitry Andric SBStream::~SBStream() = default;
300b57cec5SDimitry Andric 
IsValid() const310b57cec5SDimitry Andric bool SBStream::IsValid() const {
320b57cec5SDimitry Andric   LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBStream, IsValid);
330b57cec5SDimitry Andric   return this->operator bool();
340b57cec5SDimitry Andric }
operator bool() const350b57cec5SDimitry Andric SBStream::operator bool() const {
360b57cec5SDimitry Andric   LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBStream, operator bool);
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric   return (m_opaque_up != nullptr);
390b57cec5SDimitry Andric }
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric // If this stream is not redirected to a file, it will maintain a local cache
420b57cec5SDimitry Andric // for the stream data which can be accessed using this accessor.
GetData()430b57cec5SDimitry Andric const char *SBStream::GetData() {
440b57cec5SDimitry Andric   LLDB_RECORD_METHOD_NO_ARGS(const char *, SBStream, GetData);
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric   if (m_is_file || m_opaque_up == nullptr)
470b57cec5SDimitry Andric     return nullptr;
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric   return static_cast<StreamString *>(m_opaque_up.get())->GetData();
500b57cec5SDimitry Andric }
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric // If this stream is not redirected to a file, it will maintain a local cache
530b57cec5SDimitry Andric // for the stream output whose length can be accessed using this accessor.
GetSize()540b57cec5SDimitry Andric size_t SBStream::GetSize() {
550b57cec5SDimitry Andric   LLDB_RECORD_METHOD_NO_ARGS(size_t, SBStream, GetSize);
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric   if (m_is_file || m_opaque_up == nullptr)
580b57cec5SDimitry Andric     return 0;
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric   return static_cast<StreamString *>(m_opaque_up.get())->GetSize();
610b57cec5SDimitry Andric }
620b57cec5SDimitry Andric 
Print(const char * str)635ffd83dbSDimitry Andric void SBStream::Print(const char *str) {
645ffd83dbSDimitry Andric   LLDB_RECORD_METHOD(void, SBStream, Print, (const char *), str);
655ffd83dbSDimitry Andric 
665ffd83dbSDimitry Andric   Printf("%s", str);
675ffd83dbSDimitry Andric }
685ffd83dbSDimitry Andric 
Printf(const char * format,...)690b57cec5SDimitry Andric void SBStream::Printf(const char *format, ...) {
700b57cec5SDimitry Andric   if (!format)
710b57cec5SDimitry Andric     return;
720b57cec5SDimitry Andric   va_list args;
730b57cec5SDimitry Andric   va_start(args, format);
740b57cec5SDimitry Andric   ref().PrintfVarArg(format, args);
750b57cec5SDimitry Andric   va_end(args);
760b57cec5SDimitry Andric }
770b57cec5SDimitry Andric 
RedirectToFile(const char * path,bool append)780b57cec5SDimitry Andric void SBStream::RedirectToFile(const char *path, bool append) {
790b57cec5SDimitry Andric   LLDB_RECORD_METHOD(void, SBStream, RedirectToFile, (const char *, bool), path,
800b57cec5SDimitry Andric                      append);
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric   if (path == nullptr)
830b57cec5SDimitry Andric     return;
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric   std::string local_data;
860b57cec5SDimitry Andric   if (m_opaque_up) {
870b57cec5SDimitry Andric     // See if we have any locally backed data. If so, copy it so we can then
880b57cec5SDimitry Andric     // redirect it to the file so we don't lose the data
890b57cec5SDimitry Andric     if (!m_is_file)
905ffd83dbSDimitry Andric       local_data = std::string(
915ffd83dbSDimitry Andric           static_cast<StreamString *>(m_opaque_up.get())->GetString());
920b57cec5SDimitry Andric   }
939dba64beSDimitry Andric   auto open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate;
940b57cec5SDimitry Andric   if (append)
950b57cec5SDimitry Andric     open_options |= File::eOpenOptionAppend;
960b57cec5SDimitry Andric   else
970b57cec5SDimitry Andric     open_options |= File::eOpenOptionTruncate;
980b57cec5SDimitry Andric 
999dba64beSDimitry Andric   llvm::Expected<FileUP> file =
1009dba64beSDimitry Andric       FileSystem::Instance().Open(FileSpec(path), open_options);
1019dba64beSDimitry Andric   if (!file) {
1029dba64beSDimitry Andric     LLDB_LOG_ERROR(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), file.takeError(),
1039dba64beSDimitry Andric                    "Cannot open {1}: {0}", path);
1049dba64beSDimitry Andric     return;
1059dba64beSDimitry Andric   }
1060b57cec5SDimitry Andric 
1079dba64beSDimitry Andric   m_opaque_up = std::make_unique<StreamFile>(std::move(file.get()));
1080b57cec5SDimitry Andric   m_is_file = true;
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric   // If we had any data locally in our StreamString, then pass that along to
1110b57cec5SDimitry Andric   // the to new file we are redirecting to.
1120b57cec5SDimitry Andric   if (!local_data.empty())
1130b57cec5SDimitry Andric     m_opaque_up->Write(&local_data[0], local_data.size());
1140b57cec5SDimitry Andric }
1150b57cec5SDimitry Andric 
RedirectToFileHandle(FILE * fh,bool transfer_fh_ownership)1160b57cec5SDimitry Andric void SBStream::RedirectToFileHandle(FILE *fh, bool transfer_fh_ownership) {
1170b57cec5SDimitry Andric   LLDB_RECORD_METHOD(void, SBStream, RedirectToFileHandle, (FILE *, bool), fh,
1180b57cec5SDimitry Andric                      transfer_fh_ownership);
1199dba64beSDimitry Andric   FileSP file = std::make_unique<NativeFile>(fh, transfer_fh_ownership);
1209dba64beSDimitry Andric   return RedirectToFile(file);
1219dba64beSDimitry Andric }
1220b57cec5SDimitry Andric 
RedirectToFile(SBFile file)1239dba64beSDimitry Andric void SBStream::RedirectToFile(SBFile file) {
1249dba64beSDimitry Andric   LLDB_RECORD_METHOD(void, SBStream, RedirectToFile, (SBFile), file)
1259dba64beSDimitry Andric   RedirectToFile(file.GetFile());
1269dba64beSDimitry Andric }
1279dba64beSDimitry Andric 
RedirectToFile(FileSP file_sp)1289dba64beSDimitry Andric void SBStream::RedirectToFile(FileSP file_sp) {
1299dba64beSDimitry Andric   LLDB_RECORD_METHOD(void, SBStream, RedirectToFile, (FileSP), file_sp);
1309dba64beSDimitry Andric 
1319dba64beSDimitry Andric   if (!file_sp || !file_sp->IsValid())
1320b57cec5SDimitry Andric     return;
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric   std::string local_data;
1350b57cec5SDimitry Andric   if (m_opaque_up) {
1360b57cec5SDimitry Andric     // See if we have any locally backed data. If so, copy it so we can then
1370b57cec5SDimitry Andric     // redirect it to the file so we don't lose the data
1380b57cec5SDimitry Andric     if (!m_is_file)
1395ffd83dbSDimitry Andric       local_data = std::string(
1405ffd83dbSDimitry Andric           static_cast<StreamString *>(m_opaque_up.get())->GetString());
1410b57cec5SDimitry Andric   }
1420b57cec5SDimitry Andric 
1439dba64beSDimitry Andric   m_opaque_up = std::make_unique<StreamFile>(file_sp);
1440b57cec5SDimitry Andric   m_is_file = true;
1450b57cec5SDimitry Andric 
1460b57cec5SDimitry Andric   // If we had any data locally in our StreamString, then pass that along to
1470b57cec5SDimitry Andric   // the to new file we are redirecting to.
1480b57cec5SDimitry Andric   if (!local_data.empty())
1490b57cec5SDimitry Andric     m_opaque_up->Write(&local_data[0], local_data.size());
1500b57cec5SDimitry Andric }
1510b57cec5SDimitry Andric 
RedirectToFileDescriptor(int fd,bool transfer_fh_ownership)1520b57cec5SDimitry Andric void SBStream::RedirectToFileDescriptor(int fd, bool transfer_fh_ownership) {
1530b57cec5SDimitry Andric   LLDB_RECORD_METHOD(void, SBStream, RedirectToFileDescriptor, (int, bool), fd,
1540b57cec5SDimitry Andric                      transfer_fh_ownership);
1550b57cec5SDimitry Andric 
1560b57cec5SDimitry Andric   std::string local_data;
1570b57cec5SDimitry Andric   if (m_opaque_up) {
1580b57cec5SDimitry Andric     // See if we have any locally backed data. If so, copy it so we can then
1590b57cec5SDimitry Andric     // redirect it to the file so we don't lose the data
1600b57cec5SDimitry Andric     if (!m_is_file)
1615ffd83dbSDimitry Andric       local_data = std::string(
1625ffd83dbSDimitry Andric           static_cast<StreamString *>(m_opaque_up.get())->GetString());
1630b57cec5SDimitry Andric   }
1640b57cec5SDimitry Andric 
1659dba64beSDimitry Andric   m_opaque_up = std::make_unique<StreamFile>(fd, transfer_fh_ownership);
1660b57cec5SDimitry Andric   m_is_file = true;
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric   // If we had any data locally in our StreamString, then pass that along to
1690b57cec5SDimitry Andric   // the to new file we are redirecting to.
1700b57cec5SDimitry Andric   if (!local_data.empty())
1710b57cec5SDimitry Andric     m_opaque_up->Write(&local_data[0], local_data.size());
1720b57cec5SDimitry Andric }
1730b57cec5SDimitry Andric 
operator ->()1740b57cec5SDimitry Andric lldb_private::Stream *SBStream::operator->() { return m_opaque_up.get(); }
1750b57cec5SDimitry Andric 
get()1760b57cec5SDimitry Andric lldb_private::Stream *SBStream::get() { return m_opaque_up.get(); }
1770b57cec5SDimitry Andric 
ref()1780b57cec5SDimitry Andric lldb_private::Stream &SBStream::ref() {
1790b57cec5SDimitry Andric   if (m_opaque_up == nullptr)
1805ffd83dbSDimitry Andric     m_opaque_up = std::make_unique<StreamString>();
1810b57cec5SDimitry Andric   return *m_opaque_up;
1820b57cec5SDimitry Andric }
1830b57cec5SDimitry Andric 
Clear()1840b57cec5SDimitry Andric void SBStream::Clear() {
1850b57cec5SDimitry Andric   LLDB_RECORD_METHOD_NO_ARGS(void, SBStream, Clear);
1860b57cec5SDimitry Andric 
1870b57cec5SDimitry Andric   if (m_opaque_up) {
1880b57cec5SDimitry Andric     // See if we have any locally backed data. If so, copy it so we can then
1890b57cec5SDimitry Andric     // redirect it to the file so we don't lose the data
1900b57cec5SDimitry Andric     if (m_is_file)
1910b57cec5SDimitry Andric       m_opaque_up.reset();
1920b57cec5SDimitry Andric     else
1930b57cec5SDimitry Andric       static_cast<StreamString *>(m_opaque_up.get())->Clear();
1940b57cec5SDimitry Andric   }
1950b57cec5SDimitry Andric }
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric namespace lldb_private {
1980b57cec5SDimitry Andric namespace repro {
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric template <>
RegisterMethods(Registry & R)2010b57cec5SDimitry Andric void RegisterMethods<SBStream>(Registry &R) {
2020b57cec5SDimitry Andric   LLDB_REGISTER_CONSTRUCTOR(SBStream, ());
2030b57cec5SDimitry Andric   LLDB_REGISTER_METHOD_CONST(bool, SBStream, IsValid, ());
2040b57cec5SDimitry Andric   LLDB_REGISTER_METHOD_CONST(bool, SBStream, operator bool, ());
2050b57cec5SDimitry Andric   LLDB_REGISTER_METHOD(const char *, SBStream, GetData, ());
2060b57cec5SDimitry Andric   LLDB_REGISTER_METHOD(size_t, SBStream, GetSize, ());
2070b57cec5SDimitry Andric   LLDB_REGISTER_METHOD(void, SBStream, RedirectToFile, (const char *, bool));
2089dba64beSDimitry Andric   LLDB_REGISTER_METHOD(void, SBStream, RedirectToFile, (FileSP));
2099dba64beSDimitry Andric   LLDB_REGISTER_METHOD(void, SBStream, RedirectToFile, (SBFile));
2100b57cec5SDimitry Andric   LLDB_REGISTER_METHOD(void, SBStream, RedirectToFileHandle, (FILE *, bool));
2110b57cec5SDimitry Andric   LLDB_REGISTER_METHOD(void, SBStream, RedirectToFileDescriptor, (int, bool));
2120b57cec5SDimitry Andric   LLDB_REGISTER_METHOD(void, SBStream, Clear, ());
2135ffd83dbSDimitry Andric   LLDB_REGISTER_METHOD(void, SBStream, Print, (const char *));
2140b57cec5SDimitry Andric }
2150b57cec5SDimitry Andric 
2160b57cec5SDimitry Andric }
2170b57cec5SDimitry Andric }
218