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