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: |
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(a&: *this, b&: 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_INSTRUMENT_VA(this); |
50 | } |
51 | |
52 | SBCommandReturnObject::SBCommandReturnObject(CommandReturnObject &ref) |
53 | : m_opaque_up(new SBCommandReturnObjectImpl(ref)) { |
54 | LLDB_INSTRUMENT_VA(this, ref); |
55 | } |
56 | |
57 | SBCommandReturnObject::SBCommandReturnObject(const SBCommandReturnObject &rhs) { |
58 | LLDB_INSTRUMENT_VA(this, rhs); |
59 | |
60 | m_opaque_up = clone(src: rhs.m_opaque_up); |
61 | } |
62 | |
63 | SBCommandReturnObject &SBCommandReturnObject:: |
64 | operator=(const SBCommandReturnObject &rhs) { |
65 | LLDB_INSTRUMENT_VA(this, rhs); |
66 | |
67 | if (this != &rhs) |
68 | m_opaque_up = clone(src: rhs.m_opaque_up); |
69 | return *this; |
70 | } |
71 | |
72 | SBCommandReturnObject::~SBCommandReturnObject() = default; |
73 | |
74 | bool SBCommandReturnObject::IsValid() const { |
75 | LLDB_INSTRUMENT_VA(this); |
76 | return this->operator bool(); |
77 | } |
78 | 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 | |
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 | |
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 | |
99 | size_t SBCommandReturnObject::GetOutputSize() { |
100 | LLDB_INSTRUMENT_VA(this); |
101 | |
102 | return ref().GetOutputData().size(); |
103 | } |
104 | |
105 | size_t SBCommandReturnObject::GetErrorSize() { |
106 | LLDB_INSTRUMENT_VA(this); |
107 | |
108 | return ref().GetErrorData().size(); |
109 | } |
110 | |
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(stream: fh, format: "%s" , GetOutput()); |
117 | } |
118 | return 0; |
119 | } |
120 | |
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(format: "%s" , GetOutput()); |
126 | } |
127 | |
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(format: "%s" , GetOutput()); |
133 | } |
134 | |
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(stream: fh, format: "%s" , GetError()); |
141 | } |
142 | return 0; |
143 | } |
144 | |
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(format: "%s" , GetError()); |
150 | } |
151 | |
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(format: "%s" , GetError()); |
157 | } |
158 | |
159 | void SBCommandReturnObject::Clear() { |
160 | LLDB_INSTRUMENT_VA(this); |
161 | |
162 | ref().Clear(); |
163 | } |
164 | |
165 | lldb::ReturnStatus SBCommandReturnObject::GetStatus() { |
166 | LLDB_INSTRUMENT_VA(this); |
167 | |
168 | return ref().GetStatus(); |
169 | } |
170 | |
171 | void SBCommandReturnObject::SetStatus(lldb::ReturnStatus status) { |
172 | LLDB_INSTRUMENT_VA(this, status); |
173 | |
174 | ref().SetStatus(status); |
175 | } |
176 | |
177 | bool SBCommandReturnObject::Succeeded() { |
178 | LLDB_INSTRUMENT_VA(this); |
179 | |
180 | return ref().Succeeded(); |
181 | } |
182 | |
183 | bool SBCommandReturnObject::HasResult() { |
184 | LLDB_INSTRUMENT_VA(this); |
185 | |
186 | return ref().HasResult(); |
187 | } |
188 | |
189 | void SBCommandReturnObject::AppendMessage(const char *message) { |
190 | LLDB_INSTRUMENT_VA(this, message); |
191 | |
192 | ref().AppendMessage(in_string: message); |
193 | } |
194 | |
195 | void SBCommandReturnObject::AppendWarning(const char *message) { |
196 | LLDB_INSTRUMENT_VA(this, message); |
197 | |
198 | ref().AppendWarning(in_string: message); |
199 | } |
200 | |
201 | CommandReturnObject *SBCommandReturnObject::operator->() const { |
202 | return &**m_opaque_up; |
203 | } |
204 | |
205 | CommandReturnObject *SBCommandReturnObject::get() const { |
206 | return &**m_opaque_up; |
207 | } |
208 | |
209 | CommandReturnObject &SBCommandReturnObject::operator*() const { |
210 | return **m_opaque_up; |
211 | } |
212 | |
213 | CommandReturnObject &SBCommandReturnObject::ref() const { |
214 | return **m_opaque_up; |
215 | } |
216 | |
217 | bool SBCommandReturnObject::GetDescription(SBStream &description) { |
218 | LLDB_INSTRUMENT_VA(this, description); |
219 | |
220 | Stream &strm = description.ref(); |
221 | |
222 | description.Printf(format: "Error: " ); |
223 | lldb::ReturnStatus status = ref().GetStatus(); |
224 | if (status == lldb::eReturnStatusStarted) |
225 | strm.PutCString(cstr: "Started" ); |
226 | else if (status == lldb::eReturnStatusInvalid) |
227 | strm.PutCString(cstr: "Invalid" ); |
228 | else if (ref().Succeeded()) |
229 | strm.PutCString(cstr: "Success" ); |
230 | else |
231 | strm.PutCString(cstr: "Fail" ); |
232 | |
233 | if (GetOutputSize() > 0) |
234 | strm.Printf(format: "\nOutput Message:\n%s" , GetOutput()); |
235 | |
236 | if (GetErrorSize() > 0) |
237 | strm.Printf(format: "\nError Message:\n%s" , GetError()); |
238 | |
239 | return true; |
240 | } |
241 | |
242 | void SBCommandReturnObject::SetImmediateOutputFile(FILE *fh) { |
243 | LLDB_INSTRUMENT_VA(this, fh); |
244 | |
245 | SetImmediateOutputFile(fh, transfer_ownership: false); |
246 | } |
247 | |
248 | void SBCommandReturnObject::SetImmediateErrorFile(FILE *fh) { |
249 | LLDB_INSTRUMENT_VA(this, fh); |
250 | |
251 | SetImmediateErrorFile(fh, transfer_ownership: false); |
252 | } |
253 | |
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>(args&: fh, args&: transfer_ownership); |
258 | ref().SetImmediateOutputFile(file); |
259 | } |
260 | |
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>(args&: fh, args&: transfer_ownership); |
265 | ref().SetImmediateErrorFile(file); |
266 | } |
267 | |
268 | void SBCommandReturnObject::SetImmediateOutputFile(SBFile file) { |
269 | LLDB_INSTRUMENT_VA(this, file); |
270 | ref().SetImmediateOutputFile(file.m_opaque_sp); |
271 | } |
272 | |
273 | void SBCommandReturnObject::SetImmediateErrorFile(SBFile file) { |
274 | LLDB_INSTRUMENT_VA(this, file); |
275 | ref().SetImmediateErrorFile(file.m_opaque_sp); |
276 | } |
277 | |
278 | void SBCommandReturnObject::SetImmediateOutputFile(FileSP file_sp) { |
279 | LLDB_INSTRUMENT_VA(this, file_sp); |
280 | SetImmediateOutputFile(SBFile(file_sp)); |
281 | } |
282 | |
283 | void SBCommandReturnObject::SetImmediateErrorFile(FileSP file_sp) { |
284 | LLDB_INSTRUMENT_VA(this, file_sp); |
285 | SetImmediateErrorFile(SBFile(file_sp)); |
286 | } |
287 | |
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(in_string: buffer.c_str()); |
296 | } else |
297 | ref().AppendMessage(in_string: string); |
298 | } |
299 | |
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 | |
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 | |
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 | |
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: error.ref(), fallback_error_cstr); |
331 | else if (fallback_error_cstr) |
332 | ref().SetError(error: Status(), fallback_error_cstr); |
333 | } |
334 | |
335 | void SBCommandReturnObject::SetError(const char *error_cstr) { |
336 | LLDB_INSTRUMENT_VA(this, error_cstr); |
337 | |
338 | if (error_cstr) |
339 | ref().AppendError(in_string: error_cstr); |
340 | } |
341 | |