https://github.com/Michael137 created https://github.com/llvm/llvm-project/pull/148877
None >From 7f805d67f73d9683d69410895be1d042f0c6da14 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Fri, 15 Nov 2024 01:59:36 +0000 Subject: [PATCH] [lldb][Expression] Encode Module and DIE UIDs into function AsmLabels --- lldb/include/lldb/Expression/Expression.h | 12 ++ lldb/include/lldb/Symbol/SymbolFile.h | 7 + lldb/source/Expression/IRExecutionUnit.cpp | 127 ++++++++++++++++++ .../Clang/ClangExpressionDeclMap.cpp | 2 +- .../Language/CPlusPlus/CPlusPlusLanguage.cpp | 7 +- .../SymbolFile/DWARF/DWARFASTParserClang.cpp | 56 +++++--- .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 52 +++++++ .../SymbolFile/DWARF/SymbolFileDWARF.h | 5 + .../SymbolFile/NativePDB/PdbAstBuilder.cpp | 6 +- .../Plugins/SymbolFile/PDB/PDBASTParser.cpp | 7 +- .../TypeSystem/Clang/TypeSystemClang.cpp | 50 ++++++- .../TypeSystem/Clang/TypeSystemClang.h | 5 +- lldb/unittests/Symbol/TestTypeSystemClang.cpp | 12 +- 13 files changed, 310 insertions(+), 38 deletions(-) diff --git a/lldb/include/lldb/Expression/Expression.h b/lldb/include/lldb/Expression/Expression.h index 8de9364436ccf..a3f1fcc0ef442 100644 --- a/lldb/include/lldb/Expression/Expression.h +++ b/lldb/include/lldb/Expression/Expression.h @@ -96,6 +96,18 @@ class Expression { ///invalid. }; +inline constexpr llvm::StringRef FunctionCallLabelPrefix = "$__lldb_func"; + +inline bool hasFunctionCallLabelPrefix(llvm::StringRef name) { + name.consume_front("_"); + return name.starts_with(FunctionCallLabelPrefix); +} + +inline bool consumeFunctionCallLabelPrefix(llvm::StringRef &name) { + name.consume_front("_"); + return name.consume_front(FunctionCallLabelPrefix); +} + } // namespace lldb_private #endif // LLDB_EXPRESSION_EXPRESSION_H diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h index e95f95553c17c..bfb89721c98c8 100644 --- a/lldb/include/lldb/Symbol/SymbolFile.h +++ b/lldb/include/lldb/Symbol/SymbolFile.h @@ -18,6 +18,7 @@ #include "lldb/Symbol/CompilerType.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/SourceModule.h" +#include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/Type.h" #include "lldb/Symbol/TypeList.h" #include "lldb/Symbol/TypeSystem.h" @@ -328,6 +329,12 @@ class SymbolFile : public PluginInterface { GetMangledNamesForFunction(const std::string &scope_qualified_name, std::vector<ConstString> &mangled_names); + virtual ConstString GetMangledNameForUID(lldb::user_id_t uid) { return {}; } + virtual llvm::Error ResolveFunctionUID(SymbolContextList &sc_list, + lldb::user_id_t uid) { + return llvm::createStringError("Not implemented"); + } + virtual void GetTypes(lldb_private::SymbolContextScope *sc_scope, lldb::TypeClass type_mask, lldb_private::TypeList &type_list) = 0; diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp index e445fa8833022..2edfa661b4e98 100644 --- a/lldb/source/Expression/IRExecutionUnit.cpp +++ b/lldb/source/Expression/IRExecutionUnit.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/StringRef.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/ObjectCache.h" #include "llvm/IR/Constants.h" @@ -19,7 +20,9 @@ #include "lldb/Core/Debugger.h" #include "lldb/Core/Disassembler.h" #include "lldb/Core/Module.h" +#include "lldb/Core/ModuleList.h" #include "lldb/Core/Section.h" +#include "lldb/Expression/Expression.h" #include "lldb/Expression/IRExecutionUnit.h" #include "lldb/Expression/ObjectFileJIT.h" #include "lldb/Host/HostInfo.h" @@ -36,6 +39,7 @@ #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" +#include "lldb/lldb-defines.h" #include <optional> @@ -771,6 +775,123 @@ class LoadAddressResolver { lldb::addr_t m_best_internal_load_address = LLDB_INVALID_ADDRESS; }; +static llvm::Expected<Module *> GetModulePtr(llvm::StringRef module, Target &target) { + uintptr_t module_ptr = 0; + if (module.starts_with("0x") && !module.consumeInteger(0, module_ptr) + && module_ptr != 0) + return reinterpret_cast<Module *>(module_ptr); + + UUID module_uuid; + if (!module_uuid.SetFromStringRef(module) || !module_uuid.IsValid()) + return llvm::createStringError("failed to create Module UUID from '%s'", module.data()); + + Module *found_module = target.GetImages().FindModule(module_uuid).get(); + if (!found_module) + return llvm::createStringError("failed to find module with UUID '{0}'", module.data()); + + return found_module; +} + +static lldb::addr_t +ResolveFunctionCallLabel(llvm::StringRef label, + const lldb_private::SymbolContext &sc, + bool &symbol_was_missing_weak) { + symbol_was_missing_weak = false; + + Target *target = sc.target_sp.get(); + if (!target) { + LLDB_LOG(GetLog(LLDBLog::Expressions), + "Failed to resolve function label '{0}': target not available.", + label); + return LLDB_INVALID_ADDRESS; + } + + if (!consumeFunctionCallLabelPrefix(label)) + return LLDB_INVALID_ADDRESS; + + if (!label.consume_front(":")) { + LLDB_LOG(GetLog(LLDBLog::Expressions), + "Failed to resolve function label '{0}': incorrect format.", + label); + return LLDB_INVALID_ADDRESS; + } + + // Expected format at this point is: <mangled name>:<module + // id>:<definition/declaration DIE id> + // TODO: YES, GetFunction in ResolveFunction requires a definition + // DIE...currently regular functions work because we use definition DIEs? + // ...so if we have a declaration DIE, we should do a lookup by linkage_name + // (or name for constructors) and make sure specification matches. Then we use + // that DIE. + llvm::SmallVector<llvm::StringRef, 3> components; + label.split(components, ":"); + + if (components.size() != 3) { + LLDB_LOG(GetLog(LLDBLog::Expressions), + "Failed to resolve function label '{0}': incorrect format: too " + "many label subcomponents.", + label); + return LLDB_INVALID_ADDRESS; + } + + const auto mangled_name = components[0]; + const auto module = components[1]; + auto die = components[2]; + + // TODO: module UID is only a Darwin concept (?) + auto found_module_or_err = GetModulePtr(module, *target); + if (!found_module_or_err) { + LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions), found_module_or_err.takeError(), + "Failed to resolve function label {1}: {0}", + label); + return LLDB_INVALID_ADDRESS; + } + + Module * found_module = *found_module_or_err; + + lldb::user_id_t die_id; + if (die.consumeInteger(/*Radix=*/0, die_id)) { + LLDB_LOG(GetLog(LLDBLog::Expressions), + "Failed to resolve function label '{0}': failed to parse DIE ID " + "for '{1}'.", + label, components[2]); + return LLDB_INVALID_ADDRESS; + } + + auto *symbol_file = found_module->GetSymbolFile(); + if (!symbol_file) { + LLDB_LOG(GetLog(LLDBLog::Expressions), + "Failed to resolve function label '{0}': no SymbolFile found on " + "module.", + label); + return LLDB_INVALID_ADDRESS; + } + + //// TODO: we probably don't need this + // auto mangled = symbol_file->GetMangledNameForUID(die_id); + // if (!mangled) { + // LLDB_LOG(GetLog(LLDBLog::Expressions), + // "Failed to resolve function label '{0}': failed to get mangled " + // "name for DIE '{1}'.", + // die_id); + // return LLDB_INVALID_ADDRESS; + // } + + // assert(mangled == mangled_name); + + // TODO: API should return SC list item and we should push it back to sc_list + // here. In that case we wouldn't need the sc_list size checks below... + SymbolContextList sc_list; + if (auto err = symbol_file->ResolveFunctionUID(sc_list, die_id)) { + LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions), std::move(err), + "Failed to resolve function by UID: {0}"); + return LLDB_INVALID_ADDRESS; + } + + LoadAddressResolver resolver(target, symbol_was_missing_weak); + return resolver.Resolve(sc_list).value_or(LLDB_INVALID_ADDRESS); +} + lldb::addr_t IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names, const lldb_private::SymbolContext &sc, @@ -796,6 +917,8 @@ IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names, function_options.include_symbols = true; function_options.include_inlines = false; + // TODO: do we need the multiple manglings anymore? + // TODO: do we even need this entire loop anymore? for (const ConstString &name : names) { // The lookup order here is as follows: // 1) Functions in `sc.module_sp` @@ -906,6 +1029,10 @@ lldb::addr_t IRExecutionUnit::FindInUserDefinedSymbols( lldb::addr_t IRExecutionUnit::FindSymbol(lldb_private::ConstString name, bool &missing_weak) { + // llvm::errs() << __func__ << " " << name.AsCString("<<UNNAMED>>") << '\n'; + if (hasFunctionCallLabelPrefix(name.GetStringRef())) + return ResolveFunctionCallLabel(name, m_sym_ctx, missing_weak); + std::vector<ConstString> candidate_C_names; std::vector<ConstString> candidate_CPlusPlus_names; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp index 9f77fbc1d2434..a6c4334bf2e59 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -1991,7 +1991,7 @@ void ClangExpressionDeclMap::AddContextClassType(NameSearchContext &context, const bool is_artificial = false; CXXMethodDecl *method_decl = m_clang_ast_context->AddMethodToCXXRecordType( - copied_clang_type.GetOpaqueQualType(), "$__lldb_expr", nullptr, + copied_clang_type.GetOpaqueQualType(), "$__lldb_expr", std::nullopt, method_type, lldb::eAccessPublic, is_virtual, is_static, is_inline, is_explicit, is_attr_used, is_artificial); diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index 17963c0273ba8..bd95590aed607 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -400,6 +400,11 @@ bool CPlusPlusLanguage::CxxMethodName::TrySimplifiedParse() { // A::B::C::fun(std::vector<T> &) const size_t arg_start, arg_end; llvm::StringRef full(m_full.GetCString()); + + // TODO: check for "operator" in IsTrivialBasename + if (full.starts_with("operator()")) + return false; + llvm::StringRef parens("()", 2); if (ReverseFindMatchingChars(full, parens, arg_start, arg_end)) { m_arguments = full.substr(arg_start, arg_end - arg_start + 1); @@ -438,7 +443,7 @@ bool CPlusPlusLanguage::CxxMethodName::TrySimplifiedParse() { void CPlusPlusLanguage::CxxMethodName::Parse() { if (!m_parsed && m_full) { - if (TrySimplifiedParse()) { + if (false /*TrySimplifiedParse()*/) { m_parse_error = false; } else { CPlusPlusNameParser parser(m_full.GetStringRef()); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index c76d67b47b336..069e817fba798 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -24,6 +24,7 @@ #include "Plugins/Language/ObjC/ObjCLanguage.h" #include "lldb/Core/Module.h" #include "lldb/Core/Value.h" +#include "lldb/Expression/Expression.h" #include "lldb/Host/Host.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" @@ -249,6 +250,41 @@ static unsigned GetCXXMethodCVQuals(const DWARFDIE &subprogram, return cv_quals; } +// TODO: +// 0. Adjust FindInSymbols +// 1. log failure paths +// 2. What happens for functions without a linkage name? Previously we didn't +// attach a label for those but now we would +// 3. Unit-test +// 4. API test (whilch checks expr and AST dump) +static std::optional<std::string> MakeLLDBFuncAsmLabel(const DWARFDIE &die) { + std::optional<std::string> label; + char const *mangled = die.GetMangledName(/*substitute_name_allowed=*/false); + if (mangled) + label.emplace(mangled); + + auto module_sp = die.GetModule(); + if (!module_sp) + return label; + + // Module UID is only a Darwin concept (?) + // If UUID is not available encode as pointer. + // Maybe add character to signal whether this is a pointer + // or UUID. Or maybe if it's not hex that implies a UUID? + auto module_id = module_sp->GetUUID(); + Module * module_ptr = nullptr; + if (!module_id.IsValid()) + module_ptr = module_sp.get(); + + const auto die_id = die.GetID(); + if (die_id == LLDB_INVALID_UID) + return label; + + return llvm::formatv("{0}:{1}:{2}:{3:x}", FunctionCallLabelPrefix, + mangled ? mangled : "", module_ptr ? llvm::formatv("{0:x}", module_ptr).str() : module_id.GetAsString(), die_id) + .str(); +} + TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc, const DWARFDIE &die, Log *log) { @@ -1231,7 +1267,7 @@ std::pair<bool, TypeSP> DWARFASTParserClang::ParseCXXMethod( clang::CXXMethodDecl *cxx_method_decl = m_ast.AddMethodToCXXRecordType( class_opaque_type.GetOpaqueQualType(), attrs.name.GetCString(), - attrs.mangled_name, clang_type, accessibility, attrs.is_virtual, + MakeLLDBFuncAsmLabel(die), clang_type, accessibility, attrs.is_virtual, is_static, attrs.is_inline, attrs.is_explicit, is_attr_used, attrs.is_artificial); @@ -1384,7 +1420,7 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, ignore_containing_context ? m_ast.GetTranslationUnitDecl() : containing_decl_ctx, GetOwningClangModule(die), name, clang_type, attrs.storage, - attrs.is_inline); + attrs.is_inline, MakeLLDBFuncAsmLabel(die)); std::free(name_buf); if (has_template_params) { @@ -1394,7 +1430,7 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, ignore_containing_context ? m_ast.GetTranslationUnitDecl() : containing_decl_ctx, GetOwningClangModule(die), attrs.name.GetStringRef(), clang_type, - attrs.storage, attrs.is_inline); + attrs.storage, attrs.is_inline, /*asm_label=*/std::nullopt); clang::FunctionTemplateDecl *func_template_decl = m_ast.CreateFunctionTemplateDecl( containing_decl_ctx, GetOwningClangModule(die), @@ -1406,20 +1442,6 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, lldbassert(function_decl); if (function_decl) { - // Attach an asm(<mangled_name>) label to the FunctionDecl. - // This ensures that clang::CodeGen emits function calls - // using symbols that are mangled according to the DW_AT_linkage_name. - // If we didn't do this, the external symbols wouldn't exactly - // match the mangled name LLDB knows about and the IRExecutionUnit - // would have to fall back to searching object files for - // approximately matching function names. The motivating - // example is generating calls to ABI-tagged template functions. - // This is done separately for member functions in - // AddMethodToCXXRecordType. - if (attrs.mangled_name) - function_decl->addAttr(clang::AsmLabelAttr::CreateImplicit( - m_ast.getASTContext(), attrs.mangled_name, /*literal=*/false)); - LinkDeclContextToDIE(function_decl, die); const clang::FunctionProtoType *function_prototype( diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 5b16ce5f75138..dea0ec7ad509a 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -11,6 +11,7 @@ #include "llvm/DebugInfo/DWARF/DWARFAddressRange.h" #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/Error.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Support/FormatAdapters.h" #include "llvm/Support/Threading.h" @@ -22,6 +23,7 @@ #include "lldb/Core/Progress.h" #include "lldb/Core/Section.h" #include "lldb/Core/Value.h" +#include "lldb/Symbol/SymbolContext.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/RegularExpression.h" @@ -73,6 +75,7 @@ #include "ManualDWARFIndex.h" #include "SymbolFileDWARFDebugMap.h" #include "SymbolFileDWARFDwo.h" +#include "lldb/lldb-enumerations.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" @@ -2471,6 +2474,51 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die, return false; } +llvm::Error SymbolFileDWARF::ResolveFunctionUID(SymbolContextList &sc_list, + lldb::user_id_t uid) { + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); + auto die = GetDIE(uid); + + if (!die.IsValid()) + return llvm::createStringError( + llvm::formatv("{0}: invalid input DIE", __func__)); + + // TODO: clang indexes by mangled name too...so could technically look up + // by mangled name....but GCC doesn't do that + char const *name = die.GetMangledName(/*substitute_name_allowed=*/true); + if (!name) + return llvm::createStringError( + llvm::formatv("{0}: input DIE has no name", __func__)); + + Module::LookupInfo info(ConstString(name), lldb::eFunctionNameTypeMethod, + lldb::eLanguageTypeUnknown); + m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) { + if (entry.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0)) + return true; + + if (auto spec = entry.GetAttributeValueAsReferenceDIE( + llvm::dwarf::DW_AT_specification); + spec == die) { + die = entry; + return false; + } + + return true; + }); + + if (!ResolveFunction(die, false, sc_list)) + return llvm::createStringError( + llvm::formatv("{0}: failed to resolve function DIE", __func__)); + + if (sc_list.IsEmpty()) + return llvm::createStringError( + llvm::formatv("{0}: no definition DIE found", __func__)); + + assert(sc_list.GetSize() == 1); + + return llvm::Error::success(); +} + bool SymbolFileDWARF::DIEInDeclContext(const CompilerDeclContext &decl_ctx, const DWARFDIE &die, bool only_root_namespaces) { @@ -2958,6 +3006,10 @@ TypeSP SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE( return type_sp; } +// llvm::Expected<DWARFDIE> +// SymbolFileDWARF::FindFunctionDefinitionDIE(const DWARFDIE &die) { +// } + DWARFDIE SymbolFileDWARF::FindDefinitionDIE(const DWARFDIE &die) { const char *name = die.GetName(); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index 2dc862cccca14..f3f6d565f3d4a 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -374,6 +374,8 @@ class SymbolFileDWARF : public SymbolFileCommon { SymbolFileDWARF(const SymbolFileDWARF &) = delete; const SymbolFileDWARF &operator=(const SymbolFileDWARF &) = delete; + // llvm::Expected<DWARFDIE> FindFunctionDefinitionDIE(const DWARFDIE &die); + virtual void LoadSectionData(lldb::SectionType sect_type, DWARFDataExtractor &data); @@ -438,6 +440,9 @@ class SymbolFileDWARF : public SymbolFileCommon { bool ResolveFunction(const DWARFDIE &die, bool include_inlines, SymbolContextList &sc_list); + llvm::Error ResolveFunctionUID(SymbolContextList &sc_list, + lldb::user_id_t uid) override; + /// Resolve functions and (possibly) blocks for the given file address and a /// compile unit. The compile unit comes from the sc argument and it must be /// set. The results of the lookup (if any) are written back to the symbol diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp index 702ec5e5c9ea9..bce721c149fee 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp @@ -88,7 +88,7 @@ struct CreateMethodDecl : public TypeVisitorCallbacks { MethodOptions::CompilerGenerated; function_decl = m_clang.AddMethodToCXXRecordType( parent_ty, proc_name, - /*mangled_name=*/nullptr, func_ct, /*access=*/access_type, + /*mangled_name=*/std::nullopt, func_ct, /*access=*/access_type, /*is_virtual=*/is_virtual, /*is_static=*/is_static, /*is_inline=*/false, /*is_explicit=*/false, /*is_attr_used=*/false, /*is_artificial=*/is_artificial); @@ -903,7 +903,7 @@ PdbAstBuilder::CreateFunctionDecl(PdbCompilandSymId func_id, if (!function_decl) { function_decl = m_clang.AddMethodToCXXRecordType( parent_opaque_ty, func_name, - /*mangled_name=*/nullptr, func_ct, + /*mangled_name=*/std::nullopt, func_ct, /*access=*/lldb::AccessType::eAccessPublic, /*is_virtual=*/false, /*is_static=*/false, /*is_inline=*/false, /*is_explicit=*/false, @@ -913,7 +913,7 @@ PdbAstBuilder::CreateFunctionDecl(PdbCompilandSymId func_id, } else { function_decl = m_clang.CreateFunctionDeclaration( parent, OptionalClangModuleID(), func_name, func_ct, func_storage, - is_inline); + is_inline, /*asm_label=*/std::nullopt); CreateFunctionParameters(func_id, *function_decl, param_count); } return function_decl; diff --git a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp index 0090d8ff03ab6..548a3ed25111f 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp +++ b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp @@ -954,7 +954,8 @@ PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) { auto decl = m_ast.CreateFunctionDeclaration( decl_context, OptionalClangModuleID(), name, - type->GetForwardCompilerType(), storage, func->hasInlineAttribute()); + type->GetForwardCompilerType(), storage, func->hasInlineAttribute(), + /*asm_label=*/std::nullopt); std::vector<clang::ParmVarDecl *> params; if (std::unique_ptr<PDBSymbolTypeFunctionSig> sig = func->getSignature()) { @@ -1446,8 +1447,8 @@ PDBASTParser::AddRecordMethod(lldb_private::SymbolFile &symbol_file, // TODO: get mangled name for the method. return m_ast.AddMethodToCXXRecordType( record_type.GetOpaqueQualType(), name.c_str(), - /*mangled_name*/ nullptr, method_comp_type, access, method.isVirtual(), - method.isStatic(), method.hasInlineAttribute(), + /*mangled_name*/ std::nullopt, method_comp_type, access, + method.isVirtual(), method.isStatic(), method.hasInlineAttribute(), /*is_explicit*/ false, // FIXME: Need this field in CodeView. /*is_attr_used*/ false, /*is_artificial*/ method.isCompilerGenerated()); diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 82e07bb8e0ffb..2bcaca6fa6382 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -2151,7 +2151,8 @@ std::string TypeSystemClang::GetTypeNameForDecl(const NamedDecl *named_decl, FunctionDecl *TypeSystemClang::CreateFunctionDeclaration( clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, llvm::StringRef name, const CompilerType &function_clang_type, - clang::StorageClass storage, bool is_inline) { + clang::StorageClass storage, bool is_inline, + std::optional<std::string> asm_label) { FunctionDecl *func_decl = nullptr; ASTContext &ast = getASTContext(); if (!decl_ctx) @@ -2172,6 +2173,21 @@ FunctionDecl *TypeSystemClang::CreateFunctionDeclaration( func_decl->setConstexprKind(isConstexprSpecified ? ConstexprSpecKind::Constexpr : ConstexprSpecKind::Unspecified); + + // Attach an asm(<mangled_name>) label to the FunctionDecl. + // This ensures that clang::CodeGen emits function calls + // using symbols that are mangled according to the DW_AT_linkage_name. + // If we didn't do this, the external symbols wouldn't exactly + // match the mangled name LLDB knows about and the IRExecutionUnit + // would have to fall back to searching object files for + // approximately matching function names. The motivating + // example is generating calls to ABI-tagged template functions. + // This is done separately for member functions in + // AddMethodToCXXRecordType. + if (asm_label) + func_decl->addAttr(clang::AsmLabelAttr::CreateImplicit(ast, *asm_label, + /*literal=*/false)); + SetOwningModule(func_decl, owning_module); decl_ctx->addDecl(func_decl); @@ -7658,7 +7674,7 @@ TypeSystemClang::CreateParameterDeclarations( clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( lldb::opaque_compiler_type_t type, llvm::StringRef name, - const char *mangled_name, const CompilerType &method_clang_type, + std::optional<std::string> asm_label, const CompilerType &method_clang_type, lldb::AccessType access, bool is_virtual, bool is_static, bool is_inline, bool is_explicit, bool is_attr_used, bool is_artificial) { if (!type || !method_clang_type.IsValid() || name.empty()) @@ -7791,10 +7807,9 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( if (is_attr_used) cxx_method_decl->addAttr(clang::UsedAttr::CreateImplicit(getASTContext())); - if (mangled_name != nullptr) { + if (asm_label) cxx_method_decl->addAttr(clang::AsmLabelAttr::CreateImplicit( - getASTContext(), mangled_name, /*literal=*/false)); - } + getASTContext(), *asm_label, /*literal=*/false)); // Parameters on member function declarations in DWARF generally don't // have names, so we omit them when creating the ParmVarDecls. @@ -9027,6 +9042,27 @@ bool TypeSystemClang::LayoutRecordType( // CompilerDecl override functions +// TODO: remove duplication with the ResolveFunctionCallLabel in +// IRExecutionUnit.cpp +static std::optional<llvm::StringRef> +GetMangledNameFromLLDBFuncLabel(llvm::StringRef label) { + if (!consumeFunctionCallLabelPrefix(label)) + return {}; + + if (!label.consume_front(":")) + return {}; + + // Expected format at this point is: <mangled name>:<module + // id>:<definition/declaration DIE id> + llvm::SmallVector<llvm::StringRef, 3> components; + label.split(components, ":"); + + if (components.size() != 3) + return {}; + + return components[0]; +} + ConstString TypeSystemClang::DeclGetName(void *opaque_decl) { if (opaque_decl) { clang::NamedDecl *nd = @@ -9048,6 +9084,10 @@ ConstString TypeSystemClang::DeclGetMangledName(void *opaque_decl) { if (!mc || !mc->shouldMangleCXXName(nd)) return {}; + if (const auto *label = nd->getAttr<AsmLabelAttr>()) + if (auto name = GetMangledNameFromLLDBFuncLabel(label->getLabel())) + return ConstString(*name); + llvm::SmallVector<char, 1024> buf; llvm::raw_svector_ostream llvm_ostrm(buf); if (llvm::isa<clang::CXXConstructorDecl>(nd)) { diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index 63dee9dceded3..dcf77f9ec1cb8 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -477,7 +477,8 @@ class TypeSystemClang : public TypeSystem { clang::FunctionDecl *CreateFunctionDeclaration( clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, llvm::StringRef name, const CompilerType &function_Type, - clang::StorageClass storage, bool is_inline); + clang::StorageClass storage, bool is_inline, + std::optional<std::string> asm_label); CompilerType CreateFunctionType(const CompilerType &result_type, @@ -1001,7 +1002,7 @@ class TypeSystemClang : public TypeSystem { clang::CXXMethodDecl *AddMethodToCXXRecordType( lldb::opaque_compiler_type_t type, llvm::StringRef name, - const char *mangled_name, const CompilerType &method_type, + std::optional<std::string> mangled_name, const CompilerType &method_type, lldb::AccessType access, bool is_virtual, bool is_static, bool is_inline, bool is_explicit, bool is_attr_used, bool is_artificial); diff --git a/lldb/unittests/Symbol/TestTypeSystemClang.cpp b/lldb/unittests/Symbol/TestTypeSystemClang.cpp index d555d27bef958..c0428a62f7b3d 100644 --- a/lldb/unittests/Symbol/TestTypeSystemClang.cpp +++ b/lldb/unittests/Symbol/TestTypeSystemClang.cpp @@ -869,7 +869,7 @@ TEST_F(TestTypeSystemClang, TestFunctionTemplateConstruction) { CompilerType clang_type = m_ast->CreateFunctionType(int_type, {}, false, 0U); FunctionDecl *func = m_ast->CreateFunctionDeclaration( TU, OptionalClangModuleID(), "foo", clang_type, StorageClass::SC_None, - false); + false, std::nullopt); TypeSystemClang::TemplateParameterInfos empty_params; // Create the actual function template. @@ -900,7 +900,7 @@ TEST_F(TestTypeSystemClang, TestFunctionTemplateInRecordConstruction) { // 2. It is mirroring the behavior of DWARFASTParserClang::ParseSubroutine. FunctionDecl *func = m_ast->CreateFunctionDeclaration( TU, OptionalClangModuleID(), "foo", clang_type, StorageClass::SC_None, - false); + false, std::nullopt); TypeSystemClang::TemplateParameterInfos empty_params; // Create the actual function template. @@ -938,7 +938,7 @@ TEST_F(TestTypeSystemClang, TestDeletingImplicitCopyCstrDueToMoveCStr) { bool is_attr_used = false; bool is_artificial = false; m_ast->AddMethodToCXXRecordType( - t.GetOpaqueQualType(), class_name, nullptr, function_type, + t.GetOpaqueQualType(), class_name, std::nullopt, function_type, lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline, is_explicit, is_attr_used, is_artificial); @@ -975,7 +975,7 @@ TEST_F(TestTypeSystemClang, TestNotDeletingUserCopyCstrDueToMoveCStr) { CompilerType function_type = m_ast->CreateFunctionType( return_type, args, /*variadic=*/false, /*quals*/ 0U); m_ast->AddMethodToCXXRecordType( - t.GetOpaqueQualType(), class_name, nullptr, function_type, + t.GetOpaqueQualType(), class_name, std::nullopt, function_type, lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline, is_explicit, is_attr_used, is_artificial); } @@ -987,7 +987,7 @@ TEST_F(TestTypeSystemClang, TestNotDeletingUserCopyCstrDueToMoveCStr) { m_ast->CreateFunctionType(return_type, args, /*variadic=*/false, /*quals*/ 0U); m_ast->AddMethodToCXXRecordType( - t.GetOpaqueQualType(), class_name, nullptr, function_type, + t.GetOpaqueQualType(), class_name, std::nullopt, function_type, lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline, is_explicit, is_attr_used, is_artificial); } @@ -1098,7 +1098,7 @@ TEST_F(TestTypeSystemClang, AddMethodToCXXRecordType_ParmVarDecls) { m_ast->CreateFunctionType(return_type, param_types, /*variadic=*/false, /*quals*/ 0U); m_ast->AddMethodToCXXRecordType( - t.GetOpaqueQualType(), "myFunc", nullptr, function_type, + t.GetOpaqueQualType(), "myFunc", std::nullopt, function_type, lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline, is_explicit, is_attr_used, is_artificial); _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits