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 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 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 = Status::FromErrorString("Missing command language value."); 74 return data_up; 75 } 76 77 interp_language = ScriptInterpreter::StringToLanguage(interpreter_str); 78 if (interp_language == eScriptLanguageUnknown) { 79 error = Status::FromErrorStringWithFormatv( 80 "Unknown breakpoint command language: {0}.", 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 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 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 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:: 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 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 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 = 234 Status::FromErrorStringWithFormat("%s key is not a boolean.", key); 235 return nullptr; 236 } 237 set_options.Set(eEnabled); 238 } 239 240 key = GetKey(OptionNames::OneShotState); 241 if (key && options_dict.HasKey(key)) { 242 success = options_dict.GetValueForKeyAsBoolean(key, one_shot); 243 if (!success) { 244 error = 245 Status::FromErrorStringWithFormat("%s key is not a boolean.", key); 246 return nullptr; 247 } 248 set_options.Set(eOneShot); 249 } 250 251 key = GetKey(OptionNames::AutoContinue); 252 if (key && options_dict.HasKey(key)) { 253 success = options_dict.GetValueForKeyAsBoolean(key, auto_continue); 254 if (!success) { 255 error = 256 Status::FromErrorStringWithFormat("%s key is not a boolean.", key); 257 return nullptr; 258 } 259 set_options.Set(eAutoContinue); 260 } 261 262 key = GetKey(OptionNames::IgnoreCount); 263 if (key && options_dict.HasKey(key)) { 264 success = options_dict.GetValueForKeyAsInteger(key, ignore_count); 265 if (!success) { 266 error = 267 Status::FromErrorStringWithFormat("%s key is not an integer.", key); 268 return nullptr; 269 } 270 set_options.Set(eIgnoreCount); 271 } 272 273 key = GetKey(OptionNames::ConditionText); 274 if (key && options_dict.HasKey(key)) { 275 success = options_dict.GetValueForKeyAsString(key, condition_ref); 276 if (!success) { 277 error = 278 Status::FromErrorStringWithFormat("%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 CommandData::GetSerializationKey(), cmds_dict); 288 if (success && cmds_dict) { 289 Status cmds_error; 290 cmd_data_up = CommandData::CreateFromStructuredData(*cmds_dict, cmds_error); 291 if (cmds_error.Fail()) { 292 error = Status::FromErrorStringWithFormat( 293 "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 condition_ref.str().c_str(), enabled, 301 ignore_count, one_shot, 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 "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 "Current script language doesn't match breakpoint's language: %s", 315 ScriptInterpreter::LanguageToString(cmd_data_up->interpreter) 316 .c_str()); 317 return nullptr; 318 } 319 Status script_error; 320 script_error = 321 interp->SetBreakpointCommandCallback(*bp_options, cmd_data_up); 322 if (script_error.Fail()) { 323 error = Status::FromErrorStringWithFormat( 324 "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 ThreadSpec::GetSerializationKey(), thread_spec_dict); 333 if (success) { 334 Status thread_spec_error; 335 std::unique_ptr<ThreadSpec> thread_spec_up = 336 ThreadSpec::CreateFromStructuredData(*thread_spec_dict, 337 thread_spec_error); 338 if (thread_spec_error.Fail()) { 339 error = Status::FromErrorStringWithFormat( 340 "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 349 StructuredData::ObjectSP BreakpointOptions::SerializeToStructuredData() { 350 StructuredData::DictionarySP options_dict_sp( 351 new StructuredData::Dictionary()); 352 if (m_set_flags.Test(eEnabled)) 353 options_dict_sp->AddBooleanItem(GetKey(OptionNames::EnabledState), 354 m_enabled); 355 if (m_set_flags.Test(eOneShot)) 356 options_dict_sp->AddBooleanItem(GetKey(OptionNames::OneShotState), 357 m_one_shot); 358 if (m_set_flags.Test(eAutoContinue)) 359 options_dict_sp->AddBooleanItem(GetKey(OptionNames::AutoContinue), 360 m_auto_continue); 361 if (m_set_flags.Test(eIgnoreCount)) 362 options_dict_sp->AddIntegerItem(GetKey(OptionNames::IgnoreCount), 363 m_ignore_count); 364 if (m_set_flags.Test(eCondition)) 365 options_dict_sp->AddStringItem(GetKey(OptionNames::ConditionText), 366 m_condition_text); 367 368 if (m_set_flags.Test(eCallback) && m_baton_is_command_baton) { 369 auto cmd_baton = 370 std::static_pointer_cast<CommandBaton>(m_callback_baton_sp); 371 StructuredData::ObjectSP commands_sp = 372 cmd_baton->getItem()->SerializeToStructuredData(); 373 if (commands_sp) { 374 options_dict_sp->AddItem( 375 BreakpointOptions::CommandData::GetSerializationKey(), commands_sp); 376 } 377 } 378 if (m_set_flags.Test(eThreadSpec) && m_thread_spec_up) { 379 StructuredData::ObjectSP thread_spec_sp = 380 m_thread_spec_up->SerializeToStructuredData(); 381 options_dict_sp->AddItem(ThreadSpec::GetSerializationKey(), thread_spec_sp); 382 } 383 384 return options_dict_sp; 385 } 386 387 // Callbacks 388 void 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 408 void 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 419 void 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(eCallback); 425 } 426 427 Baton *BreakpointOptions::GetBaton() { return m_callback_baton_sp.get(); } 428 429 const Baton *BreakpointOptions::GetBaton() const { 430 return m_callback_baton_sp.get(); 431 } 432 433 bool 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 448 bool BreakpointOptions::HasCallback() const { 449 return static_cast<bool>(m_callback); 450 } 451 452 bool 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>(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 466 void BreakpointOptions::SetCondition(const char *condition) { 467 if (!condition || condition[0] == '\0') { 468 condition = ""; 469 m_set_flags.Clear(eCondition); 470 } 471 else 472 m_set_flags.Set(eCondition); 473 474 m_condition_text.assign(condition); 475 std::hash<std::string> hasher; 476 m_condition_text_hash = hasher(m_condition_text); 477 } 478 479 const 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 490 const ThreadSpec *BreakpointOptions::GetThreadSpecNoCreate() const { 491 return m_thread_spec_up.get(); 492 } 493 494 ThreadSpec *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 503 void BreakpointOptions::SetThreadID(lldb::tid_t thread_id) { 504 GetThreadSpec()->SetTID(thread_id); 505 m_set_flags.Set(eThreadSpec); 506 } 507 508 void 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 514 void 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("Breakpoint Options:\n"); 527 s->IndentMore(); 528 s->Indent(); 529 } else 530 s->PutCString(" Options: "); 531 532 if (m_ignore_count > 0) 533 s->Printf("ignore: %d ", m_ignore_count); 534 s->Printf("%sabled ", m_enabled ? "en" : "dis"); 535 536 if (m_one_shot) 537 s->Printf("one-shot "); 538 539 if (m_auto_continue) 540 s->Printf("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->AsRawOstream(), level, 555 s->GetIndentLevel()); 556 } 557 } 558 if (!m_condition_text.empty()) { 559 if (level != eDescriptionLevelBrief) { 560 s->EOL(); 561 s->Printf("Condition: %s\n", m_condition_text.c_str()); 562 } 563 } 564 } 565 566 void 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(indentation); 579 s << "Breakpoint commands"; 580 if (data->interpreter != eScriptLanguageNone) 581 s << llvm::formatv(" ({0}):\n", 582 ScriptInterpreter::LanguageToString(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(indentation); 590 s << str << "\n"; 591 } 592 } else 593 s << "No commands.\n"; 594 } 595 596 void BreakpointOptions::SetCommandDataCallback( 597 std::unique_ptr<CommandData> &cmd_data) { 598 cmd_data->interpreter = eScriptLanguageNone; 599 auto baton_sp = std::make_shared<CommandBaton>(std::move(cmd_data)); 600 SetCallback(BreakpointOptions::BreakpointOptionsCallbackFunction, baton_sp); 601 m_set_flags.Set(eCallback); 602 } 603 604 bool 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 StreamSP output_stream(debugger.GetAsyncOutputStream()); 624 StreamSP error_stream(debugger.GetAsyncErrorStream()); 625 result.SetImmediateOutputStream(output_stream); 626 result.SetImmediateErrorStream(error_stream); 627 628 CommandInterpreterRunOptions options; 629 options.SetStopOnContinue(true); 630 options.SetStopOnError(data->stop_on_error); 631 options.SetEchoCommands(true); 632 options.SetPrintResults(true); 633 options.SetPrintErrors(true); 634 options.SetAddToHistory(false); 635 636 debugger.GetCommandInterpreter().HandleCommands(commands, exe_ctx, 637 options, result); 638 result.GetImmediateOutputStream()->Flush(); 639 result.GetImmediateErrorStream()->Flush(); 640 } 641 } 642 return ret_value; 643 } 644 645 void BreakpointOptions::Clear() 646 { 647 m_set_flags.Clear(); 648 m_thread_spec_up.release(); 649 m_one_shot = false; 650 m_ignore_count = 0; 651 m_auto_continue = false; 652 m_callback = nullptr; 653 m_callback_baton_sp.reset(); 654 m_baton_is_command_baton = false; 655 m_callback_is_synchronous = false; 656 m_enabled = false; 657 m_condition_text.clear(); 658 } 659