mirror of
https://github.com/intel/llvm.git
synced 2026-01-14 20:10:50 +08:00
This is the main part of a change to add breakpoint save and restore to lldb.
Still to come: 1) SB API's 2) Testcases 3) Loose ends: a) serialize Thread options b) serialize Exception resolvers 4) "break list --file" should list breakpoints contained in a file and "break read -f 1 3 5" should then read in only those breakpoints. <rdar://problem/12611863> llvm-svn: 281273
This commit is contained in:
@@ -27,6 +27,7 @@
|
||||
#include "lldb/Core/Event.h"
|
||||
#include "lldb/Core/SearchFilter.h"
|
||||
#include "lldb/Core/StringList.h"
|
||||
#include "lldb/Core/StructuredData.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
@@ -164,6 +165,13 @@ public:
|
||||
|
||||
typedef std::shared_ptr<BreakpointPrecondition> BreakpointPreconditionSP;
|
||||
|
||||
// Saving & restoring breakpoints:
|
||||
static lldb::BreakpointSP CreateFromStructuredData(
|
||||
Target &target, StructuredData::ObjectSP &data_object_sp, Error &error);
|
||||
|
||||
virtual StructuredData::ObjectSP SerializeToStructuredData();
|
||||
|
||||
static const char *GetSerializationKey() { return "Breakpoint"; }
|
||||
//------------------------------------------------------------------
|
||||
/// Destructor.
|
||||
///
|
||||
@@ -717,7 +725,8 @@ private:
|
||||
// to skip certain breakpoint hits. For instance, exception breakpoints
|
||||
// use this to limit the stop to certain exception classes, while leaving
|
||||
// the condition & callback free for user specification.
|
||||
BreakpointOptions m_options; // Settable breakpoint options
|
||||
std::unique_ptr<BreakpointOptions>
|
||||
m_options_up; // Settable breakpoint options
|
||||
BreakpointLocationList
|
||||
m_locations; // The list of locations currently found for this breakpoint.
|
||||
std::string m_kind_description;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
// Project includes
|
||||
#include "lldb/Core/Baton.h"
|
||||
#include "lldb/Core/StringList.h"
|
||||
#include "lldb/Core/StructuredData.h"
|
||||
#include "lldb/lldb-private.h"
|
||||
|
||||
namespace lldb_private {
|
||||
@@ -32,6 +33,52 @@ namespace lldb_private {
|
||||
|
||||
class BreakpointOptions {
|
||||
public:
|
||||
struct CommandData {
|
||||
CommandData() : user_source(), script_source(), stop_on_error(true) {}
|
||||
|
||||
~CommandData() = default;
|
||||
|
||||
static const char *GetSerializationKey() { return "BKPTCMDData"; }
|
||||
|
||||
StructuredData::ObjectSP SerializeToStructuredData();
|
||||
|
||||
static CommandData *
|
||||
CreateFromStructuredData(StructuredData::Dictionary &options_dict,
|
||||
Error &error);
|
||||
|
||||
StringList user_source;
|
||||
std::string script_source;
|
||||
bool stop_on_error;
|
||||
|
||||
private:
|
||||
enum OptionNames {
|
||||
UserSource = 0,
|
||||
ScriptSource,
|
||||
StopOnError,
|
||||
LastOptionName
|
||||
};
|
||||
|
||||
static const char *g_option_names[LastOptionName];
|
||||
|
||||
static const char *GetKey(enum OptionNames enum_value) {
|
||||
return g_option_names[enum_value];
|
||||
}
|
||||
};
|
||||
|
||||
class CommandBaton : public Baton {
|
||||
public:
|
||||
CommandBaton(CommandData *data) : Baton(data) {}
|
||||
|
||||
~CommandBaton() override {
|
||||
delete ((CommandData *)m_data);
|
||||
m_data = nullptr;
|
||||
}
|
||||
|
||||
void GetDescription(Stream *s, lldb::DescriptionLevel level) const override;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<CommandBaton> CommandBatonSP;
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Constructors and Destructors
|
||||
//------------------------------------------------------------------
|
||||
@@ -43,35 +90,34 @@ public:
|
||||
BreakpointOptions(const BreakpointOptions &rhs);
|
||||
|
||||
static BreakpointOptions *CopyOptionsNoCallback(BreakpointOptions &rhs);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// This constructor allows you to specify all the breakpoint options.
|
||||
/// This constructor allows you to specify all the breakpoint options
|
||||
/// except the callback. That one is more complicated, and better
|
||||
/// to do by hand.
|
||||
///
|
||||
/// @param[in] condition
|
||||
/// The expression which if it evaluates to \b true if we are to stop
|
||||
///
|
||||
/// @param[in] callback
|
||||
/// This is the plugin for some code that gets run, returns \b true if we
|
||||
/// are to stop.
|
||||
///
|
||||
/// @param[in] baton
|
||||
/// Client data that will get passed to the callback.
|
||||
///
|
||||
/// @param[in] enabled
|
||||
/// Is this breakpoint enabled.
|
||||
///
|
||||
/// @param[in] ignore
|
||||
/// How many breakpoint hits we should ignore before stopping.
|
||||
///
|
||||
/// @param[in] thread_id
|
||||
/// Only stop if \a thread_id hits the breakpoint.
|
||||
//------------------------------------------------------------------
|
||||
BreakpointOptions(void *condition, BreakpointHitCallback callback,
|
||||
void *baton, bool enabled = true, int32_t ignore = 0,
|
||||
lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID,
|
||||
bool one_shot = false);
|
||||
BreakpointOptions(const char *condition, bool enabled = true,
|
||||
int32_t ignore = 0, bool one_shot = false);
|
||||
|
||||
virtual ~BreakpointOptions();
|
||||
|
||||
static BreakpointOptions *
|
||||
CreateFromStructuredData(StructuredData::Dictionary &data_dict, Error &error);
|
||||
|
||||
virtual StructuredData::ObjectSP SerializeToStructuredData();
|
||||
|
||||
static const char *GetSerializationKey() { return "BKPTOptions"; }
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Operators
|
||||
//------------------------------------------------------------------
|
||||
@@ -131,6 +177,10 @@ public:
|
||||
void SetCallback(BreakpointHitCallback callback,
|
||||
const lldb::BatonSP &baton_sp, bool synchronous = false);
|
||||
|
||||
void SetCallback(BreakpointHitCallback callback,
|
||||
const BreakpointOptions::CommandBatonSP &command_baton_sp,
|
||||
bool synchronous = false);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Remove the callback from this option set.
|
||||
//------------------------------------------------------------------
|
||||
@@ -279,40 +329,39 @@ public:
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// This is the default empty callback.
|
||||
/// @return
|
||||
/// The thread id for which the breakpoint hit will stop,
|
||||
/// LLDB_INVALID_THREAD_ID for all threads.
|
||||
//------------------------------------------------------------------
|
||||
static bool NullCallback(void *baton, StoppointCallbackContext *context,
|
||||
lldb::user_id_t break_id,
|
||||
lldb::user_id_t break_loc_id);
|
||||
|
||||
struct CommandData {
|
||||
CommandData() : user_source(), script_source(), stop_on_error(true) {}
|
||||
|
||||
~CommandData() = default;
|
||||
|
||||
StringList user_source;
|
||||
std::string script_source;
|
||||
bool stop_on_error;
|
||||
};
|
||||
|
||||
class CommandBaton : public Baton {
|
||||
public:
|
||||
CommandBaton(CommandData *data) : Baton(data) {}
|
||||
|
||||
~CommandBaton() override {
|
||||
delete ((CommandData *)m_data);
|
||||
m_data = nullptr;
|
||||
}
|
||||
|
||||
void GetDescription(Stream *s, lldb::DescriptionLevel level) const override;
|
||||
};
|
||||
//------------------------------------------------------------------
|
||||
/// Set a callback based on BreakpointOptions::CommandData.
|
||||
/// @param[in] cmd_data
|
||||
/// A new'ed CommandData object. The breakpoint will take ownership
|
||||
/// of this object.
|
||||
//------------------------------------------------------------------
|
||||
void SetCommandDataCallback(CommandData *cmd_data);
|
||||
|
||||
protected:
|
||||
//------------------------------------------------------------------
|
||||
// Classes that inherit from BreakpointOptions can see and modify these
|
||||
//------------------------------------------------------------------
|
||||
enum OptionNames {
|
||||
ConditionText = 0,
|
||||
IgnoreCount,
|
||||
EnabledState,
|
||||
OneShotState,
|
||||
LastOptionName
|
||||
};
|
||||
static const char *g_option_names[LastOptionName];
|
||||
|
||||
static const char *GetKey(enum OptionNames enum_value) {
|
||||
return g_option_names[enum_value];
|
||||
}
|
||||
|
||||
static bool BreakpointOptionsCallbackFunction(
|
||||
void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id,
|
||||
lldb::user_id_t break_loc_id);
|
||||
|
||||
private:
|
||||
//------------------------------------------------------------------
|
||||
@@ -320,6 +369,7 @@ private:
|
||||
//------------------------------------------------------------------
|
||||
BreakpointHitCallback m_callback; // This is the callback function pointer
|
||||
lldb::BatonSP m_callback_baton_sp; // This is the client data for the callback
|
||||
bool m_baton_is_command_baton;
|
||||
bool m_callback_is_synchronous;
|
||||
bool m_enabled;
|
||||
bool m_one_shot;
|
||||
|
||||
@@ -136,29 +136,95 @@ public:
|
||||
//------------------------------------------------------------------
|
||||
virtual void Dump(Stream *s) const = 0;
|
||||
|
||||
/// This section handles serializing and deserializing from StructuredData
|
||||
/// objects.
|
||||
|
||||
static lldb::BreakpointResolverSP
|
||||
CreateFromStructuredData(StructuredData::Dictionary &resolver_dict,
|
||||
Error &error);
|
||||
|
||||
virtual StructuredData::ObjectSP SerializeToStructuredData() {
|
||||
return StructuredData::ObjectSP();
|
||||
}
|
||||
|
||||
static const char *GetSerializationKey() { return "BKPTResolver"; }
|
||||
|
||||
static const char *GetSerializationSubclassKey() { return "Type"; }
|
||||
|
||||
static const char *GetSerializationSubclassOptionsKey() { return "Options"; }
|
||||
|
||||
StructuredData::DictionarySP
|
||||
WrapOptionsDict(StructuredData::DictionarySP options_dict_sp);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
//------------------------------------------------------------------
|
||||
/// An enumeration for keeping track of the concrete subclass that
|
||||
/// is actually instantiated. Values of this enumeration are kept in the
|
||||
/// BreakpointResolver's SubclassID field. They are used for concrete type
|
||||
/// identification.
|
||||
enum ResolverTy {
|
||||
FileLineResolver, // This is an instance of BreakpointResolverFileLine
|
||||
AddressResolver, // This is an instance of BreakpointResolverAddress
|
||||
NameResolver, // This is an instance of BreakpointResolverName
|
||||
FileLineResolver = 0, // This is an instance of BreakpointResolverFileLine
|
||||
AddressResolver, // This is an instance of BreakpointResolverAddress
|
||||
NameResolver, // This is an instance of BreakpointResolverName
|
||||
FileRegexResolver,
|
||||
ExceptionResolver,
|
||||
LastKnownResolverType = ExceptionResolver
|
||||
LastKnownResolverType = ExceptionResolver,
|
||||
UnknownResolver
|
||||
};
|
||||
|
||||
// Translate the Ty to name for serialization,
|
||||
// the "+2" is one for size vrs. index, and one for UnknownResolver.
|
||||
static const char *g_ty_to_name[LastKnownResolverType + 2];
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// getResolverID - Return an ID for the concrete type of this object. This
|
||||
/// is used to implement the LLVM classof checks. This should not be used
|
||||
/// for any other purpose, as the values may change as LLDB evolves.
|
||||
unsigned getResolverID() const { return SubclassID; }
|
||||
|
||||
enum ResolverTy GetResolverTy() {
|
||||
if (SubclassID > ResolverTy::LastKnownResolverType)
|
||||
return ResolverTy::UnknownResolver;
|
||||
else
|
||||
return (enum ResolverTy)SubclassID;
|
||||
}
|
||||
|
||||
const char *GetResolverName() { return ResolverTyToName(GetResolverTy()); }
|
||||
|
||||
static const char *ResolverTyToName(enum ResolverTy);
|
||||
|
||||
static ResolverTy NameToResolverTy(const char *name);
|
||||
|
||||
virtual lldb::BreakpointResolverSP
|
||||
CopyForBreakpoint(Breakpoint &breakpoint) = 0;
|
||||
|
||||
protected:
|
||||
// Used for serializing resolver options:
|
||||
// The options in this enum and the strings in the
|
||||
// g_option_names must be kept in sync.
|
||||
enum OptionNames {
|
||||
AddressOffset = 0,
|
||||
ExactMatch,
|
||||
FileName,
|
||||
Inlines,
|
||||
LanguageName,
|
||||
LineNumber,
|
||||
ModuleName,
|
||||
NameMaskArray,
|
||||
Offset,
|
||||
RegexString,
|
||||
SectionName,
|
||||
SkipPrologue,
|
||||
SymbolNameArray,
|
||||
LastOptionName
|
||||
};
|
||||
static const char *g_option_names[LastOptionName];
|
||||
|
||||
public:
|
||||
static const char *GetKey(enum OptionNames enum_value) {
|
||||
return g_option_names[enum_value];
|
||||
}
|
||||
|
||||
protected:
|
||||
//------------------------------------------------------------------
|
||||
/// SetSCMatchesByLine - Takes a symbol context list of matches which
|
||||
|
||||
@@ -36,6 +36,11 @@ public:
|
||||
|
||||
~BreakpointResolverAddress() override;
|
||||
|
||||
static BreakpointResolver *CreateFromStructuredData(
|
||||
Breakpoint *bkpt, StructuredData::Dictionary &options_dict, Error &error);
|
||||
|
||||
StructuredData::ObjectSP SerializeToStructuredData() override;
|
||||
|
||||
void ResolveBreakpoint(SearchFilter &filter) override;
|
||||
|
||||
void ResolveBreakpointInModules(SearchFilter &filter,
|
||||
|
||||
@@ -33,6 +33,12 @@ public:
|
||||
bool check_inlines, bool skip_prologue,
|
||||
bool exact_match);
|
||||
|
||||
static BreakpointResolver *
|
||||
CreateFromStructuredData(Breakpoint *bkpt,
|
||||
StructuredData::Dictionary &data_dict, Error &error);
|
||||
|
||||
StructuredData::ObjectSP SerializeToStructuredData() override;
|
||||
|
||||
~BreakpointResolverFileLine() override;
|
||||
|
||||
Searcher::CallbackReturn SearchCallback(SearchFilter &filter,
|
||||
|
||||
@@ -35,6 +35,11 @@ public:
|
||||
Breakpoint *bkpt, RegularExpression ®ex,
|
||||
const std::unordered_set<std::string> &func_name_set, bool exact_match);
|
||||
|
||||
static BreakpointResolver *CreateFromStructuredData(
|
||||
Breakpoint *bkpt, StructuredData::Dictionary &options_dict, Error &error);
|
||||
|
||||
StructuredData::ObjectSP SerializeToStructuredData() override;
|
||||
|
||||
~BreakpointResolverFileRegex() override;
|
||||
|
||||
Searcher::CallbackReturn SearchCallback(SearchFilter &filter,
|
||||
|
||||
@@ -54,9 +54,11 @@ public:
|
||||
lldb::LanguageType language, lldb::addr_t offset,
|
||||
bool skip_prologue);
|
||||
|
||||
BreakpointResolverName(Breakpoint *bkpt, const char *class_name,
|
||||
const char *method, Breakpoint::MatchType type,
|
||||
lldb::addr_t offset, bool skip_prologue);
|
||||
static BreakpointResolver *
|
||||
CreateFromStructuredData(Breakpoint *bkpt,
|
||||
StructuredData::Dictionary &data_dict, Error &error);
|
||||
|
||||
StructuredData::ObjectSP SerializeToStructuredData() override;
|
||||
|
||||
~BreakpointResolverName() override;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
#include "lldb/Core/FileSpecList.h"
|
||||
#include "lldb/Core/StructuredData.h"
|
||||
#include "lldb/lldb-private.h"
|
||||
|
||||
namespace lldb_private {
|
||||
@@ -101,6 +102,8 @@ public:
|
||||
|
||||
SearchFilter(const SearchFilter &rhs);
|
||||
|
||||
SearchFilter(const lldb::TargetSP &target_sp, unsigned char filterType);
|
||||
|
||||
virtual ~SearchFilter();
|
||||
|
||||
SearchFilter &operator=(const SearchFilter &rhs);
|
||||
@@ -213,7 +216,60 @@ public:
|
||||
|
||||
lldb::SearchFilterSP CopyForBreakpoint(Breakpoint &breakpoint);
|
||||
|
||||
static SearchFilter *
|
||||
CreateFromStructuredData(Target &target,
|
||||
StructuredData::Dictionary &data_dict, Error &error);
|
||||
|
||||
virtual StructuredData::ObjectSP SerializeToStructuredData() {
|
||||
return StructuredData::ObjectSP();
|
||||
}
|
||||
|
||||
static const char *GetSerializationKey() { return "SearchFilter"; }
|
||||
|
||||
static const char *GetSerializationSubclassKey() { return "Type"; }
|
||||
|
||||
static const char *GetSerializationSubclassOptionsKey() { return "Options"; }
|
||||
|
||||
enum FilterTy {
|
||||
Unconstrained = 0,
|
||||
Exception,
|
||||
ByModule,
|
||||
ByModules,
|
||||
ByModulesAndCU,
|
||||
LastKnownFilterType = ByModulesAndCU,
|
||||
UnknownFilter
|
||||
};
|
||||
|
||||
static const char *g_ty_to_name[LastKnownFilterType + 2];
|
||||
|
||||
enum FilterTy GetFilterTy() {
|
||||
if (SubclassID > FilterTy::LastKnownFilterType)
|
||||
return FilterTy::UnknownFilter;
|
||||
else
|
||||
return (enum FilterTy)SubclassID;
|
||||
}
|
||||
|
||||
const char *GetFilterName() { return FilterTyToName(GetFilterTy()); }
|
||||
|
||||
static const char *FilterTyToName(enum FilterTy);
|
||||
|
||||
static FilterTy NameToFilterTy(const char *name);
|
||||
|
||||
protected:
|
||||
// Serialization of SearchFilter options:
|
||||
enum OptionNames { ModList = 0, CUList, LanguageName, LastOptionName };
|
||||
static const char *g_option_names[LastOptionName];
|
||||
|
||||
static const char *GetKey(enum OptionNames enum_value) {
|
||||
return g_option_names[enum_value];
|
||||
}
|
||||
|
||||
StructuredData::DictionarySP
|
||||
WrapOptionsDict(StructuredData::DictionarySP options_dict_sp);
|
||||
|
||||
void SerializeFileSpecList(StructuredData::DictionarySP &options_dict_sp,
|
||||
OptionNames name, FileSpecList &file_list);
|
||||
|
||||
// These are utility functions to assist with the search iteration. They are
|
||||
// used by the
|
||||
// default Search method.
|
||||
@@ -239,6 +295,8 @@ protected:
|
||||
lldb::TargetSP
|
||||
m_target_sp; // Every filter has to be associated with a target for
|
||||
// now since you need a starting place for the search.
|
||||
private:
|
||||
unsigned char SubclassID;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@@ -250,13 +308,20 @@ protected:
|
||||
class SearchFilterForUnconstrainedSearches : public SearchFilter {
|
||||
public:
|
||||
SearchFilterForUnconstrainedSearches(const lldb::TargetSP &target_sp)
|
||||
: SearchFilter(target_sp) {}
|
||||
: SearchFilter(target_sp, FilterTy::Unconstrained) {}
|
||||
|
||||
~SearchFilterForUnconstrainedSearches() override = default;
|
||||
|
||||
bool ModulePasses(const FileSpec &module_spec) override;
|
||||
|
||||
bool ModulePasses(const lldb::ModuleSP &module_sp) override;
|
||||
|
||||
static SearchFilter *
|
||||
CreateFromStructuredData(Target &target,
|
||||
StructuredData::Dictionary &data_dict, Error &error);
|
||||
|
||||
StructuredData::ObjectSP SerializeToStructuredData() override;
|
||||
|
||||
protected:
|
||||
lldb::SearchFilterSP DoCopyForBreakpoint(Breakpoint &breakpoint) override;
|
||||
};
|
||||
@@ -304,6 +369,12 @@ public:
|
||||
|
||||
void Search(Searcher &searcher) override;
|
||||
|
||||
static SearchFilter *
|
||||
CreateFromStructuredData(Target &target,
|
||||
StructuredData::Dictionary &data_dict, Error &error);
|
||||
|
||||
StructuredData::ObjectSP SerializeToStructuredData() override;
|
||||
|
||||
protected:
|
||||
lldb::SearchFilterSP DoCopyForBreakpoint(Breakpoint &breakpoint) override;
|
||||
|
||||
@@ -326,6 +397,10 @@ public:
|
||||
SearchFilterByModuleList(const lldb::TargetSP &targetSP,
|
||||
const FileSpecList &module_list);
|
||||
|
||||
SearchFilterByModuleList(const lldb::TargetSP &targetSP,
|
||||
const FileSpecList &module_list,
|
||||
enum FilterTy filter_ty);
|
||||
|
||||
SearchFilterByModuleList(const SearchFilterByModuleList &rhs);
|
||||
|
||||
~SearchFilterByModuleList() override;
|
||||
@@ -350,6 +425,14 @@ public:
|
||||
|
||||
void Search(Searcher &searcher) override;
|
||||
|
||||
static SearchFilter *
|
||||
CreateFromStructuredData(Target &target,
|
||||
StructuredData::Dictionary &data_dict, Error &error);
|
||||
|
||||
StructuredData::ObjectSP SerializeToStructuredData() override;
|
||||
|
||||
void SerializeUnwrapped(StructuredData::DictionarySP &options_dict_sp);
|
||||
|
||||
protected:
|
||||
lldb::SearchFilterSP DoCopyForBreakpoint(Breakpoint &breakpoint) override;
|
||||
|
||||
@@ -394,6 +477,12 @@ public:
|
||||
|
||||
void Search(Searcher &searcher) override;
|
||||
|
||||
static SearchFilter *
|
||||
CreateFromStructuredData(Target &target,
|
||||
StructuredData::Dictionary &data_dict, Error &error);
|
||||
|
||||
StructuredData::ObjectSP SerializeToStructuredData() override;
|
||||
|
||||
protected:
|
||||
lldb::SearchFilterSP DoCopyForBreakpoint(Breakpoint &breakpoint) override;
|
||||
|
||||
|
||||
@@ -390,6 +390,18 @@ public:
|
||||
return value_sp;
|
||||
}
|
||||
|
||||
bool GetValueForKeyAsBoolean(llvm::StringRef key, bool &result) const {
|
||||
bool success = false;
|
||||
ObjectSP value_sp = GetValueForKey(key);
|
||||
if (value_sp.get()) {
|
||||
Boolean *result_ptr = value_sp->GetAsBoolean();
|
||||
if (result_ptr) {
|
||||
result = result_ptr->GetValue();
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
template <class IntType>
|
||||
bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result) const {
|
||||
ObjectSP value_sp = GetValueForKey(key);
|
||||
@@ -539,6 +551,8 @@ public:
|
||||
};
|
||||
|
||||
static ObjectSP ParseJSON(std::string json_text);
|
||||
|
||||
static ObjectSP ParseJSONFromFile(FileSpec &file, Error &error);
|
||||
};
|
||||
|
||||
} // namespace lldb_private
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//===-- LanguageRuntime.h ---------------------------------------------------*-
|
||||
//C++ -*-===//
|
||||
// C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@@ -29,6 +29,38 @@
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
class ExceptionSearchFilter : public SearchFilter {
|
||||
public:
|
||||
ExceptionSearchFilter(const lldb::TargetSP &target_sp,
|
||||
lldb::LanguageType language,
|
||||
bool update_module_list = true);
|
||||
|
||||
~ExceptionSearchFilter() override = default;
|
||||
|
||||
bool ModulePasses(const lldb::ModuleSP &module_sp) override;
|
||||
|
||||
bool ModulePasses(const FileSpec &spec) override;
|
||||
|
||||
void Search(Searcher &searcher) override;
|
||||
|
||||
void GetDescription(Stream *s) override;
|
||||
|
||||
static SearchFilter *
|
||||
CreateFromStructuredData(Target &target,
|
||||
StructuredData::Dictionary &data_dict, Error &error);
|
||||
|
||||
StructuredData::ObjectSP SerializeToStructuredData() override;
|
||||
|
||||
protected:
|
||||
lldb::LanguageType m_language;
|
||||
LanguageRuntime *m_language_runtime;
|
||||
lldb::SearchFilterSP m_filter_sp;
|
||||
|
||||
lldb::SearchFilterSP DoCopyForBreakpoint(Breakpoint &breakpoint) override;
|
||||
|
||||
void UpdateModuleListIfNeeded();
|
||||
};
|
||||
|
||||
class LanguageRuntime : public PluginInterface {
|
||||
public:
|
||||
~LanguageRuntime() override;
|
||||
|
||||
@@ -48,16 +48,17 @@ Breakpoint::Breakpoint(Target &target, SearchFilterSP &filter_sp,
|
||||
BreakpointResolverSP &resolver_sp, bool hardware,
|
||||
bool resolve_indirect_symbols)
|
||||
: m_being_created(true), m_hardware(hardware), m_target(target),
|
||||
m_filter_sp(filter_sp), m_resolver_sp(resolver_sp), m_options(),
|
||||
m_locations(*this), m_resolve_indirect_symbols(resolve_indirect_symbols),
|
||||
m_hit_count(0) {
|
||||
m_filter_sp(filter_sp), m_resolver_sp(resolver_sp),
|
||||
m_options_up(new BreakpointOptions()), m_locations(*this),
|
||||
m_resolve_indirect_symbols(resolve_indirect_symbols), m_hit_count(0) {
|
||||
m_being_created = false;
|
||||
}
|
||||
|
||||
Breakpoint::Breakpoint(Target &new_target, Breakpoint &source_bp)
|
||||
: m_being_created(true), m_hardware(source_bp.m_hardware),
|
||||
m_target(new_target), m_name_list(source_bp.m_name_list),
|
||||
m_options(source_bp.m_options), m_locations(*this),
|
||||
m_options_up(new BreakpointOptions(*source_bp.m_options_up.get())),
|
||||
m_locations(*this),
|
||||
m_resolve_indirect_symbols(source_bp.m_resolve_indirect_symbols),
|
||||
m_hit_count(0) {
|
||||
// Now go through and copy the filter & resolver:
|
||||
@@ -70,6 +71,115 @@ Breakpoint::Breakpoint(Target &new_target, Breakpoint &source_bp)
|
||||
//----------------------------------------------------------------------
|
||||
Breakpoint::~Breakpoint() = default;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Serialization
|
||||
//----------------------------------------------------------------------
|
||||
StructuredData::ObjectSP Breakpoint::SerializeToStructuredData() {
|
||||
// Serialize the resolver:
|
||||
StructuredData::DictionarySP breakpoint_dict_sp(
|
||||
new StructuredData::Dictionary());
|
||||
StructuredData::DictionarySP breakpoint_contents_sp(
|
||||
new StructuredData::Dictionary());
|
||||
|
||||
StructuredData::ObjectSP resolver_dict_sp(
|
||||
m_resolver_sp->SerializeToStructuredData());
|
||||
if (!resolver_dict_sp)
|
||||
return StructuredData::ObjectSP();
|
||||
|
||||
breakpoint_contents_sp->AddItem(BreakpointResolver::GetSerializationKey(),
|
||||
resolver_dict_sp);
|
||||
|
||||
StructuredData::ObjectSP filter_dict_sp(
|
||||
m_filter_sp->SerializeToStructuredData());
|
||||
if (!filter_dict_sp)
|
||||
return StructuredData::ObjectSP();
|
||||
|
||||
breakpoint_contents_sp->AddItem(SearchFilter::GetSerializationKey(),
|
||||
filter_dict_sp);
|
||||
|
||||
StructuredData::ObjectSP options_dict_sp(
|
||||
m_options_up->SerializeToStructuredData());
|
||||
if (!options_dict_sp)
|
||||
return StructuredData::ObjectSP();
|
||||
|
||||
breakpoint_contents_sp->AddItem(BreakpointOptions::GetSerializationKey(),
|
||||
options_dict_sp);
|
||||
|
||||
breakpoint_dict_sp->AddItem(GetSerializationKey(), breakpoint_contents_sp);
|
||||
return breakpoint_dict_sp;
|
||||
}
|
||||
|
||||
lldb::BreakpointSP Breakpoint::CreateFromStructuredData(
|
||||
Target &target, StructuredData::ObjectSP &object_data, Error &error) {
|
||||
BreakpointSP result_sp;
|
||||
|
||||
StructuredData::Dictionary *breakpoint_dict = object_data->GetAsDictionary();
|
||||
|
||||
if (!breakpoint_dict || !breakpoint_dict->IsValid()) {
|
||||
error.SetErrorString("Can't deserialize from an invalid data object.");
|
||||
return result_sp;
|
||||
}
|
||||
|
||||
StructuredData::Dictionary *resolver_dict;
|
||||
bool success = breakpoint_dict->GetValueForKeyAsDictionary(
|
||||
BreakpointResolver::GetSerializationKey(), resolver_dict);
|
||||
if (!success) {
|
||||
error.SetErrorStringWithFormat(
|
||||
"Breakpoint data missing toplevel resolver key");
|
||||
return result_sp;
|
||||
}
|
||||
|
||||
Error create_error;
|
||||
BreakpointResolverSP resolver_sp =
|
||||
BreakpointResolver::CreateFromStructuredData(*resolver_dict,
|
||||
create_error);
|
||||
if (create_error.Fail()) {
|
||||
error.SetErrorStringWithFormat(
|
||||
"Error creating breakpoint resolver from data: %s.",
|
||||
create_error.AsCString());
|
||||
return result_sp;
|
||||
}
|
||||
|
||||
StructuredData::Dictionary *filter_dict;
|
||||
success = breakpoint_dict->GetValueForKeyAsDictionary(
|
||||
SearchFilter::GetSerializationKey(), filter_dict);
|
||||
SearchFilterSP filter_sp;
|
||||
if (!success)
|
||||
filter_sp.reset(
|
||||
new SearchFilterForUnconstrainedSearches(target.shared_from_this()));
|
||||
else {
|
||||
filter_sp.reset(SearchFilter::CreateFromStructuredData(target, *filter_dict,
|
||||
create_error));
|
||||
if (create_error.Fail()) {
|
||||
error.SetErrorStringWithFormat(
|
||||
"Error creating breakpoint filter from data: %s.",
|
||||
create_error.AsCString());
|
||||
return result_sp;
|
||||
}
|
||||
}
|
||||
|
||||
BreakpointOptions *options = nullptr;
|
||||
StructuredData::Dictionary *options_dict;
|
||||
success = breakpoint_dict->GetValueForKeyAsDictionary(
|
||||
BreakpointOptions::GetSerializationKey(), options_dict);
|
||||
if (success) {
|
||||
options = BreakpointOptions::CreateFromStructuredData(*options_dict,
|
||||
create_error);
|
||||
if (create_error.Fail()) {
|
||||
error.SetErrorStringWithFormat(
|
||||
"Error creating breakpoint options from data: %s.",
|
||||
create_error.AsCString());
|
||||
return result_sp;
|
||||
}
|
||||
}
|
||||
result_sp =
|
||||
target.CreateBreakpoint(filter_sp, resolver_sp, false, false, true);
|
||||
if (result_sp && options) {
|
||||
result_sp->m_options_up.reset(options);
|
||||
}
|
||||
return result_sp;
|
||||
}
|
||||
|
||||
const lldb::TargetSP Breakpoint::GetTargetSP() {
|
||||
return m_target.shared_from_this();
|
||||
}
|
||||
@@ -111,10 +221,10 @@ void Breakpoint::RemoveInvalidLocations(const ArchSpec &arch) {
|
||||
// up the individual settings.
|
||||
|
||||
void Breakpoint::SetEnabled(bool enable) {
|
||||
if (enable == m_options.IsEnabled())
|
||||
if (enable == m_options_up->IsEnabled())
|
||||
return;
|
||||
|
||||
m_options.SetEnabled(enable);
|
||||
m_options_up->SetEnabled(enable);
|
||||
if (enable)
|
||||
m_locations.ResolveAllBreakpointSites();
|
||||
else
|
||||
@@ -124,24 +234,24 @@ void Breakpoint::SetEnabled(bool enable) {
|
||||
: eBreakpointEventTypeDisabled);
|
||||
}
|
||||
|
||||
bool Breakpoint::IsEnabled() { return m_options.IsEnabled(); }
|
||||
bool Breakpoint::IsEnabled() { return m_options_up->IsEnabled(); }
|
||||
|
||||
void Breakpoint::SetIgnoreCount(uint32_t n) {
|
||||
if (m_options.GetIgnoreCount() == n)
|
||||
if (m_options_up->GetIgnoreCount() == n)
|
||||
return;
|
||||
|
||||
m_options.SetIgnoreCount(n);
|
||||
m_options_up->SetIgnoreCount(n);
|
||||
SendBreakpointChangedEvent(eBreakpointEventTypeIgnoreChanged);
|
||||
}
|
||||
|
||||
void Breakpoint::DecrementIgnoreCount() {
|
||||
uint32_t ignore = m_options.GetIgnoreCount();
|
||||
uint32_t ignore = m_options_up->GetIgnoreCount();
|
||||
if (ignore != 0)
|
||||
m_options.SetIgnoreCount(ignore - 1);
|
||||
m_options_up->SetIgnoreCount(ignore - 1);
|
||||
}
|
||||
|
||||
uint32_t Breakpoint::GetIgnoreCount() const {
|
||||
return m_options.GetIgnoreCount();
|
||||
return m_options_up->GetIgnoreCount();
|
||||
}
|
||||
|
||||
bool Breakpoint::IgnoreCountShouldStop() {
|
||||
@@ -160,79 +270,81 @@ bool Breakpoint::IgnoreCountShouldStop() {
|
||||
|
||||
uint32_t Breakpoint::GetHitCount() const { return m_hit_count; }
|
||||
|
||||
bool Breakpoint::IsOneShot() const { return m_options.IsOneShot(); }
|
||||
bool Breakpoint::IsOneShot() const { return m_options_up->IsOneShot(); }
|
||||
|
||||
void Breakpoint::SetOneShot(bool one_shot) { m_options.SetOneShot(one_shot); }
|
||||
void Breakpoint::SetOneShot(bool one_shot) {
|
||||
m_options_up->SetOneShot(one_shot);
|
||||
}
|
||||
|
||||
void Breakpoint::SetThreadID(lldb::tid_t thread_id) {
|
||||
if (m_options.GetThreadSpec()->GetTID() == thread_id)
|
||||
if (m_options_up->GetThreadSpec()->GetTID() == thread_id)
|
||||
return;
|
||||
|
||||
m_options.GetThreadSpec()->SetTID(thread_id);
|
||||
m_options_up->GetThreadSpec()->SetTID(thread_id);
|
||||
SendBreakpointChangedEvent(eBreakpointEventTypeThreadChanged);
|
||||
}
|
||||
|
||||
lldb::tid_t Breakpoint::GetThreadID() const {
|
||||
if (m_options.GetThreadSpecNoCreate() == nullptr)
|
||||
if (m_options_up->GetThreadSpecNoCreate() == nullptr)
|
||||
return LLDB_INVALID_THREAD_ID;
|
||||
else
|
||||
return m_options.GetThreadSpecNoCreate()->GetTID();
|
||||
return m_options_up->GetThreadSpecNoCreate()->GetTID();
|
||||
}
|
||||
|
||||
void Breakpoint::SetThreadIndex(uint32_t index) {
|
||||
if (m_options.GetThreadSpec()->GetIndex() == index)
|
||||
if (m_options_up->GetThreadSpec()->GetIndex() == index)
|
||||
return;
|
||||
|
||||
m_options.GetThreadSpec()->SetIndex(index);
|
||||
m_options_up->GetThreadSpec()->SetIndex(index);
|
||||
SendBreakpointChangedEvent(eBreakpointEventTypeThreadChanged);
|
||||
}
|
||||
|
||||
uint32_t Breakpoint::GetThreadIndex() const {
|
||||
if (m_options.GetThreadSpecNoCreate() == nullptr)
|
||||
if (m_options_up->GetThreadSpecNoCreate() == nullptr)
|
||||
return 0;
|
||||
else
|
||||
return m_options.GetThreadSpecNoCreate()->GetIndex();
|
||||
return m_options_up->GetThreadSpecNoCreate()->GetIndex();
|
||||
}
|
||||
|
||||
void Breakpoint::SetThreadName(const char *thread_name) {
|
||||
if (m_options.GetThreadSpec()->GetName() != nullptr &&
|
||||
::strcmp(m_options.GetThreadSpec()->GetName(), thread_name) == 0)
|
||||
if (m_options_up->GetThreadSpec()->GetName() != nullptr &&
|
||||
::strcmp(m_options_up->GetThreadSpec()->GetName(), thread_name) == 0)
|
||||
return;
|
||||
|
||||
m_options.GetThreadSpec()->SetName(thread_name);
|
||||
m_options_up->GetThreadSpec()->SetName(thread_name);
|
||||
SendBreakpointChangedEvent(eBreakpointEventTypeThreadChanged);
|
||||
}
|
||||
|
||||
const char *Breakpoint::GetThreadName() const {
|
||||
if (m_options.GetThreadSpecNoCreate() == nullptr)
|
||||
if (m_options_up->GetThreadSpecNoCreate() == nullptr)
|
||||
return nullptr;
|
||||
else
|
||||
return m_options.GetThreadSpecNoCreate()->GetName();
|
||||
return m_options_up->GetThreadSpecNoCreate()->GetName();
|
||||
}
|
||||
|
||||
void Breakpoint::SetQueueName(const char *queue_name) {
|
||||
if (m_options.GetThreadSpec()->GetQueueName() != nullptr &&
|
||||
::strcmp(m_options.GetThreadSpec()->GetQueueName(), queue_name) == 0)
|
||||
if (m_options_up->GetThreadSpec()->GetQueueName() != nullptr &&
|
||||
::strcmp(m_options_up->GetThreadSpec()->GetQueueName(), queue_name) == 0)
|
||||
return;
|
||||
|
||||
m_options.GetThreadSpec()->SetQueueName(queue_name);
|
||||
m_options_up->GetThreadSpec()->SetQueueName(queue_name);
|
||||
SendBreakpointChangedEvent(eBreakpointEventTypeThreadChanged);
|
||||
}
|
||||
|
||||
const char *Breakpoint::GetQueueName() const {
|
||||
if (m_options.GetThreadSpecNoCreate() == nullptr)
|
||||
if (m_options_up->GetThreadSpecNoCreate() == nullptr)
|
||||
return nullptr;
|
||||
else
|
||||
return m_options.GetThreadSpecNoCreate()->GetQueueName();
|
||||
return m_options_up->GetThreadSpecNoCreate()->GetQueueName();
|
||||
}
|
||||
|
||||
void Breakpoint::SetCondition(const char *condition) {
|
||||
m_options.SetCondition(condition);
|
||||
m_options_up->SetCondition(condition);
|
||||
SendBreakpointChangedEvent(eBreakpointEventTypeConditionChanged);
|
||||
}
|
||||
|
||||
const char *Breakpoint::GetConditionText() const {
|
||||
return m_options.GetConditionText();
|
||||
return m_options_up->GetConditionText();
|
||||
}
|
||||
|
||||
// This function is used when "baton" doesn't need to be freed
|
||||
@@ -240,7 +352,8 @@ void Breakpoint::SetCallback(BreakpointHitCallback callback, void *baton,
|
||||
bool is_synchronous) {
|
||||
// The default "Baton" class will keep a copy of "baton" and won't free
|
||||
// or delete it when it goes goes out of scope.
|
||||
m_options.SetCallback(callback, BatonSP(new Baton(baton)), is_synchronous);
|
||||
m_options_up->SetCallback(callback, BatonSP(new Baton(baton)),
|
||||
is_synchronous);
|
||||
|
||||
SendBreakpointChangedEvent(eBreakpointEventTypeCommandChanged);
|
||||
}
|
||||
@@ -250,17 +363,17 @@ void Breakpoint::SetCallback(BreakpointHitCallback callback, void *baton,
|
||||
void Breakpoint::SetCallback(BreakpointHitCallback callback,
|
||||
const BatonSP &callback_baton_sp,
|
||||
bool is_synchronous) {
|
||||
m_options.SetCallback(callback, callback_baton_sp, is_synchronous);
|
||||
m_options_up->SetCallback(callback, callback_baton_sp, is_synchronous);
|
||||
}
|
||||
|
||||
void Breakpoint::ClearCallback() { m_options.ClearCallback(); }
|
||||
void Breakpoint::ClearCallback() { m_options_up->ClearCallback(); }
|
||||
|
||||
bool Breakpoint::InvokeCallback(StoppointCallbackContext *context,
|
||||
break_id_t bp_loc_id) {
|
||||
return m_options.InvokeCallback(context, GetID(), bp_loc_id);
|
||||
return m_options_up->InvokeCallback(context, GetID(), bp_loc_id);
|
||||
}
|
||||
|
||||
BreakpointOptions *Breakpoint::GetOptions() { return &m_options; }
|
||||
BreakpointOptions *Breakpoint::GetOptions() { return m_options_up.get(); }
|
||||
|
||||
void Breakpoint::ResolveBreakpoint() {
|
||||
if (m_resolver_sp)
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include "lldb/Core/Stream.h"
|
||||
#include "lldb/Core/StringList.h"
|
||||
#include "lldb/Core/Value.h"
|
||||
#include "lldb/Interpreter/CommandInterpreter.h"
|
||||
#include "lldb/Interpreter/CommandReturnObject.h"
|
||||
#include "lldb/Target/Process.h"
|
||||
#include "lldb/Target/Target.h"
|
||||
#include "lldb/Target/ThreadSpec.h"
|
||||
@@ -24,6 +26,71 @@
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
const char *BreakpointOptions::CommandData::g_option_names
|
||||
[BreakpointOptions::CommandData::OptionNames::LastOptionName]{
|
||||
"UserSource", "ScriptSource", "StopOnError"};
|
||||
|
||||
StructuredData::ObjectSP
|
||||
BreakpointOptions::CommandData::SerializeToStructuredData() {
|
||||
size_t num_strings = user_source.GetSize();
|
||||
if (num_strings == 0 && script_source.empty()) {
|
||||
// We shouldn't serialize commands if there aren't any, return an empty sp
|
||||
// to indicate this.
|
||||
return StructuredData::ObjectSP();
|
||||
}
|
||||
|
||||
StructuredData::DictionarySP options_dict_sp(
|
||||
new StructuredData::Dictionary());
|
||||
options_dict_sp->AddBooleanItem(GetKey(OptionNames::StopOnError),
|
||||
stop_on_error);
|
||||
|
||||
StructuredData::ArraySP user_source_sp(new StructuredData::Array());
|
||||
if (num_strings > 0) {
|
||||
for (size_t i = 0; i < num_strings; i++) {
|
||||
StructuredData::StringSP item_sp(
|
||||
new StructuredData::String(user_source[i]));
|
||||
user_source_sp->AddItem(item_sp);
|
||||
options_dict_sp->AddItem(GetKey(OptionNames::UserSource), user_source_sp);
|
||||
}
|
||||
}
|
||||
|
||||
if (!script_source.empty()) {
|
||||
StructuredData::StringSP item_sp(new StructuredData::String(script_source));
|
||||
options_dict_sp->AddItem(GetKey(OptionNames::ScriptSource), user_source_sp);
|
||||
}
|
||||
return options_dict_sp;
|
||||
}
|
||||
|
||||
BreakpointOptions::CommandData *
|
||||
BreakpointOptions::CommandData::CreateFromStructuredData(
|
||||
StructuredData::Dictionary &options_dict, Error &error) {
|
||||
std::string script_source;
|
||||
CommandData *data = new CommandData();
|
||||
bool success = options_dict.GetValueForKeyAsBoolean(
|
||||
GetKey(OptionNames::StopOnError), data->stop_on_error);
|
||||
|
||||
success = options_dict.GetValueForKeyAsString(
|
||||
GetKey(OptionNames::ScriptSource), data->script_source);
|
||||
|
||||
StructuredData::Array *user_source;
|
||||
success = options_dict.GetValueForKeyAsArray(GetKey(OptionNames::UserSource),
|
||||
user_source);
|
||||
if (success) {
|
||||
size_t num_elems = user_source->GetSize();
|
||||
for (size_t i = 0; i < num_elems; i++) {
|
||||
std::string elem_string;
|
||||
success = user_source->GetItemAtIndexAsString(i, elem_string);
|
||||
if (success)
|
||||
data->user_source.AppendString(elem_string);
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
const char *BreakpointOptions::g_option_names
|
||||
[BreakpointOptions::OptionNames::LastOptionName]{
|
||||
"ConditionText", "IgnoreCount", "EnabledState", "OneShotState"};
|
||||
|
||||
bool BreakpointOptions::NullCallback(void *baton,
|
||||
StoppointCallbackContext *context,
|
||||
lldb::user_id_t break_id,
|
||||
@@ -36,15 +103,25 @@ bool BreakpointOptions::NullCallback(void *baton,
|
||||
//----------------------------------------------------------------------
|
||||
BreakpointOptions::BreakpointOptions()
|
||||
: m_callback(BreakpointOptions::NullCallback), m_callback_baton_sp(),
|
||||
m_callback_is_synchronous(false), m_enabled(true), m_one_shot(false),
|
||||
m_ignore_count(0), m_thread_spec_ap(), m_condition_text(),
|
||||
m_condition_text_hash(0) {}
|
||||
m_baton_is_command_baton(false), m_callback_is_synchronous(false),
|
||||
m_enabled(true), m_one_shot(false), m_ignore_count(0), m_thread_spec_ap(),
|
||||
m_condition_text(), m_condition_text_hash(0) {}
|
||||
|
||||
BreakpointOptions::BreakpointOptions(const char *condition, bool enabled,
|
||||
int32_t ignore, bool one_shot)
|
||||
: m_callback(nullptr), m_baton_is_command_baton(false),
|
||||
m_callback_is_synchronous(false), m_enabled(enabled),
|
||||
m_one_shot(one_shot), m_ignore_count(ignore), m_condition_text(condition),
|
||||
m_condition_text_hash(0)
|
||||
|
||||
{}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// BreakpointOptions copy constructor
|
||||
//----------------------------------------------------------------------
|
||||
BreakpointOptions::BreakpointOptions(const BreakpointOptions &rhs)
|
||||
: m_callback(rhs.m_callback), m_callback_baton_sp(rhs.m_callback_baton_sp),
|
||||
m_baton_is_command_baton(rhs.m_baton_is_command_baton),
|
||||
m_callback_is_synchronous(rhs.m_callback_is_synchronous),
|
||||
m_enabled(rhs.m_enabled), m_one_shot(rhs.m_one_shot),
|
||||
m_ignore_count(rhs.m_ignore_count), m_thread_spec_ap() {
|
||||
@@ -61,6 +138,7 @@ const BreakpointOptions &BreakpointOptions::
|
||||
operator=(const BreakpointOptions &rhs) {
|
||||
m_callback = rhs.m_callback;
|
||||
m_callback_baton_sp = rhs.m_callback_baton_sp;
|
||||
m_baton_is_command_baton = rhs.m_baton_is_command_baton;
|
||||
m_callback_is_synchronous = rhs.m_callback_is_synchronous;
|
||||
m_enabled = rhs.m_enabled;
|
||||
m_one_shot = rhs.m_one_shot;
|
||||
@@ -91,21 +169,109 @@ BreakpointOptions::CopyOptionsNoCallback(BreakpointOptions &orig) {
|
||||
//----------------------------------------------------------------------
|
||||
BreakpointOptions::~BreakpointOptions() = default;
|
||||
|
||||
BreakpointOptions *BreakpointOptions::CreateFromStructuredData(
|
||||
StructuredData::Dictionary &options_dict, Error &error) {
|
||||
bool enabled = true;
|
||||
bool one_shot = false;
|
||||
int32_t ignore_count = 0;
|
||||
std::string condition_text;
|
||||
|
||||
bool success = options_dict.GetValueForKeyAsBoolean(
|
||||
GetKey(OptionNames::EnabledState), enabled);
|
||||
if (!success) {
|
||||
error.SetErrorStringWithFormat("%s key is not a boolean.",
|
||||
GetKey(OptionNames::EnabledState));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
success = options_dict.GetValueForKeyAsBoolean(
|
||||
GetKey(OptionNames::OneShotState), one_shot);
|
||||
if (!success) {
|
||||
error.SetErrorStringWithFormat("%s key is not a boolean.",
|
||||
GetKey(OptionNames::OneShotState));
|
||||
return nullptr;
|
||||
}
|
||||
success = options_dict.GetValueForKeyAsInteger(
|
||||
GetKey(OptionNames::IgnoreCount), ignore_count);
|
||||
if (!success) {
|
||||
error.SetErrorStringWithFormat("%s key is not an integer.",
|
||||
GetKey(OptionNames::IgnoreCount));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BreakpointOptions::CommandData *cmd_data = nullptr;
|
||||
StructuredData::Dictionary *cmds_dict;
|
||||
success = options_dict.GetValueForKeyAsDictionary(
|
||||
CommandData::GetSerializationKey(), cmds_dict);
|
||||
if (success && cmds_dict) {
|
||||
Error cmds_error;
|
||||
cmd_data = CommandData::CreateFromStructuredData(*cmds_dict, cmds_error);
|
||||
if (cmds_error.Fail()) {
|
||||
error.SetErrorStringWithFormat(
|
||||
"Failed to deserialize breakpoint command options: %s.",
|
||||
cmds_error.AsCString());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
BreakpointOptions *bp_options = new BreakpointOptions(
|
||||
condition_text.c_str(), enabled, ignore_count, one_shot);
|
||||
if (cmd_data)
|
||||
bp_options->SetCommandDataCallback(cmd_data);
|
||||
return bp_options;
|
||||
}
|
||||
|
||||
StructuredData::ObjectSP BreakpointOptions::SerializeToStructuredData() {
|
||||
StructuredData::DictionarySP options_dict_sp(
|
||||
new StructuredData::Dictionary());
|
||||
options_dict_sp->AddBooleanItem(GetKey(OptionNames::EnabledState), m_enabled);
|
||||
options_dict_sp->AddBooleanItem(GetKey(OptionNames::OneShotState),
|
||||
m_one_shot);
|
||||
options_dict_sp->AddIntegerItem(GetKey(OptionNames::IgnoreCount),
|
||||
m_ignore_count);
|
||||
options_dict_sp->AddStringItem(GetKey(OptionNames::ConditionText),
|
||||
m_condition_text);
|
||||
if (m_baton_is_command_baton) {
|
||||
CommandData *cmd_data =
|
||||
static_cast<CommandData *>(m_callback_baton_sp->m_data);
|
||||
StructuredData::ObjectSP commands_sp =
|
||||
cmd_data->SerializeToStructuredData();
|
||||
if (commands_sp) {
|
||||
options_dict_sp->AddItem(
|
||||
BreakpointOptions::CommandData::GetSerializationKey(), commands_sp);
|
||||
}
|
||||
}
|
||||
// FIXME: Need to serialize thread filter...
|
||||
return options_dict_sp;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Callbacks
|
||||
//------------------------------------------------------------------
|
||||
void BreakpointOptions::SetCallback(BreakpointHitCallback callback,
|
||||
const BatonSP &callback_baton_sp,
|
||||
const lldb::BatonSP &callback_baton_sp,
|
||||
bool callback_is_synchronous) {
|
||||
m_callback_is_synchronous = callback_is_synchronous;
|
||||
m_callback = callback;
|
||||
m_callback_baton_sp = callback_baton_sp;
|
||||
m_baton_is_command_baton = false;
|
||||
}
|
||||
|
||||
void BreakpointOptions::SetCallback(
|
||||
BreakpointHitCallback callback,
|
||||
const BreakpointOptions::CommandBatonSP &callback_baton_sp,
|
||||
bool callback_is_synchronous) {
|
||||
m_callback_is_synchronous = callback_is_synchronous;
|
||||
m_callback = callback;
|
||||
m_callback_baton_sp = callback_baton_sp;
|
||||
m_baton_is_command_baton = true;
|
||||
}
|
||||
|
||||
void BreakpointOptions::ClearCallback() {
|
||||
m_callback = BreakpointOptions::NullCallback;
|
||||
m_callback_is_synchronous = false;
|
||||
m_callback_baton_sp.reset();
|
||||
m_baton_is_command_baton = false;
|
||||
}
|
||||
|
||||
Baton *BreakpointOptions::GetBaton() { return m_callback_baton_sp.get(); }
|
||||
@@ -239,3 +405,49 @@ void BreakpointOptions::CommandBaton::GetDescription(
|
||||
s->IndentLess();
|
||||
s->IndentLess();
|
||||
}
|
||||
|
||||
void BreakpointOptions::SetCommandDataCallback(CommandData *cmd_data) {
|
||||
CommandBatonSP baton_sp(new CommandBaton(cmd_data));
|
||||
SetCallback(BreakpointOptions::BreakpointOptionsCallbackFunction, baton_sp);
|
||||
}
|
||||
|
||||
bool BreakpointOptions::BreakpointOptionsCallbackFunction(
|
||||
void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id,
|
||||
lldb::user_id_t break_loc_id) {
|
||||
bool ret_value = true;
|
||||
if (baton == nullptr)
|
||||
return true;
|
||||
|
||||
CommandData *data = (CommandData *)baton;
|
||||
StringList &commands = data->user_source;
|
||||
|
||||
if (commands.GetSize() > 0) {
|
||||
ExecutionContext exe_ctx(context->exe_ctx_ref);
|
||||
Target *target = exe_ctx.GetTargetPtr();
|
||||
if (target) {
|
||||
CommandReturnObject result;
|
||||
Debugger &debugger = target->GetDebugger();
|
||||
// Rig up the results secondary output stream to the debugger's, so the
|
||||
// output will come out synchronously
|
||||
// if the debugger is set up that way.
|
||||
|
||||
StreamSP output_stream(debugger.GetAsyncOutputStream());
|
||||
StreamSP error_stream(debugger.GetAsyncErrorStream());
|
||||
result.SetImmediateOutputStream(output_stream);
|
||||
result.SetImmediateErrorStream(error_stream);
|
||||
|
||||
CommandInterpreterRunOptions options;
|
||||
options.SetStopOnContinue(true);
|
||||
options.SetStopOnError(data->stop_on_error);
|
||||
options.SetEchoCommands(true);
|
||||
options.SetPrintResults(true);
|
||||
options.SetAddToHistory(false);
|
||||
|
||||
debugger.GetCommandInterpreter().HandleCommands(commands, &exe_ctx,
|
||||
options, result);
|
||||
result.GetImmediateOutputStream()->Flush();
|
||||
result.GetImmediateErrorStream()->Flush();
|
||||
}
|
||||
}
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,12 @@
|
||||
// Project includes
|
||||
#include "lldb/Breakpoint/Breakpoint.h"
|
||||
#include "lldb/Breakpoint/BreakpointLocation.h"
|
||||
// Have to include the other breakpoint resolver types here so the static create
|
||||
// from StructuredData can call them.
|
||||
#include "lldb/Breakpoint/BreakpointResolverAddress.h"
|
||||
#include "lldb/Breakpoint/BreakpointResolverFileLine.h"
|
||||
#include "lldb/Breakpoint/BreakpointResolverFileRegex.h"
|
||||
#include "lldb/Breakpoint/BreakpointResolverName.h"
|
||||
#include "lldb/Core/Address.h"
|
||||
#include "lldb/Core/Log.h"
|
||||
#include "lldb/Core/ModuleList.h"
|
||||
@@ -32,6 +38,32 @@ using namespace lldb;
|
||||
//----------------------------------------------------------------------
|
||||
// BreakpointResolver:
|
||||
//----------------------------------------------------------------------
|
||||
const char *BreakpointResolver::g_ty_to_name[] = {"FileAndLine", "Address",
|
||||
"SymbolName", "SourceRegex",
|
||||
"Exception", "Unknown"};
|
||||
|
||||
const char *BreakpointResolver::g_option_names
|
||||
[BreakpointResolver::OptionNames::LastOptionName] = {
|
||||
"AddressOffset", "Exact", "FileName", "Inlines", "Language",
|
||||
"LineNumber", "ModuleName", "NameMask", "Offset", "Regex",
|
||||
"SectionName", "SkipPrologue", "SymbolNames"};
|
||||
|
||||
const char *BreakpointResolver::ResolverTyToName(enum ResolverTy type) {
|
||||
if (type > LastKnownResolverType)
|
||||
return g_ty_to_name[UnknownResolver];
|
||||
|
||||
return g_ty_to_name[type];
|
||||
}
|
||||
|
||||
BreakpointResolver::ResolverTy
|
||||
BreakpointResolver::NameToResolverTy(const char *name) {
|
||||
for (size_t i = 0; i < LastKnownResolverType; i++) {
|
||||
if (strcmp(name, g_ty_to_name[i]) == 0)
|
||||
return (ResolverTy)i;
|
||||
}
|
||||
return UnknownResolver;
|
||||
}
|
||||
|
||||
BreakpointResolver::BreakpointResolver(Breakpoint *bkpt,
|
||||
const unsigned char resolverTy,
|
||||
lldb::addr_t offset)
|
||||
@@ -39,6 +71,98 @@ BreakpointResolver::BreakpointResolver(Breakpoint *bkpt,
|
||||
|
||||
BreakpointResolver::~BreakpointResolver() {}
|
||||
|
||||
BreakpointResolverSP BreakpointResolver::CreateFromStructuredData(
|
||||
StructuredData::Dictionary &resolver_dict, Error &error) {
|
||||
BreakpointResolverSP result_sp;
|
||||
if (!resolver_dict.IsValid()) {
|
||||
error.SetErrorString("Can't deserialize from an invalid data object.");
|
||||
return result_sp;
|
||||
}
|
||||
|
||||
std::string subclass_name;
|
||||
|
||||
bool success = resolver_dict.GetValueForKeyAsString(
|
||||
GetSerializationSubclassKey(), subclass_name);
|
||||
|
||||
if (!success) {
|
||||
error.SetErrorStringWithFormat(
|
||||
"Resolver data missing subclass resolver key");
|
||||
return result_sp;
|
||||
}
|
||||
|
||||
ResolverTy resolver_type = NameToResolverTy(subclass_name.c_str());
|
||||
if (resolver_type == UnknownResolver) {
|
||||
error.SetErrorStringWithFormat("Unknown resolver type: %s.",
|
||||
subclass_name.c_str());
|
||||
return result_sp;
|
||||
}
|
||||
|
||||
StructuredData::Dictionary *subclass_options = nullptr;
|
||||
success = resolver_dict.GetValueForKeyAsDictionary(
|
||||
GetSerializationSubclassOptionsKey(), subclass_options);
|
||||
if (!success || !subclass_options || !subclass_options->IsValid()) {
|
||||
error.SetErrorString("Resolver data missing subclass options key.");
|
||||
return result_sp;
|
||||
}
|
||||
|
||||
lldb::addr_t offset;
|
||||
success = subclass_options->GetValueForKeyAsInteger(
|
||||
GetKey(OptionNames::Offset), offset);
|
||||
if (!success) {
|
||||
error.SetErrorString("Resolver data missing offset options key.");
|
||||
return result_sp;
|
||||
}
|
||||
|
||||
BreakpointResolver *resolver;
|
||||
|
||||
switch (resolver_type) {
|
||||
case FileLineResolver:
|
||||
resolver = BreakpointResolverFileLine::CreateFromStructuredData(
|
||||
nullptr, *subclass_options, error);
|
||||
break;
|
||||
case AddressResolver:
|
||||
resolver = BreakpointResolverAddress::CreateFromStructuredData(
|
||||
nullptr, *subclass_options, error);
|
||||
break;
|
||||
case NameResolver:
|
||||
resolver = BreakpointResolverName::CreateFromStructuredData(
|
||||
nullptr, *subclass_options, error);
|
||||
break;
|
||||
case FileRegexResolver:
|
||||
resolver = BreakpointResolverFileRegex::CreateFromStructuredData(
|
||||
nullptr, *subclass_options, error);
|
||||
break;
|
||||
case ExceptionResolver:
|
||||
error.SetErrorString("Exception resolvers are hard.");
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("Should never get an unresolvable resolver type.");
|
||||
}
|
||||
|
||||
if (!error.Success()) {
|
||||
return result_sp;
|
||||
} else {
|
||||
// Add on the global offset option:
|
||||
resolver->SetOffset(offset);
|
||||
return BreakpointResolverSP(resolver);
|
||||
}
|
||||
}
|
||||
|
||||
StructuredData::DictionarySP BreakpointResolver::WrapOptionsDict(
|
||||
StructuredData::DictionarySP options_dict_sp) {
|
||||
if (!options_dict_sp || !options_dict_sp->IsValid())
|
||||
return StructuredData::DictionarySP();
|
||||
|
||||
StructuredData::DictionarySP type_dict_sp(new StructuredData::Dictionary());
|
||||
type_dict_sp->AddStringItem(GetSerializationSubclassKey(), GetResolverName());
|
||||
type_dict_sp->AddItem(GetSerializationSubclassOptionsKey(), options_dict_sp);
|
||||
|
||||
// Add the m_offset to the dictionary:
|
||||
options_dict_sp->AddIntegerItem(GetKey(OptionNames::Offset), m_offset);
|
||||
|
||||
return type_dict_sp;
|
||||
}
|
||||
|
||||
void BreakpointResolver::SetBreakpoint(Breakpoint *bkpt) {
|
||||
m_breakpoint = bkpt;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "lldb/Breakpoint/BreakpointLocation.h"
|
||||
#include "lldb/Core/Log.h"
|
||||
#include "lldb/Core/Module.h"
|
||||
#include "lldb/Core/Section.h"
|
||||
#include "lldb/Core/StreamString.h"
|
||||
#include "lldb/Target/Process.h"
|
||||
#include "lldb/Target/Target.h"
|
||||
@@ -41,6 +42,62 @@ BreakpointResolverAddress::BreakpointResolverAddress(Breakpoint *bkpt,
|
||||
|
||||
BreakpointResolverAddress::~BreakpointResolverAddress() {}
|
||||
|
||||
BreakpointResolver *BreakpointResolverAddress::CreateFromStructuredData(
|
||||
Breakpoint *bkpt, StructuredData::Dictionary &options_dict, Error &error) {
|
||||
std::string module_name;
|
||||
lldb::addr_t addr_offset;
|
||||
FileSpec module_filespec;
|
||||
bool success;
|
||||
|
||||
success = options_dict.GetValueForKeyAsInteger(
|
||||
GetKey(OptionNames::AddressOffset), addr_offset);
|
||||
if (!success) {
|
||||
error.SetErrorString("BRFL::CFSD: Couldn't find address offset entry.");
|
||||
return nullptr;
|
||||
}
|
||||
Address address(addr_offset);
|
||||
|
||||
success = options_dict.HasKey(GetKey(OptionNames::ModuleName));
|
||||
if (success) {
|
||||
success = options_dict.GetValueForKeyAsString(
|
||||
GetKey(OptionNames::ModuleName), module_name);
|
||||
if (!success) {
|
||||
error.SetErrorString("BRA::CFSD: Couldn't read module name entry.");
|
||||
return nullptr;
|
||||
}
|
||||
module_filespec.SetFile(module_name.c_str(), false);
|
||||
}
|
||||
return new BreakpointResolverAddress(bkpt, address, module_filespec);
|
||||
}
|
||||
|
||||
StructuredData::ObjectSP
|
||||
BreakpointResolverAddress::SerializeToStructuredData() {
|
||||
StructuredData::DictionarySP options_dict_sp(
|
||||
new StructuredData::Dictionary());
|
||||
SectionSP section_sp = m_addr.GetSection();
|
||||
if (section_sp) {
|
||||
ModuleSP module_sp = section_sp->GetModule();
|
||||
ConstString module_name;
|
||||
if (module_sp)
|
||||
module_name.SetCString(module_name.GetCString());
|
||||
|
||||
options_dict_sp->AddStringItem(GetKey(OptionNames::ModuleName),
|
||||
module_name.GetCString());
|
||||
options_dict_sp->AddIntegerItem(GetKey(OptionNames::AddressOffset),
|
||||
m_addr.GetOffset());
|
||||
} else {
|
||||
options_dict_sp->AddIntegerItem(GetKey(OptionNames::AddressOffset),
|
||||
m_addr.GetOffset());
|
||||
if (m_module_filespec) {
|
||||
options_dict_sp->AddStringItem(GetKey(OptionNames::ModuleName),
|
||||
m_module_filespec.GetPath());
|
||||
}
|
||||
}
|
||||
|
||||
return WrapOptionsDict(options_dict_sp);
|
||||
return StructuredData::ObjectSP();
|
||||
}
|
||||
|
||||
void BreakpointResolverAddress::ResolveBreakpoint(SearchFilter &filter) {
|
||||
// If the address is not section relative, then we should not try to
|
||||
// re-resolve it, it is just some
|
||||
|
||||
@@ -36,6 +36,77 @@ BreakpointResolverFileLine::BreakpointResolverFileLine(
|
||||
|
||||
BreakpointResolverFileLine::~BreakpointResolverFileLine() {}
|
||||
|
||||
BreakpointResolver *BreakpointResolverFileLine::CreateFromStructuredData(
|
||||
Breakpoint *bkpt, StructuredData::Dictionary &options_dict, Error &error) {
|
||||
std::string filename;
|
||||
uint32_t line_no;
|
||||
bool check_inlines;
|
||||
bool skip_prologue;
|
||||
bool exact_match;
|
||||
bool success;
|
||||
|
||||
lldb::addr_t offset = 0;
|
||||
|
||||
success = options_dict.GetValueForKeyAsString(GetKey(OptionNames::FileName),
|
||||
filename);
|
||||
if (!success) {
|
||||
error.SetErrorString("BRFL::CFSD: Couldn't find filename entry.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
success = options_dict.GetValueForKeyAsInteger(
|
||||
GetKey(OptionNames::LineNumber), line_no);
|
||||
if (!success) {
|
||||
error.SetErrorString("BRFL::CFSD: Couldn't find line number entry.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
success = options_dict.GetValueForKeyAsBoolean(GetKey(OptionNames::Inlines),
|
||||
check_inlines);
|
||||
if (!success) {
|
||||
error.SetErrorString("BRFL::CFSD: Couldn't find check inlines entry.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
success = options_dict.GetValueForKeyAsBoolean(
|
||||
GetKey(OptionNames::SkipPrologue), skip_prologue);
|
||||
if (!success) {
|
||||
error.SetErrorString("BRFL::CFSD: Couldn't find skip prologue entry.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
success = options_dict.GetValueForKeyAsBoolean(
|
||||
GetKey(OptionNames::ExactMatch), exact_match);
|
||||
if (!success) {
|
||||
error.SetErrorString("BRFL::CFSD: Couldn't find exact match entry.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileSpec file_spec(filename.c_str(), false);
|
||||
|
||||
return new BreakpointResolverFileLine(bkpt, file_spec, line_no, offset,
|
||||
check_inlines, skip_prologue,
|
||||
exact_match);
|
||||
}
|
||||
|
||||
StructuredData::ObjectSP
|
||||
BreakpointResolverFileLine::SerializeToStructuredData() {
|
||||
StructuredData::DictionarySP options_dict_sp(
|
||||
new StructuredData::Dictionary());
|
||||
|
||||
options_dict_sp->AddStringItem(GetKey(OptionNames::FileName),
|
||||
m_file_spec.GetPath());
|
||||
options_dict_sp->AddIntegerItem(GetKey(OptionNames::LineNumber),
|
||||
m_line_number);
|
||||
options_dict_sp->AddBooleanItem(GetKey(OptionNames::Inlines), m_inlines);
|
||||
options_dict_sp->AddBooleanItem(GetKey(OptionNames::SkipPrologue),
|
||||
m_skip_prologue);
|
||||
options_dict_sp->AddBooleanItem(GetKey(OptionNames::ExactMatch),
|
||||
m_exact_match);
|
||||
|
||||
return WrapOptionsDict(options_dict_sp);
|
||||
}
|
||||
|
||||
Searcher::CallbackReturn
|
||||
BreakpointResolverFileLine::SearchCallback(SearchFilter &filter,
|
||||
SymbolContext &context,
|
||||
|
||||
@@ -36,6 +36,70 @@ BreakpointResolverFileRegex::BreakpointResolverFileRegex(
|
||||
|
||||
BreakpointResolverFileRegex::~BreakpointResolverFileRegex() {}
|
||||
|
||||
BreakpointResolver *BreakpointResolverFileRegex::CreateFromStructuredData(
|
||||
Breakpoint *bkpt, StructuredData::Dictionary &options_dict, Error &error) {
|
||||
bool success;
|
||||
|
||||
std::string regex_string;
|
||||
success = options_dict.GetValueForKeyAsString(
|
||||
GetKey(OptionNames::RegexString), regex_string);
|
||||
if (!success) {
|
||||
error.SetErrorString("BRFR::CFSD: Couldn't find regex entry.");
|
||||
return nullptr;
|
||||
}
|
||||
RegularExpression regex(regex_string.c_str());
|
||||
|
||||
bool exact_match;
|
||||
success = options_dict.GetValueForKeyAsBoolean(
|
||||
GetKey(OptionNames::ExactMatch), exact_match);
|
||||
if (!success) {
|
||||
error.SetErrorString("BRFL::CFSD: Couldn't find exact match entry.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// The names array is optional:
|
||||
std::unordered_set<std::string> names_set;
|
||||
StructuredData::Array *names_array;
|
||||
success = options_dict.GetValueForKeyAsArray(
|
||||
GetKey(OptionNames::SymbolNameArray), names_array);
|
||||
if (success && names_array) {
|
||||
size_t num_names = names_array->GetSize();
|
||||
for (size_t i = 0; i < num_names; i++) {
|
||||
std::string name;
|
||||
success = names_array->GetItemAtIndexAsString(i, name);
|
||||
if (!success) {
|
||||
error.SetErrorStringWithFormat(
|
||||
"BRFR::CFSD: Malformed element %zu in the names array.", i);
|
||||
return nullptr;
|
||||
}
|
||||
names_set.insert(name);
|
||||
}
|
||||
}
|
||||
|
||||
return new BreakpointResolverFileRegex(bkpt, regex, names_set, exact_match);
|
||||
}
|
||||
|
||||
StructuredData::ObjectSP
|
||||
BreakpointResolverFileRegex::SerializeToStructuredData() {
|
||||
StructuredData::DictionarySP options_dict_sp(
|
||||
new StructuredData::Dictionary());
|
||||
|
||||
options_dict_sp->AddStringItem(GetKey(OptionNames::RegexString),
|
||||
m_regex.GetText());
|
||||
options_dict_sp->AddBooleanItem(GetKey(OptionNames::ExactMatch),
|
||||
m_exact_match);
|
||||
if (!m_function_names.empty()) {
|
||||
StructuredData::ArraySP names_array_sp(new StructuredData::Array());
|
||||
for (std::string name : m_function_names) {
|
||||
StructuredData::StringSP item(new StructuredData::String(name));
|
||||
names_array_sp->AddItem(item);
|
||||
}
|
||||
options_dict_sp->AddItem(GetKey(OptionNames::LineNumber), names_array_sp);
|
||||
}
|
||||
|
||||
return WrapOptionsDict(options_dict_sp);
|
||||
}
|
||||
|
||||
Searcher::CallbackReturn
|
||||
BreakpointResolverFileRegex::SearchCallback(SearchFilter &filter,
|
||||
SymbolContext &context,
|
||||
|
||||
@@ -80,19 +80,6 @@ BreakpointResolverName::BreakpointResolverName(Breakpoint *bkpt,
|
||||
m_match_type(Breakpoint::Regexp), m_language(language),
|
||||
m_skip_prologue(skip_prologue) {}
|
||||
|
||||
BreakpointResolverName::BreakpointResolverName(
|
||||
Breakpoint *bkpt, const char *class_name, const char *method,
|
||||
Breakpoint::MatchType type, lldb::addr_t offset, bool skip_prologue)
|
||||
: BreakpointResolver(bkpt, BreakpointResolver::NameResolver, offset),
|
||||
m_class_name(class_name), m_regex(), m_match_type(type),
|
||||
m_language(eLanguageTypeUnknown), m_skip_prologue(skip_prologue) {
|
||||
Module::LookupInfo lookup;
|
||||
lookup.SetName(ConstString(method));
|
||||
lookup.SetLookupName(lookup.GetName());
|
||||
lookup.SetNameTypeMask(eFunctionNameTypeMethod);
|
||||
m_lookups.push_back(lookup);
|
||||
}
|
||||
|
||||
BreakpointResolverName::~BreakpointResolverName() = default;
|
||||
|
||||
BreakpointResolverName::BreakpointResolverName(
|
||||
@@ -103,6 +90,132 @@ BreakpointResolverName::BreakpointResolverName(
|
||||
m_regex(rhs.m_regex), m_match_type(rhs.m_match_type),
|
||||
m_language(rhs.m_language), m_skip_prologue(rhs.m_skip_prologue) {}
|
||||
|
||||
BreakpointResolver *BreakpointResolverName::CreateFromStructuredData(
|
||||
Breakpoint *bkpt, StructuredData::Dictionary &options_dict, Error &error) {
|
||||
LanguageType language = eLanguageTypeUnknown;
|
||||
std::string language_name;
|
||||
bool success = options_dict.GetValueForKeyAsString(
|
||||
GetKey(OptionNames::LanguageName), language_name);
|
||||
if (success) {
|
||||
language = Language::GetLanguageTypeFromString(language_name.c_str());
|
||||
if (language == eLanguageTypeUnknown) {
|
||||
error.SetErrorStringWithFormat("BRN::CFSD: Unknown language: %s.",
|
||||
language_name.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
lldb::addr_t offset = 0;
|
||||
success =
|
||||
options_dict.GetValueForKeyAsInteger(GetKey(OptionNames::Offset), offset);
|
||||
if (!success) {
|
||||
error.SetErrorStringWithFormat("BRN::CFSD: Missing offset entry.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool skip_prologue;
|
||||
success = options_dict.GetValueForKeyAsBoolean(
|
||||
GetKey(OptionNames::SkipPrologue), skip_prologue);
|
||||
if (!success) {
|
||||
error.SetErrorStringWithFormat("BRN::CFSD: Missing Skip prologue entry.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string regex_text;
|
||||
success = options_dict.GetValueForKeyAsString(
|
||||
GetKey(OptionNames::RegexString), regex_text);
|
||||
if (success) {
|
||||
RegularExpression regex(regex_text.c_str());
|
||||
return new BreakpointResolverName(bkpt, regex, language, offset,
|
||||
skip_prologue);
|
||||
} else {
|
||||
StructuredData::Array *names_array;
|
||||
success = options_dict.GetValueForKeyAsArray(
|
||||
GetKey(OptionNames::SymbolNameArray), names_array);
|
||||
if (!success) {
|
||||
error.SetErrorStringWithFormat("BRN::CFSD: Missing symbol names entry.");
|
||||
return nullptr;
|
||||
}
|
||||
StructuredData::Array *names_mask_array;
|
||||
success = options_dict.GetValueForKeyAsArray(
|
||||
GetKey(OptionNames::NameMaskArray), names_mask_array);
|
||||
if (!success) {
|
||||
error.SetErrorStringWithFormat(
|
||||
"BRN::CFSD: Missing symbol names mask entry.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t num_elem = names_array->GetSize();
|
||||
if (num_elem != names_mask_array->GetSize()) {
|
||||
error.SetErrorString(
|
||||
"BRN::CFSD: names and names mask arrays have different sizes.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (num_elem == 0) {
|
||||
error.SetErrorString(
|
||||
"BRN::CFSD: no name entry in a breakpoint by name breakpoint.");
|
||||
return nullptr;
|
||||
}
|
||||
std::vector<std::string> names;
|
||||
std::vector<uint32_t> name_masks;
|
||||
for (size_t i = 0; i < num_elem; i++) {
|
||||
uint32_t name_mask;
|
||||
std::string name;
|
||||
|
||||
success = names_array->GetItemAtIndexAsString(i, name);
|
||||
if (!success) {
|
||||
error.SetErrorString("BRN::CFSD: name entry is not a string.");
|
||||
return nullptr;
|
||||
}
|
||||
success = names_mask_array->GetItemAtIndexAsInteger(i, name_mask);
|
||||
if (!success) {
|
||||
error.SetErrorString("BRN::CFSD: name mask entry is not an integer.");
|
||||
return nullptr;
|
||||
}
|
||||
names.push_back(name);
|
||||
name_masks.push_back(name_mask);
|
||||
}
|
||||
|
||||
BreakpointResolverName *resolver = new BreakpointResolverName(
|
||||
bkpt, names[0].c_str(), name_masks[0], language,
|
||||
Breakpoint::MatchType::Exact, offset, skip_prologue);
|
||||
for (size_t i = 1; i < num_elem; i++) {
|
||||
resolver->AddNameLookup(ConstString(names[i]), name_masks[i]);
|
||||
}
|
||||
return resolver;
|
||||
}
|
||||
}
|
||||
|
||||
StructuredData::ObjectSP BreakpointResolverName::SerializeToStructuredData() {
|
||||
StructuredData::DictionarySP options_dict_sp(
|
||||
new StructuredData::Dictionary());
|
||||
|
||||
if (m_regex.IsValid()) {
|
||||
options_dict_sp->AddStringItem(GetKey(OptionNames::RegexString),
|
||||
m_regex.GetText());
|
||||
} else {
|
||||
StructuredData::ArraySP names_sp(new StructuredData::Array());
|
||||
StructuredData::ArraySP name_masks_sp(new StructuredData::Array());
|
||||
for (auto lookup : m_lookups) {
|
||||
names_sp->AddItem(StructuredData::StringSP(
|
||||
new StructuredData::String(lookup.GetName().AsCString())));
|
||||
name_masks_sp->AddItem(StructuredData::IntegerSP(
|
||||
new StructuredData::Integer(lookup.GetNameTypeMask())));
|
||||
}
|
||||
options_dict_sp->AddItem(GetKey(OptionNames::SymbolNameArray), names_sp);
|
||||
options_dict_sp->AddItem(GetKey(OptionNames::NameMaskArray), name_masks_sp);
|
||||
}
|
||||
if (m_language != eLanguageTypeUnknown)
|
||||
options_dict_sp->AddStringItem(
|
||||
GetKey(OptionNames::LanguageName),
|
||||
Language::GetNameForLanguageType(m_language));
|
||||
options_dict_sp->AddBooleanItem(GetKey(OptionNames::SkipPrologue),
|
||||
m_skip_prologue);
|
||||
|
||||
return WrapOptionsDict(options_dict_sp);
|
||||
}
|
||||
|
||||
void BreakpointResolverName::AddNameLookup(const ConstString &name,
|
||||
uint32_t name_type_mask) {
|
||||
ObjCLanguage::MethodName objc_method(name.GetCString(), false);
|
||||
|
||||
@@ -523,25 +523,26 @@ protected:
|
||||
|
||||
case eSetTypeFunctionRegexp: // Breakpoint by regular expression function
|
||||
// name
|
||||
{
|
||||
RegularExpression regexp(m_options.m_func_regexp.c_str());
|
||||
if (!regexp.IsValid()) {
|
||||
char err_str[1024];
|
||||
regexp.GetErrorAsCString(err_str, sizeof(err_str));
|
||||
result.AppendErrorWithFormat(
|
||||
"Function name regular expression could not be compiled: \"%s\"",
|
||||
err_str);
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
{
|
||||
RegularExpression regexp(m_options.m_func_regexp.c_str());
|
||||
if (!regexp.IsValid()) {
|
||||
char err_str[1024];
|
||||
regexp.GetErrorAsCString(err_str, sizeof(err_str));
|
||||
result.AppendErrorWithFormat(
|
||||
"Function name regular expression could not be compiled: \"%s\"",
|
||||
err_str);
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
bp = target
|
||||
->CreateFuncRegexBreakpoint(
|
||||
&(m_options.m_modules), &(m_options.m_filenames), regexp,
|
||||
m_options.m_language, m_options.m_skip_prologue, internal,
|
||||
m_options.m_hardware)
|
||||
.get();
|
||||
} break;
|
||||
bp = target
|
||||
->CreateFuncRegexBreakpoint(
|
||||
&(m_options.m_modules), &(m_options.m_filenames), regexp,
|
||||
m_options.m_language, m_options.m_skip_prologue, internal,
|
||||
m_options.m_hardware)
|
||||
.get();
|
||||
}
|
||||
break;
|
||||
case eSetTypeSourceRegexp: // Breakpoint by regexp on source text.
|
||||
{
|
||||
const size_t num_files = m_options.m_filenames.GetSize();
|
||||
@@ -2058,7 +2059,7 @@ private:
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// CommandObjectMultiwordBreakpoint
|
||||
// CommandObjectBreakpointName
|
||||
//-------------------------------------------------------------------------
|
||||
class CommandObjectBreakpointName : public CommandObjectMultiword {
|
||||
public:
|
||||
@@ -2081,6 +2082,307 @@ public:
|
||||
~CommandObjectBreakpointName() override = default;
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// CommandObjectBreakpointRead
|
||||
//-------------------------------------------------------------------------
|
||||
#pragma mark Restore
|
||||
|
||||
class CommandObjectBreakpointRead : public CommandObjectParsed {
|
||||
public:
|
||||
CommandObjectBreakpointRead(CommandInterpreter &interpreter)
|
||||
: CommandObjectParsed(interpreter, "breakpoint read",
|
||||
"Read and set the breakpoints previously saved to "
|
||||
"a file with \"breakpoint write\". ",
|
||||
nullptr),
|
||||
m_options() {
|
||||
CommandArgumentEntry arg;
|
||||
CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
|
||||
eArgTypeBreakpointIDRange);
|
||||
// Add the entry for the first argument for this command to the object's
|
||||
// arguments vector.
|
||||
m_arguments.push_back(arg);
|
||||
}
|
||||
|
||||
~CommandObjectBreakpointRead() override = default;
|
||||
|
||||
Options *GetOptions() override { return &m_options; }
|
||||
|
||||
class CommandOptions : public Options {
|
||||
public:
|
||||
CommandOptions() : Options() {}
|
||||
|
||||
~CommandOptions() override = default;
|
||||
|
||||
Error SetOptionValue(uint32_t option_idx, const char *option_arg,
|
||||
ExecutionContext *execution_context) override {
|
||||
Error error;
|
||||
const int short_option = m_getopt_table[option_idx].val;
|
||||
|
||||
switch (short_option) {
|
||||
case 'f':
|
||||
m_filename.assign(option_arg);
|
||||
break;
|
||||
default:
|
||||
error.SetErrorStringWithFormat("unrecognized option '%c'",
|
||||
short_option);
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void OptionParsingStarting(ExecutionContext *execution_context) override {
|
||||
m_filename.clear();
|
||||
}
|
||||
|
||||
const OptionDefinition *GetDefinitions() override { return g_option_table; }
|
||||
|
||||
// Options table: Required for subclasses of Options.
|
||||
|
||||
static OptionDefinition g_option_table[];
|
||||
|
||||
// Instance variables to hold the values for command options.
|
||||
|
||||
std::string m_filename;
|
||||
};
|
||||
|
||||
protected:
|
||||
bool DoExecute(Args &command, CommandReturnObject &result) override {
|
||||
Target *target = GetSelectedOrDummyTarget();
|
||||
if (target == nullptr) {
|
||||
result.AppendError("Invalid target. No existing target or breakpoints.");
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
private:
|
||||
CommandOptions m_options;
|
||||
};
|
||||
|
||||
#pragma mark Modify::CommandOptions
|
||||
OptionDefinition CommandObjectBreakpointRead::CommandOptions::g_option_table[] =
|
||||
{
|
||||
// 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."},
|
||||
{0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// CommandObjectBreakpointWrite
|
||||
//-------------------------------------------------------------------------
|
||||
#pragma mark Save
|
||||
class CommandObjectBreakpointWrite : public CommandObjectParsed {
|
||||
public:
|
||||
CommandObjectBreakpointWrite(CommandInterpreter &interpreter)
|
||||
: CommandObjectParsed(interpreter, "breakpoint write",
|
||||
"Write the breakpoints listed to a file that can "
|
||||
"be read in with \"breakpoint read\". "
|
||||
"If given no arguments, writes all breakpoints.",
|
||||
nullptr),
|
||||
m_options() {
|
||||
CommandArgumentEntry arg;
|
||||
CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
|
||||
eArgTypeBreakpointIDRange);
|
||||
// Add the entry for the first argument for this command to the object's
|
||||
// arguments vector.
|
||||
m_arguments.push_back(arg);
|
||||
}
|
||||
|
||||
~CommandObjectBreakpointWrite() override = default;
|
||||
|
||||
Options *GetOptions() override { return &m_options; }
|
||||
|
||||
class CommandOptions : public Options {
|
||||
public:
|
||||
CommandOptions() : Options() {}
|
||||
|
||||
~CommandOptions() override = default;
|
||||
|
||||
Error SetOptionValue(uint32_t option_idx, const char *option_arg,
|
||||
ExecutionContext *execution_context) override {
|
||||
Error error;
|
||||
const int short_option = m_getopt_table[option_idx].val;
|
||||
|
||||
switch (short_option) {
|
||||
case 'f':
|
||||
m_filename.assign(option_arg);
|
||||
break;
|
||||
default:
|
||||
error.SetErrorStringWithFormat("unrecognized option '%c'",
|
||||
short_option);
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void OptionParsingStarting(ExecutionContext *execution_context) override {
|
||||
m_filename.clear();
|
||||
}
|
||||
|
||||
const OptionDefinition *GetDefinitions() override { return g_option_table; }
|
||||
|
||||
// Options table: Required for subclasses of Options.
|
||||
|
||||
static OptionDefinition g_option_table[];
|
||||
|
||||
// Instance variables to hold the values for command options.
|
||||
|
||||
std::string m_filename;
|
||||
};
|
||||
|
||||
protected:
|
||||
bool DoExecute(Args &command, CommandReturnObject &result) override {
|
||||
Target *target = GetSelectedOrDummyTarget();
|
||||
if (target == nullptr) {
|
||||
result.AppendError("Invalid target. No existing target or breakpoints.");
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break_store_sp->Dump(out_file, false);
|
||||
out_file.PutChar('\n');
|
||||
|
||||
return result.Succeeded();
|
||||
}
|
||||
|
||||
private:
|
||||
CommandOptions m_options;
|
||||
};
|
||||
|
||||
#pragma mark Modify::CommandOptions
|
||||
OptionDefinition
|
||||
CommandObjectBreakpointWrite::CommandOptions::g_option_table[] = {
|
||||
// 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."},
|
||||
{0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// CommandObjectMultiwordBreakpoint
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -2110,6 +2412,10 @@ CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint(
|
||||
new CommandObjectBreakpointModify(interpreter));
|
||||
CommandObjectSP name_command_object(
|
||||
new CommandObjectBreakpointName(interpreter));
|
||||
CommandObjectSP write_command_object(
|
||||
new CommandObjectBreakpointWrite(interpreter));
|
||||
CommandObjectSP read_command_object(
|
||||
new CommandObjectBreakpointRead(interpreter));
|
||||
|
||||
list_command_object->SetCommandName("breakpoint list");
|
||||
enable_command_object->SetCommandName("breakpoint enable");
|
||||
@@ -2120,6 +2426,8 @@ CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint(
|
||||
command_command_object->SetCommandName("breakpoint command");
|
||||
modify_command_object->SetCommandName("breakpoint modify");
|
||||
name_command_object->SetCommandName("breakpoint name");
|
||||
write_command_object->SetCommandName("breakpoint write");
|
||||
read_command_object->SetCommandName("breakpoint read");
|
||||
|
||||
LoadSubCommand("list", list_command_object);
|
||||
LoadSubCommand("enable", enable_command_object);
|
||||
@@ -2130,6 +2438,8 @@ CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint(
|
||||
LoadSubCommand("command", command_command_object);
|
||||
LoadSubCommand("modify", modify_command_object);
|
||||
LoadSubCommand("name", name_command_object);
|
||||
LoadSubCommand("write", write_command_object);
|
||||
LoadSubCommand("read", read_command_object);
|
||||
}
|
||||
|
||||
CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint() = default;
|
||||
|
||||
@@ -215,14 +215,10 @@ are no syntax errors may indicate that a function was declared but never called.
|
||||
if (!bp_options)
|
||||
continue;
|
||||
|
||||
std::unique_ptr<BreakpointOptions::CommandData> data_ap(
|
||||
new BreakpointOptions::CommandData());
|
||||
if (data_ap) {
|
||||
data_ap->user_source.SplitIntoLines(line.c_str(), line.size());
|
||||
BatonSP baton_sp(
|
||||
new BreakpointOptions::CommandBaton(data_ap.release()));
|
||||
bp_options->SetCallback(BreakpointOptionsCallbackFunction, baton_sp);
|
||||
}
|
||||
BreakpointOptions::CommandData *cmd_data =
|
||||
new BreakpointOptions::CommandData();
|
||||
cmd_data->user_source.SplitIntoLines(line.c_str(), line.size());
|
||||
bp_options->SetCommandDataCallback(cmd_data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,8 +238,8 @@ are no syntax errors may indicate that a function was declared but never called.
|
||||
SetBreakpointCommandCallback(std::vector<BreakpointOptions *> &bp_options_vec,
|
||||
const char *oneliner) {
|
||||
for (auto bp_options : bp_options_vec) {
|
||||
std::unique_ptr<BreakpointOptions::CommandData> data_ap(
|
||||
new BreakpointOptions::CommandData());
|
||||
BreakpointOptions::CommandData *cmd_data =
|
||||
new BreakpointOptions::CommandData();
|
||||
|
||||
// It's necessary to set both user_source and script_source to the
|
||||
// oneliner.
|
||||
@@ -251,57 +247,14 @@ are no syntax errors may indicate that a function was declared but never called.
|
||||
// command list)
|
||||
// while the latter is used for Python to interpret during the actual
|
||||
// callback.
|
||||
data_ap->user_source.AppendString(oneliner);
|
||||
data_ap->script_source.assign(oneliner);
|
||||
data_ap->stop_on_error = m_options.m_stop_on_error;
|
||||
cmd_data->user_source.AppendString(oneliner);
|
||||
cmd_data->script_source.assign(oneliner);
|
||||
cmd_data->stop_on_error = m_options.m_stop_on_error;
|
||||
|
||||
BatonSP baton_sp(new BreakpointOptions::CommandBaton(data_ap.release()));
|
||||
bp_options->SetCallback(BreakpointOptionsCallbackFunction, baton_sp);
|
||||
bp_options->SetCommandDataCallback(cmd_data);
|
||||
}
|
||||
}
|
||||
|
||||
static bool BreakpointOptionsCallbackFunction(
|
||||
void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id,
|
||||
lldb::user_id_t break_loc_id) {
|
||||
bool ret_value = true;
|
||||
if (baton == nullptr)
|
||||
return true;
|
||||
|
||||
BreakpointOptions::CommandData *data =
|
||||
(BreakpointOptions::CommandData *)baton;
|
||||
StringList &commands = data->user_source;
|
||||
|
||||
if (commands.GetSize() > 0) {
|
||||
ExecutionContext exe_ctx(context->exe_ctx_ref);
|
||||
Target *target = exe_ctx.GetTargetPtr();
|
||||
if (target) {
|
||||
CommandReturnObject result;
|
||||
Debugger &debugger = target->GetDebugger();
|
||||
// Rig up the results secondary output stream to the debugger's, so the
|
||||
// output will come out synchronously
|
||||
// if the debugger is set up that way.
|
||||
|
||||
StreamSP output_stream(debugger.GetAsyncOutputStream());
|
||||
StreamSP error_stream(debugger.GetAsyncErrorStream());
|
||||
result.SetImmediateOutputStream(output_stream);
|
||||
result.SetImmediateErrorStream(error_stream);
|
||||
|
||||
CommandInterpreterRunOptions options;
|
||||
options.SetStopOnContinue(true);
|
||||
options.SetStopOnError(data->stop_on_error);
|
||||
options.SetEchoCommands(true);
|
||||
options.SetPrintResults(true);
|
||||
options.SetAddToHistory(false);
|
||||
|
||||
debugger.GetCommandInterpreter().HandleCommands(commands, &exe_ctx,
|
||||
options, result);
|
||||
result.GetImmediateOutputStream()->Flush();
|
||||
result.GetImmediateErrorStream()->Flush();
|
||||
}
|
||||
}
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
class CommandOptions : public Options {
|
||||
public:
|
||||
CommandOptions()
|
||||
|
||||
@@ -21,14 +21,37 @@
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
const char *SearchFilter::g_ty_to_name[] = {"Unconstrained", "Exception",
|
||||
"Module", "Modules",
|
||||
"ModulesAndCU", "Unknown"};
|
||||
|
||||
const char
|
||||
*SearchFilter::g_option_names[SearchFilter::OptionNames::LastOptionName] = {
|
||||
"ModuleList", "CUList"};
|
||||
|
||||
const char *SearchFilter::FilterTyToName(enum FilterTy type) {
|
||||
if (type > LastKnownFilterType)
|
||||
return g_ty_to_name[UnknownFilter];
|
||||
|
||||
return g_ty_to_name[type];
|
||||
}
|
||||
|
||||
SearchFilter::FilterTy SearchFilter::NameToFilterTy(const char *name) {
|
||||
for (size_t i = 0; i < LastKnownFilterType; i++) {
|
||||
if (strcmp(name, g_ty_to_name[i]) == 0)
|
||||
return (FilterTy)i;
|
||||
}
|
||||
return UnknownFilter;
|
||||
}
|
||||
|
||||
Searcher::Searcher() = default;
|
||||
|
||||
Searcher::~Searcher() = default;
|
||||
|
||||
void Searcher::GetDescription(Stream *s) {}
|
||||
|
||||
SearchFilter::SearchFilter(const TargetSP &target_sp)
|
||||
: m_target_sp(target_sp) {}
|
||||
SearchFilter::SearchFilter(const TargetSP &target_sp, unsigned char filterType)
|
||||
: m_target_sp(target_sp), SubclassID(filterType) {}
|
||||
|
||||
SearchFilter::SearchFilter(const SearchFilter &rhs) = default;
|
||||
|
||||
@@ -36,6 +59,65 @@ SearchFilter &SearchFilter::operator=(const SearchFilter &rhs) = default;
|
||||
|
||||
SearchFilter::~SearchFilter() = default;
|
||||
|
||||
SearchFilter *SearchFilter::CreateFromStructuredData(
|
||||
Target &target, StructuredData::Dictionary &filter_dict, Error &error) {
|
||||
SearchFilter *result = nullptr;
|
||||
if (!filter_dict.IsValid()) {
|
||||
error.SetErrorString("Can't deserialize from an invalid data object.");
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string subclass_name;
|
||||
|
||||
bool success = filter_dict.GetValueForKeyAsString(
|
||||
GetSerializationSubclassKey(), subclass_name);
|
||||
if (!success) {
|
||||
error.SetErrorStringWithFormat("Filter data missing subclass key");
|
||||
return result;
|
||||
}
|
||||
|
||||
FilterTy filter_type = NameToFilterTy(subclass_name.c_str());
|
||||
if (filter_type == UnknownFilter) {
|
||||
error.SetErrorStringWithFormat("Unknown filter type: %s.",
|
||||
subclass_name.c_str());
|
||||
return result;
|
||||
}
|
||||
|
||||
StructuredData::Dictionary *subclass_options = nullptr;
|
||||
success = filter_dict.GetValueForKeyAsDictionary(
|
||||
GetSerializationSubclassOptionsKey(), subclass_options);
|
||||
if (!success || !subclass_options || !subclass_options->IsValid()) {
|
||||
error.SetErrorString("Filter data missing subclass options key.");
|
||||
return result;
|
||||
}
|
||||
|
||||
switch (filter_type) {
|
||||
case Unconstrained:
|
||||
result = SearchFilterForUnconstrainedSearches::CreateFromStructuredData(
|
||||
target, *subclass_options, error);
|
||||
break;
|
||||
case ByModule:
|
||||
result = SearchFilterByModule::CreateFromStructuredData(
|
||||
target, *subclass_options, error);
|
||||
break;
|
||||
case ByModules:
|
||||
result = SearchFilterByModuleList::CreateFromStructuredData(
|
||||
target, *subclass_options, error);
|
||||
break;
|
||||
case ByModulesAndCU:
|
||||
result = SearchFilterByModuleListAndCU::CreateFromStructuredData(
|
||||
target, *subclass_options, error);
|
||||
break;
|
||||
case Exception:
|
||||
error.SetErrorString("Can't serialize exception breakpoints yet.");
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("Should never get an uresolvable filter type.");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool SearchFilter::ModulePasses(const FileSpec &spec) { return true; }
|
||||
|
||||
bool SearchFilter::ModulePasses(const ModuleSP &module_sp) { return true; }
|
||||
@@ -61,6 +143,34 @@ lldb::SearchFilterSP SearchFilter::CopyForBreakpoint(Breakpoint &breakpoint) {
|
||||
return ret_sp;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Helper functions for serialization.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
StructuredData::DictionarySP
|
||||
SearchFilter::WrapOptionsDict(StructuredData::DictionarySP options_dict_sp) {
|
||||
if (!options_dict_sp || !options_dict_sp->IsValid())
|
||||
return StructuredData::DictionarySP();
|
||||
|
||||
StructuredData::DictionarySP type_dict_sp(new StructuredData::Dictionary());
|
||||
type_dict_sp->AddStringItem(GetSerializationSubclassKey(), GetFilterName());
|
||||
type_dict_sp->AddItem(GetSerializationSubclassOptionsKey(), options_dict_sp);
|
||||
|
||||
return type_dict_sp;
|
||||
}
|
||||
|
||||
void SearchFilter::SerializeFileSpecList(
|
||||
StructuredData::DictionarySP &options_dict_sp, OptionNames name,
|
||||
FileSpecList &file_list) {
|
||||
StructuredData::ArraySP module_array_sp(new StructuredData::Array());
|
||||
size_t num_modules = file_list.GetSize();
|
||||
for (size_t i = 0; i < num_modules; i++) {
|
||||
module_array_sp->AddItem(StructuredData::StringSP(
|
||||
new StructuredData::String(file_list.GetFileSpecAtIndex(i).GetPath())));
|
||||
}
|
||||
options_dict_sp->AddItem(GetKey(name), module_array_sp);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// UTILITY Functions to help iterate down through the elements of the
|
||||
// SymbolContext.
|
||||
@@ -202,6 +312,18 @@ Searcher::CallbackReturn SearchFilter::DoFunctionIteration(
|
||||
// Selects a shared library matching a given file spec, consulting the targets
|
||||
// "black list".
|
||||
//----------------------------------------------------------------------
|
||||
SearchFilter *SearchFilterForUnconstrainedSearches::CreateFromStructuredData(
|
||||
Target &target, StructuredData::Dictionary &data_dict, Error &error) {
|
||||
// No options for an unconstrained search.
|
||||
return new SearchFilterForUnconstrainedSearches(target.shared_from_this());
|
||||
}
|
||||
|
||||
StructuredData::ObjectSP
|
||||
SearchFilterForUnconstrainedSearches::SerializeToStructuredData() {
|
||||
// The options dictionary is an empty dictionary:
|
||||
StructuredData::DictionarySP result_sp(new StructuredData::Dictionary());
|
||||
return WrapOptionsDict(result_sp);
|
||||
}
|
||||
|
||||
bool SearchFilterForUnconstrainedSearches::ModulePasses(
|
||||
const FileSpec &module_spec) {
|
||||
@@ -234,7 +356,7 @@ lldb::SearchFilterSP SearchFilterForUnconstrainedSearches::DoCopyForBreakpoint(
|
||||
|
||||
SearchFilterByModule::SearchFilterByModule(const lldb::TargetSP &target_sp,
|
||||
const FileSpec &module)
|
||||
: SearchFilter(target_sp), m_module_spec(module) {}
|
||||
: SearchFilter(target_sp, FilterTy::ByModule), m_module_spec(module) {}
|
||||
|
||||
SearchFilterByModule::SearchFilterByModule(const SearchFilterByModule &rhs) =
|
||||
default;
|
||||
@@ -325,6 +447,44 @@ SearchFilterByModule::DoCopyForBreakpoint(Breakpoint &breakpoint) {
|
||||
return ret_sp;
|
||||
}
|
||||
|
||||
SearchFilter *SearchFilterByModule::CreateFromStructuredData(
|
||||
Target &target, StructuredData::Dictionary &data_dict, Error &error) {
|
||||
StructuredData::Array *modules_array;
|
||||
bool success = data_dict.GetValueForKeyAsArray(GetKey(OptionNames::ModList),
|
||||
modules_array);
|
||||
if (!success) {
|
||||
error.SetErrorString("SFBM::CFSD: Could not find the module list key.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t num_modules = modules_array->GetSize();
|
||||
if (num_modules > 1) {
|
||||
error.SetErrorString(
|
||||
"SFBM::CFSD: Only one modules allowed for SearchFilterByModule.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string module;
|
||||
success = modules_array->GetItemAtIndexAsString(0, module);
|
||||
if (!success) {
|
||||
error.SetErrorString("SFBM::CFSD: filter module item not a string.");
|
||||
return nullptr;
|
||||
}
|
||||
FileSpec module_spec(module.c_str(), false);
|
||||
|
||||
return new SearchFilterByModule(target.shared_from_this(), module_spec);
|
||||
}
|
||||
|
||||
StructuredData::ObjectSP SearchFilterByModule::SerializeToStructuredData() {
|
||||
StructuredData::DictionarySP options_dict_sp(
|
||||
new StructuredData::Dictionary());
|
||||
StructuredData::ArraySP module_array_sp(new StructuredData::Array());
|
||||
module_array_sp->AddItem(StructuredData::StringSP(
|
||||
new StructuredData::String(m_module_spec.GetPath())));
|
||||
options_dict_sp->AddItem(GetKey(OptionNames::ModList), module_array_sp);
|
||||
return WrapOptionsDict(options_dict_sp);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// SearchFilterByModuleList:
|
||||
// Selects a shared library matching a given file spec
|
||||
@@ -332,7 +492,13 @@ SearchFilterByModule::DoCopyForBreakpoint(Breakpoint &breakpoint) {
|
||||
|
||||
SearchFilterByModuleList::SearchFilterByModuleList(
|
||||
const lldb::TargetSP &target_sp, const FileSpecList &module_list)
|
||||
: SearchFilter(target_sp), m_module_spec_list(module_list) {}
|
||||
: SearchFilter(target_sp, FilterTy::ByModules),
|
||||
m_module_spec_list(module_list) {}
|
||||
|
||||
SearchFilterByModuleList::SearchFilterByModuleList(
|
||||
const lldb::TargetSP &target_sp, const FileSpecList &module_list,
|
||||
enum FilterTy filter_ty)
|
||||
: SearchFilter(target_sp, filter_ty), m_module_spec_list(module_list) {}
|
||||
|
||||
SearchFilterByModuleList::SearchFilterByModuleList(
|
||||
const SearchFilterByModuleList &rhs) = default;
|
||||
@@ -456,6 +622,45 @@ SearchFilterByModuleList::DoCopyForBreakpoint(Breakpoint &breakpoint) {
|
||||
return ret_sp;
|
||||
}
|
||||
|
||||
SearchFilter *SearchFilterByModuleList::CreateFromStructuredData(
|
||||
Target &target, StructuredData::Dictionary &data_dict, Error &error) {
|
||||
StructuredData::Array *modules_array;
|
||||
bool success = data_dict.GetValueForKeyAsArray(GetKey(OptionNames::ModList),
|
||||
modules_array);
|
||||
if (!success) {
|
||||
error.SetErrorString("SFBM::CFSD: Could not find the module list key.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t num_modules = modules_array->GetSize();
|
||||
FileSpecList modules;
|
||||
for (size_t i = 0; i < num_modules; i++) {
|
||||
std::string module;
|
||||
success = modules_array->GetItemAtIndexAsString(i, module);
|
||||
if (!success) {
|
||||
error.SetErrorStringWithFormat(
|
||||
"SFBM::CFSD: filter module item %zu not a string.", i);
|
||||
return nullptr;
|
||||
}
|
||||
modules.Append(FileSpec(module.c_str(), false));
|
||||
}
|
||||
|
||||
return new SearchFilterByModuleList(target.shared_from_this(), modules);
|
||||
}
|
||||
|
||||
void SearchFilterByModuleList::SerializeUnwrapped(
|
||||
StructuredData::DictionarySP &options_dict_sp) {
|
||||
SerializeFileSpecList(options_dict_sp, OptionNames::ModList,
|
||||
m_module_spec_list);
|
||||
}
|
||||
|
||||
StructuredData::ObjectSP SearchFilterByModuleList::SerializeToStructuredData() {
|
||||
StructuredData::DictionarySP options_dict_sp(
|
||||
new StructuredData::Dictionary());
|
||||
SerializeUnwrapped(options_dict_sp);
|
||||
return WrapOptionsDict(options_dict_sp);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// SearchFilterByModuleListAndCU:
|
||||
// Selects a shared library matching a given file spec
|
||||
@@ -464,7 +669,8 @@ SearchFilterByModuleList::DoCopyForBreakpoint(Breakpoint &breakpoint) {
|
||||
SearchFilterByModuleListAndCU::SearchFilterByModuleListAndCU(
|
||||
const lldb::TargetSP &target_sp, const FileSpecList &module_list,
|
||||
const FileSpecList &cu_list)
|
||||
: SearchFilterByModuleList(target_sp, module_list),
|
||||
: SearchFilterByModuleList(target_sp, module_list,
|
||||
FilterTy::ByModulesAndCU),
|
||||
m_cu_spec_list(cu_list) {}
|
||||
|
||||
SearchFilterByModuleListAndCU::SearchFilterByModuleListAndCU(
|
||||
@@ -482,6 +688,63 @@ operator=(const SearchFilterByModuleListAndCU &rhs) {
|
||||
|
||||
SearchFilterByModuleListAndCU::~SearchFilterByModuleListAndCU() = default;
|
||||
|
||||
SearchFilter *SearchFilterByModuleListAndCU::CreateFromStructuredData(
|
||||
Target &target, StructuredData::Dictionary &data_dict, Error &error) {
|
||||
StructuredData::Array *modules_array;
|
||||
bool success = data_dict.GetValueForKeyAsArray(GetKey(OptionNames::ModList),
|
||||
modules_array);
|
||||
if (!success) {
|
||||
error.SetErrorString("SFBM::CFSD: Could not find the module list key.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t num_modules = modules_array->GetSize();
|
||||
FileSpecList modules;
|
||||
for (size_t i = 0; i < num_modules; i++) {
|
||||
std::string module;
|
||||
success = modules_array->GetItemAtIndexAsString(i, module);
|
||||
if (!success) {
|
||||
error.SetErrorStringWithFormat(
|
||||
"SFBM::CFSD: filter module item %zu not a string.", i);
|
||||
return nullptr;
|
||||
}
|
||||
modules.Append(FileSpec(module.c_str(), false));
|
||||
}
|
||||
|
||||
StructuredData::Array *cus_array;
|
||||
success =
|
||||
data_dict.GetValueForKeyAsArray(GetKey(OptionNames::CUList), cus_array);
|
||||
if (!success) {
|
||||
error.SetErrorString("SFBM::CFSD: Could not find the CU list key.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t num_cus = cus_array->GetSize();
|
||||
FileSpecList cus;
|
||||
for (size_t i = 0; i < num_cus; i++) {
|
||||
std::string cu;
|
||||
success = modules_array->GetItemAtIndexAsString(i, cu);
|
||||
if (!success) {
|
||||
error.SetErrorStringWithFormat(
|
||||
"SFBM::CFSD: filter cu item %zu not a string.", i);
|
||||
return nullptr;
|
||||
}
|
||||
cus.Append(FileSpec(cu.c_str(), false));
|
||||
}
|
||||
|
||||
return new SearchFilterByModuleListAndCU(target.shared_from_this(), modules,
|
||||
cus);
|
||||
}
|
||||
|
||||
StructuredData::ObjectSP
|
||||
SearchFilterByModuleListAndCU::SerializeToStructuredData() {
|
||||
StructuredData::DictionarySP options_dict_sp(
|
||||
new StructuredData::Dictionary());
|
||||
SearchFilterByModuleList::SerializeUnwrapped(options_dict_sp);
|
||||
SerializeFileSpecList(options_dict_sp, OptionNames::CUList, m_cu_spec_list);
|
||||
return WrapOptionsDict(options_dict_sp);
|
||||
}
|
||||
|
||||
bool SearchFilterByModuleListAndCU::AddressPasses(Address &address) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,11 @@
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "lldb/Core/DataBuffer.h"
|
||||
#include "lldb/Core/Error.h"
|
||||
#include "lldb/Core/StreamString.h"
|
||||
#include "lldb/Host/File.h"
|
||||
#include "lldb/Host/FileSpec.h"
|
||||
#include "lldb/Host/StringConvert.h"
|
||||
#include "lldb/Utility/JSON.h"
|
||||
|
||||
@@ -27,6 +31,44 @@ 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 return_sp;
|
||||
if (!input_spec.Exists()) {
|
||||
error.SetErrorStringWithFormat("input file %s does not exist.",
|
||||
input_spec.GetPath().c_str());
|
||||
return return_sp;
|
||||
}
|
||||
|
||||
File input_file(nullptr, File::OpenOptions::eOpenOptionRead,
|
||||
lldb::eFilePermissionsUserRead);
|
||||
std::string input_path = input_spec.GetPath();
|
||||
error =
|
||||
input_file.Open(input_path.c_str(), File::OpenOptions::eOpenOptionRead,
|
||||
lldb::eFilePermissionsUserRead);
|
||||
|
||||
if (!error.Success()) {
|
||||
error.SetErrorStringWithFormat("could not open input file: %s - %s.",
|
||||
input_spec.GetPath().c_str(),
|
||||
error.AsCString());
|
||||
return return_sp;
|
||||
}
|
||||
|
||||
lldb::DataBufferSP input_data;
|
||||
size_t num_bytes = SIZE_T_MAX;
|
||||
off_t offset = 0;
|
||||
error = input_file.Read(num_bytes, offset, true, input_data);
|
||||
if (!error.Success()) {
|
||||
error.SetErrorStringWithFormat("could not read input file: %s - %s.",
|
||||
input_spec.GetPath().c_str(),
|
||||
error.AsCString());
|
||||
return return_sp;
|
||||
}
|
||||
JSONParser json_parser((char *)input_data->GetBytes());
|
||||
return_sp = ParseJSONValue(json_parser);
|
||||
return return_sp;
|
||||
}
|
||||
|
||||
static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser) {
|
||||
// The "JSONParser::Token::ObjectStart" token should have already been
|
||||
// consumed
|
||||
|
||||
@@ -420,7 +420,7 @@ void ScriptInterpreterPython::IOHandlerInputComplete(IOHandler &io_handler,
|
||||
if (GenerateBreakpointCommandCallbackData(data_ap->user_source,
|
||||
data_ap->script_source)
|
||||
.Success()) {
|
||||
BatonSP baton_sp(
|
||||
BreakpointOptions::CommandBatonSP baton_sp(
|
||||
new BreakpointOptions::CommandBaton(data_ap.release()));
|
||||
bp_options->SetCallback(
|
||||
ScriptInterpreterPython::BreakpointCallbackFunction, baton_sp);
|
||||
@@ -1050,11 +1050,11 @@ bool ScriptInterpreterPython::ExecuteOneLineWithReturn(
|
||||
}
|
||||
case eScriptReturnTypeCharStrOrNone: // char* or NULL if py_return ==
|
||||
// Py_None
|
||||
{
|
||||
const char format[3] = "z";
|
||||
success = PyArg_Parse(py_return.get(), format, (char **)ret_value);
|
||||
break;
|
||||
}
|
||||
{
|
||||
const char format[3] = "z";
|
||||
success = PyArg_Parse(py_return.get(), format, (char **)ret_value);
|
||||
break;
|
||||
}
|
||||
case eScriptReturnTypeBool: {
|
||||
const char format[2] = "b";
|
||||
success = PyArg_Parse(py_return.get(), format, (bool *)ret_value);
|
||||
@@ -1251,7 +1251,8 @@ Error ScriptInterpreterPython::SetBreakpointCommandCallback(
|
||||
Error error = GenerateBreakpointCommandCallbackData(data_ap->user_source,
|
||||
data_ap->script_source);
|
||||
if (error.Success()) {
|
||||
BatonSP baton_sp(new BreakpointOptions::CommandBaton(data_ap.release()));
|
||||
BreakpointOptions::CommandBatonSP baton_sp(
|
||||
new BreakpointOptions::CommandBaton(data_ap.release()));
|
||||
bp_options->SetCallback(ScriptInterpreterPython::BreakpointCallbackFunction,
|
||||
baton_sp);
|
||||
return error;
|
||||
|
||||
@@ -23,80 +23,83 @@
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
class ExceptionSearchFilter : public SearchFilter {
|
||||
public:
|
||||
ExceptionSearchFilter(const lldb::TargetSP &target_sp,
|
||||
lldb::LanguageType language,
|
||||
bool update_module_list = true)
|
||||
: SearchFilter(target_sp), m_language(language),
|
||||
m_language_runtime(nullptr), m_filter_sp() {
|
||||
if (update_module_list)
|
||||
UpdateModuleListIfNeeded();
|
||||
}
|
||||
|
||||
~ExceptionSearchFilter() override = default;
|
||||
|
||||
bool ModulePasses(const lldb::ModuleSP &module_sp) override {
|
||||
ExceptionSearchFilter::ExceptionSearchFilter(const lldb::TargetSP &target_sp,
|
||||
lldb::LanguageType language,
|
||||
bool update_module_list)
|
||||
: SearchFilter(target_sp, FilterTy::Exception), m_language(language),
|
||||
m_language_runtime(nullptr), m_filter_sp() {
|
||||
if (update_module_list)
|
||||
UpdateModuleListIfNeeded();
|
||||
if (m_filter_sp)
|
||||
return m_filter_sp->ModulePasses(module_sp);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ModulePasses(const FileSpec &spec) override {
|
||||
UpdateModuleListIfNeeded();
|
||||
if (m_filter_sp)
|
||||
return m_filter_sp->ModulePasses(spec);
|
||||
return false;
|
||||
}
|
||||
bool ExceptionSearchFilter::ModulePasses(const lldb::ModuleSP &module_sp) {
|
||||
UpdateModuleListIfNeeded();
|
||||
if (m_filter_sp)
|
||||
return m_filter_sp->ModulePasses(module_sp);
|
||||
return false;
|
||||
}
|
||||
|
||||
void Search(Searcher &searcher) override {
|
||||
UpdateModuleListIfNeeded();
|
||||
if (m_filter_sp)
|
||||
m_filter_sp->Search(searcher);
|
||||
}
|
||||
bool ExceptionSearchFilter::ModulePasses(const FileSpec &spec) {
|
||||
UpdateModuleListIfNeeded();
|
||||
if (m_filter_sp)
|
||||
return m_filter_sp->ModulePasses(spec);
|
||||
return false;
|
||||
}
|
||||
|
||||
void GetDescription(Stream *s) override {
|
||||
UpdateModuleListIfNeeded();
|
||||
if (m_filter_sp)
|
||||
m_filter_sp->GetDescription(s);
|
||||
}
|
||||
void ExceptionSearchFilter::Search(Searcher &searcher) {
|
||||
UpdateModuleListIfNeeded();
|
||||
if (m_filter_sp)
|
||||
m_filter_sp->Search(searcher);
|
||||
}
|
||||
|
||||
protected:
|
||||
LanguageType m_language;
|
||||
LanguageRuntime *m_language_runtime;
|
||||
SearchFilterSP m_filter_sp;
|
||||
void ExceptionSearchFilter::GetDescription(Stream *s) {
|
||||
UpdateModuleListIfNeeded();
|
||||
if (m_filter_sp)
|
||||
m_filter_sp->GetDescription(s);
|
||||
}
|
||||
|
||||
SearchFilterSP DoCopyForBreakpoint(Breakpoint &breakpoint) override {
|
||||
return SearchFilterSP(
|
||||
new ExceptionSearchFilter(TargetSP(), m_language, false));
|
||||
}
|
||||
|
||||
void UpdateModuleListIfNeeded() {
|
||||
ProcessSP process_sp(m_target_sp->GetProcessSP());
|
||||
if (process_sp) {
|
||||
bool refreash_filter = !m_filter_sp;
|
||||
if (m_language_runtime == nullptr) {
|
||||
m_language_runtime = process_sp->GetLanguageRuntime(m_language);
|
||||
refreash_filter = true;
|
||||
} else {
|
||||
LanguageRuntime *language_runtime =
|
||||
process_sp->GetLanguageRuntime(m_language);
|
||||
if (m_language_runtime != language_runtime) {
|
||||
m_language_runtime = language_runtime;
|
||||
refreash_filter = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (refreash_filter && m_language_runtime) {
|
||||
m_filter_sp = m_language_runtime->CreateExceptionSearchFilter();
|
||||
}
|
||||
void ExceptionSearchFilter::UpdateModuleListIfNeeded() {
|
||||
ProcessSP process_sp(m_target_sp->GetProcessSP());
|
||||
if (process_sp) {
|
||||
bool refreash_filter = !m_filter_sp;
|
||||
if (m_language_runtime == nullptr) {
|
||||
m_language_runtime = process_sp->GetLanguageRuntime(m_language);
|
||||
refreash_filter = true;
|
||||
} else {
|
||||
m_filter_sp.reset();
|
||||
m_language_runtime = nullptr;
|
||||
LanguageRuntime *language_runtime =
|
||||
process_sp->GetLanguageRuntime(m_language);
|
||||
if (m_language_runtime != language_runtime) {
|
||||
m_language_runtime = language_runtime;
|
||||
refreash_filter = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (refreash_filter && m_language_runtime) {
|
||||
m_filter_sp = m_language_runtime->CreateExceptionSearchFilter();
|
||||
}
|
||||
} else {
|
||||
m_filter_sp.reset();
|
||||
m_language_runtime = nullptr;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
SearchFilterSP
|
||||
ExceptionSearchFilter::DoCopyForBreakpoint(Breakpoint &breakpoint) {
|
||||
return SearchFilterSP(
|
||||
new ExceptionSearchFilter(TargetSP(), m_language, false));
|
||||
}
|
||||
|
||||
SearchFilter *ExceptionSearchFilter::CreateFromStructuredData(
|
||||
Target &target, StructuredData::Dictionary &data_dict, Error &error) {
|
||||
SearchFilter *result = nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
StructuredData::ObjectSP ExceptionSearchFilter::SerializeToStructuredData() {
|
||||
StructuredData::ObjectSP result_sp;
|
||||
|
||||
return result_sp;
|
||||
}
|
||||
|
||||
// The Target is the one that knows how to create breakpoints, so this function
|
||||
// is meant to be used either by the target or internally in
|
||||
|
||||
Reference in New Issue
Block a user