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,74 @@ #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_FLAGS(ID, NAME) MACRO_FLAG_##NAME = ID, +#include "llvm/BinaryFormat/Dwarf.def" + }; + struct Header { + /// 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 64-bit DWARF; + 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; + }; + uint64_t HeaderOffset; + Header HeaderData; + + uint64_t getHeaderOffset() const { return HeaderOffset; } + uint16_t getVersion() const { return HeaderData.Version; } + uint8_t getFlags() const { return HeaderData.Flags; } + uint32_t getDebugLineOffset() const { return HeaderData.DebugLineOffset; } + + void setHeaderOffset(uint64_t *Offset) { HeaderOffset = *Offset; } + void setVersion(uint16_t Version) { HeaderData.Version = Version; } + Expected setFlags(uint8_t Flags) { + if (Flags != 2) { + Error Err = createStringError( + errc::not_supported, + "DWARF64 is not supported and debug_line_offset must be present!"); + return std::move(Err); + } + HeaderData.Flags = Flags; + return true; + } + void setDebugLineOffset(uint64_t DebugLineOffset) { + HeaderData.DebugLineOffset = DebugLineOffset; + } + /// A single macro entry within a macro list. struct Entry { /// The type of the macro entry. @@ -47,11 +107,17 @@ public: DWARFDebugMacro() = default; - /// Print the macro list found within the debug_macinfo section. + /// Print the macro header from the debug_macro section. + void dumpMacroHeader(raw_ostream &OS) const; + /// Print the macro list found within the debug_macinfo/debug_macro section. void dump(raw_ostream &OS) const; - /// Parse the debug_macinfo section accessible via the 'data' parameter. - void parse(DataExtractor data); + /// Parse the debug_macro header. + Expected parseMacroHeader(DWARFDataExtractor data, uint64_t *Offset); + + /// Parse the debug_macinfo/debug_macro section accessible via the 'data' + /// parameter. + void parse(DWARFContext &Context, DWARFDataExtractor data, uint64_t *Offset); /// 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 @@ -48,6 +48,7 @@ virtual const DWARFSection &getRangesSection() const { return Dummy; } virtual const DWARFSection &getRnglistsSection() const { return Dummy; } virtual StringRef getMacinfoSection() const { return ""; } + virtual const DWARFSection &getMacroSection() const { return Dummy; } virtual StringRef getMacinfoDWOSection() const { return ""; } virtual const DWARFSection &getPubnamesSection() const { return Dummy; } virtual const DWARFSection &getPubtypesSection() const { return Dummy; } Index: llvm/lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -319,6 +319,24 @@ } } +static void dumpMacroSection(DWARFContext &Context, raw_ostream &OS, + DWARFDataExtractor MacroData) { + uint64_t Offset = 0; + DWARFDebugMacro Macro; + while (MacroData.isValidOffset(Offset)) { + // While parsing header if flag field has other value then + // 2 skip the rest of parsing/dumping and report the error. + Expected Status = Macro.parseMacroHeader(MacroData, &Offset); + if (!Status) { + WithColor::error() << toString(std::move(Status.takeError())) << '\n'; + return; + } + Macro.dumpMacroHeader(OS); + Macro.parse(Context, MacroData, &Offset); + Macro.dump(OS); + } +} + void DWARFContext::dump( raw_ostream &OS, DIDumpOptions DumpOpts, std::array, DIDT_ID_Count> DumpOffsets) { @@ -443,6 +461,13 @@ getDebugMacro()->dump(OS); } + if (shouldDump(Explicit, ".debug_macro", DIDT_ID_DebugMacro, + DObj->getMacroSection().Data)) { + DWARFDataExtractor Data(*DObj, DObj->getMacroSection(), isLittleEndian(), + 0); + dumpMacroSection(*this, OS, Data); + } + if (shouldDump(Explicit, ".debug_macinfo.dwo", DIDT_ID_DebugMacro, DObj->getMacinfoDWOSection())) { getDebugMacroDWO()->dump(OS); @@ -809,21 +834,22 @@ const DWARFDebugMacro *DWARFContext::getDebugMacroDWO() { if (MacroDWO) return MacroDWO.get(); - - DataExtractor MacinfoDWOData(DObj->getMacinfoDWOSection(), isLittleEndian(), - 0); + uint64_t Offset = 0; + DWARFDataExtractor MacinfoDWOData(DObj->getMacinfoDWOSection(), + isLittleEndian(), 0); MacroDWO.reset(new DWARFDebugMacro()); - MacroDWO->parse(MacinfoDWOData); + MacroDWO->parse(*this, MacinfoDWOData, &Offset); return MacroDWO.get(); } const DWARFDebugMacro *DWARFContext::getDebugMacro() { if (Macro) return Macro.get(); - - DataExtractor MacinfoData(DObj->getMacinfoSection(), isLittleEndian(), 0); + uint64_t Offset = 0; + DWARFDataExtractor MacinfoData(DObj->getMacinfoSection(), isLittleEndian(), + 0); Macro.reset(new DWARFDebugMacro()); - Macro->parse(MacinfoData); + Macro->parse(*this, MacinfoData, &Offset); return Macro.get(); } @@ -1472,6 +1498,7 @@ DWARFSectionMap PubtypesSection; DWARFSectionMap GnuPubnamesSection; DWARFSectionMap GnuPubtypesSection; + DWARFSectionMap MacroSection; DWARFSectionMap *mapNameToDWARFSection(StringRef Name) { return StringSwitch(Name) @@ -1499,6 +1526,7 @@ .Case("apple_namespaces", &AppleNamespacesSection) .Case("apple_namespac", &AppleNamespacesSection) .Case("apple_objc", &AppleObjCSection) + .Case("debug_macro", &MacroSection) .Default(nullptr); } @@ -1853,6 +1881,7 @@ return RnglistsSection; } StringRef getMacinfoSection() const override { return MacinfoSection; } + const DWARFSection &getMacroSection() const override { return MacroSection; } StringRef getMacinfoDWOSection() const override { return MacinfoDWOSection; } const DWARFSection &getPubnamesSection() const override { return PubnamesSection; } const DWARFSection &getPubtypesSection() const override { return PubtypesSection; } 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,12 +17,20 @@ using namespace llvm; using namespace dwarf; +void DWARFDebugMacro::dumpMacroHeader(raw_ostream &OS) const { + OS << format("0x%08" PRIx64 ": ", getHeaderOffset()); + OS << format("macro header: version = 0x%04" PRIx16 ", flags = 0x%02" PRIx8 + ", debug_line_offset = 0x%04" PRIx32 "\n", + getVersion(), getFlags(), getDebugLineOffset()); +} + void DWARFDebugMacro::dump(raw_ostream &OS) const { unsigned IndLevel = 0; for (const auto &Macros : MacroLists) { for (const Entry &E : Macros) { - // There should not be DW_MACINFO_end_file when IndLevel is Zero. However, - // this check handles the case of corrupted ".debug_macinfo" section. + // There should not be DW_MACINFO_end_file/DW_MACRO_end_file when IndLevel + // is Zero. However, this check handles the case of corrupted + // ".debug_macinfo/.debug_macro" section. if (IndLevel > 0) IndLevel -= (E.Type == DW_MACINFO_end_file); // Print indentation. @@ -28,13 +38,20 @@ 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 (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: + case DW_MACRO_define_strp: + case DW_MACRO_undef_strp: OS << " - lineno: " << E.Line; OS << " macro: " << E.MacroStr; break; @@ -55,10 +72,11 @@ } } -void DWARFDebugMacro::parse(DataExtractor data) { - uint64_t Offset = 0; +void DWARFDebugMacro::parse(DWARFContext &Context, DWARFDataExtractor data, + uint64_t *Offset) { + uint64_t strOffset = 0; MacroList *M = nullptr; - while (data.isValidOffset(Offset)) { + while (data.isValidOffset(*Offset)) { if (!M) { MacroLists.emplace_back(); M = &MacroLists.back(); @@ -67,40 +85,66 @@ M->emplace_back(); Entry &E = M->back(); // 1. Macinfo type - E.Type = data.getULEB128(&Offset); + E.Type = data.getULEB128(Offset); if (E.Type == 0) { + // Contribution of one CU finished, dump this and + // check if Offset is still valid, if so, start parsing/dumping + // debug_macro again.This is not needed for debug_macinfo section since + // contribution from different CU's got merged into single debug_macinfo + // section with macro termination sequence at the end of the section. + if (getVersion() >= 5) + return; // Reached end of a ".debug_macinfo" section contribution. continue; } switch (E.Type) { default: - // Got a corrupted ".debug_macinfo" section (invalid macinfo type). - // Push the corrupted entry to the list and halt parsing. + // Got a corrupted ".debug_macinfo/debug_macro" 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: // 2. Source line - E.Line = data.getULEB128(&Offset); + E.Line = data.getULEB128(Offset); // 3. Macro string - E.MacroStr = data.getCStr(&Offset); + E.MacroStr = data.getCStr(Offset); + break; + case DW_MACRO_define_strp: + case DW_MACRO_undef_strp: + // 2. Source line + E.Line = data.getULEB128(Offset); + // 3. Macro string + strOffset = data.getRelocatedValue(4 /*Offset Size*/, Offset); + E.MacroStr = Context.getStringExtractor().getCStr(&strOffset); break; case DW_MACINFO_start_file: // 2. Source line - E.Line = data.getULEB128(&Offset); + E.Line = data.getULEB128(Offset); // 3. Source file id - E.File = data.getULEB128(&Offset); + E.File = data.getULEB128(Offset); break; case DW_MACINFO_end_file: break; case DW_MACINFO_vendor_ext: // 2. Vendor extension constant - E.ExtConstant = data.getULEB128(&Offset); + E.ExtConstant = data.getULEB128(Offset); // 3. Vendor extension string - E.ExtStr = data.getCStr(&Offset); + E.ExtStr = data.getCStr(Offset); break; } } } + +Expected DWARFDebugMacro::parseMacroHeader(DWARFDataExtractor data, + uint64_t *Offset) { + setHeaderOffset(Offset); + setVersion(data.getU16(Offset)); + Expected Status = setFlags(data.getU8(Offset)); + if (!Status) + return std::move(Status.takeError()); + setDebugLineOffset(data.getU32(Offset)); + return true; +} Index: llvm/test/DebugInfo/X86/debug-macro-v5.s =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/debug-macro-v5.s @@ -0,0 +1,170 @@ +# RUN: llvm-mc --filetype=obj -dwarf-version=5 %s -o %t.o +# RUN: llvm-dwarfdump -v %t.o | FileCheck %s + +# CHECK: .debug_abbrev contents: +# CHECK: DW_AT_macros DW_FORM_sec_offset +# CHECK: .debug_info contents: +# CHECK: DW_AT_macros [DW_FORM_sec_offset] (0x00000000) + +#CHECK: .debug_macro +# CHECK-NEXT: 0x00000000: 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_start_file - lineno: 2 filenum: 2 +# CHECK-NEXT: DW_MACRO_define_strp - lineno: 1 macro: BAR 6 +# CHECK-NEXT: DW_MACRO_end_file +# CHECK-NEXT: DW_MACRO_define_strp - lineno: 4 macro: WORLD 4 +# CHECK-NEXT: DW_MACRO_define_strp - lineno: 5 macro: WORLD1 1 +# CHECK-NEXT: DW_MACRO_undef_strp - lineno: 7 macro: WORLD +# CHECK-NEXT: DW_MACRO_undef_strp - lineno: 8 macro: WORLD1 +# CHECK-NEXT: DW_MACRO_end_file +# CHECK-NEXT: DW_MACRO_define_strp - lineno: 0 macro: __llvm__ 1 +# CHECK-NEXT: DW_MACRO_define_strp - lineno: 0 macro: __clang__ 1 +# CHECK-NEXT: DW_MACRO_define_strp - lineno: 0 macro: __clang_major__ 11 +# CHECK-NEXT: DW_MACRO_define_strp - lineno: 0 macro: __clang_minor__ 0 +# CHECK-NEXT: DW_MACRO_define_strp - lineno: 0 macro: __clang_patchlevel__ 0 +# CHECK-NEXT: DW_MACRO_define_strp - lineno: 0 macro: __clang_version__ 11.0.0 +# CHECK-NEXT: DW_MACRO_define_strp - lineno: 0 macro: clang version 11.0.0 + + .text + .file "test.c" + .file 0 "/home" "test.c" md5 0x55645bd344ef72cf48bab13d10ec2c80 + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 0 # DW_CHILDREN_no + .byte 37 # DW_AT_producer + .byte 37 # DW_FORM_strx1 + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 114 # DW_AT_str_offsets_base + .byte 23 # DW_FORM_sec_offset + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 27 # DW_AT_comp_dir + .byte 37 # DW_FORM_strx1 + .byte 121 # DW_AT_macros + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit +.Ldebug_info_start0: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 1 # Abbrev [1] 0xc:0x12 DW_TAG_compile_unit + .byte 0 # DW_AT_producer + .short 12 # DW_AT_language + .byte 1 # DW_AT_name + .long .Lstr_offsets_base0 # DW_AT_str_offsets_base + .long .Lline_table_start0 # DW_AT_stmt_list + .byte 2 # DW_AT_comp_dir + .long .Lcu_macro_begin0 # DW_AT_macros +.Ldebug_info_end0: + .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 3 # DW_MACRO_start_file + .byte 2 # Line Number + .file 2 "." "bar.h" md5 0xbf4b34c333eaaa1d7085c25313b8d100 # File Number + .byte 2 + .byte 5 # DW_MACRO_define_strp + .byte 1 # Line Number + .long .Linfo_string4 # Macro String + .byte 4 # DW_MACRO_end_file + .byte 5 # DW_MACRO_define_strp + .byte 4 # Line Number + .long .Linfo_string5 # Macro String + .byte 5 # DW_MACRO_define_strp + .byte 5 # Line Number + .long .Linfo_string6 # Macro String + .byte 6 # DW_MACRO_undef_strp + .byte 7 # Line Number + .long .Linfo_string7 # Macro String + .byte 6 # DW_MACRO_undef_strp + .byte 8 # Line Number + .long .Linfo_string8 # Macro String + .byte 4 # DW_MACRO_end_file + .byte 5 # DW_MACRO_define_strp + .byte 0 # Line Number + .long .Linfo_string9 # Macro String + .byte 5 # DW_MACRO_define_strp + .byte 0 # Line Number + .long .Linfo_string10 # Macro String + .byte 5 # DW_MACRO_define_strp + .byte 0 # Line Number + .long .Linfo_string11 # Macro String + .byte 5 # DW_MACRO_define_strp + .byte 0 # Line Number + .long .Linfo_string12 # Macro String + .byte 5 # DW_MACRO_define_strp + .byte 0 # Line Number + .long .Linfo_string13 # Macro String + .byte 5 # DW_MACRO_define_strp + .byte 0 # Line Number + .long .Linfo_string14 # Macro String + .byte 5 # DW_MACRO_define_strp + .byte 0 # Line Number + .byte 0 # End Of Macro List Mark + .section .debug_str_offsets,"",@progbits + .long 16 + .short 5 + .short 0 +.Lstr_offsets_base0: + .section .debug_str,"MS",@progbits,1 +.Linfo_string0: + .asciz "clang version 11.0.0" # string offset=0 +.Linfo_string1: + .asciz "test.c" # string offset=105 +.Linfo_string2: + .asciz "/home/sourabh/work/dwarf/c_c++/macro" # string offset=112 +.Linfo_string3: + .asciz "FOO 5" # string offset=149 +.Linfo_string4: + .asciz "BAR 6" # string offset=155 +.Linfo_string5: + .asciz "WORLD 4" # string offset=161 +.Linfo_string6: + .asciz "WORLD1 1" # string offset=169 +.Linfo_string7: + .asciz "WORLD " # string offset=178 +.Linfo_string8: + .asciz "WORLD1 " # string offset=185 +.Linfo_string9: + .asciz "__llvm__ 1" # string offset=193 +.Linfo_string10: + .asciz "__clang__ 1" # string offset=204 +.Linfo_string11: + .asciz "__clang_major__ 11" # string offset=216 +.Linfo_string12: + .asciz "__clang_minor__ 0" # string offset=235 +.Linfo_string13: + .asciz "__clang_patchlevel__ 0" # string offset=253 +.Linfo_string14: + .asciz "__clang_version__ 11.0.0" # string offset=276 + .ident "clang version 11.0.0 (https://github.com/llvm/llvm-project.git e4c50ac4207915968d76be259c042c0311fa2d97)" + .section ".note.GNU-stack","",@progbits + .addrsig + .section .debug_line,"",@progbits +.Lline_table_start0: Index: llvm/test/DebugInfo/X86/unsupported-flag-debug-macro-v5.s =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/unsupported-flag-debug-macro-v5.s @@ -0,0 +1,9 @@ +# RUN: llvm-mc --filetype=obj -dwarf-version=5 %s -o %t.o +# RUN: not llvm-dwarfdump -v %t.o /dev/null 2>&1 | FileCheck %s + +#CHECK: error: DWARF64 is not supported and debug_line_offset must be present! + + .section .debug_macro,"",@progbits +.Lcu_macro_begin0: + .short 5 # Macro information version + .byte 5 # Flags