Skip to content

Commit a8b4c11

Browse files
[DWARFYAML] Implement debug_names support (#79666)
This commit brings support for debug_names in DWARFYAML. It parses YAML and generates emits a DWARF5 Accelerator table with the following limitations: 1. All forms must have a fixed length (zero length is also ok). 2. Hard-coded support for DWARF 5 and DWARF32. 3. The generated table does not contain a hash index All of these limitations can be lifted in the future, but for now this is good enough to enable testing.
1 parent 9ecf4d2 commit a8b4c11

File tree

5 files changed

+521
-0
lines changed

5 files changed

+521
-0
lines changed

llvm/include/llvm/ObjectYAML/DWARFEmitter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ Error emitDebugAddr(raw_ostream &OS, const Data &DI);
4242
Error emitDebugStrOffsets(raw_ostream &OS, const Data &DI);
4343
Error emitDebugRnglists(raw_ostream &OS, const Data &DI);
4444
Error emitDebugLoclists(raw_ostream &OS, const Data &DI);
45+
Error emitDebugNames(raw_ostream &OS, const Data &DI);
4546

4647
std::function<Error(raw_ostream &, const Data &)>
4748
getDWARFEmitterByName(StringRef SecName);

llvm/include/llvm/ObjectYAML/DWARFYAML.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,28 @@ struct Unit {
118118
std::vector<Entry> Entries;
119119
};
120120

121+
struct IdxForm {
122+
dwarf::Index Idx;
123+
dwarf::Form Form;
124+
};
125+
126+
struct DebugNameAbbreviation {
127+
yaml::Hex64 Code;
128+
dwarf::Tag Tag;
129+
std::vector<IdxForm> Indices;
130+
};
131+
132+
struct DebugNameEntry {
133+
yaml::Hex32 NameStrp;
134+
yaml::Hex64 Code;
135+
std::vector<yaml::Hex64> Values;
136+
};
137+
138+
struct DebugNamesSection {
139+
std::vector<DebugNameAbbreviation> Abbrevs;
140+
std::vector<DebugNameEntry> Entries;
141+
};
142+
121143
struct File {
122144
StringRef Name;
123145
uint64_t DirIdx;
@@ -228,6 +250,7 @@ struct Data {
228250
std::vector<LineTable> DebugLines;
229251
std::optional<std::vector<ListTable<RnglistEntry>>> DebugRnglists;
230252
std::optional<std::vector<ListTable<LoclistEntry>>> DebugLoclists;
253+
std::optional<DebugNamesSection> DebugNames;
231254

232255
bool isEmpty() const;
233256

@@ -276,6 +299,9 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(
276299
llvm::DWARFYAML::ListEntries<DWARFYAML::LoclistEntry>)
277300
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::LoclistEntry)
278301
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::DWARFOperation)
302+
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::DebugNameEntry)
303+
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::DebugNameAbbreviation)
304+
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::IdxForm)
279305

280306
namespace llvm {
281307
namespace yaml {
@@ -324,6 +350,19 @@ template <> struct MappingTraits<DWARFYAML::Unit> {
324350
static void mapping(IO &IO, DWARFYAML::Unit &Unit);
325351
};
326352

353+
template <> struct MappingTraits<DWARFYAML::DebugNamesSection> {
354+
static void mapping(IO &IO, DWARFYAML::DebugNamesSection &);
355+
};
356+
template <> struct MappingTraits<DWARFYAML::DebugNameEntry> {
357+
static void mapping(IO &IO, DWARFYAML::DebugNameEntry &);
358+
};
359+
template <> struct MappingTraits<DWARFYAML::DebugNameAbbreviation> {
360+
static void mapping(IO &IO, DWARFYAML::DebugNameAbbreviation &);
361+
};
362+
template <> struct MappingTraits<DWARFYAML::IdxForm> {
363+
static void mapping(IO &IO, DWARFYAML::IdxForm &);
364+
};
365+
327366
template <> struct MappingTraits<DWARFYAML::Entry> {
328367
static void mapping(IO &IO, DWARFYAML::Entry &Entry);
329368
};
@@ -437,6 +476,16 @@ template <> struct ScalarEnumerationTraits<dwarf::Form> {
437476
}
438477
};
439478

479+
#define HANDLE_DW_IDX(unused, name) \
480+
io.enumCase(value, "DW_IDX_" #name, dwarf::DW_IDX_##name);
481+
482+
template <> struct ScalarEnumerationTraits<dwarf::Index> {
483+
static void enumeration(IO &io, dwarf::Index &value) {
484+
#include "llvm/BinaryFormat/Dwarf.def"
485+
io.enumFallback<Hex16>(value);
486+
}
487+
};
488+
440489
#define HANDLE_DW_UT(unused, name) \
441490
io.enumCase(value, "DW_UT_" #name, dwarf::DW_UT_##name);
442491

llvm/lib/ObjectYAML/DWARFEmitter.cpp

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,194 @@ Error DWARFYAML::emitDebugStrOffsets(raw_ostream &OS, const Data &DI) {
691691
return Error::success();
692692
}
693693

694+
namespace {
695+
/// Emits the header for a DebugNames section.
696+
void emitDebugNamesHeader(raw_ostream &OS, bool IsLittleEndian,
697+
uint32_t NameCount, uint32_t AbbrevSize,
698+
uint32_t CombinedSizeOtherParts) {
699+
// Use the same AugmentationString as AsmPrinter.
700+
StringRef AugmentationString = "LLVM0700";
701+
size_t TotalSize = CombinedSizeOtherParts + 5 * sizeof(uint32_t) +
702+
2 * sizeof(uint16_t) + sizeof(NameCount) +
703+
sizeof(AbbrevSize) + AugmentationString.size();
704+
writeInteger(uint32_t(TotalSize), OS, IsLittleEndian); // Unit length
705+
706+
// Everything below is included in total size.
707+
writeInteger(uint16_t(5), OS, IsLittleEndian); // Version
708+
writeInteger(uint16_t(0), OS, IsLittleEndian); // Padding
709+
writeInteger(uint32_t(1), OS, IsLittleEndian); // Compilation Unit count
710+
writeInteger(uint32_t(0), OS, IsLittleEndian); // Local Type Unit count
711+
writeInteger(uint32_t(0), OS, IsLittleEndian); // Foreign Type Unit count
712+
writeInteger(uint32_t(0), OS, IsLittleEndian); // Bucket count
713+
writeInteger(NameCount, OS, IsLittleEndian);
714+
writeInteger(AbbrevSize, OS, IsLittleEndian);
715+
writeInteger(uint32_t(AugmentationString.size()), OS, IsLittleEndian);
716+
OS.write(AugmentationString.data(), AugmentationString.size());
717+
return;
718+
}
719+
720+
/// Emits the abbreviations for a DebugNames section.
721+
std::string
722+
emitDebugNamesAbbrev(ArrayRef<DWARFYAML::DebugNameAbbreviation> Abbrevs) {
723+
std::string Data;
724+
raw_string_ostream OS(Data);
725+
for (const DWARFYAML::DebugNameAbbreviation &Abbrev : Abbrevs) {
726+
encodeULEB128(Abbrev.Code, OS);
727+
encodeULEB128(Abbrev.Tag, OS);
728+
for (auto [Idx, Form] : Abbrev.Indices) {
729+
encodeULEB128(Idx, OS);
730+
encodeULEB128(Form, OS);
731+
}
732+
encodeULEB128(0, OS);
733+
encodeULEB128(0, OS);
734+
}
735+
encodeULEB128(0, OS);
736+
return Data;
737+
}
738+
739+
/// Emits a simple CU offsets list for a DebugNames section containing a single
740+
/// CU at offset 0.
741+
std::string emitDebugNamesCUOffsets(bool IsLittleEndian) {
742+
std::string Data;
743+
raw_string_ostream OS(Data);
744+
writeInteger(uint32_t(0), OS, IsLittleEndian);
745+
return Data;
746+
}
747+
748+
/// Emits the "NameTable" for a DebugNames section; according to the spec, it
749+
/// consists of two arrays: an array of string offsets, followed immediately by
750+
/// an array of entry offsets. The string offsets are emitted in the order
751+
/// provided in `Entries`.
752+
std::string emitDebugNamesNameTable(
753+
bool IsLittleEndian,
754+
const DenseMap<uint32_t, std::vector<DWARFYAML::DebugNameEntry>> &Entries,
755+
ArrayRef<uint32_t> EntryPoolOffsets) {
756+
assert(Entries.size() == EntryPoolOffsets.size());
757+
758+
std::string Data;
759+
raw_string_ostream OS(Data);
760+
761+
for (uint32_t Strp : make_first_range(Entries))
762+
writeInteger(Strp, OS, IsLittleEndian);
763+
for (uint32_t PoolOffset : EntryPoolOffsets)
764+
writeInteger(PoolOffset, OS, IsLittleEndian);
765+
return Data;
766+
}
767+
768+
/// Groups entries based on their name (strp) code and returns a map.
769+
DenseMap<uint32_t, std::vector<DWARFYAML::DebugNameEntry>>
770+
groupEntries(ArrayRef<DWARFYAML::DebugNameEntry> Entries) {
771+
DenseMap<uint32_t, std::vector<DWARFYAML::DebugNameEntry>> StrpToEntries;
772+
for (const DWARFYAML::DebugNameEntry &Entry : Entries)
773+
StrpToEntries[Entry.NameStrp].push_back(Entry);
774+
return StrpToEntries;
775+
}
776+
777+
/// Finds the abbreviation whose code is AbbrevCode and returns a list
778+
/// containing the expected size of all non-zero-length forms.
779+
Expected<SmallVector<uint8_t>>
780+
getNonZeroDataSizesFor(uint32_t AbbrevCode,
781+
ArrayRef<DWARFYAML::DebugNameAbbreviation> Abbrevs) {
782+
const auto *AbbrevIt = find_if(Abbrevs, [&](const auto &Abbrev) {
783+
return Abbrev.Code.value == AbbrevCode;
784+
});
785+
if (AbbrevIt == Abbrevs.end())
786+
return createStringError(inconvertibleErrorCode(),
787+
"did not find an Abbreviation for this code");
788+
789+
SmallVector<uint8_t> DataSizes;
790+
dwarf::FormParams Params{/*Version=*/5, /*AddrSize=*/4, dwarf::DWARF32};
791+
for (auto [Idx, Form] : AbbrevIt->Indices) {
792+
std::optional<uint8_t> FormSize = dwarf::getFixedFormByteSize(Form, Params);
793+
if (!FormSize)
794+
return createStringError(inconvertibleErrorCode(),
795+
"unsupported Form for YAML debug_names emitter");
796+
if (FormSize == 0)
797+
continue;
798+
DataSizes.push_back(*FormSize);
799+
}
800+
return DataSizes;
801+
}
802+
803+
struct PoolOffsetsAndData {
804+
std::string PoolData;
805+
std::vector<uint32_t> PoolOffsets;
806+
};
807+
808+
/// Emits the entry pool and returns an array of offsets containing the start
809+
/// offset for the entries of each unique name.
810+
/// Verifies that the provided number of data values match those expected by
811+
/// the abbreviation table.
812+
Expected<PoolOffsetsAndData> emitDebugNamesEntryPool(
813+
bool IsLittleEndian,
814+
const DenseMap<uint32_t, std::vector<DWARFYAML::DebugNameEntry>>
815+
&StrpToEntries,
816+
ArrayRef<DWARFYAML::DebugNameAbbreviation> Abbrevs) {
817+
PoolOffsetsAndData Result;
818+
raw_string_ostream OS(Result.PoolData);
819+
820+
for (ArrayRef<DWARFYAML::DebugNameEntry> EntriesWithSameName :
821+
make_second_range(StrpToEntries)) {
822+
Result.PoolOffsets.push_back(Result.PoolData.size());
823+
824+
for (const DWARFYAML::DebugNameEntry &Entry : EntriesWithSameName) {
825+
encodeULEB128(Entry.Code, OS);
826+
827+
Expected<SmallVector<uint8_t>> DataSizes =
828+
getNonZeroDataSizesFor(Entry.Code, Abbrevs);
829+
if (!DataSizes)
830+
return DataSizes.takeError();
831+
if (DataSizes->size() != Entry.Values.size())
832+
return createStringError(
833+
inconvertibleErrorCode(),
834+
"mismatch between provided and required number of values");
835+
836+
for (auto [Value, ValueSize] : zip_equal(Entry.Values, *DataSizes))
837+
if (Error E =
838+
writeVariableSizedInteger(Value, ValueSize, OS, IsLittleEndian))
839+
return std::move(E);
840+
}
841+
encodeULEB128(0, OS);
842+
}
843+
844+
return Result;
845+
}
846+
} // namespace
847+
848+
Error DWARFYAML::emitDebugNames(raw_ostream &OS, const Data &DI) {
849+
assert(DI.DebugNames && "unexpected emitDebugNames() call");
850+
const DebugNamesSection DebugNames = DI.DebugNames.value();
851+
852+
DenseMap<uint32_t, std::vector<DebugNameEntry>> StrpToEntries =
853+
groupEntries(DebugNames.Entries);
854+
855+
// Emit all sub-sections into individual strings so that we may compute
856+
// relative offsets and sizes.
857+
Expected<PoolOffsetsAndData> PoolInfo = emitDebugNamesEntryPool(
858+
DI.IsLittleEndian, StrpToEntries, DebugNames.Abbrevs);
859+
if (!PoolInfo)
860+
return PoolInfo.takeError();
861+
std::string NamesTableData = emitDebugNamesNameTable(
862+
DI.IsLittleEndian, StrpToEntries, PoolInfo->PoolOffsets);
863+
864+
std::string AbbrevData = emitDebugNamesAbbrev(DebugNames.Abbrevs);
865+
std::string CUOffsetsData = emitDebugNamesCUOffsets(DI.IsLittleEndian);
866+
867+
size_t TotalSize = PoolInfo->PoolData.size() + NamesTableData.size() +
868+
AbbrevData.size() + CUOffsetsData.size();
869+
870+
// Start real emission by combining all individual strings.
871+
emitDebugNamesHeader(OS, DI.IsLittleEndian, StrpToEntries.size(),
872+
AbbrevData.size(), TotalSize);
873+
OS.write(CUOffsetsData.data(), CUOffsetsData.size());
874+
// No local TUs, no foreign TUs, no hash lookups table.
875+
OS.write(NamesTableData.data(), NamesTableData.size());
876+
OS.write(AbbrevData.data(), AbbrevData.size());
877+
OS.write(PoolInfo->PoolData.data(), PoolInfo->PoolData.size());
878+
879+
return Error::success();
880+
}
881+
694882
static Error checkOperandCount(StringRef EncodingString,
695883
ArrayRef<yaml::Hex64> Values,
696884
uint64_t ExpectedOperands) {
@@ -1024,6 +1212,7 @@ DWARFYAML::getDWARFEmitterByName(StringRef SecName) {
10241212
.Case("debug_rnglists", DWARFYAML::emitDebugRnglists)
10251213
.Case("debug_str", DWARFYAML::emitDebugStr)
10261214
.Case("debug_str_offsets", DWARFYAML::emitDebugStrOffsets)
1215+
.Case("debug_names", DWARFYAML::emitDebugNames)
10271216
.Default([&](raw_ostream &, const DWARFYAML::Data &) {
10281217
return createStringError(errc::not_supported,
10291218
SecName + " is not supported");

llvm/lib/ObjectYAML/DWARFYAML.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ SetVector<StringRef> DWARFYAML::Data::getNonEmptySectionNames() const {
5252
SecNames.insert("debug_rnglists");
5353
if (DebugLoclists)
5454
SecNames.insert("debug_loclists");
55+
if (DebugNames)
56+
SecNames.insert("debug_names");
5557
return SecNames;
5658
}
5759

@@ -105,6 +107,7 @@ void MappingTraits<DWARFYAML::Data>::mapping(IO &IO, DWARFYAML::Data &DWARF) {
105107
IO.mapOptional("debug_str_offsets", DWARF.DebugStrOffsets);
106108
IO.mapOptional("debug_rnglists", DWARF.DebugRnglists);
107109
IO.mapOptional("debug_loclists", DWARF.DebugLoclists);
110+
IO.mapOptional("debug_names", DWARF.DebugNames);
108111
IO.setContext(OldContext);
109112
}
110113

@@ -122,6 +125,32 @@ void MappingTraits<DWARFYAML::Abbrev>::mapping(IO &IO,
122125
IO.mapOptional("Attributes", Abbrev.Attributes);
123126
}
124127

128+
void MappingTraits<DWARFYAML::IdxForm>::mapping(IO &IO,
129+
DWARFYAML::IdxForm &IdxForm) {
130+
IO.mapRequired("Idx", IdxForm.Idx);
131+
IO.mapRequired("Form", IdxForm.Form);
132+
}
133+
134+
void MappingTraits<DWARFYAML::DebugNameAbbreviation>::mapping(
135+
IO &IO, DWARFYAML::DebugNameAbbreviation &DebugNameAbbreviation) {
136+
IO.mapRequired("Code", DebugNameAbbreviation.Code);
137+
IO.mapRequired("Tag", DebugNameAbbreviation.Tag);
138+
IO.mapRequired("Indices", DebugNameAbbreviation.Indices);
139+
}
140+
141+
void MappingTraits<DWARFYAML::DebugNameEntry>::mapping(
142+
IO &IO, DWARFYAML::DebugNameEntry &DebugNameEntry) {
143+
IO.mapRequired("Name", DebugNameEntry.NameStrp);
144+
IO.mapRequired("Code", DebugNameEntry.Code);
145+
IO.mapOptional("Values", DebugNameEntry.Values);
146+
}
147+
148+
void MappingTraits<DWARFYAML::DebugNamesSection>::mapping(
149+
IO &IO, DWARFYAML::DebugNamesSection &DebugNames) {
150+
IO.mapRequired("Abbreviations", DebugNames.Abbrevs);
151+
IO.mapRequired("Entries", DebugNames.Entries);
152+
}
153+
125154
void MappingTraits<DWARFYAML::AttributeAbbrev>::mapping(
126155
IO &IO, DWARFYAML::AttributeAbbrev &AttAbbrev) {
127156
IO.mapRequired("Attribute", AttAbbrev.Attribute);

0 commit comments

Comments
 (0)