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