mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-19 11:02:59 +02:00
dsymutil: Resolve forward decls for types defined in clang modules.
This patch extends llvm-dsymutil's ODR type uniquing machinery to also resolve forward decls for types defined in clang modules. http://reviews.llvm.org/D13038 llvm-svn: 248398
This commit is contained in:
parent
262b6e0016
commit
b3b6345bb5
@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
// RUN: llvm-dsymutil -f -oso-prepend-path=%p/../Inputs/mismatch \
|
||||
// RUN: -y %p/dummy-debug-map.map -o - 2>&1 | FileCheck %s
|
||||
// RUN: -y %p/dummy-debug-map.map -o %t 2>&1 | FileCheck %s
|
||||
|
||||
@import mismatch;
|
||||
|
||||
|
@ -29,8 +29,13 @@
|
||||
#ifdef BAR_H
|
||||
// ---------------------------------------------------------------------
|
||||
// CHECK: DW_TAG_compile_unit
|
||||
// CHECK-NOT: DW_TAG
|
||||
// CHECK: DW_TAG_module
|
||||
// CHECK-NEXT: DW_AT_name {{.*}}"Bar"
|
||||
// CHECK-NEXT: DW_AT_name{{.*}}"Bar"
|
||||
// CHECK-NOT: DW_TAG
|
||||
// CHECK: 0x0[[BAR:.*]]: DW_TAG_structure_type
|
||||
// CHECK: DW_AT_name {{.*}}"Bar"
|
||||
// CHECK-NOT: DW_TAG
|
||||
// CHECK: DW_TAG_member
|
||||
// CHECK: DW_AT_name {{.*}}"value"
|
||||
|
||||
@ -43,8 +48,10 @@ struct Bar {
|
||||
#ifdef FOO_H
|
||||
// ---------------------------------------------------------------------
|
||||
// CHECK: DW_TAG_compile_unit
|
||||
// CHECK: DW_TAG_module
|
||||
// CHECK-NEXT: DW_AT_name {{.*}}"Foo"
|
||||
// CHECK-NOT: DW_TAG
|
||||
// CHECK: 0x0[[FOO:.*]]: DW_TAG_module
|
||||
// CHECK-NEXT: DW_AT_name{{.*}}"Foo"
|
||||
// CHECK-NOT: DW_TAG
|
||||
// CHECK: DW_TAG_typedef
|
||||
@import Bar;
|
||||
typedef struct Bar Bar;
|
||||
@ -55,6 +62,19 @@ struct S {};
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
// CHECK: DW_TAG_compile_unit
|
||||
// CHECK: DW_TAG_module
|
||||
// CHECK-NEXT: DW_AT_name{{.*}}"Bar"
|
||||
// CHECK: DW_TAG_module
|
||||
// CHECK-NEXT: DW_AT_name{{.*}}"Foo"
|
||||
// CHECK-NOT: DW_TAG
|
||||
// CHECK: DW_TAG_typedef
|
||||
// CHECK-NOT: DW_TAG
|
||||
// CHECK: DW_AT_type [DW_FORM_ref_addr] (0x{{0*}}[[BAR]])
|
||||
//
|
||||
// CHECK: DW_TAG_imported_declaration
|
||||
// CHECK-NOT: DW_TAG
|
||||
// CHECK: DW_AT_import [DW_FORM_ref_addr] (0x{{0*}}[[FOO]]
|
||||
//
|
||||
// CHECK: DW_TAG_subprogram
|
||||
// CHECK: DW_AT_name {{.*}}"main"
|
||||
@import Foo;
|
||||
|
@ -188,13 +188,15 @@ public:
|
||||
DeclContext *Ctxt; ///< ODR Declaration context.
|
||||
DIE *Clone; ///< Cloned version of that DIE.
|
||||
uint32_t ParentIdx; ///< The index of this DIE's parent.
|
||||
bool Keep; ///< Is the DIE part of the linked output?
|
||||
bool InDebugMap; ///< Was this DIE's entity found in the map?
|
||||
bool Keep : 1; ///< Is the DIE part of the linked output?
|
||||
bool InDebugMap : 1;///< Was this DIE's entity found in the map?
|
||||
bool Prune : 1; ///< Is this a pure forward declaration we can strip?
|
||||
};
|
||||
|
||||
CompileUnit(DWARFUnit &OrigUnit, unsigned ID, bool CanUseODR)
|
||||
CompileUnit(DWARFUnit &OrigUnit, unsigned ID, bool CanUseODR,
|
||||
StringRef ClangModuleName)
|
||||
: OrigUnit(OrigUnit), ID(ID), LowPc(UINT64_MAX), HighPc(0), RangeAlloc(),
|
||||
Ranges(RangeAlloc) {
|
||||
Ranges(RangeAlloc), ClangModuleName(ClangModuleName) {
|
||||
Info.resize(OrigUnit.getNumDIEs());
|
||||
|
||||
const auto *CUDie = OrigUnit.getUnitDIE(false);
|
||||
@ -224,6 +226,8 @@ public:
|
||||
void setOutputUnitDIE(DIE *Die) { CUDie = Die; }
|
||||
|
||||
bool hasODR() const { return HasODR; }
|
||||
bool isClangModule() const { return !ClangModuleName.empty(); }
|
||||
const std::string &getClangModuleName() const { return ClangModuleName; }
|
||||
|
||||
DIEInfo &getInfo(unsigned Idx) { return Info[Idx]; }
|
||||
const DIEInfo &getInfo(unsigned Idx) const { return Info[Idx]; }
|
||||
@ -378,11 +382,14 @@ private:
|
||||
bool HasODR;
|
||||
/// Did a DIE actually contain a valid reloc?
|
||||
bool HasInterestingContent;
|
||||
/// If this is a Clang module, this holds the module's name.
|
||||
std::string ClangModuleName;
|
||||
};
|
||||
|
||||
void CompileUnit::markEverythingAsKept() {
|
||||
for (auto &I : Info)
|
||||
I.Keep = true;
|
||||
// Mark everything that wasn't explicity marked for pruning.
|
||||
I.Keep = !I.Prune;
|
||||
}
|
||||
|
||||
uint64_t CompileUnit::computeNextUnitOffset() {
|
||||
@ -1205,7 +1212,8 @@ private:
|
||||
/// Recursively add the debug info in this clang module .pcm
|
||||
/// file (and all the modules imported by it in a bottom-up fashion)
|
||||
/// to Units.
|
||||
void loadClangModule(StringRef Filename, StringRef ModulePath, uint64_t DwoId,
|
||||
void loadClangModule(StringRef Filename, StringRef ModulePath,
|
||||
StringRef ModuleName, uint64_t DwoId,
|
||||
DebugMap &ModuleMap, unsigned Indent = 0);
|
||||
|
||||
/// \brief Flags passed to DwarfLinker::lookForDIEsToKeep
|
||||
@ -1549,8 +1557,9 @@ PointerIntPair<DeclContext *, 1> DeclContextTree::getChildDeclContext(
|
||||
default:
|
||||
// By default stop gathering child contexts.
|
||||
return PointerIntPair<DeclContext *, 1>(nullptr);
|
||||
case dwarf::DW_TAG_module:
|
||||
break;
|
||||
case dwarf::DW_TAG_compile_unit:
|
||||
// FIXME: Add support for DW_TAG_module.
|
||||
return PointerIntPair<DeclContext *, 1>(&Context);
|
||||
case dwarf::DW_TAG_subprogram:
|
||||
// Do not unique anything inside CU local functions.
|
||||
@ -1609,10 +1618,12 @@ PointerIntPair<DeclContext *, 1> DeclContextTree::getChildDeclContext(
|
||||
// creating: File, line number and byte size. This shouldn't be
|
||||
// necessary, because the ODR is just about names, but given that we
|
||||
// do some approximations with overloaded functions and anonymous
|
||||
// namespaces, use these additional data points to make the process safer.
|
||||
// namespaces, use these additional data points to make the process
|
||||
// safer. This is disabled for clang modules, because forward
|
||||
// declarations of module-defined types do not have a file and line.
|
||||
ByteSize = DIE->getAttributeValueAsUnsignedConstant(
|
||||
&U.getOrigUnit(), dwarf::DW_AT_byte_size, UINT64_MAX);
|
||||
if (Tag != dwarf::DW_TAG_namespace || !Name) {
|
||||
if (!U.isClangModule() && (Tag != dwarf::DW_TAG_namespace || !Name)) {
|
||||
if (unsigned FileNum = DIE->getAttributeValueAsUnsignedConstant(
|
||||
&U.getOrigUnit(), dwarf::DW_AT_decl_file, 0)) {
|
||||
if (const auto *LT = U.getOrigUnit().getContext().getLineTableForUnit(
|
||||
@ -1653,11 +1664,16 @@ PointerIntPair<DeclContext *, 1> DeclContextTree::getChildDeclContext(
|
||||
if (!Line && NameRef.empty())
|
||||
return PointerIntPair<DeclContext *, 1>(nullptr);
|
||||
|
||||
// FIXME: dsymutil-classic compat won't unique the same type
|
||||
// presented once as a struct and once as a class. Use the Tag in
|
||||
// the fully qualified name hash to get the same effect.
|
||||
// We hash NameRef, which is the mangled name, in order to get most
|
||||
// overloaded functions resolvec correctly.
|
||||
// overloaded functions resolve correctly.
|
||||
//
|
||||
// Strictly speaking, hashing the Tag is only necessary for a
|
||||
// DW_TAG_module, to prevent uniquing of a module and a namespace
|
||||
// with the same name.
|
||||
//
|
||||
// FIXME: dsymutil-classic won't unique the same type presented
|
||||
// once as a struct and once as a class. Using the Tag in the fully
|
||||
// qualified name hash to get the same effect.
|
||||
unsigned Hash = hash_combine(Context.getQualifiedNameHash(), Tag, NameRef);
|
||||
|
||||
// FIXME: dsymutil-classic compatibility: when we don't have a name,
|
||||
@ -1737,18 +1753,38 @@ bool DwarfLinker::createStreamer(Triple TheTriple, StringRef OutputFilename) {
|
||||
return Streamer->init(TheTriple, OutputFilename);
|
||||
}
|
||||
|
||||
/// \brief Recursive helper to gather the child->parent relationships in the
|
||||
/// original compile unit.
|
||||
static void gatherDIEParents(const DWARFDebugInfoEntryMinimal *DIE,
|
||||
/// Recursive helper to build the global DeclContext information and
|
||||
/// gather the child->parent relationships in the original compile unit.
|
||||
///
|
||||
/// \return true when this DIE and all of its children are only
|
||||
/// forward declarations to types defined in external clang modules
|
||||
/// (i.e., forward declarations that are children of a DW_TAG_module).
|
||||
static bool analyzeContextInfo(const DWARFDebugInfoEntryMinimal *DIE,
|
||||
unsigned ParentIdx, CompileUnit &CU,
|
||||
DeclContext *CurrentDeclContext,
|
||||
NonRelocatableStringpool &StringPool,
|
||||
DeclContextTree &Contexts) {
|
||||
DeclContextTree &Contexts,
|
||||
bool InTagModule = false) {
|
||||
unsigned MyIdx = CU.getOrigUnit().getDIEIndex(DIE);
|
||||
CompileUnit::DIEInfo &Info = CU.getInfo(MyIdx);
|
||||
|
||||
// Clang imposes an ODR on modules(!) regardless of the language:
|
||||
// "The module-id should consist of only a single identifier,
|
||||
// which provides the name of the module being defined. Each
|
||||
// module shall have a single definition."
|
||||
//
|
||||
// This does not extend to the types inside the modules:
|
||||
// "[I]n C, this implies that if two structs are defined in
|
||||
// different submodules with the same name, those two types are
|
||||
// distinct types (but may be compatible types if their
|
||||
// definitions match)."
|
||||
//
|
||||
// We treat non-C++ modules like namespaces for this reason.
|
||||
if (DIE->getTag() == dwarf::DW_TAG_module)
|
||||
InTagModule = true;
|
||||
|
||||
Info.ParentIdx = ParentIdx;
|
||||
if (CU.hasODR()) {
|
||||
if (CU.hasODR() || CU.isClangModule() || InTagModule) {
|
||||
if (CurrentDeclContext) {
|
||||
auto PtrInvalidPair = Contexts.getChildDeclContext(*CurrentDeclContext,
|
||||
DIE, CU, StringPool);
|
||||
@ -1759,11 +1795,21 @@ static void gatherDIEParents(const DWARFDebugInfoEntryMinimal *DIE,
|
||||
Info.Ctxt = CurrentDeclContext = nullptr;
|
||||
}
|
||||
|
||||
Info.Prune = InTagModule;
|
||||
if (DIE->hasChildren())
|
||||
for (auto *Child = DIE->getFirstChild(); Child && !Child->isNULL();
|
||||
Child = Child->getSibling())
|
||||
gatherDIEParents(Child, MyIdx, CU, CurrentDeclContext, StringPool,
|
||||
Contexts);
|
||||
Info.Prune &= analyzeContextInfo(Child, MyIdx, CU, CurrentDeclContext,
|
||||
StringPool, Contexts, InTagModule);
|
||||
|
||||
// Prune this DIE if it is either a forward declaration inside a
|
||||
// DW_TAG_module or a DW_TAG_module that contains nothing but
|
||||
// forward declarations.
|
||||
Info.Prune &= (DIE->getTag() == dwarf::DW_TAG_module) ||
|
||||
DIE->getAttributeValueAsUnsignedConstant(
|
||||
&CU.getOrigUnit(), dwarf::DW_AT_declaration, 0);
|
||||
|
||||
return Info.Prune;
|
||||
}
|
||||
|
||||
static bool dieNeedsChildrenToBeMeaningful(uint32_t Tag) {
|
||||
@ -2148,6 +2194,7 @@ void DwarfLinker::keepDIEAndDependencies(RelocationManager &RelocMgr,
|
||||
Info.Ctxt->getCanonicalDIEOffset() && isODRAttribute(AttrSpec.Attr))
|
||||
continue;
|
||||
|
||||
Info.Prune = false;
|
||||
unsigned ODRFlag = UseODR ? TF_ODR : 0;
|
||||
lookForDIEsToKeep(RelocMgr, *RefDIE, DMO, *ReferencedCU,
|
||||
TF_Keep | TF_DependencyWalk | ODRFlag);
|
||||
@ -2174,6 +2221,8 @@ void DwarfLinker::lookForDIEsToKeep(RelocationManager &RelocMgr,
|
||||
unsigned Idx = CU.getOrigUnit().getDIEIndex(&Die);
|
||||
CompileUnit::DIEInfo &MyInfo = CU.getInfo(Idx);
|
||||
bool AlreadyKept = MyInfo.Keep;
|
||||
if (MyInfo.Prune)
|
||||
return;
|
||||
|
||||
// If the Keep flag is set, we are marking a required DIE's
|
||||
// dependencies. If our target is already marked as kept, we're all
|
||||
@ -2611,7 +2660,8 @@ DIE *DwarfLinker::DIECloner::cloneDIE(
|
||||
Die = Info.Clone = DIE::get(DIEAlloc, dwarf::Tag(InputDIE.getTag()));
|
||||
assert(Die->getTag() == InputDIE.getTag());
|
||||
Die->setOffset(OutOffset);
|
||||
if (Unit.hasODR() && Die->getTag() != dwarf::DW_TAG_namespace && Info.Ctxt &&
|
||||
if ((Unit.hasODR() || Unit.isClangModule()) &&
|
||||
Die->getTag() != dwarf::DW_TAG_namespace && Info.Ctxt &&
|
||||
Info.Ctxt != Unit.getInfo(Info.ParentIdx).Ctxt &&
|
||||
!Info.Ctxt->getCanonicalDIEOffset()) {
|
||||
// We are about to emit a DIE that is the root of its own valid
|
||||
@ -3117,6 +3167,13 @@ bool DwarfLinker::registerModuleReference(
|
||||
CUDie.getAttributeValueAsString(&Unit, dwarf::DW_AT_comp_dir, "");
|
||||
uint64_t DwoId = getDwoId(CUDie, Unit);
|
||||
|
||||
std::string Name =
|
||||
CUDie.getAttributeValueAsString(&Unit, dwarf::DW_AT_name, "");
|
||||
if (Name.empty()) {
|
||||
reportWarning("Anonymous module skeleton CU for " + PCMfile);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Options.Verbose) {
|
||||
outs().indent(Indent);
|
||||
outs() << "Found clang module reference " << PCMfile;
|
||||
@ -3137,7 +3194,7 @@ bool DwarfLinker::registerModuleReference(
|
||||
// Cyclic dependencies are disallowed by Clang, but we still
|
||||
// shouldn't run into an infinite loop, so mark it as processed now.
|
||||
ClangModules.insert({PCMfile, DwoId});
|
||||
loadClangModule(PCMfile, PCMpath, DwoId, ModuleMap, Indent + 2);
|
||||
loadClangModule(PCMfile, PCMpath, Name, DwoId, ModuleMap, Indent + 2);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3157,8 +3214,8 @@ DwarfLinker::loadObject(BinaryHolder &BinaryHolder, DebugMapObject &Obj,
|
||||
}
|
||||
|
||||
void DwarfLinker::loadClangModule(StringRef Filename, StringRef ModulePath,
|
||||
uint64_t DwoId, DebugMap &ModuleMap,
|
||||
unsigned Indent) {
|
||||
StringRef ModuleName, uint64_t DwoId,
|
||||
DebugMap &ModuleMap, unsigned Indent) {
|
||||
SmallString<80> Path(Options.PrependPath);
|
||||
if (sys::path::is_relative(Filename))
|
||||
sys::path::append(Path, ModulePath, Filename);
|
||||
@ -3193,9 +3250,10 @@ void DwarfLinker::loadClangModule(StringRef Filename, StringRef ModulePath,
|
||||
"different version of the module ") + Filename);
|
||||
|
||||
// Add this module.
|
||||
Unit = llvm::make_unique<CompileUnit>(*CU, UnitID++, !Options.NoODR);
|
||||
Unit = llvm::make_unique<CompileUnit>(*CU, UnitID++, !Options.NoODR,
|
||||
ModuleName);
|
||||
Unit->setHasInterestingContent();
|
||||
gatherDIEParents(CUDie, 0, *Unit, &ODRContexts.getRoot(), StringPool,
|
||||
analyzeContextInfo(CUDie, 0, *Unit, &ODRContexts.getRoot(), StringPool,
|
||||
ODRContexts);
|
||||
// Keep everything.
|
||||
Unit->markEverythingAsKept();
|
||||
@ -3291,8 +3349,8 @@ bool DwarfLinker::link(const DebugMap &Map) {
|
||||
CUDie->dump(outs(), CU.get(), 0);
|
||||
}
|
||||
if (!registerModuleReference(*CUDie, *CU, ModuleMap)) {
|
||||
Units.emplace_back(*CU, UnitID++, !Options.NoODR);
|
||||
gatherDIEParents(CUDie, 0, Units.back(), &ODRContexts.getRoot(),
|
||||
Units.emplace_back(*CU, UnitID++, !Options.NoODR, "");
|
||||
analyzeContextInfo(CUDie, 0, Units.back(), &ODRContexts.getRoot(),
|
||||
StringPool, ODRContexts);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user