293 lines
11 KiB
C++
293 lines
11 KiB
C++
//===- tools/dsymutil/DwarfLinkerForBinary.h --------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H
|
|
#define LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H
|
|
|
|
#include "BinaryHolder.h"
|
|
#include "DebugMap.h"
|
|
#include "LinkUtils.h"
|
|
#include "MachOUtils.h"
|
|
#include "RelocationMap.h"
|
|
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
|
#include "llvm/Remarks/RemarkFormat.h"
|
|
#include "llvm/Remarks/RemarkLinker.h"
|
|
#include <mutex>
|
|
#include <optional>
|
|
|
|
namespace llvm {
|
|
using namespace dwarf_linker;
|
|
|
|
namespace dsymutil {
|
|
|
|
/// DwarfLinkerForBinaryRelocationMap contains the logic to handle the
|
|
/// relocations and to store them inside an associated RelocationMap.
|
|
class DwarfLinkerForBinaryRelocationMap {
|
|
public:
|
|
void init(DWARFContext &Context);
|
|
|
|
bool isInitialized() {
|
|
return StoredValidDebugInfoRelocsMap.getMemorySize() != 0;
|
|
}
|
|
|
|
void addValidRelocs(RelocationMap &RM);
|
|
|
|
void updateAndSaveValidRelocs(bool IsDWARF5,
|
|
std::vector<ValidReloc> &InRelocs,
|
|
uint64_t UnitOffset, int64_t LinkedOffset);
|
|
|
|
void updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset,
|
|
uint64_t OutputUnitOffset);
|
|
|
|
/// Map compilation unit offset to the valid relocations to store
|
|
/// @{
|
|
DenseMap<uint64_t, std::vector<ValidReloc>> StoredValidDebugInfoRelocsMap;
|
|
DenseMap<uint64_t, std::vector<ValidReloc>> StoredValidDebugAddrRelocsMap;
|
|
/// @}
|
|
|
|
DwarfLinkerForBinaryRelocationMap() = default;
|
|
};
|
|
|
|
struct ObjectWithRelocMap {
|
|
ObjectWithRelocMap(
|
|
std::unique_ptr<DWARFFile> Object,
|
|
std::shared_ptr<DwarfLinkerForBinaryRelocationMap> OutRelocs)
|
|
: Object(std::move(Object)), OutRelocs(OutRelocs) {}
|
|
std::unique_ptr<DWARFFile> Object;
|
|
std::shared_ptr<DwarfLinkerForBinaryRelocationMap> OutRelocs;
|
|
};
|
|
|
|
/// The core of the Dsymutil Dwarf linking logic.
|
|
///
|
|
/// The link of the dwarf information from the object files will be
|
|
/// driven by DWARFLinker. DwarfLinkerForBinary reads DebugMap objects
|
|
/// and pass information to the DWARFLinker. DWARFLinker
|
|
/// optimizes DWARF taking into account valid relocations.
|
|
/// Finally, optimized DWARF is passed to DwarfLinkerForBinary through
|
|
/// DWARFEmitter interface.
|
|
class DwarfLinkerForBinary {
|
|
public:
|
|
DwarfLinkerForBinary(raw_fd_ostream &OutFile, BinaryHolder &BinHolder,
|
|
LinkOptions Options, std::mutex &ErrorHandlerMutex)
|
|
: OutFile(OutFile), BinHolder(BinHolder), Options(std::move(Options)),
|
|
ErrorHandlerMutex(ErrorHandlerMutex) {}
|
|
|
|
/// Link the contents of the DebugMap.
|
|
bool link(const DebugMap &);
|
|
|
|
void reportWarning(Twine Warning, Twine Context = {},
|
|
const DWARFDie *DIE = nullptr) const;
|
|
void reportError(Twine Error, Twine Context = {},
|
|
const DWARFDie *DIE = nullptr) const;
|
|
|
|
/// Returns true if input verification is enabled and verification errors were
|
|
/// found.
|
|
bool InputVerificationFailed() const { return HasVerificationErrors; }
|
|
|
|
/// Flags passed to DwarfLinker::lookForDIEsToKeep
|
|
enum TraversalFlags {
|
|
TF_Keep = 1 << 0, ///< Mark the traversed DIEs as kept.
|
|
TF_InFunctionScope = 1 << 1, ///< Current scope is a function scope.
|
|
TF_DependencyWalk = 1 << 2, ///< Walking the dependencies of a kept DIE.
|
|
TF_ParentWalk = 1 << 3, ///< Walking up the parents of a kept DIE.
|
|
TF_ODR = 1 << 4, ///< Use the ODR while keeping dependents.
|
|
TF_SkipPC = 1 << 5, ///< Skip all location attributes.
|
|
};
|
|
|
|
private:
|
|
|
|
/// Keeps track of relocations.
|
|
class AddressManager : public dwarf_linker::AddressesMap {
|
|
|
|
const DwarfLinkerForBinary &Linker;
|
|
|
|
/// The valid relocations for the current DebugMapObject.
|
|
/// These vectors are sorted by relocation offset.
|
|
/// {
|
|
std::vector<ValidReloc> ValidDebugInfoRelocs;
|
|
std::vector<ValidReloc> ValidDebugAddrRelocs;
|
|
/// }
|
|
|
|
StringRef SrcFileName;
|
|
|
|
uint8_t DebugMapObjectType;
|
|
|
|
std::shared_ptr<DwarfLinkerForBinaryRelocationMap> DwarfLinkerRelocMap;
|
|
|
|
std::optional<std::string> LibInstallName;
|
|
|
|
/// Returns list of valid relocations from \p Relocs,
|
|
/// between \p StartOffset and \p NextOffset.
|
|
///
|
|
/// \returns true if any relocation is found.
|
|
std::vector<ValidReloc>
|
|
getRelocations(const std::vector<ValidReloc> &Relocs, uint64_t StartPos,
|
|
uint64_t EndPos);
|
|
|
|
/// Resolve specified relocation \p Reloc.
|
|
///
|
|
/// \returns resolved value.
|
|
uint64_t relocate(const ValidReloc &Reloc) const;
|
|
|
|
/// \returns value for the specified \p Reloc.
|
|
int64_t getRelocValue(const ValidReloc &Reloc);
|
|
|
|
/// Print contents of debug map entry for the specified \p Reloc.
|
|
void printReloc(const ValidReloc &Reloc);
|
|
|
|
public:
|
|
AddressManager(DwarfLinkerForBinary &Linker, const object::ObjectFile &Obj,
|
|
const DebugMapObject &DMO,
|
|
std::shared_ptr<DwarfLinkerForBinaryRelocationMap> DLBRM)
|
|
: Linker(Linker), SrcFileName(DMO.getObjectFilename()),
|
|
DebugMapObjectType(MachO::N_OSO), DwarfLinkerRelocMap(DLBRM) {
|
|
if (DMO.getRelocationMap().has_value()) {
|
|
DebugMapObjectType = MachO::N_LIB;
|
|
LibInstallName.emplace(DMO.getInstallName().value());
|
|
const RelocationMap &RM = DMO.getRelocationMap().value();
|
|
for (const auto &Reloc : RM.relocations()) {
|
|
const auto *DebugMapEntry = DMO.lookupSymbol(Reloc.SymbolName);
|
|
if (!DebugMapEntry)
|
|
continue;
|
|
std::optional<uint64_t> ObjAddress;
|
|
ObjAddress.emplace(DebugMapEntry->getValue().ObjectAddress.value());
|
|
ValidDebugInfoRelocs.emplace_back(
|
|
Reloc.Offset, Reloc.Size, Reloc.Addend, Reloc.SymbolName,
|
|
SymbolMapping(ObjAddress, DebugMapEntry->getValue().BinaryAddress,
|
|
DebugMapEntry->getValue().Size));
|
|
// FIXME: Support relocations debug_addr.
|
|
}
|
|
} else {
|
|
findValidRelocsInDebugSections(Obj, DMO);
|
|
}
|
|
}
|
|
~AddressManager() override { clear(); }
|
|
|
|
bool hasValidRelocs() override {
|
|
return !ValidDebugInfoRelocs.empty() || !ValidDebugAddrRelocs.empty();
|
|
}
|
|
|
|
/// \defgroup FindValidRelocations Translate debug map into a list
|
|
/// of relevant relocations
|
|
///
|
|
/// @{
|
|
bool findValidRelocsInDebugSections(const object::ObjectFile &Obj,
|
|
const DebugMapObject &DMO);
|
|
|
|
bool findValidRelocs(const object::SectionRef &Section,
|
|
const object::ObjectFile &Obj,
|
|
const DebugMapObject &DMO,
|
|
std::vector<ValidReloc> &ValidRelocs);
|
|
|
|
void findValidRelocsMachO(const object::SectionRef &Section,
|
|
const object::MachOObjectFile &Obj,
|
|
const DebugMapObject &DMO,
|
|
std::vector<ValidReloc> &ValidRelocs);
|
|
/// @}
|
|
|
|
/// Checks that there is a relocation in the \p Relocs array against a
|
|
/// debug map entry between \p StartOffset and \p NextOffset.
|
|
/// Print debug output if \p Verbose is set.
|
|
///
|
|
/// \returns relocation value if relocation exist, otherwise std::nullopt.
|
|
std::optional<int64_t>
|
|
hasValidRelocationAt(const std::vector<ValidReloc> &Relocs,
|
|
uint64_t StartOffset, uint64_t EndOffset,
|
|
bool Verbose);
|
|
|
|
std::optional<int64_t> getExprOpAddressRelocAdjustment(
|
|
DWARFUnit &U, const DWARFExpression::Operation &Op,
|
|
uint64_t StartOffset, uint64_t EndOffset, bool Verbose) override;
|
|
|
|
std::optional<int64_t> getSubprogramRelocAdjustment(const DWARFDie &DIE,
|
|
bool Verbose) override;
|
|
|
|
std::optional<StringRef> getLibraryInstallName() override;
|
|
|
|
bool applyValidRelocs(MutableArrayRef<char> Data, uint64_t BaseOffset,
|
|
bool IsLittleEndian) override;
|
|
|
|
bool needToSaveValidRelocs() override { return true; }
|
|
|
|
void updateAndSaveValidRelocs(bool IsDWARF5, uint64_t OriginalUnitOffset,
|
|
int64_t LinkedOffset, uint64_t StartOffset,
|
|
uint64_t EndOffset) override;
|
|
|
|
void updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset,
|
|
uint64_t OutputUnitOffset) override;
|
|
|
|
void clear() override {
|
|
ValidDebugInfoRelocs.clear();
|
|
ValidDebugAddrRelocs.clear();
|
|
}
|
|
};
|
|
|
|
private:
|
|
/// \defgroup Helpers Various helper methods.
|
|
///
|
|
/// @{
|
|
template <typename OutStreamer>
|
|
bool createStreamer(const Triple &TheTriple,
|
|
typename OutStreamer::OutputFileType FileType,
|
|
std::unique_ptr<OutStreamer> &Streamer,
|
|
raw_fd_ostream &OutFile);
|
|
|
|
/// Attempt to load a debug object from disk.
|
|
ErrorOr<const object::ObjectFile &> loadObject(const DebugMapObject &Obj,
|
|
const Triple &triple);
|
|
ErrorOr<std::unique_ptr<dwarf_linker::DWARFFile>>
|
|
loadObject(const DebugMapObject &Obj, const DebugMap &DebugMap,
|
|
remarks::RemarkLinker &RL,
|
|
std::shared_ptr<DwarfLinkerForBinaryRelocationMap> DLBRM);
|
|
|
|
void collectRelocationsToApplyToSwiftReflectionSections(
|
|
const object::SectionRef &Section, StringRef &Contents,
|
|
const llvm::object::MachOObjectFile *MO,
|
|
const std::vector<uint64_t> &SectionToOffsetInDwarf,
|
|
const llvm::dsymutil::DebugMapObject *Obj,
|
|
std::vector<MachOUtils::DwarfRelocationApplicationInfo>
|
|
&RelocationsToApply) const;
|
|
|
|
Error copySwiftInterfaces(StringRef Architecture) const;
|
|
|
|
void copySwiftReflectionMetadata(
|
|
const llvm::dsymutil::DebugMapObject *Obj,
|
|
classic::DwarfStreamer *Streamer,
|
|
std::vector<uint64_t> &SectionToOffsetInDwarf,
|
|
std::vector<MachOUtils::DwarfRelocationApplicationInfo>
|
|
&RelocationsToApply);
|
|
|
|
template <typename Linker>
|
|
bool linkImpl(const DebugMap &Map,
|
|
typename Linker::OutputFileType ObjectType);
|
|
|
|
Error emitRelocations(const DebugMap &DM,
|
|
std::vector<ObjectWithRelocMap> &ObjectsForLinking);
|
|
|
|
raw_fd_ostream &OutFile;
|
|
BinaryHolder &BinHolder;
|
|
LinkOptions Options;
|
|
std::mutex &ErrorHandlerMutex;
|
|
|
|
std::vector<std::string> EmptyWarnings;
|
|
|
|
/// A list of all .swiftinterface files referenced by the debug
|
|
/// info, mapping Module name to path on disk. The entries need to
|
|
/// be uniqued and sorted and there are only few entries expected
|
|
/// per compile unit, which is why this is a std::map.
|
|
std::map<std::string, std::string> ParseableSwiftInterfaces;
|
|
|
|
bool ModuleCacheHintDisplayed = false;
|
|
bool ArchiveHintDisplayed = false;
|
|
bool HasVerificationErrors = false;
|
|
};
|
|
|
|
} // end namespace dsymutil
|
|
} // end namespace llvm
|
|
|
|
#endif // LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H
|