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(key: GetKey(enum_value: OptionNames::StopOnError),
43 value: 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: item_sp);
50 options_dict_sp->AddItem(key: GetKey(enum_value: OptionNames::UserSource), value_sp: user_source_sp);
51 }
52
53 options_dict_sp->AddStringItem(
54 key: GetKey(enum_value: OptionNames::Interpreter),
55 value: ScriptInterpreter::LanguageToString(language: 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
64 bool success = options_dict.GetValueForKeyAsBoolean(
65 key: GetKey(enum_value: OptionNames::StopOnError), result&: data_up->stop_on_error);
66
67 llvm::StringRef interpreter_str;
68 ScriptLanguage interp_language;
69 success = options_dict.GetValueForKeyAsString(
70 key: GetKey(enum_value: OptionNames::Interpreter), result&: interpreter_str);
71
72 if (!success) {
73 error = Status::FromErrorString(str: "Missing command language value.");
74 return data_up;
75 }
76
77 interp_language = ScriptInterpreter::StringToLanguage(string: interpreter_str);
78 if (interp_language == eScriptLanguageUnknown) {
79 error = Status::FromErrorStringWithFormatv(
80 format: "Unknown breakpoint command language: {0}.", args&: interpreter_str);
81 return data_up;
82 }
83 data_up->interpreter = interp_language;
84
85 StructuredData::Array *user_source;
86 success = options_dict.GetValueForKeyAsArray(key: GetKey(enum_value: OptionNames::UserSource),
87 result&: user_source);
88 if (success) {
89 size_t num_elems = user_source->GetSize();
90 for (size_t i = 0; i < num_elems; i++) {
91 if (std::optional<llvm::StringRef> maybe_elem_string =
92 user_source->GetItemAtIndexAsString(idx: i))
93 data_up->user_source.AppendString(str: *maybe_elem_string);
94 }
95 }
96
97 return data_up;
98}
99
100const char *BreakpointOptions::g_option_names[(
101 size_t)BreakpointOptions::OptionNames::LastOptionName]{
102 "ConditionText", "IgnoreCount", "EnabledState", "OneShotState",
103 "AutoContinue"};
104
105// BreakpointOptions constructor
106BreakpointOptions::BreakpointOptions(bool all_flags_set)
107 : m_callback(nullptr), m_baton_is_command_baton(false),
108 m_callback_is_synchronous(false), m_enabled(true), m_one_shot(false),
109 m_ignore_count(0), m_inject_condition(false), m_auto_continue(false),
110 m_set_flags(0) {
111 if (all_flags_set)
112 m_set_flags.Set(~((Flags::ValueType)0));
113}
114
115BreakpointOptions::BreakpointOptions(const char *condition, bool enabled,
116 int32_t ignore, bool one_shot,
117 bool auto_continue)
118 : m_callback(nullptr), m_baton_is_command_baton(false),
119 m_callback_is_synchronous(false), m_enabled(enabled),
120 m_one_shot(one_shot), m_ignore_count(ignore), m_condition(condition),
121 m_inject_condition(false), m_auto_continue(auto_continue) {
122 m_set_flags.Set(eEnabled | eIgnoreCount | eOneShot | eAutoContinue);
123 if (condition && *condition != '\0') {
124 SetCondition(StopCondition(condition));
125 }
126}
127
128// BreakpointOptions copy constructor
129BreakpointOptions::BreakpointOptions(const BreakpointOptions &rhs)
130 : m_callback(rhs.m_callback), m_callback_baton_sp(rhs.m_callback_baton_sp),
131 m_baton_is_command_baton(rhs.m_baton_is_command_baton),
132 m_callback_is_synchronous(rhs.m_callback_is_synchronous),
133 m_enabled(rhs.m_enabled), m_one_shot(rhs.m_one_shot),
134 m_ignore_count(rhs.m_ignore_count), m_inject_condition(false),
135 m_auto_continue(rhs.m_auto_continue), m_set_flags(rhs.m_set_flags) {
136 if (rhs.m_thread_spec_up != nullptr)
137 m_thread_spec_up = std::make_unique<ThreadSpec>(args&: *rhs.m_thread_spec_up);
138 m_condition = rhs.m_condition;
139}
140
141// BreakpointOptions assignment operator
142const BreakpointOptions &BreakpointOptions::
143operator=(const BreakpointOptions &rhs) {
144 m_callback = rhs.m_callback;
145 m_callback_baton_sp = rhs.m_callback_baton_sp;
146 m_baton_is_command_baton = rhs.m_baton_is_command_baton;
147 m_callback_is_synchronous = rhs.m_callback_is_synchronous;
148 m_enabled = rhs.m_enabled;
149 m_one_shot = rhs.m_one_shot;
150 m_ignore_count = rhs.m_ignore_count;
151 if (rhs.m_thread_spec_up != nullptr)
152 m_thread_spec_up = std::make_unique<ThreadSpec>(args&: *rhs.m_thread_spec_up);
153 m_condition = rhs.m_condition;
154 m_inject_condition = rhs.m_inject_condition;
155 m_auto_continue = rhs.m_auto_continue;
156 m_set_flags = rhs.m_set_flags;
157 return *this;
158}
159
160void BreakpointOptions::CopyOverSetOptions(const BreakpointOptions &incoming)
161{
162 if (incoming.m_set_flags.Test(bit: eEnabled))
163 {
164 m_enabled = incoming.m_enabled;
165 m_set_flags.Set(eEnabled);
166 }
167 if (incoming.m_set_flags.Test(bit: eOneShot))
168 {
169 m_one_shot = incoming.m_one_shot;
170 m_set_flags.Set(eOneShot);
171 }
172 if (incoming.m_set_flags.Test(bit: eCallback))
173 {
174 m_callback = incoming.m_callback;
175 m_callback_baton_sp = incoming.m_callback_baton_sp;
176 m_callback_is_synchronous = incoming.m_callback_is_synchronous;
177 m_baton_is_command_baton = incoming.m_baton_is_command_baton;
178 m_set_flags.Set(eCallback);
179 }
180 if (incoming.m_set_flags.Test(bit: eIgnoreCount))
181 {
182 m_ignore_count = incoming.m_ignore_count;
183 m_set_flags.Set(eIgnoreCount);
184 }
185 if (incoming.m_set_flags.Test(bit: eCondition))
186 {
187 // If we're copying over an empty condition, mark it as unset.
188 if (!incoming.m_condition) {
189 m_condition = StopCondition();
190 m_set_flags.Clear(mask: eCondition);
191 } else {
192 m_condition = incoming.m_condition;
193 m_set_flags.Set(eCondition);
194 }
195 }
196 if (incoming.m_set_flags.Test(bit: eAutoContinue))
197 {
198 m_auto_continue = incoming.m_auto_continue;
199 m_set_flags.Set(eAutoContinue);
200 }
201 if (incoming.m_set_flags.Test(bit: eThreadSpec) && incoming.m_thread_spec_up) {
202 if (!m_thread_spec_up)
203 m_thread_spec_up =
204 std::make_unique<ThreadSpec>(args&: *incoming.m_thread_spec_up);
205 else
206 *m_thread_spec_up = *incoming.m_thread_spec_up;
207 m_set_flags.Set(eThreadSpec);
208 }
209}
210
211// Destructor
212BreakpointOptions::~BreakpointOptions() = default;
213
214std::unique_ptr<BreakpointOptions> BreakpointOptions::CreateFromStructuredData(
215 Target &target, const StructuredData::Dictionary &options_dict,
216 Status &error) {
217 bool enabled = true;
218 bool one_shot = false;
219 bool auto_continue = false;
220 uint32_t ignore_count = 0;
221 llvm::StringRef condition_ref("");
222 Flags set_options;
223
224 const char *key = GetKey(enum_value: OptionNames::EnabledState);
225 bool success;
226 if (key && options_dict.HasKey(key)) {
227 success = options_dict.GetValueForKeyAsBoolean(key, result&: enabled);
228 if (!success) {
229 error =
230 Status::FromErrorStringWithFormat(format: "%s key is not a boolean.", key);
231 return nullptr;
232 }
233 set_options.Set(eEnabled);
234 }
235
236 key = GetKey(enum_value: OptionNames::OneShotState);
237 if (key && options_dict.HasKey(key)) {
238 success = options_dict.GetValueForKeyAsBoolean(key, result&: one_shot);
239 if (!success) {
240 error =
241 Status::FromErrorStringWithFormat(format: "%s key is not a boolean.", key);
242 return nullptr;
243 }
244 set_options.Set(eOneShot);
245 }
246
247 key = GetKey(enum_value: OptionNames::AutoContinue);
248 if (key && options_dict.HasKey(key)) {
249 success = options_dict.GetValueForKeyAsBoolean(key, result&: auto_continue);
250 if (!success) {
251 error =
252 Status::FromErrorStringWithFormat(format: "%s key is not a boolean.", key);
253 return nullptr;
254 }
255 set_options.Set(eAutoContinue);
256 }
257
258 key = GetKey(enum_value: OptionNames::IgnoreCount);
259 if (key && options_dict.HasKey(key)) {
260 success = options_dict.GetValueForKeyAsInteger(key, result&: ignore_count);
261 if (!success) {
262 error =
263 Status::FromErrorStringWithFormat(format: "%s key is not an integer.", key);
264 return nullptr;
265 }
266 set_options.Set(eIgnoreCount);
267 }
268
269 key = GetKey(enum_value: OptionNames::ConditionText);
270 if (key && options_dict.HasKey(key)) {
271 success = options_dict.GetValueForKeyAsString(key, result&: condition_ref);
272 if (!success) {
273 error =
274 Status::FromErrorStringWithFormat(format: "%s key is not an string.", key);
275 return nullptr;
276 }
277 set_options.Set(eCondition);
278 }
279
280 std::unique_ptr<CommandData> cmd_data_up;
281 StructuredData::Dictionary *cmds_dict;
282 success = options_dict.GetValueForKeyAsDictionary(
283 key: CommandData::GetSerializationKey(), result&: cmds_dict);
284 if (success && cmds_dict) {
285 Status cmds_error;
286 cmd_data_up = CommandData::CreateFromStructuredData(options_dict: *cmds_dict, error&: cmds_error);
287 if (cmds_error.Fail()) {
288 error = Status::FromErrorStringWithFormat(
289 format: "Failed to deserialize breakpoint command options: %s.",
290 cmds_error.AsCString());
291 return nullptr;
292 }
293 }
294
295 auto bp_options = std::make_unique<BreakpointOptions>(
296 args: condition_ref.str().c_str(), args&: enabled, args&: ignore_count, args&: one_shot,
297 args&: auto_continue);
298 if (cmd_data_up) {
299 if (cmd_data_up->interpreter == eScriptLanguageNone)
300 bp_options->SetCommandDataCallback(cmd_data_up);
301 else {
302 ScriptInterpreter *interp = target.GetDebugger().GetScriptInterpreter();
303 if (!interp) {
304 error = Status::FromErrorString(
305 str: "Can't set script commands - no script interpreter");
306 return nullptr;
307 }
308 if (interp->GetLanguage() != cmd_data_up->interpreter) {
309 error = Status::FromErrorStringWithFormat(
310 format: "Current script language doesn't match breakpoint's language: %s",
311 ScriptInterpreter::LanguageToString(language: cmd_data_up->interpreter)
312 .c_str());
313 return nullptr;
314 }
315 Status script_error;
316 script_error =
317 interp->SetBreakpointCommandCallback(bp_options&: *bp_options, data_up&: cmd_data_up);
318 if (script_error.Fail()) {
319 error = Status::FromErrorStringWithFormat(
320 format: "Error generating script callback: %s.", error.AsCString());
321 return nullptr;
322 }
323 }
324 }
325
326 StructuredData::Dictionary *thread_spec_dict;
327 success = options_dict.GetValueForKeyAsDictionary(
328 key: ThreadSpec::GetSerializationKey(), result&: thread_spec_dict);
329 if (success) {
330 Status thread_spec_error;
331 std::unique_ptr<ThreadSpec> thread_spec_up =
332 ThreadSpec::CreateFromStructuredData(data_dict: *thread_spec_dict,
333 error&: thread_spec_error);
334 if (thread_spec_error.Fail()) {
335 error = Status::FromErrorStringWithFormat(
336 format: "Failed to deserialize breakpoint thread spec options: %s.",
337 thread_spec_error.AsCString());
338 return nullptr;
339 }
340 bp_options->SetThreadSpec(thread_spec_up);
341 }
342 return bp_options;
343}
344
345StructuredData::ObjectSP BreakpointOptions::SerializeToStructuredData() {
346 StructuredData::DictionarySP options_dict_sp(
347 new StructuredData::Dictionary());
348 if (m_set_flags.Test(bit: eEnabled))
349 options_dict_sp->AddBooleanItem(key: GetKey(enum_value: OptionNames::EnabledState),
350 value: m_enabled);
351 if (m_set_flags.Test(bit: eOneShot))
352 options_dict_sp->AddBooleanItem(key: GetKey(enum_value: OptionNames::OneShotState),
353 value: m_one_shot);
354 if (m_set_flags.Test(bit: eAutoContinue))
355 options_dict_sp->AddBooleanItem(key: GetKey(enum_value: OptionNames::AutoContinue),
356 value: m_auto_continue);
357 if (m_set_flags.Test(bit: eIgnoreCount))
358 options_dict_sp->AddIntegerItem(key: GetKey(enum_value: OptionNames::IgnoreCount),
359 value: m_ignore_count);
360 if (m_set_flags.Test(bit: eCondition))
361 options_dict_sp->AddStringItem(key: GetKey(enum_value: OptionNames::ConditionText),
362 value: m_condition.GetText());
363
364 if (m_set_flags.Test(bit: eCallback) && m_baton_is_command_baton) {
365 auto cmd_baton =
366 std::static_pointer_cast<CommandBaton>(r: m_callback_baton_sp);
367 StructuredData::ObjectSP commands_sp =
368 cmd_baton->getItem()->SerializeToStructuredData();
369 if (commands_sp) {
370 options_dict_sp->AddItem(
371 key: BreakpointOptions::CommandData::GetSerializationKey(), value_sp: commands_sp);
372 }
373 }
374 if (m_set_flags.Test(bit: eThreadSpec) && m_thread_spec_up) {
375 StructuredData::ObjectSP thread_spec_sp =
376 m_thread_spec_up->SerializeToStructuredData();
377 options_dict_sp->AddItem(key: ThreadSpec::GetSerializationKey(), value_sp: thread_spec_sp);
378 }
379
380 return options_dict_sp;
381}
382
383// Callbacks
384void BreakpointOptions::SetCallback(BreakpointHitCallback callback,
385 const lldb::BatonSP &callback_baton_sp,
386 bool callback_is_synchronous) {
387 // FIXME: This seems unsafe. If BatonSP actually *is* a CommandBaton, but
388 // in a shared_ptr<Baton> instead of a shared_ptr<CommandBaton>, then we will
389 // set m_baton_is_command_baton to false, which is incorrect. One possible
390 // solution is to make the base Baton class provide a method such as:
391 // virtual StringRef getBatonId() const { return ""; }
392 // and have CommandBaton override this to return something unique, and then
393 // check for it here. Another option might be to make Baton using the llvm
394 // casting infrastructure, so that we could write something like:
395 // if (llvm::isa<CommandBaton>(callback_baton_sp))
396 // at relevant callsites instead of storing a boolean.
397 m_callback_is_synchronous = callback_is_synchronous;
398 m_callback = callback;
399 m_callback_baton_sp = callback_baton_sp;
400 m_baton_is_command_baton = false;
401 m_set_flags.Set(eCallback);
402}
403
404void BreakpointOptions::SetCallback(
405 BreakpointHitCallback callback,
406 const BreakpointOptions::CommandBatonSP &callback_baton_sp,
407 bool callback_is_synchronous) {
408 m_callback_is_synchronous = callback_is_synchronous;
409 m_callback = callback;
410 m_callback_baton_sp = callback_baton_sp;
411 m_baton_is_command_baton = true;
412 m_set_flags.Set(eCallback);
413}
414
415void BreakpointOptions::ClearCallback() {
416 m_callback = nullptr;
417 m_callback_is_synchronous = false;
418 m_callback_baton_sp.reset();
419 m_baton_is_command_baton = false;
420 m_set_flags.Clear(mask: eCallback);
421}
422
423Baton *BreakpointOptions::GetBaton() { return m_callback_baton_sp.get(); }
424
425const Baton *BreakpointOptions::GetBaton() const {
426 return m_callback_baton_sp.get();
427}
428
429bool BreakpointOptions::InvokeCallback(StoppointCallbackContext *context,
430 lldb::user_id_t break_id,
431 lldb::user_id_t break_loc_id) {
432 if (m_callback) {
433 if (context->is_synchronous == IsCallbackSynchronous()) {
434 return m_callback(m_callback_baton_sp ? m_callback_baton_sp->data()
435 : nullptr,
436 context, break_id, break_loc_id);
437 }
438 if (IsCallbackSynchronous()) {
439 return false;
440 }
441 }
442 return true;
443}
444
445bool BreakpointOptions::HasCallback() const {
446 return static_cast<bool>(m_callback);
447}
448
449bool BreakpointOptions::GetCommandLineCallbacks(StringList &command_list) {
450 if (!HasCallback())
451 return false;
452 if (!m_baton_is_command_baton)
453 return false;
454
455 auto cmd_baton = std::static_pointer_cast<CommandBaton>(r: m_callback_baton_sp);
456 CommandData *data = cmd_baton->getItem();
457 if (!data)
458 return false;
459 command_list = data->user_source;
460 return true;
461}
462
463void BreakpointOptions::SetCondition(StopCondition condition) {
464 if (!condition)
465 m_set_flags.Clear(mask: eCondition);
466 else
467 m_set_flags.Set(eCondition);
468
469 m_condition = std::move(condition);
470}
471
472const StopCondition &BreakpointOptions::GetCondition() const {
473 return m_condition;
474}
475
476StopCondition &BreakpointOptions::GetCondition() { return m_condition; }
477
478const ThreadSpec *BreakpointOptions::GetThreadSpecNoCreate() const {
479 return m_thread_spec_up.get();
480}
481
482ThreadSpec *BreakpointOptions::GetThreadSpec() {
483 if (m_thread_spec_up == nullptr) {
484 m_set_flags.Set(eThreadSpec);
485 m_thread_spec_up = std::make_unique<ThreadSpec>();
486 }
487
488 return m_thread_spec_up.get();
489}
490
491void BreakpointOptions::SetThreadID(lldb::tid_t thread_id) {
492 GetThreadSpec()->SetTID(thread_id);
493 m_set_flags.Set(eThreadSpec);
494}
495
496void BreakpointOptions::SetThreadSpec(
497 std::unique_ptr<ThreadSpec> &thread_spec_up) {
498 m_thread_spec_up = std::move(thread_spec_up);
499 m_set_flags.Set(eThreadSpec);
500}
501
502void BreakpointOptions::GetDescription(Stream *s,
503 lldb::DescriptionLevel level) const {
504 // Figure out if there are any options not at their default value, and only
505 // print anything if there are:
506
507 if (m_ignore_count != 0 || !m_enabled || m_one_shot || m_auto_continue ||
508 (GetThreadSpecNoCreate() != nullptr &&
509 GetThreadSpecNoCreate()->HasSpecification())) {
510 if (level == lldb::eDescriptionLevelVerbose) {
511 s->EOL();
512 s->IndentMore();
513 s->Indent();
514 s->PutCString(cstr: "Breakpoint Options:\n");
515 s->IndentMore();
516 s->Indent();
517 } else
518 s->PutCString(cstr: " Options: ");
519
520 if (m_ignore_count > 0)
521 s->Printf(format: "ignore: %d ", m_ignore_count);
522 s->Printf(format: "%sabled ", m_enabled ? "en" : "dis");
523
524 if (m_one_shot)
525 s->Printf(format: "one-shot ");
526
527 if (m_auto_continue)
528 s->Printf(format: "auto-continue ");
529
530 if (m_thread_spec_up)
531 m_thread_spec_up->GetDescription(s, level);
532
533 if (level == lldb::eDescriptionLevelFull) {
534 s->IndentLess();
535 s->IndentMore();
536 }
537 }
538
539 if (m_callback_baton_sp.get()) {
540 if (level != eDescriptionLevelBrief) {
541 s->EOL();
542 m_callback_baton_sp->GetDescription(s&: s->AsRawOstream(), level,
543 indentation: s->GetIndentLevel());
544 }
545 }
546 if (m_condition) {
547 if (level != eDescriptionLevelBrief) {
548 s->EOL();
549 s->Printf(format: "Condition: %s\n", m_condition.GetText().data());
550 }
551 }
552}
553
554void BreakpointOptions::CommandBaton::GetDescription(
555 llvm::raw_ostream &s, lldb::DescriptionLevel level,
556 unsigned indentation) const {
557 const CommandData *data = getItem();
558
559 if (level == eDescriptionLevelBrief) {
560 s << ", commands = "
561 << ((data && data->user_source.GetSize() > 0) ? "yes" : "no");
562 return;
563 }
564
565 indentation += 2;
566 s.indent(NumSpaces: indentation);
567 s << "Breakpoint commands";
568 if (data->interpreter != eScriptLanguageNone)
569 s << llvm::formatv(Fmt: " ({0}):\n",
570 Vals: ScriptInterpreter::LanguageToString(language: data->interpreter));
571 else
572 s << ":\n";
573
574 indentation += 2;
575 if (data && data->user_source.GetSize() > 0) {
576 for (llvm::StringRef str : data->user_source) {
577 s.indent(NumSpaces: indentation);
578 s << str << "\n";
579 }
580 } else
581 s << "No commands.\n";
582}
583
584void BreakpointOptions::SetCommandDataCallback(
585 std::unique_ptr<CommandData> &cmd_data) {
586 cmd_data->interpreter = eScriptLanguageNone;
587 auto baton_sp = std::make_shared<CommandBaton>(args: std::move(cmd_data));
588 SetCallback(callback: BreakpointOptions::BreakpointOptionsCallbackFunction, callback_baton_sp: baton_sp);
589 m_set_flags.Set(eCallback);
590}
591
592bool BreakpointOptions::BreakpointOptionsCallbackFunction(
593 void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id,
594 lldb::user_id_t break_loc_id) {
595 bool ret_value = true;
596 if (baton == nullptr)
597 return true;
598
599 CommandData *data = (CommandData *)baton;
600 StringList &commands = data->user_source;
601
602 if (commands.GetSize() > 0) {
603 ExecutionContext exe_ctx(context->exe_ctx_ref);
604 Target *target = exe_ctx.GetTargetPtr();
605 if (target) {
606 Debugger &debugger = target->GetDebugger();
607 CommandReturnObject result(debugger.GetUseColor());
608
609 // Rig up the results secondary output stream to the debugger's, so the
610 // output will come out synchronously if the debugger is set up that way.
611 result.SetImmediateOutputStream(debugger.GetAsyncOutputStream());
612 result.SetImmediateErrorStream(debugger.GetAsyncErrorStream());
613
614 CommandInterpreterRunOptions options;
615 options.SetStopOnContinue(true);
616 options.SetStopOnError(data->stop_on_error);
617 options.SetEchoCommands(true);
618 options.SetPrintResults(true);
619 options.SetPrintErrors(true);
620 options.SetAddToHistory(false);
621
622 debugger.GetCommandInterpreter().HandleCommands(commands, context: exe_ctx,
623 options, result);
624 result.GetImmediateOutputStream()->Flush();
625 result.GetImmediateErrorStream()->Flush();
626 }
627 }
628 return ret_value;
629}
630
631void BreakpointOptions::Clear()
632{
633 m_set_flags.Clear();
634 m_thread_spec_up.release();
635 m_one_shot = false;
636 m_ignore_count = 0;
637 m_auto_continue = false;
638 m_callback = nullptr;
639 m_callback_baton_sp.reset();
640 m_baton_is_command_baton = false;
641 m_callback_is_synchronous = false;
642 m_enabled = false;
643 m_condition = StopCondition();
644}
645

source code of lldb/source/Breakpoint/BreakpointOptions.cpp