Bug Summary

File:src/gnu/usr.bin/clang/liblldbBreakpoint/../../../llvm/lldb/source/Breakpoint/BreakpointOptions.cpp
Warning:line 69, column 5
Value stored to 'found_something' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name BreakpointOptions.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/gnu/usr.bin/clang/liblldbBreakpoint/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/gnu/usr.bin/clang/liblldbBreakpoint/../../../llvm/llvm/include -I /usr/src/gnu/usr.bin/clang/liblldbBreakpoint/../include -I /usr/src/gnu/usr.bin/clang/liblldbBreakpoint/obj -I /usr/src/gnu/usr.bin/clang/liblldbBreakpoint/obj/../include -D NDEBUG -D __STDC_LIMIT_MACROS -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D LLVM_PREFIX="/usr" -I /usr/src/gnu/usr.bin/clang/liblldbBreakpoint/../../../llvm/lldb/include -I /usr/src/gnu/usr.bin/clang/liblldbBreakpoint/../../../llvm/lldb/source -I /usr/src/gnu/usr.bin/clang/liblldbBreakpoint/../../../llvm/clang/include -internal-isystem /usr/include/c++/v1 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-comment -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/usr/src/gnu/usr.bin/clang/liblldbBreakpoint/obj -ferror-limit 19 -fvisibility-inlines-hidden -fwrapv -stack-protector 2 -fno-rtti -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c++ /usr/src/gnu/usr.bin/clang/liblldbBreakpoint/../../../llvm/lldb/source/Breakpoint/BreakpointOptions.cpp
1//===-- BreakpointOptions.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/Breakpoint/BreakpointOptions.h"
10
11#include "lldb/Breakpoint/StoppointCallbackContext.h"
12#include "lldb/Core/Value.h"
13#include "lldb/Interpreter/CommandInterpreter.h"
14#include "lldb/Interpreter/CommandReturnObject.h"
15#include "lldb/Target/Process.h"
16#include "lldb/Target/Target.h"
17#include "lldb/Target/ThreadSpec.h"
18#include "lldb/Utility/Stream.h"
19#include "lldb/Utility/StringList.h"
20
21#include "llvm/ADT/STLExtras.h"
22
23using namespace lldb;
24using namespace lldb_private;
25
26const char
27 *BreakpointOptions::CommandData::g_option_names[static_cast<uint32_t>(
28 BreakpointOptions::CommandData::OptionNames::LastOptionName)]{
29 "UserSource", "ScriptSource", "StopOnError"};
30
31StructuredData::ObjectSP
32BreakpointOptions::CommandData::SerializeToStructuredData() {
33 size_t num_strings = user_source.GetSize();
34 if (num_strings == 0 && script_source.empty()) {
35 // We shouldn't serialize commands if there aren't any, return an empty sp
36 // to indicate this.
37 return StructuredData::ObjectSP();
38 }
39
40 StructuredData::DictionarySP options_dict_sp(
41 new StructuredData::Dictionary());
42 options_dict_sp->AddBooleanItem(GetKey(OptionNames::StopOnError),
43 stop_on_error);
44
45 StructuredData::ArraySP user_source_sp(new StructuredData::Array());
46 for (size_t i = 0; i < num_strings; i++) {
47 StructuredData::StringSP item_sp(
48 new StructuredData::String(user_source[i]));
49 user_source_sp->AddItem(item_sp);
50 options_dict_sp->AddItem(GetKey(OptionNames::UserSource), user_source_sp);
51 }
52
53 options_dict_sp->AddStringItem(
54 GetKey(OptionNames::Interpreter),
55 ScriptInterpreter::LanguageToString(interpreter));
56 return options_dict_sp;
57}
58
59std::unique_ptr<BreakpointOptions::CommandData>
60BreakpointOptions::CommandData::CreateFromStructuredData(
61 const StructuredData::Dictionary &options_dict, Status &error) {
62 std::unique_ptr<CommandData> data_up(new CommandData());
63 bool found_something = false;
64
65 bool success = options_dict.GetValueForKeyAsBoolean(
66 GetKey(OptionNames::StopOnError), data_up->stop_on_error);
67
68 if (success)
69 found_something = true;
Value stored to 'found_something' is never read
70
71 llvm::StringRef interpreter_str;
72 ScriptLanguage interp_language;
73 success = options_dict.GetValueForKeyAsString(
74 GetKey(OptionNames::Interpreter), interpreter_str);
75
76 if (!success) {
77 error.SetErrorString("Missing command language value.");
78 return data_up;
79 }
80
81 found_something = true;
82 interp_language = ScriptInterpreter::StringToLanguage(interpreter_str);
83 if (interp_language == eScriptLanguageUnknown) {
84 error.SetErrorStringWithFormatv("Unknown breakpoint command language: {0}.",
85 interpreter_str);
86 return data_up;
87 }
88 data_up->interpreter = interp_language;
89
90 StructuredData::Array *user_source;
91 success = options_dict.GetValueForKeyAsArray(GetKey(OptionNames::UserSource),
92 user_source);
93 if (success) {
94 found_something = true;
95 size_t num_elems = user_source->GetSize();
96 for (size_t i = 0; i < num_elems; i++) {
97 llvm::StringRef elem_string;
98 success = user_source->GetItemAtIndexAsString(i, elem_string);
99 if (success)
100 data_up->user_source.AppendString(elem_string);
101 }
102 }
103
104 if (found_something)
105 return data_up;
106 else
107 return std::unique_ptr<BreakpointOptions::CommandData>();
108}
109
110const char *BreakpointOptions::g_option_names[(
111 size_t)BreakpointOptions::OptionNames::LastOptionName]{
112 "ConditionText", "IgnoreCount",
113 "EnabledState", "OneShotState", "AutoContinue"};
114
115bool BreakpointOptions::NullCallback(void *baton,
116 StoppointCallbackContext *context,
117 lldb::user_id_t break_id,
118 lldb::user_id_t break_loc_id) {
119 return true;
120}
121
122// BreakpointOptions constructor
123BreakpointOptions::BreakpointOptions(bool all_flags_set)
124 : m_callback(BreakpointOptions::NullCallback), m_callback_baton_sp(),
125 m_baton_is_command_baton(false), m_callback_is_synchronous(false),
126 m_enabled(true), m_one_shot(false), m_ignore_count(0), m_thread_spec_up(),
127 m_condition_text(), m_condition_text_hash(0), m_auto_continue(false),
128 m_set_flags(0) {
129 if (all_flags_set)
130 m_set_flags.Set(~((Flags::ValueType)0));
131}
132
133BreakpointOptions::BreakpointOptions(const char *condition, bool enabled,
134 int32_t ignore, bool one_shot,
135 bool auto_continue)
136 : m_callback(nullptr), m_baton_is_command_baton(false),
137 m_callback_is_synchronous(false), m_enabled(enabled),
138 m_one_shot(one_shot), m_ignore_count(ignore),
139 m_condition_text_hash(0), m_auto_continue(auto_continue)
140{
141 m_set_flags.Set(eEnabled | eIgnoreCount | eOneShot
142 | eAutoContinue);
143 if (condition && *condition != '\0') {
144 SetCondition(condition);
145 }
146}
147
148// BreakpointOptions copy constructor
149BreakpointOptions::BreakpointOptions(const BreakpointOptions &rhs)
150 : m_callback(rhs.m_callback), m_callback_baton_sp(rhs.m_callback_baton_sp),
151 m_baton_is_command_baton(rhs.m_baton_is_command_baton),
152 m_callback_is_synchronous(rhs.m_callback_is_synchronous),
153 m_enabled(rhs.m_enabled), m_one_shot(rhs.m_one_shot),
154 m_ignore_count(rhs.m_ignore_count), m_thread_spec_up(),
155 m_auto_continue(rhs.m_auto_continue), m_set_flags(rhs.m_set_flags) {
156 if (rhs.m_thread_spec_up != nullptr)
157 m_thread_spec_up = std::make_unique<ThreadSpec>(*rhs.m_thread_spec_up);
158 m_condition_text = rhs.m_condition_text;
159 m_condition_text_hash = rhs.m_condition_text_hash;
160}
161
162// BreakpointOptions assignment operator
163const BreakpointOptions &BreakpointOptions::
164operator=(const BreakpointOptions &rhs) {
165 m_callback = rhs.m_callback;
166 m_callback_baton_sp = rhs.m_callback_baton_sp;
167 m_baton_is_command_baton = rhs.m_baton_is_command_baton;
168 m_callback_is_synchronous = rhs.m_callback_is_synchronous;
169 m_enabled = rhs.m_enabled;
170 m_one_shot = rhs.m_one_shot;
171 m_ignore_count = rhs.m_ignore_count;
172 if (rhs.m_thread_spec_up != nullptr)
173 m_thread_spec_up = std::make_unique<ThreadSpec>(*rhs.m_thread_spec_up);
174 m_condition_text = rhs.m_condition_text;
175 m_condition_text_hash = rhs.m_condition_text_hash;
176 m_auto_continue = rhs.m_auto_continue;
177 m_set_flags = rhs.m_set_flags;
178 return *this;
179}
180
181void BreakpointOptions::CopyOverSetOptions(const BreakpointOptions &incoming)
182{
183 if (incoming.m_set_flags.Test(eEnabled))
184 {
185 m_enabled = incoming.m_enabled;
186 m_set_flags.Set(eEnabled);
187 }
188 if (incoming.m_set_flags.Test(eOneShot))
189 {
190 m_one_shot = incoming.m_one_shot;
191 m_set_flags.Set(eOneShot);
192 }
193 if (incoming.m_set_flags.Test(eCallback))
194 {
195 m_callback = incoming.m_callback;
196 m_callback_baton_sp = incoming.m_callback_baton_sp;
197 m_callback_is_synchronous = incoming.m_callback_is_synchronous;
198 m_baton_is_command_baton = incoming.m_baton_is_command_baton;
199 m_set_flags.Set(eCallback);
200 }
201 if (incoming.m_set_flags.Test(eIgnoreCount))
202 {
203 m_ignore_count = incoming.m_ignore_count;
204 m_set_flags.Set(eIgnoreCount);
205 }
206 if (incoming.m_set_flags.Test(eCondition))
207 {
208 // If we're copying over an empty condition, mark it as unset.
209 if (incoming.m_condition_text.empty()) {
210 m_condition_text.clear();
211 m_condition_text_hash = 0;
212 m_set_flags.Clear(eCondition);
213 } else {
214 m_condition_text = incoming.m_condition_text;
215 m_condition_text_hash = incoming.m_condition_text_hash;
216 m_set_flags.Set(eCondition);
217 }
218 }
219 if (incoming.m_set_flags.Test(eAutoContinue))
220 {
221 m_auto_continue = incoming.m_auto_continue;
222 m_set_flags.Set(eAutoContinue);
223 }
224 if (incoming.m_set_flags.Test(eThreadSpec) && incoming.m_thread_spec_up) {
225 if (!m_thread_spec_up)
226 m_thread_spec_up =
227 std::make_unique<ThreadSpec>(*incoming.m_thread_spec_up);
228 else
229 *m_thread_spec_up = *incoming.m_thread_spec_up;
230 m_set_flags.Set(eThreadSpec);
231 }
232}
233
234// Destructor
235BreakpointOptions::~BreakpointOptions() = default;
236
237std::unique_ptr<BreakpointOptions> BreakpointOptions::CreateFromStructuredData(
238 Target &target, const StructuredData::Dictionary &options_dict,
239 Status &error) {
240 bool enabled = true;
241 bool one_shot = false;
242 bool auto_continue = false;
243 int32_t ignore_count = 0;
244 llvm::StringRef condition_ref("");
245 Flags set_options;
246
247 const char *key = GetKey(OptionNames::EnabledState);
248 bool success;
249 if (key && options_dict.HasKey(key)) {
250 success = options_dict.GetValueForKeyAsBoolean(key, enabled);
251 if (!success) {
252 error.SetErrorStringWithFormat("%s key is not a boolean.", key);
253 return nullptr;
254 }
255 set_options.Set(eEnabled);
256 }
257
258 key = GetKey(OptionNames::OneShotState);
259 if (key && options_dict.HasKey(key)) {
260 success = options_dict.GetValueForKeyAsBoolean(key, one_shot);
261 if (!success) {
262 error.SetErrorStringWithFormat("%s key is not a boolean.", key);
263 return nullptr;
264 }
265 set_options.Set(eOneShot);
266 }
267
268 key = GetKey(OptionNames::AutoContinue);
269 if (key && options_dict.HasKey(key)) {
270 success = options_dict.GetValueForKeyAsBoolean(key, auto_continue);
271 if (!success) {
272 error.SetErrorStringWithFormat("%s key is not a boolean.", key);
273 return nullptr;
274 }
275 set_options.Set(eAutoContinue);
276 }
277
278 key = GetKey(OptionNames::IgnoreCount);
279 if (key && options_dict.HasKey(key)) {
280 success = options_dict.GetValueForKeyAsInteger(key, ignore_count);
281 if (!success) {
282 error.SetErrorStringWithFormat("%s key is not an integer.", key);
283 return nullptr;
284 }
285 set_options.Set(eIgnoreCount);
286 }
287
288 key = GetKey(OptionNames::ConditionText);
289 if (key && options_dict.HasKey(key)) {
290 success = options_dict.GetValueForKeyAsString(key, condition_ref);
291 if (!success) {
292 error.SetErrorStringWithFormat("%s key is not an string.", key);
293 return nullptr;
294 }
295 set_options.Set(eCondition);
296 }
297
298 std::unique_ptr<CommandData> cmd_data_up;
299 StructuredData::Dictionary *cmds_dict;
300 success = options_dict.GetValueForKeyAsDictionary(
301 CommandData::GetSerializationKey(), cmds_dict);
302 if (success && cmds_dict) {
303 Status cmds_error;
304 cmd_data_up = CommandData::CreateFromStructuredData(*cmds_dict, cmds_error);
305 if (cmds_error.Fail()) {
306 error.SetErrorStringWithFormat(
307 "Failed to deserialize breakpoint command options: %s.",
308 cmds_error.AsCString());
309 return nullptr;
310 }
311 }
312
313 auto bp_options = std::make_unique<BreakpointOptions>(
314 condition_ref.str().c_str(), enabled,
315 ignore_count, one_shot, auto_continue);
316 if (cmd_data_up) {
317 if (cmd_data_up->interpreter == eScriptLanguageNone)
318 bp_options->SetCommandDataCallback(cmd_data_up);
319 else {
320 ScriptInterpreter *interp = target.GetDebugger().GetScriptInterpreter();
321 if (!interp) {
322 error.SetErrorString(
323 "Can't set script commands - no script interpreter");
324 return nullptr;
325 }
326 if (interp->GetLanguage() != cmd_data_up->interpreter) {
327 error.SetErrorStringWithFormat(
328 "Current script language doesn't match breakpoint's language: %s",
329 ScriptInterpreter::LanguageToString(cmd_data_up->interpreter)
330 .c_str());
331 return nullptr;
332 }
333 Status script_error;
334 script_error =
335 interp->SetBreakpointCommandCallback(*bp_options, cmd_data_up);
336 if (script_error.Fail()) {
337 error.SetErrorStringWithFormat("Error generating script callback: %s.",
338 error.AsCString());
339 return nullptr;
340 }
341 }
342 }
343
344 StructuredData::Dictionary *thread_spec_dict;
345 success = options_dict.GetValueForKeyAsDictionary(
346 ThreadSpec::GetSerializationKey(), thread_spec_dict);
347 if (success) {
348 Status thread_spec_error;
349 std::unique_ptr<ThreadSpec> thread_spec_up =
350 ThreadSpec::CreateFromStructuredData(*thread_spec_dict,
351 thread_spec_error);
352 if (thread_spec_error.Fail()) {
353 error.SetErrorStringWithFormat(
354 "Failed to deserialize breakpoint thread spec options: %s.",
355 thread_spec_error.AsCString());
356 return nullptr;
357 }
358 bp_options->SetThreadSpec(thread_spec_up);
359 }
360 return bp_options;
361}
362
363StructuredData::ObjectSP BreakpointOptions::SerializeToStructuredData() {
364 StructuredData::DictionarySP options_dict_sp(
365 new StructuredData::Dictionary());
366 if (m_set_flags.Test(eEnabled))
367 options_dict_sp->AddBooleanItem(GetKey(OptionNames::EnabledState),
368 m_enabled);
369 if (m_set_flags.Test(eOneShot))
370 options_dict_sp->AddBooleanItem(GetKey(OptionNames::OneShotState),
371 m_one_shot);
372 if (m_set_flags.Test(eAutoContinue))
373 options_dict_sp->AddBooleanItem(GetKey(OptionNames::AutoContinue),
374 m_auto_continue);
375 if (m_set_flags.Test(eIgnoreCount))
376 options_dict_sp->AddIntegerItem(GetKey(OptionNames::IgnoreCount),
377 m_ignore_count);
378 if (m_set_flags.Test(eCondition))
379 options_dict_sp->AddStringItem(GetKey(OptionNames::ConditionText),
380 m_condition_text);
381
382 if (m_set_flags.Test(eCallback) && m_baton_is_command_baton) {
383 auto cmd_baton =
384 std::static_pointer_cast<CommandBaton>(m_callback_baton_sp);
385 StructuredData::ObjectSP commands_sp =
386 cmd_baton->getItem()->SerializeToStructuredData();
387 if (commands_sp) {
388 options_dict_sp->AddItem(
389 BreakpointOptions::CommandData::GetSerializationKey(), commands_sp);
390 }
391 }
392 if (m_set_flags.Test(eThreadSpec) && m_thread_spec_up) {
393 StructuredData::ObjectSP thread_spec_sp =
394 m_thread_spec_up->SerializeToStructuredData();
395 options_dict_sp->AddItem(ThreadSpec::GetSerializationKey(), thread_spec_sp);
396 }
397
398 return options_dict_sp;
399}
400
401// Callbacks
402void BreakpointOptions::SetCallback(BreakpointHitCallback callback,
403 const lldb::BatonSP &callback_baton_sp,
404 bool callback_is_synchronous) {
405 // FIXME: This seems unsafe. If BatonSP actually *is* a CommandBaton, but
406 // in a shared_ptr<Baton> instead of a shared_ptr<CommandBaton>, then we will
407 // set m_baton_is_command_baton to false, which is incorrect. One possible
408 // solution is to make the base Baton class provide a method such as:
409 // virtual StringRef getBatonId() const { return ""; }
410 // and have CommandBaton override this to return something unique, and then
411 // check for it here. Another option might be to make Baton using the llvm
412 // casting infrastructure, so that we could write something like:
413 // if (llvm::isa<CommandBaton>(callback_baton_sp))
414 // at relevant callsites instead of storing a boolean.
415 m_callback_is_synchronous = callback_is_synchronous;
416 m_callback = callback;
417 m_callback_baton_sp = callback_baton_sp;
418 m_baton_is_command_baton = false;
419 m_set_flags.Set(eCallback);
420}
421
422void BreakpointOptions::SetCallback(
423 BreakpointHitCallback callback,
424 const BreakpointOptions::CommandBatonSP &callback_baton_sp,
425 bool callback_is_synchronous) {
426 m_callback_is_synchronous = callback_is_synchronous;
427 m_callback = callback;
428 m_callback_baton_sp = callback_baton_sp;
429 m_baton_is_command_baton = true;
430 m_set_flags.Set(eCallback);
431}
432
433void BreakpointOptions::ClearCallback() {
434 m_callback = BreakpointOptions::NullCallback;
435 m_callback_is_synchronous = false;
436 m_callback_baton_sp.reset();
437 m_baton_is_command_baton = false;
438 m_set_flags.Clear(eCallback);
439}
440
441Baton *BreakpointOptions::GetBaton() { return m_callback_baton_sp.get(); }
442
443const Baton *BreakpointOptions::GetBaton() const {
444 return m_callback_baton_sp.get();
445}
446
447bool BreakpointOptions::InvokeCallback(StoppointCallbackContext *context,
448 lldb::user_id_t break_id,
449 lldb::user_id_t break_loc_id) {
450 if (m_callback) {
451 if (context->is_synchronous == IsCallbackSynchronous()) {
452 return m_callback(m_callback_baton_sp ? m_callback_baton_sp->data()
453 : nullptr,
454 context, break_id, break_loc_id);
455 } else if (IsCallbackSynchronous()) {
456 return false;
457 }
458 }
459 return true;
460}
461
462bool BreakpointOptions::HasCallback() const {
463 return m_callback != BreakpointOptions::NullCallback;
464}
465
466bool BreakpointOptions::GetCommandLineCallbacks(StringList &command_list) {
467 if (!HasCallback())
468 return false;
469 if (!m_baton_is_command_baton)
470 return false;
471
472 auto cmd_baton = std::static_pointer_cast<CommandBaton>(m_callback_baton_sp);
473 CommandData *data = cmd_baton->getItem();
474 if (!data)
475 return false;
476 command_list = data->user_source;
477 return true;
478}
479
480void BreakpointOptions::SetCondition(const char *condition) {
481 if (!condition || condition[0] == '\0') {
482 condition = "";
483 m_set_flags.Clear(eCondition);
484 }
485 else
486 m_set_flags.Set(eCondition);
487
488 m_condition_text.assign(condition);
489 std::hash<std::string> hasher;
490 m_condition_text_hash = hasher(m_condition_text);
491}
492
493const char *BreakpointOptions::GetConditionText(size_t *hash) const {
494 if (!m_condition_text.empty()) {
495 if (hash)
496 *hash = m_condition_text_hash;
497
498 return m_condition_text.c_str();
499 } else {
500 return nullptr;
501 }
502}
503
504const ThreadSpec *BreakpointOptions::GetThreadSpecNoCreate() const {
505 return m_thread_spec_up.get();
506}
507
508ThreadSpec *BreakpointOptions::GetThreadSpec() {
509 if (m_thread_spec_up == nullptr) {
510 m_set_flags.Set(eThreadSpec);
511 m_thread_spec_up = std::make_unique<ThreadSpec>();
512 }
513
514 return m_thread_spec_up.get();
515}
516
517void BreakpointOptions::SetThreadID(lldb::tid_t thread_id) {
518 GetThreadSpec()->SetTID(thread_id);
519 m_set_flags.Set(eThreadSpec);
520}
521
522void BreakpointOptions::SetThreadSpec(
523 std::unique_ptr<ThreadSpec> &thread_spec_up) {
524 m_thread_spec_up = std::move(thread_spec_up);
525 m_set_flags.Set(eThreadSpec);
526}
527
528void BreakpointOptions::GetDescription(Stream *s,
529 lldb::DescriptionLevel level) const {
530 // Figure out if there are any options not at their default value, and only
531 // print anything if there are:
532
533 if (m_ignore_count != 0 || !m_enabled || m_one_shot || m_auto_continue ||
534 (GetThreadSpecNoCreate() != nullptr &&
535 GetThreadSpecNoCreate()->HasSpecification())) {
536 if (level == lldb::eDescriptionLevelVerbose) {
537 s->EOL();
538 s->IndentMore();
539 s->Indent();
540 s->PutCString("Breakpoint Options:\n");
541 s->IndentMore();
542 s->Indent();
543 } else
544 s->PutCString(" Options: ");
545
546 if (m_ignore_count > 0)
547 s->Printf("ignore: %d ", m_ignore_count);
548 s->Printf("%sabled ", m_enabled ? "en" : "dis");
549
550 if (m_one_shot)
551 s->Printf("one-shot ");
552
553 if (m_auto_continue)
554 s->Printf("auto-continue ");
555
556 if (m_thread_spec_up)
557 m_thread_spec_up->GetDescription(s, level);
558
559 if (level == lldb::eDescriptionLevelFull) {
560 s->IndentLess();
561 s->IndentMore();
562 }
563 }
564
565 if (m_callback_baton_sp.get()) {
566 if (level != eDescriptionLevelBrief) {
567 s->EOL();
568 m_callback_baton_sp->GetDescription(s->AsRawOstream(), level,
569 s->GetIndentLevel());
570 }
571 }
572 if (!m_condition_text.empty()) {
573 if (level != eDescriptionLevelBrief) {
574 s->EOL();
575 s->Printf("Condition: %s\n", m_condition_text.c_str());
576 }
577 }
578}
579
580void BreakpointOptions::CommandBaton::GetDescription(
581 llvm::raw_ostream &s, lldb::DescriptionLevel level,
582 unsigned indentation) const {
583 const CommandData *data = getItem();
584
585 if (level == eDescriptionLevelBrief) {
586 s << ", commands = "
587 << ((data && data->user_source.GetSize() > 0) ? "yes" : "no");
588 return;
589 }
590
591 indentation += 2;
592 s.indent(indentation);
593 s << "Breakpoint commands";
594 if (data->interpreter != eScriptLanguageNone)
595 s << llvm::formatv(" ({0}):\n",
596 ScriptInterpreter::LanguageToString(data->interpreter));
597 else
598 s << ":\n";
599
600 indentation += 2;
601 if (data && data->user_source.GetSize() > 0) {
602 for (llvm::StringRef str : data->user_source) {
603 s.indent(indentation);
604 s << str << "\n";
605 }
606 } else
607 s << "No commands.\n";
608}
609
610void BreakpointOptions::SetCommandDataCallback(
611 std::unique_ptr<CommandData> &cmd_data) {
612 cmd_data->interpreter = eScriptLanguageNone;
613 auto baton_sp = std::make_shared<CommandBaton>(std::move(cmd_data));
614 SetCallback(BreakpointOptions::BreakpointOptionsCallbackFunction, baton_sp);
615 m_set_flags.Set(eCallback);
616}
617
618bool BreakpointOptions::BreakpointOptionsCallbackFunction(
619 void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id,
620 lldb::user_id_t break_loc_id) {
621 bool ret_value = true;
622 if (baton == nullptr)
623 return true;
624
625 CommandData *data = (CommandData *)baton;
626 StringList &commands = data->user_source;
627
628 if (commands.GetSize() > 0) {
629 ExecutionContext exe_ctx(context->exe_ctx_ref);
630 Target *target = exe_ctx.GetTargetPtr();
631 if (target) {
632 Debugger &debugger = target->GetDebugger();
633 CommandReturnObject result(debugger.GetUseColor());
634
635 // Rig up the results secondary output stream to the debugger's, so the
636 // output will come out synchronously if the debugger is set up that way.
637 StreamSP output_stream(debugger.GetAsyncOutputStream());
638 StreamSP error_stream(debugger.GetAsyncErrorStream());
639 result.SetImmediateOutputStream(output_stream);
640 result.SetImmediateErrorStream(error_stream);
641
642 CommandInterpreterRunOptions options;
643 options.SetStopOnContinue(true);
644 options.SetStopOnError(data->stop_on_error);
645 options.SetEchoCommands(true);
646 options.SetPrintResults(true);
647 options.SetPrintErrors(true);
648 options.SetAddToHistory(false);
649
650 debugger.GetCommandInterpreter().HandleCommands(commands, exe_ctx,
651 options, result);
652 result.GetImmediateOutputStream()->Flush();
653 result.GetImmediateErrorStream()->Flush();
654 }
655 }
656 return ret_value;
657}
658
659void BreakpointOptions::Clear()
660{
661 m_set_flags.Clear();
662 m_thread_spec_up.release();
663 m_one_shot = false;
664 m_ignore_count = 0;
665 m_auto_continue = false;
666 m_callback = nullptr;
667 m_callback_baton_sp.reset();
668 m_baton_is_command_baton = false;
669 m_callback_is_synchronous = false;
670 m_enabled = false;
671 m_condition_text.clear();
672}