Files
gps/tools/local/circt/include/llvm/DWP/DWP.h
T
2026-07-12 11:01:51 +03:00

223 lines
6.3 KiB
C++

#ifndef LLVM_DWP_DWP_H
#define LLVM_DWP_DWP_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/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,
Continue,
};
enum Dwarf64StrOffsetsPromotion {
Disabled, ///< Don't do any conversion of .debug_str_offsets tables.
Enabled, ///< Convert any .debug_str_offsets tables to DWARF64 if needed.
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.
///
/// 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);
}
};
class DWPStringPool {
DWPWriter &Out;
DenseMap<StringRef, uint64_t> Pool;
uint64_t Offset = 0;
public:
DWPStringPool(DWPWriter &Out) : Out(Out) {}
uint64_t getOffset(const char *Str, unsigned Length) {
assert(strlen(Str) + 1 == Length && "Ensure length hint is correct");
StringRef Key(Str, Length);
auto Pair = Pool.insert(std::make_pair(Key, Offset));
if (Pair.second) {
Out.emitBytes(Key);
Offset += Length;
}
return Pair.first->second;
}
};
struct UnitIndexEntry {
DWARFUnitIndex::Entry::SectionContribution Contributions[8];
std::string Name;
std::string DWOName;
StringRef DWPName;
};
// Holds data for Skeleton, Split Compilation, and Type Unit Headers (only in
// v5) as defined in Dwarf 5 specification, 7.5.1.2, 7.5.1.3 and Dwarf 4
// specification 7.5.1.1.
struct InfoSectionUnitHeader {
// unit_length field. Note that the type is uint64_t even in 32-bit dwarf.
uint64_t Length = 0;
// version field.
uint16_t Version = 0;
// unit_type field. Initialized only if Version >= 5.
uint8_t UnitType = 0;
// address_size field.
uint8_t AddrSize = 0;
// debug_abbrev_offset field. Note that the type is uint64_t even in 32-bit
// dwarf. It is assumed to be 0.
uint64_t DebugAbbrevOffset = 0;
// dwo_id field. This resides in the header only if Version >= 5.
// In earlier versions, it is read from DW_AT_GNU_dwo_id.
std::optional<uint64_t> Signature;
// Derived from the length of Length field.
dwarf::DwarfFormat Format = dwarf::DwarfFormat::DWARF32;
// The size of the Header in bytes. This is derived while parsing the header,
// and is stored as a convenience.
uint8_t HeaderSize = 0;
};
struct CompileUnitIdentifiers {
uint64_t Signature = 0;
const char *Name = "";
const char *DWOName = "";
};
LLVM_ABI Error write(DWPWriter &Out, ArrayRef<std::string> Inputs,
OnCuIndexOverflow OverflowOptValue,
Dwarf64StrOffsetsPromotion StrOffsetsOptValue,
raw_pwrite_stream *OS = nullptr);
typedef std::vector<std::pair<DWARFSectionKind, uint32_t>> SectionLengths;
LLVM_ABI Expected<InfoSectionUnitHeader>
parseInfoSectionUnitHeader(StringRef Info);
} // namespace llvm
#endif // LLVM_DWP_DWP_H