[llvm-dwp] Replace MCStreamer with direct ELF writer for zero-copy output (#192112)

Replace the MCStreamer-based output pipeline with a lightweight direct
ELF writer (DWPWriter). Section data is stored as zero-copy StringRef
chunks pointing to the mmap'd input files, and written as a minimal
ELF64 relocatable object directly to disk.

## Rationale
The MCStreamer pipeline copies all section data into 16KB MCDataFragment
blocks, accumulates them in memory, then writes everything out during
MCAssembler::Finish(). This can be cause lots of memory pressure and
slow down llvm-dwp.

For instance, on a 3.3GB DWP file, this translates to rougly ~3.3GB of
heap allocation and two full copies of the data.

The new DWPWriter avoids this via:
- emitBytes() stores a StringRef chunk (zero-copy, no allocation)
- emitIntValue() writes to a small per-section buffer (index tables)
- writeELF() streams chunks directly from input mmap to output file
- for single-input DWP files, string deduplication is also skipped since
all strings are already unique. (minor optimization)
 
Bonus: this also removes all MC library dependencies from llvm-dwp
(AllTargetsCodeGens, AllTargetsDescs, AllTargetsInfos, MC,
TargetParser), reducing the binary size.

## Benchmark
I benchmarked on a 3.3GB production DWP file (8638 CUs, ~981MB
.debug_str.dwo):

Results:
    Before: 23.6s wall (19.6s user, 3.9s sys)
    After:   6.0s wall  (3.0s user, 2.9s sys)

**3.9x**  wall time improvement, 6x fewer page faults (178K vs ~1M).
This commit is contained in:
Farid Zakaria
2026-04-29 14:33:50 -07:00
committed by GitHub
parent a9cef141e9
commit caa18a808a
9 changed files with 581 additions and 274 deletions

View File

@@ -4,18 +4,23 @@
#include "DWPStringPool.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Error.h"
#include <deque>
#include <vector>
namespace llvm::object {
class ObjectFile;
}
namespace llvm {
class raw_pwrite_stream;
enum OnCuIndexOverflow {
HardStop,
SoftStop,
@@ -28,6 +33,115 @@ enum Dwarf64StrOffsetsPromotion {
Always, ///< Always emit .debug_str_offsets talbes as DWARF64 for testing.
};
/// Section identifiers for DWP output.
enum DWPSectionId : unsigned {
DS_Info,
DS_Types,
DS_Abbrev,
DS_Line,
DS_Loc,
DS_Loclists,
DS_Rnglists,
DS_Macro,
DS_Str,
DS_StrOffsets,
DS_CUIndex,
DS_TUIndex,
DS_NumSections
};
/// Direct ELF writer for DWP output, bypassing MCStreamer.
///
/// Section data is stored as zero-copy StringRef chunks pointing to the
/// mmap'd input files, plus an inline buffer for constructed data
/// (emitIntValue). This avoids copying gigabytes of debug section data
/// through the MC infrastructure (MCContext, MCAssembler, MCDataFragment
/// allocation, layout, etc.).
class LLVM_ABI DWPWriter {
/// Per-section storage: ordered sequence of zero-copy chunks and inline
/// data. emitBytes() adds zero-copy StringRef references, emitIntValue()
/// appends to an inline buffer. When emitBytes() is called with pending
/// inline data, the buffer is flushed to an owned block first to preserve
/// the correct interleaving order in the output.
struct SectionData {
SmallVector<StringRef, 4> Chunks; // ordered segments (refs + flushed bufs)
SmallVector<char, 0> Buffer; // pending inline data (emitIntValue)
// Heap storage for flushed buffers. Uses std::deque so that push_back
// does not invalidate existing elements (StringRefs point into these).
std::deque<SmallVector<char, 0>> OwnedBuffers;
/// Flush pending Buffer data into Chunks as an owned block.
void flushBuffer() {
if (!Buffer.empty()) {
OwnedBuffers.push_back(std::move(Buffer));
auto &B = OwnedBuffers.back();
Chunks.push_back(StringRef(B.data(), B.size()));
Buffer = SmallVector<char, 0>();
}
}
uint64_t totalSize() const {
uint64_t Size = 0;
for (auto &C : Chunks)
Size += C.size();
Size += Buffer.size();
return Size;
}
bool empty() const { return Chunks.empty() && Buffer.empty(); }
void writeTo(raw_ostream &OS) const {
for (auto &C : Chunks)
OS.write(C.data(), C.size());
if (!Buffer.empty())
OS.write(Buffer.data(), Buffer.size());
}
};
SectionData Sections[DS_NumSections];
DWPSectionId CurrentSection = DS_Info;
uint16_t ELFMachine = 0;
uint8_t ELFOSABI = 0;
bool IsWASM = false;
public:
DWPWriter() = default;
void setMachine(uint16_t Machine) { ELFMachine = Machine; }
void setOSABI(uint8_t OSABI) { ELFOSABI = OSABI; }
void setIsWASM(bool V) { IsWASM = V; }
SmallVectorImpl<char> &getSectionBuffer(DWPSectionId Id) {
return Sections[Id].Buffer;
}
void switchSection(DWPSectionId Id) { CurrentSection = Id; }
/// Zero-copy: stores a reference to the input data without copying.
/// Flushes any pending inline data first to preserve output order.
void emitBytes(StringRef Data) {
if (!Data.empty()) {
auto &SD = Sections[CurrentSection];
SD.flushBuffer();
SD.Chunks.push_back(Data);
}
}
void emitIntValue(uint64_t Value, unsigned Size) {
auto &Buf = Sections[CurrentSection].Buffer;
for (unsigned I = 0; I < Size; ++I) {
Buf.push_back(static_cast<char>(Value & 0xff));
Value >>= 8;
}
}
Error writeELF(raw_pwrite_stream &OS);
Error writeWASM(raw_pwrite_stream &OS);
Error write(raw_pwrite_stream &OS) {
return IsWASM ? writeWASM(OS) : writeELF(OS);
}
};
struct UnitIndexEntry {
DWARFUnitIndex::Entry::SectionContribution Contributions[8];
std::string Name;
@@ -73,45 +187,15 @@ struct CompileUnitIdentifiers {
const char *DWOName = "";
};
LLVM_ABI Error write(MCStreamer &Out, ArrayRef<std::string> Inputs,
LLVM_ABI Error write(DWPWriter &Out, ArrayRef<std::string> Inputs,
OnCuIndexOverflow OverflowOptValue,
Dwarf64StrOffsetsPromotion StrOffsetsOptValue);
Dwarf64StrOffsetsPromotion StrOffsetsOptValue,
raw_pwrite_stream *OS = nullptr);
typedef std::vector<std::pair<DWARFSectionKind, uint32_t>> SectionLengths;
LLVM_ABI Error handleSection(
const StringMap<std::pair<MCSection *, DWARFSectionKind>> &KnownSections,
const MCSection *StrSection, const MCSection *StrOffsetSection,
const MCSection *TypesSection, const MCSection *CUIndexSection,
const MCSection *TUIndexSection, const MCSection *InfoSection,
const object::SectionRef &Section, MCStreamer &Out,
std::deque<SmallString<32>> &UncompressedSections,
uint32_t (&ContributionOffsets)[8], UnitIndexEntry &CurEntry,
StringRef &CurStrSection, StringRef &CurStrOffsetSection,
std::vector<StringRef> &CurTypesSection,
std::vector<StringRef> &CurInfoSection, StringRef &AbbrevSection,
StringRef &CurCUIndexSection, StringRef &CurTUIndexSection,
SectionLengths &SectionLength);
LLVM_ABI Expected<InfoSectionUnitHeader>
parseInfoSectionUnitHeader(StringRef Info);
LLVM_ABI void
writeStringsAndOffsets(MCStreamer &Out, DWPStringPool &Strings,
MCSection *StrOffsetSection, StringRef CurStrSection,
StringRef CurStrOffsetSection, uint16_t Version,
SectionLengths &SectionLength,
const Dwarf64StrOffsetsPromotion StrOffsetsOptValue);
LLVM_ABI Error
buildDuplicateError(const std::pair<uint64_t, UnitIndexEntry> &PrevE,
const CompileUnitIdentifiers &ID, StringRef DWPName);
LLVM_ABI void
writeIndex(MCStreamer &Out, MCSection *Section,
ArrayRef<unsigned> ContributionOffsets,
const MapVector<uint64_t, UnitIndexEntry> &IndexEntries,
uint32_t IndexVersion);
} // namespace llvm
#endif // LLVM_DWP_DWP_H

View File

@@ -2,49 +2,28 @@
#define LLVM_DWP_DWPSTRINGPOOL_H
#include "llvm/ADT/DenseMap.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include <cassert>
namespace llvm {
class DWPStringPool {
struct CStrDenseMapInfo {
static inline const char *getEmptyKey() {
return reinterpret_cast<const char *>(~static_cast<uintptr_t>(0));
}
static inline const char *getTombstoneKey() {
return reinterpret_cast<const char *>(~static_cast<uintptr_t>(1));
}
static unsigned getHashValue(const char *Val) {
assert(Val != getEmptyKey() && "Cannot hash the empty key!");
assert(Val != getTombstoneKey() && "Cannot hash the tombstone key!");
return (unsigned)hash_value(StringRef(Val));
}
static bool isEqual(const char *LHS, const char *RHS) {
if (RHS == getEmptyKey())
return LHS == getEmptyKey();
if (RHS == getTombstoneKey())
return LHS == getTombstoneKey();
return strcmp(LHS, RHS) == 0;
}
};
MCStreamer &Out;
MCSection *Sec;
DenseMap<const char *, uint64_t, CStrDenseMapInfo> Pool;
SmallVectorImpl<char> &Buffer;
// Use StringRef keys instead of const char* to avoid redundant strlen
// on every hash computation and strcmp on every probe comparison.
DenseMap<StringRef, uint64_t> Pool;
uint64_t Offset = 0;
public:
DWPStringPool(MCStreamer &Out, MCSection *Sec) : Out(Out), Sec(Sec) {}
DWPStringPool(SmallVectorImpl<char> &Buffer) : Buffer(Buffer) {}
uint64_t getOffset(const char *Str, unsigned Length) {
assert(strlen(Str) + 1 == Length && "Ensure length hint is correct");
auto Pair = Pool.insert(std::make_pair(Str, Offset));
StringRef Key(Str, Length - 1);
auto Pair = Pool.insert(std::make_pair(Key, Offset));
if (Pair.second) {
Out.switchSection(Sec);
Out.emitBytes(StringRef(Str, Length));
Buffer.insert(Buffer.end(), Str, Str + Length);
Offset += Length;
}

View File

@@ -0,0 +1,37 @@
//===- llvm/DWP/ELFWriter.h - ELF structure writer -----*- 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
//
//===----------------------------------------------------------------------===//
//
// Shared utilities for writing ELF header and section header structures.
// Used by both the MC ELFObjectWriter and the DWP direct ELF writer.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DWP_ELFWRITER_H
#define LLVM_DWP_ELFWRITER_H
#include "llvm/Support/EndianStream.h"
#include <cstdint>
namespace llvm {
namespace ELF {
/// Write an ELF file header (Elf32_Ehdr or Elf64_Ehdr) for an ET_REL object.
void writeHeader(support::endian::Writer &W, bool Is64Bit, uint8_t OSABI,
uint8_t ABIVersion, uint16_t EMachine, uint32_t EFlags,
uint64_t SHOff, uint16_t SHNum, uint16_t SHStrNdx);
/// Write a single ELF section header entry (Elf32_Shdr or Elf64_Shdr).
void writeSectionHeader(support::endian::Writer &W, bool Is64Bit, uint32_t Name,
uint32_t Type, uint64_t Flags, uint64_t Address,
uint64_t Offset, uint64_t Size, uint32_t Link,
uint32_t Info, uint64_t Alignment, uint64_t EntrySize);
} // namespace ELF
} // namespace llvm
#endif // LLVM_DWP_ELFWRITER_H

View File

@@ -1,6 +1,7 @@
add_llvm_component_library(LLVMDWP
DWP.cpp
DWPError.cpp
ELFWriter.cpp
ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/DWP
@@ -10,7 +11,6 @@ add_llvm_component_library(LLVMDWP
LINK_COMPONENTS
DebugInfoDWARF
MC
Object
Support
)

View File

@@ -11,20 +11,22 @@
//
//===----------------------------------------------------------------------===//
#include "llvm/DWP/DWP.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Twine.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/DWP/DWPError.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCTargetOptionsCommandFlags.h"
#include "llvm/DWP/ELFWriter.h"
#include "llvm/Object/Decompressor.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Support/EndianStream.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/MathExtras.h"
#include <limits>
using namespace llvm;
using namespace llvm::object;
static mc::RegisterMCTargetOptionsFlags MCTargetOptionsFlags;
// Returns the size of debug_str_offsets section headers in bytes.
static uint64_t debugStrOffsetsHeaderSize(DataExtractor StrOffsetsData,
uint16_t DwarfVersion) {
@@ -200,12 +202,12 @@ static Error sectionOverflowErrorOrWarning(uint32_t PrevOffset,
}
static Error addAllTypesFromDWP(
MCStreamer &Out, MapVector<uint64_t, UnitIndexEntry> &TypeIndexEntries,
const DWARFUnitIndex &TUIndex, MCSection *OutputTypes, StringRef Types,
DWPWriter &Out, MapVector<uint64_t, UnitIndexEntry> &TypeIndexEntries,
const DWARFUnitIndex &TUIndex, DWPSectionId OutputSection, StringRef Types,
const UnitIndexEntry &TUEntry, uint32_t &TypesOffset,
unsigned TypesContributionIndex, OnCuIndexOverflow OverflowOptValue,
bool &AnySectionOverflow) {
Out.switchSection(OutputTypes);
Out.switchSection(OutputSection);
for (const DWARFUnitIndex::Entry &E : TUIndex.getRows()) {
auto *I = E.getContributions();
if (!I)
@@ -249,12 +251,12 @@ static Error addAllTypesFromDWP(
}
static Error addAllTypesFromTypesSection(
MCStreamer &Out, MapVector<uint64_t, UnitIndexEntry> &TypeIndexEntries,
MCSection *OutputTypes, const std::vector<StringRef> &TypesSections,
DWPWriter &Out, MapVector<uint64_t, UnitIndexEntry> &TypeIndexEntries,
DWPSectionId OutputSection, const std::vector<StringRef> &TypesSections,
const UnitIndexEntry &CUEntry, uint32_t &TypesOffset,
OnCuIndexOverflow OverflowOptValue, bool &AnySectionOverflow) {
for (StringRef Types : TypesSections) {
Out.switchSection(OutputTypes);
Out.switchSection(OutputSection);
uint64_t Offset = 0;
DataExtractor Data(Types, true, 0);
while (Data.isValidOffset(Offset)) {
@@ -351,6 +353,32 @@ handleCompressedSection(std::deque<SmallString<32>> &UncompressedSections,
return Error::success();
}
static Error
buildDuplicateError(const std::pair<uint64_t, UnitIndexEntry> &PrevE,
const CompileUnitIdentifiers &ID, StringRef DWPName) {
return make_error<DWPError>(
std::string("duplicate DWO ID (") + utohexstr(PrevE.first) + ") in " +
buildDWODescription(PrevE.second.Name, PrevE.second.DWPName,
PrevE.second.DWOName) +
" and " + buildDWODescription(ID.Name, DWPName, ID.DWOName));
}
// Create a mask so we don't trigger a emitIntValue() assert below if the
// NewOffset is over 4GB.
static void writeNewOffsetsTo(DWPWriter &Out, DataExtractor &Data,
DenseMap<uint64_t, uint64_t> &OffsetRemapping,
uint64_t &Offset, const uint64_t Size,
uint32_t OldOffsetSize, uint32_t NewOffsetSize) {
const uint64_t NewOffsetMask = NewOffsetSize == 8 ? UINT64_MAX : UINT32_MAX;
while (Offset < Size) {
const uint64_t OldOffset = Data.getUnsigned(&Offset, OldOffsetSize);
const uint64_t NewOffset = OffsetRemapping[OldOffset];
// Truncate the string offset like the old llvm-dwp would have if we aren't
// promoting the .debug_str_offsets to DWARF64.
Out.emitIntValue(NewOffset & NewOffsetMask, NewOffsetSize);
}
}
namespace llvm {
// Parse and return the header of an info section compile/type unit.
Expected<InfoSectionUnitHeader> parseInfoSectionUnitHeader(StringRef Info) {
@@ -412,33 +440,30 @@ Expected<InfoSectionUnitHeader> parseInfoSectionUnitHeader(StringRef Info) {
return Header;
}
static void writeNewOffsetsTo(MCStreamer &Out, DataExtractor &Data,
DenseMap<uint64_t, uint64_t> &OffsetRemapping,
uint64_t &Offset, const uint64_t Size,
uint32_t OldOffsetSize, uint32_t NewOffsetSize) {
// Create a mask so we don't trigger a emitIntValue() assert below if the
// NewOffset is over 4GB.
const uint64_t NewOffsetMask = NewOffsetSize == 8 ? UINT64_MAX : UINT32_MAX;
while (Offset < Size) {
const uint64_t OldOffset = Data.getUnsigned(&Offset, OldOffsetSize);
const uint64_t NewOffset = OffsetRemapping[OldOffset];
// Truncate the string offset like the old llvm-dwp would have if we aren't
// promoting the .debug_str_offsets to DWARF64.
Out.emitIntValue(NewOffset & NewOffsetMask, NewOffsetSize);
}
}
void writeStringsAndOffsets(
MCStreamer &Out, DWPStringPool &Strings, MCSection *StrOffsetSection,
StringRef CurStrSection, StringRef CurStrOffsetSection, uint16_t Version,
SectionLengths &SectionLength,
const Dwarf64StrOffsetsPromotion StrOffsetsOptValue) {
static void
writeStringsAndOffsets(DWPWriter &Out, DWPStringPool &Strings,
StringRef CurStrSection, StringRef CurStrOffsetSection,
uint16_t Version, SectionLengths &SectionLength,
const Dwarf64StrOffsetsPromotion StrOffsetsOptValue,
bool SingleInput) {
// Could possibly produce an error or warning if one of these was non-null but
// the other was null.
if (CurStrSection.empty() || CurStrOffsetSection.empty())
return;
// Fast path: when there is only one input, all strings are unique and offsets
// don't need remapping. Copy both sections directly without any hashing.
if (SingleInput && StrOffsetsOptValue != Dwarf64StrOffsetsPromotion::Always) {
Out.switchSection(DS_Str);
Out.emitBytes(CurStrSection);
Out.switchSection(DS_StrOffsets);
Out.emitBytes(CurStrOffsetSection);
return;
}
DenseMap<uint64_t, uint64_t> OffsetRemapping;
// Pre-reserve based on estimated string count to avoid rehashing.
OffsetRemapping.reserve(CurStrSection.size() / 20);
DataExtractor Data(CurStrSection, true, 0);
uint64_t LocalOffset = 0;
@@ -464,7 +489,7 @@ void writeStringsAndOffsets(
Data = DataExtractor(CurStrOffsetSection, true, 0);
Out.switchSection(StrOffsetSection);
Out.switchSection(DS_StrOffsets);
uint64_t Offset = 0;
uint64_t Size = CurStrOffsetSection.size();
@@ -530,9 +555,11 @@ void writeStringsAndOffsets(
}
enum AccessField { Offset, Length };
void writeIndexTable(MCStreamer &Out, ArrayRef<unsigned> ContributionOffsets,
const MapVector<uint64_t, UnitIndexEntry> &IndexEntries,
const AccessField &Field) {
static void
writeIndexTable(DWPWriter &Out, ArrayRef<unsigned> ContributionOffsets,
const MapVector<uint64_t, UnitIndexEntry> &IndexEntries,
const AccessField &Field) {
for (const auto &E : IndexEntries)
for (size_t I = 0; I != std::size(E.second.Contributions); ++I)
if (ContributionOffsets[I])
@@ -542,10 +569,10 @@ void writeIndexTable(MCStreamer &Out, ArrayRef<unsigned> ContributionOffsets,
4);
}
void writeIndex(MCStreamer &Out, MCSection *Section,
ArrayRef<unsigned> ContributionOffsets,
const MapVector<uint64_t, UnitIndexEntry> &IndexEntries,
uint32_t IndexVersion) {
static void writeIndex(DWPWriter &Out, DWPSectionId Section,
ArrayRef<unsigned> ContributionOffsets,
const MapVector<uint64_t, UnitIndexEntry> &IndexEntries,
uint32_t IndexVersion) {
if (IndexEntries.empty())
return;
@@ -596,21 +623,29 @@ void writeIndex(MCStreamer &Out, MCSection *Section,
writeIndexTable(Out, ContributionOffsets, IndexEntries, AccessField::Length);
}
Error buildDuplicateError(const std::pair<uint64_t, UnitIndexEntry> &PrevE,
const CompileUnitIdentifiers &ID, StringRef DWPName) {
return make_error<DWPError>(
std::string("duplicate DWO ID (") + utohexstr(PrevE.first) + ") in " +
buildDWODescription(PrevE.second.Name, PrevE.second.DWPName,
PrevE.second.DWOName) +
" and " + buildDWODescription(ID.Name, DWPName, ID.DWOName));
/// Map input ELF section names to DWP section IDs and DWARF section kinds.
static const StringMap<std::pair<DWPSectionId, DWARFSectionKind>> &
getKnownSections() {
static const StringMap<std::pair<DWPSectionId, DWARFSectionKind>> Map = {
{"debug_info.dwo", {DS_Info, DW_SECT_INFO}},
{"debug_types.dwo", {DS_Types, DW_SECT_EXT_TYPES}},
{"debug_str_offsets.dwo", {DS_StrOffsets, DW_SECT_STR_OFFSETS}},
{"debug_str.dwo", {DS_Str, static_cast<DWARFSectionKind>(0)}},
{"debug_loc.dwo", {DS_Loc, DW_SECT_EXT_LOC}},
{"debug_line.dwo", {DS_Line, DW_SECT_LINE}},
{"debug_macro.dwo", {DS_Macro, DW_SECT_MACRO}},
{"debug_abbrev.dwo", {DS_Abbrev, DW_SECT_ABBREV}},
{"debug_loclists.dwo", {DS_Loclists, DW_SECT_LOCLISTS}},
{"debug_rnglists.dwo", {DS_Rnglists, DW_SECT_RNGLISTS}},
{"debug_cu_index", {DS_CUIndex, static_cast<DWARFSectionKind>(0)}},
{"debug_tu_index", {DS_TUIndex, static_cast<DWARFSectionKind>(0)}},
};
return Map;
}
Error handleSection(
const StringMap<std::pair<MCSection *, DWARFSectionKind>> &KnownSections,
const MCSection *StrSection, const MCSection *StrOffsetSection,
const MCSection *TypesSection, const MCSection *CUIndexSection,
const MCSection *TUIndexSection, const MCSection *InfoSection,
const SectionRef &Section, MCStreamer &Out,
static Error handleSection(
const StringMap<std::pair<DWPSectionId, DWARFSectionKind>> &KnownSections,
const SectionRef &Section, DWPWriter &Out,
std::deque<SmallString<32>> &UncompressedSections,
uint32_t (&ContributionOffsets)[8], UnitIndexEntry &CurEntry,
StringRef &CurStrSection, StringRef &CurStrOffsetSection,
@@ -644,61 +679,49 @@ Error handleSection(
if (SectionPair == KnownSections.end())
return Error::success();
if (DWARFSectionKind Kind = SectionPair->second.second) {
if (Kind != DW_SECT_EXT_TYPES && Kind != DW_SECT_INFO) {
SectionLength.push_back(std::make_pair(Kind, Contents.size()));
}
DWPSectionId SectionId = SectionPair->second.first;
DWARFSectionKind Kind = SectionPair->second.second;
if (Kind == DW_SECT_ABBREV) {
if (Kind) {
if (Kind != DW_SECT_EXT_TYPES && Kind != DW_SECT_INFO)
SectionLength.push_back(std::make_pair(Kind, Contents.size()));
if (Kind == DW_SECT_ABBREV)
AbbrevSection = Contents;
}
}
MCSection *OutSection = SectionPair->second.first;
if (OutSection == StrOffsetSection)
switch (SectionId) {
case DS_StrOffsets:
CurStrOffsetSection = Contents;
else if (OutSection == StrSection)
break;
case DS_Str:
CurStrSection = Contents;
else if (OutSection == TypesSection)
break;
case DS_Types:
CurTypesSection.push_back(Contents);
else if (OutSection == CUIndexSection)
break;
case DS_CUIndex:
CurCUIndexSection = Contents;
else if (OutSection == TUIndexSection)
break;
case DS_TUIndex:
CurTUIndexSection = Contents;
else if (OutSection == InfoSection)
break;
case DS_Info:
CurInfoSection.push_back(Contents);
else {
Out.switchSection(OutSection);
break;
default:
// Pass-through: emit directly to output (zero-copy).
Out.switchSection(SectionId);
Out.emitBytes(Contents);
break;
}
return Error::success();
}
Error write(MCStreamer &Out, ArrayRef<std::string> Inputs,
Error write(DWPWriter &Out, ArrayRef<std::string> Inputs,
OnCuIndexOverflow OverflowOptValue,
Dwarf64StrOffsetsPromotion StrOffsetsOptValue) {
const auto &MCOFI = *Out.getContext().getObjectFileInfo();
MCSection *const StrSection = MCOFI.getDwarfStrDWOSection();
MCSection *const StrOffsetSection = MCOFI.getDwarfStrOffDWOSection();
MCSection *const TypesSection = MCOFI.getDwarfTypesDWOSection();
MCSection *const CUIndexSection = MCOFI.getDwarfCUIndexSection();
MCSection *const TUIndexSection = MCOFI.getDwarfTUIndexSection();
MCSection *const InfoSection = MCOFI.getDwarfInfoDWOSection();
const StringMap<std::pair<MCSection *, DWARFSectionKind>> KnownSections = {
{"debug_info.dwo", {InfoSection, DW_SECT_INFO}},
{"debug_types.dwo", {MCOFI.getDwarfTypesDWOSection(), DW_SECT_EXT_TYPES}},
{"debug_str_offsets.dwo", {StrOffsetSection, DW_SECT_STR_OFFSETS}},
{"debug_str.dwo", {StrSection, static_cast<DWARFSectionKind>(0)}},
{"debug_loc.dwo", {MCOFI.getDwarfLocDWOSection(), DW_SECT_EXT_LOC}},
{"debug_line.dwo", {MCOFI.getDwarfLineDWOSection(), DW_SECT_LINE}},
{"debug_macro.dwo", {MCOFI.getDwarfMacroDWOSection(), DW_SECT_MACRO}},
{"debug_abbrev.dwo", {MCOFI.getDwarfAbbrevDWOSection(), DW_SECT_ABBREV}},
{"debug_loclists.dwo",
{MCOFI.getDwarfLoclistsDWOSection(), DW_SECT_LOCLISTS}},
{"debug_rnglists.dwo",
{MCOFI.getDwarfRnglistsDWOSection(), DW_SECT_RNGLISTS}},
{"debug_cu_index", {CUIndexSection, static_cast<DWARFSectionKind>(0)}},
{"debug_tu_index", {TUIndexSection, static_cast<DWARFSectionKind>(0)}}};
Dwarf64StrOffsetsPromotion StrOffsetsOptValue,
raw_pwrite_stream *OutputOS) {
const auto &KnownSections = getKnownSections();
MapVector<uint64_t, UnitIndexEntry> IndexEntries;
MapVector<uint64_t, UnitIndexEntry> TypeIndexEntries;
@@ -709,13 +732,15 @@ Error write(MCStreamer &Out, ArrayRef<std::string> Inputs,
StringRef FirstInput;
bool AnySectionOverflow = false;
DWPStringPool Strings(Out, StrSection);
DWPStringPool Strings(Out.getSectionBuffer(DS_Str));
SmallVector<OwningBinary<object::ObjectFile>, 128> Objects;
Objects.reserve(Inputs.size());
std::deque<SmallString<32>> UncompressedSections;
bool MachineSet = false;
for (const auto &Input : Inputs) {
auto ErrOrObj = object::ObjectFile::createObjectFile(Input);
if (!ErrOrObj) {
@@ -728,6 +753,17 @@ Error write(MCStreamer &Out, ArrayRef<std::string> Inputs,
auto &Obj = *ErrOrObj->getBinary();
Objects.push_back(std::move(*ErrOrObj));
// Set output format metadata from the first input file.
if (!MachineSet) {
if (auto *ELFObj = dyn_cast<ELFObjectFileBase>(&Obj)) {
Out.setMachine(ELFObj->getEMachine());
Out.setOSABI(ELFObj->getOS());
} else if (Obj.isWasm()) {
Out.setIsWASM(true);
}
MachineSet = true;
}
UnitIndexEntry CurEntry = {};
StringRef CurStrSection;
@@ -745,11 +781,9 @@ Error write(MCStreamer &Out, ArrayRef<std::string> Inputs,
for (const auto &Section : Obj.sections())
if (auto Err = handleSection(
KnownSections, StrSection, StrOffsetSection, TypesSection,
CUIndexSection, TUIndexSection, InfoSection, Section, Out,
UncompressedSections, ContributionOffsets, CurEntry,
CurStrSection, CurStrOffsetSection, CurTypesSection,
CurInfoSection, AbbrevSection, CurCUIndexSection,
KnownSections, Section, Out, UncompressedSections,
ContributionOffsets, CurEntry, CurStrSection, CurStrOffsetSection,
CurTypesSection, CurInfoSection, AbbrevSection, CurCUIndexSection,
CurTUIndexSection, SectionLength))
return Err;
@@ -773,9 +807,9 @@ Error write(MCStreamer &Out, ArrayRef<std::string> Inputs,
utostr(Version) + ")");
}
writeStringsAndOffsets(Out, Strings, StrOffsetSection, CurStrSection,
CurStrOffsetSection, Header.Version, SectionLength,
StrOffsetsOptValue);
writeStringsAndOffsets(Out, Strings, CurStrSection, CurStrOffsetSection,
Header.Version, SectionLength, StrOffsetsOptValue,
Inputs.size() == 1);
for (auto Pair : SectionLength) {
auto Index = getContributionIndex(Pair.first, IndexVersion);
@@ -803,7 +837,7 @@ Error write(MCStreamer &Out, ArrayRef<std::string> Inputs,
ContributionOffsets[getContributionIndex(DW_SECT_INFO, IndexVersion)];
if (CurCUIndexSection.empty()) {
bool FoundCUUnit = false;
Out.switchSection(InfoSection);
Out.switchSection(DS_Info);
for (StringRef Info : CurInfoSection) {
uint64_t UnitOffset = 0;
while (Info.size() > UnitOffset) {
@@ -869,7 +903,7 @@ Error write(MCStreamer &Out, ArrayRef<std::string> Inputs,
if (IndexVersion == 2) {
// Add types from the .debug_types section from DWARF < 5.
if (Error Err = addAllTypesFromTypesSection(
Out, TypeIndexEntries, TypesSection, CurTypesSection, CurEntry,
Out, TypeIndexEntries, DS_Types, CurTypesSection, CurEntry,
ContributionOffsets[getContributionIndex(DW_SECT_EXT_TYPES, 2)],
OverflowOptValue, AnySectionOverflow))
return Err;
@@ -893,7 +927,7 @@ Error write(MCStreamer &Out, ArrayRef<std::string> Inputs,
utostr(CUIndex.getVersion()) +
" and expecting " + utostr(IndexVersion));
Out.switchSection(InfoSection);
Out.switchSection(DS_Info);
for (const DWARFUnitIndex::Entry &E : CUIndex.getRows()) {
auto *I = E.getContributions();
if (!I)
@@ -939,12 +973,12 @@ Error write(MCStreamer &Out, ArrayRef<std::string> Inputs,
if (!CurTUIndexSection.empty()) {
llvm::DWARFSectionKind TUSectionKind;
MCSection *OutSection;
DWPSectionId OutSection;
StringRef TypeInputSection;
// Write type units into debug info section for DWARFv5.
if (Version >= 5) {
TUSectionKind = DW_SECT_INFO;
OutSection = InfoSection;
OutSection = DS_Info;
TypeInputSection = DwpSingleInfoSection;
} else {
// Write type units into debug types section for DWARF < 5.
@@ -953,7 +987,7 @@ Error write(MCStreamer &Out, ArrayRef<std::string> Inputs,
"multiple type unit sections in .dwp file");
TUSectionKind = DW_SECT_EXT_TYPES;
OutSection = TypesSection;
OutSection = DS_Types;
TypeInputSection = CurTypesSection.front();
}
@@ -984,8 +1018,8 @@ Error write(MCStreamer &Out, ArrayRef<std::string> Inputs,
// contribution to the info section, so we do not want to lie about it.
ContributionOffsets[0] = 0;
}
writeIndex(Out, MCOFI.getDwarfTUIndexSection(), ContributionOffsets,
TypeIndexEntries, IndexVersion);
writeIndex(Out, DS_TUIndex, ContributionOffsets, TypeIndexEntries,
IndexVersion);
if (Version < 5) {
// Lie about the type contribution for DWARF < 5. In DWARFv5 the type
@@ -995,9 +1029,207 @@ Error write(MCStreamer &Out, ArrayRef<std::string> Inputs,
ContributionOffsets[0] = 1;
}
writeIndex(Out, MCOFI.getDwarfCUIndexSection(), ContributionOffsets,
IndexEntries, IndexVersion);
writeIndex(Out, DS_CUIndex, ContributionOffsets, IndexEntries, IndexVersion);
// Write ELF output while input data is still alive (zero-copy chunks
// reference mmap'd input data held by the Objects vector above).
if (OutputOS)
return Out.write(*OutputOS);
return Error::success();
}
//===----------------------------------------------------------------------===//
// DWPWriter::writeELF — produce a minimal ELF64 relocatable object.
//===----------------------------------------------------------------------===//
Error DWPWriter::writeELF(raw_pwrite_stream &OS) {
support::endian::Writer Wr(OS, llvm::endianness::little);
// Section metadata table.
struct SectionMeta {
DWPSectionId Id;
const char *Name;
uint64_t Flags;
uint64_t EntSize;
};
static constexpr SectionMeta Meta[] = {
{DS_Loclists, ".debug_loclists.dwo", ELF::SHF_EXCLUDE, 0},
{DS_Loc, ".debug_loc.dwo", ELF::SHF_EXCLUDE, 0},
{DS_Abbrev, ".debug_abbrev.dwo", ELF::SHF_EXCLUDE, 0},
{DS_Line, ".debug_line.dwo", ELF::SHF_EXCLUDE, 0},
{DS_Rnglists, ".debug_rnglists.dwo", ELF::SHF_EXCLUDE, 0},
{DS_Macro, ".debug_macro.dwo", ELF::SHF_EXCLUDE, 0},
{DS_Str, ".debug_str.dwo",
ELF::SHF_EXCLUDE | ELF::SHF_MERGE | ELF::SHF_STRINGS, 1},
{DS_StrOffsets, ".debug_str_offsets.dwo", ELF::SHF_EXCLUDE, 0},
{DS_Info, ".debug_info.dwo", ELF::SHF_EXCLUDE, 0},
{DS_Types, ".debug_types.dwo", ELF::SHF_EXCLUDE, 0},
{DS_TUIndex, ".debug_tu_index", 0, 0},
{DS_CUIndex, ".debug_cu_index", 0, 0},
};
// Collect non-empty sections and build the section name string table.
struct OutputEntry {
const SectionData *Data;
const char *Name;
uint64_t Flags;
uint64_t EntSize;
uint32_t NameOffset;
uint64_t FileOffset; // filled in during layout
};
SmallVector<OutputEntry> Entries;
SmallString<256> Strtab;
Strtab.push_back('\0'); // null string at offset 0
for (const auto &M : Meta) {
if (Sections[M.Id].empty())
continue;
uint32_t NameOff = Strtab.size();
Strtab.append(M.Name);
Strtab.push_back('\0');
Entries.push_back(
{&Sections[M.Id], M.Name, M.Flags, M.EntSize, NameOff, 0});
}
// Add .strtab and .symtab name entries.
uint32_t StrtabNameOff = Strtab.size();
Strtab.append(".strtab");
Strtab.push_back('\0');
uint32_t SymtabNameOff = Strtab.size();
Strtab.append(".symtab");
Strtab.push_back('\0');
// Layout:
// [ELF Header] 64 bytes
// [section data...] variable
// [.strtab data] variable
// [padding to 8-byte align]
// [.symtab data] 24 bytes (one null entry)
// [padding to 8-byte align]
// [Section Header Table] 64 * NumSections bytes
constexpr uint64_t EhdrSize = sizeof(ELF::Elf64_Ehdr);
constexpr uint64_t SymEntSize = 24;
uint64_t Offset = EhdrSize;
for (auto &E : Entries) {
E.FileOffset = Offset;
Offset += E.Data->totalSize();
}
uint64_t StrtabOffset = Offset;
Offset += Strtab.size();
uint64_t SymtabOffset = alignTo(Offset, 8);
Offset = SymtabOffset + SymEntSize;
uint64_t SHTOffset = alignTo(Offset, 8);
// Section indices: [0]=null, [1..N]=data, [N+1]=strtab, [N+2]=symtab
uint32_t StrtabIdx = 1 + Entries.size();
uint32_t SymtabIdx = StrtabIdx + 1;
uint32_t NumSections = SymtabIdx + 1;
// --- Write ELF header ---
ELF::writeHeader(Wr, /*Is64Bit=*/true, ELFOSABI, /*ABIVersion=*/0, ELFMachine,
/*EFlags=*/0, SHTOffset, NumSections, StrtabIdx);
// --- Write section data ---
for (const auto &E : Entries)
E.Data->writeTo(OS);
// --- Write .strtab ---
OS.write(Strtab.data(), Strtab.size());
// --- Pad + write .symtab (one null symbol entry) ---
OS.write_zeros(SymtabOffset - (StrtabOffset + Strtab.size()));
OS.write_zeros(SymEntSize);
// --- Pad for section header table ---
uint64_t CurPos = SymtabOffset + SymEntSize;
OS.write_zeros(SHTOffset - CurPos);
// [0] ELF::SHT_NULL
ELF::writeSectionHeader(Wr, true, 0, ELF::SHT_NULL, 0, 0, 0, 0, 0, 0, 0, 0);
// [1..N] data sections
for (const auto &E : Entries)
ELF::writeSectionHeader(Wr, true, E.NameOffset, ELF::SHT_PROGBITS, E.Flags,
0, E.FileOffset, E.Data->totalSize(), 0, 0, 1,
E.EntSize);
// [N+1] .strtab
ELF::writeSectionHeader(Wr, true, StrtabNameOff, ELF::SHT_STRTAB, 0, 0,
StrtabOffset, Strtab.size(), 0, 0, 1, 0);
// [N+2] .symtab
ELF::writeSectionHeader(Wr, true, SymtabNameOff, ELF::SHT_SYMTAB, 0, 0,
SymtabOffset, SymEntSize, StrtabIdx, 1, 8,
SymEntSize);
return Error::success();
}
//===----------------------------------------------------------------------===//
// DWPWriter::writeWASM — produce a minimal WASM object with custom sections.
//===----------------------------------------------------------------------===//
Error DWPWriter::writeWASM(raw_pwrite_stream &OS) {
// Section name table (same names as ELF but without SHF_EXCLUDE flags).
static constexpr struct {
DWPSectionId Id;
const char *Name;
} Meta[] = {
{DS_Loclists, ".debug_loclists.dwo"},
{DS_Loc, ".debug_loc.dwo"},
{DS_Abbrev, ".debug_abbrev.dwo"},
{DS_Line, ".debug_line.dwo"},
{DS_Rnglists, ".debug_rnglists.dwo"},
{DS_Macro, ".debug_macro.dwo"},
{DS_Str, ".debug_str.dwo"},
{DS_StrOffsets, ".debug_str_offsets.dwo"},
{DS_Info, ".debug_info.dwo"},
{DS_Types, ".debug_types.dwo"},
{DS_TUIndex, ".debug_tu_index"},
{DS_CUIndex, ".debug_cu_index"},
};
// WASM magic and version.
OS.write("\0asm", 4);
const uint8_t Version[] = {0x01, 0x00, 0x00, 0x00};
OS.write(reinterpret_cast<const char *>(Version), 4);
// Emit each non-empty section as a WASM custom section (id=0).
for (const auto &M : Meta) {
const SectionData &SD = Sections[M.Id];
if (SD.empty())
continue;
size_t NameLen = strlen(M.Name);
uint64_t PayloadSize = SD.totalSize();
// Custom section payload = ULEB128(name_len) + name + data.
uint8_t NameLenEncoded[10];
unsigned NameLenSize = encodeULEB128(NameLen, NameLenEncoded);
uint64_t SectionPayloadSize = NameLenSize + NameLen + PayloadSize;
// Section header: id byte + ULEB128(section_payload_size).
OS.write(0x00); // Custom section id
uint8_t SizeEncoded[10];
unsigned SizeLen = encodeULEB128(SectionPayloadSize, SizeEncoded);
OS.write(reinterpret_cast<const char *>(SizeEncoded), SizeLen);
// Name
OS.write(reinterpret_cast<const char *>(NameLenEncoded), NameLenSize);
OS.write(M.Name, NameLen);
// Data
SD.writeTo(OS);
}
return Error::success();
}
} // namespace llvm

View File

@@ -0,0 +1,63 @@
//===- ELFWriter.cpp - Low-level ELF structure writer ---------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#include "llvm/DWP/ELFWriter.h"
#include "llvm/BinaryFormat/ELF.h"
using namespace llvm;
static void writeWord(support::endian::Writer &W, bool Is64Bit, uint64_t Val) {
if (Is64Bit)
W.write<uint64_t>(Val);
else
W.write<uint32_t>(Val);
}
void ELF::writeHeader(support::endian::Writer &W, bool Is64Bit, uint8_t OSABI,
uint8_t ABIVersion, uint16_t EMachine, uint32_t EFlags,
uint64_t SHOff, uint16_t SHNum, uint16_t SHStrNdx) {
W.OS << ElfMagic;
W.OS << char(Is64Bit ? ELFCLASS64 : ELFCLASS32);
W.OS << char(W.Endian == llvm::endianness::little ? ELFDATA2LSB
: ELFDATA2MSB);
W.OS << char(EV_CURRENT);
W.OS << char(OSABI);
W.OS << char(ABIVersion);
W.OS.write_zeros(EI_NIDENT - EI_PAD);
W.write<uint16_t>(ET_REL);
W.write<uint16_t>(EMachine);
W.write<uint32_t>(EV_CURRENT);
writeWord(W, Is64Bit, 0); // e_entry
writeWord(W, Is64Bit, 0); // e_phoff
writeWord(W, Is64Bit, SHOff);
W.write<uint32_t>(EFlags);
W.write<uint16_t>(Is64Bit ? sizeof(Elf64_Ehdr) : sizeof(Elf32_Ehdr));
W.write<uint16_t>(0); // e_phentsize
W.write<uint16_t>(0); // e_phnum
W.write<uint16_t>(Is64Bit ? sizeof(Elf64_Shdr) : sizeof(Elf32_Shdr));
W.write<uint16_t>(SHNum);
W.write<uint16_t>(SHStrNdx);
}
void ELF::writeSectionHeader(support::endian::Writer &W, bool Is64Bit,
uint32_t Name, uint32_t Type, uint64_t Flags,
uint64_t Address, uint64_t Offset, uint64_t Size,
uint32_t Link, uint32_t Info, uint64_t Alignment,
uint64_t EntrySize) {
W.write<uint32_t>(Name);
W.write<uint32_t>(Type);
writeWord(W, Is64Bit, Flags);
writeWord(W, Is64Bit, Address);
writeWord(W, Is64Bit, Offset);
writeWord(W, Is64Bit, Size);
W.write<uint32_t>(Link);
W.write<uint32_t>(Info);
writeWord(W, Is64Bit, Alignment);
writeWord(W, Is64Bit, EntrySize);
}

View File

@@ -1,3 +1,4 @@
# REQUIRES: webassembly-registered-target
# RUN: llvm-mc %s -filetype obj -triple wasm32-unknown-unknown -o %t.o \
# RUN: -split-dwarf-file=%t.dwo -dwarf-version=5
# RUN: llvm-dwp %t.dwo -o %t.dwp

View File

@@ -1,14 +1,9 @@
set(LLVM_LINK_COMPONENTS
AllTargetsCodeGens
AllTargetsDescs
AllTargetsInfos
DebugInfoDWARF
DWP
MC
Object
Option
Support
TargetParser
)
set(LLVM_TARGET_DEFINITIONS Opts.td)

View File

@@ -13,31 +13,19 @@
#include "llvm/DWP/DWP.h"
#include "llvm/DWP/DWPError.h"
#include "llvm/DWP/DWPStringPool.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCTargetOptionsCommandFlags.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/LLVMDriver.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/ToolOutputFile.h"
#include <optional>
using namespace llvm;
using namespace llvm::object;
static mc::RegisterMCTargetOptionsFlags MCTargetOptionsFlags;
// Command-line option boilerplate.
namespace {
enum ID {
@@ -112,14 +100,6 @@ static int error(const Twine &Error, const Twine &Context) {
return 1;
}
static Expected<Triple> readTargetTriple(StringRef FileName) {
auto ErrOrObj = object::ObjectFile::createObjectFile(FileName);
if (!ErrOrObj)
return ErrOrObj.takeError();
return ErrOrObj->getBinary()->makeTriple();
}
int llvm_dwp_main(int argc, char **argv, const llvm::ToolContext &) {
DwpOptTable Tbl;
llvm::BumpPtrAllocator A;
@@ -192,11 +172,6 @@ int llvm_dwp_main(int argc, char **argv, const llvm::ToolContext &) {
for (const llvm::opt::Arg *A : Args.filtered(OPT_INPUT))
DWOFilenames.emplace_back(A->getValue());
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllTargets();
llvm::InitializeAllAsmPrinters();
for (const auto &ExecFilename : ExecFilenames) {
auto DWOs = getDWOFilenames(ExecFilename);
if (!DWOs) {
@@ -249,68 +224,14 @@ int llvm_dwp_main(int argc, char **argv, const llvm::ToolContext &) {
}
}
std::string ErrorStr;
StringRef Context = "dwarf streamer init";
auto ErrOrTriple = readTargetTriple(DWOFilenames.front());
if (!ErrOrTriple) {
logAllUnhandledErrors(
handleErrors(ErrOrTriple.takeError(),
[&](std::unique_ptr<ECError> EC) -> Error {
return createFileError(DWOFilenames.front(),
Error(std::move(EC)));
}),
WithColor::error());
return 1;
}
// Get the target.
const Target *TheTarget =
TargetRegistry::lookupTarget("", *ErrOrTriple, ErrorStr);
if (!TheTarget)
return error(ErrorStr, Context);
std::string TripleName = ErrOrTriple->getTriple();
Triple TheTriple(TripleName);
// Create all the MC Objects.
std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TheTriple));
if (!MRI)
return error(Twine("no register info for target ") + TripleName, Context);
MCTargetOptions MCOptions = llvm::mc::InitMCTargetOptionsFromFlags();
std::unique_ptr<MCAsmInfo> MAI(
TheTarget->createMCAsmInfo(*MRI, TheTriple, MCOptions));
if (!MAI)
return error("no asm info for target " + TripleName, Context);
std::unique_ptr<MCSubtargetInfo> MSTI(
TheTarget->createMCSubtargetInfo(TheTriple, "", ""));
if (!MSTI)
return error("no subtarget info for target " + TripleName, Context);
MCContext MC(*ErrOrTriple, *MAI, MRI.get(), MSTI.get());
std::unique_ptr<MCObjectFileInfo> MOFI(
TheTarget->createMCObjectFileInfo(MC, /*PIC=*/false));
MC.setObjectFileInfo(MOFI.get());
auto MAB = TheTarget->createMCAsmBackend(*MSTI, *MRI, MCOptions);
if (!MAB)
return error("no asm backend for target " + TripleName, Context);
std::unique_ptr<MCInstrInfo> MII(TheTarget->createMCInstrInfo());
if (!MII)
return error("no instr info info for target " + TripleName, Context);
MCCodeEmitter *MCE = TheTarget->createMCCodeEmitter(*MII, MC);
if (!MCE)
return error("no code emitter for target " + TripleName, Context);
// Create the output file.
std::error_code EC;
ToolOutputFile OutFile(OutputFilename, EC, sys::fs::OF_None);
std::optional<buffer_ostream> BOS;
raw_pwrite_stream *OS;
if (EC)
return error(Twine(OutputFilename) + ": " + EC.message(), Context);
return error(Twine(OutputFilename) + ": " + EC.message(),
"dwp output init");
if (OutFile.os().supportsSeeking()) {
OS = &OutFile.os();
} else {
@@ -318,20 +239,15 @@ int llvm_dwp_main(int argc, char **argv, const llvm::ToolContext &) {
OS = &*BOS;
}
std::unique_ptr<MCStreamer> MS(TheTarget->createMCObjectStreamer(
*ErrOrTriple, MC, std::unique_ptr<MCAsmBackend>(MAB),
MAB->createObjectWriter(*OS), std::unique_ptr<MCCodeEmitter>(MCE),
*MSTI));
if (!MS)
return error("no object streamer for target " + TripleName, Context);
// Use DWPWriter for direct ELF output, bypassing MCStreamer.
DWPWriter Writer;
if (auto Err =
write(*MS, DWOFilenames, OverflowOptValue, Dwarf64StrOffsetsValue)) {
if (auto Err = write(Writer, DWOFilenames, OverflowOptValue,
Dwarf64StrOffsetsValue, OS)) {
logAllUnhandledErrors(std::move(Err), WithColor::error());
return 1;
}
MS->finish();
OutFile.keep();
return 0;
}