#include "MachOUtils.h"
#include "NonRelocatableStringpool.h"
#include "llvm/ADT/IntervalMap.h"
-#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/DIE.h"
return LocationAttributes;
}
+ void setHasInterestingContent() { HasInterestingContent = true; }
+ bool hasInterestingContent() { return HasInterestingContent; }
+
+ /// Mark every DIE in this unit as kept. This function also
+ /// marks variables as InDebugMap so that they appear in the
+ /// reconstructed accelerator tables.
+ void markEverythingAsKept();
+
/// \brief Compute the end offset for this unit. Must be
/// called after the CU's DIEs have been cloned.
/// \returns the next unit offset (which is also the current
/// Is this unit subject to the ODR rule?
bool HasODR;
+ /// Did a DIE actually contain a valid reloc?
+ bool HasInterestingContent;
};
+void CompileUnit::markEverythingAsKept() {
+ for (auto &I : Info)
+ I.Keep = true;
+}
+
uint64_t CompileUnit::computeNextUnitOffset() {
NextUnitOffset = StartOffset + 11 /* Header size */;
// The root DIE might be null, meaning that the Unit had nothing to
const DebugMapObject &DMO, CompileUnit &CU,
unsigned Flags);
+ /// If this compile unit is really a skeleton CU that points to a
+ /// clang module, register it in ClangModules and return true.
+ ///
+ /// A skeleton CU is a CU without children, a DW_AT_gnu_dwo_name
+ /// pointing to the module, and a DW_AT_gnu_dwo_id with the module
+ /// hash.
+ bool registerModuleReference(const DWARFDebugInfoEntryMinimal &CUDie,
+ const DWARFUnit &Unit, DebugMap &ModuleMap,
+ unsigned Indent = 0);
+
+ /// 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,
+ DebugMap &ModuleMap, unsigned Indent = 0);
+
/// \brief Flags passed to DwarfLinker::lookForDIEsToKeep
enum TravesalFlags {
TF_Keep = 1 << 0, ///< Mark the traversed DIEs as kept.
const DebugMap &Map);
/// @}
-private:
std::string OutputFilename;
LinkOptions Options;
BinaryHolder BinHolder;
std::unique_ptr<DwarfStreamer> Streamer;
uint64_t OutputDebugInfoSize;
+ unsigned UnitID; ///< A unique ID that identifies each compile unit.
/// The units of the current debug map object.
std::vector<CompileUnit> Units;
/// Offset of the last CIE that has been emitted in the output
/// debug_frame section.
uint32_t LastCIEOffset;
+
+ /// FIXME: We may need to use something more resilient than the PCM filename.
+ StringSet<> ClangModules;
};
/// Similar to DWARFUnitSection::getUnitForOffset(), but returning our
// Extract and clone every attribute.
DataExtractor Data = U.getDebugInfoExtractor();
- uint32_t NextOffset = U.getDIEAtIndex(Idx + 1)->getOffset();
+ // Point to the next DIE (generally there is always at least a NULL
+ // entry after the current one). If this is a lone
+ // DW_TAG_compile_unit without any children, point to the next unit.
+ uint32_t NextOffset =
+ (Idx + 1 < U.getNumDIEs())
+ ? U.getDIEAtIndex(Idx + 1)->getOffset()
+ : U.getNextUnitOffset();
AttributesInfo AttrInfo;
// We could copy the data only if we need to aply a relocation to
Linker.AssignAbbrev(Copy);
}
+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, "");
+ 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, "");
+
+ if (Options.Verbose) {
+ outs().indent(Indent);
+ outs() << "Found clang module reference " << PCMfile;
+ }
+
+ if (ClangModules.count(PCMfile)) {
+ if (Options.Verbose)
+ outs() << " [cached].\n";
+ return true;
+ }
+ if (Options.Verbose)
+ outs() << " ...\n";
+
+ // 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);
+ return true;
+}
+
ErrorOr<const object::ObjectFile &>
DwarfLinker::loadObject(BinaryHolder &BinaryHolder, DebugMapObject &Obj,
const DebugMap &Map) {
return ErrOrObj;
}
+void DwarfLinker::loadClangModule(StringRef Filename, StringRef ModulePath,
+ DebugMap &ModuleMap, unsigned Indent) {
+ SmallString<80> Path(Options.PrependPath);
+ if (sys::path::is_relative(Filename))
+ sys::path::append(Path, ModulePath, Filename);
+ else
+ sys::path::append(Path, Filename);
+ BinaryHolder ObjHolder(Options.Verbose);
+ auto &Obj =
+ ModuleMap.addDebugMapObject(Path, sys::TimeValue::PosixZeroTime());
+ auto ErrOrObj = loadObject(ObjHolder, Obj, ModuleMap);
+ if (!ErrOrObj) {
+ ClangModules.erase(ClangModules.find(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;
+
+ // Setup access to the debug info.
+ DWARFContextInMemory DwarfContext(*ErrOrObj);
+ RelocationManager RelocMgr(*this);
+ for (const auto &CU : DwarfContext.compile_units()) {
+ 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);
+ Unit->setHasInterestingContent();
+ gatherDIEParents(CUDie, 0, *Unit, &ODRContexts.getRoot(), StringPool,
+ ODRContexts);
+ // Keep everything.
+ Unit->markEverythingAsKept();
+ }
+ }
+ if (Options.Verbose) {
+ outs().indent(Indent);
+ outs() << "cloning .debug_info from " << Filename << "\n";
+ }
+
+ DIECloner(*this, RelocMgr, DIEAlloc, MutableArrayRef<CompileUnit>(*Unit),
+ Options)
+ .cloneAllCompileUnits(DwarfContext);
+}
+
void DwarfLinker::DIECloner::cloneAllCompileUnits(
DWARFContextInMemory &DwarfContext) {
if (!Linker.Streamer)
// Size of the DIEs (and headers) generated for the linked output.
OutputDebugInfoSize = 0;
// A unique ID that identifies each compile unit.
- unsigned UnitID = 0;
+ UnitID = 0;
+ DebugMap ModuleMap(Map.getTriple(), Map.getBinaryPath());
+
for (const auto &Obj : Map.objects()) {
CurrentDebugObject = Obj.get();
outs() << "Input compilation unit:";
CUDie->dump(outs(), CU.get(), 0);
}
- 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);
+ gatherDIEParents(CUDie, 0, Units.back(), &ODRContexts.getRoot(),
+ StringPool, ODRContexts);
+ }
}
// Then mark all the DIEs that need to be present in the linked