1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
|
//===- OutputSections.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_LIB_DWARFLINKER_PARALLEL_OUTPUTSECTIONS_H
#define LLVM_LIB_DWARFLINKER_PARALLEL_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/DWARFLinker/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 dwarf_linker {
namespace parallel {
class TypeUnit;
/// 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;
};
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 : SectionDescriptorBase {
friend OutputSections;
SectionDescriptor(DebugSectionKind SectionKind, LinkingGlobalData &GlobalData,
dwarf::FormParams Format, llvm::endianness Endianess)
: SectionDescriptorBase(SectionKind, Format, 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) {}
/// Erase whole section content(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 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 ¬ePatch(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(¬ePatch(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() override {
if (SectionOffsetInsideAsmPrinterOutputStart == 0)
return StringRef(Contents.data(), Contents.size());
return Contents.slice(SectionOffsetInsideAsmPrinterOutputStart,
SectionOffsetInsideAsmPrinterOutputEnd);
}
/// 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);
void emitBinaryData(llvm::StringRef Data);
/// 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 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;
/// 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;
};
/// 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());
assert(It->second.get() != nullptr);
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.get();
}
/// 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.get();
}
/// Returns descriptor for the specified section of \p SectionKind.
/// If descriptor does not exist then creates it.
SectionDescriptor &
getOrCreateSectionDescriptor(DebugSectionKind SectionKind) {
SectionsSetTy::iterator It = SectionDescriptors.find(SectionKind);
if (It == SectionDescriptors.end()) {
SectionDescriptor *Section =
new SectionDescriptor(SectionKind, GlobalData, Format, Endianness);
auto Result = SectionDescriptors.try_emplace(SectionKind, Section);
assert(Result.second);
It = Result.first;
}
return *It->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) {
assert(Section.second.get() != nullptr);
Handler(*(Section.second));
}
}
/// Enumerate all sections and call \p Handler for each.
void forEach(
function_ref<void(std::shared_ptr<SectionDescriptor> Section)> 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:
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, std::shared_ptr<SectionDescriptor>>;
SectionsSetTy SectionDescriptors;
};
} // end of namespace parallel
} // end of namespace dwarf_linker
} // end of namespace llvm
#endif // LLVM_LIB_DWARFLINKER_PARALLEL_OUTPUTSECTIONS_H
|