diff --git a/lldb/include/lldb/API/SBBreakpoint.h b/lldb/include/lldb/API/SBBreakpoint.h index 232db4d8afb1a..0bfd9f3d42a1a 100644 --- a/lldb/include/lldb/API/SBBreakpoint.h +++ b/lldb/include/lldb/API/SBBreakpoint.h @@ -119,6 +119,7 @@ class LLDB_API SBBreakpoint { GetNumBreakpointLocationsFromEvent(const lldb::SBEvent &event_sp); private: + friend class SBBreakpointList; friend class SBBreakpointLocation; friend class SBTarget; @@ -139,6 +140,35 @@ class LLDB_API SBBreakpoint { lldb::BreakpointSP m_opaque_sp; }; +class SBBreakpointListImpl; + +class LLDB_API SBBreakpointList { +public: + SBBreakpointList(SBTarget &target); + + ~SBBreakpointList(); + + size_t GetSize() const; + + SBBreakpoint GetBreakpointAtIndex(size_t idx); + + void Append(const SBBreakpoint &sb_file); + + bool AppendIfUnique(const SBBreakpoint &sb_file); + + void AppendByID(lldb::break_id_t id); + + void Clear(); + +protected: + friend class SBTarget; + + void CopyToBreakpointIDList(lldb_private::BreakpointIDList &bp_id_list); + +private: + std::shared_ptr m_opaque_sp; +}; + } // namespace lldb #endif // LLDB_SBBreakpoint_h_ diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h index 4ab926714e63c..c7d99b1849e6b 100644 --- a/lldb/include/lldb/API/SBTarget.h +++ b/lldb/include/lldb/API/SBTarget.h @@ -16,6 +16,7 @@ // Project includes #include "lldb/API/SBAddress.h" #include "lldb/API/SBAttachInfo.h" +#include "lldb/API/SBBreakpoint.h" #include "lldb/API/SBBroadcaster.h" #include "lldb/API/SBDefines.h" #include "lldb/API/SBFileSpec.h" @@ -641,6 +642,18 @@ class LLDB_API SBTarget { lldb::SBBreakpoint BreakpointCreateBySBAddress(SBAddress &address); + // Reads in breakpoints from source_file, returning the newly created + // breakpoints in new_bps. + lldb::SBError BreakpointsCreateFromFile(SBFileSpec &source_file, + SBBreakpointList &new_bps); + + // Writes all breakpoints to dest_file. + lldb::SBError BreakpointsWriteToFile(SBFileSpec &dest_file); + + // Writes the breakpoints in bkpt_list to dest_file + lldb::SBError BreakpointsWriteToFile(SBFileSpec &dest_file, + SBBreakpointList &bkpt_list); + uint32_t GetNumBreakpoints() const; lldb::SBBreakpoint GetBreakpointAtIndex(uint32_t idx) const; @@ -741,6 +754,7 @@ class LLDB_API SBTarget { protected: friend class SBAddress; friend class SBBlock; + friend class SBBreakpointListImpl; friend class SBDebugger; friend class SBExecutionContext; friend class SBFunction; diff --git a/lldb/include/lldb/Core/StructuredData.h b/lldb/include/lldb/Core/StructuredData.h index 321fee62e672d..efd8100f1185e 100644 --- a/lldb/include/lldb/Core/StructuredData.h +++ b/lldb/include/lldb/Core/StructuredData.h @@ -552,7 +552,7 @@ class StructuredData { static ObjectSP ParseJSON(std::string json_text); - static ObjectSP ParseJSONFromFile(FileSpec &file, Error &error); + static ObjectSP ParseJSONFromFile(const FileSpec &file, Error &error); }; } // namespace lldb_private diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index de9cbbc08866b..88498f0a5ba05 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -678,6 +678,12 @@ class Target : public std::enable_shared_from_this, bool IgnoreWatchpointByID(lldb::watch_id_t watch_id, uint32_t ignore_count); + Error SerializeBreakpointsToFile(const FileSpec &file, + const BreakpointIDList &bp_ids); + + Error CreateBreakpointsFromFile(const FileSpec &file, + BreakpointIDList &new_bps); + //------------------------------------------------------------------ /// Get \a load_addr as a callable code load address for this target /// @@ -1191,10 +1197,10 @@ class Target : public std::enable_shared_from_this, Debugger &m_debugger; lldb::PlatformSP m_platform_sp; ///< The platform for this target. std::recursive_mutex m_mutex; ///< An API mutex that is used by the lldb::SB* - ///classes make the SB interface thread safe + /// classes make the SB interface thread safe ArchSpec m_arch; ModuleList m_images; ///< The list of images for this process (shared - ///libraries and anything dynamically loaded). + /// libraries and anything dynamically loaded). SectionLoadHistory m_section_load_history; BreakpointList m_breakpoint_list; BreakpointList m_internal_breakpoint_list; diff --git a/lldb/scripts/interface/SBBreakpoint.i b/lldb/scripts/interface/SBBreakpoint.i index 6394d741b8517..f36027722a3d3 100644 --- a/lldb/scripts/interface/SBBreakpoint.i +++ b/lldb/scripts/interface/SBBreakpoint.i @@ -263,4 +263,29 @@ public: }; +class SBBreakpointListImpl; + +class LLDB_API SBBreakpointList +{ +public: + SBBreakpointList(SBTarget &target); + + ~SBBreakpointList(); + + size_t GetSize() const; + + SBBreakpoint + GetBreakpointAtIndex(size_t idx); + + void Append(const SBBreakpoint &sb_bkpt); + + bool AppendIfUnique(const SBBreakpoint &sb_bkpt); + + void AppendByID (lldb::break_id_t id); + + void Clear(); +private: + std::shared_ptr m_opaque_sp; +}; + } // namespace lldb diff --git a/lldb/scripts/interface/SBTarget.i b/lldb/scripts/interface/SBTarget.i index 12494142866bf..f907dcc181dfd 100644 --- a/lldb/scripts/interface/SBTarget.i +++ b/lldb/scripts/interface/SBTarget.i @@ -713,6 +713,16 @@ public: bool DeleteAllBreakpoints (); + lldb::SBError + BreakpointsCreateFromFile(SBFileSpec &source_file, + SBBreakpointList &bkpt_list); + + lldb::SBError + BreakpointsWriteToFile(SBFileSpec &dest_file); + + lldb::SBError + BreakpointsWriteToFile(SBFileSpec &dest_file, SBBreakpointList &bkpt_list); + uint32_t GetNumWatchpoints () const; diff --git a/lldb/source/API/SBBreakpoint.cpp b/lldb/source/API/SBBreakpoint.cpp index bbdb23766cc4f..800ad0a277fce 100644 --- a/lldb/source/API/SBBreakpoint.cpp +++ b/lldb/source/API/SBBreakpoint.cpp @@ -21,6 +21,7 @@ #include "lldb/API/SBThread.h" #include "lldb/Breakpoint/Breakpoint.h" +#include "lldb/Breakpoint/BreakpointIDList.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Core/Address.h" @@ -678,3 +679,128 @@ SBBreakpoint::GetNumBreakpointLocationsFromEvent(const lldb::SBEvent &event) { event.GetSP())); return num_locations; } + +// This is simple collection of breakpoint id's and their target. +class lldb::SBBreakpointListImpl { +public: + SBBreakpointListImpl(SBTarget &target) : m_target_wp() { + if (target.IsValid()) + m_target_wp = target.GetSP(); + } + + ~SBBreakpointListImpl() = default; + + size_t GetSize() { return m_break_ids.size(); } + + BreakpointSP GetBreakpointAtIndex(size_t idx) { + if (idx >= m_break_ids.size()) + return BreakpointSP(); + TargetSP target_sp = m_target_wp.lock(); + if (!target_sp) + return BreakpointSP(); + lldb::break_id_t bp_id = m_break_ids[idx]; + return target_sp->GetBreakpointList().FindBreakpointByID(bp_id); + } + + bool Append(Breakpoint &bkpt) { + TargetSP target_sp = m_target_wp.lock(); + if (!target_sp) + return false; + if (bkpt.GetTargetSP() != target_sp) + return false; + m_break_ids.push_back(bkpt.GetID()); + return true; + } + + bool AppendIfUnique(Breakpoint &bkpt) { + TargetSP target_sp = m_target_wp.lock(); + if (!target_sp) + return false; + if (bkpt.GetTargetSP() != target_sp) + return false; + lldb::break_id_t bp_id = bkpt.GetID(); + if (find(m_break_ids.begin(), m_break_ids.end(), bp_id) == + m_break_ids.end()) + return false; + + m_break_ids.push_back(bkpt.GetID()); + return true; + } + + bool AppendByID(lldb::break_id_t id) { + TargetSP target_sp = m_target_wp.lock(); + if (!target_sp) + return false; + if (id == LLDB_INVALID_BREAK_ID) + return false; + m_break_ids.push_back(id); + return true; + } + + void Clear() { m_break_ids.clear(); } + + void CopyToBreakpointIDList(lldb_private::BreakpointIDList &bp_list) { + for (lldb::break_id_t id : m_break_ids) { + bp_list.AddBreakpointID(BreakpointID(id)); + } + } + + TargetSP GetTarget() { return m_target_wp.lock(); } + +private: + std::vector m_break_ids; + TargetWP m_target_wp; +}; + +SBBreakpointList::SBBreakpointList(SBTarget &target) + : m_opaque_sp(new lldb::SBBreakpointListImpl(target)) {} + +SBBreakpointList::~SBBreakpointList() {} + +size_t SBBreakpointList::GetSize() const { + if (!m_opaque_sp) + return 0; + else + return m_opaque_sp->GetSize(); +} + +SBBreakpoint SBBreakpointList::GetBreakpointAtIndex(size_t idx) { + if (!m_opaque_sp) + return SBBreakpoint(); + + BreakpointSP bkpt_sp = m_opaque_sp->GetBreakpointAtIndex(idx); + return SBBreakpoint(bkpt_sp); +} + +void SBBreakpointList::Append(const SBBreakpoint &sb_bkpt) { + if (!sb_bkpt.IsValid()) + return; + if (!m_opaque_sp) + return; + m_opaque_sp->Append(*sb_bkpt.get()); +} + +void SBBreakpointList::AppendByID(lldb::break_id_t id) { + if (!m_opaque_sp) + return; + m_opaque_sp->AppendByID(id); +} + +bool SBBreakpointList::AppendIfUnique(const SBBreakpoint &sb_bkpt) { + if (!sb_bkpt.IsValid()) + return false; + if (!m_opaque_sp) + return false; + return m_opaque_sp->AppendIfUnique(*sb_bkpt.get()); +} + +void SBBreakpointList::Clear() { + if (m_opaque_sp) + m_opaque_sp->Clear(); +} + +void SBBreakpointList::CopyToBreakpointIDList( + lldb_private::BreakpointIDList &bp_id_list) { + if (m_opaque_sp) + m_opaque_sp->CopyToBreakpointIDList(bp_id_list); +} diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp index 5ada7fb8a30e4..66d375aa4578c 100644 --- a/lldb/source/API/SBTarget.cpp +++ b/lldb/source/API/SBTarget.cpp @@ -1097,6 +1097,58 @@ bool SBTarget::DeleteAllBreakpoints() { return false; } +lldb::SBError SBTarget::BreakpointsCreateFromFile(SBFileSpec &source_file, + SBBreakpointList &new_bps) { + SBError sberr; + TargetSP target_sp(GetSP()); + if (!target_sp) { + sberr.SetErrorString( + "BreakpointCreateFromFile called with invalid target."); + return sberr; + } + std::lock_guard guard(target_sp->GetAPIMutex()); + + BreakpointIDList bp_ids; + sberr.ref() = target_sp->CreateBreakpointsFromFile(source_file.ref(), bp_ids); + if (sberr.Fail()) + return sberr; + + size_t num_bkpts = bp_ids.GetSize(); + for (size_t i = 0; i < num_bkpts; i++) { + BreakpointID bp_id = bp_ids.GetBreakpointIDAtIndex(i); + new_bps.AppendByID(bp_id.GetBreakpointID()); + } + return sberr; +} + +lldb::SBError SBTarget::BreakpointsWriteToFile(SBFileSpec &dest_file) { + SBError sberr; + TargetSP target_sp(GetSP()); + if (!target_sp) { + sberr.SetErrorString("BreakpointWriteToFile called with invalid target."); + return sberr; + } + SBBreakpointList bkpt_list(*this); + return BreakpointsWriteToFile(dest_file, bkpt_list); +} + +lldb::SBError SBTarget::BreakpointsWriteToFile(SBFileSpec &dest_file, + SBBreakpointList &bkpt_list) { + SBError sberr; + TargetSP target_sp(GetSP()); + if (!target_sp) { + sberr.SetErrorString("BreakpointWriteToFile called with invalid target."); + return sberr; + } + + 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); + return sberr; +} + uint32_t SBTarget::GetNumWatchpoints() const { TargetSP target_sp(GetSP()); if (target_sp) { diff --git a/lldb/source/Commands/CommandObjectBreakpoint.cpp b/lldb/source/Commands/CommandObjectBreakpoint.cpp index 222bb5f4601df..c5576e527e223 100644 --- a/lldb/source/Commands/CommandObjectBreakpoint.cpp +++ b/lldb/source/Commands/CommandObjectBreakpoint.cpp @@ -2155,57 +2155,16 @@ class CommandObjectBreakpointRead : public CommandObjectParsed { return false; } - std::unique_lock lock; - target->GetBreakpointList().GetListMutex(lock); - FileSpec input_spec(m_options.m_filename, true); - Error error; - StructuredData::ObjectSP input_data_sp = - StructuredData::ParseJSONFromFile(input_spec, error); - if (!error.Success()) { - result.AppendErrorWithFormat("Error reading data from input file: %s.", - error.AsCString()); - result.SetStatus(eReturnStatusFailed); - return false; - } else if (!input_data_sp || !input_data_sp->IsValid()) { - result.AppendErrorWithFormat("Invalid JSON from input file: %s.", - input_spec.GetPath().c_str()); - result.SetStatus(eReturnStatusFailed); - return false; - } + BreakpointIDList new_bps; + Error error = target->CreateBreakpointsFromFile(input_spec, new_bps); - StructuredData::Array *bkpt_array = input_data_sp->GetAsArray(); - if (!bkpt_array) { - result.AppendErrorWithFormat( - "Invalid breakpoint data from input file: %s.", - input_spec.GetPath().c_str()); + if (!error.Success()) { + result.AppendError(error.AsCString()); result.SetStatus(eReturnStatusFailed); return false; } - - size_t num_bkpts = bkpt_array->GetSize(); - 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: - StructuredData::Dictionary *bkpt_dict = bkpt_object_sp->GetAsDictionary(); - if (!bkpt_dict) { - result.AppendErrorWithFormat( - "Invalid breakpoint data for element %zu from input file: %s.", i, - input_spec.GetPath().c_str()); - result.SetStatus(eReturnStatusFailed); - return false; - } - StructuredData::ObjectSP bkpt_data_sp = - bkpt_dict->GetValueForKey(Breakpoint::GetSerializationKey()); - BreakpointSP bkpt_sp = - Breakpoint::CreateFromStructuredData(*target, bkpt_data_sp, error); - if (!error.Success()) { - result.AppendErrorWithFormat( - "Error restoring breakpoint %zu from %s: %s.", i, - input_spec.GetPath().c_str(), error.AsCString()); - result.SetStatus(eReturnStatusFailed); - } - } + // FIXME: Report the newly created breakpoints. return result.Succeeded(); } @@ -2295,78 +2254,26 @@ class CommandObjectBreakpointWrite : public CommandObjectParsed { return false; } - // Before we do anything else make sure we can actually write to this file: - StreamFile out_file(m_options.m_filename.c_str(), - File::OpenOptions::eOpenOptionTruncate | - File::OpenOptions::eOpenOptionWrite | - File::OpenOptions::eOpenOptionCanCreate | - File::OpenOptions::eOpenOptionCloseOnExec, - lldb::eFilePermissionsFileDefault); - if (!out_file.GetFile().IsValid()) { - result.AppendErrorWithFormat("Unable to open output file: %s.", - m_options.m_filename.c_str()); - result.SetStatus(eReturnStatusFailed); - return false; - } - std::unique_lock lock; target->GetBreakpointList().GetListMutex(lock); - StructuredData::ArraySP break_store_sp(new StructuredData::Array()); - - if (command.GetArgumentCount() == 0) { - const BreakpointList &breakpoints = target->GetBreakpointList(); - - size_t num_breakpoints = breakpoints.GetSize(); - for (size_t i = 0; i < num_breakpoints; i++) { - Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get(); - 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); - } - } else { - - BreakpointIDList valid_bp_ids; - + BreakpointIDList valid_bp_ids; + if (command.GetArgumentCount() > 0) { CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs( command, target, result, &valid_bp_ids); - if (result.Succeeded()) { - std::unordered_set processed_bkpts; - const size_t count = valid_bp_ids.GetSize(); - for (size_t i = 0; i < count; ++i) { - BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i); - lldb::break_id_t bp_id = cur_bp_id.GetBreakpointID(); - - if (bp_id != LLDB_INVALID_BREAK_ID) { - // Only do each breakpoint once: - std::pair::iterator, bool> - insert_result = processed_bkpts.insert(bp_id); - if (!insert_result.second) - continue; - - Breakpoint *bp = target->GetBreakpointByID(bp_id).get(); - StructuredData::ObjectSP bkpt_save_sp = - bp->SerializeToStructuredData(); - // If the user explicitly asked to serialize a breakpoint, and we - // can't, then - // raise an error: - if (!bkpt_save_sp) { - result.AppendErrorWithFormat("Unable to serialize breakpoint %d", - bp_id); - result.SetStatus(eReturnStatusFailed); - return false; - } - break_store_sp->AddItem(bkpt_save_sp); - } - } + if (!result.Succeeded()) { + result.SetStatus(eReturnStatusFailed); + return false; } } - - break_store_sp->Dump(out_file, false); - out_file.PutChar('\n'); - + Error error = target->SerializeBreakpointsToFile( + FileSpec(m_options.m_filename.c_str(), true), valid_bp_ids); + if (!error.Success()) { + result.AppendErrorWithFormat("error serializing breakpoints: %s.", + error.AsCString()); + result.SetStatus(eReturnStatusFailed); + } return result.Succeeded(); } diff --git a/lldb/source/Core/StructuredData.cpp b/lldb/source/Core/StructuredData.cpp index 22c3dd8b9095d..3866861b8c178 100644 --- a/lldb/source/Core/StructuredData.cpp +++ b/lldb/source/Core/StructuredData.cpp @@ -31,8 +31,8 @@ static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser); static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser); static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser); -StructuredData::ObjectSP StructuredData::ParseJSONFromFile(FileSpec &input_spec, - Error &error) { +StructuredData::ObjectSP +StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Error &error) { StructuredData::ObjectSP return_sp; if (!input_spec.Exists()) { error.SetErrorStringWithFormat("input file %s does not exist.", diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index bd8ae563319db..0b612c6ddaecd 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -15,6 +15,7 @@ #include "Plugins/ExpressionParser/Clang/ClangASTSource.h" #include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h" #include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" +#include "lldb/Breakpoint/BreakpointIDList.h" #include "lldb/Breakpoint/BreakpointResolver.h" #include "lldb/Breakpoint/BreakpointResolverAddress.h" #include "lldb/Breakpoint/BreakpointResolverFileLine.h" @@ -794,6 +795,127 @@ bool Target::EnableBreakpointByID(break_id_t break_id) { return false; } +Error Target::SerializeBreakpointsToFile(const FileSpec &file, + const BreakpointIDList &bp_ids) { + Error error; + + if (!file) { + error.SetErrorString("Invalid FileSpec."); + return error; + } + + std::string path(file.GetPath()); + StreamFile out_file(path.c_str(), + File::OpenOptions::eOpenOptionTruncate | + File::OpenOptions::eOpenOptionWrite | + File::OpenOptions::eOpenOptionCanCreate | + File::OpenOptions::eOpenOptionCloseOnExec, + lldb::eFilePermissionsFileDefault); + if (!out_file.GetFile().IsValid()) { + error.SetErrorStringWithFormat("Unable to open output file: %s.", + path.c_str()); + return error; + } + + std::unique_lock lock; + GetBreakpointList().GetListMutex(lock); + + StructuredData::ArraySP break_store_sp(new StructuredData::Array()); + if (bp_ids.GetSize() == 0) { + const BreakpointList &breakpoints = GetBreakpointList(); + + size_t num_breakpoints = breakpoints.GetSize(); + for (size_t i = 0; i < num_breakpoints; i++) { + Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get(); + 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); + } + } else { + + std::unordered_set processed_bkpts; + const size_t count = bp_ids.GetSize(); + for (size_t i = 0; i < count; ++i) { + BreakpointID cur_bp_id = bp_ids.GetBreakpointIDAtIndex(i); + lldb::break_id_t bp_id = cur_bp_id.GetBreakpointID(); + + if (bp_id != LLDB_INVALID_BREAK_ID) { + // Only do each breakpoint once: + std::pair::iterator, bool> + insert_result = processed_bkpts.insert(bp_id); + if (!insert_result.second) + continue; + + Breakpoint *bp = GetBreakpointByID(bp_id).get(); + StructuredData::ObjectSP bkpt_save_sp = bp->SerializeToStructuredData(); + // If the user explicitly asked to serialize a breakpoint, and we + // can't, then + // raise an error: + if (!bkpt_save_sp) { + error.SetErrorStringWithFormat("Unable to serialize breakpoint %d", + bp_id); + return error; + } + break_store_sp->AddItem(bkpt_save_sp); + } + } + } + + break_store_sp->Dump(out_file, false); + out_file.PutChar('\n'); + return error; +} + +Error Target::CreateBreakpointsFromFile(const FileSpec &file, + BreakpointIDList &new_bps) { + std::unique_lock lock; + GetBreakpointList().GetListMutex(lock); + + Error error; + StructuredData::ObjectSP input_data_sp = + StructuredData::ParseJSONFromFile(file, error); + if (!error.Success()) { + return error; + } else if (!input_data_sp || !input_data_sp->IsValid()) { + error.SetErrorStringWithFormat("Invalid JSON from input file: %s.", + file.GetPath().c_str()); + return error; + } + + StructuredData::Array *bkpt_array = input_data_sp->GetAsArray(); + if (!bkpt_array) { + error.SetErrorStringWithFormat( + "Invalid breakpoint data from input file: %s.", file.GetPath().c_str()); + return error; + } + + size_t num_bkpts = bkpt_array->GetSize(); + 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: + StructuredData::Dictionary *bkpt_dict = bkpt_object_sp->GetAsDictionary(); + if (!bkpt_dict) { + error.SetErrorStringWithFormat( + "Invalid breakpoint data for element %zu from input file: %s.", i, + file.GetPath().c_str()); + return error; + } + StructuredData::ObjectSP bkpt_data_sp = + bkpt_dict->GetValueForKey(Breakpoint::GetSerializationKey()); + BreakpointSP bkpt_sp = + Breakpoint::CreateFromStructuredData(*this, bkpt_data_sp, error); + if (!error.Success()) { + error.SetErrorStringWithFormat( + "Error restoring breakpoint %zu from %s: %s.", i, + file.GetPath().c_str(), error.AsCString()); + return error; + } + new_bps.AddBreakpointID(BreakpointID(bkpt_sp->GetID())); + } + return error; +} + // The flag 'end_to_end', default to true, signifies that the operation is // performed end to end, for both the debugger and the debuggee.