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 Format; } + + /// Return the length of this table. + uint64_t getLength() const { return Length; } + + /// Return the version of this table. + uint16_t getVersion() const { return Version; } + + /// Return the address size of this table. + uint8_t getAddressSize() const { return AddrSize; } + + /// Return the segment selector size of this table. + uint8_t getSegmentSelectorSize() const { return SegSize; } + + /// Return the parsed addresses of this table. + ArrayRef getAddressEntries() const { return Addrs; } }; } // end namespace llvm 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,215 @@ +## 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: -DADDRSIZE=4 | obj2yaml | \ +# RUN: FileCheck %s --check-prefix=BASIC --implicit-check-not=Sections: \ +# RUN: -DLENGTH1=0x0000000000000014 \ +# RUN: -DADDRSIZE1=0x08 \ +# RUN: -DADDR=0xFFFFFFFFFFFFFFFF \ +# RUN: -DLENGTH2=0x000000000000000C \ +# RUN: -DADDRSIZE2=0x04 + +## Dumping address tables from a big endian 64-bit object file. +# RUN: yaml2obj --docnum=1 %s -DENDIAN=MSB -DADDRESS=0xFFFFFFFFFFFFFFFF \ +# RUN: -DADDRSIZE=4 | obj2yaml | \ +# RUN: FileCheck %s --check-prefix=BASIC --implicit-check-not=Sections: \ +# RUN: -DLENGTH1=0x0000000000000014 \ +# RUN: -DADDRSIZE1=0x08 \ +# RUN: -DADDR=0xFFFFFFFFFFFFFFFF \ +# RUN: -DLENGTH2=0x000000000000000C \ +# RUN: -DADDRSIZE2=0x04 + +## Dumping address tables from a little endian 32-bit object file. +# RUN: yaml2obj --docnum=1 %s -DBITS=32 -DADDRESS=0xFFFFFFFF \ +# RUN: -DADDRSIZE=8 | obj2yaml | \ +# RUN: FileCheck %s --check-prefix=BASIC --implicit-check-not=Sections: \ +# RUN: -DLENGTH1=0x000000000000000C \ +# RUN: -DADDRSIZE1=0x04 \ +# RUN: -DADDR=0x00000000FFFFFFFF \ +# RUN: -DLENGTH2=0x0000000000000014 \ +# RUN: -DADDRSIZE2=0x08 + +## Dumping address tables from a big endian 32-bit object file. +# RUN: yaml2obj --docnum=1 %s -DBITS=32 -DENDIAN=MSB -DADDRESS=0xFFFFFFFF \ +# RUN: -DADDRSIZE=8 | obj2yaml | \ +# RUN: FileCheck %s --check-prefix=BASIC --implicit-check-not=Sections: \ +# RUN: -DLENGTH1=0x000000000000000C \ +# RUN: -DADDRSIZE1=0x04 \ +# RUN: -DADDR=0x00000000FFFFFFFF \ +# RUN: -DLENGTH2=0x0000000000000014 \ +# RUN: -DADDRSIZE2=0x08 + +# BASIC: DWARF: +# BASIC-NEXT: debug_addr: +# BASIC-NEXT: - Length: [[LENGTH1]] +# BASIC-NEXT: Version: 0x0005 +# BASIC-NEXT: AddressSize: [[ADDRSIZE1]] +# BASIC-NEXT: Entries: +# BASIC-NEXT: - Address: 0x0000000000001234 +# BASIC-NEXT: - Address: 0x0000000000005678 +# BASIC-NEXT: - Format: DWARF64 +# BASIC-NEXT: Length: [[LENGTH1]] +# BASIC-NEXT: Version: 0x0005 +# BASIC-NEXT: AddressSize: [[ADDRSIZE1]] +# BASIC-NEXT: Entries: +# BASIC-NEXT: - Address: 0x0000000000001234 +# BASIC-NEXT: - Address: [[ADDR]] +# BASIC-NEXT: - Length: [[LENGTH2]] +# BASIC-NEXT: Version: 0x0005 +# BASIC-NEXT: AddressSize: [[ADDRSIZE2]] +# BASIC-NEXT: Entries: +# BASIC-NEXT: - Address: 0x0000000000001234 +# BASIC-NEXT: - Address: 0x0000000000005678 +# BASIC-NEXT: - Format: DWARF64 +# BASIC-NEXT: Length: [[LENGTH2]] +# BASIC-NEXT: Version: 0x0005 +# BASIC-NEXT: AddressSize: [[ADDRSIZE2]] +# 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: [[ADDRSIZE]] + Entries: + - Address: 0x1234 + - Address: 0x5678 + ## A DWARF64 address table with a mutable address size. + - Format: DWARF64 + Version: 5 + AddressSize: [[ADDRSIZE]] + 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 an address table whose version isn't 5. +## This causes the DWARF parser to fail to parse it and we will dump it as a raw +## content section. + +# RUN: yaml2obj --docnum=3 %s -DCONTENT="AABBCC" | obj2yaml | \ +# RUN: FileCheck %s --check-prefix=RAW --implicit-check-not=DWARF: + +# RAW: Sections: +# RAW-NEXT: - Name: .debug_addr +# RAW-NEXT: Type: SHT_PROGBITS +# RAW-NEXT: AddressAlign: 0x0000000000000001 +# RAW-NEXT: Content: AABBCC +# RAW-NEXT: ... + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC +Sections: + - Name: .debug_addr + Type: SHT_PROGBITS + AddressAlign: 1 + Size: [[SIZE=]] + Content: [[CONTENT=]] + +## d) Test dumping an empty .debug_addr section. + +# RUN: yaml2obj --docnum=3 %s -DSIZE=0 | obj2yaml | \ +# RUN: FileCheck %s --check-prefix=EMPTY --implicit-check-not=Sections: + +# EMPTY: DWARF: +# EMPTY-NEXT: debug_addr: [] +# EMPTY-NEXT: ... 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,38 @@ } } +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. + if (Error Err = AddrTable.extractV5(AddrData, &Offset, /*CUAddrSize=*/0, + consumeError)) + return Err; + AddrTables.emplace_back(); + 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. + AddrTables.back().SegAddrPairs.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(); + } + Y.DebugAddr = std::move(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);