diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:26:05 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:26:05 +0000 |
commit | 14f1b3e8826ce43b978db93a62d1166055db5394 (patch) | |
tree | 0a00ad8d3498783fe0193f3b656bca17c4c8697d /include/lldb/Target | |
parent | 4ee8c119c71a06dcad1e0fecc8c675e480e59337 (diff) | |
download | src-14f1b3e8826ce43b978db93a62d1166055db5394.tar.gz src-14f1b3e8826ce43b978db93a62d1166055db5394.zip |
Vendor import of lldb trunk r290819:vendor/lldb/lldb-trunk-r290819
Notes
Notes:
svn path=/vendor/lldb/dist/; revision=311128
svn path=/vendor/lldb/lldb-trunk-r290819/; revision=311129; tag=vendor/lldb/lldb-trunk-r290819
Diffstat (limited to 'include/lldb/Target')
62 files changed, 12984 insertions, 14997 deletions
diff --git a/include/lldb/Target/ABI.h b/include/lldb/Target/ABI.h index cd0b57e61ff8..8a1243613616 100644 --- a/include/lldb/Target/ABI.h +++ b/include/lldb/Target/ABI.h @@ -22,145 +22,125 @@ #include "llvm/ADT/ArrayRef.h" // forward define the llvm::Type class -namespace llvm { class Type; } +namespace llvm { +class Type; +} namespace lldb_private { -class ABI : - public PluginInterface -{ +class ABI : public PluginInterface { public: - - struct CallArgument - { - enum eType - { - HostPointer = 0, /* pointer to host data */ - TargetValue , /* value is on the target or literal */ - }; - eType type; /* value of eType */ - size_t size; /* size in bytes of this argument */ - - lldb::addr_t value; /* literal value */ - std::unique_ptr<uint8_t[]> data_ap; /* host data pointer */ + struct CallArgument { + enum eType { + HostPointer = 0, /* pointer to host data */ + TargetValue, /* value is on the target or literal */ }; + eType type; /* value of eType */ + size_t size; /* size in bytes of this argument */ + + lldb::addr_t value; /* literal value */ + std::unique_ptr<uint8_t[]> data_ap; /* host data pointer */ + }; + + ~ABI() override; + + virtual size_t GetRedZoneSize() const = 0; + + virtual bool PrepareTrivialCall(lldb_private::Thread &thread, lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t returnAddress, + llvm::ArrayRef<lldb::addr_t> args) const = 0; + + // Prepare trivial call used from ThreadPlanFunctionCallUsingABI + // AD: + // . Because i don't want to change other ABI's this is not declared pure + // virtual. + // The dummy implementation will simply fail. Only HexagonABI will + // currently + // use this method. + // . Two PrepareTrivialCall's is not good design so perhaps this should be + // combined. + // + virtual bool PrepareTrivialCall(lldb_private::Thread &thread, lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t returnAddress, + llvm::Type &prototype, + llvm::ArrayRef<CallArgument> args) const; + + virtual bool GetArgumentValues(Thread &thread, ValueList &values) const = 0; + + lldb::ValueObjectSP GetReturnValueObject(Thread &thread, CompilerType &type, + bool persistent = true) const; + + // specialized to work with llvm IR types + lldb::ValueObjectSP GetReturnValueObject(Thread &thread, llvm::Type &type, + bool persistent = true) const; + + // Set the Return value object in the current frame as though a function with + virtual Error SetReturnValueObject(lldb::StackFrameSP &frame_sp, + lldb::ValueObjectSP &new_value) = 0; - ~ABI() override; - - virtual size_t - GetRedZoneSize () const = 0; - - virtual bool - PrepareTrivialCall ( lldb_private::Thread &thread, - lldb::addr_t sp, - lldb::addr_t functionAddress, - lldb::addr_t returnAddress, - llvm::ArrayRef<lldb::addr_t> args) const = 0; - - // Prepare trivial call used from ThreadPlanFunctionCallUsingABI - // AD: - // . Because i don't want to change other ABI's this is not declared pure virtual. - // The dummy implementation will simply fail. Only HexagonABI will currently - // use this method. - // . Two PrepareTrivialCall's is not good design so perhaps this should be combined. - // - virtual bool - PrepareTrivialCall ( lldb_private::Thread &thread, - lldb::addr_t sp, - lldb::addr_t functionAddress, - lldb::addr_t returnAddress, - llvm::Type &prototype, - llvm::ArrayRef<CallArgument> args) const; - - virtual bool - GetArgumentValues (Thread &thread, - ValueList &values) const = 0; - - lldb::ValueObjectSP - GetReturnValueObject (Thread &thread, - CompilerType &type, - bool persistent = true) const; - - // specialized to work with llvm IR types - lldb::ValueObjectSP - GetReturnValueObject (Thread &thread, - llvm::Type &type, - bool persistent = true) const; - - // Set the Return value object in the current frame as though a function with - virtual Error - SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value) = 0; - -protected: - // This is the method the ABI will call to actually calculate the return value. - // Don't put it in a persistent value object, that will be done by the ABI::GetReturnValueObject. - virtual lldb::ValueObjectSP - GetReturnValueObjectImpl (Thread &thread, CompilerType &ast_type) const = 0; - - // specialized to work with llvm IR types - virtual lldb::ValueObjectSP - GetReturnValueObjectImpl( Thread &thread, llvm::Type &ir_type ) const; +protected: + // This is the method the ABI will call to actually calculate the return + // value. + // Don't put it in a persistent value object, that will be done by the + // ABI::GetReturnValueObject. + virtual lldb::ValueObjectSP + GetReturnValueObjectImpl(Thread &thread, CompilerType &ast_type) const = 0; + + // specialized to work with llvm IR types + virtual lldb::ValueObjectSP + GetReturnValueObjectImpl(Thread &thread, llvm::Type &ir_type) const; public: - virtual bool - CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan) = 0; - - virtual bool - CreateDefaultUnwindPlan (UnwindPlan &unwind_plan) = 0; - - virtual bool - RegisterIsVolatile (const RegisterInfo *reg_info) = 0; - - virtual bool - GetFallbackRegisterLocation (const RegisterInfo *reg_info, - UnwindPlan::Row::RegisterLocation &unwind_regloc); - - // Should take a look at a call frame address (CFA) which is just the stack - // pointer value upon entry to a function. ABIs usually impose alignment - // restrictions (4, 8 or 16 byte aligned), and zero is usually not allowed. - // This function should return true if "cfa" is valid call frame address for - // the ABI, and false otherwise. This is used by the generic stack frame unwinding - // code to help determine when a stack ends. - virtual bool - CallFrameAddressIsValid (lldb::addr_t cfa) = 0; - - // Validates a possible PC value and returns true if an opcode can be at "pc". - virtual bool - CodeAddressIsValid (lldb::addr_t pc) = 0; - - virtual lldb::addr_t - FixCodeAddress (lldb::addr_t pc) - { - // Some targets might use bits in a code address to indicate - // a mode switch. ARM uses bit zero to signify a code address is - // thumb, so any ARM ABI plug-ins would strip those bits. - return pc; - } - - virtual const RegisterInfo * - GetRegisterInfoArray (uint32_t &count) = 0; - - bool - GetRegisterInfoByName (const ConstString &name, RegisterInfo &info); - - bool - GetRegisterInfoByKind (lldb::RegisterKind reg_kind, - uint32_t reg_num, - RegisterInfo &info); - - static lldb::ABISP - FindPlugin (const ArchSpec &arch); - -protected: + virtual bool CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) = 0; - //------------------------------------------------------------------ - // Classes that inherit from ABI can see and modify these - //------------------------------------------------------------------ - ABI(); + virtual bool CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) = 0; -private: + virtual bool RegisterIsVolatile(const RegisterInfo *reg_info) = 0; + + virtual bool + GetFallbackRegisterLocation(const RegisterInfo *reg_info, + UnwindPlan::Row::RegisterLocation &unwind_regloc); + + // Should take a look at a call frame address (CFA) which is just the stack + // pointer value upon entry to a function. ABIs usually impose alignment + // restrictions (4, 8 or 16 byte aligned), and zero is usually not allowed. + // This function should return true if "cfa" is valid call frame address for + // the ABI, and false otherwise. This is used by the generic stack frame + // unwinding + // code to help determine when a stack ends. + virtual bool CallFrameAddressIsValid(lldb::addr_t cfa) = 0; + + // Validates a possible PC value and returns true if an opcode can be at "pc". + virtual bool CodeAddressIsValid(lldb::addr_t pc) = 0; + + virtual lldb::addr_t FixCodeAddress(lldb::addr_t pc) { + // Some targets might use bits in a code address to indicate + // a mode switch. ARM uses bit zero to signify a code address is + // thumb, so any ARM ABI plug-ins would strip those bits. + return pc; + } - DISALLOW_COPY_AND_ASSIGN (ABI); + virtual const RegisterInfo *GetRegisterInfoArray(uint32_t &count) = 0; + + bool GetRegisterInfoByName(const ConstString &name, RegisterInfo &info); + + bool GetRegisterInfoByKind(lldb::RegisterKind reg_kind, uint32_t reg_num, + RegisterInfo &info); + + virtual bool GetPointerReturnRegister(const char *&name) { return false; } + + static lldb::ABISP FindPlugin(const ArchSpec &arch); + +protected: + //------------------------------------------------------------------ + // Classes that inherit from ABI can see and modify these + //------------------------------------------------------------------ + ABI(); + +private: + DISALLOW_COPY_AND_ASSIGN(ABI); }; } // namespace lldb_private diff --git a/include/lldb/Target/CPPLanguageRuntime.h b/include/lldb/Target/CPPLanguageRuntime.h index 788f4e60a493..aae85f420ef7 100644 --- a/include/lldb/Target/CPPLanguageRuntime.h +++ b/include/lldb/Target/CPPLanguageRuntime.h @@ -1,4 +1,5 @@ -//===-- CPPLanguageRuntime.h ---------------------------------------------------*- C++ -*-===// +//===-- CPPLanguageRuntime.h +//---------------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -16,42 +17,34 @@ // Other libraries and framework includes // Project includes #include "lldb/Core/PluginInterface.h" -#include "lldb/lldb-private.h" #include "lldb/Target/LanguageRuntime.h" +#include "lldb/lldb-private.h" namespace lldb_private { -class CPPLanguageRuntime : - public LanguageRuntime -{ +class CPPLanguageRuntime : public LanguageRuntime { public: - ~CPPLanguageRuntime() override; - - lldb::LanguageType - GetLanguageType() const override - { - return lldb::eLanguageTypeC_plus_plus; - } - - virtual bool - IsVTableName (const char *name) = 0; - - bool - GetObjectDescription(Stream &str, ValueObject &object) override; - - bool - GetObjectDescription(Stream &str, Value &value, ExecutionContextScope *exe_scope) override; - -protected: + ~CPPLanguageRuntime() override; - //------------------------------------------------------------------ - // Classes that inherit from CPPLanguageRuntime can see and modify these - //------------------------------------------------------------------ - CPPLanguageRuntime(Process *process); + lldb::LanguageType GetLanguageType() const override { + return lldb::eLanguageTypeC_plus_plus; + } -private: + virtual bool IsVTableName(const char *name) = 0; + + bool GetObjectDescription(Stream &str, ValueObject &object) override; - DISALLOW_COPY_AND_ASSIGN (CPPLanguageRuntime); + bool GetObjectDescription(Stream &str, Value &value, + ExecutionContextScope *exe_scope) override; + +protected: + //------------------------------------------------------------------ + // Classes that inherit from CPPLanguageRuntime can see and modify these + //------------------------------------------------------------------ + CPPLanguageRuntime(Process *process); + +private: + DISALLOW_COPY_AND_ASSIGN(CPPLanguageRuntime); }; } // namespace lldb_private diff --git a/include/lldb/Target/DynamicLoader.h b/include/lldb/Target/DynamicLoader.h index 2c4956829b29..071cbe69d880 100644 --- a/include/lldb/Target/DynamicLoader.h +++ b/include/lldb/Target/DynamicLoader.h @@ -11,9 +11,10 @@ #define liblldb_DynamicLoader_h_ // Project includes -#include "lldb/lldb-private.h" #include "lldb/Core/Error.h" #include "lldb/Core/PluginInterface.h" +#include "lldb/Core/UUID.h" +#include "lldb/lldb-private.h" namespace lldb_private { @@ -32,285 +33,313 @@ namespace lldb_private { /// /// Breakpoints can also be set in the process which can register /// functions that get called using: -/// Process::BreakpointSetCallback (lldb::user_id_t, BreakpointHitCallback, void *). +/// Process::BreakpointSetCallback (lldb::user_id_t, BreakpointHitCallback, void +/// *). /// These breakpoint callbacks return a boolean value that indicates if /// the process should continue or halt and should return the global /// setting for this using: /// DynamicLoader::StopWhenImagesChange() const. //---------------------------------------------------------------------- -class DynamicLoader : - public PluginInterface -{ +class DynamicLoader : public PluginInterface { public: - //------------------------------------------------------------------ - /// Find a dynamic loader plugin for a given process. - /// - /// Scans the installed DynamicLoader plug-ins and tries to find - /// an instance that can be used to track image changes in \a - /// process. - /// - /// @param[in] process - /// The process for which to try and locate a dynamic loader - /// plug-in instance. - /// - /// @param[in] plugin_name - /// An optional name of a specific dynamic loader plug-in that - /// should be used. If NULL, pick the best plug-in. - //------------------------------------------------------------------ - static DynamicLoader* - FindPlugin (Process *process, const char *plugin_name); + //------------------------------------------------------------------ + /// Find a dynamic loader plugin for a given process. + /// + /// Scans the installed DynamicLoader plug-ins and tries to find + /// an instance that can be used to track image changes in \a + /// process. + /// + /// @param[in] process + /// The process for which to try and locate a dynamic loader + /// plug-in instance. + /// + /// @param[in] plugin_name + /// An optional name of a specific dynamic loader plug-in that + /// should be used. If NULL, pick the best plug-in. + //------------------------------------------------------------------ + static DynamicLoader *FindPlugin(Process *process, const char *plugin_name); - //------------------------------------------------------------------ - /// Construct with a process. - //------------------------------------------------------------------ - DynamicLoader (Process *process); + //------------------------------------------------------------------ + /// Construct with a process. + //------------------------------------------------------------------ + DynamicLoader(Process *process); - //------------------------------------------------------------------ - /// Destructor. - /// - /// The destructor is virtual since this class is designed to be - /// inherited from by the plug-in instance. - //------------------------------------------------------------------ - virtual ~DynamicLoader() override; + //------------------------------------------------------------------ + /// Destructor. + /// + /// The destructor is virtual since this class is designed to be + /// inherited from by the plug-in instance. + //------------------------------------------------------------------ + virtual ~DynamicLoader() override; - //------------------------------------------------------------------ - /// Called after attaching a process. - /// - /// Allow DynamicLoader plug-ins to execute some code after - /// attaching to a process. - //------------------------------------------------------------------ - virtual void - DidAttach () = 0; + //------------------------------------------------------------------ + /// Called after attaching a process. + /// + /// Allow DynamicLoader plug-ins to execute some code after + /// attaching to a process. + //------------------------------------------------------------------ + virtual void DidAttach() = 0; - //------------------------------------------------------------------ - /// Called after launching a process. - /// - /// Allow DynamicLoader plug-ins to execute some code after - /// the process has stopped for the first time on launch. - //------------------------------------------------------------------ - virtual void - DidLaunch () = 0; - - - //------------------------------------------------------------------ - /// Helper function that can be used to detect when a process has - /// called exec and is now a new and different process. This can - /// be called when necessary to try and detect the exec. The process - /// might be able to answer this question, but sometimes it might - /// not be able and the dynamic loader often knows what the program - /// entry point is. So the process and the dynamic loader can work - /// together to detect this. - //------------------------------------------------------------------ - virtual bool - ProcessDidExec () - { - return false; - } - //------------------------------------------------------------------ - /// Get whether the process should stop when images change. - /// - /// When images (executables and shared libraries) get loaded or - /// unloaded, often debug sessions will want to try and resolve or - /// unresolve breakpoints that are set in these images. Any - /// breakpoints set by DynamicLoader plug-in instances should - /// return this value to ensure consistent debug session behaviour. - /// - /// @return - /// Returns \b true if the process should stop when images - /// change, \b false if the process should resume. - //------------------------------------------------------------------ - bool - GetStopWhenImagesChange () const; + //------------------------------------------------------------------ + /// Called after launching a process. + /// + /// Allow DynamicLoader plug-ins to execute some code after + /// the process has stopped for the first time on launch. + //------------------------------------------------------------------ + virtual void DidLaunch() = 0; - //------------------------------------------------------------------ - /// Set whether the process should stop when images change. - /// - /// When images (executables and shared libraries) get loaded or - /// unloaded, often debug sessions will want to try and resolve or - /// unresolve breakpoints that are set in these images. The default - /// is set so that the process stops when images change, but this - /// can be overridden using this function callback. - /// - /// @param[in] stop - /// Boolean value that indicates whether the process should stop - /// when images change. - //------------------------------------------------------------------ - void - SetStopWhenImagesChange (bool stop); + //------------------------------------------------------------------ + /// Helper function that can be used to detect when a process has + /// called exec and is now a new and different process. This can + /// be called when necessary to try and detect the exec. The process + /// might be able to answer this question, but sometimes it might + /// not be able and the dynamic loader often knows what the program + /// entry point is. So the process and the dynamic loader can work + /// together to detect this. + //------------------------------------------------------------------ + virtual bool ProcessDidExec() { return false; } + //------------------------------------------------------------------ + /// Get whether the process should stop when images change. + /// + /// When images (executables and shared libraries) get loaded or + /// unloaded, often debug sessions will want to try and resolve or + /// unresolve breakpoints that are set in these images. Any + /// breakpoints set by DynamicLoader plug-in instances should + /// return this value to ensure consistent debug session behaviour. + /// + /// @return + /// Returns \b true if the process should stop when images + /// change, \b false if the process should resume. + //------------------------------------------------------------------ + bool GetStopWhenImagesChange() const; - //------------------------------------------------------------------ - /// Provides a plan to step through the dynamic loader trampoline - /// for the current state of \a thread. - /// - /// - /// @param[in] stop_others - /// Whether the plan should be set to stop other threads. - /// - /// @return - /// A pointer to the plan (caller owned) or NULL if we are not at such - /// a trampoline. - //------------------------------------------------------------------ - virtual lldb::ThreadPlanSP - GetStepThroughTrampolinePlan (Thread &thread, bool stop_others) = 0; + //------------------------------------------------------------------ + /// Set whether the process should stop when images change. + /// + /// When images (executables and shared libraries) get loaded or + /// unloaded, often debug sessions will want to try and resolve or + /// unresolve breakpoints that are set in these images. The default + /// is set so that the process stops when images change, but this + /// can be overridden using this function callback. + /// + /// @param[in] stop + /// Boolean value that indicates whether the process should stop + /// when images change. + //------------------------------------------------------------------ + void SetStopWhenImagesChange(bool stop); + //------------------------------------------------------------------ + /// Provides a plan to step through the dynamic loader trampoline + /// for the current state of \a thread. + /// + /// + /// @param[in] stop_others + /// Whether the plan should be set to stop other threads. + /// + /// @return + /// A pointer to the plan (caller owned) or NULL if we are not at such + /// a trampoline. + //------------------------------------------------------------------ + virtual lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread, + bool stop_others) = 0; - //------------------------------------------------------------------ - /// Some dynamic loaders provide features where there are a group of symbols "equivalent to" - /// a given symbol one of which will be chosen when the symbol is bound. If you want to - /// set a breakpoint on one of these symbols, you really need to set it on all the - /// equivalent symbols. - /// - /// - /// @param[in] original_symbol - /// The symbol for which we are finding equivalences. - /// - /// @param[in] module_list - /// The set of modules in which to search. - /// - /// @param[out] equivalent_symbols - /// The equivalent symbol list - any equivalent symbols found are appended to this list. - /// - /// @return - /// Number of equivalent symbols found. - //------------------------------------------------------------------ - virtual size_t - FindEquivalentSymbols (Symbol *original_symbol, ModuleList &module_list, SymbolContextList &equivalent_symbols) - { - return 0; - } + //------------------------------------------------------------------ + /// Some dynamic loaders provide features where there are a group of symbols + /// "equivalent to" + /// a given symbol one of which will be chosen when the symbol is bound. If + /// you want to + /// set a breakpoint on one of these symbols, you really need to set it on all + /// the + /// equivalent symbols. + /// + /// + /// @param[in] original_symbol + /// The symbol for which we are finding equivalences. + /// + /// @param[in] module_list + /// The set of modules in which to search. + /// + /// @param[out] equivalent_symbols + /// The equivalent symbol list - any equivalent symbols found are appended + /// to this list. + /// + /// @return + /// Number of equivalent symbols found. + //------------------------------------------------------------------ + virtual size_t FindEquivalentSymbols(Symbol *original_symbol, + ModuleList &module_list, + SymbolContextList &equivalent_symbols) { + return 0; + } - //------------------------------------------------------------------ - /// Ask if it is ok to try and load or unload an shared library - /// (image). - /// - /// The dynamic loader often knows when it would be ok to try and - /// load or unload a shared library. This function call allows the - /// dynamic loader plug-ins to check any current dyld state to make - /// sure it is an ok time to load a shared library. - /// - /// @return - /// \b true if it is currently ok to try and load a shared - /// library into the process, \b false otherwise. - //------------------------------------------------------------------ - virtual Error - CanLoadImage () = 0; + //------------------------------------------------------------------ + /// Ask if it is ok to try and load or unload an shared library + /// (image). + /// + /// The dynamic loader often knows when it would be ok to try and + /// load or unload a shared library. This function call allows the + /// dynamic loader plug-ins to check any current dyld state to make + /// sure it is an ok time to load a shared library. + /// + /// @return + /// \b true if it is currently ok to try and load a shared + /// library into the process, \b false otherwise. + //------------------------------------------------------------------ + virtual Error CanLoadImage() = 0; - //------------------------------------------------------------------ - /// Ask if the eh_frame information for the given SymbolContext should - /// be relied on even when it's the first frame in a stack unwind. - /// - /// The CFI instructions from the eh_frame section are normally only - /// valid at call sites -- places where a program could throw an - /// exception and need to unwind out. But some Modules may be known - /// to the system as having reliable eh_frame information at all call - /// sites. This would be the case if the Module's contents are largely - /// hand-written assembly with hand-written eh_frame information. - /// Normally when unwinding from a function at the beginning of a stack - /// unwind lldb will examine the assembly instructions to understand - /// how the stack frame is set up and where saved registers are stored. - /// But with hand-written assembly this is not reliable enough -- we need - /// to consult those function's hand-written eh_frame information. - /// - /// @return - /// \b True if the symbol context should use eh_frame instructions - /// unconditionally when unwinding from this frame. Else \b false, - /// the normal lldb unwind behavior of only using eh_frame when the - /// function appears in the middle of the stack. - //------------------------------------------------------------------ - virtual bool - AlwaysRelyOnEHUnwindInfo (SymbolContext &sym_ctx) - { - return false; - } + //------------------------------------------------------------------ + /// Ask if the eh_frame information for the given SymbolContext should + /// be relied on even when it's the first frame in a stack unwind. + /// + /// The CFI instructions from the eh_frame section are normally only + /// valid at call sites -- places where a program could throw an + /// exception and need to unwind out. But some Modules may be known + /// to the system as having reliable eh_frame information at all call + /// sites. This would be the case if the Module's contents are largely + /// hand-written assembly with hand-written eh_frame information. + /// Normally when unwinding from a function at the beginning of a stack + /// unwind lldb will examine the assembly instructions to understand + /// how the stack frame is set up and where saved registers are stored. + /// But with hand-written assembly this is not reliable enough -- we need + /// to consult those function's hand-written eh_frame information. + /// + /// @return + /// \b True if the symbol context should use eh_frame instructions + /// unconditionally when unwinding from this frame. Else \b false, + /// the normal lldb unwind behavior of only using eh_frame when the + /// function appears in the middle of the stack. + //------------------------------------------------------------------ + virtual bool AlwaysRelyOnEHUnwindInfo(SymbolContext &sym_ctx) { + return false; + } - //------------------------------------------------------------------ - /// Retrieves the per-module TLS block for a given thread. - /// - /// @param[in] module - /// The module to query TLS data for. - /// - /// @param[in] thread - /// The specific thread to query TLS data for. - /// - /// @return - /// If the given thread has TLS data allocated for the - /// module, the address of the TLS block. Otherwise - /// LLDB_INVALID_ADDRESS is returned. - //------------------------------------------------------------------ - virtual lldb::addr_t - GetThreadLocalData(const lldb::ModuleSP module, const lldb::ThreadSP thread, lldb::addr_t tls_file_addr) - { - return LLDB_INVALID_ADDRESS; - } + //------------------------------------------------------------------ + /// Retrieves the per-module TLS block for a given thread. + /// + /// @param[in] module + /// The module to query TLS data for. + /// + /// @param[in] thread + /// The specific thread to query TLS data for. + /// + /// @return + /// If the given thread has TLS data allocated for the + /// module, the address of the TLS block. Otherwise + /// LLDB_INVALID_ADDRESS is returned. + //------------------------------------------------------------------ + virtual lldb::addr_t GetThreadLocalData(const lldb::ModuleSP module, + const lldb::ThreadSP thread, + lldb::addr_t tls_file_addr) { + return LLDB_INVALID_ADDRESS; + } - /// Locates or creates a module given by @p file and updates/loads the - /// resulting module at the virtual base address @p base_addr. - virtual lldb::ModuleSP - LoadModuleAtAddress(const lldb_private::FileSpec &file, - lldb::addr_t link_map_addr, - lldb::addr_t base_addr, - bool base_addr_is_offset); + /// Locates or creates a module given by @p file and updates/loads the + /// resulting module at the virtual base address @p base_addr. + virtual lldb::ModuleSP LoadModuleAtAddress(const lldb_private::FileSpec &file, + lldb::addr_t link_map_addr, + lldb::addr_t base_addr, + bool base_addr_is_offset); + + //------------------------------------------------------------------ + /// Get information about the shared cache for a process, if possible. + /// + /// On some systems (e.g. Darwin based systems), a set of libraries + /// that are common to most processes may be put in a single region + /// of memory and mapped into every process, this is called the + /// shared cache, as a performance optimization. + /// + /// Many targets will not have the concept of a shared cache. + /// + /// Depending on how the DynamicLoader gathers information about the + /// shared cache, it may be able to only return basic information - + /// like the UUID of the cache - or it may be able to return additional + /// information about the cache. + /// + /// @param[out] base_address + /// The base address (load address) of the shared cache. + /// LLDB_INVALID_ADDRESS if it cannot be determined. + /// + /// @param[out] uuid + /// The UUID of the shared cache, if it can be determined. + /// If the UUID cannot be fetched, IsValid() will be false. + /// + /// @param[out] using_shared_cache + /// If this process is using a shared cache. + /// If unknown, eLazyBoolCalculate is returned. + /// + /// @param[out] private_shared_cache + /// A LazyBool indicating whether this process is using a + /// private shared cache. + /// If this information cannot be fetched, eLazyBoolCalculate. + /// + /// @return + /// Returns false if this DynamicLoader cannot gather information + /// about the shared cache / has no concept of a shared cache. + //------------------------------------------------------------------ + virtual bool GetSharedCacheInformation(lldb::addr_t &base_address, UUID &uuid, + LazyBool &using_shared_cache, + LazyBool &private_shared_cache) { + base_address = LLDB_INVALID_ADDRESS; + uuid.Clear(); + using_shared_cache = eLazyBoolCalculate; + private_shared_cache = eLazyBoolCalculate; + return false; + } protected: - //------------------------------------------------------------------ - // Utility methods for derived classes - //------------------------------------------------------------------ + //------------------------------------------------------------------ + // Utility methods for derived classes + //------------------------------------------------------------------ - /// Checks to see if the target module has changed, updates the target - /// accordingly and returns the target executable module. - lldb::ModuleSP - GetTargetExecutable(); + /// Checks to see if the target module has changed, updates the target + /// accordingly and returns the target executable module. + lldb::ModuleSP GetTargetExecutable(); - /// Updates the load address of every allocatable section in @p module. - /// - /// @param module The module to traverse. - /// - /// @param link_map_addr The virtual address of the link map for the @p module. - /// - /// @param base_addr The virtual base address @p module is loaded at. - virtual void - UpdateLoadedSections(lldb::ModuleSP module, - lldb::addr_t link_map_addr, - lldb::addr_t base_addr, - bool base_addr_is_offset); + /// Updates the load address of every allocatable section in @p module. + /// + /// @param module The module to traverse. + /// + /// @param link_map_addr The virtual address of the link map for the @p + /// module. + /// + /// @param base_addr The virtual base address @p module is loaded at. + virtual void UpdateLoadedSections(lldb::ModuleSP module, + lldb::addr_t link_map_addr, + lldb::addr_t base_addr, + bool base_addr_is_offset); - // Utility method so base classes can share implementation of UpdateLoadedSections - void - UpdateLoadedSectionsCommon(lldb::ModuleSP module, - lldb::addr_t base_addr, - bool base_addr_is_offset); + // Utility method so base classes can share implementation of + // UpdateLoadedSections + void UpdateLoadedSectionsCommon(lldb::ModuleSP module, lldb::addr_t base_addr, + bool base_addr_is_offset); - /// Removes the loaded sections from the target in @p module. - /// - /// @param module The module to traverse. - virtual void - UnloadSections(const lldb::ModuleSP module); + /// Removes the loaded sections from the target in @p module. + /// + /// @param module The module to traverse. + virtual void UnloadSections(const lldb::ModuleSP module); - // Utility method so base classes can share implementation of UnloadSections - void - UnloadSectionsCommon(const lldb::ModuleSP module); + // Utility method so base classes can share implementation of UnloadSections + void UnloadSectionsCommon(const lldb::ModuleSP module); - const lldb_private::SectionList * - GetSectionListFromModule(const lldb::ModuleSP module) const; + const lldb_private::SectionList * + GetSectionListFromModule(const lldb::ModuleSP module) const; - // Read an unsigned int of the given size from memory at the given addr. - // Return -1 if the read fails, otherwise return the result as an int64_t. - int64_t - ReadUnsignedIntWithSizeInBytes(lldb::addr_t addr, int size_in_bytes); + // Read an unsigned int of the given size from memory at the given addr. + // Return -1 if the read fails, otherwise return the result as an int64_t. + int64_t ReadUnsignedIntWithSizeInBytes(lldb::addr_t addr, int size_in_bytes); - // Read a pointer from memory at the given addr. - // Return LLDB_INVALID_ADDRESS if the read fails. - lldb::addr_t - ReadPointer(lldb::addr_t addr); + // Read a pointer from memory at the given addr. + // Return LLDB_INVALID_ADDRESS if the read fails. + lldb::addr_t ReadPointer(lldb::addr_t addr); - //------------------------------------------------------------------ - // Member variables. - //------------------------------------------------------------------ - Process* m_process; ///< The process that this dynamic loader plug-in is tracking. + //------------------------------------------------------------------ + // Member variables. + //------------------------------------------------------------------ + Process + *m_process; ///< The process that this dynamic loader plug-in is tracking. private: - - DISALLOW_COPY_AND_ASSIGN (DynamicLoader); + DISALLOW_COPY_AND_ASSIGN(DynamicLoader); }; } // namespace lldb_private diff --git a/include/lldb/Target/ExecutionContext.h b/include/lldb/Target/ExecutionContext.h index da585e4c9dad..04af3ebc278d 100644 --- a/include/lldb/Target/ExecutionContext.h +++ b/include/lldb/Target/ExecutionContext.h @@ -16,26 +16,26 @@ // Other libraries and framework includes // Project includes -#include "lldb/lldb-private.h" #include "lldb/Target/StackID.h" +#include "lldb/lldb-private.h" namespace lldb_private { //===----------------------------------------------------------------------===// /// Execution context objects refer to objects in the execution of the -/// program that is being debugged. The consist of one or more of the +/// program that is being debugged. The consist of one or more of the /// following objects: target, process, thread, and frame. Many objects /// in the debugger need to track different executions contexts. For /// example, a local function variable might have an execution context -/// that refers to a stack frame. A global or static variable might +/// that refers to a stack frame. A global or static variable might /// refer to a target since a stack frame isn't required in order to /// evaluate a global or static variable (a process isn't necessarily /// needed for a global variable since we might be able to read the -/// variable value from a data section in one of the object files in +/// variable value from a data section in one of the object files in /// a target). There are two types of objects that hold onto execution /// contexts: ExecutionContextRef and ExecutionContext. Both of these /// objects are described below. -/// +/// /// Not all objects in an ExectionContext objects will be valid. If you want /// to refer strongly (ExectionContext) or weakly (ExectionContextRef) to /// a process, then only the process and target references will be valid. @@ -47,7 +47,8 @@ namespace lldb_private { //===----------------------------------------------------------------------===// //---------------------------------------------------------------------- -/// @class ExecutionContextRef ExecutionContext.h "lldb/Target/ExecutionContext.h" +/// @class ExecutionContextRef ExecutionContext.h +/// "lldb/Target/ExecutionContext.h" /// @brief A class that holds a weak reference to an execution context. /// /// ExecutionContextRef objects are designed to hold onto an execution @@ -62,296 +63,267 @@ namespace lldb_private { /// to a stack frame and a stack frame is no longer in a thread, then a /// ExecutionContextRef object that refers to that frame will not be able /// to get a shared pointer to those objects since they are no longer around. -/// +/// /// ExecutionContextRef objects can also be used as objects in classes -/// that want to track a "previous execution context". Since the weak +/// that want to track a "previous execution context". Since the weak /// references to the execution objects (target, process, thread and frame) -/// don't keep these objects around, they are safe to keep around. +/// don't keep these objects around, they are safe to keep around. /// /// The general rule of thumb is all long lived objects that want to /// refer to execution contexts should use ExecutionContextRef objects. -/// The ExecutionContext class is used to temporarily get shared +/// The ExecutionContext class is used to temporarily get shared /// pointers to any execution context objects that are still around /// so they are guaranteed to exist during a function that requires the /// objects. ExecutionContext objects should NOT be used for long term -/// storage since they will keep objects alive with extra shared pointer +/// storage since they will keep objects alive with extra shared pointer /// references to these objects. //---------------------------------------------------------------------- -class ExecutionContextRef -{ +class ExecutionContextRef { public: - //------------------------------------------------------------------ - /// Default Constructor. - //------------------------------------------------------------------ - ExecutionContextRef(); - - //------------------------------------------------------------------ - /// Copy Constructor. - //------------------------------------------------------------------ - ExecutionContextRef (const ExecutionContextRef &rhs); - - //------------------------------------------------------------------ - /// Construct using an ExecutionContext object that might be nullptr. - /// - /// If \a exe_ctx_ptr is valid, then make weak references to any - /// valid objects in the ExecutionContext, otherwise no weak - /// references to any execution context objects will be made. - //------------------------------------------------------------------ - ExecutionContextRef (const ExecutionContext *exe_ctx_ptr); - - //------------------------------------------------------------------ - /// Construct using an ExecutionContext object. - /// - /// Make weak references to any valid objects in the ExecutionContext. - //------------------------------------------------------------------ - ExecutionContextRef (const ExecutionContext &exe_ctx); - - //------------------------------------------------------------------ - /// Construct using the target and all the selected items inside of it - /// (the process and its selected thread, and the thread's selected - /// frame). If there is no selected thread, default to the first thread - /// If there is no selected frame, default to the first frame. - //------------------------------------------------------------------ - ExecutionContextRef (Target *target, bool adopt_selected); - - //------------------------------------------------------------------ - /// Construct using an execution context scope. - /// - /// If the ExecutionContextScope object is valid and refers to a frame, - /// make weak references too the frame, thread, process and target. - /// If the ExecutionContextScope object is valid and refers to a thread, - /// make weak references too the thread, process and target. - /// If the ExecutionContextScope object is valid and refers to a process, - /// make weak references too the process and target. - /// If the ExecutionContextScope object is valid and refers to a target, - /// make weak references too the target. - //------------------------------------------------------------------ - ExecutionContextRef (ExecutionContextScope *exe_scope); - - //------------------------------------------------------------------ - /// Construct using an execution context scope. - /// - /// If the ExecutionContextScope object refers to a frame, - /// make weak references too the frame, thread, process and target. - /// If the ExecutionContextScope object refers to a thread, - /// make weak references too the thread, process and target. - /// If the ExecutionContextScope object refers to a process, - /// make weak references too the process and target. - /// If the ExecutionContextScope object refers to a target, - /// make weak references too the target. - //------------------------------------------------------------------ - ExecutionContextRef (ExecutionContextScope &exe_scope); - - ~ExecutionContextRef(); - - //------------------------------------------------------------------ - /// Assignment operator - /// - /// Copy all weak references in \a rhs. - //------------------------------------------------------------------ - ExecutionContextRef & - operator =(const ExecutionContextRef &rhs); - - //------------------------------------------------------------------ - /// Assignment operator from a ExecutionContext - /// - /// Make weak references to any strongly referenced objects in \a exe_ctx. - //------------------------------------------------------------------ - ExecutionContextRef & - operator =(const ExecutionContext &exe_ctx); - - //------------------------------------------------------------------ - /// Clear the object's state. - /// - /// Sets the process and thread to nullptr, and the frame index to an - /// invalid value. - //------------------------------------------------------------------ - void - Clear (); - - //------------------------------------------------------------------ - /// Set accessor that creates a weak reference to the target - /// referenced in \a target_sp. - /// - /// If \a target_sp is valid this object will create a weak - /// reference to that object, otherwise any previous target weak - /// reference contained in this object will be reset. - /// - /// Only the weak reference to the target will be updated, no other - /// weak references will be modified. If you want this execution - /// context to make a weak reference to the target's process, use - /// the ExecutionContextRef::SetContext() functions. - /// - /// @see ExecutionContextRef::SetContext(const lldb::TargetSP &, bool) - //------------------------------------------------------------------ - void - SetTargetSP (const lldb::TargetSP &target_sp); - - //------------------------------------------------------------------ - /// Set accessor that creates a weak reference to the process - /// referenced in \a process_sp. - /// - /// If \a process_sp is valid this object will create a weak - /// reference to that object, otherwise any previous process weak - /// reference contained in this object will be reset. - /// - /// Only the weak reference to the process will be updated, no other - /// weak references will be modified. If you want this execution - /// context to make a weak reference to the target, use the - /// ExecutionContextRef::SetContext() functions. - /// - /// @see ExecutionContextRef::SetContext(const lldb::ProcessSP &) - //------------------------------------------------------------------ - void - SetProcessSP (const lldb::ProcessSP &process_sp); - - //------------------------------------------------------------------ - /// Set accessor that creates a weak reference to the thread - /// referenced in \a thread_sp. - /// - /// If \a thread_sp is valid this object will create a weak - /// reference to that object, otherwise any previous thread weak - /// reference contained in this object will be reset. - /// - /// Only the weak reference to the thread will be updated, no other - /// weak references will be modified. If you want this execution - /// context to make a weak reference to the thread's process and - /// target, use the ExecutionContextRef::SetContext() functions. - /// - /// @see ExecutionContextRef::SetContext(const lldb::ThreadSP &) - //------------------------------------------------------------------ - void - SetThreadSP (const lldb::ThreadSP &thread_sp); - - //------------------------------------------------------------------ - /// Set accessor that creates a weak reference to the frame - /// referenced in \a frame_sp. - /// - /// If \a frame_sp is valid this object will create a weak - /// reference to that object, otherwise any previous frame weak - /// reference contained in this object will be reset. - /// - /// Only the weak reference to the frame will be updated, no other - /// weak references will be modified. If you want this execution - /// context to make a weak reference to the frame's thread, process - /// and target, use the ExecutionContextRef::SetContext() functions. - /// - /// @see ExecutionContextRef::SetContext(const lldb::StackFrameSP &) - //------------------------------------------------------------------ - void - SetFrameSP (const lldb::StackFrameSP &frame_sp); - - void - SetTargetPtr (Target* target, bool adopt_selected); - - void - SetProcessPtr (Process *process); - - void - SetThreadPtr (Thread *thread); - - void - SetFramePtr (StackFrame *frame); - - //------------------------------------------------------------------ - /// Get accessor that creates a strong reference from the weak target - /// reference contained in this object. - /// - /// @returns - /// A shared pointer to a target that is not guaranteed to be valid. - //------------------------------------------------------------------ - lldb::TargetSP - GetTargetSP () const; - - //------------------------------------------------------------------ - /// Get accessor that creates a strong reference from the weak process - /// reference contained in this object. - /// - /// @returns - /// A shared pointer to a process that is not guaranteed to be valid. - //------------------------------------------------------------------ - lldb::ProcessSP - GetProcessSP () const; - - //------------------------------------------------------------------ - /// Get accessor that creates a strong reference from the weak thread - /// reference contained in this object. - /// - /// @returns - /// A shared pointer to a thread that is not guaranteed to be valid. - //------------------------------------------------------------------ - lldb::ThreadSP - GetThreadSP () const; - - //------------------------------------------------------------------ - /// Get accessor that creates a strong reference from the weak frame - /// reference contained in this object. - /// - /// @returns - /// A shared pointer to a frame that is not guaranteed to be valid. - //------------------------------------------------------------------ - lldb::StackFrameSP - GetFrameSP () const; - - //------------------------------------------------------------------ - /// Create an ExecutionContext object from this object. - /// - /// Create strong references to any execution context objects that - /// are still valid. Any of the returned shared pointers in the - /// ExecutionContext objects is not guaranteed to be valid. - /// @returns - /// An execution context object that has strong references to - /// any valid weak references in this object. - //------------------------------------------------------------------ - ExecutionContext - Lock (bool thread_and_frame_only_if_stopped) const; - - //------------------------------------------------------------------ - /// Returns true if this object has a weak reference to a thread. - /// The return value is only an indication of whether this object has - /// a weak reference and does not indicate whether the weak reference - /// is valid or not. - //------------------------------------------------------------------ - bool - HasThreadRef () const - { - return m_tid != LLDB_INVALID_THREAD_ID; - } - - //------------------------------------------------------------------ - /// Returns true if this object has a weak reference to a frame. - /// The return value is only an indication of whether this object has - /// a weak reference and does not indicate whether the weak reference - /// is valid or not. - //------------------------------------------------------------------ - bool - HasFrameRef () const - { - return m_stack_id.IsValid(); - } - - void - ClearThread () - { - m_thread_wp.reset(); - m_tid = LLDB_INVALID_THREAD_ID; - } - - void - ClearFrame () - { - m_stack_id.Clear(); - } + //------------------------------------------------------------------ + /// Default Constructor. + //------------------------------------------------------------------ + ExecutionContextRef(); + + //------------------------------------------------------------------ + /// Copy Constructor. + //------------------------------------------------------------------ + ExecutionContextRef(const ExecutionContextRef &rhs); + + //------------------------------------------------------------------ + /// Construct using an ExecutionContext object that might be nullptr. + /// + /// If \a exe_ctx_ptr is valid, then make weak references to any + /// valid objects in the ExecutionContext, otherwise no weak + /// references to any execution context objects will be made. + //------------------------------------------------------------------ + ExecutionContextRef(const ExecutionContext *exe_ctx_ptr); + + //------------------------------------------------------------------ + /// Construct using an ExecutionContext object. + /// + /// Make weak references to any valid objects in the ExecutionContext. + //------------------------------------------------------------------ + ExecutionContextRef(const ExecutionContext &exe_ctx); + + //------------------------------------------------------------------ + /// Construct using the target and all the selected items inside of it + /// (the process and its selected thread, and the thread's selected + /// frame). If there is no selected thread, default to the first thread + /// If there is no selected frame, default to the first frame. + //------------------------------------------------------------------ + ExecutionContextRef(Target *target, bool adopt_selected); + + //------------------------------------------------------------------ + /// Construct using an execution context scope. + /// + /// If the ExecutionContextScope object is valid and refers to a frame, + /// make weak references too the frame, thread, process and target. + /// If the ExecutionContextScope object is valid and refers to a thread, + /// make weak references too the thread, process and target. + /// If the ExecutionContextScope object is valid and refers to a process, + /// make weak references too the process and target. + /// If the ExecutionContextScope object is valid and refers to a target, + /// make weak references too the target. + //------------------------------------------------------------------ + ExecutionContextRef(ExecutionContextScope *exe_scope); + + //------------------------------------------------------------------ + /// Construct using an execution context scope. + /// + /// If the ExecutionContextScope object refers to a frame, + /// make weak references too the frame, thread, process and target. + /// If the ExecutionContextScope object refers to a thread, + /// make weak references too the thread, process and target. + /// If the ExecutionContextScope object refers to a process, + /// make weak references too the process and target. + /// If the ExecutionContextScope object refers to a target, + /// make weak references too the target. + //------------------------------------------------------------------ + ExecutionContextRef(ExecutionContextScope &exe_scope); + + ~ExecutionContextRef(); + + //------------------------------------------------------------------ + /// Assignment operator + /// + /// Copy all weak references in \a rhs. + //------------------------------------------------------------------ + ExecutionContextRef &operator=(const ExecutionContextRef &rhs); + + //------------------------------------------------------------------ + /// Assignment operator from a ExecutionContext + /// + /// Make weak references to any strongly referenced objects in \a exe_ctx. + //------------------------------------------------------------------ + ExecutionContextRef &operator=(const ExecutionContext &exe_ctx); + + //------------------------------------------------------------------ + /// Clear the object's state. + /// + /// Sets the process and thread to nullptr, and the frame index to an + /// invalid value. + //------------------------------------------------------------------ + void Clear(); + + //------------------------------------------------------------------ + /// Set accessor that creates a weak reference to the target + /// referenced in \a target_sp. + /// + /// If \a target_sp is valid this object will create a weak + /// reference to that object, otherwise any previous target weak + /// reference contained in this object will be reset. + /// + /// Only the weak reference to the target will be updated, no other + /// weak references will be modified. If you want this execution + /// context to make a weak reference to the target's process, use + /// the ExecutionContextRef::SetContext() functions. + /// + /// @see ExecutionContextRef::SetContext(const lldb::TargetSP &, bool) + //------------------------------------------------------------------ + void SetTargetSP(const lldb::TargetSP &target_sp); + + //------------------------------------------------------------------ + /// Set accessor that creates a weak reference to the process + /// referenced in \a process_sp. + /// + /// If \a process_sp is valid this object will create a weak + /// reference to that object, otherwise any previous process weak + /// reference contained in this object will be reset. + /// + /// Only the weak reference to the process will be updated, no other + /// weak references will be modified. If you want this execution + /// context to make a weak reference to the target, use the + /// ExecutionContextRef::SetContext() functions. + /// + /// @see ExecutionContextRef::SetContext(const lldb::ProcessSP &) + //------------------------------------------------------------------ + void SetProcessSP(const lldb::ProcessSP &process_sp); + + //------------------------------------------------------------------ + /// Set accessor that creates a weak reference to the thread + /// referenced in \a thread_sp. + /// + /// If \a thread_sp is valid this object will create a weak + /// reference to that object, otherwise any previous thread weak + /// reference contained in this object will be reset. + /// + /// Only the weak reference to the thread will be updated, no other + /// weak references will be modified. If you want this execution + /// context to make a weak reference to the thread's process and + /// target, use the ExecutionContextRef::SetContext() functions. + /// + /// @see ExecutionContextRef::SetContext(const lldb::ThreadSP &) + //------------------------------------------------------------------ + void SetThreadSP(const lldb::ThreadSP &thread_sp); + + //------------------------------------------------------------------ + /// Set accessor that creates a weak reference to the frame + /// referenced in \a frame_sp. + /// + /// If \a frame_sp is valid this object will create a weak + /// reference to that object, otherwise any previous frame weak + /// reference contained in this object will be reset. + /// + /// Only the weak reference to the frame will be updated, no other + /// weak references will be modified. If you want this execution + /// context to make a weak reference to the frame's thread, process + /// and target, use the ExecutionContextRef::SetContext() functions. + /// + /// @see ExecutionContextRef::SetContext(const lldb::StackFrameSP &) + //------------------------------------------------------------------ + void SetFrameSP(const lldb::StackFrameSP &frame_sp); + + void SetTargetPtr(Target *target, bool adopt_selected); + + void SetProcessPtr(Process *process); + + void SetThreadPtr(Thread *thread); + + void SetFramePtr(StackFrame *frame); + + //------------------------------------------------------------------ + /// Get accessor that creates a strong reference from the weak target + /// reference contained in this object. + /// + /// @returns + /// A shared pointer to a target that is not guaranteed to be valid. + //------------------------------------------------------------------ + lldb::TargetSP GetTargetSP() const; + + //------------------------------------------------------------------ + /// Get accessor that creates a strong reference from the weak process + /// reference contained in this object. + /// + /// @returns + /// A shared pointer to a process that is not guaranteed to be valid. + //------------------------------------------------------------------ + lldb::ProcessSP GetProcessSP() const; + + //------------------------------------------------------------------ + /// Get accessor that creates a strong reference from the weak thread + /// reference contained in this object. + /// + /// @returns + /// A shared pointer to a thread that is not guaranteed to be valid. + //------------------------------------------------------------------ + lldb::ThreadSP GetThreadSP() const; + + //------------------------------------------------------------------ + /// Get accessor that creates a strong reference from the weak frame + /// reference contained in this object. + /// + /// @returns + /// A shared pointer to a frame that is not guaranteed to be valid. + //------------------------------------------------------------------ + lldb::StackFrameSP GetFrameSP() const; + + //------------------------------------------------------------------ + /// Create an ExecutionContext object from this object. + /// + /// Create strong references to any execution context objects that + /// are still valid. Any of the returned shared pointers in the + /// ExecutionContext objects is not guaranteed to be valid. + /// @returns + /// An execution context object that has strong references to + /// any valid weak references in this object. + //------------------------------------------------------------------ + ExecutionContext Lock(bool thread_and_frame_only_if_stopped) const; + + //------------------------------------------------------------------ + /// Returns true if this object has a weak reference to a thread. + /// The return value is only an indication of whether this object has + /// a weak reference and does not indicate whether the weak reference + /// is valid or not. + //------------------------------------------------------------------ + bool HasThreadRef() const { return m_tid != LLDB_INVALID_THREAD_ID; } + + //------------------------------------------------------------------ + /// Returns true if this object has a weak reference to a frame. + /// The return value is only an indication of whether this object has + /// a weak reference and does not indicate whether the weak reference + /// is valid or not. + //------------------------------------------------------------------ + bool HasFrameRef() const { return m_stack_id.IsValid(); } + + void ClearThread() { + m_thread_wp.reset(); + m_tid = LLDB_INVALID_THREAD_ID; + } + + void ClearFrame() { m_stack_id.Clear(); } protected: - //------------------------------------------------------------------ - // Member variables - //------------------------------------------------------------------ - lldb::TargetWP m_target_wp; ///< A weak reference to a target - lldb::ProcessWP m_process_wp; ///< A weak reference to a process - mutable lldb::ThreadWP m_thread_wp; ///< A weak reference to a thread - lldb::tid_t m_tid; ///< The thread ID that this object refers to in case the backing object changes - StackID m_stack_id; ///< The stack ID that this object refers to in case the backing object changes + //------------------------------------------------------------------ + // Member variables + //------------------------------------------------------------------ + lldb::TargetWP m_target_wp; ///< A weak reference to a target + lldb::ProcessWP m_process_wp; ///< A weak reference to a process + mutable lldb::ThreadWP m_thread_wp; ///< A weak reference to a thread + lldb::tid_t m_tid; ///< The thread ID that this object refers to in case the + ///backing object changes + StackID m_stack_id; ///< The stack ID that this object refers to in case the + ///backing object changes }; //---------------------------------------------------------------------- @@ -362,7 +334,7 @@ protected: /// a context that specifies a target, process, thread and frame. /// These objects are designed to be used for short term execution /// context object storage while a function might be trying to evaluate -/// something that requires a thread or frame. ExecutionContextRef +/// something that requires a thread or frame. ExecutionContextRef /// objects can be used to initialize one of these objects to turn /// the weak execution context object references to the target, process, /// thread and frame into strong references (shared pointers) so that @@ -375,413 +347,360 @@ protected: /// require specific contexts. They should NOT be used for long term /// storage, for long term storage use ExecutionContextRef objects. //---------------------------------------------------------------------- -class ExecutionContext -{ +class ExecutionContext { public: - //------------------------------------------------------------------ - /// Default Constructor. - //------------------------------------------------------------------ - ExecutionContext(); - - //------------------------------------------------------------------ - // Copy constructor - //------------------------------------------------------------------ - ExecutionContext (const ExecutionContext &rhs); - - //------------------------------------------------------------------ - // Adopt the target and optionally its current context. - //------------------------------------------------------------------ - ExecutionContext (Target* t, bool fill_current_process_thread_frame = true); - - //------------------------------------------------------------------ - // Create execution contexts from shared pointers - //------------------------------------------------------------------ - ExecutionContext (const lldb::TargetSP &target_sp, bool get_process); - ExecutionContext (const lldb::ProcessSP &process_sp); - ExecutionContext (const lldb::ThreadSP &thread_sp); - ExecutionContext (const lldb::StackFrameSP &frame_sp); - - //------------------------------------------------------------------ - // Create execution contexts from weak pointers - //------------------------------------------------------------------ - ExecutionContext (const lldb::TargetWP &target_wp, bool get_process); - ExecutionContext (const lldb::ProcessWP &process_wp); - ExecutionContext (const lldb::ThreadWP &thread_wp); - ExecutionContext (const lldb::StackFrameWP &frame_wp); - ExecutionContext (const ExecutionContextRef &exe_ctx_ref); - ExecutionContext (const ExecutionContextRef *exe_ctx_ref, bool thread_and_frame_only_if_stopped = false); - - // These two variants take in a locker, and grab the target, lock the API mutex into locker, then - // fill in the rest of the shared pointers. - ExecutionContext(const ExecutionContextRef &exe_ctx_ref, std::unique_lock<std::recursive_mutex> &locker); - ExecutionContext(const ExecutionContextRef *exe_ctx_ref, std::unique_lock<std::recursive_mutex> &locker); - //------------------------------------------------------------------ - // Create execution contexts from execution context scopes - //------------------------------------------------------------------ - ExecutionContext (ExecutionContextScope *exe_scope); - ExecutionContext (ExecutionContextScope &exe_scope); - - //------------------------------------------------------------------ - /// Construct with process, thread, and frame index. - /// - /// Initialize with process \a p, thread \a t, and frame index \a f. - /// - /// @param[in] process - /// The process for this execution context. - /// - /// @param[in] thread - /// The thread for this execution context. - /// - /// @param[in] frame - /// The frame index for this execution context. - //------------------------------------------------------------------ - ExecutionContext(Process* process, - Thread *thread = nullptr, - StackFrame * frame = nullptr); - - - ~ExecutionContext(); - - ExecutionContext & - operator =(const ExecutionContext &rhs); - - bool - operator ==(const ExecutionContext &rhs) const; - - bool - operator !=(const ExecutionContext &rhs) const; - - //------------------------------------------------------------------ - /// Clear the object's state. - /// - /// Sets the process and thread to nullptr, and the frame index to an - /// invalid value. - //------------------------------------------------------------------ - void - Clear (); - - RegisterContext * - GetRegisterContext () const; - - ExecutionContextScope * - GetBestExecutionContextScope () const; - - uint32_t - GetAddressByteSize() const; - - lldb::ByteOrder - GetByteOrder() const; - - //------------------------------------------------------------------ - /// Returns a pointer to the target object. - /// - /// The returned pointer might be nullptr. Calling HasTargetScope(), - /// HasProcessScope(), HasThreadScope(), or HasFrameScope() - /// can help to pre-validate this pointer so that this accessor can - /// freely be used without having to check for nullptr each time. - /// - /// @see ExecutionContext::HasTargetScope() const - /// @see ExecutionContext::HasProcessScope() const - /// @see ExecutionContext::HasThreadScope() const - /// @see ExecutionContext::HasFrameScope() const - //------------------------------------------------------------------ - Target * - GetTargetPtr () const; - - //------------------------------------------------------------------ - /// Returns a pointer to the process object. - /// - /// The returned pointer might be nullptr. Calling HasProcessScope(), - /// HasThreadScope(), or HasFrameScope() can help to pre-validate - /// this pointer so that this accessor can freely be used without - /// having to check for nullptr each time. - /// - /// @see ExecutionContext::HasProcessScope() const - /// @see ExecutionContext::HasThreadScope() const - /// @see ExecutionContext::HasFrameScope() const - //------------------------------------------------------------------ - Process * - GetProcessPtr () const; - - //------------------------------------------------------------------ - /// Returns a pointer to the thread object. - /// - /// The returned pointer might be nullptr. Calling HasThreadScope() or - /// HasFrameScope() can help to pre-validate this pointer so that - /// this accessor can freely be used without having to check for - /// nullptr each time. - /// - /// @see ExecutionContext::HasThreadScope() const - /// @see ExecutionContext::HasFrameScope() const - //------------------------------------------------------------------ - Thread * - GetThreadPtr () const - { - return m_thread_sp.get(); - } - - //------------------------------------------------------------------ - /// Returns a pointer to the frame object. - /// - /// The returned pointer might be nullptr. Calling HasFrameScope(), - /// can help to pre-validate this pointer so that this accessor can - /// freely be used without having to check for nullptr each time. - /// - /// @see ExecutionContext::HasFrameScope() const - //------------------------------------------------------------------ - StackFrame * - GetFramePtr () const - { - return m_frame_sp.get(); - } - - //------------------------------------------------------------------ - /// Returns a reference to the target object. - /// - /// Clients should call HasTargetScope(), HasProcessScope(), - /// HasThreadScope(), or HasFrameScope() prior to calling this - /// function to ensure that this ExecutionContext object contains - /// a valid target. - /// - /// @see ExecutionContext::HasTargetScope() const - /// @see ExecutionContext::HasProcessScope() const - /// @see ExecutionContext::HasThreadScope() const - /// @see ExecutionContext::HasFrameScope() const - //------------------------------------------------------------------ - Target & - GetTargetRef () const; - - //------------------------------------------------------------------ - /// Returns a reference to the process object. - /// - /// Clients should call HasProcessScope(), HasThreadScope(), or - /// HasFrameScope() prior to calling this function to ensure that - /// this ExecutionContext object contains a valid target. - /// - /// @see ExecutionContext::HasProcessScope() const - /// @see ExecutionContext::HasThreadScope() const - /// @see ExecutionContext::HasFrameScope() const - //------------------------------------------------------------------ - Process & - GetProcessRef () const; - - //------------------------------------------------------------------ - /// Returns a reference to the thread object. - /// - /// Clients should call HasThreadScope(), or HasFrameScope() prior - /// to calling this function to ensure that this ExecutionContext - /// object contains a valid target. - /// - /// @see ExecutionContext::HasThreadScope() const - /// @see ExecutionContext::HasFrameScope() const - //------------------------------------------------------------------ - Thread & - GetThreadRef () const; - - //------------------------------------------------------------------ - /// Returns a reference to the thread object. - /// - /// Clients should call HasFrameScope() prior to calling this - /// function to ensure that this ExecutionContext object contains - /// a valid target. - /// - /// @see ExecutionContext::HasFrameScope() const - //------------------------------------------------------------------ - StackFrame & - GetFrameRef () const; - - //------------------------------------------------------------------ - /// Get accessor to get the target shared pointer. - /// - /// The returned shared pointer is not guaranteed to be valid. - //------------------------------------------------------------------ - const lldb::TargetSP & - GetTargetSP () const - { - return m_target_sp; - } - - //------------------------------------------------------------------ - /// Get accessor to get the process shared pointer. - /// - /// The returned shared pointer is not guaranteed to be valid. - //------------------------------------------------------------------ - const lldb::ProcessSP & - GetProcessSP () const - { - return m_process_sp; - } - - //------------------------------------------------------------------ - /// Get accessor to get the thread shared pointer. - /// - /// The returned shared pointer is not guaranteed to be valid. - //------------------------------------------------------------------ - const lldb::ThreadSP & - GetThreadSP () const - { - return m_thread_sp; - } - - //------------------------------------------------------------------ - /// Get accessor to get the frame shared pointer. - /// - /// The returned shared pointer is not guaranteed to be valid. - //------------------------------------------------------------------ - const lldb::StackFrameSP & - GetFrameSP () const - { - return m_frame_sp; - } - - //------------------------------------------------------------------ - /// Set accessor to set only the target shared pointer. - //------------------------------------------------------------------ - void - SetTargetSP (const lldb::TargetSP &target_sp); - - //------------------------------------------------------------------ - /// Set accessor to set only the process shared pointer. - //------------------------------------------------------------------ - void - SetProcessSP (const lldb::ProcessSP &process_sp); - - //------------------------------------------------------------------ - /// Set accessor to set only the thread shared pointer. - //------------------------------------------------------------------ - void - SetThreadSP (const lldb::ThreadSP &thread_sp); - - //------------------------------------------------------------------ - /// Set accessor to set only the frame shared pointer. - //------------------------------------------------------------------ - void - SetFrameSP (const lldb::StackFrameSP &frame_sp); - - //------------------------------------------------------------------ - /// Set accessor to set only the target shared pointer from a target - /// pointer. - //------------------------------------------------------------------ - void - SetTargetPtr (Target* target); - - //------------------------------------------------------------------ - /// Set accessor to set only the process shared pointer from a - /// process pointer. - //------------------------------------------------------------------ - void - SetProcessPtr (Process *process); - - //------------------------------------------------------------------ - /// Set accessor to set only the thread shared pointer from a thread - /// pointer. - //------------------------------------------------------------------ - void - SetThreadPtr (Thread *thread); - - //------------------------------------------------------------------ - /// Set accessor to set only the frame shared pointer from a frame - /// pointer. - //------------------------------------------------------------------ - void - SetFramePtr (StackFrame *frame); - - //------------------------------------------------------------------ - // Set the execution context using a target shared pointer. - // - // If "target_sp" is valid, sets the target context to match and - // if "get_process" is true, sets the process shared pointer if - // the target currently has a process. - //------------------------------------------------------------------ - void - SetContext (const lldb::TargetSP &target_sp, bool get_process); - - //------------------------------------------------------------------ - // Set the execution context using a process shared pointer. - // - // If "process_sp" is valid, then set the process and target in this - // context. Thread and frame contexts will be cleared. - // If "process_sp" is not valid, all shared pointers are reset. - //------------------------------------------------------------------ - void - SetContext (const lldb::ProcessSP &process_sp); - - //------------------------------------------------------------------ - // Set the execution context using a thread shared pointer. - // - // If "thread_sp" is valid, then set the thread, process and target - // in this context. The frame context will be cleared. - // If "thread_sp" is not valid, all shared pointers are reset. - //------------------------------------------------------------------ - void - SetContext (const lldb::ThreadSP &thread_sp); - - //------------------------------------------------------------------ - // Set the execution context using a frame shared pointer. - // - // If "frame_sp" is valid, then set the frame, thread, process and - // target in this context - // If "frame_sp" is not valid, all shared pointers are reset. - //------------------------------------------------------------------ - void - SetContext (const lldb::StackFrameSP &frame_sp); - - //------------------------------------------------------------------ - /// Returns true the ExecutionContext object contains a valid - /// target. - /// - /// This function can be called after initializing an ExecutionContext - /// object, and if it returns true, calls to GetTargetPtr() and - /// GetTargetRef() do not need to be checked for validity. - //------------------------------------------------------------------ - bool - HasTargetScope () const; - - //------------------------------------------------------------------ - /// Returns true the ExecutionContext object contains a valid - /// target and process. - /// - /// This function can be called after initializing an ExecutionContext - /// object, and if it returns true, calls to GetTargetPtr() and - /// GetTargetRef(), GetProcessPtr(), and GetProcessRef(), do not - /// need to be checked for validity. - //------------------------------------------------------------------ - bool - HasProcessScope () const; - - //------------------------------------------------------------------ - /// Returns true the ExecutionContext object contains a valid - /// target, process, and thread. - /// - /// This function can be called after initializing an ExecutionContext - /// object, and if it returns true, calls to GetTargetPtr(), - /// GetTargetRef(), GetProcessPtr(), GetProcessRef(), GetThreadPtr(), - /// and GetThreadRef() do not need to be checked for validity. - //------------------------------------------------------------------ - bool - HasThreadScope () const; - - //------------------------------------------------------------------ - /// Returns true the ExecutionContext object contains a valid - /// target, process, thread and frame. - /// - /// This function can be called after initializing an ExecutionContext - /// object, and if it returns true, calls to GetTargetPtr(), - /// GetTargetRef(), GetProcessPtr(), GetProcessRef(), GetThreadPtr(), - /// GetThreadRef(), GetFramePtr(), and GetFrameRef() do not need - /// to be checked for validity. - //------------------------------------------------------------------ - bool - HasFrameScope () const; - + //------------------------------------------------------------------ + /// Default Constructor. + //------------------------------------------------------------------ + ExecutionContext(); + + //------------------------------------------------------------------ + // Copy constructor + //------------------------------------------------------------------ + ExecutionContext(const ExecutionContext &rhs); + + //------------------------------------------------------------------ + // Adopt the target and optionally its current context. + //------------------------------------------------------------------ + ExecutionContext(Target *t, bool fill_current_process_thread_frame = true); + + //------------------------------------------------------------------ + // Create execution contexts from shared pointers + //------------------------------------------------------------------ + ExecutionContext(const lldb::TargetSP &target_sp, bool get_process); + ExecutionContext(const lldb::ProcessSP &process_sp); + ExecutionContext(const lldb::ThreadSP &thread_sp); + ExecutionContext(const lldb::StackFrameSP &frame_sp); + + //------------------------------------------------------------------ + // Create execution contexts from weak pointers + //------------------------------------------------------------------ + ExecutionContext(const lldb::TargetWP &target_wp, bool get_process); + ExecutionContext(const lldb::ProcessWP &process_wp); + ExecutionContext(const lldb::ThreadWP &thread_wp); + ExecutionContext(const lldb::StackFrameWP &frame_wp); + ExecutionContext(const ExecutionContextRef &exe_ctx_ref); + ExecutionContext(const ExecutionContextRef *exe_ctx_ref, + bool thread_and_frame_only_if_stopped = false); + + // These two variants take in a locker, and grab the target, lock the API + // mutex into locker, then + // fill in the rest of the shared pointers. + ExecutionContext(const ExecutionContextRef &exe_ctx_ref, + std::unique_lock<std::recursive_mutex> &locker); + ExecutionContext(const ExecutionContextRef *exe_ctx_ref, + std::unique_lock<std::recursive_mutex> &locker); + //------------------------------------------------------------------ + // Create execution contexts from execution context scopes + //------------------------------------------------------------------ + ExecutionContext(ExecutionContextScope *exe_scope); + ExecutionContext(ExecutionContextScope &exe_scope); + + //------------------------------------------------------------------ + /// Construct with process, thread, and frame index. + /// + /// Initialize with process \a p, thread \a t, and frame index \a f. + /// + /// @param[in] process + /// The process for this execution context. + /// + /// @param[in] thread + /// The thread for this execution context. + /// + /// @param[in] frame + /// The frame index for this execution context. + //------------------------------------------------------------------ + ExecutionContext(Process *process, Thread *thread = nullptr, + StackFrame *frame = nullptr); + + ~ExecutionContext(); + + ExecutionContext &operator=(const ExecutionContext &rhs); + + bool operator==(const ExecutionContext &rhs) const; + + bool operator!=(const ExecutionContext &rhs) const; + + //------------------------------------------------------------------ + /// Clear the object's state. + /// + /// Sets the process and thread to nullptr, and the frame index to an + /// invalid value. + //------------------------------------------------------------------ + void Clear(); + + RegisterContext *GetRegisterContext() const; + + ExecutionContextScope *GetBestExecutionContextScope() const; + + uint32_t GetAddressByteSize() const; + + lldb::ByteOrder GetByteOrder() const; + + //------------------------------------------------------------------ + /// Returns a pointer to the target object. + /// + /// The returned pointer might be nullptr. Calling HasTargetScope(), + /// HasProcessScope(), HasThreadScope(), or HasFrameScope() + /// can help to pre-validate this pointer so that this accessor can + /// freely be used without having to check for nullptr each time. + /// + /// @see ExecutionContext::HasTargetScope() const + /// @see ExecutionContext::HasProcessScope() const + /// @see ExecutionContext::HasThreadScope() const + /// @see ExecutionContext::HasFrameScope() const + //------------------------------------------------------------------ + Target *GetTargetPtr() const; + + //------------------------------------------------------------------ + /// Returns a pointer to the process object. + /// + /// The returned pointer might be nullptr. Calling HasProcessScope(), + /// HasThreadScope(), or HasFrameScope() can help to pre-validate + /// this pointer so that this accessor can freely be used without + /// having to check for nullptr each time. + /// + /// @see ExecutionContext::HasProcessScope() const + /// @see ExecutionContext::HasThreadScope() const + /// @see ExecutionContext::HasFrameScope() const + //------------------------------------------------------------------ + Process *GetProcessPtr() const; + + //------------------------------------------------------------------ + /// Returns a pointer to the thread object. + /// + /// The returned pointer might be nullptr. Calling HasThreadScope() or + /// HasFrameScope() can help to pre-validate this pointer so that + /// this accessor can freely be used without having to check for + /// nullptr each time. + /// + /// @see ExecutionContext::HasThreadScope() const + /// @see ExecutionContext::HasFrameScope() const + //------------------------------------------------------------------ + Thread *GetThreadPtr() const { return m_thread_sp.get(); } + + //------------------------------------------------------------------ + /// Returns a pointer to the frame object. + /// + /// The returned pointer might be nullptr. Calling HasFrameScope(), + /// can help to pre-validate this pointer so that this accessor can + /// freely be used without having to check for nullptr each time. + /// + /// @see ExecutionContext::HasFrameScope() const + //------------------------------------------------------------------ + StackFrame *GetFramePtr() const { return m_frame_sp.get(); } + + //------------------------------------------------------------------ + /// Returns a reference to the target object. + /// + /// Clients should call HasTargetScope(), HasProcessScope(), + /// HasThreadScope(), or HasFrameScope() prior to calling this + /// function to ensure that this ExecutionContext object contains + /// a valid target. + /// + /// @see ExecutionContext::HasTargetScope() const + /// @see ExecutionContext::HasProcessScope() const + /// @see ExecutionContext::HasThreadScope() const + /// @see ExecutionContext::HasFrameScope() const + //------------------------------------------------------------------ + Target &GetTargetRef() const; + + //------------------------------------------------------------------ + /// Returns a reference to the process object. + /// + /// Clients should call HasProcessScope(), HasThreadScope(), or + /// HasFrameScope() prior to calling this function to ensure that + /// this ExecutionContext object contains a valid target. + /// + /// @see ExecutionContext::HasProcessScope() const + /// @see ExecutionContext::HasThreadScope() const + /// @see ExecutionContext::HasFrameScope() const + //------------------------------------------------------------------ + Process &GetProcessRef() const; + + //------------------------------------------------------------------ + /// Returns a reference to the thread object. + /// + /// Clients should call HasThreadScope(), or HasFrameScope() prior + /// to calling this function to ensure that this ExecutionContext + /// object contains a valid target. + /// + /// @see ExecutionContext::HasThreadScope() const + /// @see ExecutionContext::HasFrameScope() const + //------------------------------------------------------------------ + Thread &GetThreadRef() const; + + //------------------------------------------------------------------ + /// Returns a reference to the thread object. + /// + /// Clients should call HasFrameScope() prior to calling this + /// function to ensure that this ExecutionContext object contains + /// a valid target. + /// + /// @see ExecutionContext::HasFrameScope() const + //------------------------------------------------------------------ + StackFrame &GetFrameRef() const; + + //------------------------------------------------------------------ + /// Get accessor to get the target shared pointer. + /// + /// The returned shared pointer is not guaranteed to be valid. + //------------------------------------------------------------------ + const lldb::TargetSP &GetTargetSP() const { return m_target_sp; } + + //------------------------------------------------------------------ + /// Get accessor to get the process shared pointer. + /// + /// The returned shared pointer is not guaranteed to be valid. + //------------------------------------------------------------------ + const lldb::ProcessSP &GetProcessSP() const { return m_process_sp; } + + //------------------------------------------------------------------ + /// Get accessor to get the thread shared pointer. + /// + /// The returned shared pointer is not guaranteed to be valid. + //------------------------------------------------------------------ + const lldb::ThreadSP &GetThreadSP() const { return m_thread_sp; } + + //------------------------------------------------------------------ + /// Get accessor to get the frame shared pointer. + /// + /// The returned shared pointer is not guaranteed to be valid. + //------------------------------------------------------------------ + const lldb::StackFrameSP &GetFrameSP() const { return m_frame_sp; } + + //------------------------------------------------------------------ + /// Set accessor to set only the target shared pointer. + //------------------------------------------------------------------ + void SetTargetSP(const lldb::TargetSP &target_sp); + + //------------------------------------------------------------------ + /// Set accessor to set only the process shared pointer. + //------------------------------------------------------------------ + void SetProcessSP(const lldb::ProcessSP &process_sp); + + //------------------------------------------------------------------ + /// Set accessor to set only the thread shared pointer. + //------------------------------------------------------------------ + void SetThreadSP(const lldb::ThreadSP &thread_sp); + + //------------------------------------------------------------------ + /// Set accessor to set only the frame shared pointer. + //------------------------------------------------------------------ + void SetFrameSP(const lldb::StackFrameSP &frame_sp); + + //------------------------------------------------------------------ + /// Set accessor to set only the target shared pointer from a target + /// pointer. + //------------------------------------------------------------------ + void SetTargetPtr(Target *target); + + //------------------------------------------------------------------ + /// Set accessor to set only the process shared pointer from a + /// process pointer. + //------------------------------------------------------------------ + void SetProcessPtr(Process *process); + + //------------------------------------------------------------------ + /// Set accessor to set only the thread shared pointer from a thread + /// pointer. + //------------------------------------------------------------------ + void SetThreadPtr(Thread *thread); + + //------------------------------------------------------------------ + /// Set accessor to set only the frame shared pointer from a frame + /// pointer. + //------------------------------------------------------------------ + void SetFramePtr(StackFrame *frame); + + //------------------------------------------------------------------ + // Set the execution context using a target shared pointer. + // + // If "target_sp" is valid, sets the target context to match and + // if "get_process" is true, sets the process shared pointer if + // the target currently has a process. + //------------------------------------------------------------------ + void SetContext(const lldb::TargetSP &target_sp, bool get_process); + + //------------------------------------------------------------------ + // Set the execution context using a process shared pointer. + // + // If "process_sp" is valid, then set the process and target in this + // context. Thread and frame contexts will be cleared. + // If "process_sp" is not valid, all shared pointers are reset. + //------------------------------------------------------------------ + void SetContext(const lldb::ProcessSP &process_sp); + + //------------------------------------------------------------------ + // Set the execution context using a thread shared pointer. + // + // If "thread_sp" is valid, then set the thread, process and target + // in this context. The frame context will be cleared. + // If "thread_sp" is not valid, all shared pointers are reset. + //------------------------------------------------------------------ + void SetContext(const lldb::ThreadSP &thread_sp); + + //------------------------------------------------------------------ + // Set the execution context using a frame shared pointer. + // + // If "frame_sp" is valid, then set the frame, thread, process and + // target in this context + // If "frame_sp" is not valid, all shared pointers are reset. + //------------------------------------------------------------------ + void SetContext(const lldb::StackFrameSP &frame_sp); + + //------------------------------------------------------------------ + /// Returns true the ExecutionContext object contains a valid + /// target. + /// + /// This function can be called after initializing an ExecutionContext + /// object, and if it returns true, calls to GetTargetPtr() and + /// GetTargetRef() do not need to be checked for validity. + //------------------------------------------------------------------ + bool HasTargetScope() const; + + //------------------------------------------------------------------ + /// Returns true the ExecutionContext object contains a valid + /// target and process. + /// + /// This function can be called after initializing an ExecutionContext + /// object, and if it returns true, calls to GetTargetPtr() and + /// GetTargetRef(), GetProcessPtr(), and GetProcessRef(), do not + /// need to be checked for validity. + //------------------------------------------------------------------ + bool HasProcessScope() const; + + //------------------------------------------------------------------ + /// Returns true the ExecutionContext object contains a valid + /// target, process, and thread. + /// + /// This function can be called after initializing an ExecutionContext + /// object, and if it returns true, calls to GetTargetPtr(), + /// GetTargetRef(), GetProcessPtr(), GetProcessRef(), GetThreadPtr(), + /// and GetThreadRef() do not need to be checked for validity. + //------------------------------------------------------------------ + bool HasThreadScope() const; + + //------------------------------------------------------------------ + /// Returns true the ExecutionContext object contains a valid + /// target, process, thread and frame. + /// + /// This function can be called after initializing an ExecutionContext + /// object, and if it returns true, calls to GetTargetPtr(), + /// GetTargetRef(), GetProcessPtr(), GetProcessRef(), GetThreadPtr(), + /// GetThreadRef(), GetFramePtr(), and GetFrameRef() do not need + /// to be checked for validity. + //------------------------------------------------------------------ + bool HasFrameScope() const; + protected: - //------------------------------------------------------------------ - // Member variables - //------------------------------------------------------------------ - lldb::TargetSP m_target_sp; ///< The target that owns the process/thread/frame - lldb::ProcessSP m_process_sp; ///< The process that owns the thread/frame - lldb::ThreadSP m_thread_sp; ///< The thread that owns the frame - lldb::StackFrameSP m_frame_sp; ///< The stack frame in thread. + //------------------------------------------------------------------ + // Member variables + //------------------------------------------------------------------ + lldb::TargetSP m_target_sp; ///< The target that owns the process/thread/frame + lldb::ProcessSP m_process_sp; ///< The process that owns the thread/frame + lldb::ThreadSP m_thread_sp; ///< The thread that owns the frame + lldb::StackFrameSP m_frame_sp; ///< The stack frame in thread. }; } // namespace lldb_private diff --git a/include/lldb/Target/ExecutionContextScope.h b/include/lldb/Target/ExecutionContextScope.h index 4a1b17d5a114..36d3d9de49b0 100644 --- a/include/lldb/Target/ExecutionContextScope.h +++ b/include/lldb/Target/ExecutionContextScope.h @@ -19,7 +19,8 @@ namespace lldb_private { //---------------------------------------------------------------------- -/// @class ExecutionContextScope ExecutionContextScope.h "lldb/Symbol/ExecutionContextScope.h" +/// @class ExecutionContextScope ExecutionContextScope.h +/// "lldb/Symbol/ExecutionContextScope.h" /// @brief Inherit from this if your object can reconstruct its /// execution context. /// @@ -36,39 +37,32 @@ namespace lldb_private { /// execution context to allow functions that take a execution contexts /// to be called. //---------------------------------------------------------------------- -class ExecutionContextScope -{ +class ExecutionContextScope { public: - virtual - ~ExecutionContextScope () {} + virtual ~ExecutionContextScope() {} - virtual lldb::TargetSP - CalculateTarget () = 0; + virtual lldb::TargetSP CalculateTarget() = 0; - virtual lldb::ProcessSP - CalculateProcess () = 0; + virtual lldb::ProcessSP CalculateProcess() = 0; - virtual lldb::ThreadSP - CalculateThread () = 0; + virtual lldb::ThreadSP CalculateThread() = 0; - virtual lldb::StackFrameSP - CalculateStackFrame () = 0; + virtual lldb::StackFrameSP CalculateStackFrame() = 0; - //------------------------------------------------------------------ - /// Reconstruct the object's execution context into \a sc. - /// - /// The object should fill in as much of the ExecutionContextScope as it - /// can so function calls that require a execution context can be made - /// for the given object. - /// - /// @param[out] exe_ctx - /// A reference to an execution context object that gets filled - /// in. - //------------------------------------------------------------------ - virtual void - CalculateExecutionContext (ExecutionContext &exe_ctx) = 0; + //------------------------------------------------------------------ + /// Reconstruct the object's execution context into \a sc. + /// + /// The object should fill in as much of the ExecutionContextScope as it + /// can so function calls that require a execution context can be made + /// for the given object. + /// + /// @param[out] exe_ctx + /// A reference to an execution context object that gets filled + /// in. + //------------------------------------------------------------------ + virtual void CalculateExecutionContext(ExecutionContext &exe_ctx) = 0; }; } // namespace lldb_private -#endif // liblldb_ExecutionContextScope_h_ +#endif // liblldb_ExecutionContextScope_h_ diff --git a/include/lldb/Target/FileAction.h b/include/lldb/Target/FileAction.h index 907c4d937beb..81122ec68798 100644 --- a/include/lldb/Target/FileAction.h +++ b/include/lldb/Target/FileAction.h @@ -10,65 +10,48 @@ #ifndef liblldb_Target_FileAction_h #define liblldb_Target_FileAction_h -#include <string> #include "lldb/Host/FileSpec.h" +#include <string> -namespace lldb_private -{ +namespace lldb_private { -class FileAction -{ - public: - enum Action - { - eFileActionNone, - eFileActionClose, - eFileActionDuplicate, - eFileActionOpen - }; +class FileAction { +public: + enum Action { + eFileActionNone, + eFileActionClose, + eFileActionDuplicate, + eFileActionOpen + }; - FileAction(); + FileAction(); - void Clear(); + void Clear(); - bool Close(int fd); + bool Close(int fd); - bool Duplicate(int fd, int dup_fd); + bool Duplicate(int fd, int dup_fd); - bool Open(int fd, const FileSpec &file_spec, bool read, bool write); + bool Open(int fd, const FileSpec &file_spec, bool read, bool write); - int - GetFD() const - { - return m_fd; - } + int GetFD() const { return m_fd; } - Action - GetAction() const - { - return m_action; - } + Action GetAction() const { return m_action; } - int - GetActionArgument() const - { - return m_arg; - } + int GetActionArgument() const { return m_arg; } - const char * - GetPath() const; + llvm::StringRef GetPath() const; - const FileSpec & - GetFileSpec() const; + const FileSpec &GetFileSpec() const; - void - Dump (Stream &stream) const; + void Dump(Stream &stream) const; - protected: - Action m_action; // The action for this file - int m_fd; // An existing file descriptor - int m_arg; // oflag for eFileActionOpen*, dup_fd for eFileActionDuplicate - FileSpec m_file_spec; // A file spec to use for opening after fork or posix_spawn +protected: + Action m_action; // The action for this file + int m_fd; // An existing file descriptor + int m_arg; // oflag for eFileActionOpen*, dup_fd for eFileActionDuplicate + FileSpec + m_file_spec; // A file spec to use for opening after fork or posix_spawn }; } // namespace lldb_private diff --git a/include/lldb/Target/InstrumentationRuntime.h b/include/lldb/Target/InstrumentationRuntime.h index a5dc853ab55b..a40914d04ea9 100644 --- a/include/lldb/Target/InstrumentationRuntime.h +++ b/include/lldb/Target/InstrumentationRuntime.h @@ -12,40 +12,89 @@ // C Includes // C++ Includes -#include <vector> #include <map> +#include <vector> // Other libraries and framework includes // Project includes -#include "lldb/lldb-private.h" -#include "lldb/lldb-types.h" #include "lldb/Core/PluginInterface.h" #include "lldb/Core/StructuredData.h" +#include "lldb/lldb-forward.h" +#include "lldb/lldb-private.h" +#include "lldb/lldb-types.h" namespace lldb_private { - -typedef std::map<lldb::InstrumentationRuntimeType, lldb::InstrumentationRuntimeSP> InstrumentationRuntimeCollection; - -class InstrumentationRuntime : - public std::enable_shared_from_this<InstrumentationRuntime>, - public PluginInterface -{ + +typedef std::map<lldb::InstrumentationRuntimeType, + lldb::InstrumentationRuntimeSP> + InstrumentationRuntimeCollection; + +class InstrumentationRuntime + : public std::enable_shared_from_this<InstrumentationRuntime>, + public PluginInterface { + /// The instrumented process. + lldb::ProcessWP m_process_wp; + + /// The module containing the instrumentation runtime. + lldb::ModuleSP m_runtime_module; + + /// The breakpoint in the instrumentation runtime. + lldb::user_id_t m_breakpoint_id; + + /// Indicates whether or not breakpoints have been registered in the + /// instrumentation runtime. + bool m_is_active; + +protected: + InstrumentationRuntime(const lldb::ProcessSP &process_sp) + : m_process_wp(), m_runtime_module(), m_breakpoint_id(0), + m_is_active(false) { + if (process_sp) + m_process_wp = process_sp; + } + + lldb::ProcessSP GetProcessSP() { return m_process_wp.lock(); } + + lldb::ModuleSP GetRuntimeModuleSP() { return m_runtime_module; } + + void SetRuntimeModuleSP(lldb::ModuleSP module_sp) { + m_runtime_module = module_sp; + } + + lldb::user_id_t GetBreakpointID() const { return m_breakpoint_id; } + + void SetBreakpointID(lldb::user_id_t ID) { m_breakpoint_id = ID; } + + void SetActive(bool IsActive) { m_is_active = IsActive; } + + /// Return a regular expression which can be used to identify a valid version + /// of the runtime library. + virtual const RegularExpression &GetPatternForRuntimeLibrary() = 0; + + /// Check whether \p module_sp corresponds to a valid runtime library. + virtual bool CheckIfRuntimeIsValid(const lldb::ModuleSP module_sp) = 0; + + /// Register a breakpoint in the runtime library and perform any other + /// necessary initialization. The runtime library + /// is guaranteed to be loaded. + virtual void Activate() = 0; + public: - - static void - ModulesDidLoad(lldb_private::ModuleList &module_list, Process *process, InstrumentationRuntimeCollection &runtimes); - - virtual void - ModulesDidLoad(lldb_private::ModuleList &module_list); - - virtual bool - IsActive(); - - virtual lldb::ThreadCollectionSP - GetBacktracesFromExtendedStopInfo(StructuredData::ObjectSP info); - + static void ModulesDidLoad(lldb_private::ModuleList &module_list, + Process *process, + InstrumentationRuntimeCollection &runtimes); + + /// Look for the instrumentation runtime in \p module_list. Register and + /// activate the runtime if this hasn't already + /// been done. + void ModulesDidLoad(lldb_private::ModuleList &module_list); + + bool IsActive() const { return m_is_active; } + + virtual lldb::ThreadCollectionSP + GetBacktracesFromExtendedStopInfo(StructuredData::ObjectSP info); }; - + } // namespace lldb_private -#endif // liblldb_InstrumentationRuntime_h_ +#endif // liblldb_InstrumentationRuntime_h_ diff --git a/include/lldb/Target/InstrumentationRuntimeStopInfo.h b/include/lldb/Target/InstrumentationRuntimeStopInfo.h index df1b937e6e26..0a4a17003d93 100644 --- a/include/lldb/Target/InstrumentationRuntimeStopInfo.h +++ b/include/lldb/Target/InstrumentationRuntimeStopInfo.h @@ -16,40 +16,30 @@ // Other libraries and framework includes // Project includes -#include "lldb/Target/StopInfo.h" #include "lldb/Core/StructuredData.h" +#include "lldb/Target/StopInfo.h" namespace lldb_private { -class InstrumentationRuntimeStopInfo : public StopInfo -{ +class InstrumentationRuntimeStopInfo : public StopInfo { public: - - ~InstrumentationRuntimeStopInfo() override - { - } - - lldb::StopReason - GetStopReason() const override - { - return lldb::eStopReasonInstrumentation; - } - - const char * - GetDescription() override; - - bool - DoShouldNotify(Event *event_ptr) override - { - return true; - } - - static lldb::StopInfoSP - CreateStopReasonWithInstrumentationData (Thread &thread, std::string description, StructuredData::ObjectSP additional_data); - + ~InstrumentationRuntimeStopInfo() override {} + + lldb::StopReason GetStopReason() const override { + return lldb::eStopReasonInstrumentation; + } + + const char *GetDescription() override; + + bool DoShouldNotify(Event *event_ptr) override { return true; } + + static lldb::StopInfoSP CreateStopReasonWithInstrumentationData( + Thread &thread, std::string description, + StructuredData::ObjectSP additional_data); + private: - - InstrumentationRuntimeStopInfo(Thread &thread, std::string description, StructuredData::ObjectSP additional_data); + InstrumentationRuntimeStopInfo(Thread &thread, std::string description, + StructuredData::ObjectSP additional_data); }; } // namespace lldb_private diff --git a/include/lldb/Target/JITLoader.h b/include/lldb/Target/JITLoader.h index 8a2d6828db2f..97f2a9796a80 100644 --- a/include/lldb/Target/JITLoader.h +++ b/include/lldb/Target/JITLoader.h @@ -21,67 +21,61 @@ namespace lldb_private { /// @class JITLoader JITLoader.h "lldb/Target/JITLoader.h" /// @brief A plug-in interface definition class for JIT loaders. /// -/// Plugins of this kind listen for code generated at runtime in the +/// Plugins of this kind listen for code generated at runtime in the /// target. They are very similar to dynamic loader, with the difference /// that they do not have information about the target's dyld and -/// that there may be multiple JITLoader plugins per process, while -/// there is at most one DynamicLoader. +/// that there may be multiple JITLoader plugins per process, while +/// there is at most one DynamicLoader. //---------------------------------------------------------------------- -class JITLoader : - public PluginInterface -{ +class JITLoader : public PluginInterface { public: - //------------------------------------------------------------------ - /// Find a JIT loader plugin for a given process. - /// - /// Scans the installed DynamicLoader plug-ins and tries to find - /// all applicable instances for the current process. - /// - /// @param[in] process - /// The process for which to try and locate a JIT loader - /// plug-in instance. - /// - //------------------------------------------------------------------ - static void - LoadPlugins (Process *process, lldb_private::JITLoaderList &list); + //------------------------------------------------------------------ + /// Find a JIT loader plugin for a given process. + /// + /// Scans the installed DynamicLoader plug-ins and tries to find + /// all applicable instances for the current process. + /// + /// @param[in] process + /// The process for which to try and locate a JIT loader + /// plug-in instance. + /// + //------------------------------------------------------------------ + static void LoadPlugins(Process *process, lldb_private::JITLoaderList &list); - //------------------------------------------------------------------ - /// Construct with a process. - //------------------------------------------------------------------ - JITLoader (Process *process); + //------------------------------------------------------------------ + /// Construct with a process. + //------------------------------------------------------------------ + JITLoader(Process *process); - ~JITLoader() override; + ~JITLoader() override; - //------------------------------------------------------------------ - /// Called after attaching a process. - /// - /// Allow JITLoader plug-ins to execute some code after - /// attaching to a process. - //------------------------------------------------------------------ - virtual void - DidAttach () = 0; + //------------------------------------------------------------------ + /// Called after attaching a process. + /// + /// Allow JITLoader plug-ins to execute some code after + /// attaching to a process. + //------------------------------------------------------------------ + virtual void DidAttach() = 0; - //------------------------------------------------------------------ - /// Called after launching a process. - /// - /// Allow JITLoader plug-ins to execute some code after - /// the process has stopped for the first time on launch. - //------------------------------------------------------------------ - virtual void - DidLaunch () = 0; + //------------------------------------------------------------------ + /// Called after launching a process. + /// + /// Allow JITLoader plug-ins to execute some code after + /// the process has stopped for the first time on launch. + //------------------------------------------------------------------ + virtual void DidLaunch() = 0; - //------------------------------------------------------------------ - /// Called after a new shared object has been loaded so that it can - /// be probed for JIT entry point hooks. - //------------------------------------------------------------------ - virtual void - ModulesDidLoad (lldb_private::ModuleList &module_list) = 0; + //------------------------------------------------------------------ + /// Called after a new shared object has been loaded so that it can + /// be probed for JIT entry point hooks. + //------------------------------------------------------------------ + virtual void ModulesDidLoad(lldb_private::ModuleList &module_list) = 0; protected: - //------------------------------------------------------------------ - // Member variables. - //------------------------------------------------------------------ - Process* m_process; + //------------------------------------------------------------------ + // Member variables. + //------------------------------------------------------------------ + Process *m_process; }; } // namespace lldb_private diff --git a/include/lldb/Target/JITLoaderList.h b/include/lldb/Target/JITLoaderList.h index c86043c5cf1f..4b9d79bbfcab 100644 --- a/include/lldb/Target/JITLoaderList.h +++ b/include/lldb/Target/JITLoaderList.h @@ -22,37 +22,28 @@ namespace lldb_private { /// /// Class used by the Process to hold a list of its JITLoaders. //---------------------------------------------------------------------- -class JITLoaderList -{ +class JITLoaderList { public: + JITLoaderList(); + ~JITLoaderList(); - JITLoaderList(); - ~JITLoaderList(); + void Append(const lldb::JITLoaderSP &jit_loader_sp); - void - Append (const lldb::JITLoaderSP &jit_loader_sp); + void Remove(const lldb::JITLoaderSP &jit_loader_sp); - void - Remove (const lldb::JITLoaderSP &jit_loader_sp); + size_t GetSize() const; - size_t - GetSize() const; + lldb::JITLoaderSP GetLoaderAtIndex(size_t idx); - lldb::JITLoaderSP - GetLoaderAtIndex (size_t idx); + void DidLaunch(); - void - DidLaunch(); + void DidAttach(); - void - DidAttach(); - - void - ModulesDidLoad (ModuleList &module_list); + void ModulesDidLoad(ModuleList &module_list); private: - std::vector<lldb::JITLoaderSP> m_jit_loaders_vec; - std::recursive_mutex m_jit_loaders_mutex; + std::vector<lldb::JITLoaderSP> m_jit_loaders_vec; + std::recursive_mutex m_jit_loaders_mutex; }; } // namespace lldb_private diff --git a/include/lldb/Target/Language.h b/include/lldb/Target/Language.h index d1a3ff8e6747..bcf840f93edd 100644 --- a/include/lldb/Target/Language.h +++ b/include/lldb/Target/Language.h @@ -1,4 +1,5 @@ -//===-- Language.h ---------------------------------------------------*- C++ -*-===// +//===-- Language.h ---------------------------------------------------*- C++ +//-*-===// // // The LLVM Compiler Infrastructure // @@ -19,191 +20,255 @@ // Other libraries and framework includes // Project includes -#include "lldb/lldb-public.h" -#include "lldb/lldb-private.h" #include "lldb/Core/PluginInterface.h" #include "lldb/DataFormatters/DumpValueObjectOptions.h" #include "lldb/DataFormatters/FormatClasses.h" #include "lldb/DataFormatters/StringPrinter.h" +#include "lldb/lldb-private.h" +#include "lldb/lldb-public.h" namespace lldb_private { - -class Language : -public PluginInterface -{ + +class Language : public PluginInterface { public: - class TypeScavenger - { + class TypeScavenger { + public: + class Result { public: - class Result - { - public: - virtual bool - IsValid () = 0; - - virtual bool - DumpToStream (Stream& stream, - bool print_help_if_available) = 0; - - virtual ~Result() = default; - }; - - typedef std::set<std::unique_ptr<Result>> ResultSet; - - virtual ~TypeScavenger () = default; - - size_t - Find (ExecutionContextScope *exe_scope, - const char *key, - ResultSet &results, - bool append = true); - - protected: - TypeScavenger () = default; - - virtual bool - Find_Impl (ExecutionContextScope *exe_scope, - const char *key, - ResultSet &results) = 0; + virtual bool IsValid() = 0; + + virtual bool DumpToStream(Stream &stream, + bool print_help_if_available) = 0; + + virtual ~Result() = default; }; - - enum class FunctionNameRepresentation - { - eName, - eNameWithArgs, - eNameWithNoArgs + + typedef std::set<std::unique_ptr<Result>> ResultSet; + + virtual ~TypeScavenger() = default; + + size_t Find(ExecutionContextScope *exe_scope, const char *key, + ResultSet &results, bool append = true); + + protected: + TypeScavenger() = default; + + virtual bool Find_Impl(ExecutionContextScope *exe_scope, const char *key, + ResultSet &results) = 0; + }; + + class ImageListTypeScavenger : public TypeScavenger { + class Result : public Language::TypeScavenger::Result { + public: + Result(CompilerType type) + : Language::TypeScavenger::Result(), m_compiler_type(type) {} + + bool IsValid() override { return m_compiler_type.IsValid(); } + + bool DumpToStream(Stream &stream, bool print_help_if_available) override { + if (IsValid()) { + m_compiler_type.DumpTypeDescription(&stream); + stream.EOL(); + return true; + } + return false; + } + + ~Result() override = default; + + private: + CompilerType m_compiler_type; }; - ~Language() override; - - static Language* - FindPlugin (lldb::LanguageType language); - - // return false from callback to stop iterating - static void - ForEach (std::function<bool(Language*)> callback); - - virtual lldb::LanguageType - GetLanguageType () const = 0; - - virtual bool - IsTopLevelFunction (Function& function); - - virtual lldb::TypeCategoryImplSP - GetFormatters (); - - virtual HardcodedFormatters::HardcodedFormatFinder - GetHardcodedFormats (); - - virtual HardcodedFormatters::HardcodedSummaryFinder - GetHardcodedSummaries (); - - virtual HardcodedFormatters::HardcodedSyntheticFinder - GetHardcodedSynthetics (); - - virtual HardcodedFormatters::HardcodedValidatorFinder - GetHardcodedValidators (); - - virtual std::vector<ConstString> - GetPossibleFormattersMatches (ValueObject& valobj, lldb::DynamicValueType use_dynamic); - - virtual lldb_private::formatters::StringPrinter::EscapingHelper - GetStringPrinterEscapingHelper (lldb_private::formatters::StringPrinter::GetPrintableElementType); - - virtual std::unique_ptr<TypeScavenger> - GetTypeScavenger (); - - virtual const char* - GetLanguageSpecificTypeLookupHelp (); - - // if an individual data formatter can apply to several types and cross a language boundary - // it makes sense for individual languages to want to customize the printing of values of that - // type by appending proper prefix/suffix information in language-specific ways - virtual bool - GetFormatterPrefixSuffix (ValueObject& valobj, ConstString type_hint, - std::string& prefix, std::string& suffix); - - // if a language has a custom format for printing variable declarations that it wants LLDB to honor - // it should return an appropriate closure here - virtual DumpValueObjectOptions::DeclPrintingHelper - GetDeclPrintingHelper (); - - virtual LazyBool - IsLogicalTrue (ValueObject& valobj, - Error& error); - - // for a ValueObject of some "reference type", if the value points to the - // nil/null object, this method returns true - virtual bool - IsNilReference (ValueObject& valobj); - - // for a ValueObject of some "reference type", if the language provides a technique - // to decide whether the reference has ever been assigned to some object, this method - // will return true if such detection is possible, and if the reference has never been assigned - virtual bool - IsUninitializedReference (ValueObject& valobj); - - virtual bool - GetFunctionDisplayName (const SymbolContext *sc, - const ExecutionContext *exe_ctx, - FunctionNameRepresentation representation, - Stream& s); - - virtual void - GetExceptionResolverDescription(bool catch_on, bool throw_on, Stream &s); - - static void - GetDefaultExceptionResolverDescription(bool catch_on, bool throw_on, Stream &s); - - // These are accessors for general information about the Languages lldb knows about: - - static lldb::LanguageType - GetLanguageTypeFromString (const char *string); - - static const char * - GetNameForLanguageType (lldb::LanguageType language); - - static void - PrintAllLanguages (Stream &s, const char *prefix, const char *suffix); - - // return false from callback to stop iterating - static void - ForAllLanguages (std::function<bool(lldb::LanguageType)> callback); - - static bool - LanguageIsCPlusPlus (lldb::LanguageType language); - - static bool - LanguageIsObjC (lldb::LanguageType language); - - static bool - LanguageIsC (lldb::LanguageType language); - - static bool - LanguageIsPascal (lldb::LanguageType language); - - // return the primary language, so if LanguageIsC(l), return eLanguageTypeC, etc. - static lldb::LanguageType - GetPrimaryLanguage (lldb::LanguageType language); - - static void - GetLanguagesSupportingTypeSystems (std::set<lldb::LanguageType> &languages, - std::set<lldb::LanguageType> &languages_for_expressions); - - static void - GetLanguagesSupportingREPLs (std::set<lldb::LanguageType> &languages); - + protected: + ImageListTypeScavenger() = default; + + ~ImageListTypeScavenger() override = default; + + // is this type something we should accept? it's usually going to be a + // filter by language + maybe some sugar tweaking + // returning an empty type means rejecting this candidate entirely; + // any other result will be accepted as a valid match + virtual CompilerType AdjustForInclusion(CompilerType &candidate) = 0; + + bool Find_Impl(ExecutionContextScope *exe_scope, const char *key, + ResultSet &results) override; + }; + + template <typename... ScavengerTypes> + class EitherTypeScavenger : public TypeScavenger { + public: + EitherTypeScavenger() : TypeScavenger(), m_scavengers() { + for (std::shared_ptr<TypeScavenger> scavenger : { std::shared_ptr<TypeScavenger>(new ScavengerTypes())... }) { + if (scavenger) + m_scavengers.push_back(scavenger); + } + } + protected: + bool Find_Impl(ExecutionContextScope *exe_scope, const char *key, + ResultSet &results) override { + const bool append = false; + for (auto& scavenger : m_scavengers) { + if (scavenger && scavenger->Find(exe_scope, key, results, append)) + return true; + } + return false; + } + private: + std::vector<std::shared_ptr<TypeScavenger>> m_scavengers; + }; + + template <typename... ScavengerTypes> + class UnionTypeScavenger : public TypeScavenger { + public: + UnionTypeScavenger() : TypeScavenger(), m_scavengers() { + for (std::shared_ptr<TypeScavenger> scavenger : { std::shared_ptr<TypeScavenger>(new ScavengerTypes())... }) { + if (scavenger) + m_scavengers.push_back(scavenger); + } + } + protected: + bool Find_Impl(ExecutionContextScope *exe_scope, const char *key, + ResultSet &results) override { + const bool append = true; + bool success = false; + for (auto& scavenger : m_scavengers) { + if (scavenger) + success = scavenger->Find(exe_scope, key, results, append) || success; + } + return success; + } + private: + std::vector<std::shared_ptr<TypeScavenger>> m_scavengers; + }; + + enum class FunctionNameRepresentation { + eName, + eNameWithArgs, + eNameWithNoArgs + }; + + ~Language() override; + + static Language *FindPlugin(lldb::LanguageType language); + + // return false from callback to stop iterating + static void ForEach(std::function<bool(Language *)> callback); + + virtual lldb::LanguageType GetLanguageType() const = 0; + + virtual bool IsTopLevelFunction(Function &function); + + virtual lldb::TypeCategoryImplSP GetFormatters(); + + virtual HardcodedFormatters::HardcodedFormatFinder GetHardcodedFormats(); + + virtual HardcodedFormatters::HardcodedSummaryFinder GetHardcodedSummaries(); + + virtual HardcodedFormatters::HardcodedSyntheticFinder + GetHardcodedSynthetics(); + + virtual HardcodedFormatters::HardcodedValidatorFinder + GetHardcodedValidators(); + + virtual std::vector<ConstString> + GetPossibleFormattersMatches(ValueObject &valobj, + lldb::DynamicValueType use_dynamic); + + virtual lldb_private::formatters::StringPrinter::EscapingHelper + GetStringPrinterEscapingHelper( + lldb_private::formatters::StringPrinter::GetPrintableElementType); + + virtual std::unique_ptr<TypeScavenger> GetTypeScavenger(); + + virtual const char *GetLanguageSpecificTypeLookupHelp(); + + // if an individual data formatter can apply to several types and cross a + // language boundary + // it makes sense for individual languages to want to customize the printing + // of values of that + // type by appending proper prefix/suffix information in language-specific + // ways + virtual bool GetFormatterPrefixSuffix(ValueObject &valobj, + ConstString type_hint, + std::string &prefix, + std::string &suffix); + + // if a language has a custom format for printing variable declarations that + // it wants LLDB to honor + // it should return an appropriate closure here + virtual DumpValueObjectOptions::DeclPrintingHelper GetDeclPrintingHelper(); + + virtual LazyBool IsLogicalTrue(ValueObject &valobj, Error &error); + + // for a ValueObject of some "reference type", if the value points to the + // nil/null object, this method returns true + virtual bool IsNilReference(ValueObject &valobj); + + // for a ValueObject of some "reference type", if the language provides a + // technique + // to decide whether the reference has ever been assigned to some object, this + // method + // will return true if such detection is possible, and if the reference has + // never been assigned + virtual bool IsUninitializedReference(ValueObject &valobj); + + virtual bool GetFunctionDisplayName(const SymbolContext *sc, + const ExecutionContext *exe_ctx, + FunctionNameRepresentation representation, + Stream &s); + + virtual void GetExceptionResolverDescription(bool catch_on, bool throw_on, + Stream &s); + + static void GetDefaultExceptionResolverDescription(bool catch_on, + bool throw_on, Stream &s); + + // These are accessors for general information about the Languages lldb knows + // about: + + static lldb::LanguageType + GetLanguageTypeFromString(const char *string) = delete; + static lldb::LanguageType GetLanguageTypeFromString(llvm::StringRef string); + + static const char *GetNameForLanguageType(lldb::LanguageType language); + + static void PrintAllLanguages(Stream &s, const char *prefix, + const char *suffix); + + // return false from callback to stop iterating + static void ForAllLanguages(std::function<bool(lldb::LanguageType)> callback); + + static bool LanguageIsCPlusPlus(lldb::LanguageType language); + + static bool LanguageIsObjC(lldb::LanguageType language); + + static bool LanguageIsC(lldb::LanguageType language); + + static bool LanguageIsPascal(lldb::LanguageType language); + + // return the primary language, so if LanguageIsC(l), return eLanguageTypeC, + // etc. + static lldb::LanguageType GetPrimaryLanguage(lldb::LanguageType language); + + static void GetLanguagesSupportingTypeSystems( + std::set<lldb::LanguageType> &languages, + std::set<lldb::LanguageType> &languages_for_expressions); + + static void + GetLanguagesSupportingREPLs(std::set<lldb::LanguageType> &languages); + protected: - //------------------------------------------------------------------ - // Classes that inherit from Language can see and modify these - //------------------------------------------------------------------ - - Language(); + //------------------------------------------------------------------ + // Classes that inherit from Language can see and modify these + //------------------------------------------------------------------ + + Language(); + private: - - DISALLOW_COPY_AND_ASSIGN (Language); + DISALLOW_COPY_AND_ASSIGN(Language); }; - + } // namespace lldb_private #endif // liblldb_Language_h_ diff --git a/include/lldb/Target/LanguageRuntime.h b/include/lldb/Target/LanguageRuntime.h index beb7a9e74876..a57216e84794 100644 --- a/include/lldb/Target/LanguageRuntime.h +++ b/include/lldb/Target/LanguageRuntime.h @@ -1,4 +1,5 @@ -//===-- LanguageRuntime.h ---------------------------------------------------*- C++ -*-===// +//===-- LanguageRuntime.h ---------------------------------------------------*- +// C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,168 +15,161 @@ // C++ Includes // Other libraries and framework includes // Project includes -#include "lldb/lldb-public.h" #include "lldb/Breakpoint/BreakpointResolver.h" #include "lldb/Breakpoint/BreakpointResolverName.h" #include "lldb/Core/PluginInterface.h" -#include "lldb/lldb-private.h" -#include "lldb/Core/ValueObject.h" #include "lldb/Core/Value.h" -#include "lldb/Target/ExecutionContextScope.h" +#include "lldb/Core/ValueObject.h" #include "lldb/Expression/LLVMUserExpression.h" +#include "lldb/Target/ExecutionContextScope.h" +#include "lldb/lldb-private.h" +#include "lldb/lldb-public.h" #include "clang/Basic/TargetOptions.h" namespace lldb_private { -class LanguageRuntime : - public PluginInterface -{ +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, + const StructuredData::Dictionary &data_dict, + Error &error); + + StructuredData::ObjectSP SerializeToStructuredData() override; - ~LanguageRuntime() override; - - static LanguageRuntime* - FindPlugin (Process *process, lldb::LanguageType language); - - static void - InitializeCommands (CommandObject* parent); - - virtual lldb::LanguageType - GetLanguageType () const = 0; - - virtual bool - GetObjectDescription (Stream &str, ValueObject &object) = 0; - - virtual bool - GetObjectDescription (Stream &str, Value &value, ExecutionContextScope *exe_scope) = 0; - - // this call should return true if it could set the name and/or the type - virtual bool - GetDynamicTypeAndAddress (ValueObject &in_value, - lldb::DynamicValueType use_dynamic, - TypeAndOrName &class_type_or_name, - Address &address, - Value::ValueType &value_type) = 0; - - // This call should return a CompilerType given a generic type name - // and an ExecutionContextScope in which one can actually fetch - // any specialization information required. - virtual CompilerType - GetConcreteType (ExecutionContextScope *exe_scope, - ConstString abstract_type_name) - { - return CompilerType(); - } - - // This should be a fast test to determine whether it is likely that this value would - // have a dynamic type. - virtual bool - CouldHaveDynamicValue (ValueObject &in_value) = 0; - - // The contract for GetDynamicTypeAndAddress() is to return a "bare-bones" dynamic type - // For instance, given a Base* pointer, GetDynamicTypeAndAddress() will return the type of - // Derived, not Derived*. The job of this API is to correct this misalignment between the - // static type and the discovered dynamic type - virtual TypeAndOrName - FixUpDynamicType (const TypeAndOrName& type_and_or_name, - ValueObject& static_value) = 0; - - virtual void - SetExceptionBreakpoints () - { - } - - virtual void - ClearExceptionBreakpoints () - { - } - - virtual bool - ExceptionBreakpointsAreSet () - { - return false; - } - - virtual bool - ExceptionBreakpointsExplainStop (lldb::StopInfoSP stop_reason) - { - return false; - } - - static lldb::BreakpointSP - CreateExceptionBreakpoint (Target &target, - lldb::LanguageType language, - bool catch_bp, - bool throw_bp, - bool is_internal = false); - - static Breakpoint::BreakpointPreconditionSP - CreateExceptionPrecondition (lldb::LanguageType language, - bool catch_bp, - bool throw_bp); - Process * - GetProcess() - { - return m_process; - } - - Target& - GetTargetRef() - { - return m_process->GetTarget(); - } - - virtual lldb::BreakpointResolverSP - CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp) = 0; - - virtual lldb::SearchFilterSP - CreateExceptionSearchFilter (); - - virtual bool - GetTypeBitSize (const CompilerType& compiler_type, - uint64_t &size) - { - return false; - } - - virtual bool - IsRuntimeSupportValue (ValueObject& valobj) - { - return false; - } - - virtual void - ModulesDidLoad (const ModuleList &module_list) - { - } - - // Called by the Clang expression evaluation engine to allow runtimes to alter the set of target options provided to - // the compiler. - // If the options prototype is modified, runtimes must return true, false otherwise. - virtual bool - GetOverrideExprOptions(clang::TargetOptions &prototype) - { - return false; - } - - // Called by ClangExpressionParser::PrepareForExecution to query for any custom LLVM IR passes - // that need to be run before an expression is assembled and run. - virtual bool - GetIRPasses(LLVMUserExpression::IRPasses &custom_passes) - { - return false; - } protected: - //------------------------------------------------------------------ - // Classes that inherit from LanguageRuntime can see and modify these - //------------------------------------------------------------------ - - LanguageRuntime(Process *process); - Process *m_process; -private: + 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; + + static LanguageRuntime *FindPlugin(Process *process, + lldb::LanguageType language); + + static void InitializeCommands(CommandObject *parent); + + virtual lldb::LanguageType GetLanguageType() const = 0; - DISALLOW_COPY_AND_ASSIGN (LanguageRuntime); + virtual bool GetObjectDescription(Stream &str, ValueObject &object) = 0; + + virtual bool GetObjectDescription(Stream &str, Value &value, + ExecutionContextScope *exe_scope) = 0; + + // this call should return true if it could set the name and/or the type + virtual bool GetDynamicTypeAndAddress(ValueObject &in_value, + lldb::DynamicValueType use_dynamic, + TypeAndOrName &class_type_or_name, + Address &address, + Value::ValueType &value_type) = 0; + + // This call should return a CompilerType given a generic type name + // and an ExecutionContextScope in which one can actually fetch + // any specialization information required. + virtual CompilerType GetConcreteType(ExecutionContextScope *exe_scope, + ConstString abstract_type_name) { + return CompilerType(); + } + + // This should be a fast test to determine whether it is likely that this + // value would + // have a dynamic type. + virtual bool CouldHaveDynamicValue(ValueObject &in_value) = 0; + + // The contract for GetDynamicTypeAndAddress() is to return a "bare-bones" + // dynamic type + // For instance, given a Base* pointer, GetDynamicTypeAndAddress() will return + // the type of + // Derived, not Derived*. The job of this API is to correct this misalignment + // between the + // static type and the discovered dynamic type + virtual TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name, + ValueObject &static_value) = 0; + + virtual void SetExceptionBreakpoints() {} + + virtual void ClearExceptionBreakpoints() {} + + virtual bool ExceptionBreakpointsAreSet() { return false; } + + virtual bool ExceptionBreakpointsExplainStop(lldb::StopInfoSP stop_reason) { + return false; + } + + static lldb::BreakpointSP + CreateExceptionBreakpoint(Target &target, lldb::LanguageType language, + bool catch_bp, bool throw_bp, + bool is_internal = false); + + static Breakpoint::BreakpointPreconditionSP + CreateExceptionPrecondition(lldb::LanguageType language, bool catch_bp, + bool throw_bp); + Process *GetProcess() { return m_process; } + + Target &GetTargetRef() { return m_process->GetTarget(); } + + virtual lldb::BreakpointResolverSP + CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp, bool throw_bp) = 0; + + virtual lldb::SearchFilterSP CreateExceptionSearchFilter(); + + virtual bool GetTypeBitSize(const CompilerType &compiler_type, + uint64_t &size) { + return false; + } + + virtual bool IsRuntimeSupportValue(ValueObject &valobj) { return false; } + + virtual void ModulesDidLoad(const ModuleList &module_list) {} + + // Called by the Clang expression evaluation engine to allow runtimes to alter + // the set of target options provided to + // the compiler. + // If the options prototype is modified, runtimes must return true, false + // otherwise. + virtual bool GetOverrideExprOptions(clang::TargetOptions &prototype) { + return false; + } + + // Called by ClangExpressionParser::PrepareForExecution to query for any + // custom LLVM IR passes + // that need to be run before an expression is assembled and run. + virtual bool GetIRPasses(LLVMUserExpression::IRPasses &custom_passes) { + return false; + } + +protected: + //------------------------------------------------------------------ + // Classes that inherit from LanguageRuntime can see and modify these + //------------------------------------------------------------------ + + LanguageRuntime(Process *process); + Process *m_process; + +private: + DISALLOW_COPY_AND_ASSIGN(LanguageRuntime); }; } // namespace lldb_private diff --git a/include/lldb/Target/Memory.h b/include/lldb/Target/Memory.h index f4d776a43c99..57275bbda593 100644 --- a/include/lldb/Target/Memory.h +++ b/include/lldb/Target/Memory.h @@ -19,187 +19,140 @@ // Other libraries and framework includes // Project includes -#include "lldb/lldb-private.h" #include "lldb/Core/RangeMap.h" +#include "lldb/lldb-private.h" namespace lldb_private { - //---------------------------------------------------------------------- - // A class to track memory that was read from a live process between - // runs. - //---------------------------------------------------------------------- - class MemoryCache - { - public: - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - MemoryCache (Process &process); - - ~MemoryCache (); - - void - Clear(bool clear_invalid_ranges = false); - - void - Flush (lldb::addr_t addr, size_t size); - - size_t - Read (lldb::addr_t addr, - void *dst, - size_t dst_len, - Error &error); - - uint32_t - GetMemoryCacheLineSize() const - { - return m_L2_cache_line_byte_size ; - } - - void - AddInvalidRange (lldb::addr_t base_addr, lldb::addr_t byte_size); - - bool - RemoveInvalidRange (lldb::addr_t base_addr, lldb::addr_t byte_size); - - // Allow external sources to populate data into the L1 memory cache - void - AddL1CacheData(lldb::addr_t addr, const void *src, size_t src_len); - - void - AddL1CacheData(lldb::addr_t addr, const lldb::DataBufferSP &data_buffer_sp); - - protected: - typedef std::map<lldb::addr_t, lldb::DataBufferSP> BlockMap; - typedef RangeArray<lldb::addr_t, lldb::addr_t, 4> InvalidRanges; - typedef Range<lldb::addr_t, lldb::addr_t> AddrRange; - //------------------------------------------------------------------ - // Classes that inherit from MemoryCache can see and modify these - //------------------------------------------------------------------ - std::recursive_mutex m_mutex; - BlockMap m_L1_cache; // A first level memory cache whose chunk sizes vary that will be used only if the memory read fits entirely in a chunk - BlockMap m_L2_cache; // A memory cache of fixed size chinks (m_L2_cache_line_byte_size bytes in size each) - InvalidRanges m_invalid_ranges; - Process &m_process; - uint32_t m_L2_cache_line_byte_size; - private: - DISALLOW_COPY_AND_ASSIGN (MemoryCache); - }; - - - class AllocatedBlock - { - public: - AllocatedBlock (lldb::addr_t addr, - uint32_t byte_size, - uint32_t permissions, - uint32_t chunk_size); - - ~AllocatedBlock (); - - lldb::addr_t - ReserveBlock (uint32_t size); - - bool - FreeBlock (lldb::addr_t addr); - - lldb::addr_t - GetBaseAddress () const - { - return m_addr; - } - - uint32_t - GetByteSize () const - { - return m_byte_size; - } - - uint32_t - GetPermissions () const - { - return m_permissions; - } - - uint32_t - GetChunkSize () const - { - return m_chunk_size; - } - - bool - Contains (lldb::addr_t addr) const - { - return ((addr >= m_addr) && addr < (m_addr + m_byte_size)); - } - protected: - uint32_t - TotalChunks () const - { - return m_byte_size / m_chunk_size; - } - - uint32_t - CalculateChunksNeededForSize (uint32_t size) const - { - return (size + m_chunk_size - 1) / m_chunk_size; - } - const lldb::addr_t m_addr; // Base address of this block of memory - const uint32_t m_byte_size; // 4GB of chunk should be enough... - const uint32_t m_permissions; // Permissions for this memory (logical OR of lldb::Permissions bits) - const uint32_t m_chunk_size; // The size of chunks that the memory at m_addr is divied up into - typedef std::map<uint32_t, uint32_t> OffsetToChunkSize; - OffsetToChunkSize m_offset_to_chunk_size; - }; - - - //---------------------------------------------------------------------- - // A class that can track allocated memory and give out allocated memory - // without us having to make an allocate/deallocate call every time we - // need some memory in a process that is being debugged. - //---------------------------------------------------------------------- - class AllocatedMemoryCache - { - public: - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - AllocatedMemoryCache (Process &process); - - ~AllocatedMemoryCache (); - - void - Clear(); - - lldb::addr_t - AllocateMemory (size_t byte_size, - uint32_t permissions, - Error &error); - - bool - DeallocateMemory (lldb::addr_t ptr); - - protected: - typedef std::shared_ptr<AllocatedBlock> AllocatedBlockSP; - - AllocatedBlockSP - AllocatePage (uint32_t byte_size, - uint32_t permissions, - uint32_t chunk_size, - Error &error); - - - //------------------------------------------------------------------ - // Classes that inherit from MemoryCache can see and modify these - //------------------------------------------------------------------ - Process &m_process; - std::recursive_mutex m_mutex; - typedef std::multimap<uint32_t, AllocatedBlockSP> PermissionsToBlockMap; - PermissionsToBlockMap m_memory_map; - - private: - DISALLOW_COPY_AND_ASSIGN (AllocatedMemoryCache); - }; +//---------------------------------------------------------------------- +// A class to track memory that was read from a live process between +// runs. +//---------------------------------------------------------------------- +class MemoryCache { +public: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + MemoryCache(Process &process); + + ~MemoryCache(); + + void Clear(bool clear_invalid_ranges = false); + + void Flush(lldb::addr_t addr, size_t size); + + size_t Read(lldb::addr_t addr, void *dst, size_t dst_len, Error &error); + + uint32_t GetMemoryCacheLineSize() const { return m_L2_cache_line_byte_size; } + + void AddInvalidRange(lldb::addr_t base_addr, lldb::addr_t byte_size); + + bool RemoveInvalidRange(lldb::addr_t base_addr, lldb::addr_t byte_size); + + // Allow external sources to populate data into the L1 memory cache + void AddL1CacheData(lldb::addr_t addr, const void *src, size_t src_len); + + void AddL1CacheData(lldb::addr_t addr, + const lldb::DataBufferSP &data_buffer_sp); + +protected: + typedef std::map<lldb::addr_t, lldb::DataBufferSP> BlockMap; + typedef RangeArray<lldb::addr_t, lldb::addr_t, 4> InvalidRanges; + typedef Range<lldb::addr_t, lldb::addr_t> AddrRange; + //------------------------------------------------------------------ + // Classes that inherit from MemoryCache can see and modify these + //------------------------------------------------------------------ + std::recursive_mutex m_mutex; + BlockMap m_L1_cache; // A first level memory cache whose chunk sizes vary that + // will be used only if the memory read fits entirely in + // a chunk + BlockMap m_L2_cache; // A memory cache of fixed size chinks + // (m_L2_cache_line_byte_size bytes in size each) + InvalidRanges m_invalid_ranges; + Process &m_process; + uint32_t m_L2_cache_line_byte_size; + +private: + DISALLOW_COPY_AND_ASSIGN(MemoryCache); +}; + +class AllocatedBlock { +public: + AllocatedBlock(lldb::addr_t addr, uint32_t byte_size, uint32_t permissions, + uint32_t chunk_size); + + ~AllocatedBlock(); + + lldb::addr_t ReserveBlock(uint32_t size); + + bool FreeBlock(lldb::addr_t addr); + + lldb::addr_t GetBaseAddress() const { return m_addr; } + + uint32_t GetByteSize() const { return m_byte_size; } + + uint32_t GetPermissions() const { return m_permissions; } + + uint32_t GetChunkSize() const { return m_chunk_size; } + + bool Contains(lldb::addr_t addr) const { + return ((addr >= m_addr) && addr < (m_addr + m_byte_size)); + } + +protected: + uint32_t TotalChunks() const { return m_byte_size / m_chunk_size; } + + uint32_t CalculateChunksNeededForSize(uint32_t size) const { + return (size + m_chunk_size - 1) / m_chunk_size; + } + const lldb::addr_t m_addr; // Base address of this block of memory + const uint32_t m_byte_size; // 4GB of chunk should be enough... + const uint32_t m_permissions; // Permissions for this memory (logical OR of + // lldb::Permissions bits) + const uint32_t m_chunk_size; // The size of chunks that the memory at m_addr + // is divied up into + typedef std::map<uint32_t, uint32_t> OffsetToChunkSize; + OffsetToChunkSize m_offset_to_chunk_size; +}; + +//---------------------------------------------------------------------- +// A class that can track allocated memory and give out allocated memory +// without us having to make an allocate/deallocate call every time we +// need some memory in a process that is being debugged. +//---------------------------------------------------------------------- +class AllocatedMemoryCache { +public: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + AllocatedMemoryCache(Process &process); + + ~AllocatedMemoryCache(); + + void Clear(); + + lldb::addr_t AllocateMemory(size_t byte_size, uint32_t permissions, + Error &error); + + bool DeallocateMemory(lldb::addr_t ptr); + +protected: + typedef std::shared_ptr<AllocatedBlock> AllocatedBlockSP; + + AllocatedBlockSP AllocatePage(uint32_t byte_size, uint32_t permissions, + uint32_t chunk_size, Error &error); + + //------------------------------------------------------------------ + // Classes that inherit from MemoryCache can see and modify these + //------------------------------------------------------------------ + Process &m_process; + std::recursive_mutex m_mutex; + typedef std::multimap<uint32_t, AllocatedBlockSP> PermissionsToBlockMap; + PermissionsToBlockMap m_memory_map; + +private: + DISALLOW_COPY_AND_ASSIGN(AllocatedMemoryCache); +}; } // namespace lldb_private -#endif // liblldb_Memory_h_ +#endif // liblldb_Memory_h_ diff --git a/include/lldb/Target/MemoryHistory.h b/include/lldb/Target/MemoryHistory.h index b3bd62d6547c..acc36ffe2eb4 100644 --- a/include/lldb/Target/MemoryHistory.h +++ b/include/lldb/Target/MemoryHistory.h @@ -1,4 +1,5 @@ -//===-- MemoryHistory.h ---------------------------------------------------*- C++ -*-===// +//===-- MemoryHistory.h ---------------------------------------------------*- +//C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -16,27 +17,22 @@ // Other libraries and framework includes // Project includes +#include "lldb/Core/PluginInterface.h" #include "lldb/lldb-private.h" #include "lldb/lldb-types.h" -#include "lldb/Core/PluginInterface.h" namespace lldb_private { - + typedef std::vector<lldb::ThreadSP> HistoryThreads; - -class MemoryHistory : - public std::enable_shared_from_this<MemoryHistory>, - public PluginInterface -{ -public: - static lldb::MemoryHistorySP - FindPlugin (const lldb::ProcessSP process); +class MemoryHistory : public std::enable_shared_from_this<MemoryHistory>, + public PluginInterface { +public: + static lldb::MemoryHistorySP FindPlugin(const lldb::ProcessSP process); - virtual HistoryThreads - GetHistoryThreads(lldb::addr_t address) = 0; + virtual HistoryThreads GetHistoryThreads(lldb::addr_t address) = 0; }; - + } // namespace lldb_private -#endif // liblldb_MemoryHistory_h_ +#endif // liblldb_MemoryHistory_h_ diff --git a/include/lldb/Target/MemoryRegionInfo.h b/include/lldb/Target/MemoryRegionInfo.h index 5c82a1f294dd..be0cfa429b8f 100644 --- a/include/lldb/Target/MemoryRegionInfo.h +++ b/include/lldb/Target/MemoryRegionInfo.h @@ -1,4 +1,5 @@ -//===-- MemoryRegionInfo.h ---------------------------------------*- C++ -*-===// +//===-- MemoryRegionInfo.h ---------------------------------------*- C++ +//-*-===// // // The LLVM Compiler Infrastructure // @@ -10,154 +11,93 @@ #ifndef lldb_MemoryRegionInfo_h #define lldb_MemoryRegionInfo_h +#include "lldb/Core/ConstString.h" #include "lldb/Core/RangeMap.h" #include "lldb/Utility/Range.h" -namespace lldb_private -{ - class MemoryRegionInfo - { - public: - typedef Range<lldb::addr_t, lldb::addr_t> RangeType; - - enum OptionalBool { - eDontKnow = -1, - eNo = 0, - eYes = 1 - }; - - MemoryRegionInfo () : - m_range (), - m_read (eDontKnow), - m_write (eDontKnow), - m_execute (eDontKnow), - m_mapped (eDontKnow) - { - } - - ~MemoryRegionInfo () - { - } - - RangeType & - GetRange() - { - return m_range; - } - - void - Clear() - { - m_range.Clear(); - m_read = m_write = m_execute = eDontKnow; - } - - const RangeType & - GetRange() const - { - return m_range; - } - - OptionalBool - GetReadable () const - { - return m_read; - } - - OptionalBool - GetWritable () const - { - return m_write; - } - - OptionalBool - GetExecutable () const - { - return m_execute; - } - - OptionalBool - GetMapped () const - { - return m_mapped; - } - - void - SetReadable (OptionalBool val) - { - m_read = val; - } - - void - SetWritable (OptionalBool val) - { - m_write = val; - } - - void - SetExecutable (OptionalBool val) - { - m_execute = val; - } - - void - SetMapped (OptionalBool val) - { - m_mapped = val; - } - - //---------------------------------------------------------------------- - // Get permissions as a uint32_t that is a mask of one or more bits from - // the lldb::Permissions - //---------------------------------------------------------------------- - uint32_t - GetLLDBPermissions() const - { - uint32_t permissions = 0; - if (m_read) - permissions |= lldb::ePermissionsReadable; - if (m_write) - permissions |= lldb::ePermissionsWritable; - if (m_execute) - permissions |= lldb::ePermissionsExecutable; - return permissions; - } - - //---------------------------------------------------------------------- - // Set permissions from a uint32_t that contains one or more bits from - // the lldb::Permissions - //---------------------------------------------------------------------- - void - SetLLDBPermissions(uint32_t permissions) - { - m_read = (permissions & lldb::ePermissionsReadable) ? eYes : eNo; - m_write = (permissions & lldb::ePermissionsWritable) ? eYes : eNo; - m_execute = (permissions & lldb::ePermissionsExecutable) ? eYes : eNo; - } - - bool - operator == (const MemoryRegionInfo &rhs) const - { - return m_range == rhs.m_range && - m_read == rhs.m_read && - m_write == rhs.m_write && - m_execute == rhs.m_execute && - m_mapped == rhs.m_mapped; - } - - bool - operator != (const MemoryRegionInfo &rhs) const - { - return !(*this == rhs); - } - - protected: - RangeType m_range; - OptionalBool m_read; - OptionalBool m_write; - OptionalBool m_execute; - OptionalBool m_mapped; - }; +namespace lldb_private { +class MemoryRegionInfo { +public: + typedef Range<lldb::addr_t, lldb::addr_t> RangeType; + + enum OptionalBool { eDontKnow = -1, eNo = 0, eYes = 1 }; + + MemoryRegionInfo() + : m_range(), m_read(eDontKnow), m_write(eDontKnow), m_execute(eDontKnow), + m_mapped(eDontKnow) {} + + ~MemoryRegionInfo() {} + + RangeType &GetRange() { return m_range; } + + void Clear() { + m_range.Clear(); + m_read = m_write = m_execute = eDontKnow; + } + + const RangeType &GetRange() const { return m_range; } + + OptionalBool GetReadable() const { return m_read; } + + OptionalBool GetWritable() const { return m_write; } + + OptionalBool GetExecutable() const { return m_execute; } + + OptionalBool GetMapped() const { return m_mapped; } + + const ConstString &GetName() const { return m_name; } + + void SetReadable(OptionalBool val) { m_read = val; } + + void SetWritable(OptionalBool val) { m_write = val; } + + void SetExecutable(OptionalBool val) { m_execute = val; } + + void SetMapped(OptionalBool val) { m_mapped = val; } + + void SetName(const char *name) { m_name = ConstString(name); } + + //---------------------------------------------------------------------- + // Get permissions as a uint32_t that is a mask of one or more bits from + // the lldb::Permissions + //---------------------------------------------------------------------- + uint32_t GetLLDBPermissions() const { + uint32_t permissions = 0; + if (m_read) + permissions |= lldb::ePermissionsReadable; + if (m_write) + permissions |= lldb::ePermissionsWritable; + if (m_execute) + permissions |= lldb::ePermissionsExecutable; + return permissions; + } + + //---------------------------------------------------------------------- + // Set permissions from a uint32_t that contains one or more bits from + // the lldb::Permissions + //---------------------------------------------------------------------- + void SetLLDBPermissions(uint32_t permissions) { + m_read = (permissions & lldb::ePermissionsReadable) ? eYes : eNo; + m_write = (permissions & lldb::ePermissionsWritable) ? eYes : eNo; + m_execute = (permissions & lldb::ePermissionsExecutable) ? eYes : eNo; + } + + bool operator==(const MemoryRegionInfo &rhs) const { + return m_range == rhs.m_range && m_read == rhs.m_read && + m_write == rhs.m_write && m_execute == rhs.m_execute && + m_mapped == rhs.m_mapped; + } + + bool operator!=(const MemoryRegionInfo &rhs) const { return !(*this == rhs); } + +protected: + RangeType m_range; + OptionalBool m_read; + OptionalBool m_write; + OptionalBool m_execute; + OptionalBool m_mapped; + ConstString m_name; +}; } #endif // #ifndef lldb_MemoryRegionInfo_h diff --git a/include/lldb/Target/ObjCLanguageRuntime.h b/include/lldb/Target/ObjCLanguageRuntime.h index 75f096fdedfe..0a9ffa933bd1 100644 --- a/include/lldb/Target/ObjCLanguageRuntime.h +++ b/include/lldb/Target/ObjCLanguageRuntime.h @@ -21,500 +21,404 @@ #include "llvm/Support/Casting.h" // Project includes -#include "lldb/lldb-private.h" #include "lldb/Core/PluginInterface.h" #include "lldb/Core/ThreadSafeDenseMap.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Symbol/DeclVendor.h" #include "lldb/Symbol/Type.h" #include "lldb/Target/LanguageRuntime.h" +#include "lldb/lldb-private.h" class CommandObjectObjC_ClassTable_Dump; namespace lldb_private { - + class UtilityFunction; -class ObjCLanguageRuntime : - public LanguageRuntime -{ +class ObjCLanguageRuntime : public LanguageRuntime { public: - enum class ObjCRuntimeVersions - { - eObjC_VersionUnknown = 0, - eAppleObjC_V1 = 1, - eAppleObjC_V2 = 2 - }; - - typedef lldb::addr_t ObjCISA; - - class ClassDescriptor; - typedef std::shared_ptr<ClassDescriptor> ClassDescriptorSP; - - // the information that we want to support retrieving from an ObjC class - // this needs to be pure virtual since there are at least 2 different implementations - // of the runtime, and more might come - class ClassDescriptor - { - public: - ClassDescriptor() : - m_is_kvo (eLazyBoolCalculate), - m_is_cf (eLazyBoolCalculate), - m_type_wp () - { - } - - virtual - ~ClassDescriptor() = default; - - virtual ConstString - GetClassName () = 0; - - virtual ClassDescriptorSP - GetSuperclass () = 0; - - virtual ClassDescriptorSP - GetMetaclass () const = 0; - - // virtual if any implementation has some other version-specific rules - // but for the known v1/v2 this is all that needs to be done - virtual bool - IsKVO () - { - if (m_is_kvo == eLazyBoolCalculate) - { - const char* class_name = GetClassName().AsCString(); - if (class_name && *class_name) - m_is_kvo = (LazyBool)(strstr(class_name,"NSKVONotifying_") == class_name); - } - return (m_is_kvo == eLazyBoolYes); - } - - // virtual if any implementation has some other version-specific rules - // but for the known v1/v2 this is all that needs to be done - virtual bool - IsCFType () - { - if (m_is_cf == eLazyBoolCalculate) - { - const char* class_name = GetClassName().AsCString(); - if (class_name && *class_name) - m_is_cf = (LazyBool)(strcmp(class_name,"__NSCFType") == 0 || - strcmp(class_name,"NSCFType") == 0); - } - return (m_is_cf == eLazyBoolYes); - } - - virtual bool - IsValid () = 0; - - virtual bool - GetTaggedPointerInfo(uint64_t* info_bits = nullptr, - uint64_t* value_bits = nullptr, - uint64_t* payload = nullptr) = 0; - - virtual uint64_t - GetInstanceSize () = 0; - - // use to implement version-specific additional constraints on pointers - virtual bool - CheckPointer (lldb::addr_t value, - uint32_t ptr_size) const - { - return true; - } - - virtual ObjCISA - GetISA () = 0; - - // This should return true iff the interface could be completed - virtual bool - Describe (std::function <void (ObjCISA)> const &superclass_func, - std::function <bool (const char*, const char*)> const &instance_method_func, - std::function <bool (const char*, const char*)> const &class_method_func, - std::function <bool (const char *, const char *, lldb::addr_t, uint64_t)> const &ivar_func) const - { - return false; - } - - lldb::TypeSP - GetType () - { - return m_type_wp.lock(); - } - - void - SetType (const lldb::TypeSP &type_sp) - { - m_type_wp = type_sp; - } - - struct iVarDescriptor { - ConstString m_name; - CompilerType m_type; - uint64_t m_size; - int32_t m_offset; - }; - - virtual size_t - GetNumIVars () - { - return 0; - } - - virtual iVarDescriptor - GetIVarAtIndex (size_t idx) - { - return iVarDescriptor(); - } - - protected: - bool - IsPointerValid (lldb::addr_t value, - uint32_t ptr_size, - bool allow_NULLs = false, - bool allow_tagged = false, - bool check_version_specific = false) const; - - private: - LazyBool m_is_kvo; - LazyBool m_is_cf; - lldb::TypeWP m_type_wp; - }; - - class EncodingToType - { - public: - virtual ~EncodingToType(); - - virtual CompilerType RealizeType (ClangASTContext& ast_ctx, const char* name, bool for_expression); - virtual CompilerType RealizeType (const char* name, bool for_expression); - - virtual CompilerType RealizeType (clang::ASTContext& ast_ctx, const char* name, bool for_expression) = 0; - - protected: - std::unique_ptr<ClangASTContext> m_scratch_ast_ctx_ap; - }; + enum class ObjCRuntimeVersions { + eObjC_VersionUnknown = 0, + eAppleObjC_V1 = 1, + eAppleObjC_V2 = 2 + }; + + typedef lldb::addr_t ObjCISA; + + class ClassDescriptor; + typedef std::shared_ptr<ClassDescriptor> ClassDescriptorSP; + + // the information that we want to support retrieving from an ObjC class + // this needs to be pure virtual since there are at least 2 different + // implementations + // of the runtime, and more might come + class ClassDescriptor { + public: + ClassDescriptor() + : m_is_kvo(eLazyBoolCalculate), m_is_cf(eLazyBoolCalculate), + m_type_wp() {} + + virtual ~ClassDescriptor() = default; + + virtual ConstString GetClassName() = 0; + + virtual ClassDescriptorSP GetSuperclass() = 0; + + virtual ClassDescriptorSP GetMetaclass() const = 0; + + // virtual if any implementation has some other version-specific rules + // but for the known v1/v2 this is all that needs to be done + virtual bool IsKVO() { + if (m_is_kvo == eLazyBoolCalculate) { + const char *class_name = GetClassName().AsCString(); + if (class_name && *class_name) + m_is_kvo = + (LazyBool)(strstr(class_name, "NSKVONotifying_") == class_name); + } + return (m_is_kvo == eLazyBoolYes); + } - class ObjCExceptionPrecondition : public Breakpoint::BreakpointPrecondition - { - public: - ObjCExceptionPrecondition(); + // virtual if any implementation has some other version-specific rules + // but for the known v1/v2 this is all that needs to be done + virtual bool IsCFType() { + if (m_is_cf == eLazyBoolCalculate) { + const char *class_name = GetClassName().AsCString(); + if (class_name && *class_name) + m_is_cf = (LazyBool)(strcmp(class_name, "__NSCFType") == 0 || + strcmp(class_name, "NSCFType") == 0); + } + return (m_is_cf == eLazyBoolYes); + } - ~ObjCExceptionPrecondition() override = default; + virtual bool IsValid() = 0; - bool EvaluatePrecondition(StoppointCallbackContext &context) override; - void GetDescription(Stream &stream, lldb::DescriptionLevel level) override; - Error ConfigurePrecondition(Args &args) override; + virtual bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr, + uint64_t *value_bits = nullptr, + uint64_t *payload = nullptr) = 0; - protected: - void AddClassName(const char *class_name); + virtual uint64_t GetInstanceSize() = 0; - private: - std::unordered_set<std::string> m_class_names; - }; - - class TaggedPointerVendor - { - public: - virtual - ~TaggedPointerVendor() = default; + // use to implement version-specific additional constraints on pointers + virtual bool CheckPointer(lldb::addr_t value, uint32_t ptr_size) const { + return true; + } + + virtual ObjCISA GetISA() = 0; - virtual bool - IsPossibleTaggedPointer (lldb::addr_t ptr) = 0; - - virtual ObjCLanguageRuntime::ClassDescriptorSP - GetClassDescriptor (lldb::addr_t ptr) = 0; + // This should return true iff the interface could be completed + virtual bool + Describe(std::function<void(ObjCISA)> const &superclass_func, + std::function<bool(const char *, const char *)> const + &instance_method_func, + std::function<bool(const char *, const char *)> const + &class_method_func, + std::function<bool(const char *, const char *, lldb::addr_t, + uint64_t)> const &ivar_func) const { + return false; + } - protected: - TaggedPointerVendor() = default; + lldb::TypeSP GetType() { return m_type_wp.lock(); } - private: - DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendor); + void SetType(const lldb::TypeSP &type_sp) { m_type_wp = type_sp; } + + struct iVarDescriptor { + ConstString m_name; + CompilerType m_type; + uint64_t m_size; + int32_t m_offset; }; - - ~ObjCLanguageRuntime() override; - virtual TaggedPointerVendor* - GetTaggedPointerVendor () - { - return nullptr; - } - - typedef std::shared_ptr<EncodingToType> EncodingToTypeSP; - - virtual EncodingToTypeSP - GetEncodingToType (); - - virtual ClassDescriptorSP - GetClassDescriptor (ValueObject& in_value); - - ClassDescriptorSP - GetNonKVOClassDescriptor (ValueObject& in_value); - - virtual ClassDescriptorSP - GetClassDescriptorFromClassName (const ConstString &class_name); - - virtual ClassDescriptorSP - GetClassDescriptorFromISA (ObjCISA isa); - - ClassDescriptorSP - GetNonKVOClassDescriptor (ObjCISA isa); - - lldb::LanguageType - GetLanguageType () const override - { - return lldb::eLanguageTypeObjC; - } - - virtual bool - IsModuleObjCLibrary (const lldb::ModuleSP &module_sp) = 0; - - virtual bool - ReadObjCLibrary (const lldb::ModuleSP &module_sp) = 0; - - virtual bool - HasReadObjCLibrary () = 0; - - virtual lldb::ThreadPlanSP - GetStepThroughTrampolinePlan (Thread &thread, bool stop_others) = 0; - - lldb::addr_t - LookupInMethodCache (lldb::addr_t class_addr, lldb::addr_t sel); - - void - AddToMethodCache (lldb::addr_t class_addr, lldb::addr_t sel, lldb::addr_t impl_addr); - - TypeAndOrName - LookupInClassNameCache (lldb::addr_t class_addr); - - void - AddToClassNameCache (lldb::addr_t class_addr, const char *name, lldb::TypeSP type_sp); - - void - AddToClassNameCache (lldb::addr_t class_addr, const TypeAndOrName &class_or_type_name); - - lldb::TypeSP - LookupInCompleteClassCache (ConstString &name); - - virtual UtilityFunction * - CreateObjectChecker (const char *) = 0; - - virtual ObjCRuntimeVersions - GetRuntimeVersion () const - { - return ObjCRuntimeVersions::eObjC_VersionUnknown; - } - - bool - IsValidISA(ObjCISA isa) - { - UpdateISAToDescriptorMap(); - return m_isa_to_descriptor.count(isa) > 0; + virtual size_t GetNumIVars() { return 0; } + + virtual iVarDescriptor GetIVarAtIndex(size_t idx) { + return iVarDescriptor(); } - virtual void - UpdateISAToDescriptorMapIfNeeded() = 0; + protected: + bool IsPointerValid(lldb::addr_t value, uint32_t ptr_size, + bool allow_NULLs = false, bool allow_tagged = false, + bool check_version_specific = false) const; - void - UpdateISAToDescriptorMap() - { - if (m_process && m_process->GetStopID() != m_isa_to_descriptor_stop_id) - { - UpdateISAToDescriptorMapIfNeeded (); - } - } - - virtual ObjCISA - GetISA(const ConstString &name); - - virtual ConstString - GetActualTypeName(ObjCISA isa); - - virtual ObjCISA - GetParentClass(ObjCISA isa); - - virtual DeclVendor * - GetDeclVendor() - { - return nullptr; - } - - // Finds the byte offset of the child_type ivar in parent_type. If it can't find the - // offset, returns LLDB_INVALID_IVAR_OFFSET. - - virtual size_t - GetByteOffsetForIvar (CompilerType &parent_qual_type, const char *ivar_name); - - // Given the name of an Objective-C runtime symbol (e.g., ivar offset symbol), - // try to determine from the runtime what the value of that symbol would be. - // Useful when the underlying binary is stripped. - virtual lldb::addr_t - LookupRuntimeSymbol (const ConstString &name) - { - return LLDB_INVALID_ADDRESS; - } - - bool - HasNewLiteralsAndIndexing () - { - if (m_has_new_literals_and_indexing == eLazyBoolCalculate) - { - if (CalculateHasNewLiteralsAndIndexing()) - m_has_new_literals_and_indexing = eLazyBoolYes; - else - m_has_new_literals_and_indexing = eLazyBoolNo; - } - - return (m_has_new_literals_and_indexing == eLazyBoolYes); + private: + LazyBool m_is_kvo; + LazyBool m_is_cf; + lldb::TypeWP m_type_wp; + }; + + class EncodingToType { + public: + virtual ~EncodingToType(); + + virtual CompilerType RealizeType(ClangASTContext &ast_ctx, const char *name, + bool for_expression); + virtual CompilerType RealizeType(const char *name, bool for_expression); + + virtual CompilerType RealizeType(clang::ASTContext &ast_ctx, + const char *name, bool for_expression) = 0; + + protected: + std::unique_ptr<ClangASTContext> m_scratch_ast_ctx_ap; + }; + + class ObjCExceptionPrecondition : public Breakpoint::BreakpointPrecondition { + public: + ObjCExceptionPrecondition(); + + ~ObjCExceptionPrecondition() override = default; + + bool EvaluatePrecondition(StoppointCallbackContext &context) override; + void GetDescription(Stream &stream, lldb::DescriptionLevel level) override; + Error ConfigurePrecondition(Args &args) override; + + protected: + void AddClassName(const char *class_name); + + private: + std::unordered_set<std::string> m_class_names; + }; + + class TaggedPointerVendor { + public: + virtual ~TaggedPointerVendor() = default; + + virtual bool IsPossibleTaggedPointer(lldb::addr_t ptr) = 0; + + virtual ObjCLanguageRuntime::ClassDescriptorSP + GetClassDescriptor(lldb::addr_t ptr) = 0; + + protected: + TaggedPointerVendor() = default; + + private: + DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendor); + }; + + ~ObjCLanguageRuntime() override; + + virtual TaggedPointerVendor *GetTaggedPointerVendor() { return nullptr; } + + typedef std::shared_ptr<EncodingToType> EncodingToTypeSP; + + virtual EncodingToTypeSP GetEncodingToType(); + + virtual ClassDescriptorSP GetClassDescriptor(ValueObject &in_value); + + ClassDescriptorSP GetNonKVOClassDescriptor(ValueObject &in_value); + + virtual ClassDescriptorSP + GetClassDescriptorFromClassName(const ConstString &class_name); + + virtual ClassDescriptorSP GetClassDescriptorFromISA(ObjCISA isa); + + ClassDescriptorSP GetNonKVOClassDescriptor(ObjCISA isa); + + lldb::LanguageType GetLanguageType() const override { + return lldb::eLanguageTypeObjC; + } + + virtual bool IsModuleObjCLibrary(const lldb::ModuleSP &module_sp) = 0; + + virtual bool ReadObjCLibrary(const lldb::ModuleSP &module_sp) = 0; + + virtual bool HasReadObjCLibrary() = 0; + + virtual lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread, + bool stop_others) = 0; + + lldb::addr_t LookupInMethodCache(lldb::addr_t class_addr, lldb::addr_t sel); + + void AddToMethodCache(lldb::addr_t class_addr, lldb::addr_t sel, + lldb::addr_t impl_addr); + + TypeAndOrName LookupInClassNameCache(lldb::addr_t class_addr); + + void AddToClassNameCache(lldb::addr_t class_addr, const char *name, + lldb::TypeSP type_sp); + + void AddToClassNameCache(lldb::addr_t class_addr, + const TypeAndOrName &class_or_type_name); + + lldb::TypeSP LookupInCompleteClassCache(ConstString &name); + + virtual UtilityFunction *CreateObjectChecker(const char *) = 0; + + virtual ObjCRuntimeVersions GetRuntimeVersion() const { + return ObjCRuntimeVersions::eObjC_VersionUnknown; + } + + bool IsValidISA(ObjCISA isa) { + UpdateISAToDescriptorMap(); + return m_isa_to_descriptor.count(isa) > 0; + } + + virtual void UpdateISAToDescriptorMapIfNeeded() = 0; + + void UpdateISAToDescriptorMap() { + if (m_process && m_process->GetStopID() != m_isa_to_descriptor_stop_id) { + UpdateISAToDescriptorMapIfNeeded(); } - - virtual void - SymbolsDidLoad (const ModuleList& module_list) - { - m_negative_complete_class_cache.clear(); + } + + virtual ObjCISA GetISA(const ConstString &name); + + virtual ConstString GetActualTypeName(ObjCISA isa); + + virtual ObjCISA GetParentClass(ObjCISA isa); + + virtual DeclVendor *GetDeclVendor() { return nullptr; } + + // Finds the byte offset of the child_type ivar in parent_type. If it can't + // find the + // offset, returns LLDB_INVALID_IVAR_OFFSET. + + virtual size_t GetByteOffsetForIvar(CompilerType &parent_qual_type, + const char *ivar_name); + + // Given the name of an Objective-C runtime symbol (e.g., ivar offset symbol), + // try to determine from the runtime what the value of that symbol would be. + // Useful when the underlying binary is stripped. + virtual lldb::addr_t LookupRuntimeSymbol(const ConstString &name) { + return LLDB_INVALID_ADDRESS; + } + + bool HasNewLiteralsAndIndexing() { + if (m_has_new_literals_and_indexing == eLazyBoolCalculate) { + if (CalculateHasNewLiteralsAndIndexing()) + m_has_new_literals_and_indexing = eLazyBoolYes; + else + m_has_new_literals_and_indexing = eLazyBoolNo; } - - bool - GetTypeBitSize (const CompilerType& compiler_type, - uint64_t &size) override; + + return (m_has_new_literals_and_indexing == eLazyBoolYes); + } + + virtual void SymbolsDidLoad(const ModuleList &module_list) { + m_negative_complete_class_cache.clear(); + } + + bool GetTypeBitSize(const CompilerType &compiler_type, + uint64_t &size) override; protected: - //------------------------------------------------------------------ - // Classes that inherit from ObjCLanguageRuntime can see and modify these - //------------------------------------------------------------------ - ObjCLanguageRuntime(Process *process); + //------------------------------------------------------------------ + // Classes that inherit from ObjCLanguageRuntime can see and modify these + //------------------------------------------------------------------ + ObjCLanguageRuntime(Process *process); - virtual bool CalculateHasNewLiteralsAndIndexing() - { - return false; + virtual bool CalculateHasNewLiteralsAndIndexing() { return false; } + + bool ISAIsCached(ObjCISA isa) const { + return m_isa_to_descriptor.find(isa) != m_isa_to_descriptor.end(); + } + + bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp) { + if (isa != 0) { + m_isa_to_descriptor[isa] = descriptor_sp; + return true; } - - bool - ISAIsCached (ObjCISA isa) const - { - return m_isa_to_descriptor.find(isa) != m_isa_to_descriptor.end(); + return false; + } + + bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp, + const char *class_name); + + bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp, + uint32_t class_name_hash) { + if (isa != 0) { + m_isa_to_descriptor[isa] = descriptor_sp; + m_hash_to_isa_map.insert(std::make_pair(class_name_hash, isa)); + return true; } + return false; + } - bool - AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp) - { - if (isa != 0) - { - m_isa_to_descriptor[isa] = descriptor_sp; - return true; - } - return false; +private: + // We keep a map of <Class,Selector>->Implementation so we don't have to call + // the resolver + // function over and over. + + // FIXME: We need to watch for the loading of Protocols, and flush the cache + // for any + // class that we see so changed. + + struct ClassAndSel { + ClassAndSel() { + sel_addr = LLDB_INVALID_ADDRESS; + class_addr = LLDB_INVALID_ADDRESS; } - bool - AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp, const char *class_name); + ClassAndSel(lldb::addr_t in_sel_addr, lldb::addr_t in_class_addr) + : class_addr(in_class_addr), sel_addr(in_sel_addr) {} - bool - AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp, uint32_t class_name_hash) - { - if (isa != 0) - { - m_isa_to_descriptor[isa] = descriptor_sp; - m_hash_to_isa_map.insert(std::make_pair(class_name_hash, isa)); - return true; - } + bool operator==(const ClassAndSel &rhs) { + if (class_addr == rhs.class_addr && sel_addr == rhs.sel_addr) + return true; + else return false; } -private: - // We keep a map of <Class,Selector>->Implementation so we don't have to call the resolver - // function over and over. - - // FIXME: We need to watch for the loading of Protocols, and flush the cache for any - // class that we see so changed. - - struct ClassAndSel - { - ClassAndSel() - { - sel_addr = LLDB_INVALID_ADDRESS; - class_addr = LLDB_INVALID_ADDRESS; - } - - ClassAndSel (lldb::addr_t in_sel_addr, lldb::addr_t in_class_addr) : - class_addr (in_class_addr), - sel_addr(in_sel_addr) - { - } - - bool operator== (const ClassAndSel &rhs) - { - if (class_addr == rhs.class_addr - && sel_addr == rhs.sel_addr) - return true; - else - return false; - } - - bool operator< (const ClassAndSel &rhs) const - { - if (class_addr < rhs.class_addr) - return true; - else if (class_addr > rhs.class_addr) - return false; - else - { - if (sel_addr < rhs.sel_addr) - return true; - else - return false; - } - } - - lldb::addr_t class_addr; - lldb::addr_t sel_addr; - }; + bool operator<(const ClassAndSel &rhs) const { + if (class_addr < rhs.class_addr) + return true; + else if (class_addr > rhs.class_addr) + return false; + else { + if (sel_addr < rhs.sel_addr) + return true; + else + return false; + } + } + + lldb::addr_t class_addr; + lldb::addr_t sel_addr; + }; - typedef std::map<ClassAndSel,lldb::addr_t> MsgImplMap; - typedef std::map<ObjCISA, ClassDescriptorSP> ISAToDescriptorMap; - typedef std::multimap<uint32_t, ObjCISA> HashToISAMap; - typedef ISAToDescriptorMap::iterator ISAToDescriptorIterator; - typedef HashToISAMap::iterator HashToISAIterator; - typedef ThreadSafeDenseMap<void*, uint64_t> TypeSizeCache; + typedef std::map<ClassAndSel, lldb::addr_t> MsgImplMap; + typedef std::map<ObjCISA, ClassDescriptorSP> ISAToDescriptorMap; + typedef std::multimap<uint32_t, ObjCISA> HashToISAMap; + typedef ISAToDescriptorMap::iterator ISAToDescriptorIterator; + typedef HashToISAMap::iterator HashToISAIterator; + typedef ThreadSafeDenseMap<void *, uint64_t> TypeSizeCache; - MsgImplMap m_impl_cache; - LazyBool m_has_new_literals_and_indexing; - ISAToDescriptorMap m_isa_to_descriptor; - HashToISAMap m_hash_to_isa_map; - TypeSizeCache m_type_size_cache; + MsgImplMap m_impl_cache; + LazyBool m_has_new_literals_and_indexing; + ISAToDescriptorMap m_isa_to_descriptor; + HashToISAMap m_hash_to_isa_map; + TypeSizeCache m_type_size_cache; protected: - uint32_t m_isa_to_descriptor_stop_id; - - typedef std::map<ConstString, lldb::TypeWP> CompleteClassMap; - CompleteClassMap m_complete_class_cache; - - struct ConstStringSetHelpers { - size_t operator () (const ConstString& arg) const // for hashing - { - return (size_t)arg.GetCString(); - } - bool operator () (const ConstString& arg1, const ConstString& arg2) const // for equality - { - return arg1.operator==(arg2); - } - }; - typedef std::unordered_set<ConstString, ConstStringSetHelpers, ConstStringSetHelpers> CompleteClassSet; - CompleteClassSet m_negative_complete_class_cache; + uint32_t m_isa_to_descriptor_stop_id; + + typedef std::map<ConstString, lldb::TypeWP> CompleteClassMap; + CompleteClassMap m_complete_class_cache; + + struct ConstStringSetHelpers { + size_t operator()(const ConstString &arg) const // for hashing + { + return (size_t)arg.GetCString(); + } + bool operator()(const ConstString &arg1, + const ConstString &arg2) const // for equality + { + return arg1.operator==(arg2); + } + }; + typedef std::unordered_set<ConstString, ConstStringSetHelpers, + ConstStringSetHelpers> + CompleteClassSet; + CompleteClassSet m_negative_complete_class_cache; + + ISAToDescriptorIterator GetDescriptorIterator(const ConstString &name); - ISAToDescriptorIterator - GetDescriptorIterator (const ConstString &name); + friend class ::CommandObjectObjC_ClassTable_Dump; - friend class ::CommandObjectObjC_ClassTable_Dump; - - std::pair<ISAToDescriptorIterator,ISAToDescriptorIterator> - GetDescriptorIteratorPair (bool update_if_needed = true); + std::pair<ISAToDescriptorIterator, ISAToDescriptorIterator> + GetDescriptorIteratorPair(bool update_if_needed = true); - void - ReadObjCLibraryIfNeeded (const ModuleList &module_list); + void ReadObjCLibraryIfNeeded(const ModuleList &module_list); - DISALLOW_COPY_AND_ASSIGN (ObjCLanguageRuntime); + DISALLOW_COPY_AND_ASSIGN(ObjCLanguageRuntime); }; } // namespace lldb_private diff --git a/include/lldb/Target/OperatingSystem.h b/include/lldb/Target/OperatingSystem.h index 74de5645da5a..24ded3f69723 100644 --- a/include/lldb/Target/OperatingSystem.h +++ b/include/lldb/Target/OperatingSystem.h @@ -1,4 +1,5 @@ -//===-- OperatingSystem.h ----------------------------------------------*- C++ -*-===// +//===-- OperatingSystem.h ----------------------------------------------*- C++ +//-*-===// // // The LLVM Compiler Infrastructure // @@ -14,84 +15,77 @@ // C++ Includes // Other libraries and framework includes -#include "lldb/lldb-private.h" #include "lldb/Core/PluginInterface.h" +#include "lldb/lldb-private.h" namespace lldb_private { - + //---------------------------------------------------------------------- /// @class OperatingSystem OperatingSystem.h "lldb/Target/OperatingSystem.h" /// @brief A plug-in interface definition class for halted OS helpers. /// -/// Halted OS plug-ins can be used by any process to locate and create -/// OS objects, like threads, during the lifetime of a debug session. +/// Halted OS plug-ins can be used by any process to locate and create +/// OS objects, like threads, during the lifetime of a debug session. /// This is commonly used when attaching to an operating system that is /// halted, such as when debugging over JTAG or connecting to low level /// kernel debug services. //---------------------------------------------------------------------- -class OperatingSystem : - public PluginInterface -{ +class OperatingSystem : public PluginInterface { public: - //------------------------------------------------------------------ - /// Find a halted OS plugin for a given process. - /// - /// Scans the installed OperatingSystem plug-ins and tries to find - /// an instance that matches the current target triple and - /// executable. - /// - /// @param[in] process - /// The process for which to try and locate a halted OS - /// plug-in instance. - /// - /// @param[in] plugin_name - /// An optional name of a specific halted OS plug-in that - /// should be used. If NULL, pick the best plug-in. - //------------------------------------------------------------------ - static OperatingSystem* - FindPlugin (Process *process, const char *plugin_name); - - //------------------------------------------------------------------ - // Class Methods - //------------------------------------------------------------------ - OperatingSystem (Process *process); - - ~OperatingSystem() override; - - //------------------------------------------------------------------ - // Plug-in Methods - //------------------------------------------------------------------ - virtual bool - UpdateThreadList (ThreadList &old_thread_list, - ThreadList &real_thread_list, - ThreadList &new_thread_list) = 0; - - virtual void - ThreadWasSelected (Thread *thread) = 0; - - virtual lldb::RegisterContextSP - CreateRegisterContextForThread (Thread *thread, lldb::addr_t reg_data_addr) = 0; - - virtual lldb::StopInfoSP - CreateThreadStopReason (Thread *thread) = 0; - - virtual lldb::ThreadSP - CreateThread (lldb::tid_t tid, lldb::addr_t context) - { - return lldb::ThreadSP(); - } - - virtual bool - IsOperatingSystemPluginThread (const lldb::ThreadSP &thread_sp); + //------------------------------------------------------------------ + /// Find a halted OS plugin for a given process. + /// + /// Scans the installed OperatingSystem plug-ins and tries to find + /// an instance that matches the current target triple and + /// executable. + /// + /// @param[in] process + /// The process for which to try and locate a halted OS + /// plug-in instance. + /// + /// @param[in] plugin_name + /// An optional name of a specific halted OS plug-in that + /// should be used. If NULL, pick the best plug-in. + //------------------------------------------------------------------ + static OperatingSystem *FindPlugin(Process *process, const char *plugin_name); + + //------------------------------------------------------------------ + // Class Methods + //------------------------------------------------------------------ + OperatingSystem(Process *process); + + ~OperatingSystem() override; + + //------------------------------------------------------------------ + // Plug-in Methods + //------------------------------------------------------------------ + virtual bool UpdateThreadList(ThreadList &old_thread_list, + ThreadList &real_thread_list, + ThreadList &new_thread_list) = 0; + + virtual void ThreadWasSelected(Thread *thread) = 0; + + virtual lldb::RegisterContextSP + CreateRegisterContextForThread(Thread *thread, + lldb::addr_t reg_data_addr) = 0; + + virtual lldb::StopInfoSP CreateThreadStopReason(Thread *thread) = 0; + + virtual lldb::ThreadSP CreateThread(lldb::tid_t tid, lldb::addr_t context) { + return lldb::ThreadSP(); + } + + virtual bool IsOperatingSystemPluginThread(const lldb::ThreadSP &thread_sp); protected: - //------------------------------------------------------------------ - // Member variables. - //------------------------------------------------------------------ - Process* m_process; ///< The process that this dynamic loader plug-in is tracking. + //------------------------------------------------------------------ + // Member variables. + //------------------------------------------------------------------ + Process + *m_process; ///< The process that this dynamic loader plug-in is tracking. private: - DISALLOW_COPY_AND_ASSIGN (OperatingSystem); + DISALLOW_COPY_AND_ASSIGN(OperatingSystem); }; } // namespace lldb_private diff --git a/include/lldb/Target/PathMappingList.h b/include/lldb/Target/PathMappingList.h index 1a486c4642dc..4e5a5693235a 100644 --- a/include/lldb/Target/PathMappingList.h +++ b/include/lldb/Target/PathMappingList.h @@ -21,153 +21,119 @@ namespace lldb_private { -class PathMappingList -{ +class PathMappingList { public: + typedef void (*ChangedCallback)(const PathMappingList &path_list, + void *baton); + + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + PathMappingList(); + + PathMappingList(ChangedCallback callback, void *callback_baton); + + PathMappingList(const PathMappingList &rhs); + + ~PathMappingList(); + + const PathMappingList &operator=(const PathMappingList &rhs); + + void Append(const ConstString &path, const ConstString &replacement, + bool notify); + + void Append(const PathMappingList &rhs, bool notify); + + void Clear(bool notify); + + // By default, dump all pairs. + void Dump(Stream *s, int pair_index = -1); + + bool IsEmpty() const { return m_pairs.empty(); } + + size_t GetSize() const { return m_pairs.size(); } + + bool GetPathsAtIndex(uint32_t idx, ConstString &path, + ConstString &new_path) const; + + void Insert(const ConstString &path, const ConstString &replacement, + uint32_t insert_idx, bool notify); + + bool Remove(size_t index, bool notify); + + bool Remove(const ConstString &path, bool notify); + + bool Replace(const ConstString &path, const ConstString &replacement, + bool notify); + + bool Replace(const ConstString &path, const ConstString &replacement, + uint32_t index, bool notify); + bool RemapPath(const ConstString &path, ConstString &new_path) const; + + //------------------------------------------------------------------ + /// Remaps a source file given \a path into \a new_path. + /// + /// Remaps \a path if any source remappings match. This function + /// does NOT stat the file system so it can be used in tight loops + /// where debug info is being parsed. + /// + /// @param[in] path + /// The original source file path to try and remap. + /// + /// @param[out] new_path + /// The newly remapped filespec that is may or may not exist. + /// + /// @return + /// /b true if \a path was successfully located and \a new_path + /// is filled in with a new source path, \b false otherwise. + //------------------------------------------------------------------ + bool RemapPath(llvm::StringRef path, std::string &new_path) const; + bool RemapPath(const char *, std::string &) const = delete; + + bool ReverseRemapPath(const ConstString &path, ConstString &new_path) const; + + //------------------------------------------------------------------ + /// Finds a source file given a file spec using the path remappings. + /// + /// Tries to resolve \a orig_spec by checking the path remappings. + /// It makes sure the file exists by checking with the file system, + /// so this call can be expensive if the remappings are on a network + /// or are even on the local file system, so use this function + /// sparingly (not in a tight debug info parsing loop). + /// + /// @param[in] orig_spec + /// The original source file path to try and remap. + /// + /// @param[out] new_spec + /// The newly remapped filespec that is guaranteed to exist. + /// + /// @return + /// /b true if \a orig_spec was successfully located and + /// \a new_spec is filled in with an existing file spec, + /// \b false otherwise. + //------------------------------------------------------------------ + bool FindFile(const FileSpec &orig_spec, FileSpec &new_spec) const; + + uint32_t FindIndexForPath(const ConstString &path) const; + + uint32_t GetModificationID() const { return m_mod_id; } - typedef void (*ChangedCallback) (const PathMappingList &path_list, - void *baton); - - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - PathMappingList (); - - PathMappingList (ChangedCallback callback, - void *callback_baton); - - PathMappingList (const PathMappingList &rhs); - - ~PathMappingList (); - - const PathMappingList & - operator =(const PathMappingList &rhs); - - void - Append (const ConstString &path, const ConstString &replacement, bool notify); - - void - Append (const PathMappingList &rhs, bool notify); - - void - Clear (bool notify); - - // By default, dump all pairs. - void - Dump (Stream *s, int pair_index=-1); - - bool - IsEmpty() const - { - return m_pairs.empty(); - } - - size_t - GetSize () const - { - return m_pairs.size(); - } - - bool - GetPathsAtIndex (uint32_t idx, ConstString &path, ConstString &new_path) const; - - void - Insert (const ConstString &path, - const ConstString &replacement, - uint32_t insert_idx, - bool notify); - - bool - Remove (size_t index, bool notify); - - bool - Remove (const ConstString &path, bool notify); - - bool - Replace (const ConstString &path, - const ConstString &replacement, - bool notify); - - bool - Replace (const ConstString &path, - const ConstString &replacement, - uint32_t index, - bool notify); - bool - RemapPath (const ConstString &path, ConstString &new_path) const; - - //------------------------------------------------------------------ - /// Remaps a source file given \a path into \a new_path. - /// - /// Remaps \a path if any source remappings match. This function - /// does NOT stat the file system so it can be used in tight loops - /// where debug info is being parsed. - /// - /// @param[in] path - /// The original source file path to try and remap. - /// - /// @param[out] new_path - /// The newly remapped filespec that is may or may not exist. - /// - /// @return - /// /b true if \a path was successfully located and \a new_path - /// is filled in with a new source path, \b false otherwise. - //------------------------------------------------------------------ - bool - RemapPath (const char *path, std::string &new_path) const; - - bool - ReverseRemapPath (const ConstString &path, ConstString &new_path) const; - - //------------------------------------------------------------------ - /// Finds a source file given a file spec using the path remappings. - /// - /// Tries to resolve \a orig_spec by checking the path remappings. - /// It makes sure the file exists by checking with the file system, - /// so this call can be expensive if the remappings are on a network - /// or are even on the local file system, so use this function - /// sparingly (not in a tight debug info parsing loop). - /// - /// @param[in] orig_spec - /// The original source file path to try and remap. - /// - /// @param[out] new_spec - /// The newly remapped filespec that is guaranteed to exist. - /// - /// @return - /// /b true if \a orig_spec was successfully located and - /// \a new_spec is filled in with an existing file spec, - /// \b false otherwise. - //------------------------------------------------------------------ - bool - FindFile (const FileSpec &orig_spec, FileSpec &new_spec) const; - - uint32_t - FindIndexForPath (const ConstString &path) const; - - uint32_t - GetModificationID() const - { - return m_mod_id; - } protected: - typedef std::pair <ConstString, ConstString> pair; - typedef std::vector <pair> collection; - typedef collection::iterator iterator; - typedef collection::const_iterator const_iterator; - - iterator - FindIteratorForPath (const ConstString &path); - - const_iterator - FindIteratorForPath (const ConstString &path) const; - - collection m_pairs; - ChangedCallback m_callback; - void * m_callback_baton; - uint32_t m_mod_id; // Incremented anytime anything is added or removed. + typedef std::pair<ConstString, ConstString> pair; + typedef std::vector<pair> collection; + typedef collection::iterator iterator; + typedef collection::const_iterator const_iterator; + + iterator FindIteratorForPath(const ConstString &path); + + const_iterator FindIteratorForPath(const ConstString &path) const; + + collection m_pairs; + ChangedCallback m_callback; + void *m_callback_baton; + uint32_t m_mod_id; // Incremented anytime anything is added or removed. }; } // namespace lldb_private -#endif // liblldb_PathMappingList_h_ +#endif // liblldb_PathMappingList_h_ diff --git a/include/lldb/Target/Platform.h b/include/lldb/Target/Platform.h index 6fdd92db5680..9707093440a5 100644 --- a/include/lldb/Target/Platform.h +++ b/include/lldb/Target/Platform.h @@ -21,14 +21,14 @@ // Other libraries and framework includes // Project includes -#include "lldb/lldb-private-forward.h" -#include "lldb/lldb-public.h" #include "lldb/Core/ArchSpec.h" #include "lldb/Core/ConstString.h" #include "lldb/Core/PluginInterface.h" #include "lldb/Core/UserSettingsController.h" -#include "lldb/Interpreter/Options.h" #include "lldb/Host/FileSpec.h" +#include "lldb/Interpreter/Options.h" +#include "lldb/lldb-private-forward.h" +#include "lldb/lldb-public.h" // TODO pull NativeDelegate class out of NativeProcessProtocol so we // can just forward ref the NativeDelegate rather than include it here. @@ -37,1390 +37,1133 @@ namespace lldb_private { class ModuleCache; - enum MmapFlags { - eMmapFlagsPrivate = 1, - eMmapFlagsAnon = 2 - }; +enum MmapFlags { eMmapFlagsPrivate = 1, eMmapFlagsAnon = 2 }; + +class PlatformProperties : public Properties { +public: + PlatformProperties(); + + static ConstString GetSettingName(); + + bool GetUseModuleCache() const; + bool SetUseModuleCache(bool use_module_cache); + + FileSpec GetModuleCacheDirectory() const; + bool SetModuleCacheDirectory(const FileSpec &dir_spec); +}; + +typedef std::shared_ptr<PlatformProperties> PlatformPropertiesSP; + +//---------------------------------------------------------------------- +/// @class Platform Platform.h "lldb/Target/Platform.h" +/// @brief A plug-in interface definition class for debug platform that +/// includes many platform abilities such as: +/// @li getting platform information such as supported architectures, +/// supported binary file formats and more +/// @li launching new processes +/// @li attaching to existing processes +/// @li download/upload files +/// @li execute shell commands +/// @li listing and getting info for existing processes +/// @li attaching and possibly debugging the platform's kernel +//---------------------------------------------------------------------- +class Platform : public PluginInterface { +public: + //------------------------------------------------------------------ + /// Default Constructor + //------------------------------------------------------------------ + Platform(bool is_host_platform); + + //------------------------------------------------------------------ + /// Destructor. + /// + /// The destructor is virtual since this class is designed to be + /// inherited from by the plug-in instance. + //------------------------------------------------------------------ + ~Platform() override; + + static void Initialize(); + + static void Terminate(); + + static const PlatformPropertiesSP &GetGlobalPlatformProperties(); + + //------------------------------------------------------------------ + /// Get the native host platform plug-in. + /// + /// There should only be one of these for each host that LLDB runs + /// upon that should be statically compiled in and registered using + /// preprocessor macros or other similar build mechanisms in a + /// PlatformSubclass::Initialize() function. + /// + /// This platform will be used as the default platform when launching + /// or attaching to processes unless another platform is specified. + //------------------------------------------------------------------ + static lldb::PlatformSP GetHostPlatform(); + + static lldb::PlatformSP + GetPlatformForArchitecture(const ArchSpec &arch, ArchSpec *platform_arch_ptr); + + static const char *GetHostPlatformName(); + + static void SetHostPlatform(const lldb::PlatformSP &platform_sp); + + // Find an existing platform plug-in by name + static lldb::PlatformSP Find(const ConstString &name); + + static lldb::PlatformSP Create(const ConstString &name, Error &error); + + static lldb::PlatformSP Create(const ArchSpec &arch, + ArchSpec *platform_arch_ptr, Error &error); + + static uint32_t GetNumConnectedRemotePlatforms(); + + static lldb::PlatformSP GetConnectedRemotePlatformAtIndex(uint32_t idx); + + //------------------------------------------------------------------ + /// Find a platform plugin for a given process. + /// + /// Scans the installed Platform plug-ins and tries to find + /// an instance that can be used for \a process + /// + /// @param[in] process + /// The process for which to try and locate a platform + /// plug-in instance. + /// + /// @param[in] plugin_name + /// An optional name of a specific platform plug-in that + /// should be used. If nullptr, pick the best plug-in. + //------------------------------------------------------------------ + // static lldb::PlatformSP + // FindPlugin (Process *process, const ConstString &plugin_name); + + //------------------------------------------------------------------ + /// Set the target's executable based off of the existing + /// architecture information in \a target given a path to an + /// executable \a exe_file. + /// + /// Each platform knows the architectures that it supports and can + /// select the correct architecture slice within \a exe_file by + /// inspecting the architecture in \a target. If the target had an + /// architecture specified, then in can try and obey that request + /// and optionally fail if the architecture doesn't match up. + /// If no architecture is specified, the platform should select the + /// default architecture from \a exe_file. Any application bundles + /// or executable wrappers can also be inspected for the actual + /// application binary within the bundle that should be used. + /// + /// @return + /// Returns \b true if this Platform plug-in was able to find + /// a suitable executable, \b false otherwise. + //------------------------------------------------------------------ + virtual Error ResolveExecutable(const ModuleSpec &module_spec, + lldb::ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr); + + //------------------------------------------------------------------ + /// Find a symbol file given a symbol file module specification. + /// + /// Each platform might have tricks to find symbol files for an + /// executable given information in a symbol file ModuleSpec. Some + /// platforms might also support symbol files that are bundles and + /// know how to extract the right symbol file given a bundle. + /// + /// @param[in] target + /// The target in which we are trying to resolve the symbol file. + /// The target has a list of modules that we might be able to + /// use in order to help find the right symbol file. If the + /// "m_file" or "m_platform_file" entries in the \a sym_spec + /// are filled in, then we might be able to locate a module in + /// the target, extract its UUID and locate a symbol file. + /// If just the "m_uuid" is specified, then we might be able + /// to find the module in the target that matches that UUID + /// and pair the symbol file along with it. If just "m_symbol_file" + /// is specified, we can use a variety of tricks to locate the + /// symbols in an SDK, PDK, or other development kit location. + /// + /// @param[in] sym_spec + /// A module spec that describes some information about the + /// symbol file we are trying to resolve. The ModuleSpec might + /// contain the following: + /// m_file - A full or partial path to an executable from the + /// target (might be empty). + /// m_platform_file - Another executable hint that contains + /// the path to the file as known on the + /// local/remote platform. + /// m_symbol_file - A full or partial path to a symbol file + /// or symbol bundle that should be used when + /// trying to resolve the symbol file. + /// m_arch - The architecture we are looking for when resolving + /// the symbol file. + /// m_uuid - The UUID of the executable and symbol file. This + /// can often be used to match up an executable with + /// a symbol file, or resolve an symbol file in a + /// symbol file bundle. + /// + /// @param[out] sym_file + /// The resolved symbol file spec if the returned error + /// indicates success. + /// + /// @return + /// Returns an error that describes success or failure. + //------------------------------------------------------------------ + virtual Error ResolveSymbolFile(Target &target, const ModuleSpec &sym_spec, + FileSpec &sym_file); + + //------------------------------------------------------------------ + /// Resolves the FileSpec to a (possibly) remote path. Remote + /// platforms must override this to resolve to a path on the remote + /// side. + //------------------------------------------------------------------ + virtual bool ResolveRemotePath(const FileSpec &platform_path, + FileSpec &resolved_platform_path); + + //------------------------------------------------------------------ + /// Get the OS version from a connected platform. + /// + /// Some platforms might not be connected to a remote platform, but + /// can figure out the OS version for a process. This is common for + /// simulator platforms that will run native programs on the current + /// host, but the simulator might be simulating a different OS. The + /// \a process parameter might be specified to help to determine + /// the OS version. + //------------------------------------------------------------------ + virtual bool GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update, + Process *process = nullptr); + + bool SetOSVersion(uint32_t major, uint32_t minor, uint32_t update); + + bool GetOSBuildString(std::string &s); + + bool GetOSKernelDescription(std::string &s); + + // Returns the name of the platform + ConstString GetName(); + + virtual const char *GetHostname(); + + virtual ConstString GetFullNameForDylib(ConstString basename); + + virtual const char *GetDescription() = 0; + + //------------------------------------------------------------------ + /// Report the current status for this platform. + /// + /// The returned string usually involves returning the OS version + /// (if available), and any SDK directory that might be being used + /// for local file caching, and if connected a quick blurb about + /// what this platform is connected to. + //------------------------------------------------------------------ + virtual void GetStatus(Stream &strm); + + //------------------------------------------------------------------ + // Subclasses must be able to fetch the current OS version + // + // Remote classes must be connected for this to succeed. Local + // subclasses don't need to override this function as it will just + // call the HostInfo::GetOSVersion(). + //------------------------------------------------------------------ + virtual bool GetRemoteOSVersion() { return false; } + + virtual bool GetRemoteOSBuildString(std::string &s) { + s.clear(); + return false; + } + + virtual bool GetRemoteOSKernelDescription(std::string &s) { + s.clear(); + return false; + } + + // Remote Platform subclasses need to override this function + virtual ArchSpec GetRemoteSystemArchitecture() { + return ArchSpec(); // Return an invalid architecture + } + + virtual FileSpec GetRemoteWorkingDirectory() { return m_working_dir; } + + virtual bool SetRemoteWorkingDirectory(const FileSpec &working_dir); + + virtual const char *GetUserName(uint32_t uid); + + virtual const char *GetGroupName(uint32_t gid); + + //------------------------------------------------------------------ + /// Locate a file for a platform. + /// + /// The default implementation of this function will return the same + /// file patch in \a local_file as was in \a platform_file. + /// + /// @param[in] platform_file + /// The platform file path to locate and cache locally. + /// + /// @param[in] uuid_ptr + /// If we know the exact UUID of the file we are looking for, it + /// can be specified. If it is not specified, we might now know + /// the exact file. The UUID is usually some sort of MD5 checksum + /// for the file and is sometimes known by dynamic linkers/loaders. + /// If the UUID is known, it is best to supply it to platform + /// file queries to ensure we are finding the correct file, not + /// just a file at the correct path. + /// + /// @param[out] local_file + /// A locally cached version of the platform file. For platforms + /// that describe the current host computer, this will just be + /// the same file. For remote platforms, this file might come from + /// and SDK directory, or might need to be sync'ed over to the + /// current machine for efficient debugging access. + /// + /// @return + /// An error object. + //------------------------------------------------------------------ + virtual Error GetFileWithUUID(const FileSpec &platform_file, + const UUID *uuid_ptr, FileSpec &local_file); + + //---------------------------------------------------------------------- + // Locate the scripting resource given a module specification. + // + // Locating the file should happen only on the local computer or using + // the current computers global settings. + //---------------------------------------------------------------------- + virtual FileSpecList + LocateExecutableScriptingResources(Target *target, Module &module, + Stream *feedback_stream); + + virtual Error GetSharedModule(const ModuleSpec &module_spec, Process *process, + lldb::ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr, + lldb::ModuleSP *old_module_sp_ptr, + bool *did_create_ptr); + + virtual bool GetModuleSpec(const FileSpec &module_file_spec, + const ArchSpec &arch, ModuleSpec &module_spec); + + virtual Error ConnectRemote(Args &args); + + virtual Error DisconnectRemote(); + + //------------------------------------------------------------------ + /// Get the platform's supported architectures in the order in which + /// they should be searched. + /// + /// @param[in] idx + /// A zero based architecture index + /// + /// @param[out] arch + /// A copy of the architecture at index if the return value is + /// \b true. + /// + /// @return + /// \b true if \a arch was filled in and is valid, \b false + /// otherwise. + //------------------------------------------------------------------ + virtual bool GetSupportedArchitectureAtIndex(uint32_t idx, + ArchSpec &arch) = 0; + + virtual size_t GetSoftwareBreakpointTrapOpcode(Target &target, + BreakpointSite *bp_site); + + //------------------------------------------------------------------ + /// Launch a new process on a platform, not necessarily for + /// debugging, it could be just for running the process. + //------------------------------------------------------------------ + virtual Error LaunchProcess(ProcessLaunchInfo &launch_info); + + //------------------------------------------------------------------ + /// Perform expansion of the command-line for this launch info + /// This can potentially involve wildcard expansion + // environment variable replacement, and whatever other + // argument magic the platform defines as part of its typical + // user experience + //------------------------------------------------------------------ + virtual Error ShellExpandArguments(ProcessLaunchInfo &launch_info); + + //------------------------------------------------------------------ + /// Kill process on a platform. + //------------------------------------------------------------------ + virtual Error KillProcess(const lldb::pid_t pid); + + //------------------------------------------------------------------ + /// Lets a platform answer if it is compatible with a given + /// architecture and the target triple contained within. + //------------------------------------------------------------------ + virtual bool IsCompatibleArchitecture(const ArchSpec &arch, + bool exact_arch_match, + ArchSpec *compatible_arch_ptr); + + //------------------------------------------------------------------ + /// Not all platforms will support debugging a process by spawning + /// somehow halted for a debugger (specified using the + /// "eLaunchFlagDebug" launch flag) and then attaching. If your + /// platform doesn't support this, override this function and return + /// false. + //------------------------------------------------------------------ + virtual bool CanDebugProcess() { return true; } + + //------------------------------------------------------------------ + /// Subclasses do not need to implement this function as it uses + /// the Platform::LaunchProcess() followed by Platform::Attach (). + /// Remote platforms will want to subclass this function in order + /// to be able to intercept STDIO and possibly launch a separate + /// process that will debug the debuggee. + //------------------------------------------------------------------ + virtual lldb::ProcessSP + DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, + Target *target, // Can be nullptr, if nullptr create a new + // target, else use existing one + Error &error); + + virtual lldb::ProcessSP ConnectProcess(llvm::StringRef connect_url, + llvm::StringRef plugin_name, + lldb_private::Debugger &debugger, + lldb_private::Target *target, + lldb_private::Error &error); + + //------------------------------------------------------------------ + /// Attach to an existing process using a process ID. + /// + /// Each platform subclass needs to implement this function and + /// attempt to attach to the process with the process ID of \a pid. + /// The platform subclass should return an appropriate ProcessSP + /// subclass that is attached to the process, or an empty shared + /// pointer with an appropriate error. + /// + /// @param[in] pid + /// The process ID that we should attempt to attach to. + /// + /// @return + /// An appropriate ProcessSP containing a valid shared pointer + /// to the default Process subclass for the platform that is + /// attached to the process, or an empty shared pointer with an + /// appropriate error fill into the \a error object. + //------------------------------------------------------------------ + virtual lldb::ProcessSP Attach(ProcessAttachInfo &attach_info, + Debugger &debugger, + Target *target, // Can be nullptr, if nullptr + // create a new target, else + // use existing one + Error &error) = 0; + + //------------------------------------------------------------------ + /// Attach to an existing process by process name. + /// + /// This function is not meant to be overridden by Process + /// subclasses. It will first call + /// Process::WillAttach (const char *) and if that returns \b + /// true, Process::DoAttach (const char *) will be called to + /// actually do the attach. If DoAttach returns \b true, then + /// Process::DidAttach() will be called. + /// + /// @param[in] process_name + /// A process name to match against the current process list. + /// + /// @return + /// Returns \a pid if attaching was successful, or + /// LLDB_INVALID_PROCESS_ID if attaching fails. + //------------------------------------------------------------------ + // virtual lldb::ProcessSP + // Attach (const char *process_name, + // bool wait_for_launch, + // Error &error) = 0; + + //------------------------------------------------------------------ + // The base class Platform will take care of the host platform. + // Subclasses will need to fill in the remote case. + //------------------------------------------------------------------ + virtual uint32_t FindProcesses(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &proc_infos); + + virtual bool GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &proc_info); + + //------------------------------------------------------------------ + // Set a breakpoint on all functions that can end up creating a thread + // for this platform. This is needed when running expressions and + // also for process control. + //------------------------------------------------------------------ + virtual lldb::BreakpointSP SetThreadCreationBreakpoint(Target &target); + + //------------------------------------------------------------------ + // Given a target, find the local SDK directory if one exists on the + // current host. + //------------------------------------------------------------------ + virtual lldb_private::ConstString + GetSDKDirectory(lldb_private::Target &target) { + return lldb_private::ConstString(); + } + + const std::string &GetRemoteURL() const { return m_remote_url; } + + bool IsHost() const { + return m_is_host; // Is this the default host platform? + } + + bool IsRemote() const { return !m_is_host; } + + virtual bool IsConnected() const { + // Remote subclasses should override this function + return IsHost(); + } + + const ArchSpec &GetSystemArchitecture(); + + void SetSystemArchitecture(const ArchSpec &arch) { + m_system_arch = arch; + if (IsHost()) + m_os_version_set_while_connected = m_system_arch.IsValid(); + } + + // Used for column widths + size_t GetMaxUserIDNameLength() const { return m_max_uid_name_len; } + + // Used for column widths + size_t GetMaxGroupIDNameLength() const { return m_max_gid_name_len; } + + const ConstString &GetSDKRootDirectory() const { return m_sdk_sysroot; } + + void SetSDKRootDirectory(const ConstString &dir) { m_sdk_sysroot = dir; } + + const ConstString &GetSDKBuild() const { return m_sdk_build; } + + void SetSDKBuild(const ConstString &sdk_build) { m_sdk_build = sdk_build; } + + // Override this to return true if your platform supports Clang modules. + // You may also need to override AddClangModuleCompilationOptions to pass the + // right Clang flags for your platform. + virtual bool SupportsModules() { return false; } + + // Appends the platform-specific options required to find the modules for the + // current platform. + virtual void + AddClangModuleCompilationOptions(Target *target, + std::vector<std::string> &options); + + FileSpec GetWorkingDirectory(); + + bool SetWorkingDirectory(const FileSpec &working_dir); + + // There may be modules that we don't want to find by default for operations + // like "setting breakpoint by name". + // The platform will return "true" from this call if the passed in module + // happens to be one of these. + + virtual bool + ModuleIsExcludedForUnconstrainedSearches(Target &target, + const lldb::ModuleSP &module_sp) { + return false; + } + + virtual Error MakeDirectory(const FileSpec &file_spec, uint32_t permissions); + + virtual Error GetFilePermissions(const FileSpec &file_spec, + uint32_t &file_permissions); - class PlatformProperties : public Properties - { - public: - PlatformProperties(); - - static ConstString - GetSettingName (); - - bool - GetUseModuleCache () const; - bool - SetUseModuleCache (bool use_module_cache); - - FileSpec - GetModuleCacheDirectory () const; - bool - SetModuleCacheDirectory (const FileSpec& dir_spec); - }; - - typedef std::shared_ptr<PlatformProperties> PlatformPropertiesSP; - - //---------------------------------------------------------------------- - /// @class Platform Platform.h "lldb/Target/Platform.h" - /// @brief A plug-in interface definition class for debug platform that - /// includes many platform abilities such as: - /// @li getting platform information such as supported architectures, - /// supported binary file formats and more - /// @li launching new processes - /// @li attaching to existing processes - /// @li download/upload files - /// @li execute shell commands - /// @li listing and getting info for existing processes - /// @li attaching and possibly debugging the platform's kernel - //---------------------------------------------------------------------- - class Platform : - public PluginInterface - { - public: - //------------------------------------------------------------------ - /// Default Constructor - //------------------------------------------------------------------ - Platform (bool is_host_platform); - - //------------------------------------------------------------------ - /// Destructor. - /// - /// The destructor is virtual since this class is designed to be - /// inherited from by the plug-in instance. - //------------------------------------------------------------------ - ~Platform() override; - - static void - Initialize (); - - static void - Terminate (); - - static const PlatformPropertiesSP & - GetGlobalPlatformProperties (); - - //------------------------------------------------------------------ - /// Get the native host platform plug-in. - /// - /// There should only be one of these for each host that LLDB runs - /// upon that should be statically compiled in and registered using - /// preprocessor macros or other similar build mechanisms in a - /// PlatformSubclass::Initialize() function. - /// - /// This platform will be used as the default platform when launching - /// or attaching to processes unless another platform is specified. - //------------------------------------------------------------------ - static lldb::PlatformSP - GetHostPlatform (); - - static lldb::PlatformSP - GetPlatformForArchitecture (const ArchSpec &arch, - ArchSpec *platform_arch_ptr); - - static const char * - GetHostPlatformName (); - - static void - SetHostPlatform (const lldb::PlatformSP &platform_sp); - - // Find an existing platform plug-in by name - static lldb::PlatformSP - Find (const ConstString &name); - - static lldb::PlatformSP - Create (const ConstString &name, Error &error); - - static lldb::PlatformSP - Create (const ArchSpec &arch, ArchSpec *platform_arch_ptr, Error &error); - - static uint32_t - GetNumConnectedRemotePlatforms (); - - static lldb::PlatformSP - GetConnectedRemotePlatformAtIndex (uint32_t idx); - - //------------------------------------------------------------------ - /// Find a platform plugin for a given process. - /// - /// Scans the installed Platform plug-ins and tries to find - /// an instance that can be used for \a process - /// - /// @param[in] process - /// The process for which to try and locate a platform - /// plug-in instance. - /// - /// @param[in] plugin_name - /// An optional name of a specific platform plug-in that - /// should be used. If nullptr, pick the best plug-in. - //------------------------------------------------------------------ -// static lldb::PlatformSP -// FindPlugin (Process *process, const ConstString &plugin_name); - - //------------------------------------------------------------------ - /// Set the target's executable based off of the existing - /// architecture information in \a target given a path to an - /// executable \a exe_file. - /// - /// Each platform knows the architectures that it supports and can - /// select the correct architecture slice within \a exe_file by - /// inspecting the architecture in \a target. If the target had an - /// architecture specified, then in can try and obey that request - /// and optionally fail if the architecture doesn't match up. - /// If no architecture is specified, the platform should select the - /// default architecture from \a exe_file. Any application bundles - /// or executable wrappers can also be inspected for the actual - /// application binary within the bundle that should be used. - /// - /// @return - /// Returns \b true if this Platform plug-in was able to find - /// a suitable executable, \b false otherwise. - //------------------------------------------------------------------ - virtual Error - ResolveExecutable (const ModuleSpec &module_spec, - lldb::ModuleSP &module_sp, - const FileSpecList *module_search_paths_ptr); - - //------------------------------------------------------------------ - /// Find a symbol file given a symbol file module specification. - /// - /// Each platform might have tricks to find symbol files for an - /// executable given information in a symbol file ModuleSpec. Some - /// platforms might also support symbol files that are bundles and - /// know how to extract the right symbol file given a bundle. - /// - /// @param[in] target - /// The target in which we are trying to resolve the symbol file. - /// The target has a list of modules that we might be able to - /// use in order to help find the right symbol file. If the - /// "m_file" or "m_platform_file" entries in the \a sym_spec - /// are filled in, then we might be able to locate a module in - /// the target, extract its UUID and locate a symbol file. - /// If just the "m_uuid" is specified, then we might be able - /// to find the module in the target that matches that UUID - /// and pair the symbol file along with it. If just "m_symbol_file" - /// is specified, we can use a variety of tricks to locate the - /// symbols in an SDK, PDK, or other development kit location. - /// - /// @param[in] sym_spec - /// A module spec that describes some information about the - /// symbol file we are trying to resolve. The ModuleSpec might - /// contain the following: - /// m_file - A full or partial path to an executable from the - /// target (might be empty). - /// m_platform_file - Another executable hint that contains - /// the path to the file as known on the - /// local/remote platform. - /// m_symbol_file - A full or partial path to a symbol file - /// or symbol bundle that should be used when - /// trying to resolve the symbol file. - /// m_arch - The architecture we are looking for when resolving - /// the symbol file. - /// m_uuid - The UUID of the executable and symbol file. This - /// can often be used to match up an executable with - /// a symbol file, or resolve an symbol file in a - /// symbol file bundle. - /// - /// @param[out] sym_file - /// The resolved symbol file spec if the returned error - /// indicates success. - /// - /// @return - /// Returns an error that describes success or failure. - //------------------------------------------------------------------ - virtual Error - ResolveSymbolFile (Target &target, - const ModuleSpec &sym_spec, - FileSpec &sym_file); - - //------------------------------------------------------------------ - /// Resolves the FileSpec to a (possibly) remote path. Remote - /// platforms must override this to resolve to a path on the remote - /// side. - //------------------------------------------------------------------ - virtual bool - ResolveRemotePath (const FileSpec &platform_path, - FileSpec &resolved_platform_path); - - //------------------------------------------------------------------ - /// Get the OS version from a connected platform. - /// - /// Some platforms might not be connected to a remote platform, but - /// can figure out the OS version for a process. This is common for - /// simulator platforms that will run native programs on the current - /// host, but the simulator might be simulating a different OS. The - /// \a process parameter might be specified to help to determine - /// the OS version. - //------------------------------------------------------------------ - virtual bool - GetOSVersion (uint32_t &major, - uint32_t &minor, - uint32_t &update, - Process *process = nullptr); - - bool - SetOSVersion (uint32_t major, - uint32_t minor, - uint32_t update); - - bool - GetOSBuildString (std::string &s); - - bool - GetOSKernelDescription (std::string &s); - - // Returns the name of the platform - ConstString - GetName (); - - virtual const char * - GetHostname (); - - virtual ConstString - GetFullNameForDylib (ConstString basename); - - virtual const char * - GetDescription () = 0; - - //------------------------------------------------------------------ - /// Report the current status for this platform. - /// - /// The returned string usually involves returning the OS version - /// (if available), and any SDK directory that might be being used - /// for local file caching, and if connected a quick blurb about - /// what this platform is connected to. - //------------------------------------------------------------------ - virtual void - GetStatus (Stream &strm); - - //------------------------------------------------------------------ - // Subclasses must be able to fetch the current OS version - // - // Remote classes must be connected for this to succeed. Local - // subclasses don't need to override this function as it will just - // call the HostInfo::GetOSVersion(). - //------------------------------------------------------------------ - virtual bool - GetRemoteOSVersion () - { - return false; - } + virtual Error SetFilePermissions(const FileSpec &file_spec, + uint32_t file_permissions); - virtual bool - GetRemoteOSBuildString (std::string &s) - { - s.clear(); - return false; - } - - virtual bool - GetRemoteOSKernelDescription (std::string &s) - { - s.clear(); - return false; - } + virtual lldb::user_id_t OpenFile(const FileSpec &file_spec, uint32_t flags, + uint32_t mode, Error &error) { + return UINT64_MAX; + } - // Remote Platform subclasses need to override this function - virtual ArchSpec - GetRemoteSystemArchitecture () - { - return ArchSpec(); // Return an invalid architecture - } + virtual bool CloseFile(lldb::user_id_t fd, Error &error) { return false; } - virtual FileSpec - GetRemoteWorkingDirectory() - { - return m_working_dir; - } - - virtual bool - SetRemoteWorkingDirectory(const FileSpec &working_dir); - - virtual const char * - GetUserName (uint32_t uid); - - virtual const char * - GetGroupName (uint32_t gid); - - //------------------------------------------------------------------ - /// Locate a file for a platform. - /// - /// The default implementation of this function will return the same - /// file patch in \a local_file as was in \a platform_file. - /// - /// @param[in] platform_file - /// The platform file path to locate and cache locally. - /// - /// @param[in] uuid_ptr - /// If we know the exact UUID of the file we are looking for, it - /// can be specified. If it is not specified, we might now know - /// the exact file. The UUID is usually some sort of MD5 checksum - /// for the file and is sometimes known by dynamic linkers/loaders. - /// If the UUID is known, it is best to supply it to platform - /// file queries to ensure we are finding the correct file, not - /// just a file at the correct path. - /// - /// @param[out] local_file - /// A locally cached version of the platform file. For platforms - /// that describe the current host computer, this will just be - /// the same file. For remote platforms, this file might come from - /// and SDK directory, or might need to be sync'ed over to the - /// current machine for efficient debugging access. - /// - /// @return - /// An error object. - //------------------------------------------------------------------ - virtual Error - GetFileWithUUID (const FileSpec &platform_file, - const UUID *uuid_ptr, - FileSpec &local_file); - - //---------------------------------------------------------------------- - // Locate the scripting resource given a module specification. - // - // Locating the file should happen only on the local computer or using - // the current computers global settings. - //---------------------------------------------------------------------- - virtual FileSpecList - LocateExecutableScriptingResources (Target *target, - Module &module, - Stream* feedback_stream); - - virtual Error - GetSharedModule (const ModuleSpec &module_spec, - Process* process, - lldb::ModuleSP &module_sp, - const FileSpecList *module_search_paths_ptr, - lldb::ModuleSP *old_module_sp_ptr, - bool *did_create_ptr); - - virtual bool - GetModuleSpec (const FileSpec& module_file_spec, - const ArchSpec& arch, - ModuleSpec &module_spec); - - virtual Error - ConnectRemote (Args& args); - - virtual Error - DisconnectRemote (); - - //------------------------------------------------------------------ - /// Get the platform's supported architectures in the order in which - /// they should be searched. - /// - /// @param[in] idx - /// A zero based architecture index - /// - /// @param[out] arch - /// A copy of the architecture at index if the return value is - /// \b true. - /// - /// @return - /// \b true if \a arch was filled in and is valid, \b false - /// otherwise. - //------------------------------------------------------------------ - virtual bool - GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch) = 0; - - virtual size_t - GetSoftwareBreakpointTrapOpcode (Target &target, - BreakpointSite *bp_site); - - //------------------------------------------------------------------ - /// Launch a new process on a platform, not necessarily for - /// debugging, it could be just for running the process. - //------------------------------------------------------------------ - virtual Error - LaunchProcess (ProcessLaunchInfo &launch_info); - - //------------------------------------------------------------------ - /// Perform expansion of the command-line for this launch info - /// This can potentially involve wildcard expansion - // environment variable replacement, and whatever other - // argument magic the platform defines as part of its typical - // user experience - //------------------------------------------------------------------ - virtual Error - ShellExpandArguments (ProcessLaunchInfo &launch_info); - - //------------------------------------------------------------------ - /// Kill process on a platform. - //------------------------------------------------------------------ - virtual Error - KillProcess (const lldb::pid_t pid); - - //------------------------------------------------------------------ - /// Lets a platform answer if it is compatible with a given - /// architecture and the target triple contained within. - //------------------------------------------------------------------ - virtual bool - IsCompatibleArchitecture (const ArchSpec &arch, - bool exact_arch_match, - ArchSpec *compatible_arch_ptr); - - //------------------------------------------------------------------ - /// Not all platforms will support debugging a process by spawning - /// somehow halted for a debugger (specified using the - /// "eLaunchFlagDebug" launch flag) and then attaching. If your - /// platform doesn't support this, override this function and return - /// false. - //------------------------------------------------------------------ - virtual bool - CanDebugProcess () - { - return true; - } + virtual lldb::user_id_t GetFileSize(const FileSpec &file_spec) { + return UINT64_MAX; + } - //------------------------------------------------------------------ - /// Subclasses do not need to implement this function as it uses - /// the Platform::LaunchProcess() followed by Platform::Attach (). - /// Remote platforms will want to subclass this function in order - /// to be able to intercept STDIO and possibly launch a separate - /// process that will debug the debuggee. - //------------------------------------------------------------------ - virtual lldb::ProcessSP - DebugProcess (ProcessLaunchInfo &launch_info, - Debugger &debugger, - Target *target, // Can be nullptr, if nullptr create a new target, else use existing one - Error &error); - - virtual lldb::ProcessSP - ConnectProcess (const char* connect_url, - const char* plugin_name, - lldb_private::Debugger &debugger, - lldb_private::Target *target, - lldb_private::Error &error); - - //------------------------------------------------------------------ - /// Attach to an existing process using a process ID. - /// - /// Each platform subclass needs to implement this function and - /// attempt to attach to the process with the process ID of \a pid. - /// The platform subclass should return an appropriate ProcessSP - /// subclass that is attached to the process, or an empty shared - /// pointer with an appropriate error. - /// - /// @param[in] pid - /// The process ID that we should attempt to attach to. - /// - /// @return - /// An appropriate ProcessSP containing a valid shared pointer - /// to the default Process subclass for the platform that is - /// attached to the process, or an empty shared pointer with an - /// appropriate error fill into the \a error object. - //------------------------------------------------------------------ - virtual lldb::ProcessSP - Attach (ProcessAttachInfo &attach_info, - Debugger &debugger, - Target *target, // Can be nullptr, if nullptr create a new target, else use existing one - Error &error) = 0; - - //------------------------------------------------------------------ - /// Attach to an existing process by process name. - /// - /// This function is not meant to be overridden by Process - /// subclasses. It will first call - /// Process::WillAttach (const char *) and if that returns \b - /// true, Process::DoAttach (const char *) will be called to - /// actually do the attach. If DoAttach returns \b true, then - /// Process::DidAttach() will be called. - /// - /// @param[in] process_name - /// A process name to match against the current process list. - /// - /// @return - /// Returns \a pid if attaching was successful, or - /// LLDB_INVALID_PROCESS_ID if attaching fails. - //------------------------------------------------------------------ -// virtual lldb::ProcessSP -// Attach (const char *process_name, -// bool wait_for_launch, -// Error &error) = 0; - - //------------------------------------------------------------------ - // The base class Platform will take care of the host platform. - // Subclasses will need to fill in the remote case. - //------------------------------------------------------------------ - virtual uint32_t - FindProcesses (const ProcessInstanceInfoMatch &match_info, - ProcessInstanceInfoList &proc_infos); - - virtual bool - GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &proc_info); - - //------------------------------------------------------------------ - // Set a breakpoint on all functions that can end up creating a thread - // for this platform. This is needed when running expressions and - // also for process control. - //------------------------------------------------------------------ - virtual lldb::BreakpointSP - SetThreadCreationBreakpoint (Target &target); - - //------------------------------------------------------------------ - // Given a target, find the local SDK directory if one exists on the - // current host. - //------------------------------------------------------------------ - virtual lldb_private::ConstString - GetSDKDirectory (lldb_private::Target &target) - { - return lldb_private::ConstString(); - } + virtual uint64_t ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst, + uint64_t dst_len, Error &error) { + error.SetErrorStringWithFormat( + "Platform::ReadFile() is not supported in the %s platform", + GetName().GetCString()); + return -1; + } - const std::string & - GetRemoteURL () const - { - return m_remote_url; - } + virtual uint64_t WriteFile(lldb::user_id_t fd, uint64_t offset, + const void *src, uint64_t src_len, Error &error) { + error.SetErrorStringWithFormat( + "Platform::ReadFile() is not supported in the %s platform", + GetName().GetCString()); + return -1; + } - bool - IsHost () const - { - return m_is_host; // Is this the default host platform? - } + virtual Error GetFile(const FileSpec &source, const FileSpec &destination); - bool - IsRemote () const - { - return !m_is_host; - } - - virtual bool - IsConnected () const - { - // Remote subclasses should override this function - return IsHost(); - } - - const ArchSpec & - GetSystemArchitecture(); - - void - SetSystemArchitecture (const ArchSpec &arch) - { - m_system_arch = arch; - if (IsHost()) - m_os_version_set_while_connected = m_system_arch.IsValid(); - } + virtual Error PutFile(const FileSpec &source, const FileSpec &destination, + uint32_t uid = UINT32_MAX, uint32_t gid = UINT32_MAX); - // Used for column widths - size_t - GetMaxUserIDNameLength() const - { - return m_max_uid_name_len; - } + virtual Error + CreateSymlink(const FileSpec &src, // The name of the link is in src + const FileSpec &dst); // The symlink points to dst - // Used for column widths - size_t - GetMaxGroupIDNameLength() const - { - return m_max_gid_name_len; - } - - const ConstString & - GetSDKRootDirectory () const - { - return m_sdk_sysroot; - } + //---------------------------------------------------------------------- + /// Install a file or directory to the remote system. + /// + /// Install is similar to Platform::PutFile(), but it differs in that if + /// an application/framework/shared library is installed on a remote + /// platform and the remote platform requires something to be done to + /// register the application/framework/shared library, then this extra + /// registration can be done. + /// + /// @param[in] src + /// The source file/directory to install on the remote system. + /// + /// @param[in] dst + /// The destination file/directory where \a src will be installed. + /// If \a dst has no filename specified, then its filename will + /// be set from \a src. It \a dst has no directory specified, it + /// will use the platform working directory. If \a dst has a + /// directory specified, but the directory path is relative, the + /// platform working directory will be prepended to the relative + /// directory. + /// + /// @return + /// An error object that describes anything that went wrong. + //---------------------------------------------------------------------- + virtual Error Install(const FileSpec &src, const FileSpec &dst); + + virtual size_t GetEnvironment(StringList &environment); + + virtual bool GetFileExists(const lldb_private::FileSpec &file_spec); + + virtual Error Unlink(const FileSpec &file_spec); + + virtual uint64_t ConvertMmapFlagsToPlatform(const ArchSpec &arch, + unsigned flags); + + virtual bool GetSupportsRSync() { return m_supports_rsync; } + + virtual void SetSupportsRSync(bool flag) { m_supports_rsync = flag; } + + virtual const char *GetRSyncOpts() { return m_rsync_opts.c_str(); } + + virtual void SetRSyncOpts(const char *opts) { m_rsync_opts.assign(opts); } + + virtual const char *GetRSyncPrefix() { return m_rsync_prefix.c_str(); } + + virtual void SetRSyncPrefix(const char *prefix) { + m_rsync_prefix.assign(prefix); + } + + virtual bool GetSupportsSSH() { return m_supports_ssh; } + + virtual void SetSupportsSSH(bool flag) { m_supports_ssh = flag; } + + virtual const char *GetSSHOpts() { return m_ssh_opts.c_str(); } + + virtual void SetSSHOpts(const char *opts) { m_ssh_opts.assign(opts); } + + virtual bool GetIgnoresRemoteHostname() { return m_ignores_remote_hostname; } + + virtual void SetIgnoresRemoteHostname(bool flag) { + m_ignores_remote_hostname = flag; + } + + virtual lldb_private::OptionGroupOptions * + GetConnectionOptions(CommandInterpreter &interpreter) { + return nullptr; + } + + virtual lldb_private::Error RunShellCommand( + const char *command, // Shouldn't be nullptr + const FileSpec &working_dir, // Pass empty FileSpec to use the current + // working directory + int *status_ptr, // Pass nullptr if you don't want the process exit status + int *signo_ptr, // Pass nullptr if you don't want the signal that caused + // the process to exit + std::string + *command_output, // Pass nullptr if you don't want the command output + uint32_t timeout_sec); // Timeout in seconds to wait for shell program to + // finish + + virtual void SetLocalCacheDirectory(const char *local); + + virtual const char *GetLocalCacheDirectory(); + + virtual std::string GetPlatformSpecificConnectionInformation() { return ""; } + + virtual bool CalculateMD5(const FileSpec &file_spec, uint64_t &low, + uint64_t &high); + + virtual int32_t GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) { + return 1; + } + + virtual const lldb::UnixSignalsSP &GetRemoteUnixSignals(); + + const lldb::UnixSignalsSP &GetUnixSignals(); + + //------------------------------------------------------------------ + /// Locate a queue name given a thread's qaddr + /// + /// On a system using libdispatch ("Grand Central Dispatch") style + /// queues, a thread may be associated with a GCD queue or not, + /// and a queue may be associated with multiple threads. + /// The process/thread must provide a way to find the "dispatch_qaddr" + /// for each thread, and from that dispatch_qaddr this Platform method + /// will locate the queue name and provide that. + /// + /// @param[in] process + /// A process is required for reading memory. + /// + /// @param[in] dispatch_qaddr + /// The dispatch_qaddr for this thread. + /// + /// @return + /// The name of the queue, if there is one. An empty string + /// means that this thread is not associated with a dispatch + /// queue. + //------------------------------------------------------------------ + virtual std::string + GetQueueNameForThreadQAddress(Process *process, lldb::addr_t dispatch_qaddr) { + return ""; + } + + //------------------------------------------------------------------ + /// Locate a queue ID given a thread's qaddr + /// + /// On a system using libdispatch ("Grand Central Dispatch") style + /// queues, a thread may be associated with a GCD queue or not, + /// and a queue may be associated with multiple threads. + /// The process/thread must provide a way to find the "dispatch_qaddr" + /// for each thread, and from that dispatch_qaddr this Platform method + /// will locate the queue ID and provide that. + /// + /// @param[in] process + /// A process is required for reading memory. + /// + /// @param[in] dispatch_qaddr + /// The dispatch_qaddr for this thread. + /// + /// @return + /// The queue_id for this thread, if this thread is associated + /// with a dispatch queue. Else LLDB_INVALID_QUEUE_ID is returned. + //------------------------------------------------------------------ + virtual lldb::queue_id_t + GetQueueIDForThreadQAddress(Process *process, lldb::addr_t dispatch_qaddr) { + return LLDB_INVALID_QUEUE_ID; + } + + //------------------------------------------------------------------ + /// Provide a list of trap handler function names for this platform + /// + /// The unwinder needs to treat trap handlers specially -- the stack + /// frame may not be aligned correctly for a trap handler (the kernel + /// often won't perturb the stack pointer, or won't re-align it properly, + /// in the process of calling the handler) and the frame above the handler + /// needs to be treated by the unwinder's "frame 0" rules instead of its + /// "middle of the stack frame" rules. + /// + /// In a user process debugging scenario, the list of trap handlers is + /// typically just "_sigtramp". + /// + /// The Platform base class provides the m_trap_handlers ivar but it does + /// not populate it. Subclasses should add the names of the asynchronous + /// signal handler routines as needed. For most Unix platforms, add + /// _sigtramp. + /// + /// @return + /// A list of symbol names. The list may be empty. + //------------------------------------------------------------------ + virtual const std::vector<ConstString> &GetTrapHandlerSymbolNames(); + + //------------------------------------------------------------------ + /// Find a support executable that may not live within in the + /// standard locations related to LLDB. + /// + /// Executable might exist within the Platform SDK directories, or + /// in standard tool directories within the current IDE that is + /// running LLDB. + /// + /// @param[in] basename + /// The basename of the executable to locate in the current + /// platform. + /// + /// @return + /// A FileSpec pointing to the executable on disk, or an invalid + /// FileSpec if the executable cannot be found. + //------------------------------------------------------------------ + virtual FileSpec LocateExecutable(const char *basename) { return FileSpec(); } + + //------------------------------------------------------------------ + /// Allow the platform to set preferred memory cache line size. If non-zero + /// (and the user + /// has not set cache line size explicitly), this value will be used as the + /// cache line + /// size for memory reads. + //------------------------------------------------------------------ + virtual uint32_t GetDefaultMemoryCacheLineSize() { return 0; } + + //------------------------------------------------------------------ + /// Load a shared library into this process. + /// + /// Try and load a shared library into the current process. This + /// call might fail in the dynamic loader plug-in says it isn't safe + /// to try and load shared libraries at the moment. + /// + /// @param[in] process + /// The process to load the image. + /// + /// @param[in] local_file + /// The file spec that points to the shared library that you want + /// to load if the library is located on the host. The library will + /// be copied over to the location specified by remote_file or into + /// the current working directory with the same filename if the + /// remote_file isn't specified. + /// + /// @param[in] remote_file + /// If local_file is specified then the location where the library + /// should be copied over from the host. If local_file isn't + /// specified, then the path for the shared library on the target + /// what you want to load. + /// + /// @param[out] error + /// An error object that gets filled in with any errors that + /// might occur when trying to load the shared library. + /// + /// @return + /// A token that represents the shared library that can be + /// later used to unload the shared library. A value of + /// LLDB_INVALID_IMAGE_TOKEN will be returned if the shared + /// library can't be opened. + //------------------------------------------------------------------ + uint32_t LoadImage(lldb_private::Process *process, + const lldb_private::FileSpec &local_file, + const lldb_private::FileSpec &remote_file, + lldb_private::Error &error); + + virtual uint32_t DoLoadImage(lldb_private::Process *process, + const lldb_private::FileSpec &remote_file, + lldb_private::Error &error); + + virtual Error UnloadImage(lldb_private::Process *process, + uint32_t image_token); + + //------------------------------------------------------------------ + /// Connect to all processes waiting for a debugger to attach + /// + /// If the platform have a list of processes waiting for a debugger + /// to connect to them then connect to all of these pending processes. + /// + /// @param[in] debugger + /// The debugger used for the connect. + /// + /// @param[out] error + /// If an error occurred during the connect then this object will + /// contain the error message. + /// + /// @return + /// The number of processes we are successfully connected to. + //------------------------------------------------------------------ + virtual size_t ConnectToWaitingProcesses(lldb_private::Debugger &debugger, + lldb_private::Error &error); + +protected: + bool m_is_host; + // Set to true when we are able to actually set the OS version while + // being connected. For remote platforms, we might set the version ahead + // of time before we actually connect and this version might change when + // we actually connect to a remote platform. For the host platform this + // will be set to the once we call HostInfo::GetOSVersion(). + bool m_os_version_set_while_connected; + bool m_system_arch_set_while_connected; + ConstString + m_sdk_sysroot; // the root location of where the SDK files are all located + ConstString m_sdk_build; + FileSpec m_working_dir; // The working directory which is used when installing + // modules that have no install path set + std::string m_remote_url; + std::string m_name; + uint32_t m_major_os_version; + uint32_t m_minor_os_version; + uint32_t m_update_os_version; + ArchSpec + m_system_arch; // The architecture of the kernel or the remote platform + typedef std::map<uint32_t, ConstString> IDToNameMap; + // Mutex for modifying Platform data structures that should only be used for + // non-reentrant code + std::mutex m_mutex; + IDToNameMap m_uid_map; + IDToNameMap m_gid_map; + size_t m_max_uid_name_len; + size_t m_max_gid_name_len; + bool m_supports_rsync; + std::string m_rsync_opts; + std::string m_rsync_prefix; + bool m_supports_ssh; + std::string m_ssh_opts; + bool m_ignores_remote_hostname; + std::string m_local_cache_directory; + std::vector<ConstString> m_trap_handlers; + bool m_calculated_trap_handlers; + const std::unique_ptr<ModuleCache> m_module_cache; + + //------------------------------------------------------------------ + /// Ask the Platform subclass to fill in the list of trap handler names + /// + /// For most Unix user process environments, this will be a single + /// function name, _sigtramp. More specialized environments may have + /// additional handler names. The unwinder code needs to know when a + /// trap handler is on the stack because the unwind rules for the frame + /// that caused the trap are different. + /// + /// The base class Platform ivar m_trap_handlers should be updated by + /// the Platform subclass when this method is called. If there are no + /// predefined trap handlers, this method may be a no-op. + //------------------------------------------------------------------ + virtual void CalculateTrapHandlerSymbolNames() = 0; + + const char *GetCachedUserName(uint32_t uid) { + std::lock_guard<std::mutex> guard(m_mutex); + // return the empty string if our string is NULL + // so we can tell when things were in the negative + // cached (didn't find a valid user name, don't keep + // trying) + const auto pos = m_uid_map.find(uid); + return ((pos != m_uid_map.end()) ? pos->second.AsCString("") : nullptr); + } + + const char *SetCachedUserName(uint32_t uid, const char *name, + size_t name_len) { + std::lock_guard<std::mutex> guard(m_mutex); + ConstString const_name(name); + m_uid_map[uid] = const_name; + if (m_max_uid_name_len < name_len) + m_max_uid_name_len = name_len; + // Const strings lives forever in our const string pool, so we can return + // the const char * + return const_name.GetCString(); + } + + void SetUserNameNotFound(uint32_t uid) { + std::lock_guard<std::mutex> guard(m_mutex); + m_uid_map[uid] = ConstString(); + } + + void ClearCachedUserNames() { + std::lock_guard<std::mutex> guard(m_mutex); + m_uid_map.clear(); + } + + const char *GetCachedGroupName(uint32_t gid) { + std::lock_guard<std::mutex> guard(m_mutex); + // return the empty string if our string is NULL + // so we can tell when things were in the negative + // cached (didn't find a valid group name, don't keep + // trying) + const auto pos = m_gid_map.find(gid); + return ((pos != m_gid_map.end()) ? pos->second.AsCString("") : nullptr); + } + + const char *SetCachedGroupName(uint32_t gid, const char *name, + size_t name_len) { + std::lock_guard<std::mutex> guard(m_mutex); + ConstString const_name(name); + m_gid_map[gid] = const_name; + if (m_max_gid_name_len < name_len) + m_max_gid_name_len = name_len; + // Const strings lives forever in our const string pool, so we can return + // the const char * + return const_name.GetCString(); + } + + void SetGroupNameNotFound(uint32_t gid) { + std::lock_guard<std::mutex> guard(m_mutex); + m_gid_map[gid] = ConstString(); + } + + void ClearCachedGroupNames() { + std::lock_guard<std::mutex> guard(m_mutex); + m_gid_map.clear(); + } + + Error GetCachedExecutable(ModuleSpec &module_spec, lldb::ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr, + Platform &remote_platform); + + virtual Error DownloadModuleSlice(const FileSpec &src_file_spec, + const uint64_t src_offset, + const uint64_t src_size, + const FileSpec &dst_file_spec); + + virtual Error DownloadSymbolFile(const lldb::ModuleSP &module_sp, + const FileSpec &dst_file_spec); + + virtual const char *GetCacheHostname(); + +private: + typedef std::function<Error(const ModuleSpec &)> ModuleResolver; + + Error GetRemoteSharedModule(const ModuleSpec &module_spec, Process *process, + lldb::ModuleSP &module_sp, + const ModuleResolver &module_resolver, + bool *did_create_ptr); - void - SetSDKRootDirectory (const ConstString &dir) - { - m_sdk_sysroot = dir; - } + bool GetCachedSharedModule(const ModuleSpec &module_spec, + lldb::ModuleSP &module_sp, bool *did_create_ptr); - const ConstString & - GetSDKBuild () const - { - return m_sdk_build; - } - - void - SetSDKBuild (const ConstString &sdk_build) - { - m_sdk_build = sdk_build; - } - - // Override this to return true if your platform supports Clang modules. - // You may also need to override AddClangModuleCompilationOptions to pass the right Clang flags for your platform. - virtual bool - SupportsModules () { return false; } - - // Appends the platform-specific options required to find the modules for the current platform. - virtual void - AddClangModuleCompilationOptions (Target *target, std::vector<std::string> &options); - - FileSpec - GetWorkingDirectory(); - - bool - SetWorkingDirectory(const FileSpec &working_dir); - - // There may be modules that we don't want to find by default for operations like "setting breakpoint by name". - // The platform will return "true" from this call if the passed in module happens to be one of these. - - virtual bool - ModuleIsExcludedForUnconstrainedSearches (Target &target, const lldb::ModuleSP &module_sp) - { - return false; - } - - virtual Error - MakeDirectory(const FileSpec &file_spec, uint32_t permissions); - - virtual Error - GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions); - - virtual Error - SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions); - - virtual lldb::user_id_t - OpenFile (const FileSpec& file_spec, - uint32_t flags, - uint32_t mode, - Error &error) - { - return UINT64_MAX; - } - - virtual bool - CloseFile (lldb::user_id_t fd, - Error &error) - { - return false; - } - - virtual lldb::user_id_t - GetFileSize (const FileSpec& file_spec) - { - return UINT64_MAX; - } + Error LoadCachedExecutable(const ModuleSpec &module_spec, + lldb::ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr, + Platform &remote_platform); - virtual uint64_t - ReadFile (lldb::user_id_t fd, - uint64_t offset, - void *dst, - uint64_t dst_len, - Error &error) - { - error.SetErrorStringWithFormat ("Platform::ReadFile() is not supported in the %s platform", GetName().GetCString()); - return -1; - } - - virtual uint64_t - WriteFile (lldb::user_id_t fd, - uint64_t offset, - const void* src, - uint64_t src_len, - Error &error) - { - error.SetErrorStringWithFormat ("Platform::ReadFile() is not supported in the %s platform", GetName().GetCString()); - return -1; - } - - virtual Error - GetFile (const FileSpec& source, - const FileSpec& destination); - - virtual Error - PutFile (const FileSpec& source, - const FileSpec& destination, - uint32_t uid = UINT32_MAX, - uint32_t gid = UINT32_MAX); - - virtual Error - CreateSymlink(const FileSpec &src, // The name of the link is in src - const FileSpec &dst); // The symlink points to dst - - //---------------------------------------------------------------------- - /// Install a file or directory to the remote system. - /// - /// Install is similar to Platform::PutFile(), but it differs in that if - /// an application/framework/shared library is installed on a remote - /// platform and the remote platform requires something to be done to - /// register the application/framework/shared library, then this extra - /// registration can be done. - /// - /// @param[in] src - /// The source file/directory to install on the remote system. - /// - /// @param[in] dst - /// The destination file/directory where \a src will be installed. - /// If \a dst has no filename specified, then its filename will - /// be set from \a src. It \a dst has no directory specified, it - /// will use the platform working directory. If \a dst has a - /// directory specified, but the directory path is relative, the - /// platform working directory will be prepended to the relative - /// directory. - /// - /// @return - /// An error object that describes anything that went wrong. - //---------------------------------------------------------------------- - virtual Error - Install (const FileSpec& src, const FileSpec& dst); - - virtual size_t - GetEnvironment (StringList &environment); - - virtual bool - GetFileExists (const lldb_private::FileSpec& file_spec); - - virtual Error - Unlink(const FileSpec &file_spec); - - virtual uint64_t - ConvertMmapFlagsToPlatform(const ArchSpec &arch, unsigned flags); - - virtual bool - GetSupportsRSync () - { - return m_supports_rsync; - } - - virtual void - SetSupportsRSync(bool flag) - { - m_supports_rsync = flag; - } - - virtual const char* - GetRSyncOpts () - { - return m_rsync_opts.c_str(); - } - - virtual void - SetRSyncOpts (const char* opts) - { - m_rsync_opts.assign(opts); - } - - virtual const char* - GetRSyncPrefix () - { - return m_rsync_prefix.c_str(); - } - - virtual void - SetRSyncPrefix (const char* prefix) - { - m_rsync_prefix.assign(prefix); - } - - virtual bool - GetSupportsSSH () - { - return m_supports_ssh; - } - - virtual void - SetSupportsSSH(bool flag) - { - m_supports_ssh = flag; - } - - virtual const char* - GetSSHOpts () - { - return m_ssh_opts.c_str(); - } - - virtual void - SetSSHOpts (const char* opts) - { - m_ssh_opts.assign(opts); - } - - virtual bool - GetIgnoresRemoteHostname () - { - return m_ignores_remote_hostname; - } - - virtual void - SetIgnoresRemoteHostname(bool flag) - { - m_ignores_remote_hostname = flag; - } - - virtual lldb_private::OptionGroupOptions * - GetConnectionOptions (CommandInterpreter& interpreter) - { - return nullptr; - } - - virtual lldb_private::Error - RunShellCommand(const char *command, // Shouldn't be nullptr - const FileSpec &working_dir, // Pass empty FileSpec to use the current working directory - int *status_ptr, // Pass nullptr if you don't want the process exit status - int *signo_ptr, // Pass nullptr if you don't want the signal that caused the process to exit - std::string *command_output, // Pass nullptr if you don't want the command output - uint32_t timeout_sec); // Timeout in seconds to wait for shell program to finish - - virtual void - SetLocalCacheDirectory (const char* local); - - virtual const char* - GetLocalCacheDirectory (); - - virtual std::string - GetPlatformSpecificConnectionInformation() - { - return ""; - } - - virtual bool - CalculateMD5 (const FileSpec& file_spec, - uint64_t &low, - uint64_t &high); - - virtual int32_t - GetResumeCountForLaunchInfo (ProcessLaunchInfo &launch_info) - { - return 1; - } + FileSpec GetModuleCacheRoot(); - virtual const lldb::UnixSignalsSP & - GetRemoteUnixSignals(); - - const lldb::UnixSignalsSP & - GetUnixSignals(); - - //------------------------------------------------------------------ - /// Locate a queue name given a thread's qaddr - /// - /// On a system using libdispatch ("Grand Central Dispatch") style - /// queues, a thread may be associated with a GCD queue or not, - /// and a queue may be associated with multiple threads. - /// The process/thread must provide a way to find the "dispatch_qaddr" - /// for each thread, and from that dispatch_qaddr this Platform method - /// will locate the queue name and provide that. - /// - /// @param[in] process - /// A process is required for reading memory. - /// - /// @param[in] dispatch_qaddr - /// The dispatch_qaddr for this thread. - /// - /// @return - /// The name of the queue, if there is one. An empty string - /// means that this thread is not associated with a dispatch - /// queue. - //------------------------------------------------------------------ - virtual std::string - GetQueueNameForThreadQAddress (Process *process, lldb::addr_t dispatch_qaddr) - { - return ""; - } + DISALLOW_COPY_AND_ASSIGN(Platform); +}; - //------------------------------------------------------------------ - /// Locate a queue ID given a thread's qaddr - /// - /// On a system using libdispatch ("Grand Central Dispatch") style - /// queues, a thread may be associated with a GCD queue or not, - /// and a queue may be associated with multiple threads. - /// The process/thread must provide a way to find the "dispatch_qaddr" - /// for each thread, and from that dispatch_qaddr this Platform method - /// will locate the queue ID and provide that. - /// - /// @param[in] process - /// A process is required for reading memory. - /// - /// @param[in] dispatch_qaddr - /// The dispatch_qaddr for this thread. - /// - /// @return - /// The queue_id for this thread, if this thread is associated - /// with a dispatch queue. Else LLDB_INVALID_QUEUE_ID is returned. - //------------------------------------------------------------------ - virtual lldb::queue_id_t - GetQueueIDForThreadQAddress (Process *process, lldb::addr_t dispatch_qaddr) - { - return LLDB_INVALID_QUEUE_ID; - } +class PlatformList { +public: + PlatformList() : m_mutex(), m_platforms(), m_selected_platform_sp() {} - //------------------------------------------------------------------ - /// Provide a list of trap handler function names for this platform - /// - /// The unwinder needs to treat trap handlers specially -- the stack - /// frame may not be aligned correctly for a trap handler (the kernel - /// often won't perturb the stack pointer, or won't re-align it properly, - /// in the process of calling the handler) and the frame above the handler - /// needs to be treated by the unwinder's "frame 0" rules instead of its - /// "middle of the stack frame" rules. - /// - /// In a user process debugging scenario, the list of trap handlers is - /// typically just "_sigtramp". - /// - /// The Platform base class provides the m_trap_handlers ivar but it does - /// not populate it. Subclasses should add the names of the asynchronous - /// signal handler routines as needed. For most Unix platforms, add _sigtramp. - /// - /// @return - /// A list of symbol names. The list may be empty. - //------------------------------------------------------------------ - virtual const std::vector<ConstString> & - GetTrapHandlerSymbolNames (); - - //------------------------------------------------------------------ - /// Find a support executable that may not live within in the - /// standard locations related to LLDB. - /// - /// Executable might exist within the Platform SDK directories, or - /// in standard tool directories within the current IDE that is - /// running LLDB. - /// - /// @param[in] basename - /// The basename of the executable to locate in the current - /// platform. - /// - /// @return - /// A FileSpec pointing to the executable on disk, or an invalid - /// FileSpec if the executable cannot be found. - //------------------------------------------------------------------ - virtual FileSpec - LocateExecutable (const char *basename) - { - return FileSpec(); - } + ~PlatformList() = default; - //------------------------------------------------------------------ - /// Allow the platform to set preferred memory cache line size. If non-zero (and the user - /// has not set cache line size explicitly), this value will be used as the cache line - /// size for memory reads. - //------------------------------------------------------------------ - virtual uint32_t - GetDefaultMemoryCacheLineSize() { return 0; } - - //------------------------------------------------------------------ - /// Load a shared library into this process. - /// - /// Try and load a shared library into the current process. This - /// call might fail in the dynamic loader plug-in says it isn't safe - /// to try and load shared libraries at the moment. - /// - /// @param[in] process - /// The process to load the image. - /// - /// @param[in] local_file - /// The file spec that points to the shared library that you want - /// to load if the library is located on the host. The library will - /// be copied over to the location specified by remote_file or into - /// the current working directory with the same filename if the - /// remote_file isn't specified. - /// - /// @param[in] remote_file - /// If local_file is specified then the location where the library - /// should be copied over from the host. If local_file isn't - /// specified, then the path for the shared library on the target - /// what you want to load. - /// - /// @param[out] error - /// An error object that gets filled in with any errors that - /// might occur when trying to load the shared library. - /// - /// @return - /// A token that represents the shared library that can be - /// later used to unload the shared library. A value of - /// LLDB_INVALID_IMAGE_TOKEN will be returned if the shared - /// library can't be opened. - //------------------------------------------------------------------ - uint32_t - LoadImage (lldb_private::Process* process, - const lldb_private::FileSpec& local_file, - const lldb_private::FileSpec& remote_file, - lldb_private::Error& error); - - virtual uint32_t - DoLoadImage (lldb_private::Process* process, - const lldb_private::FileSpec& remote_file, - lldb_private::Error& error); - - virtual Error - UnloadImage (lldb_private::Process* process, uint32_t image_token); - - //------------------------------------------------------------------ - /// Connect to all processes waiting for a debugger to attach - /// - /// If the platform have a list of processes waiting for a debugger - /// to connect to them then connect to all of these pending processes. - /// - /// @param[in] debugger - /// The debugger used for the connect. - /// - /// @param[out] error - /// If an error occurred during the connect then this object will - /// contain the error message. - /// - /// @return - /// The number of processes we are succesfully connected to. - //------------------------------------------------------------------ - virtual size_t - ConnectToWaitingProcesses(lldb_private::Debugger& debugger, lldb_private::Error& error); - - protected: - bool m_is_host; - // Set to true when we are able to actually set the OS version while - // being connected. For remote platforms, we might set the version ahead - // of time before we actually connect and this version might change when - // we actually connect to a remote platform. For the host platform this - // will be set to the once we call HostInfo::GetOSVersion(). - bool m_os_version_set_while_connected; - bool m_system_arch_set_while_connected; - ConstString m_sdk_sysroot; // the root location of where the SDK files are all located - ConstString m_sdk_build; - FileSpec m_working_dir; // The working directory which is used when installing modules that have no install path set - std::string m_remote_url; - std::string m_name; - uint32_t m_major_os_version; - uint32_t m_minor_os_version; - uint32_t m_update_os_version; - ArchSpec m_system_arch; // The architecture of the kernel or the remote platform - typedef std::map<uint32_t, ConstString> IDToNameMap; - // Mutex for modifying Platform data structures that should only be used for non-reentrant code - std::mutex m_mutex; - IDToNameMap m_uid_map; - IDToNameMap m_gid_map; - size_t m_max_uid_name_len; - size_t m_max_gid_name_len; - bool m_supports_rsync; - std::string m_rsync_opts; - std::string m_rsync_prefix; - bool m_supports_ssh; - std::string m_ssh_opts; - bool m_ignores_remote_hostname; - std::string m_local_cache_directory; - std::vector<ConstString> m_trap_handlers; - bool m_calculated_trap_handlers; - const std::unique_ptr<ModuleCache> m_module_cache; - - //------------------------------------------------------------------ - /// Ask the Platform subclass to fill in the list of trap handler names - /// - /// For most Unix user process environments, this will be a single - /// function name, _sigtramp. More specialized environments may have - /// additional handler names. The unwinder code needs to know when a - /// trap handler is on the stack because the unwind rules for the frame - /// that caused the trap are different. - /// - /// The base class Platform ivar m_trap_handlers should be updated by - /// the Platform subclass when this method is called. If there are no - /// predefined trap handlers, this method may be a no-op. - //------------------------------------------------------------------ - virtual void - CalculateTrapHandlerSymbolNames () = 0; - - const char * - GetCachedUserName(uint32_t uid) - { - std::lock_guard<std::mutex> guard(m_mutex); - // return the empty string if our string is NULL - // so we can tell when things were in the negative - // cached (didn't find a valid user name, don't keep - // trying) - const auto pos = m_uid_map.find(uid); - return ((pos != m_uid_map.end()) ? pos->second.AsCString("") : nullptr); - } + void Append(const lldb::PlatformSP &platform_sp, bool set_selected) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + m_platforms.push_back(platform_sp); + if (set_selected) + m_selected_platform_sp = m_platforms.back(); + } - const char * - SetCachedUserName(uint32_t uid, const char *name, size_t name_len) - { - std::lock_guard<std::mutex> guard(m_mutex); - ConstString const_name(name); - m_uid_map[uid] = const_name; - if (m_max_uid_name_len < name_len) - m_max_uid_name_len = name_len; - // Const strings lives forever in our const string pool, so we can return the const char * - return const_name.GetCString(); - } + size_t GetSize() { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + return m_platforms.size(); + } - void - SetUserNameNotFound(uint32_t uid) - { - std::lock_guard<std::mutex> guard(m_mutex); - m_uid_map[uid] = ConstString(); + lldb::PlatformSP GetAtIndex(uint32_t idx) { + lldb::PlatformSP platform_sp; + { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + if (idx < m_platforms.size()) + platform_sp = m_platforms[idx]; + } + return platform_sp; + } + + //------------------------------------------------------------------ + /// Select the active platform. + /// + /// In order to debug remotely, other platform's can be remotely + /// connected to and set as the selected platform for any subsequent + /// debugging. This allows connection to remote targets and allows + /// the ability to discover process info, launch and attach to remote + /// processes. + //------------------------------------------------------------------ + lldb::PlatformSP GetSelectedPlatform() { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + if (!m_selected_platform_sp && !m_platforms.empty()) + m_selected_platform_sp = m_platforms.front(); + + return m_selected_platform_sp; + } + + void SetSelectedPlatform(const lldb::PlatformSP &platform_sp) { + if (platform_sp) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + const size_t num_platforms = m_platforms.size(); + for (size_t idx = 0; idx < num_platforms; ++idx) { + if (m_platforms[idx].get() == platform_sp.get()) { + m_selected_platform_sp = m_platforms[idx]; + return; } + } + m_platforms.push_back(platform_sp); + m_selected_platform_sp = m_platforms.back(); + } + } - void - ClearCachedUserNames() - { - std::lock_guard<std::mutex> guard(m_mutex); - m_uid_map.clear(); - } +protected: + typedef std::vector<lldb::PlatformSP> collection; + mutable std::recursive_mutex m_mutex; + collection m_platforms; + lldb::PlatformSP m_selected_platform_sp; - const char * - GetCachedGroupName(uint32_t gid) - { - std::lock_guard<std::mutex> guard(m_mutex); - // return the empty string if our string is NULL - // so we can tell when things were in the negative - // cached (didn't find a valid group name, don't keep - // trying) - const auto pos = m_gid_map.find(gid); - return ((pos != m_gid_map.end()) ? pos->second.AsCString("") : nullptr); - } +private: + DISALLOW_COPY_AND_ASSIGN(PlatformList); +}; - const char * - SetCachedGroupName(uint32_t gid, const char *name, size_t name_len) - { - std::lock_guard<std::mutex> guard(m_mutex); - ConstString const_name(name); - m_gid_map[gid] = const_name; - if (m_max_gid_name_len < name_len) - m_max_gid_name_len = name_len; - // Const strings lives forever in our const string pool, so we can return the const char * - return const_name.GetCString(); - } +class OptionGroupPlatformRSync : public lldb_private::OptionGroup { +public: + OptionGroupPlatformRSync() = default; - void - SetGroupNameNotFound(uint32_t gid) - { - std::lock_guard<std::mutex> guard(m_mutex); - m_gid_map[gid] = ConstString(); - } + ~OptionGroupPlatformRSync() override = default; - void - ClearCachedGroupNames() - { - std::lock_guard<std::mutex> guard(m_mutex); - m_gid_map.clear(); - } + lldb_private::Error + SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, + ExecutionContext *execution_context) override; - Error - GetCachedExecutable (ModuleSpec &module_spec, - lldb::ModuleSP &module_sp, - const FileSpecList *module_search_paths_ptr, - Platform &remote_platform); + void OptionParsingStarting(ExecutionContext *execution_context) override; - virtual Error - DownloadModuleSlice (const FileSpec& src_file_spec, - const uint64_t src_offset, - const uint64_t src_size, - const FileSpec& dst_file_spec); - - virtual Error - DownloadSymbolFile (const lldb::ModuleSP& module_sp, - const FileSpec& dst_file_spec); - - virtual const char * - GetCacheHostname (); - - private: - typedef std::function<Error (const ModuleSpec &)> ModuleResolver; - - Error - GetRemoteSharedModule (const ModuleSpec &module_spec, - Process* process, - lldb::ModuleSP &module_sp, - const ModuleResolver &module_resolver, - bool *did_create_ptr); - - bool - GetCachedSharedModule (const ModuleSpec& module_spec, - lldb::ModuleSP &module_sp, - bool *did_create_ptr); - - Error - LoadCachedExecutable (const ModuleSpec &module_spec, - lldb::ModuleSP &module_sp, - const FileSpecList *module_search_paths_ptr, - Platform &remote_platform); + llvm::ArrayRef<OptionDefinition> GetDefinitions() override; - FileSpec - GetModuleCacheRoot (); + // Options table: Required for subclasses of Options. - DISALLOW_COPY_AND_ASSIGN (Platform); - }; + static lldb_private::OptionDefinition g_option_table[]; - class PlatformList - { - public: - PlatformList() : m_mutex(), m_platforms(), m_selected_platform_sp() {} - - ~PlatformList() = default; - - void - Append(const lldb::PlatformSP &platform_sp, bool set_selected) - { - std::lock_guard<std::recursive_mutex> guard(m_mutex); - m_platforms.push_back(platform_sp); - if (set_selected) - m_selected_platform_sp = m_platforms.back(); - } + // Instance variables to hold the values for command options. - size_t - GetSize() - { - std::lock_guard<std::recursive_mutex> guard(m_mutex); - return m_platforms.size(); - } + bool m_rsync; + std::string m_rsync_opts; + std::string m_rsync_prefix; + bool m_ignores_remote_hostname; - lldb::PlatformSP - GetAtIndex(uint32_t idx) - { - lldb::PlatformSP platform_sp; - { - std::lock_guard<std::recursive_mutex> guard(m_mutex); - if (idx < m_platforms.size()) - platform_sp = m_platforms[idx]; - } - return platform_sp; - } +private: + DISALLOW_COPY_AND_ASSIGN(OptionGroupPlatformRSync); +}; - //------------------------------------------------------------------ - /// Select the active platform. - /// - /// In order to debug remotely, other platform's can be remotely - /// connected to and set as the selected platform for any subsequent - /// debugging. This allows connection to remote targets and allows - /// the ability to discover process info, launch and attach to remote - /// processes. - //------------------------------------------------------------------ - lldb::PlatformSP - GetSelectedPlatform() - { - std::lock_guard<std::recursive_mutex> guard(m_mutex); - if (!m_selected_platform_sp && !m_platforms.empty()) - m_selected_platform_sp = m_platforms.front(); - - return m_selected_platform_sp; - } +class OptionGroupPlatformSSH : public lldb_private::OptionGroup { +public: + OptionGroupPlatformSSH() = default; - void - SetSelectedPlatform(const lldb::PlatformSP &platform_sp) - { - if (platform_sp) - { - std::lock_guard<std::recursive_mutex> guard(m_mutex); - const size_t num_platforms = m_platforms.size(); - for (size_t idx = 0; idx < num_platforms; ++idx) - { - if (m_platforms[idx].get() == platform_sp.get()) - { - m_selected_platform_sp = m_platforms[idx]; - return; - } - } - m_platforms.push_back(platform_sp); - m_selected_platform_sp = m_platforms.back(); - } - } + ~OptionGroupPlatformSSH() override = default; - protected: - typedef std::vector<lldb::PlatformSP> collection; - mutable std::recursive_mutex m_mutex; - collection m_platforms; - lldb::PlatformSP m_selected_platform_sp; + lldb_private::Error + SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, + ExecutionContext *execution_context) override; - private: - DISALLOW_COPY_AND_ASSIGN (PlatformList); - }; + void OptionParsingStarting(ExecutionContext *execution_context) override; + + llvm::ArrayRef<OptionDefinition> GetDefinitions() override; + + // Options table: Required for subclasses of Options. + + static lldb_private::OptionDefinition g_option_table[]; + + // Instance variables to hold the values for command options. + + bool m_ssh; + std::string m_ssh_opts; + +private: + DISALLOW_COPY_AND_ASSIGN(OptionGroupPlatformSSH); +}; + +class OptionGroupPlatformCaching : public lldb_private::OptionGroup { +public: + OptionGroupPlatformCaching() = default; + + ~OptionGroupPlatformCaching() override = default; + + lldb_private::Error + SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, + ExecutionContext *execution_context) override; + + void OptionParsingStarting(ExecutionContext *execution_context) override; + + llvm::ArrayRef<OptionDefinition> GetDefinitions() override; + + // Options table: Required for subclasses of Options. + + static lldb_private::OptionDefinition g_option_table[]; + + // Instance variables to hold the values for command options. + + std::string m_cache_dir; + +private: + DISALLOW_COPY_AND_ASSIGN(OptionGroupPlatformCaching); +}; - class OptionGroupPlatformRSync : public lldb_private::OptionGroup - { - public: - OptionGroupPlatformRSync() = default; - - ~OptionGroupPlatformRSync() override = default; - - lldb_private::Error - SetOptionValue(CommandInterpreter &interpreter, - uint32_t option_idx, - const char *option_value) override; - - void - OptionParsingStarting(CommandInterpreter &interpreter) override; - - const lldb_private::OptionDefinition* - GetDefinitions() override; - - uint32_t - GetNumDefinitions() override; - - // Options table: Required for subclasses of Options. - - static lldb_private::OptionDefinition g_option_table[]; - - // Instance variables to hold the values for command options. - - bool m_rsync; - std::string m_rsync_opts; - std::string m_rsync_prefix; - bool m_ignores_remote_hostname; - - private: - DISALLOW_COPY_AND_ASSIGN(OptionGroupPlatformRSync); - }; - - class OptionGroupPlatformSSH : public lldb_private::OptionGroup - { - public: - OptionGroupPlatformSSH() = default; - - ~OptionGroupPlatformSSH() override = default; - - lldb_private::Error - SetOptionValue(CommandInterpreter &interpreter, - uint32_t option_idx, - const char *option_value) override; - - void - OptionParsingStarting(CommandInterpreter &interpreter) override; - - uint32_t - GetNumDefinitions() override; - - const lldb_private::OptionDefinition* - GetDefinitions() override; - - // Options table: Required for subclasses of Options. - - static lldb_private::OptionDefinition g_option_table[]; - - // Instance variables to hold the values for command options. - - bool m_ssh; - std::string m_ssh_opts; - - private: - DISALLOW_COPY_AND_ASSIGN(OptionGroupPlatformSSH); - }; - - class OptionGroupPlatformCaching : public lldb_private::OptionGroup - { - public: - OptionGroupPlatformCaching() = default; - - ~OptionGroupPlatformCaching() override = default; - - lldb_private::Error - SetOptionValue(CommandInterpreter &interpreter, - uint32_t option_idx, - const char *option_value) override; - - void - OptionParsingStarting(CommandInterpreter &interpreter) override; - - uint32_t - GetNumDefinitions() override; - - const lldb_private::OptionDefinition* - GetDefinitions() override; - - // Options table: Required for subclasses of Options. - - static lldb_private::OptionDefinition g_option_table[]; - - // Instance variables to hold the values for command options. - - std::string m_cache_dir; - - private: - DISALLOW_COPY_AND_ASSIGN(OptionGroupPlatformCaching); - }; - } // namespace lldb_private #endif // liblldb_Platform_h_ diff --git a/include/lldb/Target/Process.h b/include/lldb/Target/Process.h index 57787f2f8f39..251dfe6a17c0 100644 --- a/include/lldb/Target/Process.h +++ b/include/lldb/Target/Process.h @@ -16,16 +16,17 @@ #include <limits.h> // C++ Includes +#include <chrono> #include <list> #include <memory> #include <mutex> #include <string> -#include <vector> #include <unordered_set> +#include <vector> // Other libraries and framework includes // Project includes -#include "lldb/lldb-private.h" +#include "lldb/Breakpoint/BreakpointSiteList.h" #include "lldb/Core/ArchSpec.h" #include "lldb/Core/Broadcaster.h" #include "lldb/Core/Communication.h" @@ -33,88 +34,74 @@ #include "lldb/Core/Event.h" #include "lldb/Core/Listener.h" #include "lldb/Core/LoadedModuleInfoList.h" -#include "lldb/Core/ThreadSafeValue.h" #include "lldb/Core/PluginInterface.h" #include "lldb/Core/StructuredData.h" +#include "lldb/Core/ThreadSafeValue.h" #include "lldb/Core/UserSettingsController.h" -#include "lldb/Breakpoint/BreakpointSiteList.h" #include "lldb/Host/HostThread.h" #include "lldb/Host/ProcessRunLock.h" #include "lldb/Interpreter/Options.h" #include "lldb/Target/ExecutionContextScope.h" +#include "lldb/Target/InstrumentationRuntime.h" #include "lldb/Target/Memory.h" #include "lldb/Target/ProcessInfo.h" #include "lldb/Target/ProcessLaunchInfo.h" #include "lldb/Target/QueueList.h" #include "lldb/Target/ThreadList.h" -#include "lldb/Target/InstrumentationRuntime.h" +#include "lldb/lldb-private.h" + +#include "llvm/ADT/ArrayRef.h" namespace lldb_private { -template <typename B, typename S> -struct Range; +template <typename B, typename S> struct Range; //---------------------------------------------------------------------- // ProcessProperties //---------------------------------------------------------------------- -class ProcessProperties : public Properties -{ +class ProcessProperties : public Properties { public: - // Pass nullptr for "process" if the ProcessProperties are to be the global copy - ProcessProperties (lldb_private::Process *process); - - ~ProcessProperties() override; - - bool - GetDisableMemoryCache() const; - - uint64_t - GetMemoryCacheLineSize () const; - - Args - GetExtraStartupCommands () const; - - void - SetExtraStartupCommands (const Args &args); - - FileSpec - GetPythonOSPluginPath () const; - - void - SetPythonOSPluginPath (const FileSpec &file); - - bool - GetIgnoreBreakpointsInExpressions () const; - - void - SetIgnoreBreakpointsInExpressions (bool ignore); - - bool - GetUnwindOnErrorInExpressions () const; - - void - SetUnwindOnErrorInExpressions (bool ignore); - - bool - GetStopOnSharedLibraryEvents () const; - - void - SetStopOnSharedLibraryEvents (bool stop); - - bool - GetDetachKeepsStopped () const; - - void - SetDetachKeepsStopped (bool keep_stopped); - - bool - GetWarningsOptimization () const; + // Pass nullptr for "process" if the ProcessProperties are to be the global + // copy + ProcessProperties(lldb_private::Process *process); + + ~ProcessProperties() override; + + bool GetDisableMemoryCache() const; + + uint64_t GetMemoryCacheLineSize() const; + + Args GetExtraStartupCommands() const; + + void SetExtraStartupCommands(const Args &args); + + FileSpec GetPythonOSPluginPath() const; + + void SetPythonOSPluginPath(const FileSpec &file); + + bool GetIgnoreBreakpointsInExpressions() const; + + void SetIgnoreBreakpointsInExpressions(bool ignore); + + bool GetUnwindOnErrorInExpressions() const; + + void SetUnwindOnErrorInExpressions(bool ignore); + + bool GetStopOnSharedLibraryEvents() const; + + void SetStopOnSharedLibraryEvents(bool stop); + + bool GetDetachKeepsStopped() const; + + void SetDetachKeepsStopped(bool keep_stopped); + + bool GetWarningsOptimization() const; protected: - static void - OptionValueChangedCallback (void *baton, OptionValue *option_value); + static void OptionValueChangedCallback(void *baton, + OptionValue *option_value); - Process * m_process; // Can be nullptr for global ProcessProperties + Process *m_process; // Can be nullptr for global ProcessProperties }; typedef std::shared_ptr<ProcessProperties> ProcessPropertiesSP; @@ -125,103 +112,55 @@ typedef std::shared_ptr<ProcessProperties> ProcessPropertiesSP; // Describes an existing process and any discoverable information that // pertains to that process. //---------------------------------------------------------------------- -class ProcessInstanceInfo : public ProcessInfo -{ +class ProcessInstanceInfo : public ProcessInfo { public: - ProcessInstanceInfo () : - ProcessInfo (), - m_euid (UINT32_MAX), - m_egid (UINT32_MAX), - m_parent_pid (LLDB_INVALID_PROCESS_ID) - { - } + ProcessInstanceInfo() + : ProcessInfo(), m_euid(UINT32_MAX), m_egid(UINT32_MAX), + m_parent_pid(LLDB_INVALID_PROCESS_ID) {} - ProcessInstanceInfo (const char *name, - const ArchSpec &arch, - lldb::pid_t pid) : - ProcessInfo (name, arch, pid), - m_euid (UINT32_MAX), - m_egid (UINT32_MAX), - m_parent_pid (LLDB_INVALID_PROCESS_ID) - { - } - - void - Clear () - { - ProcessInfo::Clear(); - m_euid = UINT32_MAX; - m_egid = UINT32_MAX; - m_parent_pid = LLDB_INVALID_PROCESS_ID; - } - - uint32_t - GetEffectiveUserID() const - { - return m_euid; - } + ProcessInstanceInfo(const char *name, const ArchSpec &arch, lldb::pid_t pid) + : ProcessInfo(name, arch, pid), m_euid(UINT32_MAX), m_egid(UINT32_MAX), + m_parent_pid(LLDB_INVALID_PROCESS_ID) {} - uint32_t - GetEffectiveGroupID() const - { - return m_egid; - } - - bool - EffectiveUserIDIsValid () const - { - return m_euid != UINT32_MAX; - } + void Clear() { + ProcessInfo::Clear(); + m_euid = UINT32_MAX; + m_egid = UINT32_MAX; + m_parent_pid = LLDB_INVALID_PROCESS_ID; + } - bool - EffectiveGroupIDIsValid () const - { - return m_egid != UINT32_MAX; - } + uint32_t GetEffectiveUserID() const { return m_euid; } - void - SetEffectiveUserID (uint32_t uid) - { - m_euid = uid; - } - - void - SetEffectiveGroupID (uint32_t gid) - { - m_egid = gid; - } + uint32_t GetEffectiveGroupID() const { return m_egid; } - lldb::pid_t - GetParentProcessID () const - { - return m_parent_pid; - } - - void - SetParentProcessID (lldb::pid_t pid) - { - m_parent_pid = pid; - } - - bool - ParentProcessIDIsValid() const - { - return m_parent_pid != LLDB_INVALID_PROCESS_ID; - } - - void - Dump (Stream &s, Platform *platform) const; + bool EffectiveUserIDIsValid() const { return m_euid != UINT32_MAX; } + + bool EffectiveGroupIDIsValid() const { return m_egid != UINT32_MAX; } + + void SetEffectiveUserID(uint32_t uid) { m_euid = uid; } + + void SetEffectiveGroupID(uint32_t gid) { m_egid = gid; } + + lldb::pid_t GetParentProcessID() const { return m_parent_pid; } + + void SetParentProcessID(lldb::pid_t pid) { m_parent_pid = pid; } - static void - DumpTableHeader (Stream &s, Platform *platform, bool show_args, bool verbose); + bool ParentProcessIDIsValid() const { + return m_parent_pid != LLDB_INVALID_PROCESS_ID; + } + + void Dump(Stream &s, Platform *platform) const; + + static void DumpTableHeader(Stream &s, Platform *platform, bool show_args, + bool verbose); + + void DumpAsTableRow(Stream &s, Platform *platform, bool show_args, + bool verbose) const; - void - DumpAsTableRow (Stream &s, Platform *platform, bool show_args, bool verbose) const; - protected: - uint32_t m_euid; - uint32_t m_egid; - lldb::pid_t m_parent_pid; + uint32_t m_euid; + uint32_t m_egid; + lldb::pid_t m_parent_pid; }; //---------------------------------------------------------------------- @@ -229,230 +168,132 @@ protected: // // Describes any information that is required to attach to a process. //---------------------------------------------------------------------- - -class ProcessAttachInfo : public ProcessInstanceInfo -{ + +class ProcessAttachInfo : public ProcessInstanceInfo { public: - ProcessAttachInfo() : - ProcessInstanceInfo(), - m_listener_sp(), - m_hijack_listener_sp(), - m_plugin_name (), - m_resume_count (0), - m_wait_for_launch (false), - m_ignore_existing (true), - m_continue_once_attached (false), - m_detach_on_error (true), - m_async (false) - { - } + ProcessAttachInfo() + : ProcessInstanceInfo(), m_listener_sp(), m_hijack_listener_sp(), + m_plugin_name(), m_resume_count(0), m_wait_for_launch(false), + m_ignore_existing(true), m_continue_once_attached(false), + m_detach_on_error(true), m_async(false) {} - ProcessAttachInfo (const ProcessLaunchInfo &launch_info) : - ProcessInstanceInfo(), - m_listener_sp(), - m_hijack_listener_sp(), - m_plugin_name (), - m_resume_count (0), - m_wait_for_launch (false), - m_ignore_existing (true), - m_continue_once_attached (false), - m_detach_on_error (true), - m_async (false) - { - ProcessInfo::operator= (launch_info); - SetProcessPluginName (launch_info.GetProcessPluginName()); - SetResumeCount (launch_info.GetResumeCount()); - SetListener(launch_info.GetListener()); - SetHijackListener(launch_info.GetHijackListener()); - m_detach_on_error = launch_info.GetDetachOnError(); - } - - bool - GetWaitForLaunch () const - { - return m_wait_for_launch; - } - - void - SetWaitForLaunch (bool b) - { - m_wait_for_launch = b; - } + ProcessAttachInfo(const ProcessLaunchInfo &launch_info) + : ProcessInstanceInfo(), m_listener_sp(), m_hijack_listener_sp(), + m_plugin_name(), m_resume_count(0), m_wait_for_launch(false), + m_ignore_existing(true), m_continue_once_attached(false), + m_detach_on_error(true), m_async(false) { + ProcessInfo::operator=(launch_info); + SetProcessPluginName(launch_info.GetProcessPluginName()); + SetResumeCount(launch_info.GetResumeCount()); + SetListener(launch_info.GetListener()); + SetHijackListener(launch_info.GetHijackListener()); + m_detach_on_error = launch_info.GetDetachOnError(); + } - bool - GetAsync () const - { - return m_async; - } + bool GetWaitForLaunch() const { return m_wait_for_launch; } - void - SetAsync (bool b) - { - m_async = b; - } + void SetWaitForLaunch(bool b) { m_wait_for_launch = b; } - bool - GetIgnoreExisting () const - { - return m_ignore_existing; - } - - void - SetIgnoreExisting (bool b) - { - m_ignore_existing = b; - } + bool GetAsync() const { return m_async; } - bool - GetContinueOnceAttached () const - { - return m_continue_once_attached; - } - - void - SetContinueOnceAttached (bool b) - { - m_continue_once_attached = b; - } + void SetAsync(bool b) { m_async = b; } - uint32_t - GetResumeCount () const - { - return m_resume_count; - } - - void - SetResumeCount (uint32_t c) - { - m_resume_count = c; - } - - const char * - GetProcessPluginName () const - { - return (m_plugin_name.empty() ? nullptr : m_plugin_name.c_str()); - } - - void - SetProcessPluginName (const char *plugin) - { - if (plugin && plugin[0]) - m_plugin_name.assign (plugin); - else - m_plugin_name.clear(); - } + bool GetIgnoreExisting() const { return m_ignore_existing; } - void - Clear () - { - ProcessInstanceInfo::Clear(); - m_plugin_name.clear(); - m_resume_count = 0; - m_wait_for_launch = false; - m_ignore_existing = true; - m_continue_once_attached = false; - } + void SetIgnoreExisting(bool b) { m_ignore_existing = b; } - bool - ProcessInfoSpecified () const - { - if (GetExecutableFile()) - return true; - if (GetProcessID() != LLDB_INVALID_PROCESS_ID) - return true; - if (GetParentProcessID() != LLDB_INVALID_PROCESS_ID) - return true; - return false; - } - - lldb::ListenerSP - GetHijackListener () const - { - return m_hijack_listener_sp; - } - - void - SetHijackListener (const lldb::ListenerSP &listener_sp) - { - m_hijack_listener_sp = listener_sp; - } - - bool - GetDetachOnError () const - { - return m_detach_on_error; - } - - void - SetDetachOnError (bool enable) - { - m_detach_on_error = enable; - } + bool GetContinueOnceAttached() const { return m_continue_once_attached; } - // Get and set the actual listener that will be used for the process events - lldb::ListenerSP - GetListener () const - { - return m_listener_sp; - } + void SetContinueOnceAttached(bool b) { m_continue_once_attached = b; } - void - SetListener (const lldb::ListenerSP &listener_sp) - { - m_listener_sp = listener_sp; - } + uint32_t GetResumeCount() const { return m_resume_count; } + + void SetResumeCount(uint32_t c) { m_resume_count = c; } + + const char *GetProcessPluginName() const { + return (m_plugin_name.empty() ? nullptr : m_plugin_name.c_str()); + } + + void SetProcessPluginName(llvm::StringRef plugin) { m_plugin_name = plugin; } - lldb::ListenerSP - GetListenerForProcess (Debugger &debugger); + void Clear() { + ProcessInstanceInfo::Clear(); + m_plugin_name.clear(); + m_resume_count = 0; + m_wait_for_launch = false; + m_ignore_existing = true; + m_continue_once_attached = false; + } + + bool ProcessInfoSpecified() const { + if (GetExecutableFile()) + return true; + if (GetProcessID() != LLDB_INVALID_PROCESS_ID) + return true; + if (GetParentProcessID() != LLDB_INVALID_PROCESS_ID) + return true; + return false; + } + + lldb::ListenerSP GetHijackListener() const { return m_hijack_listener_sp; } + + void SetHijackListener(const lldb::ListenerSP &listener_sp) { + m_hijack_listener_sp = listener_sp; + } + + bool GetDetachOnError() const { return m_detach_on_error; } + + void SetDetachOnError(bool enable) { m_detach_on_error = enable; } + + // Get and set the actual listener that will be used for the process events + lldb::ListenerSP GetListener() const { return m_listener_sp; } + + void SetListener(const lldb::ListenerSP &listener_sp) { + m_listener_sp = listener_sp; + } + + lldb::ListenerSP GetListenerForProcess(Debugger &debugger); protected: - lldb::ListenerSP m_listener_sp; - lldb::ListenerSP m_hijack_listener_sp; - std::string m_plugin_name; - uint32_t m_resume_count; // How many times do we resume after launching - bool m_wait_for_launch; - bool m_ignore_existing; - bool m_continue_once_attached; // Supports the use-case scenario of immediately continuing the process once attached. - bool m_detach_on_error; // If we are debugging remotely, instruct the stub to detach rather than killing the target on error. - bool m_async; // Use an async attach where we start the attach and return immediately (used by GUI programs with --waitfor so they can call SBProcess::Stop() to cancel attach) + lldb::ListenerSP m_listener_sp; + lldb::ListenerSP m_hijack_listener_sp; + std::string m_plugin_name; + uint32_t m_resume_count; // How many times do we resume after launching + bool m_wait_for_launch; + bool m_ignore_existing; + bool m_continue_once_attached; // Supports the use-case scenario of + // immediately continuing the process once + // attached. + bool m_detach_on_error; // If we are debugging remotely, instruct the stub to + // detach rather than killing the target on error. + bool m_async; // Use an async attach where we start the attach and return + // immediately (used by GUI programs with --waitfor so they can + // call SBProcess::Stop() to cancel attach) }; -class ProcessLaunchCommandOptions : public Options -{ +class ProcessLaunchCommandOptions : public Options { public: - ProcessLaunchCommandOptions (CommandInterpreter &interpreter) : - Options(interpreter) - { - // Keep default values of all options in one place: OptionParsingStarting () - OptionParsingStarting (); - } + ProcessLaunchCommandOptions() : Options() { + // Keep default values of all options in one place: OptionParsingStarting () + OptionParsingStarting(nullptr); + } - ~ProcessLaunchCommandOptions() override = default; + ~ProcessLaunchCommandOptions() override = default; - Error - SetOptionValue (uint32_t option_idx, const char *option_arg) override; - - void - OptionParsingStarting() override - { - launch_info.Clear(); - disable_aslr = eLazyBoolCalculate; - } - - 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. - - ProcessLaunchInfo launch_info; - lldb_private::LazyBool disable_aslr; + Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override; + + void OptionParsingStarting(ExecutionContext *execution_context) override { + launch_info.Clear(); + disable_aslr = eLazyBoolCalculate; + } + + llvm::ArrayRef<OptionDefinition> GetDefinitions() override; + + // Instance variables to hold the values for command options. + + ProcessLaunchInfo launch_info; + lldb_private::LazyBool disable_aslr; }; //---------------------------------------------------------------------- @@ -461,3129 +302,2874 @@ public: // A class to help matching one ProcessInstanceInfo to another. //---------------------------------------------------------------------- -class ProcessInstanceInfoMatch -{ +class ProcessInstanceInfoMatch { public: - ProcessInstanceInfoMatch () : - m_match_info (), - m_name_match_type (eNameMatchIgnore), - m_match_all_users (false) - { - } + ProcessInstanceInfoMatch() + : m_match_info(), m_name_match_type(eNameMatchIgnore), + m_match_all_users(false) {} - ProcessInstanceInfoMatch (const char *process_name, - NameMatchType process_name_match_type) : - m_match_info (), - m_name_match_type (process_name_match_type), - m_match_all_users (false) - { - m_match_info.GetExecutableFile().SetFile(process_name, false); - } + ProcessInstanceInfoMatch(const char *process_name, + NameMatchType process_name_match_type) + : m_match_info(), m_name_match_type(process_name_match_type), + m_match_all_users(false) { + m_match_info.GetExecutableFile().SetFile(process_name, false); + } - ProcessInstanceInfo & - GetProcessInfo () - { - return m_match_info; - } + ProcessInstanceInfo &GetProcessInfo() { return m_match_info; } - const ProcessInstanceInfo & - GetProcessInfo () const - { - return m_match_info; - } - - bool - GetMatchAllUsers () const - { - return m_match_all_users; - } + const ProcessInstanceInfo &GetProcessInfo() const { return m_match_info; } - void - SetMatchAllUsers (bool b) - { - m_match_all_users = b; - } + bool GetMatchAllUsers() const { return m_match_all_users; } - NameMatchType - GetNameMatchType () const - { - return m_name_match_type; - } + void SetMatchAllUsers(bool b) { m_match_all_users = b; } - void - SetNameMatchType (NameMatchType name_match_type) - { - m_name_match_type = name_match_type; - } - - bool - NameMatches (const char *process_name) const; + NameMatchType GetNameMatchType() const { return m_name_match_type; } + + void SetNameMatchType(NameMatchType name_match_type) { + m_name_match_type = name_match_type; + } - bool - Matches (const ProcessInstanceInfo &proc_info) const; + bool NameMatches(const char *process_name) const; - bool - MatchAllProcesses () const; - void - Clear (); + bool Matches(const ProcessInstanceInfo &proc_info) const; + + bool MatchAllProcesses() const; + void Clear(); protected: - ProcessInstanceInfo m_match_info; - NameMatchType m_name_match_type; - bool m_match_all_users; + ProcessInstanceInfo m_match_info; + NameMatchType m_name_match_type; + bool m_match_all_users; }; -class ProcessInstanceInfoList -{ +class ProcessInstanceInfoList { public: - ProcessInstanceInfoList() = default; + ProcessInstanceInfoList() = default; - void - Clear() - { - m_infos.clear(); - } - - size_t - GetSize() - { - return m_infos.size(); - } - - void - Append (const ProcessInstanceInfo &info) - { - m_infos.push_back (info); - } + void Clear() { m_infos.clear(); } - const char * - GetProcessNameAtIndex (size_t idx) - { - return ((idx < m_infos.size()) ? m_infos[idx].GetName() : nullptr); - } + size_t GetSize() { return m_infos.size(); } - size_t - GetProcessNameLengthAtIndex (size_t idx) - { - return ((idx < m_infos.size()) ? m_infos[idx].GetNameLength() : 0); - } + void Append(const ProcessInstanceInfo &info) { m_infos.push_back(info); } - lldb::pid_t - GetProcessIDAtIndex (size_t idx) - { - return ((idx < m_infos.size()) ? m_infos[idx].GetProcessID() : 0); - } + const char *GetProcessNameAtIndex(size_t idx) { + return ((idx < m_infos.size()) ? m_infos[idx].GetName() : nullptr); + } - bool - GetInfoAtIndex (size_t idx, ProcessInstanceInfo &info) - { - if (idx < m_infos.size()) - { - info = m_infos[idx]; - return true; - } - return false; - } - - // You must ensure "idx" is valid before calling this function - const ProcessInstanceInfo & - GetProcessInfoAtIndex (size_t idx) const - { - assert (idx < m_infos.size()); - return m_infos[idx]; + size_t GetProcessNameLengthAtIndex(size_t idx) { + return ((idx < m_infos.size()) ? m_infos[idx].GetNameLength() : 0); + } + + lldb::pid_t GetProcessIDAtIndex(size_t idx) { + return ((idx < m_infos.size()) ? m_infos[idx].GetProcessID() : 0); + } + + bool GetInfoAtIndex(size_t idx, ProcessInstanceInfo &info) { + if (idx < m_infos.size()) { + info = m_infos[idx]; + return true; } - + return false; + } + + // You must ensure "idx" is valid before calling this function + const ProcessInstanceInfo &GetProcessInfoAtIndex(size_t idx) const { + assert(idx < m_infos.size()); + return m_infos[idx]; + } + protected: - typedef std::vector<ProcessInstanceInfo> collection; - collection m_infos; + typedef std::vector<ProcessInstanceInfo> collection; + collection m_infos; }; -// This class tracks the Modification state of the process. Things that can currently modify -// the program are running the program (which will up the StopID) and writing memory (which -// will up the MemoryID.) +// This class tracks the Modification state of the process. Things that can +// currently modify +// the program are running the program (which will up the StopID) and writing +// memory (which +// will up the MemoryID.) // FIXME: Should we also include modification of register states? -class ProcessModID -{ - friend bool operator== (const ProcessModID &lhs, const ProcessModID &rhs); +class ProcessModID { + friend bool operator==(const ProcessModID &lhs, const ProcessModID &rhs); + public: - ProcessModID () : - m_stop_id (0), - m_last_natural_stop_id(0), - m_resume_id (0), - m_memory_id (0), - m_last_user_expression_resume (0), - m_running_user_expression (false) - {} - - ProcessModID (const ProcessModID &rhs) : - m_stop_id (rhs.m_stop_id), - m_memory_id (rhs.m_memory_id) - {} - - const ProcessModID & operator= (const ProcessModID &rhs) - { - if (this != &rhs) - { - m_stop_id = rhs.m_stop_id; - m_memory_id = rhs.m_memory_id; - } - return *this; - } - - ~ProcessModID() = default; - - void BumpStopID () { - m_stop_id++; - if (!IsLastResumeForUserExpression()) - m_last_natural_stop_id++; - } - - void BumpMemoryID () { m_memory_id++; } - - void BumpResumeID () { - m_resume_id++; - if (m_running_user_expression > 0) - m_last_user_expression_resume = m_resume_id; - } - - uint32_t GetStopID() const { return m_stop_id; } - uint32_t GetLastNaturalStopID() const { return m_last_natural_stop_id; } - uint32_t GetMemoryID () const { return m_memory_id; } - uint32_t GetResumeID () const { return m_resume_id; } - uint32_t GetLastUserExpressionResumeID () const { return m_last_user_expression_resume; } - - bool MemoryIDEqual (const ProcessModID &compare) const - { - return m_memory_id == compare.m_memory_id; - } - - bool StopIDEqual (const ProcessModID &compare) const - { - return m_stop_id == compare.m_stop_id; - } - - void SetInvalid () - { - m_stop_id = UINT32_MAX; - } - - bool IsValid () const - { - return m_stop_id != UINT32_MAX; - } - - bool - IsLastResumeForUserExpression () const - { - // If we haven't yet resumed the target, then it can't be for a user expression... - if (m_resume_id == 0) - return false; - - return m_resume_id == m_last_user_expression_resume; - } - - void - SetRunningUserExpression (bool on) - { - if (on) - m_running_user_expression++; - else - m_running_user_expression--; - } + ProcessModID() + : m_stop_id(0), m_last_natural_stop_id(0), m_resume_id(0), m_memory_id(0), + m_last_user_expression_resume(0), m_running_user_expression(false) {} - void - SetStopEventForLastNaturalStopID (lldb::EventSP event_sp) - { - m_last_natural_stop_event = event_sp; - } + ProcessModID(const ProcessModID &rhs) + : m_stop_id(rhs.m_stop_id), m_memory_id(rhs.m_memory_id) {} - lldb::EventSP GetStopEventForStopID (uint32_t stop_id) const - { - if (stop_id == m_last_natural_stop_id) - return m_last_natural_stop_event; - return lldb::EventSP(); + const ProcessModID &operator=(const ProcessModID &rhs) { + if (this != &rhs) { + m_stop_id = rhs.m_stop_id; + m_memory_id = rhs.m_memory_id; } + return *this; + } + + ~ProcessModID() = default; + + void BumpStopID() { + m_stop_id++; + if (!IsLastResumeForUserExpression()) + m_last_natural_stop_id++; + } + + void BumpMemoryID() { m_memory_id++; } + + void BumpResumeID() { + m_resume_id++; + if (m_running_user_expression > 0) + m_last_user_expression_resume = m_resume_id; + } + + uint32_t GetStopID() const { return m_stop_id; } + uint32_t GetLastNaturalStopID() const { return m_last_natural_stop_id; } + uint32_t GetMemoryID() const { return m_memory_id; } + uint32_t GetResumeID() const { return m_resume_id; } + uint32_t GetLastUserExpressionResumeID() const { + return m_last_user_expression_resume; + } + + bool MemoryIDEqual(const ProcessModID &compare) const { + return m_memory_id == compare.m_memory_id; + } + + bool StopIDEqual(const ProcessModID &compare) const { + return m_stop_id == compare.m_stop_id; + } + + void SetInvalid() { m_stop_id = UINT32_MAX; } + + bool IsValid() const { return m_stop_id != UINT32_MAX; } + + bool IsLastResumeForUserExpression() const { + // If we haven't yet resumed the target, then it can't be for a user + // expression... + if (m_resume_id == 0) + return false; + + return m_resume_id == m_last_user_expression_resume; + } + + void SetRunningUserExpression(bool on) { + if (on) + m_running_user_expression++; + else + m_running_user_expression--; + } + + void SetStopEventForLastNaturalStopID(lldb::EventSP event_sp) { + m_last_natural_stop_event = event_sp; + } + + lldb::EventSP GetStopEventForStopID(uint32_t stop_id) const { + if (stop_id == m_last_natural_stop_id) + return m_last_natural_stop_event; + return lldb::EventSP(); + } private: - uint32_t m_stop_id; - uint32_t m_last_natural_stop_id; - uint32_t m_resume_id; - uint32_t m_memory_id; - uint32_t m_last_user_expression_resume; - uint32_t m_running_user_expression; - lldb::EventSP m_last_natural_stop_event; + uint32_t m_stop_id; + uint32_t m_last_natural_stop_id; + uint32_t m_resume_id; + uint32_t m_memory_id; + uint32_t m_last_user_expression_resume; + uint32_t m_running_user_expression; + lldb::EventSP m_last_natural_stop_event; }; -inline bool operator== (const ProcessModID &lhs, const ProcessModID &rhs) -{ - if (lhs.StopIDEqual (rhs) - && lhs.MemoryIDEqual (rhs)) - return true; - else - return false; +inline bool operator==(const ProcessModID &lhs, const ProcessModID &rhs) { + if (lhs.StopIDEqual(rhs) && lhs.MemoryIDEqual(rhs)) + return true; + else + return false; } -inline bool operator!= (const ProcessModID &lhs, const ProcessModID &rhs) -{ - return (!lhs.StopIDEqual (rhs) || !lhs.MemoryIDEqual (rhs)); +inline bool operator!=(const ProcessModID &lhs, const ProcessModID &rhs) { + return (!lhs.StopIDEqual(rhs) || !lhs.MemoryIDEqual(rhs)); } - + //---------------------------------------------------------------------- /// @class Process Process.h "lldb/Target/Process.h" /// @brief A plug-in interface definition class for debugging a process. //---------------------------------------------------------------------- -class Process : - public std::enable_shared_from_this<Process>, - public ProcessProperties, - public UserID, - public Broadcaster, - public ExecutionContextScope, - public PluginInterface -{ - friend class FunctionCaller; // For WaitForStateChangeEventsPrivate - friend class Debugger; // For PopProcessIOHandler and ProcessIOHandlerIsActive - friend class ProcessEventData; - friend class StopInfo; - friend class Target; - friend class ThreadList; +class Process : public std::enable_shared_from_this<Process>, + public ProcessProperties, + public UserID, + public Broadcaster, + public ExecutionContextScope, + public PluginInterface { + friend class FunctionCaller; // For WaitForStateChangeEventsPrivate + friend class Debugger; // For PopProcessIOHandler and ProcessIOHandlerIsActive + friend class ProcessEventData; + friend class StopInfo; + friend class Target; + friend class ThreadList; public: - //------------------------------------------------------------------ - /// Broadcaster event bits definitions. - //------------------------------------------------------------------ - enum - { - eBroadcastBitStateChanged = (1 << 0), - eBroadcastBitInterrupt = (1 << 1), - eBroadcastBitSTDOUT = (1 << 2), - eBroadcastBitSTDERR = (1 << 3), - eBroadcastBitProfileData = (1 << 4) - }; - - enum - { - eBroadcastInternalStateControlStop = (1<<0), - eBroadcastInternalStateControlPause = (1<<1), - eBroadcastInternalStateControlResume = (1<<2) - }; - - //------------------------------------------------------------------ - /// Process warning types. - //------------------------------------------------------------------ - enum Warnings - { - eWarningsOptimization = 1 - }; - - typedef Range<lldb::addr_t, lldb::addr_t> LoadRange; - // We use a read/write lock to allow on or more clients to - // access the process state while the process is stopped (reader). - // We lock the write lock to control access to the process - // while it is running (readers, or clients that want the process - // stopped can block waiting for the process to stop, or just - // try to lock it to see if they can immediately access the stopped - // process. If the try read lock fails, then the process is running. - typedef ProcessRunLock::ProcessRunLocker StopLocker; - - // These two functions fill out the Broadcaster interface: - - static ConstString &GetStaticBroadcasterClass (); - - ConstString &GetBroadcasterClass() const override - { - return GetStaticBroadcasterClass(); - } - - //------------------------------------------------------------------ - /// A notification structure that can be used by clients to listen - /// for changes in a process's lifetime. - /// - /// @see RegisterNotificationCallbacks (const Notifications&) - /// @see UnregisterNotificationCallbacks (const Notifications&) - //------------------------------------------------------------------ + //------------------------------------------------------------------ + /// Broadcaster event bits definitions. + //------------------------------------------------------------------ + enum { + eBroadcastBitStateChanged = (1 << 0), + eBroadcastBitInterrupt = (1 << 1), + eBroadcastBitSTDOUT = (1 << 2), + eBroadcastBitSTDERR = (1 << 3), + eBroadcastBitProfileData = (1 << 4), + eBroadcastBitStructuredData = (1 << 5), + }; + + enum { + eBroadcastInternalStateControlStop = (1 << 0), + eBroadcastInternalStateControlPause = (1 << 1), + eBroadcastInternalStateControlResume = (1 << 2) + }; + + //------------------------------------------------------------------ + /// Process warning types. + //------------------------------------------------------------------ + enum Warnings { eWarningsOptimization = 1 }; + + typedef Range<lldb::addr_t, lldb::addr_t> LoadRange; + // We use a read/write lock to allow on or more clients to + // access the process state while the process is stopped (reader). + // We lock the write lock to control access to the process + // while it is running (readers, or clients that want the process + // stopped can block waiting for the process to stop, or just + // try to lock it to see if they can immediately access the stopped + // process. If the try read lock fails, then the process is running. + typedef ProcessRunLock::ProcessRunLocker StopLocker; + + // These two functions fill out the Broadcaster interface: + + static ConstString &GetStaticBroadcasterClass(); + + ConstString &GetBroadcasterClass() const override { + return GetStaticBroadcasterClass(); + } + +//------------------------------------------------------------------ +/// A notification structure that can be used by clients to listen +/// for changes in a process's lifetime. +/// +/// @see RegisterNotificationCallbacks (const Notifications&) +/// @see UnregisterNotificationCallbacks (const Notifications&) +//------------------------------------------------------------------ #ifndef SWIG - typedef struct - { - void *baton; - void (*initialize)(void *baton, Process *process); - void (*process_state_changed) (void *baton, Process *process, lldb::StateType state); - } Notifications; - - class ProcessEventData : - public EventData - { - friend class Process; - - public: - ProcessEventData (); - ProcessEventData (const lldb::ProcessSP &process, lldb::StateType state); - - ~ProcessEventData() override; - - static const ConstString & - GetFlavorString (); - - const ConstString & - GetFlavor() const override; - - lldb::ProcessSP - GetProcessSP() const - { - return m_process_wp.lock(); - } - - lldb::StateType - GetState() const - { - return m_state; - } - bool - GetRestarted () const - { - return m_restarted; - } - - size_t - GetNumRestartedReasons () - { - return m_restarted_reasons.size(); - } - - const char * - GetRestartedReasonAtIndex(size_t idx) - { - return ((idx < m_restarted_reasons.size()) ? m_restarted_reasons[idx].c_str() : nullptr); - } - - bool - GetInterrupted () const - { - return m_interrupted; - } - - void - Dump(Stream *s) const override; - - void - DoOnRemoval(Event *event_ptr) override; - - static const Process::ProcessEventData * - GetEventDataFromEvent (const Event *event_ptr); - - static lldb::ProcessSP - GetProcessFromEvent (const Event *event_ptr); - - static lldb::StateType - GetStateFromEvent (const Event *event_ptr); - - static bool - GetRestartedFromEvent (const Event *event_ptr); - - static size_t - GetNumRestartedReasons(const Event *event_ptr); - - static const char * - GetRestartedReasonAtIndex(const Event *event_ptr, size_t idx); - - static void - AddRestartedReason (Event *event_ptr, const char *reason); - - static void - SetRestartedInEvent (Event *event_ptr, bool new_value); - - static bool - GetInterruptedFromEvent (const Event *event_ptr); - - static void - SetInterruptedInEvent (Event *event_ptr, bool new_value); - - static bool - SetUpdateStateOnRemoval (Event *event_ptr); - - private: - void - SetUpdateStateOnRemoval() - { - m_update_state++; - } - - void - SetRestarted (bool new_value) - { - m_restarted = new_value; - } - - void - SetInterrupted (bool new_value) - { - m_interrupted = new_value; - } - - void - AddRestartedReason (const char *reason) - { - m_restarted_reasons.push_back(reason); - } - - lldb::ProcessWP m_process_wp; - lldb::StateType m_state; - std::vector<std::string> m_restarted_reasons; - bool m_restarted; // For "eStateStopped" events, this is true if the target was automatically restarted. - int m_update_state; - bool m_interrupted; - - DISALLOW_COPY_AND_ASSIGN (ProcessEventData); - }; -#endif // SWIG + typedef struct { + void *baton; + void (*initialize)(void *baton, Process *process); + void (*process_state_changed)(void *baton, Process *process, + lldb::StateType state); + } Notifications; - //------------------------------------------------------------------ - /// Construct with a shared pointer to a target, and the Process listener. - /// Uses the Host UnixSignalsSP by default. - //------------------------------------------------------------------ - Process(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp); - - //------------------------------------------------------------------ - /// Construct with a shared pointer to a target, the Process listener, - /// and the appropriate UnixSignalsSP for the process. - //------------------------------------------------------------------ - Process(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, const lldb::UnixSignalsSP &unix_signals_sp); - - //------------------------------------------------------------------ - /// Destructor. - /// - /// The destructor is virtual since this class is designed to be - /// inherited from by the plug-in instance. - //------------------------------------------------------------------ - ~Process() override; - - static void - SettingsInitialize (); - - static void - SettingsTerminate (); - - static const ProcessPropertiesSP & - GetGlobalProperties(); - - //------------------------------------------------------------------ - /// Find a Process plug-in that can debug \a module using the - /// currently selected architecture. - /// - /// Scans all loaded plug-in interfaces that implement versions of - /// the Process plug-in interface and returns the first instance - /// that can debug the file. - /// - /// @param[in] module_sp - /// The module shared pointer that this process will debug. - /// - /// @param[in] plugin_name - /// If nullptr, select the best plug-in for the binary. If non-nullptr - /// then look for a plugin whose PluginInfo's name matches - /// this string. - /// - /// @see Process::CanDebug () - //------------------------------------------------------------------ - static lldb::ProcessSP - FindPlugin (lldb::TargetSP target_sp, - const char *plugin_name, - lldb::ListenerSP listener_sp, - const FileSpec *crash_file_path); - - //------------------------------------------------------------------ - /// Static function that can be used with the \b host function - /// Host::StartMonitoringChildProcess (). - /// - /// This function can be used by lldb_private::Process subclasses - /// when they want to watch for a local process and have its exit - /// status automatically set when the host child process exits. - /// Subclasses should call Host::StartMonitoringChildProcess () - /// with: - /// callback = Process::SetHostProcessExitStatus - /// pid = Process::GetID() - /// monitor_signals = false - //------------------------------------------------------------------ - static bool - SetProcessExitStatus(lldb::pid_t pid, // The process ID we want to monitor - bool exited, - int signo, // Zero for no signal - int status); // Exit value of process if signal is zero - - lldb::ByteOrder - GetByteOrder () const; - - uint32_t - GetAddressByteSize () const; - - uint32_t - GetUniqueID() const - { - return m_process_unique_id; - } + class ProcessEventData : public EventData { + friend class Process; - //------------------------------------------------------------------ - /// Check if a plug-in instance can debug the file in \a module. - /// - /// Each plug-in is given a chance to say whether it can debug - /// the file in \a module. If the Process plug-in instance can - /// debug a file on the current system, it should return \b true. - /// - /// @return - /// Returns \b true if this Process plug-in instance can - /// debug the executable, \b false otherwise. - //------------------------------------------------------------------ - virtual bool - CanDebug (lldb::TargetSP target, - bool plugin_specified_by_name) = 0; - - //------------------------------------------------------------------ - /// This object is about to be destroyed, do any necessary cleanup. - /// - /// Subclasses that override this method should always call this - /// superclass method. - //------------------------------------------------------------------ - virtual void - Finalize(); - - //------------------------------------------------------------------ - /// Return whether this object is valid (i.e. has not been finalized.) - /// - /// @return - /// Returns \b true if this Process has not been finalized - /// and \b false otherwise. - //------------------------------------------------------------------ - bool - IsValid() const - { - return !m_finalize_called; - } + public: + ProcessEventData(); + ProcessEventData(const lldb::ProcessSP &process, lldb::StateType state); - //------------------------------------------------------------------ - /// Return a multi-word command object that can be used to expose - /// plug-in specific commands. - /// - /// This object will be used to resolve plug-in commands and can be - /// triggered by a call to: - /// - /// (lldb) process commmand <args> - /// - /// @return - /// A CommandObject which can be one of the concrete subclasses - /// of CommandObject like CommandObjectRaw, CommandObjectParsed, - /// or CommandObjectMultiword. - //------------------------------------------------------------------ - virtual CommandObject * - GetPluginCommandObject() - { - return nullptr; - } + ~ProcessEventData() override; - //------------------------------------------------------------------ - /// Launch a new process. - /// - /// Launch a new process by spawning a new process using the - /// target object's executable module's file as the file to launch. - /// - /// This function is not meant to be overridden by Process - /// subclasses. It will first call Process::WillLaunch (Module *) - /// and if that returns \b true, Process::DoLaunch (Module*, - /// char const *[],char const *[],const char *,const char *, - /// const char *) will be called to actually do the launching. If - /// DoLaunch returns \b true, then Process::DidLaunch() will be - /// called. - /// - /// @param[in] launch_info - /// Details regarding the environment, STDIN/STDOUT/STDERR - /// redirection, working path, etc. related to the requested launch. - /// - /// @return - /// An error object. Call GetID() to get the process ID if - /// the error object is success. - //------------------------------------------------------------------ - virtual Error - Launch (ProcessLaunchInfo &launch_info); - - virtual Error - LoadCore (); - - virtual Error - DoLoadCore () - { - Error error; - error.SetErrorStringWithFormat("error: %s does not support loading core files.", GetPluginName().GetCString()); - return error; - } + static const ConstString &GetFlavorString(); - //------------------------------------------------------------------ - /// Get the dynamic loader plug-in for this process. - /// - /// The default action is to let the DynamicLoader plug-ins check - /// the main executable and the DynamicLoader will select itself - /// automatically. Subclasses can override this if inspecting the - /// executable is not desired, or if Process subclasses can only - /// use a specific DynamicLoader plug-in. - //------------------------------------------------------------------ - virtual DynamicLoader * - GetDynamicLoader (); - - //------------------------------------------------------------------ - // Returns AUXV structure found in many ELF-based environments. - // - // The default action is to return an empty data buffer. - // - // @return - // A data buffer containing the contents of the AUXV data. - //------------------------------------------------------------------ - virtual const lldb::DataBufferSP - GetAuxvData(); - - //------------------------------------------------------------------ - /// Sometimes processes know how to retrieve and load shared libraries. - /// This is normally done by DynamicLoader plug-ins, but sometimes the - /// connection to the process allows retrieving this information. The - /// dynamic loader plug-ins can use this function if they can't - /// determine the current shared library load state. - /// - /// @return - /// The number of shared libraries that were loaded - //------------------------------------------------------------------ - virtual size_t - LoadModules () - { - return 0; - } + const ConstString &GetFlavor() const override; - virtual size_t - LoadModules (LoadedModuleInfoList &) - { - return 0; - } + lldb::ProcessSP GetProcessSP() const { return m_process_wp.lock(); } -protected: - virtual JITLoaderList & - GetJITLoaders (); + lldb::StateType GetState() const { return m_state; } + bool GetRestarted() const { return m_restarted; } -public: - //------------------------------------------------------------------ - /// Get the system runtime plug-in for this process. - /// - /// @return - /// Returns a pointer to the SystemRuntime plugin for this Process - /// if one is available. Else returns nullptr. - //------------------------------------------------------------------ - virtual SystemRuntime * - GetSystemRuntime (); - - //------------------------------------------------------------------ - /// Attach to an existing process using the process attach info. - /// - /// This function is not meant to be overridden by Process - /// subclasses. It will first call WillAttach (lldb::pid_t) - /// or WillAttach (const char *), and if that returns \b - /// true, DoAttach (lldb::pid_t) or DoAttach (const char *) will - /// be called to actually do the attach. If DoAttach returns \b - /// true, then Process::DidAttach() will be called. - /// - /// @param[in] pid - /// The process ID that we should attempt to attach to. - /// - /// @return - /// Returns \a pid if attaching was successful, or - /// LLDB_INVALID_PROCESS_ID if attaching fails. - //------------------------------------------------------------------ - virtual Error - Attach (ProcessAttachInfo &attach_info); - - //------------------------------------------------------------------ - /// Attach to a remote system via a URL - /// - /// @param[in] strm - /// A stream where output intended for the user - /// (if the driver has a way to display that) generated during - /// the connection. This may be nullptr if no output is needed.A - /// - /// @param[in] remote_url - /// The URL format that we are connecting to. - /// - /// @return - /// Returns an error object. - //------------------------------------------------------------------ - virtual Error - ConnectRemote (Stream *strm, const char *remote_url); - - bool - GetShouldDetach () const - { - return m_should_detach; - } + size_t GetNumRestartedReasons() { return m_restarted_reasons.size(); } - void - SetShouldDetach (bool b) - { - m_should_detach = b; + const char *GetRestartedReasonAtIndex(size_t idx) { + return ((idx < m_restarted_reasons.size()) + ? m_restarted_reasons[idx].c_str() + : nullptr); } - //------------------------------------------------------------------ - /// Get the image information address for the current process. - /// - /// Some runtimes have system functions that can help dynamic - /// loaders locate the dynamic loader information needed to observe - /// shared libraries being loaded or unloaded. This function is - /// in the Process interface (as opposed to the DynamicLoader - /// interface) to ensure that remote debugging can take advantage of - /// this functionality. - /// - /// @return - /// The address of the dynamic loader information, or - /// LLDB_INVALID_ADDRESS if this is not supported by this - /// interface. - //------------------------------------------------------------------ - virtual lldb::addr_t - GetImageInfoAddress (); - - //------------------------------------------------------------------ - /// Called when the process is about to broadcast a public stop. - /// - /// There are public and private stops. Private stops are when the - /// process is doing things like stepping and the client doesn't - /// need to know about starts and stop that implement a thread plan. - /// Single stepping over a source line in code might end up being - /// implemented by one or more process starts and stops. Public stops - /// are when clients will be notified that the process is stopped. - /// These events typically trigger UI updates (thread stack frames to - /// be displayed, variables to be displayed, and more). This function - /// can be overriden and allows process subclasses to do something - /// before the eBroadcastBitStateChanged event is sent to public - /// clients. - //------------------------------------------------------------------ - virtual void - WillPublicStop () - { - } + bool GetInterrupted() const { return m_interrupted; } - //------------------------------------------------------------------ - /// Register for process and thread notifications. - /// - /// Clients can register notification callbacks by filling out a - /// Process::Notifications structure and calling this function. - /// - /// @param[in] callbacks - /// A structure that contains the notification baton and - /// callback functions. - /// - /// @see Process::Notifications - //------------------------------------------------------------------ -#ifndef SWIG - void - RegisterNotificationCallbacks (const Process::Notifications& callbacks); -#endif + void Dump(Stream *s) const override; - //------------------------------------------------------------------ - /// Unregister for process and thread notifications. - /// - /// Clients can unregister notification callbacks by passing a copy of - /// the original baton and callbacks in \a callbacks. - /// - /// @param[in] callbacks - /// A structure that contains the notification baton and - /// callback functions. - /// - /// @return - /// Returns \b true if the notification callbacks were - /// successfully removed from the process, \b false otherwise. - /// - /// @see Process::Notifications - //------------------------------------------------------------------ -#ifndef SWIG - bool - UnregisterNotificationCallbacks (const Process::Notifications& callbacks); -#endif + void DoOnRemoval(Event *event_ptr) override; - //================================================================== - // Built in Process Control functions - //================================================================== - //------------------------------------------------------------------ - /// Resumes all of a process's threads as configured using the - /// Thread run control functions. - /// - /// Threads for a process should be updated with one of the run - /// control actions (resume, step, or suspend) that they should take - /// when the process is resumed. If no run control action is given - /// to a thread it will be resumed by default. - /// - /// This function is not meant to be overridden by Process - /// subclasses. This function will take care of disabling any - /// breakpoints that threads may be stopped at, single stepping, and - /// re-enabling breakpoints, and enabling the basic flow control - /// that the plug-in instances need not worry about. - /// - /// N.B. This function also sets the Write side of the Run Lock, - /// which is unset when the corresponding stop event is pulled off - /// the Public Event Queue. If you need to resume the process without - /// setting the Run Lock, use PrivateResume (though you should only do - /// that from inside the Process class. - /// - /// @return - /// Returns an error object. - /// - /// @see Thread:Resume() - /// @see Thread:Step() - /// @see Thread:Suspend() - //------------------------------------------------------------------ - Error - Resume(); - - Error - ResumeSynchronous (Stream *stream); - - //------------------------------------------------------------------ - /// Halts a running process. - /// - /// This function is not meant to be overridden by Process - /// subclasses. - /// If the process is successfully halted, a eStateStopped - /// process event with GetInterrupted will be broadcast. If false, we will - /// halt the process with no events generated by the halt. - /// - /// @param[in] clear_thread_plans - /// If true, when the process stops, clear all thread plans. - /// - /// @param[in] use_run_lock - /// Whether to release the run lock after the stop. - /// - /// @return - /// Returns an error object. If the error is empty, the process is halted. - /// otherwise the halt has failed. - //------------------------------------------------------------------ - Error - Halt (bool clear_thread_plans = false, bool use_run_lock = true); - - //------------------------------------------------------------------ - /// Detaches from a running or stopped process. - /// - /// This function is not meant to be overridden by Process - /// subclasses. - /// - /// @param[in] keep_stopped - /// If true, don't resume the process on detach. - /// - /// @return - /// Returns an error object. - //------------------------------------------------------------------ - Error - Detach (bool keep_stopped); - - //------------------------------------------------------------------ - /// Kills the process and shuts down all threads that were spawned - /// to track and monitor the process. - /// - /// This function is not meant to be overridden by Process - /// subclasses. - /// - /// @param[in] force_kill - /// Whether lldb should force a kill (instead of a detach) from - /// the inferior process. Normally if lldb launched a binary and - /// Destory is called, lldb kills it. If lldb attached to a - /// running process and Destory is called, lldb detaches. If - /// this behavior needs to be over-ridden, this is the bool that - /// can be used. - /// - /// @return - /// Returns an error object. - //------------------------------------------------------------------ - Error - Destroy(bool force_kill); - - //------------------------------------------------------------------ - /// Sends a process a UNIX signal \a signal. - /// - /// This function is not meant to be overridden by Process - /// subclasses. - /// - /// @return - /// Returns an error object. - //------------------------------------------------------------------ - Error - Signal (int signal); - - void - SetUnixSignals(lldb::UnixSignalsSP &&signals_sp); - - const lldb::UnixSignalsSP & - GetUnixSignals(); - - //================================================================== - // Plug-in Process Control Overrides - //================================================================== - - //------------------------------------------------------------------ - /// Called before attaching to a process. - /// - /// Allow Process plug-ins to execute some code before attaching a - /// process. - /// - /// @return - /// Returns an error object. - //------------------------------------------------------------------ - virtual Error - WillAttachToProcessWithID (lldb::pid_t pid) - { - return Error(); - } + static const Process::ProcessEventData * + GetEventDataFromEvent(const Event *event_ptr); - //------------------------------------------------------------------ - /// Called before attaching to a process. - /// - /// Allow Process plug-ins to execute some code before attaching a - /// process. - /// - /// @return - /// Returns an error object. - //------------------------------------------------------------------ - virtual Error - WillAttachToProcessWithName (const char *process_name, bool wait_for_launch) - { - return Error(); - } + static lldb::ProcessSP GetProcessFromEvent(const Event *event_ptr); - //------------------------------------------------------------------ - /// Attach to a remote system via a URL - /// - /// @param[in] strm - /// A stream where output intended for the user - /// (if the driver has a way to display that) generated during - /// the connection. This may be nullptr if no output is needed.A - /// - /// @param[in] remote_url - /// The URL format that we are connecting to. - /// - /// @return - /// Returns an error object. - //------------------------------------------------------------------ - virtual Error - DoConnectRemote (Stream *strm, const char *remote_url) - { - Error error; - error.SetErrorString ("remote connections are not supported"); - return error; - } + static lldb::StateType GetStateFromEvent(const Event *event_ptr); - //------------------------------------------------------------------ - /// Attach to an existing process using a process ID. - /// - /// @param[in] pid - /// The process ID that we should attempt to attach to. - /// - /// @param[in] attach_info - /// Information on how to do the attach. For example, GetUserID() - /// will return the uid to attach as. - /// - /// @return - /// Returns a successful Error attaching was successful, or - /// an appropriate (possibly platform-specific) error code if - /// attaching fails. - /// hanming : need flag - //------------------------------------------------------------------ - virtual Error - DoAttachToProcessWithID (lldb::pid_t pid, const ProcessAttachInfo &attach_info) - { - Error error; - error.SetErrorStringWithFormat("error: %s does not support attaching to a process by pid", GetPluginName().GetCString()); - return error; - } + static bool GetRestartedFromEvent(const Event *event_ptr); - //------------------------------------------------------------------ - /// Attach to an existing process using a partial process name. - /// - /// @param[in] process_name - /// The name of the process to attach to. - /// - /// @param[in] attach_info - /// Information on how to do the attach. For example, GetUserID() - /// will return the uid to attach as. - /// - /// @return - /// Returns a successful Error attaching was successful, or - /// an appropriate (possibly platform-specific) error code if - /// attaching fails. - //------------------------------------------------------------------ - virtual Error - DoAttachToProcessWithName (const char *process_name, const ProcessAttachInfo &attach_info) - { - Error error; - error.SetErrorString("attach by name is not supported"); - return error; - } + static size_t GetNumRestartedReasons(const Event *event_ptr); - //------------------------------------------------------------------ - /// Called after attaching a process. - /// - /// @param[in] process_arch - /// If you can figure out the process architecture after attach, fill it in here. - /// - /// Allow Process plug-ins to execute some code after attaching to - /// a process. - //------------------------------------------------------------------ - virtual void - DidAttach (ArchSpec &process_arch) - { - process_arch.Clear(); - } + static const char *GetRestartedReasonAtIndex(const Event *event_ptr, + size_t idx); - //------------------------------------------------------------------ - /// Called after a process re-execs itself. - /// - /// Allow Process plug-ins to execute some code after a process has - /// exec'ed itself. Subclasses typically should override DoDidExec() - /// as the lldb_private::Process class needs to remove its dynamic - /// loader, runtime, ABI and other plug-ins, as well as unload all - /// shared libraries. - //------------------------------------------------------------------ - virtual void - DidExec (); - - //------------------------------------------------------------------ - /// Subclasses of Process should implement this function if they - /// need to do anything after a process exec's itself. - //------------------------------------------------------------------ - virtual void - DoDidExec () - { - } + static void AddRestartedReason(Event *event_ptr, const char *reason); - //------------------------------------------------------------------ - /// Called before launching to a process. - /// - /// Allow Process plug-ins to execute some code before launching a - /// process. - /// - /// @return - /// Returns an error object. - //------------------------------------------------------------------ - virtual Error - WillLaunch (Module* module) - { - return Error(); - } + static void SetRestartedInEvent(Event *event_ptr, bool new_value); - //------------------------------------------------------------------ - /// Launch a new process. - /// - /// Launch a new process by spawning a new process using - /// \a exe_module's file as the file to launch. Launch details are - /// provided in \a launch_info. - /// - /// @param[in] exe_module - /// The module from which to extract the file specification and - /// launch. - /// - /// @param[in] launch_info - /// Details (e.g. arguments, stdio redirection, etc.) for the - /// requested launch. - /// - /// @return - /// An Error instance indicating success or failure of the - /// operation. - //------------------------------------------------------------------ - virtual Error - DoLaunch (Module *exe_module, - ProcessLaunchInfo &launch_info) - { - Error error; - error.SetErrorStringWithFormat("error: %s does not support launching processes", GetPluginName().GetCString()); - return error; - } + static bool GetInterruptedFromEvent(const Event *event_ptr); - //------------------------------------------------------------------ - /// Called after launching a process. - /// - /// Allow Process plug-ins to execute some code after launching - /// a process. - //------------------------------------------------------------------ - virtual void - DidLaunch () {} - - //------------------------------------------------------------------ - /// Called before resuming to a process. - /// - /// Allow Process plug-ins to execute some code before resuming a - /// process. - /// - /// @return - /// Returns an error object. - //------------------------------------------------------------------ - virtual Error - WillResume () { return Error(); } - - //------------------------------------------------------------------ - /// Resumes all of a process's threads as configured using the - /// Thread run control functions. - /// - /// Threads for a process should be updated with one of the run - /// control actions (resume, step, or suspend) that they should take - /// when the process is resumed. If no run control action is given - /// to a thread it will be resumed by default. - /// - /// @return - /// Returns \b true if the process successfully resumes using - /// the thread run control actions, \b false otherwise. - /// - /// @see Thread:Resume() - /// @see Thread:Step() - /// @see Thread:Suspend() - //------------------------------------------------------------------ - virtual Error - DoResume () - { - Error error; - error.SetErrorStringWithFormat("error: %s does not support resuming processes", GetPluginName().GetCString()); - return error; - } + static void SetInterruptedInEvent(Event *event_ptr, bool new_value); - //------------------------------------------------------------------ - /// Called after resuming a process. - /// - /// Allow Process plug-ins to execute some code after resuming - /// a process. - //------------------------------------------------------------------ - virtual void - DidResume () {} - - //------------------------------------------------------------------ - /// Called before halting to a process. - /// - /// Allow Process plug-ins to execute some code before halting a - /// process. - /// - /// @return - /// Returns an error object. - //------------------------------------------------------------------ - virtual Error - WillHalt () { return Error(); } - - //------------------------------------------------------------------ - /// Halts a running process. - /// - /// DoHalt must produce one and only one stop StateChanged event if it actually - /// stops the process. If the stop happens through some natural event (for - /// instance a SIGSTOP), then forwarding that event will do. Otherwise, you must - /// generate the event manually. This function is called from the context of the - /// private state thread. - /// - /// @param[out] caused_stop - /// If true, then this Halt caused the stop, otherwise, the - /// process was already stopped. - /// - /// @return - /// Returns \b true if the process successfully halts, \b false - /// otherwise. - //------------------------------------------------------------------ - virtual Error - DoHalt (bool &caused_stop) - { - Error error; - error.SetErrorStringWithFormat("error: %s does not support halting processes", GetPluginName().GetCString()); - return error; - } + static bool SetUpdateStateOnRemoval(Event *event_ptr); - //------------------------------------------------------------------ - /// Called after halting a process. - /// - /// Allow Process plug-ins to execute some code after halting - /// a process. - //------------------------------------------------------------------ - virtual void - DidHalt () {} - - //------------------------------------------------------------------ - /// Called before detaching from a process. - /// - /// Allow Process plug-ins to execute some code before detaching - /// from a process. - /// - /// @return - /// Returns an error object. - //------------------------------------------------------------------ - virtual Error - WillDetach () - { - return Error(); - } + private: + void SetUpdateStateOnRemoval() { m_update_state++; } - //------------------------------------------------------------------ - /// Detaches from a running or stopped process. - /// - /// @return - /// Returns \b true if the process successfully detaches, \b - /// false otherwise. - //------------------------------------------------------------------ - virtual Error - DoDetach (bool keep_stopped) - { - Error error; - error.SetErrorStringWithFormat("error: %s does not support detaching from processes", GetPluginName().GetCString()); - return error; - } + void SetRestarted(bool new_value) { m_restarted = new_value; } - //------------------------------------------------------------------ - /// Called after detaching from a process. - /// - /// Allow Process plug-ins to execute some code after detaching - /// from a process. - //------------------------------------------------------------------ - virtual void - DidDetach () {} - - virtual bool - DetachRequiresHalt() { return false; } - - //------------------------------------------------------------------ - /// Called before sending a signal to a process. - /// - /// Allow Process plug-ins to execute some code before sending a - /// signal to a process. - /// - /// @return - /// Returns no error if it is safe to proceed with a call to - /// Process::DoSignal(int), otherwise an error describing what - /// prevents the signal from being sent. - //------------------------------------------------------------------ - virtual Error - WillSignal () { return Error(); } - - //------------------------------------------------------------------ - /// Sends a process a UNIX signal \a signal. - /// - /// @return - /// Returns an error object. - //------------------------------------------------------------------ - virtual Error - DoSignal (int signal) - { - Error error; - error.SetErrorStringWithFormat("error: %s does not support sending signals to processes", GetPluginName().GetCString()); - return error; - } + void SetInterrupted(bool new_value) { m_interrupted = new_value; } - virtual Error - WillDestroy () { return Error(); } - - virtual Error - DoDestroy () = 0; - - virtual void - DidDestroy () { } - - virtual bool - DestroyRequiresHalt() { return true; } - - //------------------------------------------------------------------ - /// Called after sending a signal to a process. - /// - /// Allow Process plug-ins to execute some code after sending a - /// signal to a process. - //------------------------------------------------------------------ - virtual void - DidSignal () {} - - //------------------------------------------------------------------ - /// Currently called as part of ShouldStop. - /// FIXME: Should really happen when the target stops before the - /// event is taken from the queue... - /// - /// This callback is called as the event - /// is about to be queued up to allow Process plug-ins to execute - /// some code prior to clients being notified that a process was - /// stopped. Common operations include updating the thread list, - /// invalidating any thread state (registers, stack, etc) prior to - /// letting the notification go out. - /// - //------------------------------------------------------------------ - virtual void - RefreshStateAfterStop () = 0; - - //------------------------------------------------------------------ - /// Sometimes the connection to a process can detect the host OS - /// version that the process is running on. The current platform - /// should be checked first in case the platform is connected, but - /// clients can fall back onto this function if the platform fails - /// to identify the host OS version. The platform should be checked - /// first in case you are running a simulator platform that might - /// itself be running natively, but have different heuristics for - /// figuring out which OS is is emulating. - /// - /// @param[out] major - /// The major OS version, or UINT32_MAX if it can't be determined - /// - /// @param[out] minor - /// The minor OS version, or UINT32_MAX if it can't be determined - /// - /// @param[out] update - /// The update OS version, or UINT32_MAX if it can't be determined - /// - /// @return - /// Returns \b true if the host OS version info was filled in - /// and \b false otherwise. - //------------------------------------------------------------------ - virtual bool - GetHostOSVersion(uint32_t &major, - uint32_t &minor, - uint32_t &update) - { - major = UINT32_MAX; - minor = UINT32_MAX; - update = UINT32_MAX; - return false; + void AddRestartedReason(const char *reason) { + m_restarted_reasons.push_back(reason); } + lldb::ProcessWP m_process_wp; + lldb::StateType m_state; + std::vector<std::string> m_restarted_reasons; + bool m_restarted; // For "eStateStopped" events, this is true if the target + // was automatically restarted. + int m_update_state; + bool m_interrupted; - //------------------------------------------------------------------ - /// Get the target object pointer for this module. - /// - /// @return - /// A Target object pointer to the target that owns this - /// module. - //------------------------------------------------------------------ - Target & - GetTarget () - { - return *m_target_sp.lock(); - } - - //------------------------------------------------------------------ - /// Get the const target object pointer for this module. - /// - /// @return - /// A const Target object pointer to the target that owns this - /// module. - //------------------------------------------------------------------ - const Target & - GetTarget () const - { - return *m_target_sp.lock(); - } + DISALLOW_COPY_AND_ASSIGN(ProcessEventData); + }; +#endif // SWIG - //------------------------------------------------------------------ - /// Flush all data in the process. - /// - /// Flush the memory caches, all threads, and any other cached data - /// in the process. - /// - /// This function can be called after a world changing event like - /// adding a new symbol file, or after the process makes a large - /// context switch (from boot ROM to booted into an OS). - //------------------------------------------------------------------ - void - Flush (); - - //------------------------------------------------------------------ - /// Get accessor for the current process state. - /// - /// @return - /// The current state of the process. - /// - /// @see lldb::StateType - //------------------------------------------------------------------ - lldb::StateType - GetState (); - - lldb::ExpressionResults - RunThreadPlan(ExecutionContext &exe_ctx, lldb::ThreadPlanSP &thread_plan_sp, - const EvaluateExpressionOptions &options, DiagnosticManager &diagnostic_manager); - - static const char * - ExecutionResultAsCString(lldb::ExpressionResults result); - - void - GetStatus (Stream &ostrm); - - size_t - GetThreadStatus (Stream &ostrm, - bool only_threads_with_stop_reason, - uint32_t start_frame, - uint32_t num_frames, - uint32_t num_frames_with_source); - - void - SendAsyncInterrupt (); - - //------------------------------------------------------------------ - // Notify this process class that modules got loaded. - // - // If subclasses override this method, they must call this version - // before doing anything in the subclass version of the function. - //------------------------------------------------------------------ - virtual void - ModulesDidLoad (ModuleList &module_list); - - //------------------------------------------------------------------ - /// Retrieve the list of shared libraries that are loaded for this process - /// - /// For certain platforms, the time it takes for the DynamicLoader plugin to - /// read all of the shared libraries out of memory over a slow communication - /// channel may be too long. In that instance, the gdb-remote stub may be - /// able to retrieve the necessary information about the solibs out of memory - /// and return a concise summary sufficient for the DynamicLoader plugin. - /// - /// @param [in] image_list_address - /// The address where the table of shared libraries is stored in memory, - /// if that is appropriate for this platform. Else this may be - /// passed as LLDB_INVALID_ADDRESS. - /// - /// @param [in] image_count - /// The number of shared libraries that are present in this process, if - /// that is appropriate for this platofrm Else this may be passed as - /// LLDB_INVALID_ADDRESS. - /// - /// @return - /// A StructureDataSP object which, if non-empty, will contain the - /// information the DynamicLoader needs to get the initial scan of - /// solibs resolved. - //------------------------------------------------------------------ - virtual lldb_private::StructuredData::ObjectSP - GetLoadedDynamicLibrariesInfos (lldb::addr_t image_list_address, lldb::addr_t image_count) - { - return StructuredData::ObjectSP(); - } + //------------------------------------------------------------------ + /// Construct with a shared pointer to a target, and the Process listener. + /// Uses the Host UnixSignalsSP by default. + //------------------------------------------------------------------ + Process(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp); + + //------------------------------------------------------------------ + /// Construct with a shared pointer to a target, the Process listener, + /// and the appropriate UnixSignalsSP for the process. + //------------------------------------------------------------------ + Process(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, + const lldb::UnixSignalsSP &unix_signals_sp); + + //------------------------------------------------------------------ + /// Destructor. + /// + /// The destructor is virtual since this class is designed to be + /// inherited from by the plug-in instance. + //------------------------------------------------------------------ + ~Process() override; + + static void SettingsInitialize(); + + static void SettingsTerminate(); + + static const ProcessPropertiesSP &GetGlobalProperties(); + + //------------------------------------------------------------------ + /// Find a Process plug-in that can debug \a module using the + /// currently selected architecture. + /// + /// Scans all loaded plug-in interfaces that implement versions of + /// the Process plug-in interface and returns the first instance + /// that can debug the file. + /// + /// @param[in] module_sp + /// The module shared pointer that this process will debug. + /// + /// @param[in] plugin_name + /// If nullptr, select the best plug-in for the binary. If non-nullptr + /// then look for a plugin whose PluginInfo's name matches + /// this string. + /// + /// @see Process::CanDebug () + //------------------------------------------------------------------ + static lldb::ProcessSP FindPlugin(lldb::TargetSP target_sp, + llvm::StringRef plugin_name, + lldb::ListenerSP listener_sp, + const FileSpec *crash_file_path); + + //------------------------------------------------------------------ + /// Static function that can be used with the \b host function + /// Host::StartMonitoringChildProcess (). + /// + /// This function can be used by lldb_private::Process subclasses + /// when they want to watch for a local process and have its exit + /// status automatically set when the host child process exits. + /// Subclasses should call Host::StartMonitoringChildProcess () + /// with: + /// callback = Process::SetHostProcessExitStatus + /// pid = Process::GetID() + /// monitor_signals = false + //------------------------------------------------------------------ + static bool + SetProcessExitStatus(lldb::pid_t pid, // The process ID we want to monitor + bool exited, + int signo, // Zero for no signal + int status); // Exit value of process if signal is zero + + lldb::ByteOrder GetByteOrder() const; + + uint32_t GetAddressByteSize() const; + + uint32_t GetUniqueID() const { return m_process_unique_id; } + + //------------------------------------------------------------------ + /// Check if a plug-in instance can debug the file in \a module. + /// + /// Each plug-in is given a chance to say whether it can debug + /// the file in \a module. If the Process plug-in instance can + /// debug a file on the current system, it should return \b true. + /// + /// @return + /// Returns \b true if this Process plug-in instance can + /// debug the executable, \b false otherwise. + //------------------------------------------------------------------ + virtual bool CanDebug(lldb::TargetSP target, + bool plugin_specified_by_name) = 0; + + //------------------------------------------------------------------ + /// This object is about to be destroyed, do any necessary cleanup. + /// + /// Subclasses that override this method should always call this + /// superclass method. + //------------------------------------------------------------------ + virtual void Finalize(); + + //------------------------------------------------------------------ + /// Return whether this object is valid (i.e. has not been finalized.) + /// + /// @return + /// Returns \b true if this Process has not been finalized + /// and \b false otherwise. + //------------------------------------------------------------------ + bool IsValid() const { return !m_finalize_called; } + + //------------------------------------------------------------------ + /// Return a multi-word command object that can be used to expose + /// plug-in specific commands. + /// + /// This object will be used to resolve plug-in commands and can be + /// triggered by a call to: + /// + /// (lldb) process commmand <args> + /// + /// @return + /// A CommandObject which can be one of the concrete subclasses + /// of CommandObject like CommandObjectRaw, CommandObjectParsed, + /// or CommandObjectMultiword. + //------------------------------------------------------------------ + virtual CommandObject *GetPluginCommandObject() { return nullptr; } + + //------------------------------------------------------------------ + /// Launch a new process. + /// + /// Launch a new process by spawning a new process using the + /// target object's executable module's file as the file to launch. + /// + /// This function is not meant to be overridden by Process + /// subclasses. It will first call Process::WillLaunch (Module *) + /// and if that returns \b true, Process::DoLaunch (Module*, + /// char const *[],char const *[],const char *,const char *, + /// const char *) will be called to actually do the launching. If + /// DoLaunch returns \b true, then Process::DidLaunch() will be + /// called. + /// + /// @param[in] launch_info + /// Details regarding the environment, STDIN/STDOUT/STDERR + /// redirection, working path, etc. related to the requested launch. + /// + /// @return + /// An error object. Call GetID() to get the process ID if + /// the error object is success. + //------------------------------------------------------------------ + virtual Error Launch(ProcessLaunchInfo &launch_info); + + virtual Error LoadCore(); + + virtual Error DoLoadCore() { + Error error; + error.SetErrorStringWithFormat( + "error: %s does not support loading core files.", + GetPluginName().GetCString()); + return error; + } + + //------------------------------------------------------------------ + /// Get the dynamic loader plug-in for this process. + /// + /// The default action is to let the DynamicLoader plug-ins check + /// the main executable and the DynamicLoader will select itself + /// automatically. Subclasses can override this if inspecting the + /// executable is not desired, or if Process subclasses can only + /// use a specific DynamicLoader plug-in. + //------------------------------------------------------------------ + virtual DynamicLoader *GetDynamicLoader(); + + //------------------------------------------------------------------ + // Returns AUXV structure found in many ELF-based environments. + // + // The default action is to return an empty data buffer. + // + // @return + // A data buffer containing the contents of the AUXV data. + //------------------------------------------------------------------ + virtual const lldb::DataBufferSP GetAuxvData(); + + //------------------------------------------------------------------ + /// Sometimes processes know how to retrieve and load shared libraries. + /// This is normally done by DynamicLoader plug-ins, but sometimes the + /// connection to the process allows retrieving this information. The + /// dynamic loader plug-ins can use this function if they can't + /// determine the current shared library load state. + /// + /// @return + /// The number of shared libraries that were loaded + //------------------------------------------------------------------ + virtual size_t LoadModules() { return 0; } + + virtual size_t LoadModules(LoadedModuleInfoList &) { return 0; } - //------------------------------------------------------------------ - /// Print a user-visible warning about a module being built with optimization - /// - /// Prints a async warning message to the user one time per Module - /// where a function is found that was compiled with optimization, per - /// Process. - /// - /// @param [in] sc - /// A SymbolContext with eSymbolContextFunction and eSymbolContextModule - /// pre-computed. - //------------------------------------------------------------------ - void - PrintWarningOptimization (const SymbolContext &sc); - - virtual bool - GetProcessInfo(ProcessInstanceInfo &info); +protected: + virtual JITLoaderList &GetJITLoaders(); public: - //------------------------------------------------------------------ - /// Get the exit status for a process. - /// - /// @return - /// The process's return code, or -1 if the current process - /// state is not eStateExited. - //------------------------------------------------------------------ - int - GetExitStatus (); - - //------------------------------------------------------------------ - /// Get a textual description of what the process exited. - /// - /// @return - /// The textual description of why the process exited, or nullptr - /// if there is no description available. - //------------------------------------------------------------------ - const char * - GetExitDescription (); - - virtual void - DidExit () - { - } - - //------------------------------------------------------------------ - /// Get the Modification ID of the process. - /// - /// @return - /// The modification ID of the process. - //------------------------------------------------------------------ - ProcessModID - GetModID () const - { - return m_mod_id; - } - - const ProcessModID & - GetModIDRef () const - { - return m_mod_id; - } - - uint32_t - GetStopID () const - { - return m_mod_id.GetStopID(); - } - - uint32_t - GetResumeID () const - { - return m_mod_id.GetResumeID(); - } - - uint32_t - GetLastUserExpressionResumeID () const - { - return m_mod_id.GetLastUserExpressionResumeID(); - } - - uint32_t - GetLastNaturalStopID() const - { - return m_mod_id.GetLastNaturalStopID(); - } + //------------------------------------------------------------------ + /// Get the system runtime plug-in for this process. + /// + /// @return + /// Returns a pointer to the SystemRuntime plugin for this Process + /// if one is available. Else returns nullptr. + //------------------------------------------------------------------ + virtual SystemRuntime *GetSystemRuntime(); + + //------------------------------------------------------------------ + /// Attach to an existing process using the process attach info. + /// + /// This function is not meant to be overridden by Process + /// subclasses. It will first call WillAttach (lldb::pid_t) + /// or WillAttach (const char *), and if that returns \b + /// true, DoAttach (lldb::pid_t) or DoAttach (const char *) will + /// be called to actually do the attach. If DoAttach returns \b + /// true, then Process::DidAttach() will be called. + /// + /// @param[in] pid + /// The process ID that we should attempt to attach to. + /// + /// @return + /// Returns \a pid if attaching was successful, or + /// LLDB_INVALID_PROCESS_ID if attaching fails. + //------------------------------------------------------------------ + virtual Error Attach(ProcessAttachInfo &attach_info); + + //------------------------------------------------------------------ + /// Attach to a remote system via a URL + /// + /// @param[in] strm + /// A stream where output intended for the user + /// (if the driver has a way to display that) generated during + /// the connection. This may be nullptr if no output is needed.A + /// + /// @param[in] remote_url + /// The URL format that we are connecting to. + /// + /// @return + /// Returns an error object. + //------------------------------------------------------------------ + virtual Error ConnectRemote(Stream *strm, llvm::StringRef remote_url); + + bool GetShouldDetach() const { return m_should_detach; } + + void SetShouldDetach(bool b) { m_should_detach = b; } + + //------------------------------------------------------------------ + /// Get the image information address for the current process. + /// + /// Some runtimes have system functions that can help dynamic + /// loaders locate the dynamic loader information needed to observe + /// shared libraries being loaded or unloaded. This function is + /// in the Process interface (as opposed to the DynamicLoader + /// interface) to ensure that remote debugging can take advantage of + /// this functionality. + /// + /// @return + /// The address of the dynamic loader information, or + /// LLDB_INVALID_ADDRESS if this is not supported by this + /// interface. + //------------------------------------------------------------------ + virtual lldb::addr_t GetImageInfoAddress(); + + //------------------------------------------------------------------ + /// Called when the process is about to broadcast a public stop. + /// + /// There are public and private stops. Private stops are when the + /// process is doing things like stepping and the client doesn't + /// need to know about starts and stop that implement a thread plan. + /// Single stepping over a source line in code might end up being + /// implemented by one or more process starts and stops. Public stops + /// are when clients will be notified that the process is stopped. + /// These events typically trigger UI updates (thread stack frames to + /// be displayed, variables to be displayed, and more). This function + /// can be overriden and allows process subclasses to do something + /// before the eBroadcastBitStateChanged event is sent to public + /// clients. + //------------------------------------------------------------------ + virtual void WillPublicStop() {} + +//------------------------------------------------------------------ +/// Register for process and thread notifications. +/// +/// Clients can register notification callbacks by filling out a +/// Process::Notifications structure and calling this function. +/// +/// @param[in] callbacks +/// A structure that contains the notification baton and +/// callback functions. +/// +/// @see Process::Notifications +//------------------------------------------------------------------ +#ifndef SWIG + void RegisterNotificationCallbacks(const Process::Notifications &callbacks); +#endif - lldb::EventSP - GetStopEventForStopID (uint32_t stop_id) const - { - return m_mod_id.GetStopEventForStopID(stop_id); - } +//------------------------------------------------------------------ +/// Unregister for process and thread notifications. +/// +/// Clients can unregister notification callbacks by passing a copy of +/// the original baton and callbacks in \a callbacks. +/// +/// @param[in] callbacks +/// A structure that contains the notification baton and +/// callback functions. +/// +/// @return +/// Returns \b true if the notification callbacks were +/// successfully removed from the process, \b false otherwise. +/// +/// @see Process::Notifications +//------------------------------------------------------------------ +#ifndef SWIG + bool UnregisterNotificationCallbacks(const Process::Notifications &callbacks); +#endif - //------------------------------------------------------------------ - /// Set accessor for the process exit status (return code). - /// - /// Sometimes a child exits and the exit can be detected by global - /// functions (signal handler for SIGCHLD for example). This - /// accessor allows the exit status to be set from an external - /// source. - /// - /// Setting this will cause a eStateExited event to be posted to - /// the process event queue. - /// - /// @param[in] exit_status - /// The value for the process's return code. - /// - /// @see lldb::StateType - //------------------------------------------------------------------ - virtual bool - SetExitStatus (int exit_status, const char *cstr); - - //------------------------------------------------------------------ - /// Check if a process is still alive. - /// - /// @return - /// Returns \b true if the process is still valid, \b false - /// otherwise. - //------------------------------------------------------------------ - virtual bool - IsAlive (); - - //------------------------------------------------------------------ - /// Before lldb detaches from a process, it warns the user that they are about to lose their debug session. - /// In some cases, this warning doesn't need to be emitted -- for instance, with core file debugging where - /// the user can reconstruct the "state" by simply re-running the debugger on the core file. - /// - /// @return - // true if the user should be warned about detaching from this process. - //------------------------------------------------------------------ - virtual bool - WarnBeforeDetach () const - { - return true; - } + //================================================================== + // Built in Process Control functions + //================================================================== + //------------------------------------------------------------------ + /// Resumes all of a process's threads as configured using the + /// Thread run control functions. + /// + /// Threads for a process should be updated with one of the run + /// control actions (resume, step, or suspend) that they should take + /// when the process is resumed. If no run control action is given + /// to a thread it will be resumed by default. + /// + /// This function is not meant to be overridden by Process + /// subclasses. This function will take care of disabling any + /// breakpoints that threads may be stopped at, single stepping, and + /// re-enabling breakpoints, and enabling the basic flow control + /// that the plug-in instances need not worry about. + /// + /// N.B. This function also sets the Write side of the Run Lock, + /// which is unset when the corresponding stop event is pulled off + /// the Public Event Queue. If you need to resume the process without + /// setting the Run Lock, use PrivateResume (though you should only do + /// that from inside the Process class. + /// + /// @return + /// Returns an error object. + /// + /// @see Thread:Resume() + /// @see Thread:Step() + /// @see Thread:Suspend() + //------------------------------------------------------------------ + Error Resume(); + + Error ResumeSynchronous(Stream *stream); + + //------------------------------------------------------------------ + /// Halts a running process. + /// + /// This function is not meant to be overridden by Process + /// subclasses. + /// If the process is successfully halted, a eStateStopped + /// process event with GetInterrupted will be broadcast. If false, we will + /// halt the process with no events generated by the halt. + /// + /// @param[in] clear_thread_plans + /// If true, when the process stops, clear all thread plans. + /// + /// @param[in] use_run_lock + /// Whether to release the run lock after the stop. + /// + /// @return + /// Returns an error object. If the error is empty, the process is + /// halted. + /// otherwise the halt has failed. + //------------------------------------------------------------------ + Error Halt(bool clear_thread_plans = false, bool use_run_lock = true); + + //------------------------------------------------------------------ + /// Detaches from a running or stopped process. + /// + /// This function is not meant to be overridden by Process + /// subclasses. + /// + /// @param[in] keep_stopped + /// If true, don't resume the process on detach. + /// + /// @return + /// Returns an error object. + //------------------------------------------------------------------ + Error Detach(bool keep_stopped); + + //------------------------------------------------------------------ + /// Kills the process and shuts down all threads that were spawned + /// to track and monitor the process. + /// + /// This function is not meant to be overridden by Process + /// subclasses. + /// + /// @param[in] force_kill + /// Whether lldb should force a kill (instead of a detach) from + /// the inferior process. Normally if lldb launched a binary and + /// Destory is called, lldb kills it. If lldb attached to a + /// running process and Destory is called, lldb detaches. If + /// this behavior needs to be over-ridden, this is the bool that + /// can be used. + /// + /// @return + /// Returns an error object. + //------------------------------------------------------------------ + Error Destroy(bool force_kill); + + //------------------------------------------------------------------ + /// Sends a process a UNIX signal \a signal. + /// + /// This function is not meant to be overridden by Process + /// subclasses. + /// + /// @return + /// Returns an error object. + //------------------------------------------------------------------ + Error Signal(int signal); + + void SetUnixSignals(lldb::UnixSignalsSP &&signals_sp); + + const lldb::UnixSignalsSP &GetUnixSignals(); + + //================================================================== + // Plug-in Process Control Overrides + //================================================================== + + //------------------------------------------------------------------ + /// Called before attaching to a process. + /// + /// Allow Process plug-ins to execute some code before attaching a + /// process. + /// + /// @return + /// Returns an error object. + //------------------------------------------------------------------ + virtual Error WillAttachToProcessWithID(lldb::pid_t pid) { return Error(); } + + //------------------------------------------------------------------ + /// Called before attaching to a process. + /// + /// Allow Process plug-ins to execute some code before attaching a + /// process. + /// + /// @return + /// Returns an error object. + //------------------------------------------------------------------ + virtual Error WillAttachToProcessWithName(const char *process_name, + bool wait_for_launch) { + return Error(); + } + + //------------------------------------------------------------------ + /// Attach to a remote system via a URL + /// + /// @param[in] strm + /// A stream where output intended for the user + /// (if the driver has a way to display that) generated during + /// the connection. This may be nullptr if no output is needed.A + /// + /// @param[in] remote_url + /// The URL format that we are connecting to. + /// + /// @return + /// Returns an error object. + //------------------------------------------------------------------ + virtual Error DoConnectRemote(Stream *strm, llvm::StringRef remote_url) { + Error error; + error.SetErrorString("remote connections are not supported"); + return error; + } + + //------------------------------------------------------------------ + /// Attach to an existing process using a process ID. + /// + /// @param[in] pid + /// The process ID that we should attempt to attach to. + /// + /// @param[in] attach_info + /// Information on how to do the attach. For example, GetUserID() + /// will return the uid to attach as. + /// + /// @return + /// Returns a successful Error attaching was successful, or + /// an appropriate (possibly platform-specific) error code if + /// attaching fails. + /// hanming : need flag + //------------------------------------------------------------------ + virtual Error DoAttachToProcessWithID(lldb::pid_t pid, + const ProcessAttachInfo &attach_info) { + Error error; + error.SetErrorStringWithFormat( + "error: %s does not support attaching to a process by pid", + GetPluginName().GetCString()); + return error; + } + + //------------------------------------------------------------------ + /// Attach to an existing process using a partial process name. + /// + /// @param[in] process_name + /// The name of the process to attach to. + /// + /// @param[in] attach_info + /// Information on how to do the attach. For example, GetUserID() + /// will return the uid to attach as. + /// + /// @return + /// Returns a successful Error attaching was successful, or + /// an appropriate (possibly platform-specific) error code if + /// attaching fails. + //------------------------------------------------------------------ + virtual Error + DoAttachToProcessWithName(const char *process_name, + const ProcessAttachInfo &attach_info) { + Error error; + error.SetErrorString("attach by name is not supported"); + return error; + } + + //------------------------------------------------------------------ + /// Called after attaching a process. + /// + /// @param[in] process_arch + /// If you can figure out the process architecture after attach, fill it + /// in here. + /// + /// Allow Process plug-ins to execute some code after attaching to + /// a process. + //------------------------------------------------------------------ + virtual void DidAttach(ArchSpec &process_arch) { process_arch.Clear(); } + + //------------------------------------------------------------------ + /// Called after a process re-execs itself. + /// + /// Allow Process plug-ins to execute some code after a process has + /// exec'ed itself. Subclasses typically should override DoDidExec() + /// as the lldb_private::Process class needs to remove its dynamic + /// loader, runtime, ABI and other plug-ins, as well as unload all + /// shared libraries. + //------------------------------------------------------------------ + virtual void DidExec(); + + //------------------------------------------------------------------ + /// Subclasses of Process should implement this function if they + /// need to do anything after a process exec's itself. + //------------------------------------------------------------------ + virtual void DoDidExec() {} + + //------------------------------------------------------------------ + /// Called before launching to a process. + /// + /// Allow Process plug-ins to execute some code before launching a + /// process. + /// + /// @return + /// Returns an error object. + //------------------------------------------------------------------ + virtual Error WillLaunch(Module *module) { return Error(); } + + //------------------------------------------------------------------ + /// Launch a new process. + /// + /// Launch a new process by spawning a new process using + /// \a exe_module's file as the file to launch. Launch details are + /// provided in \a launch_info. + /// + /// @param[in] exe_module + /// The module from which to extract the file specification and + /// launch. + /// + /// @param[in] launch_info + /// Details (e.g. arguments, stdio redirection, etc.) for the + /// requested launch. + /// + /// @return + /// An Error instance indicating success or failure of the + /// operation. + //------------------------------------------------------------------ + virtual Error DoLaunch(Module *exe_module, ProcessLaunchInfo &launch_info) { + Error error; + error.SetErrorStringWithFormat( + "error: %s does not support launching processes", + GetPluginName().GetCString()); + return error; + } + + //------------------------------------------------------------------ + /// Called after launching a process. + /// + /// Allow Process plug-ins to execute some code after launching + /// a process. + //------------------------------------------------------------------ + virtual void DidLaunch() {} + + //------------------------------------------------------------------ + /// Called before resuming to a process. + /// + /// Allow Process plug-ins to execute some code before resuming a + /// process. + /// + /// @return + /// Returns an error object. + //------------------------------------------------------------------ + virtual Error WillResume() { return Error(); } + + //------------------------------------------------------------------ + /// Resumes all of a process's threads as configured using the + /// Thread run control functions. + /// + /// Threads for a process should be updated with one of the run + /// control actions (resume, step, or suspend) that they should take + /// when the process is resumed. If no run control action is given + /// to a thread it will be resumed by default. + /// + /// @return + /// Returns \b true if the process successfully resumes using + /// the thread run control actions, \b false otherwise. + /// + /// @see Thread:Resume() + /// @see Thread:Step() + /// @see Thread:Suspend() + //------------------------------------------------------------------ + virtual Error DoResume() { + Error error; + error.SetErrorStringWithFormat( + "error: %s does not support resuming processes", + GetPluginName().GetCString()); + return error; + } + + //------------------------------------------------------------------ + /// Called after resuming a process. + /// + /// Allow Process plug-ins to execute some code after resuming + /// a process. + //------------------------------------------------------------------ + virtual void DidResume() {} + + //------------------------------------------------------------------ + /// Called before halting to a process. + /// + /// Allow Process plug-ins to execute some code before halting a + /// process. + /// + /// @return + /// Returns an error object. + //------------------------------------------------------------------ + virtual Error WillHalt() { return Error(); } + + //------------------------------------------------------------------ + /// Halts a running process. + /// + /// DoHalt must produce one and only one stop StateChanged event if it + /// actually + /// stops the process. If the stop happens through some natural event (for + /// instance a SIGSTOP), then forwarding that event will do. Otherwise, you + /// must + /// generate the event manually. This function is called from the context of + /// the + /// private state thread. + /// + /// @param[out] caused_stop + /// If true, then this Halt caused the stop, otherwise, the + /// process was already stopped. + /// + /// @return + /// Returns \b true if the process successfully halts, \b false + /// otherwise. + //------------------------------------------------------------------ + virtual Error DoHalt(bool &caused_stop) { + Error error; + error.SetErrorStringWithFormat( + "error: %s does not support halting processes", + GetPluginName().GetCString()); + return error; + } + + //------------------------------------------------------------------ + /// Called after halting a process. + /// + /// Allow Process plug-ins to execute some code after halting + /// a process. + //------------------------------------------------------------------ + virtual void DidHalt() {} + + //------------------------------------------------------------------ + /// Called before detaching from a process. + /// + /// Allow Process plug-ins to execute some code before detaching + /// from a process. + /// + /// @return + /// Returns an error object. + //------------------------------------------------------------------ + virtual Error WillDetach() { return Error(); } + + //------------------------------------------------------------------ + /// Detaches from a running or stopped process. + /// + /// @return + /// Returns \b true if the process successfully detaches, \b + /// false otherwise. + //------------------------------------------------------------------ + virtual Error DoDetach(bool keep_stopped) { + Error error; + error.SetErrorStringWithFormat( + "error: %s does not support detaching from processes", + GetPluginName().GetCString()); + return error; + } + + //------------------------------------------------------------------ + /// Called after detaching from a process. + /// + /// Allow Process plug-ins to execute some code after detaching + /// from a process. + //------------------------------------------------------------------ + virtual void DidDetach() {} + + virtual bool DetachRequiresHalt() { return false; } + + //------------------------------------------------------------------ + /// Called before sending a signal to a process. + /// + /// Allow Process plug-ins to execute some code before sending a + /// signal to a process. + /// + /// @return + /// Returns no error if it is safe to proceed with a call to + /// Process::DoSignal(int), otherwise an error describing what + /// prevents the signal from being sent. + //------------------------------------------------------------------ + virtual Error WillSignal() { return Error(); } + + //------------------------------------------------------------------ + /// Sends a process a UNIX signal \a signal. + /// + /// @return + /// Returns an error object. + //------------------------------------------------------------------ + virtual Error DoSignal(int signal) { + Error error; + error.SetErrorStringWithFormat( + "error: %s does not support sending signals to processes", + GetPluginName().GetCString()); + return error; + } + + virtual Error WillDestroy() { return Error(); } + + virtual Error DoDestroy() = 0; + + virtual void DidDestroy() {} + + virtual bool DestroyRequiresHalt() { return true; } + + //------------------------------------------------------------------ + /// Called after sending a signal to a process. + /// + /// Allow Process plug-ins to execute some code after sending a + /// signal to a process. + //------------------------------------------------------------------ + virtual void DidSignal() {} + + //------------------------------------------------------------------ + /// Currently called as part of ShouldStop. + /// FIXME: Should really happen when the target stops before the + /// event is taken from the queue... + /// + /// This callback is called as the event + /// is about to be queued up to allow Process plug-ins to execute + /// some code prior to clients being notified that a process was + /// stopped. Common operations include updating the thread list, + /// invalidating any thread state (registers, stack, etc) prior to + /// letting the notification go out. + /// + //------------------------------------------------------------------ + virtual void RefreshStateAfterStop() = 0; + + //------------------------------------------------------------------ + /// Sometimes the connection to a process can detect the host OS + /// version that the process is running on. The current platform + /// should be checked first in case the platform is connected, but + /// clients can fall back onto this function if the platform fails + /// to identify the host OS version. The platform should be checked + /// first in case you are running a simulator platform that might + /// itself be running natively, but have different heuristics for + /// figuring out which OS is is emulating. + /// + /// @param[out] major + /// The major OS version, or UINT32_MAX if it can't be determined + /// + /// @param[out] minor + /// The minor OS version, or UINT32_MAX if it can't be determined + /// + /// @param[out] update + /// The update OS version, or UINT32_MAX if it can't be determined + /// + /// @return + /// Returns \b true if the host OS version info was filled in + /// and \b false otherwise. + //------------------------------------------------------------------ + virtual bool GetHostOSVersion(uint32_t &major, uint32_t &minor, + uint32_t &update) { + major = UINT32_MAX; + minor = UINT32_MAX; + update = UINT32_MAX; + return false; + } + + //------------------------------------------------------------------ + /// Get the target object pointer for this module. + /// + /// @return + /// A Target object pointer to the target that owns this + /// module. + //------------------------------------------------------------------ + Target &GetTarget() { return *m_target_sp.lock(); } + + //------------------------------------------------------------------ + /// Get the const target object pointer for this module. + /// + /// @return + /// A const Target object pointer to the target that owns this + /// module. + //------------------------------------------------------------------ + const Target &GetTarget() const { return *m_target_sp.lock(); } + + //------------------------------------------------------------------ + /// Flush all data in the process. + /// + /// Flush the memory caches, all threads, and any other cached data + /// in the process. + /// + /// This function can be called after a world changing event like + /// adding a new symbol file, or after the process makes a large + /// context switch (from boot ROM to booted into an OS). + //------------------------------------------------------------------ + void Flush(); + + //------------------------------------------------------------------ + /// Get accessor for the current process state. + /// + /// @return + /// The current state of the process. + /// + /// @see lldb::StateType + //------------------------------------------------------------------ + lldb::StateType GetState(); + + lldb::ExpressionResults + RunThreadPlan(ExecutionContext &exe_ctx, lldb::ThreadPlanSP &thread_plan_sp, + const EvaluateExpressionOptions &options, + DiagnosticManager &diagnostic_manager); + + static const char *ExecutionResultAsCString(lldb::ExpressionResults result); + + void GetStatus(Stream &ostrm); + + size_t GetThreadStatus(Stream &ostrm, bool only_threads_with_stop_reason, + uint32_t start_frame, uint32_t num_frames, + uint32_t num_frames_with_source, + bool stop_format); + + void SendAsyncInterrupt(); + + //------------------------------------------------------------------ + // Notify this process class that modules got loaded. + // + // If subclasses override this method, they must call this version + // before doing anything in the subclass version of the function. + //------------------------------------------------------------------ + virtual void ModulesDidLoad(ModuleList &module_list); + + //------------------------------------------------------------------ + /// Retrieve the list of shared libraries that are loaded for this process + /// This method is used on pre-macOS 10.12, pre-iOS 10, pre-tvOS 10, + /// pre-watchOS 3 systems. The following two methods are for newer versions + /// of those OSes. + /// + /// For certain platforms, the time it takes for the DynamicLoader plugin to + /// read all of the shared libraries out of memory over a slow communication + /// channel may be too long. In that instance, the gdb-remote stub may be + /// able to retrieve the necessary information about the solibs out of memory + /// and return a concise summary sufficient for the DynamicLoader plugin. + /// + /// @param [in] image_list_address + /// The address where the table of shared libraries is stored in memory, + /// if that is appropriate for this platform. Else this may be + /// passed as LLDB_INVALID_ADDRESS. + /// + /// @param [in] image_count + /// The number of shared libraries that are present in this process, if + /// that is appropriate for this platofrm Else this may be passed as + /// LLDB_INVALID_ADDRESS. + /// + /// @return + /// A StructureDataSP object which, if non-empty, will contain the + /// information the DynamicLoader needs to get the initial scan of + /// solibs resolved. + //------------------------------------------------------------------ + virtual lldb_private::StructuredData::ObjectSP + GetLoadedDynamicLibrariesInfos(lldb::addr_t image_list_address, + lldb::addr_t image_count) { + return StructuredData::ObjectSP(); + } + + // On macOS 10.12, tvOS 10, iOS 10, watchOS 3 and newer, debugserver can + // return + // the full list of loaded shared libraries without needing any input. + virtual lldb_private::StructuredData::ObjectSP + GetLoadedDynamicLibrariesInfos() { + return StructuredData::ObjectSP(); + } + + // On macOS 10.12, tvOS 10, iOS 10, watchOS 3 and newer, debugserver can + // return + // information about binaries given their load addresses. + virtual lldb_private::StructuredData::ObjectSP GetLoadedDynamicLibrariesInfos( + const std::vector<lldb::addr_t> &load_addresses) { + return StructuredData::ObjectSP(); + } + + //------------------------------------------------------------------ + // Get information about the library shared cache, if that exists + // + // On macOS 10.12, tvOS 10, iOS 10, watchOS 3 and newer, debugserver can + // return + // information about the library shared cache (a set of standard libraries + // that are + // loaded at the same location for all processes on a system) in use. + //------------------------------------------------------------------ + virtual lldb_private::StructuredData::ObjectSP GetSharedCacheInfo() { + return StructuredData::ObjectSP(); + } + + //------------------------------------------------------------------ + /// Print a user-visible warning about a module being built with optimization + /// + /// Prints a async warning message to the user one time per Module + /// where a function is found that was compiled with optimization, per + /// Process. + /// + /// @param [in] sc + /// A SymbolContext with eSymbolContextFunction and eSymbolContextModule + /// pre-computed. + //------------------------------------------------------------------ + void PrintWarningOptimization(const SymbolContext &sc); + + virtual bool GetProcessInfo(ProcessInstanceInfo &info); - //------------------------------------------------------------------ - /// Actually do the reading of memory from a process. - /// - /// Subclasses must override this function and can return fewer - /// bytes than requested when memory requests are too large. This - /// class will break up the memory requests and keep advancing the - /// arguments along as needed. - /// - /// @param[in] vm_addr - /// A virtual load address that indicates where to start reading - /// memory from. - /// - /// @param[in] size - /// The number of bytes to read. - /// - /// @param[out] buf - /// A byte buffer that is at least \a size bytes long that - /// will receive the memory bytes. - /// - /// @return - /// The number of bytes that were actually read into \a buf. - //------------------------------------------------------------------ - virtual size_t - DoReadMemory (lldb::addr_t vm_addr, - void *buf, - size_t size, - Error &error) = 0; - - //------------------------------------------------------------------ - /// Read of memory from a process. - /// - /// This function will read memory from the current process's - /// address space and remove any traps that may have been inserted - /// into the memory. - /// - /// This function is not meant to be overridden by Process - /// subclasses, the subclasses should implement - /// Process::DoReadMemory (lldb::addr_t, size_t, void *). - /// - /// @param[in] vm_addr - /// A virtual load address that indicates where to start reading - /// memory from. - /// - /// @param[out] buf - /// A byte buffer that is at least \a size bytes long that - /// will receive the memory bytes. - /// - /// @param[in] size - /// The number of bytes to read. - /// - /// @return - /// The number of bytes that were actually read into \a buf. If - /// the returned number is greater than zero, yet less than \a - /// size, then this function will get called again with \a - /// vm_addr, \a buf, and \a size updated appropriately. Zero is - /// returned to indicate an error. - //------------------------------------------------------------------ - virtual size_t - ReadMemory (lldb::addr_t vm_addr, - void *buf, - size_t size, - Error &error); - - //------------------------------------------------------------------ - /// Read a NULL terminated string from memory - /// - /// This function will read a cache page at a time until a NULL - /// string terminator is found. It will stop reading if an aligned - /// sequence of NULL termination \a type_width bytes is not found - /// before reading \a cstr_max_len bytes. The results are always - /// guaranteed to be NULL terminated, and that no more than - /// (max_bytes - type_width) bytes will be read. - /// - /// @param[in] vm_addr - /// The virtual load address to start the memory read. - /// - /// @param[in] str - /// A character buffer containing at least max_bytes. - /// - /// @param[in] max_bytes - /// The maximum number of bytes to read. - /// - /// @param[in] error - /// The error status of the read operation. - /// - /// @param[in] type_width - /// The size of the null terminator (1 to 4 bytes per - /// character). Defaults to 1. - /// - /// @return - /// The error status or the number of bytes prior to the null terminator. - //------------------------------------------------------------------ - size_t - ReadStringFromMemory (lldb::addr_t vm_addr, - char *str, - size_t max_bytes, - Error &error, - size_t type_width = 1); - - //------------------------------------------------------------------ - /// Read a NULL terminated C string from memory - /// - /// This function will read a cache page at a time until the NULL - /// C string terminator is found. It will stop reading if the NULL - /// termination byte isn't found before reading \a cstr_max_len - /// bytes, and the results are always guaranteed to be NULL - /// terminated (at most cstr_max_len - 1 bytes will be read). - //------------------------------------------------------------------ - size_t - ReadCStringFromMemory (lldb::addr_t vm_addr, - char *cstr, - size_t cstr_max_len, - Error &error); - - size_t - ReadCStringFromMemory (lldb::addr_t vm_addr, - std::string &out_str, - Error &error); - - size_t - ReadMemoryFromInferior (lldb::addr_t vm_addr, - void *buf, - size_t size, +public: + //------------------------------------------------------------------ + /// Get the exit status for a process. + /// + /// @return + /// The process's return code, or -1 if the current process + /// state is not eStateExited. + //------------------------------------------------------------------ + int GetExitStatus(); + + //------------------------------------------------------------------ + /// Get a textual description of what the process exited. + /// + /// @return + /// The textual description of why the process exited, or nullptr + /// if there is no description available. + //------------------------------------------------------------------ + const char *GetExitDescription(); + + virtual void DidExit() {} + + //------------------------------------------------------------------ + /// Get the Modification ID of the process. + /// + /// @return + /// The modification ID of the process. + //------------------------------------------------------------------ + ProcessModID GetModID() const { return m_mod_id; } + + const ProcessModID &GetModIDRef() const { return m_mod_id; } + + uint32_t GetStopID() const { return m_mod_id.GetStopID(); } + + uint32_t GetResumeID() const { return m_mod_id.GetResumeID(); } + + uint32_t GetLastUserExpressionResumeID() const { + return m_mod_id.GetLastUserExpressionResumeID(); + } + + uint32_t GetLastNaturalStopID() const { + return m_mod_id.GetLastNaturalStopID(); + } + + lldb::EventSP GetStopEventForStopID(uint32_t stop_id) const { + return m_mod_id.GetStopEventForStopID(stop_id); + } + + //------------------------------------------------------------------ + /// Set accessor for the process exit status (return code). + /// + /// Sometimes a child exits and the exit can be detected by global + /// functions (signal handler for SIGCHLD for example). This + /// accessor allows the exit status to be set from an external + /// source. + /// + /// Setting this will cause a eStateExited event to be posted to + /// the process event queue. + /// + /// @param[in] exit_status + /// The value for the process's return code. + /// + /// @see lldb::StateType + //------------------------------------------------------------------ + virtual bool SetExitStatus(int exit_status, const char *cstr); + + //------------------------------------------------------------------ + /// Check if a process is still alive. + /// + /// @return + /// Returns \b true if the process is still valid, \b false + /// otherwise. + //------------------------------------------------------------------ + virtual bool IsAlive(); + + //------------------------------------------------------------------ + /// Before lldb detaches from a process, it warns the user that they are about + /// to lose their debug session. + /// In some cases, this warning doesn't need to be emitted -- for instance, + /// with core file debugging where + /// the user can reconstruct the "state" by simply re-running the debugger on + /// the core file. + /// + /// @return + // true if the user should be warned about detaching from this process. + //------------------------------------------------------------------ + virtual bool WarnBeforeDetach() const { return true; } + + //------------------------------------------------------------------ + /// Actually do the reading of memory from a process. + /// + /// Subclasses must override this function and can return fewer + /// bytes than requested when memory requests are too large. This + /// class will break up the memory requests and keep advancing the + /// arguments along as needed. + /// + /// @param[in] vm_addr + /// A virtual load address that indicates where to start reading + /// memory from. + /// + /// @param[in] size + /// The number of bytes to read. + /// + /// @param[out] buf + /// A byte buffer that is at least \a size bytes long that + /// will receive the memory bytes. + /// + /// @return + /// The number of bytes that were actually read into \a buf. + //------------------------------------------------------------------ + virtual size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, + Error &error) = 0; + + //------------------------------------------------------------------ + /// Read of memory from a process. + /// + /// This function will read memory from the current process's + /// address space and remove any traps that may have been inserted + /// into the memory. + /// + /// This function is not meant to be overridden by Process + /// subclasses, the subclasses should implement + /// Process::DoReadMemory (lldb::addr_t, size_t, void *). + /// + /// @param[in] vm_addr + /// A virtual load address that indicates where to start reading + /// memory from. + /// + /// @param[out] buf + /// A byte buffer that is at least \a size bytes long that + /// will receive the memory bytes. + /// + /// @param[in] size + /// The number of bytes to read. + /// + /// @return + /// The number of bytes that were actually read into \a buf. If + /// the returned number is greater than zero, yet less than \a + /// size, then this function will get called again with \a + /// vm_addr, \a buf, and \a size updated appropriately. Zero is + /// returned to indicate an error. + //------------------------------------------------------------------ + virtual size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, Error &error); - - //------------------------------------------------------------------ - /// Reads an unsigned integer of the specified byte size from - /// process memory. - /// - /// @param[in] load_addr - /// A load address of the integer to read. - /// - /// @param[in] byte_size - /// The size in byte of the integer to read. - /// - /// @param[in] fail_value - /// The value to return if we fail to read an integer. - /// - /// @param[out] error - /// An error that indicates the success or failure of this - /// operation. If error indicates success (error.Success()), - /// then the value returned can be trusted, otherwise zero - /// will be returned. - /// - /// @return - /// The unsigned integer that was read from the process memory - /// space. If the integer was smaller than a uint64_t, any - /// unused upper bytes will be zero filled. If the process - /// byte order differs from the host byte order, the integer - /// value will be appropriately byte swapped into host byte - /// order. - //------------------------------------------------------------------ - uint64_t - ReadUnsignedIntegerFromMemory(lldb::addr_t load_addr, size_t byte_size, uint64_t fail_value, Error &error); - - int64_t - ReadSignedIntegerFromMemory(lldb::addr_t load_addr, size_t byte_size, int64_t fail_value, Error &error); - - lldb::addr_t - ReadPointerFromMemory (lldb::addr_t vm_addr, - Error &error); - - bool - WritePointerToMemory (lldb::addr_t vm_addr, - lldb::addr_t ptr_value, - Error &error); - - //------------------------------------------------------------------ - /// Actually do the writing of memory to a process. - /// - /// @param[in] vm_addr - /// A virtual load address that indicates where to start writing - /// memory to. - /// - /// @param[in] buf - /// A byte buffer that is at least \a size bytes long that - /// contains the data to write. - /// - /// @param[in] size - /// The number of bytes to write. - /// - /// @param[out] error - /// An error value in case the memory write fails. - /// - /// @return - /// The number of bytes that were actually written. - //------------------------------------------------------------------ - virtual size_t - DoWriteMemory (lldb::addr_t vm_addr, const void *buf, size_t size, Error &error) - { - error.SetErrorStringWithFormat("error: %s does not support writing to processes", GetPluginName().GetCString()); - return 0; - } - - //------------------------------------------------------------------ - /// Write all or part of a scalar value to memory. - /// - /// The value contained in \a scalar will be swapped to match the - /// byte order of the process that is being debugged. If \a size is - /// less than the size of scalar, the least significant \a size bytes - /// from scalar will be written. If \a size is larger than the byte - /// size of scalar, then the extra space will be padded with zeros - /// and the scalar value will be placed in the least significant - /// bytes in memory. - /// - /// @param[in] vm_addr - /// A virtual load address that indicates where to start writing - /// memory to. - /// - /// @param[in] scalar - /// The scalar to write to the debugged process. - /// - /// @param[in] size - /// This value can be smaller or larger than the scalar value - /// itself. If \a size is smaller than the size of \a scalar, - /// the least significant bytes in \a scalar will be used. If - /// \a size is larger than the byte size of \a scalar, then - /// the extra space will be padded with zeros. If \a size is - /// set to UINT32_MAX, then the size of \a scalar will be used. - /// - /// @param[out] error - /// An error value in case the memory write fails. - /// - /// @return - /// The number of bytes that were actually written. - //------------------------------------------------------------------ - size_t - WriteScalarToMemory (lldb::addr_t vm_addr, - const Scalar &scalar, - size_t size, - Error &error); - - size_t - ReadScalarIntegerFromMemory (lldb::addr_t addr, - uint32_t byte_size, - bool is_signed, - Scalar &scalar, - Error &error); - - //------------------------------------------------------------------ - /// Write memory to a process. - /// - /// This function will write memory to the current process's - /// address space and maintain any traps that might be present due - /// to software breakpoints. - /// - /// This function is not meant to be overridden by Process - /// subclasses, the subclasses should implement - /// Process::DoWriteMemory (lldb::addr_t, size_t, void *). - /// - /// @param[in] vm_addr - /// A virtual load address that indicates where to start writing - /// memory to. - /// - /// @param[in] buf - /// A byte buffer that is at least \a size bytes long that - /// contains the data to write. - /// - /// @param[in] size - /// The number of bytes to write. - /// - /// @return - /// The number of bytes that were actually written. - //------------------------------------------------------------------ - size_t - WriteMemory (lldb::addr_t vm_addr, const void *buf, size_t size, Error &error); - - //------------------------------------------------------------------ - /// Actually allocate memory in the process. - /// - /// This function will allocate memory in the process's address - /// space. This can't rely on the generic function calling mechanism, - /// since that requires this function. - /// - /// @param[in] size - /// The size of the allocation requested. - /// - /// @return - /// The address of the allocated buffer in the process, or - /// LLDB_INVALID_ADDRESS if the allocation failed. - //------------------------------------------------------------------ - - virtual lldb::addr_t - DoAllocateMemory (size_t size, uint32_t permissions, Error &error) - { - error.SetErrorStringWithFormat("error: %s does not support allocating in the debug process", GetPluginName().GetCString()); - return LLDB_INVALID_ADDRESS; - } - - //------------------------------------------------------------------ - /// The public interface to allocating memory in the process. - /// - /// This function will allocate memory in the process's address - /// space. This can't rely on the generic function calling mechanism, - /// since that requires this function. - /// - /// @param[in] size - /// The size of the allocation requested. - /// - /// @param[in] permissions - /// Or together any of the lldb::Permissions bits. The permissions on - /// a given memory allocation can't be changed after allocation. Note - /// that a block that isn't set writable can still be written on from lldb, - /// just not by the process itself. - /// - /// @param[in,out] error - /// An error object to fill in if things go wrong. - /// @return - /// The address of the allocated buffer in the process, or - /// LLDB_INVALID_ADDRESS if the allocation failed. - //------------------------------------------------------------------ - lldb::addr_t - AllocateMemory (size_t size, uint32_t permissions, Error &error); - - //------------------------------------------------------------------ - /// The public interface to allocating memory in the process, this also - /// clears the allocated memory. - /// - /// This function will allocate memory in the process's address - /// space. This can't rely on the generic function calling mechanism, - /// since that requires this function. - /// - /// @param[in] size - /// The size of the allocation requested. - /// - /// @param[in] permissions - /// Or together any of the lldb::Permissions bits. The permissions on - /// a given memory allocation can't be changed after allocation. Note - /// that a block that isn't set writable can still be written on from lldb, - /// just not by the process itself. - /// - /// @param[in/out] error - /// An error object to fill in if things go wrong. - /// @return - /// The address of the allocated buffer in the process, or - /// LLDB_INVALID_ADDRESS if the allocation failed. - //------------------------------------------------------------------ - - lldb::addr_t - CallocateMemory (size_t size, uint32_t permissions, Error &error); - - //------------------------------------------------------------------ - /// Resolve dynamically loaded indirect functions. - /// - /// @param[in] address - /// The load address of the indirect function to resolve. - /// - /// @param[out] error - /// An error value in case the resolve fails. - /// - /// @return - /// The address of the resolved function. - /// LLDB_INVALID_ADDRESS if the resolution failed. - //------------------------------------------------------------------ - virtual lldb::addr_t - ResolveIndirectFunction(const Address *address, Error &error); - - //------------------------------------------------------------------ - /// Locate the memory region that contains load_addr. - /// - /// If load_addr is within the address space the process has mapped - /// range_info will be filled in with the start and end of that range - /// as well as the permissions for that range and range_info.GetMapped - /// will return true. - /// - /// If load_addr is outside any mapped region then range_info will - /// have its start address set to load_addr and the end of the - /// range will indicate the start of the next mapped range or be - /// set to LLDB_INVALID_ADDRESS if there are no valid mapped ranges - /// between load_addr and the end of the process address space. - /// - /// GetMemoryRegionInfo will only return an error if it is - /// unimplemented for the current process. - /// - /// @param[in] load_addr - /// The load address to query the range_info for. - /// - /// @param[out] range_info - /// An range_info value containing the details of the range. - /// - /// @return - /// An error value. - //------------------------------------------------------------------ - virtual Error - GetMemoryRegionInfo (lldb::addr_t load_addr, - MemoryRegionInfo &range_info) - { - Error error; - error.SetErrorString ("Process::GetMemoryRegionInfo() not supported"); - return error; - } - - //------------------------------------------------------------------ - /// Obtain all the mapped memory regions within this process. - /// - /// @param[out] region_list - /// A vector to contain MemoryRegionInfo objects for all mapped - /// ranges. - /// - /// @return - /// An error value. - //------------------------------------------------------------------ - virtual Error - GetMemoryRegions (std::vector<lldb::MemoryRegionInfoSP>& region_list); - - virtual Error - GetWatchpointSupportInfo (uint32_t &num) - { - Error error; - num = 0; - error.SetErrorString ("Process::GetWatchpointSupportInfo() not supported"); - return error; - } - virtual Error - GetWatchpointSupportInfo (uint32_t &num, bool& after) - { - Error error; - num = 0; - after = true; - error.SetErrorString ("Process::GetWatchpointSupportInfo() not supported"); - return error; - } - - lldb::ModuleSP - ReadModuleFromMemory (const FileSpec& file_spec, - lldb::addr_t header_addr, - size_t size_to_read = 512); - - //------------------------------------------------------------------ - /// Attempt to get the attributes for a region of memory in the process. - /// - /// It may be possible for the remote debug server to inspect attributes - /// for a region of memory in the process, such as whether there is a - /// valid page of memory at a given address or whether that page is - /// readable/writable/executable by the process. - /// - /// @param[in] load_addr - /// The address of interest in the process. - /// - /// @param[out] permissions - /// If this call returns successfully, this bitmask will have - /// its Permissions bits set to indicate whether the region is - /// readable/writable/executable. If this call fails, the - /// bitmask values are undefined. - /// - /// @return - /// Returns true if it was able to determine the attributes of the - /// memory region. False if not. - //------------------------------------------------------------------ - virtual bool - GetLoadAddressPermissions (lldb::addr_t load_addr, uint32_t &permissions); - - //------------------------------------------------------------------ - /// Determines whether executing JIT-compiled code in this process - /// is possible. - /// - /// @return - /// True if execution of JIT code is possible; false otherwise. - //------------------------------------------------------------------ - bool CanJIT (); - - //------------------------------------------------------------------ - /// Sets whether executing JIT-compiled code in this process - /// is possible. - /// - /// @param[in] can_jit - /// True if execution of JIT code is possible; false otherwise. - //------------------------------------------------------------------ - void SetCanJIT (bool can_jit); - - //------------------------------------------------------------------ - /// Determines whether executing function calls using the interpreter - /// is possible for this process. - /// - /// @return - /// True if possible; false otherwise. - //------------------------------------------------------------------ - bool CanInterpretFunctionCalls () - { - return m_can_interpret_function_calls; - } - - //------------------------------------------------------------------ - /// Sets whether executing function calls using the interpreter - /// is possible for this process. - /// - /// @param[in] can_interpret_function_calls - /// True if possible; false otherwise. - //------------------------------------------------------------------ - void SetCanInterpretFunctionCalls (bool can_interpret_function_calls) - { - m_can_interpret_function_calls = can_interpret_function_calls; - } - - //------------------------------------------------------------------ - /// Sets whether executing code in this process is possible. - /// This could be either through JIT or interpreting. - /// - /// @param[in] can_run_code - /// True if execution of code is possible; false otherwise. - //------------------------------------------------------------------ - void SetCanRunCode (bool can_run_code); - - //------------------------------------------------------------------ - /// Actually deallocate memory in the process. - /// - /// This function will deallocate memory in the process's address - /// space that was allocated with AllocateMemory. - /// - /// @param[in] ptr - /// A return value from AllocateMemory, pointing to the memory you - /// want to deallocate. - /// - /// @return - /// \btrue if the memory was deallocated, \bfalse otherwise. - //------------------------------------------------------------------ - virtual Error - DoDeallocateMemory (lldb::addr_t ptr) - { - Error error; - error.SetErrorStringWithFormat("error: %s does not support deallocating in the debug process", GetPluginName().GetCString()); - return error; - } + //------------------------------------------------------------------ + /// Read a NULL terminated string from memory + /// + /// This function will read a cache page at a time until a NULL + /// string terminator is found. It will stop reading if an aligned + /// sequence of NULL termination \a type_width bytes is not found + /// before reading \a cstr_max_len bytes. The results are always + /// guaranteed to be NULL terminated, and that no more than + /// (max_bytes - type_width) bytes will be read. + /// + /// @param[in] vm_addr + /// The virtual load address to start the memory read. + /// + /// @param[in] str + /// A character buffer containing at least max_bytes. + /// + /// @param[in] max_bytes + /// The maximum number of bytes to read. + /// + /// @param[in] error + /// The error status of the read operation. + /// + /// @param[in] type_width + /// The size of the null terminator (1 to 4 bytes per + /// character). Defaults to 1. + /// + /// @return + /// The error status or the number of bytes prior to the null terminator. + //------------------------------------------------------------------ + size_t ReadStringFromMemory(lldb::addr_t vm_addr, char *str, size_t max_bytes, + Error &error, size_t type_width = 1); + + //------------------------------------------------------------------ + /// Read a NULL terminated C string from memory + /// + /// This function will read a cache page at a time until the NULL + /// C string terminator is found. It will stop reading if the NULL + /// termination byte isn't found before reading \a cstr_max_len + /// bytes, and the results are always guaranteed to be NULL + /// terminated (at most cstr_max_len - 1 bytes will be read). + //------------------------------------------------------------------ + size_t ReadCStringFromMemory(lldb::addr_t vm_addr, char *cstr, + size_t cstr_max_len, Error &error); + + size_t ReadCStringFromMemory(lldb::addr_t vm_addr, std::string &out_str, + Error &error); + + size_t ReadMemoryFromInferior(lldb::addr_t vm_addr, void *buf, size_t size, + Error &error); + + //------------------------------------------------------------------ + /// Reads an unsigned integer of the specified byte size from + /// process memory. + /// + /// @param[in] load_addr + /// A load address of the integer to read. + /// + /// @param[in] byte_size + /// The size in byte of the integer to read. + /// + /// @param[in] fail_value + /// The value to return if we fail to read an integer. + /// + /// @param[out] error + /// An error that indicates the success or failure of this + /// operation. If error indicates success (error.Success()), + /// then the value returned can be trusted, otherwise zero + /// will be returned. + /// + /// @return + /// The unsigned integer that was read from the process memory + /// space. If the integer was smaller than a uint64_t, any + /// unused upper bytes will be zero filled. If the process + /// byte order differs from the host byte order, the integer + /// value will be appropriately byte swapped into host byte + /// order. + //------------------------------------------------------------------ + uint64_t ReadUnsignedIntegerFromMemory(lldb::addr_t load_addr, + size_t byte_size, uint64_t fail_value, + Error &error); + + int64_t ReadSignedIntegerFromMemory(lldb::addr_t load_addr, size_t byte_size, + int64_t fail_value, Error &error); + + lldb::addr_t ReadPointerFromMemory(lldb::addr_t vm_addr, Error &error); + + bool WritePointerToMemory(lldb::addr_t vm_addr, lldb::addr_t ptr_value, + Error &error); - //------------------------------------------------------------------ - /// The public interface to deallocating memory in the process. - /// - /// This function will deallocate memory in the process's address - /// space that was allocated with AllocateMemory. - /// - /// @param[in] ptr - /// A return value from AllocateMemory, pointing to the memory you - /// want to deallocate. - /// - /// @return - /// \btrue if the memory was deallocated, \bfalse otherwise. - //------------------------------------------------------------------ - Error - DeallocateMemory (lldb::addr_t ptr); - - //------------------------------------------------------------------ - /// Get any available STDOUT. - /// - /// Calling this method is a valid operation only if all of the - /// following conditions are true: - /// 1) The process was launched, and not attached to. - /// 2) The process was not launched with eLaunchFlagDisableSTDIO. - /// 3) The process was launched without supplying a valid file path - /// for STDOUT. - /// - /// Note that the implementation will probably need to start a read - /// thread in the background to make sure that the pipe is drained - /// and the STDOUT buffered appropriately, to prevent the process - /// from deadlocking trying to write to a full buffer. - /// - /// Events will be queued indicating that there is STDOUT available - /// that can be retrieved using this function. - /// - /// @param[out] buf - /// A buffer that will receive any STDOUT bytes that are - /// currently available. - /// - /// @param[in] buf_size - /// The size in bytes for the buffer \a buf. - /// - /// @return - /// The number of bytes written into \a buf. If this value is - /// equal to \a buf_size, another call to this function should - /// be made to retrieve more STDOUT data. - //------------------------------------------------------------------ - virtual size_t - GetSTDOUT (char *buf, size_t buf_size, Error &error); - - //------------------------------------------------------------------ - /// Get any available STDERR. - /// - /// Calling this method is a valid operation only if all of the - /// following conditions are true: - /// 1) The process was launched, and not attached to. - /// 2) The process was not launched with eLaunchFlagDisableSTDIO. - /// 3) The process was launched without supplying a valid file path - /// for STDERR. - /// - /// Note that the implementation will probably need to start a read - /// thread in the background to make sure that the pipe is drained - /// and the STDERR buffered appropriately, to prevent the process - /// from deadlocking trying to write to a full buffer. - /// - /// Events will be queued indicating that there is STDERR available - /// that can be retrieved using this function. - /// - /// @param[in] buf - /// A buffer that will receive any STDERR bytes that are - /// currently available. - /// - /// @param[out] buf_size - /// The size in bytes for the buffer \a buf. - /// - /// @return - /// The number of bytes written into \a buf. If this value is - /// equal to \a buf_size, another call to this function should - /// be made to retrieve more STDERR data. - //------------------------------------------------------------------ - virtual size_t - GetSTDERR (char *buf, size_t buf_size, Error &error); - - //------------------------------------------------------------------ - /// Puts data into this process's STDIN. - /// - /// Calling this method is a valid operation only if all of the - /// following conditions are true: - /// 1) The process was launched, and not attached to. - /// 2) The process was not launched with eLaunchFlagDisableSTDIO. - /// 3) The process was launched without supplying a valid file path - /// for STDIN. - /// - /// @param[in] buf - /// A buffer that contains the data to write to the process's STDIN. - /// - /// @param[in] buf_size - /// The size in bytes for the buffer \a buf. - /// - /// @return - /// The number of bytes written into \a buf. If this value is - /// less than \a buf_size, another call to this function should - /// be made to write the rest of the data. - //------------------------------------------------------------------ - virtual size_t - PutSTDIN (const char *buf, size_t buf_size, Error &error) - { - error.SetErrorString("stdin unsupported"); - return 0; - } + //------------------------------------------------------------------ + /// Actually do the writing of memory to a process. + /// + /// @param[in] vm_addr + /// A virtual load address that indicates where to start writing + /// memory to. + /// + /// @param[in] buf + /// A byte buffer that is at least \a size bytes long that + /// contains the data to write. + /// + /// @param[in] size + /// The number of bytes to write. + /// + /// @param[out] error + /// An error value in case the memory write fails. + /// + /// @return + /// The number of bytes that were actually written. + //------------------------------------------------------------------ + virtual size_t DoWriteMemory(lldb::addr_t vm_addr, const void *buf, + size_t size, Error &error) { + error.SetErrorStringWithFormat( + "error: %s does not support writing to processes", + GetPluginName().GetCString()); + return 0; + } + + //------------------------------------------------------------------ + /// Write all or part of a scalar value to memory. + /// + /// The value contained in \a scalar will be swapped to match the + /// byte order of the process that is being debugged. If \a size is + /// less than the size of scalar, the least significant \a size bytes + /// from scalar will be written. If \a size is larger than the byte + /// size of scalar, then the extra space will be padded with zeros + /// and the scalar value will be placed in the least significant + /// bytes in memory. + /// + /// @param[in] vm_addr + /// A virtual load address that indicates where to start writing + /// memory to. + /// + /// @param[in] scalar + /// The scalar to write to the debugged process. + /// + /// @param[in] size + /// This value can be smaller or larger than the scalar value + /// itself. If \a size is smaller than the size of \a scalar, + /// the least significant bytes in \a scalar will be used. If + /// \a size is larger than the byte size of \a scalar, then + /// the extra space will be padded with zeros. If \a size is + /// set to UINT32_MAX, then the size of \a scalar will be used. + /// + /// @param[out] error + /// An error value in case the memory write fails. + /// + /// @return + /// The number of bytes that were actually written. + //------------------------------------------------------------------ + size_t WriteScalarToMemory(lldb::addr_t vm_addr, const Scalar &scalar, + size_t size, Error &error); + + size_t ReadScalarIntegerFromMemory(lldb::addr_t addr, uint32_t byte_size, + bool is_signed, Scalar &scalar, + Error &error); + + //------------------------------------------------------------------ + /// Write memory to a process. + /// + /// This function will write memory to the current process's + /// address space and maintain any traps that might be present due + /// to software breakpoints. + /// + /// This function is not meant to be overridden by Process + /// subclasses, the subclasses should implement + /// Process::DoWriteMemory (lldb::addr_t, size_t, void *). + /// + /// @param[in] vm_addr + /// A virtual load address that indicates where to start writing + /// memory to. + /// + /// @param[in] buf + /// A byte buffer that is at least \a size bytes long that + /// contains the data to write. + /// + /// @param[in] size + /// The number of bytes to write. + /// + /// @return + /// The number of bytes that were actually written. + //------------------------------------------------------------------ + // TODO: change this to take an ArrayRef<uint8_t> + size_t WriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, + Error &error); + + //------------------------------------------------------------------ + /// Actually allocate memory in the process. + /// + /// This function will allocate memory in the process's address + /// space. This can't rely on the generic function calling mechanism, + /// since that requires this function. + /// + /// @param[in] size + /// The size of the allocation requested. + /// + /// @return + /// The address of the allocated buffer in the process, or + /// LLDB_INVALID_ADDRESS if the allocation failed. + //------------------------------------------------------------------ + + virtual lldb::addr_t DoAllocateMemory(size_t size, uint32_t permissions, + Error &error) { + error.SetErrorStringWithFormat( + "error: %s does not support allocating in the debug process", + GetPluginName().GetCString()); + return LLDB_INVALID_ADDRESS; + } + + //------------------------------------------------------------------ + /// The public interface to allocating memory in the process. + /// + /// This function will allocate memory in the process's address + /// space. This can't rely on the generic function calling mechanism, + /// since that requires this function. + /// + /// @param[in] size + /// The size of the allocation requested. + /// + /// @param[in] permissions + /// Or together any of the lldb::Permissions bits. The permissions on + /// a given memory allocation can't be changed after allocation. Note + /// that a block that isn't set writable can still be written on from + /// lldb, + /// just not by the process itself. + /// + /// @param[in,out] error + /// An error object to fill in if things go wrong. + /// @return + /// The address of the allocated buffer in the process, or + /// LLDB_INVALID_ADDRESS if the allocation failed. + //------------------------------------------------------------------ + lldb::addr_t AllocateMemory(size_t size, uint32_t permissions, Error &error); + + //------------------------------------------------------------------ + /// The public interface to allocating memory in the process, this also + /// clears the allocated memory. + /// + /// This function will allocate memory in the process's address + /// space. This can't rely on the generic function calling mechanism, + /// since that requires this function. + /// + /// @param[in] size + /// The size of the allocation requested. + /// + /// @param[in] permissions + /// Or together any of the lldb::Permissions bits. The permissions on + /// a given memory allocation can't be changed after allocation. Note + /// that a block that isn't set writable can still be written on from + /// lldb, + /// just not by the process itself. + /// + /// @param[in/out] error + /// An error object to fill in if things go wrong. + /// @return + /// The address of the allocated buffer in the process, or + /// LLDB_INVALID_ADDRESS if the allocation failed. + //------------------------------------------------------------------ + + lldb::addr_t CallocateMemory(size_t size, uint32_t permissions, Error &error); + + //------------------------------------------------------------------ + /// Resolve dynamically loaded indirect functions. + /// + /// @param[in] address + /// The load address of the indirect function to resolve. + /// + /// @param[out] error + /// An error value in case the resolve fails. + /// + /// @return + /// The address of the resolved function. + /// LLDB_INVALID_ADDRESS if the resolution failed. + //------------------------------------------------------------------ + virtual lldb::addr_t ResolveIndirectFunction(const Address *address, + Error &error); + + //------------------------------------------------------------------ + /// Locate the memory region that contains load_addr. + /// + /// If load_addr is within the address space the process has mapped + /// range_info will be filled in with the start and end of that range + /// as well as the permissions for that range and range_info.GetMapped + /// will return true. + /// + /// If load_addr is outside any mapped region then range_info will + /// have its start address set to load_addr and the end of the + /// range will indicate the start of the next mapped range or be + /// set to LLDB_INVALID_ADDRESS if there are no valid mapped ranges + /// between load_addr and the end of the process address space. + /// + /// GetMemoryRegionInfo will only return an error if it is + /// unimplemented for the current process. + /// + /// @param[in] load_addr + /// The load address to query the range_info for. + /// + /// @param[out] range_info + /// An range_info value containing the details of the range. + /// + /// @return + /// An error value. + //------------------------------------------------------------------ + virtual Error GetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo &range_info) { + Error error; + error.SetErrorString("Process::GetMemoryRegionInfo() not supported"); + return error; + } + + //------------------------------------------------------------------ + /// Obtain all the mapped memory regions within this process. + /// + /// @param[out] region_list + /// A vector to contain MemoryRegionInfo objects for all mapped + /// ranges. + /// + /// @return + /// An error value. + //------------------------------------------------------------------ + virtual Error + GetMemoryRegions(std::vector<lldb::MemoryRegionInfoSP> ®ion_list); + + virtual Error GetWatchpointSupportInfo(uint32_t &num) { + Error error; + num = 0; + error.SetErrorString("Process::GetWatchpointSupportInfo() not supported"); + return error; + } + + virtual Error GetWatchpointSupportInfo(uint32_t &num, bool &after) { + Error error; + num = 0; + after = true; + error.SetErrorString("Process::GetWatchpointSupportInfo() not supported"); + return error; + } + + lldb::ModuleSP ReadModuleFromMemory(const FileSpec &file_spec, + lldb::addr_t header_addr, + size_t size_to_read = 512); + + //------------------------------------------------------------------ + /// Attempt to get the attributes for a region of memory in the process. + /// + /// It may be possible for the remote debug server to inspect attributes + /// for a region of memory in the process, such as whether there is a + /// valid page of memory at a given address or whether that page is + /// readable/writable/executable by the process. + /// + /// @param[in] load_addr + /// The address of interest in the process. + /// + /// @param[out] permissions + /// If this call returns successfully, this bitmask will have + /// its Permissions bits set to indicate whether the region is + /// readable/writable/executable. If this call fails, the + /// bitmask values are undefined. + /// + /// @return + /// Returns true if it was able to determine the attributes of the + /// memory region. False if not. + //------------------------------------------------------------------ + virtual bool GetLoadAddressPermissions(lldb::addr_t load_addr, + uint32_t &permissions); + + //------------------------------------------------------------------ + /// Determines whether executing JIT-compiled code in this process + /// is possible. + /// + /// @return + /// True if execution of JIT code is possible; false otherwise. + //------------------------------------------------------------------ + bool CanJIT(); + + //------------------------------------------------------------------ + /// Sets whether executing JIT-compiled code in this process + /// is possible. + /// + /// @param[in] can_jit + /// True if execution of JIT code is possible; false otherwise. + //------------------------------------------------------------------ + void SetCanJIT(bool can_jit); + + //------------------------------------------------------------------ + /// Determines whether executing function calls using the interpreter + /// is possible for this process. + /// + /// @return + /// True if possible; false otherwise. + //------------------------------------------------------------------ + bool CanInterpretFunctionCalls() { return m_can_interpret_function_calls; } + + //------------------------------------------------------------------ + /// Sets whether executing function calls using the interpreter + /// is possible for this process. + /// + /// @param[in] can_interpret_function_calls + /// True if possible; false otherwise. + //------------------------------------------------------------------ + void SetCanInterpretFunctionCalls(bool can_interpret_function_calls) { + m_can_interpret_function_calls = can_interpret_function_calls; + } + + //------------------------------------------------------------------ + /// Sets whether executing code in this process is possible. + /// This could be either through JIT or interpreting. + /// + /// @param[in] can_run_code + /// True if execution of code is possible; false otherwise. + //------------------------------------------------------------------ + void SetCanRunCode(bool can_run_code); + + //------------------------------------------------------------------ + /// Actually deallocate memory in the process. + /// + /// This function will deallocate memory in the process's address + /// space that was allocated with AllocateMemory. + /// + /// @param[in] ptr + /// A return value from AllocateMemory, pointing to the memory you + /// want to deallocate. + /// + /// @return + /// \btrue if the memory was deallocated, \bfalse otherwise. + //------------------------------------------------------------------ + virtual Error DoDeallocateMemory(lldb::addr_t ptr) { + Error error; + error.SetErrorStringWithFormat( + "error: %s does not support deallocating in the debug process", + GetPluginName().GetCString()); + return error; + } + + //------------------------------------------------------------------ + /// The public interface to deallocating memory in the process. + /// + /// This function will deallocate memory in the process's address + /// space that was allocated with AllocateMemory. + /// + /// @param[in] ptr + /// A return value from AllocateMemory, pointing to the memory you + /// want to deallocate. + /// + /// @return + /// \btrue if the memory was deallocated, \bfalse otherwise. + //------------------------------------------------------------------ + Error DeallocateMemory(lldb::addr_t ptr); + + //------------------------------------------------------------------ + /// Get any available STDOUT. + /// + /// Calling this method is a valid operation only if all of the + /// following conditions are true: + /// 1) The process was launched, and not attached to. + /// 2) The process was not launched with eLaunchFlagDisableSTDIO. + /// 3) The process was launched without supplying a valid file path + /// for STDOUT. + /// + /// Note that the implementation will probably need to start a read + /// thread in the background to make sure that the pipe is drained + /// and the STDOUT buffered appropriately, to prevent the process + /// from deadlocking trying to write to a full buffer. + /// + /// Events will be queued indicating that there is STDOUT available + /// that can be retrieved using this function. + /// + /// @param[out] buf + /// A buffer that will receive any STDOUT bytes that are + /// currently available. + /// + /// @param[in] buf_size + /// The size in bytes for the buffer \a buf. + /// + /// @return + /// The number of bytes written into \a buf. If this value is + /// equal to \a buf_size, another call to this function should + /// be made to retrieve more STDOUT data. + //------------------------------------------------------------------ + virtual size_t GetSTDOUT(char *buf, size_t buf_size, Error &error); + + //------------------------------------------------------------------ + /// Get any available STDERR. + /// + /// Calling this method is a valid operation only if all of the + /// following conditions are true: + /// 1) The process was launched, and not attached to. + /// 2) The process was not launched with eLaunchFlagDisableSTDIO. + /// 3) The process was launched without supplying a valid file path + /// for STDERR. + /// + /// Note that the implementation will probably need to start a read + /// thread in the background to make sure that the pipe is drained + /// and the STDERR buffered appropriately, to prevent the process + /// from deadlocking trying to write to a full buffer. + /// + /// Events will be queued indicating that there is STDERR available + /// that can be retrieved using this function. + /// + /// @param[in] buf + /// A buffer that will receive any STDERR bytes that are + /// currently available. + /// + /// @param[out] buf_size + /// The size in bytes for the buffer \a buf. + /// + /// @return + /// The number of bytes written into \a buf. If this value is + /// equal to \a buf_size, another call to this function should + /// be made to retrieve more STDERR data. + //------------------------------------------------------------------ + virtual size_t GetSTDERR(char *buf, size_t buf_size, Error &error); + + //------------------------------------------------------------------ + /// Puts data into this process's STDIN. + /// + /// Calling this method is a valid operation only if all of the + /// following conditions are true: + /// 1) The process was launched, and not attached to. + /// 2) The process was not launched with eLaunchFlagDisableSTDIO. + /// 3) The process was launched without supplying a valid file path + /// for STDIN. + /// + /// @param[in] buf + /// A buffer that contains the data to write to the process's STDIN. + /// + /// @param[in] buf_size + /// The size in bytes for the buffer \a buf. + /// + /// @return + /// The number of bytes written into \a buf. If this value is + /// less than \a buf_size, another call to this function should + /// be made to write the rest of the data. + //------------------------------------------------------------------ + virtual size_t PutSTDIN(const char *buf, size_t buf_size, Error &error) { + error.SetErrorString("stdin unsupported"); + return 0; + } + + //------------------------------------------------------------------ + /// Get any available profile data. + /// + /// @param[out] buf + /// A buffer that will receive any profile data bytes that are + /// currently available. + /// + /// @param[out] buf_size + /// The size in bytes for the buffer \a buf. + /// + /// @return + /// The number of bytes written into \a buf. If this value is + /// equal to \a buf_size, another call to this function should + /// be made to retrieve more profile data. + //------------------------------------------------------------------ + virtual size_t GetAsyncProfileData(char *buf, size_t buf_size, Error &error); + + //---------------------------------------------------------------------- + // Process Breakpoints + //---------------------------------------------------------------------- + size_t GetSoftwareBreakpointTrapOpcode(BreakpointSite *bp_site); + + virtual Error EnableBreakpointSite(BreakpointSite *bp_site) { + Error error; + error.SetErrorStringWithFormat( + "error: %s does not support enabling breakpoints", + GetPluginName().GetCString()); + return error; + } + + virtual Error DisableBreakpointSite(BreakpointSite *bp_site) { + Error error; + error.SetErrorStringWithFormat( + "error: %s does not support disabling breakpoints", + GetPluginName().GetCString()); + return error; + } + + // This is implemented completely using the lldb::Process API. Subclasses + // don't need to implement this function unless the standard flow of + // read existing opcode, write breakpoint opcode, verify breakpoint opcode + // doesn't work for a specific process plug-in. + virtual Error EnableSoftwareBreakpoint(BreakpointSite *bp_site); + + // This is implemented completely using the lldb::Process API. Subclasses + // don't need to implement this function unless the standard flow of + // restoring original opcode in memory and verifying the restored opcode + // doesn't work for a specific process plug-in. + virtual Error DisableSoftwareBreakpoint(BreakpointSite *bp_site); + + BreakpointSiteList &GetBreakpointSiteList(); + + const BreakpointSiteList &GetBreakpointSiteList() const; + + void DisableAllBreakpointSites(); + + Error ClearBreakpointSiteByID(lldb::user_id_t break_id); + + lldb::break_id_t CreateBreakpointSite(const lldb::BreakpointLocationSP &owner, + bool use_hardware); + + Error DisableBreakpointSiteByID(lldb::user_id_t break_id); + + Error EnableBreakpointSiteByID(lldb::user_id_t break_id); + + // BreakpointLocations use RemoveOwnerFromBreakpointSite to remove + // themselves from the owner's list of this breakpoint sites. + void RemoveOwnerFromBreakpointSite(lldb::user_id_t owner_id, + lldb::user_id_t owner_loc_id, + lldb::BreakpointSiteSP &bp_site_sp); + + //---------------------------------------------------------------------- + // Process Watchpoints (optional) + //---------------------------------------------------------------------- + virtual Error EnableWatchpoint(Watchpoint *wp, bool notify = true); + + virtual Error DisableWatchpoint(Watchpoint *wp, bool notify = true); + + //------------------------------------------------------------------ + // Thread Queries + //------------------------------------------------------------------ + virtual bool UpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) = 0; + + void UpdateThreadListIfNeeded(); + + ThreadList &GetThreadList() { return m_thread_list; } + + // When ExtendedBacktraces are requested, the HistoryThreads that are + // created need an owner -- they're saved here in the Process. The + // threads in this list are not iterated over - driver programs need to + // request the extended backtrace calls starting from a root concrete + // thread one by one. + ThreadList &GetExtendedThreadList() { return m_extended_thread_list; } + + ThreadList::ThreadIterable Threads() { return m_thread_list.Threads(); } + + uint32_t GetNextThreadIndexID(uint64_t thread_id); + + lldb::ThreadSP CreateOSPluginThread(lldb::tid_t tid, lldb::addr_t context); + + // Returns true if an index id has been assigned to a thread. + bool HasAssignedIndexIDToThread(uint64_t sb_thread_id); + + // Given a thread_id, it will assign a more reasonable index id for display to + // the user. + // If the thread_id has previously been assigned, the same index id will be + // used. + uint32_t AssignIndexIDToThread(uint64_t thread_id); + + //------------------------------------------------------------------ + // Queue Queries + //------------------------------------------------------------------ + + void UpdateQueueListIfNeeded(); + + QueueList &GetQueueList() { + UpdateQueueListIfNeeded(); + return m_queue_list; + } + + QueueList::QueueIterable Queues() { + UpdateQueueListIfNeeded(); + return m_queue_list.Queues(); + } + + //------------------------------------------------------------------ + // Event Handling + //------------------------------------------------------------------ + lldb::StateType GetNextEvent(lldb::EventSP &event_sp); + + // Returns the process state when it is stopped. If specified, event_sp_ptr + // is set to the event which triggered the stop. If wait_always = false, + // and the process is already stopped, this function returns immediately. + // If the process is hijacked and use_run_lock is true (the default), then + // this + // function releases the run lock after the stop. Setting use_run_lock to + // false + // will avoid this behavior. + lldb::StateType + WaitForProcessToStop(const Timeout<std::micro> &timeout, + lldb::EventSP *event_sp_ptr = nullptr, + bool wait_always = true, + lldb::ListenerSP hijack_listener = lldb::ListenerSP(), + Stream *stream = nullptr, bool use_run_lock = true); + + uint32_t GetIOHandlerID() const { return m_iohandler_sync.GetValue(); } + + //-------------------------------------------------------------------------------------- + /// Waits for the process state to be running within a given msec timeout. + /// + /// The main purpose of this is to implement an interlock waiting for + /// HandlePrivateEvent + /// to push an IOHandler. + /// + /// @param[in] timeout_msec + /// The maximum time length to wait for the process to transition to the + /// eStateRunning state, specified in milliseconds. + //-------------------------------------------------------------------------------------- + void SyncIOHandler(uint32_t iohandler_id, uint64_t timeout_msec); + + lldb::StateType GetStateChangedEvents( + lldb::EventSP &event_sp, const Timeout<std::micro> &timeout, + lldb::ListenerSP + hijack_listener); // Pass an empty ListenerSP to use builtin listener + + //-------------------------------------------------------------------------------------- + /// Centralize the code that handles and prints descriptions for process state + /// changes. + /// + /// @param[in] event_sp + /// The process state changed event + /// + /// @param[in] stream + /// The output stream to get the state change description + /// + /// @param[in,out] pop_process_io_handler + /// If this value comes in set to \b true, then pop the Process IOHandler + /// if needed. + /// Else this variable will be set to \b true or \b false to indicate if + /// the process + /// needs to have its process IOHandler popped. + /// + /// @return + /// \b true if the event describes a process state changed event, \b false + /// otherwise. + //-------------------------------------------------------------------------------------- + static bool HandleProcessStateChangedEvent(const lldb::EventSP &event_sp, + Stream *stream, + bool &pop_process_io_handler); + + Event *PeekAtStateChangedEvents(); + + class ProcessEventHijacker { + public: + ProcessEventHijacker(Process &process, lldb::ListenerSP listener_sp) + : m_process(process) { + m_process.HijackProcessEvents(listener_sp); + } + + ~ProcessEventHijacker() { m_process.RestoreProcessEvents(); } + + private: + Process &m_process; + }; + + friend class ProcessEventHijacker; + friend class ProcessProperties; + //------------------------------------------------------------------ + /// If you need to ensure that you and only you will hear about some public + /// event, then make a new listener, set to listen to process events, and + /// then call this with that listener. Then you will have to wait on that + /// listener explicitly for events (rather than using the GetNextEvent & + /// WaitFor* + /// calls above. Be sure to call RestoreProcessEvents when you are done. + /// + /// @param[in] listener + /// This is the new listener to whom all process events will be delivered. + /// + /// @return + /// Returns \b true if the new listener could be installed, + /// \b false otherwise. + //------------------------------------------------------------------ + bool HijackProcessEvents(lldb::ListenerSP listener_sp); + + //------------------------------------------------------------------ + /// Restores the process event broadcasting to its normal state. + /// + //------------------------------------------------------------------ + void RestoreProcessEvents(); + + const lldb::ABISP &GetABI(); + + OperatingSystem *GetOperatingSystem() { return m_os_ap.get(); } + + ArchSpec::StopInfoOverrideCallbackType GetStopInfoOverrideCallback() const { + return m_stop_info_override_callback; + } + + virtual LanguageRuntime *GetLanguageRuntime(lldb::LanguageType language, + bool retry_if_null = true); + + virtual CPPLanguageRuntime *GetCPPLanguageRuntime(bool retry_if_null = true); + + virtual ObjCLanguageRuntime * + GetObjCLanguageRuntime(bool retry_if_null = true); + + bool IsPossibleDynamicValue(ValueObject &in_value); + + bool IsRunning() const; + + DynamicCheckerFunctions *GetDynamicCheckers() { + return m_dynamic_checkers_ap.get(); + } + + void SetDynamicCheckers(DynamicCheckerFunctions *dynamic_checkers); + + //------------------------------------------------------------------ + /// Call this to set the lldb in the mode where it breaks on new thread + /// creations, and then auto-restarts. This is useful when you are trying + /// to run only one thread, but either that thread or the kernel is creating + /// new threads in the process. If you stop when the thread is created, you + /// can immediately suspend it, and keep executing only the one thread you + /// intend. + /// + /// @return + /// Returns \b true if we were able to start up the notification + /// \b false otherwise. + //------------------------------------------------------------------ + virtual bool StartNoticingNewThreads() { return true; } + + //------------------------------------------------------------------ + /// Call this to turn off the stop & notice new threads mode. + /// + /// @return + /// Returns \b true if we were able to start up the notification + /// \b false otherwise. + //------------------------------------------------------------------ + virtual bool StopNoticingNewThreads() { return true; } + + void SetRunningUserExpression(bool on); + + //------------------------------------------------------------------ + // lldb::ExecutionContextScope pure virtual functions + //------------------------------------------------------------------ + lldb::TargetSP CalculateTarget() override; + + lldb::ProcessSP CalculateProcess() override { return shared_from_this(); } + + lldb::ThreadSP CalculateThread() override { return lldb::ThreadSP(); } + + lldb::StackFrameSP CalculateStackFrame() override { + return lldb::StackFrameSP(); + } + + void CalculateExecutionContext(ExecutionContext &exe_ctx) override; + + void SetSTDIOFileDescriptor(int file_descriptor); + + //------------------------------------------------------------------ + // Add a permanent region of memory that should never be read or + // written to. This can be used to ensure that memory reads or writes + // to certain areas of memory never end up being sent to the + // DoReadMemory or DoWriteMemory functions which can improve + // performance. + //------------------------------------------------------------------ + void AddInvalidMemoryRegion(const LoadRange ®ion); + + //------------------------------------------------------------------ + // Remove a permanent region of memory that should never be read or + // written to that was previously added with AddInvalidMemoryRegion. + //------------------------------------------------------------------ + bool RemoveInvalidMemoryRange(const LoadRange ®ion); + + //------------------------------------------------------------------ + // If the setup code of a thread plan needs to do work that might involve + // calling a function in the target, it should not do that work directly + // in one of the thread plan functions (DidPush/WillResume) because + // such work needs to be handled carefully. Instead, put that work in + // a PreResumeAction callback, and register it with the process. It will + // get done before the actual "DoResume" gets called. + //------------------------------------------------------------------ + + typedef bool(PreResumeActionCallback)(void *); + + void AddPreResumeAction(PreResumeActionCallback callback, void *baton); + + bool RunPreResumeActions(); + + void ClearPreResumeActions(); + + void ClearPreResumeAction(PreResumeActionCallback callback, void *baton); + + ProcessRunLock &GetRunLock(); + + virtual Error SendEventData(const char *data) { + Error return_error("Sending an event is not supported for this process."); + return return_error; + } + + lldb::ThreadCollectionSP GetHistoryThreads(lldb::addr_t addr); + + lldb::InstrumentationRuntimeSP + GetInstrumentationRuntime(lldb::InstrumentationRuntimeType type); + + //------------------------------------------------------------------ + /// Try to fetch the module specification for a module with the + /// given file name and architecture. Process sub-classes have to + /// override this method if they support platforms where the + /// Platform object can't get the module spec for all module. + /// + /// @param[in] module_file_spec + /// The file name of the module to get specification for. + /// + /// @param[in] arch + /// The architecture of the module to get specification for. + /// + /// @param[out] module_spec + /// The fetched module specification if the return value is + /// \b true, unchanged otherwise. + /// + /// @return + /// Returns \b true if the module spec fetched successfully, + /// \b false otherwise. + //------------------------------------------------------------------ + virtual bool GetModuleSpec(const FileSpec &module_file_spec, + const ArchSpec &arch, ModuleSpec &module_spec); + + virtual void PrefetchModuleSpecs(llvm::ArrayRef<FileSpec> module_file_specs, + const llvm::Triple &triple) {} + + //------------------------------------------------------------------ + /// Try to find the load address of a file. + /// The load address is defined as the address of the first memory + /// region what contains data mapped from the specified file. + /// + /// @param[in] file + /// The name of the file whose load address we are looking for + /// + /// @param[out] is_loaded + /// \b True if the file is loaded into the memory and false + /// otherwise. + /// + /// @param[out] load_addr + /// The load address of the file if it is loaded into the + /// processes address space, LLDB_INVALID_ADDRESS otherwise. + //------------------------------------------------------------------ + virtual Error GetFileLoadAddress(const FileSpec &file, bool &is_loaded, + lldb::addr_t &load_addr) { + return Error("Not supported"); + } + + size_t AddImageToken(lldb::addr_t image_ptr); + + lldb::addr_t GetImagePtrFromToken(size_t token) const; + + void ResetImageToken(size_t token); + + //------------------------------------------------------------------ + /// Find the next branch instruction to set a breakpoint on + /// + /// When instruction stepping through a source line, instead of + /// stepping through each instruction, we can put a breakpoint on + /// the next branch instruction (within the range of instructions + /// we are stepping through) and continue the process to there, + /// yielding significant performance benefits over instruction + /// stepping. + /// + /// @param[in] default_stop_addr + /// The address of the instruction where lldb would put a + /// breakpoint normally. + /// + /// @param[in] range_bounds + /// The range which the breakpoint must be contained within. + /// Typically a source line. + /// + /// @return + /// The address of the next branch instruction, or the end of + /// the range provided in range_bounds. If there are any + /// problems with the disassembly or getting the instructions, + /// the original default_stop_addr will be returned. + //------------------------------------------------------------------ + Address AdvanceAddressToNextBranchInstruction(Address default_stop_addr, + AddressRange range_bounds); + + //------------------------------------------------------------------ + /// Configure asynchronous structured data feature. + /// + /// Each Process type that supports using an asynchronous StructuredData + /// feature should implement this to enable/disable/configure the feature. + /// The default implementation here will always return an error indiciating + /// the feature is unsupported. + /// + /// StructuredDataPlugin implementations will call this to configure + /// a feature that has been reported as being supported. + /// + /// @param[in] type_name + /// The StructuredData type name as previously discovered by + /// the Process-derived instance. + /// + /// @param[in] config + /// Configuration data for the feature being enabled. This config + /// data, which may be null, will be passed along to the feature + /// to process. The feature will dictate whether this is a dictionary, + /// an array or some other object. If the feature needs to be + /// set up properly before it can be enabled, then the config should + /// also take an enable/disable flag. + /// + /// @return + /// Returns the result of attempting to configure the feature. + //------------------------------------------------------------------ + virtual Error + ConfigureStructuredData(const ConstString &type_name, + const StructuredData::ObjectSP &config_sp); + + //------------------------------------------------------------------ + /// Broadcasts the given structured data object from the given + /// plugin. + /// + /// StructuredDataPlugin instances can use this to optionally + /// broadcast any of their data if they want to make it available + /// for clients. The data will come in on the structured data + /// event bit (eBroadcastBitStructuredData). + /// + /// @param[in] object_sp + /// The structured data object to broadcast. + /// + /// @param[in] plugin_sp + /// The plugin that will be reported in the event's plugin + /// parameter. + //------------------------------------------------------------------ + void BroadcastStructuredData(const StructuredData::ObjectSP &object_sp, + const lldb::StructuredDataPluginSP &plugin_sp); + + //------------------------------------------------------------------ + /// Returns the StructuredDataPlugin associated with a given type + /// name, if there is one. + /// + /// There will only be a plugin for a given StructuredDataType if the + /// debugged process monitor claims that the feature is supported. + /// This is one way to tell whether a feature is available. + /// + /// @return + /// The plugin if one is available for the specified feature; + /// otherwise, returns an empty shared pointer. + //------------------------------------------------------------------ + lldb::StructuredDataPluginSP + GetStructuredDataPlugin(const ConstString &type_name) const; - //------------------------------------------------------------------ - /// Get any available profile data. - /// - /// @param[out] buf - /// A buffer that will receive any profile data bytes that are - /// currently available. - /// - /// @param[out] buf_size - /// The size in bytes for the buffer \a buf. - /// - /// @return - /// The number of bytes written into \a buf. If this value is - /// equal to \a buf_size, another call to this function should - /// be made to retrieve more profile data. - //------------------------------------------------------------------ - virtual size_t - GetAsyncProfileData (char *buf, size_t buf_size, Error &error); - - //---------------------------------------------------------------------- - // Process Breakpoints - //---------------------------------------------------------------------- - size_t - GetSoftwareBreakpointTrapOpcode (BreakpointSite* bp_site); - - virtual Error - EnableBreakpointSite (BreakpointSite *bp_site) - { - Error error; - error.SetErrorStringWithFormat("error: %s does not support enabling breakpoints", GetPluginName().GetCString()); - return error; - } +protected: + void SetState(lldb::EventSP &event_sp); + + lldb::StateType GetPrivateState(); + + //------------------------------------------------------------------ + /// The "private" side of resuming a process. This doesn't alter the + /// state of m_run_lock, but just causes the process to resume. + /// + /// @return + /// An Error object describing the success or failure of the resume. + //------------------------------------------------------------------ + Error PrivateResume(); + + //------------------------------------------------------------------ + // Called internally + //------------------------------------------------------------------ + void CompleteAttach(); + + //------------------------------------------------------------------ + /// Print a user-visible warning one time per Process + /// + /// A facility for printing a warning to the user once per repeat_key. + /// + /// warning_type is from the Process::Warnings enums. + /// repeat_key is a pointer value that will be used to ensure that the + /// warning message is not printed multiple times. For instance, with a + /// warning about a function being optimized, you can pass the CompileUnit + /// pointer to have the warning issued for only the first function in a + /// CU, or the Function pointer to have it issued once for every function, + /// or a Module pointer to have it issued once per Module. + /// + /// Classes outside Process should call a specific PrintWarning method + /// so that the warning strings are all centralized in Process, instead of + /// calling PrintWarning() directly. + /// + /// @param [in] warning_type + /// One of the types defined in Process::Warnings. + /// + /// @param [in] repeat_key + /// A pointer value used to ensure that the warning is only printed once. + /// May be nullptr, indicating that the warning is printed unconditionally + /// every time. + /// + /// @param [in] fmt + /// printf style format string + //------------------------------------------------------------------ + void PrintWarning(uint64_t warning_type, const void *repeat_key, + const char *fmt, ...) __attribute__((format(printf, 4, 5))); + + //------------------------------------------------------------------ + // NextEventAction provides a way to register an action on the next + // event that is delivered to this process. There is currently only + // one next event action allowed in the process at one time. If a + // new "NextEventAction" is added while one is already present, the + // old action will be discarded (with HandleBeingUnshipped called + // after it is discarded.) + // + // If you want to resume the process as a result of a resume action, + // call RequestResume, don't call Resume directly. + //------------------------------------------------------------------ + class NextEventAction { + public: + typedef enum EventActionResult { + eEventActionSuccess, + eEventActionRetry, + eEventActionExit + } EventActionResult; + + NextEventAction(Process *process) : m_process(process) {} + + virtual ~NextEventAction() = default; + + virtual EventActionResult PerformAction(lldb::EventSP &event_sp) = 0; + virtual void HandleBeingUnshipped() {} + virtual EventActionResult HandleBeingInterrupted() = 0; + virtual const char *GetExitString() = 0; + void RequestResume() { m_process->m_resume_requested = true; } + + protected: + Process *m_process; + }; + + void SetNextEventAction(Process::NextEventAction *next_event_action) { + if (m_next_event_action_ap.get()) + m_next_event_action_ap->HandleBeingUnshipped(); + + m_next_event_action_ap.reset(next_event_action); + } + + // This is the completer for Attaching: + class AttachCompletionHandler : public NextEventAction { + public: + AttachCompletionHandler(Process *process, uint32_t exec_count); + + ~AttachCompletionHandler() override = default; + + EventActionResult PerformAction(lldb::EventSP &event_sp) override; + EventActionResult HandleBeingInterrupted() override; + const char *GetExitString() override; + + private: + uint32_t m_exec_count; + std::string m_exit_string; + }; + + bool PrivateStateThreadIsValid() const { + lldb::StateType state = m_private_state.GetValue(); + return state != lldb::eStateInvalid && state != lldb::eStateDetached && + state != lldb::eStateExited && m_private_state_thread.IsJoinable(); + } + + void ForceNextEventDelivery() { m_force_next_event_delivery = true; } + + //------------------------------------------------------------------ + /// Loads any plugins associated with asynchronous structured data + /// and maps the relevant supported type name to the plugin. + /// + /// Processes can receive asynchronous structured data from the + /// process monitor. This method will load and map any structured + /// data plugins that support the given set of supported type names. + /// Later, if any of these features are enabled, the process monitor + /// is free to generate asynchronous structured data. The data must + /// come in as a single \b StructuredData::Dictionary. That dictionary + /// must have a string field named 'type', with a value that equals + /// the relevant type name string (one of the values in + /// \b supported_type_names). + /// + /// @param[in] supported_type_names + /// An array of zero or more type names. Each must be unique. + /// For each entry in the list, a StructuredDataPlugin will be + /// searched for that supports the structured data type name. + //------------------------------------------------------------------ + void MapSupportedStructuredDataPlugins( + const StructuredData::Array &supported_type_names); + + //------------------------------------------------------------------ + /// Route the incoming structured data dictionary to the right plugin. + /// + /// The incoming structured data must be a dictionary, and it must + /// have a key named 'type' that stores a string value. The string + /// value must be the name of the structured data feature that + /// knows how to handle it. + /// + /// @param[in] object_sp + /// When non-null and pointing to a dictionary, the 'type' + /// key's string value is used to look up the plugin that + /// was registered for that structured data type. It then + /// calls the following method on the StructuredDataPlugin + /// instance: + /// + /// virtual void + /// HandleArrivalOfStructuredData(Process &process, + /// const ConstString &type_name, + /// const StructuredData::ObjectSP + /// &object_sp) + /// + /// @return + /// True if the structured data was routed to a plugin; otherwise, + /// false. + //------------------------------------------------------------------ + bool RouteAsyncStructuredData(const StructuredData::ObjectSP object_sp); + + //------------------------------------------------------------------ + // Type definitions + //------------------------------------------------------------------ + typedef std::map<lldb::LanguageType, lldb::LanguageRuntimeSP> + LanguageRuntimeCollection; + typedef std::unordered_set<const void *> WarningsPointerSet; + typedef std::map<uint64_t, WarningsPointerSet> WarningsCollection; + + struct PreResumeCallbackAndBaton { + bool (*callback)(void *); + void *baton; + PreResumeCallbackAndBaton(PreResumeActionCallback in_callback, + void *in_baton) + : callback(in_callback), baton(in_baton) {} + bool operator== (const PreResumeCallbackAndBaton &rhs) { + return callback == rhs.callback && baton == rhs.baton; + } + }; + + using StructuredDataPluginMap = + std::map<ConstString, lldb::StructuredDataPluginSP>; + + //------------------------------------------------------------------ + // Member variables + //------------------------------------------------------------------ + std::weak_ptr<Target> m_target_sp; ///< The target that owns this process. + ThreadSafeValue<lldb::StateType> m_public_state; + ThreadSafeValue<lldb::StateType> + m_private_state; // The actual state of our process + Broadcaster m_private_state_broadcaster; // This broadcaster feeds state + // changed events into the private + // state thread's listener. + Broadcaster m_private_state_control_broadcaster; // This is the control + // broadcaster, used to + // pause, resume & stop the + // private state thread. + lldb::ListenerSP m_private_state_listener_sp; // This is the listener for the + // private state thread. + HostThread m_private_state_thread; ///< Thread ID for the thread that watches + ///internal state events + ProcessModID m_mod_id; ///< Tracks the state of the process over stops and + ///other alterations. + uint32_t m_process_unique_id; ///< Each lldb_private::Process class that is + ///created gets a unique integer ID that + ///increments with each new instance + uint32_t m_thread_index_id; ///< Each thread is created with a 1 based index + ///that won't get re-used. + std::map<uint64_t, uint32_t> m_thread_id_to_index_id_map; + int m_exit_status; ///< The exit status of the process, or -1 if not set. + std::string m_exit_string; ///< A textual description of why a process exited. + std::mutex m_exit_status_mutex; ///< Mutex so m_exit_status m_exit_string can + ///be safely accessed from multiple threads + std::recursive_mutex m_thread_mutex; + ThreadList m_thread_list_real; ///< The threads for this process as are known + ///to the protocol we are debugging with + ThreadList m_thread_list; ///< The threads for this process as the user will + ///see them. This is usually the same as + ///< m_thread_list_real, but might be different if there is an OS plug-in + ///creating memory threads + ThreadList m_extended_thread_list; ///< Owner for extended threads that may be + ///generated, cleared on natural stops + uint32_t m_extended_thread_stop_id; ///< The natural stop id when + ///extended_thread_list was last updated + QueueList + m_queue_list; ///< The list of libdispatch queues at a given stop point + uint32_t m_queue_list_stop_id; ///< The natural stop id when queue list was + ///last fetched + std::vector<Notifications> m_notifications; ///< The list of notifications + ///that this process can deliver. + std::vector<lldb::addr_t> m_image_tokens; + lldb::ListenerSP m_listener_sp; ///< Shared pointer to the listener used for + ///public events. Can not be empty. + BreakpointSiteList m_breakpoint_site_list; ///< This is the list of breakpoint + ///locations we intend to insert in + ///the target. + lldb::DynamicLoaderUP m_dyld_ap; + lldb::JITLoaderListUP m_jit_loaders_ap; + lldb::DynamicCheckerFunctionsUP m_dynamic_checkers_ap; ///< The functions used + ///by the expression + ///parser to validate + ///data that + ///expressions use. + lldb::OperatingSystemUP m_os_ap; + lldb::SystemRuntimeUP m_system_runtime_ap; + lldb::UnixSignalsSP + m_unix_signals_sp; /// This is the current signal set for this process. + lldb::ABISP m_abi_sp; + lldb::IOHandlerSP m_process_input_reader; + Communication m_stdio_communication; + std::recursive_mutex m_stdio_communication_mutex; + bool m_stdin_forward; /// Remember if stdin must be forwarded to remote debug + /// server + std::string m_stdout_data; + std::string m_stderr_data; + std::recursive_mutex m_profile_data_comm_mutex; + std::vector<std::string> m_profile_data; + Predicate<uint32_t> m_iohandler_sync; + MemoryCache m_memory_cache; + AllocatedMemoryCache m_allocated_memory_cache; + bool m_should_detach; /// Should we detach if the process object goes away + /// with an explicit call to Kill or Detach? + LanguageRuntimeCollection m_language_runtimes; + InstrumentationRuntimeCollection m_instrumentation_runtimes; + std::unique_ptr<NextEventAction> m_next_event_action_ap; + std::vector<PreResumeCallbackAndBaton> m_pre_resume_actions; + ProcessRunLock m_public_run_lock; + ProcessRunLock m_private_run_lock; + ArchSpec::StopInfoOverrideCallbackType m_stop_info_override_callback; + bool m_currently_handling_do_on_removals; + bool m_resume_requested; // If m_currently_handling_event or + // m_currently_handling_do_on_removals are true, + // Resume will only request a resume, using this flag + // to check. + bool m_finalizing; // This is set at the beginning of Process::Finalize() to + // stop functions from looking up or creating things during + // a finalize call + bool m_finalize_called; // This is set at the end of Process::Finalize() + bool m_clear_thread_plans_on_stop; + bool m_force_next_event_delivery; + lldb::StateType m_last_broadcast_state; /// This helps with the Public event + /// coalescing in + /// ShouldBroadcastEvent. + std::map<lldb::addr_t, lldb::addr_t> m_resolved_indirect_addresses; + bool m_destroy_in_process; + bool m_can_interpret_function_calls; // Some targets, e.g the OSX kernel, + // don't support the ability to modify + // the stack. + WarningsCollection m_warnings_issued; // A set of object pointers which have + // already had warnings printed + std::mutex m_run_thread_plan_lock; + StructuredDataPluginMap m_structured_data_plugin_map; + + enum { eCanJITDontKnow = 0, eCanJITYes, eCanJITNo } m_can_jit; + + size_t RemoveBreakpointOpcodesFromBuffer(lldb::addr_t addr, size_t size, + uint8_t *buf) const; + + void SynchronouslyNotifyStateChanged(lldb::StateType state); + + void SetPublicState(lldb::StateType new_state, bool restarted); + + void SetPrivateState(lldb::StateType state); + + bool StartPrivateStateThread(bool is_secondary_thread = false); + + void StopPrivateStateThread(); + + void PausePrivateStateThread(); + + void ResumePrivateStateThread(); - virtual Error - DisableBreakpointSite (BreakpointSite *bp_site) - { - Error error; - error.SetErrorStringWithFormat("error: %s does not support disabling breakpoints", GetPluginName().GetCString()); - return error; - } +private: + struct PrivateStateThreadArgs { + PrivateStateThreadArgs(Process *p, bool s) + : process(p), is_secondary_thread(s){}; + Process *process; + bool is_secondary_thread; + }; + + // arg is a pointer to a new'ed PrivateStateThreadArgs structure. + // PrivateStateThread will free it for you. + static lldb::thread_result_t PrivateStateThread(void *arg); + + // The starts up the private state thread that will watch for events from the + // debugee. + // Pass true for is_secondary_thread in the case where you have to temporarily + // spin up a + // secondary state thread to handle events from a hand-called function on the + // primary + // private state thread. + + lldb::thread_result_t RunPrivateStateThread(bool is_secondary_thread); - // This is implemented completely using the lldb::Process API. Subclasses - // don't need to implement this function unless the standard flow of - // read existing opcode, write breakpoint opcode, verify breakpoint opcode - // doesn't work for a specific process plug-in. - virtual Error - EnableSoftwareBreakpoint (BreakpointSite *bp_site); - - // This is implemented completely using the lldb::Process API. Subclasses - // don't need to implement this function unless the standard flow of - // restoring original opcode in memory and verifying the restored opcode - // doesn't work for a specific process plug-in. - virtual Error - DisableSoftwareBreakpoint (BreakpointSite *bp_site); - - BreakpointSiteList & - GetBreakpointSiteList(); - - const BreakpointSiteList & - GetBreakpointSiteList() const; - - void - DisableAllBreakpointSites (); - - Error - ClearBreakpointSiteByID (lldb::user_id_t break_id); - - lldb::break_id_t - CreateBreakpointSite (const lldb::BreakpointLocationSP &owner, - bool use_hardware); - - Error - DisableBreakpointSiteByID (lldb::user_id_t break_id); - - Error - EnableBreakpointSiteByID (lldb::user_id_t break_id); - - // BreakpointLocations use RemoveOwnerFromBreakpointSite to remove - // themselves from the owner's list of this breakpoint sites. - void - RemoveOwnerFromBreakpointSite (lldb::user_id_t owner_id, - lldb::user_id_t owner_loc_id, - lldb::BreakpointSiteSP &bp_site_sp); - - //---------------------------------------------------------------------- - // Process Watchpoints (optional) - //---------------------------------------------------------------------- - virtual Error - EnableWatchpoint (Watchpoint *wp, bool notify = true); - - virtual Error - DisableWatchpoint (Watchpoint *wp, bool notify = true); - - //------------------------------------------------------------------ - // Thread Queries - //------------------------------------------------------------------ - virtual bool - UpdateThreadList (ThreadList &old_thread_list, ThreadList &new_thread_list) = 0; - - void - UpdateThreadListIfNeeded (); - - ThreadList & - GetThreadList () - { - return m_thread_list; - } +protected: + void HandlePrivateEvent(lldb::EventSP &event_sp); - // When ExtendedBacktraces are requested, the HistoryThreads that are - // created need an owner -- they're saved here in the Process. The - // threads in this list are not iterated over - driver programs need to - // request the extended backtrace calls starting from a root concrete - // thread one by one. - ThreadList & - GetExtendedThreadList () - { - return m_extended_thread_list; - } + Error HaltPrivate(); - ThreadList::ThreadIterable - Threads () - { - return m_thread_list.Threads(); - } + lldb::StateType WaitForProcessStopPrivate(lldb::EventSP &event_sp, + const Timeout<std::micro> &timeout); - uint32_t - GetNextThreadIndexID (uint64_t thread_id); - - lldb::ThreadSP - CreateOSPluginThread (lldb::tid_t tid, lldb::addr_t context); - - // Returns true if an index id has been assigned to a thread. - bool - HasAssignedIndexIDToThread(uint64_t sb_thread_id); - - // Given a thread_id, it will assign a more reasonable index id for display to the user. - // If the thread_id has previously been assigned, the same index id will be used. - uint32_t - AssignIndexIDToThread(uint64_t thread_id); - - //------------------------------------------------------------------ - // Queue Queries - //------------------------------------------------------------------ - - void - UpdateQueueListIfNeeded (); - - QueueList & - GetQueueList () - { - UpdateQueueListIfNeeded(); - return m_queue_list; - } + // This waits for both the state change broadcaster, and the control + // broadcaster. + // If control_only, it only waits for the control broadcaster. - QueueList::QueueIterable - Queues () - { - UpdateQueueListIfNeeded(); - return m_queue_list.Queues(); - } + bool GetEventsPrivate(lldb::EventSP &event_sp, + const Timeout<std::micro> &timeout, bool control_only); - //------------------------------------------------------------------ - // Event Handling - //------------------------------------------------------------------ - lldb::StateType - GetNextEvent (lldb::EventSP &event_sp); - - // Returns the process state when it is stopped. If specified, event_sp_ptr - // is set to the event which triggered the stop. If wait_always = false, - // and the process is already stopped, this function returns immediately. - // If the process is hijacked and use_run_lock is true (the default), then this - // function releases the run lock after the stop. Setting use_run_lock to false - // will avoid this behavior. - lldb::StateType - WaitForProcessToStop(const TimeValue *timeout, - lldb::EventSP *event_sp_ptr = nullptr, - bool wait_always = true, - lldb::ListenerSP hijack_listener = lldb::ListenerSP(), - Stream *stream = nullptr, - bool use_run_lock = true); - - uint32_t - GetIOHandlerID () const - { - return m_iohandler_sync.GetValue(); - } + lldb::StateType + GetStateChangedEventsPrivate(lldb::EventSP &event_sp, + const Timeout<std::micro> &timeout); - //-------------------------------------------------------------------------------------- - /// Waits for the process state to be running within a given msec timeout. - /// - /// The main purpose of this is to implement an interlock waiting for HandlePrivateEvent - /// to push an IOHandler. - /// - /// @param[in] timeout_msec - /// The maximum time length to wait for the process to transition to the - /// eStateRunning state, specified in milliseconds. - //-------------------------------------------------------------------------------------- - void - SyncIOHandler (uint32_t iohandler_id, uint64_t timeout_msec); - - lldb::StateType - WaitForStateChangedEvents(const TimeValue *timeout, - lldb::EventSP &event_sp, - lldb::ListenerSP hijack_listener); // Pass an empty ListenerSP to use builtin listener - - //-------------------------------------------------------------------------------------- - /// Centralize the code that handles and prints descriptions for process state changes. - /// - /// @param[in] event_sp - /// The process state changed event - /// - /// @param[in] stream - /// The output stream to get the state change description - /// - /// @param[in,out] pop_process_io_handler - /// If this value comes in set to \b true, then pop the Process IOHandler if needed. - /// Else this variable will be set to \b true or \b false to indicate if the process - /// needs to have its process IOHandler popped. - /// - /// @return - /// \b true if the event describes a process state changed event, \b false otherwise. - //-------------------------------------------------------------------------------------- - static bool - HandleProcessStateChangedEvent (const lldb::EventSP &event_sp, - Stream *stream, - bool &pop_process_io_handler); - - Event * - PeekAtStateChangedEvents (); - - class - ProcessEventHijacker - { - public: - ProcessEventHijacker (Process &process, lldb::ListenerSP listener_sp) : - m_process (process) - { - m_process.HijackProcessEvents (listener_sp); - } - - ~ProcessEventHijacker () - { - m_process.RestoreProcessEvents(); - } - - private: - Process &m_process; - }; - - friend class ProcessEventHijacker; - friend class ProcessProperties; - //------------------------------------------------------------------ - /// If you need to ensure that you and only you will hear about some public - /// event, then make a new listener, set to listen to process events, and - /// then call this with that listener. Then you will have to wait on that - /// listener explicitly for events (rather than using the GetNextEvent & WaitFor* - /// calls above. Be sure to call RestoreProcessEvents when you are done. - /// - /// @param[in] listener - /// This is the new listener to whom all process events will be delivered. - /// - /// @return - /// Returns \b true if the new listener could be installed, - /// \b false otherwise. - //------------------------------------------------------------------ - bool - HijackProcessEvents (lldb::ListenerSP listener_sp); - - //------------------------------------------------------------------ - /// Restores the process event broadcasting to its normal state. - /// - //------------------------------------------------------------------ - void - RestoreProcessEvents (); - - const lldb::ABISP & - GetABI (); - - OperatingSystem * - GetOperatingSystem () - { - return m_os_ap.get(); - } + size_t WriteMemoryPrivate(lldb::addr_t addr, const void *buf, size_t size, + Error &error); - ArchSpec::StopInfoOverrideCallbackType - GetStopInfoOverrideCallback () const - { - return m_stop_info_override_callback; - } + void AppendSTDOUT(const char *s, size_t len); - virtual LanguageRuntime * - GetLanguageRuntime (lldb::LanguageType language, bool retry_if_null = true); - - virtual CPPLanguageRuntime * - GetCPPLanguageRuntime (bool retry_if_null = true); - - virtual ObjCLanguageRuntime * - GetObjCLanguageRuntime (bool retry_if_null = true); - - bool - IsPossibleDynamicValue (ValueObject& in_value); - - bool - IsRunning () const; - - DynamicCheckerFunctions *GetDynamicCheckers() - { - return m_dynamic_checkers_ap.get(); - } - - void SetDynamicCheckers(DynamicCheckerFunctions *dynamic_checkers); - - //------------------------------------------------------------------ - /// Call this to set the lldb in the mode where it breaks on new thread - /// creations, and then auto-restarts. This is useful when you are trying - /// to run only one thread, but either that thread or the kernel is creating - /// new threads in the process. If you stop when the thread is created, you - /// can immediately suspend it, and keep executing only the one thread you intend. - /// - /// @return - /// Returns \b true if we were able to start up the notification - /// \b false otherwise. - //------------------------------------------------------------------ - virtual bool - StartNoticingNewThreads() - { - return true; - } - - //------------------------------------------------------------------ - /// Call this to turn off the stop & notice new threads mode. - /// - /// @return - /// Returns \b true if we were able to start up the notification - /// \b false otherwise. - //------------------------------------------------------------------ - virtual bool - StopNoticingNewThreads() - { - return true; - } - - void - SetRunningUserExpression (bool on); - - //------------------------------------------------------------------ - // lldb::ExecutionContextScope pure virtual functions - //------------------------------------------------------------------ - lldb::TargetSP - CalculateTarget() override; - - lldb::ProcessSP - CalculateProcess() override - { - return shared_from_this(); - } - - lldb::ThreadSP - CalculateThread() override - { - return lldb::ThreadSP(); - } - - lldb::StackFrameSP - CalculateStackFrame() override - { - return lldb::StackFrameSP(); - } + void AppendSTDERR(const char *s, size_t len); - void - CalculateExecutionContext(ExecutionContext &exe_ctx) override; - - void - SetSTDIOFileDescriptor (int file_descriptor); - - //------------------------------------------------------------------ - // Add a permanent region of memory that should never be read or - // written to. This can be used to ensure that memory reads or writes - // to certain areas of memory never end up being sent to the - // DoReadMemory or DoWriteMemory functions which can improve - // performance. - //------------------------------------------------------------------ - void - AddInvalidMemoryRegion (const LoadRange ®ion); - - //------------------------------------------------------------------ - // Remove a permanent region of memory that should never be read or - // written to that was previously added with AddInvalidMemoryRegion. - //------------------------------------------------------------------ - bool - RemoveInvalidMemoryRange (const LoadRange ®ion); - - //------------------------------------------------------------------ - // If the setup code of a thread plan needs to do work that might involve - // calling a function in the target, it should not do that work directly - // in one of the thread plan functions (DidPush/WillResume) because - // such work needs to be handled carefully. Instead, put that work in - // a PreResumeAction callback, and register it with the process. It will - // get done before the actual "DoResume" gets called. - //------------------------------------------------------------------ - - typedef bool (PreResumeActionCallback)(void *); - - void - AddPreResumeAction (PreResumeActionCallback callback, void *baton); - - bool - RunPreResumeActions (); - - void - ClearPreResumeActions (); - - ProcessRunLock & - GetRunLock (); - - virtual Error - SendEventData(const char *data) - { - Error return_error ("Sending an event is not supported for this process."); - return return_error; - } - - lldb::ThreadCollectionSP - GetHistoryThreads(lldb::addr_t addr); - - lldb::InstrumentationRuntimeSP - GetInstrumentationRuntime(lldb::InstrumentationRuntimeType type); - - //------------------------------------------------------------------ - /// Try to fetch the module specification for a module with the - /// given file name and architecture. Process sub-classes have to - /// override this method if they support platforms where the - /// Platform object can't get the module spec for all module. - /// - /// @param[in] module_file_spec - /// The file name of the module to get specification for. - /// - /// @param[in] arch - /// The architecture of the module to get specification for. - /// - /// @param[out] module_spec - /// The fetched module specification if the return value is - /// \b true, unchanged otherwise. - /// - /// @return - /// Returns \b true if the module spec fetched successfully, - /// \b false otherwise. - //------------------------------------------------------------------ - virtual bool - GetModuleSpec(const FileSpec& module_file_spec, const ArchSpec& arch, ModuleSpec &module_spec); - - //------------------------------------------------------------------ - /// Try to find the load address of a file. - /// The load address is defined as the address of the first memory - /// region what contains data mapped from the specified file. - /// - /// @param[in] file - /// The name of the file whose load address we are looking for - /// - /// @param[out] is_loaded - /// \b True if the file is loaded into the memory and false - /// otherwise. - /// - /// @param[out] load_addr - /// The load address of the file if it is loaded into the - /// processes address space, LLDB_INVALID_ADDRESS otherwise. - //------------------------------------------------------------------ - virtual Error - GetFileLoadAddress(const FileSpec& file, bool& is_loaded, lldb::addr_t& load_addr) - { - return Error("Not supported"); - } + void BroadcastAsyncProfileData(const std::string &one_profile_data); - size_t - AddImageToken(lldb::addr_t image_ptr); - - lldb::addr_t - GetImagePtrFromToken(size_t token) const; - - void - ResetImageToken(size_t token); - - //------------------------------------------------------------------ - /// Find the next branch instruction to set a breakpoint on - /// - /// When instruction stepping through a source line, instead of - /// stepping through each instruction, we can put a breakpoint on - /// the next branch instruction (within the range of instructions - /// we are stepping through) and continue the process to there, - /// yielding significant performance benefits over instruction - /// stepping. - /// - /// @param[in] default_stop_addr - /// The address of the instruction where lldb would put a - /// breakpoint normally. - /// - /// @param[in] range_bounds - /// The range which the breakpoint must be contained within. - /// Typically a source line. - /// - /// @return - /// The address of the next branch instruction, or the end of - /// the range provided in range_bounds. If there are any - /// problems with the disassembly or getting the instructions, - /// the original default_stop_addr will be returned. - //------------------------------------------------------------------ - Address - AdvanceAddressToNextBranchInstruction (Address default_stop_addr, - AddressRange range_bounds); + static void STDIOReadThreadBytesReceived(void *baton, const void *src, + size_t src_len); -protected: - void - SetState (lldb::EventSP &event_sp); - - lldb::StateType - GetPrivateState (); - - //------------------------------------------------------------------ - /// The "private" side of resuming a process. This doesn't alter the - /// state of m_run_lock, but just causes the process to resume. - /// - /// @return - /// An Error object describing the success or failure of the resume. - //------------------------------------------------------------------ - Error - PrivateResume (); - - //------------------------------------------------------------------ - // Called internally - //------------------------------------------------------------------ - void - CompleteAttach (); - - //------------------------------------------------------------------ - /// Print a user-visible warning one time per Process - /// - /// A facility for printing a warning to the user once per repeat_key. - /// - /// warning_type is from the Process::Warnings enums. - /// repeat_key is a pointer value that will be used to ensure that the - /// warning message is not printed multiple times. For instance, with a - /// warning about a function being optimized, you can pass the CompileUnit - /// pointer to have the warning issued for only the first function in a - /// CU, or the Function pointer to have it issued once for every function, - /// or a Module pointer to have it issued once per Module. - /// - /// Classes outside Process should call a specific PrintWarning method - /// so that the warning strings are all centralized in Process, instead of - /// calling PrintWarning() directly. - /// - /// @param [in] warning_type - /// One of the types defined in Process::Warnings. - /// - /// @param [in] repeat_key - /// A pointer value used to ensure that the warning is only printed once. - /// May be nullptr, indicating that the warning is printed unconditionally - /// every time. - /// - /// @param [in] fmt - /// printf style format string - //------------------------------------------------------------------ - void - PrintWarning (uint64_t warning_type, const void *repeat_key, const char *fmt, ...) __attribute__((format(printf, 4, 5))); - - //------------------------------------------------------------------ - // NextEventAction provides a way to register an action on the next - // event that is delivered to this process. There is currently only - // one next event action allowed in the process at one time. If a - // new "NextEventAction" is added while one is already present, the - // old action will be discarded (with HandleBeingUnshipped called - // after it is discarded.) - // - // If you want to resume the process as a result of a resume action, - // call RequestResume, don't call Resume directly. - //------------------------------------------------------------------ - class NextEventAction - { - public: - typedef enum EventActionResult - { - eEventActionSuccess, - eEventActionRetry, - eEventActionExit - } EventActionResult; - - NextEventAction (Process *process) : - m_process(process) - { - } - - virtual - ~NextEventAction() = default; - - virtual EventActionResult PerformAction (lldb::EventSP &event_sp) = 0; - virtual void HandleBeingUnshipped () {} - virtual EventActionResult HandleBeingInterrupted () = 0; - virtual const char *GetExitString() = 0; - void RequestResume() - { - m_process->m_resume_requested = true; - } - - protected: - Process *m_process; - }; - - void SetNextEventAction (Process::NextEventAction *next_event_action) - { - if (m_next_event_action_ap.get()) - m_next_event_action_ap->HandleBeingUnshipped(); - - m_next_event_action_ap.reset(next_event_action); - } - - // This is the completer for Attaching: - class AttachCompletionHandler : public NextEventAction - { - public: - AttachCompletionHandler (Process *process, uint32_t exec_count); - - ~AttachCompletionHandler() override = default; - - EventActionResult PerformAction(lldb::EventSP &event_sp) override; - EventActionResult HandleBeingInterrupted() override; - const char *GetExitString() override; - - private: - uint32_t m_exec_count; - std::string m_exit_string; - }; - - bool - PrivateStateThreadIsValid () const - { - lldb::StateType state = m_private_state.GetValue(); - return state != lldb::eStateInvalid && - state != lldb::eStateDetached && - state != lldb::eStateExited && - m_private_state_thread.IsJoinable(); - } + bool PushProcessIOHandler(); - void - ForceNextEventDelivery() - { - m_force_next_event_delivery = true; - } + bool PopProcessIOHandler(); - //------------------------------------------------------------------ - // Type definitions - //------------------------------------------------------------------ - typedef std::map<lldb::LanguageType, lldb::LanguageRuntimeSP> LanguageRuntimeCollection; - typedef std::unordered_set<const void *> WarningsPointerSet; - typedef std::map<uint64_t, WarningsPointerSet> WarningsCollection; - - struct PreResumeCallbackAndBaton - { - bool (*callback) (void *); - void *baton; - PreResumeCallbackAndBaton (PreResumeActionCallback in_callback, void *in_baton) : - callback (in_callback), - baton (in_baton) - { - } - }; - - //------------------------------------------------------------------ - // Member variables - //------------------------------------------------------------------ - std::weak_ptr<Target> m_target_sp; ///< The target that owns this process. - ThreadSafeValue<lldb::StateType> m_public_state; - ThreadSafeValue<lldb::StateType> m_private_state; // The actual state of our process - Broadcaster m_private_state_broadcaster; // This broadcaster feeds state changed events into the private state thread's listener. - Broadcaster m_private_state_control_broadcaster; // This is the control broadcaster, used to pause, resume & stop the private state thread. - lldb::ListenerSP m_private_state_listener_sp; // This is the listener for the private state thread. - HostThread m_private_state_thread; ///< Thread ID for the thread that watches internal state events - ProcessModID m_mod_id; ///< Tracks the state of the process over stops and other alterations. - uint32_t m_process_unique_id; ///< Each lldb_private::Process class that is created gets a unique integer ID that increments with each new instance - uint32_t m_thread_index_id; ///< Each thread is created with a 1 based index that won't get re-used. - std::map<uint64_t, uint32_t> m_thread_id_to_index_id_map; - int m_exit_status; ///< The exit status of the process, or -1 if not set. - std::string m_exit_string; ///< A textual description of why a process exited. - std::mutex - m_exit_status_mutex; ///< Mutex so m_exit_status m_exit_string can be safely accessed from multiple threads - std::recursive_mutex m_thread_mutex; - ThreadList m_thread_list_real; ///< The threads for this process as are known to the protocol we are debugging with - ThreadList m_thread_list; ///< The threads for this process as the user will see them. This is usually the same as - ///< m_thread_list_real, but might be different if there is an OS plug-in creating memory threads - ThreadList m_extended_thread_list; ///< Owner for extended threads that may be generated, cleared on natural stops - uint32_t m_extended_thread_stop_id; ///< The natural stop id when extended_thread_list was last updated - QueueList m_queue_list; ///< The list of libdispatch queues at a given stop point - uint32_t m_queue_list_stop_id; ///< The natural stop id when queue list was last fetched - std::vector<Notifications> m_notifications; ///< The list of notifications that this process can deliver. - std::vector<lldb::addr_t> m_image_tokens; - lldb::ListenerSP m_listener_sp; ///< Shared pointer to the listener used for public events. Can not be empty. - BreakpointSiteList m_breakpoint_site_list; ///< This is the list of breakpoint locations we intend to insert in the target. - lldb::DynamicLoaderUP m_dyld_ap; - lldb::JITLoaderListUP m_jit_loaders_ap; - lldb::DynamicCheckerFunctionsUP m_dynamic_checkers_ap; ///< The functions used by the expression parser to validate data that expressions use. - lldb::OperatingSystemUP m_os_ap; - lldb::SystemRuntimeUP m_system_runtime_ap; - lldb::UnixSignalsSP m_unix_signals_sp; /// This is the current signal set for this process. - lldb::ABISP m_abi_sp; - lldb::IOHandlerSP m_process_input_reader; - Communication m_stdio_communication; - std::recursive_mutex m_stdio_communication_mutex; - bool m_stdin_forward; /// Remember if stdin must be forwarded to remote debug server - std::string m_stdout_data; - std::string m_stderr_data; - std::recursive_mutex m_profile_data_comm_mutex; - std::vector<std::string> m_profile_data; - Predicate<uint32_t> m_iohandler_sync; - MemoryCache m_memory_cache; - AllocatedMemoryCache m_allocated_memory_cache; - bool m_should_detach; /// Should we detach if the process object goes away with an explicit call to Kill or Detach? - LanguageRuntimeCollection m_language_runtimes; - InstrumentationRuntimeCollection m_instrumentation_runtimes; - std::unique_ptr<NextEventAction> m_next_event_action_ap; - std::vector<PreResumeCallbackAndBaton> m_pre_resume_actions; - ProcessRunLock m_public_run_lock; - ProcessRunLock m_private_run_lock; - ArchSpec::StopInfoOverrideCallbackType m_stop_info_override_callback; - bool m_currently_handling_do_on_removals; - bool m_resume_requested; // If m_currently_handling_event or m_currently_handling_do_on_removals are true, Resume will only request a resume, using this flag to check. - bool m_finalizing; // This is set at the beginning of Process::Finalize() to stop functions from looking up or creating things during a finalize call - bool m_finalize_called; // This is set at the end of Process::Finalize() - bool m_clear_thread_plans_on_stop; - bool m_force_next_event_delivery; - lldb::StateType m_last_broadcast_state; /// This helps with the Public event coalescing in ShouldBroadcastEvent. - std::map<lldb::addr_t,lldb::addr_t> m_resolved_indirect_addresses; - bool m_destroy_in_process; - bool m_can_interpret_function_calls; // Some targets, e.g the OSX kernel, don't support the ability to modify the stack. - WarningsCollection m_warnings_issued; // A set of object pointers which have already had warnings printed - std::mutex m_run_thread_plan_lock; - - enum { - eCanJITDontKnow= 0, - eCanJITYes, - eCanJITNo - } m_can_jit; - - size_t - RemoveBreakpointOpcodesFromBuffer (lldb::addr_t addr, size_t size, uint8_t *buf) const; - - void - SynchronouslyNotifyStateChanged (lldb::StateType state); - - void - SetPublicState (lldb::StateType new_state, bool restarted); - - void - SetPrivateState (lldb::StateType state); - - bool - StartPrivateStateThread (bool is_secondary_thread = false); - - void - StopPrivateStateThread (); - - void - PausePrivateStateThread (); - - void - ResumePrivateStateThread (); + bool ProcessIOHandlerIsActive(); -private: - struct PrivateStateThreadArgs - { - PrivateStateThreadArgs(Process *p, bool s) : process(p), is_secondary_thread(s) {}; - Process *process; - bool is_secondary_thread; - }; - - // arg is a pointer to a new'ed PrivateStateThreadArgs structure. PrivateStateThread will free it for you. - static lldb::thread_result_t - PrivateStateThread (void *arg); - - // The starts up the private state thread that will watch for events from the debugee. - // Pass true for is_secondary_thread in the case where you have to temporarily spin up a - // secondary state thread to handle events from a hand-called function on the primary - // private state thread. - - lldb::thread_result_t - RunPrivateStateThread (bool is_secondary_thread); + bool ProcessIOHandlerExists() const { + return static_cast<bool>(m_process_input_reader); + } -protected: - void - HandlePrivateEvent (lldb::EventSP &event_sp); - - Error - HaltPrivate(); - - lldb::StateType - WaitForProcessStopPrivate (const TimeValue *timeout, lldb::EventSP &event_sp); - - // This waits for both the state change broadcaster, and the control broadcaster. - // If control_only, it only waits for the control broadcaster. - - bool - WaitForEventsPrivate (const TimeValue *timeout, lldb::EventSP &event_sp, bool control_only); - - lldb::StateType - WaitForStateChangedEventsPrivate (const TimeValue *timeout, lldb::EventSP &event_sp); - - lldb::StateType - WaitForState (const TimeValue *timeout, - const lldb::StateType *match_states, - const uint32_t num_match_states); - - size_t - WriteMemoryPrivate (lldb::addr_t addr, const void *buf, size_t size, Error &error); - - void - AppendSTDOUT (const char *s, size_t len); - - void - AppendSTDERR (const char *s, size_t len); - - void - BroadcastAsyncProfileData(const std::string &one_profile_data); - - static void - STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len); - - bool - PushProcessIOHandler (); - - bool - PopProcessIOHandler (); - - bool - ProcessIOHandlerIsActive (); - - bool - ProcessIOHandlerExists () const - { - return static_cast<bool>(m_process_input_reader); - } - - Error - StopForDestroyOrDetach(lldb::EventSP &exit_event_sp); + Error StopForDestroyOrDetach(lldb::EventSP &exit_event_sp); - bool - StateChangedIsExternallyHijacked(); + bool StateChangedIsExternallyHijacked(); - void - LoadOperatingSystemPlugin(bool flush); + void LoadOperatingSystemPlugin(bool flush); private: - //------------------------------------------------------------------ - /// This is the part of the event handling that for a process event. - /// It decides what to do with the event and returns true if the - /// event needs to be propagated to the user, and false otherwise. - /// If the event is not propagated, this call will most likely set - /// the target to executing again. - /// There is only one place where this call should be called, HandlePrivateEvent. - /// Don't call it from anywhere else... - /// - /// @param[in] event_ptr - /// This is the event we are handling. - /// - /// @return - /// Returns \b true if the event should be reported to the - /// user, \b false otherwise. - //------------------------------------------------------------------ - bool - ShouldBroadcastEvent (Event *event_ptr); - - void ControlPrivateStateThread (uint32_t signal); - - DISALLOW_COPY_AND_ASSIGN (Process); + //------------------------------------------------------------------ + /// This is the part of the event handling that for a process event. + /// It decides what to do with the event and returns true if the + /// event needs to be propagated to the user, and false otherwise. + /// If the event is not propagated, this call will most likely set + /// the target to executing again. + /// There is only one place where this call should be called, + /// HandlePrivateEvent. + /// Don't call it from anywhere else... + /// + /// @param[in] event_ptr + /// This is the event we are handling. + /// + /// @return + /// Returns \b true if the event should be reported to the + /// user, \b false otherwise. + //------------------------------------------------------------------ + bool ShouldBroadcastEvent(Event *event_ptr); + + void ControlPrivateStateThread(uint32_t signal); + + DISALLOW_COPY_AND_ASSIGN(Process); }; } // namespace lldb_private diff --git a/include/lldb/Target/ProcessInfo.h b/include/lldb/Target/ProcessInfo.h index 1539e043d6fc..f8d37fa4ebb4 100644 --- a/include/lldb/Target/ProcessInfo.h +++ b/include/lldb/Target/ProcessInfo.h @@ -15,174 +15,89 @@ #include "lldb/Host/FileSpec.h" #include "lldb/Interpreter/Args.h" -namespace lldb_private -{ - //---------------------------------------------------------------------- - // ProcessInfo - // - // A base class for information for a process. This can be used to fill - // out information for a process prior to launching it, or it can be - // used for an instance of a process and can be filled in with the - // existing values for that process. - //---------------------------------------------------------------------- - class ProcessInfo - { - public: - ProcessInfo (); - - ProcessInfo (const char *name, - const ArchSpec &arch, - lldb::pid_t pid); - - void - Clear (); - - const char * - GetName() const; - - size_t - GetNameLength() const; - - FileSpec & - GetExecutableFile () - { - return m_executable; - } - - void - SetExecutableFile (const FileSpec &exe_file, bool add_exe_file_as_first_arg); - - const FileSpec & - GetExecutableFile () const - { - return m_executable; - } - - uint32_t - GetUserID() const - { - return m_uid; - } - - uint32_t - GetGroupID() const - { - return m_gid; - } - - bool - UserIDIsValid () const - { - return m_uid != UINT32_MAX; - } - - bool - GroupIDIsValid () const - { - return m_gid != UINT32_MAX; - } - - void - SetUserID (uint32_t uid) - { - m_uid = uid; - } - - void - SetGroupID (uint32_t gid) - { - m_gid = gid; - } - - ArchSpec & - GetArchitecture () - { - return m_arch; - } - - const ArchSpec & - GetArchitecture () const - { - return m_arch; - } - - void - SetArchitecture (const ArchSpec& arch) - { - m_arch = arch; - } - - lldb::pid_t - GetProcessID () const - { - return m_pid; - } - - void - SetProcessID (lldb::pid_t pid) - { - m_pid = pid; - } - - bool - ProcessIDIsValid() const - { - return m_pid != LLDB_INVALID_PROCESS_ID; - } - - void - Dump (Stream &s, Platform *platform) const; - - Args & - GetArguments () - { - return m_arguments; - } - - const Args & - GetArguments () const - { - return m_arguments; - } - - const char * - GetArg0 () const; - - void - SetArg0 (const char *arg); - - void - SetArguments (const Args& args, bool first_arg_is_executable); - - void - SetArguments (char const **argv, bool first_arg_is_executable); - - Args & - GetEnvironmentEntries () - { - return m_environment; - } - - const Args & - GetEnvironmentEntries () const - { - return m_environment; - } - - protected: - FileSpec m_executable; - std::string m_arg0; // argv[0] if supported. If empty, then use m_executable. - // Not all process plug-ins support specifying an argv[0] - // that differs from the resolved platform executable - // (which is in m_executable) - Args m_arguments; // All program arguments except argv[0] - Args m_environment; - uint32_t m_uid; - uint32_t m_gid; - ArchSpec m_arch; - lldb::pid_t m_pid; - }; +namespace lldb_private { +//---------------------------------------------------------------------- +// ProcessInfo +// +// A base class for information for a process. This can be used to fill +// out information for a process prior to launching it, or it can be +// used for an instance of a process and can be filled in with the +// existing values for that process. +//---------------------------------------------------------------------- +class ProcessInfo { +public: + ProcessInfo(); + + ProcessInfo(const char *name, const ArchSpec &arch, lldb::pid_t pid); + + void Clear(); + + const char *GetName() const; + + size_t GetNameLength() const; + + FileSpec &GetExecutableFile() { return m_executable; } + + void SetExecutableFile(const FileSpec &exe_file, + bool add_exe_file_as_first_arg); + + const FileSpec &GetExecutableFile() const { return m_executable; } + + uint32_t GetUserID() const { return m_uid; } + + uint32_t GetGroupID() const { return m_gid; } + + bool UserIDIsValid() const { return m_uid != UINT32_MAX; } + + bool GroupIDIsValid() const { return m_gid != UINT32_MAX; } + + void SetUserID(uint32_t uid) { m_uid = uid; } + + void SetGroupID(uint32_t gid) { m_gid = gid; } + + ArchSpec &GetArchitecture() { return m_arch; } + + const ArchSpec &GetArchitecture() const { return m_arch; } + + void SetArchitecture(const ArchSpec &arch) { m_arch = arch; } + + lldb::pid_t GetProcessID() const { return m_pid; } + + void SetProcessID(lldb::pid_t pid) { m_pid = pid; } + + bool ProcessIDIsValid() const { return m_pid != LLDB_INVALID_PROCESS_ID; } + + void Dump(Stream &s, Platform *platform) const; + + Args &GetArguments() { return m_arguments; } + + const Args &GetArguments() const { return m_arguments; } + + llvm::StringRef GetArg0() const; + + void SetArg0(llvm::StringRef arg); + + void SetArguments(const Args &args, bool first_arg_is_executable); + + void SetArguments(char const **argv, bool first_arg_is_executable); + + Args &GetEnvironmentEntries() { return m_environment; } + + const Args &GetEnvironmentEntries() const { return m_environment; } + +protected: + FileSpec m_executable; + std::string m_arg0; // argv[0] if supported. If empty, then use m_executable. + // Not all process plug-ins support specifying an argv[0] + // that differs from the resolved platform executable + // (which is in m_executable) + Args m_arguments; // All program arguments except argv[0] + Args m_environment; + uint32_t m_uid; + uint32_t m_gid; + ArchSpec m_arch; + lldb::pid_t m_pid; +}; } #endif // #ifndef liblldb_ProcessInfo_h_ - diff --git a/include/lldb/Target/ProcessLaunchInfo.h b/include/lldb/Target/ProcessLaunchInfo.h index d1a45794b551..2c192c24da87 100644 --- a/include/lldb/Target/ProcessLaunchInfo.h +++ b/include/lldb/Target/ProcessLaunchInfo.h @@ -21,224 +21,144 @@ #include "lldb/Target/ProcessInfo.h" #include "lldb/Utility/PseudoTerminal.h" -namespace lldb_private -{ - - //---------------------------------------------------------------------- - // ProcessLaunchInfo - // - // Describes any information that is required to launch a process. - //---------------------------------------------------------------------- - - class ProcessLaunchInfo : public ProcessInfo - { - public: - - ProcessLaunchInfo (); - - ProcessLaunchInfo(const FileSpec &stdin_file_spec, - const FileSpec &stdout_file_spec, - const FileSpec &stderr_file_spec, - const FileSpec &working_dir, - uint32_t launch_flags); - - void - AppendFileAction (const FileAction &info) - { - m_file_actions.push_back(info); - } - - bool - AppendCloseFileAction (int fd); - - bool - AppendDuplicateFileAction (int fd, int dup_fd); - - bool - AppendOpenFileAction(int fd, const FileSpec &file_spec, - bool read, bool write); - - bool - AppendSuppressFileAction (int fd, bool read, bool write); - - void - FinalizeFileActions (Target *target, - bool default_to_use_pty); - - size_t - GetNumFileActions () const - { - return m_file_actions.size(); - } - - const FileAction * - GetFileActionAtIndex (size_t idx) const; - - const FileAction * - GetFileActionForFD (int fd) const; - - Flags & - GetFlags () - { - return m_flags; - } - - const Flags & - GetFlags () const - { - return m_flags; - } - - const FileSpec & - GetWorkingDirectory() const; - - void - SetWorkingDirectory(const FileSpec &working_dir); - - const char * - GetProcessPluginName () const; - - void - SetProcessPluginName (const char *plugin); - - const FileSpec & - GetShell () const; - - void - SetShell (const FileSpec &shell); - - uint32_t - GetResumeCount () const - { - return m_resume_count; - } - - void - SetResumeCount (uint32_t c) - { - m_resume_count = c; - } - - bool - GetLaunchInSeparateProcessGroup() const - { - return m_flags.Test(lldb::eLaunchFlagLaunchInSeparateProcessGroup); - } - - void - SetLaunchInSeparateProcessGroup (bool separate); - - bool - GetShellExpandArguments () const - { - return m_flags.Test(lldb::eLaunchFlagShellExpandArguments); - } - - void - SetShellExpandArguments (bool expand); - - void - Clear (); - - bool - ConvertArgumentsForLaunchingInShell (Error &error, - bool localhost, - bool will_debug, - bool first_arg_is_full_shell_command, - int32_t num_resumes); - - void - SetMonitorProcessCallback(const Host::MonitorChildProcessCallback &callback, bool monitor_signals); - - Host::MonitorChildProcessCallback - GetMonitorProcessCallback() const - { - return m_monitor_callback; - } - - bool - GetMonitorSignals() const - { - return m_monitor_signals; - } - - // If the LaunchInfo has a monitor callback, then arrange to monitor the process. - // Return true if the LaunchInfo has taken care of monitoring the process, and false if the - // caller might want to monitor the process themselves. - - bool - MonitorProcess () const; - - lldb_utility::PseudoTerminal & - GetPTY () - { - return *m_pty; - } - - // Get and set the actual listener that will be used for the process events - lldb::ListenerSP - GetListener () const - { - return m_listener_sp; - } - - void - SetListener (const lldb::ListenerSP &listener_sp) - { - m_listener_sp = listener_sp; - } - - lldb::ListenerSP - GetListenerForProcess (Debugger &debugger); - - lldb::ListenerSP - GetHijackListener () const - { - return m_hijack_listener_sp; - } - - void - SetHijackListener (const lldb::ListenerSP &listener_sp) - { - m_hijack_listener_sp = listener_sp; - } - - void - SetLaunchEventData (const char *data) - { - m_event_data.assign (data); - } - - const char * - GetLaunchEventData () const - { - return m_event_data.c_str(); - } - - void - SetDetachOnError (bool enable); - - bool - GetDetachOnError () const - { - return m_flags.Test(lldb::eLaunchFlagDetachOnError); - } - - protected: - FileSpec m_working_dir; - std::string m_plugin_name; - FileSpec m_shell; - Flags m_flags; // Bitwise OR of bits from lldb::LaunchFlags - std::vector<FileAction> m_file_actions; // File actions for any other files - std::shared_ptr<lldb_utility::PseudoTerminal> m_pty; - uint32_t m_resume_count; // How many times do we resume after launching - Host::MonitorChildProcessCallback m_monitor_callback; - void *m_monitor_callback_baton; - bool m_monitor_signals; - std::string m_event_data; // A string passed to the plugin launch, having no meaning to the upper levels of lldb. - lldb::ListenerSP m_listener_sp; - lldb::ListenerSP m_hijack_listener_sp; - }; +namespace lldb_private { + +//---------------------------------------------------------------------- +// ProcessLaunchInfo +// +// Describes any information that is required to launch a process. +//---------------------------------------------------------------------- + +class ProcessLaunchInfo : public ProcessInfo { +public: + ProcessLaunchInfo(); + + ProcessLaunchInfo(const FileSpec &stdin_file_spec, + const FileSpec &stdout_file_spec, + const FileSpec &stderr_file_spec, + const FileSpec &working_dir, uint32_t launch_flags); + + void AppendFileAction(const FileAction &info) { + m_file_actions.push_back(info); + } + + bool AppendCloseFileAction(int fd); + + bool AppendDuplicateFileAction(int fd, int dup_fd); + + bool AppendOpenFileAction(int fd, const FileSpec &file_spec, bool read, + bool write); + + bool AppendSuppressFileAction(int fd, bool read, bool write); + + void FinalizeFileActions(Target *target, bool default_to_use_pty); + + size_t GetNumFileActions() const { return m_file_actions.size(); } + + const FileAction *GetFileActionAtIndex(size_t idx) const; + + const FileAction *GetFileActionForFD(int fd) const; + + Flags &GetFlags() { return m_flags; } + + const Flags &GetFlags() const { return m_flags; } + + const FileSpec &GetWorkingDirectory() const; + + void SetWorkingDirectory(const FileSpec &working_dir); + + const char *GetProcessPluginName() const; + + void SetProcessPluginName(llvm::StringRef plugin); + + const FileSpec &GetShell() const; + + void SetShell(const FileSpec &shell); + + uint32_t GetResumeCount() const { return m_resume_count; } + + void SetResumeCount(uint32_t c) { m_resume_count = c; } + + bool GetLaunchInSeparateProcessGroup() const { + return m_flags.Test(lldb::eLaunchFlagLaunchInSeparateProcessGroup); + } + + void SetLaunchInSeparateProcessGroup(bool separate); + + bool GetShellExpandArguments() const { + return m_flags.Test(lldb::eLaunchFlagShellExpandArguments); + } + + void SetShellExpandArguments(bool expand); + + void Clear(); + + bool ConvertArgumentsForLaunchingInShell(Error &error, bool localhost, + bool will_debug, + bool first_arg_is_full_shell_command, + int32_t num_resumes); + + void + SetMonitorProcessCallback(const Host::MonitorChildProcessCallback &callback, + bool monitor_signals); + + Host::MonitorChildProcessCallback GetMonitorProcessCallback() const { + return m_monitor_callback; + } + + bool GetMonitorSignals() const { return m_monitor_signals; } + + // If the LaunchInfo has a monitor callback, then arrange to monitor the + // process. + // Return true if the LaunchInfo has taken care of monitoring the process, and + // false if the + // caller might want to monitor the process themselves. + + bool MonitorProcess() const; + + lldb_utility::PseudoTerminal &GetPTY() { return *m_pty; } + + // Get and set the actual listener that will be used for the process events + lldb::ListenerSP GetListener() const { return m_listener_sp; } + + void SetListener(const lldb::ListenerSP &listener_sp) { + m_listener_sp = listener_sp; + } + + lldb::ListenerSP GetListenerForProcess(Debugger &debugger); + + lldb::ListenerSP GetHijackListener() const { return m_hijack_listener_sp; } + + void SetHijackListener(const lldb::ListenerSP &listener_sp) { + m_hijack_listener_sp = listener_sp; + } + + void SetLaunchEventData(const char *data) { m_event_data.assign(data); } + + const char *GetLaunchEventData() const { return m_event_data.c_str(); } + + void SetDetachOnError(bool enable); + + bool GetDetachOnError() const { + return m_flags.Test(lldb::eLaunchFlagDetachOnError); + } + +protected: + FileSpec m_working_dir; + std::string m_plugin_name; + FileSpec m_shell; + Flags m_flags; // Bitwise OR of bits from lldb::LaunchFlags + std::vector<FileAction> m_file_actions; // File actions for any other files + std::shared_ptr<lldb_utility::PseudoTerminal> m_pty; + uint32_t m_resume_count; // How many times do we resume after launching + Host::MonitorChildProcessCallback m_monitor_callback; + void *m_monitor_callback_baton; + bool m_monitor_signals; + std::string m_event_data; // A string passed to the plugin launch, having no + // meaning to the upper levels of lldb. + lldb::ListenerSP m_listener_sp; + lldb::ListenerSP m_hijack_listener_sp; +}; } #endif // liblldb_ProcessLaunch_Info_h diff --git a/include/lldb/Target/Queue.h b/include/lldb/Target/Queue.h index 514481fe8c9d..2df4d54a89b6 100644 --- a/include/lldb/Target/Queue.h +++ b/include/lldb/Target/Queue.h @@ -10,21 +10,20 @@ #ifndef liblldb_Queue_h_ #define liblldb_Queue_h_ -#include <vector> #include <string> +#include <vector> -#include "lldb/lldb-forward.h" +#include "lldb/Target/QueueItem.h" #include "lldb/lldb-enumerations.h" +#include "lldb/lldb-forward.h" #include "lldb/lldb-private.h" -#include "lldb/Target/QueueItem.h" - namespace lldb_private { //------------------------------------------------------------------ // Queue: // This class represents a libdispatch aka Grand Central Dispatch -// queue in the process. +// queue in the process. // // A program using libdispatch will create queues, put work items // (functions, blocks) on the queues. The system will create / @@ -34,169 +33,147 @@ namespace lldb_private { // be associated with multiple threads. //------------------------------------------------------------------ - -class Queue : - public std::enable_shared_from_this<Queue> -{ +class Queue : public std::enable_shared_from_this<Queue> { public: - - Queue (lldb::ProcessSP process_sp, lldb::queue_id_t queue_id, const char *queue_name); - - ~Queue (); - - //------------------------------------------------------------------ - /// Get the QueueID for this Queue - /// - /// A 64-bit ID number that uniquely identifies a queue at this particular - /// stop_id. Currently the libdispatch serialnum is used for the QueueID; - /// it is a number that starts at 1 for each process and increments with - /// each queue. A serialnum is not reused for a different queue in the - /// lifetime of that process execution. - /// - /// @return - /// The QueueID for this Queue. - //------------------------------------------------------------------ - lldb::queue_id_t - GetID (); - - //------------------------------------------------------------------ - /// Get the name of this Queue - /// - /// @return - /// The name of the queue, if one is available. - /// A NULL pointer is returned if none is available. - //------------------------------------------------------------------ - const char * - GetName (); - - //------------------------------------------------------------------ - /// Get the IndexID for this Queue - /// - /// This is currently the same as GetID(). If it changes in the future, - /// it will be a small integer value (starting with 1) assigned to - /// each queue that is seen during a Process lifetime. - /// - /// Both the GetID and GetIndexID are being retained for Queues to - /// maintain similar API to the Thread class, and allow for the - /// possibility of GetID changing to a different source in the future. - /// - /// @return - /// The IndexID for this queue. - //------------------------------------------------------------------ - uint32_t - GetIndexID (); - - //------------------------------------------------------------------ - /// Return the threads currently associated with this queue - /// - /// Zero, one, or many threads may be executing code for a queue at - /// a given point in time. This call returns the list of threads - /// that are currently executing work for this queue. - /// - /// @return - /// The threads currently performing work for this queue - //------------------------------------------------------------------ - std::vector<lldb::ThreadSP> - GetThreads (); - - //------------------------------------------------------------------ - /// Return the items that are currently enqueued - /// - /// "Enqueued" means that the item has been added to the queue to - /// be done, but has not yet been done. When the item is going to - /// be processed it is "dequeued". - /// - /// @return - /// The vector of enqueued items for this queue - //------------------------------------------------------------------ - const std::vector<lldb::QueueItemSP> & - GetPendingItems(); - - lldb::ProcessSP - GetProcess() const - { - return m_process_wp.lock(); - } - - //------------------------------------------------------------------ - /// Get the number of work items that this queue is currently running - /// - /// @return - /// The number of work items currently executing. For a serial - /// queue, this will be 0 or 1. For a concurrent queue, this - /// may be any number. - //------------------------------------------------------------------ - uint32_t - GetNumRunningWorkItems () const; - - //------------------------------------------------------------------ - /// Get the number of work items enqueued on this queue - /// - /// @return - /// The number of work items currently enqueued, waiting to - /// execute. - //------------------------------------------------------------------ - uint32_t - GetNumPendingWorkItems () const; - - //------------------------------------------------------------------ - /// Get the dispatch_queue_t structure address for this Queue - /// - /// Get the address in the inferior process' memory of this Queue's - /// dispatch_queue_t structure. - /// - /// @return - /// The address of the dispatch_queue_t structure, if known. - /// LLDB_INVALID_ADDRESS will be returned if it is unavailable. - //------------------------------------------------------------------ - lldb::addr_t - GetLibdispatchQueueAddress () const; - - - void - SetNumRunningWorkItems (uint32_t count); - - void - SetNumPendingWorkItems (uint32_t count); - - void - SetLibdispatchQueueAddress (lldb::addr_t dispatch_queue_t_addr); - - void - PushPendingQueueItem (lldb::QueueItemSP item) - { - m_pending_items.push_back (item); - } - - //------------------------------------------------------------------ - /// Return the kind (serial, concurrent) of this queue - /// - /// @return - // Whether this is a serial or a concurrent queue - //------------------------------------------------------------------ - lldb::QueueKind - GetKind (); - - void - SetKind (lldb::QueueKind kind); + Queue(lldb::ProcessSP process_sp, lldb::queue_id_t queue_id, + const char *queue_name); + + ~Queue(); + + //------------------------------------------------------------------ + /// Get the QueueID for this Queue + /// + /// A 64-bit ID number that uniquely identifies a queue at this particular + /// stop_id. Currently the libdispatch serialnum is used for the QueueID; + /// it is a number that starts at 1 for each process and increments with + /// each queue. A serialnum is not reused for a different queue in the + /// lifetime of that process execution. + /// + /// @return + /// The QueueID for this Queue. + //------------------------------------------------------------------ + lldb::queue_id_t GetID(); + + //------------------------------------------------------------------ + /// Get the name of this Queue + /// + /// @return + /// The name of the queue, if one is available. + /// A NULL pointer is returned if none is available. + //------------------------------------------------------------------ + const char *GetName(); + + //------------------------------------------------------------------ + /// Get the IndexID for this Queue + /// + /// This is currently the same as GetID(). If it changes in the future, + /// it will be a small integer value (starting with 1) assigned to + /// each queue that is seen during a Process lifetime. + /// + /// Both the GetID and GetIndexID are being retained for Queues to + /// maintain similar API to the Thread class, and allow for the + /// possibility of GetID changing to a different source in the future. + /// + /// @return + /// The IndexID for this queue. + //------------------------------------------------------------------ + uint32_t GetIndexID(); + + //------------------------------------------------------------------ + /// Return the threads currently associated with this queue + /// + /// Zero, one, or many threads may be executing code for a queue at + /// a given point in time. This call returns the list of threads + /// that are currently executing work for this queue. + /// + /// @return + /// The threads currently performing work for this queue + //------------------------------------------------------------------ + std::vector<lldb::ThreadSP> GetThreads(); + + //------------------------------------------------------------------ + /// Return the items that are currently enqueued + /// + /// "Enqueued" means that the item has been added to the queue to + /// be done, but has not yet been done. When the item is going to + /// be processed it is "dequeued". + /// + /// @return + /// The vector of enqueued items for this queue + //------------------------------------------------------------------ + const std::vector<lldb::QueueItemSP> &GetPendingItems(); + + lldb::ProcessSP GetProcess() const { return m_process_wp.lock(); } + + //------------------------------------------------------------------ + /// Get the number of work items that this queue is currently running + /// + /// @return + /// The number of work items currently executing. For a serial + /// queue, this will be 0 or 1. For a concurrent queue, this + /// may be any number. + //------------------------------------------------------------------ + uint32_t GetNumRunningWorkItems() const; + + //------------------------------------------------------------------ + /// Get the number of work items enqueued on this queue + /// + /// @return + /// The number of work items currently enqueued, waiting to + /// execute. + //------------------------------------------------------------------ + uint32_t GetNumPendingWorkItems() const; + + //------------------------------------------------------------------ + /// Get the dispatch_queue_t structure address for this Queue + /// + /// Get the address in the inferior process' memory of this Queue's + /// dispatch_queue_t structure. + /// + /// @return + /// The address of the dispatch_queue_t structure, if known. + /// LLDB_INVALID_ADDRESS will be returned if it is unavailable. + //------------------------------------------------------------------ + lldb::addr_t GetLibdispatchQueueAddress() const; + + void SetNumRunningWorkItems(uint32_t count); + + void SetNumPendingWorkItems(uint32_t count); + + void SetLibdispatchQueueAddress(lldb::addr_t dispatch_queue_t_addr); + + void PushPendingQueueItem(lldb::QueueItemSP item) { + m_pending_items.push_back(item); + } + + //------------------------------------------------------------------ + /// Return the kind (serial, concurrent) of this queue + /// + /// @return + // Whether this is a serial or a concurrent queue + //------------------------------------------------------------------ + lldb::QueueKind GetKind(); + + void SetKind(lldb::QueueKind kind); private: - //------------------------------------------------------------------ - // For Queue only - //------------------------------------------------------------------ - - lldb::ProcessWP m_process_wp; - lldb::queue_id_t m_queue_id; - std::string m_queue_name; - uint32_t m_running_work_items_count; - uint32_t m_pending_work_items_count; - std::vector<lldb::QueueItemSP> m_pending_items; - lldb::addr_t m_dispatch_queue_t_addr; // address of libdispatch dispatch_queue_t for this Queue - lldb::QueueKind m_kind; - - DISALLOW_COPY_AND_ASSIGN (Queue); + //------------------------------------------------------------------ + // For Queue only + //------------------------------------------------------------------ + + lldb::ProcessWP m_process_wp; + lldb::queue_id_t m_queue_id; + std::string m_queue_name; + uint32_t m_running_work_items_count; + uint32_t m_pending_work_items_count; + std::vector<lldb::QueueItemSP> m_pending_items; + lldb::addr_t m_dispatch_queue_t_addr; // address of libdispatch + // dispatch_queue_t for this Queue + lldb::QueueKind m_kind; + + DISALLOW_COPY_AND_ASSIGN(Queue); }; } // namespace lldb_private -#endif // liblldb_Queue_h_ +#endif // liblldb_Queue_h_ diff --git a/include/lldb/Target/QueueItem.h b/include/lldb/Target/QueueItem.h index aea506644c37..f6378502c19c 100644 --- a/include/lldb/Target/QueueItem.h +++ b/include/lldb/Target/QueueItem.h @@ -18,9 +18,9 @@ // Other libraries and framework includes // Project includes -#include "lldb/lldb-private.h" #include "lldb/lldb-enumerations.h" #include "lldb/lldb-forward.h" +#include "lldb/lldb-private.h" #include "lldb/Core/Address.h" #include "lldb/Core/ConstString.h" @@ -33,197 +33,153 @@ namespace lldb_private { // Grand Central Dispatch (GCD) queue. Most often, this will be a // function or block. // "enqueued" here means that the work item has been added to a queue -// but it has not yet started executing. When it is "dequeued", +// but it has not yet started executing. When it is "dequeued", // execution of the item begins. //------------------------------------------------------------------ -class QueueItem : - public std::enable_shared_from_this<QueueItem> -{ +class QueueItem : public std::enable_shared_from_this<QueueItem> { public: - QueueItem (lldb::QueueSP queue_sp, lldb::ProcessSP process_sp, lldb::addr_t item_ref, lldb_private::Address address); - - ~QueueItem (); - - //------------------------------------------------------------------ - /// Get the kind of work item this is - /// - /// @return - /// The type of work item that this QueueItem object - /// represents. eQueueItemKindUnknown may be returned. - //------------------------------------------------------------------ - lldb::QueueItemKind - GetKind (); - - //------------------------------------------------------------------ - /// Set the type of work item this is - /// - /// @param [in] item_kind - /// Set the kind of this work item object. - //------------------------------------------------------------------ - void - SetKind (lldb::QueueItemKind item_kind); - - //------------------------------------------------------------------ - /// Get the code address that will be executed when this work item - /// is executed. - /// - /// @return - /// The address that will be invoked when this work item is - /// executed. Not all types of QueueItems will have an - /// address associated with them; check that the returned - /// Address is valid, or check that the WorkItemKind is a - /// kind that involves an address, such as eQueueItemKindFunction - /// or eQueueItemKindBlock. - //------------------------------------------------------------------ - lldb_private::Address & - GetAddress (); - - //------------------------------------------------------------------ - /// Set the work item address for this object - /// - /// @param [in] addr - /// The address that will be invoked when this work item - /// is executed. - //------------------------------------------------------------------ - void - SetAddress (lldb_private::Address addr); - - //------------------------------------------------------------------ - /// Check if this QueueItem object is valid - /// - /// If the weak pointer to the parent Queue cannot be revivified, - /// it is invalid. - /// - /// @return - /// True if this object is valid. - //------------------------------------------------------------------ - bool - IsValid () - { - return m_queue_wp.lock() != nullptr; - } - - //------------------------------------------------------------------ - /// Get an extended backtrace thread for this queue item, if available - /// - /// If the backtrace/thread information was collected when this item - /// was enqueued, this call will provide it. - /// - /// @param [in] type - /// The type of extended backtrace being requested, e.g. "libdispatch" - /// or "pthread". - /// - /// @return - /// A thread shared pointer which will have a reference to an extended - /// thread if one was available. - //------------------------------------------------------------------ - lldb::ThreadSP - GetExtendedBacktraceThread (ConstString type); - - void - SetItemThatEnqueuedThis (lldb::addr_t address_of_item) - { - m_item_that_enqueued_this_ref = address_of_item; - } - - lldb::addr_t - GetItemThatEnqueuedThis (); - - void - SetEnqueueingThreadID (lldb::tid_t tid) - { - m_enqueueing_thread_id = tid; - } - - lldb::tid_t - GetEnqueueingThreadID (); - - void - SetEnqueueingQueueID (lldb::queue_id_t qid) - { - m_enqueueing_queue_id = qid; - } - - lldb::queue_id_t - GetEnqueueingQueueID (); - - void - SetTargetQueueID (lldb::queue_id_t qid) - { - m_target_queue_id = qid; - } - - void - SetStopID (uint32_t stop_id) - { - m_stop_id = stop_id; - } - - uint32_t - GetStopID (); - - void - SetEnqueueingBacktrace (std::vector<lldb::addr_t> backtrace) - { - m_backtrace = backtrace; - } - - std::vector<lldb::addr_t> & - GetEnqueueingBacktrace (); - - void - SetThreadLabel (std::string thread_name) - { - m_thread_label = thread_name; - } - - std::string - GetThreadLabel (); - - void - SetQueueLabel (std::string queue_name) - { - m_queue_label = queue_name; - } - - std::string - GetQueueLabel (); - - void - SetTargetQueueLabel (std::string queue_name) - { - m_target_queue_label = queue_name; - } - - lldb::ProcessSP - GetProcessSP (); + QueueItem(lldb::QueueSP queue_sp, lldb::ProcessSP process_sp, + lldb::addr_t item_ref, lldb_private::Address address); + + ~QueueItem(); + + //------------------------------------------------------------------ + /// Get the kind of work item this is + /// + /// @return + /// The type of work item that this QueueItem object + /// represents. eQueueItemKindUnknown may be returned. + //------------------------------------------------------------------ + lldb::QueueItemKind GetKind(); + + //------------------------------------------------------------------ + /// Set the type of work item this is + /// + /// @param [in] item_kind + /// Set the kind of this work item object. + //------------------------------------------------------------------ + void SetKind(lldb::QueueItemKind item_kind); + + //------------------------------------------------------------------ + /// Get the code address that will be executed when this work item + /// is executed. + /// + /// @return + /// The address that will be invoked when this work item is + /// executed. Not all types of QueueItems will have an + /// address associated with them; check that the returned + /// Address is valid, or check that the WorkItemKind is a + /// kind that involves an address, such as eQueueItemKindFunction + /// or eQueueItemKindBlock. + //------------------------------------------------------------------ + lldb_private::Address &GetAddress(); + + //------------------------------------------------------------------ + /// Set the work item address for this object + /// + /// @param [in] addr + /// The address that will be invoked when this work item + /// is executed. + //------------------------------------------------------------------ + void SetAddress(lldb_private::Address addr); + + //------------------------------------------------------------------ + /// Check if this QueueItem object is valid + /// + /// If the weak pointer to the parent Queue cannot be revivified, + /// it is invalid. + /// + /// @return + /// True if this object is valid. + //------------------------------------------------------------------ + bool IsValid() { return m_queue_wp.lock() != nullptr; } + + //------------------------------------------------------------------ + /// Get an extended backtrace thread for this queue item, if available + /// + /// If the backtrace/thread information was collected when this item + /// was enqueued, this call will provide it. + /// + /// @param [in] type + /// The type of extended backtrace being requested, e.g. "libdispatch" + /// or "pthread". + /// + /// @return + /// A thread shared pointer which will have a reference to an extended + /// thread if one was available. + //------------------------------------------------------------------ + lldb::ThreadSP GetExtendedBacktraceThread(ConstString type); + + void SetItemThatEnqueuedThis(lldb::addr_t address_of_item) { + m_item_that_enqueued_this_ref = address_of_item; + } + + lldb::addr_t GetItemThatEnqueuedThis(); + + void SetEnqueueingThreadID(lldb::tid_t tid) { m_enqueueing_thread_id = tid; } + + lldb::tid_t GetEnqueueingThreadID(); + + void SetEnqueueingQueueID(lldb::queue_id_t qid) { + m_enqueueing_queue_id = qid; + } + + lldb::queue_id_t GetEnqueueingQueueID(); + + void SetTargetQueueID(lldb::queue_id_t qid) { m_target_queue_id = qid; } + + void SetStopID(uint32_t stop_id) { m_stop_id = stop_id; } + + uint32_t GetStopID(); + + void SetEnqueueingBacktrace(std::vector<lldb::addr_t> backtrace) { + m_backtrace = backtrace; + } + + std::vector<lldb::addr_t> &GetEnqueueingBacktrace(); + + void SetThreadLabel(std::string thread_name) { m_thread_label = thread_name; } + + std::string GetThreadLabel(); + + void SetQueueLabel(std::string queue_name) { m_queue_label = queue_name; } + + std::string GetQueueLabel(); + + void SetTargetQueueLabel(std::string queue_name) { + m_target_queue_label = queue_name; + } + + lldb::ProcessSP GetProcessSP(); protected: - void - FetchEntireItem (); - - lldb::QueueWP m_queue_wp; - lldb::ProcessWP m_process_wp; - - lldb::addr_t m_item_ref; // the token we can be used to fetch more information about this queue item - lldb_private::Address m_address; - bool m_have_fetched_entire_item; - - lldb::QueueItemKind m_kind; - lldb::addr_t m_item_that_enqueued_this_ref; // a handle that we can pass into libBacktraceRecording - // to get the QueueItem that enqueued this item - lldb::tid_t m_enqueueing_thread_id; // thread that enqueued this item - lldb::queue_id_t m_enqueueing_queue_id; // Queue that enqueued this item, if it was a queue - lldb::queue_id_t m_target_queue_id; - uint32_t m_stop_id; // indicates when this backtrace was recorded in time - std::vector<lldb::addr_t> m_backtrace; - std::string m_thread_label; - std::string m_queue_label; - std::string m_target_queue_label; + void FetchEntireItem(); + + lldb::QueueWP m_queue_wp; + lldb::ProcessWP m_process_wp; + + lldb::addr_t m_item_ref; // the token we can be used to fetch more information + // about this queue item + lldb_private::Address m_address; + bool m_have_fetched_entire_item; + + lldb::QueueItemKind m_kind; + lldb::addr_t m_item_that_enqueued_this_ref; // a handle that we can pass into + // libBacktraceRecording + // to get the QueueItem that enqueued this item + lldb::tid_t m_enqueueing_thread_id; // thread that enqueued this item + lldb::queue_id_t + m_enqueueing_queue_id; // Queue that enqueued this item, if it was a queue + lldb::queue_id_t m_target_queue_id; + uint32_t m_stop_id; // indicates when this backtrace was recorded in time + std::vector<lldb::addr_t> m_backtrace; + std::string m_thread_label; + std::string m_queue_label; + std::string m_target_queue_label; private: - DISALLOW_COPY_AND_ASSIGN (QueueItem); + DISALLOW_COPY_AND_ASSIGN(QueueItem); }; } // namespace lldb_private diff --git a/include/lldb/Target/QueueList.h b/include/lldb/Target/QueueList.h index 265145db2696..038463d9ab02 100644 --- a/include/lldb/Target/QueueList.h +++ b/include/lldb/Target/QueueList.h @@ -13,130 +13,118 @@ #include <mutex> #include <vector> -#include "lldb/lldb-private.h" #include "lldb/Core/UserID.h" #include "lldb/Utility/Iterable.h" - +#include "lldb/lldb-private.h" namespace lldb_private { //------------------------------------------------------------------ // QueueList: -// This is the container for libdispatch aka Grand Central Dispatch +// This is the container for libdispatch aka Grand Central Dispatch // Queue objects. // // Each Process will have a QueueList. When the process execution is -// paused, the QueueList may be populated with Queues by the +// paused, the QueueList may be populated with Queues by the // SystemRuntime. //------------------------------------------------------------------ -class QueueList -{ -friend class Process; +class QueueList { + friend class Process; public: - - QueueList (Process *process); - - ~QueueList (); - - //------------------------------------------------------------------ - /// Get the number of libdispatch queues that are available - /// - /// @return - /// The number of queues that are stored in the QueueList. - //------------------------------------------------------------------ - uint32_t - GetSize(); - - //------------------------------------------------------------------ - /// Get the Queue at a given index number - /// - /// @param [in] idx - /// The index number (0-based) of the queue. - /// @return - /// The Queue at that index number. - //------------------------------------------------------------------ - lldb::QueueSP - GetQueueAtIndex (uint32_t idx); - - typedef std::vector<lldb::QueueSP> collection; - typedef LockingAdaptedIterable<collection, lldb::QueueSP, vector_adapter, std::mutex> QueueIterable; - - //------------------------------------------------------------------ - /// Iterate over the list of queues - /// - /// @return - /// An Iterable object which can be used to loop over the queues - /// that exist. - //------------------------------------------------------------------ - QueueIterable - Queues () - { - return QueueIterable(m_queues, m_mutex); - } - - //------------------------------------------------------------------ - /// Clear out the list of queues from the QueueList - //------------------------------------------------------------------ - void - Clear(); - - //------------------------------------------------------------------ - /// Add a Queue to the QueueList - /// - /// @param [in] queue - /// Used by the SystemRuntime to populate the QueueList - //------------------------------------------------------------------ - void - AddQueue (lldb::QueueSP queue); - - //------------------------------------------------------------------ - /// Find a queue in the QueueList by QueueID - /// - /// @param [in] qid - /// The QueueID (same as returned by Thread::GetQueueID()) to find. - /// - /// @return - /// A QueueSP to the queue requested, if it is present in the QueueList. - /// An empty QueueSP will be returned if this queue was not found. - //------------------------------------------------------------------ - lldb::QueueSP - FindQueueByID (lldb::queue_id_t qid); - - //------------------------------------------------------------------ - /// Find a queue in the QueueList by IndexID - /// - /// @param [in] index_id - /// Find a queue by IndexID. This is an integer associated with each - /// unique queue seen during a debug session and will not be reused - /// for a different queue. Unlike the QueueID, a 64-bit value, this - /// will tend to be an integral value like 1 or 7. - /// - /// @return - /// A QueueSP to the queue requested, if it is present in the QueueList. - /// An empty QueueSP will be returned if this queue was not found. - //------------------------------------------------------------------ - lldb::QueueSP - FindQueueByIndexID (uint32_t index_id); - - std::mutex & - GetMutex(); + QueueList(Process *process); + + ~QueueList(); + + //------------------------------------------------------------------ + /// Get the number of libdispatch queues that are available + /// + /// @return + /// The number of queues that are stored in the QueueList. + //------------------------------------------------------------------ + uint32_t GetSize(); + + //------------------------------------------------------------------ + /// Get the Queue at a given index number + /// + /// @param [in] idx + /// The index number (0-based) of the queue. + /// @return + /// The Queue at that index number. + //------------------------------------------------------------------ + lldb::QueueSP GetQueueAtIndex(uint32_t idx); + + typedef std::vector<lldb::QueueSP> collection; + typedef LockingAdaptedIterable<collection, lldb::QueueSP, vector_adapter, + std::mutex> + QueueIterable; + + //------------------------------------------------------------------ + /// Iterate over the list of queues + /// + /// @return + /// An Iterable object which can be used to loop over the queues + /// that exist. + //------------------------------------------------------------------ + QueueIterable Queues() { return QueueIterable(m_queues, m_mutex); } + + //------------------------------------------------------------------ + /// Clear out the list of queues from the QueueList + //------------------------------------------------------------------ + void Clear(); + + //------------------------------------------------------------------ + /// Add a Queue to the QueueList + /// + /// @param [in] queue + /// Used by the SystemRuntime to populate the QueueList + //------------------------------------------------------------------ + void AddQueue(lldb::QueueSP queue); + + //------------------------------------------------------------------ + /// Find a queue in the QueueList by QueueID + /// + /// @param [in] qid + /// The QueueID (same as returned by Thread::GetQueueID()) to find. + /// + /// @return + /// A QueueSP to the queue requested, if it is present in the QueueList. + /// An empty QueueSP will be returned if this queue was not found. + //------------------------------------------------------------------ + lldb::QueueSP FindQueueByID(lldb::queue_id_t qid); + + //------------------------------------------------------------------ + /// Find a queue in the QueueList by IndexID + /// + /// @param [in] index_id + /// Find a queue by IndexID. This is an integer associated with each + /// unique queue seen during a debug session and will not be reused + /// for a different queue. Unlike the QueueID, a 64-bit value, this + /// will tend to be an integral value like 1 or 7. + /// + /// @return + /// A QueueSP to the queue requested, if it is present in the QueueList. + /// An empty QueueSP will be returned if this queue was not found. + //------------------------------------------------------------------ + lldb::QueueSP FindQueueByIndexID(uint32_t index_id); + + std::mutex &GetMutex(); protected: - - //------------------------------------------------------------------ - // Classes that inherit from Process can see and modify these - //------------------------------------------------------------------ - Process *m_process; ///< The process that manages this queue list. - uint32_t m_stop_id; ///< The process stop ID that this queue list is valid for. - collection m_queues; ///< The queues for this process. - std::mutex m_mutex; + //------------------------------------------------------------------ + // Classes that inherit from Process can see and modify these + //------------------------------------------------------------------ + Process *m_process; ///< The process that manages this queue list. + uint32_t + m_stop_id; ///< The process stop ID that this queue list is valid for. + collection m_queues; ///< The queues for this process. + std::mutex m_mutex; private: - QueueList (); + QueueList(); }; } // namespace lldb_private -#endif // liblldb_QueueList_h_ +#endif // liblldb_QueueList_h_ diff --git a/include/lldb/Target/RegisterCheckpoint.h b/include/lldb/Target/RegisterCheckpoint.h index 3e61e1490d4b..8391cadcdf66 100644 --- a/include/lldb/Target/RegisterCheckpoint.h +++ b/include/lldb/Target/RegisterCheckpoint.h @@ -10,62 +10,46 @@ #ifndef liblldb_RegisterCheckpoint_h_ #define liblldb_RegisterCheckpoint_h_ -#include "lldb/lldb-private.h" #include "lldb/Core/UserID.h" #include "lldb/Target/StackID.h" +#include "lldb/lldb-private.h" namespace lldb_private { - // Inherit from UserID in case pushing/popping all register values can be - // done using a 64 bit integer that holds a baton/cookie instead of actually - // having to read all register values into a buffer - class RegisterCheckpoint : public UserID - { - public: - - enum class Reason { - // An expression is about to be run on the thread if the protocol that - // talks to the debuggee supports checkpointing the registers using a - // push/pop then the UserID base class in the RegisterCheckpoint can - // be used to store the baton/cookie that refers to the remote saved - // state. - eExpression, - // The register checkpoint wants the raw register bytes, so they must - // be read into m_data_sp, or the save/restore checkpoint should fail. - eDataBackup - }; - - RegisterCheckpoint(Reason reason) : - UserID(0), - m_data_sp (), - m_reason(reason) - { - } - - ~RegisterCheckpoint() - { - } - - lldb::DataBufferSP & - GetData() - { - return m_data_sp; - } - - const lldb::DataBufferSP & - GetData() const - { - return m_data_sp; - } - - protected: - lldb::DataBufferSP m_data_sp; - Reason m_reason; - - // Make RegisterCheckpointSP if you wish to share the data in this class. - DISALLOW_COPY_AND_ASSIGN(RegisterCheckpoint); - }; - +// Inherit from UserID in case pushing/popping all register values can be +// done using a 64 bit integer that holds a baton/cookie instead of actually +// having to read all register values into a buffer +class RegisterCheckpoint : public UserID { +public: + enum class Reason { + // An expression is about to be run on the thread if the protocol that + // talks to the debuggee supports checkpointing the registers using a + // push/pop then the UserID base class in the RegisterCheckpoint can + // be used to store the baton/cookie that refers to the remote saved + // state. + eExpression, + // The register checkpoint wants the raw register bytes, so they must + // be read into m_data_sp, or the save/restore checkpoint should fail. + eDataBackup + }; + + RegisterCheckpoint(Reason reason) + : UserID(0), m_data_sp(), m_reason(reason) {} + + ~RegisterCheckpoint() {} + + lldb::DataBufferSP &GetData() { return m_data_sp; } + + const lldb::DataBufferSP &GetData() const { return m_data_sp; } + +protected: + lldb::DataBufferSP m_data_sp; + Reason m_reason; + + // Make RegisterCheckpointSP if you wish to share the data in this class. + DISALLOW_COPY_AND_ASSIGN(RegisterCheckpoint); +}; + } // namespace lldb_private -#endif // liblldb_RegisterCheckpoint_h_ +#endif // liblldb_RegisterCheckpoint_h_ diff --git a/include/lldb/Target/RegisterContext.h b/include/lldb/Target/RegisterContext.h index dfeb18348bf7..485645b2dc14 100644 --- a/include/lldb/Target/RegisterContext.h +++ b/include/lldb/Target/RegisterContext.h @@ -14,255 +14,217 @@ // C++ Includes // Other libraries and framework includes // Project includes -#include "lldb/lldb-private.h" #include "lldb/Target/ExecutionContextScope.h" +#include "lldb/lldb-private.h" namespace lldb_private { -class RegisterContext : - public std::enable_shared_from_this<RegisterContext>, - public ExecutionContextScope -{ +class RegisterContext : public std::enable_shared_from_this<RegisterContext>, + public ExecutionContextScope { public: - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - RegisterContext (Thread &thread, uint32_t concrete_frame_idx); - - ~RegisterContext() override; - - void - InvalidateIfNeeded (bool force); - - //------------------------------------------------------------------ - // Subclasses must override these functions - //------------------------------------------------------------------ - virtual void - InvalidateAllRegisters () = 0; - - virtual size_t - GetRegisterCount () = 0; - - virtual const RegisterInfo * - GetRegisterInfoAtIndex (size_t reg) = 0; - - // Detect the register size dynamically. - uint32_t - UpdateDynamicRegisterSize (const lldb_private::ArchSpec &arch, - RegisterInfo* reg_info); - - virtual size_t - GetRegisterSetCount () = 0; - - virtual const RegisterSet * - GetRegisterSet (size_t reg_set) = 0; - - virtual bool - ReadRegister (const RegisterInfo *reg_info, RegisterValue ®_value) = 0; - - virtual bool - WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value) = 0; - - virtual bool - ReadAllRegisterValues (lldb::DataBufferSP &data_sp) - { - return false; - } - - virtual bool - WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) - { - return false; - } - - // These two functions are used to implement "push" and "pop" of register states. They are used primarily - // for expression evaluation, where we need to push a new state (storing the old one in data_sp) and then - // restoring the original state by passing the data_sp we got from ReadAllRegisters to WriteAllRegisterValues. - // ReadAllRegisters will do what is necessary to return a coherent set of register values for this thread, which - // may mean e.g. interrupting a thread that is sitting in a kernel trap. That is a somewhat disruptive operation, - // so these API's should only be used when this behavior is needed. - - virtual bool - ReadAllRegisterValues (lldb_private::RegisterCheckpoint ®_checkpoint); - - virtual bool - WriteAllRegisterValues (const lldb_private::RegisterCheckpoint ®_checkpoint); - - bool - CopyFromRegisterContext (lldb::RegisterContextSP context); - - //------------------------------------------------------------------ - /// Convert from a given register numbering scheme to the lldb register - /// numbering scheme - /// - /// There may be multiple ways to enumerate the registers for a given - /// architecture. ABI references will specify one to be used with - /// DWARF, the register numberings from process plugin, there may - /// be a variation used for eh_frame unwind instructions (e.g. on Darwin), - /// and so on. Register 5 by itself is meaningless - RegisterKind - /// enumeration tells you what context that number should be translated as. - /// - /// Inside lldb, register numbers are in the eRegisterKindLLDB scheme; - /// arguments which take a register number should take one in that - /// scheme. - /// - /// eRegisterKindGeneric is a special numbering scheme which gives us - /// constant values for the pc, frame register, stack register, etc., for - /// use within lldb. They may not be defined for all architectures but - /// it allows generic code to translate these common registers into the - /// lldb numbering scheme. - /// - /// This method translates a given register kind + register number into - /// the eRegisterKindLLDB register numbering. - /// - /// @param [in] kind - /// The register numbering scheme (RegisterKind) that the following - /// register number is in. - /// - /// @param [in] num - /// A register number in the 'kind' register numbering scheme. - /// - /// @return - /// The equivalent register number in the eRegisterKindLLDB - /// numbering scheme, if possible, else LLDB_INVALID_REGNUM. - //------------------------------------------------------------------ - virtual uint32_t - ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num) = 0; - - //------------------------------------------------------------------ - // Subclasses can override these functions if desired - //------------------------------------------------------------------ - virtual uint32_t - NumSupportedHardwareBreakpoints (); - - virtual uint32_t - SetHardwareBreakpoint (lldb::addr_t addr, size_t size); - - virtual bool - ClearHardwareBreakpoint (uint32_t hw_idx); - - virtual uint32_t - NumSupportedHardwareWatchpoints (); - - virtual uint32_t - SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write); - - virtual bool - ClearHardwareWatchpoint (uint32_t hw_index); - - virtual bool - HardwareSingleStep (bool enable); - - virtual Error - ReadRegisterValueFromMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t src_addr, uint32_t src_len, RegisterValue ®_value); - - virtual Error - WriteRegisterValueToMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr, uint32_t dst_len, const RegisterValue ®_value); - - //------------------------------------------------------------------ - // Subclasses should not override these - //------------------------------------------------------------------ - virtual lldb::tid_t - GetThreadID() const; - - virtual Thread & - GetThread () - { - return m_thread; - } - - const RegisterInfo * - GetRegisterInfoByName (const char *reg_name, uint32_t start_idx = 0); - - const RegisterInfo * - GetRegisterInfo (lldb::RegisterKind reg_kind, uint32_t reg_num); - - |