Index: llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h =================================================================== --- llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h +++ llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h @@ -61,6 +61,7 @@ std::unique_ptr Line; std::unique_ptr DebugFrame; std::unique_ptr EHFrame; + std::unique_ptr Macro; std::unique_ptr Macinfo; std::unique_ptr Names; std::unique_ptr AppleNames; @@ -272,7 +273,10 @@ /// Get a pointer to the parsed eh frame information object. const DWARFDebugFrame *getEHFrame(); - /// Get a pointer to the parsed DebugMacro object. + /// Get a pointer to the parsed Macro information object. + const DWARFDebugMacro *getDebugMacro(); + + /// Get a pointer to the parsed Macinfo inforamtion object. const DWARFDebugMacro *getDebugMacinfo(); /// Get a pointer to the parsed dwo DebugMacro object. Index: llvm/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h =================================================================== --- llvm/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h +++ llvm/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h @@ -10,14 +10,59 @@ #define LLVM_DEBUGINFO_DWARF_DWARFDEBUGMACRO_H #include "llvm/ADT/SmallVector.h" -#include "llvm/Support/DataExtractor.h" +#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/WithColor.h" #include namespace llvm { class raw_ostream; - +class DWARFContext; class DWARFDebugMacro { + /// DWARFv5 section 6.3.1 Macro Information Header + enum HeaderFlagMask { +#define HANDLE_MACRO_FLAG(ID, NAME) MACRO_##NAME = ID, +#include "llvm/BinaryFormat/Dwarf.def" + }; + struct MacroHeader { + /// Macro information number. + uint16_t Version; + /// flags + /// The bits of the flags field are interpreted as a set of flags, some of + /// which may indicate that additional fields follow. The following flags, + /// beginning with the least significant bit, are defined: offset_size_flag: + /// If the offset_size_flag is zero, the header is for a 32-bit DWARF + /// format macro section and all offsets are 4 bytes long; if it is one, + /// the header is for a 64-bit DWARF format macro section and all offsets + /// are 8 bytes long. + /// debug_line_offset_flag: + /// If the debug_line_offset_flag is one, the debug_line_offset field (see + /// below) is present. If zero, that field is omitted. + /// opcode_operands_table_flag: + /// If the opcode_operands_table_flag is one, the opcode_operands_table + /// field (see below) is present. If zero, that field is omitted. + // FIXME: add support for opcode_operands_table_flag. + + uint8_t Flags; + /// debug_line_offset + /// An offset in the .debug_line section of the beginning of the line + /// number information in the containing compilation, encoded as a 4-byte + /// offset for a 32-bit DWARF format macro section and an 8-byte offset + /// for a 64-bit DWARF format macro section + uint64_t DebugLineOffset; + + uint16_t getVersion() const { return Version; } + uint8_t getFlags() const { return Flags; } + uint64_t getDebugLineOffset() const { return DebugLineOffset; } + + /// Print the macro header from the debug_macro section. + void dumpMacroHeader(raw_ostream &OS) const; + + /// Parse the debug_macro header. + Error parseMacroHeader(DWARFDataExtractor data, uint64_t *Offset); + }; /// A single macro entry within a macro list. struct Entry { /// The type of the macro entry. @@ -40,6 +85,7 @@ }; struct MacroList { + MacroHeader Header; SmallVector Macros; uint64_t Offset; }; @@ -50,11 +96,13 @@ public: DWARFDebugMacro() = default; - /// Print the macro list found within the debug_macinfo section. - void dump(raw_ostream &OS) const; + /// Print the macro list found within the debug_macinfo/debug_macro section. + void dump(raw_ostream &OS, StringRef SectionName) const; - /// Parse the debug_macinfo section accessible via the 'data' parameter. - void parse(DataExtractor data); + /// Parse the debug_macinfo/debug_macro section accessible via the 'data' + /// parameter. + void parse(DWARFContext &Context, DWARFDataExtractor data, + StringRef SecctionName); /// Return whether the section has any entries. bool empty() const { return MacroLists.empty(); } Index: llvm/include/llvm/DebugInfo/DWARF/DWARFObject.h =================================================================== --- llvm/include/llvm/DebugInfo/DWARF/DWARFObject.h +++ llvm/include/llvm/DebugInfo/DWARF/DWARFObject.h @@ -47,6 +47,7 @@ virtual StringRef getStrSection() const { return ""; } virtual const DWARFSection &getRangesSection() const { return Dummy; } virtual const DWARFSection &getRnglistsSection() const { return Dummy; } + virtual const DWARFSection &getMacroSection() const { return Dummy; } virtual StringRef getMacinfoSection() const { return ""; } virtual StringRef getMacinfoDWOSection() const { return ""; } virtual const DWARFSection &getPubnamesSection() const { return Dummy; } Index: llvm/lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -444,14 +444,19 @@ DObj->getEHFrameSection().Data)) getEHFrame()->dump(OS, getRegisterInfo(), *Off); + if (shouldDump(Explicit, ".debug_macro", DIDT_ID_DebugMacro, + DObj->getMacroSection().Data)) { + getDebugMacro()->dump(OS, StringRef(".debug_macro")); + } + if (shouldDump(Explicit, ".debug_macinfo", DIDT_ID_DebugMacro, DObj->getMacinfoSection())) { - getDebugMacinfo()->dump(OS); + getDebugMacinfo()->dump(OS, StringRef(".debug_macinfo")); } if (shouldDump(Explicit, ".debug_macinfo.dwo", DIDT_ID_DebugMacro, DObj->getMacinfoDWOSection())) { - getDebugMacinfoDWO()->dump(OS); + getDebugMacinfoDWO()->dump(OS, StringRef(".debug_macinfo.dwo")); } if (shouldDump(Explicit, ".debug_aranges", DIDT_ID_DebugAranges, @@ -819,20 +824,31 @@ if (MacinfoDWO) return MacinfoDWO.get(); - DataExtractor MacinfoDWOData(DObj->getMacinfoDWOSection(), isLittleEndian(), - 0); + DWARFDataExtractor MacinfoDWOData(DObj->getMacinfoDWOSection(), + isLittleEndian(), 0); MacinfoDWO.reset(new DWARFDebugMacro()); - MacinfoDWO->parse(MacinfoDWOData); + MacinfoDWO->parse(*this, MacinfoDWOData, StringRef(".debug_macinfo.dwo")); return MacinfoDWO.get(); } +const DWARFDebugMacro *DWARFContext::getDebugMacro() { + if (Macro) + return Macro.get(); + DWARFDataExtractor MacroData(*DObj, DObj->getMacroSection(), isLittleEndian(), + 0); + Macro.reset(new DWARFDebugMacro()); + Macro->parse(*this, MacroData, StringRef(".debug_macro")); + return Macro.get(); +} + const DWARFDebugMacro *DWARFContext::getDebugMacinfo() { if (Macinfo) return Macinfo.get(); - DataExtractor MacinfoData(DObj->getMacinfoSection(), isLittleEndian(), 0); + DWARFDataExtractor MacinfoData(DObj->getMacinfoSection(), isLittleEndian(), + 0); Macinfo.reset(new DWARFDebugMacro()); - Macinfo->parse(MacinfoData); + Macinfo->parse(*this, MacinfoData, StringRef(".debug_macinfo")); return Macinfo.get(); } @@ -1476,6 +1492,7 @@ DWARFSectionMap PubtypesSection; DWARFSectionMap GnuPubnamesSection; DWARFSectionMap GnuPubtypesSection; + DWARFSectionMap MacroSection; DWARFSectionMap *mapNameToDWARFSection(StringRef Name) { return StringSwitch(Name) @@ -1503,6 +1520,7 @@ .Case("apple_namespaces", &AppleNamespacesSection) .Case("apple_namespac", &AppleNamespacesSection) .Case("apple_objc", &AppleObjCSection) + .Case("debug_macro", &MacroSection) .Default(nullptr); } @@ -1847,6 +1865,7 @@ const DWARFSection &getRnglistsSection() const override { return RnglistsSection; } + const DWARFSection &getMacroSection() const override { return MacroSection; } StringRef getMacinfoSection() const override { return MacinfoSection; } StringRef getMacinfoDWOSection() const override { return MacinfoDWOSection; } const DWARFSection &getPubnamesSection() const override { return PubnamesSection; } Index: llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp @@ -8,6 +8,8 @@ #include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h" #include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" #include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" #include @@ -15,10 +17,23 @@ using namespace llvm; using namespace dwarf; -void DWARFDebugMacro::dump(raw_ostream &OS) const { +void DWARFDebugMacro::MacroHeader::dumpMacroHeader(raw_ostream &OS) const { + // FIXME: Add support for dumping opcode_operands_table + OS << format("macro header: version = 0x%04" PRIx16 ", flags = 0x%02" PRIx8, + getVersion(), getFlags()); + if (getFlags() & MACRO_DEBUG_LINE_OFFSET) + OS << format(", debug_line_offset = 0x%04" PRIx64 "\n", + getDebugLineOffset()); + else + OS << "\n"; +} + +void DWARFDebugMacro::dump(raw_ostream &OS, StringRef SectionName) const { unsigned IndLevel = 0; for (const auto &Macros : MacroLists) { OS << format("0x%08" PRIx64 ":\n", Macros.Offset); + if (SectionName == ".debug_macro") + Macros.Header.dumpMacroHeader(OS); for (const Entry &E : Macros.Macros) { // There should not be DW_MACINFO_end_file when IndLevel is Zero. However, // this check handles the case of corrupted ".debug_macinfo" section. @@ -28,22 +43,34 @@ for (unsigned I = 0; I < IndLevel; I++) OS << " "; IndLevel += (E.Type == DW_MACINFO_start_file); - - WithColor(OS, HighlightColor::Macro).get() << MacinfoString(E.Type); + // Based on which version we are handling choose appropriate macro forms. + if (Macros.Header.getVersion() >= 5) + WithColor(OS, HighlightColor::Macro).get() << MacroString(E.Type); + else + WithColor(OS, HighlightColor::Macro).get() << MacinfoString(E.Type); switch (E.Type) { default: - // Got a corrupted ".debug_macinfo" section (invalid macinfo type). + // Got a corrupted ".debug_macinfo/.debug_macro" section (invalid + // macinfo type). break; - case DW_MACINFO_define: - case DW_MACINFO_undef: + // debug_macro/debug_macinfo shares couple of common encodings. + // DW_MACRO_define == DW_MACINFO_define + // DW_MACRO_undef == DW_MACINFO_undef + // DW_MACRO_start_file == DW_MACINFO_start_file + // DW_MACRO_end_file == DW_MACINFO_end_file + // For readibility/uniformity we are using DW_MACRO_*. + case DW_MACRO_define: + case DW_MACRO_undef: + case DW_MACRO_define_strp: + case DW_MACRO_undef_strp: OS << " - lineno: " << E.Line; OS << " macro: " << E.MacroStr; break; - case DW_MACINFO_start_file: + case DW_MACRO_start_file: OS << " - lineno: " << E.Line; OS << " filenum: " << E.File; break; - case DW_MACINFO_end_file: + case DW_MACRO_end_file: break; case DW_MACINFO_vendor_ext: OS << " - constant: " << E.ExtConstant; @@ -55,7 +82,8 @@ } } -void DWARFDebugMacro::parse(DataExtractor data) { +void DWARFDebugMacro::parse(DWARFContext &Context, DWARFDataExtractor data, + StringRef SectionName) { uint64_t Offset = 0; MacroList *M = nullptr; while (data.isValidOffset(Offset)) { @@ -63,39 +91,62 @@ MacroLists.emplace_back(); M = &MacroLists.back(); M->Offset = Offset; + if (SectionName == ".debug_macro") { + auto Err = M->Header.parseMacroHeader(data, &Offset); + auto handleParsingErr = Context.getRecoverableErrorHandler(); + if (Err) + return handleParsingErr(std::move(Err)); + } } // A macro list entry consists of: M->Macros.emplace_back(); Entry &E = M->Macros.back(); + // A macro list entry consists of: // 1. Macinfo type E.Type = data.getULEB128(&Offset); if (E.Type == 0) { - // Reached end of a ".debug_macinfo" section contribution. + // Reached end of a ".debug_macinfo/debug_macro" section contribution. M = nullptr; continue; } + uint64_t strOffset = 0; switch (E.Type) { default: // Got a corrupted ".debug_macinfo" section (invalid macinfo type). // Push the corrupted entry to the list and halt parsing. E.Type = DW_MACINFO_invalid; return; - case DW_MACINFO_define: - case DW_MACINFO_undef: + // debug_macro/debug_macinfo shares couple of common encodings. + // DW_MACRO_define == DW_MACINFO_define + // DW_MACRO_undef == DW_MACINFO_undef + // DW_MACRO_start_file == DW_MACINFO_start_file + // DW_MACRO_end_file == DW_MACINFO_end_file + // For readibility/uniformity we are using DW_MACRO_*. + case DW_MACRO_define: + case DW_MACRO_undef: // 2. Source line E.Line = data.getULEB128(&Offset); // 3. Macro string E.MacroStr = data.getCStr(&Offset); break; - case DW_MACINFO_start_file: + case DW_MACRO_define_strp: + case DW_MACRO_undef_strp: + // 2. Source line + E.Line = data.getULEB128(&Offset); + // 3. Macro string + // FIXME:Add support for DWARF64 + strOffset = data.getRelocatedValue(4 /*Offset Size*/, &Offset); + E.MacroStr = Context.getStringExtractor().getCStr(&strOffset); + break; + case DW_MACRO_start_file: // 2. Source line E.Line = data.getULEB128(&Offset); // 3. Source file id E.File = data.getULEB128(&Offset); break; - case DW_MACINFO_end_file: + case DW_MACRO_end_file: break; case DW_MACINFO_vendor_ext: // 2. Vendor extension constant @@ -106,3 +157,21 @@ } } } + +Error DWARFDebugMacro::MacroHeader::parseMacroHeader(DWARFDataExtractor data, + uint64_t *Offset) { + Version = data.getU16(Offset); + uint8_t Flagdata = data.getU8(Offset); + // FIXME: Add support for DWARF64 + if (Flagdata & MACRO_OFFSET_SIZE) + return createStringError(errc::not_supported, "DWARF64 is not supported"); + + // FIXME: Add support for parsing opcode_operands_table + if (Flagdata & MACRO_OPCODE_OPERANDS_TABLE) + return createStringError(errc::not_supported, + "opcode_operands_table is not supported"); + Flags = Flagdata; + if (Flags & MACRO_DEBUG_LINE_OFFSET) + DebugLineOffset = data.getU32(Offset); + return Error::success(); +} Index: llvm/test/DebugInfo/X86/debug-macro-v5.s =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/debug-macro-v5.s @@ -0,0 +1,59 @@ +# RUN: llvm-mc -triple x86_64-unknown-linux --filetype=obj -dwarf-version=5 %s -o -|\ +# RUN: llvm-dwarfdump --debug-macro - | FileCheck %s + +# CHECK: .debug_macro +# CHECK-NEXT: 0x00000000: +# CHECK-NEXT: macro header: version = 0x0005, flags = 0x02, debug_line_offset = 0x0000 +# CHECK-NEXT: DW_MACRO_start_file - lineno: 0 filenum: 0 +# CHECK-NEXT: DW_MACRO_start_file - lineno: 1 filenum: 1 +# CHECK-NEXT: DW_MACRO_define_strp - lineno: 1 macro: FOO 5 +# CHECK-NEXT: DW_MACRO_end_file +# CHECK-NEXT: DW_MACRO_undef_strp - lineno: 8 macro: WORLD1 +# CHECK-NEXT: DW_MACRO_end_file + +# CHECK: 0x{{.*}}: +# CHECK-NEXT: macro header: version = 0x0005, flags = 0x00 +# CHECK-NEXT: DW_MACRO_define_strp - lineno: 0 macro: WORLD2 + + .section .debug_macro,"",@progbits +.Lcu_macro_begin0: + .short 5 # Macro information version + .byte 2 # Flags: 32 bit, lineptr present + .long .Lline_table_start0 # lineptr + .byte 3 # DW_MACRO_start_file + .byte 0 # Line Number + .byte 0 # File Number + .byte 3 # DW_MACRO_start_file + .byte 1 # Line Number + .file 1 "." "foo.h" md5 0x0f0cd0e22b44f49d3944992c8dc28661 # File Number + .byte 1 + .byte 5 # DW_MACRO_define_strp + .byte 1 # Line Number + .long .Linfo_string3 # Macro String + .byte 4 # DW_MACRO_end_file + .byte 6 # DW_MACRO_undef_strp + .byte 8 # Line Number + .long .Linfo_string4 # Macro String + .byte 4 # DW_MACRO_end_file + .byte 0 # End Of Macro List Mark + .short 5 # Macro information version + .byte 0 # Flags: 32 bit + .byte 5 # DW_MACRO_define_strp + .byte 0 # Line Number + .long .Linfo_string5 # Macro String + .byte 0 # End Of Macro List Mark + .section .debug_str,"MS",@progbits,1 +.Linfo_string0: + .asciz "clang version 11.0.0" +.Linfo_string1: + .asciz "test.c" +.Linfo_string2: + .asciz "/" +.Linfo_string3: + .asciz "FOO 5" +.Linfo_string4: + .asciz "WORLD1 " +.Linfo_string5: + .asciz "WORLD2 " + .section .debug_line,"",@progbits +.Lline_table_start0: Index: llvm/test/DebugInfo/X86/dwarfdump-macro-macinfo.test =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/dwarfdump-macro-macinfo.test @@ -0,0 +1,23 @@ +RUN: llvm-dwarfdump -v %p/../Inputs/dwarfdump-macro-macinfo.elf-x86_64 | FileCheck %s + +CHECK: .debug_abbrev contents: +CHECK: DW_AT_macros DW_FORM_sec_offset +CHECK: DW_AT_macro_info DW_FORM_sec_offset + +CHECK: .debug_info contents: +CHECK: DW_AT_macros [DW_FORM_sec_offset] (0x00000000) +CHECK: DW_AT_macro_info [DW_FORM_sec_offset] (0x00000000) + +CHECK: debug_macro contents: +CHECK-NEXT: 0x00000000: +CHECK-NEXT: macro header: version = 0x0005, flags = 0x02, debug_line_offset = 0x0000 +CHECK-NEXT: DW_MACRO_start_file - lineno: 0 filenum: 0 +CHECK-NEXT: DW_MACRO_define_strp - lineno: 1 macro: DWARF_VERSION 5 +CHECK-NEXT: DW_MACRO_end_file + + +CHECK: .debug_macinfo contents: +CHECK-NEXT: 0x00000000: +CHECK-NEXT: DW_MACINFO_start_file - lineno: 0 filenum: 1 +CHECK-NEXT: DW_MACINFO_define - lineno: 1 macro: DWARF_VERSION 4 +CHECK-NEXT: DW_MACINFO_end_file Index: llvm/test/DebugInfo/X86/unsupported-dwarf64-debug-macro-v5.s =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/unsupported-dwarf64-debug-macro-v5.s @@ -0,0 +1,12 @@ +# RUN: llvm-mc -triple x86_64-unknown-linux --filetype=obj -dwarf-version=5 %s -o -|\ +# RUN: not llvm-dwarfdump --debug-macro - /dev/null 2>&1 | FileCheck %s + +# CHECK: error: DWARF64 is not supported + + .section .debug_macro,"",@progbits +.Lcu_macro_begin0: + .short 5 # Macro information version + .byte 3 # Flags: 64 bit, lineptr present + .long .Lline_table_start0 # lineptr + .section .debug_line,"",@progbits +.Lline_table_start0: Index: llvm/test/DebugInfo/X86/unsupported-opcode_operands_table-debug-macro-v5.s =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/unsupported-opcode_operands_table-debug-macro-v5.s @@ -0,0 +1,12 @@ +# RUN: llvm-mc -triple x86_64-unknown-linux --filetype=obj -dwarf-version=5 %s -o -|\ +# RUN: not llvm-dwarfdump --debug-macro - /dev/null 2>&1 | FileCheck %s + +# CHECK: error: opcode_operands_table is not supported + + .section .debug_macro,"",@progbits +.Lcu_macro_begin0: + .short 5 # Macro information version + .byte 4 # Flags: 32 bit, lineptr present, opcode_operands_table present + .long .Lline_table_start0 # lineptr + .section .debug_line,"",@progbits +.Lline_table_start0: