diff options
-rw-r--r-- | lldb/include/lldb/API/SBBreakpoint.h | 4 | ||||
-rw-r--r-- | lldb/include/lldb/API/SBBreakpointLocation.h | 4 | ||||
-rw-r--r-- | lldb/include/lldb/Breakpoint/Breakpoint.h | 12 | ||||
-rw-r--r-- | lldb/include/lldb/Breakpoint/BreakpointLocation.h | 13 | ||||
-rw-r--r-- | lldb/include/lldb/Breakpoint/BreakpointOptions.h | 33 | ||||
-rw-r--r-- | lldb/include/lldb/lldb-enumerations.h | 4 | ||||
-rw-r--r-- | lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py | 31 | ||||
-rw-r--r-- | lldb/scripts/interface/SBBreakpoint.i | 4 | ||||
-rw-r--r-- | lldb/scripts/interface/SBBreakpointLocation.i | 4 | ||||
-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 |
16 files changed, 273 insertions, 29 deletions
diff --git a/lldb/include/lldb/API/SBBreakpoint.h b/lldb/include/lldb/API/SBBreakpoint.h index 9abc9cd39dc..bdf2f650b52 100644 --- a/lldb/include/lldb/API/SBBreakpoint.h +++ b/lldb/include/lldb/API/SBBreakpoint.h @@ -70,6 +70,10 @@ public: const char *GetCondition(); + void SetAutoContinue(bool auto_continue); + + bool GetAutoContinue(); + void SetThreadID(lldb::tid_t sb_thread_id); lldb::tid_t GetThreadID(); diff --git a/lldb/include/lldb/API/SBBreakpointLocation.h b/lldb/include/lldb/API/SBBreakpointLocation.h index c8fa4a1934d..5b942f362ea 100644 --- a/lldb/include/lldb/API/SBBreakpointLocation.h +++ b/lldb/include/lldb/API/SBBreakpointLocation.h @@ -47,6 +47,10 @@ public: void SetCondition(const char *condition); const char *GetCondition(); + + void SetAutoContinue(bool auto_continue); + + bool GetAutoContinue(); void SetScriptCallbackFunction(const char *callback_function_name); diff --git a/lldb/include/lldb/Breakpoint/Breakpoint.h b/lldb/include/lldb/Breakpoint/Breakpoint.h index 41241334dcf..6deaeaad2b9 100644 --- a/lldb/include/lldb/Breakpoint/Breakpoint.h +++ b/lldb/include/lldb/Breakpoint/Breakpoint.h @@ -421,6 +421,18 @@ public: bool IsOneShot() const; //------------------------------------------------------------------ + /// If \a auto_continue is \b true, breakpoint will auto-continue when on hit. + //------------------------------------------------------------------ + void SetAutoContinue(bool auto_continue); + + //------------------------------------------------------------------ + /// Check the AutoContinue state. + /// @return + /// \b true if the breakpoint is set to auto-continue, \b false otherwise. + //------------------------------------------------------------------ + bool IsAutoContinue() const; + + //------------------------------------------------------------------ /// Set the valid thread to be checked when the breakpoint is hit. /// @param[in] thread_id /// If this thread hits the breakpoint, we stop, otherwise not. diff --git a/lldb/include/lldb/Breakpoint/BreakpointLocation.h b/lldb/include/lldb/Breakpoint/BreakpointLocation.h index 2a94f3c2a2b..b68a9ffad04 100644 --- a/lldb/include/lldb/Breakpoint/BreakpointLocation.h +++ b/lldb/include/lldb/Breakpoint/BreakpointLocation.h @@ -107,6 +107,19 @@ public: bool IsEnabled() const; //------------------------------------------------------------------ + /// If \a auto_continue is \b true, set the breakpoint to continue when hit. + //------------------------------------------------------------------ + void SetAutoContinue(bool auto_continue); + + //------------------------------------------------------------------ + /// Check the AutoContinue state. + /// + /// @return + /// \b true if the breakpoint is set to auto-continue, \b false if not. + //------------------------------------------------------------------ + bool IsAutoContinue() const; + + //------------------------------------------------------------------ /// Return the current Ignore Count. /// /// @return diff --git a/lldb/include/lldb/Breakpoint/BreakpointOptions.h b/lldb/include/lldb/Breakpoint/BreakpointOptions.h index cb379a9103a..b0276cb1568 100644 --- a/lldb/include/lldb/Breakpoint/BreakpointOptions.h +++ b/lldb/include/lldb/Breakpoint/BreakpointOptions.h @@ -38,12 +38,13 @@ friend class Breakpoint; public: enum OptionKind { - eCallback = 1 << 0, - eEnabled = 1 << 1, - eOneShot = 1 << 2, - eIgnoreCount = 1 << 3, - eThreadSpec = 1 << 4, - eCondition = 1 << 5 + eCallback = 1 << 0, + eEnabled = 1 << 1, + eOneShot = 1 << 2, + eIgnoreCount = 1 << 3, + eThreadSpec = 1 << 4, + eCondition = 1 << 5, + eAutoContinue = 1 << 6 }; struct CommandData { CommandData() @@ -112,7 +113,8 @@ public: /// //------------------------------------------------------------------ BreakpointOptions(const char *condition, bool enabled = true, - int32_t ignore = 0, bool one_shot = false); + int32_t ignore = 0, bool one_shot = false, + bool auto_continue = false); virtual ~BreakpointOptions(); @@ -296,6 +298,21 @@ public: } //------------------------------------------------------------------ + /// Check the auto-continue state. + /// @return + /// \b true if the breakpoint is set to auto-continue, \b false otherwise. + //------------------------------------------------------------------ + bool IsAutoContinue() const { return m_auto_continue; } + + //------------------------------------------------------------------ + /// Set the auto-continue state. + //------------------------------------------------------------------ + void SetAutoContinue(bool auto_continue) { + m_auto_continue = auto_continue; + m_set_flags.Set(eAutoContinue); + } + + //------------------------------------------------------------------ /// Check the One-shot state. /// @return /// \b true if the breakpoint is one-shot, \b false otherwise. @@ -394,6 +411,7 @@ protected: IgnoreCount, EnabledState, OneShotState, + AutoContinue, LastOptionName }; static const char *g_option_names[(size_t)OptionNames::LastOptionName]; @@ -424,6 +442,7 @@ private: std::string m_condition_text; // The condition to test. size_t m_condition_text_hash; // Its hash, so that locations know when the // condition is updated. + bool m_auto_continue; // If set, auto-continue from breakpoint. Flags m_set_flags; // Which options are set at this level. Drawn // from BreakpointOptions::SetOptionsFlags. }; diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h index 14bae6ca206..c6cd98806a2 100644 --- a/lldb/include/lldb/lldb-enumerations.h +++ b/lldb/include/lldb/lldb-enumerations.h @@ -380,7 +380,8 @@ FLAGS_ENUM(BreakpointEventType){ eBreakpointEventTypeCommandChanged = (1u << 8), eBreakpointEventTypeConditionChanged = (1u << 9), eBreakpointEventTypeIgnoreChanged = (1u << 10), - eBreakpointEventTypeThreadChanged = (1u << 11)}; + eBreakpointEventTypeThreadChanged = (1u << 11), + eBreakpointEventTypeAutoContinueChanged = (1u << 12)}; FLAGS_ENUM(WatchpointEventType){ eWatchpointEventTypeInvalidType = (1u << 0), @@ -566,6 +567,7 @@ enum CommandArgumentType { eArgTypeWatchpointIDRange, eArgTypeWatchType, eArgRawInput, + eArgTypeCommand, eArgTypeLastArg // Always keep this entry as the last entry in this // enumeration!! }; diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py b/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py index e67a6332d9d..cb4aeadbf93 100644 --- a/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py +++ b/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py @@ -24,12 +24,21 @@ class BreakpointCommandTestCase(TestBase): cls.RemoveTempFile("output2.txt") @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24528") - def test(self): + def test_breakpoint_command_sequence(self): """Test a sequence of breakpoint command add, list, and delete.""" self.build() self.breakpoint_command_sequence() + + @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24528") + def test_script_parameters(self): + """Test a sequence of breakpoint command add, list, and delete.""" + self.build() self.breakpoint_command_script_parameters() + def test_commands_on_creation(self): + self.build() + self.breakpoint_commands_on_creation() + def setUp(self): # Call super's setUp(). TestBase.setUp(self) @@ -268,3 +277,23 @@ class BreakpointCommandTestCase(TestBase): # Now remove 'output-2.txt' os.remove('output-2.txt') + + def breakpoint_commands_on_creation(self): + """Test that setting breakpoint commands when creating the breakpoint works""" + exe = os.path.join(os.getcwd(), "a.out") + target = self.dbg.CreateTarget(exe) + self.assertTrue(target.IsValid(), "Created an invalid target.") + + # Add a breakpoint. + lldbutil.run_break_set_by_file_and_line( + self, "main.c", self.line, num_expected_locations=1, loc_exact=True, + extra_options='-d bt -d "thread list" -d continue') + + bkpt = target.FindBreakpointByID(1) + self.assertTrue(bkpt.IsValid(), "Couldn't find breakpoint 1") + com_list = lldb.SBStringList() + bkpt.GetCommandLineCommands(com_list) + self.assertEqual(com_list.GetSize(), 3, "Got the wrong number of commands") + self.assertEqual(com_list.GetStringAtIndex(0), "bt", "First bt") + self.assertEqual(com_list.GetStringAtIndex(1), "thread list", "Next thread list") + self.assertEqual(com_list.GetStringAtIndex(2), "continue", "Last continue") diff --git a/lldb/scripts/interface/SBBreakpoint.i b/lldb/scripts/interface/SBBreakpoint.i index e3b1eea0630..76ddd7259e9 100644 --- a/lldb/scripts/interface/SBBreakpoint.i +++ b/lldb/scripts/interface/SBBreakpoint.i @@ -153,6 +153,10 @@ public: const char * GetCondition (); + void SetAutoContinue(bool auto_continue); + + bool GetAutoContinue(); + void SetThreadID (lldb::tid_t sb_thread_id); diff --git a/lldb/scripts/interface/SBBreakpointLocation.i b/lldb/scripts/interface/SBBreakpointLocation.i index 5609c1f84f8..7a9a15db8ff 100644 --- a/lldb/scripts/interface/SBBreakpointLocation.i +++ b/lldb/scripts/interface/SBBreakpointLocation.i @@ -73,6 +73,10 @@ public: const char * GetCondition (); + bool GetAutoContinue(); + + void SetAutoContinue(bool auto_continue); + %feature("docstring", " //------------------------------------------------------------------ /// Set the callback to the given Python function name. 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. |