From d5180ea134796f96b0c6c4ab23c592d58f25733d Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Tue, 3 Mar 2020 16:05:23 -0800 Subject: [PATCH] Add debug info support for Swift/Clang APINotes. In order for dsymutil to collect .apinotes files (which capture attributes such as nullability, Swift import names, and availability), I want to propose adding an apinotes: field to DIModule that gets translated into a DW_AT_LLVM_apinotes (path) nested inside DW_TAG_module. This will be primarily used by LLDB to indirectly extract the Swift names of Clang declarations that were deserialized from DWARF. Differential Revision: https://reviews.llvm.org/D75585 --- llvm/include/llvm-c/DebugInfo.h | 5 ++++- llvm/include/llvm/BinaryFormat/Dwarf.def | 4 ++++ llvm/include/llvm/IR/DIBuilder.h | 3 ++- llvm/include/llvm/IR/DebugInfoMetadata.h | 27 ++++++++++++++++++--------- llvm/lib/AsmParser/LLParser.cpp | 10 ++++++---- llvm/lib/Bitcode/Reader/MetadataLoader.cpp | 9 +++++---- llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp | 2 ++ llvm/lib/IR/AsmWriter.cpp | 1 + llvm/lib/IR/DIBuilder.cpp | 5 +++-- llvm/lib/IR/DebugInfo.cpp | 6 ++++-- llvm/lib/IR/DebugInfoMetadata.cpp | 11 ++++++----- llvm/lib/IR/LLVMContextImpl.h | 11 +++++++---- llvm/test/Assembler/dimodule.ll | 7 +++++-- llvm/test/DebugInfo/X86/DIModule.ll | 3 ++- llvm/tools/llvm-c-test/debuginfo.c | 6 ++++-- llvm/unittests/IR/MetadataTest.cpp | 21 +++++++++++++++------ 16 files changed, 88 insertions(+), 43 deletions(-) diff --git a/llvm/include/llvm-c/DebugInfo.h b/llvm/include/llvm-c/DebugInfo.h index f17517b..6170225 100644 --- a/llvm/include/llvm-c/DebugInfo.h +++ b/llvm/include/llvm-c/DebugInfo.h @@ -288,12 +288,15 @@ LLVMDIBuilderCreateFile(LLVMDIBuilderRef Builder, const char *Filename, * \param ConfigMacrosLen The length of the C string passed to \c ConfigMacros. * \param IncludePath The path to the module map file. * \param IncludePathLen The length of the C string passed to \c IncludePath. + * \param APINotesFile The path to an API notes file for the module. + * \param APINotesFileLen The length of the C string passed to \c APINotestFile. */ LLVMMetadataRef LLVMDIBuilderCreateModule(LLVMDIBuilderRef Builder, LLVMMetadataRef ParentScope, const char *Name, size_t NameLen, const char *ConfigMacros, size_t ConfigMacrosLen, - const char *IncludePath, size_t IncludePathLen); + const char *IncludePath, size_t IncludePathLen, + const char *APINotestFile, size_t APINotestFileLen); /** * Creates a new descriptor for a namespace with the specified parent scope. diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.def b/llvm/include/llvm/BinaryFormat/Dwarf.def index 287b70a..f5078b3 100644 --- a/llvm/include/llvm/BinaryFormat/Dwarf.def +++ b/llvm/include/llvm/BinaryFormat/Dwarf.def @@ -412,7 +412,11 @@ HANDLE_DW_AT(0x3e00, LLVM_include_path, 0, LLVM) HANDLE_DW_AT(0x3e01, LLVM_config_macros, 0, LLVM) HANDLE_DW_AT(0x3e02, LLVM_sysroot, 0, LLVM) HANDLE_DW_AT(0x3e03, LLVM_tag_offset, 0, LLVM) +// The missing numbers here are reserved for ptrauth support. +HANDLE_DW_AT(0x3e07, LLVM_apinotes, 0, APPLE) + // Apple extensions. + HANDLE_DW_AT(0x3fe1, APPLE_optimized, 0, APPLE) HANDLE_DW_AT(0x3fe2, APPLE_flags, 0, APPLE) HANDLE_DW_AT(0x3fe3, APPLE_isa, 0, APPLE) diff --git a/llvm/include/llvm/IR/DIBuilder.h b/llvm/include/llvm/IR/DIBuilder.h index 82a9c5e..8885121 100644 --- a/llvm/include/llvm/IR/DIBuilder.h +++ b/llvm/include/llvm/IR/DIBuilder.h @@ -741,9 +741,10 @@ namespace llvm { /// A space-separated shell-quoted list of -D macro /// definitions as they would appear on a command line. /// \param IncludePath The path to the module map file. + /// \param APINotesFile The path to an API notes file for this module. DIModule *createModule(DIScope *Scope, StringRef Name, StringRef ConfigurationMacros, - StringRef IncludePath); + StringRef IncludePath, StringRef APINotesFile = {}); /// This creates a descriptor for a lexical block with a new file /// attached. This merely extends the existing diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h index 3bf78ba..221ff51 100644 --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -2089,31 +2089,38 @@ class DIModule : public DIScope { static DIModule *getImpl(LLVMContext &Context, DIScope *Scope, StringRef Name, StringRef ConfigurationMacros, StringRef IncludePath, - StorageType Storage, bool ShouldCreate = true) { + StringRef APINotesFile, StorageType Storage, + bool ShouldCreate = true) { return getImpl(Context, Scope, getCanonicalMDString(Context, Name), getCanonicalMDString(Context, ConfigurationMacros), getCanonicalMDString(Context, IncludePath), + getCanonicalMDString(Context, APINotesFile), Storage, ShouldCreate); } static DIModule *getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, MDString *ConfigurationMacros, - MDString *IncludePath, StorageType Storage, - bool ShouldCreate = true); + MDString *IncludePath, MDString *APINotesFile, + StorageType Storage, bool ShouldCreate = true); TempDIModule cloneImpl() const { return getTemporary(getContext(), getScope(), getName(), - getConfigurationMacros(), getIncludePath()); + getConfigurationMacros(), getIncludePath(), + getAPINotesFile()); } public: DEFINE_MDNODE_GET(DIModule, (DIScope * Scope, StringRef Name, - StringRef ConfigurationMacros, StringRef IncludePath), - (Scope, Name, ConfigurationMacros, IncludePath)) + StringRef ConfigurationMacros, StringRef IncludePath, + StringRef APINotesFile), + (Scope, Name, ConfigurationMacros, IncludePath, + APINotesFile)) DEFINE_MDNODE_GET(DIModule, - (Metadata *Scope, MDString *Name, MDString *ConfigurationMacros, - MDString *IncludePath), - (Scope, Name, ConfigurationMacros, IncludePath)) + (Metadata * Scope, MDString *Name, + MDString *ConfigurationMacros, MDString *IncludePath, + MDString *APINotesFile), + (Scope, Name, ConfigurationMacros, IncludePath, + APINotesFile)) TempDIModule clone() const { return cloneImpl(); } @@ -2121,11 +2128,13 @@ public: StringRef getName() const { return getStringOperand(1); } StringRef getConfigurationMacros() const { return getStringOperand(2); } StringRef getIncludePath() const { return getStringOperand(3); } + StringRef getAPINotesFile() const { return getStringOperand(4); } Metadata *getRawScope() const { return getOperand(0); } MDString *getRawName() const { return getOperandAs(1); } MDString *getRawConfigurationMacros() const { return getOperandAs(2); } MDString *getRawIncludePath() const { return getOperandAs(3); } + MDString *getRawAPINotesFile() const { return getOperandAs(4); } static bool classof(const Metadata *MD) { return MD->getMetadataID() == DIModuleKind; diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index 86313cd..d219f60 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -4827,18 +4827,20 @@ bool LLParser::ParseDIMacroFile(MDNode *&Result, bool IsDistinct) { /// ParseDIModule: /// ::= !DIModule(scope: !0, name: "SomeModule", configMacros: "-DNDEBUG", -/// includePath: "/usr/include") +/// includePath: "/usr/include", apinotes: "module.apinotes") bool LLParser::ParseDIModule(MDNode *&Result, bool IsDistinct) { #define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ REQUIRED(scope, MDField, ); \ REQUIRED(name, MDStringField, ); \ OPTIONAL(configMacros, MDStringField, ); \ - OPTIONAL(includePath, MDStringField, ); + OPTIONAL(includePath, MDStringField, ); \ + OPTIONAL(apinotes, MDStringField, ); PARSE_MD_FIELDS(); #undef VISIT_MD_FIELDS - Result = GET_OR_DISTINCT(DIModule, (Context, scope.Val, name.Val, - configMacros.Val, includePath.Val)); + Result = + GET_OR_DISTINCT(DIModule, (Context, scope.Val, name.Val, configMacros.Val, + includePath.Val, apinotes.Val)); return false; } diff --git a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp index 17778e7..c1fa91d 100644 --- a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp +++ b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp @@ -1418,14 +1418,15 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata( } case bitc::METADATA_MODULE: { - if (Record.size() < 5 || Record.size() > 6) + if (Record.size() < 5 || Record.size() > 7) return error("Invalid record"); IsDistinct = Record[0]; MetadataList.assignValue( - GET_OR_DISTINCT( - DIModule, (Context, getMDOrNull(Record[1]), getMDString(Record[2]), - getMDString(Record[3]), getMDString(Record[4]))), + GET_OR_DISTINCT(DIModule, + (Context, getMDOrNull(Record[1]), + getMDString(Record[2]), getMDString(Record[3]), + getMDString(Record[4]), getMDString(Record[5]))), NextMetadataNo); NextMetadataNo++; break; diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index 134ef74..9136264 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -1126,6 +1126,8 @@ DIE *DwarfUnit::getOrCreateModule(const DIModule *M) { M->getConfigurationMacros()); if (!M->getIncludePath().empty()) addString(MDie, dwarf::DW_AT_LLVM_include_path, M->getIncludePath()); + if (!M->getAPINotesFile().empty()) + addString(MDie, dwarf::DW_AT_LLVM_apinotes, M->getAPINotesFile()); return &MDie; } diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp index ea603a6..733fc10 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -2061,6 +2061,7 @@ static void writeDIModule(raw_ostream &Out, const DIModule *N, Printer.printString("name", N->getName()); Printer.printString("configMacros", N->getConfigurationMacros()); Printer.printString("includePath", N->getIncludePath()); + Printer.printString("apinotes", N->getAPINotesFile()); Out << ")"; } diff --git a/llvm/lib/IR/DIBuilder.cpp b/llvm/lib/IR/DIBuilder.cpp index 2fcdcd9..b6446f4 100644 --- a/llvm/lib/IR/DIBuilder.cpp +++ b/llvm/lib/IR/DIBuilder.cpp @@ -831,9 +831,10 @@ DINamespace *DIBuilder::createNameSpace(DIScope *Scope, StringRef Name, DIModule *DIBuilder::createModule(DIScope *Scope, StringRef Name, StringRef ConfigurationMacros, - StringRef IncludePath) { + StringRef IncludePath, + StringRef APINotesFile) { return DIModule::get(VMContext, getNonCompileUnitScope(Scope), Name, - ConfigurationMacros, IncludePath); + ConfigurationMacros, IncludePath, APINotesFile); } DILexicalBlockFile *DIBuilder::createLexicalBlockFile(DIScope *Scope, diff --git a/llvm/lib/IR/DebugInfo.cpp b/llvm/lib/IR/DebugInfo.cpp index f893ea9..aaa8443 100644 --- a/llvm/lib/IR/DebugInfo.cpp +++ b/llvm/lib/IR/DebugInfo.cpp @@ -791,11 +791,13 @@ LLVMMetadataRef LLVMDIBuilderCreateModule(LLVMDIBuilderRef Builder, LLVMMetadataRef ParentScope, const char *Name, size_t NameLen, const char *ConfigMacros, size_t ConfigMacrosLen, - const char *IncludePath, size_t IncludePathLen) { + const char *IncludePath, size_t IncludePathLen, + const char *APINotesFile, size_t APINotesFileLen) { return wrap(unwrap(Builder)->createModule( unwrapDI(ParentScope), StringRef(Name, NameLen), StringRef(ConfigMacros, ConfigMacrosLen), - StringRef(IncludePath, IncludePathLen))); + StringRef(IncludePath, IncludePathLen), + StringRef(APINotesFile, APINotesFileLen))); } LLVMMetadataRef LLVMDIBuilderCreateNameSpace(LLVMDIBuilderRef Builder, diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index 48e38db..0c0ea50 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -717,12 +717,13 @@ DICommonBlock *DICommonBlock::getImpl(LLVMContext &Context, Metadata *Scope, DIModule *DIModule::getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, MDString *ConfigurationMacros, - MDString *IncludePath, StorageType Storage, - bool ShouldCreate) { + MDString *IncludePath, MDString *APINotesFile, + StorageType Storage, bool ShouldCreate) { assert(isCanonical(Name) && "Expected canonical MDString"); - DEFINE_GETIMPL_LOOKUP(DIModule, - (Scope, Name, ConfigurationMacros, IncludePath)); - Metadata *Ops[] = {Scope, Name, ConfigurationMacros, IncludePath}; + DEFINE_GETIMPL_LOOKUP( + DIModule, (Scope, Name, ConfigurationMacros, IncludePath, APINotesFile)); + Metadata *Ops[] = {Scope, Name, ConfigurationMacros, IncludePath, + APINotesFile}; DEFINE_GETIMPL_STORE_NO_CONSTRUCTOR_ARGS(DIModule, Ops); } diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h index 7f324b1..e136bd5 100644 --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -819,20 +819,23 @@ template <> struct MDNodeKeyImpl { MDString *Name; MDString *ConfigurationMacros; MDString *IncludePath; + MDString *APINotesFile; MDNodeKeyImpl(Metadata *Scope, MDString *Name, MDString *ConfigurationMacros, - MDString *IncludePath) + MDString *IncludePath, MDString *APINotesFile) : Scope(Scope), Name(Name), ConfigurationMacros(ConfigurationMacros), - IncludePath(IncludePath) {} + IncludePath(IncludePath), APINotesFile(APINotesFile) {} MDNodeKeyImpl(const DIModule *N) : Scope(N->getRawScope()), Name(N->getRawName()), ConfigurationMacros(N->getRawConfigurationMacros()), - IncludePath(N->getRawIncludePath()) {} + IncludePath(N->getRawIncludePath()), + APINotesFile(N->getRawAPINotesFile()) {} bool isKeyOf(const DIModule *RHS) const { return Scope == RHS->getRawScope() && Name == RHS->getRawName() && ConfigurationMacros == RHS->getRawConfigurationMacros() && - IncludePath == RHS->getRawIncludePath(); + IncludePath == RHS->getRawIncludePath() && + APINotesFile == RHS->getRawAPINotesFile(); } unsigned getHashValue() const { diff --git a/llvm/test/Assembler/dimodule.ll b/llvm/test/Assembler/dimodule.ll index cc5f013..c3802ea 100644 --- a/llvm/test/Assembler/dimodule.ll +++ b/llvm/test/Assembler/dimodule.ll @@ -1,8 +1,8 @@ ; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s ; RUN: verify-uselistorder %s -; CHECK: !named = !{!0, !1, !2, !1} -!named = !{!0, !1, !2, !3} +; CHECK: !named = !{!0, !1, !2, !1, !3} +!named = !{!0, !1, !2, !3, !4} !0 = distinct !{} @@ -13,3 +13,6 @@ !2 = !DIModule(scope: !0, name: "Module", configMacros: "-DNDEBUG", includePath: "/usr/include") !3 = !DIModule(scope: !0, name: "Module", configMacros: "") + +; CHECK: !3 = !DIModule(scope: !0, name: "Module", configMacros: "-DNDEBUG", includePath: "/usr/include", apinotes: "/tmp/m.apinotes") +!4 = !DIModule(scope: !0, name: "Module", configMacros: "-DNDEBUG", includePath: "/usr/include", apinotes: "/tmp/m.apinotes") diff --git a/llvm/test/DebugInfo/X86/DIModule.ll b/llvm/test/DebugInfo/X86/DIModule.ll index 4aa785a..fadd38d 100644 --- a/llvm/test/DebugInfo/X86/DIModule.ll +++ b/llvm/test/DebugInfo/X86/DIModule.ll @@ -9,6 +9,7 @@ ; CHECK-NEXT: DW_AT_name {{.*}}"DebugModule" ; CHECK-NEXT: DW_AT_LLVM_config_macros {{.*}}"-DMODULES=0" ; CHECK-NEXT: DW_AT_LLVM_include_path {{.*}}"/llvm/tools/clang/test/Modules/Inputs" +; CHECK-NEXT: DW_AT_LLVM_apinotes {{.*}}"m.apinotes" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx" @@ -22,7 +23,7 @@ target triple = "x86_64-apple-macosx" !2 = !{} !3 = !{!4} !4 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !5, file: !1, line: 5) -!5 = !DIModule(scope: null, name: "DebugModule", configMacros: "-DMODULES=0", includePath: "/llvm/tools/clang/test/Modules/Inputs") +!5 = !DIModule(scope: null, name: "DebugModule", configMacros: "-DMODULES=0", includePath: "/llvm/tools/clang/test/Modules/Inputs", apinotes: "m.apinotes") !6 = !{i32 2, !"Dwarf Version", i32 4} !7 = !{i32 2, !"Debug Info Version", i32 3} !8 = !{!"LLVM version 3.7.0"} diff --git a/llvm/tools/llvm-c-test/debuginfo.c b/llvm/tools/llvm-c-test/debuginfo.c index 6ae1f19..994bd53 100644 --- a/llvm/tools/llvm-c-test/debuginfo.c +++ b/llvm/tools/llvm-c-test/debuginfo.c @@ -44,13 +44,15 @@ int llvm_test_dibuilder(void) { LLVMDIBuilderCreateModule(DIB, CompileUnit, "llvm-c-test", 11, "", 0, - "/test/include/llvm-c-test.h", 27); + "/test/include/llvm-c-test.h", 27, + "", 0); LLVMMetadataRef OtherModule = LLVMDIBuilderCreateModule(DIB, CompileUnit, "llvm-c-test-import", 18, "", 0, - "/test/include/llvm-c-test-import.h", 34); + "/test/include/llvm-c-test-import.h", 34, + "", 0); LLVMMetadataRef ImportedModule = LLVMDIBuilderCreateImportedModuleFromModule(DIB, Module, OtherModule, File, 42); diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp index 0f71097..e886c77 100644 --- a/llvm/unittests/IR/MetadataTest.cpp +++ b/llvm/unittests/IR/MetadataTest.cpp @@ -2057,19 +2057,28 @@ TEST_F(DIModuleTest, get) { StringRef Name = "module"; StringRef ConfigMacro = "-DNDEBUG"; StringRef Includes = "-I."; + StringRef APINotes = "/tmp/m.apinotes"; - auto *N = DIModule::get(Context, Scope, Name, ConfigMacro, Includes); + auto *N = DIModule::get(Context, Scope, Name, ConfigMacro, Includes, APINotes); EXPECT_EQ(dwarf::DW_TAG_module, N->getTag()); EXPECT_EQ(Scope, N->getScope()); EXPECT_EQ(Name, N->getName()); EXPECT_EQ(ConfigMacro, N->getConfigurationMacros()); EXPECT_EQ(Includes, N->getIncludePath()); - EXPECT_EQ(N, DIModule::get(Context, Scope, Name, ConfigMacro, Includes)); - EXPECT_NE(N, DIModule::get(Context, getFile(), Name, ConfigMacro, Includes)); - EXPECT_NE(N, DIModule::get(Context, Scope, "other", ConfigMacro, Includes)); - EXPECT_NE(N, DIModule::get(Context, Scope, Name, "other", Includes)); - EXPECT_NE(N, DIModule::get(Context, Scope, Name, ConfigMacro, "other")); + EXPECT_EQ(APINotes, N->getAPINotesFile()); + EXPECT_EQ( + N, DIModule::get(Context, Scope, Name, ConfigMacro, Includes, APINotes)); + EXPECT_NE(N, DIModule::get(Context, getFile(), Name, ConfigMacro, Includes, + APINotes)); + EXPECT_NE(N, DIModule::get(Context, Scope, "other", ConfigMacro, Includes, + APINotes)); + EXPECT_NE(N, + DIModule::get(Context, Scope, Name, "other", Includes, APINotes)); + EXPECT_NE( + N, DIModule::get(Context, Scope, Name, ConfigMacro, "other", APINotes)); + EXPECT_NE( + N, DIModule::get(Context, Scope, Name, ConfigMacro, Includes, "other")); TempDIModule Temp = N->clone(); EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); -- 2.7.4