Skip to content

Commit 121452a

Browse files
committed
[DebugInfo] Handle fixed-width DW_FORM_addrx variants in DWARFFormValue::getAsSectionedAddress()
Previously this would incorrectly return the raw offset into the .debug_addr section for the DW_FORM_addrx1/2/3/4 forms rather than the actual address. Note that this was handled correctly in the dump() function so this issue only occurs for users of this API and not in tools such as llvm-dwarfdump. The dump() method has now been updated to use this method to increase coverage. This also now adds a few unit tests for indexed addresses to DWARFDebugInfoTest. Differential Revision: https://reviews.llvm.org/D143073
1 parent f8563a2 commit 121452a

File tree

4 files changed

+131
-25
lines changed

4 files changed

+131
-25
lines changed

llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -420,39 +420,27 @@ void DWARFFormValue::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
420420
case DW_FORM_addrx2:
421421
case DW_FORM_addrx3:
422422
case DW_FORM_addrx4:
423-
case DW_FORM_GNU_addr_index: {
423+
case DW_FORM_GNU_addr_index:
424+
case DW_FORM_LLVM_addrx_offset: {
424425
if (U == nullptr) {
425426
OS << "<invalid dwarf unit>";
426427
break;
427428
}
428-
std::optional<object::SectionedAddress> A =
429-
U->getAddrOffsetSectionItem(UValue);
430-
if (!A || DumpOpts.Verbose)
431-
AddrOS << format("indexed (%8.8x) address = ", (uint32_t)UValue);
429+
std::optional<object::SectionedAddress> A = getAsSectionedAddress();
430+
if (!A || DumpOpts.Verbose) {
431+
if (Form == DW_FORM_LLVM_addrx_offset) {
432+
uint32_t Index = UValue >> 32;
433+
uint32_t Offset = UValue & 0xffffffff;
434+
AddrOS << format("indexed (%8.8x) + 0x%x address = ", Index, Offset);
435+
} else
436+
AddrOS << format("indexed (%8.8x) address = ", (uint32_t)UValue);
437+
}
432438
if (A)
433439
dumpSectionedAddress(AddrOS, DumpOpts, *A);
434440
else
435441
OS << "<unresolved>";
436442
break;
437443
}
438-
case DW_FORM_LLVM_addrx_offset: {
439-
if (U == nullptr) {
440-
OS << "<invalid dwarf unit>";
441-
break;
442-
}
443-
uint32_t Index = UValue >> 32;
444-
uint32_t Offset = UValue & 0xffffffff;
445-
std::optional<object::SectionedAddress> A =
446-
U->getAddrOffsetSectionItem(Index);
447-
if (!A || DumpOpts.Verbose)
448-
AddrOS << format("indexed (%8.8x) + 0x%x address = ", Index, Offset);
449-
if (A) {
450-
A->Address += Offset;
451-
dumpSectionedAddress(AddrOS, DumpOpts, *A);
452-
} else
453-
OS << "<unresolved>";
454-
break;
455-
}
456444
case DW_FORM_flag_present:
457445
OS << "true";
458446
break;
@@ -677,7 +665,9 @@ DWARFFormValue::getAsSectionedAddress() const {
677665
if (!isFormClass(FC_Address))
678666
return std::nullopt;
679667
bool AddrOffset = Form == dwarf::DW_FORM_LLVM_addrx_offset;
680-
if (Form == DW_FORM_GNU_addr_index || Form == DW_FORM_addrx || AddrOffset) {
668+
if (Form == DW_FORM_GNU_addr_index || Form == DW_FORM_addrx ||
669+
Form == DW_FORM_addrx1 || Form == DW_FORM_addrx2 ||
670+
Form == DW_FORM_addrx3 || Form == DW_FORM_addrx4 || AddrOffset) {
681671

682672
uint32_t Index = AddrOffset ? (Value.uval >> 32) : Value.uval;
683673
if (!U)

llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ void TestAllForms() {
4848

4949
// Test that we can decode all DW_FORM values correctly.
5050
const AddrType AddrValue = (AddrType)0x0123456789abcdefULL;
51+
const AddrType AddrxValue = (AddrType)0x4231abcd4231abcdULL;
52+
const AddrType Addrx1Value = (AddrType)0x0000aaaabbbbccccULL;
53+
const AddrType Addrx2Value = (AddrType)0xf00123f00456f000ULL;
54+
const AddrType Addrx4Value = (AddrType)0xa1b2c3d4e5f6e5d4ULL;
55+
5156
const uint8_t BlockData[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
5257
const uint32_t BlockSize = sizeof(BlockData);
5358
const RefAddrType RefAddr = 0x12345678;
@@ -79,8 +84,10 @@ void TestAllForms() {
7984
dwarfgen::CompileUnit &CU = DG->addCompileUnit();
8085
dwarfgen::DIE CUDie = CU.getUnitDIE();
8186

82-
if (Version >= 5)
87+
if (Version >= 5) {
8388
CUDie.addStrOffsetsBaseAttribute();
89+
CUDie.addAddrBaseAttribute();
90+
}
8491

8592
uint16_t Attr = DW_AT_lo_user;
8693

@@ -90,6 +97,20 @@ void TestAllForms() {
9097
const auto Attr_DW_FORM_addr = static_cast<dwarf::Attribute>(Attr++);
9198
CUDie.addAttribute(Attr_DW_FORM_addr, DW_FORM_addr, AddrValue);
9299

100+
const auto Attr_DW_FORM_addrx = static_cast<dwarf::Attribute>(Attr++);
101+
const auto Attr_DW_FORM_addrx1 = static_cast<dwarf::Attribute>(Attr++);
102+
const auto Attr_DW_FORM_addrx2 = static_cast<dwarf::Attribute>(Attr++);
103+
// TODO: Add Attr_DW_FORM_addrx3 test (this form type is currently
104+
// unsupported)
105+
const auto Attr_DW_FORM_addrx4 = static_cast<dwarf::Attribute>(Attr++);
106+
107+
if (Version >= 5) {
108+
CUDie.addAttribute(Attr_DW_FORM_addrx, DW_FORM_addrx, AddrxValue);
109+
CUDie.addAttribute(Attr_DW_FORM_addrx1, DW_FORM_addrx1, Addrx1Value);
110+
CUDie.addAttribute(Attr_DW_FORM_addrx2, DW_FORM_addrx2, Addrx2Value);
111+
CUDie.addAttribute(Attr_DW_FORM_addrx4, DW_FORM_addrx4, Addrx4Value);
112+
}
113+
93114
//----------------------------------------------------------------------
94115
// Test block forms
95116
//----------------------------------------------------------------------
@@ -241,6 +262,24 @@ void TestAllForms() {
241262
//----------------------------------------------------------------------
242263
EXPECT_EQ(AddrValue, toAddress(DieDG.find(Attr_DW_FORM_addr), 0));
243264

265+
if (Version >= 5) {
266+
auto ExtractedAddrxValue = toAddress(DieDG.find(Attr_DW_FORM_addrx));
267+
EXPECT_TRUE(ExtractedAddrxValue.has_value());
268+
EXPECT_EQ(AddrxValue, *ExtractedAddrxValue);
269+
270+
auto ExtractedAddrx1Value = toAddress(DieDG.find(Attr_DW_FORM_addrx1));
271+
EXPECT_TRUE(ExtractedAddrx1Value.has_value());
272+
EXPECT_EQ(Addrx1Value, *ExtractedAddrx1Value);
273+
274+
auto ExtractedAddrx2Value = toAddress(DieDG.find(Attr_DW_FORM_addrx2));
275+
EXPECT_TRUE(ExtractedAddrx2Value.has_value());
276+
EXPECT_EQ(Addrx2Value, *ExtractedAddrx2Value);
277+
278+
auto ExtractedAddrx4Value = toAddress(DieDG.find(Attr_DW_FORM_addrx4));
279+
EXPECT_TRUE(ExtractedAddrx1Value.has_value());
280+
EXPECT_EQ(Addrx4Value, *ExtractedAddrx4Value);
281+
}
282+
244283
//----------------------------------------------------------------------
245284
// Test block forms
246285
//----------------------------------------------------------------------

llvm/unittests/DebugInfo/DWARF/DwarfGenerator.cpp

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,16 @@ unsigned dwarfgen::DIE::computeSizeAndOffsets(unsigned Offset) {
5353

5454
void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form, uint64_t U) {
5555
auto &DG = CU->getGenerator();
56+
switch (Form) {
57+
case DW_FORM_addrx:
58+
case DW_FORM_addrx1:
59+
case DW_FORM_addrx2:
60+
case DW_FORM_addrx3:
61+
case DW_FORM_addrx4:
62+
U = DG.getAddressPool().getIndex(U);
63+
default:
64+
break;
65+
}
5666
Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
5767
DIEInteger(U));
5868
}
@@ -142,6 +152,24 @@ void dwarfgen::DIE::addStrOffsetsBaseAttribute() {
142152
addAttribute(dwarf::DW_AT_str_offsets_base, DW_FORM_sec_offset, *Expr);
143153
}
144154

155+
// This is currently fixed to be the first address entry after the header.
156+
void dwarfgen::DIE::addAddrBaseAttribute() {
157+
auto &DG = CU->getGenerator();
158+
auto &MC = *DG.getMCContext();
159+
AsmPrinter *Asm = DG.getAsmPrinter();
160+
161+
const MCSymbol *SectionStart =
162+
Asm->getObjFileLowering().getDwarfAddrSection()->getBeginSymbol();
163+
164+
const MCExpr *Expr = MCSymbolRefExpr::create(DG.getAddrTableStartSym(), MC);
165+
166+
if (!Asm->MAI->doesDwarfUseRelocationsAcrossSections())
167+
Expr = MCBinaryExpr::createSub(
168+
Expr, MCSymbolRefExpr::create(SectionStart, MC), MC);
169+
170+
addAttribute(dwarf::DW_AT_addr_base, DW_FORM_sec_offset, *Expr);
171+
}
172+
145173
dwarfgen::DIE dwarfgen::DIE::addChild(dwarf::Tag Tag) {
146174
auto &DG = CU->getGenerator();
147175
return dwarfgen::DIE(CU,
@@ -495,9 +523,41 @@ llvm::Error dwarfgen::Generator::init(Triple TheTriple, uint16_t V) {
495523
StringPool = std::make_unique<DwarfStringPool>(Allocator, *Asm, StringRef());
496524
StringOffsetsStartSym = Asm->createTempSymbol("str_offsets_base");
497525

526+
AddrTableStartSym = Asm->createTempSymbol("addr_table_base");
527+
498528
return Error::success();
499529
}
500530

531+
unsigned dwarfgen::Generator::DummyAddressPool::getIndex(uint64_t Address) {
532+
AddressValues.push_back(Address);
533+
return static_cast<unsigned>(AddressValues.size() - 1);
534+
}
535+
536+
void dwarfgen::Generator::DummyAddressPool::emit(AsmPrinter &Asm,
537+
MCSection *AddrSection,
538+
MCSymbol *StartSym) {
539+
const uint8_t AddrSize = Asm.getPointerSize();
540+
541+
// Switch to .debug_addr section
542+
Asm.OutStreamer->switchSection(AddrSection);
543+
544+
if (Asm.getDwarfVersion() >= 5) {
545+
// Emit header
546+
Asm.emitDwarfUnitLength(AddrSize * AddressValues.size() + 4,
547+
"Length of contribution");
548+
Asm.emitInt16(Asm.getDwarfVersion());
549+
Asm.emitInt8(AddrSize);
550+
Asm.emitInt8(0);
551+
}
552+
553+
if (StartSym)
554+
Asm.OutStreamer->emitLabel(StartSym);
555+
556+
// Emit addresses
557+
for (uint64_t Addr : AddressValues)
558+
Asm.OutStreamer->emitIntValue(Addr, AddrSize);
559+
}
560+
501561
StringRef dwarfgen::Generator::generate() {
502562
// Offset from the first CU in the debug info section is 0 initially.
503563
uint64_t SecOffset = 0;
@@ -521,6 +581,8 @@ StringRef dwarfgen::Generator::generate() {
521581
StringPool->emit(*Asm, TLOF->getDwarfStrSection(),
522582
TLOF->getDwarfStrOffSection());
523583

584+
AddressPool.emit(*Asm, TLOF->getDwarfAddrSection(), AddrTableStartSym);
585+
524586
MS->switchSection(TLOF->getDwarfInfoSection());
525587
for (auto &CU : CompileUnits) {
526588
uint16_t Version = CU->getVersion();

llvm/unittests/DebugInfo/DWARF/DwarfGenerator.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,9 @@ class DIE {
133133
/// Add a DW_AT_str_offsets_base attribute to this DIE.
134134
void addStrOffsetsBaseAttribute();
135135

136+
/// Add a DW_AT_addr_base attribute to this DIE.
137+
void addAddrBaseAttribute();
138+
136139
/// Add a new child to this DIE object.
137140
///
138141
/// \param Tag the dwarf::Tag to assing to the llvm::DIE object.
@@ -258,7 +261,17 @@ class Generator {
258261
std::vector<std::unique_ptr<LineTable>> LineTables;
259262
DIEAbbrevSet Abbreviations;
260263

264+
// Mimics llvm::AddressPool, but allows for constant addresses for testing.
265+
struct DummyAddressPool {
266+
unsigned getIndex(uint64_t Address);
267+
268+
void emit(AsmPrinter &Asm, MCSection *AddrSection, MCSymbol *StartSym);
269+
270+
std::vector<uint64_t> AddressValues;
271+
} AddressPool;
272+
261273
MCSymbol *StringOffsetsStartSym;
274+
MCSymbol *AddrTableStartSym;
262275

263276
SmallString<4096> FileBytes;
264277
/// The stream we use to generate the DWARF into as an ELF file.
@@ -312,6 +325,8 @@ class Generator {
312325
DIEAbbrevSet &getAbbrevSet() { return Abbreviations; }
313326
DwarfStringPool &getStringPool() { return *StringPool; }
314327
MCSymbol *getStringOffsetsStartSym() const { return StringOffsetsStartSym; }
328+
DummyAddressPool &getAddressPool() { return AddressPool; }
329+
MCSymbol *getAddrTableStartSym() const { return AddrTableStartSym; }
315330

316331
/// Save the generated DWARF file to disk.
317332
///

0 commit comments

Comments
 (0)