| //===-- ClangExpressionDeclMap.cpp -----------------------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "ClangExpressionDeclMap.h" |
| |
| #include "ASTDumper.h" |
| #include "ClangASTSource.h" |
| #include "ClangModulesDeclVendor.h" |
| #include "ClangPersistentVariables.h" |
| |
| #include "lldb/Core/Address.h" |
| #include "lldb/Core/Module.h" |
| #include "lldb/Core/ModuleSpec.h" |
| #include "lldb/Core/RegisterValue.h" |
| #include "lldb/Core/ValueObjectConstResult.h" |
| #include "lldb/Core/ValueObjectVariable.h" |
| #include "lldb/Expression/Materializer.h" |
| #include "lldb/Symbol/ClangASTContext.h" |
| #include "lldb/Symbol/CompileUnit.h" |
| #include "lldb/Symbol/CompilerDecl.h" |
| #include "lldb/Symbol/CompilerDeclContext.h" |
| #include "lldb/Symbol/Function.h" |
| #include "lldb/Symbol/ObjectFile.h" |
| #include "lldb/Symbol/SymbolContext.h" |
| #include "lldb/Symbol/SymbolFile.h" |
| #include "lldb/Symbol/SymbolVendor.h" |
| #include "lldb/Symbol/Type.h" |
| #include "lldb/Symbol/TypeList.h" |
| #include "lldb/Symbol/Variable.h" |
| #include "lldb/Symbol/VariableList.h" |
| #include "lldb/Target/CPPLanguageRuntime.h" |
| #include "lldb/Target/ExecutionContext.h" |
| #include "lldb/Target/ObjCLanguageRuntime.h" |
| #include "lldb/Target/Process.h" |
| #include "lldb/Target/RegisterContext.h" |
| #include "lldb/Target/StackFrame.h" |
| #include "lldb/Target/Target.h" |
| #include "lldb/Target/Thread.h" |
| #include "lldb/Utility/Endian.h" |
| #include "lldb/Utility/Log.h" |
| #include "lldb/Utility/Status.h" |
| #include "lldb/lldb-private.h" |
| #include "clang/AST/ASTConsumer.h" |
| #include "clang/AST/ASTContext.h" |
| #include "clang/AST/ASTImporter.h" |
| #include "clang/AST/Decl.h" |
| #include "clang/AST/DeclarationName.h" |
| #include "clang/AST/RecursiveASTVisitor.h" |
| |
| #include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" |
| |
| using namespace lldb; |
| using namespace lldb_private; |
| using namespace clang; |
| |
| namespace { |
| const char *g_lldb_local_vars_namespace_cstr = "$__lldb_local_vars"; |
| } // anonymous namespace |
| |
| ClangExpressionDeclMap::ClangExpressionDeclMap( |
| bool keep_result_in_memory, |
| Materializer::PersistentVariableDelegate *result_delegate, |
| ExecutionContext &exe_ctx) |
| : ClangASTSource(exe_ctx.GetTargetSP()), m_found_entities(), |
| m_struct_members(), m_keep_result_in_memory(keep_result_in_memory), |
| m_result_delegate(result_delegate), m_parser_vars(), m_struct_vars() { |
| EnableStructVars(); |
| } |
| |
| ClangExpressionDeclMap::~ClangExpressionDeclMap() { |
| // Note: The model is now that the parser's AST context and all associated |
| // data does not vanish until the expression has been executed. This means |
| // that valuable lookup data (like namespaces) doesn't vanish, but |
| |
| DidParse(); |
| DisableStructVars(); |
| } |
| |
| bool ClangExpressionDeclMap::WillParse(ExecutionContext &exe_ctx, |
| Materializer *materializer) { |
| ClangASTMetrics::ClearLocalCounters(); |
| |
| EnableParserVars(); |
| m_parser_vars->m_exe_ctx = exe_ctx; |
| |
| Target *target = exe_ctx.GetTargetPtr(); |
| if (exe_ctx.GetFramePtr()) |
| m_parser_vars->m_sym_ctx = |
| exe_ctx.GetFramePtr()->GetSymbolContext(lldb::eSymbolContextEverything); |
| else if (exe_ctx.GetThreadPtr() && |
| exe_ctx.GetThreadPtr()->GetStackFrameAtIndex(0)) |
| m_parser_vars->m_sym_ctx = |
| exe_ctx.GetThreadPtr()->GetStackFrameAtIndex(0)->GetSymbolContext( |
| lldb::eSymbolContextEverything); |
| else if (exe_ctx.GetProcessPtr()) { |
| m_parser_vars->m_sym_ctx.Clear(true); |
| m_parser_vars->m_sym_ctx.target_sp = exe_ctx.GetTargetSP(); |
| } else if (target) { |
| m_parser_vars->m_sym_ctx.Clear(true); |
| m_parser_vars->m_sym_ctx.target_sp = exe_ctx.GetTargetSP(); |
| } |
| |
| if (target) { |
| m_parser_vars->m_persistent_vars = llvm::cast<ClangPersistentVariables>( |
| target->GetPersistentExpressionStateForLanguage(eLanguageTypeC)); |
| |
| if (!target->GetScratchClangASTContext()) |
| return false; |
| } |
| |
| m_parser_vars->m_target_info = GetTargetInfo(); |
| m_parser_vars->m_materializer = materializer; |
| |
| return true; |
| } |
| |
| void ClangExpressionDeclMap::InstallCodeGenerator( |
| clang::ASTConsumer *code_gen) { |
| assert(m_parser_vars); |
| m_parser_vars->m_code_gen = code_gen; |
| } |
| |
| void ClangExpressionDeclMap::DidParse() { |
| Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); |
| |
| if (log) |
| ClangASTMetrics::DumpCounters(log); |
| |
| if (m_parser_vars.get()) { |
| for (size_t entity_index = 0, num_entities = m_found_entities.GetSize(); |
| entity_index < num_entities; ++entity_index) { |
| ExpressionVariableSP var_sp( |
| m_found_entities.GetVariableAtIndex(entity_index)); |
| if (var_sp) |
| llvm::cast<ClangExpressionVariable>(var_sp.get()) |
| ->DisableParserVars(GetParserID()); |
| } |
| |
| for (size_t pvar_index = 0, |
| num_pvars = m_parser_vars->m_persistent_vars->GetSize(); |
| pvar_index < num_pvars; ++pvar_index) { |
| ExpressionVariableSP pvar_sp( |
| m_parser_vars->m_persistent_vars->GetVariableAtIndex(pvar_index)); |
| if (ClangExpressionVariable *clang_var = |
| llvm::dyn_cast<ClangExpressionVariable>(pvar_sp.get())) |
| clang_var->DisableParserVars(GetParserID()); |
| } |
| |
| DisableParserVars(); |
| } |
| } |
| |
| // Interface for IRForTarget |
| |
| ClangExpressionDeclMap::TargetInfo ClangExpressionDeclMap::GetTargetInfo() { |
| assert(m_parser_vars.get()); |
| |
| TargetInfo ret; |
| |
| ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx; |
| |
| Process *process = exe_ctx.GetProcessPtr(); |
| if (process) { |
| ret.byte_order = process->GetByteOrder(); |
| ret.address_byte_size = process->GetAddressByteSize(); |
| } else { |
| Target *target = exe_ctx.GetTargetPtr(); |
| if (target) { |
| ret.byte_order = target->GetArchitecture().GetByteOrder(); |
| ret.address_byte_size = target->GetArchitecture().GetAddressByteSize(); |
| } |
| } |
| |
| return ret; |
| } |
| |
| namespace { |
| /// This class walks an AST and ensures that all DeclContexts defined inside the |
| /// current source file are properly complete. |
| /// |
| /// This is used to ensure that persistent types defined in the current source |
| /// file migrate completely to the persistent AST context before they are |
| /// reused. If that didn't happen, it would be impoossible to complete them |
| /// because their origin would be gone. |
| /// |
| /// The stragtegy used by this class is to check the SourceLocation (to be |
| /// specific, the FileID) and see if it's the FileID for the current expression. |
| /// Alternate strategies could include checking whether an ExternalASTMerger, |
| /// set up to not have the current context as a source, can find an original for |
| /// the type. |
| class Completer : public clang::RecursiveASTVisitor<Completer> { |
| private: |
| clang::ASTImporter &m_exporter; /// Used to import Decl contents |
| clang::FileID m_file; /// The file that's going away |
| llvm::DenseSet<clang::Decl *> m_completed; /// Visited Decls, to avoid cycles |
| |
| bool ImportAndCheckCompletable(clang::Decl *decl) { |
| (void)m_exporter.Import(decl); |
| if (m_completed.count(decl)) |
| return false; |
| if (!llvm::isa<DeclContext>(decl)) |
| return false; |
| const clang::SourceLocation loc = decl->getLocation(); |
| if (!loc.isValid()) |
| return false; |
| const clang::FileID file = |
| m_exporter.getFromContext().getSourceManager().getFileID(loc); |
| if (file != m_file) |
| return false; |
| // We are assuming the Decl was parsed in this very expression, so it |
| // should not have external storage. |
| lldbassert(!llvm::cast<DeclContext>(decl)->hasExternalLexicalStorage()); |
| return true; |
| } |
| |
| void Complete(clang::Decl *decl) { |
| m_completed.insert(decl); |
| auto *decl_context = llvm::cast<DeclContext>(decl); |
| (void)m_exporter.Import(decl); |
| m_exporter.CompleteDecl(decl); |
| for (Decl *child : decl_context->decls()) |
| if (ImportAndCheckCompletable(child)) |
| Complete(child); |
| } |
| |
| void MaybeComplete(clang::Decl *decl) { |
| if (ImportAndCheckCompletable(decl)) |
| Complete(decl); |
| } |
| |
| public: |
| Completer(clang::ASTImporter &exporter, clang::FileID file) |
| : m_exporter(exporter), m_file(file) {} |
| |
| // Implements the RecursiveASTVisitor's core API. It is called on each Decl |
| // that the RecursiveASTVisitor encounters, and returns true if the traversal |
| // should continue. |
| bool VisitDecl(clang::Decl *decl) { |
| MaybeComplete(decl); |
| return true; |
| } |
| }; |
| } |
| |
| static void CompleteAllDeclContexts(clang::ASTImporter &exporter, |
| clang::FileID file, |
| clang::QualType root) { |
| clang::QualType canonical_type = root.getCanonicalType(); |
| if (clang::TagDecl *tag_decl = canonical_type->getAsTagDecl()) { |
| Completer(exporter, file).TraverseDecl(tag_decl); |
| } else if (auto interface_type = llvm::dyn_cast<ObjCInterfaceType>( |
| canonical_type.getTypePtr())) { |
| Completer(exporter, file).TraverseDecl(interface_type->getDecl()); |
| } else { |
| Completer(exporter, file).TraverseType(canonical_type); |
| } |
| } |
| |
| static clang::QualType ExportAllDeclaredTypes( |
| clang::ExternalASTMerger &merger, |
| clang::ASTContext &source, clang::FileManager &source_file_manager, |
| const clang::ExternalASTMerger::OriginMap &source_origin_map, |
| clang::FileID file, clang::QualType root) { |
| clang::ExternalASTMerger::ImporterSource importer_source = |
| { source, source_file_manager, source_origin_map }; |
| merger.AddSources(importer_source); |
| clang::ASTImporter &exporter = merger.ImporterForOrigin(source); |
| CompleteAllDeclContexts(exporter, file, root); |
| clang::QualType ret = exporter.Import(root); |
| merger.RemoveSources(importer_source); |
| return ret; |
| } |
| |
| TypeFromUser ClangExpressionDeclMap::DeportType(ClangASTContext &target, |
| ClangASTContext &source, |
| TypeFromParser parser_type) { |
| assert (&target == m_target->GetScratchClangASTContext()); |
| assert ((TypeSystem*)&source == parser_type.GetTypeSystem()); |
| assert (source.getASTContext() == m_ast_context); |
| |
| if (m_ast_importer_sp) { |
| return TypeFromUser(m_ast_importer_sp->DeportType( |
| target.getASTContext(), source.getASTContext(), |
| parser_type.GetOpaqueQualType()), |
| &target); |
| } else if (m_merger_up) { |
| clang::FileID source_file = |
| source.getASTContext()->getSourceManager().getFileID( |
| source.getASTContext()->getTranslationUnitDecl()->getLocation()); |
| auto scratch_ast_context = static_cast<ClangASTContextForExpressions*>( |
| m_target->GetScratchClangASTContext()); |
| clang::QualType exported_type = ExportAllDeclaredTypes( |
| scratch_ast_context->GetMergerUnchecked(), |
| *source.getASTContext(), *source.getFileManager(), |
| m_merger_up->GetOrigins(), |
| source_file, |
| clang::QualType::getFromOpaquePtr(parser_type.GetOpaqueQualType())); |
| return TypeFromUser(exported_type.getAsOpaquePtr(), &target); |
| } else { |
| lldbassert(0 && "No mechanism for deporting a type!"); |
| return TypeFromUser(); |
| } |
| } |
| |
| bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, |
| const ConstString &name, |
| TypeFromParser parser_type, |
| bool is_result, |
| bool is_lvalue) { |
| assert(m_parser_vars.get()); |
| |
| ClangASTContext *ast = |
| llvm::dyn_cast_or_null<ClangASTContext>(parser_type.GetTypeSystem()); |
| if (ast == nullptr) |
| return false; |
| |
| if (m_parser_vars->m_materializer && is_result) { |
| Status err; |
| |
| ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx; |
| Target *target = exe_ctx.GetTargetPtr(); |
| if (target == nullptr) |
| return false; |
| |
| TypeFromUser user_type = |
| DeportType(*target->GetScratchClangASTContext(), *ast, parser_type); |
| |
| uint32_t offset = m_parser_vars->m_materializer->AddResultVariable( |
| user_type, is_lvalue, m_keep_result_in_memory, m_result_delegate, err); |
| |
| ClangExpressionVariable *var = new ClangExpressionVariable( |
| exe_ctx.GetBestExecutionContextScope(), name, user_type, |
| m_parser_vars->m_target_info.byte_order, |
| m_parser_vars->m_target_info.address_byte_size); |
| |
| m_found_entities.AddNewlyConstructedVariable(var); |
| |
| var->EnableParserVars(GetParserID()); |
| |
| ClangExpressionVariable::ParserVars *parser_vars = |
| var->GetParserVars(GetParserID()); |
| |
| parser_vars->m_named_decl = decl; |
| parser_vars->m_parser_type = parser_type; |
| |
| var->EnableJITVars(GetParserID()); |
| |
| ClangExpressionVariable::JITVars *jit_vars = var->GetJITVars(GetParserID()); |
| |
| jit_vars->m_offset = offset; |
| |
| return true; |
| } |
| |
| Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); |
| ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx; |
| Target *target = exe_ctx.GetTargetPtr(); |
| if (target == NULL) |
| return false; |
| |
| ClangASTContext *context(target->GetScratchClangASTContext()); |
| |
| TypeFromUser user_type = DeportType(*context, *ast, parser_type); |
| |
| if (!user_type.GetOpaqueQualType()) { |
| if (log) |
| log->Printf("Persistent variable's type wasn't copied successfully"); |
| return false; |
| } |
| |
| if (!m_parser_vars->m_target_info.IsValid()) |
| return false; |
| |
| ClangExpressionVariable *var = llvm::cast<ClangExpressionVariable>( |
| m_parser_vars->m_persistent_vars |
| ->CreatePersistentVariable( |
| exe_ctx.GetBestExecutionContextScope(), name, user_type, |
| m_parser_vars->m_target_info.byte_order, |
| m_parser_vars->m_target_info.address_byte_size) |
| .get()); |
| |
| if (!var) |
| return false; |
| |
| var->m_frozen_sp->SetHasCompleteType(); |
| |
| if (is_result) |
| var->m_flags |= ClangExpressionVariable::EVNeedsFreezeDry; |
| else |
| var->m_flags |= |
| ClangExpressionVariable::EVKeepInTarget; // explicitly-declared |
| // persistent variables should |
| // persist |
| |
| if (is_lvalue) { |
| var->m_flags |= ClangExpressionVariable::EVIsProgramReference; |
| } else { |
| var->m_flags |= ClangExpressionVariable::EVIsLLDBAllocated; |
| var->m_flags |= ClangExpressionVariable::EVNeedsAllocation; |
| } |
| |
| if (m_keep_result_in_memory) { |
| var->m_flags |= ClangExpressionVariable::EVKeepInTarget; |
| } |
| |
| if (log) |
| log->Printf("Created persistent variable with flags 0x%hx", var->m_flags); |
| |
| var->EnableParserVars(GetParserID()); |
| |
| ClangExpressionVariable::ParserVars *parser_vars = |
| var->GetParserVars(GetParserID()); |
| |
| parser_vars->m_named_decl = decl; |
| parser_vars->m_parser_type = parser_type; |
| |
| return true; |
| } |
| |
| bool ClangExpressionDeclMap::AddValueToStruct(const NamedDecl *decl, |
| const ConstString &name, |
| llvm::Value *value, size_t size, |
| lldb::offset_t alignment) { |
| assert(m_struct_vars.get()); |
| assert(m_parser_vars.get()); |
| |
| bool is_persistent_variable = false; |
| |
| Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); |
| |
| m_struct_vars->m_struct_laid_out = false; |
| |
| if (ClangExpressionVariable::FindVariableInList(m_struct_members, decl, |
| GetParserID())) |
| return true; |
| |
| ClangExpressionVariable *var(ClangExpressionVariable::FindVariableInList( |
| m_found_entities, decl, GetParserID())); |
| |
| if (!var) { |
| var = ClangExpressionVariable::FindVariableInList( |
| *m_parser_vars->m_persistent_vars, decl, GetParserID()); |
| is_persistent_variable = true; |
| } |
| |
| if (!var) |
| return false; |
| |
| if (log) |
| log->Printf("Adding value for (NamedDecl*)%p [%s - %s] to the structure", |
| static_cast<const void *>(decl), name.GetCString(), |
| var->GetName().GetCString()); |
| |
| // We know entity->m_parser_vars is valid because we used a parser variable |
| // to find it |
| |
| ClangExpressionVariable::ParserVars *parser_vars = |
| llvm::cast<ClangExpressionVariable>(var)->GetParserVars(GetParserID()); |
| |
| parser_vars->m_llvm_value = value; |
| |
| if (ClangExpressionVariable::JITVars *jit_vars = |
| llvm::cast<ClangExpressionVariable>(var)->GetJITVars(GetParserID())) { |
| // We already laid this out; do not touch |
| |
| if (log) |
| log->Printf("Already placed at 0x%llx", |
| (unsigned long long)jit_vars->m_offset); |
| } |
| |
| llvm::cast<ClangExpressionVariable>(var)->EnableJITVars(GetParserID()); |
| |
| ClangExpressionVariable::JITVars *jit_vars = |
| llvm::cast<ClangExpressionVariable>(var)->GetJITVars(GetParserID()); |
| |
| jit_vars->m_alignment = alignment; |
| jit_vars->m_size = size; |
| |
| m_struct_members.AddVariable(var->shared_from_this()); |
| |
| if (m_parser_vars->m_materializer) { |
| uint32_t offset = 0; |
| |
| Status err; |
| |
| if (is_persistent_variable) { |
| ExpressionVariableSP var_sp(var->shared_from_this()); |
| offset = m_parser_vars->m_materializer->AddPersistentVariable( |
| var_sp, nullptr, err); |
| } else { |
| if (const lldb_private::Symbol *sym = parser_vars->m_lldb_sym) |
| offset = m_parser_vars->m_materializer->AddSymbol(*sym, err); |
| else if (const RegisterInfo *reg_info = var->GetRegisterInfo()) |
| offset = m_parser_vars->m_materializer->AddRegister(*reg_info, err); |
| else if (parser_vars->m_lldb_var) |
| offset = m_parser_vars->m_materializer->AddVariable( |
| parser_vars->m_lldb_var, err); |
| } |
| |
| if (!err.Success()) |
| return false; |
| |
| if (log) |
| log->Printf("Placed at 0x%llx", (unsigned long long)offset); |
| |
| jit_vars->m_offset = |
| offset; // TODO DoStructLayout() should not change this. |
| } |
| |
| return true; |
| } |
| |
| bool ClangExpressionDeclMap::DoStructLayout() { |
| assert(m_struct_vars.get()); |
| |
| if (m_struct_vars->m_struct_laid_out) |
| return true; |
| |
| if (!m_parser_vars->m_materializer) |
| return false; |
| |
| m_struct_vars->m_struct_alignment = |
| m_parser_vars->m_materializer->GetStructAlignment(); |
| m_struct_vars->m_struct_size = |
| m_parser_vars->m_materializer->GetStructByteSize(); |
| m_struct_vars->m_struct_laid_out = true; |
| return true; |
| } |
| |
| bool ClangExpressionDeclMap::GetStructInfo(uint32_t &num_elements, size_t &size, |
| lldb::offset_t &alignment) { |
| assert(m_struct_vars.get()); |
| |
| if (!m_struct_vars->m_struct_laid_out) |
| return false; |
| |
| num_elements = m_struct_members.GetSize(); |
| size = m_struct_vars->m_struct_size; |
| alignment = m_struct_vars->m_struct_alignment; |
| |
| return true; |
| } |
| |
| bool ClangExpressionDeclMap::GetStructElement(const NamedDecl *&decl, |
| llvm::Value *&value, |
| lldb::offset_t &offset, |
| ConstString &name, |
| uint32_t index) { |
| assert(m_struct_vars.get()); |
| |
| if (!m_struct_vars->m_struct_laid_out) |
| return false; |
| |
| if (index >= m_struct_members.GetSize()) |
| return false; |
| |
| ExpressionVariableSP member_sp(m_struct_members.GetVariableAtIndex(index)); |
| |
| if (!member_sp) |
| return false; |
| |
| ClangExpressionVariable::ParserVars *parser_vars = |
| llvm::cast<ClangExpressionVariable>(member_sp.get()) |
| ->GetParserVars(GetParserID()); |
| ClangExpressionVariable::JITVars *jit_vars = |
| llvm::cast<ClangExpressionVariable>(member_sp.get()) |
| ->GetJITVars(GetParserID()); |
| |
| if (!parser_vars || !jit_vars || !member_sp->GetValueObject()) |
| return false; |
| |
| decl = parser_vars->m_named_decl; |
| value = parser_vars->m_llvm_value; |
| offset = jit_vars->m_offset; |
| name = member_sp->GetName(); |
| |
| return true; |
| } |
| |
| bool ClangExpressionDeclMap::GetFunctionInfo(const NamedDecl *decl, |
| uint64_t &ptr) { |
| ClangExpressionVariable *entity(ClangExpressionVariable::FindVariableInList( |
| m_found_entities, decl, GetParserID())); |
| |
| if (!entity) |
| return false; |
| |
| // We know m_parser_vars is valid since we searched for the variable by its |
| // NamedDecl |
| |
| ClangExpressionVariable::ParserVars *parser_vars = |
| entity->GetParserVars(GetParserID()); |
| |
| ptr = parser_vars->m_lldb_value.GetScalar().ULongLong(); |
| |
| return true; |
| } |
| |
| addr_t ClangExpressionDeclMap::GetSymbolAddress(Target &target, |
| Process *process, |
| const ConstString &name, |
| lldb::SymbolType symbol_type, |
| lldb_private::Module *module) { |
| SymbolContextList sc_list; |
| |
| if (module) |
| module->FindSymbolsWithNameAndType(name, symbol_type, sc_list); |
| else |
| target.GetImages().FindSymbolsWithNameAndType(name, symbol_type, sc_list); |
| |
| const uint32_t num_matches = sc_list.GetSize(); |
| addr_t symbol_load_addr = LLDB_INVALID_ADDRESS; |
| |
| for (uint32_t i = 0; |
| i < num_matches && |
| (symbol_load_addr == 0 || symbol_load_addr == LLDB_INVALID_ADDRESS); |
| i++) { |
| SymbolContext sym_ctx; |
| sc_list.GetContextAtIndex(i, sym_ctx); |
| |
| const Address sym_address = sym_ctx.symbol->GetAddress(); |
| |
| if (!sym_address.IsValid()) |
| continue; |
| |
| switch (sym_ctx.symbol->GetType()) { |
| case eSymbolTypeCode: |
| case eSymbolTypeTrampoline: |
| symbol_load_addr = sym_address.GetCallableLoadAddress(&target); |
| break; |
| |
| case eSymbolTypeResolver: |
| symbol_load_addr = sym_address.GetCallableLoadAddress(&target, true); |
| break; |
| |
| case eSymbolTypeReExported: { |
| ConstString reexport_name = sym_ctx.symbol->GetReExportedSymbolName(); |
| if (reexport_name) { |
| ModuleSP reexport_module_sp; |
| ModuleSpec reexport_module_spec; |
| reexport_module_spec.GetPlatformFileSpec() = |
| sym_ctx.symbol->GetReExportedSymbolSharedLibrary(); |
| if (reexport_module_spec.GetPlatformFileSpec()) { |
| reexport_module_sp = |
| target.GetImages().FindFirstModule(reexport_module_spec); |
| if (!reexport_module_sp) { |
| reexport_module_spec.GetPlatformFileSpec().GetDirectory().Clear(); |
| reexport_module_sp = |
| target.GetImages().FindFirstModule(reexport_module_spec); |
| } |
| } |
| symbol_load_addr = GetSymbolAddress( |
| target, process, sym_ctx.symbol->GetReExportedSymbolName(), |
| symbol_type, reexport_module_sp.get()); |
| } |
| } break; |
| |
| case eSymbolTypeData: |
| case eSymbolTypeRuntime: |
| case eSymbolTypeVariable: |
| case eSymbolTypeLocal: |
| case eSymbolTypeParam: |
| case eSymbolTypeInvalid: |
| case eSymbolTypeAbsolute: |
| case eSymbolTypeException: |
| case eSymbolTypeSourceFile: |
| case eSymbolTypeHeaderFile: |
| case eSymbolTypeObjectFile: |
| case eSymbolTypeCommonBlock: |
| case eSymbolTypeBlock: |
| case eSymbolTypeVariableType: |
| case eSymbolTypeLineEntry: |
| case eSymbolTypeLineHeader: |
| case eSymbolTypeScopeBegin: |
| case eSymbolTypeScopeEnd: |
| case eSymbolTypeAdditional: |
| case eSymbolTypeCompiler: |
| case eSymbolTypeInstrumentation: |
| case eSymbolTypeUndefined: |
| case eSymbolTypeObjCClass: |
| case eSymbolTypeObjCMetaClass: |
| case eSymbolTypeObjCIVar: |
| symbol_load_addr = sym_address.GetLoadAddress(&target); |
| break; |
| } |
| } |
| |
| if (symbol_load_addr == LLDB_INVALID_ADDRESS && process) { |
| ObjCLanguageRuntime *runtime = process->GetObjCLanguageRuntime(); |
| |
| if (runtime) { |
| symbol_load_addr = runtime->LookupRuntimeSymbol(name); |
| } |
| } |
| |
| return symbol_load_addr; |
| } |
| |
| addr_t ClangExpressionDeclMap::GetSymbolAddress(const ConstString &name, |
| lldb::SymbolType symbol_type) { |
| assert(m_parser_vars.get()); |
| |
| if (!m_parser_vars->m_exe_ctx.GetTargetPtr()) |
| return false; |
| |
| return GetSymbolAddress(m_parser_vars->m_exe_ctx.GetTargetRef(), |
| m_parser_vars->m_exe_ctx.GetProcessPtr(), name, |
| symbol_type); |
| } |
| |
| lldb::VariableSP ClangExpressionDeclMap::FindGlobalVariable( |
| Target &target, ModuleSP &module, const ConstString &name, |
| CompilerDeclContext *namespace_decl, TypeFromUser *type) { |
| VariableList vars; |
| |
| if (module && namespace_decl) |
| module->FindGlobalVariables(name, namespace_decl, -1, vars); |
| else |
| target.GetImages().FindGlobalVariables(name, -1, vars); |
| |
| if (vars.GetSize()) { |
| if (type) { |
| for (size_t i = 0; i < vars.GetSize(); ++i) { |
| VariableSP var_sp = vars.GetVariableAtIndex(i); |
| |
| if (ClangASTContext::AreTypesSame( |
| *type, var_sp->GetType()->GetFullCompilerType())) |
| return var_sp; |
| } |
| } else { |
| return vars.GetVariableAtIndex(0); |
| } |
| } |
| |
| return VariableSP(); |
| } |
| |
| ClangASTContext *ClangExpressionDeclMap::GetClangASTContext() { |
| StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr(); |
| if (frame == nullptr) |
| return nullptr; |
| |
| SymbolContext sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction | |
| lldb::eSymbolContextBlock); |
| if (sym_ctx.block == nullptr) |
| return nullptr; |
| |
| CompilerDeclContext frame_decl_context = sym_ctx.block->GetDeclContext(); |
| if (!frame_decl_context) |
| return nullptr; |
| |
| return llvm::dyn_cast_or_null<ClangASTContext>( |
| frame_decl_context.GetTypeSystem()); |
| } |
| |
| // Interface for ClangASTSource |
| |
| void ClangExpressionDeclMap::FindExternalVisibleDecls( |
| NameSearchContext &context) { |
| assert(m_ast_context); |
| |
| ClangASTMetrics::RegisterVisibleQuery(); |
| |
| const ConstString name(context.m_decl_name.getAsString().c_str()); |
| |
| Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); |
| |
| if (GetImportInProgress()) { |
| if (log && log->GetVerbose()) |
| log->Printf("Ignoring a query during an import"); |
| return; |
| } |
| |
| static unsigned int invocation_id = 0; |
| unsigned int current_id = invocation_id++; |
| |
| if (log) { |
| if (!context.m_decl_context) |
| log->Printf("ClangExpressionDeclMap::FindExternalVisibleDecls[%u] for " |
| "'%s' in a NULL DeclContext", |
| current_id, name.GetCString()); |
| else if (const NamedDecl *context_named_decl = |
| dyn_cast<NamedDecl>(context.m_decl_context)) |
| log->Printf("ClangExpressionDeclMap::FindExternalVisibleDecls[%u] for " |
| "'%s' in '%s'", |
| current_id, name.GetCString(), |
| context_named_decl->getNameAsString().c_str()); |
| else |
| log->Printf("ClangExpressionDeclMap::FindExternalVisibleDecls[%u] for " |
| "'%s' in a '%s'", |
| current_id, name.GetCString(), |
| context.m_decl_context->getDeclKindName()); |
| } |
| |
| if (const NamespaceDecl *namespace_context = |
| dyn_cast<NamespaceDecl>(context.m_decl_context)) { |
| if (namespace_context->getName().str() == |
| std::string(g_lldb_local_vars_namespace_cstr)) { |
| CompilerDeclContext compiler_decl_ctx( |
| GetClangASTContext(), const_cast<void *>(static_cast<const void *>( |
| context.m_decl_context))); |
| FindExternalVisibleDecls(context, lldb::ModuleSP(), compiler_decl_ctx, |
| current_id); |
| return; |
| } |
| |
| ClangASTImporter::NamespaceMapSP namespace_map = |
| m_ast_importer_sp |
| ? m_ast_importer_sp->GetNamespaceMap(namespace_context) |
| : ClangASTImporter::NamespaceMapSP(); |
| |
| if (!namespace_map) |
| return; |
| |
| if (log && log->GetVerbose()) |
| log->Printf(" CEDM::FEVD[%u] Inspecting (NamespaceMap*)%p (%d entries)", |
| current_id, static_cast<void *>(namespace_map.get()), |
| (int)namespace_map->size()); |
| |
| for (ClangASTImporter::NamespaceMap::iterator i = namespace_map->begin(), |
| e = namespace_map->end(); |
| i != e; ++i) { |
| if (log) |
| log->Printf(" CEDM::FEVD[%u] Searching namespace %s in module %s", |
| current_id, i->second.GetName().AsCString(), |
| i->first->GetFileSpec().GetFilename().GetCString()); |
| |
| FindExternalVisibleDecls(context, i->first, i->second, current_id); |
| } |
| } else if (isa<TranslationUnitDecl>(context.m_decl_context)) { |
| CompilerDeclContext namespace_decl; |
| |
| if (log) |
| log->Printf(" CEDM::FEVD[%u] Searching the root namespace", current_id); |
| |
| FindExternalVisibleDecls(context, lldb::ModuleSP(), namespace_decl, |
| current_id); |
| } |
| |
| ClangASTSource::FindExternalVisibleDecls(context); |
| } |
| |
| void ClangExpressionDeclMap::FindExternalVisibleDecls( |
| NameSearchContext &context, lldb::ModuleSP module_sp, |
| CompilerDeclContext &namespace_decl, unsigned int current_id) { |
| assert(m_ast_context); |
| |
| std::function<void(clang::FunctionDecl *)> MaybeRegisterFunctionBody = |
| [this](clang::FunctionDecl *copied_function_decl) { |
| if (copied_function_decl->getBody() && m_parser_vars->m_code_gen) { |
| DeclGroupRef decl_group_ref(copied_function_decl); |
| m_parser_vars->m_code_gen->HandleTopLevelDecl(decl_group_ref); |
| } |
| }; |
| |
| Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); |
| |
| SymbolContextList sc_list; |
| |
| const ConstString name(context.m_decl_name.getAsString().c_str()); |
| if (IgnoreName(name, false)) |
| return; |
| |
| // Only look for functions by name out in our symbols if the function doesn't |
| // start with our phony prefix of '$' |
| Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr(); |
| StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr(); |
| SymbolContext sym_ctx; |
| if (frame != nullptr) |
| sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction | |
| lldb::eSymbolContextBlock); |
| |
| // Try the persistent decls, which take precedence over all else. |
| if (!namespace_decl) { |
| do { |
| if (!target) |
| break; |
| |
| ClangASTContext *scratch_clang_ast_context = |
| target->GetScratchClangASTContext(); |
| |
| if (!scratch_clang_ast_context) |
| break; |
| |
| ASTContext *scratch_ast_context = |
| scratch_clang_ast_context->getASTContext(); |
| |
| if (!scratch_ast_context) |
| break; |
| |
| NamedDecl *persistent_decl = |
| m_parser_vars->m_persistent_vars->GetPersistentDecl(name); |
| |
| if (!persistent_decl) |
| break; |
| |
| Decl *parser_persistent_decl = CopyDecl(persistent_decl); |
| |
| if (!parser_persistent_decl) |
| break; |
| |
| NamedDecl *parser_named_decl = |
| dyn_cast<NamedDecl>(parser_persistent_decl); |
| |
| if (!parser_named_decl) |
| break; |
| |
| if (clang::FunctionDecl *parser_function_decl = |
| llvm::dyn_cast<clang::FunctionDecl>(parser_named_decl)) { |
| MaybeRegisterFunctionBody(parser_function_decl); |
| } |
| |
| if (log) |
| log->Printf(" CEDM::FEVD[%u] Found persistent decl %s", current_id, |
| name.GetCString()); |
| |
| context.AddNamedDecl(parser_named_decl); |
| } while (0); |
| } |
| |
| if (name.GetCString()[0] == '$' && !namespace_decl) { |
| static ConstString g_lldb_class_name("$__lldb_class"); |
| |
| if (name == g_lldb_class_name) { |
| // Clang is looking for the type of "this" |
| |
| if (frame == NULL) |
| return; |
| |
| // Find the block that defines the function represented by "sym_ctx" |
| Block *function_block = sym_ctx.GetFunctionBlock(); |
| |
| if (!function_block) |
| return; |
| |
| CompilerDeclContext function_decl_ctx = function_block->GetDeclContext(); |
| |
| if (!function_decl_ctx) |
| return; |
| |
| clang::CXXMethodDecl *method_decl = |
| ClangASTContext::DeclContextGetAsCXXMethodDecl(function_decl_ctx); |
| |
| if (method_decl) { |
| clang::CXXRecordDecl *class_decl = method_decl->getParent(); |
| |
| QualType class_qual_type(class_decl->getTypeForDecl(), 0); |
| |
| TypeFromUser class_user_type( |
| class_qual_type.getAsOpaquePtr(), |
| ClangASTContext::GetASTContext(&class_decl->getASTContext())); |
| |
| if (log) { |
| ASTDumper ast_dumper(class_qual_type); |
| log->Printf(" CEDM::FEVD[%u] Adding type for $__lldb_class: %s", |
| current_id, ast_dumper.GetCString()); |
| } |
| |
| AddThisType(context, class_user_type, current_id); |
| |
| if (method_decl->isInstance()) { |
| // self is a pointer to the object |
| |
| QualType class_pointer_type = |
| method_decl->getASTContext().getPointerType(class_qual_type); |
| |
| TypeFromUser self_user_type( |
| class_pointer_type.getAsOpaquePtr(), |
| ClangASTContext::GetASTContext(&method_decl->getASTContext())); |
| |
| m_struct_vars->m_object_pointer_type = self_user_type; |
| } |
| } else { |
| // This branch will get hit if we are executing code in the context of |
| // a function that claims to have an object pointer (through |
| // DW_AT_object_pointer?) but is not formally a method of the class. |
| // In that case, just look up the "this" variable in the current scope |
| // and use its type. |
| // FIXME: This code is formally correct, but clang doesn't currently |
| // emit DW_AT_object_pointer |
| // for C++ so it hasn't actually been tested. |
| |
| VariableList *vars = frame->GetVariableList(false); |
| |
| lldb::VariableSP this_var = vars->FindVariable(ConstString("this")); |
| |
| if (this_var && this_var->IsInScope(frame) && |
| this_var->LocationIsValidForFrame(frame)) { |
| Type *this_type = this_var->GetType(); |
| |
| if (!this_type) |
| return; |
| |
| TypeFromUser pointee_type = |
| this_type->GetForwardCompilerType().GetPointeeType(); |
| |
| if (pointee_type.IsValid()) { |
| if (log) { |
| ASTDumper ast_dumper(pointee_type); |
| log->Printf(" FEVD[%u] Adding type for $__lldb_class: %s", |
| current_id, ast_dumper.GetCString()); |
| } |
| |
| AddThisType(context, pointee_type, current_id); |
| TypeFromUser this_user_type(this_type->GetFullCompilerType()); |
| m_struct_vars->m_object_pointer_type = this_user_type; |
| return; |
| } |
| } |
| } |
| |
| return; |
| } |
| |
| static ConstString g_lldb_objc_class_name("$__lldb_objc_class"); |
| if (name == g_lldb_objc_class_name) { |
| // Clang is looking for the type of "*self" |
| |
| if (!frame) |
| return; |
| |
| SymbolContext sym_ctx = frame->GetSymbolContext( |
| lldb::eSymbolContextFunction | lldb::eSymbolContextBlock); |
| |
| // Find the block that defines the function represented by "sym_ctx" |
| Block *function_block = sym_ctx.GetFunctionBlock(); |
| |
| if (!function_block) |
| return; |
| |
| CompilerDeclContext function_decl_ctx = function_block->GetDeclContext(); |
| |
| if (!function_decl_ctx) |
| return; |
| |
| clang::ObjCMethodDecl *method_decl = |
| ClangASTContext::DeclContextGetAsObjCMethodDecl(function_decl_ctx); |
| |
| if (method_decl) { |
| ObjCInterfaceDecl *self_interface = method_decl->getClassInterface(); |
| |
| if (!self_interface) |
| return; |
| |
| const clang::Type *interface_type = self_interface->getTypeForDecl(); |
| |
| if (!interface_type) |
| return; // This is unlikely, but we have seen crashes where this |
| // occurred |
| |
| TypeFromUser class_user_type( |
| QualType(interface_type, 0).getAsOpaquePtr(), |
| ClangASTContext::GetASTContext(&method_decl->getASTContext())); |
| |
| if (log) { |
| ASTDumper ast_dumper(interface_type); |
| log->Printf(" FEVD[%u] Adding type for $__lldb_objc_class: %s", |
| current_id, ast_dumper.GetCString()); |
| } |
| |
| AddOneType(context, class_user_type, current_id); |
| |
| if (method_decl->isInstanceMethod()) { |
| // self is a pointer to the object |
| |
| QualType class_pointer_type = |
| method_decl->getASTContext().getObjCObjectPointerType( |
| QualType(interface_type, 0)); |
| |
| TypeFromUser self_user_type( |
| class_pointer_type.getAsOpaquePtr(), |
| ClangASTContext::GetASTContext(&method_decl->getASTContext())); |
| |
| m_struct_vars->m_object_pointer_type = self_user_type; |
| } else { |
| // self is a Class pointer |
| QualType class_type = method_decl->getASTContext().getObjCClassType(); |
| |
| TypeFromUser self_user_type( |
| class_type.getAsOpaquePtr(), |
| ClangASTContext::GetASTContext(&method_decl->getASTContext())); |
| |
| m_struct_vars->m_object_pointer_type = self_user_type; |
| } |
| |
| return; |
| } else { |
| // This branch will get hit if we are executing code in the context of |
| // a function that claims to have an object pointer (through |
| // DW_AT_object_pointer?) but is not formally a method of the class. |
| // In that case, just look up the "self" variable in the current scope |
| // and use its type. |
| |
| VariableList *vars = frame->GetVariableList(false); |
| |
| lldb::VariableSP self_var = vars->FindVariable(ConstString("self")); |
| |
| if (self_var && self_var->IsInScope(frame) && |
| self_var->LocationIsValidForFrame(frame)) { |
| Type *self_type = self_var->GetType(); |
| |
| if (!self_type) |
| return; |
| |
| CompilerType self_clang_type = self_type->GetFullCompilerType(); |
| |
| if (ClangASTContext::IsObjCClassType(self_clang_type)) { |
| return; |
| } else if (ClangASTContext::IsObjCObjectPointerType( |
| self_clang_type)) { |
| self_clang_type = self_clang_type.GetPointeeType(); |
| |
| if (!self_clang_type) |
| return; |
| |
| if (log) { |
| ASTDumper ast_dumper(self_type->GetFullCompilerType()); |
| log->Printf(" FEVD[%u] Adding type for $__lldb_objc_class: %s", |
| current_id, ast_dumper.GetCString()); |
| } |
| |
| TypeFromUser class_user_type(self_clang_type); |
| |
| AddOneType(context, class_user_type, current_id); |
| |
| TypeFromUser self_user_type(self_type->GetFullCompilerType()); |
| |
| m_struct_vars->m_object_pointer_type = self_user_type; |
| return; |
| } |
| } |
| } |
| |
| return; |
| } |
| |
| if (name == ConstString(g_lldb_local_vars_namespace_cstr)) { |
| CompilerDeclContext frame_decl_context = |
| sym_ctx.block != nullptr ? sym_ctx.block->GetDeclContext() |
| : CompilerDeclContext(); |
| |
| if (frame_decl_context) { |
| ClangASTContext *ast = llvm::dyn_cast_or_null<ClangASTContext>( |
| frame_decl_context.GetTypeSystem()); |
| |
| if (ast) { |
| clang::NamespaceDecl *namespace_decl = |
| ClangASTContext::GetUniqueNamespaceDeclaration( |
| m_ast_context, name.GetCString(), nullptr); |
| if (namespace_decl) { |
| context.AddNamedDecl(namespace_decl); |
| clang::DeclContext *clang_decl_ctx = |
| clang::Decl::castToDeclContext(namespace_decl); |
| clang_decl_ctx->setHasExternalVisibleStorage(true); |
| context.m_found.local_vars_nsp = true; |
| } |
| } |
| } |
| |
| return; |
| } |
| |
| // any other $__lldb names should be weeded out now |
| if (name.GetStringRef().startswith("$__lldb")) |
| return; |
| |
| ExpressionVariableSP pvar_sp( |
| m_parser_vars->m_persistent_vars->GetVariable(name)); |
| |
| if (pvar_sp) { |
| AddOneVariable(context, pvar_sp, current_id); |
| return; |
| } |
| |
| const char *reg_name(&name.GetCString()[1]); |
| |
| if (m_parser_vars->m_exe_ctx.GetRegisterContext()) { |
| const RegisterInfo *reg_info( |
| m_parser_vars->m_exe_ctx.GetRegisterContext()->GetRegisterInfoByName( |
| reg_name)); |
| |
| if (reg_info) { |
| if (log) |
| log->Printf(" CEDM::FEVD[%u] Found register %s", current_id, |
| reg_info->name); |
| |
| AddOneRegister(context, reg_info, current_id); |
| } |
| } |
| } else { |
| ValueObjectSP valobj; |
| VariableSP var; |
| |
| bool local_var_lookup = |
| !namespace_decl || (namespace_decl.GetName() == |
| ConstString(g_lldb_local_vars_namespace_cstr)); |
| if (frame && local_var_lookup) { |
| CompilerDeclContext compiler_decl_context = |
| sym_ctx.block != nullptr ? sym_ctx.block->GetDeclContext() |
| : CompilerDeclContext(); |
| |
| if (compiler_decl_context) { |
| // Make sure that the variables are parsed so that we have the |
| // declarations. |
| VariableListSP vars = frame->GetInScopeVariableList(true); |
| for (size_t i = 0; i < vars->GetSize(); i++) |
| vars->GetVariableAtIndex(i)->GetDecl(); |
| |
| // Search for declarations matching the name. Do not include imported |
| // decls in the search if we are looking for decls in the artificial |
| // namespace $__lldb_local_vars. |
| std::vector<CompilerDecl> found_decls = |
| compiler_decl_context.FindDeclByName(name, |
| namespace_decl.IsValid()); |
| |
| bool variable_found = false; |
| for (CompilerDecl decl : found_decls) { |
| for (size_t vi = 0, ve = vars->GetSize(); vi != ve; ++vi) { |
| VariableSP candidate_var = vars->GetVariableAtIndex(vi); |
| if (candidate_var->GetDecl() == decl) { |
| var = candidate_var; |
| break; |
| } |
| } |
| |
| if (var && !variable_found) { |
| variable_found = true; |
| valobj = ValueObjectVariable::Create(frame, var); |
| AddOneVariable(context, var, valobj, current_id); |
| context.m_found.variable = true; |
| } |
| } |
| if (variable_found) |
| return; |
| } |
| } |
| if (target) { |
| var = FindGlobalVariable(*target, module_sp, name, &namespace_decl, NULL); |
| |
| if (var) { |
| valobj = ValueObjectVariable::Create(target, var); |
| AddOneVariable(context, var, valobj, current_id); |
| context.m_found.variable = true; |
| return; |
| } |
| } |
| |
| std::vector<clang::NamedDecl *> decls_from_modules; |
| |
| if (target) { |
| if (ClangModulesDeclVendor *decl_vendor = |
| target->GetClangModulesDeclVendor()) { |
| decl_vendor->FindDecls(name, false, UINT32_MAX, decls_from_modules); |
| } |
| } |
| |
| const bool include_inlines = false; |
| const bool append = false; |
| |
| if (namespace_decl && module_sp) { |
| const bool include_symbols = false; |
| |
| module_sp->FindFunctions(name, &namespace_decl, eFunctionNameTypeBase, |
| include_symbols, include_inlines, append, |
| sc_list); |
| } else if (target && !namespace_decl) { |
| const bool include_symbols = true; |
| |
| // TODO Fix FindFunctions so that it doesn't return |
| // instance methods for eFunctionNameTypeBase. |
| |
| target->GetImages().FindFunctions(name, eFunctionNameTypeFull, |
| include_symbols, include_inlines, |
| append, sc_list); |
| } |
| |
| // If we found more than one function, see if we can use the frame's decl |
| // context to remove functions that are shadowed by other functions which |
| // match in type but are nearer in scope. |
| // |
| // AddOneFunction will not add a function whose type has already been |
| // added, so if there's another function in the list with a matching type, |
| // check to see if their decl context is a parent of the current frame's or |
| // was imported via a and using statement, and pick the best match |
| // according to lookup rules. |
| if (sc_list.GetSize() > 1) { |
| // Collect some info about our frame's context. |
| StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr(); |
| SymbolContext frame_sym_ctx; |
| if (frame != nullptr) |
| frame_sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction | |
| lldb::eSymbolContextBlock); |
| CompilerDeclContext frame_decl_context = |
| frame_sym_ctx.block != nullptr ? frame_sym_ctx.block->GetDeclContext() |
| : CompilerDeclContext(); |
| |
| // We can't do this without a compiler decl context for our frame. |
| if (frame_decl_context) { |
| clang::DeclContext *frame_decl_ctx = |
| (clang::DeclContext *)frame_decl_context.GetOpaqueDeclContext(); |
| ClangASTContext *ast = llvm::dyn_cast_or_null<ClangASTContext>( |
| frame_decl_context.GetTypeSystem()); |
| |
| // Structure to hold the info needed when comparing function |
| // declarations. |
| struct FuncDeclInfo { |
| ConstString m_name; |
| CompilerType m_copied_type; |
| uint32_t m_decl_lvl; |
| SymbolContext m_sym_ctx; |
| }; |
| |
| // First, symplify things by looping through the symbol contexts to |
| // remove unwanted functions and separate out the functions we want to |
| // compare and prune into a separate list. Cache the info needed about |
| // the function declarations in a vector for efficiency. |
| SymbolContextList sc_sym_list; |
| uint32_t num_indices = sc_list.GetSize(); |
| std::vector<FuncDeclInfo> fdi_cache; |
| fdi_cache.reserve(num_indices); |
| for (uint32_t index = 0; index < num_indices; ++index) { |
| FuncDeclInfo fdi; |
| SymbolContext sym_ctx; |
| sc_list.GetContextAtIndex(index, sym_ctx); |
| |
| // We don't know enough about symbols to compare them, but we should |
| // keep them in the list. |
| Function *function = sym_ctx.function; |
| if (!function) { |
| sc_sym_list.Append(sym_ctx); |
| continue; |
| } |
| // Filter out functions without declaration contexts, as well as |
| // class/instance methods, since they'll be skipped in the code that |
| // follows anyway. |
| CompilerDeclContext func_decl_context = function->GetDeclContext(); |
| if (!func_decl_context || |
| func_decl_context.IsClassMethod(nullptr, nullptr, nullptr)) |
| continue; |
| // We can only prune functions for which we can copy the type. |
| CompilerType func_clang_type = |
| function->GetType()->GetFullCompilerType(); |
| CompilerType copied_func_type = GuardedCopyType(func_clang_type); |
| if (!copied_func_type) { |
| sc_sym_list.Append(sym_ctx); |
| continue; |
| } |
| |
| fdi.m_sym_ctx = sym_ctx; |
| fdi.m_name = function->GetName(); |
| fdi.m_copied_type = copied_func_type; |
| fdi.m_decl_lvl = LLDB_INVALID_DECL_LEVEL; |
| if (fdi.m_copied_type && func_decl_context) { |
| // Call CountDeclLevels to get the number of parent scopes we have |
| // to look through before we find the function declaration. When |
| // comparing functions of the same type, the one with a lower count |
| // will be closer to us in the lookup scope and shadows the other. |
| clang::DeclContext *func_decl_ctx = |
| (clang::DeclContext *)func_decl_context.GetOpaqueDeclContext(); |
| fdi.m_decl_lvl = ast->CountDeclLevels( |
| frame_decl_ctx, func_decl_ctx, &fdi.m_name, &fdi.m_copied_type); |
| } |
| fdi_cache.emplace_back(fdi); |
| } |
| |
| // Loop through the functions in our cache looking for matching types, |
| // then compare their scope levels to see which is closer. |
| std::multimap<CompilerType, const FuncDeclInfo *> matches; |
| for (const FuncDeclInfo &fdi : fdi_cache) { |
| const CompilerType t = fdi.m_copied_type; |
| auto q = matches.find(t); |
| if (q != matches.end()) { |
| if (q->second->m_decl_lvl > fdi.m_decl_lvl) |
| // This function is closer; remove the old set. |
| matches.erase(t); |
| else if (q->second->m_decl_lvl < fdi.m_decl_lvl) |
| // The functions in our set are closer - skip this one. |
| continue; |
| } |
| matches.insert(std::make_pair(t, &fdi)); |
| } |
| |
| // Loop through our matches and add their symbol contexts to our list. |
| SymbolContextList sc_func_list; |
| for (const auto &q : matches) |
| sc_func_list.Append(q.second->m_sym_ctx); |
| |
| // Rejoin the lists with the functions in front. |
| sc_list = sc_func_list; |
| sc_list.Append(sc_sym_list); |
| } |
| } |
| |
| if (sc_list.GetSize()) { |
| Symbol *extern_symbol = NULL; |
| Symbol *non_extern_symbol = NULL; |
| |
| for (uint32_t index = 0, num_indices = sc_list.GetSize(); |
| index < num_indices; ++index) { |
| SymbolContext sym_ctx; |
| sc_list.GetContextAtIndex(index, sym_ctx); |
| |
| if (sym_ctx.function) { |
| CompilerDeclContext decl_ctx = sym_ctx.function->GetDeclContext(); |
| |
| if (!decl_ctx) |
| continue; |
| |
| // Filter out class/instance methods. |
| if (decl_ctx.IsClassMethod(nullptr, nullptr, nullptr)) |
| continue; |
| |
| AddOneFunction(context, sym_ctx.function, NULL, current_id); |
| context.m_found.function_with_type_info = true; |
| context.m_found.function = true; |
| } else if (sym_ctx.symbol) { |
| if (sym_ctx.symbol->GetType() == eSymbolTypeReExported && target) { |
| sym_ctx.symbol = sym_ctx.symbol->ResolveReExportedSymbol(*target); |
| if (sym_ctx.symbol == NULL) |
| continue; |
| } |
| |
| if (sym_ctx.symbol->IsExternal()) |
| extern_symbol = sym_ctx.symbol; |
| else |
| non_extern_symbol = sym_ctx.symbol; |
| } |
| } |
| |
| if (!context.m_found.function_with_type_info) { |
| for (clang::NamedDecl *decl : decls_from_modules) { |
| if (llvm::isa<clang::FunctionDecl>(decl)) { |
| clang::NamedDecl *copied_decl = |
| llvm::cast_or_null<FunctionDecl>(CopyDecl(decl)); |
| if (copied_decl) { |
| context.AddNamedDecl(copied_decl); |
| context.m_found.function_with_type_info = true; |
| } |
| } |
| } |
| } |
| |
| if (!context.m_found.function_with_type_info) { |
| if (extern_symbol) { |
| AddOneFunction(context, NULL, extern_symbol, current_id); |
| context.m_found.function = true; |
| } else if (non_extern_symbol) { |
| AddOneFunction(context, NULL, non_extern_symbol, current_id); |
| context.m_found.function = true; |
| } |
| } |
| } |
| |
| if (!context.m_found.function_with_type_info) { |
| // Try the modules next. |
| |
| do { |
| if (ClangModulesDeclVendor *modules_decl_vendor = |
| m_target->GetClangModulesDeclVendor()) { |
| bool append = false; |
| uint32_t max_matches = 1; |
| std::vector<clang::NamedDecl *> decls; |
| |
| if (!modules_decl_vendor->FindDecls(name, append, max_matches, decls)) |
| break; |
| |
| clang::NamedDecl *const decl_from_modules = decls[0]; |
| |
| if (llvm::isa<clang::FunctionDecl>(decl_from_modules)) { |
| if (log) { |
| log->Printf(" CAS::FEVD[%u] Matching function found for " |
| "\"%s\" in the modules", |
| current_id, name.GetCString()); |
| } |
| |
| clang::Decl *copied_decl = CopyDecl(decl_from_modules); |
| clang::FunctionDecl *copied_function_decl = |
| copied_decl ? dyn_cast<clang::FunctionDecl>(copied_decl) |
| : nullptr; |
| |
| if (!copied_function_decl) { |
| if (log) |
| log->Printf(" CAS::FEVD[%u] - Couldn't export a function " |
| "declaration from the modules", |
| current_id); |
| |
| break; |
| } |
| |
| MaybeRegisterFunctionBody(copied_function_decl); |
| |
| context.AddNamedDecl(copied_function_decl); |
| |
| context.m_found.function_with_type_info = true; |
| context.m_found.function = true; |
| } else if (llvm::isa<clang::VarDecl>(decl_from_modules)) { |
| if (log) { |
| log->Printf(" CAS::FEVD[%u] Matching variable found for " |
| "\"%s\" in the modules", |
| current_id, name.GetCString()); |
| } |
| |
| clang::Decl *copied_decl = CopyDecl(decl_from_modules); |
| clang::VarDecl *copied_var_decl = |
| copied_decl ? dyn_cast_or_null<clang::VarDecl>(copied_decl) |
| : nullptr; |
| |
| if (!copied_var_decl) { |
| if (log) |
| log->Printf(" CAS::FEVD[%u] - Couldn't export a variable " |
| "declaration from the modules", |
| current_id); |
| |
| break; |
| } |
| |
| context.AddNamedDecl(copied_var_decl); |
| |
| context.m_found.variable = true; |
| } |
| } |
| } while (0); |
| } |
| |
| if (target && !context.m_found.variable && !namespace_decl) { |
| // We couldn't find a non-symbol variable for this. Now we'll hunt for a |
| // generic data symbol, and -- if it is found -- treat it as a variable. |
| Status error; |
| |
| const Symbol *data_symbol = |
| m_parser_vars->m_sym_ctx.FindBestGlobalDataSymbol(name, error); |
| |
| if (!error.Success()) { |
| const unsigned diag_id = |
| m_ast_context->getDiagnostics().getCustomDiagID( |
| clang::DiagnosticsEngine::Level::Error, "%0"); |
| m_ast_context->getDiagnostics().Report(diag_id) << error.AsCString(); |
| } |
| |
| if (data_symbol) { |
| std::string warning("got name from symbols: "); |
| warning.append(name.AsCString()); |
| const unsigned diag_id = |
| m_ast_context->getDiagnostics().getCustomDiagID( |
| clang::DiagnosticsEngine::Level::Warning, "%0"); |
| m_ast_context->getDiagnostics().Report(diag_id) << warning.c_str(); |
| AddOneGenericVariable(context, *data_symbol, current_id); |
| context.m_found.variable = true; |
| } |
| } |
| } |
| } |
| |
| bool ClangExpressionDeclMap::GetVariableValue(VariableSP &var, |
| lldb_private::Value &var_location, |
| TypeFromUser *user_type, |
| TypeFromParser *parser_type) { |
| Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); |
| |
| Type *var_type = var->GetType(); |
| |
| if (!var_type) { |
| if (log) |
| log->PutCString("Skipped a definition because it has no type"); |
| return false; |
| } |
| |
| CompilerType var_clang_type = var_type->GetFullCompilerType(); |
| |
| if (!var_clang_type) { |
| if (log) |
| log->PutCString("Skipped a definition because it has no Clang type"); |
| return false; |
| } |
| |
| ClangASTContext *clang_ast = llvm::dyn_cast_or_null<ClangASTContext>( |
| var_type->GetForwardCompilerType().GetTypeSystem()); |
| |
| if (!clang_ast) { |
| if (log) |
| log->PutCString("Skipped a definition because it has no Clang AST"); |
| return false; |
| } |
| |
| ASTContext *ast = clang_ast->getASTContext(); |
| |
| if (!ast) { |
| if (log) |
| log->PutCString( |
| "There is no AST context for the current execution context"); |
| return false; |
| } |
| |
| DWARFExpression &var_location_expr = var->LocationExpression(); |
| |
| Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr(); |
| Status err; |
| |
| if (var->GetLocationIsConstantValueData()) { |
| DataExtractor const_value_extractor; |
| |
| if (var_location_expr.GetExpressionData(const_value_extractor)) { |
| var_location = Value(const_value_extractor.GetDataStart(), |
| const_value_extractor.GetByteSize()); |
| var_location.SetValueType(Value::eValueTypeHostAddress); |
| } else { |
| if (log) |
| log->Printf("Error evaluating constant variable: %s", err.AsCString()); |
| return false; |
| } |
| } |
| |
| CompilerType type_to_use = GuardedCopyType(var_clang_type); |
| |
| if (!type_to_use) { |
| if (log) |
| log->Printf( |
| "Couldn't copy a variable's type into the parser's AST context"); |
| |
| return false; |
| } |
| |
| if (parser_type) |
| *parser_type = TypeFromParser(type_to_use); |
| |
| if (var_location.GetContextType() == Value::eContextTypeInvalid) |
| var_location.SetCompilerType(type_to_use); |
| |
| if (var_location.GetValueType() == Value::eValueTypeFileAddress) { |
| SymbolContext var_sc; |
| var->CalculateSymbolContext(&var_sc); |
| |
| if (!var_sc.module_sp) |
| return false; |
| |
| Address so_addr(var_location.GetScalar().ULongLong(), |
| var_sc.module_sp->GetSectionList()); |
| |
| lldb::addr_t load_addr = so_addr.GetLoadAddress(target); |
| |
| if (load_addr != LLDB_INVALID_ADDRESS) { |
| var_location.GetScalar() = load_addr; |
| var_location.SetValueType(Value::eValueTypeLoadAddress); |
| } |
| } |
| |
| if (user_type) |
| *user_type = TypeFromUser(var_clang_type); |
| |
| return true; |
| } |
| |
| void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context, |
| VariableSP var, |
| ValueObjectSP valobj, |
| unsigned int current_id) { |
| assert(m_parser_vars.get()); |
| |
| Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); |
| |
| TypeFromUser ut; |
| TypeFromParser pt; |
| Value var_location; |
| |
| if (!GetVariableValue(var, var_location, &ut, &pt)) |
| return; |
| |
| clang::QualType parser_opaque_type = |
| QualType::getFromOpaquePtr(pt.GetOpaqueQualType()); |
| |
| if (parser_opaque_type.isNull()) |
| return; |
| |
| if (const clang::Type *parser_type = parser_opaque_type.getTypePtr()) { |
| if (const TagType *tag_type = dyn_cast<TagType>(parser_type)) |
| CompleteType(tag_type->getDecl()); |
| if (const ObjCObjectPointerType *objc_object_ptr_type = |
| dyn_cast<ObjCObjectPointerType>(parser_type)) |
| CompleteType(objc_object_ptr_type->getInterfaceDecl()); |
| } |
| |
| bool is_reference = pt.IsReferenceType(); |
| |
| NamedDecl *var_decl = NULL; |
| if (is_reference) |
| var_decl = context.AddVarDecl(pt); |
| else |
| var_decl = context.AddVarDecl(pt.GetLValueReferenceType()); |
| |
| std::string decl_name(context.m_decl_name.getAsString()); |
| ConstString entity_name(decl_name.c_str()); |
| ClangExpressionVariable *entity(new ClangExpressionVariable(valobj)); |
| m_found_entities.AddNewlyConstructedVariable(entity); |
| |
| assert(entity); |
| entity->EnableParserVars(GetParserID()); |
| ClangExpressionVariable::ParserVars *parser_vars = |
| entity->GetParserVars(GetParserID()); |
| parser_vars->m_parser_type = pt; |
| parser_vars->m_named_decl = var_decl; |
| parser_vars->m_llvm_value = NULL; |
| parser_vars->m_lldb_value = var_location; |
| parser_vars->m_lldb_var = var; |
| |
| if (is_reference) |
| entity->m_flags |= ClangExpressionVariable::EVTypeIsReference; |
| |
| if (log) { |
| ASTDumper orig_dumper(ut.GetOpaqueQualType()); |
| ASTDumper ast_dumper(var_decl); |
| log->Printf(" CEDM::FEVD[%u] Found variable %s, returned %s (original %s)", |
| current_id, decl_name.c_str(), ast_dumper.GetCString(), |
| orig_dumper.GetCString()); |
| } |
| } |
| |
| void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context, |
| ExpressionVariableSP &pvar_sp, |
| unsigned int current_id) { |
| Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); |
| |
| TypeFromUser user_type( |
| llvm::cast<ClangExpressionVariable>(pvar_sp.get())->GetTypeFromUser()); |
| |
| TypeFromParser parser_type(GuardedCopyType(user_type)); |
| |
| if (!parser_type.GetOpaqueQualType()) { |
| if (log) |
| log->Printf(" CEDM::FEVD[%u] Couldn't import type for pvar %s", |
| current_id, pvar_sp->GetName().GetCString()); |
| return; |
| } |
| |
| NamedDecl *var_decl = |
| context.AddVarDecl(parser_type.GetLValueReferenceType()); |
| |
| llvm::cast<ClangExpressionVariable>(pvar_sp.get()) |
| ->EnableParserVars(GetParserID()); |
| ClangExpressionVariable::ParserVars *parser_vars = |
| llvm::cast<ClangExpressionVariable>(pvar_sp.get()) |
| ->GetParserVars(GetParserID()); |
| parser_vars->m_parser_type = parser_type; |
| parser_vars->m_named_decl = var_decl; |
| parser_vars->m_llvm_value = NULL; |
| parser_vars->m_lldb_value.Clear(); |
| |
| if (log) { |
| ASTDumper ast_dumper(var_decl); |
| log->Printf(" CEDM::FEVD[%u] Added pvar %s, returned %s", current_id, |
| pvar_sp->GetName().GetCString(), ast_dumper.GetCString()); |
| } |
| } |
| |
| void ClangExpressionDeclMap::AddOneGenericVariable(NameSearchContext &context, |
| const Symbol &symbol, |
| unsigned int current_id) { |
| assert(m_parser_vars.get()); |
| |
| Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); |
| |
| Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr(); |
| |
| if (target == NULL) |
| return; |
| |
| ASTContext *scratch_ast_context = |
| target->GetScratchClangASTContext()->getASTContext(); |
| |
| TypeFromUser user_type( |
| ClangASTContext::GetBasicType(scratch_ast_context, eBasicTypeVoid) |
| .GetPointerType() |
| .GetLValueReferenceType()); |
| TypeFromParser parser_type( |
| ClangASTContext::GetBasicType(m_ast_context, eBasicTypeVoid) |
| .GetPointerType() |
| .GetLValueReferenceType()); |
| NamedDecl *var_decl = context.AddVarDecl(parser_type); |
| |
| std::string decl_name(context.m_decl_name.getAsString()); |
| ConstString entity_name(decl_name.c_str()); |
| ClangExpressionVariable *entity(new ClangExpressionVariable( |
| m_parser_vars->m_exe_ctx.GetBestExecutionContextScope(), entity_name, |
| user_type, m_parser_vars->m_target_info.byte_order, |
| m_parser_vars->m_target_info.address_byte_size)); |
| m_found_entities.AddNewlyConstructedVariable(entity); |
| |
| entity->EnableParserVars(GetParserID()); |
| ClangExpressionVariable::ParserVars *parser_vars = |
| entity->GetParserVars(GetParserID()); |
| |
| const Address symbol_address = symbol.GetAddress(); |
| lldb::addr_t symbol_load_addr = symbol_address.GetLoadAddress(target); |
| |
| // parser_vars->m_lldb_value.SetContext(Value::eContextTypeClangType, |
| // user_type.GetOpaqueQualType()); |
| parser_vars->m_lldb_value.SetCompilerType(user_type); |
| parser_vars->m_lldb_value.GetScalar() = symbol_load_addr; |
| parser_vars->m_lldb_value.SetValueType(Value::eValueTypeLoadAddress); |
| |
| parser_vars->m_parser_type = parser_type; |
| parser_vars->m_named_decl = var_decl; |
| parser_vars->m_llvm_value = NULL; |
| parser_vars->m_lldb_sym = &symbol; |
| |
| if (log) { |
| ASTDumper ast_dumper(var_decl); |
| |
| log->Printf(" CEDM::FEVD[%u] Found variable %s, returned %s", current_id, |
| decl_name.c_str(), ast_dumper.GetCString()); |
| } |
| } |
| |
| bool ClangExpressionDeclMap::ResolveUnknownTypes() { |
| Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); |
| Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr(); |
| |
| ClangASTContextForExpressions *scratch_ast_context = |
| static_cast<ClangASTContextForExpressions*>( |
| target->GetScratchClangASTContext()); |
| |
| for (size_t index = 0, num_entities = m_found_entities.GetSize(); |
| index < num_entities; ++index) { |
| ExpressionVariableSP entity = m_found_entities.GetVariableAtIndex(index); |
| |
| ClangExpressionVariable::ParserVars *parser_vars = |
| llvm::cast<ClangExpressionVariable>(entity.get()) |
| ->GetParserVars(GetParserID()); |
| |
| if (entity->m_flags & ClangExpressionVariable::EVUnknownType) { |
| const NamedDecl *named_decl = parser_vars->m_named_decl; |
| const VarDecl *var_decl = dyn_cast<VarDecl>(named_decl); |
| |
| if (!var_decl) { |
| if (log) |
| log->Printf("Entity of unknown type does not have a VarDecl"); |
| return false; |
| } |
| |
| if (log) { |
| ASTDumper ast_dumper(const_cast<VarDecl *>(var_decl)); |
| log->Printf("Variable of unknown type now has Decl %s", |
| ast_dumper.GetCString()); |
| } |
| |
| QualType var_type = var_decl->getType(); |
| TypeFromParser parser_type( |
| var_type.getAsOpaquePtr(), |
| ClangASTContext::GetASTContext(&var_decl->getASTContext())); |
| |
| lldb::opaque_compiler_type_t copied_type = 0; |
| if (m_ast_importer_sp) { |
| copied_type = m_ast_importer_sp->CopyType( |
| scratch_ast_context->getASTContext(), &var_decl->getASTContext(), |
| var_type.getAsOpaquePtr()); |
| } else if (HasMerger()) { |
| copied_type = CopyTypeWithMerger( |
| var_decl->getASTContext(), |
| scratch_ast_context->GetMergerUnchecked(), |
| var_type).getAsOpaquePtr(); |
| } else { |
| lldbassert(0 && "No mechanism to copy a resolved unknown type!"); |
| return false; |
| } |
| |
| if (!copied_type) { |
| if (log) |
| log->Printf("ClangExpressionDeclMap::ResolveUnknownType - Couldn't " |
| "import the type for a variable"); |
| |
| return (bool)lldb::ExpressionVariableSP(); |
| } |
| |
| TypeFromUser user_type(copied_type, scratch_ast_context); |
| |
| // parser_vars->m_lldb_value.SetContext(Value::eContextTypeClangType, |
| // user_type.GetOpaqueQualType()); |
| parser_vars->m_lldb_value.SetCompilerType(user_type); |
| parser_vars->m_parser_type = parser_type; |
| |
| entity->SetCompilerType(user_type); |
| |
| entity->m_flags &= ~(ClangExpressionVariable::EVUnknownType); |
| } |
| } |
| |
| return true; |
| } |
| |
| void ClangExpressionDeclMap::AddOneRegister(NameSearchContext &context, |
| const RegisterInfo *reg_info, |
| unsigned int current_id) { |
| Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); |
| |
| CompilerType clang_type = |
| ClangASTContext::GetBuiltinTypeForEncodingAndBitSize( |
| m_ast_context, reg_info->encoding, reg_info->byte_size * 8); |
| |
| if (!clang_type) { |
| if (log) |
| log->Printf(" Tried to add a type for %s, but couldn't get one", |
| context.m_decl_name.getAsString().c_str()); |
| return; |
| } |
| |
| TypeFromParser parser_clang_type(clang_type); |
| |
| NamedDecl *var_decl = context.AddVarDecl(parser_clang_type); |
| |
| ClangExpressionVariable *entity(new ClangExpressionVariable( |
| m_parser_vars->m_exe_ctx.GetBestExecutionContextScope(), |
| m_parser_vars->m_target_info.byte_order, |
| m_parser_vars->m_target_info.address_byte_size)); |
| m_found_entities.AddNewlyConstructedVariable(entity); |
| |
| std::string decl_name(context.m_decl_name.getAsString()); |
| entity->SetName(ConstString(decl_name.c_str())); |
| entity->SetRegisterInfo(reg_info); |
| entity->EnableParserVars(GetParserID()); |
| ClangExpressionVariable::ParserVars *parser_vars = |
| entity->GetParserVars(GetParserID()); |
| parser_vars->m_parser_type = parser_clang_type; |
| parser_vars->m_named_decl = var_decl; |
| parser_vars->m_llvm_value = NULL; |
| parser_vars->m_lldb_value.Clear(); |
| entity->m_flags |= ClangExpressionVariable::EVBareRegister; |
| |
| if (log) { |
| ASTDumper ast_dumper(var_decl); |
| log->Printf(" CEDM::FEVD[%d] Added register %s, returned %s", current_id, |
| context.m_decl_name.getAsString().c_str(), |
| ast_dumper.GetCString()); |
| } |
| } |
| |
| void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, |
| Function *function, Symbol *symbol, |
| unsigned int current_id) { |
| assert(m_parser_vars.get()); |
| |
| Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); |
| |
| NamedDecl *function_decl = NULL; |
| Address fun_address; |
| CompilerType function_clang_type; |
| |
| bool is_indirect_function = false; |
| |
| if (function) { |
| Type *function_type = function->GetType(); |
| |
| const auto lang = function->GetCompileUnit()->GetLanguage(); |
| const auto name = function->GetMangled().GetMangledName().AsCString(); |
| const bool extern_c = (Language::LanguageIsC(lang) && |
| !CPlusPlusLanguage::IsCPPMangledName(name)) || |
| (Language::LanguageIsObjC(lang) && |
| !Language::LanguageIsCPlusPlus(lang)); |
| |
| if (!extern_c) { |
| TypeSystem *type_system = function->GetDeclContext().GetTypeSystem(); |
| if (llvm::isa<ClangASTContext>(type_system)) { |
| clang::DeclContext *src_decl_context = |
| (clang::DeclContext *)function->GetDeclContext() |
| .GetOpaqueDeclContext(); |
| clang::FunctionDecl *src_function_decl = |
| llvm::dyn_cast_or_null<clang::FunctionDecl>(src_decl_context); |
| if (src_function_decl && |
| src_function_decl->getTemplateSpecializationInfo()) { |
| clang::FunctionTemplateDecl *function_template = |
| src_function_decl->getTemplateSpecializationInfo()->getTemplate(); |
| clang::FunctionTemplateDecl *copied_function_template = |
| llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>( |
| CopyDecl(function_template)); |
| if (copied_function_template) { |
| if (log) { |
| ASTDumper ast_dumper((clang::Decl *)copied_function_template); |
| |
| StreamString ss; |
| |
| function->DumpSymbolContext(&ss); |
| |
| log->Printf(" CEDM::FEVD[%u] Imported decl for function template" |
| " %s (description %s), returned %s", |
| current_id, |
| copied_function_template->getNameAsString().c_str(), |
| ss.GetData(), ast_dumper.GetCString()); |
| } |
| |
| context.AddNamedDecl(copied_function_template); |
| } |
| } else if (src_function_decl) { |
| if (clang::FunctionDecl *copied_function_decl = |
| llvm::dyn_cast_or_null<clang::FunctionDecl>( |
| CopyDecl(src_function_decl))) { |
| if (log) { |
| ASTDumper ast_dumper((clang::Decl *)copied_function_decl); |
| |
| StreamString ss; |
| |
| function->DumpSymbolContext(&ss); |
| |
| log->Printf(" CEDM::FEVD[%u] Imported decl for function %s " |
| "(description %s), returned %s", |
| current_id, |
| copied_function_decl->getNameAsString().c_str(), |
| ss.GetData(), ast_dumper.GetCString()); |
| } |
| |
| context.AddNamedDecl(copied_function_decl); |
| return; |
| } else { |
| if (log) { |
| log->Printf(" Failed to import the function decl for '%s'", |
| src_function_decl->getName().str().c_str()); |
| } |
| } |
| } |
| } |
| } |
| |
| if (!function_type) { |
| if (log) |
| log->PutCString(" Skipped a function because it has no type"); |
| return; |
| } |
| |
| function_clang_type = function_type->GetFullCompilerType(); |
| |
| if (!function_clang_type) { |
| if (log) |
| log->PutCString(" Skipped a function because it has no Clang type"); |
| return; |
| } |
| |
| fun_address = function->GetAddressRange().GetBaseAddress(); |
| |
| CompilerType copied_function_type = GuardedCopyType(function_clang_type); |
| if (copied_function_type) { |
| function_decl = context.AddFunDecl(copied_function_type, extern_c); |
| |
| if (!function_decl) { |
| if (log) { |
| log->Printf( |
| " Failed to create a function decl for '%s' {0x%8.8" PRIx64 "}", |
| function_type->GetName().GetCString(), function_type->GetID()); |
| } |
| |
| return; |
| } |
| } else { |
| // We failed to copy the type we found |
| if (log) { |
| log->Printf(" Failed to import the function type '%s' {0x%8.8" PRIx64 |
| "} into the expression parser AST contenxt", |
| function_type->GetName().GetCString(), |
| function_type->GetID()); |
| } |
| |
| return; |
| } |
| } else if (symbol) { |
| fun_address = symbol->GetAddress(); |
| function_decl = context.AddGenericFunDecl(); |
| is_indirect_function = symbol->IsIndirect(); |
| } else { |
| if (log) |
| log->PutCString(" AddOneFunction called with no function and no symbol"); |
| return; |
| } |
| |
| Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr(); |
| |
| lldb::addr_t load_addr = |
| fun_address.GetCallableLoadAddress(target, is_indirect_function); |
| |
| ClangExpressionVariable *entity(new ClangExpressionVariable( |
| m_parser_vars->m_exe_ctx.GetBestExecutionContextScope(), |
| m_parser_vars->m_target_info.byte_order, |
| m_parser_vars->m_target_info.address_byte_size)); |
| m_found_entities.AddNewlyConstructedVariable(entity); |
| |
| std::string decl_name(context.m_decl_name.getAsString()); |
| entity->SetName(ConstString(decl_name.c_str())); |
| entity->SetCompilerType(function_clang_type); |
| entity->EnableParserVars(GetParserID()); |
| |
| ClangExpressionVariable::ParserVars *parser_vars = |
| entity->GetParserVars(GetParserID()); |
| |
| if (load_addr != LLDB_INVALID_ADDRESS) { |
| parser_vars->m_lldb_value.SetValueType(Value::eValueTypeLoadAddress); |
| parser_vars->m_lldb_value.GetScalar() = load_addr; |
| } else { |
| // We have to try finding a file address. |
| |
| lldb::addr_t file_addr = fun_address.GetFileAddress(); |
| |
| parser_vars->m_lldb_value.SetValueType(Value::eValueTypeFileAddress); |
| parser_vars->m_lldb_value.GetScalar() = file_addr; |
| } |
| |
| parser_vars->m_named_decl = function_decl; |
| parser_vars->m_llvm_value = NULL; |
| |
| if (log) { |
| std::string function_str = |
| function_decl ? ASTDumper(function_decl).GetCString() : "nullptr"; |
| |
| StreamString ss; |
| |
| fun_address.Dump(&ss, |
| m_parser_vars->m_exe_ctx.GetBestExecutionContextScope(), |
| Address::DumpStyleResolvedDescription); |
| |
| log->Printf( |
| " CEDM::FEVD[%u] Found %s function %s (description %s), returned %s", |
| current_id, (function ? "specific" : "generic"), decl_name.c_str(), |
| ss.GetData(), function_str.c_str()); |
| } |
| } |
| |
| void ClangExpressionDeclMap::AddThisType(NameSearchContext &context, |
| TypeFromUser &ut, |
| unsigned int current_id) { |
| CompilerType copied_clang_type = GuardedCopyType(ut); |
| |
| Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); |
| |
| if (!copied_clang_type) { |
| if (log) |
| log->Printf( |
| "ClangExpressionDeclMap::AddThisType - Couldn't import the type"); |
| |
| return; |
| } |
| |
| if (copied_clang_type.IsAggregateType() && |
| copied_clang_type.GetCompleteType()) { |
| CompilerType void_clang_type = |
| ClangASTContext::GetBasicType(m_ast_context, eBasicTypeVoid); |
| CompilerType void_ptr_clang_type = void_clang_type.GetPointerType(); |
| |
| CompilerType method_type = ClangASTContext::CreateFunctionType( |
| m_ast_context, void_clang_type, &void_ptr_clang_type, 1, false, 0); |
| |
| const bool is_virtual = false; |
| const bool is_static = false; |
| const bool is_inline = false; |
| const bool is_explicit = false; |
| const bool is_attr_used = true; |
| const bool is_artificial = false; |
| |
| CXXMethodDecl *method_decl = |
| ClangASTContext::GetASTContext(m_ast_context) |
| ->AddMethodToCXXRecordType( |
| copied_clang_type.GetOpaqueQualType(), "$__lldb_expr", NULL, |
| method_type, lldb::eAccessPublic, is_virtual, is_static, |
| is_inline, is_explicit, is_attr_used, is_artificial); |
| |
| if (log) { |
| ASTDumper method_ast_dumper((clang::Decl *)method_decl); |
| ASTDumper type_ast_dumper(copied_clang_type); |
| |
| log->Printf(" CEDM::AddThisType Added function $__lldb_expr " |
| "(description %s) for this type %s", |
| method_ast_dumper.GetCString(), type_ast_dumper.GetCString()); |
| } |
| } |
| |
| if (!copied_clang_type.IsValid()) |
| return; |
| |
| TypeSourceInfo *type_source_info = m_ast_context->getTrivialTypeSourceInfo( |
| QualType::getFromOpaquePtr(copied_clang_type.GetOpaqueQualType())); |
| |
| if (!type_source_info) |
| return; |
| |
| // Construct a typedef type because if "*this" is a templated type we can't |
| // just return ClassTemplateSpecializationDecls in response to name queries. |
| // Using a typedef makes this much more robust. |
| |
| TypedefDecl *typedef_decl = TypedefDecl::Create( |
| *m_ast_context, m_ast_context->getTranslationUnitDecl(), SourceLocation(), |
| SourceLocation(), context.m_decl_name.getAsIdentifierInfo(), |
| type_source_info); |
| |
| if (!typedef_decl) |
| return; |
| |
| context.AddNamedDecl(typedef_decl); |
| |
| return; |
| } |
| |
| void ClangExpressionDeclMap::AddOneType(NameSearchContext &context, |
| TypeFromUser &ut, |
| unsigned int current_id) { |
| CompilerType copied_clang_type = GuardedCopyType(ut); |
| |
| if (!copied_clang_type) { |
| Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); |
| |
| if (log) |
| log->Printf( |
| "ClangExpressionDeclMap::AddOneType - Couldn't import the type"); |
| |
| return; |
| } |
| |
| context.AddTypeDecl(copied_clang_type); |
| } |