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