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 "SBReproducerPrivate.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     : m_opaque_up() {
60   LLDB_RECORD_CONSTRUCTOR(SBCommandReturnObject,
61                           (const lldb::SBCommandReturnObject &), rhs);
62 
63   m_opaque_up = clone(rhs.m_opaque_up);
64 }
65 
66 SBCommandReturnObject &SBCommandReturnObject::
67 operator=(const SBCommandReturnObject &rhs) {
68   LLDB_RECORD_METHOD(
69       lldb::SBCommandReturnObject &,
70       SBCommandReturnObject, operator=,(const lldb::SBCommandReturnObject &),
71       rhs);
72 
73   if (this != &rhs)
74     m_opaque_up = clone(rhs.m_opaque_up);
75   return LLDB_RECORD_RESULT(*this);
76 }
77 
78 SBCommandReturnObject::~SBCommandReturnObject() = default;
79 
80 bool SBCommandReturnObject::IsValid() const {
81   LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBCommandReturnObject, IsValid);
82   return this->operator bool();
83 }
84 SBCommandReturnObject::operator bool() const {
85   LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBCommandReturnObject, operator bool);
86 
87   // This method is not useful but it needs to stay to keep SB API stable.
88   return true;
89 }
90 
91 const char *SBCommandReturnObject::GetOutput() {
92   LLDB_RECORD_METHOD_NO_ARGS(const char *, SBCommandReturnObject, GetOutput);
93 
94   ConstString output(ref().GetOutputData());
95   return output.AsCString(/*value_if_empty*/ "");
96 }
97 
98 const char *SBCommandReturnObject::GetError() {
99   LLDB_RECORD_METHOD_NO_ARGS(const char *, SBCommandReturnObject, GetError);
100 
101   ConstString output(ref().GetErrorData());
102   return output.AsCString(/*value_if_empty*/ "");
103 }
104 
105 size_t SBCommandReturnObject::GetOutputSize() {
106   LLDB_RECORD_METHOD_NO_ARGS(size_t, SBCommandReturnObject, GetOutputSize);
107 
108   return ref().GetOutputData().size();
109 }
110 
111 size_t SBCommandReturnObject::GetErrorSize() {
112   LLDB_RECORD_METHOD_NO_ARGS(size_t, SBCommandReturnObject, GetErrorSize);
113 
114   return ref().GetErrorData().size();
115 }
116 
117 size_t SBCommandReturnObject::PutOutput(FILE *fh) {
118   LLDB_RECORD_DUMMY(size_t, SBCommandReturnObject, PutOutput, (FILE *), fh);
119   if (fh) {
120     size_t num_bytes = GetOutputSize();
121     if (num_bytes)
122       return ::fprintf(fh, "%s", GetOutput());
123   }
124   return 0;
125 }
126 
127 size_t SBCommandReturnObject::PutOutput(FileSP file_sp) {
128   LLDB_RECORD_METHOD(size_t, SBCommandReturnObject, PutOutput, (FileSP),
129                      file_sp);
130   if (!file_sp)
131     return 0;
132   return file_sp->Printf("%s", GetOutput());
133 }
134 
135 size_t SBCommandReturnObject::PutOutput(SBFile file) {
136   LLDB_RECORD_METHOD(size_t, SBCommandReturnObject, PutOutput, (SBFile), file);
137   if (!file.m_opaque_sp)
138     return 0;
139   return file.m_opaque_sp->Printf("%s", GetOutput());
140 }
141 
142 size_t SBCommandReturnObject::PutError(FILE *fh) {
143   LLDB_RECORD_DUMMY(size_t, SBCommandReturnObject, PutError, (FILE *), fh);
144   if (fh) {
145     size_t num_bytes = GetErrorSize();
146     if (num_bytes)
147       return ::fprintf(fh, "%s", GetError());
148   }
149   return 0;
150 }
151 
152 size_t SBCommandReturnObject::PutError(FileSP file_sp) {
153   LLDB_RECORD_METHOD(size_t, SBCommandReturnObject, PutError, (FileSP),
154                      file_sp);
155   if (!file_sp)
156     return 0;
157   return file_sp->Printf("%s", GetError());
158 }
159 
160 size_t SBCommandReturnObject::PutError(SBFile file) {
161   LLDB_RECORD_METHOD(size_t, SBCommandReturnObject, PutError, (SBFile), file);
162   if (!file.m_opaque_sp)
163     return 0;
164   return file.m_opaque_sp->Printf("%s", GetError());
165 }
166 
167 void SBCommandReturnObject::Clear() {
168   LLDB_RECORD_METHOD_NO_ARGS(void, SBCommandReturnObject, Clear);
169 
170   ref().Clear();
171 }
172 
173 lldb::ReturnStatus SBCommandReturnObject::GetStatus() {
174   LLDB_RECORD_METHOD_NO_ARGS(lldb::ReturnStatus, SBCommandReturnObject,
175                              GetStatus);
176 
177   return ref().GetStatus();
178 }
179 
180 void SBCommandReturnObject::SetStatus(lldb::ReturnStatus status) {
181   LLDB_RECORD_METHOD(void, SBCommandReturnObject, SetStatus,
182                      (lldb::ReturnStatus), status);
183 
184   ref().SetStatus(status);
185 }
186 
187 bool SBCommandReturnObject::Succeeded() {
188   LLDB_RECORD_METHOD_NO_ARGS(bool, SBCommandReturnObject, Succeeded);
189 
190   return ref().Succeeded();
191 }
192 
193 bool SBCommandReturnObject::HasResult() {
194   LLDB_RECORD_METHOD_NO_ARGS(bool, SBCommandReturnObject, HasResult);
195 
196   return ref().HasResult();
197 }
198 
199 void SBCommandReturnObject::AppendMessage(const char *message) {
200   LLDB_RECORD_METHOD(void, SBCommandReturnObject, AppendMessage, (const char *),
201                      message);
202 
203   ref().AppendMessage(message);
204 }
205 
206 void SBCommandReturnObject::AppendWarning(const char *message) {
207   LLDB_RECORD_METHOD(void, SBCommandReturnObject, AppendWarning, (const char *),
208                      message);
209 
210   ref().AppendWarning(message);
211 }
212 
213 CommandReturnObject *SBCommandReturnObject::operator->() const {
214   return &**m_opaque_up;
215 }
216 
217 CommandReturnObject *SBCommandReturnObject::get() const {
218   return &**m_opaque_up;
219 }
220 
221 CommandReturnObject &SBCommandReturnObject::operator*() const {
222   return **m_opaque_up;
223 }
224 
225 CommandReturnObject &SBCommandReturnObject::ref() const {
226   return **m_opaque_up;
227 }
228 
229 bool SBCommandReturnObject::GetDescription(SBStream &description) {
230   LLDB_RECORD_METHOD(bool, SBCommandReturnObject, GetDescription,
231                      (lldb::SBStream &), description);
232 
233   Stream &strm = description.ref();
234 
235   description.Printf("Error:  ");
236   lldb::ReturnStatus status = ref().GetStatus();
237   if (status == lldb::eReturnStatusStarted)
238     strm.PutCString("Started");
239   else if (status == lldb::eReturnStatusInvalid)
240     strm.PutCString("Invalid");
241   else if (ref().Succeeded())
242     strm.PutCString("Success");
243   else
244     strm.PutCString("Fail");
245 
246   if (GetOutputSize() > 0)
247     strm.Printf("\nOutput Message:\n%s", GetOutput());
248 
249   if (GetErrorSize() > 0)
250     strm.Printf("\nError Message:\n%s", GetError());
251 
252   return true;
253 }
254 
255 void SBCommandReturnObject::SetImmediateOutputFile(FILE *fh) {
256   LLDB_RECORD_DUMMY(void, SBCommandReturnObject, SetImmediateOutputFile,
257                     (FILE *), fh);
258 
259   SetImmediateOutputFile(fh, false);
260 }
261 
262 void SBCommandReturnObject::SetImmediateErrorFile(FILE *fh) {
263   LLDB_RECORD_DUMMY(void, SBCommandReturnObject, SetImmediateErrorFile,
264                     (FILE *), fh);
265 
266   SetImmediateErrorFile(fh, false);
267 }
268 
269 void SBCommandReturnObject::SetImmediateOutputFile(FILE *fh,
270                                                    bool transfer_ownership) {
271   LLDB_RECORD_DUMMY(void, SBCommandReturnObject, SetImmediateOutputFile,
272                     (FILE *, bool), fh, transfer_ownership);
273   FileSP file = std::make_shared<NativeFile>(fh, transfer_ownership);
274   ref().SetImmediateOutputFile(file);
275 }
276 
277 void SBCommandReturnObject::SetImmediateErrorFile(FILE *fh,
278                                                   bool transfer_ownership) {
279   LLDB_RECORD_DUMMY(void, SBCommandReturnObject, SetImmediateErrorFile,
280                     (FILE *, bool), fh, transfer_ownership);
281   FileSP file = std::make_shared<NativeFile>(fh, transfer_ownership);
282   ref().SetImmediateErrorFile(file);
283 }
284 
285 void SBCommandReturnObject::SetImmediateOutputFile(SBFile file) {
286   LLDB_RECORD_METHOD(void, SBCommandReturnObject, SetImmediateOutputFile,
287                      (SBFile), file);
288   ref().SetImmediateOutputFile(file.m_opaque_sp);
289 }
290 
291 void SBCommandReturnObject::SetImmediateErrorFile(SBFile file) {
292   LLDB_RECORD_METHOD(void, SBCommandReturnObject, SetImmediateErrorFile,
293                      (SBFile), file);
294   ref().SetImmediateErrorFile(file.m_opaque_sp);
295 }
296 
297 void SBCommandReturnObject::SetImmediateOutputFile(FileSP file_sp) {
298   LLDB_RECORD_METHOD(void, SBCommandReturnObject, SetImmediateOutputFile,
299                      (FileSP), file_sp);
300   SetImmediateOutputFile(SBFile(file_sp));
301 }
302 
303 void SBCommandReturnObject::SetImmediateErrorFile(FileSP file_sp) {
304   LLDB_RECORD_METHOD(void, SBCommandReturnObject, SetImmediateErrorFile,
305                      (FileSP), file_sp);
306   SetImmediateErrorFile(SBFile(file_sp));
307 }
308 
309 void SBCommandReturnObject::PutCString(const char *string, int len) {
310   LLDB_RECORD_METHOD(void, SBCommandReturnObject, PutCString,
311                      (const char *, int), string, len);
312 
313   if (len == 0 || string == nullptr || *string == 0) {
314     return;
315   } else if (len > 0) {
316     std::string buffer(string, len);
317     ref().AppendMessage(buffer.c_str());
318   } else
319     ref().AppendMessage(string);
320 }
321 
322 const char *SBCommandReturnObject::GetOutput(bool only_if_no_immediate) {
323   LLDB_RECORD_METHOD(const char *, SBCommandReturnObject, GetOutput, (bool),
324                      only_if_no_immediate);
325 
326   if (!only_if_no_immediate ||
327       ref().GetImmediateOutputStream().get() == nullptr)
328     return GetOutput();
329   return nullptr;
330 }
331 
332 const char *SBCommandReturnObject::GetError(bool only_if_no_immediate) {
333   LLDB_RECORD_METHOD(const char *, SBCommandReturnObject, GetError, (bool),
334                      only_if_no_immediate);
335 
336   if (!only_if_no_immediate || ref().GetImmediateErrorStream().get() == nullptr)
337     return GetError();
338   return nullptr;
339 }
340 
341 size_t SBCommandReturnObject::Printf(const char *format, ...) {
342   va_list args;
343   va_start(args, format);
344   size_t result = ref().GetOutputStream().PrintfVarArg(format, args);
345   va_end(args);
346   return result;
347 }
348 
349 void SBCommandReturnObject::SetError(lldb::SBError &error,
350                                      const char *fallback_error_cstr) {
351   LLDB_RECORD_METHOD(void, SBCommandReturnObject, SetError,
352                      (lldb::SBError &, const char *), error,
353                      fallback_error_cstr);
354 
355   if (error.IsValid())
356     ref().SetError(error.ref(), fallback_error_cstr);
357   else if (fallback_error_cstr)
358     ref().SetError(Status(), fallback_error_cstr);
359 }
360 
361 void SBCommandReturnObject::SetError(const char *error_cstr) {
362   LLDB_RECORD_METHOD(void, SBCommandReturnObject, SetError, (const char *),
363                      error_cstr);
364 
365   if (error_cstr)
366     ref().AppendError(error_cstr);
367 }
368 
369 namespace lldb_private {
370 namespace repro {
371 
372 template <>
373 void RegisterMethods<SBCommandReturnObject>(Registry &R) {
374   LLDB_REGISTER_CONSTRUCTOR(SBCommandReturnObject, ());
375   LLDB_REGISTER_CONSTRUCTOR(SBCommandReturnObject,
376                             (lldb_private::CommandReturnObject &));
377   LLDB_REGISTER_CONSTRUCTOR(SBCommandReturnObject,
378                             (const lldb::SBCommandReturnObject &));
379   LLDB_REGISTER_METHOD(
380       lldb::SBCommandReturnObject &,
381       SBCommandReturnObject, operator=,(const lldb::SBCommandReturnObject &));
382   LLDB_REGISTER_METHOD_CONST(bool, SBCommandReturnObject, IsValid, ());
383   LLDB_REGISTER_METHOD_CONST(bool, SBCommandReturnObject, operator bool, ());
384   LLDB_REGISTER_METHOD(const char *, SBCommandReturnObject, GetOutput, ());
385   LLDB_REGISTER_METHOD(const char *, SBCommandReturnObject, GetError, ());
386   LLDB_REGISTER_METHOD(size_t, SBCommandReturnObject, GetOutputSize, ());
387   LLDB_REGISTER_METHOD(size_t, SBCommandReturnObject, GetErrorSize, ());
388   LLDB_REGISTER_METHOD(size_t, SBCommandReturnObject, PutOutput, (FILE *));
389   LLDB_REGISTER_METHOD(size_t, SBCommandReturnObject, PutError, (FILE *));
390   LLDB_REGISTER_METHOD(size_t, SBCommandReturnObject, PutOutput, (SBFile));
391   LLDB_REGISTER_METHOD(size_t, SBCommandReturnObject, PutError, (SBFile));
392   LLDB_REGISTER_METHOD(size_t, SBCommandReturnObject, PutOutput, (FileSP));
393   LLDB_REGISTER_METHOD(size_t, SBCommandReturnObject, PutError, (FileSP));
394   LLDB_REGISTER_METHOD(void, SBCommandReturnObject, Clear, ());
395   LLDB_REGISTER_METHOD(lldb::ReturnStatus, SBCommandReturnObject, GetStatus,
396                        ());
397   LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetStatus,
398                        (lldb::ReturnStatus));
399   LLDB_REGISTER_METHOD(bool, SBCommandReturnObject, Succeeded, ());
400   LLDB_REGISTER_METHOD(bool, SBCommandReturnObject, HasResult, ());
401   LLDB_REGISTER_METHOD(void, SBCommandReturnObject, AppendMessage,
402                        (const char *));
403   LLDB_REGISTER_METHOD(void, SBCommandReturnObject, AppendWarning,
404                        (const char *));
405   LLDB_REGISTER_METHOD(bool, SBCommandReturnObject, GetDescription,
406                        (lldb::SBStream &));
407   LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetImmediateOutputFile,
408                        (FILE *));
409   LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetImmediateErrorFile,
410                        (FILE *));
411   LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetImmediateOutputFile,
412                        (SBFile));
413   LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetImmediateErrorFile,
414                        (SBFile));
415   LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetImmediateOutputFile,
416                        (FileSP));
417   LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetImmediateErrorFile,
418                        (FileSP));
419   LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetImmediateOutputFile,
420                        (FILE *, bool));
421   LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetImmediateErrorFile,
422                        (FILE *, bool));
423   LLDB_REGISTER_METHOD(void, SBCommandReturnObject, PutCString,
424                        (const char *, int));
425   LLDB_REGISTER_METHOD(const char *, SBCommandReturnObject, GetOutput,
426                        (bool));
427   LLDB_REGISTER_METHOD(const char *, SBCommandReturnObject, GetError, (bool));
428   LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetError,
429                        (lldb::SBError &, const char *));
430   LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetError, (const char *));
431 }
432 
433 }
434 }
435