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/SBStream.h"
14 #include "lldb/Interpreter/CommandReturnObject.h"
15 #include "lldb/Utility/ConstString.h"
16 #include "lldb/Utility/Status.h"
17 
18 using namespace lldb;
19 using namespace lldb_private;
20 
21 class lldb_private::SBCommandReturnObjectImpl {
22 public:
23   SBCommandReturnObjectImpl()
24       : m_ptr(new CommandReturnObject()), m_owned(true) {}
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;
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_METHOD(size_t, SBCommandReturnObject, PutOutput, (FILE *), fh);
119 
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::PutError(FILE *fh) {
129   LLDB_RECORD_METHOD(size_t, SBCommandReturnObject, PutError, (FILE *), fh);
130 
131   if (fh) {
132     size_t num_bytes = GetErrorSize();
133     if (num_bytes)
134       return ::fprintf(fh, "%s", GetError());
135   }
136   return 0;
137 }
138 
139 void SBCommandReturnObject::Clear() {
140   LLDB_RECORD_METHOD_NO_ARGS(void, SBCommandReturnObject, Clear);
141 
142   ref().Clear();
143 }
144 
145 lldb::ReturnStatus SBCommandReturnObject::GetStatus() {
146   LLDB_RECORD_METHOD_NO_ARGS(lldb::ReturnStatus, SBCommandReturnObject,
147                              GetStatus);
148 
149   return ref().GetStatus();
150 }
151 
152 void SBCommandReturnObject::SetStatus(lldb::ReturnStatus status) {
153   LLDB_RECORD_METHOD(void, SBCommandReturnObject, SetStatus,
154                      (lldb::ReturnStatus), status);
155 
156   ref().SetStatus(status);
157 }
158 
159 bool SBCommandReturnObject::Succeeded() {
160   LLDB_RECORD_METHOD_NO_ARGS(bool, SBCommandReturnObject, Succeeded);
161 
162   return ref().Succeeded();
163 }
164 
165 bool SBCommandReturnObject::HasResult() {
166   LLDB_RECORD_METHOD_NO_ARGS(bool, SBCommandReturnObject, HasResult);
167 
168   return ref().HasResult();
169 }
170 
171 void SBCommandReturnObject::AppendMessage(const char *message) {
172   LLDB_RECORD_METHOD(void, SBCommandReturnObject, AppendMessage, (const char *),
173                      message);
174 
175   ref().AppendMessage(message);
176 }
177 
178 void SBCommandReturnObject::AppendWarning(const char *message) {
179   LLDB_RECORD_METHOD(void, SBCommandReturnObject, AppendWarning, (const char *),
180                      message);
181 
182   ref().AppendWarning(message);
183 }
184 
185 CommandReturnObject *SBCommandReturnObject::operator->() const {
186   return &**m_opaque_up;
187 }
188 
189 CommandReturnObject *SBCommandReturnObject::get() const {
190   return &**m_opaque_up;
191 }
192 
193 CommandReturnObject &SBCommandReturnObject::operator*() const {
194   return **m_opaque_up;
195 }
196 
197 CommandReturnObject &SBCommandReturnObject::ref() const {
198   return **m_opaque_up;
199 }
200 
201 bool SBCommandReturnObject::GetDescription(SBStream &description) {
202   LLDB_RECORD_METHOD(bool, SBCommandReturnObject, GetDescription,
203                      (lldb::SBStream &), description);
204 
205   Stream &strm = description.ref();
206 
207   description.Printf("Error:  ");
208   lldb::ReturnStatus status = ref().GetStatus();
209   if (status == lldb::eReturnStatusStarted)
210     strm.PutCString("Started");
211   else if (status == lldb::eReturnStatusInvalid)
212     strm.PutCString("Invalid");
213   else if (ref().Succeeded())
214     strm.PutCString("Success");
215   else
216     strm.PutCString("Fail");
217 
218   if (GetOutputSize() > 0)
219     strm.Printf("\nOutput Message:\n%s", GetOutput());
220 
221   if (GetErrorSize() > 0)
222     strm.Printf("\nError Message:\n%s", GetError());
223 
224   return true;
225 }
226 
227 void SBCommandReturnObject::SetImmediateOutputFile(FILE *fh) {
228   LLDB_RECORD_METHOD(void, SBCommandReturnObject, SetImmediateOutputFile,
229                      (FILE *), fh);
230 
231   SetImmediateOutputFile(fh, false);
232 }
233 
234 void SBCommandReturnObject::SetImmediateErrorFile(FILE *fh) {
235   LLDB_RECORD_METHOD(void, SBCommandReturnObject, SetImmediateErrorFile,
236                      (FILE *), fh);
237 
238   SetImmediateErrorFile(fh, false);
239 }
240 
241 void SBCommandReturnObject::SetImmediateOutputFile(FILE *fh,
242                                                    bool transfer_ownership) {
243   LLDB_RECORD_METHOD(void, SBCommandReturnObject, SetImmediateOutputFile,
244                      (FILE *, bool), fh, transfer_ownership);
245 
246   ref().SetImmediateOutputFile(fh, transfer_ownership);
247 }
248 
249 void SBCommandReturnObject::SetImmediateErrorFile(FILE *fh,
250                                                   bool transfer_ownership) {
251   LLDB_RECORD_METHOD(void, SBCommandReturnObject, SetImmediateErrorFile,
252                      (FILE *, bool), fh, transfer_ownership);
253 
254   ref().SetImmediateErrorFile(fh, transfer_ownership);
255 }
256 
257 void SBCommandReturnObject::PutCString(const char *string, int len) {
258   LLDB_RECORD_METHOD(void, SBCommandReturnObject, PutCString,
259                      (const char *, int), string, len);
260 
261   if (len == 0 || string == nullptr || *string == 0) {
262     return;
263   } else if (len > 0) {
264     std::string buffer(string, len);
265     ref().AppendMessage(buffer.c_str());
266   } else
267     ref().AppendMessage(string);
268 }
269 
270 const char *SBCommandReturnObject::GetOutput(bool only_if_no_immediate) {
271   LLDB_RECORD_METHOD(const char *, SBCommandReturnObject, GetOutput, (bool),
272                      only_if_no_immediate);
273 
274   if (!only_if_no_immediate ||
275       ref().GetImmediateOutputStream().get() == nullptr)
276     return GetOutput();
277   return nullptr;
278 }
279 
280 const char *SBCommandReturnObject::GetError(bool only_if_no_immediate) {
281   LLDB_RECORD_METHOD(const char *, SBCommandReturnObject, GetError, (bool),
282                      only_if_no_immediate);
283 
284   if (!only_if_no_immediate || ref().GetImmediateErrorStream().get() == nullptr)
285     return GetError();
286   return nullptr;
287 }
288 
289 size_t SBCommandReturnObject::Printf(const char *format, ...) {
290   va_list args;
291   va_start(args, format);
292   size_t result = ref().GetOutputStream().PrintfVarArg(format, args);
293   va_end(args);
294   return result;
295 }
296 
297 void SBCommandReturnObject::SetError(lldb::SBError &error,
298                                      const char *fallback_error_cstr) {
299   LLDB_RECORD_METHOD(void, SBCommandReturnObject, SetError,
300                      (lldb::SBError &, const char *), error,
301                      fallback_error_cstr);
302 
303   if (error.IsValid())
304     ref().SetError(error.ref(), fallback_error_cstr);
305   else if (fallback_error_cstr)
306     ref().SetError(Status(), fallback_error_cstr);
307 }
308 
309 void SBCommandReturnObject::SetError(const char *error_cstr) {
310   LLDB_RECORD_METHOD(void, SBCommandReturnObject, SetError, (const char *),
311                      error_cstr);
312 
313   if (error_cstr)
314     ref().SetError(error_cstr);
315 }
316 
317 namespace lldb_private {
318 namespace repro {
319 
320 template <>
321 void RegisterMethods<SBCommandReturnObject>(Registry &R) {
322   LLDB_REGISTER_CONSTRUCTOR(SBCommandReturnObject, ());
323   LLDB_REGISTER_CONSTRUCTOR(SBCommandReturnObject,
324                             (lldb_private::CommandReturnObject &));
325   LLDB_REGISTER_CONSTRUCTOR(SBCommandReturnObject,
326                             (const lldb::SBCommandReturnObject &));
327   LLDB_REGISTER_METHOD(
328       lldb::SBCommandReturnObject &,
329       SBCommandReturnObject, operator=,(const lldb::SBCommandReturnObject &));
330   LLDB_REGISTER_METHOD_CONST(bool, SBCommandReturnObject, IsValid, ());
331   LLDB_REGISTER_METHOD_CONST(bool, SBCommandReturnObject, operator bool, ());
332   LLDB_REGISTER_METHOD(const char *, SBCommandReturnObject, GetOutput, ());
333   LLDB_REGISTER_METHOD(const char *, SBCommandReturnObject, GetError, ());
334   LLDB_REGISTER_METHOD(size_t, SBCommandReturnObject, GetOutputSize, ());
335   LLDB_REGISTER_METHOD(size_t, SBCommandReturnObject, GetErrorSize, ());
336   LLDB_REGISTER_METHOD(size_t, SBCommandReturnObject, PutOutput, (FILE *));
337   LLDB_REGISTER_METHOD(size_t, SBCommandReturnObject, PutError, (FILE *));
338   LLDB_REGISTER_METHOD(void, SBCommandReturnObject, Clear, ());
339   LLDB_REGISTER_METHOD(lldb::ReturnStatus, SBCommandReturnObject, GetStatus,
340                        ());
341   LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetStatus,
342                        (lldb::ReturnStatus));
343   LLDB_REGISTER_METHOD(bool, SBCommandReturnObject, Succeeded, ());
344   LLDB_REGISTER_METHOD(bool, SBCommandReturnObject, HasResult, ());
345   LLDB_REGISTER_METHOD(void, SBCommandReturnObject, AppendMessage,
346                        (const char *));
347   LLDB_REGISTER_METHOD(void, SBCommandReturnObject, AppendWarning,
348                        (const char *));
349   LLDB_REGISTER_METHOD(bool, SBCommandReturnObject, GetDescription,
350                        (lldb::SBStream &));
351   LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetImmediateOutputFile,
352                        (FILE *));
353   LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetImmediateErrorFile,
354                        (FILE *));
355   LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetImmediateOutputFile,
356                        (FILE *, bool));
357   LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetImmediateErrorFile,
358                        (FILE *, bool));
359   LLDB_REGISTER_METHOD(void, SBCommandReturnObject, PutCString,
360                        (const char *, int));
361   LLDB_REGISTER_METHOD(const char *, SBCommandReturnObject, GetOutput,
362                        (bool));
363   LLDB_REGISTER_METHOD(const char *, SBCommandReturnObject, GetError, (bool));
364   LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetError,
365                        (lldb::SBError &, const char *));
366   LLDB_REGISTER_METHOD(void, SBCommandReturnObject, SetError, (const char *));
367 }
368 
369 }
370 }
371