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
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
100const char *BreakpointOptions::g_option_names[(
101    size_t)BreakpointOptions::OptionNames::LastOptionName]{
102    "ConditionText", "IgnoreCount",
103    "EnabledState", "OneShotState", "AutoContinue"};
104
105bool 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
113BreakpointOptions::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
123BreakpointOptions::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
137BreakpointOptions::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
151const BreakpointOptions &BreakpointOptions::
152operator=(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
170void 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
224BreakpointOptions::~BreakpointOptions() = default;
225
226std::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
352StructuredData::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
391void 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
411void 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
422void 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
430Baton *BreakpointOptions::GetBaton() { return m_callback_baton_sp.get(); }
431
432const Baton *BreakpointOptions::GetBaton() const {
433  return m_callback_baton_sp.get();
434}
435
436bool 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
451bool BreakpointOptions::HasCallback() const {
452  return m_callback != BreakpointOptions::NullCallback;
453}
454
455bool 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
469void 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
482const 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
493const ThreadSpec *BreakpointOptions::GetThreadSpecNoCreate() const {
494  return m_thread_spec_up.get();
495}
496
497ThreadSpec *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
506void BreakpointOptions::SetThreadID(lldb::tid_t thread_id) {
507  GetThreadSpec()->SetTID(thread_id);
508  m_set_flags.Set(eThreadSpec);
509}
510
511void 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
517void 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
569void 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
599void 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
607bool 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
648void 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