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