diff options
Diffstat (limited to 'lldb/source')
-rw-r--r-- | lldb/source/API/SBBreakpoint.cpp | 19 | ||||
-rw-r--r-- | lldb/source/API/SBBreakpointLocation.cpp | 19 | ||||
-rw-r--r-- | lldb/source/Breakpoint/Breakpoint.cpp | 8 | ||||
-rw-r--r-- | lldb/source/Breakpoint/BreakpointLocation.cpp | 13 | ||||
-rw-r--r-- | lldb/source/Breakpoint/BreakpointOptions.cpp | 38 | ||||
-rw-r--r-- | lldb/source/Commands/CommandObjectBreakpoint.cpp | 53 | ||||
-rw-r--r-- | lldb/source/Target/StopInfo.cpp | 43 |
7 files changed, 173 insertions, 20 deletions
diff --git a/lldb/source/API/SBBreakpoint.cpp b/lldb/source/API/SBBreakpoint.cpp index bf9603248d7..c7d6d6c5b18 100644 --- a/lldb/source/API/SBBreakpoint.cpp +++ b/lldb/source/API/SBBreakpoint.cpp @@ -264,6 +264,25 @@ const char *SBBreakpoint::GetCondition() { return nullptr; } +void SBBreakpoint::SetAutoContinue(bool auto_continue) { + BreakpointSP bkpt_sp = GetSP(); + if (bkpt_sp) { + std::lock_guard<std::recursive_mutex> guard( + bkpt_sp->GetTarget().GetAPIMutex()); + bkpt_sp->SetAutoContinue(auto_continue); + } +} + +bool SBBreakpoint::GetAutoContinue() { + BreakpointSP bkpt_sp = GetSP(); + if (bkpt_sp) { + std::lock_guard<std::recursive_mutex> guard( + bkpt_sp->GetTarget().GetAPIMutex()); + return bkpt_sp->IsAutoContinue(); + } + return nullptr; +} + uint32_t SBBreakpoint::GetHitCount() const { uint32_t count = 0; BreakpointSP bkpt_sp = GetSP(); diff --git a/lldb/source/API/SBBreakpointLocation.cpp b/lldb/source/API/SBBreakpointLocation.cpp index f5e0b91483e..2678e1ea758 100644 --- a/lldb/source/API/SBBreakpointLocation.cpp +++ b/lldb/source/API/SBBreakpointLocation.cpp @@ -149,6 +149,25 @@ const char *SBBreakpointLocation::GetCondition() { return NULL; } +void SBBreakpointLocation::SetAutoContinue(bool auto_continue) { + BreakpointLocationSP loc_sp = GetSP(); + if (loc_sp) { + std::lock_guard<std::recursive_mutex> guard( + loc_sp->GetTarget().GetAPIMutex()); + loc_sp->SetAutoContinue(auto_continue); + } +} + +bool SBBreakpointLocation::GetAutoContinue() { + BreakpointLocationSP loc_sp = GetSP(); + if (loc_sp) { + std::lock_guard<std::recursive_mutex> guard( + loc_sp->GetTarget().GetAPIMutex()); + return loc_sp->IsAutoContinue(); + } + return NULL; +} + void SBBreakpointLocation::SetScriptCallbackFunction( const char *callback_function_name) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); diff --git a/lldb/source/Breakpoint/Breakpoint.cpp b/lldb/source/Breakpoint/Breakpoint.cpp index 043e5e8f591..fd606aa83d6 100644 --- a/lldb/source/Breakpoint/Breakpoint.cpp +++ b/lldb/source/Breakpoint/Breakpoint.cpp @@ -348,6 +348,14 @@ void Breakpoint::SetOneShot(bool one_shot) { m_options_up->SetOneShot(one_shot); } +bool Breakpoint::IsAutoContinue() const { + return m_options_up->IsAutoContinue(); +} + +void Breakpoint::SetAutoContinue(bool auto_continue) { + m_options_up->SetAutoContinue(auto_continue); +} + void Breakpoint::SetThreadID(lldb::tid_t thread_id) { if (m_options_up->GetThreadSpec()->GetTID() == thread_id) return; diff --git a/lldb/source/Breakpoint/BreakpointLocation.cpp b/lldb/source/Breakpoint/BreakpointLocation.cpp index 15865be3f9a..f59c334fe5c 100644 --- a/lldb/source/Breakpoint/BreakpointLocation.cpp +++ b/lldb/source/Breakpoint/BreakpointLocation.cpp @@ -93,6 +93,19 @@ void BreakpointLocation::SetEnabled(bool enabled) { : eBreakpointEventTypeDisabled); } +bool BreakpointLocation::IsAutoContinue() const { + if (m_options_ap + && m_options_ap->IsOptionSet(BreakpointOptions::eAutoContinue)) + return m_options_ap->IsAutoContinue(); + else + return m_owner.IsAutoContinue(); +} + +void BreakpointLocation::SetAutoContinue(bool auto_continue) { + GetLocationOptions()->SetAutoContinue(auto_continue); + SendBreakpointLocationChangedEvent(eBreakpointEventTypeAutoContinueChanged); +} + void BreakpointLocation::SetThreadID(lldb::tid_t thread_id) { if (thread_id != LLDB_INVALID_THREAD_ID) GetLocationOptions()->SetThreadID(thread_id); diff --git a/lldb/source/Breakpoint/BreakpointOptions.cpp b/lldb/source/Breakpoint/BreakpointOptions.cpp index 3e8d3dd41f3..7159688102d 100644 --- a/lldb/source/Breakpoint/BreakpointOptions.cpp +++ b/lldb/source/Breakpoint/BreakpointOptions.cpp @@ -114,7 +114,8 @@ BreakpointOptions::CommandData::CreateFromStructuredData( const char *BreakpointOptions::g_option_names[( size_t)BreakpointOptions::OptionNames::LastOptionName]{ - "ConditionText", "IgnoreCount", "EnabledState", "OneShotState"}; + "ConditionText", "IgnoreCount", + "EnabledState", "OneShotState", "AutoContinue"}; bool BreakpointOptions::NullCallback(void *baton, StoppointCallbackContext *context, @@ -130,20 +131,22 @@ BreakpointOptions::BreakpointOptions(bool all_flags_set) : m_callback(BreakpointOptions::NullCallback), m_callback_baton_sp(), m_baton_is_command_baton(false), m_callback_is_synchronous(false), m_enabled(true), m_one_shot(false), m_ignore_count(0), m_thread_spec_ap(), - m_condition_text(), m_condition_text_hash(0), + m_condition_text(), m_condition_text_hash(0), m_auto_continue(false), m_set_flags() { if (all_flags_set) m_set_flags.Set(~((Flags::ValueType) 0)); } BreakpointOptions::BreakpointOptions(const char *condition, bool enabled, - int32_t ignore, bool one_shot) + int32_t ignore, bool one_shot, + bool auto_continue) : m_callback(nullptr), m_baton_is_command_baton(false), m_callback_is_synchronous(false), m_enabled(enabled), m_one_shot(one_shot), m_ignore_count(ignore), m_condition_text(condition), - m_condition_text_hash(0) + m_condition_text_hash(0), m_auto_continue(auto_continue) { - m_set_flags.Set(eEnabled | eIgnoreCount | eOneShot | eCondition); + m_set_flags.Set(eEnabled | eIgnoreCount | eOneShot + | eCondition | eAutoContinue); } //---------------------------------------------------------------------- @@ -155,6 +158,7 @@ BreakpointOptions::BreakpointOptions(const BreakpointOptions &rhs) m_callback_is_synchronous(rhs.m_callback_is_synchronous), m_enabled(rhs.m_enabled), m_one_shot(rhs.m_one_shot), m_ignore_count(rhs.m_ignore_count), m_thread_spec_ap(), + m_auto_continue(rhs.m_auto_continue), m_set_flags(rhs.m_set_flags) { if (rhs.m_thread_spec_ap.get() != nullptr) m_thread_spec_ap.reset(new ThreadSpec(*rhs.m_thread_spec_ap.get())); @@ -178,6 +182,7 @@ operator=(const BreakpointOptions &rhs) { m_thread_spec_ap.reset(new ThreadSpec(*rhs.m_thread_spec_ap.get())); m_condition_text = rhs.m_condition_text; m_condition_text_hash = rhs.m_condition_text_hash; + m_auto_continue = rhs.m_auto_continue; m_set_flags = rhs.m_set_flags; return *this; } @@ -192,6 +197,7 @@ std::unique_ptr<BreakpointOptions> BreakpointOptions::CreateFromStructuredData( Status &error) { bool enabled = true; bool one_shot = false; + bool auto_continue = false; int32_t ignore_count = 0; llvm::StringRef condition_ref(""); Flags set_options; @@ -219,6 +225,17 @@ std::unique_ptr<BreakpointOptions> BreakpointOptions::CreateFromStructuredData( set_options.Set(eOneShot); } + key = GetKey(OptionNames::AutoContinue); + if (key) { + success = options_dict.GetValueForKeyAsBoolean(key, auto_continue); + if (!success) { + error.SetErrorStringWithFormat("%s key is not a boolean.", + GetKey(OptionNames::AutoContinue)); + return nullptr; + } + set_options.Set(eAutoContinue); + } + key = GetKey(OptionNames::IgnoreCount); if (key) { success = options_dict.GetValueForKeyAsInteger(key, ignore_count); @@ -257,7 +274,8 @@ std::unique_ptr<BreakpointOptions> BreakpointOptions::CreateFromStructuredData( } auto bp_options = llvm::make_unique<BreakpointOptions>( - condition_ref.str().c_str(), enabled, ignore_count, one_shot); + condition_ref.str().c_str(), enabled, + ignore_count, one_shot, auto_continue); if (cmd_data_up.get()) { if (cmd_data_up->interpreter == eScriptLanguageNone) bp_options->SetCommandDataCallback(cmd_data_up); @@ -315,6 +333,9 @@ StructuredData::ObjectSP BreakpointOptions::SerializeToStructuredData() { if (m_set_flags.Set(eOneShot)) options_dict_sp->AddBooleanItem(GetKey(OptionNames::OneShotState), m_one_shot); + if (m_set_flags.Set(eAutoContinue)) + options_dict_sp->AddBooleanItem(GetKey(OptionNames::AutoContinue), + m_auto_continue); if (m_set_flags.Set(eIgnoreCount)) options_dict_sp->AddIntegerItem(GetKey(OptionNames::IgnoreCount), m_ignore_count); @@ -471,7 +492,7 @@ void BreakpointOptions::GetDescription(Stream *s, // print // anything if there are: - if (m_ignore_count != 0 || !m_enabled || m_one_shot || + if (m_ignore_count != 0 || !m_enabled || m_one_shot || m_auto_continue || (GetThreadSpecNoCreate() != nullptr && GetThreadSpecNoCreate()->HasSpecification())) { if (level == lldb::eDescriptionLevelVerbose) { @@ -491,6 +512,9 @@ void BreakpointOptions::GetDescription(Stream *s, if (m_one_shot) s->Printf("one-shot "); + if (m_auto_continue) + s->Printf("auto-continue "); + if (m_thread_spec_ap.get()) m_thread_spec_ap->GetDescription(s, level); diff --git a/lldb/source/Commands/CommandObjectBreakpoint.cpp b/lldb/source/Commands/CommandObjectBreakpoint.cpp index 266864d1a1f..d53e681514d 100644 --- a/lldb/source/Commands/CommandObjectBreakpoint.cpp +++ b/lldb/source/Commands/CommandObjectBreakpoint.cpp @@ -60,7 +60,9 @@ static OptionDefinition g_breakpoint_set_options[] = { "multiple times to specify multiple shared libraries." }, { LLDB_OPT_SET_ALL, false, "ignore-count", 'i', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCount, "Set the number of times this breakpoint is skipped before stopping." }, { LLDB_OPT_SET_ALL, false, "one-shot", 'o', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "The breakpoint is deleted the first time it causes a stop." }, + { LLDB_OPT_SET_ALL, false, "auto-continue", 'G', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "The breakpoint will auto-continue after running its commands." }, { LLDB_OPT_SET_ALL, false, "condition", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeExpression, "The breakpoint stops only if this condition expression evaluates to true." }, + { LLDB_OPT_SET_ALL, false, "command", 'd', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCommand, "A command to run when the breakpoint is hit, can be provided more than once, the commands will get run in order left to right." }, { LLDB_OPT_SET_ALL, false, "thread-index", 'x', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeThreadIndex, "The breakpoint stops only for the thread whose indeX matches this argument." }, { LLDB_OPT_SET_ALL, false, "thread-id", 't', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeThreadID, "The breakpoint stops only for the thread whose TID matches this argument." }, { LLDB_OPT_SET_ALL, false, "thread-name", 'T', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeThreadName, "The breakpoint stops only for the thread whose thread name matches this " @@ -208,6 +210,10 @@ public: m_condition.assign(option_arg); break; + case 'd': + m_commands.push_back(option_arg); + break; + case 'D': m_use_dummy = true; break; @@ -255,6 +261,15 @@ public: m_func_names.push_back(option_arg); m_func_name_type_mask |= eFunctionNameTypeFull; break; + + case 'G' : { + bool success; + m_auto_continue = Args::StringToBoolean(option_arg, true, &success); + if (!success) + error.SetErrorStringWithFormat( + "Invalid boolean value for auto-continue option: '%s'", + option_arg.str().c_str()); + } break; case 'h': { bool success; @@ -445,6 +460,8 @@ public: m_exception_extra_args.Clear(); m_move_to_nearest_code = eLazyBoolCalculate; m_source_regex_func_names.clear(); + m_commands.clear(); + m_auto_continue = false; } llvm::ArrayRef<OptionDefinition> GetDefinitions() override { @@ -482,6 +499,8 @@ public: Args m_exception_extra_args; LazyBool m_move_to_nearest_code; std::unordered_set<std::string> m_source_regex_func_names; + std::vector<std::string> m_commands; + bool m_auto_continue; }; protected: @@ -719,6 +738,18 @@ protected: } bp->SetOneShot(m_options.m_one_shot); + bp->SetAutoContinue(m_options.m_auto_continue); + + if (!m_options.m_commands.empty()) + { + auto cmd_data = llvm::make_unique<BreakpointOptions::CommandData>(); + + for (std::string &str : m_options.m_commands) + cmd_data->user_source.AppendString(str); + + cmd_data->stop_on_error = true; + bp->GetOptions()->SetCommandDataCallback(cmd_data); + } } if (bp) { @@ -802,6 +833,7 @@ static OptionDefinition g_breakpoint_modify_options[] = { { LLDB_OPT_SET_1, false, "enable", 'e', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Enable the breakpoint." }, { LLDB_OPT_SET_2, false, "disable", 'd', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Disable the breakpoint." }, { LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Sets Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets." }, + { LLDB_OPT_SET_ALL, false, "auto-continue", 'G', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "The breakpoint will auto-continue after running its commands." }, // clang-format on }; @@ -865,6 +897,17 @@ public: m_enable_passed = true; m_enable_value = true; break; + case 'G': { + bool value, success; + value = Args::StringToBoolean(option_arg, false, &success); + if (success) { + m_auto_continue_passed = true; + m_auto_continue = value; + } else + error.SetErrorStringWithFormat( + "invalid boolean value '%s' passed for -G option", + option_arg.str().c_str()); + } break; case 'i': if (option_arg.getAsInteger(0, m_ignore_count)) error.SetErrorStringWithFormat("invalid ignore count '%s'", @@ -938,6 +981,8 @@ public: m_condition_passed = false; m_one_shot_passed = false; m_use_dummy = false; + m_auto_continue = false; + m_auto_continue_passed = false; } llvm::ArrayRef<OptionDefinition> GetDefinitions() override { @@ -962,6 +1007,8 @@ public: bool m_condition_passed; bool m_one_shot_passed; bool m_use_dummy; + bool m_auto_continue; + bool m_auto_continue_passed; }; protected: @@ -1013,6 +1060,9 @@ protected: if (m_options.m_condition_passed) location->SetCondition(m_options.m_condition.c_str()); + + if (m_options.m_auto_continue_passed) + location->SetAutoContinue(m_options.m_auto_continue); } } else { if (m_options.m_thread_id_passed) @@ -1035,6 +1085,9 @@ protected: if (m_options.m_condition_passed) bp->SetCondition(m_options.m_condition.c_str()); + + if (m_options.m_auto_continue_passed) + bp->SetAutoContinue(m_options.m_auto_continue); } } } diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp index 6af5ce1b2eb..8dbcec9fa81 100644 --- a/lldb/source/Target/StopInfo.cpp +++ b/lldb/source/Target/StopInfo.cpp @@ -393,7 +393,10 @@ protected: for (size_t j = 0; j < num_owners; j++) { lldb::BreakpointLocationSP bp_loc_sp = site_locations.GetByIndex(j); - + StreamString loc_desc; + if (log) { + bp_loc_sp->GetDescription(&loc_desc, eDescriptionLevelBrief); + } // If another action disabled this breakpoint or its location, then // don't run the actions. if (!bp_loc_sp->IsEnabled() || @@ -405,16 +408,16 @@ protected: // this thread. Skip the ones that aren't: if (!bp_loc_sp->ValidForThisThread(thread_sp.get())) { if (log) { - StreamString s; - bp_loc_sp->GetDescription(&s, eDescriptionLevelBrief); log->Printf("Breakpoint %s hit on thread 0x%llx but it was not " "for this thread, continuing.", - s.GetData(), static_cast<unsigned long long>( + loc_desc.GetData(), static_cast<unsigned long long>( thread_sp->GetID())); } continue; } + internal_breakpoint = bp_loc_sp->GetBreakpoint().IsInternal(); + // First run the precondition, but since the precondition is per // breakpoint, only run it once // per breakpoint. @@ -458,11 +461,10 @@ protected: error_sp->Flush(); } else { if (log) { - StreamString s; - bp_loc_sp->GetDescription(&s, eDescriptionLevelBrief); log->Printf("Condition evaluated for breakpoint %s on thread " "0x%llx conditon_says_stop: %i.", - s.GetData(), static_cast<unsigned long long>( + loc_desc.GetData(), + static_cast<unsigned long long>( thread_sp->GetID()), condition_says_stop); } @@ -477,7 +479,26 @@ protected: } } - bool callback_says_stop; + // Check the auto-continue bit on the location, do this before the + // callback since it may change this, but that would be for the + // NEXT hit. Note, you might think you could check auto-continue + // before the condition, and not evaluate the condition if it says + // to continue. But failing the condition means the breakpoint was + // effectively NOT HIT. So these two states are different. + bool auto_continue_says_stop = true; + if (bp_loc_sp->IsAutoContinue()) + { + if (log) + log->Printf("Continuing breakpoint %s as AutoContinue was set.", + loc_desc.GetData()); + // We want this stop reported, so you will know we auto-continued + // but only for external breakpoints: + if (!internal_breakpoint) + thread_sp->SetShouldReportStop(eVoteYes); + auto_continue_says_stop = false; + } + + bool callback_says_stop = true; // FIXME: For now the callbacks have to run in async mode - the // first time we restart we need @@ -493,11 +514,8 @@ protected: debugger.SetAsyncExecution(old_async); - if (callback_says_stop) + if (callback_says_stop && auto_continue_says_stop) m_should_stop = true; - - if (m_should_stop && !bp_loc_sp->GetBreakpoint().IsInternal()) - internal_breakpoint = false; // If we are going to stop for this breakpoint, then remove the // breakpoint. @@ -506,7 +524,6 @@ protected: thread_sp->GetProcess()->GetTarget().RemoveBreakpointByID( bp_loc_sp->GetBreakpoint().GetID()); } - // Also make sure that the callback hasn't continued the target. // If it did, when we'll set m_should_start to false and get out of // here. |