From e14dc26857470f248e5fc1dd14d89314eae47fa5 Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Mon, 12 Sep 2016 23:10:56 +0000 Subject: [PATCH] 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. llvm-svn: 281273 --- lldb/include/lldb/Breakpoint/Breakpoint.h | 11 +- lldb/include/lldb/Breakpoint/BreakpointOptions.h | 126 +++++--- lldb/include/lldb/Breakpoint/BreakpointResolver.h | 74 ++++- .../lldb/Breakpoint/BreakpointResolverAddress.h | 5 + .../lldb/Breakpoint/BreakpointResolverFileLine.h | 6 + .../lldb/Breakpoint/BreakpointResolverFileRegex.h | 5 + .../lldb/Breakpoint/BreakpointResolverName.h | 8 +- lldb/include/lldb/Core/SearchFilter.h | 91 +++++- lldb/include/lldb/Core/StructuredData.h | 14 + lldb/include/lldb/Target/LanguageRuntime.h | 34 +- lldb/source/Breakpoint/Breakpoint.cpp | 191 ++++++++--- lldb/source/Breakpoint/BreakpointOptions.cpp | 220 ++++++++++++- lldb/source/Breakpoint/BreakpointResolver.cpp | 124 ++++++++ .../Breakpoint/BreakpointResolverAddress.cpp | 57 ++++ .../Breakpoint/BreakpointResolverFileLine.cpp | 71 +++++ .../Breakpoint/BreakpointResolverFileRegex.cpp | 64 ++++ lldb/source/Breakpoint/BreakpointResolverName.cpp | 139 +++++++- lldb/source/Commands/CommandObjectBreakpoint.cpp | 348 +++++++++++++++++++-- .../Commands/CommandObjectBreakpointCommand.cpp | 67 +--- lldb/source/Core/SearchFilter.cpp | 273 +++++++++++++++- lldb/source/Core/StructuredData.cpp | 42 +++ .../Python/ScriptInterpreterPython.cpp | 15 +- lldb/source/Target/LanguageRuntime.cpp | 129 ++++---- 23 files changed, 1859 insertions(+), 255 deletions(-) diff --git a/lldb/include/lldb/Breakpoint/Breakpoint.h b/lldb/include/lldb/Breakpoint/Breakpoint.h index bef10db..e002f71 100644 --- a/lldb/include/lldb/Breakpoint/Breakpoint.h +++ b/lldb/include/lldb/Breakpoint/Breakpoint.h @@ -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 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 + m_options_up; // Settable breakpoint options BreakpointLocationList m_locations; // The list of locations currently found for this breakpoint. std::string m_kind_description; diff --git a/lldb/include/lldb/Breakpoint/BreakpointOptions.h b/lldb/include/lldb/Breakpoint/BreakpointOptions.h index 281d594..5397fb6 100644 --- a/lldb/include/lldb/Breakpoint/BreakpointOptions.h +++ b/lldb/include/lldb/Breakpoint/BreakpointOptions.h @@ -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 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; diff --git a/lldb/include/lldb/Breakpoint/BreakpointResolver.h b/lldb/include/lldb/Breakpoint/BreakpointResolver.h index 60476f4..bac7ec6 100644 --- a/lldb/include/lldb/Breakpoint/BreakpointResolver.h +++ b/lldb/include/lldb/Breakpoint/BreakpointResolver.h @@ -136,30 +136,96 @@ 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 /// supposedly represent the same file and diff --git a/lldb/include/lldb/Breakpoint/BreakpointResolverAddress.h b/lldb/include/lldb/Breakpoint/BreakpointResolverAddress.h index 6e947d7..ed2d61a 100644 --- a/lldb/include/lldb/Breakpoint/BreakpointResolverAddress.h +++ b/lldb/include/lldb/Breakpoint/BreakpointResolverAddress.h @@ -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, diff --git a/lldb/include/lldb/Breakpoint/BreakpointResolverFileLine.h b/lldb/include/lldb/Breakpoint/BreakpointResolverFileLine.h index 9efa24e..82ed24c 100644 --- a/lldb/include/lldb/Breakpoint/BreakpointResolverFileLine.h +++ b/lldb/include/lldb/Breakpoint/BreakpointResolverFileLine.h @@ -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, diff --git a/lldb/include/lldb/Breakpoint/BreakpointResolverFileRegex.h b/lldb/include/lldb/Breakpoint/BreakpointResolverFileRegex.h index 495c5bd..4afe9b1 100644 --- a/lldb/include/lldb/Breakpoint/BreakpointResolverFileRegex.h +++ b/lldb/include/lldb/Breakpoint/BreakpointResolverFileRegex.h @@ -35,6 +35,11 @@ public: Breakpoint *bkpt, RegularExpression ®ex, const std::unordered_set &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, diff --git a/lldb/include/lldb/Breakpoint/BreakpointResolverName.h b/lldb/include/lldb/Breakpoint/BreakpointResolverName.h index 7765ee4..85a8bb0 100644 --- a/lldb/include/lldb/Breakpoint/BreakpointResolverName.h +++ b/lldb/include/lldb/Breakpoint/BreakpointResolverName.h @@ -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; diff --git a/lldb/include/lldb/Core/SearchFilter.h b/lldb/include/lldb/Core/SearchFilter.h index 82fc647..d6053cb 100644 --- a/lldb/include/lldb/Core/SearchFilter.h +++ b/lldb/include/lldb/Core/SearchFilter.h @@ -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; diff --git a/lldb/include/lldb/Core/StructuredData.h b/lldb/include/lldb/Core/StructuredData.h index 71f6900..321fee6 100644 --- a/lldb/include/lldb/Core/StructuredData.h +++ b/lldb/include/lldb/Core/StructuredData.h @@ -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 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 diff --git a/lldb/include/lldb/Target/LanguageRuntime.h b/lldb/include/lldb/Target/LanguageRuntime.h index 063d8ab..d13ec15 100644 --- a/lldb/include/lldb/Target/LanguageRuntime.h +++ b/lldb/include/lldb/Target/LanguageRuntime.h @@ -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; diff --git a/lldb/source/Breakpoint/Breakpoint.cpp b/lldb/source/Breakpoint/Breakpoint.cpp index 78354e2..a73b82e 100644 --- a/lldb/source/Breakpoint/Breakpoint.cpp +++ b/lldb/source/Breakpoint/Breakpoint.cpp @@ -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) diff --git a/lldb/source/Breakpoint/BreakpointOptions.cpp b/lldb/source/Breakpoint/BreakpointOptions.cpp index bb43e3a9..bf24ee0 100644 --- a/lldb/source/Breakpoint/BreakpointOptions.cpp +++ b/lldb/source/Breakpoint/BreakpointOptions.cpp @@ -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(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; +} diff --git a/lldb/source/Breakpoint/BreakpointResolver.cpp b/lldb/source/Breakpoint/BreakpointResolver.cpp index ee6e4c8..5a93d57 100644 --- a/lldb/source/Breakpoint/BreakpointResolver.cpp +++ b/lldb/source/Breakpoint/BreakpointResolver.cpp @@ -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; } diff --git a/lldb/source/Breakpoint/BreakpointResolverAddress.cpp b/lldb/source/Breakpoint/BreakpointResolverAddress.cpp index e52ec9c..cf8637b 100644 --- a/lldb/source/Breakpoint/BreakpointResolverAddress.cpp +++ b/lldb/source/Breakpoint/BreakpointResolverAddress.cpp @@ -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 diff --git a/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp b/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp index 482b165..5f0b0d2 100644 --- a/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp +++ b/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp @@ -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, diff --git a/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp b/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp index 8d08908..da8b7b3 100644 --- a/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp +++ b/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp @@ -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 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, diff --git a/lldb/source/Breakpoint/BreakpointResolverName.cpp b/lldb/source/Breakpoint/BreakpointResolverName.cpp index 64d0318..a946ba3 100644 --- a/lldb/source/Breakpoint/BreakpointResolverName.cpp +++ b/lldb/source/Breakpoint/BreakpointResolverName.cpp @@ -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 names; + std::vector 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); diff --git a/lldb/source/Commands/CommandObjectBreakpoint.cpp b/lldb/source/Commands/CommandObjectBreakpoint.cpp index a5bfe1d..222bb5f 100644 --- a/lldb/source/Commands/CommandObjectBreakpoint.cpp +++ b/lldb/source/Commands/CommandObjectBreakpoint.cpp @@ -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: @@ -2082,6 +2083,307 @@ public: }; //------------------------------------------------------------------------- +// 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 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 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 processed_bkpts; + const size_t count = valid_bp_ids.GetSize(); + for (size_t i = 0; i < count; ++i) { + BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i); + lldb::break_id_t bp_id = cur_bp_id.GetBreakpointID(); + + if (bp_id != LLDB_INVALID_BREAK_ID) { + // Only do each breakpoint once: + std::pair::iterator, bool> + insert_result = processed_bkpts.insert(bp_id); + if (!insert_result.second) + continue; + + Breakpoint *bp = target->GetBreakpointByID(bp_id).get(); + StructuredData::ObjectSP bkpt_save_sp = + bp->SerializeToStructuredData(); + // If the user explicitly asked to serialize a breakpoint, and we + // can't, then + // raise an error: + if (!bkpt_save_sp) { + result.AppendErrorWithFormat("Unable to serialize breakpoint %d", + bp_id); + result.SetStatus(eReturnStatusFailed); + return false; + } + break_store_sp->AddItem(bkpt_save_sp); + } + } + } + } + + 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 //------------------------------------------------------------------------- #pragma mark MultiwordBreakpoint @@ -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; diff --git a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp index 557cb5f..7884728 100644 --- a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp +++ b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp @@ -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 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 &bp_options_vec, const char *oneliner) { for (auto bp_options : bp_options_vec) { - std::unique_ptr 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,55 +247,12 @@ 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); - } - } - - 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(); - } + bp_options->SetCommandDataCallback(cmd_data); } - return ret_value; } class CommandOptions : public Options { diff --git a/lldb/source/Core/SearchFilter.cpp b/lldb/source/Core/SearchFilter.cpp index 5736b11..aa21422 100644 --- a/lldb/source/Core/SearchFilter.cpp +++ b/lldb/source/Core/SearchFilter.cpp @@ -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; } @@ -62,6 +144,34 @@ lldb::SearchFilterSP SearchFilter::CopyForBreakpoint(Breakpoint &breakpoint) { } //---------------------------------------------------------------------- +// 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; } diff --git a/lldb/source/Core/StructuredData.cpp b/lldb/source/Core/StructuredData.cpp index 6e544c1..5980e0f 100644 --- a/lldb/source/Core/StructuredData.cpp +++ b/lldb/source/Core/StructuredData.cpp @@ -14,7 +14,11 @@ #include #include +#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 diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp index 5806d33d..3257afb 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -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; diff --git a/lldb/source/Target/LanguageRuntime.cpp b/lldb/source/Target/LanguageRuntime.cpp index 16cd12d..83c6afa 100644 --- a/lldb/source/Target/LanguageRuntime.cpp +++ b/lldb/source/Target/LanguageRuntime.cpp @@ -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 { - UpdateModuleListIfNeeded(); - if (m_filter_sp) - return m_filter_sp->ModulePasses(module_sp); - return false; - } - - bool ModulePasses(const FileSpec &spec) 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(spec); - return false; - } +} - void Search(Searcher &searcher) override { - UpdateModuleListIfNeeded(); - if (m_filter_sp) - m_filter_sp->Search(searcher); - } +bool ExceptionSearchFilter::ModulePasses(const lldb::ModuleSP &module_sp) { + UpdateModuleListIfNeeded(); + if (m_filter_sp) + return m_filter_sp->ModulePasses(module_sp); + return false; +} - void GetDescription(Stream *s) override { - UpdateModuleListIfNeeded(); - if (m_filter_sp) - m_filter_sp->GetDescription(s); - } +bool ExceptionSearchFilter::ModulePasses(const FileSpec &spec) { + UpdateModuleListIfNeeded(); + if (m_filter_sp) + return m_filter_sp->ModulePasses(spec); + return false; +} -protected: - LanguageType m_language; - LanguageRuntime *m_language_runtime; - SearchFilterSP m_filter_sp; +void ExceptionSearchFilter::Search(Searcher &searcher) { + UpdateModuleListIfNeeded(); + if (m_filter_sp) + m_filter_sp->Search(searcher); +} - SearchFilterSP DoCopyForBreakpoint(Breakpoint &breakpoint) override { - return SearchFilterSP( - new ExceptionSearchFilter(TargetSP(), m_language, false)); - } +void ExceptionSearchFilter::GetDescription(Stream *s) { + UpdateModuleListIfNeeded(); + if (m_filter_sp) + m_filter_sp->GetDescription(s); +} - 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); +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 { + LanguageRuntime *language_runtime = + process_sp->GetLanguageRuntime(m_language); + if (m_language_runtime != language_runtime) { + m_language_runtime = language_runtime; 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(); - } - } else { - m_filter_sp.reset(); - m_language_runtime = nullptr; + 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 -- 2.7.4