xref: /freebsd/contrib/llvm-project/lldb/source/Breakpoint/BreakpointOptions.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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
SerializeToStructuredData()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>
CreateFromStructuredData(const StructuredData::Dictionary & options_dict,Status & error)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 = Status::FromErrorString("Missing command language value.");
74     return data_up;
75   }
76 
77   interp_language = ScriptInterpreter::StringToLanguage(interpreter_str);
78   if (interp_language == eScriptLanguageUnknown) {
79     error = Status::FromErrorStringWithFormatv(
80         "Unknown breakpoint command language: {0}.", 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", "EnabledState", "OneShotState",
103     "AutoContinue"};
104 
105 // BreakpointOptions constructor
BreakpointOptions(bool all_flags_set)106 BreakpointOptions::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 
BreakpointOptions(const char * condition,bool enabled,int32_t ignore,bool one_shot,bool auto_continue)115 BreakpointOptions::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
BreakpointOptions(const BreakpointOptions & rhs)129 BreakpointOptions::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>(*rhs.m_thread_spec_up);
138   m_condition = rhs.m_condition;
139 }
140 
141 // BreakpointOptions assignment operator
142 const BreakpointOptions &BreakpointOptions::
operator =(const BreakpointOptions & rhs)143 operator=(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>(*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 
CopyOverSetOptions(const BreakpointOptions & incoming)160 void BreakpointOptions::CopyOverSetOptions(const BreakpointOptions &incoming)
161 {
162   if (incoming.m_set_flags.Test(eEnabled))
163   {
164     m_enabled = incoming.m_enabled;
165     m_set_flags.Set(eEnabled);
166   }
167   if (incoming.m_set_flags.Test(eOneShot))
168   {
169     m_one_shot = incoming.m_one_shot;
170     m_set_flags.Set(eOneShot);
171   }
172   if (incoming.m_set_flags.Test(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(eIgnoreCount))
181   {
182     m_ignore_count = incoming.m_ignore_count;
183     m_set_flags.Set(eIgnoreCount);
184   }
185   if (incoming.m_set_flags.Test(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(eCondition);
191     } else {
192       m_condition = incoming.m_condition;
193       m_set_flags.Set(eCondition);
194     }
195   }
196   if (incoming.m_set_flags.Test(eAutoContinue))
197   {
198     m_auto_continue = incoming.m_auto_continue;
199     m_set_flags.Set(eAutoContinue);
200   }
201   if (incoming.m_set_flags.Test(eThreadSpec) && incoming.m_thread_spec_up) {
202     if (!m_thread_spec_up)
203       m_thread_spec_up =
204           std::make_unique<ThreadSpec>(*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
212 BreakpointOptions::~BreakpointOptions() = default;
213 
CreateFromStructuredData(Target & target,const StructuredData::Dictionary & options_dict,Status & error)214 std::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(OptionNames::EnabledState);
225   bool success;
226   if (key && options_dict.HasKey(key)) {
227     success = options_dict.GetValueForKeyAsBoolean(key, enabled);
228     if (!success) {
229       error =
230           Status::FromErrorStringWithFormat("%s key is not a boolean.", key);
231       return nullptr;
232     }
233     set_options.Set(eEnabled);
234   }
235 
236   key = GetKey(OptionNames::OneShotState);
237   if (key && options_dict.HasKey(key)) {
238     success = options_dict.GetValueForKeyAsBoolean(key, one_shot);
239     if (!success) {
240       error =
241           Status::FromErrorStringWithFormat("%s key is not a boolean.", key);
242       return nullptr;
243       }
244       set_options.Set(eOneShot);
245   }
246 
247   key = GetKey(OptionNames::AutoContinue);
248   if (key && options_dict.HasKey(key)) {
249     success = options_dict.GetValueForKeyAsBoolean(key, auto_continue);
250     if (!success) {
251       error =
252           Status::FromErrorStringWithFormat("%s key is not a boolean.", key);
253       return nullptr;
254       }
255       set_options.Set(eAutoContinue);
256   }
257 
258   key = GetKey(OptionNames::IgnoreCount);
259   if (key && options_dict.HasKey(key)) {
260     success = options_dict.GetValueForKeyAsInteger(key, ignore_count);
261     if (!success) {
262       error =
263           Status::FromErrorStringWithFormat("%s key is not an integer.", key);
264       return nullptr;
265     }
266     set_options.Set(eIgnoreCount);
267   }
268 
269   key = GetKey(OptionNames::ConditionText);
270   if (key && options_dict.HasKey(key)) {
271     success = options_dict.GetValueForKeyAsString(key, condition_ref);
272     if (!success) {
273       error =
274           Status::FromErrorStringWithFormat("%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       CommandData::GetSerializationKey(), cmds_dict);
284   if (success && cmds_dict) {
285     Status cmds_error;
286     cmd_data_up = CommandData::CreateFromStructuredData(*cmds_dict, cmds_error);
287     if (cmds_error.Fail()) {
288       error = Status::FromErrorStringWithFormat(
289           "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       condition_ref.str().c_str(), enabled, ignore_count, one_shot,
297       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             "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             "Current script language doesn't match breakpoint's language: %s",
311             ScriptInterpreter::LanguageToString(cmd_data_up->interpreter)
312                 .c_str());
313         return nullptr;
314       }
315       Status script_error;
316       script_error =
317           interp->SetBreakpointCommandCallback(*bp_options, cmd_data_up);
318       if (script_error.Fail()) {
319         error = Status::FromErrorStringWithFormat(
320             "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       ThreadSpec::GetSerializationKey(), thread_spec_dict);
329   if (success) {
330     Status thread_spec_error;
331     std::unique_ptr<ThreadSpec> thread_spec_up =
332         ThreadSpec::CreateFromStructuredData(*thread_spec_dict,
333                                              thread_spec_error);
334     if (thread_spec_error.Fail()) {
335       error = Status::FromErrorStringWithFormat(
336           "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 
SerializeToStructuredData()345 StructuredData::ObjectSP BreakpointOptions::SerializeToStructuredData() {
346   StructuredData::DictionarySP options_dict_sp(
347       new StructuredData::Dictionary());
348   if (m_set_flags.Test(eEnabled))
349     options_dict_sp->AddBooleanItem(GetKey(OptionNames::EnabledState),
350                                     m_enabled);
351   if (m_set_flags.Test(eOneShot))
352     options_dict_sp->AddBooleanItem(GetKey(OptionNames::OneShotState),
353                                m_one_shot);
354   if (m_set_flags.Test(eAutoContinue))
355     options_dict_sp->AddBooleanItem(GetKey(OptionNames::AutoContinue),
356                                m_auto_continue);
357   if (m_set_flags.Test(eIgnoreCount))
358     options_dict_sp->AddIntegerItem(GetKey(OptionNames::IgnoreCount),
359                                     m_ignore_count);
360   if (m_set_flags.Test(eCondition))
361     options_dict_sp->AddStringItem(GetKey(OptionNames::ConditionText),
362                                    m_condition.GetText());
363 
364   if (m_set_flags.Test(eCallback) && m_baton_is_command_baton) {
365     auto cmd_baton =
366         std::static_pointer_cast<CommandBaton>(m_callback_baton_sp);
367     StructuredData::ObjectSP commands_sp =
368         cmd_baton->getItem()->SerializeToStructuredData();
369     if (commands_sp) {
370       options_dict_sp->AddItem(
371           BreakpointOptions::CommandData::GetSerializationKey(), commands_sp);
372     }
373   }
374   if (m_set_flags.Test(eThreadSpec) && m_thread_spec_up) {
375     StructuredData::ObjectSP thread_spec_sp =
376         m_thread_spec_up->SerializeToStructuredData();
377     options_dict_sp->AddItem(ThreadSpec::GetSerializationKey(), thread_spec_sp);
378   }
379 
380   return options_dict_sp;
381 }
382 
383 // Callbacks
SetCallback(BreakpointHitCallback callback,const lldb::BatonSP & callback_baton_sp,bool callback_is_synchronous)384 void 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 
SetCallback(BreakpointHitCallback callback,const BreakpointOptions::CommandBatonSP & callback_baton_sp,bool callback_is_synchronous)404 void 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 
ClearCallback()415 void 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(eCallback);
421 }
422 
GetBaton()423 Baton *BreakpointOptions::GetBaton() { return m_callback_baton_sp.get(); }
424 
GetBaton() const425 const Baton *BreakpointOptions::GetBaton() const {
426   return m_callback_baton_sp.get();
427 }
428 
InvokeCallback(StoppointCallbackContext * context,lldb::user_id_t break_id,lldb::user_id_t break_loc_id)429 bool 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 
HasCallback() const445 bool BreakpointOptions::HasCallback() const {
446   return static_cast<bool>(m_callback);
447 }
448 
GetCommandLineCallbacks(StringList & command_list)449 bool 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>(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 
SetCondition(StopCondition condition)463 void BreakpointOptions::SetCondition(StopCondition condition) {
464   if (!condition)
465     m_set_flags.Clear(eCondition);
466   else
467     m_set_flags.Set(eCondition);
468 
469   m_condition = std::move(condition);
470 }
471 
GetCondition() const472 const StopCondition &BreakpointOptions::GetCondition() const {
473   return m_condition;
474 }
475 
GetCondition()476 StopCondition &BreakpointOptions::GetCondition() { return m_condition; }
477 
GetThreadSpecNoCreate() const478 const ThreadSpec *BreakpointOptions::GetThreadSpecNoCreate() const {
479   return m_thread_spec_up.get();
480 }
481 
GetThreadSpec()482 ThreadSpec *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 
SetThreadID(lldb::tid_t thread_id)491 void BreakpointOptions::SetThreadID(lldb::tid_t thread_id) {
492   GetThreadSpec()->SetTID(thread_id);
493   m_set_flags.Set(eThreadSpec);
494 }
495 
SetThreadSpec(std::unique_ptr<ThreadSpec> & thread_spec_up)496 void 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 
GetDescription(Stream * s,lldb::DescriptionLevel level) const502 void 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("Breakpoint Options:\n");
515       s->IndentMore();
516       s->Indent();
517     } else
518       s->PutCString(" Options: ");
519 
520     if (m_ignore_count > 0)
521       s->Printf("ignore: %d ", m_ignore_count);
522     s->Printf("%sabled ", m_enabled ? "en" : "dis");
523 
524     if (m_one_shot)
525       s->Printf("one-shot ");
526 
527     if (m_auto_continue)
528       s->Printf("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->AsRawOstream(), level,
543                                           s->GetIndentLevel());
544     }
545   }
546   if (m_condition) {
547     if (level != eDescriptionLevelBrief) {
548       s->EOL();
549       s->Printf("Condition: %s\n", m_condition.GetText().data());
550     }
551   }
552 }
553 
GetDescription(llvm::raw_ostream & s,lldb::DescriptionLevel level,unsigned indentation) const554 void 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(indentation);
567   s << "Breakpoint commands";
568   if (data->interpreter != eScriptLanguageNone)
569     s << llvm::formatv(" ({0}):\n",
570                        ScriptInterpreter::LanguageToString(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(indentation);
578       s << str << "\n";
579     }
580   } else
581     s << "No commands.\n";
582 }
583 
SetCommandDataCallback(std::unique_ptr<CommandData> & cmd_data)584 void BreakpointOptions::SetCommandDataCallback(
585     std::unique_ptr<CommandData> &cmd_data) {
586   cmd_data->interpreter = eScriptLanguageNone;
587   auto baton_sp = std::make_shared<CommandBaton>(std::move(cmd_data));
588   SetCallback(BreakpointOptions::BreakpointOptionsCallbackFunction, baton_sp);
589   m_set_flags.Set(eCallback);
590 }
591 
BreakpointOptionsCallbackFunction(void * baton,StoppointCallbackContext * context,lldb::user_id_t break_id,lldb::user_id_t break_loc_id)592 bool 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, exe_ctx,
623                                                       options, result);
624       result.GetImmediateOutputStream()->Flush();
625       result.GetImmediateErrorStream()->Flush();
626     }
627   }
628   return ret_value;
629 }
630 
Clear()631 void 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