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