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