//===-- ClangExpressionDeclMap.h --------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef liblldb_ClangExpressionDeclMap_h_ #define liblldb_ClangExpressionDeclMap_h_ // C Includes #include #include // C++ Includes #include // Other libraries and framework includes // Project includes #include "llvm/ADT/APInt.h" #include "llvm/ADT/DenseMap.h" #include "clang/AST/Decl.h" #include "lldb/lldb-public.h" #include "lldb/Core/ClangForward.h" #include "lldb/Core/Value.h" #include "lldb/Expression/ClangASTSource.h" #include "lldb/Expression/ClangExpressionVariable.h" #include "lldb/Expression/Materializer.h" #include "lldb/Symbol/TaggedASTType.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Target/ExecutionContext.h" namespace lldb_private { //---------------------------------------------------------------------- /// @class ClangExpressionDeclMap ClangExpressionDeclMap.h "lldb/Expression/ClangExpressionDeclMap.h" /// @brief 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] exe_ctx /// The execution context to use when parsing. //------------------------------------------------------------------ ClangExpressionDeclMap (bool keep_result_in_memory, ExecutionContext &exe_ctx); //------------------------------------------------------------------ /// Destructor //------------------------------------------------------------------ ~ClangExpressionDeclMap (); //------------------------------------------------------------------ /// 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); //------------------------------------------------------------------ /// [Used by ClangExpressionParser] For each variable that had an unknown /// type at the beginning of parsing, determine its final type now. /// /// @return /// True on success; false otherwise. //------------------------------------------------------------------ bool ResolveUnknownTypes(); //------------------------------------------------------------------ /// 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, const 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, const ConstString &name, llvm::Value *value, size_t size, off_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, off_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, off_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 function given nothing /// but its name. Some functions are needed but didn't get Decls made /// during parsing -- specifically, sel_registerName is never called /// in the generated IR but we need to call it nonetheless. /// /// @param[in] name /// The name of the function. /// /// @param[out] ptr /// The absolute address of the function in the target. /// /// @return /// True if the address could be retrieved; false otherwise. //------------------------------------------------------------------ bool GetFunctionAddress (const ConstString &name, 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. /// /// @return /// Valid load address for the symbol //------------------------------------------------------------------ lldb::addr_t GetSymbolAddress (Target &target, Process *process, const ConstString &name, lldb::SymbolType symbol_type); lldb::addr_t GetSymbolAddress (const ConstString &name, lldb::SymbolType symbol_type); //------------------------------------------------------------------ /// [Used by IRInterpreter] Get basic target information. /// /// @param[out] byte_order /// The byte order of the target. /// /// @param[out] address_byte_size /// The size of a pointer in bytes. /// /// @return /// True if the information could be determined; false /// otherwise. //------------------------------------------------------------------ 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. /// /// @return /// True on success; false otherwise. //------------------------------------------------------------------ void FindExternalVisibleDecls (NameSearchContext &context); //------------------------------------------------------------------ /// 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. /// /// @param[in] name /// The name as a plain C string. The NameSearchContext contains /// a DeclarationName for the name so at first the name may seem /// redundant, but ClangExpressionDeclMap operates in RTTI land so /// it can't access DeclarationName. /// /// @param[in] current_id /// The ID for the current FindExternalVisibleDecls invocation, /// for logging purposes. /// /// @return /// True on success; false otherwise. //------------------------------------------------------------------ void FindExternalVisibleDecls (NameSearchContext &context, lldb::ModuleSP module, ClangNamespaceDecl &namespace_decl, unsigned int current_id); private: ClangExpressionVariableList m_found_entities; ///< All entities that were looked up for the parser. ClangExpressionVariableList 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. //---------------------------------------------------------------------- /// The following values should not live beyond parsing //---------------------------------------------------------------------- class ParserVars { public: ParserVars(ClangExpressionDeclMap &decl_map) : m_exe_ctx(), m_sym_ctx(), m_persistent_vars(NULL), m_enable_lookups(false), m_materializer(NULL), m_decl_map(decl_map) { } Target * GetTarget() { if (m_exe_ctx.GetTargetPtr()) return m_exe_ctx.GetTargetPtr(); else if (m_sym_ctx.target_sp) m_sym_ctx.target_sp.get(); return NULL; } 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; ///< The persistent variables for the process. bool m_enable_lookups; ///< 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; ///< If non-NULL, the materializer to use when reporting used variables. private: ClangExpressionDeclMap &m_decl_map; DISALLOW_COPY_AND_ASSIGN (ParserVars); }; std::unique_ptr m_parser_vars; //---------------------------------------------------------------------- /// Activate parser-specific variables //---------------------------------------------------------------------- void EnableParserVars() { if (!m_parser_vars.get()) m_parser_vars.reset(new ParserVars(*this)); } //---------------------------------------------------------------------- /// 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(NULL, NULL) { } off_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; } //------------------------------------------------------------------ /// Given a target, find a data symbol that has the given name. /// /// @param[in] target /// The target to use as the basis for the search. /// /// @param[in] name /// The name as a plain C string. /// /// @return /// The LLDB Symbol found, or NULL if none was found. //--------------------------------------------------------- const Symbol * FindGlobalDataSymbol (Target &target, const ConstString &name); //------------------------------------------------------------------ /// 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. /// /// @param[in] type /// The required type for the variable. This function may be called /// during parsing, in which case we don't know its type; hence the /// default. /// /// @return /// The LLDB Variable found, or NULL if none was found. //------------------------------------------------------------------ lldb::VariableSP FindGlobalVariable (Target &target, lldb::ModuleSP &module, const ConstString &name, ClangNamespaceDecl *namespace_decl, TypeFromUser *type = NULL); //------------------------------------------------------------------ /// 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. /// /// @param[in] decl /// The Decl to be looked up. /// /// @return /// Return true if the value was successfully filled in. //------------------------------------------------------------------ bool GetVariableValue (lldb::VariableSP &var, lldb_private::Value &var_location, TypeFromUser *found_type = NULL, TypeFromParser *parser_type = NULL); //------------------------------------------------------------------ /// 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, unsigned int current_id); //------------------------------------------------------------------ /// 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 /// The persistent variable that needs a Decl. /// /// @param[in] current_id /// The ID of the current invocation of FindExternalVisibleDecls /// for logging purposes. //------------------------------------------------------------------ void AddOneVariable (NameSearchContext &context, lldb::ClangExpressionVariableSP &pvar_sp, unsigned int current_id); //------------------------------------------------------------------ /// 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. /// /// @param[in] context /// The NameSearchContext to use when constructing the Decl. /// /// @param[in] var /// The LLDB Variable that needs a Decl. //------------------------------------------------------------------ void AddOneGenericVariable (NameSearchContext &context, const Symbol &symbol, unsigned int current_id); //------------------------------------------------------------------ /// 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, unsigned int current_id); //------------------------------------------------------------------ /// 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, unsigned int current_id); //------------------------------------------------------------------ /// 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, TypeFromUser &type, unsigned int current_id); //------------------------------------------------------------------ /// Copy a C++ class type into the parser's AST context and add a /// member function declaration to it for the expression. /// /// @param[in] type /// The type that needs to be created. //------------------------------------------------------------------ TypeFromParser CopyClassType(TypeFromUser &type, unsigned int current_id); }; } // namespace lldb_private #endif // liblldb_ClangExpressionDeclMap_h_