#include "MachOUtils.h"
#include "NonRelocatableStringpool.h"
#include "llvm/ADT/IntervalMap.h"
-#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/DIE.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCTargetOptionsCommandFlags.h"
#include "llvm/Object/MachO.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/LEB128.h"
/// required strings will be interned in \a StringPool.
/// \returns The child DeclContext along with one bit that is set if
/// this context is invalid.
- /// FIXME: the invalid bit along the return value is to emulate some
- /// dsymutil-classic functionality. See the fucntion definition for
- /// a more thorough discussion of its use.
+ /// An invalid context means it shouldn't be considered for uniquing, but its
+ /// not returning null, because some children of that context might be
+ /// uniquing candidates. FIXME: The invalid bit along the return value is to
+ /// emulate some dsymutil-classic functionality.
PointerIntPair<DeclContext *, 1>
getChildDeclContext(DeclContext &Context,
const DWARFDebugInfoEntryMinimal *DIE, CompileUnit &Unit,
- NonRelocatableStringpool &StringPool);
+ NonRelocatableStringpool &StringPool, bool InClangModule);
DeclContext &getRoot() { return Root; }
};
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);
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]; }
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() {
/// \brief Emit the abbreviation table \p Abbrevs to the
/// debug_abbrev section.
- void emitAbbrevs(const std::vector<DIEAbbrev *> &Abbrevs);
+ void emitAbbrevs(const std::vector<std::unique_ptr<DIEAbbrev>> &Abbrevs);
/// \brief Emit the string table described by \p Pool.
void emitStrings(const NonRelocatableStringpool &Pool);
if (EC)
return error(Twine(OutputFilename) + ": " + EC.message(), Context);
- MS = TheTarget->createMCObjectStreamer(TheTriple, *MC, *MAB, *OutFile, MCE,
- *MSTI, false,
- /*DWARFMustBeAtTheEnd*/ false);
+ MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags();
+ MS = TheTarget->createMCObjectStreamer(
+ TheTriple, *MC, *MAB, *OutFile, MCE, *MSTI, MCOptions.MCRelaxAll,
+ MCOptions.MCIncrementalLinkerCompatible,
+ /*DWARFMustBeAtTheEnd*/ false);
if (!MS)
return error("no object streamer for target " + TripleName, Context);
/// \brief Emit the \p Abbrevs array as the shared abbreviation table
/// for the linked Dwarf file.
-void DwarfStreamer::emitAbbrevs(const std::vector<DIEAbbrev *> &Abbrevs) {
+void DwarfStreamer::emitAbbrevs(
+ const std::vector<std::unique_ptr<DIEAbbrev>> &Abbrevs) {
MS->SwitchSection(MOFI->getDwarfAbbrevSection());
Asm->emitDwarfAbbrevs(Abbrevs);
}
: OutputFilename(OutputFilename), Options(Options),
BinHolder(Options.Verbose), LastCIEOffset(0) {}
- ~DwarfLinker() {
- for (auto *Abbrev : Abbreviations)
- delete Abbrev;
- }
-
/// \brief Link the contents of the DebugMap.
bool link(const DebugMap &);
/// file (and all the modules imported by it in a bottom-up fashion)
/// to Units.
void loadClangModule(StringRef Filename, StringRef ModulePath,
+ StringRef ModuleName, uint64_t DwoId,
DebugMap &ModuleMap, unsigned Indent = 0);
/// \brief Flags passed to DwarfLinker::lookForDIEsToKeep
/// \brief Storage for the unique Abbreviations.
/// This is passed to AsmPrinter::emitDwarfAbbrevs(), thus it cannot
/// be changed to a vecot of unique_ptrs.
- std::vector<DIEAbbrev *> Abbreviations;
+ std::vector<std::unique_ptr<DIEAbbrev>> Abbreviations;
/// \brief Compute and emit debug_ranges section for \p Unit, and
/// patch the attributes referencing it.
/// The units of the current debug map object.
std::vector<CompileUnit> Units;
- /// The debug map object curently under consideration.
+ /// The debug map object currently under consideration.
DebugMapObject *CurrentDebugObject;
/// \brief The Dwarf string pool
/// debug_frame section.
uint32_t LastCIEOffset;
- /// FIXME: We may need to use something more resilient than the PCM filename.
- StringSet<> ClangModules;
+ /// Mapping the PCM filename to the DwoId.
+ StringMap<uint64_t> ClangModules;
};
/// Similar to DWARFUnitSection::getUnitForOffset(), but returning our
return true;
}
-/// Get the child context of \a Context corresponding to \a DIE.
-///
-/// \returns the child context or null if we shouldn't track children
-/// contexts. It also returns an additional bit meaning 'invalid'. An
-/// invalid context means it shouldn't be considered for uniquing, but
-/// its not returning null, because some children of that context
-/// might be uniquing candidates.
-/// FIXME: this is for dsymutil-classic compatibility, I don't think
-/// it buys us much.
PointerIntPair<DeclContext *, 1> DeclContextTree::getChildDeclContext(
DeclContext &Context, const DWARFDebugInfoEntryMinimal *DIE, CompileUnit &U,
- NonRelocatableStringpool &StringPool) {
+ NonRelocatableStringpool &StringPool, bool InClangModule) {
unsigned Tag = DIE->getTag();
// FIXME: dsymutil-classic compat: We should bail out here if we
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.
std::string File;
unsigned Line = 0;
- unsigned ByteSize = 0;
-
- // Gather some discriminating data about the DeclContext we will be
- // 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.
- ByteSize = DIE->getAttributeValueAsUnsignedConstant(
- &U.getOrigUnit(), dwarf::DW_AT_byte_size, UINT64_MAX);
- if (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(
- &U.getOrigUnit())) {
- // FIXME: dsymutil-classic compatibility. I'd rather not
- // unique anything in anonymous namespaces, but if we do, then
- // verify that the file and line correspond.
- if (!Name && Tag == dwarf::DW_TAG_namespace)
- FileNum = 1;
-
- // FIXME: Passing U.getOrigUnit().getCompilationDir()
- // instead of "" would allow more uniquing, but for now, do
- // it this way to match dsymutil-classic.
- if (LT->getFileNameByIndex(
- FileNum, "",
- DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath,
- File)) {
- Line = DIE->getAttributeValueAsUnsignedConstant(
- &U.getOrigUnit(), dwarf::DW_AT_decl_line, 0);
+ unsigned ByteSize = UINT32_MAX;
+
+ if (!InClangModule) {
+ // Gather some discriminating data about the DeclContext we will be
+ // 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. 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 (unsigned FileNum = DIE->getAttributeValueAsUnsignedConstant(
+ &U.getOrigUnit(), dwarf::DW_AT_decl_file, 0)) {
+ if (const auto *LT = U.getOrigUnit().getContext().getLineTableForUnit(
+ &U.getOrigUnit())) {
+ // FIXME: dsymutil-classic compatibility. I'd rather not
+ // unique anything in anonymous namespaces, but if we do, then
+ // verify that the file and line correspond.
+ if (!Name && Tag == dwarf::DW_TAG_namespace)
+ FileNum = 1;
+
+ // FIXME: Passing U.getOrigUnit().getCompilationDir()
+ // instead of "" would allow more uniquing, but for now, do
+ // it this way to match dsymutil-classic.
+ if (LT->getFileNameByIndex(
+ FileNum, "",
+ DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath,
+ File)) {
+ Line = DIE->getAttributeValueAsUnsignedConstant(
+ &U.getOrigUnit(), dwarf::DW_AT_decl_line, 0);
#ifdef HAVE_REALPATH
- // Cache the resolved paths, because calling realpath is expansive.
- if (const char *ResolvedPath = U.getResolvedPath(FileNum)) {
- File = ResolvedPath;
- } else {
- char RealPath[PATH_MAX + 1];
- RealPath[PATH_MAX] = 0;
- if (::realpath(File.c_str(), RealPath))
- File = RealPath;
- U.setResolvedPath(FileNum, File);
- }
+ // Cache the resolved paths, because calling realpath is expansive.
+ if (const char *ResolvedPath = U.getResolvedPath(FileNum)) {
+ File = ResolvedPath;
+ } else {
+ char RealPath[PATH_MAX + 1];
+ RealPath[PATH_MAX] = 0;
+ if (::realpath(File.c_str(), RealPath))
+ File = RealPath;
+ U.setResolvedPath(FileNum, File);
+ }
#endif
- FileRef = StringPool.internString(File);
+ FileRef = StringPool.internString(File);
+ }
}
}
}
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,
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,
- unsigned ParentIdx, CompileUnit &CU,
- DeclContext *CurrentDeclContext,
- NonRelocatableStringpool &StringPool,
- DeclContextTree &Contexts) {
+/// 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,
+ bool InImportedModule = 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 && ParentIdx == 0 &&
+ DIE->getAttributeValueAsString(&CU.getOrigUnit(), dwarf::DW_AT_name,
+ "") != CU.getClangModuleName()) {
+ InImportedModule = true;
+ }
+
Info.ParentIdx = ParentIdx;
- if (CU.hasODR()) {
+ bool InClangModule = CU.isClangModule() || InImportedModule;
+ if (CU.hasODR() || InClangModule) {
if (CurrentDeclContext) {
- auto PtrInvalidPair = Contexts.getChildDeclContext(*CurrentDeclContext,
- DIE, CU, StringPool);
+ auto PtrInvalidPair = Contexts.getChildDeclContext(
+ *CurrentDeclContext, DIE, CU, StringPool, InClangModule);
CurrentDeclContext = PtrInvalidPair.getPointer();
Info.Ctxt =
PtrInvalidPair.getInt() ? nullptr : PtrInvalidPair.getPointer();
Info.Ctxt = CurrentDeclContext = nullptr;
}
+ Info.Prune = InImportedModule;
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, InImportedModule);
+
+ // 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);
+
+ // Don't prune it if there is no definition for the DIE.
+ Info.Prune &= Info.Ctxt && Info.Ctxt->getCanonicalDIEOffset();
+
+ return Info.Prune;
}
static bool dieNeedsChildrenToBeMeaningful(uint32_t Tag) {
Info.Ctxt->getCanonicalDIEOffset() && isODRAttribute(AttrSpec.Attr))
continue;
+ // Keep a module forward declaration if there is no definition.
+ if (!(isODRAttribute(AttrSpec.Attr) && Info.Ctxt &&
+ Info.Ctxt->getCanonicalDIEOffset()))
+ Info.Prune = false;
+
unsigned ODRFlag = UseODR ? TF_ODR : 0;
lookForDIEsToKeep(RelocMgr, *RefDIE, DMO, *ReferencedCU,
TF_Keep | TF_DependencyWalk | ODRFlag);
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
} else {
// Add to abbreviation list.
Abbreviations.push_back(
- new DIEAbbrev(Abbrev.getTag(), Abbrev.hasChildren()));
+ llvm::make_unique<DIEAbbrev>(Abbrev.getTag(), Abbrev.hasChildren()));
for (const auto &Attr : Abbrev.getData())
Abbreviations.back()->AddAttribute(Attr.getAttribute(), Attr.getForm());
- AbbreviationsSet.InsertNode(Abbreviations.back(), InsertToken);
+ AbbreviationsSet.InsertNode(Abbreviations.back().get(), InsertToken);
// Assign the unique abbreviation number.
Abbrev.setNumber(Abbreviations.size());
Abbreviations.back()->setNumber(Abbreviations.size());
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
Unit.addTypeAccelerator(Die, AttrInfo.Name, AttrInfo.NameOffset);
}
+ // Determine whether there are any children that we want to keep.
+ bool HasChildren = false;
+ for (auto *Child = InputDIE.getFirstChild(); Child && !Child->isNULL();
+ Child = Child->getSibling()) {
+ unsigned Idx = U.getDIEIndex(Child);
+ if (Unit.getInfo(Idx).Keep) {
+ HasChildren = true;
+ break;
+ }
+ }
+
DIEAbbrev NewAbbrev = Die->generateAbbrev();
- // If a scope DIE is kept, we must have kept at least one child. If
- // it's not the case, we'll just be emitting one wasteful end of
- // children marker, but things won't break.
- if (InputDIE.hasChildren())
+ if (HasChildren)
NewAbbrev.setChildrenFlag(dwarf::DW_CHILDREN_yes);
// Assign a permanent abbrev number
Linker.AssignAbbrev(NewAbbrev);
// Add the size of the abbreviation number to the output offset.
OutOffset += getULEB128Size(Die->getAbbrevNumber());
- if (!Abbrev->hasChildren()) {
+ if (!HasChildren) {
// Update our size.
Die->setSize(OutOffset - Die->getOffset());
return Die;
uint64_t OrigLowPc = OrigUnitDie->getAttributeValueAsAddress(
&OrigUnit, dwarf::DW_AT_low_pc, -1ULL);
// Ranges addresses are based on the unit's low_pc. Compute the
- // offset we need to apply to adapt to the the new unit's low_pc.
+ // offset we need to apply to adapt to the new unit's low_pc.
int64_t UnitPcOffset = 0;
if (OrigLowPc != -1ULL)
UnitPcOffset = int64_t(OrigLowPc) - Unit.getLowPc();
Linker.AssignAbbrev(Copy);
}
+static uint64_t getDwoId(const DWARFDebugInfoEntryMinimal &CUDie,
+ const DWARFUnit &Unit) {
+ uint64_t DwoId =
+ CUDie.getAttributeValueAsUnsignedConstant(&Unit, dwarf::DW_AT_dwo_id, 0);
+ if (!DwoId)
+ DwoId = CUDie.getAttributeValueAsUnsignedConstant(&Unit,
+ dwarf::DW_AT_GNU_dwo_id, 0);
+ return DwoId;
+}
+
bool DwarfLinker::registerModuleReference(
const DWARFDebugInfoEntryMinimal &CUDie, const DWARFUnit &Unit,
DebugMap &ModuleMap, unsigned Indent) {
std::string PCMfile =
- CUDie.getAttributeValueAsString(&Unit, dwarf::DW_AT_GNU_dwo_name, "");
+ CUDie.getAttributeValueAsString(&Unit, dwarf::DW_AT_dwo_name, "");
+ if (PCMfile.empty())
+ PCMfile =
+ CUDie.getAttributeValueAsString(&Unit, dwarf::DW_AT_GNU_dwo_name, "");
if (PCMfile.empty())
return false;
// Clang module DWARF skeleton CUs abuse this for the path to the module.
std::string PCMpath =
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;
}
- if (ClangModules.count(PCMfile)) {
+ auto Cached = ClangModules.find(PCMfile);
+ if (Cached != ClangModules.end()) {
+ if (Cached->second != DwoId)
+ reportWarning(Twine("hash mismatch: this object file was built against a "
+ "different version of the module ") + PCMfile);
if (Options.Verbose)
outs() << " [cached].\n";
return true;
// 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);
- loadClangModule(PCMfile, PCMpath, ModuleMap, Indent + 2);
+ ClangModules.insert({PCMfile, DwoId});
+ loadClangModule(PCMfile, PCMpath, Name, DwoId, ModuleMap, Indent + 2);
return true;
}
}
void DwarfLinker::loadClangModule(StringRef Filename, StringRef ModulePath,
+ StringRef ModuleName, uint64_t DwoId,
DebugMap &ModuleMap, unsigned Indent) {
SmallString<80> Path(Options.PrependPath);
if (sys::path::is_relative(Filename))
return;
}
- // FIXME: At this point dsymutil should verify the DW_AT_gnu_dwo_id
- // against the module hash of the clang module.
-
- CompileUnit *Unit = nullptr;
+ std::unique_ptr<CompileUnit> Unit;
// Setup access to the debug info.
DWARFContextInMemory DwarfContext(*ErrOrObj);
auto *CUDie = CU->getUnitDIE(false);
// Recursively get all modules imported by this one.
if (!registerModuleReference(*CUDie, *CU, ModuleMap, Indent)) {
- // Add this module.
if (Unit) {
errs() << Filename << ": Clang modules are expected to have exactly"
<< " 1 compile unit.\n";
exitDsymutil(1);
}
- Unit = new CompileUnit(*CU, UnitID++, !Options.NoODR);
+ if (getDwoId(*CUDie, *CU) != DwoId)
+ reportWarning(
+ Twine("hash mismatch: this object file was built against a "
+ "different version of the module ") + Filename);
+
+ // Add this module.
+ Unit = llvm::make_unique<CompileUnit>(*CU, UnitID++, !Options.NoODR,
+ ModuleName);
Unit->setHasInterestingContent();
- gatherDIEParents(CUDie, 0, *Unit, &ODRContexts.getRoot(), StringPool,
- ODRContexts);
+ analyzeContextInfo(CUDie, 0, *Unit, &ODRContexts.getRoot(), StringPool,
+ ODRContexts);
// Keep everything.
Unit->markEverythingAsKept();
}
DWARFContextInMemory DwarfContext(*ErrOrObj);
startDebugObject(DwarfContext, *Obj);
- // In a first phase, just read in the debug info and store the DIE
- // parent links that we will use during the next phase.
+ // In a first phase, just read in the debug info and load all clang modules.
for (const auto &CU : DwarfContext.compile_units()) {
auto *CUDie = CU->getUnitDIE(false);
if (Options.Verbose) {
outs() << "Input compilation unit:";
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(),
- StringPool, ODRContexts);
- }
+
+ if (!registerModuleReference(*CUDie, *CU, ModuleMap))
+ Units.emplace_back(*CU, UnitID++, !Options.NoODR, "");
}
+ // Now build the DIE parent links that we will use during the next phase.
+ for (auto &CurrentUnit : Units)
+ analyzeContextInfo(CurrentUnit.getOrigUnit().getUnitDIE(), 0, CurrentUnit,
+ &ODRContexts.getRoot(), StringPool, ODRContexts);
+
// Then mark all the DIEs that need to be present in the linked
// output and collect some information about them. Note that this
// loop can not be merged with the previous one becaue cross-cu