From 2d3628e1f0c52db37d53061f2113e90e52ca0200 Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Thu, 22 Sep 2016 23:42:42 +0000 Subject: [PATCH] Add the ability to append breakpoints to the save file. llvm-svn: 282212 --- lldb/include/lldb/API/SBTarget.h | 8 ++- lldb/include/lldb/Target/Target.h | 2 +- .../serialize/TestBreakpointSerialization.py | 60 ++++++++++++++++++- lldb/scripts/interface/SBTarget.i | 9 ++- lldb/source/API/SBTarget.cpp | 7 ++- .../Commands/CommandObjectBreakpoint.cpp | 11 +++- lldb/source/Target/Target.cpp | 32 ++++++++-- 7 files changed, 113 insertions(+), 16 deletions(-) diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h index 7ef230b2fe34..a4503ae88a90 100644 --- a/lldb/include/lldb/API/SBTarget.h +++ b/lldb/include/lldb/API/SBTarget.h @@ -703,11 +703,17 @@ public: /// @param[in] bkpt_list /// Only write breakpoints from this list. /// + /// @param[in] append + /// If \btrue, append the breakpoints in bkpt_list to the others + /// serialized in dest_file. If dest_file doesn't exist, then a new + /// file will be created and the breakpoints in bkpt_list written to it. + /// /// @return /// An SBError detailing any errors in writing in the breakpoints. //------------------------------------------------------------------ lldb::SBError BreakpointsWriteToFile(SBFileSpec &dest_file, - SBBreakpointList &bkpt_list); + SBBreakpointList &bkpt_list, + bool append = false); uint32_t GetNumBreakpoints() const; diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 226c5f0e956b..a6282fe038ef 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -679,7 +679,7 @@ public: bool IgnoreWatchpointByID(lldb::watch_id_t watch_id, uint32_t ignore_count); Error SerializeBreakpointsToFile(const FileSpec &file, - const BreakpointIDList &bp_ids); + const BreakpointIDList &bp_ids, bool append); Error CreateBreakpointsFromFile(const FileSpec &file, BreakpointIDList &new_bps); 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 044aba9ecca7..f550063038a6 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_appending(self): + """Use Python APIs to test that we serialize breakpoint options correctly.""" + self.build() + self.setup_targets_and_cleanup() + self.do_check_appending() + def test_name_filters(self): """Use python APIs to test that reading in by name works correctly.""" self.build() @@ -70,11 +76,13 @@ class BreakpointSerialization(TestBase): self.bkpts_file_path = os.path.join(os.getcwd(), "breakpoints.json") self.bkpts_file_spec = lldb.SBFileSpec(self.bkpts_file_path) - def check_equivalence(self, source_bps): + def check_equivalence(self, source_bps, do_write = True): error = lldb.SBError() - error = self.orig_target.BreakpointsWriteToFile(self.bkpts_file_spec, source_bps) - self.assertTrue(error.Success(), "Failed writing breakpoints to file: %s."%(error.GetCString())) + + if (do_write): + error = self.orig_target.BreakpointsWriteToFile(self.bkpts_file_spec, source_bps) + self.assertTrue(error.Success(), "Failed writing breakpoints to file: %s."%(error.GetCString())) copy_bps = lldb.SBBreakpointList(self.copy_target) error = self.copy_target.BreakpointsCreateFromFile(self.bkpts_file_spec, copy_bps) @@ -205,6 +213,52 @@ class BreakpointSerialization(TestBase): self.check_equivalence(source_bps) + def do_check_appending(self): + """Use Python APIs to check appending to already serialized options.""" + + empty_module_list = lldb.SBFileSpecList() + empty_cu_list = lldb.SBFileSpecList() + blubby_file_spec = lldb.SBFileSpec(os.path.join(os.getcwd(), "blubby.c")) + + # It isn't actually important for these purposes that these breakpoint + # actually have locations. + + all_bps = lldb.SBBreakpointList(self.orig_target) + source_bps = lldb.SBBreakpointList(self.orig_target) + + bkpt = self.orig_target.BreakpointCreateByLocation("blubby.c", 666) + bkpt.SetEnabled(False) + bkpt.SetOneShot(True) + bkpt.SetThreadID(10) + source_bps.Append(bkpt) + all_bps.Append(bkpt) + + error = lldb.SBError() + error = self.orig_target.BreakpointsWriteToFile(self.bkpts_file_spec, source_bps) + self.assertTrue(error.Success(), "Failed writing breakpoints to file: %s."%(error.GetCString())) + + source_bps.Clear() + + bkpt = self.orig_target.BreakpointCreateByName("blubby", lldb.eFunctionNameTypeAuto, empty_module_list, empty_cu_list) + bkpt.SetIgnoreCount(10) + bkpt.SetThreadName("grubby") + source_bps.Append(bkpt) + all_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") + + source_bps.Append(bkpt) + all_bps.Append(bkpt) + + error = self.orig_target.BreakpointsWriteToFile(self.bkpts_file_spec, source_bps, True) + self.assertTrue(error.Success(), "Failed appending breakpoints to file: %s."%(error.GetCString())) + + self.check_equivalence(all_bps) + def do_check_names(self): bkpt = self.orig_target.BreakpointCreateByLocation("blubby.c", 666) good_bkpt_name = "GoodBreakpoint" diff --git a/lldb/scripts/interface/SBTarget.i b/lldb/scripts/interface/SBTarget.i index 9a9cc63531d3..c1d749c7ce75 100644 --- a/lldb/scripts/interface/SBTarget.i +++ b/lldb/scripts/interface/SBTarget.i @@ -786,12 +786,19 @@ public: /// @param[in] bkpt_list /// Only write breakpoints from this list. /// + /// @param[in] append + /// If \btrue, append the breakpoints in bkpt_list to the others + /// serialized in dest_file. If dest_file doesn't exist, then a new + /// file will be created and the breakpoints in bkpt_list written to it. + /// /// @return /// An SBError detailing any errors in writing in the breakpoints. //------------------------------------------------------------------ ") BreakpointsCreateFromFile; lldb::SBError - BreakpointsWriteToFile(SBFileSpec &dest_file, SBBreakpointList &bkpt_list); + BreakpointsWriteToFile(SBFileSpec &dest_file, + SBBreakpointList &bkpt_list, + bool append = false); uint32_t GetNumWatchpoints () const; diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp index 54ed0989daf8..7515343e0445 100644 --- a/lldb/source/API/SBTarget.cpp +++ b/lldb/source/API/SBTarget.cpp @@ -1176,7 +1176,8 @@ lldb::SBError SBTarget::BreakpointsWriteToFile(SBFileSpec &dest_file) { } lldb::SBError SBTarget::BreakpointsWriteToFile(SBFileSpec &dest_file, - SBBreakpointList &bkpt_list) { + SBBreakpointList &bkpt_list, + bool append) { SBError sberr; TargetSP target_sp(GetSP()); if (!target_sp) { @@ -1187,8 +1188,8 @@ lldb::SBError SBTarget::BreakpointsWriteToFile(SBFileSpec &dest_file, std::lock_guard guard(target_sp->GetAPIMutex()); BreakpointIDList bp_id_list; bkpt_list.CopyToBreakpointIDList(bp_id_list); - sberr.ref() = - target_sp->SerializeBreakpointsToFile(dest_file.ref(), bp_id_list); + sberr.ref() = target_sp->SerializeBreakpointsToFile(dest_file.ref(), + bp_id_list, append); return sberr; } diff --git a/lldb/source/Commands/CommandObjectBreakpoint.cpp b/lldb/source/Commands/CommandObjectBreakpoint.cpp index 1e90b57abcf7..cb6d1d83907c 100644 --- a/lldb/source/Commands/CommandObjectBreakpoint.cpp +++ b/lldb/source/Commands/CommandObjectBreakpoint.cpp @@ -2210,7 +2210,8 @@ private: #pragma mark Write::CommandOptions static OptionDefinition g_breakpoint_write_options[] = { // clang-format off - { LLDB_OPT_SET_ALL, true, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eDiskFileCompletion, eArgTypeFilename, "The file into which to write the breakpoints." }, + { LLDB_OPT_SET_ALL, true, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eDiskFileCompletion, eArgTypeFilename, "The file into which to write the breakpoints." }, + { LLDB_OPT_SET_ALL, false, "append",'a', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Append to saved breakpoints file if it exists."}, // clang-format on }; @@ -2251,6 +2252,9 @@ public: case 'f': m_filename.assign(option_arg); break; + case 'a': + m_append = true; + break; default: error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); @@ -2262,6 +2266,7 @@ public: void OptionParsingStarting(ExecutionContext *execution_context) override { m_filename.clear(); + m_append = false; } llvm::ArrayRef GetDefinitions() override { @@ -2271,6 +2276,7 @@ public: // Instance variables to hold the values for command options. std::string m_filename; + bool m_append = false; }; protected: @@ -2296,7 +2302,8 @@ protected: } } Error error = target->SerializeBreakpointsToFile( - FileSpec(m_options.m_filename.c_str(), true), valid_bp_ids); + FileSpec(m_options.m_filename.c_str(), true), valid_bp_ids, + m_options.m_append); if (!error.Success()) { result.AppendErrorWithFormat("error serializing breakpoints: %s.", error.AsCString()); diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index d73cc84a1561..1fcc46608539 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -796,7 +796,8 @@ bool Target::EnableBreakpointByID(break_id_t break_id) { } Error Target::SerializeBreakpointsToFile(const FileSpec &file, - const BreakpointIDList &bp_ids) { + const BreakpointIDList &bp_ids, + bool append) { Error error; if (!file) { @@ -805,6 +806,28 @@ Error Target::SerializeBreakpointsToFile(const FileSpec &file, } std::string path(file.GetPath()); + StructuredData::ObjectSP input_data_sp; + + StructuredData::ArraySP break_store_sp; + StructuredData::Array *break_store_ptr = nullptr; + + if (append) { + input_data_sp = StructuredData::ParseJSONFromFile(file, error); + if (error.Success()) { + break_store_ptr = input_data_sp->GetAsArray(); + if (!break_store_ptr) { + error.SetErrorStringWithFormat( + "Tried to append to invalid input file %s", path.c_str()); + return error; + } + } + } + + if (!break_store_ptr) { + break_store_sp.reset(new StructuredData::Array()); + break_store_ptr = break_store_sp.get(); + } + StreamFile out_file(path.c_str(), File::OpenOptions::eOpenOptionTruncate | File::OpenOptions::eOpenOptionWrite | @@ -820,7 +843,6 @@ Error Target::SerializeBreakpointsToFile(const FileSpec &file, std::unique_lock lock; GetBreakpointList().GetListMutex(lock); - StructuredData::ArraySP break_store_sp(new StructuredData::Array()); if (bp_ids.GetSize() == 0) { const BreakpointList &breakpoints = GetBreakpointList(); @@ -830,7 +852,7 @@ Error Target::SerializeBreakpointsToFile(const FileSpec &file, StructuredData::ObjectSP bkpt_save_sp = bp->SerializeToStructuredData(); // If a breakpoint can't serialize it, just ignore it for now: if (bkpt_save_sp) - break_store_sp->AddItem(bkpt_save_sp); + break_store_ptr->AddItem(bkpt_save_sp); } } else { @@ -857,12 +879,12 @@ Error Target::SerializeBreakpointsToFile(const FileSpec &file, bp_id); return error; } - break_store_sp->AddItem(bkpt_save_sp); + break_store_ptr->AddItem(bkpt_save_sp); } } } - break_store_sp->Dump(out_file, false); + break_store_ptr->Dump(out_file, false); out_file.PutChar('\n'); return error; }