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
case DW_FORM_addrx2:
case DW_FORM_addrx3:
case DW_FORM_addrx4:
- case DW_FORM_GNU_addr_index: {
+ case DW_FORM_GNU_addr_index:
+ case DW_FORM_LLVM_addrx_offset: {
if (U == nullptr) {
OS << "<invalid dwarf unit>";
break;
}
- std::optional<object::SectionedAddress> A =
- U->getAddrOffsetSectionItem(UValue);
- if (!A || DumpOpts.Verbose)
- AddrOS << format("indexed (%8.8x) address = ", (uint32_t)UValue);
+ std::optional<object::SectionedAddress> A = getAsSectionedAddress();
+ if (!A || DumpOpts.Verbose) {
+ if (Form == DW_FORM_LLVM_addrx_offset) {
+ uint32_t Index = UValue >> 32;
+ uint32_t Offset = UValue & 0xffffffff;
+ AddrOS << format("indexed (%8.8x) + 0x%x address = ", Index, Offset);
+ } else
+ AddrOS << format("indexed (%8.8x) address = ", (uint32_t)UValue);
+ }
if (A)
dumpSectionedAddress(AddrOS, DumpOpts, *A);
else
OS << "<unresolved>";
break;
}
- case DW_FORM_LLVM_addrx_offset: {
- if (U == nullptr) {
- OS << "<invalid dwarf unit>";
- break;
- }
- uint32_t Index = UValue >> 32;
- uint32_t Offset = UValue & 0xffffffff;
- std::optional<object::SectionedAddress> A =
- U->getAddrOffsetSectionItem(Index);
- if (!A || DumpOpts.Verbose)
- AddrOS << format("indexed (%8.8x) + 0x%x address = ", Index, Offset);
- if (A) {
- A->Address += Offset;
- dumpSectionedAddress(AddrOS, DumpOpts, *A);
- } else
- OS << "<unresolved>";
- break;
- }
case DW_FORM_flag_present:
OS << "true";
break;
if (!isFormClass(FC_Address))
return std::nullopt;
bool AddrOffset = Form == dwarf::DW_FORM_LLVM_addrx_offset;
- if (Form == DW_FORM_GNU_addr_index || Form == DW_FORM_addrx || AddrOffset) {
+ if (Form == DW_FORM_GNU_addr_index || Form == DW_FORM_addrx ||
+ Form == DW_FORM_addrx1 || Form == DW_FORM_addrx2 ||
+ Form == DW_FORM_addrx3 || Form == DW_FORM_addrx4 || AddrOffset) {
uint32_t Index = AddrOffset ? (Value.uval >> 32) : Value.uval;
if (!U)
// Test that we can decode all DW_FORM values correctly.
const AddrType AddrValue = (AddrType)0x0123456789abcdefULL;
+ const AddrType AddrxValue = (AddrType)0x4231abcd4231abcdULL;
+ const AddrType Addrx1Value = (AddrType)0x0000aaaabbbbccccULL;
+ const AddrType Addrx2Value = (AddrType)0xf00123f00456f000ULL;
+ const AddrType Addrx4Value = (AddrType)0xa1b2c3d4e5f6e5d4ULL;
+
const uint8_t BlockData[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
const uint32_t BlockSize = sizeof(BlockData);
const RefAddrType RefAddr = 0x12345678;
dwarfgen::CompileUnit &CU = DG->addCompileUnit();
dwarfgen::DIE CUDie = CU.getUnitDIE();
- if (Version >= 5)
+ if (Version >= 5) {
CUDie.addStrOffsetsBaseAttribute();
+ CUDie.addAddrBaseAttribute();
+ }
uint16_t Attr = DW_AT_lo_user;
const auto Attr_DW_FORM_addr = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr_DW_FORM_addr, DW_FORM_addr, AddrValue);
+ const auto Attr_DW_FORM_addrx = static_cast<dwarf::Attribute>(Attr++);
+ const auto Attr_DW_FORM_addrx1 = static_cast<dwarf::Attribute>(Attr++);
+ const auto Attr_DW_FORM_addrx2 = static_cast<dwarf::Attribute>(Attr++);
+ // TODO: Add Attr_DW_FORM_addrx3 test (this form type is currently
+ // unsupported)
+ const auto Attr_DW_FORM_addrx4 = static_cast<dwarf::Attribute>(Attr++);
+
+ if (Version >= 5) {
+ CUDie.addAttribute(Attr_DW_FORM_addrx, DW_FORM_addrx, AddrxValue);
+ CUDie.addAttribute(Attr_DW_FORM_addrx1, DW_FORM_addrx1, Addrx1Value);
+ CUDie.addAttribute(Attr_DW_FORM_addrx2, DW_FORM_addrx2, Addrx2Value);
+ CUDie.addAttribute(Attr_DW_FORM_addrx4, DW_FORM_addrx4, Addrx4Value);
+ }
+
//----------------------------------------------------------------------
// Test block forms
//----------------------------------------------------------------------
//----------------------------------------------------------------------
EXPECT_EQ(AddrValue, toAddress(DieDG.find(Attr_DW_FORM_addr), 0));
+ if (Version >= 5) {
+ auto ExtractedAddrxValue = toAddress(DieDG.find(Attr_DW_FORM_addrx));
+ EXPECT_TRUE(ExtractedAddrxValue.has_value());
+ EXPECT_EQ(AddrxValue, *ExtractedAddrxValue);
+
+ auto ExtractedAddrx1Value = toAddress(DieDG.find(Attr_DW_FORM_addrx1));
+ EXPECT_TRUE(ExtractedAddrx1Value.has_value());
+ EXPECT_EQ(Addrx1Value, *ExtractedAddrx1Value);
+
+ auto ExtractedAddrx2Value = toAddress(DieDG.find(Attr_DW_FORM_addrx2));
+ EXPECT_TRUE(ExtractedAddrx2Value.has_value());
+ EXPECT_EQ(Addrx2Value, *ExtractedAddrx2Value);
+
+ auto ExtractedAddrx4Value = toAddress(DieDG.find(Attr_DW_FORM_addrx4));
+ EXPECT_TRUE(ExtractedAddrx1Value.has_value());
+ EXPECT_EQ(Addrx4Value, *ExtractedAddrx4Value);
+ }
+
//----------------------------------------------------------------------
// Test block forms
//----------------------------------------------------------------------
void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form, uint64_t U) {
auto &DG = CU->getGenerator();
+ switch (Form) {
+ case DW_FORM_addrx:
+ case DW_FORM_addrx1:
+ case DW_FORM_addrx2:
+ case DW_FORM_addrx3:
+ case DW_FORM_addrx4:
+ U = DG.getAddressPool().getIndex(U);
+ default:
+ break;
+ }
Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
DIEInteger(U));
}
addAttribute(dwarf::DW_AT_str_offsets_base, DW_FORM_sec_offset, *Expr);
}
+// This is currently fixed to be the first address entry after the header.
+void dwarfgen::DIE::addAddrBaseAttribute() {
+ auto &DG = CU->getGenerator();
+ auto &MC = *DG.getMCContext();
+ AsmPrinter *Asm = DG.getAsmPrinter();
+
+ const MCSymbol *SectionStart =
+ Asm->getObjFileLowering().getDwarfAddrSection()->getBeginSymbol();
+
+ const MCExpr *Expr = MCSymbolRefExpr::create(DG.getAddrTableStartSym(), MC);
+
+ if (!Asm->MAI->doesDwarfUseRelocationsAcrossSections())
+ Expr = MCBinaryExpr::createSub(
+ Expr, MCSymbolRefExpr::create(SectionStart, MC), MC);
+
+ addAttribute(dwarf::DW_AT_addr_base, DW_FORM_sec_offset, *Expr);
+}
+
dwarfgen::DIE dwarfgen::DIE::addChild(dwarf::Tag Tag) {
auto &DG = CU->getGenerator();
return dwarfgen::DIE(CU,
StringPool = std::make_unique<DwarfStringPool>(Allocator, *Asm, StringRef());
StringOffsetsStartSym = Asm->createTempSymbol("str_offsets_base");
+ AddrTableStartSym = Asm->createTempSymbol("addr_table_base");
+
return Error::success();
}
+unsigned dwarfgen::Generator::DummyAddressPool::getIndex(uint64_t Address) {
+ AddressValues.push_back(Address);
+ return static_cast<unsigned>(AddressValues.size() - 1);
+}
+
+void dwarfgen::Generator::DummyAddressPool::emit(AsmPrinter &Asm,
+ MCSection *AddrSection,
+ MCSymbol *StartSym) {
+ const uint8_t AddrSize = Asm.getPointerSize();
+
+ // Switch to .debug_addr section
+ Asm.OutStreamer->switchSection(AddrSection);
+
+ if (Asm.getDwarfVersion() >= 5) {
+ // Emit header
+ Asm.emitDwarfUnitLength(AddrSize * AddressValues.size() + 4,
+ "Length of contribution");
+ Asm.emitInt16(Asm.getDwarfVersion());
+ Asm.emitInt8(AddrSize);
+ Asm.emitInt8(0);
+ }
+
+ if (StartSym)
+ Asm.OutStreamer->emitLabel(StartSym);
+
+ // Emit addresses
+ for (uint64_t Addr : AddressValues)
+ Asm.OutStreamer->emitIntValue(Addr, AddrSize);
+}
+
StringRef dwarfgen::Generator::generate() {
// Offset from the first CU in the debug info section is 0 initially.
uint64_t SecOffset = 0;
StringPool->emit(*Asm, TLOF->getDwarfStrSection(),
TLOF->getDwarfStrOffSection());
+ AddressPool.emit(*Asm, TLOF->getDwarfAddrSection(), AddrTableStartSym);
+
MS->switchSection(TLOF->getDwarfInfoSection());
for (auto &CU : CompileUnits) {
uint16_t Version = CU->getVersion();
/// Add a DW_AT_str_offsets_base attribute to this DIE.
void addStrOffsetsBaseAttribute();
+ /// Add a DW_AT_addr_base attribute to this DIE.
+ void addAddrBaseAttribute();
+
/// Add a new child to this DIE object.
///
/// \param Tag the dwarf::Tag to assing to the llvm::DIE object.
std::vector<std::unique_ptr<LineTable>> LineTables;
DIEAbbrevSet Abbreviations;
+ // Mimics llvm::AddressPool, but allows for constant addresses for testing.
+ struct DummyAddressPool {
+ unsigned getIndex(uint64_t Address);
+
+ void emit(AsmPrinter &Asm, MCSection *AddrSection, MCSymbol *StartSym);
+
+ std::vector<uint64_t> AddressValues;
+ } AddressPool;
+
MCSymbol *StringOffsetsStartSym;
+ MCSymbol *AddrTableStartSym;
SmallString<4096> FileBytes;
/// The stream we use to generate the DWARF into as an ELF file.
DIEAbbrevSet &getAbbrevSet() { return Abbreviations; }
DwarfStringPool &getStringPool() { return *StringPool; }
MCSymbol *getStringOffsetsStartSym() const { return StringOffsetsStartSym; }
+ DummyAddressPool &getAddressPool() { return AddressPool; }
+ MCSymbol *getAddrTableStartSym() const { return AddrTableStartSym; }
/// Save the generated DWARF file to disk.
///