diff --git a/llvm/include/llvm/ObjectYAML/DWARFEmitter.h b/llvm/include/llvm/ObjectYAML/DWARFEmitter.h --- a/llvm/include/llvm/ObjectYAML/DWARFEmitter.h +++ b/llvm/include/llvm/ObjectYAML/DWARFEmitter.h @@ -32,6 +32,7 @@ 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); diff --git a/llvm/include/llvm/ObjectYAML/DWARFYAML.h b/llvm/include/llvm/ObjectYAML/DWARFYAML.h --- a/llvm/include/llvm/ObjectYAML/DWARFYAML.h +++ b/llvm/include/llvm/ObjectYAML/DWARFYAML.h @@ -71,6 +71,20 @@ std::vector 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 Entries; +}; + struct PubEntry { llvm::yaml::Hex32 DieOffset; llvm::yaml::Hex8 Descriptor; @@ -145,6 +159,7 @@ std::vector AbbrevDecls; std::vector DebugStrings; std::vector ARanges; + std::vector Ranges; PubSection PubNames; PubSection PubTypes; @@ -165,6 +180,8 @@ 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 @@ static void mapping(IO &IO, DWARFYAML::ARange &Range); }; +template <> struct MappingTraits { + static void mapping(IO &IO, DWARFYAML::RangeEntry &Entry); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, DWARFYAML::Ranges &Ranges); +}; + template <> struct MappingTraits { static void mapping(IO &IO, DWARFYAML::PubEntry &Entry); }; diff --git a/llvm/lib/ObjectYAML/DWARFEmitter.cpp b/llvm/lib/ObjectYAML/DWARFEmitter.cpp --- a/llvm/lib/ObjectYAML/DWARFEmitter.cpp +++ b/llvm/lib/ObjectYAML/DWARFEmitter.cpp @@ -114,6 +114,23 @@ } } +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 @@ DebugSections); EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugAranges, "debug_aranges", DebugSections); + EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugRanges, "debug_ranges", + DebugSections); return std::move(DebugSections); } diff --git a/llvm/lib/ObjectYAML/DWARFYAML.cpp b/llvm/lib/ObjectYAML/DWARFYAML.cpp --- a/llvm/lib/ObjectYAML/DWARFYAML.cpp +++ b/llvm/lib/ObjectYAML/DWARFYAML.cpp @@ -28,6 +28,8 @@ 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 @@ IO.mapRequired("Descriptors", Range.Descriptors); } +void MappingTraits::mapping( + IO &IO, DWARFYAML::RangeEntry &Descriptor) { + IO.mapRequired("LowOffset", Descriptor.LowOffset); + IO.mapRequired("HighOffset", Descriptor.HighOffset); +} + +void MappingTraits::mapping(IO &IO, + DWARFYAML::Ranges &Ranges) { + IO.mapRequired("Offset", Ranges.Offset); + IO.mapRequired("AddrSize", Ranges.AddrSize); + IO.mapRequired("Entries", Ranges.Entries); +} + void MappingTraits::mapping(IO &IO, DWARFYAML::PubEntry &Entry) { IO.mapRequired("DieOffset", Entry.DieOffset); diff --git a/llvm/lib/ObjectYAML/MachOEmitter.cpp b/llvm/lib/ObjectYAML/MachOEmitter.cpp --- a/llvm/lib/ObjectYAML/MachOEmitter.cpp +++ b/llvm/lib/ObjectYAML/MachOEmitter.cpp @@ -287,6 +287,8 @@ 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); diff --git a/llvm/test/tools/obj2yaml/macho-DWARF-debug-ranges.yaml b/llvm/test/tools/obj2yaml/macho-DWARF-debug-ranges.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/obj2yaml/macho-DWARF-debug-ranges.yaml @@ -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: [] +... 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 @@ -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 @@ 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 @@ 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);