aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/DWARFLinkerParallel/OutputSections.h
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/DWARFLinkerParallel/OutputSections.h')
-rw-r--r--llvm/lib/DWARFLinkerParallel/OutputSections.h503
1 files changed, 469 insertions, 34 deletions
diff --git a/llvm/lib/DWARFLinkerParallel/OutputSections.h b/llvm/lib/DWARFLinkerParallel/OutputSections.h
index 15ab4cc1167a..f23b2efb869d 100644
--- a/llvm/lib/DWARFLinkerParallel/OutputSections.h
+++ b/llvm/lib/DWARFLinkerParallel/OutputSections.h
@@ -9,56 +9,491 @@
#ifndef LLVM_LIB_DWARFLINKERPARALLEL_OUTPUTSECTIONS_H
#define LLVM_LIB_DWARFLINKERPARALLEL_OUTPUTSECTIONS_H
+#include "ArrayList.h"
+#include "StringEntryToDwarfStringPoolEntryMap.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/CodeGen/DwarfStringPoolEntry.h"
+#include "llvm/DWARFLinkerParallel/StringPool.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFObject.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/MemoryBufferRef.h"
+#include "llvm/Support/raw_ostream.h"
#include <array>
#include <cstdint>
namespace llvm {
namespace dwarflinker_parallel {
-/// This class keeps offsets to the debug sections. Any object which is
-/// supposed to be emitted into the debug section should use this class to
-/// track debug sections offsets.
-class OutputSections {
-public:
- /// List of tracked debug sections.
- enum class DebugSectionKind : uint8_t {
- DebugInfo = 0,
- DebugLine,
- DebugFrame,
- DebugRange,
- DebugRngLists,
- DebugLoc,
- DebugLocLists,
- DebugARanges,
- DebugAbbrev,
- DebugMacinfo,
- DebugMacro,
- };
- constexpr static size_t SectionKindsNum = 11;
+class TypeUnit;
+
+/// List of tracked debug tables.
+enum class DebugSectionKind : uint8_t {
+ DebugInfo = 0,
+ DebugLine,
+ DebugFrame,
+ DebugRange,
+ DebugRngLists,
+ DebugLoc,
+ DebugLocLists,
+ DebugARanges,
+ DebugAbbrev,
+ DebugMacinfo,
+ DebugMacro,
+ DebugAddr,
+ DebugStr,
+ DebugLineStr,
+ DebugStrOffsets,
+ DebugPubNames,
+ DebugPubTypes,
+ DebugNames,
+ AppleNames,
+ AppleNamespaces,
+ AppleObjC,
+ AppleTypes,
+ NumberOfEnumEntries // must be last
+};
+constexpr static size_t SectionKindsNum =
+ static_cast<size_t>(DebugSectionKind::NumberOfEnumEntries);
+
+/// Recognise the table name and match it with the DebugSectionKind.
+std::optional<DebugSectionKind> parseDebugTableName(StringRef Name);
+
+/// Return the name of the section.
+const StringLiteral &getSectionName(DebugSectionKind SectionKind);
+
+/// There are fields(sizes, offsets) which should be updated after
+/// sections are generated. To remember offsets and related data
+/// the descendants of SectionPatch structure should be used.
+
+struct SectionPatch {
+ uint64_t PatchOffset = 0;
+};
+
+/// This structure is used to update strings offsets into .debug_str.
+struct DebugStrPatch : SectionPatch {
+ const StringEntry *String = nullptr;
+};
+
+/// This structure is used to update strings offsets into .debug_line_str.
+struct DebugLineStrPatch : SectionPatch {
+ const StringEntry *String = nullptr;
+};
+
+/// This structure is used to update range list offset into
+/// .debug_ranges/.debug_rnglists.
+struct DebugRangePatch : SectionPatch {
+ /// Indicates patch which points to immediate compile unit's attribute.
+ bool IsCompileUnitRanges = false;
+};
+
+/// This structure is used to update location list offset into
+/// .debug_loc/.debug_loclists.
+struct DebugLocPatch : SectionPatch {
+ int64_t AddrAdjustmentValue = 0;
+};
+
+/// This structure is used to update offset with start of another section.
+struct SectionDescriptor;
+struct DebugOffsetPatch : SectionPatch {
+ DebugOffsetPatch(uint64_t PatchOffset, SectionDescriptor *SectionPtr,
+ bool AddLocalValue = false)
+ : SectionPatch({PatchOffset}), SectionPtr(SectionPtr, AddLocalValue) {}
+
+ PointerIntPair<SectionDescriptor *, 1> SectionPtr;
+};
+
+/// This structure is used to update reference to the DIE.
+struct DebugDieRefPatch : SectionPatch {
+ DebugDieRefPatch(uint64_t PatchOffset, CompileUnit *SrcCU, CompileUnit *RefCU,
+ uint32_t RefIdx);
+
+ PointerIntPair<CompileUnit *, 1> RefCU;
+ uint64_t RefDieIdxOrClonedOffset = 0;
+};
+
+/// This structure is used to update reference to the DIE of ULEB128 form.
+struct DebugULEB128DieRefPatch : SectionPatch {
+ DebugULEB128DieRefPatch(uint64_t PatchOffset, CompileUnit *SrcCU,
+ CompileUnit *RefCU, uint32_t RefIdx);
+
+ PointerIntPair<CompileUnit *, 1> RefCU;
+ uint64_t RefDieIdxOrClonedOffset = 0;
+};
+
+/// This structure is used to update reference to the type DIE.
+struct DebugDieTypeRefPatch : SectionPatch {
+ DebugDieTypeRefPatch(uint64_t PatchOffset, TypeEntry *RefTypeName);
+
+ TypeEntry *RefTypeName = nullptr;
+};
+
+/// This structure is used to update reference to the type DIE.
+struct DebugType2TypeDieRefPatch : SectionPatch {
+ DebugType2TypeDieRefPatch(uint64_t PatchOffset, DIE *Die, TypeEntry *TypeName,
+ TypeEntry *RefTypeName);
+
+ DIE *Die = nullptr;
+ TypeEntry *TypeName = nullptr;
+ TypeEntry *RefTypeName = nullptr;
+};
- /// Recognise the section name and match it with the DebugSectionKind.
- static std::optional<DebugSectionKind> parseDebugSectionName(StringRef Name);
+struct DebugTypeStrPatch : SectionPatch {
+ DebugTypeStrPatch(uint64_t PatchOffset, DIE *Die, TypeEntry *TypeName,
+ StringEntry *String);
+
+ DIE *Die = nullptr;
+ TypeEntry *TypeName = nullptr;
+ StringEntry *String = nullptr;
+};
+
+struct DebugTypeLineStrPatch : SectionPatch {
+ DebugTypeLineStrPatch(uint64_t PatchOffset, DIE *Die, TypeEntry *TypeName,
+ StringEntry *String);
+
+ DIE *Die = nullptr;
+ TypeEntry *TypeName = nullptr;
+ StringEntry *String = nullptr;
+};
+
+struct DebugTypeDeclFilePatch {
+ DebugTypeDeclFilePatch(DIE *Die, TypeEntry *TypeName, StringEntry *Directory,
+ StringEntry *FilePath);
+
+ DIE *Die = nullptr;
+ TypeEntry *TypeName = nullptr;
+ StringEntry *Directory = nullptr;
+ StringEntry *FilePath = nullptr;
+ uint32_t FileID = 0;
+};
+
+/// Type for section data.
+using OutSectionDataTy = SmallString<0>;
+
+/// Type for list of pointers to patches offsets.
+using OffsetsPtrVector = SmallVector<uint64_t *>;
+
+class OutputSections;
+
+/// This structure is used to keep data of the concrete section.
+/// Like data bits, list of patches, format.
+struct SectionDescriptor {
+ friend OutputSections;
+
+ SectionDescriptor(DebugSectionKind SectionKind, LinkingGlobalData &GlobalData,
+ dwarf::FormParams Format, llvm::endianness Endianess)
+ : OS(Contents), ListDebugStrPatch(&GlobalData.getAllocator()),
+ ListDebugLineStrPatch(&GlobalData.getAllocator()),
+ ListDebugRangePatch(&GlobalData.getAllocator()),
+ ListDebugLocPatch(&GlobalData.getAllocator()),
+ ListDebugDieRefPatch(&GlobalData.getAllocator()),
+ ListDebugULEB128DieRefPatch(&GlobalData.getAllocator()),
+ ListDebugOffsetPatch(&GlobalData.getAllocator()),
+ ListDebugDieTypeRefPatch(&GlobalData.getAllocator()),
+ ListDebugType2TypeDieRefPatch(&GlobalData.getAllocator()),
+ ListDebugTypeStrPatch(&GlobalData.getAllocator()),
+ ListDebugTypeLineStrPatch(&GlobalData.getAllocator()),
+ ListDebugTypeDeclFilePatch(&GlobalData.getAllocator()),
+ GlobalData(GlobalData), SectionKind(SectionKind), Format(Format),
+ Endianess(Endianess) {}
+
+ /// Erase whole section contents(data bits, list of patches).
+ void clearAllSectionData();
+
+ /// Erase only section output data bits.
+ void clearSectionContent();
/// When objects(f.e. compile units) are glued into the single file,
/// the debug sections corresponding to the concrete object are assigned
- /// with offsets inside the whole file. This method returns offset
- /// to the \p SectionKind debug section, corresponding to this object.
- uint64_t getStartOffset(DebugSectionKind SectionKind) const {
- return Offsets[static_cast<
- typename std::underlying_type<DebugSectionKind>::type>(SectionKind)];
+ /// with offsets inside the whole file. This field keeps offset
+ /// to the debug section, corresponding to this object.
+ uint64_t StartOffset = 0;
+
+ /// Stream which stores data to the Contents.
+ raw_svector_ostream OS;
+
+ /// Section patches.
+#define ADD_PATCHES_LIST(T) \
+ T &notePatch(const T &Patch) { return List##T.add(Patch); } \
+ ArrayList<T> List##T;
+
+ ADD_PATCHES_LIST(DebugStrPatch)
+ ADD_PATCHES_LIST(DebugLineStrPatch)
+ ADD_PATCHES_LIST(DebugRangePatch)
+ ADD_PATCHES_LIST(DebugLocPatch)
+ ADD_PATCHES_LIST(DebugDieRefPatch)
+ ADD_PATCHES_LIST(DebugULEB128DieRefPatch)
+ ADD_PATCHES_LIST(DebugOffsetPatch)
+ ADD_PATCHES_LIST(DebugDieTypeRefPatch)
+ ADD_PATCHES_LIST(DebugType2TypeDieRefPatch)
+ ADD_PATCHES_LIST(DebugTypeStrPatch)
+ ADD_PATCHES_LIST(DebugTypeLineStrPatch)
+ ADD_PATCHES_LIST(DebugTypeDeclFilePatch)
+
+ /// While creating patches, offsets to attributes may be partially
+ /// unknown(because size of abbreviation number is unknown). In such case we
+ /// remember patch itself and pointer to patch application offset to add size
+ /// of abbreviation number later.
+ template <typename T>
+ void notePatchWithOffsetUpdate(const T &Patch,
+ OffsetsPtrVector &PatchesOffsetsList) {
+ PatchesOffsetsList.emplace_back(&notePatch(Patch).PatchOffset);
+ }
+
+ /// Some sections are emitted using AsmPrinter. In that case "Contents"
+ /// member of SectionDescriptor contains elf file. This method searches
+ /// for section data inside elf file and remember offset to it.
+ void setSizesForSectionCreatedByAsmPrinter();
+
+ /// Returns section content.
+ StringRef getContents() {
+ if (SectionOffsetInsideAsmPrinterOutputStart == 0)
+ return StringRef(Contents.data(), Contents.size());
+
+ return Contents.slice(SectionOffsetInsideAsmPrinterOutputStart,
+ SectionOffsetInsideAsmPrinterOutputEnd);
}
- /// Set offset to the start of specified \p SectionKind debug section,
- /// corresponding to this object.
- void setStartOffset(DebugSectionKind SectionKind, uint64_t Offset) {
- Offsets[static_cast<typename std::underlying_type<DebugSectionKind>::type>(
- SectionKind)] = Offset;
+ /// Emit unit length into the current section contents.
+ void emitUnitLength(uint64_t Length) {
+ maybeEmitDwarf64Mark();
+ emitIntVal(Length, getFormParams().getDwarfOffsetByteSize());
+ }
+
+ /// Emit DWARF64 mark into the current section contents.
+ void maybeEmitDwarf64Mark() {
+ if (getFormParams().Format != dwarf::DWARF64)
+ return;
+ emitIntVal(dwarf::DW_LENGTH_DWARF64, 4);
+ }
+
+ /// Emit specified offset value into the current section contents.
+ void emitOffset(uint64_t Val) {
+ emitIntVal(Val, getFormParams().getDwarfOffsetByteSize());
+ }
+
+ /// Emit specified integer value into the current section contents.
+ void emitIntVal(uint64_t Val, unsigned Size);
+
+ void emitString(dwarf::Form StringForm, const char *StringVal);
+
+ /// Emit specified inplace string value into the current section contents.
+ void emitInplaceString(StringRef String) {
+ OS << GlobalData.translateString(String);
+ emitIntVal(0, 1);
}
+ /// Emit string placeholder into the current section contents.
+ void emitStringPlaceholder() {
+ // emit bad offset which should be updated later.
+ emitOffset(0xBADDEF);
+ }
+
+ /// Write specified \p Value of \p AttrForm to the \p PatchOffset.
+ void apply(uint64_t PatchOffset, dwarf::Form AttrForm, uint64_t Val);
+
+ /// Returns section kind.
+ DebugSectionKind getKind() { return SectionKind; }
+
+ /// Returns section name.
+ const StringLiteral &getName() const { return getSectionName(SectionKind); }
+
+ /// Returns endianess used by section.
+ llvm::endianness getEndianess() const { return Endianess; }
+
+ /// Returns FormParams used by section.
+ dwarf::FormParams getFormParams() const { return Format; }
+
+ /// Returns integer value of \p Size located by specified \p PatchOffset.
+ uint64_t getIntVal(uint64_t PatchOffset, unsigned Size);
+
+protected:
+ /// Writes integer value \p Val of \p Size by specified \p PatchOffset.
+ void applyIntVal(uint64_t PatchOffset, uint64_t Val, unsigned Size);
+
+ /// Writes integer value \p Val of ULEB128 format by specified \p PatchOffset.
+ void applyULEB128(uint64_t PatchOffset, uint64_t Val);
+
+ /// Writes integer value \p Val of SLEB128 format by specified \p PatchOffset.
+ void applySLEB128(uint64_t PatchOffset, uint64_t Val);
+
+ /// Sets output format.
+ void setOutputFormat(dwarf::FormParams Format, llvm::endianness Endianess) {
+ this->Format = Format;
+ this->Endianess = Endianess;
+ }
+
+ LinkingGlobalData &GlobalData;
+
+ /// The section kind.
+ DebugSectionKind SectionKind = DebugSectionKind::NumberOfEnumEntries;
+
+ /// Section data bits.
+ OutSectionDataTy Contents;
+
+ /// Some sections are generated using AsmPrinter. The real section data
+ /// located inside elf file in that case. Following fields points to the
+ /// real section content inside elf file.
+ size_t SectionOffsetInsideAsmPrinterOutputStart = 0;
+ size_t SectionOffsetInsideAsmPrinterOutputEnd = 0;
+
+ /// Output format.
+ dwarf::FormParams Format = {4, 4, dwarf::DWARF32};
+ llvm::endianness Endianess = llvm::endianness::little;
+};
+
+/// This class keeps contents and offsets to the debug sections. Any objects
+/// which is supposed to be emitted into the debug sections should use this
+/// class to track debug sections offsets and keep sections data.
+class OutputSections {
+public:
+ OutputSections(LinkingGlobalData &GlobalData) : GlobalData(GlobalData) {}
+
+ /// Sets output format for all keeping sections.
+ void setOutputFormat(dwarf::FormParams Format, llvm::endianness Endianness) {
+ this->Format = Format;
+ this->Endianness = Endianness;
+ }
+
+ /// Returns descriptor for the specified section of \p SectionKind.
+ /// The descriptor should already be created. The llvm_unreachable
+ /// would be raised if it is not.
+ const SectionDescriptor &
+ getSectionDescriptor(DebugSectionKind SectionKind) const {
+ SectionsSetTy::const_iterator It = SectionDescriptors.find(SectionKind);
+
+ if (It == SectionDescriptors.end())
+ llvm_unreachable(
+ formatv("Section {0} does not exist", getSectionName(SectionKind))
+ .str()
+ .c_str());
+
+ return It->second;
+ }
+
+ /// Returns descriptor for the specified section of \p SectionKind.
+ /// The descriptor should already be created. The llvm_unreachable
+ /// would be raised if it is not.
+ SectionDescriptor &getSectionDescriptor(DebugSectionKind SectionKind) {
+ SectionsSetTy::iterator It = SectionDescriptors.find(SectionKind);
+
+ if (It == SectionDescriptors.end())
+ llvm_unreachable(
+ formatv("Section {0} does not exist", getSectionName(SectionKind))
+ .str()
+ .c_str());
+
+ return It->second;
+ }
+
+ /// Returns descriptor for the specified section of \p SectionKind.
+ /// Returns std::nullopt if section descriptor is not created yet.
+ std::optional<const SectionDescriptor *>
+ tryGetSectionDescriptor(DebugSectionKind SectionKind) const {
+ SectionsSetTy::const_iterator It = SectionDescriptors.find(SectionKind);
+
+ if (It == SectionDescriptors.end())
+ return std::nullopt;
+
+ return &It->second;
+ }
+
+ /// Returns descriptor for the specified section of \p SectionKind.
+ /// Returns std::nullopt if section descriptor is not created yet.
+ std::optional<SectionDescriptor *>
+ tryGetSectionDescriptor(DebugSectionKind SectionKind) {
+ SectionsSetTy::iterator It = SectionDescriptors.find(SectionKind);
+
+ if (It == SectionDescriptors.end())
+ return std::nullopt;
+
+ return &It->second;
+ }
+
+ /// Returns descriptor for the specified section of \p SectionKind.
+ /// If descriptor does not exist then creates it.
+ SectionDescriptor &
+ getOrCreateSectionDescriptor(DebugSectionKind SectionKind) {
+ return SectionDescriptors
+ .try_emplace(SectionKind, SectionKind, GlobalData, Format, Endianness)
+ .first->second;
+ }
+
+ /// Erases data of all sections.
+ void eraseSections() {
+ for (auto &Section : SectionDescriptors)
+ Section.second.clearAllSectionData();
+ }
+
+ /// Enumerate all sections and call \p Handler for each.
+ void forEach(function_ref<void(SectionDescriptor &)> Handler) {
+ for (auto &Section : SectionDescriptors)
+ Handler(Section.second);
+ }
+
+ /// Enumerate all sections, for each section set current offset
+ /// (kept by \p SectionSizesAccumulator), update current offset with section
+ /// length.
+ void assignSectionsOffsetAndAccumulateSize(
+ std::array<uint64_t, SectionKindsNum> &SectionSizesAccumulator) {
+ for (auto &Section : SectionDescriptors) {
+ Section.second.StartOffset = SectionSizesAccumulator[static_cast<uint8_t>(
+ Section.second.getKind())];
+ SectionSizesAccumulator[static_cast<uint8_t>(Section.second.getKind())] +=
+ Section.second.getContents().size();
+ }
+ }
+
+ /// Enumerate all sections, for each section apply all section patches.
+ void applyPatches(SectionDescriptor &Section,
+ StringEntryToDwarfStringPoolEntryMap &DebugStrStrings,
+ StringEntryToDwarfStringPoolEntryMap &DebugLineStrStrings,
+ TypeUnit *TypeUnitPtr);
+
+ /// Endiannes for the sections.
+ llvm::endianness getEndianness() const { return Endianness; }
+
+ /// Return DWARF version.
+ uint16_t getVersion() const { return Format.Version; }
+
+ /// Return size of header of debug_info table.
+ uint16_t getDebugInfoHeaderSize() const {
+ return Format.Version >= 5 ? 12 : 11;
+ }
+
+ /// Return size of header of debug_ table.
+ uint16_t getDebugAddrHeaderSize() const {
+ assert(Format.Version >= 5);
+ return Format.Format == dwarf::DwarfFormat::DWARF32 ? 8 : 16;
+ }
+
+ /// Return size of header of debug_str_offsets table.
+ uint16_t getDebugStrOffsetsHeaderSize() const {
+ assert(Format.Version >= 5);
+ return Format.Format == dwarf::DwarfFormat::DWARF32 ? 8 : 16;
+ }
+
+ /// Return size of address.
+ const dwarf::FormParams &getFormParams() const { return Format; }
+
protected:
- /// Offsets to the debug sections composing this object.
- std::array<uint64_t, SectionKindsNum> Offsets = {0};
+ LinkingGlobalData &GlobalData;
+
+ /// Format for sections.
+ dwarf::FormParams Format = {4, 4, dwarf::DWARF32};
+
+ /// Endiannes for sections.
+ llvm::endianness Endianness = llvm::endianness::native;
+
+ /// All keeping sections.
+ using SectionsSetTy = std::map<DebugSectionKind, SectionDescriptor>;
+ SectionsSetTy SectionDescriptors;
};
} // end of namespace dwarflinker_parallel