forked from OSchip/llvm-project
Add SB API's for writing breakpoints to & creating the from a file.
Moved the guts of the code from CommandObjectBreakpoint to Target (should have done it that way in the first place.) Added an SBBreakpointList class so there's a way to specify which breakpoints to serialize and to report the deserialized breakpoints. <rdar://problem/12611863> llvm-svn: 281520
This commit is contained in:
parent
db30877477
commit
01f1666471
|
@ -119,6 +119,7 @@ public:
|
||||||
GetNumBreakpointLocationsFromEvent(const lldb::SBEvent &event_sp);
|
GetNumBreakpointLocationsFromEvent(const lldb::SBEvent &event_sp);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend class SBBreakpointList;
|
||||||
friend class SBBreakpointLocation;
|
friend class SBBreakpointLocation;
|
||||||
friend class SBTarget;
|
friend class SBTarget;
|
||||||
|
|
||||||
|
@ -139,6 +140,35 @@ private:
|
||||||
lldb::BreakpointSP m_opaque_sp;
|
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<SBBreakpointListImpl> m_opaque_sp;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace lldb
|
} // namespace lldb
|
||||||
|
|
||||||
#endif // LLDB_SBBreakpoint_h_
|
#endif // LLDB_SBBreakpoint_h_
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
// Project includes
|
// Project includes
|
||||||
#include "lldb/API/SBAddress.h"
|
#include "lldb/API/SBAddress.h"
|
||||||
#include "lldb/API/SBAttachInfo.h"
|
#include "lldb/API/SBAttachInfo.h"
|
||||||
|
#include "lldb/API/SBBreakpoint.h"
|
||||||
#include "lldb/API/SBBroadcaster.h"
|
#include "lldb/API/SBBroadcaster.h"
|
||||||
#include "lldb/API/SBDefines.h"
|
#include "lldb/API/SBDefines.h"
|
||||||
#include "lldb/API/SBFileSpec.h"
|
#include "lldb/API/SBFileSpec.h"
|
||||||
|
@ -641,6 +642,18 @@ public:
|
||||||
|
|
||||||
lldb::SBBreakpoint BreakpointCreateBySBAddress(SBAddress &address);
|
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;
|
uint32_t GetNumBreakpoints() const;
|
||||||
|
|
||||||
lldb::SBBreakpoint GetBreakpointAtIndex(uint32_t idx) const;
|
lldb::SBBreakpoint GetBreakpointAtIndex(uint32_t idx) const;
|
||||||
|
@ -741,6 +754,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
friend class SBAddress;
|
friend class SBAddress;
|
||||||
friend class SBBlock;
|
friend class SBBlock;
|
||||||
|
friend class SBBreakpointListImpl;
|
||||||
friend class SBDebugger;
|
friend class SBDebugger;
|
||||||
friend class SBExecutionContext;
|
friend class SBExecutionContext;
|
||||||
friend class SBFunction;
|
friend class SBFunction;
|
||||||
|
|
|
@ -552,7 +552,7 @@ public:
|
||||||
|
|
||||||
static ObjectSP ParseJSON(std::string json_text);
|
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
|
} // namespace lldb_private
|
||||||
|
|
|
@ -678,6 +678,12 @@ public:
|
||||||
|
|
||||||
bool IgnoreWatchpointByID(lldb::watch_id_t watch_id, uint32_t ignore_count);
|
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
|
/// Get \a load_addr as a callable code load address for this target
|
||||||
///
|
///
|
||||||
|
@ -1191,10 +1197,10 @@ protected:
|
||||||
Debugger &m_debugger;
|
Debugger &m_debugger;
|
||||||
lldb::PlatformSP m_platform_sp; ///< The platform for this target.
|
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*
|
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;
|
ArchSpec m_arch;
|
||||||
ModuleList m_images; ///< The list of images for this process (shared
|
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;
|
SectionLoadHistory m_section_load_history;
|
||||||
BreakpointList m_breakpoint_list;
|
BreakpointList m_breakpoint_list;
|
||||||
BreakpointList m_internal_breakpoint_list;
|
BreakpointList m_internal_breakpoint_list;
|
||||||
|
|
|
@ -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<SBBreakpointListImpl> m_opaque_sp;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace lldb
|
} // namespace lldb
|
||||||
|
|
|
@ -713,6 +713,16 @@ public:
|
||||||
bool
|
bool
|
||||||
DeleteAllBreakpoints ();
|
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
|
uint32_t
|
||||||
GetNumWatchpoints () const;
|
GetNumWatchpoints () const;
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "lldb/API/SBThread.h"
|
#include "lldb/API/SBThread.h"
|
||||||
|
|
||||||
#include "lldb/Breakpoint/Breakpoint.h"
|
#include "lldb/Breakpoint/Breakpoint.h"
|
||||||
|
#include "lldb/Breakpoint/BreakpointIDList.h"
|
||||||
#include "lldb/Breakpoint/BreakpointLocation.h"
|
#include "lldb/Breakpoint/BreakpointLocation.h"
|
||||||
#include "lldb/Breakpoint/StoppointCallbackContext.h"
|
#include "lldb/Breakpoint/StoppointCallbackContext.h"
|
||||||
#include "lldb/Core/Address.h"
|
#include "lldb/Core/Address.h"
|
||||||
|
@ -678,3 +679,128 @@ SBBreakpoint::GetNumBreakpointLocationsFromEvent(const lldb::SBEvent &event) {
|
||||||
event.GetSP()));
|
event.GetSP()));
|
||||||
return num_locations;
|
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<lldb::break_id_t> 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);
|
||||||
|
}
|
||||||
|
|
|
@ -1097,6 +1097,58 @@ bool SBTarget::DeleteAllBreakpoints() {
|
||||||
return false;
|
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<std::recursive_mutex> 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<std::recursive_mutex> 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 {
|
uint32_t SBTarget::GetNumWatchpoints() const {
|
||||||
TargetSP target_sp(GetSP());
|
TargetSP target_sp(GetSP());
|
||||||
if (target_sp) {
|
if (target_sp) {
|
||||||
|
|
|
@ -2155,57 +2155,16 @@ protected:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_lock<std::recursive_mutex> lock;
|
|
||||||
target->GetBreakpointList().GetListMutex(lock);
|
|
||||||
|
|
||||||
FileSpec input_spec(m_options.m_filename, true);
|
FileSpec input_spec(m_options.m_filename, true);
|
||||||
Error error;
|
BreakpointIDList new_bps;
|
||||||
StructuredData::ObjectSP input_data_sp =
|
Error error = target->CreateBreakpointsFromFile(input_spec, new_bps);
|
||||||
StructuredData::ParseJSONFromFile(input_spec, error);
|
|
||||||
if (!error.Success()) {
|
if (!error.Success()) {
|
||||||
result.AppendErrorWithFormat("Error reading data from input file: %s.",
|
result.AppendError(error.AsCString());
|
||||||
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);
|
result.SetStatus(eReturnStatusFailed);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// FIXME: Report the newly created breakpoints.
|
||||||
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());
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result.Succeeded();
|
return result.Succeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2295,78 +2254,26 @@ protected:
|
||||||
return false;
|
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<std::recursive_mutex> lock;
|
std::unique_lock<std::recursive_mutex> lock;
|
||||||
target->GetBreakpointList().GetListMutex(lock);
|
target->GetBreakpointList().GetListMutex(lock);
|
||||||
|
|
||||||
StructuredData::ArraySP break_store_sp(new StructuredData::Array());
|
BreakpointIDList valid_bp_ids;
|
||||||
|
if (command.GetArgumentCount() > 0) {
|
||||||
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;
|
|
||||||
|
|
||||||
CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(
|
CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(
|
||||||
command, target, result, &valid_bp_ids);
|
command, target, result, &valid_bp_ids);
|
||||||
|
|
||||||
if (result.Succeeded()) {
|
if (!result.Succeeded()) {
|
||||||
std::unordered_set<lldb::break_id_t> processed_bkpts;
|
result.SetStatus(eReturnStatusFailed);
|
||||||
const size_t count = valid_bp_ids.GetSize();
|
return false;
|
||||||
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<std::unordered_set<lldb::break_id_t>::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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Error error = target->SerializeBreakpointsToFile(
|
||||||
break_store_sp->Dump(out_file, false);
|
FileSpec(m_options.m_filename.c_str(), true), valid_bp_ids);
|
||||||
out_file.PutChar('\n');
|
if (!error.Success()) {
|
||||||
|
result.AppendErrorWithFormat("error serializing breakpoints: %s.",
|
||||||
|
error.AsCString());
|
||||||
|
result.SetStatus(eReturnStatusFailed);
|
||||||
|
}
|
||||||
return result.Succeeded();
|
return result.Succeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,8 +31,8 @@ static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser);
|
||||||
static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser);
|
static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser);
|
||||||
static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser);
|
static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser);
|
||||||
|
|
||||||
StructuredData::ObjectSP StructuredData::ParseJSONFromFile(FileSpec &input_spec,
|
StructuredData::ObjectSP
|
||||||
Error &error) {
|
StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Error &error) {
|
||||||
StructuredData::ObjectSP return_sp;
|
StructuredData::ObjectSP return_sp;
|
||||||
if (!input_spec.Exists()) {
|
if (!input_spec.Exists()) {
|
||||||
error.SetErrorStringWithFormat("input file %s does not exist.",
|
error.SetErrorStringWithFormat("input file %s does not exist.",
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "Plugins/ExpressionParser/Clang/ClangASTSource.h"
|
#include "Plugins/ExpressionParser/Clang/ClangASTSource.h"
|
||||||
#include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h"
|
#include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h"
|
||||||
#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h"
|
#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h"
|
||||||
|
#include "lldb/Breakpoint/BreakpointIDList.h"
|
||||||
#include "lldb/Breakpoint/BreakpointResolver.h"
|
#include "lldb/Breakpoint/BreakpointResolver.h"
|
||||||
#include "lldb/Breakpoint/BreakpointResolverAddress.h"
|
#include "lldb/Breakpoint/BreakpointResolverAddress.h"
|
||||||
#include "lldb/Breakpoint/BreakpointResolverFileLine.h"
|
#include "lldb/Breakpoint/BreakpointResolverFileLine.h"
|
||||||
|
@ -794,6 +795,127 @@ bool Target::EnableBreakpointByID(break_id_t break_id) {
|
||||||
return false;
|
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<std::recursive_mutex> 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<lldb::break_id_t> 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<std::unordered_set<lldb::break_id_t>::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<std::recursive_mutex> 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
|
// The flag 'end_to_end', default to true, signifies that the operation is
|
||||||
// performed end to end, for both the debugger and the debuggee.
|
// performed end to end, for both the debugger and the debuggee.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue