diff options
-rw-r--r-- | lldb/include/lldb/API/SBBreakpointLocation.h | 4 | ||||
-rw-r--r-- | lldb/include/lldb/API/SBStringList.h | 1 | ||||
-rw-r--r-- | lldb/include/lldb/Breakpoint/BreakpointLocation.h | 10 | ||||
-rw-r--r-- | lldb/include/lldb/Breakpoint/BreakpointOptions.h | 58 | ||||
-rw-r--r-- | lldb/lldb.xcodeproj/xcshareddata/xcschemes/desktop.xcscheme | 2 | ||||
-rw-r--r-- | lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py | 108 | ||||
-rw-r--r-- | lldb/scripts/interface/SBBreakpoint.i | 33 | ||||
-rw-r--r-- | lldb/scripts/interface/SBBreakpointLocation.i | 4 | ||||
-rw-r--r-- | lldb/source/API/SBBreakpointLocation.cpp | 28 | ||||
-rw-r--r-- | lldb/source/Breakpoint/Breakpoint.cpp | 2 | ||||
-rw-r--r-- | lldb/source/Breakpoint/BreakpointLocation.cpp | 63 | ||||
-rw-r--r-- | lldb/source/Breakpoint/BreakpointOptions.cpp | 130 | ||||
-rw-r--r-- | lldb/source/Commands/CommandObjectBreakpointCommand.cpp | 63 |
13 files changed, 378 insertions, 128 deletions
diff --git a/lldb/include/lldb/API/SBBreakpointLocation.h b/lldb/include/lldb/API/SBBreakpointLocation.h index 900541b0201..c8fa4a1934d 100644 --- a/lldb/include/lldb/API/SBBreakpointLocation.h +++ b/lldb/include/lldb/API/SBBreakpointLocation.h @@ -51,7 +51,11 @@ public: void SetScriptCallbackFunction(const char *callback_function_name); SBError SetScriptCallbackBody(const char *script_body_text); + + void SetCommandLineCommands(SBStringList &commands); + bool GetCommandLineCommands(SBStringList &commands); + void SetThreadID(lldb::tid_t sb_thread_id); lldb::tid_t GetThreadID(); diff --git a/lldb/include/lldb/API/SBStringList.h b/lldb/include/lldb/API/SBStringList.h index 66b5172a0b3..c50594db07f 100644 --- a/lldb/include/lldb/API/SBStringList.h +++ b/lldb/include/lldb/API/SBStringList.h @@ -44,6 +44,7 @@ protected: friend class SBCommandInterpreter; friend class SBDebugger; friend class SBBreakpoint; + friend class SBBreakpointLocation; SBStringList(const lldb_private::StringList *lldb_strings); diff --git a/lldb/include/lldb/Breakpoint/BreakpointLocation.h b/lldb/include/lldb/Breakpoint/BreakpointLocation.h index a1086aa3fe5..2a94f3c2a2b 100644 --- a/lldb/include/lldb/Breakpoint/BreakpointLocation.h +++ b/lldb/include/lldb/Breakpoint/BreakpointLocation.h @@ -17,6 +17,7 @@ // Other libraries and framework includes // Project includes +#include "lldb/Breakpoint/BreakpointOptions.h" #include "lldb/Breakpoint/StoppointLocation.h" #include "lldb/Core/Address.h" #include "lldb/Utility/UserID.h" @@ -255,14 +256,17 @@ public: //------------------------------------------------------------------ /// Use this to access breakpoint options from this breakpoint location. - /// This will point to the owning breakpoint's options unless options have - /// been set specifically on this location. + /// This will return the options that have a setting for the specified + /// BreakpointOptions kind. /// + /// @param[in] kind + /// The particular option you are looking up. /// @return /// A pointer to the containing breakpoint's options if this /// location doesn't have its own copy. //------------------------------------------------------------------ - const BreakpointOptions *GetOptionsNoCreate() const; + const BreakpointOptions *GetOptionsSpecifyingKind( + BreakpointOptions::OptionKind kind) const; bool ValidForThisThread(Thread *thread); diff --git a/lldb/include/lldb/Breakpoint/BreakpointOptions.h b/lldb/include/lldb/Breakpoint/BreakpointOptions.h index 420d5915fd4..cb379a9103a 100644 --- a/lldb/include/lldb/Breakpoint/BreakpointOptions.h +++ b/lldb/include/lldb/Breakpoint/BreakpointOptions.h @@ -18,6 +18,7 @@ // Other libraries and framework includes // Project includes #include "lldb/Utility/Baton.h" +#include "lldb/Utility/Flags.h" #include "lldb/Utility/StringList.h" #include "lldb/Utility/StructuredData.h" #include "lldb/lldb-private.h" @@ -32,7 +33,18 @@ namespace lldb_private { //---------------------------------------------------------------------- class BreakpointOptions { +friend class BreakpointLocation; +friend class Breakpoint; + public: + enum OptionKind { + eCallback = 1 << 0, + eEnabled = 1 << 1, + eOneShot = 1 << 2, + eIgnoreCount = 1 << 3, + eThreadSpec = 1 << 4, + eCondition = 1 << 5 + }; struct CommandData { CommandData() : user_source(), script_source(), @@ -85,18 +97,6 @@ public: typedef std::shared_ptr<CommandBaton> CommandBatonSP; //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - //------------------------------------------------------------------ - /// Default constructor. The breakpoint is enabled, and has no condition, - /// callback, ignore count, etc... - //------------------------------------------------------------------ - BreakpointOptions(); - BreakpointOptions(const BreakpointOptions &rhs); - - static BreakpointOptions *CopyOptionsNoCallback(BreakpointOptions &rhs); - - //------------------------------------------------------------------ /// This constructor allows you to specify all the breakpoint options /// except the callback. That one is more complicated, and better /// to do by hand. @@ -290,7 +290,10 @@ public: //------------------------------------------------------------------ /// If \a enable is \b true, enable the breakpoint, if \b false disable it. //------------------------------------------------------------------ - void SetEnabled(bool enabled) { m_enabled = enabled; } + void SetEnabled(bool enabled) { + m_enabled = enabled; + m_set_flags.Set(eEnabled); + } //------------------------------------------------------------------ /// Check the One-shot state. @@ -302,7 +305,10 @@ public: //------------------------------------------------------------------ /// If \a enable is \b true, enable the breakpoint, if \b false disable it. //------------------------------------------------------------------ - void SetOneShot(bool one_shot) { m_one_shot = one_shot; } + void SetOneShot(bool one_shot) { + m_one_shot = one_shot; + m_set_flags.Set(eOneShot); + } //------------------------------------------------------------------ /// Set the breakpoint to ignore the next \a count breakpoint hits. @@ -310,7 +316,10 @@ public: /// The number of breakpoint hits to ignore. //------------------------------------------------------------------ - void SetIgnoreCount(uint32_t n) { m_ignore_count = n; } + void SetIgnoreCount(uint32_t n) { + m_ignore_count = n; + m_set_flags.Set(eIgnoreCount); + } //------------------------------------------------------------------ /// Return the current Ignore Count. @@ -360,11 +369,26 @@ public: /// The breakpoint will take ownership of pointer held by this object. //------------------------------------------------------------------ void SetCommandDataCallback(std::unique_ptr<CommandData> &cmd_data); - + protected: //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + //------------------------------------------------------------------ + /// Breakpoints make options with all flags set. Locations make options + /// with no flags set. Nobody else should make breakpoint options. + //------------------------------------------------------------------ + BreakpointOptions(bool all_flags_set); + BreakpointOptions(const BreakpointOptions &rhs); + +//------------------------------------------------------------------ // Classes that inherit from BreakpointOptions can see and modify these //------------------------------------------------------------------ + bool IsOptionSet(OptionKind kind) + { + return m_set_flags.Test(kind); + } + enum class OptionNames { ConditionText = 0, IgnoreCount, @@ -400,6 +424,8 @@ 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. + Flags m_set_flags; // Which options are set at this level. Drawn + // from BreakpointOptions::SetOptionsFlags. }; } // namespace lldb_private diff --git a/lldb/lldb.xcodeproj/xcshareddata/xcschemes/desktop.xcscheme b/lldb/lldb.xcodeproj/xcshareddata/xcschemes/desktop.xcscheme index 17aedff2ce5..7512a281357 100644 --- a/lldb/lldb.xcodeproj/xcshareddata/xcschemes/desktop.xcscheme +++ b/lldb/lldb.xcodeproj/xcshareddata/xcschemes/desktop.xcscheme @@ -26,6 +26,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" shouldUseLaunchSchemeArgsEnv = "YES"> <Testables> </Testables> @@ -36,6 +37,7 @@ buildConfiguration = "DebugClang" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py b/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py index fdbd622f767..de24d8b002d 100644 --- a/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py +++ b/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py @@ -18,27 +18,40 @@ class BreakpointLocationsTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24528") - def test(self): + def test_enable(self): """Test breakpoint enable/disable for a breakpoint ID with multiple locations.""" self.build() self.breakpoint_locations_test() + def test_shadowed_cond_options(self): + """Test that options set on the breakpoint and location behave correctly.""" + self.build() + self.shadowed_bkpt_cond_test() + + + def test_shadowed_command_options(self): + """Test that options set on the breakpoint and location behave correctly.""" + self.build() + self.shadowed_bkpt_command_test() + def setUp(self): # Call super's setUp(). TestBase.setUp(self) # Find the line number to break inside main(). self.line = line_number('main.c', '// Set break point at this line.') - def breakpoint_locations_test(self): - """Test breakpoint enable/disable for a breakpoint ID with multiple locations.""" + def set_breakpoint (self): exe = os.path.join(os.getcwd(), "a.out") - self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, "Target %s is not valid"%(exe)) # This should create a breakpoint with 3 locations. - lldbutil.run_break_set_by_file_and_line( - self, "main.c", self.line, num_expected_locations=3) + + bkpt = target.BreakpointCreateByLocation("main.c", self.line) # The breakpoint list should show 3 locations. + self.assertEqual(bkpt.GetNumLocations(), 3, "Wrong number of locations") + self.expect( "breakpoint list -f", "Breakpoint locations shown correctly", @@ -49,6 +62,87 @@ class BreakpointLocationsTestCase(TestBase): "where = a.out`func_inlined .+unresolved, hit count = 0", "where = a.out`main .+\[inlined\].+unresolved, hit count = 0"]) + return bkpt + + def shadowed_bkpt_cond_test(self): + """Test that options set on the breakpoint and location behave correctly.""" + # Breakpoint option propagation from bkpt to loc used to be done the first time + # a breakpoint location option was specifically set. After that the other options + # on that location would stop tracking the breakpoint. That got fixed, and this test + # makes sure only the option touched is affected. + + bkpt = self.set_breakpoint() + bkpt_cond = "1 == 0" + bkpt.SetCondition(bkpt_cond) + self.assertEqual(bkpt.GetCondition(), bkpt_cond,"Successfully set condition") + self.assertTrue(bkpt.location[0].GetCondition() == bkpt.GetCondition(), "Conditions are the same") + + # Now set a condition on the locations, make sure that this doesn't effect the bkpt: + bkpt_loc_1_cond = "1 == 1" + bkpt.location[0].SetCondition(bkpt_loc_1_cond) + self.assertEqual(bkpt.location[0].GetCondition(), bkpt_loc_1_cond, "Successfully changed location condition") + self.assertNotEqual(bkpt.GetCondition(), bkpt_loc_1_cond, "Changed location changed Breakpoint condition") + self.assertEqual(bkpt.location[1].GetCondition(), bkpt_cond, "Changed another location's condition") + + # Now make sure that setting one options doesn't fix the value of another: + bkpt.SetIgnoreCount(10) + self.assertEqual(bkpt.GetIgnoreCount(), 10, "Set the ignore count successfully") + self.assertEqual(bkpt.location[0].GetIgnoreCount(), 10, "Location doesn't track top-level bkpt.") + + # Now make sure resetting the condition to "" resets the tracking: + bkpt.location[0].SetCondition("") + bkpt_new_cond = "1 == 3" + bkpt.SetCondition(bkpt_new_cond) + self.assertEqual(bkpt.location[0].GetCondition(), bkpt_new_cond, "Didn't go back to tracking condition") + + def shadowed_bkpt_command_test(self): + """Test that options set on the breakpoint and location behave correctly.""" + # Breakpoint option propagation from bkpt to loc used to be done the first time + # a breakpoint location option was specifically set. After that the other options + # on that location would stop tracking the breakpoint. That got fixed, and this test + # makes sure only the option touched is affected. + + bkpt = self.set_breakpoint() + commands = ["AAAAAA", "BBBBBB", "CCCCCC"] + str_list = lldb.SBStringList() + str_list.AppendList(commands, len(commands)) + + bkpt.SetCommandLineCommands(str_list) + cmd_list = lldb.SBStringList() + bkpt.GetCommandLineCommands(cmd_list) + list_size = str_list.GetSize() + self.assertEqual(cmd_list.GetSize() , list_size, "Added the right number of commands") + for i in range(0,list_size): + self.assertEqual(str_list.GetStringAtIndex(i), cmd_list.GetStringAtIndex(i), "Mismatched commands.") + + commands = ["DDDDDD", "EEEEEE", "FFFFFF", "GGGGGG"] + loc_list = lldb.SBStringList() + loc_list.AppendList(commands, len(commands)) + bkpt.location[1].SetCommandLineCommands(loc_list) + loc_cmd_list = lldb.SBStringList() + bkpt.location[1].GetCommandLineCommands(loc_cmd_list) + + loc_list_size = loc_list.GetSize() + + # Check that the location has the right commands: + self.assertEqual(loc_cmd_list.GetSize() , loc_list_size, "Added the right number of commands to location") + for i in range(0,loc_list_size): + self.assertEqual(loc_list.GetStringAtIndex(i), loc_cmd_list.GetStringAtIndex(i), "Mismatched commands.") + + # Check that we didn't mess up the breakpoint level commands: + self.assertEqual(cmd_list.GetSize() , list_size, "Added the right number of commands") + for i in range(0,list_size): + self.assertEqual(str_list.GetStringAtIndex(i), cmd_list.GetStringAtIndex(i), "Mismatched commands.") + + # And check we didn't mess up another location: + untouched_loc_cmds = lldb.SBStringList() + bkpt.location[0].GetCommandLineCommands(untouched_loc_cmds) + self.assertEqual(untouched_loc_cmds.GetSize() , 0, "Changed the wrong location") + + def breakpoint_locations_test(self): + """Test breakpoint enable/disable for a breakpoint ID with multiple locations.""" + self.set_breakpoint() + # The 'breakpoint disable 3.*' command should fail gracefully. self.expect("breakpoint disable 3.*", "Disabling an invalid breakpoint should fail gracefully", @@ -80,7 +174,7 @@ class BreakpointLocationsTestCase(TestBase): "1 breakpoint locatons disabled correctly", startstr="1 breakpoints disabled.") - # Run the program againt. We should stop on the two breakpoint + # Run the program again. We should stop on the two breakpoint # locations. self.runCmd("run", RUN_SUCCEEDED) diff --git a/lldb/scripts/interface/SBBreakpoint.i b/lldb/scripts/interface/SBBreakpoint.i index 95bc0cda005..e3b1eea0630 100644 --- a/lldb/scripts/interface/SBBreakpoint.i +++ b/lldb/scripts/interface/SBBreakpoint.i @@ -251,6 +251,39 @@ public: %pythoncode %{ + class locations_access(object): + '''A helper object that will lazily hand out locations for a breakpoint when supplied an index.''' + def __init__(self, sbbreakpoint): + self.sbbreakpoint = sbbreakpoint + + def __len__(self): + if self.sbbreakpoint: + return int(self.sbbreakpoint.GetNumLocations()) + return 0 + + def __getitem__(self, key): + if type(key) is int and key < len(self): + return self.sbbreakpoint.GetLocationAtIndex(key) + return None + + def get_locations_access_object(self): + '''An accessor function that returns a locations_access() object which allows lazy location access from a lldb.SBBreakpoint object.''' + return self.locations_access (self) + + def get_breakpoint_location_list(self): + '''An accessor function that returns a list() that contains all locations in a lldb.SBBreakpoint object.''' + locations = [] + accessor = self.get_locations_access_object() + for idx in range(len(accessor)): + locations.append(accessor[idx]) + return locations + + __swig_getmethods__["locations"] = get_breakpoint_location_list + if _newclass: locations = property(get_breakpoint_location_list, None, doc='''A read only property that returns a list() of lldb.SBBreakpointLocation objects for this breakpoint.''') + + __swig_getmethods__["location"] = get_locations_access_object + if _newclass: location = property(get_locations_access_object, None, doc='''A read only property that returns an object that can access locations by index (not location ID) (location = bkpt.location[12]).''') + __swig_getmethods__["id"] = GetID if _newclass: id = property(GetID, None, doc='''A read only property that returns the ID of this breakpoint.''') diff --git a/lldb/scripts/interface/SBBreakpointLocation.i b/lldb/scripts/interface/SBBreakpointLocation.i index 4a5aac031b4..5609c1f84f8 100644 --- a/lldb/scripts/interface/SBBreakpointLocation.i +++ b/lldb/scripts/interface/SBBreakpointLocation.i @@ -96,6 +96,10 @@ public: SBError SetScriptCallbackBody (const char *script_body_text); + void SetCommandLineCommands(SBStringList &commands); + + bool GetCommandLineCommands(SBStringList &commands); + void SetThreadID (lldb::tid_t sb_thread_id); diff --git a/lldb/source/API/SBBreakpointLocation.cpp b/lldb/source/API/SBBreakpointLocation.cpp index 3678d1d33e0..f5e0b91483e 100644 --- a/lldb/source/API/SBBreakpointLocation.cpp +++ b/lldb/source/API/SBBreakpointLocation.cpp @@ -12,6 +12,7 @@ #include "lldb/API/SBDebugger.h" #include "lldb/API/SBDefines.h" #include "lldb/API/SBStream.h" +#include "lldb/API/SBStringList.h" #include "lldb/Breakpoint/Breakpoint.h" #include "lldb/Breakpoint/BreakpointLocation.h" @@ -195,6 +196,33 @@ SBBreakpointLocation::SetScriptCallbackBody(const char *callback_body_text) { return sb_error; } +void SBBreakpointLocation::SetCommandLineCommands(SBStringList &commands) { + BreakpointLocationSP loc_sp = GetSP(); + if (!loc_sp) + return; + if (commands.GetSize() == 0) + return; + + std::lock_guard<std::recursive_mutex> guard( + loc_sp->GetTarget().GetAPIMutex()); + std::unique_ptr<BreakpointOptions::CommandData> cmd_data_up( + new BreakpointOptions::CommandData(*commands, eScriptLanguageNone)); + + loc_sp->GetLocationOptions()->SetCommandDataCallback(cmd_data_up); +} + +bool SBBreakpointLocation::GetCommandLineCommands(SBStringList &commands) { + BreakpointLocationSP loc_sp = GetSP(); + if (!loc_sp) + return false; + StringList command_list; + bool has_commands = + loc_sp->GetLocationOptions()->GetCommandLineCallbacks(command_list); + if (has_commands) + commands.AppendList(command_list); + return has_commands; +} + void SBBreakpointLocation::SetThreadID(tid_t thread_id) { BreakpointLocationSP loc_sp = GetSP(); if (loc_sp) { diff --git a/lldb/source/Breakpoint/Breakpoint.cpp b/lldb/source/Breakpoint/Breakpoint.cpp index 17c104ba0c6..043e5e8f591 100644 --- a/lldb/source/Breakpoint/Breakpoint.cpp +++ b/lldb/source/Breakpoint/Breakpoint.cpp @@ -53,7 +53,7 @@ Breakpoint::Breakpoint(Target &target, SearchFilterSP &filter_sp, bool resolve_indirect_symbols) : m_being_created(true), m_hardware(hardware), m_target(target), m_filter_sp(filter_sp), m_resolver_sp(resolver_sp), - m_options_up(new BreakpointOptions()), m_locations(*this), + m_options_up(new BreakpointOptions(true)), m_locations(*this), m_resolve_indirect_symbols(resolve_indirect_symbols), m_hit_count(0) { m_being_created = false; } diff --git a/lldb/source/Breakpoint/BreakpointLocation.cpp b/lldb/source/Breakpoint/BreakpointLocation.cpp index ec8f141e8d3..15865be3f9a 100644 --- a/lldb/source/Breakpoint/BreakpointLocation.cpp +++ b/lldb/source/Breakpoint/BreakpointLocation.cpp @@ -58,6 +58,15 @@ lldb::addr_t BreakpointLocation::GetLoadAddress() const { return m_address.GetOpcodeLoadAddress(&m_owner.GetTarget()); } +const BreakpointOptions * +BreakpointLocation::GetOptionsSpecifyingKind(BreakpointOptions::OptionKind kind) +const { + if (m_options_ap && m_options_ap->IsOptionSet(kind)) + return m_options_ap.get(); + else + return m_owner.GetOptions(); +} + Address &BreakpointLocation::GetAddress() { return m_address; } Breakpoint &BreakpointLocation::GetBreakpoint() { return m_owner; } @@ -97,8 +106,11 @@ void BreakpointLocation::SetThreadID(lldb::tid_t thread_id) { } lldb::tid_t BreakpointLocation::GetThreadID() { - if (GetOptionsNoCreate()->GetThreadSpecNoCreate()) - return GetOptionsNoCreate()->GetThreadSpecNoCreate()->GetTID(); + const ThreadSpec *thread_spec = + GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec) + ->GetThreadSpecNoCreate(); + if (thread_spec) + return thread_spec->GetTID(); else return LLDB_INVALID_THREAD_ID; } @@ -116,8 +128,11 @@ void BreakpointLocation::SetThreadIndex(uint32_t index) { } uint32_t BreakpointLocation::GetThreadIndex() const { - if (GetOptionsNoCreate()->GetThreadSpecNoCreate()) - return GetOptionsNoCreate()->GetThreadSpecNoCreate()->GetIndex(); + const ThreadSpec *thread_spec = + GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec) + ->GetThreadSpecNoCreate(); + if (thread_spec) + return thread_spec->GetIndex(); else return 0; } @@ -135,8 +150,11 @@ void BreakpointLocation::SetThreadName(const char *thread_name) { } const char *BreakpointLocation::GetThreadName() const { - if (GetOptionsNoCreate()->GetThreadSpecNoCreate()) - return GetOptionsNoCreate()->GetThreadSpecNoCreate()->GetName(); + const ThreadSpec *thread_spec = + GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec) + ->GetThreadSpecNoCreate(); + if (thread_spec) + return thread_spec->GetName(); else return nullptr; } @@ -154,8 +172,11 @@ void BreakpointLocation::SetQueueName(const char *queue_name) { } const char *BreakpointLocation::GetQueueName() const { - if (GetOptionsNoCreate()->GetThreadSpecNoCreate()) - return GetOptionsNoCreate()->GetThreadSpecNoCreate()->GetQueueName(); + const ThreadSpec *thread_spec = + GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec) + ->GetThreadSpecNoCreate(); + if (thread_spec) + return thread_spec->GetQueueName(); else return nullptr; } @@ -193,7 +214,8 @@ void BreakpointLocation::SetCondition(const char *condition) { } const char *BreakpointLocation::GetConditionText(size_t *hash) const { - return GetOptionsNoCreate()->GetConditionText(hash); + return GetOptionsSpecifyingKind(BreakpointOptions::eCondition) + ->GetConditionText(hash); } bool BreakpointLocation::ConditionSaysStop(ExecutionContext &exe_ctx, @@ -305,7 +327,8 @@ bool BreakpointLocation::ConditionSaysStop(ExecutionContext &exe_ctx, } uint32_t BreakpointLocation::GetIgnoreCount() { - return GetOptionsNoCreate()->GetIgnoreCount(); + return GetOptionsSpecifyingKind(BreakpointOptions::eIgnoreCount) + ->GetIgnoreCount(); } void BreakpointLocation::SetIgnoreCount(uint32_t n) { @@ -335,26 +358,21 @@ bool BreakpointLocation::IgnoreCountShouldStop() { return true; } -const BreakpointOptions *BreakpointLocation::GetOptionsNoCreate() const { - if (m_options_ap.get() != nullptr) - return m_options_ap.get(); - else - return m_owner.GetOptions(); -} - BreakpointOptions *BreakpointLocation::GetLocationOptions() { // If we make the copy we don't copy the callbacks because that is potentially // expensive and we don't want to do that for the simple case where someone is // just disabling the location. if (m_options_ap.get() == nullptr) m_options_ap.reset( - BreakpointOptions::CopyOptionsNoCallback(*m_owner.GetOptions())); + new BreakpointOptions(false)); return m_options_ap.get(); } bool BreakpointLocation::ValidForThisThread(Thread *thread) { - return thread->MatchesSpec(GetOptionsNoCreate()->GetThreadSpecNoCreate()); + return thread + ->MatchesSpec(GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec) + ->GetThreadSpecNoCreate()); } // RETURNS - true if we should stop at this breakpoint, false if we @@ -600,17 +618,20 @@ void BreakpointLocation::Dump(Stream *s) const { if (s == nullptr) return; + lldb::tid_t tid = GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec) + ->GetThreadSpecNoCreate()->GetTID(); s->Printf( "BreakpointLocation %u: tid = %4.4" PRIx64 " load addr = 0x%8.8" PRIx64 " state = %s type = %s breakpoint " "hw_index = %i hit_count = %-4u ignore_count = %-4u", - GetID(), GetOptionsNoCreate()->GetThreadSpecNoCreate()->GetTID(), + GetID(), tid, (uint64_t)m_address.GetOpcodeLoadAddress(&m_owner.GetTarget()), (m_options_ap.get() ? m_options_ap->IsEnabled() : m_owner.IsEnabled()) ? "enabled " : "disabled", IsHardware() ? "hardware" : "software", GetHardwareIndex(), GetHitCount(), - GetOptionsNoCreate()->GetIgnoreCount()); + GetOptionsSpecifyingKind(BreakpointOptions::eIgnoreCount) + ->GetIgnoreCount()); } void BreakpointLocation::SendBreakpointLocationChangedEvent( diff --git a/lldb/source/Breakpoint/BreakpointOptions.cpp b/lldb/source/Breakpoint/BreakpointOptions.cpp index bef63cc0f22..3e8d3dd41f3 100644 --- a/lldb/source/Breakpoint/BreakpointOptions.cpp +++ b/lldb/source/Breakpoint/BreakpointOptions.cpp @@ -126,11 +126,15 @@ bool BreakpointOptions::NullCallback(void *baton, //---------------------------------------------------------------------- // BreakpointOptions constructor //---------------------------------------------------------------------- -BreakpointOptions::BreakpointOptions() +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_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) @@ -138,8 +142,9 @@ BreakpointOptions::BreakpointOptions(const char *condition, bool enabled, 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_set_flags.Set(eEnabled | eIgnoreCount | eOneShot | eCondition); +} //---------------------------------------------------------------------- // BreakpointOptions copy constructor @@ -149,7 +154,8 @@ BreakpointOptions::BreakpointOptions(const BreakpointOptions &rhs) m_baton_is_command_baton(rhs.m_baton_is_command_baton), 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_ignore_count(rhs.m_ignore_count), m_thread_spec_ap(), + 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())); m_condition_text = rhs.m_condition_text; @@ -172,23 +178,10 @@ 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_set_flags = rhs.m_set_flags; return *this; } -BreakpointOptions * -BreakpointOptions::CopyOptionsNoCallback(BreakpointOptions &orig) { - BreakpointHitCallback orig_callback = orig.m_callback; - lldb::BatonSP orig_callback_baton_sp = orig.m_callback_baton_sp; - bool orig_is_sync = orig.m_callback_is_synchronous; - - orig.ClearCallback(); - BreakpointOptions *ret_val = new BreakpointOptions(orig); - - orig.SetCallback(orig_callback, orig_callback_baton_sp, orig_is_sync); - - return ret_val; -} - //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- @@ -200,29 +193,52 @@ std::unique_ptr<BreakpointOptions> BreakpointOptions::CreateFromStructuredData( bool enabled = true; bool one_shot = false; int32_t ignore_count = 0; - std::string condition_text; - - bool success = options_dict.GetValueForKeyAsBoolean( - GetKey(OptionNames::EnabledState), enabled); - if (!success) { - error.SetErrorStringWithFormat("%s key is not a boolean.", + llvm::StringRef condition_ref(""); + Flags set_options; + + const char *key = GetKey(OptionNames::EnabledState); + bool success; + if (key) { + success = options_dict.GetValueForKeyAsBoolean(key, enabled); + if (!success) { + error.SetErrorStringWithFormat("%s key is not a boolean.", GetKey(OptionNames::EnabledState)); - return nullptr; + return nullptr; + } + set_options.Set(eEnabled); } - success = options_dict.GetValueForKeyAsBoolean( - GetKey(OptionNames::OneShotState), one_shot); - if (!success) { - error.SetErrorStringWithFormat("%s key is not a boolean.", - GetKey(OptionNames::OneShotState)); - return nullptr; + key = GetKey(OptionNames::OneShotState); + if (key) { + success = options_dict.GetValueForKeyAsBoolean(key, one_shot); + if (!success) { + error.SetErrorStringWithFormat("%s key is not a boolean.", + GetKey(OptionNames::OneShotState)); + return nullptr; + } + set_options.Set(eOneShot); } - success = options_dict.GetValueForKeyAsInteger( - GetKey(OptionNames::IgnoreCount), ignore_count); - if (!success) { - error.SetErrorStringWithFormat("%s key is not an integer.", - GetKey(OptionNames::IgnoreCount)); - return nullptr; + + key = GetKey(OptionNames::IgnoreCount); + if (key) { + success = options_dict.GetValueForKeyAsInteger(key, ignore_count); + if (!success) { + error.SetErrorStringWithFormat("%s key is not an integer.", + GetKey(OptionNames::IgnoreCount)); + return nullptr; + } + set_options.Set(eIgnoreCount); + } + + key = GetKey(OptionNames::ConditionText); + if (key) { + success = options_dict.GetValueForKeyAsString(key, condition_ref); + if (!success) { + error.SetErrorStringWithFormat("%s key is not an string.", + GetKey(OptionNames::ConditionText)); + return nullptr; + } + set_options.Set(eCondition); } std::unique_ptr<CommandData> cmd_data_up; @@ -241,7 +257,7 @@ std::unique_ptr<BreakpointOptions> BreakpointOptions::CreateFromStructuredData( } auto bp_options = llvm::make_unique<BreakpointOptions>( - condition_text.c_str(), enabled, ignore_count, one_shot); + condition_ref.str().c_str(), enabled, ignore_count, one_shot); if (cmd_data_up.get()) { if (cmd_data_up->interpreter == eScriptLanguageNone) bp_options->SetCommandDataCallback(cmd_data_up); @@ -293,14 +309,20 @@ std::unique_ptr<BreakpointOptions> BreakpointOptions::CreateFromStructuredData( StructuredData::ObjectSP BreakpointOptions::SerializeToStructuredData() { StructuredData::DictionarySP options_dict_sp( new StructuredData::Dictionary()); - options_dict_sp->AddBooleanItem(GetKey(OptionNames::EnabledState), m_enabled); - options_dict_sp->AddBooleanItem(GetKey(OptionNames::OneShotState), - m_one_shot); - options_dict_sp->AddIntegerItem(GetKey(OptionNames::IgnoreCount), - m_ignore_count); - options_dict_sp->AddStringItem(GetKey(OptionNames::ConditionText), - m_condition_text); - if (m_baton_is_command_baton) { + if (m_set_flags.Set(eEnabled)) + options_dict_sp->AddBooleanItem(GetKey(OptionNames::EnabledState), + m_enabled); + if (m_set_flags.Set(eOneShot)) + options_dict_sp->AddBooleanItem(GetKey(OptionNames::OneShotState), + m_one_shot); + if (m_set_flags.Set(eIgnoreCount)) + options_dict_sp->AddIntegerItem(GetKey(OptionNames::IgnoreCount), + m_ignore_count); + if (m_set_flags.Set(eCondition)) + options_dict_sp->AddStringItem(GetKey(OptionNames::ConditionText), + m_condition_text); + + if (m_set_flags.Set(eCallback) && m_baton_is_command_baton) { auto cmd_baton = std::static_pointer_cast<CommandBaton>(m_callback_baton_sp); StructuredData::ObjectSP commands_sp = @@ -310,7 +332,7 @@ StructuredData::ObjectSP BreakpointOptions::SerializeToStructuredData() { BreakpointOptions::CommandData::GetSerializationKey(), commands_sp); } } - if (m_thread_spec_ap) { + if (m_set_flags.Set(eThreadSpec) && m_thread_spec_ap) { StructuredData::ObjectSP thread_spec_sp = m_thread_spec_ap->SerializeToStructuredData(); options_dict_sp->AddItem(ThreadSpec::GetSerializationKey(), thread_spec_sp); @@ -340,6 +362,7 @@ void BreakpointOptions::SetCallback(BreakpointHitCallback callback, m_callback = callback; m_callback_baton_sp = callback_baton_sp; m_baton_is_command_baton = false; + m_set_flags.Set(eCallback); } void BreakpointOptions::SetCallback( @@ -350,6 +373,7 @@ void BreakpointOptions::SetCallback( m_callback = callback; m_callback_baton_sp = callback_baton_sp; m_baton_is_command_baton = true; + m_set_flags.Set(eCallback); } void BreakpointOptions::ClearCallback() { @@ -357,6 +381,7 @@ void BreakpointOptions::ClearCallback() { m_callback_is_synchronous = false; m_callback_baton_sp.reset(); m_baton_is_command_baton = false; + m_set_flags.Clear(eCallback); } Baton *BreakpointOptions::GetBaton() { return m_callback_baton_sp.get(); } @@ -395,8 +420,12 @@ bool BreakpointOptions::GetCommandLineCallbacks(StringList &command_list) { } void BreakpointOptions::SetCondition(const char *condition) { - if (!condition) + if (!condition || condition[0] == '\0') { condition = ""; + m_set_flags.Clear(eCondition); + } + else + m_set_flags.Set(eCondition); m_condition_text.assign(condition); std::hash<std::string> hasher; @@ -427,11 +456,13 @@ ThreadSpec *BreakpointOptions::GetThreadSpec() { void BreakpointOptions::SetThreadID(lldb::tid_t thread_id) { GetThreadSpec()->SetTID(thread_id); + m_set_flags.Set(eThreadSpec); } void BreakpointOptions::SetThreadSpec( std::unique_ptr<ThreadSpec> &thread_spec_up) { m_thread_spec_ap = std::move(thread_spec_up); + m_set_flags.Set(eThreadSpec); } void BreakpointOptions::GetDescription(Stream *s, @@ -520,6 +551,7 @@ void BreakpointOptions::SetCommandDataCallback( cmd_data->interpreter = eScriptLanguageNone; auto baton_sp = std::make_shared<CommandBaton>(std::move(cmd_data)); SetCallback(BreakpointOptions::BreakpointOptionsCallbackFunction, baton_sp); + m_set_flags.Set(eCallback); } bool BreakpointOptions::BreakpointOptionsCallbackFunction( diff --git a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp index de491195310..ecb00f9a339 100644 --- a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp +++ b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp @@ -673,48 +673,49 @@ protected: target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get(); if (bp) { - const BreakpointOptions *bp_options = nullptr; + BreakpointLocationSP bp_loc_sp; if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) { - BreakpointLocationSP bp_loc_sp( - bp->FindLocationByID(cur_bp_id.GetLocationID())); - if (bp_loc_sp) - bp_options = bp_loc_sp->GetOptionsNoCreate(); - else { + bp_loc_sp = bp->FindLocationByID(cur_bp_id.GetLocationID()); + if (!bp_loc_sp) + { result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n", cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID()); result.SetStatus(eReturnStatusFailed); return false; } - } else { - bp_options = bp->GetOptions(); } - if (bp_options) { - StreamString id_str; - BreakpointID::GetCanonicalReference(&id_str, - cur_bp_id.GetBreakpointID(), - cur_bp_id.GetLocationID()); - const Baton *baton = bp_options->GetBaton(); - if (baton) { - result.GetOutputStream().Printf("Breakpoint %s:\n", - id_str.GetData()); - result.GetOutputStream().IndentMore(); - baton->GetDescription(&result.GetOutputStream(), - eDescriptionLevelFull); - result.GetOutputStream().IndentLess(); - } else { - result.AppendMessageWithFormat( - "Breakpoint %s does not have an associated command.\n", - id_str.GetData()); - } + StreamString id_str; + BreakpointID::GetCanonicalReference(&id_str, + cur_bp_id.GetBreakpointID(), + cur_bp_id.GetLocationID()); + const Baton *baton = nullptr; + if (bp_loc_sp) + baton = bp_loc_sp + ->GetOptionsSpecifyingKind(BreakpointOptions::eCallback) + ->GetBaton(); + else + baton = bp->GetOptions()->GetBaton(); + + if (baton) { + result.GetOutputStream().Printf("Breakpoint %s:\n", + id_str.GetData()); + result.GetOutputStream().IndentMore(); + baton->GetDescription(&result.GetOutputStream(), + eDescriptionLevelFull); + result.GetOutputStream().IndentLess(); + } else { + result.AppendMessageWithFormat( + "Breakpoint %s does not have an associated command.\n", + id_str.GetData()); } - result.SetStatus(eReturnStatusSuccessFinishResult); - } else { - result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", - cur_bp_id.GetBreakpointID()); - result.SetStatus(eReturnStatusFailed); } + result.SetStatus(eReturnStatusSuccessFinishResult); + } else { + result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", + cur_bp_id.GetBreakpointID()); + result.SetStatus(eReturnStatusFailed); } } } |