forked from OSchip/llvm-project
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. <rdar://problem/59514626> Differential Revision: https://reviews.llvm.org/D75585
This commit is contained in:
parent
49d4e0e327
commit
d5180ea134
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<MDString>(1); }
|
||||
MDString *getRawConfigurationMacros() const { return getOperandAs<MDString>(2); }
|
||||
MDString *getRawIncludePath() const { return getOperandAs<MDString>(3); }
|
||||
MDString *getRawAPINotesFile() const { return getOperandAs<MDString>(4); }
|
||||
|
||||
static bool classof(const Metadata *MD) {
|
||||
return MD->getMetadataID() == DIModuleKind;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 << ")";
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<DIScope>(ParentScope), StringRef(Name, NameLen),
|
||||
StringRef(ConfigMacros, ConfigMacrosLen),
|
||||
StringRef(IncludePath, IncludePathLen)));
|
||||
StringRef(IncludePath, IncludePathLen),
|
||||
StringRef(APINotesFile, APINotesFileLen)));
|
||||
}
|
||||
|
||||
LLVMMetadataRef LLVMDIBuilderCreateNameSpace(LLVMDIBuilderRef Builder,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -819,20 +819,23 @@ template <> struct MDNodeKeyImpl<DIModule> {
|
|||
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 {
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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"}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)));
|
||||
|
|
Loading…
Reference in New Issue