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