Add .debug_ranges support to the DWARF YAML.

Summary: This allows DIEs with DW_AT_ranges to be encoded and decoded _and_ actually have their address ranges be included instead of having DW_AT_ranges with a section offset value for a section that doesn't exist.

Reviewers: labath, aprantl, JDevlieghere, dblaikie, probinson

Subscribers: hiraditya, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D78782
This commit is contained in:
Greg Clayton 2020-04-23 19:25:12 -07:00
parent 3254a001fc
commit 6025fc2243
7 changed files with 342 additions and 0 deletions

View File

@ -32,6 +32,7 @@ void EmitDebugAbbrev(raw_ostream &OS, const Data &DI);
void EmitDebugStr(raw_ostream &OS, const Data &DI);
void EmitDebugAranges(raw_ostream &OS, const Data &DI);
void EmitDebugRanges(raw_ostream &OS, const Data &DI);
void EmitPubSection(raw_ostream &OS, const PubSection &Sect,
bool IsLittleEndian);
void EmitDebugInfo(raw_ostream &OS, const Data &DI);

View File

@ -71,6 +71,20 @@ struct ARange {
std::vector<ARangeDescriptor> Descriptors;
};
/// Class that describes a range list entry, or a base address selection entry
/// within a range list in the .debug_ranges section.
struct RangeEntry {
llvm::yaml::Hex64 LowOffset;
llvm::yaml::Hex64 HighOffset;
};
/// Class that describes a single range list inside the .debug_ranges section.
struct Ranges {
llvm::yaml::Hex32 Offset;
llvm::yaml::Hex8 AddrSize;
std::vector<RangeEntry> Entries;
};
struct PubEntry {
llvm::yaml::Hex32 DieOffset;
llvm::yaml::Hex8 Descriptor;
@ -145,6 +159,7 @@ struct Data {
std::vector<Abbrev> AbbrevDecls;
std::vector<StringRef> DebugStrings;
std::vector<ARange> ARanges;
std::vector<Ranges> Ranges;
PubSection PubNames;
PubSection PubTypes;
@ -165,6 +180,8 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::AttributeAbbrev)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::Abbrev)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::ARangeDescriptor)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::ARange)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::RangeEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::Ranges)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::PubEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::Unit)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::FormValue)
@ -196,6 +213,14 @@ template <> struct MappingTraits<DWARFYAML::ARange> {
static void mapping(IO &IO, DWARFYAML::ARange &Range);
};
template <> struct MappingTraits<DWARFYAML::RangeEntry> {
static void mapping(IO &IO, DWARFYAML::RangeEntry &Entry);
};
template <> struct MappingTraits<DWARFYAML::Ranges> {
static void mapping(IO &IO, DWARFYAML::Ranges &Ranges);
};
template <> struct MappingTraits<DWARFYAML::PubEntry> {
static void mapping(IO &IO, DWARFYAML::PubEntry &Entry);
};

View File

@ -114,6 +114,23 @@ void DWARFYAML::EmitDebugAranges(raw_ostream &OS, const DWARFYAML::Data &DI) {
}
}
void DWARFYAML::EmitDebugRanges(raw_ostream &OS, const DWARFYAML::Data &DI) {
const size_t RangesOffset = OS.tell();
for (auto Ranges : DI.Ranges) {
const size_t CurrOffset = OS.tell() - RangesOffset;
assert(Ranges.Offset <= CurrOffset);
if (Ranges.Offset > CurrOffset)
ZeroFillBytes(OS, Ranges.Offset - CurrOffset);
for (auto Entry : Ranges.Entries) {
writeVariableSizedInteger(Entry.LowOffset, Ranges.AddrSize, OS,
DI.IsLittleEndian);
writeVariableSizedInteger(Entry.HighOffset, Ranges.AddrSize, OS,
DI.IsLittleEndian);
}
ZeroFillBytes(OS, Ranges.AddrSize * 2);
}
}
void DWARFYAML::EmitPubSection(raw_ostream &OS,
const DWARFYAML::PubSection &Sect,
bool IsLittleEndian) {
@ -377,5 +394,7 @@ DWARFYAML::EmitDebugSections(StringRef YAMLString, bool ApplyFixups,
DebugSections);
EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugAranges, "debug_aranges",
DebugSections);
EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugRanges, "debug_ranges",
DebugSections);
return std::move(DebugSections);
}

View File

@ -28,6 +28,8 @@ void MappingTraits<DWARFYAML::Data>::mapping(IO &IO, DWARFYAML::Data &DWARF) {
IO.mapOptional("debug_abbrev", DWARF.AbbrevDecls);
if (!DWARF.ARanges.empty() || !IO.outputting())
IO.mapOptional("debug_aranges", DWARF.ARanges);
if (!DWARF.Ranges.empty() || !IO.outputting())
IO.mapOptional("debug_ranges", DWARF.Ranges);
if (!DWARF.PubNames.Entries.empty() || !IO.outputting())
IO.mapOptional("debug_pubnames", DWARF.PubNames);
if (!DWARF.PubTypes.Entries.empty() || !IO.outputting())
@ -73,6 +75,19 @@ void MappingTraits<DWARFYAML::ARange>::mapping(IO &IO,
IO.mapRequired("Descriptors", Range.Descriptors);
}
void MappingTraits<DWARFYAML::RangeEntry>::mapping(
IO &IO, DWARFYAML::RangeEntry &Descriptor) {
IO.mapRequired("LowOffset", Descriptor.LowOffset);
IO.mapRequired("HighOffset", Descriptor.HighOffset);
}
void MappingTraits<DWARFYAML::Ranges>::mapping(IO &IO,
DWARFYAML::Ranges &Ranges) {
IO.mapRequired("Offset", Ranges.Offset);
IO.mapRequired("AddrSize", Ranges.AddrSize);
IO.mapRequired("Entries", Ranges.Entries);
}
void MappingTraits<DWARFYAML::PubEntry>::mapping(IO &IO,
DWARFYAML::PubEntry &Entry) {
IO.mapRequired("DieOffset", Entry.DieOffset);

View File

@ -287,6 +287,8 @@ void MachOWriter::writeSectionData(raw_ostream &OS) {
DWARFYAML::EmitDebugAbbrev(OS, Obj.DWARF);
} else if (0 == strncmp(&Sec.sectname[0], "__debug_aranges", 16)) {
DWARFYAML::EmitDebugAranges(OS, Obj.DWARF);
} else if (0 == strncmp(&Sec.sectname[0], "__debug_ranges", 16)) {
DWARFYAML::EmitDebugRanges(OS, Obj.DWARF);
} else if (0 == strncmp(&Sec.sectname[0], "__debug_pubnames", 16)) {
DWARFYAML::EmitPubSection(OS, Obj.DWARF.PubNames,
Obj.IsLittleEndian);

View File

@ -0,0 +1,246 @@
## Test that yaml2obj and obj2yaml can create mach-o files with valid
## __debug_ranges section.
##
## The DWARF should end up looking like:
##
## 0x0000000b: DW_TAG_compile_unit
## DW_AT_name ("/tmp/main.c")
## DW_AT_language (DW_LANG_C_plus_plus)
## DW_AT_low_pc (0x0000000000000000)
## DW_AT_ranges (0x00000000
## [0x0000000000000000, 0x0000000000000020)
## [0x0000000000000000, 0x0000000000000030)
## [0x0000000000001000, 0x0000000000002000))
## DW_AT_stmt_list (0x00000000)
##
## 0x00000022: DW_TAG_subprogram
## DW_AT_name ("stripped1")
## DW_AT_low_pc (0x0000000000000000)
## DW_AT_high_pc (0x0000000000000020)
##
## 0x00000033: DW_TAG_subprogram
## DW_AT_name ("stripped2")
## DW_AT_low_pc (0x0000000000000000)
## DW_AT_high_pc (0x0000000000000030)
##
## 0x00000048: DW_TAG_subprogram
## DW_AT_name ("main")
## DW_AT_low_pc (0x0000000000001000)
## DW_AT_high_pc (0x0000000000002000)
##
## 0x00000059: NULL
# RUN: yaml2obj %s > %t
# RUN: llvm-dwarfdump %t | FileCheck %s
# RUN: obj2yaml %t | FileCheck --check-prefix=YAML %s
# CHECK: DW_AT_ranges (0x00000000
# CHECK-NEXT: [0x0000000000000000, 0x0000000000000020)
# CHECK-NEXT: [0x0000000000000000, 0x0000000000000030)
# CHECK-NEXT: [0x0000000000001000, 0x0000000000002000))
# YAML: - sectname: __debug_ranges
# YAML-NEXT: segname: __DWARF
# YAML-NEXT: addr: 0x000000000000007A
# YAML-NEXT: size: 80
# YAML-NEXT: offset: 0x0000028A
# YAML: debug_ranges:
# YAML-NEXT: - Offset: 0x00000000
# YAML-NEXT: AddrSize: 0x08
# YAML-NEXT: Entries:
# YAML-NEXT: - LowOffset: 0x0000000000000000
# YAML-NEXT: HighOffset: 0x0000000000000020
# YAML-NEXT: - LowOffset: 0x0000000000000000
# YAML-NEXT: HighOffset: 0x0000000000000030
# YAML-NEXT: - LowOffset: 0xFFFFFFFFFFFFFFFF
# YAML-NEXT: HighOffset: 0x0000000000001000
# YAML-NEXT: - LowOffset: 0x0000000000000000
# YAML-NEXT: HighOffset: 0x0000000000001000
--- !mach-o
FileHeader:
magic: 0xFEEDFACF
cputype: 0x01000007
cpusubtype: 0x00000003
filetype: 0x00000001
ncmds: 4
sizeofcmds: 464
flags: 0x00002000
reserved: 0x00000000
LoadCommands:
- cmd: LC_SEGMENT_64
cmdsize: 392
segname: ''
vmaddr: 0
vmsize: 240
fileoff: 528
filesize: 240
maxprot: 7
initprot: 7
nsects: 4
flags: 0
Sections:
- sectname: __debug_abbrev
segname: __DWARF
addr: 0x0000000000000000
size: 36
offset: 0x00000210
align: 0
reloff: 0x00000000
nreloc: 0
flags: 0x00000000
reserved1: 0x00000000
reserved2: 0x00000000
reserved3: 0x00000000
content: 011101030E1305110155170000022E00030E110112060000032E00030E11011201000000
- sectname: __debug_info
segname: __DWARF
addr: 0x0000000000000024
size: 86
offset: 0x00000234
align: 0
reloff: 0x00000000
nreloc: 0
flags: 0x00000000
reserved1: 0x00000000
reserved2: 0x00000000
reserved3: 0x00000000
content: 520000000400000000000801010000000400000000000000000000000000020D000000000000000000000020000000031700000000000000000000003000000000000000022100000000100000000000000010000000
- sectname: __debug_ranges
segname: __DWARF
addr: 0x000000000000007A
size: 80
offset: 0x0000028A
align: 0
reloff: 0x00000000
nreloc: 0
flags: 0x00000000
reserved1: 0x00000000
reserved2: 0x00000000
reserved3: 0x00000000
content: 0000000000000000200000000000000000000000000000003000000000000000FFFFFFFFFFFFFFFF00100000000000000000000000000000001000000000000000000000000000000000000000000000
- sectname: __debug_str
segname: __DWARF
addr: 0x00000000000000CA
size: 38
offset: 0x000002DA
align: 0
reloff: 0x00000000
nreloc: 0
flags: 0x00000000
reserved1: 0x00000000
reserved2: 0x00000000
reserved3: 0x00000000
content: 002F746D702F6D61696E2E630073747269707065643100737472697070656432006D61696E00
- cmd: LC_SYMTAB
cmdsize: 24
symoff: 0
nsyms: 0
stroff: 768
strsize: 8
- cmd: LC_BUILD_VERSION
cmdsize: 32
platform: 1
minos: 658944
sdk: 658944
ntools: 1
Tools:
- tool: 3
version: 34734080
- cmd: LC_DATA_IN_CODE
cmdsize: 16
dataoff: 768
datasize: 0
LinkEditData:
StringTable:
- ' '
- ''
- ''
- ''
- ''
- ''
- ''
DWARF:
debug_str:
- ''
- '/tmp/main.c'
- stripped1
- stripped2
- main
debug_abbrev:
- Code: 0x00000001
Tag: DW_TAG_compile_unit
Children: DW_CHILDREN_yes
Attributes:
- Attribute: DW_AT_name
Form: DW_FORM_strp
- Attribute: DW_AT_language
Form: DW_FORM_data2
- Attribute: DW_AT_low_pc
Form: DW_FORM_addr
- Attribute: DW_AT_ranges
Form: DW_FORM_sec_offset
- Code: 0x00000002
Tag: DW_TAG_subprogram
Children: DW_CHILDREN_no
Attributes:
- Attribute: DW_AT_name
Form: DW_FORM_strp
- Attribute: DW_AT_low_pc
Form: DW_FORM_addr
- Attribute: DW_AT_high_pc
Form: DW_FORM_data4
- Code: 0x00000003
Tag: DW_TAG_subprogram
Children: DW_CHILDREN_no
Attributes:
- Attribute: DW_AT_name
Form: DW_FORM_strp
- Attribute: DW_AT_low_pc
Form: DW_FORM_addr
- Attribute: DW_AT_high_pc
Form: DW_FORM_addr
debug_ranges:
- Offset: 0x00000000
AddrSize: 0x08
Entries:
- LowOffset: 0x0000000000000000
HighOffset: 0x0000000000000020
- LowOffset: 0x0000000000000000
HighOffset: 0x0000000000000030
- LowOffset: 0xFFFFFFFFFFFFFFFF
HighOffset: 0x0000000000001000
- LowOffset: 0x0000000000000000
HighOffset: 0x0000000000001000
debug_info:
- Length:
TotalLength: 82
Version: 4
AbbrOffset: 0
AddrSize: 8
Entries:
- AbbrCode: 0x00000001
Values:
- Value: 0x0000000000000001
- Value: 0x0000000000000004
- Value: 0x0000000000000000
- Value: 0x0000000000000000
- AbbrCode: 0x00000002
Values:
- Value: 0x000000000000000D
- Value: 0x0000000000000000
- Value: 0x0000000000000020
- AbbrCode: 0x00000003
Values:
- Value: 0x0000000000000017
- Value: 0x0000000000000000
- Value: 0x0000000000000030
- AbbrCode: 0x00000002
Values:
- Value: 0x0000000000000021
- Value: 0x0000000000001000
- Value: 0x0000000000001000
- AbbrCode: 0x00000000
Values: []
...

View File

@ -9,6 +9,7 @@
#include "Error.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/ObjectYAML/DWARFYAML.h"
@ -82,6 +83,37 @@ Error dumpDebugARanges(DWARFContext &DCtx, DWARFYAML::Data &Y) {
return ErrorSuccess();
}
Error dumpDebugRanges(DWARFContext &DCtx, DWARFYAML::Data &Y) {
// We are assuming all address byte sizes will be consistent across all
// compile units.
uint8_t AddrSize = 0;
for (const auto &CU : DCtx.compile_units()) {
const uint8_t CUAddrSize = CU->getAddressByteSize();
if (AddrSize == 0)
AddrSize = CUAddrSize;
else if (CUAddrSize != AddrSize)
return createStringError(std::errc::invalid_argument,
"address sizes vary in different compile units");
}
DWARFDataExtractor Data(DCtx.getDWARFObj().getRangesSection().Data,
DCtx.isLittleEndian(), AddrSize);
uint64_t Offset = 0;
DWARFDebugRangeList DwarfRanges;
while (Data.isValidOffset(Offset)) {
DWARFYAML::Ranges YamlRanges;
YamlRanges.Offset = Offset;
YamlRanges.AddrSize = AddrSize;
if (Error E = DwarfRanges.extract(Data, &Offset))
return E;
for (const auto &RLE : DwarfRanges.getEntries())
YamlRanges.Entries.push_back({RLE.StartAddress, RLE.EndAddress});
Y.Ranges.push_back(std::move(YamlRanges));
}
return ErrorSuccess();
}
void dumpPubSection(DWARFContext &DCtx, DWARFYAML::PubSection &Y,
DWARFSection Section) {
DWARFDataExtractor PubSectionData(DCtx.getDWARFObj(), Section,
@ -354,6 +386,8 @@ llvm::Error dwarf2yaml(DWARFContext &DCtx, DWARFYAML::Data &Y) {
dumpDebugStrings(DCtx, Y);
if (Error E = dumpDebugARanges(DCtx, Y))
return E;
if (Error E = dumpDebugRanges(DCtx, Y))
return E;
dumpDebugPubSections(DCtx, Y);
dumpDebugInfo(DCtx, Y);
dumpDebugLines(DCtx, Y);