1 //===-- SBCommandReturnObject.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/SBCommandReturnObject.h" 10 #include "Utils.h" 11 #include "lldb/API/SBError.h" 12 #include "lldb/API/SBFile.h" 13 #include "lldb/API/SBStream.h" 14 #include "lldb/API/SBStructuredData.h" 15 #include "lldb/Core/StructuredDataImpl.h" 16 #include "lldb/Interpreter/CommandReturnObject.h" 17 #include "lldb/Utility/ConstString.h" 18 #include "lldb/Utility/Instrumentation.h" 19 #include "lldb/Utility/Status.h" 20 21 using namespace lldb; 22 using namespace lldb_private; 23 24 class lldb_private::SBCommandReturnObjectImpl { 25 public: 26 SBCommandReturnObjectImpl() : m_ptr(new CommandReturnObject(false)) {} 27 SBCommandReturnObjectImpl(CommandReturnObject &ref) 28 : m_ptr(&ref), m_owned(false) {} 29 SBCommandReturnObjectImpl(const SBCommandReturnObjectImpl &rhs) 30 : m_ptr(new CommandReturnObject(*rhs.m_ptr)), m_owned(rhs.m_owned) {} 31 SBCommandReturnObjectImpl &operator=(const SBCommandReturnObjectImpl &rhs) { 32 SBCommandReturnObjectImpl copy(rhs); 33 std::swap(*this, copy); 34 return *this; 35 } 36 // rvalue ctor+assignment are not used by SBCommandReturnObject. 37 ~SBCommandReturnObjectImpl() { 38 if (m_owned) 39 delete m_ptr; 40 } 41 42 CommandReturnObject &operator*() const { return *m_ptr; } 43 44 private: 45 CommandReturnObject *m_ptr; 46 bool m_owned = true; 47 }; 48 49 SBCommandReturnObject::SBCommandReturnObject() 50 : m_opaque_up(new SBCommandReturnObjectImpl()) { 51 LLDB_INSTRUMENT_VA(this); 52 } 53 54 SBCommandReturnObject::SBCommandReturnObject(CommandReturnObject &ref) 55 : m_opaque_up(new SBCommandReturnObjectImpl(ref)) { 56 LLDB_INSTRUMENT_VA(this, ref); 57 } 58 59 SBCommandReturnObject::SBCommandReturnObject(const SBCommandReturnObject &rhs) { 60 LLDB_INSTRUMENT_VA(this, rhs); 61 62 m_opaque_up = clone(rhs.m_opaque_up); 63 } 64 65 SBCommandReturnObject &SBCommandReturnObject:: 66 operator=(const SBCommandReturnObject &rhs) { 67 LLDB_INSTRUMENT_VA(this, rhs); 68 69 if (this != &rhs) 70 m_opaque_up = clone(rhs.m_opaque_up); 71 return *this; 72 } 73 74 SBCommandReturnObject::~SBCommandReturnObject() = default; 75 76 bool SBCommandReturnObject::IsValid() const { 77 LLDB_INSTRUMENT_VA(this); 78 return this->operator bool(); 79 } 80 SBCommandReturnObject::operator bool() const { 81 LLDB_INSTRUMENT_VA(this); 82 83 // This method is not useful but it needs to stay to keep SB API stable. 84 return true; 85 } 86 87 const char *SBCommandReturnObject::GetOutput() { 88 LLDB_INSTRUMENT_VA(this); 89 90 ConstString output(ref().GetOutputString()); 91 return output.AsCString(/*value_if_empty*/ ""); 92 } 93 94 const char *SBCommandReturnObject::GetError() { 95 LLDB_INSTRUMENT_VA(this); 96 97 ConstString output(ref().GetErrorString()); 98 return output.AsCString(/*value_if_empty*/ ""); 99 } 100 101 SBStructuredData SBCommandReturnObject::GetErrorData() { 102 LLDB_INSTRUMENT_VA(this); 103 104 StructuredData::ObjectSP data(ref().GetErrorData()); 105 SBStructuredData sb_data; 106 sb_data.m_impl_up->SetObjectSP(data); 107 return sb_data; 108 } 109 110 size_t SBCommandReturnObject::GetOutputSize() { 111 LLDB_INSTRUMENT_VA(this); 112 113 return ref().GetOutputString().size(); 114 } 115 116 size_t SBCommandReturnObject::GetErrorSize() { 117 LLDB_INSTRUMENT_VA(this); 118 119 return ref().GetErrorString().size(); 120 } 121 122 size_t SBCommandReturnObject::PutOutput(FILE *fh) { 123 LLDB_INSTRUMENT_VA(this, fh); 124 if (fh) { 125 size_t num_bytes = GetOutputSize(); 126 if (num_bytes) 127 return ::fprintf(fh, "%s", GetOutput()); 128 } 129 return 0; 130 } 131 132 size_t SBCommandReturnObject::PutOutput(FileSP file_sp) { 133 LLDB_INSTRUMENT_VA(this, file_sp); 134 if (!file_sp) 135 return 0; 136 return file_sp->Printf("%s", GetOutput()); 137 } 138 139 size_t SBCommandReturnObject::PutOutput(SBFile file) { 140 LLDB_INSTRUMENT_VA(this, file); 141 if (!file.m_opaque_sp) 142 return 0; 143 return file.m_opaque_sp->Printf("%s", GetOutput()); 144 } 145 146 size_t SBCommandReturnObject::PutError(FILE *fh) { 147 LLDB_INSTRUMENT_VA(this, fh); 148 if (fh) { 149 size_t num_bytes = GetErrorSize(); 150 if (num_bytes) 151 return ::fprintf(fh, "%s", GetError()); 152 } 153 return 0; 154 } 155 156 size_t SBCommandReturnObject::PutError(FileSP file_sp) { 157 LLDB_INSTRUMENT_VA(this, file_sp); 158 if (!file_sp) 159 return 0; 160 return file_sp->Printf("%s", GetError()); 161 } 162 163 size_t SBCommandReturnObject::PutError(SBFile file) { 164 LLDB_INSTRUMENT_VA(this, file); 165 if (!file.m_opaque_sp) 166 return 0; 167 return file.m_opaque_sp->Printf("%s", GetError()); 168 } 169 170 void SBCommandReturnObject::Clear() { 171 LLDB_INSTRUMENT_VA(this); 172 173 ref().Clear(); 174 } 175 176 lldb::ReturnStatus SBCommandReturnObject::GetStatus() { 177 LLDB_INSTRUMENT_VA(this); 178 179 return ref().GetStatus(); 180 } 181 182 void SBCommandReturnObject::SetStatus(lldb::ReturnStatus status) { 183 LLDB_INSTRUMENT_VA(this, status); 184 185 ref().SetStatus(status); 186 } 187 188 bool SBCommandReturnObject::Succeeded() { 189 LLDB_INSTRUMENT_VA(this); 190 191 return ref().Succeeded(); 192 } 193 194 bool SBCommandReturnObject::HasResult() { 195 LLDB_INSTRUMENT_VA(this); 196 197 return ref().HasResult(); 198 } 199 200 void SBCommandReturnObject::AppendMessage(const char *message) { 201 LLDB_INSTRUMENT_VA(this, message); 202 203 ref().AppendMessage(message); 204 } 205 206 void SBCommandReturnObject::AppendWarning(const char *message) { 207 LLDB_INSTRUMENT_VA(this, message); 208 209 ref().AppendWarning(message); 210 } 211 212 CommandReturnObject *SBCommandReturnObject::operator->() const { 213 return &**m_opaque_up; 214 } 215 216 CommandReturnObject *SBCommandReturnObject::get() const { 217 return &**m_opaque_up; 218 } 219 220 CommandReturnObject &SBCommandReturnObject::operator*() const { 221 return **m_opaque_up; 222 } 223 224 CommandReturnObject &SBCommandReturnObject::ref() const { 225 return **m_opaque_up; 226 } 227 228 bool SBCommandReturnObject::GetDescription(SBStream &description) { 229 LLDB_INSTRUMENT_VA(this, description); 230 231 Stream &strm = description.ref(); 232 233 description.Printf("Error: "); 234 lldb::ReturnStatus status = ref().GetStatus(); 235 if (status == lldb::eReturnStatusStarted) 236 strm.PutCString("Started"); 237 else if (status == lldb::eReturnStatusInvalid) 238 strm.PutCString("Invalid"); 239 else if (ref().Succeeded()) 240 strm.PutCString("Success"); 241 else 242 strm.PutCString("Fail"); 243 244 if (GetOutputSize() > 0) 245 strm.Printf("\nOutput Message:\n%s", GetOutput()); 246 247 if (GetErrorSize() > 0) 248 strm.Printf("\nError Message:\n%s", GetError()); 249 250 return true; 251 } 252 253 void SBCommandReturnObject::SetImmediateOutputFile(FILE *fh) { 254 LLDB_INSTRUMENT_VA(this, fh); 255 256 SetImmediateOutputFile(fh, false); 257 } 258 259 void SBCommandReturnObject::SetImmediateErrorFile(FILE *fh) { 260 LLDB_INSTRUMENT_VA(this, fh); 261 262 SetImmediateErrorFile(fh, false); 263 } 264 265 void SBCommandReturnObject::SetImmediateOutputFile(FILE *fh, 266 bool transfer_ownership) { 267 LLDB_INSTRUMENT_VA(this, fh, transfer_ownership); 268 FileSP file = std::make_shared<NativeFile>(fh, transfer_ownership); 269 ref().SetImmediateOutputFile(file); 270 } 271 272 void SBCommandReturnObject::SetImmediateErrorFile(FILE *fh, 273 bool transfer_ownership) { 274 LLDB_INSTRUMENT_VA(this, fh, transfer_ownership); 275 FileSP file = std::make_shared<NativeFile>(fh, transfer_ownership); 276 ref().SetImmediateErrorFile(file); 277 } 278 279 void SBCommandReturnObject::SetImmediateOutputFile(SBFile file) { 280 LLDB_INSTRUMENT_VA(this, file); 281 ref().SetImmediateOutputFile(file.m_opaque_sp); 282 } 283 284 void SBCommandReturnObject::SetImmediateErrorFile(SBFile file) { 285 LLDB_INSTRUMENT_VA(this, file); 286 ref().SetImmediateErrorFile(file.m_opaque_sp); 287 } 288 289 void SBCommandReturnObject::SetImmediateOutputFile(FileSP file_sp) { 290 LLDB_INSTRUMENT_VA(this, file_sp); 291 SetImmediateOutputFile(SBFile(file_sp)); 292 } 293 294 void SBCommandReturnObject::SetImmediateErrorFile(FileSP file_sp) { 295 LLDB_INSTRUMENT_VA(this, file_sp); 296 SetImmediateErrorFile(SBFile(file_sp)); 297 } 298 299 void SBCommandReturnObject::PutCString(const char *string, int len) { 300 LLDB_INSTRUMENT_VA(this, string, len); 301 302 if (len == 0 || string == nullptr || *string == 0) { 303 return; 304 } else if (len > 0) { 305 std::string buffer(string, len); 306 ref().AppendMessage(buffer.c_str()); 307 } else 308 ref().AppendMessage(string); 309 } 310 311 const char *SBCommandReturnObject::GetOutput(bool only_if_no_immediate) { 312 LLDB_INSTRUMENT_VA(this, only_if_no_immediate); 313 314 if (!only_if_no_immediate || 315 ref().GetImmediateOutputStream().get() == nullptr) 316 return GetOutput(); 317 return nullptr; 318 } 319 320 const char *SBCommandReturnObject::GetError(bool only_if_no_immediate) { 321 LLDB_INSTRUMENT_VA(this, only_if_no_immediate); 322 323 if (!only_if_no_immediate || ref().GetImmediateErrorStream().get() == nullptr) 324 return GetError(); 325 return nullptr; 326 } 327 328 size_t SBCommandReturnObject::Printf(const char *format, ...) { 329 va_list args; 330 va_start(args, format); 331 size_t result = ref().GetOutputStream().PrintfVarArg(format, args); 332 va_end(args); 333 return result; 334 } 335 336 void SBCommandReturnObject::SetError(lldb::SBError &error, 337 const char *fallback_error_cstr) { 338 LLDB_INSTRUMENT_VA(this, error, fallback_error_cstr); 339 340 if (error.IsValid() && !error.Fail()) 341 ref().SetError(error.ref().Clone()); 342 else if (fallback_error_cstr) 343 ref().SetError(Status::FromErrorString(fallback_error_cstr)); 344 } 345 346 void SBCommandReturnObject::SetError(const char *error_cstr) { 347 LLDB_INSTRUMENT_VA(this, error_cstr); 348 349 if (error_cstr) 350 ref().AppendError(error_cstr); 351 } 352