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(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 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 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 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 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>(*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>(*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(eEnabled)) 173 { 174 m_enabled = incoming.m_enabled; 175 m_set_flags.Set(eEnabled); 176 } 177 if (incoming.m_set_flags.Test(eOneShot)) 178 { 179 m_one_shot = incoming.m_one_shot; 180 m_set_flags.Set(eOneShot); 181 } 182 if (incoming.m_set_flags.Test(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(eIgnoreCount)) 191 { 192 m_ignore_count = incoming.m_ignore_count; 193 m_set_flags.Set(eIgnoreCount); 194 } 195 if (incoming.m_set_flags.Test(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(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(eAutoContinue)) 209 { 210 m_auto_continue = incoming.m_auto_continue; 211 m_set_flags.Set(eAutoContinue); 212 } 213 if (incoming.m_set_flags.Test(eThreadSpec) && incoming.m_thread_spec_up) { 214 if (!m_thread_spec_up) 215 m_thread_spec_up = 216 std::make_unique<ThreadSpec>(*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(OptionNames::EnabledState); 237 bool success; 238 if (key && options_dict.HasKey(key)) { 239 success = options_dict.GetValueForKeyAsBoolean(key, 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(OptionNames::OneShotState); 248 if (key && options_dict.HasKey(key)) { 249 success = options_dict.GetValueForKeyAsBoolean(key, 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(OptionNames::AutoContinue); 258 if (key && options_dict.HasKey(key)) { 259 success = options_dict.GetValueForKeyAsBoolean(key, 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(OptionNames::IgnoreCount); 268 if (key && options_dict.HasKey(key)) { 269 success = options_dict.GetValueForKeyAsInteger(key, 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(OptionNames::ConditionText); 278 if (key && options_dict.HasKey(key)) { 279 success = options_dict.GetValueForKeyAsString(key, 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 CommandData::GetSerializationKey(), cmds_dict); 291 if (success && cmds_dict) { 292 Status cmds_error; 293 cmd_data_up = CommandData::CreateFromStructuredData(*cmds_dict, 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 condition_ref.str().c_str(), enabled, 304 ignore_count, one_shot, 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(cmd_data_up->interpreter) 319 .c_str()); 320 return nullptr; 321 } 322 Status script_error; 323 script_error = 324 interp->SetBreakpointCommandCallback(*bp_options, 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 ThreadSpec::GetSerializationKey(), thread_spec_dict); 336 if (success) { 337 Status thread_spec_error; 338 std::unique_ptr<ThreadSpec> thread_spec_up = 339 ThreadSpec::CreateFromStructuredData(*thread_spec_dict, 340 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(eEnabled)) 356 options_dict_sp->AddBooleanItem(GetKey(OptionNames::EnabledState), 357 m_enabled); 358 if (m_set_flags.Test(eOneShot)) 359 options_dict_sp->AddBooleanItem(GetKey(OptionNames::OneShotState), 360 m_one_shot); 361 if (m_set_flags.Test(eAutoContinue)) 362 options_dict_sp->AddBooleanItem(GetKey(OptionNames::AutoContinue), 363 m_auto_continue); 364 if (m_set_flags.Test(eIgnoreCount)) 365 options_dict_sp->AddIntegerItem(GetKey(OptionNames::IgnoreCount), 366 m_ignore_count); 367 if (m_set_flags.Test(eCondition)) 368 options_dict_sp->AddStringItem(GetKey(OptionNames::ConditionText), 369 m_condition_text); 370 371 if (m_set_flags.Test(eCallback) && m_baton_is_command_baton) { 372 auto cmd_baton = 373 std::static_pointer_cast<CommandBaton>(m_callback_baton_sp); 374 StructuredData::ObjectSP commands_sp = 375 cmd_baton->getItem()->SerializeToStructuredData(); 376 if (commands_sp) { 377 options_dict_sp->AddItem( 378 BreakpointOptions::CommandData::GetSerializationKey(), commands_sp); 379 } 380 } 381 if (m_set_flags.Test(eThreadSpec) && m_thread_spec_up) { 382 StructuredData::ObjectSP thread_spec_sp = 383 m_thread_spec_up->SerializeToStructuredData(); 384 options_dict_sp->AddItem(ThreadSpec::GetSerializationKey(), 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(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>(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(eCondition); 473 } 474 else 475 m_set_flags.Set(eCondition); 476 477 m_condition_text.assign(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("Breakpoint Options:\n"); 530 s->IndentMore(); 531 s->Indent(); 532 } else 533 s->PutCString(" Options: "); 534 535 if (m_ignore_count > 0) 536 s->Printf("ignore: %d ", m_ignore_count); 537 s->Printf("%sabled ", m_enabled ? "en" : "dis"); 538 539 if (m_one_shot) 540 s->Printf("one-shot "); 541 542 if (m_auto_continue) 543 s->Printf("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->AsRawOstream(), level, 558 s->GetIndentLevel()); 559 } 560 } 561 if (!m_condition_text.empty()) { 562 if (level != eDescriptionLevelBrief) { 563 s->EOL(); 564 s->Printf("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(indentation); 582 s << "Breakpoint commands"; 583 if (data->interpreter != eScriptLanguageNone) 584 s << llvm::formatv(" ({0}):\n", 585 ScriptInterpreter::LanguageToString(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(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>(std::move(cmd_data)); 603 SetCallback(BreakpointOptions::BreakpointOptionsCallbackFunction, 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, 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