| //===-- 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/Error.h" |
| #include "lldb/Core/Log.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/Host/Endian.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/lldb-private.h" |
| #include "clang/AST/ASTConsumer.h" |
| #include "clang/AST/ASTContext.h" |
| #include "clang/AST/Decl.h" |
| #include "clang/AST/DeclarationName.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; |
| } |
| |
| 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) { |
| Error err; |
| |
| ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx; |
| Target *target = exe_ctx.GetTargetPtr(); |
| if (target == nullptr) |
| return false; |
| |
| ClangASTContext *context(target->GetScratchClangASTContext()); |
| |
| TypeFromUser user_type(m_ast_importer_sp->DeportType( |
| context->getASTContext(), ast->getASTContext(), |
| parser_type.GetOpaqueQualType()), |
| context); |
| |
| 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(m_ast_importer_sp->DeportType( |
| context->getASTContext(), ast->getASTContext(), |
| parser_type.GetOpaqueQualType()), |
| context); |
| |
| 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; |
| |
| Error 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); |
| } |
| |
| const Symbol *ClangExpressionDeclMap::FindGlobalDataSymbol( |
| Target &target, const ConstString &name, lldb_private::Module *module) { |
| SymbolContextList sc_list; |
| |
| if (module) |
| module->FindSymbolsWithNameAndType(name, eSymbolTypeAny, sc_list); |
| else |
| target.GetImages().FindSymbolsWithNameAndType(name, eSymbolTypeAny, |
| sc_list); |
| |
| const uint32_t matches = sc_list.GetSize(); |
| for (uint32_t i = 0; i < matches; ++i) { |
| SymbolContext sym_ctx; |
| sc_list.GetContextAtIndex(i, sym_ctx); |
| if (sym_ctx.symbol) { |
| const Symbol *symbol = sym_ctx.symbol; |
| const Address sym_address = symbol->GetAddress(); |
| |
| if (sym_address.IsValid()) { |
| switch (symbol->GetType()) { |
| case eSymbolTypeData: |
| case eSymbolTypeRuntime: |
| case eSymbolTypeAbsolute: |
| case eSymbolTypeObjCClass: |
| case eSymbolTypeObjCMetaClass: |
| case eSymbolTypeObjCIVar: |
| if (symbol->GetDemangledNameIsSynthesized()) { |
| // If the demangled name was synthesized, then don't use it |
| // for expressions. Only let the symbol match if the mangled |
| // named matches for these symbols. |
| if (symbol->GetMangled().GetMangledName() != name) |
| break; |
| } |
| return symbol; |
| |
| case eSymbolTypeReExported: { |
| ConstString reexport_name = symbol->GetReExportedSymbolName(); |
| if (reexport_name) { |
| ModuleSP reexport_module_sp; |
| ModuleSpec reexport_module_spec; |
| reexport_module_spec.GetPlatformFileSpec() = |
| 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); |
| } |
| } |
| // Don't allow us to try and resolve a re-exported symbol if it is |
| // the same |
| // as the current symbol |
| if (name == symbol->GetReExportedSymbolName() && |
| module == reexport_module_sp.get()) |
| return NULL; |
| |
| return FindGlobalDataSymbol(target, |
| symbol->GetReExportedSymbolName(), |
| reexport_module_sp.get()); |
| } |
| } break; |
| |
| case eSymbolTypeCode: // We already lookup functions elsewhere |
| case eSymbolTypeVariable: |
| case eSymbolTypeLocal: |
| case eSymbolTypeParam: |
| case eSymbolTypeTrampoline: |
| case eSymbolTypeInvalid: |
| 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 eSymbolTypeResolver: |
| break; |
| } |
| } |
| } |
| } |
| |
| return NULL; |
| } |
| |
| 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, true, -1, vars); |
| else |
| target.GetImages().FindGlobalVariables(name, true, -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->GetNamespaceMap(namespace_context); |
| |
| 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()); |
| |
| if (!namespace_map) |
| return; |
| |
| 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); |
| } |
| |
| if (!context.m_found.variable && !context.m_found.local_vars_nsp) |
| 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()); |
| |
| const char *name_unique_cstr = name.GetCString(); |
| |
| if (name_unique_cstr == NULL) |
| return; |
| |
| static ConstString id_name("id"); |
| static ConstString Class_name("Class"); |
| |
| if (name == id_name || name == Class_name) |
| 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 = m_ast_importer_sp->CopyDecl( |
| m_ast_context, scratch_ast_context, 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_unique_cstr[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_unique_cstr, 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 (!::strncmp(name_unique_cstr, "$__lldb", sizeof("$__lldb") - 1)) |
| 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 = 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); |
| } |
| } |
| |
| if (!context.m_found.variable) { |
| 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>(m_ast_importer_sp->CopyDecl( |
| m_ast_context, &decl->getASTContext(), 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 = m_ast_importer_sp->CopyDecl( |
| m_ast_context, &decl_from_modules->getASTContext(), |
| 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 = m_ast_importer_sp->CopyDecl( |
| m_ast_context, &decl_from_modules->getASTContext(), |
| 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. |
| |
| const Symbol *data_symbol = FindGlobalDataSymbol(*target, name); |
| |
| 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; |
| } |
| } |
| } |
| } |
| } |
| |
| // static opaque_compiler_type_t |
| // MaybePromoteToBlockPointerType |
| //( |
| // ASTContext *ast_context, |
| // opaque_compiler_type_t candidate_type |
| //) |
| //{ |
| // if (!candidate_type) |
| // return candidate_type; |
| // |
| // QualType candidate_qual_type = QualType::getFromOpaquePtr(candidate_type); |
| // |
| // const PointerType *candidate_pointer_type = |
| // dyn_cast<PointerType>(candidate_qual_type); |
| // |
| // if (!candidate_pointer_type) |
| // return candidate_type; |
| // |
| // QualType pointee_qual_type = candidate_pointer_type->getPointeeType(); |
| // |
| // const RecordType *pointee_record_type = |
| // dyn_cast<RecordType>(pointee_qual_type); |
| // |
| // if (!pointee_record_type) |
| // return candidate_type; |
| // |
| // RecordDecl *pointee_record_decl = pointee_record_type->getDecl(); |
| // |
| // if (!pointee_record_decl->isRecord()) |
| // return candidate_type; |
| // |
| // if |
| // (!pointee_record_decl->getName().startswith(llvm::StringRef("__block_literal_"))) |
| // return candidate_type; |
| // |
| // QualType generic_function_type = |
| // ast_context->getFunctionNoProtoType(ast_context->UnknownAnyTy); |
| // QualType block_pointer_type = |
| // ast_context->getBlockPointerType(generic_function_type); |
| // |
| // return block_pointer_type.getAsOpaquePtr(); |
| //} |
| |
| 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; |
| } |
| // var_clang_type = MaybePromoteToBlockPointerType (ast, var_clang_type); |
| |
| DWARFExpression &var_location_expr = var->LocationExpression(); |
| |
| Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr(); |
| Error 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(); |
| |
| ClangASTContext *scratch_ast_context = 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 = m_ast_importer_sp->CopyType( |
| scratch_ast_context->getASTContext(), &var_decl->getASTContext(), |
| var_type.getAsOpaquePtr()); |
| |
| 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 lldb::LanguageType comp_unit_language = |
| function->GetCompileUnit()->GetLanguage(); |
| const bool extern_c = Language::LanguageIsC(comp_unit_language) || |
| (Language::LanguageIsObjC(comp_unit_language) && |
| !Language::LanguageIsCPlusPlus(comp_unit_language)); |
| |
| if (!extern_c) { |
| TypeSystem *type_system = function->GetDeclContext().GetTypeSystem(); |
| if (ClangASTContext *src_ast = |
| llvm::dyn_cast<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) { |
| if (clang::FunctionDecl *copied_function_decl = |
| llvm::dyn_cast_or_null<clang::FunctionDecl>( |
| m_ast_importer_sp->CopyDecl(m_ast_context, |
| src_ast->getASTContext(), |
| 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) { |
| ASTDumper ast_dumper(function_decl); |
| |
| 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(), ast_dumper.GetCString()); |
| } |
| } |
| |
| 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", |
| 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); |
| } |