Skip to content

Add support for Dwarf 5 in MCCAS #7611

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class DWARFFormValue {

dwarf::Form getForm() const { return Form; }
uint64_t getRawUValue() const { return Value.uval; }
int64_t getRawSValue() const { return Value.sval; }

bool isFormClass(FormClass FC) const;
const DWARFUnit *getUnit() const { return U; }
Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/MCCAS/MCCASDebugV1.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ namespace mccasformats {
namespace v1 {

constexpr unsigned Dwarf4HeaderSize32Bit = 11;
constexpr unsigned Dwarf5HeaderSize32Bit = 12;

/// Returns true if the values associated with a combination of Form and Attr
/// are not expected to deduplicate.
Expand Down Expand Up @@ -72,6 +73,9 @@ struct DataWriter {
/// Write ULEB128(V) to the data stream.
void writeULEB128(uint64_t V) { encodeULEB128(V, DataStream); }

/// Write SLEB128(V) to the data stream.
void writeSLEB128(int64_t V) { encodeSLEB128(V, DataStream); }

/// Write V to the data stream.
void writeByte(uint8_t V) { DataStream << V; }

Expand Down
5 changes: 5 additions & 0 deletions llvm/include/llvm/MCCAS/MCCASObjectV1.h
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,7 @@ struct DwarfSectionsCache {
MCSection *Line;
MCSection *Str;
MCSection *Abbrev;
MCSection *StrOffsets;
};

/// Queries `Asm` for all dwarf sections and returns an object with (possibly
Expand Down Expand Up @@ -580,6 +581,10 @@ class MCCASBuilder {
struct CUSplit {
SmallVector<MutableArrayRef<char>> SplitCUData;
SmallVector<size_t> AbbrevOffsets;
/// A list of Dwarf versions of the compile units, to help determine what
/// the Compile Unit header format and size is like when creating
/// CASObjects.
SmallVector<uint16_t> DwarfVersions;
};
/// Split the data of the __debug_info section it into multiple pieces, one
/// per Compile Unit(CU) and return them. The abbreviation offset for each CU
Expand Down
42 changes: 41 additions & 1 deletion llvm/lib/MCCAS/MCCASDebugV1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,13 @@ void AbbrevEntryWriter::writeAbbrevEntry(DWARFDie DIE) {
if (Form == dwarf::Form::DW_FORM_strp)
Form = dwarf::Form::DW_FORM_strp_cas;
writeULEB128(Form);
// Dwarf 5: Section 7.4:
// The form DW_FORM_implicit_const has to be handled specially. It's
// specification contains a third part, which is a signed LEB128 number.
// This number is used as the value of the attribute with the aformentioned
// form and nothing is stored in the .debug_info section.
if (Form == dwarf::Form::DW_FORM_implicit_const)
writeSLEB128(AttrValue.Value.getRawSValue());
}
}

Expand All @@ -281,11 +288,32 @@ Expected<dwarf::Attribute> AbbrevEntryReader::readAttr() {
return static_cast<dwarf::Attribute>(AttrAsInt);
}

static Expected<int64_t> handleImplicitConst(BinaryStreamReader &Reader) {
int64_t ImplicitVal;
if (auto E = Reader.readSLEB128(ImplicitVal))
return E;
return ImplicitVal;
}

Expected<dwarf::Form> AbbrevEntryReader::readForm() {
uint64_t FormAsInt;
if (auto E = DataStream.readULEB128(FormAsInt))
return std::move(E);
return static_cast<dwarf::Form>(FormAsInt);
auto Form = static_cast<dwarf::Form>(FormAsInt);

// Dwarf 5: Section 7.4:
// The form DW_FORM_implicit_const has to be handled specially. It's
// specification contains a third part, which is a signed LEB128 number. This
// number is used as the value of the attribute with the aformentioned form
// and nothing is stored in the .debug_info section.

// Advance reader to beyond the implicit_const value, to read Forms correctly.
if (Form == dwarf::Form::DW_FORM_implicit_const) {
auto ImplicitVal = handleImplicitConst(DataStream);
if (!ImplicitVal)
return ImplicitVal.takeError();
}
return Form;
}

uint64_t
Expand Down Expand Up @@ -330,6 +358,18 @@ mccasformats::v1::reconstructAbbrevSection(raw_ostream &OS,
Form = dwarf::Form::DW_FORM_strp;

WrittenSize += encodeULEB128(Form, OS);

// Dwarf 5: Section 7.4:
// The form DW_FORM_implicit_const has to be handled specially. It's
// specification contains a third part, which is a signed LEB128 number.
// This number is used as the value of the attribute with the
// aformentioned form and nothing is stored in the .debug_info section.
if (Form == dwarf::Form::DW_FORM_implicit_const) {
auto ImplicitVal = handleImplicitConst(Reader);
if (!ImplicitVal)
handleAllErrors(ImplicitVal.takeError());
WrittenSize += encodeSLEB128(*ImplicitVal, OS);
}
}

// Dwarf 5: Section 7.5.3:
Expand Down
132 changes: 107 additions & 25 deletions llvm/lib/MCCAS/MCCASObjectV1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,26 @@ class AbbrevSetWriter;
/// debug info.
class InMemoryCASDWARFObject : public DWARFObject {
ArrayRef<char> DebugAbbrevSection;
DWARFSection DebugStringOffsetsSection;
bool IsLittleEndian;

public:
InMemoryCASDWARFObject(ArrayRef<char> AbbrevContents, bool IsLittleEndian)
: DebugAbbrevSection(AbbrevContents), IsLittleEndian(IsLittleEndian) {}
InMemoryCASDWARFObject(ArrayRef<char> AbbrevContents,
ArrayRef<char> StringOffsetsContents,
bool IsLittleEndian)
: DebugAbbrevSection(AbbrevContents),
DebugStringOffsetsSection({toStringRef(StringOffsetsContents)}),
IsLittleEndian(IsLittleEndian) {}
bool isLittleEndian() const override { return IsLittleEndian; }

StringRef getAbbrevSection() const override {
return toStringRef(DebugAbbrevSection);
}

const DWARFSection &getStrOffsetsSection() const override {
return DebugStringOffsetsSection;
}

std::optional<RelocAddrEntry> find(const DWARFSection &Sec,
uint64_t Pos) const override {
return {};
Expand All @@ -103,12 +112,13 @@ class InMemoryCASDWARFObject : public DWARFObject {
/// unit.
Error partitionCUData(ArrayRef<char> DebugInfoData, uint64_t AbbrevOffset,
DWARFContext *Ctx, MCCASBuilder &Builder,
AbbrevSetWriter &AbbrevWriter);
AbbrevSetWriter &AbbrevWriter, uint16_t DwarfVersion);
};

struct CUInfo {
uint64_t CUSize;
uint32_t AbbrevOffset;
uint16_t DwarfVersion;
};
static Expected<CUInfo> getAndSetDebugAbbrevOffsetAndSkip(
MutableArrayRef<char> CUData, support::endianness Endian,
Expand Down Expand Up @@ -807,9 +817,23 @@ getLineTableLengthInfoAndVersion(DWARFDataExtractor &LineTableDataReader,
auto Version = LineTableDataReader.getU16(OffsetPtr, &Err);
if (Err)
return std::move(Err);
if (Version >= 5)
return createStringError(inconvertibleErrorCode(),
"DWARF 5 and above is not currently supported");
if (Version >= 5) {
// Dwarf 5 Section 6.2.4:
// Line Table Header Format is now changed with an address_size and
// segment_selector_size after the version. Parse both values from the
// header.
auto AddressSize = LineTableDataReader.getU8(OffsetPtr, &Err);
if (Err)
return std::move(Err);
if (AddressSize != 8)
return createStringError(
inconvertibleErrorCode(),
"Address size is not 8 bytes, unsupported architecture for MCCAS!");
LineTableDataReader.getU8(OffsetPtr, &Err);
if (Err)
return std::move(Err);
}

Prologue.Version = Version;
// Since we do not support 64 bit DWARF, the prologue length is 4 bytes in
// size.
Expand Down Expand Up @@ -1461,7 +1485,8 @@ DwarfSectionsCache mccasformats::v1::getDwarfSections(MCAssembler &Asm) {
Asm.getContext().getObjectFileInfo()->getDwarfInfoSection(),
Asm.getContext().getObjectFileInfo()->getDwarfLineSection(),
Asm.getContext().getObjectFileInfo()->getDwarfStrSection(),
Asm.getContext().getObjectFileInfo()->getDwarfAbbrevSection()};
Asm.getContext().getObjectFileInfo()->getDwarfAbbrevSection(),
Asm.getContext().getObjectFileInfo()->getDwarfStrOffSection()};
}

Error MCCASBuilder::prepare() {
Expand Down Expand Up @@ -1725,10 +1750,25 @@ getAndSetDebugAbbrevOffsetAndSkip(MutableArrayRef<char> CUData,
if (auto E = Reader.readInteger(DwarfVersion))
return std::move(E);

// TODO: Dwarf 5 has a different order for the next fields.
if (DwarfVersion != 4)
return createStringError(inconvertibleErrorCode(),
"Expected Dwarf 4 input");
if (DwarfVersion >= 5) {
// From Dwarf 5 Section 7.5.1.1:
// Compile Unit Header Format is now changed with unit_type and address_size
// after the version. Parse both values from the header.
uint8_t UnitType;
if (auto E = Reader.readInteger(UnitType))
return std::move(E);
if (UnitType != dwarf::DW_UT_compile)
return createStringError(
inconvertibleErrorCode(),
"Unit type is not DW_UT_compile, and is incompatible with MCCAS!");
uint8_t AddressSize;
if (auto E = Reader.readInteger(AddressSize))
return std::move(E);
if (AddressSize != 8)
return createStringError(
inconvertibleErrorCode(),
"Address size is not 8 bytes, unsupported architecture for MCCAS!");
}

// TODO: Handle Dwarf 64 format, which uses 8 bytes.
size_t AbbrevPosition = Reader.getOffset();
Expand All @@ -1750,7 +1790,7 @@ getAndSetDebugAbbrevOffsetAndSkip(MutableArrayRef<char> CUData,
if (auto E = Reader.skip(*Size))
return std::move(E);

return CUInfo{Reader.getOffset(), AbbrevOffset};
return CUInfo{Reader.getOffset(), AbbrevOffset, DwarfVersion};
}

/// Given a list of MCFragments, return a vector with the concatenation of their
Expand Down Expand Up @@ -1790,6 +1830,7 @@ MCCASBuilder::splitDebugInfoSectionData(MutableArrayRef<char> DebugInfoData) {
return Info.takeError();
Split.SplitCUData.push_back(DebugInfoData.take_front(Info->CUSize));
Split.AbbrevOffsets.push_back(Info->AbbrevOffset);
Split.DwarfVersions.push_back(Info->DwarfVersion);
DebugInfoData = DebugInfoData.drop_front(Info->CUSize);
}

Expand Down Expand Up @@ -1938,7 +1979,8 @@ Error InMemoryCASDWARFObject::partitionCUData(ArrayRef<char> DebugInfoData,
uint64_t AbbrevOffset,
DWARFContext *Ctx,
MCCASBuilder &Builder,
AbbrevSetWriter &AbbrevWriter) {
AbbrevSetWriter &AbbrevWriter,
uint16_t DwarfVersion) {
StringRef AbbrevSectionContribution =
getAbbrevSection().drop_front(AbbrevOffset);
DataExtractor Data(AbbrevSectionContribution, isLittleEndian(), 8);
Expand All @@ -1957,13 +1999,24 @@ Error InMemoryCASDWARFObject::partitionCUData(ArrayRef<char> DebugInfoData,

DWARFDie CUDie = DCU.getUnitDIE(false);
assert(CUDie);
// Copy 11 bytes which represents the 32-bit DWARF Header for DWARF4.
if (DebugInfoData.size() < Dwarf4HeaderSize32Bit)
return createStringError(inconvertibleErrorCode(),
"DebugInfoData is too small, it doesn't even "
"contain a 32-bit DWARF Header");
ArrayRef<char> HeaderData;
if (DwarfVersion >= 5) {
// Copy 12 bytes which represents the 32-bit DWARF Header for DWARF5.
if (DebugInfoData.size() < Dwarf5HeaderSize32Bit)
return createStringError(inconvertibleErrorCode(),
"DebugInfoData is too small, it doesn't even "
"contain a 32-bit DWARF5 Header");

HeaderData = DebugInfoData.take_front(Dwarf5HeaderSize32Bit);
} else {
// Copy 11 bytes which represents the 32-bit DWARF Header for DWARF4.
if (DebugInfoData.size() < Dwarf4HeaderSize32Bit)
return createStringError(inconvertibleErrorCode(),
"DebugInfoData is too small, it doesn't even "
"contain a 32-bit DWARF4 Header");

ArrayRef<char> HeaderData = DebugInfoData.take_front(Dwarf4HeaderSize32Bit);
HeaderData = DebugInfoData.take_front(Dwarf4HeaderSize32Bit);
}
Expected<DIETopLevelRef> Converted =
DIEToCASConverter(DebugInfoData, Builder)
.convert(CUDie, HeaderData, AbbrevWriter);
Expand Down Expand Up @@ -1993,20 +2046,32 @@ Error MCCASBuilder::splitDebugInfoAndAbbrevSections() {

Expected<SmallVector<char, 0>> FullAbbrevData =
mergeMCFragmentContents(AbbrevFragmentList);

if (!FullAbbrevData)
return FullAbbrevData.takeError();

InMemoryCASDWARFObject CASObj(
*FullAbbrevData, Asm.getBackend().Endian == support::endianness::little);
const MCSection::FragmentListType &StringOffsetsFragmentList =
DwarfSections.StrOffsets->getFragmentList();

Expected<SmallVector<char, 0>> FullStringOffsetsData =
mergeMCFragmentContents(StringOffsetsFragmentList);

if (!FullStringOffsetsData)
return FullStringOffsetsData.takeError();

InMemoryCASDWARFObject CASObj(*FullAbbrevData, *FullStringOffsetsData,
Asm.getBackend().Endian ==
support::endianness::little);
auto DWARFObj = std::make_unique<InMemoryCASDWARFObject>(CASObj);
auto DWARFContextHolder = std::make_unique<DWARFContext>(std::move(DWARFObj));
auto *DWARFCtx = DWARFContextHolder.get();

AbbrevSetWriter AbbrevWriter;
for (auto [CUData, AbbrevOffset] :
llvm::zip(SplitInfo->SplitCUData, SplitInfo->AbbrevOffsets)) {
for (auto [CUData, AbbrevOffset, DwarfVersion] :
llvm::zip(SplitInfo->SplitCUData, SplitInfo->AbbrevOffsets,
SplitInfo->DwarfVersions)) {
if (auto E = CASObj.partitionCUData(CUData, AbbrevOffset, DWARFCtx, *this,
AbbrevWriter))
AbbrevWriter, DwarfVersion))
return E;
}
return Error::success();
Expand Down Expand Up @@ -2162,6 +2227,8 @@ Error MCCASBuilder::createDebugStrSection() {
startSection(DwarfSections.Str);
for (auto DebugStringRef : *DebugStringRefs)
addNode(DebugStringRef);
if (auto E = createPaddingRef(DwarfSections.Str))
return E;
return finalizeSection<DebugStringSectionRef>();
}

Expand Down Expand Up @@ -3166,7 +3233,22 @@ Error mccasformats::v1::visitDebugInfo(
StringRef DistinctData = LoadedTopRef->DistinctData.getData();
BinaryStreamReader DistinctReader(DistinctData, support::endianness::little);
ArrayRef<char> HeaderData;
if (auto E = DistinctReader.readArray(HeaderData, Dwarf4HeaderSize32Bit))

auto BeginOffset = DistinctReader.getOffset();
auto Size = getSizeFromDwarfHeader(DistinctReader);
if (!Size)
return Size.takeError();

// 2-byte Dwarf version identifier.
uint16_t DwarfVersion;
if (auto E = DistinctReader.readInteger(DwarfVersion))
return E;

DistinctReader.setOffset(BeginOffset);

if (auto E = DistinctReader.readArray(
HeaderData,
DwarfVersion >= 5 ? Dwarf5HeaderSize32Bit : Dwarf4HeaderSize32Bit))
return E;
HeaderCallback(toStringRef(HeaderData));

Expand Down
Loading