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