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);
|
||||
|
||||
private:
|
||||
friend class SBBreakpointList;
|
||||
friend class SBBreakpointLocation;
|
||||
friend class SBTarget;
|
||||
|
||||
|
@ -139,6 +140,35 @@ private:
|
|||
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
|
||||
|
||||
#endif // LLDB_SBBreakpoint_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 @@ public:
|
|||
|
||||
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 @@ public:
|
|||
protected:
|
||||
friend class SBAddress;
|
||||
friend class SBBlock;
|
||||
friend class SBBreakpointListImpl;
|
||||
friend class SBDebugger;
|
||||
friend class SBExecutionContext;
|
||||
friend class SBFunction;
|
||||
|
|
|
@ -552,7 +552,7 @@ public:
|
|||
|
||||
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
|
||||
|
|
|
@ -678,6 +678,12 @@ public:
|
|||
|
||||
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 @@ protected:
|
|||
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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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<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;
|
||||
}
|
||||
|
||||
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 {
|
||||
TargetSP target_sp(GetSP());
|
||||
if (target_sp) {
|
||||
|
|
|
@ -2155,57 +2155,16 @@ protected:
|
|||
return false;
|
||||
}
|
||||
|
||||
std::unique_lock<std::recursive_mutex> 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);
|
||||
BreakpointIDList new_bps;
|
||||
Error error = target->CreateBreakpointsFromFile(input_spec, new_bps);
|
||||
|
||||
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.AppendError(error.AsCString());
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
// FIXME: Report the newly created breakpoints.
|
||||
return result.Succeeded();
|
||||
}
|
||||
|
||||
|
@ -2295,78 +2254,26 @@ protected:
|
|||
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;
|
||||
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<lldb::break_id_t> 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<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);
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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.",
|
||||
|
|
|
@ -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<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
|
||||
// performed end to end, for both the debugger and the debuggee.
|
||||
|
||||
|
|
Loading…
Reference in New Issue