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

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

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