Index: llvm/include/llvm/BinaryFormat/Dwarf.h =================================================================== --- llvm/include/llvm/BinaryFormat/Dwarf.h +++ llvm/include/llvm/BinaryFormat/Dwarf.h @@ -470,6 +470,7 @@ StringRef LNStandardString(unsigned Standard); StringRef LNExtendedString(unsigned Encoding); StringRef MacinfoString(unsigned Encoding); +StringRef MacroString(unsigned Encoding); StringRef RangeListEncodingString(unsigned Encoding); StringRef LocListEncodingString(unsigned Encoding); StringRef CallFrameString(unsigned Encoding, Triple::ArchType Arch); Index: llvm/include/llvm/BinaryFormat/Dwarf.def =================================================================== --- llvm/include/llvm/BinaryFormat/Dwarf.def +++ llvm/include/llvm/BinaryFormat/Dwarf.def @@ -17,6 +17,7 @@ defined HANDLE_DW_VIRTUALITY || defined HANDLE_DW_DEFAULTED || \ defined HANDLE_DW_CC || defined HANDLE_DW_LNS || defined HANDLE_DW_LNE || \ defined HANDLE_DW_LNCT || defined HANDLE_DW_MACRO || \ + defined HANDLE_MACRO_FLAGS || \ defined HANDLE_DW_RLE || defined HANDLE_DW_LLE || \ (defined HANDLE_DW_CFA && defined HANDLE_DW_CFA_PRED) || \ defined HANDLE_DW_APPLE_PROPERTY || defined HANDLE_DW_UT || \ @@ -87,6 +88,10 @@ #define HANDLE_DW_MACRO(ID, NAME) #endif +#ifndef HANDLE_MACRO_FLAGS +#define HANDLE_MACRO_FLAGS(ID, NAME) +#endif + #ifndef HANDLE_DW_RLE #define HANDLE_DW_RLE(ID, NAME) #endif @@ -821,6 +826,10 @@ HANDLE_DW_MACRO(0x0a, import_sup) HANDLE_DW_MACRO(0x0b, define_strx) HANDLE_DW_MACRO(0x0c, undef_strx) +// DWARF v5 Macro header flags +HANDLE_MACRO_FLAGS(0x01, OFFSET_SIZE) +HANDLE_MACRO_FLAGS(0x02, DEBUG_LINE_OFFSET) +HANDLE_MACRO_FLAGS(0x04, OPCODE_OPERANDS_TABLE) // DWARF v5 Range List Entry encoding values. HANDLE_DW_RLE(0x00, end_of_list) @@ -956,6 +965,7 @@ #undef HANDLE_DW_LNE #undef HANDLE_DW_LNCT #undef HANDLE_DW_MACRO +#undef HANDLE_MACRO_FLAGS #undef HANDLE_DW_RLE #undef HANDLE_DW_LLE #undef HANDLE_DW_CFA 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; @@ -273,6 +274,7 @@ const DWARFDebugFrame *getEHFrame(); /// Get a pointer to the parsed DebugMacro object. + const DWARFDebugMacro *getDebugMacro(); 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,57 @@ #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_##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 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; + // FIXME: add support for opcode_operands_table_flag. + 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. + Expected parseMacroHeader(DWARFDataExtractor data, uint64_t *Offset); + }; /// A single macro entry within a macro list. struct Entry { /// The type of the macro entry. @@ -40,6 +83,7 @@ }; struct MacroList { + MacroHeader Header; SmallVector Macros; uint64_t Offset; }; @@ -53,8 +97,9 @@ /// Print the macro list found within the debug_macinfo section. void dump(raw_ostream &OS) 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); /// 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/BinaryFormat/Dwarf.cpp =================================================================== --- llvm/lib/BinaryFormat/Dwarf.cpp +++ llvm/lib/BinaryFormat/Dwarf.cpp @@ -448,6 +448,17 @@ } } +StringRef llvm::dwarf::MacroString(unsigned Encoding) { + switch (Encoding) { + default: + return StringRef(); +#define HANDLE_DW_MACRO(ID, NAME) \ + case DW_MACRO_##NAME: \ + return "DW_MACRO_" #NAME; +#include "llvm/BinaryFormat/Dwarf.def" + } +} + StringRef llvm::dwarf::MacinfoString(unsigned Encoding) { switch (Encoding) { // Macinfo Type Encodings Index: llvm/lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -444,6 +444,11 @@ DObj->getEHFrameSection().Data)) getEHFrame()->dump(OS, getRegisterInfo(), *Off); + if (shouldDump(Explicit, ".debug_macro", DIDT_ID_DebugMacro, + DObj->getMacroSection().Data)) { + getDebugMacro()->dump(OS); + } + if (shouldDump(Explicit, ".debug_macinfo", DIDT_ID_DebugMacro, DObj->getMacinfoSection())) { getDebugMacinfo()->dump(OS); @@ -818,20 +823,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); 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); + 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); return Macinfo.get(); } @@ -1475,6 +1491,7 @@ DWARFSectionMap PubtypesSection; DWARFSectionMap GnuPubnamesSection; DWARFSectionMap GnuPubtypesSection; + DWARFSectionMap MacroSection; DWARFSectionMap *mapNameToDWARFSection(StringRef Name) { return StringSwitch(Name) @@ -1502,6 +1519,7 @@ .Case("apple_namespaces", &AppleNamespacesSection) .Case("apple_namespac", &AppleNamespacesSection) .Case("apple_objc", &AppleObjCSection) + .Case("debug_macro", &MacroSection) .Default(nullptr); } @@ -1846,6 +1864,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::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) const { unsigned IndLevel = 0; for (const auto &Macros : MacroLists) { OS << format("0x%08" PRIx64 ":\n", Macros.Offset); + if (Macros.Header.getVersion() >= 5) + 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,14 +43,20 @@ 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: + case DW_MACRO_define_strp: + case DW_MACRO_undef_strp: OS << " - lineno: " << E.Line; OS << " macro: " << E.MacroStr; break; @@ -55,7 +76,8 @@ } } -void DWARFDebugMacro::parse(DataExtractor data) { +void DWARFDebugMacro::parse(DWARFContext &Context, DWARFDataExtractor data) { + uint64_t strOffset = 0; uint64_t Offset = 0; MacroList *M = nullptr; while (data.isValidOffset(Offset)) { @@ -63,15 +85,23 @@ MacroLists.emplace_back(); M = &MacroLists.back(); M->Offset = Offset; + if (Context.getMaxVersion() >= 5) { + Expected Status = M->Header.parseMacroHeader(data, &Offset); + if (!Status) { + WithColor::error() << toString(std::move(Status.takeError())) << '\n'; + return; + } + } } // 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; } @@ -89,6 +119,15 @@ // 3. Macro string 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 + // FIXME:Add support for DWARF64 + 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); @@ -106,3 +145,20 @@ } } } +Expected +DWARFDebugMacro::MacroHeader::parseMacroHeader(DWARFDataExtractor data, + uint64_t *Offset) { + // FIXME: Add support for parsing opcode_operands_table + Version = data.getU16(Offset); + uint8_t Flagdata = data.getU8(Offset); + // FIXME: Add support for DWARF64 + if (Flagdata & MACRO_OFFSET_SIZE) { + Error Err = + createStringError(errc::not_supported, "DWARF64 is not supported"); + return std::move(Err); + } + Flags = Flagdata; + if (Flags == MACRO_DEBUG_LINE_OFFSET) + DebugLineOffset = 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,109 @@ +# 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: +# 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-NEXT: DW_MACRO_define_strp - lineno: 0 macro: __llvm__ 1 +# 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 6 # DW_MACRO_undef_strp + .byte 8 # Line Number + .long .Linfo_string4 # Macro String + .byte 4 # DW_MACRO_end_file + .byte 5 # DW_MACRO_define_strp + .byte 0 # Line Number + .long .Linfo_string5 # 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 "WORLD1 " # string offset=185 +.Linfo_string5: + .asciz "__llvm__ 1" # string offset=193 + .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: