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