Skip to content

Commit 99fad7e

Browse files
authored
[BOLT][DWARF] Update DW_AT_comp_dir/DW_AT_dwo_name for DWO TUs (#91486)
Type unit DIE generated by clang contains DW_AT_comp_dir/DW_AT_dwo_name. This was added to clang to help LLDB to figure out where type unit come from when accessing an entry in a .debug_names accelerator table and type units in .dwp file. When BOLT writes out .dwo files it changes the name of them. User can also specify directory of where they can be written out. Added support to BOLT to update those attributes.
1 parent 5bf653c commit 99fad7e

9 files changed

+575
-120
lines changed

bolt/include/bolt/Core/DIEBuilder.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ class DIEBuilder {
129129
uint64_t UnitSize{0};
130130
llvm::DenseSet<uint64_t> AllProcessed;
131131
DWARF5AcceleratorTable &DebugNamesTable;
132+
// Unordered map to handle name collision if output DWO directory is
133+
// specified.
134+
std::unordered_map<std::string, uint32_t> NameToIndexMap;
132135

133136
/// Returns current state of the DIEBuilder
134137
State &getState() { return *BuilderState.get(); }
@@ -384,6 +387,17 @@ class DIEBuilder {
384387
bool deleteValue(DIEValueList *Die, dwarf::Attribute Attribute) {
385388
return Die->deleteValue(Attribute);
386389
}
390+
/// Updates DWO Name and Compilation directory for Skeleton CU \p Unit.
391+
std::string updateDWONameCompDir(DebugStrOffsetsWriter &StrOffstsWriter,
392+
DebugStrWriter &StrWriter,
393+
DWARFUnit &SkeletonCU,
394+
std::optional<StringRef> DwarfOutputPath,
395+
std::optional<StringRef> DWONameToUse);
396+
/// Updates DWO Name and Compilation directory for Type Units.
397+
void updateDWONameCompDirForTypes(DebugStrOffsetsWriter &StrOffstsWriter,
398+
DebugStrWriter &StrWriter, DWARFUnit &Unit,
399+
std::optional<StringRef> DwarfOutputPath,
400+
const StringRef DWOName);
387401
};
388402
} // namespace bolt
389403
} // namespace llvm

bolt/include/bolt/Core/DebugData.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ class DebugAddrWriterDwarf5 : public DebugAddrWriter {
430430
using DebugStrOffsetsBufferVector = SmallVector<char, 16>;
431431
class DebugStrOffsetsWriter {
432432
public:
433-
DebugStrOffsetsWriter() {
433+
DebugStrOffsetsWriter(BinaryContext &BC) : BC(BC) {
434434
StrOffsetsBuffer = std::make_unique<DebugStrOffsetsBufferVector>();
435435
StrOffsetsStream = std::make_unique<raw_svector_ostream>(*StrOffsetsBuffer);
436436
}
@@ -460,20 +460,27 @@ class DebugStrOffsetsWriter {
460460
StrOffsets.clear();
461461
}
462462

463+
bool isStrOffsetsSectionModified() const {
464+
return StrOffsetSectionWasModified;
465+
}
466+
463467
private:
464468
std::unique_ptr<DebugStrOffsetsBufferVector> StrOffsetsBuffer;
465469
std::unique_ptr<raw_svector_ostream> StrOffsetsStream;
466470
std::map<uint32_t, uint32_t> IndexToAddressMap;
467471
SmallVector<uint32_t, 5> StrOffsets;
468472
std::unordered_map<uint64_t, uint64_t> ProcessedBaseOffsets;
469473
bool StrOffsetSectionWasModified = false;
474+
BinaryContext &BC;
470475
};
471476

472477
using DebugStrBufferVector = SmallVector<char, 16>;
473478
class DebugStrWriter {
474479
public:
475480
DebugStrWriter() = delete;
476-
DebugStrWriter(BinaryContext &BC) : BC(BC) { create(); }
481+
DebugStrWriter(DWARFContext &DwCtx, bool IsDWO) : DwCtx(DwCtx), IsDWO(IsDWO) {
482+
create();
483+
}
477484
std::unique_ptr<DebugStrBufferVector> releaseBuffer() {
478485
return std::move(StrBuffer);
479486
}
@@ -495,7 +502,8 @@ class DebugStrWriter {
495502
void create();
496503
std::unique_ptr<DebugStrBufferVector> StrBuffer;
497504
std::unique_ptr<raw_svector_ostream> StrStream;
498-
BinaryContext &BC;
505+
DWARFContext &DwCtx;
506+
bool IsDWO;
499507
};
500508

501509
enum class LocWriterKind { DebugLocWriter, DebugLoclistWriter };

bolt/include/bolt/Rewrite/DWARFRewriter.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,13 +203,16 @@ class DWARFRewriter {
203203
using OverriddenSectionsMap = std::unordered_map<DWARFSectionKind, StringRef>;
204204
/// Output .dwo files.
205205
void writeDWOFiles(DWARFUnit &, const OverriddenSectionsMap &,
206-
const std::string &, DebugLocWriter &);
206+
const std::string &, DebugLocWriter &,
207+
DebugStrOffsetsWriter &, DebugStrWriter &);
207208
using KnownSectionsEntry = std::pair<MCSection *, DWARFSectionKind>;
208209
struct DWPState {
209210
std::unique_ptr<ToolOutputFile> Out;
210211
std::unique_ptr<BinaryContext> TmpBC;
211212
std::unique_ptr<MCStreamer> Streamer;
212213
std::unique_ptr<DWPStringPool> Strings;
214+
/// Used to store String sections for .dwo files if they are being modified.
215+
std::vector<std::unique_ptr<DebugBufferVector>> StrSections;
213216
const MCObjectFileInfo *MCOFI = nullptr;
214217
const DWARFUnitIndex *CUIndex = nullptr;
215218
std::deque<SmallString<32>> UncompressedSections;
@@ -230,7 +233,8 @@ class DWARFRewriter {
230233

231234
/// add content of dwo to .dwp file.
232235
void updateDWP(DWARFUnit &, const OverriddenSectionsMap &, const UnitMeta &,
233-
UnitMetaVectorType &, DWPState &, DebugLocWriter &);
236+
UnitMetaVectorType &, DWPState &, DebugLocWriter &,
237+
DebugStrOffsetsWriter &, DebugStrWriter &);
234238
};
235239

236240
} // namespace bolt

bolt/lib/Core/DIEBuilder.cpp

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "llvm/Support/Casting.h"
2323
#include "llvm/Support/Debug.h"
2424
#include "llvm/Support/ErrorHandling.h"
25+
#include "llvm/Support/FileSystem.h"
2526
#include "llvm/Support/LEB128.h"
2627

2728
#include <algorithm>
@@ -41,6 +42,90 @@ extern cl::opt<unsigned> Verbosity;
4142
namespace llvm {
4243
namespace bolt {
4344

45+
/// Returns DWO Name to be used to update DW_AT_dwo_name/DW_AT_GNU_dwo_name
46+
/// either in CU or TU unit die. Handles case where user specifies output DWO
47+
/// directory, and there are duplicate names. Assumes DWO ID is unique.
48+
static std::string
49+
getDWOName(llvm::DWARFUnit &CU,
50+
std::unordered_map<std::string, uint32_t> &NameToIndexMap,
51+
std::optional<StringRef> &DwarfOutputPath) {
52+
assert(CU.getDWOId() && "DWO ID not found.");
53+
std::string DWOName = dwarf::toString(
54+
CU.getUnitDIE().find({dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}),
55+
"");
56+
assert(!DWOName.empty() &&
57+
"DW_AT_dwo_name/DW_AT_GNU_dwo_name does not exist.");
58+
if (DwarfOutputPath) {
59+
DWOName = std::string(sys::path::filename(DWOName));
60+
auto Iter = NameToIndexMap.find(DWOName);
61+
if (Iter == NameToIndexMap.end())
62+
Iter = NameToIndexMap.insert({DWOName, 0}).first;
63+
DWOName.append(std::to_string(Iter->second));
64+
++Iter->second;
65+
}
66+
DWOName.append(".dwo");
67+
return DWOName;
68+
}
69+
70+
/// Adds a \p Str to .debug_str section.
71+
/// Uses \p AttrInfoVal to either update entry in a DIE for legacy DWARF using
72+
/// \p DebugInfoPatcher, or for DWARF5 update an index in .debug_str_offsets
73+
/// for this contribution of \p Unit.
74+
static void addStringHelper(DebugStrOffsetsWriter &StrOffstsWriter,
75+
DebugStrWriter &StrWriter, DIEBuilder &DIEBldr,
76+
DIE &Die, const DWARFUnit &Unit,
77+
DIEValue &DIEAttrInfo, StringRef Str) {
78+
uint32_t NewOffset = StrWriter.addString(Str);
79+
if (Unit.getVersion() >= 5) {
80+
StrOffstsWriter.updateAddressMap(DIEAttrInfo.getDIEInteger().getValue(),
81+
NewOffset);
82+
return;
83+
}
84+
DIEBldr.replaceValue(&Die, DIEAttrInfo.getAttribute(), DIEAttrInfo.getForm(),
85+
DIEInteger(NewOffset));
86+
}
87+
88+
std::string DIEBuilder::updateDWONameCompDir(
89+
DebugStrOffsetsWriter &StrOffstsWriter, DebugStrWriter &StrWriter,
90+
DWARFUnit &SkeletonCU, std::optional<StringRef> DwarfOutputPath,
91+
std::optional<StringRef> DWONameToUse) {
92+
DIE &UnitDIE = *getUnitDIEbyUnit(SkeletonCU);
93+
DIEValue DWONameAttrInfo = UnitDIE.findAttribute(dwarf::DW_AT_dwo_name);
94+
if (!DWONameAttrInfo)
95+
DWONameAttrInfo = UnitDIE.findAttribute(dwarf::DW_AT_GNU_dwo_name);
96+
if (!DWONameAttrInfo)
97+
return "";
98+
std::string ObjectName;
99+
if (DWONameToUse)
100+
ObjectName = *DWONameToUse;
101+
else
102+
ObjectName = getDWOName(SkeletonCU, NameToIndexMap, DwarfOutputPath);
103+
addStringHelper(StrOffstsWriter, StrWriter, *this, UnitDIE, SkeletonCU,
104+
DWONameAttrInfo, ObjectName);
105+
106+
DIEValue CompDirAttrInfo = UnitDIE.findAttribute(dwarf::DW_AT_comp_dir);
107+
assert(CompDirAttrInfo && "DW_AT_comp_dir is not in Skeleton CU.");
108+
109+
if (DwarfOutputPath) {
110+
if (!sys::fs::exists(*DwarfOutputPath))
111+
sys::fs::create_directory(*DwarfOutputPath);
112+
addStringHelper(StrOffstsWriter, StrWriter, *this, UnitDIE, SkeletonCU,
113+
CompDirAttrInfo, *DwarfOutputPath);
114+
}
115+
return ObjectName;
116+
}
117+
118+
void DIEBuilder::updateDWONameCompDirForTypes(
119+
DebugStrOffsetsWriter &StrOffstsWriter, DebugStrWriter &StrWriter,
120+
DWARFUnit &Unit, std::optional<StringRef> DwarfOutputPath,
121+
const StringRef DWOName) {
122+
for (DWARFUnit *DU : getState().DWARF5TUVector)
123+
updateDWONameCompDir(StrOffstsWriter, StrWriter, *DU, DwarfOutputPath,
124+
DWOName);
125+
if (StrOffstsWriter.isStrOffsetsSectionModified())
126+
StrOffstsWriter.finalizeSection(Unit, *this);
127+
}
128+
44129
void DIEBuilder::updateReferences() {
45130
for (auto &[SrcDIEInfo, ReferenceInfo] : getState().AddrReferences) {
46131
DIEInfo *DstDIEInfo = ReferenceInfo.Dst;

bolt/lib/Core/DebugData.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <cstdint>
3232
#include <functional>
3333
#include <memory>
34+
#include <optional>
3435
#include <unordered_map>
3536
#include <vector>
3637

@@ -867,10 +868,17 @@ void DebugStrOffsetsWriter::finalizeSection(DWARFUnit &Unit,
867868
DIEBuilder &DIEBldr) {
868869
std::optional<AttrInfo> AttrVal =
869870
findAttributeInfo(Unit.getUnitDIE(), dwarf::DW_AT_str_offsets_base);
870-
if (!AttrVal)
871+
if (!AttrVal && !Unit.isDWOUnit())
871872
return;
872-
std::optional<uint64_t> Val = AttrVal->V.getAsSectionOffset();
873-
assert(Val && "DW_AT_str_offsets_base Value not present.");
873+
std::optional<uint64_t> Val = std::nullopt;
874+
if (AttrVal) {
875+
Val = AttrVal->V.getAsSectionOffset();
876+
} else {
877+
if (!Unit.isDWOUnit())
878+
BC.errs() << "BOLT-WARNING: [internal-dwarf-error]: "
879+
"DW_AT_str_offsets_base Value not present\n";
880+
Val = 0;
881+
}
874882
DIE &Die = *DIEBldr.getUnitDIEbyUnit(Unit);
875883
DIEValue StrListBaseAttrInfo =
876884
Die.findAttribute(dwarf::DW_AT_str_offsets_base);
@@ -915,7 +923,11 @@ void DebugStrWriter::create() {
915923
}
916924

917925
void DebugStrWriter::initialize() {
918-
auto StrSection = BC.DwCtx->getDWARFObj().getStrSection();
926+
StringRef StrSection;
927+
if (IsDWO)
928+
StrSection = DwCtx.getDWARFObj().getStrDWOSection();
929+
else
930+
StrSection = DwCtx.getDWARFObj().getStrSection();
919931
(*StrStream) << StrSection;
920932
}
921933

0 commit comments

Comments
 (0)