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