dsymutil: Factor out the relocation handling into a RelocationManager (NFC)
llvm-svn: 247490
This commit is contained in:
		
							parent
							
								
									541de378ce
								
							
						
					
					
						commit
						67a4fc71df
					
				| 
						 | 
				
			
			@ -1103,52 +1103,74 @@ private:
 | 
			
		|||
  /// \brief Called at the end of a debug object link.
 | 
			
		||||
  void endDebugObject();
 | 
			
		||||
 | 
			
		||||
  /// \defgroup FindValidRelocations Translate debug map into a list
 | 
			
		||||
  /// of relevant relocations
 | 
			
		||||
  ///
 | 
			
		||||
  /// @{
 | 
			
		||||
  struct ValidReloc {
 | 
			
		||||
    uint32_t Offset;
 | 
			
		||||
    uint32_t Size;
 | 
			
		||||
    uint64_t Addend;
 | 
			
		||||
    const DebugMapObject::DebugMapEntry *Mapping;
 | 
			
		||||
  /// Keeps track of relocations.
 | 
			
		||||
  class RelocationManager {
 | 
			
		||||
    struct ValidReloc {
 | 
			
		||||
      uint32_t Offset;
 | 
			
		||||
      uint32_t Size;
 | 
			
		||||
      uint64_t Addend;
 | 
			
		||||
      const DebugMapObject::DebugMapEntry *Mapping;
 | 
			
		||||
 | 
			
		||||
    ValidReloc(uint32_t Offset, uint32_t Size, uint64_t Addend,
 | 
			
		||||
               const DebugMapObject::DebugMapEntry *Mapping)
 | 
			
		||||
        : Offset(Offset), Size(Size), Addend(Addend), Mapping(Mapping) {}
 | 
			
		||||
      ValidReloc(uint32_t Offset, uint32_t Size, uint64_t Addend,
 | 
			
		||||
                 const DebugMapObject::DebugMapEntry *Mapping)
 | 
			
		||||
          : Offset(Offset), Size(Size), Addend(Addend), Mapping(Mapping) {}
 | 
			
		||||
 | 
			
		||||
    bool operator<(const ValidReloc &RHS) const { return Offset < RHS.Offset; }
 | 
			
		||||
      bool operator<(const ValidReloc &RHS) const {
 | 
			
		||||
        return Offset < RHS.Offset;
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    DwarfLinker &Linker;
 | 
			
		||||
 | 
			
		||||
    /// \brief The valid relocations for the current DebugMapObject.
 | 
			
		||||
    /// This vector is sorted by relocation offset.
 | 
			
		||||
    std::vector<ValidReloc> ValidRelocs;
 | 
			
		||||
 | 
			
		||||
    /// \brief Index into ValidRelocs of the next relocation to
 | 
			
		||||
    /// consider. As we walk the DIEs in acsending file offset and as
 | 
			
		||||
    /// ValidRelocs is sorted by file offset, keeping this index
 | 
			
		||||
    /// uptodate is all we have to do to have a cheap lookup during the
 | 
			
		||||
    /// root DIE selection and during DIE cloning.
 | 
			
		||||
    unsigned NextValidReloc;
 | 
			
		||||
 | 
			
		||||
  public:
 | 
			
		||||
    RelocationManager(DwarfLinker &Linker)
 | 
			
		||||
        : Linker(Linker), NextValidReloc(0) {}
 | 
			
		||||
 | 
			
		||||
    bool hasValidRelocs() const { return !ValidRelocs.empty(); }
 | 
			
		||||
    /// \brief Reset the NextValidReloc counter.
 | 
			
		||||
    void resetValidRelocs() { NextValidReloc = 0; }
 | 
			
		||||
 | 
			
		||||
    /// \defgroup FindValidRelocations Translate debug map into a list
 | 
			
		||||
    /// of relevant relocations
 | 
			
		||||
    ///
 | 
			
		||||
    /// @{
 | 
			
		||||
    bool findValidRelocsInDebugInfo(const object::ObjectFile &Obj,
 | 
			
		||||
                                    const DebugMapObject &DMO);
 | 
			
		||||
 | 
			
		||||
    bool findValidRelocs(const object::SectionRef &Section,
 | 
			
		||||
                         const object::ObjectFile &Obj,
 | 
			
		||||
                         const DebugMapObject &DMO);
 | 
			
		||||
 | 
			
		||||
    void findValidRelocsMachO(const object::SectionRef &Section,
 | 
			
		||||
                              const object::MachOObjectFile &Obj,
 | 
			
		||||
                              const DebugMapObject &DMO);
 | 
			
		||||
    /// @}
 | 
			
		||||
 | 
			
		||||
    bool hasValidRelocation(uint32_t StartOffset, uint32_t EndOffset,
 | 
			
		||||
                            CompileUnit::DIEInfo &Info);
 | 
			
		||||
 | 
			
		||||
    bool applyValidRelocs(MutableArrayRef<char> Data, uint32_t BaseOffset,
 | 
			
		||||
                          bool isLittleEndian);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  /// \brief The valid relocations for the current DebugMapObject.
 | 
			
		||||
  /// This vector is sorted by relocation offset.
 | 
			
		||||
  std::vector<ValidReloc> ValidRelocs;
 | 
			
		||||
 | 
			
		||||
  /// \brief Index into ValidRelocs of the next relocation to
 | 
			
		||||
  /// consider. As we walk the DIEs in acsending file offset and as
 | 
			
		||||
  /// ValidRelocs is sorted by file offset, keeping this index
 | 
			
		||||
  /// uptodate is all we have to do to have a cheap lookup during the
 | 
			
		||||
  /// root DIE selection and during DIE cloning.
 | 
			
		||||
  unsigned NextValidReloc;
 | 
			
		||||
 | 
			
		||||
  bool findValidRelocsInDebugInfo(const object::ObjectFile &Obj,
 | 
			
		||||
                                  const DebugMapObject &DMO);
 | 
			
		||||
 | 
			
		||||
  bool findValidRelocs(const object::SectionRef &Section,
 | 
			
		||||
                       const object::ObjectFile &Obj,
 | 
			
		||||
                       const DebugMapObject &DMO);
 | 
			
		||||
 | 
			
		||||
  void findValidRelocsMachO(const object::SectionRef &Section,
 | 
			
		||||
                            const object::MachOObjectFile &Obj,
 | 
			
		||||
                            const DebugMapObject &DMO);
 | 
			
		||||
  /// @}
 | 
			
		||||
 | 
			
		||||
  /// \defgroup FindRootDIEs Find DIEs corresponding to debug map entries.
 | 
			
		||||
  ///
 | 
			
		||||
  /// @{
 | 
			
		||||
  /// \brief Recursively walk the \p DIE tree and look for DIEs to
 | 
			
		||||
  /// keep. Store that information in \p CU's DIEInfo.
 | 
			
		||||
  void lookForDIEsToKeep(const DWARFDebugInfoEntryMinimal &DIE,
 | 
			
		||||
  void lookForDIEsToKeep(RelocationManager &RelocMgr,
 | 
			
		||||
                         const DWARFDebugInfoEntryMinimal &DIE,
 | 
			
		||||
                         const DebugMapObject &DMO, CompileUnit &CU,
 | 
			
		||||
                         unsigned Flags);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1164,20 +1186,24 @@ private:
 | 
			
		|||
 | 
			
		||||
  /// \brief Mark the passed DIE as well as all the ones it depends on
 | 
			
		||||
  /// as kept.
 | 
			
		||||
  void keepDIEAndDenpendencies(const DWARFDebugInfoEntryMinimal &DIE,
 | 
			
		||||
  void keepDIEAndDenpendencies(RelocationManager &RelocMgr,
 | 
			
		||||
                               const DWARFDebugInfoEntryMinimal &DIE,
 | 
			
		||||
                               CompileUnit::DIEInfo &MyInfo,
 | 
			
		||||
                               const DebugMapObject &DMO, CompileUnit &CU,
 | 
			
		||||
                               bool UseODR);
 | 
			
		||||
 | 
			
		||||
  unsigned shouldKeepDIE(const DWARFDebugInfoEntryMinimal &DIE,
 | 
			
		||||
  unsigned shouldKeepDIE(RelocationManager &RelocMgr,
 | 
			
		||||
                         const DWARFDebugInfoEntryMinimal &DIE,
 | 
			
		||||
                         CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo,
 | 
			
		||||
                         unsigned Flags);
 | 
			
		||||
 | 
			
		||||
  unsigned shouldKeepVariableDIE(const DWARFDebugInfoEntryMinimal &DIE,
 | 
			
		||||
  unsigned shouldKeepVariableDIE(RelocationManager &RelocMgr,
 | 
			
		||||
                                 const DWARFDebugInfoEntryMinimal &DIE,
 | 
			
		||||
                                 CompileUnit &Unit,
 | 
			
		||||
                                 CompileUnit::DIEInfo &MyInfo, unsigned Flags);
 | 
			
		||||
 | 
			
		||||
  unsigned shouldKeepSubprogramDIE(const DWARFDebugInfoEntryMinimal &DIE,
 | 
			
		||||
  unsigned shouldKeepSubprogramDIE(RelocationManager &RelocMgr,
 | 
			
		||||
                                   const DWARFDebugInfoEntryMinimal &DIE,
 | 
			
		||||
                                   CompileUnit &Unit,
 | 
			
		||||
                                   CompileUnit::DIEInfo &MyInfo,
 | 
			
		||||
                                   unsigned Flags);
 | 
			
		||||
| 
						 | 
				
			
			@ -1200,9 +1226,19 @@ private:
 | 
			
		|||
  /// applied to the entry point of the function to get the linked address.
 | 
			
		||||
  ///
 | 
			
		||||
  /// \returns the root of the cloned tree.
 | 
			
		||||
  DIE *cloneDIE(const DWARFDebugInfoEntryMinimal &InputDIE, CompileUnit &U,
 | 
			
		||||
  DIE *cloneDIE(RelocationManager &RelocMgr,
 | 
			
		||||
                const DWARFDebugInfoEntryMinimal &InputDIE, CompileUnit &U,
 | 
			
		||||
                int64_t PCOffset, uint32_t OutOffset, unsigned Flags);
 | 
			
		||||
 | 
			
		||||
  /// Construct the output DIE tree by cloning the DIEs we chose to
 | 
			
		||||
  /// keep above. If there are no valid relocs, then there's nothing
 | 
			
		||||
  /// to clone/emit.
 | 
			
		||||
  void cloneCompileUnit(RelocationManager &RelocMgr,
 | 
			
		||||
                        MutableArrayRef<CompileUnit> CompileUnit,
 | 
			
		||||
                        DWARFContextInMemory &DwarfContext);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  typedef DWARFAbbreviationDeclaration::AttributeSpec AttributeSpec;
 | 
			
		||||
 | 
			
		||||
  /// \brief Information gathered and exchanged between the various
 | 
			
		||||
| 
						 | 
				
			
			@ -1257,10 +1293,6 @@ private:
 | 
			
		|||
                                const DWARFFormValue &Val, unsigned AttrSize,
 | 
			
		||||
                                AttributesInfo &Info);
 | 
			
		||||
 | 
			
		||||
  /// \brief Helper for cloneDIE.
 | 
			
		||||
  bool applyValidRelocs(MutableArrayRef<char> Data, uint32_t BaseOffset,
 | 
			
		||||
                        bool isLittleEndian);
 | 
			
		||||
 | 
			
		||||
  /// \brief Assign an abbreviation number to \p Abbrev
 | 
			
		||||
  void AssignAbbrev(DIEAbbrev &Abbrev);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1334,6 +1366,7 @@ private:
 | 
			
		|||
  LinkOptions Options;
 | 
			
		||||
  BinaryHolder BinHolder;
 | 
			
		||||
  std::unique_ptr<DwarfStreamer> Streamer;
 | 
			
		||||
  uint64_t OutputDebugInfoSize;
 | 
			
		||||
 | 
			
		||||
  /// The units of the current debug map object.
 | 
			
		||||
  std::vector<CompileUnit> Units;
 | 
			
		||||
| 
						 | 
				
			
			@ -1701,7 +1734,6 @@ static unsigned getRefAddrSize(const DWARFUnit &U) {
 | 
			
		|||
 | 
			
		||||
void DwarfLinker::startDebugObject(DWARFContext &Dwarf, DebugMapObject &Obj) {
 | 
			
		||||
  Units.reserve(Dwarf.getNumCompileUnits());
 | 
			
		||||
  NextValidReloc = 0;
 | 
			
		||||
  // Iterate over the debug map entries and put all the ones that are
 | 
			
		||||
  // functions (because they have a size) into the Ranges map. This
 | 
			
		||||
  // map is very similar to the FunctionRanges that are stored in each
 | 
			
		||||
| 
						 | 
				
			
			@ -1727,7 +1759,6 @@ void DwarfLinker::startDebugObject(DWARFContext &Dwarf, DebugMapObject &Obj) {
 | 
			
		|||
 | 
			
		||||
void DwarfLinker::endDebugObject() {
 | 
			
		||||
  Units.clear();
 | 
			
		||||
  ValidRelocs.clear();
 | 
			
		||||
  Ranges.clear();
 | 
			
		||||
 | 
			
		||||
  for (auto I = DIEBlocks.begin(), E = DIEBlocks.end(); I != E; ++I)
 | 
			
		||||
| 
						 | 
				
			
			@ -1743,9 +1774,10 @@ void DwarfLinker::endDebugObject() {
 | 
			
		|||
/// \brief Iterate over the relocations of the given \p Section and
 | 
			
		||||
/// store the ones that correspond to debug map entries into the
 | 
			
		||||
/// ValidRelocs array.
 | 
			
		||||
void DwarfLinker::findValidRelocsMachO(const object::SectionRef &Section,
 | 
			
		||||
                                       const object::MachOObjectFile &Obj,
 | 
			
		||||
                                       const DebugMapObject &DMO) {
 | 
			
		||||
void DwarfLinker::RelocationManager::
 | 
			
		||||
findValidRelocsMachO(const object::SectionRef &Section,
 | 
			
		||||
                     const object::MachOObjectFile &Obj,
 | 
			
		||||
                     const DebugMapObject &DMO) {
 | 
			
		||||
  StringRef Contents;
 | 
			
		||||
  Section.getContents(Contents);
 | 
			
		||||
  DataExtractor Data(Contents, Obj.isLittleEndian(), 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -1756,7 +1788,7 @@ void DwarfLinker::findValidRelocsMachO(const object::SectionRef &Section,
 | 
			
		|||
    unsigned RelocSize = 1 << Obj.getAnyRelocationLength(MachOReloc);
 | 
			
		||||
    uint64_t Offset64 = Reloc.getOffset();
 | 
			
		||||
    if ((RelocSize != 4 && RelocSize != 8)) {
 | 
			
		||||
      reportWarning(" unsupported relocation in debug_info section.");
 | 
			
		||||
      Linker.reportWarning(" unsupported relocation in debug_info section.");
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
    uint32_t Offset = Offset64;
 | 
			
		||||
| 
						 | 
				
			
			@ -1767,7 +1799,7 @@ void DwarfLinker::findValidRelocsMachO(const object::SectionRef &Section,
 | 
			
		|||
    if (Sym != Obj.symbol_end()) {
 | 
			
		||||
      ErrorOr<StringRef> SymbolName = Sym->getName();
 | 
			
		||||
      if (!SymbolName) {
 | 
			
		||||
        reportWarning("error getting relocation symbol name.");
 | 
			
		||||
        Linker.reportWarning("error getting relocation symbol name.");
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
      if (const auto *Mapping = DMO.lookupSymbol(*SymbolName))
 | 
			
		||||
| 
						 | 
				
			
			@ -1783,14 +1815,15 @@ void DwarfLinker::findValidRelocsMachO(const object::SectionRef &Section,
 | 
			
		|||
 | 
			
		||||
/// \brief Dispatch the valid relocation finding logic to the
 | 
			
		||||
/// appropriate handler depending on the object file format.
 | 
			
		||||
bool DwarfLinker::findValidRelocs(const object::SectionRef &Section,
 | 
			
		||||
                                  const object::ObjectFile &Obj,
 | 
			
		||||
                                  const DebugMapObject &DMO) {
 | 
			
		||||
bool DwarfLinker::RelocationManager::findValidRelocs(
 | 
			
		||||
    const object::SectionRef &Section, const object::ObjectFile &Obj,
 | 
			
		||||
    const DebugMapObject &DMO) {
 | 
			
		||||
  // Dispatch to the right handler depending on the file type.
 | 
			
		||||
  if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(&Obj))
 | 
			
		||||
    findValidRelocsMachO(Section, *MachOObj, DMO);
 | 
			
		||||
  else
 | 
			
		||||
    reportWarning(Twine("unsupported object file type: ") + Obj.getFileName());
 | 
			
		||||
    Linker.reportWarning(Twine("unsupported object file type: ") +
 | 
			
		||||
                         Obj.getFileName());
 | 
			
		||||
 | 
			
		||||
  if (ValidRelocs.empty())
 | 
			
		||||
    return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -1808,8 +1841,9 @@ bool DwarfLinker::findValidRelocs(const object::SectionRef &Section,
 | 
			
		|||
/// link by indicating which DIEs refer to symbols present in the
 | 
			
		||||
/// linked binary.
 | 
			
		||||
/// \returns wether there are any valid relocations in the debug info.
 | 
			
		||||
bool DwarfLinker::findValidRelocsInDebugInfo(const object::ObjectFile &Obj,
 | 
			
		||||
                                             const DebugMapObject &DMO) {
 | 
			
		||||
bool DwarfLinker::RelocationManager::
 | 
			
		||||
findValidRelocsInDebugInfo(const object::ObjectFile &Obj,
 | 
			
		||||
                           const DebugMapObject &DMO) {
 | 
			
		||||
  // Find the debug_info section.
 | 
			
		||||
  for (const object::SectionRef &Section : Obj.sections()) {
 | 
			
		||||
    StringRef SectionName;
 | 
			
		||||
| 
						 | 
				
			
			@ -1828,8 +1862,9 @@ bool DwarfLinker::findValidRelocsInDebugInfo(const object::ObjectFile &Obj,
 | 
			
		|||
/// This function must be called with offsets in strictly ascending
 | 
			
		||||
/// order because it never looks back at relocations it already 'went past'.
 | 
			
		||||
/// \returns true and sets Info.InDebugMap if it is the case.
 | 
			
		||||
bool DwarfLinker::hasValidRelocation(uint32_t StartOffset, uint32_t EndOffset,
 | 
			
		||||
                                     CompileUnit::DIEInfo &Info) {
 | 
			
		||||
bool DwarfLinker::RelocationManager::
 | 
			
		||||
hasValidRelocation(uint32_t StartOffset, uint32_t EndOffset,
 | 
			
		||||
                   CompileUnit::DIEInfo &Info) {
 | 
			
		||||
  assert(NextValidReloc == 0 ||
 | 
			
		||||
         StartOffset > ValidRelocs[NextValidReloc - 1].Offset);
 | 
			
		||||
  if (NextValidReloc >= ValidRelocs.size())
 | 
			
		||||
| 
						 | 
				
			
			@ -1849,7 +1884,7 @@ bool DwarfLinker::hasValidRelocation(uint32_t StartOffset, uint32_t EndOffset,
 | 
			
		|||
 | 
			
		||||
  const auto &ValidReloc = ValidRelocs[NextValidReloc++];
 | 
			
		||||
  const auto &Mapping = ValidReloc.Mapping->getValue();
 | 
			
		||||
  if (Options.Verbose)
 | 
			
		||||
  if (Linker.Options.Verbose)
 | 
			
		||||
    outs() << "Found valid debug map entry: " << ValidReloc.Mapping->getKey()
 | 
			
		||||
           << " " << format("\t%016" PRIx64 " => %016" PRIx64,
 | 
			
		||||
                            uint64_t(Mapping.ObjectAddress),
 | 
			
		||||
| 
						 | 
				
			
			@ -1882,9 +1917,11 @@ getAttributeOffsets(const DWARFAbbreviationDeclaration *Abbrev, unsigned Idx,
 | 
			
		|||
 | 
			
		||||
/// \brief Check if a variable describing DIE should be kept.
 | 
			
		||||
/// \returns updated TraversalFlags.
 | 
			
		||||
unsigned DwarfLinker::shouldKeepVariableDIE(
 | 
			
		||||
    const DWARFDebugInfoEntryMinimal &DIE, CompileUnit &Unit,
 | 
			
		||||
    CompileUnit::DIEInfo &MyInfo, unsigned Flags) {
 | 
			
		||||
unsigned DwarfLinker::shouldKeepVariableDIE(RelocationManager &RelocMgr,
 | 
			
		||||
                                            const DWARFDebugInfoEntryMinimal &DIE,
 | 
			
		||||
                                            CompileUnit &Unit,
 | 
			
		||||
                                            CompileUnit::DIEInfo &MyInfo,
 | 
			
		||||
                                            unsigned Flags) {
 | 
			
		||||
  const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
 | 
			
		||||
 | 
			
		||||
  // Global variables with constant value can always be kept.
 | 
			
		||||
| 
						 | 
				
			
			@ -1909,7 +1946,7 @@ unsigned DwarfLinker::shouldKeepVariableDIE(
 | 
			
		|||
  // always check in the variable has a valid relocation, so that the
 | 
			
		||||
  // DIEInfo is filled. However, we don't want a static variable in a
 | 
			
		||||
  // function to force us to keep the enclosing function.
 | 
			
		||||
  if (!hasValidRelocation(LocationOffset, LocationEndOffset, MyInfo) ||
 | 
			
		||||
  if (!RelocMgr.hasValidRelocation(LocationOffset, LocationEndOffset, MyInfo) ||
 | 
			
		||||
      (Flags & TF_InFunctionScope))
 | 
			
		||||
    return Flags;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1922,6 +1959,7 @@ unsigned DwarfLinker::shouldKeepVariableDIE(
 | 
			
		|||
/// \brief Check if a function describing DIE should be kept.
 | 
			
		||||
/// \returns updated TraversalFlags.
 | 
			
		||||
unsigned DwarfLinker::shouldKeepSubprogramDIE(
 | 
			
		||||
    RelocationManager &RelocMgr,
 | 
			
		||||
    const DWARFDebugInfoEntryMinimal &DIE, CompileUnit &Unit,
 | 
			
		||||
    CompileUnit::DIEInfo &MyInfo, unsigned Flags) {
 | 
			
		||||
  const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
 | 
			
		||||
| 
						 | 
				
			
			@ -1942,7 +1980,7 @@ unsigned DwarfLinker::shouldKeepSubprogramDIE(
 | 
			
		|||
      DIE.getAttributeValueAsAddress(&OrigUnit, dwarf::DW_AT_low_pc, -1ULL);
 | 
			
		||||
  assert(LowPc != -1ULL && "low_pc attribute is not an address.");
 | 
			
		||||
  if (LowPc == -1ULL ||
 | 
			
		||||
      !hasValidRelocation(LowPcOffset, LowPcEndOffset, MyInfo))
 | 
			
		||||
      !RelocMgr.hasValidRelocation(LowPcOffset, LowPcEndOffset, MyInfo))
 | 
			
		||||
    return Flags;
 | 
			
		||||
 | 
			
		||||
  if (Options.Verbose)
 | 
			
		||||
| 
						 | 
				
			
			@ -1973,16 +2011,17 @@ unsigned DwarfLinker::shouldKeepSubprogramDIE(
 | 
			
		|||
 | 
			
		||||
/// \brief Check if a DIE should be kept.
 | 
			
		||||
/// \returns updated TraversalFlags.
 | 
			
		||||
unsigned DwarfLinker::shouldKeepDIE(const DWARFDebugInfoEntryMinimal &DIE,
 | 
			
		||||
unsigned DwarfLinker::shouldKeepDIE(RelocationManager &RelocMgr,
 | 
			
		||||
                                    const DWARFDebugInfoEntryMinimal &DIE,
 | 
			
		||||
                                    CompileUnit &Unit,
 | 
			
		||||
                                    CompileUnit::DIEInfo &MyInfo,
 | 
			
		||||
                                    unsigned Flags) {
 | 
			
		||||
  switch (DIE.getTag()) {
 | 
			
		||||
  case dwarf::DW_TAG_constant:
 | 
			
		||||
  case dwarf::DW_TAG_variable:
 | 
			
		||||
    return shouldKeepVariableDIE(DIE, Unit, MyInfo, Flags);
 | 
			
		||||
    return shouldKeepVariableDIE(RelocMgr, DIE, Unit, MyInfo, Flags);
 | 
			
		||||
  case dwarf::DW_TAG_subprogram:
 | 
			
		||||
    return shouldKeepSubprogramDIE(DIE, Unit, MyInfo, Flags);
 | 
			
		||||
    return shouldKeepSubprogramDIE(RelocMgr, DIE, Unit, MyInfo, Flags);
 | 
			
		||||
  case dwarf::DW_TAG_module:
 | 
			
		||||
  case dwarf::DW_TAG_imported_module:
 | 
			
		||||
  case dwarf::DW_TAG_imported_declaration:
 | 
			
		||||
| 
						 | 
				
			
			@ -2002,7 +2041,8 @@ unsigned DwarfLinker::shouldKeepDIE(const DWARFDebugInfoEntryMinimal &DIE,
 | 
			
		|||
/// back to lookForDIEsToKeep while adding TF_DependencyWalk to the
 | 
			
		||||
/// TraversalFlags to inform it that it's not doing the primary DIE
 | 
			
		||||
/// tree walk.
 | 
			
		||||
void DwarfLinker::keepDIEAndDenpendencies(const DWARFDebugInfoEntryMinimal &Die,
 | 
			
		||||
void DwarfLinker::keepDIEAndDenpendencies(RelocationManager &RelocMgr,
 | 
			
		||||
                                          const DWARFDebugInfoEntryMinimal &Die,
 | 
			
		||||
                                          CompileUnit::DIEInfo &MyInfo,
 | 
			
		||||
                                          const DebugMapObject &DMO,
 | 
			
		||||
                                          CompileUnit &CU, bool UseODR) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2013,7 +2053,7 @@ void DwarfLinker::keepDIEAndDenpendencies(const DWARFDebugInfoEntryMinimal &Die,
 | 
			
		|||
  unsigned AncestorIdx = MyInfo.ParentIdx;
 | 
			
		||||
  while (!CU.getInfo(AncestorIdx).Keep) {
 | 
			
		||||
    unsigned ODRFlag = UseODR ? TF_ODR : 0;
 | 
			
		||||
    lookForDIEsToKeep(*Unit.getDIEAtIndex(AncestorIdx), DMO, CU,
 | 
			
		||||
    lookForDIEsToKeep(RelocMgr, *Unit.getDIEAtIndex(AncestorIdx), DMO, CU,
 | 
			
		||||
                      TF_ParentWalk | TF_Keep | TF_DependencyWalk | ODRFlag);
 | 
			
		||||
    AncestorIdx = CU.getInfo(AncestorIdx).ParentIdx;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -2053,7 +2093,7 @@ void DwarfLinker::keepDIEAndDenpendencies(const DWARFDebugInfoEntryMinimal &Die,
 | 
			
		|||
        continue;
 | 
			
		||||
 | 
			
		||||
      unsigned ODRFlag = UseODR ? TF_ODR : 0;
 | 
			
		||||
      lookForDIEsToKeep(*RefDIE, DMO, *ReferencedCU,
 | 
			
		||||
      lookForDIEsToKeep(RelocMgr, *RefDIE, DMO, *ReferencedCU,
 | 
			
		||||
                        TF_Keep | TF_DependencyWalk | ODRFlag);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -2071,7 +2111,8 @@ void DwarfLinker::keepDIEAndDenpendencies(const DWARFDebugInfoEntryMinimal &Die,
 | 
			
		|||
/// also called, but during these dependency walks the file order is
 | 
			
		||||
/// not respected. The TF_DependencyWalk flag tells us which kind of
 | 
			
		||||
/// traversal we are currently doing.
 | 
			
		||||
void DwarfLinker::lookForDIEsToKeep(const DWARFDebugInfoEntryMinimal &Die,
 | 
			
		||||
void DwarfLinker::lookForDIEsToKeep(RelocationManager &RelocMgr,
 | 
			
		||||
                                    const DWARFDebugInfoEntryMinimal &Die,
 | 
			
		||||
                                    const DebugMapObject &DMO, CompileUnit &CU,
 | 
			
		||||
                                    unsigned Flags) {
 | 
			
		||||
  unsigned Idx = CU.getOrigUnit().getDIEIndex(&Die);
 | 
			
		||||
| 
						 | 
				
			
			@ -2087,12 +2128,12 @@ void DwarfLinker::lookForDIEsToKeep(const DWARFDebugInfoEntryMinimal &Die,
 | 
			
		|||
  // We must not call shouldKeepDIE while called from keepDIEAndDenpendencies,
 | 
			
		||||
  // because it would screw up the relocation finding logic.
 | 
			
		||||
  if (!(Flags & TF_DependencyWalk))
 | 
			
		||||
    Flags = shouldKeepDIE(Die, CU, MyInfo, Flags);
 | 
			
		||||
    Flags = shouldKeepDIE(RelocMgr, Die, CU, MyInfo, Flags);
 | 
			
		||||
 | 
			
		||||
  // If it is a newly kept DIE mark it as well as all its dependencies as kept.
 | 
			
		||||
  if (!AlreadyKept && (Flags & TF_Keep)) {
 | 
			
		||||
    bool UseOdr = (Flags & TF_DependencyWalk) ? (Flags & TF_ODR) : CU.hasODR();
 | 
			
		||||
    keepDIEAndDenpendencies(Die, MyInfo, DMO, CU, UseOdr);
 | 
			
		||||
    keepDIEAndDenpendencies(RelocMgr, Die, MyInfo, DMO, CU, UseOdr);
 | 
			
		||||
  }
 | 
			
		||||
  // The TF_ParentWalk flag tells us that we are currently walking up
 | 
			
		||||
  // the parent chain of a required DIE, and we don't want to mark all
 | 
			
		||||
| 
						 | 
				
			
			@ -2108,7 +2149,7 @@ void DwarfLinker::lookForDIEsToKeep(const DWARFDebugInfoEntryMinimal &Die,
 | 
			
		|||
 | 
			
		||||
  for (auto *Child = Die.getFirstChild(); Child && !Child->isNULL();
 | 
			
		||||
       Child = Child->getSibling())
 | 
			
		||||
    lookForDIEsToKeep(*Child, DMO, CU, Flags);
 | 
			
		||||
    lookForDIEsToKeep(RelocMgr, *Child, DMO, CU, Flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// \brief Assign an abbreviation numer to \p Abbrev.
 | 
			
		||||
| 
						 | 
				
			
			@ -2412,8 +2453,9 @@ unsigned DwarfLinker::cloneAttribute(DIE &Die,
 | 
			
		|||
/// monotonic \p BaseOffset values.
 | 
			
		||||
///
 | 
			
		||||
/// \returns wether any reloc has been applied.
 | 
			
		||||
bool DwarfLinker::applyValidRelocs(MutableArrayRef<char> Data,
 | 
			
		||||
                                   uint32_t BaseOffset, bool isLittleEndian) {
 | 
			
		||||
bool DwarfLinker::RelocationManager::
 | 
			
		||||
applyValidRelocs(MutableArrayRef<char> Data, uint32_t BaseOffset,
 | 
			
		||||
                 bool isLittleEndian) {
 | 
			
		||||
  assert((NextValidReloc == 0 ||
 | 
			
		||||
          BaseOffset > ValidRelocs[NextValidReloc - 1].Offset) &&
 | 
			
		||||
         "BaseOffset should only be increasing.");
 | 
			
		||||
| 
						 | 
				
			
			@ -2512,7 +2554,8 @@ shouldSkipAttribute(DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,
 | 
			
		|||
/// lie in the linked compile unit.
 | 
			
		||||
///
 | 
			
		||||
/// \returns the cloned DIE object or null if nothing was selected.
 | 
			
		||||
DIE *DwarfLinker::cloneDIE(const DWARFDebugInfoEntryMinimal &InputDIE,
 | 
			
		||||
DIE *DwarfLinker::cloneDIE(RelocationManager &RelocMgr,
 | 
			
		||||
                           const DWARFDebugInfoEntryMinimal &InputDIE,
 | 
			
		||||
                           CompileUnit &Unit, int64_t PCOffset,
 | 
			
		||||
                           uint32_t OutOffset, unsigned Flags) {
 | 
			
		||||
  DWARFUnit &U = Unit.getOrigUnit();
 | 
			
		||||
| 
						 | 
				
			
			@ -2551,7 +2594,7 @@ DIE *DwarfLinker::cloneDIE(const DWARFDebugInfoEntryMinimal &InputDIE,
 | 
			
		|||
  SmallString<40> DIECopy(Data.getData().substr(Offset, NextOffset - Offset));
 | 
			
		||||
  Data = DataExtractor(DIECopy, Data.isLittleEndian(), Data.getAddressSize());
 | 
			
		||||
  // Modify the copy with relocated addresses.
 | 
			
		||||
  if (applyValidRelocs(DIECopy, Offset, Data.isLittleEndian())) {
 | 
			
		||||
  if (RelocMgr.applyValidRelocs(DIECopy, Offset, Data.isLittleEndian())) {
 | 
			
		||||
    // If we applied relocations, we store the value of high_pc that was
 | 
			
		||||
    // potentially stored in the input DIE. If high_pc is an address
 | 
			
		||||
    // (Dwarf version == 2), then it might have been relocated to a
 | 
			
		||||
| 
						 | 
				
			
			@ -2652,7 +2695,8 @@ DIE *DwarfLinker::cloneDIE(const DWARFDebugInfoEntryMinimal &InputDIE,
 | 
			
		|||
  // Recursively clone children.
 | 
			
		||||
  for (auto *Child = InputDIE.getFirstChild(); Child && !Child->isNULL();
 | 
			
		||||
       Child = Child->getSibling()) {
 | 
			
		||||
    if (DIE *Clone = cloneDIE(*Child, Unit, PCOffset, OutOffset, Flags)) {
 | 
			
		||||
    if (DIE *Clone =
 | 
			
		||||
            cloneDIE(RelocMgr, *Child, Unit, PCOffset, OutOffset, Flags)) {
 | 
			
		||||
      Die->addChild(Clone);
 | 
			
		||||
      OutOffset = Clone->getOffset() + Clone->getSize();
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -3020,13 +3064,53 @@ DwarfLinker::loadObject(BinaryHolder &BinaryHolder, DebugMapObject &Obj,
 | 
			
		|||
  return ErrOrObj;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DwarfLinker::cloneCompileUnit(RelocationManager &RelocMgr,
 | 
			
		||||
                                   MutableArrayRef<CompileUnit> CompileUnits,
 | 
			
		||||
                                   DWARFContextInMemory &DwarfContext) {
 | 
			
		||||
  if (!Streamer)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  for (auto &CurrentUnit : CompileUnits) {
 | 
			
		||||
    const auto *InputDIE = CurrentUnit.getOrigUnit().getUnitDIE();
 | 
			
		||||
    CurrentUnit.setStartOffset(OutputDebugInfoSize);
 | 
			
		||||
    DIE *OutputDIE = cloneDIE(RelocMgr, *InputDIE, CurrentUnit,
 | 
			
		||||
                              0 /* PC offset */, 11 /* Unit Header size */, 0);
 | 
			
		||||
    CurrentUnit.setOutputUnitDIE(OutputDIE);
 | 
			
		||||
    OutputDebugInfoSize = CurrentUnit.computeNextUnitOffset();
 | 
			
		||||
    if (Options.NoOutput)
 | 
			
		||||
      continue;
 | 
			
		||||
    // FIXME: for compatibility with the classic dsymutil, we emit
 | 
			
		||||
    // an empty line table for the unit, even if the unit doesn't
 | 
			
		||||
    // actually exist in the DIE tree.
 | 
			
		||||
    patchLineTableForUnit(CurrentUnit, DwarfContext);
 | 
			
		||||
    if (!OutputDIE)
 | 
			
		||||
      continue;
 | 
			
		||||
    patchRangesForUnit(CurrentUnit, DwarfContext);
 | 
			
		||||
    Streamer->emitLocationsForUnit(CurrentUnit, DwarfContext);
 | 
			
		||||
    emitAcceleratorEntriesForUnit(CurrentUnit);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (Options.NoOutput)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  // Emit all the compile unit's debug information.
 | 
			
		||||
  for (auto &CurrentUnit : CompileUnits) {
 | 
			
		||||
    generateUnitRanges(CurrentUnit);
 | 
			
		||||
    CurrentUnit.fixupForwardReferences();
 | 
			
		||||
    Streamer->emitCompileUnitHeader(CurrentUnit);
 | 
			
		||||
    if (!CurrentUnit.getOutputUnitDIE())
 | 
			
		||||
      continue;
 | 
			
		||||
    Streamer->emitDIE(*CurrentUnit.getOutputUnitDIE());
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool DwarfLinker::link(const DebugMap &Map) {
 | 
			
		||||
 | 
			
		||||
  if (!createStreamer(Map.getTriple(), OutputFilename))
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
  // Size of the DIEs (and headers) generated for the linked output.
 | 
			
		||||
  uint64_t OutputDebugInfoSize = 0;
 | 
			
		||||
  OutputDebugInfoSize = 0;
 | 
			
		||||
  // A unique ID that identifies each compile unit.
 | 
			
		||||
  unsigned UnitID = 0;
 | 
			
		||||
  for (const auto &Obj : Map.objects()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -3039,7 +3123,8 @@ bool DwarfLinker::link(const DebugMap &Map) {
 | 
			
		|||
      continue;
 | 
			
		||||
 | 
			
		||||
    // Look for relocations that correspond to debug map entries.
 | 
			
		||||
    if (!findValidRelocsInDebugInfo(*ErrOrObj, *Obj)) {
 | 
			
		||||
    RelocationManager RelocMgr(*this);
 | 
			
		||||
    if (!RelocMgr.findValidRelocsInDebugInfo(*ErrOrObj, *Obj)) {
 | 
			
		||||
      if (Options.Verbose)
 | 
			
		||||
        outs() << "No valid relocations found. Skipping.\n";
 | 
			
		||||
      continue;
 | 
			
		||||
| 
						 | 
				
			
			@ -3068,50 +3153,16 @@ bool DwarfLinker::link(const DebugMap &Map) {
 | 
			
		|||
    // references require the ParentIdx to be setup for every CU in
 | 
			
		||||
    // the object file before calling this.
 | 
			
		||||
    for (auto &CurrentUnit : Units)
 | 
			
		||||
      lookForDIEsToKeep(*CurrentUnit.getOrigUnit().getUnitDIE(), *Obj,
 | 
			
		||||
      lookForDIEsToKeep(RelocMgr, *CurrentUnit.getOrigUnit().getUnitDIE(), *Obj,
 | 
			
		||||
                        CurrentUnit, 0);
 | 
			
		||||
 | 
			
		||||
    // The calls to applyValidRelocs inside cloneDIE will walk the
 | 
			
		||||
    // reloc array again (in the same way findValidRelocsInDebugInfo()
 | 
			
		||||
    // did). We need to reset the NextValidReloc index to the beginning.
 | 
			
		||||
    NextValidReloc = 0;
 | 
			
		||||
 | 
			
		||||
    // Construct the output DIE tree by cloning the DIEs we chose to
 | 
			
		||||
    // keep above. If there are no valid relocs, then there's nothing
 | 
			
		||||
    // to clone/emit.
 | 
			
		||||
    if (!ValidRelocs.empty())
 | 
			
		||||
      for (auto &CurrentUnit : Units) {
 | 
			
		||||
        const auto *InputDIE = CurrentUnit.getOrigUnit().getUnitDIE();
 | 
			
		||||
        CurrentUnit.setStartOffset(OutputDebugInfoSize);
 | 
			
		||||
        DIE *OutputDIE = cloneDIE(*InputDIE, CurrentUnit, 0 /* PCOffset */,
 | 
			
		||||
                                  11 /* Unit Header size */, /* Flags =*/0);
 | 
			
		||||
        CurrentUnit.setOutputUnitDIE(OutputDIE);
 | 
			
		||||
        OutputDebugInfoSize = CurrentUnit.computeNextUnitOffset();
 | 
			
		||||
        if (Options.NoOutput)
 | 
			
		||||
          continue;
 | 
			
		||||
        // FIXME: for compatibility with the classic dsymutil, we emit
 | 
			
		||||
        // an empty line table for the unit, even if the unit doesn't
 | 
			
		||||
        // actually exist in the DIE tree.
 | 
			
		||||
        patchLineTableForUnit(CurrentUnit, DwarfContext);
 | 
			
		||||
        if (!OutputDIE)
 | 
			
		||||
          continue;
 | 
			
		||||
        patchRangesForUnit(CurrentUnit, DwarfContext);
 | 
			
		||||
        Streamer->emitLocationsForUnit(CurrentUnit, DwarfContext);
 | 
			
		||||
        emitAcceleratorEntriesForUnit(CurrentUnit);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    // Emit all the compile unit's debug information.
 | 
			
		||||
    if (!ValidRelocs.empty() && !Options.NoOutput)
 | 
			
		||||
      for (auto &CurrentUnit : Units) {
 | 
			
		||||
        generateUnitRanges(CurrentUnit);
 | 
			
		||||
        CurrentUnit.fixupForwardReferences();
 | 
			
		||||
        Streamer->emitCompileUnitHeader(CurrentUnit);
 | 
			
		||||
        if (!CurrentUnit.getOutputUnitDIE())
 | 
			
		||||
          continue;
 | 
			
		||||
        Streamer->emitDIE(*CurrentUnit.getOutputUnitDIE());
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    if (!ValidRelocs.empty() && !Options.NoOutput && !Units.empty())
 | 
			
		||||
    RelocMgr.resetValidRelocs();
 | 
			
		||||
    if (RelocMgr.hasValidRelocs())
 | 
			
		||||
      cloneCompileUnit(RelocMgr, Units, DwarfContext);
 | 
			
		||||
    if (!Options.NoOutput && !Units.empty())
 | 
			
		||||
      patchFrameInfoForObject(*Obj, DwarfContext,
 | 
			
		||||
                              Units[0].getOrigUnit().getAddressByteSize());
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue