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(key: GetKey(enum_value: OptionNames::StopOnError),
43 value: 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: item_sp);
50 options_dict_sp->AddItem(key: GetKey(enum_value: OptionNames::UserSource), value_sp: user_source_sp);
51 }
52
53 options_dict_sp->AddStringItem(
54 key: GetKey(enum_value: OptionNames::Interpreter),
55 value: ScriptInterpreter::LanguageToString(language: 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 key: GetKey(enum_value: OptionNames::StopOnError), result&: data_up->stop_on_error);
66
67 llvm::StringRef interpreter_str;
68 ScriptLanguage interp_language;
69 success = options_dict.GetValueForKeyAsString(
70 key: GetKey(enum_value: OptionNames::Interpreter), result&: interpreter_str);
71
72 if (!success) {
73 error.SetErrorString("Missing command language value.");
74 return data_up;
75 }
76
77 interp_language = ScriptInterpreter::StringToLanguage(string: interpreter_str);
78 if (interp_language == eScriptLanguageUnknown) {
79 error.SetErrorStringWithFormatv(format: "Unknown breakpoint command language: {0}.",
80 args&: interpreter_str);
81 return data_up;
82 }
83 data_up->interpreter = interp_language;
84
85 StructuredData::Array *user_source;
86 success = options_dict.GetValueForKeyAsArray(key: GetKey(enum_value: OptionNames::UserSource),
87 result&: 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(idx: i))
93 data_up->user_source.AppendString(str: *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>(args&: *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>(args&: *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(bit: eEnabled))
173 {
174 m_enabled = incoming.m_enabled;
175 m_set_flags.Set(eEnabled);
176 }
177 if (incoming.m_set_flags.Test(bit: eOneShot))
178 {
179 m_one_shot = incoming.m_one_shot;
180 m_set_flags.Set(eOneShot);
181 }
182 if (incoming.m_set_flags.Test(bit: 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(bit: eIgnoreCount))
191 {
192 m_ignore_count = incoming.m_ignore_count;
193 m_set_flags.Set(eIgnoreCount);
194 }
195 if (incoming.m_set_flags.Test(bit: 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(mask: 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(bit: eAutoContinue))
209 {
210 m_auto_continue = incoming.m_auto_continue;
211 m_set_flags.Set(eAutoContinue);
212 }
213 if (incoming.m_set_flags.Test(bit: eThreadSpec) && incoming.m_thread_spec_up) {
214 if (!m_thread_spec_up)
215 m_thread_spec_up =
216 std::make_unique<ThreadSpec>(args&: *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(enum_value: OptionNames::EnabledState);
237 bool success;
238 if (key && options_dict.HasKey(key)) {
239 success = options_dict.GetValueForKeyAsBoolean(key, result&: 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(enum_value: OptionNames::OneShotState);
248 if (key && options_dict.HasKey(key)) {
249 success = options_dict.GetValueForKeyAsBoolean(key, result&: 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(enum_value: OptionNames::AutoContinue);
258 if (key && options_dict.HasKey(key)) {
259 success = options_dict.GetValueForKeyAsBoolean(key, result&: 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(enum_value: OptionNames::IgnoreCount);
268 if (key && options_dict.HasKey(key)) {
269 success = options_dict.GetValueForKeyAsInteger(key, result&: 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(enum_value: OptionNames::ConditionText);
278 if (key && options_dict.HasKey(key)) {
279 success = options_dict.GetValueForKeyAsString(key, result&: 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 key: CommandData::GetSerializationKey(), result&: cmds_dict);
291 if (success && cmds_dict) {
292 Status cmds_error;
293 cmd_data_up = CommandData::CreateFromStructuredData(options_dict: *cmds_dict, error&: 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 args: condition_ref.str().c_str(), args&: enabled,
304 args&: ignore_count, args&: one_shot, args&: 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(language: cmd_data_up->interpreter)
319 .c_str());
320 return nullptr;
321 }
322 Status script_error;
323 script_error =
324 interp->SetBreakpointCommandCallback(bp_options&: *bp_options, data_up&: 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 key: ThreadSpec::GetSerializationKey(), result&: thread_spec_dict);
336 if (success) {
337 Status thread_spec_error;
338 std::unique_ptr<ThreadSpec> thread_spec_up =
339 ThreadSpec::CreateFromStructuredData(data_dict: *thread_spec_dict,
340 error&: 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(bit: eEnabled))
356 options_dict_sp->AddBooleanItem(key: GetKey(enum_value: OptionNames::EnabledState),
357 value: m_enabled);
358 if (m_set_flags.Test(bit: eOneShot))
359 options_dict_sp->AddBooleanItem(key: GetKey(enum_value: OptionNames::OneShotState),
360 value: m_one_shot);
361 if (m_set_flags.Test(bit: eAutoContinue))
362 options_dict_sp->AddBooleanItem(key: GetKey(enum_value: OptionNames::AutoContinue),
363 value: m_auto_continue);
364 if (m_set_flags.Test(bit: eIgnoreCount))
365 options_dict_sp->AddIntegerItem(key: GetKey(enum_value: OptionNames::IgnoreCount),
366 value: m_ignore_count);
367 if (m_set_flags.Test(bit: eCondition))
368 options_dict_sp->AddStringItem(key: GetKey(enum_value: OptionNames::ConditionText),
369 value: m_condition_text);
370
371 if (m_set_flags.Test(bit: eCallback) && m_baton_is_command_baton) {
372 auto cmd_baton =
373 std::static_pointer_cast<CommandBaton>(r: m_callback_baton_sp);
374 StructuredData::ObjectSP commands_sp =
375 cmd_baton->getItem()->SerializeToStructuredData();
376 if (commands_sp) {
377 options_dict_sp->AddItem(
378 key: BreakpointOptions::CommandData::GetSerializationKey(), value_sp: commands_sp);
379 }
380 }
381 if (m_set_flags.Test(bit: eThreadSpec) && m_thread_spec_up) {
382 StructuredData::ObjectSP thread_spec_sp =
383 m_thread_spec_up->SerializeToStructuredData();
384 options_dict_sp->AddItem(key: ThreadSpec::GetSerializationKey(), value_sp: 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(mask: 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>(r: 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(mask: eCondition);
473 }
474 else
475 m_set_flags.Set(eCondition);
476
477 m_condition_text.assign(s: 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(cstr: "Breakpoint Options:\n");
530 s->IndentMore();
531 s->Indent();
532 } else
533 s->PutCString(cstr: " Options: ");
534
535 if (m_ignore_count > 0)
536 s->Printf(format: "ignore: %d ", m_ignore_count);
537 s->Printf(format: "%sabled ", m_enabled ? "en" : "dis");
538
539 if (m_one_shot)
540 s->Printf(format: "one-shot ");
541
542 if (m_auto_continue)
543 s->Printf(format: "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&: s->AsRawOstream(), level,
558 indentation: s->GetIndentLevel());
559 }
560 }
561 if (!m_condition_text.empty()) {
562 if (level != eDescriptionLevelBrief) {
563 s->EOL();
564 s->Printf(format: "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(NumSpaces: indentation);
582 s << "Breakpoint commands";
583 if (data->interpreter != eScriptLanguageNone)
584 s << llvm::formatv(Fmt: " ({0}):\n",
585 Vals: ScriptInterpreter::LanguageToString(language: 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(NumSpaces: 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>(args: std::move(cmd_data));
603 SetCallback(callback: BreakpointOptions::BreakpointOptionsCallbackFunction, callback_baton_sp: 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, context: 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

source code of lldb/source/Breakpoint/BreakpointOptions.cpp