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