From 3acdf38519923f1ce293c7bacac542804145ea7c Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Thu, 22 Sep 2016 22:20:28 +0000 Subject: [PATCH] Add the ability to deserialize only breakpoints matching a given name. Also tests for this and the ThreadSpec serialization. llvm-svn: 282207 --- lldb/include/lldb/API/SBTarget.h | 59 +++++++++++++++-- lldb/include/lldb/Breakpoint/Breakpoint.h | 4 ++ lldb/include/lldb/Target/Target.h | 4 ++ .../serialize/TestBreakpointSerialization.py | 39 +++++++++++- lldb/scripts/interface/SBTarget.i | 63 +++++++++++++++++++ lldb/source/API/SBTarget.cpp | 16 ++++- lldb/source/Breakpoint/Breakpoint.cpp | 35 +++++++++++ .../Commands/CommandObjectBreakpoint.cpp | 43 +++++++++++-- lldb/source/Target/Target.cpp | 13 ++++ 9 files changed, 264 insertions(+), 12 deletions(-) diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h index 715c37c8b3e4..7ef230b2fe34 100644 --- a/lldb/include/lldb/API/SBTarget.h +++ b/lldb/include/lldb/API/SBTarget.h @@ -646,15 +646,66 @@ public: lldb::SBBreakpoint BreakpointCreateBySBAddress(SBAddress &address); - // Reads in breakpoints from source_file, returning the newly created - // breakpoints in new_bps. + //------------------------------------------------------------------ + /// Read breakpoints from source_file and return the newly created + /// breakpoints in bkpt_list. + /// + /// @param[in] source_file + /// The file from which to read the breakpoints. + /// + /// @param[out] bkpt_list + /// A list of the newly created breakpoints. + /// + /// @return + /// An SBError detailing any errors in reading in the breakpoints. + //------------------------------------------------------------------ lldb::SBError BreakpointsCreateFromFile(SBFileSpec &source_file, SBBreakpointList &new_bps); - // Writes all breakpoints to dest_file. + //------------------------------------------------------------------ + /// Read breakpoints from source_file and return the newly created + /// breakpoints in bkpt_list. + /// + /// @param[in] source_file + /// The file from which to read the breakpoints. + /// + /// @param[in] matching_names + /// Only read in breakpoints whose names match one of the names in this + /// list. + /// + /// @param[out] bkpt_list + /// A list of the newly created breakpoints. + /// + /// @return + /// An SBError detailing any errors in reading in the breakpoints. + //------------------------------------------------------------------ + lldb::SBError BreakpointsCreateFromFile(SBFileSpec &source_file, + SBStringList &matching_names, + SBBreakpointList &new_bps); + + //------------------------------------------------------------------ + /// Write breakpoints to dest_file. + /// + /// @param[in] dest_file + /// The file to which to write the breakpoints. + /// + /// @return + /// An SBError detailing any errors in writing in the breakpoints. + //------------------------------------------------------------------ lldb::SBError BreakpointsWriteToFile(SBFileSpec &dest_file); - // Writes the breakpoints in bkpt_list to dest_file + //------------------------------------------------------------------ + /// Write breakpoints listed in bkpt_list to dest_file. + /// + /// @param[in] dest_file + /// The file to which to write the breakpoints. + /// + /// @param[in] bkpt_list + /// Only write breakpoints from this list. + /// + /// @return + /// An SBError detailing any errors in writing in the breakpoints. + //------------------------------------------------------------------ lldb::SBError BreakpointsWriteToFile(SBFileSpec &dest_file, SBBreakpointList &bkpt_list); diff --git a/lldb/include/lldb/Breakpoint/Breakpoint.h b/lldb/include/lldb/Breakpoint/Breakpoint.h index 03a92caf2c6c..9af6e586de39 100644 --- a/lldb/include/lldb/Breakpoint/Breakpoint.h +++ b/lldb/include/lldb/Breakpoint/Breakpoint.h @@ -180,6 +180,10 @@ public: static lldb::BreakpointSP CreateFromStructuredData( Target &target, StructuredData::ObjectSP &data_object_sp, Error &error); + static bool + SerializedBreakpointMatchesNames(StructuredData::ObjectSP &bkpt_object_sp, + std::vector &names); + virtual StructuredData::ObjectSP SerializeToStructuredData(); static const char *GetSerializationKey() { return "Breakpoint"; } diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 88498f0a5ba0..226c5f0e956b 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -684,6 +684,10 @@ public: Error CreateBreakpointsFromFile(const FileSpec &file, BreakpointIDList &new_bps); + Error CreateBreakpointsFromFile(const FileSpec &file, + std::vector &names, + BreakpointIDList &new_bps); + //------------------------------------------------------------------ /// Get \a load_addr as a callable code load address for this target /// diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/TestBreakpointSerialization.py b/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/TestBreakpointSerialization.py index e609d8ec4cce..044aba9ecca7 100644 --- a/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/TestBreakpointSerialization.py +++ b/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/TestBreakpointSerialization.py @@ -37,6 +37,12 @@ class BreakpointSerialization(TestBase): self.setup_targets_and_cleanup() self.do_check_options() + def test_name_filters(self): + """Use python APIs to test that reading in by name works correctly.""" + self.build() + self.setup_targets_and_cleanup() + self.do_check_names() + def setup_targets_and_cleanup(self): def cleanup (): self.RemoveTempFile(self.bkpts_file_path) @@ -50,7 +56,7 @@ class BreakpointSerialization(TestBase): exe = os.path.join(os.getcwd(), "a.out") - # Create a targets we are making breakpoint in and copying to: + # Create the targets we are making breakpoints in and copying them to: self.orig_target = self.dbg.CreateTarget(exe) self.assertTrue(self.orig_target, VALID_TARGET) @@ -169,6 +175,7 @@ class BreakpointSerialization(TestBase): bkpt = self.orig_target.BreakpointCreateByLocation("blubby.c", 666) bkpt.SetEnabled(False) bkpt.SetOneShot(True) + bkpt.SetThreadID(10) source_bps.Append(bkpt) # Make sure we get one right: @@ -177,10 +184,12 @@ class BreakpointSerialization(TestBase): bkpt = self.orig_target.BreakpointCreateByName("blubby", lldb.eFunctionNameTypeAuto, empty_module_list, empty_cu_list) bkpt.SetIgnoreCount(10) + bkpt.SetThreadName("grubby") source_bps.Append(bkpt) bkpt = self.orig_target.BreakpointCreateByName("blubby", lldb.eFunctionNameTypeFull, empty_module_list,empty_cu_list) bkpt.SetCondition("something != something_else") + bkpt.SetQueueName("grubby") bkpt.AddName("FirstName") bkpt.AddName("SecondName") @@ -196,6 +205,30 @@ class BreakpointSerialization(TestBase): self.check_equivalence(source_bps) - - + def do_check_names(self): + bkpt = self.orig_target.BreakpointCreateByLocation("blubby.c", 666) + good_bkpt_name = "GoodBreakpoint" + write_bps = lldb.SBBreakpointList(self.orig_target) + bkpt.AddName(good_bkpt_name) + write_bps.Append(bkpt) + + error = lldb.SBError() + error = self.orig_target.BreakpointsWriteToFile(self.bkpts_file_spec, write_bps) + self.assertTrue(error.Success(), "Failed writing breakpoints to file: %s."%(error.GetCString())) + + copy_bps = lldb.SBBreakpointList(self.copy_target) + names_list = lldb.SBStringList() + names_list.AppendString("NoSuchName") + + error = self.copy_target.BreakpointsCreateFromFile(self.bkpts_file_spec, names_list, copy_bps) + self.assertTrue(error.Success(), "Failed reading breakpoints from file: %s"%(error.GetCString())) + self.assertTrue(copy_bps.GetSize() == 0, "Found breakpoints with a nonexistent name.") + + names_list.AppendString(good_bkpt_name) + error = self.copy_target.BreakpointsCreateFromFile(self.bkpts_file_spec, names_list, copy_bps) + self.assertTrue(error.Success(), "Failed reading breakpoints from file: %s"%(error.GetCString())) + self.assertTrue(copy_bps.GetSize() == 1, "Found the matching breakpoint.") + + + diff --git a/lldb/scripts/interface/SBTarget.i b/lldb/scripts/interface/SBTarget.i index 6764d6973198..9a9cc63531d3 100644 --- a/lldb/scripts/interface/SBTarget.i +++ b/lldb/scripts/interface/SBTarget.i @@ -720,13 +720,76 @@ public: bool DeleteAllBreakpoints (); + %feature("docstring", " + //------------------------------------------------------------------ + /// Read breakpoints from source_file and return the newly created + /// breakpoints in bkpt_list. + /// + /// @param[in] source_file + /// The file from which to read the breakpoints + /// + /// @param[out] bkpt_list + /// A list of the newly created breakpoints. + /// + /// @return + /// An SBError detailing any errors in reading in the breakpoints. + //------------------------------------------------------------------ + ") BreakpointsCreateFromFile; lldb::SBError BreakpointsCreateFromFile(SBFileSpec &source_file, SBBreakpointList &bkpt_list); + %feature("docstring", " + //------------------------------------------------------------------ + /// Read breakpoints from source_file and return the newly created + /// breakpoints in bkpt_list. + /// + /// @param[in] source_file + /// The file from which to read the breakpoints + /// + /// @param[in] matching_names + /// Only read in breakpoints whose names match one of the names in this + /// list. + /// + /// @param[out] bkpt_list + /// A list of the newly created breakpoints. + /// + /// @return + /// An SBError detailing any errors in reading in the breakpoints. + //------------------------------------------------------------------ + ") BreakpointsCreateFromFile; + lldb::SBError BreakpointsCreateFromFile(SBFileSpec &source_file, + SBStringList &matching_names, + SBBreakpointList &new_bps); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Write breakpoints to dest_file. + /// + /// @param[in] dest_file + /// The file to which to write the breakpoints. + /// + /// @return + /// An SBError detailing any errors in writing in the breakpoints. + //------------------------------------------------------------------ + ") BreakpointsCreateFromFile; lldb::SBError BreakpointsWriteToFile(SBFileSpec &dest_file); + %feature("docstring", " + //------------------------------------------------------------------ + /// Write breakpoints listed in bkpt_list to dest_file. + /// + /// @param[in] dest_file + /// The file to which to write the breakpoints. + /// + /// @param[in] bkpt_list + /// Only write breakpoints from this list. + /// + /// @return + /// An SBError detailing any errors in writing in the breakpoints. + //------------------------------------------------------------------ + ") BreakpointsCreateFromFile; lldb::SBError BreakpointsWriteToFile(SBFileSpec &dest_file, SBBreakpointList &bkpt_list); diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp index 8616d22d0e3a..54ed0989daf8 100644 --- a/lldb/source/API/SBTarget.cpp +++ b/lldb/source/API/SBTarget.cpp @@ -1128,6 +1128,13 @@ bool SBTarget::DeleteAllBreakpoints() { lldb::SBError SBTarget::BreakpointsCreateFromFile(SBFileSpec &source_file, SBBreakpointList &new_bps) { + SBStringList empty_name_list; + return BreakpointsCreateFromFile(source_file, empty_name_list, new_bps); +} + +lldb::SBError SBTarget::BreakpointsCreateFromFile(SBFileSpec &source_file, + SBStringList &matching_names, + SBBreakpointList &new_bps) { SBError sberr; TargetSP target_sp(GetSP()); if (!target_sp) { @@ -1138,7 +1145,14 @@ lldb::SBError SBTarget::BreakpointsCreateFromFile(SBFileSpec &source_file, std::lock_guard guard(target_sp->GetAPIMutex()); BreakpointIDList bp_ids; - sberr.ref() = target_sp->CreateBreakpointsFromFile(source_file.ref(), bp_ids); + + std::vector name_vector; + size_t num_names = matching_names.GetSize(); + for (size_t i = 0; i < num_names; i++) + name_vector.push_back(matching_names.GetStringAtIndex(i)); + + sberr.ref() = target_sp->CreateBreakpointsFromFile(source_file.ref(), + name_vector, bp_ids); if (sberr.Fail()) return sberr; diff --git a/lldb/source/Breakpoint/Breakpoint.cpp b/lldb/source/Breakpoint/Breakpoint.cpp index a9666f4bc21e..9f4376c69a44 100644 --- a/lldb/source/Breakpoint/Breakpoint.cpp +++ b/lldb/source/Breakpoint/Breakpoint.cpp @@ -216,6 +216,41 @@ lldb::BreakpointSP Breakpoint::CreateFromStructuredData( return result_sp; } +bool Breakpoint::SerializedBreakpointMatchesNames( + StructuredData::ObjectSP &bkpt_object_sp, std::vector &names) { + if (!bkpt_object_sp) + return false; + + StructuredData::Dictionary *bkpt_dict = bkpt_object_sp->GetAsDictionary(); + if (!bkpt_dict) + return false; + + if (names.empty()) + return true; + + StructuredData::Array *names_array; + + bool success = + bkpt_dict->GetValueForKeyAsArray(GetKey(OptionNames::Names), names_array); + // If there are no names, it can't match these names; + if (!success) + return false; + + size_t num_names = names_array->GetSize(); + std::vector::iterator begin = names.begin(); + std::vector::iterator end = names.end(); + + for (size_t i = 0; i < num_names; i++) { + std::string name; + if (names_array->GetItemAtIndexAsString(i, name)) { + if (std::find(begin, end, name) != end) { + return true; + } + } + } + return false; +} + const lldb::TargetSP Breakpoint::GetTargetSP() { return m_target.shared_from_this(); } diff --git a/lldb/source/Commands/CommandObjectBreakpoint.cpp b/lldb/source/Commands/CommandObjectBreakpoint.cpp index 13235d7c740b..1e90b57abcf7 100644 --- a/lldb/source/Commands/CommandObjectBreakpoint.cpp +++ b/lldb/source/Commands/CommandObjectBreakpoint.cpp @@ -2077,10 +2077,11 @@ public: //------------------------------------------------------------------------- // CommandObjectBreakpointRead //------------------------------------------------------------------------- -#pragma mark Modify::CommandOptions +#pragma mark Read::CommandOptions static OptionDefinition g_breakpoint_read_options[] = { // clang-format off - { LLDB_OPT_SET_ALL, true, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eDiskFileCompletion, eArgTypeFilename, "The file from which to read the breakpoints." }, + { LLDB_OPT_SET_ALL, true, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eDiskFileCompletion, eArgTypeFilename, "The file from which to read the breakpoints." }, + {LLDB_OPT_SET_ALL, false, "breakpoint-name", 'N', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBreakpointName, "Only read in breakpoints with this name."}, // clang-format on }; @@ -2121,6 +2122,16 @@ public: case 'f': m_filename.assign(option_arg); break; + case 'N': { + Error name_error; + if (!BreakpointID::StringIsBreakpointName(llvm::StringRef(option_arg), + name_error)) { + error.SetErrorStringWithFormat("Invalid breakpoint name: %s", + name_error.AsCString()); + } + m_names.push_back(option_arg); + break; + } default: error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); @@ -2132,6 +2143,7 @@ public: void OptionParsingStarting(ExecutionContext *execution_context) override { m_filename.clear(); + m_names.clear(); } llvm::ArrayRef GetDefinitions() override { @@ -2141,6 +2153,7 @@ public: // Instance variables to hold the values for command options. std::string m_filename; + std::vector m_names; }; protected: @@ -2152,16 +2165,38 @@ protected: return false; } + std::unique_lock lock; + target->GetBreakpointList().GetListMutex(lock); + FileSpec input_spec(m_options.m_filename, true); BreakpointIDList new_bps; - Error error = target->CreateBreakpointsFromFile(input_spec, new_bps); + Error error = target->CreateBreakpointsFromFile(input_spec, + m_options.m_names, new_bps); if (!error.Success()) { result.AppendError(error.AsCString()); result.SetStatus(eReturnStatusFailed); return false; } - // FIXME: Report the newly created breakpoints. + + Stream &output_stream = result.GetOutputStream(); + + size_t num_breakpoints = new_bps.GetSize(); + if (num_breakpoints == 0) { + result.AppendMessage("No breakpoints added."); + } else { + // No breakpoint selected; show info about all currently set breakpoints. + result.AppendMessage("New breakpoints:"); + for (size_t i = 0; i < num_breakpoints; ++i) { + BreakpointID bp_id = new_bps.GetBreakpointIDAtIndex(i); + Breakpoint *bp = target->GetBreakpointList() + .FindBreakpointByID(bp_id.GetBreakpointID()) + .get(); + if (bp) + bp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial, + false); + } + } return result.Succeeded(); } diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 0b612c6ddaec..d73cc84a1561 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -869,6 +869,13 @@ Error Target::SerializeBreakpointsToFile(const FileSpec &file, Error Target::CreateBreakpointsFromFile(const FileSpec &file, BreakpointIDList &new_bps) { + std::vector no_names; + return CreateBreakpointsFromFile(file, no_names, new_bps); +} + +Error Target::CreateBreakpointsFromFile(const FileSpec &file, + std::vector &names, + BreakpointIDList &new_bps) { std::unique_lock lock; GetBreakpointList().GetListMutex(lock); @@ -891,6 +898,8 @@ Error Target::CreateBreakpointsFromFile(const FileSpec &file, } size_t num_bkpts = bkpt_array->GetSize(); + size_t num_names = names.size(); + for (size_t i = 0; i < num_bkpts; i++) { StructuredData::ObjectSP bkpt_object_sp = bkpt_array->GetItemAtIndex(i); // Peel off the breakpoint key, and feed the rest to the Breakpoint: @@ -903,6 +912,10 @@ Error Target::CreateBreakpointsFromFile(const FileSpec &file, } StructuredData::ObjectSP bkpt_data_sp = bkpt_dict->GetValueForKey(Breakpoint::GetSerializationKey()); + if (num_names && + !Breakpoint::SerializedBreakpointMatchesNames(bkpt_data_sp, names)) + continue; + BreakpointSP bkpt_sp = Breakpoint::CreateFromStructuredData(*this, bkpt_data_sp, error); if (!error.Success()) {