diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugAddr.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugAddr.h --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugAddr.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugAddr.h @@ -74,6 +74,24 @@ /// Return the full length of this table, including the length field. /// Return None if the length cannot be identified reliably. Optional getFullLength() const; + + /// Return the DWARF format of this table. + dwarf::DwarfFormat getFormat() const; + + /// Return the length of this table. + uint64_t getLength() const; + + /// Return the version of this table. + uint16_t getVersion() const; + + /// Return the address size of this table. + uint8_t getAddressSize() const; + + /// Return the segment selector size of this table. + uint8_t getSegmentSelectorSize() const; + + /// Return the parsed addresses of this table. + ArrayRef getAddressEntries() const; }; } // end namespace llvm diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp @@ -172,3 +172,16 @@ return Length + dwarf::getUnitLengthFieldByteSize(Format); } +dwarf::DwarfFormat DWARFDebugAddrTable::getFormat() const { return Format; } + +uint64_t DWARFDebugAddrTable::getLength() const { return Length; } + +uint16_t DWARFDebugAddrTable::getVersion() const { return Version; } + +uint8_t DWARFDebugAddrTable::getAddressSize() const { return AddrSize; } + +uint8_t DWARFDebugAddrTable::getSegmentSelectorSize() const { return SegSize; } + +ArrayRef DWARFDebugAddrTable::getAddressEntries() const { + return Addrs; +} diff --git a/llvm/test/tools/obj2yaml/ELF/DWARF/debug-addr.yaml b/llvm/test/tools/obj2yaml/ELF/DWARF/debug-addr.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/obj2yaml/ELF/DWARF/debug-addr.yaml @@ -0,0 +1,224 @@ +## Test how we dump the .debug_addr section. + +## a) Dumping address tables from various object files. + +## Dumping address tables from a little endian 64-bit object file. +# RUN: yaml2obj --docnum=1 %s -DADDRESS=0xFFFFFFFFFFFFFFFF \ +# RUN: -DADDRSIZE1=4 -DADDRSIZE2=4 | obj2yaml | \ +# RUN: FileCheck %s --check-prefix=BASIC --implicit-check-not=Sections \ +# RUN: -DLENGTH12=0x0000000000000014 \ +# RUN: -DADDRSIZE12=0x08 \ +# RUN: -DADDR=0xFFFFFFFFFFFFFFFF \ +# RUN: -DLENGTH34=0x000000000000000C \ +# RUN: -DADDRSIZE34=0x04 + +## Dumping address tables from a big endian 64-bit object file. +# RUN: yaml2obj --docnum=1 %s -DENDIAN=MSB -DADDRESS=0xFFFFFFFFFFFFFFFF \ +# RUN: -DADDRSIZE1=4 -DADDRSIZE2=4 | obj2yaml | \ +# RUN: FileCheck %s --check-prefix=BASIC --implicit-check-not=Sections \ +# RUN: -DLENGTH12=0x0000000000000014 \ +# RUN: -DADDRSIZE12=0x08 \ +# RUN: -DADDR=0xFFFFFFFFFFFFFFFF \ +# RUN: -DLENGTH34=0x000000000000000C \ +# RUN: -DADDRSIZE34=0x04 + +## Dumping address tables from a little endian 32-bit object file. +# RUN: yaml2obj --docnum=1 %s -DBITS=32 -DADDRESS=0xFFFFFFFF \ +# RUN: -DADDRSIZE1=8 -DADDRSIZE2=8 | obj2yaml | \ +# RUN: FileCheck %s --check-prefix=BASIC --implicit-check-not=Sections \ +# RUN: -DLENGTH12=0x000000000000000C \ +# RUN: -DADDRSIZE12=0x04 \ +# RUN: -DADDR=0x00000000FFFFFFFF \ +# RUN: -DLENGTH34=0x0000000000000014 \ +# RUN: -DADDRSIZE34=0x08 + +## Dumping address tables from a big endian 32-bit object file. +# RUN: yaml2obj --docnum=1 %s -DBITS=32 -DENDIAN=MSB -DADDRESS=0xFFFFFFFF \ +# RUN: -DADDRSIZE1=8 -DADDRSIZE2=8 | obj2yaml | \ +# RUN: FileCheck %s --check-prefix=BASIC --implicit-check-not=Sections \ +# RUN: -DLENGTH12=0x000000000000000C \ +# RUN: -DADDRSIZE12=0x04 \ +# RUN: -DADDR=0x00000000FFFFFFFF \ +# RUN: -DLENGTH34=0x0000000000000014 \ +# RUN: -DADDRSIZE34=0x08 + +# BASIC: DWARF: +# BASIC-NEXT: debug_addr: +# BASIC-NEXT: - Length: [[LENGTH12]] +# BASIC-NEXT: Version: 0x0005 +# BASIC-NEXT: AddressSize: [[ADDRSIZE12]] +# BASIC-NEXT: Entries: +# BASIC-NEXT: - Address: 0x0000000000001234 +# BASIC-NEXT: - Address: 0x0000000000005678 +# BASIC-NEXT: - Format: DWARF64 +# BASIC-NEXT: Length: [[LENGTH12]] +# BASIC-NEXT: Version: 0x0005 +# BASIC-NEXT: AddressSize: [[ADDRSIZE12]] +# BASIC-NEXT: Entries: +# BASIC-NEXT: - Address: 0x0000000000001234 +# BASIC-NEXT: - Address: [[ADDR]] +# BASIC-NEXT: - Length: [[LENGTH34]] +# BASIC-NEXT: Version: 0x0005 +# BASIC-NEXT: AddressSize: [[ADDRSIZE34]] +# BASIC-NEXT: Entries: +# BASIC-NEXT: - Address: 0x0000000000001234 +# BASIC-NEXT: - Address: 0x0000000000005678 +# BASIC-NEXT: - Format: DWARF64 +# BASIC-NEXT: Length: [[LENGTH34]] +# BASIC-NEXT: Version: 0x0005 +# BASIC-NEXT: AddressSize: [[ADDRSIZE34]] +# BASIC-NEXT: Entries: +# BASIC-NEXT: - Address: 0x0000000000001234 +# BASIC-NEXT: - Address: 0x0000000000005678 +# BASIC-NEXT: ... + +--- !ELF +FileHeader: + Class: ELFCLASS[[BITS=64]] + Data: ELFDATA2[[ENDIAN=LSB]] + Type: ET_EXEC +DWARF: + debug_addr: + ## a DWARF32 address table. + - Version: 5 + Entries: + - Address: 0x1234 + - Address: 0x5678 + ## a DWARF64 address table. + - Format: DWARF64 + Version: 5 + Entries: + - Address: 0x1234 + - Address: [[ADDRESS]] + ## a DWARF32 address table with a mutable address size. + - Version: 5 + AddressSize: [[ADDRSIZE1]] + Entries: + - Address: 0x1234 + - Address: 0x5678 + ## a DWARF64 address table with a mutable address size. + - Format: DWARF64 + Version: 5 + AddressSize: [[ADDRSIZE2]] + Entries: + - Address: 0x1234 + - Address: 0x5678 + +## b) Test dumping a .debug_addr section whose section header properties are +## overridden. + +## Override the sh_type field. +# RUN: yaml2obj --docnum=2 %s -DTYPE=SHT_STRTAB | obj2yaml | \ +# RUN: FileCheck %s -DTYPE=SHT_STRTAB --check-prefix=COMMON + +## Override the sh_flags field. +# RUN: yaml2obj --docnum=2 %s -DFLAGS='[ SHF_ALLOC ]' | obj2yaml | \ +# RUN: FileCheck %s -DTYPE=SHT_PROGBITS --check-prefixes=COMMON,FLAGS + +## Override the sh_link field. +# RUN: yaml2obj --docnum=2 %s -DLINK=.sec | obj2yaml | \ +# RUN: FileCheck %s -DTYPE=SHT_PROGBITS --check-prefixes=COMMON,LINK + +## Override the sh_addr field. +# RUN: yaml2obj --docnum=2 %s -DADDRESS=0x2020 | obj2yaml | \ +# RUN: FileCheck %s -DTYPE=SHT_PROGBITS --check-prefixes=COMMON,ADDR + +## Override the sh_addralign field. +# RUN: yaml2obj --docnum=2 %s -DADDRALIGN=3 | obj2yaml | \ +# RUN: FileCheck %s -DTYPE=SHT_PROGBITS --check-prefixes=COMMON,ADDRALIGN + +## Override the sh_entsize field. +# RUN: yaml2obj --docnum=2 %s -DENTSIZE=3 | obj2yaml | \ +# RUN: FileCheck %s -DTYPE=SHT_PROGBITS --check-prefixes=COMMON,ENTSIZE + +## Override the sh_info field. +# RUN: yaml2obj --docnum=2 %s -DINFO=3 | obj2yaml | \ +# RUN: FileCheck %s -DTYPE=SHT_PROGBITS --check-prefixes=COMMON,INFO + +# COMMON: Sections: +# COMMON-NEXT: - Name: .debug_addr +# COMMON-NEXT: Type: [[TYPE]] +# FLAGS-NEXT: Flags: [ SHF_ALLOC ] +# LINK-NEXT: Link: .sec +# ADDR-NEXT: Address: 0x0000000000002020 +# ADDRALIGN-NEXT: AddressAlign: 0x0000000000000003 +# ENTSIZE-NEXT: EntSize: 0x0000000000000003 +# INFO-NEXT: Info: 0x0000000000000003 +# COMMON-NEXT: - Name: .sec +# COMMON-NEXT: Type: SHT_PROGBITS +# COMMON-NEXT: DWARF: +# COMMON-NEXT: debug_addr: +# COMMON-NEXT: - Length: 0x0000000000000014 +# COMMON-NEXT: Version: 0x0005 +# COMMON-NEXT: AddressSize: 0x08 +# COMMON-NEXT: Entries: +# COMMON-NEXT: - Address: 0x0000000000001234 +# COMMON-NEXT: - Address: 0x0000000000005678 +# COMMON-NEXT: ... + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC +Sections: + - Name: .debug_addr + Type: [[TYPE=SHT_PROGBITS]] + Flags: [[FLAGS=]] + Link: [[LINK='']] + EntSize: [[ENTSIZE=]] + Info: [[INFO=]] + AddressAlign: [[ADDRALIGN=0]] + Address: [[ADDRESS=]] + - Name: .sec + Type: SHT_PROGBITS +DWARF: + debug_addr: + - Version: 5 + Entries: + - Address: 0x1234 + - Address: 0x5678 + +## c) Test dumping a address table whose version isn't 5. +## This makes the DWARF parser fail to parse it and we will dump it as a raw +## content section. + +# RUN: yaml2obj --docnum=3 %s | obj2yaml | \ +# RUN: FileCheck %s --check-prefix=RAW --implicit-check-not=debug_addr + +# RAW: Sections: +# RAW-NEXT: - Name: .debug_addr +# RAW-NEXT: Type: SHT_PROGBITS +# RAW-NEXT: AddressAlign: 0x0000000000000001 +# RAW-NEXT: Content: '0400000004000800' +## ^------- unit_length (4-byte) +## ^--- version (2-byte) +## ^- address_size (1-byte) +## ^- segment_selector_size (1-byte) +# RAW-NEXT: ... + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC +DWARF: + debug_addr: + - Version: 4 + +## d) Test dumping an empty .debug_addr section. + +# RUN: yaml2obj --docnum=4 %s | obj2yaml | \ +# RUN: FileCheck %s --check-prefix=EMPTY --implicit-check-not=Sections + +# EMPTY: DWARF: +# EMPTY-NEXT: debug_addr: [] +# EMPTY-NEXT: ... + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC +DWARF: + debug_addr: [] diff --git a/llvm/tools/obj2yaml/dwarf2yaml.cpp b/llvm/tools/obj2yaml/dwarf2yaml.cpp --- a/llvm/tools/obj2yaml/dwarf2yaml.cpp +++ b/llvm/tools/obj2yaml/dwarf2yaml.cpp @@ -8,6 +8,7 @@ #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h" #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h" #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" @@ -46,6 +47,40 @@ } } +Error dumpDebugAddr(DWARFContext &DCtx, DWARFYAML::Data &Y) { + DWARFDebugAddrTable AddrTable; + DWARFDataExtractor AddrData(DCtx.getDWARFObj(), + DCtx.getDWARFObj().getAddrSection(), + DCtx.isLittleEndian(), /*AddrSize=*/0); + std::vector AddrTables; + uint64_t Offset = 0; + while (AddrData.isValidOffset(Offset)) { + // We ignore any errors that don't prevent parsing the section, since we can + // still represent such sections. + auto DiscardError = [](Error Err) { consumeError(std::move(Err)); }; + if (Error Err = AddrTable.extractV5(AddrData, &Offset, /*CUAddrSize=*/0, + DiscardError)) + return Err; + AddrTables.push_back({}); + std::vector Entries; + for (uint64_t Addr : AddrTable.getAddressEntries()) { + // Currently, the parser doesn't support parsing an address table with non + // linear addresses (segment_selector_size != 0). The segment selectors + // are specified to be zero. + Entries.push_back({/*SegmentSelector=*/0, /*Address=*/Addr}); + } + + AddrTables.back().Format = AddrTable.getFormat(); + AddrTables.back().Length = AddrTable.getLength(); + AddrTables.back().Version = AddrTable.getVersion(); + AddrTables.back().AddrSize = AddrTable.getAddressSize(); + AddrTables.back().SegSelectorSize = AddrTable.getSegmentSelectorSize(); + AddrTables.back().SegAddrPairs = Entries; + } + Y.DebugAddr = AddrTables; + return Error::success(); +} + Error dumpDebugStrings(DWARFContext &DCtx, DWARFYAML::Data &Y) { DataExtractor StrData = DCtx.getStringExtractor(); uint64_t Offset = 0; diff --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp --- a/llvm/tools/obj2yaml/elf2yaml.cpp +++ b/llvm/tools/obj2yaml/elf2yaml.cpp @@ -418,6 +418,8 @@ Err = dumpDebugStrings(*DWARFCtx.get(), DWARF); else if (RawSec->Name == ".debug_ranges") Err = dumpDebugRanges(*DWARFCtx.get(), DWARF); + else if (RawSec->Name == ".debug_addr") + Err = dumpDebugAddr(*DWARFCtx.get(), DWARF); else continue; diff --git a/llvm/tools/obj2yaml/obj2yaml.h b/llvm/tools/obj2yaml/obj2yaml.h --- a/llvm/tools/obj2yaml/obj2yaml.h +++ b/llvm/tools/obj2yaml/obj2yaml.h @@ -41,6 +41,7 @@ } void dumpDebugAbbrev(llvm::DWARFContext &DCtx, llvm::DWARFYAML::Data &Y); +llvm::Error dumpDebugAddr(llvm::DWARFContext &DCtx, llvm::DWARFYAML::Data &Y); llvm::Error dumpDebugARanges(llvm::DWARFContext &DCtx, llvm::DWARFYAML::Data &Y); void dumpDebugPubSections(llvm::DWARFContext &DCtx, llvm::DWARFYAML::Data &Y);