//===-- ClangExpressionDeclMap.h --------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONDECLMAP_H #define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONDECLMAP_H #include #include #include #include "ClangASTSource.h" #include "ClangExpressionVariable.h" #include "lldb/Core/Value.h" #include "lldb/Expression/Materializer.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/TaggedASTType.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/lldb-public.h" #include "clang/AST/Decl.h" #include "llvm/ADT/DenseMap.h" namespace lldb_private { class ClangPersistentVariables; /// \class ClangExpressionDeclMap ClangExpressionDeclMap.h /// "lldb/Expression/ClangExpressionDeclMap.h" Manages named entities that are /// defined in LLDB's debug information. /// /// The Clang parser uses the ClangASTSource as an interface to request named /// entities from outside an expression. The ClangASTSource reports back, /// listing all possible objects corresponding to a particular name. But it /// in turn relies on ClangExpressionDeclMap, which performs several important /// functions. /// /// First, it records what variables and functions were looked up and what /// Decls were returned for them. /// /// Second, it constructs a struct on behalf of IRForTarget, recording which /// variables should be placed where and relaying this information back so /// that IRForTarget can generate context-independent code. /// /// Third, it "materializes" this struct on behalf of the expression command, /// finding the current values of each variable and placing them into the /// struct so that it can be passed to the JITted version of the IR. /// /// Fourth and finally, it "dematerializes" the struct after the JITted code /// has has executed, placing the new values back where it found the old ones. class ClangExpressionDeclMap : public ClangASTSource { public: /// Constructor /// /// Initializes class variables. /// /// \param[in] keep_result_in_memory /// If true, inhibits the normal deallocation of the memory for /// the result persistent variable, and instead marks the variable /// as persisting. /// /// \param[in] result_delegate /// If non-NULL, use this delegate to report result values. This /// allows the client ClangUserExpression to report a result. /// /// \param[in] target /// The target to use when parsing. /// /// \param[in] importer /// The ClangASTImporter to use when parsing. /// /// \param[in] ctx_obj /// If not empty, then expression is evaluated in context of this object. /// See the comment to `UserExpression::Evaluate` for details. ClangExpressionDeclMap( bool keep_result_in_memory, Materializer::PersistentVariableDelegate *result_delegate, const lldb::TargetSP &target, const std::shared_ptr &importer, ValueObject *ctx_obj); /// Destructor ~ClangExpressionDeclMap() override; /// Enable the state needed for parsing and IR transformation. /// /// \param[in] exe_ctx /// The execution context to use when finding types for variables. /// Also used to find a "scratch" AST context to store result types. /// /// \param[in] materializer /// If non-NULL, the materializer to populate with information about /// the variables to use /// /// \return /// True if parsing is possible; false if it is unsafe to continue. bool WillParse(ExecutionContext &exe_ctx, Materializer *materializer); void InstallCodeGenerator(clang::ASTConsumer *code_gen); void InstallDiagnosticManager(DiagnosticManager &diag_manager); /// Disable the state needed for parsing and IR transformation. void DidParse(); /// [Used by IRForTarget] Add a variable to the list of persistent /// variables for the process. /// /// \param[in] decl /// The Clang declaration for the persistent variable, used for /// lookup during parsing. /// /// \param[in] name /// The name of the persistent variable, usually $something. /// /// \param[in] type /// The type of the variable, in the Clang parser's context. /// /// \return /// True on success; false otherwise. bool AddPersistentVariable(const clang::NamedDecl *decl, ConstString name, TypeFromParser type, bool is_result, bool is_lvalue); /// [Used by IRForTarget] Add a variable to the struct that needs to /// be materialized each time the expression runs. /// /// \param[in] decl /// The Clang declaration for the variable. /// /// \param[in] name /// The name of the variable. /// /// \param[in] value /// The LLVM IR value for this variable. /// /// \param[in] size /// The size of the variable in bytes. /// /// \param[in] alignment /// The required alignment of the variable in bytes. /// /// \return /// True on success; false otherwise. bool AddValueToStruct(const clang::NamedDecl *decl, ConstString name, llvm::Value *value, size_t size, lldb::offset_t alignment); /// [Used by IRForTarget] Finalize the struct, laying out the position of /// each object in it. /// /// \return /// True on success; false otherwise. bool DoStructLayout(); /// [Used by IRForTarget] Get general information about the laid-out struct /// after DoStructLayout() has been called. /// /// \param[out] num_elements /// The number of elements in the struct. /// /// \param[out] size /// The size of the struct, in bytes. /// /// \param[out] alignment /// The alignment of the struct, in bytes. /// /// \return /// True if the information could be retrieved; false otherwise. bool GetStructInfo(uint32_t &num_elements, size_t &size, lldb::offset_t &alignment); /// [Used by IRForTarget] Get specific information about one field of the /// laid-out struct after DoStructLayout() has been called. /// /// \param[out] decl /// The parsed Decl for the field, as generated by ClangASTSource /// on ClangExpressionDeclMap's behalf. In the case of the result /// value, this will have the name $__lldb_result even if the /// result value ends up having the name $1. This is an /// implementation detail of IRForTarget. /// /// \param[out] value /// The IR value for the field (usually a GlobalVariable). In /// the case of the result value, this will have the correct /// name ($1, for instance). This is an implementation detail /// of IRForTarget. /// /// \param[out] offset /// The offset of the field from the beginning of the struct. /// As long as the struct is aligned according to its required /// alignment, this offset will align the field correctly. /// /// \param[out] name /// The name of the field as used in materialization. /// /// \param[in] index /// The index of the field about which information is requested. /// /// \return /// True if the information could be retrieved; false otherwise. bool GetStructElement(const clang::NamedDecl *&decl, llvm::Value *&value, lldb::offset_t &offset, ConstString &name, uint32_t index); /// [Used by IRForTarget] Get information about a function given its Decl. /// /// \param[in] decl /// The parsed Decl for the Function, as generated by ClangASTSource /// on ClangExpressionDeclMap's behalf. /// /// \param[out] ptr /// The absolute address of the function in the target. /// /// \return /// True if the information could be retrieved; false otherwise. bool GetFunctionInfo(const clang::NamedDecl *decl, uint64_t &ptr); /// [Used by IRForTarget] Get the address of a symbol given nothing but its /// name. /// /// \param[in] target /// The target to find the symbol in. If not provided, /// then the current parsing context's Target. /// /// \param[in] process /// The process to use. For Objective-C symbols, the process's /// Objective-C language runtime may be queried if the process /// is non-NULL. /// /// \param[in] name /// The name of the symbol. /// /// \param[in] module /// The module to limit the search to. This can be NULL /// /// \return /// Valid load address for the symbol lldb::addr_t GetSymbolAddress(Target &target, Process *process, ConstString name, lldb::SymbolType symbol_type, Module *module = nullptr); lldb::addr_t GetSymbolAddress(ConstString name, lldb::SymbolType symbol_type); struct TargetInfo { lldb::ByteOrder byte_order; size_t address_byte_size; TargetInfo() : byte_order(lldb::eByteOrderInvalid), address_byte_size(0) {} bool IsValid() { return (byte_order != lldb::eByteOrderInvalid && address_byte_size != 0); } }; TargetInfo GetTargetInfo(); /// [Used by ClangASTSource] Find all entities matching a given name, using /// a NameSearchContext to make Decls for them. /// /// \param[in] context /// The NameSearchContext that can construct Decls for this name. void FindExternalVisibleDecls(NameSearchContext &context) override; /// Find all entities matching a given name in a given module/namespace, /// using a NameSearchContext to make Decls for them. /// /// \param[in] context /// The NameSearchContext that can construct Decls for this name. /// /// \param[in] module /// If non-NULL, the module to query. /// /// \param[in] namespace_decl /// If valid and module is non-NULL, the parent namespace. void FindExternalVisibleDecls(NameSearchContext &context, lldb::ModuleSP module, const CompilerDeclContext &namespace_decl); protected: /// Retrieves the declaration with the given name from the storage of /// persistent declarations. /// /// \return /// A persistent decl with the given name or a nullptr. virtual clang::NamedDecl *GetPersistentDecl(ConstString name); private: ExpressionVariableList m_found_entities; ///< All entities that were looked up for the parser. ExpressionVariableList m_struct_members; ///< All entities that need to be placed in the struct. bool m_keep_result_in_memory; ///< True if result persistent variables ///generated by this expression should stay in ///memory. Materializer::PersistentVariableDelegate *m_result_delegate; ///< If non-NULL, used to report expression results to ///ClangUserExpression. ValueObject *m_ctx_obj; ///< If not empty, then expression is ///evaluated in context of this object. ///For details see the comment to ///`UserExpression::Evaluate`. /// The following values should not live beyond parsing class ParserVars { public: ParserVars() {} Target *GetTarget() { if (m_exe_ctx.GetTargetPtr()) return m_exe_ctx.GetTargetPtr(); else if (m_sym_ctx.target_sp) return m_sym_ctx.target_sp.get(); return nullptr; } ExecutionContext m_exe_ctx; ///< The execution context to use when parsing. SymbolContext m_sym_ctx; ///< The symbol context to use in finding variables ///and types. ClangPersistentVariables *m_persistent_vars = nullptr; ///< The persistent variables for the process. bool m_enable_lookups = false; ///< Set to true during parsing if we have ///found the first "$__lldb" name. TargetInfo m_target_info; ///< Basic information about the target. Materializer *m_materializer = nullptr; ///< If non-NULL, the materializer ///to use when reporting used ///variables. clang::ASTConsumer *m_code_gen = nullptr; ///< If non-NULL, a code generator ///that receives new top-level ///functions. DiagnosticManager *m_diagnostics = nullptr; private: ParserVars(const ParserVars &) = delete; const ParserVars &operator=(const ParserVars &) = delete; }; std::unique_ptr m_parser_vars; /// Activate parser-specific variables void EnableParserVars() { if (!m_parser_vars.get()) m_parser_vars = std::make_unique(); } /// Deallocate parser-specific variables void DisableParserVars() { m_parser_vars.reset(); } /// The following values contain layout information for the materialized /// struct, but are not specific to a single materialization struct StructVars { StructVars() : m_struct_alignment(0), m_struct_size(0), m_struct_laid_out(false), m_result_name(), m_object_pointer_type(nullptr, nullptr) {} lldb::offset_t m_struct_alignment; ///< The alignment of the struct in bytes. size_t m_struct_size; ///< The size of the struct in bytes. bool m_struct_laid_out; ///< True if the struct has been laid out and the ///layout is valid (that is, no new fields have been ///added since). ConstString m_result_name; ///< The name of the result variable ($1, for example) TypeFromUser m_object_pointer_type; ///< The type of the "this" variable, if ///one exists }; std::unique_ptr m_struct_vars; /// Activate struct variables void EnableStructVars() { if (!m_struct_vars.get()) m_struct_vars.reset(new struct StructVars); } /// Deallocate struct variables void DisableStructVars() { m_struct_vars.reset(); } /// Get this parser's ID for use in extracting parser- and JIT-specific data /// from persistent variables. uint64_t GetParserID() { return (uint64_t) this; } /// Should be called on all copied functions. void MaybeRegisterFunctionBody(clang::FunctionDecl *copied_function_decl); /// Searches the persistent decls of the target for entities with the /// given name. /// /// \param[in] context /// The NameSearchContext that can construct Decls for this name. /// /// \param[in] name /// The name of the entities that need to be found. void SearchPersistenDecls(NameSearchContext &context, const ConstString name); /// Handles looking up $__lldb_class which requires special treatment. /// /// \param[in] context /// The NameSearchContext that can construct Decls for this name. void LookUpLldbClass(NameSearchContext &context); /// Handles looking up $__lldb_objc_class which requires special treatment. /// /// \param[in] context /// The NameSearchContext that can construct Decls for this name. void LookUpLldbObjCClass(NameSearchContext &context); /// Handles looking up the synthetic namespace that contains our local /// variables for the current frame. /// /// \param[in] sym_ctx /// The current SymbolContext of this frame. /// /// \param[in] name_context /// The NameSearchContext that can construct Decls for this name. void LookupLocalVarNamespace(SymbolContext &sym_ctx, NameSearchContext &name_context); /// Lookup entities in the ClangModulesDeclVendor. /// \param[in] context /// The NameSearchContext that can construct Decls for this name. /// /// \param[in] name /// The name of the entities that need to be found. void LookupInModulesDeclVendor(NameSearchContext &context, ConstString name); /// Looks up a local variable. /// /// \param[in] context /// The NameSearchContext that can construct Decls for this name. /// /// \param[in] name /// The name of the entities that need to be found. /// /// \param[in] sym_ctx /// The current SymbolContext of this frame. /// /// \param[in] namespace_decl /// The parent namespace if there is one. /// /// \return /// True iff a local variable was found. bool LookupLocalVariable(NameSearchContext &context, ConstString name, SymbolContext &sym_ctx, const CompilerDeclContext &namespace_decl); /// Searches for functions in the given SymbolContextList. /// /// \param[in] sc_list /// The SymbolContextList to search. /// /// \param[in] frame_decl_context /// The current DeclContext of the current frame. /// /// \return /// A SymbolContextList with any found functions in the front and /// any unknown SymbolContexts which are not functions in the back. /// The SymbolContexts for the functions are ordered by how close they are /// to the DeclContext for the given frame DeclContext. SymbolContextList SearchFunctionsInSymbolContexts( const SymbolContextList &sc_list, const CompilerDeclContext &frame_decl_context); /// Looks up a function. /// /// \param[in] context /// The NameSearchContext that can construct Decls for this name. /// /// \param[in] module_sp /// If non-NULL, the module to query. /// /// \param[in] name /// The name of the function that should be find. /// /// \param[in] namespace_decl /// If valid and module is non-NULL, the parent namespace. void LookupFunction(NameSearchContext &context, lldb::ModuleSP module_sp, ConstString name, const CompilerDeclContext &namespace_decl); /// Given a target, find a variable that matches the given name and type. /// /// \param[in] target /// The target to use as a basis for finding the variable. /// /// \param[in] module /// If non-NULL, the module to search. /// /// \param[in] name /// The name as a plain C string. /// /// \param[in] namespace_decl /// If non-NULL and module is non-NULL, the parent namespace. /// /// \return /// The LLDB Variable found, or NULL if none was found. lldb::VariableSP FindGlobalVariable(Target &target, lldb::ModuleSP &module, ConstString name, const CompilerDeclContext &namespace_decl); /// Get the value of a variable in a given execution context and return the /// associated Types if needed. /// /// \param[in] var /// The variable to evaluate. /// /// \param[out] var_location /// The variable location value to fill in /// /// \param[out] found_type /// The type of the found value, as it was found in the user process. /// This is only useful when the variable is being inspected on behalf /// of the parser, hence the default. /// /// \param[out] parser_type /// The type of the found value, as it was copied into the parser's /// AST context. This is only useful when the variable is being /// inspected on behalf of the parser, hence the default. /// /// \return /// Return true if the value was successfully filled in. bool GetVariableValue(lldb::VariableSP &var, lldb_private::Value &var_location, TypeFromUser *found_type = nullptr, TypeFromParser *parser_type = nullptr); /// Use the NameSearchContext to generate a Decl for the given LLDB /// Variable, and put it in the Tuple list. /// /// \param[in] context /// The NameSearchContext to use when constructing the Decl. /// /// \param[in] var /// The LLDB Variable that needs a Decl. /// /// \param[in] valobj /// The LLDB ValueObject for that variable. void AddOneVariable(NameSearchContext &context, lldb::VariableSP var, lldb::ValueObjectSP valobj); /// Use the NameSearchContext to generate a Decl for the given persistent /// variable, and put it in the list of found entities. /// /// \param[in] context /// The NameSearchContext to use when constructing the Decl. /// /// \param[in] pvar_sp /// The persistent variable that needs a Decl. void AddOneVariable(NameSearchContext &context, lldb::ExpressionVariableSP &pvar_sp); /// Use the NameSearchContext to generate a Decl for the given LLDB symbol /// (treated as a variable), and put it in the list of found entities. void AddOneGenericVariable(NameSearchContext &context, const Symbol &symbol); /// Use the NameSearchContext to generate a Decl for the given function. /// (Functions are not placed in the Tuple list.) Can handle both fully /// typed functions and generic functions. /// /// \param[in] context /// The NameSearchContext to use when constructing the Decl. /// /// \param[in] fun /// The Function that needs to be created. If non-NULL, this is /// a fully-typed function. /// /// \param[in] sym /// The Symbol that corresponds to a function that needs to be /// created with generic type (unitptr_t foo(...)). void AddOneFunction(NameSearchContext &context, Function *fun, Symbol *sym); /// Use the NameSearchContext to generate a Decl for the given register. /// /// \param[in] context /// The NameSearchContext to use when constructing the Decl. /// /// \param[in] reg_info /// The information corresponding to that register. void AddOneRegister(NameSearchContext &context, const RegisterInfo *reg_info); /// Use the NameSearchContext to generate a Decl for the given type. (Types /// are not placed in the Tuple list.) /// /// \param[in] context /// The NameSearchContext to use when constructing the Decl. /// /// \param[in] type /// The type that needs to be created. void AddOneType(NameSearchContext &context, const TypeFromUser &type); /// Adds the class in which the expression is evaluated to the lookup and /// prepares the class to be used as a context for expression evaluation (for /// example, it creates a fake member function that will contain the /// expression LLDB is trying to evaluate). /// /// \param[in] context /// The NameSearchContext to which the class should be added as a lookup /// result. /// /// \param[in] type /// The type of the class that serves as the evaluation context. void AddContextClassType(NameSearchContext &context, const TypeFromUser &type); /// Move a type out of the current ASTContext into another, but make sure to /// export all components of the type also. /// /// \param[in] target /// The TypeSystemClang to move to. /// \param[in] source /// The TypeSystemClang to move from. This is assumed to be going away. /// \param[in] parser_type /// The type as it appears in the source context. /// /// \return /// Returns the moved type, or an empty type if there was a problem. TypeFromUser DeportType(TypeSystemClang &target, TypeSystemClang &source, TypeFromParser parser_type); TypeSystemClang *GetTypeSystemClang(); }; } // namespace lldb_private #endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONDECLMAP_H